src/HOL/Tools/Nitpick/nitpick_isar.ML
changeset 33552 ab01b72715ef
parent 33547 cba22e2999d5
child 33557 1c62ac4ef6d1
equal deleted inserted replaced
33551:b12ab081e5d1 33552:ab01b72715ef
     8 
     8 
     9 signature NITPICK_ISAR =
     9 signature NITPICK_ISAR =
    10 sig
    10 sig
    11   type params = Nitpick.params
    11   type params = Nitpick.params
    12 
    12 
       
    13   val auto: bool Unsynchronized.ref
    13   val default_params : theory -> (string * string) list -> params
    14   val default_params : theory -> (string * string) list -> params
       
    15   val setup : theory -> theory
    14 end
    16 end
    15 
    17 
    16 structure Nitpick_Isar : NITPICK_ISAR =
    18 structure Nitpick_Isar : NITPICK_ISAR =
    17 struct
    19 struct
    18 
    20 
    19 open Nitpick_Util
    21 open Nitpick_Util
    20 open Nitpick_HOL
    22 open Nitpick_HOL
    21 open Nitpick_Rep
    23 open Nitpick_Rep
    22 open Nitpick_Nut
    24 open Nitpick_Nut
    23 open Nitpick
    25 open Nitpick
       
    26 
       
    27 val auto = Unsynchronized.ref false;
       
    28 
       
    29 val _ = ProofGeneralPgip.add_preference Preferences.category_tracing
       
    30             (setmp_CRITICAL auto false
       
    31                  (fn () => Preferences.bool_pref auto
       
    32                                "auto-nitpick"
       
    33                                "Whether to run Nitpick automatically.") ())
    24 
    34 
    25 type raw_param = string * string list
    35 type raw_param = string * string list
    26 
    36 
    27 val default_default_params =
    37 val default_default_params =
    28   [("card", ["1\<midarrow>8"]),
    38   [("card", ["1\<midarrow>8"]),
    31    ("box", ["smart"]),
    41    ("box", ["smart"]),
    32    ("mono", ["smart"]),
    42    ("mono", ["smart"]),
    33    ("wf", ["smart"]),
    43    ("wf", ["smart"]),
    34    ("sat_solver", ["smart"]),
    44    ("sat_solver", ["smart"]),
    35    ("batch_size", ["smart"]),
    45    ("batch_size", ["smart"]),
    36    ("auto", ["false"]),
       
    37    ("blocking", ["true"]),
    46    ("blocking", ["true"]),
    38    ("falsify", ["true"]),
    47    ("falsify", ["true"]),
    39    ("user_axioms", ["smart"]),
    48    ("user_axioms", ["smart"]),
    40    ("assms", ["true"]),
    49    ("assms", ["true"]),
    41    ("merge_type_vars", ["false"]),
    50    ("merge_type_vars", ["false"]),
    45    ("star_linear_preds", ["true"]),
    54    ("star_linear_preds", ["true"]),
    46    ("uncurry", ["true"]),
    55    ("uncurry", ["true"]),
    47    ("fast_descrs", ["true"]),
    56    ("fast_descrs", ["true"]),
    48    ("peephole_optim", ["true"]),
    57    ("peephole_optim", ["true"]),
    49    ("timeout", ["30 s"]),
    58    ("timeout", ["30 s"]),
    50    ("auto_timeout", ["5 s"]),
       
    51    ("tac_timeout", ["500 ms"]),
    59    ("tac_timeout", ["500 ms"]),
    52    ("sym_break", ["20"]),
    60    ("sym_break", ["20"]),
    53    ("sharing_depth", ["3"]),
    61    ("sharing_depth", ["3"]),
    54    ("flatten_props", ["false"]),
    62    ("flatten_props", ["false"]),
    55    ("max_threads", ["0"]),
    63    ("max_threads", ["0"]),
    68 
    76 
    69 val negated_params =
    77 val negated_params =
    70   [("dont_box", "box"),
    78   [("dont_box", "box"),
    71    ("non_mono", "mono"),
    79    ("non_mono", "mono"),
    72    ("non_wf", "wf"),
    80    ("non_wf", "wf"),
    73    ("no_auto", "auto"),
       
    74    ("non_blocking", "blocking"),
    81    ("non_blocking", "blocking"),
    75    ("satisfy", "falsify"),
    82    ("satisfy", "falsify"),
    76    ("no_user_axioms", "user_axioms"),
    83    ("no_user_axioms", "user_axioms"),
    77    ("no_assms", "assms"),
    84    ("no_assms", "assms"),
    78    ("dont_merge_type_vars", "merge_type_vars"),
    85    ("dont_merge_type_vars", "merge_type_vars"),
   124                           | [] => ["false"]
   131                           | [] => ["false"]
   125                           | _ => value)
   132                           | _ => value)
   126   | NONE => (name, value)
   133   | NONE => (name, value)
   127 
   134 
   128 structure TheoryData = TheoryDataFun(
   135 structure TheoryData = TheoryDataFun(
   129   type T = {params: raw_param list, registered_auto: bool}
   136   type T = {params: raw_param list}
   130   val empty = {params = rev default_default_params, registered_auto = false}
   137   val empty = {params = rev default_default_params}
   131   val copy = I
   138   val copy = I
   132   val extend = I
   139   val extend = I
   133   fun merge _ ({params = ps1, registered_auto = a1},
   140   fun merge _ ({params = ps1}, {params = ps2}) =
   134                {params = ps2, registered_auto = a2}) =
   141     {params = AList.merge (op =) (op =) (ps1, ps2)})
   135     {params = AList.merge (op =) (op =) (ps1, ps2),
       
   136      registered_auto = a1 orelse a2})
       
   137 
   142 
   138 (* raw_param -> theory -> theory *)
   143 (* raw_param -> theory -> theory *)
   139 fun set_default_raw_param param thy =
   144 fun set_default_raw_param param thy =
   140   let val {params, registered_auto} = TheoryData.get thy in
   145   let val {params} = TheoryData.get thy in
   141     TheoryData.put
   146     TheoryData.put
   142       {params = AList.update (op =) (unnegate_raw_param param) params,
   147         {params = AList.update (op =) (unnegate_raw_param param) params} thy
   143        registered_auto = registered_auto} thy
       
   144   end
   148   end
   145 (* theory -> raw_param list *)
   149 (* theory -> raw_param list *)
   146 val default_raw_params = #params o TheoryData.get
   150 val default_raw_params = #params o TheoryData.get
   147 
       
   148 (* theory -> theory *)
       
   149 fun set_registered_auto thy =
       
   150   TheoryData.put {params = default_raw_params thy, registered_auto = true} thy
       
   151 (* theory -> bool *)
       
   152 val is_registered_auto = #registered_auto o TheoryData.get
       
   153 
   151 
   154 (* string -> bool *)
   152 (* string -> bool *)
   155 fun is_punctuation s = (s = "," orelse s = "-" orelse s = "\<midarrow>")
   153 fun is_punctuation s = (s = "," orelse s = "-" orelse s = "\<midarrow>")
   156 
   154 
   157 (* string list -> string *)
   155 (* string list -> string *)
   311     val skolemize = lookup_bool "skolemize"
   309     val skolemize = lookup_bool "skolemize"
   312     val star_linear_preds = lookup_bool "star_linear_preds"
   310     val star_linear_preds = lookup_bool "star_linear_preds"
   313     val uncurry = lookup_bool "uncurry"
   311     val uncurry = lookup_bool "uncurry"
   314     val fast_descrs = lookup_bool "fast_descrs"
   312     val fast_descrs = lookup_bool "fast_descrs"
   315     val peephole_optim = lookup_bool "peephole_optim"
   313     val peephole_optim = lookup_bool "peephole_optim"
   316     val timeout = if auto then lookup_time "auto_timeout"
   314     val timeout = if auto then NONE else lookup_time "timeout"
   317                   else lookup_time "timeout"
       
   318     val tac_timeout = lookup_time "tac_timeout"
   315     val tac_timeout = lookup_time "tac_timeout"
   319     val sym_break = Int.max (0, lookup_int "sym_break")
   316     val sym_break = Int.max (0, lookup_int "sym_break")
   320     val sharing_depth = Int.max (1, lookup_int "sharing_depth")
   317     val sharing_depth = Int.max (1, lookup_int "sharing_depth")
   321     val flatten_props = lookup_bool "flatten_props"
   318     val flatten_props = lookup_bool "flatten_props"
   322     val max_threads = Int.max (0, lookup_int "max_threads")
   319     val max_threads = Int.max (0, lookup_int "max_threads")
   324     val show_skolems = show_all orelse lookup_bool "show_skolems"
   321     val show_skolems = show_all orelse lookup_bool "show_skolems"
   325     val show_datatypes = show_all orelse lookup_bool "show_datatypes"
   322     val show_datatypes = show_all orelse lookup_bool "show_datatypes"
   326     val show_consts = show_all orelse lookup_bool "show_consts"
   323     val show_consts = show_all orelse lookup_bool "show_consts"
   327     val formats = lookup_ints_assigns read_term_polymorphic "format" 0
   324     val formats = lookup_ints_assigns read_term_polymorphic "format" 0
   328     val evals = lookup_term_list "eval"
   325     val evals = lookup_term_list "eval"
   329     val max_potential = if auto then 0
   326     val max_potential =
   330                         else Int.max (0, lookup_int "max_potential")
   327       if auto then 0 else Int.max (0, lookup_int "max_potential")
   331     val max_genuine = Int.max (0, lookup_int "max_genuine")
   328     val max_genuine = Int.max (0, lookup_int "max_genuine")
   332     val check_potential = lookup_bool "check_potential"
   329     val check_potential = lookup_bool "check_potential"
   333     val check_genuine = lookup_bool "check_genuine"
   330     val check_genuine = lookup_bool "check_genuine"
   334     val batch_size = case lookup_int_option "batch_size" of
   331     val batch_size = case lookup_int_option "batch_size" of
   335                        SOME n => Int.max (1, n)
   332                        SOME n => Int.max (1, n)
   410        | Kodkod.SYNTAX (_, details) =>
   407        | Kodkod.SYNTAX (_, details) =>
   411          (warning ("Ill-formed Kodkodi output: " ^ details ^ "."); x)
   408          (warning ("Ill-formed Kodkodi output: " ^ details ^ "."); x)
   412        | Refute.REFUTE (loc, details) =>
   409        | Refute.REFUTE (loc, details) =>
   413          error ("Unhandled Refute error (" ^ quote loc ^ "): " ^ details ^ ".")
   410          error ("Unhandled Refute error (" ^ quote loc ^ "): " ^ details ^ ".")
   414 
   411 
   415 (* raw_param list -> bool -> int -> Proof.state -> Proof.state *)
   412 (* raw_param list -> bool -> int -> Proof.state -> bool * Proof.state *)
   416 fun pick_nits override_params auto subgoal state =
   413 fun pick_nits override_params auto subgoal state =
   417   let
   414   let
   418     val thy = Proof.theory_of state
   415     val thy = Proof.theory_of state
   419     val ctxt = Proof.context_of state
   416     val ctxt = Proof.context_of state
   420     val thm = snd (snd (Proof.get_goal state))
   417     val thm = state |> Proof.get_goal |> snd |> snd
   421     val _ = List.app check_raw_param override_params
   418     val _ = List.app check_raw_param override_params
   422     val params as {blocking, debug, ...} =
   419     val params as {blocking, debug, ...} =
   423       extract_params ctxt auto (default_raw_params thy) override_params
   420       extract_params ctxt auto (default_raw_params thy) override_params
   424     (* unit -> Proof.state *)
   421     (* unit -> bool * Proof.state *)
   425     fun go () =
   422     fun go () =
   426       (if auto then perhaps o try
   423       (false, state)
   427        else if debug then fn f => fn x => f x
   424       |> (if auto then perhaps o try
   428        else handle_exceptions ctxt)
   425           else if debug then fn f => fn x => f x
   429       (fn state => pick_nits_in_subgoal state params auto subgoal |> snd)
   426           else handle_exceptions ctxt)
   430       state
   427          (fn (_, state) => pick_nits_in_subgoal state params auto subgoal
       
   428                            |>> equal "genuine")
   431   in
   429   in
   432     if auto orelse blocking then
   430     if auto orelse blocking then go ()
   433       go ()
   431     else (SimpleThread.fork true (fn () => (go (); ())); (false, state))
   434     else
       
   435       (SimpleThread.fork true (fn () => (go (); ()));
       
   436        state)
       
   437   end
   432   end
   438 
   433 
   439 (* (TableFun().key * string list) list option * int option
   434 (* (TableFun().key * string list) list option * int option
   440    -> Toplevel.transition -> Toplevel.transition *)
   435    -> Toplevel.transition -> Toplevel.transition *)
   441 fun nitpick_trans (opt_params, opt_subgoal) =
   436 fun nitpick_trans (opt_params, opt_subgoal) =
   442   Toplevel.keep (K ()
   437   Toplevel.keep (K ()
   443       o pick_nits (these opt_params) false (the_default 1 opt_subgoal)
   438       o snd o pick_nits (these opt_params) false (the_default 1 opt_subgoal)
   444       o Toplevel.proof_of)
   439       o Toplevel.proof_of)
   445 
   440 
   446 (* raw_param -> string *)
   441 (* raw_param -> string *)
   447 fun string_for_raw_param (name, value) =
   442 fun string_for_raw_param (name, value) =
   448   name ^ " = " ^ stringify_raw_param_value value
   443   name ^ " = " ^ stringify_raw_param_value value
   449 
       
   450 (* bool -> Proof.state -> Proof.state *)
       
   451 fun pick_nits_auto interactive state =
       
   452   let val thy = Proof.theory_of state in
       
   453     ((interactive andalso not (!Toplevel.quiet)
       
   454       andalso the (general_lookup_bool false (default_raw_params thy)
       
   455                   (SOME false) "auto"))
       
   456      ? pick_nits [] true 0) state
       
   457   end
       
   458 
       
   459 (* theory -> theory *)
       
   460 fun register_auto thy =
       
   461   (not (is_registered_auto thy)
       
   462    ? (set_registered_auto
       
   463       #> Context.theory_map (Specification.add_theorem_hook pick_nits_auto)))
       
   464   thy
       
   465 
   444 
   466 (* (TableFun().key * string) list option -> Toplevel.transition
   445 (* (TableFun().key * string) list option -> Toplevel.transition
   467    -> Toplevel.transition *)
   446    -> Toplevel.transition *)
   468 fun nitpick_params_trans opt_params =
   447 fun nitpick_params_trans opt_params =
   469   Toplevel.theory
   448   Toplevel.theory
   470       (fn thy =>
   449       (fold set_default_raw_param (these opt_params)
   471           let val thy = fold set_default_raw_param (these opt_params) thy in
   450        #> tap (fn thy => 
   472             writeln ("Default parameters for Nitpick:\n" ^
   451                   writeln ("Default parameters for Nitpick:\n" ^
   473                      (case rev (default_raw_params thy) of
   452                            (case rev (default_raw_params thy) of
   474                         [] => "none"
   453                               [] => "none"
   475                       | params =>
   454                             | params =>
   476                         (map check_raw_param params;
   455                               (map check_raw_param params;
   477                          params |> map string_for_raw_param |> sort_strings
   456                                params |> map string_for_raw_param
   478                                 |> cat_lines)));
   457                                       |> sort_strings |> cat_lines)))))
   479             register_auto thy
       
   480           end)
       
   481 
   458 
   482 (* OuterParse.token list
   459 (* OuterParse.token list
   483    -> (Toplevel.transition -> Toplevel.transition) * OuterParse.token list *)
   460    -> (Toplevel.transition -> Toplevel.transition) * OuterParse.token list *)
   484 fun scan_nitpick_command tokens =
   461 val scan_nitpick_command =
   485   (scan_params -- Scan.option OuterParse.nat) tokens |>> nitpick_trans
   462   (scan_params -- Scan.option OuterParse.nat) #>> nitpick_trans
   486 fun scan_nitpick_params_command tokens =
   463 val scan_nitpick_params_command = scan_params #>> nitpick_params_trans
   487   scan_params tokens |>> nitpick_params_trans
       
   488 
   464 
   489 val _ = OuterSyntax.improper_command "nitpick"
   465 val _ = OuterSyntax.improper_command "nitpick"
   490             "try to find a counterexample for a given subgoal using Kodkod"
   466             "try to find a counterexample for a given subgoal using Kodkod"
   491             OuterKeyword.diag scan_nitpick_command
   467             OuterKeyword.diag scan_nitpick_command
   492 val _ = OuterSyntax.command "nitpick_params"
   468 val _ = OuterSyntax.command "nitpick_params"
   493             "set and display the default parameters for Nitpick"
   469             "set and display the default parameters for Nitpick"
   494             OuterKeyword.thy_decl scan_nitpick_params_command
   470             OuterKeyword.thy_decl scan_nitpick_params_command
   495 
   471 
       
   472 (* Proof.state -> bool * Proof.state *)
       
   473 fun auto_nitpick state =
       
   474   if not (!auto) then (false, state) else pick_nits [] true 1 state
       
   475 
       
   476 val setup = Auto_Counterexample.register_tool ("nitpick", auto_nitpick)
       
   477 
   496 end;
   478 end;