src/HOL/Tools/Nitpick/nitpick_model.ML
changeset 46083 efeaa79f021b
parent 45479 3387d482e0a9
child 46097 0ed9365fa9d2
equal deleted inserted replaced
46082:1c436a920730 46083:efeaa79f021b
   226     ((T11, SOME T12), (T2, NONE))
   226     ((T11, SOME T12), (T2, NONE))
   227   | factor_out_types T1 (Type (@{type_name prod}, [T21, T22])) =
   227   | factor_out_types T1 (Type (@{type_name prod}, [T21, T22])) =
   228     ((T1, NONE), (T21, SOME T22))
   228     ((T1, NONE), (T21, SOME T22))
   229   | factor_out_types T1 T2 = ((T1, NONE), (T2, NONE))
   229   | factor_out_types T1 T2 = ((T1, NONE), (T2, NONE))
   230 
   230 
       
   231 (* Term-encoded data structure for holding key-value pairs as well as an "opt"
       
   232    flag indicating whether the function is approximated. *)
   231 fun make_plain_fun maybe_opt T1 T2 =
   233 fun make_plain_fun maybe_opt T1 T2 =
   232   let
   234   let
   233     fun aux T1 T2 [] =
   235     fun aux T1 T2 [] =
   234         Const (if maybe_opt then opt_flag else non_opt_flag, T1 --> T2)
   236         Const (if maybe_opt then opt_flag else non_opt_flag, T1 --> T2)
   235       | aux T1 T2 ((t1, t2) :: tps) =
   237       | aux T1 T2 ((t1, t2) :: tps) =
   266     if T1 = T1' then HOLogic.mk_prod (t1, t2)
   268     if T1 = T1' then HOLogic.mk_prod (t1, t2)
   267     else HOLogic.mk_prod (t11, pair_up T2' t12 t2)
   269     else HOLogic.mk_prod (t11, pair_up T2' t12 t2)
   268   | pair_up _ t1 t2 = HOLogic.mk_prod (t1, t2)
   270   | pair_up _ t1 t2 = HOLogic.mk_prod (t1, t2)
   269 fun multi_pair_up T1 t1 (ts2, ts3) = map2 (pair o pair_up T1 t1) ts2 ts3
   271 fun multi_pair_up T1 t1 (ts2, ts3) = map2 (pair o pair_up T1 t1) ts2 ts3
   270 
   272 
   271 fun typecast_fun (Type (@{type_name fun}, [T1', T2'])) T1 T2 t =
   273 fun format_fun T' T1 T2 t =
   272     let
   274   let
   273       fun do_curry T1 T1a T1b T2 t =
   275     val T1' = pseudo_domain_type T'
   274         let
   276     val T2' = pseudo_range_type T'
   275           val (maybe_opt, tsp) = dest_plain_fun t
   277     fun do_curry T1 T1a T1b T2 t =
   276           val tps =
   278       let
   277             tsp |>> map (break_in_two T1 T1a T1b)
   279         val (maybe_opt, tsp) = dest_plain_fun t
   278                 |> uncurry (map2 (fn (t1a, t1b) => fn t2 => (t1a, (t1b, t2))))
   280         val tps =
   279                 |> AList.coalesce (op =)
   281           tsp |>> map (break_in_two T1 T1a T1b)
   280                 |> map (apsnd (make_plain_fun maybe_opt T1b T2))
   282               |> uncurry (map2 (fn (t1a, t1b) => fn t2 => (t1a, (t1b, t2))))
   281         in make_plain_fun maybe_opt T1a (T1b --> T2) tps end
   283               |> AList.coalesce (op =)
   282       and do_uncurry T1 T2 t =
   284               |> map (apsnd (make_plain_fun maybe_opt T1b T2))
   283         let
   285       in make_plain_fun maybe_opt T1a (T1b --> T2) tps end
   284           val (maybe_opt, tsp) = dest_plain_fun t
   286     and do_uncurry T1 T2 t =
   285           val tps =
   287       let
   286             tsp |> op ~~
   288         val (maybe_opt, tsp) = dest_plain_fun t
   287                 |> maps (fn (t1, t2) =>
   289         val tps =
   288                             multi_pair_up T1 t1 (snd (dest_plain_fun t2)))
   290           tsp |> op ~~
   289         in make_plain_fun maybe_opt T1 T2 tps end
   291               |> maps (fn (t1, t2) =>
   290       and do_arrow T1' T2' _ _ (Const (s, _)) = Const (s, T1' --> T2')
   292                           multi_pair_up T1 t1 (snd (dest_plain_fun t2)))
   291         | do_arrow T1' T2' T1 T2
   293       in make_plain_fun maybe_opt T1 T2 tps end
   292                    (Const (@{const_name fun_upd}, _) $ t0 $ t1 $ t2) =
   294     and do_arrow T1' T2' _ _ (Const (s, _)) = Const (s, T1' --> T2')
   293           Const (@{const_name fun_upd},
   295       | do_arrow T1' T2' T1 T2
   294                  (T1' --> T2') --> T1' --> T2' --> T1' --> T2')
   296                  (Const (@{const_name fun_upd}, _) $ t0 $ t1 $ t2) =
   295           $ do_arrow T1' T2' T1 T2 t0 $ do_term T1' T1 t1 $ do_term T2' T2 t2
   297         Const (@{const_name fun_upd},
   296         | do_arrow _ _ _ _ t =
   298                (T1' --> T2') --> T1' --> T2' --> T1' --> T2')
   297           raise TERM ("Nitpick_Model.typecast_fun.do_arrow", [t])
   299         $ do_arrow T1' T2' T1 T2 t0 $ do_term T1' T1 t1 $ do_term T2' T2 t2
   298       and do_fun T1' T2' T1 T2 t =
   300       | do_arrow _ _ _ _ t =
   299         case factor_out_types T1' T1 of
   301         raise TERM ("Nitpick_Model.format_fun.do_arrow", [t])
   300           ((_, NONE), (_, NONE)) => t |> do_arrow T1' T2' T1 T2
   302     and do_fun T1' T2' T1 T2 t =
   301         | ((_, NONE), (T1a, SOME T1b)) =>
   303       case factor_out_types T1' T1 of
   302           t |> do_curry T1 T1a T1b T2 |> do_arrow T1' T2' T1a (T1b --> T2)
   304         ((_, NONE), (_, NONE)) => t |> do_arrow T1' T2' T1 T2
   303         | ((T1a', SOME T1b'), (_, NONE)) =>
   305       | ((_, NONE), (T1a, SOME T1b)) =>
   304           t |> do_arrow T1a' (T1b' --> T2') T1 T2 |> do_uncurry T1' T2'
   306         t |> do_curry T1 T1a T1b T2 |> do_arrow T1' T2' T1a (T1b --> T2)
   305         | _ => raise TYPE ("Nitpick_Model.typecast_fun.do_fun", [T1, T1'], [])
   307       | ((T1a', SOME T1b'), (_, NONE)) =>
   306       and do_term (Type (@{type_name fun}, [T1', T2']))
   308         t |> do_arrow T1a' (T1b' --> T2') T1 T2 |> do_uncurry T1' T2'
   307                   (Type (@{type_name fun}, [T1, T2])) t =
   309       | _ => raise TYPE ("Nitpick_Model.format_fun.do_fun", [T1, T1'], [])
   308           do_fun T1' T2' T1 T2 t
   310     and do_term (Type (@{type_name fun}, [T1', T2']))
   309         | do_term (T' as Type (@{type_name prod}, Ts' as [T1', T2']))
   311                 (Type (@{type_name fun}, [T1, T2])) t =
   310                   (Type (@{type_name prod}, [T1, T2]))
   312         do_fun T1' T2' T1 T2 t
   311                   (Const (@{const_name Pair}, _) $ t1 $ t2) =
   313       | do_term (T' as Type (@{type_name prod}, Ts' as [T1', T2']))
   312           Const (@{const_name Pair}, Ts' ---> T')
   314                 (Type (@{type_name prod}, [T1, T2]))
   313           $ do_term T1' T1 t1 $ do_term T2' T2 t2
   315                 (Const (@{const_name Pair}, _) $ t1 $ t2) =
   314         | do_term T' T t =
   316         Const (@{const_name Pair}, Ts' ---> T')
   315           if T = T' then t
   317         $ do_term T1' T1 t1 $ do_term T2' T2 t2
   316           else raise TYPE ("Nitpick_Model.typecast_fun.do_term", [T, T'], [])
   318       | do_term T' T t =
   317     in if T1' = T1 andalso T2' = T2 then t else do_fun T1' T2' T1 T2 t end
   319         if T = T' then t
   318   | typecast_fun T' _ _ _ =
   320         else raise TYPE ("Nitpick_Model.format_fun.do_term", [T, T'], [])
   319     raise TYPE ("Nitpick_Model.typecast_fun", [T'], [])
   321   in if T1' = T1 andalso T2' = T2 then t else do_fun T1' T2' T1 T2 t end
   320 
   322 
   321 fun truth_const_sort_key @{const True} = "0"
   323 fun truth_const_sort_key @{const True} = "0"
   322   | truth_const_sort_key @{const False} = "2"
   324   | truth_const_sort_key @{const False} = "2"
   323   | truth_const_sort_key _ = "1"
   325   | truth_const_sort_key _ = "1"
   324 
   326 
   383           postprocess_term (fastype_of1 (Ts, t)) t
   385           postprocess_term (fastype_of1 (Ts, t)) t
   384         end
   386         end
   385       | postprocess_subterms Ts (Abs (s, T, t')) =
   387       | postprocess_subterms Ts (Abs (s, T, t')) =
   386         Abs (s, T, postprocess_subterms (T :: Ts) t')
   388         Abs (s, T, postprocess_subterms (T :: Ts) t')
   387       | postprocess_subterms Ts t = postprocess_term (fastype_of1 (Ts, t)) t
   389       | postprocess_subterms Ts t = postprocess_term (fastype_of1 (Ts, t)) t
   388     fun make_set maybe_opt T1 T2 tps =
   390     fun make_set maybe_opt T tps =
   389       let
   391       let
   390         val empty_const = Const (@{const_abbrev Set.empty}, T1 --> T2)
   392         val empty_const = Const (@{const_abbrev Set.empty}, T --> bool_T)
   391         val insert_const = Const (@{const_name insert},
   393         val insert_const =
   392                                   T1 --> (T1 --> T2) --> T1 --> T2)
   394           Const (@{const_name insert}, T --> (T --> bool_T) --> T --> bool_T)
   393         fun aux [] =
   395         fun aux [] =
   394             if maybe_opt andalso not (is_complete_type datatypes false T1) then
   396             if maybe_opt andalso not (is_complete_type datatypes false T) then
   395               insert_const $ Const (unrep (), T1) $ empty_const
   397               insert_const $ Const (unrep (), T) $ empty_const
   396             else
   398             else
   397               empty_const
   399               empty_const
   398           | aux ((t1, t2) :: zs) =
   400           | aux ((t1, t2) :: zs) =
   399             aux zs
   401             aux zs
   400             |> t2 <> @{const False}
   402             |> t2 <> @{const False}
   401                ? curry (op $)
   403                ? curry (op $)
   402                        (insert_const
   404                        (insert_const
   403                         $ (t1 |> t2 <> @{const True}
   405                         $ (t1 |> t2 <> @{const True}
   404                                  ? curry (op $)
   406                                  ? curry (op $)
   405                                          (Const (maybe_name, T1 --> T1))))
   407                                          (Const (maybe_name, T --> T))))
   406       in
   408       in
   407         if forall (fn (_, t) => t <> @{const True} andalso t <> @{const False})
   409         if forall (fn (_, t) => t <> @{const True} andalso t <> @{const False})
   408                   tps then
   410                   tps then
   409           Const (unknown, T1 --> T2)
   411           Const (unknown, T --> bool_T)
   410         else
   412         else
   411           aux tps
   413           aux tps
   412       end
   414       end
   413     fun make_map maybe_opt T1 T2 T2' =
   415     fun make_map maybe_opt T1 T2 T2' =
   414       let
   416       let
   429     fun polish_funs Ts t =
   431     fun polish_funs Ts t =
   430       (case fastype_of1 (Ts, t) of
   432       (case fastype_of1 (Ts, t) of
   431          Type (@{type_name fun}, [T1, T2]) =>
   433          Type (@{type_name fun}, [T1, T2]) =>
   432          if is_plain_fun t then
   434          if is_plain_fun t then
   433            case T2 of
   435            case T2 of
   434              @{typ bool} =>
   436              Type (@{type_name option}, [T2']) =>
   435              let
       
   436                val (maybe_opt, ts_pair) =
       
   437                  dest_plain_fun t ||> pairself (map (polish_funs Ts))
       
   438              in
       
   439                make_set maybe_opt T1 T2
       
   440                         (sort_wrt (truth_const_sort_key o snd) (op ~~ ts_pair))
       
   441              end
       
   442            | Type (@{type_name option}, [T2']) =>
       
   443              let
   437              let
   444                val (maybe_opt, ts_pair) =
   438                val (maybe_opt, ts_pair) =
   445                  dest_plain_fun t ||> pairself (map (polish_funs Ts))
   439                  dest_plain_fun t ||> pairself (map (polish_funs Ts))
   446              in make_map maybe_opt T1 T2 T2' (rev (op ~~ ts_pair)) end
   440              in make_map maybe_opt T1 T2 T2' (rev (op ~~ ts_pair)) end
   447            | _ => raise SAME ()
   441            | _ => raise SAME ()
   464                              else
   458                              else
   465                                unknown, T2))
   459                                unknown, T2))
   466                else
   460                else
   467                  t
   461                  t
   468              | t => t
   462              | t => t
   469     fun make_fun maybe_opt T1 T2 T' ts1 ts2 =
   463     fun make_fun_or_set maybe_opt T T1 T2 T' ts1 ts2 =
   470       ts1 ~~ ts2 |> sort (nice_term_ord o pairself fst)
   464       ts1 ~~ ts2
   471                  |> make_plain_fun maybe_opt T1 T2
   465       |> sort (nice_term_ord o pairself fst)
   472                  |> unarize_unbox_etc_term
   466       |> (case T of
   473                  |> typecast_fun (uniterize_unarize_unbox_etc_type T')
   467             Type (@{type_name set}, _) =>
   474                                  (uniterize_unarize_unbox_etc_type T1)
   468             sort_wrt (truth_const_sort_key o snd)
   475                                  (uniterize_unarize_unbox_etc_type T2)
   469             #> make_set maybe_opt T'
       
   470           | _ =>
       
   471             make_plain_fun maybe_opt T1 T2
       
   472             #> unarize_unbox_etc_term
       
   473             #> format_fun (uniterize_unarize_unbox_etc_type T')
       
   474                           (uniterize_unarize_unbox_etc_type T1)
       
   475                           (uniterize_unarize_unbox_etc_type T2))
   476     fun term_for_atom seen (T as Type (@{type_name fun}, [T1, T2])) T' j _ =
   476     fun term_for_atom seen (T as Type (@{type_name fun}, [T1, T2])) T' j _ =
   477         let
   477         let
   478           val k1 = card_of_type card_assigns T1
   478           val k1 = card_of_type card_assigns T1
   479           val k2 = card_of_type card_assigns T2
   479           val k2 = card_of_type card_assigns T2
   480         in
   480         in
   601                   end
   601                   end
   602                 else
   602                 else
   603                   t
   603                   t
   604               end
   604               end
   605           end
   605           end
   606     and term_for_vect seen k R T1 T2 T' js =
   606     and term_for_vect seen k R T T' js =
   607       make_fun true T1 T2 T'
   607       let
   608                (map (fn j => term_for_atom seen T1 T1 j k) (index_seq 0 k))
   608         val T1 = pseudo_domain_type T
   609                (map (term_for_rep true seen T2 T2 R o single)
   609         val T2 = pseudo_range_type T
   610                     (batch_list (arity_of_rep R) js))
   610       in
       
   611         make_fun_or_set true T T1 T2 T'
       
   612             (map (fn j => term_for_atom seen T1 T1 j k) (index_seq 0 k))
       
   613             (map (term_for_rep true seen T2 T2 R o single)
       
   614                  (batch_list (arity_of_rep R) js))
       
   615       end
   611     and term_for_rep _ seen T T' (R as Atom (k, j0)) [[j]] =
   616     and term_for_rep _ seen T T' (R as Atom (k, j0)) [[j]] =
   612         if j >= j0 andalso j < j0 + k then term_for_atom seen T T' (j - j0) k
   617         if j >= j0 andalso j < j0 + k then term_for_atom seen T T' (j - j0) k
   613         else raise REP ("Nitpick_Model.reconstruct_term.term_for_rep", [R])
   618         else raise REP ("Nitpick_Model.reconstruct_term.term_for_rep", [R])
   614       | term_for_rep _ seen (Type (@{type_name prod}, [T1, T2])) _
   619       | term_for_rep _ seen (Type (@{type_name prod}, [T1, T2])) _
   615                      (Struct [R1, R2]) [js] =
   620                      (Struct [R1, R2]) [js] =
   619         in
   624         in
   620           list_comb (HOLogic.pair_const T1 T2,
   625           list_comb (HOLogic.pair_const T1 T2,
   621                      map3 (fn T => term_for_rep true seen T T) [T1, T2] [R1, R2]
   626                      map3 (fn T => term_for_rep true seen T T) [T1, T2] [R1, R2]
   622                           [[js1], [js2]])
   627                           [[js1], [js2]])
   623         end
   628         end
   624       | term_for_rep _ seen (Type (@{type_name fun}, [T1, T2])) T'
   629       | term_for_rep _ seen T T' (Vect (k, R')) [js] =
   625                      (Vect (k, R')) [js] =
   630         term_for_vect seen k R' T T' js
   626         term_for_vect seen k R' T1 T2 T' js
   631       | term_for_rep maybe_opt seen T T' (Func (R1, Formula Neut)) jss =
   627       | term_for_rep maybe_opt seen (Type (@{type_name fun}, [T1, T2])) T'
       
   628                      (Func (R1, Formula Neut)) jss =
       
   629         let
   632         let
       
   633           val T1 = pseudo_domain_type T
       
   634           val T2 = pseudo_range_type T
   630           val jss1 = all_combinations_for_rep R1
   635           val jss1 = all_combinations_for_rep R1
   631           val ts1 = map (term_for_rep true seen T1 T1 R1 o single) jss1
   636           val ts1 = map (term_for_rep true seen T1 T1 R1 o single) jss1
   632           val ts2 =
   637           val ts2 =
   633             map (fn js => term_for_rep true seen T2 T2 (Atom (2, 0))
   638             map (fn js => term_for_rep true seen T2 T2 (Atom (2, 0))
   634                                        [[int_from_bool (member (op =) jss js)]])
   639                                        [[int_from_bool (member (op =) jss js)]])
   635                 jss1
   640                 jss1
   636         in make_fun maybe_opt T1 T2 T' ts1 ts2 end
   641         in make_fun_or_set maybe_opt T T1 T2 T' ts1 ts2 end
   637       | term_for_rep maybe_opt seen (Type (@{type_name fun}, [T1, T2])) T'
   642       | term_for_rep maybe_opt seen T T' (Func (R1, R2)) jss =
   638                      (Func (R1, R2)) jss =
       
   639         let
   643         let
       
   644           val T1 = pseudo_domain_type T
       
   645           val T2 = pseudo_range_type T
   640           val arity1 = arity_of_rep R1
   646           val arity1 = arity_of_rep R1
   641           val jss1 = all_combinations_for_rep R1
   647           val jss1 = all_combinations_for_rep R1
   642           val ts1 = map (term_for_rep false seen T1 T1 R1 o single) jss1
   648           val ts1 = map (term_for_rep false seen T1 T1 R1 o single) jss1
   643           val grouped_jss2 = AList.group (op =) (map (chop arity1) jss)
   649           val grouped_jss2 = AList.group (op =) (map (chop arity1) jss)
   644           val ts2 = map (term_for_rep false seen T2 T2 R2 o the_default []
   650           val ts2 = map (term_for_rep false seen T2 T2 R2 o the_default []
   645                          o AList.lookup (op =) grouped_jss2) jss1
   651                          o AList.lookup (op =) grouped_jss2) jss1
   646         in make_fun maybe_opt T1 T2 T' ts1 ts2 end
   652         in make_fun_or_set maybe_opt T T1 T2 T' ts1 ts2 end
   647       | term_for_rep _ seen T T' (Opt R) jss =
   653       | term_for_rep _ seen T T' (Opt R) jss =
   648         if null jss then Const (unknown, T)
   654         if null jss then Const (unknown, T)
   649         else term_for_rep true seen T T' R jss
   655         else term_for_rep true seen T T' R jss
   650       | term_for_rep _ _ T _ R jss =
   656       | term_for_rep _ _ T _ R jss =
   651         raise ARG ("Nitpick_Model.reconstruct_term.term_for_rep",
   657         raise ARG ("Nitpick_Model.reconstruct_term.term_for_rep",
  1043                     (Object_Logic.atomize_term thy prop)
  1049                     (Object_Logic.atomize_term thy prop)
  1044         val prop = HOLogic.mk_Trueprop (HOLogic.mk_imp (assm, concl))
  1050         val prop = HOLogic.mk_Trueprop (HOLogic.mk_imp (assm, concl))
  1045                    |> map_types (map_type_tfree
  1051                    |> map_types (map_type_tfree
  1046                                      (fn (s, []) => TFree (s, HOLogic.typeS)
  1052                                      (fn (s, []) => TFree (s, HOLogic.typeS)
  1047                                        | x => TFree x))
  1053                                        | x => TFree x))
  1048        val _ = if debug then
  1054         val _ =
  1049                  Output.urgent_message ((if negate then "Genuineness" else "Spuriousness") ^
  1055           if debug then
  1050                            " goal: " ^ Syntax.string_of_term ctxt prop ^ ".")
  1056             (if negate then "Genuineness" else "Spuriousness") ^ " goal: " ^
  1051                else
  1057             Syntax.string_of_term ctxt prop ^ "."
  1052                  ()
  1058             |> Output.urgent_message
       
  1059           else
       
  1060             ()
  1053         val goal = prop |> cterm_of thy |> Goal.init
  1061         val goal = prop |> cterm_of thy |> Goal.init
  1054       in
  1062       in
  1055         (goal |> SINGLE (DETERM_TIMEOUT auto_timeout (auto_tac ctxt))
  1063         (goal |> SINGLE (DETERM_TIMEOUT auto_timeout (auto_tac ctxt))
  1056               |> the |> Goal.finish ctxt; true)
  1064               |> the |> Goal.finish ctxt; true)
  1057         handle THM _ => false
  1065         handle THM _ => false