aboutsummaryrefslogtreecommitdiff
path: root/mathcomp/attic/multinom.v
blob: cc9d9d8a0de3c8320f95d37c488ee3ae9672f442 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
(* (c) Copyright 2006-2015 Microsoft Corporation and Inria.                  *)
(* Distributed under the terms of CeCILL-B.                                  *)
Require Import mathcomp.ssreflect.ssreflect.
From mathcomp
Require Import ssrfun ssrbool eqtype ssrnat seq choice fintype.
From mathcomp
Require Import tuple finfun bigop ssralg poly generic_quotient bigenough.

(* We build the ring of multinomials with an arbitrary (countable) *)
(* number of indeterminates. We show it is a ring when the base field *)
(* is a ring, and a commutative ring when the base field is commutative *)

(* TODO:
  - when the base field is an integral domain, so are multinomials (WIP)
  - replace the countable type of indeterminates by an arbitrary choice type
  - do the theory of symmetric polynomials
*)



Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.

Local Open Scope ring_scope.
Local Open Scope quotient_scope.

Import GRing.Theory BigEnough.

Module Multinomial.

Section Multinomial.

Variable X : countType.

Section MultinomialRing.

Variable R : ringType.

(* Definining the free algebra of multinomial terms *)
Inductive multi_term :=
| Coef of R
| Var of X
| Oper of bool & multi_term & multi_term.

Notation Sum := (Oper false).
Notation Prod := (Oper true).

(* Encoding to a tree structure in order to recover equality and choice *)
Fixpoint to_tree m : GenTree.tree (X + R) :=
match m with
| Coef x => GenTree.Node 0 [:: GenTree.Leaf (inr _ x)]
| Var x => GenTree.Node 0 [:: GenTree.Leaf (inl _ x)]
| Oper b m1 m2 => GenTree.Node (b.+1)  [:: to_tree m1; to_tree m2]
end.

Fixpoint from_tree t :=
match t with
| GenTree.Node 0 [:: GenTree.Leaf (inr x)] => Some (Coef x)
| GenTree.Node 0 [:: GenTree.Leaf (inl x)] => Some (Var x)
| GenTree.Node n.+1 [:: t1; t2] => 
  if (from_tree t1, from_tree t2) is (Some m1, Some m2)
  then Some (Oper (n == 1)%N m1 m2) else None
| _ => None
end.

Lemma to_treeK : pcancel to_tree from_tree.
Proof. by elim=> //=; case=> ? -> ? ->. Qed.

Definition multi_term_eqMixin := PcanEqMixin to_treeK.
Canonical multi_term_eqType := EqType multi_term multi_term_eqMixin.
Definition multi_term_choiceMixin := PcanChoiceMixin to_treeK.
Canonical multi_term_choiceType := ChoiceType multi_term multi_term_choiceMixin.

(* counting the variables, in order to know how to interpret multi_term *)
Fixpoint nbvar_term t :=
  match t with
    | Coef _ => 0%N
    | Var x => (pickle x).+1
    | Sum u v => maxn (nbvar_term u) (nbvar_term v)
    | Prod u v => maxn (nbvar_term u) (nbvar_term v)
  end.

(* Iterated polynomials over a ring *)
Fixpoint multi n := if n is n.+1 then [ringType of {poly multi n}] else R.

Fixpoint inject n m (p : multi n) {struct m} : multi (m + n) :=
  if m is m'.+1 return multi (m + n) then (inject m' p)%:P else p.

Lemma inject_inj : forall i m, injective (@inject i m).
Proof. by move=> i; elim=> //= m IHm p q; move/polyC_inj; move/IHm. Qed.

Lemma inject0 : forall i m, @inject i m 0 = 0.
Proof. by move=> i; elim=> //= m ->. Qed.

Lemma inject_eq0 : forall i m p, (@inject i m p == 0) = (p == 0).
Proof. by move=> i m p; rewrite -(inj_eq (@inject_inj i m)) inject0. Qed.

Lemma size_inject : forall i m p, size (@inject i m.+1 p) = (p != 0 : nat).
Proof. by move=> i m p; rewrite size_polyC inject_eq0. Qed.

