AERA
model_base.cpp
1 //_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
2 //_/_/
3 //_/_/ AERA
4 //_/_/ Autocatalytic Endogenous Reflective Architecture
5 //_/_/
6 //_/_/ Copyright (c) 2018-2025 Jeff Thompson
7 //_/_/ Copyright (c) 2018-2025 Kristinn R. Thorisson
8 //_/_/ Copyright (c) 2018-2025 Icelandic Institute for Intelligent Machines
9 //_/_/ Copyright (c) 2018 Jacqueline Clare Mallett
10 //_/_/ 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 "model_base.h"
87 #include "mem.h"
88 
89 using namespace std::chrono;
90 using namespace r_code;
91 
92 namespace r_exec {
93 
94 uint32 ModelBase::MEntry::_ComputeHashCode(_Fact *component) { // 14 bits: [fact or |fact (1)|type (3)|data (10)].
95 
96  uint32 hash_code;
97  if (component->is_fact())
98  hash_code = 0x00000000;
99  else
100  hash_code = 0x00002000;
101  Code *payload = component->get_reference(0);
102  Atom head = payload->code(0);
103  uint16 opcode = head.asOpcode();
104  switch (head.getDescriptor()) {
105  case Atom::OBJECT:
106  if (opcode == Opcodes::Cmd) { // type: 2.
107 
108  hash_code |= 0x00000800;
109  hash_code |= (payload->code(CMD_FUNCTION).asOpcode() & 0x000003FF); // data: function id.
110  } else if (opcode == Opcodes::IMdl) { // type 3.
111 
112  hash_code |= 0x00000C00;
113  hash_code |= (((uint32)payload->get_reference(0)) & 0x000003FF); // data: address of the mdl.
114  } else if (opcode == Opcodes::ICst) { // type 4.
115 
116  hash_code |= 0x00001000;
117  hash_code |= (((uint32)payload->get_reference(0)) & 0x000003FF); // data: address of the cst.
118  } else // type: 0.
119  hash_code |= (opcode & 0x000003FF); // data: class id.
120  break;
121  case Atom::MARKER: // type 1.
122  hash_code |= 0x00000400;
123  hash_code |= (opcode & 0x000003FF); // data: class id.
124  break;
125  }
126 
127  return hash_code;
128 }
129 
130 uint32 ModelBase::MEntry::ComputeHashCode(Code *mdl, bool packed) {
131 
132  uint32 hash_code = (mdl->code(mdl->code(HLP_TPL_ARGS).asIndex()).getAtomCount() << 28);
133  _Fact *lhs;
134  _Fact *rhs;
135  if (packed) {
136 
137  Code *unpacked_mdl = mdl->get_reference(mdl->references_size() - MDL_HIDDEN_REFS);
138  lhs = (_Fact *)unpacked_mdl->get_reference(0);
139  rhs = (_Fact *)unpacked_mdl->get_reference(1);
140  } else {
141 
142  lhs = (_Fact *)mdl->get_reference(0);
143  rhs = (_Fact *)mdl->get_reference(1);
144  }
145  hash_code |= (_ComputeHashCode(lhs) << 14);
146  hash_code |= _ComputeHashCode(rhs);
147  return hash_code;
148 }
149 
150 bool ModelBase::MEntry::Match(Code *lhs, Code *rhs) {
151 
152  if (lhs->code(0).asOpcode() == Opcodes::Ent || rhs->code(0).asOpcode() == Opcodes::Ent)
153  return lhs == rhs;
154  if (lhs->code(0).asOpcode() == Opcodes::Ont || rhs->code(0).asOpcode() == Opcodes::Ont)
155  return lhs == rhs;
156  if (lhs->code_size() != rhs->code_size())
157  return false;
158  if (lhs->references_size() != rhs->references_size())
159  return false;
160  for (uint16 i = 0; i < lhs->code_size(); ++i) {
161 
162  if (lhs->code(i) != rhs->code(i))
163  return false;
164  }
165  for (uint16 i = 0; i < lhs->references_size(); ++i) {
166 
167  if (!Match(lhs->get_reference(i), rhs->get_reference(i)))
168  return false;
169  }
170  return true;
171 }
172 
173 ModelBase::MEntry::MEntry() : mdl_(NULL), packed_(false), touch_time_(seconds(0)), hash_code_(0) {
174 }
175 
176 ModelBase::MEntry::MEntry(Code *mdl, bool packed) : mdl_(mdl), packed_(packed), touch_time_(Now()), hash_code_(ComputeHashCode(mdl, packed)) {
177 }
178 
179 bool ModelBase::MEntry::match(const MEntry &e) const { // at this point both models have the same hash code.
180 
181  if (mdl_ == e.mdl_)
182  return true;
183 
184  // Get the unpacked models.
185  Code* mdl_0 = (packed_ ? mdl_->get_reference(mdl_->references_size() - MDL_HIDDEN_REFS) : (Code*)mdl_);
186  Code* mdl_1 = (e.packed_ ? e.mdl_->get_reference(e.mdl_->references_size() - MDL_HIDDEN_REFS) : (Code*)e.mdl_);
187 
188  if (mdl_0->code_size() != mdl_1->code_size())
189  return false;
190  for (uint16 i = 0; i < mdl_0->code_size(); ++i) { // first check the mdl code: this checks on tpl args and guards.
191 
192  if (i == MDL_STRENGTH || i == MDL_CNT || i == MDL_SR || i == MDL_DSR || i == MDL_ARITY) // ignore house keeping data.
193  continue;
194 
195  if (mdl_0->code(i) != mdl_1->code(i))
196  return false;
197  }
198 
199  Code* f_lhs_0 = mdl_0->get_reference(0);
200  Code* f_lhs_1 = mdl_1->get_reference(0);
201  if (f_lhs_0->references_size() < 1)
202  return false;
203  if (f_lhs_1->references_size() < 1)
204  return false;
205  // Make sure we don't match fact with anti-fact.
206  if (f_lhs_0->code(0) != f_lhs_1->code(0))
207  return false;
208  // Match the payloads of the facts.
209  if (!Match(f_lhs_0->get_reference(0), f_lhs_1->get_reference(0)))
210  return false;
211 
212  Code* f_rhs_0 = mdl_0->get_reference(1);
213  Code* f_rhs_1 = mdl_1->get_reference(1);
214  // Make sure we don't match fact with anti-fact.
215  if (f_rhs_0->code(0) != f_rhs_1->code(0))
216  return false;
217  // Match the payloads of the facts.
218  if (!Match(f_rhs_0->get_reference(0), f_rhs_1->get_reference(0)))
219  return false;
220 
221  return true;
222 }
223 
225 
226 ModelBase *ModelBase::singleton_ = NULL;
227 
228 ModelBase *ModelBase::Get() {
229 
230  return singleton_;
231 }
232 
233 ModelBase::ModelBase() {
234 
235  singleton_ = this;
236 }
237 
238 void ModelBase::trim_objects() {
239 
240  mdlCS_.enter();
241  auto now = Now();
242  MdlSet::iterator m;
243  for (m = black_list_.begin(); m != black_list_.end();) {
244 
245  if (now - (*m).touch_time_ >= thz_)
246  m = black_list_.erase(m);
247  else
248  ++m;
249  }
250  mdlCS_.leave();
251 }
252 
253 void ModelBase::load(Code *mdl) { // mdl is already packed.
254 
255  MEntry e(mdl, true);
256  if (mdl->views_.size() > 0) // no need to lock at load time.
257  white_list_.insert(e);
258  else
259  black_list_.insert(e);
260 }
261 
262 void ModelBase::get_models(r_code::list<P<Code> > &models) {
263 
264  mdlCS_.enter();
265  MdlSet::iterator m;
266  for (m = white_list_.begin(); m != white_list_.end(); ++m)
267  models.push_back((*m).mdl_);
268  for (m = black_list_.begin(); m != black_list_.end(); ++m)
269  models.push_back((*m).mdl_);
270  mdlCS_.leave();
271 }
272 
273 Code *ModelBase::check_existence(Code *mdl) {
274 
275  MEntry e(mdl, false);
276  MEntry copy;
277  mdlCS_.enter();
278  MdlSet::iterator m = black_list_.find(e);
279 
280  // jm: iterator's on sets are now immutable because of hash keey issues
281  // solution is to remove and re-add
282  if (m != black_list_.end()) {
283 
284  copy = *m;
285  copy.touch_time_ = Now();
286  black_list_.erase(*m);
287  black_list_.insert(copy);
288 
289  //(*m).touch_time_=Now();
290  mdlCS_.leave();
291  return NULL;
292  }
293  m = white_list_.find(e);
294  if (m != white_list_.end())
295  {
296  copy = *m;
297  copy.touch_time_ = Now();
298  white_list_.erase(*m);
299  white_list_.insert(copy);
300 
301  //(*m).touch_time_=Now(); // jm
302  mdlCS_.leave();
303  return copy.mdl_;
304  }
305  _Mem::Get()->pack_hlp(e.mdl_);
306  e.packed_ = true;
307  white_list_.insert(e);
308  mdlCS_.leave();
309  return mdl;
310 }
311 
312 void ModelBase::check_existence(Code *m0, Code *m1, Code *&_m0, Code *&_m1) { // m0 and m1 unpacked.
313 
314  MEntry e_m0(m0, false);
315  MEntry copy;
316  mdlCS_.enter();
317  MdlSet::iterator m = black_list_.find(e_m0);
318  if (m != black_list_.end())
319  {
320  copy = *m;
321  copy.touch_time_ = Now();
322  black_list_.erase(*m);
323  black_list_.insert(copy);
324 
325  // (*m).touch_time_=Now(); jm
326  mdlCS_.leave();
327  _m0 = _m1 = NULL;
328  return;
329  }
330  m = white_list_.find(e_m0);
331  if (m != white_list_.end()) {
332 
333  copy = *m;
334  copy.touch_time_ = Now();
335  white_list_.erase(*m);
336  white_list_.insert(copy);
337 
338  //(*m).touch_time_=Now(); //jm
339  _m0 = copy.mdl_;
340  Code *rhs = m1->get_reference(m1->code(m1->code(MDL_OBJS).asIndex() + 2).asIndex());
341  Code *im0 = rhs->get_reference(0);
342  im0->set_reference(0, _m0); // change imdl m0 into imdl _m0.
343  } else
344  _m0 = m0;
345  MEntry e_m1(m1, false);
346  m = black_list_.find(e_m1);
347  if (m != black_list_.end()) {
348  copy = *m;
349  copy.touch_time_ = Now();
350  black_list_.erase(*m);
351  black_list_.insert(copy);
352 
353  //(*m).touch_time_=Now();
354  mdlCS_.leave();
355  _m1 = NULL;
356  return;
357  }
358  m = white_list_.find(e_m1);
359  if (m != white_list_.end()) {
360  copy = *m;
361  copy.touch_time_ = Now();
362  white_list_.erase(*m);
363  white_list_.insert(copy);
364 
365  //(*m).touch_time_=Now(); //jm
366  mdlCS_.leave();
367  _m1 = copy.mdl_;
368  return;
369  }
370  if (_m0 == m0) {
371 
372  _Mem::Get()->pack_hlp(m0);
373  e_m0.packed_ = true;
374  white_list_.insert(e_m0);
375  }
376  _Mem::Get()->pack_hlp(m1);
377  e_m1.packed_ = true;
378  white_list_.insert(e_m1);
379  mdlCS_.leave();
380  _m1 = m1;
381 }
382 
383 void ModelBase::register_mdl_failure(Code *mdl) { // mdl is packed.
384 
385  MEntry e(mdl, true);
386  mdlCS_.enter();
387  white_list_.erase(e);
388  black_list_.insert(e);
389  mdlCS_.leave();
390 }
391 
392 void ModelBase::register_mdl_timeout(Code *mdl) { // mdl is packed.
393 
394  MEntry e(mdl, true);
395  mdlCS_.enter();
396  white_list_.erase(e);
397  mdlCS_.leave();
398 }
399 }
r_code::Atom
Definition: atom.h:104
core::P
Definition: base.h:103
r_code::Code
Definition: r_code/object.h:224
r_code::list
Definition: list.h:99