miscelleaneous

Random Lean experiments

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
  25. 25
  26. 26
  27. 27
  28. 28
  29. 29
  30. 30
  31. 31
  32. 32
  33. 33
  34. 34
  35. 35
  36. 36
  37. 37
  38. 38
  39. 39
  40. 40
  41. 41
  42. 42
  43. 43
  44. 44
  45. 45
  46. 46
  47. 47
  48. 48
  49. 49
  50. 50
  51. 51
  52. 52
  53. 53
  54. 54
  55. 55
  56. 56
  57. 57
  58. 58
  59. 59
  60. 60
  61. 61
  62. 62
  63. 63
  64. 64
  65. 65
  66. 66
  67. 67
  68. 68
  69. 69
  70. 70
  71. 71
  72. 72
  73. 73
  74. 74
  75. 75
  76. 76
  77. 77
  78. 78
  79. 79
  80. 80
  81. 81
  82. 82
  83. 83
  84. 84
  85. 85
  86. 86
  87. 87
  88. 88
  89. 89
  90. 90
  91. 91
  92. 92
  93. 93
  94. 94
  95. 95
  96. 96
  97. 97
  98. 98
  99. 99
  100. 100
  101. 101
  102. 102
  103. 103
  104. 104
  105. 105
  106. 106
  107. 107
  108. 108
  109. 109
  110. 110
  111. 111
  112. 112
  113. 113
  114. 114
  115. 115
  116. 116
  117. 117
  118. 118
  119. 119
  120. 120
  121. 121
  122. 122
  123. 123
  124. 124
  125. 125
  126. 126
  127. 127
  128. 128
  129. 129
  130. 130
  131. 131
  132. 132
  133. 133
  134. 134
  135. 135
  136. 136
  137. 137
  138. 138
  139. 139
  140. 140
  141. 141
  142. 142
  143. 143
  144. 144
  145. 145
  146. 146
  147. 147
  148. 148
  149. 149
  150. 150
  151. 151
  152. 152
  153. 153
  154. 154
  155. 155
  156. 156
  157. 157
  158. 158
  159. 159
  160. 160
  161. 161
  162. 162
  163. 163
  164. 164
  165. 165
  166. 166
  167. 167
  168. 168
  169. 169
  170. 170
  171. 171
  172. 172
  173. 173
  174. 174
  175. 175
  176. 176
  177. 177
  178. 178
  179. 179
  180. 180
  181. 181
  182. 182
  183. 183
  184. 184
  185. 185
  186. 186
  187. 187
  188. 188
  189. 189
  190. 190
  191. 191
  192. 192
  193. 193
  194. 194
  195. 195
  196. 196
  197. 197
  198. 198
  199. 199
  200. 200
  201. 201
  202. 202
  203. 203
  204. 204
  205. 205
  206. 206
  207. 207
  208. 208
  209. 209
  210. 210
  211. 211
  212. 212
  213. 213
  214. 214
  215. 215
  216. 216
  217. 217
  218. 218
  219. 219
  220. 220
  221. 221
  222. 222
  223. 223
  224. 224
  225. 225
  226. 226
  227. 227
  228. 228
  229. 229
  230. 230
  231. 231
  232. 232
  233. 233
  234. 234
  235. 235
  236. 236
  237. 237
  238. 238
  239. 239
  240. 240
  241. 241
  242. 242
  243. 243
  244. 244
  245. 245
  246. 246
  247. 247
  248. 248
  249. 249
  250. 250
  251. 251
  252. 252
  253. 253
  254. 254
  255. 255
  256. 256
  257. 257
  258. 258
  259. 259
  260. 260
  261. 261
  262. 262
  263. 263
  264. 264
  265. 265
  266. 266
  267. 267
  268. 268
  269. 269
  270. 270
  271. 271
  272. 272
  273. 273
  274. 274
  275. 275
  276. 276
  277. 277
  278. 278
  279. 279
  280. 280
  281. 281
  282. 282
  283. 283
  284. 284
  285. 285
  286. 286
  287. 287
  288. 288
  289. 289
  290. 290
  291. 291
  292. 292
  293. 293
  294. 294
  295. 295
  296. 296
  297. 297
  298. 298
  299. 299
  300. 300
  301. 301
  302. 302
  303. 303
  304. 304
  305. 305
  306. 306
  307. 307
  308. 308
  309. 309
  310. 310
  311. 311
  312. 312
  313. 313
  314. 314
  315. 315
  316. 316
  317. 317
  318. 318
  319. 319
  320. 320
  321. 321
  322. 322
  323. 323
  324. 324
  325. 325
  326. 326
  327. 327
  328. 328
  329. 329
  330. 330
  331. 331
  332. 332
  333. 333
  334. 334
  335. 335
  336. 336
  337. 337
  338. 338
  339. 339
  340. 340
  341. 341
  342. 342
  343. 343
  344. 344
  345. 345
  346. 346
  347. 347
  348. 348
  349. 349
  350. 350
  351. 351
  352. 352
  353. 353
  354. 354
  355. 355
  356. 356
  357. 357
  358. 358
  359. 359
  360. 360
  361. 361
  362. 362
  363. 363
  364. 364
  365. 365
  366. 366
  367. 367
  368. 368
  369. 369
  370. 370
  371. 371
  372. 372
  373. 373
  374. 374
  375. 375
  376. 376
  377. 377
  378. 378
  379. 379
  380. 380
  381. 381
  382. 382
  383. 383
  384. 384
  385. 385
  386. 386
  387. 387
  388. 388
  389. 389
  390. 390
  391. 391
  392. 392
  393. 393
  394. 394
  395. 395
  396. 396
  397. 397
  398. 398
  399. 399
  400. 400
  401. 401
  402. 402
  403. 403
  404. 404
  405. 405
  406. 406
  407. 407
  408. 408
  409. 409
  410. 410
  411. 411
  412. 412
  413. 413
  414. 414
  415. 415
  416. 416
  417. 417
  418. 418
  419. 419
  420. 420
  421. 421
  422. 422
  423. 423
  424. 424
  425. 425
  426. 426
  427. 427
  428. 428
  429. 429
  430. 430
  431. 431
  432. 432
  433. 433
  434. 434
  435. 435
  436. 436
  437. 437
  438. 438
  439. 439
  440. 440
  441. 441
  442. 442
  443. 443
  444. 444
  445. 445
  446. 446
  447. 447
  448. 448
  449. 449
  450. 450
  451. 451
  452. 452
  453. 453
  454. 454
  455. 455
  456. 456
  457. 457
  458. 458
  459. 459
  460. 460
  461. 461
  462. 462
  463. 463
  464. 464
  465. 465
  466. 466
  467. 467
  468. 468
  469. 469
  470. 470
  471. 471
  472. 472
  473. 473
  474. 474
  475. 475
  476. 476
  477. 477
  478. 478
  479. 479
  480. 480
  481. 481
  482. 482
  483. 483
  484. 484
  485. 485
  486. 486
  487. 487
  488. 488
  489. 489
  490. 490
  491. 491
  492. 492
  493. 493
  494. 494
  495. 495
  496. 496
  497. 497
  498. 498
  499. 499
  500. 500
  501. 501
  502. 502
  503. 503
  504. 504
  505. 505
  506. 506
  507. 507
  508. 508
  509. 509
  510. 510
  511. 511
  512. 512
  513. 513
  514. 514
  515. 515
  516. 516
  517. 517
  518. 518
  519. 519
  520. 520
  521. 521
  522. 522
  523. 523
  524. 524
  525. 525
  526. 526
  527. 527
  528. 528
  529. 529
  530. 530
  531. 531
  532. 532
  533. 533
  534. 534
  535. 535
  536. 536
  537. 537
  538. 538
  539. 539
  540. 540
  541. 541
  542. 542
  543. 543
  544. 544
  545. 545
  546. 546
  547. 547
  548. 548
  549. 549
  550. 550
  551. 551
  552. 552
  553. 553
  554. 554
  555. 555
  556. 556
  557. 557
  558. 558
  559. 559
  560. 560
  561. 561
  562. 562
  563. 563
  564. 564
  565. 565
  566. 566
  567. 567
  568. 568
  569. 569
  570. 570
  571. 571
  572. 572
  573. 573
  574. 574
  575. 575
  576. 576
  577. 577
  578. 578
  579. 579
  580. 580
  581. 581
  582. 582
  583. 583
  584. 584
  585. 585
  586. 586
  587. 587
  588. 588
  589. 589
  590. 590
  591. 591
  592. 592
  593. 593
  594. 594
  595. 595
  596. 596
  597. 597
  598. 598
  599. 599
  600. 600
  601. 601
  602. 602
  603. 603
  604. 604
  605. 605
  606. 606
  607. 607
  608. 608
  609. 609
  610. 610
  611. 611
  612. 612
  613. 613
  614. 614
  615. 615
  616. 616
  617. 617
  618. 618
  619. 619
  620. 620
  621. 621
  622. 622
  623. 623
  624. 624
  625. 625
  626. 626
  627. 627
  628. 628
  629. 629
  630. 630
  631. 631
  632. 632
  633. 633
  634. 634
  635. 635
  636. 636
  637. 637
  638. 638
  639. 639
  640. 640
  641. 641
  642. 642
  643. 643
  644. 644
  645. 645
  646. 646
  647. 647
  648. 648
  649. 649
  650. 650
  651. 651
  652. 652
  653. 653
  654. 654
  655. 655
  656. 656
  657. 657
  658. 658
  659. 659
  660. 660
  661. 661
  662. 662
