src/Provers/blast.ML
changeset 3092 b92a1b50b16b
parent 3083 1a7edbd7f55a
child 3101 e8a92f497295
equal deleted inserted replaced
3091:9366415b93ad 3092:b92a1b50b16b
    18   * rules must not require higher-order unification, e.g. apply_type in ZF
    18   * rules must not require higher-order unification, e.g. apply_type in ZF
    19     + message "Function Var's argument not a bound variable" relates to this
    19     + message "Function Var's argument not a bound variable" relates to this
    20   * its proof strategy is more general but can actually be slower
    20   * its proof strategy is more general but can actually be slower
    21 
    21 
    22 Known problems:
    22 Known problems:
    23   "Recursive" rules such as transitivity can exclude other unsafe formulae
    23   "Recursive" chains of rules can sometimes exclude other unsafe formulae
    24 	from expansion.  This happens because newly-created formulae always
    24 	from expansion.  This happens because newly-created formulae always
    25 	have priority over existing ones.
    25 	have priority over existing ones.  But obviously recursive rules 
       
    26 	such as transitivity are treated specially to prevent this.
    26 
    27 
    27   With overloading:
    28   With overloading:
    28         Overloading can't follow all chains of type dependencies.  Cannot
    29         Overloading can't follow all chains of type dependencies.  Cannot
    29         prove "In1 x ~: Part A In0" because PartE introducees the polymorphic
    30         prove "In1 x ~: Part A In0" because PartE introducees the polymorphic
    30 	equality In1 x = In0 y, when the corresponding rule uses the (distinct)
    31 	equality In1 x = In0 y, when the corresponding rule uses the (distinct)
    32 	creates new equalities (e.g. PartE in HOL/ex/Simult)
    33 	creates new equalities (e.g. PartE in HOL/ex/Simult)
    33 	==> affects freeness reasoning about Sexp constants (since they have
    34 	==> affects freeness reasoning about Sexp constants (since they have
    34 		type ... set)
    35 		type ... set)
    35 
    36 
    36   With substition for equalities (hyp_subst_tac):
    37   With substition for equalities (hyp_subst_tac):
    37     1.  Sometimes hyp_subst_tac will fail due to occurrence of the parameter
    38         When substitution affects a haz formula or literal, it is moved
    38         as the argument of a function variable
       
    39     2.  When substitution affects a haz formula or literal, it is moved
       
    40         back to the list of safe formulae.
    39         back to the list of safe formulae.
    41         But there's no way of putting it in the right place.  A "moved" or
    40         But there's no way of putting it in the right place.  A "moved" or
    42         "no DETERM" flag would prevent proofs failing here.
    41         "no DETERM" flag would prevent proofs failing here.
    43 *)
    42 *)
    44 
    43 
   104                   (int->tactic) list * branch list list * (int*int*exn) list
   103                   (int->tactic) list * branch list list * (int*int*exn) list
   105   val normBr		: branch -> branch
   104   val normBr		: branch -> branch
   106   end;
   105   end;
   107 
   106 
   108 
   107 
   109 functor BlastFun(Data: BLAST_DATA)(**********: BLAST*******) = 
   108 functor BlastFun(Data: BLAST_DATA) : BLAST = 
   110 struct
   109 struct
   111 
   110 
   112 type claset = Data.claset;
   111 type claset = Data.claset;
   113 
   112 
   114 val trace = ref false;
   113 val trace = ref false;
   121   | Var   of term option ref
   120   | Var   of term option ref
   122   | Bound of int
   121   | Bound of int
   123   | Abs   of string*term
   122   | Abs   of string*term
   124   | op $  of term*term;
   123   | op $  of term*term;
   125 
   124 
   126 
       
   127 exception DEST_EQ;
       
   128 
       
   129   (*Take apart an equality (plain or overloaded).  NO constant Trueprop*)
       
   130   fun dest_eq (Const  "op ="     $ t $ u) = (t,u)
       
   131     | dest_eq (OConst("op =",_)  $ t $ u) = (t,u)
       
   132     | dest_eq _                      = raise DEST_EQ;
       
   133 
   125 
   134 (** Basic syntactic operations **)
   126 (** Basic syntactic operations **)
   135 
   127 
   136 fun is_Var (Var _) = true
   128 fun is_Var (Var _) = true
   137   | is_Var _ = false;
   129   | is_Var _ = false;
   306 	| subst (f$t, lev) =  subst(f,lev)  $  subst(t,lev)
   298 	| subst (f$t, lev) =  subst(f,lev)  $  subst(t,lev)
   307 	| subst (t,lev)    = t
   299 	| subst (t,lev)    = t
   308   in  subst (t,0)  end;
   300   in  subst (t,0)  end;
   309 
   301 
   310 
   302 
   311 (*Normalize...but not the bodies of ABSTRACTIONS*)
   303 (*Normalize, INCLUDING bodies of abstractions--this might be slow?*)
   312 fun norm t = case t of
   304 fun norm t = case t of
   313     Skolem (a,args)      => Skolem(a, vars_in_vars args)
   305     Skolem (a,args)      => Skolem(a, vars_in_vars args)
   314   | (Var (ref None))     => t
   306   | (Var (ref None))     => t
   315   | (Var (ref (Some u))) => norm u
   307   | (Var (ref (Some u))) => norm u
   316   | (f $ u) => (case norm f of
   308   | (f $ u) => (case norm f of
   317 		    Abs(_,body) => norm (subst_bound (u, body))
   309 		    Abs(_,body) => norm (subst_bound (u, body))
   318 		  | nf => nf $ norm u)
   310 		  | nf => nf $ norm u)
       
   311   | Abs (a,body) => Abs (a, norm body)
   319   | _ => t;
   312   | _ => t;
   320 
   313 
   321 
   314 
   322 (*Weak (one-level) normalize for use in unification*)
   315 (*Weak (one-level) normalize for use in unification*)
   323 fun wkNormAux t = case t of
   316 fun wkNormAux t = case t of
   331 	(case wkNormAux body of
   324 	(case wkNormAux body of
   332 	     nb as (f $ t) => 
   325 	     nb as (f $ t) => 
   333 		 if (0 mem_int loose_bnos f) orelse wkNorm t <> Bound 0
   326 		 if (0 mem_int loose_bnos f) orelse wkNorm t <> Bound 0
   334 		 then Abs(a,nb)
   327 		 then Abs(a,nb)
   335 		 else wkNorm (incr_boundvars ~1 f)
   328 		 else wkNorm (incr_boundvars ~1 f)
   336 	   | nb          => Abs (a,nb))
   329 	   | nb => Abs (a,nb))
   337   | _ => t
   330   | _ => t
   338 and wkNorm t = case head_of t of
   331 and wkNorm t = case head_of t of
   339     Const _        => t
   332     Const _        => t
   340   | OConst _       => t
   333   | OConst _       => t
   341   | Skolem(a,args) => t
   334   | Skolem(a,args) => t
   551 
   544 
   552 (**
   545 (**
   553 end;
   546 end;
   554 **)
   547 **)
   555 
   548 
       
   549 
       
   550 (*Pending formulae carry md (may duplicate) flags*)
       
   551 type branch = ((term*bool) list *	(*safe formulae on this level*)
       
   552                (term*bool) list) list * (*haz formulae  on this level*)
       
   553 	      term list *               (*literals: irreducible formulae*)
       
   554 	      term option ref list *    (*variables occurring in branch*)
       
   555 	      int;                      (*resource limit*)
       
   556 
       
   557 val fullTrace = ref[] : branch list list ref;
       
   558 
       
   559 (*Normalize a branch--for tracing*)
       
   560 fun norm2 (G,md) = (norm G, md);
       
   561 
       
   562 fun normLev (Gs,Hs) = (map norm2 Gs, map norm2 Hs);
       
   563 
       
   564 fun normBr (br, lits, vars, lim) =
       
   565      (map normLev br, map norm lits, vars, lim);
       
   566 
       
   567 
       
   568 val dummyVar2 = Term.Var(("var",0), dummyT);
       
   569 
       
   570 (*Convert from prototerms to ordinary terms with dummy types for tracing*)
       
   571 fun showTerm d (Const a)     = Term.Const (a,dummyT)
       
   572   | showTerm d (OConst(a,_)) = Term.Const (a,dummyT)
       
   573   | showTerm d (Skolem(a,_)) = Term.Const (a,dummyT)
       
   574   | showTerm d (Free a)      = Term.Free  (a,dummyT)
       
   575   | showTerm d (Bound i)     = Term.Bound i
       
   576   | showTerm d (Var _)       = dummyVar2
       
   577   | showTerm d (Abs(a,t))    = if d=0 then dummyVar
       
   578 			       else Term.Abs(a, dummyT, showTerm (d-1) t)
       
   579   | showTerm d (f $ u)       = if d=0 then dummyVar
       
   580 			       else Term.$ (showTerm d f, showTerm (d-1) u);
       
   581 
       
   582 
       
   583 fun traceTerm sign t = Sign.string_of_term sign (showTerm 8 (norm t));
       
   584 
       
   585 
       
   586 (*Print tracing information at each iteration of prover*)
       
   587 fun tracing sign brs = 
       
   588   let fun printPairs (((G,_)::_,_)::_)  = prs(traceTerm sign G)
       
   589 	| printPairs (([],(H,_)::_)::_) = prs(traceTerm sign H ^ "\t (Unsafe)")
       
   590 	| printPairs _                 = ()
       
   591       fun printBrs (brs0 as (pairs, lits, _, lim) :: brs) =
       
   592 	    (fullTrace := brs0 :: !fullTrace;
       
   593 	     seq (fn _ => prs "+") brs;
       
   594 	     prs (" [" ^ Int.toString lim ^ "] ");
       
   595 	     printPairs pairs;
       
   596 	     writeln"")
       
   597   in if !trace then printBrs (map normBr brs) else ()
       
   598   end;
       
   599 
       
   600 (*Tracing: variables updated in the last branch operation?*)
       
   601 fun traceVars ntrl =
       
   602     if !trace then 
       
   603        (case !ntrail-ntrl of
       
   604 	    0 => writeln""
       
   605 	  | 1 => writeln"\t1 variable updated"
       
   606 	  | n => writeln("\t" ^ Int.toString n ^ " variables updated"))
       
   607     else ();
       
   608 
       
   609 (*Tracing: how many new branches are created?*)
       
   610 fun traceNew prems =
       
   611     if !trace then 
       
   612         case length prems of
       
   613 	    0 => prs"branch closed by rule"
       
   614 	  | 1 => prs"branch extended (1 new subgoal)"
       
   615 	  | n => prs("branch split: "^ Int.toString n ^ " new subgoals")
       
   616     else ();
       
   617 
       
   618 
       
   619 
   556 (*** Code for handling equality: naive substitution, like hyp_subst_tac ***)
   620 (*** Code for handling equality: naive substitution, like hyp_subst_tac ***)
   557 
   621 
   558 (*Replace the ATOMIC term "old" by "new" in t*)  
   622 (*Replace the ATOMIC term "old" by "new" in t*)  
   559 fun subst_atomic (old,new) t =
   623 fun subst_atomic (old,new) t =
   560     let fun subst (Var(ref(Some u))) = subst u
   624     let fun subst (Var(ref(Some u))) = subst u
   591         | occ (Abs(_,u))         = occEq u
   655         | occ (Abs(_,u))         = occEq u
   592         | occ (f$u)              = occEq u  orelse  occEq f
   656         | occ (f$u)              = occEq u  orelse  occEq f
   593         | occ (_)                = false;
   657         | occ (_)                = false;
   594   in  occEq  end;
   658   in  occEq  end;
   595 
   659 
       
   660 exception DEST_EQ;
       
   661 
       
   662 (*Take apart an equality (plain or overloaded).  NO constant Trueprop*)
       
   663 fun dest_eq (Const  "op ="     $ t $ u) = 
       
   664 		(eta_contract_atom t, eta_contract_atom u)
       
   665   | dest_eq (OConst("op =",_)  $ t $ u) = 
       
   666 		(eta_contract_atom t, eta_contract_atom u)
       
   667   | dest_eq _                           = raise DEST_EQ;
       
   668 
   596 fun check (t,u,v) = if substOccur t u then raise DEST_EQ else v;
   669 fun check (t,u,v) = if substOccur t u then raise DEST_EQ else v;
   597 
   670 
   598 (*IF the goal is an equality with a substitutable variable 
   671 (*IF the goal is an equality with a substitutable variable 
   599   THEN orient that equality ELSE raise exception DEST_EQ*)
   672   THEN orient that equality ELSE raise exception DEST_EQ*)
   600 fun orientGoal (t,u) =
   673 fun orientGoal (t,u) = case (t,u) of
   601   case (eta_contract_atom t, eta_contract_atom u) of
       
   602        (Skolem _, _) => check(t,u,(t,u))	(*eliminates t*)
   674        (Skolem _, _) => check(t,u,(t,u))	(*eliminates t*)
   603      | (_, Skolem _) => check(u,t,(u,t))	(*eliminates u*)
   675      | (_, Skolem _) => check(u,t,(u,t))	(*eliminates u*)
   604      | (Free _, _)   => check(t,u,(t,u))	(*eliminates t*)
   676      | (Free _, _)   => check(t,u,(t,u))	(*eliminates t*)
   605      | (_, Free _)   => check(u,t,(u,t))	(*eliminates u*)
   677      | (_, Free _)   => check(u,t,(u,t))	(*eliminates u*)
   606      | _             => raise DEST_EQ;
   678      | _             => raise DEST_EQ;
   607 
   679 
   608 
       
   609 
       
   610 
       
   611 (*Substitute through the branch if an equality goal (else raise DEST_EQ).
   680 (*Substitute through the branch if an equality goal (else raise DEST_EQ).
   612   Moves affected literals back into the branch, but it is not clear where
   681   Moves affected literals back into the branch, but it is not clear where
   613   they should go: this could make proofs fail.  ??? *)
   682   they should go: this could make proofs fail.  ??? *)
   614 fun equalSubst (G, pairs, lits, vars, lim) = 
   683 fun equalSubst sign (G, pairs, lits, vars, lim) = 
   615   let val subst = subst_atomic (orientGoal(dest_eq G))
   684   let val (t,u) = orientGoal(dest_eq G)
       
   685       val subst = subst_atomic (t,u)
   616       fun subst2(G,md) = (subst G, md)
   686       fun subst2(G,md) = (subst G, md)
   617       (*substitute throughout Haz list; move affected ones to Safe part*)
   687       (*substitute throughout Haz list; move affected ones to Safe part*)
   618       fun subHazs ([], Gs, nHs)         = (Gs,nHs)
   688       fun subHazs ([], Gs, nHs)         = (Gs,nHs)
   619 	| subHazs ((H,md)::Hs, Gs, nHs) =
   689 	| subHazs ((H,md)::Hs, Gs, nHs) =
   620 	    let val nH = subst H
   690 	    let val nH = subst H
   628 	| subLits (lit::lits, Gs, nlits) =
   698 	| subLits (lit::lits, Gs, nlits) =
   629 	    let val nlit = subst lit
   699 	    let val nlit = subst lit
   630 	    in  if nlit aconv lit then subLits (lits, Gs, nlit::nlits)
   700 	    in  if nlit aconv lit then subLits (lits, Gs, nlit::nlits)
   631 		                  else subLits (lits, (nlit,true)::Gs, nlits)
   701 		                  else subLits (lits, (nlit,true)::Gs, nlits)
   632             end
   702             end
   633   in  if !trace then writeln "substitution in branch" else ();
   703   in  if !trace then writeln ("Substituting " ^ traceTerm sign u ^
       
   704 			      " for " ^ traceTerm sign t ^ " in branch" )
       
   705       else ();
   634       subLits (rev lits, [], [])  
   706       subLits (rev lits, [], [])  
   635   end;
   707   end;
   636 
   708 
   637 
   709 
   638 exception NEWBRANCHES and CLOSEF;
   710 exception NEWBRANCHES and CLOSEF;
   639 
       
   640 (*Pending formulae carry md (may duplicate) flags*)
       
   641 type branch = ((term*bool) list *	(*safe formulae on this level*)
       
   642                (term*bool) list) list * (*haz formulae  on this level*)
       
   643 	      term list *               (*literals: irreducible formulae*)
       
   644 	      term option ref list *    (*variables occurring in branch*)
       
   645 	      int;                      (*resource limit*)
       
   646 
       
   647 val fullTrace = ref[] : branch list list ref;
       
   648 
       
   649 (*Normalize a branch--for tracing*)
       
   650 fun norm2 (G,md) = (norm G, md);
       
   651 
       
   652 fun normLev (Gs,Hs) = (map norm2 Gs, map norm2 Hs);
       
   653 
       
   654 fun normBr (br, lits, vars, lim) =
       
   655      (map normLev br, map norm lits, vars, lim);
       
   656 
       
   657 
       
   658 val dummyVar2 = Term.Var(("var",0), dummyT);
       
   659 
       
   660 (*Convert from prototerms to ordinary terms with dummy types for tracing*)
       
   661 fun showTerm d (Const a)     = Term.Const (a,dummyT)
       
   662   | showTerm d (OConst(a,_)) = Term.Const (a,dummyT)
       
   663   | showTerm d (Skolem(a,_)) = Term.Const (a,dummyT)
       
   664   | showTerm d (Free a)      = Term.Free  (a,dummyT)
       
   665   | showTerm d (Bound i)     = Term.Bound i
       
   666   | showTerm d (Var _)       = dummyVar2
       
   667   | showTerm d (Abs(a,t))    = if d=0 then dummyVar
       
   668 			       else Term.Abs(a, dummyT, showTerm (d-1) t)
       
   669   | showTerm d (f $ u)       = if d=0 then dummyVar
       
   670 			       else Term.$ (showTerm d f, showTerm (d-1) u);
       
   671 
       
   672 
       
   673 (*Print tracing information at each iteration of prover*)
       
   674 fun tracing sign brs = 
       
   675   let fun pr t = prs (Sign.string_of_term sign (showTerm 8 t))
       
   676       fun printPairs (((G,_)::_,_)::_) = pr G
       
   677 	| printPairs (([],(H,_)::_)::_) = (pr H;  prs"\t (Unsafe)")
       
   678 	| printPairs _                 = ()
       
   679       fun printBrs (brs0 as (pairs, lits, _, lim) :: brs) =
       
   680 	    (fullTrace := brs0 :: !fullTrace;
       
   681 	     seq (fn _ => prs "+") brs;
       
   682 	     prs (" [" ^ Int.toString lim ^ "] ");
       
   683 	     printPairs pairs;
       
   684 	     writeln"")
       
   685   in if !trace then printBrs (map normBr brs) else ()
       
   686   end;
       
   687 
       
   688 fun traceNew prems =
       
   689     if !trace then 
       
   690 	case length prems of
       
   691 	    0 => writeln"branch closed by rule"
       
   692 	  | 1 => writeln"branch extended (1 new subgoal)"
       
   693 	  | n => writeln("branch split: "^ Int.toString n ^
       
   694 			 " new subgoals")
       
   695     else ();
       
   696 
       
   697 
       
   698 
   711 
   699 exception PROVE;
   712 exception PROVE;
   700 
   713 
   701 val eq_contr_tac = eresolve_tac [Data.notE]  THEN'  eq_assume_tac;
   714 val eq_contr_tac = eresolve_tac [Data.notE]  THEN'  eq_assume_tac;
   702 
   715 
   871 			 val vars' = foldr add_terms_vars (prems, vars)
   884 			 val vars' = foldr add_terms_vars (prems, vars)
   872 			 val choices' = (ntrl, nbrs, PRV) :: choices
   885 			 val choices' = (ntrl, nbrs, PRV) :: choices
   873 			 val tacs' = (DETERM o (tac false)) :: tacs 
   886 			 val tacs' = (DETERM o (tac false)) :: tacs 
   874 					 (*no duplication*)
   887 					 (*no duplication*)
   875 		     in
   888 		     in
   876 			 traceNew prems;
   889 			 traceNew prems;  traceVars ntrl;
   877 			 (if null prems then (*closed the branch: prune!*)
   890 			 (if null prems then (*closed the branch: prune!*)
   878 			    prv(tacs',  brs0::trs, 
   891 			    prv(tacs',  brs0::trs, 
   879 				prune (nbrs, nxtVars, choices'),
   892 				prune (nbrs, nxtVars, choices'),
   880 				brs)
   893 				brs)
   881 			  else
   894 			  else
   899 		| closeF (L::Ls) = 
   912 		| closeF (L::Ls) = 
   900 		    case tryClose(G,L) of
   913 		    case tryClose(G,L) of
   901 			None     => closeF Ls
   914 			None     => closeF Ls
   902 		      | Some tac => 
   915 		      | Some tac => 
   903 			    let val choices' = 
   916 			    let val choices' = 
   904 				    (if !trace then writeln"branch closed"
   917 				    (if !trace then (prs"branch closed";
       
   918 						     traceVars ntrl)
   905 				               else ();
   919 				               else ();
   906 				     prune (nbrs, nxtVars, 
   920 				     prune (nbrs, nxtVars, 
   907 					    (ntrl, nbrs, PRV) :: choices))
   921 					    (ntrl, nbrs, PRV) :: choices))
   908 			    in  prv (tac::tacs, brs0::trs, choices', brs)  
   922 			    in  prv (tac::tacs, brs0::trs, choices', brs)  
   909 				handle PRV => 
   923 				handle PRV => 
   917 		      handle CLOSEF => closeF (map fst haz)
   931 		      handle CLOSEF => closeF (map fst haz)
   918 			handle CLOSEF => closeFl pairs
   932 			handle CLOSEF => closeFl pairs
   919 	  in tracing sign brs0; 
   933 	  in tracing sign brs0; 
   920 	     if lim<0 then backtrack choices
   934 	     if lim<0 then backtrack choices
   921 	     else
   935 	     else
   922 	     prv (Data.vars_gen_hyp_subst_tac false :: tacs, 
   936 	     prv ((TRY  o  Data.vars_gen_hyp_subst_tac false)  ::  tacs, 
       
   937 		  (*The TRY above allows the substitution to fail, e.g. if
       
   938 		    the real version is z = f(?x z).  Rest of proof might
       
   939 		    still succeed!*)
   923 		  brs0::trs,  choices,
   940 		  brs0::trs,  choices,
   924 		  equalSubst (G, (br,haz)::pairs, lits, vars, lim) :: brs)
   941 		  equalSubst sign (G, (br,haz)::pairs, lits, vars, lim) :: brs)
   925 	     handle DEST_EQ => closeF lits
   942 	     handle DEST_EQ => closeF lits
   926 	      handle CLOSEF => closeFl ((br,haz)::pairs)
   943 	      handle CLOSEF => closeFl ((br,haz)::pairs)
   927 	        handle CLOSEF => 
   944 	        handle CLOSEF => 
   928 		 deeper rules
   945 		 deeper rules
   929 		  handle NEWBRANCHES => 
   946 		  handle NEWBRANCHES => 
   987 		     in
  1004 		     in
   988 		       if lim'<0 andalso not (null prems)
  1005 		       if lim'<0 andalso not (null prems)
   989 		       then (*it's faster to kill ALL the alternatives*)
  1006 		       then (*it's faster to kill ALL the alternatives*)
   990 			   raise NEWBRANCHES
  1007 			   raise NEWBRANCHES
   991 		       else 
  1008 		       else 
   992 			 traceNew prems;
  1009 			 traceNew prems;  traceVars ntrl;
   993 			 prv(tac dup :: tacs, 
  1010 			 prv(tac dup :: tacs, 
   994 			     brs0::trs, 
  1011 			     brs0::trs, 
   995 			     (ntrl, length brs0, PRV) :: choices, 
  1012 			     (ntrl, length brs0, PRV) :: choices, 
   996 			     newBr (vars', recur, dup, lim') prems)
  1013 			     newBr (vars', recur, dup, lim') prems)
   997 			  handle PRV => 
  1014 			  handle PRV => 
  1071 
  1088 
  1072       (*Skolemize a subgoal from a proof state*)
  1089       (*Skolemize a subgoal from a proof state*)
  1073       fun skoSubgoal i t =
  1090       fun skoSubgoal i t =
  1074 	  if i<npars then 
  1091 	  if i<npars then 
  1075 	      skoSubgoal (i+1)
  1092 	      skoSubgoal (i+1)
  1076 		(subst_bound (Skolem (gensym "SG_", getVars (!alist) i), 
  1093 		(subst_bound (Skolem (gensym "T_", getVars (!alist) i), 
  1077 			      t))
  1094 			      t))
  1078 	  else t
  1095 	  else t
  1079 
  1096 
  1080   in  skoSubgoal 0 (from 0 (discard_foralls t))  end;
  1097   in  skoSubgoal 0 (from 0 (discard_foralls t))  end;
  1081 
  1098