Definition cast_multi i m n Emn : multi i -> multi n :=
  let: erefl in _ = n' := Emn return _ -> multi n' in inject m.

Definition multi_var n (i : 'I_n) := cast_multi (subnK (valP i)) 'X.

Notation "'X_ i" := (multi_var i).

Lemma inject_is_rmorphism : forall m n, rmorphism (@inject n m).
Proof. 
elim=> // m ihm n /=; have ->: inject m = RMorphism (ihm n) by [].
by rewrite -/(_ \o _); apply: rmorphismP.
Qed.
Canonical inject_rmorphism m n := RMorphism (inject_is_rmorphism m n).
Canonical inject_additive m n := Additive (inject_is_rmorphism m n).

Lemma cast_multi_is_rmorphism i m n Enm : rmorphism (@cast_multi i m n Enm).
Proof. by case: n / Enm; apply: rmorphismP. Qed.
Canonical cast_multi_rmorphism i m n e := 
  RMorphism (@cast_multi_is_rmorphism i m n e).
Canonical cast_multi_additive i m n e := 
  Additive (@cast_multi_is_rmorphism i m n e).

Definition multiC n : R -> multi n := cast_multi (addn0 n).
Lemma multiC_is_rmorphism n : rmorphism (multiC n).
Proof. by rewrite /multiC -[R]/(multi 0); apply: rmorphismP. Qed.
Canonical multiC_rmorphism n := RMorphism (multiC_is_rmorphism n).
Canonical multiC_additive n := Additive (multiC_is_rmorphism n).

Lemma cast_multi_inj n i i' n' (m1 m2 : multi n)
  (p1: (i + n)%N=n') (p2: (i' + n)%N=n') :
  cast_multi p1 m1 == cast_multi p2 m2 = (m1 == m2).
Proof.
have := p2; rewrite -{1}[n']p1; move/eqP; rewrite eqn_add2r.
move=> /eqP /= Eii; move:p2; rewrite Eii=> p2 {Eii}.
have <-: p1 = p2; first exact: nat_irrelevance.
apply/idP/idP; last by move/eqP->.
move => Hm {p2}.
have : inject i m1 = inject i m2; last first.
   by move/eqP; rewrite (inj_eq (@inject_inj _ _)).
move: Hm; move:(p1); rewrite -p1 => p2. 
rewrite (_ : p2 = erefl (i+n)%N); last exact: nat_irrelevance. 
by move/eqP.
Qed.

Lemma Emj_Enk i j k m n :
  forall (Emj : (m + i)%N = j) (Enk : (n + j)%N = k), (n + m + i)%N = k.
Proof. by move<-; rewrite addnA. Qed.

Lemma cast_multi_id n (e : (0 + n)%N = n) m : cast_multi e m = m.
Proof. by rewrite (_ : e = erefl _) //; apply: nat_irrelevance. Qed.

Lemma cast_multiS n i n' (m : multi n)
  (p: (i + n)%N = n') (pS: ((i.+1) + n)%N = n'.+1) :
  (cast_multi pS m) = (cast_multi p m)%:P.
Proof. by case: _ / p  in pS *; rewrite [pS](nat_irrelevance _ (erefl _)). Qed.

Lemma injectnm_cast_multi i m n p : 
  inject (n + m)%N p = 
  ((@cast_multi (m + i)%N n ((n + m) + i)%N (addnA _ _ _)) \o (inject m)) p.
Proof.
elim: n => [|n /= -> /=].
  by rewrite [addnA 0%N m i](nat_irrelevance _ (erefl _)).
by rewrite cast_multiS; congr (cast_multi _ _)%:P; apply: nat_irrelevance.
Qed.

Lemma cast_multi_add i j k m n Emj Enk p :
  @cast_multi j n k Enk (@cast_multi i m j Emj p) =
  @cast_multi i (n + m)%N k (Emj_Enk Emj Enk) p.
Proof.
move: (Emj) (Enk) (Emj_Enk Emj Enk); rewrite -Enk -Emj.
change (addn_rec n (addn_rec m i)) with (n+m+i)%N.
rewrite {-1}[(n+(m+i))%N]addnA=> Emj0 Enk0 Enmi.
have ->: (Emj0 = erefl (m+i)%N); first exact: nat_irrelevance.
have ->: (Enmi = erefl (n+m+i)%N); first exact: nat_irrelevance.
rewrite /= injectnm_cast_multi /=.
by apply/eqP; rewrite cast_multi_inj.
Qed.

(* Interpretation of a multi_term in iterated polynomials,
  for a given number of variables n *)
Fixpoint interp n m : multi n :=
  match m with
    | Coef x => multiC n x
    | Var x => let i := pickle x in
      (if i < n as b return (i < n) = b -> multi n
        then fun iltn => cast_multi (subnK iltn) 'X_(Ordinal (leqnn i.+1))
        else fun _ => 0)   (refl_equal (i < n))
    | Sum p q => interp n p + interp n q
    | Prod p q => interp n p * interp n q
end.

Lemma interp_cast_multi n n' m (nltn' : n <= n') :
  nbvar_term m <= n -> interp n' m = cast_multi (subnK nltn') (interp n m).
Proof.
move=> dmltn; have dmltn' := (leq_trans dmltn nltn').
elim: m nltn' dmltn dmltn'.
+ move=> a /= nltn' dmltn dmltn'. 
  apply/eqP; rewrite /multiC. 
  by rewrite cast_multi_add /= cast_multi_inj.
