forked from djvelleman/HTPIwL
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathChap3.qmd
4971 lines (4266 loc) · 156 KB
/
Chap3.qmd
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
# Proofs
## 3.1 & 3.2. Proofs Involving Negations and Conditionals
Sections 3.1 and 3.2 of *How To Prove It* present strategies for dealing with givens and goals involving negations and conditionals. We restate those strategies here, and explain how to use them with Lean.
Section 3.1 gives two strategies for proving a goal of the form `P → Q` (*HTPI* pp. 95, 96):
#### To prove a goal of the form `P → Q`:
1. Assume `P` is true and prove `Q`.
2. Assume `Q` is false and prove that `P` is false.
We've already seen how to carry out both of these strategies in Lean. For the first strategy, use the `assume` tactic to introduce the assumption `P` and assign an identifier to it; Lean will automatically set `Q` as the goal. We can summarize the effect of using this strategy by showing how the tactic state changes if you use the tactic `assume h : P`:
::: {.lftrt}
::: {.bef}
```state
>> ⋮
⊢ P → Q
```
:::
::: {.aft}
```state
>> ⋮
h : P
⊢ Q
```
:::
:::
The second strategy is justified by the contrapositive law. In Lean, you can use the `contrapos` tactic to rewrite the goal as `¬Q → ¬P` and then use the tactic `assume h : ¬Q`. The net effect of these two tactics is:
::: {.lftrt}
::: {.bef}
```state
>> ⋮
⊢ P → Q
```
:::
::: {.aft}
```state
>> ⋮
h : ¬Q
⊢ ¬P
```
:::
:::
Section 3.2 gives two strategies for using givens of the form `P → Q`, with the second once again being a variation on the first based on the contrapositive law (*HTPI* p. 108):
#### To use a given of the form `P → Q`:
1. If you are also given `P`, or you can prove that `P` is true, then you can use this given to conclude that `Q` is true.
2. If you are also given `¬Q`, or you can prove that `Q` is false, then you can use this given to conclude that `P` is false.
The first strategy is the modus ponens rule of inference, and we saw in the last chapter that if you have `h1 : P → Q` and `h2 : P`, then `h1 h2` is a (term-mode) proof of `Q`; often we use this rule with the `have` or `show` tactic. For the second strategy, if you have `h1 : P → Q` and `h2 : ¬Q`, then the `contrapos at h1` tactic will change `h1` to `h1 : ¬Q → ¬P`, and then `h1 h2` will be a proof of `¬P`.
All of the strategies listed above for working with conditional statements as givens or goals were illustrated in examples in the last chapter.
Section 3.2 of *HTPI* offers two strategies for proving negative goals (*HTPI* pp. 101, 102):
#### To prove a goal of the form `¬P`:
1. Reexpress the goal in some other form.
2. Use proof by contradiction: assume `P` is true and try to deduce a contradiction.
For the first strategy, the tactics `demorgan`, `conditional`, `double_neg`, and `bicond_neg` may be useful, and we saw how those tactics work in the last chapter. But how do you write a proof by contradiction in Lean? The answer is to use a tactic called `by_contra`. If the goal is `¬P`, then the tactic `by_contra h` will introduce the assumption `h : P` and set the goal to be `False`, like this:
::: {.lftrt}
::: {.bef}
```state
>> ⋮
⊢ ¬P
```
:::
::: {.aft}
```state
>> ⋮
h : P
⊢ False
```
:::
:::
In Lean, `False` represents a statement that is always false---that is, a contradiction, as that term is defined in Section 1.2 of *HTPI*. The `by_contra` tactic can actually be used even if the goal is not a negative statement. If the goal is a statement `P` that is not a negative statement, then `by_contra h` will initiate a proof by contradiction by introducing the assumption `h : ¬P` and setting the goal to be `False`.
You will usually complete a proof by contradiction by deducing two contradictory statements---say, `h1 : Q` and `h2 : ¬Q`. But how do you convince Lean that the proof is over? You must be able to prove the goal `False` from the two givens `h1` and `h2`. There are two ways to do this. The first is based on the fact that Lean treats a statement of the form `¬Q` as meaning the same thing as `Q → False`. This makes sense, because these statements are logically equivalent, as shown by the following truth table:
::: {style="margin: 0% 20%"}
| `Q` | `¬Q` | `(Q` | `→` | `False)`|
|:----------:|:----------:|-:|:-:|:-|
| F | T | F | T | [ ]{.excl} F |
| T | F | T | F | [ ]{.excl} F |
:::
Thinking of `h2 : ¬Q` as meaning `h2 : Q → False`, we can combine it with `h1 : Q` using modus ponens to deduce `False`. In other words, `h2 h1` is a proof of `False`.
But there is a second way of completing the proof that it is worthwhile to know about. From contradictory statements `h1 : Q` and `h2 : ¬Q` you can validly deduce *any* statement. This follows from the definition of a *valid argument* in Section 1.1 of *HTPI*. According to that definition, you can validly infer a conclusion `R` from premises `h1 : Q` and `h2 : ¬Q` if the premises cannot both be true without the conclusion also being true. In this case, that standard is met, for the simple reason that the premises cannot both be true! (This gives part of the answer to exercise 18 in Section 1.2 of *HTPI*.) Thus, Lean has a rule that allows you to prove any statement from contradictory premises. If you have `h1 : Q` and `h2 : ¬Q`, then Lean will recognize `absurd h1 h2` as a (term-mode) proof of *any* statement.
To summarize, if you have `h1 : Q` and `h2 : ¬Q`, then there are two ways to prove `False`. Lean will recognize `h2 h1` as a proof of `False`, and it will recognize `absurd h1 h2` as a proof of any statement, including `False`. Notice the difference in the order in which `h1` and `h2` are listed in these two proofs: In the first one, the negative statement `h2` must come first, just as the conditional statement must come first in an application of modus ponens. But in a proof using `absurd`, the negative statement must come second.
To illustrate proof by contradiction in Lean, let's redo our first example from the last Chapter in a different way. That example was based on Example 3.2.4 in *HTPI*. We'll begin with the same first two steps, introducing two assumptions.
::: {.inout}
::: {.inpt}
```lean
theorem Example_3_2_4_v2 (P Q R : Prop)
(h : P → (Q → R)) : ¬R → (P → ¬Q) := by
assume h2 : ¬R
assume h3 : P
**done::
```
:::
::: {.outpt}
```state
P Q R : Prop
h : P → Q → R
h2 : ¬R
h3 : P
⊢ ¬Q
```
:::
:::
Now the goal is a negative statement, so we use the tactic `by_contra h4` to introduce the assumption `h4 : Q` and set the goal to be `False`:
::: {.inout}
::: {.inpt}
```lean
theorem Example_3_2_4_v2 (P Q R : Prop)
(h : P → (Q → R)) : ¬R → (P → ¬Q) := by
assume h2 : ¬R
assume h3 : P
by_contra h4
**done::
```
:::
::: {.outpt}
```state
P Q R : Prop
h : P → Q → R
h2 : ¬R
h3 : P
h4 : Q
⊢ False
```
:::
:::
Using the givens `h`, `h3`, and `h4` we can deduce first `Q → R` and then `R` by two applications of modus ponens:
::: {.inout}
::: {.inpt}
```lean
theorem Example_3_2_4_v2 (P Q R : Prop)
(h : P → (Q → R)) : ¬R → (P → ¬Q) := by
assume h2 : ¬R
assume h3 : P
by_contra h4
have h5 : Q → R := h h3
have h6 : R := h5 h4
**done::
```
:::
::: {.outpt}
```state
P Q R : Prop
h : P → Q → R
h2 : ¬R
h3 : P
h4 : Q
h5 : Q → R
h6 : R
⊢ False
```
:::
:::
Now we have a contradiction: `h2 : ¬R` and `h6 : R`. To complete the proof, we deduce `False` from these two givens. Either `h2 h6` or `absurd h6 h2` would be accepted by Lean as a proof of `False`:
::: {.inout}
::: {.inpt}
```lean
theorem Example_3_2_4_v2 (P Q R : Prop)
(h : P → (Q → R)) : ¬R → (P → ¬Q) := by
assume h2 : ¬R
assume h3 : P
by_contra h4
have h5 : Q → R := h h3
have h6 : R := h5 h4
show False from h2 h6
done
```
:::
::: {.outpt}
```state
No goals
```
:::
:::
Finally, we have two strategies for using a given that is a negative statement (*HTPI* pp. 105, 108):
#### To use a given of the form `¬P`:
1. Reexpress the given in some other form.
2. If you are doing a proof by contradiction, you can achieve a contradiction by proving `P`, since that would contradict the given `¬P`.
Of course, strategy 1 suggests the use of the `demorgan`, `conditional`, `double_neg`, and `bicond_neg` tactics, if they apply. For strategy 2, if you are doing a proof by contradiction and you have a given `h : ¬P`, then the tactic `contradict h` will set the goal to be `P`, which will complete the proof by contradicting `h`. In fact, this tactic can be used with any given; if you have a given `h : P`, where `P` is not a negative statement, then `contradict h` will set the goal to be `¬P`. You can also follow the word `contradict` with a proof that is more complicated than a single identifier. For example, if you have givens `h1 : P → ¬Q` and `h2 : P`, then `h1 h2` is a proof of `¬Q`, so the tactic `contradict h1 h2` will set the goal to be `Q`.
If you're not doing a proof by contradiction, then the tactic `contradict h with h'` will first initiate a proof by contradiction by assuming the negation of the goal, giving that assumption the identifier `h'`, and then it will set the goal to be the negation of the statement proven by `h`. In other words, `contradict h with h'` is shorthand for `by_contra h'; contradict h`.
We can illustrate this with yet another way to write the proof from Example 3.2.4. Our first three steps will be the same as last time:
::: {.inout}
::: {.inpt}
```lean
theorem Example_3_2_4_v3 (P Q R : Prop)
(h : P → (Q → R)) : ¬R → (P → ¬Q) := by
assume h2 : ¬R
assume h3 : P
by_contra h4
**done::
```
:::
::: {.outpt}
```state
P Q R : Prop
h : P → Q → R
h2 : ¬R
h3 : P
h4 : Q
⊢ False
```
:::
:::
Since we are now doing a proof by contradiction and the given `h2 : ¬R` is a negative statement, a likely way to proceed is to try to prove `R`, which would contradict `h2`. So we use the tactic `contradict h2`:
::: {.inout}
::: {.inpt}
```lean
theorem Example_3_2_4_v3 (P Q R : Prop)
(h : P → (Q → R)) : ¬R → (P → ¬Q) := by
assume h2 : ¬R
assume h3 : P
by_contra h4
contradict h2
**done::
```
:::
::: {.outpt}
```state
P Q R : Prop
h : P → Q → R
h2 : ¬R
h3 : P
h4 : Q
⊢ R
```
:::
:::
As before, we can now prove `R` by combining `h`, `h3`, and `h4`. In fact, we could do it in one step: by modus ponens, `h h3` is a proof of `Q → R`, and therefore, by another application of modus ponens, `(h h3) h4` is a proof of `R`. The parentheses here are not necessary; Lean will interpret `h h3 h4` as `(h h3) h4`, so we can complete the proof like this:
::: {.inout}
::: {.inpt}
```lean
theorem Example_3_2_4_v3 (P Q R : Prop)
(h : P → (Q → R)) : ¬R → (P → ¬Q) := by
assume h2 : ¬R
assume h3 : P
by_contra h4
contradict h2
show R from h h3 h4
done
```
:::
::: {.outpt}
```state
No goals
```
:::
:::
You could shorten this proof slightly by replacing the lines `by_contra h4` and `contradict h2` with the single line `contradict h2 with h4`.
There is one more idea that is introduced in Section 3.2 of *HTPI*. The last example in that section illustrates how you can sometimes use rules of inference to work backwards. Here's a similar example in Lean:
::: {.inout}
::: {.inpt}
```lean
theorem Like_Example_3_2_5
(U : Type) (A B C : Set U) (a : U)
(h1 : a ∈ A) (h2 : a ∉ A \ B)
(h3 : a ∈ B → a ∈ C) : a ∈ C := by
**done::
```
:::
::: {.outpt}
```state
U : Type
A B C : Set U
a : U
h1 : a ∈ A
h2 : a ∉ A \ B
h3 : a ∈ B → a ∈ C
⊢ a ∈ C
```
:::
:::
The goal is `a ∈ C`, and the only given that even mentions `C` is `h3 : a ∈ B → a ∈ C`. If only we could prove `a ∈ B`, then we could apply `h3`, using modus ponens, to reach our goal. So it would make sense to work toward the goal of proving `a ∈ B`.
To get Lean to use this proof strategy, we use the tactic `apply h3 _`. The underscore here represents a blank to be filled in by Lean. You might think of this tactic as asking Lean the question: If we want `h3 _` to be a proof of the goal `a ∈ C`, what do we have to put in the blank? Lean is able to figure out that the answer is: a proof of `a ∈ B`. So it sets the goal to be `a ∈ B`, since a proof of that goal, when inserted into the blank in `h3 _`, would prove the original goal `a ∈ C`:
::: {.inout}
::: {.inpt}
```lean
theorem Like_Example_3_2_5
(U : Type) (A B C : Set U) (a : U)
(h1 : a ∈ A) (h2 : a ∉ A \ B)
(h3 : a ∈ B → a ∈ C) : a ∈ C := by
apply h3 _
**done::
```
:::
::: {.outpt}
```state
U : Type
A B C: Set U
a : U
h1 : a ∈ A
h2 : a ∉ A \ B
h3 : a ∈ B → a ∈ C
⊢ a ∈ B
```
:::
:::
Our situation now is very much like the one in the theorem `Example_3_2_5_Simple` in the previous chapter, and the rest of our proof will be similar to the proof there. The given `h2` is a negative statement (`a ∉ A \ B` is shorthand for `¬a ∈ A \ B`), so, as suggested by our first strategy for using negative givens, we reexpress it as an equivalent positive statement. Writing out the definition of set difference, `h2` means `¬(a ∈ A ∧ a ∉ B)`, and then one of De Morgan's laws and a conditional law allow us to rewrite it first as `a ∉ A ∨ a ∈ B` and then as `a ∈ A → a ∈ B`. Of course, we have tactics to accomplish all of these reexpressions:
::: {.inout}
::: {.inpt}
```lean
theorem Like_Example_3_2_5
(U : Type) (A B C : Set U) (a : U)
(h1 : a ∈ A) (h2 : a ∉ A \ B)
(h3 : a ∈ B → a ∈ C) : a ∈ C := by
apply h3 _
define at h2
demorgan at h2; conditional at h2
**done::
```
:::
::: {.outpt}
```state
U : Type
A B C : Set U
a : U
h1 : a ∈ A
h2 : a ∈ A → a ∈ B
h3 : a ∈ B → a ∈ C
⊢ a ∈ B
```
:::
:::
And now it is easy to complete the proof by applying modus ponens, using `h2` and `h1`:
::: {.inout}
::: {.inpt}
```lean
theorem Like_Example_3_2_5
(U : Type) (A B C : Set U) (a : U)
(h1 : a ∈ A) (h2 : a ∉ A \ B)
(h3 : a ∈ B → a ∈ C) : a ∈ C := by
apply h3 _
define at h2
demorgan at h2; conditional at h2
show a ∈ B from h2 h1
done
```
:::
::: {.outpt}
```state
No goals
```
:::
:::
We will see many more uses of the `apply` tactic later in this book.
Sections 3.1 and 3.2 of *HTPI* contain several proofs that involve algebraic reasoning. Although one can do such proofs in Lean, it requires ideas that we are not ready to introduce yet. So for the moment we will stick to proofs involving only logic and set theory.
### Exercises
Fill in proofs of the following theorems. All of them are based on exercises in *HTPI*.
::: {.numex arguments="1"}
```lean
theorem Exercise_3_2_1a (P Q R : Prop)
(h1 : P → Q) (h2 : Q → R) : P → R := by
**done::
```
:::
::: {.numex arguments="2"}
```lean
theorem Exercise_3_2_1b (P Q R : Prop)
(h1 : ¬R → (P → ¬Q)) : P → (Q → R) := by
**done::
```
:::
::: {.numex arguments="3"}
```lean
theorem Exercise_3_2_2a (P Q R : Prop)
(h1 : P → Q) (h2 : R → ¬Q) : P → ¬R := by
**done::
```
:::
::: {.numex arguments="4"}
```lean
theorem Exercise_3_2_2b (P Q : Prop)
(h1 : P) : Q → ¬(Q → ¬P) := by
**done::
```
:::
## 3.3. Proofs Involving Quantifiers
In the notation used in *HTPI*, if $P(x)$ is a statement about $x$, then $\forall x\, P(x)$ means "for all $x$, $P(x)$," and $\exists x\, P(x)$ means "there exists at least one $x$ such that $P(x)$." The letter $P$ here does not stand for a proposition; it is only when it is applied to some object $x$ that we get a proposition. We will say that $P$ is a *predicate*, and when we apply $P$ to an object $x$ we get the proposition $P(x)$. You might want to think of the predicate $P$ as representing some property that an object might have, and the proposition $P(x)$ asserts that $x$ has that property.
To use a predicate in Lean, you must tell Lean the type of objects to which it applies. If `U` is a type, then `Pred U` is the type of predicates that apply to objects of type `U`. If `P` has type `Pred U` (that is, `P` is a predicate applying to objects of type `U`) and `x` has type `U`, then to apply `P` to `x` we just write `P x` (with a space but no parentheses). Thus, if we have `P : Pred U` and `x : U`, then `P x` is an expression of type `Prop`. That is, `P x` is a proposition, and its meaning is that `x` has the property represented by the predicate `P`.
There are a few differences between the way quantified statements are written in *HTPI* and the way they are written in Lean. First of all, when we apply a quantifier to a variable in Lean we will specify the type of the variable explicitly. Also, Lean requires that after specifying the variable and its type, you must put a comma before the proposition to which the quantifier is applied. Thus, if `P` has type `Pred U`, then to say that `P` holds for all objects of type `U` we would write `∀ (x : U), P x`. Similarly, `∃ (x : U), P x` is the proposition asserting that there exists at least one `x` of type `U` such that `P x`.
And there is one more important difference between the way quantified statements are written in *HTPI* and Lean. In *HTPI*, a quantifier is interpreted as applying to as little as possible. Thus, $\forall x\, P(x) \wedge Q(x)$ is interpreted as $(\forall x\, P(x)) \wedge Q(x)$; if you want the quantifier $\forall x$ to apply to the entire statement $P(x) \wedge Q(x)$ you must use parentheses and write $\forall x(P(x) \wedge Q(x))$. The convention in Lean is exactly the opposite: a quantifier applies to as much as possible. Thus, Lean will interpret `∀ (x : U), P x ∧ Q x` as meaning `∀ (x : U), (P x ∧ Q x)`. If you want the quantifier to apply to only `P x`, then you must use parentheses and write `(∀ (x : U), P x) ∧ Q x`.
With this preparation, we are ready to consider how to write proofs involving quantifiers in Lean. The most common way to prove a goal of the form `∀ (x : U), P x` is to use the following strategy (*HTPI* p. 114):
#### To prove a goal of the form `∀ (x : U), P x`:
::: {.ind}
Let `x` stand for an arbitrary object of type `U` and prove `P x`. If the letter `x` is already being used in the proof to stand for something, then you must choose an unused variable, say `y`, to stand for the arbitrary object, and prove `P y`.
:::
To do this in Lean, you should use the tactic `fix x : U`, which tells Lean to treat `x` as standing for some fixed but arbitrary object of type `U`. This has the following effect on the tactic state:
::: {.lftrt}
::: {.bef}
```state
>> ⋮
⊢ ∀ (x : U), P x
```
:::
::: {.aft}
```state
>> ⋮
x : U
⊢ P x
```
:::
:::
To use a given of the form `∀ (x : U), P x`, we usually apply a rule of inference called *universal instantiation*, which is described by the following proof strategy (*HTPI* p. 121):
#### To use a given of the form `∀ (x : U), P x`:
::: {.ind}
You may plug in any value of type `U`, say `a`, for `x` and use this given to conclude that `P a` is true.
:::
This strategy says that if you have `h : ∀ (x : U), P x` and `a : U`, then you can infer `P a`. Indeed, in this situation Lean will recognize `h a` as a proof of `P a`. For example, you can write `have h' : P a := h a` in a Lean tactic-mode proof, and Lean will add `h' : P a` to the tactic state. Note that `a` here need not be simply a variable; it can be any expression denoting an object of type `U`.
Let's try these strategies out in a Lean proof. In Lean, if you don't want to give a theorem a name, you can simply call it an `example` rather than a `theorem`, and then there is no need to give it a name. In the following example, you can enter the symbol `∀` by typing `\forall` or `\all`, and you can enter `∃` by typing `\exists` or `\ex`.
::: {.inout}
::: {.inpt}
```lean
example (U : Type) (P Q : Pred U)
(h1 : ∀ (x : U), P x → ¬Q x)
(h2 : ∀ (x : U), Q x) :
¬∃ (x : U), P x := by
**done::
```
:::
::: {.outpt}
```state
U : Type
P Q : Pred U
h1 : ∀ (x : U), P x → ¬Q x
h2 : ∀ (x : U), Q x
⊢ ¬∃ (x : U), P x
```
:::
:::
To use the givens `h1` and `h2`, we will probably want to use universal instantiation. But to do that we would need an object of type `U` to plug in for `x` in `h1` and `h2`, and there is no object of type `U` in the tactic state. So at this point, we can't apply universal instantiation to `h1` and `h2`. We should watch for an object of type `U` to come up in the course of the proof, and consider applying universal instantiation if one does. Until then, we turn our attention to the goal.
The goal is a negative statement, so we begin by reexpressing it as an equivalent positive statement, using a quantifier negation law. The tactic `quant_neg` applies a quantifier negation law to rewrite the goal. As with the other tactics for applying logical equivalences, you can write `quant_neg at h` if you want to apply a quantifier negation law to a given `h`. The effect of the tactic can be summarized as follows:
::: {style="margin: 0% 10%"}
| | `quant_neg` Tactic | |
|:--:|:--:|:--:|
| `¬∀ (x : U), P x` | is changed to | `∃ (x : U), ¬P x` |
| `¬∃ (x : U), P x` | is changed to | `∀ (x : U), ¬P x` |
| `∀ (x : U), P x` | is changed to | `¬∃ (x : U), ¬P x` |
| `∃ (x : U), P x` | is changed to | `¬∀ (x : U), ¬P x` |
:::
Using the `quant_neg` tactic leads to the following result.
::: {.inout}
::: {.inpt}
```lean
example (U : Type) (P Q : Pred U)
(h1 : ∀ (x : U), P x → ¬Q x)
(h2 : ∀ (x : U), Q x) :
¬∃ (x : U), P x := by
quant_neg --Goal is now ∀ (x : U), ¬P x
**done::
```
:::
::: {.outpt}
```state
U : Type
P Q : Pred U
h1 : ∀ (x : U), P x → ¬Q x
h2 : ∀ (x : U), Q x
⊢ ∀ (x : U), ¬P x
```
:::
:::
Now the goal starts with `∀`, so we use the strategy above and introduce an arbitrary object of type `U`. Since the variable `x` occurs as a bound variable in several statements in this theorem, it might be best to use a different letter for the arbitrary object; this isn't absolutely necessary, but it may help to avoid confusion. So our next tactic is `fix y : U`.
::: {.inout}
::: {.inpt}
```lean
example (U : Type) (P Q : Pred U)
(h1 : ∀ (x : U), P x → ¬Q x)
(h2 : ∀ (x : U), Q x) :
¬∃ (x : U), P x := by
quant_neg --Goal is now ∀ (x : U), ¬P x
fix y : U
**done::
```
:::
::: {.outpt}
```state
U : Type
P Q : Pred U
h1 : ∀ (x : U), P x → ¬Q x
h2 : ∀ (x : U), Q x
y : U
⊢ ¬P y
```
:::
:::
Now we have an object of type `U` in the tactic state, namely, `y`. So let's try applying universal instantiation to `h1` and `h2` and see if it helps.
::: {.inout}
::: {.inpt}
```lean
example (U : Type) (P Q : Pred U)
(h1 : ∀ (x : U), P x → ¬Q x)
(h2 : ∀ (x : U), Q x) :
¬∃ (x : U), P x := by
quant_neg --Goal is now ∀ (x : U), ¬P x
fix y : U
have h3 : P y → ¬Q y := h1 y
have h4 : Q y := h2 y
**done::
```
:::
::: {.outpt}
```state
U : Type
P Q : Pred U
h1 : ∀ (x : U), P x → ¬Q x
h2 : ∀ (x : U), Q x
y : U
h3 : P y → ¬Q y
h4 : Q y
⊢ ¬P y
```
:::
:::
We're almost done, because the goal now follows easily from `h3` and `h4`. If we use the contrapositive law to rewrite `h3` as `Q y → ¬P y`, then we can apply modus ponens to the rewritten `h3` and `h4` to reach the goal:
::: {.inout}
::: {.inpt}
```lean
example (U : Type) (P Q : Pred U)
(h1 : ∀ (x : U), P x → ¬Q x)
(h2 : ∀ (x : U), Q x) :
¬∃ (x : U), P x := by
quant_neg --Goal is now ∀ (x : U), ¬P x
fix y : U
have h3 : P y → ¬Q y := h1 y
have h4 : Q y := h2 y
contrapos at h3 --Now h3 : Q y → ¬P y
show ¬P y from h3 h4
done
```
:::
::: {.outpt}
```state
No goals
```
:::
:::
Our next example is a theorem of set theory. You already know how to type a few set theory symbols in Lean, but you'll need a few more for our next example. Here's a summary of the most important set theory symbols and how to type them in Lean.
::: {style="margin: 0% 10%"}
| Symbol | How To Type It |
|:----:|:-------:|
| `∈` | `\in` |
| `∉` | `\notin` or `\inn` |
| `⊆` | `\sub` |
| `⊈` | `\subn` |
| `=` | `=` |
| `≠` | `\ne` |
| `∪` | `\union` or `\cup` |
| `∩` | `\inter` or `\cap` |
| `\` | `\\` |
| `∆` | `\symmdiff` |
| `∅` | `\emptyset` |
| `𝒫` | `\powerset` |
:::
With this preparation, we can turn to our next example.
::: {.inout}
::: {.inpt}
```lean
example (U : Type) (A B C : Set U) (h1 : A ⊆ B ∪ C)
(h2 : ∀ (x : U), x ∈ A → x ∉ B) : A ⊆ C := by
**done::
```
:::
::: {.outpt}
```state
U : Type
A B C : Set U
h1 : A ⊆ B ∪ C
h2 : ∀ x ∈ A, x ∉ B
⊢ A ⊆ C
```
:::
:::
Notice that in the Infoview, Lean has written `h2` as `∀ x ∈ A, x ∉ B`, using a bounded quantifier. As explained in Section 2.2 of *HTPI* (see p. 72), this is a shorter way of writing the statement `∀ (x : U), x ∈ A → x ∉ B`. We begin by using the `define` tactic to write out the definition of the goal.
::: {.inout}
::: {.inpt}
```lean
example (U : Type) (A B C : Set U) (h1 : A ⊆ B ∪ C)
(h2 : ∀ (x : U), x ∈ A → x ∉ B) : A ⊆ C := by
define --Goal : ∀ ⦃a : U⦄, a ∈ A → a ∈ C
**done::
```
:::
::: {.outpt}
```state
U : Type
A B C: Set U
h1 : A ⊆ B ∪ C
h2 : ∀ x ∈ A, x ∉ B
⊢ ∀ ⦃a : U⦄,
>> a ∈ A → a ∈ C
```
:::
:::
Notice that Lean's definition of the goal starts with `∀ ⦃a : U⦄`, not `∀ (a : U)`. Why did Lean use those funny double braces rather than parentheses? We'll return to that question shortly. The difference doesn't affect our next steps, which are to introduce an arbitrary object `y` of type `U` and assume `y ∈ A`.
::: {.inout}
::: {.inpt}
```lean
example (U : Type) (A B C : Set U) (h1 : A ⊆ B ∪ C)
(h2 : ∀ (x : U), x ∈ A → x ∉ B) : A ⊆ C := by
define --Goal : ∀ ⦃a : U⦄, a ∈ A → a ∈ C
fix y : U
assume h3 : y ∈ A
**done::
```
:::
::: {.outpt}
```state
U : Type
A B C : Set U
h1 : A ⊆ B ∪ C
h2 : ∀ x ∈ A, x ∉ B
y : U
h3 : y ∈ A
⊢ y ∈ C
```
:::
:::
Now we can combine `h2` and `h3` to conclude that `y ∉ B`. Since we have `y : U`, by universal instantiation, `h2 y` is a proof of `y ∈ A → y ∉ B`, and therefore by modus ponens, `h2 y h3` is a proof of `y ∉ B`.
::: {.inout}
::: {.inpt}
```lean
example (U : Type) (A B C : Set U) (h1 : A ⊆ B ∪ C)
(h2 : ∀ (x : U), x ∈ A → x ∉ B) : A ⊆ C := by
define --Goal : ∀ ⦃a : U⦄, a ∈ A → a ∈ C
fix y : U
assume h3 : y ∈ A
have h4 : y ∉ B := h2 y h3
**done::
```
:::
::: {.outpt}
```state
U : Type
A B C : Set U
h1 : A ⊆ B ∪ C
h2 : ∀ x ∈ A, x ∉ B
y : U
h3 : y ∈ A
h4 : y ∉ B
⊢ y ∈ C
```
:::
:::
We should be able to use similar reasoning to combine `h1` and `h3`, if we first write out the definition of `h1`.
::: {.inout}
::: {.inpt}
```lean
example (U : Type) (A B C : Set U) (h1 : A ⊆ B ∪ C)
(h2 : ∀ (x : U), x ∈ A → x ∉ B) : A ⊆ C := by
define --Goal : ∀ ⦃a : U⦄, a ∈ A → a ∈ C
fix y : U
assume h3 : y ∈ A
have h4 : y ∉ B := h2 y h3
define at h1 --h1 : ∀ ⦃a : U⦄, a ∈ A → a ∈ B ∪ C
**done::
```
:::
::: {.outpt}
```state
U : Type
A B C : Set U
h1 : ∀ ⦃a : U⦄,
>> a ∈ A → a ∈ B ∪ C
h2 : ∀ x ∈ A, x ∉ B
y : U
h3 : y ∈ A
h4 : y ∉ B
⊢ y ∈ C
```
:::
:::
Once again, Lean has used double braces to define `h1`, and now we are ready to explain what they mean. If the definition had been `h1 : ∀ (a : U), a ∈ A → a ∈ B ∪ C`, then exactly as in the previous step, `h1 y h3` would be a proof of `y ∈ B ∪ C`. The use of double braces in the definition `h1 : ∀ ⦃a : U⦄, a ∈ A → a ∈ B ∪ C` means that you don't need to tell Lean that `y` is being plugged in for `a` in the universal instantiation step; Lean will figure that out on its own. Thus, you can just write `h1 h3` as a proof of `y ∈ B ∪ C`. Indeed, if you write `h1 y h3` then you will get an error message, because Lean expects *not* to be told what to plug in for `a`. You might think of the definition of `h1` as meaning `h1 : _ ∈ A → _ ∈ B ∪ C`, where the blanks can be filled in with anything of type `U` (with the same thing being put in both blanks). When you ask Lean to apply modus ponens by combining this statement with `h3 : y ∈ A`, Lean figures out that in order for modus ponens to apply, the blanks must be filled in with `y`.
In this situation, the `a` in `h1` is called an *implicit argument*. What this means is that, when `h1` is applied to make an inference in a proof, the value to be assigned to `a` is not specified explicitly; rather, the value is inferred by Lean. We will see many more examples of implicit arguments later in this book. In fact, there are two slightly different kinds of implicit arguments in Lean. One kind is indicated using the double braces `⦃ ⦄` used in this example, and the other is indicated using curly braces, `{ }`. The difference between these two kinds of implicit arguments won't be important in this book; all that will matter to us is that if you see either `∀ ⦃a : U⦄` or `∀ {a : U}` rather than `∀ (a : U)`, then you must remember that `a` is an implicit argument.
::: {.inout}
::: {.inpt}
```lean
example (U : Type) (A B C : Set U) (h1 : A ⊆ B ∪ C)
(h2 : ∀ (x : U), x ∈ A → x ∉ B) : A ⊆ C := by
define --Goal : ∀ ⦃a : U⦄, a ∈ A → a ∈ C
fix y : U
assume h3 : y ∈ A
have h4 : y ∉ B := h2 y h3
define at h1 --h1 : ∀ ⦃a : U⦄, a ∈ A → a ∈ B ∪ C
have h5 : y ∈ B ∪ C := h1 h3
**done::
```
:::
::: {.outpt}
```state
U : Type
A B C : Set U
h1 : ∀ ⦃a : U⦄,
>> a ∈ A → a ∈ B ∪ C
h2 : ∀ x ∈ A, x ∉ B
y : U
h3 : y ∈ A
h4 : y ∉ B
h5 : y ∈ B ∪ C
⊢ y ∈ C
```
:::
:::
If Lean was able to figure out that `y` should be plugged in for `a` in `h1` in this step, couldn't it have figured out that `y` should be plugged in for `x` in `h2` in the previous `have` step? The answer is yes. Of course, in `h2`, `x` was not an implicit argument, so Lean wouldn't *automatically* figure out what to plug in for `x`. But we could have asked it to figure it out by writing the proof in the previous step as `h2 _ h3` rather than `h2 y h3`. In a term-mode proof, an underscore represents a blank to be filled in by Lean. Try changing the earlier step of the proof to `have h4 : y ∉ B := h2 _ h3` and you will see that Lean will accept it. Of course, in this case this doesn't save us any typing, but in some situations it is useful to let Lean figure out some part of a proof.
Lean's ability to fill in blanks in term-mode proofs is limited. For example, if you try changing the previous step to `have h4 : y ∉ B := h2 y _`, you'll get a red squiggle under the blank, and the error message in the Infoview pane will say `don't know how to synthesize placeholder`. In other words, Lean was unable to figure out how to fill in the blank in this case. In future proofs you might try replacing some expressions with blanks to get a feel for what Lean can and cannot figure out for itself.
Continuing with the proof, we see that we're almost done, because we can combine `h4` and `h5` to reach our goal. To see how, we first write out the definition of `h5`.
::: {.inout}
::: {.inpt}
```lean
example (U : Type) (A B C : Set U) (h1 : A ⊆ B ∪ C)
(h2 : ∀ (x : U), x ∈ A → x ∉ B) : A ⊆ C := by
define --Goal : ∀ ⦃a : U⦄, a ∈ A → a ∈ C
fix y : U
assume h3 : y ∈ A
have h4 : y ∉ B := h2 y h3
define at h1 --h1 : ∀ ⦃a : U⦄, a ∈ A → a ∈ B ∪ C
have h5 : y ∈ B ∪ C := h1 h3
define at h5 --h5 : y ∈ B ∨ y ∈ C
**done::
```
:::
::: {.outpt}
```state
U : Type
A B C : Set U
h1 : ∀ ⦃a : U⦄,
>> a ∈ A → a ∈ B ∪ C
h2 : ∀ x ∈ A, x ∉ B
y : U
h3 : y ∈ A
h4 : y ∉ B
h5 : y ∈ B ∨ y ∈ C
⊢ y ∈ C
```
:::
:::
A conditional law will convert `h5` to `y ∉ B → y ∈ C`, and then modus ponens with `h4` will complete the proof.
::: {.inout}
::: {.inpt}
```lean
example (U : Type) (A B C : Set U) (h1 : A ⊆ B ∪ C)
(h2 : ∀ (x : U), x ∈ A → x ∉ B) : A ⊆ C := by
define --Goal : ∀ ⦃a : U⦄, a ∈ A → a ∈ C
fix y : U
assume h3 : y ∈ A
have h4 : y ∉ B := h2 y h3
define at h1 --h1 : ∀ ⦃a : U⦄, a ∈ A → a ∈ B ∪ C
have h5 : y ∈ B ∪ C := h1 h3
define at h5 --h5 : y ∈ B ∨ y ∈ C
conditional at h5 --h5 : y ∉ B → y ∈ C
show y ∈ C from h5 h4
done
```
:::
::: {.outpt}
```state
No goals
```
:::
:::
Next we turn to strategies for working with existential quantifiers (*HTPI* p. 118).
#### To prove a goal of the form `∃ (x : U), P x`:
::: {.ind}
Find a value of `x`, say `a`, for which you think `P a` is true, and prove `P a`.
:::
This strategy is based on the fact that if you have `a : U` and `h : P a`, then you can infer `∃ (x : U), P x`. Indeed, in this situation the expression `Exists.intro a h` is a Lean term-mode proof of `∃ (x : U), P x`. The name `Exists.intro` indicates that this is a rule for introducing an existential quantifier.
Note that, as with the universal instantiation rule, `a` here can be any expression denoting an object of type `U`; it need not be simply a variable. For example, if `A` and `B` have type `Set U`, `F` has type `Set (Set U)`, and you have a given `h : A ∪ B ∈ F`, then `Exists.intro (A ∪ B) h` is a proof of `∃ (x : Set U), x ∈ F`.
As suggested by the strategy above, we will often want to use the `Exists.intro` rule in situations in which our goal is `∃ (x : U), P x` and we have an object `a` of type `U` that we think makes `P a` true, but we don't yet have a proof of `P a`. In that situation we can use the tactic `apply Exists.intro a _`. Recall that the `apply` tactic asks Lean to figure out what to put in the blank to turn `Exists.intro a _` into a proof of the goal. Lean will figure out that what needs to go in the blank is a proof of `P a`, so it sets `P a` to be the goal. In other words, the tactic `apply Exists.intro a _` has the following effect on the tactic state:
::: {.lftrt}
::: {.bef}
```state
>> ⋮
a : U
⊢ ∃ (x : U), P x
```
:::
::: {.aft}
```state
>> ⋮
a : U
⊢ P a
```
:::
:::
Our strategy for using an existential given is a rule that is called *existential instantiation* in *HTPI* (*HTPI* p. 120):
#### To use a given of the form `∃ (x : U), P x`:
::: {.ind}
Introduce a new variable, say `u`, into the proof to stand for an object of type `U` for which `P u` is true.
:::
Suppose that, in a Lean proof, you have `h : ∃ (x : U), P x`. To apply the existential instantiation rule, you would use the tactic `obtain (u : U) (h' : P u) from h`. This tactic introduces into the tactic state both a new variable `u` of type `U` and also the identifier `h'` for the new given `P u`. Note that `h` can be any proof of a statement of the form `∃ (x : U), P x`; it need not be just a single identifier.
Often, if your goal is an existential statement `∃ (x : U), P x`, you won't be able to use the strategy above for existential goals right away, because you won't know what object `a` to use in the tactic `apply Exists.intro a _`. You may have to wait until a likely candidate for `a` pops up in the course of the proof. On the other hand, it is usually best to use the `obtain` tactic right away if you have an existential given. This is illustrated in our next example.
::: {.inout}
::: {.inpt}
```lean
example (U : Type) (P Q : Pred U)
(h1 : ∀ (x : U), ∃ (y : U), P x → ¬ Q y)
(h2 : ∃ (x : U), ∀ (y : U), P x → Q y) :
∃ (x : U), ¬P x := by
**done::
```
:::
::: {.outpt}
```state
U : Type
P Q : Pred U
h1 : ∀ (x : U), ∃ (y : U),
>> P x → ¬Q y
h2 : ∃ (x : U), ∀ (y : U),
>> P x → Q y
⊢ ∃ (x : U), ¬P x
```
:::
:::
The goal is the existential statement `∃ (x : U), ¬P x`, and our strategy for existential goals says that we should try to find an object `a` of type `U` that we think would make the statement `¬P a` true. But we don't have any objects of type `U` in the tactic state, so it looks like we can't use that strategy yet. Similarly, we can't use the given `h1` yet, since we have nothing to plug in for `x` in `h1`. However, `h2` is an existential given, and we can use it right away.
::: {.inout}
::: {.inpt}
```lean
example (U : Type) (P Q : Pred U)
(h1 : ∀ (x : U), ∃ (y : U), P x → ¬ Q y)
(h2 : ∃ (x : U), ∀ (y : U), P x → Q y) :
∃ (x : U), ¬P x := by
obtain (a : U)
(h3 : ∀ (y : U), P a → Q y) from h2
**done::
```
:::
::: {.outpt}
```state
U : Type
P Q : Pred U
h1 : ∀ (x : U), ∃ (y : U),
>> P x → ¬Q y
h2 : ∃ (x : U), ∀ (y : U),
>> P x → Q y
a : U
h3 : ∀ (y : U), P a → Q y
⊢ ∃ (x : U), ¬P x
```
:::
:::
Now that we have `a : U`, we can apply universal instantiation to `h1`, plugging in `a` for `x`.