more work on Nitpick's support for nonstandard models + fix in model reconstruction
authorblanchet
Sat, 13 Feb 2010 15:04:09 +0100
changeset 35180c57dba973391
parent 35179 4b198af5beb5
child 35181 92d857a4e5e0
more work on Nitpick's support for nonstandard models + fix in model reconstruction
doc-src/Nitpick/nitpick.tex
src/HOL/Nitpick.thy
src/HOL/Nitpick_Examples/Manual_Nits.thy
src/HOL/Tools/Nitpick/nitpick_model.ML
     1.1 --- a/doc-src/Nitpick/nitpick.tex	Sat Feb 13 11:56:06 2010 +0100
     1.2 +++ b/doc-src/Nitpick/nitpick.tex	Sat Feb 13 15:04:09 2010 +0100
     1.3 @@ -1331,7 +1331,7 @@
     1.4  and this time \textit{arith} can finish off the subgoals.
     1.5  
     1.6  A similar technique can be employed for structural induction. The
     1.7 -following mini-formalization of full binary trees will serve as illustration:
     1.8 +following mini formalization of full binary trees will serve as illustration:
     1.9  
    1.10  \prew
    1.11  \textbf{datatype} $\kern1pt'a$~\textit{bin\_tree} = $\textit{Leaf}~{\kern1pt'a}$ $\mid$ $\textit{Branch}$ ``\kern1pt$'a$ \textit{bin\_tree}'' ``\kern1pt$'a$ \textit{bin\_tree}'' \\[2\smallskipamount]
    1.12 @@ -1350,8 +1350,7 @@
    1.13  obtained by swapping $a$ and $b$:
    1.14  
    1.15  \prew
    1.16 -\textbf{lemma} $``\lbrakk a \in \textit{labels}~t;\, b \in \textit{labels}~t;\, a \not= b\rbrakk {}$ \\
    1.17 -\phantom{\textbf{lemma} ``}$\,{\Longrightarrow}{\;\,} \textit{labels}~(\textit{swap}~t~a~b) = \textit{labels}~t$''
    1.18 +\textbf{lemma} $``\{a, b\} \subseteq \textit{labels}~t \,\Longrightarrow\, \textit{labels}~(\textit{swap}~t~a~b) = \textit{labels}~t$''
    1.19  \postw
    1.20  
    1.21  Nitpick can't find any counterexample, so we proceed with induction
    1.22 @@ -1370,29 +1369,29 @@
    1.23  \prew
    1.24  \slshape
    1.25  Hint: To check that the induction hypothesis is general enough, try this command:
    1.26 -\textbf{nitpick}~[\textit{non\_std} ``${\kern1pt'a}~\textit{bin\_tree}$'', \textit{show\_consts}].
    1.27 +\textbf{nitpick}~[\textit{non\_std} ``${\kern1pt'a}~\textit{bin\_tree}$'', \textit{show\_all}].
    1.28  \postw
    1.29  
    1.30  If we follow the hint, we get a ``nonstandard'' counterexample for the step:
    1.31  
    1.32  \prew
    1.33 -\slshape Nitpick found a nonstandard counterexample for \textit{card} $'a$ = 4: \\[2\smallskipamount]
    1.34 +\slshape Nitpick found a nonstandard counterexample for \textit{card} $'a$ = 3: \\[2\smallskipamount]
    1.35  \hbox{}\qquad Free variables: \nopagebreak \\
    1.36  \hbox{}\qquad\qquad $a = a_1$ \\
    1.37  \hbox{}\qquad\qquad $b = a_2$ \\
    1.38  \hbox{}\qquad\qquad $t = \xi_1$ \\
    1.39  \hbox{}\qquad\qquad $u = \xi_2$ \\
    1.40 +\hbox{}\qquad Datatype: \nopagebreak \\
    1.41 +\hbox{}\qquad\qquad $\alpha~\textit{btree} = \{\xi_1 \mathbin{=} \textit{Branch}~\xi_1~\xi_1,\> \xi_2 \mathbin{=} \textit{Branch}~\xi_2~\xi_2,\> \textit{Branch}~\xi_1~\xi_2\}$ \\
    1.42  \hbox{}\qquad {\slshape Constants:} \nopagebreak \\
    1.43  \hbox{}\qquad\qquad $\textit{labels} = \undef
    1.44      (\!\begin{aligned}[t]%
    1.45 -    & \xi_1 := \{a_1, a_4, a_3^\Q\},\> \xi_2 := \{a_2, a_3^\Q\}, \\[-2pt] %% TYPESETTING
    1.46 -    & \textit{Branch}~\xi_1~\xi_2 := \{a_1, a_2, a_4, a_3^\Q\}, \\[-2pt]
    1.47 -    & \textit{Branch}~\xi_2~\xi_2 := \{a_2, a_3^\Q\})\end{aligned}$ \\
    1.48 +    & \xi_1 := \{a_2, a_3\},\> \xi_2 := \{a_1\},\> \\[-2pt]
    1.49 +    & \textit{Branch}~\xi_1~\xi_2 := \{a_1, a_2, a_3\})\end{aligned}$ \\
    1.50  \hbox{}\qquad\qquad $\lambda x_1.\> \textit{swap}~x_1~a~b = \undef
    1.51      (\!\begin{aligned}[t]%
    1.52      & \xi_1 := \xi_2,\> \xi_2 := \xi_2, \\[-2pt]
    1.53 -    & \textit{Branch}~\xi_1~\xi_2 := \textit{Branch}~\xi_2~\xi_2, \\[-2pt]
    1.54 -    & \textit{Branch}~\xi_2~\xi_2 := \textit{Branch}~\xi_2~\xi_2)\end{aligned}$ \\[2\smallskipamount]
    1.55 +    & \textit{Branch}~\xi_1~\xi_2 := \xi_2)\end{aligned}$ \\[2\smallskipamount]
    1.56  The existence of a nonstandard model suggests that the induction hypothesis is not general enough or perhaps
    1.57  even wrong. See the ``Inductive Properties'' section of the Nitpick manual for details (``\textit{isabelle doc nitpick}'').
    1.58  \postw
    1.59 @@ -1408,9 +1407,9 @@
    1.60  \textit{reach\/}$'' assumption). In both cases, we effectively enlarge the
    1.61  set of objects over which the induction is performed while doing the step
    1.62  in order to test the induction hypothesis's strength.}
    1.63 -The new trees are so nonstandard that we know nothing about them, except what
    1.64 -the induction hypothesis states and what can be proved about all trees without
    1.65 -relying on induction or case distinction. The key observation is,
    1.66 +Unlike standard trees, these new trees contain cycles. We will see later that
    1.67 +every property of acyclic trees that can be proved without using induction also
    1.68 +holds for cyclic trees. Hence,
    1.69  %
    1.70  \begin{quote}
    1.71  \textsl{If the induction
    1.72 @@ -1418,9 +1417,9 @@
    1.73  objects, and Nitpick won't find any nonstandard counterexample.}
    1.74  \end{quote}
    1.75  %
    1.76 -But here, Nitpick did find some nonstandard trees $t = \xi_1$
    1.77 -and $u = \xi_2$ such that $a \in \textit{labels}~t$, $b \notin
    1.78 -\textit{labels}~t$, $a \notin \textit{labels}~u$, and $b \in \textit{labels}~u$.
    1.79 +But here the tool find some nonstandard trees $t = \xi_1$
    1.80 +and $u = \xi_2$ such that $a \notin \textit{labels}~t$, $b \in
    1.81 +\textit{labels}~t$, $a \in \textit{labels}~u$, and $b \notin \textit{labels}~u$.
    1.82  Because neither tree contains both $a$ and $b$, the induction hypothesis tells
    1.83  us nothing about the labels of $\textit{swap}~t~a~b$ and $\textit{swap}~u~a~b$,
    1.84  and as a result we know nothing about the labels of the tree
     2.1 --- a/src/HOL/Nitpick.thy	Sat Feb 13 11:56:06 2010 +0100
     2.2 +++ b/src/HOL/Nitpick.thy	Sat Feb 13 15:04:09 2010 +0100
     2.3 @@ -37,7 +37,6 @@
     2.4             and bisim_iterator_max :: bisim_iterator
     2.5             and Quot :: "'a \<Rightarrow> 'b"
     2.6             and quot_normal :: "'a \<Rightarrow> 'a"
     2.7 -           and Silly :: "'a \<Rightarrow> 'b"
     2.8             and Tha :: "('a \<Rightarrow> bool) \<Rightarrow> 'a"
     2.9  
    2.10  datatype ('a, 'b) pair_box = PairBox 'a 'b
    2.11 @@ -45,7 +44,6 @@
    2.12  
    2.13  typedecl unsigned_bit
    2.14  typedecl signed_bit
    2.15 -typedecl \<xi>
    2.16  
    2.17  datatype 'a word = Word "('a set)"
    2.18  
    2.19 @@ -254,12 +252,12 @@
    2.20  setup {* Nitpick_Isar.setup *}
    2.21  
    2.22  hide (open) const unknown is_unknown undefined_fast_The undefined_fast_Eps bisim 
    2.23 -    bisim_iterator_max Quot quot_normal Silly Tha PairBox FunBox Word refl' wf'
    2.24 +    bisim_iterator_max Quot quot_normal Tha PairBox FunBox Word refl' wf'
    2.25      wf_wfrec wf_wfrec' wfrec' card' setsum' fold_graph' nat_gcd nat_lcm int_gcd
    2.26      int_lcm Frac Abs_Frac Rep_Frac zero_frac one_frac num denom norm_frac frac
    2.27      plus_frac times_frac uminus_frac number_of_frac inverse_frac less_eq_frac
    2.28      of_frac
    2.29 -hide (open) type bisim_iterator pair_box fun_box unsigned_bit signed_bit \<xi> word
    2.30 +hide (open) type bisim_iterator pair_box fun_box unsigned_bit signed_bit word
    2.31  hide (open) fact If_def Ex1_def rtrancl_def rtranclp_def tranclp_def refl'_def
    2.32      wf'_def wf_wfrec'_def wfrec'_def card'_def setsum'_def fold_graph'_def
    2.33      The_psimp Eps_psimp unit_case_def nat_case_def list_size_simp nat_gcd_def
     3.1 --- a/src/HOL/Nitpick_Examples/Manual_Nits.thy	Sat Feb 13 11:56:06 2010 +0100
     3.2 +++ b/src/HOL/Nitpick_Examples/Manual_Nits.thy	Sat Feb 13 15:04:09 2010 +0100
     3.3 @@ -259,7 +259,7 @@
     3.4   (if c = a then Leaf b else if c = b then Leaf a else Leaf c)" |
     3.5  "swap (Branch t u) a b = Branch (swap t a b) (swap u a b)"
     3.6  
     3.7 -lemma "\<lbrakk>a \<in> labels t; b \<in> labels t; a \<noteq> b\<rbrakk> \<Longrightarrow> labels (swap t a b) = labels t"
     3.8 +lemma "{a, b} \<subseteq> labels t \<Longrightarrow> labels (swap t a b) = labels t"
     3.9  nitpick
    3.10  proof (induct t)
    3.11    case Leaf thus ?case by simp
     4.1 --- a/src/HOL/Tools/Nitpick/nitpick_model.ML	Sat Feb 13 11:56:06 2010 +0100
     4.2 +++ b/src/HOL/Tools/Nitpick/nitpick_model.ML	Sat Feb 13 15:04:09 2010 +0100
     4.3 @@ -54,7 +54,7 @@
     4.4  val step_mixfix = "_\<^bsub>step\<^esub>"
     4.5  val abs_mixfix = "\<guillemotleft>_\<guillemotright>"
     4.6  val cyclic_co_val_name = "\<omega>"
     4.7 -val cyclic_non_std_type_name = "\<xi>"
     4.8 +val cyclic_type_name = "\<xi>"
     4.9  val opt_flag = nitpick_prefix ^ "opt"
    4.10  val non_opt_flag = nitpick_prefix ^ "non_opt"
    4.11  
    4.12 @@ -259,14 +259,13 @@
    4.13    | mk_tuple _ (t :: _) = t
    4.14    | mk_tuple T [] = raise TYPE ("Nitpick_Model.mk_tuple", [T], [])
    4.15  
    4.16 -(* string * string * string * string -> scope -> nut list -> nut list
    4.17 -   -> nut list -> nut NameTable.table -> KK.raw_bound list -> typ -> typ -> rep
    4.18 -   -> int list list -> term *)
    4.19 -fun reconstruct_term (maybe_name, base_name, step_name, abs_name)
    4.20 +(* bool -> atom_pool -> string * string * string * string -> scope -> nut list
    4.21 +   -> nut list -> nut list -> nut NameTable.table -> KK.raw_bound list -> typ
    4.22 +   -> typ -> rep -> int list list -> term *)
    4.23 +fun reconstruct_term elaborate pool (maybe_name, base_name, step_name, abs_name)
    4.24          ({hol_ctxt as {thy, ctxt, ...}, card_assigns, bits, datatypes, ofs, ...}
    4.25           : scope) sel_names rel_table bounds =
    4.26    let
    4.27 -    val pool = Unsynchronized.ref []
    4.28      val for_auto = (maybe_name = "")
    4.29      (* int list list -> int *)
    4.30      fun value_of_bits jss =
    4.31 @@ -404,8 +403,11 @@
    4.32              (* styp -> int list *)
    4.33              fun tuples_for_const (s, T) =
    4.34                tuple_list_for_name rel_table bounds (ConstName (s, T, Any))
    4.35 -            (* unit -> indexname * typ *)
    4.36 -            fun var () = ((nth_atom_name pool "" T j k, 0), T)
    4.37 +            (* unit -> term *)
    4.38 +            fun cyclic_atom () =
    4.39 +              nth_atom pool for_auto (Type (cyclic_type_name, [])) j k
    4.40 +            fun cyclic_var () = Var ((nth_atom_name pool "" T j k, 0), T)
    4.41 +
    4.42              val discr_jsss = map (tuples_for_const o discr_for_constr o #const)
    4.43                                   constrs
    4.44              val real_j = j + offset_of_type ofs T
    4.45 @@ -432,8 +434,9 @@
    4.46              val uncur_arg_Ts = binder_types constr_T
    4.47              val maybe_cyclic = co orelse not standard
    4.48            in
    4.49 -            if maybe_cyclic andalso member (op =) seen (T, j) then
    4.50 -              Var (var ())
    4.51 +            if maybe_cyclic andalso not (null seen) andalso
    4.52 +               member (op =) (seen |> elaborate ? (fst o split_last)) (T, j) then
    4.53 +              cyclic_var ()
    4.54              else if constr_s = @{const_name Word} then
    4.55                HOLogic.mk_number
    4.56                    (if T = @{typ "unsigned_bit word"} then nat_T else int_T)
    4.57 @@ -476,16 +479,23 @@
    4.58                      list_comb (Const constr_x, ts)
    4.59                in
    4.60                  if maybe_cyclic then
    4.61 -                  let val var = var () in
    4.62 -                    if exists_subterm (curry (op =) (Var var)) t then
    4.63 +                  let val var = cyclic_var () in
    4.64 +                    if elaborate andalso not standard andalso
    4.65 +                       length seen = 1 andalso
    4.66 +                       exists_subterm (fn Const (s, _) =>
    4.67 +                                          String.isPrefix cyclic_type_name s
    4.68 +                                        | t' => t' = var) t then
    4.69 +                      let val atom = cyclic_atom () in
    4.70 +                        HOLogic.mk_eq (atom, subst_atomic [(var, atom)] t)
    4.71 +                      end
    4.72 +                    else if exists_subterm (curry (op =) var) t then
    4.73                        if co then
    4.74                          Const (@{const_name The}, (T --> bool_T) --> T)
    4.75                          $ Abs (cyclic_co_val_name, T,
    4.76                                 Const (@{const_name "op ="}, T --> T --> bool_T)
    4.77 -                               $ Bound 0 $ abstract_over (Var var, t))
    4.78 +                               $ Bound 0 $ abstract_over (var, t))
    4.79                        else
    4.80 -                        nth_atom pool for_auto
    4.81 -                                 (Type (cyclic_non_std_type_name, [])) j k
    4.82 +                        cyclic_atom ()
    4.83                      else
    4.84                        t
    4.85                    end
    4.86 @@ -541,17 +551,15 @@
    4.87          raise ARG ("Nitpick_Model.reconstruct_term.term_for_rep",
    4.88                     Refute.string_of_typ T ^ " " ^ string_for_rep R ^ " " ^
    4.89                     string_of_int (length jss))
    4.90 -  in
    4.91 -    polish_funs [] o unbit_and_unbox_term oooo term_for_rep []
    4.92 -  end
    4.93 +  in polish_funs [] o unbit_and_unbox_term oooo term_for_rep [] end
    4.94  
    4.95 -(* scope -> nut list -> nut NameTable.table -> KK.raw_bound list -> nut
    4.96 -   -> term *)
    4.97 -fun term_for_name scope sel_names rel_table bounds name =
    4.98 +(* atom_pool -> scope -> nut list -> nut NameTable.table -> KK.raw_bound list
    4.99 +   -> nut -> term *)
   4.100 +fun term_for_name pool scope sel_names rel_table bounds name =
   4.101    let val T = type_of name in
   4.102      tuple_list_for_name rel_table bounds name
   4.103 -    |> reconstruct_term ("", "", "", "") scope sel_names rel_table bounds T T
   4.104 -                        (rep_of name)
   4.105 +    |> reconstruct_term false pool ("", "", "", "") scope sel_names rel_table
   4.106 +                        bounds T T (rep_of name)
   4.107    end
   4.108  
   4.109  (* Proof.context -> (string * string * string * string) * Proof.context *)
   4.110 @@ -614,6 +622,7 @@
   4.111           card_assigns, bits, bisim_depth, datatypes, ofs} : scope)
   4.112          formats all_frees free_names sel_names nonsel_names rel_table bounds =
   4.113    let
   4.114 +    val pool = Unsynchronized.ref []
   4.115      val (wacky_names as (_, base_name, step_name, _), ctxt) =
   4.116        add_wacky_syntax ctxt
   4.117      val hol_ctxt =
   4.118 @@ -633,11 +642,13 @@
   4.119      val scope = {hol_ctxt = hol_ctxt, card_assigns = card_assigns,
   4.120                   bits = bits, bisim_depth = bisim_depth, datatypes = datatypes,
   4.121                   ofs = ofs}
   4.122 -    (* typ -> typ -> rep -> int list list -> term *)
   4.123 -    val term_for_rep = reconstruct_term wacky_names scope sel_names rel_table
   4.124 -                                        bounds
   4.125 +    (* bool -> typ -> typ -> rep -> int list list -> term *)
   4.126 +    fun term_for_rep elaborate =
   4.127 +      reconstruct_term elaborate pool wacky_names scope sel_names rel_table
   4.128 +                       bounds
   4.129      (* nat -> typ -> nat -> typ *)
   4.130 -    fun nth_value_of_type card T n = term_for_rep T T (Atom (card, 0)) [[n]]
   4.131 +    fun nth_value_of_type card T n =
   4.132 +      term_for_rep true T T (Atom (card, 0)) [[n]]
   4.133      (* nat -> typ -> typ list *)
   4.134      fun all_values_of_type card T =
   4.135        index_seq 0 card |> map (nth_value_of_type card T) |> sort nice_term_ord
   4.136 @@ -670,7 +681,7 @@
   4.137                     Const (@{const_name undefined}, T')
   4.138                   else
   4.139                     tuple_list_for_name rel_table bounds name
   4.140 -                   |> term_for_rep T T' (rep_of name)
   4.141 +                   |> term_for_rep false T T' (rep_of name)
   4.142        in
   4.143          Pretty.block (Pretty.breaks
   4.144              [setmp_show_all_types (Syntax.pretty_term ctxt) t1,
   4.145 @@ -763,7 +774,7 @@
   4.146      (* nut -> term *)
   4.147      fun free_name_assm name =
   4.148        HOLogic.mk_eq (Free (nickname_of name, type_of name),
   4.149 -                     term_for_name scope sel_names rel_table bounds name)
   4.150 +                     term_for_name pool scope sel_names rel_table bounds name)
   4.151      val freeT_assms = map free_type_assm (filter (is_TFree o fst) card_assigns)
   4.152      val model_assms = map free_name_assm free_names
   4.153      val assm = foldr1 s_conj (freeT_assms @ model_assms)