Fs.v (570 lines of code) (raw):

Require Import mathcomp.ssreflect.path. Require Import Commons Tree OtDef ListTools Comp SortedTree. Import Bool. Section FilesystemOT. Parameter T : eqType. Parameter R : rel T. Parameter Rord : order R. Inductive raw_fs_cmd := | RawEdit of T & T | RawCreate of tree T | RawRemove of tree T | RawOpen of T & raw_fs_cmd. Fixpoint raw_fs_inv (cmd : raw_fs_cmd) := match cmd with | RawOpen l c => RawOpen l (raw_fs_inv c) | RawEdit l k => RawEdit k l | RawCreate t => RawRemove t | RawRemove t => RawCreate t end. Fixpoint eq_cmd (t1 t2 : raw_fs_cmd) : bool := match t1, t2 with | RawOpen l c, RawOpen l2 c2 => (l == l2) && (eq_cmd c c2) | RawEdit l k, RawEdit l2 k2 => (l == l2) && (k == k2) | RawCreate t, RawCreate t2 => (t == t2) | RawRemove t, RawRemove t2 => (t == t2) | _, _ => false end. Lemma eq_cmdK: @Equality.axiom raw_fs_cmd eq_cmd. elim => [l k | t | t | l c IH] [l2 k2| t2| t2| l2 c2] /=; (try by constructor); repeat (case A0: (eq_op _ _) => /=; move: A0 => /eqP); try constructor; subst => // A; try by case: A. + subst. case A0: (eq_cmd); move: A0 => /IH; constructor; subst => // A. by case: A. Qed. Canonical cmd_eqMixin := EqMixin eq_cmdK. Canonical cmd_eqType := Eval hnf in EqType raw_fs_cmd cmd_eqMixin. Ltac correct_label A := let H := fresh "H" in move: (find_pred A) => H; rewrite /by_value /= in H; move: H => /eqP H; subst. Ltac correct_interp_label A := let A' := fresh A in (assert (A':=A); move: A' => /interp_label_indep /= A'; move: A; rewrite ?A' => [] [] A; subst). Section FsCmd. Inductive fs_cmd := | Edit of T & T | Create (c : sorted_tree R) | Remove (c : sorted_tree R) | Open of T & fs_cmd. Fixpoint fs_to_raw_fs (c : fs_cmd) : raw_fs_cmd := match c with | Edit l k => RawEdit l k | Create c => RawCreate (treeOf c) | Remove t => RawRemove (treeOf t) | Open l c => RawOpen l (fs_to_raw_fs c) end. Fixpoint fs_inv (cmd : fs_cmd) := match cmd with | Open l c => Open l (fs_inv c) | Edit l k => Edit k l | Create t => Remove t | Remove t => Create t end. End FsCmd. Section Interpretation. Fixpoint raw_fs_interp (c : raw_fs_cmd) (t : tree T) : option (tree T) := let (v, cs) := t in let without v := filter (negb \o @by_value T v) in match c with | RawCreate tc => [! negb (has (by_value (value tc)) cs) !] Node v (insert R tc cs) | RawRemove tr => find (by_value (value tr)) cs >>= fun tr' => [! tr == tr' !] Node v (without' (value tr) cs) | RawOpen vo co => open R (fun t => raw_fs_interp co t) vo t | RawEdit ve ve' => find (by_value ve) cs >>= fun te => let cs' := without' ve cs in match te with | Node _ cste => [! negb (has (by_value ve') cs') !] Node v (insert R (Node ve' cste) cs') end end. Lemma interp_label_preserving c: label_preserving (raw_fs_interp c). move: c => [s s0|t |t |s r] [vt ts] /=. + by case find => [[]|] //=; case: has. + by case has. + by case find => [?|] //=; case eq_op. + by case find => [?|] //=; case raw_fs_interp. Qed. Lemma interp_label_indep v cs v' (op : raw_fs_cmd) t : raw_fs_interp op (Node v cs) = Some t -> raw_fs_interp op (Node v' cs) = Some (Node v' (children t)). by case: op v v' cs t => [l l'|c |c |l op] v v' cs [vt cst] /=; [case: find => [[??]|] //=; case: has | case has | case find => [?|] //=; case eq_op | case: bind => a]; move => //= [] [] ? ->. Qed. Corollary interp_some c t t': raw_fs_interp c t = Some t' -> value t = value t'. move: (interp_label_preserving c t); rewrite /label_preserving. by case: (raw_fs_interp _ _) => [a <- [] <-|]. Qed. Lemma raw_fs_interp_sorted c (t t' : tree T): is_tree_sorted R t -> raw_fs_interp (fs_to_raw_fs c) t = Some t' -> is_tree_sorted R t'. Ltac tc1 X := by (move: X => /= /andP []; try by rewrite -?sorted_compatibility). elim: c t t' => [l k|t1 |t1 |l c IH] [v cs] [v' cs'] A0 /=; try rewrite /without' -lock. + case A1: find => [[v'' cs'']| //] /=; case A2: has => [] //= [] A3 <-. rewrite insert_all sorted_compatibility insert_sorted /=. * move: A1 => /(find_sorted R v) A1. assert (A0' := A0). move: A0 => /A1 /= /andP [] -> ->. rewrite ?andb_true_r. apply all_filter. tc1 A0'. apply Rord. * apply sorted_filter. by expand_order (treeR_order _ Rord). tc1 A0. + move: t1 => [t1 H0]. case A1: has => //= [] [] ? <-. rewrite insert_all H0 sorted_compatibility insert_sorted. by move: A0 => /= /andP [] ? ->. apply Rord. tc1 A0. + case A1: find => [] //=; case A2: eq_op => [] //= [] ? <-. apply /andP. split. + rewrite sorted_compatibility. apply sorted_filter. by expand_order (treeR_order _ Rord). tc1 A0. + apply all_filter. tc1 A0. + case A1: find => [a|] //=. case A2: raw_fs_interp => [a'|] //= [] ? <-. assert (A0' := A0). move: A1 => /find_sorted A1. move: A0 => /(A1 R v) A0. move: A2 => /(IH _ _ A0) A2. rewrite sorted_compatibility insert_sorted /= ?insert_all ?A2 ?andb_true_r. * apply all_without. tc1 A0'. apply Rord. * apply without_sorted. apply Rord. tc1 A0'. Qed. Corollary raw_fs_interp_sorted_all c t t': is_tree_sorted R t -> exec_all (raw_fs_interp \o fs_to_raw_fs) (Some t) c = Some t' -> is_tree_sorted R t'. elim: c t => [|a c IH] t //=. + by move => A0 [] <-. + move => A0. rewrite /bind /flip. case A1: (raw_fs_interp (fs_to_raw_fs a) t) => [b|]. + apply (IH b (raw_fs_interp_sorted _ _ _ A0 A1)). + by rewrite exec_all_none. Qed. (* Inversion property IP1 *) Theorem ip1 c x y: is_tree_sorted R x -> raw_fs_interp c x = Some y -> raw_fs_interp (raw_fs_inv c) y = Some x. elim: c x y=> [ s c | t | t | s c IH] [l0 cs0] [l cs] S; assert (S' := S); move: S' => /= /andP [] S0 S1; rewrite sorted_compatibility in S0. + case A0: find => [[v1 cs1]|] /=; case A1: has => [] //= [] <- <- {l} /=. rewrite /without' -lock in A1. sop_simpl => /=. correct_label A0. rewrite insert_same //. apply Rord. + case A0: has => [] //= [] <- <- {l} /=. by sop_simpl. + case A0: find => [[v1 cs1]|] //=. case A1: eq_op => //= [] [] <- <- {l}. move: A1 => /eqP A1; subst. sop_simpl => /=. rewrite insert_same //. apply Rord. + rewrite /bind /=. case A0: find => [[v1 cs1]|] //=. correct_label A0. case A1: raw_fs_interp => [[v2 cs2]|] // [] <- <- {l}. move: (IH _ _ (find_sorted R _ _ _ _ S A0) A1) => A1'. correct_interp_label A1'. sop_simpl. rewrite A1'0. rewrite insert_same //. apply Rord. Qed. Lemma ip1_e v v' t mv mcs: sorted (treeR R) mcs -> find (by_value v) mcs = Some t -> has (by_value v') (without v mcs) = false -> (exec_all raw_fs_interp) (Some ((Node mv mcs))) ([:: RawEdit v v'; RawEdit v' v]) = Some (Node mv mcs). move: t => [v1 cs1] S A0 A1 /=; rewrite /bind /flip /= A0 /without' -lock A1 /=. correct_label A0. sop_simpl. rewrite /= insert_same //. apply Rord. Qed. End Interpretation. Section InsFs. Inductive ins_cmd := | Ins of T | IOpen of T & ins_cmd. Fixpoint ins_fs (cmd : ins_cmd) := match cmd with | Ins t => RawCreate (Node t [::]) | IOpen t c => RawOpen t (ins_fs c) end. Fixpoint ins_fs' (cmd : ins_cmd) := match cmd with | Ins t => Create (SNode R t) | IOpen t c => Open t (ins_fs' c) end. Lemma ins_fs_inj: injective ins_fs. by elim => [t1|t1 c1 IH] [t2|t2 c2] //= [] -> // /IH ->. Qed. Fixpoint eq_ins (t1 t2 : ins_cmd) : bool := match t1, t2 with | IOpen l c, IOpen l2 c2 => (l == l2) && (eq_ins c c2) | Ins t1, Ins t2 => t1 == t2 | _, _ => false end. Lemma eq_insK: @Equality.axiom ins_cmd eq_ins. elim => [t | l c IH] [t2| l2 c2] /=; (try by constructor); repeat (case A0: (eq_op _ _) => /=; move: A0 => /eqP); try constructor; subst => // A; try by case: A. + subst. case A0: (eq_ins); move: A0 => /IH; constructor; subst => // A. by case: A. Qed. Canonical ins_eqMixin := EqMixin eq_insK. Canonical ins_cmd_eqType := Eval hnf in EqType ins_cmd ins_eqMixin. Fixpoint subdiv (t : tree T) : seq (raw_fs_cmd) := match t with Node v cs => RawCreate (Node v [::]) :: (map (fun y => RawOpen v y) (flatten (map subdiv cs))) end. Fixpoint subdiv' (t : tree T) : seq (ins_cmd) := match t with Node v cs => Ins v :: (map (fun y => IOpen v y) (flatten (map subdiv' cs))) end. Lemma sd_step1 t v1 v2: exec_all raw_fs_interp t [:: RawCreate v1; RawCreate v2] = exec_all raw_fs_interp t [:: RawCreate v2; RawCreate v1]. rewrite /= /flip /=. case: t => [[t ts]|] //=. case A0: (has (by_value (value v1)) ts); case A1: (has (by_value (value v2)) ts) => //=; rewrite ?has_insert ?A0 ?A1 //= /by_value /= eq_sym insert_insert //. apply Rord. Qed. Corollary sd_commutes t v vs: exec_all raw_fs_interp t (map (fun t => RawCreate t) (v :: vs)) = exec_all raw_fs_interp t (map (fun t => RawCreate t) (rcons vs v)). elim: vs v t => [|v0 vs IH] v t //. rewrite 2!map_cons 2!exec_all_ind. move: (sd_step1 t v0 v) => A1; rewrite /= /flip in A1. rewrite -A1. remember (bind (raw_fs_interp (RawCreate v0)) t) as l1. move: (IH v l1) => A2; rewrite /= /flip in A2. by rewrite A2 Heql1 rcons_cons. Qed. Local Notation insert_sorted := (insert_sorted R Rord). Local Notation without_sorted := (without_sorted R Rord). Lemma sd_open (cmds : seq raw_fs_cmd) vs cs v: sorted (treeR R) cs -> has (by_value v) cs -> exec_all raw_fs_interp (Some (Node vs cs)) ((map (fun c => RawOpen v c) cmds)) = open R ((flip (exec_all raw_fs_interp) cmds) \o (fun t => Some t)) v (Node vs cs). elim: cmds vs cs => [|c cmds IH] /= vs cs A0. + move => /has_find [a A1]; rewrite A1 /= insert_same //. apply Rord. + move => A1. assert (A1':=A1). move: A1' => /has_find [[vx xs]] A2. rewrite /flip /= A2 /flip /bind /=. case A3: (raw_fs_interp c _) => [[av acs]|] /=; [| by rewrite ?exec_all_none]. rewrite IH //; try (by apply insert_sorted, without_sorted); (move: A2 A3 => /find_pred; rewrite /by_value /= => /eqP -> /=); [|by move => /interp_some /= ->; rewrite has_insert /= eq_refl orb_true_r]. rewrite /flip /bind => /interp_some /= ->. sop_simpl. case A2: (exec_all _ _) => [a|] //. Qed. Lemma open_create v: (fun t => RawOpen v (RawCreate t)) =1 (fun c => RawOpen v c) \o (fun t => RawCreate t). by rewrite /eqfun /=. Qed. Lemma create_many v xs: sorted (treeR R) xs -> exec_all raw_fs_interp (Some (Node v [::])) [seq RawCreate t | t <- xs] = Some (Node v xs). elim: xs => [|x xs IH] // A0. rewrite /flip sd_commutes map_rcons exec_all_rcons_ind IH /=; try by move: A0 => /path_sorted. assert (A0' := A0). move: A0' => /= /path_has -> /=. rewrite /insert g_insert_path //. apply treeR_order, Rord. apply Rord. Qed. Lemma subdivision_step: forall t v xs, is_tree_sorted R (Node v xs) -> is_tree_sorted R t -> exec_all raw_fs_interp (Some t) ((RawCreate (Node v [::])) :: (map (fun t => RawOpen v (RawCreate t)) xs)) = raw_fs_interp (RawCreate (Node v xs)) t. move => [vt tcs]; intros. rewrite (@eq_map _ _ _ _ (open_create v)) exec_all_ind map_comp. move A0: (bind (raw_fs_interp (RawCreate (Node v [::]))) (Some (Node vt tcs))) => [[va csa]|] //=; move: A0 => /=; case A0: (has _ _) => //=; [move => [] [] -> <-| by rewrite exec_all_none]. + rewrite sd_open. rewrite /flip /= without_insert_i //. sop_simpl. rewrite /= create_many ?has_without //. + use_sortedness H. + use_sortedness H0. apply Rord. + by rewrite has_insert /by_value /= eq_refl orb_true_r. Qed. Lemma insert_subdivision: forall c t, is_tree_sorted R t -> is_tree_sorted R c -> exec_all raw_fs_interp (Some t) (subdiv c) = raw_fs_interp (RawCreate c) t. elim => [v|v cs IH] [vt ts] A0 A1. + by rewrite /= /flip /bind /=. + rewrite -subdivision_step //. simpl subdiv. rewrite ?exec_all_cons. move A2: (raw_fs_interp _ _) => [[a1 as1]|]; rewrite ?exec_all_none //. move: A2 => /=. case A2: has => [] //= [] ? <-. rewrite (@eq_map _ _ _ _ (open_create v)) map_comp ?sd_open; try (by rewrite insert_has_t // ?/by_value /= eq_refl); try (by rewrite insert_sorted //; move: A0 => /= /andP []; rewrite sorted_compatibility). rewrite /flip /= /bind /=. case A3: (find (by_value v) _) => [a|] //. assert (A3': is_tree_sorted R a). + move: A3 => /=. by sop_simpl => [] [] <-. clear A3. elim: cs IH A0 A1 a A3' => [|c cs IHcs] IH A0 A1 a A3' //. rewrite ?map_cons /= /flip /bind. move: IH => [] A4 A5. rewrite exec_all_cat A4. move A6: (raw_fs_interp _ a) => [a'|]. move: A5 => /IHcs A5. apply (A5 A0). * by move: A1 => /= /andP [] /path_sorted -> /andP [] ? ->. * move: A1 => /= /andP [] ? /andP [] A1 ?. case: a A6 A3' => [va csa] /=. case: (has _ _ ) => [] //=; try by rewrite exec_all_none. case => <-. * move => /andP [] A6 A7 /=. by rewrite sorted_compatibility insert_sorted ?andb_true_l ?insert_all ?A7 // -sorted_compatibility. * by rewrite ?exec_all_none. * done. * by move: A1 => /= /andP [] ? /andP []. Qed. Fixpoint ins_it (x y : ins_cmd) (f : bool) : seq ins_cmd := match x, y with | Ins t1, Ins t2 => if (t1 == t2) then [::] else [::Ins t1] | IOpen t1 c1, IOpen t2 c2 => if t1 == t2 then map (IOpen t1) (ins_it c1 c2 f) else [:: x] | _, _ => [::x] end. Lemma ins_it1 i1 i2 f: ins_it i1 i2 f = if (i1 == i2) then [:: ] else [:: i1]. elim: i1 i2 => [t1|t1 c1 IH] [t2|t2 c2] //=. case A0: eq_op. + move: A0 (IH c2) => /eqP -> ->. rewrite /eq_op /= eq_refl. by case eq_ins. + by rewrite /eq_op /= A0. Qed. Lemma subdiv_l1 l1 x2: uniq l1 -> exists n, transform ins_it l1 [:: x2] n = Some ([:: x2] \ l1, l1 \ [:: x2]). elim: l1 => [|x1 l1 IH] U. rewrite ?seqminus_nil seqminus_nil'. by exists 1. move: U => /= /andP [] B0 B1. move: (IH B1) => [] n A0. exists (n.+2). remember (n.+1) as n1. simpl. rewrite ?ins_it1 eq_sym. move: B0. case A1: eq_op. move: A1 => /eqP -> /=. rewrite Heqn1 2!TransformApp.tr_through_nil /= /in_mem /= eq_refl /= => B0. by rewrite seqminus_singleton. rewrite Heqn1 => B0. apply tstab with (k:=1) in A0. move: A0. rewrite addn1 => ->. by rewrite TransformApp.tr_through_nil /= /in_mem /= eq_sym A1 /= cats0. Qed. Lemma subdiv_it l1 l2: uniq l1 -> uniq l2 -> exists n, @transform ins_cmd ins_it l1 l2 n = Some (l2 \ l1, l1 \ l2). elim: l2 l1 => [|x2 l2 IH] [|x1 l1] //=; rewrite ?seqminus_nil; try by exists 1. move => B1 /andP [] B2 B2'. move: B1 => /andP [] B1 B1'. move: (IH (l1) B1' B2') => [n' A0']. move: (subdiv_l1 l1 x2 B1') => [n01 A01]. assert (U: uniq (x1 :: l1 \ [:: x2])). rewrite /=. apply /andP. split. + by rewrite /seqminus mem_filter (negbTE B1) andb_false_r. + by apply uniq_setminus. move: (IH (x1 :: l1 \ [:: x2]) U B2') => [n02 A02]. remember (n01 + n02) as n. exists ((n'+n).+2). remember ((n'+n).+1) as n1. simpl. rewrite ?ins_it1 eq_sym. case A1: eq_op => /=. + move: A1 B2 => /eqP <- B2. rewrite Heqn1 TransformApp.tr_through_nil -Heqn1 /=. apply tstab with (k:=n+1) in A0'. move: A0'. rewrite addnA addn1 Heqn1 => ->. by rewrite /in_mem /= eq_refl /= ?seqminus_cons. + apply tstab with (k:=n02 + n' +1) in A01. move: A01. rewrite 2!addnA -Heqn addn1 addnC -Heqn1 => ->. apply tstab with (k:=n01 + n' +1) in A02. move: A02. rewrite ?addnA (addnC n02) -Heqn addn1 addnC -Heqn1 => ->. rewrite /in_mem /= eq_sym A1 /= /in_mem /=. case C0: ([eta mem_seq l1] x2); case C1: ([eta mem_seq l2] x1) => /=; rewrite ?seqminus_cat /=; (rewrite -(seqminus_cons' l1 [::x2] x1); [rewrite seqminus_p1; try done| by rewrite /in_mem /= A1]). Qed. Lemma subdiv_prime x: subdiv x = map ins_fs (subdiv' x). elim: x => [x|x xs IH] //=. elim: xs IH => [|x' xs IH'] IH //=. rewrite ?map_cat /=. move: IH => /= [] IH0 IH1. apply IH' in IH1. clear IH'. move: IH1 IH0 => [] <- ->. rewrite -?map_comp. assert (A0: [eta RawOpen x] \o ins_fs =1 ins_fs \o [eta IOpen x]). by move => ? /=. by rewrite (@eq_map _ _ _ _ A0). Qed. End InsFs. Definition merge_trees (x y : tree T) : seq raw_fs_cmd := (subdiv x) \ (subdiv y). Fixpoint raw_fs_it (x y : raw_fs_cmd) (f : bool) : seq raw_fs_cmd := let instead a b := [:: raw_fs_inv a; b] in match x, y with | RawEdit xl xk, RawEdit yl yk => match xl == yl, xk == yk with | false, false => [:: x] | true, true => [::] | true, false => (if f then [::] else [:: RawEdit yk xk]) | false, true => [:: RawEdit yk yl] end | RawEdit xl xk, RawCreate yt => if xk == value yt then instead y x else [:: x] | RawCreate xt, RawEdit yl yk => if value xt == yk then [::] else [:: x] | RawOpen xl xc, RawOpen yl yc => if xl == yl then map (RawOpen xl) (raw_fs_it xc yc f) else [:: x] | RawRemove xt, RawRemove yt => if value xt == value yt then [::] else [:: x] | RawRemove xt, RawOpen yl yc => if value xt == yl then if raw_fs_interp yc xt is Some t then [:: RawRemove t] else [::] else [:: x] | RawOpen xl xc, RawRemove yt => if value yt == xl then [::] else [:: x] | RawOpen xl xc, RawEdit yl yk => if xl == yl then [:: RawOpen yk xc ] else [:: x] | RawEdit xl xk, RawRemove yt => if xl == value yt then [::] else [:: x] | RawRemove xt, RawEdit yl yk => if yl == value xt then [:: RawRemove (Node yk (children xt)) ] else [:: x] | RawCreate xt, RawCreate yt => if value xt == value yt then merge_trees xt yt else [:: x] | _, _ => [:: x] end. Lemma ins_fs_comp i1 i2 f: raw_fs_it (ins_fs i1) (ins_fs i2) f = map ins_fs (ins_it i1 i2 f). elim: i1 i2 => [t1|t1 c1 IH] [t2|t2 c2] //=; case A0: eq_op => //=. + move: A0 => /eqP ->. by rewrite /merge_trees /= /in_mem /= eq_refl. + rewrite IH -?map_comp. apply eq_map. by rewrite /eqfun. Qed. Section PropertyC1. Definition C1' (op1 op2 : raw_fs_cmd) := forall (f : bool) m (m1 m2 : tree T), is_tree_sorted R m -> raw_fs_interp op1 m = Some m1 -> raw_fs_interp op2 m = Some m2 -> let m21 := (exec_all raw_fs_interp) (Some m2) (raw_fs_it op1 op2 f) in let m12 := (exec_all raw_fs_interp) (Some m1) (raw_fs_it op2 op1 (~~f)) in m21 = m12 /\ exists node, m21 = Some node. Lemma c1_r_r t s: C1' (RawRemove t) (RawRemove s). move => f [v cs] [v' cs'] [v'' cs''] ?. case A0: (eq_op (value s) (value t)); move: A0; [move => /eqP| move => A0]. + simpl => ->. rewrite eq_refl. case A1: find => [a| //] /=. repeat (case: eq_op => //=). move => <- <-. by split; eauto. + simpl raw_fs_it. rewrite eq_sym A0 /= /flip /bind /=. case A1: find => [tr'|]; case A2: find => [tr''|] //=; case A3: eq_op; case A4: eq_op => //=. repeat (case => -> <-). rewrite /without' -lock ?find_filter ?A1 ?A2 /= ?A3 ?A4 /=; [|apply by_diff_values; rewrite eq_sym| apply by_diff_values] => //. rewrite without_without. eauto. Qed. Lemma c1_c_r tc tr: C1' (RawCreate tc) (RawRemove tr). move => f [v cs] [v' cs'] [v'' cs''] S /=. case A0: has => //= [] [] <- <-. case A1: find => [a|] //=. case A2: eq_op => //=. move: A2 => /eqP -> [] <- <-. rewrite /flip /bind /=. move: (find_pred A1); rewrite {1}/by_value /= => /eqP <-. case A2: (eq_op (value tc) (value tr)). + move: A2 A0 => /eqP ->. move /find_absent. by rewrite A1. + rewrite /without' -lock has_filter ?A0 /=; [|by (apply by_diff_values; rewrite eq_sym)]. sop_simpl. rewrite A1 /= eq_refl /= -without_insert; [ eauto | by apply Rord | by use_sortedness S | by rewrite A2]. Qed. Lemma c1_c_e tc ve ve': C1' (RawCreate tc) (RawEdit ve ve'). move => f [v cs] [v' cs'] [v'' cs''] S /=. rewrite /without' -lock. case A0: has => //= [] [] <- <-. case A1: find => [[av acs]|] //=. case A2: has => [] //= [] <- <-. rewrite eq_sym. case A3: (ve' == value tc) => /=; rewrite /flip /bind /=. + move: A3 A2 => /eqP -> A2. sop_simpl. rewrite A1 /= A2 /=. eauto. + assert (H0: (value tc) == ve = false). by (case H1: eq_op => //; move: H1 A1 A0 => /eqP <- /find_has ->). rewrite has_insert {2}/by_value /= eq_sym A3 orb_false_r; sop_simpl. rewrite A0 /= A1 /= -without_insert; try by apply Rord. + rewrite has_insert /by_value /= A3 orb_false_r A2 /= insert_insert. + rewrite eq_sym A3 /=. eauto. + apply Rord. + use_sortedness S. + by rewrite H0. Qed. Lemma c1_r_e tr ve ve': C1' (RawRemove tr) (RawEdit ve ve'). move => f [v cs] [v' cs'] [v'' cs''] /= S. rewrite /without' -lock. case A0: find => //= [a]. case A1: eq_op => //=. move: A1 A0 => /eqP <- A0 {a} [] <- <-. case A1: find => //= [[va csa]]. case A2: has => //= [] [] <- <-. assert (A1':=A1). move: A1' A1 => /find_by_value <- A1. case A3: eq_op => //=; rewrite /flip /bind /=. + sop_simpl. move: A3 A1 A2 => /eqP -> /=. rewrite A0 => [] [] -> /= A2. sop_simpl. eauto. + assert (H0: (value tr == ve') = false). (case H1: eq_op => //; move: H1 A0 A2 => /eqP <- /find_has; sop_simpl => -> //). sop_simpl. rewrite A0 /= eq_refl /=. rewrite A1 /= without_without. sop_simpl. rewrite A2 /= -without_insert /=; [ eauto | | use_sortedness S | rewrite eq_sym H0 //]; apply Rord. Qed. Lemma c1_e_e ve ve' vf vf': C1' (RawEdit vf vf') (RawEdit ve ve'). move => f [v cs] [v' cs'] [v'' cs''] /= S. rewrite /without' -lock. assert (H: sorted (T:=tree_eqType T) (treeR R) cs) by use_sortedness S. case A0: find => //= [[fa fcs]]. case A1: has => //= [] [] <- <-. case A0': find => //= [[ea ecs]]. case A1': has => //= [] [] <- <-. rewrite eq_sym. case A2: eq_op => /=; rewrite eq_sym; case A2': eq_op => /=. + move: A2 A2' => /eqP A2 /eqP A2'; subst. by move: A0 A0' => -> [] ? <-; eauto. + move: A2 => /eqP A2; subst; case f; rewrite /= /bind /flip /=; sop_simpl; rewrite ?A1' ?A1 /=; by move: A0 A0' => -> [] ? ->; eauto. + move: (ip1_e vf vf' _ v _ H A0 A1). move: (ip1_e ve ve' _ v _ H A0' A1'). by rewrite /= {2 4}/flip {2 4}/bind /= A0 A0' /= /without' -lock A1 A1' /= => -> ->; eauto. + rewrite /= /bind /flip /= /without' -lock . case A3: (vf == ve'). * move: A3 => /eqP A3. by assert False; by move: A0 A1' => /find_has; sop_simpl => ->. * case A4: (ve == vf'). * move: A4 => /eqP A4. subst. rewrite without_has' // in A1. apply find_has in A0'. by rewrite A0' in A1. by rewrite eq_sym A2. * sop_simpl; rewrite A0 A0' /=. rewrite -?without_insert /=; try (by rewrite eq_sym ?A3 ?A4); try apply without_sorted => //; try by apply Rord. rewrite ?insert_has_f /=; try rewrite /by_value //= eq_sym //. rewrite (without_without vf); sop_simpl; rewrite A1. rewrite (without_without ve); sop_simpl; rewrite A1' /=. rewrite insert_insert; eauto. apply Rord. Qed. Lemma c1_o_e vc vc' vo op1: C1' (RawOpen vo op1) (RawEdit vc vc'). move => f [v cs] [v' cs'] [v'' cs''] /= S. rewrite /without' -lock. case A0: bind => [a|] // [] <- <-. case A1: find => [[bv bcs]|] //=. move: (find_pred A1); rewrite {1}/by_value /= => /eqP H0; subst. case A2: has => //= [] [] <- <-. case A3: eq_op => /=. + move: A3 => /eqP A3. subst. rewrite /flip /bind /=. sop_simpl; destruct a as [va csa]. rewrite A1 /= in A0. correct_interp_label A0. sop_simpl; rewrite A2 /=. eauto. + rewrite /flip /bind /=. case A4: (vc' == vo). * move: A4 => /eqP A4. subst. move: A2 A0. rewrite eq_sym in A3. by rewrite without_has' // => /find_absent ->. * rewrite find_insert_f //; [|by rewrite /by_value /= eq_sym A4]. sop_simpl; rewrite A0. case: a A0 => [va csa]. case A5: find => [[vc ccs]|] //=. correct_label A5 => A0. assert (A0' := A0). move: A0' => /interp_label_indep /= A0'. move: A0. rewrite ?A0' => [] [] A0. sop_simpl; rewrite A1. rewrite -(without_insert Rord _ bv) /=; [| by use_sortedness S; apply Rord| by rewrite A3]. rewrite without_without. rewrite insert_has_f; [|by rewrite /by_value /= A4]. sop_simpl. rewrite A2 /=. rewrite -without_insert /=; [| |use_sortedness S | by rewrite A4]; try by apply Rord. rewrite insert_insert. eauto. apply Rord. Qed. Lemma c1_o_r s vo op1: C1' (RawOpen vo op1) (RawRemove s). move => f [v cs] [v' cs'] [v'' cs''] /= S. rewrite /without' -lock /=. case A0: find => [[ev ecs]|] //=. correct_label A0. case A1: raw_fs_interp => [[av acs]|] //= [] <- <-. correct_interp_label A1. case A1: find => [[bv bcs]|] //=. case A3: eq_op => [] //=; move: A3 A1 => /eqP -> /= A1 {s} [] <- <-. case A4: eq_op => [] /=. + move: A4 => /eqP A4; subst. move: A0. rewrite A1 => [] [] A3; subst. rewrite A2 /= /bind /flip /=. sop_simpl; eauto. + rewrite /flip /=. sop_simpl; rewrite A0 /= A2 A1 /= eq_refl -without_insert; [ rewrite without_without; eauto | | use_sortedness S | rewrite eq_sym A4 //]; apply Rord. Qed. Lemma c1_o_c s vo op1: C1' (RawOpen vo op1) (RawCreate s). move => f [v cs] [v' cs'] [v'' cs''] /= S. case A0: find => [[av acs]|] //=. correct_label A0. case A1: raw_fs_interp => [[bv bcs]|] //=. correct_interp_label A1 => [] [] <- <-. case A1: has => [] //= [] <- <-. rewrite /flip /= /bind /=. case A3: ((value s) == bv). + by move: A3 A0 A1=> /eqP <- /find_has ->. + rewrite find_insert_f; [| by rewrite /by_value /= eq_sym]. rewrite A0 A2 insert_has_f;[| by rewrite /by_value /=]. sop_simpl; by rewrite /= A1 /= -without_insert; [ rewrite insert_insert; eauto | | use_sortedness S | rewrite /= A3 //]; apply Rord. Qed. Lemma C1'_C c1 c2: C1' c1 c2 -> C1' c2 c1. rewrite /C1'; intros. move: (H (~~f) m m2 m1 H0 H2 H1) => [] => ->. rewrite negb_involutive; eauto. Qed. Lemma c1_o_o op1 op2: C1' op1 op2 -> (forall l1 l2, C1' (RawOpen l1 op1) (RawOpen l2 op2)). move => IH; intros. rewrite /C1' => f [v cs] [v' cs'] [v'' cs''] S /=. rewrite eq_sym. case A3: eq_op. * move: A3 => /eqP A3; subst. move A0: (find (by_value l1) cs) => [[vf csf]|] //=. case A1: raw_fs_interp => [[va csa]|] //= [] [] <- <-. case A2: raw_fs_interp => [[vb csb]|] //= [] [] <- <-. move: (find_sorted R v _ _ _ S A0) => SF. move: (IH f (Node vf csf) _ _ SF A1 A2) => /= IH0. move: (find_pred A0) => H. rewrite /by_value /= in H. move: H A0 => /eqP -> A0. move: (interp_some _ _ _ A1) (interp_some _ _ _ A2) => /= H1 H2; subst; subst. rewrite ?sd_open; try (by rewrite insert_has_t // /by_value /= eq_refl); try (by use_sortedness S; apply Rord). rewrite /flip /= /bind /=. sop_simpl; move: IH0 => [] -> [] x ->. eauto. * rewrite /bind /=. case A1: find => [[va csa]|] //=. case A2: find => [[vb csb]|] //=. case A4: raw_fs_interp => [[ve cse]|] //= [] [] <- <-. case A5: raw_fs_interp => [[vf csf]|] //= [] [] <- <-. move: (interp_some _ _ _ A4) (interp_some _ _ _ A5) => /= H1 H2; subst; subst. correct_label A1. correct_label A2. rewrite /= /flip /= /bind /=. sop_simpl; rewrite A1 A2 A4 A5. rewrite -(without_insert Rord _ ve) /=; [| by use_sortedness S; apply Rord |by rewrite A3]. rewrite -(without_insert Rord _ vf) /=; [| by use_sortedness S; apply Rord |by rewrite eq_sym A3]. rewrite insert_insert. rewrite without_without. eauto. apply Rord. Qed. Ltac elem_case := first [apply c1_e_e | apply c1_c_e | apply c1_r_e | apply c1_o_e | apply c1_o_r | apply c1_r_e | apply c1_r_r | apply c1_c_r | apply c1_o_c | apply c1_o_o]. Ltac elem_or_sym := (try by elem_case); (try by apply C1'_C; elem_case). Ltac ii := let A0 := fresh "A0" in let A1 := fresh "A1" in let A2 := fresh "A2" in move => f [v cs] [v' cs'] [v'' cs''] S; simpl raw_fs_it; rewrite eq_sym; case A0: eq_op; [rewrite -?insert_subdivision /merge_trees // => A1 A2; rewrite -A1 -A2 | simpl; case A1: has => //= [] [] <- <-; case A2: has => //= [] [] <- <-; rewrite /flip /=; rewrite ?insert_has_f /=; (try by rewrite /by_value /= ?A0 // eq_sym ?A0); rewrite A1 A2 /= insert_insert; eauto]. Lemma c1_ins op1 op2: C1' (ins_fs op1) (ins_fs op2). elim: op1 op2 => [t1|t1 c1 IH] [t2|t2 c2] /=; elem_or_sym. + ii. rewrite -?exec_all_cat. move: A0 A1 => /eqP ->; rewrite /= /in_mem /= eq_refl /= => /= ->. eauto. apply Rord. Qed. Definition ins_interp (c : ins_cmd) (t : sorted_tree R) : option (tree T) := raw_fs_interp (fs_to_raw_fs (ins_fs' c)) (treeOf t). Definition sorted_option (x : option (tree T)) := match x with None => true | Some t => is_tree_sorted R t end. Lemma so_from_sorted (c : fs_cmd) t: is_tree_sorted R t -> sorted_option (raw_fs_interp (fs_to_raw_fs c) t). case A0: (raw_fs_interp (fs_to_raw_fs c) t) => [t'|] A1 //=. exact (raw_fs_interp_sorted _ _ _ A1 A0). Qed. Definition so_st (t : option (tree T)): sorted_option t -> option (sorted_tree R). case: t => [t|] /= A0. exact (Some (STree R t A0)). exact None. Defined. Lemma fmap_so_st t S: (fmap (@treeOf T R)) (so_st t S) = t. rewrite /so_st. by dependent destruction t. Qed. Definition ins_sorted (c : ins_cmd) (t : sorted_tree R) : option (sorted_tree R). move: t => [t S]. apply (so_st (raw_fs_interp (fs_to_raw_fs (ins_fs' c)) t)), so_from_sorted, S. Defined. Lemma ins_sorted_treeOf c (s : sorted_tree R): (fmap (@treeOf T R)) (ins_sorted c s) = ins_interp c s. rewrite /ins_sorted. case: s => [t S] /=. by rewrite fmap_so_st /ins_interp. Qed. Lemma ins_compat x: fs_to_raw_fs (ins_fs' x) = ins_fs x. elim: x => [t|t c IH] //=. by rewrite IH. Qed. Corollary ins_compat': fs_to_raw_fs \o ins_fs' =1 ins_fs. apply /ins_compat. Qed. Lemma exec_ins_compat: forall c s, (fmap (@treeOf T R)) (exec_all ins_sorted (Some s) c) = exec_all (raw_fs_interp \o ins_fs) (Some (treeOf s)) c. apply (@last_ind ins_cmd (fun c => forall s, fmap (@treeOf T R) (exec_all ins_sorted (Some s) c) = exec_all (raw_fs_interp \o ins_fs) (Some (treeOf s)) c)). + done. + intros s x IH s'. rewrite 2!exec_all_rcons_ind /= /bind /flip -IH. case A0: exec_all => [b|] //=. by rewrite ins_sorted_treeOf /ins_interp ins_compat. Qed. Lemma ins_fs_fs'_compat m c: exec_all (raw_fs_interp \o fs_to_raw_fs) m (map ins_fs' c) = exec_all (raw_fs_interp \o ins_fs) m c. case: m => [m|]. + by rewrite (exec_all_compat _ ins_fs') (exec_all_eqfun (compA _ _ _)) (exec_all_eqfun (eq_comp (frefl _) ins_compat')). + by rewrite ?exec_all_none. Qed. Theorem c1: forall (op1 op2 : ins_cmd) (f : bool) (m m1 m2 : sorted_tree R), ins_sorted op1 m = Some m1 -> ins_sorted op2 m = Some m2 -> let m21 := exec_all ins_sorted (Some m2) (ins_it op1 op2 f) in let m12 := exec_all ins_sorted (Some m1) (ins_it op2 op1 (~~ f)) in m21 = m12 /\ (exists node : sorted_tree R, m21 = Some node). intros. rewrite /m21 /m12 => {m12} {m21}. case: m m1 m2 H H0 => [m S] [m1 S1] [m2 S2]. move /opt_eq => H. rewrite ins_sorted_treeOf /= in H. move /opt_eq => H0. rewrite ins_sorted_treeOf /= in H0. move: H H0. rewrite ?ins_sorted_treeOf /= /ins_interp /=? ins_compat => /= H H0. move: (c1_ins op1 op2 f m m1 m2 S H H0) => [] A0 A1. split. + apply opt_eq. by rewrite ?exec_ins_compat /= -?(exec_all_compat raw_fs_interp ins_fs) -?ins_fs_comp A0. + move: A1 => [t]. rewrite ins_fs_comp exec_all_compat -ins_fs_fs'_compat => A1. assert (A1' := A1). move: A1 => /raw_fs_interp_sorted_all A1. exists (STree R t (A1 S2)) => /=. apply opt_eq. by rewrite /= -A1' exec_ins_compat ins_fs_fs'_compat /=. Qed. Instance insOT': (OTBase (sorted_tree R) ins_cmd) := {interp := ins_sorted; it := ins_it; it_c1:=c1}. Definition firstP (x : ins_cmd) := match x with | Ins t => t | IOpen t c => t end. Lemma firstP_subdiv' c xs: c \in flatten [seq subdiv' i | i <- xs] -> firstP c \in map value xs. elim: xs => [|x xs IH] //=. rewrite mem_cat. case A0: in_mem => /=. + move => ?. destruct x. move: A0 => /=. move: (flatten _) => f. destruct c => /=; rewrite /in_mem /=. + case A0: eq_op. + move: A0 => /eqP [] ->. by rewrite eq_refl. + by elim: f. + elim: f => //= f fs IHf. case A0: eq_op. + move: A0 => /eqP [] ->. by rewrite eq_refl. + by rewrite orb_false_l. + move => /IH. rewrite /in_mem /= => ->. by rewrite orb_true_r. Qed. Lemma uniq_subdiv' {s}: is_tree_sorted R s -> uniq (subdiv' s). expand_order Rord. elim: s => [x|x xs IH] //= /andP [] /(sorted_uniq H2 H0) A0 A1. apply /andP. split. + by elim: flatten. + assert (injective [eta IOpen x]). by move => ?? []. rewrite (map_inj_uniq H3). elim: xs A1 A0 IH => [|x' xs IH] //= /andP [] A0 A1 /andP [] A2 A3 [] A4 A5. move: (IH A1 A3 A5) => A6 {IH}. rewrite cat_uniq A6 andb_true_r (A4 A0) /=. apply /negP => /hasP /= [c A7 A8]. apply firstP_subdiv' in A7. move: (firstP_subdiv' c [::x']) => /=. rewrite cats0 => A9. apply A9 in A8. clear A9. by case: c A8 A7 => [v|v c] /=; rewrite {1}/in_mem /= orb_false_r => /eqP ->; rewrite (negbTE A2). Qed. Lemma c1_c_c t s : is_tree_sorted R s -> is_tree_sorted R t -> C1' (RawCreate t) (RawCreate s). move => S1 S2. ii. move: (subdiv_it _ _ (uniq_subdiv' S1) (uniq_subdiv' S2)) => [n B0]. move: A1 A2. rewrite ?subdiv_prime ?(exec_all_compat raw_fs_interp ins_fs) -?map_seq_minus; try by apply ins_fs_inj. move => A1 A2. assert (B1 := A1). assert (B2 := A2). rewrite -ins_fs_fs'_compat in A1. rewrite -ins_fs_fs'_compat in A2. move: (raw_fs_interp_sorted_all _ _ _ S A1) => SA1. move: (raw_fs_interp_sorted_all _ _ _ S A2) => SA2. Ltac tc2 := apply opt_eq; rewrite /= exec_ins_compat /=; by rewrite -ins_fs_fs'_compat. assert (H: exec_all ins_sorted (Some {| treeOf := Node v cs; stp := S |}) (subdiv' s) = Some {| treeOf := Node v'' cs''; stp := SA2 |}). by tc2. assert (H2: exec_all ins_sorted (Some {| treeOf := Node v cs; stp := S |}) (subdiv' t) = Some {| treeOf := Node v' cs'; stp := SA1 |}). by tc2. move: (ot_execution insOT' n (subdiv' s) (subdiv' t) (subdiv' s \ subdiv' t) (subdiv' t \ subdiv' s) (Some (STree R _ S)) (STree R _ SA2) (STree R _ SA1) (conj H H2) B0) => [] C1 C2. by split; [move: C1 | move: C2 => [[m3t S3]] /= C2; exists m3t; move: C2]; move => /opt_eq /=; rewrite ?exec_ins_compat /= -?A1 -?A2 ?ins_fs_fs'_compat ?(exec_all_compat _ ins_fs). apply Rord. Qed. Theorem c1' (op1 op2 : fs_cmd): C1' (fs_to_raw_fs op1) (fs_to_raw_fs op2). elim: op1 op2 => [l1 l1'|c1|c1|l1 op1 IH] [l2 l2'|c2|c2|l2 op2]; (try by elem_case); (try by apply C1'_C; elem_case). + apply c1_c_c. destruct c2. apply stp. destruct c1. apply stp. Qed. End PropertyC1. Section Computability. Fixpoint raw_fs_sz0 (x : raw_fs_cmd) := match x with | RawOpen l c => raw_fs_sz0 c | RawEdit l c => 1 | RawCreate t => weight t | RawRemove t => 1 end. Fixpoint raw_fs_si0 (x : raw_fs_cmd) := match x with | RawOpen l c => raw_fs_si0 c | RawEdit l c => 0 | RawCreate t => weight t | RawRemove t => 0 end. Lemma sz0_open y: raw_fs_sz0 =1 raw_fs_sz0 \o (RawOpen y). by rewrite /eqfun => [] []. Qed. Lemma si0_open y: raw_fs_si0 =1 raw_fs_si0 \o (RawOpen y). by rewrite /eqfun; case. Qed. Definition raw_fs_sz (x : seq raw_fs_cmd) := foldl addn 0 (map raw_fs_sz0 x). Definition raw_fs_si (x : seq raw_fs_cmd) := foldl addn 0 (map raw_fs_si0 x). Lemma fs_sz_cons x xs: raw_fs_sz (x :: xs) = raw_fs_sz0 x + raw_fs_sz xs. by rewrite /raw_fs_sz /= add0n (fadd (raw_fs_sz0 x)). Qed. Lemma fs_si_cons x xs: raw_fs_si (x :: xs) = raw_fs_si0 x + raw_fs_si xs. by rewrite /raw_fs_si /= add0n (fadd (raw_fs_si0 x)). Qed. Lemma fs_sz_cat xs1 xs2: raw_fs_sz (xs1 ++ xs2) = raw_fs_sz xs1 + raw_fs_sz xs2. elim: xs1 xs2 => [|x xs1 IH] xs2 //=. by rewrite ?fs_sz_cons IH addnA. Qed. Lemma fs_si_cat xs1 xs2: raw_fs_si (xs1 ++ xs2) = raw_fs_si xs1 + raw_fs_si xs2. elim: xs1 xs2 => [|x xs1 IH] xs2 //=. by rewrite ?fs_si_cons IH addnA. Qed. Corollary sz_open s l: raw_fs_sz [seq RawOpen s i | i <- l] = raw_fs_sz l. case: l => [|l ls] //=. move Heqf: (RawOpen s) => f. by rewrite /raw_fs_sz /= -map_comp -Heqf (eq_map (sz0_open s)). Qed. Corollary si_open s l: raw_fs_si [seq RawOpen s i | i <- l] = raw_fs_si l. case: l => [|l ls] //=. move Heqf: (RawOpen s) => f. by rewrite /raw_fs_si /= -map_comp -Heqf (eq_map (si0_open s)). Qed. Lemma weight_subdiv t1: weight t1 = raw_fs_sz (subdiv t1). elim: t1 => [] //= v cs. elim: cs => [|c cs IH2] [] // A0 A1. apply IH2 in A1. move: A1. rewrite map_cons /= map_cat ?fs_sz_cons fs_sz_cat ?sz_open -A0. rewrite (addnA _ (weight c)) (addnC _ (weight c)) -addnA => <-. by rewrite ?weight_Node ?weights_cons addnA. Qed. Lemma weight_subdiv_si t1: weight t1 = raw_fs_si (subdiv t1). elim: t1 => [] //= v cs. elim: cs => [|c cs IH2] [] // A0 A1. apply IH2 in A1. move: A1. rewrite map_cons /= map_cat ?fs_si_cons fs_si_cat ?si_open -A0. rewrite (addnA _ (weight c)) (addnC _ (weight c)) -addnA => <-. by rewrite ?weight_Node ?weights_cons addnA. Qed. Lemma sz_weight t1 t2: raw_fs_sz (merge_trees t1 t2) <= weight t1. rewrite /merge_trees /raw_fs_sz. move: (sum_setminus raw_fs_sz0 (subdiv t1) (subdiv t2)). by rewrite weight_subdiv /raw_fs_sz. Qed. Lemma si_weight t1 t2: raw_fs_si (merge_trees t1 t2) <= weight t1. rewrite /merge_trees /raw_fs_si. move: (sum_setminus raw_fs_si0 (subdiv t1) (subdiv t2)). by rewrite weight_subdiv_si /raw_fs_si. Qed. Lemma weight_nonzero (t : tree T): weight t > 0. by case: t => t l; rewrite /weight /encode. Qed. Theorem OT_C op1 op2: computability raw_fs_it raw_fs_sz raw_fs_si op1 op2. rewrite /computability. elim: op1 op2 => [s1 c1|t1|t1|s1 r1 IH] [s2 c2|t2|t2|s2 r2] f; try (case: f => [] /=; rewrite (eq_sym (value t2)); case (_ == _); move A0: (raw_fs_sz [::_]) => f0; move A1: (raw_fs_sz [::_]) => f1; move A2: (raw_fs_si [::_]) => f2; move A3: (raw_fs_si [::_]) => f3; rewrite /raw_fs_sz /raw_fs_si /= ?add0n in A0, A1, A2, A3; subst; eauto; move: (sz_weight t1 t2) (sz_weight t2 t1) (si_weight t1 t2) (si_weight t2 t1) => H0 H1 H2 H3; intuition; try (by apply (leq_add H0 H1)); by apply (leq_add H2 H3)); try (rewrite /= ?(eq_sym s2); case: (s1 == s2); rewrite ?sz_open ?si_open; move: (IH r2 f) => /=; rewrite /raw_fs_sz /raw_fs_si; intuition); rewrite /raw_fs_sz /raw_fs_si /= ?(eq_sym s2) ?(eq_sym c2) ?(eq_sym (value t2)); try by intuition. + by case: (s1 == s2); case: (c1 == c2); case: f => /=; eauto. + by case: (c1 == value t2) => [] /=; move: (weight_nonzero t2); intuition. + by case: (s1 == value t2); intuition. + by case: (s1 == s2); intuition. + by case: (value t1 == c2); nat_norm; move: (weight_nonzero t1); intuition. + by case: (value t1 == s2) => /=; nat_norm; intuition. + by case: (value t1 == s2) => /=; nat_norm; case: (raw_fs_interp r2 t1) => [a|] /=; intuition. + by case: (s1 == s2); intuition. + case: (s1 == value t2) => /=; nat_norm; [|intuition]. move: (raw_fs_interp _ _) => [t|] /=; intuition. Qed. End Computability. End FilesystemOT.