Skip to content

Instantly share code, notes, and snippets.

@TOTBWF
Created January 28, 2023 22:44
Show Gist options
  • Save TOTBWF/ebcd73d1cd1f78e147f4ed3bbcace788 to your computer and use it in GitHub Desktop.
Save TOTBWF/ebcd73d1cd1f78e147f4ed3bbcace788 to your computer and use it in GitHub Desktop.
CNF for classic propositional logic
open import 1Lab.Prelude

open import Data.Bool
open import Data.Fin
open import Data.List
open import Data.Nat

module Data.Bool.CNF where

CNF For Booleans

private variable
   n : Nat

data Expr (n : Nat) : Type where
  evar   : Fin n  Expr n
  etrue  : Expr n
  efalse : Expr n
  enot   : Expr n  Expr n
  eand   : Expr n  Expr n  Expr n
  eor    : Expr n  Expr n  Expr n

⟦_⟧ᵉ : Expr n  (Fin n  Bool)  Bool
⟦ evar x ⟧ᵉ ρ = ρ x
⟦ etrue ⟧ᵉ ρ = true
⟦ efalse ⟧ᵉ ρ = false
⟦ enot e ⟧ᵉ ρ = not (⟦ e ⟧ᵉ ρ)
⟦ eand e1 e2 ⟧ᵉ ρ = and (⟦ e1 ⟧ᵉ ρ) (⟦ e2 ⟧ᵉ ρ)
⟦ eor e1 e2 ⟧ᵉ ρ = or (⟦ e1 ⟧ᵉ ρ) (⟦ e2 ⟧ᵉ ρ)

data Atom (n : Nat) : Type where
  avar    : Fin n  Atom n
  anegvar : Fin n  Atom n

Clause : Nat  Type
Clause n = List (Atom n)

CNF : Nat  Type
CNF n = List (Clause n)


⟦_⟧ᵃ : Atom n  (Fin n  Bool)  Bool
⟦ avar x ⟧ᵃ ρ = ρ x
⟦ anegvar x ⟧ᵃ ρ = not (ρ x)

⟦_⟧ᶜ : Clause n  (Fin n  Bool)  Bool
⟦ [] ⟧ᶜ ρ = false
⟦ a ∷ as ⟧ᶜ ρ = or (⟦ a ⟧ᵃ ρ) (⟦ as ⟧ᶜ ρ)

⟦_⟧ⁿ : CNF n  (Fin n  Bool)  Bool
⟦ [] ⟧ⁿ ρ = true
⟦ c ∷ cs ⟧ⁿ ρ = and (⟦ c ⟧ᶜ ρ) (⟦ cs ⟧ⁿ ρ)

atom-not : Atom n  Atom n
atom-not (avar x) = anegvar x
atom-not (anegvar x) = avar x

clause-or : Clause n  Clause n  Clause n
clause-or as bs = as ++ bs

clause-not : Clause n  CNF n
clause-not [] = []
clause-not (a ∷ as) = (atom-not a ∷ []) ∷ clause-not as

cnf-var : Fin n  CNF n
cnf-var n = (avar n ∷ []) ∷ []

cnf-true : CNF n
cnf-true = []

cnf-false : CNF n
cnf-false = [] ∷ []

cnf-and : CNF n  CNF n  CNF n
cnf-and as bs = as ++ bs

cnf-or : CNF n  CNF n  CNF n
cnf-or [] bs = cnf-true
cnf-or (a ∷ as) bs = cnf-and (map (clause-or a) bs) (cnf-or as bs)

cnf-not : CNF n  CNF n
cnf-not [] = cnf-false
cnf-not (a ∷ as) = cnf-or (clause-not a) (cnf-not as) 

eval : Expr n  CNF n
eval (evar x) = cnf-var x
eval etrue = cnf-true
eval efalse = cnf-false
eval (enot e) = cnf-not (eval e)
eval (eand e1 e2) = cnf-and (eval e1) (eval e2)
eval (eor e1 e2) = cnf-or (eval e1) (eval e2)

reflect-atom : Atom n  Expr n
reflect-atom (avar x) = evar x
reflect-atom (anegvar x) = enot (evar x)

reflect-clause : Clause n  Expr n
reflect-clause = foldr (λ a  eor (reflect-atom a)) efalse

reflect : CNF n  Expr n
reflect = foldr (λ c  eand (reflect-clause c)) etrue

nf : Expr n  Expr n
nf e = reflect (eval e)

Soundness of evaluation

atom-not-sound :  (a : Atom n) : Fin n  Bool)
                ⟦ atom-not a ⟧ᵃ ρ ≡ not (⟦ a ⟧ᵃ ρ)
