-
Notifications
You must be signed in to change notification settings - Fork 1
/
PolSBase.v
969 lines (772 loc) · 29.8 KB
/
PolSBase.v
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
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
(* Some code to perform simple simplification over a ring *)
Require Export ZArith.
Require Export List.
Require Import PolAuxList.
Section PolSimplBase.
(* The set of the coefficient usually Z or better Q *)
Variable C : Set.
(* Usual operations *)
Variable Cplus : C -> C -> C.
Variable Cmul : C -> C -> C.
Variable Cop : C -> C.
(* Constant *)
Variable C0 : C.
Variable C1 : C.
(* Test to 1 *)
Variable isC1 : C -> bool.
(* Test to 0 *)
Variable isC0 : C -> bool.
(* Test if positive *)
Variable isPos : C -> bool.
(* Divisibility *)
Variable Cdivide : C -> C -> bool.
(* Division *)
Variable Cdiv : C -> C -> C.
(*********************************************************************)
(* *)
(* Auxillary functions on positive *)
(* *)
(*********************************************************************)
(* One positive is smaller than another *)
Definition le_pos p1 p2 := Zle_bool (Zpos p1) (Zpos p2).
(* Two positives are equal *)
Definition eq_pos p1 p2 := Zeq_bool (Zpos p1) (Zpos p2).
(*********************************************************************)
(* *)
(* Polynomial Expressions *)
(* *)
(*********************************************************************)
Inductive PExpr : Set :=
| PEc: C -> PExpr
| PEX: positive -> PExpr
| PEadd: PExpr -> PExpr -> PExpr
| PEsub: PExpr -> PExpr -> PExpr
| PEmul: PExpr -> PExpr -> PExpr
| PEopp: PExpr -> PExpr .
(* Check if a constant is 0 *)
Definition isP0 e :=
match e with PEc c => isC0 c | _ => false end.
(* Check if a constant is 0 *)
Definition isP1 e :=
match e with PEc c => isC1 c | _ => false end.
(* Simplification for mul when 1 or 0 *)
Fixpoint mkPEmulc (c: C) (e: PExpr) :=
if isC0 c then PEc C0 else
if isC1 c then e else
match e with
| (PEc c1) => PEc (Cmul c c1)
| (PEopp e1) => mkPEmulc (Cop c) e1
| (PEmul (PEc c1) e1) => mkPEmulc (Cmul c c1) e1
| _ => PEmul (PEc c) e
end.
Definition mkPEmul (e1 e2 : PExpr) :=
match e1 with
| (PEc c1) => mkPEmulc c1 e2
| (PEopp e3) =>
match e2 with
| (PEc c2) => mkPEmulc (Cop c2) e3
| (PEmul (PEc c2) e4) => mkPEmulc (Cop c2) (PEmul e3 e4)
| (PEopp e4) => PEmul e3 e4
| _ => PEopp (PEmul e3 e2)
end
| (PEmul (PEc c1) e3) =>
match e2 with
| (PEc c2) => mkPEmulc (Cmul c1 c2) e3
| (PEmul (PEc c2) (PEopp e4)) => mkPEmulc (Cmul c1 c2) (PEmul e3 e4)
| (PEopp e4) => mkPEmulc (Cop c1) (PEmul e3 e4)
| _ => mkPEmulc c1 (PEmul e3 e2)
end
| _ =>
match e2 with
| (PEc c2) => mkPEmulc c2 e1
| (PEmul (PEc c2) e4) => mkPEmulc c2 (PEmul e1 e4)
| (PEopp e4) => PEopp (PEmul e1 e4)
| _ => PEmul e1 e2
end
end.
(* Simplification for add when 0 or when to turn it into a substraction *)
Definition mkPEadd (e1 e2 : PExpr) :=
match e1, e2 with
| (PEc c1), (PEc c2) => (PEc (Cplus c1 c2))
| _, _ =>
if isP0 e1 then e2 else
if isP0 e2 then e1 else
match e2 with
| PEmul (PEc c1) e3 =>
if isPos c1 then PEadd e1 e2
else PEsub e1 (mkPEmul (PEc (Cop c1)) e3)
| PEc c1 =>
if isPos c1 then PEadd e1 e2
else PEsub e1 (PEc (Cop c1))
| _ => PEadd e1 e2
end
end.
(* Simplification for opp when double opp and when there is a coefficient *)
Definition mkPEopp (e1 : PExpr) :=
match e1 with
| PEopp e2 => e2
| PEc c1 => PEc (Cop c1)
| PEmul (PEc c1) e2 => PEmul (PEc (Cop c1)) e2
| _ => PEopp e1
end.
(* Simplification for sub when 0 or when to turn it into an addition *)
Definition mkPEsub (e1 e2 : PExpr) :=
match e1, e2 with
| (PEc c1), (PEc c2) => (PEc (Cplus c1 (Cop c2)))
| _ , _ =>
if isP0 e1 then mkPEopp e2 else
if isP0 e2 then e1 else
match e2 with
| PEmul (PEc c1) e3 =>
if isPos c1 then PEsub e1 e2
else PEadd e1 (mkPEmul (PEc (Cop c1)) e3)
| PEc c1 =>
if isPos c1 then PEsub e1 e2
else PEadd e1 (PEc (Cop c1))
| _ => PEsub e1 e2
end
end.
(*********************************************************************)
(* *)
(* First step of the algorithm: *)
(* put a constant at the beginning of each sequence of products. *)
(* These constants play the role of positions *)
(* *)
(*********************************************************************)
(* Factorize the constant in a product. Always return a product by a constant*)
Definition lift_make_mul (e1 e2 : PExpr) : PExpr :=
match e1 with
| PEc c1 =>
match e2 with
| PEc c2 => PEc (Cmul c1 c2)
| PEmul (PEc c2) e4 => PEmul (PEc (Cmul c1 c2)) e4
| _ => PEmul (PEc c1) e2
end
| PEmul (PEc c1) e3 =>
match e2 with
| PEc c2 => PEmul (PEc (Cmul c1 c2)) e3
| PEmul (PEc c2) e4 => PEmul (PEc (Cmul c1 c2)) (PEmul e3 e4)
| _ => PEmul (PEc c1) (PEmul e3 e2)
end
| _ =>
match e2 with
| PEc c2 => PEmul (PEc c2) e1
| PEmul (PEc c2) e4 => PEmul (PEc c2) (PEmul e1 e4)
| _ => PEmul (PEc C1) (PEmul e1 e2)
end
end.
(* Multiply an expression by the constant 1 if necessary *)
Definition list_mult_one e :=
match e with PEX _ => PEmul (PEc C1) e | _ => e end.
(* Put a product by a constant in top of each list of products *)
Fixpoint lift_const (e : PExpr) : PExpr :=
match e with
| PEadd e1 e2 =>
PEadd (list_mult_one (lift_const e1)) (list_mult_one (lift_const e2))
| PEsub e1 e2 =>
PEsub (list_mult_one (lift_const e1)) (list_mult_one (lift_const e2))
| PEmul e1 e2 => lift_make_mul (lift_const e1) (lift_const e2)
| PEopp e1 => PEopp (list_mult_one (lift_const e1))
| _ => list_mult_one e
end.
(*********************************************************************)
(* *)
(* Monomial of Positions *)
(* *)
(*********************************************************************)
(* Variable of position are encoded by a positive *)
Definition pos := positive.
(* Initial pos *)
Definition init_pos : pos := 1%positive.
(* Generate a new position from an old one *)
Definition next_pos (p : pos) : pos := (1 + p)%positive.
(* Monomials for positions are encoded by a list positive *)
Definition mon_pos := list pos.
(* Do the product of two monomials of position *)
Definition prod_pos (e1 e2 : mon_pos) : mon_pos := app e1 e2.
(* Check if a variable of position is in a monomial *)
Fixpoint pos_in_mon (p : pos) (l : mon_pos) {struct l} : bool :=
match l with
| nil => false
| cons p1 l1 => if eq_pos p p1 then true else pos_in_mon p l1
end.
(* Remove a position from a monomial of positions *)
Fixpoint pos_remove (p : pos) (l : mon_pos) {struct l} : mon_pos :=
match l with
| nil => nil
| cons p1 l1 => if eq_pos p p1 then l1 else cons p1 (pos_remove p l1)
end.
(* Insert a variable in an ordered list of position with no repetition *)
Fixpoint insert_list_pos (p1 : pos) (l : list pos) {struct l} : list pos :=
match l with
| nil => cons p1 nil
| cons p2 l1 =>
if eq_pos p1 p2 then l else
if le_pos p1 p2 then cons p1 l
else cons p2 (insert_list_pos p1 l1)
end.
(* Append two ordered list of variable of positions with no repetition *)
Definition append_pos (l1 l2 : list pos) : list pos :=
fold_left (fun l a => insert_list_pos a l) l1 l2.
(* Check if list of positive intersect *)
Fixpoint list_pos_intersect (l1 l2 : list pos) {struct l2} : bool :=
match l2 with
| nil => false
| cons p1 l3 => if pos_in_mon p1 l1 then true else list_pos_intersect l1 l3
end.
(*********************************************************************)
(* *)
(* Monomial of Expressions *)
(* *)
(*********************************************************************)
(* Variable of expression are encoded by a positive *)
Definition exp := positive.
(* Monomials for expressions are encoded by a list positive *)
Definition mon_exp := list exp.
(* Check if two monomials of expressions are equal *)
Fixpoint mon_exp_eq (l1 l2 : mon_exp) {struct l1} : bool :=
match l1, l2 with
| nil, nil => true
| cons p1 l3, cons p2 l4 => if eq_pos p1 p2 then mon_exp_eq l3 l4 else false
| _, _ => false
end.
(* Insert a variable in a monomial of expression *)
Fixpoint insert_exp (p1 : exp) (l : mon_exp) {struct l} : mon_exp :=
match l with
| nil => cons p1 nil
| cons p2 l1 => if le_pos p1 p2 then cons p1 l else cons p2 (insert_exp p1 l1)
end.
(* Do the product of two monomials of expression *)
Definition prod_exp (l1 l2 : mon_exp) : mon_exp :=
fold_left (fun l a => insert_exp a l) l1 l2.
(* An environment associates a value to each position *)
Definition env := (list (pos * C))%type.
(* Empty environment *)
Definition empty_env : env := nil.
(* Add an element in an enviroment *)
Definition add_env n c e : env := cons (n, c) e.
(* Check if the variable is bound in an environment
Check if a position is bounded in an environment *)
Fixpoint is_bound_env (n : pos) (e : env) {struct e} : bool :=
match e with
| nil => false
| cons ((n1, c)) e1 => if eq_pos n n1 then true else is_bound_env n e1
end.
(* The number of times a position is associated to zero in an environment*)
Fixpoint number_of_zero_env (e : env) : Z :=
match e with
| nil => 0%Z
| cons ((n1, c)) e1 =>
if isC0 c then (1 + number_of_zero_env e1)%Z else number_of_zero_env e1
end.
(* Get the value of a position in an enviroment*)
Fixpoint value_env (n : pos) (e : env) {struct e} : C :=
match e with
| nil => C0
| cons ((n1, c)) e1 => if eq_pos n n1 then c else value_env n e1
end.
(* Update the value of a position in an enviroment*)
Fixpoint update_env (n : pos) (c : C) (e : env) {struct e} : env :=
match e with
| nil => cons (n, c) nil
| cons ((n1, c1)) e1 =>
if eq_pos n n1 then cons (n, c) e1 else cons (n1, c1) (update_env n c e1)
end.
(* Merge two environments *)
Definition merge_env (e1 e2 : env) : env :=
fold_left (fun env x =>
match x with (y, val) => update_env y val env end) e1 e2.
(* Restrict an environment with respect a list of position *)
Let restrict_env (l : list pos) (e : env) : env :=
map (fun x => (x, value_env x e)) l.
(* The number of equal associations between two environments*)
Fixpoint number_of_equality_env (e1 e2 : env) {struct e1} : Z :=
match e1 with
| nil => 0%Z
| cons (n1, c) e3 =>
(* if isC0 (Cplus c (Cop (value_env n1 e2))) *)
if isC0 c then number_of_equality_env e3 e2 else
if isC0 (value_env n1 e2) then number_of_equality_env e3 e2 else
if isPos (Cmul c (value_env n1 e2))
then (1 + number_of_equality_env e3 e2)%Z
else number_of_equality_env e3 e2
end.
(*********************************************************************)
(* *)
(* Monomial *)
(* *)
(*********************************************************************)
(* Definition of a monomial composed of a position part and an *)
(* expression part *)
Definition mon := ((C * mon_pos) * mon_exp)%type.
(* Get the positions information of a monomial *)
Definition get_pos (m : mon) := fst m.
(* Get the expression information of a monomial *)
Definition get_exp (m : mon) := snd m.
(* Create a monomial with an empty monomial expression *)
Definition make_const_mon n : list mon := cons ((C1, cons n nil), nil) nil.
(* Create a monomial with an empty position *)
Definition make_exp_mon x : list mon := cons ((C1, nil), cons x nil) nil.
(* The opposite of a monomial *)
Definition opp_mon (m : mon) : mon :=
match m with ((c, l1), l2) => ((Cop c, l1), l2) end.
(* Product of two monomials *)
Definition prod_mon (m1 m2 : mon) : mon :=
match m1, m2 with
| ((c1, l1), l2), ((c2, l3), l4) =>
((Cmul c1 c2, prod_pos l1 l3), prod_exp l2 l4)
end.
(* Distribute a monomial inside a list of monomials *)
Definition insert_mon (m : mon) (l : list mon) : list mon := map (prod_mon m) l.
(* Do the product of two list of monomials *)
Definition app_mon (l1 l2 : list mon) : list mon :=
flat_map (fun x => insert_mon x l1) l2.
(*********************************************************************)
(* *)
(* Second step of the algorithm: *)
(* generate the list of all monomials by applying distributivity. *)
(* The constant at the beginning of each product are replaced by *)
(* variable of position *)
(*********************************************************************)
(* The result of creating the list of monomials: *)
(* the list of monomials *)
(* an environment that associates variable of positions to their *)
(* initial value the position counter *)
Definition list_res := ((list mon * env) * pos)%type.
(*Get the list of monomials from a result *)
Definition list_get_list (r : list_res) : list mon := fst (fst r).
(* Get the default value of the positions *)
Definition list_get_env (e : list_res) :=
match e with ((_, e), _) => e end.
(* Get the number of positions that are generated *)
Definition list_get_pos (e : list_res) : pos :=
match e with ((_, _), n) => n end.
(* Create a result *)
Definition make_list_res l e n : list_res := ((l, e), n).
(* Create the list of monomials *)
Fixpoint make_list (p : PExpr) (e : env) (n : pos) {struct p} : list_res :=
match p with
| PEc c => make_list_res (make_const_mon n) (add_env n c e) (next_pos n)
| PEX x => make_list_res (make_exp_mon x) e n
| PEopp p1 =>
let r1 := make_list p1 e n in
make_list_res
(map opp_mon (list_get_list r1))
(list_get_env r1) (list_get_pos r1)
| PEadd p1 p2 =>
let r1 := make_list p1 e n in
let r2 := make_list p2 (list_get_env r1) (list_get_pos r1) in
make_list_res
(app (list_get_list r1) (list_get_list r2))
(list_get_env r2) (list_get_pos r2)
| PEsub p1 p2 =>
let r1 := make_list p1 e n in
let r2 := make_list p2 (list_get_env r1) (list_get_pos r1) in
make_list_res
(app (list_get_list r1) (map opp_mon (list_get_list r2)))
(list_get_env r2) (list_get_pos r2)
| PEmul p1 p2 =>
let r1 := make_list p1 e n in
let r2 := make_list p2 (list_get_env r1) (list_get_pos r1) in
make_list_res
(app_mon (list_get_list r1) (list_get_list r2))
(list_get_env r2) (list_get_pos r2)
end.
(*********************************************************************)
(* *)
(* Third step of the algorithm: *)
(* regroup the list of monomial by monomials of expressions. *)
(* *)
(*********************************************************************)
(* A factor is a constant multiplied by a monomial of position *)
Definition factor := (C * mon_pos)%type.
(* Get the list of positions that appear in a list of factors *)
Definition factor_pos (l : list factor) : list pos :=
fold_left (fun l a => append_pos (snd a) l) l nil.
(* Eval a list of factors *)
Fixpoint eval_factors (e : env) (eq : list factor) {struct eq} : C :=
match eq with
| nil => C0
| cons ((c, l1)) eq1 =>
Cplus
(Cmul c (fold_left (fun a b => Cmul a (value_env b e)) l1 C1))
(eval_factors e eq1)
end.
(* A group is composed of the monomial expression and it is *)
(* associated list of factor *)
Definition group := (mon_exp * list factor)%type.
(* Create a group *)
Definition make_group e1 e2 : group := (e1, e2).
(* Add a monomial in a list of groups *)
Fixpoint add_groups (m : mon) (l : list group) {struct l} : list group :=
match l with
| nil => cons (make_group (get_exp m) (cons (get_pos m) nil)) nil
| cons ((e, p)) l1 =>
if mon_exp_eq e (get_exp m)
then cons (e, cons (get_pos m) p) l1
else cons (e, p) (add_groups m l1)
end.
(* Convert a list of monomials into a list of groups *)
Definition make_groups (l : list mon) : list group :=
fold_left (fun l a => add_groups a l) l nil.
(**********************************************************************)
(* *)
(* Forth step of the algorithm: *)
(* turn groups into a system, composed of subsystems with *)
(* related equations, so we can resolve subsystems independantly *)
(* *)
(**********************************************************************)
(* Define an equation as a constant associated to a list of factors *)
Definition equation := (C * list factor)%type.
(* Create an equation *)
Definition make_equation (c : C) (f : list factor) : equation := (c, f).
(* Get the constant in an equation *)
Definition get_const (f : equation) : C := fst f.
(* Get the factors *)
Definition get_factors (f : equation) : list factor := snd f.
(* A system is composed of a list of associated positions and list of *)
(* equations *)
Definition system := list (list pos * list equation).
Fixpoint add_equation_to_system_aux
(l : list pos) (f : list equation) (s : system) {struct s} : system :=
match s with
| nil => cons (l,f) nil
| cons ((l1, f1)) s1 =>
if list_pos_intersect l l1
then add_equation_to_system_aux (append_pos l l1) (app f f1) s1
else cons (l1, f1) (add_equation_to_system_aux l f s1)
end.
Definition add_equation_to_system (l : list pos) (f : equation) (s : system)
: system :=
add_equation_to_system_aux l (cons f nil) s.
(* Create a system *)
Fixpoint make_system (e : env) (l : list group) {struct l} : system :=
match l with
| nil => nil
| cons ((_, f)) l1 =>
add_equation_to_system
(factor_pos f) (make_equation (eval_factors e f) f) (make_system e l1)
end.
(************************************************************************)
(* *)
(* Forth step of the algorithm: *)
(* try to solve the different subsystem *)
(* *)
(************************************************************************)
(* Substitute a position p with a value c in the equation is l = cumul,*)
(* to get a new equation *)
Fixpoint pos_subst (p : pos) (c : C) (cumul : C) (l : list factor) {struct l}
: equation :=
match l with
| nil => (cumul, nil)
| cons ((c1, l1)) l2 =>
if pos_in_mon p l1 then
if isC0 (Cmul c c1) then
pos_subst p c cumul l2
else
match pos_remove p l1 with
| nil => pos_subst p c (Cplus cumul (Cop (Cmul c c1))) l2
| cons x y =>
let r1 := pos_subst p c cumul l2 in
(fst r1, cons (Cmul c c1, cons x y) (snd r1))
end
else
let r1 := pos_subst p c cumul l2 in
(fst r1, cons (c1, l1) (snd r1))
end.
Definition update_res := option (equation * option (pos * C)).
(* Update an equation if impossible return None, otherwise the new equation *)
(* and a possible propagation *)
Definition update_equation (p : pos) (c : C) (e : equation) : update_res :=
match pos_subst p c (get_const e) (get_factors e) with
| (c1, nil) =>
if isC0 c1 then Some ((c1, nil), None) else None
| (c1, cons ((c2, cons p1 nil)) nil) =>
if Cdivide c2 c1 then Some ((C0, nil), Some (p1, Cdiv c1 c2)) else None
| (c1, cons ((c2, l1)) nil) =>
if Cdivide c2 c1 then Some ((c1, cons (c2, l1) nil), None) else None
| (c1, l1) => Some ((c1, l1), None)
end.
(* Result of an update of equations*)
Definition updates_res := option (list equation * list (positive * C)).
Definition list_of_option (e : option (positive * C)) :=
match e with None => nil | Some e => cons e nil end.
Definition ocons (x : equation) y :=
match x with (_, nil) => y | _ => (cons x y) end.
Fixpoint update_equations (p : pos) (c : C) (l : list equation) : updates_res :=
match l with
| nil => Some (nil, nil)
| cons eq l1 =>
match update_equation p c eq with
| None => None
| Some ((eq1, v1)) =>
match update_equations p c l1 with
| None => None
| Some ((l2, l3)) => Some (ocons eq1 l2, app (list_of_option v1) l3)
end
end
end.
(* Result of the propagation of an update of equations, *)
(* we use a natural to get the fixpoint behaviour *)
Definition propagate_res := option (list equation * env).
Fixpoint propagate (n : nat) (p : pos) (c : C) (e : env) (l : list equation)
{struct n} : propagate_res :=
match update_equations p c l with
| None => None
| Some ((l1, nil)) => Some (l1, update_env p c e)
| Some ((l1, l2)) =>
match n with
| 0 => None
| S n1 =>
fold_left
(fun res a =>
match res with
| None => None
| Some ((l1, e1)) => propagate n1 (fst a) (snd a) e1 l1
end)
l2 (Some (l1, update_env p c e))
end
end.
(* A candidat is a solution to a subsystem with it is associated *)
(* weight. The weight is used to decide with candidat is the best one *)
Definition candidat := option ((Z * Z) * env).
(* Get the best of two candidats*)
Definition get_best (c1 c2 : candidat) : candidat :=
match c1 with
| None => c2
| Some (((i1, j1), _)) =>
match c2 with
| None => c1
| Some (((i2, j2), _)) =>
if Zeq_bool i1 i2 then if Zle_bool j2 j1 then c1 else c2
else if Zle_bool i1 i2 then c2 else c1
end
end.
(* Check if a better solution is possible *)
Definition is_possible (best : candidat) (e : env) (vars : list pos) : bool :=
match best with
| None => true
| Some ((i1, j1), _) => Zeq_bool i1 (number_of_zero_env e + Zlength vars)
end.
Definition make_candidat (init_e e : env) : candidat :=
Some ((number_of_zero_env e, number_of_equality_env e init_e), e).
(* Try a find a solution using a backtracking algorithm *)
(* that takes the first variable in a list and tries to assign *)
(* it to 0 or to its initial value or leaves it unassigned *)
Fixpoint search_best_aux (best : candidat) (n: nat) (init_e e : env) (l : list equation)
(vars : list pos) {struct vars} : candidat :=
if is_possible best e vars then
match vars with
| nil =>
match l with
| nil => get_best best (make_candidat init_e e)
| _ => best
end
| cons x vars1 =>
if is_bound_env x e then
search_best_aux best n init_e e l vars1
else
let best1 :=
match propagate n x C0 e l with
| None => best
| Some ((l1, e1)) => search_best_aux best n init_e e1 l1 vars1
end
in
let best2 :=
match propagate n x (value_env x init_e) e l with
| None => best
| Some ((l1, e1)) => search_best_aux best1 n init_e e1 l1 vars1
end
in
search_best_aux best2 n init_e e l vars1
end
else best.
Definition search_best (init_e : env) (s : system) : env :=
flat_map
(fun x =>
match x with
| (vars, eqs) =>
match search_best_aux
None (S (length vars)) (restrict_env vars init_e) nil eqs vars
with None => nil | Some (_, e) => e end
end) s.
(**********************************************************************)
(* *)
(* Last step of the algorithm: *)
(* put back the new values of positions into the expression *)
(* to get the new expression *)
(* *)
(**********************************************************************)
Fixpoint make_PExpr_aux (p : PExpr) (e : env) (n : pos) {struct p}
: (PExpr * pos)%type :=
match p with
PEc c => (PEc (value_env n e), next_pos n)
| PEX x => (p, n)
| PEopp p1 =>
let (fr1, sr1) := make_PExpr_aux p1 e n in
(mkPEopp fr1, sr1)
| PEadd p1 p2 =>
let (fr1, sr1) := make_PExpr_aux p1 e n in
let (fr2, sr2) := make_PExpr_aux p2 e sr1 in
(mkPEadd fr1 fr2, sr2)
| PEsub p1 p2 =>
let (fr1, sr1) := make_PExpr_aux p1 e n in
let (fr2, sr2) := make_PExpr_aux p2 e sr1 in
(mkPEsub fr1 fr2, sr2)
| PEmul p1 p2 =>
let (fr1, sr1) := make_PExpr_aux p1 e n in
let (fr2, sr2) := make_PExpr_aux p2 e sr1 in
(mkPEmul fr1 fr2, sr2)
end.
Definition make_PExpr (p : PExpr) (e : env) :=
fst (make_PExpr_aux p e init_pos).
(* Ensure that the top minus is preserved *)
Definition make_PExpr_minus (p : PExpr) (e : env) :=
fst match p with
| PEsub p1 p2 =>
let r1 := make_PExpr_aux p1 e init_pos in
let r2 := make_PExpr_aux p2 e (snd r1) in
(PEsub (fst r1) (fst r2), snd r2)
| _ => make_PExpr_aux p e init_pos
end.
(*********************************************************************)
(* *)
(* Put everything together *)
(* *)
(*********************************************************************)
Definition simpl (e : PExpr) : PExpr :=
let exp := lift_const e in
let res := make_list exp empty_env init_pos in
make_PExpr
exp
(search_best
(list_get_env res)
(make_system (list_get_env res) (make_groups (list_get_list res)))).
(* Ensure that the top minus is preserved *)
Definition simpl_minus (e : PExpr) :=
let exp := lift_const e in
let res := make_list exp empty_env init_pos in
make_PExpr_minus
exp
(search_best
(list_get_env res)
(make_system (list_get_env res) (make_groups (list_get_list res)))).
(*********************************************************************)
(* *)
(* Interfaces *)
(* *)
(*********************************************************************)
Fixpoint convert_back (F : Set) (f : F) (Fadd Fsub Fmult : F -> F -> F)
(Fop : F -> F) (C2F : C -> F) (l : list F) (e : PExpr) : F :=
match e with
| PEc c => C2F c
| PEX x => pos_nth f x l
| PEopp e1 =>
Fop (convert_back F f Fadd Fsub Fmult Fop C2F l e1)
| PEadd e1 e2 =>
Fadd (convert_back F f Fadd Fsub Fmult Fop C2F l e1)
(convert_back F f Fadd Fsub Fmult Fop C2F l e2)
| PEsub e1 e2 =>
Fsub (convert_back F f Fadd Fsub Fmult Fop C2F l e1)
(convert_back F f Fadd Fsub Fmult Fop C2F l e2)
| PEmul e1 e2 =>
Fmult (convert_back F f Fadd Fsub Fmult Fop C2F l e1)
(convert_back F f Fadd Fsub Fmult Fop C2F l e2)
end.
End PolSimplBase.
Arguments PEc [C].
Arguments PEX [C].
Arguments PEadd [C].
Arguments PEsub [C].
Arguments PEmul [C].
Arguments PEopp [C].
(* Code taken from Ring *)
(* Path to handle evar
Ltac IN a l :=
match l with
| (cons a ?l) => constr:true
| (cons _ ?l) => IN a l
| nil => constr:false
end.
*)
Ltac term_eq t1 t2 :=
constr:(ltac:(first[constr_eq t1 t2; exact true | exact false])).
Ltac IN a l :=
match l with
| (cons ?b ?l1) =>
let t := term_eq a b in
match t with
| true => constr:(true)
| _ => IN a l1
end
| nil => false
end.
Ltac AddFv a l :=
match IN a l with
| true => constr:(l)
| _ => constr:(cons a l)
end.
Ltac Find_at a l :=
match l with
| nil => constr:(xH)
| (cons ?b ?l) =>
let t := term_eq a b in
match t with
| true => constr:(xH)
| false => let p := Find_at a l in eval compute in (Pos.succ p)
end
end.
Ltac FV Cst add mul sub opp t fv :=
let rec TFV t fv :=
match t with
| (add ?t1 ?t2) =>
let fv1 := TFV t1 fv in
let fv2 := TFV t2 fv1 in
constr:(fv2)
| (mul ?t1 ?t2) =>
let fv1 := TFV t1 fv in
let fv2 := TFV t2 fv1 in
constr:(fv2)
| (sub ?t1 ?t2) =>
let fv1 := TFV t1 fv in
let fv2 := TFV t2 fv1 in
constr:(fv2)
| (opp ?t1) =>
let fv1 := TFV t1 fv in
constr:(fv1)
| _ =>
match Cst t with
| false =>
let fv1 := AddFv t fv in
constr:(fv1)
| _ => constr:(fv)
end
end
in TFV t fv.
Ltac mkPolexpr T Cst add mul sub opp t fv :=
let rec mkP t :=
match Cst t with
| false =>
match t with
| (add ?t1 ?t2) =>
let e1 := mkP t1 in
let e2 := mkP t2 in
constr:(PEadd e1 e2)
| (mul ?t1 ?t2) =>
let e1 := mkP t1 in
let e2 := mkP t2 in
constr:(PEmul e1 e2)
| (sub ?t1 ?t2) =>
let e1 := mkP t1 in
let e2 := mkP t2 in
constr:(PEsub e1 e2)
| (opp ?t1) =>
let e1 := mkP t1 in
constr:(PEopp e1)
| _ =>
let p := Find_at t fv in
constr:(@PEX T p)
end
| ?c => constr:(PEc c)
end
in mkP t.