src/Tools/isac/Specify/i-model.sml
author wneuper <Walther.Neuper@jku.at>
Mon, 11 Dec 2023 17:26:30 +0100
changeset 60782 e797d1bdfe37
parent 60780 91b105cf194a
permissions -rw-r--r--
eliminate the intermediate *_POS
     1 (* Title:  Specify/i-model.sml
     2    Author: Walther Neuper 110226
     3    (c) due to copyright terms
     4 
     5 \<open>I_Model\<close> serves students' interactive modelling and gives feedback in the specify-phase.
     6 *)
     7 
     8 signature INTERACTION_MODEL =
     9 sig
    10 
    11   type T
    12   val empty: T
    13 
    14   type single
    15   val empty_single: single
    16   val is_empty_single: single -> bool
    17 
    18   type variant
    19   type variants
    20   type m_field
    21   type descriptor
    22   type values
    23 
    24   datatype feedback = datatype Model_Def.i_model_feedback
    25   val feedback_empty: Model_Def.i_model_feedback
    26 
    27   type env
    28   type message
    29 
    30   val single_to_string: Proof.context -> single -> string
    31   val to_string: Proof.context -> T -> string
    32 
    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
    38 
    39   val make_tactic: m_field -> TermC.as_string * T -> Tactic.T
    40 
    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
    49 
    50   val fill_from_o: O_Model.T -> single -> single option
    51 
    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 ->
    55     T * T
    56   val s_are_complete: Proof.context -> O_Model.T -> T * T -> Problem.id * MethodC.id -> bool
    57 
    58   val is_error: feedback -> bool
    59   val to_p_model: theory -> feedback -> string
    60 
    61 (*/----- from isac_test for Minisubpbl*)
    62   val msg: variants -> feedback -> string
    63   val transfer_terms: O_Model.single -> single
    64 
    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
    68 
    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*)
    73 
    74 \<^isac_test>\<open>
    75   (*copy "from isac_test for Minisubpbl" here*)
    76 
    77 \<close>
    78 
    79 end
    80 
    81 (**)
    82 structure I_Model(**) : INTERACTION_MODEL(**) =
    83 struct
    84 (**)
    85 
    86 (** data types **)
    87 
    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
    93 
    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
   101 
   102 val empty = []: T;
   103 
   104 type env = Env.T
   105 
   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) =
   110     "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))
   118 
   119 fun descr_vals_to_string ctxt (descr, values) =
   120   UnparseC.term ctxt (descr $ Model_Def.values_to_present values)
   121 
   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)
   132 
   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);
   137 
   138 
   139 (** make a Tactic.T **)
   140 
   141 fun make_tactic m_field (term_as_string, i_model) =
   142   case m_field of
   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);
   147 
   148 
   149 (** initialise a model **)
   150 
   151 (*
   152   NEW design decision:
   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.
   158 *)
   159 (**)
   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 =
   166   let
   167     val pre_items = map (patt_to_item ctxt o_model) model_patt
   168   in
   169     O_Model.add_enumerate pre_items |> map (fn (a, (b, c, d, e)) => (a, b, c, d, e))
   170   end
   171 
   172 
   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
   183 
   184 (*assumption: i_model has filtered max_vnt*)
   185 local
   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]
   189    | NONE => []
   190 in
   191   fun order_by_patt model_patt i_model = model_patt |> map (order_by_pa i_model) |> flat
   192 end
   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
   199   |> flat
   200 
   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)
   204   |> strs2str'
   205 
   206 fun variables model_patt i_model =
   207   Pre_Conds.environment model_patt i_model
   208   |> map snd
   209 
   210 (*update the itm_ already input, all..from ori*)
   211 fun single_from_o (feedb:feedback) _ all (id, vt, fd, d, ts) = 
   212   let 
   213     val ts' = union op = (feedb_values feedb) ts;
   214     val complete = if eq_set op = (ts', all) then true else false
   215   in
   216     case feedb of
   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))
   223     | Sup (d, ts') =>
   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)
   226   end
   227 
   228 
   229 (** find next step **)
   230 
   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, _)) =>
   238           let
   239             val ts' = inter op = (feedb_values feedb) ts
   240           in
   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))
   244 	        end
   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))
   247 
   248 datatype add_single =
   249 	Add of single   (* return-value of check_single *)
   250 | Err of string   (* error-message                *)
   251 
   252 (*
   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.
   257 *)
   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*)) =
   261     let
   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
   269     in
   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
   275             NONE =>
   276               Add (i, [], true, f, (Cor (d, ts), Position.none))
   277           | SOME (i', _, _, _, (itm_, _)) => 
   278             if Input_Descript.for_list d then 
   279               let
   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)))
   285     end
   286     (*will come directly from PIDE ----------------------vvvvvvvvvvv*)
   287   | check_single ctxt m_field o_model i_model m_patt (str(*, pos*)) =
   288     let
   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 ^ "\"")*)
   292     in 
   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 ^ "\"")
   296         | SOME m_field' => 
   297           if m_field <> m_field' then
   298             Err ("ERROR I_Model.check_single: \"" ^ UnparseC.term ctxt t ^ "\"" ^
   299              "\" not for field \"" ^ m_field ^ "\"")
   300           else
   301             case O_Model.contains ctxt m_field o_model t of
   302               ("", ori', all) => 
   303                 (case is_notyet_input ctxt i_model all ori' m_patt of
   304                    ("", itm) => Add itm
   305                  | (msg, _) => Err ("ERROR I_Model.check_single: is_notyet_input: " ^ msg))
   306             | (msg, _, _) => Err ("ERROR I_Model.check_single: contains: " ^ msg)
   307     end
   308      
   309 
   310 (** add input **)
   311 
   312 fun overwrite_ppc thy itm model =
   313   let 
   314     fun repl _ (_, _, _, _, (itm_, _)) [] =
   315         raise ERROR ("overwrite_ppc: " ^ feedback_to_string (Proof_Context.init_global thy) itm_
   316           ^ " not found")
   317       | repl model' itm (p :: model) =
   318 	      if (#1 itm) = (#1 p)
   319 	      then model' @ [itm] @ model
   320 	      else repl (model' @ [p]) itm model
   321   in repl [] itm model end
   322 
   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
   326 
   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 =
   330   let 
   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
   337 
   338 
   339 (** complete I_Model.T **)
   340 
   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) =
   344   let
   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"
   350       else hd max_vnts
   351 
   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)
   355 
   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)
   358   in
   359     pbl_check andalso met_check
   360   end
   361 
   362 fun is_error (Cor _) = false
   363   | is_error (Sup _) = false
   364   | is_error (Inc _) = false
   365   | is_error (Syn _) = true
   366 
   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))
   372 
   373 fun fill_from_o o_model (i, vnts, bool, _, (feedb, pos)) = 
   374   let
   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*)
   380   in
   381 (*---------------vvvvvvvvvvvvv MV if TermC.is_list all_value-----*)
   382     if Model_Def.is_list_descr descr
   383     then
   384       let
   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]
   388       in
   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))
   392       end
   393     else SOME (i, vnts, bool, m_field, (Cor (descr, all_values(*only 1 term*)), pos))
   394   end
   395 
   396 (*
   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.
   400 *)
   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
   403           NONE => false
   404         | SOME descr1 => descr1 = descr2 andalso Model_Def.member_vnt vnts1 max_vnt) i1_model of
   405       NONE =>
   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*)
   409 
   410 (*fill method from items already input*)
   411 fun fill_method o_model (pbl_imod, met_imod) met_patt =
   412   let
   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*)
   417 
   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)*)
   421   in
   422     map (add_other max_vnt pbl_imod) i_from_met
   423   end 
   424 
   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) =
   431   let
   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
   439       then
   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
   444 
   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*)
   449 
   450     val met_from_pbl = map ((fn i_single as (_, _, _, _, (feedb, _)) =>
   451       if is_empty_single i_single
   452       then
   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
   457   in
   458     (filter (fn (_, vnts', _, _, _) => member op = vnts' max_vnt) pbl_from_o_model,
   459       met_from_pbl)
   460   end
   461 
   462 (**)end(**);