CookBook/Recipes/ExternalSolver.thy
author Christian Urban <urbanc@in.tum.de>
Wed, 14 Jan 2009 23:44:14 +0000
changeset 72 7b8c4fe235aa
parent 61 64c9540f2f84
child 79 a53c7810e38b
permissions -rw-r--r--
added an antiquotation option [gray] for gray boxes around displays

theory ExternalSolver
imports "../Base"
begin

section {* Using an External Solver *} 

text {*
  {\bf Problem:}
  You want to use an external solver, say, because it is more efficient in
  deciding particular formulas than any Isabelle tactic.
  \smallskip

  {\bf Solution:} The easiest way to do this is writing an oracle.
  To yield results checked by Isabelle's kernel, one can reconstruct the
  proofs.
  \smallskip

  \begin{readmore}
  A short introduction to oracles can be found in [isar-ref: no suitable label
  for section 3.11]. A simple example is given in 
  @{ML_file "FOL/ex/IffOracle"}.
  (TODO: add more references to the code)
  \end{readmore}

  The general layout will be as follows. Given a goal G, we transform it into
  the syntactical respresentation of the external solver, and invoke the
  solver. The solver's result is then used inside the oracle to either return
  the proved goal or raise an exception meaning that the solver was unable to
  prove the goal.

  For communication with external programs, there are the primitives
  @{ML_text system} and @{ML_text system_out}, the latter of which captures
  the invoked program's output. For simplicity, here, we will use metis, an
  external solver included in the Isabelle destribution. Since it is written
  in ML, we can call it directly without the detour of invoking an external
  program.

  We will restrict ourselves to proving formulas of propositional logic, a
  task metis is very good at.
  *}


ML {*
fun trans t =
  (case t of
    @{term Trueprop} $ t => trans t
  | @{term True} => Metis.Formula.True
  | @{term False} => Metis.Formula.False
  | @{term Not} $ t => Metis.Formula.Not (trans t)
  | @{term "op &"} $ t1 $ t2 => Metis.Formula.And (trans t1, trans t2)
  | @{term "op |"} $ t1 $ t2 => Metis.Formula.Or (trans t1, trans t2)
  | @{term "op -->"} $ t1 $ t2 => Metis.Formula.Imp (trans t1, trans t2)
  | @{term "op = :: bool => bool => bool"} $ t1 $ t2 => 
      Metis.Formula.Iff (trans t1, trans t2)
  | Free (n, @{typ bool}) => Metis.Formula.Atom (n, [])
  | _ => error "inacceptable term")
*}


ML {*
fun solve f =
  let
    open Metis
    fun fromLiterals fms = LiteralSet.fromList (map Literal.fromFormula fms)
    fun fromClause fm = fromLiterals (Formula.stripDisj fm)
    fun fromCnf fm = map fromClause (Formula.stripConj fm)

    val mk_cnfs = map fromCnf o Normalize.cnf o Formula.Not
    fun refute cls =
      let val res = Resolution.new Resolution.default (map Thm.axiom cls)
      in
        (case Resolution.loop res of
          Resolution.Contradiction _ => true
        | Resolution.Satisfiable _ => false)
      end
  in List.all refute (mk_cnfs f) end
*}


ML {*
fun prop_dp (thy, t) = if solve (trans t) then Thm.cterm_of thy t 
  else error "Proof failed."
*}

oracle prop_oracle = prop_dp

ML {*
fun prop_oracle_tac ctxt = 
  SUBGOAL (fn (goal, i) => 
    (case try prop_oracle (ProofContext.theory_of ctxt, goal) of
      SOME thm => rtac thm i
    | NONE => no_tac))
*}

method_setup prop_oracle = {*
  Method.ctxt_args (fn ctxt => Method.SIMPLE_METHOD' (prop_oracle_tac ctxt))
*} "Oracle-based decision procedure for propositional logic"

lemma "p \<or> \<not>p"
  by prop_oracle

lemma "((p \<longrightarrow> q) \<longrightarrow> p) \<longrightarrow> p"
  by prop_oracle

lemma "\<forall>x::nat. x \<ge> 0"
  sorry


(* TODO: proof reconstruction *)


end