atom-not-sound (avar x) ρ = refl
atom-not-sound (anegvar x) ρ = sym $ not-involutive (ρ x)

clause-or-sound :  (as bs : Clause n) : Fin n  Bool)
             ⟦ clause-or as bs ⟧ᶜ ρ ≡ or (⟦ as ⟧ᶜ ρ) (⟦ bs ⟧ᶜ ρ)
clause-or-sound [] bs ρ = refl
clause-or-sound (a ∷ as) bs ρ =
  or (⟦ a ⟧ᵃ ρ) (⟦ as ++ bs ⟧ᶜ ρ)            ≡⟨ ap (or (⟦ a ⟧ᵃ ρ)) (clause-or-sound as bs ρ) ⟩
  or (⟦ a ⟧ᵃ ρ) (or (⟦ as ⟧ᶜ ρ) (⟦ bs ⟧ᶜ ρ)) ≡⟨ or-associative (⟦ a ⟧ᵃ ρ) (⟦ as ⟧ᶜ ρ) (⟦ bs ⟧ᶜ ρ) ⟩
  or (or (⟦ a ⟧ᵃ ρ) (⟦ as ⟧ᶜ ρ)) (⟦ bs ⟧ᶜ ρ) ∎

cnf-and-sound :  (as bs : CNF n) : Fin n  Bool)
            ⟦ cnf-and as bs ⟧ⁿ ρ ≡ and (⟦ as ⟧ⁿ ρ) (⟦ bs ⟧ⁿ ρ)
cnf-and-sound [] bs ρ = refl
cnf-and-sound (b ∷ as) bs ρ =
  and (⟦ b ⟧ᶜ ρ) (⟦ as ++ bs ⟧ⁿ ρ)             ≡⟨ ap (and (⟦ b ⟧ᶜ ρ)) (cnf-and-sound as bs ρ) ⟩
  and (⟦ b ⟧ᶜ ρ) (and (⟦ as ⟧ⁿ ρ) (⟦ bs ⟧ⁿ ρ)) ≡⟨ and-associative (⟦ b ⟧ᶜ ρ) (⟦ as ⟧ⁿ ρ) (⟦ bs ⟧ⁿ ρ) ⟩
  and (and (⟦ b ⟧ᶜ ρ) (⟦ as ⟧ⁿ ρ)) (⟦ bs ⟧ⁿ ρ) ∎

map-clause-or-sound :  (a : Clause n) (bs : CNF n) : Fin n  Bool)
               ⟦ map (clause-or a) bs ⟧ⁿ ρ ≡ or (⟦ a ⟧ᶜ ρ) (⟦ bs ⟧ⁿ ρ)
map-clause-or-sound a [] ρ = sym $ or-truer _
map-clause-or-sound a (b ∷ bs) ρ =
  and (⟦ clause-or a b ⟧ᶜ ρ) (⟦ map (clause-or a) bs ⟧ⁿ ρ)                                  ≡⟨ ap (and (⟦ clause-or a b ⟧ᶜ ρ)) (map-clause-or-sound a bs ρ) ⟩
  and (⟦ clause-or a b ⟧ᶜ ρ) (or (⟦ a ⟧ᶜ ρ) (⟦ bs ⟧ⁿ ρ))                                    ≡⟨ and-distrib-orl (⟦ clause-or a b ⟧ᶜ ρ) (⟦ a ⟧ᶜ ρ) (⟦ bs ⟧ⁿ ρ) ⟩
  or (and ⌜ ⟦ clause-or a b ⟧ᶜ ρ ⌝ (⟦ a ⟧ᶜ ρ)) (and (⟦ clause-or a b ⟧ᶜ ρ) (⟦ bs ⟧ⁿ ρ))     ≡⟨ ap! (clause-or-sound a b ρ) ⟩
  or ⌜ and (or (⟦ a ⟧ᶜ ρ) (⟦ b ⟧ᶜ ρ)) (⟦ a ⟧ᶜ ρ) ⌝ (and (⟦ clause-or a b ⟧ᶜ ρ) (⟦ bs ⟧ⁿ ρ)) ≡⟨ ap! (and-commutative (or (⟦ a ⟧ᶜ ρ) (⟦ b ⟧ᶜ ρ)) (⟦ a ⟧ᶜ ρ) ∙ and-absorbs-orr (⟦ a ⟧ᶜ ρ) (⟦ b ⟧ᶜ ρ)) ⟩
  or (⟦ a ⟧ᶜ ρ) (and ⌜ ⟦ clause-or a b ⟧ᶜ ρ ⌝ (⟦ bs ⟧ⁿ ρ))                                  ≡⟨ ap! (clause-or-sound a b ρ) ⟩
  or (⟦ a ⟧ᶜ ρ) ⌜ and (or (⟦ a ⟧ᶜ ρ) (⟦ b ⟧ᶜ ρ)) (⟦ bs ⟧ⁿ ρ) ⌝                              ≡⟨ ap! (and-distrib-orr (⟦ a ⟧ᶜ ρ) (⟦ b ⟧ᶜ ρ) (⟦ bs ⟧ⁿ ρ)) ⟩
  or (⟦ a ⟧ᶜ ρ) (or (and (⟦ a ⟧ᶜ ρ) (⟦ bs ⟧ⁿ ρ)) (and (⟦ b ⟧ᶜ ρ) (⟦ bs ⟧ⁿ ρ)))              ≡⟨ or-associative (⟦ a ⟧ᶜ ρ) (and (⟦ a ⟧ᶜ ρ) (⟦ bs ⟧ⁿ ρ)) (and (⟦ b ⟧ᶜ ρ) (⟦ bs ⟧ⁿ ρ)) ⟩
  or ⌜ or (⟦ a ⟧ᶜ ρ) (and (⟦ a ⟧ᶜ ρ) (⟦ bs ⟧ⁿ ρ)) ⌝ (and (⟦ b ⟧ᶜ ρ) (⟦ bs ⟧ⁿ ρ))            ≡⟨ ap! (or-absorbs-andr (⟦ a ⟧ᶜ ρ) (⟦ bs ⟧ⁿ ρ)) ⟩
  or (⟦ a ⟧ᶜ ρ) (and (⟦ b ⟧ᶜ ρ) (⟦ bs ⟧ⁿ ρ))                                                ∎

