module Calf.Solver.Nat.Arithmetic where

open import Cubical.Foundations.Prelude
open import Cubical.Data.Nat using (; zero; suc; _+_; _∸_; _·_)
import Cubical.Data.Nat.Properties as Nat
open import Cubical.Data.Nat.Order using
  (_≤_; isProp≤; zero-≤; ≤-refl; suc-≤-suc; ≤-trans; ≤-+-≤; ≤SumLeft; ≤SumRight;
   ≤-∸-+-cancel; ≤-∸-≤; ≤-∸-k)
open import Cubical.Data.Sigma using (fst; snd)

∸-witness :  {m n : }  (h : m  n)  n  m  fst h
∸-witness {m} {n} h =
  cong fst (isProp≤ ((n  m) , ≤-∸-+-cancel h) h)

natRefl : (x : )  x  x
natRefl x = refl

natCongSuc : (x y : )  x  y  suc x  suc y
natCongSuc x y p = cong suc p

natCong₂+ :
  (a a′ b b′ : )
   a  a′
   b  b′
   a + b  a′ + b′
natCong₂+ a a′ b b′ p q = cong₂ _+_ p q

natCong₂· :
  (a a′ b b′ : )
   a  a′
   b  b′
   a · b  a′ · b′
natCong₂· a a′ b b′ p q = cong₂ _·_ p q

natCong₂∸ :
  (a a′ b b′ : )
   a  a′
   b  b′
   a  b  a′  b′
natCong₂∸ a a′ b b′ p q = cong₂ _∸_ p q

natComp :
  (x y z : )
   x  y
   y  z
   x  z
natComp x y z p q = p  q

finishNatExplicit :
  (lhs lhs′ rhs rhs′ : )
   lhs  lhs′
   lhs′  rhs′
   rhs  rhs′
   lhs  rhs
finishNatExplicit lhs lhs′ rhs rhs′ lhs-step middle rhs-step =
  lhs-step  middle  sym rhs-step

finishLeExplicit :
  (lower lower′ upper upper′ : )
   lower  lower′
   lower′  upper′
   upper  upper′
   lower  upper
finishLeExplicit lower lower′ upper upper′ lower-step middle upper-step =
  subst  n  lower  n) (sym upper-step)
    (subst  n  n  upper′) (sym lower-step) middle)

leRefl : (m : )  m  m
leRefl m = ≤-refl

leZero : (n : )  0  n
leZero n = zero-≤

leSuc : (m n : )  m  n  suc m  suc n
leSuc m n p = suc-≤-suc p

leTrans : (k m n : )  k  m  m  n  k  n
leTrans k m n p q = ≤-trans p q

lePlus :
  (m n l k : )
   m  n
   l  k
   m + l  n + k
lePlus m n l k p q = ≤-+-≤ p q

leSumLeft : (n k : )  n  n + k
leSumLeft n k = ≤SumLeft

leSumRight : (n k : )  n  k + n
leSumRight n k = ≤SumRight

leMulRight : (m n k : )  m  n  m  suc k · n
leMulRight m n k h = ≤-trans h (≤SumLeft {n} {k · n})

leWitnessEq : (lower upper : )  (p : lower  upper)  upper  fst p + lower
leWitnessEq lower upper p = sym (snd p)

leMinusPlusEq : (lower upper : )  (p : lower  upper)  upper  (upper  lower) + lower
leMinusPlusEq lower upper p = sym (≤-∸-+-cancel p)

minusZeroRight : (x : )  x  0  x
minusZeroRight x = refl

minusZeroLeft : (x : )  0  x  0
minusZeroLeft x = Nat.zero∸ x

minusSelf : (x : )  x  x  0
minusSelf x = Nat.n∸n x

minusPullLeft :
  (m n k : )
   m  n
   (k + n)  m  k + (n  m)
minusPullLeft m n k p = sym (≤-∸-k p)

minusPullRight :
  (m n k : )
   m  n
   (n + k)  m  (n  m) + k
minusPullRight m n k p =
  cong (_∸ m) (Nat.+-comm n k)
   minusPullLeft m n k p
   Nat.+-comm k (n  m)

minusPlusRight : (x k : )  (x + k)  x  k
minusPlusRight x k = Nat.∸+ k x

minusPlusLeft : (k x : )  (k + x)  x  k
minusPlusLeft k x = Nat.+∸ k x

leMinusRight : (a b c : )  a + c  b  a  b  c
leMinusRight a b c p =
  subst  x  x  b  c) (Nat.+∸ a c) (≤-∸-≤ (a + c) b c p)

leMinusRightComm : (a b c : )  c + a  b  a  b  c
leMinusRightComm a b c p =
  leMinusRight a b c (subst (_≤ b) (Nat.+-comm c a) p)

leWitnessLower : (a c b : )  a + c  b  (p : c  b)  a  fst p
leWitnessLower a c b h p =
  subst (a ≤_) (∸-witness p) (leMinusRight a b c h)

leWitnessLowerComm : (a c b : )  c + a  b  (p : c  b)  a  fst p
leWitnessLowerComm a c b h p =
  subst (a ≤_) (∸-witness p) (leMinusRightComm a b c h)