RichText.v (539 lines of code) (raw):
Require Import OtDef Ssromega Tree Basics ArithAux Commons.
Require Export mathcomp.ssreflect.seq.
Require Import ListTools.
Section RichTextOTDefinition.
Import Equality.
Context {X : eqType} (C : Type) {otX : OTBase X C} {ipX : OTInv _ _ otX} {otcX : OTComp otX}.
Inductive jcmd : Type :=
| JInsert of nat & seq (tree X)
| JRemove of nat & seq (tree X)
| JUnite of nat & X & seq (tree X)
| JFlat of nat & (tree X)
| JOpenRoot of nat & jcmd
| JEditLabel of C.
(* fix unite nop (force it to be non-empty) *)
Fixpoint jinterp (cmd : jcmd) (m : tree X) : option (tree X) :=
match m with | Node x xs =>
match cmd with
| JInsert i es => NodeW x (ins i es xs)
| JRemove i es => NodeW x (rm i es xs)
| JUnite i y es => if es is [::] then Some (Node x xs) else
if rm i es xs is Some xs' then NodeW x (ins i [:: Node y es] xs') else None
| JFlat i (Node z zs) =>
if nth i xs is Some (Node y ys) then
if (zs == ys) && (y == z) then NodeW x (oins i ys (rm i [:: Node y ys] xs))
else None else None
| JOpenRoot i cmd' => if nth i xs is Some x' then NodeW x (rplc i (jinterp cmd' x') xs) else None
| JEditLabel cmd => if @interp X C otX cmd x is Some x' then Some (Node x' xs) else None
end
end.
Fixpoint jinv (cmd : jcmd) :=
match cmd with
| JInsert n l => JRemove n l
| JRemove n l => if l is [::] then JInsert 0 [::] else JInsert n l
| JUnite n x l => if l is [::] then JInsert 0 [::] else JFlat n (Node x l)
| JFlat n (Node x l) => if l is [::] then JInsert n [:: Node x [::]] else JUnite n x l
| JOpenRoot n c => JOpenRoot n (jinv c)
| JEditLabel c => JEditLabel (inv c)
end.
Definition tr_ins (len : nat) (n1 n2 : nat) :=
if (n1 < n2) then n1 else n1 + len.
Definition tr_rem (len : nat) (n1 n2 : nat) :=
if (n1 < n2) then Some n1 else if (n1 >= n2 + len) then Some (n1 - len) else None.
Definition tr_uni (len : nat) (n1 n2 : nat) :=
if (n1 < n2) then Some n1 else if (n1 >= n2 + len) then Some (n1 - len + 1) else None.
Definition openroot_in (cmd : seq (tree X) -> jcmd) n1 l1 n2 tc2 :=
match tr_rem (size l1) n2 n1 with
None => let i := n2 - n1 in
if nth i l1 is Some x' then
match rplc i (jinterp tc2 x') l1 with
| Some l1' => [:: cmd l1']
| _ => [:: (* unused *)]
end
else [:: (* unused *)]
| _ => [:: cmd l1]
end.
Fixpoint jit (op1 op2 : jcmd) (flag : bool) : seq jcmd :=
match op1, op2 with
| JEditLabel c1, JEditLabel c2 => map JEditLabel (it c1 c2 flag)
| _, JEditLabel _ | JEditLabel _, _ => [:: op1]
| JOpenRoot n1 tc1, JOpenRoot n2 tc2 =>
if n1 == n2 then map (JOpenRoot n1) (jit tc1 tc2 flag) else [:: op1]
| JRemove n1 l1, JOpenRoot n2 tc2 => openroot_in (JRemove n1) n1 l1 n2 tc2
| JOpenRoot n1 tc1, JRemove n2 l2 =>
match tr_rem (size l2) n1 n2 with
| Some n1' => [:: JOpenRoot n1' tc1]
| None => nil
end
| JUnite n1 x1 l1, JOpenRoot n2 tc2 => openroot_in (JUnite n1 x1) n1 l1 n2 tc2
| JOpenRoot n1 tc1, JUnite n2 _ l2 =>
match tr_uni (size l2) n1 n2 with
| Some n1' => [:: JOpenRoot n1' tc1]
| None => [:: JOpenRoot n2 (JOpenRoot (n1 - n2) tc1)]
end
| JFlat n1 (Node x1 l1), JOpenRoot n2 tc2 =>
(* is it really unnecessary to check nth here? *)
if (n1 == n2) then
match jinterp tc2 (Node x1 l1) with
| Some t1' => [:: JFlat n1 t1']
| None => [:: (* unused *)]
end
else [:: op1]
| JOpenRoot n1 tc1, JFlat n2 (Node x2 l2) =>
if (n1 < n2) then [:: op1]
else if (n2 < n1) then [:: JOpenRoot (n1 + size l2 - 1) tc1]
else match tc1 with
| JOpenRoot n' tc' => [:: JOpenRoot (n' + n2) tc']
| JEditLabel c' => [::]
| JInsert n' l' => [:: JInsert (n' + n2) l']
| JRemove n' l' => [:: JRemove (n' + n2) l']
| JUnite n' x' l' => [:: JUnite (n' + n2) x' l']
| JFlat n' l' => [:: JFlat (n' + n2) l']
end
| _, JOpenRoot _ _ => [:: op1]
| JOpenRoot n1 tc1, JInsert n2 l2 => [:: JOpenRoot (tr_ins (size l2) n1 n2) tc1]
| JInsert n1 l1, JInsert n2 l2 =>
if (n1 == n2) then (if flag then [:: op1] else [:: JInsert (n1 + size l2) l1])
else [:: JInsert (tr_ins (size l2) n1 n2) l1]
| JInsert n1 l1, JRemove n2 l2 => if l2 is [::] then [:: op1] else
let len := size l2 in
if (n1 <= n2) then [:: op1] else
if (n1 >= n2 + len) then [:: JInsert (n1 - len) l1] else [::]
| JRemove n1 l1, JInsert n2 l2 =>
let (len1, len2) := (size l1, size l2) in
if (n1 + len1 <= n2) then [:: op1]
else if (n2 <= n1) then [:: JRemove (n1 + len2) l1]
else match ins (n2 - n1) l2 l1 with
| Some l1' => [:: JRemove n1 l1']
| None => [:: op1] end (* <- this branch is unused *)
| JInsert n1 l1, JUnite n2 x2 l2 =>
if l2 is [::] then
if n2 <= n1 then [:: JInsert n1.+1 l1] else [:: op1]
else if (n1 <= n2) then [:: op1]
else if (n1 >= n2 + size l2) then [:: JInsert (n1 - size l2 + 1) l1]
else [:: JOpenRoot n2 (JInsert (n1 - n2) l1)]
| JUnite n1 x1 l1, JInsert n2 l2 =>
if l1 is [::] then if n1 <= n2 then [:: op1] else [:: JUnite (n1 + size l2) x1 l2]
else if (n2 >= n1 + size l1) then [:: op1]
else if (n2 <= n1) then [:: JUnite (n1 + size l2) x1 l1]
else if (ins (n2 - n1) l2 l1) is Some zs then [:: JUnite n1 x1 zs] else [:: (* unused *)]
| JInsert n1 l1, JFlat n2 (Node x2 l2) =>
if (n1 <= n2) then [:: op1] else [:: JInsert (n1 + (size l2) - 1) l1]
| JFlat n1 l1, JInsert n2 l2 =>
if (n1 < n2) then [:: op1] else [:: JFlat (n1 + size l2) l1]
| JRemove n1 l1, JRemove n2 l2 =>
let (len1, len2) := (size l1, size l2) in
interval_interval_case n1 len1 n2 len2 (mkIIChoice (seq jcmd)
[:: op1]
[:: JRemove (n1 - len2) l1]
[::]
[:: JRemove n1 (rotr (n2 - n1) (drop len2 (rot (n2 - n1) l1)))]
[::]
[:: JRemove n2 (drop (n2 + len2 - n1) l1)]
[:: JRemove n1 (take (n2 - n1) l1)])
| JRemove n1 l1, JUnite n2 x2 l2 =>
let (len1, len2) := (size l1, size l2) in
if l1 is [::] then [::]
else if l2 is [::] then [::]
else let united := (oins (n2 - n1) [:: Node x2 l2] (rm (n2 - n1) l2 l1)) in
interval_interval_case n1 len1 n2 len2 (mkIIChoice (seq jcmd)
[:: op1]
[:: JRemove (n1 - len2).+1 l1]
(if united is Some l1' then [::JRemove n1 l1'] else [:: (* unused *)])
(if united is Some l1' then [::JRemove n1 l1'] else [:: (* unused *)])
[:: JOpenRoot n2 (JRemove (n1 - n2) l1)]
[:: JOpenRoot n2 (JRemove (n1-n2) (take (len2 + n2 - n1) l1)); JRemove (n2.+1) (drop (len2 + n2 - n1) l1) ]
[:: JRemove n1 (take (n2 - n1) l1); JOpenRoot n1 (JRemove 0 (drop (n2 - n1) l1))])
| JUnite n1 x1 l1, JRemove n2 l2 =>
let (len1, len2) := (size l1, size l2) in
if l2 is [::] then [::op1]
else if l1 is [::] then [::] else
interval_interval_case n1 len1 n2 len2 (mkIIChoice _
[:: op1]
[:: JUnite (n1 - len2) x1 l1]
[::]
[:: JUnite n1 x1 (rotr (n2 - n1) (drop len2 (rot (n2 - n1) l1)))]
[::]
[:: JUnite n2 x1 (drop (n2 + len2 - n1) l1)]
[:: JUnite n1 x1 (take (n2 - n1) l1)])
| JRemove n1 l1, JFlat n2 (Node x l2) =>
if l1 is [::] then [::]
else if (n1 + size l1 <= n2) then [:: op1]
else if (n1 > n2) then [:: JRemove (n1 + size l2 - 1) l1]
else if rm (n2 - n1) [:: Node x l2] l1 is Some ws then
if ins (n2 - n1) l2 ws is Some zs then
(if zs is nil then [::] else [:: JRemove n1 zs]) else [:: (* unused *) ] else [:: (* unused *)]
| JFlat n1 l1, JRemove n2 l2 =>
if l2 is [::] then [:: op1]
else if (n1 < n2) then [:: op1] else
if (n1 >= n2 + size l2) then [:: JFlat (n1 - size l2) l1]
else [::]
| JUnite n1 x1 l1, JUnite n2 x2 l2 =>
let (len1, len2) := (size l1, size l2) in
interval_interval_case n1 len1 n2 len2 (mkIIChoice _
[:: op1]
[:: JUnite (n1 - len2 + 1) x1 l1]
(if ~~flag then [:: JUnite n1 x1 [:: Node x2 l2]]
else [:: JOpenRoot n1 (JUnite 0 x1 l2)])
(if rm (n2 - n1) l2 l1 is Some l1' then
if ins (n2 - n1) [:: Node x2 l2] l1' is Some l1'' then
[:: JUnite n1 x1 l1''] else (* unused *) [::] else [::])
[:: JOpenRoot n2 (JUnite (n1 - n2) x1 l1)]
(if flag then [:: JFlat n2 (Node x2 l2); op1] else [::])
(if flag then [:: JFlat n2 (Node x2 l2); op1] else [::]))
| JUnite n1 x1 l1, JFlat n2 (Node x2 l2) =>
if (n2 >= n1 + size l1) then [:: op1]
else if (n2 < n1) then [:: JUnite (n1 + size l2 -1) x1 l1]
else if rm (n2 - n1) [:: Node x2 l2] l1 is Some ws then
if ins (n2 - n1) l2 ws is Some zs then
if zs is [::] then [:: JInsert n1 [:: Node x1 [::]]] else [:: JUnite n1 x1 zs]
else [:: (* unused *) ] else [:: (* unused *)]
| JFlat n1 l1, JUnite n2 x2 l2 =>
match tr_uni (size l2) n1 n2 with
| Some n1' => [:: JFlat n1' l1]
| None => [:: JOpenRoot n2 (JFlat (n1 - n2) l1)]
end
| JFlat n1 l1, JFlat n2 (Node x2 l2) =>
if (n1 < n2) then [:: op1]
else if (n1 == n2) then [::]
else [:: JFlat (n1 + size l2 - 1) l1]
end.
Fixpoint nonempty_op (t : jcmd) : bool :=
match t with
| (JEditLabel c) => true
| (JRemove _ l) => l != nil
| (JInsert _ l) => l != nil
| (JUnite _ _ l) => l != nil
| (JFlat _ l) => true
| (JOpenRoot _ c) => nonempty_op c
end.
Lemma nonempty_map n l: all nonempty_op [seq JOpenRoot n i | i <- l] = all nonempty_op l.
by elim: l => [|l ls] //= ->. Qed.
Lemma ins_nonempty {Z : eqType} n a2 l1 l2 (l1' : seq Z):
ins n (a2 :: l2) l1 = Some l1' -> l1' != nil.
by elim: n l1 => [l1 [] <- |n IHn [|a l] // /wcons_some [] x [] _ ->]. Qed.
Lemma rplc_nonempty {Z : eqType} n t (l1 : seq Z) b:
l1 != nil -> rplc n t l1 = Some b -> b != nil.
elim: n l1 => [|n IHn] [|a l1] // _ /=.
+ by case: t => [t|] //= [] <-.
+ by move => /wcons_some [] x [] _ ->. Qed.
Lemma rm0 {Z : eqType} (l : seq Z): rm 0 [::] l = Some l. by case: l. Qed.
(* TODO: Show that the result of transformation of two
nonempty operations is a composite of nonempty operations *)
Theorem nonempty_it op1 op2 f: nonempty_op op1 -> nonempty_op op2 -> all nonempty_op (jit op1 op2 f).
elim: op1 op2 => [n1 l1|n1 l1|n1 x1 l1|n1 [x1 l1]|n1 c1 IHc1|c1]
[n2 l2|n2 l2|n2 x2 l2|n2 [x2 l2]|n2 c2|c2] //=; eauto;
try by rewrite ?andbT.
+ (* 1/24 *) by move: (n1 == n2) f => [] [] //=; rewrite andbT.
+ (* 2/24 *) by move: l2 (n1 <= n2) => [|a2 l2] [] //=; try case (_ <= _) => //=; rewrite andbT.
+ (* 3/24 *) by move: l2 (n1 <= n2) => [|a2 l2] [] //=; try case (_ <= _) => //=; rewrite andbT.
+ (* 4/24 *) by move: (n1 <= n2) => [] //=; rewrite ?andbT.
+ (* 5/24 *) move A0: (_ <= _) => [] //=.
+ by rewrite andbT.
+ move A1: (_ <= _) => [] //=. by rewrite ?andbT.
case A2: (ins _ _ _) => [a|] //=; rewrite ?andbT => //.
by move: l2 A2 => [|a2 l2] // /ins_nonempty.
+ (* 6/24 TODO: *) case: (interval_cases_analysisP _ _ _ _ _) => //=; rewrite andbT //.
+ rewrite -[rotr _ _ == _]size_eq0 /rotr size_rot size_drop size_rot. case: eqP => //=.
- move=> -> _. rewrite eq_sym leq_add2l => H [] // H'. move/andP: (conj H' H).
rewrite -ltn_neqAle -subn_gt0 lt0n //.
- move/eqP. move=> A B. move/andP:(conj A B). rewrite -ltn_neqAle -subn_gt0 => H.
move/(leq_sub2r (size l2)). rewrite -addnBA // subnn addn0.
move/(leq_sub2r n1). rewrite subnAC addnC -addnBA // subnn addn0 -lt0n => /(leq_trans H) //.
+ admit.
+ admit.
+ (* 7/24 TODO: *) admit.
+ (* 8/24 *)
by move A0: (_ <= _) l1 => [] [|a1 l1'] //=;
move A1: (_ <= _) => []; case A2: (n2 - n1) => [|n] // _ _;
try case: (_ == _) => [] //; case: (rm _ _ _) => // [] // a;
rewrite -?cons_wcons; case: (ins _ _ _) => [[]|].
+ (* 9/24 *) rewrite /openroot_in.
case: (tr_rem _ _ _) => [] //=; rewrite ?andbT //.
case: (nth _ _) => [a|] //. case A0: (rplc _ _ _) => [b|] //=.
rewrite ?andbT. by move: A0 => /rplc_nonempty A0 /A0.
+ (* 10/24 *) repeat (move: (_ <= _) => []); move: l1 l2 => [|a1 l1] [|a2 l2] //=;
move A0: (ins _ _ _) => [a|] // _ _ /=; move: A0 => /ins_nonempty; by rewrite ?andbT.
+ (* 11/24 TODO *) admit.
+ (* 12/24 TODO *) admit.
+ (* 13/24 *) repeat (move: (_ <= _) => [] //=); try by rewrite ?andbT;
move A0: (rm _ _ _) => [a|] //; move A1: (ins _ _ _) => [[|b bl]|] //=.
by rewrite ?andbT. by rewrite ?andbT.
+ (* 14/24 same as 9/24 *) rewrite /openroot_in.
case: (tr_rem _ _ _) => [] //=; rewrite ?andbT //.
case: (nth _ _) => [a|] //. case A0: (rplc _ _ _) => [b|] //=.
rewrite ?andbT. by move: A0 => /rplc_nonempty A0 /A0.
+ (* 15/24 *) by case: (n1 < n2).
+ (* 16/24 *) case: l2 (n1 < n2) => [|a2 l2] [] _ _ //=; case: (_ <= _) => //=.
+ (* 17/24 *) case: (tr_uni _ _ _) => [_|] //=.
+ (* 18/24 *) case: (_ < _) (_ == _) => [] [] //=.
+ (* 19/24 *) by case: (_ == _) => [] //=; case: (jinterp _ _) => [_|] /=.
+ (* 20/24 *) by case: (tr_rem _ _ _) => [_|] //=; rewrite andbT.
+ (* 21/24 *) by case: (tr_uni _ _ _) => [_|] //=; rewrite andbT.
+ (* 22/24 *) move: (n1 < n2) (n2 < n1) => [] [] //= {IHc1}; try by rewrite andbT.
by case: c1 => //= _ l l'; rewrite andbT.
+ (* 23/24 *) case: (n1 == n2).
- by move /(IHc1 c2) => A /A; rewrite nonempty_map.
- by rewrite /= andbT.
+ (* 24/24 *) by elim: (it c1 c2 f) => [] //=. Admitted.
Fixpoint jcmdsi cmd : nat :=
match cmd with
| (JEditLabel c) => @cmdsi X C otX otcX c
| (JUnite _ _ _) => 1
| (JInsert _ _) => 1
| (JOpenRoot _ c) => jcmdsi c
| _ => 0
end.
Fixpoint jcmdsz cmd : nat :=
match cmd with
| (JEditLabel c) => @cmdsz X C otX otcX c
| (JRemove _ t) => weights t
| (JInsert _ t) => weights t
| (JOpenRoot _ c) => jcmdsz c
| _ => 1
end.
Definition jsz := foldl addn 0 \o map jcmdsz.
Definition jsi := foldl addn 0 \o map jcmdsi.
Definition jcomputability := computability jit jsz jsi.
Ltac comp_unfold := rewrite /jcomputability /computability /flip /jit ?/tr_uni ?/openroot_in ?/tr_rem.
(* TODO: This lemma is true only for nonempty operations *)
(* Lemma jsz_nondg : forall cmd, 0 < jcmdsz cmd.
by elim=> //=; exact: sz_nondg. Qed. *)
Section WeightLemmata.
Lemma weights_ins l1: forall (n : nat) (l : seq (tree X)) r,
ins n l1 l = Some r -> weights r = weights l1 + weights l.
elim => [l r|n] /=.
+ by case => <-; rewrite weights_app.
+ move => IHn [] // a l r /wcons_some [] x [] /IHn A1 ->.
by rewrite ?weights_cons addnA (addnC (weights _)) -addnA A1. Qed.
Lemma weights_rm (l1 : seq (tree X)) l2 l3 n: rm n l2 l1 = Some l3 ->
weights l3 + weights l2 = weights l1.
elim: n l1 l2 l3 => [|n IHn] //.
+ move => l1 l2 l3 => /rm_eq <-. by rewrite weights_app addnC.
+ case => [|a1 l1] /= [|a2 l2] l3 //.
+ by case => <-.
+ case => <- /=. by rewrite {2}/weights /= addn0.
+ move => /wcons_some [] x [] /IHn; rewrite ?weights_cons => <- ->.
by rewrite weights_cons ?addnA. Qed.
Lemma weights_Node (x : X) l: weights [:: Node x l] = weights l + 1.
by rewrite {1}/weights /= weight_Node addn0. Qed.
Lemma weights_rplc {n} {t : tree X} {l l1 b}: nth n l = Some l1 ->
rplc n (Some t) l = Some b -> weights b + weight l1 = weight t + weights l.
elim: n l b => [|n IHn] /= [|a l] // b.
+ move => [] -> [] <-. rewrite ?weights_cons. ssromega.
+ move => A0 /wcons_some [] x [] /(IHn _ _ A0) A1 ->; rewrite ?weights_cons. ssromega. Qed.
End WeightLemmata.
Lemma ins_rm_corr {l1 n1 l2 n2}:
jcomputability (JInsert n1 l1) (JRemove n2 l2).
Proof. comp_unfold => _. case: l2 => [|l2 l2s] /=.
- rewrite addn0 [n2 <= n1]leqNgt [n1 <= n2]leqNgt; case: (ltngtP n1 n2) => /=;
rewrite /jsz /jsi /= ?add0n ?addn0; eauto.
- case: (int_ptP n2 (size l2s) n1) => /=; try (case A1: ins => [r_ins|] /=);
rewrite ?leqnn ?leqnSn; eauto; rewrite /jsz /jsi /= ?add0n ?addn0 => _ _; split => //; eauto.
- by move: A1 => /weights_ins ->.
- by apply /leq_addl. Qed.
Lemma ins_uni_corr {n1 l1 n2 x2 l2}: jcomputability (JInsert n1 l1) (JUnite n2 x2 l2).
comp_unfold => _. case: l2 => [|l2 l2s] /=.
+ case: (n2 <= n1); rewrite /jsz /jsi /=; nat_norm; eauto.
+ case: (n1 <= n2); case: (n2 + (size l2s).+1 <= n1);
rewrite /jsz /jsi /=; try (case: (ins _ _ _)); nat_norm; eauto. Qed.
Lemma ins_flat_corr {n1 l1 n2 x2 l2}:
jcomputability (JInsert n1 l1) (JFlat n2 (Node x2 l2)).
Proof. comp_unfold; rewrite [n1 <= n2]leqNgt => _.
case: ltngtP => //=; rewrite ?leqnn ?leqnSn; intuition. Qed.
Lemma L0: forall n (l1 l2 : seq (tree_eqType X)),
weights (rotr n (drop (size l1) (rot n l2))) <= weights l2.
by elim => [|n IHn] l1 l2 /=; rewrite ?weights_rotr ?weights_rot;
[set j := rot 0 l2 | set j := rot (n.+1) l2];
move: (weights_drop (size l1) j); rewrite ?weights_rot. Qed.
Lemma rm_rm_corr {n1 l1 n2 l2}:
jcomputability (JRemove n1 l1) (JRemove n2 l2).
Proof. comp_unfold => _.
case: (interval_interval_case_analP);
rewrite /jsz /jsi /= ?addn0 ?add0n; eauto;
move => _ _; try move => _; split => //;
try (split; [done| left; split]) => //;
(try apply leq_add); (try apply weights_drop); (try apply weights_take);
[rewrite -ltnS -addnS; apply ltn_addl; rewrite ltnS| |
rewrite addnC -ltnS -addnS; apply ltn_addl; rewrite ltnS |]; apply L0. Qed.
Lemma L1 (l : tree X): weights [:: l] = weight l.
by rewrite /weights /= addn0. Qed.
Lemma L2 n (l : seq (tree X)): weights (take n l) + weights (drop n l) = weights l.
elim: n l => [|n IHn] [|a l] //=. by rewrite ?weights_cons -addnA (IHn l). Qed.
Lemma rm_uni_corr {n1 l1 n2 x2 l2}:
jcomputability (JRemove n1 l1) (JUnite n2 x2 l2).
Proof. comp_unfold.
case: (interval_interval_case_analP) => /=;
move: l1 l2 => [|l1 l1s] [|l2 l2s]; try (by simpl; eauto);
move => _ _ _; try move => _;
try (move: (l1 :: l1s) (l2 :: l2s) => l1' l2';
case A0: (rm _ _ _) => /= [z|]; try case A1: (ins _ _) => [z2|] //=);
rewrite /jsz /jsi /= ?addn0 ?add0n; eauto;
(try by move: A0 => /weights_rm <-; move: A1 => /weights_ins ->; rewrite weights_Node;
split;[ssromega| split;[|right]]);
[move: ((size l2s).+1 + n2 - n1) => [|n] /=| move: (n2 - n1) => [|n] /=]; eauto;
rewrite ?weights_cons -?addnA ?addnS addn0 L2 addn0; eauto. Qed.
Lemma rm_flat_corr {n1 l1 n2 x2 l2}:
jcomputability (JRemove n1 l1) (JFlat n2 (Node x2 l2)).
Proof. comp_unfold => _; case: (int_pt_incP n1 (size l1) n2);
case: l1 => [|a1 l1]; try by (rewrite /jsz /jsi /=; nat_norm; eauto).
case: (n2 - n1) => [|d].
+ simpl. case A0: (a1 == Node x2 l2) => /= _ _; eauto.
move: A0 => /eqP ->. rewrite rm_id. case A0: (l2 ++ l1) => [|a l]; eauto.
move: A0 => <-; rewrite /jsz /jsi /= weights_app weights_cons weight_Node; nat_norm.
split; try split; try done; try left; by elim: (addn _ _) => [] //.
+ move A0: (rm _ _ _) => [[|w ws]|]; try move A1: (ins _ _ _) => [[|z zs]|];
try by rewrite /jsz /jsi /= ?add0n ?addn0; eauto.
move: A0 => /weights_rm A0. move: A1 => /weights_ins A1.
rewrite /jsz /jsi /= ?add0n ?addn0 A1 -A0 weights_Node; intuition.
ssromega. left. split => //. ssromega. Qed.
Lemma weights_interp {a b c} {l : seq (tree X)} {n}:
nth n l = Some a -> rplc n (jinterp c a) l = Some b ->
weights b <= (jcmdsz c) + weights l /\ (weights b <= weights l \/ (0 < jcmdsi c)).
elim: c l a n b => [n1 l1|n1 l1 |n1 s l1| n1 t|n1 j IH| c] /= l a n b A0.
+ case: a A0 => [x xs]. move A0: (NodeW _ _) => [[x2 l2]|] //=.
+ move: A0 => /nodew_some [] _ /weights_ins A0 A1 /(weights_rplc A1).
rewrite ?weight_Node A0 => A2. split. ssromega. by right.
+ by rewrite rplc_none_none.
+ case: a A0 => [x xs]. move A0: (NodeW _ _) => [[x2 l2]|] //=.
+ move: A0 => /nodew_some [] _ /weights_rm A0 A1 /(weights_rplc A1).
rewrite ?weight_Node -A0 => A2. split. ssromega. left. ssromega.
+ by rewrite rplc_none_none.
+ case: a A0 l1 => [x xs] A0 [|a1 l1] A1.
+ move: (weights_rplc A0 A1) => A2. split. ssromega. by right.
+ move A2: (rm _ _ _) A1 => [xs'|]; try move A3: (NodeW _ _) => [[x2 l2]|] //=;
try by rewrite rplc_none_none. move => A4.
move: (weights_rplc A0 A4). move: A3 => /nodew_some [] -> /weights_ins.
move: A2 => /weights_rm. rewrite weights_Node ?weight_Node => <- ->. split. ssromega. by right.
+ case: a A0 t => [x xs] A0 [z zs]. move A1: (nth _ _) => [[y ys]|];
try move A22: (_ && _) => [/andP [/eqP A21 /eqP]|]; try move A3: (rm _ _ _) => [a|] /=;
try move A4: (ins _ _ _) => [c|] /=; try by rewrite rplc_none_none.
move => /(weights_rplc A0). move: A4 => /weights_ins. move: A3 => /weights_rm.
rewrite ?weights_Node ?weight_Node => <- -> A2. split; try left; ssromega.
+ case: a A0 => [t l0] A0; case A1: (nth _ _ ) => [x'|];
try move A2: (rplc n1 _ _) => [l1|] /=; try move => /(weights_rplc A0);
try move: (IH _ _ _ _ A1 A2) => [] IH0 IH1; try (case A3: (jinterp _ _) A2 => [t1|]);
try by rewrite ?rplc_none_none. rewrite ?weight_Node. move /(weights_rplc A1) => H0 H1.
split. ssromega. move: IH1 => [H2|]. left. ssromega. by right.
+ case: a A0 => t1 l1 A1. case: (interp c t1) => [a /(weights_rplc A1)|].
rewrite ?weight_Node => A2. have: (weights b = weights l) by ssromega.
move => ->. split. ssromega. left. done. by rewrite rplc_none_none. Qed.
Lemma rm_or_corr {n1 l1 n2 c2} :
jcomputability (JRemove n1 l1) (JOpenRoot n2 c2).
Proof. comp_unfold; rewrite /tr_rem /openroot_in /tr_rem.
case: (int_pt_incP n1 (size l1) n2) => /=; eauto;
case A0: nth => [a|]; eauto.
case A1: (rplc _ _ _) => [b|]; eauto.
move => _ _ _. rewrite /jsz /=; nat_norm.
move: (weights_interp A0 A1) => [H0 H1].
split. by rewrite addnC. split. done. by case: H1; [left|right]. Qed.
Lemma uni_uni_corr {n1 x1 l1 n2 x2 l2} :
jcomputability (JUnite n1 x1 l1) (JUnite n2 x2 l2).
Proof. comp_unfold => srv. case: (interval_interval_case_analP) => /=; case: srv => /=; try (by intuition);
case: rm => [?|]; try (by intuition); case: ins => [?|]; try (by intuition). Qed.
Lemma uni_flat_corr {n1 x1 l1 n2 x2 l2}:
jcomputability (JUnite n1 x1 l1) (JFlat n2 (Node x2 l2)).
Proof. comp_unfold.
case: (int_pt_incP n1 (size l1) n2) => /=; try (by intuition).
case: rm => [?|]; try (case: ins => [[|??]|]); by intuition. Qed.
Lemma uni_or_corr {n1 x1 l1 n2 c2}:
jcomputability (JUnite n1 x1 l1) (JOpenRoot n2 c2).
Proof. comp_unfold.
case: (int_pt_incP n1 (size l1) n2) => /=; try (by intuition).
case: nth => [?|]; try (case: rplc => [?|]); by intuition. Qed.
Lemma flat_flat_corr {n1 x1 l1 n2 x2 l2}:
jcomputability (JFlat n1 (Node x1 l1)) (JFlat n2 (Node x2 l2)).
Proof. comp_unfold => _. rewrite eq_sym.
case: (ltngtP n2 n1) => /=; by intuition. Qed.
Lemma flat_or_corr {n1 x1 l1 n2 c2}:
jcomputability (JFlat n1 (Node x1 l1)) (JOpenRoot n2 c2).
Proof. comp_unfold => _. case: (ltngtP n1 n2) => /=; try (by intuition).
case: c2 => [n' l'|n' l'|n' x' l'|n' [x' l']|n' c'|c1']; case: jinterp => [?|] /=; by intuition. Qed.
Lemma or_or_corr {n1 c1 n2 c2}:
(forall op2, jcomputability c1 op2) -> jcomputability (JOpenRoot n1 c1) (JOpenRoot n2 c2).
Proof. move=> IH. rewrite /jcomputability /computability /jsz /jsi /flip => /=; rewrite eq_sym.
case: (n2 == n1) => /= srv; try (by intuition).
move: (IH c2). rewrite /jcomputability /computability /jsz /jsi /flip => /(_ srv) /= [] H1 [] H2 H3.
split. rewrite -!map_comp. exact: H1.
split. by rewrite -!map_comp. rewrite -!map_comp. case: H3 => H3. by left. right. done. Qed.
Lemma el_el_corr {c1 c2}:
jcomputability (JEditLabel c1) (JEditLabel c2).
Proof.
comp_unfold; rewrite /jsz /jsi /comp => srv.
move: (@comp_corr X C otX otcX c1 c2 srv). by rewrite /flip /si /sz -?map_comp. Qed.
Lemma ins_ins_corr {n1 l1 n2 l2} :
jcomputability (JInsert n1 l1) (JInsert n2 l2).
Proof. by comp_unfold; rewrite eq_sym => srv; case: eqP => H; case: srv => /=; rewrite ?leqnn; intuition. Qed.
Ltac symm1 := rewrite [jsi _ + jsi _]addnC [jsz _ + jsz _]addnC (and_comm (jsz _ <= _))
[(jsi ([:: _])) + _]addnC [(jsz ([:: _])) + _]addnC.
Ltac symm2 := rewrite [jsi _ + jsi _]addnC [jsi [:: _] + jsi [:: _]]addnC
[jsz _ + jsz _] addnC [jsz [:: _] + jsz [:: _]]addnC
(and_comm (jsz _ <= jsz [:: _])).
(*TODO: Fix holes in the proof *)
Theorem jcomp_corr: forall (op1 op2 : jcmd),
jcomputability op1 op2.
Proof. elim => [n1 l1|n1 l1|n1 x1 l1|n1 [x1 l1]|n1 c1 IHc1|c1]
[n2 l2|n2 l2|n2 x2 l2|n2 [x2 l2]|n2 c2|c2] srv;
try (simpl; by comp_unfold; nat_norm; intuition);
move => op1' op2'; subst op1' op2'.
+ exact: ins_ins_corr.
+ exact: ins_rm_corr.
+ exact: ins_uni_corr.
+ exact: ins_flat_corr.
+ symm1. exact: ins_rm_corr.
+ exact: rm_rm_corr.
+ exact: rm_uni_corr.
+ exact: rm_flat_corr.
+ exact: rm_or_corr.
+ symm1; exact: ins_uni_corr.
+ symm1; exact: rm_uni_corr.
+ exact: uni_uni_corr.
+ exact: uni_flat_corr.
+ exact: uni_or_corr.
+ symm1; exact: ins_flat_corr.
+ symm1; exact: rm_flat_corr.
+ symm1; exact: uni_flat_corr.
+ exact: flat_flat_corr.
+ exact: flat_or_corr.
+ symm2; exact: rm_or_corr.
+ symm2; exact: uni_or_corr.
+ symm2; exact: flat_or_corr.
+ exact: or_or_corr.
+ exact: el_el_corr. Qed.
Theorem jip1 : forall op m mr, jinterp op m = Some mr -> jinterp (jinv op) mr = (Some m).
Proof. elim => [n1 l1|n1 l1|n1 x1 l1|n1 [x1 l1]|n1 c1 IHc1|c1] [x xs] [rx rxs] //=.
+ by move/nodew_some => []-> /rm_ins_id ->.
+ move/nodew_some => [] ->; case: l1 => [|x1 l1] /=.
- by rewrite rm_id => [] [] -> /=.
- by move/ins_rm_id => /(_ (ltn0Sn _)) ->.
+ case: l1 => [|l1 l1s] //=.
case Hrm: rm => [r_rm|//] /nodew_some [] -> H; move:(H).
move/ins_some_nth_in => /(_ 0 (ltn0Sn _)). rewrite addn0 => -> /=; rewrite ?eq_refl orm_some /=.
apply/nodew_some; split => //. move/rm_ins_id: H ->. by move/ins_rm_id: Hrm => /(_ (ltn0Sn _)).
+ case: l1 => [|l1 l1s] //; case: nth => [r_nth|] //; case: r_nth => [z zs];
case: eqP =>// <- /=; case: eqP => // <- /nodew_some [] ->; case Hrm: rm => [r_rm|] //=.
- move=> /ins_id <-. move: Hrm => /ins_rm_id => Hrm. by rewrite Hrm.
by move/rm_ins_id ->; move/ins_rm_id: Hrm => /(_ (ltn0Sn _)) ->.
+ case Hnth: nth => [r_nth|]// /nodew_some [] <-. case Hjint: jinterp => [r_jint|]; try by rewrite rplc_none_none.
move=> Hrplc. move/rplc_nth_eq:(Hrplc) ->.
by rewrite (IHc1 _ _ Hjint) -Hnth orplc_some -Hrplc orplc_some rplc_rplcC_eq /= (rplc_nth_id' _ _ _ Hnth).
+ case Hinterp: interp => [?|] // [] <- <-.
by move: (@ip1 _ _ _ ipX _ _ _ Hinterp) ->. Qed.
Theorem c1: forall (op1 op2 : jcmd) (f : bool) (m m1 m2 : tree X),
jinterp op1 m = Some m1 ->
jinterp op2 m = Some m2 ->
let m21 := exec_all jinterp (Some m2) (jit op1 op2 f) in let m12 := exec_all jinterp (Some m1) (jit op2 op1 (~~ f)) in m21 = m12 /\ (exists node : tree X, m21 = Some node).
Admitted.
Instance jOT : OTBase (tree X) jcmd := {interp := jinterp; it := jit; it_c1:=c1}.
(*TODO: Prove commutation *)
(*TODO: Restrict to nonempty operations
Instance jInv : OTInv (tree X) jcmd jOT := {inv := jinv; ip1 := jip1}.
Instance jCompOT : OTComp jOT := {cmdsz := jcmdsz; cmdsi := jcmdsi; (*sz_nondg := jsz_nondg; *) comp_corr := jcomp_corr}.
Admitted. *)
End RichTextOTDefinition.
Arguments JEditLabel [X] [C].
Arguments JInsert [X] [C].
Arguments JRemove [X] [C].
Arguments JUnite [X] [C].
Arguments JFlat [X] [C].
Arguments JOpenRoot [X] [C].