packages feed

idris-1.3.3: libs/contrib/Data/Nat/Parity.idr

module Data.Nat.Parity

%access public export

----------------------------------------

-- Type-level, constructive definitions of parity.

||| A nat is Even when it is twice some other nat.
Even : Nat -> Type
Even n = (half : Nat ** n = half * 2)

||| A nat is Odd when it is one more than twice some other nat.
Odd : Nat -> Type
Odd n = (haf : Nat ** n = S $ haf * 2)

----------------------------------------

||| Two more than an Even is Even.
add2Even : Even n -> Even (2 + n)
add2Even (half ** pf) = (S half ** cong {f = (+) 2} pf)

||| Two more than an Odd is Odd.
add2Odd : Odd n -> Odd (2 + n)
add2Odd (haf ** pf) = (S haf ** cong {f = (+) 2} pf)

||| One more than an Even is Odd.
succEvenOdd : Even n -> Odd (S n)
succEvenOdd (half ** pf) = (half ** cong {f = S} pf)

||| One more than an Odd is Even.
succOddEven : Odd n -> Even (S n)
succOddEven (haf ** pf) = (S haf ** cong {f = S} pf)

||| One less than an Odd is Even.
predOddEven : Odd (S n) -> Even n
predOddEven (haf ** pf) = (haf ** cong {f = Nat.pred} pf)

||| A helper fact.
succDoublePredPred : S n = k * 2 -> n = S $ (pred k) * 2
succDoublePredPred {k = Z} prf = absurd prf
succDoublePredPred {k = S _} prf = cong {f = Nat.pred} prf

||| One less than an Even is Odd.
predEvenOdd : Even (S n) -> Odd n
predEvenOdd (half ** pf) = (pred half ** succDoublePredPred pf)

----------------------------------------

-- Boolean definitions of parity.

mutual
  even : Nat -> Bool
  even Z = True
  even (S k) = odd k

  odd : Nat -> Bool
  odd Z = False
  odd (S k) = even k

----------------------------------------

-- The boolean and type-level definitions are equivalent in the sense
-- that a proof of one can be gotten from a proof of the other.

mutual
  ||| Evens are even.
  evenEven : Even n -> even n = True
  evenEven {n = Z} _ = Refl
  evenEven {n = S _} pf = oddOdd $ predEvenOdd pf

  ||| Odds are odd.
  oddOdd : Odd n -> odd n = True
  oddOdd {n = Z} (_ ** pf) = absurd pf
  oddOdd {n = S _} pf = evenEven $ predOddEven pf

mutual
  ||| If it's even, it's Even.
  evenEvenConverse : even n = True -> Even n
  evenEvenConverse {n = Z} prf = (0 ** Refl)
  evenEvenConverse {n = S k} prf =
    let (haf ** pf) = oddOddConverse prf in
      (S haf ** cong pf)

  ||| If it's odd, it's Odd
  oddOddConverse : odd n = True -> Odd n
  oddOddConverse {n = Z} prf = absurd prf
  oddOddConverse {n = S k} prf =
    let (half ** pf) = evenEvenConverse prf in
      (half ** cong pf)

----------------------------------------

||| Every nat is either even or odd.
evenorodd : (n : Nat) -> Either (even n = True) (odd n = True)
evenorodd Z = Left Refl
evenorodd (S k) = case evenorodd k of
  Left l => Right l
  Right r => Left r

||| Every nat is either Even or Odd.
evenOrOdd : (n : Nat) -> Either (Even n) (Odd n)
evenOrOdd n = case evenorodd n of
  Left e => Left $ evenEvenConverse e
  Right o => Right $ oddOddConverse o

||| No nat is both even and odd.
notevenandodd : even n = True -> odd n = True -> Void
notevenandodd {n = Z} en on = absurd on
notevenandodd {n = S _} en on = notevenandodd on en

||| No nat is both Even and Odd.
notEvenAndOdd : Even n -> Odd n -> Void
notEvenAndOdd en on = notevenandodd (evenEven en) (oddOdd on)

