4 |
4 |
5 section {* Using an External Solver *} |
5 section {* Using an External Solver *} |
6 |
6 |
7 text {* |
7 text {* |
8 {\bf Problem:} |
8 {\bf Problem:} |
9 You want to use an external solver, say, because it is more efficient in |
9 You want to use an external solver, because the solver might be more efficient |
10 deciding particular formulas than any Isabelle tactic. |
10 for deciding a certain class of formulae than Isabelle tactics. |
11 \smallskip |
11 \smallskip |
12 |
12 |
13 {\bf Solution:} The easiest way to do this is writing an oracle. |
13 {\bf Solution:} The easiest way to do this is by implementing an oracle. |
14 To yield results checked by Isabelle's kernel, one can reconstruct the |
14 We will also construct proofs inside Isabelle by using the results produced |
15 proofs. |
15 by the oracle. |
16 \smallskip |
16 \smallskip |
17 |
17 |
18 \begin{readmore} |
18 \begin{readmore} |
19 A short introduction to oracles can be found in [isar-ref: no suitable label |
19 A short introduction to oracles can be found in [isar-ref: no suitable label |
20 for section 3.11]. A simple example is given in |
20 for section 3.11]. A simple example is given in |
21 @{ML_file "FOL/ex/IffOracle"}. |
21 @{ML_file "FOL/ex/IffOracle"}. |
22 (TODO: add more references to the code) |
22 (TODO: add more references to the code) |
23 \end{readmore} |
23 \end{readmore} |
24 |
24 |
25 The general layout will be as follows. Given a goal G, we transform it into |
25 For our explanation here, we will use the @{text metis} prover for proving |
26 the syntactical respresentation of the external solver, and invoke the |
26 propositional formulae. The general method will be roughly as follows: |
27 solver. The solver's result is then used inside the oracle to either return |
27 Given a goal @{text G}, we transform it into the syntactical respresentation |
28 the proved goal or raise an exception meaning that the solver was unable to |
28 of @{text "metis"}, build the CNF and then let metis search for a refutation. |
29 prove the goal. |
29 @{text Metis} will either return the proved goal or raise an exception meaning |
|
30 that it was unable to prove the goal (FIXME: is this so?). |
30 |
31 |
31 For communication with external programs, there are the primitives |
32 The translation function from Isabelle propositions into formulae of |
32 @{ML_text system} and @{ML_text system_out}, the latter of which captures |
33 @{text metis} is as follows: |
33 the invoked program's output. For simplicity, here, we will use metis, an |
|
34 external solver included in the Isabelle destribution. Since it is written |
|
35 in ML, we can call it directly without the detour of invoking an external |
|
36 program. |
|
37 |
|
38 We will restrict ourselves to proving formulas of propositional logic, a |
|
39 task metis is very good at. |
|
40 *} |
34 *} |
41 |
35 |
42 |
36 ML{*fun trans t = |
43 ML {* |
|
44 fun trans t = |
|
45 (case t of |
37 (case t of |
46 @{term Trueprop} $ t => trans t |
38 @{term Trueprop} $ t => trans t |
47 | @{term True} => Metis.Formula.True |
39 | @{term True} => Metis.Formula.True |
48 | @{term False} => Metis.Formula.False |
40 | @{term False} => Metis.Formula.False |
49 | @{term Not} $ t => Metis.Formula.Not (trans t) |
41 | @{term Not} $ t => Metis.Formula.Not (trans t) |
50 | @{term "op &"} $ t1 $ t2 => Metis.Formula.And (trans t1, trans t2) |
42 | @{term "op &"} $ t1 $ t2 => Metis.Formula.And (trans t1, trans t2) |
51 | @{term "op |"} $ t1 $ t2 => Metis.Formula.Or (trans t1, trans t2) |
43 | @{term "op |"} $ t1 $ t2 => Metis.Formula.Or (trans t1, trans t2) |
52 | @{term "op -->"} $ t1 $ t2 => Metis.Formula.Imp (trans t1, trans t2) |
44 | @{term "op -->"} $ t1 $ t2 => Metis.Formula.Imp (trans t1, trans t2) |
53 | @{term "op = :: bool => bool => bool"} $ t1 $ t2 => |
45 | @{term "op = :: bool => bool => bool"} $ t1 $ t2 => |
54 Metis.Formula.Iff (trans t1, trans t2) |
46 Metis.Formula.Iff (trans t1, trans t2) |
55 | Free (n, @{typ bool}) => Metis.Formula.Atom (n, []) |
47 | Free (n, @{typ bool}) => Metis.Formula.Atom (n, []) |
56 | _ => error "inacceptable term") |
48 | _ => error "inacceptable term")*} |
|
49 |
|
50 |
|
51 text {* |
|
52 An example is as follows: |
|
53 |
|
54 @{ML_response [display,gray] "trans @{prop \"A \<and> B\"}" |
|
55 "Metis.Formula.And |
|
56 (Metis.Formula.Atom (\"A\", []), Metis.Formula.Atom (\"B\", []))"} |
|
57 |
|
58 |
|
59 The next function computes the conjunctive-normal-form. |
57 *} |
60 *} |
58 |
61 |
59 |
62 |
60 ML {* |
63 ML %linenumbers{*fun make_cnfs fm = |
61 fun solve f = |
64 fm |> Metis.Formula.Not |
62 let |
65 |> Metis.Normalize.cnf |
63 open Metis |
66 |> map Metis.Formula.stripConj |
64 fun fromLiterals fms = LiteralSet.fromList (map Literal.fromFormula fms) |
67 |> map (map Metis.Formula.stripDisj) |
65 fun fromClause fm = fromLiterals (Formula.stripDisj fm) |
68 |> map (map (map Metis.Literal.fromFormula)) |
66 fun fromCnf fm = map fromClause (Formula.stripConj fm) |
69 |> map (map Metis.LiteralSet.fromList) |
|
70 |> map (map Metis.Thm.axiom)*} |
67 |
71 |
68 val mk_cnfs = map fromCnf o Normalize.cnf o Formula.Not |
72 text {* |
69 fun refute cls = |
73 (FIXME: Is there a deep reason why Metis.Normalize.cnf returns a list?) |
70 let val res = Resolution.new Resolution.default (map Thm.axiom cls) |
74 |
71 in |
75 (FIXME: What does Line 8 do?) |
72 (case Resolution.loop res of |
76 |
73 Resolution.Contradiction _ => true |
77 (FIXME: Can this code improved?) |
74 | Resolution.Satisfiable _ => false) |
78 |
75 end |
79 |
76 in List.all refute (mk_cnfs f) end |
80 Setting up the resolution. |
77 *} |
81 *} |
78 |
82 |
|
83 ML{*fun refute cls = |
|
84 let val result = |
|
85 Metis.Resolution.loop |
|
86 (Metis.Resolution.new Metis.Resolution.default cls) |
|
87 in |
|
88 (case result of |
|
89 Metis.Resolution.Contradiction _ => true |
|
90 | Metis.Resolution.Satisfiable _ => false) |
|
91 end*} |
79 |
92 |
80 ML {* |
93 text {* |
81 fun prop_dp (thy, t) = if solve (trans t) then Thm.cterm_of thy t |
94 Stringing the functions together. |
82 else error "Proof failed." |
|
83 *} |
95 *} |
|
96 |
|
97 ML{*fun solve f = List.all refute (make_cnfs f)*} |
|
98 |
|
99 text {* Setting up the oracle*} |
|
100 |
|
101 ML{*fun prop_dp (thy, t) = |
|
102 if solve (trans t) then (Thm.cterm_of thy t) |
|
103 else error "Proof failed."*} |
84 |
104 |
85 oracle prop_oracle = prop_dp |
105 oracle prop_oracle = prop_dp |
86 |
106 |
87 ML {* |
107 text {* (FIXME: What does oracle this do?) *} |
88 fun prop_oracle_tac ctxt = |
108 |
|
109 |
|
110 ML{*fun prop_oracle_tac ctxt = |
89 SUBGOAL (fn (goal, i) => |
111 SUBGOAL (fn (goal, i) => |
90 (case try prop_oracle (ProofContext.theory_of ctxt, goal) of |
112 (case (try prop_oracle (ProofContext.theory_of ctxt, goal)) of |
91 SOME thm => rtac thm i |
113 SOME thm => rtac thm i |
92 | NONE => no_tac)) |
114 | NONE => no_tac))*} |
|
115 |
|
116 text {* |
|
117 (FIXME: The oracle returns a @{text cterm}. How is it possible |
|
118 that I can apply this cterm with @{ML rtac}?) |
93 *} |
119 *} |
94 |
120 |
95 method_setup prop_oracle = {* |
121 method_setup prop_oracle = {* |
96 Method.ctxt_args (fn ctxt => Method.SIMPLE_METHOD' (prop_oracle_tac ctxt)) |
122 Method.ctxt_args (fn ctxt => Method.SIMPLE_METHOD' (prop_oracle_tac ctxt)) |
97 *} "Oracle-based decision procedure for propositional logic" |
123 *} "Oracle-based decision procedure for propositional logic" |
98 |
124 |
99 lemma "p \<or> \<not>p" |
125 text {* (FIXME What does @{ML Method.SIMPLE_METHOD'} do?) *} |
|
126 |
|
127 lemma test: "p \<or> \<not>p" |
100 by prop_oracle |
128 by prop_oracle |
|
129 |
|
130 text {* (FIXME: say something about what the proof of the oracle is) *} |
|
131 |
|
132 ML {* Thm.proof_of @{thm test} *} |
101 |
133 |
102 lemma "((p \<longrightarrow> q) \<longrightarrow> p) \<longrightarrow> p" |
134 lemma "((p \<longrightarrow> q) \<longrightarrow> p) \<longrightarrow> p" |
103 by prop_oracle |
135 by prop_oracle |
104 |
136 |
105 lemma "\<forall>x::nat. x \<ge> 0" |
137 lemma "\<forall>x::nat. x \<ge> 0" |
106 sorry |
138 sorry |
107 |
139 |
|
140 text {* |
|
141 (FIXME: proof reconstruction) |
|
142 *} |
108 |
143 |
109 (* TODO: proof reconstruction *) |
144 |
|
145 |
|
146 text {* |
|
147 For communication with external programs, there are the primitives |
|
148 @{ML_text system} and @{ML_text system_out}, the latter of which captures |
|
149 the invoked program's output. For simplicity, here, we will use metis, an |
|
150 external solver included in the Isabelle destribution. Since it is written |
|
151 in ML, we can call it directly without the detour of invoking an external |
|
152 program. |
|
153 *} |
110 |
154 |
111 |
155 |
112 end |
156 end |