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 |