src/HOL/Mutabelle/mutabelle_extra.ML
changeset 40653 d921c97bdbd8
parent 40381 96c37a685a13
child 40906 b5a319668955
equal deleted inserted replaced
40652:7bdfc1d6b143 40653:d921c97bdbd8
     6 signature MUTABELLE_EXTRA =
     6 signature MUTABELLE_EXTRA =
     7 sig
     7 sig
     8 
     8 
     9 val take_random : int -> 'a list -> 'a list
     9 val take_random : int -> 'a list -> 'a list
    10 
    10 
    11 datatype outcome = GenuineCex | PotentialCex | NoCex | Donno | Timeout | Error
    11 datatype outcome = GenuineCex | PotentialCex | NoCex | Donno | Timeout | Error | Solved | Unsolved
    12 type timing = (string * int) list
    12 type timing = (string * int) list
    13 
    13 
    14 type mtd = string * (theory -> term -> outcome * (timing * (int * Quickcheck.report list) list option))
    14 type mtd = string * (theory -> term -> outcome * (timing * (int * Quickcheck.report list) list option))
    15 
    15 
    16 type mutant_subentry = term * (string * (outcome * (timing * Quickcheck.report option))) list
    16 type mutant_subentry = term * (string * (outcome * (timing * Quickcheck.report option))) list
    18 
    18 
    19 type subentry = string * int * int * int * int * int * int
    19 type subentry = string * int * int * int * int * int * int
    20 type entry = string * bool * subentry list
    20 type entry = string * bool * subentry list
    21 type report = entry list
    21 type report = entry list
    22 
    22 
    23 val quickcheck_mtd : string -> mtd
    23 val quickcheck_mtd : (Proof.context -> Proof.context) -> string -> mtd
       
    24 
       
    25 val solve_direct_mtd : mtd
       
    26 val try_mtd : mtd
    24 (*
    27 (*
    25 val refute_mtd : mtd
    28 val refute_mtd : mtd
    26 val nitpick_mtd : mtd
    29 val nitpick_mtd : mtd
    27 *)
    30 *)
    28 
    31 
    43 (* Own seed; can't rely on the Isabelle one to stay the same *)
    46 (* Own seed; can't rely on the Isabelle one to stay the same *)
    44 val random_seed = Unsynchronized.ref 1.0;
    47 val random_seed = Unsynchronized.ref 1.0;
    45 
    48 
    46 
    49 
    47 (* mutation options *)
    50 (* mutation options *)
    48 val max_mutants = 4
    51 (*val max_mutants = 4
       
    52 val num_mutations = 1*)
       
    53 (* soundness check: *)
       
    54 val max_mutants =  10
    49 val num_mutations = 1
    55 val num_mutations = 1
    50 (* soundness check: *)
       
    51 (*val max_mutants = 1
       
    52 val num_mutations = 0*)
       
    53 
    56 
    54 (* quickcheck options *)
    57 (* quickcheck options *)
    55 (*val quickcheck_generator = "SML"*)
    58 (*val quickcheck_generator = "SML"*)
       
    59 
       
    60 (* Another Random engine *)
    56 
    61 
    57 exception RANDOM;
    62 exception RANDOM;
    58 
    63 
    59 fun rmod x y = x - y * Real.realFloor (x / y);
    64 fun rmod x y = x - y * Real.realFloor (x / y);
    60 
    65 
    71 
    76 
    72 fun random_range l h =
    77 fun random_range l h =
    73   if h < l orelse l < 0 then raise RANDOM
    78   if h < l orelse l < 0 then raise RANDOM
    74   else l + Real.floor (rmod (random ()) (real (h - l + 1)));
    79   else l + Real.floor (rmod (random ()) (real (h - l + 1)));
    75 
    80 
    76 datatype outcome = GenuineCex | PotentialCex | NoCex | Donno | Timeout | Error
    81 fun take_random 0 _ = []
       
    82   | take_random _ [] = []
       
    83   | take_random n xs =
       
    84     let val j = random_range 0 (length xs - 1) in
       
    85       Library.nth xs j :: take_random (n - 1) (nth_drop j xs)
       
    86     end
       
    87   
       
    88 (* possible outcomes *)
       
    89 
       
    90 datatype outcome = GenuineCex | PotentialCex | NoCex | Donno | Timeout | Error | Solved | Unsolved
       
    91 
       
    92 fun string_of_outcome GenuineCex = "GenuineCex"
       
    93   | string_of_outcome PotentialCex = "PotentialCex"
       
    94   | string_of_outcome NoCex = "NoCex"
       
    95   | string_of_outcome Donno = "Donno"
       
    96   | string_of_outcome Timeout = "Timeout"
       
    97   | string_of_outcome Error = "Error"
       
    98   | string_of_outcome Solved = "Solved"
       
    99   | string_of_outcome Unsolved = "Unsolved"
       
   100 
    77 type timing = (string * int) list
   101 type timing = (string * int) list
    78 
   102 
    79 type mtd = string * (theory -> term -> outcome * (timing * (int * Quickcheck.report list) list option))
   103 type mtd = string * (theory -> term -> outcome * (timing * (int * Quickcheck.report list) list option))
    80 
   104 
    81 type mutant_subentry = term * (string * (outcome * (timing * Quickcheck.report option))) list
   105 type mutant_subentry = term * (string * (outcome * (timing * Quickcheck.report option))) list
    83 
   107 
    84 type subentry = string * int * int * int * int * int * int
   108 type subentry = string * int * int * int * int * int * int
    85 type entry = string * bool * subentry list
   109 type entry = string * bool * subentry list
    86 type report = entry list
   110 type report = entry list
    87 
   111 
    88 fun inst_type insts (Type (s, Ts)) = Type (s, map (inst_type insts) Ts)
   112 (* possible invocations *)
    89   | inst_type insts T = the_default HOLogic.intT (AList.lookup op = insts T)
   113 
    90 
   114 (** quickcheck **)
    91 fun preprocess thy insts t = Object_Logic.atomize_term thy
   115 
    92  (map_types (inst_type insts) (Mutabelle.freeze t));
   116 fun invoke_quickcheck change_options quickcheck_generator thy t =
    93 
       
    94 fun invoke_quickcheck quickcheck_generator thy t =
       
    95   TimeLimit.timeLimit (Time.fromSeconds (!Auto_Tools.time_limit))
   117   TimeLimit.timeLimit (Time.fromSeconds (!Auto_Tools.time_limit))
    96       (fn _ =>
   118       (fn _ =>
    97           case Quickcheck.test_term (ProofContext.init_global thy)
   119           case Quickcheck.test_goal_terms (change_options (ProofContext.init_global thy))
    98               (SOME quickcheck_generator) (preprocess thy [] t) of
   120               (SOME quickcheck_generator, []) [t] of
    99             (NONE, (time_report, report)) => (NoCex, (time_report, report))
   121             (NONE, _) => (NoCex, ([], NONE))
   100           | (SOME _, (time_report, report)) => (GenuineCex, (time_report, report))) ()
   122           | (SOME _, _) => (GenuineCex, ([], NONE))) ()
   101   handle TimeLimit.TimeOut => (Timeout, ([("timelimit", !Auto_Tools.time_limit)], NONE))
   123   handle TimeLimit.TimeOut => (Timeout, ([("timelimit", !Auto_Tools.time_limit)], NONE))
   102 
   124 
   103 fun quickcheck_mtd quickcheck_generator =
   125 fun quickcheck_mtd change_options quickcheck_generator =
   104   ("quickcheck_" ^ quickcheck_generator, invoke_quickcheck quickcheck_generator)
   126   ("quickcheck_" ^ quickcheck_generator, invoke_quickcheck change_options quickcheck_generator)
   105 
   127 
   106   (*
   128 (** solve direct **)
       
   129  
       
   130 fun invoke_solve_direct thy t =
       
   131   let
       
   132     val state = Proof.theorem NONE (K I) (map (single o rpair []) [t]) (ProofContext.init_global thy) 
       
   133   in
       
   134     case Solve_Direct.solve_direct false state of
       
   135       (true, _) => (Solved, ([], NONE))
       
   136     | (false, _) => (Unsolved, ([], NONE))
       
   137   end
       
   138 
       
   139 val solve_direct_mtd = ("solve_direct", invoke_solve_direct) 
       
   140 
       
   141 (** try **)
       
   142 
       
   143 fun invoke_try thy t =
       
   144   let
       
   145     val state = Proof.theorem NONE (K I) (map (single o rpair []) [t]) (ProofContext.init_global thy) 
       
   146   in
       
   147     case Try.invoke_try NONE state of
       
   148       true => (Solved, ([], NONE))
       
   149     | false => (Unsolved, ([], NONE))
       
   150   end
       
   151 
       
   152 val try_mtd = ("try", invoke_try)
       
   153 
       
   154 (*
   107 fun invoke_refute thy t =
   155 fun invoke_refute thy t =
   108   let
   156   let
   109     val res = MyRefute.refute_term thy [] t
   157     val res = MyRefute.refute_term thy [] t
   110     val _ = Output.urgent_message ("Refute: " ^ res)
   158     val _ = Output.urgent_message ("Refute: " ^ res)
   111   in
   159   in
   183          | _ => (Output.urgent_message ("Unknown error in Nitpick"); Error)
   231          | _ => (Output.urgent_message ("Unknown error in Nitpick"); Error)
   184   end
   232   end
   185 val nitpick_mtd = ("nitpick", invoke_nitpick)
   233 val nitpick_mtd = ("nitpick", invoke_nitpick)
   186 *)
   234 *)
   187 
   235 
       
   236 (* filtering forbidden theorems and mutants *)
       
   237 
   188 val comms = [@{const_name HOL.eq}, @{const_name HOL.disj}, @{const_name HOL.conj}]
   238 val comms = [@{const_name HOL.eq}, @{const_name HOL.disj}, @{const_name HOL.conj}]
   189 
   239 
   190 val forbidden =
   240 val forbidden =
   191  [(* (@{const_name "power"}, "'a"), *)
   241  [(* (@{const_name "power"}, "'a"), *)
   192   (*(@{const_name induct_equal}, "'a"),
   242   (*(@{const_name induct_equal}, "'a"),
   198   (@{const_name "HOL.simp_implies"}, "prop => prop => prop"),
   248   (@{const_name "HOL.simp_implies"}, "prop => prop => prop"),
   199   (@{const_name "bot_fun_inst.bot_fun"}, "'a"),
   249   (@{const_name "bot_fun_inst.bot_fun"}, "'a"),
   200   (@{const_name "top_fun_inst.top_fun"}, "'a"),
   250   (@{const_name "top_fun_inst.top_fun"}, "'a"),
   201   (@{const_name "Pure.term"}, "'a"),
   251   (@{const_name "Pure.term"}, "'a"),
   202   (@{const_name "top_class.top"}, "'a"),
   252   (@{const_name "top_class.top"}, "'a"),
   203   (@{const_name "HOL.equal"}, "'a"),
       
   204   (@{const_name "Quotient.Quot_True"}, "'a")(*,
   253   (@{const_name "Quotient.Quot_True"}, "'a")(*,
   205   (@{const_name "uminus"}, "'a"),
   254   (@{const_name "uminus"}, "'a"),
   206   (@{const_name "Nat.size"}, "'a"),
   255   (@{const_name "Nat.size"}, "'a"),
   207   (@{const_name "Groups.abs"}, "'a") *)]
   256   (@{const_name "Groups.abs"}, "'a") *)]
   208 
   257 
   209 val forbidden_thms =
   258 val forbidden_thms =
   210  ["finite_intvl_succ_class",
   259  ["finite_intvl_succ_class",
   211   "nibble"]
   260   "nibble"]
   212 
   261 
   213 val forbidden_consts =
   262 val forbidden_consts =
   214  [@{const_name nibble_pair_of_char}]
   263  [@{const_name nibble_pair_of_char}, @{const_name "TYPE"}]
   215 
   264 
   216 fun is_forbidden_theorem (s, th) =
   265 fun is_forbidden_theorem (s, th) =
   217   let val consts = Term.add_const_names (prop_of th) [] in
   266   let val consts = Term.add_const_names (prop_of th) [] in
   218     exists (member (op =) (space_explode "." s)) forbidden_thms orelse
   267     exists (member (op =) (space_explode "." s)) forbidden_thms orelse
   219     exists (member (op =) forbidden_consts) consts orelse
   268     exists (member (op =) forbidden_consts) consts orelse
   220     length (space_explode "." s) <> 2 orelse
   269     length (space_explode "." s) <> 2 orelse
   221     String.isPrefix "type_definition" (List.last (space_explode "." s)) orelse
   270     String.isPrefix "type_definition" (List.last (space_explode "." s)) orelse
   222     String.isSuffix "_def" s orelse
   271     String.isSuffix "_def" s orelse
   223     String.isSuffix "_raw" s
   272     String.isSuffix "_raw" s orelse
       
   273     String.isPrefix "term_of" (List.last (space_explode "." s))
   224   end
   274   end
   225 
   275 
   226 val forbidden_mutant_constnames =
   276 val forbidden_mutant_constnames =
   227  ["HOL.induct_equal",
   277  ["HOL.induct_equal",
   228   "HOL.induct_implies",
   278   "HOL.induct_implies",
   233  @{const_name "HOL.simp_implies"},
   283  @{const_name "HOL.simp_implies"},
   234  @{const_name "bot_fun_inst.bot_fun"},
   284  @{const_name "bot_fun_inst.bot_fun"},
   235  @{const_name "top_fun_inst.top_fun"},
   285  @{const_name "top_fun_inst.top_fun"},
   236  @{const_name "Pure.term"},
   286  @{const_name "Pure.term"},
   237  @{const_name "top_class.top"},
   287  @{const_name "top_class.top"},
   238  @{const_name "HOL.equal"},
   288  (*@{const_name "HOL.equal"},*)
   239  @{const_name "Quotient.Quot_True"}]
   289  @{const_name "Quotient.Quot_True"}
       
   290  (*@{const_name "==>"}, @{const_name "=="}*)]
       
   291 
       
   292 val forbidden_mutant_consts =
       
   293   [
       
   294    (@{const_name "Groups.zero_class.zero"}, @{typ "prop => prop => prop"}),
       
   295    (@{const_name "Groups.one_class.one"}, @{typ "prop => prop => prop"}),
       
   296    (@{const_name "Groups.plus_class.plus"}, @{typ "prop => prop => prop"}),
       
   297    (@{const_name "Groups.minus_class.minus"}, @{typ "prop => prop => prop"}),
       
   298    (@{const_name "Groups.times_class.times"}, @{typ "prop => prop => prop"}),
       
   299    (@{const_name "Rings.inverse_class.divide"}, @{typ "prop => prop => prop"}),
       
   300    (@{const_name "Lattices.semilattice_inf_class.inf"}, @{typ "prop => prop => prop"}),
       
   301    (@{const_name "Lattices.semilattice_sup_class.sup"}, @{typ "prop => prop => prop"}),
       
   302    (@{const_name "Orderings.bot_class.bot"}, @{typ "prop => prop => prop"}),
       
   303    (@{const_name "Orderings.ord_class.min"}, @{typ "prop => prop => prop"}),
       
   304    (@{const_name "Orderings.ord_class.max"}, @{typ "prop => prop => prop"}),
       
   305    (@{const_name "Divides.div_class.mod"}, @{typ "prop => prop => prop"}),
       
   306    (@{const_name "Divides.div_class.div"}, @{typ "prop => prop => prop"}),
       
   307    (@{const_name "GCD.gcd_class.gcd"}, @{typ "prop => prop => prop"}),
       
   308    (@{const_name "GCD.gcd_class.lcm"}, @{typ "prop => prop => prop"}),
       
   309    (@{const_name "Orderings.bot_class.bot"}, @{typ "bool => prop"}),
       
   310    (@{const_name "Groups.one_class.one"}, @{typ "bool => prop"}),
       
   311    (@{const_name "Groups.zero_class.zero"},@{typ "bool => prop"})]
   240 
   312 
   241 fun is_forbidden_mutant t =
   313 fun is_forbidden_mutant t =
   242   let
   314   let
   243     val consts = Term.add_const_names t []
   315     val const_names = Term.add_const_names t []
   244   in
   316     val consts = Term.add_consts t []
   245     exists (String.isPrefix "Nitpick") consts orelse
   317   in
   246     exists (String.isSubstring "_sumC") consts orelse
   318     exists (String.isPrefix "Nitpick") const_names orelse
   247     exists (member (op =) forbidden_mutant_constnames) consts
   319     exists (String.isSubstring "_sumC") const_names orelse
   248   end
   320     exists (member (op =) forbidden_mutant_constnames) const_names orelse
       
   321     exists (member (op =) forbidden_mutant_consts) consts
       
   322   end
       
   323 
       
   324 (* executable via quickcheck *)
   249 
   325 
   250 fun is_executable_term thy t =
   326 fun is_executable_term thy t =
   251   can (TimeLimit.timeLimit (seconds 2.0)
   327   let
   252     (Quickcheck.test_term
   328     val ctxt = ProofContext.init_global thy
   253       (Context.proof_map (Quickcheck.map_test_params (apfst (K (1, 0)))) (ProofContext.init_global thy))
   329   in
   254       (SOME "SML"))) (preprocess thy [] t)
   330     can (TimeLimit.timeLimit (seconds 2.0)
       
   331       (Quickcheck.test_goal_terms
       
   332         ((Config.put Quickcheck.finite_types true #>
       
   333           Config.put Quickcheck.size 1 #> Config.put Quickcheck.iterations 1) ctxt)
       
   334         (SOME "random" , []))) (map (Object_Logic.atomize_term thy) (fst (Variable.import_terms true [t] ctxt)))
       
   335   end
   255 
   336 
   256 fun is_executable_thm thy th = is_executable_term thy (prop_of th)
   337 fun is_executable_thm thy th = is_executable_term thy (prop_of th)
   257 
   338 
   258 val freezeT =
   339 val freezeT =
   259   map_types (map_type_tvar (fn ((a, i), S) =>
   340   map_types (map_type_tvar (fn ((a, i), S) =>
   265       (* andalso is_executable_thm thy th *))
   346       (* andalso is_executable_thm thy th *))
   266     (map snd (filter_out is_forbidden_theorem (Mutabelle.all_unconcealed_thms_of thy)))
   347     (map snd (filter_out is_forbidden_theorem (Mutabelle.all_unconcealed_thms_of thy)))
   267 
   348 
   268 val count = length oo filter o equal
   349 val count = length oo filter o equal
   269 
   350 
   270 fun take_random 0 _ = []
       
   271   | take_random _ [] = []
       
   272   | take_random n xs =
       
   273     let val j = random_range 0 (length xs - 1) in
       
   274       Library.nth xs j :: take_random (n - 1) (nth_drop j xs)
       
   275     end
       
   276 
       
   277 fun cpu_time description f =
   351 fun cpu_time description f =
   278   let
   352   let
   279     val start = start_timing ()
   353     val start = start_timing ()
   280     val result = Exn.capture f ()
   354     val result = Exn.capture f ()
   281     val time = Time.toMilliseconds (#cpu (end_timing start))
   355     val time = Time.toMilliseconds (#cpu (end_timing start))
   282   in (Exn.release result, (description, time)) end
   356   in (Exn.release result, (description, time)) end
   283 
   357 (*
       
   358 fun unsafe_invoke_mtd thy (mtd_name, invoke_mtd) t =
       
   359   let
       
   360     val _ = Output.urgent_message ("Invoking " ^ mtd_name)
       
   361     val ((res, (timing, reports)), time) = cpu_time "total time" (fn () => invoke_mtd thy t
       
   362       handle ERROR s => (tracing s; (Error, ([], NONE))))
       
   363     val _ = Output.urgent_message (" Done")
       
   364   in (res, (time :: timing, reports)) end
       
   365 *)  
   284 fun safe_invoke_mtd thy (mtd_name, invoke_mtd) t =
   366 fun safe_invoke_mtd thy (mtd_name, invoke_mtd) t =
   285   let
   367   let
   286     val _ = Output.urgent_message ("Invoking " ^ mtd_name)
   368     val _ = Output.urgent_message ("Invoking " ^ mtd_name)
   287     val ((res, (timing, reports)), time) = cpu_time "total time"
   369     val (res, (timing, reports)) = (*cpu_time "total time"
   288       (fn () => case try (invoke_mtd thy) t of
   370       (fn () => *)case try (invoke_mtd thy) t of
   289           SOME (res, (timing, reports)) => (res, (timing, reports))
   371           SOME (res, (timing, reports)) => (res, (timing, reports))
   290         | NONE => (Output.urgent_message ("**** PROBLEMS WITH " ^ Syntax.string_of_term_global thy t);
   372         | NONE => (Output.urgent_message ("**** PROBLEMS WITH " ^ Syntax.string_of_term_global thy t);
   291            (Error , ([], NONE))))
   373            (Error, ([], NONE)))
   292     val _ = Output.urgent_message (" Done")
   374     val _ = Output.urgent_message (" Done")
   293   in (res, (time :: timing, reports)) end
   375   in (res, (timing, reports)) end
   294 
   376 
   295 (* theory -> term list -> mtd -> subentry *)
   377 (* theory -> term list -> mtd -> subentry *)
   296 (*
   378 
   297 fun test_mutants_using_one_method thy mutants (mtd_name, invoke_mtd) =
   379 fun test_mutants_using_one_method thy mutants (mtd_name, invoke_mtd) =
   298   let
   380   let
   299      val res = map (safe_invoke_mtd thy (mtd_name, invoke_mtd)) mutants
   381      val res = map (fst o safe_invoke_mtd thy (mtd_name, invoke_mtd)) mutants
   300   in
   382   in
   301     (mtd_name, count GenuineCex res, count PotentialCex res, count NoCex res,
   383     (mtd_name, count GenuineCex res, count PotentialCex res, count NoCex res,
   302      count Donno res, count Timeout res, count Error res)
   384      count Donno res, count Timeout res, count Error res)
   303   end
   385   end
   304 
   386 
       
   387 (* creating entries *)
       
   388 
   305 fun create_entry thy thm exec mutants mtds =
   389 fun create_entry thy thm exec mutants mtds =
   306   (Thm.get_name_hint thm, exec, map (test_mutants_using_one_method thy mutants) mtds)
   390   (Thm.get_name_hint thm, exec, map (test_mutants_using_one_method thy mutants) mtds)
   307 *)
   391 
   308 fun create_detailed_entry thy thm exec mutants mtds =
   392 fun create_detailed_entry thy thm exec mutants mtds =
   309   let
   393   let
   310     fun create_mutant_subentry mutant = (mutant,
   394     fun create_mutant_subentry mutant = (mutant,
   311       map (fn (mtd_name, invoke_mtd) =>
   395       map (fn (mtd_name, invoke_mtd) =>
   312         (mtd_name, safe_invoke_mtd thy (mtd_name, invoke_mtd) mutant)) mtds)
   396         (mtd_name, safe_invoke_mtd thy (mtd_name, invoke_mtd) mutant)) mtds)
   316 
   400 
   317 (* (theory -> thm -> bool -> term list -> mtd list -> 'a) -> theory -> mtd list -> thm -> 'a *)
   401 (* (theory -> thm -> bool -> term list -> mtd list -> 'a) -> theory -> mtd list -> thm -> 'a *)
   318 fun mutate_theorem create_entry thy mtds thm =
   402 fun mutate_theorem create_entry thy mtds thm =
   319   let
   403   let
   320     val exec = is_executable_thm thy thm
   404     val exec = is_executable_thm thy thm
   321     val _ = Output.urgent_message (if exec then "EXEC" else "NOEXEC")
   405     val _ = Output.tracing (if exec then "EXEC" else "NOEXEC")
   322     val mutants =
   406     val mutants =
   323           (if num_mutations = 0 then
   407           (if num_mutations = 0 then
   324              [Thm.prop_of thm]
   408              [Thm.prop_of thm]
   325            else
   409            else
   326              Mutabelle.mutate_mix (Thm.prop_of thm) thy comms forbidden
   410              Mutabelle.mutate_mix (Thm.prop_of thm) thy comms forbidden
   327                                   num_mutations)
   411                                   num_mutations)
       
   412              |> tap (fn muts => tracing ("mutants: " ^ string_of_int (length muts)))
   328              |> filter_out is_forbidden_mutant
   413              |> filter_out is_forbidden_mutant
   329     val mutants =
   414     val mutants =
   330       if exec then
   415       if exec then
   331         let
   416         let
   332           val _ = Output.urgent_message ("BEFORE PARTITION OF " ^
   417           val _ = Output.urgent_message ("BEFORE PARTITION OF " ^
   342     val mutants = mutants
   427     val mutants = mutants
   343           |> take_random max_mutants
   428           |> take_random max_mutants
   344           |> map Mutabelle.freeze |> map freezeT
   429           |> map Mutabelle.freeze |> map freezeT
   345 (*          |> filter (not o is_forbidden_mutant) *)
   430 (*          |> filter (not o is_forbidden_mutant) *)
   346           |> List.mapPartial (try (Sign.cert_term thy))
   431           |> List.mapPartial (try (Sign.cert_term thy))
       
   432           |> List.filter (is_some o try (cterm_of thy))
   347     val _ = map (fn t => Output.urgent_message ("MUTANT: " ^ Syntax.string_of_term_global thy t)) mutants
   433     val _ = map (fn t => Output.urgent_message ("MUTANT: " ^ Syntax.string_of_term_global thy t)) mutants
   348   in
   434   in
   349     create_entry thy thm exec mutants mtds
   435     create_entry thy thm exec mutants mtds
   350   end
   436   end
   351 
   437 
   352 (* theory -> mtd list -> thm list -> report *)
   438 (* theory -> mtd list -> thm list -> report *)
   353 val mutate_theorems = map ooo mutate_theorem
   439 val mutate_theorems = map ooo mutate_theorem
   354 
       
   355 fun string_of_outcome GenuineCex = "GenuineCex"
       
   356   | string_of_outcome PotentialCex = "PotentialCex"
       
   357   | string_of_outcome NoCex = "NoCex"
       
   358   | string_of_outcome Donno = "Donno"
       
   359   | string_of_outcome Timeout = "Timeout"
       
   360   | string_of_outcome Error = "Error"
       
   361 
   440 
   362 fun string_of_mutant_subentry thy thm_name (t, results) =
   441 fun string_of_mutant_subentry thy thm_name (t, results) =
   363   "mutant: " ^ Syntax.string_of_term_global thy t ^ "\n" ^
   442   "mutant: " ^ Syntax.string_of_term_global thy t ^ "\n" ^
   364   space_implode "; "
   443   space_implode "; "
   365     (map (fn (mtd_name, (outcome, timing)) => mtd_name ^ ": " ^ string_of_outcome outcome) results) ^
   444     (map (fn (mtd_name, (outcome, timing)) => mtd_name ^ ": " ^ string_of_outcome outcome) results) ^
   376     fun string_of_reports NONE = ""
   455     fun string_of_reports NONE = ""
   377       | string_of_reports (SOME reports) =
   456       | string_of_reports (SOME reports) =
   378         cat_lines (map (fn (size, [report]) =>
   457         cat_lines (map (fn (size, [report]) =>
   379           "size " ^ string_of_int size ^ ": " ^ string_of_report report) (rev reports))
   458           "size " ^ string_of_int size ^ ": " ^ string_of_report report) (rev reports))
   380     fun string_of_mtd_result (mtd_name, (outcome, (timing, reports))) =
   459     fun string_of_mtd_result (mtd_name, (outcome, (timing, reports))) =
   381       mtd_name ^ ": " ^ string_of_outcome outcome ^ "; " ^
   460       mtd_name ^ ": " ^ string_of_outcome outcome
   382       space_implode "; " (map (fn (s, t) => (s ^ ": " ^ string_of_int t)) timing)
   461       (*" with time " ^ " (" ^ space_implode "; " (map (fn (s, t) => (s ^ ": " ^ string_of_int t)) timing) ^ ")"*)
   383       (*^ "\n" ^ string_of_reports reports*)
   462       (*^ "\n" ^ string_of_reports reports*)
   384   in
   463   in
   385     "mutant of " ^ thm_name ^ ":\n"
   464     "mutant of " ^ thm_name ^ ":\n"
   386     ^ unyxml (Syntax.string_of_term_global thy t) ^ "\n" ^ cat_lines (map string_of_mtd_result results)
   465     ^ unyxml (Syntax.string_of_term_global thy t) ^ "\n" ^ space_implode "; " (map string_of_mtd_result results)
   387   end
   466   end
   388 
   467 
   389 fun string_of_detailed_entry thy (thm_name, exec, t, mutant_subentries) = 
   468 fun string_of_detailed_entry thy (thm_name, exec, t, mutant_subentries) = 
   390    thm_name ^ " " ^ (if exec then "[exe]" else "[noexe]") ^ ": " ^
   469    thm_name ^ " " ^ (if exec then "[exe]" else "[noexe]") ^ ": " ^
   391    Syntax.string_of_term_global thy t ^ "\n" ^                                    
   470    Syntax.string_of_term_global thy t ^ "\n" ^                                    
   392    cat_lines (map (string_of_mutant_subentry' thy thm_name) mutant_subentries) ^ "\n"
   471    cat_lines (map (string_of_mutant_subentry' thy thm_name) mutant_subentries) ^ "\n"
   393 
   472 
   394 fun theoryfile_string_of_mutant_subentry thy thm_name (i, (t, results)) =
   473 fun theoryfile_string_of_mutant_subentry thy thm_name (i, (t, results)) =
   395   "lemma " ^ thm_name ^ "_" ^ string_of_int (i + 1) ^ ":\n" ^
   474   "lemma " ^ thm_name ^ "_" ^ string_of_int (i + 1) ^ ":\n" ^
   396   "\"" ^ unyxml (Syntax.string_of_term_global thy t) ^
   475   "\"" ^ unyxml (Syntax.string_of_term_global thy t) ^
   397   "\" \nquickcheck[generator = SML]\nquickcheck[generator = predicate_compile_wo_ff]\n" ^
   476   "\" \nquickcheck\noops\n"
   398   "quickcheck[generator = predicate_compile_ff_nofs]\noops\n"
       
   399 
   477 
   400 fun theoryfile_string_of_detailed_entry thy (thm_name, exec, t, mutant_subentries) =
   478 fun theoryfile_string_of_detailed_entry thy (thm_name, exec, t, mutant_subentries) =
   401   "subsubsection {* mutants of " ^ thm_name ^ " *}\n\n" ^
   479   "subsubsection {* mutants of " ^ thm_name ^ " *}\n\n" ^
   402   cat_lines (map_index
   480   cat_lines (map_index
   403     (theoryfile_string_of_mutant_subentry thy thm_name) mutant_subentries) ^ "\n"
   481     (theoryfile_string_of_mutant_subentry thy thm_name) mutant_subentries) ^ "\n"
   407                          timeout, error) =
   485                          timeout, error) =
   408   "    " ^ mtd_name ^ ": " ^ Int.toString genuine_cex ^ "+ " ^
   486   "    " ^ mtd_name ^ ": " ^ Int.toString genuine_cex ^ "+ " ^
   409   Int.toString potential_cex ^ "= " ^ Int.toString no_cex ^ "- " ^
   487   Int.toString potential_cex ^ "= " ^ Int.toString no_cex ^ "- " ^
   410   Int.toString donno ^ "? " ^ Int.toString timeout ^ "T " ^
   488   Int.toString donno ^ "? " ^ Int.toString timeout ^ "T " ^
   411   Int.toString error ^ "!"
   489   Int.toString error ^ "!"
       
   490 
   412 (* entry -> string *)
   491 (* entry -> string *)
   413 fun string_for_entry (thm_name, exec, subentries) =
   492 fun string_for_entry (thm_name, exec, subentries) =
   414   thm_name ^ " " ^ (if exec then "[exe]" else "[noexe]") ^ ":\n" ^
   493   thm_name ^ " " ^ (if exec then "[exe]" else "[noexe]") ^ ":\n" ^
   415   cat_lines (map string_for_subentry subentries) ^ "\n"
   494   cat_lines (map string_for_subentry subentries) ^ "\n"
       
   495 
   416 (* report -> string *)
   496 (* report -> string *)
   417 fun string_for_report report = cat_lines (map string_for_entry report)
   497 fun string_for_report report = cat_lines (map string_for_entry report)
   418 
   498 
   419 (* string -> report -> unit *)
   499 (* string -> report -> unit *)
   420 fun write_report file_name =
   500 fun write_report file_name =
   422 
   502 
   423 (* theory -> mtd list -> thm list -> string -> unit *)
   503 (* theory -> mtd list -> thm list -> string -> unit *)
   424 fun mutate_theorems_and_write_report thy mtds thms file_name =
   504 fun mutate_theorems_and_write_report thy mtds thms file_name =
   425   let
   505   let
   426     val _ = Output.urgent_message "Starting Mutabelle..."
   506     val _ = Output.urgent_message "Starting Mutabelle..."
   427     val Quickcheck.Test_Params test_params = Quickcheck.test_params_of (ProofContext.init_global thy)
   507     val ctxt = ProofContext.init_global thy
   428     val path = Path.explode file_name
   508     val path = Path.explode file_name
   429     (* for normal report: *)
   509     (* for normal report: *)
   430     (*val (gen_create_entry, gen_string_for_entry) = (create_entry, string_for_entry)*)
   510     (*
   431     (*for detailled report: *)
   511     val (gen_create_entry, gen_string_for_entry) = (create_entry, string_for_entry)
   432     val (gen_create_entry, gen_string_for_entry) =
   512     *)
   433       (create_detailed_entry, string_of_detailed_entry thy)
   513     (* for detailled report: *)
   434     val (gen_create_entry, gen_string_for_entry) =
   514     val (gen_create_entry, gen_string_for_entry) = (create_detailed_entry, string_of_detailed_entry thy)
   435       (create_detailed_entry, theoryfile_string_of_detailed_entry thy)
   515     (* for theory creation: *)
       
   516     (*val (gen_create_entry, gen_string_for_entry) = (create_detailed_entry, theoryfile_string_of_detailed_entry thy)*)
   436   in
   517   in
   437     File.write path (
   518     File.write path (
   438     "Mutation options = "  ^
   519     "Mutation options = "  ^
   439       "max_mutants: " ^ string_of_int max_mutants ^
   520       "max_mutants: " ^ string_of_int max_mutants ^
   440       "; num_mutations: " ^ string_of_int num_mutations ^ "\n" ^
   521       "; num_mutations: " ^ string_of_int num_mutations ^ "\n" ^
   441     "QC options = " ^
   522     "QC options = " ^
   442       (*"quickcheck_generator: " ^ quickcheck_generator ^ ";*)
   523       (*"quickcheck_generator: " ^ quickcheck_generator ^ ";*)
   443       "size: " ^ string_of_int (#size test_params) ^
   524       "size: " ^ string_of_int (Config.get ctxt Quickcheck.size) ^
   444       "; iterations: " ^ string_of_int (#iterations test_params) ^ "\n");
   525       "; iterations: " ^ string_of_int (Config.get ctxt Quickcheck.iterations) ^ "\n");
   445     map (File.append path o gen_string_for_entry o mutate_theorem gen_create_entry thy mtds) thms;
   526     map (File.append path o gen_string_for_entry o mutate_theorem gen_create_entry thy mtds) thms;
   446     ()
   527     ()
   447   end
   528   end
   448 
   529 
   449 end;
   530 end;