import GlimpseOfLean.Library.Short

/- # A shorter Glimpse of Lean

This file is the short track of the Glimpse of Lean project. It is meant for people
who want to spend two hours discovering Lean. The hope is that two hours are
enough to reach at least the first exercises about limits of sequences of real numbers.
If you go faster or have a bit more time, you can try to do all those exercises.

Of course the proofs are not always the most idiomatic ones since we aim to keep
the amount of things to explain very low, while still giving a glimpse of how Lean
sees mathematical proofs.

Every command that is typed to make progress in the proof is called a “tactic”.
We will learn about a dozen of them. For each tactic, we will see a couple of
examples and then you will have exercises to do. The goal of each exercise is
to replace the word `sorry` by a sequence of tactics that bring Lean to report
there are no remaining goal, without reporting any error along the way.
-/

/- ## Computing

We start with basic computations using real numbers. We could play the micro-management
game invoking properties like commutatitivity and associativity of addition.
But we can also ask Lean to take care of any proof that only uses those properties
using the `ring` tactic.
By “only those properties” we mean in particular it won’t use any assumption
specific to the proof at hand.

The word `ring` refers to the abstract mathematical definition that encapsulates the
basic properties of addition, subtraction and multiplication. Knowing about this
abstract algebra is not required here.
-/

