Soar Kernel  9.3.2 08-06-12
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
semantic_memory.cpp
Go to the documentation of this file.
1 #include <portability.h>
2 
3 /*************************************************************************
4  * PLEASE SEE THE FILE "COPYING" (INCLUDED WITH THIS SOFTWARE PACKAGE)
5  * FOR LICENSE AND COPYRIGHT INFORMATION.
6  *************************************************************************/
7 
8 /*************************************************************************
9  *
10  * file: semantic_memory.cpp
11  *
12  * =======================================================================
13  * Description : Various functions for Soar-SMem
14  * =======================================================================
15  */
16 
17 #include "semantic_memory.h"
18 
19 #include "agent.h"
20 #include "prefmem.h"
21 #include "symtab.h"
22 #include "wmem.h"
23 #include "print.h"
24 #include "xml.h"
25 #include "lexer.h"
26 #include "instantiations.h"
27 #include "rhsfun.h"
28 #include "decide.h"
29 
30 #include <list>
31 #include <map>
32 #include <queue>
33 #include <utility>
34 #include <ctype.h>
35 #include <fstream>
36 
39 // Bookmark strings to help navigate the code
42 
43 // parameters smem::param
44 // stats smem::stats
45 // timers smem::timers
46 // statements smem::statements
47 
48 // wmes smem::wmes
49 
50 // variables smem::var
51 // temporal hash smem::hash
52 // activation smem::act
53 // long-term identifiers smem::lti
54 
55 // storage smem::storage
56 // non-cue-based retrieval smem::ncb
57 // cue-based retrieval smem::cbr
58 
59 // initialization smem::init
60 // parsing smem::parse
61 // api smem::api
62 
63 // visualization smem::viz
64 
65 
68 // Parameter Functions (smem::params)
71 
72 smem_param_container::smem_param_container( agent *new_agent ): soar_module::param_container( new_agent )
73 {
74  // learning
76  add( learning );
77 
78  // database
80  database->add_mapping( memory, "memory" );
81  database->add_mapping( file, "file" );
82  add( database );
83 
84  // path
86  add( path );
87 
88  // auto-commit
90  add( lazy_commit );
91 
92  //
93 
94  // timers
96  timers->add_mapping( soar_module::timer::zero, "off" );
100  add( timers );
101 
102  //
103 
104  // page_size
106  page_size->add_mapping( page_1k, "1k" );
107  page_size->add_mapping( page_2k, "2k" );
108  page_size->add_mapping( page_4k, "4k" );
109  page_size->add_mapping( page_8k, "8k" );
110  page_size->add_mapping( page_16k, "16k" );
111  page_size->add_mapping( page_32k, "32k" );
112  page_size->add_mapping( page_64k, "64k" );
113  add( page_size );
114 
115  // cache_size
117  add( cache_size );
118 
119  // opt
121  opt->add_mapping( opt_safety, "safety" );
122  opt->add_mapping( opt_speed, "performance" );
123  add( opt );
124 
125  // thresh
127  add( thresh );
128 
129  // merge
131  merge->add_mapping( merge_none, "none" );
132  merge->add_mapping( merge_add, "add" );
133  add( merge );
134 
135  // activate_on_query
138 
139  // activation_mode
141  activation_mode->add_mapping( act_recency, "recency" );
142  activation_mode->add_mapping( act_frequency, "frequency" );
143  activation_mode->add_mapping( act_base, "base-level" );
144  add( activation_mode );
145 
146  // base_decay
148  add( base_decay );
149 
150  // base_update_policy
152  base_update->add_mapping( bupt_stable, "stable" );
153  base_update->add_mapping( bupt_naive, "naive" );
154  base_update->add_mapping( bupt_incremental, "incremental" );
155  add( base_update );
156 
157  // incremental update thresholds
160 
161  // mirroring
163  add( mirroring );
164 }
165 
166 //
167 
168 smem_path_param::smem_path_param( const char *new_name, const char *new_value, soar_module::predicate<const char *> *new_val_pred, soar_module::predicate<const char *> *new_prot_pred, agent *new_agent ): soar_module::string_param( new_name, new_value, new_val_pred, new_prot_pred ), my_agent( new_agent ) {}
169 
170 void smem_path_param::set_value( const char *new_value )
171 {
173  {
174  my_agent->smem_first_switch = false;
176 
177  const char *msg = "Database set to file";
178  print( my_agent, const_cast<char *>( msg ) );
179  xml_generate_message( my_agent, const_cast<char *>( msg ) );
180  }
181 
182  value->assign( new_value );
183 }
184 
185 //
186 
187 template <typename T>
188 smem_db_predicate<T>::smem_db_predicate( agent *new_agent ): soar_module::agent_predicate<T>( new_agent ) {}
189 
190 template <typename T>
191 bool smem_db_predicate<T>::operator() ( T /*val*/ ) { return ( this->my_agent->smem_db->get_status() == soar_module::connected ); }
192 
193 
194 bool smem_enabled( agent *my_agent )
195 {
196  return ( my_agent->smem_params->learning->get_value() == soar_module::on );
197 }
198 
199 
202 // Statistic Functions (smem::stats)
205 
206 smem_stat_container::smem_stat_container( agent *new_agent ): soar_module::stat_container( new_agent )
207 {
208  // db-lib-version
210  add( db_lib_version );
211 
212  // mem-usage
214  add( mem_usage );
215 
216  // mem-high
218  add( mem_high );
219 
220  //
221 
222  // expansions
224  add( expansions );
225 
226  // cue-based-retrievals
228  add( cbr );
229 
230  // stores
232  add( stores );
233 
234  // activations
236  add( act_updates );
237 
238  // mirrors
240  add( mirrors );
241 
242  //
243 
244  // chunks
246  add( chunks );
247 
248  // slots
250  add( slots );
251 }
252 
253 //
254 
255 smem_db_lib_version_stat::smem_db_lib_version_stat( agent* new_agent, const char* new_name, const char* new_value, soar_module::predicate< const char* >* new_prot_pred ): soar_module::primitive_stat< const char* >( new_name, new_value, new_prot_pred ), my_agent( new_agent ) {}
256 
258 {
259  return my_agent->smem_db->lib_version();
260 }
261 
262 //
263 
264 smem_mem_usage_stat::smem_mem_usage_stat( agent *new_agent, const char *new_name, int64_t new_value, soar_module::predicate<int64_t> *new_prot_pred ): soar_module::integer_stat( new_name, new_value, new_prot_pred ), my_agent( new_agent ) {}
265 
267 {
268  return my_agent->smem_db->memory_usage();
269 }
270 
271 //
272 
273 smem_mem_high_stat::smem_mem_high_stat( agent *new_agent, const char *new_name, int64_t new_value, soar_module::predicate<int64_t> *new_prot_pred ): soar_module::integer_stat( new_name, new_value, new_prot_pred ), my_agent( new_agent ) {}
274 
276 {
277  return my_agent->smem_db->memory_highwater();
278 }
279 
280 
283 // Timer Functions (smem::timers)
286 
287 smem_timer_container::smem_timer_container( agent *new_agent ): soar_module::timer_container( new_agent )
288 {
289  // one
290 
291  total = new smem_timer( "_total", my_agent, soar_module::timer::one );
292  add( total );
293 
294  // two
295 
296  storage = new smem_timer( "smem_storage", my_agent, soar_module::timer::two );
297  add( storage );
298 
299  ncb_retrieval = new smem_timer( "smem_ncb_retrieval", my_agent, soar_module::timer::two );
300  add( ncb_retrieval );
301 
302  query = new smem_timer( "smem_query", my_agent, soar_module::timer::two );
303  add( query );
304 
305  api = new smem_timer( "smem_api", my_agent, soar_module::timer::two );
306  add( api );
307 
308  init = new smem_timer( "smem_init", my_agent, soar_module::timer::two );
309  add( init );
310 
311  hash = new smem_timer( "smem_hash", my_agent, soar_module::timer::two );
312  add( hash );
313 
314  act = new smem_timer( "three_activation", my_agent, soar_module::timer::three );
315  add( act );
316 }
317 
318 //
319 
320 smem_timer_level_predicate::smem_timer_level_predicate( agent *new_agent ): soar_module::agent_predicate<soar_module::timer::timer_level>( new_agent ) {}
321 
323 
324 //
325 
326 smem_timer::smem_timer(const char *new_name, agent *new_agent, soar_module::timer::timer_level new_level): soar_module::timer( new_name, new_agent, new_level, new smem_timer_level_predicate( new_agent ) ) {}
327 
328 
331 // Statement Functions (smem::statements)
334 
335 smem_statement_container::smem_statement_container( agent *new_agent ): soar_module::sqlite_statement_container( new_agent->smem_db )
336 {
337  soar_module::sqlite_database *new_db = new_agent->smem_db;
338 
339  //
340 
341  add_structure( "CREATE TABLE " SMEM_SCHEMA "vars (id INTEGER PRIMARY KEY,value INTEGER)" );
342 
343  add_structure( "CREATE TABLE " SMEM_SCHEMA "symbols_type (id INTEGER PRIMARY KEY, sym_type INTEGER)" );
344  add_structure( "CREATE TABLE " SMEM_SCHEMA "symbols_int (id INTEGER PRIMARY KEY, sym_const INTEGER)" );
345  add_structure( "CREATE UNIQUE INDEX " SMEM_SCHEMA "symbols_int_const ON " SMEM_SCHEMA "symbols_int (sym_const)" );
346  add_structure( "CREATE TABLE " SMEM_SCHEMA "symbols_float (id INTEGER PRIMARY KEY, sym_const REAL)" );
347  add_structure( "CREATE UNIQUE INDEX " SMEM_SCHEMA "symbols_float_const ON " SMEM_SCHEMA "symbols_float (sym_const)" );
348  add_structure( "CREATE TABLE " SMEM_SCHEMA "symbols_str (id INTEGER PRIMARY KEY, sym_const TEXT)" );
349  add_structure( "CREATE UNIQUE INDEX " SMEM_SCHEMA "symbols_str_const ON " SMEM_SCHEMA "symbols_str (sym_const)" );
350 
351  add_structure( "CREATE TABLE " SMEM_SCHEMA "lti (id INTEGER PRIMARY KEY, letter INTEGER, num INTEGER, child_ct INTEGER, act_value REAL, access_n INTEGER, access_t INTEGER, access_1 INTEGER)" );
352  add_structure( "CREATE UNIQUE INDEX " SMEM_SCHEMA "lti_letter_num ON " SMEM_SCHEMA "lti (letter, num)" );
353  add_structure( "CREATE INDEX " SMEM_SCHEMA "lti_t ON " SMEM_SCHEMA "lti (access_t)" );
354 
355  add_structure( "CREATE TABLE " SMEM_SCHEMA "history (id INTEGER PRIMARY KEY, t1 INTEGER, t2 INTEGER, t3 INTEGER, t4 INTEGER, t5 INTEGER, t6 INTEGER, t7 INTEGER, t8 INTEGER, t9 INTEGER, t10 INTEGER)" );
356 
357  add_structure( "CREATE TABLE " SMEM_SCHEMA "web (parent_id INTEGER, attr INTEGER, val_const INTEGER, val_lti INTEGER, act_value REAL)" );
358  add_structure( "CREATE INDEX " SMEM_SCHEMA "web_parent_attr_val_lti ON " SMEM_SCHEMA "web (parent_id, attr, val_const, val_lti)" );
359  add_structure( "CREATE INDEX " SMEM_SCHEMA "web_attr_val_lti_cycle ON " SMEM_SCHEMA "web (attr, val_const, val_lti, act_value)" );
360  add_structure( "CREATE INDEX " SMEM_SCHEMA "web_attr_cycle ON " SMEM_SCHEMA "web (attr, act_value)" );
361 
362  add_structure( "CREATE TABLE " SMEM_SCHEMA "ct_attr (attr INTEGER PRIMARY KEY, ct INTEGER)" );
363 
364  add_structure( "CREATE TABLE " SMEM_SCHEMA "ct_const (attr INTEGER, val_const INTEGER, ct INTEGER)" );
365  add_structure( "CREATE UNIQUE INDEX " SMEM_SCHEMA "ct_const_attr_val ON " SMEM_SCHEMA "ct_const (attr, val_const)" );
366 
367  add_structure( "CREATE TABLE " SMEM_SCHEMA "ct_lti (attr INTEGER, val_lti INTEGER, ct INTEGER)" );
368  add_structure( "CREATE UNIQUE INDEX " SMEM_SCHEMA "ct_lti_attr_val ON " SMEM_SCHEMA "ct_lti (attr, val_lti)" );
369 
370  // adding an ascii table just to make lti queries easier when inspecting database
371  add_structure( "CREATE TABLE " SMEM_SCHEMA "ascii (ascii_num INTEGER PRIMARY KEY, ascii_chr TEXT)" );
372  add_structure( "DELETE FROM " SMEM_SCHEMA "ascii" );
373  {
374  add_structure( "INSERT INTO " SMEM_SCHEMA "ascii (ascii_num, ascii_chr) VALUES (65,'A')" );
375  add_structure( "INSERT INTO " SMEM_SCHEMA "ascii (ascii_num, ascii_chr) VALUES (66,'B')" );
376  add_structure( "INSERT INTO " SMEM_SCHEMA "ascii (ascii_num, ascii_chr) VALUES (67,'C')" );
377  add_structure( "INSERT INTO " SMEM_SCHEMA "ascii (ascii_num, ascii_chr) VALUES (68,'D')" );
378  add_structure( "INSERT INTO " SMEM_SCHEMA "ascii (ascii_num, ascii_chr) VALUES (69,'E')" );
379  add_structure( "INSERT INTO " SMEM_SCHEMA "ascii (ascii_num, ascii_chr) VALUES (70,'F')" );
380  add_structure( "INSERT INTO " SMEM_SCHEMA "ascii (ascii_num, ascii_chr) VALUES (71,'G')" );
381  add_structure( "INSERT INTO " SMEM_SCHEMA "ascii (ascii_num, ascii_chr) VALUES (72,'H')" );
382  add_structure( "INSERT INTO " SMEM_SCHEMA "ascii (ascii_num, ascii_chr) VALUES (73,'I')" );
383  add_structure( "INSERT INTO " SMEM_SCHEMA "ascii (ascii_num, ascii_chr) VALUES (74,'J')" );
384  add_structure( "INSERT INTO " SMEM_SCHEMA "ascii (ascii_num, ascii_chr) VALUES (75,'K')" );
385  add_structure( "INSERT INTO " SMEM_SCHEMA "ascii (ascii_num, ascii_chr) VALUES (76,'L')" );
386  add_structure( "INSERT INTO " SMEM_SCHEMA "ascii (ascii_num, ascii_chr) VALUES (77,'M')" );
387  add_structure( "INSERT INTO " SMEM_SCHEMA "ascii (ascii_num, ascii_chr) VALUES (78,'N')" );
388  add_structure( "INSERT INTO " SMEM_SCHEMA "ascii (ascii_num, ascii_chr) VALUES (79,'O')" );
389  add_structure( "INSERT INTO " SMEM_SCHEMA "ascii (ascii_num, ascii_chr) VALUES (80,'P')" );
390  add_structure( "INSERT INTO " SMEM_SCHEMA "ascii (ascii_num, ascii_chr) VALUES (81,'Q')" );
391  add_structure( "INSERT INTO " SMEM_SCHEMA "ascii (ascii_num, ascii_chr) VALUES (82,'R')" );
392  add_structure( "INSERT INTO " SMEM_SCHEMA "ascii (ascii_num, ascii_chr) VALUES (83,'S')" );
393  add_structure( "INSERT INTO " SMEM_SCHEMA "ascii (ascii_num, ascii_chr) VALUES (84,'T')" );
394  add_structure( "INSERT INTO " SMEM_SCHEMA "ascii (ascii_num, ascii_chr) VALUES (85,'U')" );
395  add_structure( "INSERT INTO " SMEM_SCHEMA "ascii (ascii_num, ascii_chr) VALUES (86,'V')" );
396  add_structure( "INSERT INTO " SMEM_SCHEMA "ascii (ascii_num, ascii_chr) VALUES (87,'W')" );
397  add_structure( "INSERT INTO " SMEM_SCHEMA "ascii (ascii_num, ascii_chr) VALUES (88,'X')" );
398  add_structure( "INSERT INTO " SMEM_SCHEMA "ascii (ascii_num, ascii_chr) VALUES (89,'Y')" );
399  add_structure( "INSERT INTO " SMEM_SCHEMA "ascii (ascii_num, ascii_chr) VALUES (90,'Z')" );
400  }
401 
402  //
403 
404  begin = new soar_module::sqlite_statement( new_db, "BEGIN" );
405  add( begin );
406 
407  commit = new soar_module::sqlite_statement( new_db, "COMMIT" );
408  add( commit );
409 
410  rollback = new soar_module::sqlite_statement( new_db, "ROLLBACK" );
411  add( rollback );
412 
413  //
414 
415  var_get = new soar_module::sqlite_statement( new_db, "SELECT value FROM " SMEM_SCHEMA "vars WHERE id=?" );
416  add( var_get );
417 
418  var_set = new soar_module::sqlite_statement( new_db, "UPDATE " SMEM_SCHEMA "vars SET value=? WHERE id=?" );
419  add( var_set );
420 
421  var_create = new soar_module::sqlite_statement( new_db, "INSERT INTO " SMEM_SCHEMA "vars (id,value) VALUES (?,?)" );
422  add( var_create );
423 
424  //
425 
426  hash_rev_int = new soar_module::sqlite_statement( new_db, "SELECT sym_const FROM " SMEM_SCHEMA "symbols_int WHERE id=?" );
427  add( hash_rev_int );
428 
429  hash_rev_float = new soar_module::sqlite_statement( new_db, "SELECT sym_const FROM " SMEM_SCHEMA "symbols_float WHERE id=?" );
430  add( hash_rev_float );
431 
432  hash_rev_str = new soar_module::sqlite_statement( new_db, "SELECT sym_const FROM " SMEM_SCHEMA "symbols_str WHERE id=?" );
433  add( hash_rev_str );
434 
435  hash_get_int = new soar_module::sqlite_statement( new_db, "SELECT id FROM " SMEM_SCHEMA "symbols_int WHERE sym_const=?" );
436  add( hash_get_int );
437 
438  hash_get_float = new soar_module::sqlite_statement( new_db, "SELECT id FROM " SMEM_SCHEMA "symbols_float WHERE sym_const=?" );
439  add( hash_get_float );
440 
441  hash_get_str = new soar_module::sqlite_statement( new_db, "SELECT id FROM " SMEM_SCHEMA "symbols_str WHERE sym_const=?" );
442  add( hash_get_str );
443 
444  hash_add_type = new soar_module::sqlite_statement( new_db, "INSERT INTO " SMEM_SCHEMA "symbols_type (sym_type) VALUES (?)" );
445  add( hash_add_type );
446 
447  hash_add_int = new soar_module::sqlite_statement( new_db, "INSERT INTO " SMEM_SCHEMA "symbols_int (id,sym_const) VALUES (?,?)" );
448  add( hash_add_int );
449 
450  hash_add_float = new soar_module::sqlite_statement( new_db, "INSERT INTO " SMEM_SCHEMA "symbols_float (id,sym_const) VALUES (?,?)" );
451  add( hash_add_float );
452 
453  hash_add_str = new soar_module::sqlite_statement( new_db, "INSERT INTO " SMEM_SCHEMA "symbols_str (id,sym_const) VALUES (?,?)" );
454  add( hash_add_str );
455 
456  //
457 
458  lti_add = new soar_module::sqlite_statement( new_db, "INSERT INTO " SMEM_SCHEMA "lti (letter,num,child_ct,act_value,access_n,access_t,access_1) VALUES (?,?,?,?,?,?,?)" );
459  add( lti_add );
460 
461  lti_get = new soar_module::sqlite_statement( new_db, "SELECT id FROM " SMEM_SCHEMA "lti WHERE letter=? AND num=?" );
462  add( lti_get );
463 
464  lti_letter_num = new soar_module::sqlite_statement( new_db, "SELECT letter, num FROM " SMEM_SCHEMA "lti WHERE id=?" );
465  add( lti_letter_num );
466 
467  lti_max = new soar_module::sqlite_statement( new_db, "SELECT letter, MAX(num) FROM " SMEM_SCHEMA "lti GROUP BY letter" );
468  add( lti_max );
469 
470  lti_access_get = new soar_module::sqlite_statement( new_db, "SELECT access_n, access_t, access_1 FROM " SMEM_SCHEMA "lti WHERE id=?" );
471  add( lti_access_get );
472 
473  lti_access_set = new soar_module::sqlite_statement( new_db, "UPDATE " SMEM_SCHEMA "lti SET access_n=?, access_t=?, access_1=? WHERE id=?" );
474  add( lti_access_set );
475 
476  lti_get_t = new soar_module::sqlite_statement( new_db, "SELECT id FROM " SMEM_SCHEMA "lti WHERE access_t=?" );
477  add ( lti_get_t );
478 
479  //
480 
481  web_add = new soar_module::sqlite_statement( new_db, "INSERT INTO " SMEM_SCHEMA "web (parent_id, attr, val_const, val_lti, act_value) VALUES (?,?,?,?,?)" );
482  add( web_add );
483 
484  web_truncate = new soar_module::sqlite_statement( new_db, "DELETE FROM " SMEM_SCHEMA "web WHERE parent_id=?" );
485  add( web_truncate );
486 
487  web_expand = new soar_module::sqlite_statement( new_db, "SELECT tsh_a.sym_type AS attr_type, tsh_a.id AS attr_hash, vcl.sym_type AS value_type, vcl.id AS value_hash, vcl.letter AS value_letter, vcl.num AS value_num, vcl.val_lti AS value_lti FROM ((" SMEM_SCHEMA "web w LEFT JOIN " SMEM_SCHEMA "symbols_type tsh_v ON w.val_const=tsh_v.id) vc LEFT JOIN " SMEM_SCHEMA "lti AS lti ON vc.val_lti=lti.id) vcl INNER JOIN " SMEM_SCHEMA "symbols_type tsh_a ON vcl.attr=tsh_a.id WHERE parent_id=?" );
488  add( web_expand );
489 
490  //
491 
492  web_all = new soar_module::sqlite_statement( new_db, "SELECT attr, val_const, val_lti FROM " SMEM_SCHEMA "web WHERE parent_id=?" );
493  add( web_all );
494 
495  //
496 
497  web_attr_all = new soar_module::sqlite_statement( new_db, "SELECT parent_id, act_value FROM " SMEM_SCHEMA "web w WHERE attr=? ORDER BY act_value DESC" );
498  add( web_attr_all );
499 
500  web_const_all = new soar_module::sqlite_statement( new_db, "SELECT parent_id, act_value FROM " SMEM_SCHEMA "web w WHERE attr=? AND val_const=? AND val_lti=" SMEM_WEB_NULL_STR " ORDER BY act_value DESC" );
501  add( web_const_all );
502 
503  web_lti_all = new soar_module::sqlite_statement( new_db, "SELECT parent_id, act_value FROM " SMEM_SCHEMA "web w WHERE attr=? AND val_const=" SMEM_WEB_NULL_STR " AND val_lti=? ORDER BY act_value DESC" );
504  add( web_lti_all );
505 
506  //
507 
508  web_attr_child = new soar_module::sqlite_statement( new_db, "SELECT parent_id FROM " SMEM_SCHEMA "web WHERE parent_id=? AND attr=?" );
509  add( web_attr_child );
510 
511  web_const_child = new soar_module::sqlite_statement( new_db, "SELECT parent_id FROM " SMEM_SCHEMA "web WHERE parent_id=? AND attr=? AND val_const=?" );
512  add( web_const_child );
513 
514  web_lti_child = new soar_module::sqlite_statement( new_db, "SELECT parent_id FROM " SMEM_SCHEMA "web WHERE parent_id=? AND attr=? AND val_const=" SMEM_WEB_NULL_STR " AND val_lti=?" );
515  add( web_lti_child );
516 
517  //
518 
519  ct_attr_check = new soar_module::sqlite_statement( new_db, "SELECT ct FROM " SMEM_SCHEMA "ct_attr WHERE attr=?" );
520  add( ct_attr_check );
521 
522  ct_const_check = new soar_module::sqlite_statement( new_db, "SELECT ct FROM " SMEM_SCHEMA "ct_const WHERE attr=? AND val_const=?" );
523  add( ct_const_check );
524 
525  ct_lti_check = new soar_module::sqlite_statement( new_db, "SELECT ct FROM " SMEM_SCHEMA "ct_lti WHERE attr=? AND val_lti=?" );
526  add( ct_lti_check );
527 
528  //
529 
530  ct_attr_add = new soar_module::sqlite_statement( new_db, "INSERT INTO " SMEM_SCHEMA "ct_attr (attr, ct) VALUES (?,1)" );
531  add( ct_attr_add );
532 
533  ct_const_add = new soar_module::sqlite_statement( new_db, "INSERT INTO " SMEM_SCHEMA "ct_const (attr, val_const, ct) VALUES (?,?,1)" );
534  add( ct_const_add );
535 
536  ct_lti_add = new soar_module::sqlite_statement( new_db, "INSERT INTO " SMEM_SCHEMA "ct_lti (attr, val_lti, ct) VALUES (?,?,1)" );
537  add( ct_lti_add );
538 
539  //
540 
541  ct_attr_update = new soar_module::sqlite_statement( new_db, "UPDATE " SMEM_SCHEMA "ct_attr SET ct = ct + ? WHERE attr=?" );
542  add( ct_attr_update );
543 
544  ct_const_update = new soar_module::sqlite_statement( new_db, "UPDATE " SMEM_SCHEMA "ct_const SET ct = ct + ? WHERE attr=? AND val_const=?" );
545  add( ct_const_update );
546 
547  ct_lti_update = new soar_module::sqlite_statement( new_db, "UPDATE " SMEM_SCHEMA "ct_lti SET ct = ct + ? WHERE attr=? AND val_lti=?" );
548  add( ct_lti_update );
549 
550  //
551 
552  ct_attr_get = new soar_module::sqlite_statement( new_db, "SELECT ct FROM " SMEM_SCHEMA "ct_attr WHERE attr=?" );
553  add( ct_attr_get );
554 
555  ct_const_get = new soar_module::sqlite_statement( new_db, "SELECT ct FROM " SMEM_SCHEMA "ct_const WHERE attr=? AND val_const=?" );
556  add( ct_const_get );
557 
558  ct_lti_get = new soar_module::sqlite_statement( new_db, "SELECT ct FROM " SMEM_SCHEMA "ct_lti WHERE attr=? AND val_lti=?" );
559  add( ct_lti_get );
560 
561  //
562 
563  act_set = new soar_module::sqlite_statement( new_db, "UPDATE " SMEM_SCHEMA "web SET act_value=? WHERE parent_id=?" );
564  add( act_set );
565 
566  act_lti_child_ct_get = new soar_module::sqlite_statement( new_db, "SELECT child_ct FROM " SMEM_SCHEMA "lti WHERE id=?" );
568 
569  act_lti_child_ct_set = new soar_module::sqlite_statement( new_db, "UPDATE " SMEM_SCHEMA "lti SET child_ct=? WHERE id=?" );
571 
572  act_lti_set = new soar_module::sqlite_statement( new_db, "UPDATE " SMEM_SCHEMA "lti SET act_value=? WHERE id=?" );
573  add( act_lti_set );
574 
575  act_lti_get = new soar_module::sqlite_statement( new_db, "SELECT act_value FROM " SMEM_SCHEMA "lti WHERE id=?" );
576  add( act_lti_get );
577 
578  history_get = new soar_module::sqlite_statement( new_db, "SELECT t1,t2,t3,t4,t5,t6,t7,t8,t9,t10 FROM " SMEM_SCHEMA "history WHERE id=?" );
579  add( history_get );
580 
581  history_push = new soar_module::sqlite_statement( new_db, "UPDATE " SMEM_SCHEMA "history SET t10=t9,t9=t8,t8=t7,t8=t7,t7=t6,t6=t5,t5=t4,t4=t3,t3=t2,t2=t1,t1=? WHERE id=?" );
582  add( history_push );
583 
584  history_add = new soar_module::sqlite_statement( new_db, "INSERT INTO " SMEM_SCHEMA "history (id,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10) VALUES (?,?,0,0,0,0,0,0,0,0,0)" );
585  add( history_add );
586 
587  //
588 
589  vis_lti = new soar_module::sqlite_statement( new_db, "SELECT id, letter, num, act_value FROM " SMEM_SCHEMA "lti ORDER BY letter ASC, num ASC" );
590  add( vis_lti );
591 
592  vis_lti_act = new soar_module::sqlite_statement( new_db, "SELECT act_value FROM " SMEM_SCHEMA "lti WHERE id=?" );
593  add( vis_lti_act );
594 
595  vis_value_const = new soar_module::sqlite_statement( new_db, "SELECT parent_id, tsh1.sym_type AS attr_type, tsh1.id AS attr_hash, tsh2.sym_type AS val_type, tsh2.id AS val_hash FROM " SMEM_SCHEMA "web w, " SMEM_SCHEMA "symbols_type tsh1, " SMEM_SCHEMA "symbols_type tsh2 WHERE (w.attr=tsh1.id) AND (w.val_const=tsh2.id)" );
596  add( vis_value_const );
597 
598  vis_value_lti = new soar_module::sqlite_statement( new_db, "SELECT parent_id, tsh.sym_type AS attr_type, tsh.id AS attr_hash, val_lti FROM " SMEM_SCHEMA "web w, " SMEM_SCHEMA "symbols_type tsh WHERE (w.attr=tsh.id) AND (val_lti<>" SMEM_WEB_NULL_STR ")" );
599  add( vis_value_lti );
600 }
601 
602 
605 // WME Functions (smem::wmes)
608 
610 {
611  slot *s;
612  wme *w;
613  smem_wme_list *return_val = new smem_wme_list;
614 
615  // augs only exist for identifiers
616  if ( id->common.symbol_type == IDENTIFIER_SYMBOL_TYPE )
617  {
618  if ( tc != NIL )
619  {
620  if ( tc == id->id.tc_num )
621  {
622  return return_val;
623  }
624  else
625  {
626  id->id.tc_num = tc;
627  }
628  }
629 
630  // impasse wmes
631  for ( w=id->id.impasse_wmes; w!=NIL; w=w->next )
632  {
633  if ( !w->acceptable )
634  {
635  return_val->push_back( w );
636  }
637  }
638 
639  // input wmes
640  for ( w=id->id.input_wmes; w!=NIL; w=w->next )
641  {
642  return_val->push_back( w );
643  }
644 
645  // regular wmes
646  for ( s=id->id.slots; s!=NIL; s=s->next )
647  {
648  for ( w=s->wmes; w!=NIL; w=w->next )
649  {
650  if ( !w->acceptable )
651  {
652  return_val->push_back( w );
653  }
654  }
655  }
656  }
657 
658  return return_val;
659 }
660 
661 inline bool smem_symbol_is_constant( Symbol *sym )
662 {
663  return ( ( sym->common.symbol_type == SYM_CONSTANT_SYMBOL_TYPE ) ||
664  ( sym->common.symbol_type == INT_CONSTANT_SYMBOL_TYPE ) ||
665  ( sym->common.symbol_type == FLOAT_CONSTANT_SYMBOL_TYPE ) );
666 }
667 
668 //
669 
670 inline void _smem_process_buffered_wme_list( agent* my_agent, Symbol* state, soar_module::wme_set& cue_wmes, soar_module::symbol_triple_list& my_list, bool meta )
671 {
672  if ( my_list.empty() )
673  {
674  return;
675  }
676 
677  instantiation* inst = soar_module::make_fake_instantiation( my_agent, state, &cue_wmes, &my_list );
678 
679  for ( preference* pref=inst->preferences_generated; pref; pref=pref->inst_next )
680  {
681  // add the preference to temporary memory
682  if ( add_preference_to_tm( my_agent, pref ) )
683  {
684  // and add it to the list of preferences to be removed
685  // when the goal is removed
686  insert_at_head_of_dll( state->id.preferences_from_goal, pref, all_of_goal_next, all_of_goal_prev );
687  pref->on_goal_list = true;
688 
689  if ( meta )
690  {
691  // if this is a meta wme, then it is completely local
692  // to the state and thus we will manually remove it
693  // (via preference removal) when the time comes
694  state->id.smem_info->smem_wmes->push_back( pref );
695  }
696  }
697  else
698  {
699  preference_add_ref( pref );
700  preference_remove_ref( my_agent, pref );
701  }
702  }
703 
704  if ( !meta )
705  {
706  // otherwise, we submit the fake instantiation to backtracing
707  // such as to potentially produce justifications that can follow
708  // it to future adventures (potentially on new states)
709  instantiation *my_justification_list = NIL;
710  chunk_instantiation( my_agent, inst, false, &my_justification_list );
711 
712  // if any justifications are created, assert their preferences manually
713  // (copied mainly from assert_new_preferences with respect to our circumstances)
714  if ( my_justification_list != NIL )
715  {
716  preference *just_pref = NIL;
717  instantiation *next_justification = NIL;
718 
719  for ( instantiation *my_justification=my_justification_list;
720  my_justification!=NIL;
721  my_justification=next_justification )
722  {
723  next_justification = my_justification->next;
724 
725  if ( my_justification->in_ms )
726  {
727  insert_at_head_of_dll( my_justification->prod->instantiations, my_justification, next, prev );
728  }
729 
730  for ( just_pref=my_justification->preferences_generated; just_pref!=NIL; just_pref=just_pref->inst_next )
731  {
732  if ( add_preference_to_tm( my_agent, just_pref ) )
733  {
734  if ( wma_enabled( my_agent ) )
735  {
736  wma_activate_wmes_in_pref( my_agent, just_pref );
737  }
738  }
739  else
740  {
741  preference_add_ref( just_pref );
742  preference_remove_ref( my_agent, just_pref );
743  }
744  }
745  }
746  }
747  }
748 }
749 
751 {
752  _smem_process_buffered_wme_list( my_agent, state, cue_wmes, meta_wmes, true );
753  _smem_process_buffered_wme_list( my_agent, state, cue_wmes, retrieval_wmes, false );
754 }
755 
756 inline void smem_buffer_add_wme( soar_module::symbol_triple_list& my_list, Symbol* id, Symbol* attr, Symbol* value )
757 {
758  my_list.push_back( new soar_module::symbol_triple( id, attr, value ) );
759 
760  symbol_add_ref( id );
761  symbol_add_ref( attr );
762  symbol_add_ref( value );
763 }
764 
767 // Variable Functions (smem::var)
768 //
769 // Variables are key-value pairs stored in the database
770 // that are necessary to maintain a store between
771 // multiple runs of Soar.
772 //
775 
776 // gets an SMem variable from the database
777 inline bool smem_variable_get( agent *my_agent, smem_variable_key variable_id, int64_t *variable_value )
778 {
780  soar_module::sqlite_statement *var_get = my_agent->smem_stmts->var_get;
781 
782  var_get->bind_int( 1, variable_id );
783  status = var_get->execute();
784 
785  if ( status == soar_module::row )
786  {
787  (*variable_value) = var_get->column_int( 0 );
788  }
789 
790  var_get->reinitialize();
791 
792  return ( status == soar_module::row );
793 }
794 
795 // sets an existing SMem variable in the database
796 inline void smem_variable_set( agent *my_agent, smem_variable_key variable_id, int64_t variable_value )
797 {
798  soar_module::sqlite_statement *var_set = my_agent->smem_stmts->var_set;
799 
800  var_set->bind_int( 1, variable_value );
801  var_set->bind_int( 2, variable_id );
802 
803  var_set->execute( soar_module::op_reinit );
804 }
805 
806 // creates a new SMem variable in the database
807 inline void smem_variable_create( agent *my_agent, smem_variable_key variable_id, int64_t variable_value )
808 {
809  soar_module::sqlite_statement *var_create = my_agent->smem_stmts->var_create;
810 
811  var_create->bind_int( 1, variable_id );
812  var_create->bind_int( 2, variable_value );
813 
814  var_create->execute( soar_module::op_reinit );
815 }
816 
817 
820 // Temporal Hash Functions (smem::hash)
821 //
822 // The rete has symbol hashing, but the values are
823 // reliable only for the lifetime of a symbol. This
824 // isn't good for SMem. Hence, we implement a simple
825 // lookup table.
826 //
827 // Note the hashing functions for the symbol types are
828 // very similar, but with enough differences that I
829 // separated them out for clarity.
830 //
833 
834 inline smem_hash_id smem_temporal_hash_add( agent* my_agent, byte sym_type )
835 {
836  my_agent->smem_stmts->hash_add_type->bind_int( 1, sym_type );
838  return static_cast<smem_hash_id>( my_agent->smem_db->last_insert_rowid() );
839 }
840 
841 inline smem_hash_id smem_temporal_hash_int( agent *my_agent, int64_t val, bool add_on_fail = true )
842 {
843  smem_hash_id return_val = NIL;
844 
845  // search first
846  my_agent->smem_stmts->hash_get_int->bind_int( 1, val );
847  if ( my_agent->smem_stmts->hash_get_int->execute() == soar_module::row )
848  {
849  return_val = static_cast<smem_hash_id>( my_agent->smem_stmts->hash_get_int->column_int( 0 ) );
850  }
851  my_agent->smem_stmts->hash_get_int->reinitialize();
852 
853  // if fail and supposed to add
854  if ( !return_val && add_on_fail )
855  {
856  // type first
857  return_val = smem_temporal_hash_add( my_agent, INT_CONSTANT_SYMBOL_TYPE );
858 
859  // then content
860  my_agent->smem_stmts->hash_add_int->bind_int( 1, return_val );
861  my_agent->smem_stmts->hash_add_int->bind_int( 2, val );
863  }
864 
865  return return_val;
866 }
867 
868 inline smem_hash_id smem_temporal_hash_float( agent *my_agent, double val, bool add_on_fail = true )
869 {
870  smem_hash_id return_val = NIL;
871 
872  // search first
873  my_agent->smem_stmts->hash_get_float->bind_double( 1, val );
874  if ( my_agent->smem_stmts->hash_get_float->execute() == soar_module::row )
875  {
876  return_val = static_cast<smem_hash_id>( my_agent->smem_stmts->hash_get_float->column_int( 0 ) );
877  }
878  my_agent->smem_stmts->hash_get_float->reinitialize();
879 
880  // if fail and supposed to add
881  if ( !return_val && add_on_fail )
882  {
883  // type first
884  return_val = smem_temporal_hash_add( my_agent, FLOAT_CONSTANT_SYMBOL_TYPE );
885 
886  // then content
887  my_agent->smem_stmts->hash_add_float->bind_int( 1, return_val );
888  my_agent->smem_stmts->hash_add_float->bind_double( 2, val );
890  }
891 
892  return return_val;
893 }
894 
895 inline smem_hash_id smem_temporal_hash_str( agent *my_agent, char* val, bool add_on_fail = true )
896 {
897  smem_hash_id return_val = NIL;
898 
899  // search first
900  my_agent->smem_stmts->hash_get_str->bind_text( 1, static_cast<const char *>( val ) );
901  if ( my_agent->smem_stmts->hash_get_str->execute() == soar_module::row )
902  {
903  return_val = static_cast<smem_hash_id>( my_agent->smem_stmts->hash_get_str->column_int( 0 ) );
904  }
905  my_agent->smem_stmts->hash_get_str->reinitialize();
906 
907  // if fail and supposed to add
908  if ( !return_val && add_on_fail )
909  {
910  // type first
911  return_val = smem_temporal_hash_add( my_agent, SYM_CONSTANT_SYMBOL_TYPE );
912 
913  // then content
914  my_agent->smem_stmts->hash_add_str->bind_int( 1, return_val );
915  my_agent->smem_stmts->hash_add_str->bind_text( 2, static_cast<const char*>( val ) );
917  }
918 
919  return return_val;
920 }
921 
922 // returns a temporally unique integer representing a symbol constant
923 smem_hash_id smem_temporal_hash( agent *my_agent, Symbol *sym, bool add_on_fail = true )
924 {
925  smem_hash_id return_val = NIL;
926 
928  my_agent->smem_timers->hash->start();
930 
931  if ( smem_symbol_is_constant( sym ) )
932  {
933  if ( ( !sym->common.smem_hash ) || ( sym->common.smem_valid != my_agent->smem_validation ) )
934  {
935  sym->common.smem_hash = NIL;
936  sym->common.smem_valid = my_agent->smem_validation;
937 
938  switch ( sym->common.symbol_type )
939  {
941  return_val = smem_temporal_hash_str( my_agent, sym->sc.name, add_on_fail );
942  break;
943 
945  return_val = smem_temporal_hash_int( my_agent, sym->ic.value, add_on_fail );
946  break;
947 
949  return_val = smem_temporal_hash_float( my_agent, sym->fc.value, add_on_fail );
950  break;
951  }
952 
953  // cache results for later re-use
954  sym->common.smem_hash = return_val;
955  sym->common.smem_valid = my_agent->smem_validation;
956  }
957 
958  return_val = sym->common.smem_hash;
959  }
960 
962  my_agent->smem_timers->hash->stop();
964 
965  return return_val;
966 }
967 
968 inline int64_t smem_reverse_hash_int( agent* my_agent, smem_hash_id hash_value )
969 {
970  int64_t return_val = NIL;
971 
972  my_agent->smem_stmts->hash_rev_int->bind_int( 1, hash_value );
974  (void)res; // quells compiler warning
975  assert( res == soar_module::row );
976  return_val = my_agent->smem_stmts->hash_rev_int->column_int(0);
977  my_agent->smem_stmts->hash_rev_int->reinitialize();
978 
979  return return_val;
980 }
981 
982 inline double smem_reverse_hash_float( agent* my_agent, smem_hash_id hash_value )
983 {
984  double return_val = NIL;
985 
986  my_agent->smem_stmts->hash_rev_float->bind_int( 1, hash_value );
988  (void)res; // quells compiler warning
989  assert( res == soar_module::row );
990  return_val = my_agent->smem_stmts->hash_rev_float->column_double(0);
991  my_agent->smem_stmts->hash_rev_float->reinitialize();
992 
993  return return_val;
994 }
995 
996 inline void smem_reverse_hash_str( agent* my_agent, smem_hash_id hash_value, std::string& dest )
997 {
998  my_agent->smem_stmts->hash_rev_str->bind_int( 1, hash_value );
1000  (void)res; // quells compiler warning
1001  assert( res == soar_module::row );
1002  dest.assign( my_agent->smem_stmts->hash_rev_str->column_text(0) );
1003  my_agent->smem_stmts->hash_rev_str->reinitialize();
1004 }
1005 
1006 inline Symbol* smem_reverse_hash( agent* my_agent, byte sym_type, smem_hash_id hash_value )
1007 {
1008  Symbol *return_val = NULL;
1009  std::string dest;
1010 
1011  switch ( sym_type )
1012  {
1014  smem_reverse_hash_str( my_agent, hash_value, dest );
1015  return_val = make_sym_constant( my_agent, const_cast<char *>( dest.c_str() ) );
1016  break;
1017 
1019  return_val = make_int_constant( my_agent, smem_reverse_hash_int( my_agent, hash_value ) );
1020  break;
1021 
1023  return_val = make_float_constant( my_agent, smem_reverse_hash_float( my_agent, hash_value ) );
1024  break;
1025 
1026  default:
1027  return_val = NULL;
1028  break;
1029  }
1030 
1031  return return_val;
1032 }
1033 
1034 
1037 // Activation Functions (smem::act)
1040 
1041 inline double smem_lti_calc_base( agent *my_agent, smem_lti_id lti, int64_t time_now, uint64_t n = 0, uint64_t access_1 = 0 )
1042 {
1043  double sum = 0.0;
1044  double d = my_agent->smem_params->base_decay->get_value();
1045  uint64_t t_k;
1046  uint64_t t_n = ( time_now - access_1 );
1047 
1048  if ( n == 0 )
1049  {
1050  my_agent->smem_stmts->lti_access_get->bind_int( 1, lti );
1051  my_agent->smem_stmts->lti_access_get->execute();
1052 
1053  n = my_agent->smem_stmts->lti_access_get->column_int( 0 );
1054  access_1 = my_agent->smem_stmts->lti_access_get->column_int( 2 );
1055 
1056  my_agent->smem_stmts->lti_access_get->reinitialize();
1057  }
1058 
1059  // get all history
1060  my_agent->smem_stmts->history_get->bind_int( 1, lti );
1061  my_agent->smem_stmts->history_get->execute();
1062  {
1063  int available_history = static_cast<int>( ( SMEM_ACT_HISTORY_ENTRIES<n )?(SMEM_ACT_HISTORY_ENTRIES):(n) );
1064  t_k = static_cast<uint64_t>( time_now - my_agent->smem_stmts->history_get->column_int( available_history-1 ) );
1065 
1066  for ( int i=0; i<available_history; i++ )
1067  {
1068  sum += pow( static_cast<double>( time_now - my_agent->smem_stmts->history_get->column_int( i ) ),
1069  static_cast<double>( -d ) );
1070  }
1071  }
1072  my_agent->smem_stmts->history_get->reinitialize();
1073 
1074  // if available history was insufficient, approximate rest
1075  if ( n > SMEM_ACT_HISTORY_ENTRIES )
1076  {
1077  double apx_numerator = ( static_cast<double>( n - SMEM_ACT_HISTORY_ENTRIES ) * ( pow( static_cast<double>( t_n ), 1.0-d ) - pow( static_cast<double>( t_k ), 1.0-d ) ) );
1078  double apx_denominator = ( ( 1.0-d ) * static_cast<double>( t_n - t_k ) );
1079 
1080  sum += ( apx_numerator / apx_denominator );
1081  }
1082 
1083  return ( ( sum > 0 )?( log(sum) ):( SMEM_ACT_LOW ) );
1084 }
1085 
1086 // activates a new or existing long-term identifier
1087 // note: optional num_edges parameter saves us a lookup
1088 // just when storing a new chunk (default is a
1089 // big number that should never come up naturally
1090 // and if it does, satisfies thresholding behavior).
1091 inline double smem_lti_activate( agent *my_agent, smem_lti_id lti, bool add_access, uint64_t num_edges = SMEM_ACT_MAX )
1092 {
1094  my_agent->smem_timers->act->start();
1096 
1097  int64_t time_now;
1098  if ( add_access )
1099  {
1100  time_now = my_agent->smem_max_cycle++;
1101 
1104  {
1105  int64_t time_diff;
1106 
1107  for ( std::set< int64_t >::iterator b=my_agent->smem_params->base_incremental_threshes->set_begin(); b!=my_agent->smem_params->base_incremental_threshes->set_end(); b++ )
1108  {
1109  if ( *b > 0 )
1110  {
1111  time_diff = ( time_now - *b );
1112 
1113  if ( time_diff > 0 )
1114  {
1115  std::list< smem_lti_id > to_update;
1116 
1117  my_agent->smem_stmts->lti_get_t->bind_int( 1, time_diff );
1118  while ( my_agent->smem_stmts->lti_get_t->execute() == soar_module::row )
1119  {
1120  to_update.push_back( static_cast< smem_lti_id >( my_agent->smem_stmts->lti_get_t->column_int(0) ) );
1121  }
1122  my_agent->smem_stmts->lti_get_t->reinitialize();
1123 
1124  for ( std::list< smem_lti_id >::iterator it=to_update.begin(); it!=to_update.end(); it++ )
1125  {
1126  smem_lti_activate( my_agent, (*it), false );
1127  }
1128  }
1129  }
1130  }
1131  }
1132  }
1133  else
1134  {
1135  time_now = my_agent->smem_max_cycle;
1136 
1137  my_agent->smem_stats->act_updates->set_value( my_agent->smem_stats->act_updates->get_value() + 1 );
1138  }
1139 
1140  // access information
1141  uint64_t prev_access_n = 0;
1142  uint64_t prev_access_t = 0;
1143  uint64_t prev_access_1 = 0;
1144  {
1145  // get old (potentially useful below)
1146  {
1147  my_agent->smem_stmts->lti_access_get->bind_int( 1, lti );
1148  my_agent->smem_stmts->lti_access_get->execute();
1149 
1150  prev_access_n = my_agent->smem_stmts->lti_access_get->column_int( 0 );
1151  prev_access_t = my_agent->smem_stmts->lti_access_get->column_int( 1 );
1152  prev_access_1 = my_agent->smem_stmts->lti_access_get->column_int( 2 );
1153 
1154  my_agent->smem_stmts->lti_access_get->reinitialize();
1155  }
1156 
1157  // set new
1158  if ( add_access )
1159  {
1160  my_agent->smem_stmts->lti_access_set->bind_int( 1, ( prev_access_n + 1 ) );
1161  my_agent->smem_stmts->lti_access_set->bind_int( 2, time_now );
1162  my_agent->smem_stmts->lti_access_set->bind_int( 3, ( ( prev_access_n == 0 )?( time_now ):( prev_access_1 ) ) );
1163  my_agent->smem_stmts->lti_access_set->bind_int( 4, lti );
1165  }
1166  }
1167 
1168  // get new activation value (depends upon bias)
1169  double new_activation = 0.0;
1171  if ( act_mode == smem_param_container::act_recency )
1172  {
1173  new_activation = static_cast<double>( time_now );
1174  }
1175  else if ( act_mode == smem_param_container::act_frequency )
1176  {
1177  new_activation = static_cast<double>( prev_access_n + ( ( add_access )?(1):(0) ) );
1178  }
1179  else if ( act_mode == smem_param_container::act_base )
1180  {
1181  if ( prev_access_n == 0 )
1182  {
1183  if ( add_access )
1184  {
1185  my_agent->smem_stmts->history_add->bind_int( 1, lti );
1186  my_agent->smem_stmts->history_add->bind_int( 2, time_now );
1188  }
1189 
1190  new_activation = 0;
1191  }
1192  else
1193  {
1194  if ( add_access )
1195  {
1196  my_agent->smem_stmts->history_push->bind_int( 1, time_now );
1197  my_agent->smem_stmts->history_push->bind_int( 2, lti );
1199  }
1200 
1201  new_activation = smem_lti_calc_base( my_agent, lti, time_now+( ( add_access )?(1):(0) ), prev_access_n+( ( add_access )?(1):(0) ), prev_access_1 );
1202  }
1203  }
1204 
1205  // get number of augmentations (if not supplied)
1206  if ( num_edges == SMEM_ACT_MAX )
1207  {
1208  my_agent->smem_stmts->act_lti_child_ct_get->bind_int( 1, lti );
1209  my_agent->smem_stmts->act_lti_child_ct_get->execute();
1210 
1211  num_edges = my_agent->smem_stmts->act_lti_child_ct_get->column_int( 0 );
1212 
1214  }
1215 
1216  // only if augmentation count is less than threshold do we associate with edges
1217  if ( num_edges < static_cast<uint64_t>( my_agent->smem_params->thresh->get_value() ) )
1218  {
1219  // act_value=? WHERE lti=?
1220  my_agent->smem_stmts->act_set->bind_double( 1, new_activation );
1221  my_agent->smem_stmts->act_set->bind_int( 2, lti );
1223  }
1224 
1225  // always associate activation with lti
1226  {
1227  // act_value=? WHERE lti=?
1228  my_agent->smem_stmts->act_lti_set->bind_double( 1, new_activation );
1229  my_agent->smem_stmts->act_lti_set->bind_int( 2, lti );
1231  }
1232 
1234  my_agent->smem_timers->act->stop();
1236 
1237  return new_activation;
1238 }
1239 
1240 
1243 // Long-Term Identifier Functions (smem::lti)
1246 
1247 // copied primarily from add_bound_variables_in_test
1248 void _smem_lti_from_test( test t, std::set<Symbol *> *valid_ltis )
1249 {
1250  if ( test_is_blank_test(t) ) return;
1251 
1253  {
1254  Symbol *referent = referent_of_equality_test(t);
1255  if ( ( referent->common.symbol_type == IDENTIFIER_SYMBOL_TYPE ) && ( referent->id.smem_lti != NIL ) )
1256  {
1257  valid_ltis->insert( referent );
1258  }
1259 
1260  return;
1261  }
1262 
1263  {
1265 
1266  if ( ct->type==CONJUNCTIVE_TEST )
1267  {
1268  for ( cons *c=ct->data.conjunct_list; c!=NIL; c=c->rest )
1269  {
1270  _smem_lti_from_test( static_cast<test>( c->first ), valid_ltis );
1271  }
1272  }
1273  }
1274 }
1275 
1276 // copied primarily from add_all_variables_in_rhs_value
1277 void _smem_lti_from_rhs_value( rhs_value rv, std::set<Symbol *> *valid_ltis )
1278 {
1279  if ( rhs_value_is_symbol( rv ) )
1280  {
1281  Symbol *sym = rhs_value_to_symbol( rv );
1282  if ( ( sym->common.symbol_type == IDENTIFIER_SYMBOL_TYPE ) && ( sym->id.smem_lti != NIL ) )
1283  {
1284  valid_ltis->insert( sym );
1285  }
1286  }
1287  else
1288  {
1289  list *fl = rhs_value_to_funcall_list( rv );
1290  for ( cons *c=fl->rest; c!=NIL; c=c->rest )
1291  {
1292  _smem_lti_from_rhs_value( static_cast<rhs_value>( c->first ), valid_ltis );
1293  }
1294  }
1295 }
1296 
1297 // make sure ltis in actions are grounded
1298 bool smem_valid_production( condition *lhs_top, action *rhs_top )
1299 {
1300  bool return_val = true;
1301 
1302  std::set<Symbol *> valid_ltis;
1303  std::set<Symbol *>::iterator lti_p;
1304 
1305  // collect valid ltis
1306  for ( condition *c=lhs_top; c!=NIL; c=c->next )
1307  {
1308  if ( c->type == POSITIVE_CONDITION )
1309  {
1310  _smem_lti_from_test( c->data.tests.attr_test, &valid_ltis );
1311  _smem_lti_from_test( c->data.tests.value_test, &valid_ltis );
1312  }
1313  }
1314 
1315  // validate ltis in actions
1316  // copied primarily from add_all_variables_in_action
1317  {
1318  Symbol *id;
1319  action *a;
1320  int action_counter = 0;
1321 
1322  for ( a=rhs_top; a!=NIL; a=a->next )
1323  {
1324  a->already_in_tc = false;
1325  action_counter++;
1326  }
1327 
1328  // good_pass detects infinite loops
1329  bool good_pass = true;
1330  bool good_action = true;
1331  while ( good_pass && action_counter )
1332  {
1333  good_pass = false;
1334 
1335  for ( a=rhs_top; a!=NIL; a=a->next )
1336  {
1337  if ( !a->already_in_tc )
1338  {
1339  good_action = false;
1340 
1341  if ( a->type == MAKE_ACTION )
1342  {
1343  id = rhs_value_to_symbol( a->id );
1344 
1345  // non-identifiers are ok
1346  if ( id->common.symbol_type != IDENTIFIER_SYMBOL_TYPE )
1347  {
1348  good_action = true;
1349  }
1350  // short-term identifiers are ok
1351  else if ( id->id.smem_lti == NIL )
1352  {
1353  good_action = true;
1354  }
1355  // valid long-term identifiers are ok
1356  else if ( valid_ltis.find( id ) != valid_ltis.end() )
1357  {
1358  good_action = true;
1359  }
1360  }
1361  else
1362  {
1363  good_action = true;
1364  }
1365 
1366  // we've found a new good action
1367  // mark as good, collect all goodies
1368  if ( good_action )
1369  {
1370  a->already_in_tc = true;
1371 
1372  // everyone has values
1373  _smem_lti_from_rhs_value( a->value, &valid_ltis );
1374 
1375  // function calls don't have attributes
1376  if ( a->type == MAKE_ACTION )
1377  {
1378  _smem_lti_from_rhs_value( a->attr, &valid_ltis );
1379  }
1380 
1381  // note that we've dealt with another action
1382  action_counter--;
1383  good_pass = true;
1384  }
1385  }
1386  }
1387  };
1388 
1389  return_val = ( action_counter == 0 );
1390  }
1391 
1392  return return_val;
1393 }
1394 
1395 // instance of hash_table_callback_fn2
1396 Bool smem_count_ltis( agent * /*my_agent*/, void *item, void *userdata )
1397 {
1398  Symbol *id = static_cast<symbol_union *>(item);
1399 
1400  if ( id->id.smem_lti != NIL )
1401  {
1402  uint64_t* counter = reinterpret_cast<uint64_t*>( userdata );
1403  (*counter)++;
1404  }
1405 
1406  return false;
1407 }
1408 
1409 // gets the lti id for an existing lti letter/number pair (or NIL if failure)
1410 smem_lti_id smem_lti_get_id( agent *my_agent, char name_letter, uint64_t name_number )
1411 {
1412  smem_lti_id return_val = NIL;
1413 
1414  // getting lti ids requires an open semantic database
1415  smem_attach( my_agent );
1416 
1417  // letter=? AND number=?
1418  my_agent->smem_stmts->lti_get->bind_int( 1, static_cast<uint64_t>( name_letter ) );
1419  my_agent->smem_stmts->lti_get->bind_int( 2, static_cast<uint64_t>( name_number ) );
1420 
1421  if ( my_agent->smem_stmts->lti_get->execute() == soar_module::row )
1422  {
1423  return_val = my_agent->smem_stmts->lti_get->column_int( 0 );
1424  }
1425 
1426  my_agent->smem_stmts->lti_get->reinitialize();
1427 
1428  return return_val;
1429 }
1430 
1431 // adds a new lti id for a letter/number pair
1432 inline smem_lti_id smem_lti_add_id( agent *my_agent, char name_letter, uint64_t name_number )
1433 {
1434  smem_lti_id return_val;
1435 
1436  // create lti: letter, number, child_ct, act_value, access_n, access_t, access_1
1437  my_agent->smem_stmts->lti_add->bind_int( 1, static_cast<uint64_t>( name_letter ) );
1438  my_agent->smem_stmts->lti_add->bind_int( 2, static_cast<uint64_t>( name_number ) );
1439  my_agent->smem_stmts->lti_add->bind_int( 3, static_cast<uint64_t>( 0 ) );
1440  my_agent->smem_stmts->lti_add->bind_double( 4, static_cast<double>( 0 ) );
1441  my_agent->smem_stmts->lti_add->bind_int( 5, static_cast<uint64_t>( 0 ) );
1442  my_agent->smem_stmts->lti_add->bind_int( 6, static_cast<uint64_t>( 0 ) );
1443  my_agent->smem_stmts->lti_add->bind_int( 7, static_cast<uint64_t>( 0 ) );
1445 
1446  return_val = static_cast<smem_lti_id>( my_agent->smem_db->last_insert_rowid() );
1447 
1448  // increment stat
1449  my_agent->smem_stats->chunks->set_value( my_agent->smem_stats->chunks->get_value() + 1 );
1450 
1451  return return_val;
1452 }
1453 
1454 // makes a non-long-term identifier into a long-term identifier
1455 inline smem_lti_id smem_lti_soar_add( agent *my_agent, Symbol *id )
1456 {
1457  if ( ( id->common.symbol_type == IDENTIFIER_SYMBOL_TYPE ) &&
1458  ( id->id.smem_lti == NIL ) )
1459  {
1460  // try to find existing lti
1461  id->id.smem_lti = smem_lti_get_id( my_agent, id->id.name_letter, id->id.name_number );
1462 
1463  // if doesn't exist, add
1464  if ( id->id.smem_lti == NIL )
1465  {
1466  id->id.smem_lti = smem_lti_add_id( my_agent, id->id.name_letter, id->id.name_number );
1467 
1468  id->id.smem_time_id = my_agent->epmem_stats->time->get_value();
1469  id->id.smem_valid = my_agent->epmem_validation;
1470  epmem_schedule_promotion( my_agent, id );
1471  }
1472  }
1473 
1474  return id->id.smem_lti;
1475 }
1476 
1477 // returns a reference to an lti
1478 Symbol *smem_lti_soar_make( agent *my_agent, smem_lti_id lti, char name_letter, uint64_t name_number, goal_stack_level level )
1479 {
1480  Symbol *return_val;
1481 
1482  // try to find existing
1483  return_val = find_identifier( my_agent, name_letter, name_number );
1484 
1485  // otherwise create
1486  if ( return_val == NIL )
1487  {
1488  return_val = make_new_identifier( my_agent, name_letter, level, name_number );
1489  }
1490  else
1491  {
1492  symbol_add_ref( return_val );
1493 
1494  if ( ( return_val->id.level == SMEM_LTI_UNKNOWN_LEVEL ) && ( level != SMEM_LTI_UNKNOWN_LEVEL ) )
1495  {
1496  return_val->id.level = level;
1497  return_val->id.promotion_level = level;
1498  }
1499  }
1500 
1501  // set lti field irrespective
1502  return_val->id.smem_lti = lti;
1503 
1504  return return_val;
1505 }
1506 
1508 {
1509  if ( my_agent->smem_db->get_status() == soar_module::connected )
1510  {
1511  // letter, max
1512  while ( my_agent->smem_stmts->lti_max->execute() == soar_module::row )
1513  {
1514  uint64_t name_letter = static_cast<uint64_t>( my_agent->smem_stmts->lti_max->column_int( 0 ) );
1515  uint64_t letter_max = static_cast<uint64_t>( my_agent->smem_stmts->lti_max->column_int( 1 ) );
1516 
1517  // shift to alphabet
1518  name_letter -= static_cast<uint64_t>( 'A' );
1519 
1520  // get count
1521  uint64_t *letter_ct =& my_agent->id_counter[ name_letter ];
1522 
1523  // adjust if necessary
1524  if ( (*letter_ct) <= letter_max )
1525  {
1526  (*letter_ct) = ( letter_max + 1 );
1527  }
1528  }
1529 
1530  my_agent->smem_stmts->lti_max->reinitialize();
1531  }
1532 }
1533 
1534 
1537 // Storage Functions (smem::storage)
1540 
1542 {
1543  smem_slot **s =& (*slots)[ attr ];
1544 
1545  if ( !(*s) )
1546  {
1547  (*s) = new smem_slot;
1548  }
1549 
1550  return (*s);
1551 }
1552 
1553 void smem_disconnect_chunk( agent *my_agent, smem_lti_id parent_id )
1554 {
1555  // adjust attr, attr/value counts
1556  {
1557  uint64_t pair_count = 0;
1558 
1559  smem_lti_id child_attr = 0;
1560  std::set<smem_lti_id> distinct_attr;
1561 
1562  // pairs first, accumulate distinct attributes and pair count
1563  my_agent->smem_stmts->web_all->bind_int( 1, parent_id );
1564  while ( my_agent->smem_stmts->web_all->execute() == soar_module::row )
1565  {
1566  pair_count++;
1567 
1568  child_attr = my_agent->smem_stmts->web_all->column_int( 0 );
1569  distinct_attr.insert( child_attr );
1570 
1571  // null -> attr/lti
1572  if ( my_agent->smem_stmts->web_all->column_int( 1 ) != SMEM_WEB_NULL )
1573  {
1574  // adjust in opposite direction ( adjust, attribute, const )
1575  my_agent->smem_stmts->ct_const_update->bind_int( 1, -1 );
1576  my_agent->smem_stmts->ct_const_update->bind_int( 2, child_attr );
1577  my_agent->smem_stmts->ct_const_update->bind_int( 3, my_agent->smem_stmts->web_all->column_int( 1 ) );
1579  }
1580  else
1581  {
1582  // adjust in opposite direction ( adjust, attribute, lti )
1583  my_agent->smem_stmts->ct_lti_update->bind_int( 1, -1 );
1584  my_agent->smem_stmts->ct_lti_update->bind_int( 2, child_attr );
1585  my_agent->smem_stmts->ct_lti_update->bind_int( 3, my_agent->smem_stmts->web_all->column_int( 2 ) );
1587  }
1588  }
1589  my_agent->smem_stmts->web_all->reinitialize();
1590 
1591  // now attributes
1592  for (std::set<smem_lti_id>::iterator a=distinct_attr.begin(); a!=distinct_attr.end(); a++)
1593  {
1594  // adjust in opposite direction ( adjust, attribute )
1595  my_agent->smem_stmts->ct_attr_update->bind_int( 1, -1 );
1596  my_agent->smem_stmts->ct_attr_update->bind_int( 2, *a );
1598  }
1599 
1600  // update local statistic
1601  my_agent->smem_stats->slots->set_value( my_agent->smem_stats->slots->get_value() - pair_count );
1602  }
1603 
1604  // disconnect
1605  {
1606  my_agent->smem_stmts->web_truncate->bind_int( 1, parent_id );
1608  }
1609 }
1610 
1611 void smem_store_chunk( agent *my_agent, smem_lti_id parent_id, smem_slot_map *children, bool remove_old_children = true, Symbol* print_id = NULL )
1612 {
1613  // if remove children, disconnect chunk -> no existing edges
1614  // else, need to query number of existing edges
1615  uint64_t existing_edges = 0;
1616  if ( remove_old_children )
1617  {
1618  smem_disconnect_chunk( my_agent, parent_id );
1619 
1620  // provide trace output
1621  if ( my_agent->sysparams[ TRACE_SMEM_SYSPARAM ] && ( print_id ) )
1622  {
1623  char buf[256];
1624 
1625  snprintf_with_symbols( my_agent, buf, 256, "<=SMEM: (%y ^* *)\n", print_id );
1626 
1627  print( my_agent, buf );
1628  xml_generate_warning( my_agent, buf );
1629  }
1630  }
1631  else
1632  {
1633  my_agent->smem_stmts->act_lti_child_ct_get->bind_int( 1, parent_id );
1634  my_agent->smem_stmts->act_lti_child_ct_get->execute();
1635 
1636  existing_edges = static_cast<uint64_t>( my_agent->smem_stmts->act_lti_child_ct_get->column_int(0) );
1637 
1639  }
1640 
1641  // get new edges
1642  // if didn't disconnect, entails lookups in existing edges
1643  std::set<smem_hash_id> attr_new;
1644  std::set< std::pair<smem_hash_id, smem_hash_id> > const_new;
1645  std::set< std::pair<smem_hash_id, smem_lti_id> > lti_new;
1646  {
1647  smem_slot_map::iterator s;
1648  smem_slot::iterator v;
1649 
1650  smem_hash_id attr_hash = 0;
1651  smem_hash_id value_hash = 0;
1652  smem_lti_id value_lti = 0;
1653 
1654  for ( s=children->begin(); s!=children->end(); s++ )
1655  {
1656  attr_hash = smem_temporal_hash( my_agent, s->first );
1657  if ( remove_old_children )
1658  {
1659  attr_new.insert( attr_hash );
1660  }
1661  else
1662  {
1663  // parent_id, attr
1664  my_agent->smem_stmts->web_attr_child->bind_int( 1, parent_id );
1665  my_agent->smem_stmts->web_attr_child->bind_int( 2, attr_hash );
1667  {
1668  attr_new.insert( attr_hash );
1669  }
1670  }
1671 
1672  for ( v=s->second->begin(); v!=s->second->end(); v++ )
1673  {
1674  if ( (*v)->val_const.val_type == value_const_t )
1675  {
1676  value_hash = smem_temporal_hash( my_agent, (*v)->val_const.val_value );
1677 
1678  if ( remove_old_children )
1679  {
1680  const_new.insert( std::make_pair< smem_hash_id, smem_hash_id >( attr_hash, value_hash ) );
1681  }
1682  else
1683  {
1684  // parent_id, attr, val_const
1685  my_agent->smem_stmts->web_const_child->bind_int( 1, parent_id );
1686  my_agent->smem_stmts->web_const_child->bind_int( 2, attr_hash );
1687  my_agent->smem_stmts->web_const_child->bind_int( 3, value_hash );
1689  {
1690  const_new.insert( std::make_pair< smem_hash_id, smem_hash_id >( attr_hash, value_hash ) );
1691  }
1692  }
1693 
1694  // provide trace output
1695  if ( my_agent->sysparams[ TRACE_SMEM_SYSPARAM ] && ( print_id ) )
1696  {
1697  char buf[256];
1698 
1699  snprintf_with_symbols( my_agent, buf, 256, "=>SMEM: (%y ^%y %y)\n", print_id, s->first, (*v)->val_const.val_value );
1700 
1701  print( my_agent, buf );
1702  xml_generate_warning( my_agent, buf );
1703  }
1704  }
1705  else
1706  {
1707  value_lti = (*v)->val_lti.val_value->lti_id;
1708  if ( value_lti == NIL )
1709  {
1710  value_lti = smem_lti_add_id( my_agent, (*v)->val_lti.val_value->lti_letter, (*v)->val_lti.val_value->lti_number );
1711  (*v)->val_lti.val_value->lti_id = value_lti;
1712 
1713  if ( (*v)->val_lti.val_value->soar_id != NIL )
1714  {
1715  (*v)->val_lti.val_value->soar_id->id.smem_lti = value_lti;
1716 
1717  (*v)->val_lti.val_value->soar_id->id.smem_time_id = my_agent->epmem_stats->time->get_value();
1718  (*v)->val_lti.val_value->soar_id->id.smem_valid = my_agent->epmem_validation;
1719  epmem_schedule_promotion( my_agent, (*v)->val_lti.val_value->soar_id );
1720  }
1721  }
1722 
1723  if ( remove_old_children )
1724  {
1725  lti_new.insert( std::make_pair< smem_hash_id, smem_lti_id >( attr_hash, value_lti ) );
1726  }
1727  else
1728  {
1729  // parent_id, attr, val_lti
1730  my_agent->smem_stmts->web_lti_child->bind_int( 1, parent_id );
1731  my_agent->smem_stmts->web_lti_child->bind_int( 2, attr_hash );
1732  my_agent->smem_stmts->web_lti_child->bind_int( 3, value_lti );
1734  {
1735  lti_new.insert( std::make_pair< smem_hash_id, smem_lti_id >( attr_hash, value_lti ) );
1736  }
1737  }
1738 
1739  // provide trace output
1740  if ( my_agent->sysparams[ TRACE_SMEM_SYSPARAM ] && ( print_id ) )
1741  {
1742  char buf[256];
1743 
1744  snprintf_with_symbols( my_agent, buf, 256, "=>SMEM: (%y ^%y %y)\n", print_id, s->first, (*v)->val_lti.val_value->soar_id );
1745 
1746  print( my_agent, buf );
1747  xml_generate_warning( my_agent, buf );
1748  }
1749  }
1750  }
1751  }
1752  }
1753 
1754  // activation function assumes proper thresholding state
1755  // thus, consider four cases of augmentation counts (w.r.t. thresh)
1756  // 1. before=below, after=below: good (activation will update web)
1757  // 2. before=below, after=above: need to update web->inf
1758  // 3. before=after, after=below: good (activation will update web, free transition)
1759  // 4. before=after, after=after: good (activation won't touch web)
1760  //
1761  // hence, we detect + handle case #2 here
1762  uint64_t new_edges = ( existing_edges + const_new.size() + lti_new.size() );
1763  bool after_above;
1764  double web_act = static_cast<double>( SMEM_ACT_MAX );
1765  {
1766  uint64_t thresh = static_cast<uint64_t>( my_agent->smem_params->thresh->get_value() );
1767  after_above = ( new_edges >= thresh );
1768 
1769  // if before below
1770  if ( existing_edges < thresh )
1771  {
1772  if ( after_above )
1773  {
1774  // update web to inf
1775  my_agent->smem_stmts->act_set->bind_double( 1, web_act );
1776  my_agent->smem_stmts->act_set->bind_int( 2, parent_id );
1778  }
1779  }
1780  }
1781 
1782  // update edge counter
1783  {
1784  my_agent->smem_stmts->act_lti_child_ct_set->bind_int( 1, new_edges );
1785  my_agent->smem_stmts->act_lti_child_ct_set->bind_int( 2, parent_id );
1787  }
1788 
1789  // now we can safely activate the lti
1790  {
1791  double lti_act = smem_lti_activate( my_agent, parent_id, true, new_edges );
1792 
1793  if ( !after_above )
1794  {
1795  web_act = lti_act;
1796  }
1797  }
1798 
1799  // insert new edges, update counters
1800  {
1801  // attr/const pairs
1802  {
1803  for ( std::set< std::pair< smem_hash_id, smem_hash_id > >::iterator p=const_new.begin(); p!=const_new.end(); p++ )
1804  {
1805  // insert
1806  {
1807  // parent_id, attr, val_const, val_lti, act_value
1808  my_agent->smem_stmts->web_add->bind_int( 1, parent_id );
1809  my_agent->smem_stmts->web_add->bind_int( 2, p->first );
1810  my_agent->smem_stmts->web_add->bind_int( 3, p->second );
1811  my_agent->smem_stmts->web_add->bind_int( 4, SMEM_WEB_NULL );
1812  my_agent->smem_stmts->web_add->bind_double( 5, web_act );
1814  }
1815 
1816  // update counter
1817  {
1818  // check if counter exists (and add if does not): attr, val
1819  my_agent->smem_stmts->ct_const_check->bind_int( 1, p->first );
1820  my_agent->smem_stmts->ct_const_check->bind_int( 2, p->second );
1822  {
1823  my_agent->smem_stmts->ct_const_add->bind_int( 1, p->first );
1824  my_agent->smem_stmts->ct_const_add->bind_int( 2, p->second );
1826  }
1827  else
1828  {
1829  // adjust count (adjustment, attr, val)
1830  my_agent->smem_stmts->ct_const_update->bind_int( 1, 1 );
1831  my_agent->smem_stmts->ct_const_update->bind_int( 2, p->first );
1832  my_agent->smem_stmts->ct_const_update->bind_int( 3, p->second );
1834  }
1835  }
1836  }
1837  }
1838 
1839  // attr/lti pairs
1840  {
1841  for ( std::set< std::pair< smem_hash_id, smem_lti_id > >::iterator p=lti_new.begin(); p!=lti_new.end(); p++ )
1842  {
1843  // insert
1844  {
1845  // parent_id, attr, val_const, val_lti, act_value
1846  my_agent->smem_stmts->web_add->bind_int( 1, parent_id );
1847  my_agent->smem_stmts->web_add->bind_int( 2, p->first );
1848  my_agent->smem_stmts->web_add->bind_int( 3, SMEM_WEB_NULL );
1849  my_agent->smem_stmts->web_add->bind_int( 4, p->second );
1850  my_agent->smem_stmts->web_add->bind_double( 5, web_act );
1852  }
1853 
1854  // update counter
1855  {
1856  // check if counter exists (and add if does not): attr, val
1857  my_agent->smem_stmts->ct_lti_check->bind_int( 1, p->first );
1858  my_agent->smem_stmts->ct_lti_check->bind_int( 2, p->second );
1860  {
1861  my_agent->smem_stmts->ct_lti_add->bind_int( 1, p->first );
1862  my_agent->smem_stmts->ct_lti_add->bind_int( 2, p->second );
1864  }
1865  else
1866  {
1867  // adjust count (adjustment, attr, lti)
1868  my_agent->smem_stmts->ct_lti_update->bind_int( 1, 1 );
1869  my_agent->smem_stmts->ct_lti_update->bind_int( 2, p->first );
1870  my_agent->smem_stmts->ct_lti_update->bind_int( 3, p->second );
1872  }
1873  }
1874  }
1875  }
1876 
1877  // update attribute count
1878  {
1879  for ( std::set< smem_hash_id >::iterator a=attr_new.begin(); a!=attr_new.end(); a++ )
1880  {
1881  // check if counter exists (and add if does not): attr
1882  my_agent->smem_stmts->ct_attr_check->bind_int( 1, *a );
1884  {
1885  my_agent->smem_stmts->ct_attr_add->bind_int( 1, *a );
1887  }
1888  else
1889  {
1890  // adjust count (adjustment, attr)
1891  my_agent->smem_stmts->ct_attr_update->bind_int( 1, 1 );
1892  my_agent->smem_stmts->ct_attr_update->bind_int( 2, *a );
1894  }
1895  }
1896  }
1897 
1898  // update local edge count
1899  {
1900  my_agent->smem_stats->slots->set_value( my_agent->smem_stats->slots->get_value() + ( const_new.size() + lti_new.size() ) );
1901  }
1902  }
1903 }
1904 
1905 void smem_soar_store( agent *my_agent, Symbol *id, smem_storage_type store_type = store_level, tc_number tc = NIL )
1906 {
1907  // transitive closure only matters for recursive storage
1908  if ( ( store_type == store_recursive ) && ( tc == NIL ) )
1909  {
1910  tc = get_new_tc_number( my_agent );
1911  }
1912  smem_sym_list shorties;
1913 
1914  // get level
1915  smem_wme_list *children = smem_get_direct_augs_of_id( id, tc );
1916  smem_wme_list::iterator w;
1917 
1918  // make the target an lti, so intermediary data structure has lti_id
1919  // (takes care of short-term id self-referencing)
1920  smem_lti_soar_add( my_agent, id );
1921 
1922  // encode this level
1923  {
1924  smem_sym_to_chunk_map sym_to_chunk;
1925  smem_sym_to_chunk_map::iterator c_p;
1926  smem_chunk **c;
1927 
1928  smem_slot_map slots;
1929  smem_slot_map::iterator s_p;
1930  smem_slot::iterator v_p;
1931  smem_slot *s;
1932  smem_chunk_value *v;
1933 
1934  for ( w=children->begin(); w!=children->end(); w++ )
1935  {
1936  // get slot
1937  s = smem_make_slot( &( slots ), (*w)->attr );
1938 
1939  // create value, per type
1940  v = new smem_chunk_value;
1941  if ( smem_symbol_is_constant( (*w)->value ) )
1942  {
1944  v->val_const.val_value = (*w)->value;
1945  }
1946  else
1947  {
1949 
1950  // try to find existing chunk
1951  c =& sym_to_chunk[ (*w)->value ];
1952 
1953  // if doesn't exist, add; else use existing
1954  if ( !(*c) )
1955  {
1956  (*c) = new smem_chunk;
1957  (*c)->lti_id = (*w)->value->id.smem_lti;
1958  (*c)->lti_letter = (*w)->value->id.name_letter;
1959  (*c)->lti_number = (*w)->value->id.name_number;
1960  (*c)->slots = NULL;
1961  (*c)->soar_id = (*w)->value;
1962 
1963  // only traverse to short-term identifiers
1964  if ( ( store_type == store_recursive ) && ( (*c)->lti_id == NIL ) )
1965  {
1966  shorties.push_back( (*c)->soar_id );
1967  }
1968  }
1969 
1970  v->val_lti.val_value = (*c);
1971  }
1972 
1973  // add value to slot
1974  s->push_back( v );
1975  }
1976 
1977  smem_store_chunk( my_agent, id->id.smem_lti, &( slots ), true, id );
1978 
1979  // clean up
1980  {
1981  // de-allocate slots
1982  for ( s_p=slots.begin(); s_p!=slots.end(); s_p++ )
1983  {
1984  for ( v_p=s_p->second->begin(); v_p!=s_p->second->end(); v_p++ )
1985  {
1986  delete (*v_p);
1987  }
1988 
1989  delete s_p->second;
1990  }
1991 
1992  // de-allocate chunks
1993  for ( c_p=sym_to_chunk.begin(); c_p!=sym_to_chunk.end(); c_p++ )
1994  {
1995  delete c_p->second;
1996  }
1997 
1998  delete children;
1999  }
2000  }
2001 
2002  // recurse as necessary
2003  for ( smem_sym_list::iterator shorty=shorties.begin(); shorty!=shorties.end(); shorty++ )
2004  {
2005  smem_soar_store( my_agent, (*shorty), store_recursive, tc );
2006  }
2007 }
2008 
2009 
2012 // Non-Cue-Based Retrieval Functions (smem::ncb)
2015 
2016 void smem_install_memory( agent *my_agent, Symbol *state, smem_lti_id parent_id, Symbol *lti, bool activate_lti, soar_module::symbol_triple_list& meta_wmes, soar_module::symbol_triple_list& retrieval_wmes )
2017 {
2019  my_agent->smem_timers->ncb_retrieval->start();
2021 
2022  // get the ^result header for this state
2023  Symbol *result_header = state->id.smem_result_header;
2024 
2025  // get identifier if not known
2026  bool lti_created_here = false;
2027  if ( lti == NIL )
2028  {
2030 
2031  q->bind_int( 1, parent_id );
2032  q->execute();
2033 
2034  lti = smem_lti_soar_make( my_agent, parent_id, static_cast<char>( q->column_int( 0 ) ), static_cast<uint64_t>( q->column_int( 1 ) ), result_header->id.level );
2035 
2036  q->reinitialize();
2037 
2038  lti_created_here = true;
2039  }
2040 
2041  // activate lti
2042  if ( activate_lti )
2043  {
2044  smem_lti_activate( my_agent, parent_id, true );
2045  }
2046 
2047  // point retrieved to lti
2048  smem_buffer_add_wme( meta_wmes, result_header, my_agent->smem_sym_retrieved, lti );
2049  if ( lti_created_here )
2050  {
2051  // if the identifier was created above we need to
2052  // remove a single ref count AFTER the wme
2053  // is added (such as to not deallocate the symbol
2054  // prematurely)
2055  symbol_remove_ref( my_agent, lti );
2056  }
2057 
2058  // if no children, then retrieve children
2059  // merge may override this behavior
2060  if ( ( my_agent->smem_params->merge->get_value() == smem_param_container::merge_add ) ||
2061  ( ( lti->id.impasse_wmes == NIL ) &&
2062  ( lti->id.input_wmes == NIL ) &&
2063  ( lti->id.slots == NIL ) ) )
2064  {
2065  soar_module::sqlite_statement *expand_q = my_agent->smem_stmts->web_expand;
2066  Symbol *attr_sym;
2067  Symbol *value_sym;
2068 
2069  // get direct children: attr_type, attr_hash, value_type, value_hash, value_letter, value_num, value_lti
2070  expand_q->bind_int( 1, parent_id );
2071  while ( expand_q->execute() == soar_module::row )
2072  {
2073  // make the identifier symbol irrespective of value type
2074  attr_sym = smem_reverse_hash( my_agent, static_cast<byte>( expand_q->column_int(0) ), static_cast<smem_hash_id>( expand_q->column_int(1) ) );
2075 
2076  // identifier vs. constant
2077  if ( expand_q->column_int( 6 ) != SMEM_WEB_NULL )
2078  {
2079  value_sym = smem_lti_soar_make( my_agent, static_cast<smem_lti_id>( expand_q->column_int( 6 ) ), static_cast<char>( expand_q->column_int( 4 ) ), static_cast<uint64_t>( expand_q->column_int( 5 ) ), lti->id.level );
2080  }
2081  else
2082  {
2083  value_sym = smem_reverse_hash( my_agent, static_cast<byte>( expand_q->column_int(2) ), static_cast<smem_hash_id>( expand_q->column_int(3) ) );
2084  }
2085 
2086  // add wme
2087  smem_buffer_add_wme( retrieval_wmes, lti, attr_sym, value_sym );
2088 
2089  // deal with ref counts - attribute/values are always created in this function
2090  // (thus an extra ref count is set before adding a wme)
2091  symbol_remove_ref( my_agent, attr_sym );
2092  symbol_remove_ref( my_agent, value_sym );
2093  }
2094  expand_q->reinitialize();
2095  }
2096 
2098  my_agent->smem_timers->ncb_retrieval->stop();
2100 }
2101 
2102 
2105 // Cue-Based Retrieval Functions (smem::cbr)
2108 
2110 {
2112 
2113  // first, point to correct query and setup
2114  // query-specific parameters
2115  if ( el->element_type == attr_t )
2116  {
2117  // attr=?
2118  q = my_agent->smem_stmts->web_attr_all;
2119  }
2120  else if ( el->element_type == value_const_t )
2121  {
2122  // attr=? AND val_const=?
2123  q = my_agent->smem_stmts->web_const_all;
2124  q->bind_int( 2, el->value_hash );
2125  }
2126  else if ( el->element_type == value_lti_t )
2127  {
2128  // attr=? AND val_lti=?
2129  q = my_agent->smem_stmts->web_lti_all;
2130  q->bind_int( 2, el->value_lti );
2131  }
2132 
2133  // all require hash as first parameter
2134  q->bind_int( 1, el->attr_hash );
2135 
2136  return q;
2137 }
2138 
2139 inline bool _smem_process_cue_wme( agent* my_agent, wme* w, bool pos_cue, smem_prioritized_weighted_cue& weighted_pq )
2140 {
2141  bool good_wme = true;
2142  smem_weighted_cue_element *new_cue_element;
2143 
2144  smem_hash_id attr_hash;
2145  smem_hash_id value_hash;
2146  smem_lti_id value_lti;
2147  smem_cue_element_type element_type;
2148 
2150 
2151  {
2152  // we only have to do hard work if
2153  attr_hash = smem_temporal_hash( my_agent, w->attr, false );
2154  if ( attr_hash != NIL )
2155  {
2156  if ( smem_symbol_is_constant( w->value ) )
2157  {
2158  value_lti = NIL;
2159  value_hash = smem_temporal_hash( my_agent, w->value, false );
2160 
2161  if ( value_hash != NIL )
2162  {
2163  q = my_agent->smem_stmts->ct_const_get;
2164  q->bind_int( 1, attr_hash );
2165  q->bind_int( 2, value_hash );
2166 
2167  element_type = value_const_t;
2168  }
2169  else
2170  {
2171  if ( pos_cue )
2172  {
2173  good_wme = false;
2174  }
2175  }
2176  }
2177  else
2178  {
2179  value_lti = w->value->id.smem_lti;
2180  value_hash = NIL;
2181 
2182  if ( value_lti == NIL )
2183  {
2184  q = my_agent->smem_stmts->ct_attr_get;
2185  q->bind_int( 1, attr_hash );
2186 
2187  element_type = attr_t;
2188  }
2189  else
2190  {
2191  q = my_agent->smem_stmts->ct_lti_get;
2192  q->bind_int( 1, attr_hash );
2193  q->bind_int( 2, value_lti );
2194 
2195  element_type = value_lti_t;
2196  }
2197  }
2198 
2199  if ( good_wme )
2200  {
2201  if ( q->execute() == soar_module::row )
2202  {
2203  new_cue_element = new smem_weighted_cue_element;
2204 
2205  new_cue_element->weight = q->column_int( 0 );
2206  new_cue_element->attr_hash = attr_hash;
2207  new_cue_element->value_hash = value_hash;
2208  new_cue_element->value_lti = value_lti;
2209  new_cue_element->cue_element = w;
2210 
2211  new_cue_element->element_type = element_type;
2212  new_cue_element->pos_element = pos_cue;
2213 
2214  weighted_pq.push( new_cue_element );
2215  new_cue_element = NULL;
2216  }
2217  else
2218  {
2219  if ( pos_cue )
2220  {
2221  good_wme = false;
2222  }
2223  }
2224 
2225  q->reinitialize();
2226  }
2227  }
2228  else
2229  {
2230  if ( pos_cue )
2231  {
2232  good_wme = false;
2233  }
2234  }
2235  }
2236 
2237  return good_wme;
2238 }
2239 
2240 smem_lti_id smem_process_query( agent *my_agent, Symbol *state, Symbol *query, Symbol *negquery, smem_lti_set *prohibit, soar_module::wme_set& cue_wmes, soar_module::symbol_triple_list& meta_wmes, soar_module::symbol_triple_list& retrieval_wmes, smem_query_levels query_level = qry_full )
2241 {
2242  smem_weighted_cue_list weighted_cue;
2243  bool good_cue = true;
2244 
2246 
2247  smem_lti_id king_id = NIL;
2248 
2250  my_agent->smem_timers->query->start();
2252 
2253  // prepare query stats
2254  {
2255  smem_prioritized_weighted_cue weighted_pq;
2256 
2257  // positive cue - always
2258  {
2259  smem_wme_list *cue = smem_get_direct_augs_of_id( query );
2260  if ( cue->empty() )
2261  {
2262  good_cue = false;
2263  }
2264 
2265  for ( smem_wme_list::iterator cue_p=cue->begin(); cue_p!=cue->end(); cue_p++ )
2266  {
2267  cue_wmes.insert( (*cue_p) );
2268 
2269  if ( good_cue )
2270  {
2271  good_cue = _smem_process_cue_wme( my_agent, (*cue_p), true, weighted_pq );
2272  }
2273  }
2274 
2275  delete cue;
2276  }
2277 
2278  // negative cue - if present
2279  if ( negquery )
2280  {
2281  smem_wme_list *cue = smem_get_direct_augs_of_id( negquery );
2282 
2283  for ( smem_wme_list::iterator cue_p=cue->begin(); cue_p!=cue->end(); cue_p++ )
2284  {
2285  cue_wmes.insert( (*cue_p) );
2286 
2287  if ( good_cue )
2288  {
2289  good_cue = _smem_process_cue_wme( my_agent, (*cue_p), false, weighted_pq );
2290  }
2291  }
2292 
2293  delete cue;
2294  }
2295 
2296  // if valid cue, transfer priority queue to list
2297  if ( good_cue )
2298  {
2299  while ( !weighted_pq.empty() )
2300  {
2301  weighted_cue.push_back( weighted_pq.top() );
2302  weighted_pq.pop();
2303  }
2304  }
2305  // else deallocate priority queue contents
2306  else
2307  {
2308  while ( !weighted_pq.empty() )
2309  {
2310  delete weighted_pq.top();
2311  weighted_pq.pop();
2312  }
2313  }
2314  }
2315 
2316  // only search if the cue was valid
2317  if ( good_cue && !weighted_cue.empty() )
2318  {
2319  // by definition, the first positive-cue element dictates the candidate set
2320  smem_weighted_cue_list::iterator cand_set;
2321  smem_weighted_cue_list::iterator next_element;
2322  for ( next_element=weighted_cue.begin(); next_element!=weighted_cue.end(); next_element++ )
2323  {
2324  if ( (*next_element)->pos_element )
2325  {
2326  cand_set = next_element;
2327  break;
2328  }
2329  }
2330 
2331  soar_module::sqlite_statement *q2 = NULL;
2332  smem_lti_set::iterator prohibit_p;
2333 
2334  smem_lti_id cand;
2335  bool good_cand;
2336 
2338  {
2339  // naive base-level updates means update activation of
2340  // every candidate in the minimal list before the
2341  // confirmation walk
2343  {
2344  q = smem_setup_web_crawl( my_agent, (*cand_set) );
2345 
2346  // queue up distinct lti's to update
2347  // - set because queries could contain wilds
2348  // - not in loop because the effects of activation may actually
2349  // alter the resultset of the query (isolation???)
2350  std::set< smem_lti_id > to_update;
2351  while ( q->execute() == soar_module::row )
2352  {
2353  to_update.insert( q->column_int(0) );
2354  }
2355 
2356  for ( std::set< smem_lti_id >::iterator it=to_update.begin(); it!=to_update.end(); it++ )
2357  {
2358  smem_lti_activate( my_agent, (*it), false );
2359  }
2360 
2361  q->reinitialize();
2362  }
2363  }
2364 
2365  // setup first query, which is sorted on activation already
2366  q = smem_setup_web_crawl( my_agent, (*cand_set) );
2367 
2368  // this becomes the minimal set to walk (till match or fail)
2369  if ( q->execute() == soar_module::row )
2370  {
2371  smem_prioritized_activated_lti_queue plentiful_parents;
2372  bool more_rows = true;
2373  bool use_db = false;
2374  bool has_feature = false;
2375 
2376  while ( more_rows && ( q->column_double( 1 ) == static_cast<double>( SMEM_ACT_MAX ) ) )
2377  {
2378  my_agent->smem_stmts->act_lti_get->bind_int( 1, q->column_int( 0 ) );
2379  my_agent->smem_stmts->act_lti_get->execute();
2380  plentiful_parents.push( std::make_pair< double, smem_lti_id >( my_agent->smem_stmts->act_lti_get->column_double( 0 ), q->column_int( 0 ) ) );
2381  my_agent->smem_stmts->act_lti_get->reinitialize();
2382 
2383  more_rows = ( q->execute() == soar_module::row );
2384  }
2385 
2386  while ( ( king_id == NIL ) && ( ( more_rows ) || ( !plentiful_parents.empty() ) ) )
2387  {
2388  // choose next candidate (db vs. priority queue)
2389  {
2390  use_db = false;
2391 
2392  if ( !more_rows )
2393  {
2394  use_db = false;
2395  }
2396  else if ( plentiful_parents.empty() )
2397  {
2398  use_db = true;
2399  }
2400  else
2401  {
2402  use_db = ( q->column_double( 1 ) > plentiful_parents.top().first );
2403  }
2404 
2405  if ( use_db )
2406  {
2407  cand = q->column_int( 0 );
2408  more_rows = ( q->execute() == soar_module::row );
2409  }
2410  else
2411  {
2412  cand = plentiful_parents.top().second;
2413  plentiful_parents.pop();
2414  }
2415  }
2416 
2417  // if not prohibited, submit to the remaining cue elements
2418  prohibit_p = prohibit->find( cand );
2419  if ( prohibit_p == prohibit->end() )
2420  {
2421  good_cand = true;
2422 
2423  for ( next_element=weighted_cue.begin(); next_element!=weighted_cue.end(); next_element++ )
2424  {
2425  // don't need to check the generating list
2426  if ( (*next_element) == (*cand_set) )
2427  {
2428  continue;
2429  }
2430 
2431  if ( (*next_element)->element_type == attr_t )
2432  {
2433  // parent=? AND attr=?
2434  q2 = my_agent->smem_stmts->web_attr_child;
2435  }
2436  else if ( (*next_element)->element_type == value_const_t )
2437  {
2438  // parent=? AND attr=? AND val_const=?
2439  q2 = my_agent->smem_stmts->web_const_child;
2440  q2->bind_int( 3, (*next_element)->value_hash );
2441  }
2442  else if ( (*next_element)->element_type == value_lti_t )
2443  {
2444  // parent=? AND attr=? AND val_lti=?
2445  q2 = my_agent->smem_stmts->web_lti_child;
2446  q2->bind_int( 3, (*next_element)->value_lti );
2447  }
2448 
2449  // all require own id, attribute
2450  q2->bind_int( 1, cand );
2451  q2->bind_int( 2, (*next_element)->attr_hash );
2452 
2453  has_feature = ( q2->execute( soar_module::op_reinit ) == soar_module::row );
2454  good_cand = ( ( (*next_element)->pos_element )?( has_feature ):( !has_feature ) );
2455  if ( !good_cand )
2456  {
2457  break;
2458  }
2459  }
2460 
2461  if ( good_cand )
2462  {
2463  king_id = cand;
2464  }
2465  }
2466  }
2467  }
2468  q->reinitialize();
2469 
2470  // clean weighted cue
2471  for ( next_element=weighted_cue.begin(); next_element!=weighted_cue.end(); next_element++ )
2472  {
2473  delete (*next_element);
2474  }
2475  }
2476 
2477  // reconstruction depends upon level
2478  if ( query_level == qry_full )
2479  {
2480  // produce results
2481  if ( king_id != NIL )
2482  {
2483  // success!
2484  smem_buffer_add_wme( meta_wmes, state->id.smem_result_header, my_agent->smem_sym_success, query );
2485  if ( negquery )
2486  {
2487  smem_buffer_add_wme( meta_wmes, state->id.smem_result_header, my_agent->smem_sym_success, negquery );
2488  }
2489 
2491  my_agent->smem_timers->query->stop();
2493 
2494  smem_install_memory( my_agent, state, king_id, NIL, ( my_agent->smem_params->activate_on_query->get_value() == soar_module::on ), meta_wmes, retrieval_wmes );
2495  }
2496  else
2497  {
2498  smem_buffer_add_wme( meta_wmes, state->id.smem_result_header, my_agent->smem_sym_failure, query );
2499  if ( negquery )
2500  {
2501  smem_buffer_add_wme( meta_wmes, state->id.smem_result_header, my_agent->smem_sym_failure, negquery );
2502  }
2503 
2505  my_agent->smem_timers->query->stop();
2507  }
2508  }
2509  else
2510  {
2512  my_agent->smem_timers->query->stop();
2514  }
2515 
2516  return king_id;
2517 }
2518 
2519 
2522 // Initialization (smem::init)
2525 
2526 void smem_clear_result( agent *my_agent, Symbol *state )
2527 {
2528  preference *pref;
2529 
2530  while ( !state->id.smem_info->smem_wmes->empty() )
2531  {
2532  pref = state->id.smem_info->smem_wmes->back();
2533  state->id.smem_info->smem_wmes->pop_back();
2534 
2535  if ( pref->in_tm )
2536  {
2537  remove_preference_from_tm( my_agent, pref );
2538  }
2539  }
2540 }
2541 
2542 // performs cleanup when a state is removed
2543 void smem_reset( agent *my_agent, Symbol *state )
2544 {
2545  if ( state == NULL )
2546  {
2547  state = my_agent->top_goal;
2548  }
2549 
2550  while( state )
2551  {
2552  smem_data *data = state->id.smem_info;
2553 
2554  data->last_cmd_time[0] = 0;
2555  data->last_cmd_time[1] = 0;
2556  data->last_cmd_count[0] = 0;
2557  data->last_cmd_count[1] = 0;
2558 
2559  // this will be called after prefs from goal are already removed,
2560  // so just clear out result stack
2561  data->smem_wmes->clear();
2562 
2563  state = state->id.lower_goal;
2564  }
2565 }
2566 
2567 // opens the SQLite database and performs all initialization required for the current mode
2568 void smem_init_db( agent *my_agent )
2569 {
2570  if ( my_agent->smem_db->get_status() != soar_module::disconnected )
2571  {
2572  return;
2573  }
2574 
2576  my_agent->smem_timers->init->start();
2578 
2579  const char *db_path;
2581  {
2582  db_path = ":memory:";
2583  }
2584  else
2585  {
2586  db_path = my_agent->smem_params->path->get_value();
2587  }
2588 
2589  // attempt connection
2590  my_agent->smem_db->connect( db_path );
2591 
2592  if ( my_agent->smem_db->get_status() == soar_module::problem )
2593  {
2594  char buf[256];
2595  SNPRINTF( buf, 254, "DB ERROR: %s", my_agent->smem_db->get_errmsg() );
2596 
2597  print( my_agent, buf );
2598  xml_generate_warning( my_agent, buf );
2599  }
2600  else
2601  {
2602  // temporary queries for one-time init actions
2603  soar_module::sqlite_statement *temp_q = NULL;
2604 
2605  // apply performance options
2606  {
2607  // page_size
2608  {
2609  switch ( my_agent->smem_params->page_size->get_value() )
2610  {
2612  temp_q = new soar_module::sqlite_statement( my_agent->smem_db, "PRAGMA page_size = 1024" );
2613  break;
2614 
2616  temp_q = new soar_module::sqlite_statement( my_agent->smem_db, "PRAGMA page_size = 2048" );
2617  break;
2618 
2620  temp_q = new soar_module::sqlite_statement( my_agent->smem_db, "PRAGMA page_size = 4096" );
2621  break;
2622 
2624  temp_q = new soar_module::sqlite_statement( my_agent->smem_db, "PRAGMA page_size = 8192" );
2625  break;
2626 
2628  temp_q = new soar_module::sqlite_statement( my_agent->smem_db, "PRAGMA page_size = 16384" );
2629  break;
2630 
2632  temp_q = new soar_module::sqlite_statement( my_agent->smem_db, "PRAGMA page_size = 32768" );
2633  break;
2634 
2636  temp_q = new soar_module::sqlite_statement( my_agent->smem_db, "PRAGMA page_size = 65536" );
2637  break;
2638  }
2639 
2640  temp_q->prepare();
2641  temp_q->execute();
2642  delete temp_q;
2643  temp_q = NULL;
2644  }
2645 
2646  // cache_size
2647  {
2648  std::string cache_sql( "PRAGMA cache_size = " );
2649  char* str = my_agent->smem_params->cache_size->get_string();
2650  cache_sql.append( str );
2651  free(str);
2652  str = NULL;
2653 
2654  temp_q = new soar_module::sqlite_statement( my_agent->smem_db, cache_sql.c_str() );
2655 
2656  temp_q->prepare();
2657  temp_q->execute();
2658  delete temp_q;
2659  temp_q = NULL;
2660  }
2661 
2662  // optimization
2664  {
2665  // synchronous - don't wait for writes to complete (can corrupt the db in case unexpected crash during transaction)
2666  temp_q = new soar_module::sqlite_statement( my_agent->smem_db, "PRAGMA synchronous = OFF" );
2667  temp_q->prepare();
2668  temp_q->execute();
2669  delete temp_q;
2670  temp_q = NULL;
2671 
2672  // journal_mode - no atomic transactions (can result in database corruption if crash during transaction)
2673  temp_q = new soar_module::sqlite_statement( my_agent->smem_db, "PRAGMA journal_mode = OFF" );
2674  temp_q->prepare();
2675  temp_q->execute();
2676  delete temp_q;
2677  temp_q = NULL;
2678 
2679  // locking_mode - no one else can view the database after our first write
2680  temp_q = new soar_module::sqlite_statement( my_agent->smem_db, "PRAGMA locking_mode = EXCLUSIVE" );
2681  temp_q->prepare();
2682  temp_q->execute();
2683  delete temp_q;
2684  temp_q = NULL;
2685  }
2686  }
2687 
2688  // update validation count
2689  my_agent->smem_validation++;
2690 
2691  // setup common structures/queries
2692  my_agent->smem_stmts = new smem_statement_container( my_agent );
2693 
2694  // setup initial structures (if necessary)
2695  bool tabula_rasa;
2696  {
2697  // create structures if database does not contain signature table
2698  // which we can detect by trying to create it
2699  // note: this only could have been done with an open database (hence in initialization)
2700 
2701  temp_q = new soar_module::sqlite_statement( my_agent->smem_db, "CREATE TABLE " SMEM_SIGNATURE " (uid INTEGER)" );
2702 
2703  temp_q->prepare();
2704  tabula_rasa = ( temp_q->get_status() == soar_module::ready );
2705 
2706  if ( tabula_rasa )
2707  {
2708  // if was possible to prepare, the table doesn't exist so we create it
2709  temp_q->execute();
2710 
2711  // and all other structures
2712  my_agent->smem_stmts->structure();
2713  }
2714 
2715  delete temp_q;
2716  temp_q = NULL;
2717  }
2718 
2719  // initialize queries given database structure
2720  my_agent->smem_stmts->prepare();
2721 
2722  // initialize persistent variables
2723  if ( tabula_rasa )
2724  {
2726  {
2727  // max cycle
2728  my_agent->smem_max_cycle = static_cast<int64_t>( 1 );
2729  smem_variable_create( my_agent, var_max_cycle, 1 );
2730 
2731  // number of nodes
2732  my_agent->smem_stats->chunks->set_value( 0 );
2733  smem_variable_create( my_agent, var_num_nodes, 0 );
2734 
2735  // number of edges
2736  my_agent->smem_stats->slots->set_value( 0 );
2737  smem_variable_create( my_agent, var_num_edges, 0 );
2738 
2739  // threshold (from user parameter value)
2740  smem_variable_create( my_agent, var_act_thresh, static_cast<int64_t>( my_agent->smem_params->thresh->get_value() ) );
2741 
2742  // activation mode (from user parameter value)
2743  smem_variable_create( my_agent, var_act_mode, static_cast<int64_t>( my_agent->smem_params->activation_mode->get_value() ) );
2744  }
2746  }
2747  else
2748  {
2749  int64_t temp;
2750 
2751  // max cycle
2752  smem_variable_get( my_agent, var_max_cycle, &( my_agent->smem_max_cycle ) );
2753 
2754  // number of nodes
2755  smem_variable_get( my_agent, var_num_nodes, &( temp ) );
2756  my_agent->smem_stats->chunks->set_value( temp );
2757 
2758  // number of edges
2759  smem_variable_get( my_agent, var_num_edges, &( temp ) );
2760  my_agent->smem_stats->slots->set_value( temp );
2761 
2762  // threshold
2763  smem_variable_get( my_agent, var_act_thresh, &( temp ) );
2764  my_agent->smem_params->thresh->set_value( temp );
2765 
2766  // activation mode
2767  smem_variable_get( my_agent, var_act_mode, &( temp ) );
2768  my_agent->smem_params->activation_mode->set_value( static_cast< smem_param_container::act_choices >( temp ) );
2769  }
2770 
2771  // reset identifier counters
2772  smem_reset_id_counters( my_agent );
2773 
2774  // if lazy commit, then we encapsulate the entire lifetime of the agent in a single transaction
2775  if ( my_agent->smem_params->lazy_commit->get_value() == soar_module::on )
2776  {
2778  }
2779  }
2780 
2782  my_agent->smem_timers->init->stop();
2784 }
2785 
2786 void smem_attach( agent *my_agent )
2787 {
2788  if ( my_agent->smem_db->get_status() == soar_module::disconnected )
2789  {
2790  smem_init_db( my_agent );
2791  }
2792 }
2793 
2794 inline void _smem_close_vars( agent* my_agent )
2795 {
2796  // store max cycle for future use of the smem database
2797  smem_variable_set( my_agent, var_max_cycle, my_agent->smem_max_cycle );
2798 
2799  // store num nodes/edges for future use of the smem database
2800  smem_variable_set( my_agent, var_num_nodes, my_agent->smem_stats->chunks->get_value() );
2801  smem_variable_set( my_agent, var_num_edges, my_agent->smem_stats->slots->get_value() );
2802 }
2803 
2804 // performs cleanup operations when the database needs to be closed (end soar, manual close, etc)
2805 void smem_close( agent *my_agent )
2806 {
2807  if ( my_agent->smem_db->get_status() == soar_module::connected )
2808  {
2809  _smem_close_vars( my_agent );
2810 
2811  // if lazy, commit
2812  if ( my_agent->smem_params->lazy_commit->get_value() == soar_module::on )
2813  {
2815  }
2816 
2817  // de-allocate common statements
2818  delete my_agent->smem_stmts;
2819 
2820  // close the database
2821  my_agent->smem_db->disconnect();
2822  }
2823 }
2824 
2825 
2828 // Parsing (smem::parse)
2831 
2832 void smem_deallocate_chunk( agent *my_agent, smem_chunk *chunk, bool free_chunk = true )
2833 {
2834  if ( chunk )
2835  {
2836  // proceed to slots
2837  if ( chunk->slots )
2838  {
2839  smem_slot_map::iterator s;
2840  smem_slot::iterator v;
2841 
2842  // iterate over slots
2843  while ( !chunk->slots->empty() )
2844  {
2845  s = chunk->slots->begin();
2846 
2847  // proceed to slot contents
2848  if ( s->second )
2849  {
2850  // iterate over each value
2851  for ( v=s->second->begin(); v!=s->second->end(); v=s->second->erase(v) )
2852  {
2853  // de-allocation of value is dependent upon type
2854  if ( (*v)->val_const.val_type == value_const_t )
2855  {
2856  symbol_remove_ref( my_agent, (*v)->val_const.val_value );
2857  }
2858  else
2859  {
2860  // we never deallocate the lti chunk, as we assume
2861  // it will exist elsewhere for deallocation
2862  // delete (*s)->val_lti.val_value;
2863  }
2864 
2865  delete (*v);
2866  }
2867 
2868  delete s->second;
2869  }
2870 
2871  // deallocate attribute for each corresponding value
2872  symbol_remove_ref( my_agent, s->first );
2873 
2874  chunk->slots->erase( s );
2875  }
2876 
2877  // remove slots
2878  delete chunk->slots;
2879  chunk->slots = NULL;
2880  }
2881 
2882  // remove chunk itself
2883  if ( free_chunk )
2884  {
2885  delete chunk;
2886  chunk = NULL;
2887  }
2888  }
2889 }
2890 
2891 inline std::string *smem_parse_lti_name( struct lexeme_info *lexeme, char *id_letter, uint64_t *id_number )
2892 {
2893  std::string *return_val = new std::string;
2894 
2895  if ( (*lexeme).type == IDENTIFIER_LEXEME )
2896  {
2897  std::string num;
2898  to_string( (*lexeme).id_number, num );
2899 
2900  return_val->append( 1, (*lexeme).id_letter );
2901  return_val->append( num );
2902 
2903  (*id_letter) = (*lexeme).id_letter;
2904  (*id_number) = (*lexeme).id_number;
2905  }
2906  else
2907  {
2908  return_val->assign( (*lexeme).string );
2909 
2910  (*id_letter) = static_cast<char>( toupper( (*lexeme).string[1] ) );
2911  (*id_number) = 0;
2912  }
2913 
2914  return return_val;
2915 }
2916 
2918 {
2919  Symbol *return_val = NIL;
2920 
2921  if ( (*lexeme).type == SYM_CONSTANT_LEXEME )
2922  {
2923  return_val = make_sym_constant( my_agent, static_cast<const char *>( (*lexeme).string ) );
2924  }
2925  else if ( (*lexeme).type == INT_CONSTANT_LEXEME )
2926  {
2927  return_val = make_int_constant( my_agent, (*lexeme).int_val );
2928  }
2929  else if ( (*lexeme).type == FLOAT_CONSTANT_LEXEME )
2930  {
2931  return_val = make_float_constant( my_agent, (*lexeme).float_val );
2932  }
2933 
2934  return return_val;
2935 }
2936 
2937 bool smem_parse_chunk( agent *my_agent, smem_str_to_chunk_map *chunks, smem_chunk_set *newbies )
2938 {
2939  bool return_val = false;
2940 
2941  smem_chunk *new_chunk = new smem_chunk;
2942  new_chunk->slots = NULL;
2943 
2944  std::string *chunk_name = NULL;
2945 
2946  char temp_letter;
2947  uint64_t temp_number;
2948 
2949  bool good_at;
2950 
2951  //
2952 
2953  // consume left paren
2954  get_lexeme( my_agent );
2955 
2956  if ( ( my_agent->lexeme.type == AT_LEXEME ) || ( my_agent->lexeme.type == IDENTIFIER_LEXEME ) || ( my_agent->lexeme.type == VARIABLE_LEXEME ) )
2957  {
2958  good_at = true;
2959 
2960  if ( my_agent->lexeme.type == AT_LEXEME )
2961  {
2962  get_lexeme( my_agent );
2963 
2964  good_at = ( my_agent->lexeme.type == IDENTIFIER_LEXEME );
2965  }
2966 
2967  if ( good_at )
2968  {
2969  // save identifier
2970  chunk_name = smem_parse_lti_name( &( my_agent->lexeme ), &( temp_letter ), &( temp_number ) );
2971  new_chunk->lti_letter = temp_letter;
2972  new_chunk->lti_number = temp_number;
2973  new_chunk->lti_id = NIL;
2974  new_chunk->soar_id = NIL;
2975  new_chunk->slots = new smem_slot_map;
2976 
2977  // consume id
2978  get_lexeme( my_agent );
2979 
2980  //
2981 
2982  uint64_t intermediate_counter = 1;
2983  smem_chunk *intermediate_parent;
2984  smem_chunk *temp_chunk;
2985  std::string temp_key;
2986  std::string *temp_key2;
2987  Symbol *chunk_attr;
2988  smem_chunk_value *chunk_value;
2989  smem_slot *s;
2990 
2991  // populate slots
2992  while ( my_agent->lexeme.type == UP_ARROW_LEXEME )
2993  {
2994  intermediate_parent = new_chunk;
2995 
2996  // go on to attribute
2997  get_lexeme( my_agent );
2998 
2999  // get the appropriate constant type
3000  chunk_attr = smem_parse_constant_attr( my_agent, &( my_agent->lexeme ) );
3001 
3002  // if constant attribute, proceed to value
3003  if ( chunk_attr != NIL )
3004  {
3005  // consume attribute
3006  get_lexeme( my_agent );
3007 
3008  // support for dot notation:
3009  // when we encounter a dot, instantiate
3010  // the previous attribute as a temporary
3011  // identifier and use that as the parent
3012  while ( my_agent->lexeme.type == PERIOD_LEXEME )
3013  {
3014  // create a new chunk
3015  temp_chunk = new smem_chunk;
3016  temp_chunk->lti_letter = ( ( chunk_attr->common.symbol_type == SYM_CONSTANT_SYMBOL_TYPE )?( static_cast<char>( static_cast<int>( chunk_attr->sc.name[0] ) ) ):( 'X' ) );
3017  temp_chunk->lti_number = ( intermediate_counter++ );
3018  temp_chunk->lti_id = NIL;
3019  temp_chunk->slots = new smem_slot_map;
3020  temp_chunk->soar_id = NIL;
3021 
3022  // add it as a child to the current parent
3023  chunk_value = new smem_chunk_value;
3024  chunk_value->val_lti.val_type = value_lti_t;
3025  chunk_value->val_lti.val_value = temp_chunk;
3026  s = smem_make_slot( intermediate_parent->slots, chunk_attr );
3027  s->push_back( chunk_value );
3028 
3029  // create a key guaranteed to be unique
3030  std::string temp_key3;
3031  to_string( temp_chunk->lti_number, temp_key3 );
3032  temp_key.assign( "<" );
3033  temp_key.append( 1, temp_chunk->lti_letter );
3034  temp_key.append( "#" );
3035  temp_key.append( temp_key3 );
3036  temp_key.append( ">" );
3037 
3038  // insert the new chunk
3039  (*chunks)[ temp_key ] = temp_chunk;
3040 
3041  // definitely a new chunk
3042  newbies->insert( temp_chunk );
3043 
3044  // the new chunk is our parent for this set of values (or further dots)
3045  intermediate_parent = temp_chunk;
3046  temp_chunk = NULL;
3047 
3048  // get the next attribute
3049  get_lexeme( my_agent );
3050  chunk_attr = smem_parse_constant_attr( my_agent, &( my_agent->lexeme ) );
3051 
3052  // consume attribute
3053  get_lexeme( my_agent );
3054  }
3055 
3056  if ( chunk_attr != NIL )
3057  {
3058  bool first_value = true;
3059 
3060  do
3061  {
3062  // value by type
3063  chunk_value = NIL;
3064  if ( my_agent->lexeme.type == SYM_CONSTANT_LEXEME )
3065  {
3066  chunk_value = new smem_chunk_value;
3067  chunk_value->val_const.val_type = value_const_t;
3068  chunk_value->val_const.val_value = make_sym_constant( my_agent, static_cast<const char *>( my_agent->lexeme.string ) );
3069  }
3070  else if ( my_agent->lexeme.type == INT_CONSTANT_LEXEME )
3071  {
3072  chunk_value = new smem_chunk_value;
3073  chunk_value->val_const.val_type = value_const_t;
3074  chunk_value->val_const.val_value = make_int_constant( my_agent, my_agent->lexeme.int_val );
3075  }
3076  else if ( my_agent->lexeme.type == FLOAT_CONSTANT_LEXEME )
3077  {
3078  chunk_value = new smem_chunk_value;
3079  chunk_value->val_const.val_type = value_const_t;
3080  chunk_value->val_const.val_value = make_float_constant( my_agent, my_agent->lexeme.float_val );
3081  }
3082  else if ( ( my_agent->lexeme.type == AT_LEXEME ) || ( my_agent->lexeme.type == IDENTIFIER_LEXEME ) || ( my_agent->lexeme.type == VARIABLE_LEXEME ) )
3083  {
3084  good_at = true;
3085 
3086  if ( my_agent->lexeme.type == AT_LEXEME )
3087  {
3088  get_lexeme( my_agent );
3089 
3090  good_at = ( my_agent->lexeme.type == IDENTIFIER_LEXEME );
3091  }
3092 
3093  if ( good_at )
3094  {
3095  // create new value
3096  chunk_value = new smem_chunk_value;
3097  chunk_value->val_lti.val_type = value_lti_t;
3098 
3099  // get key
3100  temp_key2 = smem_parse_lti_name( &( my_agent->lexeme ), &( temp_letter ), &( temp_number ) );
3101 
3102  // search for an existing chunk
3103  smem_str_to_chunk_map::iterator p = chunks->find( (*temp_key2) );
3104 
3105  // if exists, point; else create new
3106  if ( p != chunks->end() )
3107  {
3108  chunk_value->val_lti.val_value = p->second;
3109  }
3110  else
3111  {
3112  // create new chunk
3113  temp_chunk = new smem_chunk;
3114  temp_chunk->lti_id = NIL;
3115  temp_chunk->lti_letter = temp_letter;
3116  temp_chunk->lti_number = temp_number;
3117  temp_chunk->lti_id = NIL;
3118  temp_chunk->slots = NIL;
3119  temp_chunk->soar_id = NIL;
3120 
3121  // associate with value
3122  chunk_value->val_lti.val_value = temp_chunk;
3123 
3124  // add to chunks
3125  (*chunks)[ (*temp_key2) ] = temp_chunk;
3126 
3127  // possibly a newbie (could be a self-loop)
3128  newbies->insert( temp_chunk );
3129  }
3130 
3131  delete temp_key2;
3132  }
3133  }
3134 
3135  if ( chunk_value != NIL )
3136  {
3137  // consume
3138  get_lexeme( my_agent );
3139 
3140  // add to appropriate slot
3141  s = smem_make_slot( intermediate_parent->slots, chunk_attr );
3142  if ( first_value && !s->empty() )
3143  {
3144  // in the case of a repeated attribute, remove ref here to avoid leak
3145  symbol_remove_ref( my_agent, chunk_attr );
3146  }
3147  s->push_back( chunk_value );
3148 
3149  // if this was the last attribute
3150  if ( my_agent->lexeme.type == R_PAREN_LEXEME )
3151  {
3152  return_val = true;
3153  get_lexeme( my_agent );
3154  chunk_value = NIL;
3155  }
3156 
3157  first_value = false;
3158  }
3159  } while ( chunk_value != NIL );
3160  }
3161  }
3162  }
3163  }
3164  else
3165  {
3166  delete new_chunk;
3167  }
3168  }
3169  else
3170  {
3171  delete new_chunk;
3172  }
3173 
3174  if ( return_val )
3175  {
3176  // search for an existing chunk (occurs if value comes before id)
3177  smem_chunk **p =& (*chunks)[ (*chunk_name ) ];
3178 
3179  if ( !(*p) )
3180  {
3181  (*p) = new_chunk;
3182 
3183  // a newbie!
3184  newbies->insert( new_chunk );
3185  }
3186  else
3187  {
3188  // transfer slots
3189  if ( !(*p)->slots )
3190  {
3191  // if none previously, can just use
3192  (*p)->slots = new_chunk->slots;
3193  new_chunk->slots = NULL;
3194  }
3195  else
3196  {
3197  // otherwise, copy
3198 
3199  smem_slot_map::iterator ss_p;
3200  smem_slot::iterator s_p;
3201 
3202  smem_slot *source_slot;
3203  smem_slot *target_slot;
3204 
3205  // for all slots
3206  for ( ss_p=new_chunk->slots->begin(); ss_p!=new_chunk->slots->end(); ss_p++ )
3207  {
3208  target_slot = smem_make_slot( (*p)->slots, ss_p->first );
3209  source_slot = ss_p->second;
3210 
3211  // for all values in the slot
3212  for ( s_p=source_slot->begin(); s_p!=source_slot->end(); s_p++ )
3213  {
3214  // copy each value
3215  target_slot->push_back( (*s_p) );
3216  }
3217 
3218  // once copied, we no longer need the slot
3219  delete source_slot;
3220  }
3221 
3222  // we no longer need the slots
3223  delete new_chunk->slots;
3224  new_chunk->slots = NULL;
3225  }
3226 
3227  // contents are new
3228  newbies->insert( (*p) );
3229 
3230  // deallocate
3231  smem_deallocate_chunk( my_agent, new_chunk );
3232  }
3233  }
3234  else
3235  {
3236  newbies->clear();
3237  }
3238 
3239  // de-allocate id name
3240  if ( chunk_name )
3241  {
3242  delete chunk_name;
3243  }
3244 
3245  return return_val;
3246 }
3247 
3248 bool smem_parse_chunks( agent *my_agent, const char *chunks_str, std::string **err_msg )
3249 {
3250  bool return_val = false;
3251  uint64_t clause_count = 0;
3252 
3253  // parsing chunks requires an open semantic database
3254  smem_attach( my_agent );
3255 
3256  // copied primarily from cli_sp
3257  my_agent->alternate_input_string = chunks_str;
3258  my_agent->alternate_input_suffix = const_cast<char *>( ") " );
3259  my_agent->current_char = ' ';
3260  my_agent->alternate_input_exit = true;
3261  set_lexer_allow_ids( my_agent, true );
3262 
3263  bool good_chunk = true;
3264 
3265  smem_str_to_chunk_map chunks;
3266  smem_str_to_chunk_map::iterator c_old;
3267 
3268  smem_chunk_set newbies;
3269  smem_chunk_set::iterator c_new;
3270 
3271  // consume next token
3272  get_lexeme( my_agent );
3273 
3274  // while there are chunks to consume
3275  while ( ( my_agent->lexeme.type == L_PAREN_LEXEME ) && ( good_chunk ) )
3276  {
3277  good_chunk = smem_parse_chunk( my_agent, &( chunks ), &( newbies ) );
3278 
3279  if ( good_chunk )
3280  {
3281  // add all newbie lti's as appropriate
3282  for ( c_new=newbies.begin(); c_new!=newbies.end(); c_new++ )
3283  {
3284  if ( (*c_new)->lti_id == NIL )
3285  {
3286  // deal differently with variable vs. lti
3287  if ( (*c_new)->lti_number == NIL )
3288  {
3289  // add a new lti id (we have a guarantee this won't be in Soar's WM)
3290  (*c_new)->lti_number = ( my_agent->id_counter[ (*c_new)->lti_letter - static_cast<char>('A') ]++ );
3291  (*c_new)->lti_id = smem_lti_add_id( my_agent, (*c_new)->lti_letter, (*c_new)->lti_number );
3292  }
3293  else
3294  {
3295  // should ALWAYS be the case (it's a newbie and we've initialized lti_id to NIL)
3296  if ( (*c_new)->lti_id == NIL )
3297  {
3298  // get existing
3299  (*c_new)->lti_id = smem_lti_get_id( my_agent, (*c_new)->lti_letter, (*c_new)->lti_number );
3300 
3301  // if doesn't exist, add it
3302  if ( (*c_new)->lti_id == NIL )
3303  {
3304  (*c_new)->lti_id = smem_lti_add_id( my_agent, (*c_new)->lti_letter, (*c_new)->lti_number );
3305 
3306  // this could affect an existing identifier in Soar's WM
3307  Symbol *id_parent = find_identifier( my_agent, (*c_new)->lti_letter, (*c_new)->lti_number );
3308  if ( id_parent != NIL )
3309  {
3310  // if so we make it an lti manually
3311  id_parent->id.smem_lti = (*c_new)->lti_id;
3312 
3313  id_parent->id.smem_time_id = my_agent->epmem_stats->time->get_value();
3314  id_parent->id.smem_valid = my_agent->epmem_validation;
3315  epmem_schedule_promotion( my_agent, id_parent );
3316  }
3317  }
3318  }
3319  }
3320  }
3321  }
3322 
3323  // add all newbie contents (append, as opposed to replace, children)
3324  for ( c_new=newbies.begin(); c_new!=newbies.end(); c_new++ )
3325  {
3326  if ( (*c_new)->slots != NIL )
3327  {
3328  smem_store_chunk( my_agent, (*c_new)->lti_id, (*c_new)->slots, false );
3329  }
3330  }
3331 
3332  // deallocate *contents* of all newbies (need to keep around name->id association for future chunks)
3333  for ( c_new=newbies.begin(); c_new!=newbies.end(); c_new++ )
3334  {
3335  smem_deallocate_chunk( my_agent, (*c_new), false );
3336  }
3337 
3338  // increment clause counter
3339  clause_count++;
3340 
3341  // clear newbie list
3342  newbies.clear();
3343  }
3344  };
3345 
3346  return_val = good_chunk;
3347 
3348  // deallocate all chunks
3349  {
3350  for ( c_old=chunks.begin(); c_old!=chunks.end(); c_old++ )
3351  {
3352  smem_deallocate_chunk( my_agent, c_old->second, true );
3353  }
3354  }
3355 
3356  // produce error message on failure
3357  if ( !return_val )
3358  {
3359  std::string num;
3360  to_string( clause_count, num );
3361 
3362  (*err_msg) = new std::string( "Error parsing clause #" );
3363  (*err_msg)->append( num );
3364  }
3365 
3366  return return_val;
3367 }
3368 
3369 
3372 // API Implementation (smem::api)
3375 
3376 void smem_respond_to_cmd( agent *my_agent, bool store_only )
3377 {
3378  // start at the bottom and work our way up
3379  // (could go in the opposite direction as well)
3380  Symbol *state = my_agent->bottom_goal;
3381 
3382  smem_wme_list *wmes;
3383  smem_wme_list *cmds;
3384  smem_wme_list::iterator w_p;
3385 
3387  soar_module::symbol_triple_list retrieval_wmes;
3388  soar_module::wme_set cue_wmes;
3389 
3390  Symbol *query;
3391  Symbol *negquery;
3392  Symbol *retrieve;
3393  smem_sym_list prohibit;
3394  smem_sym_list store;
3395 
3396  enum path_type { blank_slate, cmd_bad, cmd_retrieve, cmd_query, cmd_store } path;
3397 
3398  unsigned int time_slot = ( ( store_only )?(1):(0) );
3399  uint64_t wme_count;
3400  bool new_cue;
3401 
3402  tc_number tc;
3403 
3404  Symbol *parent_sym;
3405  std::queue<Symbol *> syms;
3406 
3407  int parent_level;
3408  std::queue<int> levels;
3409 
3410  bool do_wm_phase = false;
3411  bool mirroring_on = ( my_agent->smem_params->mirroring->get_value() == soar_module::on );
3412 
3413  //
3414 
3415  while ( state != NULL )
3416  {
3418  my_agent->smem_timers->api->start();
3420 
3421  // make sure this state has had some sort of change to the cmd
3422  // NOTE: we only care one-level deep!
3423  new_cue = false;
3424  wme_count = 0;
3425  cmds = NIL;
3426  {
3427  tc = get_new_tc_number( my_agent );
3428 
3429  // initialize BFS at command
3430  syms.push( state->id.smem_cmd_header );
3431  levels.push( 0 );
3432 
3433  while ( !syms.empty() )
3434  {
3435  // get state
3436  parent_sym = syms.front();
3437  syms.pop();
3438 
3439  parent_level = levels.front();
3440  levels.pop();
3441 
3442  // get children of the current identifier
3443  wmes = smem_get_direct_augs_of_id( parent_sym, tc );
3444  {
3445  for ( w_p=wmes->begin(); w_p!=wmes->end(); w_p++ )
3446  {
3447  if ( ( ( store_only ) && ( ( parent_level != 0 ) || ( (*w_p)->attr == my_agent->smem_sym_store ) ) ) ||
3448  ( ( !store_only ) && ( ( parent_level != 0 ) || ( (*w_p)->attr != my_agent->smem_sym_store ) ) ) )
3449  {
3450  wme_count++;
3451 
3452  if ( (*w_p)->timetag > state->id.smem_info->last_cmd_time[ time_slot ] )
3453  {
3454  new_cue = true;
3455  state->id.smem_info->last_cmd_time[ time_slot ] = (*w_p)->timetag;
3456  }
3457 
3458  if ( ( (*w_p)->value->common.symbol_type == IDENTIFIER_SYMBOL_TYPE ) &&
3459  ( parent_level == 0 ) &&
3460  ( ( (*w_p)->attr == my_agent->smem_sym_query ) || ( (*w_p)->attr == my_agent->smem_sym_store ) ) )
3461  {
3462  syms.push( (*w_p)->value );
3463  levels.push( parent_level + 1 );
3464  }
3465  }
3466  }
3467 
3468  // free space from aug list
3469  if ( cmds == NIL )
3470  {
3471  cmds = wmes;
3472  }
3473  else
3474  {
3475  delete wmes;
3476  }
3477  }
3478  }
3479 
3480  // see if any WMEs were removed
3481  if ( state->id.smem_info->last_cmd_count[ time_slot ] != wme_count )
3482  {
3483  new_cue = true;
3484  state->id.smem_info->last_cmd_count[ time_slot ] = wme_count;
3485  }
3486 
3487 
3488  if ( new_cue )
3489  {
3490  // clear old results
3491  smem_clear_result( my_agent, state );
3492 
3493  do_wm_phase = true;
3494  }
3495  }
3496 
3497  // a command is issued if the cue is new
3498  // and there is something on the cue
3499  if ( new_cue && wme_count )
3500  {
3501  cue_wmes.clear();
3502  meta_wmes.clear();
3503  retrieval_wmes.clear();
3504 
3505  // initialize command vars
3506  retrieve = NIL;
3507  query = NIL;
3508  negquery = NIL;
3509  store.clear();
3510  prohibit.clear();
3511  path = blank_slate;
3512 
3513  // process top-level symbols
3514  for ( w_p=cmds->begin(); w_p!=cmds->end(); w_p++ )
3515  {
3516  cue_wmes.insert( (*w_p) );
3517 
3518  if ( path != cmd_bad )
3519  {
3520  // collect information about known commands
3521  if ( (*w_p)->attr == my_agent->smem_sym_retrieve )
3522  {
3523  if ( ( (*w_p)->value->common.symbol_type == IDENTIFIER_SYMBOL_TYPE ) &&
3524  ( path == blank_slate ) )
3525  {
3526  retrieve = (*w_p)->value;
3527  path = cmd_retrieve;
3528  }
3529  else
3530  {
3531  path = cmd_bad;
3532  }
3533  }
3534  else if ( (*w_p)->attr == my_agent->smem_sym_query )
3535  {
3536  if ( ( (*w_p)->value->common.symbol_type == IDENTIFIER_SYMBOL_TYPE ) &&
3537  ( ( path == blank_slate ) || ( path == cmd_query ) ) &&
3538  ( query == NIL ) )
3539 
3540  {
3541  query = (*w_p)->value;
3542  path = cmd_query;
3543  }
3544  else
3545  {
3546  path = cmd_bad;
3547  }
3548  }
3549  else if ( (*w_p)->attr == my_agent->smem_sym_negquery )
3550  {
3551  if ( ( (*w_p)->value->common.symbol_type == IDENTIFIER_SYMBOL_TYPE ) &&
3552  ( ( path == blank_slate ) || ( path == cmd_query ) ) &&
3553  ( negquery == NIL ) )
3554 
3555  {
3556  negquery = (*w_p)->value;
3557  path = cmd_query;
3558  }
3559  else
3560  {
3561  path = cmd_bad;
3562  }
3563  }
3564  else if ( (*w_p)->attr == my_agent->smem_sym_prohibit )
3565  {
3566  if ( ( (*w_p)->value->common.symbol_type == IDENTIFIER_SYMBOL_TYPE ) &&
3567  ( ( path == blank_slate ) || ( path == cmd_query ) ) &&
3568  ( (*w_p)->value->id.smem_lti != NIL ) )
3569  {
3570  prohibit.push_back( (*w_p)->value );
3571  path = cmd_query;
3572  }
3573  else
3574  {
3575  path = cmd_bad;
3576  }
3577  }
3578  else if ( (*w_p)->attr == my_agent->smem_sym_store )
3579  {
3580  if ( ( (*w_p)->value->common.symbol_type == IDENTIFIER_SYMBOL_TYPE ) &&
3581  ( ( path == blank_slate ) || ( path == cmd_store ) ) )
3582  {
3583  store.push_back( (*w_p)->value );
3584  path = cmd_store;
3585  }
3586  else
3587  {
3588  path = cmd_bad;
3589  }
3590  }
3591  else
3592  {
3593  path = cmd_bad;
3594  }
3595  }
3596  }
3597 
3598  // if on path 3 must have query/neg-query
3599  if ( ( path == cmd_query ) && ( query == NULL ) )
3600  {
3601  path = cmd_bad;
3602  }
3603 
3604  // must be on a path
3605  if ( path == blank_slate )
3606  {
3607  path = cmd_bad;
3608  }
3609 
3611  my_agent->smem_timers->api->stop();
3613 
3614  // process command
3615  if ( path != cmd_bad )
3616  {
3617  // performing any command requires an initialized database
3618  smem_attach( my_agent );
3619 
3620  // retrieve
3621  if ( path == cmd_retrieve )
3622  {
3623  if ( retrieve->id.smem_lti == NIL )
3624  {
3625  // retrieve is not pointing to an lti!
3626  smem_buffer_add_wme( meta_wmes, state->id.smem_result_header, my_agent->smem_sym_failure, retrieve );
3627  }
3628  else
3629  {
3630  // status: success
3631  smem_buffer_add_wme( meta_wmes, state->id.smem_result_header, my_agent->smem_sym_success, retrieve );
3632 
3633  // install memory directly onto the retrieve identifier
3634  smem_install_memory( my_agent, state, retrieve->id.smem_lti, retrieve, true, meta_wmes, retrieval_wmes );
3635 
3636  // add one to the expansions stat
3637  my_agent->smem_stats->expansions->set_value( my_agent->smem_stats->expansions->get_value() + 1 );
3638  }
3639  }
3640  // query
3641  else if ( path == cmd_query )
3642  {
3643  smem_lti_set prohibit_lti;
3644  smem_sym_list::iterator sym_p;
3645 
3646  for ( sym_p=prohibit.begin(); sym_p!=prohibit.end(); sym_p++ )
3647  {
3648  prohibit_lti.insert( (*sym_p)->id.smem_lti );
3649  }
3650 
3651  smem_process_query( my_agent, state, query, negquery, &( prohibit_lti ), cue_wmes, meta_wmes, retrieval_wmes );
3652 
3653  // add one to the cbr stat
3654  my_agent->smem_stats->cbr->set_value( my_agent->smem_stats->cbr->get_value() + 1 );
3655  }
3656  else if ( path == cmd_store )
3657  {
3658  smem_sym_list::iterator sym_p;
3659 
3661  my_agent->smem_timers->storage->start();
3663 
3664  // start transaction (if not lazy)
3665  if ( my_agent->smem_params->lazy_commit->get_value() == soar_module::off )
3666  {
3668  }
3669 
3670  for ( sym_p=store.begin(); sym_p!=store.end(); sym_p++ )
3671  {
3672  smem_soar_store( my_agent, (*sym_p), ( ( mirroring_on )?( store_recursive ):( store_level ) ) );
3673 
3674  // status: success
3675  smem_buffer_add_wme( meta_wmes, state->id.smem_result_header, my_agent->smem_sym_success, (*sym_p) );
3676 
3677  // add one to the store stat
3678  my_agent->smem_stats->stores->set_value( my_agent->smem_stats->stores->get_value() + 1 );
3679  }
3680 
3681  // commit transaction (if not lazy)
3682  if ( my_agent->smem_params->lazy_commit->get_value() == soar_module::off )
3683  {
3685  }
3686 
3688  my_agent->smem_timers->storage->stop();
3690  }
3691  }
3692  else
3693  {
3694  smem_buffer_add_wme( meta_wmes, state->id.smem_result_header, my_agent->smem_sym_bad_cmd, state->id.smem_cmd_header );
3695  }
3696 
3697  if ( !meta_wmes.empty() || !retrieval_wmes.empty() )
3698  {
3699  // process preference assertion en masse
3700  smem_process_buffered_wmes( my_agent, state, cue_wmes, meta_wmes, retrieval_wmes );
3701 
3702  // clear cache
3703  {
3704  soar_module::symbol_triple_list::iterator mw_it;
3705 
3706  for ( mw_it=retrieval_wmes.begin(); mw_it!=retrieval_wmes.end(); mw_it++ )
3707  {
3708  symbol_remove_ref( my_agent, (*mw_it)->id );
3709  symbol_remove_ref( my_agent, (*mw_it)->attr );
3710  symbol_remove_ref( my_agent, (*mw_it)->value );
3711 
3712  delete (*mw_it);
3713  }
3714  retrieval_wmes.clear();
3715 
3716  for ( mw_it=meta_wmes.begin(); mw_it!=meta_wmes.end(); mw_it++ )
3717  {
3718  symbol_remove_ref( my_agent, (*mw_it)->id );
3719  symbol_remove_ref( my_agent, (*mw_it)->attr );
3720  symbol_remove_ref( my_agent, (*mw_it)->value );
3721 
3722  delete (*mw_it);
3723  }
3724  meta_wmes.clear();
3725  }
3726 
3727  // process wm changes on this state
3728  do_wm_phase = true;
3729  }
3730 
3731  // clear cue wmes
3732  cue_wmes.clear();
3733  }
3734  else
3735  {
3737  my_agent->smem_timers->api->stop();
3739  }
3740 
3741  // free space from aug list
3742  delete cmds;
3743 
3744  state = state->id.higher_goal;
3745  }
3746 
3747  if ( store_only && mirroring_on && ( !my_agent->smem_changed_ids->empty() ) )
3748  {
3750  my_agent->smem_timers->storage->start();
3752 
3753  // start transaction (if not lazy)
3754  if ( my_agent->smem_params->lazy_commit->get_value() == soar_module::off )
3755  {
3757  }
3758 
3759  for ( smem_pooled_symbol_set::iterator it=my_agent->smem_changed_ids->begin(); it!=my_agent->smem_changed_ids->end(); it++ )
3760  {
3761  // require that the lti has at least one augmentation
3762  if ( (*it)->id.slots )
3763  {
3764  smem_soar_store( my_agent, (*it), store_recursive );
3765 
3766  // add one to the mirrors stat
3767  my_agent->smem_stats->mirrors->set_value( my_agent->smem_stats->mirrors->get_value() + 1 );
3768  }
3769 
3770  symbol_remove_ref( my_agent, (*it) );
3771  }
3772 
3773  // commit transaction (if not lazy)
3774  if ( my_agent->smem_params->lazy_commit->get_value() == soar_module::off )
3775  {
3777  }
3778 
3779  // clear symbol set
3780  my_agent->smem_changed_ids->clear();
3781 
3783  my_agent->smem_timers->storage->stop();
3785  }
3786 
3787  if ( do_wm_phase )
3788  {
3789  my_agent->smem_ignore_changes = true;
3790 
3791  do_working_memory_phase( my_agent );
3792 
3793  my_agent->smem_ignore_changes = false;
3794  }
3795 }
3796 
3797 void smem_go( agent *my_agent, bool store_only )
3798 {
3799  my_agent->smem_timers->total->start();
3800 
3801 #ifndef SMEM_EXPERIMENT
3802 
3803  smem_respond_to_cmd( my_agent, store_only );
3804 
3805 #else // SMEM_EXPERIMENT
3806 
3807 #endif // SMEM_EXPERIMENT
3808 
3809  my_agent->smem_timers->total->stop();
3810 }
3811 
3812 bool smem_backup_db( agent* my_agent, const char* file_name, std::string *err )
3813 {
3814  bool return_val = false;
3815 
3816  if ( my_agent->smem_db->get_status() == soar_module::connected )
3817  {
3818  _smem_close_vars( my_agent );
3819 
3820  if ( my_agent->smem_params->lazy_commit->get_value() == soar_module::on )
3821  {
3823  }
3824 
3825  return_val = my_agent->smem_db->backup( file_name, err );
3826 
3827  if ( my_agent->smem_params->lazy_commit->get_value() == soar_module::on )
3828  {
3830  }
3831  }
3832  else
3833  {
3834  err->assign( "Semantic database is not currently connected." );
3835  }
3836 
3837  return return_val;
3838 }
3839 
3840 
3843 // Visualization (smem::viz)
3846 
3847 void smem_visualize_store( agent *my_agent, std::string *return_val )
3848 {
3849  // vizualizing the store requires an open semantic database
3850  smem_attach( my_agent );
3851 
3852  // header
3853  return_val->append( "digraph smem {" );
3854  return_val->append( "\n" );
3855 
3856  // LTIs
3857  return_val->append( "node [ shape = doublecircle ];" );
3858  return_val->append( "\n" );
3859 
3860  std::map< smem_lti_id, std::string > lti_names;
3861  std::map< smem_lti_id, std::string >::iterator n_p;
3862  {
3864 
3865  smem_lti_id lti_id;
3866  char lti_letter;
3867  uint64_t lti_number;
3868 
3869  std::string *lti_name;
3870  std::string temp_str;
3871  int64_t temp_int;
3872  double temp_double;
3873 
3874  // id, letter, number
3875  q = my_agent->smem_stmts->vis_lti;
3876  while ( q->execute() == soar_module::row )
3877  {
3878  lti_id = q->column_int( 0 );
3879  lti_letter = static_cast<char>( q->column_int( 1 ) );
3880  lti_number = static_cast<uint64_t>( q->column_int( 2 ) );
3881 
3882  lti_name =& lti_names[ lti_id ];
3883  lti_name->push_back( lti_letter );
3884 
3885  to_string( lti_number, temp_str );
3886  lti_name->append( temp_str );
3887 
3888  return_val->append( (*lti_name) );
3889  return_val->append( " [ label=\"" );
3890  return_val->append( (*lti_name) );
3891  return_val->append( "\\n[" );
3892 
3893  temp_double = q->column_double( 3 );
3894  to_string( temp_double, temp_str, 3, true );
3895  if ( temp_double >= 0 )
3896  {
3897  return_val->append( "+" );
3898  }
3899  return_val->append( temp_str );
3900 
3901  return_val->append( "]\"" );
3902  return_val->append( " ];" );
3903  return_val->append( "\n" );
3904  }
3905  q->reinitialize();
3906 
3907  if ( !lti_names.empty() )
3908  {
3909  // terminal nodes first
3910  {
3911  std::map< smem_lti_id, std::list<std::string> > lti_terminals;
3912  std::map< smem_lti_id, std::list<std::string> >::iterator t_p;
3913  std::list<std::string>::iterator a_p;
3914 
3915  std::list<std::string> *my_terminals;
3916  std::list<std::string>::size_type terminal_num;
3917 
3918  return_val->append( "\n" );
3919 
3920  // proceed to terminal nodes
3921  return_val->append( "node [ shape = plaintext ];" );
3922  return_val->append( "\n" );
3923 
3924  // parent_id, attr_type, attr_hash, val_type, val_hash
3925  q = my_agent->smem_stmts->vis_value_const;
3926  while ( q->execute() == soar_module::row )
3927  {
3928  lti_id = q->column_int( 0 );
3929  my_terminals =& lti_terminals[ lti_id ];
3930  lti_name =& lti_names[ lti_id ];
3931 
3932  // parent prefix
3933  return_val->append( (*lti_name) );
3934  return_val->append( "_" );
3935 
3936  // terminal count
3937  terminal_num = my_terminals->size();
3938  to_string( terminal_num, temp_str );
3939  return_val->append( temp_str );
3940 
3941  // prepare for value
3942  return_val->append( " [ label = \"" );
3943 
3944  // output value
3945  {
3946  switch ( q->column_int( 3 ) )
3947  {
3949  smem_reverse_hash_str( my_agent, q->column_int(4), temp_str );
3950  break;
3951 
3953  temp_int = smem_reverse_hash_int( my_agent, q->column_int(4) );
3954  to_string( temp_int, temp_str );
3955  break;
3956 
3958  temp_double = smem_reverse_hash_float( my_agent, q->column_int(4) );
3959  to_string( temp_double, temp_str );
3960  break;
3961 
3962  default:
3963  temp_str.clear();
3964  break;
3965  }
3966 
3967  return_val->append( temp_str );
3968  }
3969 
3970  // store terminal (attribute for edge label)
3971  {
3972  switch ( q->column_int(1) )
3973  {
3975  smem_reverse_hash_str( my_agent, q->column_int(2), temp_str );
3976  break;
3977 
3979  temp_int = smem_reverse_hash_int( my_agent, q->column_int(2) );
3980  to_string( temp_int, temp_str );
3981  break;
3982 
3984  temp_double = smem_reverse_hash_float( my_agent, q->column_int(2) );
3985  to_string( temp_double, temp_str );
3986  break;
3987 
3988  default:
3989  temp_str.clear();
3990  break;
3991  }
3992 
3993  my_terminals->push_back( temp_str );
3994  }
3995 
3996  // footer
3997  return_val->append( "\" ];" );
3998  return_val->append( "\n" );
3999  }
4000  q->reinitialize();
4001 
4002  // output edges
4003  {
4004  unsigned int terminal_counter;
4005 
4006  for ( n_p=lti_names.begin(); n_p!=lti_names.end(); n_p++ )
4007  {
4008  t_p = lti_terminals.find( n_p->first );
4009 
4010  if ( t_p != lti_terminals.end() )
4011  {
4012  terminal_counter = 0;
4013 
4014  for ( a_p=t_p->second.begin(); a_p!=t_p->second.end(); a_p++ )
4015  {
4016  return_val->append( n_p->second );
4017  return_val ->append( " -> " );
4018  return_val->append( n_p->second );
4019  return_val->append( "_" );
4020 
4021  to_string( terminal_counter, temp_str );
4022  return_val->append( temp_str );
4023  return_val->append( " [ label=\"" );
4024 
4025  return_val->append( (*a_p) );
4026 
4027  return_val->append( "\" ];" );
4028  return_val->append( "\n" );
4029 
4030  terminal_counter++;
4031  }
4032  }
4033  }
4034  }
4035  }
4036 
4037  // then links to other LTIs
4038  {
4039  // parent_id, attr_type, attr_hash, val_lti
4040  q = my_agent->smem_stmts->vis_value_lti;
4041  while ( q->execute() == soar_module::row )
4042  {
4043  // source
4044  lti_id = q->column_int( 0 );
4045  lti_name =& lti_names[ lti_id ];
4046  return_val->append( (*lti_name) );
4047  return_val->append( " -> " );
4048 
4049  // destination
4050  lti_id = q->column_int( 3 );
4051  lti_name =& lti_names[ lti_id ];
4052  return_val->append( (*lti_name) );
4053  return_val->append( " [ label =\"" );
4054 
4055  // output attribute
4056  {
4057  switch ( q->column_int(1) )
4058  {
4060  smem_reverse_hash_str( my_agent, q->column_int(2), temp_str );
4061  break;
4062 
4064  temp_int = smem_reverse_hash_int( my_agent, q->column_int(2) );
4065  to_string( temp_int, temp_str );
4066  break;
4067 
4069  temp_double = smem_reverse_hash_float( my_agent, q->column_int(2) );
4070  to_string( temp_double, temp_str );
4071  break;
4072 
4073  default:
4074  temp_str.clear();
4075  break;
4076  }
4077 
4078  return_val->append( temp_str );
4079  }
4080 
4081  // footer
4082  return_val->append( "\" ];" );
4083  return_val->append( "\n" );
4084  }
4085  q->reinitialize();
4086  }
4087  }
4088  }
4089 
4090  // footer
4091  return_val->append( "}" );
4092  return_val->append( "\n" );
4093 }
4094 
4095 void smem_visualize_lti( agent *my_agent, smem_lti_id lti_id, unsigned int depth, std::string *return_val )
4096 {
4097  // buffer
4098  std::string return_val2;
4099 
4100  soar_module::sqlite_statement* expand_q = my_agent->smem_stmts->web_expand;
4101 
4102  uint64_t child_counter;
4103 
4104  std::string temp_str;
4105  std::string temp_str2;
4106  int64_t temp_int;
4107  double temp_double;
4108 
4109  std::queue<smem_vis_lti *> bfs;
4110  smem_vis_lti *new_lti;
4111  smem_vis_lti *parent_lti;
4112 
4113  std::map< smem_lti_id, smem_vis_lti* > close_list;
4114  std::map< smem_lti_id, smem_vis_lti* >::iterator cl_p;
4115 
4116  // header
4117  return_val->append( "digraph smem_lti {" );
4118  return_val->append( "\n" );
4119 
4120  // root
4121  {
4122  new_lti = new smem_vis_lti;
4123  new_lti->lti_id = lti_id;
4124  new_lti->level = 0;
4125 
4126  // fake former linkage
4127  {
4129 
4130  // get just this lti
4131  lti_q->bind_int( 1, lti_id );
4132  lti_q->execute();
4133 
4134  // letter
4135  new_lti->lti_name.push_back( static_cast<char>( lti_q->column_int( 0 ) ) );
4136 
4137  // number
4138  temp_int = lti_q->column_int( 1 );
4139  to_string( temp_int, temp_str );
4140  new_lti->lti_name.append( temp_str );
4141 
4142  // done with lookup
4143  lti_q->reinitialize();
4144  }
4145 
4146  bfs.push( new_lti );
4147  close_list.insert( std::make_pair< smem_lti_id, smem_vis_lti* >( lti_id, new_lti ) );
4148 
4149  new_lti = NULL;
4150  }
4151 
4152  // optionally depth-limited breadth-first-search of children
4153  while ( !bfs.empty() )
4154  {
4155  parent_lti = bfs.front();
4156  bfs.pop();
4157 
4158  child_counter = 0;
4159 
4160  // get direct children: attr_type, attr_hash, value_type, value_hash, value_letter, value_num, value_lti
4161  expand_q->bind_int( 1, parent_lti->lti_id );
4162  while ( expand_q->execute() == soar_module::row )
4163  {
4164  // identifier vs. constant
4165  if ( expand_q->column_int( 6 ) != SMEM_WEB_NULL )
4166  {
4167  new_lti = new smem_vis_lti;
4168  new_lti->lti_id = expand_q->column_int( 6 );
4169  new_lti->level = ( parent_lti->level + 1 );
4170 
4171  // add node
4172  {
4173  // letter
4174  new_lti->lti_name.push_back( static_cast<char>( expand_q->column_int( 4 ) ) );
4175 
4176  // number
4177  temp_int = expand_q->column_int( 5 );
4178  to_string( temp_int, temp_str );
4179  new_lti->lti_name.append( temp_str );
4180  }
4181 
4182 
4183  // add linkage
4184  {
4185  // get attribute
4186  switch ( expand_q->column_int(0) )
4187  {
4189  smem_reverse_hash_str( my_agent, expand_q->column_int(1), temp_str );
4190  break;
4191 
4193  temp_int = smem_reverse_hash_int( my_agent, expand_q->column_int(1) );
4194  to_string( temp_int, temp_str );
4195  break;
4196 
4198  temp_double = smem_reverse_hash_float( my_agent, expand_q->column_int(1) );
4199  to_string( temp_double, temp_str );
4200  break;
4201 
4202  default:
4203  temp_str.clear();
4204  break;
4205  }
4206 
4207  // output linkage
4208  return_val2.append( parent_lti->lti_name );
4209  return_val2.append( " -> " );
4210  return_val2.append( new_lti->lti_name );
4211  return_val2.append( " [ label = \"" );
4212  return_val2.append( temp_str );
4213  return_val2.append( "\" ];" );
4214  return_val2.append( "\n" );
4215  }
4216 
4217  // prevent looping
4218  {
4219  cl_p = close_list.find( new_lti->lti_id );
4220  if ( cl_p == close_list.end() )
4221  {
4222  close_list.insert( std::make_pair< smem_lti_id, smem_vis_lti* >( new_lti->lti_id, new_lti ) );
4223 
4224  if ( ( depth == 0 ) || ( new_lti->level < depth ) )
4225  {
4226  bfs.push( new_lti );
4227  }
4228  }
4229  else
4230  {
4231  delete new_lti;
4232  }
4233  }
4234 
4235  new_lti = NULL;
4236  }
4237  else
4238  {
4239  // add value node
4240  {
4241  // get node name
4242  {
4243  temp_str2.assign( parent_lti->lti_name );
4244  temp_str2.append( "_" );
4245 
4246  to_string( child_counter, temp_str );
4247  temp_str2.append( temp_str );
4248  }
4249 
4250  // get value
4251  switch ( expand_q->column_int(2) )
4252  {
4254  smem_reverse_hash_str( my_agent, expand_q->column_int(3), temp_str );
4255  break;
4256 
4258  temp_int = smem_reverse_hash_int( my_agent, expand_q->column_int(3) );
4259  to_string( temp_int, temp_str );
4260  break;
4261 
4263  temp_double = smem_reverse_hash_float( my_agent, expand_q->column_int(3) );
4264  to_string( temp_double, temp_str );
4265  break;
4266 
4267  default:
4268  temp_str.clear();
4269  break;
4270  }
4271 
4272  // output node
4273  return_val2.append( "node [ shape = plaintext ];" );
4274  return_val2.append( "\n" );
4275  return_val2.append( temp_str2 );
4276  return_val2.append( " [ label=\"" );
4277  return_val2.append( temp_str );
4278  return_val2.append( "\" ];" );
4279  return_val2.append( "\n" );
4280  }
4281 
4282  // add linkage
4283  {
4284  // get attribute
4285  switch ( expand_q->column_int(0) )
4286  {
4288  smem_reverse_hash_str( my_agent, expand_q->column_int(1), temp_str );
4289  break;
4290 
4292  temp_int = smem_reverse_hash_int( my_agent, expand_q->column_int(1) );
4293  to_string( temp_int, temp_str );
4294  break;
4295 
4297  temp_double = smem_reverse_hash_float( my_agent, expand_q->column_int(1) );
4298  to_string( temp_double, temp_str );
4299  break;
4300 
4301  default:
4302  temp_str.clear();
4303  break;
4304  }
4305 
4306  // output linkage
4307  return_val2.append( parent_lti->lti_name );
4308  return_val2.append( " -> " );
4309  return_val2.append( temp_str2 );
4310  return_val2.append( " [ label = \"" );
4311  return_val2.append( temp_str );
4312  return_val2.append( "\" ];" );
4313  return_val2.append( "\n" );
4314  }
4315 
4316  child_counter++;
4317  }
4318  }
4319  expand_q->reinitialize();
4320  }
4321 
4322  // footer
4323  return_val2.append( "}" );
4324  return_val2.append( "\n" );
4325 
4326  // handle lti nodes at once
4327  {
4329 
4330  return_val->append( "node [ shape = doublecircle ];" );
4331  return_val->append( "\n" );
4332 
4333  for ( cl_p=close_list.begin(); cl_p!=close_list.end(); cl_p++ )
4334  {
4335  return_val->append( cl_p->second->lti_name );
4336  return_val->append( " [ label=\"" );
4337  return_val->append( cl_p->second->lti_name );
4338  return_val->append( "\\n[" );
4339 
4340  act_q->bind_int( 1, cl_p->first );
4341  if ( act_q->execute() == soar_module::row )
4342  {
4343  temp_double = act_q->column_double( 0 );
4344  to_string( temp_double, temp_str, 3, true );
4345  if ( temp_double >= 0 )
4346  {
4347  return_val->append( "+" );
4348  }
4349  return_val->append( temp_str );
4350  }
4351  act_q->reinitialize();
4352 
4353  return_val->append( "]\"" );
4354  return_val->append( " ];" );
4355  return_val->append( "\n" );
4356 
4357  delete cl_p->second;
4358  }
4359  }
4360 
4361  // transfer buffer after nodes
4362  return_val->append( return_val2 );
4363 }
4364 
4365 inline std::set< smem_lti_id > _smem_print_lti( agent* my_agent, smem_lti_id lti_id, char lti_letter, uint64_t lti_number, double lti_act, std::string *return_val )
4366 {
4367  std::set< smem_lti_id > next;
4368 
4369  std::string temp_str, temp_str2, temp_str3;
4370  int64_t temp_int;
4371  double temp_double;
4372 
4373  std::map< std::string, std::list< std::string > > augmentations;
4374  std::map< std::string, std::list< std::string > >::iterator lti_slot;
4375  std::list< std::string >::iterator slot_val;
4376 
4377  soar_module::sqlite_statement* expand_q = my_agent->smem_stmts->web_expand;
4378 
4379  //
4380  //
4381 
4382  return_val->append( "(@" );
4383  return_val->push_back( lti_letter );
4384  to_string( lti_number, temp_str );
4385  return_val->append( temp_str );
4386 
4387  // get direct children: attr_type, attr_hash, value_type, value_hash, value_letter, value_num, value_lti
4388  expand_q->bind_int( 1, lti_id );
4389  while ( expand_q->execute() == soar_module::row )
4390  {
4391  // get attribute
4392  switch ( expand_q->column_int(0) )
4393  {
4395  smem_reverse_hash_str( my_agent, expand_q->column_int(1), temp_str );
4396  break;
4397 
4399  temp_int = smem_reverse_hash_int( my_agent, expand_q->column_int(1) );
4400  to_string( temp_int, temp_str );
4401  break;
4402 
4404  temp_double = smem_reverse_hash_float( my_agent, expand_q->column_int(1) );
4405  to_string( temp_double, temp_str );
4406  break;
4407 
4408  default:
4409  temp_str.clear();
4410  break;
4411  }
4412 
4413  // identifier vs. constant
4414  if ( expand_q->column_int( 6 ) != SMEM_WEB_NULL )
4415  {
4416  temp_str2.clear();
4417  temp_str2.push_back( '@' );
4418 
4419  // letter
4420  temp_str2.push_back( static_cast<char>( expand_q->column_int( 4 ) ) );
4421 
4422  // number
4423  temp_int = expand_q->column_int( 5 );
4424  to_string( temp_int, temp_str3 );
4425  temp_str2.append( temp_str3 );
4426 
4427  // add to next
4428  next.insert( static_cast< smem_lti_id >( expand_q->column_int( 6 ) ) );
4429  }
4430  else
4431  {
4432  switch ( expand_q->column_int(2) )
4433  {
4435  smem_reverse_hash_str( my_agent, expand_q->column_int(3), temp_str2 );
4436  break;
4437 
4439  temp_int = smem_reverse_hash_int( my_agent, expand_q->column_int(3) );
4440  to_string( temp_int, temp_str2 );
4441  break;
4442 
4444  temp_double = smem_reverse_hash_float( my_agent, expand_q->column_int(3) );
4445  to_string( temp_double, temp_str2 );
4446  break;
4447 
4448  default:
4449  temp_str2.clear();
4450  break;
4451  }
4452  }
4453 
4454  augmentations[ temp_str ].push_back( temp_str2 );
4455  }
4456  expand_q->reinitialize();
4457 
4458  // output augmentations nicely
4459  {
4460  for ( lti_slot=augmentations.begin(); lti_slot!=augmentations.end(); lti_slot++ )
4461  {
4462  return_val->append( " ^" );
4463  return_val->append( lti_slot->first );
4464 
4465  for ( slot_val=lti_slot->second.begin(); slot_val!=lti_slot->second.end(); slot_val++ )
4466  {
4467  return_val->append( " " );
4468  return_val->append( (*slot_val) );
4469  }
4470  }
4471  }
4472  augmentations.clear();
4473 
4474  return_val->append( " [" );
4475  to_string( lti_act, temp_str, 3, true );
4476  if ( lti_act >= 0 )
4477  {
4478  return_val->append( "+" );
4479  }
4480  return_val->append( temp_str );
4481  return_val->append( "]" );
4482  return_val->append( ")\n" );
4483 
4484  return next;
4485 }
4486 
4487 void smem_print_store( agent *my_agent, std::string *return_val )
4488 {
4489  // vizualizing the store requires an open semantic database
4490  smem_attach( my_agent );
4491 
4492  // id, letter, number
4494  while ( q->execute() == soar_module::row )
4495  {
4496  _smem_print_lti( my_agent, q->column_int( 0 ), static_cast<char>( q->column_int( 1 ) ), static_cast<uint64_t>( q->column_int( 2 ) ), q->column_double( 3 ), return_val );
4497  }
4498  q->reinitialize();
4499 }
4500 
4501 void smem_print_lti( agent *my_agent, smem_lti_id lti_id, unsigned int depth, std::string *return_val )
4502 {
4503  std::set< smem_lti_id > visited;
4504  std::pair< std::set< smem_lti_id >::iterator, bool > visited_ins_result;
4505 
4506  std::queue< std::pair< smem_lti_id, unsigned int > > to_visit;
4507  std::pair< smem_lti_id, unsigned int > c;
4508 
4509  std::set< smem_lti_id > next;
4510  std::set< smem_lti_id >::iterator next_it;
4511 
4514  unsigned int i;
4515 
4516  // vizualizing the store requires an open semantic database
4517  smem_attach( my_agent );
4518 
4519  // initialize queue/set
4520  to_visit.push( std::make_pair< smem_lti_id, unsigned int >( lti_id, 1 ) );
4521  visited.insert( lti_id );
4522 
4523  while ( !to_visit.empty() )
4524  {
4525  c = to_visit.front();
4526  to_visit.pop();
4527 
4528  // output leading spaces ala depth
4529  for ( i=1; i<c.second; i++ )
4530  {
4531  return_val->append( " " );
4532  }
4533 
4534  // get lti info
4535  {
4536  lti_q->bind_int( 1, c.first );
4537  lti_q->execute();
4538 
4539  act_q->bind_int( 1, c.first );
4540  act_q->execute();
4541 
4542  next = _smem_print_lti( my_agent, c.first, static_cast<char>( lti_q->column_int( 0 ) ), static_cast<uint64_t>( lti_q->column_int( 1 ) ), act_q->column_double( 0 ), return_val );
4543 
4544  // done with lookup
4545  lti_q->reinitialize();
4546  act_q->reinitialize();
4547 
4548  // consider further depth
4549  if ( c.second < depth )
4550  {
4551  for ( next_it=next.begin(); next_it!=next.end(); next_it++ )
4552  {
4553  visited_ins_result = visited.insert( (*next_it) );
4554  if ( visited_ins_result.second )
4555  {
4556  to_visit.push( std::make_pair< smem_lti_id, unsigned int >( (*next_it), c.second+1 ) );
4557  }
4558  }
4559  }
4560  }
4561  }
4562 }