define divides : (fn (UInt, UInt) -> bool) = fun a:UInt, b:UInt {
      some k:UInt. a * k = b
    }

fromNat_div: (all x:Nat, y:Nat. fromNat(x) / fromNat(y) = fromNat(x / y))

fromNat_mod: (all x:Nat, y:Nat. fromNat(x) % fromNat(y) = fromNat(x % y))

recfun gcd(a:UInt, b:UInt) -> UInt
  measure b of UInt
{
  if b = 0 then
    a
  else
    gcd(b, a % b)
}
terminates {
  arbitrary a.s26_3 : UInt,
  b.s26_4 : UInt
  assume bnz.s26_5: b  0
  have b_pos: 0 < b by {
    apply or_not to uint_zero_or_positive[b], bnz
  }
  conclude a % b < b by {
    apply uint_mod_less_divisor[a, b] to b_pos
  }
}

define lcm : (fn (UInt, UInt) -> UInt) = fun a:UInt, b:UInt {
      if ((a = 0) or (b = 0)) then
        0
      else
        (a * b) / gcd(a, b)
    }

define operator % : (fn (UInt, UInt) -> UInt) = fun n:UInt, m:UInt {
      n  (n / m) * m
    }

recfun operator /(n:UInt, m:UInt) -> UInt
  measure n of UInt
{
  if n < m then
    0
  else
    if m = 0 then
      0
    else
      1 + (n  m) / m
}
terminates {
  arbitrary n.s9_3 : UInt,
  m.s9_4 : UInt
  assume cond.s9_5: (not (n < m) and m  0)
  suffices m + (n  m) < m + n  by {
uint_add_both_sides_of_less[m, n  m, n]
  }
  suffices n < m + n  by {
    have m_n: m  n by {
      apply uint_not_less_implies_less_equal to conjunct 0 of cond
    }
    replace (apply uint_monus_add_identity[n, m] to m_n)
.
  }
  have m_pos: 0 < m by {
    apply uint_not_zero_pos to conjunct 1 of cond
  }
  conclude n < m + n by {
replace uint_add_commute in apply uint_less_add_pos[n, m] to expand lit | fromNat in m_pos
  }
}

toNat_mod: (all x:UInt, y:UInt. toNat(x % y) = toNat(x) % toNat(y))

uint_add_div_one: (all n:UInt, m:UInt. (if 0 < m then (n + m) / m = 1 + n / m))

uint_add_mod: (all a:UInt, b:UInt, m:UInt. (if 0 < m then (a + b) % m = (a % m + b % m) % m))

uint_add_mult_div: (all n:UInt, k:UInt, m:UInt. (if 0 < m then (n + k * m) / m = k + n / m))

uint_add_mult_mod: (all n:UInt, k:UInt, m:UInt. (if 0 < m then (n + k * m) % m = n % m))

uint_div_cancel: (all y:UInt. (if 0 < y then y / y = 1))

uint_div_less: (all n:UInt, m:UInt. (if ((0 < n) and (1 < m)) then n / m < n))

uint_div_less_equal: (all n:UInt, m:UInt. (if 0 < m then n / m  n))

uint_div_mod: (all n:UInt, m:UInt. (if 0 < m then (n / m) * m + n % m = n))

uint_div_one: (all n:UInt. n / 1 = n)

uint_div_zero: (all n:UInt. n / 0 = 0)

uint_divides_add: (all d:UInt, m:UInt, n:UInt. (if (divides(d, m) and divides(d, n)) then divides(d, m + n)))

uint_divides_antisymmetric: (all a:UInt, b:UInt. (if (divides(a, b) and divides(b, a)) then a = b))

uint_divides_lcm_left: (all a:UInt, b:UInt. divides(a, lcm(a, b)))

uint_divides_lcm_right: (all a:UInt, b:UInt. divides(b, lcm(a, b)))

uint_divides_less_equal: (all a:UInt, b:UInt. (if (divides(a, b) and (0 < b)) then a  b))

uint_divides_mod: (all d:UInt, m:UInt, n:UInt. (if (divides(d, n) and divides(d, m % n) and (0 < n)) then divides(d, m)))

uint_divides_mod_of_divides: (all d:UInt, m:UInt, n:UInt. (if (divides(d, m) and divides(d, n)) then divides(d, m % n)))