||| Evenness is decidable.
evenDec : (n : Nat) -> Dec $ Even n
evenDec n = case evenOrOdd n of
  Left even => Yes even
  Right odd => No $ \even => notEvenAndOdd even odd

||| Oddness is decidable.
oddDec : (n : Nat) -> Dec $ Odd n
oddDec n = case evenOrOdd n of
  Left even => No $ notEvenAndOdd even
  Right odd => Yes odd

----------------------------------------

||| An Odd is the successor of an Even.
oddSuccEven : Odd n -> (m : Nat ** (n = S m, Even m))
oddSuccEven (haf ** pf) = (haf * 2 ** (pf, (haf ** Refl)))

||| Even plus Even is Even.
evenPlusEven : Even j -> Even k -> Even (j + k)
evenPlusEven (half_j ** pf_j) (half_k ** pf_k) =
  (half_j + half_k **
    rewrite pf_j in
      rewrite pf_k in
        sym $ multDistributesOverPlusLeft half_j half_k 2)

||| Odd plus Even is Odd.
oddPlusEven : Odd j -> Even k -> Odd (j + k)
oddPlusEven oj ek =
  let
    (i ** (ipj, ei)) = oddSuccEven oj
    (half_ik ** eik) = evenPlusEven ei ek
      in
  (half_ik **
    rewrite ipj in
      cong {f = S} eik)

||| Even plus Odd is Odd.
evenPlusOdd : Even j -> Odd k -> Odd (j + k)
evenPlusOdd {j} {k} ej ok = rewrite plusCommutative j k in oddPlusEven ok ej

||| Odd plus Odd is Even.
oddPlusOdd : Odd j -> Odd k -> Even (j + k)
oddPlusOdd oj ok =
  let
    (i ** (ipj, ei)) = oddSuccEven oj
    (haf_ik ** oik) = evenPlusOdd ei ok
      in
  (S haf_ik **
    rewrite ipj in
      rewrite oik in
        Refl)

||| A helper fact.
multShuffle : (a, b, c : Nat) ->
  (a * c) * (b * c) = ((a * b) * c) * c
multShuffle a b c =
  rewrite multAssociative (a * c) b c in
    rewrite multCommutative (a * c) b in
      rewrite multAssociative b a c in
        rewrite multCommutative b a in
          Refl

||| Even times Even is Even.
evenMultEven : Even j -> Even k -> Even (j * k)
evenMultEven (half_j ** pf_j) (half_k ** pf_k) =
  (half_j * half_k * 2 **
    rewrite pf_j in
      rewrite pf_k in
        multShuffle half_j half_k 2)

||| Odd times Even is Even.
oddMultEven : Odd j -> Even k -> Even (j * k)
oddMultEven oj (half_k ** pf_k) =
  let
    (i ** (ipj, ei)) = oddSuccEven oj
    (half_ik ** oik) = evenMultEven ei (half_k ** pf_k)
      in
  (half_k + half_ik **
    rewrite multDistributesOverPlusLeft half_k half_ik 2 in
      rewrite ipj in
        rewrite oik in
          rewrite pf_k in
            Refl)

||| Even times Odd is Even.
evenMultOdd : Even j -> Odd k -> Even (j * k)
evenMultOdd {j} {k} ej ok = rewrite multCommutative j k in oddMultEven ok ej

||| Odd times Odd is Odd.
oddMultOdd : Odd j -> Odd k -> Odd (j * k)
oddMultOdd oj (haf_k ** pf_k) =
  let
    (i ** (ipj, ei)) = oddSuccEven oj
    (half_ik ** eik) = evenMultOdd ei (haf_k ** pf_k)
      in
  (haf_k + half_ik **
    rewrite multDistributesOverPlusLeft haf_k half_ik 2 in
      rewrite ipj in
        rewrite eik in
          rewrite pf_k in
            Refl)