-
Notifications
You must be signed in to change notification settings - Fork 112
/
ordered_qelim.v
1185 lines (1076 loc) · 47.9 KB
/
ordered_qelim.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
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
(* (c) Copyright 2006-2016 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 div choice fintype.
From mathcomp
Require Import bigop ssralg finset fingroup zmodp.
From mathcomp
Require Import poly ssrnum.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
Local Open Scope ring_scope.
Import GRing.
Reserved Notation "p <% q" (at level 70, no associativity).
Reserved Notation "p <=% q" (at level 70, no associativity).
(* Set Printing Width 30. *)
Module ord.
Section Formulas.
Variable T : Type.
Inductive formula : Type :=
| Bool of bool
| Equal of (term T) & (term T)
| Lt of (term T) & (term T)
| Le of (term T) & (term T)
| Unit of (term T)
| And of formula & formula
| Or of formula & formula
| Implies of formula & formula
| Not of formula
| Exists of nat & formula
| Forall of nat & formula.
End Formulas.
Fixpoint term_eq (T : eqType)(t1 t2 : term T) :=
match t1, t2 with
| Var n1, Var n2 => n1 == n2
| Const r1, Const r2 => r1 == r2
| NatConst n1, NatConst n2 => n1 == n2
| Add r1 s1, Add r2 s2 => (term_eq r1 r2) && (term_eq s1 s2)
| Opp r1, Opp r2 => term_eq r1 r2
| NatMul r1 n1, NatMul r2 n2 => (term_eq r1 r2) && (n1 == n2)
| Mul r1 s1, Mul r2 s2 => (term_eq r1 r2) && (term_eq s1 s2)
| Inv r1, Inv r2 => term_eq r1 r2
| Exp r1 n1, Exp r2 n2 => (term_eq r1 r2) && (n1 == n2)
|_, _ => false
end.
Lemma term_eqP (T : eqType) : Equality.axiom (@term_eq T).
Proof.
move=> t1 t2; apply: (iffP idP) => [|<-]; last first.
by elim: t1 {t2} => //= t -> // n; rewrite eqxx.
elim: t1 t2.
- by move=> n1 /= [] // n2 /eqP ->.
- by move=> r1 /= [] // r2 /eqP ->.
- by move=> n1 /= [] // n2 /eqP ->.
- by move=> r1 hr1 r2 hr2 [] //= s1 s2 /andP [] /hr1 -> /hr2 ->.
- by move=> r1 hr1 [] //= s1 /hr1 ->.
- by move=> s1 hs1 n1 [] //= s2 n2 /andP [] /hs1 -> /eqP ->.
- by move=> r1 hr1 r2 hr2 [] //= s1 s2 /andP [] /hr1 -> /hr2 ->.
- by move=> r1 hr1 [] //= s1 /hr1 ->.
- by move=> s1 hs1 n1 [] //= s2 n2 /andP [] /hs1 -> /eqP ->.
Qed.
Canonical term_eqMixin (T : eqType) := EqMixin (@term_eqP T).
Canonical term_eqType (T : eqType) :=
Eval hnf in EqType (term T) (@term_eqMixin T).
Implicit Arguments term_eqP [x y].
Prenex Implicits term_eq.
Bind Scope oterm_scope with term.
Bind Scope oterm_scope with formula.
Arguments Scope Add [_ oterm_scope oterm_scope].
Arguments Scope Opp [_ oterm_scope].
Arguments Scope NatMul [_ oterm_scope nat_scope].
Arguments Scope Mul [_ oterm_scope oterm_scope].
Arguments Scope Mul [_ oterm_scope oterm_scope].
Arguments Scope Inv [_ oterm_scope].
Arguments Scope Exp [_ oterm_scope nat_scope].
Arguments Scope Equal [_ oterm_scope oterm_scope].
Arguments Scope Unit [_ oterm_scope].
Arguments Scope And [_ oterm_scope oterm_scope].
Arguments Scope Or [_ oterm_scope oterm_scope].
Arguments Scope Implies [_ oterm_scope oterm_scope].
Arguments Scope Not [_ oterm_scope].
Arguments Scope Exists [_ nat_scope oterm_scope].
Arguments Scope Forall [_ nat_scope oterm_scope].
Implicit Arguments Bool [T].
Prenex Implicits Const Add Opp NatMul Mul Exp Bool Unit And Or Implies Not.
Prenex Implicits Exists Forall Lt.
Notation True := (Bool true).
Notation False := (Bool false).
Delimit Scope oterm_scope with oT.
Notation "''X_' i" := (Var _ i) : oterm_scope.
Notation "n %:R" := (NatConst _ n) : oterm_scope.
Notation "x %:T" := (Const x) : oterm_scope.
Notation "0" := 0%:R%oT : oterm_scope.
Notation "1" := 1%:R%oT : oterm_scope.
Infix "+" := Add : oterm_scope.
Notation "- t" := (Opp t) : oterm_scope.
Notation "t - u" := (Add t (- u)) : oterm_scope.
Infix "*" := Mul : oterm_scope.
Infix "*+" := NatMul : oterm_scope.
Notation "t ^-1" := (Inv t) : oterm_scope.
Notation "t / u" := (Mul t u^-1) : oterm_scope.
Infix "^+" := Exp : oterm_scope.
Notation "t ^- n" := (t^-1 ^+ n)%oT : oterm_scope.
Infix "==" := Equal : oterm_scope.
Infix "<%" := Lt : oterm_scope.
Infix "<=%" := Le : oterm_scope.
Infix "/\" := And : oterm_scope.
Infix "\/" := Or : oterm_scope.
Infix "==>" := Implies : oterm_scope.
Notation "~ f" := (Not f) : oterm_scope.
Notation "x != y" := (Not (x == y)) : oterm_scope.
Notation "''exists' ''X_' i , f" := (Exists i f) : oterm_scope.
Notation "''forall' ''X_' i , f" := (Forall i f) : oterm_scope.
Section Substitution.
Variable T : Type.
Fixpoint fsubst (f : formula T) (s : nat * term T) :=
match f with
| Bool _ => f
| (t1 == t2) => (tsubst t1 s == tsubst t2 s)
| (t1 <% t2) => (tsubst t1 s <% tsubst t2 s)
| (t1 <=% t2) => (tsubst t1 s <=% tsubst t2 s)
| (Unit t1) => Unit (tsubst t1 s)
| (f1 /\ f2) => (fsubst f1 s /\ fsubst f2 s)
| (f1 \/ f2) => (fsubst f1 s \/ fsubst f2 s)
| (f1 ==> f2) => (fsubst f1 s ==> fsubst f2 s)
| (~ f1) => (~ fsubst f1 s)
| ('exists 'X_i, f1) => ('exists 'X_i, if i == s.1 then f1 else fsubst f1 s)
| ('forall 'X_i, f1) => ('forall 'X_i, if i == s.1 then f1 else fsubst f1 s)
end%oT.
End Substitution.
Section OrderedClause.
Inductive oclause (R : Type) : Type :=
Oclause : seq (term R) -> seq (term R) -> seq (term R) -> seq (term R) -> oclause R.
Definition eq_of_oclause (R : Type)(x : oclause R) :=
let: Oclause y _ _ _ := x in y.
Definition neq_of_oclause (R : Type)(x : oclause R) :=
let: Oclause _ y _ _ := x in y.
Definition lt_of_oclause (R : Type) (x : oclause R) :=
let: Oclause _ _ y _ := x in y.
Definition le_of_oclause (R : Type) (x : oclause R) :=
let: Oclause _ _ _ y := x in y.
End OrderedClause.
Delimit Scope oclause_scope with OCLAUSE.
Open Scope oclause_scope.
Notation "p .1" := (@eq_of_oclause _ p)
(at level 2, left associativity, format "p .1") : oclause_scope.
Notation "p .2" := (@neq_of_oclause _ p)
(at level 2, left associativity, format "p .2") : oclause_scope.
Notation "p .3" := (@lt_of_oclause _ p)
(at level 2, left associativity, format "p .3") : oclause_scope.
Notation "p .4" := (@le_of_oclause _ p)
(at level 2, left associativity, format "p .4") : oclause_scope.
Definition oclause_eq (T : eqType)(t1 t2 : oclause T) :=
let: Oclause eq_l1 neq_l1 lt_l1 leq_l1 := t1 in
let: Oclause eq_l2 neq_l2 lt_l2 leq_l2 := t2 in
[&& eq_l1 == eq_l2, neq_l1 == neq_l2, lt_l1 == lt_l2 & leq_l1 == leq_l2].
Lemma oclause_eqP (T : eqType) : Equality.axiom (@oclause_eq T).
Proof.
move=> t1 t2; apply: (iffP idP) => [|<-] /= ; last first.
by rewrite /oclause_eq; case: t1=> l1 l2 l3 l4; rewrite !eqxx.
case: t1 => [l1 l2 l3 l4]; case: t2 => m1 m2 m3 m4 /=; case/and4P.
by move/eqP=> -> /eqP -> /eqP -> /eqP ->.
Qed.
Canonical oclause_eqMixin (T : eqType) := EqMixin (@oclause_eqP T).
Canonical oclause_eqType (T : eqType) :=
Eval hnf in EqType (oclause T) (@oclause_eqMixin T).
Implicit Arguments oclause_eqP [x y].
Prenex Implicits oclause_eq.
Section EvalTerm.
Variable R : realDomainType.
(* Evaluation of a reified formula *)
Fixpoint holds (e : seq R) (f : ord.formula R) {struct f} : Prop :=
match f with
| Bool b => b
| (t1 == t2)%oT => eval e t1 = eval e t2
| (t1 <% t2)%oT => eval e t1 < eval e t2
| (t1 <=% t2)%oT => eval e t1 <= eval e t2
| Unit t1 => eval e t1 \in unit
| (f1 /\ f2)%oT => holds e f1 /\ holds e f2
| (f1 \/ f2)%oT => holds e f1 \/ holds e f2
| (f1 ==> f2)%oT => holds e f1 -> holds e f2
| (~ f1)%oT => ~ holds e f1
| ('exists 'X_i, f1)%oT => exists x, holds (set_nth 0 e i x) f1
| ('forall 'X_i, f1)%oT => forall x, holds (set_nth 0 e i x) f1
end.
(* Extensionality of formula evaluation *)
Lemma eq_holds e e' f : same_env e e' -> holds e f -> holds e' f.
Proof.
pose sv := set_nth (0 : R).
have eq_i i v e1 e2: same_env e1 e2 -> same_env (sv e1 i v) (sv e2 i v).
by move=> eq_e j; rewrite !nth_set_nth /= eq_e.
elim: f e e' => //=.
- by move=> t1 t2 e e' eq_e; rewrite !(eq_eval _ eq_e).
- by move=> t1 t2 e e' eq_e; rewrite !(eq_eval _ eq_e).
- by move=> t1 t2 e e' eq_e; rewrite !(eq_eval _ eq_e).
- by move=> t e e' eq_e; rewrite (eq_eval _ eq_e).
- by move=> f1 IH1 f2 IH2 e e' eq_e; move/IH2: (eq_e); move/IH1: eq_e; tauto.
- by move=> f1 IH1 f2 IH2 e e' eq_e; move/IH2: (eq_e); move/IH1: eq_e; tauto.
- by move=> f1 IH1 f2 IH2 e e' eq_e f12; move/IH1: (same_env_sym eq_e); eauto.
- by move=> f1 IH1 e e'; move/same_env_sym; move/IH1; tauto.
- by move=> i f1 IH1 e e'; move/(eq_i i)=> eq_e [x f_ex]; exists x; eauto.
by move=> i f1 IH1 e e'; move/(eq_i i); eauto.
Qed.
(* Evaluation and substitution by a constant *)
Lemma holds_fsubst e f i v :
holds e (fsubst f (i, v%:T)%T) <-> holds (set_nth 0 e i v) f.
Proof.
elim: f e => //=; do [
by move=> *; rewrite !eval_tsubst
| move=> f1 IHf1 f2 IHf2 e; move: (IHf1 e) (IHf2 e); tauto
| move=> f IHf e; move: (IHf e); tauto
| move=> j f IHf e].
- case eq_ji: (j == i); first rewrite (eqP eq_ji).
by split=> [] [x f_x]; exists x; rewrite set_set_nth eqxx in f_x *.
split=> [] [x f_x]; exists x; move: f_x; rewrite set_set_nth eq_sym eq_ji;
have:= IHf (set_nth 0 e j x); tauto.
case eq_ji: (j == i); first rewrite (eqP eq_ji).
by split=> [] f_ x; move: (f_ x); rewrite set_set_nth eqxx.
split=> [] f_ x; move: (IHf (set_nth 0 e j x)) (f_ x);
by rewrite set_set_nth eq_sym eq_ji; tauto.
Qed.
(* Boolean test selecting formulas in the theory of rings *)
Fixpoint rformula (f : formula R) :=
match f with
| Bool _ => true
| t1 == t2 => rterm t1 && rterm t2
| t1 <% t2 => rterm t1 && rterm t2
| t1 <=% t2 => rterm t1 && rterm t2
| Unit t1 => false
| (f1 /\ f2) | (f1 \/ f2) | (f1 ==> f2) => rformula f1 && rformula f2
| (~ f1) | ('exists 'X__, f1) | ('forall 'X__, f1) => rformula f1
end%oT.
(* An oformula stating that t1 is equal to 0 in the ring theory. *)
Definition eq0_rform t1 :=
let m := @ub_var R t1 in
let: (t1', r1) := to_rterm t1 [::] m in
let fix loop r i := match r with
| [::] => t1' == 0
| t :: r' =>
let f := ('X_i * t == 1 /\ t * 'X_i == 1) in
'forall 'X_i, (f \/ 'X_i == t /\ ~ ('exists 'X_i, f)) ==> loop r' i.+1
end%oT
in loop r1 m.
(* An oformula stating that t1 is less than 0 in the equational ring theory.
Definition leq0_rform t1 :=
let m := @ub_var R t1 in
let: (t1', r1) := to_rterm t1 [::] m in
let fix loop r i := match r with
| [::] => 'exists 'X_m.+1, t1' == 'X_m.+1 * 'X_m.+1
| t :: r' =>
let f := ('X_i * t == 1 /\ t * 'X_i == 1) in
'forall 'X_i, (f \/ 'X_i == t /\ ~ ('exists 'X_i, f)) ==> loop r' i.+1
end%oT
in loop r1 m.
*)
Definition leq0_rform t1 :=
let m := @ub_var R t1 in
let: (t1', r1) := to_rterm t1 [::] m in
let fix loop r i := match r with
| [::] => t1' <=% 0
| t :: r' =>
let f := ('X_i * t == 1 /\ t * 'X_i == 1) in
'forall 'X_i, (f \/ 'X_i == t /\ ~ ('exists 'X_i, f)) ==> loop r' i.+1
end%oT
in loop r1 m.
(* Definition lt0_rform t1 := *)
(* let m := @ub_var R t1 in *)
(* let: (t1', r1) := to_rterm t1 [::] m in *)
(* let fix loop r i := match r with *)
(* | [::] => 'exists 'X_m.+1, (t1' == 'X_m.+1 * 'X_m.+1 /\ ~ ('X_m.+1 == 0)) *)
(* | t :: r' => *)
(* let f := ('X_i * t == 1 /\ t * 'X_i == 1) in *)
(* 'forall 'X_i, (f \/ 'X_i == t /\ ~ ('exists 'X_i, f)) ==> loop r' i.+1 *)
(* end%oT *)
(* in loop r1 m. *)
Definition lt0_rform t1 :=
let m := @ub_var R t1 in
let: (t1', r1) := to_rterm t1 [::] m in
let fix loop r i := match r with
| [::] => t1' <% 0
| t :: r' =>
let f := ('X_i * t == 1 /\ t * 'X_i == 1) in
'forall 'X_i, (f \/ 'X_i == t /\ ~ ('exists 'X_i, f)) ==> loop r' i.+1
end%oT
in loop r1 m.
(* Transformation of a formula in the theory of rings with units into an *)
(* equivalent formula in the sub-theory of rings. *)
Fixpoint to_rform f :=
match f with
| Bool b => f
| t1 == t2 => eq0_rform (t1 - t2)
| t1 <% t2 => lt0_rform (t1 - t2)
| t1 <=% t2 => leq0_rform (t1 - t2)
| Unit t1 => eq0_rform (t1 * t1^-1 - 1)
| f1 /\ f2 => to_rform f1 /\ to_rform f2
| f1 \/ f2 => to_rform f1 \/ to_rform f2
| f1 ==> f2 => to_rform f1 ==> to_rform f2
| ~ f1 => ~ to_rform f1
| ('exists 'X_i, f1) => 'exists 'X_i, to_rform f1
| ('forall 'X_i, f1) => 'forall 'X_i, to_rform f1
end%oT.
(* The transformation gives a ring formula. *)
(* the last part of the proof consists in 3 cases that are exactly the same.
how to factorize ? *)
Lemma to_rform_rformula f : rformula (to_rform f).
Proof.
suffices [h1 h2 h3]:
[/\ forall t1, rformula (eq0_rform t1),
forall t1, rformula (lt0_rform t1) &
forall t1, rformula (leq0_rform t1)].
by elim: f => //= => f1 ->.
split=> t1.
- rewrite /eq0_rform; move: (ub_var t1) => m.
set tr := _ m.
suffices: all (@rterm R) (tr.1 :: tr.2)%PAIR.
case: tr => {t1} t1 r /= /andP[t1_r].
by elim: r m => [|t r IHr] m; rewrite /= ?andbT // => /andP[->]; apply: IHr.
have: all (@rterm R) [::] by [].
rewrite {}/tr; elim: t1 [::] => //=.
+ move=> t1 IHt1 t2 IHt2 r.
move/IHt1; case: to_rterm => {t1 r IHt1} t1 r /= /andP[t1_r].
move/IHt2; case: to_rterm => {t2 r IHt2} t2 r /= /andP[t2_r].
by rewrite t1_r t2_r.
+ by move=> t1 IHt1 r /IHt1; case: to_rterm.
+ by move=> t1 IHt1 n r /IHt1; case: to_rterm.
+ move=> t1 IHt1 t2 IHt2 r.
move/IHt1; case: to_rterm => {t1 r IHt1} t1 r /= /andP[t1_r].
move/IHt2; case: to_rterm => {t2 r IHt2} t2 r /= /andP[t2_r].
by rewrite t1_r t2_r.
+ move=> t1 IHt1 r.
by move/IHt1; case: to_rterm => {t1 r IHt1} t1 r /=; rewrite all_rcons.
+ by move=> t1 IHt1 n r /IHt1; case: to_rterm.
- rewrite /lt0_rform; move: (ub_var t1) => m; set tr := _ m.
suffices: all (@rterm R) (tr.1 :: tr.2)%PAIR.
case: tr => {t1} t1 r /= /andP[t1_r].
by elim: r m => [|t r IHr] m; rewrite /= ?andbT // => /andP[->]; apply: IHr.
have: all (@rterm R) [::] by [].
rewrite {}/tr; elim: t1 [::] => //=.
+ move=> t1 IHt1 t2 IHt2 r.
move/IHt1; case: to_rterm => {t1 r IHt1} t1 r /= /andP[t1_r].
move/IHt2; case: to_rterm => {t2 r IHt2} t2 r /= /andP[t2_r].
by rewrite t1_r t2_r.
+ by move=> t1 IHt1 r /IHt1; case: to_rterm.
+ by move=> t1 IHt1 n r /IHt1; case: to_rterm.
+ move=> t1 IHt1 t2 IHt2 r.
move/IHt1; case: to_rterm => {t1 r IHt1} t1 r /= /andP[t1_r].
move/IHt2; case: to_rterm => {t2 r IHt2} t2 r /= /andP[t2_r].
by rewrite t1_r t2_r.
+ move=> t1 IHt1 r.
by move/IHt1; case: to_rterm => {t1 r IHt1} t1 r /=; rewrite all_rcons.
+ by move=> t1 IHt1 n r /IHt1; case: to_rterm.
- rewrite /leq0_rform; move: (ub_var t1) => m; set tr := _ m.
suffices: all (@rterm R) (tr.1 :: tr.2)%PAIR.
case: tr => {t1} t1 r /= /andP[t1_r].
by elim: r m => [|t r IHr] m; rewrite /= ?andbT // => /andP[->]; apply: IHr.
have: all (@rterm R) [::] by [].
rewrite {}/tr; elim: t1 [::] => //=.
+ move=> t1 IHt1 t2 IHt2 r.
move/IHt1; case: to_rterm => {t1 r IHt1} t1 r /= /andP[t1_r].
move/IHt2; case: to_rterm => {t2 r IHt2} t2 r /= /andP[t2_r].
by rewrite t1_r t2_r.
+ by move=> t1 IHt1 r /IHt1; case: to_rterm.
+ by move=> t1 IHt1 n r /IHt1; case: to_rterm.
+ move=> t1 IHt1 t2 IHt2 r.
move/IHt1; case: to_rterm => {t1 r IHt1} t1 r /= /andP[t1_r].
move/IHt2; case: to_rterm => {t2 r IHt2} t2 r /= /andP[t2_r].
by rewrite t1_r t2_r.
+ move=> t1 IHt1 r.
by move/IHt1; case: to_rterm => {t1 r IHt1} t1 r /=; rewrite all_rcons.
+ by move=> t1 IHt1 n r /IHt1; case: to_rterm.
Qed.
Import Num.Theory.
(* Correctness of the transformation. *)
Lemma to_rformP e f : holds e (to_rform f) <-> holds e f.
Proof.
suffices{e f} [equal0_equiv lt0_equiv le0_equiv]:
[/\ forall e t1 t2, holds e (eq0_rform (t1 - t2)) <-> (eval e t1 == eval e t2),
forall e t1 t2, holds e (lt0_rform (t1 - t2)) <-> (eval e t1 < eval e t2) &
forall e t1 t2, holds e (leq0_rform (t1 - t2)) <-> (eval e t1 <= eval e t2)].
- elim: f e => /=; try tauto.
+ move=> t1 t2 e.
by split; [move/equal0_equiv/eqP | move/eqP/equal0_equiv].
+ by move=> t1 t2 e; split; move/lt0_equiv.
+ by move=> t1 t2 e; split; move/le0_equiv.
+ by move=> t1 e; rewrite unitrE; apply: equal0_equiv.
+ by move=> f1 IHf1 f2 IHf2 e; move: (IHf1 e) (IHf2 e); tauto.
+ by move=> f1 IHf1 f2 IHf2 e; move: (IHf1 e) (IHf2 e); tauto.
+ by move=> f1 IHf1 f2 IHf2 e; move: (IHf1 e) (IHf2 e); tauto.
+ by move=> f1 IHf1 e; move: (IHf1 e); tauto.
+ by move=> n f1 IHf1 e; split=> [] [x] /IHf1; exists x.
+ by move=> n f1 IHf1 e; split=> Hx x; apply/IHf1.
suffices h e t1 t2 :
[/\ holds e (eq0_rform (t1 - t2)) <-> (eval e t1 == eval e t2),
holds e (lt0_rform (t1 - t2)) <-> (eval e t1 < eval e t2) &
holds e (leq0_rform (t1 - t2)) <-> (eval e t1 <= eval e t2)].
by split => e t1 t2; case: (h e t1 t2).
rewrite -{1}(add0r (eval e t2)) -(can2_eq (subrK _) (addrK _)).
rewrite -subr_lt0 -subr_le0 -/(eval e (t1 - t2)); move: {t1 t2}(t1 - t2)%T => t.
have sub_var_tsubst s t0: (s.1%PAIR >= ub_var t0)%N -> tsubst t0 s = t0.
elim: t0 {t} => //=.
- by move=> n; case: ltngtP.
- by move=> t1 IHt1 t2 IHt2; rewrite geq_max => /andP[/IHt1-> /IHt2->].
- by move=> t1 IHt1 /IHt1->.
- by move=> t1 IHt1 n /IHt1->.
- by move=> t1 IHt1 t2 IHt2; rewrite geq_max => /andP[/IHt1-> /IHt2->].
- by move=> t1 IHt1 /IHt1->.
- by move=> t1 IHt1 n /IHt1->.
pose fix rsub t' m r : term R :=
if r is u :: r' then tsubst (rsub t' m.+1 r') (m, u^-1)%T else t'.
pose fix ub_sub m r : Prop :=
if r is u :: r' then (ub_var u <= m)%N /\ ub_sub m.+1 r' else true.
suffices{t} rsub_to_r t r0 m: (m >= ub_var t)%N -> ub_sub _ m r0 ->
let: (t', r) := to_rterm t r0 m in
[/\ take (size r0) r = r0,
ub_var t' <= m + size r, ub_sub _ m r & rsub t' m r = t]%N.
- have:= rsub_to_r t [::] _ (leqnn _); rewrite /eq0_rform /lt0_rform /leq0_rform.
case: (to_rterm _ _ _) => [t1' r1] /= [//| _ _ ub_r1 def_t].
rewrite -{2 4 6}def_t {def_t}.
elim: r1 (ub_var t) e ub_r1 => [|u r1 IHr1] m e /= => [_|[ub_u ub_r1]].
by split => //; split=> /eqP.
rewrite eval_tsubst /=; set y := eval e u; split; split => //= t_h0.
+ case: (IHr1 m.+1 (set_nth 0 e m y^-1) ub_r1) => h _ _; apply/h.
apply: t_h0.
rewrite nth_set_nth /= eqxx -(eval_tsubst e u (m, Const _)).
rewrite sub_var_tsubst //= -/y.
case Uy: (y \in unit); [left | right]; first by rewrite mulVr ?divrr.
split=> [|[z]]; first by rewrite invr_out ?Uy.
rewrite nth_set_nth /= eqxx.
rewrite -!(eval_tsubst _ _ (m, Const _)) !sub_var_tsubst // -/y => yz1.
by case/unitrP: Uy; exists z.
+ move=> x def_x.
case: (IHr1 m.+1 (set_nth 0 e m x) ub_r1) => h _ _. apply/h.
suff ->: x = y^-1 by []; move: def_x.
rewrite nth_set_nth /= eqxx -(eval_tsubst e u (m, Const _)).
rewrite sub_var_tsubst //= -/y; case=> [[xy1 yx1] | [xy nUy]].
by rewrite -[y^-1]mul1r -[1]xy1 mulrK //; apply/unitrP; exists x.
rewrite invr_out //; apply/unitrP=> [[z yz1]]; case: nUy; exists z.
rewrite nth_set_nth /= eqxx -!(eval_tsubst _ _ (m, _%:T)%T).
by rewrite !sub_var_tsubst.
+ case: (IHr1 m.+1 (set_nth 0 e m y^-1) ub_r1) => _ h _. apply/h.
apply: t_h0.
rewrite nth_set_nth /= eqxx -(eval_tsubst e u (m, Const _)).
rewrite sub_var_tsubst //= -/y.
case Uy: (y \in unit); [left | right]; first by rewrite mulVr ?divrr.
split=> [|[z]]; first by rewrite invr_out ?Uy.
rewrite nth_set_nth /= eqxx.
rewrite -!(eval_tsubst _ _ (m, Const _)) !sub_var_tsubst // -/y => yz1.
by case/unitrP: Uy; exists z.
+ move=> x def_x.
case: (IHr1 m.+1 (set_nth 0 e m x) ub_r1) => _ h _. apply/h.
suff ->: x = y^-1 by []; move: def_x.
rewrite nth_set_nth /= eqxx -(eval_tsubst e u (m, Const _)).
rewrite sub_var_tsubst //= -/y; case=> [[xy1 yx1] | [xy nUy]].
by rewrite -[y^-1]mul1r -[1]xy1 mulrK //; apply/unitrP; exists x.
rewrite invr_out //; apply/unitrP=> [[z yz1]]; case: nUy; exists z.
rewrite nth_set_nth /= eqxx -!(eval_tsubst _ _ (m, _%:T)%T).
by rewrite !sub_var_tsubst.
+ case: (IHr1 m.+1 (set_nth 0 e m y^-1) ub_r1) => _ _ h. apply/h.
apply: t_h0.
rewrite nth_set_nth /= eqxx -(eval_tsubst e u (m, Const _)).
rewrite sub_var_tsubst //= -/y.
case Uy: (y \in unit); [left | right]; first by rewrite mulVr ?divrr.
split=> [|[z]]; first by rewrite invr_out ?Uy.
rewrite nth_set_nth /= eqxx.
rewrite -!(eval_tsubst _ _ (m, Const _)) !sub_var_tsubst // -/y => yz1.
by case/unitrP: Uy; exists z.
+ move=> x def_x.
case: (IHr1 m.+1 (set_nth 0 e m x) ub_r1) => _ _ h. apply/h.
suff ->: x = y^-1 by []; move: def_x.
rewrite nth_set_nth /= eqxx -(eval_tsubst e u (m, Const _)).
rewrite sub_var_tsubst //= -/y; case=> [[xy1 yx1] | [xy nUy]].
by rewrite -[y^-1]mul1r -[1]xy1 mulrK //; apply/unitrP; exists x.
rewrite invr_out //; apply/unitrP=> [[z yz1]]; case: nUy; exists z.
rewrite nth_set_nth /= eqxx -!(eval_tsubst _ _ (m, _%:T)%T).
by rewrite !sub_var_tsubst.
have rsub_id r t0 n: (ub_var t0 <= n)%N -> rsub t0 n r = t0.
by elim: r n => //= t1 r IHr n let0n; rewrite IHr ?sub_var_tsubst ?leqW.
have rsub_acc r s t1 m1:
(ub_var t1 <= m1 + size r)%N -> rsub t1 m1 (r ++ s) = rsub t1 m1 r.
elim: r t1 m1 => [|t1 r IHr] t2 m1 /=; first by rewrite addn0; apply: rsub_id.
by move=> letmr; rewrite IHr ?addSnnS.
elim: t r0 m => /=; try do [
by move=> n r m hlt hub; rewrite take_size (ltn_addr _ hlt) rsub_id
| by move=> n r m hlt hub; rewrite leq0n take_size rsub_id
| move=> t1 IHt1 t2 IHt2 r m; rewrite geq_max; case/andP=> hub1 hub2 hmr;
case: to_rterm {IHt1 hub1 hmr}(IHt1 r m hub1 hmr) => t1' r1;
case=> htake1 hub1' hsub1 <-;
case: to_rterm {IHt2 hub2 hsub1}(IHt2 r1 m hub2 hsub1) => t2' r2 /=;
rewrite geq_max; case=> htake2 -> hsub2 /= <-;
rewrite -{1 2}(cat_take_drop (size r1) r2) htake2; set r3 := drop _ _;
rewrite size_cat addnA (leq_trans _ (leq_addr _ _)) //;
split=> {hsub2}//;
first by [rewrite takel_cat // -htake1 size_take geq_minr];
rewrite -(rsub_acc r1 r3 t1') {hub1'}// -{htake1}htake2 {r3}cat_take_drop;
by elim: r2 m => //= u r2 IHr2 m; rewrite IHr2
| do [ move=> t1 IHt1 r m; do 2!move/IHt1=> {IHt1}IHt1
| move=> t1 IHt1 n r m; do 2!move/IHt1=> {IHt1}IHt1];
case: to_rterm IHt1 => t1' r1 [-> -> hsub1 <-]; split=> {hsub1}//;
by elim: r1 m => //= u r1 IHr1 m; rewrite IHr1].
move=> t1 IH r m letm /IH {IH} /(_ letm) {letm}.
case: to_rterm => t1' r1 /= [def_r ub_t1' ub_r1 <-].
rewrite size_rcons addnS leqnn -{1}cats1 takel_cat ?def_r; last first.
by rewrite -def_r size_take geq_minr.
elim: r1 m ub_r1 ub_t1' {def_r} => /= [|u r1 IHr1] m => [_|[->]].
by rewrite addn0 eqxx.
by rewrite -addSnnS => /IHr1 IH /IH[_ _ ub_r1 ->].
Qed.
(* The above proof is ugly but is in fact copypaste *)
(* Boolean test selecting formulas which describe a constructible set, *)
(* i.e. formulas without quantifiers. *)
(* The quantifier elimination check. *)
Fixpoint qf_form (f : formula R) :=
match f with
| Bool _ | _ == _ | Unit _ | Lt _ _ | Le _ _ => true
| f1 /\ f2 | f1 \/ f2 | f1 ==> f2 => qf_form f1 && qf_form f2
| ~ f1 => qf_form f1
| _ => false
end%oT.
(* Boolean holds predicate for quantifier free formulas *)
Definition qf_eval e := fix loop (f : formula R) : bool :=
match f with
| Bool b => b
| t1 == t2 => (eval e t1 == eval e t2)%bool
| t1 <% t2 => (eval e t1 < eval e t2)%bool
| t1 <=% t2 => (eval e t1 <= eval e t2)%bool
| Unit t1 => eval e t1 \in unit
| f1 /\ f2 => loop f1 && loop f2
| f1 \/ f2 => loop f1 || loop f2
| f1 ==> f2 => (loop f1 ==> loop f2)%bool
| ~ f1 => ~~ loop f1
|_ => false
end%oT.
(* qf_eval is equivalent to holds *)
Lemma qf_evalP e f : qf_form f -> reflect (holds e f) (qf_eval e f).
Proof.
elim: f => //=; try by move=> *; apply: idP.
- by move=> t1 t2 _; apply: eqP.
- move=> f1 IHf1 f2 IHf2 /= /andP[/IHf1[] f1T]; last by right; case.
by case/IHf2; [left | right; case].
- move=> f1 IHf1 f2 IHf2 /= /andP[/IHf1[] f1F]; first by do 2 left.
by case/IHf2; [left; right | right; case].
- move=> f1 IHf1 f2 IHf2 /= /andP[/IHf1[] f1T]; last by left.
by case/IHf2; [left | right; move/(_ f1T)].
by move=> f1 IHf1 /IHf1[]; [right | left].
Qed.
(* Quantifier-free formula are normalized into DNF. A DNF is *)
(* represented by the type seq (seq (term R) * seq (term R)), where we *)
(* separate positive and negative literals *)
(* DNF preserving conjunction *)
Definition and_odnf (bcs1 bcs2 : seq (oclause R)) :=
\big[cat/nil]_(bc1 <- bcs1)
map (fun bc2 : oclause R =>
(Oclause (bc1.1 ++ bc2.1) (bc1.2 ++ bc2.2) (bc1.3 ++ bc2.3) (bc1.4 ++ bc2.4)))%OCLAUSE bcs2.
(* Computes a DNF from a qf ring formula *)
Fixpoint qf_to_odnf (f : formula R) (neg : bool) {struct f} : seq (oclause R) :=
match f with
| Bool b => if b (+) neg then [:: (Oclause [::] [::] [::] [::])] else [::]
| t1 == t2 =>
[:: if neg then (Oclause [::] [:: t1 - t2] [::] [::]) else (Oclause [:: t1 - t2] [::] [::] [::])]
| t1 <% t2 =>
[:: if neg then (Oclause [::] [::] [::] [:: t1 - t2]) else (Oclause [::] [::] [:: t2 - t1] [::])]
| t1 <=% t2 =>
[:: if neg then (Oclause [::] [::] [:: t1 - t2] [::]) else (Oclause [::] [::] [::] [:: t2 - t1])]
| f1 /\ f2 => (if neg then cat else and_odnf) [rec f1, neg] [rec f2, neg]
| f1 \/ f2 => (if neg then and_odnf else cat) [rec f1, neg] [rec f2, neg]
| f1 ==> f2 => (if neg then and_odnf else cat) [rec f1, ~~ neg] [rec f2, neg]
| ~ f1 => [rec f1, ~~ neg]
| _ => if neg then [:: (Oclause [::] [::] [::] [::])] else [::]
end%oT where "[ 'rec' f , neg ]" := (qf_to_odnf f neg).
(* Conversely, transforms a DNF into a formula *)
Definition odnf_to_oform :=
let pos_lit t := And (t == 0)%oT in let neg_lit t := And (t != 0)%oT in
let lt_lit t := And (0 <% t)%oT in let le_lit t := And (0 <=% t)%oT in
let ocls (bc : oclause R) :=
Or
(foldr pos_lit True bc.1 /\ foldr neg_lit True bc.2 /\
foldr lt_lit True bc.3 /\ foldr le_lit True bc.4) in
foldr ocls False.
(* Catenation of dnf is the Or of formulas *)
Lemma cat_dnfP e bcs1 bcs2 :
qf_eval e (odnf_to_oform (bcs1 ++ bcs2))
= qf_eval e (odnf_to_oform bcs1 \/ odnf_to_oform bcs2).
Proof.
by elim: bcs1 => //= bc1 bcs1 IH1; rewrite -orbA; congr orb; rewrite IH1.
Qed.
(* and_dnf is the And of formulas *)
Lemma and_odnfP e bcs1 bcs2 :
qf_eval e (odnf_to_oform (and_odnf bcs1 bcs2))
= qf_eval e (odnf_to_oform bcs1 /\ odnf_to_oform bcs2).
Proof.
elim: bcs1 => [|bc1 bcs1 IH1] /=; first by rewrite /and_odnf big_nil.
rewrite /and_odnf big_cons -/(and_odnf bcs1 bcs2) cat_dnfP /=.
rewrite {}IH1 /= andb_orl; congr orb.
elim: bcs2 bc1 {bcs1} => [|bc2 bcs2 IH] bc1 /=; first by rewrite andbF.
rewrite {}IH /= andb_orr; congr orb => {bcs2}.
suffices aux (l1 l2 : seq (term R)) g : let redg := foldr (And \o g) True in
qf_eval e (redg (l1 ++ l2)) = qf_eval e (redg l1 /\ redg l2)%oT.
+ rewrite !aux /= !andbA; congr (_ && _); rewrite -!andbA; congr (_ && _).
rewrite -andbCA; congr (_ && _); bool_congr; rewrite andbCA; bool_congr.
by rewrite andbA andbC !andbA.
by elim: l1 => [| t1 l1 IHl1] //=; rewrite -andbA IHl1.
Qed.
Lemma qf_to_dnfP e :
let qev f b := qf_eval e (odnf_to_oform (qf_to_odnf f b)) in
forall f, qf_form f && rformula f -> qev f false = qf_eval e f.
Proof.
move=> qev; have qevT f: qev f true = ~~ qev f false.
rewrite {}/qev; elim: f => //=; do [by case | move=> f1 IH1 f2 IH2 | ].
- by move=> t1 t2; rewrite !andbT !orbF.
- by move=> t1 t2; rewrite !andbT !orbF; rewrite !subr_gte0 -lerNgt.
- by move=> t1 t2; rewrite !andbT !orbF; rewrite !subr_gte0 -ltrNge.
- by rewrite and_odnfP cat_dnfP negb_and -IH1 -IH2.
- by rewrite and_odnfP cat_dnfP negb_or -IH1 -IH2.
- by rewrite and_odnfP cat_dnfP /= negb_or IH1 -IH2 negbK.
by move=> t1 ->; rewrite negbK.
rewrite /qev; elim=> //=; first by case.
- by move=> t1 t2 _; rewrite subr_eq0 !andbT orbF.
- by move=> t1 t2 _; rewrite orbF !andbT subr_gte0.
- by move=> t1 t2 _; rewrite orbF !andbT subr_gte0.
- move=> f1 IH1 f2 IH2; rewrite andbCA -andbA andbCA andbA; case/andP.
by rewrite and_odnfP /= => /IH1-> /IH2->.
- move=> f1 IH1 f2 IH2; rewrite andbCA -andbA andbCA andbA; case/andP.
by rewrite cat_dnfP /= => /IH1-> => /IH2->.
- move=> f1 IH1 f2 IH2; rewrite andbCA -andbA andbCA andbA; case/andP.
by rewrite cat_dnfP /= [qf_eval _ _]qevT -implybE => /IH1 <- /IH2->.
by move=> f1 IH1 /IH1 <-; rewrite -qevT.
Qed.
Lemma dnf_to_form_qf bcs : qf_form (odnf_to_oform bcs).
Proof.
elim: bcs => //= [[clT clF] clLt clLe ? ->] /=; elim: clT => //=.
by rewrite andbT; elim: clF; elim: clLt => //; elim: clLe.
Qed.
Definition dnf_rterm (cl : oclause R) :=
[&& all (@rterm R) cl.1, all (@rterm R) cl.2,
all (@rterm R) cl.3 & all (@rterm R) cl.4].
Lemma qf_to_dnf_rterm f b : rformula f -> all dnf_rterm (qf_to_odnf f b).
Proof.
set ok := all dnf_rterm.
have cat_ok bcs1 bcs2: ok bcs1 -> ok bcs2 -> ok (bcs1 ++ bcs2).
by move=> ok1 ok2; rewrite [ok _]all_cat; apply/andP.
have and_ok bcs1 bcs2: ok bcs1 -> ok bcs2 -> ok (and_odnf bcs1 bcs2).
rewrite /and_odnf unlock; elim: bcs1 => //= cl1 bcs1 IH1; rewrite -andbA.
case/and3P=> ok11 ok12 ok1 ok2; rewrite cat_ok ?{}IH1 {bcs1 ok1}//.
elim: bcs2 ok2 => //= cl2 bcs2 IH2 /andP[ok2 /IH2->].
by rewrite /dnf_rterm /= !all_cat andbT ok11; case/and3P: ok12=> -> -> ->.
elim: f b => //=; try by [move=> _ ? ? [] | move=> ? ? ? ? [] /= /andP[]; auto].
- by do 2!case.
- by rewrite /dnf_rterm => ? ? [] /= ->.
- by rewrite /dnf_rterm => ? ? [] /=; rewrite andbC !andbT.
- by rewrite /dnf_rterm => ? ? [] /=; rewrite andbC !andbT.
by auto.
Qed.
Lemma dnf_to_rform bcs : rformula (odnf_to_oform bcs) = all dnf_rterm bcs.
Proof.
elim: bcs => //= [[cl1 cl2 cl3 cl4] bcs ->]; rewrite {2}/dnf_rterm /=; congr (_ && _).
congr andb; first by elim: cl1 => //= t cl ->; rewrite andbT.
congr andb; first by elim: cl2 => //= t cl ->; rewrite andbT.
congr andb; first by elim: cl3 => //= t cl ->.
by elim: cl4 => //= t cl ->.
Qed.
Implicit Type f : formula R.
Fixpoint leq_elim_aux (eq_l lt_l le_l : seq (term R)) :=
match le_l with
[::] => [:: (eq_l, lt_l)]
|le1 :: le_l' =>
let res := leq_elim_aux eq_l lt_l le_l' in
let as_eq := map (fun x => (le1 :: x.1%PAIR, x.2%PAIR)) res in
let as_lt := map (fun x => (x.1%PAIR, le1 :: x.2%PAIR)) res in
as_eq ++ as_lt
end.
Definition oclause_leq_elim oc : seq (oclause R) :=
let: Oclause eq_l neq_l lt_l le_l := oc in
map (fun x => Oclause x.1%PAIR neq_l x.2%PAIR [::])
(leq_elim_aux eq_l lt_l le_l).
Definition terms_of_oclause (oc : oclause R) :=
let: Oclause eq_l neq_l lt_l le_l := oc in
eq_l ++ neq_l ++ lt_l ++ le_l.
Lemma terms_of_leq_elim oc1 oc2:
oc2 \in (oclause_leq_elim oc1) ->
(terms_of_oclause oc2) =i (terms_of_oclause oc1).
case: oc1 => eq1 neq1 lt1 leq1 /=.
elim: leq1 eq1 lt1 oc2 => [|t1 leq1 ih] eq1 lt1 [eq2 neq2 lt2 leq2] /=.
by rewrite inE; case/eqP=> -> -> -> -> ?.
rewrite map_cat /= mem_cat -!map_comp; set f := fun _ => _.
rewrite -/f in ih; case/orP.
case/mapP=> [[y1 y2]] yin ye.
move: (ih eq1 lt1 (f (y1, y2))); rewrite mem_map //; last first.
by move=> [u1 u2] [v1 v2]; rewrite /f /=; case=> -> ->.
move/(_ yin); move: ye; rewrite /f /=; case=> -> -> -> -> /= h.
move=> u; rewrite in_cons (h u) !mem_cat in_cons.
by rewrite orbC !orbA; set x := _ || (u \in lt1); rewrite orbAC.
case/mapP=> [[y1 y2]] yin ye.
move: (ih eq1 lt1 (f (y1, y2))); rewrite mem_map //; last first.
by move=> [u1 u2] [v1 v2]; rewrite /f /=; case=> -> ->.
move/(_ yin); move: ye; rewrite /f /=; case=> -> -> -> -> /= h u.
rewrite !mem_cat !in_cons orbA orbCA -!orbA; move: (h u); rewrite !mem_cat=> ->.
by rewrite orbC !orbA; set x := _ || (u \in lt1); rewrite orbAC.
Qed.
Lemma odnf_to_oform_cat e c d : holds e (odnf_to_oform (c ++ d))
<-> holds e ((odnf_to_oform c) \/ (odnf_to_oform d))%oT.
Proof.
elim: c d => [| tc c ihc] d /=; first by split => // hd; [right | case: hd].
rewrite ihc /=; split.
case; first by case=> ?; case => ?; case => ? ?; left; left.
case; first by move=> ?; left; right.
by move=> ?; right.
case; last by move=> ?; right; right.
case; last by move=> ?; right; left.
by do 3!case=> ?; move=> ?; left.
Qed.
Lemma oclause_leq_elimP oc e :
holds e (odnf_to_oform [:: oc]) <->
holds e (odnf_to_oform (oclause_leq_elim oc)).
Proof.
case: oc => eq_l neq_l lt_l le_l; rewrite /oclause_leq_elim.
elim: le_l eq_l neq_l lt_l => [|t le_l ih] eq_l neq_l lt_l //=.
move: (ih eq_l neq_l lt_l) => /= {ih}.
set x1 := foldr _ _ _; set x2 := foldr _ _ _; set x3 := foldr _ _ _.
set x4 := foldr _ _ _ => h.
have -> : (holds e x1 /\ holds e x2 /\ holds e x3 /\ 0%:R <= eval e t /\
holds e x4 \/ false) <->
(0%:R <= eval e t) /\ (holds e x1 /\ holds e x2 /\ holds e x3 /\
holds e x4 \/ false).
split; first by case=> //; do 4! (case => ?); move=> ?; split => //; left.
by case=> ?; case => //; do 3! (case=> ?); move=> ?; left.
rewrite h {h} /= !map_cat /= -!map_comp.
set s1 := [seq _ | _ <- _]; set s2 := [seq _ | _ <- _].
set s3 := [seq _ | _ <- _]. rewrite odnf_to_oform_cat.
suff {x1 x2 x3 x4} /= -> :
holds e (odnf_to_oform s2) <-> eval e t == 0%:R /\ holds e (odnf_to_oform s1).
suff /= -> :
holds e (odnf_to_oform s3) <-> 0%:R < eval e t /\ holds e (odnf_to_oform s1).
rewrite ler_eqVlt eq_sym; split; first by case; case/orP=> -> ?; [left|right].
by case; [case=> -> ? /= |case=> ->; rewrite orbT].
rewrite /s1 /s3.
elim: (leq_elim_aux eq_l lt_l le_l) => /= [| t1 l ih]; first by split=> // [[]].
rewrite /= ih; split.
case; last by case=> -> ?; split=> //; right.
by do 2!case=> ?; case; case=> -> ? _; split => //; auto.
by case=> ->; case; [do 3!case=> ?; move=> _; left | right].
rewrite /s2 /s1.
elim: (leq_elim_aux eq_l lt_l le_l) => /= [| t1 l ih]; first by split=> // [[]].
rewrite /= ih; split.
case; last by case=> -> ?; split=> //; right.
by case; case=> /eqP ? ?; do 2! case=> ?; move=> _; split=>//; left.
case=> /eqP ?; case; first by do 3!case=> ?; move=> _; left.
by right; split=> //; apply/eqP.
Qed.
Fixpoint neq_elim_aux (lt_l neq_l : seq (term R)) :=
match neq_l with
[::] => [:: lt_l]
|neq1 :: neq_l' =>
let res := neq_elim_aux lt_l neq_l' in
let as_pos := map (fun x => neq1 :: x) res in
let as_neg := map (fun x => Opp neq1 :: x) res in
as_pos ++ as_neg
end.
Definition oclause_neq_elim oc : seq (oclause R) :=
let: Oclause eq_l neq_l lt_l le_l := oc in
map (fun x => Oclause eq_l [::] x le_l) (neq_elim_aux lt_l neq_l).
Lemma terms_of_neq_elim oc1 oc2:
oc2 \in (oclause_neq_elim oc1) ->
{subset (terms_of_oclause oc2) <= (terms_of_oclause oc1) ++ (map Opp oc1.2)}.
Proof.
case: oc1 => eq1 neq1 lt1 leq1 /=.
elim: neq1 lt1 oc2 => [|t1 neq1 ih] lt1 [eq2 neq2 lt2 leq2] /=.
by rewrite inE; case/eqP=> -> -> -> ->; rewrite !cats0 !cat0s.
rewrite map_cat /= mem_cat -!map_comp; set f := fun _ => _.
rewrite -/f in ih; case/orP.
case/mapP=> y yin ye.
move: (ih lt1 (f y)); rewrite mem_map //; last first.
by move=> u v; rewrite /f /=; case.
move/(_ yin); move: ye; rewrite /f /=; case=> -> -> -> -> /= h.
move=> u. rewrite !mem_cat !in_cons orbAC orbC mem_cat -!orbA.
case/orP; first by move->; rewrite !orbT.
rewrite !orbA [_ || (_ \in eq1)]orbC; move: (h u); rewrite !mem_cat=> hu.
by move/hu; do 2! (case/orP; last by move->; rewrite !orbT); move->.
case/mapP=> y yin ye.
move: (ih lt1 (f y)); rewrite mem_map //; last first.
by move=> u v; rewrite /f /=; case.
move/(_ yin); move: ye; rewrite /f /=; case=> -> -> -> -> /= h.
move=> u; rewrite !mem_cat !in_cons orbAC orbC mem_cat -!orbA.
case/orP; first by move->; rewrite !orbT.
rewrite !orbA [_ || (_ \in eq1)]orbC; move: (h u); rewrite !mem_cat=> hu.
by move/hu; do 2! (case/orP; last by move->; rewrite !orbT); move->.
Qed.
Lemma oclause_neq_elimP oc e :
holds e (odnf_to_oform [:: oc]) <->
holds e (odnf_to_oform (oclause_neq_elim oc)).
Proof.
case: oc => eq_l neq_l lt_l le_l; rewrite /oclause_neq_elim.
elim: neq_l lt_l => [|t neq_l ih] lt_l //=.
move: (ih lt_l) => /= {ih}.
set x1 := foldr _ _ _; set x2 := foldr _ _ _; set x3 := foldr _ _ _.
set x4 := foldr _ _ _ => h /=.
have -> : holds e x1 /\
(eval e t <> 0%:R /\
holds e x2) /\
holds e x3 /\ holds e x4 \/
false <->
(eval e t <> 0%:R) /\ (holds e x1 /\ holds e x2 /\ holds e x3 /\
holds e x4 \/ false).
split; case => //.
- by case=> ?; case; case=> ? ? [] ? ?; split=> //; left.
- by move=> ?; case => //; do 3! case => ?; move=> ?; left.
rewrite h {h} /= !map_cat /= -!map_comp.
set s1 := [seq _ | _ <- _]; set s2 := [seq _ | _ <- _].
set s3 := [seq _ | _ <- _]; rewrite odnf_to_oform_cat.
suff {x1 x2 x3 x4} /= -> :
holds e (odnf_to_oform s2) <-> 0%:R < eval e t/\ holds e (odnf_to_oform s1).
suff /= -> :
holds e (odnf_to_oform s3) <-> 0%:R < - eval e t /\ holds e (odnf_to_oform s1).
rewrite oppr_gt0; split.
by case; move/eqP; rewrite neqr_lt; case/orP=> -> h1; [right | left].
by case; case=> h ?; split=> //; apply/eqP; rewrite neqr_lt h ?orbT.
rewrite /s1 /s3.
elim: (neq_elim_aux lt_l neq_l) => /= [| t1 l ih] /=; first by split => //; case.
set y1 := foldr _ _ _; set y2 := foldr _ _ _; set y3 := foldr _ _ _.
rewrite ih; split.
case; first by case=> ?; case=> _; case; case=> -> ? ?; split=> //; left.
by case=> ? ?; split=> //; right.
by case=> ->; case; [case=> ?; case=> _; case=> ? ?; left| move=> ? ; right].
rewrite /s1 /s2.
elim: (neq_elim_aux lt_l neq_l) => /= [| t1 l ih] /=; first by split => //; case.
set y1 := foldr _ _ _; set y2 := foldr _ _ _; set y3 := foldr _ _ _.
rewrite ih; split.
case; first by case=> ? [] _ [] [] ? ? ?; split=> //; left.
by case=> ? ?; split=> //; right.
case=> ? []; last by right.
by case=> ? [] _ [] ? ?; left.
Qed.
Definition oclause_neq_leq_elim oc :=
flatten (map oclause_neq_elim (oclause_leq_elim oc)).
Lemma terms_of_neq_leq_elim oc1 oc2:
oc2 \in (oclause_neq_leq_elim oc1) ->
{subset (terms_of_oclause oc2) <= (terms_of_oclause oc1) ++ map Opp oc1.2}.
Proof.
rewrite /oclause_neq_leq_elim /flatten; rewrite foldr_map.
suff : forall oc3,
oc3 \in (oclause_leq_elim oc1) ->
(terms_of_oclause oc3 =i terms_of_oclause oc1) /\ oc3.2 = oc1.2.
elim: (oclause_leq_elim oc1) => [| t l ih] //= h1.
rewrite mem_cat; case/orP.
- move/terms_of_neq_elim=> h u; move/(h u); rewrite !mem_cat.
by case: (h1 t (mem_head _ _)); move/(_ u)=> -> ->.
- by move=> h; apply: (ih _ h) => ? loc3; apply: h1; rewrite in_cons loc3 orbT.
move=> {oc2} oc3 hoc3; split; first exact: terms_of_leq_elim.
case: oc3 hoc3=> eq2 neq2 lt2 leq2 /=; case: oc1=> eq1 neq1 lt1 leq1 /=.
elim: leq1 => [| t1 le1 ih] //=; first by rewrite inE; case/eqP=> _ ->.
rewrite map_cat mem_cat; move: ih.
elim: (leq_elim_aux eq1 lt1 le1) => [| t2 l2 ih2] //=; rewrite !in_cons.
move=> h1; case/orP=> /=.
case/orP; first by case/eqP.
by move=> h2; apply: ih2; rewrite ?h2 //; move=> h3; apply: h1; rewrite h3 orbT.
case/orP; first by case/eqP.
move=> h3; apply: ih2; last by rewrite h3 orbT.
by move=> h2; apply: h1; rewrite h2 orbT.
Qed.
Lemma oclause_neq_leq_elimP oc e :
holds e (odnf_to_oform [:: oc]) <->
holds e (odnf_to_oform (oclause_neq_leq_elim oc)).
Proof.
rewrite /oclause_neq_leq_elim.
rewrite oclause_leq_elimP; elim: (oclause_leq_elim oc) => [| t l ih] //=.
rewrite odnf_to_oform_cat /= ih -oclause_neq_elimP /=.
suff -> : forall A, A \/ false <-> A by [].
by intuition.
Qed.
Definition oclause_to_w oc :=
let s := oclause_neq_leq_elim oc in
map (fun x => let: Oclause eq_l neq_l lt_l leq_l := x in (eq_l, lt_l)) s.
Definition w_to_oclause (t : seq (term R) * seq (term R)) :=
Oclause t.1%PAIR [::] t.2%PAIR [::].
Lemma oclause_leq_elim4 bc oc : oc \in (oclause_leq_elim bc) -> oc.4 == [::].
Proof.
case: bc => bc1 bc2 bc3 bc4; elim: bc4 bc1 bc3 oc => [|t bc4 ih] bc1 bc3 /= oc.
by rewrite inE; move/eqP; case: oc => ? ? ? oc4 /=; case=> _ _ _ /eqP.
rewrite map_cat; move: (ih bc1 bc3 oc) => /= {ih}.
elim: (leq_elim_aux bc1 bc3 bc4) => [| t2 l2 ih2] //= ih1.
rewrite in_cons; case/orP.
by move/eqP; case: oc {ih1 ih2} => ? ? ? ? [] /= _ _ _ /eqP.
rewrite mem_cat; case/orP=> [hoc1|].
apply: ih2; first by move=> hoc2; apply: ih1; rewrite in_cons hoc2 orbT.
by rewrite mem_cat hoc1.
rewrite in_cons; case/orP=> [| hoc1].
by move/eqP; case: {ih1 ih2} oc=> ? ? ? ? [] /= _ _ _ /eqP.
apply: ih2; first by move=> hoc2; apply: ih1; rewrite in_cons hoc2 orbT.
by rewrite mem_cat hoc1 orbT.
Qed.
Lemma oclause_neq_elim2 bc oc :
oc \in (oclause_neq_elim bc) -> (oc.2 == [::]) && (oc.4 == bc.4).
Proof.
case: bc => bc1 bc2 bc3 bc4; elim: bc2 bc4 oc => [|t bc2 /= ih] bc4 /= oc.
by rewrite inE; move/eqP; case: oc => ? ? ? oc4 /=; case=> _ /eqP -> _ /eqP.
rewrite map_cat; move: (ih bc4 oc) => /= {ih}.
elim: (neq_elim_aux bc3 bc2) => [| t2 l2 ih2] //= ih1.
rewrite in_cons; case/orP.
by move/eqP; case: oc {ih1 ih2} => ? ? ? ? [] /= _ -> _ ->; rewrite !eqxx.
rewrite mem_cat; case/orP=> [hoc1|].
apply: ih2; first by move=> hoc2; apply: ih1; rewrite in_cons hoc2 orbT.
by rewrite mem_cat hoc1.
rewrite in_cons; case/orP=> [| hoc1].
by move/eqP; case: {ih1 ih2} oc=> ? ? ? ? [] /= _ -> _ ->; rewrite !eqxx.
apply: ih2; first by move=> hoc2; apply: ih1; rewrite in_cons hoc2 orbT.
by rewrite mem_cat hoc1 orbT.
Qed.
Lemma oclause_to_wP e bc :