src/Provers/order_tac.ML
changeset 74625 e6f0c9bf966c
parent 74561 8e6c973003c8
child 78095 bc42c074e58f
equal deleted inserted replaced
74624:c2bc0180151a 74625:e6f0c9bf966c
     6   val get_term : int -> table -> term option
     6   val get_term : int -> table -> term option
     7 end
     7 end
     8 
     8 
     9 structure Reifytab: REIFY_TABLE =
     9 structure Reifytab: REIFY_TABLE =
    10 struct
    10 struct
    11   type table = (int * int Termtab.table * term Inttab.table)
    11   type table = (int * (term * int) list)
    12   
    12   
    13   val empty = (0, Termtab.empty, Inttab.empty)
    13   val empty = (0, [])
    14   
    14   
    15   fun get_var t (tab as (max_var, termtab, inttab)) =
    15   fun get_var t (max_var, tis) =
    16     (case Termtab.lookup termtab t of
    16     (case AList.lookup Envir.aeconv tis t of
    17       SOME v => (v, tab)
    17       SOME v => (v, (max_var, tis))
    18     | NONE => (max_var,
    18     | NONE => (max_var, (max_var + 1, (t, max_var) :: tis))
    19               (max_var + 1, Termtab.update (t, max_var) termtab, Inttab.update (max_var, t) inttab))
       
    20     )
    19     )
    21   
    20   
    22   fun get_term v (_, _, inttab) = Inttab.lookup inttab v
    21   fun get_term v (_, tis) = Library.find_first (fn (_, v2) => v = v2) tis
       
    22                             |> Option.map fst
    23 end
    23 end
    24 
    24 
    25 signature LOGIC_SIGNATURE =
    25 signature LOGIC_SIGNATURE =
    26 sig
    26 sig
    27   val mk_Trueprop : term -> term
    27   val mk_Trueprop : term -> term
    52  *)
    52  *)
    53 val order_split_limit_cfg = Attrib.setup_config_int @{binding "order_split_limit"} (K 8)
    53 val order_split_limit_cfg = Attrib.setup_config_int @{binding "order_split_limit"} (K 8)
    54 
    54 
    55 datatype order_kind = Order | Linorder
    55 datatype order_kind = Order | Linorder
    56 
    56 
    57 type order_literal = (bool * Order_Procedure.o_atom)
    57 type order_literal = (bool * Order_Procedure.order_atom)
    58 
    58 
    59 type order_context = {
    59 type order_context = {
    60     kind : order_kind,
    60     kind : order_kind,
    61     ops : term list, thms : (string * thm) list, conv_thms : (string * thm) list
    61     ops : term list, thms : (string * thm) list, conv_thms : (string * thm) list
    62   }
    62   }
    76   open Order_Procedure
    76   open Order_Procedure
    77 
    77 
    78   fun expect _ (SOME x) = x
    78   fun expect _ (SOME x) = x
    79     | expect f NONE = f ()
    79     | expect f NONE = f ()
    80 
    80 
    81   fun matches_skeleton t s = t = Term.dummy orelse
       
    82     (case (t, s) of
       
    83       (t0 $ t1, s0 $ s1) => matches_skeleton t0 s0 andalso matches_skeleton t1 s1
       
    84     | _ => t aconv s)
       
    85 
       
    86   fun dest_binop t =
       
    87     let
       
    88       val binop_skel = Term.dummy $ Term.dummy $ Term.dummy
       
    89       val not_binop_skel = Logic_Sig.Not $ binop_skel
       
    90     in
       
    91       if matches_skeleton not_binop_skel t
       
    92         then (case t of (_ $ (t1 $ t2 $ t3)) => (false, (t1, t2, t3)))
       
    93         else if matches_skeleton binop_skel t
       
    94           then (case t of (t1 $ t2 $ t3) => (true, (t1, t2, t3)))
       
    95           else raise TERM ("Not a binop literal", [t])
       
    96     end
       
    97 
       
    98   fun find_term t = Library.find_first (fn (t', _) => t' aconv t)
       
    99 
       
   100   fun reify_order_atom (eq, le, lt) t reifytab =
       
   101     let
       
   102       val (b, (t0, t1, t2)) =
       
   103         (dest_binop t) handle TERM (_, _) => raise TERM ("Can't reify order literal", [t])
       
   104       val binops = [(eq, EQ), (le, LEQ), (lt, LESS)]
       
   105     in
       
   106       case find_term t0 binops of
       
   107         SOME (_, reified_bop) =>
       
   108           reifytab
       
   109           |> Reifytab.get_var t1 ||> Reifytab.get_var t2
       
   110           |> (fn (v1, (v2, vartab')) =>
       
   111                ((b, reified_bop (Int_of_integer v1, Int_of_integer v2)), vartab'))
       
   112           |>> Atom
       
   113       | NONE => raise TERM ("Can't reify order literal", [t])
       
   114     end
       
   115 
       
   116   fun reify consts reify_atom t reifytab =
       
   117     let
       
   118       fun reify' (t1 $ t2) reifytab =
       
   119             let
       
   120               val (t0, ts) = strip_comb (t1 $ t2)
       
   121               val consts_of_arity = filter (fn (_, (_, ar)) => length ts = ar) consts
       
   122             in
       
   123               (case find_term t0 consts_of_arity of
       
   124                 SOME (_, (reified_op, _)) => fold_map reify' ts reifytab |>> reified_op
       
   125               | NONE => reify_atom (t1 $ t2) reifytab)
       
   126             end
       
   127         | reify' t reifytab = reify_atom t reifytab
       
   128     in
       
   129       reify' t reifytab
       
   130     end
       
   131 
       
   132   fun list_curry0 f = (fn [] => f, 0)
    81   fun list_curry0 f = (fn [] => f, 0)
   133   fun list_curry1 f = (fn [x] => f x, 1)
    82   fun list_curry1 f = (fn [x] => f x, 1)
   134   fun list_curry2 f = (fn [x, y] => f x y, 2)
    83   fun list_curry2 f = (fn [x, y] => f x y, 2)
   135 
       
   136   fun reify_order_conj ord_ops =
       
   137     let
       
   138       val consts = map (apsnd (list_curry2 o curry)) [(Logic_Sig.conj, And), (Logic_Sig.disj, Or)]
       
   139     in   
       
   140       reify consts (reify_order_atom ord_ops)
       
   141     end
       
   142 
    84 
   143   fun dereify_term consts reifytab t =
    85   fun dereify_term consts reifytab t =
   144     let
    86     let
   145       fun dereify_term' (App (t1, t2)) = (dereify_term' t1) $ (dereify_term' t2)
    87       fun dereify_term' (App (t1, t2)) = (dereify_term' t1) $ (dereify_term' t2)
   146         | dereify_term' (Const s) =
    88         | dereify_term' (Const s) =
   202             |> expect (fn () => error ("Cannot replay theorem: " ^ s))
   144             |> expect (fn () => error ("Cannot replay theorem: " ^ s))
   203         | replay_prf_trm' assmtab (Appt (p, t)) =
   145         | replay_prf_trm' assmtab (Appt (p, t)) =
   204             replay_prf_trm' assmtab p
   146             replay_prf_trm' assmtab p
   205             |> Drule.infer_instantiate' ctxt [SOME (Thm.cterm_of ctxt (dereify t))]
   147             |> Drule.infer_instantiate' ctxt [SOME (Thm.cterm_of ctxt (dereify t))]
   206         | replay_prf_trm' assmtab (AppP (p1, p2)) =
   148         | replay_prf_trm' assmtab (AppP (p1, p2)) =
   207             apply2 (replay_prf_trm' assmtab) (p2, p1) |> (op COMP)
   149             apply2 (replay_prf_trm' assmtab) (p2, p1) |> op COMP
   208         | replay_prf_trm' assmtab (AbsP (reified_t, p)) =
   150         | replay_prf_trm' assmtab (AbsP (reified_t, p)) =
   209             let
   151             let
   210               val t = dereify reified_t
   152               val t = dereify reified_t
   211               val t_thm = Logic_Sig.mk_Trueprop t |> Thm.cterm_of ctxt |> Assumption.assume ctxt
   153               val t_thm = Logic_Sig.mk_Trueprop t |> Thm.cterm_of ctxt |> Assumption.assume ctxt
   212               val rp = replay_prf_trm' (Termtab.update (Thm.prop_of t_thm, t_thm) assmtab) p
   154               val rp = replay_prf_trm' (Termtab.update (Thm.prop_of t_thm, t_thm) assmtab) p
   251       val dereify = dereify_order_fm ord_ops reifytab
   193       val dereify = dereify_order_fm ord_ops reifytab
   252     in
   194     in
   253       replay_prf_trm (replay_conv convs) dereify ctxt thmtab assmtab
   195       replay_prf_trm (replay_conv convs) dereify ctxt thmtab assmtab
   254     end
   196     end
   255 
   197 
   256   fun is_binop_term t =
   198   fun strip_Not (nt $ t) = if nt = Logic_Sig.Not then t else nt $ t
   257     let
   199     | strip_Not t = t
   258       fun is_included t = forall (curry (op <>) (t |> fastype_of |> domain_type)) excluded_types
   200 
   259     in
   201   fun limit_not_less [_, _, lt] ctxt decomp_prems =
   260       (case dest_binop (Logic_Sig.dest_Trueprop t) of
       
   261         (_, (binop, t1, t2)) =>
       
   262           is_included binop andalso
       
   263           (* Exclude terms with schematic variables since the solver can't deal with them.
       
   264              More specifically, the solver uses Assumption.assume which does not allow schematic
       
   265              variables in the assumed cterm.
       
   266           *)
       
   267           Term.add_var_names (binop $ t1 $ t2) [] = []
       
   268       ) handle TERM (_, _) => false
       
   269     end
       
   270 
       
   271   fun partition_matches ctxt term_of pats ys =
       
   272     let
       
   273       val thy = Proof_Context.theory_of ctxt
       
   274 
       
   275       fun find_match t env =
       
   276         Library.get_first (try (fn pat => Pattern.match thy (pat, t) env)) pats
       
   277       
       
   278       fun filter_matches xs = fold (fn x => fn (mxs, nmxs, env) =>
       
   279         case find_match (term_of x) env of
       
   280           SOME env' => (x::mxs, nmxs, env')
       
   281         | NONE => (mxs, x::nmxs, env)) xs ([], [], (Vartab.empty, Vartab.empty))
       
   282 
       
   283       fun partition xs =
       
   284         case filter_matches xs of
       
   285           ([], _, _) => []
       
   286         | (mxs, nmxs, env) => (env, mxs) :: partition nmxs
       
   287     in
       
   288       partition ys
       
   289     end
       
   290 
       
   291   fun limit_not_less [_, _, lt] ctxt prems =
       
   292     let
   202     let
   293       val thy = Proof_Context.theory_of ctxt
   203       val thy = Proof_Context.theory_of ctxt
   294       val trace = Config.get ctxt order_trace_cfg
   204       val trace = Config.get ctxt order_trace_cfg
   295       val limit = Config.get ctxt order_split_limit_cfg
   205       val limit = Config.get ctxt order_split_limit_cfg
   296 
   206 
   297       fun is_not_less_term t =
   207       fun is_not_less_term t =
   298         (case dest_binop (Logic_Sig.dest_Trueprop t) of
   208         case try (strip_Not o Logic_Sig.dest_Trueprop) t of
   299           (false, (t0, _, _)) => Pattern.matches thy (lt, t0)
   209           SOME (binop $ _ $ _) => Pattern.matches thy (lt, binop)
   300         | _ => false)
   210         | NONE => false
   301         handle TERM _ => false
   211 
   302 
   212       val not_less_prems = filter (is_not_less_term o Thm.prop_of o fst) decomp_prems
   303       val not_less_prems = filter (is_not_less_term o Thm.prop_of) prems
       
   304       val _ = if trace andalso length not_less_prems > limit
   213       val _ = if trace andalso length not_less_prems > limit
   305                 then tracing "order split limit exceeded"
   214                 then tracing "order split limit exceeded"
   306                 else ()
   215                 else ()
   307      in
   216      in
   308       filter_out (is_not_less_term o Thm.prop_of) prems @
   217       filter_out (is_not_less_term o Thm.prop_of o fst) decomp_prems @
   309       take limit not_less_prems
   218       take limit not_less_prems
   310      end
   219      end
       
   220 
       
   221   fun decomp [eq, le, lt] ctxt t =
       
   222     let
       
   223       fun is_excluded t = exists (fn ty => ty = fastype_of t) excluded_types
       
   224 
       
   225       fun decomp'' (binop $ t1 $ t2) =
       
   226             let
       
   227               open Order_Procedure
       
   228               val thy = Proof_Context.theory_of ctxt
       
   229               fun try_match pat = try (Pattern.match thy (pat, binop)) (Vartab.empty, Vartab.empty)
       
   230             in if is_excluded t1 then NONE
       
   231                else case (try_match eq, try_match le, try_match lt) of
       
   232                       (SOME env, _, _) => SOME (true, EQ, (t1, t2), env)
       
   233                     | (_, SOME env, _) => SOME (true, LEQ, (t1, t2), env)
       
   234                     | (_, _, SOME env) => SOME (true, LESS, (t1, t2), env)
       
   235                     | _ => NONE
       
   236             end
       
   237         | decomp'' _ = NONE
       
   238 
       
   239         fun decomp' (nt $ t) =
       
   240               if nt = Logic_Sig.Not
       
   241                 then decomp'' t |> Option.map (fn (b, c, p, e) => (not b, c, p, e))
       
   242                 else decomp'' (nt $ t)
       
   243           | decomp' t = decomp'' t
       
   244 
       
   245     in
       
   246       try Logic_Sig.dest_Trueprop t |> Option.mapPartial decomp'
       
   247     end
       
   248 
       
   249   fun maximal_envs envs =
       
   250     let
       
   251       fun test_opt p (SOME x) = p x
       
   252         | test_opt _ NONE = false
       
   253 
       
   254       fun leq_env (tyenv1, tenv1) (tyenv2, tenv2) =
       
   255         Vartab.forall (fn (v, ty) =>
       
   256           Vartab.lookup tyenv2 v |> test_opt (fn ty2 => ty2 = ty)) tyenv1
       
   257         andalso
       
   258         Vartab.forall (fn (v, (ty, t)) =>
       
   259           Vartab.lookup tenv2 v |> test_opt (fn (ty2, t2) => ty2 = ty andalso t2 aconv t)) tenv1
       
   260 
       
   261       fun fold_env (i, env) es = fold_index (fn (i2, env2) => fn es =>
       
   262         if i = i2 then es else if leq_env env env2 then (i, i2) :: es else es) envs es
       
   263       
       
   264       val env_order = fold_index fold_env envs []
       
   265 
       
   266       val graph = fold_index (fn (i, env) => fn g => Int_Graph.new_node (i, env) g)
       
   267                              envs Int_Graph.empty
       
   268       val graph = fold Int_Graph.add_edge env_order graph
       
   269 
       
   270       val strong_conns = Int_Graph.strong_conn graph
       
   271       val maximals =
       
   272         filter (fn comp => length comp = length (Int_Graph.all_succs graph comp)) strong_conns
       
   273     in
       
   274       map (Int_Graph.all_preds graph) maximals
       
   275     end
   311       
   276       
   312   fun order_tac raw_order_proc octxt simp_prems =
   277   fun order_tac raw_order_proc octxt simp_prems =
   313     Subgoal.FOCUS (fn {prems=prems, context=ctxt, ...} =>
   278     Subgoal.FOCUS (fn {prems=prems, context=ctxt, ...} =>
   314       let
   279       let
   315         val trace = Config.get ctxt order_trace_cfg
   280         val trace = Config.get ctxt order_trace_cfg
   316 
   281 
   317         val binop_prems = filter (is_binop_term o Thm.prop_of) (prems @ simp_prems)
   282         fun these' _ [] = []
   318         val strip_binop = (fn (x, _, _) => x) o snd o dest_binop
   283           | these' f (x :: xs) = case f x of NONE => these' f xs | SOME y => (x, y) :: these' f xs
   319         val binop_of = strip_binop o Logic_Sig.dest_Trueprop o Thm.prop_of
   284 
   320 
   285         val prems = simp_prems @ prems
   321         (* Due to local_setup, the operators of the order may contain schematic term and type
   286                     |> filter (fn p => null (Term.add_vars (Thm.prop_of p) []))
   322            variables. We partition the premises according to distinct instances of those operators.
   287                     |> map (Conv.fconv_rule Thm.eta_conversion)
   323          *)
   288         val decomp_prems = these' (decomp (#ops octxt) ctxt o Thm.prop_of) prems
   324         val part_prems = partition_matches ctxt binop_of (#ops octxt) binop_prems
   289 
   325           |> (case #kind octxt of
   290         fun env_of (_, (_, _, _, env)) = env
   326                 Order => map (fn (env, prems) =>
   291         val env_groups = maximal_envs (map env_of decomp_prems)
   327                           (env, limit_not_less (#ops octxt) ctxt prems))
   292         
   328               | _ => I)
   293         fun order_tac' (_, []) = no_tac
       
   294           | order_tac' (env, decomp_prems) =
       
   295             let
       
   296               val [eq, le, lt] = #ops octxt |> map (Envir.eta_contract o Envir.subst_term env)
       
   297 
       
   298               val decomp_prems = case #kind octxt of
       
   299                                    Order => limit_not_less (#ops octxt) ctxt decomp_prems
       
   300                                  | _ => decomp_prems
       
   301       
       
   302               fun reify_prem (_, (b, ctor, (x, y), _)) (ps, reifytab) =
       
   303                 (Reifytab.get_var x ##>> Reifytab.get_var y) reifytab
       
   304                 |>> (fn vp => (b, ctor (apply2 Int_of_integer vp)) :: ps)
       
   305               val (reified_prems, reifytab) = fold_rev reify_prem decomp_prems ([], Reifytab.empty)
       
   306 
       
   307               val reified_prems_conj = foldl1 (fn (x, a) => And (x, a)) (map Atom reified_prems)
       
   308               val prems_conj_thm = map fst decomp_prems
       
   309                                    |> foldl1 (fn (x, a) => Logic_Sig.conjI OF [x, a])
       
   310                                    |> Conv.fconv_rule Thm.eta_conversion 
       
   311               val prems_conj = prems_conj_thm |> Thm.prop_of
   329               
   312               
   330         fun order_tac' (_, []) = no_tac
       
   331           | order_tac' (env, prems) =
       
   332             let
       
   333               val [eq, le, lt] = #ops octxt
       
   334               val subst_contract = Envir.eta_contract o Envir.subst_term env
       
   335               val ord_ops = (subst_contract eq,
       
   336                              subst_contract le,
       
   337                              subst_contract lt)
       
   338   
       
   339               val _ = if trace then @{print} (ord_ops, prems) else (ord_ops, prems)
       
   340   
       
   341               val prems_conj_thm = foldl1 (fn (x, a) => Logic_Sig.conjI OF [x, a]) prems
       
   342                 |> Conv.fconv_rule Thm.eta_conversion 
       
   343               val prems_conj = prems_conj_thm |> Thm.prop_of
       
   344               val (reified_prems_conj, reifytab) =
       
   345                 reify_order_conj ord_ops (Logic_Sig.dest_Trueprop prems_conj) Reifytab.empty
       
   346   
       
   347               val proof = raw_order_proc reified_prems_conj
   313               val proof = raw_order_proc reified_prems_conj
   348   
   314 
       
   315               val pretty_term_list =
       
   316                 Pretty.list "" "" o map (Syntax.pretty_term (Config.put show_types true ctxt))
       
   317               val pretty_thm_list = Pretty.list "" "" o map (Thm.pretty_thm ctxt)
       
   318               fun pretty_type_of t = Pretty.block [ Pretty.str "::", Pretty.brk 1,
       
   319                     Pretty.quote (Syntax.pretty_typ ctxt (Term.fastype_of t)) ]
       
   320               fun pretty_trace () = 
       
   321                 [ ("order kind:", Pretty.str (@{make_string} (#kind octxt)))
       
   322                 , ("order operators:", Pretty.block [ pretty_term_list [eq, le, lt], Pretty.brk 1
       
   323                                                      , pretty_type_of le ])
       
   324                 , ("premises:", pretty_thm_list prems)
       
   325                 , ("selected premises:", pretty_thm_list (map fst decomp_prems))
       
   326                 , ("reified premises:", Pretty.str (@{make_string} reified_prems))
       
   327                 , ("contradiction:", Pretty.str (@{make_string} (Option.isSome proof)))
       
   328                 ] |> map (fn (t, pp) => Pretty.block [Pretty.str t, Pretty.brk 1, pp])
       
   329                   |> Pretty.big_list "order solver called with the parameters"
       
   330               val _ = if trace then tracing (Pretty.string_of (pretty_trace ())) else ()
       
   331 
   349               val assmtab = Termtab.make [(prems_conj, prems_conj_thm)]
   332               val assmtab = Termtab.make [(prems_conj, prems_conj_thm)]
   350               val replay = replay_order_prf_trm ord_ops octxt ctxt reifytab assmtab
   333               val replay = replay_order_prf_trm (eq, le, lt) octxt ctxt reifytab assmtab
   351             in
   334             in
   352               case proof of
   335               case proof of
   353                 NONE => no_tac
   336                 NONE => no_tac
   354               | SOME p => SOLVED' (resolve_tac ctxt [replay p]) 1
   337               | SOME p => SOLVED' (resolve_tac ctxt [replay p]) 1
   355             end
   338             end
   356      in
   339      in
   357       FIRST (map order_tac' part_prems)
   340        map (fn is => ` (env_of o hd) (map (nth decomp_prems) is) |> order_tac') env_groups
       
   341        |> FIRST
   358      end)
   342      end)
   359 
   343 
   360   val ad_absurdum_tac = SUBGOAL (fn (A, i) =>
   344   val ad_absurdum_tac = SUBGOAL (fn (A, i) =>
   361       case try (Logic_Sig.dest_Trueprop o Logic.strip_assums_concl) A of
   345     case try (Logic_Sig.dest_Trueprop o Logic.strip_assums_concl) A of
   362         SOME (nt $ _) =>
   346       SOME (nt $ _) =>
   363           if nt = Logic_Sig.Not
   347         if nt = Logic_Sig.Not
   364             then resolve0_tac [Logic_Sig.notI] i
   348           then resolve0_tac [Logic_Sig.notI] i
   365             else resolve0_tac [Logic_Sig.ccontr] i
   349           else resolve0_tac [Logic_Sig.ccontr] i
   366       | SOME _ => resolve0_tac [Logic_Sig.ccontr] i
   350     | _ => resolve0_tac [Logic_Sig.ccontr] i)
   367       | NONE => resolve0_tac [Logic_Sig.ccontr] i)
       
   368 
   351 
   369   fun tac raw_order_proc octxt simp_prems ctxt =
   352   fun tac raw_order_proc octxt simp_prems ctxt =
   370       EVERY' [
   353     ad_absurdum_tac THEN' order_tac raw_order_proc octxt simp_prems ctxt
   371           ad_absurdum_tac,
       
   372           CONVERSION Thm.eta_conversion,
       
   373           order_tac raw_order_proc octxt simp_prems ctxt
       
   374         ]
       
   375   
   354   
   376 end
   355 end
   377 
   356 
   378 functor Order_Tac(structure Base_Tac : BASE_ORDER_TAC) = struct
   357 functor Order_Tac(structure Base_Tac : BASE_ORDER_TAC) = struct
   379 
   358