1(****************************************************************************) 2(* Copyright (C) 2007-2009 Gacek *) 3(* Copyright (C) 2013-2018 Inria (Institut National de Recherche *) 4(* en Informatique et en Automatique) *) 5(* *) 6(* This file is part of Abella. *) 7(* *) 8(* Abella is free software: you can redistribute it and/or modify *) 9(* it under the terms of the GNU General Public License as published by *) 10(* the Free Software Foundation, either version 3 of the License, or *) 11(* (at your option) any later version. *) 12(* *) 13(* Abella is distributed in the hope that it will be useful, *) 14(* but WITHOUT ANY WARRANTY; without even the implied warranty of *) 15(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *) 16(* GNU General Public License for more details. *) 17(* *) 18(* You should have received a copy of the GNU General Public License *) 19(* along with Abella. If not, see <http://www.gnu.org/licenses/>. *) 20(****************************************************************************) 21 22open Term 23open Typing 24open Metaterm 25open Format 26open Tactics 27open Checks 28open Abella_types 29open Extensions 30open Unifyty 31 32module H = Hashtbl 33 34let lemmas : (string, string list * metaterm) H.t = State.table () 35 36type subgoal = unit -> unit 37let subgoals : subgoal list ref = State.rref [] 38 39type hyp = { 40 id : id ; 41 term : metaterm ; 42 abbrev : string option ; 43} 44 45type sequent = { 46 mutable vars : (id * term) list ; 47 mutable hyps : hyp list ; 48 mutable goal : metaterm ; 49 mutable count : int ; 50 mutable name : string ; 51 mutable next_subgoal_id : int ; 52} 53 54(* The vars = sq.vars is superfluous, but forces the copy *) 55let cp_sequent sq = {sq with vars = sq.vars} 56let assign_sequent sq1 sq2 = 57 sq1.vars <- sq2.vars ; 58 sq1.hyps <- sq2.hyps ; 59 sq1.goal <- sq2.goal ; 60 sq1.count <- sq2.count ; 61 sq1.name <- sq2.name ; 62 sq1.next_subgoal_id <- sq2.next_subgoal_id 63 64let sequent = 65 State.make ~copy:cp_sequent ~assign:assign_sequent { 66 vars = [] ; 67 hyps = [] ; 68 goal = termobj (const "placeholder" propty) ; 69 count = 0 ; 70 name = "" ; 71 next_subgoal_id = 1 ; 72 } 73 74let add_global_types tys knd = 75 sign := add_types !sign tys knd 76 77let locally_add_global_consts cs = 78 let local_sr = List.fold_left Subordination.update !sr (List.map snd cs) 79 and local_sign = add_consts !sign cs 80 in (local_sr, local_sign) 81 82let commit_global_consts local_sr local_sign = 83 sr := local_sr ; 84 sign := local_sign 85 86let add_global_consts cs = 87 sr := List.fold_left Subordination.update !sr (List.map snd cs) ; 88 sign := add_consts !sign cs 89 90let close_types sign clauses atys = 91 List.iter (kind_check sign) (List.map tybase atys); 92 let tys = List.map tybase atys in 93 begin match List.intersect [oty; olistty; propty] tys with 94 | [] -> () 95 | xs -> failwithf "Cannot close %s" 96 (String.concat ", " (List.map ty_to_string xs)) 97 end ; 98 sr := Subordination.close !sr atys; 99 List.iter (Typing.term_ensure_subordination !sr) (List.map snd clauses) 100 101let add_subgoals ?(mainline) new_subgoals = 102 let extend_name i = 103 if sequent.name = "" then 104 sequent.name <- string_of_int i 105 else 106 sequent.name <- sequent.name ^ "." ^ (string_of_int i) 107 in 108 let rec annotate i gs = 109 match gs with 110 | [] -> [] 111 | g::rest -> 112 (fun () -> g (); extend_name i; sequent.next_subgoal_id <- 1) :: 113 annotate (i+1) rest 114 in 115 let n = List.length new_subgoals in 116 let annotated_subgoals = 117 match mainline with 118 | None -> 119 if n > 1 then 120 annotate sequent.next_subgoal_id new_subgoals 121 else 122 new_subgoals 123 | Some mainline -> 124 let new_mainline () = 125 mainline () ; 126 sequent.next_subgoal_id <- sequent.next_subgoal_id + n 127 in 128 annotate sequent.next_subgoal_id new_subgoals @ [new_mainline] 129 in 130 subgoals := annotated_subgoals @ !subgoals 131 132let copy_sequent () = cp_sequent sequent 133let set_sequent other = assign_sequent sequent other 134 135let fresh_hyp_name base = 136 if base = "" then begin 137 sequent.count <- sequent.count + 1 ; 138 "H" ^ (string_of_int sequent.count) 139 end else 140 fresh_name base (List.map (fun h -> (h.id, ())) sequent.hyps) 141 142(* let normalize mt = *) 143(* let before = metaterm_to_string mt in *) 144(* Printf.fprintf stderr "normalizing\n%s\n%!" before ; *) 145(* let mt = normalize mt in *) 146(* let after = metaterm_to_string mt in *) 147(* Printf.fprintf stderr "normalized form\n%s\n%!" after ; *) 148(* mt *) 149 150let normalize_sequent () = 151 (* Printf.fprintf stderr "Normalizing Sequent %s\n%!" sequent.name ; *) 152 sequent.goal <- normalize sequent.goal ; 153 sequent.hyps <- 154 sequent.hyps |> List.map (fun h -> { h with term = normalize h.term }) 155 156(* Clauses *) 157 158let clauses : clause list ref = State.rref [] 159 160let add_clauses new_clauses = 161 clauses := !clauses @ new_clauses 162 163let parse_defs ?(sign = !sign) str = 164 Lexing.from_string str |> 165 Parser.defs Lexer.token |> 166 type_udefs ~sr:!sr ~sign |> 167 List.map (fun (head, body) -> {head ; body}) 168 169let defs_table : defs_table = State.table () 170 171let built_ins_done = ref false 172 173let add_defs typarams preds flavor clauses = 174 List.iter begin fun (id, _) -> 175 if H.mem defs_table id then 176 failwithf "Predicate %s has already been defined" id ; 177 end preds ; 178 (* List.iter begin fun (head, body) -> *) 179 (* Format.eprintf "%a := %a@." format_metaterm head format_metaterm body *) 180 (* end defs ; *) 181 let mutual = List.fold_left begin fun mutual (id, ty) -> 182 Itab.add id ty mutual 183 end Itab.empty preds in 184 let def = {flavor ; typarams ; mutual ; clauses} in 185 Checks.check_def ~def ; 186 List.iter (fun (id, _) -> H.add defs_table id def) preds 187 188let lookup_poly_const k = 189 try let Poly (typarams, ty) = List.assoc k (snd !sign) in (typarams, ty) with 190 | Not_found -> failwithf "Unknown constant: %S" k 191 192 193let register_definition = function 194 | Define (flav, idtys, udefs) -> 195 let typarams = List.unique (idtys |> List.map snd |> get_typarams) in 196 check_typarams typarams (List.map snd idtys); 197 let ids = List.map fst idtys in 198 check_noredef ids; 199 let (basics, consts) = !sign in 200 (* Note that in order to type check the definitions, the types 201 of predicates being defined are fixed to their most generate 202 form by fixing the type variables in them to generic ones *) 203 let consts = List.map (fun (id, ty) -> (id, Poly ([], ty))) idtys @ consts in 204 let clauses = type_udefs ~sr:!sr ~sign:(basics, consts) udefs |> 205 List.map (fun (head, body) -> {head ; body}) in 206 ensure_no_schm_clauses typarams clauses; 207 let (basics, consts) = !sign in 208 let consts = List.map (fun (id, ty) -> (id, Poly (typarams, ty))) idtys @ consts in 209 sign := (basics, consts) ; 210 add_defs typarams idtys flav clauses ; 211 CDefine (flav, typarams, idtys, clauses) 212 | _ -> bugf "Not a definition!" 213 214let parse_definition str = 215 Lexing.from_string str |> 216 Parser.top_command Lexer.token |> 217 register_definition 218 219let k_member = "member" 220let member_def_compiled = 221 "Define " ^ k_member ^ " : A -> list A -> prop by\ 222 \ " ^ k_member ^ " A (A :: L) ; \ 223 \ " ^ k_member ^ " A (B :: L) := " ^ k_member ^ " A L." |> 224 parse_definition 225 226let () = built_ins_done := true 227 228let term_spine t = 229 match term_head t with 230 | Some (_, spine) -> spine 231 | None -> assert false 232 233let clause_head_name cl = 234 match cl.head with 235 | Binding (Nabla, _, Pred (p, _)) | Pred (p, _) -> 236 term_head_name p 237 | _ -> bugf "Clause head name for invalid clause: %s" (metaterm_to_string cl.head) 238 239(* let rec app_ty tymap = function 240 * | Ty (args, res) -> 241 * let args = List.map (app_ty tymap) args in 242 * let res = try Itab.find res tymap with Not_found -> tybase res in 243 * tyarrow args res *) 244 245(* let instantiate_clauses_aux = 246 * let fn (pn, ty_acts) def = 247 * let Ty (ty_exps, _) = Itab.find pn def.mutual in 248 * let ty_fresh = List.fold_left begin fun fresh_sub tyvar -> 249 * let tv = Term.fresh_tyvar () in 250 * Itab.add tyvar tv fresh_sub 251 * end Itab.empty def.typarams in 252 * let ty_exps = List.map (app_ty ty_fresh) ty_exps in 253 * let eqns = List.map2 begin fun ty_exp ty_act -> 254 * (ty_exp, ty_act, (ghost, CArg)) 255 * end ty_exps ty_acts in 256 * let tysol = unify_constraints eqns in 257 * let tymap = List.fold_left begin fun tymap tyv -> 258 * try begin 259 * let Ty (_, tyf) = Itab.find tyv ty_fresh in 260 * Itab.add tyv (List.assoc tyf tysol) tymap 261 * end with Not_found -> tymap 262 * end Itab.empty def.typarams in 263 * (\* Itab.iter begin fun v ty -> *\) 264 * (\* Format.eprintf "instantiating: %s <- %s@." v (ty_to_string ty) *\) 265 * (\* end tymap ; *\) 266 * List.map begin fun cl -> 267 * if clause_head_name cl = pn then 268 * {head = map_on_tys (app_ty tymap) cl.head ; 269 * body = map_on_tys (app_ty tymap) cl.body} 270 * else cl 271 * end def.clauses 272 * in 273 * memoize fn *) 274 275(* let instantiate_clauses pn def args = 276 * let ty_acts = List.map (tc []) args in 277 * instantiate_clauses_aux (pn, ty_acts) def *) 278 279let instantiate_pred_types tysub (tbl: ty Itab.t) : ty Itab.t = 280 let res = ref Itab.empty in 281 Itab.iter begin fun id ty -> 282 let ty' = apply_sub_ty tysub ty in 283 res := Itab.add id ty' !res 284 end tbl; 285 !res 286 287let instantiate_clause tysub cl = 288 let head = map_on_tys (apply_sub_ty tysub) cl.head in 289 let body = map_on_tys (apply_sub_ty tysub) cl.body in 290 {head = head; body = body} 291 292let instantiate_clauses p def = 293 let pn = term_head_name p in 294 let pty = term_head_ty p in 295 let clauses = def.clauses in 296 let tysub = List.map (fun id -> (id, Term.fresh_tyvar ())) def.typarams in 297 let mutual = instantiate_pred_types tysub def.mutual in 298 let dpty = Itab.find pn mutual in 299 unify_constraints [(pty, dpty, def_cinfo)]; 300 assert (ty_tyvars dpty = []); 301 let clauses = List.map (instantiate_clause tysub) clauses in 302 (mutual, clauses) 303 304let def_unfold term = 305 match term with 306 | Pred(p, _) -> 307 let pn = term_head_name p in 308 if H.mem defs_table pn then begin 309 let def = H.find defs_table pn in 310 let (mutual, clauses) = instantiate_clauses p def in 311 List.iter begin fun cl -> 312 metaterm_ensure_subordination !sr cl.head ; 313 metaterm_ensure_subordination !sr cl.body 314 end clauses; 315 (mutual,clauses) 316 end else 317 failwith "Cannot perform case-analysis on undefined atom" 318 | _ -> (Itab.empty, []) 319 320 321(* Pretty print *) 322 323let sequent_var_to_string (x, _xt) = 324 x (* ^ "(=" ^ term_to_string xt ^ ")" *) 325 326let show_instantiations = State.rref false 327 328let separate_strings xs = 329 let __max_len = 30 in 330 let result = ref [] in 331 let emit xs = result := String.concat "," (List.rev xs) :: !result in 332 let rec spin nxs pos = function 333 | [] -> emit nxs 334 | x :: xs -> 335 if pos + String.length x + 1 < __max_len then 336 spin (x :: nxs) (pos + String.length x + 1) xs 337 else begin 338 emit nxs ; 339 spin [x] (String.length x) xs 340 end 341 in 342 spin [] 0 xs ; 343 List.rev !result 344 345let format_typed_vars ff (ty, xs) = 346 let open Format in 347 List.iter begin fun xs -> 348 pp_print_string ff " " ; 349 pp_print_string ff xs ; 350 pp_print_string ff " : " ; 351 pp_open_box ff 0 ; Term.format_ty ff ty ; pp_close_box ff () ; 352 pp_print_newline ff () ; 353 end (separate_strings xs) 354 355let format_vars ff = 356 let open Format in 357 let (eigen_vars, inst_vars) = 358 List.partition is_uninstantiated sequent.vars in 359 if eigen_vars <> [] then begin 360 pp_print_string ff "Variables: " ; 361 if !show_types then begin 362 pp_print_newline ff () ; 363 eigen_vars 364 |> List.map 365 (fun (x, xtm) -> (Term.tc [] xtm, x)) 366 |> List.sort 367 (fun (ty1, _) (ty2, _) -> compare ty1 ty2) 368 |> List.collate_assoc 369 |> List.iter (format_typed_vars ff) ; 370 end else begin 371 pp_open_hovbox ff 0 ; begin 372 pp_print_string ff (sequent_var_to_string (List.hd eigen_vars)) ; 373 List.iter begin 374 fun v -> 375 pp_print_space ff () ; 376 pp_print_string ff (sequent_var_to_string v) 377 end (List.tl eigen_vars) ; 378 end ; pp_close_box ff () ; 379 pp_print_newline ff () 380 end 381 end ; 382 if inst_vars <> [] && !show_instantiations then 383 List.iter begin fun (v, vtm) -> 384 pp_print_string ff v ; 385 pp_print_string ff " <-- " ; 386 Term.format_term ff vtm ; 387 pp_print_newline ff () ; 388 end inst_vars 389 390let format_hyp fmt hyp = 391 fprintf fmt "%s : " hyp.id ; 392 begin match hyp.abbrev with 393 | None -> format_metaterm fmt hyp.term 394 | Some s -> fprintf fmt "%s" s 395 end; 396 pp_force_newline fmt () 397 398let format_hyps fmt = 399 let (am, hyps) = List.fold_left begin fun (am, hs) h -> 400 match h.abbrev with 401 | None -> (am, h :: hs) 402 | Some ab -> 403 let am = match Itab.find ab am with 404 | hs -> Itab.add ab (h.id :: hs) am 405 | exception Not_found -> Itab.add ab [h.id] am 406 in 407 (am, hs) 408 end (Itab.empty, []) sequent.hyps 409 in 410 Itab.iter begin fun ab hs -> 411 fprintf fmt "%s : %s@\n" (String.concat "," (List.rev hs)) ab 412 end am ; 413 List.iter (format_hyp fmt) (List.rev hyps) 414 415let format_count_subgoals fmt n = 416 match n with 417 | 0 -> () 418 | 1 -> fprintf fmt "1 other subgoal.@\n@\n" 419 | n -> fprintf fmt "%d other subgoals.@\n@\n" n 420 421type subgoal_max = { 422 smax_default : int ; 423 smax_map : int IntMap.t ; 424} 425let subgoal_max_init = { smax_default = max_int ; 426 smax_map = IntMap.empty } 427let subgoal_max : subgoal_max ref = State.rref subgoal_max_init 428let reset_subgoal_max () = 429 subgoal_max := subgoal_max_init 430let set_subgoal_max_default smax_default = 431 let smax = !subgoal_max in 432 subgoal_max := { smax with smax_default } 433let set_subgoal_max ndps = 434 let smax = !subgoal_max in 435 let smax_map = List.fold_left begin 436 fun smax_map (dp, n) -> 437 let n = Option.default max_int n in 438 (* Printf.printf "Max subgoals at depth %d: %d\n%!" dp n ; *) 439 IntMap.add dp n smax_map 440 end smax.smax_map ndps in 441 subgoal_max := { smax with smax_map } 442 443let format_other_subgoals fmt = 444 let pristine = State.snapshot () in 445 let smax = !subgoal_max in 446 let smax_map = ref smax.smax_map in 447 let count = ref 0 in 448 List.iter begin fun set_state -> 449 set_state () ; 450 let goal_depth = String.count sequent.name '.' in 451 let max_goals = try IntMap.find goal_depth !smax_map with Not_found -> smax.smax_default in 452 (* Printf.printf "Showing %d goals at depth %d\n%!" max_goals goal_depth ; *) 453 if max_goals > 0 then begin 454 smax_map := IntMap.add goal_depth (max_goals - 1) !smax_map ; 455 fprintf fmt "@[<1>Subgoal %s%sis:@\n%a@]@\n@\n" 456 sequent.name 457 (if sequent.name = "" then "" else " ") 458 format_metaterm (normalize sequent.goal) 459 end else incr count 460 end !subgoals ; 461 format_count_subgoals fmt !count ; 462 State.reload pristine 463 464let format_sequent fmt = 465 pp_open_vbox fmt 0 ; begin 466 format_vars fmt ; 467 format_hyps fmt ; 468 fprintf fmt "============================@\n " ; 469 format_metaterm fmt sequent.goal 470 end ; pp_close_box fmt () 471 472let format_display fmt = 473 pp_open_box fmt 0 ; 474 if sequent.name = "" then 475 fprintf fmt "@\n" 476 else 477 fprintf fmt "Subgoal %s:@\n@\n" sequent.name; 478 format_sequent fmt ; 479 fprintf fmt "@\n@\n" ; 480 format_other_subgoals fmt ; 481 pp_close_box fmt () ; 482 pp_print_flush fmt () 483 484let display out = 485 format_display (formatter_of_out_channel out) 486 487let get_display () = 488 let b = Buffer.create 100 in 489 format_display (formatter_of_buffer b) ; 490 Buffer.contents b 491 492 493(* Proof state manipulation utilities *) 494 495let reset_prover original_state original_sequent = 496 (* let original_state = get_bind_state () in 497 * let original_sequent = copy_sequent () in *) 498 fun () -> 499 set_bind_state original_state ; 500 set_sequent original_sequent ; 501 subgoals := [] 502 503let full_reset_prover original_state original_sequent 504 original_clauses original_defs_table = 505 (* let original_clauses = !clauses in 506 * let original_defs_table = H.copy defs_table in *) 507 fun () -> 508 reset_prover original_state original_sequent () ; 509 clauses := original_clauses ; 510 H.assign defs_table original_defs_table 511 512let add_hyp ?name term = 513 let name = fresh_hyp_name begin 514 match name with 515 | None -> "" 516 | Some name -> name 517 end in 518 sequent.hyps <- List.append sequent.hyps 519 [{ id = name ; term = term ; abbrev = None }] 520 521let remove_hyp cm name = 522 let removed_h = ref None in 523 let hyps = List.filter begin fun h -> 524 h.id <> name || begin 525 removed_h := Some h ; 526 false 527 end 528 end sequent.hyps in 529 sequent.hyps <- hyps ; 530 match cm, !removed_h with 531 | Clear_extro, Some h -> 532 sequent.goal <- Arrow (h.term, sequent.goal) 533 | Clear_extro, None -> 534 failwithf "Cannot extrude unknown hypothesis %s" name 535 | _ -> () 536 537let replace_hyp name t = 538 let rec aux hyplist = 539 match hyplist with 540 | [] -> [] 541 | hyp::rest when hyp.id = name -> {hyp with term = t} :: rest 542 | hyp::rest -> hyp :: (aux rest) 543 in 544 sequent.hyps <- aux sequent.hyps 545 546let add_var v = 547 sequent.vars <- List.append sequent.vars [v] 548 549let add_if_new_var (name, v) = 550 if not (List.mem_assoc name sequent.vars) then 551 add_var (name, v) 552 553let add_lemma name tys lemma = 554 if H.mem lemmas name then 555 Format.eprintf "Warning: overriding existing lemma named %S@." name ; 556 H.replace lemmas name (tys, lemma) 557 558let get_hyp name = 559 let hyp = List.find (fun h -> h.id = name) sequent.hyps in 560 hyp.term 561 562let is_hyp name = 563 List.exists (fun h -> h.id = name) sequent.hyps 564 565let get_generic_lemma name = 566 try H.find lemmas name with 567 | Not_found -> 568 failwithf "Could not find theorem named %S" name 569 570let get_lemma ?(tys:ty list = []) name = 571 let (argtys, bod) = H.find lemmas name in 572 let tys = 573 if (List.length argtys > 0 && List.length tys = 0) then 574 List.map (fun _t -> fresh_tyvar ()) argtys 575 else if List.length tys <> List.length argtys then 576 failwithf "Need to provide mappings for %d types" (List.length argtys) 577 else 578 tys in 579 let tysub = List.map2 (fun id ty -> (id,ty)) argtys tys in 580 map_on_tys (apply_sub_ty tysub) bod 581 582let get_hyp_or_lemma ?tys name = 583 try get_hyp name with 584 | Not_found -> get_lemma ?tys name 585 586let stmt_name = function 587 | Keep (h, _) | Remove (h, _) -> h 588 589let get_stmt_clearly h = 590 try begin 591 match h with 592 | Keep (h, tys) -> 593 get_hyp_or_lemma ~tys h 594 | Remove (h, []) when is_hyp h -> 595 let stmt = get_hyp h in 596 remove_hyp Clear_delete h ; stmt 597 | Remove (h, tys) -> 598 get_lemma ~tys h 599 end 600 with Not_found -> 601 failwithf "Could not find hypothesis or lemma %s" (stmt_name h) 602 603let get_arg_clearly = function 604 | Keep ("_", _) -> None 605 | arg -> Some (get_stmt_clearly arg) 606 607exception End_proof of [`completed | `aborted] 608 609let next_subgoal () = 610 match !subgoals with 611 | [] -> raise (End_proof `completed) 612 | set_subgoal::rest -> 613 set_subgoal () ; 614 subgoals := rest ; 615 normalize_sequent () 616 617(* Show *) 618 619let print_theorem name (tys, thm) = 620 let ff = Format.formatter_of_out_channel !Checks.out in 621 Format.fprintf ff "@[<hv2>Theorem %s%s :@ %a@].@." 622 name (gen_to_string tys) format_metaterm thm 623 624let show name = 625 print_theorem name (get_generic_lemma name) 626 627(* Object level instantiation *) 628 629let inst ?name h ws = 630 let ht = get_stmt_clearly h in 631 match ht with 632 | Obj _ -> 633 let rec aux ws ht = match ws with 634 | [] -> add_hyp ?name ht 635 | (n, t) :: ws -> 636 let ntids = metaterm_nominal_tids ht in 637 let nty = try List.assoc n ntids with 638 | Not_found -> failwithf "Nominal constant %s not in support" n in 639 let ctx = sequent.vars @ 640 (List.map (fun (id, ty) -> (id, nominal_var id ty)) ntids) 641 in 642 let t = type_uterm ~expected_ty:nty ~sr:!sr ~sign:!sign ~ctx t in 643 aux ws (object_inst ht n t) 644 in 645 aux ws ht 646 | _ -> 647 failwith "Cannot instantiate this hypothesis\n\ 648 \ Instantiation can only be used on hypotheses of the form {...}" 649 650 651(* Object level cut *) 652 653let cut ?name h arg = 654 let h = get_stmt_clearly h in 655 let arg = get_stmt_clearly arg in 656 match h, arg with 657 | Obj(obj_h, _), Obj(obj_arg, _) -> 658 add_hyp ?name (object_cut obj_h obj_arg) 659 | _ -> failwith "Cut can only be used on hypotheses of the form {...}" 660 661(* Search *) 662 663let retype t = type_uterm ~sr:!sr ~sign:!sign ~ctx:sequent.vars t 664 665let has_inductive_hyps hyp = 666 let rec aux term = 667 match term with 668 | Binding(Forall, _, body) -> aux body 669 | Binding(Nabla, _, body) -> aux body 670 | Arrow(Obj(_, Smaller _i), _) -> true 671 | Arrow(Pred(_, Smaller _i), _) -> true 672 | Arrow(_left, right) -> aux right 673 | _ -> false 674 in 675 aux hyp.term 676 677let remove_inductive_hypotheses hyps = 678 List.remove_all has_inductive_hyps hyps 679 680let has_coinductive_result hyp = 681 let rec aux term nested = 682 match term with 683 | Binding(Forall, _, body) -> aux body true 684 | Binding(Nabla, _, body) -> aux body true 685 | Arrow(_left, right) -> aux right true 686 | Pred(_, CoSmaller _) -> nested 687 | Pred(_, CoEqual _) -> nested 688 | _ -> false 689 in 690 aux hyp.term false 691 692let remove_coinductive_hypotheses hyps = 693 List.remove_all has_coinductive_result hyps 694 695let search_depth = State.rref 5 696 697let search_goal_witness ?depth goal witness = 698 let hyps = sequent.hyps 699 |> remove_inductive_hypotheses 700 |> remove_coinductive_hypotheses 701 |> List.map (fun h -> (h.id, h.term)) 702 in 703 let depth = Option.default !search_depth depth in 704 Tactics.search 705 ~depth 706 ~hyps 707 ~clauses:!clauses 708 ~def_unfold 709 ~sr:!sr 710 ~retype 711 ~witness 712 goal 713 714let search_goal ?depth goal = 715 try Option.is_some (search_goal_witness ?depth goal WMagic) 716 with Failure _ -> false 717 718let search ?depth ~witness ~handle_witness () = 719 let search_result = search_goal_witness ?depth sequent.goal witness in 720 match search_result with 721 | None -> failwith "Search failed" 722 | Some w -> handle_witness w ; next_subgoal () 723 724let async () = 725 failwith "async not implemented" 726 727(* Search cut *) 728 729let search_cut ?name h = 730 match get_stmt_clearly h with 731 | Obj(obj, _) -> 732 add_hyp ?name (Obj(search_cut ~search_goal obj, Irrelevant)) 733 | _ -> 734 failwith "Cut can only be used on hypotheses of the form {... |- ...}" 735 736(* Apply *) 737 738let goal_to_subgoal g = 739 let saved_sequent = copy_sequent () in 740 let bind_state = Term.get_bind_state () in 741 fun () -> 742 set_sequent saved_sequent ; 743 Term.set_bind_state bind_state ; 744 sequent.goal <- g 745 746let ensure_no_logic_variable terms = 747 let logic_vars = List.flatten_map (metaterm_vars_alist Logic) terms in 748 if logic_vars <> [] then 749 failwith "Found logic variable at toplevel" 750 751let ensure_no_restrictions term = 752 let rec aux t nested = 753 match t with 754 | Binding(Forall, _, body) -> aux body true 755 | Binding(Nabla, _, body) -> aux body true 756 | Arrow(left, right) -> aux left true; aux right true 757 | Obj(_, Smaller _i) | Obj(_, Equal _i) 758 | Pred(_, Smaller _i) | Pred(_, Equal _i) -> 759 if nested then 760 failwithf "Inductive restrictions must not occur in strict subterms:\n%s" 761 (metaterm_to_string term) 762 | Pred(_, CoSmaller _i) | Pred(_, CoEqual _i) -> 763 failwithf "Co-Inductive restrictions must not be present:\n%s" 764 (metaterm_to_string term) 765 | _ -> () 766 in 767 aux term false 768 769let toplevel_bindings stmt = 770 let rec aux = function 771 | Binding(Forall, tids, t) -> tids @ (aux t) 772 | Binding(Nabla, tids, t) -> tids @ (aux t) 773 | _ -> [] 774 in 775 aux stmt 776 777let type_apply_withs stmt ws = 778 let bindings = toplevel_bindings stmt in 779 List.map 780 (fun (id, t) -> 781 try 782 let ty = List.assoc id bindings in 783 (id, type_uterm ~expected_ty:ty ~sr:!sr ~sign:!sign ~ctx:sequent.vars t) 784 with 785 | Not_found -> failwithf "Unknown variable %s" id) 786 ws 787 788let partition_obligations ?depth obligations = 789 Either.partition_eithers 790 (List.map 791 (fun g -> match search_goal_witness ?depth g WMagic with 792 | None -> Either.Left g 793 | Some w -> Either.Right (g, w)) 794 obligations) 795 796let apply ?depth ?name ?(term_witness=ignore) h args ws = 797 let stmt = get_stmt_clearly h in 798 let args = List.map get_arg_clearly args in 799 let () = List.iter (Option.map_default ensure_no_restrictions ()) args in 800 let ws = type_apply_withs stmt ws in 801 let result, obligations = Tactics.apply_with stmt args ws in 802 let remaining_obligations, term_witnesses = 803 partition_obligations ?depth obligations 804 in 805 let () = ensure_no_logic_variable (result :: remaining_obligations) in 806 let () = List.iter term_witness term_witnesses in 807 let obligation_subgoals = List.map goal_to_subgoal remaining_obligations in 808 let resulting_case = recursive_metaterm_case ~used:sequent.vars ~sr:!sr result in 809 begin match resulting_case with 810 | None -> add_subgoals obligation_subgoals 811 | Some case -> 812 let resulting_subgoal = 813 let restore = goal_to_subgoal sequent.goal in 814 fun () -> 815 restore () ; 816 List.iter add_if_new_var case.stateless_new_vars ; 817 List.iter (add_hyp ?name) case.stateless_new_hyps 818 in 819 add_subgoals ~mainline:resulting_subgoal obligation_subgoals 820 end ; 821 next_subgoal () 822 823(* Bachchain *) 824 825let type_backchain_withs stmt ws = 826 let bindings = toplevel_bindings stmt in 827 let nctx = List.map term_to_pair (metaterm_support sequent.goal) in 828 List.map 829 (fun (id, t) -> 830 try 831 let ty = List.assoc id bindings in 832 (id, type_uterm ~expected_ty:ty ~sr:!sr ~sign:!sign 833 ~ctx:(nctx @ sequent.vars) t) 834 with 835 | Not_found -> failwithf "Unknown variable %s" id) 836 ws 837 838let backchain ?depth ?(term_witness=ignore) h ws = 839 let stmt = get_stmt_clearly h in 840 let ws = type_backchain_withs stmt ws in 841 let obligations = Tactics.backchain_with stmt ws sequent.goal in 842 let remaining_obligations, term_witnesses = 843 partition_obligations ?depth obligations 844 in 845 let () = ensure_no_logic_variable remaining_obligations in 846 let () = List.iter term_witness term_witnesses in 847 let obligation_subgoals = List.map goal_to_subgoal remaining_obligations in 848 add_subgoals obligation_subgoals ; 849 next_subgoal () 850 851(* Case analysis *) 852 853(* Lifting during case analysis may cause some variables to be bound to 854 themselves. We need to update sequent.vars to reflect this. *) 855let update_self_bound_vars () = 856 sequent.vars <- 857 sequent.vars |> List.map 858 (fun (id, term) -> 859 match term_head term with 860 | Some (v, _) when term_to_name v = id -> 861 (id, v) 862 | _ -> (id, term)) 863 864let case_to_subgoal ?name case = 865 let saved_sequent = copy_sequent () in 866 fun () -> 867 set_sequent saved_sequent ; 868 List.iter add_if_new_var case.new_vars ; 869 List.iter (add_hyp ?name) case.new_hyps ; 870 Term.set_bind_state case.bind_state ; 871 update_self_bound_vars () 872 873let case ?name str = 874 let global_support = 875 (List.flatten_map metaterm_support 876 (List.map (fun h -> h.term) sequent.hyps)) @ 877 (metaterm_support sequent.goal) 878 in 879 let term = get_stmt_clearly str in 880 let (mutual, defs) = def_unfold term in 881 let cases = 882 Tactics.case ~used:sequent.vars ~sr:!sr ~clauses:!clauses 883 ~mutual ~defs ~global_support term 884 in 885 add_subgoals (List.map (case_to_subgoal ?name) cases) ; 886 next_subgoal () 887 888 889(* Induction *) 890 891let next_restriction () = 892 1 + (sequent.hyps |> List.map (fun h -> h.term) |> 893 List.map get_max_restriction |> List.max) 894 895let rec nth_product n term = 896 match term with 897 | Binding(Forall, _, body) -> nth_product n body 898 | Binding(Nabla, _, body) -> nth_product n body 899 | Arrow(left, right) -> 900 if n = 1 then 901 left 902 else 903 nth_product (n-1) right 904 | _ -> failwith "Can only induct on predicates and judgments" 905 906let ensure_is_inductive term = 907 match term with 908 | Obj _ -> () 909 | Pred(p, _) -> 910 let pname = term_head_name p in 911 begin try 912 match (H.find defs_table pname).flavor with 913 | Inductive -> () 914 | CoInductive -> 915 failwithf "Cannot induct on %s since it has\ 916 \ been coinductively defined" 917 pname 918 with Not_found -> 919 failwithf "Cannot induct on %s since it has not been defined" pname 920 end 921 | _ -> failwith "Can only induct on predicates and judgments" 922 923let add_ih h = 924 add_hyp ~name:(fresh_hyp_name "IH") h 925 926let induction ?name ind_args = 927 if has_coinductive_restriction sequent.goal then 928 failwith "Induction within coinduction is not allowed" ; 929 let stmts = and_to_list sequent.goal in 930 if List.length ind_args != List.length stmts then 931 failwithf "Expecting %d induction arguments but got %d" 932 (List.length stmts) (List.length ind_args) ; 933 List.iter 934 (fun (arg, goal) -> ensure_is_inductive (nth_product arg goal)) 935 (List.combine ind_args stmts) ; 936 let res_num = next_restriction () in 937 let (ihs, new_goal) = Tactics.induction ind_args res_num sequent.goal in 938 let name = match name with 939 | None -> fresh_hyp_name "IH" 940 | Some name -> name 941 in 942 List.iter (add_hyp ~name) ihs ; 943 sequent.goal <- new_goal 944 945 946(* CoInduction *) 947 948let rec conclusion term = 949 match term with 950 | Binding(Forall, _, body) -> conclusion body 951 | Binding(Nabla, _, body) -> conclusion body 952 | Arrow(_left, right) -> conclusion right 953 | Pred(p, _) -> p 954 | _ -> failwith "Cannot coinduct on a goal of this form" 955 956let ensure_is_coinductive p = 957 let pname = term_head_name p in 958 try 959 match (H.find defs_table pname).flavor with 960 | CoInductive -> () 961 | Inductive -> 962 failwithf "Cannot coinduct on %s since it has\ 963 \ been inductively defined" 964 pname 965 with Not_found -> 966 failwithf "Cannot coinduct on %s since it has not been defined" pname 967 968let coinduction ?name () = 969 ensure_is_coinductive (conclusion sequent.goal) ; 970 if has_inductive_restriction sequent.goal then 971 failwith "Coinduction within induction is not allowed" ; 972 let res_num = next_restriction () in 973 let (ch, new_goal) = Tactics.coinduction res_num sequent.goal in 974 let name = match name with 975 | None -> fresh_hyp_name "CH" 976 | Some name -> name 977 in 978 add_hyp ~name ch ; 979 sequent.goal <- new_goal 980 981 982(* Assert *) 983 984let delay_mainline ?name ?depth new_hyp detour_goal = 985 if depth <> Some 0 && unwind_state (search_goal ?depth) detour_goal then 986 add_hyp ?name new_hyp 987 else 988 let mainline = 989 case_to_subgoal ?name 990 { bind_state = get_bind_state () ; 991 new_vars = [] ; 992 new_hyps = [new_hyp] } 993 in 994 let detour = goal_to_subgoal detour_goal in 995 (* Using add_subgoals to take care of annotations *) 996 add_subgoals ~mainline [detour] ; 997 next_subgoal () 998 999let assert_hyp ?name ?depth term = 1000 let term = type_umetaterm ~sr:!sr ~sign:!sign ~ctx:sequent.vars term in 1001 delay_mainline ?name ?depth term term 1002 1003(* Object logic monotone *) 1004 1005let monotone ?name h t = 1006 let ht = get_stmt_clearly h in 1007 match ht with 1008 | Obj (obj, r) -> 1009 let ntids = metaterm_nominal_tids ht in 1010 let ctx = sequent.vars @ 1011 (List.map (fun (id, ty) -> (id, nominal_var id ty)) ntids) 1012 in 1013 let t = type_uterm ~expected_ty:olistty ~sr:!sr ~sign:!sign ~ctx t in 1014 let new_obj = {obj with context = Context.normalize [t]} in 1015 delay_mainline ?name 1016 (Obj (new_obj, r)) 1017 (Binding(Forall, [("X", oty)], 1018 Arrow(member (Term.const "X" oty) 1019 (Context.context_to_term obj.context), 1020 member (Term.const "X" oty) 1021 t))) ; 1022 | _ -> 1023 failwith "The monotone command can only be used on hypotheses of the form {...}" 1024 1025 1026(* Theorem *) 1027 1028let theorem thm = 1029 sequent.goal <- thm 1030 1031 1032(* Introduction of forall variables *) 1033 1034let intros hs = 1035 let rec aux hs term = 1036 match term with 1037 | Binding(Forall, bindings, body) -> 1038 let support = metaterm_support body in 1039 let (alist, vars) = 1040 fresh_raised_alist ~sr:!sr ~tag:Eigen ~used:sequent.vars 1041 ~support bindings 1042 in 1043 List.iter add_var (List.map term_to_pair vars) ; 1044 aux hs (replace_metaterm_vars alist body) 1045 | Binding(Nabla, bindings, body) -> 1046 let (ids, tys) = List.split bindings in 1047 aux hs (replace_metaterm_vars 1048 (List.combine ids (fresh_nominals tys body)) 1049 body) 1050 | Arrow(left, right) -> begin 1051 let (name, hs) = match hs with 1052 | [] -> (None, []) 1053 | "_" :: hs -> (None, hs) 1054 | h :: hs -> (Some h, hs) 1055 in 1056 add_hyp ?name (normalize left) ; 1057 aux hs right 1058 end 1059 | _ -> term 1060 in 1061 sequent.goal <- aux hs sequent.goal 1062 1063(* Split *) 1064 1065let split ?name propogate_result = 1066 let rec accum_goals conjs prev = 1067 match conjs with 1068 | [] -> [] 1069 | g::rest -> 1070 let saved = goal_to_subgoal g in 1071 let subgoal () = 1072 saved () ; 1073 if propogate_result then 1074 List.iter (add_hyp ?name) (List.rev prev) 1075 in 1076 subgoal :: (accum_goals rest (g :: prev)) 1077 in 1078 let conjs = and_to_list sequent.goal in 1079 if List.length conjs = 1 then failwith "Needless use of split" ; 1080 add_subgoals (accum_goals conjs []) ; 1081 next_subgoal () 1082 1083(* Split theorem *) 1084 1085let decompose_forall_nabla t = 1086 match t with 1087 | Binding(Forall, foralls, Binding(Nabla, nablas, body)) -> 1088 (foralls, nablas, body) 1089 | Binding(Forall, foralls, body) -> 1090 (foralls, [], body) 1091 | Binding(Nabla, nablas, body) -> 1092 ([], nablas, body) 1093 | _ -> 1094 ([], [], t) 1095 1096let multiarrow arrows body = 1097 let rec aux = function 1098 | h::hs -> Arrow(h, aux hs) 1099 | [] -> body 1100 in 1101 aux arrows 1102 1103let ensure_no_renaming vars terms = 1104 let conflicts = 1105 List.intersect 1106 vars 1107 (List.map fst (all_tids (List.flatten_map collect_terms terms))) 1108 in 1109 if conflicts <> [] then 1110 bugf "Variable renaming required" 1111 1112let split_theorem (tys, thm) = 1113 let foralls, nablas, body = decompose_forall_nabla thm in 1114 let arrows, conj = decompose_arrow body in 1115 let nabla_consts = List.map (fun (x, ty) -> const x ty) nablas in 1116 let lift t = 1117 let iforalls, inablas, ibody = decompose_forall_nabla t in 1118 (* Raise iforalls over nablas *) 1119 let alist, iforall_vars = 1120 fresh_raised_alist ~used:[] ~sr:!sr ~tag:Constant 1121 ~support:nabla_consts iforalls 1122 in 1123 let iforalls = List.map (fun x -> (term_to_name x, tc [] x)) iforall_vars in 1124 let ibody = replace_metaterm_vars alist ibody in 1125 ensure_no_renaming (List.map fst (iforalls @ inablas)) arrows ; 1126 let thm = forall (foralls @ iforalls) 1127 (nabla (nablas @ inablas) 1128 (multiarrow arrows ibody)) in 1129 (tys, thm) 1130 in 1131 List.map lift (and_to_list conj) 1132 1133let create_split_theorems name names = 1134 let thms = split_theorem (get_generic_lemma name) in 1135 let rec loop = function 1136 | n::ns, t::ts, count -> 1137 (n, t) :: (loop (ns, ts, count+1)) 1138 | [], t::ts, count -> 1139 (name ^ (string_of_int count), t) :: (loop ([], ts, count+1)) 1140 | _ -> [] 1141 in 1142 if List.length thms = 1 then 1143 failwith "Cannot split this type of theorem" ; 1144 loop (names, thms, 1) 1145 1146(* Left and right side of disjunction *) 1147 1148let left () = 1149 match sequent.goal with 1150 | Or(left, _) -> sequent.goal <- left 1151 | _ -> () 1152 1153let right () = 1154 match sequent.goal with 1155 | Or(_, right) -> sequent.goal <- right 1156 | _ -> () 1157 1158 1159(* Unfold *) 1160 1161let unfold clause_sel sol_sel = 1162 let mdefs = def_unfold sequent.goal in 1163 let used = sequent.vars in 1164 let goal = unfold ~used ~mdefs clause_sel sol_sel sequent.goal in 1165 let goals = List.concat (List.map and_to_list goal) in 1166 add_subgoals (List.map goal_to_subgoal goals) ; 1167 next_subgoal () 1168 1169(* Exists *) 1170 1171let rec resolve_ewitness ew tids = 1172 match ew, tids with 1173 | ETerm t, ((id, ty) :: tids) -> 1174 (id, ty, t, tids) 1175 | ESub (x, t), ((id, ty) :: tids) -> 1176 if x = id then (x, ty, t, tids) else 1177 let (_, xty, _, tids) = resolve_ewitness ew tids in 1178 (x, xty, t, (id, ty) :: tids) 1179 | _, [] -> 1180 failwithf "Could not resolve existential witness %s" (ewitness_to_string ew) 1181 1182let exists ew = 1183 match sequent.goal with 1184 | Binding (Metaterm.Exists, tids, body) -> 1185 let (id, ty, t, tids) = resolve_ewitness ew tids in 1186 let ntids = metaterm_nominal_tids body in 1187 let ctx = sequent.vars @ 1188 (List.map (fun (id, ty) -> (id, nominal_var id ty)) ntids) 1189 in 1190 let t = type_uterm ~expected_ty:ty ~sr:!sr ~sign:!sign ~ctx t in 1191 let goal = replace_metaterm_vars [(id, t)] (exists tids body) in 1192 sequent.goal <- goal ; 1193 normalize_sequent () 1194 | _ -> () 1195 1196(* Skip *) 1197 1198let skip () = 1199 next_subgoal () 1200 1201(* Clear *) 1202 1203let remove_var cm h = 1204 let v = term_to_var (List.assoc h sequent.vars) in 1205 sequent.vars <- List.filter (fun xv -> fst xv <> h) sequent.vars ; 1206 match cm with 1207 | Clear_extro -> 1208 let goal = replace_metaterm_vars [h, var Constant v.Term.name v.ts v.ty] sequent.goal in 1209 sequent.goal <- forall [v.Term.name, v.ty] goal 1210 | _ -> () 1211 1212let remove_thing cm h = 1213 if is_hyp h 1214 then remove_hyp cm h 1215 else remove_var cm h 1216 1217let is_used v = 1218 List.exists begin fun h -> 1219 get_metaterm_used h.term |> 1220 List.exists (fun xv -> fst xv = v) 1221 end sequent.hyps 1222 1223let check_removable h = 1224 if not (is_hyp h) then 1225 try 1226 let v = List.assoc h sequent.vars in 1227 if is_uninstantiated (h, v) && is_used h then 1228 failwithf "Cannot clear strict uninstantiated variable %s" h 1229 with Not_found -> 1230 failwithf "Unknown hypothesis or variable %s" h 1231 1232let clear cm hs = 1233 List.iter begin fun h -> 1234 check_removable h ; 1235 remove_thing cm h ; 1236 end hs 1237 1238(* Abbrev *) 1239 1240let abbrev ids str = 1241 sequent.hyps <- 1242 List.map begin fun h -> 1243 if Iset.mem h.id ids then 1244 {h with abbrev = Some str} 1245 else h 1246 end sequent.hyps 1247 1248let unabbrev ids = 1249 sequent.hyps <- 1250 List.map begin fun h -> 1251 if Iset.mem h.id ids then 1252 {h with abbrev = None} 1253 else h 1254 end sequent.hyps 1255 1256(* Rename *) 1257 1258let rename_hyp hfr hto = 1259 let hyps = List.map begin 1260 fun h -> 1261 if h.id = hfr then 1262 { h with id = hto } 1263 else h 1264 end sequent.hyps 1265 in sequent.hyps <- hyps 1266 1267let rename_var vfr xto = 1268 let ty = tc [] (List.assoc vfr sequent.vars) in 1269 let vto = var Eigen xto 0 ty in 1270 let repl = [vfr, vto] in 1271 let rewrite mt = replace_metaterm_vars repl mt in 1272 sequent.hyps <- 1273 List.map (fun h -> { h with term = rewrite h.term }) sequent.hyps ; 1274 sequent.vars <- 1275 List.filter_map begin fun v -> 1276 let (x, _) = v in 1277 if x = vfr then Some (xto, vto) 1278 else if x = xto then None 1279 else Some v 1280 end sequent.vars ; 1281 sequent.goal <- rewrite sequent.goal 1282 1283let var_unavailable x = 1284 try is_uninstantiated (x, List.assoc x sequent.vars) 1285 with Not_found -> false 1286 1287let rename xfr xto = 1288 if H.mem lemmas xto then 1289 failwithf "%S already refers to a lemma" xto ; 1290 if List.exists (fun h -> h.id = xto) sequent.hyps then 1291 failwithf "%S already refers to an existing hypothesis" xto ; 1292 if var_unavailable xto then 1293 failwithf "%S already refers to an existing variable" xto ; 1294 if List.exists (fun h -> h.id = xfr) sequent.hyps then 1295 rename_hyp xfr xto 1296 else if List.mem_assoc xfr sequent.vars then 1297 rename_var xfr xto 1298 else 1299 failwithf "Unknown variable or hypothesis label %S" xfr 1300 1301(* Permute *) 1302 1303let permute_nominals ids form = 1304 if not (List.is_unique ids) then failwith "Not a permutation" ; 1305 let term = 1306 match form with 1307 | None -> sequent.goal 1308 | Some h -> get_hyp h 1309 in 1310 let support_alist = 1311 List.map (fun t -> (term_to_name t, t)) (metaterm_support term) 1312 in 1313 let perm = 1314 List.map 1315 (fun id -> 1316 try 1317 List.assoc id support_alist 1318 with Not_found -> nominal_var id (tybase (atybase ""))) 1319 ids 1320 in 1321 let result = Tactics.permute_nominals perm term in 1322 match form with 1323 | None -> sequent.goal <- result 1324 | Some hyp -> replace_hyp hyp result 1325 1326(* Object level cut with explicit cut formula*) 1327 1328let cut_from ?name h arg term = 1329 let term = type_uterm ~sr:!sr ~sign:!sign ~ctx:sequent.vars term in 1330 let h = get_stmt_clearly h in 1331 let arg = get_stmt_clearly arg in 1332 match h, arg with 1333 | Obj(obj_h1, _),Obj(obj_h2, _) -> 1334 add_hyp ?name (object_cut_from obj_h1 obj_h2 term) 1335 | _,_ -> failwith "The cut command can only be used on \ 1336 \ hypotheses of the form {...}" 1337