-- WadrayVerification/Aux.lean

import CorelibVerification.Aux.ZMod

import Aegis.Aux.Bool

import Aegis.Aux.ZMod.DivMod

open Sierra

namespace Wad

variable (w w' : Wad)

end Wad

def Ray : Type := UInt128

namespace Ray

def RAY_SCALE : ℕ := 1000000000000000000000000000

variable (r r' : Ray)

protected def toZMod : UInt128 := r

protected def toRat : ℚ := r.toZMod.val / RAY_SCALE

protected def mul : Ray := (r.toZMod.val * r'.toZMod.val / RAY_SCALE  : UInt128)

end Ray

namespace SignedWad

variable (w w₁ w₂ : SignedWad)

end SignedWad

def SignedRay := UInt128 × (Unit ⊕ Unit)

namespace SignedRay

instance : Inhabited SignedRay := ⟨default, default⟩

variable (w w₁ w₂ : SignedRay)

def sign : ℤ := if SierraBool.toBool w.2 then -1 else 1

instance : Zero SignedRay := ⟨(0, false.toSierraBool)⟩

def toRat : ℚ := if SierraBool.toBool w.2 then -(Ray.toRat w.1) else Ray.toRat w.1

protected def mul : SignedRay :=
⟨Ray.mul w₁.1 w₂.1, Bool.toSierraBool (Bool.xor (SierraBool.toBool w₁.2) (SierraBool.toBool w₂.2))⟩

instance : Mul SignedRay := ⟨SignedRay.mul⟩

-- Repository definitions used:
content: ...

-- Repository lemmas used:
content: theorem List.getElem_append_left{α : Type u_1} {l₁ l₂ : List α} {i : Nat} (hn : i < l₁.length) :\n(l₁ ++ l₂)[i] = l₁[i]

-- Local definitions used:
content: def Ray : Type := UInt128

content: def RAY_SCALE : ℕ := 1000000000000000000000000000

content: protected def toZMod : UInt128 := r

content: protected def toRat : ℚ := r.toZMod.val / RAY_SCALE

content: protected def mul : Ray := (r.toZMod.val * r'.toZMod.val / RAY_SCALE  : UInt128)

content: def SignedRay := UInt128 × (Unit ⊕ Unit)

content: def toRat : ℚ := if SierraBool.toBool w.2 then -(Ray.toRat w.1) else Ray.toRat w.1

-- Local lemmas used:
content: theorem Rat.nat_cast_div_eq {a b : ℕ} :
    ↑(a / b) = (a : ℚ) / (b : ℚ) - ↑(a % b) / (b : ℚ)

content: theorem RAY_SCALE_pos : 0 < RAY_SCALE

content: theorem RAY_SCALE_rat_pos : 0 < (RAY_SCALE : ℚ)

content: theorem mul_def :
    w₁ * w₂ = ⟨Ray.mul w₁.1 w₂.1, Bool.toSierraBool (Bool.xor (SierraBool.toBool w₁.2) (SierraBool.toBool w₂.2))⟩

-- Target theorem and proof:
theorem toRat_mul (h₁ : w₁.1.val * w₂.1.val / Ray.RAY_SCALE < U128_MOD ):
    |SignedRay.toRat (w₁ * w₂) - SignedRay.toRat w₁ * SignedRay.toRat w₂| < 1 / Ray.RAY_SCALE
:= by
  rcases w₁ with ⟨w₁, s₁⟩
  rcases w₂ with ⟨w₂, s₂⟩
  rcases s₁ with (⟨⟨⟩⟩|⟨⟨⟩⟩) <;> rcases s₂ with (⟨⟨⟩⟩|⟨⟨⟩⟩)
    <;> dsimp only at h₁
    <;> simp [mul_def, toRat, Ray.mul, Ray.toRat, Ray.toZMod, Nat.mod_eq_of_lt h₁, -one_div]
    <;> rw [Rat.nat_cast_div_eq, Nat.cast_mul, ZMod.natCast_val, ZMod.natCast_val, mul_div_assoc,
      sub_div, div_mul_eq_mul_div]
    <;> [rw [sub_right_comm, sub_self, zero_sub, abs_neg];
       rw [neg_sub, sub_add_cancel];
       rw [neg_sub, sub_add_cancel];
       rw [sub_right_comm, sub_self, zero_sub, abs_neg]]
    <;> rw [abs_div,
      Nat.abs_cast, div_lt_div_right Ray.RAY_SCALE_rat_pos, abs_div, Nat.abs_cast,
      Nat.abs_cast, div_lt_one Ray.RAY_SCALE_rat_pos, Nat.cast_lt]
    <;> apply Nat.mod_lt _ Ray.RAY_SCALE_pos