+  move=> N /= nltn' dmltn dmltn'.
  move: (refl_equal (_ N < n')) (refl_equal (_ N < n)).
  rewrite {2 3}[_ N < n]dmltn {2 3}[_ N < n']dmltn' => Nn' Nn.
  by apply/eqP; rewrite cast_multi_add cast_multi_inj.
move=> [] m1 Hm1 m2 Hm2 nltn' /=;
rewrite !geq_max => /andP [dm1n dm1n'] /andP [dm2n dm2n'];
by rewrite (Hm1 nltn') // (Hm2 nltn') // (rmorphM, rmorphD).
Qed.

(* identification of to multi_terms modulo equality of iterated polynomials *)
Definition equivm m1 m2 := let n := maxn (nbvar_term m1) (nbvar_term m2) in
                             interp n m1 == interp n m2.

(* it works even for a bigger n *)
Lemma interp_gtn n m1 m2 : maxn (nbvar_term m1) (nbvar_term m2) <= n -> 
                           equivm m1 m2 = (interp n m1 == interp n m2).
Proof.
move=> hn; rewrite !(interp_cast_multi hn) ?leq_max ?leqnn ?orbT //.
by rewrite cast_multi_inj.
Qed.

Lemma equivm_refl : reflexive equivm. Proof. by move=> x; rewrite /equivm. Qed.

Lemma equivm_sym : symmetric equivm.
Proof. by move=> x y; rewrite /equivm eq_sym maxnC. Qed.

Lemma equivm_trans : transitive equivm.
Proof.
move=> x y z; pose_big_enough n.
  by rewrite !(@interp_gtn n) => // /eqP-> /eqP->.
by close.
Qed.

(* equivm is an equivalence *)
Canonical equivm_equivRel := EquivRel equivm
  equivm_refl equivm_sym equivm_trans.

(* we quotient by the equivalence *)
Definition multinom := {eq_quot equivm}.
Definition multinom_of of phant X & phant R := multinom.

Local Notation "{ 'multinom' R }" := (multinom_of (Phant X) (Phant R))
   (at level 0, format "{ 'multinom'  R }").
(* We recover a lot of structure *)
Canonical multinom_quotType := [quotType of multinom].
Canonical multinom_eqType := [eqType of multinom].
Canonical multinom_eqQuotType := [eqQuotType equivm of multinom].
Canonical multinom_choiceType := [choiceType of multinom].
Canonical multinom_of_quotType := [quotType of {multinom R}].
Canonical multinom_of_eqType := [eqType of {multinom R}].
Canonical multinom_of_eqQuotType := [eqQuotType equivm of {multinom R}].
Canonical multinom_of_choiceType := [choiceType of {multinom R}].

Lemma eqm_interp n m1 m2 : maxn (nbvar_term m1) (nbvar_term m2) <= n -> 
         (interp n m1 == interp n m2) = (m1 == m2 %[mod {multinom R}]).
Proof. by move=> hn; rewrite eqmodE /= -interp_gtn. Qed.

Definition cstm := lift_embed {multinom R} Coef.
Notation "c %:M" := (cstm c) (at level 2, format "c %:M").
Canonical pi_cstm_morph := PiEmbed cstm.

Definition varm := lift_embed {multinom R} Var.
Notation "n %:X" := (varm n) (at level 2, format "n %:X").
Canonical pi_varm_morph := PiEmbed varm.

(* addition is defined by lifting Sum *)
Definition addm := lift_op2 {multinom R} Sum.
Lemma pi_addm : {morph \pi : x y / Sum x y >-> addm x y}.
Proof.
move=> x y /=; unlock addm; apply/eqmodP => /=.
pose_big_enough n.
  rewrite (@interp_gtn n) //=; apply/eqP; congr (_ + _);
  by apply/eqP; rewrite eqm_interp // reprK.
by close.
Qed.
Canonical pi_addm_morph := PiMorph2 pi_addm.

Definition Opp := Prod (Coef (-1)).
Definition oppm := lift_op1 {multinom R} Opp.
Lemma pi_oppm : {morph \pi : x / Opp x >-> oppm x}.
Proof.
move=> x; unlock oppm; apply/eqmodP => /=.
rewrite /equivm /= !max0n; apply/eqP; congr (_ * _).
by apply/eqP; rewrite eqm_interp ?reprK.
Qed.
Canonical pi_oppm_morph := PiMorph1 pi_oppm.

(* addition is defined by lifting Prod *)
Definition mulm := lift_op2 {multinom R} Prod.
Lemma pi_mulm : {morph \pi : x y / Prod x y >-> mulm x y}.
Proof.
move=> x y; unlock mulm; apply/eqP; set x' := repr _; set y' := repr _.
rewrite -(@eqm_interp (nbvar_term (Sum (Sum x y) (Sum x' y')))) /=.
  apply/eqP; congr (_ * _); apply/eqP;
  by rewrite eqm_interp ?reprK // !(geq_max, leq_max, leqnn, orbT).
by rewrite maxnC.
Qed.
Canonical pi_mulm_morph := PiMorph2 pi_mulm.

(* Ring properties are obtained from iterated polynomials *)
Lemma addmA : associative addm.
Proof.
elim/quotW=> x; elim/quotW=> y; elim/quotW=> z; apply/eqP.
by rewrite !piE /equivm /= addrA.
Qed.

Lemma addmC : commutative addm.
Proof.
by elim/quotW=> x; elim/quotW=> y; apply/eqP; rewrite !piE /equivm /= addrC.
Qed.

Lemma add0m : left_id 0%:M addm.
Proof. by elim/quotW=> x; apply/eqP; rewrite piE /equivm /= rmorph0 add0r. Qed.

Lemma addmN : left_inverse 0%:M oppm addm.
Proof.
elim/quotW=> x; apply/eqP; rewrite piE /equivm /=.
by rewrite !rmorph0 rmorphN rmorph1 mulN1r addNr.
Qed.

Definition multinom_zmodMixin :=  ZmodMixin addmA addmC add0m addmN.
Canonical multinom_zmodType := ZmodType multinom multinom_zmodMixin.
Canonical multinom_of_zmodType := ZmodType {multinom R} multinom_zmodMixin.

Lemma mulmA : associative mulm.
Proof.
elim/quotW=> x; elim/quotW=> y; elim/quotW=> z; apply/eqP.
by rewrite piE /equivm /= mulrA.
Qed.

Lemma mul1m : left_id 1%:M mulm.
Proof. by elim/quotW=> x; apply/eqP; rewrite piE /equivm /= rmorph1 mul1r. Qed.

Lemma mulm1 : right_id 1%:M mulm.
Proof.
elim/quotW=> x; rewrite !piE /=; apply/eqmodP; rewrite /= /equivm /=.
by rewrite rmorph1 mulr1.
Qed.

Lemma mulm_addl : left_distributive mulm addm.
Proof.
elim/quotW=> x; elim/quotW=> y; elim/quotW=> z; apply/eqP.
by rewrite !piE /equivm /= mulrDl.
Qed.

Lemma mulm_addr : right_distributive mulm addm.
Proof.
elim/quotW=> x; elim/quotW=> y; elim/quotW=> z; apply/eqP.
by rewrite !piE /equivm /= mulrDr.
Qed.

Lemma nonzero1m : 1%:M != 0%:M.
Proof. by rewrite piE /equivm /= rmorph1 rmorph0 oner_neq0. Qed.

Definition multinom_ringMixin := RingMixin mulmA mul1m mulm1 mulm_addl mulm_addr nonzero1m.
Canonical multinom_ringType := RingType multinom multinom_ringMixin.
Canonical multinom_of_ringType := RingType {multinom R} multinom_ringMixin.

End MultinomialRing.

Notation "{ 'multinom' R }" := (@multinom_of _ (Phant X) (Phant R))
   (at level 0, format "{ 'multinom'  R }").

Notation "c %:M" := (cstm c) (at level 2, format "c %:M").
Notation "n %:X" := (varm n) (at level 2, format "n %:X").

Section MultinomialComRing.

Variable R : comRingType.

Lemma mul_multiC n : commutative (@GRing.mul (multi R n)).
Proof.
suff [M IH_CR] : {CR : comRingType | [ringType of CR] = multi R n}.
  by case: _ / IH_CR => x y; rewrite mulrC.
elim: n => [|n [CR IH_CR]] //=; first by exists R.
by exists [comRingType of {poly CR}]; rewrite -IH_CR.
Qed.

Lemma mulmC : commutative (@mulm R).
Proof.
elim/quotW=> x; elim/quotW=> y; apply/eqP.
by rewrite piE /equivm /= mul_multiC.
Qed.

(* if R is commutative, so is {multinom R} *)
Canonical multinom_comRing := Eval hnf in ComRingType (@multinom R) mulmC.
Canonical multinom_of_comRing := Eval hnf in ComRingType {multinom R} mulmC.

End MultinomialComRing.

Section MultinomialIdomain.

Variable R : idomainType.

(* if R is an integral domain, {multinom R} should also be one,
  but the developpment is unfinished *)
Lemma multi_unitClass n : GRing.UnitRing.class_of (multi R n).
Proof.
suff [D IH_D] : {D : idomainType | [ringType of D] = multi R n}.
  by case: _ / IH_D; case: D => [sort [[[rc /= _ um _ _]]]]; exists rc.
elim: n => [|n [D IH_D]] //=; first by exists R.
by exists [idomainType of {poly D}]; case: _ / IH_D.
Qed.

Canonical multi_unitRing n := GRing.UnitRing.Pack
                                (multi_unitClass n) (multi R n).

(* Definition Unit (m : multi_term R) := *)
(*   let n := nbvar_term m in interp n m \in GRing.unit. *)
(* Definition unitm := lift_fun1 {multinom R} Unit. *)
(* Lemma pi_unitm : {mono \pi : x / Unit x >-> unitm x}. *)
(* Proof. *)
(* move=> x; unlock unitm; rewrite /Unit /=. *)
(* Admitted. *)
(* Canonical pi_unitm_morph := PiMono1 pi_unitm. *)

Lemma multi_idomain n : GRing.IntegralDomain.axiom (multi R n).
Proof.
suff [D IH_D] : {D : idomainType | [ringType of D] = multi R n}.
  by case: _ / IH_D => x y /eqP; rewrite mulf_eq0.
elim: n => [|n [D IH_D]] //=; first by exists R.
by exists [idomainType of {poly D}]; rewrite -IH_D.
Qed.

Lemma multinom_idomain : GRing.IntegralDomain.axiom [ringType of multinom R].
Proof.
elim/quotW=> x; elim/quotW=> y /eqP; rewrite -[_ * _]pi_mulm !piE.
pose_big_enough n.
  by rewrite !(@interp_gtn _ n) //= !rmorph0 => /eqP /multi_idomain.
by close.
Qed.

(* Work in progress *)

End MultinomialIdomain.

End Multinomial.
End Multinomial.