src/Provers/quasi.ML
author haftmann
Thu, 08 Jul 2010 16:19:24 +0200
changeset 37743 3daaf23b9ab4
parent 33061 4d462963a7db
child 39406 0dec18004e75
permissions -rw-r--r--
tuned titles
     1 (*  Title:      Provers/quasi.ML
     2     Author:     Oliver Kutter, TU Muenchen
     3 
     4 Reasoner for simple transitivity and quasi orders.
     5 *)
     6 
     7 (*
     8 
     9 The package provides tactics trans_tac and quasi_tac that use
    10 premises of the form
    11 
    12   t = u, t ~= u, t < u and t <= u
    13 
    14 to
    15 - either derive a contradiction, in which case the conclusion can be
    16   any term,
    17 - or prove the concluson, which must be of the form t ~= u, t < u or
    18   t <= u.
    19 
    20 Details:
    21 
    22 1. trans_tac:
    23    Only premises of form t <= u are used and the conclusion must be of
    24    the same form.  The conclusion is proved, if possible, by a chain of
    25    transitivity from the assumptions.
    26 
    27 2. quasi_tac:
    28    <= is assumed to be a quasi order and < its strict relative, defined
    29    as t < u == t <= u & t ~= u.  Again, the conclusion is proved from
    30    the assumptions.
    31    Note that the presence of a strict relation is not necessary for
    32    quasi_tac.  Configure decomp_quasi to ignore < and ~=.  A list of
    33    required theorems for both situations is given below.
    34 *)
    35 
    36 signature LESS_ARITH =
    37 sig
    38   (* Transitivity of <=
    39      Note that transitivities for < hold for partial orders only. *)
    40   val le_trans: thm  (* [| x <= y; y <= z |] ==> x <= z *)
    41 
    42   (* Additional theorem for quasi orders *)
    43   val le_refl: thm  (* x <= x *)
    44   val eqD1: thm (* x = y ==> x <= y *)
    45   val eqD2: thm (* x = y ==> y <= x *)
    46 
    47   (* Additional theorems for premises of the form x < y *)
    48   val less_reflE: thm  (* x < x ==> P *)
    49   val less_imp_le : thm (* x < y ==> x <= y *)
    50 
    51   (* Additional theorems for premises of the form x ~= y *)
    52   val le_neq_trans : thm (* [| x <= y ; x ~= y |] ==> x < y *)
    53   val neq_le_trans : thm (* [| x ~= y ; x <= y |] ==> x < y *)
    54 
    55   (* Additional theorem for goals of form x ~= y *)
    56   val less_imp_neq : thm (* x < y ==> x ~= y *)
    57 
    58   (* Analysis of premises and conclusion *)
    59   (* decomp_x (`x Rel y') should yield SOME (x, Rel, y)
    60        where Rel is one of "<", "<=", "=" and "~=",
    61        other relation symbols cause an error message *)
    62   (* decomp_trans is used by trans_tac, it may only return Rel = "<=" *)
    63   val decomp_trans: theory -> term -> (term * string * term) option
    64   (* decomp_quasi is used by quasi_tac *)
    65   val decomp_quasi: theory -> term -> (term * string * term) option
    66 end;
    67 
    68 signature QUASI_TAC =
    69 sig
    70   val trans_tac: Proof.context -> int -> tactic
    71   val quasi_tac: Proof.context -> int -> tactic
    72 end;
    73 
    74 functor Quasi_Tac(Less: LESS_ARITH): QUASI_TAC =
    75 struct
    76 
    77 (* Internal datatype for the proof *)
    78 datatype proof
    79   = Asm of int
    80   | Thm of proof list * thm;
    81 
    82 exception Cannot;
    83  (* Internal exception, raised if conclusion cannot be derived from
    84      assumptions. *)
    85 exception Contr of proof;
    86   (* Internal exception, raised if contradiction ( x < x ) was derived *)
    87 
    88 fun prove asms =
    89   let fun pr (Asm i) = List.nth (asms, i)
    90   |       pr (Thm (prfs, thm)) = (map pr prfs) MRS thm
    91   in pr end;
    92 
    93 (* Internal datatype for inequalities *)
    94 datatype less
    95    = Less  of term * term * proof
    96    | Le    of term * term * proof
    97    | NotEq of term * term * proof;
    98 
    99  (* Misc functions for datatype less *)
   100 fun lower (Less (x, _, _)) = x
   101   | lower (Le (x, _, _)) = x
   102   | lower (NotEq (x,_,_)) = x;
   103 
   104 fun upper (Less (_, y, _)) = y
   105   | upper (Le (_, y, _)) = y
   106   | upper (NotEq (_,y,_)) = y;
   107 
   108 fun getprf   (Less (_, _, p)) = p
   109 |   getprf   (Le   (_, _, p)) = p
   110 |   getprf   (NotEq (_,_, p)) = p;
   111 
   112 (* ************************************************************************ *)
   113 (*                                                                          *)
   114 (* mkasm_trans sign (t, n) :  theory -> (Term.term * int)  -> less          *)
   115 (*                                                                          *)
   116 (* Tuple (t, n) (t an assumption, n its index in the assumptions) is        *)
   117 (* translated to an element of type less.                                   *)
   118 (* Only assumptions of form x <= y are used, all others are ignored         *)
   119 (*                                                                          *)
   120 (* ************************************************************************ *)
   121 
   122 fun mkasm_trans thy (t, n) =
   123   case Less.decomp_trans thy t of
   124     SOME (x, rel, y) =>
   125     (case rel of
   126      "<="  =>  [Le (x, y, Asm n)]
   127     | _     => error ("trans_tac: unknown relation symbol ``" ^ rel ^
   128                  "''returned by decomp_trans."))
   129   | NONE => [];
   130 
   131 (* ************************************************************************ *)
   132 (*                                                                          *)
   133 (* mkasm_quasi sign (t, n) : theory -> (Term.term * int) -> less            *)
   134 (*                                                                          *)
   135 (* Tuple (t, n) (t an assumption, n its index in the assumptions) is        *)
   136 (* translated to an element of type less.                                   *)
   137 (* Quasi orders only.                                                       *)
   138 (*                                                                          *)
   139 (* ************************************************************************ *)
   140 
   141 fun mkasm_quasi thy (t, n) =
   142   case Less.decomp_quasi thy t of
   143     SOME (x, rel, y) => (case rel of
   144       "<"   => if (x aconv y) then raise Contr (Thm ([Asm n], Less.less_reflE))
   145                else [Less (x, y, Asm n)]
   146     | "<="  => [Le (x, y, Asm n)]
   147     | "="   => [Le (x, y, Thm ([Asm n], Less.eqD1)),
   148                 Le (y, x, Thm ([Asm n], Less.eqD2))]
   149     | "~="  => if (x aconv y) then
   150                   raise Contr (Thm ([(Thm ([(Thm ([], Less.le_refl)) ,(Asm n)], Less.le_neq_trans))], Less.less_reflE))
   151                else [ NotEq (x, y, Asm n),
   152                       NotEq (y, x,Thm ( [Asm n], thm "not_sym"))]
   153     | _     => error ("quasi_tac: unknown relation symbol ``" ^ rel ^
   154                  "''returned by decomp_quasi."))
   155   | NONE => [];
   156 
   157 
   158 (* ************************************************************************ *)
   159 (*                                                                          *)
   160 (* mkconcl_trans sign t : theory -> Term.term -> less                       *)
   161 (*                                                                          *)
   162 (* Translates conclusion t to an element of type less.                      *)
   163 (* Only for Conclusions of form x <= y or x < y.                            *)
   164 (*                                                                          *)
   165 (* ************************************************************************ *)
   166 
   167 
   168 fun mkconcl_trans thy t =
   169   case Less.decomp_trans thy t of
   170     SOME (x, rel, y) => (case rel of
   171      "<="  => (Le (x, y, Asm ~1), Asm 0)
   172     | _  => raise Cannot)
   173   | NONE => raise Cannot;
   174 
   175 
   176 (* ************************************************************************ *)
   177 (*                                                                          *)
   178 (* mkconcl_quasi sign t : theory -> Term.term -> less                       *)
   179 (*                                                                          *)
   180 (* Translates conclusion t to an element of type less.                      *)
   181 (* Quasi orders only.                                                       *)
   182 (*                                                                          *)
   183 (* ************************************************************************ *)
   184 
   185 fun mkconcl_quasi thy t =
   186   case Less.decomp_quasi thy t of
   187     SOME (x, rel, y) => (case rel of
   188       "<"   => ([Less (x, y, Asm ~1)], Asm 0)
   189     | "<="  => ([Le (x, y, Asm ~1)], Asm 0)
   190     | "~="  => ([NotEq (x,y, Asm ~1)], Asm 0)
   191     | _  => raise Cannot)
   192 | NONE => raise Cannot;
   193 
   194 
   195 (* ******************************************************************* *)
   196 (*                                                                     *)
   197 (* mergeLess (less1,less2):  less * less -> less                       *)
   198 (*                                                                     *)
   199 (* Merge to elements of type less according to the following rules     *)
   200 (*                                                                     *)
   201 (* x <= y && y <= z ==> x <= z                                         *)
   202 (* x <= y && x ~= y ==> x < y                                          *)
   203 (* x ~= y && x <= y ==> x < y                                          *)
   204 (*                                                                     *)
   205 (* ******************************************************************* *)
   206 
   207 fun mergeLess (Le (x, _, p) , Le (_ , z, q)) =
   208       Le (x, z, Thm ([p,q] , Less.le_trans))
   209 |   mergeLess (Le (x, z, p) , NotEq (x', z', q)) =
   210       if (x aconv x' andalso z aconv z' )
   211        then Less (x, z, Thm ([p,q] , Less.le_neq_trans))
   212         else error "quasi_tac: internal error le_neq_trans"
   213 |   mergeLess (NotEq (x, z, p) , Le (x' , z', q)) =
   214       if (x aconv x' andalso z aconv z')
   215       then Less (x, z, Thm ([p,q] , Less.neq_le_trans))
   216       else error "quasi_tac: internal error neq_le_trans"
   217 |   mergeLess (_, _) =
   218       error "quasi_tac: internal error: undefined case";
   219 
   220 
   221 (* ******************************************************************** *)
   222 (* tr checks for valid transitivity step                                *)
   223 (* ******************************************************************** *)
   224 
   225 infix tr;
   226 fun (Le (_, y, _))   tr (Le (x', _, _))   = ( y aconv x' )
   227   | _ tr _ = false;
   228 
   229 (* ******************************************************************* *)
   230 (*                                                                     *)
   231 (* transPath (Lesslist, Less): (less list * less) -> less              *)
   232 (*                                                                     *)
   233 (* If a path represented by a list of elements of type less is found,  *)
   234 (* this needs to be contracted to a single element of type less.       *)
   235 (* Prior to each transitivity step it is checked whether the step is   *)
   236 (* valid.                                                              *)
   237 (*                                                                     *)
   238 (* ******************************************************************* *)
   239 
   240 fun transPath ([],lesss) = lesss
   241 |   transPath (x::xs,lesss) =
   242       if lesss tr x then transPath (xs, mergeLess(lesss,x))
   243       else error "trans/quasi_tac: internal error transpath";
   244 
   245 (* ******************************************************************* *)
   246 (*                                                                     *)
   247 (* less1 subsumes less2 : less -> less -> bool                         *)
   248 (*                                                                     *)
   249 (* subsumes checks whether less1 implies less2                         *)
   250 (*                                                                     *)
   251 (* ******************************************************************* *)
   252 
   253 infix subsumes;
   254 fun (Le (x, y, _)) subsumes (Le (x', y', _)) =
   255       (x aconv x' andalso y aconv y')
   256   | (Le _) subsumes (Less _) =
   257       error "trans/quasi_tac: internal error: Le cannot subsume Less"
   258   | (NotEq(x,y,_)) subsumes (NotEq(x',y',_)) = x aconv x' andalso y aconv y' orelse x aconv y' andalso y aconv x'
   259   | _ subsumes _ = false;
   260 
   261 (* ******************************************************************* *)
   262 (*                                                                     *)
   263 (* triv_solv less1 : less ->  proof option                     *)
   264 (*                                                                     *)
   265 (* Solves trivial goal x <= x.                                         *)
   266 (*                                                                     *)
   267 (* ******************************************************************* *)
   268 
   269 fun triv_solv (Le (x, x', _)) =
   270     if x aconv x' then  SOME (Thm ([], Less.le_refl))
   271     else NONE
   272 |   triv_solv _ = NONE;
   273 
   274 (* ********************************************************************* *)
   275 (* Graph functions                                                       *)
   276 (* ********************************************************************* *)
   277 
   278 (* *********************************************************** *)
   279 (* Functions for constructing graphs                           *)
   280 (* *********************************************************** *)
   281 
   282 fun addEdge (v,d,[]) = [(v,d)]
   283 |   addEdge (v,d,((u,dl)::el)) = if v aconv u then ((v,d@dl)::el)
   284     else (u,dl):: (addEdge(v,d,el));
   285 
   286 (* ********************************************************************** *)
   287 (*                                                                        *)
   288 (* mkQuasiGraph constructs from a list of objects of type less a graph g, *)
   289 (* by taking all edges that are candidate for a <=, and a list neqE, by   *)
   290 (* taking all edges that are candiate for a ~=                            *)
   291 (*                                                                        *)
   292 (* ********************************************************************** *)
   293 
   294 fun mkQuasiGraph [] = ([],[])
   295 |   mkQuasiGraph lessList =
   296  let
   297  fun buildGraphs ([],leG, neqE) = (leG,  neqE)
   298   |   buildGraphs (l::ls, leG,  neqE) = case l of
   299        (Less (x,y,p)) =>
   300          let
   301           val leEdge  = Le (x,y, Thm ([p], Less.less_imp_le))
   302           val neqEdges = [ NotEq (x,y, Thm ([p], Less.less_imp_neq)),
   303                            NotEq (y,x, Thm ( [Thm ([p], Less.less_imp_neq)], thm "not_sym"))]
   304          in
   305            buildGraphs (ls, addEdge(y,[],(addEdge (x,[(y,leEdge)],leG))), neqEdges@neqE)
   306          end
   307      |  (Le (x,y,p))   => buildGraphs (ls, addEdge(y,[],(addEdge (x,[(y,l)],leG))), neqE)
   308      | _ =>  buildGraphs (ls, leG,  l::neqE) ;
   309 
   310 in buildGraphs (lessList, [],  []) end;
   311 
   312 (* ********************************************************************** *)
   313 (*                                                                        *)
   314 (* mkGraph constructs from a list of objects of type less a graph g       *)
   315 (* Used for plain transitivity chain reasoning.                           *)
   316 (*                                                                        *)
   317 (* ********************************************************************** *)
   318 
   319 fun mkGraph [] = []
   320 |   mkGraph lessList =
   321  let
   322   fun buildGraph ([],g) = g
   323   |   buildGraph (l::ls, g) =  buildGraph (ls, (addEdge ((lower l),[((upper l),l)],g)))
   324 
   325 in buildGraph (lessList, []) end;
   326 
   327 (* *********************************************************************** *)
   328 (*                                                                         *)
   329 (* adjacent g u : (''a * 'b list ) list -> ''a -> 'b list                  *)
   330 (*                                                                         *)
   331 (* List of successors of u in graph g                                      *)
   332 (*                                                                         *)
   333 (* *********************************************************************** *)
   334 
   335 fun adjacent eq_comp ((v,adj)::el) u =
   336     if eq_comp (u, v) then adj else adjacent eq_comp el u
   337 |   adjacent _  []  _ = []
   338 
   339 (* *********************************************************************** *)
   340 (*                                                                         *)
   341 (* dfs eq_comp g u v:                                                      *)
   342 (* ('a * 'a -> bool) -> ('a  *( 'a * less) list) list ->                   *)
   343 (* 'a -> 'a -> (bool * ('a * less) list)                                   *)
   344 (*                                                                         *)
   345 (* Depth first search of v from u.                                         *)
   346 (* Returns (true, path(u, v)) if successful, otherwise (false, []).        *)
   347 (*                                                                         *)
   348 (* *********************************************************************** *)
   349 
   350 fun dfs eq_comp g u v =
   351  let
   352     val pred = Unsynchronized.ref [];
   353     val visited = Unsynchronized.ref [];
   354 
   355     fun been_visited v = exists (fn w => eq_comp (w, v)) (!visited)
   356 
   357     fun dfs_visit u' =
   358     let val _ = visited := u' :: (!visited)
   359 
   360     fun update (x,l) = let val _ = pred := (x,l) ::(!pred) in () end;
   361 
   362     in if been_visited v then ()
   363     else (app (fn (v',l) => if been_visited v' then () else (
   364        update (v',l);
   365        dfs_visit v'; ()) )) (adjacent eq_comp g u')
   366      end
   367   in
   368     dfs_visit u;
   369     if (been_visited v) then (true, (!pred)) else (false , [])
   370   end;
   371 
   372 (* ************************************************************************ *)
   373 (*                                                                          *)
   374 (* Begin: Quasi Order relevant functions                                    *)
   375 (*                                                                          *)
   376 (*                                                                          *)
   377 (* ************************************************************************ *)
   378 
   379 (* ************************************************************************ *)
   380 (*                                                                          *)
   381 (* findPath x y g: Term.term -> Term.term ->                                *)
   382 (*                  (Term.term * (Term.term * less list) list) ->           *)
   383 (*                  (bool, less list)                                       *)
   384 (*                                                                          *)
   385 (*  Searches a path from vertex x to vertex y in Graph g, returns true and  *)
   386 (*  the list of edges forming the path, if a path is found, otherwise false *)
   387 (*  and nil.                                                                *)
   388 (*                                                                          *)
   389 (* ************************************************************************ *)
   390 
   391 
   392  fun findPath x y g =
   393   let
   394     val (found, tmp) =  dfs (op aconv) g x y ;
   395     val pred = map snd tmp;
   396 
   397     fun path x y  =
   398       let
   399        (* find predecessor u of node v and the edge u -> v *)
   400        fun lookup v [] = raise Cannot
   401        |   lookup v (e::es) = if (upper e) aconv v then e else lookup v es;
   402 
   403        (* traverse path backwards and return list of visited edges *)
   404        fun rev_path v =
   405         let val l = lookup v pred
   406             val u = lower l;
   407         in
   408            if u aconv x then [l] else (rev_path u) @ [l]
   409         end
   410       in rev_path y end;
   411 
   412   in
   413    if found then (
   414     if x aconv y then (found,[(Le (x, y, (Thm ([], Less.le_refl))))])
   415     else (found, (path x y) ))
   416    else (found,[])
   417   end;
   418 
   419 
   420 (* ************************************************************************ *)
   421 (*                                                                          *)
   422 (* findQuasiProof (leqG, neqE) subgoal:                                     *)
   423 (* (Term.term * (Term.term * less list) list) * less list  -> less -> proof *)
   424 (*                                                                          *)
   425 (* Constructs a proof for subgoal by searching a special path in leqG and   *)
   426 (* neqE. Raises Cannot if construction of the proof fails.                  *)
   427 (*                                                                          *)
   428 (* ************************************************************************ *)
   429 
   430 
   431 (* As the conlusion can be either of form x <= y, x < y or x ~= y we have        *)
   432 (* three cases to deal with. Finding a transitivity path from x to y with label  *)
   433 (* 1. <=                                                                         *)
   434 (*    This is simply done by searching any path from x to y in the graph leG.    *)
   435 (*    The graph leG contains only edges with label <=.                           *)
   436 (*                                                                               *)
   437 (* 2. <                                                                          *)
   438 (*    A path from x to y with label < can be found by searching a path with      *)
   439 (*    label <= from x to y in the graph leG and merging the path x <= y with     *)
   440 (*    a parallel edge x ~= y resp. y ~= x to x < y.                              *)
   441 (*                                                                               *)
   442 (* 3. ~=                                                                         *)
   443 (*   If the conclusion is of form x ~= y, we can find a proof either directly,   *)
   444 (*   if x ~= y or y ~= x are among the assumptions, or by constructing x ~= y if *)
   445 (*   x < y or y < x follows from the assumptions.                                *)
   446 
   447 fun findQuasiProof (leG, neqE) subgoal =
   448   case subgoal of (Le (x,y, _)) => (
   449    let
   450     val (xyLefound,xyLePath) = findPath x y leG
   451    in
   452     if xyLefound then (
   453      let
   454       val Le_x_y = (transPath (tl xyLePath, hd xyLePath))
   455      in getprf Le_x_y end )
   456     else raise Cannot
   457    end )
   458   | (Less (x,y,_))  => (
   459    let
   460     fun findParallelNeq []  = NONE
   461     |   findParallelNeq (e::es)  =
   462      if      (x aconv (lower e) andalso y aconv (upper e)) then SOME e
   463      else if (y aconv (lower e) andalso x aconv (upper e)) then SOME (NotEq (x,y, (Thm ([getprf e], thm "not_sym"))))
   464      else findParallelNeq es ;
   465    in
   466    (* test if there is a edge x ~= y respectivly  y ~= x and     *)
   467    (* if it possible to find a path x <= y in leG, thus we can conclude x < y *)
   468     (case findParallelNeq neqE of (SOME e) =>
   469       let
   470        val (xyLeFound,xyLePath) = findPath x y leG
   471       in
   472        if xyLeFound then (
   473         let
   474          val Le_x_y = (transPath (tl xyLePath, hd xyLePath))
   475          val Less_x_y = mergeLess (e, Le_x_y)
   476         in getprf Less_x_y end
   477        ) else raise Cannot
   478       end
   479     | _ => raise Cannot)
   480    end )
   481  | (NotEq (x,y,_)) =>
   482   (* First check if a single premiss is sufficient *)
   483   (case (Library.find_first (fn fact => fact subsumes subgoal) neqE, subgoal) of
   484     (SOME (NotEq (x, y, p)), NotEq (x', y', _)) =>
   485       if  (x aconv x' andalso y aconv y') then p
   486       else Thm ([p], thm "not_sym")
   487     | _  => raise Cannot
   488   )
   489 
   490 
   491 (* ************************************************************************ *)
   492 (*                                                                          *)
   493 (* End: Quasi Order relevant functions                                      *)
   494 (*                                                                          *)
   495 (*                                                                          *)
   496 (* ************************************************************************ *)
   497 
   498 (* *********************************************************************** *)
   499 (*                                                                         *)
   500 (* solveLeTrans sign (asms,concl) :                                        *)
   501 (* theory -> less list * Term.term -> proof list                           *)
   502 (*                                                                         *)
   503 (* Solves                                                                  *)
   504 (*                                                                         *)
   505 (* *********************************************************************** *)
   506 
   507 fun solveLeTrans thy (asms, concl) =
   508  let
   509   val g = mkGraph asms
   510  in
   511    let
   512     val (subgoal, prf) = mkconcl_trans thy concl
   513     val (found, path) = findPath (lower subgoal) (upper subgoal) g
   514    in
   515     if found then [getprf (transPath (tl path, hd path))]
   516     else raise Cannot
   517   end
   518  end;
   519 
   520 
   521 (* *********************************************************************** *)
   522 (*                                                                         *)
   523 (* solveQuasiOrder sign (asms,concl) :                                     *)
   524 (* theory -> less list * Term.term -> proof list                           *)
   525 (*                                                                         *)
   526 (* Find proof if possible for quasi order.                                 *)
   527 (*                                                                         *)
   528 (* *********************************************************************** *)
   529 
   530 fun solveQuasiOrder thy (asms, concl) =
   531  let
   532   val (leG, neqE) = mkQuasiGraph asms
   533  in
   534    let
   535    val (subgoals, prf) = mkconcl_quasi thy concl
   536    fun solve facts less =
   537        (case triv_solv less of NONE => findQuasiProof (leG, neqE) less
   538        | SOME prf => prf )
   539   in   map (solve asms) subgoals end
   540  end;
   541 
   542 (* ************************************************************************ *)
   543 (*                                                                          *)
   544 (* Tactics                                                                  *)
   545 (*                                                                          *)
   546 (*  - trans_tac                                                          *)
   547 (*  - quasi_tac, solves quasi orders                                        *)
   548 (* ************************************************************************ *)
   549 
   550 
   551 (* trans_tac - solves transitivity chains over <= *)
   552 
   553 fun trans_tac ctxt = SUBGOAL (fn (A, n) => fn st =>
   554  let
   555   val thy = ProofContext.theory_of ctxt;
   556   val rfrees = map Free (Term.rename_wrt_term A (Logic.strip_params A));
   557   val Hs = map (fn H => subst_bounds (rfrees, H)) (Logic.strip_assums_hyp A);
   558   val C = subst_bounds (rfrees, Logic.strip_assums_concl A);
   559   val lesss = flat (map_index (mkasm_trans thy o swap) Hs);
   560   val prfs = solveLeTrans thy (lesss, C);
   561 
   562   val (subgoal, prf) = mkconcl_trans thy C;
   563  in
   564   Subgoal.FOCUS (fn {prems, ...} =>
   565     let val thms = map (prove prems) prfs
   566     in rtac (prove thms prf) 1 end) ctxt n st
   567  end
   568  handle Contr p => Subgoal.FOCUS (fn {prems, ...} => rtac (prove prems p) 1) ctxt n st
   569   | Cannot  => Seq.empty);
   570 
   571 
   572 (* quasi_tac - solves quasi orders *)
   573 
   574 fun quasi_tac ctxt = SUBGOAL (fn (A, n) => fn st =>
   575  let
   576   val thy = ProofContext.theory_of ctxt
   577   val rfrees = map Free (Term.rename_wrt_term A (Logic.strip_params A));
   578   val Hs = map (fn H => subst_bounds (rfrees, H)) (Logic.strip_assums_hyp A);
   579   val C = subst_bounds (rfrees, Logic.strip_assums_concl A);
   580   val lesss = flat (map_index (mkasm_quasi thy o swap) Hs);
   581   val prfs = solveQuasiOrder thy (lesss, C);
   582   val (subgoals, prf) = mkconcl_quasi thy C;
   583  in
   584   Subgoal.FOCUS (fn {prems, ...} =>
   585     let val thms = map (prove prems) prfs
   586     in rtac (prove thms prf) 1 end) ctxt n st
   587  end
   588  handle Contr p =>
   589     (Subgoal.FOCUS (fn {prems, ...} => rtac (prove prems p) 1) ctxt n st
   590       handle Subscript => Seq.empty)
   591   | Cannot => Seq.empty
   592   | Subscript => Seq.empty);
   593 
   594 end;