src/HOL/Tools/Nitpick/nitpick.ML
changeset 43022 7d3ce43d9464
parent 43020 abb5d1f907e4
child 43602 8c89a1fb30f2
equal deleted inserted replaced
43021:5910dd009d0e 43022:7d3ce43d9464
     7 
     7 
     8 signature NITPICK =
     8 signature NITPICK =
     9 sig
     9 sig
    10   type styp = Nitpick_Util.styp
    10   type styp = Nitpick_Util.styp
    11   type term_postprocessor = Nitpick_Model.term_postprocessor
    11   type term_postprocessor = Nitpick_Model.term_postprocessor
       
    12 
       
    13   datatype mode = Auto_Try | Try | Normal
       
    14 
    12   type params =
    15   type params =
    13     {cards_assigns: (typ option * int list) list,
    16     {cards_assigns: (typ option * int list) list,
    14      maxes_assigns: (styp option * int list) list,
    17      maxes_assigns: (styp option * int list) list,
    15      iters_assigns: (styp option * int list) list,
    18      iters_assigns: (styp option * int list) list,
    16      bitss: int list,
    19      bitss: int list,
    66   val unregister_codatatype : typ -> theory -> theory
    69   val unregister_codatatype : typ -> theory -> theory
    67   val register_term_postprocessor :
    70   val register_term_postprocessor :
    68     typ -> term_postprocessor -> theory -> theory
    71     typ -> term_postprocessor -> theory -> theory
    69   val unregister_term_postprocessor : typ -> theory -> theory
    72   val unregister_term_postprocessor : typ -> theory -> theory
    70   val pick_nits_in_term :
    73   val pick_nits_in_term :
    71     Proof.state -> params -> bool -> int -> int -> int -> (term * term) list
    74     Proof.state -> params -> mode -> int -> int -> int -> (term * term) list
    72     -> term list -> term -> string * Proof.state
    75     -> term list -> term -> string * Proof.state
    73   val pick_nits_in_subgoal :
    76   val pick_nits_in_subgoal :
    74     Proof.state -> params -> bool -> int -> int -> string * Proof.state
    77     Proof.state -> params -> mode -> int -> int -> string * Proof.state
    75 end;
    78 end;
    76 
    79 
    77 structure Nitpick : NITPICK =
    80 structure Nitpick : NITPICK =
    78 struct
    81 struct
    79 
    82 
    87 open Nitpick_Nut
    90 open Nitpick_Nut
    88 open Nitpick_Kodkod
    91 open Nitpick_Kodkod
    89 open Nitpick_Model
    92 open Nitpick_Model
    90 
    93 
    91 structure KK = Kodkod
    94 structure KK = Kodkod
       
    95 
       
    96 datatype mode = Auto_Try | Try | Normal
    92 
    97 
    93 type params =
    98 type params =
    94   {cards_assigns: (typ option * int list) list,
    99   {cards_assigns: (typ option * int list) list,
    95    maxes_assigns: (styp option * int list) list,
   100    maxes_assigns: (styp option * int list) list,
    96    iters_assigns: (styp option * int list) list,
   101    iters_assigns: (styp option * int list) list,
   208   | has_tfree_syntactic_sort _ = false
   213   | has_tfree_syntactic_sort _ = false
   209 val has_syntactic_sorts = exists_type (exists_subtype has_tfree_syntactic_sort)
   214 val has_syntactic_sorts = exists_type (exists_subtype has_tfree_syntactic_sort)
   210 
   215 
   211 fun plazy f = Pretty.blk (0, pstrs (f ()))
   216 fun plazy f = Pretty.blk (0, pstrs (f ()))
   212 
   217 
   213 fun pick_them_nits_in_term deadline state (params : params) auto i n step
   218 fun pick_them_nits_in_term deadline state (params : params) mode i n step
   214                            subst assm_ts orig_t =
   219                            subst assm_ts orig_t =
   215   let
   220   let
   216     val timer = Timer.startRealTimer ()
   221     val timer = Timer.startRealTimer ()
   217     val thy = Proof.theory_of state
   222     val thy = Proof.theory_of state
   218     val ctxt = Proof.context_of state
   223     val ctxt = Proof.context_of state
   230          kodkod_sym_break, tac_timeout, max_threads, show_datatypes,
   235          kodkod_sym_break, tac_timeout, max_threads, show_datatypes,
   231          show_skolems, show_consts, evals, formats, atomss, max_potential,
   236          show_skolems, show_consts, evals, formats, atomss, max_potential,
   232          max_genuine, check_potential, check_genuine, batch_size, ...} = params
   237          max_genuine, check_potential, check_genuine, batch_size, ...} = params
   233     val state_ref = Unsynchronized.ref state
   238     val state_ref = Unsynchronized.ref state
   234     val pprint =
   239     val pprint =
   235       if auto then
   240       if mode = Auto_Try then
   236         Unsynchronized.change state_ref o Proof.goal_message o K
   241         Unsynchronized.change state_ref o Proof.goal_message o K
   237         o Pretty.chunks o cons (Pretty.str "") o single
   242         o Pretty.chunks o cons (Pretty.str "") o single
   238         o Pretty.mark Markup.hilite
   243         o Pretty.mark Markup.hilite
   239       else
   244       else
   240         (fn s => (Output.urgent_message s; if debug then tracing s else ()))
   245         (fn s => (Output.urgent_message s; if debug then tracing s else ()))
   241         o Pretty.string_of
   246         o Pretty.string_of
   242     fun pprint_m f = () |> not auto ? pprint o f
   247     fun pprint_n f = () |> mode = Normal ? pprint o f
   243     fun pprint_v f = () |> verbose ? pprint o f
   248     fun pprint_v f = () |> verbose ? pprint o f
   244     fun pprint_d f = () |> debug ? pprint o f
   249     fun pprint_d f = () |> debug ? pprint o f
   245     val print = pprint o curry Pretty.blk 0 o pstrs
   250     val print = pprint o curry Pretty.blk 0 o pstrs
   246 (*
   251 (*
   247     val print_g = pprint o Pretty.str
   252     val print_g = pprint o Pretty.str
   248 *)
   253 *)
   249     val print_m = pprint_m o K o plazy
   254     val print_n = pprint_n o K o plazy
   250     val print_v = pprint_v o K o plazy
   255     val print_v = pprint_v o K o plazy
   251 
   256 
   252     fun check_deadline () =
   257     fun check_deadline () =
   253       if passed_deadline deadline then raise TimeLimit.TimeOut else ()
   258       if passed_deadline deadline then raise TimeLimit.TimeOut else ()
   254 
   259 
   255     val assm_ts = if assms orelse auto then assm_ts else []
   260     val assm_ts = if assms orelse mode <> Normal then assm_ts else []
   256     val _ =
   261     val _ =
   257       if step = 0 then
   262       if step = 0 then
   258         print_m (fn () => "Nitpicking formula...")
   263         print_n (fn () => "Nitpicking formula...")
   259       else
   264       else
   260         pprint_m (fn () => Pretty.chunks (
   265         pprint_n (fn () => Pretty.chunks (
   261             pretties_for_formulas ctxt ("Nitpicking " ^
   266             pretties_for_formulas ctxt ("Nitpicking " ^
   262                 (if i <> 1 orelse n <> 1 then
   267                 (if i <> 1 orelse n <> 1 then
   263                    "subgoal " ^ string_of_int i ^ " of " ^ string_of_int n
   268                    "subgoal " ^ string_of_int i ^ " of " ^ string_of_int n
   264                  else
   269                  else
   265                    "goal")) [Logic.list_implies (assm_ts, orig_t)]))
   270                    "goal")) [Logic.list_implies (assm_ts, orig_t)]))
   406                    \presence of rationals, reals, \"Suc\", \"gcd\", or \"lcm\" \
   411                    \presence of rationals, reals, \"Suc\", \"gcd\", or \"lcm\" \
   407                    \in the problem or because of the \"non_std\" option.")
   412                    \in the problem or because of the \"non_std\" option.")
   408       else
   413       else
   409         ()
   414         ()
   410     val _ =
   415     val _ =
   411       if not auto andalso
   416       if mode = Normal andalso
   412          exists (fn Type (@{type_name Datatype.node}, _) => true | _ => false)
   417          exists (fn Type (@{type_name Datatype.node}, _) => true | _ => false)
   413                 all_Ts then
   418                 all_Ts then
   414         print_m (K ("Warning: The problem involves directly or indirectly the \
   419         print_n (K ("Warning: The problem involves directly or indirectly the \
   415                     \internal type " ^ quote @{type_name Datatype.node} ^
   420                     \internal type " ^ quote @{type_name Datatype.node} ^
   416                     ". This type is very Nitpick-unfriendly, and its presence \
   421                     ". This type is very Nitpick-unfriendly, and its presence \
   417                     \usually indicates either a failure of abstraction or a \
   422                     \usually indicates either a failure of abstraction or a \
   418                     \quirk in Nitpick."))
   423                     \quirk in Nitpick."))
   419       else
   424       else
   450       exists (exists (curry (op =) name o shortest_name o fst)
   455       exists (exists (curry (op =) name o shortest_name o fst)
   451               o datatype_constrs hol_ctxt) deep_dataTs
   456               o datatype_constrs hol_ctxt) deep_dataTs
   452     val likely_in_struct_induct_step =
   457     val likely_in_struct_induct_step =
   453       exists is_struct_induct_step (Proof_Context.cases_of ctxt)
   458       exists is_struct_induct_step (Proof_Context.cases_of ctxt)
   454     val _ = if standard andalso likely_in_struct_induct_step then
   459     val _ = if standard andalso likely_in_struct_induct_step then
   455               pprint_m (fn () => Pretty.blk (0,
   460               pprint_n (fn () => Pretty.blk (0,
   456                   pstrs "Hint: To check that the induction hypothesis is \
   461                   pstrs "Hint: To check that the induction hypothesis is \
   457                         \general enough, try this command: " @
   462                         \general enough, try this command: " @
   458                   [Pretty.mark Markup.sendback (Pretty.blk (0,
   463                   [Pretty.mark Markup.sendback (Pretty.blk (0,
   459                        pstrs ("nitpick [non_std, show_all]")))] @ pstrs "."))
   464                        pstrs ("nitpick [non_std, show_all]")))] @ pstrs "."))
   460             else
   465             else
   470     val actual_sat_solver =
   475     val actual_sat_solver =
   471       if sat_solver <> "smart" then
   476       if sat_solver <> "smart" then
   472         if incremental andalso
   477         if incremental andalso
   473            not (member (op =) (Kodkod_SAT.configured_sat_solvers true)
   478            not (member (op =) (Kodkod_SAT.configured_sat_solvers true)
   474                        sat_solver) then
   479                        sat_solver) then
   475           (print_m (K ("An incremental SAT solver is required: \"SAT4J\" will \
   480           (print_n (K ("An incremental SAT solver is required: \"SAT4J\" will \
   476                        \be used instead of " ^ quote sat_solver ^ "."));
   481                        \be used instead of " ^ quote sat_solver ^ "."));
   477            "SAT4J")
   482            "SAT4J")
   478         else
   483         else
   479           sat_solver
   484           sat_solver
   480       else
   485       else
   648 
   653 
   649     fun update_checked_problems problems =
   654     fun update_checked_problems problems =
   650       List.app (Unsynchronized.change checked_problems o Option.map o cons
   655       List.app (Unsynchronized.change checked_problems o Option.map o cons
   651                 o nth problems)
   656                 o nth problems)
   652     fun show_kodkod_warning "" = ()
   657     fun show_kodkod_warning "" = ()
   653       | show_kodkod_warning s = print_m (fn () => "Kodkod warning: " ^ s ^ ".")
   658       | show_kodkod_warning s = print_n (fn () => "Kodkod warning: " ^ s ^ ".")
   654 
   659 
   655     fun print_and_check_model genuine bounds
   660     fun print_and_check_model genuine bounds
   656             ({free_names, sel_names, nonsel_names, rel_table, scope, ...}
   661             ({free_names, sel_names, nonsel_names, rel_table, scope, ...}
   657              : problem_extension) =
   662              : problem_extension) =
   658       let
   663       let
   668           codatatypes_ok
   673           codatatypes_ok
   669         fun assms_prop () = Logic.mk_conjunction_list (neg_t :: assm_ts)
   674         fun assms_prop () = Logic.mk_conjunction_list (neg_t :: assm_ts)
   670       in
   675       in
   671         (pprint (Pretty.chunks
   676         (pprint (Pretty.chunks
   672              [Pretty.blk (0,
   677              [Pretty.blk (0,
   673                   (pstrs ((if auto then "Auto " else "") ^ "Nitpick found a" ^
   678                   (pstrs ((if mode = Auto_Try then "Auto " else "") ^
       
   679                           "Nitpick found a" ^
   674                           (if not genuine then " potentially spurious "
   680                           (if not genuine then " potentially spurious "
   675                            else if genuine_means_genuine then " "
   681                            else if genuine_means_genuine then " "
   676                            else " quasi genuine ") ^ das_wort_model) @
   682                            else " quasi genuine ") ^ das_wort_model) @
   677                    (case pretties_for_scope scope verbose of
   683                    (case pretties_for_scope scope verbose of
   678                       [] => []
   684                       [] => []
   779           (found_really_genuine, 0, 0, donno)
   785           (found_really_genuine, 0, 0, donno)
   780         else
   786         else
   781           case KK.solve_any_problem debug overlord deadline max_threads
   787           case KK.solve_any_problem debug overlord deadline max_threads
   782                                     max_solutions (map fst problems) of
   788                                     max_solutions (map fst problems) of
   783             KK.JavaNotInstalled =>
   789             KK.JavaNotInstalled =>
   784             (print_m install_java_message;
   790             (print_n install_java_message;
   785              (found_really_genuine, max_potential, max_genuine, donno + 1))
   791              (found_really_genuine, max_potential, max_genuine, donno + 1))
   786           | KK.JavaTooOld =>
   792           | KK.JavaTooOld =>
   787             (print_m install_java_message;
   793             (print_n install_java_message;
   788              (found_really_genuine, max_potential, max_genuine, donno + 1))
   794              (found_really_genuine, max_potential, max_genuine, donno + 1))
   789           | KK.KodkodiNotInstalled =>
   795           | KK.KodkodiNotInstalled =>
   790             (print_m install_kodkodi_message;
   796             (print_n install_kodkodi_message;
   791              (found_really_genuine, max_potential, max_genuine, donno + 1))
   797              (found_really_genuine, max_potential, max_genuine, donno + 1))
   792           | KK.Normal ([], unsat_js, s) =>
   798           | KK.Normal ([], unsat_js, s) =>
   793             (update_checked_problems problems unsat_js; show_kodkod_warning s;
   799             (update_checked_problems problems unsat_js; show_kodkod_warning s;
   794              (found_really_genuine, max_potential, max_genuine, donno))
   800              (found_really_genuine, max_potential, max_genuine, donno))
   795           | KK.Normal (sat_ps, unsat_js, s) =>
   801           | KK.Normal (sat_ps, unsat_js, s) =>
   872     fun run_batch j n scopes (found_really_genuine, max_potential, max_genuine,
   878     fun run_batch j n scopes (found_really_genuine, max_potential, max_genuine,
   873                               donno) =
   879                               donno) =
   874       let
   880       let
   875         val _ =
   881         val _ =
   876           if null scopes then
   882           if null scopes then
   877             print_m (K "The scope specification is inconsistent.")
   883             print_n (K "The scope specification is inconsistent.")
   878           else if verbose then
   884           else if verbose then
   879             pprint (Pretty.chunks
   885             pprint (Pretty.chunks
   880                 [Pretty.blk (0,
   886                 [Pretty.blk (0,
   881                      pstrs ((if n > 1 then
   887                      pstrs ((if n > 1 then
   882                                "Batch " ^ string_of_int (j + 1) ^ " of " ^
   888                                "Batch " ^ string_of_int (j + 1) ^ " of " ^
   920                 List.partition (#unsound o snd) (!generated_problems)
   926                 List.partition (#unsound o snd) (!generated_problems)
   921             in
   927             in
   922               if not (null sound_problems) andalso
   928               if not (null sound_problems) andalso
   923                  forall (KK.is_problem_trivially_false o fst)
   929                  forall (KK.is_problem_trivially_false o fst)
   924                         sound_problems then
   930                         sound_problems then
   925                 print_m (fn () =>
   931                 print_n (fn () =>
   926                     "Warning: The conjecture either trivially holds for the \
   932                     "Warning: The conjecture either trivially holds for the \
   927                     \given scopes or lies outside Nitpick's supported \
   933                     \given scopes or lies outside Nitpick's supported \
   928                     \fragment." ^
   934                     \fragment." ^
   929                     (if exists (not o KK.is_problem_trivially_false o fst)
   935                     (if exists (not o KK.is_problem_trivially_false o fst)
   930                                unsound_problems then
   936                                unsound_problems then
   970     val (skipped, the_scopes) =
   976     val (skipped, the_scopes) =
   971       all_scopes hol_ctxt binarize cards_assigns maxes_assigns iters_assigns
   977       all_scopes hol_ctxt binarize cards_assigns maxes_assigns iters_assigns
   972                  bitss bisim_depths mono_Ts nonmono_Ts deep_dataTs
   978                  bitss bisim_depths mono_Ts nonmono_Ts deep_dataTs
   973                  finitizable_dataTs
   979                  finitizable_dataTs
   974     val _ = if skipped > 0 then
   980     val _ = if skipped > 0 then
   975               print_m (fn () => "Too many scopes. Skipping " ^
   981               print_n (fn () => "Too many scopes. Skipping " ^
   976                                 string_of_int skipped ^ " scope" ^
   982                                 string_of_int skipped ^ " scope" ^
   977                                 plural_s skipped ^
   983                                 plural_s skipped ^
   978                                 ". (Consider using \"mono\" or \
   984                                 ". (Consider using \"mono\" or \
   979                                 \\"merge_type_vars\" to prevent this.)")
   985                                 \\"merge_type_vars\" to prevent this.)")
   980             else
   986             else
   982     val _ = scopes := the_scopes
   988     val _ = scopes := the_scopes
   983 
   989 
   984     fun run_batches _ _ []
   990     fun run_batches _ _ []
   985                     (found_really_genuine, max_potential, max_genuine, donno) =
   991                     (found_really_genuine, max_potential, max_genuine, donno) =
   986         if donno > 0 andalso max_genuine > 0 then
   992         if donno > 0 andalso max_genuine > 0 then
   987           (print_m (fn () => excipit "checked"); unknownN)
   993           (print_n (fn () => excipit "checked"); unknownN)
   988         else if max_genuine = original_max_genuine then
   994         else if max_genuine = original_max_genuine then
   989           if max_potential = original_max_potential then
   995           if max_potential = original_max_potential then
   990             (print_m (fn () =>
   996             (print_n (fn () =>
   991                  "Nitpick found no " ^ das_wort_model ^ "." ^
   997                  "Nitpick found no " ^ das_wort_model ^ "." ^
   992                  (if not standard andalso likely_in_struct_induct_step then
   998                  (if not standard andalso likely_in_struct_induct_step then
   993                     " This suggests that the induction hypothesis might be \
   999                     " This suggests that the induction hypothesis might be \
   994                     \general enough to prove this subgoal."
  1000                     \general enough to prove this subgoal."
   995                   else
  1001                   else
   996                     "")); if skipped > 0 then unknownN else noneN)
  1002                     "")); if skipped > 0 then unknownN else noneN)
   997           else
  1003           else
   998             (print_m (fn () =>
  1004             (print_n (fn () =>
   999                  excipit ("could not find a" ^
  1005                  excipit ("could not find a" ^
  1000                           (if max_genuine = 1 then
  1006                           (if max_genuine = 1 then
  1001                              " better " ^ das_wort_model ^ "."
  1007                              " better " ^ das_wort_model ^ "."
  1002                            else
  1008                            else
  1003                              "ny better " ^ das_wort_model ^ "s.") ^
  1009                              "ny better " ^ das_wort_model ^ "s.") ^
  1015     val batches = batch_list batch_size (!scopes)
  1021     val batches = batch_list batch_size (!scopes)
  1016     val outcome_code =
  1022     val outcome_code =
  1017       run_batches 0 (length batches) batches
  1023       run_batches 0 (length batches) batches
  1018                   (false, max_potential, max_genuine, 0)
  1024                   (false, max_potential, max_genuine, 0)
  1019       handle TimeLimit.TimeOut =>
  1025       handle TimeLimit.TimeOut =>
  1020              (print_m (fn () => excipit "ran out of time after checking");
  1026              (print_n (fn () => excipit "ran out of time after checking");
  1021               if !met_potential > 0 then potentialN else unknownN)
  1027               if !met_potential > 0 then potentialN else unknownN)
  1022     val _ = print_v (fn () =>
  1028     val _ = print_v (fn () =>
  1023                 "Total time: " ^ string_from_time (Timer.checkRealTimer timer) ^
  1029                 "Total time: " ^ string_from_time (Timer.checkRealTimer timer) ^
  1024                 ".")
  1030                 ".")
  1025   in (outcome_code, !state_ref) end
  1031   in (outcome_code, !state_ref) end
  1026 
  1032 
  1027 (* Give the inner timeout a chance. *)
  1033 (* Give the inner timeout a chance. *)
  1028 val timeout_bonus = seconds 1.0
  1034 val timeout_bonus = seconds 1.0
  1029 
  1035 
  1030 fun pick_nits_in_term state (params as {debug, timeout, expect, ...}) auto i n
  1036 fun pick_nits_in_term state (params as {debug, timeout, expect, ...}) mode i n
  1031                       step subst assm_ts orig_t =
  1037                       step subst assm_ts orig_t =
  1032   let val print_m = if auto then K () else Output.urgent_message in
  1038   let val print_n = if mode = Normal then Output.urgent_message else K () in
  1033     if getenv "KODKODI" = "" then
  1039     if getenv "KODKODI" = "" then
  1034       (* The "expect" argument is deliberately ignored if Kodkodi is missing so
  1040       (* The "expect" argument is deliberately ignored if Kodkodi is missing so
  1035          that the "Nitpick_Examples" can be processed on any machine. *)
  1041          that the "Nitpick_Examples" can be processed on any machine. *)
  1036       (print_m (Pretty.string_of (plazy install_kodkodi_message));
  1042       (print_n (Pretty.string_of (plazy install_kodkodi_message));
  1037        ("no_kodkodi", state))
  1043        ("no_kodkodi", state))
  1038     else
  1044     else
  1039       let
  1045       let
  1040         val unknown_outcome = (unknownN, state)
  1046         val unknown_outcome = (unknownN, state)
  1041         val deadline = Option.map (curry Time.+ (Time.now ())) timeout
  1047         val deadline = Option.map (curry Time.+ (Time.now ())) timeout
  1042         val outcome as (outcome_code, _) =
  1048         val outcome as (outcome_code, _) =
  1043           time_limit (if debug orelse is_none timeout then NONE
  1049           time_limit (if debug orelse is_none timeout then NONE
  1044                       else SOME (Time.+ (the timeout, timeout_bonus)))
  1050                       else SOME (Time.+ (the timeout, timeout_bonus)))
  1045               (pick_them_nits_in_term deadline state params auto i n step subst
  1051               (pick_them_nits_in_term deadline state params mode i n step subst
  1046                                       assm_ts) orig_t
  1052                                       assm_ts) orig_t
  1047           handle TOO_LARGE (_, details) =>
  1053           handle TOO_LARGE (_, details) =>
  1048                  (print_m ("Limit reached: " ^ details ^ "."); unknown_outcome)
  1054                  (print_n ("Limit reached: " ^ details ^ "."); unknown_outcome)
  1049                | TOO_SMALL (_, details) =>
  1055                | TOO_SMALL (_, details) =>
  1050                  (print_m ("Limit reached: " ^ details ^ "."); unknown_outcome)
  1056                  (print_n ("Limit reached: " ^ details ^ "."); unknown_outcome)
  1051                | Kodkod.SYNTAX (_, details) =>
  1057                | Kodkod.SYNTAX (_, details) =>
  1052                  (print_m ("Malformed Kodkodi output: " ^ details ^ ".");
  1058                  (print_n ("Malformed Kodkodi output: " ^ details ^ ".");
  1053                   unknown_outcome)
  1059                   unknown_outcome)
  1054                | TimeLimit.TimeOut =>
  1060                | TimeLimit.TimeOut =>
  1055                  (print_m "Nitpick ran out of time."; unknown_outcome)
  1061                  (print_n "Nitpick ran out of time."; unknown_outcome)
  1056       in
  1062       in
  1057         if expect = "" orelse outcome_code = expect then outcome
  1063         if expect = "" orelse outcome_code = expect then outcome
  1058         else error ("Unexpected outcome: " ^ quote outcome_code ^ ".")
  1064         else error ("Unexpected outcome: " ^ quote outcome_code ^ ".")
  1059       end
  1065       end
  1060   end
  1066   end
  1068     val (subst, other_assms) =
  1074     val (subst, other_assms) =
  1069       List.partition (is_fixed_equation ctxt) assms
  1075       List.partition (is_fixed_equation ctxt) assms
  1070       |>> map Logic.dest_equals
  1076       |>> map Logic.dest_equals
  1071   in (subst, other_assms, subst_atomic subst t) end
  1077   in (subst, other_assms, subst_atomic subst t) end
  1072 
  1078 
  1073 fun pick_nits_in_subgoal state params auto i step =
  1079 fun pick_nits_in_subgoal state params mode i step =
  1074   let
  1080   let
  1075     val ctxt = Proof.context_of state
  1081     val ctxt = Proof.context_of state
  1076     val t = state |> Proof.raw_goal |> #goal |> prop_of
  1082     val t = state |> Proof.raw_goal |> #goal |> prop_of
  1077   in
  1083   in
  1078     case Logic.count_prems t of
  1084     case Logic.count_prems t of
  1080     | n =>
  1086     | n =>
  1081       let
  1087       let
  1082         val t = Logic.goal_params t i |> fst
  1088         val t = Logic.goal_params t i |> fst
  1083         val assms = map term_of (Assumption.all_assms_of ctxt)
  1089         val assms = map term_of (Assumption.all_assms_of ctxt)
  1084         val (subst, assms, t) = extract_fixed_frees ctxt (assms, t)
  1090         val (subst, assms, t) = extract_fixed_frees ctxt (assms, t)
  1085       in pick_nits_in_term state params auto i n step subst assms t end
  1091       in pick_nits_in_term state params mode i n step subst assms t end
  1086   end
  1092   end
  1087 
  1093 
  1088 end;
  1094 end;