cnf-or-sound :  (as bs : CNF n) : Fin n  Bool)
             ⟦ cnf-or as bs ⟧ⁿ ρ ≡ or (⟦ as ⟧ⁿ ρ) (⟦ bs ⟧ⁿ ρ)
cnf-or-sound [] bs ρ = refl
cnf-or-sound (a ∷ as) bs ρ =
  ⟦ cnf-and (map (clause-or a) bs) (cnf-or as bs) ⟧ⁿ ρ         ≡⟨ cnf-and-sound (map (clause-or a) bs) (cnf-or as bs) ρ ⟩
  and ⌜ ⟦ map (clause-or a) bs ⟧ⁿ ρ ⌝ (⟦ cnf-or as bs ⟧ⁿ ρ)    ≡⟨ ap! (map-clause-or-sound a bs ρ) ⟩
  and (or (⟦ a ⟧ᶜ ρ) (⟦ bs ⟧ⁿ ρ)) ⌜ ⟦ cnf-or as bs ⟧ⁿ ρ ⌝      ≡⟨ ap! (cnf-or-sound as bs ρ) ⟩
  and (or (⟦ a ⟧ᶜ ρ) (⟦ bs ⟧ⁿ ρ)) (or (⟦ as ⟧ⁿ ρ) (⟦ bs ⟧ⁿ ρ)) ≡˘⟨ or-distrib-andr (⟦ a ⟧ᶜ ρ) (⟦ as ⟧ⁿ ρ) (⟦ bs ⟧ⁿ ρ) ⟩
  or (⟦ a ∷ as ⟧ⁿ ρ) (⟦ bs ⟧ⁿ ρ) ∎

clause-not-sound :  (as : Clause n) : Fin n  Bool)
                  ⟦ clause-not as ⟧ⁿ ρ ≡ not (⟦ as ⟧ᶜ ρ)
clause-not-sound [] ρ = refl
clause-not-sound (a ∷ as) ρ =
  and (or (⟦ atom-not a ⟧ᵃ ρ) false) (⟦ clause-not as ⟧ⁿ ρ) ≡⟨ ap (λ ϕ  and ϕ (⟦ clause-not as ⟧ⁿ ρ)) (or-falser (⟦ atom-not a ⟧ᵃ ρ)) ⟩
  and (⟦ atom-not a ⟧ᵃ ρ) (⟦ clause-not as ⟧ⁿ ρ)            ≡⟨ ap₂ and (atom-not-sound a ρ) (clause-not-sound as ρ) ⟩
  and (not (⟦ a ⟧ᵃ ρ)) (not (⟦ as ⟧ᶜ ρ))                    ≡˘⟨ not-or≡and-not (⟦ a ⟧ᵃ ρ) (⟦ as ⟧ᶜ ρ) ⟩
  not (⟦ a ∷ as ⟧ᶜ ρ) ∎

cnf-not-sound :  (as : CNF n) : Fin n  Bool)
               ⟦ cnf-not as ⟧ⁿ ρ ≡ not (⟦ as ⟧ⁿ ρ)