example (a b : ) : (a+b)^2 = a^2 + 2*a*b + b^2 := by
  ring

/-
Now it’s your turn: replace the word sorry with the relevant tactic to
finish the exercise.
-/

example (a b : ) : (a+b)*(a-b) = a^2 - b^2 := by
  ring

/-
Our next tactic is the `congr` tactic (`congr` stands for “congruence”).
It tries to prove equalities by comparing both sides and creating new goals each time it
sees some mismatch.
-/

example (a b : ) (f :   ) : f ((a+b)^2) = f (a^2 + 2*a*b + b^2) := by
  congr
  -- `congr` recognized the pattern `f _ = f _` and created a new goal
  -- about the mismatching part, namely the arguments supplied to `f`.
  ring

/-
Try it on the next example.
-/

example (a b : ) (f :   ) : f ((a+b)^2 - 2*a*b) = f (a^2 + b^2) := by
  congr
  ring

/-
When there are several mismatches, `congr` creates several goals.
Sometimes it gets over-enthusastic and matches “too much”. For instance, if the goal
is `f (a+b) = f (b+a)` then `congr` will recognize the common pattern
`f (_ + _) = f (_ + _)` and create two goals: `a = b` and `b = a`.
This can be controlled in various ways. The most basic one is enough for us: we can limit
the number of function application layers by putting a number after `congr`.
In the example the two functions that are applied are `f` and addition, and we want to
go only through the application of `f`.
-/

example (a b : ) (f :   ) : f (a + b) = f (b + a) := by
  congr 1 -- try removing that 1 or increasing it to see the issue.
  ring

/-
Actually `congr` does more than finding mismatches, it also try to resolve them
using assumptions. In the next example, `congr` creates the goal `a + b = c` by
matching, and then immediately proves it by noticing and using assumption `h`.
-/

example (a b c : ) (h : a + b = c) (f :   ) : f (a + b) = f c := by
  congr

/-
The tactics `ring` and `congr` are the basic tools we will use to compute.
But sometimes we need to chain several computation steps.
This is the job of the `calc` tactic.

In the following example, it helps to carefully consider the tactic state
displayed after each `by` after the `calc` line.
-/

example (a b c d : ) (h : c = b*a - d) (h' : d = a*b) : c = 0 := by
  calc
    c = b*a - d   := by congr
    _ = b*a - a*b := by congr
    _ = 0         := by ring

/-
Note that each `_` stands for the right-hand side of the previous line.
So we are really proving a sequence of equalities, and then the `calc` tactic
takes care of applying transitivity of equality (or equalities and inequalities
when proving inequalities). Each proof in this sequence is introduced by `:= by`.

The indentation rules for `calc` are a bit subtle, especially when there
are other tactics after `calc`. Be careful to always align the `_`.
Aligning the equality signs and the `:=` signs looks nice but is not mandatory.

Laying out those calculation steps and copy-pasting the common pieces can be a
bit tedious on larger examples, but we get help from the calc widget, as can be
seen on the video at

https://www.imo.universite-paris-saclay.fr/~patrick.massot/calc_widget.webm

As you can see there, the `calc?` tactic propose to create a one-line compution,
and then putting the cursor after `:= by` allows to select subterms to replace in
a new calculation step.

Note that subterm selection is done using Shift-click.
There is no “click and move the cursor and then stop clicking”.
This is different from regular selection of text in your editor or browser.
-/

example (a b c : ) (h : a = -b) (h' : b + c = 0) : b*(a - c) = 0 := by
  calc
    b*(a - c) = b*(-b - c) := by congr
    _ = -b*(b + c) := by ring
    _ = -b*0 := by congr
    _ = 0 := by ring

/-
We can also handle inequalities using `gcongr` (which stands for “generalized congruence”)
instead of `congr`.
-/

example (a b : ) (h : a  2*b) : a + b  3*b := by
  calc
    a + b  2*b + b := by gcongr
    _     = 3*b     := by ring

example (a b : ) (h : b  a) : a + b  2*a := by
  calc
    a + b  a + a := by gcongr
    _ = 2*a := by ring

/-
The last tactic you will use in computation is the simplifier `simp`. It will
repeatedly apply a number of lemmas that are marked as simplification lemmas.
For instance the proof below simplifies `x - x` to `0` and then `|0|` to `0`.
-/

example (x : ) : |x - x| = 0 := by
  simp


/- ## Universal quantifiers and implications

Now let’s learn about the `∀` quantifier.

Let `P` be a predicate on a type `X`. This means for every mathematical
object `x` with type `X`, we get a mathematical statement `P x`.

Lean sees a proof `h` of `∀ x, P x` as a function sending any `x : X` to
a proof `h x` of `P x`.
This already explains the main way to use an assumption or lemma which
starts with a `∀`: we can simply feed it an element of the relevant `X`.

Note we don't need to spell out `X` in the expression `∀ x, P x`
as long as the type of `P` is clear to Lean, which can then infer the type of `x`.

Let's define a predicate to play with `∀`. In that example we have a function
`f : ℝ → ℝ` at hand, and `X = ℝ` (this value of `X` is inferred from the fact
that we feed `x` to `f` which goes from `ℝ` to `ℝ`).
-/

def even_fun (f :   ) :=  x, f (-x) = f x

/-
In the above definition, note how there is no parentheses in `f x`.
This is how Lean denotes function application. In `f (-x)` there are parentheses
to prevent Lean from seeing a subtraction of `f` and `x` (which would make no sense).
Also be careful the space between `f` and `(-x)` is mandatory.

The `apply` tactic can be used to specialize universally quantified statements.
-/

example (f :   ) (hf : even_fun f) : f (-3) = f 3 := by
  apply hf 3

/-
Fortunately, Lean is willing to work for us, so we can leave out the `3` and
let the `apply` tactic compare the goal with the assumption
and decide to specialize it to `x = 3`.
-/

example (f :   ) (hf : even_fun f) : f (-3) = f 3 := by
  apply hf

/-
In the following exercise, you get to choose whether you want help from Lean
or do all the work.
-/
example (f :   ) (hf : even_fun f) : f (-5) = f 5 := by
  apply hf

/-
This was about using a `∀`. Let us now see how to prove a `∀`.

In order to prove `∀ x, P x`, we use `intro x₀` to fix an arbitrary object
with type `X`, and call it `x₀` (`intro` stands for “introduce”).
Note we don’t have to use the letter `x₀`, any name will work.

We will prove that the real cosine function is even. After introducing some `x₀`,
the simplifier tactic can finish the proof. Remember to carefully inspect the goal
at the beginning of each line.
-/

open Real in -- this line insists that we mean real cos, not the complex numbers one.
example : even_fun cos := by
  intro x₀
  simp

/-
In order to get slightly more interesting examples, we will both use and prove
some universally quantified statements.

In the next proof, we also take the opportunity to introduce the
`unfold` tactic, which simply unfolds definitions. Here this is purely
for didactic reason, Lean doesn't need those `unfold` invocations.
-/

example (f g :   ) (hf : even_fun f) (hg : even_fun g) : even_fun (f + g) := by
  -- Our assumption on that f is even means ∀ x, f (-x) = f x
  unfold even_fun at hf -- note how `hf` changes after this line
  -- and the same for g
  unfold even_fun at hg
  -- We need to prove ∀ x, (f+g)(-x) = (f+g)(x)
  unfold even_fun
  -- Let x₀ be any real number
  intro x₀
  -- and let's compute
  calc
    (f + g) (-x₀) = f (-x₀) + g (-x₀)  := by simp
    _             = f x₀ + g (-x₀)     := by congr 1; apply hf
  -- put you cursor between `;` and `apply` in the previous line to see the intermediate goal
    _             = f x₀ + g x₀        := by congr 1; apply hg
    _             = (f + g) x₀         := by simp


/-
Tactics like `congr` and `ring` will not unfold definitions that appear in the goal.
This is why the first computation line is necessary, although it only unfolds a definition.
The last line is not necessary however, since it only proves
something that is true by definition, and is not followed by any other tactic.

Also note that `congr` can generate several goals so we don’t have to call it twice.

Hence we can compress the above proof to:
-/

example (f g :   )  (hf : even_fun f) (hg : even_fun g) : even_fun (f + g) := by
  intro x₀
  calc
    (f + g) (-x₀) = f (-x₀) + g (-x₀)  := by simp
    _             = f x₀ + g x₀        := by congr 1; apply hf; apply hg

/-
If you would rather uncompress the proof, you can use the `specialize` tactic to
specialize a universally quantified assumption before using it.
-/

example (f g :   ) (hf : even_fun f) (hg : even_fun g) : even_fun (f + g) := by
  -- Let x₀ be any real number
  intro x₀
  specialize hf x₀ -- hf is now only about the x₀ we just introduced
  specialize hg x₀ -- hg is now only about the x₀ we just introduced
  -- and let's compute
  -- (note how `congr` now finds assumptions finishing those steps)
  calc
    (f + g) (-x₀) = f (-x₀) + g (-x₀)  := by simp
    _             = f x₀ + g (-x₀)     := by congr
    _             = f x₀ + g x₀        := by congr
    _             = (f + g) x₀         := by simp

/-
Now let's practice. If you need to learn how to type a unicode symbol, you can
put your mouse cursor above the symbol and wait for one second.
Recall you can set a depth limit in `congr` by giving it a number as in `congr 1`.

Note also that you can call your arbitrary real number `x` instead of `x₀` if
you want to save some typing. We called it `x₀` only to emphasize it doesn’t
need to be the same notation as in the statement.
-/

example (f g :   ) (hf : even_fun f) : even_fun (g  f) := by
  intro x
  specialize hf x
  calc
    (g  f) (-x) = g (f (-x)) := by simp
    _            = g (f x)    := by congr
    _            = (g  f) x  := by simp


/-
Let's now combine the universal quantifier with implication.

In the next definitions, note how `∀ x₁, ∀ x₂, ...` is abbreviated to `∀ x₁ x₂, ...`.
-/

def non_decreasing (f :   ) :=  x₁ x₂, x₁  x₂  f x₁  f x₂

def non_increasing (f :   ) :=  x₁ x₂, x₁  x₂  f x₁  f x₂

/-
Note how Lean uses a single arrow `→` to denote implication. This is the same arrow
as in `f : ℝ → ℝ`. Indeed Lean sees a proof of the implication `P → Q` as a
function from proofs of `P` to proofs of `Q`.

So an assumption `hf : non_decreasing f` is a function that takes as input two numbers
and a inequality between them and outputs an inequality between their images under `f`.
-/

example (f :   ) (hf : non_decreasing f) (x₁ x₂ : ) (hx : x₁  x₂) : f x₁  f x₂ := by
  apply hf x₁ x₂ hx

/-
We can ask Lean to work more for us, as in the following example:
-/

example (f :   ) (hf : non_decreasing f) (x₁ x₂ : ) (hx : x₁  x₂) : f x₁  f x₂ := by
  apply hf -- Lean compares the goal with the assumption `hf`. It recognizes that `hf`
           -- needs to be specialized to the numbers `x₁` and `x₂` that are given, to get
           -- the implication `x₁ ≤ x₂ → f x₁ ≤ f x₂` and then asks for a proof of the
           -- premise `x₁ ≤ x₂`
  apply hx -- Our assumption hx is such a proof

/-
Note that the tactic `apply` does not mean anything vague like “make something
of that expression somehow”. It asks for an input that is either a full proof
as in the first example, or a proof of statement involving universal
quantifiers and implications in front of some statement that can be specialized
to the current goal (as in the previous example).

In this very simple example, we did not gain much. Now compare the following
two proofs of the same statement.
-/

example (f g :   ) (hf : non_decreasing f) (hg : non_decreasing g) :
    non_decreasing (g  f) := by
  intro x₁ x₂ hx -- Note how `intro` is also introducing the assumption `h : x₁ ≤ x₂`
  apply hg (f x₁) (f x₂) (hf x₁ x₂ hx)

example (f g :   ) (hf : non_decreasing f) (hg : non_decreasing g) :
    non_decreasing (g  f) := by
  intro x₁ x₂ h
  apply hg
  apply hf
  apply h

/-
Take some time to understand how, in the second proof, Lean saves us the
trouble of finding the relevant pairs of numbers and also nicely cuts the proof
into pieces. You can choose your way in the following variation.
-/

example (f g :   ) (hf : non_decreasing f) (hg : non_increasing g) :
    non_increasing (g  f) := by
  intro x₁ x₂ hx
  apply hg
  apply hf
  apply hx

/-
At this stage you should feel that such a proof actually doesn’t require any
thinking at all. And indeed Lean can easily handle the full proof in one tactic
(but we won’t need this here).

We can also use the `specialize` tactic to feed arguments to an assumption
before using it, as we saw with the example of even functions.
-/

example (f g :   ) (hf : non_decreasing f) (hg : non_decreasing g) :
    non_decreasing (g + f) := by
  intro x₁ x₂ h
  specialize hf x₁ x₂ h
  specialize hg x₁ x₂ h
  calc
    (g + f) x₁ = g x₁ + f x₁ := by simp
    _           g x₂ + f x₂ := by gcongr
    _          = (g + f) x₂  := by simp


/- # Finding lemmas

Lean’s mathematical library contains many useful facts, and remembering all of
them by name is infeasible. We already saw the simplifier tactic `simp` which
applies many lemmas without using their names.

Use `simp` to prove the following. Note that `X : Set ℝ` means that `X` is a
set containing (only) real numbers. -/

example (x : ) (X Y : Set ) (hx : x  X) : x  (X  Y)  (X \ Y) := by
  simp
  apply hx

/-
The `apply?` tactic will find lemmas from the library and tell you their names.
It creates a suggestion below the goal display. You can click on this suggestion
to edit your code.
Use `apply?` to find the lemma that every continuous function with compact support
has a global minimum. -/

example (f :   ) (hf : Continuous f) (h2f : HasCompactSupport f) :  x,  y, f x  f y := by
  exact Continuous.exists_forall_le_of_hasCompactSupport hf h2f

/- ## Existential quantifiers

In order to prove `∃ x, P x`, we give some `x₀` that works with `use x₀` and
then prove `P x₀`. This `x₀` can be an object from the local context
or a more complicated expression. In the example below, the property
to check after `use` is true by definition so the proof is over.
-/
example :  n : , 8 = 2*n := by
  use 4

/-
In order to use `h : ∃ x, P x`, we use the `rcases` tactic to fix
one `x₀` that works.

Again `h` can come straight from the local context or can be a more
complicated expression.

The examples will use divisibility in `ℤ` (beware the `∣` symbol which is
not ASCII but a unicode symbol). The angle brackets appearing after the
word `with` are also unicode symbols.
If your keyboard is not configured to directly type those symbols, you can
put your mouse cursor above the symbol and wait for one second to see how
to type them in this editor.

-/

example (a b c : ) (h₁ : a  b) (h₂ : b  c) : a  c := by
  rcases h₁ with k, hk -- we fix some `k` such that `b = a * k`
  rcases h₂ with l, hl -- we fix some `l` such that `c = b * l`
  -- Since `a ∣ c` means `∃ k, c = a*k`, we need the `use` tactic.
  use k*l
  calc
    c = b*l     := by congr
    _ = (a*k)*l := by congr
    _ = a*(k*l) := by ring

example (a b c : ) (h₁ : a  b) (h₂ : a  c) : a  b + c := by
  rcases h₁ with k, hk
  rcases h₂ with l, hl
  use k + l
  rw [hk]
  rw [hl]
  exact Eq.symm (Int.mul_add a k l)


/-
## Conjunctions

We now explain how to handle one more logical gadget: conjunction.

Given two statements `P` and `Q`, the conjunction `P ∧ Q` is the statement that
`P` and `Q` are both true (`∧` is sometimes called the “logical and”).

In order to prove `P ∧ Q` we use the `constructor` tactic that splits the goal
into proving `P` and then proving `Q`.

In order to use a proof `h` of `P ∧ Q`, we use `h.1` to get a proof of `P`
and `h.2` to get a proof of `Q`. We can also use `rcases h with ⟨hP, hQ⟩` to
get `hP : P` and `hQ : Q`.

Let us see both in action in a very basic logic proof: let us deduce `Q ∧ P`
from `P ∧ Q`.
-/

example (P Q : Prop) (h : P  Q) : Q  P := by
  constructor
  apply h.2
  apply h.1

/-
## Limits

We learned enough tactics to manipulate a definition involving both kinds of quantifiers:
limits of sequences of real numbers.

-/

/-- A sequence `u` converges to a limit `l` if the following holds. -/
def seq_limit (u :   ) (l : ) :=  ε > 0,  N,  n  N, |u n - l|  ε
apply?
/-
Let’s see an example manipulating this definition and using a lot of the tactics
we’ve seen above: if `u` is constant with value `l` then `u` tends to `l`.

Remember `apply?` can find lemmas whose name you don’t want to remember, such as
the lemma saying that positive implies non-negative. -/
example (h :  n, u n = l) : seq_limit u l := by
  intro ε ε_pos
  use 0
  intro n hn
  calc |u n - l| = |l - l| := by congr; apply h
    _            = 0       := by simp
    _             ε       := by apply?

/- When dealing with absolute values, we'll use the lemma:

`abs_le {x y : ℝ} : |x| ≤ y ↔ -y ≤ x ∧ x ≤ y`

When dealing with max, we’ll use

`ge_max_iff (p q r) : r ≥ max p q ↔ r ≥ p ∧ r ≥ q`

The way we will use those lemmas is with the rewriting command
`rw`. Let's see an example.
In that example, we kept `apply?` instead of accepting its suggestions in order to emphasize
there is no need to remember those lemma names.
Note also how we can use `by` anywhere to start proving something using tactics. In the example
below, we use it to prove `ε/2 > 0` from our assumption `ε > 0`.
-/

-- If `u` tends to `l` and `v` tends `l'` then `u+v` tends to `l+l'`
example (hu : seq_limit u l) (hv : seq_limit v l') :
    seq_limit (u + v) (l + l') := by
  intro ε ε_pos
  rcases hu (ε/2) (by apply?) with N₁, hN₁
  rcases hv (ε/2) (by apply?) with N₂, hN₂
  use max N₁ N₂
  intro n hn
  rw [ge_max_iff] at hn -- Note how hn changes from `n ≥ max N₁ N₂` to `n ≥ N₁ ∧ n ≥ N₂`
  specialize hN₁ n hn.1
  specialize hN₂ n hn.2
  calc
    |(u + v) n - (l + l')| = |u n + v n - (l + l')|   := by simp
    _ = |(u n - l) + (v n - l')|                      := by congr; ring
    _  |u n - l| + |v n - l'|                        := by apply?
    _  ε/2 + ε/2                                     := by gcongr
    _ = ε                                             := by simp


/- Let's do something similar: the squeezing theorem using both `ge_max_iff` and `abs_le`.
You will probably want to rewrite using `abs_le` in several assumptions as well as in the
goal. You can use `rw [abs_le] at *` for this. -/
example (hu : seq_limit u l) (hw : seq_limit w l) (h :  n, u n  v n) (h' :  n, v n  w n) :
    seq_limit v l := by
  intro ε ε_pos
  rcases hu ε ε_pos with N, hN
  rcases hw ε ε_pos with N', hN'
  use max N N'
  intro n hn
  rw [ge_max_iff] at hn
  specialize hN n hn.1
  specialize hN' n hn.2
  specialize h n
  specialize h' n
  rw [abs_le] at *
  constructor
  calc
    -ε  u n - l := by apply hN.1
    _  v n - l  := by gcongr
  calc
    v n - l  w n - l := by gcongr
          _  ε := by apply hN'.2


/- In the next exercise, we'll use

`eq_of_abs_sub_le_all (x y : ℝ) : (∀ ε > 0, |x - y| ≤ ε) → x = y`

as the first step.
-/

-- A sequence admits at most one limit. You will be able to use that lemma in the following
-- exercises.
lemma uniq_limit (hl : seq_limit u l) (hl' : seq_limit u l') : l = l' := by
  apply eq_of_abs_sub_le_all
  intro ε ε_pos
  rcases hl ε ε_pos with N, hN
  rcases hl' ε ε_pos with N', hN'
  -- use max N N'
  -- intro n hn



/-

## Subsequences

We will now play with subsequences.

The new definition we will use is that `φ : ℕ → ℕ` is an extraction
if it is (strictly) increasing.
-/

def extraction (φ :   ) :=  n m, n < m  φ n < φ m

/-
In the following, `φ` will always denote a function from `ℕ` to `ℕ`.

The next lemma is proved by an easy induction, but we haven't seen induction
in this tutorial. If you did the natural number game then you can delete
the proof below and try to reconstruct it. Otherwise you can simply take a quick look
at how proofs by induction look like (but we won’t need any other one here).
-/
/-- An extraction is greater than id -/
lemma id_le_extraction' : extraction φ   n, n  φ n := by
  intro hyp n
  induction n with
  | zero =>  apply?
  | succ n ih => exact Nat.succ_le_of_lt (by
      calc n  φ n := ih
        _    < φ (n + 1) := by apply hyp; apply?)

/-
In the exercise, we use `∃ n ≥ N, ...` which is the abbreviation of
`∃ n, n ≥ N ∧ ...`.

Don’t forget to move the cursor around to see what each `apply?` is proving.
-/

/-- Extractions take arbitrarily large values for arbitrarily large
inputs. -/
lemma extraction_ge : extraction φ   N N',  n  N', φ n  N := by
  sorry

/-- A real number `a` is a cluster point of a sequence `u`
if `u` has a subsequence converging to `a`. -/
def cluster_point (u :   ) (a : ) :=  φ, extraction φ  seq_limit (u  φ) a

/-- If `a` is a cluster point of `u` then there are values of
`u` arbitrarily close to `a` for arbitrarily large input. -/
lemma near_cluster :
  cluster_point u a   ε > 0,  N,  n  N, |u n - a|  ε := by
  sorry


/-- If `u` tends to `l` then its subsequences tend to `l`. -/
lemma subseq_tendsto_of_tendsto' (h : seq_limit u l) ( : extraction φ) :
  seq_limit (u  φ) l := by
  sorry

/-- If `u` tends to `l` all its cluster points are equal to `l`. -/
lemma cluster_limit (hl : seq_limit u l) (ha : cluster_point u a) : a = l := by
  sorry

/-- `u` is a Cauchy sequence if its values get arbitrarily close for large
enough inputs. -/
def CauchySequence (u :   ) :=
   ε > 0,  N,  p q, p  N  q  N  |u p - u q|  ε

example : ( l, seq_limit u l)  CauchySequence u := by
  sorry