Soar Kernel  9.3.2 08-06-12
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
utilities.cpp
Go to the documentation of this file.
1 #include <portability.h>
2 
3 /*************************************************************************
4  * PLEASE SEE THE FILE "license.txt" (INCLUDED WITH THIS SOFTWARE PACKAGE)
5  * FOR LICENSE AND COPYRIGHT INFORMATION.
6  *************************************************************************/
7 
8 /* utilities.cpp */
9 
10 #include "agent.h"
11 #include "misc.h"
12 #include "utilities.h"
13 #include "gdatastructs.h"
14 #include "wmem.h"
15 #include "print.h"
16 #include "xml.h"
17 
18 #include <time.h>
19 
20 bool read_id_or_context_var_from_string (agent* agnt, const char * the_lexeme,
21  Symbol * * result_id)
22 {
23  Symbol *id;
24  Symbol *g, *attr, *value;
25 
26  get_lexeme_from_string(agnt, the_lexeme);
27 
28  if (agnt->lexeme.type == IDENTIFIER_LEXEME)
29  {
30  id = find_identifier(agnt, agnt->lexeme.id_letter, agnt->lexeme.id_number);
31  if (!id)
32  {
33  return false;
34  }
35  else
36  {
37  *result_id = id;
38  return true;
39  }
40  }
41 
42  if (agnt->lexeme.type==VARIABLE_LEXEME)
43  {
44  get_context_var_info (agnt, &g, &attr, &value);
45 
46  if ((!attr) || (!value))
47  {
48  return false;
49  }
50 
51  if (value->common.symbol_type != IDENTIFIER_SYMBOL_TYPE)
52  {
53  return false;
54  }
55 
56  *result_id = value;
57  return true;
58  }
59 
60  return false;
61 }
62 
63 void get_lexeme_from_string (agent* agnt, const char * the_lexeme)
64 {
65  int i;
66  const char * c;
67  bool sym_constant_start_found = FALSE;
68  bool sym_constant_end_found = FALSE;
69 
70  for (c = the_lexeme, i = 0; *c; c++, i++)
71  {
72  if (*c == '|')
73  {
74  if (!sym_constant_start_found)
75  {
76  i--;
77  sym_constant_start_found = TRUE;
78  }
79  else
80  {
81  i--;
82  sym_constant_end_found = TRUE;
83  }
84  }
85  else
86  {
87  agnt->lexeme.string[i] = *c;
88  }
89  }
90 
91  agnt->lexeme.string[i] = '\0'; /* Null terminate lexeme string */
92 
93  agnt->lexeme.length = i;
94 
95  if (sym_constant_end_found)
96  {
98  }
99  else
100  {
102  }
103 }
104 
105 void get_context_var_info ( agent* agnt, Symbol **dest_goal,
106  Symbol **dest_attr_of_slot,
107  Symbol **dest_current_value)
108 {
109  Symbol *v, *g;
110  int levels_up;
111  wme *w;
112 
113  v = find_variable (agnt, agnt->lexeme.string);
114  if (v==agnt->s_context_variable) {
115  levels_up = 0;
116  *dest_attr_of_slot = agnt->state_symbol;
117  } else if (v==agnt->o_context_variable) {
118  levels_up = 0;
119  *dest_attr_of_slot = agnt->operator_symbol;
120  } else if (v==agnt->ss_context_variable) {
121  levels_up = 1;
122  *dest_attr_of_slot = agnt->state_symbol;
123  } else if (v==agnt->so_context_variable) {
124  levels_up = 1;
125  *dest_attr_of_slot = agnt->operator_symbol;
126  } else if (v==agnt->sss_context_variable) {
127  levels_up = 2;
128  *dest_attr_of_slot = agnt->state_symbol;
129  } else if (v==agnt->sso_context_variable) {
130  levels_up = 2;
131  *dest_attr_of_slot = agnt->operator_symbol;
132  } else if (v==agnt->ts_context_variable) {
133  levels_up = agnt->top_goal ? agnt->bottom_goal->id.level-agnt->top_goal->id.level : 0;
134  *dest_attr_of_slot = agnt->state_symbol;
135  } else if (v==agnt->to_context_variable) {
136  levels_up = agnt->top_goal ? agnt->bottom_goal->id.level-agnt->top_goal->id.level : 0;
137  *dest_attr_of_slot = agnt->operator_symbol;
138  } else {
139  *dest_goal = NIL;
140  *dest_attr_of_slot = NIL;
141  *dest_current_value = NIL;
142  return;
143  }
144 
145  g = agnt->bottom_goal;
146  while (g && levels_up) {
147  g = g->id.higher_goal;
148  levels_up--;
149  }
150  *dest_goal = g;
151 
152  if (!g) {
153  *dest_current_value = NIL;
154  return;
155  }
156 
157  if (*dest_attr_of_slot==agnt->state_symbol) {
158  *dest_current_value = g;
159  } else {
160  w = g->id.operator_slot->wmes;
161  *dest_current_value = w ? w->value : NIL;
162  }
163 }
164 
166 {
167  Symbol *id;
168  Symbol *g, *attr, *value;
169 
170  if (agnt->lexeme.type==IDENTIFIER_LEXEME) {
171  id = find_identifier (agnt, agnt->lexeme.id_letter, agnt->lexeme.id_number);
172  if (!id) {
173  print (agnt, "There is no identifier %c%lu.\n", agnt->lexeme.id_letter,
174  agnt->lexeme.id_number);
176  return NIL;
177  }
178  return id;
179  }
180  if (agnt->lexeme.type==VARIABLE_LEXEME)
181  {
182  get_context_var_info (agnt, &g, &attr, &value);
183  if (!attr) {
184  print (agnt, "Expected identifier (or context variable)\n");
186  return NIL;
187  }
188  if (!value) {
189  print (agnt, "There is no current %s.\n", agnt->lexeme.string);
191  return NIL;
192  }
193  if (value->common.symbol_type!=IDENTIFIER_SYMBOL_TYPE) {
194  print (agnt, "The current %s ", agnt->lexeme.string);
195  print_with_symbols (agnt, "(%y) is not an identifier.\n", value);
197  return NIL;
198  }
199  return value;
200  }
201  print (agnt, "Expected identifier (or context variable)\n");
203  return NIL;
204 }
205 
206 #ifdef REAL_TIME_BEHAVIOR
207 * RMJ */
208 void init_real_time (agent* thisAgent) {
209  thisAgent->real_time_tracker =
210  (struct timeval *) malloc(sizeof(struct timeval));
211  timerclear(thisAgent->real_time_tracker);
212  thisAgent->real_time_idling = FALSE;
213  current_real_time =
214  (struct timeval *) malloc(sizeof(struct timeval));
215 }
216 void test_for_input_delay (agent* thisAgent) {
217  /* RMJ; For real-time behavior, don't start any new decision phase
218  * until the specified "artificial" time step has passed
219  */
220  start_timer (thisAgent, current_real_time);
221  if (timercmp(current_real_time, thisAgent->real_time_tracker, <)) {
222  if (!(thisAgent->real_time_idling)) {
223  thisAgent->real_time_idling = TRUE;
224  if (thisAgent->sysparams[TRACE_PHASES_SYSPARAM]) {
225  print_phase (thisAgent, "\n--- Real-time Idle Phase ---\n");
226  }
227  }
228  break;
229  }
230  /* Artificial time delay has passed.
231  * Reset new delay and start the decision phase with input
232  */
233  thisAgent->real_time_tracker->tv_sec = current_real_time->tv_sec;
234  thisAgent->real_time_tracker->tv_usec =
235  current_real_time->tv_usec +
236  1000 * thisAgent->sysparams[REAL_TIME_SYSPARAM];
237  if (thisAgent->real_time_tracker->tv_usec >= 1000000) {
238  thisAgent->real_time_tracker->tv_sec +=
239  thisAgent->real_time_tracker->tv_usec / 1000000;
240  thisAgent->real_time_tracker->tv_usec %= 1000000;
241  }
242  thisAgent->real_time_idling = FALSE;
243 }
244 #endif // REAL_TIME_BEHAVIOR
245 
246 #ifdef ATTENTION_LAPSE
247 * RMJ */
248 
249 void init_attention_lapse (void) {
250  thisAgent->attention_lapse_tracker =
251  (struct timeval *) malloc(sizeof(struct timeval));
252  wake_from_attention_lapse();
253 #ifndef REAL_TIME_BEHAVIOR
254  current_real_time =
255  (struct timeval *) malloc(sizeof(struct timeval));
256 #endif // REAL_TIME_BEHAVIOR
257 }
258 void start_attention_lapse (int64_t duration) {
259  /* Set tracker to time we should wake up */
260  start_timer (thisAgent->attention_lapse_tracker);
261  thisAgent->attention_lapse_tracker->tv_usec += 1000 * duration;
262  if (thisAgent->attention_lapse_tracker->tv_usec >= 1000000) {
263  thisAgent->attention_lapse_tracker->tv_sec +=
264  thisAgent->attention_lapse_tracker->tv_usec / 1000000;
265  thisAgent->attention_lapse_tracker->tv_usec %= 1000000;
266  }
267  thisAgent->attention_lapsing = TRUE;
268 }
269 void wake_from_attention_lapse (void) {
270  /* Set tracker to last time we woke up */
271  start_timer (thisAgent->attention_lapse_tracker);
272  thisAgent->attention_lapsing = FALSE;
273 }
274 void determine_lapsing (agent* thisAgent) {
275  /* RMJ; decide whether to start or finish an attentional lapse */
276  if (thisAgent->sysparams[ATTENTION_LAPSE_ON_SYSPARAM]) {
277  if (thisAgent->attention_lapsing) {
278  /* If lapsing, is it time to stop? */
279  start_timer (thisAgent, current_real_time);
280  if (`cmp(current_real_time,
281  thisAgent->attention_lapse_tracker, >)) {
282  wake_from_attention_lapse();
283  }
284  } else {
285  /* If not lapsing, should we start? */
286  lapse_duration = init_lapse_duration(thisAgent->attention_lapse_tracker);
287  if (lapse_duration > 0) {
288  start_attention_lapse(lapse_duration);
289  }
290  }
291  }
292 }
293 * RMJ;
294  When doing attentional lapsing, we need a function that determines
295  when (and for how long) attentional lapses should occur. This
296  will normally be provided as a user-defined TCL procedure. But
297  we need to put a placeholder function here just to be safe.
298 */
299 int64_t init_lapse_duration(struct timeval *tv) {
300  return 0;
301 }
302 #endif // ATTENTION_LAPSE
303 
304 // formerly in misc.cpp:
305 /***************************************************************************
306  * Function : is_natural_number
307  **************************************************************************/
308 bool is_whole_number(const std::string &str)
309 {
310  return is_whole_number(str.c_str());
311 }
312 
313 bool is_whole_number(const char * str)
314 {
315  if(!str || !*str)
316  return false;
317 
318  do {
319  if(isdigit(*str))
320  ++str;
321  else
322  return false;
323  } while(*str);
324 
325  return true;
326 }
327 
328 /***************************************************************************
329  * Function : get_number_from_symbol
330  **************************************************************************/
332 {
333  if ( sym->common.symbol_type == FLOAT_CONSTANT_SYMBOL_TYPE )
334  return sym->fc.value;
335  else if ( sym->common.symbol_type == INT_CONSTANT_SYMBOL_TYPE )
336  return static_cast<double>(sym->ic.value);
337 
338  return 0.0;
339 }
340 
341 void stats_init_db( agent *my_agent )
342 {
343  if ( my_agent->stats_db->get_status() != soar_module::disconnected )
344  return;
345 
346  const char *db_path = ":memory:";
347  //const char *db_path = "C:\\Users\\voigtjr\\Desktop\\stats_debug.db";
348 
349  // attempt connection
350  my_agent->stats_db->connect( db_path );
351 
352  if ( my_agent->stats_db->get_status() == soar_module::problem )
353  {
354  char buf[256];
355  SNPRINTF( buf, 254, "DB ERROR: %s", my_agent->stats_db->get_errmsg() );
356 
357  print( my_agent, buf );
358  xml_generate_warning( my_agent, buf );
359  }
360  else
361  {
362  // setup common structures/queries
363  my_agent->stats_stmts = new stats_statement_container( my_agent );
364  my_agent->stats_stmts->structure();
365  my_agent->stats_stmts->prepare();
366  }
367 }
368 
369 
370 void stats_db_store(agent* my_agent, const uint64_t& dc_time, const uint64_t& dc_wm_changes, const uint64_t& dc_firing_counts)
371 {
372  if ( my_agent->stats_db->get_status() == soar_module::disconnected )
373  {
374  stats_init_db( my_agent );
375  }
376 
377  my_agent->stats_stmts->insert->bind_int(1, my_agent->d_cycle_count);
378  my_agent->stats_stmts->insert->bind_int(2, dc_time);
379  my_agent->stats_stmts->insert->bind_int(3, dc_wm_changes);
380  my_agent->stats_stmts->insert->bind_int(4, dc_firing_counts);
381 
382  my_agent->stats_stmts->insert->execute( soar_module::op_reinit ); // makes it ready for next execution
383 }
384 
385 stats_statement_container::stats_statement_container( agent *new_agent ): soar_module::sqlite_statement_container( new_agent->stats_db )
386 {
387  soar_module::sqlite_database *new_db = new_agent->stats_db;
388 
389  //
390 
391  add_structure( "CREATE TABLE IF NOT EXISTS stats (dc INTEGER PRIMARY KEY, time INTEGER, wm_changes INTEGER, firing_count INTEGER)" );
392  add_structure( "CREATE INDEX IF NOT EXISTS stats_time ON stats (time)" );
393  add_structure( "CREATE INDEX IF NOT EXISTS stats_wm_changes ON stats (wm_changes)" );
394  add_structure( "CREATE INDEX IF NOT EXISTS stats_firing_count ON stats (firing_count)" );
395 
396  //
397 
398  insert = new soar_module::sqlite_statement( new_db, "INSERT INTO stats (dc, time, wm_changes, firing_count) VALUES (?,?,?,?)" );
399  add( insert );
400 
401  cache5 = new soar_module::sqlite_statement( new_db, "PRAGMA cache_size = 5000" );
402  add( cache5 );
403 
404  cache20 = new soar_module::sqlite_statement( new_db, "PRAGMA cache_size = 20000" );
405  add( cache20 );
406 
407  cache100 = new soar_module::sqlite_statement( new_db, "PRAGMA cache_size = 100000" );
408  add( cache100 );
409 
410  sel_dc_inc = new soar_module::sqlite_statement( new_db, "SELECT * FROM stats ORDER BY dc" );
411  add( sel_dc_inc );
412 
413  sel_dc_dec = new soar_module::sqlite_statement( new_db, "SELECT * FROM stats ORDER BY dc DESC" );
414  add( sel_dc_dec );
415 
416  sel_time_inc = new soar_module::sqlite_statement( new_db, "SELECT * FROM stats ORDER BY time" );
417  add( sel_time_inc );
418 
419  sel_time_dec = new soar_module::sqlite_statement( new_db, "SELECT * FROM stats ORDER BY time DESC" );
420  add( sel_time_dec );
421 
422  sel_wm_changes_inc = new soar_module::sqlite_statement( new_db, "SELECT * FROM stats ORDER BY wm_changes" );
424 
425  sel_wm_changes_dec = new soar_module::sqlite_statement( new_db, "SELECT * FROM stats ORDER BY wm_changes DESC" );
427 
428  sel_firing_count_inc = new soar_module::sqlite_statement( new_db, "SELECT * FROM stats ORDER BY firing_count" );
430 
431  sel_firing_count_dec = new soar_module::sqlite_statement( new_db, "SELECT * FROM stats ORDER BY firing_count DESC" );
433 }
434 
435 void stats_close( agent *my_agent )
436 {
437  if ( my_agent->stats_db->get_status() == soar_module::connected )
438  {
439  // de-allocate common statements
440  delete my_agent->stats_stmts;
441  my_agent->stats_stmts = 0;
442 
443  // close the database
444  my_agent->stats_db->disconnect();
445  }
446 }
447 
448 uint64_t get_derived_kernel_time_usec(agent* thisAgent) {
449 #ifndef NO_TIMING_STUFF
450  return thisAgent->timers_decision_cycle_phase[INPUT_PHASE].get_usec()
451  + thisAgent->timers_decision_cycle_phase[PROPOSE_PHASE].get_usec()
452  + thisAgent->timers_decision_cycle_phase[APPLY_PHASE].get_usec()
453  + thisAgent->timers_decision_cycle_phase[PREFERENCE_PHASE].get_usec()
454  + thisAgent->timers_decision_cycle_phase[WM_PHASE].get_usec()
455  + thisAgent->timers_decision_cycle_phase[OUTPUT_PHASE].get_usec()
456  + thisAgent->timers_decision_cycle_phase[DECISION_PHASE].get_usec();
457 #else
458  return 0;
459 #endif
460 }
461