Soar Kernel  9.3.2 08-06-12
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
consistency.cpp
Go to the documentation of this file.
1 #include <portability.h>
2 
3 /*************************************************************************
4  * PLEASE SEE THE FILE "license.txt" (INCLUDED WITH THIS SOFTWARE PACKAGE)
5  * FOR LICENSE AND COPYRIGHT INFORMATION.
6  *************************************************************************/
7 
8 /*************************************************************************
9  *
10  * file: consistency.cpp
11  *
12  * =======================================================================
13  *
14  * Source code for Operand2/Waterfall specific functions in the kernel.
15  *
16  * =======================================================================
17  * Revision history:
18  *
19  * 05 May 97: Created for version 2.0 of Operand2
20  * REW
21  *
22  * 20 Aug 97: Version 2.1 of Operand2/Waterfall
23  * Reimplemented the Waterfall functions with a more efficient algorithm
24  * REW
25  *
26  */
27 
28 #include <stdlib.h>
29 
30 #include "consistency.h"
31 #include "agent.h"
32 #include "print.h"
33 #include "decide.h"
34 #include "symtab.h"
35 #include "production.h"
36 #include "init_soar.h"
37 #include "rete.h"
38 #include "wmem.h"
39 #include "xml.h"
40 
41 void remove_operator_if_necessary(agent* thisAgent, slot *s, wme *w){
42 
43 /* REW: begin 11.25.96 */
44 #ifndef NO_TIMING_STUFF
45 #ifdef DETAILED_TIMING_STATS
46 thisAgent->timers_gds.start();
47 #endif
48 #endif
49 /* REW: end 11.25.96 */
50 
51 /* printf("Examining slot (next)\n");
52 for (next = s; next; next=next->next){
53  print_with_symbols("Slot ID: [%y]\n", next->id);
54  print_with_symbols("Slot Attr: [%y]\n", next->attr);
55 }
56 
57  printf("Examining slot (prev)\n");
58 for (prev = s->prev; prev; prev=prev->prev){
59  print_with_symbols("Slot ID: [%y]\n", prev->id);
60  print_with_symbols("Slot Attr: [%y]\n", prev->attr);
61 }
62 
63 printf("Examining slot WMEs\n");
64 for (slot_wmes=s->wmes; slot_wmes; slot_wmes=slot_wmes->next){
65  print_wme(thisAgent, slot_wmes);
66 }
67 
68 printf("Examining acceptable preference WMEs\n");
69 for (slot_wmes=s->acceptable_preference_wmes; slot_wmes; slot_wmes=slot_wmes->next){
70  print_wme(thisAgent, slot_wmes);
71 }
72 
73 if (thisAgent->highest_goal_whose_context_changed) print_with_symbols("Highest goal with changed context: [%y]\n", thisAgent->highest_goal_whose_context_changed);
74 
75 print_with_symbols("Slot ID: [%y]\n", s->id);
76 print_with_symbols("Slot Attr: [%y]\n", s->attr);
77 if (s->isa_context_slot) printf("this is a context slot.\n");
78 if (s->impasse_id) print_with_symbols("Impasse: [%y]\n", s->impasse_id);
79 if (s->acceptable_preference_changed) printf("Acceptable pref changed\n");
80 
81 print_with_symbols("WME ID: [%y]\n", w->id);
82 print_with_symbols("WME Attr: [%y]\n", w->attr);
83 print_with_symbols("WME Value: [%y]\n", w->value);
84 if (w->value->id.isa_operator) printf("This is an operator\n");
85 
86 print_with_symbols("s->id->id.operator_slot->id: [%y]\n", s->id->id.operator_slot->id); */
87 
88 if (s->wmes) { /* If there is something in the context slot */
89  if (s->wmes->value == w->value) { /* The WME in the context slot is WME whose pref changed */
91  print(thisAgent, "\n REMOVING: Operator from context slot (proposal no longer matches): ");
92  print_wme(thisAgent, w);
93  }
94  remove_wmes_for_context_slot (thisAgent, s);
95  if (s->id->id.lower_goal)
96  {
97  if ( thisAgent->soar_verbose_flag || thisAgent->sysparams[TRACE_WM_CHANGES_SYSPARAM] )
98  print_with_symbols(thisAgent, "Removing state %y because of an operator removal.\n", s->id->id.lower_goal);
99 
101  }
102  }
103 }
104 
105 /* REW: begin 11.25.96 */
106 #ifndef NO_TIMING_STUFF
107 #ifdef DETAILED_TIMING_STATS
108 thisAgent->timers_gds.stop();
109 thisAgent->timers_gds_cpu_time[thisAgent->current_phase].update(thisAgent->timers_gds);
110 #endif
111 #endif
112 /* REW: end 11.25.96 */
113 }
114 
115 
116 
117 /* This code concerns the implementation of a 'consistency check' following
118  each IE phase. The basic idea is that we want context decisions to
119  remain consistent with the current preferences, even if the proposal
120  for some operator is still acceptable */
121 
123  byte current_impasse_type, new_impasse_type;
124  Symbol *current_impasse_attribute;
125  wme *current_operator;
126  preference *candidates, *cand;
127  Bool operator_in_slot, goal_is_impassed;
128 
129 #ifdef DEBUG_CONSISTENCY_CHECK
130  if (s->isa_context_slot) {
131  printf(" slot (s) isa context slot: ");
132  print_with_symbols(thisAgent, " Slot Identifier [%y] and attribute [%y]\n", s->id, s->attr);
133  }
134  /* printf(" Address of s: %x\n", s); */
135  printf(" s->impasse_type: %d\n", s->impasse_type);
136  if (s->impasse_id) printf(" Impasse ID is set (non-NIL)\n");
137 #endif
138 
139  /* Determine the current operator/impasse in the slot*/
140  if (goal->id.operator_slot->wmes) {
141  /* There is an operator in the slot */
142  current_operator = goal->id.operator_slot->wmes;
143  operator_in_slot = TRUE;
144  } else {
145  /* There is not an operator in the slot */
146  current_operator = NIL;
147  operator_in_slot = FALSE;
148  }
149 
150  if (goal->id.lower_goal){
151  /* the goal is impassed */
152  goal_is_impassed = TRUE;
153  current_impasse_type = type_of_existing_impasse(thisAgent, goal);
154  current_impasse_attribute = attribute_of_existing_impasse(thisAgent, goal);
155 #ifdef DEBUG_CONSISTENCY_CHECK
156  printf(" Goal is impassed: Impasse type: %d: ", current_impasse_type);
157  print_with_symbols(thisAgent, " Impasse attribute: [%y]\n", current_impasse_attribute);
158 #endif
159  /* Special case for an operator no-change */
160  if ((operator_in_slot) &&
161  (current_impasse_type == NO_CHANGE_IMPASSE_TYPE)) {
162  /* Operator no-change impasse: run_preference_semantics will return 0
163  and we only want to blow away this operator if another is better
164  than it (checked in NONE_IMPASSE_TYPE switch) or if another kind
165  of impasse would be generated (e.g., OPERATOR_TIE). So, we set
166  the impasse type here to 0; that way we'll know that we should be
167  comparing a previous decision for a unique operator against the
168  current preference semantics. */
169 #ifdef DEBUG_CONSISTENCY_CHECK
170  printf(" This is an operator no-change impasse.\n");
171 #endif
172  current_impasse_type = NONE_IMPASSE_TYPE;
173  }
174  } else {
175  goal_is_impassed = FALSE;
176  current_impasse_type = NONE_IMPASSE_TYPE;
177  current_impasse_attribute = NIL;
178 #ifdef DEBUG_CONSISTENCY_CHECK
179  printf(" Goal is not impassed: ");
180 #endif
181  }
182 
183  /* Determine the new impasse type, based on the preferences that exist now */
184  new_impasse_type = run_preference_semantics_for_consistency_check (thisAgent, s, &candidates);
185 
186 #ifdef DEBUG_CONSISTENCY_CHECK
187  printf(" Impasse Type returned by run preference semantics: %d\n", new_impasse_type);
188 
189  for (cand = candidates; cand; cand=cand->next) {
190  printf(" Preference for slot:");
191  print_preference(thisAgent, cand);
192  }
193 
194  for (cand = candidates; cand; cand=cand->next_candidate) {
195  printf("\n Candidate for slot:");
196  print_preference(thisAgent, cand);
197  }
198 #endif
199 
200  if (current_impasse_type != new_impasse_type) {
201  /* Then there is an inconsistency: no more work necessary */
202 #ifdef DEBUG_CONSISTENCY_CHECK
203  printf(" Impasse types are different: Returning FALSE, preferences are not consistent with prior decision.\n");
204 #endif
205  return FALSE;
206  }
207 
208 
209 
210  /* in these cases, we know that the new impasse and the old impasse *TYPES* are the same. We
211  just want to check and make the actual impasses/decisions are the same. */
212  switch (new_impasse_type) {
213 
214  case NONE_IMPASSE_TYPE:
215  /* There are four cases to consider when NONE_IMPASSE_TYPE is returned: */
216  /* 1. Previous operator and operator returned by run_pref_sem are the same.
217  In this case, return TRUE (decision remains consistent) */
218 
219  /* This next if is meant to test that there actually is something in the slot but
220  I'm nut quite certain that it will not always be true? */
221  if (operator_in_slot){
222 #ifdef DEBUG_CONSISTENCY_CHECK
223  printf(" There is a WME in the operator slot:"); print_wme(current_operator);
224 #endif
225 
226  /* Because of indifferent preferences, we need to compare all possible candidates
227  with the current decision */
228  for (cand = candidates; cand; cand=cand->next_candidate) {
229  if (current_operator->value == cand->value) {
230 #ifdef DEBUG_CONSISTENCY_CHECK
231  print_with_symbols(thisAgent, " Operator slot ID [%y] and candidate ID [%y] are the same.\n",
232  current_operator->value,
233  cand->value);
234 #endif
235  return TRUE;
236  }
237  }
238 
239  /* 2. A different operator is indicated for the slot than the one that is
240  currently installed. In this case, we return FALSE (the decision is
241  not consistent with the preferences). */
242 
243  /* Now we know that the decision is inconsistent */
244  return FALSE;
245 
246  /* 3. A single operator is suggested when an impasse existed previously.
247  In this case, return FALSE so that the impasse can be removed. */
248 
249  } else { /* There is no operator in the slot */
250  if (goal->id.lower_goal) { /* But there is an impasse */
251  if (goal->id.lower_goal->id.isa_impasse) printf("This goal is an impasse\n");
252  printf(" No Impasse Needed but Impasse exists: remove impasse now\n");
253  printf("\n\n *************This should never be executed*******************\n\n");
254  return FALSE;
255  }
256  }
257 
258  /* 4. This is the bottom goal in the stack and there is no operator or
259  impasse for the operator slot created yet. We shouldn't call this
260  routine in this case (this condition is checked before
261  decision_consistent_with_current_preferences is called) but, for
262  completeness' sake, we check this condition and return TRUE
263  (because no decision has been made at this level, there is no
264  need to remove anything). */
265  printf("\n\n *************This should never be executed*******************\n\n");
266  return TRUE;
267  break;
268 
270 #ifdef DEBUG_CONSISTENCY_CHECK
271  printf(" Constraint Failure Impasse: Returning TRUE\n");
272 #endif
273  return TRUE;
274  break;
275 
277 #ifdef DEBUG_CONSISTENCY_CHECK
278  printf(" Conflict Impasse: Returning TRUE\n");
279 #endif
280  return TRUE;
281  break;
282 
283  case TIE_IMPASSE_TYPE:
284 #ifdef DEBUG_CONSISTENCY_CHECK
285  printf(" Tie Impasse: Returning TRUE\n");
286 #endif
287  return TRUE;
288  break;
289 
291 #ifdef DEBUG_CONSISTENCY_CHECK
292  printf(" No change Impasse: Returning TRUE\n");
293 #endif
294  return TRUE;
295  break;
296  }
297 
298  printf("\n After switch................");
299  printf("\n\n *************This should never be executed*******************\n\n");
300  return TRUE;
301 
302 
303 }
304 
305 void remove_current_decision(agent* thisAgent, slot *s) {
306 
307  if (!s->wmes)
308  if (thisAgent->sysparams[TRACE_OPERAND2_REMOVALS_SYSPARAM]) print_with_symbols(thisAgent, "\n REMOVING CONTEXT SLOT: Slot Identifier [%y] and attribute [%y]\n", s->id, s->attr);
309 
310  if (s->id)
311  if (thisAgent->sysparams[TRACE_OPERAND2_REMOVALS_SYSPARAM]) print_with_symbols(thisAgent, "\n Decision for goal [%y] is inconsistent. Replacing it with....\n", s->id);
312 
313  /* If there is an operator in the slot, remove it */
314  remove_wmes_for_context_slot (thisAgent, s);
315 
316  /* If there are any subgoals, remove those */
318 
320 
321 }
322 
323 /* ------------------------------------------------------------------
324  Check Context Slot Decisions
325 
326  This scans down the goal stack and checks the consistency of the current
327  decision versus the current preferences for the slot, if the preferences
328  have changed.
329 ------------------------------------------------------------------ */
330 
331 
333  Symbol *goal;
334  slot *s;
335 
336 #ifdef DEBUG_CONSISTENCY_CHECK
337  if (thisAgent->highest_goal_whose_context_changed)
338  print_with_symbols(thisAgent, " Highest goal with changed context: [%y]\n", thisAgent->highest_goal_whose_context_changed);
339 #endif
340 
341 /* REW: begin 05.05.97 */
342  /* Check only those goals where preferences have changes that are at or above the level
343  of the consistency check */
344  for (goal=thisAgent->highest_goal_whose_context_changed; goal && goal->id.level <= level; goal=goal->id.lower_goal) {
345 /* REW: end 05.05.97 */
346 #ifdef DEBUG_CONSISTENCY_CHECK
347  print_with_symbols(thisAgent, " Looking at goal [%y] to see if its preferences have changed\n", goal);
348 #endif
349  s = goal->id.operator_slot;
350 
351  if ((goal->id.lower_goal) ||
352  (s->wmes)) { /* If we are not at the bottom goal or if there is an operator in the
353  bottom goal's operator slot */
354 #ifdef DEBUG_CONSISTENCY_CHECK
355  printf(" This is a goal that either has subgoals or, if the bottom goal, has an operator in the slot\n");
356 #endif
357  if (s->changed) { /* Only need to check a goal if its prefs have changed */
358 #ifdef DEBUG_CONSISTENCY_CHECK
359  printf(" This goal's preferences have changed.\n");
360 #endif
361  if (!decision_consistent_with_current_preferences(thisAgent, goal,s)) {
362 #ifdef DEBUG_CONSISTENCY_CHECK
363  print_with_symbols(thisAgent, " The current preferences indicate that the decision at [%y] needs to be removed.\n", goal);
364 #endif
365  if ( thisAgent->soar_verbose_flag || thisAgent->sysparams[TRACE_WM_CHANGES_SYSPARAM] )
366  print_with_symbols(thisAgent, "Removing state %y because of a failed consistency check.\n", goal);
367  /* This doesn;t seem like it should be necessary but evidently it is: see 2.008 */
368  remove_current_decision(thisAgent, s);
369  return FALSE;
370  break; /* No need to continue once a decision is removed */
371  }
372  }
373  }
374 #ifdef DEBUG_CONSISTENCY_CHECK
375  else {
376  printf(" This is a bottom goal with no operator in the slot\n");
377  }
378 #endif
379  }
380 
381  return TRUE;
382 }
383 
384 /* REW: begin 08.20.97 */
385 
387 
388  /* print_with_symbols("\nLooking for I-activity at goal: %y\n", goal); */
389 
390  if (goal->id.ms_i_assertions)
391  return TRUE;
392 
393  if (goal->id.ms_retractions)
394  return TRUE;
395 
396 
397  /* printf("\nNo instantiation found. Returning FALSE\n"); */
398  return FALSE;
399 }
400 
401 /* Minor Quiescence at GOAL
402 
403  This procedure returns TRUE if the current firing type is IE_PRODS and
404  there are no i-assertions (or any retractions) ready to fire in the
405  current GOAL. Else it returns FALSE. */
406 
407 
409 
410  if ((thisAgent->FIRING_TYPE == IE_PRODS) &&
411  (!i_activity_at_goal(goal)))
412  /* firing IEs but no more to fire == minor quiescence */
413  return TRUE;
414  else
415  return FALSE;
416 }
417 
418 /* ---------------------------------------------------------------------- */
419 /* Find the highest goal of activity among the current assertions and
420  * retractions */
421 
422 /* We have to start at the top of the goal stack (not anymore, see next comment)
423  * and go down because *any*
424  * goal in the goal stack could be active (and we want to highest one).
425  * However, we terminate as soon as a goal with assertions or retractions
426  * is found. Propose cares only about ms_i_assertions & retractions
427  *
428  * Modified for new waterfall to increase code reuse, now it takes a start_goal
429  * which is used as the top of the stack to look down. In the new waterfall
430  * model, we sometimes don't want to look for active goals starting at the
431  * highest state, this allows us to be flexible.
432  */
433 
434 Symbol * highest_active_goal_propose(agent* thisAgent, Symbol* start_goal, Bool noneOk) {
435 
436  Symbol *goal;
437 
438  for (goal=start_goal; goal; goal=goal->id.lower_goal) {
439 
440 #ifdef DEBUG_DETERMINE_LEVEL_PHASE
441  /* Debugging only */
442  print(thisAgent, "In highest_active_goal_propose:\n");
445 #endif
446 
447  /* If there are any active productions at this goal, return the goal */
448  if ((goal->id.ms_i_assertions) || (goal->id.ms_retractions)) return goal;
449  }
450 
451  /* This routine should only be called when !quiescence. However, there is
452  still the possibility that the only active productions are retractions
453  that matched in a NIL goal. If so, then we just return the bottom goal.
454  If not, then all possibilities have been exausted and we have encounted
455  an unrecoverable error. */
456 
457 #ifdef DEBUG_DETERMINE_LEVEL_PHASE
458  print(thisAgent, "WARNING: Returning NIL active goal because only NIL goal retractions are active.");
459  xml_generate_warning(thisAgent, "WARNING: Returning NIL active goal because only NIL goal retractions are active.");
460 #endif
461  if (thisAgent->nil_goal_retractions)
462  return NIL;
463 
464  if (!noneOk) {
465  char msg[BUFFER_MSG_SIZE];
466  strncpy(msg, "\n consistency.c: Error: Unable to find an active goal when not at quiescence.\n", BUFFER_MSG_SIZE);
467  msg[BUFFER_MSG_SIZE - 1] = 0; /* ensure null termination */
468  abort_with_fatal_error(thisAgent, msg);
469  }
470 
471  return NIL;
472 }
473 
474 Symbol * highest_active_goal_apply(agent* thisAgent, Symbol* start_goal, Bool noneOk) {
475 
476  Symbol *goal;
477 
478  for (goal=start_goal; goal; goal=goal->id.lower_goal) {
479 
480 #if 0 //DEBUG_DETERMINE_LEVEL_PHASE
481  /* Debugging only */
482  print(thisAgent, "In highest_active_goal_apply :\n");
486 #endif
487 
488  /* If there are any active productions at this goal, return the goal */
489  if ((goal->id.ms_i_assertions) || (goal->id.ms_o_assertions)
490  || (goal->id.ms_retractions)) return goal;
491  }
492 
493  /* This routine should only be called when !quiescence. However, there is
494  still the possibility that the only active productions are retractions
495  that matched in a NIL goal. If so, then we just return the bottom goal.
496  If not, then all possibilities have been exausted and we have encounted
497  an unrecoverable error. */
498 
499 #ifdef DEBUG_DETERMINE_LEVEL_PHASE
500  print(thisAgent, "WARNING: Returning NIL active goal because only NIL goal retractions are active.");
501  xml_generate_warning(thisAgent, "WARNING: Returning NIL active goal because only NIL goal retractions are active.");
502 #endif
503  if (thisAgent->nil_goal_retractions)
504  return NIL;
505 
506  if (!noneOk) {
507  char msg[BUFFER_MSG_SIZE];
508  strncpy(msg, "\nconsistency.c: Error: Unable to find an active goal when not at quiescence.\n", BUFFER_MSG_SIZE);
509  msg[BUFFER_MSG_SIZE - 1] = 0; /* ensure null termination */
510  abort_with_fatal_error(thisAgent, msg);
511  }
512 
513  return NIL;
514 }
515 
516 /* ---------------------------------------------------------------------- */
517 
518 /* active_production_type_at_goal
519 
520  Determines type of productions active at some active level. If
521  IE PRODS are active, this value is returned (regardless of whether there
522  are PEs active or not). Note that this procedure will return erroneous
523  values if there is no activity at the current level. It should only be
524  called when activity at the active_level has been determined. */
525 
527 
528  if (i_activity_at_goal(goal))
529  return IE_PRODS;
530  else
531  return PE_PRODS;
532 }
533 
534 
535 /* ---------------------------------------------------------------------- */
536 
538  Bool test;
539 
540 #ifndef NO_TIMING_STUFF
541 #ifdef DETAILED_TIMING_STATS
542  thisAgent->timers_gds.start();
543 #endif
544 #endif
545 
546 #ifdef DEBUG_CONSISTENCY_CHECK
547  print(thisAgent, "\nStart: CONSISTENCY CHECK at level %d\n", goal->id.level);
548 
549  /* Just a bunch of debug stuff for now */
550  if (thisAgent->highest_goal_whose_context_changed){
551  print_with_symbols(thisAgent, "current_agent(highest_goal_whose_context_changed) = [%y]\n",
553  } else {
554  printf("Evidently, nothing has changed: not checking slots\n");
555  }
556 #endif
557 
558  test = check_context_slot_decisions(thisAgent, goal->id.level);
559 
560 #ifdef DEBUG_CONSISTENCY_CHECK
561  printf("\nEnd: CONSISTENCY CHECK\n");
562 #endif
563 
564 #ifndef NO_TIMING_STUFF
565 #ifdef DETAILED_TIMING_STATS
566  thisAgent->timers_gds.stop();
567  thisAgent->timers_gds_cpu_time[thisAgent->current_phase].update(thisAgent->timers_gds);
568 #endif
569 #endif
570 
571  return test;
572 }
573 /* REW: end 08.20.97 */
574 
575 
576 /* ---------------------------------------------------------------------- */
577 
578 /* REW: begin 05.05.97 */
579 
581 
582  Symbol *goal;
583 
584 #ifdef DEBUG_DETERMINE_LEVEL_PHASE
585  printf("\nInitialize consistency calculations for new decision.\n");
586 #endif
587 
588  /* No current activity level */
589  thisAgent->active_level = 0;
590  thisAgent->active_goal = NIL;
591 
592  /* Clear any interruption flags on the goals....*/
593  for(goal=thisAgent->top_goal; goal; goal=goal->id.lower_goal)
595 }
596 
597 /* ---------------------------------------------------------------------- */
598 
599  /* determine_highest_active_production_level_in_stack_apply()
600 
601  This routine is responsible for implementing the DETERMINE_LEVEL_PHASE.
602  In the Waterfall version of Soar, the DETERMINE_LEVEL_PHASE makes the
603  determination of what goal level is active in the stack. Activity
604  proceeds from top goal to bottom goal so the active goal is the goal
605  highest in the stack with productions waiting to fire. This procedure
606  also recognizes quiescence (no productions active anywhere) and
607  mini-quiescence (no more IE_PRODS are waiting to fire in some goal for a
608  goal that fired IE_PRODS in the previous elaboration). Mini-quiescence is
609  followed by a consistency check. */
610 
612 
613  Symbol * goal;
614  int level_change_type, diff;
615 
616  /* KJC 04/05 - moved phase printing to init_soar: do_one_top_level_phase, case APPLY */
617 
618 
619  #ifdef DEBUG_DETERMINE_LEVEL_PHASE
620  printf("\nDetermining the highest active level in the stack....\n");
621  #endif
622 
623  if (!any_assertions_or_retractions_ready(thisAgent))
624  {
625  /* This is quiescence */
626  #ifdef DEBUG_DETERMINE_LEVEL_PHASE
627  printf("\n(Full) APPLY phase Quiescence has been reached...going to output\n");
628  #endif
629 
630  /* Need to determine if this quiescence is also a minor quiescence,
631  otherwise, an inconsistent decision could get retained here (because
632  the consistency check was never run). (2.008). Therefore, if
633  in the previous preference phase, IE_PRODS fired, then force a
634  consistency check over the entire stack (by checking at the
635  bottom goal). */
636 
637  if (minor_quiescence_at_goal(thisAgent, thisAgent->bottom_goal))
638  {
639  goal_stack_consistent_through_goal(thisAgent, thisAgent->bottom_goal);
640  }
641 
642  /* regardless of the outcome, we go to the output phase */
643 
644  thisAgent->current_phase = OUTPUT_PHASE;
645  return;
646  }
647 
648  /* Not Quiescence */
649 
650  /* Check for Max ELABORATIONS EXCEEDED */
651 
652  if (thisAgent->e_cycles_this_d_cycle >=
653  static_cast<uint64_t>(thisAgent->sysparams[MAX_ELABORATIONS_SYSPARAM]))
654  {
655  if (thisAgent->sysparams[PRINT_WARNINGS_SYSPARAM]) {
656  print(thisAgent, "\nWarning: reached max-elaborations; proceeding to output phase.");
657  xml_generate_warning(thisAgent, "Warning: reached max-elaborations; proceeding to output phase.");
658  }
659  thisAgent->current_phase = OUTPUT_PHASE;
660  return;
661  }
662 
663  /* Save the old goal and level (must save level explicitly in case goal is NIL) */
664  thisAgent->previous_active_goal = thisAgent->active_goal;
665  thisAgent->previous_active_level = thisAgent->active_level;
666 
667  /* Determine the new highest level of activity */
668  thisAgent->active_goal = highest_active_goal_apply(thisAgent, thisAgent->top_goal, FALSE);
669  if (thisAgent->active_goal)
670  thisAgent->active_level = thisAgent->active_goal->id.level;
671  else
672  thisAgent->active_level = 0; /* Necessary for get_next_retraction */
673 
674  #ifdef DEBUG_DETERMINE_LEVEL_PHASE
675  printf("\nHighest level of activity is....%d", thisAgent->active_level);
676  printf("\n Previous level of activity is....%d", thisAgent->previous_active_level);
677  #endif
678 
679  if (!thisAgent->active_goal)
680  /* Only NIL goal retractions */
681  level_change_type = NIL_GOAL_RETRACTIONS;
682  else if (thisAgent->previous_active_level == 0)
683  level_change_type = NEW_DECISION;
684  else
685  {
686  diff = thisAgent->active_level - thisAgent->previous_active_level;
687  if (diff == 0)
688  level_change_type = SAME_LEVEL;
689  else if (diff > 0)
690  level_change_type = LOWER_LEVEL;
691  else
692  level_change_type = HIGHER_LEVEL;
693  }
694 
695 
696  switch (level_change_type)
697  {
699  #ifdef DEBUG_DETERMINE_LEVEL_PHASE
700  print(thisAgent, "\nOnly NIL goal retractions are active");
701  #endif
702  thisAgent->FIRING_TYPE = IE_PRODS;
703  //thisAgent->current_phase = PREFERENCE_PHASE;
704  break;
705 
706  case NEW_DECISION:
707  #ifdef DEBUG_DETERMINE_LEVEL_PHASE
708  print(thisAgent, "\nThis is a new decision....");
709  #endif
710  thisAgent->FIRING_TYPE = active_production_type_at_goal(thisAgent->active_goal);
711  /* in APPLY phase, we can test for ONC here, check ms_o_assertions */
712  // KJC: thisAgent->current_phase = PREFERENCE_PHASE;
713  break;
714 
715  case LOWER_LEVEL:
716  #ifdef DEBUG_DETERMINE_LEVEL_PHASE
717  print(thisAgent, "\nThe level is lower than the previous level....");
718  #endif
719  /* Is there a minor quiescence at the previous level? */
720  if (minor_quiescence_at_goal(thisAgent, thisAgent->previous_active_goal)) {
721  #ifdef DEBUG_DETERMINE_LEVEL_PHASE
722  printf("\nMinor quiescence at level %d", thisAgent->previous_active_level);
723  #endif
724  if (!goal_stack_consistent_through_goal(thisAgent, thisAgent->previous_active_goal))
725  {
726  thisAgent->current_phase = OUTPUT_PHASE;
727  break;
728  }
729  }
730 
731  /* else: check if return to interrupted level */
732 
733  goal = thisAgent->active_goal;
734 
735  #ifdef DEBUG_DETERMINE_LEVEL_PHASE
736  if (goal->id.saved_firing_type == IE_PRODS)
737  print(thisAgent, "\nSaved production type: IE _PRODS");
738  if (goal->id.saved_firing_type == PE_PRODS)
739  print(thisAgent, "\nSaved production type: PE _PRODS");
740  if (goal->id.saved_firing_type == NO_SAVED_PRODS)
741  print(thisAgent, "\nSaved production type: NONE");
742  #endif
743 
744  if (goal->id.saved_firing_type != NO_SAVED_PRODS) {
745  #ifdef DEBUG_DETERMINE_LEVEL_PHASE
746  print(thisAgent, "\nRestoring production type from previous processing at this level");
747  #endif
748  thisAgent->FIRING_TYPE = goal->id.saved_firing_type;
749  // KJC 04.05 commented the next line after reworking the phases in init_soar.cpp
750  // thisAgent->current_phase = DETERMINE_LEVEL_PHASE;
751  // Reluctant to make this a recursive call, but somehow we need to go thru
752  // and determine which level we should start with now that we've
753  // returned from a lower level (solved a subgoal or changed the conditions).
754  // We could return a flag instead and test it everytime thru loop in APPLY.
756 
757  break;
758  }
759 
760  /* else: just do a preference phase */
761  thisAgent->FIRING_TYPE = active_production_type_at_goal(thisAgent->active_goal);
762  //KJC: thisAgent->current_phase = PREFERENCE_PHASE;
763  break;
764 
765  case SAME_LEVEL:
766  #ifdef DEBUG_DETERMINE_LEVEL_PHASE
767  print(thisAgent, "\nThe level is the same as the previous level....");
768  #endif
769  if (minor_quiescence_at_goal(thisAgent, thisAgent->active_goal)) {
770  #ifdef DEBUG_DETERMINE_LEVEL_PHASE
771  printf("\nMinor quiescence at level %d", thisAgent->active_level);
772  #endif
773  if (!goal_stack_consistent_through_goal(thisAgent, thisAgent->active_goal)) {
774  thisAgent->current_phase = OUTPUT_PHASE;
775  break;
776  }
777  }
778  thisAgent->FIRING_TYPE = active_production_type_at_goal(thisAgent->active_goal);
779  //thisAgent->current_phase = PREFERENCE_PHASE;
780  break;
781 
782  case HIGHER_LEVEL:
783  #ifdef DEBUG_DETERMINE_LEVEL_PHASE
784  print(thisAgent, "\nThe level is higher than the previous level....");
785  #endif
786 
787  goal = thisAgent->previous_active_goal;
788  goal->id.saved_firing_type = thisAgent->FIRING_TYPE;
789 
790  #ifdef DEBUG_DETERMINE_LEVEL_PHASE
791  if (goal->id.saved_firing_type == IE_PRODS)
792  print(thisAgent, "\n Saving current firing type as IE_PRODS");
793  else if (goal->id.saved_firing_type == PE_PRODS)
794  print(thisAgent, "\n Saving current firing type as PE_PRODS");
795  else if (goal->id.saved_firing_type == NO_SAVED_PRODS)
796  print(thisAgent, "\n Saving current firing type as NO_SAVED_PRODS");
797  else
798  print(thisAgent, "\n Unknown SAVED firing type???????");
799  #endif
800 
801  /* run consistency check at new active level *before* firing any
802  productions there */
803 
804  #ifdef DEBUG_DETERMINE_LEVEL_PHASE
805  printf("\nMinor quiescence at level %d", thisAgent->active_level);
806  #endif
807  if (!goal_stack_consistent_through_goal(thisAgent, thisAgent->active_goal))
808  {
809  thisAgent->current_phase = OUTPUT_PHASE;
810  break;
811  }
812 
813  /* If the decision is consistent, then just start processing at this level */
814  thisAgent->FIRING_TYPE = active_production_type_at_goal(thisAgent->active_goal);
815  //thisAgent->current_phase = PREFERENCE_PHASE;
816  break;
817  }
818 
819 }
820 /* REW: end 05.05.97 */
821 
822 /* KJC: begin 10.04.98 */ /* swiped from REW's determine_highest_active... */
823 /* ---------------------------------------------------------------------- */
824 
825  /* determine_highest_active_production_level_in_stack_propose()
826 
827  This routine is called from the Propose Phase
828  under the new reordering of the Decision Cycle.
829  In the Waterfall version of Soar, the this routine makes the
830  determination of what goal level is active in the stack. Activity
831  proceeds from top goal to bottom goal so the active goal is the goal
832  highest in the stack with productions waiting to fire. This procedure
833  also recognizes quiescence (no productions active anywhere) and
834  mini-quiescence (no more IE_PRODS are waiting to fire in some goal for a
835  goal that fired IE_PRODS in the previous elaboration). Mini-quiescence is
836  followed by a consistency check. */
837 
838  /* This routine could be further pruned, since with 8.6.0 we have a
839  PROPOSE Phase, and don't have to keep toggling IE_PRODS
840  KJC april 2005 */
841 
843 
844  Symbol * goal;
845  int level_change_type, diff;
846 
847  /* KJC 04/05 - moved phase printing to init_soar: do_one_top_level_phase, case APPLY */
848 
849  #ifdef DEBUG_DETERMINE_LEVEL_PHASE
850  printf("\n(Propose) Determining the highest active level in the stack....\n");
851  #endif
852 
853  // KJC 01.24.06 Changed logic for testing for IE prods. Was incorrectly
854  // checking only the bottom goal. Need to check at all levels. A previous
855  // code change required #define, but it was never defined.
856 
857  /* We are only checking for i_assertions, not o_assertions, since we don't
858  * want operators to fire in the proposal phase
859  */
860  if (!(thisAgent->ms_retractions || thisAgent->ms_i_assertions))
861  {
862  if (minor_quiescence_at_goal(thisAgent, thisAgent->bottom_goal))
863  {
864 
865  /* This is minor quiescence */
866 #ifdef DEBUG_DETERMINE_LEVEL_PHASE
867  printf("\n Propose Phase Quiescence has been reached...going to decision\n");
868 #endif
869 
870  /* Force a consistency check over the entire stack (by checking at
871  the bottom goal). */
872  goal_stack_consistent_through_goal(thisAgent, thisAgent->bottom_goal);
873 
874  /* Decision phase is always next */
875 
876  thisAgent->current_phase = DECISION_PHASE;
877  return;
878  }
879  }
880 
881  /* Not Quiescence, there are elaborations ready to fire at some level. */
882 
883  /* Check for Max ELABORATIONS EXCEEDED */
884 
885  if (thisAgent->e_cycles_this_d_cycle >=
886  static_cast<uint64_t>(thisAgent->sysparams[MAX_ELABORATIONS_SYSPARAM])) {
887  if (thisAgent->sysparams[PRINT_WARNINGS_SYSPARAM]) {
888  print(thisAgent, "\nWarning: reached max-elaborations; proceeding to decision phase.");
889  xml_generate_warning(thisAgent, "Warning: reached max-elaborations; proceeding to decision phase.");
890  }
891  thisAgent->current_phase = DECISION_PHASE;
892  return;
893  }
894 
895  /* not Max Elaborations */
896 
897  /* Save the old goal and level (must save level explicitly in case
898  goal is NIL) */
899  thisAgent->previous_active_goal = thisAgent->active_goal;
900  thisAgent->previous_active_level = thisAgent->active_level;
901 
902  /* Determine the new highest level of activity */
903  thisAgent->active_goal = highest_active_goal_propose(thisAgent, thisAgent->top_goal, FALSE);
904  if (thisAgent->active_goal)
905  thisAgent->active_level = thisAgent->active_goal->id.level;
906  else
907  thisAgent->active_level = 0; /* Necessary for get_next_retraction */
908 
909  #ifdef DEBUG_DETERMINE_LEVEL_PHASE
910  printf("\nHighest level of activity is....%d", thisAgent->active_level);
911  printf("\n Previous level of activity is....%d", thisAgent->previous_active_level);
912  #endif
913 
914  if (!thisAgent->active_goal)
915  /* Only NIL goal retractions */
916  level_change_type = NIL_GOAL_RETRACTIONS;
917  else if (thisAgent->previous_active_level == 0)
918  level_change_type = NEW_DECISION;
919  else {
920  diff = thisAgent->active_level - thisAgent->previous_active_level;
921  if (diff == 0)
922  level_change_type = SAME_LEVEL;
923  else if (diff > 0)
924  level_change_type = LOWER_LEVEL;
925  else
926  level_change_type = HIGHER_LEVEL;
927  }
928 
929  switch (level_change_type) {
931  #ifdef DEBUG_DETERMINE_LEVEL_PHASE
932  print(thisAgent, "\nOnly NIL goal retractions are active");
933  #endif
934  thisAgent->FIRING_TYPE = IE_PRODS;
935  //thisAgent->current_phase = PREFERENCE_PHASE;
936  break;
937 
938  case NEW_DECISION:
939  #ifdef DEBUG_DETERMINE_LEVEL_PHASE
940  print(thisAgent, "\nThis is a new decision....");
941  #endif
942  thisAgent->FIRING_TYPE = IE_PRODS;
943  //thisAgent->current_phase = PREFERENCE_PHASE;
944  break;
945 
946  case LOWER_LEVEL:
947  #ifdef DEBUG_DETERMINE_LEVEL_PHASE
948  print(thisAgent, "\nThe level is lower than the previous level....");
949  #endif
950  /* There is always a minor quiescence at the previous level
951  in the propose phase, so check for consistency. */
952  if (!goal_stack_consistent_through_goal(thisAgent, thisAgent->previous_active_goal)) {
953  thisAgent->current_phase = DECISION_PHASE;
954  break;
955  }
956  /* else: just do a preference phase */
957  thisAgent->FIRING_TYPE = IE_PRODS;
958  // thisAgent->current_phase = PREFERENCE_PHASE;
959  break;
960 
961  case SAME_LEVEL:
962  #ifdef DEBUG_DETERMINE_LEVEL_PHASE
963  print(thisAgent, "\nThe level is the same as the previous level....");
964  #endif
965  thisAgent->FIRING_TYPE = IE_PRODS;
966  // thisAgent->current_phase = PREFERENCE_PHASE;
967  break;
968 
969  case HIGHER_LEVEL:
970  #ifdef DEBUG_DETERMINE_LEVEL_PHASE
971  print(thisAgent, "\nThe level is higher than the previous level....");
972  #endif
973 
974  goal = thisAgent->previous_active_goal;
975  goal->id.saved_firing_type = thisAgent->FIRING_TYPE;
976 
977  #ifdef DEBUG_DETERMINE_LEVEL_PHASE
978  if (goal->id.saved_firing_type == IE_PRODS)
979  print(thisAgent, "\n Saving current firing type as IE_PRODS");
980  else if (goal->id.saved_firing_type == PE_PRODS)
981  print(thisAgent, "\n Saving current firing type as PE_PRODS");
982  else if (goal->id.saved_firing_type == NO_SAVED_PRODS)
983  print(thisAgent, "\n Saving current firing type as NO_SAVED_PRODS");
984  else
985  print(thisAgent, "\n Unknown SAVED firing type???????");
986  #endif
987 
988  /* run consistency check at new active level *before* firing any
989  productions there */
990 
991  #ifdef DEBUG_DETERMINE_LEVEL_PHASE
992  printf("\nMinor quiescence at level %d", thisAgent->active_level);
993  #endif
994  if (!goal_stack_consistent_through_goal(thisAgent, thisAgent->active_goal)) {
995  thisAgent->current_phase = DECISION_PHASE;
996  break;
997  }
998 
999  /* If the decision is consistent, then just keep processing
1000  at this level */
1001 
1002  thisAgent->FIRING_TYPE = IE_PRODS;
1003  // thisAgent->current_phase = PREFERENCE_PHASE;
1004  break;
1005  }
1006 
1007 }
1008 /* KJC: end 10.04.98 */
1009