Skip to content

Commit 9831197

Browse files
committed
post assignment 5 (week 6) on tactics
1 parent c831ac9 commit 9831197

1 file changed

Lines changed: 391 additions & 0 deletions

File tree

Lines changed: 391 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,391 @@
1+
-- PROOF101 Week 6: Theorem Proving in Lean — Programming Assignment 5
2+
-- Name: _________________
3+
-- Date: _________________
4+
5+
/-
6+
Instructions:
7+
- Replace each `sorry` with a valid proof
8+
- Make sure all theorems type-check
9+
- You may use any tactic covered in Weeks 4–5: rfl, exact, decide, intro,
10+
rw, symm, apply, refine, obtain, constructor, left, right,
11+
cases, induction, simp, simp_all, omega, calc, have, etc.
12+
- Do not modify the theorem statements or the provided definitions
13+
- You ARE allowed (and encouraged!) to use previously proven theorems
14+
from this file in your proofs
15+
16+
Useful tactic reminders:
17+
rfl — closes goals of the form `a = a`
18+
exact e — closes the goal by providing the exact term `e`
19+
decide — evaluates decidable propositions (concrete computations)
20+
intro h — introduces a hypothesis `h` from the goal
21+
rw [h] — rewrites the goal using equality `h` (left to right)
22+
rw [← h] — rewrites right to left
23+
apply f — performs backward reasoning with `f`
24+
constructor — splits a ∧ goal into two subgoals
25+
left / right — selects a side of a ∨ goal
26+
obtain ⟨a, b⟩ — destructures ∧ or ∃ hypotheses
27+
cases h with — splits on constructors (for inductive types, ∨, etc.)
28+
induction x with — performs structural induction
29+
simp [f] — simplifies using the defining equations of `f`
30+
omega — solves linear arithmetic over ℕ and ℤ
31+
calc ... — structured chain of equalities/inequalities
32+
-/
33+
34+
35+
-- ============================================================================
36+
-- Provided Definitions (DO NOT MODIFY)
37+
-- ============================================================================
38+
39+
/-! ### Custom list operations
40+
41+
We define our own list operations so you can prove properties about them
42+
from first principles, without relying on Lean's built-in library lemmas.
43+
You have implemented similar functions in Assignments 2 and 3, and now you
44+
will *prove* things about them.
45+
-/
46+
47+
def app {α : Type} : List α → List α → List α
48+
| [], ys => ys
49+
| x :: xs, ys => x :: app xs ys
50+
51+
def len {α : Type} : List α → Nat
52+
| [] => 0
53+
| _ :: xs => 1 + len xs
54+
55+
def naiveRev {α : Type} : List α → List α
56+
| [] => []
57+
| x :: xs => app (naiveRev xs) [x]
58+
59+
def myMap {α β : Type} (f : α → β) : List α → List β
60+
| [] => []
61+
| x :: xs => f x :: myMap f xs
62+
63+
/-! ### Binary tree type and operations -/
64+
65+
inductive BTree (α : Type) : Type where
66+
| empty : BTree α
67+
| node : α → BTree α → BTree α → BTree α
68+
deriving Repr
69+
70+
namespace BTree
71+
72+
def size : BTree α → Nat
73+
| .empty => 0
74+
| .node _ l r => 1 + l.size + r.size
75+
76+
def mirror : BTree α → BTree α
77+
| .empty => .empty
78+
| .node v l r => .node v r.mirror l.mirror
79+
80+
def depth : BTree α → Nat
81+
| .empty => 0
82+
| .node _ l r => 1 + max l.depth r.depth
83+
84+
def mapTree (f : α → β) : BTree α → BTree β
85+
| .empty => .empty
86+
| .node v l r => .node (f v) (l.mapTree f) (r.mapTree f)
87+
88+
def flatten : BTree α → List α
89+
| .empty => []
90+
| .node v l r => app l.flatten (app [v] r.flatten)
91+
92+
end BTree
93+
94+
/-! ### A custom Nat function -/
95+
96+
def double : Nat → Nat
97+
| 0 => 0
98+
| n + 1 => double n + 2
99+
100+
101+
-- ============================================================================
102+
-- Part 1: Tactic Warm-Up — Propositional Logic (20 points)
103+
-- ============================================================================
104+
105+
/-
106+
These exercises warm you up with the basic building-block tactics.
107+
Using induction here is overkill, careful use of intro, apply, exact,
108+
constructor, cases, obtain, left, and right is enough.
109+
-/
110+
111+
/- Problem 1.1 (5 points)
112+
Theorem: Transitivity of implication.
113+
-/
114+
theorem imp_trans (P Q R : Prop) : (P → Q) → (Q → R) → P → R := by
115+
sorry
116+
117+
118+
/- Problem 1.2 (5 points)
119+
Theorem: If P implies both Q and R, then P implies their conjunction.
120+
Hint: After introducing hypotheses, use `constructor` to split the ∧ goal
121+
into two separate subgoals.
122+
-/
123+
theorem imp_and_intro (P Q R : Prop) : (P → Q) → (P → R) → P → Q ∧ R := by
124+
sorry
125+
126+
127+
/- Problem 1.3 (5 points)
128+
Theorem: ∧ distributes over ∨ (left to right).
129+
Hint: First `obtain` the two parts of the ∧. Then `cases` on the ∨ part.
130+
-/
131+
theorem and_or_distrib (P Q R : Prop) :
132+
P ∧ (Q ∨ R) → (P ∧ Q) ∨ (P ∧ R) := by
133+
sorry
134+
135+
136+
/- Problem 1.4 (5 points)
137+
Provide a concrete existential witness.
138+
Hint: Use `exact ⟨witness, proof⟩`.
139+
-/
140+
theorem exists_witness : ∃ n : Nat, n * n + 3 * n + 2 = 12 := by
141+
sorry
142+
143+
144+
-- ============================================================================
145+
-- Part 2: Induction on Natural Numbers (20 points)
146+
-- ============================================================================
147+
148+
/-
149+
These exercises use induction on Nat to prove properties of the `double`
150+
function defined above. Remember the induction pattern:
151+
152+
induction n with
153+
| zero => ... -- base case: n = 0
154+
| succ n ih => ... -- inductive step: assuming `ih` for n, prove for n+1
155+
156+
Tip: After unfolding the definition with `simp [double]`, you can often close
157+
the arithmetic with `omega`.
158+
-/
159+
160+
/- Problem 2.1 (5 points)
161+
Theorem: Our custom `double` agrees with multiplication by 2.
162+
Hint: Induction on n, then `simp [double]` to unfold...
163+
-/
164+
theorem double_eq_two_mul (n : Nat) : double n = 2 * n := by
165+
sorry
166+
167+
168+
/- Problem 2.2 (5 points)
169+
Theorem: `double` distributes over addition.
170+
Hint: Think carefully about which variable to induct on.
171+
Recall that Lean defines addition by recursion on the second argument.
172+
-/
173+
theorem double_add (m n : Nat) : double (m + n) = double m + double n := by
174+
sorry
175+
176+
177+
/- Problem 2.3 (5 points)
178+
A concrete arithmetic fact using omega.
179+
Hint: You should not necessarily use induction.
180+
-/
181+
theorem nat_squeeze (n : Nat) (h₁ : n > 5) (h₂ : n < 10) :
182+
2 * n + 113 := by
183+
sorry
184+
185+
186+
/- Problem 2.4 (5 points)
187+
Theorem: If n is positive then double n is positive.
188+
Hint: Induction on n. In the zero case, the hypothesis `h : 0 > 0` is
189+
contradictory — `omega` will close it.
190+
-/
191+
theorem double_pos (n : Nat) (h : n > 0) : double n > 0 := by
192+
sorry
193+
194+
195+
-- ============================================================================
196+
-- Part 3: Induction on Lists (35 points)
197+
-- ============================================================================
198+
199+
/-
200+
Now we move to structural induction on lists. The pattern is:
201+
202+
induction xs with
203+
| nil => ... -- base case: xs = []
204+
| cons x xs ih => ... -- inductive step: assuming `ih` for xs
205+
206+
The key technique is: unfold the custom function with `simp [f]`, then
207+
use the inductive hypothesis `ih`, then (if needed) close with `omega`
208+
for arithmetic or `rfl` for reflexivity.
209+
210+
IMPORTANT: You may (and should!) use theorems you proved earlier in later
211+
proofs. For example, after proving `app_nil`, you can write `rw [app_nil]`
212+
in subsequent proofs.
213+
-/
214+
215+
/- Problem 3.1 (5 points)
216+
Theorem: Appending the empty list on the right is the identity.
217+
-/
218+
theorem app_nil {α : Type} (xs : List α) : app xs [] = xs := by
219+
sorry
220+
221+
222+
/- Problem 3.2 (8 points)
223+
Theorem: Append is associative.
224+
-/
225+
theorem app_assoc {α : Type} (xs ys zs : List α) :
226+
app (app xs ys) zs = app xs (app ys zs) := by
227+
sorry
228+
229+
230+
/- Problem 3.3 (7 points)
231+
Theorem: Length distributes over append.
232+
Hint: After `simp [...]`, you may need `omega`
233+
to handle the resulting arithmetic (i.e. associativity of +).
234+
-/
235+
theorem len_app {α : Type} (xs ys : List α) :
236+
len (app xs ys) = len xs + len ys := by
237+
sorry
238+
239+
240+
/- Problem 3.4 (7 points)
241+
Theorem: Map distributes over append.
242+
-/
243+
theorem myMap_app {α β : Type} (f : α → β) (xs ys : List α) :
244+
myMap f (app xs ys) = app (myMap f xs) (myMap f ys) := by
245+
sorry
246+
247+
248+
/- Problem 3.5 (8 points)
249+
Theorem: Reversing a list preserves its length.
250+
251+
This might be the hardest problem in Part 3: you must combine induction with a
252+
previously proven theorem.
253+
-/
254+
theorem len_naiveRev {α : Type} (xs : List α) :
255+
len (naiveRev xs) = len xs := by
256+
sorry
257+
258+
259+
-- ============================================================================
260+
-- Part 4: Induction on Binary Trees (30 points)
261+
-- ============================================================================
262+
263+
/-
264+
Structural induction on binary trees follows the same idea, but now the
265+
inductive type has *two* recursive children:
266+
267+
induction t with
268+
| empty => ... -- base case: the empty tree
269+
| node v l r ihl ihr => ... -- inductive step: two IHs!
270+
271+
As with lists, `simp [f, ihl, ihr]` is your main workhorse.
272+
-/
273+
274+
/- Problem 4.1 (8 points)
275+
Theorem: Mirroring a tree twice gives back the original tree (mirror is an involution).
276+
-/
277+
theorem mirror_mirror {α : Type} (t : BTree α) :
278+
t.mirror.mirror = t := by
279+
sorry
280+
281+
282+
/- Problem 4.2 (8 points)
283+
Theorem: Mirroring preserves the number of nodes.
284+
Hint: After `simp [...]`, you may need `omega` to handle the commutativity of addition
285+
(since mirror swaps left and right, the addition order changes).
286+
-/
287+
theorem size_mirror {α : Type} (t : BTree α) :
288+
t.mirror.size = t.size := by
289+
sorry
290+
291+
292+
/- Problem 4.3 (7 points)
293+
Theorem: Mapping the identity function over a tree changes nothing (functor identity law).
294+
-/
295+
theorem mapTree_id {α : Type} (t : BTree α) :
296+
BTree.mapTree id t = t := by
297+
sorry
298+
299+
300+
/- Problem 4.4 (7 points)
301+
Theorem: Mapping f after g is the same as mapping (f ∘ g) (functor composition law).
302+
Hint: On top of the expected tactics you'll use, you may also use `simp [Function.comp]`
303+
-/
304+
theorem mapTree_comp {α β γ : Type} (f : β → γ) (g : α → β) (t : BTree α) :
305+
BTree.mapTree f (BTree.mapTree g t) = BTree.mapTree (f ∘ g) t := by
306+
sorry
307+
308+
309+
-- ============================================================================
310+
-- Part 5: Calc Mode (15 points)
311+
-- ============================================================================
312+
313+
/-
314+
Calc mode lets you write proofs as readable chains of equalities (or
315+
inequalities). Each step needs a justification after `:= by`.
316+
317+
calc LHS
318+
= step₁ := by ...
319+
_ = step₂ := by ...
320+
_ = RHS := by ...
321+
-/
322+
323+
/- Problem 5.1 (7 points)
324+
Chain hypotheses together using calc.
325+
-/
326+
theorem calc_chain (a b c d : Nat)
327+
(h₁ : a = b + 3) (h₂ : b = c * 2) (h₃ : c = d + 1) :
328+
a = 2 * d + 5 := by
329+
sorry
330+
331+
332+
/- Problem 5.2 (8 points)
333+
Use calc mode together with previously proven list theorems.
334+
Hint: Use `rw [len_app]` for each step that distributes len over app.
335+
-/
336+
theorem len_app_three {α : Type} (xs ys zs : List α) :
337+
len (app (app xs ys) zs) = len xs + len ys + len zs := by
338+
sorry
339+
340+
341+
-- ============================================================================
342+
-- BONUS CHALLENGE (25 extra points)
343+
-- ============================================================================
344+
345+
/-!
346+
These problems are designed to be harder than the main assignment. They
347+
require you to chain multiple lemmas together and think carefully about
348+
what intermediate facts you need.
349+
350+
Both bonus problems concern `naiveRev` (our naive list reversal function).
351+
Bonus 1 is a key lemma, and Bonus 2 *depends* on it — if you solve Bonus 1,
352+
you may use it in Bonus 2.
353+
-/
354+
355+
/- BONUS Problem 1 (15 points)
356+
Theorem: Reversing distributes over append — but in *reverse order*.
357+
358+
Hint:
359+
- Base case: Use `app_nil` (from Problem 3.1).
360+
- Inductive case: Unfold `naiveRev` and `app` to get a goal about nested `app` calls.
361+
-/
362+
theorem naiveRev_app {α : Type} (xs ys : List α) :
363+
naiveRev (app xs ys) = app (naiveRev ys) (naiveRev xs) := by
364+
sorry
365+
366+
367+
/- BONUS Problem 2 (10 points)
368+
Theorem: Reversing a list twice gives back the original list.
369+
370+
Hint: In the inductive step, unfold `naiveRev` and apply `naiveRev_app` (Bonus 1!).
371+
-/
372+
theorem naiveRev_naiveRev {α : Type} (xs : List α) :
373+
naiveRev (naiveRev xs) = xs := by
374+
sorry
375+
376+
377+
-- ============================================================================
378+
-- END OF ASSIGNMENT
379+
-- ============================================================================
380+
381+
/-
382+
Grading Rubric:
383+
- Part 1 (20 points): Propositional logic warm-up
384+
- Part 2 (20 points): Natural number induction
385+
- Part 3 (35 points): List induction
386+
- Part 4 (30 points): Binary tree induction
387+
- Part 5 (15 points): Calc mode
388+
- Bonus (25 points): Reverse involution
389+
390+
Total: 120 points (145 with bonus)
391+
-/

0 commit comments

Comments
 (0)