uint_divides_monus: (all d:UInt, m:UInt, n:UInt. (if (divides(d, m) and divides(d, n)) then divides(d, m  n)))

uint_divides_mult_both: (all k:UInt, a:UInt, b:UInt. (if divides(a, b) then divides(k * a, k * b)))

uint_divides_mult_cancel: (all k:UInt, a:UInt, b:UInt. (if ((0 < k) and divides(k * a, k * b)) then divides(a, b)))

uint_divides_mult_left: (all d:UInt, n:UInt, m:UInt. (if divides(d, n) then divides(d, m * n)))

uint_divides_mult_right: (all d:UInt, n:UInt, m:UInt. (if divides(d, n) then divides(d, n * m)))

uint_divides_refl: (all n:UInt. divides(n, n))

uint_divides_trans: (all a:UInt, b:UInt, c:UInt. (if (divides(a, b) and divides(b, c)) then divides(a, c)))

uint_divides_zero: (all n:UInt. divides(n, 0))

uint_gcd_commutative: (all a:UInt, b:UInt. gcd(a, b) = gcd(b, a))

uint_gcd_divides: (all b:UInt, a:UInt. (divides(gcd(a, b), a) and divides(gcd(a, b), b)))

uint_gcd_divides_left: (all a:UInt, b:UInt. divides(gcd(a, b), a))

uint_gcd_divides_right: (all a:UInt, b:UInt. divides(gcd(a, b), b))

uint_gcd_greatest: (all d:UInt, a:UInt, b:UInt. (if (divides(d, a) and divides(d, b)) then divides(d, gcd(a, b))))

uint_gcd_lcm_product: (all a:UInt, b:UInt. gcd(a, b) * lcm(a, b) = a * b)

uint_gcd_mult_distributive: (all k:UInt, a:UInt, b:UInt. gcd(k * a, k * b) = k * gcd(a, b))

uint_gcd_pos: (all a:UInt, b:UInt. (if 0 < a then 0 < gcd(a, b)))

uint_gcd_self: (all a:UInt. gcd(a, a) = a)

uint_gcd_zero_left: (all b:UInt. gcd(0, b) = b)

uint_gcd_zero_right: (all a:UInt. gcd(a, 0) = a)

uint_lcm_commutative: (all a:UInt, b:UInt. lcm(a, b) = lcm(b, a))

uint_lcm_least: (all a:UInt, b:UInt, m:UInt. (if (divides(a, m) and divides(b, m)) then divides(lcm(a, b), m)))

auto uint_lcm_zero_left

uint_lcm_zero_left: (all b:UInt. lcm(0, b) = 0)

auto uint_lcm_zero_right

uint_lcm_zero_right: (all a:UInt. lcm(a, 0) = 0)

auto uint_lit_div

uint_lit_div: (all x:Nat, y:Nat. fromNat(lit(x)) / fromNat(lit(y)) = fromNat(lit(x) / lit(y)))

uint_mod_less_divisor: (all n:UInt, m:UInt. (if 0 < m then n % m < m))

uint_mod_mod: (all n:UInt, m:UInt. (if 0 < m then (n % m) % m = n % m))

uint_mod_one: (all n:UInt. n % 1 = 0)

uint_mod_self_zero: (all y:UInt. y % y = 0)

uint_mod_small: (all n:UInt, m:UInt. (if n < m then n % m = n))

uint_mult_add_div: (all k:UInt, n:UInt, m:UInt. (if 0 < m then (k * m + n) / m = k + n / m))

uint_mult_add_mod: (all k:UInt, n:UInt, m:UInt. (if 0 < m then (k * m + n) % m = n % m))

uint_mult_div_inverse: (all n:UInt, m:UInt. (if 0 < m then (n * m) / m = n))

uint_mult_div_left_inverse: (all n:UInt, m:UInt. (if 0 < m then (m * n) / m = n))

uint_mult_mod: (all a:UInt, b:UInt, m:UInt. (if 0 < m then (a * b) % m = ((a % m) * (b % m)) % m))

uint_mult_mod_left_zero: (all n:UInt, m:UInt. (if 0 < m then (m * n) % m = 0))

uint_mult_mod_right_zero: (all n:UInt, m:UInt. (if 0 < m then (n * m) % m = 0))

uint_zero_div: (all x:UInt. (if 0 < x then 0 / x = 0))

uint_zero_mod: (all x:UInt. 0 % x = 0)