Int.mul
import Natural (+, *, plusZeroId, plusSucId, zeroPlusId, sucPlus, plusComm, plusAssoc, swapLeft, multZeroId, multSucId, zeroMult, sucMult, multComm, multDistrib, multAssoc)
import Int (Int, intZero, intOne, intNeg)
import Int.add (+, intAddComm, intAddAssoc)
import Core.equality (trans, cong, sym, paireta)
distribBack : {n m k : ℕ} → n * m + n * k ≡ n * (m + k) using (multDistrib)
distribBack = λn m k. ⋆
distribBackR : (m k n : ℕ) → m * n + k * n ≡ (m + k) * n using (distribBack)
distribBackR =
λm k n. trans
_
_
_
trans
_
_
_
cong (λu. ℕ) (λw. w + k * n) (multComm n m)
cong (λu. ℕ) (λw. n * m + w) (multComm n k)
trans (n * m + n * k) _ _ distribBack (multComm (m + k) n)
swap4 : (p q r s : ℕ) → p + q + (r + s) ≡ p + r + (q + s)
using (hyp.rw,
Natural.swapMid,
Natural.swapMid.rw,
plusAssoc,
plusAssoc.rw,
swapLeft,
swapLeft.rw)
swap4 = λp q r s. ⋆
swap4b : {p q r s : ℕ} → p + q + (r + s) ≡ p + s + (q + r)
using (Int.add.intAddCross, swap4, plusAssoc)
swap4b =
λp q r s. p + q + (r + s) ≡⟨ plusComm s r ⟩ p + q + (s + r) ≡⟨ swap4 p q s r ⟩ p + s + (q + r)
plusCongL : {x y z : ℕ} → (x ≡ y) → x + z ≡ y + z using (hyp.rw)
plusCongL = λx y z h. ⋆
plusCongR : {x y z : ℕ} → (y ≡ z) → x + y ≡ x + z
plusCongR = λx y z h. ⋆
collectL : (x y z u v : ℕ) → x * y * z + x * u * v ≡ x * (y * z + u * v)
using (distribBack, multAssoc)
collectL =
λx y z u v. trans
_
_
_
trans
{ℕ}
x * y * z + x * u * v
x * (y * z) + x * u * v
x * (y * z) + x * (u * v)
plusCongL (multAssoc x y z)
plusCongR (multAssoc x u v)
distribBack
assocRep : (a1 a2 b1 b2 c1 c2 : ℕ)
→ (a1 * b1 + a2 * b2) * c1 + (a1 * b2 + a2 * b1) * c2
≡ a1 * (b1 * c1 + b2 * c2) + a2 * (b1 * c2 + b2 * c1)
using (hyp.rw)
assocRep =
λa1 a2 b1 b2 c1 c2. (a1 * b1 + a2 * b2) * c1 + (a1 * b2 + a2 * b1) * c2
≡⟨ distribBackR (a1 * b1) (a2 * b2) c1 ⟩ a1 * b1 * c1 + a2 * b2 * c1 + (a1 * b2 + a2 * b1) * c2
≡⟨ distribBackR (a1 * b2) (a2 * b1) c2 ⟩
a1 * b1 * c1 + a2 * b2 * c1 + (a1 * b2 * c2 + a2 * b1 * c2)
≡⟨ swap4 (a1 * b1 * c1) (a2 * b2 * c1) (a1 * b2 * c2) (a2 * b1 * c2) ⟩
a1 * b1 * c1 + a1 * b2 * c2 + (a2 * b2 * c1 + a2 * b1 * c2)
≡⟨ collectL a1 b1 c1 b2 c2 ⟩ a1 * (b1 * c1 + b2 * c2) + (a2 * b2 * c1 + a2 * b1 * c2)
≡⟨ collectL a2 b2 c1 b1 c2 ⟩ a1 * (b1 * c1 + b2 * c2) + a2 * (b2 * c1 + b1 * c2)
≡⟨ plusComm (b1 * c2) (b2 * c1) ⟩ a1 * (b1 * c1 + b2 * c2) + a2 * (b1 * c2 + b2 * c1)
sum4Distrib : (a1 a2 b1 b2 c1 c2 : ℕ)
→ a1 * b1 + a2 * b2 + (a1 * c2 + a2 * c1) ≡ a1 * (b1 + c2) + a2 * (b2 + c1)
using (distribBack, plusAssoc)
sum4Distrib =
λa1 a2 b1 b2 c1 c2. trans
_
_
_
swap4 (a1 * b1) (a2 * b2) (a1 * c2) (a2 * c1)
trans
_
_
_
cong (λu. ℕ) (λw. w + (a2 * b2 + a2 * c1)) {a1 * b1 + a1 * c2} {a1 * (b1 + c2)} distribBack
cong (λu. ℕ) (λw. a1 * (b1 + c2) + w) {a2 * b2 + a2 * c1} {a2 * (b2 + c1)} distribBack
sum4DistribR : (x1 x2 y1 y2 c1 c2 : ℕ)
→ x1 * c1 + x2 * c2 + (y1 * c2 + y2 * c1) ≡ (x1 + y2) * c1 + (x2 + y1) * c2
using (distribBackR, plusAssoc)
sum4DistribR =
λx1 x2 y1 y2 c1 c2. trans
_
_
_
swap4b
trans
_
_
_
cong (λu. ℕ) (λw. w + (x2 * c2 + y1 * c2)) (distribBackR x1 y2 c1)
cong (λu. ℕ) (λw. (x1 + y2) * c1 + w) (distribBackR x2 y1 c2)
intMulWD : (a1 a2 b1 b2 c1 c2 : ℕ)
(h : b1 + c2 ≡ b2 + c1)
→ a1 * b1 + a2 * b2 + (a1 * c2 + a2 * c1) ≡ a1 * b2 + a2 * b1 + (a1 * c1 + a2 * c2)
using (distribBack, distribBackR, hyp.rw, plusAssoc, sum4Distrib)
intMulWD =
λa1 a2 b1 b2 c1 c2 h. trans
_
_
_
sum4Distrib a1 a2 b1 b2 c1 c2
sym _ _ (sum4Distrib a1 a2 b2 b1 c2 c1)
intMulWDRep : (a1 a2 b1 b2 c1 c2 : ℕ)
(h : a1 + b2 ≡ a2 + b1)
→ a1 * c1 + a2 * c2 + (b1 * c2 + b2 * c1) ≡ a1 * c2 + a2 * c1 + (b1 * c1 + b2 * c2)
using (distribBack, hyp.rw, plusAssoc, plusComm, sum4DistribR)
intMulWDRep =
λa1 a2 b1 b2 c1 c2 h. trans
_
_
_
sum4DistribR a1 a2 b1 b2 c1 c2
sym _ _ (sum4DistribR a1 a2 b1 b2 c2 c1)
intMulWDOuter : (a b : ℕ × ℕ)
(h : a .π₁ + b .π₂ ≡ a .π₂ + b .π₁)
(zy : Int)
→ quot-elim (z. Int) (x. class (a .π₁ * x .π₁ + a .π₂ * x .π₂, a .π₁ * x .π₂ + a .π₂ * x .π₁)) zy
≡ quot-elim (x. class (b .π₁ * x .π₁ + b .π₂ * x .π₂, b .π₁ * x .π₂ + b .π₂ * x .π₁)) zy
using (distribBack,
distribBackR,
Int.Int.unfold,
Int.mul.intMulWD,
Int.mul.intMulWDRep,
multDistrib,
plusAssoc,
plusComm,
sum4Distrib,
sum4DistribR)
intMulWDOuter =
λa b h zy. quot-elim
q. quot-elim
z. Int
x. class (a .π₁ * x .π₁ + a .π₂ * x .π₂, a .π₁ * x .π₂ + a .π₂ * x .π₁)
q
≡ quot-elim (x. class (b .π₁ * x .π₁ + b .π₂ * x .π₂, b .π₁ * x .π₂ + b .π₂ * x .π₁)) q
c. ⋆
zy
infixl 7 *
* : Int → Int → Int
using (distribBackR, intMulWDOuter, Int.Int.unfold, Int.mul.intMulWD, plusAssoc, sum4Distrib)
(*) =
λx y. quot-elim
a. quot-elim (b. class (a .π₁ * b .π₁ + a .π₂ * b .π₂, a .π₁ * b .π₂ + a .π₂ * b .π₁)) y
x
intMulTest1 : class (2, Z) * class (3, Z) ≡ class (6, Z)
using (Int.Int.unfold, Int.mul.*.eq, Natural.*.eq, Natural.+.eq)
intMulTest1 = ⋆
intMulTest2 : class (Z, 2) * class (3, Z) ≡ class (Z, 6)
using (Int.Int.unfold, Int.mul.*.eq, Natural.*.eq, Natural.+.eq)
intMulTest2 = ⋆
classPairEta : (p : ℕ × ℕ) → class (p .π₁, p .π₂) ≡ class p ∈ Int using (Int.Int.unfold)
classPairEta = λp. cong (λu. Int) (λr. class r) (paireta p)
oneMult : (m : ℕ) → S Z * m ≡ m using (multComm)
oneMult = λm. S Z * m ≡⟨ sucMult Z m ⟩ m + Z * m ≡⟨ zeroMult m ⟩ m + Z ≡⟨ plusZeroId m ⟩ m
classCong2 : {u1 u2 v1 v2 : ℕ} → (u1 ≡ v1) → (u2 ≡ v2) → class (u1, u2) ≡ class (v1, v2) ∈ Int
using (hyp.rw, Int.Int.unfold)
classCong2 = λu1 u2 v1 v2 h1 h2. ⋆
intMulOneL : (z : Int) → intOne * z ≡ z
using (classPairEta,
Int.Int.unfold,
Int.intOne.eq,
Int.mul.*.eq,
oneMult,
oneMult.rw,
plusZeroId,
plusZeroId.rw,
zeroMult,
zeroMult.rw)
intMulOneL = λz. quot-elim (p. trans (class (p .π₁, p .π₂)) _ _ ⋆ (classPairEta p)) z
intMulOneR : (z : Int) → z * intOne ≡ z
using (classPairEta,
Int.Int.unfold,
Int.intOne.eq,
Int.mul.*.eq,
multSucId,
multSucId.rw,
multZeroId,
multZeroId.rw,
plusZeroId,
plusZeroId.rw,
zeroPlusId,
zeroPlusId.rw)
intMulOneR = λz. quot-elim (p. classPairEta p) z
intMulZeroL : (z : Int) → intZero * z ≡ intZero
using (distribBack,
distribBack.rw,
hyp.rw,
Int.mul.*.eq,
Int.Int.eq,
Int.Int.unfold,
Int.intZero.eq,
zeroMult,
zeroMult.rw)
intMulZeroL = λz. quot-elim (p. ⋆) z
intMulZeroR : {z : Int} → z * intZero ≡ intZero using (Int.Int.unfold, Int.intZero.eq, Int.mul.*.eq)
intMulZeroR = λz. quot-elim (p. ⋆) z
mulComm2 : (u1 u2 v1 v2 : ℕ) → u1 * v1 + u2 * v2 ≡ v1 * u1 + v2 * u2
mulComm2 =
λu1 u2 v1 v2. trans
_
_
_
cong (λw. ℕ) (λw. w + u2 * v2) (multComm v1 u1)
cong (λw. ℕ) (λw. v1 * u1 + w) (multComm v2 u2)
intMulComm : (x y : Int) → x * y ≡ y * x using (Int.Int.unfold, Int.mul.*.eq, plusAssoc)
intMulComm =
λx y. quot-elim
a. quot-elim
b. classCong2
mulComm2 (a .π₁) (a .π₂) (b .π₁) (b .π₂)
trans
_
_
_
mulComm2 (a .π₁) (a .π₂) (b .π₂) (b .π₁)
plusComm (b .π₁ * a .π₂) (b .π₂ * a .π₁)
y
x
intMulAssoc : (x y z : Int) → x * y * z ≡ x * (y * z) using (assocRep, Int.Int.unfold, Int.mul.*.eq)
intMulAssoc =
λx y z. quot-elim
a. quot-elim
b. quot-elim
c. classCong2
assocRep (a .π₁) (a .π₂) (b .π₁) (b .π₂) (c .π₁) (c .π₂)
assocRep (a .π₁) (a .π₂) (b .π₁) (b .π₂) (c .π₂) (c .π₁)
z
y
x
intMulDistribL : (x y z : Int) → x * (y + z) ≡ x * y + x * z
using (hyp.rw,
Int.mul.*.eq,
Int.Int.eq,
Int.Int.unfold,
Int.add.+.eq,
plusAssoc,
plusAssoc.rw,
sum4Distrib,
sum4Distrib.rw)
intMulDistribL = λx y z. quot-elim (a. quot-elim (b. quot-elim (c. ⋆) z) y) x
intAddCong2 : (x y u v : Int) → (x ≡ u) → (y ≡ v) → x + y ≡ u + v using (hyp.rw, Int.Int.unfold)
intAddCong2 = λx y u v h1 h2. ⋆
intMulCong2 : (x y u v : Int) → (x ≡ u) → (y ≡ v) → x * y ≡ u * v using (hyp.rw, Int.Int.unfold)
intMulCong2 = λx y u v h1 h2. ⋆
intMulDistribR : (x y z : Int) → (x + y) * z ≡ x * z + y * z
intMulDistribR =
λx y z. trans
_
_
_
trans _ _ _ (intMulComm (x + y) z) (intMulDistribL z x y)
intAddCong2 _ _ _ _ (intMulComm z x) (intMulComm z y)
intNegNeg : (z : Int) → intNeg (intNeg z) ≡ z using (classPairEta, Int.Int.unfold, Int.intNeg.eq)
intNegNeg = λz. quot-elim (p. classPairEta p) z
intAddNegR : (z : Int) → z + intNeg z ≡ intZero
using (Int.Int.unfold,
Int.intNeg.eq,
Int.intZero.eq,
Int.zeroEq,
Int.add.+.eq,
plusComm,
plusZeroId,
plusZeroId.rw)
intAddNegR = λz. quot-elim (p. ⋆) z
intAddNegL : (z : Int) → intNeg z + z ≡ intZero
using (Int.Int.unfold,
Int.intNeg.eq,
Int.intZero.eq,
Int.zeroEq,
Int.add.+.eq,
plusComm,
plusZeroId,
plusZeroId.rw)
intAddNegL = λz. quot-elim (p. ⋆) z
intMulNegL : (x y : Int) → intNeg x * y ≡ intNeg (x * y)
using (Int.Int.unfold, Int.intNeg.eq, Int.mul.*.eq)
intMulNegL =
λx y. quot-elim
a. quot-elim
b. classCong2
plusComm (a .π₁ * b .π₂) (a .π₂ * b .π₁)
plusComm (a .π₁ * b .π₁) (a .π₂ * b .π₂)
y
x
intMulNegR : (x y : Int) → x * intNeg y ≡ intNeg (x * y) using (intMulNegL)
intMulNegR =
λx y. trans
_
_
_
intMulComm x (intNeg y)
trans _ _ _ (intMulNegL y x) (cong (λu. Int) intNeg (intMulComm y x))