added yet another hint to Nitpick's output, this time warning about problems for which nothing was effectively tested
authorblanchet
Wed, 17 Feb 2010 12:14:08 +0100
changeset 35185 9b8f351cced6
parent 35184 a219865c02c9
child 35186 bb64d089c643
added yet another hint to Nitpick's output, this time warning about problems for which nothing was effectively tested
doc-src/Nitpick/nitpick.tex
src/HOL/Nitpick_Examples/Manual_Nits.thy
src/HOL/Tools/Nitpick/kodkod.ML
src/HOL/Tools/Nitpick/minipick.ML
src/HOL/Tools/Nitpick/nitpick.ML
src/HOL/Tools/Nitpick/nitpick_kodkod.ML
src/HOL/Tools/Nitpick/nitpick_nut.ML
src/HOL/Tools/Nitpick/nitpick_tests.ML
--- a/doc-src/Nitpick/nitpick.tex	Wed Feb 17 11:20:09 2010 +0100
+++ b/doc-src/Nitpick/nitpick.tex	Wed Feb 17 12:14:08 2010 +0100
@@ -472,7 +472,9 @@
 \prew
 \textbf{lemma} ``$\forall n.\; \textit{Suc}~n \mathbin{\not=} n \,\Longrightarrow\, P$'' \\
 \textbf{nitpick} [\textit{card~nat}~= 100, \textit{check\_potential}] \\[2\smallskipamount]
-\slshape Nitpick found a potential counterexample: \\[2\smallskipamount]
+\slshape Warning: The conjecture either trivially holds or (more likely) lies outside Nitpick's supported
+fragment. Only potential counterexamples may be found. \\[2\smallskipamount]
+Nitpick found a potential counterexample: \\[2\smallskipamount]
 \hbox{}\qquad Free variable: \nopagebreak \\
 \hbox{}\qquad\qquad $P = \textit{False}$ \\[2\smallskipamount]
 Confirmation by ``\textit{auto}'': The above counterexample is genuine.
--- a/src/HOL/Nitpick_Examples/Manual_Nits.thy	Wed Feb 17 11:20:09 2010 +0100
+++ b/src/HOL/Nitpick_Examples/Manual_Nits.thy	Wed Feb 17 12:14:08 2010 +0100
@@ -266,7 +266,7 @@
 next
   case (Branch t u) thus ?case
   nitpick
-  nitpick [non_std "'a bin_tree", show_consts]
+  nitpick [non_std, show_all]
 oops
 
 lemma "labels (swap t a b) =
--- a/src/HOL/Tools/Nitpick/kodkod.ML	Wed Feb 17 11:20:09 2010 +0100
+++ b/src/HOL/Tools/Nitpick/kodkod.ML	Wed Feb 17 12:14:08 2010 +0100
@@ -167,6 +167,7 @@
 
   val max_arity : int -> int
   val arity_of_rel_expr : rel_expr -> int
+  val is_problem_trivially_false : problem -> bool
   val problems_equivalent : problem -> problem -> bool
   val solve_any_problem :
     bool -> Time.time option -> int -> int -> problem list -> outcome
@@ -491,6 +492,10 @@
   | arity_of_decl (DeclSome ((n, _), _)) = n
   | arity_of_decl (DeclSet ((n, _), _)) = n
 
+(* problem -> bool *)
+fun is_problem_trivially_false ({formula = False, ...} : problem) = true
+  | is_problem_trivially_false _ = false
+
 (* string -> bool *)
 val is_relevant_setting = not o member (op =) ["solver", "delay"]
 
@@ -1014,7 +1019,7 @@
     val indexed_problems = if j >= 0 then
                              [(j, nth problems j)]
                            else
