src/HOL/Tools/Nitpick/nitpick_nut.ML
changeset 36913 0010f08e288e
parent 36912 55b97cb3806e
child 37256 0dca1ec52999
equal deleted inserted replaced
36912:55b97cb3806e 36913:0010f08e288e
   393     (case fast_string_ord (s1, s2) of
   393     (case fast_string_ord (s1, s2) of
   394        EQUAL => Term_Ord.typ_ord (T1, T2)
   394        EQUAL => Term_Ord.typ_ord (T1, T2)
   395      | ord => ord)
   395      | ord => ord)
   396   | name_ord (u1, u2) = raise NUT ("Nitpick_Nut.name_ord", [u1, u2])
   396   | name_ord (u1, u2) = raise NUT ("Nitpick_Nut.name_ord", [u1, u2])
   397 
   397 
   398 fun num_occs_in_nut needle_u stack_u =
   398 fun num_occurrences_in_nut needle_u stack_u =
   399   fold_nut (fn u => if u = needle_u then Integer.add 1 else I) stack_u 0
   399   fold_nut (fn u => if u = needle_u then Integer.add 1 else I) stack_u 0
   400 val is_subterm_of = not_equal 0 oo num_occs_in_nut
   400 val is_subnut_of = not_equal 0 oo num_occurrences_in_nut
   401 
   401 
   402 fun substitute_in_nut needle_u needle_u' =
   402 fun substitute_in_nut needle_u needle_u' =
   403   map_nut (fn u => if u = needle_u then needle_u' else u)
   403   map_nut (fn u => if u = needle_u then needle_u' else u)
   404 
   404 
   405 val add_free_and_const_names =
   405 val add_free_and_const_names =
   470           end
   470           end
   471         fun do_quantifier quant s T t1 =
   471         fun do_quantifier quant s T t1 =
   472           let
   472           let
   473             val bound_u = BoundName (length Ts, T, Any, s)
   473             val bound_u = BoundName (length Ts, T, Any, s)
   474             val body_u = sub_abs s T t1
   474             val body_u = sub_abs s T t1
   475           in
   475           in Op2 (quant, bool_T, Any, bound_u, body_u) end
   476             if is_subterm_of bound_u body_u then
       
   477               Op2 (quant, bool_T, Any, bound_u, body_u)
       
   478             else
       
   479               body_u
       
   480           end
       
   481         fun do_apply t0 ts =
   476         fun do_apply t0 ts =
   482           let
   477           let
   483             val (ts', t2) = split_last ts
   478             val (ts', t2) = split_last ts
   484             val t1 = list_comb (t0, ts')
   479             val t1 = list_comb (t0, ts')
   485             val T1 = fastype_of1 (Ts, t1)
   480             val T1 = fastype_of1 (Ts, t1)
   747   let val R = best_one_rep_for_type scope (type_of v) in
   742   let val R = best_one_rep_for_type scope (type_of v) in
   748     NameTable.update (v, R) table
   743     NameTable.update (v, R) table
   749   end
   744   end
   750 
   745 
   751 (* A nut is said to be constructive if whenever it evaluates to unknown in our
   746 (* A nut is said to be constructive if whenever it evaluates to unknown in our
   752    three-valued logic, it would evaluate to a unrepresentable value ("Unrep")
   747    three-valued logic, it would evaluate to an unrepresentable value ("Unrep")
   753    according to the HOL semantics. For example, "Suc n" is constructive if "n"
   748    according to the HOL semantics. For example, "Suc n" is constructive if "n"
   754    is representable or "Unrep", because unknown implies "Unrep". *)
   749    is representable or "Unrep", because unknown implies "Unrep". *)
   755 fun is_constructive u =
   750 fun is_constructive u =
   756   is_Cst Unrep u orelse
   751   is_Cst Unrep u orelse
   757   (not (is_fun_type (type_of u)) andalso not (is_opt_rep (rep_of u))) orelse
   752   (not (is_fun_type (type_of u)) andalso not (is_opt_rep (rep_of u))) orelse
   774 fun is_fully_representable_set u =
   769 fun is_fully_representable_set u =
   775   not (is_opt_rep (rep_of u)) andalso
   770   not (is_opt_rep (rep_of u)) andalso
   776   case u of
   771   case u of
   777     FreeName _ => true
   772     FreeName _ => true
   778   | Op1 (SingletonSet, _, _, _) => true
   773   | Op1 (SingletonSet, _, _, _) => true
       
   774   | Op1 (Converse, _, _, u1) => is_fully_representable_set u1
   779   | Op2 (oper, _, _, u1, u2) =>
   775   | Op2 (oper, _, _, u1, u2) =>
   780     member (op =) [Union, SetDifference, Intersect] oper andalso
   776     if oper = Union orelse oper = SetDifference orelse oper = Intersect then
   781     forall is_fully_representable_set [u1, u2]
   777       forall is_fully_representable_set [u1, u2]
       
   778     else if oper = Apply then
       
   779       case u1 of
       
   780         ConstName (s, _, _) => is_sel_like_and_no_discr s
       
   781       | _ => false
       
   782     else
       
   783       false
   782   | _ => false
   784   | _ => false
   783 
   785 
   784 fun s_op1 oper T R u1 =
   786 fun s_op1 oper T R u1 =
   785   ((if oper = Not then
   787   ((if oper = Not then
   786       if is_Cst True u1 then Cst (False, T, R)
   788       if is_Cst True u1 then Cst (False, T, R)
   790       raise SAME ())
   792       raise SAME ())
   791    handle SAME () => Op1 (oper, T, R, u1))
   793    handle SAME () => Op1 (oper, T, R, u1))
   792   |> optimize_unit
   794   |> optimize_unit
   793 fun s_op2 oper T R u1 u2 =
   795 fun s_op2 oper T R u1 u2 =
   794   ((case oper of
   796   ((case oper of
   795       Or =>
   797       All => if is_subnut_of u1 u2 then Op2 (All, T, R, u1, u2) else u2
       
   798     | Exist => if is_subnut_of u1 u2 then Op2 (Exist, T, R, u1, u2) else u2
       
   799     | Or =>
   796       if exists (is_Cst True) [u1, u2] then Cst (True, T, unopt_rep R)
   800       if exists (is_Cst True) [u1, u2] then Cst (True, T, unopt_rep R)
   797       else if is_Cst False u1 then u2
   801       else if is_Cst False u1 then u2
   798       else if is_Cst False u2 then u1
   802       else if is_Cst False u2 then u1
   799       else raise SAME ()
   803       else raise SAME ()
   800     | And =>
   804     | And =>
   814       else raise SAME ()
   818       else raise SAME ()
   815     | Apply =>
   819     | Apply =>
   816       if is_Cst Unrep u1 then
   820       if is_Cst Unrep u1 then
   817         Cst (Unrep, T, R)
   821         Cst (Unrep, T, R)
   818       else if is_Cst Unrep u2 then
   822       else if is_Cst Unrep u2 then
   819         if is_constructive u1 then
   823         if is_boolean_type T then
   820           Cst (Unrep, T, R)
       
   821         else if is_boolean_type T then
       
   822           if is_fully_representable_set u1 then Cst (False, T, Formula Neut)
   824           if is_fully_representable_set u1 then Cst (False, T, Formula Neut)
   823           else unknown_boolean T R
   825           else unknown_boolean T R
       
   826         else if is_constructive u1 then
       
   827           Cst (Unrep, T, R)
   824         else case u1 of
   828         else case u1 of
   825           Op2 (Apply, _, _, ConstName (@{const_name List.append}, _, _), _) =>
   829           Op2 (Apply, _, _, ConstName (@{const_name List.append}, _, _), _) =>
   826           Cst (Unrep, T, R)
   830           Cst (Unrep, T, R)
   827         | _ => raise SAME ()
   831         | _ => raise SAME ()
   828       else
   832       else
   831    handle SAME () => Op2 (oper, T, R, u1, u2))
   835    handle SAME () => Op2 (oper, T, R, u1, u2))
   832   |> optimize_unit
   836   |> optimize_unit
   833 fun s_op3 oper T R u1 u2 u3 =
   837 fun s_op3 oper T R u1 u2 u3 =
   834   ((case oper of
   838   ((case oper of
   835       Let =>
   839       Let =>
   836       if inline_nut u2 orelse num_occs_in_nut u1 u3 < 2 then
   840       if inline_nut u2 orelse num_occurrences_in_nut u1 u3 < 2 then
   837         substitute_in_nut u1 u2 u3
   841         substitute_in_nut u1 u2 u3
   838       else
   842       else
   839         raise SAME ()
   843         raise SAME ()
   840     | _ => raise SAME ())
   844     | _ => raise SAME ())
   841    handle SAME () => Op3 (oper, T, R, u1, u2, u3))
   845    handle SAME () => Op3 (oper, T, R, u1, u2, u3))
   842   |> optimize_unit
   846   |> optimize_unit
   843 fun s_tuple T R us =
   847 fun s_tuple T R us =
   844   (if exists (is_Cst Unrep) us then Cst (Unrep, T, R) else Tuple (T, R, us))
   848   (if exists (is_Cst Unrep) us then Cst (Unrep, T, R) else Tuple (T, R, us))
   845   |> optimize_unit
   849   |> optimize_unit
   846 
       
   847 fun optimize_nut u =
       
   848   case u of
       
   849     Op1 (oper, T, R, u1) => s_op1 oper T R (optimize_nut u1)
       
   850   | Op2 (oper, T, R, u1, u2) =>
       
   851     s_op2 oper T R (optimize_nut u1) (optimize_nut u2)
       
   852   | Op3 (oper, T, R, u1, u2, u3) =>
       
   853     s_op3 oper T R (optimize_nut u1) (optimize_nut u2) (optimize_nut u3)
       
   854   | Tuple (T, R, us) => s_tuple T R (map optimize_nut us)
       
   855   | Construct (us', T, R, us) => Construct (us', T, R, map optimize_nut us)
       
   856   | _ => optimize_unit u
       
   857 
   850 
   858 fun untuple f (Tuple (_, _, us)) = maps (untuple f) us
   851 fun untuple f (Tuple (_, _, us)) = maps (untuple f) us
   859   | untuple f u = if rep_of u = Unit then [] else [f u]
   852   | untuple f u = if rep_of u = Unit then [] else [f u]
   860 
   853 
   861 fun choose_reps_in_nut (scope as {card_assigns, bits, datatypes, ofs, ...})
   854 fun choose_reps_in_nut (scope as {card_assigns, bits, datatypes, ofs, ...})
  1031                      Op2 (Lambda, T, Any, y_u,
  1024                      Op2 (Lambda, T, Any, y_u,
  1032                           Op2 (Exist, bool_T, Any, x_u,
  1025                           Op2 (Exist, bool_T, Any, x_u,
  1033                                Op2 (And, bool_T, Any,
  1026                                Op2 (And, bool_T, Any,
  1034                                     case u2 of
  1027                                     case u2 of
  1035                                       Op2 (Lambda, _, _, u21, u22) =>
  1028                                       Op2 (Lambda, _, _, u21, u22) =>
  1036                                       if num_occs_in_nut u21 u22 = 0 then
  1029                                       if num_occurrences_in_nut u21 u22 = 0 then
  1037                                         u22
  1030                                         u22
  1038                                       else
  1031                                       else
  1039                                         Op2 (Apply, bool_T, Any, u2, x_u)
  1032                                         Op2 (Apply, bool_T, Any, u2, x_u)
  1040                                     | _ => Op2 (Apply, bool_T, Any, u2, x_u),
  1033                                     | _ => Op2 (Apply, bool_T, Any, u2, x_u),
  1041 
  1034 
  1073                val u2' = aux table' false Neut u2
  1066                val u2' = aux table' false Neut u2
  1074                val R =
  1067                val R =
  1075                  if is_opt_rep (rep_of u2') orelse
  1068                  if is_opt_rep (rep_of u2') orelse
  1076                     (range_type T = bool_T andalso
  1069                     (range_type T = bool_T andalso
  1077                      not (is_Cst False (unrepify_nut_in_nut table false Neut
  1070                      not (is_Cst False (unrepify_nut_in_nut table false Neut
  1078                                                             u1 u2
  1071                                                             u1 u2))) then
  1079                                         |> optimize_nut))) then
       
  1080                    opt_rep ofs T R
  1072                    opt_rep ofs T R
  1081                  else
  1073                  else
  1082                    unopt_rep R
  1074                    unopt_rep R
  1083              in s_op2 Lambda T R u1' u2' end
  1075              in s_op2 Lambda T R u1' u2' end
  1084            | _ => raise NUT ("Nitpick_Nut.aux.choose_reps_in_nut", [u]))
  1076            | _ => raise NUT ("Nitpick_Nut.choose_reps_in_nut.aux", [u]))
  1085         | Op2 (oper, T, _, u1, u2) =>
  1077         | Op2 (oper, T, _, u1, u2) =>
  1086           if oper = All orelse oper = Exist then
  1078           if oper = All orelse oper = Exist then
  1087             let
  1079             let
  1088               val table' = fold (choose_rep_for_bound_var scope) (untuple I u1)
  1080               val table' = fold (choose_rep_for_bound_var scope) (untuple I u1)
  1089                                 table
  1081                                 table