-
Notifications
You must be signed in to change notification settings - Fork 20
/
Copy pathCheatSheet.lean
1370 lines (1112 loc) · 34.5 KB
/
CheatSheet.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
/-
This cheat sheet summarizes the
crucial introduction and elimination
reasoning rules for each connective
and quantifier in predicate logic.
* true
* false
* P ∧ Q
* ∀ p : P, Q -- predicate Q usually involves p
* P → Q (view as function type)
* P → Q (viewed as implication)
* ¬ P
* P ↔ Q
* P ∨ Q
* ∃ p : P, Q -- predicate Q usually involves p
Introduction rules are used when
your goal is to prove a proposition
(below the line or to the right of
the turnstile) that contains a given
connective or quantifier. For example,
you would use the introduction rule
for ∧ to prove a propopsition of the
form, P ∧ Q.
Elimination rules are used to prove
something else when you are given,
as an assumption, a proof of a
proposition that uses a given
connective or quantifier. You would
use an elimination rule for ∧, for
example to prove P when you already
have a proof of P ∧ Q.
-/
/- *****************************************-/
/- *****************************************-/
/- *****************************************-/
variables P Q : Type
#check (P → Q)
/- **** -/
/- true -/
/- **** -/
/-
The proposition, true, has
a single proof and can thus
always be judged to be true.
The introduction rule gives us
a proof without conditions.
---------------- (true.intro)
true.intro: true
Having a proof of true isn't
very useful. One is always
available, and no information
can be obtained from a proof
of true. We thus don't see a
proof of true very often in
practice.
-/
/- ----------------- -/
/- true introduction -/
/- ----------------- -/
theorem trueIsTrue : true :=
true.intro
theorem
trueIsTrue' : true :=
begin
exact (true.intro),
end
/- ----------------- -/
/- true elimination -/
/- ----------------- -/
/-
A proof of true, true.intro, doesn't tell
you anything meaningful, so a proof of true
never really helps to prove anything else.
A proof of true is both free and worthless.
Elimination rules let you deduce something
meaningful from a proof of something else.
For example from a proof of P ∧ Q one can
obtain a proof of P (which can be useful!).
There is thus no meaningful elimination
rule for true.
-/
/- *****************************************-/
/- *****************************************-/
/- *****************************************-/
/-*******-/
/- false -/
/-*******-/
/-
The proposition, false, has no
proofs, and can thus be judged
to be false.
-/
/- false introduction -/
/-
Because there is no proof of false,
there is no introduction rule for
false.
-/
/- false elimination -/
/-
On the other hand, it often happens
in real proofs that one ends up with
inconsistent assumptions. When this
happens, it shows that in reality
such a case can't occur.
When one ends up in such a situation,
a proof of false can be derived from
the contradiction, and the elimination
rule for false can then be used to
finish off the proof of the current
proof goal.
It might seem a bit like magic that
false elimination can be used to prove
anything at all, but all that it really
says is "we can safely ignore this case
because it can never really happen."
What the rule technically says is that
from an assumed proof of false (or from
a proof of false that is obtained from
a contradiction), any proposition, P,
can be proved by applying false.elim to
the proof of false.
P : Prop, f : false
------------------- false.elim
pf : P
-/
def fromFalse (P: Prop) (f: false) : P :=
false.elim f
theorem fromFalse': ∀ P : Prop, false → P :=
λ P f,
false.elim f
theorem fromFalse'': ∀ P : Prop, false → P :=
begin
assume P,
assume f,
show P,
from false.elim f,
end
/- *****************************************-/
/- *****************************************-/
/- *****************************************-/
/-**** -/
/- and -/
/-**** -/
/-
If P and Q are propositions, then
P ∧ Q is a proposition. It is read
as asserting that both P and Q are
true.
To prove P ∧ Q, one applies the
introduction rule for ∧ to a proof
of P and to a proof of Q.
{ P, Q : Prop } (p: P) (q: Q)
----------------------------- and.intro
⟨ p, q ⟩ : P ∧ Q
From a proof of P and Q one can derive
proofs of P and of Q by applying the left
and right elimination rules, respectively.
{ P Q: Prop } (pq : P ∧ Q)
--------------------------- and.elim_left
p : P
{ P Q: Prop } (pq : P ∧ Q)
--------------------------- and.elim_right
q : Q
-/
/- and introduction -/
def PandQ (P Q : Prop) (p: P) (q: Q) : P ∧ Q :=
and.intro p q
#check PandQ -- P → Q → P ∧ Q
theorem PandQ' : ∀ ( P Q : Prop ), P → Q → P ∧ Q :=
λ P Q p q,
⟨ p, q ⟩ -- shorthand for and.intro p q
#check PandQ'
theorem PandQ'' : ∀ { P Q : Prop }, P → Q → P ∧ Q :=
begin
assume P Q p q,
show P ∧ Q,
from ⟨ p, q ⟩, -- again shorthand for and.intro p q
end
/- and elimination -/
def PfromPandQ (P Q: Prop) (pq: P ∧ Q) : P :=
and.elim_left pq
def QfromPandQ (P Q: Prop) (pq: P ∧ Q) : Q :=
and.elim_right pq
theorem PfromPandQ' : ∀ { P Q : Prop }, P ∧ Q → P :=
λ P Q pq,
pq.left -- shorthand for and.elim_left pq
theorem QfromPandQ' : ∀ { P Q : Prop }, P ∧ Q → Q :=
λ P Q pq,
pq.right -- shorthand for and.elim_right pq
theorem PfromPandQ'' : ∀ { P Q : Prop }, P ∧ Q → P :=
begin
assume P Q pq,
show P,
from pq.left
end
theorem QfromPandQ'' : ∀ { P Q : Prop }, P ∧ Q → Q :=
begin
assume P Q pq,
show Q,
from pq.right
end
/- *****************************************-/
/- *****************************************-/
/- *****************************************-/
/- ********* -/
/- functions -/
/- ********* -/
/-
If P and Q are arbitrary types (examples of which include
bool, nat, and string), then P → Q is the type of a total
function that takes, as an argument, any value of type P,
and that always then returns some value of type Q.
The type judgment, f : P → Q, asserts that the identifier,
f, will bound to a value of type, P → Q: that is to say, f
is (bound to) some function that takes values of type P as
arguments and that returns values of type Q as results.
To "prove" (which means to provide a value of) type P → Q,
you have to provide a lambda abstraction that defines some
particular function from type P to type Q.
-/
/- → introduction -/
/-
To "prove" a function type, P → Q, you provide a lambda
abstraction that defines a particular function value of
this type. The particular lambda expressions selected as
a proof is significant, as their are many functions values
of most function types. For example, a function that takes
a ℕ, n, and that returns n + 1, and a function that takes
a ℕ, n and returns n * n, are both of type ℕ → ℕ, but in
most cases would not be interchangeable in a program. So,
when "proving" a function type, we're almost always very
careful to pick a specific function definition of interest
as a proof.
-/
/-
For example, we could exhibit a proof, inc, of ℕ → ℕ,
which is to say that we could define a function, inc,
that simply increments its argument, with the lambda
abstraction, λ n, n + 1. This is the function that
adds one to its argument, n, of type ℕ. Let's look at
different ways this function can be defined in Lean.
-/
/-
First, we define inc to be a value of type ℕ → ℕ,
namely the value, λ n : ℕ, n + 1.
-/
def inc : ℕ → ℕ := λ n : ℕ, (n + 1 : ℕ)
#check inc -- type: ℕ → ℕ
#reduce inc -- value/proof: λ n : ℕ, n + 1
#check inc 3
#reduce inc 3
/-
Typically we would drop explicit types in places where
Lean can infer them.
-/
def inc' : ℕ → ℕ := λ n, n + 1
/-
We can also write such a function in a more Python-like
style.
-/
def inc'' (n : ℕ) : ℕ := n + 1
-- It really is the same function type and value
#check inc''
#reduce inc''
/-
Again we can often simplify code by leaving out explicit types
-/
def inc''' (n : ℕ) := n + 1
/-
We can confirm that the type of this function is still ℕ → ℕ.
-/
#check inc'''
/-
You must be able to express function values using both
Python-like expressions and lambda abstractions.
-/
/-
We note that we can even construct function values
using tactic scripts.
Knowing how to do this can be useful both in handling
unexpected proof states, and might be useful for
some who like to create functions in an imperative style.
-/
def inc'''' (n : ℕ) : ℕ :=
begin
exact n + 1
end
def inc''''' : ℕ → ℕ :=
begin
assume n,
show ℕ,
from n + 1
end
-- these are all exactly the same function
#reduce inc
#reduce inc'
#reduce inc'''
#reduce inc''''
#reduce inc'''''
/- multiple arguments -/
/-
If P, Q, and R are types, then P → Q → R is
also a type. Because → is right associative,
this type can also be written as P → (Q → R).
This is the type of functions that take values
of type P as arguments and that return values
of type (Q → R) as results.
If we have a function, f, of type P → Q → R,
we can apply it to a value p : P and get back
some function of type Q → R.
So the result of (f p) is a function of type
Q → R. The function (f p) can thus be applied
to an value, q, of type Q to obtain a result,
r, of type R, with the expression (f p) q.
Because function application is left associative
the parenthesis can be dropped and you can just
write f p q, giving the impression that f is a
function that takes two arguments, one of type P
and one of type Q (and that then returns a value
of type R).
Here's an example.
-/
def plus (n m: ℕ) : ℕ := n + m
#check plus
#reduce plus
#check plus 3
#reduce plus 3 -- a function taking one argument!
#reduce (plus 3) 4 -- that function applied to 4
#reduce plus 3 4 -- the parentheses were redundant
/-
The following section addresses implication,
where, if P and Q are propositions, P → Q, is
the logical implication, if there is a proof of
P then a proof of Q can be constructed. A proof
of this proposition is given by any function of
type P → Q.
Everything in this section about function types
and values/implementations (lambda expressions)
applies to implications, so bear the lessons of
this section in mind as you read the next one.
-/
/- → elimination -/
/-
The elimination rule for functions is easy. The
application of a function, f : P → Q, to a value,
p : P, will produce a value of type Q.
-/
#check inc 3
#reduce inc 3
/- *****************************************-/
/- *****************************************-/
/- *****************************************-/
/- *********** -/
/- implication -/
/-************ -/
/-
If P and Q are propositions, then P → Q
is a proposition. It read as asserting
that if P is true then Q is true.
To prove P → Q, one must show that there
is a (total) function that, when given a
proof of P as an argument, constructs a
proof of Q as a result. NB: Functions can
be defined to take argument of types that
have no value! See the false elimination
examples above. It is very important to
understand that P → Q being true does not
necessarily mean that P is true, but only
that *if* P is true (there is a proof of
P) then Q is true (a proof of Q can be
constructed).
To prove P → Q, provide a function that
shows that from an assumed proof of P
one can construct a proof of Q. The type
of such a function is P → Q.
-/
-- implication introduction
def falseImpliesTrue (f : false) : true :=
true.intro
#check falseImpliesTrue
example : false → true :=
λ f : false, true.intro
example : false → true :=
falseImpliesTrue
/- → implication elimination -/
/-
From a proof of P → Q and a proof of P
one can derive a proof of Q. This is done
by "applying" the proof of the implication
(which in Lean is a function) to the proof
of P, the result of which is a proof of Q.
(P Q : Prop) (p2q: P → Q) (p : P)
--------------------------------- → elim
(p2q p) : Q
-/
def arrowElim {P Q : Prop} (p2q: P → Q) (p : P) : Q :=
p2q p
theorem arrowElim': ∀ { P Q : Prop}, (P → Q) → P → Q :=
λ P Q p2q p,
p2q p
theorem arrowElim'': ∀ { P Q : Prop}, (P → Q) → P → Q :=
begin
assume P Q p2q p,
show Q,
from p2q p
end
/- ********** -/
/- forall (∀) -/
/- ********** -/
/-
If P is a type and Q is a predicate,
then ∀ p : P, Q is a proposition. It
is read as stating that the predicate,
Q, is true for any value, p, in the
set of values (domain of discourse)
given by the type, P. The predicate,
Q, is usually one that takes a value
of type, P, as an argument, but this
is not always the case. For example,
one could write, ∀ n : ℕ, true. Here
the predicate, true, is a predicate
that takes no arguments at all, and
so it is simply a proposition, and it
is true for every value of n, so the
proposition, ∀ n : ℕ, true, is true.
More commonly, the predicate part of
a universally quantified proposition
will be "about" the values over which
the quantification ranges. Here is an
example:
∀ n : ℕ : (n > 2 ∧ prime n) → odd n
This proposition asserts that any n
greater than 2 and prime is also odd
(which also happens to be true). The
predicate, (n > 2 ∧ prime n) → odd n,
in this case takes n as an argument,
and is thus "about" each of the values
over which the ∀ ranges.
-/
/- ∀ introduction -/
/-
To prove a proposition, ∀ p : P, Q,
assume an arbitrary value, p : P,
and shows that the predicate, Q, is
true for that assumed value. As the
value was chosen arbitrarily, it thus
follows that the predicate is true
for *any* such value, proving the ∀.
To see this principle in action,
study the following proof script.
-/
theorem allNEqualSelf: ∀ n : ℕ, n = n :=
begin
assume n, -- assume an arbitrary n
show n = n, -- show predicate true for n
from rfl, -- thus proving ∀ n, n = n
end
/- ∀ elimination -/
/-
∀ elimination reasons that if some
predicate, Q, is true for every value of
some type, then it must also be true for
any particular value of that type. So
from a proof, p2q, of ∀ P, Q and a proof,
p : P, we conclude Q.
P : Type, Q : P → Prop, p2q : ∀ p : P, Q, p : P
-----------------------------------------------
(p2q p) : Q p
Forall elimination is just another form
of arrow elimination. In constructive
logic this is function application. Study
the following examples carefully to see
how this works.
-/
def forallElim (p2q: ∀ n : nat, n = n) (p : nat) : p = p :=
p2q p
def forallElim' (p2q: ∀ n : nat, n = n) (p : nat) : p = p :=
begin
exact (p2q p)
end
#reduce forallElim allNEqualSelf 7
/- *****************************************-/
/- *****************************************-/
/- *****************************************-/
/- ************** -/
/- ** Negation ** -/
/- ************** -/
/-
If P is a proposition, then ¬ P is one, too.
We read ¬ P as asserting that P is false. In
constructive logic this means that there is
no proof of P. In constructive logic, ¬ P is
thus actually defined as P → false. So ¬ P
means P → false, and a proof of ¬ P is just
a proof of P → false.
To prove ¬ P, one thus assumes a proof of P
and shows that, in that context, one can
construct a proof of false. That is, one
exhibits a function that takes a proof of
P as an argument and constructs and returns
a proof of false as a result.
This is the introduction rule for ¬. Another
way to say this: To prove ¬ P, assume P and
show that this leads to a contradiction.
This is of course just the principle of proof
by negation, equivalent to the introduction
rule for false.
P: Prop, f2p : P → false
------------------------ false introduction
np : ¬ P
We discuss the elimination rule for ¬ below.
The key idea is that it's really a rule for
double negation elimination, and it requires
classical reasoning. More on this later.
-/
-- negation introduction
/-
That Lean accepts the following function definition
shows that a proof of P → false *is* a proof of ¬ P
-/
def notIntro (P : Prop) (p2f: P → false) : ¬P :=
p2f
/-
An equivalent proof script.
-/
theorem notIntro':
∀ P : Prop, (P → false) → ¬P :=
begin
assume P : Prop,
assume p2f : P → false,
show ¬P,
from p2f
end
/-
Example: from the assumption that a
proposition, P, is true, we can deduce
that ¬ ¬ P is true, as well. This is
a rule for double negation introduction,
though not a rule that is commonly needed.
-/
theorem doubleNegIntro : ∀ P : Prop, P → ¬¬P :=
begin
assume P : Prop,
assume p : P,
assume np : ¬P, -- ¬¬P means ¬P → false, so assume ¬P
show false,
--from np p,
contradiction,
end
theorem doubleNegIntro' : ∀ P : Prop, P → ¬¬P :=
λ P p np,
np p
/- negation elimination -/
/-
The rule for negation elimination in
natural deduction is really a rule
for double negation elimination: it
states that, ∀ P : Prop, ¬ (¬ P) → P.
Because ¬ is right associative, we
can drop the parenthesis: ¬ ¬ P → P.
This rule is not valid in constructive
logic. You can't prove the following
unless you also accept the axiom of
the excluded middle, or equivalent.
-/
example: ∀ P : Prop, ¬¬P → P :=
begin
assume P nnp,
/-
No way to get from ¬¬P to P.
stuck and giving up on this proof.
-/
end
/-
However, if we accept the axiom of the
excluded middle, which we can do by
"opening" Lean's "classical" module,
then we can prove that double negation
elimination is valid.
-/
open classical
#check em
/-
Now em is the axiom of the excluded middle.
What em tells us is that if P is any
proposition, then either one of P or ¬ P is
true, and there are no other possibilities.
And from em we can now prove double negation
elimination. The proof is by "case analysis."
We consider each of the two possible cases for
P (true and false) in turn.
If we assume P is true, then we are done,
as our goal is to show P (from ¬ ¬ P). On
the other hand, if we assume P is false,
i.e., ¬ P, then we reach a contradiction.
We have already assumed ¬ ¬ P is true and
we are trying to prove P. But now if we
also assume that ¬ P is true, then clearly
we have a contradiction (between ¬ P and
¬ ¬ P). Using false elimination finishes
this case leaving us with the conclusion
that P is true in either case.
-/
theorem doubleNegationElim:
∀(P : Prop), ¬¬P → P :=
begin
assume P nnp,
show P,
from
begin
-- preview: we study case analysis later
-- proof by case analysis for P
cases (em P) with pf_P pf_nP, -- (em P) is (P ∨ ¬ P)
-- case with P is assumed to be true
exact pf_P,
-- case with P is assumed to be false
exact false.elim (nnp pf_nP)
-- em says there are no other cases
end,
end
/-
Double negation elimination is the fundamental
operation needed in a proof by contradiction.
In a proof by contradiction, on tries to prove
P by assuming ¬ P and showing that that leads
to a contradiction, thus to a proof that ¬ P
is not true, that is, ¬ (¬ P). The negation
elimination rule lets us then conclude P.
-/
/-
Note: The law of the excluded middle
allows you to conclude P ∨ ¬ P "for free,"
without giving a proof of either P or of
¬ P. It is in this precise sense that em
is not "constructive." When using em, you
do not build a "bigger" proof (of P ∨ ¬ P)
from one or more "smaller" proofs (of P or
of ¬ P). Whereas constructive proofs are
"informative," in that they contain the
smaller proofs needed to justify a given
conclusion, classical proofs are not, in
general. Accepting that P ∨ ¬ P by using
em gives you a proof but such a proof does
not tell you anything at all about which
case is true, whereas a constructive proof
does.
-/
/- *****************************************-/
/- *****************************************-/
/- *****************************************-/
/- *************** -/
/- bi-implication -/
/- *************** -/
/-
If P and Q are propositions then so is P ↔ Q.
We read P ↔ Q as asserting P → Q ∧ Q → P. To
prove P ↔ Q, we have to provide proofs of both
conjunctions, and from a proof of P ↔ Q we can
obtain proofs of P → Q and of Q → P by use of
the elimination rule for ↔.
The ↔ symbol is pronounced as is equivalent
to," or as "if and only if," In mathematical
writing it is often written as "iff". And to
get the ↔ symbol in Lean, use backslash-iff.
Its introduction and elimination rules are
equivalent to those for conjunction, but
specialized to the case where each of the
conjuncts is an implication and where one
is the other going in the other direction.
-/
/- iff introduction -/
/-
To prove P ↔ Q (introduction), apply iff.intro
to proofs of P and Q.
(P Q : Prop), (pq : P → Q) (qp : Q → P)
--------------------------------------- iff.intro
pqEquiv: P ↔ Q
-/
theorem iffIntro:
∀(P Q: Prop), (P → Q) → (Q → P) → (P ↔ Q) :=
begin
assume P Q : Prop,
assume p2q q2p,
apply iff.intro p2q q2p
end
theorem iffIntro':
∀(P Q : Prop), (P → Q) → (Q → P) → (P ↔ Q) :=
λ P Q pq qp,
iff.intro pq qp
theorem iffIntro'':
∀(P Q: Prop), (P → Q) → (Q → P) → (P ↔ Q) :=
begin
assume P Q : Prop,
assume p2q q2p,
apply iff.intro,
exact p2q,
exact q2p
end
/- iff elimination -/
/-
Similarly, the left and right iff elimination
rules are equivalent to the and elimination
rules but for the special case where the
conjunction is a bi-implication in particular.
-/
theorem iffElimLeft:
∀(P Q : Prop), (P ↔ Q) → P → Q :=
begin
assume P Q : Prop,
assume bi : P ↔ Q,
show P → Q,
from iff.elim_left bi -- bi.1 is a shorthand
end
theorem iffElimLeft':
∀(P Q : Prop), (P ↔ Q) → P → Q :=
λ P Q bi,
iff.elim_left bi
theorem iffElimRight:
∀(P Q : Prop), (P ↔ Q) → Q → P :=
λ P Q bi,
iff.elim_right bi
/- *****************************************-/
/- *****************************************-/
/- *****************************************-/
/- **************** -/
/- or (disjunction) -/
/- **************** -/
/-
If P and Q are propositions, then so is P ∨ Q.
P ∨ Q asserts that at least one of P, Q is true,
but it does not indicate which case holds.
-/
/- introduction rules for or -/
/-
To prove P ∨ Q, in constructive logic
one either applies the or.intro_left rule
to a proof of P or the or.intro_right rule
to a proof of Q. In either case, one must
also provide, as the first argument, the
proposition that is not being proved. The
shorthand or.inl and or.inr rules infer
these propositional arguments and are
easier and clearer to use in practice.
-/
theorem orIntroLeft (P Q : Prop) (p : P) : P ∨ Q :=
or.intro_left Q p -- args: proposition Q, proof of P
theorem orIntroLeft': forall P Q: Prop, P → (P ∨ Q) :=
λ P Q p,
or.inl p -- shorthand
theorem orIntroLeft'' (P Q : Prop) (p : P) : P ∨ Q :=
begin
apply or.intro_left,
assumption
end
theorem orIntroRight: forall P Q: Prop, Q → (P ∨ Q) :=
λ P Q q,
or.inr q
/- or elimination -/
/-
The elimination rule for or says that if
(1) P ∨ Q is true, (2) P → R, and (3) Q → R,
then you can conclude R.
The reasoning in by "case analysis." In
one case, if P ∨ Q because P is, then use
P → R to prove R. Otherwise, if P ∨ Q is
true because Q is, then use Q → R to prove
R. Usually you don't know which case holds
so to prove R from P ∨ Q you have to show
that R follows "in either case", and to
do that, you need both P → R and Q → R.
pfPQ: P ∨ Q, pfPR: P → R, pfQR: Q → R
-------------------------------------- or.elim
R
So, for example if (1) "it's raining or the
fire hydrant is running" (P ∨ Q), (2)"if it's
raining then the streets are wet", and (3)
"if the fire hydrant is running then the
streets are wet", then the streets are wet!
-/
theorem orElim :
∀(P Q R: Prop),
(P ∨ Q) → (P → R) → (Q → R) → R
:=
begin
assume P Q R,
assume PorQ: (P ∨ Q),
assume pr: (P → R),
assume qr: (Q → R),
show R,
from or.elim PorQ pr qr
end
theorem orElim' :
∀(P Q R: Prop),
(P ∨ Q) → (P → R) → (Q → R) → R
:=
begin