Soar Kernel  9.3.2 08-06-12
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
decide.cpp
Go to the documentation of this file.
1 #include <portability.h>
2 #include "soar_rand.h" // provides SoarRand, a better random number generator (see bug 595)
3 
4 /*************************************************************************
5  * PLEASE SEE THE FILE "license.txt" (INCLUDED WITH THIS SOFTWARE PACKAGE)
6  * FOR LICENSE AND COPYRIGHT INFORMATION.
7  *************************************************************************/
8 
9 /*************************************************************************
10  *
11  * file: decide.cpp
12  *
13  * =======================================================================
14  * Decider and Associated Routines for Soar 6
15  *
16  * This file contains the decider as well as routine for managing
17  * slots, and the garbage collection of disconnected WMEs.
18  * =======================================================================
19  */
20 
21 
22 /* Debugging stuff: #define DEBUG_LINKS to get links, gc printouts */
23 /* #define DEBUG_SLOTS to get slot printouts */
24 /* #define DEBUG_LINKS */
25 /* #define DEBUG_SLOTS */
26 
27 /* REW: begin 09.15.96 */
28 /* For low-level, detailed information on the processing of the GDS */
29 /* #define DEBUG_GDS */
30 /* For high-level information on the instantiations that created an
31  * o-supported element and lead to the elaboration of the GDS */
32 /* #define DEBUG_GDS_HIGH */
33 /* REW: end 09.15.96 */
34 
35 #include "decide.h"
36 #include "gdatastructs.h"
37 #include "instantiations.h"
38 #include "mem.h"
39 #include "kernel.h"
40 #include "agent.h"
41 #include "symtab.h"
42 #include "wmem.h"
43 #include "init_soar.h"
44 #include "prefmem.h"
45 #include "production.h"
46 #include "print.h"
47 #include "trace.h"
48 #include "explain.h"
49 #include "tempmem.h"
50 #include "io_soar.h"
51 #include "xml.h"
52 #include "soar_TraceNames.h"
53 
54 #include "soar_module.h"
55 
56 #include "exploration.h"
57 #include "reinforcement_learning.h"
58 #include "decision_manipulation.h"
59 #include "wma.h"
60 #include "misc.h"
61 
62 #include "episodic_memory.h"
63 #include "semantic_memory.h"
64 
65 #include "assert.h"
66 
67 #include <list>
68 
69 using namespace soar_TraceNames;
70 
71 #ifdef USE_MEM_POOL_ALLOCATORS
72 typedef std::list< Symbol*, soar_module::soar_memory_pool_allocator< Symbol* > > symbol_list;
73 #else
74 typedef std::list< Symbol* > symbol_list;
75 #endif
76 
77 
78 /* REW: 2003-01-06 A temporary helper function */
79 
80 void print_candidates(agent* thisAgent, preference * candidates)
81 {
82  preference *cand = 0;
83  int max_count = 0;
84 
85  for (cand = candidates; cand != NIL; cand = cand->next_candidate) {
86  max_count++;
87  print(thisAgent, "\n Candidate %d", cand);
88  print_with_symbols(thisAgent, "\n %y %y %y", cand->id, cand->attr, cand->value);
89  if (max_count > 10)
90  break;
91  }
92 }
93 
94 /* END: 2003-01-02 Behavior Variability Kernel Experiments */
95 
96 //#endif
97 
98 /* ------------------------------------------------------------------------
99  Decider Global Variables
100 
101  Top_goal and bottom_goal point to the top and bottom goal identifiers,
102  respectively. (If there is no goal stack at all, they're both NIL.)
103  Top_state points to the top state (Symbol) if there is a top state, and
104  is NIL of there isn't any top state selected.
105 
106  Highest_goal_whose_context_changed points to the identifier of the highest
107  goal for which some context slot has changed preferences. If no context
108  slot has changed preferences, this variable is NIL. This is used by
109  the decider during decision phase to avoid scanning down the whole
110  goal stack when (as is the usual case) it really only needs to look at
111  the lowest context.
112 
113  Changed_slots is a dl_list of non-context slots with changed preferences.
114  This is used by the decider during working memory phase to tell which
115  slots need to be re-decided.
116 
117  Context_slots_with_changed_acceptable_preferences is a dl_list of
118  context slots for which the set of acceptable or require preferences
119  has changed. This is used to update the acceptable preference WMEs.
120 ------------------------------------------------------------------------ */
121 
122 /* --------------------------------------------------
123  Decider Flags
124 
125  The decider often needs to mark symbols with
126  certain flags, usually to record that the symbols
127  are in certain sets or have a certain status.
128  The "common.decider_flag" field on symbols is
129  used for this, and is set to one of the following
130  flag values. (Usually only two or three of these
131  values are used at once, and the meaning should
132  be clear from the code.)
133 -------------------------------------------------- */
134 
135 #define NOTHING_DECIDER_FLAG 0 /* Warning: code relies in this being 0 */
136 #define CANDIDATE_DECIDER_FLAG 1
137 #define CONFLICTED_DECIDER_FLAG 2
138 #define FORMER_CANDIDATE_DECIDER_FLAG 3
139 #define BEST_DECIDER_FLAG 4
140 #define WORST_DECIDER_FLAG 5
141 #define UNARY_INDIFFERENT_DECIDER_FLAG 6
142 #define ALREADY_EXISTING_WME_DECIDER_FLAG 7
143 #define UNARY_PARALLEL_DECIDER_FLAG 8
144 /* REW: 2003-01-02 Behavior Variability Kernel Experiments
145  A new preference type: unary indifferent + constant (probability) value
146 */
147 #define UNARY_INDIFFERENT_CONSTANT_DECIDER_FLAG 9
148 
149 /* ======================================================================
150 
151  Acceptable Preference WME Routines
152 
153  Whenever some acceptable or require preference for a context slot
154  changes, we call mark_context_slot_as_acceptable_preference_changed().
155 
156  At the end of the phase, do_buffered_acceptable_preference_wme_changes()
157  is called to update the acceptable preference wmes. This should be
158  called *before* do_buffered_link_changes() and do_buffered_wm_changes().
159 ====================================================================== */
160 
162  dl_cons *dc;
163 
164  if (s->acceptable_preference_changed) return;
165  allocate_with_pool (thisAgent, &thisAgent->dl_cons_pool, &dc);
166  dc->item = s;
169  next, prev);
170 }
171 
172 /* --- This updates the acceptable preference wmes for a single slot. --- */
174 {
175  wme *w, *next_w;
176  preference *p;
177 
178  /* --- first, reset marks to "NOTHING" --- */
179  for (w=s->acceptable_preference_wmes; w!=NIL; w=w->next)
180  w->value->common.decider_flag = NOTHING_DECIDER_FLAG;
181 
182  /* --- now mark values for which we WANT a wme as "CANDIDATE" values --- */
183  for (p=s->preferences[REQUIRE_PREFERENCE_TYPE]; p!=NIL; p=p->next)
184  p->value->common.decider_flag = CANDIDATE_DECIDER_FLAG;
185  for (p=s->preferences[ACCEPTABLE_PREFERENCE_TYPE]; p!=NIL; p=p->next)
186  p->value->common.decider_flag = CANDIDATE_DECIDER_FLAG;
187 
188  /* --- remove any existing wme's that aren't CANDIDATEs; mark the
189  rest as ALREADY_EXISTING --- */
190 
192  while (w)
193  {
194  next_w = w->next;
195  if (w->value->common.decider_flag==CANDIDATE_DECIDER_FLAG) {
196  w->value->common.decider_flag = ALREADY_EXISTING_WME_DECIDER_FLAG;
197  w->value->common.a.decider_wme = w;
198  w->preference = NIL; /* we'll update this later */
199  } else {
200  remove_from_dll (s->acceptable_preference_wmes, w, next, prev);
201  /* REW: begin 09.15.96 */
202  /* IF we lose an acceptable preference for an operator, then that
203  operator comes out of the slot immediately in OPERAND2.
204  However, if the lost acceptable preference is not for item
205  in the slot, then we don;t need to do anything special until
206  mini-quiescence. */
207  remove_operator_if_necessary(thisAgent, s,w);
208  /* REW: end 09.15.96 */
209  remove_wme_from_wm (thisAgent, w);
210  }
211  w = next_w;
212  }
213 
214  /* --- add the necessary wme's that don't ALREADY_EXIST --- */
215 
216  for (p=s->preferences[REQUIRE_PREFERENCE_TYPE]; p!=NIL; p=p->next) {
217  if (p->value->common.decider_flag==ALREADY_EXISTING_WME_DECIDER_FLAG) {
218  /* --- found existing wme, so just update its trace --- */
219  w = p->value->common.a.decider_wme;
220  if (! w->preference) w->preference = p;
221  } else {
222  w = make_wme (thisAgent, p->id, p->attr, p->value, TRUE);
224  w->preference = p;
225  add_wme_to_wm (thisAgent, w);
226  p->value->common.decider_flag = ALREADY_EXISTING_WME_DECIDER_FLAG;
227  p->value->common.a.decider_wme = w;
228  }
229  }
230  for (p=s->preferences[ACCEPTABLE_PREFERENCE_TYPE]; p!=NIL; p=p->next) {
231  if (p->value->common.decider_flag==ALREADY_EXISTING_WME_DECIDER_FLAG) {
232  /* --- found existing wme, so just update its trace --- */
233  w = p->value->common.a.decider_wme;
234  if (! w->preference) w->preference = p;
235  } else {
236  w = make_wme (thisAgent, p->id, p->attr, p->value, TRUE);
238  w->preference = p;
239  add_wme_to_wm (thisAgent, w);
240  p->value->common.decider_flag = ALREADY_EXISTING_WME_DECIDER_FLAG;
241  p->value->common.a.decider_wme = w;
242  }
243  }
244 }
245 
247  dl_cons *dc;
248  slot *s;
249 
253  s = static_cast<slot_struct *>(dc->item);
254  free_with_pool (&thisAgent->dl_cons_pool, dc);
257  }
258 }
259 
260 
261 /* **********************************************************************
262 
263  Ownership Calculations
264 
265  Whenever a link is added from one identifier to another (i.e.,
266  (I37 ^x R26)), we call post_link_addition(). This records the link
267  addition and buffers it for later processing. Similarly, whenever a
268  link is removed, we call post_link_removal(), which buffers the
269  removal for later processing. At the end of the phase, we call
270  do_buffered_link_changes() to update the goal stack level of all
271  identifiers, and garbage collect anything that's now disconnected.
272 
273  On each identifier, we maintain a count of how many links there are
274  to it. If the count is decremented to 0, the id must be disconnected,
275  so we can GC it. If the count is decremented but nonzero, we have
276  to walk through WM to see whether it's connected--it could be disconnected
277  but have a positive link count, if there's a circular structure in WM.
278 
279  Goal and impasse identifiers are handled specially. We don't want to
280  GC these even though WM may not have any pointers to them. So instead
281  of the normal link count stuff, we use a special "link" to each goal or
282  impasse id. This special link is added/removed by calling
283  post_link_addition/removal (NIL, id).
284 ********************************************************************** */
285 
286 /* ======================================================================
287 
288  Promotion (Upgrade) Routines
289 
290  The list "promoted_ids" indicates which identifiers need to be
291  promoted at the end of the current phase. On every id, we have a
292  "promotion_level" field indicating the new goal_stack_level to which
293  the id is going to be promoted. When we actually do the promotion,
294  we set the id's level to promotion_level. We also promote anything
295  in the id's transitive closure to the same level, if necessary.
296 ====================================================================== */
297 
298 /* ----------------------------------------------
299  Post a link addition for later processing.
300 ---------------------------------------------- */
301 
302 void post_link_addition (agent* thisAgent, Symbol *from, Symbol *to)
303 {
304 
305 /* --- don't add links to goals/impasses, except the special one
306  (NIL,goal) --- */
307  if ((to->id.isa_goal || to->id.isa_impasse) && from)
308  return;
309 
310  to->id.link_count++;
311 
312 #ifdef DEBUG_LINKS
313  if (from)
314  print_with_symbols (thisAgent, "\nAdding link from %y to %y", from, to);
315  else
316  print_with_symbols (thisAgent, "\nAdding special link to %y", to);
317  print (" (count=%lu)", to->id.link_count);
318 #endif
319 
320  if (!from)
321  return; /* if adding a special link, we're done */
322 
323  /* --- if adding link from same level, ignore it --- */
324  if (from->id.promotion_level == to->id.promotion_level)
325  return;
326 
327  /* --- if adding link from lower to higher, mark higher accordingly --- */
328  if (from->id.promotion_level > to->id.promotion_level) {
330  return;
331  }
332 
333  /* --- otherwise buffer it for later --- */
334  to->id.promotion_level = from->id.promotion_level;
335  symbol_add_ref (to);
336  push (thisAgent, to, thisAgent->promoted_ids);
337 }
338 
339 /* ----------------------------------------------
340  Promote an id and its transitive closure.
341 ---------------------------------------------- */
342 
343 #define promote_if_needed(thisAgent, sym) \
344  { if ((sym)->common.symbol_type==IDENTIFIER_SYMBOL_TYPE) \
345  promote_id_and_tc(thisAgent, sym,new_level); }
346 
347 void promote_id_and_tc (agent* thisAgent, Symbol *id, goal_stack_level new_level) {
348  slot *s;
349  preference *pref;
350  wme *w;
351 
352  /* --- if it's already that high, or is going to be soon, don't bother -- */
353  if (id->id.level <= new_level) return;
354  if (id->id.promotion_level < new_level) return;
355 
356  /* --- update its level, etc. --- */
357  id->id.level = new_level;
358  id->id.promotion_level = new_level;
359  id->id.could_be_a_link_from_below = TRUE;
360 
361  /* --- sanity check --- */
362  if (id->id.isa_goal || id->id.isa_impasse) {
363  char msg[BUFFER_MSG_SIZE];
364  strncpy (msg, "decide.c: Internal error: tried to promote a goal or impasse id\n", BUFFER_MSG_SIZE);
365  msg[BUFFER_MSG_SIZE - 1] = 0; /* ensure null termination */
366  abort_with_fatal_error(thisAgent, msg);
367  /* Note--since we can't promote a goal, we don't have to worry about
368  slot->acceptable_preference_wmes below */
369  }
370 
371  /* --- scan through all preferences and wmes for all slots for this id -- */
372  for (w=id->id.input_wmes; w!=NIL; w=w->next)
373  promote_if_needed (thisAgent, w->value);
374  for (s=id->id.slots; s!=NIL; s=s->next) {
375  for (pref=s->all_preferences; pref!=NIL; pref=pref->all_of_slot_next) {
376  promote_if_needed (thisAgent, pref->value);
377  if (preference_is_binary(pref->type))
378  promote_if_needed (thisAgent, pref->referent);
379  }
380  for (w=s->wmes; w!=NIL; w=w->next)
381  promote_if_needed (thisAgent, w->value);
382  } /* end of for slots loop */
383 }
384 
385 /* ----------------------------------------------
386  Do all buffered promotions.
387 ---------------------------------------------- */
388 
389 void do_promotion (agent* thisAgent) {
390  cons *c;
391  Symbol *to;
392 
393  while (thisAgent->promoted_ids) {
394  c = thisAgent->promoted_ids;
395  to = static_cast<symbol_union *>(c->first);
396  thisAgent->promoted_ids = thisAgent->promoted_ids->rest;
397  free_cons (thisAgent, c);
398  promote_id_and_tc (thisAgent, to, to->id.promotion_level);
399  symbol_remove_ref (thisAgent, to);
400  }
401 }
402 
403 /* ======================================================================
404 
405  Demotion (Downgrade) and Garbage Collection Routines
406 
407  Demotions happen in stages. Post_link_removal() is called from
408  various places; this decrements the link count on an identifier and
409  adds it to the dl_list "ids_with_unknown_level". (While this is going
410  on, link_update_mode is always set to UPDATE_LINKS_NORMALLY.)
411 
412  At the end of the phase, do_demotion() is called. This has three
413  stages:
414  (1) the ids with unknown level whose link count is 0 are moved
415  over to a list of disconnected_ids -- these ids are definitely
416  disconnected and are going to be GC'd
417  (2) We GC the disconnected_ids. While doing this GC, more wmes
418  are removed from WM and more links are removed. For these
419  link removals, if the link count on an id goes to 0, we put
420  it onto disconnected_ids (rather than ids_with_unknown_level).
421  (Here link_update_mode is UPDATE_DISCONNECTED_IDS_LIST.)
422  We keep GC-ing disconnected_ids until none are left.
423  (3) Mark & Walk: If there are still remaining ids_with_unknown_level,
424  we mark each such id and its transitive closure, then walk the
425  goal stack (or parts of it) to find out what's really still
426  connected.
427  (4) For each id now known to be disconnected, we GC it. While doing
428  this GC, more links are removed, but for those, we merely update
429  the link count, nothing else--because we already took the TC of
430  each id in step 3, so we're already certain of what's connected
431  and what's not. (Here link_update_mode is JUST_UPDATE_COUNT.)
432 ====================================================================== */
433 
434 /* ----------------------------------------------
435  Post a link removal for later processing.
436 ---------------------------------------------- */
437 
438 void post_link_removal (agent* thisAgent, Symbol *from, Symbol *to)
439 {
440  dl_cons *dc;
441 
442  /* --- don't remove links to goals/impasses, except the special one
443  (NIL,goal) --- */
444  if ((to->id.isa_goal || to->id.isa_impasse) && from) return;
445 
446  to->id.link_count--;
447 
448 #ifdef DEBUG_LINKS
449  if (from) {
450  print_with_symbols (thisAgent, "\nRemoving link from %y to %y", from, to);
451  print (" (%d to %d)", from->id.level, to->id.level);
452  } else {
453  print_with_symbols (thisAgent, S"\nRemoving special link to %y ", to);
454  print (" (%d)", to->id.level);
455  }
456  print (" (count=%lu)", to->id.link_count);
457 #endif
458 
459  /* --- if a gc is in progress, handle differently --- */
460  if (thisAgent->link_update_mode==JUST_UPDATE_COUNT) return;
461 
463  (to->id.link_count==0)) {
464  if (to->id.unknown_level) {
465  dc = to->id.unknown_level;
466  remove_from_dll (thisAgent->ids_with_unknown_level, dc, next, prev);
467  insert_at_head_of_dll (thisAgent->disconnected_ids, dc, next, prev);
468  } else {
469  symbol_add_ref (to);
470  allocate_with_pool (thisAgent, &thisAgent->dl_cons_pool, &dc);
471  dc->item = to;
472  to->id.unknown_level = dc;
473  insert_at_head_of_dll (thisAgent->disconnected_ids, dc, next, prev);
474  }
475  return;
476  }
477 
478  /* --- if removing a link from a different level, there must be some other
479  link at the same level, so we can ignore this change --- */
480  if (from && (from->id.level != to->id.level)) return;
481 
482  if (! to->id.unknown_level) {
483  symbol_add_ref (to);
484  allocate_with_pool (thisAgent, &thisAgent->dl_cons_pool, &dc);
485  dc->item = to;
486  to->id.unknown_level = dc;
487  insert_at_head_of_dll (thisAgent->ids_with_unknown_level, dc, next, prev);
488  }
489 }
490 
491 /* ----------------------------------------------
492  Garbage collect an identifier. This removes
493  all wmes, input wmes, and preferences for that
494  id from TM.
495 ---------------------------------------------- */
496 
497 void garbage_collect_id (agent* thisAgent, Symbol *id)
498 {
499  slot *s;
500  preference *pref, *next_pref;
501 
502 #ifdef DEBUG_LINKS
503  print_with_symbols (thisAgent, "\n*** Garbage collecting id: %y",id);
504 #endif
505 
506  /* Note--for goal/impasse id's, this does not remove the impasse wme's.
507  This is handled by remove_existing_such-and-such... */
508 
509  /* --- remove any input wmes from the id --- */
510  remove_wme_list_from_wm (thisAgent, id->id.input_wmes, true);
511  id->id.input_wmes = NIL;
512 
513  for (s = id->id.slots; s != NIL; s = s->next)
514  {
515  /* --- remove any existing attribute impasse for the slot --- */
518 
519  /* --- remove all wme's from the slot --- */
520  remove_wme_list_from_wm (thisAgent, s->wmes);
521  s->wmes = NIL;
522 
523  /* --- remove all preferences for the slot --- */
524  pref = s->all_preferences;
525  while (pref)
526  {
527  next_pref = pref->all_of_slot_next;
528  remove_preference_from_tm (thisAgent, pref);
529 
530  /* Note: the call to remove_preference_from_slot handles the removal
531  of acceptable_preference_wmes */
532  pref = next_pref;
533  }
534 
535  mark_slot_for_possible_removal (thisAgent, s);
536  } /* end of for slots loop */
537 }
538 
539 /* ----------------------------------------------
540  During the mark & walk, these variables keep
541  track of the highest goal stack level that
542  any identifier could "fall from" and the lowest
543  level any could "fall to". These are used to
544  delimit a range of goal stack levels that
545  need to be walked. (In many cases, much of
546  the goal stack can be ignored.)
547 ---------------------------------------------- */
548 
549 /* ----------------------------------------------
550  Mark an id and its transitive closure as having
551  an unknown level. Ids are marked by setting
552  id.tc_num to mark_tc_number. The starting id's
553  goal stack level is recorded in
554  level_at_which_marking_started by the caller.
555  The marked ids are added to ids_with_unknown_level.
556 ---------------------------------------------- */
557 
558 inline bool mark_level_unknown_needed(agent* /*thisAgent*/, Symbol* sym)
559 {
560  return ( sym->common.symbol_type == IDENTIFIER_SYMBOL_TYPE );
561 }
562 
563 void mark_id_and_tc_as_unknown_level (agent* thisAgent, Symbol *root) {
564  slot *s;
565  preference *pref;
566  wme *w;
567  dl_cons *dc;
568 
569  Symbol *id;
570 #ifdef USE_MEM_POOL_ALLOCATORS
572 #else
573  symbol_list ids_to_walk;
574 #endif
575  ids_to_walk.push_back( root );
576 
577  while ( !ids_to_walk.empty() )
578  {
579  id = ids_to_walk.back();
580  ids_to_walk.pop_back();
581 
582  /* --- if id is already marked, do nothing --- */
583  if (id->id.tc_num==thisAgent->mark_tc_number) continue;
584 
585  /* --- don't mark anything higher up as disconnected--in order to be higher
586  up, it must have a link to it up there --- */
587  if (id->id.level < thisAgent->level_at_which_marking_started) continue;
588 
589  /* --- mark id, so we won't do it again later --- */
590  id->id.tc_num = thisAgent->mark_tc_number;
591 
592  /* --- update range of goal stack levels we'll need to walk --- */
593  if (id->id.level < thisAgent->highest_level_anything_could_fall_from)
594  thisAgent->highest_level_anything_could_fall_from = id->id.level;
595  if (id->id.level > thisAgent->lowest_level_anything_could_fall_to)
596  thisAgent->lowest_level_anything_could_fall_to = id->id.level;
599 
600  /* --- add id to the set of ids with unknown level --- */
601  if (! id->id.unknown_level) {
602  allocate_with_pool (thisAgent, &thisAgent->dl_cons_pool, &dc);
603  dc->item = id;
604  id->id.unknown_level = dc;
605  insert_at_head_of_dll (thisAgent->ids_with_unknown_level, dc, next, prev);
606  symbol_add_ref (id);
607  }
608 
609  /* -- scan through all preferences and wmes for all slots for this id -- */
610  for (w=id->id.input_wmes; w!=NIL; w=w->next)
611  {
612  if ( mark_level_unknown_needed( thisAgent, w->value ) )
613  {
614  ids_to_walk.push_back( w->value );
615  }
616  }
617 
618  for (s=id->id.slots; s!=NIL; s=s->next)
619  {
620  for (pref=s->all_preferences; pref!=NIL; pref=pref->all_of_slot_next)
621  {
622  if ( mark_level_unknown_needed( thisAgent, pref->value ) )
623  {
624  ids_to_walk.push_back( pref->value );
625  }
626 
627  if (preference_is_binary(pref->type))
628  {
629  if ( mark_level_unknown_needed( thisAgent, pref->referent ) )
630  {
631  ids_to_walk.push_back( pref->referent );
632  }
633  }
634  }
635 
636  if(s->impasse_id)
637  {
638  if ( mark_level_unknown_needed( thisAgent, s->impasse_id ) )
639  {
640  ids_to_walk.push_back( s->impasse_id );
641  }
642  }
643 
644  for (w=s->wmes; w!=NIL; w=w->next)
645  {
646  if ( mark_level_unknown_needed( thisAgent, w->value ) )
647  {
648  ids_to_walk.push_back( w->value );
649  }
650  }
651  } /* end of for slots loop */
652  }
653 }
654 
655 /* ----------------------------------------------
656  After marking the ids with unknown level,
657  we walk various levels of the goal stack,
658  higher level to lower level. If, while doing
659  the walk, we encounter an id marked as having
660  an unknown level, we update its level and
661  remove it from ids_with_unknown_level.
662 ---------------------------------------------- */
663 
664 inline bool level_update_needed(agent* thisAgent, Symbol *sym)
665 {
666  return ( ( sym->common.symbol_type == IDENTIFIER_SYMBOL_TYPE ) && ( sym->id.tc_num != thisAgent->walk_tc_number ) );
667 }
668 
669 void walk_and_update_levels (agent* thisAgent, Symbol *root) {
670  slot *s;
671  preference *pref;
672  wme *w;
673  dl_cons *dc;
674  Symbol *id;
675 
676 #ifdef USE_MEM_POOL_ALLOCATORS
678 #else
679  symbol_list ids_to_walk;
680 #endif
681  ids_to_walk.push_back( root );
682 
683  while ( !ids_to_walk.empty() )
684  {
685  id = ids_to_walk.back();
686  ids_to_walk.pop_back();
687 
688  /* --- mark id so we don't walk it twice --- */
689  id->id.tc_num = thisAgent->walk_tc_number;
690 
691  /* --- if we already know its level, and it's higher up, then exit --- */
692  if ((! id->id.unknown_level) && (id->id.level < thisAgent->walk_level)) continue;
693 
694  /* --- if we didn't know its level before, we do now --- */
695  if (id->id.unknown_level) {
696  dc = id->id.unknown_level;
697  remove_from_dll (thisAgent->ids_with_unknown_level, dc, next, prev);
698  free_with_pool (&thisAgent->dl_cons_pool, dc);
699  symbol_remove_ref (thisAgent, id);
700  id->id.unknown_level = NIL;
701  id->id.level = thisAgent->walk_level;
702  id->id.promotion_level = thisAgent->walk_level;
703  }
704 
705  /* -- scan through all preferences and wmes for all slots for this id -- */
706  for (w=id->id.input_wmes; w!=NIL; w=w->next)
707  {
708  if ( level_update_needed( thisAgent, w->value ) )
709  {
710  ids_to_walk.push_back( w->value );
711  }
712  }
713 
714  for ( s=id->id.slots; s!=NIL; s=s->next )
715  {
716  for ( pref=s->all_preferences; pref!=NIL; pref=pref->all_of_slot_next )
717  {
718  if ( level_update_needed( thisAgent, pref->value ) )
719  {
720  ids_to_walk.push_back( pref->value );
721 
722  if ( preference_is_binary( pref->type ) )
723  {
724  if ( level_update_needed( thisAgent, pref->referent ) )
725  {
726  ids_to_walk.push_back( pref->referent );
727  }
728  }
729  }
730  }
731 
732  if ( s->impasse_id )
733  {
734  if ( level_update_needed( thisAgent, s->impasse_id ) )
735  {
736  ids_to_walk.push_back( s->impasse_id );
737  }
738  }
739 
740  for ( w=s->wmes; w!=NIL; w=w->next )
741  {
742  if ( level_update_needed( thisAgent, w->value ) )
743  {
744  ids_to_walk.push_back( w->value );
745  }
746  }
747  }
748  }
749 }
750 
751 /* ----------------------------------------------
752  Do all buffered demotions and gc's.
753 ---------------------------------------------- */
754 
755 void do_demotion (agent* thisAgent) {
756  Symbol *g, *id;
757  dl_cons *dc, *next_dc;
758 
759  /* --- scan through ids_with_unknown_level, move the ones with link_count==0
760  * over to disconnected_ids --- */
761  for (dc=thisAgent->ids_with_unknown_level; dc!=NIL; dc=next_dc) {
762  next_dc = dc->next;
763  id = static_cast<symbol_union *>(dc->item);
764  if (id->id.link_count==0) {
765  remove_from_dll (thisAgent->ids_with_unknown_level, dc, next, prev);
766  insert_at_head_of_dll (thisAgent->disconnected_ids, dc, next, prev);
767  }
768  }
769 
770  /* --- keep garbage collecting ids until nothing left to gc --- */
772  while (thisAgent->disconnected_ids) {
773  dc = thisAgent->disconnected_ids;
774  thisAgent->disconnected_ids = thisAgent->disconnected_ids->next;
775  id = static_cast<symbol_union *>(dc->item);
776  free_with_pool (&thisAgent->dl_cons_pool, dc);
777  id->id.unknown_level = NIL;
778  garbage_collect_id (thisAgent, id);
779  symbol_remove_ref (thisAgent, id);
780  }
782 
783  /* --- if nothing's left with an unknown level, we're done --- */
784  if (! thisAgent->ids_with_unknown_level) return;
785 
786  /* --- do the mark --- */
789  thisAgent->lowest_level_anything_could_fall_to = -1;
790  thisAgent->mark_tc_number = get_new_tc_number(thisAgent);
791  for (dc=thisAgent->ids_with_unknown_level; dc!=NIL; dc=dc->next) {
792  id = static_cast<symbol_union *>(dc->item);
793  thisAgent->level_at_which_marking_started = id->id.level;
794  mark_id_and_tc_as_unknown_level (thisAgent, id);
795  }
796 
797  /* --- do the walk --- */
798  g = thisAgent->top_goal;
799  while (TRUE) {
800  if (!g) break;
801  if (g->id.level > thisAgent->lowest_level_anything_could_fall_to) break;
802  if (g->id.level >= thisAgent->highest_level_anything_could_fall_from) {
803  thisAgent->walk_level = g->id.level;
804  thisAgent->walk_tc_number = get_new_tc_number(thisAgent);
805  walk_and_update_levels (thisAgent, g);
806  }
807  g = g->id.lower_goal;
808  }
809 
810  /* --- GC anything left with an unknown level after the walk --- */
811  thisAgent->link_update_mode = JUST_UPDATE_COUNT;
812  while (thisAgent->ids_with_unknown_level) {
813  dc = thisAgent->ids_with_unknown_level;
814  thisAgent->ids_with_unknown_level =
815  thisAgent->ids_with_unknown_level->next;
816  id = static_cast<symbol_union *>(dc->item);
817  free_with_pool (&thisAgent->dl_cons_pool, dc);
818  id->id.unknown_level = NIL; /* AGR 640: GAP set to NIL because */
819  /* symbol may still have pointers to it */
820  garbage_collect_id (thisAgent, id);
821  symbol_remove_ref (thisAgent, id);
822  }
824 }
825 
826 /* ------------------------------------------------------------------
827  Do Buffered Link Changes
828 
829  This routine does all the buffered link (ownership) chages, updating
830  the goal stack level on all identifiers and garbage collecting
831  disconnected wmes.
832 ------------------------------------------------------------------ */
833 
834 void do_buffered_link_changes (agent* thisAgent) {
835 
836 #ifndef NO_TIMING_STUFF
837 #ifdef DETAILED_TIMING_STATS
838  soar_process_timer local_timer;
839  local_timer.set_enabled( &( thisAgent->sysparams[ TIMERS_ENABLED ] ) );
840 #endif
841 #endif
842 
843  /* --- if no promotions or demotions are buffered, do nothing --- */
844  if (! (thisAgent->promoted_ids ||
845  thisAgent->ids_with_unknown_level ||
846  thisAgent->disconnected_ids)) return;
847 
848 #ifndef NO_TIMING_STUFF
849 #ifdef DETAILED_TIMING_STATS
850  local_timer.start();
851 #endif
852 #endif
853  do_promotion (thisAgent);
854  do_demotion (thisAgent);
855 #ifndef NO_TIMING_STUFF
856 #ifdef DETAILED_TIMING_STATS
857  local_timer.stop();
858  thisAgent->timers_ownership_cpu_time[thisAgent->current_phase].update(local_timer);
859 #endif
860 #endif
861 }
862 
863 /* **************************************************************************
864 
865  Preference Semantics
866 
867  Run_preference_semantics (slot *s, preference **result_candidates) examines
868  the preferences for a given slot, and returns an impasse type for the
869  slot. The argument "result_candidates" is set to a list of candidate
870  values for the slot--if the returned impasse type is NONE_IMPASSE_TYPE,
871  this is the set of winners; otherwise it is the set of tied, conflicted,
872  or constraint-failured values. This list of values is a list of preferences
873  for those values, linked via the "next_candidate" field on each preference
874  structure. If there is more than one preference for a given value,
875  only one is returned in the result_candidates, with (first) require
876  preferences being preferred over acceptable preferences, and (second)
877  preferences from higher match goals being preferred over those from
878  lower match goals.
879 
880  BUGBUG There is a problem here: since the require/acceptable priority
881  takes precedence over the match goal level priority, it's possible that
882  we could return a require preference from lower in the goal stack than
883  some acceptable preference. If the goal stack gets popped soon
884  afterwards (i.e., before the next time the slot is re-decided, I think),
885  we would be left with a WME still in WM (not GC'd, because of the acceptable
886  preference higher up) but with a trace pointing to a deallocated require
887  preference. This case is very obsure and unlikely to come up, but it
888  could easily cause a core dump or worse.
889 
890  Require_preference_semantics() is a helper function for
891  run_preference_semantics() that is used when there is at least one
892  require preference for the slot.
893 ************************************************************************** */
894 
895 byte require_preference_semantics (agent *thisAgent, slot *s, preference **result_candidates, bool consistency) {
896  preference *p;
897  preference *candidates;
898  Symbol *value;
899 
900  /* --- collect set of required items into candidates list --- */
901  for (p=s->preferences[REQUIRE_PREFERENCE_TYPE]; p!=NIL; p=p->next)
902  p->value->common.decider_flag = NOTHING_DECIDER_FLAG;
903  candidates = NIL;
904  for (p=s->preferences[REQUIRE_PREFERENCE_TYPE]; p!=NIL; p=p->next) {
905  if (p->value->common.decider_flag == NOTHING_DECIDER_FLAG) {
906  p->next_candidate = candidates;
907  candidates = p;
908  /* --- unmark it, in order to prevent it from being added twice --- */
909  p->value->common.decider_flag = CANDIDATE_DECIDER_FLAG;
910  }
911  }
912  *result_candidates = candidates;
913 
914  /* --- if more than one required item, we have a constraint failure --- */
915  if (candidates->next_candidate) return CONSTRAINT_FAILURE_IMPASSE_TYPE;
916 
917  /* --- just one require, check for require-prohibit impasse --- */
918  value = candidates->value;
919  for (p=s->preferences[PROHIBIT_PREFERENCE_TYPE]; p!=NIL; p=p->next)
920  if (p->value == value) return CONSTRAINT_FAILURE_IMPASSE_TYPE;
921 
922  /* --- the lone require is the winner --- */
923  if ( !consistency && candidates && rl_enabled( thisAgent ) )
924  {
925  rl_tabulate_reward_values( thisAgent );
926  exploration_compute_value_of_candidate( thisAgent, candidates, s, 0 );
927  rl_perform_update( thisAgent, candidates->numeric_value, candidates->rl_contribution, s->id );
928  }
929 
930  return NONE_IMPASSE_TYPE;
931 }
932 
933 byte run_preference_semantics (agent* thisAgent, slot *s, preference **result_candidates, bool consistency = false, bool predict = false)
934 {
935  preference *p, *p2, *cand, *prev_cand;
936  Bool match_found, not_all_indifferent, not_all_parallel;
937  preference *candidates;
938 
939  /* --- if the slot has no preferences at all, things are trivial --- */
940  if (!s->all_preferences)
941  {
942  if (! s->isa_context_slot) mark_slot_for_possible_removal (thisAgent, s);
943  *result_candidates = NIL;
944  return NONE_IMPASSE_TYPE;
945  }
946 
947  // if this is the true decision slot and selection has been made, attempt force selection
948  if ( s->isa_context_slot && !consistency)
949  {
950  if ( select_get_operator( thisAgent ) != NULL )
951  {
952  preference *force_result = select_force( thisAgent, s->preferences[ACCEPTABLE_PREFERENCE_TYPE], !predict );
953 
954  if ( force_result )
955  {
956  force_result->next_candidate = NIL;
957  *result_candidates = force_result;
958 
959  if ( !predict && rl_enabled( thisAgent ) )
960  {
961  rl_tabulate_reward_values( thisAgent );
962  exploration_compute_value_of_candidate( thisAgent, force_result, s, 0 );
963  rl_perform_update( thisAgent, force_result->numeric_value, force_result->rl_contribution, s->id );
964  }
965 
966  return NONE_IMPASSE_TYPE;
967  }
968  }
969  }
970 
971  /* === Requires === */
973  return require_preference_semantics (thisAgent, s, result_candidates, consistency);
974  }
975 
976  /* === Acceptables, Prohibits, Rejects === */
977 
978  /* --- mark everything that's acceptable, then unmark the prohibited
979  and rejected items --- */
980  for (p=s->preferences[ACCEPTABLE_PREFERENCE_TYPE]; p!=NIL; p=p->next)
981  p->value->common.decider_flag = CANDIDATE_DECIDER_FLAG;
982  for (p=s->preferences[PROHIBIT_PREFERENCE_TYPE]; p!=NIL; p=p->next)
983  p->value->common.decider_flag = NOTHING_DECIDER_FLAG;
984  for (p=s->preferences[REJECT_PREFERENCE_TYPE]; p!=NIL; p=p->next)
985  p->value->common.decider_flag = NOTHING_DECIDER_FLAG;
986 
987  /* --- now scan through acceptables and build the list of candidates --- */
988  candidates = NIL;
989  for (p=s->preferences[ACCEPTABLE_PREFERENCE_TYPE]; p!=NIL; p=p->next) {
990  if (p->value->common.decider_flag == CANDIDATE_DECIDER_FLAG) {
991  p->next_candidate = candidates;
992  candidates = p;
993  /* --- unmark it, in order to prevent it from being added twice --- */
994  p->value->common.decider_flag = NOTHING_DECIDER_FLAG;
995  }
996  }
997 
998  if (!s->isa_context_slot) {
999  *result_candidates = candidates;
1000  return NONE_IMPASSE_TYPE;
1001  }
1002 
1003  /* === If there are only 0 or 1 candidates, we're done === */
1004  if ((!candidates) || (! candidates->next_candidate)) {
1005  *result_candidates = candidates;
1006 
1007  if ( !consistency && rl_enabled( thisAgent ) && candidates )
1008  {
1009  // perform update here for just one candidate
1010  rl_tabulate_reward_values( thisAgent );
1011  exploration_compute_value_of_candidate( thisAgent, candidates, s, 0 );
1012  rl_perform_update( thisAgent, candidates->numeric_value, candidates->rl_contribution, s->id );
1013  }
1014 
1015  return NONE_IMPASSE_TYPE;
1016  }
1017 
1018  /* === Better/Worse === */
1019 #define NEW_PREFERENCES_SCHEME 1 // bug 234
1020 #if(NEW_PREFERENCES_SCHEME == 1)
1021  // new algorithm:
1022  // for each j > k:
1023  // if j is (candidate or conflicted) and k is (candidate or conflicted):
1024  // if one of (j, k) is candidate:
1025  // candidate -= k, if not already true
1026  // conflicted += k, if not already true
1027  // for each j < k:
1028  // if j is (candidate or conflicted) and k is (candidate or conflicted):
1029  // if one of (j, k) is candidate:
1030  // candidate -= j, if not already true
1031  // conflicted += j, if not already true
1032  // if no remaning candidates:
1033  // conflict impasse using conflicted as candidates
1034  // else
1035  // pass on candidates to next filter
1037  {
1038  Symbol *j, *k;
1039 
1040  // initialize
1041  for (p=s->preferences[BETTER_PREFERENCE_TYPE]; p!=NIL; p=p->next)
1042  {
1043  p->value->common.decider_flag = NOTHING_DECIDER_FLAG;
1044  p->referent->common.decider_flag = NOTHING_DECIDER_FLAG;
1045  }
1046  for (p=s->preferences[WORSE_PREFERENCE_TYPE]; p!=NIL; p=p->next)
1047  {
1048  p->value->common.decider_flag = NOTHING_DECIDER_FLAG;
1049  p->referent->common.decider_flag = NOTHING_DECIDER_FLAG;
1050  }
1051  for (cand=candidates; cand!=NIL; cand=cand->next_candidate) {
1052  cand->value->common.decider_flag = CANDIDATE_DECIDER_FLAG;
1053  }
1054 
1055  for (p=s->preferences[BETTER_PREFERENCE_TYPE]; p!=NIL; p=p->next)
1056  {
1057  j = p->value;
1058  k = p->referent;
1059  if (j==k)
1060  continue;
1061  if (j->common.decider_flag && k->common.decider_flag)
1062  {
1063  if (j->common.decider_flag == CANDIDATE_DECIDER_FLAG || k->common.decider_flag == CANDIDATE_DECIDER_FLAG)
1064  k->common.decider_flag = CONFLICTED_DECIDER_FLAG;
1065  }
1066  }
1067 
1068  for (p=s->preferences[WORSE_PREFERENCE_TYPE]; p!=NIL; p=p->next)
1069  {
1070  j = p->value;
1071  k = p->referent;
1072  if (j==k)
1073  continue;
1074  if (j->common.decider_flag && k->common.decider_flag)
1075  {
1076  if (j->common.decider_flag == CANDIDATE_DECIDER_FLAG || k->common.decider_flag == CANDIDATE_DECIDER_FLAG)
1077  j->common.decider_flag = CONFLICTED_DECIDER_FLAG;
1078  }
1079  }
1080 
1081  /* --- now scan through candidates list, look for remaining candidates --- */
1082  for (cand=candidates; cand!=NIL; cand=cand->next_candidate)
1083  {
1084  if (cand->value->common.decider_flag==CANDIDATE_DECIDER_FLAG)
1085  break;
1086  }
1087  if (!cand) {
1088  /* --- collect conflicted candidates into new candidates list --- */
1089  prev_cand = NIL;
1090  cand = candidates;
1091  while (cand)
1092  {
1093  if (cand->value->common.decider_flag != CONFLICTED_DECIDER_FLAG)
1094  {
1095  if (prev_cand)
1096  prev_cand->next_candidate = cand->next_candidate;
1097  else
1098  candidates = cand->next_candidate;
1099  }
1100  else
1101  {
1102  prev_cand = cand;
1103  }
1104  cand = cand->next_candidate;
1105  }
1106  *result_candidates = candidates;
1107  return CONFLICT_IMPASSE_TYPE;
1108  }
1109  /* --- non-conflict candidates found, remove conflicts from candidates --- */
1110  prev_cand = NIL;
1111  cand = candidates;
1112  while (cand)
1113  {
1114  if (cand->value->common.decider_flag == CONFLICTED_DECIDER_FLAG)
1115  {
1116  if (prev_cand)
1117  prev_cand->next_candidate = cand->next_candidate;
1118  else
1119  candidates = cand->next_candidate;
1120  }
1121  else
1122  {
1123  prev_cand = cand;
1124  }
1125  cand = cand->next_candidate;
1126  }
1127  }
1128 #else // !NEW_PREFERENCES_SCHEME
1131  Symbol *j, *k;
1132 
1133  /* -------------------- Algorithm to find conflicted set:
1134  conflicted = {}
1135  for each (j > k):
1136  if j is (candidate or conflicted)
1137  and k is (candidate or conflicted)
1138  and at least one of j,k is a candidate
1139  then if (k > j) or (j < k) then
1140  conflicted += j, if not already true
1141  conflicted += k, if not already true
1142  candidate -= j, if not already true
1143  candidate -= k, if not already true
1144  for each (j < k):
1145  if j is (candidate or conflicted)
1146  and k is (candidate or conflicted)
1147  and at least one of j,k is a candidate
1148  then if (k < j)
1149  then
1150  conflicted += j, if not already true
1151  conflicted += k, if not already true
1152  candidate -= j, if not already true
1153  candidate -= k, if not already true
1154  ----------------------- */
1155 
1156  for (p=s->preferences[BETTER_PREFERENCE_TYPE]; p!=NIL; p=p->next) {
1157  p->value->common.decider_flag = NOTHING_DECIDER_FLAG;
1158  p->referent->common.decider_flag = NOTHING_DECIDER_FLAG;
1159  }
1160  for (p=s->preferences[WORSE_PREFERENCE_TYPE]; p!=NIL; p=p->next) {
1161  p->value->common.decider_flag = NOTHING_DECIDER_FLAG;
1162  p->referent->common.decider_flag = NOTHING_DECIDER_FLAG;
1163  }
1164  for (cand=candidates; cand!=NIL; cand=cand->next_candidate) {
1165  cand->value->common.decider_flag = CANDIDATE_DECIDER_FLAG;
1166  }
1167  for (p=s->preferences[BETTER_PREFERENCE_TYPE]; p!=NIL; p=p->next) {
1168  j = p->value;
1169  k = p->referent;
1170  if (j==k) continue;
1171  if (j->common.decider_flag && k->common.decider_flag) {
1172  if(k->common.decider_flag != CONFLICTED_DECIDER_FLAG)
1173  k->common.decider_flag = FORMER_CANDIDATE_DECIDER_FLAG;
1174  if ((j->common.decider_flag!=CONFLICTED_DECIDER_FLAG) ||
1175  (k->common.decider_flag!=CONFLICTED_DECIDER_FLAG)) {
1176  for (p2=s->preferences[BETTER_PREFERENCE_TYPE]; p2; p2=p2->next)
1177  if ((p2->value==k)&&(p2->referent==j)) {
1178  j->common.decider_flag = CONFLICTED_DECIDER_FLAG;
1179  k->common.decider_flag = CONFLICTED_DECIDER_FLAG;
1180  break;
1181  }
1182  for (p2=s->preferences[WORSE_PREFERENCE_TYPE]; p2; p2=p2->next)
1183  if ((p2->value==j)&&(p2->referent==k)) {
1184  j->common.decider_flag = CONFLICTED_DECIDER_FLAG;
1185  k->common.decider_flag = CONFLICTED_DECIDER_FLAG;
1186  break;
1187  }
1188  }
1189  }
1190  }
1191  for (p=s->preferences[WORSE_PREFERENCE_TYPE]; p!=NIL; p=p->next) {
1192  j = p->value;
1193  k = p->referent;
1194  if (j==k) continue;
1195  if (j->common.decider_flag && k->common.decider_flag) {
1196  if(j->common.decider_flag != CONFLICTED_DECIDER_FLAG)
1197  j->common.decider_flag = FORMER_CANDIDATE_DECIDER_FLAG;
1198  if ((j->common.decider_flag!=CONFLICTED_DECIDER_FLAG) ||
1199  (k->common.decider_flag!=CONFLICTED_DECIDER_FLAG)) {
1200  for (p2=s->preferences[WORSE_PREFERENCE_TYPE]; p2; p2=p2->next)
1201  if ((p2->value==k)&&(p2->referent==j)) {
1202  j->common.decider_flag = CONFLICTED_DECIDER_FLAG;
1203  k->common.decider_flag = CONFLICTED_DECIDER_FLAG;
1204  break;
1205  }
1206  }
1207  }
1208  }
1209 
1210  /* --- now scan through candidates list, look for conflicted stuff --- */
1211  for (cand=candidates; cand!=NIL; cand=cand->next_candidate)
1212  if (cand->value->common.decider_flag==CONFLICTED_DECIDER_FLAG) break;
1213  if (cand) {
1214  /* --- collect conflicted candidates into new candidates list --- */
1215  prev_cand = NIL;
1216  cand = candidates;
1217  while (cand) {
1218  if (cand->value->common.decider_flag != CONFLICTED_DECIDER_FLAG) {
1219  if (prev_cand)
1220  prev_cand->next_candidate = cand->next_candidate;
1221  else
1222  candidates = cand->next_candidate;
1223  } else {
1224  prev_cand = cand;
1225  }
1226  cand = cand->next_candidate;
1227  }
1228  *result_candidates = candidates;
1229  return CONFLICT_IMPASSE_TYPE;
1230  }
1231  /* --- no conflicts found, remove former_candidates from candidates --- */
1232  prev_cand = NIL;
1233  cand = candidates;
1234  while (cand) {
1235  if (cand->value->common.decider_flag == FORMER_CANDIDATE_DECIDER_FLAG) {
1236  if (prev_cand)
1237  prev_cand->next_candidate = cand->next_candidate;
1238  else
1239  candidates = cand->next_candidate;
1240  } else {
1241  prev_cand = cand;
1242  }
1243  cand = cand->next_candidate;
1244  }
1245  }
1246 #endif // !NEW_PREFERENCES_SCHEME
1247 
1248  /* === Bests === */
1250  for (cand=candidates; cand!=NIL; cand=cand->next_candidate)
1251  cand->value->common.decider_flag = NOTHING_DECIDER_FLAG;
1252  for (p=s->preferences[BEST_PREFERENCE_TYPE]; p!=NIL; p=p->next)
1253  p->value->common.decider_flag = BEST_DECIDER_FLAG;
1254  prev_cand = NIL;
1255  for (cand=candidates; cand!=NIL; cand=cand->next_candidate)
1256  if (cand->value->common.decider_flag == BEST_DECIDER_FLAG) {
1257  if (prev_cand)
1258  prev_cand->next_candidate = cand;
1259  else
1260  candidates = cand;
1261  prev_cand = cand;
1262  }
1263  if (prev_cand) prev_cand->next_candidate = NIL;
1264  }
1265 
1266  /* === Worsts === */
1268  for (cand=candidates; cand!=NIL; cand=cand->next_candidate)
1269  cand->value->common.decider_flag = NOTHING_DECIDER_FLAG;
1270  for (p=s->preferences[WORST_PREFERENCE_TYPE]; p!=NIL; p=p->next)
1271  p->value->common.decider_flag = WORST_DECIDER_FLAG;
1272  prev_cand = NIL;
1273  for (cand=candidates; cand!=NIL; cand=cand->next_candidate)
1274  if (cand->value->common.decider_flag != WORST_DECIDER_FLAG) {
1275  if (prev_cand)
1276  prev_cand->next_candidate = cand;
1277  else
1278  candidates = cand;
1279  prev_cand = cand;
1280  }
1281  if (prev_cand) prev_cand->next_candidate = NIL;
1282  }
1283 
1284  /* === If there are only 0 or 1 candidates, we're done === */
1285  if ( !candidates || !candidates->next_candidate )
1286  {
1287  *result_candidates = candidates;
1288 
1289  if ( !consistency && rl_enabled( thisAgent ) && candidates )
1290  {
1291  // perform update here for just one candidate
1292  rl_tabulate_reward_values( thisAgent );
1293  exploration_compute_value_of_candidate( thisAgent, candidates, s, 0 );
1294  rl_perform_update( thisAgent, candidates->numeric_value, candidates->rl_contribution, s->id );
1295  }
1296 
1297  return NONE_IMPASSE_TYPE;
1298  }
1299 
1300  /* === Indifferents === */
1301  for (cand=candidates; cand!=NIL; cand=cand->next_candidate)
1302  cand->value->common.decider_flag = NOTHING_DECIDER_FLAG;
1304  p->value->common.decider_flag = UNARY_INDIFFERENT_DECIDER_FLAG;
1305 
1306 
1308  p->value->common.decider_flag = UNARY_INDIFFERENT_CONSTANT_DECIDER_FLAG;
1309 
1313  p->value->common.decider_flag = UNARY_INDIFFERENT_CONSTANT_DECIDER_FLAG;
1314 
1315 
1316 
1317  not_all_indifferent = FALSE;
1318  for (cand=candidates; cand!=NIL; cand=cand->next_candidate)
1319  {
1320  if (cand->value->common.decider_flag==UNARY_INDIFFERENT_DECIDER_FLAG)
1321  continue;
1322  else if ( cand->value->common.decider_flag==UNARY_INDIFFERENT_CONSTANT_DECIDER_FLAG )
1323  continue;
1324 
1325  /* --- check whether cand is binary indifferent to each other one --- */
1326  for (p=candidates; p!=NIL; p=p->next_candidate) {
1327  if (p==cand) continue;
1328  match_found = FALSE;
1330  p2=p2->next)
1331  if ( ((p2->value==cand->value)&&(p2->referent==p->value)) ||
1332  ((p2->value==p->value)&&(p2->referent==cand->value)) ) {
1333  match_found = TRUE;
1334  break;
1335  }
1336  if (!match_found) {
1337  not_all_indifferent = TRUE;
1338  break;
1339  }
1340  } /* end of for p loop */
1341  if (not_all_indifferent) break;
1342  } /* end of for cand loop */
1343 
1344  if ( !not_all_indifferent )
1345  {
1346  if ( !consistency )
1347  {
1348  (*result_candidates) = exploration_choose_according_to_policy( thisAgent, s, candidates );
1349  (*result_candidates)->next_candidate = NIL;
1350  }
1351  else
1352  *result_candidates = candidates;
1353 
1354  return NONE_IMPASSE_TYPE;
1355  }
1356 
1357  /* --- items not all indifferent; for context slots this gives a tie --- */
1358  if (s->isa_context_slot) {
1359  *result_candidates = candidates;
1360  return TIE_IMPASSE_TYPE;
1361  }
1362 
1363  /* === Parallels === */
1364  for (cand=candidates; cand!=NIL; cand=cand->next_candidate)
1365  cand->value->common.decider_flag = NOTHING_DECIDER_FLAG;
1366  for (p=s->preferences[UNARY_PARALLEL_PREFERENCE_TYPE]; p; p=p->next)
1367  p->value->common.decider_flag = UNARY_PARALLEL_DECIDER_FLAG;
1368  not_all_parallel = FALSE;
1369  for (cand=candidates; cand!=NIL; cand=cand->next_candidate) {
1370  /* --- if cand is unary parallel, it's fine --- */
1371  if (cand->value->common.decider_flag==UNARY_PARALLEL_DECIDER_FLAG)
1372  continue;
1373  /* --- check whether cand is binary parallel to each other candidate --- */
1374  for (p=candidates; p!=NIL; p=p->next_candidate) {
1375  if (p==cand) continue;
1376  match_found = FALSE;
1378  p2=p2->next)
1379  if ( ((p2->value==cand->value)&&(p2->referent==p->value)) ||
1380  ((p2->value==p->value)&&(p2->referent==cand->value)) ) {
1381  match_found = TRUE;
1382  break;
1383  }
1384  if (!match_found) {
1385  not_all_parallel = TRUE;
1386  break;
1387  }
1388  } /* end of for p loop */
1389  if (not_all_parallel) break;
1390  } /* end of for cand loop */
1391 
1392  *result_candidates = candidates;
1393 
1394  if (! not_all_parallel) {
1395  /* --- items are all parallel, so return them all --- */
1396  return NONE_IMPASSE_TYPE;
1397  }
1398 
1399  /* --- otherwise we have a tie --- */
1400  return TIE_IMPASSE_TYPE;
1401 }
1402 
1403 
1405 {
1406  return run_preference_semantics( thisAgent, s, result_candidates, true );
1407 }
1408 
1409 /* **************************************************************************
1410 
1411  Decider and Impasser Routines
1412 
1413 ************************************************************************** */
1414 
1415 /* ------------------------------------------------------------------
1416  Add Impasse Wme
1417 
1418  This creates a new wme and adds it to the given impasse object.
1419  "Id" indicates the goal/impasse id; (id ^attr value) is the impasse
1420  wme to be added. The "preference" argument indicates the preference
1421  (if non-NIL) for backtracing.
1422 ------------------------------------------------------------------ */
1423 
1424 void add_impasse_wme (agent* thisAgent, Symbol *id, Symbol *attr, Symbol *value, preference *p) {
1425  wme *w;
1426 
1427  w = make_wme (thisAgent, id, attr, value, FALSE);
1428  insert_at_head_of_dll (id->id.impasse_wmes, w, next, prev);
1429  w->preference = p;
1430  add_wme_to_wm (thisAgent, w);
1431 }
1432 
1433 /* ------------------------------------------------------------------
1434  Create New Impasse
1435 
1436  This creates a new impasse, returning its identifier. The caller is
1437  responsible for filling in either id->isa_impasse or id->isa_goal,
1438  and all the extra stuff for goal identifiers.
1439 ------------------------------------------------------------------ */
1440 
1441 Symbol *create_new_impasse (agent* thisAgent, Bool isa_goal, Symbol *object, Symbol *attr,
1442  byte impasse_type, goal_stack_level level) {
1443  Symbol *id;
1444 
1445  id = make_new_identifier (thisAgent, (isa_goal ? 'S' : 'I'), level);
1446  post_link_addition (thisAgent, NIL, id); /* add the special link */
1447 
1448  add_impasse_wme (thisAgent, id, thisAgent->type_symbol, isa_goal ? thisAgent->state_symbol : thisAgent->impasse_symbol,
1449  NIL);
1450 
1451  if (isa_goal)
1452  {
1453  add_impasse_wme (thisAgent, id, thisAgent->superstate_symbol, object, NIL);
1454  id->id.reward_header = make_new_identifier( thisAgent, 'R', level );
1455  soar_module::add_module_wme( thisAgent, id, thisAgent->rl_sym_reward_link, id->id.reward_header );
1456 
1457  id->id.epmem_header = make_new_identifier( thisAgent, 'E', level );
1458  soar_module::add_module_wme( thisAgent, id, thisAgent->epmem_sym, id->id.epmem_header );
1459  id->id.epmem_cmd_header = make_new_identifier( thisAgent, 'C', level );
1460  soar_module::add_module_wme( thisAgent, id->id.epmem_header, thisAgent->epmem_sym_cmd, id->id.epmem_cmd_header );
1461  id->id.epmem_result_header = make_new_identifier( thisAgent, 'R', level );
1463 
1464  {
1465  int64_t my_time = static_cast<int64_t>( thisAgent->epmem_stats->time->get_value() );
1466  if ( my_time == 0 )
1467  {
1468  // special case: pre-initialization
1469  my_time = 1;
1470  }
1471 
1472  Symbol* my_time_sym = make_int_constant( thisAgent, my_time );
1473  id->id.epmem_time_wme = soar_module::add_module_wme( thisAgent, id->id.epmem_header, thisAgent->epmem_sym_present_id, my_time_sym );
1474  symbol_remove_ref( thisAgent, my_time_sym );
1475  }
1476 
1477  id->id.smem_header = make_new_identifier( thisAgent, 'S', level );
1478  soar_module::add_module_wme( thisAgent, id, thisAgent->smem_sym, id->id.smem_header );
1479  id->id.smem_cmd_header = make_new_identifier( thisAgent, 'C', level );
1480  soar_module::add_module_wme( thisAgent, id->id.smem_header, thisAgent->smem_sym_cmd, id->id.smem_cmd_header );
1481  id->id.smem_result_header = make_new_identifier( thisAgent, 'R', level );
1483 
1484  }
1485  else
1486  add_impasse_wme (thisAgent, id, thisAgent->object_symbol, object, NIL);
1487 
1488  if (attr) add_impasse_wme (thisAgent, id, thisAgent->attribute_symbol, attr, NIL);
1489 
1490  switch (impasse_type) {
1491  case NONE_IMPASSE_TYPE:
1492  break; /* this happens only when creating the top goal */
1494  add_impasse_wme (thisAgent, id, thisAgent->impasse_symbol, thisAgent->constraint_failure_symbol, NIL);
1495  add_impasse_wme (thisAgent, id, thisAgent->choices_symbol, thisAgent->none_symbol, NIL);
1496  break;
1497  case CONFLICT_IMPASSE_TYPE:
1498  add_impasse_wme (thisAgent, id, thisAgent->impasse_symbol, thisAgent->conflict_symbol, NIL);
1499  add_impasse_wme (thisAgent, id, thisAgent->choices_symbol, thisAgent->multiple_symbol, NIL);
1500  break;
1501  case TIE_IMPASSE_TYPE:
1502  add_impasse_wme (thisAgent, id, thisAgent->impasse_symbol, thisAgent->tie_symbol, NIL);
1503  add_impasse_wme (thisAgent, id, thisAgent->choices_symbol, thisAgent->multiple_symbol, NIL);
1504  break;
1506  add_impasse_wme (thisAgent, id, thisAgent->impasse_symbol, thisAgent->no_change_symbol, NIL);
1507  add_impasse_wme (thisAgent, id, thisAgent->choices_symbol, thisAgent->none_symbol, NIL);
1508  break;
1509  }
1510  return id;
1511 }
1512 
1513 /* ------------------------------------------------------------------
1514  Create/Remove Attribute Impasse for Slot
1515 
1516  These routines create and remove an attribute impasse for a given
1517  slot.
1518 ------------------------------------------------------------------ */
1519 
1520 void create_new_attribute_impasse_for_slot (agent* thisAgent, slot *s, byte impasse_type) {
1521  Symbol *id;
1522 
1523  s->impasse_type = impasse_type;
1524  id = create_new_impasse (thisAgent, FALSE, s->id, s->attr, impasse_type,
1526  s->impasse_id = id;
1527  id->id.isa_impasse = TRUE;
1528 
1529  soar_invoke_callbacks(thisAgent,
1531  static_cast<soar_call_data>(s) );
1532 }
1533 
1535  Symbol *id;
1536 
1537  soar_invoke_callbacks(thisAgent,
1539  static_cast<soar_call_data>(s) );
1540 
1541  id = s->impasse_id;
1542  s->impasse_id = NIL;
1544  remove_wme_list_from_wm (thisAgent, id->id.impasse_wmes);
1545  id->id.impasse_wmes = NIL;
1546  post_link_removal (thisAgent, NIL, id); /* remove the special link */
1547  symbol_remove_ref (thisAgent, id);
1548 }
1549 
1550 /* ------------------------------------------------------------------
1551  Fake Preferences for Goal ^Item Augmentations
1552 
1553  When we backtrace through a (goal ^item) augmentation, we want
1554  to backtrace to the acceptable preference wme in the supercontext
1555  corresponding to that ^item. A slick way to do this automagically
1556  is to set the backtracing preference pointer on the (goal ^item)
1557  wme to be a "fake" preference for a "fake" instantiation. The
1558  instantiation has as its LHS a list of one condition, which matched
1559  the acceptable preference wme in the supercontext.
1560 
1561  Make_fake_preference_for_goal_item() builds such a fake preference
1562  and instantiation, given a pointer to the supergoal and the
1563  acceptable/require preference for the value, and returns a pointer
1564  to the fake preference. *** for Soar 8.3, we changed the fake
1565  preference to be ACCEPTABLE instead of REQUIRE. This could
1566  potentially break some code, but it avoids the BUGBUG condition
1567  that can occur when you have a REQUIRE lower in the stack than an
1568  ACCEPTABLE but the goal stack gets popped while the WME backtrace
1569  still points to the REQUIRE, instead of the higher ACCEPTABLE.
1570  See the section above on Preference Semantics. It also allows
1571  the GDS to backtrace through ^items properly.
1572 
1573  Remove_fake_preference_for_goal_item() is called to clean up the
1574  fake stuff once the (goal ^item) wme is no longer needed.
1575 ------------------------------------------------------------------ */
1576 
1578  Symbol *goal,
1579  preference *cand) {
1580  slot *s;
1581  wme *ap_wme;
1582  instantiation *inst;
1583  preference *pref;
1584  condition *cond;
1585 
1586  /* --- find the acceptable preference wme we want to backtrace to --- */
1587  s = cand->slot;
1588  for (ap_wme=s->acceptable_preference_wmes; ap_wme!=NIL; ap_wme=ap_wme->next)
1589  if (ap_wme->value==cand->value) break;
1590  if (!ap_wme) {
1591  char msg[BUFFER_MSG_SIZE];
1592  strncpy (msg,
1593  "decide.c: Internal error: couldn't find acceptable pref wme\n", BUFFER_MSG_SIZE);
1594  msg[BUFFER_MSG_SIZE - 1] = 0; /* ensure null termination */
1595  abort_with_fatal_error(thisAgent, msg);
1596  }
1597  /* --- make the fake preference --- */
1598  /* kjc: here's where we changed REQUIRE to ACCEPTABLE */
1599  pref = make_preference (thisAgent, ACCEPTABLE_PREFERENCE_TYPE, goal, thisAgent->item_symbol,
1600  cand->value, NIL);
1601  symbol_add_ref (pref->id);
1602  symbol_add_ref (pref->attr);
1603  symbol_add_ref (pref->value);
1605  all_of_goal_next, all_of_goal_prev);
1606  pref->on_goal_list = TRUE;
1607  preference_add_ref (pref);
1608  /* --- make the fake instantiation --- */
1609  allocate_with_pool (thisAgent, &thisAgent->instantiation_pool, &inst);
1610  pref->inst = inst;
1611  pref->inst_next = pref->inst_prev = NIL;
1612  inst->preferences_generated = pref;
1613  inst->prod = NIL;
1614  inst->next = inst->prev = NIL;
1615  inst->rete_token = NIL;
1616  inst->rete_wme = NIL;
1617  inst->match_goal = goal;
1618  inst->match_goal_level = goal->id.level;
1619  inst->reliable = true;
1620  inst->backtrace_number = 0;
1621  inst->in_ms = FALSE;
1622  /* --- make the fake condition --- */
1623  allocate_with_pool (thisAgent, &thisAgent->condition_pool, &cond);
1624  cond->type = POSITIVE_CONDITION;
1625  cond->next = cond->prev = NIL;
1626  inst->top_of_instantiated_conditions = cond;
1627  inst->bottom_of_instantiated_conditions = cond;
1628  inst->nots = NIL;
1629  cond->data.tests.id_test = make_equality_test (ap_wme->id);
1630  cond->data.tests.attr_test = make_equality_test (ap_wme->attr);
1631  cond->data.tests.value_test = make_equality_test (ap_wme->value);
1633  cond->bt.wme_ = ap_wme;
1634  #ifdef DO_TOP_LEVEL_REF_CTS
1635  wme_add_ref (ap_wme);
1636  #else
1637  if (inst->match_goal_level > TOP_GOAL_LEVEL) wme_add_ref (ap_wme);
1638  #endif
1639  cond->bt.level = ap_wme->id->id.level;
1640  cond->bt.trace = NIL;
1641  cond->bt.prohibits = NIL;
1642  /* --- return the fake preference --- */
1643  return pref;
1644 }
1645 
1647  preference_remove_ref (thisAgent, pref); /* everything else happens automatically */
1648 }
1649 
1650 /* ------------------------------------------------------------------
1651  Update Impasse Items
1652 
1653  This routine updates the set of ^item wmes on a goal or attribute
1654  impasse. It takes the identifier of the goal/impasse, and a list
1655  of preferences (linked via the "next_candidate" field) for the new
1656  set of items that should be there.
1657 
1658  NLD 11/11: using this same basic framework to maintain a parallel
1659  list for those candidates that do not have numeric preferences.
1660 ------------------------------------------------------------------ */
1661 
1662 void update_impasse_items (agent* thisAgent, Symbol *id, preference *items)
1663 {
1664  enum item_types { regular, numeric };
1665 
1666  wme *w, *next_w;
1667  preference *cand;
1668  preference *bt_pref;
1669  unsigned int item_count;
1670  Symbol* loop_sym = NULL;
1671  Symbol* loop_count_sym = NULL;
1672  Symbol* count_sym = NULL;
1673 
1674  for ( int it=regular; it<=numeric; it++ )
1675  {
1676  if ( it == regular )
1677  {
1678  loop_sym = thisAgent->item_symbol;
1679  loop_count_sym = thisAgent->item_count_symbol;
1680  }
1681  else
1682  {
1683  loop_sym = thisAgent->non_numeric_symbol;
1684  loop_count_sym = thisAgent->non_numeric_count_symbol;
1685  }
1686 
1687  // reset flags on existing items to NOTHING
1688  for ( w=id->id.impasse_wmes; w!=NIL; w=w->next )
1689  if ( w->attr == loop_sym )
1690  w->value->common.decider_flag = NOTHING_DECIDER_FLAG;
1691 
1692  // reset flags on all items as CANDIDATEs
1693  for ( cand=items; cand!=NIL; cand=cand->next_candidate )
1694  cand->value->common.decider_flag = CANDIDATE_DECIDER_FLAG;
1695 
1696  // if numeric, block out candidates with numeric
1697  if ( ( it == numeric ) && items )
1698  {
1699  for ( cand=items->slot->preferences[NUMERIC_INDIFFERENT_PREFERENCE_TYPE]; cand; cand=cand->next )
1700  cand->value->common.decider_flag = NOTHING_DECIDER_FLAG;
1701  }
1702 
1703  // count up candidates (used for count WME)
1704  item_count = 0;
1705  for ( cand=items; cand!=NIL; cand=cand->next_candidate )
1706  if ( cand->value->common.decider_flag == CANDIDATE_DECIDER_FLAG )
1707  item_count++;
1708 
1709  // for each existing item: if supposed to be there, ALREADY EXISTING; otherwise remove
1710  w = id->id.impasse_wmes;
1711  while ( w )
1712  {
1713  next_w = w->next;
1714  if ( w->attr == loop_sym )
1715  {
1716  if ( w->value->common.decider_flag==CANDIDATE_DECIDER_FLAG )
1717  {
1718  w->value->common.decider_flag = ALREADY_EXISTING_WME_DECIDER_FLAG;
1719  w->value->common.a.decider_wme = w; // so we can update the pref later
1720  }
1721  else
1722  {
1723  remove_from_dll( id->id.impasse_wmes, w, next, prev );
1724 
1725  if ( id->id.isa_goal )
1727 
1728  remove_wme_from_wm( thisAgent, w );
1729  }
1730  }
1731  else if ( w->attr == loop_count_sym )
1732  {
1733  remove_from_dll( id->id.impasse_wmes, w, next, prev );
1734  remove_wme_from_wm( thisAgent, w );
1735  }
1736 
1737  w = next_w;
1738  }
1739 
1740  // for each desired item: if doesn't ALREADY_EXIST, add it
1741  for ( cand=items; cand!=NIL; cand=cand->next_candidate )
1742  {
1743  // takes care of numerics
1744  if ( cand->value->common.decider_flag == NOTHING_DECIDER_FLAG )
1745  continue;
1746 
1747  if (id->id.isa_goal)
1748  bt_pref = make_fake_preference_for_goal_item( thisAgent, id, cand );
1749  else
1750  bt_pref = cand;
1751 
1752  if ( cand->value->common.decider_flag == ALREADY_EXISTING_WME_DECIDER_FLAG )
1753  {
1754  if ( id->id.isa_goal )
1755  remove_fake_preference_for_goal_item( thisAgent, cand->value->common.a.decider_wme->preference );
1756 
1757  cand->value->common.a.decider_wme->preference = bt_pref;
1758  }
1759  else
1760  {
1761  add_impasse_wme( thisAgent, id, loop_sym, cand->value, bt_pref );
1762  }
1763  }
1764 
1765  if ( item_count > 0 )
1766  {
1767  count_sym = make_int_constant( thisAgent, static_cast< int64_t >( item_count ) );
1768  add_impasse_wme( thisAgent, id, loop_count_sym, count_sym, NIL );
1769  symbol_remove_ref( thisAgent, count_sym );
1770  }
1771  }
1772 }
1773 
1774 /* ------------------------------------------------------------------
1775  Decide Non Context Slot
1776 
1777  This routine decides a given slot, which must be a non-context
1778  slot. It calls run_preference_semantics() on the slot, then
1779  updates the wmes and/or impasse for the slot accordingly.
1780 ------------------------------------------------------------------ */
1781 
1782 void decide_non_context_slot (agent* thisAgent, slot *s)
1783 {
1784  byte impasse_type;
1785  wme *w, *next_w;
1786  preference *candidates, *cand, *pref;
1787 
1788  impasse_type = run_preference_semantics (thisAgent, s, &candidates);
1789 
1790  if (impasse_type==NONE_IMPASSE_TYPE)
1791  {
1792  /* --- no impasse, so remove any existing one and update the wmes --- */
1793  if (s->impasse_type != NONE_IMPASSE_TYPE)
1795 
1796  /* --- reset marks on existing wme values to "NOTHING" --- */
1797  for (w=s->wmes; w!=NIL; w=w->next)
1798  w->value->common.decider_flag = NOTHING_DECIDER_FLAG;
1799 
1800  /* --- set marks on desired values to "CANDIDATES" --- */
1801  for (cand=candidates; cand!=NIL; cand=cand->next_candidate)
1802  cand->value->common.decider_flag = CANDIDATE_DECIDER_FLAG;
1803 
1804  /* --- for each existing wme, if we want it there, mark it as
1805  ALREADY_EXISTING; otherwise remove it --- */
1806  w = s->wmes;
1807  while (w)
1808  {
1809  next_w = w->next;
1810  if (w->value->common.decider_flag == CANDIDATE_DECIDER_FLAG)
1811  {
1812  w->value->common.decider_flag = ALREADY_EXISTING_WME_DECIDER_FLAG;
1813  w->value->common.a.decider_wme = w; /* so we can set the pref later */
1814  }
1815  else
1816  {
1817  remove_from_dll (s->wmes, w, next, prev);
1818  /* REW: begin 09.15.96 */
1819  if (w->gds)
1820  {
1821  if (w->gds->goal != NIL)
1822  {
1823  /* If the goal pointer is non-NIL, then goal is in the stack */
1824  gds_invalid_so_remove_goal(thisAgent, w);
1825  }
1826  }
1827  /* REW: end 09.15.96 */
1828  remove_wme_from_wm (thisAgent, w);
1829  }
1830  w = next_w;
1831  } /* end while (W) */
1832 
1833  /* --- for each desired value, if it's not already there, add it --- */
1834  for (cand=candidates; cand!=NIL; cand=cand->next_candidate)
1835  {
1836  if (cand->value->common.decider_flag==ALREADY_EXISTING_WME_DECIDER_FLAG)
1837  {
1838  /* REW: begin 11.22.97 */
1839  /* print(thisAgent, "\n This WME was marked as already existing...."); print_wme(cand->value->common.a.decider_wme); */
1840 
1841  /* REW: end 11.22.97 */
1842  cand->value->common.a.decider_wme->preference = cand;
1843  }
1844  else
1845  {
1846  w = make_wme (thisAgent, cand->id, cand->attr, cand->value, FALSE);
1847  insert_at_head_of_dll (s->wmes, w, next, prev);
1848  w->preference = cand;
1849 
1850  if ( ( s->wma_val_references != NIL ) && wma_enabled( thisAgent ) )
1851  {
1852  wma_sym_reference_map::iterator it = s->wma_val_references->find( w->value );
1853  if ( it != s->wma_val_references->end() )
1854  {
1855  // should only activate at this point if WME is o-supported
1856  wma_activate_wme( thisAgent, w, it->second, NULL, true );
1857 
1858  s->wma_val_references->erase( it );
1859  if ( s->wma_val_references->empty() )
1860  {
1861  s->wma_val_references->~wma_sym_reference_map();
1862  free_with_pool( &( thisAgent->wma_slot_refs_pool ), s->wma_val_references );
1863  s->wma_val_references = NIL;
1864  }
1865  }
1866  }
1867 
1868  /* REW: begin 09.15.96 */
1869  /* Whenever we add a WME to WM, we also want to check and see if
1870  this new WME is o-supported. If so, then we want to add the
1871  supergoal dependencies of the new, o-supported element to the
1872  goal in which the element was created (as long as the o_supported
1873  element was not created in the top state -- the top goal has
1874  no gds). */
1875 
1876  /* REW: begin 11.25.96 */
1877 #ifndef NO_TIMING_STUFF
1878 #ifdef DETAILED_TIMING_STATS
1879  thisAgent->timers_gds.start();
1880 #endif
1881 #endif
1882  /* REW: end 11.25.96 */
1883 
1884  thisAgent->parent_list_head = NIL;
1885 
1886  /* If the working memory element being added is going to have
1887  o_supported preferences and the instantion that created it
1888  is not in the top_level_goal (where there is no GDS), then
1889  loop over the preferences for this WME and determine which
1890  WMEs should be added to the goal's GDS (the goal here being the
1891  goal to which the added memory is attached). */
1892 
1893  if ((w->preference->o_supported == TRUE) && (w->preference->inst->match_goal_level != 1))
1894  {
1895  if (w->preference->inst->match_goal->id.gds == NIL)
1896  {
1897  /* If there is no GDS yet for this goal,
1898  * then we need to create one */
1899  if (w->preference->inst->match_goal_level == w->preference->id->id.level)
1900  {
1901  /*
1902  * NLD: BUG when the system has already halted and this code is reached, Soar will
1903  * report a memory leak because the elaborate_gds call below will not execute (notice the
1904  * check for system_halted), and hence the gds for this goal will not be populated,
1905  * leading to the gds struct not being freed on quit.
1906  *
1907  * I'm not sure if this situation will come up anymore (after r12593), so not doing
1908  * anything about it. However, if it does, this can lead to a memory leak. I know
1909  * it can add up between calls to init-soar, but I'm not sure if it can increase
1910  * more frequently than that.
1911  */
1912  create_gds_for_goal( thisAgent, w->preference->inst->match_goal );
1913 
1914  /* REW: BUG When chunks and result instantiations both create
1915  * preferences for the same WME, then we only want to create
1916  * the GDS for the highest goal. Right now I ensure that we
1917  * elaborate the correct GDS with the tests in the loop just
1918  * below this code, but the GDS creation above assumes that
1919  * the chunk will be first on the GDS list. This order
1920  * appears to be always true, although I am not 100% certain
1921  * (I think it occurs this way because the chunk is
1922  * necessarily added to the instantiaton list after the
1923  * original instantiation and lists get built such older items
1924  * appear further from the head of the list) . If not true,
1925  * then we need to keep track of any GDS's that get created
1926  * here to remove them later if we find a higher match goal
1927  * for the WME. For now, the program just exits in this
1928  * situation; otherwise, we would build a GDS for the wrong
1929  * level and never elaborate it (resulting in a memory
1930  * leak).
1931  */
1932  }
1933  else
1934  {
1935  // If this happens, we better be halted, see chunk.cpp:chunk_instantiation
1936  // This can happen if a chunk can't be created, because then the match level
1937  // of the preference instantiation can map back to the original matching
1938  // production which can be at a different level than the id wme.
1939  // Normally, there would be a chunk or justification firing at the higher
1940  // goal with a match level equal to the id level.
1941  // See more comments in chunk_instantiation.
1942  if (!thisAgent->system_halted)
1943  {
1944  abort_with_fatal_error(thisAgent, "**** Wanted to create a GDS for a WME level different from the instantiation level.....Big problems....exiting....****\n\n");
1945  }
1946  }
1947  } /* end if no GDS yet for goal... */
1948 
1949  /* Loop over all the preferences for this WME:
1950  * If the instantiation that lead to the preference has not
1951  * been already explored; OR
1952  * If the instantiation is not an subgoal instantiation
1953  * for a chunk instantiation we are already exploring
1954  * Then
1955  * Add the instantiation to a list of instantiations that
1956  * will be explored in elaborate_gds().
1957  */
1958 
1959  // Added halt test because chunk_instantiation can cause problems,
1960  // see comment a few lines above and in chunk_instantiation.
1961  if (!thisAgent->system_halted)
1962  {
1963  for (pref=w->preference; pref!=NIL; pref=pref->next)
1964  {
1965 #ifdef DEBUG_GDS_HIGH
1966  print(thisAgent, thisAgent, "\n\n "); print_preference(pref);
1967  print(thisAgent, " Goal level of preference: %d\n",
1968  pref->id->id.level);
1969 #endif
1970 
1971  if (pref->inst->GDS_evaluated_already == FALSE)
1972  {
1973 #ifdef DEBUG_GDS_HIGH
1974  print_with_symbols(thisAgent, " Match goal lev of instantiation %y ",
1975  pref->inst->prod->name);
1976  print(thisAgent, "is %d\n", pref->inst->match_goal_level);
1977 #endif
1978  if (pref->inst->match_goal_level > pref->id->id.level)
1979  {
1980 #ifdef DEBUG_GDS_HIGH
1981  print_with_symbols(thisAgent, " %y is simply the instantiation that led to a chunk.\n Not adding it the current instantiations.\n", pref->inst->prod->name);
1982 #endif
1983 
1984  }
1985  else
1986  {
1987 #ifdef DEBUG_GDS_HIGH
1988  print_with_symbols(thisAgent, "\n Adding %y to list of parent instantiations\n", pref->inst->prod->name);
1989 #endif
1990  uniquely_add_to_head_of_dll(thisAgent, pref->inst);
1991  pref->inst->GDS_evaluated_already = TRUE;
1992  }
1993  } /* end if GDS_evaluated_already is FALSE */
1994 #ifdef DEBUG_GDS_HIGH
1995  else
1996  print_with_symbols(thisAgent, "\n Instantiation %y was already explored; skipping it\n", pref->inst->prod->name);
1997 #endif
1998 
1999  } /* end of forloop over preferences for this wme */
2000 
2001 #ifdef DEBUG_GDS_HIGH
2002  print(thisAgent, "\n CALLING ELABORATE GDS....\n");
2003 #endif
2004  elaborate_gds(thisAgent);
2005 
2006  /* technically, the list should be empty at this point ??? */
2007 
2008  free_parent_list(thisAgent);
2009 #ifdef DEBUG_GDS_HIGH
2010  print(thisAgent, " FINISHED ELABORATING GDS.\n\n");
2011 #endif
2012  } /* end if not halted */
2013  } /* end if w->preference->o_supported == TRUE ... */
2014 
2015  /* REW: begin 11.25.96 */
2016 #ifndef NO_TIMING_STUFF
2017 #ifdef DETAILED_TIMING_STATS
2018  thisAgent->timers_gds.stop();
2019  thisAgent->timers_gds_cpu_time[thisAgent->current_phase].update(thisAgent->timers_gds);
2020 #endif
2021 #endif
2022  /* REW: end 11.25.96 */
2023  /* REW: end 09.15.96 */
2024 
2025  add_wme_to_wm (thisAgent, w);
2026  }
2027  }
2028 
2029  return;
2030  } /* end of if impasse type == NONE */
2031 
2032  /* --- impasse type != NONE --- */
2033  if (s->wmes)
2034  {
2035  /* --- remove any existing wmes --- */
2036  remove_wme_list_from_wm (thisAgent, s->wmes);
2037  s->wmes = NIL;
2038  }
2039 
2040  /* --- create and/or update impasse structure --- */
2041  if (s->impasse_type != NONE_IMPASSE_TYPE)
2042  {
2043  if (s->impasse_type != impasse_type)
2044  {
2046  create_new_attribute_impasse_for_slot (thisAgent, s, impasse_type);
2047  }
2048  update_impasse_items (thisAgent, s->impasse_id, candidates);
2049  }
2050  else
2051  {
2052  create_new_attribute_impasse_for_slot (thisAgent, s, impasse_type);
2053  update_impasse_items (thisAgent, s->impasse_id, candidates);
2054  }
2055 }
2056 
2057 /* ------------------------------------------------------------------
2058  Decide Non Context Slots
2059 
2060  This routine iterates through all changed non-context slots, and
2061  decides each one.
2062 ------------------------------------------------------------------ */
2063 
2064 void decide_non_context_slots (agent* thisAgent) {
2065  dl_cons *dc;
2066  slot *s;
2067 
2068  while (thisAgent->changed_slots)
2069  {
2070  dc = thisAgent->changed_slots;
2071  thisAgent->changed_slots = thisAgent->changed_slots->next;
2072  s = static_cast<slot_struct *>(dc->item);
2073  decide_non_context_slot (thisAgent, s);
2074  s->changed = NIL;
2075  free_with_pool (&thisAgent->dl_cons_pool, dc);
2076  }
2077 }
2078 
2079 /* ------------------------------------------------------------------
2080  Context Slot Is Decidable
2081 
2082  This returns TRUE iff the given slot (which must be a context slot)
2083  is decidable. A context slot is decidable if:
2084  - it has an installed value in WM and there is a reconsider
2085  preference for that value, or
2086  - it has no installed value but does have changed preferences
2087 ------------------------------------------------------------------ */
2088 
2090 {
2091  Symbol *v;
2092  preference *p;
2093 
2094  if (!s->wmes)
2095  return (s->changed != NIL);
2096 
2097  v = s->wmes->value;
2098  for (p = s->preferences[RECONSIDER_PREFERENCE_TYPE]; p != NIL; p = p->next)
2099  {
2100  if (v == p->value)
2101  return TRUE;
2102  }
2103 
2104  return FALSE;
2105 }
2106 
2107 /* ------------------------------------------------------------------
2108  Remove WMEs For Context Slot
2109 
2110  This removes the wmes (there can only be 0 or 1 of them) for the
2111  given context slot.
2112 ------------------------------------------------------------------ */
2113 
2114 void remove_wmes_for_context_slot (agent* thisAgent, slot *s) {
2115  wme *w;
2116 
2117  if (!s->wmes) return;
2118  /* Note that we only need to handle one wme--context slots never have
2119  more than one wme in them */
2120  w = s->wmes;
2121  preference_remove_ref (thisAgent, w->preference);
2122  remove_wme_from_wm (thisAgent, w);
2123  s->wmes = NIL;
2124 }
2125 
2126 /* ------------------------------------------------------------------
2127  Remove Existing Context And Descendents
2128 
2129  This routine truncates the goal stack by removing the given goal
2130  and all its subgoals. (If the given goal is the top goal, the
2131  entire context stack is removed.)
2132 ------------------------------------------------------------------ */
2133 
2135  preference *p;
2136 
2137  ms_change *head, *tail; /* REW: 08.20.97 */
2138 
2139  /* --- remove descendents of this goal --- */
2140  // BUGBUG this recursion causes a stack overflow if the goal depth is large
2141  if (goal->id.lower_goal)
2143 
2144  /* --- invoke callback routine --- */
2145  soar_invoke_callbacks(thisAgent,
2147  static_cast<soar_call_data>(goal) );
2148 
2149  if ( ( goal != thisAgent->top_goal ) && rl_enabled( thisAgent ) )
2150  {
2151  rl_tabulate_reward_value_for_goal( thisAgent, goal );
2152  rl_perform_update( thisAgent, 0, true, goal, false ); // this update only sees reward - there is no next state
2153  rl_clear_refs( goal );
2154  }
2155 
2156  /* --- disconnect this goal from the goal stack --- */
2157  if (goal == thisAgent->top_goal) {
2158  thisAgent->top_goal = NIL;
2159  thisAgent->bottom_goal = NIL;
2160  } else {
2161  thisAgent->bottom_goal = goal->id.higher_goal;
2162  thisAgent->bottom_goal->id.lower_goal = NIL;
2163  }
2164 
2165  /* --- remove any preferences supported by this goal --- */
2166 #ifdef DO_TOP_LEVEL_REF_CTS
2167  while (goal->id.preferences_from_goal) {
2168  p = goal->id.preferences_from_goal;
2170  all_of_goal_next, all_of_goal_prev);
2171  p->on_goal_list = FALSE;
2172  if (! remove_preference_from_clones (thisAgent, p))
2173  if (p->in_tm) remove_preference_from_tm (thisAgent, p);
2174  }
2175 #else
2176  /* KJC Aug 05: this seems to cure a potential for exceeding callstack
2177  * when popping soar's goal stack and not doing DO_TOP_LEVEL_REF_CTS
2178  * Probably should make this change for all cases, but needs testing. */
2179  /* Prefs are added to head of dll, so try removing from tail */
2180  if (goal->id.preferences_from_goal) {
2181  p = goal->id.preferences_from_goal;
2182  while (p->all_of_goal_next) p = p->all_of_goal_next;
2183  while (p) {
2184  preference* p_next = p->all_of_goal_prev; // RPM 10/06 we need to save this because p may be freed by the end of the loop
2186  all_of_goal_next, all_of_goal_prev);
2187  p->on_goal_list = FALSE;
2188  if (! remove_preference_from_clones (thisAgent, p))
2189  if (p->in_tm) remove_preference_from_tm (thisAgent, p);
2190  p = p_next;
2191  }
2192  }
2193 #endif
2194  /* --- remove wmes for this goal, and garbage collect --- */
2195  remove_wmes_for_context_slot (thisAgent, goal->id.operator_slot);
2196  update_impasse_items (thisAgent, goal, NIL); /* causes items & fake pref's to go away */
2197 
2198  epmem_reset( thisAgent, goal );
2199  smem_reset( thisAgent, goal );
2200 
2201  remove_wme_list_from_wm (thisAgent, goal->id.impasse_wmes);
2202  goal->id.impasse_wmes = NIL;
2203  /* REW: begin 09.15.96 */
2204  /* If there was a GDS for this goal, we want to set the pointer for the
2205  goal to NIL to indicate it no longer exists.
2206  BUG: We probably also need to make certain that the GDS doesn't need
2207  to be free'd here as well. */
2208  if (goal->id.gds != NIL) goal->id.gds->goal = NIL;
2209  /* REW: end 09.15.96 */
2210 
2211  /* REW: begin 08.20.97 */
2212 
2213  /* If we remove a goal WME, then we have to transfer any already existing
2214  retractions to the nil-goal list on the current agent. We should be
2215  able to do this more efficiently but the most obvious way (below) still
2216  requires scanning over the whole list (to set the goal pointer of each
2217  msc to NIL); therefore this solution should be acceptably efficient. */
2218 
2219  if (goal->id.ms_retractions) { /* There's something on the retraction list */
2220 
2221  head = goal->id.ms_retractions;
2222  tail = head;
2223 
2224  /* find the tail of this list */
2225  while (tail->next_in_level) {
2226  tail->goal = NIL; /* force the goal to be NIL */
2227  tail = tail->next_in_level;
2228  }
2229  tail->goal = NIL;
2230 
2231  if (thisAgent->nil_goal_retractions) {
2232  /* There are already retractions on the list */
2233 
2234  /* Append this list to front of NIL goal list */
2235  thisAgent->nil_goal_retractions->prev_in_level = tail;
2236  tail->next_in_level = thisAgent->nil_goal_retractions;
2237  thisAgent->nil_goal_retractions = head;
2238 
2239  } else { /* If no retractions, make this list the NIL goal list */
2240  thisAgent->nil_goal_retractions = head;
2241  }
2242  }
2243 
2244  goal->id.rl_info->eligibility_traces->~rl_et_map();
2245  free_with_pool( &( thisAgent->rl_et_pool ),goal->id.rl_info->eligibility_traces );
2246  goal->id.rl_info->prev_op_rl_rules->~rl_rule_list();
2247  free_with_pool( &( thisAgent->rl_rule_pool ),goal->id.rl_info->prev_op_rl_rules );
2248  symbol_remove_ref( thisAgent, goal->id.reward_header );
2249  free_with_pool( &( thisAgent->rl_info_pool ), goal->id.rl_info );
2250 
2251  goal->id.epmem_info->epmem_wmes->~epmem_wme_stack();
2252  free_with_pool( &( thisAgent->epmem_wmes_pool ), goal->id.epmem_info->epmem_wmes );
2253  symbol_remove_ref( thisAgent, goal->id.epmem_cmd_header );
2254  symbol_remove_ref( thisAgent, goal->id.epmem_result_header );
2255  symbol_remove_ref( thisAgent, goal->id.epmem_header );
2256  free_with_pool( &( thisAgent->epmem_info_pool ), goal->id.epmem_info );
2257 
2258  goal->id.smem_info->smem_wmes->~smem_wme_stack();
2259  free_with_pool( &( thisAgent->smem_wmes_pool ), goal->id.smem_info->smem_wmes );
2260  symbol_remove_ref( thisAgent, goal->id.smem_cmd_header );
2261  symbol_remove_ref( thisAgent, goal->id.smem_result_header );
2262  symbol_remove_ref( thisAgent, goal->id.smem_header );
2263  free_with_pool( &( thisAgent->smem_info_pool ), goal->id.smem_info );
2264 
2265 
2266  /* REW: BUG
2267  * Tentative assertions can exist for removed goals. However, it looks
2268  * like the removal forces a tentative retraction, which then leads to
2269  * the deletion of the tentative assertion. However, I have not tested
2270  * such cases exhaustively -- I would guess that some processing may be
2271  * necessary for the assertions here at some point?
2272  */
2273 
2274  /* REW: end 08.20.97 */
2275 
2276  /* We have to remove this state from the list of states to learn in (NLD: and free cons)
2277  * jzxu April 24, 2009 */
2278  free_list( thisAgent, extract_list_elements(thisAgent, &thisAgent->chunky_problem_spaces, cons_equality_fn, reinterpret_cast<void*>(goal)) );
2279  free_list( thisAgent, extract_list_elements(thisAgent, &thisAgent->chunk_free_problem_spaces, cons_equality_fn, reinterpret_cast<void*>(goal)) );
2280 
2281  post_link_removal (thisAgent, NIL, goal); /* remove the special link */
2282  symbol_remove_ref (thisAgent, goal);
2283 
2284  if (goal->id.level <= thisAgent->substate_break_level) {
2285  thisAgent->stop_soar++;
2286  thisAgent->substate_break_level = 0;
2287  thisAgent->reason_for_stopping = "Stopped due to substate (goal) retraction.";
2288  }
2289 }
2290 
2291 /* ------------------------------------------------------------------
2292  Create New Context
2293 
2294  This routine creates a new goal context (becoming the new bottom
2295  goal) below the current bottom goal. If there is no current
2296  bottom goal, this routine creates a new goal and makes it both
2297  the top and bottom goal.
2298 ------------------------------------------------------------------ */
2299 
2300 void create_new_context (agent* thisAgent, Symbol *attr_of_impasse, byte impasse_type)
2301 {
2302  Symbol *id;
2303 
2304  if (thisAgent->bottom_goal)
2305  {
2306  /* Creating a sub-goal (or substate) */
2307  id = create_new_impasse (thisAgent, TRUE, thisAgent->bottom_goal,
2308  attr_of_impasse, impasse_type,
2309  static_cast<goal_stack_level>(thisAgent->bottom_goal->id.level + 1));
2310  id->id.higher_goal = thisAgent->bottom_goal;
2311  thisAgent->bottom_goal->id.lower_goal = id;
2312  thisAgent->bottom_goal = id;
2313  add_impasse_wme (thisAgent, id, thisAgent->quiescence_symbol,
2314  thisAgent->t_symbol, NIL);
2315  if ((NO_CHANGE_IMPASSE_TYPE == impasse_type) &&
2316  (thisAgent->sysparams[MAX_GOAL_DEPTH] < thisAgent->bottom_goal->id.level ))
2317  {
2318  // appear to be SNC'ing deep in goalstack, so interrupt and warn user
2319  // KJC note: we actually halt, because there is no interrupt function in SoarKernel
2320  // in the gSKI Agent code, if system_halted, MAX_GOAL_DEPTH is checked and if exceeded
2321  // then the interrupt is generated and system_halted is set to FALSE so the user can recover.
2322  print(thisAgent, "\nGoal stack depth exceeded %d on a no-change impasse.\n",thisAgent->sysparams[MAX_GOAL_DEPTH]);
2323  print(thisAgent, "Soar appears to be in an infinite loop. \nContinuing to subgoal may cause Soar to \nexceed the program stack of your system.\n");
2324  xml_generate_warning(thisAgent, "\nGoal stack depth exceeded on a no-change impasse.\n");
2325  xml_generate_warning(thisAgent, "Soar appears to be in an infinite loop. \nContinuing to subgoal may cause Soar to \nexceed the program stack of your system.\n");
2326  thisAgent->stop_soar = TRUE;
2327  thisAgent->system_halted = TRUE;
2328  thisAgent->reason_for_stopping = "Max Goal Depth exceeded.";
2329  }
2330  }
2331  else
2332  {
2333  /* Creating the top state */
2334  id = create_new_impasse (thisAgent, TRUE, thisAgent->nil_symbol,
2336  TOP_GOAL_LEVEL);
2337  thisAgent->top_goal = id;
2338  thisAgent->bottom_goal = id;
2339  thisAgent->top_state = thisAgent->top_goal;
2340  id->id.higher_goal = NIL;
2341  id->id.lower_goal = NIL;
2342  }
2343 
2344  id->id.isa_goal = TRUE;
2345  id->id.operator_slot = make_slot (thisAgent, id, thisAgent->operator_symbol);
2346  id->id.allow_bottom_up_chunks = TRUE;
2347 
2348  allocate_with_pool( thisAgent, &( thisAgent->rl_info_pool ), &( id->id.rl_info ) );
2349  id->id.rl_info->previous_q = 0;
2350  id->id.rl_info->reward = 0;
2351  id->id.rl_info->gap_age = 0;
2352  id->id.rl_info->hrl_age = 0;
2353  allocate_with_pool( thisAgent, &( thisAgent->rl_et_pool ), &( id->id.rl_info->eligibility_traces ) );
2354 #ifdef USE_MEM_POOL_ALLOCATORS
2355  id->id.rl_info->eligibility_traces = new ( id->id.rl_info->eligibility_traces ) rl_et_map( std::less< production* >(), soar_module::soar_memory_pool_allocator< std::pair< production*, double > >( thisAgent ) );
2356 #else
2357  id->id.rl_info->eligibility_traces = new ( id->id.rl_info->eligibility_traces ) rl_et_map();
2358 #endif
2359  allocate_with_pool( thisAgent, &( thisAgent->rl_rule_pool ), &( id->id.rl_info->prev_op_rl_rules ) );
2360 #ifdef USE_MEM_POOL_ALLOCATORS
2361  id->id.rl_info->prev_op_rl_rules = new ( id->id.rl_info->prev_op_rl_rules ) rl_rule_list( soar_module::soar_memory_pool_allocator< production* >( thisAgent ) );
2362 #else
2363  id->id.rl_info->prev_op_rl_rules = new ( id->id.rl_info->prev_op_rl_rules ) rl_rule_list();
2364 #endif
2365 
2366  allocate_with_pool( thisAgent, &( thisAgent->epmem_info_pool ), &( id->id.epmem_info ) );
2367  id->id.epmem_info->last_ol_time = 0;
2368  id->id.epmem_info->last_cmd_time = 0;
2369  id->id.epmem_info->last_cmd_count = 0;
2370  id->id.epmem_info->last_memory = EPMEM_MEMID_NONE;
2371  allocate_with_pool( thisAgent, &( thisAgent->epmem_wmes_pool ), &( id->id.epmem_info->epmem_wmes ) );
2372 #ifdef USE_MEM_POOL_ALLOCATORS
2373  id->id.epmem_info->epmem_wmes = new ( id->id.epmem_info->epmem_wmes ) epmem_wme_stack( soar_module::soar_memory_pool_allocator< preference* >( thisAgent ) );
2374 #else
2375  id->id.epmem_info->epmem_wmes = new ( id->id.epmem_info->epmem_wmes ) epmem_wme_stack();
2376 #endif
2377 
2378  allocate_with_pool( thisAgent, &( thisAgent->smem_info_pool ), &( id->id.smem_info ) );
2379  id->id.smem_info->last_cmd_time[0] = 0;
2380  id->id.smem_info->last_cmd_time[1] = 0;
2381  id->id.smem_info->last_cmd_count[0] = 0;
2382  id->id.smem_info->last_cmd_count[1] = 0;
2383  allocate_with_pool( thisAgent, &( thisAgent->smem_wmes_pool ), &( id->id.smem_info->smem_wmes ) );
2384 #ifdef USE_MEM_POOL_ALLOCATORS
2385  id->id.smem_info->smem_wmes = new ( id->id.smem_info->smem_wmes ) smem_wme_stack( soar_module::soar_memory_pool_allocator< preference* >( thisAgent ) );
2386 #else
2387  id->id.smem_info->smem_wmes = new ( id->id.smem_info->smem_wmes ) smem_wme_stack();
2388 #endif
2389 
2390  /* --- invoke callback routine --- */
2391  soar_invoke_callbacks(thisAgent,
2393  static_cast<soar_call_data>(id) );
2394 }
2395 
2396 /* ------------------------------------------------------------------
2397  Type and Attribute of Existing Impasse
2398 
2399  Given a goal, these routines return the type and attribute,
2400  respectively, of the impasse just below that goal context. It
2401  does so by looking at the impasse wmes for the next lower goal
2402  in the goal stack.
2403 ------------------------------------------------------------------ */
2404 
2406  wme *w;
2407  char msg[BUFFER_MSG_SIZE];
2408 
2409  if (! goal->id.lower_goal) return NONE_IMPASSE_TYPE;
2410  for (w=goal->id.lower_goal->id.impasse_wmes; w!=NIL; w=w->next)
2411  if (w->attr==thisAgent->impasse_symbol) {
2412  if (w->value==thisAgent->no_change_symbol)
2413  return NO_CHANGE_IMPASSE_TYPE;
2414  if (w->value==thisAgent->tie_symbol)
2415  return TIE_IMPASSE_TYPE;
2416  if (w->value==thisAgent->constraint_failure_symbol)
2418  if (w->value==thisAgent->conflict_symbol)
2419  return CONFLICT_IMPASSE_TYPE;
2420  if (w->value==thisAgent->none_symbol)
2421  return NONE_IMPASSE_TYPE;
2422  strncpy (msg,"decide.c: Internal error: bad type of existing impasse.\n", BUFFER_MSG_SIZE);
2423  msg[BUFFER_MSG_SIZE - 1] = 0; /* ensure null termination */
2424  abort_with_fatal_error(thisAgent, msg);
2425  }
2426  strncpy (msg,"decide.c: Internal error: couldn't find type of existing impasse.\n", BUFFER_MSG_SIZE);
2427  msg[BUFFER_MSG_SIZE - 1] = 0; /* ensure null termination */
2428  abort_with_fatal_error(thisAgent, msg);
2429  return 0; /* unreachable, but without it, gcc -Wall warns here */
2430 }
2431 
2433  wme *w;
2434 
2435  if (! goal->id.lower_goal) return NIL;
2436  for (w=goal->id.lower_goal->id.impasse_wmes; w!=NIL; w=w->next)
2437  if (w->attr==thisAgent->attribute_symbol) return w->value;
2438  { char msg[BUFFER_MSG_SIZE];
2439  strncpy (msg, "decide.c: Internal error: couldn't find attribute of existing impasse.\n", BUFFER_MSG_SIZE);
2440  msg[BUFFER_MSG_SIZE - 1] = 0; /* ensure null termination */
2441  abort_with_fatal_error(thisAgent, msg);
2442  }
2443  return NIL; /* unreachable, but without it, gcc -Wall warns here */
2444 }
2445 
2446 /* ------------------------------------------------------------------
2447  Decide Context Slot
2448 
2449  This decides the given context slot. It normally returns TRUE,
2450  but returns FALSE if the ONLY change as a result of the decision
2451  procedure was a change in the set of ^item's on the impasse below
2452  the given slot.
2453 ------------------------------------------------------------------ */
2454 
2455 Bool decide_context_slot (agent* thisAgent, Symbol *goal, slot *s, bool predict = false)
2456 {
2457  byte impasse_type;
2458  Symbol *attribute_of_impasse;
2459  wme *w;
2460  preference *candidates;
2461  preference *temp;
2462 
2463  if (!context_slot_is_decidable(s))
2464  {
2465  /* --- the only time we decide a slot that's not "decidable" is when it's
2466  the last slot in the entire context stack, in which case we have a
2467  no-change impasse there --- */
2468  impasse_type = NO_CHANGE_IMPASSE_TYPE;
2469  candidates = NIL; /* we don't want any impasse ^item's later */
2470 
2471  if ( predict )
2472  {
2473  predict_set( thisAgent, "none" );
2474  return TRUE;
2475  }
2476  }
2477  else
2478  {
2479  /* --- the slot is decidable, so run preference semantics on it --- */
2480  impasse_type = run_preference_semantics (thisAgent, s, &candidates);
2481 
2482  if ( predict )
2483  {
2484  switch ( impasse_type )
2485  {
2487  predict_set( thisAgent, "constraint" );
2488  break;
2489 
2490  case CONFLICT_IMPASSE_TYPE:
2491  predict_set( thisAgent, "conflict" );
2492  break;
2493 
2494  case TIE_IMPASSE_TYPE:
2495  predict_set( thisAgent, "tie" );
2496  break;
2497 
2499  predict_set( thisAgent, "none" );
2500  break;
2501 
2502  default:
2503  if ( !candidates || ( candidates->value->common.symbol_type != IDENTIFIER_SYMBOL_TYPE ) )
2504  predict_set( thisAgent, "none" );
2505  else
2506  {
2507  std::string temp = "";
2508 
2509  // get first letter of id
2510  temp += candidates->value->id.name_letter;
2511 
2512  // get number
2513  std::string temp2;
2514  to_string( candidates->value->id.name_number, temp2 );
2515  temp += temp2;
2516 
2517  predict_set( thisAgent, temp.c_str() );
2518  }
2519  break;
2520  }
2521 
2522  return TRUE;
2523  }
2524 
2525  remove_wmes_for_context_slot (thisAgent, s); /* must remove old wme before adding
2526  the new one (if any) */
2527  if (impasse_type == NONE_IMPASSE_TYPE)
2528  {
2529  if (!candidates)
2530  {
2531  /* --- no winner ==> no-change impasse on the previous slot --- */
2532  impasse_type = NO_CHANGE_IMPASSE_TYPE;
2533  }
2534  else if (candidates->next_candidate)
2535  {
2536  /* --- more than one winner ==> internal error --- */
2537  char msg[BUFFER_MSG_SIZE];
2538  strncpy (msg,"decide.c: Internal error: more than one winner for context slot\n", BUFFER_MSG_SIZE);
2539  msg[BUFFER_MSG_SIZE - 1] = 0; /* ensure null termination */
2540  abort_with_fatal_error(thisAgent, msg);
2541  }
2542  }
2543  } /* end if !context_slot_is_decidable */
2544 
2545  /* --- mark the slot as not changed --- */
2546  s->changed = NIL;
2547 
2548  /* --- determine the attribute of the impasse (if there is no impasse,
2549  * this doesn't matter) --- */
2550  if (impasse_type == NO_CHANGE_IMPASSE_TYPE)
2551  {
2552  if (s->wmes)
2553  {
2554  attribute_of_impasse = s->attr;
2555  }
2556  else
2557  {
2558  attribute_of_impasse = thisAgent->state_symbol;
2559  }
2560  }
2561  else
2562  {
2563  /* --- for all other kinds of impasses --- */
2564  attribute_of_impasse = s->attr;
2565  }
2566 
2567  /* --- remove wme's for lower slots of this context --- */
2568  if (attribute_of_impasse == thisAgent->state_symbol)
2569  {
2570  remove_wmes_for_context_slot (thisAgent, goal->id.operator_slot);
2571  }
2572 
2573 
2574  /* --- if we have a winner, remove any existing impasse and install the
2575  new value for the current slot --- */
2576  if (impasse_type == NONE_IMPASSE_TYPE)
2577  {
2578  for(temp = candidates; temp; temp = temp->next_candidate)
2579  preference_add_ref(temp);
2580 
2581  if (goal->id.lower_goal)
2582  {
2583  if ( thisAgent->soar_verbose_flag || thisAgent->sysparams[TRACE_WM_CHANGES_SYSPARAM] )
2584  print_with_symbols(thisAgent, "Removing state %y because of a decision.\n", goal->id.lower_goal);
2585 
2587  }
2588 
2589  w = make_wme (thisAgent, s->id, s->attr, candidates->value, FALSE);
2590  insert_at_head_of_dll (s->wmes, w, next, prev);
2591  w->preference = candidates;
2593 
2594  /* JC Adding an operator to working memory in the current state */
2595  add_wme_to_wm (thisAgent, w);
2596 
2597  for(temp = candidates; temp; temp = temp->next_candidate)
2598  preference_remove_ref(thisAgent, temp);
2599 
2600  if ( rl_enabled( thisAgent ) )
2601  rl_store_data( thisAgent, goal, candidates );
2602 
2603  return TRUE;
2604  }
2605 
2606  /* --- no winner; if an impasse of the right type already existed, just
2607  update the ^item set on it --- */
2608  if ((impasse_type == type_of_existing_impasse(thisAgent, goal)) &&
2609  (attribute_of_impasse == attribute_of_existing_impasse(thisAgent, goal)))
2610  {
2611  update_impasse_items (thisAgent, goal->id.lower_goal, candidates);
2612  return FALSE;
2613  }
2614 
2615  /* --- no impasse already existed, or an impasse of the wrong type
2616  already existed --- */
2617  for(temp = candidates; temp; temp = temp->next_candidate)
2618  preference_add_ref(temp);
2619 
2620  if (goal->id.lower_goal)
2621  {
2622  if ( thisAgent->soar_verbose_flag || thisAgent->sysparams[TRACE_WM_CHANGES_SYSPARAM] )
2623  print_with_symbols(thisAgent, "Removing state %y because it's the wrong type of impasse.\n", goal->id.lower_goal);
2624 
2626  }
2627 
2628  /* REW: begin 10.24.97 */
2629  if (thisAgent->waitsnc && (impasse_type == NO_CHANGE_IMPASSE_TYPE) && (attribute_of_impasse == thisAgent->state_symbol))
2630  {
2631  thisAgent->waitsnc_detect = TRUE;
2632  }
2633  else
2634  {
2635  /* REW: end 10.24.97 */
2636  create_new_context (thisAgent, attribute_of_impasse, impasse_type);
2637  update_impasse_items (thisAgent, goal->id.lower_goal, candidates);
2638  }
2639 
2640  for(temp = candidates; temp; temp = temp->next_candidate)
2641  preference_remove_ref(thisAgent, temp);
2642 
2643  return TRUE;
2644 }
2645 
2646 /* ------------------------------------------------------------------
2647  Decide Context Slots
2648 
2649  This scans down the goal stack and runs the decision procedure on
2650  the appropriate context slots.
2651 ------------------------------------------------------------------ */
2652 
2653 void decide_context_slots (agent* thisAgent, bool predict = false)
2654 {
2655  Symbol *goal;
2656  slot *s;
2657 
2658  if (thisAgent->highest_goal_whose_context_changed)
2659  {
2660  goal = thisAgent->highest_goal_whose_context_changed;
2661  }
2662  else
2663  /* no context changed, so jump right to the bottom */
2664  goal = thisAgent->bottom_goal;
2665 
2666  s = goal->id.operator_slot;
2667 
2668  /* --- loop down context stack --- */
2669  while (TRUE)
2670  {
2671  /* --- find next slot to decide --- */
2672  while (TRUE)
2673  {
2674  if (context_slot_is_decidable(s))
2675  break;
2676 
2677  if ((s == goal->id.operator_slot) || (! s->wmes))
2678  {
2679  /* --- no more slots to look at for this goal; have we reached
2680  the last slot in whole stack? --- */
2681  if (! goal->id.lower_goal)
2682  break;
2683 
2684  /* --- no, go down one level --- */
2685  goal = goal->id.lower_goal;
2686  s = goal->id.operator_slot;
2687  }
2688  } /* end of while (TRUE) find next slot to decide */
2689 
2690  /* --- now go and decide that slot --- */
2691  if (decide_context_slot (thisAgent, goal, s, predict))
2692  break;
2693 
2694  } /* end of while (TRUE) loop down context stack */
2695 
2696  if ( !predict )
2698 }
2699 
2700 /* **********************************************************************
2701 
2702  Top-Level Decider Routines
2703 
2704  Init_decider() should be called at startup time to initialize this
2705  module.
2706 
2707  Do_buffered_wm_and_ownership_changes() does the end-of-phase processing
2708  of WM changes, ownership calculations, garbage collection, etc.
2709 
2710  Do_working_memory_phase() and do_decision_phase() are called from
2711  the top level to run those phases.
2712 
2713  Create_top_goal() creates the top goal in the goal stack.
2714  Clear_goal_stack() wipes out the whole goal stack--this is called
2715  during an init-soar.
2716 
2717  Print_lowest_slot_in_context_stack() is used for the watch 0 trace
2718  to print the context slot that was just decided.
2719 ********************************************************************** */
2720 
2721 void init_decider (agent* thisAgent)
2722 {
2723  init_memory_pool (thisAgent, &thisAgent->slot_pool, sizeof(slot), "slot");
2724  init_memory_pool (thisAgent, &thisAgent->wme_pool, sizeof(wme), "wme");
2725  init_memory_pool (thisAgent, &thisAgent->preference_pool,
2726  sizeof(preference), "preference");
2727 }
2728 
2730 {
2732  do_buffered_link_changes(thisAgent);
2733  do_buffered_wm_changes(thisAgent);
2734  remove_garbage_slots(thisAgent);
2735 }
2736 
2737 void do_working_memory_phase (agent* thisAgent) {
2738 
2739  if (thisAgent->sysparams[TRACE_PHASES_SYSPARAM]) {
2740  if (thisAgent->current_phase == APPLY_PHASE) { /* it's always IE for PROPOSE */
2741  xml_begin_tag(thisAgent, kTagSubphase);
2742  xml_att_val(thisAgent, kPhase_Name, kSubphaseName_ChangingWorkingMemory);
2743  switch (thisAgent->FIRING_TYPE) {
2744  case PE_PRODS:
2745  print (thisAgent, "\t--- Change Working Memory (PE) ---\n",0);
2746  xml_att_val(thisAgent, kPhase_FiringType, kPhaseFiringType_PE);
2747  break;
2748  case IE_PRODS:
2749  print (thisAgent, "\t--- Change Working Memory (IE) ---\n",0);
2750  xml_att_val(thisAgent, kPhase_FiringType, kPhaseFiringType_IE);
2751  break;
2752  }
2753  xml_end_tag(thisAgent, kTagSubphase);
2754  }
2755  }
2756 
2757  decide_non_context_slots(thisAgent);
2759 }
2760 
2761 void do_decision_phase (agent* thisAgent, bool predict)
2762 {
2763  predict_srand_restore_snapshot( thisAgent, !predict );
2764 
2765  /* phase printing moved to init_soar: do_one_top_level_phase */
2766 
2767  decide_context_slots (thisAgent, predict);
2768 
2769  if ( !predict )
2770  {
2772 
2773  /*
2774  * Bob provided a solution to fix WME's hanging around unsupported
2775  * for an elaboration cycle.
2776  */
2777  decide_non_context_slots(thisAgent);
2779 
2780  exploration_update_parameters( thisAgent );
2781  }
2782 }
2783 
2784 void create_top_goal (agent* thisAgent)
2785 {
2787  thisAgent->highest_goal_whose_context_changed = NIL; /* nothing changed yet */
2789 }
2790 
2791 void clear_goal_stack (agent* thisAgent)
2792 {
2793  if (!thisAgent->top_goal)
2794  return;
2795 
2796  remove_existing_context_and_descendents (thisAgent, thisAgent->top_goal);
2797  thisAgent->highest_goal_whose_context_changed = NIL; /* nothing changed yet */
2799  thisAgent->top_state = NIL;
2800  thisAgent->active_goal = NIL;
2801  do_input_cycle(thisAgent); /* tell input functions that the top state is gone */
2802  do_output_cycle(thisAgent); /* tell output functions that output commands are gone */
2803 }
2804 
2806 
2807  /* REW: begin 10.24.97 */
2808  /* This doesn't work yet so for now just print the last selection */
2809  /* if (thisAgent->waitsnc &&
2810  * thisAgent->waitsnc_detect) {
2811  * thisAgent->waitsnc_detect = FALSE;
2812  * print_stack_trace (thisAgent->wait_symbol,
2813  * thisAgent->bottom_goal, FOR_OPERATORS_TF, TRUE);
2814  * print(thisAgent, "\n waiting");
2815  * return;
2816  * }
2817  */
2818  /* REW: end 10.24.97 */
2819 
2820  if (thisAgent->bottom_goal->id.operator_slot->wmes)
2821  print_stack_trace (thisAgent, thisAgent->bottom_goal->id.operator_slot->wmes->value,
2822  thisAgent->bottom_goal, FOR_OPERATORS_TF, TRUE);
2823 
2824 
2825  /* RCHONG: begin 10.11 */
2826  /*
2827  this coded is needed just so that when an ONC is created in OPERAND
2828  (i.e. if the previous goal's operator slot is not empty), it's stack
2829  trace line doesn't get a number. this is done because in OPERAND,
2830  ONCs are detected for "free".
2831  */
2832 
2833  else {
2834 
2835  if (thisAgent->d_cycle_count == 0)
2836  print_stack_trace (thisAgent, thisAgent->bottom_goal,
2837  thisAgent->bottom_goal, FOR_STATES_TF,TRUE);
2838  else {
2839  if (thisAgent->bottom_goal->id.higher_goal &&
2840  thisAgent->bottom_goal->id.higher_goal->id.operator_slot->wmes) {
2841  print_stack_trace (thisAgent, thisAgent->bottom_goal,
2842  thisAgent->bottom_goal,
2844  }
2845  else {
2846  print_stack_trace (thisAgent, thisAgent->bottom_goal,
2847  thisAgent->bottom_goal,
2849  }
2850  }
2851  }
2852 
2853  /* RCHONG: end 10.11 */
2854 
2855 }
2856 
2857 
2858 
2859 
2860 /* REW: begin 09.15.96 */
2861 
2863 {
2864 
2865  parent_inst *new_pi, *curr_pi;
2866 
2867  /* print(thisAgent, "UNIQUE DLL: scanning parent list...\n"); */
2868 
2869  for (curr_pi = thisAgent->parent_list_head;
2870  curr_pi;
2871  curr_pi = curr_pi->next) {
2872  if (curr_pi->inst == inst) {
2873  #ifdef DEBUG_GDS
2874  print_with_symbols(thisAgent, "UNIQUE DLL: %y is already in parent list\n",curr_pi->inst->prod->name);
2875  #endif
2876  return;
2877  }
2878  #ifdef DEBUG_GDS
2879  print_with_symbols(thisAgent, "UNIQUE DLL: %y\n",curr_pi->inst->prod->name);
2880  #endif
2881  } /* end for loop */
2882 
2883  new_pi = static_cast<parent_inst *>(malloc(sizeof(parent_inst)));
2884  new_pi->next = NIL;
2885  new_pi->prev = NIL;
2886  new_pi->inst = inst;
2887 
2888  new_pi->next = thisAgent->parent_list_head;
2889 
2890  if (thisAgent->parent_list_head != NIL)
2891  thisAgent->parent_list_head->prev = new_pi;
2892 
2893  thisAgent->parent_list_head = new_pi;
2894  #ifdef DEBUG_GDS
2895  print_with_symbols(thisAgent, "UNIQUE DLL: added: %y\n",inst->prod->name);
2896  #endif
2897 }
2898 
2899 /* JC ADDED: Added this function to make one place for wme's being added to
2900  * the GDS. Callback for wme added to GDS is made here.
2901  */
2902 void add_wme_to_gds(agent* agentPtr, goal_dependency_set* gds, wme* wme_to_add)
2903 {
2904  /* Set the correct GDS for this wme (wme's point to their gds) */
2905  wme_to_add->gds = gds;
2906  insert_at_head_of_dll(gds->wmes_in_gds, wme_to_add, gds_next, gds_prev);
2907 
2908  if (agentPtr->soar_verbose_flag || agentPtr->sysparams[TRACE_GDS_SYSPARAM])
2909  {
2910  // BADBAD: the XML code makes this all very ugly
2911  char msgbuf[256];
2912  memset(msgbuf, 0, 256);
2913  snprintf_with_symbols(agentPtr, msgbuf, 255, "Adding to GDS for %y: ", wme_to_add->gds->goal);
2914  print_string(agentPtr, msgbuf);
2915 
2916  xml_begin_tag(agentPtr, kTagVerbose);
2917  xml_att_val(agentPtr, kTypeString, msgbuf);
2918  print_wme(agentPtr, wme_to_add); // prints XML, too
2919  xml_end_tag(agentPtr, kTagVerbose);
2920  }
2921 }
2922 
2923 /*
2924 ========================
2925 
2926 ========================
2927 */
2928 void elaborate_gds (agent* thisAgent) {
2929 
2930  wme *wme_matching_this_cond;
2931  goal_stack_level wme_goal_level;
2932  preference *pref_for_this_wme, *pref;
2933  condition *cond;
2934  parent_inst *curr_pi, *temp_pi;
2935  slot *s;
2936  instantiation *inst;
2937 
2938  for (curr_pi=thisAgent->parent_list_head; curr_pi; curr_pi=temp_pi) {
2939 
2940  inst = curr_pi->inst;
2941 
2942 #ifdef DEBUG_GDS
2943  print_with_symbols(thisAgent, "\n EXPLORING INSTANTIATION: %y\n",curr_pi->inst->prod->name);
2944  print(thisAgent, " ");
2945  print_instantiation_with_wmes( thisAgent, curr_pi->inst , TIMETAG_WME_TRACE, -1);
2946 #endif
2947 
2948  for (cond=inst->top_of_instantiated_conditions; cond!=NIL; cond=cond->next)
2949  {
2950 
2951  if (cond->type != POSITIVE_CONDITION)
2952  continue;
2953 
2954  /* We'll deal with negative instantiations after we get the
2955  * positive ones figured out */
2956 
2957  wme_matching_this_cond = cond->bt.wme_;
2958  wme_goal_level = cond->bt.level;
2959  pref_for_this_wme = wme_matching_this_cond->preference;
2960 
2961 #ifdef DEBUG_GDS
2962  print(thisAgent, "\n wme_matching_this_cond at goal_level = %d : ",
2963  wme_goal_level);
2964  print_wme(thisAgent, wme_matching_this_cond);
2965 
2966  if (pref_for_this_wme) {
2967  print(thisAgent, " pref_for_this_wme : ");
2968  print_preference(thisAgent, pref_for_this_wme);
2969  }
2970 #endif
2971 
2972 
2973  /* WME is in a supergoal or is arch-supported WME
2974  * (except for fake instantiations, which do have prefs, so
2975  * they get handled under "wme is local and i-supported")
2976  */
2977  if ((pref_for_this_wme == NIL) ||
2978  (wme_goal_level < inst->match_goal_level))
2979  {
2980 
2981 #ifdef DEBUG_GDS
2982  if (pref_for_this_wme == NIL)
2983  {
2984  print(thisAgent, " this wme has no preferences (it's an arch-created wme)\n");
2985  }
2986  else if (wme_goal_level < inst->match_goal_level)
2987  {
2988  print(thisAgent, " this wme is in the supergoal\n");
2989  }
2990  print_with_symbols(thisAgent, "inst->match_goal [%y]\n" , inst->match_goal);
2991 #endif
2992 
2993  if (wme_matching_this_cond->gds != NIL)
2994  {
2995  /* Then we want to check and see if the old GDS value
2996  * should be changed */
2997  if (wme_matching_this_cond->gds->goal == NIL)
2998  {
2999  /* The goal is NIL: meaning that the goal for the GDS
3000  * is no longer around */
3001  fast_remove_from_dll(wme_matching_this_cond->gds->wmes_in_gds, \
3002  wme_matching_this_cond, wme,
3003  gds_next, gds_prev);
3004 
3005  /* We have to check for GDS removal anytime we take a
3006  * WME off the GDS wme list, not just when a WME is
3007  * removed from memory. */
3008  if (!wme_matching_this_cond->gds->wmes_in_gds)
3009  {
3010  if (wme_matching_this_cond->gds->goal) wme_matching_this_cond->gds->goal->id.gds = NIL;
3011  free_with_pool( &( thisAgent->gds_pool ), wme_matching_this_cond->gds );
3012 
3013 #ifdef DEBUG_GDS
3014  print(thisAgent, "\n REMOVING GDS FROM MEMORY.");
3015 #endif
3016  }
3017 
3018  /* JC ADDED: Separate adding wme to GDS as a function */
3019  add_wme_to_gds(thisAgent, inst->match_goal->id.gds, wme_matching_this_cond);
3020 
3021  // wme_matching_this_cond->gds = inst->match_goal->id.gds;
3022  // insert_at_head_of_dll(wme_matching_this_cond->gds->wmes_in_gds,
3023  // wme_matching_this_cond, gds_next,
3024  // gds_prev);
3025 #ifdef DEBUG_GDS
3026  print(thisAgent, "\n .....GDS' goal is NIL so switching from old to new GDS list....\n");
3027 #endif
3028 
3029  }
3030  else if (wme_matching_this_cond->gds->goal->id.level >
3031  inst->match_goal_level)
3032  {
3033  /* if the WME currently belongs to the GDS of a goal below
3034  * the current one */
3035  /* 1. Take WME off old (current) GDS list
3036  * 2. Check to see if old GDS WME list is empty. If so,
3037  * remove(free) it.
3038  * 3. Add WME to new GDS list
3039  * 4. Update WME pointer to new GDS list
3040  */
3041  if (inst->match_goal_level == 1)
3042  print(thisAgent, "\n\n\n HELLO! HELLO! The inst->match_goal_level is 1");
3043 
3044  fast_remove_from_dll(wme_matching_this_cond->gds->wmes_in_gds, \
3045  wme_matching_this_cond, wme,
3046  gds_next, gds_prev);
3047  if (!wme_matching_this_cond->gds->wmes_in_gds) {
3048  if (wme_matching_this_cond->gds->goal) wme_matching_this_cond->gds->goal->id.gds = NIL;
3049  free_with_pool( &( thisAgent->gds_pool ), wme_matching_this_cond->gds );
3050 
3051 #ifdef DEBUG_GDS
3052  print(thisAgent, "\n REMOVING GDS FROM MEMORY.");
3053 #endif
3054  }
3055  /* JC ADDED: Separate adding wme to GDS as a function */
3056  add_wme_to_gds(thisAgent, inst->match_goal->id.gds, wme_matching_this_cond);
3057 
3058  // wme_matching_this_cond->gds = inst->match_goal->id.gds;
3059  // insert_at_head_of_dll(wme_matching_this_cond->gds->wmes_in_gds,
3060  // wme_matching_this_cond, gds_next,
3061  // gds_prev);
3062 #ifdef DEBUG_GDS
3063  print(thisAgent, "\n ....switching from old to new GDS list....\n");
3064 #endif
3065  wme_matching_this_cond->gds = inst->match_goal->id.gds;
3066  }
3067  }
3068  else
3069  {
3070  /* We know that the WME should be in the GDS of the current
3071  * goal if the WME's GDS does not already exist.
3072  * (i.e., if NIL GDS) */
3073 
3074  /* JC ADDED: Separate adding wme to GDS as a function */
3075  add_wme_to_gds(thisAgent, inst->match_goal->id.gds, wme_matching_this_cond);
3076 
3077  // wme_matching_this_cond->gds = inst->match_goal->id.gds;
3078  // insert_at_head_of_dll(wme_matching_this_cond->gds->wmes_in_gds,
3079  // wme_matching_this_cond, gds_next, gds_prev);
3080 
3081  if (wme_matching_this_cond->gds->wmes_in_gds->gds_prev)
3082  print(thisAgent, "\nDEBUG DEBUG : The new header should never have a prev value.\n");
3083 #ifdef DEBUG_GDS
3084  print_with_symbols(thisAgent, "\n ......WME did not have defined GDS. Now adding to goal [%y].\n", wme_matching_this_cond->gds->goal);
3085 #endif
3086  } /* end else clause for "if wme_matching_this_cond->gds != NIL" */
3087 
3088 
3089 #ifdef DEBUG_GDS
3090  print(thisAgent, " Added WME to GDS for goal = %d",
3091  wme_matching_this_cond->gds->goal->id.level);
3092  print_with_symbols(thisAgent, " [%y]\n", wme_matching_this_cond->gds->goal);
3093 #endif
3094  } /* end "wme in supergoal or arch-supported" */
3095  else
3096  {
3097  /* wme must be local */
3098 
3099  /* if wme's pref is o-supported, then just ignore it and
3100  * move to next condition */
3101  if (pref_for_this_wme->o_supported == TRUE) {
3102 #ifdef DEBUG_GDS
3103  print(thisAgent, " this wme is local and o-supported\n");
3104 #endif
3105  continue;
3106  }
3107 
3108  else {
3109  /* wme's pref is i-supported, so remember it's instantiation
3110  * for later examination */
3111 
3112  /* this test avoids "backtracing" through the top state */
3113  if (inst->match_goal_level == 1) {
3114 #ifdef DEBUG_GDS
3115  print(thisAgent, " don't back up through top state\n");
3116  if (inst->prod)
3117  if (inst->prod->name)
3118  print_with_symbols(thisAgent, " don't back up through top state for instantiation %y\n", inst->prod->name);
3119 #endif
3120  continue;
3121  }
3122 
3123  else { /* (inst->match_goal_level != 1) */
3124 #ifdef DEBUG_GDS
3125  print(thisAgent, " this wme is local and i-supported\n");
3126 #endif
3127  s = find_slot (pref_for_this_wme->id, pref_for_this_wme->attr);
3128  if (s == NIL)
3129  {
3130  /* this must be an arch-wme from a fake instantiation */
3131 
3132 #ifdef DEBUG_GDS
3133  print(thisAgent, "here's the wme with no slot:\t");
3134  print_wme(thisAgent, pref_for_this_wme->inst->top_of_instantiated_conditions->bt.wme_);
3135 #endif
3136 
3137  /* this is the same code as above, just using the
3138  * differently-named pointer. it probably should
3139  * be a subroutine */
3140  {
3141  wme *fake_inst_wme_cond;
3142 
3143  fake_inst_wme_cond = pref_for_this_wme->inst->top_of_instantiated_conditions->bt.wme_;
3144  if (fake_inst_wme_cond->gds != NIL)
3145  {
3146  /* Then we want to check and see if the old GDS
3147  * value should be changed */
3148  if (fake_inst_wme_cond->gds->goal == NIL)
3149  {
3150  /* The goal is NIL: meaning that the goal for
3151  * the GDS is no longer around */
3152 
3153  fast_remove_from_dll(fake_inst_wme_cond->gds->wmes_in_gds,
3154  fake_inst_wme_cond, wme,
3155  gds_next, gds_prev);
3156 
3157  /* We have to check for GDS removal anytime we take
3158  * a WME off the GDS wme list, not just when a WME
3159  * is removed from memory. */
3160  if (!fake_inst_wme_cond->gds->wmes_in_gds)
3161  {
3162  if (fake_inst_wme_cond->gds->goal) fake_inst_wme_cond->gds->goal->id.gds = NIL;
3163  free_with_pool( &( thisAgent->gds_pool ), fake_inst_wme_cond->gds );
3164 
3165 #ifdef DEBUG_GDS
3166  print(thisAgent, "\n REMOVING GDS FROM MEMORY.");
3167 #endif
3168  }
3169 
3170  /* JC ADDED: Separate adding wme to GDS as a function */
3171  add_wme_to_gds(thisAgent, inst->match_goal->id.gds, fake_inst_wme_cond);
3172 
3173  // fake_inst_wme_cond->gds = inst->match_goal->id.gds;
3174  // insert_at_head_of_dll(fake_inst_wme_cond->gds->wmes_in_gds,
3175  // fake_inst_wme_cond, gds_next, gds_prev);
3176 #ifdef DEBUG_GDS
3177  print(thisAgent, "\n .....GDS' goal is NIL so switching from old to new GDS list....\n");
3178 #endif
3179  }
3180  else if (fake_inst_wme_cond->gds->goal->id.level > inst->match_goal_level)
3181  {
3182  /* if the WME currently belongs to the GDS of a
3183  *goal below the current one */
3184  /* 1. Take WME off old (current) GDS list
3185  * 2. Check to see if old GDS WME list is empty.
3186  * If so, remove(free) it.
3187  * 3. Add WME to new GDS list
3188  * 4. Update WME pointer to new GDS list
3189  */
3190  if (inst->match_goal_level == 1)
3191  print(thisAgent, "\n\n\n\n\n HELLO! HELLO! The inst->match_goal_level is 1");
3192 
3193  fast_remove_from_dll(fake_inst_wme_cond->gds->wmes_in_gds, \
3194  fake_inst_wme_cond, wme,
3195  gds_next, gds_prev);
3196  if (!fake_inst_wme_cond->gds->wmes_in_gds)
3197  {
3198  if (fake_inst_wme_cond->gds->goal) fake_inst_wme_cond->gds->goal->id.gds = NIL;
3199  free_with_pool( &( thisAgent->gds_pool ), fake_inst_wme_cond->gds );
3200 
3201 #ifdef DEBUG_GDS
3202  print(thisAgent, "\n REMOVING GDS FROM MEMORY.");
3203 #endif
3204  }
3205 
3206  /* JC ADDED: Separate adding wme to GDS as a function */
3207  add_wme_to_gds(thisAgent, inst->match_goal->id.gds, fake_inst_wme_cond);
3208 
3209  // fake_inst_wme_cond->gds = inst->match_goal->id.gds;
3210  // insert_at_head_of_dll(fake_inst_wme_cond->gds->wmes_in_gds,
3211  // fake_inst_wme_cond, gds_next,
3212  // gds_prev);
3213 #ifdef DEBUG_GDS
3214  print(thisAgent, "\n .....switching from old to new GDS list....\n");
3215 #endif
3216  fake_inst_wme_cond->gds = inst->match_goal->id.gds;
3217  }
3218  }
3219  else
3220  {
3221  /* We know that the WME should be in the GDS of
3222  * the current goal if the WME's GDS does not
3223  * already exist. (i.e., if NIL GDS) */
3224 
3225  /* JC ADDED: Separate adding wme to GDS as a function */
3226  add_wme_to_gds(thisAgent, inst->match_goal->id.gds, fake_inst_wme_cond);
3227 
3228  // fake_inst_wme_cond->gds = inst->match_goal->id.gds;
3229  // insert_at_head_of_dll(fake_inst_wme_cond->gds->wmes_in_gds,
3230  // fake_inst_wme_cond,
3231  // gds_next, gds_prev);
3232 
3233  if (fake_inst_wme_cond->gds->wmes_in_gds->gds_prev)
3234  print(thisAgent, "\nDEBUG DEBUG : The new header should never have a prev value.\n");
3235 #ifdef DEBUG_GDS
3236  print_with_symbols(thisAgent, "\n ......WME did not have defined GDS. Now adding to goal [%y].\n", fake_inst_wme_cond->gds->goal);
3237 #endif
3238  }
3239 #ifdef DEBUG_GDS
3240  print(thisAgent, " Added WME to GDS for goal = %d", fake_inst_wme_cond->gds->goal->id.level);
3241  print_with_symbols(thisAgent, " [%y]\n",
3242  fake_inst_wme_cond->gds->goal);
3243 #endif
3244  } /* matches { wme *fake_inst_wme_cond */
3245  }
3246  else
3247  {
3248  /* this was the original "local & i-supported" action */
3249  for (pref=s->preferences[ACCEPTABLE_PREFERENCE_TYPE];
3250  pref; pref=pref->next)
3251  {
3252 
3253 #ifdef DEBUG_GDS
3254  print(thisAgent, " looking at pref for the wme: ");
3255  print_preference(thisAgent, pref);
3256 #endif
3257 
3258 
3259  /* REW: 2004-05-27: Bug fix
3260  We must check that the value with acceptable pref for the slot
3261  is the same as the value for the wme in the condition, since
3262  operators can have acceptable preferences for values other than
3263  the WME value. We dont want to backtrack thru acceptable prefs
3264  for other operators */
3265 
3266  if (pref->value == wme_matching_this_cond->value) {
3267 
3268 
3269  /* REW BUG: may have to go over all insts regardless
3270  * of this visited_already flag... */
3271 
3272  if (pref->inst->GDS_evaluated_already == FALSE)
3273  {
3274 
3275 #ifdef DEBUG_GDS
3276  print_with_symbols(thisAgent, "\n adding inst that produced the pref to GDS: %y\n",pref->inst->prod->name);
3277 #endif
3278 
3279  /* REW: 2003-12-07 */
3280  /* If the preference comes from a lower level inst, then
3281  ignore it. */
3282  /* Preferences from lower levels must come from result
3283  instantiations;
3284  we just want to use the justification/chunk
3285  instantiations at the match goal level*/
3286  if (pref->inst->match_goal_level <= inst->match_goal_level)
3287  {
3288 
3289 
3290 
3292  uniquely_add_to_head_of_dll(thisAgent, pref->inst);
3293  pref->inst->GDS_evaluated_already = TRUE;
3295  }
3296 #ifdef DEBUG_GDS
3297  else
3298  {
3299  print_with_symbols(thisAgent, "\n ignoring inst %y because it is at a lower level than the GDS\n",pref->inst->prod->name);
3300  pref->inst->GDS_evaluated_already = TRUE;
3301  }
3302 #endif
3303  /* REW: 2003-12-07 */
3304 
3306  }
3307 #ifdef DEBUG_GDS
3308  else
3309  {
3310  print(thisAgent, " the inst producing this pref was already explored; skipping it\n");
3311  }
3312 #endif
3313 
3314  }
3315 #ifdef DEBUG_GDS
3316  else
3317  {
3318  print(thisAgent, " this inst is for a pref with a differnt value than the condition WME; skippint it\n");
3319  }
3320 #endif
3321  } /* for pref = s->pref[ACCEPTABLE_PREF ...*/
3322  }
3323  }
3324  }
3325  }
3326  } /* for (cond = inst->top_of_instantiated_cond ... *;*/
3327 
3328 
3329  /* remove just used instantiation from list */
3330 
3331 #ifdef DEBUG_GDS
3332  print_with_symbols(thisAgent, "\n removing instantiation: %y\n",
3333  curr_pi->inst->prod->name);
3334 #endif
3335 
3336  if (curr_pi->next != NIL)
3337  curr_pi->next->prev = curr_pi->prev;
3338 
3339  if (curr_pi->prev != NIL)
3340  curr_pi->prev->next = curr_pi->next;
3341 
3342  if (thisAgent->parent_list_head == curr_pi)
3343  thisAgent->parent_list_head = curr_pi->next;
3344 
3345  temp_pi = curr_pi->next;
3346  free(curr_pi);
3347 
3348  } /* end of "for (curr_pi = thisAgent->parent_list_head ... */
3349 
3350 
3351  if (thisAgent->parent_list_head != NIL)
3352  {
3353 
3354 #ifdef DEBUG_GDS
3355  print(thisAgent, "\n RECURSING using these parents:\n");
3356  for (curr_pi = thisAgent->parent_list_head;
3357  curr_pi;
3358  curr_pi = curr_pi->next) {
3359  print_with_symbols(thisAgent, " %y\n",curr_pi->inst->prod->name);
3360  }
3361 #endif
3362 
3363  /* recursively explore the parents of all the instantiations */
3364 
3365  elaborate_gds(thisAgent);
3366 
3367  /* free the parent instantiation list. technically, the list
3368  * should be empty at this point ??? */
3369  free_parent_list(thisAgent);
3370  }
3371 
3372 } /* end of elaborate_gds */
3373 
3374 
3375 
3376 
3377 /* REW BUG: this needs to be smarter to deal with wmes that get support from
3378 multiple instantiations. for example ^enemy-out-there could be made by 50
3379 instantiations. if one of those instantiations goes, should the goal be
3380 killed???? This routine says "yes" -- anytime a dependent item gets changed,
3381 we're gonna yank out the goal -- even when that i-supported element itself
3382 may not be removed (due to multiple preferences). So, we'll say that this is
3383 a "twitchy" version of OPERAND2, and leave open the possibility that other
3384 approaches may be better */
3385 
3386 void gds_invalid_so_remove_goal (agent* thisAgent, wme *w) {
3387 
3388  if (thisAgent->soar_verbose_flag || thisAgent->sysparams[TRACE_GDS_SYSPARAM]) {
3389  // BADBAD: the XML code makes this all very ugly
3390  char msgbuf[256];
3391  memset(msgbuf, 0, 256);
3392  snprintf_with_symbols(thisAgent, msgbuf, 255, "Removing state %y because element in GDS changed. WME: ", w->gds->goal);
3393  print_string(thisAgent, msgbuf);
3394 
3395  xml_begin_tag(thisAgent, soar_TraceNames::kTagVerbose);
3396  xml_att_val(thisAgent, soar_TraceNames::kTypeString, msgbuf);
3397  print_wme(thisAgent, w); // prints XML, too
3398  xml_end_tag(thisAgent, soar_TraceNames::kTagVerbose);
3399  }
3400 
3401  /* REW: begin 11.25.96 */
3402 #ifndef NO_TIMING_STUFF
3403 #ifdef DETAILED_TIMING_STATS
3404  thisAgent->timers_gds.start();
3405 #endif
3406 #endif
3407  /* REW: end 11.25.96 */
3408 
3409  /* This call to GDS_PrintCmd will have to be uncommented later. -ajc */
3410  //if (thisAgent->soar_verbose_flag) {} //GDS_PrintCmd();
3411 
3412  /* REW: BUG. I have no idea right now if this is a terrible hack or
3413  * actually what we want to do. The idea here is that the context of
3414  * the immediately higher goal above a retraction should be marked as
3415  * having its context changed in order that the architecture doesn't
3416  * look below this level for context changes. I think it's a hack b/c
3417  * it seems like there should aready be mechanisms for doing this in
3418  * the architecture but I couldn't find any.
3419  */
3420  /* Note: the inner 'if' is correct -- we only want to change
3421  * highest_goal_whose_context_changed if the pointer is currently at
3422  * or below (greater than) the goal which we are going to retract.
3423  * However, I'm not so sure about the outer 'else.' If we don't set
3424  * this to the goal above the retraction, even if the current value
3425  * is NIL, we still seg fault in certain cases. But setting it as we do
3426  * in the inner 'if' seems to clear up the difficulty.
3427  */
3428 
3429  if (thisAgent->highest_goal_whose_context_changed)
3430  {
3431  if (thisAgent->highest_goal_whose_context_changed->id.level >= w->gds->goal->id.level)
3432  {
3434  }
3435  }
3436  else
3437  {
3438  /* If nothing has yet changed (highest_ ... = NIL) then set
3439  * the goal automatically */
3441 
3442  // Tell those slots they are changed so that the impasses can be regenerated
3443  // bug 1011
3444  for ( slot* s = thisAgent->highest_goal_whose_context_changed->id.slots; s != 0; s = s->next )
3445  {
3446  if (s->isa_context_slot && !s->changed)
3447  s->changed = reinterpret_cast<dl_cons*>(1); // use non-zero value to indicate change, see definition of slot::changed
3448  }
3449  }
3450 
3452  {
3453  print_with_symbols(thisAgent, "\n REMOVING GOAL [%y] due to change in GDS WME ", w->gds->goal);
3454  print_wme(thisAgent, w);
3455  }
3456 
3458 
3459  /* BUG: Need to reset highest_goal here ???*/
3460 
3461  /* usually, we'd call do_buffered_wm_and_ownership_changes() here, but
3462  * we don't need to because it will be done at the end of the working
3463  * memory phase; cf. the end of do_working_memory_phase().
3464  */
3465 
3466  /* REW: begin 11.25.96 */
3467 #ifndef NO_TIMING_STUFF
3468 #ifdef DETAILED_TIMING_STATS
3469  thisAgent->timers_gds.stop();
3470  thisAgent->timers_gds_cpu_time[thisAgent->current_phase].update(thisAgent->timers_gds);
3471 #endif
3472 #endif
3473  /* REW: end 11.25.96 */
3474 }
3475 
3476 
3477 void free_parent_list(agent* thisAgent)
3478 {
3479  parent_inst *curr_pi;
3480 
3481  for (curr_pi = thisAgent->parent_list_head;
3482  curr_pi;
3483  curr_pi = curr_pi->next)
3484  free(curr_pi);
3485 
3486  thisAgent->parent_list_head = NIL;
3487 }
3488 
3489 void create_gds_for_goal( agent* thisAgent, Symbol *goal){
3490  goal_dependency_set *gds;
3491 
3492  allocate_with_pool( thisAgent, &( thisAgent->gds_pool ), &gds );
3493 
3494  gds->goal = goal;
3495  gds->wmes_in_gds = NIL;
3496  goal->id.gds = gds;
3497  #ifdef DEBUG_GDS
3498  print_with_symbols(thisAgent, "\nCreated GDS for goal [%y].\n", gds->goal);
3499  #endif
3500 }