forked from flypitch/flypitch
-
Notifications
You must be signed in to change notification settings - Fork 0
/
fol.lean
2759 lines (2266 loc) · 126 KB
/
fol.lean
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
/-
Copyright (c) 2019 The Flypitch Project. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Jesse Han, Floris van Doorn
-/
/- A development of first-order logic in Lean.
* The object theory uses classical logic
* We use de Bruijn variables.
* We use a deep embedding of the logic, i.e. the type of terms and formulas is inductively defined.
* There is no well-formedness predicate; all elements of type "term" are well-formed.
-/
import .to_mathlib
open nat set
universe variables u v
local notation h :: t := dvector.cons h t
local notation `[` l:(foldr `, ` (h t, dvector.cons h t) dvector.nil `]`:0) := l
namespace fol
/- realizers of variables are just maps ℕ → S. We need some operations on them -/
/-- Given a valuation v, a nat n, and an x : S, return v truncated to its first n values, with the rest of the values replaced by x. --/
def subst_realize {S : Type u} (v : ℕ → S) (x : S) (n k : ℕ) : S :=
if k < n then v k else if n < k then v (k - 1) else x
notation v `[`:95 x ` // `:95 n `]`:0 := fol.subst_realize v x n
/-- --/
@[simp] lemma subst_realize_lt {S : Type u} (v : ℕ → S) (x : S) {n k : ℕ} (H : k < n) :
v[x // n] k = v k :=
by simp only [H, subst_realize, if_true, eq_self_iff_true]
@[simp] lemma subst_realize_gt {S : Type u} (v : ℕ → S) (x : S) {n k : ℕ} (H : n < k) :
v[x // n] k = v (k-1) :=
have h : ¬(k < n), from lt_asymm H,
by simp only [*, subst_realize, if_true, eq_self_iff_true, if_false]
@[simp] lemma subst_realize_var_eq {S : Type u} (v : ℕ → S) (x : S) (n : ℕ) : v[x // n] n = x :=
by simp only [subst_realize, lt_irrefl, eq_self_iff_true, if_false]
lemma subst_realize_congr {S : Type u} {v v' : ℕ → S} (hv : ∀k, v k = v' k) (x : S) (n k : ℕ) :
v [x // n] k = v' [x // n] k :=
by apply decidable.lt_by_cases k n; intro h;
simp only [*, subst_realize_lt, subst_realize_gt, subst_realize_var_eq, eq_self_iff_true]
lemma subst_realize2 {S : Type u} (v : ℕ → S) (x x' : S) (n₁ n₂ k : ℕ) :
v [x' // n₁ + n₂] [x // n₁] k = v [x // n₁] [x' // n₁ + n₂ + 1] k :=
begin
apply decidable.lt_by_cases k n₁; intro h,
{ have : k < n₁ + n₂, from lt_of_le_of_lt (k.le_add_right n₂) (add_lt_add_right h n₂),
have : k < n₁ + n₂ + 1, from lt.step this,
simp only [*, fol.subst_realize_lt, eq_self_iff_true] },
{ have : k < n₂ + (k + 1), from nat.lt_add_left _ _ n₂ (lt.base k),
subst h, simp [*, -add_comm] },
apply decidable.lt_by_cases k (n₁ + n₂ + 1); intro h',
{ have : k - 1 < n₁ + n₂, from (nat.sub_lt_right_iff_lt_add (one_le_of_lt h)).2 h',
simp [*, -add_comm, -add_assoc] },
{ subst h', simp [h, -add_comm, -add_assoc] },
{ have : n₁ + n₂ < k - 1, from nat.lt_sub_right_of_add_lt h',
have : n₁ < k - 1, from lt_of_le_of_lt (n₁.le_add_right n₂) this,
simp only [*, fol.subst_realize_gt, eq_self_iff_true] }
end
lemma subst_realize2_0 {S : Type u} (v : ℕ → S) (x x' : S) (n k : ℕ) :
v [x' // n] [x // 0] k = v [x // 0] [x' // n + 1] k :=
let h := subst_realize2 v x x' 0 n k in by simp only [zero_add] at h; exact h
lemma subst_realize_irrel {S : Type u} {v₁ v₂ : ℕ → S} {n : ℕ} (hv : ∀k < n, v₁ k = v₂ k) (x : S)
{k : ℕ} (hk : k < n + 1) : v₁[x // 0] k = v₂[x // 0] k :=
begin
cases k, refl, have h : 0 < succ k, from zero_lt_succ k, simp [h, hv k (lt_of_succ_lt_succ hk)]
end
lemma lift_subst_realize_cancel {S : Type u} (v : ℕ → S) (k : ℕ) :
(λn, v (n + 1))[v 0 // 0] k = v k :=
begin
cases k, refl, have h : 0 < succ k, from zero_lt_succ k, simp [h],
end
lemma subst_fin_realize_eq {S : Type u} {n} {v₁ : dvector S n} {v₂ : ℕ → S}
(hv : ∀k (hk : k < n), v₁.nth k hk = v₂ k) (x : S) (k : ℕ) (hk : k < n+1) :
(x::v₁).nth k hk = v₂[x // 0] k :=
begin
cases k, refl,
have h : 0 < succ k, from zero_lt_succ k,
have h' : (0 : fin (n+1)).val < (fin.mk (succ k) hk).val, from h,
rw [subst_realize_gt v₂ x h, dvector.nth], apply hv
end
structure Language : Type (u+1) :=
(functions : ℕ → Type u) (relations : ℕ → Type u)
def Language.constants (L : Language) := L.functions 0
variable (L : Language.{u})
/- preterm L l is a partially applied term. if applied to n terms, it becomes a term.
* Every element of preterm L 0 is a well-formed term.
* We use this encoding to avoid mutual or nested inductive types, since those are not too convenient to work with in Lean. -/
inductive preterm : ℕ → Type u
| var {} : ∀ (k : ℕ), preterm 0
| func : ∀ {l : ℕ} (f : L.functions l), preterm l
| app : ∀ {l : ℕ} (t : preterm (l + 1)) (s : preterm 0), preterm l
export preterm
@[reducible] def term := preterm L 0
variable {L}
prefix `&`:max := fol.preterm.var
@[simp] def apps : ∀{l}, preterm L l → dvector (term L) l → term L
| _ t [] := t
| _ t (t'::ts) := apps (app t t') ts
-- @[simp] def apps' : ∀{l l'}, preterm L (l'+l) → dvector (term L) l → preterm L l'
-- | _ _ t [] := t
-- | _ _ t (t'::ts) := apps' (app t t') ts
-- @[simp] def rev_apps : ∀{l l'}, preterm L (l+l) → dvector (term L) l' → preterm L l
-- | _ _ t [] := sorry
-- | l _ t (@dvector.cons _ l' t' ts) := app (@rev_apps (l+1) l' t ts) t'
@[simp] lemma apps_zero (t : term L) (ts : dvector (term L) 0) : apps t ts = t :=
by cases ts; refl
lemma apps_eq_app {l} (t : preterm L (l+1)) (s : term L) (ts : dvector (term L) l) :
∃t' s', apps t (s::ts) = app t' s' :=
begin
induction ts generalizing s, exact ⟨t, s, rfl⟩, exact ts_ih (app t s) ts_x
end
namespace preterm
@[simp] def change_arity' : ∀{l l'} (h : l = l') (t : preterm L l), preterm L l'
| _ _ h &k := by induction h; exact &k
| _ _ h (func f) := func (by induction h; exact f)
| _ _ h (app t₁ t₂) := app (change_arity' (congr_arg succ h) t₁) t₂
@[simp] lemma change_arity'_rfl : ∀{l} (t : preterm L l), change_arity' rfl t = t
| _ &k := by refl
| _ (func f) := by refl
| _ (app t₁ t₂) := by dsimp; simp*
end preterm
-- lemma apps'_concat {l l'} (t : preterm L (l'+(l+1))) (s : term L) (ts : dvector (term L) l) :
-- apps' t (ts.concat s) = app (apps' (t.change_arity' (by simp)) ts) s :=
-- begin
-- induction ts generalizing s,
-- { simp },
-- { apply ts_ih (app t ts_x) s }
-- end
lemma apps_ne_var {l} {f : L.functions l} {ts : dvector (term L) l} {k : ℕ} :
apps (func f) ts ≠ &k :=
begin
intro h, cases ts, injection h,
rcases apps_eq_app (func f) ts_x ts_xs with ⟨t, s, h'⟩, cases h.symm.trans h'
end
lemma apps_inj' {l} {t t' : preterm L l} {ts ts' : dvector (term L) l}
(h : apps t ts = apps t' ts') : t = t' ∧ ts = ts' :=
begin
induction ts; cases ts',
{ exact ⟨h, rfl⟩ },
{ rcases ts_ih h with ⟨⟨rfl, rfl⟩, rfl⟩, exact ⟨rfl, rfl⟩ }
end
-- lemma apps_inj_length {l l'} {f : L.functions l} {f' : L.functions l'}
-- {ts : dvector (term L) l} {ts' : dvector (term L) l'}
-- (h : apps (func f) ts = apps (func f') ts') : l = l' :=
-- begin
-- sorry
-- end
-- lemma apps'_inj_length {l₁ l₂ l'} {f : L.functions (l' + l₁)} {f' : L.functions (l' + l₂)}
-- {ts : dvector (term L) l₁} {ts' : dvector (term L) l₂}
-- (h : apps' (func f) ts = apps' (func f') ts') : l₁ = l₂ :=
-- begin
-- sorry
-- -- induction ts generalizing l'; cases ts',
-- -- { refl },
-- -- { rcases apps'_eq_app (func f') ts'_x ts'_xs with ⟨t, s, h'⟩, cases h.trans h' },
-- -- { rcases apps'_eq_app (func f) ts_x ts_xs with ⟨t, s, h'⟩, cases h.symm.trans h' },
-- -- { rcases apps'_eq_app (func f) ts_x ts_xs with ⟨t₁, s₁, h₁⟩,
-- -- rcases apps'_eq_app (func f') ts'_x ts'_xs with ⟨t₂, s₂, h₂⟩,
-- -- }
-- end
lemma apps_inj {l} {f f' : L.functions l} {ts ts' : dvector (term L) l}
(h : apps (func f) ts = apps (func f') ts') : f = f' ∧ ts = ts' :=
by rcases apps_inj' h with ⟨h', rfl⟩; cases h'; exact ⟨rfl, rfl⟩
def term_of_function {l} (f : L.functions l) : arity' (term L) (term L) l :=
arity'.of_dvector_map $ apps (func f)
@[elab_as_eliminator] def term.rec {C : term L → Sort v}
(hvar : ∀(k : ℕ), C &k)
(hfunc : Π {l} (f : L.functions l) (ts : dvector (term L) l) (ih_ts : ∀t, ts.pmem t → C t),
C (apps (func f) ts)) : ∀(t : term L), C t :=
have h : ∀{l} (t : preterm L l) (ts : dvector (term L) l) (ih_ts : ∀s, ts.pmem s → C s),
C (apps t ts),
begin
intros, induction t; try {rw ts.zero_eq},
{ apply hvar },
{ apply hfunc t_f ts ih_ts },
{ apply t_ih_t (t_s::ts), intros t ht,
cases ht,
{ induction ht, apply t_ih_s ([]), intros s hs, cases hs },
{ exact ih_ts t ht }},
end,
λt, h t ([]) (by intros s hs; cases hs)
@[elab_as_eliminator] def term.elim' {C : Type v}
(hvar : ∀(k : ℕ), C)
(hfunc : Π {{l}} (f : L.functions l) (ts : dvector (term L) l) (ih_ts : dvector C l), C) :
∀{l} (t : preterm L l) (ts : dvector (term L) l) (ih_ts : dvector C l), C
| _ &k ts ih_ts := hvar k
| _ (func f) ts ih_ts := hfunc f ts ih_ts
| _ (app t s) ts ih_ts := term.elim' t (s::ts) (term.elim' s ([]) ([])::ih_ts)
@[elab_as_eliminator] def term.elim {C : Type v}
(hvar : ∀(k : ℕ), C)
(hfunc : Π {{l}} (f : L.functions l) (ts : dvector (term L) l) (ih_ts : dvector C l), C) :
∀(t : term L), C :=
λt, term.elim' hvar hfunc t ([]) ([])
lemma term.elim'_apps {C : Type v}
(hvar : ∀(k : ℕ), C)
(hfunc : Π {{l}} (f : L.functions l) (ts : dvector (term L) l) (ih_ts : dvector C l), C)
{l} (t : preterm L l) (ts : dvector (term L) l) :
@term.elim' L C hvar hfunc 0 (apps t ts) ([]) ([]) = @term.elim' L C hvar hfunc l t ts
(ts.map $ term.elim hvar hfunc) :=
begin
induction ts,
{ refl },
{ dsimp only [dvector.map, apps], rw [ts_ih], refl }
end
lemma term.elim_apps {C : Type v}
(hvar : ∀(k : ℕ), C)
(hfunc : Π {{l}} (f : L.functions l) (ts : dvector (term L) l) (ih_ts : dvector C l), C)
{l} (f : L.functions l) (ts : dvector (term L) l) :
@term.elim L C hvar hfunc (apps (func f) ts) = hfunc f ts (ts.map $ @term.elim L C hvar hfunc) :=
by dsimp only [term.elim]; rw term.elim'_apps; refl
/- lift_term_at _ t n m raises variables in t which are at least m by n -/
@[simp] def lift_term_at : ∀ {l}, preterm L l → ℕ → ℕ → preterm L l
| _ &k n m := &(if m ≤ k then k+n else k)
| _ (func f) n m := func f
| _ (app t₁ t₂) n m := app (lift_term_at t₁ n m) (lift_term_at t₂ n m)
notation t ` ↑' `:90 n ` # `:90 m:90 := fol.lift_term_at t n m -- input ↑ with \u or \upa
-- @[simp] lemma lift_term_var_le {k n m} (h : m ≤ k) : &k ↑' n # m = (&(k+n) : term L) := dif_pos h
-- @[simp] lemma lift_term_var_gt {k n m} (h : ¬(m ≤ k)) : &k ↑' n # m = (&k : term L) := dif_neg h
-- @[simp] lemma lift_term_at_func {l} (f : L.functions l) (n m) : func f ↑' n # m = func f := by refl
-- @[simp] lemma lift_term_at_app {l} (t : preterm L (l+1)) (s : preterm L 0) (n m) :
-- app t s ↑' n # m = app (t ↑' n # m) (s ↑' n # m) := by refl
@[reducible] def lift_term {l} (t : preterm L l) (n : ℕ) : preterm L l := t ↑' n # 0
infix ` ↑ `:100 := fol.lift_term -- input ↑' with \u or \upa
@[reducible, simp] def lift_term1 {l} (t : preterm L l) : preterm L l := t ↑ 1
@[simp] lemma lift_term_def {l} (t : preterm L l) (n : ℕ) : t ↑' n # 0 = t ↑ n := by refl
lemma injective_lift_term_at : ∀ {l} {n m : ℕ},
function.injective (λ(t : preterm L l), lift_term_at t n m)
| _ n m &k &k' h :=
by by_cases h₁ : m ≤ k; by_cases h₂ : m ≤ k'; simp [h₁, h₂] at h;
congr;[assumption, skip, skip, assumption]; exfalso; try {apply h₁};
try {apply h₂}; subst h; apply le_trans (by assumption) (le_add_left _ _)
| _ n m &k (func f') h := by cases h
| _ n m &k (app t₁' t₂') h := by cases h
| _ n m (func f) &k' h := by cases h
| _ n m (func f) (func f') h := h
| _ n m (func f) (app t₁' t₂') h := by cases h
| _ n m (app t₁ t₂) &k' h := by cases h
| _ n m (app t₁ t₂) (func f') h := by cases h
| _ n m (app t₁ t₂) (app t₁' t₂') h :=
begin injection h, congr; apply injective_lift_term_at; assumption end
@[simp] lemma lift_term_at_zero : ∀ {l} (t : preterm L l) (m : ℕ), t ↑' 0 # m = t
| _ &k m := by simp [lift_term_at]
| _ (func f) m := by refl
| _ (app t₁ t₂) m := by dsimp; congr; apply lift_term_at_zero
@[simp] lemma lift_term_zero {l} (t : preterm L l) : t ↑ 0 = t := lift_term_at_zero t 0
/- the following lemmas simplify iterated lifts, depending on the size of m' -/
lemma lift_term_at2_small : ∀ {l} (t : preterm L l) (n n') {m m'}, m' ≤ m →
(t ↑' n # m) ↑' n' # m' = (t ↑' n' # m') ↑' n # (m + n')
| _ &k n n' m m' H :=
begin
by_cases h : m ≤ k,
{ have h₁ : m' ≤ k := le_trans H h,
have h₂ : m' ≤ k + n, from le_trans h₁ (k.le_add_right n),
simp [*, -add_assoc, -add_comm], simp },
{ have h₁ : ¬m + n' ≤ k + n', from λ h', h (le_of_add_le_add_right h'),
have h₂ : ¬m + n' ≤ k, from λ h', h₁ (le_trans h' (k.le_add_right n')),
by_cases h' : m' ≤ k; simp [*, -add_comm, -add_assoc] }
end
| _ (func f) n n' m m' H := by refl
| _ (app t₁ t₂) n n' m m' H :=
begin dsimp; congr1; apply lift_term_at2_small; assumption end
lemma lift_term_at2_medium : ∀ {l} (t : preterm L l) {n} (n') {m m'}, m ≤ m' → m' ≤ m+n →
(t ↑' n # m) ↑' n' # m' = t ↑' (n+n') # m
| _ &k n n' m m' H₁ H₂ :=
begin
by_cases h : m ≤ k,
{ have h₁ : m' ≤ k + n, from le_trans H₂ (add_le_add_right h n), simp [*, -add_comm], },
{ have h₁ : ¬m' ≤ k, from λ h', h (le_trans H₁ h'), simp [*, -add_comm, -add_assoc] }
end
| _ (func f) n n' m m' H₁ H₂ := by refl
| _ (app t₁ t₂) n n' m m' H₁ H₂ :=
begin dsimp; congr1; apply lift_term_at2_medium; assumption end
lemma lift_term2_medium {l} (t : preterm L l) {n} (n') {m'} (h : m' ≤ n) :
(t ↑ n) ↑' n' # m' = t ↑ (n+n') :=
lift_term_at2_medium t n' m'.zero_le (by simp*)
lemma lift_term2 {l} (t : preterm L l) (n n') : (t ↑ n) ↑ n' = t ↑ (n+n') :=
lift_term2_medium t n' n.zero_le
lemma lift_term_at2_eq {l} (t : preterm L l) (n n' m : ℕ) :
(t ↑' n # m) ↑' n' # (m+n) = t ↑' (n+n') # m :=
lift_term_at2_medium t n' (m.le_add_right n) (le_refl _)
lemma lift_term_at2_large {l} (t : preterm L l) {n} (n') {m m'} (H : m + n ≤ m') :
(t ↑' n # m) ↑' n' # m' = (t ↑' n' # (m'-n)) ↑' n # m :=
have H₁ : n ≤ m', from le_trans (n.le_add_left m) H,
have H₂ : m ≤ m' - n, from nat.le_sub_right_of_add_le H,
begin rw fol.lift_term_at2_small t n' n H₂, rw [nat.sub_add_cancel], exact H₁ end
@[simp] lemma lift_term_var0 (n : ℕ) : &0 ↑ n = (&n : term L) :=
by have h : 0 ≤ 0 := le_refl 0; rw [←lift_term_def]; simp [h, -lift_term_def]
@[simp] lemma lift_term_at_apps {l} (t : preterm L l) (ts : dvector (term L) l) (n m : ℕ) :
(apps t ts) ↑' n # m = apps (t ↑' n # m) (ts.map $ λx, x ↑' n # m) :=
by induction ts generalizing t;[refl, apply ts_ih (app t ts_x)]
@[simp] lemma lift_term_apps {l} (t : preterm L l) (ts : dvector (term L) l) (n : ℕ) :
(apps t ts) ↑ n = apps (t ↑ n) (ts.map $ λx, x ↑ n) :=
lift_term_at_apps t ts n 0
/- subst_term t s n substitutes s for (&n) and reduces the level of all variables above n by 1 -/
def subst_term : ∀ {l}, preterm L l → term L → ℕ → preterm L l
| _ &k s n := subst_realize var (s ↑ n) n k
| _ (func f) s n := func f
| _ (app t₁ t₂) s n := app (subst_term t₁ s n) (subst_term t₂ s n)
notation t `[`:max s ` // `:95 n `]`:0 := fol.subst_term t s n
@[simp] lemma subst_term_var_lt (s : term L) {k n : ℕ} (H : k < n) : &k[s // n] = &k :=
by simp only [H, fol.subst_term, fol.subst_realize_lt, eq_self_iff_true]
@[simp] lemma subst_term_var_gt (s : term L) {k n : ℕ} (H : n < k) : &k[s // n] = &(k-1) :=
by simp only [H, fol.subst_term, fol.subst_realize_gt, eq_self_iff_true]
@[simp] lemma subst_term_var_eq (s : term L) (n : ℕ) : &n[s // n] = s ↑' n # 0 :=
by simp [subst_term]
lemma subst_term_var0 (s : term L) : &0[s // 0] = s := by simp
@[simp] lemma subst_term_func {l} (f : L.functions l) (s : term L) (n : ℕ) :
(func f)[s // n] = func f :=
by refl
@[simp] lemma subst_term_app {l} (t₁ : preterm L (l+1)) (t₂ s : term L) (n : ℕ) :
(app t₁ t₂)[s // n] = app (t₁[s // n]) (t₂[s // n]) :=
by refl
@[simp] lemma subst_term_apps {l} (t : preterm L l) (ts : dvector (term L) l) (s : term L)
(n : ℕ) : (apps t ts)[s // n] = apps (t[s // n]) (ts.map $ λx, x[s // n]) :=
by induction ts generalizing t;[refl, apply ts_ih (app t ts_x)]
/- the following lemmas simplify first lifting and then substituting, depending on the size
of the substituted variable -/
lemma lift_at_subst_term_large : ∀{l} (t : preterm L l) (s : term L) {n₁} (n₂) {m}, m ≤ n₁ →
(t ↑' n₂ # m)[s // n₁+n₂] = (t [s // n₁]) ↑' n₂ # m
| _ &k s n₁ n₂ m h :=
begin
apply decidable.lt_by_cases k n₁; intro h₂,
{ have : k < n₁ + n₂, from lt_of_le_of_lt (k.le_add_right n₂) (by simp*),
by_cases m ≤ k; simp* },
{ subst h₂, simp [*, lift_term2_medium] },
{ have h₂ : m < k, by apply lt_of_le_of_lt; assumption,
have : m ≤ k - 1, from nat.le_sub_right_of_add_le (succ_le_of_lt h₂),
have : m ≤ k, from le_of_lt h₂,
have : 1 ≤ k, from one_le_of_lt h₂,
simp [*, nat.add_sub_swap this n₂, -add_assoc, -add_comm] }
end
| _ (func f) s n₁ n₂ m h := rfl
| _ (app t₁ t₂) s n₁ n₂ m h := by simp*
lemma lift_subst_term_large {l} (t : preterm L l) (s : term L) (n₁ n₂) :
(t ↑ n₂)[s // n₁+n₂] = (t [s // n₁]) ↑ n₂ :=
lift_at_subst_term_large t s n₂ n₁.zero_le
lemma lift_subst_term_large' {l} (t : preterm L l) (s : term L) (n₁ n₂) :
(t ↑ n₂)[s // n₂+n₁] = (t [s // n₁]) ↑ n₂ :=
by rw [add_comm]; apply lift_subst_term_large
lemma lift_at_subst_term_medium : ∀{l} (t : preterm L l) (s : term L) {n₁ n₂ m}, m ≤ n₂ →
n₂ ≤ m + n₁ → (t ↑' n₁+1 # m)[s // n₂] = t ↑' n₁ # m
| _ &k s n₁ n₂ m h₁ h₂ :=
begin
by_cases h : m ≤ k,
{ have h₃ : n₂ < k + (n₁ + 1), from lt_succ_of_le (le_trans h₂ (add_le_add_right h _)),
simp [*, add_sub_cancel_right] },
{ have h₃ : k < n₂, from lt_of_lt_of_le (lt_of_not_ge h) h₁, simp* }
end
| _ (func f) s n₁ n₂ m h₁ h₂ := rfl
| _ (app t₁ t₂) s n₁ n₂ m h₁ h₂ := by simp*
lemma lift_subst_term_medium {l} (t : preterm L l) (s : term L) (n₁ n₂) :
(t ↑ ((n₁ + n₂) + 1))[s // n₁] = t ↑ (n₁ + n₂) :=
lift_at_subst_term_medium t s n₁.zero_le (by rw [zero_add]; exact n₁.le_add_right n₂)
lemma lift_at_subst_term_eq {l} (t : preterm L l) (s : term L) (n : ℕ) : (t ↑' 1 # n)[s // n] = t :=
begin rw [lift_at_subst_term_medium t s, lift_term_at_zero]; refl end
@[simp] lemma lift_term1_subst_term {l} (t : preterm L l) (s : term L) : (t ↑ 1)[s // 0] = t :=
lift_at_subst_term_eq t s 0
lemma lift_at_subst_term_small : ∀{l} (t : preterm L l) (s : term L) (n₁ n₂ m),
(t ↑' n₁ # (m + n₂ + 1))[s ↑' n₁ # m // n₂] = (t [s // n₂]) ↑' n₁ # (m + n₂)
| _ &k s n₁ n₂ m :=
begin
by_cases h : m + n₂ + 1 ≤ k,
{ change m + n₂ + 1 ≤ k at h,
have h₂ : n₂ < k := lt_of_le_of_lt (le_add_left n₂ m) (lt_of_succ_le h),
have h₃ : n₂ < k + n₁ := by apply nat.lt_add_right; exact h₂,
have h₄ : m + n₂ ≤ k - 1 := nat.le_sub_right_of_add_le h,
simp [*, -add_comm, -add_assoc, nat.add_sub_swap (one_le_of_lt h₂)] },
{ change ¬(m + n₂ + 1 ≤ k) at h,
apply decidable.lt_by_cases k n₂; intro h₂,
{ have h₃ : ¬(m + n₂ ≤ k) := λh', not_le_of_gt h₂ (le_trans (le_add_left n₂ m) h'),
simp [h, h₂, h₃, -add_comm, -add_assoc] },
{ subst h₂,
have h₃ : ¬(k + m + 1 ≤ k) := by rw [add_comm k m]; exact h,
simp [h, h₃, -add_comm, -add_assoc],
exact lift_term_at2_small _ _ _ m.zero_le },
{ have h₃ : ¬(m + n₂ ≤ k - 1) :=
λh', h $ (nat.le_sub_right_iff_add_le $ one_le_of_lt h₂).mp h',
simp [h, h₂, h₃, -add_comm, -add_assoc] }}
end
| _ (func f) s n₁ n₂ m := rfl
| _ (app t₁ t₂) s n₁ n₂ m := by simp [*, -add_assoc, -add_comm]
lemma subst_term2 : ∀{l} (t : preterm L l) (s₁ s₂ : term L) (n₁ n₂),
t [s₁ // n₁] [s₂ // n₁ + n₂] = t [s₂ // n₁ + n₂ + 1] [s₁[s₂ // n₂] // n₁]
| _ &k s₁ s₂ n₁ n₂ :=
begin -- can we use subst_realize2 here?
apply decidable.lt_by_cases k n₁; intro h,
{ have : k < n₁ + n₂, from lt_of_le_of_lt (k.le_add_right n₂) (by simp*),
have : k < n₁ + n₂ + 1, from lt.step this,
simp only [*, eq_self_iff_true, fol.subst_term_var_lt] },
{ have : k < k + (n₂ + 1), from lt_succ_of_le (le_add_right _ n₂),
subst h, simp [*, lift_subst_term_large', -add_comm] },
apply decidable.lt_by_cases k (n₁ + n₂ + 1); intro h',
{ have : k - 1 < n₁ + n₂, from (nat.sub_lt_right_iff_lt_add (one_le_of_lt h)).2 h',
simp [*, -add_comm, -add_assoc] },
{ subst h', simp [h, lift_subst_term_medium, -add_comm, -add_assoc] },
{ have : n₁ + n₂ < k - 1, from nat.lt_sub_right_of_add_lt h',
have : n₁ < k - 1, from lt_of_le_of_lt (n₁.le_add_right n₂) this,
simp only [*, eq_self_iff_true, fol.subst_term_var_gt] }
end
| _ (func f) s₁ s₂ n₁ n₂ := rfl
| _ (app t₁ t₂) s₁ s₂ n₁ n₂ := by simp*
lemma subst_term2_0 {l} (t : preterm L l) (s₁ s₂ : term L) (n) :
t [s₁ // 0] [s₂ // n] = t [s₂ // n + 1] [s₁[s₂ // n] // 0] :=
let h := subst_term2 t s₁ s₂ 0 n in by simp only [zero_add] at h; exact h
lemma lift_subst_term_cancel : ∀{l} (t : preterm L l) (n : ℕ), (t ↑' 1 # (n+1))[&0 // n] = t
| _ &k n :=
begin
apply decidable.lt_by_cases n k; intro h,
{ change n+1 ≤ k at h, have h' : n < k+1, from lt.step (lt_of_succ_le h), simp [h, h'] },
{ have h' : ¬(k+1 ≤ k), from not_succ_le_self k, simp [h, h'] },
{ have h' : ¬(n+1 ≤ k) := not_le_of_lt (lt.step h), simp [h, h'] }
end
| _ (func f) n := rfl
| _ (app t₁ t₂) n := by dsimp; simp [*]
/- Probably useful facts about substitution which we should add when needed:
(forall M N i j k, ( M [ j ← N] ) ↑' k # (j+i) = (M ↑' k # (S (j+i))) [ j ← (N ↑' k # i ) ])
subst_travers : (forall M N P n, (M [← N]) [n ← P] = (M [n+1 ← P])[← N[n← P]])
erasure_lem3 : (forall n m t, m>n->#m = (#m ↑' 1 # (S n)) [n ← t]).
lift_is_lift_sublemma : forall j v, j<v->exists w,#v=w↑1#j.
lift_is_lift : (forall N A n i j,N ↑' i # n=A ↑' 1 # j -> j<n -> exists M,N=M ↑' 1 # j)
subst_is_lift : (forall N T A n j, N [n ← T]=A↑' 1#j->j<n->exists M,N=M↑' 1#j)
-/
/- preformula l is a partially applied formula. if applied to n terms, it becomes a formula.
* We only have implication as binary connective. Since we use classical logic, we can define
the other connectives from implication and falsum.
* Similarly, universal quantification is our only quantifier.
* We could make `falsum` and `equal` into elements of rel. However, if we do that, then we cannot make the interpretation of them in a model definitionally what we want.
-/
variable (L)
inductive preformula : ℕ → Type u
| falsum {} : preformula 0
| equal (t₁ t₂ : term L) : preformula 0
| rel {l : ℕ} (R : L.relations l) : preformula l
| apprel {l : ℕ} (f : preformula (l + 1)) (t : term L) : preformula l
| imp (f₁ f₂ : preformula 0) : preformula 0
| all (f : preformula 0) : preformula 0
export preformula
@[reducible] def formula := preformula L 0
variable {L}
notation `⊥` := fol.preformula.falsum -- input: \bot
infix ` ≃ `:88 := fol.preformula.equal -- input \~- or \simeq
infixr ` ⟹ `:62 := fol.preformula.imp -- input \==>
prefix `∀'`:110 := fol.preformula.all
def not (f : formula L) : formula L := f ⟹ ⊥
prefix `∼`:max := fol.not -- input \~, the ASCII character ~ has too low precedence
notation `⊤` := ∼⊥ -- input: \top
def and (f₁ f₂ : formula L) : formula L := ∼(f₁ ⟹ ∼f₂)
infixr ` ⊓ ` := fol.and -- input: \sqcap
def or (f₁ f₂ : formula L) : formula L := ∼f₁ ⟹ f₂
infixr ` ⊔ ` := fol.or -- input: \sqcup
def biimp (f₁ f₂ : formula L) : formula L := (f₁ ⟹ f₂) ⊓ (f₂ ⟹ f₁)
infix ` ⇔ `:61 := fol.biimp -- input \<=>
def ex (f : formula L) : formula L := ∼ ∀' ∼f
prefix `∃'`:110 := fol.ex -- input \ex
@[simp] def apps_rel : ∀{l} (f : preformula L l) (ts : dvector (term L) l), formula L
| 0 f [] := f
| (n+1) f (t::ts) := apps_rel (apprel f t) ts
@[simp] lemma apps_rel_zero (f : formula L) (ts : dvector (term L) 0) : apps_rel f ts = f :=
by cases ts; refl
-- lemma apps_rel_ne_falsum {l} {R : L.relations l} {ts : dvector (term L) l} :
-- apps_rel (rel R) ts ≠ ⊥ :=
-- by induction l; cases ts; [{cases ts_xs, intro h, injection h}, apply l_ih]
-- lemma apps_rel_ne_falsum {l} {f : preformula L (l+1)} {ts : dvector (term L) (l+1)} :
-- apps_rel f ts ≠ ⊥ :=
-- by induction l; cases ts; [{cases ts_xs, intro h, injection h}, apply l_ih]
-- lemma apps_rel_ne_equal {l} {f : preformula L (l+1)} {ts : dvector (term L) (l+1)}
-- {t₁ t₂ : term L} : apps_rel f ts ≠ t₁ ≃ t₂ :=
-- by induction l; cases ts; [{cases ts_xs, intro h, injection h}, apply l_ih]
-- lemma apps_rel_ne_imp {l} {f : preformula L (l+1)} {ts : dvector (term L) (l+1)}
-- {f₁ f₂ : formula L} : apps_rel f ts ≠ f₁ ⟹ f₂ :=
-- by induction l; cases ts; [{cases ts_xs, intro h, injection h}, apply l_ih]
-- lemma apps_rel_ne_all {l} {f : preformula L (l+1)} {ts : dvector (term L) (l+1)}
-- {f' : formula L} : apps_rel f ts ≠ ∀' f' :=
-- by induction l; cases ts; [{cases ts_xs, intro h, injection h}, apply l_ih]
def formula_of_relation {l} (R : L.relations l) : arity' (term L) (formula L) l :=
arity'.of_dvector_map $ apps_rel (rel R)
@[elab_as_eliminator] def formula.rec' {C : formula L → Sort v}
(hfalsum : C ⊥)
(hequal : Π (t₁ t₂ : term L), C (t₁ ≃ t₂))
(hrel : Π {{l}} (R : L.relations l) (ts : dvector (term L) l), C (apps_rel (rel R) ts))
(himp : Π {{f₁ f₂ : formula L}} (ih₁ : C f₁) (ih₂ : C f₂), C (f₁ ⟹ f₂))
(hall : Π {{f : formula L}} (ih : C f), C (∀' f)) :
∀{l} (f : preformula L l) (ts : dvector (term L) l), C (apps_rel f ts)
| _ falsum ts := by cases ts; exact hfalsum
| _ (t₁ ≃ t₂) ts := by cases ts; apply hequal
| _ (rel R) ts := by apply hrel
| _ (apprel f t) ts := by apply formula.rec' f (t::ts)
| _ (f₁ ⟹ f₂) ts := by cases ts; exact himp (formula.rec' f₁ ([])) (formula.rec' f₂ ([]))
| _ (∀' f) ts := by cases ts; exact hall (formula.rec' f ([]))
@[elab_as_eliminator] def formula.rec {C : formula L → Sort v}
(hfalsum : C ⊥)
(hequal : Π (t₁ t₂ : term L), C (t₁ ≃ t₂))
(hrel : Π {{l}} (R : L.relations l) (ts : dvector (term L) l), C (apps_rel (rel R) ts))
(himp : Π {{f₁ f₂ : formula L}} (ih₁ : C f₁) (ih₂ : C f₂), C (f₁ ⟹ f₂))
(hall : Π {{f : formula L}} (ih : C f), C (∀' f)) : ∀f, C f :=
λf, formula.rec' hfalsum hequal hrel himp hall f ([])
@[simp] def formula.rec'_apps_rel {C : formula L → Sort v}
(hfalsum : C ⊥)
(hequal : Π (t₁ t₂ : term L), C (t₁ ≃ t₂))
(hrel : Π {{l}} (R : L.relations l) (ts : dvector (term L) l), C (apps_rel (rel R) ts))
(himp : Π {{f₁ f₂ : formula L}} (ih₁ : C f₁) (ih₂ : C f₂), C (f₁ ⟹ f₂))
(hall : Π {{f : formula L}} (ih : C f), C (∀' f))
{l} (f : preformula L l) (ts : dvector (term L) l) :
@formula.rec' L C hfalsum hequal hrel himp hall 0 (apps_rel f ts) ([]) =
@formula.rec' L C hfalsum hequal hrel himp hall l f ts :=
begin
induction ts,
{ refl },
{ dsimp only [dvector.map, apps_rel], rw [ts_ih], refl }
end
@[simp] def formula.rec_apps_rel {C : formula L → Sort v}
(hfalsum : C ⊥)
(hequal : Π (t₁ t₂ : term L), C (t₁ ≃ t₂))
(hrel : Π {{l}} (R : L.relations l) (ts : dvector (term L) l), C (apps_rel (rel R) ts))
(himp : Π {{f₁ f₂ : formula L}} (ih₁ : C f₁) (ih₂ : C f₂), C (f₁ ⟹ f₂))
(hall : Π {{f : formula L}} (ih : C f), C (∀' f))
{l} (R : L.relations l) (ts : dvector (term L) l) :
@formula.rec L C hfalsum hequal hrel himp hall (apps_rel (rel R) ts) = hrel R ts :=
by dsimp only [formula.rec]; rw formula.rec'_apps_rel; refl
@[simp] def lift_formula_at : ∀ {l}, preformula L l → ℕ → ℕ → preformula L l
| _ falsum n m := falsum
| _ (t₁ ≃ t₂) n m := lift_term_at t₁ n m ≃ lift_term_at t₂ n m
| _ (rel R) n m := rel R
| _ (apprel f t) n m := apprel (lift_formula_at f n m) (lift_term_at t n m)
| _ (f₁ ⟹ f₂) n m := lift_formula_at f₁ n m ⟹ lift_formula_at f₂ n m
| _ (∀' f) n m := ∀' lift_formula_at f n (m+1)
notation f ` ↑' `:90 n ` # `:90 m:90 := fol.lift_formula_at f n m -- input ↑' with \upa
@[reducible] def lift_formula {l} (f : preformula L l) (n : ℕ) : preformula L l := f ↑' n # 0
infix ` ↑ `:100 := fol.lift_formula -- input ↑' with \upa
@[reducible, simp] def lift_formula1 {l} (f : preformula L l) : preformula L l := f ↑ 1
@[simp] lemma lift_formula_def {l} (f : preformula L l) (n : ℕ) : f ↑' n # 0 = f ↑ n := by refl
@[simp] lemma lift_formula1_not (n : ℕ) (f : formula L) : ∼f ↑ n = ∼(f ↑ n) := by refl
lemma injective_lift_formula_at {l} {n m : ℕ} :
function.injective (λ (f : preformula L l), lift_formula_at f n m) :=
begin
intros f f' H, induction f generalizing m; cases f'; injection H,
{ simp only [injective_lift_term_at h_1, injective_lift_term_at h_2, eq_self_iff_true, and_self] },
{ simp only [f_ih h_1, injective_lift_term_at h_2, eq_self_iff_true, and_self] },
{ simp only [f_ih_f₁ h_1, f_ih_f₂ h_2, eq_self_iff_true, and_self] },
{ simp only [f_ih h_1, eq_self_iff_true] }
end
@[simp] lemma lift_formula_at_zero : ∀ {l} (f : preformula L l) (m : ℕ), f ↑' 0 # m = f
| _ falsum m := by refl
| _ (t₁ ≃ t₂) m := by simp
| _ (rel R) m := by refl
| _ (apprel f t) m := by simp; apply lift_formula_at_zero
| _ (f₁ ⟹ f₂) m := by dsimp; congr1; apply lift_formula_at_zero
| _ (∀' f) m := by simp; apply lift_formula_at_zero
/- the following lemmas simplify iterated lifts, depending on the size of m' -/
lemma lift_formula_at2_small : ∀ {l} (f : preformula L l) (n n') {m m'}, m' ≤ m →
(f ↑' n # m) ↑' n' # m' = (f ↑' n' # m') ↑' n # (m + n')
| _ falsum n n' m m' H := by refl
| _ (t₁ ≃ t₂) n n' m m' H := by simp [lift_term_at2_small, H]
| _ (rel R) n n' m m' H := by refl
| _ (apprel f t) n n' m m' H :=
by simp [lift_term_at2_small, H, -add_comm]; apply lift_formula_at2_small; assumption
| _ (f₁ ⟹ f₂) n n' m m' H := by dsimp; congr1; apply lift_formula_at2_small; assumption
| _ (∀' f) n n' m m' H :=
by simp [lift_term_at2_small, H, lift_formula_at2_small f n n' (add_le_add_right H 1)]
lemma lift_formula_at2_medium : ∀ {l} (f : preformula L l) (n n') {m m'}, m ≤ m' → m' ≤ m+n →
(f ↑' n # m) ↑' n' # m' = f ↑' (n+n') # m
| _ falsum n n' m m' H₁ H₂ := by refl
| _ (t₁ ≃ t₂) n n' m m' H₁ H₂ := by simp [*, lift_term_at2_medium]
| _ (rel R) n n' m m' H₁ H₂ := by refl
| _ (apprel f t) n n' m m' H₁ H₂ := by simp [*, lift_term_at2_medium, -add_comm]
| _ (f₁ ⟹ f₂) n n' m m' H₁ H₂ := by simp*
| _ (∀' f) n n' m m' H₁ H₂ :=
have m' + 1 ≤ (m + 1) + n, from le_trans (add_le_add_right H₂ 1) (by simp), by simp*
lemma lift_formula_at2_eq {l} (f : preformula L l) (n n' m : ℕ) :
(f ↑' n # m) ↑' n' # (m+n) = f ↑' (n+n') # m :=
lift_formula_at2_medium f n n' (m.le_add_right n) (le_refl _)
lemma lift_formula_at2_large {l} (f : preformula L l) (n n') {m m'} (H : m + n ≤ m') :
(f ↑' n # m) ↑' n' # m' = (f ↑' n' # (m'-n)) ↑' n # m :=
have H₁ : n ≤ m', from le_trans (n.le_add_left m) H,
have H₂ : m ≤ m' - n, from nat.le_sub_right_of_add_le H,
begin rw lift_formula_at2_small f n' n H₂, rw [nat.sub_add_cancel], exact H₁ end
@[simp] lemma lift_formula_at_apps_rel {l} (f : preformula L l) (ts : dvector (term L) l)
(n m : ℕ) : (apps_rel f ts) ↑' n # m = apps_rel (f ↑' n # m) (ts.map $ λx, x ↑' n # m) :=
by induction ts generalizing f;[refl, apply ts_ih (apprel f ts_x)]
@[simp] lemma lift_formula_apps_rel {l} (f : preformula L l) (ts : dvector (term L) l)
(n : ℕ) : (apps_rel f ts) ↑ n = apps_rel (f ↑ n) (ts.map $ λx, x ↑ n) :=
lift_formula_at_apps_rel f ts n 0
@[simp] def subst_formula : ∀ {l}, preformula L l → term L → ℕ → preformula L l
| _ falsum s n := falsum
| _ (t₁ ≃ t₂) s n := subst_term t₁ s n ≃ subst_term t₂ s n
| _ (rel R) s n := rel R
| _ (apprel f t) s n := apprel (subst_formula f s n) (subst_term t s n)
| _ (f₁ ⟹ f₂) s n := subst_formula f₁ s n ⟹ subst_formula f₂ s n
| _ (∀' f) s n := ∀' subst_formula f s (n+1)
notation f `[`:95 s ` // `:95 n `]`:0 := fol.subst_formula f s n
lemma subst_formula_equal (t₁ t₂ s : term L) (n : ℕ) :
(t₁ ≃ t₂)[s // n] = t₁[s // n] ≃ (t₂[s // n]) :=
by refl
@[simp] lemma subst_formula_biimp (f₁ f₂ : formula L) (s : term L) (n : ℕ) :
(f₁ ⇔ f₂)[s // n] = f₁[s // n] ⇔ (f₂[s // n]) :=
by refl
lemma lift_at_subst_formula_large : ∀{l} (f : preformula L l) (s : term L) {n₁} (n₂) {m}, m ≤ n₁ →
(f ↑' n₂ # m)[s // n₁+n₂] = (f [s // n₁]) ↑' n₂ # m
| _ falsum s n₁ n₂ m h := by refl
| _ (t₁ ≃ t₂) s n₁ n₂ m h := by simp [*, lift_at_subst_term_large]
| _ (rel R) s n₁ n₂ m h := by refl
| _ (apprel f t) s n₁ n₂ m h := by simp [*, lift_at_subst_term_large]
| _ (f₁ ⟹ f₂) s n₁ n₂ m h := by simp*
| _ (∀' f) s n₁ n₂ m h :=
by have := lift_at_subst_formula_large f s n₂ (add_le_add_right h 1); simp at this; simp*
lemma lift_subst_formula_large {l} (f : preformula L l) (s : term L) {n₁ n₂} :
(f ↑ n₂)[s // n₁+n₂] = (f [s // n₁]) ↑ n₂ :=
lift_at_subst_formula_large f s n₂ n₁.zero_le
lemma lift_subst_formula_large' {l} (f : preformula L l) (s : term L) {n₁ n₂} :
(f ↑ n₂)[s // n₂+n₁] = (f [s // n₁]) ↑ n₂ :=
by rw [add_comm]; apply lift_subst_formula_large
lemma lift_at_subst_formula_medium : ∀{l} (f : preformula L l) (s : term L) {n₁ n₂ m}, m ≤ n₂ →
n₂ ≤ m + n₁ → (f ↑' n₁+1 # m)[s // n₂] = f ↑' n₁ # m
| _ falsum s n₁ n₂ m h₁ h₂ := by refl
| _ (t₁ ≃ t₂) s n₁ n₂ m h₁ h₂ := by simp [*, lift_at_subst_term_medium]
| _ (rel R) s n₁ n₂ m h₁ h₂ := by refl
| _ (apprel f t) s n₁ n₂ m h₁ h₂ := by simp [*, lift_at_subst_term_medium]
| _ (f₁ ⟹ f₂) s n₁ n₂ m h₁ h₂ := by simp*
| _ (∀' f) s n₁ n₂ m h₁ h₂ :=
begin
have h : n₂ + 1 ≤ (m + 1) + n₁, from le_trans (add_le_add_right h₂ 1) (by simp),
have := lift_at_subst_formula_medium f s (add_le_add_right h₁ 1) h,
simp only [fol.subst_formula, fol.lift_formula_at] at this, simp*
end
lemma lift_subst_formula_medium {l} (f : preformula L l) (s : term L) (n₁ n₂) :
(f ↑ ((n₁ + n₂) + 1))[s // n₁] = f ↑ (n₁ + n₂) :=
lift_at_subst_formula_medium f s n₁.zero_le (by rw [zero_add]; exact n₁.le_add_right n₂)
lemma lift_at_subst_formula_eq {l} (f : preformula L l) (s : term L) (n : ℕ) :
(f ↑' 1 # n)[s // n] = f :=
begin rw [lift_at_subst_formula_medium f s, lift_formula_at_zero]; refl end
@[simp] lemma lift_formula1_subst {l} (f : preformula L l) (s : term L) : (f ↑ 1)[s // 0] = f :=
lift_at_subst_formula_eq f s 0
lemma lift_at_subst_formula_small : ∀{l} (f : preformula L l) (s : term L) (n₁ n₂ m),
(f ↑' n₁ # (m + n₂ + 1))[s ↑' n₁ # m // n₂] = (f [s // n₂]) ↑' n₁ # (m + n₂)
| _ falsum s n₁ n₂ m := by refl
| _ (t₁ ≃ t₂) s n₁ n₂ m :=
by dsimp; simp only [lift_at_subst_term_small, eq_self_iff_true, and_self]
| _ (rel R) s n₁ n₂ m := by refl
| _ (apprel f t) s n₁ n₂ m :=
by dsimp; simp only [*, lift_at_subst_term_small, eq_self_iff_true, and_self]
| _ (f₁ ⟹ f₂) s n₁ n₂ m :=
by dsimp; simp only [*, lift_at_subst_term_small, eq_self_iff_true, and_self]
| _ (∀' f) s n₁ n₂ m :=
by have := lift_at_subst_formula_small f s n₁ (n₂+1) m; dsimp; simp at this ⊢; exact this
lemma lift_at_subst_formula_small0 {l} (f : preformula L l) (s : term L) (n₁ m) :
(f ↑' n₁ # (m + 1))[s ↑' n₁ # m // 0] = (f [s // 0]) ↑' n₁ # m :=
lift_at_subst_formula_small f s n₁ 0 m
lemma subst_formula2 : ∀{l} (f : preformula L l) (s₁ s₂ : term L) (n₁ n₂),
f [s₁ // n₁] [s₂ // n₁ + n₂] = f [s₂ // n₁ + n₂ + 1] [s₁[s₂ // n₂] // n₁]
| _ falsum s₁ s₂ n₁ n₂ := by refl
| _ (t₁ ≃ t₂) s₁ s₂ n₁ n₂ := by simp [*, subst_term2]
| _ (rel R) s₁ s₂ n₁ n₂ := by refl
| _ (apprel f t) s₁ s₂ n₁ n₂ := by simp [*, subst_term2]
| _ (f₁ ⟹ f₂) s₁ s₂ n₁ n₂ := by simp*
| _ (∀' f) s₁ s₂ n₁ n₂ :=
by simp*; rw [add_comm n₂ 1, ←add_assoc, subst_formula2 f s₁ s₂ (n₁ + 1) n₂]; simp
lemma subst_formula2_zero {l} (f : preformula L l) (s₁ s₂ : term L) (n) :
f [s₁ // 0] [s₂ // n] = f [s₂ // n + 1] [s₁[s₂ // n] // 0] :=
let h := subst_formula2 f s₁ s₂ 0 n in by simp only [fol.subst_formula, zero_add] at h; exact h
lemma lift_subst_formula_cancel : ∀{l} (f : preformula L l) (n : ℕ), (f ↑' 1 # (n+1))[&0 // n] = f
| _ falsum n := by refl
| _ (t₁ ≃ t₂) n := by simp [*, lift_subst_term_cancel]
| _ (rel R) n := by refl
| _ (apprel f t) n := by simp [*, lift_subst_term_cancel]
| _ (f₁ ⟹ f₂) n := by simp*
| _ (∀' f) n := by simp*
@[simp] lemma subst_formula_apps_rel {l} (f : preformula L l) (ts : dvector (term L) l) (s : term L)
(n : ℕ): (apps_rel f ts)[s // n] = apps_rel (f[s // n]) (ts.map $ λx, x[s // n]) :=
by induction ts generalizing f;[refl, apply ts_ih (apprel f ts_x)]
@[simp] def count_quantifiers : ∀ {l}, preformula L l → ℕ
| _ falsum := 0
| _ (t₁ ≃ t₂) := 0
| _ (rel R) := 0
| _ (apprel f t) := 0
| _ (f₁ ⟹ f₂) := count_quantifiers f₁ + count_quantifiers f₂
| _ (∀' f) := count_quantifiers f + 1
@[simp] def count_quantifiers_succ {l} (f : preformula L (l+1)) : count_quantifiers f = 0 :=
by cases f; refl
@[simp] lemma count_quantifiers_subst : ∀ {l} (f : preformula L l) (s : term L) (n : ℕ),
count_quantifiers (f[s // n]) = count_quantifiers f
| _ falsum s n := by refl
| _ (t₁ ≃ t₂) s n := by refl
| _ (rel R) s n := by refl
| _ (apprel f t) s n := by refl
| _ (f₁ ⟹ f₂) s n := by simp*
| _ (∀' f) s n := by simp*
def quantifier_free {l} : preformula L l → Prop := λ f, count_quantifiers f = 0
/- Provability
* to decide: should Γ be a list or a set (or finset)?
* We use natural deduction as our deduction system, since that is most convenient to work with.
* All rules are motivated to work well with backwards reasoning.
-/
inductive prf : set (formula L) → formula L → Type u
| axm {Γ A} (h : A ∈ Γ) : prf Γ A
| impI {Γ : set $ formula L} {A B} (h : prf (insert A Γ) B) : prf Γ (A ⟹ B)
| impE {Γ} (A) {B} (h₁ : prf Γ (A ⟹ B)) (h₂ : prf Γ A) : prf Γ B
| falsumE {Γ : set $ formula L} {A} (h : prf (insert ∼A Γ) ⊥) : prf Γ A
| allI {Γ A} (h : prf (lift_formula1 '' Γ) A) : prf Γ (∀' A)
| allE₂ {Γ} A t (h : prf Γ (∀' A)) : prf Γ (A[t // 0])
| ref (Γ t) : prf Γ (t ≃ t)
| subst₂ {Γ} (s t f) (h₁ : prf Γ (s ≃ t)) (h₂ : prf Γ (f[s // 0])) : prf Γ (f[t // 0])
export prf
infix ` ⊢ `:51 := fol.prf -- input: \|- or \vdash
def provable (T : set $ formula L) (f : formula L) := nonempty (T ⊢ f)
infix ` ⊢' `:51 := fol.provable -- input: \|- or \vdash
def allE {Γ} (A : formula L) (t) {B} (H₁ : Γ ⊢ ∀' A) (H₂ : A[t // 0] = B) : Γ ⊢ B :=
by induction H₂; exact allE₂ A t H₁
def subst {Γ} {s t} (f₁ : formula L) {f₂} (H₁ : Γ ⊢ s ≃ t) (H₂ : Γ ⊢ f₁[s // 0])
(H₃ : f₁[t // 0] = f₂) : Γ ⊢ f₂ :=
by induction H₃; exact subst₂ s t f₁ H₁ H₂
def axm1 {Γ : set (formula L)} {A : formula L} : insert A Γ ⊢ A := by apply axm; left; refl
def axm2 {Γ : set (formula L)} {A B : formula L} : insert A (insert B Γ) ⊢ B :=
by apply axm; right; left; refl
def weakening {Γ Δ} {f : formula L} (H₁ : Γ ⊆ Δ) (H₂ : Γ ⊢ f) : Δ ⊢ f :=
begin
induction H₂ generalizing Δ,
{ apply axm, exact H₁ H₂_h, },
{ apply impI, apply H₂_ih, apply insert_subset_insert, apply H₁ },
{ apply impE, apply H₂_ih_h₁, assumption, apply H₂_ih_h₂, assumption },
{ apply falsumE, apply H₂_ih, apply insert_subset_insert, apply H₁ },
{ apply allI, apply H₂_ih, apply image_subset _ H₁ },
{ apply allE₂, apply H₂_ih, assumption },
{ apply ref },
{ apply subst₂, apply H₂_ih_h₁, assumption, apply H₂_ih_h₂, assumption },
end
def prf_lift {Γ} {f : formula L} (n m : ℕ) (H : Γ ⊢ f) : (λf', f' ↑' n # m) '' Γ ⊢ f ↑' n # m :=
begin
induction H generalizing m,
{ apply axm, apply mem_image_of_mem _ H_h },
{ apply impI, have h := @H_ih m, rw [image_insert_eq] at h, exact h },
{ apply impE, apply H_ih_h₁, apply H_ih_h₂ },
{ apply falsumE, have h := @H_ih m, rw [image_insert_eq] at h, exact h },
{ apply allI, rw [image_image], have h := @H_ih (m+1), rw [image_image] at h,
apply cast _ h, congr1, apply image_congr', intro f', symmetry,
exact lift_formula_at2_small f' _ _ m.zero_le },
{ apply allE _ _ (H_ih m), apply lift_at_subst_formula_small0 },
{ apply ref },
{ apply subst _ (H_ih_h₁ m),
{ have h := @H_ih_h₂ m, rw [←lift_at_subst_formula_small0] at h, exact h},
rw [lift_at_subst_formula_small0] },
end
def substitution {Γ} {f : formula L} (t n) (H : Γ ⊢ f) : (λx, x[t // n]) '' Γ ⊢ f[t // n] :=
begin
induction H generalizing n,
{ apply axm, apply mem_image_of_mem _ H_h },
{ apply impI, have h := H_ih n, rw [image_insert_eq] at h, exact h },
{ apply impE, apply H_ih_h₁, apply H_ih_h₂ },
{ apply falsumE, have h := H_ih n, rw [image_insert_eq] at h, exact h },
{ apply allI, rw [image_image], have h := @H_ih (n+1), rw [image_image] at h,
apply cast _ h, congr1, apply image_congr', intro,
apply lift_subst_formula_large },
{ apply allE _ _ (H_ih n), symmetry, apply subst_formula2_zero },
{ apply ref },
{ apply subst _ (H_ih_h₁ n), { have h := @H_ih_h₂ n, rw [subst_formula2_zero] at h, exact h},
rw [subst_formula2_zero] },
end
def reflect_prf_lift1 {Γ} {f : formula L} (h : lift_formula1 '' Γ ⊢ f ↑ 1) : Γ ⊢ f :=
begin
have := substitution &0 0 h, simp [image_image] at this, exact this
end
-- def reflect_prf_lift {Γ} {f : formula L} (n m : ℕ) :
-- (λf' : formula L, f' ↑' n # m) '' Γ ⊢ f ↑' n # m → Γ ⊢ f :=
-- begin
-- induction n,
-- { rw [lift_zero] },
-- { }
-- end
def weakening1 {Γ} {f₁ f₂ : formula L} (H : Γ ⊢ f₂) : insert f₁ Γ ⊢ f₂ :=
weakening (subset_insert f₁ Γ) H
def weakening2 {Γ} {f₁ f₂ f₃ : formula L} (H : insert f₁ Γ ⊢ f₂) : insert f₁ (insert f₃ Γ) ⊢ f₂ :=
weakening (insert_subset_insert (subset_insert _ Γ)) H
def deduction {Γ} {A B : formula L} (H : Γ ⊢ A ⟹ B) : insert A Γ ⊢ B :=
impE A (weakening1 H) axm1
def exfalso {Γ} {A : formula L} (H : Γ ⊢ falsum) : Γ ⊢ A :=
falsumE (weakening1 H)
def exfalso' {Γ} {A : formula L} (H : Γ ⊢' falsum) : Γ ⊢' A :=
by {fapply nonempty.map, exact Γ ⊢ falsum, exact exfalso, exact H}
def notI {Γ} {A : formula L} (H : Γ ⊢ A ⟹ falsum) : Γ ⊢ ∼ A :=
by {rw[not], assumption}
def andI {Γ} {f₁ f₂ : formula L} (H₁ : Γ ⊢ f₁) (H₂ : Γ ⊢ f₂) : Γ ⊢ f₁ ⊓ f₂ :=
begin
apply impI, apply impE f₂,
{ apply impE f₁, apply axm1, exact weakening1 H₁ },
{ exact weakening1 H₂ }
end
def andE1 {Γ f₁} (f₂ : formula L) (H : Γ ⊢ f₁ ⊓ f₂) : Γ ⊢ f₁ :=
begin
apply falsumE, apply impE _ (weakening1 H), apply impI, apply exfalso,
apply impE f₁; [apply axm2, apply axm1]
end
def andE2 {Γ} (f₁ : formula L) {f₂} (H : Γ ⊢ f₁ ⊓ f₂) : Γ ⊢ f₂ :=
begin apply falsumE, apply impE _ (weakening1 H), apply impI, apply axm2 end
def orI1 {Γ} {A B : formula L} (H : Γ ⊢ A) : Γ ⊢ A ⊔ B :=
begin apply impI, apply exfalso, refine impE _ _ (weakening1 H), apply axm1 end
def orI2 {Γ} {A B : formula L} (H : Γ ⊢ B) : Γ ⊢ A ⊔ B :=
impI $ weakening1 H
def orE {Γ} {A B C : formula L} (H₁ : Γ ⊢ A ⊔ B) (H₂ : insert A Γ ⊢ C) (H₃ : insert B Γ ⊢ C) :
Γ ⊢ C :=
begin
apply falsumE, apply impE C, { apply axm1 },
apply impE B, { apply impI, exact weakening2 H₃ },
apply impE _ (weakening1 H₁),
apply impI (impE _ axm2 (weakening2 H₂))
end
def biimpI {Γ} {f₁ f₂ : formula L} (H₁ : insert f₁ Γ ⊢ f₂) (H₂ : insert f₂ Γ ⊢ f₁) : Γ ⊢ f₁ ⇔ f₂ :=
by apply andI; apply impI; assumption
def biimpE1 {Γ} {f₁ f₂ : formula L} (H : Γ ⊢ f₁ ⇔ f₂) : insert f₁ Γ ⊢ f₂ := deduction (andE1 _ H)
def biimpE2 {Γ} {f₁ f₂ : formula L} (H : Γ ⊢ f₁ ⇔ f₂) : insert f₂ Γ ⊢ f₁ := deduction (andE2 _ H)
def exI {Γ f} (t : term L) (H : Γ ⊢ f [t // 0]) : Γ ⊢ ∃' f :=
begin
apply impI,
apply impE (f[t // 0]) _ (weakening1 H),
apply allE₂ ∼f t axm1,
end
def exE {Γ} {f₁ f₂ : formula L} (H₁ : Γ ⊢ ∃' f₁)
(H₂ : insert f₁ (lift_formula1 '' Γ) ⊢ lift_formula1 f₂) : Γ ⊢ f₂ :=
begin
apply falsumE, apply impE _ (weakening1 H₁), apply allI, apply impI,
rw [image_insert_eq], apply impE _ axm2, apply weakening2 H₂
end
def ex_not_of_not_all {Γ} {f : formula L} (H : Γ ⊢ ∼ ∀' f) : Γ ⊢ ∃' ∼ f :=
begin
apply falsumE, apply impE _ (weakening1 H), apply allI, apply falsumE,
rw [image_insert_eq], apply impE _ axm2, apply exI &0,
rw [lift_subst_formula_cancel], exact axm1
end
def not_and_self {Γ : set (formula L)} {f : formula L} (H : Γ ⊢ f ⊓ ∼f) : Γ ⊢ ⊥ :=
impE f (andE2 f H) (andE1 ∼f H)
-- def andE1 {Γ f₁} (f₂ : formula L) (H : Γ ⊢ f₁ ⊓ f₂) : Γ ⊢ f₁ :=
def symm {Γ} {s t : term L} (H : Γ ⊢ s ≃ t) : Γ ⊢ t ≃ s :=
begin
apply subst (&0 ≃ s ↑ 1) H; rw [subst_formula_equal, lift_term1_subst_term, subst_term_var0],
apply ref
end
def trans {Γ} {t₁ t₂ t₃ : term L} (H : Γ ⊢ t₁ ≃ t₂) (H' : Γ ⊢ t₂ ≃ t₃) : Γ ⊢ t₁ ≃ t₃ :=
begin
apply subst (t₁ ↑ 1 ≃ &0) H'; rw [subst_formula_equal, lift_term1_subst_term, subst_term_var0],
exact H
end
def congr {Γ} {t₁ t₂ : term L} (s : term L) (H : Γ ⊢ t₁ ≃ t₂) : Γ ⊢ s[t₁ // 0] ≃ s[t₂ // 0] :=
begin
apply subst (s[t₁ // 0] ↑ 1 ≃ s) H,
{ rw [subst_formula_equal, lift_term1_subst_term], apply ref },
{ rw [subst_formula_equal, lift_term1_subst_term] }