module miniSatSolverNonDependentVers4 where
 
{- variant of miniSatSolver
   so that the check uses no dependent types -}


{- The first part can be implemented in Haskell
  and doesn't make use of dependent types. -}

{- Basic sets -}

data  : Set where
  zero :  
  _+1  :   

{-# BUILTIN NATURAL    #-}
{-# BUILTIN SUC    _+1  #-}
{-# BUILTIN ZERO    zero #-}

max :      
max 0      n      = n 
max n      0      = n
max (n +1) (m +1) = (max n m) +1


data 𝔹 : Set where
  tt : 𝔹
  ff : 𝔹

{-# BUILTIN BOOL  𝔹  #-}
{-# BUILTIN TRUE  tt    #-}
{-# BUILTIN FALSE ff    #-}


_∧𝔹_ : 𝔹  𝔹  𝔹
tt ∧𝔹 b = b
ff ∧𝔹 _ = ff

_∨𝔹_ : 𝔹  𝔹  𝔹
tt ∨𝔹 _ = tt
ff ∨𝔹 b = b

¬𝔹 : 𝔹  𝔹
¬𝔹 tt = ff
¬𝔹 ff = tt



{- The data type of formulas -}

data For : Set where
  const  : 𝔹   For 
  x      :     For
  _∧for_ : For   For   For
  _∨for_ : For   For   For
  ¬for   : For    For 

{- check0 checks whether the formula is valid if all variables
are instantiated with tt -}

check0 : For   𝔹
check0 (const b)  = b
check0 (x _)      = tt
check0 (φ ∧for ψ) = check0 φ ∧𝔹 check0 ψ
check0 (φ ∨for ψ) = check0 φ ∨𝔹 check0 ψ
check0 (¬for φ)   = ¬𝔹 (check0 φ)


instantiate- : For   𝔹   For
instantiate-  (const b)     b' = const b
instantiate-  (x 0)         b  = const b
instantiate-  (x (m +1))    b  = x m
instantiate-  (φ ∧for ψ )   b  = (instantiate-  φ b ) ∧for (instantiate-  ψ b) 
instantiate-  (φ ∨for ψ )   b  = (instantiate-  φ b ) ∨for (instantiate-  ψ b) 
instantiate-  (¬for φ)      b  = ¬for (instantiate-  φ b ) 

{- check1 n checks whether a formula is valid if the variables with number
 >= n are instantiated with tt -}

check1 : For     𝔹
check1 φ 0      = check0 φ
check1 φ (m +1) = check1 (instantiate- φ tt) m ∧𝔹 check1 (instantiate- φ ff) m 



maxVar : For   
maxVar (const _)    = 0
maxVar (x n)        = n +1
maxVar (φ  ∧for ψ ) = max (maxVar φ) (maxVar ψ)
maxVar (φ ∨for ψ)   = max (maxVar φ) (maxVar ψ)
maxVar (¬for φ)     = maxVar φ





check : For  𝔹
check φ = check1  φ (maxVar φ)


{- From here onwards we use dependent types.
   Up to the function check everything can be programmed
   in haskell, with check being replaced by a sat solver
   and then we can use builtins in a possible extension of Agda
   
   The rest is about proving that the above is correct -}


{- Further basic types -}

data  : Set where
  triv :  

data  : Set where



data Vec (A : Set) :   Set where
  []   : Vec A 0
  _::_ : {n : }   A   Vec A n   Vec A (n +1)

_≦_ :     Set 
0     n    =  
_ +1  0    =  
n +1  m +1 = n  m


maxlem1 : (n m k : )  (max n m  k)  n  k
maxlem1 0      _       _       _ = triv
maxlem1 (_ +1) 0       _      p = p
maxlem1 (_ +1) (_ +1) 0       ()
maxlem1 (n +1) (m +1) (k +1) p = maxlem1 n m k p


maxlem2 : (n m k : )  (max n m  k)  m  k
maxlem2 _      0       _     _  = triv
maxlem2 0       (_ +1) _     p  = p
maxlem2 (_ +1) (_ +1) 0      () 
maxlem2 (n +1) (m +1) (k +1) p  = maxlem2 n m k p

{- leq operation on Nat -}

refl≦  : {n : }  n  n
refl≦ {0}    = triv
refl≦ {n +1} = refl≦ {n}



-- allTt n 
-- is a Vector of length n consisting of tt
allTt : (n : )  Vec 𝔹 n
allTt 0      = []
allTt (n +1) = tt :: allTt n 




{- nthWithDefault a n v  
   returns the nth element of v if it exists
   if it doesn't exit it returns the default value a -}

nthWithDefault : {A : Set}   (default : A)      {n : }  Vec A n  A
nthWithDefault default _       []       = default
nthWithDefault default 0    (a :: _)    = a
nthWithDefault default (k +1) (_ :: v)  = nthWithDefault default k v


head : {A : Set}   {n : }   Vec A (n +1)   A
head (a :: _) = a

tail : {A : Set}   {n : }   Vec A (n +1)   Vec A n
tail (_ :: v) = v


-- truncateWithDefaultTt
-- truncates a list to a vector of length n
-- by cutting the list off after the nth element
-- and expanding it if necessary by adding tt
truncateWithDefaultTt : {m : }  Vec 𝔹 m  (n : )  Vec 𝔹 n
truncateWithDefaultTt  []          n       = allTt n
truncateWithDefaultTt  (_ :: _)    0       = []
truncateWithDefaultTt  (b :: bvec) (n +1)  = b :: truncateWithDefaultTt bvec n



{- Logic -}

Atom : 𝔹  Set
Atom tt =  
Atom ff =  


data _∧_ (A B :  Set) : Set where
  and : A   B   A  B

data _∨_ (A B :  Set) : Set where
  inl : A   A  B
  inr : B   A  B

¬ : Set  Set
¬ A = A   


_↔_ : Set  Set  Set
A  B = (A  B)  (B  A)





{- Lifting of check0, check1 check from 𝔹 to Set using Atom -}

Check0 : For   Set
Check0 φ = Atom (check0 φ)



Check1 : For   (n : )  Set
Check1 φ n = Atom (check1 φ n)


Check : For   Set
Check φ = Atom (check φ)



{- Conversion of elements of For into formulas
  
  [[ φ ]]
    gives formulas of the form
    ( (Atom b ∧ Atom b') ∨ (¬ (Atom b))) ∨ (¬ (Atom b') )

  [[ φ ]]' 
    gives formulas of the form
    Atom (((b ∧𝔹 b') ∨𝔹 ¬𝔹 b) ∨𝔹 ¬𝔹 b')


  [[ φ ]]b gives the boolean value used in
   [[ φ ]]' n 

  all variables with number >= n are replaced by the default
  value tt
-}
  
[[_]] : For   {n : }  Vec 𝔹 n   Set
[[ const b  ]] _    = Atom b
[[ x k      ]] bvec = Atom (nthWithDefault tt k bvec)
[[ φ ∧for ψ ]] bvec = [[ φ ]] bvec  [[ ψ ]] bvec
[[ φ ∨for ψ ]] bvec = [[ φ ]] bvec  [[ ψ ]] bvec
[[ ¬for φ   ]] bvec = ¬ ([[ φ ]] bvec)

[[_]]b  : For   {n : }   Vec 𝔹 n   𝔹
[[ const b   ]]b _    = b
[[ x k       ]]b bvec = nthWithDefault tt  k bvec
[[ φ  ∧for ψ ]]b bvec = [[ φ ]]b bvec ∧𝔹 [[ ψ ]]b bvec
[[ φ ∨for ψ  ]]b bvec = [[ φ ]]b bvec ∨𝔹 [[ ψ ]]b bvec
[[ ¬for φ    ]]b bvec = ¬𝔹 ([[ φ ]]b bvec)

[[_]]' : For   {n : }   Vec 𝔹 n   Set
[[ φ ]]' bvec = Atom ([[ φ ]]b bvec)



{- Lemmas about ∧ ∨ ¬ -}

lemma∧proj1 : (A B : Set)   A  B   A
lemma∧proj1 A B (and a _) = a

lemma∧proj2 : (A B : Set)   A  B   B
lemma∧proj2 A B (and _ b) = b


lemma∧1 : (b b' : 𝔹)    Atom (b ∧𝔹 b')  Atom b  Atom b' 
lemma∧1 tt _ p = and triv p
lemma∧1 ff _ () 

lemma∧2 : (b b' : 𝔹)    Atom b  Atom b'  Atom (b ∧𝔹 b')
lemma∧2 tt _ (and _  q) = q
lemma∧2 ff _ (and () _ )


lemma∧→ : (A B C D : Set)   (A   C)   (B   D)   (A  B)   C  D
lemma∧→ A B C D f g (and a b) = and (f a) (g b)


lemma∨1 : (b b' : 𝔹)    Atom (b ∨𝔹 b')  Atom b   Atom b' 
lemma∨1 tt _ _ = inl triv
lemma∨1 ff _ p = inr p

lemma∨2 : (b b' : 𝔹)    Atom b   Atom b'   Atom (b ∨𝔹 b')  
lemma∨2 tt _ _        = triv
lemma∨2 ff _ (inl ())
lemma∨2 ff _ (inr p)  = p

lemma∨→ : (A B C D : Set)   (A   C)   (B   D)   (A  B)   C  D
lemma∨→ A B C D f g (inl a) = inl (f a)
lemma∨→ A B C D f g (inr b) = inr (g b)

lemma¬1 : (b : 𝔹)    Atom (¬𝔹 b)  ¬ (Atom b)
lemma¬1 tt p _ = p
lemma¬1 ff _ p = p

lemma¬2 : (b : 𝔹)    ¬ (Atom b)  Atom (¬𝔹 b)  
lemma¬2 tt p  = p triv
lemma¬2 ff _  = triv

lemma¬→ : (A B : Set)   (B   A)   ¬ A  ¬ B
lemma¬→ A B f g b = g (f b)


{- Proof of the correctness -}

{- Step 1 we prove 
   Check0 φ  ↔ [[ φ ]] [] 
   this shows that correctness of check1 φ 0 ,
  i.e. gives in the inductive proof of correctnessCheck1
  the base case

-}


mutual
  lemma1a : (φ : For)   Check0 φ   [[ φ ]] []
  lemma1a (const _)  p = p
  lemma1a (x k)      p = p
  lemma1a (φ ∧for ψ) p = lemma∧→ 
                           (Check0 φ) 
                           (Check0 ψ ) 
                           ([[ φ ]] []) 
                           ([[ ψ ]] []) 
                           (lemma1a φ) 
                           (lemma1a ψ) 
                           (lemma∧1 ((check0 φ)) ((check0 ψ)) p)
  lemma1a (φ ∨for ψ) p = lemma∨→ 
                           (Check0 φ) 
                           (Check0 ψ) 
                           ([[ φ ]] [])
                           ([[ ψ ]] []) 
                           (lemma1a φ) 
                           (lemma1a ψ)
                           (lemma∨1 (check0 φ) (check0 ψ) p)
  lemma1a (¬for φ )  p = lemma¬→ 
                          (Check0 φ) 
                          ([[ φ ]] []) 
                          (lemma1b φ) 
                          (lemma¬1 ((check0 φ)) p)

  lemma1b : (φ : For)   [[ φ ]] []  Check0 φ
  lemma1b (const _)  p          = p
  lemma1b (x _)      p          = p
  lemma1b (φ ∧for ψ) (and p q)  = lemma∧2 (check0 φ) (check0 ψ) 
                                          (and (lemma1b φ p) (lemma1b ψ q))
  lemma1b (φ ∨for ψ) (inl p)    = lemma∨2 (check0 φ) (check0 ψ) 
                                          (inl (lemma1b φ p))
  lemma1b (φ ∨for ψ) (inr p)    = lemma∨2 (check0 φ) (check0 ψ) 
                                          (inr (lemma1b ψ p))
  lemma1b (¬for φ)   p          = lemma¬2 (check0 φ) 
                                          (lemma¬→ ([[ φ ]] []) 
                                                   (Check0 φ) 
                                                   (lemma1a φ) p)


{- Step 2 we prove 
   [[ φ ]] bvec  
   ↔ 
   [[ instantiate- φ (head bvec)]]  (tail bvec)

 This implies that 
   forall bvec →  [[ φ ]] bvec  
   ↔ 
   forall bvec →  [[ instantiate- φ tt ]] bvec
             ∧ 
             [[ instantiate- φ ff ]] bvec

  Since check reduces check1 φ (n +1) 
  to check1 (instantiate- φ tt) n bvec 
     ∧bool
    check1 (instantiate- φ ff) n bvec 
  this allows to show the correctness of check1 in the 
  induction step of correctnessCheck1

 
-}
mutual
  lemma2a : (φ : For) 
              {n : } 
             (bvec : Vec 𝔹 (n +1)) 
              [[ φ ]] bvec 
              [[ instantiate- φ (head bvec) ]] (tail bvec)
  lemma2a (const _)     _           p = p
  lemma2a (x 0)         (_ :: _)    p = p
  lemma2a (x (k +1))    (_ :: _)    p = p
  lemma2a (φ ∧for ψ )   bvec        p = lemma∧→ 
                                         ([[ φ ]] bvec) 
                                         ([[ ψ ]] bvec) 
                                         ([[ instantiate- φ (head bvec) ]] (tail bvec)) 
                                         ([[ instantiate- ψ (head bvec) ]] (tail bvec)) 
                                         (lemma2a φ bvec) 
                                         (lemma2a ψ bvec) 
                                         p
  lemma2a (φ ∨for ψ ) bvec p = lemma∨→ 
                                   ([[ φ ]]  bvec) 
                                   ([[ ψ ]] bvec) 
                                   ([[ instantiate- φ (head bvec) ]] (tail bvec)) 
                                   ([[ instantiate- ψ (head bvec) ]] (tail bvec)) 
                                   (lemma2a φ bvec) 
                                   (lemma2a ψ bvec) 
                                   p
  lemma2a (¬for φ) bvec p = lemma¬→ 
                                 ([[ φ ]] bvec) 
                                 ([[ instantiate- φ (head bvec) ]] (tail bvec)) 
                                 (lemma2b φ bvec) 
                                 p


  lemma2b : (φ : For) 
              {n : } 
             (bvec : Vec 𝔹 (n +1)) 
               [[ instantiate- φ (head bvec) ]] (tail bvec)
              [[ φ ]]  bvec 
  lemma2b (const _)     _           p = p
  lemma2b (x 0)         (_ :: _)    p = p
  lemma2b (x (_ +1))    (_ :: _)    p = p
  lemma2b (φ ∧for ψ)    bvec        p = lemma∧→ 
                                        ([[ instantiate- φ (head bvec) ]] 
                                         (tail bvec)) 
                                        ([[ instantiate- ψ (head bvec) ]] 
                                         (tail bvec)) 
                                        ([[ φ ]] bvec) 
                                        ([[ ψ ]] bvec) 
                                        (lemma2b φ bvec) 
                                        (lemma2b ψ bvec) 
                                        p
  lemma2b (φ ∨for ψ) bvec p = lemma∨→ 
                                   ([[ instantiate- φ (head bvec) ]] (tail bvec)) 
                                   ([[ instantiate- ψ (head bvec) ]] (tail bvec)) 
                                   (([[ φ ]] bvec)) 
                                   (([[ ψ ]] bvec)) 
                                   (lemma2b φ bvec) 
                                   (lemma2b ψ bvec) 
                                   p
  lemma2b (¬for φ) bvec p = lemma¬→ 
                                  ([[ instantiate- φ (head bvec) ]] (tail bvec)) 
                                  (([[ φ ]] bvec)) 
                                  (lemma2a φ bvec) 
                                  p



{-   lemma3 shows that [[ φ ]]  bvec and [[ φ ]]' bvec
    are equivalent.
    It is useful since formulas to be proved occur in both forms.

    This lemma is not needed for correctnessCheck1
    but for transfering the result of correctnessCheck1 to [[ φ ]]'
-}




mutual
  lemma3a : (φ : For) 
             {n : } 
             (bvec : Vec 𝔹 n) 
             [[ φ ]]  bvec 
             [[ φ ]]' bvec
  lemma3a (const _)  _    p         = p
  lemma3a (x _)      _    p         = p
  lemma3a (φ ∧for ψ) bvec (and p q) = lemma∧2 
                                          ([[ φ ]]b bvec) 
                                          ([[ ψ ]]b bvec) 
                                          (and (lemma3a φ bvec p) (lemma3a ψ bvec q)) 
  lemma3a (φ ∨for ψ) bvec (inl p)   = lemma∨2 
                                         ([[ φ ]]b bvec) 
                                          ([[ ψ ]]b bvec) 
                                          (inl (lemma3a φ bvec p))
  lemma3a (φ ∨for ψ) bvec (inr q)   = lemma∨2 
                                         ([[ φ ]]b bvec) 
                                         ([[ ψ ]]b bvec)
                                         (inr (lemma3a ψ bvec q))
  lemma3a (¬for φ ) bvec p          = lemma¬2 
                                         ([[ φ ]]b bvec) 
                                         (lemma¬→ ([[ φ ]]  bvec) 
                                                  ([[ φ ]]' bvec) 
                                                  (lemma3b φ bvec) p)

  lemma3b : (φ : For) 
             {n : } 
             (bvec : Vec 𝔹 n) 
             [[ φ ]]' bvec 
             [[ φ ]]  bvec
  lemma3b (const _)   _    p = p
  lemma3b (x _)       _    p = p
  lemma3b (φ  ∧for ψ) bvec p = and 
                                  (lemma3b φ bvec 
                                     (lemma∧proj1 
                                       ([[ φ ]]' bvec) 
                                       ([[ ψ ]]' bvec) 
                                       (lemma∧1 
                                         ([[ φ ]]b bvec) 
                                         ([[ ψ ]]b bvec) 
                                        p))) 
                                  (lemma3b ψ bvec
                                     (lemma∧proj2 
                                        ([[ φ ]]' bvec) 
                                        ([[ ψ ]]' bvec)
                                      (lemma∧1 
                                        ([[ φ ]]b bvec) 
                                        ([[ ψ ]]b bvec) 
                                       p))) 
  lemma3b (φ  ∨for ψ) bvec p = lemma∨→ 
                                   ([[ φ ]]' bvec) 
                                   ([[ ψ ]]' bvec) 
                                   ([[ φ ]]  bvec) 
                                   ([[ ψ ]] bvec) 
                                   (lemma3b φ bvec) 
                                   (lemma3b ψ bvec) 
                                   (lemma∨1 
                                      ([[ φ ]]b bvec) 
                                      ([[ ψ ]]b bvec) 
                                      p)
  lemma3b (¬for φ) bvec p = lemma¬→ 
                                ([[ φ ]]' bvec) 
                                ([[ φ ]]  bvec) 
                                (lemma3a φ bvec) 
                                (lemma¬1 ([[ φ ]]b bvec) p) 



{- The following are auxiliary lemmata used in lemma4a and lemma4b -}
lemmaNthWithDefault1 : {k : } 
                        (bvec : Vec 𝔹 k) 
                        (n m : ) 
                        ((m +1)  n) 
                        Atom (nthWithDefault tt m (truncateWithDefaultTt bvec n))                  
                        Atom (nthWithDefault tt m bvec)
lemmaNthWithDefault1 []          _      _      _  _ = triv
lemmaNthWithDefault1 (_ :: _)    0      0      () _
lemmaNthWithDefault1 (_ :: _)    (_ +1) 0      _  p = p
lemmaNthWithDefault1 (_ :: _)    0      (_ +1) () _
lemmaNthWithDefault1 (_ :: bvec) (n +1) (m +1) mn p = lemmaNthWithDefault1 
                                                        bvec n m mn p

lemmaNthWithDefault2aux : (n m : )  Atom (nthWithDefault tt m (allTt n))
lemmaNthWithDefault2aux 0      _      = triv
lemmaNthWithDefault2aux (_ +1) 0      = triv
lemmaNthWithDefault2aux (n +1) (m +1) = lemmaNthWithDefault2aux n m

lemmaNthWithDefault2 : {k : } 
                        (bvec : Vec 𝔹 k) 
                        (n m : ) 
                        ((m +1)  n) 
                        Atom (nthWithDefault tt m bvec)
                        Atom (nthWithDefault tt m (truncateWithDefaultTt bvec n))                  
lemmaNthWithDefault2 []          n      m      _  _ = lemmaNthWithDefault2aux 
                                                        n m
lemmaNthWithDefault2 (_ :: _)    0      _      _  _ = triv
lemmaNthWithDefault2 (_ :: _)    (_ +1) 0      _  p = p
lemmaNthWithDefault2 (_ :: bvec) (n +1) (m +1) mn p = lemmaNthWithDefault2 
                                                        bvec n m mn p


{- 
We show that the truth of [[ φ ]] depends only on vectors up to 
the length of the number of variables of φ 

-}




mutual
  lemma4a : (φ : For) 
             (n : ) 
             ((maxVar φ)  n) 
             {m : }
             (bvec : Vec 𝔹 m) 
             [[ φ ]] bvec
             [[ φ ]] (truncateWithDefaultTt bvec n)
  lemma4a (const _)  _ _ _    q          = q
  lemma4a (x m)      n p bvec q          = lemmaNthWithDefault2 bvec n m p q
  lemma4a (φ ∧for ψ) n p bvec (and q q') = and 
                                            (lemma4a φ n 
                                              (maxlem1 
                                                 (maxVar φ) 
                                                 (maxVar ψ) 
                                                 n p) 
                                               bvec q) 
                                            (lemma4a ψ n 
                                              (maxlem2 
                                                (maxVar φ) 
                                                (maxVar ψ) 
                                                n p)
                                               bvec q')
  lemma4a (φ ∨for ψ) n p bvec (inl q)     = inl
                                             (lemma4a φ n 
                                               (maxlem1 (maxVar φ) 
                                                        (maxVar ψ) n p)
                                               bvec q)
  lemma4a (φ ∨for ψ) n p bvec (inr q)      = inr
                                              (lemma4a ψ n 
                                                (maxlem2 (maxVar φ) 
                                                    (maxVar ψ) n p)
                                                bvec q)
  lemma4a (¬for φ) n p bvec q = λ p'  q (lemma4b φ n p bvec p')

  lemma4b : (φ : For) 
             (n : ) 
             ((maxVar φ)  n) 
             {m : }
             (bvec : Vec 𝔹 m) 
             [[ φ ]] (truncateWithDefaultTt bvec n)
             [[ φ ]] bvec
  lemma4b (const _)  _ _ _    q          = q
  lemma4b (x k)      n p bvec q          = lemmaNthWithDefault1 bvec n k p q
  lemma4b (φ ∧for ψ) n p bvec (and q q') = and 
                                             (lemma4b φ n 
                                               (maxlem1 (maxVar φ) 
                                                        (maxVar ψ) n p)
                                                bvec q) 
                                             (lemma4b ψ n 
                                               (maxlem2 (maxVar φ) 
                                                        (maxVar ψ) n p)
                                                bvec q')
  lemma4b (φ ∨for ψ) n p bvec (inl q)    = inl
                                           (lemma4b φ n 
                                             (maxlem1 (maxVar φ) 
                                                      (maxVar ψ) n p)
                                           bvec q)
  lemma4b (φ ∨for ψ) n p bvec (inr q)    = inr
                                           (lemma4b ψ n 
                                             (maxlem2 (maxVar φ) 
                                                      (maxVar ψ) n p)
                                            bvec q)
  lemma4b (¬for φ )  n p bvec q          = λ p'  q (lemma4a φ n p bvec p')




{- Now we show 
   Check1 φ n 
   ↔ 
  (bvec : Vec 𝔹 n) →  [[ φ ]]  bvec 

 i.e. check1 is correct
-}




mutual
 correctnessCheck1a : (φ : For) 
                        {n : } 
                        (Check1 φ n )   
                         (bvec : Vec 𝔹 n) 
                         [[ φ ]]  bvec
 correctnessCheck1a φ         p []            = lemma1a φ p
 correctnessCheck1a φ {n +1}  p (tt :: bvec)  = lemma2b φ (tt :: bvec)
                                                  (correctnessCheck1a 
                                                   (instantiate- φ tt) 
                                                   (lemma∧proj1 
                                                    (Check1 (instantiate- φ tt) n)
                                                    (Check1 (instantiate- φ ff) n)
                                                    (lemma∧1 
                                                     (check1 (instantiate- φ tt) n)
                                                      (check1 (instantiate- φ ff) n) 
                                                      p))
                                                   bvec)
                                               
 correctnessCheck1a φ {n +1} p (ff :: bvec) = lemma2b φ (ff :: bvec)
                                                (correctnessCheck1a 
                                                 (instantiate- φ ff) 
                                                 (lemma∧proj2 
                                                  (Check1 (instantiate- φ tt) n)
                                                  (Check1 (instantiate- φ ff) n)
                                                  (lemma∧1 
                                                   (check1 (instantiate- φ tt) n)
                                                   (check1 (instantiate- φ ff) n) 
                                                   p))
                                                bvec)
                                               


 correctnessCheck1b : (φ : For) 
                        {n : } 
                        ((bvec : Vec 𝔹 n)   [[ φ ]]  bvec) 
                       Check1 φ n   
 correctnessCheck1b φ {0}  p = lemma1b φ (p [])
 correctnessCheck1b φ {n +1} p = lemma∧2 
                                  (check1 (instantiate- φ tt) n) 
                                  (check1 (instantiate- φ ff) n) 
                                  (and 
                                   (correctnessCheck1b 
                                     (instantiate- φ tt) 
                                      bvec  lemma2a φ (tt :: bvec) 
                                                         (p (tt :: bvec)))) 
                                   (correctnessCheck1b 
                                     (instantiate- φ ff) 
                                      bvec  lemma2a φ (ff :: bvec) 
                                                         (p (ff :: bvec)))))

correctnessCheck1 : (φ : For) 
                      (n : ) 
                      (Check1 φ n)   ((b : Vec 𝔹 n)   [[ φ ]]  b)
correctnessCheck1 φ n = and (correctnessCheck1a φ) (correctnessCheck1b φ)


correctnessCheck : (φ : For) 
                     Check φ   
                     {n : } 
                    (bvec : Vec 𝔹 n) 
                     [[ φ ]]  bvec
correctnessCheck φ p {n} bvec = lemma4b 
                                 φ 
                                 (maxVar φ) 
                                 refl≦ 
                                 bvec 
                                 (correctnessCheck1a φ 
                                  {maxVar φ} p 
                                  (truncateWithDefaultTt bvec 
                                   (maxVar φ)))


correctnessCheck' : (φ : For) 
                      Check φ   
                      {n : } 
                     (bvec : Vec 𝔹 n) 
                      [[ φ ]]'  bvec
correctnessCheck' φ p bvec = lemma3a φ bvec (correctnessCheck φ p bvec)




{- Example -}


x₀ : For
x₀ = x 0

x₁ : For
x₁ = x 1

example1 : For 
example1 =  ((x₀  ∧for x₁)   ∨for (¬for x₀)) ∨for (¬for x₁)

for1 : 𝔹  𝔹  Set
for1 b b'  = ((Atom b  Atom b')  ¬ (Atom b))  ¬ (Atom b')
            {- equal to [[ example1 ]] (b :: (b' :: [])) -}

for1' : 𝔹  𝔹  Set
for1' b b'  = Atom (((b ∧𝔹 b') ∨𝔹 ¬𝔹 b) ∨𝔹 ¬𝔹 b')
              {- equal to [[ example1 ]]' (b :: (b' :: []))-}

postulate b : 𝔹
postulate b' : 𝔹

for1inst : Set
for1inst = for1 b b' 
{- equal to ((Atom b ∧ Atom b') ∨ (¬ (Atom b)) ∨ (¬ (Atom b')) -}

for1'inst : Set
for1'inst = for1' b b' 
{- equal to Atom (((b ∧𝔹 b') ∨𝔹 ¬𝔹 b) ∨𝔹 ¬𝔹 b') -}


proof : (b b' : 𝔹)   ( (Atom b  Atom b')  (¬ (Atom b)))  (¬ (Atom b') )
proof b b' = correctnessCheck example1 triv (b :: (b' :: []))  

{- as well
   proof : (b b' : 𝔹 → for1 b b' -}


proof' : (b b' : 𝔹)   Atom (((b ∧𝔹 b') ∨𝔹 ¬𝔹 b) ∨𝔹 ¬𝔹 b')
proof' b b' = correctnessCheck' example1 triv (b :: (b' :: []))