-                             filter (not_equal False o #formula o snd)
+                             filter (is_problem_trivially_false o snd)
                                     (0 upto length problems - 1 ~~ problems)
     val triv_js = filter_out (AList.defined (op =) indexed_problems)
                              (0 upto length problems - 1)
--- a/src/HOL/Tools/Nitpick/minipick.ML	Wed Feb 17 11:20:09 2010 +0100
+++ b/src/HOL/Tools/Nitpick/minipick.ML	Wed Feb 17 12:14:08 2010 +0100
@@ -84,7 +84,7 @@
 fun atom_from_formula f = RelIf (f, true_atom, false_atom)
 
 (* Proof.context -> (typ -> int) -> styp list -> term -> formula *)
-fun kodkod_formula_for_term ctxt card frees =
+fun kodkod_formula_from_term ctxt card frees =
   let
     (* typ -> rel_expr -> rel_expr *)
     fun R_rep_from_S_rep (T as Type ("fun", [T1, @{typ bool}])) r =
@@ -145,7 +145,7 @@
        | Term.Var _ => raise SAME ()
        | Bound _ => raise SAME ()
        | Const (s, _) => raise NOT_SUPPORTED ("constant " ^ quote s)
-       | _ => raise TERM ("Minipick.kodkod_formula_for_term.to_F", [t]))
+       | _ => raise TERM ("Minipick.kodkod_formula_from_term.to_F", [t]))
       handle SAME () => formula_from_atom (to_R_rep Ts t)
     (* typ list -> term -> rel_expr *)
     and to_S_rep Ts t =
@@ -306,7 +306,7 @@
     val bounds = map2 (bound_for_free card) (index_seq 0 (length frees)) frees
     val declarative_axioms =
       map2 (declarative_axiom_for_free card) (index_seq 0 (length frees)) frees
-    val formula = kodkod_formula_for_term ctxt card frees neg_t
+    val formula = kodkod_formula_from_term ctxt card frees neg_t
                   |> fold_rev (curry And) declarative_axioms
     val univ_card = univ_card 0 0 0 bounds formula
     val problem =
--- a/src/HOL/Tools/Nitpick/nitpick.ML	Wed Feb 17 11:20:09 2010 +0100
+++ b/src/HOL/Tools/Nitpick/nitpick.ML	Wed Feb 17 12:14:08 2010 +0100
@@ -130,7 +130,7 @@
   sel_names: nut list,
   nonsel_names: nut list,
   rel_table: nut NameTable.table,
-  liberal: bool,
+  unsound: bool,
   scope: scope,
   core: KK.formula,
   defs: KK.formula list}
@@ -157,15 +157,15 @@
       (Path.variable "ISABELLE_HOME_USER" ::
        map Path.basic ["etc", "components"]))) ^ "\"."
 
-val max_liberal_delay_ms = 200
-val max_liberal_delay_percent = 2
+val max_unsound_delay_ms = 200
+val max_unsound_delay_percent = 2
 
 (* Time.time option -> int *)
-fun liberal_delay_for_timeout NONE = max_liberal_delay_ms
-  | liberal_delay_for_timeout (SOME timeout) =
-    Int.max (0, Int.min (max_liberal_delay_ms,
+fun unsound_delay_for_timeout NONE = max_unsound_delay_ms
+  | unsound_delay_for_timeout (SOME timeout) =
+    Int.max (0, Int.min (max_unsound_delay_ms,
                          Time.toMilliseconds timeout
-                         * max_liberal_delay_percent div 100))
+                         * max_unsound_delay_percent div 100))
 
 (* Time.time option -> bool *)
 fun passed_deadline NONE = false
@@ -434,7 +434,7 @@
     val too_big_scopes = Unsynchronized.ref []
 
     (* bool -> scope -> rich_problem option *)
