import Mathlib.Tactic.NormNum import Mathlib.Data.Real.Basic import Mathlib.Tactic.SlimCheck namespace Tactic namespace Approx def RoundDown (a b : ℤ) : Prop := 2 * b ≤ a #align tactic.approx.round_down Tactic.Approx.RoundDown def RoundUp (a b : ℤ) : Prop := a ≤ 2 * b #align tactic.approx.round_up Tactic.Approx.RoundUp theorem RoundDown.weak {a b a' b'} (h : RoundDown a b) (ha : a ≤ a') (hb : b' ≤ b) : RoundDown a' b' := ((mul_le_mul_left two_pos (α := ℤ)).2 hb).trans <| le_trans h ha #align tactic.approx.round_down.weak Tactic.Approx.RoundDown.weak theorem RoundUp.weak {a b a' b'} (h : RoundUp a b) (ha : a' ≤ a) (hb : b ≤ b') : RoundUp a' b' := ha.trans <| le_trans h <| (mul_le_mul_left two_pos (α := ℤ)).2 hb #align tactic.approx.round_up.weak Tactic.Approx.RoundUp.weak theorem RoundDown.zero : RoundDown 0 0 := by unfold RoundDown; decide #align tactic.approx.round_down.zero Tactic.Approx.RoundDown.zero theorem RoundDown.one : RoundDown 1 0 := by unfold RoundDown; decide #align tactic.approx.round_down.one Tactic.Approx.RoundDown.one theorem RoundDown.neg_one : RoundDown (-1) (-1) := by unfold RoundDown; decide #align tactic.approx.round_down.neg_one Tactic.Approx.RoundDown.neg_one theorem RoundDown.bit0_pos (a) : RoundDown (bit0 a) a := (bit0_eq_two_mul _).ge #align tactic.approx.round_down.bit0_pos Tactic.Approx.RoundDown.bit0_pos theorem RoundDown.bit0_neg (a) : RoundDown (-bit0 a) (-a) := by rw [← _root_.bit0_neg]; apply RoundDown.bit0_pos #align tactic.approx.round_down.bit0_neg Tactic.Approx.RoundDown.bit0_neg theorem RoundDown.bit1_pos (a) : RoundDown (bit1 a) a := sorry -- (RoundDown.bit0_pos a).weak (NormNum.le_bit0_bit1 _ _ le_rfl) le_rfl #align tactic.approx.round_down.bit1_pos Tactic.Approx.RoundDown.bit1_pos theorem RoundDown.bit1_neg {a b} (h : a + 1 = b) : RoundDown (-bit1 a) (-b) := by simp [RoundDown, ← bit0_eq_two_mul, bit0_neg] sorry -- apply NormNum.le_bit1_bit0; exact_mod_cast h.le #align tactic.approx.round_down.bit1_neg Tactic.Approx.RoundDown.bit1_neg theorem RoundUp.zero : RoundUp 0 0 := by unfold RoundUp; decide #align tactic.approx.round_up.zero Tactic.Approx.RoundUp.zero theorem RoundUp.one : RoundUp 1 1 := by unfold RoundUp; decide #align tactic.approx.round_up.one Tactic.Approx.RoundUp.one theorem RoundUp.neg_one : RoundUp (-1) 0 := by unfold RoundUp; decide #align tactic.approx.round_up.neg_one Tactic.Approx.RoundUp.neg_one theorem RoundUp.bit0_pos (a) : RoundUp (bit0 a) a := (bit0_eq_two_mul _).le #align tactic.approx.round_up.bit0_pos Tactic.Approx.RoundUp.bit0_pos theorem RoundUp.bit0_neg (a) : RoundUp (-bit0 a) (-a) := by rw [← _root_.bit0_neg]; apply RoundUp.bit0_pos #align tactic.approx.round_up.bit0_neg Tactic.Approx.RoundUp.bit0_neg theorem RoundUp.bit1_pos {a b} (h : a + 1 = b) : RoundUp (bit1 a) b := by simp [RoundUp, ← bit0_eq_two_mul] sorry -- apply NormNum.le_bit1_bit0; exact_mod_cast h.le #align tactic.approx.round_up.bit1_pos Tactic.Approx.RoundUp.bit1_pos theorem RoundUp.bit1_neg (a) : RoundUp (-bit1 a) (-a) := sorry -- (RoundUp.bit0_neg a).weak (neg_le_neg <| NormNum.le_bit0_bit1 _ _ le_rfl) le_rfl #align tactic.approx.round_up.bit1_neg Tactic.Approx.RoundUp.bit1_neg def Approx (n lo hi : ℤ) (x : ℝ) : Prop := (lo / 2 ^ n : ℝ) ≤ x ∧ x ≤ hi / 2 ^ n #align tactic.approx.approx Tactic.Approx.Approx theorem bit0_neg (a : ℤ) : bit0 (-a) = -bit0 a := _root_.bit0_neg _ #align tactic.approx.bit0_neg Tactic.Approx.bit0_neg theorem Approx.up' {n lo hi lo' hi' : ℤ} {x : ℝ} (hlo : 2 * lo = lo') (hhi : 2 * hi = hi') : Approx (n + 1) lo' hi' x ↔ Approx n lo hi x := by simp [Approx, ← hlo, ← hhi, zpow_add_one₀ (two_ne_zero' ℝ), mul_comm, fun a b => mul_div_mul_left a b (two_ne_zero' ℝ)] sorry #align tactic.approx.approx.up' Tactic.Approx.Approx.up' theorem Approx.le {n lo hi : ℤ} {x : ℝ} (h : Approx n lo hi x) : lo ≤ hi := by rw [← @Int.cast_le ℝ, ← div_le_div_right (zpow_pos_of_pos (two_pos : 0 < (2 : ℝ)) n)] exact h.1.trans h.2 #align tactic.approx.approx.le Tactic.Approx.Approx.le theorem Approx.weak {n lo hi lo' hi' : ℤ} {x : ℝ} (h : Approx n lo hi x) (hlo : lo' ≤ lo) (hhi : hi ≤ hi') : Approx n lo' hi' x := by rw [← @Int.cast_le ℝ, ← div_le_div_right (zpow_pos_of_pos (two_pos : 0 < (2 : ℝ)) n)] at hlo hhi exact ⟨hlo.trans h.1, h.2.trans hhi⟩ #align tactic.approx.approx.weak Tactic.Approx.Approx.weak theorem Approx.to_le {n xlo xhi ylo yhi : ℤ} {x y : ℝ} (hx : Approx n xlo xhi x) (hy : Approx n ylo yhi y) (h : xhi ≤ ylo) : x ≤ y := haveI n0 := zpow_pos_of_pos (two_pos : 0 < (2 : ℝ)) n hx.2.trans (((div_le_div_right n0).2 (Int.cast_le.2 h)).trans hy.1) #align tactic.approx.approx.to_le Tactic.Approx.Approx.to_le theorem Approx.to_lt {n xlo xhi ylo yhi : ℤ} {x y : ℝ} (hx : Approx n xlo xhi x) (hy : Approx n ylo yhi y) (h : xhi < ylo) : x < y := haveI n0 := zpow_pos_of_pos (two_pos : 0 < (2 : ℝ)) n hx.2.trans_lt (((div_lt_div_right n0).2 (Int.cast_lt.2 h)).trans_le hy.1) #align tactic.approx.approx.to_lt Tactic.Approx.Approx.to_lt theorem Approx.to_lt₂ {n xlo xhi ylo yhi zlo zhi : ℤ} {x y z : ℝ} (hx : Approx n xlo xhi x) (hy : Approx n ylo yhi y) (hz : Approx n zlo zhi z) (h₁ : xhi < ylo) (h₂ : yhi < zlo) : x < y ∧ y < z := ⟨hx.to_lt hy h₁, hy.to_lt hz h₂⟩ #align tactic.approx.approx.to_lt₂ Tactic.Approx.Approx.to_lt₂ theorem Approx.of_exact {n a : ℤ} {x x' : ℝ} (hx : Approx n a a x) (h : (a : ℝ) / 2 ^ n = x') : x = x' := (le_antisymm hx.2 hx.1).trans h #align tactic.approx.approx.of_exact Tactic.Approx.Approx.of_exact theorem Approx.approx {n lo hi lo' hi' zlo zhi : ℤ} {x y z : ℝ} (hx : Approx n lo hi x) (xy : |x - y| ≤ z) (hz : Approx n zlo zhi z) (hlo : lo - zhi = lo') (hhi : hi + zhi = hi') : Approx n lo' hi' y := by obtain ⟨h₁, h₂⟩ := abs_sub_le_iff.1 (xy.trans hz.2) constructor · rw [← hlo, Int.cast_sub, ← div_sub_div_same] exact (sub_le_sub_right hx.1 _).trans (sub_le_comm.1 h₁) · rw [← hhi, Int.cast_add, ← div_add_div_same] refine' le_trans (sub_le_iff_le_add'.1 h₂) (add_le_add_right hx.2 _) #align tactic.approx.approx.approx Tactic.Approx.Approx.approx theorem Approx.of_integer {n ll lo hi hh z zl zr : ℤ} {x : ℝ} (hx : Approx n lo hi x) (ezl : z - 1 = zl) (ezr : z + 1 = zr) (hzl : Approx n ll ll zl) (hzr : Approx n hh hh zr) (h₁ : ll < lo) (h₂ : hi < hh) (h : ∃ z : ℤ, x = z) : x = z := by obtain ⟨rfl, rfl, ⟨a, rfl⟩⟩ := ezl, ezr, h congr; exact le_antisymm (Int.lt_add_one_iff.1 (Int.cast_lt.1 (hx.to_lt hzr h₂))) (Int.sub_one_lt_iff.1 (Int.cast_lt.1 (hzl.to_lt hx h₁))) #align tactic.approx.approx.of_integer Tactic.Approx.Approx.of_integer theorem Approx.up {n lo hi lo' hi' : ℤ} {x : ℝ} (h : Approx n lo hi x) (hlo : bit0 lo = lo') (hhi : bit0 hi = hi') : Approx (n + 1) lo' hi' x := by rw [bit0_eq_two_mul] at hlo hhi; exact (Approx.up' hlo hhi).2 h #align tactic.approx.approx.up Tactic.Approx.Approx.up theorem Approx.down {n lo hi lo' hi' : ℤ} {x : ℝ} (h : Approx n lo hi x) (hlo : RoundDown lo lo') (hhi : RoundUp hi hi') : Approx (n - 1) lo' hi' x := by have := h.weak hlo hhi rwa [← sub_add_cancel n 1, Approx.up' rfl rfl] at this #align tactic.approx.approx.down Tactic.Approx.Approx.down theorem Approx.assume {n ll lh hl hh : ℤ} {xl x xh : ℝ} (hxl : Approx n ll lh xl) (hxh : Approx n hl hh xh) (hlo : xl ≤ x) (hhi : x ≤ xh) : Approx n ll hh x := ⟨le_trans hxl.1 hlo, le_trans hhi hxh.2⟩ #align tactic.approx.approx.assume Tactic.Approx.Approx.assume theorem Approx.eq_zero (n) {x} : Approx n 0 0 x ↔ x = 0 := by simp [Approx, le_antisymm_iff, and_comm] #align tactic.approx.approx.eq_zero Tactic.Approx.Approx.eq_zero theorem Approx.zero (n) : Approx n 0 0 0 := (Approx.eq_zero _).2 rfl #align tactic.approx.approx.zero Tactic.Approx.Approx.zero theorem Approx.const {a : ℤ} {x : ℝ} (h : ↑a = x) : Approx 0 a a x := by simp [Approx, ← h] #align tactic.approx.approx.const Tactic.Approx.Approx.const theorem Approx.neg {n lo hi lo' hi' : ℤ} {x : ℝ} (h : Approx n lo hi x) (hlo : -lo = hi') (hhi : -hi = lo') : Approx n lo' hi' (-x) := by simpa [Approx, ← hlo, ← hhi, neg_div, and_comm] using h #align tactic.approx.approx.neg Tactic.Approx.Approx.neg theorem Approx.add {n xlo xhi ylo yhi lo hi : ℤ} {x y : ℝ} (hx : Approx n xlo xhi x) (hy : Approx n ylo yhi y) (hlo : xlo + ylo = lo) (hhi : xhi + yhi = hi) : Approx n lo hi (x + y) := by simpa [Approx, ← hlo, ← hhi, add_div] using And.intro (add_le_add hx.1 hy.1) (add_le_add hx.2 hy.2) #align tactic.approx.approx.add Tactic.Approx.Approx.add theorem Approx.sub {n xlo xhi ylo yhi lo hi : ℤ} {x y : ℝ} (hx : Approx n xlo xhi x) (hy : Approx n ylo yhi y) (hlo : xlo - yhi = lo) (hhi : xhi - ylo = hi) : Approx n lo hi (x - y) := Approx.add hx (Approx.neg hy rfl rfl) hlo hhi #align tactic.approx.approx.sub Tactic.Approx.Approx.sub def MulBound (xlo xhi ylo yhi lo hi : ℤ) : Prop := xlo ≤ xhi → ylo ≤ yhi → (lo ≤ xlo * ylo ∧ xlo * ylo ≤ hi) ∧ (lo ≤ xlo * yhi ∧ xlo * yhi ≤ hi) ∧ (lo ≤ xhi * ylo ∧ xhi * ylo ≤ hi) ∧ (lo ≤ xhi * yhi ∧ xhi * yhi ≤ hi) #align tactic.approx.mul_bound Tactic.Approx.MulBound theorem MulBound.exact {x y z : ℤ} (h : x * y = z) : MulBound x x y y z z := fun hx hy => by suffices h; exact ⟨h, h, h, h⟩; exact ⟨h.ge, h.le⟩ #align tactic.approx.mul_bound.exact Tactic.Approx.MulBound.exact theorem MulBound.pos_pos {xlo xhi ylo yhi lo hi : ℤ} (x0 : 0 ≤ xlo) (y0 : 0 ≤ ylo) (hlo : xlo * ylo = lo) (hhi : xhi * yhi = hi) : MulBound xlo xhi ylo yhi lo hi := fun hx hy => by have lll := hlo.ge; have hhh := hhi.le have llh := lll.trans (mul_le_mul_of_nonneg_left hy x0) have lhl := lll.trans (mul_le_mul_of_nonneg_right hx y0) have lhh := lhl.trans (mul_le_mul_of_nonneg_left hy (x0.trans hx)) have hhl := (mul_le_mul_of_nonneg_left hy (x0.trans hx)).trans hhh have hlh := (mul_le_mul_of_nonneg_right hx (y0.trans hy)).trans hhh have hll := (mul_le_mul_of_nonneg_right hx y0).trans hhl exact ⟨⟨lll, hll⟩, ⟨llh, hlh⟩, ⟨lhl, hhl⟩, ⟨lhh, hhh⟩⟩ #align tactic.approx.mul_bound.pos_pos Tactic.Approx.MulBound.pos_pos theorem MulBound.pos_neg {xlo xhi ylo yhi lo hi : ℤ} (x0 : 0 ≤ xlo) (y0 : yhi ≤ 0) (hlo : xhi * ylo = lo) (hhi : xlo * yhi = hi) : MulBound xlo xhi ylo yhi lo hi := fun hx hy => by have lhl := hlo.ge; have hlh := hhi.le have lll := lhl.trans (mul_le_mul_of_nonpos_right hx (hy.trans y0)) have llh := lll.trans (mul_le_mul_of_nonneg_left hy x0) have lhh := lhl.trans (mul_le_mul_of_nonneg_left hy (x0.trans hx)) have hhh := (mul_le_mul_of_nonpos_right hx y0).trans hlh have hhl := (mul_le_mul_of_nonneg_left hy (x0.trans hx)).trans hhh have hll := (mul_le_mul_of_nonneg_left hy x0).trans hlh exact ⟨⟨lll, hll⟩, ⟨llh, hlh⟩, ⟨lhl, hhl⟩, ⟨lhh, hhh⟩⟩ #align tactic.approx.mul_bound.pos_neg Tactic.Approx.MulBound.pos_neg theorem MulBound.neg_pos {xlo xhi ylo yhi lo hi : ℤ} (x0 : xhi ≤ 0) (y0 : 0 ≤ ylo) (hlo : xlo * yhi = lo) (hhi : xhi * ylo = hi) : MulBound xlo xhi ylo yhi lo hi := fun hx hy => by have llh := hlo.ge; have hhl := hhi.le have lll := llh.trans (mul_le_mul_of_nonpos_left hy (hx.trans x0)) have lhl := lll.trans (mul_le_mul_of_nonneg_right hx y0) have lhh := llh.trans (mul_le_mul_of_nonneg_right hx (y0.trans hy)) have hhh := (mul_le_mul_of_nonpos_left hy x0).trans hhl have hlh := (mul_le_mul_of_nonneg_right hx (y0.trans hy)).trans hhh have hll := (mul_le_mul_of_nonneg_right hx y0).trans hhl exact ⟨⟨lll, hll⟩, ⟨llh, hlh⟩, ⟨lhl, hhl⟩, ⟨lhh, hhh⟩⟩ #align tactic.approx.mul_bound.neg_pos Tactic.Approx.MulBound.neg_pos theorem MulBound.neg_neg {xlo xhi ylo yhi lo hi : ℤ} (x0 : xhi ≤ 0) (y0 : yhi ≤ 0) (hlo : xhi * yhi = lo) (hhi : xlo * ylo = hi) : MulBound xlo xhi ylo yhi lo hi := fun hx hy => by have lhh := hlo.ge; have hll := hhi.le have lhl := lhh.trans (mul_le_mul_of_nonpos_left hy x0) have llh := lhh.trans (mul_le_mul_of_nonpos_right hx y0) have lll := llh.trans (mul_le_mul_of_nonpos_left hy (hx.trans x0)) have hlh := (mul_le_mul_of_nonpos_left hy (hx.trans x0)).trans hll have hhl := (mul_le_mul_of_nonpos_right hx (hy.trans y0)).trans hll have hhh := (mul_le_mul_of_nonpos_right hx y0).trans hlh exact ⟨⟨lll, hll⟩, ⟨llh, hlh⟩, ⟨lhl, hhl⟩, ⟨lhh, hhh⟩⟩ #align tactic.approx.mul_bound.neg_neg Tactic.Approx.MulBound.neg_neg theorem MulBound.mk {xlo xhi ylo yhi ll lh hl hh lo hi : ℤ} (ell : xlo * ylo = ll) (elh : xlo * yhi = lh) (ehl : xhi * ylo = hl) (ehh : xhi * yhi = hh) (lll : lo ≤ ll) (hll : ll ≤ hi) (llh : lo ≤ lh) (hlh : lh ≤ hi) (lhl : lo ≤ hl) (hhl : hl ≤ hi) (lhh : lo ≤ hh) (hhh : hh ≤ hi) : MulBound xlo xhi ylo yhi lo hi := fun hx hy => by rw [ell, elh, ehl, ehh] exact ⟨⟨lll, hll⟩, ⟨llh, hlh⟩, ⟨lhl, hhl⟩, ⟨lhh, hhh⟩⟩ #align tactic.approx.mul_bound.mk Tactic.Approx.MulBound.mk theorem Approx.mul {m n xlo xhi ylo yhi lo hi : ℤ} {x y : ℝ} (hx : Approx m xlo xhi x) (hy : Approx n ylo yhi y) (hbd : MulBound xlo xhi ylo yhi lo hi) : Approx (m + n) lo hi (x * y) := by obtain ⟨⟨lll, hll⟩, ⟨llh, hlh⟩, ⟨lhl, hhl⟩, ⟨lhh, hhh⟩⟩ := hbd hx.le hy.le have : ∀ a b : ℤ, (↑(a * b) : ℝ) / 2 ^ (m + n) = a / 2 ^ m * (b / 2 ^ n) := by intros; rw [zpow_add₀ (two_ne_zero' ℝ), Int.cast_mul, mul_div_mul_comm] rw [← @Int.cast_le ℝ, ← div_le_div_right (zpow_pos_of_pos (two_pos : 0 < (2 : ℝ)) (m + n)), this] at lll hll llh hlh lhl hhl lhh hhh obtain x0 | x0 := le_total x 0 <;> constructor · refine' le_trans _ (mul_le_mul_of_nonpos_left hy.2 x0) obtain y0 | y0 := le_total ((yhi : ℝ) / 2 ^ n) 0 · exact le_trans lhh (mul_le_mul_of_nonpos_right hx.2 y0) · exact le_trans llh (mul_le_mul_of_nonneg_right hx.1 y0) · refine' le_trans (mul_le_mul_of_nonpos_left hy.1 x0) _ obtain y0 | y0 := le_total ((ylo : ℝ) / 2 ^ n) 0 · exact le_trans (mul_le_mul_of_nonpos_right hx.1 y0) hll · exact le_trans (mul_le_mul_of_nonneg_right hx.2 y0) hhl · refine' le_trans _ (mul_le_mul_of_nonneg_left hy.1 x0) obtain y0 | y0 := le_total ((ylo : ℝ) / 2 ^ n) 0 · exact le_trans lhl (mul_le_mul_of_nonpos_right hx.2 y0) · exact le_trans lll (mul_le_mul_of_nonneg_right hx.1 y0) · refine' le_trans (mul_le_mul_of_nonneg_left hy.2 x0) _ obtain y0 | y0 := le_total ((yhi : ℝ) / 2 ^ n) 0 · exact le_trans (mul_le_mul_of_nonpos_right hx.1 y0) hlh · exact le_trans (mul_le_mul_of_nonneg_right hx.2 y0) hhh #align tactic.approx.approx.mul Tactic.Approx.Approx.mul theorem Approx.div {m n xlo xhi ylo yhi lo hi : ℤ} {x y : ℝ} (hx : Approx m xlo xhi x) (hy : Approx n ylo yhi y⁻¹) (hbd : MulBound xlo xhi ylo yhi lo hi) : Approx (m + n) lo hi (x / y) := Approx.mul hx hy hbd #align tactic.approx.approx.div Tactic.Approx.Approx.div theorem Approx.inv_lem {m n lo hi lo' hi' : ℤ} {x p : ℝ} (hx : Approx m lo hi x) (hp : p = 2 ^ (m + n)) (H : 0 < lo ∧ p ≤ ↑(lo * hi') ∧ ↑(hi * lo') ≤ p ∨ hi < 0 ∧ p ≤ ↑(hi * lo') ∧ ↑(lo * hi') ≤ p) : Approx n lo' hi' x⁻¹ := by have two_pos := (two_pos : 0 < (2 : ℝ)) rw [zpow_add₀ two_pos.ne'] at hp have mn0 : (0 : ℝ) < 2 ^ m * 2 ^ n := mul_pos (zpow_pos_of_pos two_pos _) (zpow_pos_of_pos two_pos _) obtain ⟨x0, hlo, hhi⟩ | ⟨x0, hlo, hhi⟩ := H <;> rw [Int.cast_mul, hp] at hlo hhi <;> rw [← div_le_one mn0, ← div_mul_div_comm] at hhi <;> rw [← one_le_div mn0, ← div_mul_div_comm] at hlo <;> rw [← @Int.cast_lt ℝ, ← div_lt_div_right (zpow_pos_of_pos two_pos m), Int.cast_zero, zero_div] at x0 · have x0' := x0.trans_le hx.1; constructor · obtain lo0 | lo0 := le_total ((lo' : ℝ) / 2 ^ n) 0 · exact le_trans lo0 (inv_pos.2 x0').le rw [← one_div, le_div_iff' x0'] exact le_trans (mul_le_mul_of_nonneg_right hx.2 lo0) hhi · have hi0 : 0 ≤ (hi' : ℝ) / 2 ^ n := by rw [← div_le_iff' x0, one_div] at hlo exact le_trans (inv_nonneg.2 x0.le) hlo rw [← one_div, div_le_iff' x0'] exact le_trans hlo (mul_le_mul_of_nonneg_right hx.1 hi0) · have x0' := hx.2.trans_lt x0; constructor · have lo0 : (lo' : ℝ) / 2 ^ n ≤ 0 := by rw [← le_div_iff_of_neg' x0, one_div] at hlo exact le_trans hlo (inv_nonpos.2 x0.le) rw [← one_div, le_div_iff_of_neg' x0'] refine' le_trans hlo (mul_le_mul_of_nonpos_right hx.2 lo0) · obtain hi0 | hi0 := le_total 0 ((hi' : ℝ) / 2 ^ n) · exact le_trans (inv_lt_zero.2 x0').le hi0 rw [← one_div, div_le_iff_of_neg' x0'] exact le_trans (mul_le_mul_of_nonpos_right hx.1 hi0) hhi #align tactic.approx.approx.inv_lem Tactic.Approx.Approx.inv_lem theorem Approx.inv_lem' {m n lo hi lo' hi' lh hl p2 : ℤ} {x : ℝ} {p : ℕ} (hx : Approx m lo hi x) (hp : (p : ℤ) = m + n) (hp2 : 2 ^ p = p2) (hlh : lo * hi' = lh) (hhl : hi * lo' = hl) (H : 0 < lo ∧ p2 ≤ lh ∧ hl ≤ p2 ∨ hi < 0 ∧ p2 ≤ hl ∧ lh ≤ p2) : Approx n lo' hi' x⁻¹ := by substs hp2 hlh hhl have : ((2 ^ p : ℤ) : ℝ) = 2 ^ (m + n) := by rw [← hp]; norm_cast exact Approx.inv_lem hx this (by simpa only [Int.cast_le] using H) #align tactic.approx.approx.inv_lem' Tactic.Approx.Approx.inv_lem' nonrec theorem Approx.inv_zero {m n : ℤ} {x : ℝ} (hx : Approx m 0 0 x) : Approx n 0 0 x⁻¹ := by simp only [(Approx.eq_zero _).1 hx, inv_zero, Approx.zero] #align tactic.approx.approx.inv_zero Tactic.Approx.Approx.inv_zero theorem Approx.inv_pos {m n lo hi lo' hi' lh hl p2 : ℤ} {x : ℝ} {p : ℕ} (hx : Approx m lo hi x) (hp : (p : ℤ) = m + n) (x0 : 0 < lo) (hp2 : 2 ^ p = p2) (hlh : lo * hi' = lh) (hhl : hi * lo' = hl) (hlo : p2 ≤ lh) (hhi : hl ≤ p2) : Approx n lo' hi' x⁻¹ := Approx.inv_lem' hx hp hp2 hlh hhl (Or.inl ⟨x0, hlo, hhi⟩) #align tactic.approx.approx.inv_pos Tactic.Approx.Approx.inv_pos theorem Approx.inv_neg {m n lo hi lo' hi' lh hl p2 : ℤ} {x : ℝ} {p : ℕ} (hx : Approx m lo hi x) (hp : (p : ℤ) = m + n) (x0 : hi < 0) (hp2 : 2 ^ p = p2) (hlh : lo * hi' = lh) (hhl : hi * lo' = hl) (hlo : p2 ≤ hl) (hhi : lh ≤ p2) : Approx n lo' hi' x⁻¹ := Approx.inv_lem' hx hp hp2 hlh hhl (Or.inr ⟨x0, hlo, hhi⟩) #align tactic.approx.approx.inv_neg Tactic.Approx.Approx.inv_neg theorem Approx.inv_triv_pos {m n lo hi : ℤ} {x : ℝ} (hx : Approx m lo hi x) (hp : decide (m + n ≤ 0) = true) (x0 : 0 < lo) : Approx n 0 1 x⁻¹ := by replace hp := Bool.of_decide_true hp refine' Approx.inv_lem hx rfl (Or.inl ⟨x0, _, _⟩) <;> simp · refine' le_trans _ (Int.cast_le.2 (Int.add_one_le_iff.2 x0)) simpa only [zpow_zero, Int.cast_one, zero_add] using zpow_le_of_le one_le_two hp · exact (zpow_pos_of_pos (two_pos : 0 < (2 : ℝ)) _).le #align tactic.approx.approx.inv_triv_pos Tactic.Approx.Approx.inv_triv_pos theorem Approx.inv_triv_neg {m n lo hi : ℤ} {x : ℝ} (hx : Approx m lo hi x) (hp : decide (m + n ≤ 0) = true) (x0 : hi < 0) : Approx n (-1) 0 x⁻¹ := by replace hp := Bool.of_decide_true hp refine' Approx.inv_lem hx rfl (Or.inr ⟨x0, _, _⟩) <;> simp · rw [← Int.cast_neg]; rw [← neg_pos] at x0 refine' le_trans _ (Int.cast_le.2 (Int.add_one_le_iff.2 x0)) simpa only [zpow_zero, Int.cast_one, zero_add] using zpow_le_of_le one_le_two hp · exact (zpow_pos_of_pos (two_pos : 0 < (2 : ℝ)) _).le #align tactic.approx.approx.inv_triv_neg Tactic.Approx.Approx.inv_triv_neg open Tactic Mathlib.Meta.NormNum -- /-- Given `a`, proves `(b, |- round_down a b)` -/ -- unsafe def prove_round_down (ic : instance_cache) (a : expr) : -- tactic (instance_cache × expr × expr) := -- match match_neg a with -- | some a => -- match match_numeral a with -- | match_numeral_result.one => pure (ic, q((-1 : ℤ)), q(RoundDown.neg_one)) -- | match_numeral_result.bit0 a => -- pure (ic, q((Neg.neg : ℤ → ℤ)).mk_app [a], q(RoundDown.bit0_neg).mk_app [a]) -- | match_numeral_result.bit1 a => do -- let (ic, b, h) ← prove_succ' ic a -- pure (ic, q((Neg.neg : ℤ → ℤ)).mk_app [b], q(@RoundDown.bit1_neg).mk_app [a, b, h]) -- | _ => failed -- | none => -- match match_numeral a with -- | match_numeral_result.zero => pure (ic, q((0 : ℤ)), q(RoundDown.zero)) -- | match_numeral_result.one => pure (ic, q((0 : ℤ)), q(RoundDown.one)) -- | match_numeral_result.bit0 a => pure (ic, a, q(RoundDown.bit0_pos).mk_app [a]) -- | match_numeral_result.bit1 a => pure (ic, a, q(@RoundDown.bit1_pos).mk_app [a]) -- | _ => failed -- #align tactic.approx.prove_round_down Tactic.Approx.prove_round_down -- /-- Given `a`, proves `(b, |- round_up a b)` -/ -- unsafe def prove_round_up (ic : instance_cache) (a : expr) : -- tactic (instance_cache × expr × expr) := -- match match_neg a with -- | some a => -- match match_numeral a with -- | match_numeral_result.one => pure (ic, q((0 : ℤ)), q(RoundUp.neg_one)) -- | match_numeral_result.bit0 a => -- pure (ic, q((Neg.neg : ℤ → ℤ)).mk_app [a], q(RoundUp.bit0_neg).mk_app [a]) -- | match_numeral_result.bit1 a => -- pure (ic, q((Neg.neg : ℤ → ℤ)).mk_app [a], q(RoundUp.bit1_neg).mk_app [a]) -- | _ => failed -- | none => -- match match_numeral a with -- | match_numeral_result.zero => pure (ic, q((0 : ℤ)), q(RoundUp.zero)) -- | match_numeral_result.one => pure (ic, q((1 : ℤ)), q(RoundUp.one)) -- | match_numeral_result.bit0 a => pure (ic, a, q(RoundUp.bit0_pos).mk_app [a]) -- | match_numeral_result.bit1 a => do -- let (ic, b, h) ← prove_succ' ic a -- pure (ic, b, q(@RoundUp.bit1_pos).mk_app [a, b, h]) -- | _ => failed -- #align tactic.approx.prove_round_up Tactic.Approx.prove_round_up inductive ApproxExtra | mk #align tactic.approx.approx_extra Tactic.Approx.ApproxExtra inductive ApproxArgs | nil : ApproxArgs | prec : ℤ → ApproxArgs → ApproxArgs | unop : ApproxArgs → ApproxArgs | binop : ApproxArgs → ApproxArgs → ApproxArgs | extra : ApproxExtra → ApproxArgs #align tactic.approx.approx_args Tactic.Approx.ApproxArgs def ApproxArgs.getPrec : ApproxArgs → Option ℤ | ApproxArgs.prec n _ => some n | ApproxArgs.nil => none | ApproxArgs.unop _ => none | ApproxArgs.binop _ _ => none | ApproxArgs.extra _ => none #align tactic.approx.approx_args.get_prec Tactic.Approx.ApproxArgs.getPrec def ApproxArgs.getBinop : ApproxArgs → ApproxArgs × ApproxArgs | ApproxArgs.prec n p => p.getBinop | ApproxArgs.binop a b => (a, b) | _ => (ApproxArgs.nil, ApproxArgs.nil) #align tactic.approx.approx_args.get_binop Tactic.Approx.ApproxArgs.getBinop def ApproxArgs.getUnop : ApproxArgs → ApproxArgs | ApproxArgs.prec n p => p.getUnop | ApproxArgs.unop p => p | _ => ApproxArgs.nil #align tactic.approx.approx_args.get_unop Tactic.Approx.ApproxArgs.getUnop -- /-- Given `a : ℤ` proves `(b, |- bit0 a = b)` -/ -- unsafe def prove_bit0 : expr → expr × expr -- | a => -- match match_neg a with -- | some a => (q((Neg.neg : ℤ → ℤ)).mk_app [a], q(bit0_neg).mk_app [a]) -- | none => -- let b0 := q((bit0 : ℤ → ℤ)).mk_app [a] -- (b0, q(@rfl ℤ).mk_app [b0]) -- #align tactic.approx.prove_bit0 Tactic.Approx.prove_bit0 -- /-- `set_prec tgt ic n en lo hi x hx`: -- * `en` is the expression for `n` -- * `hx : approx n lo hi x` -- returns `(ic, lo', hi', |- approx tgt lo' hi' x)` -/ -- unsafe def set_prec (tgt : ℤ) : -- instance_cache → -- ℤ → expr → expr → expr → expr → expr → tactic (instance_cache × expr × expr × expr) -- | ic, n, en, lo, hi, x, hx => -- if n < tgt then do -- let (ic, en') ← ic.ofInt (n + 1) -- let (lo', hlo) := prove_bit0 lo -- let (hi', hhi) := prove_bit0 hi -- set_prec ic (n + 1) en' lo' hi' x <| -- q(@Approx.up).mk_app [en, lo, hi, lo', hi', x, hx, hlo, hhi] -- else -- if tgt < n then do -- let (ic, en') ← ic.ofInt (n - 1) -- let (ic, lo', hlo) ← prove_round_down ic lo -- let (ic, hi', hhi) ← prove_round_up ic hi -- set_prec ic (n - 1) en' lo' hi' x <| -- q(@Approx.down).mk_app [en, lo, hi, lo', hi', x, hx, hlo, hhi] -- else pure (ic, lo, hi, hx) -- #align tactic.approx.set_prec tactic.approx.set_prec -- unsafe def approx_fn := -- instance_cache → ℤ → expr → expr → tactic (instance_cache × expr × expr × expr) -- #align tactic.approx.approx_fn tactic.approx.approx_fn -- unsafe def eval_approx_neg (xfn : approx_fn) (n' : ℤ) (x : expr) : approx_fn -- | ic, n, en, e => do -- let (ic, en') ← ic.ofInt n' -- let (ic, lo, hi, hx) ← xfn ic n' en' x -- let (ic, hi', hlo) ← prove_neg ic lo -- let (ic, lo', hhi) ← prove_neg ic hi -- set_prec n ic n' en' lo' hi' e <| q(@Approx.neg).mk_app [en', lo, hi, lo', hi', x, hx, hlo, hhi] -- #align tactic.approx.eval_approx_neg tactic.approx.eval_approx_neg -- unsafe def eval_approx_add (xfn yfn : approx_fn) (n' : ℤ) (x y : expr) : approx_fn -- | ic, n, en, e => do -- let (ic, en') ← ic.ofInt n' -- let (ic, xlo, xhi, hx) ← xfn ic n' en' x -- let (ic, ylo, yhi, hy) ← yfn ic n' en' y -- let (ic, lo, hlo) ← prove_add_rat' ic xlo ylo -- let (ic, hi, hhi) ← prove_add_rat' ic xhi yhi -- set_prec n ic n' en' lo hi e <| -- q(@Approx.add).mk_app [en', xlo, xhi, ylo, yhi, lo, hi, x, y, hx, hy, hlo, hhi] -- #align tactic.approx.eval_approx_add tactic.approx.eval_approx_add -- unsafe def eval_approx_sub (xfn yfn : approx_fn) (n' : ℤ) (x y : expr) : approx_fn -- | ic, n, en, e => do -- let (ic, en') ← ic.ofInt n' -- let (ic, xlo, xhi, hx) ← xfn ic n' en' x -- let (ic, ylo, yhi, hy) ← yfn ic n' en' y -- let (ic, lo, hlo) ← prove_sub ic xlo yhi -- let (ic, hi, hhi) ← prove_sub ic xhi ylo -- set_prec n ic n' en' lo hi e <| -- q(@Approx.sub).mk_app [en', xlo, xhi, ylo, yhi, lo, hi, x, y, hx, hy, hlo, hhi] -- #align tactic.approx.eval_approx_sub tactic.approx.eval_approx_sub -- /-- Given `xlo, xhi, ylo, yhi` proves `(lo, hi, |- mul_bound xlo xhi ylo yhi lo hi)` -/ -- unsafe def eval_mul_bound (ic : instance_cache) (exlo exhi eylo eyhi : expr) : -- tactic (instance_cache × expr × expr × expr) := do -- let xlo ← exlo.toInt -- let xhi ← exhi.toInt -- let ylo ← eylo.toInt -- let yhi ← eyhi.toInt -- let rxlo := Rat.ofInt xlo -- let rxhi := Rat.ofInt xhi -- let rylo := Rat.ofInt ylo -- let ryhi := Rat.ofInt yhi -- (if 0 ≤ xlo then do -- let (ic, x0) ← prove_nonneg ic exlo -- if 0 ≤ ylo then do -- let (ic, y0) ← prove_nonneg ic eylo -- let (ic, lo, hlo) ← prove_mul_rat ic exlo eylo rxlo rylo -- let (ic, hi, hhi) ← prove_mul_rat ic exhi eyhi rxhi ryhi -- pure -- (ic, lo, hi, -- q(@MulBound.pos_pos).mk_app [exlo, exhi, eylo, eyhi, lo, hi, x0, y0, hlo, hhi]) -- else -- if yhi ≤ 0 then do -- let (ic, y0) ← prove_le_rat ic eyhi q((0 : ℤ)) ryhi 0 -- let (ic, lo, hlo) ← prove_mul_rat ic exhi eylo rxhi rylo -- let (ic, hi, hhi) ← prove_mul_rat ic exlo eyhi rxlo ryhi -- pure -- (ic, lo, hi, -- q(@MulBound.pos_neg).mk_app [exlo, exhi, eylo, eyhi, lo, hi, x0, y0, hlo, hhi]) -- else failed -- else -- if xhi ≤ 0 then do -- let (ic, x0) ← prove_le_rat ic exhi q((0 : ℤ)) rxhi 0 -- if 0 ≤ ylo then do -- let (ic, y0) ← prove_nonneg ic eylo -- let (ic, lo, hlo) ← prove_mul_rat ic exlo eyhi rxlo ryhi -- let (ic, hi, hhi) ← prove_mul_rat ic exhi eylo rxhi rylo -- pure -- (ic, lo, hi, -- q(@MulBound.neg_pos).mk_app [exlo, exhi, eylo, eyhi, lo, hi, x0, y0, hlo, hhi]) -- else -- if yhi ≤ 0 then do -- let (ic, y0) ← prove_le_rat ic eyhi q((0 : ℤ)) ryhi 0 -- let (ic, lo, hlo) ← prove_mul_rat ic exhi eyhi rxhi ryhi -- let (ic, hi, hhi) ← prove_mul_rat ic exlo eylo rxlo rylo -- pure -- (ic, lo, hi, -- q(@MulBound.neg_neg).mk_app -- [exlo, exhi, eylo, eyhi, lo, hi, x0, y0, hlo, hhi]) -- else failed -- else failed) <|> -- do -- let (ic, ell, hell) ← prove_mul_rat ic exlo eylo rxlo rylo -- let ll := xlo * ylo -- let rll := Rat.ofInt ll -- let (ic, elh, helh) ← prove_mul_rat ic exlo eyhi rxlo ryhi -- let lh := xlo * yhi -- let rlh := Rat.ofInt lh -- let (ic, ehl, hehl) ← prove_mul_rat ic exhi eylo rxhi rylo -- let hl := xhi * ylo -- let rhl := Rat.ofInt hl -- let (ic, ehh, hehh) ← prove_mul_rat ic exhi eyhi rxhi ryhi -- let hh := xhi * yhi -- let rhh := Rat.ofInt hh -- let lo := min ll <| min lh <| min hl hh -- let hi := max ll <| max lh <| max hl hh -- let (ic, elo) ← ic lo -- let (ic, ehi) ← ic hi -- let rlo := Rat.ofInt lo -- let rhi := Rat.ofInt hi -- let (ic, lll) ← prove_le_rat ic elo ell rlo rll -- let (ic, hll) ← prove_le_rat ic ell ehi rll rhi -- let (ic, llh) ← prove_le_rat ic elo elh rlo rlh -- let (ic, hlh) ← prove_le_rat ic elh ehi rlh rhi -- let (ic, lhl) ← prove_le_rat ic elo ehl rlo rhl -- let (ic, hhl) ← prove_le_rat ic ehl ehi rhl rhi -- let (ic, lhh) ← prove_le_rat ic elo ehh rlo rhh -- let (ic, hhh) ← prove_le_rat ic ehh ehi rhh rhi -- pure -- (ic, elo, ehi, -- q(@MulBound.mk).mk_app -- [exlo, exhi, eylo, eyhi, ell, elh, ehl, ehh, elo, ehi, hell, helh, hehl, hehh, lll, -- hll, llh, hlh, lhl, hhl, lhh, hhh]) -- #align tactic.approx.eval_mul_bound tactic.approx.eval_mul_bound -- unsafe def eval_approx_mul (xfn yfn : approx_fn) (xp yp : ℤ) (x y : expr) : approx_fn -- | ic, n, en, e => do -- let (ic, exp) ← ic.ofInt xp -- let (ic, eyp) ← ic.ofInt yp -- let (ic, xlo, xhi, hx) ← xfn ic xp exp x -- let (ic, ylo, yhi, hy) ← yfn ic yp eyp y -- let (ic, lo, hi, hbd) ← eval_mul_bound ic xlo xhi ylo yhi -- let n' := xp + yp -- let (ic, en') ← ic.ofInt n' -- set_prec n ic n' en' lo hi e <| -- q(@Approx.mul).mk_app [exp, eyp, xlo, xhi, ylo, yhi, lo, hi, x, y, hx, hy, hbd] -- #align tactic.approx.eval_approx_mul tactic.approx.eval_approx_mul -- unsafe def inv_expr : expr := -- q((Inv.inv : ℝ → ℝ)) -- #align tactic.approx.inv_expr tactic.approx.inv_expr -- unsafe def eval_approx_div (xfn iyfn : approx_fn) (xp yp : ℤ) (x y : expr) : approx_fn -- | ic, n, en, e => do -- let (ic, exp) ← ic.ofInt xp -- let (ic, eyp) ← ic.ofInt yp -- let (ic, xlo, xhi, hx) ← xfn ic xp exp x -- let (ic, ylo, yhi, hy) ← iyfn ic yp eyp (inv_expr y) -- let (ic, lo, hi, hbd) ← eval_mul_bound ic xlo xhi ylo yhi -- pure -- (ic, lo, hi, -- q(@Approx.div).mk_app [exp, eyp, xlo, xhi, ylo, yhi, lo, hi, x, y, hx, hy, hbd]) -- #align tactic.approx.eval_approx_div tactic.approx.eval_approx_div -- unsafe def eval_approx_inv (xfn : approx_fn) (m : ℤ) (x : expr) : approx_fn -- | ic, n, en, e => do -- let (ic, em) ← ic.ofInt m -- let (ic, elo, ehi, hx) ← xfn ic m em x -- let lo ← elo.toInt -- let hi ← ehi.toInt -- if lo = 0 ∧ hi = 0 then -- pure (ic, q((0 : ℤ)), q((0 : ℤ)), q(@Approx.inv_zero).mk_app [em, en, x, hx]) -- else -- if m + n ≤ 0 then -- if 0 < lo then do -- let (ic, x0) ← prove_pos ic elo -- pure -- (ic, q((0 : ℤ)), q((1 : ℤ)), -- q(@Approx.inv_triv_pos).mk_app [em, en, elo, ehi, x, hx, q(@rfl _ true), x0]) -- else -- if hi < 0 then do -- let (ic, x0) ← prove_lt_rat ic ehi q((0 : ℤ)) (Rat.ofInt hi) 0 -- pure -- (ic, q((-1 : ℤ)), q((0 : ℤ)), -- q(@Approx.inv_triv_neg).mk_app [em, en, elo, ehi, x, hx, q(@rfl _ true), x0]) -- else fail f! "at {x}⁻¹: Failed to bound away from zero. Try increasing the precision" -- else do -- let nc ← mk_instance_cache q(ℕ) -- let p := (m + n).toNat -- let (nc, ep) ← nc p -- let hp := q(@rfl _ (($(ep) : ℕ) : ℤ)) -- let (ic, ep2, hp2) ← prove_pow q((2 : ℤ)) 2 ic ep -- let p2 : ℤ := 2 ^ p -- let rp2 := Rat.ofInt p2 -- let rlo := Rat.ofInt lo -- let rhi := Rat.ofInt hi -- if 0 < lo then do -- let (ic, x0) ← prove_pos ic elo -- let lo' := p2 / hi -- let hi' := (p2 - 1) / lo + 1 -- let (ic, elo') ← ic lo' -- let (ic, ehi') ← ic hi' -- let (ic, elh, hlh) ← prove_mul_rat ic elo ehi' rlo (Rat.ofInt hi') -- let (ic, ehl, hhl) ← prove_mul_rat ic ehi elo' rhi (Rat.ofInt lo') -- let (ic, hlo) ← prove_le_rat ic ep2 elh p2 (Rat.ofInt (lo * hi')) -- let (ic, hhi) ← prove_le_rat ic ehl ep2 (Rat.ofInt (hi * lo')) p2 -- pure -- (ic, elo, ehi, -- q(@Approx.inv_pos).mk_app -- [em, en, elo, ehi, elo', ehi', elh, ehl, ep2, x, ep, hx, hp, x0, hp2, hlh, -- hhl, hlo, hhi]) -- else -- if hi < 0 then do -- let (ic, x0) ← prove_lt_rat ic ehi q((0 : ℤ)) rhi 0 -- let lo' := (p2 - 1) / hi - 1 -- let hi' := p2 / lo -- let (ic, elo') ← ic lo' -- let (ic, ehi') ← ic hi' -- let (ic, elh, hlh) ← prove_mul_rat ic elo ehi' rlo (Rat.ofInt hi') -- let (ic, ehl, hhl) ← prove_mul_rat ic ehi elo' rhi (Rat.ofInt lo') -- let (ic, hlo) ← prove_le_rat ic ep2 ehl p2 (Rat.ofInt (hi * lo')) -- let (ic, hhi) ← prove_le_rat ic elh ep2 (Rat.ofInt (lo * hi')) p2 -- pure -- (ic, elo, ehi, -- q(@Approx.inv_neg).mk_app -- [em, en, elo, ehi, elo', ehi', elh, ehl, ep2, x, ep, hx, hp, x0, hp2, hlh, -- hhl, hlo, hhi]) -- else fail f! "at {x}⁻¹: Failed to bound away from zero. Try increasing the precision" -- #align tactic.approx.eval_approx_inv tactic.approx.eval_approx_inv -- -- PLEASE REPORT THIS TO MATHPORT DEVS, THIS SHOULD NOT HAPPEN. -- -- failed to format: unknown constant 'term.pseudo.antiquot' -- unsafe -- def -- eval_approx -- : ApproxArgs → approx_fn -- | approx_args.extra args , ic , n , en , e => failed -- | -- approx_args.prec n' args , ic , n , en , e -- => -- do -- let ( ic , en' ) ← ic . ofInt n' -- let ( ic , lo , hi , hx ) ← eval_approx args ic n' en' e -- set_prec n ic n' en' lo hi e hx -- | -- args , ic , n , en , e -- => -- do -- let -- r -- ← -- try_core -- ( -- match -- e . toNat -- with -- | some 0 => pure none -- | -- some _ -- => -- do let rc ← mk_instance_cache q( ℝ ) some <$> prove_int_uncast rc ic e -- | _ => failed -- ) -- match -- r -- with -- | -- some none -- => -- pure ( ic , q( ( 0 : ℤ ) ) , q( ( 0 : ℤ ) ) , q( Approx.zero ) . mk_app [ en ] ) -- | -- some ( some ( _ , ic , a , ha ) ) -- => -- do -- set_prec n ic 0 q( ( 0 : ℤ ) ) a a e -- <| -- q( @ Approx.const ) . mk_app [ a , e , ha ] -- | -- none -- => -- match -- e -- with -- | -- q( - $ ( x ) ) -- => -- do -- let xargs := args -- let n' := ( match xargs with | some xp => min n xp | _ => n : ℤ ) -- eval_approx_neg ( eval_approx xargs ) n' x ic n en e -- | -- q( $ ( x ) + $ ( y ) ) -- => -- do -- let ( xargs , yargs ) := args -- let -- n' -- := -- ( -- match -- xargs , yargs -- with -- | some xp , some yp => min n ( max xp yp ) | _ , _ => n -- : -- ℤ -- ) -- eval_approx_add -- ( eval_approx xargs ) ( eval_approx yargs ) n' x y ic n en e -- | -- q( $ ( x ) - $ ( y ) ) -- => -- do -- let ( xargs , yargs ) := args -- let -- n' -- := -- ( -- match -- xargs , yargs -- with -- | some xp , some yp => min n ( max xp yp ) | _ , _ => n -- : -- ℤ -- ) -- eval_approx_sub -- ( eval_approx xargs ) ( eval_approx yargs ) n' x y ic n en e -- | -- q( $ ( x ) * $ ( y ) ) -- => -- do -- let ( xargs , yargs ) := args -- let -- ( xp , yp ) -- := -- ( -- match -- xargs , yargs -- with -- | some xp , some yp => ( xp , yp ) -- | none , some yp => ( n - yp , yp ) -- | some xp , none => ( xp , n - xp ) -- | none , none => let xp := n / 2 ( xp , n - xp ) -- : -- ℤ × ℤ -- ) -- eval_approx_mul -- ( eval_approx xargs ) ( eval_approx yargs ) xp yp x y ic n en e -- | -- q( $ ( x ) / $ ( y ) ) -- => -- do -- let ( xargs , yargs ) := args -- let xp := xargs ( n / 2 ) -- let yp := n - xp -- eval_approx_div -- ( eval_approx xargs ) -- ( eval_approx ( approx_args.unop yargs ) ) -- xp -- yp -- x -- y -- ic -- n -- en -- e -- | -- q( $ ( x ) ⁻¹ ) -- => -- do -- let xargs := args -- let m := xargs ( abs n ) -- eval_approx_inv ( eval_approx xargs ) m x ic n en e -- | _ => failed -- #align tactic.approx.eval_approx tactic.approx.eval_approx end Approx end Tactic