adding a mockup version for prolog code generation
authorbulwahn
Thu, 29 Jul 2010 17:27:52 +0200
changeset 3831964062d56ad3c
parent 38318 7b8c295af291
child 38320 31174744b9a2
adding a mockup version for prolog code generation
src/HOL/Tools/Predicate_Compile/code_prolog.ML
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/HOL/Tools/Predicate_Compile/code_prolog.ML	Thu Jul 29 17:27:52 2010 +0200
     1.3 @@ -0,0 +1,162 @@
     1.4 +(*  Title:      HOL/Tools/Predicate_Compile/code_prolog.ML
     1.5 +    Author:     Lukas Bulwahn, TU Muenchen
     1.6 +
     1.7 +Prototype of an code generator for logic programming languages (a.k.a. Prolog)
     1.8 +*)
     1.9 +
    1.10 +signature CODE_PROLOG =
    1.11 +sig
    1.12 +  datatype term = Var of string * typ | Cons of string | AppF of string * term list;
    1.13 +  datatype prem = Conj of prem list | NotRel of string * term list | Rel of string * term list | Eq of term * term | NotEq of term * term;
    1.14 +  type clause = ((string * term list) * prem);
    1.15 +  type logic_program = clause list;
    1.16 +
    1.17 +  val generate : Proof.context -> string list -> logic_program
    1.18 +  val write_program : logic_program -> string
    1.19 +  val run : logic_program -> string -> string list -> unit
    1.20 +
    1.21 +end;
    1.22 +
    1.23 +structure Code_Prolog : CODE_PROLOG =
    1.24 +struct
    1.25 +
    1.26 +(* general string functions *)
    1.27 +
    1.28 +val first_upper = implode o nth_map 0 Symbol.to_ascii_upper o explode;
    1.29 +val first_lower = implode o nth_map 0 Symbol.to_ascii_lower o explode;
    1.30 +
    1.31 +(* internal program representation *)
    1.32 +
    1.33 +datatype term = Var of string * typ | Cons of string | AppF of string * term list;
    1.34 +
    1.35 +datatype prem = Conj of prem list | NotRel of string * term list | Rel of string * term list | Eq of term * term | NotEq of term * term;
    1.36 +
    1.37 +fun dest_Rel (Rel (c, ts)) = (c, ts)
    1.38 + 
    1.39 +type clause = ((string * term list) * prem);
    1.40 +
    1.41 +type logic_program = clause list;
    1.42 +
    1.43 +(* translation from introduction rules to internal representation *)
    1.44 +
    1.45 +(* assuming no clashing *)
    1.46 +fun translate_const c = Long_Name.base_name c
    1.47 +
    1.48 +fun translate_term ctxt t =
    1.49 +  case strip_comb t of
    1.50 +    (Free (v, T), []) => Var (v, T) 
    1.51 +  | (Const (c, _), []) => Cons (translate_const c)
    1.52 +  | (Const (c, _), args) => AppF (translate_const c, map (translate_term ctxt) args)
    1.53 +  | _ => error ("illegal term for translation: " ^ Syntax.string_of_term ctxt t)
    1.54 +
    1.55 +
    1.56 +fun translate_literal ctxt t =
    1.57 +  case strip_comb t of
    1.58 +    (Const (@{const_name "op ="}, _), [l, r]) => Eq (pairself (translate_term ctxt) (l, r))
    1.59 +  | (Const (c, _), args) => Rel (translate_const c, map (translate_term ctxt) args)
    1.60 +  | _ => error ("illegal literal for translation: " ^ Syntax.string_of_term ctxt t)
    1.61 +
    1.62 +fun NegRel_of (Rel lit) = NotRel lit
    1.63 +  | NegRel_of (Eq eq) = NotEq eq
    1.64 +  
    1.65 +fun translate_prem ctxt t =  
    1.66 +    case try HOLogic.dest_not t of
    1.67 +      SOME t => NegRel_of (translate_literal ctxt t)
    1.68 +    | NONE => translate_literal ctxt t
    1.69 +
    1.70 +fun translate_intros ctxt gr const =
    1.71 +  let
    1.72 +    val intros = Graph.get_node gr const
    1.73 +    val (intros', ctxt') = Variable.import_terms true (map prop_of intros) ctxt
    1.74 +    fun translate_intro intro =
    1.75 +      let
    1.76 +        val head = HOLogic.dest_Trueprop (Logic.strip_imp_concl intro)
    1.77 +        val prems = map HOLogic.dest_Trueprop (Logic.strip_imp_prems intro) 
    1.78 +        val prems' = Conj (map (translate_prem ctxt') prems)
    1.79 +        val clause = (dest_Rel (translate_literal ctxt' head), prems')
    1.80 +      in clause end
    1.81 +  in map translate_intro intros' end
    1.82 +
    1.83 +fun generate ctxt const =
    1.84 +  let 
    1.85 +     fun strong_conn_of gr keys =
    1.86 +      Graph.strong_conn (Graph.subgraph (member (op =) (Graph.all_succs gr keys)) gr)
    1.87 +    val gr = Predicate_Compile_Core.intros_graph_of ctxt
    1.88 +    val scc = strong_conn_of gr const
    1.89 +    val _ = tracing (commas (flat scc))
    1.90 +  in
    1.91 +    maps (translate_intros ctxt gr) (flat scc)
    1.92 +  end
    1.93 +
    1.94 +(* transform logic program *)
    1.95 +
    1.96 +(** ensure groundness of terms before negation **)
    1.97 +
    1.98 +fun add_vars (Var x) vs = insert (op =) x vs
    1.99 +  | add_vars (Cons c) vs = vs
   1.100 +  | add_vars (AppF (f, args)) vs = fold add_vars args vs
   1.101 +
   1.102 +fun string_of_typ (Type (s, Ts)) = Long_Name.base_name s
   1.103 +
   1.104 +fun mk_groundness_prems ts =
   1.105 +  let
   1.106 +    val vars = fold add_vars ts []
   1.107 +    fun mk_ground (v, T) =
   1.108 +      Rel ("ground_" ^ string_of_typ T, [Var (v, T)])
   1.109 +  in
   1.110 +    map mk_ground vars
   1.111 +  end
   1.112 +
   1.113 +fun ensure_groundness_prem (NotRel (c, ts)) = Conj (mk_groundness_prems ts @ [NotRel (c, ts)]) 
   1.114 +  | ensure_groundness_prem (NotEq (l, r)) = Conj (mk_groundness_prems [l, r] @ [NotEq (l, r)])
   1.115 +  | ensure_groundness_prem (Conj ps) = Conj (map ensure_groundness_prem ps)
   1.116 +  | ensure_groundness_prem p = p
   1.117 +
   1.118 +fun ensure_groundness_before_negation p =
   1.119 +  map (apsnd ensure_groundness_prem) p
   1.120 +
   1.121 +(* code printer *)
   1.122 +
   1.123 +fun write_term (Var (v, _)) = first_upper v
   1.124 +  | write_term (Cons c) = first_lower c
   1.125 +  | write_term (AppF (f, args)) = first_lower f ^ "(" ^ space_implode ", " (map write_term args) ^ ")" 
   1.126 +
   1.127 +fun write_rel (pred, args) =
   1.128 +  pred ^ "(" ^ space_implode ", " (map write_term args) ^ ")" 
   1.129 +
   1.130 +fun write_prem (Conj prems) = space_implode ", " (map write_prem prems)
   1.131 +  | write_prem (Rel p) = write_rel p  
   1.132 +  | write_prem (NotRel p) = "not(" ^ write_rel p ^ ")"
   1.133 +  | write_prem (Eq (l, r)) = write_term l ^ " = " ^ write_term r
   1.134 +  | write_prem (NotEq (l, r)) = write_term l ^ " \\= " ^ write_term r
   1.135 +
   1.136 +fun write_clause (head, prem) =
   1.137 +  write_rel head ^ (if prem = Conj [] then "." else " :- " ^ write_prem prem ^ ".")
   1.138 +
   1.139 +fun write_program p =
   1.140 +  cat_lines (map write_clause p) 
   1.141 +
   1.142 +fun query_first rel vnames =
   1.143 +  "eval :- once("  ^ rel ^ "(" ^ space_implode ", " vnames ^ ")),\n" ^
   1.144 +  "writef('" ^ implode (map (fn v => v ^ " = %w\\n") vnames) ^"', [" ^ space_implode ", " vnames ^ "]).\n"
   1.145 +
   1.146 +val prelude =
   1.147 +  "#!/usr/bin/swipl -q -t main -f\n\n" ^
   1.148 +  ":- style_check(-singleton).\n\n" ^
   1.149 +  "main :- catch(eval, E, (print_message(error, E), fail)), halt.\n" ^
   1.150 +  "main :- halt(1).\n"
   1.151 +  
   1.152 +(* calling external interpreter and getting results *)
   1.153 +
   1.154 +fun run p query_rel vnames =
   1.155 +  let
   1.156 +    val cmd = Path.named_root
   1.157 +    val prog = prelude ^ query_first query_rel vnames ^ write_program p
   1.158 +    val prolog_file = File.tmp_path (Path.basic "prolog_file")
   1.159 +    val _ = File.write prolog_file prog
   1.160 +    val (solution, _) = bash_output ("/usr/bin/swipl -f " ^ File.shell_path prolog_file)
   1.161 +  in
   1.162 +    tracing ("Prolog returns result:\n" ^ solution)
   1.163 +  end
   1.164 +
   1.165 +end;