-    fun problem_for_scope liberal
+    fun problem_for_scope unsound
             (scope as {card_assigns, bits, bisim_depth, datatypes, ofs, ...}) =
       let
         val _ = not (exists (fn other => scope_less_eq other scope)
@@ -469,10 +469,10 @@
                          (univ_card nat_card int_card main_j0 [] KK.True)
         val _ = check_arity min_univ_card min_highest_arity
 
-        val core_u = choose_reps_in_nut scope liberal rep_table false core_u
-        val def_us = map (choose_reps_in_nut scope liberal rep_table true)
+        val core_u = choose_reps_in_nut scope unsound rep_table false core_u
+        val def_us = map (choose_reps_in_nut scope unsound rep_table true)
                          def_us
-        val nondef_us = map (choose_reps_in_nut scope liberal rep_table false)
+        val nondef_us = map (choose_reps_in_nut scope unsound rep_table false)
                             nondef_us
 (*
         val _ = List.app (priority o string_for_nut ctxt)
@@ -488,21 +488,19 @@
         val core_u = rename_vars_in_nut pool rel_table core_u
         val def_us = map (rename_vars_in_nut pool rel_table) def_us
         val nondef_us = map (rename_vars_in_nut pool rel_table) nondef_us
-        (* nut -> KK.formula *)
-        val to_f = kodkod_formula_from_nut bits ofs liberal kk
-        val core_f = to_f core_u
-        val def_fs = map to_f def_us
-        val nondef_fs = map to_f nondef_us
+        val core_f = kodkod_formula_from_nut bits ofs kk core_u
+        val def_fs = map (kodkod_formula_from_nut bits ofs kk) def_us
+        val nondef_fs = map (kodkod_formula_from_nut bits ofs kk) nondef_us
         val formula = fold (fold s_and) [def_fs, nondef_fs] core_f
-        val comment = (if liberal then "liberal" else "conservative") ^ "\n" ^
+        val comment = (if unsound then "unsound" else "sound") ^ "\n" ^
                       PrintMode.setmp [] multiline_string_for_scope scope
         val kodkod_sat_solver =
           Kodkod_SAT.sat_solver_spec effective_sat_solver |> snd
         val bit_width = if bits = 0 then 16 else bits + 1
-        val delay = if liberal then
+        val delay = if unsound then
                       Option.map (fn time => Time.- (time, Time.now ()))
                                  deadline
-                      |> liberal_delay_for_timeout
+                      |> unsound_delay_for_timeout
                     else
                       0
         val settings = [("solver", commas (map quote kodkod_sat_solver)),
@@ -540,13 +538,13 @@
                expr_assigns = [], formula = formula},
               {free_names = free_names, sel_names = sel_names,
                nonsel_names = nonsel_names, rel_table = rel_table,
-               liberal = liberal, scope = scope, core = core_f,
+               unsound = unsound, scope = scope, core = core_f,
                defs = nondef_fs @ def_fs @ declarative_axioms})
       end
       handle TOO_LARGE (loc, msg) =>
              if loc = "Nitpick_Kodkod.check_arity" andalso
                 not (Typtab.is_empty ofs) then
-               problem_for_scope liberal
+               problem_for_scope unsound
                    {hol_ctxt = hol_ctxt, card_assigns = card_assigns,
                     bits = bits, bisim_depth = bisim_depth,
                     datatypes = datatypes, ofs = Typtab.empty}
@@ -556,13 +554,13 @@
              else
                (Unsynchronized.change too_big_scopes (cons scope);
                 print_v (fn () => ("Limit reached: " ^ msg ^
-                                   ". Skipping " ^ (if liberal then "potential"
+                                   ". Skipping " ^ (if unsound then "potential"
                                                     else "genuine") ^
                                    " component of scope."));
                 NONE)
            | TOO_SMALL (loc, msg) =>
              (print_v (fn () => ("Limit reached: " ^ msg ^
-                                 ". Skipping " ^ (if liberal then "potential"
+                                 ". Skipping " ^ (if unsound then "potential"
                                                   else "genuine") ^
                                  " component of scope."));
               NONE)
@@ -577,7 +575,7 @@
 
     val scopes = Unsynchronized.ref []
     val generated_scopes = Unsynchronized.ref []
-    val generated_problems = Unsynchronized.ref []
+    val generated_problems = Unsynchronized.ref ([] : rich_problem list)
     val checked_problems = Unsynchronized.ref (SOME [])
     val met_potential = Unsynchronized.ref 0
 
@@ -711,7 +709,7 @@
           | KK.Normal (sat_ps, unsat_js) =>
             let
               val (lib_ps, con_ps) =
-                List.partition (#liberal o snd o nth problems o fst) sat_ps
+                List.partition (#unsound o snd o nth problems o fst) sat_ps
             in
               update_checked_problems problems (unsat_js @ map fst lib_ps);
               if null con_ps then
@@ -728,9 +726,9 @@
                     (0, 0, donno)
                   else
                     let
-                      (* "co_js" is the list of conservative problems whose
-                         liberal pendants couldn't be satisfied and hence that
-                         most probably can't be satisfied themselves. *)
+                      (* "co_js" is the list of sound problems whose unsound
+                         pendants couldn't be satisfied and hence that most
+                         probably can't be satisfied themselves. *)
                       val co_js =
                         map (fn j => j - 1) unsat_js
                         |> filter (fn j =>
@@ -743,7 +741,7 @@
                       val problems =
                         problems |> filter_out_indices bye_js
                                  |> max_potential <= 0
-                                    ? filter_out (#liberal o snd)
+                                    ? filter_out (#unsound o snd)
                     in
                       solve_any_problem max_potential max_genuine donno false
                                         problems
@@ -763,7 +761,7 @@
                                                  (map fst sat_ps @ unsat_js)
                       val problems =
                         problems |> filter_out_indices bye_js
-                                 |> filter_out (#liberal o snd)
+                                 |> filter_out (#unsound o snd)
                     in solve_any_problem 0 max_genuine donno false problems end
                 end
             end
@@ -807,10 +805,10 @@
             ()
         (* scope * bool -> rich_problem list * bool
            -> rich_problem list * bool *)
-        fun add_problem_for_scope (scope as {datatypes, ...}, liberal)
+        fun add_problem_for_scope (scope as {datatypes, ...}, unsound)
                                   (problems, donno) =
           (check_deadline ();
-           case problem_for_scope liberal scope of
+           case problem_for_scope unsound scope of
              SOME problem =>
              (problems
               |> (null problems orelse
@@ -826,6 +824,28 @@
                ([], donno)
         val _ = Unsynchronized.change generated_problems (append problems)
         val _ = Unsynchronized.change generated_scopes (append scopes)
+        val _ =
+          if j + 1 = n then
+            let
+              val (unsound_problems, sound_problems) =
+                List.partition (#unsound o snd) (!generated_problems)
+            in
+              if not (null sound_problems) andalso
+                 forall (KK.is_problem_trivially_false o fst)
+                        sound_problems then
+                print_m (fn () =>
+                    "Warning: The conjecture either trivially holds or (more \
+                    \likely) lies outside Nitpick's supported fragment." ^
+                    (if exists (not o KK.is_problem_trivially_false o fst)
+                               unsound_problems then
+                       " Only potential counterexamples may be found."
+                     else
+                       ""))
+              else
+                ()
+            end
+          else
+            ()
       in
         solve_any_problem max_potential max_genuine donno true (rev problems)
       end
@@ -838,7 +858,7 @@
       let
         (* rich_problem list -> rich_problem list *)
         val do_filter =
-          if !met_potential = max_potential then filter_out (#liberal o snd)
+          if !met_potential = max_potential then filter_out (#unsound o snd)
           else I
         val total = length (!scopes)
         val unsat =
--- a/src/HOL/Tools/Nitpick/nitpick_kodkod.ML	Wed Feb 17 11:20:09 2010 +0100
+++ b/src/HOL/Tools/Nitpick/nitpick_kodkod.ML	Wed Feb 17 12:14:08 2010 +0100
@@ -36,7 +36,7 @@
     hol_context -> int -> int Typtab.table -> kodkod_constrs
     -> nut NameTable.table -> dtype_spec list -> Kodkod.formula list
   val kodkod_formula_from_nut :
-    int -> int Typtab.table -> bool -> kodkod_constrs -> nut -> Kodkod.formula
+    int -> int Typtab.table -> kodkod_constrs -> nut -> Kodkod.formula
 end;
 
 structure Nitpick_Kodkod : NITPICK_KODKOD =
@@ -954,8 +954,8 @@
   acyclicity_axioms_for_datatypes hol_ctxt kk rel_table dtypes @
   maps (other_axioms_for_datatype hol_ctxt bits ofs kk rel_table) dtypes
 
-(* int -> int Typtab.table -> bool -> kodkod_constrs -> nut -> KK.formula *)
-fun kodkod_formula_from_nut bits ofs liberal
+(* int -> int Typtab.table -> kodkod_constrs -> nut -> KK.formula *)
+fun kodkod_formula_from_nut bits ofs
         (kk as {kk_all, kk_exist, kk_formula_let, kk_formula_if, kk_or, kk_not,
                 kk_iff, kk_implies, kk_and, kk_subset, kk_rel_eq, kk_no,
                 kk_lone, kk_one, kk_some, kk_rel_let, kk_rel_if, kk_union,
--- a/src/HOL/Tools/Nitpick/nitpick_nut.ML	Wed Feb 17 11:20:09 2010 +0100
+++ b/src/HOL/Tools/Nitpick/nitpick_nut.ML	Wed Feb 17 12:14:08 2010 +0100
@@ -892,7 +892,7 @@
 (* scope -> bool -> rep NameTable.table -> bool -> nut -> nut *)
 fun choose_reps_in_nut (scope as {hol_ctxt as {thy, ctxt, ...}, card_assigns,
                                   bits, datatypes, ofs, ...})
-                       liberal table def =
+                       unsound table def =
   let
     val bool_atom_R = Atom (2, offset_of_type ofs bool_T)
     (* polarity -> bool -> rep *)
@@ -1036,7 +1036,7 @@
               if is_constructive u then s_op2 Eq T (Formula Neut) u1' u2'
               else opt_opt_case ()
           in
-            if liberal orelse polar = Neg orelse
+            if unsound orelse polar = Neg orelse
                is_concrete_type datatypes (type_of u1) then
               case (is_opt_rep (rep_of u1'), is_opt_rep (rep_of u2')) of
                 (true, true) => opt_opt_case ()
@@ -1138,7 +1138,7 @@
               else
                 let val quant_u = s_op2 oper T (Formula polar) u1' u2' in
                   if def orelse
-                     (liberal andalso (polar = Pos) = (oper = All)) orelse
+                     (unsound andalso (polar = Pos) = (oper = All)) orelse
                      is_complete_type datatypes (type_of u1) then
                     quant_u
                   else
--- a/src/HOL/Tools/Nitpick/nitpick_tests.ML	Wed Feb 17 11:20:09 2010 +0100
+++ b/src/HOL/Tools/Nitpick/nitpick_tests.ML	Wed Feb 17 12:14:08 2010 +0100
@@ -308,7 +308,7 @@
                        NameTable.empty
     val u = Op1 (Not, type_of u, rep_of u, u)
             |> rename_vars_in_nut pool table
-    val formula = kodkod_formula_from_nut bits Typtab.empty false constrs u
+    val formula = kodkod_formula_from_nut bits Typtab.empty constrs u
     val bounds = map (bound_for_plain_rel ctxt debug) free_rels
     val univ_card = univ_card nat_card int_card j0 bounds formula
     val declarative_axioms = map (declarative_axiom_for_plain_rel constrs)