module Logic.Propositional.Classical.CNF where
Conjunctive normal formsπ
As a general theme, it is often very useful to have some notion of normal-form for logical and algebraic expressions, and Classical propositional logic is no different! There are multiple possible choices of normal form, but we will be focusing on conjunctive normal form, or CNF for short.
A statement in propositional logic is in conjunctive normal form if it is written as a conjunction of disjunctions of (potentially negated) atoms. As an example, something like is in conjunctive normal form, yet something like is not.
We call the potentially negated atoms in a CNF expression literals, and the disjunctions clauses.
data Literal (Ξ : Nat) : Type where lit : Fin Ξ β Literal Ξ neg : Fin Ξ β Literal Ξ Clause : (Ξ : Nat) β Type Clause Ξ = List (Literal Ξ) CNF : (Ξ : Nat) β Type CNF Ξ = List (Clause Ξ)
litβ neg : β {x y : Fin Ξ} β lit x β‘ neg y β β₯ litβ neg {Ξ = Ξ} p = subst is-lit p tt where is-lit : Literal Ξ β Type is-lit (lit x) = β€ is-lit (neg x) = β₯ lit-var : Literal Ξ β Fin Ξ lit-var (lit x) = x lit-var (neg x) = x lit-val : Literal Ξ β Bool lit-val (lit x) = true lit-val (neg x) = false lit-inj : β {x y : Fin Ξ} β lit x β‘ lit y β x β‘ y lit-inj p = ap lit-var p neg-inj : β {x y : Fin Ξ} β neg x β‘ neg y β x β‘ y neg-inj p = ap lit-var p instance Discrete-Literal : Discrete (Literal Ξ) Discrete-Literal {x = lit x} {lit y} = invmap (ap lit) lit-inj (x β‘? y) Discrete-Literal {x = lit x} {neg y} = no litβ neg Discrete-Literal {x = neg x} {lit y} = no (litβ neg β sym) Discrete-Literal {x = neg x} {neg y} = invmap (ap neg) neg-inj (x β‘? y) avoid-lit : (i : Fin (suc Ξ)) (x : Literal (suc Ξ)) β Β¬ i β‘ lit-var x β Literal Ξ avoid-lit i (lit x) p = lit (avoid i x p) avoid-lit i (neg x) p = neg (avoid i x p)
Semanticsπ
Like their non-normal form brethren, expressions in CNF have a natural semantics in booleans. However, evaluation is particularly easy!
lit-sem : Literal Ξ β (Fin Ξ β Bool) β Bool lit-sem (lit x) Ο = Ο x lit-sem (neg x) Ο = not (Ο x) clause-sem : Clause Ξ β (Fin Ξ β Bool) β Bool clause-sem Ps Ο = any-of (Ξ» a β lit-sem a Ο) Ps cnf-sem : CNF Ξ β (Fin Ξ β Bool) β Bool cnf-sem Ps Ο = all-of (Ξ» d β clause-sem d Ο) Ps instance β¦β§-Literal : β¦β§-notation (Literal Ξ) β¦β§-Literal {Ξ = Ξ} = brackets ((Fin Ξ β Bool) β Bool) lit-sem β¦β§-Clause : β¦β§-notation (Clause Ξ) β¦β§-Clause {Ξ = Ξ} = brackets ((Fin Ξ β Bool) β Bool) clause-sem β¦β§-CNF : β¦β§-notation (CNF Ξ) β¦β§-CNF {Ξ = Ξ} = brackets ((Fin Ξ β Bool) β Bool) cnf-sem
Soundnessπ
We can extend the normal operations on propositions to expressions in CNF.
Atoms are represented by a single clause.
cnf-atom : Fin Ξ β CNF Ξ cnf-atom x = (lit x β· []) β· []
True and false are represented by an expression with no clauses, and an expression with a single empty clause, respectively.
β€cnf : CNF Ξ β€cnf = [] β₯cnf : CNF Ξ β₯cnf = [] β· []
Conjunction can be defined by appending lists.
_β§cnf_ : CNF Ξ β CNF Ξ β CNF Ξ xs β§cnf ys = xs List.++ ys
Disjunction is somewhat tricky, but can be handled by distributing each clause.
cnf-distrib : Clause Ξ β CNF Ξ β CNF Ξ cnf-distrib P Q = map (P List.++_) Q _β¨cnf_ : CNF Ξ β CNF Ξ β CNF Ξ [] β¨cnf Q = [] (P β· Ps) β¨cnf Q = cnf-distrib P Q β§cnf (Ps β¨cnf Q)
Negation is performed by negating all the clauses, and then taking the disjunction of the negated clauses.
Β¬lit : Literal Ξ β Literal Ξ Β¬lit (lit x) = neg x Β¬lit (neg x) = lit x Β¬clause : Clause Ξ β CNF Ξ Β¬clause P = map (Ξ» a β Β¬lit a β· []) P Β¬cnf : CNF Ξ β CNF Ξ Β¬cnf [] = β₯cnf Β¬cnf (P β· Q) = Β¬clause P β¨cnf Β¬cnf Q
All of these operations commute with interpretation in the expected way, but showing this requires a few nightmare inductive arguments over syntax.
cnf-atom-sound : β (x : Fin Ξ) (Ο : Fin Ξ β Bool) β β¦ cnf-atom x β§ Ο β‘ Ο x cnf-atom-sound x Ο = and-truer _ β or-falser _ β₯cnf-sound : β (Ο : Fin Ξ β Bool) β β¦ β₯cnf β§ Ο β‘ false β₯cnf-sound Ο = refl β€cnf-sound : β (Ο : Fin Ξ β Bool) β β¦ β€cnf β§ Ο β‘ true β€cnf-sound Ο = refl β§cnf-sound : β (P Q : CNF Ξ) β (Ο : Fin Ξ β Bool) β β¦ P β§cnf Q β§ Ο β‘ and (β¦ P β§ Ο) (β¦ Q β§ Ο) β§cnf-sound P Q Ο = all-of-++ (any-of (Ξ» a β lit-sem a Ο)) P Q cnf-distrib-sound : (P : Clause Ξ) (Q : CNF Ξ) β (Ο : Fin Ξ β Bool) β β¦ cnf-distrib P Q β§ Ο β‘ or (β¦ P β§ Ο) (β¦ Q β§ Ο) cnf-distrib-sound [] Q Ο = ap (all-of (Ξ» d β clause-sem d Ο)) (map-id Q) cnf-distrib-sound (P β· Ps) Q Ο = all-of (Ξ» d β β¦ d β§ Ο) (map (Ξ» ys β P β· (Ps List.++ ys)) Q) β‘β¨ all-of-map _ _ Q β©β‘ all-of (Ξ» d β β¦ P β· (Ps List.++ d) β§ Ο) Q β‘β¨ ap (Ξ» Ο β all-of Ο Q) (funext Ξ» d β any-of-++ _ (P β· Ps) d) β©β‘ all-of (Ξ» d β or (β¦ P β· Ps β§ Ο) (β¦ d β§ Ο)) Q β‘β¨ all-of-or (Ξ» d β β¦ d β§ Ο) (β¦ P β· Ps β§ Ο) Q β©β‘ or (β¦ P β· Ps β§ Ο) (β¦ Q β§ Ο) β β¨cnf-sound : β (P Q : CNF Ξ) β (Ο : Fin Ξ β Bool) β β¦ P β¨cnf Q β§ Ο β‘ or (β¦ P β§ Ο) (β¦ Q β§ Ο) β¨cnf-sound [] Q Ο = refl β¨cnf-sound (P β· Ps) Q Ο = β¦ (P β· Ps) β¨cnf Q β§ Ο β‘β¨ all-of-++ (Ξ» d β clause-sem d Ο) (cnf-distrib P Q) (Ps β¨cnf Q) β©β‘ and (β¦ cnf-distrib P Q β§ Ο) (β¦ Ps β¨cnf Q β§ Ο) β‘β¨ apβ and (cnf-distrib-sound P Q Ο) (β¨cnf-sound Ps Q Ο) β©β‘ and (or (β¦ P β§ Ο) (β¦ Q β§ Ο)) (or (β¦ Ps β§ Ο) (β¦ Q β§ Ο)) β‘Λβ¨ or-distrib-andr (β¦ P β§ Ο) (β¦ Ps β§ Ο) (β¦ Q β§ Ο) β©β‘Λ or (β¦ P β· Ps β§ Ο) (β¦ Q β§ Ο) β Β¬lit-sound : (a : Literal Ξ) β (Ο : Fin Ξ β Bool) β β¦ Β¬lit a β§ Ο β‘ not (β¦ a β§ Ο) Β¬lit-sound (lit x) Ο = refl Β¬lit-sound (neg x) Ο = sym (not-involutive (Ο x)) Β¬clause-sound : β (P : Clause Ξ) β (Ο : Fin Ξ β Bool) β β¦ Β¬clause P β§ Ο β‘ not (β¦ P β§ Ο) Β¬clause-sound P Ο = all-of (Ξ» d β β¦ d β§ Ο) (map (Ξ» a β Β¬lit a β· []) P) β‘β¨ all-of-map (Ξ» d β β¦ d β§ Ο) (Ξ» a β Β¬lit a β· []) P β©β‘ all-of (Ξ» a β or (β¦ Β¬lit a β§ Ο) false) P β‘β¨ ap (Ξ» Ο β all-of Ο P) (funext Ξ» a β or-falser (β¦ Β¬lit a β§ Ο)) β©β‘ all-of (Ξ» a β β¦ Β¬lit a β§ Ο) P β‘β¨ ap (Ξ» Ο β all-of Ο P) (funext Ξ» a β Β¬lit-sound a Ο) β©β‘ all-of (Ξ» a β not (β¦ a β§ Ο)) P β‘Λβ¨ not-any-of (Ξ» a β β¦ a β§ Ο) P β©β‘Λ not (β¦ P β§ Ο) β Β¬cnf-sound : β (P : CNF Ξ) β (Ο : Fin Ξ β Bool) β β¦ Β¬cnf P β§ Ο β‘ not (β¦ P β§ Ο) Β¬cnf-sound [] Ο = refl Β¬cnf-sound (P β· Ps) Ο = β¦ (Β¬clause P β¨cnf Β¬cnf Ps) β§ Ο β‘β¨ β¨cnf-sound (Β¬clause P) (Β¬cnf Ps) Ο β©β‘ or (β¦ Β¬clause P β§ Ο) (β¦ Β¬cnf Ps β§ Ο) β‘β¨ apβ or (Β¬clause-sound P Ο) (Β¬cnf-sound Ps Ο) β©β‘ or (not (β¦ P β§ Ο)) (not (β¦ Ps β§ Ο)) β‘Λβ¨ not-andβ‘or-not (β¦ P β§ Ο) (β¦ Ps β§ Ο) β©β‘Λ not (β¦ P β· Ps β§ Ο) β
A naive algorithmπ
Armed with these operations on CNFs, we can give a translation from propositions into CNF. However, note that this is extremely naive, and will result in huge clause sizes! This is due to the fact that disjunction and negation distribute clauses, which will result in potentially exponential blow-ups in expression sizes.
cnf : Proposition Ξ β CNF Ξ cnf (atom x) = cnf-atom x cnf ββ€β = β€cnf cnf ββ₯β = β₯cnf cnf (P ββ§β Q) = cnf P β§cnf cnf Q cnf (P ββ¨β Q) = cnf P β¨cnf cnf Q cnf (βΒ¬β P) = Β¬cnf (cnf P) cnf-sound : β (P : Proposition Ξ) (Ο : Fin Ξ β Bool) β β¦ cnf P β§ Ο β‘ β¦ P β§ Ο cnf-sound (atom x) Ο = and-truer (or (Ο x) false) β or-falser (Ο x) cnf-sound ββ€β Ο = refl cnf-sound ββ₯β Ο = refl cnf-sound (P ββ§β Q) Ο = β¦ cnf P β§cnf cnf Q β§ Ο β‘β¨ β§cnf-sound (cnf P) (cnf Q) Ο β©β‘ and (β¦ cnf P β§ Ο) (β¦ cnf Q β§ Ο) β‘β¨ apβ and (cnf-sound P Ο) (cnf-sound Q Ο) β©β‘ and (β¦ P β§ Ο) (β¦ Q β§ Ο) β cnf-sound (P ββ¨β Q) Ο = β¦ cnf P β¨cnf cnf Q β§ Ο β‘β¨ β¨cnf-sound (cnf P) (cnf Q) Ο β©β‘ or (β¦ cnf P β§ Ο) (β¦ cnf Q β§ Ο) β‘β¨ apβ or (cnf-sound P Ο) (cnf-sound Q Ο) β©β‘ or (β¦ P β§ Ο) (β¦ Q β§ Ο) β cnf-sound (βΒ¬β P) Ο = β¦ Β¬cnf (cnf P) β§ Ο β‘β¨ Β¬cnf-sound (cnf P) Ο β©β‘ not (β¦ cnf P β§ Ο) β‘β¨ ap not (cnf-sound P Ο) β©β‘ not (β¦ P β§ Ο) β
Quotationπ
We can also read expressions in CNF back into propositions. Luckily, there are no exponential blow-ups here!
quote-lit : Literal Ξ β Proposition Ξ quote-lit (lit x) = atom x quote-lit (neg x) = βΒ¬β (atom x) quote-clause : Clause Ξ β Proposition Ξ quote-clause [] = ββ₯β quote-clause (x β· Ο) = quote-lit x ββ¨β quote-clause Ο quote-cnf : CNF Ξ β Proposition Ξ quote-cnf [] = ββ€β quote-cnf (Ο β· Οs) = quote-clause Ο ββ§β quote-cnf Οs quote-lit-sound : β (x : Literal Ξ) β (Ο : Fin Ξ β Bool) β β¦ x β§ Ο β‘ β¦ quote-lit x β§ Ο quote-lit-sound (lit x) Ο = refl quote-lit-sound (neg x) Ο = refl quote-clause-sound : β (Ο : Clause Ξ) β (Ο : Fin Ξ β Bool) β β¦ Ο β§ Ο β‘ β¦ quote-clause Ο β§ Ο quote-clause-sound [] Ο = refl quote-clause-sound (x β· Ο) Ο = apβ or (quote-lit-sound x Ο) (quote-clause-sound Ο Ο) quote-cnf-sound : β (Ο : CNF Ξ) β (Ο : Fin Ξ β Bool) β β¦ Ο β§ Ο β‘ β¦ quote-cnf Ο β§ Ο quote-cnf-sound [] Ο = refl quote-cnf-sound (Ο β· Οs) Ο = apβ and (quote-clause-sound Ο Ο) (quote-cnf-sound Οs Ο)
literal-eq-negate : β (x y : Literal Ξ) β Β¬ x β‘ y β lit-var x β‘ lit-var y β x β‘ Β¬lit y literal-eq-negate (lit x) (lit y) xβ y p = absurd (xβ y (ap lit p)) literal-eq-negate (lit x) (neg y) xβ y p = ap lit p literal-eq-negate (neg x) (lit y) xβ y p = ap neg p literal-eq-negate (neg x) (neg y) xβ y p = absurd (xβ y (ap neg p)) literal-sat-val : β (x : Literal Ξ) β (Ο : Fin Ξ β Bool) β β¦ x β§ Ο β‘ true β Ο (lit-var x) β‘ lit-val x literal-sat-val (lit x) Ο x-true = x-true literal-sat-val (neg x) Ο x-true = not-inj x-true