Migrate to lean 4.

finite-set-exercises
Joshua Potter 2023-02-10 14:51:20 -07:00
parent e18b705ad3
commit 5f8cc89727
5 changed files with 750 additions and 838 deletions

View File

@ -1,43 +1,33 @@
/- Exercises 2.10 /- Exercises 2
- -
- Avigad, Jeremy. Theorem Proving in Lean, n.d. - Avigad, Jeremy. Theorem Proving in Lean, n.d.
-/ -/
-- Borrowed from the book.
def double (x : ) : := x + x
def do_twice (f : ) (x : ) : := f (f x)
-- Exercise 1 -- Exercise 1
-- --
-- Define the function `Do_Twice`, as described in Section 2.4. -- Define the function `Do_Twice`, as described in Section 2.4.
section ex_1 namespace ex1
def Do_Twice (f : () → ()) (x : )
: () := def double (x : Nat) := x + x
f (f x) def doTwice (f : Nat → Nat) (x : Nat) : Nat := f (f x)
end ex_1 def doTwiceTwice (f : (Nat → Nat) → (Nat → Nat)) (x : Nat → Nat) := f (f x)
#reduce doTwiceTwice doTwice double 2
end ex1
-- Exercise 2 -- Exercise 2
-- --
-- Define the functions `curry` and `uncurry`, as described in Section 2.4. -- Define the functions `curry` and `uncurry`, as described in Section 2.4.
section ex_2 namespace ex2
def curry (α β γ : Type*) (f : α × β → γ)
: α → β → γ :=
λ α β, f (α, β)
def uncurry (α β γ : Type*) (f : α → β → γ) def curry (f : α × β → γ) : (α → β → γ) :=
: α × β → γ := fun α β => f (α, β)
λ x, f x.1 x.2
end ex_2
-- Borrowed from the book. def uncurry (f : α → β → γ) : (α × β → γ) :=
universe u fun x => f x.1 x.2
constant vec : Type u → → Type u
namespace vec end ex2
constant empty : Π (α : Type u), vec α 0
constant cons : Π (α : Type u) (n : ), α → vec α n → vec α (n + 1)
constant append : Π (α : Type u) (n m : ), vec α m → vec α n → vec α (n + m)
end vec
-- Exercise 3 -- Exercise 3
-- --
@ -48,23 +38,30 @@ end vec
-- implicit arguments for parameters that can be inferred. Declare some -- implicit arguments for parameters that can be inferred. Declare some
-- variables and check some expressions involving the constants that you have -- variables and check some expressions involving the constants that you have
-- declared. -- declared.
section ex_3 namespace ex3
universe u
axiom vec : Type u → Nat → Type u
namespace vec namespace vec
constant add :
Π {α : Type u} {n : }, vec α n → vec α n → vec α n axiom empty : ∀ (α : Type u), vec α 0
constant reverse : axiom cons : ∀ (α : Type u) (n : Nat), α → vec α n → vec α (n + 1)
Π {α : Type u} {n : }, vec α n → vec α n axiom append : ∀ (α : Type u) (n m : Nat), vec α m → vec α n → vec α (n + m)
axiom add : ∀ {α : Type u} {n : Nat}, vec α n → vec α n → vec α n
axiom reverse : ∀ {α : Type u} {n : Nat}, vec α n → vec α n
end vec end vec
-- Check results. -- Check results.
variables a b : vec Prop 1 variable (a b : vec Prop 1)
variables c d : vec Prop 2 variable (c d : vec Prop 2)
#check vec.add a b #check vec.add a b
-- #check vec.add a c -- #check vec.add a c
#check vec.reverse a #check vec.reverse a
end ex_3 end ex3
-- Exercise 4 -- Exercise 4
-- --
@ -74,23 +71,29 @@ end ex_3
-- (using vec) multiplication of a matrix by a vector. Once again, declare some -- (using vec) multiplication of a matrix by a vector. Once again, declare some
-- variables and check some expressions involving the constants that you have -- variables and check some expressions involving the constants that you have
-- declared. -- declared.
constant matrix : Type u → → Type u namespace ex4
section ex_4 universe u
axiom matrix : Type u → Nat → Nat → Type u
namespace matrix namespace matrix
constant add : Π {α : Type u} {m n : }, matrix α m n → matrix α m n → matrix α m n
constant mul : Π {α : Type u} {m n p : }, matrix α m n → matrix α n p → matrix α m p axiom add : ∀ {α : Type u} {m n : Nat},
constant app : Π {α : Type u} {m n : }, matrix α m n → vec α n → vec α m matrix α m n → matrix α m n → matrix α m n
axiom mul : ∀ {α : Type u} {m n p : Nat},
matrix α m n → matrix α n p → matrix α m p
axiom app : ∀ {α : Type u} {m n : Nat},
matrix α m n → ex3.vec α n → ex3.vec α m
end matrix end matrix
variables a b : matrix Prop 5 7 variable (a b : matrix Prop 5 7)
variable c : matrix Prop 7 3 variable (c : matrix Prop 7 3)
variable d : vec Prop 3 variable (d : ex3.vec Prop 3)
#check matrix.add a b #check matrix.add a b
-- #check matrix.add a c -- #check matrix.add a c
#check matrix.mul a c #check matrix.mul a c
#check matrix.app c d #check matrix.app c d
end ex_4 end ex4

View File

