(* Goal verification framework - Logic *) \ \This theory sets up syntax, semantics and a sequent for classical logic with no quantifiers. The type for an extension is arbitrary to allow reuse in different logic languages to be defined.\ theory Gvf_Logic imports Main begin section \Syntax\ \ \The usual infix operators are in bold to avoid conflict with Isabelle's built-in operators.\ datatype 'a \\<^sub>P = Atom (the_atom: 'a) | F (\\<^bold>\\) | Negation \'a \\<^sub>P\ (\\<^bold>\\) | Implication \'a \\<^sub>P\ \'a \\<^sub>P\ (infixr \\<^bold>\\ 60) | Disjunction \'a \\<^sub>P\ \'a \\<^sub>P\ (infixl \\<^bold>\\ 70) | Conjunction \'a \\<^sub>P\ \'a \\<^sub>P\ (infixl \\<^bold>\\ 80) \ \'a is a type variable for the type of the extension. An element of this type is parsed to the constructor for Atom. The Boolean operators take one (or two) formula(s) as input (parsing on the type variable).\ \ \Define a type for propositional logic formulas using string symbols.\ type_synonym \\<^sub>L = \string \\<^sub>P\ \ \Bi-implication is defined from conjunction and implication.\ abbreviation Equiv\<^sub>P :: \'a \\<^sub>P \ 'a \\<^sub>P \ 'a \\<^sub>P\ (infix \\<^bold>\\ 60) where \P \<^bold>\ Q \ (P \<^bold>\ Q) \<^bold>\ (Q \<^bold>\ P)\ abbreviation Truth\<^sub>L :: \'a \\<^sub>P\ (\\<^bold>\\) where \\<^bold>\ \ \<^bold>\ \<^bold>\\ \ \Example.\ value \P \<^bold>\ (P \<^bold>\ Q) \<^bold>\ Q\ section \Semantics\ \ \The semantics function takes an interpretation and a formula and returns a Boolean.\ primrec semantics\<^sub>P :: \('a \ bool) \ 'a \\<^sub>P \ bool\ where \semantics\<^sub>P f (Atom x) = f x\ | \semantics\<^sub>P f \<^bold>\ = False\ | \semantics\<^sub>P f (\<^bold>\ p) = (\semantics\<^sub>P f p)\ | \semantics\<^sub>P f (p \<^bold>\ q) = (semantics\<^sub>P f p \ semantics\<^sub>P f q)\ | \semantics\<^sub>P f (p \<^bold>\ q) = (semantics\<^sub>P f p \ semantics\<^sub>P f q)\ | \semantics\<^sub>P f (p \<^bold>\ q) = (semantics\<^sub>P f p \ semantics\<^sub>P f q)\ \ \The interpretation f is a function from elements of type 'a to Booleans. In the case of Atom the value is looked up and returned. In case of a Boolean operator, we can exploit Isabelle's built-in operators. This could also be achieved by proper coding of if-then structures.\ \ \Example (holds for any f, P and Q).\ lemma \semantics\<^sub>P f (P \<^bold>\ (P \<^bold>\ Q) \<^bold>\ Q)\ by simp \ \Entailment.\ abbreviation entails :: \'a \\<^sub>P list \ 'a \\<^sub>P list \ bool\ (infix \\\<^sub>P#\ 50) where \\ \\<^sub>P# \ \ (\f. (\p\set \. semantics\<^sub>P f p) \ (\p\set \. semantics\<^sub>P f p))\ \ \L entails R if, for all interpretations, all formulas in L true implies at least one in R true.\ \ \Example.\ lemma \[ P ] \\<^sub>P# [ P, Q ]\ by simp \ \Entailment for a singleton on rhs.\ abbreviation entails_singleton :: \'a \\<^sub>P list \ 'a \\<^sub>P \ bool\ (infix \\<^bold>\\<^sub>P\ 50) where \\ \<^bold>\\<^sub>P \ \ (\f. (\p\set \. semantics\<^sub>P f p) \ semantics\<^sub>P f \)\ abbreviation entails_all_singleton :: \'a \\<^sub>P \ bool\ (\\\<^sub>P\) where \\\<^sub>P \ \ (\f. semantics\<^sub>P f \)\ \ \Not derive contradiction\ lemma not_contradict: \\f. \p\set P. semantics\<^sub>P f p \ \ P \<^bold>\\<^sub>P \<^bold>\\ by simp \ \Example.\ lemma \[ P \<^bold>\ Q ] \<^bold>\\<^sub>P P\ by simp \ \Example.\ lemma \Q \ P \ \ [ Atom Q ] \<^bold>\\<^sub>P Atom P\ by auto \ \Weakening of assumptions for entailment\ lemma weakening_entailment: \set \' \ set \ \ \' \\<^sub>P# \ \ \ \\<^sub>P# \\ by blast \ \Example.\ lemma \[ P\<^sub>1, P\<^sub>2 ] \\<^sub>P# [ Q ] \ [ P\<^sub>1, P\<^sub>2, P\<^sub>3 ] \\<^sub>P# [ Q ]\ using weakening_entailment by simp section \Sequent calculus\ abbreviation append_new :: \'a list \ 'a list \ 'a list\ where \append_new L R \ L @ (filter (\x. x \ set L) R)\ type_synonym 'a gen_rules = \'a \\<^sub>P list \ 'a \\<^sub>P list \ bool\ \ \Generic sequent calculus proof system.\ inductive gen_sc :: \'a gen_rules option \ 'a \\<^sub>P list \ 'a \\<^sub>P list \ bool\ where \ \Base axiom\ Axiom: \p \ set \ \ p \ set \ \ gen_sc R \ \\ | \ \Logical non-branching\ L_Neg: \gen_sc R \ (p # \) \ gen_sc R ((\<^bold>\ p) # \) \\ | R_Neg: \gen_sc R (p # \) \ \ gen_sc R \ ((\<^bold>\ p) # \)\ | R_Imp: \gen_sc R (p # \) (q # \) \ gen_sc R \ ((p \<^bold>\ q) # \)\ | R_Or: \gen_sc R \ (p # q # \) \ gen_sc R \ ((p \<^bold>\ q) # \)\ | L_And: \gen_sc R (p # q # \) \ \ gen_sc R ((p \<^bold>\ q) # \) \\ | \ \Logical branching\ R_And: \gen_sc R \ (p # \) \ gen_sc R \ (q # \) \ gen_sc R \ ((p \<^bold>\ q) # \)\ | L_Or: \gen_sc R (p # \) \ \ gen_sc R (q # \) \ \ gen_sc R ((p \<^bold>\ q) # \) \\ | L_Imp: \gen_sc R \ (p # \) \ gen_sc R (q # \) \ \ gen_sc R ((p \<^bold>\ q) # \) \\ | \ \Cut\ Cut: \gen_sc R \ (p # \) \ gen_sc R (p # \) \ \ gen_sc R (append_new \ \) (append_new \ \)\ | \ \Weakening\ L_W: \gen_sc R \ \ \ gen_sc R (\ @ \) \\ | R_W: \gen_sc R \ \ \ gen_sc R \ (\ @ \)\ | \ \Shift\ L_Shift: \gen_sc R (rotate1 \) \ \ gen_sc R \ \\ | R_Shift: \gen_sc R \ (rotate1 \) \ gen_sc R \ \\ | \ \Generic\ Gen: \R \ None \ the R \ \ \ gen_sc R \ \\ lemma weakening_h: assumes \gen_sc R \ \\ shows \gen_sc R (p # \) \\ \gen_sc R \ (p # \)\ proof - from L_W have \gen_sc R ([p] @ \) \\ using assms by blast then show \gen_sc R (p # \) \\ by simp from R_W have \gen_sc R \ ([p] @ \)\ using assms by blast then show \gen_sc R \ (p # \)\ by simp qed lemma gen_sc_None: \gen_sc R \ \ \ R = None \ gen_sc R' \ \\ proof (induct rule: gen_sc.induct) case (Axiom R \ p \) with gen_sc.Axiom show ?case by auto next case (L_Neg R \ \ p) with gen_sc.L_Neg show ?case by simp next case (R_Neg R \ p \) with gen_sc.R_Neg show ?case by simp next case (R_Imp R \ p \ q) with gen_sc.R_Imp show ?case by simp next case (R_Or R \ \ p q) with gen_sc.R_Or show ?case by simp next case (L_And R \ p q \) with gen_sc.L_And show ?case by simp next case (R_And R \ \ p q) with gen_sc.R_And show ?case by simp next case (L_Or R \ p \ q) with gen_sc.L_Or show ?case by simp next case (L_Imp R \ \ p q) with gen_sc.L_Imp show ?case by simp next case (Cut R \ p \ \ \) with gen_sc.Cut show ?case by simp next case (L_W R \ \ \) with gen_sc.L_W show ?case by simp next case (R_W R \ \ \) with gen_sc.R_W show ?case by simp next case (Gen r \ \) with gen_sc.Gen show ?case by simp next case (L_Shift R \ \) with gen_sc.L_Shift show ?case by simp next case (R_Shift R \ \) with gen_sc.R_Shift show ?case by simp qed abbreviation sequent_calculus :: \'a \\<^sub>P list \ 'a \\<^sub>P list \ bool\ (infix \\\<^sub>P#\ 40) where \\ \\<^sub>P# \ \ gen_sc None \ \\ \ \Example.\ lemma \[ P \<^bold>\ Q ] \\<^sub>P# [ P ]\ proof - from Axiom[where p=P] have \[ P, Q ] \\<^sub>P# [ P ]\ by simp then show ?thesis using L_And by force qed \ \Notation for empty lhs and singleton rhs.\ abbreviation provable :: \'a \\<^sub>P \ bool\ (\\\<^sub>P _\ 40) where \\\<^sub>P p \ [] \\<^sub>P# [ p ]\ \ \Modus ponens\ lemma gen_sc_mp: \gen_sc R \ [ p \<^bold>\ q ] \ gen_sc R \ [ p ] \ gen_sc R \ [ q ]\ proof - assume \gen_sc R \ [ p \<^bold>\ q ]\ moreover assume \gen_sc R \ [ p ]\ with weakening_h(2) have \gen_sc R \ [q, p]\ by auto with R_Shift have \gen_sc R \ [p, q]\ by force from Axiom[where p=q] have \gen_sc R (q # \) [ q ]\ by simp with \gen_sc R \ [p, q]\ have \gen_sc R ((p \<^bold>\ q) # \) [ q ]\ using L_Imp by blast ultimately show \gen_sc R \ [ q ]\ using Cut by fastforce qed \ \Example single-step.\ lemma \\\<^sub>P P \<^bold>\ (P \<^bold>\ Q) \<^bold>\ Q\ proof - from R_Imp have \[] \\<^sub>P# [ P \<^bold>\ (P \<^bold>\ Q) \<^bold>\ Q ]\ if \[ P ] \\<^sub>P# [ (P \<^bold>\ Q) \<^bold>\ Q ]\ using that by blast with R_Imp have ?thesis if \[ P \<^bold>\ Q, P ] \\<^sub>P# [ Q ]\ using that by fastforce with L_Imp have ?thesis if \[ P ] \\<^sub>P# [ P, Q ]\ and \[ Q, P ] \\<^sub>P# [ Q ]\ using that by fastforce moreover have \[ P ] \\<^sub>P# [ P, Q ]\ using Axiom[where p=P] by simp moreover have \([ Q, P ]) \\<^sub>P# [ Q ]\ using Axiom[where p=Q] by simp ultimately show ?thesis by simp qed \ \The hassle of manually proving even simple formulas calls for an implementation of proof tactics. The deep embedding of the logic means that trivial formulas cannot be proved using Isabelle's vast knowledge about logic formulas, however I am not sure if there is a good way around this.\ section \Misc.\ lemma neg_imp: \\\<^sub>P (p \<^bold>\ \<^bold>\ q) \<^bold>\ q \<^bold>\ \<^bold>\ p\ proof - from R_Imp have ?thesis if \[ p \<^bold>\ \<^bold>\ q ] \\<^sub>P# [ q \<^bold>\ \<^bold>\ p ]\ using that by blast with R_Imp have ?thesis if \[ q, p \<^bold>\ \<^bold>\ q ] \\<^sub>P# [ \<^bold>\ p ]\ using that by blast with R_Neg have ?thesis if \[ p, q, p \<^bold>\ \<^bold>\ q ] \\<^sub>P# []\ using that by fastforce moreover have \rotate1 (rotate1 [ p, q, p \<^bold>\ \<^bold>\ q ]) = [ p \<^bold>\ \<^bold>\ q, p, q ]\ by simp ultimately have ?thesis if \[ p \<^bold>\ \<^bold>\ q, p, q ] \\<^sub>P# []\ using that L_Shift by metis with L_Imp have ?thesis if \[ p, q ] \\<^sub>P# [ p ]\ and \[ \<^bold>\ q, p, q ] \\<^sub>P# []\ using that by blast with L_Neg have ?thesis if \[ p, q ] \\<^sub>P# [ p ]\ and \[ p, q ] \\<^sub>P# [ q ]\ using that by blast with Axiom[where p=p] Axiom[where p=q] show ?thesis by simp qed \ \Proofs about the formulas that are not entailed are in general harder, so the idea is to collect a number of proofs in a small library as we encounter the need to complete such proofs.\ lemma neq_ext_not_entail: assumes \x \ y\ shows \\ [ Atom x ] \<^bold>\\<^sub>P Atom y\ using assms by auto fun distinct_ground_atoms_aux :: \'a \\<^sub>P list \ 'a list \ bool\ where \distinct_ground_atoms_aux (Atom p # L) P = distinct_ground_atoms_aux L (p#P)\ | \distinct_ground_atoms_aux (\<^bold>\ (Atom p) # L) P = (p \ set P \ distinct_ground_atoms_aux L P)\ | \distinct_ground_atoms_aux _ _ = False\ fun distinct_ground_atoms :: \'a \\<^sub>P list \ bool\ where \distinct_ground_atoms L = distinct_ground_atoms_aux L []\ section \Soundness\ \ \Proving the formula implies that it is valid. Because the sequent calculus is based on the use of multisets, whereas the semantics is based on regular sets, a conversion is required. In general going from multisets to sets is more clean due to the former always being finite.\ \ \The soundness theorem.\ lemma soundness\<^sub>P': \gen_sc R \ \ \ R = None \ \ \\<^sub>P# \\ proof (induct rule: gen_sc.induct) case (Cut R \ \ p \ \) then show ?case by fastforce qed auto theorem soundness\<^sub>P: \\ \\<^sub>P# \ \ \ \\<^sub>P# \\ using soundness\<^sub>P' by blast end