AERA
pattern_extractor.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) 2023 Leonard M. Eberding
10 //_/_/ http://www.iiim.is
11 //_/_/
12 //_/_/ Copyright (c) 2010-2012 Eric Nivel
13 //_/_/ Center for Analysis and Design of Intelligent Agents
14 //_/_/ Reykjavik University, Menntavegur 1, 102 Reykjavik, Iceland
15 //_/_/ http://cadia.ru.is
16 //_/_/
17 //_/_/ Part of this software was developed by Eric Nivel
18 //_/_/ in the HUMANOBS EU research project, which included
19 //_/_/ the following parties:
20 //_/_/
21 //_/_/ Autonomous Systems Laboratory
22 //_/_/ Technical University of Madrid, Spain
23 //_/_/ http://www.aslab.org/
24 //_/_/
25 //_/_/ Communicative Machines
26 //_/_/ Edinburgh, United Kingdom
27 //_/_/ http://www.cmlabs.com/
28 //_/_/
29 //_/_/ Istituto Dalle Molle di Studi sull'Intelligenza Artificiale
30 //_/_/ University of Lugano and SUPSI, Switzerland
31 //_/_/ http://www.idsia.ch/
32 //_/_/
33 //_/_/ Institute of Cognitive Sciences and Technologies
34 //_/_/ Consiglio Nazionale delle Ricerche, Italy
35 //_/_/ http://www.istc.cnr.it/
36 //_/_/
37 //_/_/ Dipartimento di Ingegneria Informatica
38 //_/_/ University of Palermo, Italy
39 //_/_/ http://diid.unipa.it/roboticslab/
40 //_/_/
41 //_/_/
42 //_/_/ --- HUMANOBS Open-Source BSD License, with CADIA Clause v 1.0 ---
43 //_/_/
44 //_/_/ Redistribution and use in source and binary forms, with or without
45 //_/_/ modification, is permitted provided that the following conditions
46 //_/_/ are met:
47 //_/_/ - Redistributions of source code must retain the above copyright
48 //_/_/ and collaboration notice, this list of conditions and the
49 //_/_/ following disclaimer.
50 //_/_/ - Redistributions in binary form must reproduce the above copyright
51 //_/_/ notice, this list of conditions and the following disclaimer
52 //_/_/ in the documentation and/or other materials provided with
53 //_/_/ the distribution.
54 //_/_/
55 //_/_/ - Neither the name of its copyright holders nor the names of its
56 //_/_/ contributors may be used to endorse or promote products
57 //_/_/ derived from this software without specific prior
58 //_/_/ written permission.
59 //_/_/
60 //_/_/ - CADIA Clause: The license granted in and to the software
61 //_/_/ under this agreement is a limited-use license.
62 //_/_/ The software may not be used in furtherance of:
63 //_/_/ (i) intentionally causing bodily injury or severe emotional
64 //_/_/ distress to any person;
65 //_/_/ (ii) invading the personal privacy or violating the human
66 //_/_/ rights of any person; or
67 //_/_/ (iii) committing or preparing for any act of war.
68 //_/_/
69 //_/_/ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
70 //_/_/ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
71 //_/_/ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
72 //_/_/ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
73 //_/_/ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
74 //_/_/ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
75 //_/_/ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
76 //_/_/ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
77 //_/_/ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
78 //_/_/ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
79 //_/_/ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
80 //_/_/ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
81 //_/_/ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
82 //_/_/ OF SUCH DAMAGE.
83 //_/_/
84 //_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
85 
86 #include "auto_focus.h"
87 #include "reduction_job.h"
88 #include "mem.h"
89 #include "model_base.h"
90 #include "hlp_context.h"
91 #include "mdl_controller.h"
92 
93 using namespace std;
94 using namespace std::chrono;
95 using namespace r_code;
96 
97 namespace r_exec {
98 
99 bool Input::IsEligibleCause(r_exec::View *view) {
100 
101  switch (view->get_sync()) {
102  case View::SYNC_AXIOM:
103  case View::SYNC_ONCE_AXIOM:
104  return false;
105  default:
106  return true;
107  }
108 }
109 
111 
112 TPX::TPX(AutoFocusController *auto_focus, _Fact *target, _Fact *pattern, BindingMap *bindings) : _Object(), auto_focus_(auto_focus), target_(target), abstracted_target_(pattern), target_bindings_(bindings), cst_hook_(NULL) { // called by GTPX and PTPX's ctor.
113 
114  if (bindings->is_fully_specified()) { // get a hook on a cst controller so we get icsts from it: this is needed if the target is an underspecified icst.
115 
116  Code *target_payload = target->get_reference(0)->get_reference(0)->get_reference(0);
117  if (target_payload->code(0).asOpcode() == Opcodes::ICst) {
118 
119  Code *cst = target_payload->get_reference(0);
120  cst_hook_ = (CSTController *)((r_exec::View *)cst->get_view(auto_focus->get_primary_group(), true))->controller_;
121  }
122  }
123 }
124 
125 TPX::TPX(AutoFocusController *auto_focus, _Fact *target) : _Object(), auto_focus_(auto_focus) { // called by CTPX's ctor.
126 
127  P<BindingMap> bm = new BindingMap();
128  abstracted_target_ = (_Fact *)bm->abstract_object(target, false);
129  target_ = target;
130  target_bindings_ = bm;
131 }
132 
133 TPX::~TPX() {
134 }
135 
136 bool TPX::take_input(View *input, _Fact *abstracted_input, BindingMap *bm) {
137 
138  return filter(input, abstracted_input, bm);
139 }
140 
141 void TPX::signal(View *input) const { // input->object is f->success or|f->success.
142 }
143 
144 void TPX::ack_pred_success(Success* success) {
145 }
146 
147 bool TPX::filter(View *input, _Fact *abstracted_input, BindingMap *bm) {
148 
149  if (input->object_->get_reference(0)->code(0).asOpcode() == Opcodes::ICst) // if we get an icst we are called by auto_focus::dispatch_no_inject: the input is irrelevant.
150  return false;
151  if (target_bindings_->intersect(bm)) {
152  return true; }
153  if (target_bindings_->is_fully_specified())
154  return false;
155  for (uint32 i = 0; i < new_maps_.size(); ++i)
156  if (new_maps_[i]->intersect(bm)) {
157  return true; }
158 
159  P<BindingMap> _bm = new BindingMap(target_bindings_);
160  _bm->reset_fwd_timings(input->object_);
161  time_buffer<CInput, CInput::IsInvalidated> &cache = auto_focus_->get_cache();
162  if (_bm->match_fwd_strict(input->object_, (_Fact *)target_->get_reference(0)->get_reference(0))) { // both GTPX and PTPX' target are f0->g/p->f1: we need to match on f1.
163  new_maps_.push_back(_bm);
165  auto now = Now();
166  for (i = cache.begin(now); i != cache.end(); ++i) {
167 
168  if (i->injected_) {
169  continue; }
170  if (_bm->intersect(i->bindings_)) {
171  i->injected_ = true;
172  auto_focus_->inject_input(i->input_, i->abstraction_, i->bindings_);
173  }
174  }
175  return true;
176  } else {
177 
178  if (cst_hook_ != NULL)
179  cst_hook_->take_input(input);
180  CInput ci(input, abstracted_input, bm);
182  if (i != cache.end()) { // input already cached.
183 
184  if (i->ijt_ < ci.ijt_) // older view (happens for sync_axiom and sync_old).
185  cache.erase(i);
186  else
187  return false;
188  }
189  cache.push_back(ci);
190  return false;
191  }
192 }
193 
195 
196 _TPX::_TPX(AutoFocusController *auto_focus, _Fact *target, _Fact *pattern, BindingMap *bindings) : TPX(auto_focus, target, pattern, bindings) {
197 
198  inputs_.reserve(InputsInitialSize);
199 }
200 
201 _TPX::_TPX(AutoFocusController *auto_focus, _Fact *target) : TPX(auto_focus, target) {
202 }
203 
204 _TPX::~_TPX() {
205 }
206 
207 void _TPX::filter_icst_components(ICST *icst, uint32 icst_index, vector<Component> &components) {
208 
209  uint32 found_component_count = 0;
210  uint32 *found = new uint32[icst->components_.size()];
211  for (uint32 j = 0; j < components.size(); ++j) {
212 
213  for (uint32 i = 0; i < icst->components_.size(); ++i) {
214 
215  if (components[j].discarded)
216  continue;
217  if (components[j].object == icst->components_[i]) {
218 
219  found[found_component_count] = j;
220  ++found_component_count;
221  }
222  }
223  }
224 
225  if (found_component_count > 0) { // some of the icst components are already in the inputs: discard said components, keep the icst.
226 
227  for (uint32 i = 0; i < found_component_count; ++i)
228  components[found[i]].discarded = true;
229  } else // none of the icst components are in the inputs; this can only happen because the icst shares one timestamp with the TPX's target: discard the icst.
230  components[icst_index].discarded = true;
231 
232  delete[] found;
233 }
234 
235 _Fact* _TPX::find_f_icst_component(_Fact* fact, const _Fact *component, int max_depth) {
236  Code* candidate = fact->get_reference(0);
237  if (candidate->code(0).asOpcode() == Opcodes::ICst) {
238  ICST* icst = (ICST*)candidate;
239  uint16 component_index;
240  if (icst->contains(component, component_index)) {
241  Code* cst = candidate->get_reference(0);
242  // The cst is packed, retrieve the pattern from the unpacked code.
243  Code* unpacked_cst = cst->get_reference(cst->references_size() - CST_HIDDEN_REFS);
244  return (_Fact*)unpacked_cst->get_reference(component_index);
245  }
246 
247  if (max_depth > 0) {
248  // The component was not found, so recurse to search each member.
249  for (uint32 i = 0; i < icst->components_.size(); ++i) {
250  // This will check if the component is an icst.
251  _Fact* result = find_f_icst_component(icst->components_[i], component, max_depth - 1);
252  if (result)
253  return result;
254  }
255  }
256  }
257 
258  return NULL;
259 }
260 
261 void _TPX::_find_f_icst(_Fact *component, vector<FindFIcstResult>& results, bool find_multiple) {
262 
264  for (i = inputs_.begin(); i != inputs_.end(); ++i) {
265  _Fact* component_pattern = find_f_icst_component(i->input_, component);
266  if (component_pattern) {
267  results.push_back(FindFIcstResult(i->input_, component_pattern));
268  if (!find_multiple)
269  return;
270  }
271  }
272 
273  vector<P<_Fact> >::const_iterator f_icst;
274  for (f_icst = f_icsts_.begin(); f_icst != f_icsts_.end(); ++f_icst) {
275 
276  _Fact* component_pattern = find_f_icst_component(*f_icst, component);
277  if (component_pattern) {
278  results.push_back(FindFIcstResult(*f_icst, component_pattern));
279  if (!find_multiple)
280  return;
281  }
282  }
283 }
284 
285 void _TPX::find_f_icst(_Fact *component, vector<FindFIcstResult>& results, bool find_multiple) {
286 
287  uint16 opcode = component->get_reference(0)->code(0).asOpcode();
288  if (opcode == Opcodes::Cmd || opcode == Opcodes::IMdl) // cmds/imdls cannot be components of a cst.
289  return;
290 
291  _find_f_icst(component, results, find_multiple);
292 }
293 
294 void _TPX::find_f_icst(_Fact *component, vector<FindFIcstResult>& results, P<Code> &new_cst, bool find_multiple) {
295 
296  uint16 opcode = component->get_reference(0)->code(0).asOpcode();
297  if (opcode == Opcodes::Cmd || opcode == Opcodes::IMdl)
298  // cmds/imdls cannot be components of a cst.
299  return;
300 
301  _find_f_icst(component, results, find_multiple);
302  if (results.size() > 0)
303  return;
304 
305  _Fact* component_pattern;
306  _Fact* f_icst = make_f_icst(component, component_pattern, new_cst);
307  if (f_icst)
308  results.push_back(FindFIcstResult(f_icst, component_pattern));
309 }
310 
311 _Fact *_TPX::make_f_icst(_Fact *component, _Fact*& component_pattern, P<Code> &new_cst) {
312 
313  uint16 opcode = component->get_reference(0)->code(0).asOpcode();
314  if (opcode == Opcodes::Cmd || opcode == Opcodes::IMdl)
315  // cmds/imdls cannot be components of a cst.
316  return NULL;
317 
318  vector<Component> components; // no icst found, try to identify components to assemble a cst.
319  vector<uint32> icst_components;
320 
322  for (i = inputs_.begin(); i != inputs_.end(); ++i) {
323 
324  if (component == i->input_) {
325 
326  components.push_back(Component(component));
327  } else if (component->match_timings_sync(i->input_)) {
328 
329  Code *icst = i->input_->get_reference(0);
330  if (icst->code(0).asOpcode() == Opcodes::ICst)
331  icst_components.push_back(components.size());
332  components.push_back(Component(i->input_));
333  }
334  }
335 
336  for (uint32 j = 0; j < icst_components.size(); ++j) {
337 
338  ICST *icst = (ICST *)components[icst_components[j]].object->get_reference(0);
339  filter_icst_components(icst, j, components);
340  }
341 
342  uint32 actual_size = 0;
343  for (uint32 j = 0; j < components.size(); ++j) {
344 
345  if (components[j].discarded)
346  continue;
347  else
348  ++actual_size;
349  }
350 
351  if (actual_size <= 1)
352  // contains at most only the provided component.
353  return NULL;
354 
356  for (_i = inputs_.begin(); _i != inputs_.end(); ++_i) { // flag the components so the tpx does not try them again.
357 
358  for (uint32 j = 0; j < components.size(); ++j) {
359 
360  if (_i->input_ == components[j].object)
361  _i->eligible_cause_ = false;
362  }
363  }
364 
365  P<HLPBindingMap> bm = new HLPBindingMap();
366  new_cst = build_cst(components, bm, component);
367  // build_cst adds the abstract object of the component as the first reference.
368  component_pattern = (_Fact*)new_cst->get_reference(0);
369  _Fact *f_icst = bm->build_f_ihlp(new_cst, Opcodes::ICst, false);
370  // build_f_ihlp can leave some variables pointing into bm, but we need everything valuated.
371  f_icst->set_reference(0, bm->bind_pattern(f_icst->get_reference(0)));
372  f_icsts_.push_back(f_icst); // the f_icst can be reused in subsequent model building attempts.
373  return f_icst;
374 }
375 
376 Code *_TPX::build_cst(const vector<Component> &components, BindingMap *bm, _Fact *main_component) {
377 
378  Code *cst = _Mem::Get()->build_object(Atom::CompositeState(Opcodes::Cst, CST_ARITY));
379 
380  uint16 actual_component_count = 0;
381  // Add the main_component first since its variables are assigned first.
382  for (uint16 i = 0; i < components.size(); ++i) {
383  if (components[i].discarded)
384  continue;
385  if (components[i].object == main_component) {
386  cst->add_reference(bm->abstract_object(main_component, false));
387  ++actual_component_count;
388  break;
389  }
390  }
391 
392  for (uint16 i = 0; i < components.size(); ++i) { // reference patterns;
393 
394  if (components[i].discarded)
395  continue;
396  if (components[i].object == main_component)
397  // Already added.
398  continue;
399  else
400  cst->add_reference(bm->abstract_object(components[i].object, true));
401  ++actual_component_count;
402  }
403 
404  uint16 extent_index = CST_ARITY;
405 
406  cst->code(CST_TPL_ARGS) = Atom::IPointer(++extent_index);
407  cst->code(extent_index) = Atom::Set(0); // no tpl args.
408 
409  cst->code(CST_OBJS) = Atom::IPointer(++extent_index);
410  cst->code(extent_index) = Atom::Set(actual_component_count);
411  for (uint16 i = 0; i < actual_component_count; ++i)
412  cst->code(++extent_index) = Atom::RPointer(i);
413 
414  cst->code(CST_FWD_GUARDS) = Atom::IPointer(++extent_index);
415  cst->code(extent_index) = Atom::Set(0); // no fwd guards.
416 
417  cst->code(CST_BWD_GUARDS) = Atom::IPointer(++extent_index);
418  cst->code(extent_index) = Atom::Set(0); // no bwd guards.
419 
420  cst->code(CST_OUT_GRPS) = Atom::IPointer(++extent_index);
421  cst->code(extent_index) = Atom::Set(1); // only one output group: the one the tpx lives in.
422  cst->code(++extent_index) = Atom::RPointer(cst->references_size());
423 
424  cst->code(CST_ARITY) = Atom::Float(1); // psln_thr.
425 
426  cst->add_reference(auto_focus_->get_view()->get_host()); // reference the output group.
427 
428  return cst;
429 }
430 
431 Code *_TPX::build_mdl_head(HLPBindingMap *bm, uint16 tpl_arg_count, _Fact *lhs, _Fact *rhs, uint16 &write_index, bool allow_shared_timing_vars) {
432 
433  Code* abstract_lhs = bm->abstract_object(lhs, false, allow_shared_timing_vars ? 0 : -1);
434 
435  int rhs_first_search_index = (allow_shared_timing_vars ? 0 : -1);
436  if (abstract_lhs->get_reference(0)->code(0).asOpcode() == Opcodes::IMdl) {
437  Code* imdl = abstract_lhs->get_reference(0);
438  // This is a reuse model. When matching the timings of the RHS fact, first try the last two
439  // exposed args which came from the RHS timings of the imdl being reused.
440  auto exposed_args_index = imdl->code(I_HLP_EXPOSED_ARGS).asIndex();
441  auto exposed_args_count = imdl->code(exposed_args_index).getAtomCount();
442  auto exposed_after_index = exposed_args_index + (exposed_args_count - 1);
443  if (exposed_args_count >= 2 &&
444  imdl->code(exposed_after_index).getDescriptor() == Atom::VL_PTR)
445  rhs_first_search_index = imdl->code(exposed_after_index).asIndex();
446  }
447  Code* abstract_rhs = bm->abstract_object(rhs, false, rhs_first_search_index);
448 
449  return build_mdl_head_from_abstract(tpl_arg_count, abstract_lhs, abstract_rhs, write_index);
450 }
451 
452 Code* _TPX::build_mdl_head_from_abstract(uint16 tpl_arg_count, Code* abstract_lhs, Code* abstract_rhs, uint16& write_index) {
453  Code* mdl = _Mem::Get()->build_object(Atom::Model(Opcodes::Mdl, MDL_ARITY));
454  mdl->add_reference(abstract_lhs); // reference lhs.
455  mdl->add_reference(abstract_rhs); // reference rhs.
456 
457  write_index = MDL_ARITY;
458 
459  mdl->code(MDL_TPL_ARGS) = Atom::IPointer(++write_index);
460  if (tpl_arg_count >= 2) {
461  // Assume the last two template args are a time interval.
462  mdl->code(write_index) = Atom::Set(tpl_arg_count - 1);
463  // Write the template args before the time interval.
464  for (uint16 i = 0; i < tpl_arg_count - 2; ++i)
465  mdl->code(++write_index) = Atom::VLPointer(i);
466  ++write_index;
467  mdl->code(write_index) = Atom::IPointer(write_index + 1);
468  ++write_index;
469  // Make the (ti : :) .
470  mdl->code(write_index) = Atom::Object(Opcodes::TI, 2);
471  mdl->code(++write_index) = Atom::VLPointer(tpl_arg_count - 2);
472  mdl->code(++write_index) = Atom::VLPointer(tpl_arg_count - 1);
473  }
474  else {
475  mdl->code(write_index) = Atom::Set(tpl_arg_count);
476  for (uint16 i = 0; i < tpl_arg_count; ++i)
477  mdl->code(++write_index) = Atom::VLPointer(i);
478  }
479 
480  mdl->code(MDL_OBJS) = Atom::IPointer(++write_index);
481  mdl->code(write_index) = Atom::Set(2);
482  mdl->code(++write_index) = Atom::RPointer(0);
483  mdl->code(++write_index) = Atom::RPointer(1);
484 
485  return mdl;
486 }
487 
488 void _TPX::build_mdl_tail(Code *mdl, uint16 write_index) {
489 
490  mdl->code(MDL_OUT_GRPS) = Atom::IPointer(++write_index);
491  mdl->code(write_index) = Atom::Set(1); // only one group: the one the tpx lives in.
492  mdl->code(++write_index) = Atom::RPointer(2);
493 
494  mdl->code(MDL_STRENGTH) = Atom::Float(0);
495  mdl->code(MDL_CNT) = Atom::Float(1);
496  mdl->code(MDL_SR) = Atom::Float(1);
497  mdl->code(MDL_DSR) = Atom::Float(1);
498  mdl->code(MDL_ARITY) = Atom::Float(1); // psln_thr.
499 
500  mdl->add_reference(auto_focus_->get_view()->get_host()); // reference the output group.
501 }
502 
503 void _TPX::inject_hlps() const {
504 
505  vector<P<Code> >::const_iterator c;
506  for (c = csts_.begin(); c != csts_.end(); ++c)
507  _Mem::Get()->pack_hlp(*c);
508  auto_focus_->inject_hlps(csts_);
509  auto_focus_->inject_hlps(mdls_);
510 }
511 
512 void _TPX::inject_hlps(Timestamp analysis_starting_time) {
513 
514  if (auto_focus_->decompile_models()) {
515 
516  r_code::list<P<Code> > tmp;
518  for (i = inputs_.begin(); i != inputs_.end(); ++i)
519  tmp.push_back((Code *)i->input_);
520 
521  std::string header("> from buffer -------------------\n\n");
522 
523  P<TDecompiler> td = new TDecompiler(1, header);
524  td->add_objects(tmp);
525  td->decompile();
526 
527  auto analysis_end = Now();
528  auto d = duration_cast<microseconds>(analysis_end - analysis_starting_time);
529  auto timing = to_string(d.count());
530  header = Utils::ToString_s_ms_us(Now(), Utils::GetTimeReference());
531  std::string s0 = (" > ");
532  s0 += get_header() + std::string(":production [");
533  std::string s1("us] -------------------\n\n");
534  header += s0 + timing + s1;
535 
536  td = new TDecompiler(1, header);
537  td->add_objects(mdls_);
538  inject_hlps();
539  td->decompile();
540  } else
541  inject_hlps();
542 
543  csts_.clear();
544  mdls_.clear();
545 }
546 
548 
549 GTPX::GTPX(AutoFocusController *auto_focus, _Fact *target, _Fact *pattern, BindingMap *bindings, Fact *f_imdl) : _TPX(auto_focus, target, pattern, bindings), f_imdl_(f_imdl) {
550 }
551 
552 GTPX::~GTPX() {
553 }
554 
555 bool GTPX::take_input(View *input, _Fact *abstracted_input, BindingMap *bm) { // push new input in the time-controlled buffer; old inputs are in front.
556 
557  if (!filter(input, abstracted_input, bm))
558  return false;
559 
560  inputs_.push_back(Input(input, abstracted_input, bm));
561  return true;
562 }
563 
564 void GTPX::signal(View *input) const { // will be erased from the AF map upon return. P<> kept in reduction job.
565 
566  if (!auto_focus_->gtpx_on())
567  return;
568 
569  if (((_Fact *)input->object_)->is_fact()) { // goal success.
570 
571  ReductionJob<GTPX> *j = new ReductionJob<GTPX>(new View(input), (GTPX *)this);
572 #ifdef WITH_DETAIL_OID
573  OUTPUT_LINE((TraceLevel)0, " make ReductionJob<GTPX> " << j->get_job_id() << "(" << j->get_detail_oid() <<
574  "): controller(" << get_detail_oid() << ")->reduce(View(fact_" << input->object_->get_oid() << "))");
575 #endif
576  _Mem::Get()->push_reduction_job(j);
577  }
578 }
579 
581 
582  _Fact* consequent = target_->get_goal()->get_target();
583  // Use the same check as GMonitor::reduce.
584  if (consequent->is_anti_fact() && success->get_evidence()->is_fact() &&
585  success->get_evidence()->is_evidence(consequent) == MATCH_SUCCESS_POSITIVE) {
586  // The goal anti-fact is achieved by the prediction success object. Make a model.
587  auto analysis_starting_time = Now();
588 
589  // The success object is
590  // (fact (success f_prediction evidence (mk.rdx f_imdl [cause req_mk_rdx] [f_prediction]))), and where req_mk_rdx is
591  // (mk.rdx : [f_icst] [requirement]).
592  // Make the model from fact_cst, cause and consequent.
593  MkRdx* mk_rdx = success->get_object_mk_rdx();
594  if (!mk_rdx)
595  // We don't expect this.
596  return;
597  uint16 inputs_index = mk_rdx->code(MK_RDX_INPUTS).asIndex();
598  if (mk_rdx->code(0).asOpcode() != r_exec::Opcodes::MkRdx ||
599  mk_rdx->code(inputs_index).getAtomCount() < 2)
600  // We don't expect this.
601  return;
602  _Fact* cause = (_Fact*)mk_rdx->get_first_input();
603  MkRdx* req_mk_rdx = (MkRdx*)mk_rdx->get_reference(mk_rdx->code(inputs_index + 2).asIndex());
604  if (req_mk_rdx->code(0).asOpcode() != r_exec::Opcodes::MkRdx)
605  // We don't expect this.
606  return;
607  _Fact* f_icst = (_Fact*)req_mk_rdx->get_first_input();
608 
609  auto period = duration_cast<microseconds>(consequent->get_after() - cause->get_after());
610  P<GuardBuilder> guard_builder;
611  guard_builder = new ConstBwdArgCmdGuardBuilder(microseconds(100000), period, /*Debug: get correctly*/ 6, cause);
612 
613  if (build_mdl(cause, f_icst, consequent, guard_builder, period))
614  inject_hlps(analysis_starting_time);
615 
616  if (target_->get_goal()->has_sim()) {
617  auto controller = target_->get_goal()->get_sim()->root_;
618  if (!!controller)
619  // Report a success now since it was skipped in GMonitor::reduce. This also invalidates target_ .
620  ((PMDLController*)controller)->register_goal_outcome(target_, true, success->get_evidence());
621  }
622  return;
623  }
624 
625  predictions_.push_back((_Fact*)success->get_object()->get_pred()->get_reference(0));
626 }
627 
628 void GTPX::reduce(r_exec::View *input) { // input->object: f->success.
629 
630  _Fact *consequent = (_Fact *)input->object_->get_reference(0)->get_reference(1);
631  P<BindingMap> consequent_bm = new BindingMap();
632  {
633  // Call abstract_object only to update the binding map.
634  P<Code> unused = consequent_bm->abstract_object(consequent, false);
635  }
636 
637  for (uint32 i = 0; i < predictions_.size(); ++i) { // check if some models have successfully predicted the target: if so, abort.
638 
639  P<BindingMap> bm = new BindingMap(consequent_bm);
640  bm->reset_fwd_timings(predictions_[i]);
641  if (bm->match_fwd_strict(predictions_[i], consequent))
642  return;
643  }
644 
645  auto analysis_starting_time = Now();
646 
647  if (target_->get_reference(0)->code(0).asOpcode() == Opcodes::MkVal)
648  return; // this case will be handled by CTPXs.
649 
650  P<GuardBuilder> guard_builder;
651 
652  microseconds period;
653  microseconds lhs_duration;
654  microseconds rhs_duration;
655 
657  for (i = inputs_.begin(); i != inputs_.end();) {
658 
659  if (i->input_->get_after() >= consequent->get_after()) { // discard inputs not younger than the consequent.
660 
661  i = inputs_.erase(i);
662  continue;
663  }
664 
665  if (i->input_->get_reference(0)->code(0).asOpcode() == Opcodes::ICst) {
666 
667  ++i;
668  continue; // components will be evaluated first, then the icst will be identified.
669  }
670 
671  Input cause = *i;
672 
673  if (!cause.eligible_cause_) {
674 
675  ++i;
676  continue;
677  }
678 
679  if (Utils::Synchronous(cause.input_->get_after(), target_->get_after())) { // cause in sync with the premise: ignore.
680 
681  ++i;
682  continue;
683  }
684 
685  period = duration_cast<microseconds>(consequent->get_after() - cause.input_->get_after());
686  lhs_duration = duration_cast<microseconds>(cause.input_->get_before() - cause.input_->get_after());
687  rhs_duration = duration_cast<microseconds>(consequent->get_before() - consequent->get_after());
688  guard_builder = new TimingGuardBuilder(period);// TODO: use the durations.
689 
690  vector<FindFIcstResult> results;
691  P<Code> new_cst;
692  find_f_icst(cause.input_, results, new_cst);
693  if (results.size() == 0) {
694 
695  if (build_mdl(cause.input_, NULL, consequent, guard_builder, period))
696  inject_hlps(analysis_starting_time);
697  } else {
698 
699  if (build_mdl(results[0].f_icst, results[0].component_pattern, consequent, guard_builder, period, new_cst))
700  inject_hlps(analysis_starting_time);
701  }
702  ++i;
703  }
704 }
705 
706 bool GTPX::build_mdl(_Fact *cause, _Fact* f_icst, _Fact *consequent, GuardBuilder *guard_builder, microseconds period) {
707  if (consequent->is_anti_fact()) {
708  // Special handling to build a model with the consequent is an anti-fact.
709  // Find the requirement cst now.
710  vector<FindFIcstResult> results;
711  if (!!f_icst)
712  // Use the provided f_icst.
713  results.push_back(FindFIcstResult(f_icst, NULL));
714  else {
715  P<Code> new_cst;
716  find_f_icst(target_->get_goal()->get_target(), results, new_cst);
717  if (results.size() == 0)
718  return false;
719  _Fact* f_icst = results[0].f_icst;
720  }
721 
722  P<HLPBindingMap> bm = new HLPBindingMap();
723  _Fact* goal_target = target_->get_goal()->get_target();
724  bm->init(goal_target->get_reference(0), MK_VAL_VALUE);
725  // The target is in the consequent frame but we want the pre-requisite frame.
726  bm->init(f_icst, FACT_AFTER);
727  bm->init(f_icst, FACT_BEFORE);
728 
729  uint16 write_index;
730  // Set allow_shared_timing_vars false. See BindingMap::abstract_fact .
731  P<Code> m0 = build_mdl_head(bm, 3, cause, consequent, write_index, false);
732  guard_builder->build(m0, NULL, cause, write_index);
733  build_mdl_tail(m0, write_index);
734  // Existence checks performed in build_requirement.
735  return build_requirement(bm, m0, period + milliseconds(20), results, NULL);
736  }
737 
738  P<BindingMap> bm = new BindingMap();
739 
740  uint16 write_index;
741  P<Code> m0 = build_mdl_head(bm, 0, cause, consequent, write_index);
742  guard_builder->build(m0, NULL, cause, write_index);
743  build_mdl_tail(m0, write_index);
744 
745  Code *_m0 = ModelBase::Get()->check_existence(m0);
746  if (_m0 == NULL)
747  return false;
748  else if (_m0 == m0) {
749 
750  mdls_.push_back(m0);
751  return true;
752  } else
753  return false;
754 }
755 
756 bool GTPX::build_mdl(_Fact *f_icst, _Fact *cause_pattern, _Fact *consequent, GuardBuilder *guard_builder, microseconds period, Code *new_cst) {
757 
758  P<BindingMap> bm = new BindingMap();
759 
760  uint16 write_index;
761  P<Code> m0 = build_mdl_head(bm, 0, f_icst, consequent, write_index);
762  guard_builder->build(m0, NULL, cause_pattern, write_index);
763  build_mdl_tail(m0, write_index);
764 
765  Code *_m0 = ModelBase::Get()->check_existence(m0);
766  if (_m0 == NULL)
767  return false;
768  else if (_m0 == m0) {
769 
770  if (new_cst)
771  csts_.push_back(new_cst);
772  mdls_.push_back(m0);
773  return true;
774  } else // if m0 already exist, new_cst==NULL.
775  return false;
776 }
777 
778 std::string GTPX::get_header() const {
779 
780  return std::string("GTPX");
781 }
782 
784 
785 PTPX::PTPX(AutoFocusController *auto_focus, _Fact *target, _Fact *pattern, BindingMap *bindings, Fact *f_imdl) : _TPX(auto_focus, target, pattern, bindings), f_imdl_(f_imdl) {
786 }
787 
788 PTPX::~PTPX() {
789 }
790 
791 void PTPX::signal(View *input) const { // will be erased from the AF map upon return. P<> kept in reduction job.
792 
793  if (!auto_focus_->ptpx_on())
794  return;
795 
796  if (((_Fact *)input->object_)->is_anti_fact()) { // prediction failure.
797 
798  ReductionJob<PTPX> *j = new ReductionJob<PTPX>(new View(input), (PTPX *)this);
799 #ifdef WITH_DETAIL_OID
800  OUTPUT_LINE((TraceLevel)0, " make ReductionJob<PTPX> " << j->get_job_id() << "(" << j->get_detail_oid() <<
801  "): controller(" << get_detail_oid() << ")->reduce(View(fact_" << input->object_->get_oid() << "))");
802 #endif
803  _Mem::Get()->push_reduction_job(j);
804  }
805 }
806 
807 void PTPX::reduce(r_exec::View *input) {
808 
809  auto_focus_->copy_cross_buffer(inputs_); // the cause of the prediction failure comes before the prediction.
810 
811  auto analysis_starting_time = Now();
812 
813  // input->object is the prediction failure: ignore and consider |f->imdl instead.
814  Fact* f_imdl = (Fact *)f_imdl_;
815  Timestamp f_imdl_after = f_imdl->get_after();
816  Timestamp f_imdl_before = f_imdl->get_before();
817  // Use the timestamps in the template parameters, similar to PrimaryMDLController::abduce_imdl.
818  // This is to make it symmetric with the timestamp in the forward chaining requirement.
819  MDLController::get_imdl_template_timings(f_imdl->get_reference(0), f_imdl_after, f_imdl_before);
820  P<_Fact> consequent = new Fact(f_imdl->get_reference(0), f_imdl_after, f_imdl_before, f_imdl->get_cfd(), f_imdl->get_psln_thr());
821  consequent->set_opposite();
822 
823  vector<Input> discarded_f_mk_vals;
824  vector<Input> discarded_f_icsts;
825  vector<Code*> accepted_mk_vals;
826 
827  P<BindingMap> end_bm = new BindingMap();
828  {
829  // Call abstract_object only to update the binding map.
830  P<Code> unused = end_bm->abstract_object(consequent, false);
831  }
833  for (i = inputs_.begin(); i != inputs_.end();) { // filter out inputs irrelevant for the prediction.
834 
835  if (i->input_->get_reference(0)->code(0).asOpcode() == Opcodes::Cmd)
836  // no cmds as req lhs (because no bwd-operational); prefer: cmd->effect, effect->imdl.
837  i = inputs_.erase(i);
838  else if (i->input_->get_after() > consequent->get_after())
839  // discard inputs that started after the consequent started.
840  i = inputs_.erase(i);
841  else if (!end_bm->intersect(i->bindings_)) {
842  // discard inputs that do not share values with the consequent.
843  if (i->input_->get_reference(0)->code(0).asOpcode() == Opcodes::MkVal &&
844  !_Mem::Get()->matches_axiom(i->input_->get_reference(0)))
845  // Save for below.
846  discarded_f_mk_vals.push_back(*i);
847  else if (i->input_->get_reference(0)->code(0).asOpcode() == Opcodes::ICst)
848  // Save for below.
849  discarded_f_icsts.push_back(*i);
850 
851  i = inputs_.erase(i);
852  }
853  else {
854  if (i->input_->get_reference(0)->code(0).asOpcode() == Opcodes::MkVal &&
855  !_Mem::Get()->matches_axiom(i->input_->get_reference(0)))
856  // Save for below.
857  accepted_mk_vals.push_back(i->input_->get_reference(0));
858 
859  ++i;
860  }
861  }
862 
863  // Only keep discarded mk.vals that share "attribute, value" with at least one accepted mk.val.
864  for (auto f_mk_val = discarded_f_mk_vals.begin(); f_mk_val != discarded_f_mk_vals.end();) {
865  bool match = false;
866  for (auto accepted = accepted_mk_vals.begin(); accepted != accepted_mk_vals.end(); ++accepted) {
867  // Skip the mk.val object. Start matching from the attribute.
868  if (_Fact::Match(f_mk_val->input_->get_reference(0), 0, MK_VAL_ATTR,
869  *accepted, MK_VAL_ATTR, MK_VAL_ARITY)) {
870  match = true;
871  break;
872  }
873  }
874 
875  if (match) {
876  // Restore as an accepted input.
877  inputs_.push_back(Input(*f_mk_val));
878  ++f_mk_val;
879  }
880  else
881  f_mk_val = discarded_f_mk_vals.erase(f_mk_val);
882  }
883 
884  // Find discarded f_icsts which have a discarded mk.val (which shares an "attribute, value" with an accepted mk.val).
885  for (auto f_icst = discarded_f_icsts.begin(); f_icst != discarded_f_icsts.end(); ++f_icst) {
886  bool contains = false;
887  for (auto f_mk_val = discarded_f_mk_vals.begin(); f_mk_val != discarded_f_mk_vals.end(); ++f_mk_val) {
888  if (((ICST*)f_icst->input_->get_reference(0))->r_contains(f_mk_val->input_)) {
889  contains = true;
890  break;
891  }
892  }
893 
894  if (contains)
895  // Restore as an accepted input.
896  inputs_.push_back(Input(*f_icst));
897  }
898 
899  P<GuardBuilder> guard_builder;
900  microseconds period;
901  microseconds lhs_duration;
902  microseconds rhs_duration;
903 
904  for (i = inputs_.begin(); i != inputs_.end(); ++i) {
905 
906  if (i->input_->get_reference(0)->code(0).asOpcode() == Opcodes::ICst)
907  continue; // components will be evaluated first, then the icst will be identified.
908 
909  Input cause = *i;
910 
911  if (!cause.eligible_cause_)
912  continue;
913 
914  period = duration_cast<microseconds>(consequent->get_after() - cause.input_->get_after());
915  lhs_duration = duration_cast<microseconds>(cause.input_->get_before() - cause.input_->get_after());
916  rhs_duration = duration_cast<microseconds>(consequent->get_before() - consequent->get_after());
917  if (period.count() == 0 && lhs_duration == rhs_duration)
918  // The LHS and RHS timings are the same, so we don't need guards. This often happens if the timings of the
919  // RHS imdl came from an icst.
920  guard_builder = new GuardBuilder();
921  else
922  guard_builder = new TimingGuardBuilder(period); // TODO: use the durations.
923 
924  vector<FindFIcstResult> results;
925  P<Code> new_cst;
926  find_f_icst(cause.input_, results, new_cst, true);
927  if (results.size() == 0) {
928 
929  if (build_mdl(cause.input_, consequent, guard_builder, period))
930  inject_hlps(analysis_starting_time);
931  } else {
932 
933  for (size_t i = 0; i < results.size(); ++i) {
934  if (build_mdl(results[i].f_icst, results[i].component_pattern, consequent, guard_builder, period, new_cst))
935  inject_hlps(analysis_starting_time);
936  }
937 
938  if (!new_cst) {
939  // find_f_icst returned results without making a new cst. Check if we can make one.
940  _Fact* cause_pattern;
941  P<_Fact> f_icst = make_f_icst(cause.input_, cause_pattern, new_cst);
942  if (!!f_icst) {
943  if (build_mdl(f_icst, cause_pattern, consequent, guard_builder, period, new_cst))
944  inject_hlps(analysis_starting_time);
945  }
946  }
947  }
948  }
949 }
950 
951 bool PTPX::build_mdl(_Fact *cause, _Fact *consequent, GuardBuilder *guard_builder, microseconds period) {
952 
953  P<BindingMap> bm = new BindingMap();
954 
955  uint16 write_index;
956  P<Code> m0 = build_mdl_head(bm, 0, cause, consequent, write_index);
957  guard_builder->build(m0, NULL, cause, write_index);
958  build_mdl_tail(m0, write_index);
959 
960  Code *_m0 = ModelBase::Get()->check_existence(m0);
961  if (_m0 == NULL)
962  return false;
963  else if (_m0 == m0) {
964 
965  mdls_.push_back(m0);
966  return true;
967  } else
968  return false;
969 }
970 
971 bool PTPX::build_mdl(_Fact *f_icst, _Fact *cause_pattern, _Fact *consequent, GuardBuilder *guard_builder, microseconds period, Code *new_cst) {
972 
973  P<BindingMap> bm = new BindingMap();
974 
975  uint16 write_index;
976  P<Code> m0 = build_mdl_head(bm, 0, f_icst, consequent, write_index);
977  guard_builder->build(m0, NULL, cause_pattern, write_index);
978  build_mdl_tail(m0, write_index);
979 
980  Code *_m0 = ModelBase::Get()->check_existence(m0);
981  if (_m0 == NULL)
982  return false;
983  else if (_m0 == m0) {
984 
985  if (new_cst)
986  csts_.push_back(new_cst);
987  mdls_.push_back(m0);
988  return true;
989  } else // if m0 already exist, new_cst==NULL.
990  return false;
991 }
992 
993 std::string PTPX::get_header() const {
994 
995  return std::string("PTPX");
996 }
997 
999 
1000 CTPX::CTPX(AutoFocusController *auto_focus, View *premise) : _TPX(auto_focus, premise->object_), stored_premise_(false), premise_(premise) {
1001 }
1002 
1003 CTPX::~CTPX() {
1004 }
1005 
1006 void CTPX::store_input(r_exec::View *input) {
1007 
1008  _Fact *input_object = (_Fact *)input->object_;
1009  P<BindingMap> bm = new BindingMap();
1010  _Fact *abstracted_input = (_Fact *)bm->abstract_object(input_object, false);
1011  Input i(input, abstracted_input, bm);
1012  inputs_.push_front(i);
1013  if (input_object == target_)
1014  stored_premise_ = true;
1015 }
1016 
1017 void CTPX::signal(r_exec::View *input) {
1018 
1019  View *_view = new View(input); // controller not copied.
1020  ReductionJob<CTPX> *j = new ReductionJob<CTPX>(_view, this); // holds a reference to this.
1021 #ifdef WITH_DETAIL_OID
1022  OUTPUT_LINE((TraceLevel)0, " make ReductionJob " << j->get_job_id() << "(" << j->get_detail_oid() <<
1023  "): CTPX(" << get_detail_oid() << ")->reduce(View(fact_" << input->object_->get_oid() << "))");
1024 #endif
1025  _Mem::Get()->push_reduction_job(j);
1026 }
1027 
1028 void CTPX::reduce(r_exec::View *input) {
1029 
1030  auto analysis_starting_time = Now();
1031 
1032  if (!stored_premise_)
1033  inputs_.push_back(Input(premise_, abstracted_target_, target_bindings_));
1034 
1035  _Fact *consequent = (_Fact *)input->object_; // counter-evidence for the premise.
1036 
1037  P<BindingMap> end_bm = new BindingMap();
1038  {
1039  // Call abstract_object only to update the binding map.
1040  P<Code> unused = end_bm->abstract_object(consequent, false);
1041  }
1042 
1043  bool have_delta = false;
1044  BindingMap bm_with_delta;
1045  if (target_->get_reference(0)->code(0).asOpcode() == Opcodes::MkVal) {
1046  // This is the same as the searched_for delta in find_guard_builder.
1047  float32 delta = consequent->get_reference(0)->code(MK_VAL_VALUE).asFloat() -
1048  target_->get_reference(0)->code(MK_VAL_VALUE).asFloat();
1049  if (delta != 0) {
1050  have_delta = true;
1051  P<Code> delta_code(new LObject());
1052  delta_code->code(0) = Atom::Float(delta);
1053  bm_with_delta.init(delta_code, 0);
1054  }
1055  }
1056 
1057  // Add an imdl to this set if the loop would discard it for not sharing values with
1058  // the target or consequent, but it does share delta.
1059  set<_Fact*> only_intersects_delta_imdls;
1060 
1062  for (i = inputs_.begin(); i != inputs_.end();) {
1063 
1064  if (i->input_->get_reference(0)->code(0).asOpcode() == Opcodes::ICst) {
1065  // Require each icst component to share values with the target or consequent.
1066  bool icstIsOK = true;
1067  ICST *icst = (ICST*)i->input_->get_reference(0);
1068  for (uint32 j = 0; j < icst->components_.size(); ++j) {
1069  P<BindingMap> component_bm = new BindingMap();
1070  {
1071  // Call abstract_object only to update the binding map.
1072  P<Code> unused = component_bm->abstract_object(icst->components_[j], false);
1073  }
1074  if (!(target_bindings_->intersect(component_bm) || end_bm->intersect(component_bm))) {
1075  icstIsOK = false;
1076  break;
1077  }
1078  }
1079 
1080  if (!icstIsOK ||
1081  i->input_->get_after() >= consequent->get_after()) // discard inputs not younger than the consequent.
1082  i = inputs_.erase(i);
1083  else
1084  ++i;
1085  continue;
1086  }
1087 
1088  if (i->input_->get_after() >= consequent->get_after())
1089  // Discard inputs not younger than the consequent.
1090  i = inputs_.erase(i);
1091  else if (!(target_bindings_->intersect(i->bindings_) || end_bm->intersect(i->bindings_))) {
1092  // Discard inputs that do not share values with the target or consequent.
1093  // However, allow an imdl which has the delta value.
1094  if (have_delta && i->input_->get_reference(0)->code(0).asOpcode() == Opcodes::IMdl &&
1095  bm_with_delta.intersect(i->bindings_)) {
1096  only_intersects_delta_imdls.insert(i->input_);
1097  ++i;
1098  }
1099  else
1100  i = inputs_.erase(i);
1101  }
1102  else
1103  ++i;
1104  }
1105 
1106  bool need_guard = false;
1107  if (target_->get_reference(0)->code(0).asOpcode() == Opcodes::MkVal) {
1108  Atom target_val = target_->get_reference(0)->code(MK_VAL_VALUE);
1109  if (target_val.isFloat())
1110  need_guard = true;
1111  else if (target_val.getDescriptor() == Atom::I_PTR) {
1112  if (hasUserDefinedOperators(target_->get_reference(0)->code(target_val.asIndex()).asOpcode()))
1113  need_guard = true;
1114  }
1115  }
1116 
1117  auto period = duration_cast<microseconds>(Utils::GetTimestamp<Code>(consequent, FACT_AFTER) - Utils::GetTimestamp<Code>(target_, FACT_AFTER)); // sampling period.
1118  P<GuardBuilder> guard_builder;
1119 
1120  for (i = inputs_.begin(); i != inputs_.end(); ++i) {
1121 
1122  if (target_ == i->input_)
1123  continue;
1124 
1125  if (i->input_->get_reference(0)->code(0).asOpcode() == Opcodes::ICst)
1126  continue; // components will be evaluated first, then the icst will be identified.
1127 
1128  Input cause = *i;
1129 
1130  if (!cause.eligible_cause_)
1131  continue;
1132 
1133  if (Utils::Synchronous(cause.input_->get_after(), target_->get_after())) // cause in sync with the premise: ignore.
1134  continue;
1135 
1136  // If the LHS cause is an imdl, assume that the default guard builder will be sufficient.
1137  // However, if the cause is an imdl where a value is delta (see above), call find_guard_builder.
1138  if (need_guard && (cause.input_->get_reference(0)->code(0).asOpcode() != Opcodes::IMdl ||
1139  only_intersects_delta_imdls.find(cause.input_) != only_intersects_delta_imdls.end())) {
1140 
1141  if ((guard_builder = find_guard_builder(cause.input_, consequent, period)) == NULL)
1142  continue;
1143  } else
1144  guard_builder = get_default_guard_builder(cause.input_, consequent, period);
1145 
1146  vector<FindFIcstResult> results;
1147  find_f_icst(cause.input_, results);
1148  if (results.size() == 0) { // m0:[premise.value premise.after premise.before][cause->consequent] and m1:[lhs1->imdl m0[...][...]] with lhs1 either the premise or an icst containing the premise.
1149 
1150  if (build_mdl(cause.input_, consequent, guard_builder, period))
1151  inject_hlps(analysis_starting_time);
1152  } else {
1153 
1154  // m0:[premise.value premise.after premise.before][icst->consequent] and m1:[lhs1->imdl m0[...][...]]
1155  // with lhs1 either the premise or an icst containing the premise.
1156  if (build_mdl(results[0].f_icst, results[0].component_pattern, consequent, guard_builder, period))
1157  inject_hlps(analysis_starting_time);
1158  }
1159  }
1160 }
1161 
1162 GuardBuilder *CTPX::get_default_guard_builder(_Fact *cause, _Fact *consequent, microseconds period) {
1163 
1164  Code *cause_payload = cause->get_reference(0);
1165  uint16 opcode = cause_payload->code(0).asOpcode();
1166  if (opcode == Opcodes::Cmd || opcode == Opcodes::IMdl) {
1167 
1168  auto offset = duration_cast<microseconds>(consequent->get_after() - cause->get_after());
1169  auto cmd_duration = duration_cast<microseconds>(cause->get_before() - cause->get_after());
1170  return new NoArgCmdGuardBuilder(period, offset, cmd_duration);
1171  }
1172 
1173  return new TimingGuardBuilder(period);
1174 }
1175 
1176 // Forms:
1177 // 1A - q1=q0+cmd_arg (if the cause is a cmd)
1178 // 1B - q1=q0*cmd_arg with q0 != 0 (if the cause is a cmd)
1179 // 2 - q1=q0+speed*period, with q1=consequent.value, q0=premise.value, speed=cause.value
1180 // 3A - q1=q0*constant with q0 != 0.
1181 // 3B - q1=q0+constant
1182 GuardBuilder *CTPX::find_guard_builder(_Fact *cause, _Fact *consequent, microseconds period) {
1183 
1184  Code *cause_payload = cause->get_reference(0);
1185  uint16 opcode = cause_payload->code(0).asOpcode();
1186  if (opcode == Opcodes::Cmd) {
1187  uint16 cmd_arg_set_index = cause_payload->code(CMD_ARGS).asIndex();
1188  uint16 cmd_arg_count = cause_payload->code(cmd_arg_set_index).getAtomCount();
1189 
1190  // Form 1
1191  // Form 1A
1192  // Build the expression (- q1 q0), copying the code structure at q1 and q0 and evaluate it.
1193  auto result = OpContext::build_and_evaluate_expression(target_, consequent, Atom::Operator(Opcodes::Sub, 2));
1194 
1195  //Check whether a valid result was returned.
1196  int index = -1;
1197  for (size_t i = 0; i < result.size(); ++i) {
1198  if (result[i] != Atom::Nil()) {
1199  index = i;
1200  break;
1201  }
1202  }
1203  // Match the result to the cause_payload.
1204  if (index != -1) {
1205  LocalObject searched_for;
1206  uint16 extent_index = 0;
1207  StructureValue::copy_structure(&searched_for, extent_index, &result[index], 0);
1208 
1209  for (uint16 i = 1; i <= cmd_arg_count; ++i) {
1210  Atom s = cause_payload->code(cmd_arg_set_index + i);
1211  uint16 cmd_index = cmd_arg_set_index + i;
1212  bool match = false;
1213  if (s.getDescriptor() == Atom::I_PTR) {
1214  cmd_index = s.asIndex();
1215  match = _Fact::MatchStructure(cause_payload, cmd_index, 0, &searched_for, 0, s.getAtomCount());
1216  }
1217  else {
1218  match = _Fact::Match(cause_payload, cmd_index, 0, &searched_for, 0, s.getAtomCount());
1219  }
1220  if (match) {
1221  auto offset = duration_cast<microseconds>(Utils::GetTimestamp<Code>(cause, FACT_AFTER) - Utils::GetTimestamp<Code>(target_, FACT_AFTER));
1222  return new ACGuardBuilder(period, period - offset, cmd_arg_set_index + i);
1223  }
1224  }
1225  }
1226 
1227  // Form 1B
1228  // Build the expression (/ q1 q0), copying the code structure at q1 and q0 and evaluate it.
1229  result = OpContext::build_and_evaluate_expression(target_, consequent, Atom::Operator(Opcodes::Div, 2));
1230 
1231  //Check whether a valid result was returned.
1232  index = -1;
1233  for (int i = 0; i < result.size(); ++i) {
1234  if (result[i] != Atom::Nil()) {
1235  index = i;
1236  break;
1237  }
1238  }
1239 
1240  // Match the result to the cause_payload.
1241  if (index != -1) {
1242  LocalObject searched_for;
1243  uint16 extent_index = 0;
1244  StructureValue::copy_structure(&searched_for, extent_index, &result[index], 0);
1245  for (uint16 i = 1; i <= cmd_arg_count; ++i) {
1246  Atom s = cause_payload->code(cmd_arg_set_index + i);
1247  uint16 cmd_index = cmd_arg_set_index + i;
1248  bool match = false;
1249  if (s.getDescriptor() == Atom::I_PTR) {
1250  cmd_index = s.asIndex();
1251  match = _Fact::MatchStructure(cause_payload, cmd_index, 0, &searched_for, 0, s.getAtomCount());
1252  }
1253  else {
1254  match = _Fact::Match(cause_payload, cmd_index, 0, &searched_for, 0, s.getAtomCount());
1255  }
1256  if (match) {
1257  auto offset = duration_cast<microseconds>(Utils::GetTimestamp<Code>(cause, FACT_AFTER) - Utils::GetTimestamp<Code>(target_, FACT_AFTER));
1258  return new MCGuardBuilder(period, period - offset, cmd_arg_set_index + i);
1259  }
1260  }
1261  }
1262  }
1263  else if (opcode == Opcodes::IMdl) {
1264  // Form 1
1265  float32 q0 = target_->get_reference(0)->code(MK_VAL_VALUE).asFloat();
1266  float32 q1 = consequent->get_reference(0)->code(MK_VAL_VALUE).asFloat();
1267 
1268  // Form 1A
1269  float32 searched_for = q1 - q0;
1270  Code* imdl = cause->get_reference(0);
1271  uint16 imdl_exposed_args_index = imdl->code(I_HLP_EXPOSED_ARGS).asIndex();
1272  uint16 imdl_exposed_args_count = imdl->code(imdl_exposed_args_index).getAtomCount();
1273 
1274  for (uint16 i = 1; i <= imdl_exposed_args_count; ++i) {
1275 
1276  Atom s = imdl->code(imdl_exposed_args_index + i);
1277  if (!s.isFloat())
1278  continue;
1279  float32 _s = s.asFloat();
1280  if (Utils::Equal(_s, searched_for)) {
1281  auto offset = duration_cast<microseconds>(Utils::GetTimestamp<Code>(cause, FACT_AFTER) - Utils::GetTimestamp<Code>(target_, FACT_AFTER));
1282  // Use the exposed args index in what will be the abstracted imdl.
1283  return new ACGuardBuilder(period, period - offset, BindingMap::get_abstracted_ihlp_exposed_args_index(imdl) + i);
1284  }
1285  }
1286 
1287  if (q0 != 0) {
1288  // Form 1B
1289  searched_for = q1 / q0;
1290  for (uint16 i = imdl_exposed_args_index + 1; i <= imdl_exposed_args_count; ++i) {
1291 
1292  Atom s = imdl->code(i);
1293  if (!s.isFloat())
1294  continue;
1295  float32 _s = s.asFloat();
1296  if (Utils::Equal(_s, searched_for)) {
1297  auto offset = duration_cast<microseconds>(Utils::GetTimestamp<Code>(cause, FACT_AFTER) - Utils::GetTimestamp<Code>(target_, FACT_AFTER));
1298  // Use the exposed args index in what will be the abstracted imdl.
1299  return new MCGuardBuilder(period, period - offset,
1300  (i - imdl_exposed_args_index) + BindingMap::get_abstracted_ihlp_exposed_args_index(imdl));
1301  }
1302  }
1303  }
1304  }
1305 
1306  else if (opcode == Opcodes::MkVal) {
1307  // Forms 2 and 3
1308  Atom s = cause_payload->code(MK_VAL_VALUE);
1309  if (s.isFloat()) {
1310 
1311  float32 _s = s.asFloat();
1312  float32 q0 = target_->get_reference(0)->code(MK_VAL_VALUE).asFloat();
1313  float32 q1 = consequent->get_reference(0)->code(MK_VAL_VALUE).asFloat();
1314 
1315  // Form 2
1316  float32 searched_for = (q1 - q0) / period.count();
1317  if (Utils::Equal(_s, searched_for)) {
1318 
1319  auto offset = duration_cast<microseconds>(Utils::GetTimestamp<Code>(cause, FACT_AFTER) - Utils::GetTimestamp<Code>(target_, FACT_AFTER));
1320  return new SGuardBuilder(period, period - offset);
1321  }
1322 
1323  if (q0 != 0) {
1324  // Form 3A
1325  auto offset = duration_cast<microseconds>(Utils::GetTimestamp<Code>(cause, FACT_AFTER) - Utils::GetTimestamp<Code>(target_, FACT_AFTER));
1326  return new MGuardBuilder(period, q1 / q0, offset);
1327  }
1328 
1329  // Form 3B
1330  auto offset = duration_cast<microseconds>(Utils::GetTimestamp<Code>(cause, FACT_AFTER) - Utils::GetTimestamp<Code>(target_, FACT_AFTER));
1331  return new AGuardBuilder(period, q1 - q0, offset);
1332  }
1333  }
1334 
1335  return NULL;
1336 }
1337 
1338 
1339 
1340 
1341 // m0:[premise.value premise.after premise.before][cause->consequent].
1342 // m1:[icst->imdl m0[...][...]] with icst containing the premise.
1343 bool CTPX::build_mdl(_Fact *cause, _Fact *consequent, GuardBuilder *guard_builder, microseconds period) {
1344 
1345  P<HLPBindingMap> bm = new HLPBindingMap();
1346  bm->init(target_->get_reference(0), MK_VAL_VALUE);
1347  bm->init(target_, FACT_AFTER);
1348  bm->init(target_, FACT_BEFORE);
1349 
1350  uint16 write_index;
1351  // Set allow_shared_timing_vars false. See BindingMap::abstract_fact .
1352  // NOTE: This solution is strictly temporary. We should have a heuristic for comparing time values which allows deviations. See https://github.com/IIIM-IS/replicode/pull/110 .
1353  P<Code> m0 = build_mdl_head(bm, 3, cause, consequent, write_index, false);
1354  guard_builder->build(m0, NULL, cause, write_index);
1355  build_mdl_tail(m0, write_index);
1356  return build_requirement(bm, m0, period); // existence checks performed there.
1357 }
1358 
1359 // m0:[premise.value premise.after premise.before][icst->consequent] with icst containing the cause.
1360 // m1:[icst->imdl m0[...][...]] with icst containing the premise.
1361 bool CTPX::build_mdl(_Fact *f_icst, _Fact *cause_pattern, _Fact *consequent, GuardBuilder *guard_builder, microseconds period) {
1362 
1363  P<BindingMap> bm = new BindingMap();
1364  bm->init(target_->get_reference(0), MK_VAL_VALUE);
1365  bm->init(target_, FACT_AFTER);
1366  bm->init(target_, FACT_BEFORE);
1367 
1368  uint16 write_index;
1369  Code *m0 = build_mdl_head(bm, 3, f_icst, consequent, write_index);
1370  guard_builder->build(m0, NULL, cause_pattern, write_index);
1371  build_mdl_tail(m0, write_index);
1372 
1373  return build_requirement(bm, m0, period); // existence checks performed there.
1374 }
1375 
1376 bool CTPX::build_requirement(HLPBindingMap *bm, Code *m0, microseconds period) { // check for mdl existence at the same time (ModelBase::mdlCS_-wise).
1377 
1378  vector<FindFIcstResult> results;
1379  P<Code> new_cst;
1380  find_f_icst(target_, results, new_cst);
1381  if (results.size() == 0)
1382  return false;
1383 
1384  return _TPX::build_requirement(bm, m0, period, results, new_cst);
1385 }
1386 
1387 bool _TPX::build_requirement(HLPBindingMap* bm, Code* m0, microseconds period, const vector<FindFIcstResult>& results, Code* new_cst) {
1388  _Fact* f_icst = results[0].f_icst;
1389  _Fact* premise_pattern = results[0].component_pattern;
1390  P<Fact> f_im0 = bm->build_f_ihlp(m0, Opcodes::IMdl, false);
1391  // build_f_ihlp can leave some variables pointing into bm, but abstract_object needs everything valuated.
1392  f_im0->set_reference(0, bm->bind_pattern(f_im0->get_reference(0)));
1393  Utils::SetTimestamp<Code>(f_im0, FACT_AFTER, f_icst->get_after());
1394  Utils::SetTimestamp<Code>(f_im0, FACT_BEFORE, f_icst->get_before());
1395 
1396  P<BindingMap> _bm = new BindingMap();
1397 
1398  uint16 write_index;
1399  P<Code> m1 = build_mdl_head(_bm, 0, f_icst, f_im0, write_index);
1400  P<GuardBuilder> guard_builder = new GuardBuilder();
1401  guard_builder->build(m1, premise_pattern, NULL, write_index);
1402  build_mdl_tail(m1, write_index);
1403 
1404  // Search m0 RHS for variables and check if the variable is mentioned elsewhere.
1405  // See https://github.com/IIIM-IS/AERA/pull/281 for the explanation of this algorithm.
1406  Code* rhs_object = m0->get_reference(1)->get_reference(0);
1407  for (uint16 i = 0; i < rhs_object->code_size(); ++i) {
1408  Atom v = rhs_object->code(i);
1409  if (v.getDescriptor() == Atom::VL_PTR) {
1410  // Check the LHS of m0 and the rest of the m0.
1411  if (!(m0->get_reference(0)->get_reference(0)->includes(v) || m0->includes(v))) {
1412  // Find the corresponding position of v in m1 RHS exposed args.
1413  int16 exposed_args_position = bm->get_ihlp_exposed_args_position(v.asIndex());
1414  if (exposed_args_position >= 0) {
1415  Code* m1_rhs_object = m1->get_reference(1)->get_reference(0);
1416  uint16 i_exposed_args = m1_rhs_object->code(I_HLP_EXPOSED_ARGS).asIndex();
1417  Atom m1_rhs_var = m1_rhs_object->code(i_exposed_args + 1 + exposed_args_position);
1418  // Check the LHS of m1.
1419  if (!m1->get_reference(0)->get_reference(0)->includes(m1_rhs_var))
1420  // v is a free variable. Don't make a model where the RHS has a free variable.
1421  return false;
1422  }
1423  }
1424  }
1425  }
1426 
1427  Code *_m0;
1428  Code *_m1;
1429  ModelBase::Get()->check_existence(m0, m1, _m0, _m1);
1430  if (_m1 == NULL)
1431  return false;
1432  else if (_m1 == m1) {
1433 
1434  if (_m0 == NULL)
1435  return false;
1436  else if (_m0 == m0)
1437  mdls_.push_back(m0);
1438  if (!!new_cst)
1439  csts_.push_back(new_cst);
1440  mdls_.push_back(m1);
1441  } // if m1 alrady exists, new_cst==NULL.
1442  return true;
1443 }
1444 
1445 std::string CTPX::get_header() const {
1446 
1447  return std::string("CTPX");
1448 }
1449 }
r_exec::_TPX::_find_f_icst
void _find_f_icst(_Fact *component, std::vector< FindFIcstResult > &results, bool find_multiple)
Definition: pattern_extractor.cpp:261
r_code::list::const_iterator
Definition: list.h:266
r_exec::_TPX::find_f_icst
void find_f_icst(_Fact *component, std::vector< FindFIcstResult > &results, bool find_multiple=false)
r_exec::BindingMap::get_abstracted_ihlp_exposed_args_index
static uint16 get_abstracted_ihlp_exposed_args_index(const r_code::Code *ihlp)
Definition: binding_map.cpp:483
r_exec::ICST::contains
bool contains(const _Fact *component, uint16 &component_index) const
Definition: factory.cpp:930
r_exec::MkRdx
Definition: factory.h:588
r_exec::ConstBwdArgCmdGuardBuilder
Definition: guard_builder.h:234
r_exec::StructureValue::copy_structure
static void copy_structure(r_code::Code *destination, uint16 &extent_index, const Atom *source, uint16 source_index)
Definition: binding_map.cpp:242
r_exec::BindingMap
Definition: binding_map.h:248
r_code::Atom
Definition: atom.h:104
r_exec::GTPX::ack_pred_success
void ack_pred_success(Success *success) override
Definition: pattern_extractor.cpp:580
r_exec::_Fact
Definition: factory.h:155
r_exec::MDLController::get_imdl_template_timings
static bool get_imdl_template_timings(r_code::Code *imdl, Timestamp &after, Timestamp &before, uint16 *after_ts_index=NULL, uint16 *before_ts_index=NULL)
Definition: mdl_controller.cpp:1102
r_exec::_TPX::FindFIcstResult
Definition: pattern_extractor.h:192
r_exec::ICST
Definition: factory.h:655
core::P
Definition: base.h:103
r_exec::Success::get_evidence
_Fact * get_evidence() const
Definition: factory.h:629
r_exec::_TPX::find_f_icst_component
static _Fact * find_f_icst_component(_Fact *fact, const _Fact *component, int max_depth=3)
Definition: pattern_extractor.cpp:235
r_code::Code
Definition: r_code/object.h:224
r_exec::Success
Definition: factory.h:607
core::_Object
Definition: base.h:131
r_code::list::iterator
Definition: list.h:295
r_exec::Success::get_object_mk_rdx
MkRdx * get_object_mk_rdx() const
Definition: factory.h:644
r_exec::View
Definition: view.h:102
r_code::LocalObject
Definition: r_code/object.h:377
r_code::time_buffer::iterator
Definition: time_buffer.h:108
r_code::time_buffer
Definition: time_buffer.h:99
r_code::list
Definition: list.h:99
r_exec::Success::get_object
_Fact * get_object() const
Definition: factory.h:617
r_exec::PMDLController
Definition: mdl_controller.h:332