module Data.INTEGER import Data.Nat import Syntax.PreorderReasoning %default total public export data INTEGER : Type where Z : INTEGER PS : Nat -> INTEGER NS : Nat -> INTEGER public export Cast Nat INTEGER where cast Z = Z cast (S n) = PS n public export Cast Integer INTEGER where cast i = case compare 0 i of LT => PS (cast (i - 1)) EQ => Z GT => NS (cast (negate i - 1)) public export Cast INTEGER Integer where cast Z = 0 cast (PS n) = 1 + cast n cast (NS n) = negate (1 + cast n) public export Show INTEGER where show = show . cast {to = Integer} public export add : INTEGER -> INTEGER -> INTEGER add Z n = n add m Z = m add (PS m) (PS n) = PS (S (m + n)) add (NS m) (NS n) = NS (S (m + n)) add (PS m) (NS n) = case compare m n of LT => NS (minus n (S m)) -- 1+m-1-n = 1+(m-n-1) EQ => Z GT => PS (minus m (S n)) add (NS n) (PS m) = case compare m n of LT => NS (minus n (S m)) EQ => Z GT => PS (minus m (S n)) public export mult : INTEGER -> INTEGER -> INTEGER mult Z n = Z mult m Z = Z mult (PS m) (PS n) = PS (m * n + m + n) mult (NS m) (NS n) = PS (m * n + m + n) mult (PS m) (NS n) = NS (m * n + m + n) mult (NS m) (PS n) = NS (m * n + m + n) public export Num INTEGER where fromInteger = cast (+) = add (*) = mult export plusZeroRightNeutral : (m : INTEGER) -> m + 0 === m plusZeroRightNeutral Z = Refl plusZeroRightNeutral (PS k) = Refl plusZeroRightNeutral (NS k) = Refl export plusCommutative : (m, n : INTEGER) -> m + n === n + m plusCommutative Z n = sym $ plusZeroRightNeutral n plusCommutative m Z = plusZeroRightNeutral m plusCommutative (PS k) (PS j) = cong (PS . S) (plusCommutative k j) plusCommutative (NS k) (NS j) = cong (NS . S) (plusCommutative k j) plusCommutative (PS k) (NS j) with (compare k j) _ | LT = Refl _ | EQ = Refl _ | GT = Refl plusCommutative (NS k) (PS j) with (compare j k) _ | LT = Refl _ | EQ = Refl _ | GT = Refl export castPlus : (m, n : Nat) -> the INTEGER (cast (m + n)) = cast m + cast n castPlus 0 n = Refl castPlus (S m) 0 = cong PS (plusZeroRightNeutral m) castPlus (S m) (S n) = cong PS (sym $ plusSuccRightSucc m n) public export Neg INTEGER where negate Z = Z negate (PS n) = NS n negate (NS n) = PS n m - n = add m (negate n) export unfoldPS : (m : Nat) -> PS m === 1 + cast m unfoldPS Z = Refl unfoldPS (S m) = Refl export unfoldNS : (m : Nat) -> NS m === - 1 - cast m unfoldNS Z = Refl unfoldNS (S m) = Refl export difference : (m, n : Nat) -> INTEGER difference 0 n = - cast n difference m 0 = cast m difference (S m) (S n) = difference m n export differenceZeroRight : (n : Nat) -> difference n 0 === cast n differenceZeroRight 0 = Refl differenceZeroRight (S k) = Refl export minusSuccSucc : (m, n : Nat) -> the INTEGER (cast (S m) - cast (S n)) === cast m - cast n minusSuccSucc 0 0 = Refl minusSuccSucc 0 (S n) = cong NS (minusZeroRight n) minusSuccSucc (S m) 0 = cong PS (minusZeroRight m) minusSuccSucc (S m) (S n) with (compare m n) _ | LT = Refl _ | EQ = Refl _ | GT = Refl export unfoldDifference : (m, n : Nat) -> difference m n === cast m - cast n unfoldDifference 0 n = Refl unfoldDifference m 0 = Calc $ |~ difference m 0 ~~ cast m ...( differenceZeroRight m ) ~~ cast m + 0 ...( sym (plusZeroRightNeutral $ cast m) ) unfoldDifference (S m) (S n) = Calc $ |~ difference m n ~~ cast m - cast n ...( unfoldDifference m n ) ~~ cast (S m) - cast (S n) ...( sym (minusSuccSucc m n) ) export negateInvolutive : (m : INTEGER) -> - - m === m negateInvolutive Z = Refl negateInvolutive (PS k) = Refl negateInvolutive (NS k) = Refl export negatePlus : (m, n : INTEGER) -> - (m + n) === - m + - n negatePlus Z n = Refl negatePlus (PS k) Z = Refl negatePlus (NS k) Z = Refl negatePlus (PS k) (PS j) = Refl negatePlus (PS k) (NS j) with (compare k j) proof eq _ | LT = rewrite compareNatFlip k j in rewrite eq in Refl _ | EQ = rewrite compareNatFlip k j in rewrite eq in Refl _ | GT = rewrite compareNatFlip k j in rewrite eq in Refl negatePlus (NS k) (PS j) with (compare k j) proof eq _ | LT = rewrite compareNatFlip k j in rewrite eq in Refl _ | EQ = rewrite compareNatFlip k j in rewrite eq in Refl _ | GT = rewrite compareNatFlip k j in rewrite eq in Refl negatePlus (NS k) (NS j) = Refl export negateDifference : (m, n : Nat) -> - difference m n === difference n m negateDifference 0 n = Calc $ |~ - - cast n ~~ cast n ...( negateInvolutive (cast n) ) ~~ difference n 0 ...( sym (differenceZeroRight n) ) negateDifference m 0 = cong negate (differenceZeroRight m) negateDifference (S m) (S n) = negateDifference m n plusNatDifferenceLeft : (m, n, p : Nat) -> cast m + difference n p === difference (m + n) p plusNatDifferenceLeft m 0 p = Calc $ |~ cast m - cast p ~~ difference m p ...( sym (unfoldDifference m p) ) ~~ difference (m + 0) p ...( cong (flip difference p) (sym $ plusZeroRightNeutral m) ) plusNatDifferenceLeft m (S n) p = Calc $ |~ cast m + difference (S n) p ~~ PS m + difference n p ...( sym (aux n p m) ) ~~ difference (S m + n) p ...( plusNatDifferenceLeft (S m) n p ) ~~ difference (m + S n) p ...( cong (flip difference p) (plusSuccRightSucc m n) ) where aux : (m, n, p : Nat) -> PS p + difference m n === cast p + difference (S m) n aux 0 0 p = Calc $ |~ PS p ~~ 1 + cast p ...( unfoldPS p ) ~~ cast p + 1 ...( plusCommutative 1 (cast p) ) aux 0 (S k) p = Calc $ |~ PS p + NS k ~~ difference (S p) (S k) ...( sym (unfoldDifference (S p) (S k)) ) ~~ difference p k ...( Refl ) ~~ cast p - cast k ...( unfoldDifference p k ) aux (S k) 0 p = sym $ Calc $ |~ cast p + PS (S k) ~~ cast (p + S (S k)) ...( sym (castPlus p (S (S k))) ) ~~ cast (S (p + S k)) ...( cong cast (sym $ plusSuccRightSucc p (S k)) ) ~~ cast (S (S p + k)) ...( cong PS (sym $ plusSuccRightSucc p k) ) aux (S k) (S j) p = aux k j p minusNatDifferenceRight : (m, n, p : Nat) -> - cast m + difference n p === difference n (m + p) minusNatDifferenceRight m n p = Calc $ |~ - cast m + difference n p ~~ - cast m - - difference n p ...( cong (- cast m +) (sym $ negateInvolutive ?) ) ~~ - (cast m - difference n p) ...( sym (negatePlus (cast m) (- difference n p)) ) ~~ - (cast m + difference p n) ...( cong (negate . (cast m +)) (negateDifference n p) ) ~~ - (difference (m + p) n) ...( cong negate (plusNatDifferenceLeft m p n) ) ~~ - - difference n (m + p) ...( cong negate (sym $ negateDifference n (m + p)) ) ~~ difference n (m + p) ...( negateInvolutive ? ) export minusZeroRight : (m : INTEGER) -> m - 0 === m minusZeroRight = plusZeroRightNeutral export plusInverse : (m : INTEGER) -> m - m === Z plusInverse Z = Refl plusInverse (PS k) = rewrite compareNatDiag k in Refl plusInverse (NS k) = rewrite compareNatDiag k in Refl export plusAssociative : (m, n, p : INTEGER) -> m + (n + p) === (m + n) + p plusAssociative Z n p = Refl plusAssociative m Z p = cong (+ p) (sym $ plusZeroRightNeutral m) plusAssociative m n Z = Calc $ |~ m + (n + Z) ~~ m + n ...( cong (m +) (plusZeroRightNeutral n) ) ~~ m + n + Z ...( sym $ plusZeroRightNeutral (m + n) ) plusAssociative (PS k) (PS j) (PS i) = cong (PS . S) $ Calc $ |~ k + S (j + i) ~~ S (k + (j + i)) ...( sym (plusSuccRightSucc k (j + i)) ) ~~ S ((k + j) + i) ...( cong S (plusAssociative k j i) ) plusAssociative (PS k) (PS j) (NS i) = Calc $ |~ PS k + (PS j - PS i) ~~ PS k + difference (S j) (S i) ...( cong (PS k +) (sym $ unfoldDifference (S j) (S i)) ) ~~ difference (S k + S j) (S i) ...( plusNatDifferenceLeft (S k) (S j) (S i) ) ~~ difference (S (S (k + j))) (S i) ...( cong (flip difference (S i)) (sym $ plusSuccRightSucc (S k) j) ) ~~ PS k + PS j - PS i ...( unfoldDifference (S (S (k + j))) (S i) ) plusAssociative (PS k) (NS j) (PS i) = Calc $ |~ PS k + (NS j + PS i) ~~ PS k + (PS i + NS j) ...( cong (PS k +) (plusCommutative (NS j) (PS i)) ) ~~ PS k + difference (S i) (S j) ...( cong (PS k +) (sym $ unfoldDifference (S i) (S j)) ) ~~ difference (S k + S i) (S j) ...( plusNatDifferenceLeft (S k) (S i) (S j) ) ~~ difference (S i + S k) (S j) ...( cong (flip difference (S j)) (plusCommutative (S k) (S i)) ) ~~ PS i + difference (S k) (S j) ...( sym (plusNatDifferenceLeft (S i) (S k) (S j)) ) ~~ difference (S k) (S j) + PS i ...( plusCommutative (PS i) (difference (S k) (S j)) ) ~~ PS k + NS j + PS i ...( cong (+ PS i) (unfoldDifference (S k) (S j)) ) plusAssociative (PS k) (NS j) (NS i) = Calc $ |~ PS k + NS (S j + i) ~~ difference (S k) (S (S j + i)) ...( sym (unfoldDifference (S k) (S (S j + i))) ) ~~ difference (S k) (S i + S j) ...( cong (difference k) (plusCommutative (S j) i) ) ~~ NS i + difference (S k) (S j) ...( sym (minusNatDifferenceRight (S i) (S k) (S j)) ) ~~ difference (S k) (S j) + NS i ...( plusCommutative (NS i) (difference (S k) (S j)) ) ~~ (PS k + NS j) + NS i ...( cong (+ NS i) (unfoldDifference (S k) (S j)) ) plusAssociative (NS k) (PS j) (PS i) = Calc $ |~ NS k + (PS j + PS i) ~~ (PS j + PS i) + NS k ...( plusCommutative (NS k) (PS j + PS i) ) ~~ difference (S (S (j + i))) (S k) ...( sym (unfoldDifference (S (S (j + i))) (S k)) ) ~~ difference (S i + S j) (S k) ...( cong (flip difference k) (plusCommutative (S j) i) ) ~~ PS i + difference (S j) (S k) ...( sym (plusNatDifferenceLeft (S i) (S j) (S k)) ) ~~ difference (S j) (S k) + PS i ...( plusCommutative (PS i) (difference (S j) (S k)) ) ~~ (PS j + NS k) + PS i ...( cong (+ PS i) (unfoldDifference (S j) (S k)) ) ~~ (NS k + PS j) + PS i ...( cong (+ PS i) (plusCommutative (PS j) (NS k)) ) plusAssociative (NS k) (PS j) (NS i) = Calc $ |~ NS k + (PS j + NS i) ~~ NS k + difference (S j) (S i) ...( cong (NS k +) (sym $ unfoldDifference (S j) (S i)) ) ~~ difference (S j) (S k + S i) ...( minusNatDifferenceRight (S k) (S j) (S i) ) ~~ difference (S j) (S i + S k) ...( cong (difference (S j)) (plusCommutative (S k) (S i)) ) ~~ NS i + difference (S j) (S k) ...( sym (minusNatDifferenceRight (S i) (S j) (S k)) ) ~~ difference (S j) (S k) + NS i ...( plusCommutative (NS i) (difference (S j) (S k)) ) ~~ (PS j + NS k) + NS i ...( cong (+ NS i) (unfoldDifference (S j) (S k)) ) ~~ (NS k + PS j) + NS i ...( cong (+ NS i) (plusCommutative (PS j) (NS k)) ) plusAssociative (NS k) (NS j) (PS i) = Calc $ |~ NS k + (NS j + PS i) ~~ NS k + (PS i + NS j) ...( cong (NS k +) (plusCommutative (NS j) (PS i)) ) ~~ NS k + difference (S i) (S j) ...( cong (NS k +) (sym $ unfoldDifference (S i) (S j)) ) ~~ difference (S i) (S k + S j) ...( minusNatDifferenceRight (S k) (S i) (S j) ) ~~ difference (S i) (S (S (k + j))) ...( cong (difference i) (sym $ plusSuccRightSucc k j) ) ~~ PS i + (NS k + NS j) ...( unfoldDifference (S i) (S (S (k + j))) ) ~~ (NS k + NS j) + PS i ...( plusCommutative (PS i) (NS k + NS j) ) plusAssociative (NS k) (NS j) (NS i) = cong (NS . S) $ Calc $ |~ k + S (j + i) ~~ S (k + (j + i)) ...( sym (plusSuccRightSucc k (j + i)) ) ~~ S ((k + j) + i) ...( cong S (plusAssociative k j i) )