cnf-not-sound [] ρ = refl
cnf-not-sound (a ∷ as) ρ =
  ⟦ cnf-or (clause-not a) (cnf-not as) ⟧ⁿ ρ      ≡⟨ cnf-or-sound (clause-not a) (cnf-not as) ρ ⟩
  or ⌜ ⟦ clause-not a ⟧ⁿ ρ ⌝ (⟦ cnf-not as ⟧ⁿ ρ) ≡⟨ ap₂ or (clause-not-sound a ρ) (cnf-not-sound as ρ) ⟩
  or (not (⟦ a ⟧ᶜ ρ)) (not (⟦ as ⟧ⁿ ρ))          ≡˘⟨ not-and≡or-not (⟦ a ⟧ᶜ ρ) (⟦ as ⟧ⁿ ρ) ⟩
  not (and (⟦ a ⟧ᶜ ρ) (⟦ as ⟧ⁿ ρ))               ∎

cnf-var-sound :  (x : Fin n) : Fin n  Bool)
               ⟦ cnf-var x ⟧ⁿ ρ ≡ ρ x
cnf-var-sound x ρ =
  and (or (ρ x) false) true ≡⟨ and-truer (or (ρ x) false) ⟩
  or (ρ x) false            ≡⟨ or-falser (ρ x) ⟩
  ρ x                       ∎

eval-sound :  (e : Expr n) : Fin n  Bool)
            ⟦ eval e ⟧ⁿ ρ ≡ ⟦ e ⟧ᵉ ρ
eval-sound (evar x) ρ = cnf-var-sound x ρ
eval-sound etrue ρ = refl
eval-sound efalse ρ = refl
eval-sound (enot e) ρ =
  ⟦ cnf-not (eval e) ⟧ⁿ ρ ≡⟨ cnf-not-sound (eval e) ρ ⟩
  not (⟦ eval e ⟧ⁿ ρ)     ≡⟨ ap not (eval-sound e ρ) ⟩
  not (⟦ e ⟧ᵉ ρ) ∎
eval-sound (eand e1 e2) ρ =
  ⟦ cnf-and (eval e1) (eval e2) ⟧ⁿ ρ    ≡⟨ cnf-and-sound (eval e1) (eval e2) ρ ⟩
  and (⟦ eval e1 ⟧ⁿ ρ) (⟦ eval e2 ⟧ⁿ ρ) ≡⟨ ap₂ and (eval-sound e1 ρ) (eval-sound e2 ρ) ⟩
  and (⟦ e1 ⟧ᵉ ρ) (⟦ e2 ⟧ᵉ ρ) ∎
eval-sound (eor e1 e2) ρ =
  ⟦ cnf-or (eval e1) (eval e2) ⟧ⁿ ρ    ≡⟨ cnf-or-sound (eval e1) (eval e2) ρ ⟩
  or (⟦ eval e1 ⟧ⁿ ρ) (⟦ eval e2 ⟧ⁿ ρ) ≡⟨ ap₂ or (eval-sound e1 ρ) (eval-sound e2 ρ) ⟩
  or (⟦ e1 ⟧ᵉ ρ) (⟦ e2 ⟧ᵉ ρ) ∎

Soundness of reflection

reflect-atom-sound :  (a : Atom n) : Fin n  Bool)
                    ⟦ reflect-atom a ⟧ᵉ ρ ≡ ⟦ a ⟧ᵃ ρ
reflect-atom-sound (avar x) ρ = refl
reflect-atom-sound (anegvar x) ρ = refl

reflect-clause-sound :  (as : Clause n) : Fin n  Bool)
                      ⟦ reflect-clause as ⟧ᵉ ρ ≡ ⟦ as ⟧ᶜ ρ
reflect-clause-sound [] ρ = refl
reflect-clause-sound (a ∷ as) ρ =
  ap₂ or (reflect-atom-sound a ρ) (reflect-clause-sound as ρ)

reflect-sound :  (cs : CNF n) : Fin n  Bool)
               ⟦ reflect cs ⟧ᵉ ρ ≡ ⟦ cs ⟧ⁿ ρ
reflect-sound [] ρ = refl
reflect-sound (c ∷ cs) ρ =
  ap₂ and (reflect-clause-sound c ρ) (reflect-sound cs ρ)

Soundness of evaluation

nf-sound :  (e : Expr n) : Fin n  Bool)
          ⟦ nf e ⟧ᵉ ρ ≡ ⟦ e ⟧ᵉ ρ
nf-sound e ρ = reflect-sound (eval e) ρ ∙ eval-sound e ρ
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment