CookBook/Recipes/ExternalSolver.thy
changeset 79 a53c7810e38b
parent 61 64c9540f2f84
child 81 8fda6b452f28
equal deleted inserted replaced
78:ef778679d3e0 79:a53c7810e38b
     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