1(* ========================================================================= *) 2(* A HOL INTERFACE TO THE METIS FIRST-ORDER PROVER. *) 3(* Created by Joe Hurd, October 2001 *) 4(* ========================================================================= *) 5 6(* 7app load ["mlibUseful", "mlibMetis", "folTools"]; 8*) 9 10(* 11*) 12structure metisTools :> metisTools = 13struct 14 15open HolKernel Parse boolLib folTools folMapping; 16 17(* ------------------------------------------------------------------------- *) 18(* Chatting and error handling. *) 19(* ------------------------------------------------------------------------- *) 20 21(* "Metis" trace levels: 22 0: No output 23 1: The equivalent of Meson dots 24 2: Timing information 25 3: More detailed prover information: slice by slice 26 4: Log of each step in proof translation 27 5: Log of each inference during proof search *) 28 29local 30 open mlibUseful; 31 val module = "metisTools"; 32 val aligned_traces = 33 [{module = "mlibClause", alignment = fn n => n + 4}, 34 {module = "mlibSolver", alignment = I}, 35 {module = "mlibMeson", alignment = I}, 36 {module = "mlibClauseset", alignment = I}, 37 {module = "mlibSupport", alignment = I}, 38 {module = "mlibResolution", alignment = I}, 39 {module = "folMapping", alignment = fn n => n + 3}, 40 {module = "folTools", alignment = I}, 41 {module = "metisTools", alignment = I}, 42 {module = "metisLib", alignment = I}]; 43 val () = register_trace ("metis", trace_level, 10) 44 val () = trace_level := (if !Globals.interactive then 1 else 0) (* OK *) 45 val () = set_traces aligned_traces 46in 47 fun chatting l = tracing {module = module, level = l}; 48 fun chat s = (trace s; true) 49 val ERR = mk_HOL_ERR module; 50 fun BUG f m = Bug (f ^ ": " ^ m); 51end; 52 53(* ------------------------------------------------------------------------- *) 54(* Making the Metis prover HOL specific. *) 55(* ------------------------------------------------------------------------- *) 56 57fun bool_map ":" = SOME "fst" (* Force types to be ignored in the model *) 58 | bool_map "combin.I" = SOME "id" 59 | bool_map "pair.FST" = SOME "id" 60 | bool_map "pair.," = SOME "fst" 61 | bool_map _ = NONE; 62 63fun num_map "num.0" = SOME "0" 64 | num_map "num.SUC" = SOME "suc" 65 | num_map "prim_rec.PRE" = SOME "pre" 66 | num_map "arithmetic.+" = SOME "+" 67 | num_map "arithmetic.-" = SOME "-" 68 | num_map "arithmetic.*" = SOME "*" 69 | num_map "arithmetic.EXP" = SOME "exp" 70 | num_map "arithmetic.MOD" = SOME "mod" 71 | num_map "arithmetic.<=" = SOME "<=" 72 | num_map "prim_rec.<" = SOME "<" 73 | num_map "arithmetic.>" = SOME ">" 74 | num_map "arithmetic.>=" = SOME ">=" 75 | num_map "divides.divides" = SOME "divides" 76 | num_map "arithmetic.ODD" = SOME "odd" 77 | num_map "arithmetic.EVEN" = SOME "even" 78 | num_map "arithmetic.NUMERAL" = SOME "id" 79 | num_map "arithmetic.ALT_ZERO" = SOME "0" 80 | num_map "arithmetic.NUMERAL_BIT1" = SOME "BIT1" 81 | num_map "arithmetic.NUMERAL_BIT2" = SOME "BIT2" 82 | num_map _ = NONE; 83 84fun holify_num fix N = 85 let 86 val {func,pred} = fix N 87 val funk = partial (BUG "holify_num" "missing function alert!") func 88 val one = funk ("1",[]) and two = funk ("2",[]) 89 fun func' ("BIT1",[m]) = SOME (funk ("+", [funk ("*",[two,m]), one])) 90 | func' ("BIT2",[m]) = SOME (funk ("+", [funk ("*",[two,m]), two])) 91 | func' x = func x 92 in 93 {func = func', pred = pred} 94 end; 95 96fun int_map "integer.int_neg" = SOME "~" 97 | int_map "integer.int_add" = SOME "+" 98 | int_map "integer.int_sub" = SOME "-" 99 | int_map "integer.int_mul" = SOME "*" 100 | int_map "integer.int_exp" = SOME "exp" 101 | int_map "integer.int_le" = SOME "<=" 102 | int_map "integer.int_lt" = SOME "<" 103 | int_map "integer.int_gt" = SOME ">" 104 | int_map "integer.int_ge" = SOME ">=" 105 | int_map "integer.int_of_num" = SOME "id" 106 | int_map _ = NONE; 107 108fun list_map "list.NIL" = SOME "0" 109 | list_map "list.CONS" = SOME "suc" 110 | list_map "list.TL" = SOME "pre" 111 | list_map "list.APPEND" = SOME "+" 112 | list_map "list.NULL" = SOME "is_0" 113 | list_map "list.LENGTH" = SOME "id" 114 | list_map _ = NONE; 115 116fun set_map "pred_set.EMPTY" = SOME "empty" 117 | set_map "pred_set.UNIV" = SOME "univ" 118 | set_map "pred_set.UNION" = SOME "union" 119 | set_map "pred_set.INTER" = SOME "inter" 120 | set_map "pred_set.COMPL" = SOME "compl" 121 | set_map "pred_set.CARD" = SOME "card" 122 | set_map "bool.IN" = SOME "in" 123 | set_map "pred_set.SUBSET" = SOME "subset" 124 | set_map _ = NONE; 125 126val modulo_basic_fix = 127 mlibModel.fix_merge mlibModel.modulo_fix mlibModel.basic_fix; 128 129val hol_fix = mlibModel.fix_mergel 130 [mlibModel.pure_fix, 131 mlibModel.map_fix bool_map mlibModel.basic_fix, 132 mlibModel.map_fix num_map (holify_num modulo_basic_fix), 133 mlibModel.map_fix int_map modulo_basic_fix, 134 mlibModel.map_fix list_map modulo_basic_fix, 135 mlibModel.map_fix set_map mlibModel.set_fix]; 136 137local 138 val METIS_PROVER = [mlibMetis.ordered_resolution]; 139 val MODEL_SIZE = 8; 140 val MODEL_PERTS = 5; 141 142 fun hol_parm n = 143 (mlibModel.update_fix (K hol_fix) o 144 mlibModel.update_size (K n)) mlibModel.defaults; 145 146 fun holify_res ms = 147 mlibResolution.update_sos_parm 148 (mlibSupport.update_model_perts (K MODEL_PERTS) o 149 mlibSupport.update_model_parms (K ms)); 150 151 fun holify ms (mlibMetis.mlibResolution r, f, c) = 152 (mlibMetis.mlibResolution (holify_res ms r), f, c) 153 | holify _ x = x; 154 155 fun update_models ms = map (holify ms) METIS_PROVER; 156in 157 val fo_solver = update_models [hol_parm MODEL_SIZE]; 158 val ho_solver = update_models []; 159end; 160 161(* ------------------------------------------------------------------------- *) 162(* Parameters. *) 163(* ------------------------------------------------------------------------- *) 164 165type Fparm = folTools.parameters; 166type Mparm = mlibMetis.parameters; 167type parameters = {interface : Fparm, solver : Mparm, limit : limit}; 168 169val defaults = 170 {interface = folTools.defaults, 171 limit = mlibMeter.unlimited, 172 solver = fo_solver}; 173 174fun update_interface f {interface, solver, limit} = 175 {interface = f interface, solver = solver, limit = limit}; 176 177fun update_solver f {interface, solver, limit} = 178 {interface = interface, solver = f solver, limit = limit}; 179 180fun update_limit f {interface, solver, limit} = 181 {interface = interface, solver = solver, limit = f limit}; 182 183(* ------------------------------------------------------------------------- *) 184(* Helper functions. *) 185(* ------------------------------------------------------------------------- *) 186 187fun timed_fn s f a = 188 let 189 val (t, r) = mlibUseful.timed f a 190 val _ = chatting 2 andalso chat 191 ("metis: " ^ s ^ " time: " ^ mlibUseful.real_to_string t ^ "\n") 192 in 193 r 194 end; 195 196fun contains s = 197 let 198 fun g [] _ = true | g _ [] = false | g (a::b) (c::d) = a = c andalso g b d 199 val k = explode s 200 fun f [] = false | f (l as _ :: ys) = g k l orelse f ys 201 in 202 f o explode 203 end; 204 205fun const_scheme c = 206 let val {Thy, Name, ...} = dest_thy_const c 207 in prim_mk_const {Name = Name, Thy = Thy} 208 end; 209 210fun trap f g x = 211 f x 212 handle e as HOL_ERR {message, ...} => 213 (if not (contains "proof translation error" message) then raise e else 214 (chatting 1 andalso 215 chat "metis: proof translation error: trying again with types.\n"; 216 g x)); 217 218(* ------------------------------------------------------------------------- *) 219(* Prolog solver. *) 220(* ------------------------------------------------------------------------- *) 221 222local 223 val prolog_parm = 224 {equality = false, 225 boolean = false, 226 combinator = false, 227 mapping_parm = {higher_order = false, with_types = true}}; 228in 229 fun PROLOG_SOLVE ths = 230 let 231 val _ = (chatting 1 andalso chat "prolog: "; chatting 2 andalso chat "\n") 232 val (cs,ths) = FOL_NORM ths 233 val lmap = build_map (prolog_parm,cs,ths) 234 in 235 FOL_SOLVE mlibMeson.prolog lmap mlibMeter.unlimited 236 end; 237end; 238 239(* ------------------------------------------------------------------------- *) 240(* Metis solver. *) 241(* ------------------------------------------------------------------------- *) 242 243fun GEN_METIS_SOLVE parm ths = 244 let 245 val {interface, solver, limit, ...} : parameters = parm 246 val _ = (chatting 1 andalso chat "metis solver: "; 247 chatting 2 andalso chat "\n") 248 val (cs,ths) = FOL_NORM ths 249 val lmap = build_map (interface,cs,ths) 250 in 251 FOL_SOLVE (mlibMetis.metis' solver) lmap limit 252 end; 253 254(* ------------------------------------------------------------------------- *) 255(* Tactic interface to the metis prover. *) 256(* ------------------------------------------------------------------------- *) 257 258fun X_METIS_TAC ttac ths goal = 259 (chatting 1 andalso chat "metis: "; chatting 2 andalso chat "\n"; 260 FOL_NORM_TTAC ttac ths goal); 261 262fun GEN_METIS_TTAC parm (cs,ths) = 263 let 264 val {interface, solver, limit, ...} : parameters = parm 265 val lmap = timed_fn "logic map build" build_map (interface,cs,ths) 266 in 267 FOL_TACTIC (mlibMetis.metis' solver) lmap limit 268 end; 269 270val GEN_METIS_TAC = X_METIS_TAC o GEN_METIS_TTAC; 271 272(* ------------------------------------------------------------------------- *) 273(* All the following use this limit. *) 274(* ------------------------------------------------------------------------- *) 275 276val limit : limit ref = ref (#limit defaults); 277 278(* ------------------------------------------------------------------------- *) 279(* Canned parameters for common situations. *) 280(* ------------------------------------------------------------------------- *) 281 282fun inc_limit p = update_limit (K (!limit)) p; 283fun set_limit f p t g = f (inc_limit p) t g; 284 285(* First-order *) 286 287val fo_parm = 288 update_interface 289 (update_mapping_parm (K {higher_order = false, with_types = false})) 290 (update_solver (K fo_solver) defaults); 291 292val fot_parm = 293 update_interface (update_mapping_parm (update_with_types (K true))) fo_parm; 294 295val FOT_METIS_TTAC = set_limit GEN_METIS_TTAC fot_parm; 296 297fun FO_METIS_TTAC ths = 298 trap (set_limit GEN_METIS_TTAC fo_parm ths) (FOT_METIS_TTAC ths); 299 300(* Higher-order *) 301 302val ho_parm = 303 update_interface 304 (update_mapping_parm (K {higher_order = true, with_types = false})) 305 (update_solver (K ho_solver) defaults); 306 307val hot_parm = 308 update_interface (update_mapping_parm (update_with_types (K true))) ho_parm; 309 310val HOT_METIS_TTAC = set_limit GEN_METIS_TTAC hot_parm; 311 312fun HO_METIS_TTAC ths = 313 trap (set_limit GEN_METIS_TTAC ho_parm ths) (HOT_METIS_TTAC ths); 314 315(* Higher-order with rules for combinator reductions and booleans *) 316 317val full_parm = 318 (update_interface (update_combinator (K true) o update_boolean (K true))) 319 hot_parm; 320 321val FULL_METIS_TTAC = set_limit GEN_METIS_TTAC full_parm; 322 323(* ------------------------------------------------------------------------- *) 324(* Canned tactics. *) 325(* ------------------------------------------------------------------------- *) 326 327val FO_METIS_TAC = X_METIS_TAC FO_METIS_TTAC; 328val FOT_METIS_TAC = X_METIS_TAC FOT_METIS_TTAC; 329val HO_METIS_TAC = X_METIS_TAC HO_METIS_TTAC; 330val HOT_METIS_TAC = X_METIS_TAC HOT_METIS_TTAC; 331val FULL_METIS_TAC = X_METIS_TAC FULL_METIS_TTAC; 332 333(* ------------------------------------------------------------------------- *) 334(* Simple user interface to the metis prover. *) 335(* ------------------------------------------------------------------------- *) 336 337fun prover ttac ths goal = Tactical.default_prover (goal, ttac ths); 338 339val FO_METIS_PROVE = prover FO_METIS_TAC; 340val FOT_METIS_PROVE = prover FOT_METIS_TAC; 341val HO_METIS_PROVE = prover HO_METIS_TAC; 342val HOT_METIS_PROVE = prover HOT_METIS_TAC; 343val FULL_METIS_PROVE = prover FULL_METIS_TAC; 344 345(* ------------------------------------------------------------------------- *) 346(* Uses heuristics to apply one of FO_, HO_ or FULL_. *) 347(* ------------------------------------------------------------------------- *) 348 349datatype class = First | Higher | Full; 350 351fun class_str First = "first-order" 352 | class_str Higher = "higher-order" 353 | class_str Full = "higher-order + combinators"; 354 355fun class_tac First = FO_METIS_TTAC 356 | class_tac Higher = HO_METIS_TTAC 357 | class_tac Full = FULL_METIS_TTAC; 358 359local 360 fun mk_set ts = Binaryset.addList (Binaryset.empty compare, ts); 361 fun member x s = Binaryset.member (s,x); 362 363 val empty : (term, bool * int) Binarymap.dict = Binarymap.mkDict compare; 364 fun update ts x n = Binarymap.insert (ts,x,n); 365 fun lookup ts x = Binarymap.peek (ts,x); 366 367 fun bump Full _ = Full 368 | bump Higher Full = Full 369 | bump Higher _ = Higher 370 | bump First cl = cl; 371 372 fun ord _ [] state = state 373 | ord top (tm :: tms) (c,g,l,t,v) = 374 let 375 val (f,xs) = strip_comb tm 376 val f = if is_const f then const_scheme f else f 377 val n = length xs 378 val tn = (top,n) 379 val tms = xs @ tms 380 in 381 ord false tms 382 (if member f v then 383 ((if n <> 0 orelse top then bump Higher c else c), g, l, t, v) 384 else if member f t then 385 (case lookup l f of NONE => (c, g, update l f tn, t, v) 386 | SOME tn' => ((if tn = tn' then c else bump Higher c), g, l, t, v)) 387 else 388 (case lookup g f of NONE => (c, update g f tn, l, t, v) 389 | SOME tn' => ((if tn = tn' then c else bump Higher c), g, l, t, v))) 390 end; 391 392 fun order_lit [] state = state 393 | order_lit (lit :: lits) (state as (c,g,l,t,v)) = 394 let 395 val atom = case total dest_neg lit of NONE => lit | SOME lit => lit 396 in 397 order_lit lits (ord true [atom] state) 398 end; 399 400 fun order_cl (cl,gs,_,_,_) [] = (cl,gs) 401 | order_cl state (fm :: fms) = 402 order_cl (order_lit (strip_disj fm) state) fms; 403 404 fun order (cl,_) [] = cl 405 | order (cl,cs) (fm :: fms) = 406 let 407 val (ts,fm) = strip_exists fm 408 val (vs,fm) = strip_forall fm 409 val cls = strip_conj fm 410 in 411 order (order_cl (cl, cs, empty, mk_set ts, mk_set vs) cls) fms 412 end; 413in 414 fun classify fms = order (First,empty) fms 415 handle HOL_ERR _ => raise BUG "metisTools.classify" "shouldn't fail"; 416end; 417 418fun METIS_TTAC (cs,ths) = 419 let 420 val class = timed_fn "problem classification" classify (map concl ths) 421 val _ = chatting 2 andalso 422 chat ("metis: a " ^ class_str class ^ " problem.\n") 423 in 424 class_tac class (cs,ths) 425 end; 426 427val METIS_TAC = X_METIS_TAC METIS_TTAC; 428 429(* 430val METIS_TAC = fn ths => fn goal => 431 let 432 val met = Count.mk_meter () 433 val _ = chat "\nMETIS_TAC: new\n" 434 val res = METIS_TAC ths goal 435 val {prims,...} = Count.read met 436 val _ = chat ("METIS_TAC: " ^ Int.toString prims ^ "\n") 437 in 438 res 439 end; 440*) 441 442val METIS_PROVE = prover METIS_TAC; 443 444end 445