AERA
All Classes Functions Pages
mdl_controller.cpp
1 //_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
2 //_/_/
3 //_/_/ AERA
4 //_/_/ Autocatalytic Endogenous Reflective Architecture
5 //_/_/
6 //_/_/ Copyright (c) 2018-2025 Jeff Thompson
7 //_/_/ Copyright (c) 2018-2025 Kristinn R. Thorisson
8 //_/_/ Copyright (c) 2018-2025 Icelandic Institute for Intelligent Machines
9 //_/_/ Copyright (c) 2018 Jacqueline Clare Mallett
10 //_/_/ Copyright (c) 2018 Thor Tomasarson
11 //_/_/ http://www.iiim.is
12 //_/_/
13 //_/_/ Copyright (c) 2010-2012 Eric Nivel
14 //_/_/ Center for Analysis and Design of Intelligent Agents
15 //_/_/ Reykjavik University, Menntavegur 1, 102 Reykjavik, Iceland
16 //_/_/ http://cadia.ru.is
17 //_/_/
18 //_/_/ Part of this software was developed by Eric Nivel
19 //_/_/ in the HUMANOBS EU research project, which included
20 //_/_/ the following parties:
21 //_/_/
22 //_/_/ Autonomous Systems Laboratory
23 //_/_/ Technical University of Madrid, Spain
24 //_/_/ http://www.aslab.org/
25 //_/_/
26 //_/_/ Communicative Machines
27 //_/_/ Edinburgh, United Kingdom
28 //_/_/ http://www.cmlabs.com/
29 //_/_/
30 //_/_/ Istituto Dalle Molle di Studi sull'Intelligenza Artificiale
31 //_/_/ University of Lugano and SUPSI, Switzerland
32 //_/_/ http://www.idsia.ch/
33 //_/_/
34 //_/_/ Institute of Cognitive Sciences and Technologies
35 //_/_/ Consiglio Nazionale delle Ricerche, Italy
36 //_/_/ http://www.istc.cnr.it/
37 //_/_/
38 //_/_/ Dipartimento di Ingegneria Informatica
39 //_/_/ University of Palermo, Italy
40 //_/_/ http://diid.unipa.it/roboticslab/
41 //_/_/
42 //_/_/
43 //_/_/ --- HUMANOBS Open-Source BSD License, with CADIA Clause v 1.0 ---
44 //_/_/
45 //_/_/ Redistribution and use in source and binary forms, with or without
46 //_/_/ modification, is permitted provided that the following conditions
47 //_/_/ are met:
48 //_/_/ - Redistributions of source code must retain the above copyright
49 //_/_/ and collaboration notice, this list of conditions and the
50 //_/_/ following disclaimer.
51 //_/_/ - Redistributions in binary form must reproduce the above copyright
52 //_/_/ notice, this list of conditions and the following disclaimer
53 //_/_/ in the documentation and/or other materials provided with
54 //_/_/ the distribution.
55 //_/_/
56 //_/_/ - Neither the name of its copyright holders nor the names of its
57 //_/_/ contributors may be used to endorse or promote products
58 //_/_/ derived from this software without specific prior
59 //_/_/ written permission.
60 //_/_/
61 //_/_/ - CADIA Clause: The license granted in and to the software
62 //_/_/ under this agreement is a limited-use license.
63 //_/_/ The software may not be used in furtherance of:
64 //_/_/ (i) intentionally causing bodily injury or severe emotional
65 //_/_/ distress to any person;
66 //_/_/ (ii) invading the personal privacy or violating the human
67 //_/_/ rights of any person; or
68 //_/_/ (iii) committing or preparing for any act of war.
69 //_/_/
70 //_/_/ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
71 //_/_/ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
72 //_/_/ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
73 //_/_/ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
74 //_/_/ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
75 //_/_/ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
76 //_/_/ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
77 //_/_/ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
78 //_/_/ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
79 //_/_/ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
80 //_/_/ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
81 //_/_/ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
82 //_/_/ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
83 //_/_/ OF SUCH DAMAGE.
84 //_/_/
85 //_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
86 
87 #include "mdl_controller.h"
88 #include "mem.h"
89 #include "model_base.h"
90 
91 using namespace std;
92 using namespace std::chrono;
93 using namespace r_code;
94 
95 namespace r_exec {
96 
97 MDLOverlay::MDLOverlay(Controller *c, const HLPBindingMap *bindings) : HLPOverlay(c, bindings, true) {
98 }
99 
100 MDLOverlay::~MDLOverlay() {
101 }
102 
104 
105 PrimaryMDLOverlay::PrimaryMDLOverlay(Controller *c, const HLPBindingMap *bindings) : MDLOverlay(c, bindings) {
106 }
107 
108 PrimaryMDLOverlay::~PrimaryMDLOverlay() {
109 }
110 
111 bool PrimaryMDLOverlay::reduce(_Fact *input, Fact *f_p_f_imdl, MDLController *req_controller) {
112 
113  OUTPUT_LINE(MDL_IN, Utils::RelativeTime(Now()) << " mdl: " << controller_->get_object()->get_oid() << " <- input: " << input->get_oid());
114  _Fact *input_object;
115  Pred *prediction = input->get_pred();
116  bool is_simulation;
117  if (prediction) {
118 
119  input_object = prediction->get_target();
120  is_simulation = prediction->is_simulation();
121  } else {
122 
123  input_object = input;
124  is_simulation = false;
125  }
126 
127  P<HLPBindingMap> bm = new HLPBindingMap(bindings_);
128  bm->reset_fwd_timings(input_object);
129  switch (bm->match_fwd_lenient(input_object, ((MDLController *)controller_)->get_lhs())) {
130  case MATCH_SUCCESS_POSITIVE: {
131 
132  load_code();
133  P<HLPBindingMap> original_bindings = bindings_;
134  bool is_req = ((MDLController *)controller_)->is_requirement();
135  bool match = false;
136  Fact *f_imdl = ((MDLController *)controller_)->get_f_ihlp(bm, false);
137  RequirementsPair r_p;
138  vector<BindingResult> bind_results;
139  bool wr_enabled = false;
140  ChainingStatus c_s = ((MDLController *)controller_)->retrieve_imdl_fwd(bm, f_imdl, r_p, bind_results, req_controller, wr_enabled);
141  f_imdl->get_reference(0)->code(I_HLP_WEAK_REQUIREMENT_ENABLED) = Atom::Boolean(wr_enabled);
142 
143  bool chaining_allowed = (c_s >= WEAK_REQUIREMENT_ENABLED);
144  bool did_check_simulated_chaining = false;
145  bool check_simulated_chaining_result;
146  switch (c_s) {
147  case WEAK_REQUIREMENT_DISABLED:
148  case STRONG_REQUIREMENT_NO_WEAK_REQUIREMENT: // silent monitoring of a prediction that will not be injected.
149  if (is_simulation) { // if there is simulated imdl for the root of one sim in prediction, allow forward chaining.
150 
151  bind_results.clear();
152  check_simulated_chaining_result = check_simulated_chaining(bm, f_imdl, prediction, bind_results);
153  did_check_simulated_chaining = true;
154  if (check_simulated_chaining_result)
155  chaining_allowed = true;
156  else
157  break;
158  }
159  case NO_REQUIREMENT:
160  if (!chaining_allowed && ((MDLController *)controller_)->has_tpl_args()) // there are tpl args, abort.
161  break;
162  else
163  f_imdl->get_reference(0)->code(I_HLP_WEAK_REQUIREMENT_ENABLED) = Atom::Boolean(false);
164  case STRONG_REQUIREMENT_DISABLED_WEAK_REQUIREMENT: // silent monitoring of a prediction that will not be injected.
165  if (is_simulation) { // if there is simulated imdl for the root of one sim in prediction, allow forward chaining.
166 
167  if (!did_check_simulated_chaining) {
168  bind_results.clear();
169  check_simulated_chaining_result = check_simulated_chaining(bm, f_imdl, prediction, bind_results);
170  did_check_simulated_chaining = true;
171  }
172  if (check_simulated_chaining_result)
173  chaining_allowed = true;
174  else
175  break;
176  }
177  case WEAK_REQUIREMENT_ENABLED:
178  if (bind_results.size() == 0)
179  // retrieve_imdl_fwd doesn't add a result for status such as NO_REQUIREMENT, so use the bm that we created above.
180  bind_results.push_back(BindingResult(bm, NULL, NULL));
181  vector<P<_Fact> > already_predicted;
182  for (size_t i = 0; i < bind_results.size(); ++i) {
183  // evaluate_fwd_guards() uses bindings_, so set it to the binding map.
184  bindings_ = bind_results[i].map_;
185  if (i > 0)
186  // During the previous iteration, evaluate_fwd_guards patched code_ in place, so restore.
187  load_code();
188  if (evaluate_fwd_guards()) { // may update bindings_ .
189  // Valuate f_imdl from updated binding map.
190  P<Fact> f_imdl_copy = new Fact(
191  bindings_->bind_pattern(f_imdl->get_reference(0)), f_imdl->get_after(), f_imdl->get_before(),
192  f_imdl->get_cfd(), f_imdl->get_psln_thr());
193  ((PrimaryMDLController*)controller_)->predict(bindings_, input, f_imdl_copy, chaining_allowed, r_p, bind_results[i].ground_,
194  bind_results[i].ground_mk_rdx_, already_predicted);
195  match = true;
196  }
197  }
198  break;
199  }
200  // reset.
201  delete[] code_;
202  code_ = NULL;
203  bindings_ = original_bindings;
204  if (f_p_f_imdl == NULL) // i.e. if reduction not triggered a requirement.
205  store_evidence(input, prediction, is_simulation);
206  return match;
207  }case MATCH_SUCCESS_NEGATIVE: // counter-evidence WRT the lhs.
208  if (f_p_f_imdl == NULL) // i.e. if reduction not triggered a requirement.
209  store_evidence(input, prediction, is_simulation);
210  case MATCH_FAILURE:
211  return false;
212  }
213 
214  return false;
215 }
216 
217 bool PrimaryMDLOverlay::check_simulated_chaining(const HLPBindingMap *bm, Fact *f_imdl, Pred *prediction, vector<BindingResult >& results) {
218 
219  for (uint32 i = 0; i < prediction->get_simulations_size(); ++i) {
220 
221  switch (((MDLController *)controller_)->retrieve_simulated_imdl_fwd(bm, f_imdl, prediction->get_simulation(i), results)) {
222  case NO_REQUIREMENT:
223  case WEAK_REQUIREMENT_ENABLED:
224  return true;
225  default:
226  break;
227  }
228  }
229 
230  return false;
231 }
232 
234 
235 SecondaryMDLOverlay::SecondaryMDLOverlay(Controller *c, const HLPBindingMap *bindings) : MDLOverlay(c, bindings) {
236 }
237 
238 SecondaryMDLOverlay::~SecondaryMDLOverlay() {
239 }
240 
241 bool SecondaryMDLOverlay::reduce(_Fact *input, Fact *f_p_f_imdl, MDLController *req_controller) { // no caching since no bwd.
242  P<HLPBindingMap> bm = new HLPBindingMap(bindings_);
243  bm->reset_fwd_timings(input);
244  switch (bm->match_fwd_lenient(input, ((MDLController *)controller_)->get_lhs())) {
245  case MATCH_SUCCESS_POSITIVE: {
246 
247  load_code();
248  P<HLPBindingMap> original_bindings = bindings_;
249  bindings_ = bm;
250  bool match = false;
251  Fact *f_imdl = ((MDLController *)controller_)->get_f_ihlp(bm, false);
252  RequirementsPair r_p;
253  vector<BindingResult> bind_results;
254  bool wr_enabled = false;
255  ChainingStatus c_s = ((MDLController *)controller_)->retrieve_imdl_fwd(bm, f_imdl, r_p, bind_results, req_controller, wr_enabled);
256  f_imdl->get_reference(0)->code(I_HLP_WEAK_REQUIREMENT_ENABLED) = Atom::Boolean(wr_enabled);
257  bool chaining_allowed = (c_s >= NO_REQUIREMENT);
258  switch (c_s) {
259  case WEAK_REQUIREMENT_DISABLED:
260  case STRONG_REQUIREMENT_NO_WEAK_REQUIREMENT: // silent monitoring of a prediction that will not be injected.
261  case NO_REQUIREMENT:
262  if (((MDLController *)controller_)->has_tpl_args()) // there are tpl args, abort.
263  break;
264  else
265  f_imdl->get_reference(0)->code(I_HLP_WEAK_REQUIREMENT_ENABLED) = Atom::Boolean(false);
266  case STRONG_REQUIREMENT_DISABLED_WEAK_REQUIREMENT:
267  case WEAK_REQUIREMENT_ENABLED:
268  if (bind_results.size() == 0)
269  // retrieve_imdl_fwd doesn't add a result for status such as NO_REQUIREMENT, so use the bm that we created above.
270  bind_results.push_back(BindingResult(bm, NULL, NULL));
271  vector<P<_Fact> > already_predicted;
272  for (size_t i = 0; i < bind_results.size(); ++i) {
273  // evaluate_fwd_guards() uses bindings_, so set it to the binding map.
274  bindings_ = bind_results[i].map_;
275  if (i > 0)
276  // During the previous iteration, evaluate_fwd_guards patched code_ in place, so restore.
277  load_code();
278  if (evaluate_fwd_guards()) { // may update bindings_ .
279  f_imdl->set_reference(0, bindings_->bind_pattern(f_imdl->get_reference(0))); // valuate f_imdl from updated binding map.
280  ((SecondaryMDLController*)controller_)->predict(bindings_, input, NULL, true, r_p, bind_results[i].ground_,
281  bind_results[i].ground_mk_rdx_, already_predicted);
282  match = true;
283  }
284  }
285  break;
286  }
287  // reset.
288  delete[] code_;
289  code_ = NULL;
290  bindings_ = original_bindings;
291  return match;
292  }case MATCH_SUCCESS_NEGATIVE:
293  case MATCH_FAILURE:
294  return false;
295  }
296 
297  return false;
298 }
299 
301 
302 MDLController *MDLController::New(View *view, bool &inject_in_secondary_group) {
303 
304  Code *unpacked_mdl = view->object_->get_reference(view->object_->references_size() - MDL_HIDDEN_REFS);
305  uint16 obj_set_index = unpacked_mdl->code(MDL_OBJS).asIndex();
306  Code *rhs = unpacked_mdl->get_reference(unpacked_mdl->code(obj_set_index + 2).asIndex());
307 
308  if (rhs->get_reference(0)->code(0).asOpcode() == Opcodes::Ent) { // rhs is a drive.
309 
310  inject_in_secondary_group = false;
311  return new TopLevelMDLController(view);
312  }
313 
314  inject_in_secondary_group = true;
315  return new PrimaryMDLController(view);
316 }
317 
318 MDLController::MDLController(_View *view) : HLPController(view) {
319 
320  Code *object = get_unpacked_object();
321  uint16 obj_set_index = object->code(MDL_OBJS).asIndex();
322  lhs_ = object->get_reference(object->code(obj_set_index + 1).asIndex());
323  rhs_ = object->get_reference(object->code(obj_set_index + 2).asIndex());
324 
325  Group *host = get_host();
326  controllers_.resize(2);
327 
328  Code *rhs_ihlp = rhs_->get_reference(0);
329  requirement_type_ = NOT_A_REQUIREMENT;
330  controllers_[RHSController] = NULL;
331  uint16 rhs_opcode = rhs_ihlp->code(0).asOpcode();
332  if (rhs_opcode == Opcodes::ICst ||
333  rhs_opcode == Opcodes::IMdl) {
334 
335  Code *rhs_hlp = rhs_ihlp->get_reference(0);
336  r_exec::View *rhs_hlp_v = (r_exec::View*)rhs_hlp->get_view(host, true);
337  if (rhs_hlp_v) {
338 
339  if (rhs_opcode == Opcodes::IMdl)
340  requirement_type_ = (rhs_->code(0).asOpcode() == Opcodes::AntiFact ? STRONG_REQUIREMENT : WEAK_REQUIREMENT);
341  controllers_[RHSController] = (HLPController *)rhs_hlp_v->controller_;
342  }
343  }
344 
345  Code *lhs_ihlp = lhs_->get_reference(0);
346  is_reuse_ = false;
347  controllers_[LHSController] = NULL;
348  uint16 lhs_opcode = lhs_ihlp->code(0).asOpcode();
349  if (lhs_opcode == Opcodes::ICst ||
350  lhs_opcode == Opcodes::IMdl) {
351 
352  Code *lhs_hlp = lhs_ihlp->get_reference(0);
353  r_exec::View *lhs_hlp_v = (r_exec::View*)lhs_hlp->get_view(host, true);
354  if (lhs_hlp_v) {
355 
356  if (lhs_opcode == Opcodes::IMdl)
357  is_reuse_ = true;
358  controllers_[LHSController] = (HLPController *)lhs_hlp_v->controller_;
359  }
360  }
361 
362  is_cmd_ = (lhs_opcode == Opcodes::Cmd);
363 }
364 
365 float32 MDLController::get_success_rate() const {
366 
367  return get_core_object()->code(MDL_SR).asFloat();
368 }
369 
370 bool MDLController::monitor_predictions(_Fact *input) { // predictions are admissible inputs (for checking predicted counter-evidences).
371 
372  Pred *pred = input->get_pred();
373  if (pred && pred->is_simulation()) // discard simulations.
374  return false;
375 
376  bool r = false;
377  r_code::list<P<PMonitor> >::const_iterator m;
378  p_monitorsCS_.enter();
379  for (m = p_monitors_.begin(); m != p_monitors_.end();) {
380 
381  if ((*m)->reduce(input)) {
382 
383  m = p_monitors_.erase(m);
384  r = true;
385  } else
386  ++m;
387  }
388  p_monitorsCS_.leave();
389 
390  return r;
391 }
392 
393 void MDLController::add_monitor(PMonitor *m) {
394 
395  p_monitorsCS_.enter();
396  p_monitors_.push_front(m);
397  p_monitorsCS_.leave();
398 }
399 
400 void MDLController::remove_monitor(PMonitor *m) {
401 
402  p_monitorsCS_.enter();
403  p_monitors_.remove(m);
404  p_monitorsCS_.leave();
405 }
406 
407 void MDLController::add_requirement_to_rhs() {
408 
409  if (requirement_type_ != NOT_A_REQUIREMENT) {
410 
411  HLPController *c = controllers_[RHSController];
412  if (c)
413  c->add_requirement(requirement_type_ == STRONG_REQUIREMENT);
414  }
415 }
416 
417 void MDLController::remove_requirement_from_rhs() {
418 
419  if (requirement_type_ != NOT_A_REQUIREMENT) {
420 
421  HLPController *c = controllers_[RHSController];
422  if (c)
423  c->remove_requirement(requirement_type_ == STRONG_REQUIREMENT);
424  }
425 }
426 
427 void MDLController::_store_requirement(r_code::list<RequirementEntry> *cache, RequirementEntry &e) {
428 
429  requirements_.CS_.enter();
430  auto now = Now();
432  for (_e = cache->begin(); _e != cache->end();) {
433 
434  if ((*_e).is_too_old(now)) // garbage collection.
435  _e = cache->erase(_e);
436  else
437  // JTnote: Maybe check if _e matches e and quit (to avoid duplicates).
438  ++_e;
439  }
440  cache->push_front(e);
441  requirements_.CS_.leave();
442 }
443 
444 ChainingStatus MDLController::retrieve_simulated_imdl_fwd(const HLPBindingMap *bm, Fact *f_imdl, Sim* sim, vector<BindingResult>& results) {
445 
446  uint32 wr_count;
447  uint32 sr_count;
448  uint32 r_count = get_requirement_count(wr_count, sr_count);
449  if (!r_count)
450  return NO_REQUIREMENT;
451  ChainingStatus r;
452  bool save_f_imdl_wr_enabled = f_imdl->get_reference(0)->code(I_HLP_WEAK_REQUIREMENT_ENABLED).asBoolean();
453  if (!sr_count) { // no strong req., some weak req.: true if there is one f->imdl complying with timings and bindings.
454 
455  r = WEAK_REQUIREMENT_DISABLED;
456  requirements_.CS_.enter();
457  auto now = Now();
459  for (e = simulated_requirements_.positive_evidences_.begin(); e != simulated_requirements_.positive_evidences_.end();) {
460 
461  if ((*e).is_too_old(now)) // garbage collection.
462  e = simulated_requirements_.positive_evidences_.erase(e);
463  else {
464 
465  if ((*e).evidence_->get_pred()->has_simulation(sim)) {
466 
467  _Fact *_f_imdl = (*e).evidence_->get_pred()->get_target();
468  HLPBindingMap _original(bm); // matching updates the binding map; always start afresh.
469  // Temporarily make f_imdl wr_enabled match the one from _f_imdl so that any difference is ignored.
470  f_imdl->get_reference(0)->code(I_HLP_WEAK_REQUIREMENT_ENABLED) = Atom::Boolean(
471  _f_imdl->get_reference(0)->code(I_HLP_WEAK_REQUIREMENT_ENABLED).asBoolean());
472  if (_original.match_fwd_strict(_f_imdl, f_imdl)) { // tpl args will be valuated in bm, but not in f_imdl yet.
473 
474  r = WEAK_REQUIREMENT_ENABLED;
475  results.push_back(BindingResult(new HLPBindingMap(_original), (*e).evidence_, (*e).mk_rdx_));
476  // Loop again to check for more matches.
477  }
478  }
479  ++e;
480  }
481  }
482 
483  requirements_.CS_.leave();
484  // Restore.
485  f_imdl->get_reference(0)->code(I_HLP_WEAK_REQUIREMENT_ENABLED) = Atom::Boolean(save_f_imdl_wr_enabled);
486  return r;
487  } else {
488 
489  if (!wr_count) { // some strong req., no weak req.: true if there is no |f->imdl complying with timings and bindings.
490 
491  requirements_.CS_.enter();
492  auto now = Now();
494  for (e = simulated_requirements_.negative_evidences_.begin(); e != simulated_requirements_.negative_evidences_.end();) {
495 
496  if ((*e).is_too_old(now)) // garbage collection.
497  e = simulated_requirements_.negative_evidences_.erase(e);
498  else {
499 
500  if ((*e).evidence_->get_pred()->has_simulation(sim)) {
501 
502  _Fact *_f_imdl = (*e).evidence_->get_pred()->get_target();
503  HLPBindingMap _original(bm); // matching updates the binding map; always start afresh.
504  if (_original.match_fwd_lenient(_f_imdl, f_imdl) == MATCH_SUCCESS_NEGATIVE) { // tpl args will be valuated in bm.
505 
506  results.push_back(BindingResult(new HLPBindingMap(_original), NULL, NULL));
507  requirements_.CS_.leave();
508  return STRONG_REQUIREMENT_NO_WEAK_REQUIREMENT;
509  }
510  }
511  ++e;
512  }
513  }
514 
515  requirements_.CS_.leave();
516  return NO_REQUIREMENT;
517  } else { // some strong req. and some weak req.: true if among the entries complying with timings and bindings, the youngest |f->imdl is weaker than the youngest f->imdl.
518 
519  r = WEAK_REQUIREMENT_DISABLED;
520  float32 negative_cfd = 0;
521  requirements_.CS_.enter();
522  auto now = Now();
523  _Fact* strong_requirement_ground = NULL;
524  HLPBindingMap strong_bm;
526  for (e = simulated_requirements_.negative_evidences_.begin(); e != simulated_requirements_.negative_evidences_.end();) {
527 
528  if ((*e).is_too_old(now)) // garbage collection.
529  e = simulated_requirements_.negative_evidences_.erase(e);
530  else {
531 
532  if ((*e).evidence_->get_pred()->has_simulation(sim)) {
533 
534  _Fact *_f_imdl = (*e).evidence_->get_pred()->get_target();
535  HLPBindingMap _original(bm); // matching updates the binding map; always start afresh.
536  if (_original.match_fwd_lenient(_f_imdl, f_imdl) == MATCH_SUCCESS_NEGATIVE) {
537 
538  negative_cfd = (*e).confidence_;
539  r = STRONG_REQUIREMENT_NO_WEAK_REQUIREMENT;
540  // We will update bm below.
541  strong_bm = _original;
542  strong_requirement_ground = (*e).evidence_;
543  break;
544  }
545  }
546  ++e;
547  }
548  }
549 
550  Fact* ground = NULL;
551  for (e = simulated_requirements_.positive_evidences_.begin(); e != simulated_requirements_.positive_evidences_.end();) {
552 
553  if ((*e).is_too_old(now)) // garbage collection.
554  e = simulated_requirements_.positive_evidences_.erase(e);
555  else {
556  if ((*e).evidence_->get_pred()->has_simulation(sim)) {
557 
558  _Fact *_f_imdl = (*e).evidence_->get_pred()->get_target();
559  HLPBindingMap _original(bm); // matching updates the binding map; always start afresh.
560  if (_original.match_fwd_strict(_f_imdl, f_imdl)) {
561 
562  bool strong_matches_weak =
563  (strong_requirement_ground && HLPBindingMap(_original).match_fwd_lenient
564  (_f_imdl, strong_requirement_ground->get_pred()->get_target()) == MATCH_SUCCESS_NEGATIVE);
565  if (!strong_matches_weak || (*e).confidence_ > negative_cfd) {
566 
567  r = WEAK_REQUIREMENT_ENABLED;
568  results.push_back(BindingResult(new HLPBindingMap(_original), (*e).evidence_, (*e).mk_rdx_));
569  // Loop again to check for more matches.
570  } else {
571  // If we already got a WEAK_REQUIREMENT_ENABLED, don't return STRONG_REQUIREMENT_DISABLED_WEAK_REQUIREMENT.
572  if (r != WEAK_REQUIREMENT_ENABLED) {
573  // For informational purposes, set ground in case this returns STRONG_REQUIREMENT_DISABLED_WEAK_REQUIREMENT.
574  ground = (*e).evidence_;
575  r = STRONG_REQUIREMENT_DISABLED_WEAK_REQUIREMENT;
576  }
577  }
578  }
579  }
580  ++e;
581  }
582  }
583 
584  if (r == STRONG_REQUIREMENT_NO_WEAK_REQUIREMENT || r == STRONG_REQUIREMENT_DISABLED_WEAK_REQUIREMENT)
585  results.push_back(BindingResult(new HLPBindingMap(strong_bm), ground, NULL));
586 
587  requirements_.CS_.leave();
588  return r;
589  }
590  }
591 }
592 
593 ChainingStatus MDLController::retrieve_simulated_imdl_bwd(HLPBindingMap *bm, Fact *f_imdl, Sim* prediction_sim, Fact *&ground, Fact *&strong_requirement_ground) {
594 
595  uint32 wr_count;
596  uint32 sr_count;
597  uint32 r_count = get_requirement_count(wr_count, sr_count);
598  ground = NULL;
599  strong_requirement_ground = NULL;
600  if (!r_count)
601  return NO_REQUIREMENT;
602  ChainingStatus r;
603  if (!sr_count) { // no strong req., some weak req.: true if there is one f->imdl complying with timings and bindings.
604 
605  r = WEAK_REQUIREMENT_DISABLED;
606  requirements_.CS_.enter();
607  auto now = Now();
609  for (e = simulated_requirements_.positive_evidences_.begin(); e != simulated_requirements_.positive_evidences_.end();) {
610 
611  if ((*e).is_too_old(now)) // garbage collection.
612  e = simulated_requirements_.positive_evidences_.erase(e);
613  else {
614 
615  if ((*e).evidence_->get_pred()->has_simulation(prediction_sim)) {
616 
617  _Fact *_f_imdl = (*e).evidence_->get_pred()->get_target();
618  HLPBindingMap _original(bm); // matching updates the binding map; always start afresh.
619  // Use match_fwd because the f_imdl time interval matches the binding map's fwd_after and fwd_before from the model LHS.
620  if (_original.match_fwd_strict(_f_imdl, f_imdl)) { // tpl args will be valuated in bm, but not in f_imdl yet.
621 
622  bm->load(&_original);
623  r = WEAK_REQUIREMENT_ENABLED;
624  ground = (*e).evidence_;
625  break;
626  }
627  }
628  ++e;
629  }
630  }
631 
632  requirements_.CS_.leave();
633  return r;
634  } else {
635 
636  if (!wr_count) { // some strong req., no weak req.: true if there is no |f->imdl complying with timings and bindings.
637 
638  requirements_.CS_.enter();
639  auto now = Now();
641  for (e = simulated_requirements_.negative_evidences_.begin(); e != simulated_requirements_.negative_evidences_.end();) {
642 
643  if ((*e).is_too_old(now)) // garbage collection.
644  e = simulated_requirements_.negative_evidences_.erase(e);
645  else {
646 
647  if ((*e).evidence_->get_pred()->has_simulation(prediction_sim)) {
648 
649  _Fact *_f_imdl = (*e).evidence_->get_pred()->get_target();
650  HLPBindingMap _original(bm); // matching updates the binding map; always start afresh.
651  // Use match_fwd because the f_imdl time interval matches the binding map's fwd_after and fwd_before from the model LHS.
652  if (_original.match_fwd_lenient(_f_imdl, f_imdl) == MATCH_SUCCESS_NEGATIVE) { // tpl args will be valuated in bm.
653 
654  bm->load(&_original);
655  strong_requirement_ground = (*e).evidence_;
656  requirements_.CS_.leave();
657  return STRONG_REQUIREMENT_NO_WEAK_REQUIREMENT;
658  }
659  }
660  ++e;
661  }
662  }
663 
664  requirements_.CS_.leave();
665  return NO_REQUIREMENT;
666  } else { // some strong req. and some weak req.: true if among the entries complying with timings and bindings, the youngest |f->imdl is weaker than the youngest f->imdl.
667 
668  r = WEAK_REQUIREMENT_DISABLED;
669  float32 negative_cfd = 0;
670  requirements_.CS_.enter();
671  auto now = Now();
672  HLPBindingMap strong_bm;
674  for (e = simulated_requirements_.negative_evidences_.begin(); e != simulated_requirements_.negative_evidences_.end();) {
675 
676  if ((*e).is_too_old(now)) // garbage collection.
677  e = simulated_requirements_.negative_evidences_.erase(e);
678  else {
679 
680  if ((*e).evidence_->get_pred()->has_simulation(prediction_sim)) {
681 
682  _Fact *_f_imdl = (*e).evidence_->get_pred()->get_target();
683  HLPBindingMap _original(bm); // matching updates the binding map; always start afresh.
684  // Use match_fwd because the f_imdl time interval matches the binding map's fwd_after and fwd_before from the model LHS.
685  if (_original.match_fwd_lenient(_f_imdl, f_imdl) == MATCH_SUCCESS_NEGATIVE) {
686 
687  negative_cfd = (*e).confidence_;
688  r = STRONG_REQUIREMENT_NO_WEAK_REQUIREMENT;
689  // We will update bm below.
690  strong_bm = _original;
691  strong_requirement_ground = (*e).evidence_;
692  break;
693  }
694  }
695  ++e;
696  }
697  }
698 
699  HLPBindingMap result_bm(bm);
700  for (e = simulated_requirements_.positive_evidences_.begin(); e != simulated_requirements_.positive_evidences_.end();) {
701 
702  if ((*e).is_too_old(now)) // garbage collection.
703  e = simulated_requirements_.positive_evidences_.erase(e);
704  else {
705  if ((*e).evidence_->get_pred()->has_simulation(prediction_sim)) {
706 
707  _Fact *_f_imdl = (*e).evidence_->get_pred()->get_target();
708  HLPBindingMap _original(bm); // matching updates the binding map; always start afresh.
709  // Use match_fwd because the f_imdl time interval matches the binding map's fwd_after and fwd_before from the model LHS.
710  if (_original.match_fwd_strict(_f_imdl, f_imdl)) {
711 
712  bool strong_matches_weak =
713  (strong_requirement_ground && HLPBindingMap(_original).match_fwd_lenient
714  (_f_imdl, strong_requirement_ground->get_pred()->get_target()) == MATCH_SUCCESS_NEGATIVE);
715  if (!strong_matches_weak || (*e).confidence_ > negative_cfd ||
716  _f_imdl->get_after() >= strong_requirement_ground->get_pred()->get_target()->get_before()) {
717 
718  if (r != WEAK_REQUIREMENT_ENABLED) {
719  r = WEAK_REQUIREMENT_ENABLED;
720  // We may do another iteration, so don't update bm yet.
721  result_bm.load(&_original);
722  ground = (*e).evidence_;
723  }
724  } else {
725  // Make sure the strong requirement timings overlap the weak requirement. We already made sure
726  // the strong requirement is not earlier than the weak. Now make sure it is not later.
727  if (strong_requirement_ground &&
728  strong_requirement_ground->get_pred()->get_target()->get_after() < _f_imdl->get_before()) {
729  if ((*e).evidence_->get_pred()->has_defeasible_consequence())
730  (*e).evidence_->get_pred()->get_defeasible_consequence()->invalidate();
731  if (r != WEAK_REQUIREMENT_ENABLED) {
732  ground = (*e).evidence_;
733  r = STRONG_REQUIREMENT_DISABLED_WEAK_REQUIREMENT;
734  }
735  }
736  }
737  }
738  }
739  ++e;
740  }
741  }
742 
743  if (r == STRONG_REQUIREMENT_NO_WEAK_REQUIREMENT || r == STRONG_REQUIREMENT_DISABLED_WEAK_REQUIREMENT)
744  bm->load(&strong_bm);
745  else
746  bm->load(&result_bm);
747 
748  requirements_.CS_.leave();
749  return r;
750  }
751  }
752 }
753 
754 // wr_enabled: true if there is at least one wr stronger than at least one sr.
755 ChainingStatus MDLController::retrieve_imdl_fwd(const HLPBindingMap *bm, Fact *f_imdl, RequirementsPair &r_p, std::vector<BindingResult>& results, MDLController *req_controller, bool &wr_enabled) {
756 
757  uint32 wr_count;
758  uint32 sr_count;
759  uint32 r_count = get_requirement_count(wr_count, sr_count);
760  wr_enabled = false;
761  if (!r_count)
762  return NO_REQUIREMENT;
763  ChainingStatus r;
764  if (!sr_count) { // no strong req., some weak req.: true if there is one f->imdl complying with timings and bindings.
765 
766 #if 0 // JTNote: We set ground = NULL above, so (ground != NULL) is never true.
767  if (ground != NULL) { // an imdl triggered the reduction of the cache.
768 
769  r_p.weak_requirements_.controllers.insert(req_controller);
770  r_p.weak_requirements_.f_imdl = ground;
771  r_p.weak_requirements_.chaining_was_allowed = true;
772  return WEAK_REQUIREMENT_ENABLED;
773  }
774 #endif
775 
776  r = WEAK_REQUIREMENT_DISABLED;
777  requirements_.CS_.enter();
778  auto now = Now();
780  for (e = requirements_.positive_evidences_.begin(); e != requirements_.positive_evidences_.end();) {
781 
782  Code *imdl = (*e).evidence_->get_pred()->get_target()->get_reference(0);
783  uint16 tpl_index = imdl->code(I_HLP_TPL_ARGS).asIndex();
784 
785  if ((*e).is_too_old(now)) // garbage collection.
786  e = requirements_.positive_evidences_.erase(e);
787  else if ((*e).is_out_of_range(now))
788  ++e;
789  else {
790 
791  _Fact *_f_imdl = (*e).evidence_->get_pred()->get_target();
792  HLPBindingMap _original(bm); // matching updates the binding map; always start afresh.
793  if (_original.match_fwd_strict(_f_imdl, f_imdl)) { // tpl args will be valuated in bm, but not in f_imdl yet.
794 #ifdef WITH_DETAIL_OID
795  OUTPUT_LINE(MDL_OUT, Utils::RelativeTime(Now()) << " fact (" << f_imdl->get_detail_oid() << ") imdl mdl " <<
796  f_imdl->get_reference(0)->get_reference(0)->get_oid() << " matches evidence fact (" <<
797  _f_imdl->get_detail_oid() << ") imdl mdl " << _f_imdl->get_reference(0)->get_reference(0)->get_oid());
798 #endif
799  if ((*e).chaining_was_allowed_) {
800 
801  r = WEAK_REQUIREMENT_ENABLED;
802  results.push_back(BindingResult(new HLPBindingMap(_original), (*e).evidence_, (*e).mk_rdx_));
803  // Loop again to check for more matches.
804  }
805 
806  r_p.weak_requirements_.controllers.insert((*e).controller_);
807  r_p.weak_requirements_.f_imdl = _f_imdl;
808  r_p.weak_requirements_.chaining_was_allowed = (*e).chaining_was_allowed_;
809  }
810  ++e;
811  }
812  }
813 
814  requirements_.CS_.leave();
815  return r;
816  } else {
817 
818  if (!wr_count) { // some strong req., no weak req.: true if there is no |f->imdl complying with timings and bindings.
819 
820  r = NO_REQUIREMENT;
821  requirements_.CS_.enter();
822  auto now = Now();
824  for (e = requirements_.negative_evidences_.begin(); e != requirements_.negative_evidences_.end();) {
825 
826  if ((*e).is_too_old(now)) // garbage collection.
827  e = requirements_.positive_evidences_.erase(e);
828  else if ((*e).is_out_of_range(now))
829  ++e;
830  else {
831 
832  _Fact *_f_imdl = (*e).evidence_->get_pred()->get_target();
833  HLPBindingMap _original(bm); // matching updates the binding map; always start afresh.
834  if (_original.match_fwd_lenient(_f_imdl, f_imdl) == MATCH_SUCCESS_NEGATIVE) { // tpl args will be valuated in bm.
835 
836  if (r == NO_REQUIREMENT && (*e).chaining_was_allowed_) // first match.
837  r = STRONG_REQUIREMENT_NO_WEAK_REQUIREMENT;
838 
839  r_p.strong_requirements_.controllers.insert((*e).controller_);
840  r_p.strong_requirements_.f_imdl = _f_imdl;
841  r_p.strong_requirements_.chaining_was_allowed = (*e).chaining_was_allowed_;
842  }
843  ++e;
844  }
845  }
846 
847  requirements_.CS_.leave();
848  return r;
849  } else { // some strong req. and some weak req.: true if among the entries complying with timings and bindings, the youngest |f->imdl is weaker than the youngest f->imdl.
850 
851  r = WEAK_REQUIREMENT_DISABLED;
852  requirements_.CS_.enter();
853  float32 negative_cfd = 0;
854  auto now = Now();
855 
856  _Fact* strong_requirement_ground = NULL;
857  HLPBindingMap strong_bm;
859  for (e = requirements_.negative_evidences_.begin(); e != requirements_.negative_evidences_.end();) {
860 
861  if ((*e).is_too_old(now)) // garbage collection.
862  e = requirements_.negative_evidences_.erase(e);
863  else if ((*e).is_out_of_range(now))
864  ++e;
865  else {
866 
867  _Fact *_f_imdl = (*e).evidence_->get_pred()->get_target();
868  HLPBindingMap _original(bm); // matching updates the binding map; always start afresh.
869  if (_original.match_fwd_lenient(_f_imdl, f_imdl) == MATCH_SUCCESS_NEGATIVE) {
870 
871  if (r == WEAK_REQUIREMENT_DISABLED && (*e).chaining_was_allowed_) { // first match.
872 
873  negative_cfd = (*e).confidence_;
874  r = STRONG_REQUIREMENT_NO_WEAK_REQUIREMENT;
875  // We will update bm below.
876  strong_bm = _original;
877  strong_requirement_ground = (*e).evidence_;
878  }
879 
880  r_p.strong_requirements_.controllers.insert((*e).controller_);
881  r_p.strong_requirements_.f_imdl = _f_imdl;
882  r_p.strong_requirements_.chaining_was_allowed = (*e).chaining_was_allowed_;
883  }
884  ++e;
885  }
886  }
887 
888 #if 0 // JTNote: We set ground = NULL above, so (ground != NULL) is never true.
889  if (ground != NULL) { // an imdl triggered the reduction of the cache.
890 
891  requirements_.CS_.leave();
892  float32 confidence = ground->get_pred()->get_target()->get_cfd();
893  if (confidence > negative_cfd) {
894 
895  r = WEAK_REQUIREMENT_ENABLED;
896  r_p.weak_requirements_.controllers.insert(req_controller);
897  r_p.weak_requirements_.f_imdl = ground;
898  r_p.weak_requirements_.chaining_was_allowed = true;
899  wr_enabled = true;
900  }
901  return r;
902  }
903 #endif
904  Fact* ground = NULL;
905  for (e = requirements_.positive_evidences_.begin(); e != requirements_.positive_evidences_.end();) {
906 
907  if ((*e).is_too_old(now)) // garbage collection.
908  e = requirements_.positive_evidences_.erase(e);
909  else if ((*e).is_out_of_range(now))
910  ++e;
911  else {
912 
913  _Fact *_f_imdl = (*e).evidence_->get_pred()->get_target();
914  HLPBindingMap _original(bm); // matching updates the binding map; always start afresh.
915  if (_original.match_fwd_strict(_f_imdl, f_imdl)) {
916 
917  if ((*e).chaining_was_allowed_) {
918 
919  bool strong_matches_weak =
920  (strong_requirement_ground && HLPBindingMap(_original).match_fwd_lenient
921  (_f_imdl, strong_requirement_ground->get_pred()->get_target()) == MATCH_SUCCESS_NEGATIVE);
922  if (!strong_matches_weak || (*e).confidence_ > negative_cfd) {
923 
924  r = WEAK_REQUIREMENT_ENABLED;
925  results.push_back(BindingResult(new HLPBindingMap(_original), (*e).evidence_, (*e).mk_rdx_));
926  // Loop again to check for more matches.
927  wr_enabled = strong_matches_weak;
928  } else {
929 
930  // If we already got a WEAK_REQUIREMENT_ENABLED, don't return STRONG_REQUIREMENT_DISABLED_WEAK_REQUIREMENT.
931  if (r != WEAK_REQUIREMENT_ENABLED) {
932  // For informational purposes, set ground in case this returns STRONG_REQUIREMENT_DISABLED_WEAK_REQUIREMENT.
933  ground = (*e).evidence_;
934  r = STRONG_REQUIREMENT_DISABLED_WEAK_REQUIREMENT;
935  wr_enabled = false;
936  }
937  }
938  }
939 
940  r_p.weak_requirements_.controllers.insert((*e).controller_);
941  r_p.weak_requirements_.f_imdl = _f_imdl;
942  r_p.weak_requirements_.chaining_was_allowed = (*e).chaining_was_allowed_;
943  }
944  ++e;
945  }
946  }
947 
948  if (r == STRONG_REQUIREMENT_NO_WEAK_REQUIREMENT || r == STRONG_REQUIREMENT_DISABLED_WEAK_REQUIREMENT)
949  results.push_back(BindingResult(new HLPBindingMap(strong_bm), ground, NULL));
950 
951  requirements_.CS_.leave();
952  return r;
953  }
954  }
955 }
956 
957 ChainingStatus MDLController::retrieve_imdl_bwd(HLPBindingMap *bm, Fact *f_imdl, Fact *&ground, Fact *&strong_requirement_ground) {
958 
959  uint32 wr_count;
960  uint32 sr_count;
961  uint32 r_count = get_requirement_count(wr_count, sr_count);
962  ground = NULL;
963  strong_requirement_ground = NULL;
964  if (!r_count)
965  return NO_REQUIREMENT;
966  ChainingStatus r;
967  if (!sr_count) { // no strong req., some weak req.: true if there is one f->imdl complying with timings and bindings.
968 
969  r = WEAK_REQUIREMENT_DISABLED;
970  requirements_.CS_.enter();
971  auto now = Now();
973  for (e = requirements_.positive_evidences_.begin(); e != requirements_.positive_evidences_.end();) {
974 
975  if ((*e).is_too_old(now)) // garbage collection.
976  e = requirements_.positive_evidences_.erase(e);
977  else {
978 
979  _Fact *_f_imdl = (*e).evidence_->get_pred()->get_target();
980  HLPBindingMap _original(bm); // matching updates the binding map; always start afresh.
981  // Use match_fwd because the f_imdl time interval matches the binding map's fwd_after and fwd_before from the model LHS.
982  if (_original.match_fwd_strict(_f_imdl, f_imdl)) { // tpl args will be valuated in bm, but not in f_imdl yet.
983 
984  r = WEAK_REQUIREMENT_ENABLED;
985  bm->load(&_original);
986  ground = (*e).evidence_;
987  break;
988  }
989  ++e;
990  }
991  }
992 
993  requirements_.CS_.leave();
994  return r;
995  } else {
996 
997  if (!wr_count) { // some strong req., no weak req.: true if there is no |f->imdl complying with timings and bindings.
998 
999  ground = NULL;
1000 
1001  requirements_.CS_.enter();
1002  auto now = Now();
1004  for (e = requirements_.negative_evidences_.begin(); e != requirements_.negative_evidences_.end();) {
1005 
1006  if ((*e).is_too_old(now)) // garbage collection.
1007  e = requirements_.negative_evidences_.erase(e);
1008  else {
1009 
1010  _Fact *_f_imdl = (*e).evidence_->get_pred()->get_target();
1011  HLPBindingMap _original(bm); // matching updates the binding map; always start afresh.
1012  // Use match_fwd because the f_imdl time interval matches the binding map's fwd_after and fwd_before from the model LHS.
1013  if (_original.match_fwd_lenient(_f_imdl, f_imdl) == MATCH_SUCCESS_NEGATIVE) { // tpl args will be valuated in bm.
1014 
1015  strong_requirement_ground = (*e).evidence_;
1016  requirements_.CS_.leave();
1017  return STRONG_REQUIREMENT_NO_WEAK_REQUIREMENT;
1018  }
1019  ++e;
1020  }
1021  }
1022 
1023  requirements_.CS_.leave();
1024  return NO_REQUIREMENT;
1025  } else { // some strong req. and some weak req.: true if among the entries complying with timings and bindings, the youngest |f->imdl is weaker than the youngest f->imdl.
1026 
1027  r = WEAK_REQUIREMENT_DISABLED;
1028  float32 negative_cfd = 0;
1029  requirements_.CS_.enter();
1030  auto now = Now();
1032  for (e = requirements_.negative_evidences_.begin(); e != requirements_.negative_evidences_.end();) {
1033 
1034  if ((*e).is_too_old(now)) // garbage collection.
1035  e = requirements_.negative_evidences_.erase(e);
1036  else {
1037 
1038  _Fact *_f_imdl = (*e).evidence_->get_pred()->get_target();
1039  HLPBindingMap _original(bm); // matching updates the binding map; always start afresh.
1040  // Use match_fwd because the f_imdl time interval matches the binding map's fwd_after and fwd_before from the model LHS.
1041  if (_original.match_fwd_lenient(_f_imdl, f_imdl) == MATCH_SUCCESS_NEGATIVE) {
1042 
1043  negative_cfd = (*e).confidence_;
1044  r = STRONG_REQUIREMENT_NO_WEAK_REQUIREMENT;
1045  strong_requirement_ground = (*e).evidence_;
1046  break;
1047  }
1048  ++e;
1049  }
1050  }
1051 
1052  HLPBindingMap result_bm(bm);
1053  for (e = requirements_.positive_evidences_.begin(); e != requirements_.positive_evidences_.end();) {
1054 
1055  if ((*e).is_too_old(now)) // garbage collection.
1056  e = requirements_.positive_evidences_.erase(e);
1057  else {
1058  _Fact *_f_imdl = (*e).evidence_->get_pred()->get_target();
1059  HLPBindingMap _original(bm); // matching updates the binding map; always start afresh.
1060  // Use match_fwd because the f_imdl time interval matches the binding map's fwd_after and fwd_before from the model LHS.
1061  if (_original.match_fwd_strict(_f_imdl, f_imdl)) {
1062 
1063  bool strong_matches_weak =
1064  (strong_requirement_ground && HLPBindingMap(_original).match_fwd_lenient
1065  (_f_imdl, strong_requirement_ground->get_pred()->get_target()) == MATCH_SUCCESS_NEGATIVE);
1066  if (!strong_matches_weak || (*e).confidence_ > negative_cfd) {
1067 
1068  if (r != WEAK_REQUIREMENT_ENABLED) {
1069  r = WEAK_REQUIREMENT_ENABLED;
1070  // We may do another iteration, so don't update bm yet.
1071  result_bm.load(&_original);
1072  ground = (*e).evidence_;
1073  }
1074  } else {
1075  if (r != WEAK_REQUIREMENT_ENABLED) {
1076  ground = (*e).evidence_;
1077  r = STRONG_REQUIREMENT_DISABLED_WEAK_REQUIREMENT;
1078  }
1079  }
1080  }
1081  ++e;
1082  }
1083  }
1084 
1085  if (r == WEAK_REQUIREMENT_ENABLED)
1086  bm->load(&result_bm);
1087 
1088  requirements_.CS_.leave();
1089  return r;
1090  }
1091  }
1092 }
1093 
1094 
1095 // jm Replaced template definition with make_pair
1096 void MDLController::register_requirement(_Fact *f_pred, RequirementsPair &r_p) {
1097 
1098  if (r_p.weak_requirements_.controllers.size() > 0 || r_p.strong_requirements_.controllers.size() > 0)
1099  active_requirements_.insert(std::make_pair(f_pred, r_p));
1100 }
1101 
1102 bool MDLController::get_imdl_template_timings(
1103  r_code::Code* imdl, Timestamp& after, Timestamp& before, uint16* after_ts_index, uint16* before_ts_index) {
1104  auto template_set_index = imdl->code(I_HLP_TPL_ARGS).asIndex();
1105  auto template_set_count = imdl->code(template_set_index).getAtomCount();
1106  auto template_ti_index = template_set_index + template_set_count;
1107  if (!(template_set_count >= 1 && imdl->code(template_ti_index).getDescriptor() == Atom::I_PTR &&
1108  imdl->code(imdl->code(template_ti_index).asIndex()).asOpcode() == Opcodes::TI))
1109  return false;
1110  auto ti_index = imdl->code(template_ti_index).asIndex();
1111  auto after_index = ti_index + 1;
1112  auto before_index = ti_index + 2;
1113 
1114  after = Utils::GetTimestamp(imdl, after_index);
1115  before = Utils::GetTimestamp(imdl, before_index);
1116  if (after_ts_index)
1117  *after_ts_index = imdl->code(after_index).asIndex();
1118  if (before_ts_index)
1119  *before_ts_index = imdl->code(before_index).asIndex();
1120 
1121  return true;
1122 }
1123 
1125 
1126 MDLController::RequirementEntry::RequirementEntry() : PredictedEvidenceEntry(), controller_(NULL), chaining_was_allowed_(false) {
1127 }
1128 
1129 MDLController::RequirementEntry::RequirementEntry(_Fact *f_p_f_imdl, MkRdx* mk_rdx, MDLController *c, bool chaining_was_allowed) : PredictedEvidenceEntry(f_p_f_imdl), mk_rdx_(mk_rdx), controller_(c), chaining_was_allowed_(chaining_was_allowed) {
1130 }
1131 
1133 
1134 PMDLController::PMDLController(_View *view) : MDLController(view) {
1135 }
1136 
1137 void PMDLController::add_g_monitor(_GMonitor *m) {
1138 
1139  g_monitorsCS_.enter();
1140  g_monitors_.push_front(m);
1141  g_monitorsCS_.leave();
1142 }
1143 
1144 void PMDLController::remove_g_monitor(_GMonitor *m) {
1145 
1146  g_monitorsCS_.enter();
1147  g_monitors_.remove(m);
1148  g_monitorsCS_.leave();
1149 }
1150 
1151 void PMDLController::add_r_monitor(_GMonitor *m) {
1152 
1153  g_monitorsCS_.enter();
1154  r_monitors_.push_front(m);
1155  g_monitorsCS_.leave();
1156 }
1157 
1158 void PMDLController::remove_r_monitor(_GMonitor *m) {
1159 
1160  g_monitorsCS_.enter();
1161  r_monitors_.remove(m);
1162  g_monitorsCS_.leave();
1163 }
1164 
1165 void PMDLController::inject_goal(HLPBindingMap *bm, Fact *goal, Fact *f_imdl) const {
1166 
1167  Group *primary_grp = get_host();
1168  auto before = goal->get_before();
1169  auto now = Now();
1170  int32 resilience = _Mem::Get()->get_goal_pred_success_res(primary_grp, now, before - now);
1171 
1172  View *view = new View(View::SYNC_ONCE, now, 1, resilience, primary_grp, primary_grp, goal); // SYNC_ONCE,res=resilience.
1173  _Mem::Get()->inject(view);
1174 
1175  MkRdx *mk_rdx = new MkRdx(f_imdl, goal->get_goal()->get_super_goal(), goal, 1, bm);
1176  inject_notification_into_out_groups(primary_grp, mk_rdx);
1177 
1178  OUTPUT_LINE(MDL_OUT, Utils::RelativeTime(Now()) << " mdl "
1179  << f_imdl->get_reference(0)->get_reference(0)->get_oid() << " abduce -> mk.rdx " << mk_rdx->get_oid());
1180 }
1181 
1182 void PMDLController::inject_simulation(Fact *goal_pred, Timestamp injectionTime) const { // f->pred->f->obj or f->goal->f->obj.
1183 
1184  Group *primary_grp = get_host();
1185  auto before = ((_Fact *)goal_pred->get_reference(0)->get_reference(0))->get_before();
1186  auto now = Now();
1187  int32 resilience = _Mem::Get()->get_goal_pred_success_res(primary_grp, now, before - now);
1188 
1189  View *view = new View(View::SYNC_ONCE, injectionTime, 1, resilience, primary_grp, primary_grp, goal_pred); // SYNC_ONCE,res=resilience.
1190  _Mem::Get()->inject(view);
1191 }
1192 
1193 bool PMDLController::monitor_goals(_Fact *input) {
1194 
1195  bool r = false;
1196  r_code::list<P<_GMonitor> >::const_iterator m;
1197  g_monitorsCS_.enter();
1198  for (m = g_monitors_.begin(); m != g_monitors_.end();) {
1199 
1200  if ((*m)->reduce(input)) {
1201 
1202  m = g_monitors_.erase(m);
1203  r = true;
1204  } else
1205  ++m;
1206  }
1207  g_monitorsCS_.leave();
1208  return r;
1209 }
1210 
1211 void PMDLController::register_predicted_goal_outcome(Fact *goal, HLPBindingMap *bm, Fact *f_imdl, bool success, bool injected_goal) { // called only for SIM_COMMITTED mode.
1212 
1213  if (success)
1214  goal->invalidate(); // monitor still running to detect failures (actual or predicted).
1215  else {
1216 
1217  if (!injected_goal) // the goal has not been injected; monitor still running.
1218  inject_goal(bm, goal, f_imdl);
1219  else {
1220 
1221  if (goal->is_invalidated()) { // the only case when the goal can be invalidated here is when a predicted failure follows a predicted success.
1222 
1223  Fact *new_goal = new Fact(goal);
1224  Goal *g = new_goal->get_goal();
1225  auto now = Now();
1226  auto deadline = g->get_target()->get_before();
1227  auto sim_thz = get_sim_thz(now, deadline);
1228 
1229  Sim *new_sim = new Sim(SIM_ROOT, sim_thz, g->get_sim()->get_f_super_goal(), false, this, 1);
1230 
1231  g->set_sim(new_sim);
1232 
1233  add_g_monitor(new GMonitor(this, bm, deadline, now + sim_thz, new_goal, f_imdl, NULL));
1234 
1235  inject_goal(bm, new_goal, f_imdl);
1236  }
1237  }
1238  }
1239 }
1240 
1241 inline microseconds PMDLController::get_sim_thz(Timestamp now, Timestamp deadline) const {
1242 
1243  auto min_sim_thz = _Mem::Get()->get_min_sim_time_horizon(); // time allowance for the simulated predictions to flow upward.
1244  auto sim_thz = _Mem::Get()->get_sim_time_horizon(deadline - now);
1245  if (sim_thz > min_sim_thz) {
1246 
1247  sim_thz -= min_sim_thz;
1248  auto max_sim_thz = _Mem::Get()->get_max_sim_time_horizon();
1249  if (sim_thz > max_sim_thz)
1250  sim_thz = max_sim_thz;
1251  return sim_thz;
1252  } else // no time to simulate.
1253  return microseconds(0);
1254 }
1255 
1257 
1258 TopLevelMDLController::TopLevelMDLController(_View *view) : PMDLController(view) {
1259 }
1260 
1261 void TopLevelMDLController::store_requirement(_Fact *f_p_f_imdl, MkRdx* mk_rdx, MDLController *controller, bool chaining_was_allowed) {
1262 }
1263 
1264 void TopLevelMDLController::take_input(r_exec::View *input) {
1265 
1266  if (input->object_->code(0).asOpcode() == Opcodes::Fact ||
1267  input->object_->code(0).asOpcode() == Opcodes::AntiFact) // discard everything but facts and |facts.
1268  Controller::__take_input<TopLevelMDLController>(input);
1269 }
1270 
1271 void TopLevelMDLController::reduce(r_exec::View *input) { // no lock.
1272 
1273  if (input->object_->is_invalidated())
1274  return;
1275 
1276  Goal *goal = ((_Fact *)input->object_)->get_goal();
1277  if (goal && (goal->is_drive() || goal->is_imdl_drive())) {
1278 
1279  _Fact *goal_target = goal->get_target(); // goal_target is f->object.
1280  float32 confidence = get_success_rate() * goal_target->get_cfd(); // reading STRONG_REQUIREMENT is atomic.
1281  if (confidence <= get_host()->code(GRP_SLN_THR).asFloat()) // cfd is too low for any sub-goal to be injected.
1282  return;
1283 
1284  P<HLPBindingMap> bm = new HLPBindingMap(bindings_);
1285  bm->reset_bwd_timings(goal_target);
1286  if (bm->match_bwd_strict(goal_target, rhs_)) { // the rhs of a top-level model is never a |fact, hence strict matching instead of lenient.
1287  // Log the injection of a drive, presumably from a program.
1288  // The view injection time may be different than now, so log it too.
1289  OUTPUT_LINE(MDL_IN, Utils::RelativeTime(Now()) << " -> drive " <<
1290  input->object_->get_oid() << ", ijt " << Utils::RelativeTime(input->get_ijt()));
1291  abduce(bm, (Fact*)input->object_, confidence);
1292  }
1293  else if (!goal->is_requirement()) { // goal_target may be f->imdl and not a requirement: case of a reuse of the model, i.e. the goal target is for the model to make a prediction: this translates into making a sub-goal from the lhs.
1294 
1295  Code *imdl = goal_target->get_reference(0);
1296  if (imdl->code(0).asOpcode() == Opcodes::IMdl && imdl->get_reference(0) == get_object()) { // in that case, get the bm from the imdl, ignore the bwd guards, bind the rhs and inject.
1297 
1298  bm = new HLPBindingMap(bindings_);
1299  bm->reset_bwd_timings(goal_target);
1300  bm->init_from_f_ihlp(goal_target);
1301  // Log the injection of a drive, presumably from a program.
1302  // The view injection time may be different than now, so log it too.
1303  OUTPUT_LINE(MDL_IN, Utils::RelativeTime(Now()) << " -> drive " <<
1304  input->object_->get_oid() << ", ijt " << Utils::RelativeTime(input->get_ijt()));
1305  abduce(bm, (Fact *)input->object_, confidence);
1306  }
1307  }
1308  } else {
1309 
1310  PrimaryMDLOverlay o(this, bindings_);
1311  o.reduce(input->object_, NULL, NULL); // matching is used to fill up the cache (no predictions).
1312 
1313  monitor_goals(input->object_);
1314  }
1315 }
1316 
1317 void TopLevelMDLController::abduce(HLPBindingMap *bm, Fact *super_goal, float32 confidence) { // super_goal is a drive.
1318 
1319  if (evaluate_bwd_guards(bm)) { // bm may be updated.
1320 
1321  P<_Fact> bound_lhs = (_Fact *)bm->bind_pattern(get_lhs());
1322  _Fact *evidence;
1323  Fact *f_imdl;
1324 
1325  switch (check_evidences(bound_lhs, evidence)) {
1326  case MATCH_SUCCESS_POSITIVE: // goal target is already known: report drive success.
1327  register_drive_outcome(super_goal, true);
1328  break;
1329  case MATCH_SUCCESS_NEGATIVE: // a counter evidence is already known: report drive failure.
1330  register_drive_outcome(super_goal, false);
1331  break;
1332  case MATCH_FAILURE:
1333  f_imdl = get_f_ihlp(bm, false);
1334  f_imdl->set_reference(0, bm->bind_pattern(f_imdl->get_reference(0))); // valuate f_imdl from updated bm.
1335  bound_lhs->set_cfd(confidence);
1336  switch (check_predicted_evidences(bound_lhs, evidence)) {
1337  case MATCH_SUCCESS_POSITIVE:
1338  break;
1339  case MATCH_SUCCESS_NEGATIVE:
1340  case MATCH_FAILURE:
1341  evidence = NULL;
1342  break;
1343  }
1344  abduce_lhs(bm, super_goal, bound_lhs, f_imdl, evidence);
1345  break;
1346  }
1347  }
1348 }
1349 
1350 void TopLevelMDLController::abduce_lhs(HLPBindingMap *bm,
1351  Fact *super_goal, // f->g->f->obj; actual goal.
1352  _Fact *sub_goal_target, // f->obj, i.e. bound lhs.
1353  Fact *f_imdl,
1354  _Fact *evidence) {
1355 
1356  auto now = Now();
1357  auto deadline = sub_goal_target->get_before();
1358  auto sim_thz = get_sim_thz(now, deadline);
1359  Sim *sub_sim = new Sim(SIM_ROOT, sim_thz, super_goal, false, this, 1);
1360  // Register the goal to make sure it doesn't become a subgoal.
1361  sub_sim->register_goal_target(sub_goal_target);
1362 
1363  Goal *sub_goal = new Goal(sub_goal_target, super_goal->get_goal()->get_actor(), sub_sim, 1);
1364  Fact *f_sub_goal = new Fact(sub_goal, now, now, 1, 1);
1365 
1366  if (!evidence)
1367  inject_goal(bm, f_sub_goal, f_imdl);
1368  add_g_monitor(new GMonitor(this, bm, deadline, now + sim_thz, f_sub_goal, f_imdl, evidence));
1369  OUTPUT_LINE(MDL_OUT, Utils::RelativeTime(Now()) << " mdl " << get_object()->get_oid() << " -> fact " << f_sub_goal->get_oid() <<
1370  " goal [" << Utils::RelativeTime(sub_goal_target->get_after()) << "," << Utils::RelativeTime(sub_goal_target->get_before()) << "]");
1371 }
1372 
1373 void TopLevelMDLController::predict(HLPBindingMap *bm, _Fact *input, Fact *f_imdl, bool chaining_was_allowed, RequirementsPair &r_p, Fact *ground,
1374  MkRdx* ground_mk_rdx, vector<P<_Fact> >& already_predicted) { // no prediction here.
1375 }
1376 
1377 void TopLevelMDLController::register_pred_outcome(Fact *f_pred, Code* mk_rdx, bool success, _Fact *evidence, float32 confidence, bool rate_failures) {
1378 }
1379 
1380 void TopLevelMDLController::register_goal_outcome(Fact *goal, bool success, _Fact *evidence) const {
1381 
1382  goal->invalidate();
1383 
1384  auto now = Now();
1385  Code *goal_success;
1386  Code *f_goal_success;
1387  _Fact *absentee;
1388  if (success) {
1389 
1390  goal_success = new Success(goal, evidence, 1);
1391  f_goal_success = new Fact(goal_success, now, now, 1, 1);
1392  absentee = NULL;
1393  } else {
1394 
1395  if (!evidence) { // assert absence of the goal target.
1396 
1397  absentee = goal->get_goal()->get_target()->get_absentee();
1398  goal_success = new Success(goal, absentee, 1);
1399  } else {
1400 
1401  absentee = NULL;
1402  goal_success = new Success(goal, evidence, 1);
1403  }
1404  f_goal_success = new AntiFact(goal_success, now, now, 1, 1);
1405  }
1406 
1407  Group *primary_host = get_host();
1408  uint16 out_group_count = get_out_group_count() - 1;
1409  Group *drives_host = (Group *)get_out_group(out_group_count); // the drives group is the last of the output groups.
1410  for (uint16 i = 0; i < out_group_count; ++i) { // inject notification in out groups (drives host excepted).
1411 
1412  Group *out_group = (Group *)get_out_group(i);
1413  int32 resilience = _Mem::Get()->get_goal_pred_success_res(out_group, now, seconds(0));
1414  View *view = new View(View::SYNC_ONCE, now, 1, resilience, out_group, primary_host, f_goal_success);
1415  _Mem::Get()->inject(view);
1416 
1417  if (absentee) {
1418 
1419  view = new View(View::SYNC_ONCE, now, 1, 1, out_group, primary_host, absentee);
1420  _Mem::Get()->inject(view);
1421  }
1422  }
1423 
1424  register_drive_outcome(goal->get_goal()->get_sim()->get_f_super_goal(), success);
1425  OUTPUT_LINE(GOAL_MON, Utils::RelativeTime(Now()) << " fact " << f_goal_success->get_oid() << ": " << goal->get_oid() <<
1426  " goal " << (success ? "success" : "failure") << " (TopLevel)");
1427 }
1428 
1429 void TopLevelMDLController::register_drive_outcome(Fact *drive, bool success) const {
1430 
1431  drive->invalidate();
1432 
1433  auto now = Now();
1434  Code *drive_success = new Success(drive, NULL, 1);
1435  Code *f_drive_success;
1436  if (success)
1437  f_drive_success = new Fact(drive_success, now, now, 1, 1);
1438  else
1439  f_drive_success = new AntiFact(drive_success, now, now, 1, 1);
1440 
1441  Group *primary_host = get_host();
1442  uint16 out_group_count = get_out_group_count() - 1;
1443  Group *drives_host = (Group *)get_out_group(out_group_count); // the drives group is the last of the output groups.
1444  View *view = new View(View::SYNC_ONCE, now, 1, 1, drives_host, primary_host, f_drive_success); // sln=1,res=1.
1445  _Mem::Get()->inject(view); // inject in the drives group (will be caught by the drive injectors).
1446 }
1447 
1448 void PMDLController::inject_simulated_goal_success(Fact *goal, bool success, _Fact *evidence) const { // evidence is a simulated prediction.
1449 
1450  Code *success_object = new Success(goal, evidence, 1);
1451  Pred *evidence_pred = evidence->get_pred();
1452  float32 confidence = evidence_pred->get_target()->get_cfd();
1453  _Fact* evidence_f_target = evidence_pred->get_target();
1454  _Fact *f_success_object;
1455  if (success)
1456  f_success_object = new Fact(success_object, evidence_f_target->get_after(), evidence_f_target->get_before(), confidence, 1);
1457  else
1458  f_success_object = new AntiFact(success_object, evidence_f_target->get_after(), evidence_f_target->get_before(), confidence, 1);
1459 
1460  Pred *pred = new Pred(f_success_object, evidence_pred, 1);
1461  auto now = Now();
1462  Fact *f_pred = new Fact(pred, now, now, 1, 1);
1463 
1464  Group *primary_host = get_host();
1465  int32 resilience = _Mem::Get()->get_goal_pred_success_res(primary_host, now, seconds(0));
1466  View *view = new View(View::SYNC_ONCE, now, 1, resilience, primary_host, primary_host, f_pred);
1467  _Mem::Get()->inject(view); // inject in the primary group.
1468  OUTPUT_LINE(MDL_OUT, Utils::RelativeTime(Now()) << " mdl " << get_object()->get_oid() << ": fact " <<
1469  evidence->get_oid() << " pred -> fact " << f_pred->get_oid() << " simulated pred");
1470 }
1471 
1472 void TopLevelMDLController::register_simulated_goal_outcome(Fact* goal, bool success, _Fact* evidence) const { // evidence is a simulated prediction.
1473  inject_simulated_goal_success(goal, success, evidence);
1474 }
1475 
1476 void TopLevelMDLController::register_req_outcome(Fact *f_pred, bool success, bool rate_failures) {
1477 }
1478 
1480 
1481 PrimaryMDLController::PrimaryMDLController(_View *view) : PMDLController(view) {
1482  inject_notification_into_out_groups(get_host(), new MkNew(_Mem::Get(), get_core_object()));
1483 }
1484 
1485 void PrimaryMDLController::set_secondary(SecondaryMDLController *secondary) {
1486 
1487  secondary_ = secondary;
1488  add_requirement_to_rhs();
1489  secondary->add_requirement_to_rhs();
1490 }
1491 
1492 void PrimaryMDLController::store_requirement(_Fact *f_p_f_imdl, MkRdx* mk_rdx, MDLController *controller, bool chaining_was_allowed) {
1493 
1494  bool is_simulation = f_p_f_imdl->get_pred()->is_simulation();
1495  _Fact *f_imdl = f_p_f_imdl->get_pred()->get_target();
1496  RequirementEntry e(f_p_f_imdl, mk_rdx, controller, chaining_was_allowed);
1497 
1498  // Store the requirement before signaling the monitor so that its target will match the requirement.
1499  if (f_imdl->is_fact()) {
1500  if (is_simulation)
1501  _store_requirement(&simulated_requirements_.positive_evidences_, e);
1502  else
1503  _store_requirement(&requirements_.positive_evidences_, e);
1504  }
1505  else {
1506  // Negative requirement.
1507  if (is_simulation)
1508  _store_requirement(&simulated_requirements_.negative_evidences_, e);
1509  else
1510  _store_requirement(&requirements_.negative_evidences_, e);
1511  }
1512 
1513  // Check here if this new strong requirement disables a weak requirement which may have been used.
1514  if (!f_imdl->is_fact() && is_simulation && f_p_f_imdl->get_pred()->get_simulations_size() == 1) {
1515  uint32 wr_count;
1516  uint32 sr_count;
1517  uint32 r_count = get_requirement_count(wr_count, sr_count);
1518  if (wr_count > 0 && sr_count > 0) {
1519  auto sim = f_p_f_imdl->get_pred()->get_simulation((uint16)0);
1520 
1521  requirements_.CS_.enter();
1522  for (auto e = simulated_requirements_.positive_evidences_.begin();
1523  e != simulated_requirements_.positive_evidences_.end(); ++e) {
1524  // We only care about a weak requirement where its defeasible consequence has been used.
1525  // The weak requirement sim must be the same as the strong requirement.
1526  if ((*e).evidence_->get_pred()->has_defeasible_consequence() &&
1527  (*e).evidence_->get_pred()->has_simulation(sim)) {
1528  _Fact *_f_imdl = (*e).evidence_->get_pred()->get_target();
1529  HLPBindingMap _original(bindings_);
1530  _original.reset_fwd_timings(f_imdl);
1531  // Use logic similar to retrieve_simulated_imdl_bwd.
1532  if (_original.match_fwd_lenient(_f_imdl, f_imdl) == MATCH_SUCCESS_NEGATIVE &&
1533  f_imdl->get_cfd() >= (*e).confidence_) {
1534 
1535  // The strong requirement disables the weak.
1536  (*e).evidence_->get_pred()->get_defeasible_consequence()->invalidate();
1537 #ifdef WITH_DETAIL_OID
1538  OUTPUT_LINE(MDL_OUT, Utils::RelativeTime(Now()) << " mdl " << get_object()->get_oid() << ": fact (" <<
1539  to_string((*e).evidence_->get_detail_oid()) << ") pred fact imdl, simulated pred disabled by fact (" <<
1540  to_string(f_p_f_imdl->get_detail_oid()) << ") pred |fact imdl");
1541 #endif
1542  }
1543  }
1544  }
1545  requirements_.CS_.leave();
1546  }
1547  }
1548 
1549  // In case of a positive requirement, tell monitors they can check for chaining again, which may fire a model.
1550  if (f_imdl->is_fact()) {
1551  r_code::list<P<_GMonitor> >::const_iterator m;
1552  g_monitorsCS_.enter();
1553  for (m = r_monitors_.begin(); m != r_monitors_.end();) { // signal r-monitors.
1554 
1555  if (!(*m)->is_alive())
1556  m = r_monitors_.erase(m);
1557  else {
1558 
1559  if ((*m)->signal(f_p_f_imdl->get_pred()))
1560  m = r_monitors_.erase(m);
1561  else
1562  ++m;
1563  }
1564  }
1565  g_monitorsCS_.leave();
1566 
1567  reduce_cache<PrimaryMDLController>((Fact *)f_p_f_imdl, controller);
1568  }
1569 
1570  if (!is_simulation)
1571  secondary_->store_requirement(f_p_f_imdl, NULL, controller, chaining_was_allowed);
1572 }
1573 
1574 void PrimaryMDLController::take_input(r_exec::View *input) {
1575 
1576  if (become_invalidated())
1577  return;
1578 
1579  if (input->object_->code(0).asOpcode() == Opcodes::Fact ||
1580  input->object_->code(0).asOpcode() == Opcodes::AntiFact) // discard everything but facts and |facts.
1581  Controller::__take_input<PrimaryMDLController>(input);
1582 }
1583 
1584 void PrimaryMDLController::predict(HLPBindingMap *bm, _Fact *input, Fact *f_imdl, bool chaining_was_allowed, RequirementsPair &r_p, Fact *ground,
1585  MkRdx* ground_mk_rdx, vector<P<_Fact> >& already_predicted) {
1586 
1587  _Fact *bound_rhs = (_Fact *)bm->bind_pattern(rhs_); // fact or |fact.
1588  // TODO: Do we need a critical section?
1589  for (auto i = already_predicted.begin(); i != already_predicted.end(); ++i) {
1590  // bound_rhs confidence is a wildcard, so it will match any confidence.
1591  if (_Fact::MatchObject(bound_rhs, *i, true))
1592  // Already predicted.
1593  return;
1594  }
1595 
1596  bool is_simulation;
1597  float32 confidence;
1598  Pred *prediction = input->get_pred();
1599  if (prediction) { // the input was a prediction.
1600 
1601  is_simulation = prediction->is_simulation();
1602  if (chaining_was_allowed)
1603  confidence = prediction->get_target()->get_cfd() * get_success_rate();
1604  else
1605  return;
1606  } else {
1607 
1608  is_simulation = false;
1609  if (chaining_was_allowed)
1610  confidence = input->get_cfd() * get_success_rate();
1611  else
1612  confidence = 0;
1613  }
1614 
1615  bound_rhs->set_cfd(confidence);
1616 
1617  Pred *pred;
1618  if (is_simulation)
1619  pred = new Pred(bound_rhs, prediction, 1);
1620  else
1621  pred = new Pred(bound_rhs, 1);
1622  auto now = Now();
1623  Fact *production = new Fact(pred, now, now, 1, 1);
1624 
1625  if (prediction && !is_simulation) { // store the antecedents.
1626 
1627  pred->grounds_.push_back(input);
1628  if (ground)
1629  pred->grounds_.push_back(ground);
1630  }
1631 
1632  if (is_requirement()) {
1633 
1634  if (is_invalidated())
1635  // Another thread has invalidated this controller which clears the controllers.
1636  return;
1637  // In the Pred constructor, we already copied the simulations from prediction.
1638  MkRdx* mk_rdx = new MkRdx(f_imdl, (Code *)input, production, 1, bm);
1639  inject_notification_into_out_groups(get_host(), mk_rdx);
1640  OUTPUT_LINE(MDL_OUT, Utils::RelativeTime(Now()) << " mdl " << get_object()->get_oid() << " predict imdl -> mk.rdx " << mk_rdx->get_oid());
1641 
1642  PrimaryMDLController *c = (PrimaryMDLController *)controllers_[RHSController]; // rhs controller: in the same view.
1643  c->store_requirement(production, mk_rdx, this, chaining_was_allowed); // if not simulation, stores also in the secondary controller.
1644 #ifdef WITH_DETAIL_OID
1645  OUTPUT_LINE(MDL_OUT, Utils::RelativeTime(Now()) << " fact (" << f_imdl->get_detail_oid() << ") imdl mdl " << get_object()->get_oid() <<
1646  ": " << input->get_oid() << " -> fact (" << production->get_detail_oid() << ") pred fact (" <<
1647  bound_rhs->get_detail_oid() << ") imdl mdl " << bound_rhs->get_reference(0)->get_reference(0)->get_oid());
1648 #else
1649  OUTPUT_LINE(MDL_OUT, Utils::RelativeTime(Now()) << " mdl " << get_object()->get_oid() << ": " << input->get_oid() <<
1650  " -> fact pred fact imdl mdl " << bound_rhs->get_reference(0)->get_reference(0)->get_oid());
1651 #endif
1652  return;
1653  }
1654 
1655  if (!is_simulation) { // rdx and monitor only for predictions built from actual inputs.
1656 
1657  register_requirement(production, r_p);
1658 
1659  if (!chaining_was_allowed) { // reaching this point in the code means that the input was not a prediction.
1660 
1661  PMonitor *m = new PMonitor(this, bm, production, NULL, false); // the model will not be rated in case of a failure; the requirements will be rated in both cases (if their own chaining was allowed, else only in case of success and recurse).
1662  MDLController::add_monitor(m);
1663  } else { // try to inject the prediction: if cfd too low, the prediction is not injected.
1664 
1665  auto before = bound_rhs->get_before();
1666  if (before <= now) // can happen if the input comes from the past and the predicted time is still in the past.
1667  return;
1668  if (prediction) { // no rdx nor monitoring if the input was a prediction; case of a reuse: f_imdl becomes f->p->f_imdl.
1669 
1670  Fact *f_pred_f_imdl = new Fact(new Pred(f_imdl, 1), now, now, 1, 1);
1671  if (!inject_prediction(production, f_pred_f_imdl, confidence, before - now, NULL))
1672  return;
1673  already_predicted.push_back(bound_rhs);
1674  string f_imdl_info;
1675 #ifdef WITH_DETAIL_OID
1676  f_imdl_info = " fact (" + to_string(f_imdl->get_detail_oid()) + ") imdl";
1677 #endif
1678  OUTPUT_LINE(MDL_OUT, Utils::RelativeTime(Now()) << f_imdl_info << " mdl " <<
1679  get_object()->get_oid() << ": " << input->get_oid() << " -> fact " << production->get_oid() <<
1680  " pred fact mk.val VALUE " << bound_rhs->get_reference(0)->trace_string(MK_VAL_VALUE));
1681  } else {
1682 
1683  Code *mk_rdx;
1684  if (ground)
1685  mk_rdx = new MkRdx(f_imdl, (Code *)input, ground_mk_rdx, production, 1, bm);
1686  else
1687  mk_rdx = new MkRdx(f_imdl, (Code *)input, production, 1, bm);
1688  bool rate_failures = inject_prediction(production, f_imdl, confidence, before - now, mk_rdx);
1689  PMonitor *m = new PMonitor(this, bm, production, mk_rdx, rate_failures); // not-injected predictions are monitored for rating the model that produced them (successes only).
1690  MDLController::add_monitor(m);
1691  Group *secondary_host = secondary_->get_view()->get_host(); // inject f_imdl in secondary group.
1692  View *view = new View(View::SYNC_ONCE, now, confidence, 1, get_view()->get_host(), secondary_host, f_imdl); // SYNC_ONCE,res=resilience.
1693  _Mem::Get()->inject(view);
1694  OUTPUT_LINE(MDL_OUT, Utils::RelativeTime(Now()) << " mdl " << get_object()->get_oid() << " predict -> mk.rdx " << mk_rdx->get_oid());
1695  string f_imdl_info;
1696 #ifdef WITH_DETAIL_OID
1697  f_imdl_info = "(" + to_string(f_imdl->get_detail_oid()) + ")";
1698 #endif
1699  OUTPUT_LINE(MDL_OUT, Utils::RelativeTime(Now()) << " fact " << f_imdl->get_oid() << f_imdl_info << " imdl mdl " <<
1700  get_object()->get_oid() << ": " << input->get_oid() << " -> fact " << production->get_oid() <<
1701  " pred fact mk.val VALUE " << bound_rhs->get_reference(0)->trace_string(MK_VAL_VALUE));
1702  }
1703  }
1704  } else { // no monitoring for simulated predictions.
1705 
1706  if (ground) {
1707  // Check if there could be a strong requirement in the future that could defeat the ground.
1708  uint32 wr_count;
1709  uint32 sr_count;
1710  get_requirement_count(wr_count, sr_count);
1711  if (wr_count > 0 && sr_count > 0)
1712  // Attach a DefeasibleValidity object to the prediction so that it can be invalidated later by a strong requirement.
1713  pred->defeasible_validities_.insert(ground->get_pred()->get_defeasible_consequence());
1714  }
1715 
1716  // In the Pred constructor, we already copied the simulations from prediction.
1717  if (!HLPController::inject_prediction(production, confidence)) // inject a simulated prediction in the primary group.
1718  return;
1719  already_predicted.push_back(bound_rhs);
1720  string ground_info;
1721 #ifdef WITH_DETAIL_OID
1722  if (ground)
1723  ground_info = ", using req (" + to_string(ground->get_detail_oid()) + ")";
1724 #endif
1725  OUTPUT_LINE(MDL_OUT, Utils::RelativeTime(Now()) << " mdl " << get_object()->get_oid() << ": fact " <<
1726  input->get_oid() << " pred -> fact " << production->get_oid() << " simulated pred" << ground_info);
1727 
1728  if (is_cmd() || is_reuse()) {
1729  // Inject the predicted imdl, in case other models are reusing this model.
1730  Fact *f_pred_f_imdl = new Fact(new Pred(f_imdl, prediction, 1), now, now, 1, 1);
1731  if (!HLPController::inject_prediction(f_pred_f_imdl, confidence))
1732  return;
1733  OUTPUT_LINE(MDL_OUT, Utils::RelativeTime(Now()) << " mdl " << get_object()->get_oid() << ": fact " <<
1734  input->get_oid() << " pred -> fact " << f_pred_f_imdl->get_oid() << " simulated pred fact imdl" << ground_info);
1735  }
1736  }
1737 }
1738 
1739 bool PrimaryMDLController::inject_prediction(Fact *prediction, Fact *f_imdl, float32 confidence, Timestamp::duration time_to_live, Code *mk_rdx) const { // prediction: f->pred->f->target.
1740 
1741  auto now = Now();
1742  Group *primary_host = get_host();
1743  float32 sln_thr = primary_host->code(GRP_SLN_THR).asFloat();
1744  if (confidence > sln_thr) { // do not inject if cfd is too low.
1745 
1746  int32 resilience = _Mem::Get()->get_goal_pred_success_res(primary_host, now, time_to_live);
1747  View *view = new View(View::SYNC_ONCE, now, confidence, resilience, primary_host, primary_host, prediction); // SYNC_ONCE,res=resilience.
1748  _Mem::Get()->inject(view);
1749 
1750  view = new View(View::SYNC_ONCE, now, 1, 1, primary_host, primary_host, f_imdl); // SYNC_ONCE,res=resilience.
1751  _Mem::Get()->inject(view);
1752 
1753  if (mk_rdx)
1754  inject_notification_into_out_groups(primary_host, mk_rdx);
1755  return true;
1756  } else
1757  return false;
1758 }
1759 
1760 void PrimaryMDLController::reduce(r_exec::View *input) { // no lock.
1761 
1762  if (is_orphan())
1763  return;
1764 
1765  if (input->object_->is_invalidated())
1766  return;
1767 
1768  r_code::list<P<Code> >::const_iterator a;
1769  assumptionsCS_.enter();
1770  for (a = assumptions_.begin(); a != assumptions_.end();) { // ignore home-made assumptions and perform some garbage collection.
1771 
1772  if ((*a)->is_invalidated()) // garbage collection.
1773  a = assumptions_.erase(a);
1774  else if (((Code *)*a) == input->object_) {
1775 
1776  a = assumptions_.erase(a);
1777  assumptionsCS_.leave();
1778  return;
1779  } else
1780  ++a;
1781  }
1782  assumptionsCS_.leave();
1783 
1784  Goal *goal = ((_Fact *)input->object_)->get_goal();
1785  if (goal && goal->is_self_goal() && !goal->is_drive()) {
1786 
1787  _Fact *goal_target = goal->get_target(); // goal_target is f->object.
1788  float32 confidence = get_success_rate() * goal_target->get_cfd(); // reading STRONG_REQUIREMENT is atomic.
1789  Code *host = get_host();
1790  if (confidence <= host->code(GRP_SLN_THR).asFloat()) // cfd is too low for any sub-goal to be injected.
1791  return;
1792 
1793  P<HLPBindingMap> bm = new HLPBindingMap(bindings_);
1794  bm->reset_bwd_timings(goal_target);
1795  bool opposite = false;
1796  MatchResult match_result = bm->match_bwd_lenient(goal_target, rhs_);
1797  switch (match_result) {
1798  case MATCH_SUCCESS_NEGATIVE:
1799  opposite = true;
1800  case MATCH_SUCCESS_POSITIVE:
1801  abduce(bm, (Fact *)input->object_, opposite, confidence);
1802  break;
1803  default: // no match; however, goal_target may be f->imdl, i.e. case of a reuse of the model, i.e. the goal is for the model to make a prediction: this translates into making a sub-goal from the lhs.
1804  if (!goal->is_requirement() && goal_target->is_fact()) { // models like imdl -> |rhs or |imdl -> rhs are not allowed.
1805 
1806  Code *imdl = goal_target->get_reference(0);
1807  if (imdl->code(0).asOpcode() == Opcodes::IMdl && imdl->get_reference(0) == get_object()) { // in that case, get the bm from the imdl, ignore the bwd guards, bind the rhs and inject.
1808 
1809  bm = new HLPBindingMap(bindings_);
1810  bm->reset_bwd_timings(goal_target);
1811  bm->init_from_f_ihlp(goal_target);
1812  // JTNote: opposite is always false.
1813  abduce(bm, (Fact *)input->object_, opposite, confidence);
1814  }
1815  }
1816  break;
1817  }
1818  } else {
1819 
1820  PrimaryMDLOverlay o(this, bindings_);
1821  bool match = o.reduce((_Fact *)input->object_, NULL, NULL);
1822  bool matched_p_monitor = false;
1823  bool matched_g_monitor = false;
1824  if (!match)
1825  matched_p_monitor = monitor_predictions((_Fact*)input->object_);
1826  if (!matched_p_monitor)
1827  // Monitor goals even if PrimaryMDLOverlay reduce sets match true, but not if a PMonitor matches.
1828  matched_g_monitor = monitor_goals((_Fact*)input->object_);
1829  if (!match && !matched_p_monitor && !matched_g_monitor)
1830  assume((_Fact *)input->object_);
1831 
1832  check_last_match_time(match);
1833  }
1834 }
1835 
1836 void PrimaryMDLController::debug(View *input) {
1837 }
1838 
1839 void PrimaryMDLController::reduce_batch(Fact *f_p_f_imdl, MDLController *controller) {
1840 
1841  if (is_orphan())
1842  return;
1843 
1844  reduce_cache<EvidenceEntry>(&evidences_, f_p_f_imdl, controller);
1845  reduce_cache<PredictedEvidenceEntry>(&predicted_evidences_, f_p_f_imdl, controller);
1846 }
1847 
1848 void PrimaryMDLController::abduce(HLPBindingMap *bm, Fact *super_goal, bool opposite, float32 confidence) { // goal is f->g->f->object or f->g->|f->object; called concurrently by redcue() and _GMonitor::update().
1849 
1850  if (!abduction_allowed(bm))
1851  return;
1852 
1853  P<Fact> f_imdl = get_f_ihlp(bm, false);
1854  Sim *sim = super_goal->get_goal()->get_sim();
1855  microseconds sim_thz(0);
1856  if (sim)
1857  sim_thz = sim->get_thz(); // 0 if super-goal had no time for simulation.
1858  auto min_sim_thz = _Mem::Get()->get_min_sim_time_horizon() / 2; // time allowance for the simulated predictions to flow upward.
1859 
1860  Sim *sub_sim;
1861  if (sim_thz > min_sim_thz) {
1862 
1863  sim_thz -= min_sim_thz;
1864 
1865  auto now = Now();
1866  switch (sim->get_mode()) {
1867  case SIM_ROOT:
1868  sub_sim = new Sim(opposite ? SIM_MANDATORY : SIM_OPTIONAL, sim_thz, super_goal, opposite, sim->root_, 1, this, confidence, now + sim_thz);
1869  break;
1870  case SIM_OPTIONAL:
1871  sub_sim = new Sim(opposite ? SIM_MANDATORY : SIM_OPTIONAL, sim_thz, super_goal, opposite, sim->root_, 1, this, sim->get_solution_cfd(), sim->get_solution_before());
1872  break;
1873  case SIM_MANDATORY:
1874  if (opposite)
1875  // Already switched due to an opposite match. We don't yet support switching again.
1876  return;
1877  sub_sim = new Sim(sim->get_mode(), sim_thz, super_goal, opposite, sim->root_, 1, this, sim->get_solution_cfd(), sim->get_solution_before());
1878  break;
1879  }
1880 
1881  Fact *ground;
1882  Fact *strong_requirement_ground;
1883  P<HLPBindingMap> save_bm = new HLPBindingMap(bm);
1884  P<Code> save_imdl = f_imdl->get_reference(0);
1885  ChainingStatus c_s = retrieve_imdl_bwd(bm, f_imdl, ground, strong_requirement_ground);
1886  switch (c_s) {
1887  case WEAK_REQUIREMENT_ENABLED:
1888  f_imdl->get_reference(0)->code(I_HLP_WEAK_REQUIREMENT_ENABLED) = Atom::Boolean(true);
1889  case NO_REQUIREMENT:
1890  if (sub_sim->get_mode() == SIM_ROOT)
1891  abduce_lhs(bm, super_goal, f_imdl, opposite, confidence, sub_sim, ground, true);
1892  else {
1893  abduce_simulated_lhs(bm, super_goal, f_imdl, opposite, confidence, sub_sim, ground);
1894  if (is_cmd()) {
1895  // We called abduce_simulated_lhs because there is a non-simulated requirement which can instantiate the model
1896  // with a simulated predicted command, but simulated forward chaining may fail. Therefore we also call
1897  // abduce_simulated_imdl which adds an SRMonitor for a goal to instantiate the model (the same as below),
1898  // so that if another simulation branch makes a predicted requirement it can simulate instantiating the model.
1899  // Used the saved state of the imdl before retrieve_imdl_bwd bound variables from the requirement.
1900  save_imdl->code(I_HLP_WEAK_REQUIREMENT_ENABLED) = Atom::Boolean(false);
1901  abduce_simulated_imdl(save_bm, super_goal,
1902  new Fact(save_imdl, f_imdl->get_after(), f_imdl->get_before(), confidence, 1), opposite, confidence, sub_sim);
1903  }
1904  }
1905  break;
1906  default: // WEAK_REQUIREMENT_DISABLED, STRONG_REQUIREMENT_NO_WEAK_REQUIREMENT or STRONG_REQUIREMENT_DISABLED_WEAK_REQUIREMENT.
1907  {
1908  // Note: The sim is from simulated backward chaining. retrieve_simulated_imdl_bwd checks for simulated
1909  // requirements, but these are produced in simulated forward chaining which hasn't started yet in this
1910  // simulation. Because, there are no simulated requirements, retrieve_simulated_imdl_bwd returns right away
1911  // without using sim. If the logic is changed so that retrieve_simulated_imdl_bwd does use sim, then we
1912  // need a flag to check for a requirement from any Sim with the same root (not the exact same forward-chaining Sim).
1913  Fact *sim_ground;
1914  Fact *sim_strong_requirement_ground;
1915  ChainingStatus sim_c_s = retrieve_simulated_imdl_bwd(bm, f_imdl, sim, sim_ground, sim_strong_requirement_ground);
1916  if (c_s == STRONG_REQUIREMENT_NO_WEAK_REQUIREMENT && sim_c_s == NO_REQUIREMENT)
1917  // There is no simulated weak requirement to override the non-simulated strong requirement.
1918  sim_c_s = STRONG_REQUIREMENT_NO_WEAK_REQUIREMENT;
1919  switch (sim_c_s) {
1920  case WEAK_REQUIREMENT_ENABLED:
1921  f_imdl->get_reference(0)->code(I_HLP_WEAK_REQUIREMENT_ENABLED) = Atom::Boolean(true);
1922  case NO_REQUIREMENT:
1923  if (sub_sim->get_mode() == SIM_ROOT)
1924  abduce_lhs(bm, super_goal, f_imdl, opposite, confidence, sub_sim, NULL, true);
1925  else
1926  abduce_simulated_lhs(bm, super_goal, f_imdl, opposite, confidence, sub_sim, sim_ground);
1927  break;
1928  default: // WEAK_REQUIREMENT_DISABLED, STRONG_REQUIREMENT_NO_WEAK_REQUIREMENT or STRONG_REQUIREMENT_DISABLED_WEAK_REQUIREMENT.
1929 #ifdef WITH_DETAIL_OID
1930  if (c_s == STRONG_REQUIREMENT_DISABLED_WEAK_REQUIREMENT && sim_c_s == WEAK_REQUIREMENT_DISABLED)
1931  // The call to retrieve_imdl_bwd shows that a non-simulated strong requirement disabled a non-simulated weak requrement.
1932  // (There may be other combinations of c_s and sim_c_s which apply, but we're sure about this one.)
1933  OUTPUT_LINE(MDL_OUT, Utils::RelativeTime(Now()) << " mdl " << get_object()->get_oid() << ": fact (" <<
1934  to_string(ground->get_detail_oid()) << ") pred fact imdl, from goal req " << super_goal->get_oid() <<
1935  ", pred disabled by fact (" << to_string(strong_requirement_ground->get_detail_oid()) <<
1936  ") pred |fact imdl");
1937 #endif
1938  sub_sim->is_requirement_ = true;
1939  if (sub_sim->get_mode() == SIM_ROOT)
1940  abduce_imdl(bm, super_goal, f_imdl, opposite, confidence, sub_sim);
1941  else
1942  abduce_simulated_imdl(bm, super_goal, f_imdl, opposite, confidence, sub_sim);
1943  break;
1944  }
1945  break;
1946  }
1947  }
1948  } else { // no time to simulate or allow_simulation==false.
1949 
1950  Fact *ground;
1951  Fact *strong_requirement_ground;
1952  SimMode mode = SIM_ROOT;
1953  if (sim)
1954  mode = sim->get_mode();
1955  switch (mode) {
1956  case SIM_ROOT:
1957  switch (retrieve_imdl_bwd(bm, f_imdl, ground, strong_requirement_ground)) {
1958  case WEAK_REQUIREMENT_ENABLED:
1959  f_imdl->get_reference(0)->code(I_HLP_WEAK_REQUIREMENT_ENABLED) = Atom::Boolean(true);
1960  case NO_REQUIREMENT:
1961  sub_sim = new Sim(SIM_ROOT, seconds(0), super_goal, opposite, this, 1);
1962  abduce_lhs(bm, super_goal, f_imdl, opposite, confidence, sub_sim, ground, false);
1963  break;
1964  default: // WEAK_REQUIREMENT_DISABLED, STRONG_REQUIREMENT_NO_WEAK_REQUIREMENT or STRONG_REQUIREMENT_DISABLED_WEAK_REQUIREMENT.
1965  sub_sim = new Sim(SIM_ROOT, seconds(0), super_goal, opposite, this, 1);
1966  sub_sim->is_requirement_ = true;
1967  abduce_imdl(bm, super_goal, f_imdl, opposite, confidence, sub_sim);
1968  break;
1969  }
1970  break;
1971  case SIM_OPTIONAL:
1972  case SIM_MANDATORY: // stop the simulation branch.
1973  predict_simulated_lhs(bm, opposite, confidence, sim);
1974  break;
1975  }
1976  }
1977 }
1978 
1979 void PrimaryMDLController::abduce_no_simulation(Fact *f_super_goal, bool opposite, float32 confidence, _Fact* f_p_f_success)
1980 {
1981  // Imitate PrimaryMDLController::reduce to set up the binding map.
1982  Goal *super_goal = f_super_goal->get_goal();
1983  _Fact *f_goal_target = super_goal->get_target();
1984  P<HLPBindingMap> bm = new HLPBindingMap(bindings_);
1985  bm->reset_bwd_timings(f_goal_target);
1986  MatchResult match_result = bm->match_bwd_lenient(f_goal_target, get_rhs());
1987  if (!(match_result == MATCH_SUCCESS_NEGATIVE || match_result == MATCH_SUCCESS_POSITIVE)) {
1988  // no match; however, goal_target may be f->imdl, i.e. case of a reuse of the model, i.e. the goal is for the model to make a prediction.
1989  Code *imdl = f_goal_target->get_reference(0);
1990  if (imdl->code(0).asOpcode() == Opcodes::IMdl && imdl->get_reference(0) == get_object()) {
1991  // in that case, get the bm from the imdl, ignore the bwd guards.
1992  bm = new HLPBindingMap(bindings_);
1993  bm->reset_bwd_timings(f_goal_target);
1994  bm->init_from_f_ihlp(f_goal_target);
1995  }
1996  else
1997  return;
1998  }
1999 
2000  // Make a copy of f_super_goal with a separate identity. Use a Sim with 0 time horizon so we don't simulate.
2001  Goal* super_goal_copy = new Goal
2002  (f_goal_target, super_goal->get_actor(), new Sim(SIM_ROOT, seconds(0), super_goal->get_sim()->get_f_super_goal(), false, this, 1),
2003  super_goal->get_psln_thr());
2004  P<Fact> f_super_goal_copy = new Fact(
2005  super_goal_copy, f_super_goal->get_after(), f_super_goal->get_before(), f_super_goal->get_cfd(),
2006  f_super_goal->get_psln_thr());
2007 #ifdef WITH_DETAIL_OID
2008  if (f_p_f_success)
2009  OUTPUT_LINE(MDL_OUT, Utils::RelativeTime(Now()) << " sim commit: fact " << f_p_f_success->get_oid() <<
2010  " pred fact success -> fact (" << f_super_goal_copy->get_detail_oid() << ") goal");
2011 #endif
2012 
2013  abduce(bm, f_super_goal_copy, opposite, confidence);
2014 }
2015 
2016 void PrimaryMDLController::abduce_lhs(HLPBindingMap *bm, Fact *super_goal, Fact *f_imdl, bool opposite, float32 confidence, Sim *sim, Fact *ground, bool set_before) { // goal is f->g->f->object or f->g->|f->object; called concurrently by reduce() and _GMonitor::update().
2017 
2018  if (evaluate_bwd_guards(bm, true)) { // bm may be updated.
2019 
2020  P<_Fact> bound_lhs = (_Fact *)bm->bind_pattern(get_lhs());
2021  if (opposite)
2022  bound_lhs->set_opposite();
2023  bound_lhs->set_cfd(confidence);
2024 
2025  _Fact *evidence;
2026  switch (check_evidences(bound_lhs, evidence)) {
2027  case MATCH_SUCCESS_POSITIVE: // goal target is already known: abort.
2028  break;
2029  case MATCH_SUCCESS_NEGATIVE: // a counter evidence is already known: abort.
2030  break;
2031  case MATCH_FAILURE: {
2032 
2033  f_imdl->set_reference(0, bm->bind_pattern(f_imdl->get_reference(0))); // valuate f_imdl from updated bm.
2034 
2035  switch (check_predicted_evidences(bound_lhs, evidence)) {
2036  case MATCH_SUCCESS_POSITIVE:
2037  break;
2038  case MATCH_SUCCESS_NEGATIVE:
2039  case MATCH_FAILURE:
2040  evidence = NULL;
2041  break;
2042  }
2043 
2044  Goal *sub_goal = new Goal(bound_lhs, super_goal->get_goal()->get_actor(), sim, 1);
2045  sub_goal->ground_ = ground;
2046  if (set_before)
2047  sim->set_solution_before(bound_lhs->get_before());
2048 
2049  auto now = Now();
2050  Fact *f_sub_goal = new Fact(sub_goal, now, now, 1, 1);
2051 
2052  add_g_monitor(new GMonitor(this, bm, bound_lhs->get_before(), Timestamp(seconds(0)), f_sub_goal, f_imdl, evidence));
2053 
2054  if (!evidence) {
2055  inject_goal(bm, f_sub_goal, f_imdl);
2056  OUTPUT_LINE(MDL_OUT, Utils::RelativeTime(Now()) << " mdl " << get_object()->get_oid() << " -> fact " << f_sub_goal->get_oid() <<
2057  " goal [" << Utils::RelativeTime(sub_goal->get_target()->get_after()) << "," << Utils::RelativeTime(sub_goal->get_target()->get_before()) << "]");
2058  }
2059  break;
2060  }
2061  }
2062  }
2063 }
2064 
2065 void PrimaryMDLController::abduce_imdl(HLPBindingMap *bm, Fact *super_goal, Fact *f_imdl, bool opposite, float32 confidence, Sim *sim) { // goal is f->g->f->object or f->g->|f->object; called concurrently by redcue() and _GMonitor::update().
2066 
2067  // Use the timestamps in the template parameters from the prerequisite model.
2068  // This is to make it symmetric with the timestamp in the forward chaining requirement.
2069  Timestamp f_imdl_after, f_imdl_before;
2070  if (get_template_timings(bm, f_imdl_after, f_imdl_before)) {
2071  Utils::SetTimestamp<Code>(f_imdl, FACT_AFTER, f_imdl_after);
2072  Utils::SetTimestamp<Code>(f_imdl, FACT_BEFORE, f_imdl_before);
2073  // For an imdl, also make the binding map fwd timing variables match the fact.
2074  bm->reset_fwd_timings(f_imdl);
2075  }
2076  f_imdl->set_cfd(confidence);
2077 
2078  Goal *sub_goal = new Goal(f_imdl, super_goal->get_goal()->get_actor(), sim, 1);
2079 
2080  auto now = Now();
2081  Fact *f_sub_goal = new Fact(sub_goal, now, now, 1, 1);
2082  add_r_monitor(new RMonitor(this, bm, super_goal->get_goal()->get_target()->get_before(), now + sim->get_thz(), f_sub_goal, f_imdl)); // the monitor will wait until the deadline of the super-goal.
2083  inject_goal(bm, f_sub_goal, f_imdl);
2084  string f_imdl_detail_info;
2085 #ifdef WITH_DETAIL_OID
2086  f_imdl_detail_info = "(" + to_string(f_imdl->get_detail_oid()) + ")";
2087 #endif
2088  OUTPUT_LINE(MDL_OUT, Utils::RelativeTime(Now()) << " " << get_object()->get_oid() << " -> fact " << f_sub_goal->get_oid() << " goal fact " <<
2089  f_imdl->get_oid() << f_imdl_detail_info << " imdl[" << f_imdl->get_reference(0)->get_reference(0)->get_oid() << "][" <<
2090  Utils::RelativeTime(sub_goal->get_target()->get_after()) << "," << Utils::RelativeTime(sub_goal->get_target()->get_before()) << "]");
2091 }
2092 
2093 // goal is f->g->f->object or f->g->|f->object; called concurrently by redcue() and _GMonitor::update().
2094 _Fact* PrimaryMDLController::abduce_simulated_lhs(HLPBindingMap *bm, Fact *super_goal, Fact *f_imdl, bool opposite, float32 confidence,
2095  Sim *sim, Fact *ground, Fact* goal_requirement) {
2096 
2097  _Fact* injected_lhs = NULL;
2098  if (evaluate_bwd_guards(bm, true)) { // bm may be updated.
2099 
2100  P<_Fact> bound_lhs = (_Fact *)bm->bind_pattern(get_lhs());
2101  if (opposite)
2102  bound_lhs->set_opposite();
2103  bound_lhs->set_cfd(confidence);
2104 
2105  _Fact *evidence;
2106  switch (check_evidences(bound_lhs, evidence)) {
2107  case MATCH_SUCCESS_POSITIVE: // an evidence is already known: stop the simulation.
2108  register_simulated_goal_outcome(super_goal, true, evidence);
2109  break;
2110  case MATCH_SUCCESS_NEGATIVE: // a counter evidence is already known: stop the simulation.
2111  register_simulated_goal_outcome(super_goal, false, evidence);
2112  break;
2113  case MATCH_FAILURE:
2114  switch (check_predicted_evidences(bound_lhs, evidence)) {
2115  case MATCH_SUCCESS_POSITIVE: // a predicted evidence is already known: stop the simulation.
2116  register_simulated_goal_outcome(super_goal, true, evidence);
2117  break;
2118  case MATCH_SUCCESS_NEGATIVE:
2119  register_simulated_goal_outcome(super_goal, false, evidence);
2120  break;
2121  case MATCH_FAILURE: {
2122 
2123  auto now = Now();
2124  f_imdl->set_reference(0, bm->bind_pattern(f_imdl->get_reference(0))); // valuate f_imdl from updated bm.
2125 
2126  if (!sim) {
2127  // This was called from check_simulated_imdl. Keep simulating forward. Don't loop by abducing the LHS as a goal again.
2128  // TODO: Handle the case when there are other than one Sim in the prediction.
2129  Pred* ground_pred = ground->get_pred();
2130  // Copy all the Sims from ground.
2131  Pred *pred = new Pred(bound_lhs, ground_pred, 1);
2132  Fact* fact_pred_bound_lhs = new Fact(pred, now, now, 1, 1);
2133  if (ground_pred && ground_pred->get_simulations_size() == 1) {
2134  // Check if a call to signal already caused this same LHS to be abduced with the same conditions, in this Sim by this controller.
2135  vector<P<_Fact> >& sim_already_signalled = ground_pred->get_simulation((uint16)0)->already_signalled_;
2136  bool found = false;
2137  // TODO: Do we need a critical section for this loop?
2138  for (auto signalled = sim_already_signalled.begin(); signalled != sim_already_signalled.end(); ++signalled) {
2139  // TODO: Check if signalled is invalidated?
2140  Pred* signalled_pred = (*signalled)->get_pred();
2141  if (_Fact::MatchObject(bound_lhs, signalled_pred->get_target())) {
2142  // Use the existing command but remove DefeasibleValidities which are not in the new command. This effectively
2143  // sets the defeasible_validities_ of the existing command to the intersection of it and the
2144  // defeasible_validities_ of the new command, so that a command will survive unless it would be
2145  // defeated in both cases.
2146  for (auto d = signalled_pred->defeasible_validities_.begin();
2147  d != signalled_pred->defeasible_validities_.end();) {
2148  if (ground_pred->defeasible_validities_.find(*d) == ground_pred->defeasible_validities_.end())
2149  d = signalled_pred->defeasible_validities_.erase(d);
2150  else
2151  ++d;
2152  }
2153  found = true;
2154  break;
2155  }
2156  }
2157 
2158  if (found)
2159  // Don't signal again.
2160  break;
2161  // Save for checking later and continue.
2162  sim_already_signalled.push_back(fact_pred_bound_lhs);
2163  }
2164 
2165  inject_simulation(fact_pred_bound_lhs, now);
2166  injected_lhs = fact_pred_bound_lhs;
2167 
2168  string ground_info;
2169 #ifdef WITH_DETAIL_OID
2170  ground_info = " (" + to_string(ground->get_detail_oid()) + ")";
2171 #endif
2172  string goal_requirement_info = "";
2173  if (goal_requirement)
2174  goal_requirement_info = ", from goal req " + to_string(goal_requirement->get_oid());
2175  // The ground came from matching a requirement.
2176  OUTPUT_LINE(MDL_OUT, Utils::RelativeTime(now) << " mdl " << get_object()->get_oid() << ": fact" <<
2177  ground_info << " pred fact imdl -> fact " << fact_pred_bound_lhs->get_oid() << " simulated pred" <<
2178  goal_requirement_info);
2179  break;
2180  }
2181 
2182  // TODO: If we have reached the time horizon for simulated backward chaining, start forward chaining.
2183 
2184  if (is_cmd()) {
2185  // The LHS is a command, so stop the backward chaining in this branch and schedule to start forward chaining to predict.
2186  // Create a new simulation which will be carried throughout forward chaining until (if) we reach the drive goal.
2187  // Use this as the simulation's solution_controller so that, if we commit to this solution, then we
2188  // will abduce the LHS to execute the command.
2189  // TODO: If we passed the time horizon for simulated backward chaining, stop all backward chaining and start forward.
2190  auto sub_sim = new Sim(
2191  sim->get_mode(), sim->get_thz(), super_goal, opposite, sim->root_, 1, this, sim->get_solution_cfd(),
2192  sim->get_solution_before());
2193  Pred *pred_bound_lhs = new Pred(bound_lhs, sub_sim, 1);
2194  auto forward_simulation_time = max(now, sim->get_solution_before() - sim->get_thz() / 2);
2195  Fact* f_pred_bound_lhs = new Fact(pred_bound_lhs, forward_simulation_time, forward_simulation_time, 1, 1);
2196  inject_simulation(f_pred_bound_lhs, forward_simulation_time);
2197  injected_lhs = f_pred_bound_lhs;
2198  string f_pred_bound_lhs_info;
2199  string ground_info;
2200 #ifdef WITH_DETAIL_OID
2201  f_pred_bound_lhs_info = " (" + to_string(f_pred_bound_lhs->get_detail_oid()) + ")";
2202  if (ground)
2203  ground_info = ", using req (" + to_string(ground->get_detail_oid()) + ")";
2204 #endif
2205  OUTPUT_LINE(MDL_OUT, Utils::RelativeTime(now) << " mdl " << get_object()->get_oid() << ": fact " <<
2206  super_goal->get_oid() << " super_goal -> fact" << f_pred_bound_lhs_info << " simulated pred start" <<
2207  ground_info << ", ijt " << Utils::RelativeTime(forward_simulation_time));
2208  break;
2209  }
2210 
2211  if (!sim->register_goal_target(bound_lhs))
2212  // We are already simulating from this goal, so abort to avoid loops.
2213  break;
2214 
2215  Goal *sub_goal = new Goal(bound_lhs, super_goal->get_goal()->get_actor(), sim, 1);
2216 
2217  Fact *f_sub_goal = new Fact(sub_goal, now, now, 1, 1);
2218 
2219  add_g_monitor(new SGMonitor(this, bm, now + sim->get_thz(), f_sub_goal, f_imdl));
2220  inject_simulation(f_sub_goal, now);
2221  injected_lhs = f_sub_goal;
2222  OUTPUT_LINE(MDL_OUT, Utils::RelativeTime(now) << " mdl " << get_object()->get_oid() << ": fact " <<
2223  super_goal->get_oid() << " super_goal -> fact " << f_sub_goal->get_oid() << " simulated goal");
2224  break;
2225  }
2226  }
2227  break;
2228  }
2229  }
2230 
2231  return injected_lhs;
2232 }
2233 
2234 void PrimaryMDLController::abduce_simulated_imdl(HLPBindingMap *bm, Fact *super_goal, Fact *f_imdl, bool opposite, float32 confidence, Sim *sim) { // goal is f->g->f->object or f->g->|f->object; called concurrently by redcue() and _GMonitor::update().
2235 
2236  if (!sim->is_requirement_ && !sim->register_goal_target(f_imdl))
2237  // We are already simulating from this goal, so abort to avoid loops.
2238  return;
2239 
2240  // Use the timestamps in the template parameters from the prerequisite model.
2241  // This is to make it symmetric with the timestamp in the forward chaining requirement.
2242  Timestamp f_imdl_after, f_imdl_before;
2243  if (get_template_timings(bm, f_imdl_after, f_imdl_before)) {
2244  Utils::SetTimestamp<Code>(f_imdl, FACT_AFTER, f_imdl_after);
2245  Utils::SetTimestamp<Code>(f_imdl, FACT_BEFORE, f_imdl_before);
2246  // For an imdl, also make the binding map fwd timing variables match the fact.
2247  bm->reset_fwd_timings(f_imdl);
2248  }
2249  f_imdl->set_cfd(confidence);
2250 
2251  Goal *sub_goal = new Goal(f_imdl, super_goal->get_goal()->get_actor(), sim, 1);
2252 
2253  auto now = Now();
2254  Fact *f_sub_goal = new Fact(sub_goal, now, now, 1, 1);
2255  add_r_monitor(new SRMonitor(this, bm, now + sim->get_thz(), f_sub_goal, f_imdl));
2256  inject_simulation(f_sub_goal, now);
2257  OUTPUT_LINE(MDL_OUT, Utils::RelativeTime(Now()) << " mdl " << get_object()->get_oid() << ": fact " <<
2258  super_goal->get_oid() << " super_goal -> fact " << f_sub_goal->get_oid() << " simulated goal");
2259 }
2260 
2261 bool PrimaryMDLController::check_imdl(Fact *goal, HLPBindingMap *bm) { // goal is f->g->f->imdl; called by r-monitors.
2262 
2263  Goal *g = goal->get_goal();
2264  Fact *f_imdl = (Fact *)g->get_target();
2265 
2266  Sim *sim = g->get_sim();
2267  Fact *ground;
2268  Fact *strong_requirement_ground;
2269  switch (retrieve_imdl_bwd(bm, f_imdl, ground, strong_requirement_ground)) {
2270  case WEAK_REQUIREMENT_ENABLED:
2271  f_imdl->get_reference(0)->code(I_HLP_WEAK_REQUIREMENT_ENABLED) = Atom::Boolean(true);
2272  case NO_REQUIREMENT:
2273  if (evaluate_bwd_guards(bm, true)) { // bm may be updated.
2274  // JTNote: This changes an object which is already injected.
2275  f_imdl->set_reference(0, bm->bind_pattern(f_imdl->get_reference(0))); // valuate f_imdl from updated bm.
2276  abduce_lhs(bm, sim->get_f_super_goal(), f_imdl, sim->get_opposite(), f_imdl->get_cfd(), new Sim(SIM_ROOT, seconds(0), sim->get_f_super_goal(), sim->get_opposite(), this, 1), ground, false);
2277  return true;
2278  }
2279  return false;
2280  default: // WEAK_REQUIREMENT_DISABLED, STRONG_REQUIREMENT_NO_WEAK_REQUIREMENT or STRONG_REQUIREMENT_DISABLED_WEAK_REQUIREMENT.
2281  return false;
2282  }
2283 }
2284 
2285 // goal is f->g->f->imdl; called by sr-monitors.
2287 
2288  Goal *g = goal->get_goal();
2289  Fact *f_imdl = (Fact *)g->get_target();
2290  ChainingStatus c_s;
2291  Fact *ground;
2292  Fact *strong_requirement_ground;
2293  if (prediction_sim)
2294  c_s = retrieve_simulated_imdl_bwd(bm, f_imdl, prediction_sim, ground, strong_requirement_ground);
2295  else
2296  c_s = retrieve_imdl_bwd(bm, f_imdl, ground, strong_requirement_ground);
2297 
2298  Sim *sim = g->get_sim();
2299  switch (c_s) {
2300  case WEAK_REQUIREMENT_ENABLED:
2301  f_imdl->get_reference(0)->code(I_HLP_WEAK_REQUIREMENT_ENABLED) = Atom::Boolean(true);
2302  case NO_REQUIREMENT:
2303  if (evaluate_bwd_guards(bm, true)) { // bm may be updated.
2304  // valuate f_imdl from updated bm into a copy.
2305  P<Fact> f_imdl_copy = new Fact(
2306  bm->bind_pattern(f_imdl->get_reference(0)), f_imdl->get_after(), f_imdl->get_before(),
2307  f_imdl->get_cfd(), f_imdl->get_psln_thr());
2308  // If root is provided, pass NULL as the sim to use the Sim in ground for forward chaining.
2309  _Fact* injected_lhs = abduce_simulated_lhs(bm, sim->get_f_super_goal(), f_imdl_copy, sim->get_opposite(), f_imdl->get_cfd(), prediction_sim ? NULL : new Sim(sim), ground, goal);
2310 
2311  if (c_s == WEAK_REQUIREMENT_ENABLED && prediction_sim && injected_lhs) {
2312  // We injected a simulated prediction. Check if there could be a strong requirement in the future.
2313  uint32 wr_count;
2314  uint32 sr_count;
2315  get_requirement_count(wr_count, sr_count);
2316  if (wr_count > 0 && sr_count > 0) {
2317  // Attach a DefeasibleValidity object to the prediction so that it can be invalidated later by a strong requirement.
2318  injected_lhs->get_pred()->defeasible_validities_.insert(ground->get_pred()->get_defeasible_consequence());
2319  }
2320  }
2321 
2322  return true;
2323  }
2324  return false;
2325  default: // WEAK_REQUIREMENT_DISABLED, STRONG_REQUIREMENT_NO_WEAK_REQUIREMENT or STRONG_REQUIREMENT_DISABLED_WEAK_REQUIREMENT.
2326  if (c_s == STRONG_REQUIREMENT_DISABLED_WEAK_REQUIREMENT && prediction_sim && ground && strong_requirement_ground) {
2327  // A strong requirement disabled the weak requirement.
2328 #ifdef WITH_DETAIL_OID
2329  OUTPUT_LINE(MDL_OUT, Utils::RelativeTime(Now()) << " mdl " << get_object()->get_oid() << ": fact (" <<
2330  to_string(ground->get_detail_oid()) << ") pred fact imdl, from goal req " << goal->get_oid() <<
2331  ", simulated pred disabled by fact (" << to_string(strong_requirement_ground->get_detail_oid()) <<
2332  ") pred |fact imdl");
2333 #endif
2334  }
2335  return false;
2336  }
2337 }
2338 
2339 inline void PrimaryMDLController::predict_simulated_lhs(HLPBindingMap *bm, bool opposite, float32 confidence, Sim *sim) {
2340 
2341  _Fact *bound_lhs = (_Fact *)bm->bind_pattern(get_lhs());
2342  if (opposite)
2343  bound_lhs->set_opposite();
2344  bound_lhs->set_cfd(confidence);
2345 
2346  predict_simulated_evidence(bound_lhs, sim);
2347 }
2348 
2349 inline Fact* PrimaryMDLController::predict_simulated_evidence(_Fact *evidence, Sim *sim) {
2350 
2351  Pred *pred = new Pred(evidence, sim, 1);
2352 
2353  auto now = Now();
2354  Fact* fact_pred = new Fact(pred, now, now, 1, 1);
2355  inject_simulation(fact_pred, now);
2356  return fact_pred;
2357 }
2358 
2359 void PrimaryMDLController::register_pred_outcome(Fact *f_pred, Code* mk_rdx, bool success, _Fact *evidence, float32 confidence, bool rate_failures) {
2360 
2361  f_pred->invalidate();
2362 
2363  if (confidence == 1) // else, evidence is an assumption: no rating.
2364  register_req_outcome(f_pred, success, rate_failures);
2365 
2366  if (requirement_type_)
2367  return;
2368 
2369  _Fact *f_evidence = evidence;
2370  if (!f_evidence) // failure: assert absence of the pred target.
2371  f_evidence = f_pred->get_pred()->get_target()->get_absentee();
2372 
2373  Success *success_object = new Success(f_pred, f_evidence, mk_rdx, 1);
2374  Code *f_success_object;
2375  auto now = Now();
2376  // We print the result to the output below, after injecting f_success_object to get its OID.
2377  if (success)
2378  f_success_object = new Fact(success_object, now, now, confidence, 1);
2379  else
2380  f_success_object = new AntiFact(success_object, now, now, confidence, 1);
2381 
2382  Group *primary_host = get_host();
2383  uint16 out_group_count = get_out_group_count();
2384  for (uint16 i = 0; i < out_group_count; ++i) { // inject notification in out groups.
2385 
2386  Group *out_group = (Group *)get_out_group(i);
2387  int32 resilience = _Mem::Get()->get_goal_pred_success_res(out_group, now, seconds(0));
2388  View *view = new View(View::SYNC_ONCE, now, 1, resilience, out_group, primary_host, f_success_object);
2389  _Mem::Get()->inject(view);
2390 
2391  if (!evidence) {
2392 
2393  view = new View(View::SYNC_ONCE, now, 1, 1, out_group, primary_host, f_evidence);
2394  _Mem::Get()->inject(view);
2395  }
2396  }
2397 
2398  if (success)
2399  OUTPUT_LINE(PRED_MON, Utils::RelativeTime(now) << " fact " << evidence->get_oid() << " -> fact " <<
2400  f_success_object->get_oid() << " success fact " << f_pred->get_oid() << " pred");
2401  else
2402  OUTPUT_LINE(PRED_MON, Utils::RelativeTime(now) << " |fact " << f_success_object->get_oid() <<
2403  " fact " << f_pred->get_oid() << " pred failure");
2404 }
2405 
2406 void PrimaryMDLController::register_req_outcome(Fact *f_pred, bool success, bool rate_failures) {
2407 
2408  if (success)
2409  rate_model(true);
2410  else if (rate_failures)
2411  rate_model(false);
2412 
2413  active_requirementsCS_.enter();
2414  unordered_map<P<_Fact>, RequirementsPair, PHash<_Fact> >::const_iterator r = active_requirements_.find(f_pred);
2415  if (r != active_requirements_.end()) { // some requirements were controlling the prediction: give feedback.
2416 
2417  for (auto c = r->second.weak_requirements_.controllers.begin(); c != r->second.weak_requirements_.controllers.end(); ++c) {
2418 
2419  if (!(*c)->is_invalidated())
2420  (*c)->register_req_outcome(r->second.weak_requirements_.f_imdl, success, r->second.weak_requirements_.chaining_was_allowed);
2421  }
2422  for (auto c = r->second.strong_requirements_.controllers.begin(); c != r->second.strong_requirements_.controllers.end(); ++c) {
2423 
2424  if (!(*c)->is_invalidated())
2425  (*c)->register_req_outcome(r->second.strong_requirements_.f_imdl, !success, r->second.strong_requirements_.chaining_was_allowed);
2426  }
2427  active_requirements_.erase(r);
2428  }
2429  active_requirementsCS_.leave();
2430 }
2431 
2432 void PrimaryMDLController::register_goal_outcome(Fact *goal, bool success, _Fact *evidence) const {
2433 
2434  goal->invalidate();
2435 
2436  auto now = Now();
2437  _Fact *f_success_object;
2438  _Fact *absentee;
2439  if (success) {
2440 
2441  Code *success_object = new Success(goal, evidence, 1);
2442  f_success_object = new Fact(success_object, now, now, 1, 1);
2443  absentee = NULL;
2444  } else {
2445 
2446  Code *success_object;
2447  if (!evidence) { // assert absence of the goal target.
2448 
2449  absentee = goal->get_goal()->get_target()->get_absentee();
2450  success_object = new Success(goal, absentee, 1);
2451  OUTPUT_LINE(PRED_MON, Utils::RelativeTime(now) << " " << goal->get_oid() << " goal success (Primary)");
2452  } else {
2453 
2454  absentee = NULL;
2455  success_object = new Success(goal, evidence, 1);
2456  OUTPUT_LINE(PRED_MON, Utils::RelativeTime(now) << " " << goal->get_oid() << " goal failure (Primary)");
2457  }
2458  f_success_object = new AntiFact(success_object, now, now, 1, 1);
2459  }
2460 
2461  Group *primary_host = get_host();
2462  //int32 resilience=_Mem::Get()->get_goal_pred_success_res(primary_host,0);
2463  //View *view=new View(true,now,1,resilience,primary_host,primary_host,f_success_object);
2464 
2465  uint16 out_group_count = get_out_group_count();
2466  for (uint16 i = 0; i < out_group_count; ++i) { // inject notification in out groups.
2467 
2468  Group *out_group = (Group *)get_out_group(i);
2469  int32 resilience = _Mem::Get()->get_goal_pred_success_res(out_group, now, seconds(0));
2470  View *view = new View(View::SYNC_ONCE, now, 1, resilience, out_group, primary_host, f_success_object);
2471  _Mem::Get()->inject(view);
2472 
2473  if (absentee) {
2474 
2475  view = new View(View::SYNC_ONCE, now, 1, 1, out_group, primary_host, absentee);
2476  _Mem::Get()->inject(view);
2477  }
2478  }
2479 }
2480 
2481 void PrimaryMDLController::register_simulated_goal_outcome(Fact *goal, bool success, _Fact *evidence) const {
2482 
2483  Code *success_object = new Success(goal, evidence, 1);
2484  _Fact *f_success;
2485 
2486  auto now = Now();
2487  if (success)
2488  f_success = new Fact(success_object, now, now, 1, 1);
2489  else
2490  f_success = new AntiFact(success_object, now, now, 1, 1);
2491 
2492  Pred *pred = new Pred(f_success, 1);
2493  Fact *f_pred = new Fact(pred, now, now, 1, 1);
2494 
2495  Group *primary_host = get_host();
2496  int32 resilience = _Mem::Get()->get_goal_pred_success_res(primary_host, now, seconds(0));
2497  View *view = new View(View::SYNC_ONCE, now, 1, resilience, primary_host, primary_host, f_pred);
2498  // JTNote: A View is created, but nothing is done with it.
2499 }
2500 
2501 void PrimaryMDLController::rate_model(bool success) {
2502 
2503  Code *model = get_core_object();
2504 
2505  codeCS_.enter(); // protects the model's data.
2506  if (is_invalidated()) {
2507 
2508  codeCS_.leave();
2509  return;
2510  }
2511 
2512  float32 strength = model->code(MDL_STRENGTH).asFloat();
2513  float32 evidence_count = model->code(MDL_CNT).asFloat();
2514  float32 success_count = model->code(MDL_SR).asFloat()*evidence_count;
2515 
2516  ++evidence_count;
2517  model->code(MDL_DSR) = model->code(MDL_SR);
2518 
2519  float32 success_rate;
2520  bool is_phased_out = false;
2521  bool is_deleted = false;
2522  if (success) { // leave the model active in the primary group.
2523 
2524  ++success_count;
2525  success_rate = success_count / evidence_count;
2526  uint32 evidence_count_base = _Mem::Get()->get_mdl_inertia_cnt_thr();
2527  if (success_rate >= _Mem::Get()->get_mdl_inertia_sr_thr() && evidence_count >= evidence_count_base) { // make the model strong if not already; trim the evidence count to reduce the rating's inertia.
2528 
2529  evidence_count = (uint32)(1 / success_rate);
2530  success_rate = 1;
2531  float32 new_strength = 1;
2532  if (new_strength != strength) {
2533  strength = new_strength;
2534  model->code(MDL_STRENGTH) = Atom::Float(strength);
2535  OUTPUT_LINE(MDL_REV, Utils::RelativeTime(Now()) << " mdl " << model->get_oid() << " strength:" << strength);
2536  }
2537  }
2538 
2539  model->code(MDL_CNT) = Atom::Float(evidence_count);
2540  model->code(MDL_SR) = Atom::Float(success_rate);
2541  get_view()->set_act(success_rate);
2542  codeCS_.leave();
2543  } else {
2544 
2545  success_rate = success_count / evidence_count;
2546  if (success_rate > get_host()->get_act_thr()) { // model still good enough to remain in the primary group.
2547 
2548  model->code(MDL_CNT) = Atom::Float(evidence_count);
2549  model->code(MDL_SR) = Atom::Float(success_rate);
2550  get_view()->set_act(success_rate);
2551  codeCS_.leave();
2552  } else if (strength == 1) { // activate out-of-context strong models in the secondary group, deactivate from the primary.
2553 
2554  // JTNote: Should we update model->code(MDL_CNT) and model->code(MDL_SR) before moving to the secondary group?
2555  get_view()->set_act(0);
2556  secondary_->get_view()->set_act(success_rate); // may trigger secondary->gain_activation().
2557  codeCS_.leave();
2558  is_phased_out = true;
2559  } else { // no weak models live in the secondary group.
2560 
2561  codeCS_.leave();
2562  ModelBase::Get()->register_mdl_failure(model);
2563  kill_views();
2564  is_deleted = true;
2565  }
2566  }
2567  OUTPUT_LINE(MDL_REV, Utils::RelativeTime(Now()) << " mdl " << model->get_oid() << " cnt:" << evidence_count << " sr:" << success_rate);
2568 
2569  // Delay logging these messages until after logging the updated success rate.
2570  if (is_phased_out)
2571  OUTPUT_LINE(MDL_REV, Utils::RelativeTime(Now()) << " mdl " << model->get_oid() << " phased out");
2572  if (is_deleted)
2573  OUTPUT_LINE(MDL_REV, Utils::RelativeTime(Now()) << " mdl " << model->get_oid() << " deleted");
2574 }
2575 
2576 void PrimaryMDLController::assume(_Fact *input) {
2577 
2578  if (is_requirement() || is_reuse() || is_cmd())
2579  return;
2580 
2581  Code *model = get_core_object();
2582  if (model->code(MDL_STRENGTH).asFloat() == 0) // only strong models compute assumptions.
2583  return;
2584 
2585  if (input->get_pred()) // discard predictions.
2586  return;
2587 
2588  float32 confidence = get_success_rate() * input->get_cfd(); // reading STRONG_REQUIREMENT is atomic.
2589  Code *host = get_host();
2590  if (confidence <= host->code(GRP_SLN_THR).asFloat()) // cfd is too low for any assumption to be injected.
2591  return;
2592 
2593  P<HLPBindingMap> bm = new HLPBindingMap(bindings_);
2594  bm->reset_bwd_timings(input);
2595  bool opposite = false;
2596  MatchResult match_result = bm->match_bwd_lenient(input, rhs_);
2597  switch (match_result) {
2598  case MATCH_SUCCESS_NEGATIVE:
2599  opposite = true;
2600  case MATCH_SUCCESS_POSITIVE:
2601  assume_lhs(bm, opposite, input, confidence);
2602  break;
2603  default:
2604  break;
2605  }
2606 }
2607 
2608 void PrimaryMDLController::assume_lhs(HLPBindingMap *bm, bool opposite, _Fact *input, float32 confidence) { // produce an assumption and inject in primary; no rdx.
2609 
2610  // retrieve_imdl_bwd needs the forward timings so evaluate them from the backward guards. We can't call
2611  // evaluate_bwd_guards here because some variables from the requirement need to be bound by retrieve_imdl_bwd.
2612  if (!HLPOverlay::EvaluateFWDTimings(this, bm))
2613  return;
2614 
2615  P<Fact> f_imdl = get_f_ihlp(bm, false);
2616  Fact *ground;
2617  Fact *strong_requirement_ground;
2618  switch (retrieve_imdl_bwd(bm, f_imdl, ground, strong_requirement_ground)) {
2619  case WEAK_REQUIREMENT_ENABLED:
2620  case NO_REQUIREMENT:
2621  if (evaluate_bwd_guards(bm)) // bm may be updated.
2622  break;
2623  return;
2624  default: // WEAK_REQUIREMENT_DISABLED, STRONG_REQUIREMENT_NO_WEAK_REQUIREMENT or STRONG_REQUIREMENT_DISABLED_WEAK_REQUIREMENT.
2625  return;
2626  }
2627 
2628  _Fact *bound_lhs = (_Fact *)bm->bind_pattern(lhs_); // fact or |fact.
2629  bound_lhs->set_cfd(confidence);
2630  if (opposite)
2631  bound_lhs->set_opposite();
2632 
2633  assumptionsCS_.enter();
2634  assumptions_.push_back(bound_lhs);
2635  assumptionsCS_.leave();
2636 
2637  auto now = Now();
2638  Timestamp before = bound_lhs->get_before();
2639  Group *primary_host = get_host();
2640  Timestamp::duration time_to_live;
2641  if (before > now)
2642  time_to_live = before - now;
2643  else
2644  time_to_live = seconds(0);
2645  int32 resilience = _Mem::Get()->get_goal_pred_success_res(primary_host, now, time_to_live);
2646  View *view = new View(View::SYNC_ONCE, now, confidence, resilience, primary_host, primary_host, bound_lhs); // SYNC_ONCE,res=resilience.
2647  _Mem::Get()->inject(view);
2648  OUTPUT_LINE(MDL_OUT, Utils::RelativeTime(Now()) << " mdl " << get_object()->get_oid() << " -> " << bound_lhs->get_oid() << " asmp");
2649 }
2650 
2651 void PrimaryMDLController::kill_views() {
2652 
2653  reductionCS_.enter();
2654  if (is_invalidated()) {
2655 
2656  reductionCS_.leave();
2657  return;
2658  }
2659 
2660  remove_requirement_from_rhs();
2661  secondary_->remove_requirement_from_rhs();
2662  invalidate();
2663  get_view()->force_res(0);
2664  secondary_->get_view()->force_res(0);
2665  reductionCS_.leave();
2666 }
2667 
2668 void PrimaryMDLController::check_last_match_time(bool match) {
2669 
2670  Timestamp now;
2671  if (match) {
2672 
2673  last_match_timeCS_.enter();
2674  now = Now();
2675  last_match_time_ = now;
2676  last_match_timeCS_.leave();
2677  } else {
2678 
2679  now = Now();
2680  if (now - last_match_time_ > _Mem::Get()->get_primary_thz())
2681  get_view()->set_act(0); // will trigger lose_activation(), which will activate the model in the secondary group.
2682  }
2683 }
2684 
2685 bool PrimaryMDLController::abduction_allowed(HLPBindingMap *bm) { // true if fwd timings valuated and all values used by the bwd guards can be evaluated (excepted the values in the tpl args).
2686 
2687  if (!bm)
2688  return false;
2689  if (!HLPOverlay::EvaluateFWDTimings(this, bm))
2690  return false;
2691  if (bm->get_fwd_before() <= Now())
2692  return false;
2693  if (!HLPOverlay::ScanBWDGuards(this, bm))
2694  return false;
2695  return true;
2696 }
2697 
2698 bool PrimaryMDLController::get_template_timings(HLPBindingMap *bm, Timestamp& after, Timestamp& before) {
2699  // Find the variable indexes of the last two template parameters.
2700  Code* model = get_core_object();
2701  auto template_set_index = model->code(MDL_TPL_ARGS).asIndex();
2702  auto template_set_count = model->code(template_set_index).getAtomCount();
2703  auto template_ti_index = template_set_index + template_set_count;
2704  if (!(template_set_count >= 1 && model->code(template_ti_index).getDescriptor() == Atom::I_PTR &&
2705  model->code(model->code(template_ti_index).asIndex()).asOpcode() == Opcodes::TI))
2706  return false;
2707  auto ti_index = model->code(template_ti_index).asIndex();
2708  auto after_code_index = ti_index + 1;
2709  auto before_code_index = ti_index + 2;
2710  if (model->code(after_code_index).getDescriptor() != Atom::VL_PTR ||
2711  model->code(before_code_index).getDescriptor() != Atom::VL_PTR)
2712  // Parameters are not variables.
2713  return false;
2714  auto after_map_index = model->code(after_code_index).asIndex();
2715  auto before_map_index = model->code(before_code_index).asIndex();
2716 
2717  if (bm->get_code(after_map_index) != NULL && bm->get_code(before_map_index) != NULL) {
2718  // The map entries are already evaluated, so check now.
2719 
2720  if (!bm->is_timestamp(after_map_index) || !bm->is_timestamp(before_map_index))
2721  // They are not timestamps.
2722  return false;
2723  after = Utils::GetTimestamp(bm->get_code(after_map_index));
2724  before = Utils::GetTimestamp(bm->get_code(before_map_index));
2725  return true;
2726  }
2727 
2728  // Make a copy of the binding map and evaluate the backward guards.
2729  P<HLPBindingMap> bm_copy = new HLPBindingMap(bm);
2730  if (!evaluate_bwd_guards(bm_copy))
2731  return false;
2732 
2733  if (!bm_copy->is_timestamp(after_map_index) || !bm_copy->is_timestamp(before_map_index))
2734  // They are still not timestamps.
2735  return false;
2736  after = Utils::GetTimestamp(bm_copy->get_code(after_map_index));
2737  before = Utils::GetTimestamp(bm_copy->get_code(before_map_index));
2738  return true;
2739 }
2740 
2742 
2743 SecondaryMDLController::SecondaryMDLController(_View *view) : MDLController(view) {
2744 }
2745 
2746 void SecondaryMDLController::set_primary(PrimaryMDLController *primary) {
2747 
2748  primary_ = primary;
2749 }
2750 
2751 void SecondaryMDLController::take_input(r_exec::View *input) {
2752 
2753  if (become_invalidated())
2754  return;
2755 
2756  if (input->object_->code(0).asOpcode() == Opcodes::Fact ||
2757  input->object_->code(0).asOpcode() == Opcodes::AntiFact) // discard everything but facts and |facts.
2758  Controller::__take_input<SecondaryMDLController>(input);
2759 }
2760 
2761 void SecondaryMDLController::reduce(r_exec::View *input) { // no lock.
2762 
2763  if (is_orphan())
2764  return;
2765 
2766  if (input->object_->is_invalidated())
2767  return;
2768 
2769  SecondaryMDLOverlay o(this, bindings_);
2770  bool match = o.reduce((_Fact *)input->object_, NULL, NULL); // forward chaining.
2771 
2772  if (!match)
2773  monitor_predictions((_Fact *)input->object_);
2774 
2775  check_last_match_time(match);
2776 }
2777 
2778 void SecondaryMDLController::reduce_batch(Fact *f_p_f_imdl, MDLController *controller) {
2779 
2780  if (is_orphan())
2781  return;
2782 
2783  reduce_cache<EvidenceEntry>(&evidences_, f_p_f_imdl, controller);
2784  reduce_cache<PredictedEvidenceEntry>(&predicted_evidences_, f_p_f_imdl, controller);
2785 }
2786 
2787 void SecondaryMDLController::predict(HLPBindingMap *bm, _Fact *input, Fact *f_imdl, bool chaining_was_allowed, RequirementsPair &r_p, Fact *ground,
2788  MkRdx* ground_mk_rdx, vector<P<_Fact> >& already_predicted) { // predicitons are not injected: they are silently produced for rating purposes.
2789 
2790  _Fact *bound_rhs = (_Fact *)bm->bind_pattern(rhs_); // fact or |fact.
2791  Pred *_prediction = new Pred(bound_rhs, 1);
2792  auto now = Now();
2793  Fact *production = new Fact(_prediction, now, now, 1, 1);
2794 
2795  register_requirement(production, r_p);
2796 
2797  if (is_requirement()) { // store in the rhs controller, even if primary (to allow rating in any case).
2798 
2799  if (is_invalidated())
2800  // Another thread has invalidated this controller which clears the controllers.
2801  return;
2802  ((MDLController *)controllers_[RHSController])->store_requirement(production, NULL, this, chaining_was_allowed);
2803  return;
2804  }
2805 
2806  PMonitor *m = new PMonitor(this, bm, production, NULL, false); // predictions are monitored for rating (successes only); no injection.
2807  add_monitor(m);
2808 }
2809 
2810 void SecondaryMDLController::store_requirement(_Fact *f_p_f_imdl, MkRdx* mk_rdx, MDLController *controller, bool chaining_was_allowed) {
2811 
2812  RequirementEntry e(f_p_f_imdl, NULL, controller, chaining_was_allowed);
2813  if (((_Fact*)f_p_f_imdl->get_reference(0)->get_reference(0))->is_fact()) {
2814 
2815  _store_requirement(&requirements_.positive_evidences_, e);
2816  reduce_cache<SecondaryMDLController>((Fact *)f_p_f_imdl, controller);
2817  } else
2818  _store_requirement(&requirements_.negative_evidences_, e);
2819 }
2820 
2821 void SecondaryMDLController::rate_model() { // acknowledge successes only; the purpose is to wake strong models up upon a context switch.
2822 
2823  Code *model = get_core_object();
2824 
2825  codeCS_.enter(); // protects the model's data.
2826  if (is_invalidated()) {
2827 
2828  codeCS_.leave();
2829  return;
2830  }
2831 
2832  float32 evidence_count = model->code(MDL_CNT).asFloat();
2833  float32 success_count = model->code(MDL_SR).asFloat()*evidence_count;
2834 
2835  ++evidence_count;
2836  model->code(MDL_DSR) = model->code(MDL_SR);
2837  model->code(MDL_CNT) = Atom::Float(evidence_count);
2838 
2839  ++success_count;
2840  float32 success_rate = success_count / evidence_count; // no trimming.
2841  model->code(MDL_SR) = Atom::Float(success_rate);
2842 
2843  bool is_phased_in = false;
2844  if (success_rate > primary_->get_view()->get_host()->get_act_thr()) {
2845 
2846  get_view()->set_act(0);
2847  primary_->get_view()->set_act(success_rate); // activate the primary controller in its own group g: will be performmed at the nex g->upr.
2848  codeCS_.leave();
2849  is_phased_in = true;
2850  } else { // will trigger primary->gain_activation() at the next g->upr.
2851 
2852  if (success_rate > get_view()->get_host()->get_act_thr()) // else: leave the model in the secondary group.
2853  get_view()->set_act(success_rate);
2854  codeCS_.leave();
2855  }
2856  OUTPUT_LINE(MDL_REV, Utils::RelativeTime(Now()) << " mdl " << model->get_oid() << " cnt:" << evidence_count << " sr:" << success_rate);
2857 
2858  // Delay logging this message until after logging the updated success rate.
2859  if (is_phased_in)
2860  OUTPUT_LINE(MDL_REV, Utils::RelativeTime(Now()) << " mdl " << model->get_oid() << " phased in");
2861 }
2862 
2863 void SecondaryMDLController::register_pred_outcome(Fact *f_pred, Code* mk_rdx, bool success, _Fact *evidence, float32 confidence, bool rate_failures) { // success==false means executed in the thread of a time core; otherwise, executed in the same thread as for Controller::reduce().
2864 
2865  register_req_outcome(f_pred, success, rate_failures);
2866 }
2867 
2868 void SecondaryMDLController::register_req_outcome(Fact *f_imdl, bool success, bool rate_failures) {
2869 
2870  if (success) {
2871 
2872  rate_model();
2873 
2874  active_requirementsCS_.enter();
2875  unordered_map<P<_Fact>, RequirementsPair, PHash<_Fact> >::const_iterator r = active_requirements_.find(f_imdl);
2876  if (r != active_requirements_.end()) { // some requirements were controlling the prediction: give feedback.
2877 
2878  for (auto c = r->second.weak_requirements_.controllers.begin(); c != r->second.weak_requirements_.controllers.end(); ++c) {
2879 
2880  if (!(*c)->is_invalidated())
2881  (*c)->register_req_outcome(
2882  r->second.weak_requirements_.f_imdl, success, r->second.weak_requirements_.chaining_was_allowed);
2883  }
2884  active_requirements_.erase(r);
2885  }
2886  active_requirementsCS_.leave();
2887  }
2888 }
2889 
2890 void SecondaryMDLController::kill_views() {
2891 
2892  remove_requirement_from_rhs();
2893  primary_->remove_requirement_from_rhs();
2894  invalidate();
2895  get_view()->force_res(0);
2896  primary_->get_view()->force_res(0);
2897 }
2898 
2899 void SecondaryMDLController::check_last_match_time(bool match) {
2900 
2901  Timestamp now;
2902  if (match) {
2903 
2904  last_match_timeCS_.enter();
2905  now = Now();
2906  last_match_time_ = now;
2907  last_match_timeCS_.leave();
2908  } else {
2909 
2910  now = Now();
2911  if (now - last_match_time_ > _Mem::Get()->get_secondary_thz()) {
2912 
2913  ModelBase::Get()->register_mdl_timeout(get_core_object());
2914  kill_views();
2915  }
2916  }
2917 }
2918 }
r_exec::Pred::get_simulation
Sim * get_simulation(uint16 i) const
Definition: factory.h:468
r_exec::Sim::get_f_super_goal
Fact * get_f_super_goal() const
Definition: factory.h:266
r_code::list::const_iterator
Definition: list.h:266
r_exec::PrimaryMDLController::abduce_no_simulation
void abduce_no_simulation(Fact *super_goal, bool opposite, float32 confidence, _Fact *f_p_f_success=NULL)
Definition: mdl_controller.cpp:1979
r_exec::Sim::set_solution_before
void set_solution_before(Timestamp before)
Definition: factory.h:287
r_exec::Pred::get_defeasible_consequence
DefeasibleValidity * get_defeasible_consequence()
Definition: factory.h:499
r_exec::Goal::get_sim
Sim * get_sim() const
Definition: factory.h:550
r_exec::HLPOverlay::EvaluateFWDTimings
static bool EvaluateFWDTimings(Controller *c, HLPBindingMap *bindings)
Definition: hlp_overlay.cpp:100
r_exec::PrimaryMDLController::get_template_timings
bool get_template_timings(HLPBindingMap *bm, Timestamp &after, Timestamp &before)
Definition: mdl_controller.cpp:2698
r_exec::PrimaryMDLController::store_requirement
void store_requirement(_Fact *f_p_f_imdl, MkRdx *mk_rdx, MDLController *controller, bool chaining_was_allowed) override
Definition: mdl_controller.cpp:1492
r_exec::HLPController::evaluate_bwd_guards
bool evaluate_bwd_guards(HLPBindingMap *bm, bool narrow_fwd_timings=false)
Definition: hlp_controller.cpp:168
r_exec::MkRdx
Definition: factory.h:588
r_exec::MDLController::get_success_rate
float32 get_success_rate() const
Definition: mdl_controller.cpp:365
r_code::_View
Definition: r_code/object.h:164
r_exec::MDLController::RequirementEntry
Definition: mdl_controller.h:191
r_exec::Goal
Definition: factory.h:517
r_exec::Sim
Definition: factory.h:248
r_exec::BindingMap::is_timestamp
bool is_timestamp(uint16 i) const
Definition: binding_map.h:327
r_exec::PrimaryMDLController::check_simulated_imdl
bool check_simulated_imdl(Fact *goal, HLPBindingMap *bm, Sim *prediction_sim)
Definition: mdl_controller.cpp:2286
r_exec::_Fact
Definition: factory.h:155
core::P
Definition: base.h:103
r_code::Code
Definition: r_code/object.h:224
r_exec::TopLevelMDLController::store_requirement
void store_requirement(_Fact *f_p_f_imdl, MkRdx *mk_rdx, MDLController *controller, bool chaining_was_allowed) override
Definition: mdl_controller.cpp:1261
r_exec::SecondaryMDLController::store_requirement
void store_requirement(_Fact *f_p_f_imdl, MkRdx *mk_rdx, MDLController *controller, bool chaining_was_allowed) override
Definition: mdl_controller.cpp:2810
r_exec::_Fact::MatchObject
static bool MatchObject(const r_code::Code *lhs, const r_code::Code *rhs, bool same_binding_state=false)
Definition: factory.cpp:364
r_exec::MDLController
Definition: mdl_controller.h:188
r_exec::View
Definition: view.h:102
r_exec::HLPBindingMap
Definition: binding_map.h:393
r_exec::Pred::get_simulations_size
uint16 get_simulations_size() const
Definition: factory.h:458
r_exec::Pred
Definition: factory.h:394
r_exec::HLPController::inject_notification_into_out_groups
void inject_notification_into_out_groups(r_code::Code *origin, r_code::Code *marker) const
Definition: hlp_controller.cpp:301
r_exec::Sim::get_opposite
bool get_opposite() const
Definition: factory.h:272
r_code::list
Definition: list.h:99
r_exec::Fact
Definition: factory.h:360
r_code::PHash
Definition: r_code/utils.h:96
r_code::Utils::GetTimestamp
static Timestamp GetTimestamp(const Atom *iptr)
Definition: code_utils.cpp:129