Theory Tseytin
subsubsection‹Tseytin transformation›
theory Tseytin
imports Formulas CNF_Formulas
begin
text‹The @{const cnf} transformation clearly has exponential complexity.
If the intention is to use Resolution to decide validity of a formula,
that is clearly a deal-breaker for any practical implementation,
since validity can be decided by brute force in exponential time.
This theory pair shows the Tseytin transformation, a way to transform a formula
while preserving validity.
The @{const cnf} of the transformed formula will have clauses with maximally 3 atoms,
and an amount of clauses linear in the size of the formula,
at the cost of introducing one new atom for each subformula of ‹F› (i.e. @{term "size F"} many).
›
definition "pair_fun_upd f p ≡ (case p of (k,v) ⇒ fun_upd f k v)"
lemma fold_pair_upd_triv: "A ∉ fst ` set U ⟹ foldl pair_fun_upd F U A = F A"
by(induction U arbitrary: F; simp)
(metis fun_upd_apply pair_fun_upd_def prod.simps(2) surjective_pairing)
lemma distinct_pair_update_one: "(k,v) ∈ set U ⟹ distinct (map fst U) ⟹ foldl pair_fun_upd F U k = v"
by(induction U arbitrary: F; clarsimp simp add: pair_fun_upd_def fold_pair_upd_triv split: prod.splits)
(insert fold_pair_upd_triv, fastforce)
lemma distinct_zipunzip: "distinct xs ⟹ distinct (map fst (zip xs ys))" by (simp add: distinct_conv_nth)
lemma foldl_pair_fun_upd_map_of: "distinct (map fst U) ⟹ foldl pair_fun_upd F U = (λk. case map_of U k of Some v ⇒ v | None ⇒ F k)"
by(unfold fun_eq_iff; induction U arbitrary: F; clarsimp split: option.splits simp: pair_fun_upd_def rev_image_eqI)
lemma map_of_map_apsnd: "map_of (map (apsnd t) M) = map_option t ∘ (map_of M)"
by(unfold fun_eq_iff comp_def; induction M; simp)
definition biimp (infix ‹❙↔› 67) where "F ❙↔ G ≡ (F ❙→ G) ❙∧ (G ❙→ F)"
lemma atoms_biimp[simp]: "atoms (F ❙↔ G) = atoms F ∪ atoms G"
unfolding biimp_def by auto
lemma biimp_size[simp]: "size (F ❙↔ G) = (2 * (size F + size G)) + 3"
by(simp add: biimp_def)
locale freshstuff =
fixes fresh :: "'a set ⇒ 'a"
assumes isfresh: "finite S ⟹ fresh S ∉ S"
begin
primrec nfresh where
"nfresh S 0 = []" |
"nfresh S (Suc n) = (let f = fresh S in f # nfresh (f ▹ S) n)"
lemma length_nfresh: "length (nfresh S n) = n"
by(induction n arbitrary: S; simp add: Let_def)
lemma nfresh_isfresh: "finite S ⟹ set (nfresh S n) ∩ S = {}"
by(induction n arbitrary: S; auto simp add: Let_def isfresh)
lemma nfresh_distinct: "finite S ⟹ distinct (nfresh S n)"
by(induction n arbitrary: S; simp add: Let_def; meson disjoint_iff_not_equal finite_insert insertI1 nfresh_isfresh)
definition "tseytin_assmt F ≡ let SF = remdups (subformulae F) in zip (nfresh (atoms F) (length SF)) SF"
lemma tseytin_assmt_distinct: "distinct (map fst (tseytin_assmt F))"
unfolding tseytin_assmt_def using nfresh_distinct by (simp add: Let_def length_nfresh)
lemma tseytin_assmt_has: "G ∈ set (subformulae F) ⟹ ∃n. (n,G) ∈ set (tseytin_assmt F)"
proof -
assume "G ∈ set (subformulae F)"
then have "∃n. G = subformulae F ! n ∧ n < length (subformulae F)"
by (simp add: set_conv_nth)
then have "∃a. (a, G) ∈ set (zip (nfresh (atoms F) (length (subformulae F))) (subformulae F))"
by (metis (no_types) in_set_zip length_nfresh prod.sel(1) prod.sel(2))
thus ?thesis by(simp add: tseytin_assmt_def Let_def) (metis fst_conv in_set_conv_nth in_set_zip length_nfresh set_remdups snd_conv)
qed
lemma tseytin_assmt_new_atoms: "(k,l) ∈ set (tseytin_assmt F) ⟹ k ∉ atoms F"
unfolding tseytin_assmt_def Let_def using nfresh_isfresh by (fastforce dest: set_zip_leftD)
primrec tseytin_tran1 where
"tseytin_tran1 S (Atom k) = [Atom k ❙↔ S (Atom k)]" |
"tseytin_tran1 S ⊥ = [⊥ ❙↔ S ⊥]" |
"tseytin_tran1 S (Not F) = [S (Not F) ❙↔ Not (S F)] @ tseytin_tran1 S F" |
"tseytin_tran1 S (And F G) = [S (And F G) ❙↔ And (S F) (S G)] @ tseytin_tran1 S F @ tseytin_tran1 S G" |
"tseytin_tran1 S (Or F G) = [S (Or F G) ❙↔ Or (S F) (S G)] @ tseytin_tran1 S F @ tseytin_tran1 S G" |
"tseytin_tran1 S (Imp F G) = [S (Imp F G) ❙↔ Imp (S F) (S G)] @ tseytin_tran1 S F @ tseytin_tran1 S G"
definition "tseytin_toatom F ≡ Atom ∘ the ∘ map_of (map (λ(a,b). (b,a)) (tseytin_assmt F))"
definition "tseytin_tran F ≡ ❙⋀(let S = tseytin_toatom F in S F # tseytin_tran1 S F)"
lemma distinct_snd_tseytin_assmt: "distinct (map snd (tseytin_assmt F))"
unfolding tseytin_assmt_def by(simp add: Let_def length_nfresh)
lemma tseytin_assmt_backlookup: assumes "J ∈ set (subformulae F)"
shows "(the (map_of (map (λ(a, b). (b, a)) (tseytin_assmt F)) J), J) ∈ set (tseytin_assmt F)"
proof -
have 1: "distinct (map snd M) ⟹ J ∈ snd ` set M ⟹ (the (map_of (map (λ(a, b). (b, a)) M) J), J) ∈ set M" for J M
by(induction M; clarsimp split: prod.splits)
have 2: "J ∈ set (subformulae F) ⟹ J ∈ snd ` set (tseytin_assmt F)" for J using image_iff tseytin_assmt_has by fastforce
from 1[OF distinct_snd_tseytin_assmt 2, OF assms] show ?thesis .
qed
lemma tseytin_tran_small_clauses: "∀C ∈ cnf (nnf (tseytin_tran F)). card C ≤ 3"
proof -
have 3: "card S ≤ 2 ⟹ card (a ▹ S) ≤ 3" for a S
by(cases "finite S"; simp add: card_insert_le_m1)
have 2: "card S ≤ 1 ⟹ card (a ▹ S) ≤ 2" for a S
by(cases "finite S"; simp add: card_insert_le_m1)
have 1: "card S ≤ 0 ⟹ card (a ▹ S) ≤ 1" for a S
by(cases "finite S"; simp add: card_insert_le_m1)
have *: "⟦G ∈ set (tseytin_tran1 (Atom ∘ S) F); C ∈ cnf (nnf G)⟧ ⟹ card C ≤ 3" for G C S
by(induction F arbitrary: G; simp add: biimp_def; (elim disjE exE conjE | intro 1 2 3 | simp)+)
show ?thesis
unfolding tseytin_tran_def tseytin_toatom_def Let_def
by(clarsimp simp add: cnf_BigAnd nnf_BigAnd comp_assoc *)
qed
lemma tseytin_tran_few_clauses: "card (cnf (nnf (tseytin_tran F))) ≤ 3 * size F + 1"
proof -
have "size Bot = 1" by simp
have ws: "{c ▹ D |D. D = {c1} ∨ D = {c2}} = {{c,c1},{c,c2}}" for c1 c2 c by auto
have grr: "Suc (card S) ≤ c ⟹ card (a ▹ S) ≤ c" for a S c
by(cases "finite S"; simp add: card_insert_le_m1)
have *: "card (⋃a∈set (tseytin_tran1 (Atom ∘ S) F). cnf (nnf a)) ≤ 3 * size F" for S
by(induction F; simp add: biimp_def; ((intro grr card_Un_le[THEN le_trans] | simp add: ws)+)?)
show ?thesis
unfolding tseytin_tran_def tseytin_toatom_def Let_def
by(clarsimp simp: nnf_BigAnd cnf_BigAnd; intro grr; simp add: comp_assoc *)
qed
lemma tseytin_tran_new_atom_count: "card (atoms (tseytin_tran F)) ≤ size F + card (atoms F)"
proof -
have tseytin_tran1_atoms: "H ∈ set (tseytin_tran1 (tseytin_toatom F) G) ⟹ G ∈ set (subformulae F) ⟹
atoms H ⊆ atoms F ∪ (⋃I ∈ set (subformulae F). atoms (tseytin_toatom F I))" for G H
proof(induction G arbitrary: H)
case (Atom k)
hence "k ∈ atoms F"
by simp (meson formula.set_intros(1) rev_subsetD subformula_atoms)
with Atom show ?case by simp blast
next
case Bot then show ?case by simp blast
next
case (Not G)
show ?case by(insert Not.prems(1,2);
frule subformulas_in_subformulas; simp; elim disjE; (elim Not.IH | force))
next
case (And G1 G2)
show ?case by(insert And.prems(1,2);
frule subformulas_in_subformulas; simp; elim disjE; (elim And.IH; simp | force))
next
case (Or G1 G2)
show ?case by(insert Or.prems(1,2);
frule subformulas_in_subformulas; simp; elim disjE; (elim Or.IH; simp | force))
next
case (Imp G1 G2)
show ?case by(insert Imp.prems(1,2);
frule subformulas_in_subformulas; simp; elim disjE; (elim Imp.IH; simp | force))
qed
have tseytin_tran1_atoms: "(⋃G∈set (tseytin_tran1 (tseytin_toatom F) F). atoms G) ⊆
atoms F ∪ (⋃I∈set (subformulae F). atoms (tseytin_toatom F I))"
using tseytin_tran1_atoms[OF _ subformulae_self] by blast
have 1: "card (atoms (tseytin_tran F)) ≤
card (atoms (tseytin_toatom F F) ∪ (⋃x∈set (tseytin_tran1 (tseytin_toatom F) F). atoms x))"
unfolding tseytin_tran_def by(simp add: Let_def tseytin_tran1_atoms)
have 2: "atoms (tseytin_toatom F F) ∪ (⋃x∈set (tseytin_tran1 (tseytin_toatom F) F). atoms x) ⊆
(atoms F ∪ (⋃I∈set (subformulae F). atoms (tseytin_toatom F I)))"
using tseytin_tran1_atoms by blast
have twofin: "finite (atoms F ∪ (⋃I∈set (subformulae F). atoms (tseytin_toatom F I)))" by simp
have card_subformulae: "card (set (subformulae F)) ≤ size F" using length_subformulae by (metis card_length)
have card_singleton_union: "finite S ⟹ card (⋃x∈S. {f x}) ≤ card S" for f S
by(induction S rule: finite_induct; simp add: card_insert_if)
have 3: "card (⋃I∈set (subformulae F). atoms (tseytin_toatom F I)) ≤ size F"
unfolding tseytin_toatom_def using le_trans[OF card_singleton_union card_subformulae]
by simp fast
have 4: "card (atoms (tseytin_tran F)) ≤ card (atoms F) + card (⋃f∈set (subformulae F). atoms (tseytin_toatom F f))"
using le_trans[OF 1 card_mono[OF twofin 2]] card_Un_le le_trans by blast
show ?thesis using 3 4 by linarith
qed
end
definition "freshnat S ≡ Suc (Max (0 ▹ S))"
primrec nfresh_natcode where
"nfresh_natcode S 0 = []" |
"nfresh_natcode S (Suc n) = (let f = freshnat S in f # nfresh_natcode (f ▹ S) n)"
interpretation freshnats: freshstuff freshnat unfolding freshnat_def by standard (meson Max_ge Suc_n_not_le_n finite_insert insertCI)
lemma [code_unfold]: "freshnats.nfresh = nfresh_natcode"
proof -
have "freshnats.nfresh S n = nfresh_natcode S n" for S n by(induction n arbitrary: S; simp)
thus ?thesis by auto
qed
lemmas freshnats_code[code_unfold] = freshnats.tseytin_tran_def freshnats.tseytin_toatom_def freshnats.tseytin_assmt_def freshnats.nfresh.simps
lemma "freshnats.tseytin_tran (Atom 0 ❙→ (❙¬ (Atom 1))) = ❙⋀[
Atom 2,
Atom 2 ❙↔ Atom 3 ❙→ Atom 4,
Atom 0 ❙↔ Atom 3,
Atom 4 ❙↔ ❙¬ (Atom 5),
Atom 1 ❙↔ Atom 5
]" (is "?l = ?r")
proof -
have "cnf (nnf ?r) =
{{Pos 2},
{Neg 4, Pos 2}, {Pos 3, Pos 2}, {Neg 2, Neg 3, Pos 4},
{Neg 3, Pos 0}, {Neg 0, Pos 3},
{Pos 5, Pos 4}, {Neg 4, Neg 5},
{Neg 5, Pos 1}, {Neg 1, Pos 5}}" by eval
have ?thesis by eval
show ?thesis by code_simp
qed
end