@ -1,4 +1,4 @@
/- Exercises 3.7 /- Exercises 3
- -
- Avigad, Jeremy. Theorem Proving in Lean, n.d. - Avigad, Jeremy. Theorem Proving in Lean, n.d.
-/ -/
@ -7,189 +7,153 @@
-- --
-- Prove the following identities, replacing the "sorry" placeholders with -- Prove the following identities, replacing the "sorry" placeholders with
-- actual proofs. -- actual proofs.
section ex_1 namespace ex1
open or open or
variables p q r : Prop variable (p q r : Prop)
-- Commutativity of ∧ and -- Commutativity of ∧ and
example : p ∧ q ↔ q ∧ p := example : p ∧ q ↔ q ∧ p :=
iff.intro Iff.intro
(assume ⟨p, q⟩, ⟨q, p⟩) (fun ⟨hp, hq⟩ => show q ∧ p from ⟨hq, hp⟩)
(assume ⟨q, p⟩, ⟨p, q⟩) (fun ⟨hq, hp⟩ => show p ∧ q from ⟨hp, hq⟩)
example : p q ↔ q p := example : p q ↔ q p :=
iff.intro Iff.intro
(assume h, h.elim (fun h => h.elim Or.inr Or.inl)
(assume hp : p, inr hp) (fun h => h.elim Or.inr Or.inl)
(assume hq : q, inl hq))
(assume h, h.elim
(assume hq : q, inr hq)
(assume hp : p, inl hp))
-- Associativity of ∧ and -- Associativity of ∧ and
example : (p ∧ q) ∧ r ↔ p ∧ (q ∧ r) := example : (p ∧ q) ∧ r ↔ p ∧ (q ∧ r) :=
iff.intro Iff.intro
(assume ⟨⟨p, q⟩, r⟩, ⟨p, q, r⟩) (fun ⟨⟨hp, hq⟩, hr⟩ => ⟨hp, hq, hr⟩)
(assume ⟨p, q, r⟩, ⟨⟨p, q⟩, r⟩) (fun ⟨hp, hq, hr⟩ => ⟨⟨hp, hq⟩, hr⟩)
example : (p q) r ↔ p (q r) := example : (p q) r ↔ p (q r) :=
iff.intro Iff.intro
(assume h₁, h₁.elim (fun h₁ => h₁.elim
(assume h₂, h₂.elim (assume p, inl p) (assume q, inr (inl q))) (fun h₂ => h₂.elim Or.inl (Or.inr ∘ Or.inl))
(assume r, inr (inr r))) (Or.inr ∘ Or.inr))
(assume h₁, h₁.elim (fun h₁ => h₁.elim
(assume p, inl (inl p)) (Or.inl ∘ Or.inl)
(assume h₂, h₂.elim (assume q, inl (inr q)) (assume r, inr r))) (fun h₂ => h₂.elim (Or.inl ∘ Or.inr) Or.inr))
-- Distributivity -- Distributivity
example : p ∧ (q r) ↔ (p ∧ q) (p ∧ r) := example : p ∧ (q r) ↔ (p ∧ q) (p ∧ r) :=
iff.intro Iff.intro
(assume ⟨hp, hqr⟩, hqr.elim (fun ⟨hp, hqr⟩ => hqr.elim (Or.inl ⟨hp, ·⟩) (Or.inr ⟨hp, ·⟩))
(assume hq, inl ⟨hp, hq⟩) (fun h₁ => h₁.elim
(assume hr, inr ⟨hp, hr⟩)) (fun ⟨hp, hq⟩ => ⟨hp, Or.inl hq⟩)
(assume h₁, h₁.elim (fun ⟨hp, hr⟩ => ⟨hp, Or.inr hr⟩))
(assume ⟨hp, hq⟩, ⟨hp, inl hq⟩)
(assume ⟨hp, hr⟩, ⟨hp, inr hr⟩))
example : p (q ∧ r) ↔ (p q) ∧ (p r) := example : p (q ∧ r) ↔ (p q) ∧ (p r) :=
iff.intro Iff.intro
(assume h, h.elim (fun h => h.elim
(assume hp, ⟨inl hp, inl hp⟩) (fun hp => ⟨Or.inl hp, Or.inl hp⟩)
(assume ⟨hq, hr⟩, ⟨inr hq, inr hr⟩)) (fun ⟨hq, hr⟩ => ⟨Or.inr hq, Or.inr hr⟩))
(assume ⟨h₁, h₂⟩, h₁.elim (fun ⟨h₁, h₂⟩ => h₁.elim
(assume hp, inl hp) Or.inl
(assume hq, h₂.elim (assume hp, inl hp) (assume hr, inr ⟨hq, hr⟩))) (fun hq => h₂.elim Or.inl (fun hr => Or.inr ⟨hq, hr⟩)))
-- Other properties -- Other properties
example : (p → (q → r)) ↔ (p ∧ q → r) := example : (p → (q → r)) ↔ (p ∧ q → r) :=
iff.intro Iff.intro
(assume h ⟨hp, hq⟩, h hp hq) (fun h ⟨hp, hq⟩ => h hp hq)
(assume h hp hq, h ⟨hp, hq⟩) (fun h hp hq => h ⟨hp, hq⟩)
example : ((p q) → r) ↔ (p → r) ∧ (q → r) := example : ((p q) → r) ↔ (p → r) ∧ (q → r) :=
iff.intro Iff.intro
(assume h, (fun h =>
have h₁ : p → r, from (assume hp, h (or.inl hp)), have h₁ : p → r := h ∘ Or.inl
have h₂ : q → r, from (assume hq, h (or.inr hq)), have h₂ : q → r := h ∘ Or.inr
⟨h₁, h₂⟩) show (p → r) ∧ (q → r) from ⟨h₁, h₂⟩)
(assume ⟨hpr, hqr⟩, assume hpq, hpq.elim hpr hqr) (fun ⟨h₁, h₂⟩ h => h.elim h₁ h₂)
example : ¬(p q) ↔ ¬p ∧ ¬q := example : ¬(p q) ↔ ¬p ∧ ¬q :=
iff.intro Iff.intro
(assume h, and.intro (fun h => ⟨h ∘ Or.inl, h ∘ Or.inr⟩)
(assume hp, h (inl hp)) (fun h₁ h₂ => h₂.elim (absurd · h₁.left) (absurd · h₁.right))
(assume hq, h (inr hq)))
(assume h₁ h₂, h₂.elim
(assume hp, have np : ¬p, from h₁.left, absurd hp np)
(assume hq, have nq : ¬q, from h₁.right, absurd hq nq))
example : ¬p ¬q → ¬(p ∧ q) := example : ¬p ¬q → ¬(p ∧ q) :=
assume h₁ h₂, fun h₁ h₂ => h₁.elim (absurd h₂.left ·) (absurd h₂.right ·)
h₁.elim
(assume np : ¬p, have hp : p, from h₂.left, absurd hp np)
(assume nq : ¬q, have hq : q, from h₂.right, absurd hq nq)
example : ¬(p ∧ ¬p) := example : ¬(p ∧ ¬p) :=
assume h, fun h => absurd h.left h.right
have hp : p, from h.left,
have np : ¬p, from h.right,
absurd hp np
example : p ∧ ¬q → ¬(p → q) := example : p ∧ ¬q → ¬(p → q) :=
assume ⟨hp, nq⟩ hpq, fun ⟨hp, nq⟩ hpq => absurd (hpq hp) nq
absurd (hpq hp) nq
example : ¬p → (p → q) := example : ¬p → (p → q) :=
assume np hp, fun np hp => absurd hp np
absurd hp np
example : (¬p q) → (p → q) := example : (¬p q) → (p → q) :=
assume npq hp, fun npq hp => npq.elim (absurd hp ·) id
npq.elim
(assume np, absurd hp np)
(assume hq, hq)
example : p false ↔ p := example : p False ↔ p :=
iff.intro Iff.intro (fun hpf => hpf.elim id False.elim) Or.inl
(assume hpf, hpf.elim
(assume hp, hp)
(assume hf, false.elim hf))
(assume hp, inl hp)
example : p ∧ false ↔ false := example : p ∧ False ↔ False :=
iff.intro Iff.intro (fun ⟨_, hf⟩ => hf) False.elim
(assume ⟨hp, hf⟩, hf)
(assume hf, false.elim hf)
example : (p → q) → (¬q → ¬p) := example : (p → q) → (¬q → ¬p) :=
assume hpq nq hp, fun hpq nq hp => absurd (hpq hp) nq
absurd (hpq hp) nq
end ex_1 end ex1
-- Example 2 -- Example 2
-- --
-- Prove the following identities, replacing the “sorry” placeholders with -- Prove the following identities, replacing the “sorry” placeholders with
-- actual proofs. These require classical reasoning. -- actual proofs. These require classical reasoning.
section ex_2 namespace ex2
open classical open Classical
variables p q r s : Prop variable (p q r s : Prop)
example (hp : p) : (p → r s) → ((p → r) (p → s)) := example (hp : p) : (p → r s) → ((p → r) (p → s)) :=
assume h₁, fun h => (h hp).elim
or.elim (h₁ hp) (fun hr => Or.inl (fun _ => hr))
(assume hr, or.inl (assume hp, hr)) (fun hs => Or.inr (fun _ => hs))
(assume hs, or.inr (assume hp, hs))
example : ¬(p ∧ q) → ¬p ¬q := example : ¬(p ∧ q) → ¬p ¬q :=
assume npq, fun npq => (em p).elim
or.elim (em p) (fun hp => (em q).elim
(assume hp, or.elim (em q) (fun hq => False.elim (npq ⟨hp, hq⟩))
(assume hq, false.elim (npq ⟨hp, hq⟩)) Or.inr)
(assume nq, or.inr nq)) Or.inl
(assume np, or.inl np)
example : ¬(p → q) → p ∧ ¬q := example : ¬(p → q) → p ∧ ¬q :=
assume h₁, fun h =>
and.intro have lhs : p := byContradiction
(by_contradiction ( fun np => h (fun (hp : p) => absurd hp np)
assume np, ⟨lhs, fun hq => h (fun _ => hq)⟩
h₁ (λ (hp : p), absurd hp np)
))
(assume hq, h₁ (λ (hp : p), hq))
example : (p → q) → (¬p q) := example : (p → q) → (¬p q) :=
assume hpq, fun hpq => (em p).elim (fun hp => Or.inr (hpq hp)) Or.inl
or.elim (em p)
(assume hp, or.inr (hpq hp))
(assume np, or.inl np)
example : (¬q → ¬p) → (p → q) := example : (¬q → ¬p) → (p → q) :=
assume h₁ hp, fun h hp => byContradiction
by_contradiction (assume nq, absurd hp (h₁ nq)) fun nq => absurd hp (h nq)
example : p ¬p := em p example : p ¬p := em p
example : (((p → q) → p) → p) := example : (((p → q) → p) → p) :=
assume h₁, fun h => byContradiction
by_contradiction ( fun np =>
assume np, suffices hp : p from absurd hp np
suffices hp : p, from absurd hp np, h (fun (hp : p) => absurd hp np)
h₁ (λ (hp : p), absurd hp np)
)
end ex_2 end ex2
-- Example 3 -- Example 3
-- --
-- Prove `¬(p ↔ ¬p)` without using classical logic. -- Prove `¬(p ↔ ¬p)` without using classical logic.
section ex_3 namespace ex3
variable p : Prop variable (p : Prop)
example (hp : p) : ¬(p ↔ ¬p) := example (hp : p) : ¬(p ↔ ¬p) :=
assume h, fun h => absurd hp (Iff.mp h hp)
absurd hp (iff.elim_left h (hp))
end ex_3 end ex3

View File

