src/HOL/Tools/refute.ML
changeset 30314 853778f6ef7d
parent 30312 0e0cb7ac0281
child 30347 91f73b2997f9
equal deleted inserted replaced
30312:0e0cb7ac0281 30314:853778f6ef7d
   142 (* ------------------------------------------------------------------------- *)
   142 (* ------------------------------------------------------------------------- *)
   143 (* params: parameters that control the translation into a propositional      *)
   143 (* params: parameters that control the translation into a propositional      *)
   144 (*         formula/model generation                                          *)
   144 (*         formula/model generation                                          *)
   145 (*                                                                           *)
   145 (*                                                                           *)
   146 (* The following parameters are supported (and required (!), except for      *)
   146 (* The following parameters are supported (and required (!), except for      *)
   147 (* "sizes"):                                                                 *)
   147 (* "sizes" and "expect"):                                                    *)
   148 (*                                                                           *)
   148 (*                                                                           *)
   149 (* Name          Type    Description                                         *)
   149 (* Name          Type    Description                                         *)
   150 (*                                                                           *)
   150 (*                                                                           *)
   151 (* "sizes"       (string * int) list                                         *)
   151 (* "sizes"       (string * int) list                                         *)
   152 (*                       Size of ground types (e.g. 'a=2), or depth of IDTs. *)
   152 (*                       Size of ground types (e.g. 'a=2), or depth of IDTs. *)
   155 (* "maxvars"     int     If >0, use at most 'maxvars' Boolean variables      *)
   155 (* "maxvars"     int     If >0, use at most 'maxvars' Boolean variables      *)
   156 (*                       when transforming the term into a propositional     *)
   156 (*                       when transforming the term into a propositional     *)
   157 (*                       formula.                                            *)
   157 (*                       formula.                                            *)
   158 (* "maxtime"     int     If >0, terminate after at most 'maxtime' seconds.   *)
   158 (* "maxtime"     int     If >0, terminate after at most 'maxtime' seconds.   *)
   159 (* "satsolver"   string  SAT solver to be used.                              *)
   159 (* "satsolver"   string  SAT solver to be used.                              *)
       
   160 (* "expect"      string  Expected result ("genuine", "potential", "none", or *)
       
   161 (*                       "unknown")                                          *)
   160 (* ------------------------------------------------------------------------- *)
   162 (* ------------------------------------------------------------------------- *)
   161 
   163 
   162   type params =
   164   type params =
   163     {
   165     {
   164       sizes    : (string * int) list,
   166       sizes    : (string * int) list,
   165       minsize  : int,
   167       minsize  : int,
   166       maxsize  : int,
   168       maxsize  : int,
   167       maxvars  : int,
   169       maxvars  : int,
   168       maxtime  : int,
   170       maxtime  : int,
   169       satsolver: string
   171       satsolver: string,
       
   172       expect   : string
   170     };
   173     };
   171 
   174 
   172 (* ------------------------------------------------------------------------- *)
   175 (* ------------------------------------------------------------------------- *)
   173 (* interpretation: a term's interpretation is given by a variable of type    *)
   176 (* interpretation: a term's interpretation is given by a variable of type    *)
   174 (*                 'interpretation'                                          *)
   177 (*                 'interpretation'                                          *)
   385     val maxsize   = read_int (allparams, "maxsize")
   388     val maxsize   = read_int (allparams, "maxsize")
   386     val maxvars   = read_int (allparams, "maxvars")
   389     val maxvars   = read_int (allparams, "maxvars")
   387     val maxtime   = read_int (allparams, "maxtime")
   390     val maxtime   = read_int (allparams, "maxtime")
   388     (* string *)
   391     (* string *)
   389     val satsolver = read_string (allparams, "satsolver")
   392     val satsolver = read_string (allparams, "satsolver")
       
   393     val expect = the_default "" (AList.lookup (op =) allparams "expect")
   390     (* all remaining parameters of the form "string=int" are collected in *)
   394     (* all remaining parameters of the form "string=int" are collected in *)
   391     (* 'sizes'                                                            *)
   395     (* 'sizes'                                                            *)
   392     (* TODO: it is currently not possible to specify a size for a type    *)
   396     (* TODO: it is currently not possible to specify a size for a type    *)
   393     (*       whose name is one of the other parameters (e.g. 'maxvars')   *)
   397     (*       whose name is one of the other parameters (e.g. 'maxvars')   *)
   394     (* (string * int) list *)
   398     (* (string * int) list *)
   397       (List.filter (fn (name, _) => name<>"minsize" andalso name<>"maxsize"
   401       (List.filter (fn (name, _) => name<>"minsize" andalso name<>"maxsize"
   398         andalso name<>"maxvars" andalso name<>"maxtime"
   402         andalso name<>"maxvars" andalso name<>"maxtime"
   399         andalso name<>"satsolver") allparams)
   403         andalso name<>"satsolver") allparams)
   400   in
   404   in
   401     {sizes=sizes, minsize=minsize, maxsize=maxsize, maxvars=maxvars,
   405     {sizes=sizes, minsize=minsize, maxsize=maxsize, maxvars=maxvars,
   402       maxtime=maxtime, satsolver=satsolver}
   406       maxtime=maxtime, satsolver=satsolver, expect=expect}
   403   end;
   407   end;
   404 
   408 
   405 
   409 
   406 (* ------------------------------------------------------------------------- *)
   410 (* ------------------------------------------------------------------------- *)
   407 (* TRANSLATION HOL -> PROPOSITIONAL LOGIC, BOOLEAN ASSIGNMENT -> MODEL       *)
   411 (* TRANSLATION HOL -> PROPOSITIONAL LOGIC, BOOLEAN ASSIGNMENT -> MODEL       *)
   729           (* 'rhs', we must not use this equation to unfold, because *)
   733           (* 'rhs', we must not use this equation to unfold, because *)
   730           (* that would loop.  Here would be the right place to      *)
   734           (* that would loop.  Here would be the right place to      *)
   731           (* check this.  However, getting this really right seems   *)
   735           (* check this.  However, getting this really right seems   *)
   732           (* difficult because the user may state arbitrary axioms,  *)
   736           (* difficult because the user may state arbitrary axioms,  *)
   733           (* which could interact with overloading to create loops.  *)
   737           (* which could interact with overloading to create loops.  *)
   734           ((*Output.immediate_output (" unfolding: " ^ axname);*)
   738           ((*Output.tracing (" unfolding: " ^ axname);*)
   735            unfold_loop rhs)
   739            unfold_loop rhs)
   736         | NONE => t)
   740         | NONE => t)
   737       | Free _           => t
   741       | Free _           => t
   738       | Var _            => t
   742       | Var _            => t
   739       | Bound _          => t
   743       | Bound _          => t
   769   (* To avoid collecting the same axiom multiple times, we use an           *)
   773   (* To avoid collecting the same axiom multiple times, we use an           *)
   770   (* accumulator 'axs' which contains all axioms collected so far.          *)
   774   (* accumulator 'axs' which contains all axioms collected so far.          *)
   771 
   775 
   772   fun collect_axioms thy t =
   776   fun collect_axioms thy t =
   773   let
   777   let
   774     val _ = Output.immediate_output "Adding axioms..."
   778     val _ = Output.tracing "Adding axioms..."
   775     (* (string * Term.term) list *)
   779     (* (string * Term.term) list *)
   776     val axioms = Theory.all_axioms_of thy
   780     val axioms = Theory.all_axioms_of thy
   777     (* string * Term.term -> Term.term list -> Term.term list *)
   781     (* string * Term.term -> Term.term list -> Term.term list *)
   778     fun collect_this_axiom (axname, ax) axs =
   782     fun collect_this_axiom (axname, ax) axs =
   779     let
   783     let
   780       val ax' = unfold_defs thy ax
   784       val ax' = unfold_defs thy ax
   781     in
   785     in
   782       if member (op aconv) axs ax' then
   786       if member (op aconv) axs ax' then
   783         axs
   787         axs
   784       else (
   788       else (
   785         Output.immediate_output (" " ^ axname);
   789         Output.tracing axname;
   786         collect_term_axioms (ax' :: axs, ax')
   790         collect_term_axioms (ax' :: axs, ax')
   787       )
   791       )
   788     end
   792     end
   789     (* Term.term list * Term.typ -> Term.term list *)
   793     (* Term.term list * Term.typ -> Term.term list *)
   790     and collect_sort_axioms (axs, T) =
   794     and collect_sort_axioms (axs, T) =
   943         (collect_type_axioms (axs, T), body)
   947         (collect_type_axioms (axs, T), body)
   944       | t1 $ t2          => collect_term_axioms
   948       | t1 $ t2          => collect_term_axioms
   945         (collect_term_axioms (axs, t1), t2)
   949         (collect_term_axioms (axs, t1), t2)
   946     (* Term.term list *)
   950     (* Term.term list *)
   947     val result = map close_form (collect_term_axioms ([], t))
   951     val result = map close_form (collect_term_axioms ([], t))
   948     val _ = writeln " ...done."
   952     val _ = Output.tracing " ...done."
   949   in
   953   in
   950     result
   954     result
   951   end;
   955   end;
   952 
   956 
   953 (* ------------------------------------------------------------------------- *)
   957 (* ------------------------------------------------------------------------- *)
  1153 (* negate    : if true, find a model that makes 't' false (rather than true) *)
  1157 (* negate    : if true, find a model that makes 't' false (rather than true) *)
  1154 (* ------------------------------------------------------------------------- *)
  1158 (* ------------------------------------------------------------------------- *)
  1155 
  1159 
  1156   (* theory -> params -> Term.term -> bool -> unit *)
  1160   (* theory -> params -> Term.term -> bool -> unit *)
  1157 
  1161 
  1158   fun find_model thy {sizes, minsize, maxsize, maxvars, maxtime, satsolver} t
  1162   fun find_model thy {sizes, minsize, maxsize, maxvars, maxtime, satsolver,
  1159     negate =
  1163     expect} t negate =
  1160   let
  1164   let
  1161     (* unit -> unit *)
  1165     (* unit -> unit *)
  1162     fun wrapper () =
  1166     fun wrapper () =
  1163     let
  1167     let
  1164       val u      = unfold_defs thy t
  1168       val u      = unfold_defs thy t
  1165       val _      = writeln ("Unfolded term: " ^ Syntax.string_of_term_global thy u)
  1169       val _      = Output.tracing ("Unfolded term: " ^
       
  1170                                    Syntax.string_of_term_global thy u)
  1166       val axioms = collect_axioms thy u
  1171       val axioms = collect_axioms thy u
  1167       (* Term.typ list *)
  1172       (* Term.typ list *)
  1168       val types = Library.foldl (fn (acc, t') =>
  1173       val types = Library.foldl (fn (acc, t') =>
  1169         acc union (ground_types thy t')) ([], u :: axioms)
  1174         acc union (ground_types thy t')) ([], u :: axioms)
  1170       val _     = writeln ("Ground types: "
  1175       val _     = Output.tracing ("Ground types: "
  1171         ^ (if null types then "none."
  1176         ^ (if null types then "none."
  1172            else commas (map (Syntax.string_of_typ_global thy) types)))
  1177            else commas (map (Syntax.string_of_typ_global thy) types)))
  1173       (* we can only consider fragments of recursive IDTs, so we issue a  *)
  1178       (* we can only consider fragments of recursive IDTs, so we issue a  *)
  1174       (* warning if the formula contains a recursive IDT                  *)
  1179       (* warning if the formula contains a recursive IDT                  *)
  1175       (* TODO: no warning needed for /positive/ occurrences of IDTs       *)
  1180       (* TODO: no warning needed for /positive/ occurrences of IDTs       *)
  1176       val _ = if Library.exists (fn
  1181       val maybe_spurious = Library.exists (fn
  1177           Type (s, _) =>
  1182           Type (s, _) =>
  1178           (case DatatypePackage.get_datatype thy s of
  1183           (case DatatypePackage.get_datatype thy s of
  1179             SOME info =>  (* inductive datatype *)
  1184             SOME info =>  (* inductive datatype *)
  1180             let
  1185             let
  1181               val index           = #index info
  1186               val index           = #index info
  1185               (* recursive datatype? *)
  1190               (* recursive datatype? *)
  1186               Library.exists (fn (_, ds) =>
  1191               Library.exists (fn (_, ds) =>
  1187                 Library.exists DatatypeAux.is_rec_type ds) constrs
  1192                 Library.exists DatatypeAux.is_rec_type ds) constrs
  1188             end
  1193             end
  1189           | NONE => false)
  1194           | NONE => false)
  1190         | _ => false) types then
  1195         | _ => false) types
       
  1196       val _ = if maybe_spurious then
  1191           warning ("Term contains a recursive datatype; "
  1197           warning ("Term contains a recursive datatype; "
  1192             ^ "countermodel(s) may be spurious!")
  1198             ^ "countermodel(s) may be spurious!")
  1193         else
  1199         else
  1194           ()
  1200           ()
  1195       (* (Term.typ * int) list -> unit *)
  1201       (* (Term.typ * int) list -> string *)
  1196       fun find_model_loop universe =
  1202       fun find_model_loop universe =
  1197       let
  1203       let
  1198         val init_model = (universe, [])
  1204         val init_model = (universe, [])
  1199         val init_args  = {maxvars = maxvars, def_eq = false, next_idx = 1,
  1205         val init_args  = {maxvars = maxvars, def_eq = false, next_idx = 1,
  1200           bounds = [], wellformed = True}
  1206           bounds = [], wellformed = True}
  1201         val _          = Output.immediate_output ("Translating term (sizes: "
  1207         val _          = Output.tracing ("Translating term (sizes: "
  1202           ^ commas (map (fn (_, n) => string_of_int n) universe) ^ ") ...")
  1208           ^ commas (map (fn (_, n) => string_of_int n) universe) ^ ") ...")
  1203         (* translate 'u' and all axioms *)
  1209         (* translate 'u' and all axioms *)
  1204         val ((model, args), intrs) = Library.foldl_map (fn ((m, a), t') =>
  1210         val ((model, args), intrs) = Library.foldl_map (fn ((m, a), t') =>
  1205           let
  1211           let
  1206             val (i, m', a') = interpret thy m a t'
  1212             val (i, m', a') = interpret thy m a t'
  1214         (* add the well-formedness side condition                       *)
  1220         (* add the well-formedness side condition                       *)
  1215         val fm_u  = (if negate then toFalse else toTrue) (hd intrs)
  1221         val fm_u  = (if negate then toFalse else toTrue) (hd intrs)
  1216         val fm_ax = PropLogic.all (map toTrue (tl intrs))
  1222         val fm_ax = PropLogic.all (map toTrue (tl intrs))
  1217         val fm    = PropLogic.all [#wellformed args, fm_ax, fm_u]
  1223         val fm    = PropLogic.all [#wellformed args, fm_ax, fm_u]
  1218       in
  1224       in
  1219         Output.immediate_output " invoking SAT solver...";
  1225         Output.priority "Invoking SAT solver...";
  1220         (case SatSolver.invoke_solver satsolver fm of
  1226         (case SatSolver.invoke_solver satsolver fm of
  1221           SatSolver.SATISFIABLE assignment =>
  1227           SatSolver.SATISFIABLE assignment =>
  1222           (writeln " model found!";
  1228           (Output.priority ("*** Model found: ***\n" ^ print_model thy model
  1223           writeln ("*** Model found: ***\n" ^ print_model thy model
  1229             (fn i => case assignment i of SOME b => b | NONE => true));
  1224             (fn i => case assignment i of SOME b => b | NONE => true)))
  1230            "genuine")
  1225         | SatSolver.UNSATISFIABLE _ =>
  1231         | SatSolver.UNSATISFIABLE _ =>
  1226           (Output.immediate_output " no model exists.\n";
  1232           (Output.priority "No model exists.";
  1227           case next_universe universe sizes minsize maxsize of
  1233           case next_universe universe sizes minsize maxsize of
  1228             SOME universe' => find_model_loop universe'
  1234             SOME universe' => find_model_loop universe'
  1229           | NONE           => writeln
  1235           | NONE           => (Output.priority
  1230             "Search terminated, no larger universe within the given limits.")
  1236             "Search terminated, no larger universe within the given limits.";
       
  1237             "none"))
  1231         | SatSolver.UNKNOWN =>
  1238         | SatSolver.UNKNOWN =>
  1232           (Output.immediate_output " no model found.\n";
  1239           (Output.priority "No model found.";
  1233           case next_universe universe sizes minsize maxsize of
  1240           case next_universe universe sizes minsize maxsize of
  1234             SOME universe' => find_model_loop universe'
  1241             SOME universe' => find_model_loop universe'
  1235           | NONE           => writeln
  1242           | NONE           => (Output.priority
  1236             "Search terminated, no larger universe within the given limits.")
  1243             "Search terminated, no larger universe within the given limits.";
       
  1244             "unknown"))
  1237         ) handle SatSolver.NOT_CONFIGURED =>
  1245         ) handle SatSolver.NOT_CONFIGURED =>
  1238           error ("SAT solver " ^ quote satsolver ^ " is not configured.")
  1246           (error ("SAT solver " ^ quote satsolver ^ " is not configured.");
       
  1247            "unknown")
  1239       end handle MAXVARS_EXCEEDED =>
  1248       end handle MAXVARS_EXCEEDED =>
  1240         writeln ("\nSearch terminated, number of Boolean variables ("
  1249         (Output.priority ("Search terminated, number of Boolean variables ("
  1241           ^ string_of_int maxvars ^ " allowed) exceeded.")
  1250           ^ string_of_int maxvars ^ " allowed) exceeded.");
       
  1251           "unknown")
       
  1252         val outcome_code = find_model_loop (first_universe types sizes minsize)
  1242       in
  1253       in
  1243         find_model_loop (first_universe types sizes minsize)
  1254         if expect = "" orelse outcome_code = expect then ()
       
  1255         else error ("Unexpected outcome: " ^ quote outcome_code ^ ".")
  1244       end
  1256       end
  1245     in
  1257     in
  1246       (* some parameter sanity checks *)
  1258       (* some parameter sanity checks *)
  1247       minsize>=1 orelse
  1259       minsize>=1 orelse
  1248         error ("\"minsize\" is " ^ string_of_int minsize ^ ", must be at least 1");
  1260         error ("\"minsize\" is " ^ string_of_int minsize ^ ", must be at least 1");
  1254       maxvars>=0 orelse
  1266       maxvars>=0 orelse
  1255         error ("\"maxvars\" is " ^ string_of_int maxvars ^ ", must be at least 0");
  1267         error ("\"maxvars\" is " ^ string_of_int maxvars ^ ", must be at least 0");
  1256       maxtime>=0 orelse
  1268       maxtime>=0 orelse
  1257         error ("\"maxtime\" is " ^ string_of_int maxtime ^ ", must be at least 0");
  1269         error ("\"maxtime\" is " ^ string_of_int maxtime ^ ", must be at least 0");
  1258       (* enter loop with or without time limit *)
  1270       (* enter loop with or without time limit *)
  1259       writeln ("Trying to find a model that "
  1271       Output.priority ("Trying to find a model that "
  1260         ^ (if negate then "refutes" else "satisfies") ^ ": "
  1272         ^ (if negate then "refutes" else "satisfies") ^ ": "
  1261         ^ Syntax.string_of_term_global thy t);
  1273         ^ Syntax.string_of_term_global thy t);
  1262       if maxtime>0 then (
  1274       if maxtime>0 then (
  1263         TimeLimit.timeLimit (Time.fromSeconds maxtime)
  1275         TimeLimit.timeLimit (Time.fromSeconds maxtime)
  1264           wrapper ()
  1276           wrapper ()
  1265         handle TimeLimit.TimeOut =>
  1277         handle TimeLimit.TimeOut =>
  1266           writeln ("\nSearch terminated, time limit (" ^ string_of_int maxtime
  1278           Output.priority ("Search terminated, time limit (" ^
       
  1279             string_of_int maxtime
  1267             ^ (if maxtime=1 then " second" else " seconds") ^ ") exceeded.")
  1280             ^ (if maxtime=1 then " second" else " seconds") ^ ") exceeded.")
  1268       ) else
  1281       ) else
  1269         wrapper ()
  1282         wrapper ()
  1270     end;
  1283     end;
  1271 
  1284