Fixpoint natc (m n : nat) :=
match m, n with 0, 0 => Eq | 0, _ => Lt | _, 0 => Gt | S m1, S n1 => natc m1 n1 end.
rewrite tvcompare_def.
generalize (natc_correct (tvarn v) (tvarn v)); case natc; auto.
intros H; contradict H; auto with arith.
intros H; contradict H; auto with arith.
Qed.
(* Proof *)
Variable interv : tvar -> point K.
Notation "{v[ x ]}" := (interv x).
(* Implementation of variable *)
Variable var : Type.
(* Implementation of coef *)
Variable coef : Type.
Variable cadd : coef -> coef -> coef.
Variable czerop : coef -> bool.
Variable czero : coef.
Variable conep : coef -> bool.
Variable cone : coef.
Variable copp : coef -> coef.
Variable cscale : var -> coef -> coef.
Variable interk : var -> K.
Notation "{k[ x ]}" := (interk x).
Variable interc : coef -> K.
Notation "{c[ x ]}" := (interc x).
Hypothesis cadd_c : forall x y, {c[cadd x y]} = ({c[x]} + {c[y]})%f.
Hypothesis cone_c : {c[cone]} = (1)%f.
Hypothesis conep_c : forall x,
if conep x then {c[x]} = (1)%f else True.
Hypothesis czero_c : {c[czero]} = (0)%f.
Hypothesis cscale_c : forall k x,
{c[cscale k x]} = ({k[k]} * {c[x]})%f.
Hypothesis czerop_c : forall x,
if czerop x then {c[x]} = (0)%f else True.
Hypothesis copp_c : forall x, {c[copp x]} = (- {c[x]})%f.
(* We want to reduce expression *)
Inductive tuple := Tuple (_ _ _: tvar).
Let  line := list tuple.
Let  expr := list (coef * line).
Definition intert (t : tuple) :=
let (p1,p2,p3) := t in '[{v[p1]},{v[p2]},{v[p3]}].
Notation "{t[ x ]}" := (intert x).
Fixpoint interl (l :line) :=
match l with nil => 1%f | t ::l1 => ({t[t]} * interl l1)%f end.
Notation "{l[ x ]}" := (interl x).
Fixpoint intere (e :expr) :=
match e with nil => 0%f | (c,l)::e1 =>
({c[c]} * {l[l]} + intere e1)%f
end.
Notation "{e[ x ]}" := (intere x).
Fixpoint intere1 (e :expr) :=
match e with nil => 0%f | (c,t ::nil)::nil =>
if conep c then {t[t]} else intere e
| _ => intere e end.
Notation "{e1[ x ]}" := (intere1 x).
(* Sign *)
Inductive sign := Sm1 | S0 | S1.
Definition sopp s := match s with Sm1 => S1 | S0 => S0 | S1 => Sm1 end.
Definition smult s1 s2 :=
match s1 with S0 => S0 | S1 => s2 | Sm1 => sopp s2 end.
Definition smult3 s1 s2 s3 :=
match s1 with S0 => S0
| S1 => smult s2 s3
| Sm1 => sopp (smult s2 s3) end.
(* Membership *)
Definition tin i (t : tuple) :=
let (j1,j2,j3) := t in
match tvcompare i j1 with Eq => true
| _ =>   match tvcompare i j2 with Eq => true
| _ =>   match tvcompare i j3 with Eq => true
| _ =>  false end end end.
(* Substitution *)
Definition tsubst i j (t : tuple) :=
let (i1,i2,i3) := t in
match tvcompare i i1 with
| Eq => Tuple j i2 i3
| _ =>
match tvcompare i i2 with
| Eq => Tuple i1 j i3
| _ =>
match tvcompare i i3 with
| Eq => Tuple i1 i2 j
| _ => t
end
end
end.
Definition s2k (s: sign) : K :=
match s with S0 => 0%f | S1 => 1%f | Sm1 => (-(1))%f end.
(* Add an element in a tuple  i1 [? i2 i3] *)
Definition mk_tuplel i1 i2 i3 :=
match tvcompare i1 i2 with
| Eq => (S0, Tuple i1 i2 i3)
| Lt => (S1, Tuple i1 i2 i3)
| Gt =>
match tvcompare i1 i3 with
| Eq => ( S0, Tuple i1 i2 i3)
| Lt => (Sm1, Tuple i2 i1 i3)
| Gt => ( S1, Tuple i2 i3 i1)
end
end.
(* Add an element in a tuple  [i1 i2 ?] i3 *)
Definition mk_tupler i1 i2 i3 :=
match tvcompare i2 i3 with
| Eq => (S0, Tuple i1 i2 i3)
| Lt => (S1, Tuple i1 i2 i3)
| Gt =>
match tvcompare i1 i3 with
| Eq => ( S0, Tuple i1 i2 i3)
| Lt => (Sm1, Tuple i1 i3 i2)
| Gt => ( S1, Tuple i3 i1 i2)
end
end.
Inductive sprod := SProd (s : sign) (t1 t2 : tuple).
Definition esprod (s : sprod) :=
let (s,t1,t2) := s in (s2k s * {t[t1]} * {t[t2]})%f.
Definition elsprod (l : list sprod) :=
fold_left (fun res s => (res + esprod s)%f) l 0%f.
(* i1 <= j1 *)
Definition tsplit3 (i1 i2 i3 j1 j2 j3 : tvar) :=
match tvcompare i2 j2 with
| Gt =>
(* [i1 j1 j2] [i2 i3 j3] - [i1 j1 j3] [i2 i3 j2] [i1 j2 j3] [i2 i3 j1] *)
let   (s1,t1) := mk_tuplel i1 j1 j2 in
let (s'1,t'1) := mk_tupler i2 i3 j3 in
let   (s2,t2) := mk_tuplel i1 j1 j3 in
let (s'2,t'2) := mk_tupler i2 i3 j2 in
let   (s3,t3) := mk_tuplel i1 j2 j3 in
let (s'3,t'3) := mk_tupler i2 i3 j1 in
SProd (smult s1 s'1) t1 t'1 ::
SProd (sopp (smult s2 s'2)) t2 t'2 ::
SProd (smult s3 s'3) t3 t'3 :: nil
| _  =>
match tvcompare i3 j3 with
| Gt =>
(* [i1 i2 j1] [i3 j2 j3] -[i1 i2 j2] [i3 j1 j3] [i1 i2 j3] [i3 j1 j2] *)
let   (s1,t1) := mk_tupler i1 i2 j1 in
let (s'1,t'1) := mk_tuplel i3 j2 j3 in
let   (s2,t2) := mk_tupler i1 i2 j2 in
let (s'2,t'2) := mk_tuplel i3 j1 j3 in
let   (s3,t3) := mk_tupler i1 i2 j3 in
let (s'3,t'3) := mk_tuplel i3 j1 j2 in
SProd (smult s1 s'1) t1 t'1 ::
SProd (sopp (smult s2 s'2)) t2 t'2 ::
SProd (smult s3 s'3) t3 t'3 :: nil
| _  => SProd S1 (Tuple i1 i2 i3) (Tuple j1 j2 j3)::nil
end
end.
Definition tsplit (t1 t2 : tuple) :=
Eval lazy beta delta [tsplit3] in
let (i1,i2,i3) := t1 in
let (j1,j2,j3) := t2 in
match tvcompare i1 j1 with
| Gt => (* tsplit3 j1 j2 j3 i1 i2 i3 *) SProd S1 t2 t1 :: nil
| _  => tsplit3 i1 i2 i3 j1 j2 j3
end.
(* Lexicographic comparison *)
Fixpoint list_compare (T : Type) (cmp : T -> T -> comparison)
(l1 l2 : list T) :=
match l1, l2 with
|   nil,   nil => Eq
|   nil,   _   => Lt
|     _,   nil => Gt
| a::l1, b::l2 => match cmp a b with
|  Eq => list_compare T cmp l1 l2
| res => res
end
end.
Definition tcompare (t1 t2 : tuple) :=
let (i1, i2, i3) := t1 in
let (j1, j2, j3) := t2 in
match tvcompare i1 j1 with
| Eq =>
match tvcompare i2 j2 with
| Eq => tvcompare i3 j3
|  r => r
end
|  r => r
end.
Definition lcompare : line -> line -> _ := list_compare _ tcompare.
Fixpoint linsert (t1 : tuple) (l : line) :=
match l with
|   nil => t1 :: l
| t2::l1 => match tcompare t1 t2 with
|  Gt => t2 :: linsert t1 l1
| res => t1 :: l
end
end.
Fixpoint lsort (l : line) :=
match l with
|   nil => l
| t ::l1 => linsert t (lsort l1)
end.
Fixpoint ltsort (c : sign) (l : line) :=
match l with
|   nil => (c,l)
| t ::l1 =>  let (c1,t1) := tsort t in
let (c2,l2) := ltsort (smult c1 c) l1 in
(c2, linsert t1 l2)
end.
Fixpoint einsert (c1 : coef) (l1 : line) (e : expr) :=
match e with
|   nil => (c1,l1) :: e
| (c2,l2)::e1 => match lcompare l1 l2 with
| Eq => let c := cadd c1 c2 in
if czerop c then e1 else (c,l1)::e1
| Gt => (c2,l2) :: einsert c1 l1 e1
| Lt => (c1,l1) :: e
end
end.
Definition scmp (s : sign) (c : coef) :=
match s with S0 => czero | S1 => c | Sm1 => copp c end.
Fixpoint etsort (e : expr) :=
match e with
|   nil => nil
| (c,l)::e1 => let (c1, l1) := ltsort S1 l in
einsert0 (scmp c1 c) l1 (etsort e1)
end.
(* Reverse a tuple in a tail recursive way *)
Fixpoint rev (T : Type) (t1 t2 : list T) :=
match t1 with nil => t2 | n1 :: t3 => rev _ t3 (n1 :: t2) end.
Definition lrev: line -> line -> _ := rev tuple.
Fixpoint iter_split (c1 : coef) (l l1 : line) (accu : line) (e : expr)
: expr :=
if czerop c1 then e else
match l with
| nil => einsert c1 (lrev accu nil) e
| _ :: l' =>
match l1 with
| nil => einsert c1 (lrev accu nil) e
| t1 ::nil => einsert c1 (lrev accu (t1 ::nil)) e
| t1 :: t2 :: l2 =>
fold_left (fun e (v: sprod) =>
let (s1, t1, t2) := v in
let l3 := linsert t2 l2 in
iter_split (scmp s1 c1) l' l3 (t1 ::accu) e)
(tsplit t1 t2) e
end
end.

Lemma iter_split_c c1 l l1 accu e :
length l1 <= length l ->
{e[iter_split c1 l l1 accu e]} =
({c[c1]} * {l[lrev accu l1]} + {e[e]})%f.