(* We are now ready to define our multiplication *)
Fixpoint join (n : nat) : vect n -> vect n -> vect n :=
match n return (vect n -> vect n -> vect n) with
| 0%nat => fun x y => (x * y)%f
| S n1 =>
fun x y =>
let (x1, x2) := x in
let (y1, y2) := y in (join n1 x1 y2 + join n1 (x2 ^_'f) y1,
join n1 x2 y2)
end.
(* Unicode u2228 *)
Notation "x '∨' y" := (join _ x y) (at level 40, left associativity): type_scope.

(* Specifications: *)
(* (k.x) \/  y = k. (x \/ y) *)
Lemma join_scall n k (x y : vect n) : k .* x ∨ y = k .* (x ∨ y).
Lemma join0 (v1 v2: vect 0) : v1 ∨ v2 = (v1 ∨ v2)%f.
Hint Rewrite join0l: GRm0.
(* x \/ 0  = 0 *)
Lemma join0r n (x : vect n) : x ∨ 0 = 0.
Hint Rewrite join0r: GRm0.
Lemma joinkl n k (x : vect n) : [k] ∨ x = k .* x.
(* x ∨ 1 = 1 *)
Lemma joinkr n k (x : vect n) : x ∨ [k] = k .* x.
(* 1 \/ x  = x *)
Lemma join1l n (x : vect n) : 1 ∨ x = x.
Lemma join_allr n (x: vect n) : x ∨ all n = 'C[x] .* all n.
Lemma join_allhr k n x : hom n k x -> 0 < k -> x ∨ E = 0.
Lemma join_allhl k n x : hom n k x -> 0 < k -> E ∨ x = 0.
(* x \/ (k.y) = k. (x \/ y) *)
Lemma join_scalr n k (x y : vect n) : x ∨ (k .* y) = k .* (x ∨ y).
Lemma joink n k1 k2 : [k1] ∨ [k2] = [k1 * k2] :> vect n.
Lemma join_ei n i (M : vect n.+1) : i < n ->
'e_i.+1 ∨ M =  ((-(1))%f .* ('e_i ∨ fst M), 'e_i ∨ snd M).
(* g_i \/ g_j + g_j \/ g_i = 0 *)
Lemma join_es n i j :
i < n -> j < n -> 'e_ i ∨ 'e_ j + 'e_ j ∨ 'e_ i = (0: vect n).
(* g_i \/ g_i = 0 *)
Lemma join_e n i : i < n -> 'e_ i ∨ 'e_ i = (0 : vect n).
(* (x + y) \/ z = (x \/ z) + (y \/ z) *)
Lemma join_addl n (x y z : vect n) : (x + y) ∨ z = x ∨ z + y ∨ z.
(* z \/ (x + y) = (z \/ x) + (z \/ y) *)
Lemma join_addr n (x y z : vect n) : z ∨ (x + y) = z ∨ x + z ∨ y.
Lemma conjf_join n (x y: vect n) : (x ∨ y) ^_'f =  x ^_'f ∨ y ^_'f.
(* We are now ready to prove associativity ! *)
Lemma join_assoc n (x y z : vect n) : x ∨ y ∨ z = x ∨ (y ∨ z).
(* Anti-commutativity is stable by linear combination *)
Lemma cbl_join_com n (vs: list (vect n)) :
(forall x y, In x vs -> In y vs -> y ∨ x = (- (1)).* (x ∨ y)) ->
forall x y, cbl _ vs x -> cbl _ vs y -> y ∨ x = (- (1)).* (x ∨ y).
(* Anti-commutativity is true for the base *)
Lemma cbl_base_join_com n x y :
cbl _ (base n 1) x -> cbl _ (base n 1) y ->  y ∨ x = (- (1)).* (x ∨ y).
(* x*x = 0 is stable by linear combination *)
Lemma cbl_join_id n vs :
(forall x y, In x vs -> In y vs -> join n y x = (- (1)).* (x ∨ y)) ->
(forall x, In x vs -> x ∨ x = 0) -> forall x, cbl _ vs x -> x ∨ x = 0.
(* x*x = 0 is true for the base *)
Lemma cbl_base_join_id n x : cbl _ (base n 1) x -> x ∨ x = 0.
Lemma join_hom1_id n x : hom n 1 x -> x ∨ x = 0.
(* Lift for the production *)
Lemma lift_join n x y : lift n (x ∨ y) = lift n x ∨ lift n y.
Lemma join_hom n k1 k2 (x y: vect n) :
hom n k1 x -> hom n k2 y -> hom n (k1 + k2) (x ∨ y).