@ -1,102 +1,94 @@
/- Exercises 4.6 /- Exercises 4
- -
- Avigad, Jeremy. Theorem Proving in Lean, n.d. - Avigad, Jeremy. Theorem Proving in Lean, n.d.
-/ -/
import data.int.basic
import data.nat.basic
import data.real.basic
-- Exercise 1 -- Exercise 1
-- --
-- Prove these equivalences. You should also try to understand why the reverse -- Prove these equivalences. You should also try to understand why the reverse
-- implication is not derivable in the last example. -- implication is not derivable in the last example.
section ex_1 namespace ex1
variables (α : Type*) (p q : α → Prop) variable (α : Type _)
variable (p q : α → Prop)
example : (∀ x, p x ∧ q x) ↔ (∀ x, p x) ∧ (∀ x, q x) := example : (∀ x, p x ∧ q x) ↔ (∀ x, p x) ∧ (∀ x, q x) :=
iff.intro Iff.intro
( assume h, (fun h => ⟨fun x => And.left (h x), fun x => And.right (h x)⟩)
and.intro (fun ⟨h₁, h₂⟩ x => ⟨h₁ x, h₂ x⟩)
(assume x, and.left (h x))
(assume x, and.right (h x)))
(assume ⟨h₁, h₂⟩ x, ⟨h₁ x, h₂ x⟩)
example : (∀ x, p x → q x) → (∀ x, p x) → (∀ x, q x) := example : (∀ x, p x → q x) → (∀ x, p x) → (∀ x, q x) :=
assume h₁ h₂ x, fun h₁ h₂ x =>
have px : p x, from h₂ x, have px : p x := h₂ x
h₁ x px h₁ x px
example : (∀ x, p x) (∀ x, q x) → ∀ x, p x q x := example : (∀ x, p x) (∀ x, q x) → ∀ x, p x q x :=
assume h₁ x, fun h₁ x => h₁.elim
h₁.elim (fun h₂ => Or.inl (h₂ x))
(assume h₂, or.inl (h₂ x)) (fun h₂ => Or.inr (h₂ x))
(assume h₂, or.inr (h₂ x))
-- The implication in the above example cannot be proven in the other direction -- The implication in the above example cannot be proven in the other direction
-- because it may be the case predicate `p x` holds for certain values of `x` -- because it may be the case predicate `p x` holds for certain values of `x`
-- but not others that `q x` may hold for (and vice versa). -- but not others that `q x` may hold for (and vice versa).
end ex_1 end ex1
-- Exercise 2 -- Exercise 2
-- --
-- It is often possible to bring a component of a formula outside a universal -- It is often possible to bring a component of a formula outside a universal
-- quantifier, when it does not depend on the quantified variable. Try proving -- quantifier, when it does not depend on the quantified variable. Try proving
-- these (one direction of the second of these requires classical logic). -- these (one direction of the second of these requires classical logic).
section ex_2 namespace ex2
variables (α : Type*) (p q : α → Prop) variable (α : Type _)
variable r : Prop variable (p q : α → Prop)
variable (r : Prop)
example : α → ((∀ x : α, r) ↔ r) := example : α → ((∀ _ : α, r) ↔ r) :=
assume ha, fun a => Iff.intro (fun h => h a) (fun hr _ => hr)
iff.intro (assume h, h ha) (assume hr ha, hr)
-- Ensure we do not use classical logic in the first or third subproblems.
section section
open classical open Classical
example : (∀ x, p x r) ↔ (∀ x, p x) r := example : (∀ x, p x r) ↔ (∀ x, p x) r :=
iff.intro Iff.intro
(assume h₁, or.elim (classical.em r) (fun h₁ => (em r).elim
(assume hr, or.inr hr) Or.inr
(assume nr, or.inl (λ (x : α), or.elim (h₁ x) (fun nr => Or.inl (fun x => (h₁ x).elim id (absurd · nr))))
(assume hp, hp) (fun h₁ => h₁.elim
(assume hr, absurd hr nr)))) (fun h₂ x => Or.inl (h₂ x))
(assume h₁, or.elim h₁ (fun hr _ => Or.inr hr))
(assume h₂, (λ (x : α), or.inl (h₂ x)))
(assume hr, (λ (x : α), or.inr hr)))
end end
example : (∀ x, r → p x) ↔ (r → ∀ x, p x) := example : (∀ x, r → p x) ↔ (r → ∀ x, p x) :=
iff.intro Iff.intro
(assume h₁ hr hx, h₁ hx hr) (fun h hr hx => h hx hr)
(assume h₁ hx hr, h₁ hr hx) (fun h hx hr => h hr hx)
end ex_2 end ex2
-- Exercise 3 -- Exercise 3
-- --
-- Consider the "barber paradox," that is, the claim that in a certain town -- Consider the "barber paradox," that is, the claim that in a certain town
-- there is a (male) barber that shaves all and only the men who do not shave -- there is a (male) barber that shaves all and only the men who do not shave
-- themselves. Prove that this is a contradiction. -- themselves. Prove that this is a contradiction.
section ex_3 namespace ex3
open classical open Classical
variables (men : Type*) (barber : men) variable (men : Type _)
variable (barber : men)
variable (shaves : men → men → Prop) variable (shaves : men → men → Prop)
example (h : ∀ x : men, shaves barber x ↔ ¬ shaves x x) : example (h : ∀ x : men, shaves barber x ↔ ¬shaves x x) : False :=
false := have b : shaves barber barber ↔ ¬shaves barber barber := h barber
have b : shaves barber barber ↔ ¬ shaves barber barber, from h barber, (em (shaves barber barber)).elim
or.elim (classical.em (shaves barber barber)) (fun b' => absurd b' (Iff.mp b b'))
(assume b', absurd b' (iff.elim_left b b')) (fun b' => absurd (Iff.mpr b b') b')
(assume b', absurd (iff.elim_right b b') b')
end ex_3 end ex3
-- Exercise 4 -- Exercise 4
-- --
@ -108,162 +100,141 @@ end ex_3
-- states that every odd number greater than `5` is the sum of three primes. -- states that every odd number greater than `5` is the sum of three primes.
-- Look up the definition of a Fermat prime or any of the other statements, if -- Look up the definition of a Fermat prime or any of the other statements, if
-- necessary. -- necessary.
section ex_4 namespace ex4
def prime (n : ) : Prop := def even (a : Nat) := ∃ b, a = 2 * b
n > 1 ∧ ∀ (m : ), (1 < m ∧ m < n) → n % m ≠ 0
def infinitely_many_primes : Prop := def odd (a : Nat) := ¬even a
∀ (n : ), (∃ (m : ), m > n ∧ prime m)
def Fermat_prime (n : ) : Prop := def prime (n : Nat) : Prop :=
∃ (m : ), n = 2^(2^m) + 1 n > 1 ∧ ∀ (m : Nat), (1 < m ∧ m < n) → n % m ≠ 0
def infinitely_many_Fermat_primes : Prop := def infinitelyManyPrimes : Prop :=
∀ (n : ), (∃ (m : ), m > n ∧ Fermat_prime m) ∀ (n : Nat), (∃ (m : Nat), m > n ∧ prime m)
def goldbach_conjecture : Prop := def FermatPrime (n : Nat) : Prop :=
∀ (n : ), even n ∧ n > 2 → (∃ (x y : ), prime x ∧ prime y ∧ x + y = n) ∃ (m : Nat), n = 2^(2^m) + 1
def Goldbach's_weak_conjecture : Prop := def infinitelyManyFermatPrimes : Prop :=
∀ (n : ), odd n ∧ n > 5 → (∃ (x y z : ), prime x ∧ prime y ∧ prime z ∧ x + y + z = n) ∀ (n : Nat), (∃ (m : Nat), m > n ∧ FermatPrime m)
def Fermat's_last_theorem : Prop := def GoldbachConjecture : Prop :=
∀ (n : ), n > 2 → (∀ (a b c : ), a^n + b^n ≠ c^n) ∀ (n : Nat), even n ∧ n > 2 →
∃ (x y : Nat), prime x ∧ prime y ∧ x + y = n
end ex_4 def Goldbach'sWeakConjecture : Prop :=
∀ (n : Nat), odd n ∧ n > 5 →
∃ (x y z : Nat), prime x ∧ prime y ∧ prime z ∧ x + y + z = n
def Fermat'sLastTheorem : Prop :=
∀ (n : Nat), n > 2 → (∀ (a b c : Nat), a^n + b^n ≠ c^n)
end ex4
-- Exercise 5 -- Exercise 5
-- --
-- Prove as many of the identities listed in Section 4.4 as you can. -- Prove as many of the identities listed in Section 4.4 as you can.
section ex_5 namespace ex5
open classical open Classical
variables (α : Type*) (p q : α → Prop) variable (α : Type _)
variables r s : Prop variable (p q : α → Prop)
variable (r s : Prop)
example : (∃ x : α, r) → r := example : (∃ _ : α, r) → r :=
assume ⟨hx, hr⟩, fun ⟨_, hr⟩ => hr
hr
example (a : α) : r → (∃ x : α, r) := example (a : α) : r → (∃ _ : α, r) :=
assume hr, fun hr => ⟨a, hr⟩
⟨a, hr⟩
example : (∃ x, p x ∧ r) ↔ (∃ x, p x) ∧ r := example : (∃ x, p x ∧ r) ↔ (∃ x, p x) ∧ r :=
iff.intro Iff.intro
(assume ⟨hx, ⟨hp, hr⟩⟩, ⟨⟨hx, hp⟩, hr⟩) (fun ⟨hx, ⟨hp, hr⟩⟩ => ⟨⟨hx, hp⟩, hr⟩)
(assume ⟨⟨hx, hp⟩, hr⟩, ⟨hx, ⟨hp, hr⟩⟩) (fun ⟨⟨hx, hp⟩, hr⟩ => ⟨hx, ⟨hp, hr⟩⟩)
example : (∃ x, p x q x) ↔ (∃ x, p x) (∃ x, q x) := example : (∃ x, p x q x) ↔ (∃ x, p x) (∃ x, q x) :=
iff.intro Iff.intro
(assume ⟨hx, hpq⟩, hpq.elim (fun ⟨hx, hpq⟩ => hpq.elim
(assume hp, or.inl (⟨hx, hp⟩)) (fun hp => Or.inl ⟨hx, hp⟩)
(assume hq, or.inr (⟨hx, hq⟩))) (fun hq => Or.inr ⟨hx, hq⟩))
(assume h, h.elim (fun h => h.elim
(assume ⟨hx, hp⟩, ⟨hx, or.inl hp⟩) (fun ⟨hx, hp⟩ => ⟨hx, Or.inl hp⟩)
(assume ⟨hx, hq⟩, ⟨hx, or.inr hq⟩)) (fun ⟨hx, hq⟩ => ⟨hx, Or.inr hq⟩))
example : (∀ x, p x) ↔ ¬ (∃ x, ¬ p x) := example : (∀ x, p x) ↔ ¬(∃ x, ¬p x) :=
iff.intro Iff.intro
(assume h ⟨hx, np⟩, np (h hx)) (fun h ⟨hx, np⟩ => np (h hx))
(assume h hx, classical.by_contradiction (assume np, h ⟨hx, np⟩)) (fun h hx => byContradiction
fun np => h ⟨hx, np⟩)
example : (∃ x, p x) ↔ ¬ (∀ x, ¬ p x) := example : (∃ x, p x) ↔ ¬(∀ x, ¬p x) :=
iff.intro Iff.intro
(assume ⟨hx, hp⟩ h, absurd hp (h hx)) (fun ⟨hx, hp⟩ h => absurd hp (h hx))
(assume h, classical.by_contradiction ( (fun h => byContradiction
assume h', fun h' => h (fun (x : α) hp => h' ⟨x, hp⟩))
h (λ (x : α), assume hp, h' ⟨x, hp⟩)
))
example : (¬ ∃ x, p x) ↔ (∀ x, ¬ p x) := example : (¬∃ x, p x) ↔ (∀ x, ¬p x) :=
iff.intro Iff.intro
(assume h hx hp, h ⟨hx, hp⟩) (fun h hx hp => h ⟨hx, hp⟩)
(assume h ⟨hx, hp⟩, absurd hp (h hx)) (fun h ⟨hx, hp⟩ => absurd hp (h hx))
lemma forall_negation : (¬ ∀ x, p x) ↔ (∃ x, ¬ p x) := theorem forall_negation : (¬∀ x, p x) ↔ (∃ x, ¬p x) :=
iff.intro Iff.intro
(assume h, classical.by_contradiction ( (fun h => byContradiction
assume h', fun h' => h (fun (x : α) => byContradiction
h (λ (x : α), classical.by_contradiction ( fun np => h' ⟨x, np⟩))
assume np, (fun ⟨hx, np⟩ h => absurd (h hx) np)
h' ⟨x, np⟩
))
))
(assume ⟨hx, np⟩ h, absurd (h hx) np)
example : (¬ ∀ x, p x) ↔ (∃ x, ¬ p x) := example : (¬∀ x, p x) ↔ (∃ x, ¬p x) :=
forall_negation α p forall_negation α p
example : (∀ x, p x → r) ↔ (∃ x, p x) → r := example : (∀ x, p x → r) ↔ (∃ x, p x) → r :=
iff.intro Iff.intro
(assume h ⟨hx, hp⟩, h hx hp) (fun h ⟨hx, hp⟩ => h hx hp)
(assume h hx hp, h ⟨hx, hp⟩) (fun h hx hp => h ⟨hx, hp⟩)
example (a : α) : (∃ x, p x → r) ↔ (∀ x, p x) → r := example (a : α) : (∃ x, p x → r) ↔ (∀ x, p x) → r :=
iff.intro Iff.intro
(assume ⟨hx, hp⟩ h, hp (h hx)) (fun ⟨hx, hp⟩ h => hp (h hx))
(assume h₁, or.elim (classical.em (∀ x, p x)) (fun h₁ => (em (∀ x, p x)).elim
(assume h₂, ⟨a, assume hp, h₁ h₂⟩) (fun h₂ => ⟨a, fun _ => h₁ h₂⟩)
(assume h₂, (fun h₂ =>
have h₃ : (∃ x, ¬p x), from iff.elim_left (forall_negation α p) h₂, have h₃ : (∃ x, ¬p x) := Iff.mp (forall_negation α p) h₂
match h₃ with match h₃ with
⟨hx, hp⟩ := ⟨hx, (assume hp', absurd hp' hp)⟩ | ⟨hx, hp⟩ => ⟨hx, fun hp' => absurd hp' hp⟩))
end))
example (a : α) : (∃ x, r → p x) ↔ (r → ∃ x, p x) := example (a : α) : (∃ x, r → p x) ↔ (r → ∃ x, p x) :=
iff.intro Iff.intro
(assume ⟨hx, hrp⟩ hr, ⟨hx, hrp hr⟩) (fun ⟨hx, hrp⟩ hr => ⟨hx, hrp hr⟩)
(assume h, or.elim (classical.em r) (fun h => (em r).elim
(assume hr, match h hr with (fun hr => match h hr with
⟨hx, hp⟩ := ⟨hx, (assume hr, hp)⟩ | ⟨hx, hp⟩ => ⟨hx, fun _ => hp⟩)
end) (fun nr => ⟨a, fun hr => absurd hr nr⟩))
(assume nr, ⟨a, (assume hr, absurd hr nr)⟩))
end ex_5 end ex5
-- Exercise 6 -- Exercise 6
-- --
-- Give a calculational proof of the theorem `log_mul` below. -- Give a calculational proof of the theorem `log_mul` below.
section ex_6 namespace ex6
variables log exp : real → real variable (log exp : Float → Float)
variable log_exp_eq : ∀ x, log (exp x) = x variable (log_exp_eq : ∀ x, log (exp x) = x)
variable exp_log_eq : ∀ {x}, x > 0 → exp (log x) = x variable (exp_log_eq : ∀ {x}, x > 0 → exp (log x) = x)
variable exp_pos : ∀ x, exp x > 0 variable (exp_pos : ∀ x, exp x > 0)
variable exp_add : ∀ x y, exp (x + y) = exp x * exp y variable (exp_add : ∀ x y, exp (x + y) = exp x * exp y)
-- this ensures the assumptions are available in tactic proofs example (x y z : Float) : exp (x + y + z) = exp x * exp y * exp z :=
include log_exp_eq exp_log_eq exp_pos exp_add by rw [exp_add, exp_add]
example (x y z : real) : example (y : Float) (h : y > 0) : exp (log y) = y := exp_log_eq h
exp (x + y + z) = exp x * exp y * exp z :=
by rw [exp_add, exp_add]
example (y : real) (h : y > 0) : exp (log y) = y := theorem log_mul {x y : Float} (hx : x > 0) (hy : y > 0) :
exp_log_eq h
theorem log_mul {x y : real} (hx : x > 0) (hy : y > 0) :
log (x * y) = log x + log y := log (x * y) = log x + log y :=
calc log (x * y) = log (x * exp (log y)) : by rw (exp_log_eq hy) calc log (x * y) = log (x * exp (log y)) := by rw [exp_log_eq hy]
... = log (exp (log x) * exp (log y)) : by rw (exp_log_eq hx) _ = log (exp (log x) * exp (log y)) := by rw [exp_log_eq hx]
... = log (exp (log x + log y)) : by rw exp_add _ = log (exp (log x + log y)) := by rw [exp_add]
... = log x + log y : by rw log_exp_eq _ = log x + log y := by rw [log_exp_eq]
end ex_6 end ex6
-- Exercise 7
--
-- Prove the theorem below, using only the ring properties of enumerated in
-- Section 4.2 and the theorem `sub_self.`
section ex_7
#check sub_self
example (x : ) : x * 0 = 0 :=
calc x * 0 = x * (x - x) : by rw (sub_self x)
... = x * x - x * x : by rw (mul_sub x x x)
... = 0 : by rw (sub_self (x * x))
end ex_7

View File

@ -1,499 +1,453 @@
/- Exercises 5.8 /- Exercises 5
- -
- Avigad, Jeremy. Theorem Proving in Lean, n.d. - Avigad, Jeremy. Theorem Proving in Lean, n.d.
-/ -/
import tactic.rcases
-- Exercise 1 -- Exercise 1
-- --
-- Go back to the exercises in Chapter 3 and Chapter 4 and redo as many as you -- Go back to the exercises in Chapter 3 and Chapter 4 and redo as many as you
-- can now with tactic proofs, using also `rw` and `simp` as appropriate. -- can now with tactic proofs, using also `rw` and `simp` as appropriate.
section ex_1_3_1 namespace ex1
variables p q r : Prop -- Exercises 3.1
section ex3_1
variable (p q r : Prop)
-- Commutativity of ∧ and -- Commutativity of ∧ and
example : p ∧ q ↔ q ∧ p := example : p ∧ q ↔ q ∧ p := by
begin apply Iff.intro
split, · intro ⟨hp, hq⟩
{ rintro ⟨p, q⟩, exact ⟨q, p⟩ }, exact ⟨hq, hp⟩
{ rintro ⟨q, p⟩, exact ⟨p, q⟩ }, · intro ⟨hq, hp⟩
end exact ⟨hp, hq⟩
example : p q ↔ q p := example : p q ↔ q p := by
begin apply Iff.intro
split, · intro
{ rintro (p | q), | Or.inl hp => exact Or.inr hp
{ exact or.inr p }, | Or.inr hq => exact Or.inl hq
{ exact or.inl q }, · intro
}, | Or.inl hq => exact Or.inr hq
{ rintro (q | p), | Or.inr hp => exact Or.inl hp
{ exact or.inr q },
{ exact or.inl p },
},
end
-- Associativity of ∧ and -- Associativity of ∧ and
example : (p ∧ q) ∧ r ↔ p ∧ (q ∧ r) := example : (p ∧ q) ∧ r ↔ p ∧ (q ∧ r) := by
begin apply Iff.intro
split, · intro ⟨⟨hp, hq⟩, hr⟩
{ rintro ⟨⟨p, q⟩, r⟩, exact ⟨p, q, r⟩ }, exact ⟨hp, hq, hr⟩
{ rintro ⟨p, q, r⟩, exact ⟨⟨p, q⟩, r⟩ }, · intro ⟨hp, hq, hr⟩
end exact ⟨⟨hp, hq⟩, hr⟩
example : (p q) r ↔ p (q r) := example : (p q) r ↔ p (q r) := by
begin apply Iff.intro
split, · intro
{ rintro ((p | q) | r), | Or.inl (Or.inl hp) => exact Or.inl hp
{ exact or.inl p }, | Or.inl (Or.inr hq) => exact Or.inr (Or.inl hq)
{ exact or.inr (or.inl q) }, | Or.inr hr => exact Or.inr (Or.inr hr)
{ exact or.inr (or.inr r) }, · intro
}, | Or.inl hp => exact Or.inl (Or.inl hp)
{ rintro (p | q | r), | Or.inr (Or.inl hq) => exact Or.inl (Or.inr hq)
{ exact or.inl (or.inl p) }, | Or.inr (Or.inr hr) => exact Or.inr hr
{ exact or.inl (or.inr q) },
{ exact or.inr r },
},
end
-- Distributivity -- Distributivity
example : p ∧ (q r) ↔ (p ∧ q) (p ∧ r) := example : p ∧ (q r) ↔ (p ∧ q) (p ∧ r) := by
begin apply Iff.intro
split, · intro
{ rintro ⟨p, (q | r)⟩, | ⟨hp, Or.inl hq⟩ => exact Or.inl ⟨hp, hq⟩
{ exact or.inl ⟨p, q⟩ }, | ⟨hp, Or.inr hr⟩ => exact Or.inr ⟨hp, hr⟩
{ exact or.inr ⟨p, r⟩ }, · intro
}, | Or.inl ⟨hp, hq⟩ => exact ⟨hp, Or.inl hq⟩
{ rintro (⟨p, q⟩ | ⟨p, r⟩), | Or.inr ⟨hp, hr⟩ => exact ⟨hp, Or.inr hr⟩
{ exact ⟨p, or.inl q⟩ },
{ exact ⟨p, or.inr r⟩ },
},
end
example : p (q ∧ r) ↔ (p q) ∧ (p r) := example : p (q ∧ r) ↔ (p q) ∧ (p r) := by
begin apply Iff.intro
split, · intro
{ rintro (p | ⟨q, r⟩), | Or.inl hp => exact ⟨Or.inl hp, Or.inl hp⟩
{ exact ⟨or.inl p, or.inl p⟩ }, | Or.inr ⟨hq, hr⟩ => exact ⟨Or.inr hq, Or.inr hr⟩
{ exact ⟨or.inr q, or.inr r⟩ }, · intro
}, | ⟨Or.inl hp, _⟩ => exact Or.inl hp
{ rintro ⟨(p | q), (p | r)⟩; | ⟨Or.inr _, Or.inl hp⟩ => exact Or.inl hp
exact or.inl p <|> exact or.inr ⟨q, r⟩, | ⟨Or.inr hq, Or.inr hr⟩ => exact Or.inr ⟨hq, hr⟩
},
end
-- Other properties -- Other properties
example : (p → (q → r)) ↔ (p ∧ q → r) := example : (p → (q → r)) ↔ (p ∧ q → r) := by
begin apply Iff.intro
split, · intro h ⟨hp, hq⟩
{ rintros h ⟨hp, hq⟩, exact h hp hq }, exact h hp hq
{ intros h hp hq, exact h ⟨hp, hq⟩ }, · intro h hp hq
end exact h ⟨hp, hq⟩
example : ((p q) → r) ↔ (p → r) ∧ (q → r) := example : ((p q) → r) ↔ (p → r) ∧ (q → r) := by
begin apply Iff.intro
split, · intro h
{ intros h₁, apply And.intro
split, · intro hp
{ intro p, exact h₁ (or.inl p) }, exact h (Or.inl hp)
{ intro q, exact h₁ (or.inr q) }, · intro hq
}, exact h (Or.inr hq)
{ rintros ⟨hp, hq⟩ h, · intro ⟨hpr, hqr⟩ h
apply or.elim h, apply Or.elim h
{ intro p, exact hp p }, · intro hp
{ intro q, exact hq q }, exact hpr hp
}, · intro hq
end exact hqr hq
example : ¬(p q) ↔ ¬p ∧ ¬q := example : ¬(p q) ↔ ¬p ∧ ¬q := by
begin apply Iff.intro
split, · intro h
{ intro h, apply And.intro
split, · intro hp
{ intro hp, apply h, exact or.inl hp }, exact h (Or.inl hp)
{ intro hq, apply h, exact or.inr hq }, · intro hq
}, exact h (Or.inr hq)
{ rintros ⟨np, nq⟩ (p | q), · intro ⟨np, nq⟩
{ apply np, assumption }, intro
{ apply nq, assumption }, | Or.inl hp => exact absurd hp np
}, | Or.inr hq => exact absurd hq nq
end
example : ¬p ¬q → ¬(p ∧ q) := example : ¬p ¬q → ¬(p ∧ q) := by
begin intro
rintro (np | nq) ⟨hp, hq⟩, | Or.inl np => intro h; exact absurd h.left np
{ apply np, assumption }, | Or.inr nq => intro h; exact absurd h.right nq
{ apply nq, assumption },
end
example : ¬(p ∧ ¬p) := example : ¬(p ∧ ¬p) := by
begin intro ⟨hp, np⟩
rintro ⟨hp, np⟩,
exact absurd hp np exact absurd hp np
end
example : p ∧ ¬q → ¬(p → q) := example : p ∧ ¬q → ¬(p → q) := by
begin intro ⟨hp, nq⟩ h
rintro ⟨hp, nq⟩ hpq, exact absurd (h hp) nq
apply nq,
exact hpq hp
end
example : ¬p → (p → q) := example : ¬p → (p → q) := by
begin intro np hp
intros np hp, exact absurd hp np
exact absurd hp np,
end
example : (¬p q) → (p → q) := example : (¬p q) → (p → q) := by
begin intro
rintros (np | hq) hp, | Or.inl np => intro hp; exact absurd hp np
{ exact absurd hp np }, | Or.inr hq => exact fun _ => hq
{ exact hq },
end
example : p false ↔ p := example : p False ↔ p := by
begin apply Iff.intro
split, · intro
{ rintro (hp | hf), | Or.inl hp => exact hp
{ exact hp }, | Or.inr ff => exact False.elim ff
{ exact false.elim hf }, · intro hp
}, exact Or.inl hp
{ intro hp,
exact or.inl hp,
},
end
example : p ∧ false ↔ false := example : p ∧ False ↔ False := by
begin apply Iff.intro
split, · intro ⟨_, ff⟩
{ rintro ⟨hp, hf⟩, assumption }, exact ff
{ intro hf, exact false.elim hf }, · intro ff
end exact False.elim ff
example : (p → q) → (¬q → ¬p) := example : (p → q) → (¬q → ¬p) := by
begin intro hpq nq hp
rintro hpq nq hp, exact absurd (hpq hp) nq
apply nq,
exact absurd (hpq hp) nq,
end
end ex_1_3_1 end ex3_1
section ex_1_3_2 -- Exercises 3.2
open classical section ex3_2
variables p q r s : Prop open Classical
example (hp : p) : (p → r s) → ((p → r) (p → s)) := variable (p q r s : Prop)
begin
intro h,
apply or.elim (h hp),
{ intro hr, exact or.inl (assume hp, hr) },
{ intro hs, exact or.inr (assume hp, hs) }
end
example : ¬(p ∧ q) → ¬p ¬q := example (hp : p) : (p → r s) → ((p → r) (p → s)) := by
begin intro h
intro h₁, apply (h hp).elim
apply or.elim (classical.em p), · intro hr
{ intro hp, exact Or.inl (fun _ => hr)
apply or.elim (classical.em q), · intro hs
{ assume hq, exact false.elim (h₁ ⟨hp, hq⟩) }, exact Or.inr (fun _ => hs)
{ assume nq, exact or.inr nq },
},
{ intro np,
exact or.inl np,
},
end
example : ¬(p → q) → p ∧ ¬q := example : ¬(p ∧ q) → ¬p ¬q := by
begin intro h
intro h₁, apply (em p).elim
split, · intro hp
{ by_contradiction np, apply h₁, intro hp, exact absurd hp np }, apply (em q).elim
{ intro hq, apply h₁, intro hp, exact hq }, · intro hq
end exact False.elim (h ⟨hp, hq⟩)
· intro nq
exact Or.inr nq
· intro np
exact Or.inl np
example : (p → q) → (¬p q) := example : ¬(p → q) → p ∧ ¬q := by
begin intro h
intro hpq, apply And.intro
apply or.elim (classical.em p), · apply byContradiction
{ assume hp, exact or.inr (hpq hp) }, intro np
{ assume np, exact or.inl np }, apply h
end intro hp
exact absurd hp np
· intro hq
apply h
intro _
exact hq
example : (¬q → ¬p) → (p → q) := example : (p → q) → (¬p q) := by
begin intro hpq
intros hqp hp, apply (em p).elim
by_contradiction nq, · intro hp
exact absurd hp (hqp nq), exact Or.inr (hpq hp)
end · intro np
exact Or.inl np
example : p ¬p := example : (¬q → ¬p) → (p → q) := by
by apply classical.em intro hqp hp
apply byContradiction
intro nq
exact absurd hp (hqp nq)
example : (((p → q) → p) → p) := example : p ¬p := by apply em
begin
intro h,
apply or.elim (classical.em p),
{ intro hp, assumption },
{ intro np, apply h, intro hp, exact absurd hp np },
end
end ex_1_3_2 example : (((p → q) → p) → p) := by
intro h
apply (em p).elim
· intro hp
exact hp
· intro np
apply h
intro hp
exact absurd hp np
section ex_1_3_3 end ex3_2
variable p : Prop -- Exercises 3.3
example (hp : p) : ¬(p ↔ ¬p) := section ex3_3
begin
intro h₁,
cases h₁ with h₂,
exact absurd hp (h₂ hp),
end
end ex_1_3_3 variable (p : Prop)
section ex_1_4_1 example (hp : p) : ¬(p ↔ ¬p) := by
intro h
exact absurd hp (h.mp hp)
variables (α : Type*) (p q : α → Prop) end ex3_3
example : (∀ x, p x ∧ q x) ↔ (∀ x, p x) ∧ (∀ x, q x) := -- Exercises 4.1
begin
split,
{ intro h,
split,
{ intro hx, exact and.left (h hx) },
{ intro hx, exact and.right (h hx) },
},
{ intros h hx,
have hl : ∀ (x : α), p x, from and.left h,
have hr : ∀ (x : α), q x, from and.right h,
exact ⟨hl hx, hr hx⟩
},
end
example : (∀ x, p x → q x) → (∀ x, p x) → (∀ x, q x) := section ex4_1
begin
intros h₁ h₂ hx, variable (α : Type _)
variable (p q : α → Prop)
example : (∀ x, p x ∧ q x) ↔ (∀ x, p x) ∧ (∀ x, q x) := by
apply Iff.intro
· intro h
apply And.intro
· intro hx; exact And.left (h hx)
· intro hx; exact And.right (h hx)
· intro h hx
have lhs : ∀ (x : α), p x := And.left h
have rhs : ∀ (x : α), q x := And.right h
exact ⟨lhs hx, rhs hx⟩
example : (∀ x, p x → q x) → (∀ x, p x) → (∀ x, q x) := by
intro h₁ h₂ hx
exact h₁ hx (h₂ hx) exact h₁ hx (h₂ hx)
end
example : (∀ x, p x) (∀ x, q x) → ∀ x, p x q x := example : (∀ x, p x) (∀ x, q x) → ∀ x, p x q x := by
begin intro
rintro (h₁ | h₂), | Or.inl h => intro hx; exact Or.inl (h hx)
{ intro hx, exact or.inl (h₁ hx) }, | Or.inr h => intro hx; exact Or.inr (h hx)
{ intro hx, exact or.inr (h₂ hx) },
end
end ex_1_4_1 end ex4_1
section ex_1_4_2 -- Exercises 4.2
variables (α : Type*) (p q : α → Prop) section ex4_2
variable r : Prop
example : α → ((∀ x : α, r) ↔ r) := variable (α : Type _)
begin variable (p q : α → Prop)
intro hα, variable (r : Prop)
split,
{ intro hαr, apply hαr, exact hα }, example : α → ((∀ _ : α, r) ↔ r) := by
{ intros hr hα, exact hr }, intro ha
end apply Iff.intro
· intro har
apply har
exact ha
· intro hr _
exact hr
section section
open classical open Classical
example : (∀ x, p x r) ↔ (∀ x, p x) r := example : (∀ x, p x r) ↔ (∀ x, p x) r := by
begin apply Iff.intro
split, · intro h
{ intro h₁, apply (em r).elim
apply or.elim (classical.em r), · intro hr
{ intro hr, exact or.inr hr }, exact Or.inr hr
{ intro nr, · intro nr
exact or.inl begin apply Or.inl
intro hx, · intro hx
have h₂ : p hx r, from h₁ hx, apply (h hx).elim
apply or.elim h₂, · exact id
{ intro hp, exact hp }, · intro hr
{ intro hr, exact absurd hr nr }, exact absurd hr nr
end · intro h₁ hx
}, apply h₁.elim
}, · intro h₂
{ assume h₁ hx, exact Or.inl (h₂ hx)
apply or.elim h₁, · intro hr
{ assume h₂, exact or.inl (h₂ hx) }, exact Or.inr hr
{ assume hr, exact or.inr hr },
},
end
end end
example : (∀ x, r → p x) ↔ (r → ∀ x, p x) := example : (∀ x, r → p x) ↔ (r → ∀ x, p x) := by
begin apply Iff.intro
split, · intro h hr hx
{ intros h hr hx, exact h hx hr }, exact h hx hr
{ intros h hx hr, exact h hr hx }, · intro h hx hr
end exact h hr hx
end ex_1_4_2 end ex4_2
section ex_1_4_3 -- Exercises 4.3
open classical section ex4_3
variables (men : Type*) (barber : men) open Classical
variable (men : Type _)
variable (barber : men)
variable (shaves : men → men → Prop) variable (shaves : men → men → Prop)
example (h : ∀ x : men, shaves barber x ↔ ¬ shaves x x) : example (h : ∀ x : men, shaves barber x ↔ ¬ shaves x x) : False := by
false := apply (em (shaves barber barber)).elim
begin · intro hb
apply or.elim (classical.em (shaves barber barber)), exact absurd hb ((h barber).mp hb)
{ intro hb, · intro nb
apply iff.elim_left (h barber) hb, exact absurd ((h barber).mpr nb) nb
exact hb,
},
{ intro nb,
have s, from iff.elim_right (h barber) nb,
exact absurd s nb
},
end
end ex_1_4_3 end ex4_3
section ex_1_4_5 -- Exercises 4.5
open classical section ex4_5
variables (α : Type*) (p q : α → Prop) open Classical
variables r s : Prop
example : (∃ x : α, r) → r := variable (α : Type _)
begin variable (p q : α → Prop)
rintro ⟨hx, hr⟩, variable (r s : Prop)
exact hr,
end
example (a : α) : r → (∃ x : α, r) := example : (∃ _ : α, r) → r := by
begin intro ⟨_, hr⟩
intro hr, exact hr
example (a : α) : r → (∃ _ : α, r) := by
intro hr
exact ⟨a, hr⟩ exact ⟨a, hr⟩
end
example : (∃ x, p x ∧ r) ↔ (∃ x, p x) ∧ r := example : (∃ x, p x ∧ r) ↔ (∃ x, p x) ∧ r := by
begin apply Iff.intro
split, · intro ⟨hx, hp, hr⟩
{ rintro ⟨hx, ⟨hp, hr⟩⟩, exact ⟨⟨hx, hp⟩, hr⟩ }, exact ⟨⟨hx, hp⟩, hr⟩
{ rintro ⟨⟨hx, hp⟩, hr⟩, exact ⟨hx, ⟨hp, hr⟩⟩ }, · intro ⟨⟨hx, hp⟩, hr⟩
end exact ⟨hx, hp, hr⟩
example : (∃ x, p x q x) ↔ (∃ x, p x) (∃ x, q x) := example : (∃ x, p x q x) ↔ (∃ x, p x) (∃ x, q x) := by
begin apply Iff.intro
split, · intro
{ rintro ⟨hx, (hp | hq)⟩, | ⟨hx, Or.inl hp⟩ => exact Or.inl ⟨hx, hp⟩
{ exact or.inl ⟨hx, hp⟩ }, | ⟨hx, Or.inr hq⟩ => exact Or.inr ⟨hx, hq⟩
{ exact or.inr ⟨hx, hq⟩ }, · intro
}, | Or.inl ⟨hx, hp⟩ => exact ⟨hx, Or.inl hp⟩
{ rintro (⟨hx, hp⟩ | ⟨hx, hq⟩), | Or.inr ⟨hx, hq⟩ => exact ⟨hx, Or.inr hq⟩
{ exact ⟨hx, or.inl hp⟩ },
{ exact ⟨hx, or.inr hq⟩ },
},
end
example : (∀ x, p x) ↔ ¬ (∃ x, ¬ p x) := example : (∀ x, p x) ↔ ¬(∃ x, ¬p x) := by
begin apply Iff.intro
split, · intro ha ⟨hx, np⟩
{ rintros ha ⟨hx, np⟩, exact absurd (ha hx) np }, exact absurd (ha hx) np
{ intros he hx, by_contradiction np, exact he ⟨hx, np⟩ }, · intro he hx
end apply byContradiction
intro np
exact he ⟨hx, np⟩
example : (∃ x, p x) ↔ ¬ (∀ x, ¬ p x) := example : (∃ x, p x) ↔ ¬(∀ x, ¬p x) := by
begin apply Iff.intro
split, · intro ⟨hx, hp⟩ h
{ rintro ⟨hx, hp⟩ h, exact absurd hp (h hx) },
{ intro h₁,
by_contradiction h₂,
apply h₁,
intros hx hp,
exact h₂ ⟨hx, hp⟩,
},
end
example : (¬ ∃ x, p x) ↔ (∀ x, ¬ p x) :=
begin
split,
{ intros h hx hp,
exact h ⟨hx, hp⟩
},
{ rintros h ⟨hx, hp⟩,
exact absurd hp (h hx) exact absurd hp (h hx)
}, · intro h₁
end apply byContradiction
intro h₂
apply h₁
intro hx hp
exact h₂ ⟨hx, hp⟩
lemma forall_negation : (¬ ∀ x, p x) ↔ (∃ x, ¬ p x) := example : (¬∃ x, p x) ↔ (∀ x, ¬p x) := by
begin apply Iff.intro
split, · intro h hx hp
{ intro h₁,
by_contradiction h₂,
exact h₁ (λ (x : α), begin
by_contradiction np,
exact h₂ ⟨x, np⟩
end)
},
{ rintros ⟨hx, np⟩ h, exact absurd (h hx) np },
end
example : (¬ ∀ x, p x) ↔ (∃ x, ¬ p x) := forall_negation α p
example : (∀ x, p x → r) ↔ (∃ x, p x) → r :=
begin
split,
{ rintros h ⟨hx, hp⟩, exact h hx hp },
{ intros h hx hp,
exact h ⟨hx, hp⟩ exact h ⟨hx, hp⟩
}, · intro h ⟨hx, hp⟩
end exact absurd hp (h hx)
example (a : α) : (∃ x, p x → r) ↔ (∀ x, p x) → r := theorem forall_negation : (¬∀ x, p x) ↔ (∃ x, ¬p x) := by
begin apply Iff.intro
split, · intro h₁
{ rintros ⟨hx, hp⟩ h, apply hp, exact h hx }, apply byContradiction
{ intro h₁, intro h₂
apply or.elim (classical.em (∀ x, p x)), exact h₁ (fun (x : α) => by
{ intro h₂, exact ⟨a, (assume hp, h₁ h₂)⟩ }, apply byContradiction
{ intro h₂, intro np
have h₃ : (∃ x, ¬p x), from iff.elim_left (forall_negation α p) h₂, exact h₂ ⟨x, np⟩)
exact let ⟨hx, hp⟩ := h₃ in ⟨hx, (assume hp', absurd hp' hp)⟩, · intro ⟨hx, np⟩ h
}, exact absurd (h hx) np
},
end
example (a : α) : (∃ x, r → p x) ↔ (r → ∃ x, p x) := example : (¬∀ x, p x) ↔ (∃ x, ¬p x) := forall_negation α p
begin
split,
{ rintros ⟨hx, h⟩ hr, exact ⟨hx, h hr⟩ },
{ intro h,
apply or.elim (classical.em r),
{ intro hr,
exact let ⟨hx, hp⟩ := h hr in ⟨hx, (assume hr, hp)⟩
},
{ intro nr, exact ⟨a, (assume hr, absurd hr nr)⟩ },
},
end
end ex_1_4_5 example : (∀ x, p x → r) ↔ (∃ x, p x) → r := by
apply Iff.intro
· intro h ⟨hx, hp⟩
exact h hx hp
· intro h hx hp
exact h ⟨hx, hp⟩
example (a : α) : (∃ x, p x → r) ↔ (∀ x, p x) → r := by
apply Iff.intro
· intro ⟨hx, hp⟩ h
apply hp
exact h hx
· intro h₁
apply (em (∀ x, p x)).elim
· intro h₂
exact ⟨a, fun _ => h₁ h₂⟩
· intro h₂
have ⟨hx, np⟩ : (∃ x, ¬p x) := (forall_negation α p).mp h₂
exact ⟨hx, fun hp => absurd hp np⟩
example (a : α) : (∃ x, r → p x) ↔ (r → ∃ x, p x) := by
apply Iff.intro
· intro ⟨hx, h⟩ hr
exact ⟨hx, h hr⟩
· intro h
apply (em r).elim
· intro hr
have ⟨hx, hp⟩ := h hr
exact ⟨hx, fun _ => hp⟩
· intro nr
exact ⟨a, fun hr => absurd hr nr⟩
end ex4_5
end ex1
-- Exercise 2 -- Exercise 2
-- --
-- Use tactic combinators to obtain a one line proof of the following: -- Use tactic combinators to obtain a one line proof of the following:
section ex_2 namespace ex2
example (p q r : Prop) (hp : p) : (p q r) ∧ (q p r) ∧ (q r p) := example (p q r : Prop) (hp : p) : (p q r) ∧ (q p r) ∧ (q r p) :=
by simp * by simp [*]
end ex_2 end ex2

View File

@ -1,8 +1,7 @@
/- Exercises 7.10 /- Exercises 7
- -
- Avigad, Jeremy. Theorem Proving in Lean, n.d. - Avigad, Jeremy. Theorem Proving in Lean, n.d.
-/ -/
import data.nat.basic
-- Exercise 1 -- Exercise 1
-- --
@ -15,41 +14,63 @@ import data.nat.basic
-- Since many of these are already defined in Leans core library, you should -- Since many of these are already defined in Leans core library, you should
-- work within a namespace named hide, or something like that, in order to avoid -- work within a namespace named hide, or something like that, in order to avoid
-- name clashes. -- name clashes.
namespace ex_1 namespace ex1
-- As defined in the book. -- As defined in the book.
inductive nat : Type inductive Nat where
| zero : nat | zero : Nat
| succ : nat → nat | succ : Nat → Nat
def add (m n : nat) : nat := namespace Nat
nat.rec_on n m (λ k ak, nat.succ ak)
theorem add_zero (m : nat) : add m nat.zero = m := rfl def add (m n : Nat) : Nat :=
theorem add_succ (m n : nat) : add m n.succ = (add m n).succ := rfl match n with
| Nat.zero => m
| Nat.succ n => Nat.succ (add m n)
theorem zero_add (n : nat) : add nat.zero n = n := instance : Add Nat where
nat.rec_on n add := add
(add_zero nat.zero)
(assume n ih, theorem addZero (m : Nat) : m + Nat.zero = m :=
show add nat.zero (nat.succ n) = nat.succ n, from calc rfl
add nat.zero (nat.succ n) = nat.succ (add nat.zero n) : add_succ nat.zero n
... = nat.succ n : by rw ih) theorem addSucc (m n : Nat) : m + n.succ = (m + n).succ :=
rfl
theorem zeroAdd (n : Nat) : Nat.zero + n = n :=
Nat.recOn (motive := fun x => Nat.zero + x = x)
n
(show Nat.zero + Nat.zero = Nat.zero from rfl)
(fun (n : Nat) (ih : Nat.zero + n = n) =>
show Nat.zero + n.succ = n.succ from
calc
Nat.zero + n.succ = (Nat.zero + n).succ := addSucc Nat.zero n
_ = n.succ := by rw [ih])
-- Additional definitions. -- Additional definitions.
def mul (m n : nat) : nat := def mul (m n : Nat) : Nat := sorry
nat.rec_on n nat.zero (λ k ak, add m ak)
def pred (n : nat) : nat := -- def mul (m n : nat) : nat :=
nat.cases_on n nat.zero id -- nat.rec_on n nat.zero (λ k ak, add m ak)
def sub (m n : nat) : nat := def pred (n : Nat) : Nat := sorry
nat.rec_on n m (λ k ak, pred ak)
def exp (m n : nat) : nat := -- def pred (n : nat) : nat :=
nat.rec_on n (nat.zero.succ) (λ k ak, mul m ak) -- nat.cases_on n nat.zero id
end ex_1 def sub (m n : Nat) : Nat := sorry
-- def sub (m n : nat) : nat :=
-- nat.rec_on n m (λ k ak, pred ak)
def exp (m n : Nat) : Nat := sorry
-- def exp (m n : nat) : nat :=
-- nat.rec_on n (nat.zero.succ) (λ k ak, mul m ak)
end Nat
end ex1
-- Exercise 2 -- Exercise 2
-- --
@ -59,46 +80,45 @@ end ex_1
-- a. `length (s ++ t) = length s + length t` -- a. `length (s ++ t) = length s + length t`
-- b. `length (reverse t) = length t` -- b. `length (reverse t) = length t`
-- c. `reverse (reverse t) = t` -- c. `reverse (reverse t) = t`
section ex_2 namespace ex2
open list open List
variable {α : Type*} variable {α : Type _}
-- Additional theorems. -- theorem length_sum (s t : list α) : length (s ++ t) = length s + length t :=
theorem length_sum (s t : list α) : length (s ++ t) = length s + length t := -- list.rec_on s
list.rec_on s -- (by rw [nil_append, length, zero_add])
(by rw [nil_append, length, zero_add]) -- (assume hd tl ih, by rw [
(assume hd tl ih, by rw [ -- length,
length, -- cons_append,
cons_append, -- length,
length, -- ih,
ih, -- add_assoc,
add_assoc, -- add_comm t.length,
add_comm t.length, -- add_assoc
add_assoc -- ])
]) --
-- lemma cons_reverse (hd : α) (tl : list α)
-- : reverse (hd :: tl) = reverse tl ++ [hd] :=
-- sorry
--
-- theorem length_reverse (t : list α) : length (reverse t) = length t :=
-- list.rec_on t
-- (by unfold reverse reverse_core)
-- (assume hd tl ih, begin
-- unfold length,
-- rw cons_reverse,
-- rw length_sum,
-- unfold length,
-- rw zero_add,
-- rw ih,
-- end)
--
-- theorem reverse_reverse (t : list α) : reverse (reverse t) = t :=
-- list.rec_on t rfl (assume hd tl ih, sorry)
lemma cons_reverse (hd : α) (tl : list α) end ex2
: reverse (hd :: tl) = reverse tl ++ [hd] :=
sorry
theorem length_reverse (t : list α) : length (reverse t) = length t :=
list.rec_on t
(by unfold reverse reverse_core)
(assume hd tl ih, begin
unfold length,
rw cons_reverse,
rw length_sum,
unfold length,
rw zero_add,
rw ih,
end)
theorem reverse_reverse (t : list α) : reverse (reverse t) = t :=
list.rec_on t rfl (assume hd tl ih, sorry)
end ex_2
-- Exercise 3 -- Exercise 3
-- --
@ -112,27 +132,27 @@ end ex_2
-- --
-- Recursively define a function that evaluates any such term with respect to an -- Recursively define a function that evaluates any such term with respect to an
-- assignment of values to the variables. -- assignment of values to the variables.
namespace ex_3 namespace ex3
inductive foo : Type* -- inductive foo : Type*
| const : → foo -- | const : → foo
| var : → foo -- | var : → foo
| plus : foo → foo → foo -- | plus : foo → foo → foo
| times : foo → foo → foo -- | times : foo → foo → foo
--
-- def value_at : → list
-- | 0 vs := list.head vs
-- | i [] := default
-- | (i + 1) vs := value_at i (list.tail vs)
--
-- -- The provided "variables" are supplied in a 0-indexed list.
-- def eval_foo : foo → list
-- | (foo.const n) vs := n
-- | (foo.var n) vs := value_at n vs
-- | (foo.plus m n) vs := eval_foo m vs + eval_foo n vs
-- | (foo.times m n) vs := eval_foo m vs * eval_foo n vs
def value_at : → list end ex3
| 0 vs := list.head vs
| i [] := default
| (i + 1) vs := value_at i (list.tail vs)
-- The provided "variables" are supplied in a 0-indexed list.
def eval_foo : foo → list
| (foo.const n) vs := n
| (foo.var n) vs := value_at n vs
| (foo.plus m n) vs := eval_foo m vs + eval_foo n vs
| (foo.times m n) vs := eval_foo m vs * eval_foo n vs
end ex_3
-- Exercise 4 -- Exercise 4
-- --
@ -140,35 +160,35 @@ end ex_3
-- the type of such formulas: an evaluation function, functions that measure the -- the type of such formulas: an evaluation function, functions that measure the
-- complexity of a formula, and a function that substitutes another formula for -- complexity of a formula, and a function that substitutes another formula for
-- a given variable. -- a given variable.
namespace ex_4 namespace ex4
inductive foo : Type* -- inductive foo : Type*
| tt : foo -- | tt : foo
| ff : foo -- | ff : foo
| and : foo → foo → foo -- | and : foo → foo → foo
| or : foo → foo → foo -- | or : foo → foo → foo
--
-- def eval_foo : foo → bool
-- | foo.tt := true
-- | foo.ff := false
-- | (foo.and lhs rhs) := eval_foo lhs ∧ eval_foo rhs
-- | (foo.or lhs rhs) := eval_foo lhs eval_foo rhs
--
-- def complexity_foo : foo →
-- | foo.tt := 1
-- | foo.ff := 1
-- | (foo.and lhs rhs) := 1 + complexity_foo lhs + complexity_foo rhs
-- | (foo.or lhs rhs) := 1 + complexity_foo lhs + complexity_foo rhs
--
-- def substitute : foo → foo := sorry
def eval_foo : foo → bool end ex4
| foo.tt := true
| foo.ff := false
| (foo.and lhs rhs) := eval_foo lhs ∧ eval_foo rhs
| (foo.or lhs rhs) := eval_foo lhs eval_foo rhs
def complexity_foo : foo →
| foo.tt := 1
| foo.ff := 1
| (foo.and lhs rhs) := 1 + complexity_foo lhs + complexity_foo rhs
| (foo.or lhs rhs) := 1 + complexity_foo lhs + complexity_foo rhs
def substitute : foo → foo := sorry
end ex_4
-- Exercise 5 -- Exercise 5
-- --
-- Simulate the mutual inductive definition of `even` and `odd` described in -- Simulate the mutual inductive definition of `even` and `odd` described in
-- Section 7.9 with an ordinary inductive type, using an index to encode the -- Section 7.9 with an ordinary inductive type, using an index to encode the
-- choice between them in the target type. -- choice between them in the target type.
section ex_5 namespace ex5
end ex_5 end ex5