1 (* Title: Specify/i-model.sml
2 Author: Walther Neuper 110226
3 (c) due to copyright terms
5 \<open>I_Model\<close> serves students' interactive modelling and gives feedback in the specify-phase.
8 signature INTERACTION_MODEL =
15 val empty_single: single
16 val is_empty_single: single -> bool
24 datatype feedback = datatype Model_Def.i_model_feedback
25 val feedback_empty: Model_Def.i_model_feedback
30 val single_to_string: Proof.context -> single -> string
31 val to_string: Proof.context -> T -> string
33 datatype add_single = Add of single | Err of string
34 val init: Proof.context -> O_Model.T -> Model_Pattern.T -> T
35 val check_single: Proof.context -> m_field -> O_Model.T -> T -> Model_Pattern.T ->
36 TermC.as_string -> add_single
37 val add_single: theory -> single -> T -> T
39 val make_tactic: m_field -> TermC.as_string * T -> Tactic.T
41 val descriptor: feedback -> descriptor
42 val get_values: T -> values list
43 val feedb_values: feedback -> values
44 val order_by_patt: Model_Pattern.T -> T ->T
45 val descr_pairs_to_string: Proof.context -> (Model_Pattern.single * single) list -> string
46 val variables: Model_Pattern.T -> Model_Def.i_model -> term list
47 val is_notyet_input: Proof.context -> T -> O_Model.values -> O_Model.single ->
48 Model_Pattern.T -> message * single
50 val fill_from_o: O_Model.T -> single -> single option
52 val add_other: variant -> T -> single -> single
53 val fill_method: O_Model.T -> T * T-> Model_Pattern.T -> T
54 val s_make_complete: Proof.context -> O_Model.T -> T * T -> Problem.id * MethodC.id ->
56 val s_are_complete: Proof.context -> O_Model.T -> T * T -> Problem.id * MethodC.id -> bool
58 val is_error: feedback -> bool
59 val to_p_model: theory -> feedback -> string
61 (*/----- from isac_test for Minisubpbl*)
62 val msg: variants -> feedback -> string
63 val transfer_terms: O_Model.single -> single
65 val feedback_to_string: Proof.context -> feedback -> string
66 val descr_vals_to_string: Proof.context -> descriptor * values -> string
67 val feedb_args_to_string: Proof.context -> feedback -> string
69 val single_from_o: feedback -> descriptor -> Model_Def.values -> O_Model.single -> single
70 val seek_ppc: int -> single list -> single option
71 val overwrite_ppc: theory -> single -> T -> T
72 (*\----- from isac_test for Minisubpbl*)
75 (*copy "from isac_test for Minisubpbl" here*)
82 structure I_Model(**) : INTERACTION_MODEL(**) =
88 type variant = Model_Def.variant;
89 type variants = Model_Def.variants;
90 type m_field = Model_Def.m_field;
91 type descriptor = Model_Def.descriptor;
92 type values = Model_Def.values
94 type T = Model_Def.i_model_single list;
95 datatype feedback = datatype Model_Def.i_model_feedback;
96 val feedback_empty = Model_Def.feedback_empty
97 type single = Model_Def.i_model_single;
98 val empty_single = Model_Def.i_model_empty;
99 fun is_empty_single (0, [], false, "i_model_empty", _) = true
100 | is_empty_single _ = false
106 type message = string;
107 fun feedback_to_string ctxt (Cor (d, ts)) =
108 "Cor " ^ UnparseC.term ctxt (Input_Descript.join (d, ts)) ^ " , pen2str"
109 | feedback_to_string _ (Syn c) =
111 | feedback_to_string ctxt (Inc (d, [])) =
112 "Inc " ^ UnparseC.term ctxt (Input_Descript.join (d, [])) ^ " " ^
113 Model_Pattern.empty_for d
114 | feedback_to_string ctxt (Inc (d, ts)) =
115 "Inc " ^ UnparseC.term ctxt (Input_Descript.join (d, ts)) ^ " , pen2str"
116 | feedback_to_string ctxt (Sup (d, ts)) =
117 "Sup " ^ UnparseC.term ctxt (Input_Descript.join (d, ts))
119 fun descr_vals_to_string ctxt (descr, values) =
120 UnparseC.term ctxt (descr $ Model_Def.values_to_present values)
122 (*prepare for presentation to user; thus Syn does NOT raise an exn*)
123 fun feedb_args_to_string ctxt (Cor (descr, values)) =
124 UnparseC.term ctxt (descr $ Model_Def.values_to_present values)
125 | feedb_args_to_string _ (Syn str) = str
126 | feedb_args_to_string ctxt (Inc (descr, [])) =
127 UnparseC.term ctxt descr ^ Model_Pattern.empty_for descr
128 | feedb_args_to_string ctxt (Inc (descr, values)) =
129 UnparseC.term ctxt (descr $ Model_Def.values_to_present values)
130 | feedb_args_to_string ctxt (Sup (descr, values)) =
131 UnparseC.term ctxt (descr $ Model_Def.values_to_present values)
133 fun single_to_string ctxt (i, is, b, s, (itm_, _(*Position.T*))) =
134 "(" ^ string_of_int i ^ ", " ^ ints2str' is ^ ", " ^ bool2str b ^ " ," ^
135 s ^ ", (" ^ feedback_to_string ctxt itm_ ^ ", Position.T))";
136 fun to_string ctxt itms = strs2str' (map (linefeed o (single_to_string ctxt)) itms);
139 (** make a Tactic.T **)
141 fun make_tactic m_field (term_as_string, i_model) =
143 "#Given" => Tactic.Add_Given' (term_as_string, i_model)
144 | "#Find" => Tactic.Add_Find' (term_as_string, i_model)
145 | "#Relate" => Tactic.Add_Relation'(term_as_string, i_model)
146 | str => raise ERROR ("specify_additem Frm, Pbl: uncovered case with " ^ str);
149 (** initialise a model **)
153 * Now the Model in Specification is intialised such that the placement of items can be
154 maximally stable during interactive input to the Specification.
155 * Template.show provides the initial output to the user and thus determines what will be parsed
156 by Outer_Syntax later during interaction.
157 * The relation between O_Model.T and I_Model.T becomes much simpler.
160 fun patt_to_item ctxt o_model (_, (descriptor, _)) =
161 case find_first (fn (_, _, _, desc, _) => desc = descriptor) o_model of
162 NONE => raise ERROR ("I_Model.patt_to_item NONE for " ^ UnparseC.term ctxt descriptor)
163 | SOME (_, variants, m_field, descr, _) => (variants, false, m_field,
164 (Inc (descr, []), Position.none))
165 fun init ctxt o_model model_patt =
167 val pre_items = map (patt_to_item ctxt o_model) model_patt
169 O_Model.add_enumerate pre_items |> map (fn (a, (b, c, d, e)) => (a, b, c, d, e))
173 val unique = Syntax.read_term\<^context> "UnIqE_tErM";
174 (*DANGEROUS: do NOT use "UnIqE_tErM" *)
175 fun descriptor (Cor (d ,_)) = d
176 | descriptor (Syn _) = ((*tracing ("*** descriptor: Syn ("^c^")");*) unique)
177 | descriptor (Inc (d, _)) = d
178 | descriptor (Sup (d, _)) = d
179 fun feedb_values (Cor (_, ts)) = ts
180 | feedb_values (Syn _) = raise ERROR "feedb_values NOT for Syn"
181 | feedb_values (Inc (_, ts)) = ts
182 | feedb_values (Sup (_, ts)) = ts
184 (*assumption: i_model has filtered max_vnt*)
186 fun order_by_pa i_model (_, (descr, _ )) =
187 case find_first (fn (_, _, _, _, (feedb, _)) => descr = descriptor feedb) i_model of
188 SOME i_single => [i_single]
191 fun order_by_patt model_patt i_model = model_patt |> map (order_by_pa i_model) |> flat
193 fun feedb_vals (Cor (_, ts)) = [ts]
194 | feedb_vals (Syn _) = []
195 | feedb_vals (Inc (_, ts)) = [ts]
196 | feedb_vals (Sup (_, ts)) = [ts]
197 fun get_values i_model =
198 map (fn (_, _, _, _, (feedb, _)) => feedb_vals feedb) i_model
201 fun descr_pairs_to_string ctxt equal_descr_pairs =
202 (map (fn (a, b) => pair (Model_Pattern.single_to_string ctxt a) (single_to_string ctxt b)
203 |> pair2str) equal_descr_pairs)
206 fun variables model_patt i_model =
207 Pre_Conds.environment model_patt i_model
210 (*update the itm_ already input, all..from ori*)
211 fun single_from_o (feedb:feedback) _ all (id, vt, fd, d, ts) =
213 val ts' = union op = (feedb_values feedb) ts;
214 val complete = if eq_set op = (ts', all) then true else false
217 Cor _ => if fd = "#undef"
218 then (id, vt, complete, fd, (Sup (d, ts'), Position.none))
219 else (id, vt, complete, fd, (Cor (d, ts'), Position.none))
220 | Inc _ => if complete
221 then (id, vt, true, fd, (Cor (d, ts'), Position.none))
222 else (id, vt, false, fd, (Inc (d, ts'), Position.none))
224 (id, vt, complete, fd, (Sup (d, ts'), Position.none))
225 | i => raise ERROR ("single_from_o: uncovered case of " ^ feedback_to_string (ContextC.for_ERROR ()) i)
229 (** find next step **)
231 (*old code kept for test/*)
232 fun is_notyet_input ctxt itms all (i, v, f, d, ts) pbt =
233 case find_first (fn (_, (d', _)) => d = d') pbt of
234 SOME (_, (_, pid)) =>
235 (case find_first (fn (_, _, _, f', (feedb, _)) =>
236 f = f' andalso d = (descriptor feedb)) itms of
237 SOME (_, _, _, _, (feedb, _)) =>
239 val ts' = inter op = (feedb_values feedb) ts
241 if subset op = (ts, ts')
242 then (((strs2str' o map (UnparseC.term ctxt)) ts') ^ " already input", empty_single)
243 else ("", single_from_o feedb pid all (i, v, f, d, subtract op = ts' ts))
245 | NONE => ("", single_from_o (Inc (TermC.empty, [])) pid all (i, v, f, d, ts)))
246 | NONE => ("", single_from_o (Sup (d, ts)) TermC.empty all (i, v, f, d, ts))
248 datatype add_single =
249 Add of single (* return-value of check_single *)
250 | Err of string (* error-message *)
253 Create feedback for input of TermC.as_string to m_field;
254 check w.r.t. O_Model.T and Model_Pattern.T.
255 In case of O_Model.T = [] (i.e. no data for user-guidance in Formalise.T)
256 check_single is extremely permissive.
258 (*will come directly from PIDE -----------------vvvvvvvvvvv
259 in case t comes from Step.specify_do_next -----------vvv = Position.none*)
260 fun check_single ctxt m_field [] i_model m_patt (ct(*, pos*)) =
262 val i = 1 + (if i_model = [] then 0 else map #1 i_model |> maxl)
263 (*/------------ replace by ParseC.term_position -----------\*)
264 val t = Syntax.read_term ctxt ct
265 handle ERROR msg => error (msg (*^ Position.here pos*))
266 (*\------------ replace by ParseC.term_position -----------/*)
267 (*NONE => Add (i, [], false, m_field, Syn ct)*)
268 val (d, ts) = Input_Descript.split t
270 (*if d = TermC.empty then .. *)
271 (case find_first (fn (_, (d', _)) => d = d') m_patt of
272 NONE => Add (i, [], true, m_field, (Sup (d,ts), Position.none))
273 | SOME (f, (_, _)) =>
274 case find_first (fn (i, _, _, _, (feedb, _)) => d = (descriptor feedb) andalso i <> 0) i_model of
276 Add (i, [], true, f, (Cor (d, ts), Position.none))
277 | SOME (i', _, _, _, (itm_, _)) =>
278 if Input_Descript.for_list d then
280 val in_itm = feedb_values itm_
281 val ts' = union op = ts in_itm
282 val i'' = if in_itm = [] then i else i'
283 in Add (i'', [], true, f, (Cor (d, ts'), Position.none)) end
284 else Add (i', [], true, f, (Cor (d, ts), Position.none)))
286 (*will come directly from PIDE ----------------------vvvvvvvvvvv*)
287 | check_single ctxt m_field o_model i_model m_patt (str(*, pos*)) =
289 val (t as (descriptor $ _)) = Syntax.read_term ctxt str
290 handle ERROR msg => error (msg (*TODO: ^ Position.here pp*))
291 (*old code: NONE => Err ("ERROR I_Model.check_single: syntax error in \"" ^ str ^ "\"")*)
293 case Model_Pattern.get_field descriptor m_patt of
294 NONE => Err ("ERROR I_Model.check_single: unknown descriptor \"" ^
295 UnparseC.term ctxt descriptor ^ "\"")
297 if m_field <> m_field' then
298 Err ("ERROR I_Model.check_single: \"" ^ UnparseC.term ctxt t ^ "\"" ^
299 "\" not for field \"" ^ m_field ^ "\"")
301 case O_Model.contains ctxt m_field o_model t of
303 (case is_notyet_input ctxt i_model all ori' m_patt of
305 | (msg, _) => Err ("ERROR I_Model.check_single: is_notyet_input: " ^ msg))
306 | (msg, _, _) => Err ("ERROR I_Model.check_single: contains: " ^ msg)
312 fun overwrite_ppc thy itm model =
314 fun repl _ (_, _, _, _, (itm_, _)) [] =
315 raise ERROR ("overwrite_ppc: " ^ feedback_to_string (Proof_Context.init_global thy) itm_
317 | repl model' itm (p :: model) =
319 then model' @ [itm] @ model
320 else repl (model' @ [p]) itm model
321 in repl [] itm model end
323 (*find_first item with #1 equal to id*)
324 fun seek_ppc _ [] = NONE
325 | seek_ppc id (p :: model) = if id = #1 (p: single) then SOME p else seek_ppc id model
327 (* 10.3.00: insert the parsed itm into model;
328 ev. filter_out untouched (in FE: (0,...)) item related to insert-item *)
329 fun add_single thy itm model =
331 fun eq_untouched d (0, _, _, _, (itm_, _)) = (d = descriptor itm_)
332 | eq_untouched _ _ = false
333 val model' = case seek_ppc (#1 itm) model of
334 SOME _ => overwrite_ppc thy itm model (*itm updated in is_notyet_input WN.11.03*)
335 | NONE => (model @ [itm])
336 in filter_out (eq_untouched ((descriptor o #1 o #5) itm)) model' end
339 (** complete I_Model.T **)
341 fun s_are_complete _ _ ([], _) _ = false
342 | s_are_complete _ _ (_, []) _ = false
343 | s_are_complete ctxt o_model (pbl_imod, met_imod) (pbl_id, met_id) =
345 val pbl_max_vnts = Model_Def.max_variants o_model pbl_imod
346 val met_max_vnts = Model_Def.max_variants o_model met_imod
347 val max_vnts = inter op= pbl_max_vnts met_max_vnts
348 val max_vnt = if max_vnts = []
349 then raise ERROR "I_Model.s_are_complete: request user to review met_imod"
352 val (pbl_imod', met_imod') = (
353 filter (fn (_, vnts, _, _, _) => member_swap op = max_vnt vnts) pbl_imod,
354 filter (fn (_, vnts, _, _, _) => member_swap op = max_vnt vnts) met_imod)
356 val (pbl_check, _) = Pre_Conds.check_internal ctxt pbl_imod' (Pos.Pbl, pbl_id)
357 val (met_check, _) = Pre_Conds.check_internal ctxt met_imod' (Pos.Met, met_id)
359 pbl_check andalso met_check
362 fun is_error (Cor _) = false
363 | is_error (Sup _) = false
364 | is_error (Inc _) = false
365 | is_error (Syn _) = true
367 (*create output-string for itm*)
368 fun to_p_model thy (Cor (d, ts)) = UnparseC.term_in_thy thy (Input_Descript.join (d, ts))
369 | to_p_model _ (Syn c) = c
370 | to_p_model thy (Inc (d, ts)) = UnparseC.term_in_thy thy (Input_Descript.join (d, ts))
371 | to_p_model thy (Sup (d, ts)) = UnparseC.term_in_thy thy (Input_Descript.join (d, ts))
373 fun fill_from_o o_model (i, vnts, bool, _, (feedb, pos)) =
375 val (m_field, all_values) =
376 case find_first (fn (_, _, _, descr', _) => Model_Def.descriptor_exists descr' feedb) o_model of
377 SOME (_, _, m_field, _, ts) => (m_field, ts)
378 | NONE => raise ERROR "I_Model.fill_from_o does NOT find a descriptor in O_Model"
379 val descr = Model_Def.get_descr feedb (*i_single has been filtered appropriately*)
381 (*---------------vvvvvvvvvvvvv MV if TermC.is_list all_value-----*)
382 if Model_Def.is_list_descr descr
385 val already_input = feedb |> feedb_values
386 val miss = subtract op= already_input all_values (*"[[c], [c_2], [c_3], [c_4]]"*)
387 val ts = already_input @ [hd miss]
389 if length all_values = length ts
390 then SOME (i, vnts, bool, m_field, (Cor (descr, [Model_Def.values_to_present ts]), pos))
391 else SOME (i, vnts, bool, m_field, (Inc (descr, [Model_Def.values_to_present ts]), pos))
393 else SOME (i, vnts, bool, m_field, (Cor (descr, all_values(*only 1 term*)), pos))
397 in case there is an item in i2_model(= met) with Sup,
398 find_first an appropriate (variant, descriptor) item in i1_model(= pbl) and add it instead Sup,
399 otherwise keep the items of i2_model.
401 fun add_other max_vnt i1_model (i2, _, bool2, m_field2, (Sup (descr2, ts2), pos2)) =
402 (case find_first (fn (_, vnts1, _, _, (feedb1, _)) => case Model_Def.get_dscr_opt feedb1 of
404 | SOME descr1 => descr1 = descr2 andalso Model_Def.member_vnt vnts1 max_vnt) i1_model of
406 (i2, [max_vnt], bool2, m_field2, (Sup (descr2, ts2), pos2)) (*the present in i2_model*)
407 | SOME i1_single => i1_single) (*shift the item from i1_model to i2_model*)
408 | add_other _ _ i2_single = i2_single (*keep all the other items in i2_model*)
410 (*fill method from items already input*)
411 fun fill_method o_model (pbl_imod, met_imod) met_patt =
413 val pbl_max_vnts = Model_Def.max_variants o_model pbl_imod
414 (*probably pbl/met_imod = [], so take met_patt; if empty return Sup*)
415 val i_from_met = map (fn (_, (descr, _)) => (*order from met_patt*)
416 Pre_Conds.get_descr_vnt descr pbl_max_vnts met_imod) met_patt (*\<longrightarrow> right order for args*)
418 val met_max_vnts = Model_Def.max_variants o_model i_from_met;
419 val max_vnt = hd (inter op= pbl_max_vnts met_max_vnts);
420 (*add items from pbl_imod (without overwriting existing items in met_imod)*)
422 map (add_other max_vnt pbl_imod) i_from_met
425 fun msg vnts feedb = "get_descr_vnt' returns NONE: i.e. it does not find an item of o_model with\n" ^
426 "variants " ^ ints2str' vnts ^ " and descriptor " ^
427 (feedb |> Model_Def.get_dscr_opt |> the |> UnparseC.term (ContextC.for_ERROR ()))
428 fun transfer_terms (i, vnts, m_field, descr, ts) =
429 (i, vnts, true, m_field, (Cor (descr, ts), Position.none))
430 fun s_make_complete ctxt o_model (pbl_imod, met_imod) (pbl_id, met_id) =
432 val {model = pbl_patt, ...} = Problem.from_store ctxt pbl_id;
433 val {model = met_patt, ...} = MethodC.from_store ctxt met_id;
434 val pbl_max_vnts = Model_Def.max_variants o_model pbl_imod;
435 val i_from_pbl = map (fn (_, (descr, _)) =>
436 Pre_Conds.get_descr_vnt descr pbl_max_vnts pbl_imod) pbl_patt
437 val pbl_from_o_model = map ((fn i_single as (_, _, _, _, (feedb, _)) =>
438 if is_empty_single i_single
440 case Pre_Conds.get_descr_vnt' feedb pbl_max_vnts o_model of
441 [] => raise ERROR (msg pbl_max_vnts feedb)
442 | o_singles => map transfer_terms o_singles
443 else [i_single (*fetched before from pbl_imod*)])) i_from_pbl |> flat
445 val i_from_met = map (fn (_, (descr, _)) =>
446 Pre_Conds.get_descr_vnt descr pbl_max_vnts met_imod) met_patt
447 val met_max_vnts = Model_Def.max_variants o_model i_from_met;
448 val max_vnt = hd met_max_vnts (*need only one for solve-phase*)
450 val met_from_pbl = map ((fn i_single as (_, _, _, _, (feedb, _)) =>
451 if is_empty_single i_single
453 case Pre_Conds.get_descr_vnt' feedb [max_vnt] o_model of
454 [] => raise ERROR (msg [max_vnt] feedb)
455 | o_singles => map transfer_terms o_singles
456 else [i_single (*fetched before from met_imod*)])) i_from_met |> flat
458 (filter (fn (_, vnts', _, _, _) => member op = vnts' max_vnt) pbl_from_o_model,