AERA
cst_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 //_/_/ http://www.iiim.is
10 //_/_/
11 //_/_/ Copyright (c) 2010-2012 Eric Nivel
12 //_/_/ Center for Analysis and Design of Intelligent Agents
13 //_/_/ Reykjavik University, Menntavegur 1, 102 Reykjavik, Iceland
14 //_/_/ http://cadia.ru.is
15 //_/_/
16 //_/_/ Part of this software was developed by Eric Nivel
17 //_/_/ in the HUMANOBS EU research project, which included
18 //_/_/ the following parties:
19 //_/_/
20 //_/_/ Autonomous Systems Laboratory
21 //_/_/ Technical University of Madrid, Spain
22 //_/_/ http://www.aslab.org/
23 //_/_/
24 //_/_/ Communicative Machines
25 //_/_/ Edinburgh, United Kingdom
26 //_/_/ http://www.cmlabs.com/
27 //_/_/
28 //_/_/ Istituto Dalle Molle di Studi sull'Intelligenza Artificiale
29 //_/_/ University of Lugano and SUPSI, Switzerland
30 //_/_/ http://www.idsia.ch/
31 //_/_/
32 //_/_/ Institute of Cognitive Sciences and Technologies
33 //_/_/ Consiglio Nazionale delle Ricerche, Italy
34 //_/_/ http://www.istc.cnr.it/
35 //_/_/
36 //_/_/ Dipartimento di Ingegneria Informatica
37 //_/_/ University of Palermo, Italy
38 //_/_/ http://diid.unipa.it/roboticslab/
39 //_/_/
40 //_/_/
41 //_/_/ --- HUMANOBS Open-Source BSD License, with CADIA Clause v 1.0 ---
42 //_/_/
43 //_/_/ Redistribution and use in source and binary forms, with or without
44 //_/_/ modification, is permitted provided that the following conditions
45 //_/_/ are met:
46 //_/_/ - Redistributions of source code must retain the above copyright
47 //_/_/ and collaboration notice, this list of conditions and the
48 //_/_/ following disclaimer.
49 //_/_/ - Redistributions in binary form must reproduce the above copyright
50 //_/_/ notice, this list of conditions and the following disclaimer
51 //_/_/ in the documentation and/or other materials provided with
52 //_/_/ the distribution.
53 //_/_/
54 //_/_/ - Neither the name of its copyright holders nor the names of its
55 //_/_/ contributors may be used to endorse or promote products
56 //_/_/ derived from this software without specific prior
57 //_/_/ written permission.
58 //_/_/
59 //_/_/ - CADIA Clause: The license granted in and to the software
60 //_/_/ under this agreement is a limited-use license.
61 //_/_/ The software may not be used in furtherance of:
62 //_/_/ (i) intentionally causing bodily injury or severe emotional
63 //_/_/ distress to any person;
64 //_/_/ (ii) invading the personal privacy or violating the human
65 //_/_/ rights of any person; or
66 //_/_/ (iii) committing or preparing for any act of war.
67 //_/_/
68 //_/_/ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
69 //_/_/ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
70 //_/_/ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
71 //_/_/ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
72 //_/_/ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
73 //_/_/ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
74 //_/_/ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
75 //_/_/ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
76 //_/_/ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
77 //_/_/ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
78 //_/_/ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
79 //_/_/ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
80 //_/_/ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
81 //_/_/ OF SUCH DAMAGE.
82 //_/_/
83 //_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
84 
85 #include <algorithm>
86 #include "cst_controller.h"
87 #include "mem.h"
88 #include "hlp_context.h"
89 
90 using namespace std;
91 using namespace std::chrono;
92 using namespace r_code;
93 
94 namespace r_exec {
95 
96 CSTOverlay::CSTOverlay(Controller *c, HLPBindingMap *bindings) : HLPOverlay(c, bindings), match_deadline_(Timestamp(seconds(0))), lowest_cfd_(1) {
97 }
98 
99 CSTOverlay::CSTOverlay(const CSTOverlay *original) : HLPOverlay(original->controller_, original->bindings_) {
100 
101  axiom_patterns_ = original->axiom_patterns_;
102  non_axiom_patterns_ = original->non_axiom_patterns_;
103  predictions_ = original->predictions_;
104  simulations_ = original->simulations_;
105  match_deadline_ = original->match_deadline_;
106  lowest_cfd_ = original->lowest_cfd_;
107  axiom_inputs_ = original->axiom_inputs_;
108  non_axiom_inputs_ = original->non_axiom_inputs_;
109  defeasible_validities_ = original->defeasible_validities_;
110 }
111 
112 CSTOverlay::~CSTOverlay() {
113 }
114 
115 void CSTOverlay::load_patterns() {
116 
117  Code *object = ((HLPController *)controller_)->get_unpacked_object();
118  uint16 obj_set_index = object->code(CST_OBJS).asIndex();
119  uint16 obj_count = object->code(obj_set_index).getAtomCount();
120  for (uint16 i = 1; i <= obj_count; ++i) {
121 
122  _Fact *pattern = (_Fact *)object->get_reference(object->code(obj_set_index + i).asIndex());
123  if (pattern->references_size() >= 1 && _Mem::Get()->matches_axiom(pattern->get_reference(0)))
124  axiom_patterns_.push_back(pattern);
125  else
126  non_axiom_patterns_.push_back(pattern);
127  }
128 }
129 
130 bool CSTOverlay::can_match(Timestamp now) const { // to reach inputs until a given thz in the past, return now<deadline+thz.
131 
132  if (match_deadline_.time_since_epoch().count() == 0)
133  return true;
134  return now <= match_deadline_;
135 }
136 
138 
139  Fact *f_icst = ((CSTController *)controller_)->get_f_icst(bindings_, &axiom_inputs_, &non_axiom_inputs_);
140  auto now = Now();
141  string inputs_info;
142  for (uint32 i = 0; i < axiom_inputs_.size(); ++i)
143  inputs_info += " " + to_string(axiom_inputs_[i]->get_oid());
144  for (uint32 i = 0; i < non_axiom_inputs_.size(); ++i)
145  inputs_info += " " + to_string(non_axiom_inputs_[i]->get_oid());
146 
147  if (!is_simulated()) {
148 
149  auto before = bindings_->get_fwd_before();
150  Timestamp::duration time_to_live;
151  if (now >= before)
152  time_to_live = Timestamp::duration(seconds(0));
153  else
154  time_to_live = before - now;
155  if (predictions_.size()) {
156 
157  Pred *prediction = new Pred(f_icst, 1);
158  Fact *f_p_f_icst = new Fact(prediction, now, now, 1, 1);
159  unordered_set<P<_Fact>, PHash<_Fact> >::const_iterator pred;
160  for (pred = predictions_.begin(); pred != predictions_.end(); ++pred) // add antecedents to the prediction.
161  prediction->grounds_.push_back(*pred);
162  if (!((CSTController *)controller_)->inject_prediction(f_p_f_icst, lowest_cfd_, time_to_live)) // inject a f->pred->icst in the primary group, no rdx.
163  return NULL;
164 
165  string f_icst_info;
166 #ifdef WITH_DETAIL_OID
167  f_icst_info = "(" + to_string(f_icst->get_detail_oid()) + ") ";
168 #endif
169  OUTPUT_LINE(CST_OUT, Utils::RelativeTime(Now()) << " fact " << f_p_f_icst->get_oid() <<
170  " pred fact " << f_icst_info << "icst[" << controller_->get_object()->get_oid() << "][" << inputs_info << "]");
171  return f_p_f_icst;
172  } else {
173  ((CSTController *)controller_)->inject_icst(f_icst, lowest_cfd_, time_to_live); // inject f->icst in the primary and secondary groups, and in the output groups.
174 
175  OUTPUT_LINE(CST_OUT, Utils::RelativeTime(Now()) << " fact " << f_icst->get_oid() << " icst[" << controller_->get_object()->get_oid() << "][" <<
176  inputs_info << "]");
177  return f_icst;
178  }
179  } else { // there are simulations; the production is therefore a prediction; add the simulations to the latter.
180 
181  // Make a temporary copy of simulations_ for calling the Pred constructor.
182  vector<P<Sim>> simulations_copy;
183  for (auto sim = simulations_.begin(); sim != simulations_.end(); ++sim)
184  simulations_copy.push_back(*sim);
185  // Add the simulations to the prediction.
186  Pred *prediction = new Pred(f_icst, simulations_copy, 1);
187  if (((_Fact*)input->object_)->get_pred())
188  // Propagate the accumulated of DefeasibleValidity from all the inputs to the new prediction.
189  prediction->defeasible_validities_ = defeasible_validities_;
190  Fact *f_p_f_icst = new Fact(prediction, now, now, 1, 1);
191  if (!((HLPController *)controller_)->inject_prediction(f_p_f_icst, lowest_cfd_)) // inject a simulated prediction in the main group.
192  return NULL;
193  OUTPUT_LINE(CST_OUT, Utils::RelativeTime(Now()) << " cst " << get_object()->get_oid() << ": fact " <<
194  input->object_->get_oid() << " -> fact " << f_p_f_icst->get_oid() << " simulated pred fact icst [" <<
195  inputs_info << "]");
196  return f_p_f_icst;
197  }
198 }
199 
200 CSTOverlay *CSTOverlay::get_offspring(HLPBindingMap *map, _Fact *input, bool is_axiom, _Fact *bound_pattern) {
201 
202  CSTOverlay *offspring = new CSTOverlay(this);
203  if (bound_pattern) {
204  if (is_axiom)
205  axiom_patterns_.remove(bound_pattern);
206  else
207  non_axiom_patterns_.remove(bound_pattern);
208  }
209  if (match_deadline_.time_since_epoch().count() == 0)
210  match_deadline_ = map->get_fwd_before();
211  update(map, input, is_axiom);
212  return offspring;
213 }
214 
215 void CSTOverlay::update(HLPBindingMap *map, _Fact *input, bool is_axiom) {
216 
217  bindings_ = map;
218  if (is_axiom)
219  axiom_inputs_.push_back(input);
220  else
221  non_axiom_inputs_.push_back(input);
222  float32 last_cfd;
223  Pred *prediction = input->get_pred();
224  if (prediction) {
225 
226  last_cfd = prediction->get_target()->get_cfd();
227  if (prediction->is_simulation()) {
228 
229  for (uint16 i = 0; i < prediction->get_simulations_size(); ++i) {
230  auto predictionSimulation = prediction->get_simulation(i);
231  if (!get_simulation(predictionSimulation->get_root_sim()->root_))
232  // The simulations_ does not have a Sim with the same root_, so add.
233  simulations_.insert(predictionSimulation);
234  }
235  } else
236  predictions_.insert(input);
237 
238  // Accumulate the DefeasibleValidity objects from each input.
239  defeasible_validities_.insert(prediction->defeasible_validities_.begin(), prediction->defeasible_validities_.end());
240  } else
241  last_cfd = input->get_cfd();
242 
243  if (last_cfd < lowest_cfd_)
244  lowest_cfd_ = last_cfd;
245 }
246 
247 bool CSTOverlay::reduce(View *input, CSTOverlay *&offspring) {
248 
249  offspring = NULL;
250 
251  if (input->object_->is_invalidated())
252  return false;
253 
254  for (uint16 i = 0; i < axiom_inputs_.size(); ++i) { // discard inputs that already matched.
255 
256  if (axiom_inputs_[i]->is_invalidated()) {
257  // If we make an icst from this overlay, CSTController::get_f_icst will copy axiom_inputs_
258  // to the icst components_, and ICST::is_invalidated will see the invalidated
259  // component and mark the icst as invalidated before it is even injected. So just
260  // invalidate this overlay now.
261  invalidate();
262  return false;
263  }
264  if (((_Fact *)input->object_) == axiom_inputs_[i])
265  return false;
266  }
267  for (uint16 i = 0; i < non_axiom_inputs_.size(); ++i) { // discard inputs that already matched.
268 
269  if (non_axiom_inputs_[i]->is_invalidated()) {
270  // If we make an icst from this overlay, CSTController::get_f_icst will copy non_axiom_inputs_
271  // to the icst components_, and ICST::is_invalidated will see the invalidated
272  // component and mark the icst as invalidated before it is even injected. So just
273  // invalidate this overlay now.
274  invalidate();
275  return false;
276  }
277  if (((_Fact *)input->object_) == non_axiom_inputs_[i])
278  return false;
279  }
280  _Fact *input_object;
281  Pred *prediction = ((_Fact *)input->object_)->get_pred();
282  bool is_simulation;
283  Sim* predictionSimulation = NULL;
284  if (prediction) {
285 
286  input_object = prediction->get_target(); // input_object is f1 as in f0->pred->f1->object.
287  is_simulation = prediction->is_simulation();
288  // TODO: Handle a prediction with multiple simulations for different roots.
289  if (prediction->get_simulations_size() == 1)
290  predictionSimulation = prediction->get_simulation((uint16)0);
291  } else {
292 
293  input_object = (_Fact *)input->object_;
294  is_simulation = false;
295  }
296 
297  // If the prediction is already promoted, don't examine it again.
298  if (predictionSimulation && !prediction->is_promoted_ &&
299  (simulations_.size() == 0 || simulations_.size() == 1 && *simulations_.begin() == predictionSimulation)) {
300  // The input is for the same simulation as this overlay (or this overlay is non-simulated).
301  auto now = Now();
302  predictionSimulation->defeasible_promoted_facts_.CS_.enter();
303  // Check if the input defeats a promoted fact.
304  for (auto d = predictionSimulation->defeasible_promoted_facts_.list_.begin();
305  d != predictionSimulation->defeasible_promoted_facts_.list_.end(); ) {
306  if (input_object->is_evidence(d->promoted_fact_->get_pred()->get_target()) != MATCH_FAILURE) {
307  // The actual input fact matches (positive or negative) a defeasible promoted fact, so invalidated it.
308  predictionSimulation->defeating_facts_.push_back(input_object);
309  d->defeasible_validity_->invalidate();
310  string defeasible_validity_info;
311 #ifdef WITH_DETAIL_OID
312  defeasible_validity_info = " with DefeasibleValidity(" + to_string(d->defeasible_validity_->get_detail_oid()) + ")";
313 #endif
314  OUTPUT_LINE(CST_OUT, Utils::RelativeTime(now) << " promoted simulated fact " << d->promoted_fact_->get_oid() <<
315  defeasible_validity_info << " defeated by fact " << input->object_->get_oid());
316  // We don't need this entry any more.
317  d = predictionSimulation->defeasible_promoted_facts_.list_.erase(d);
318  }
319  else
320  ++d;
321  }
322 
323  // Only consider time intervals that are not zero duration.
324  bool input_is_later = (input_object->get_before() > input_object->get_after() && bindings_->has_fwd_before() &&
325  input_object->get_after() >= bindings_->get_fwd_before());
326  if (input_is_later &&
327  find(promoted_in_sim_.begin(), promoted_in_sim_.end(), predictionSimulation) == promoted_in_sim_.end()) {
328  // We have not already promoted inputs from this overlay to a later time in this Sim.
329  promoted_in_sim_.push_back(predictionSimulation);
330 
331  // Loop through this overlay's non-axiom saved inputs, checking if it needs to be promoted in this Sim.
332  // (Axiom facts are promoted by bind_pattern when binding a non-axiom fact.)
333  for (uint32 i = 0; i < non_axiom_inputs_.size(); ++i) {
334  _Fact* saved_input = non_axiom_inputs_[i];
335  Pred* saved_input_pred = saved_input->get_pred();
336  if (saved_input_pred)
337  saved_input = saved_input_pred->get_target();
338  if (saved_input->get_reference(0)->code(0).asOpcode() == Opcodes::ICst)
339  // Don't promote an icst. (Expect that its non-icst members will be promoted and re-make the composite icst.)
340  continue;
341 
342  // Note: has_original_fact uses pointer equality, so it is a quick check.
343  if (Sim::DefeasiblePromotedFact::has_original_fact(predictionSimulation->defeasible_promoted_facts_.list_, saved_input))
344  // We already checked for promoting this fact in this Sim.
345  continue;
346 
347  if (saved_input->is_timeless_evidence(input_object) != MATCH_FAILURE)
348  // The input is an actual fact which already matches (positive or negative) the overlay's saved input. We don't need to promote.
349  continue;
350 
351  // Make a new fact with the same Sim and timings as the input object.
352  Fact* promoted_fact = new Fact(saved_input->get_reference(0), input_object->get_after(), input_object->get_before(),
353  saved_input->get_cfd(), saved_input->get_psln_thr());
354  if (!saved_input->is_fact())
355  // The overlay's saved input is an anti-fact.
356  promoted_fact->set_opposite();
357 
358  bool matches_defeating_fact = false;
359  for (auto f = predictionSimulation->defeating_facts_.begin(); f != predictionSimulation->defeating_facts_.end(); ++f) {
360  if (promoted_fact->is_evidence(*f) != MATCH_FAILURE) {
361  matches_defeating_fact = true;
362  break;
363  }
364  }
365  if (matches_defeating_fact)
366  // The candidate promoted_fact matches (positive or negative) an actual fact already made for this Sim.
367  continue;
368 
369  Pred* p_promoted_fact = new Pred(promoted_fact, prediction, 1);
370  Fact* f_p_promoted_fact = new Fact(p_promoted_fact, now, now, 1, 1);
371 
372  // The promoted fact may be defeated by a predicted fact for the same time interval, so make it defeasible.
373  P<DefeasibleValidity> defeasible_validity = new DefeasibleValidity();
374  p_promoted_fact->defeasible_validities_.insert(defeasible_validity);
375  p_promoted_fact->is_promoted_ = true;
376 
377  if (((HLPController *)controller_)->inject_prediction(f_p_promoted_fact, ((_Fact *)input->object_)->get_cfd())) {
378  // Mark that this fact was promoted for this Sim.
379  predictionSimulation->defeasible_promoted_facts_.list_.push_front(
380  Sim::DefeasiblePromotedFact(saved_input, f_p_promoted_fact, defeasible_validity));
381  OUTPUT_LINE(CST_OUT, Utils::RelativeTime(now) << " fact " << non_axiom_inputs_[i]->get_oid() <<
382  " -> promoted simulated pred fact " << f_p_promoted_fact->get_oid() << " w/ fact " <<
383  input->object_->get_oid() << " timings");
384  }
385  }
386  }
387  predictionSimulation->defeasible_promoted_facts_.CS_.leave();
388  }
389 
390  P<HLPBindingMap> bm = new HLPBindingMap();
391  bool bound_pattern_is_axiom;
392  _Fact *bound_pattern = bind_pattern(input_object, bm, predictionSimulation, bound_pattern_is_axiom);
393  if (bound_pattern) {
394 #if 0 // Debug: Show making overlays.
395  string debug_inputs_info;
396  for (uint32 i = 0; i < axiom_inputs_.size(); ++i)
397  debug_inputs_info += " " + to_string(axiom_inputs_[i]->get_oid());
398  for (uint32 i = 0; i < non_axiom_inputs_.size(); ++i)
399  debug_inputs_info += " " + to_string(non_axiom_inputs_[i]->get_oid());
400 #endif
401  if (axiom_patterns_.size() + non_axiom_patterns_.size() == 1) { // last match.
402 
403  if (!code_) {
404 
405  load_code();
406  bindings_ = bm;
407  if (evaluate_fwd_guards()) { // may update bindings; full match.
408  offspring = get_offspring(bm, (_Fact *)input->object_, bound_pattern_is_axiom);
409  inject_production(input);
410  invalidate();
411  store_evidence(input->object_, prediction, is_simulation);
412  return true;
413  } else {
414  delete[] code_;
415  code_ = NULL;
416  // JTNote: This returns after bindings_ is modified. Should they be restored?
417  return false;
418  }
419  } else { // guards already evaluated, full match.
420  offspring = get_offspring(bm, (_Fact *)input->object_, bound_pattern_is_axiom);
421 #if 0 // Debug: Show making overlays.
422  OUTPUT_LINE((TraceLevel)0, "Debug: For " << get_object()->get_oid() <<
423  (predictionSimulation ? " Sim(" + to_string(predictionSimulation->get_detail_oid()) + ")" : "") << ": CSTOverlay(" <<
424  get_detail_oid() << ") [" << debug_inputs_info << "]: Add " << input->object_->get_oid() <<
425  " (final) after making offspring CSTOverlay(" << offspring->get_detail_oid() << ")");
426 #endif
427  inject_production(input);
428  invalidate();
429  store_evidence(input->object_, prediction, is_simulation);
430  return true;
431  }
432  } else {
433  offspring = get_offspring(bm, (_Fact *)input->object_, bound_pattern_is_axiom, bound_pattern);
434 #if 0 // Debug: Show making overlays.
435  OUTPUT_LINE((TraceLevel)0, "Debug: For " << get_object()->get_oid() <<
436  (predictionSimulation ? " Sim(" + to_string(predictionSimulation->get_detail_oid()) + ")" : "") << ": CSTOverlay(" <<
437  get_detail_oid() << ") [" << debug_inputs_info << "]: Add " << input->object_->get_oid() <<
438  " after making offspring CSTOverlay(" << offspring->get_detail_oid() << ")");
439 #endif
440  store_evidence(input->object_, prediction, is_simulation);
441  return true;
442  }
443  }
444  else
445  return false;
446 }
447 
448 _Fact* CSTOverlay::bind_pattern(_Fact *input, HLPBindingMap* map, Sim* predictionSimulation, bool& is_axiom)
449 {
450  is_axiom = false;
451 
452  bool use_input_timings = (axiom_inputs_.size() + non_axiom_inputs_.size() == 0);
453  if (predictionSimulation) {
454  if (simulations_.size() > 1)
455  // TODO: Handle the case where simulations_ has multiple simulation roots.
456  return NULL;
457  if (simulations_.size() == 1) {
458  if (*simulations_.begin() != predictionSimulation)
459  // This overlay is for a simulation, but for a different simulation than the input predictionSimulation.
460  return NULL;
461  }
462 
463  if (axiom_inputs_.size() > 0 && non_axiom_inputs_.size() == 0) {
464  // This overlay's binding map forward timings have been set, and there are only saved axiom facts.
465  if (input->get_after() < bindings_->get_fwd_before() &&
466  input->get_before() > bindings_->get_fwd_after()) {
467  // The timings overlap, so let match_fwd_strict update the map from the input timings.
468  }
469  else if (input->get_before() <= bindings_->get_fwd_after())
470  // The input is earlier than the facts in this overlay, so don't match.
471  return NULL;
472  else
473  // The input is later than the facts in this overlay.
474  // Below, we update this overlay's binding map to use this input's timings.
475  use_input_timings = true;
476  }
477  }
478 
479  r_code::list<P<_Fact> >::const_iterator p;
480  for (p = axiom_patterns_.begin(); p != axiom_patterns_.end(); ++p) {
481 
482  map->load(bindings_);
483  if (use_input_timings)
484  map->reset_fwd_timings(input);
485  if (map->match_fwd_strict(input, *p)) {
486  is_axiom = true;
487  return *p;
488  }
489  }
490  for (p = non_axiom_patterns_.begin(); p != non_axiom_patterns_.end(); ++p) {
491 
492  map->load(bindings_);
493  if (use_input_timings)
494  map->reset_fwd_timings(input);
495  if (map->match_fwd_strict(input, *p))
496  return *p;
497  }
498 
499  return NULL;
500 }
501 
503  // TODO: Do we need a critical section to access simulations_?
504  for (auto sim = simulations_.begin(); sim != simulations_.end(); ++sim) {
505  if ((*sim)->root_ == root)
506  return *sim;
507  }
508 
509  return NULL;
510 }
511 
513 
514 CSTController::CSTController(_View *view) : HLPController(view) {
515 
516  CSTOverlay *o = new CSTOverlay(this, bindings_); // master overlay.
517  o->load_patterns();
518  overlays_.push_back(o);
519 
520  Group *host = get_host();
521  Code *object = get_unpacked_object();
522  uint16 obj_set_index = object->code(CST_OBJS).asIndex();
523  uint16 obj_count = object->code(obj_set_index).getAtomCount();
524  for (uint16 i = 0; i < obj_count; ++i) {
525 
526  Code *pattern = object->get_reference(object->code(obj_set_index + 1).asIndex());
527  Code *pattern_ihlp = pattern->get_reference(0);
528  uint16 opcode = pattern_ihlp->code(0).asOpcode();
529  if (opcode == Opcodes::ICst ||
530  opcode == Opcodes::IMdl) {
531 
532  Code *pattern_hlp = pattern_ihlp->get_reference(0);
533  r_exec::View *pattern_hlp_v = (r_exec::View*)pattern_hlp->get_view(host, true);
534  if (pattern_hlp_v)
535  controllers_.push_back((HLPController *)pattern_hlp_v->controller_);
536  }
537  }
538 }
539 
540 CSTController::~CSTController() {
541 }
542 
543 void CSTController::take_input(r_exec::View *input) {
544 
545  if (become_invalidated())
546  return;
547 
548  if (input->object_->code(0).asOpcode() == Opcodes::Fact ||
549  input->object_->code(0).asOpcode() == Opcodes::AntiFact) { // discard everything but facts and |facts.
550 
551  OUTPUT_LINE(CST_IN, Utils::RelativeTime(Now()) << " cst " << get_object()->get_oid() << " <- " << input->object_->get_oid());
552  Controller::__take_input<CSTController>(input);
553  }
554 }
555 
556 void CSTController::reduce(r_exec::View *input) {
557 
558  if (is_orphan())
559  return;
560 
561  if (input->object_->is_invalidated())
562  return;
563 
564  Goal *goal = ((_Fact *)input->object_)->get_goal();
565  if (goal && goal->is_self_goal() && !goal->is_drive()) { // goal is g->f->target.
566 
567  _Fact *goal_target = goal->get_target(); // handle only icst.
568  Code *target_ihlp = goal_target->get_reference(0);
569  if (target_ihlp->code(0).asOpcode() == Opcodes::ICst && target_ihlp->get_reference(0) == get_object()) { // f is f->icst; produce as many sub-goals as there are patterns in the cst.
570 
571  if (!get_requirement_count()) { // models will attempt to produce the icst
572 
573  P<HLPBindingMap> bm = new HLPBindingMap(bindings_);
574  bm->init_from_f_ihlp(goal_target);
575  if (evaluate_bwd_guards(bm)) { // leaves the controller constant: no need to protect; bm may be updated.
576  if (goal->is_simulation())
577  abduce_simulated(bm, input->object_);
578  else
579  abduce(bm, input->object_);
580  }
581  }
582  }
583  } else {
584  bool match = false;
585  CSTOverlay *offspring;
586  r_code::list<P<Overlay> >::const_iterator o;
587  reductionCS_.enter();
588  auto now = Now();
589  for (o = overlays_.begin(); o != overlays_.end();) {
590 
591  if (!((CSTOverlay *)*o)->can_match(now)) {
592  (*o)->invalidate();
593  o = overlays_.erase(o);
594  }
595  else if ((*o)->is_invalidated())
596  o = overlays_.erase(o);
597  else {
598 
599  match = (((CSTOverlay *)*o)->reduce(input, offspring) || match);
600  if (offspring)
601  overlays_.push_front(offspring);
602 
603  ++o;
604  }
605  }
606  reductionCS_.leave();
607 
608  check_last_match_time(match);
609  }
610 }
611 
612 void CSTController::abduce_simulated(HLPBindingMap *bm, Fact *f_super_goal) {
613  Goal *g = f_super_goal->get_goal();
614  _Fact *super_goal_target = g->get_target();
615  Fact* remade_f_icst = get_f_ihlp(bm, false);
616 
617  for (auto o = overlays_.begin(); o != overlays_.end(); ++o) {
618  if (((CSTOverlay*)(*o))->is_simulated())
619  // Skip overlays that were produced during simulated forward chaining.
620  continue;
621 #if 0 // Debug: Don't use inputs.
622  if (!(((CSTOverlay*)(*o))->non_axiom_inputs_.size() == 0 && ((CSTOverlay*)(*o))->axiom_patterns_.size() == 0))
623  continue;
624 #endif
625 
626  HLPBindingMap bm_copy(bm);
627  // TODO: this is inefficient. We want to merge (*o)->binding_ into bm_copy, but use an icst.
628  Fact* overlay_f_icst = get_f_ihlp(((HLPOverlay*)(*o))->bindings_, false);
629  if (bm_copy.match_object(overlay_f_icst->get_reference(0), remade_f_icst->get_reference(0)))
630  abduce(&bm_copy, f_super_goal);
631  }
632 }
633 
634 void CSTController::abduce(HLPBindingMap *bm, Fact *f_super_goal) {
635 
636  Goal *g = f_super_goal->get_goal();
637  _Fact *super_goal_target = g->get_target();
638  bool opposite = (super_goal_target->is_anti_fact());
639 
640  float32 confidence = super_goal_target->get_cfd();
641 
642  Sim *sim = g->get_sim();
643  Sim *sub_sim;
644  auto now = Now();
645  if (sim->get_mode() == SIM_ROOT)
646  sub_sim = new Sim(opposite ? SIM_MANDATORY : SIM_OPTIONAL, sim->get_thz(), f_super_goal, opposite, sim->root_, 1, sim->solution_controller_, sim->get_solution_cfd(), now + sim->get_thz());
647  else
648  sub_sim = new Sim(sim->get_mode(), sim->get_thz(), f_super_goal, opposite, sim->root_, 1, sim->solution_controller_, sim->get_solution_cfd(), sim->get_solution_before());
649 
650  Code *cst = get_unpacked_object();
651  uint16 obj_set_index = cst->code(CST_OBJS).asIndex();
652  uint16 obj_count = cst->code(obj_set_index).getAtomCount();
653  Group *host = get_host();
654  for (uint16 i = 1; i <= obj_count; ++i) {
655 
656  _Fact *pattern = (_Fact *)cst->get_reference(cst->code(obj_set_index + i).asIndex());
657  _Fact *bound_pattern = (_Fact *)bm->bind_pattern(pattern);
658  if (_Mem::Get()->matches_axiom(bound_pattern->get_reference(0)))
659  // Don't make a goal of a member which is an axiom.
660  continue;
661 
662  _Fact *evidence;
663  if (opposite)
664  bound_pattern->set_opposite();
665 #if 0 // Debug: Don't check evidences for simulated goals.
666  if (f_super_goal->get_goal()->is_simulation()) {
667  inject_goal(bm, f_super_goal, bound_pattern, sub_sim, now, confidence, host); // all sub-goals share the same sim.
668  continue;
669  }
670 #endif
671  switch (check_evidences(bound_pattern, evidence)) {
672  case MATCH_SUCCESS_POSITIVE: // positive evidence, no need to produce a sub-goal: skip.
673  break;
674  case MATCH_SUCCESS_NEGATIVE: // negative evidence, no need to produce a sub-goal, the super-goal will probably fail within the target time frame: skip.
675  break;
676  case MATCH_FAILURE:
677  switch (check_predicted_evidences(bound_pattern, evidence)) {
678  case MATCH_SUCCESS_POSITIVE:
679  break;
680  case MATCH_SUCCESS_NEGATIVE:
681  case MATCH_FAILURE: // inject a sub-goal for the missing predicted positive evidence.
682  inject_goal(bm, f_super_goal, bound_pattern, sub_sim, now, confidence, host); // all sub-goals share the same sim.
683  break;
684  }
685  }
686  }
687 }
688 
689 void CSTController::inject_goal(HLPBindingMap *bm,
690  Fact *f_super_goal,
691  _Fact *sub_goal_target, // f1.
692  Sim *sim,
693  Timestamp now,
694  float32 confidence,
695  Code *group) const {
696 
697  if (sim && !sim->register_goal_target(sub_goal_target))
698  // We are already simulating from this goal, so abort to avoid loops.
699  return;
700 
701  sub_goal_target->set_cfd(confidence);
702 
703  Goal *sub_goal = new Goal(sub_goal_target, f_super_goal->get_goal()->get_actor(), sim, 1);
704 
705  _Fact *f_icst = f_super_goal->get_goal()->get_target();
706  _Fact *sub_goal_f = new Fact(sub_goal, now, now, 1, 1);
707 
708  View *view = new View(View::SYNC_ONCE, now, confidence, 1, group, group, sub_goal_f); // SYNC_ONCE,res=1.
709  _Mem::Get()->inject(view);
710  OUTPUT_LINE(CST_OUT, Utils::RelativeTime(Now()) << " cst " << get_object()->get_oid() << ": fact " <<
711  f_super_goal->get_oid() << " super_goal -> fact " << sub_goal_f->get_oid() << " simulated goal");
712 
713  // no rdx for SIM_OPTIONAL or SIM_MANDATORY.
714  if (sim->get_mode() == SIM_ROOT)
715  inject_notification_into_out_groups(group, new MkRdx(f_icst, f_super_goal, sub_goal, 1, bm));
716 }
717 
718 Fact *CSTController::get_f_ihlp(HLPBindingMap *bindings, bool wr_enabled) const {
719 
720  return bindings->build_f_ihlp(get_object(), Opcodes::ICst, false);
721 }
722 
723 Fact *CSTController::get_f_icst(HLPBindingMap *bindings, vector<P<_Fact> > *axiom_inputs, vector<P<_Fact> > *non_axiom_inputs) const {
724 
725  Fact *f_icst = get_f_ihlp(bindings, false);
726  ICST* icst = (ICST *)f_icst->get_reference(0);
727  icst->bindings_ = bindings;
728  icst->components_ = *axiom_inputs;
729  icst->components_.insert(icst->components_.end(), non_axiom_inputs->begin(), non_axiom_inputs->end());
730  return f_icst;
731 }
732 
733 bool CSTController::inject_prediction(Fact *prediction, float32 confidence, microseconds time_to_live) const { // prediction: f->pred->f->target.
734 
735  auto now = Now();
736  Group *primary_host = get_host();
737  float32 sln_thr = primary_host->code(GRP_SLN_THR).asFloat();
738  if (confidence > sln_thr) { // do not inject if cfd is too low.
739 
740  int32 resilience = _Mem::Get()->get_goal_pred_success_res(primary_host, now, time_to_live);
741  View *view = new View(View::SYNC_ONCE, now, confidence, resilience, primary_host, primary_host, prediction); // SYNC_ONCE,res=resilience.
742  _Mem::Get()->inject(view);
743  return true;
744  } else
745  return false;
746 }
747 
748 void CSTController::inject_icst(Fact *production, float32 confidence, microseconds time_to_live) const { // production: f->icst.
749 
750  auto now = Now();
751  Group *primary_host = get_host();
752  float32 sln_thr = primary_host->code(GRP_SLN_THR).asFloat();
753  if (confidence > sln_thr) {
754 
755  View *view = new View(View::SYNC_ONCE, now, 1, Utils::GetResilience(now, time_to_live, primary_host->get_upr() * Utils::GetBasePeriod().count()), primary_host, primary_host, production);
756  _Mem::Get()->inject(view); // inject f->icst in the primary group: needed for hlps like M[icst -> X] and S[icst X Y].
757  uint16 out_group_count = get_out_group_count();
758  for (uint16 i = 0; i < out_group_count; ++i) {
759 
760  Group *out_group = (Group *)get_out_group(i);
761  View *view = new View(View::SYNC_ONCE, now, 1, 1, out_group, primary_host, production);
762  _Mem::Get()->inject(view);
763  }
764  }
765 
766  sln_thr = secondary_host_->code(GRP_SLN_THR).asFloat();
767  if (confidence > sln_thr) {
768 
769  View *view = new View(View::SYNC_ONCE, now, 1, Utils::GetResilience(now, time_to_live, secondary_host_->get_upr() * Utils::GetBasePeriod().count()), secondary_host_, primary_host, production);
770  _Mem::Get()->inject(view); // inject f->icst in the secondary group: same reason as above.
771  }
772 }
773 
774 void CSTController::set_secondary_host(Group *host) {
775 
776  secondary_host_ = host;
777 }
778 
779 Group *CSTController::get_secondary_host() const {
780 
781  return secondary_host_;
782 }
783 
784 void CSTController::kill_views() {
785 
786  invalidate();
787  get_view()->force_res(0);
788 }
789 
790 void CSTController::check_last_match_time(bool match) {
791 
792  auto now = Now();
793  if (match)
794  last_match_time_ = now;
795  else if (now - last_match_time_ > _Mem::Get()->get_primary_thz())
796  kill_views();
797 }
798 }
r_exec::Pred::get_simulation
Sim * get_simulation(uint16 i) const
Definition: factory.h:468
r_exec::HLPController::evaluate_bwd_guards
bool evaluate_bwd_guards(HLPBindingMap *bm, bool narrow_fwd_timings=false)
Definition: hlp_controller.cpp:168
r_code::_View
Definition: r_code/object.h:164
r_exec::Sim
Definition: factory.h:248
r_exec::_Fact
Definition: factory.h:155
core::P
Definition: base.h:103
r_code::Code
Definition: r_code/object.h:224
r_exec::CSTOverlay::inject_production
_Fact * inject_production(View *input)
Definition: cst_controller.cpp:137
r_exec::HLPController
Definition: hlp_controller.h:106
r_exec::Sim::DefeasiblePromotedFact::has_original_fact
static bool has_original_fact(const r_code::list< DefeasiblePromotedFact > &list, const _Fact *original_fact)
Definition: factory.cpp:806
r_exec::View
Definition: view.h:102
r_exec::Group
Definition: group.h:108
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::CSTController
Definition: cst_controller.h:187
r_exec::Controller
Definition: controller.h:104
r_exec::CSTOverlay::get_offspring
CSTOverlay * get_offspring(HLPBindingMap *map, _Fact *input, bool is_axiom, _Fact *bound_pattern=NULL)
Definition: cst_controller.cpp:200
r_code::list
Definition: list.h:99
r_exec::Fact
Definition: factory.h:360
r_exec::CSTOverlay
Definition: cst_controller.h:107
r_exec::CSTOverlay::get_simulation
Sim * get_simulation(Controller *root) const
Definition: cst_controller.cpp:502
r_exec::CSTOverlay::bind_pattern
_Fact * bind_pattern(_Fact *input, HLPBindingMap *map, Sim *predictionSimulation, bool &is_axiom)
Definition: cst_controller.cpp:448
r_code::PHash
Definition: r_code/utils.h:96