src/HOL/Tools/Predicate_Compile/code_prolog.ML
changeset 69593 3dda49e08b9d
parent 67405 e9ab4ad7bd15
child 70308 7f568724d67e
equal deleted inserted replaced
69592:a80d8ec6c998 69593:3dda49e08b9d
   121 datatype prolog_system = SWI_PROLOG | YAP
   121 datatype prolog_system = SWI_PROLOG | YAP
   122 
   122 
   123 fun string_of_system SWI_PROLOG = "swiprolog"
   123 fun string_of_system SWI_PROLOG = "swiprolog"
   124   | string_of_system YAP = "yap"
   124   | string_of_system YAP = "yap"
   125 
   125 
   126 val prolog_system = Attrib.setup_config_string @{binding prolog_system} (K "swiprolog")
   126 val prolog_system = Attrib.setup_config_string \<^binding>\<open>prolog_system\<close> (K "swiprolog")
   127 
   127 
   128 fun get_prolog_system ctxt =
   128 fun get_prolog_system ctxt =
   129   (case Config.get ctxt prolog_system of
   129   (case Config.get ctxt prolog_system of
   130     "swiprolog" => SWI_PROLOG
   130     "swiprolog" => SWI_PROLOG
   131   | "yap" => YAP
   131   | "yap" => YAP
   132   | name => error ("Bad prolog system: " ^ quote name ^ " (\"swiprolog\" or \"yap\" expected)"))
   132   | name => error ("Bad prolog system: " ^ quote name ^ " (\"swiprolog\" or \"yap\" expected)"))
   133 
   133 
   134 
   134 
   135 val prolog_timeout = Attrib.setup_config_real @{binding prolog_timeout} (K 10.0)
   135 val prolog_timeout = Attrib.setup_config_real \<^binding>\<open>prolog_timeout\<close> (K 10.0)
   136 
   136 
   137 fun get_prolog_timeout ctxt = seconds (Config.get ctxt prolog_timeout)
   137 fun get_prolog_timeout ctxt = seconds (Config.get ctxt prolog_timeout)
   138 
   138 
   139 
   139 
   140 (* internal program representation *)
   140 (* internal program representation *)
   248   | NONE => error ("No constant corresponding to "  ^ c))
   248   | NONE => error ("No constant corresponding to "  ^ c))
   249 
   249 
   250 
   250 
   251 (** translation of terms, literals, premises, and clauses **)
   251 (** translation of terms, literals, premises, and clauses **)
   252 
   252 
   253 fun translate_arith_const @{const_name "Groups.plus_class.plus"} = SOME Plus
   253 fun translate_arith_const \<^const_name>\<open>Groups.plus_class.plus\<close> = SOME Plus
   254   | translate_arith_const @{const_name "Groups.minus_class.minus"} = SOME Minus
   254   | translate_arith_const \<^const_name>\<open>Groups.minus_class.minus\<close> = SOME Minus
   255   | translate_arith_const _ = NONE
   255   | translate_arith_const _ = NONE
   256 
   256 
   257 fun mk_nat_term constant_table n =
   257 fun mk_nat_term constant_table n =
   258   let
   258   let
   259     val zero = translate_const constant_table @{const_name "Groups.zero_class.zero"}
   259     val zero = translate_const constant_table \<^const_name>\<open>Groups.zero_class.zero\<close>
   260     val Suc = translate_const constant_table @{const_name "Suc"}
   260     val Suc = translate_const constant_table \<^const_name>\<open>Suc\<close>
   261   in funpow n (fn t => AppF (Suc, [t])) (Cons zero) end
   261   in funpow n (fn t => AppF (Suc, [t])) (Cons zero) end
   262 
   262 
   263 fun translate_term ctxt constant_table t =
   263 fun translate_term ctxt constant_table t =
   264   (case try HOLogic.dest_number t of
   264   (case try HOLogic.dest_number t of
   265     SOME (@{typ "int"}, n) => Number n
   265     SOME (\<^typ>\<open>int\<close>, n) => Number n
   266   | SOME (@{typ "nat"}, n) => mk_nat_term constant_table n
   266   | SOME (\<^typ>\<open>nat\<close>, n) => mk_nat_term constant_table n
   267   | NONE =>
   267   | NONE =>
   268       (case strip_comb t of
   268       (case strip_comb t of
   269         (Free (v, T), []) => Var v
   269         (Free (v, T), []) => Var v
   270       | (Const (c, _), []) => Cons (translate_const constant_table c)
   270       | (Const (c, _), []) => Cons (translate_const constant_table c)
   271       | (Const (c, _), args) =>
   271       | (Const (c, _), args) =>
   275               AppF (translate_const constant_table c, map (translate_term ctxt constant_table) args))
   275               AppF (translate_const constant_table c, map (translate_term ctxt constant_table) args))
   276       | _ => error ("illegal term for translation: " ^ Syntax.string_of_term ctxt t)))
   276       | _ => error ("illegal term for translation: " ^ Syntax.string_of_term ctxt t)))
   277 
   277 
   278 fun translate_literal ctxt constant_table t =
   278 fun translate_literal ctxt constant_table t =
   279   (case strip_comb t of
   279   (case strip_comb t of
   280     (Const (@{const_name HOL.eq}, _), [l, r]) =>
   280     (Const (\<^const_name>\<open>HOL.eq\<close>, _), [l, r]) =>
   281       let
   281       let
   282         val l' = translate_term ctxt constant_table l
   282         val l' = translate_term ctxt constant_table l
   283         val r' = translate_term ctxt constant_table r
   283         val r' = translate_term ctxt constant_table r
   284       in
   284       in
   285         (if is_Var l' andalso is_arith_term r' andalso not (is_Var r') then ArithEq else Eq)
   285         (if is_Var l' andalso is_arith_term r' andalso not (is_Var r') then ArithEq else Eq)
   304         NegRel_of (translate_literal ctxt constant_table t)
   304         NegRel_of (translate_literal ctxt constant_table t)
   305   | NONE => translate_literal ctxt constant_table t)
   305   | NONE => translate_literal ctxt constant_table t)
   306 
   306 
   307 fun imp_prems_conv cv ct =
   307 fun imp_prems_conv cv ct =
   308   (case Thm.term_of ct of
   308   (case Thm.term_of ct of
   309     Const (@{const_name Pure.imp}, _) $ _ $ _ =>
   309     Const (\<^const_name>\<open>Pure.imp\<close>, _) $ _ $ _ =>
   310       Conv.combination_conv (Conv.arg_conv cv) (imp_prems_conv cv) ct
   310       Conv.combination_conv (Conv.arg_conv cv) (imp_prems_conv cv) ct
   311   | _ => Conv.all_conv ct)
   311   | _ => Conv.all_conv ct)
   312 
   312 
   313 fun preprocess_intro thy rule =
   313 fun preprocess_intro thy rule =
   314   Conv.fconv_rule
   314   Conv.fconv_rule
   491       Graph.strong_conn (Graph.restrict (member (op =) (Graph.all_succs gr keys)) gr)
   491       Graph.strong_conn (Graph.restrict (member (op =) (Graph.all_succs gr keys)) gr)
   492     val gr = Core_Data.intros_graph_of ctxt
   492     val gr = Core_Data.intros_graph_of ctxt
   493     val gr' = add_edges depending_preds_of const gr
   493     val gr' = add_edges depending_preds_of const gr
   494     val scc = strong_conn_of gr' [const]
   494     val scc = strong_conn_of gr' [const]
   495     val initial_constant_table =
   495     val initial_constant_table =
   496       declare_consts [@{const_name "Groups.zero_class.zero"}, @{const_name "Suc"}] []
   496       declare_consts [\<^const_name>\<open>Groups.zero_class.zero\<close>, \<^const_name>\<open>Suc\<close>] []
   497   in
   497   in
   498     (case use_modes of
   498     (case use_modes of
   499       SOME mode =>
   499       SOME mode =>
   500         let
   500         let
   501           val moded_gr = mk_moded_clauses_graph ctxt scc gr
   501           val moded_gr = mk_moded_clauses_graph ctxt scc gr
   893 
   893 
   894 
   894 
   895 (* restoring types in terms *)
   895 (* restoring types in terms *)
   896 
   896 
   897 fun restore_term ctxt constant_table (Var s, T) = Free (s, T)
   897 fun restore_term ctxt constant_table (Var s, T) = Free (s, T)
   898   | restore_term ctxt constant_table (Number n, @{typ "int"}) = HOLogic.mk_number @{typ "int"} n
   898   | restore_term ctxt constant_table (Number n, \<^typ>\<open>int\<close>) = HOLogic.mk_number \<^typ>\<open>int\<close> n
   899   | restore_term ctxt constant_table (Number n, _) = raise (Fail "unexpected type for number")
   899   | restore_term ctxt constant_table (Number n, _) = raise (Fail "unexpected type for number")
   900   | restore_term ctxt constant_table (Cons s, T) = Const (restore_const constant_table s, T)
   900   | restore_term ctxt constant_table (Cons s, T) = Const (restore_const constant_table s, T)
   901   | restore_term ctxt constant_table (AppF (f, args), T) =
   901   | restore_term ctxt constant_table (AppF (f, args), T) =
   902       let
   902       let
   903         val thy = Proof_Context.theory_of ctxt
   903         val thy = Proof_Context.theory_of ctxt
   913 
   913 
   914 
   914 
   915 (* restore numerals in natural numbers *)
   915 (* restore numerals in natural numbers *)
   916 
   916 
   917 fun restore_nat_numerals t =
   917 fun restore_nat_numerals t =
   918   if fastype_of t = @{typ nat} andalso is_some (try HOLogic.dest_nat t) then
   918   if fastype_of t = \<^typ>\<open>nat\<close> andalso is_some (try HOLogic.dest_nat t) then
   919     HOLogic.mk_number @{typ nat} (HOLogic.dest_nat t)
   919     HOLogic.mk_number \<^typ>\<open>nat\<close> (HOLogic.dest_nat t)
   920   else
   920   else
   921     (case t of
   921     (case t of
   922       t1 $ t2 => restore_nat_numerals t1 $ restore_nat_numerals t2
   922       t1 $ t2 => restore_nat_numerals t1 $ restore_nat_numerals t2
   923     | t => t)
   923     | t => t)
   924 
   924 
   952 fun values ctxt soln t_compr =
   952 fun values ctxt soln t_compr =
   953   let
   953   let
   954     val options = code_options_of (Proof_Context.theory_of ctxt)
   954     val options = code_options_of (Proof_Context.theory_of ctxt)
   955     val split =
   955     val split =
   956       (case t_compr of
   956       (case t_compr of
   957         (Const (@{const_name Collect}, _) $ t) => t
   957         (Const (\<^const_name>\<open>Collect\<close>, _) $ t) => t
   958       | _ => error ("Not a set comprehension: " ^ Syntax.string_of_term ctxt t_compr))
   958       | _ => error ("Not a set comprehension: " ^ Syntax.string_of_term ctxt t_compr))
   959     val (body, Ts, fp) = HOLogic.strip_ptupleabs split
   959     val (body, Ts, fp) = HOLogic.strip_ptupleabs split
   960     val output_names = Name.variant_list (Term.add_free_names body [])
   960     val output_names = Name.variant_list (Term.add_free_names body [])
   961       (map (fn i => "x" ^ string_of_int i) (1 upto length Ts))
   961       (map (fn i => "x" ^ string_of_int i) (1 upto length Ts))
   962     val output_frees = rev (map2 (curry Free) output_names Ts)
   962     val output_frees = rev (map2 (curry Free) output_names Ts)
   978     val constant_table' = declare_consts (fold Term.add_const_names all_args []) constant_table
   978     val constant_table' = declare_consts (fold Term.add_const_names all_args []) constant_table
   979     val args' = map (translate_term ctxt constant_table') all_args
   979     val args' = map (translate_term ctxt constant_table') all_args
   980     val _ = tracing "Running prolog program..."
   980     val _ = tracing "Running prolog program..."
   981     val tss = run ctxt p (translate_const constant_table' name, args') output_names soln
   981     val tss = run ctxt p (translate_const constant_table' name, args') output_names soln
   982     val _ = tracing "Restoring terms..."
   982     val _ = tracing "Restoring terms..."
   983     val empty = Const(@{const_name bot}, fastype_of t_compr)
   983     val empty = Const(\<^const_name>\<open>bot\<close>, fastype_of t_compr)
   984     fun mk_insert x S =
   984     fun mk_insert x S =
   985       Const (@{const_name "Set.insert"}, fastype_of x --> fastype_of S --> fastype_of S) $ x $ S
   985       Const (\<^const_name>\<open>Set.insert\<close>, fastype_of x --> fastype_of S --> fastype_of S) $ x $ S
   986     fun mk_set_compr in_insert [] xs =
   986     fun mk_set_compr in_insert [] xs =
   987        rev ((Free ("dots", fastype_of t_compr)) ::  (* FIXME proper name!? *)
   987        rev ((Free ("dots", fastype_of t_compr)) ::  (* FIXME proper name!? *)
   988         (if null in_insert then xs else (fold mk_insert in_insert empty) :: xs))
   988         (if null in_insert then xs else (fold mk_insert in_insert empty) :: xs))
   989       | mk_set_compr in_insert (t :: ts) xs =
   989       | mk_set_compr in_insert (t :: ts) xs =
   990         let
   990         let
   997               val uu as (uuN, uuT) =
   997               val uu as (uuN, uuT) =
   998                 singleton (Variable.variant_frees ctxt' [t]) ("uu", fastype_of t)
   998                 singleton (Variable.variant_frees ctxt' [t]) ("uu", fastype_of t)
   999               val set_compr =
   999               val set_compr =
  1000                 HOLogic.mk_Collect (uuN, uuT,
  1000                 HOLogic.mk_Collect (uuN, uuT,
  1001                   fold (fn (s, T) => fn t => HOLogic.mk_exists (s, T, t))
  1001                   fold (fn (s, T) => fn t => HOLogic.mk_exists (s, T, t))
  1002                     frees (HOLogic.mk_conj (HOLogic.mk_eq (Free uu, t), @{term "True"})))
  1002                     frees (HOLogic.mk_conj (HOLogic.mk_eq (Free uu, t), \<^term>\<open>True\<close>)))
  1003             in
  1003             in
  1004               mk_set_compr [] ts
  1004               mk_set_compr [] ts
  1005                 (set_compr ::
  1005                 (set_compr ::
  1006                   (if null in_insert then xs else (fold mk_insert in_insert empty) :: xs))
  1006                   (if null in_insert then xs else (fold mk_insert in_insert empty) :: xs))
  1007             end
  1007             end
  1008         end
  1008         end
  1009   in
  1009   in
  1010     foldl1 (HOLogic.mk_binop @{const_name sup}) (mk_set_compr []
  1010     foldl1 (HOLogic.mk_binop \<^const_name>\<open>sup\<close>) (mk_set_compr []
  1011       (map (fn ts => HOLogic.mk_tuple
  1011       (map (fn ts => HOLogic.mk_tuple
  1012         (map (restore_nat_numerals o restore_term ctxt' constant_table) (ts ~~ Ts))) tss) [])
  1012         (map (restore_nat_numerals o restore_term ctxt' constant_table) (ts ~~ Ts))) tss) [])
  1013   end
  1013   end
  1014 
  1014 
  1015 fun values_cmd print_modes soln raw_t state =
  1015 fun values_cmd print_modes soln raw_t state =
  1028 
  1028 
  1029 
  1029 
  1030 (* values command for Prolog queries *)
  1030 (* values command for Prolog queries *)
  1031 
  1031 
  1032 val opt_print_modes =
  1032 val opt_print_modes =
  1033   Scan.optional (@{keyword "("} |-- Parse.!!! (Scan.repeat1 Parse.name --| @{keyword ")"})) []
  1033   Scan.optional (\<^keyword>\<open>(\<close> |-- Parse.!!! (Scan.repeat1 Parse.name --| \<^keyword>\<open>)\<close>)) []
  1034 
  1034 
  1035 val _ =
  1035 val _ =
  1036   Outer_Syntax.command @{command_keyword values_prolog}
  1036   Outer_Syntax.command \<^command_keyword>\<open>values_prolog\<close>
  1037     "enumerate and print comprehensions"
  1037     "enumerate and print comprehensions"
  1038     (opt_print_modes -- Scan.optional (Parse.nat >> SOME) NONE -- Parse.term
  1038     (opt_print_modes -- Scan.optional (Parse.nat >> SOME) NONE -- Parse.term
  1039      >> (fn ((print_modes, soln), t) => Toplevel.keep (values_cmd print_modes soln t)))
  1039      >> (fn ((print_modes, soln), t) => Toplevel.keep (values_cmd print_modes soln t)))
  1040 
  1040 
  1041 
  1041 
  1042 (* quickcheck generator *)
  1042 (* quickcheck generator *)
  1043 
  1043 
  1044 (* FIXME: a small clone of Predicate_Compile_Quickcheck - maybe refactor out commons *)
  1044 (* FIXME: a small clone of Predicate_Compile_Quickcheck - maybe refactor out commons *)
  1045 
  1045 
  1046 val active = Attrib.setup_config_bool @{binding quickcheck_prolog_active} (K true)
  1046 val active = Attrib.setup_config_bool \<^binding>\<open>quickcheck_prolog_active\<close> (K true)
  1047 
  1047 
  1048 fun test_term ctxt (t, eval_terms) =
  1048 fun test_term ctxt (t, eval_terms) =
  1049   let
  1049   let
  1050     val t' = fold_rev absfree (Term.add_frees t []) t
  1050     val t' = fold_rev absfree (Term.add_frees t []) t
  1051     val options = code_options_of (Proof_Context.theory_of ctxt)
  1051     val options = code_options_of (Proof_Context.theory_of ctxt)
  1052     val thy = Proof_Context.theory_of ctxt
  1052     val thy = Proof_Context.theory_of ctxt
  1053     val ((((full_constname, constT), vs'), intro), thy1) =
  1053     val ((((full_constname, constT), vs'), intro), thy1) =
  1054       Predicate_Compile_Aux.define_quickcheck_predicate t' thy
  1054       Predicate_Compile_Aux.define_quickcheck_predicate t' thy
  1055     val thy2 =
  1055     val thy2 =
  1056       Context.theory_map (Named_Theorems.add_thm @{named_theorems code_pred_def} intro) thy1
  1056       Context.theory_map (Named_Theorems.add_thm \<^named_theorems>\<open>code_pred_def\<close> intro) thy1
  1057     val thy3 = Predicate_Compile.preprocess preprocess_options (Const (full_constname, constT)) thy2
  1057     val thy3 = Predicate_Compile.preprocess preprocess_options (Const (full_constname, constT)) thy2
  1058     val ctxt' = Proof_Context.init_global thy3
  1058     val ctxt' = Proof_Context.init_global thy3
  1059     val _ = tracing "Generating prolog program..."
  1059     val _ = tracing "Generating prolog program..."
  1060     val (p, constant_table) = generate (NONE, true) ctxt' full_constname
  1060     val (p, constant_table) = generate (NONE, true) ctxt' full_constname
  1061       |> post_process ctxt' (set_ensure_groundness options) full_constname
  1061       |> post_process ctxt' (set_ensure_groundness options) full_constname