(**************************************************************)
(*   Copyright Dominique Larchey-Wendling [*]                 *)
(*                                                            *)
(*                             [*] Affiliation LORIA -- CNRS  *)
(**************************************************************)
(*      This file is distributed under the terms of the       *)
(*         CeCILL v2 FREE SOFTWARE LICENSE AGREEMENT          *)
(**************************************************************)
(* * Shared libraries *)
(* ** Finitary sums and products over monoids *)
From Undecidability.Shared.Libs.DLW.Utils
Set Implicit Arguments.
Record monoid_theory (X : Type) (m : X -> X -> X) (u : X) := mk_monoid {
monoid_unit_l : forall x, m u x = x;
monoid_unit_r : forall x, m x u = x;
monoid_assoc  : forall x y z, m x (m y z) = m (m x y) z;
}.
Fact Nat_plus_monoid : monoid_theory plus 0.
Fact msum_0 f : ∑ 0 f = u.
Fact msum_plus a b f : ∑ (a+b) f = ∑ a f ⊕ ∑ b (fun i => f (a+i)).
Fact msum_plus1 n f : ∑ (S n) f = ∑ n f ⊕ f n.
Fact msum_ext n f g : (forall i, i < n -> f i = g i) -> ∑ n f = ∑ n g.
Fact msum_unit n : ∑ n (fun _ => u) = u.
Fact msum_comm a n f : (forall i, i < n -> f i ⊕ a = a ⊕ f i) -> ∑ n f ⊕ a = a ⊕ ∑ n f.
Fact msum_sum n f g : (forall i j, i < j < n -> f j ⊕ g i = g i ⊕ f j) -> ∑ n (fun i => f i ⊕ g i) = ∑ n f ⊕ ∑ n g.
Fact msum_of_unit n f : (forall i, i < n -> f i = u) -> ∑ n f = u.
Fact msum_only_one n f i : i < n
-> (forall j, j < n -> i <> j -> f j = u)
-> ∑ n f = f i.
Fact msum_msum n k f :
(forall i1 j1 i2 j2, i1 < n -> j1 < k -> i2 < n -> j2 < k -> f i1 j1 ⊕ f i2 j2 = f i2 j2 ⊕ f i1 j1)
-> ∑ n (fun i => ∑ k (f i)) = ∑ k (fun j => ∑ n (fun i => f i j)).
Fact msum_ends n f : (forall i, 0 < i <= n -> f i = u) -> ∑ (n+2) f = f 0 ⊕ f (S n).
Fact msum_first_two n f : 2 <= n -> (forall i, 2 <= i -> f i = u) -> ∑ n f = f 0 ⊕ f 1.
Definition mscal n x := msum n (fun _ => x).
Fact mscal_0 x : mscal 0 x = u.
Fact mscal_of_unit n : mscal n u = u.
Fact msum_mscal n k f : (forall i j, i < n -> j < n -> f i ⊕ f j = f j ⊕ f i)
-> ∑ n (fun i => mscal k (f i)) = mscal k (∑ n f).
Fact mscal_morph n x : phi (mscal m1 u1 n x) = mscal m2 u2 n (phi x).
Fact times_zero_r x : x ⊗ z = z.
Notation "∑" := (msum sum zero).
Fact sum_0n_scal n k f : ∑ n (fun i => scal k (f i)) = scal k (∑ n f).
Fact scal_one_comm k x : scal k o ⊗ x = x ⊗ scal k o.
Fact sum_0n_distr_l b n f : ∑ n (fun i => b⊗f i) = b⊗∑ n f.
Fact sum_0n_distr_r b n f : ∑ n (fun i => f i⊗b) = ∑ n f ⊗ b.
(*   Newton Binomial theorem for (X,⊕,z,⊗,o) where 1) (X,⊕,z) is a cancellative commutative monoid 2) (X,⊗,o) is a monoid 3) ⊗ distributes over ⊕ on the left and one the right  cancellative could be weakened into z is left and right absorbing for ⊗, ie a⊗z = z⊗a = z  *)

Theorem binomial_Newton n a b :
a ⊗ b = b ⊗ a
-> expo n (a ⊕ b) = ∑ (S n) (fun i => scal (binomial n i) (expo (n - i) a ⊗ expo i b)).