module Day4a
import System.File
import Data.Strings
import Data.Either
import Data.List
import Data.List.Quantifiers
import Data.List.Elem
import Decidable.Equality
import Data.Void
import Data.Nat
import Data.Nat.Order
import Decidable.Decidable
import Decidable.Order
import Data.String.Parser
import Data.Fin
import Data.Fin.Extra
%default total
Key : Type
Key = Fin 8
Cid : Key
Cid = FZ
It says that if we can decide a property for each finite number,
we can decide whether it holds for all members of Fin n
.
I should probably add this to the contrib
branch of the stdlib.
natToFinLTE : (n : Nat) -> LTE (S n) m -> Fin m
natToFinLTE n = weakenLTE (last {n})
natToFinToNat :
(n : Nat)
-> (lte : LTE (S n) m)
-> finToNat (natToFinLTE n lte) = n
natToFinToNat 0 (LTESucc lte) = Refl
natToFinToNat (S k) (LTESucc lte) = rewrite natToFinToNat k lte in Refl
-- natTOFinToNat n = ?nfn
-- lteDichotomy :
helper1 :
{P : (Fin (S n1) -> Type)}
-> P FZ
-> (x : Fin (S n1))
-> LTE (finToNat x) 0
-> P x
helper1 pf FZ LTEZero = pf
-- helper1 (LTESucc y) _ impossibl
helper2 :
{0 n1 : Nat}
-> {P : Fin (S n1) -> Type}
-> (bound' : Nat)
-> (bounded : LTE (S bound') n1)
-> P (FS $ natToFinLTE bound' bounded)
-> ((x : Fin (S n1)) -> LTE (finToNat x) bound' -> P x )
-> (x : Fin (S n1)) -> LTE (finToNat x) (S bound') -> P x
helper2 bound' bounded prf rec x lte with (isLTE (finToNat x) bound')
helper2 bound' bounded prf rec x lte | Yes lte2 = rec _ lte2
helper2 bound' bounded prf rec x lte | No nlte = rewrite eq in prf
where
natEq : finToNat x = S bound'
natEq = LTEIsAntisymmetric _ _ lte (notLTEImpliesGT nlte)
eq : x = (FS $ natToFinLTE bound' bounded)
eq = finToNatInjective _ _ $ trans natEq $ cong S (sym $ natToFinToNat _ _)
boundedFiniteDec :
{0 n : Nat}
-> {P : Fin n -> Type}
-> (bound : Nat)
-> (boundBounded : LTE (S bound) n)
-> (Dec (P (natToFinLTE bound boundBounded)) )
-> ((x : Fin n) -> Dec (P x))
-> Dec ((x : Fin n) -> LTE (finToNat x) bound -> P x )
boundedFiniteDec { n = n} bound boundBounded (No contra) ddec =
No $ \f => contra (f _ $ rewrite natToFinToNat bound boundBounded in lteRefl)
boundedFiniteDec { n = S n1} 0 (LTESucc _) (Yes prf) ddec = Yes $ helper1 prf
boundedFiniteDec { n = S n1} (S bound') (LTESucc lte) (Yes prf) ddec
with ( boundedFiniteDec { n = S n1} bound' (lteSuccRight lte) (ddec _) ddec)
boundedFiniteDec { n = S n1} (S bound') (LTESucc bounded) (Yes prf) ddec | No nrec =
No $ \ f => nrec $ \x, lte => f _ (lteSuccRight lte)
boundedFiniteDec { n = S n1} (S bound') (LTESucc bounded) (Yes prf) ddec | Yes rec =
Yes $ helper2 bound' bounded prf rec
record BoundedEx {n : Nat} (bound : Nat) (P : Fin n -> Type) where
constructor BndEx
{bndWitness : Fin n}
0 bndLTE : LTE (finToNat bndWitness) bound
bndPf : P bndWitness
boundedFiniteEx :
{0 n : Nat}
-> {P : Fin n -> Type}
-> (bound : Nat)
-> (boundBounded : LTE (S bound) n)
-> (Dec (P (natToFinLTE bound boundBounded)) )
-> ((x : Fin n) -> Dec (P x))
-> Dec (BoundedEx bound P)
boundedFiniteEx {n = n} bound boundBounded (Yes pf) ddec =
Yes $ BndEx (rewrite natToFinToNat bound boundBounded in lteRefl) pf
boundedFiniteEx {n = S n1} 0 (LTESucc bounded)(No npf) ddec = No $ \bnd => helper (bndLTE bnd) (bndPf bnd)
where
helper : {x : Fin (S n1)} -> (0 _ : LTE (finToNat x) 0) -> P x -> Void
helper {x = FZ} LTEZero pf = npf pf
boundedFiniteEx {n = S n1} (S bound') (LTESucc lte) (No npf) ddec with (boundedFiniteEx { n = S n1} bound' (lteSuccRight lte) (ddec _) ddec)
boundedFiniteEx {n = S n1} (S bound') (LTESucc lte) (No npf) ddec | Yes bnd =
Yes $ BndEx (lteSuccRight $ bndLTE bnd) (bndPf bnd)
boundedFiniteEx {n = S n1} (S bound') (LTESucc lte) (No npf) ddec | No rec =
No \ bnd => void $ helper (bndLTE bnd) (bndPf bnd)
where
helper : {x : Fin (S n1)} -> LTE (finToNat x) (S bound') -> P x -> Void
helper {x = x} xlte px with (isLTE (finToNat x) bound')
helper {x = x} xlte px | Yes blte = rec $ BndEx blte px
helper {x = x} xlte px | No nlt = npf $ (rewrite (sym eq) in px)
where
eq : x = (FS $ natToFinLTE bound' lte)
eq = finToNatInjective _ _ $ trans (LTEIsAntisymmetric _ _ xlte (notLTEImpliesGT nlt)) $ cong S (sym $ natToFinToNat _ _)
finiteDecEx : {k : Nat} -> {P : Fin k -> Type} -> ((x : Fin k) -> Dec (P x)) -> Dec (x : Fin k ** P x)
finiteDecEx {k = 0} dec = No $ \ pr => absurd (fst pr)
finiteDecEx {k = (S n1)} dec
with (boundedFiniteEx (finToNat last) (elemSmallerThanBound (last {n = n1})) (dec _) dec)
finiteDecEx {k = (S n1)} dec | Yes bnd = Yes (bndWitness bnd ** bndPf bnd)
finiteDecEx {k = (S n1)} dec | No nbnd = No $ \ pr => nbnd $ BndEx lessThanLast (snd pr)
where
lessThanLast : {x : Fin (S n1)} -> LTE (finToNat x) (finToNat (last {n = n1} ))
lessThanLast {x} =
rewrite finToNatLastIsBound {n = n1}
in fromLteSucc $ elemSmallerThanBound x
finiteDec : {n : Nat} -> {P : Fin n -> Type} -> ((x : Fin n) -> Dec (P x)) -> Dec ((x : Fin n) -> P x)
finiteDec {n = Z} dec = Yes $ \ x => absurd x
finiteDec {n = S n1} dec with (boundedFiniteDec (finToNat last) (elemSmallerThanBound (last {n = n1})) (dec _) dec)
finiteDec {n = S n1} dec | Yes pf =
Yes $ \ x => pf x $ rewrite finToNatLastIsBound {n = n1} in fromLteSucc $ elemSmallerThanBound _
finiteDec {n = S n1} dec | No npf = No $ \f => npf $ \ x, lte => f x
-- HasAllKeys : List Key -> Type
-- HasAllKeys l = (k : Key) -> Either (k = Cid) (Elem k l)