Skip to content

Commit 3841992

Browse files
author
Will Bradley
committed
Complete Homework 2.4 #5(b)
1 parent 081e656 commit 3841992

File tree

1 file changed

+153
-1
lines changed

1 file changed

+153
-1
lines changed

LogicFormalization/Chapter2/Section4/Homework.lean

Lines changed: 153 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import LogicFormalization.Chapter2.Section4.Term
22
import Mathlib.Data.Fin.VecNotation
33
import Mathlib.Tactic.Linarith.Frontend
4+
import Mathlib.Tactic.Ring
45

56
namespace Homeworks
67

@@ -105,10 +106,161 @@ theorem not_exists_nat_rig_term₁ : ¬∃ (t: Term .Rig) (x: Var) (hx: AreVarsF
105106
end a
106107

107108

109+
section b
110+
111+
/-- Represents polynomials with coefficients from `ℕ`.-/
112+
inductive Poly
113+
| const: ℕ → Poly
114+
| var
115+
| add: Poly → Poly → Poly
116+
| mul: Poly → Poly → Poly
117+
118+
namespace Poly
119+
120+
def eval: Poly → ℕ → ℕ
121+
| .const a, _ => a
122+
| .var, n => n
123+
| .add p q, n => p.eval n + q.eval n
124+
| .mul p q, n => p.eval n * q.eval n
125+
126+
lemma eval_mono: ∀ {p: Poly}, Monotone p.eval
127+
| .const _ => fun _ _ _ => Nat.le_refl _
128+
| .var => fun _ _ => id
129+
| .add _ _ => Monotone.add eval_mono eval_mono
130+
| .mul _
131+
_ => Monotone.mul' eval_mono eval_mono
132+
133+
/-- Degree of a polynomial -/
134+
def deg: Poly → ℕ
135+
| .const _ => 0
136+
| .var => 1
137+
| .add p q => max (deg p) (deg q)
138+
| .mul p q => deg p + deg q
139+
140+
/-- Polynomials are homogenous. -/
141+
lemma eval_mul_le {a n} (ha: a ≠ 0) : ∀ {p: Poly}, eval p (a * n) ≤ a^(deg p) * eval p n
142+
| .const c | .var => by simp [eval, deg]
143+
| .add q r => calc eval (add q r) (a * n)
144+
_ = eval q (a * n) + eval r (a * n) := rfl
145+
_ ≤ a^(deg q) * eval q n + a^(deg r) * eval r n :=
146+
Nat.add_le_add (eval_mul_le ha) (eval_mul_le ha)
147+
_ ≤ _ := by
148+
apply (Nat.le_or_ge (deg q) (deg r)).elim
149+
· intro h
150+
simp only [deg, h, sup_of_le_right, eval, Nat.mul_add, add_le_add_iff_right]
151+
apply Nat.mul_le_mul_right
152+
apply Nat.pow_le_pow_right <;> simp [*, Nat.zero_lt_of_ne_zero]
153+
· intro h
154+
simp only [deg, h, sup_of_le_left, eval, Nat.mul_add, add_le_add_iff_left]
155+
apply Nat.mul_le_mul_right
156+
apply Nat.pow_le_pow_right <;> simp [*, Nat.zero_lt_of_ne_zero]
157+
| .mul q r => calc eval (mul q r) (a * n)
158+
_ = eval q (a * n) * eval r (a * n) := rfl
159+
_ ≤ (a^(deg q) * eval q n) * (a^(deg r) * eval r n) :=
160+
Nat.mul_le_mul (eval_mul_le ha) (eval_mul_le ha)
161+
_ = _ := by simp [deg, eval]; ring
162+
163+
/-- Roughly speaking, use `eval_mul_le` to go from `p(n)`
164+
to `p(2 * n / 2)` to `2^deg(p) p(n)`. This is complicated
165+
by the fact that we are in `ℕ` and lack clean division.
166+
We end up using `⌈n/2⌉` instead. -/
167+
lemma eval_le_mul_eval_half {p: Poly} {n: ℕ}:
168+
eval p n ≤ 2^(deg p) * eval p ((n + 1) / 2) := calc _
169+
_ ≤ eval p (2 * ((n + 1) / 2)) := eval_mono (by omega)
170+
_ ≤ _ := eval_mul_le (by decide)
171+
172+
/-- p(n) does not converge to 2^n as n → ∞ -/
173+
lemma eval_diverges_from_two_pow: ∀ p m, ∃ N, ∀ n ≥ N, m * eval p n < 2^n
174+
| .const c, m => ⟨m * c, fun n hn => Nat.lt_of_le_of_lt hn Nat.lt_two_pow_self⟩
175+
| .var, m => ⟨m + 1, fun n hn =>
176+
have: m ≤ n - 1 := Nat.le_sub_one_of_lt hn
177+
Nat.lt_of_le_of_lt
178+
(Nat.mul_le_mul_right n this) mul_pred_self_lt_two_pow⟩
179+
| .add q r, m =>
180+
let ⟨Nq, hq⟩ := eval_diverges_from_two_pow q (2 * m)
181+
let ⟨Nr, hr⟩ := eval_diverges_from_two_pow r (2 * m)
182+
⟨max Nq Nr, fun n hn => by
183+
replace hu := hq n (le_of_max_le_left hn)
184+
replace hv := hr n (le_of_max_le_right hn)
185+
have := Nat.add_lt_add hu hv
186+
simp_rw [Nat.two_mul, Nat.add_mul, ←Nat.two_mul, ←Nat.mul_add] at this
187+
exact Nat.lt_of_mul_lt_mul_left this⟩
188+
| .mul q r, m =>
189+
-- this one is trickier. we make use of the homogeneity property (`eval_mul_le`)
190+
let ⟨Nq, hq⟩ := eval_diverges_from_two_pow q (m * 2^(deg q))
191+
let ⟨Nr, hr⟩ := eval_diverges_from_two_pow r (2 * 2^(deg r))
192+
⟨(max Nq Nr) * 2, fun n hn => by
193+
replace hq := hq ((n + 1) / 2) (by omega)
194+
replace hr := hr ((n + 1) / 2) (by omega)
195+
replace hr: 2 ^ r.deg * r.eval ((n + 1) / 2) < 2 ^ ((n + 1) / 2 - 1) := by
196+
simp only [Nat.mul_assoc] at hr
197+
apply Nat.lt_of_mul_lt_mul_left (a := 2)
198+
rw [←Nat.pow_succ']
199+
apply Nat.lt_of_lt_of_le hr
200+
apply Nat.pow_le_pow_right (by decide)
201+
omega
202+
203+
calc m * eval (mul q r) n
204+
_ = m * (eval q n * eval r n) := rfl
205+
_ ≤ m * ((2^(deg q) * eval q ((n + 1) / 2)) * (2^(deg r) * eval r ((n + 1) / 2))) := by
206+
apply Nat.mul_le_mul_left
207+
apply Nat.mul_le_mul <;> exact eval_le_mul_eval_half
208+
_ = (m * 2^(deg q) * eval q ((n + 1) / 2)) * (2^(deg r) * eval r ((n + 1) / 2)) := by ring
209+
_ < (2 ^ ((n + 1) / 2)) * (2 ^ ((n + 1) / 2 - 1)) := Nat.mul_lt_mul'' hq hr
210+
_ = 2 ^ ((n + 1) / 2 + ((n + 1) / 2 - 1)) := (Nat.pow_add ..).symm
211+
_ ≤ 2 ^ n := Nat.pow_le_pow_right (by decide) (by omega)⟩
212+
where
213+
mul_pred_self_lt_two_pow : ∀ {n: ℕ}, (n - 1) * n < 2^n
214+
| 0 => by decide
215+
| k + 1 => calc (k + 1 - 1) * (k + 1)
216+
_ = k * (k + 1) := rfl
217+
_ = (k - 1) * k + 2 * k := by
218+
simp only [Nat.mul_succ, Nat.sub_mul]
219+
have := Nat.sub_add_cancel (Nat.le_mul_self k)
220+
omega
221+
_ < 2 ^ k + 2 * k :=
222+
Nat.add_lt_add_right mul_pred_self_lt_two_pow _
223+
_ ≤ 2 ^ (k + 1) := by
224+
simp only [Nat.pow_succ, Nat.mul_two, add_le_add_iff_left]
225+
have: (k - 1) + 12^(k-1) := Nat.lt_two_pow_self
226+
match k with
227+
| 0 => decide
228+
| l + 1 =>
229+
rw [Nat.add_sub_cancel] at this
230+
omega
231+
232+
/-- Convert one of the `L`-terms to a `Poly`. -/
233+
def ofTerm (t: Term .Rig) {x: Var} (hx: AreVarsFor ![x] t):
234+
{ p // ∀ n, interp t 𝒩 hx ![n] = eval p n } :=
235+
match t with
236+
| .var _ => ⟨.var, fun n => by simp [interp, eval]⟩
237+
| .app .zero _ => ⟨.const 0, fun n => rfl⟩
238+
| .app .one _ => ⟨.const 1, fun n => rfl⟩
239+
| .app .add ts =>
240+
let ⟨a, ha⟩ := ofTerm (ts 0) (.ofApp hx 0)
241+
let ⟨b, hb⟩ := ofTerm (ts 1) (.ofApp hx 1)
242+
⟨.add a b, fun n => by simp only [eval, ←ha, ←hb]; rfl⟩
243+
| .app .mul ts =>
244+
let ⟨a, ha⟩ := ofTerm (ts 0) (.ofApp hx 0)
245+
let ⟨b, hb⟩ := ofTerm (ts 1) (.ofApp hx 1)
246+
⟨.mul a b, fun n => by simp only [eval, ←ha, ←hb]; rfl⟩
247+
248+
end Poly
249+
250+
108251
/-- 2.4 #5 (b) -/
109252
theorem not_exists_nat_rig_term₂ : ¬∃ (t: Term .Rig) (x: Var) (hx: AreVarsFor ![x] t),
110253
∀ n, interp t 𝒩 hx ![n] = 2^n :=
111-
sorry
254+
fun ⟨t, x, hx, h⟩ =>
255+
let ⟨p, hp⟩ := Poly.ofTerm t hx
256+
have ⟨N, hN⟩ := Poly.eval_diverges_from_two_pow p 17
257+
by {
258+
have := hN N (Nat.le_refl N)
259+
rw [←h N, hp N] at this
260+
omega
261+
}
262+
263+
end b
112264

113265
open Structure in
114266
/-- 2.4 #5 (c). The only substructure of `𝒩` is `𝒩` itself. -/

0 commit comments

Comments
 (0)