-- 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

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

content: instance : Mul Ray := ⟨Ray.mul⟩

-- 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

-- 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: protected theorem mul_def :
    r * r' = (r.toZMod.val * r'.toZMod.val / RAY_SCALE  : UInt128)

-- Target theorem and proof:
theorem toRat_mul (h : r.toZMod.val * r'.toZMod.val / RAY_SCALE < U128_MOD) :
    |(r * r').toRat - r.toRat * r'.toRat| < 1 / RAY_SCALE
:= by
  simp only [Ray.toRat, Ray.toZMod, Ray.mul_def] at *
  simp only [ZMod.val_natCast]
  rw [Nat.mod_eq_of_lt h, div_mul_div_comm, ← div_div, ← sub_div, abs_div,
    Nat.abs_cast, div_lt_div_right RAY_SCALE_rat_pos, Rat.nat_cast_div_eq]
  simp only [Nat.cast_mul, ZMod.val_natCast, sub_sub_cancel_left, abs_neg]
  rw [abs_div, Nat.abs_cast, Nat.abs_cast, div_lt_one RAY_SCALE_rat_pos,
    Nat.cast_lt]
  apply Nat.mod_lt _ RAY_SCALE_pos