Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals

decide.c

Go to the documentation of this file.
00001 /* ************************************************************************
00002  *
00003  *  file:  decide.c
00004  *
00005  * =======================================================================
00006  *  Decider and  Associated Routines for Soar 6
00007  *
00008  *  This file contains the decider as well as routine for managing
00009  *  slots, and the garbage collection of disconnected WMEs.
00010  * =======================================================================
00011  *
00012  * Copyright 1995-2003 Carnegie Mellon University,
00013  *                                                                               University of Michigan,
00014  *                                                                               University of Southern California/Information
00015  *                                                                               Sciences Institute. All rights reserved.
00016  *                                                                              
00017  * Redistribution and use in source and binary forms, with or without
00018  * modification, are permitted provided that the following conditions are met:
00019  *
00020  * 1.   Redistributions of source code must retain the above copyright notice,
00021  *              this list of conditions and the following disclaimer. 
00022  * 2.   Redistributions in binary form must reproduce the above copyright notice,
00023  *              this list of conditions and the following disclaimer in the documentation
00024  *              and/or other materials provided with the distribution. 
00025  *
00026  * THIS SOFTWARE IS PROVIDED BY THE SOAR CONSORTIUM ``AS IS'' AND ANY EXPRESS OR
00027  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00028  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
00029  * EVENT SHALL THE SOAR CONSORTIUM  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
00030  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00031  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00032  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00033  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00034  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00035  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00036  * The views and conclusions contained in the software and documentation are
00037  * those of the authors and should not be interpreted as representing official
00038  * policies, either expressed or implied, of Carnegie Mellon University, the
00039  * University of Michigan, the University of Southern California/Information
00040  * Sciences Institute, or the Soar consortium.
00041  * =======================================================================
00042  */
00043 
00044 /* Debugging stuff:  #define DEBUG_LINKS to get links, gc printouts */
00045 /*                   #define DEBUG_SLOTS to get slot printouts */
00046 /* #define DEBUG_LINKS */
00047 /* #define DEBUG_SLOTS */
00048 
00049 /* REW: begin 09.15.96 */
00050 /* For low-level, detailed information on the processing of the GDS */
00051 /* #define DEBUG_GDS */
00052 /* For high-level information on the instantiations that created an
00053  * o-supported element and lead to the elaboration of the GDS */
00054 /* #define DEBUG_GDS_HIGH */
00055 /* REW: end   09.15.96 */
00056 
00057 #include "soarkernel.h"
00058 #include "soarapi_datatypes.h"
00059 #include <assert.h>
00060 #include <math.h>
00061 #include <time.h>
00062 
00063 #ifdef NUMERIC_INDIFFERENCE
00064 /* REW: 2003-01-02 Behavior Variability Kernel Experiments */
00065 preference *probabilistically_select(slot * s, preference * candidates);
00066 
00067 /* REW: 2003-01-06 A temporary helper function */
00068 
00069 void print_candidates(preference * candidates)
00070 {
00071     preference *cand = 0;
00072     int max_count = 0;
00073 
00074     for (cand = candidates; cand != NIL; cand = cand->next_candidate) {
00075         max_count++;
00076         print("\n Candidate %d", cand);
00077         print_with_symbols("\n    %y %y %y", cand->id, cand->attr, cand->value);
00078         if (max_count > 10)
00079             break;
00080     }
00081 }
00082 
00083 /* END: 2003-01-02 Behavior Variability Kernel Experiments */
00084 
00085 #endif
00086 
00087 extern void soar_ecGDSPrint();
00088 
00089 void remove_existing_attribute_impasse_for_slot(slot * s);
00090 void post_link_addition(Symbol * from, Symbol * to);
00091 void post_link_removal(Symbol * from, Symbol * to);
00092 
00093 /* REW: begin 09.15.96   additions for Soar8 architecture */
00094 void elaborate_gds(void);
00095 void gds_invalid_so_remove_goal(wme * w);
00096 void free_parent_list(void);
00097 void uniquely_add_to_head_of_dll(instantiation * inst);
00098 void create_gds_for_goal(Symbol * goal);
00099 extern void remove_operator_if_necessary(slot * s, wme * w);
00100 
00101 /* REW: end   09.15.96 */
00102 
00103 /* ------------------------------------------------------------------------
00104                      Decider Global Variables
00105 
00106    Top_goal and bottom_goal point to the top and bottom goal identifiers,
00107    respectively.  (If there is no goal stack at all, they're both NIL.)
00108    Top_state points to the top state (Symbol) if there is a top state, and
00109    is NIL of there isn't any top state selected.
00110 
00111    Highest_goal_whose_context_changed points to the identifier of the highest
00112    goal for which some context slot has changed preferences.  If no context
00113    slot has changed preferences, this variable is NIL.  This is used by
00114    the decider during decision phase to avoid scanning down the whole
00115    goal stack when (as is the usual case) it really only needs to look at
00116    the lowest context.
00117 
00118    Changed_slots is a dl_list of non-context slots with changed preferences.
00119    This is used by the decider during working memory phase to tell which
00120    slots need to be re-decided.
00121 
00122    Context_slots_with_changed_acceptable_preferences is a dl_list of
00123    context slots for which the set of acceptable or require preferences
00124    has changed.  This is used to update the acceptable preference WMEs.
00125 ------------------------------------------------------------------------ */
00126 
00127 /* --------------------------------------------------
00128                    Decider Flags
00129 
00130    The decider often needs to mark symbols with
00131    certain flags, usually to record that the symbols
00132    are in certain sets or have a certain status.
00133    The "common.decider_flag" field on symbols is
00134    used for this, and is set to one of the following
00135    flag values.  (Usually only two or three of these
00136    values are used at once, and the meaning should
00137    be clear from the code.)
00138 -------------------------------------------------- */
00139 
00140 #define NOTHING_DECIDER_FLAG 0  /* Warning: code relies in this being 0 */
00141 #define CANDIDATE_DECIDER_FLAG 1
00142 #define CONFLICTED_DECIDER_FLAG 2
00143 #define FORMER_CANDIDATE_DECIDER_FLAG 3
00144 #define BEST_DECIDER_FLAG 4
00145 #define WORST_DECIDER_FLAG 5
00146 #define UNARY_INDIFFERENT_DECIDER_FLAG 6
00147 #define ALREADY_EXISTING_WME_DECIDER_FLAG 7
00148 #define UNARY_PARALLEL_DECIDER_FLAG 8
00149 /* REW: 2003-01-02 Behavior Variability Kernel Experiments 
00150    A new preference type: unary indifferent + constant (probability) value
00151 */
00152 #define UNARY_INDIFFERENT_CONSTANT_DECIDER_FLAG 9
00153 
00154 /* ======================================================================
00155 
00156                   Acceptable Preference WME Routines
00157 
00158    Whenever some acceptable or require preference for a context slot
00159    changes, we call mark_context_slot_as_acceptable_preference_changed().
00160 
00161    At the end of the phase, do_buffered_acceptable_preference_wme_changes()
00162    is called to update the acceptable preference wmes.  This should be
00163    called *before* do_buffered_link_changes() and do_buffered_wm_changes().
00164 ====================================================================== */
00165 
00166 void mark_context_slot_as_acceptable_preference_changed(slot * s)
00167 {
00168     dl_cons *dc;
00169 
00170     if (s->acceptable_preference_changed)
00171         return;
00172     allocate_with_pool(&current_agent(dl_cons_pool), &dc);
00173     dc->item = s;
00174     s->acceptable_preference_changed = dc;
00175     insert_at_head_of_dll(current_agent(context_slots_with_changed_acceptable_preferences), dc, next, prev);
00176 }
00177 
00178 /* --- This updates the acceptable preference wmes for a single slot. --- */
00179 void do_acceptable_preference_wme_changes_for_slot(slot * s)
00180 {
00181     wme *w, *next_w;
00182     preference *p;
00183 
00184     /* --- first, reset marks to "NOTHING" --- */
00185     for (w = s->acceptable_preference_wmes; w != NIL; w = w->next)
00186         w->value->common.decider_flag = NOTHING_DECIDER_FLAG;
00187 
00188     /* --- now mark values for which we WANT a wme as "CANDIDATE" values --- */
00189     for (p = s->preferences[REQUIRE_PREFERENCE_TYPE]; p != NIL; p = p->next)
00190         p->value->common.decider_flag = CANDIDATE_DECIDER_FLAG;
00191     for (p = s->preferences[ACCEPTABLE_PREFERENCE_TYPE]; p != NIL; p = p->next)
00192         p->value->common.decider_flag = CANDIDATE_DECIDER_FLAG;
00193 
00194     /* --- remove any existing wme's that aren't CANDIDATEs; mark the
00195        rest as ALREADY_EXISTING --- */
00196 
00197     w = s->acceptable_preference_wmes;
00198     while (w) {
00199         next_w = w->next;
00200         if (w->value->common.decider_flag == CANDIDATE_DECIDER_FLAG) {
00201             w->value->common.decider_flag = ALREADY_EXISTING_WME_DECIDER_FLAG;
00202             w->value->common.a.decider_wme = w;
00203             w->preference = NIL;        /* we'll update this later */
00204         } else {
00205             remove_from_dll(s->acceptable_preference_wmes, w, next, prev);
00206 /* REW: begin 09.15.96 */
00207             /* IF we lose an acceptable preference for an operator, then that
00208                operator comes out of the slot immediately in OPERAND2.
00209                However, if the lost acceptable preference is not for item
00210                in the slot, then we don;t need to do anything special until
00211                mini-quiescence. */
00212 
00213 #ifndef SOAR_8_ONLY
00214             if (current_agent(operand2_mode))
00215 #endif
00216                 remove_operator_if_necessary(s, w);
00217 /* REW: end   09.15.96 */
00218             remove_wme_from_wm(w);
00219         }
00220         w = next_w;
00221     }
00222 
00223     /* --- add the necessary wme's that don't ALREADY_EXIST --- */
00224 
00225     for (p = s->preferences[REQUIRE_PREFERENCE_TYPE]; p != NIL; p = p->next) {
00226         if (p->value->common.decider_flag == ALREADY_EXISTING_WME_DECIDER_FLAG) {
00227             /* --- found existing wme, so just update its trace --- */
00228             w = p->value->common.a.decider_wme;
00229             if (!w->preference)
00230                 w->preference = p;
00231         } else {
00232             w = make_wme(p->id, p->attr, p->value, TRUE);
00233             insert_at_head_of_dll(s->acceptable_preference_wmes, w, next, prev);
00234             w->preference = p;
00235             add_wme_to_wm(w);
00236             p->value->common.decider_flag = ALREADY_EXISTING_WME_DECIDER_FLAG;
00237             p->value->common.a.decider_wme = w;
00238         }
00239     }
00240     for (p = s->preferences[ACCEPTABLE_PREFERENCE_TYPE]; p != NIL; p = p->next) {
00241         if (p->value->common.decider_flag == ALREADY_EXISTING_WME_DECIDER_FLAG) {
00242             /* --- found existing wme, so just update its trace --- */
00243             w = p->value->common.a.decider_wme;
00244             if (!w->preference)
00245                 w->preference = p;
00246         } else {
00247             w = make_wme(p->id, p->attr, p->value, TRUE);
00248             insert_at_head_of_dll(s->acceptable_preference_wmes, w, next, prev);
00249             w->preference = p;
00250             add_wme_to_wm(w);
00251             p->value->common.decider_flag = ALREADY_EXISTING_WME_DECIDER_FLAG;
00252             p->value->common.a.decider_wme = w;
00253         }
00254     }
00255 }
00256 
00257 void do_buffered_acceptable_preference_wme_changes(void)
00258 {
00259     dl_cons *dc;
00260     slot *s;
00261 
00262     while (current_agent(context_slots_with_changed_acceptable_preferences)) {
00263         dc = current_agent(context_slots_with_changed_acceptable_preferences);
00264         current_agent(context_slots_with_changed_acceptable_preferences) = dc->next;
00265         s = dc->item;
00266         free_with_pool(&current_agent(dl_cons_pool), dc);
00267         do_acceptable_preference_wme_changes_for_slot(s);
00268         s->acceptable_preference_changed = NIL;
00269     }
00270 }
00271 
00272 /* **********************************************************************
00273 
00274                          Ownership Calculations
00275 
00276    Whenever a link is added from one identifier to another (i.e.,
00277    (I37 ^x R26)), we call post_link_addition().  This records the link
00278    addition and buffers it for later processing.  Similarly, whenever a
00279    link is removed, we call post_link_removal(), which buffers the
00280    removal for later processing.  At the end of the phase, we call
00281    do_buffered_link_changes() to update the goal stack level of all
00282    identifiers, and garbage collect anything that's now disconnected.
00283 
00284    On each identifier, we maintain a count of how many links there are
00285    to it.  If the count is decremented to 0, the id must be disconnected,
00286    so we can GC it.  If the count is decremented but nonzero, we have
00287    to walk through WM to see whether it's connected--it could be disconnected
00288    but have a positive link count, if there's a circular structure in WM.
00289 
00290    Goal and impasse identifiers are handled specially.  We don't want to
00291    GC these even though WM may not have any pointers to them.  So instead
00292    of the normal link count stuff, we use a special "link" to each goal or
00293    impasse id.  This special link is added/removed by calling
00294    post_link_addition/removal (NIL, id).
00295 ********************************************************************** */
00296 
00297 /* ======================================================================
00298 
00299                       Promotion (Upgrade) Routines
00300 
00301    The list "promoted_ids" indicates which identifiers need to be
00302    promoted at the end of the current phase.  On every id, we have a
00303    "promotion_level" field indicating the new goal_stack_level to which
00304    the id is going to be promoted.  When we actually do the promotion,
00305    we set the id's level to promotion_level.  We also promote anything
00306    in the id's transitive closure to the same level, if necessary.
00307 ====================================================================== */
00308 
00309 /* ----------------------------------------------
00310    Post a link addition for later processing.
00311 ---------------------------------------------- */
00312 
00313 void post_link_addition(Symbol * from, Symbol * to)
00314 {
00315 
00316     /* --- don't add links to goals/impasses, except the special one
00317        (NIL,goal) --- */
00318     if ((to->id.isa_goal || to->id.isa_impasse) && from)
00319         return;
00320 
00321     to->id.link_count++;
00322 
00323 #ifdef DEBUG_LINKS
00324     if (from)
00325         print_with_symbols("\nAdding link from %y to %y", from, to);
00326     else
00327         print_with_symbols("\nAdding special link to %y", to);
00328     print(" (count=%lu)", to->id.link_count);
00329 #endif
00330 
00331     if (!from)
00332         return;                 /* if adding a special link, we're done */
00333 
00334     /* --- if adding link from same level, ignore it --- */
00335     if (from->id.promotion_level == to->id.promotion_level)
00336         return;
00337 
00338     /* --- if adding link from lower to higher, mark higher accordingly --- */
00339     if (from->id.promotion_level > to->id.promotion_level) {
00340         to->id.could_be_a_link_from_below = TRUE;
00341         return;
00342     }
00343 
00344     /* --- otherwise buffer it for later --- */
00345     to->id.promotion_level = from->id.promotion_level;
00346     symbol_add_ref(to);
00347     push(to, current_agent(promoted_ids));
00348 }
00349 
00350 /* ----------------------------------------------
00351    Promote an id and its transitive closure.
00352 ---------------------------------------------- */
00353 
00354 #define promote_if_needed(sym) \
00355   { if ((sym)->common.symbol_type==IDENTIFIER_SYMBOL_TYPE) \
00356       promote_id_and_tc(sym,new_level); }
00357 
00358 void promote_id_and_tc(Symbol * id, goal_stack_level new_level)
00359 {
00360     slot *s;
00361     preference *pref;
00362     wme *w;
00363 
00364     /* --- if it's already that high, or is going to be soon, don't bother -- */
00365     if (id->id.level <= new_level)
00366         return;
00367     if (id->id.promotion_level < new_level)
00368         return;
00369 
00370     /* --- update its level, etc. --- */
00371     id->id.level = new_level;
00372     id->id.promotion_level = new_level;
00373     id->id.could_be_a_link_from_below = TRUE;
00374 
00375     /* --- sanity check --- */
00376     if (id->id.isa_goal || id->id.isa_impasse) {
00377         char msg[MESSAGE_SIZE];
00378         strncpy(msg, "decide.c: Internal error: tried to promote a goal or impasse id\n", MESSAGE_SIZE);
00379         msg[MESSAGE_SIZE - 1] = 0;
00380         abort_with_fatal_error(msg);
00381         /* Note--since we can't promote a goal, we don't have to worry about
00382            slot->acceptable_preference_wmes below */
00383     }
00384 
00385     /* --- scan through all preferences and wmes for all slots for this id -- */
00386     for (w = id->id.input_wmes; w != NIL; w = w->next)
00387         promote_if_needed(w->value);
00388     for (s = id->id.slots; s != NIL; s = s->next) {
00389         for (pref = s->all_preferences; pref != NIL; pref = pref->all_of_slot_next) {
00390             promote_if_needed(pref->value);
00391             if (preference_is_binary(pref->type))
00392                 promote_if_needed(pref->referent);
00393         }
00394         for (w = s->wmes; w != NIL; w = w->next)
00395             promote_if_needed(w->value);
00396     }                           /* end of for slots loop */
00397 }
00398 
00399 /* ----------------------------------------------
00400    Do all buffered promotions.
00401 ---------------------------------------------- */
00402 
00403 void do_promotion(void)
00404 {
00405     cons *c;
00406     Symbol *to;
00407 
00408     while (current_agent(promoted_ids)) {
00409         c = current_agent(promoted_ids);
00410         to = c->first;
00411         current_agent(promoted_ids) = current_agent(promoted_ids)->rest;
00412         free_cons(c);
00413         promote_id_and_tc(to, to->id.promotion_level);
00414         symbol_remove_ref(to);
00415     }
00416 }
00417 
00418 /* ======================================================================
00419 
00420            Demotion (Downgrade) and Garbage Collection Routines
00421 
00422    Demotions happen in stages.  Post_link_removal() is called from
00423    various places; this decrements the link count on an identifier and
00424    adds it to the dl_list "ids_with_unknown_level".  (While this is going
00425    on, link_update_mode is always set to UPDATE_LINKS_NORMALLY.)
00426 
00427    At the end of the phase, do_demotion() is called.  This has three
00428    stages:
00429      (1) the ids with unknown level whose link count is 0 are moved
00430          over to a list of disconnected_ids -- these ids are definitely
00431          disconnected and are going to be GC'd
00432      (2) We GC the disconnected_ids.  While doing this GC, more wmes
00433          are removed from WM and more links are removed.  For these
00434          link removals, if the link count on an id goes to 0, we put
00435          it onto disconnected_ids (rather than ids_with_unknown_level).
00436          (Here link_update_mode is UPDATE_DISCONNECTED_IDS_LIST.)
00437          We keep GC-ing disconnected_ids until none are left.
00438      (3) Mark & Walk:  If there are still remaining ids_with_unknown_level,
00439          we mark each such id and its transitive closure, then walk the
00440          goal stack (or parts of it) to find out what's really still
00441          connected.
00442      (4) For each id now known to be disconnected, we GC it.  While doing
00443          this GC, more links are removed, but for those, we merely update
00444          the link count, nothing else--because we already took the TC of
00445          each id in step 3, so we're already certain of what's connected
00446          and what's not.  (Here link_update_mode is JUST_UPDATE_COUNT.)
00447 ====================================================================== */
00448 
00449 /* ----------------------------------------------
00450    Post a link removal for later processing.
00451 ---------------------------------------------- */
00452 
00453 void post_link_removal(Symbol * from, Symbol * to)
00454 {
00455     dl_cons *dc;
00456 
00457     /* --- don't remove links to goals/impasses, except the special one
00458        (NIL,goal) --- */
00459     if ((to->id.isa_goal || to->id.isa_impasse) && from)
00460         return;
00461 
00462     to->id.link_count--;
00463 
00464 #ifdef DEBUG_LINKS
00465     if (from) {
00466         print_with_symbols("\nRemoving link from %y to %y", from, to);
00467         print(" (%d to %d)", from->id.level, to->id.level);
00468     } else {
00469         print_with_symbols("\nRemoving special link to %y ", to);
00470         print(" (%d)", to->id.level);
00471     }
00472     print(" (count=%lu)", to->id.link_count);
00473 #endif
00474 
00475     /* --- if a gc is in progress, handle differently --- */
00476     if (current_agent(link_update_mode) == JUST_UPDATE_COUNT)
00477         return;
00478 
00479     if ((current_agent(link_update_mode) == UPDATE_DISCONNECTED_IDS_LIST) && (to->id.link_count == 0)) {
00480         if (to->id.unknown_level) {
00481             dc = to->id.unknown_level;
00482             remove_from_dll(current_agent(ids_with_unknown_level), dc, next, prev);
00483             insert_at_head_of_dll(current_agent(disconnected_ids), dc, next, prev);
00484         } else {
00485             symbol_add_ref(to);
00486             allocate_with_pool(&current_agent(dl_cons_pool), &dc);
00487             dc->item = to;
00488             to->id.unknown_level = dc;
00489             insert_at_head_of_dll(current_agent(disconnected_ids), dc, next, prev);
00490         }
00491         return;
00492     }
00493 
00494     /* --- if removing a link from a different level, there must be some other
00495        link at the same level, so we can ignore this change --- */
00496     if (from && (from->id.level != to->id.level))
00497         return;
00498 
00499     if (!to->id.unknown_level) {
00500         symbol_add_ref(to);
00501         allocate_with_pool(&current_agent(dl_cons_pool), &dc);
00502         dc->item = to;
00503         to->id.unknown_level = dc;
00504         insert_at_head_of_dll(current_agent(ids_with_unknown_level), dc, next, prev);
00505     }
00506 }
00507 
00508 /* ----------------------------------------------
00509    Garbage collect an identifier.  This removes
00510    all wmes, input wmes, and preferences for that
00511    id from TM.
00512 ---------------------------------------------- */
00513 
00514 void garbage_collect_id(Symbol * id)
00515 {
00516     slot *s;
00517     preference *pref, *next_pref;
00518 
00519 #ifdef DEBUG_LINKS
00520     print_with_symbols("\n*** Garbage collecting id: %y", id);
00521 #endif
00522 
00523     /* Note--for goal/impasse id's, this does not remove the impasse wme's.
00524        This is handled by remove_existing_such-and-such... */
00525 
00526     /* --- remove any input wmes from the id --- */
00527     remove_wme_list_from_wm(id->id.input_wmes);
00528     id->id.input_wmes = NIL;
00529 
00530     for (s = id->id.slots; s != NIL; s = s->next) {
00531         /* --- remove any existing attribute impasse for the slot --- */
00532         if (s->impasse_type != NONE_IMPASSE_TYPE)
00533             remove_existing_attribute_impasse_for_slot(s);
00534         /* --- remove all wme's from the slot --- */
00535         remove_wme_list_from_wm(s->wmes);
00536         s->wmes = NIL;
00537         /* --- remove all preferences for the slot --- */
00538         pref = s->all_preferences;
00539         while (pref) {
00540             next_pref = pref->all_of_slot_next;
00541             remove_preference_from_tm(pref);
00542             /* Note:  the call to remove_preference_from_slot handles the removal
00543                of acceptable_preference_wmes */
00544             pref = next_pref;
00545         }
00546         mark_slot_for_possible_removal(s);
00547     }                           /* end of for slots loop */
00548 }
00549 
00550 /* ----------------------------------------------
00551    During the mark & walk, these variables keep
00552    track of the highest goal stack level that
00553    any identifier could "fall from" and the lowest
00554    level any could "fall to".  These are used to
00555    delimit a range of goal stack levels that
00556    need to be walked.  (In many cases, much of
00557    the goal stack can be ignored.)
00558 ---------------------------------------------- */
00559 
00560 /* ----------------------------------------------
00561    Mark an id and its transitive closure as having
00562    an unknown level.  Ids are marked by setting
00563    id.tc_num to mark_tc_number.  The starting id's
00564    goal stack level is recorded in
00565    level_at_which_marking_started by the caller.
00566    The marked ids are added to ids_with_unknown_level.
00567 ---------------------------------------------- */
00568 
00569 #define mark_unknown_level_if_needed(sym) \
00570   { if ((sym)->common.symbol_type==IDENTIFIER_SYMBOL_TYPE) \
00571       mark_id_and_tc_as_unknown_level(sym); }
00572 
00573 void mark_id_and_tc_as_unknown_level(Symbol * id)
00574 {
00575     slot *s;
00576     preference *pref;
00577     wme *w;
00578     dl_cons *dc;
00579 
00580     /* --- if id is already marked, do nothing --- */
00581     if (id->id.tc_num == current_agent(mark_tc_number))
00582         return;
00583 
00584     /* --- don't mark anything higher up as disconnected--in order to be higher
00585        up, it must have a link to it up there --- */
00586     if (id->id.level < current_agent(level_at_which_marking_started))
00587         return;
00588 
00589     /* --- mark id, so we won't do it again later --- */
00590     id->id.tc_num = current_agent(mark_tc_number);
00591 
00592     /* --- update range of goal stack levels we'll need to walk --- */
00593     if (id->id.level < current_agent(highest_level_anything_could_fall_from))
00594         current_agent(highest_level_anything_could_fall_from) = id->id.level;
00595     if (id->id.level > current_agent(lowest_level_anything_could_fall_to))
00596         current_agent(lowest_level_anything_could_fall_to) = id->id.level;
00597     if (id->id.could_be_a_link_from_below)
00598         current_agent(lowest_level_anything_could_fall_to) = LOWEST_POSSIBLE_GOAL_LEVEL;
00599 
00600     /* --- add id to the set of ids with unknown level --- */
00601     if (!id->id.unknown_level) {
00602         allocate_with_pool(&current_agent(dl_cons_pool), &dc);
00603         dc->item = id;
00604         id->id.unknown_level = dc;
00605         insert_at_head_of_dll(current_agent(ids_with_unknown_level), dc, next, prev);
00606         symbol_add_ref(id);
00607     }
00608 
00609     /* -- scan through all preferences and wmes for all slots for this id -- */
00610     for (w = id->id.input_wmes; w != NIL; w = w->next)
00611         mark_unknown_level_if_needed(w->value);
00612     for (s = id->id.slots; s != NIL; s = s->next) {
00613         for (pref = s->all_preferences; pref != NIL; pref = pref->all_of_slot_next) {
00614             mark_unknown_level_if_needed(pref->value);
00615             if (preference_is_binary(pref->type))
00616                 mark_unknown_level_if_needed(pref->referent);
00617         }
00618         if (s->impasse_id)
00619             mark_unknown_level_if_needed(s->impasse_id);
00620         for (w = s->wmes; w != NIL; w = w->next)
00621             mark_unknown_level_if_needed(w->value);
00622     }                           /* end of for slots loop */
00623 }
00624 
00625 /* ----------------------------------------------
00626    After marking the ids with unknown level,
00627    we walk various levels of the goal stack,
00628    higher level to lower level.  If, while doing
00629    the walk, we encounter an id marked as having
00630    an unknown level, we update its level and
00631    remove it from ids_with_unknown_level.
00632 ---------------------------------------------- */
00633 
00634 #define update_levels_if_needed(sym) \
00635   { if ((sym)->common.symbol_type==IDENTIFIER_SYMBOL_TYPE) \
00636       if ((sym)->id.tc_num!=current_agent(walk_tc_number)) \
00637         walk_and_update_levels(sym); }
00638 
00639 void walk_and_update_levels(Symbol * id)
00640 {
00641     slot *s;
00642     preference *pref;
00643     wme *w;
00644     dl_cons *dc;
00645 
00646     /* --- mark id so we don't walk it twice --- */
00647     id->id.tc_num = current_agent(walk_tc_number);
00648 
00649     /* --- if we already know its level, and it's higher up, then exit --- */
00650     if ((!id->id.unknown_level) && (id->id.level < current_agent(walk_level)))
00651         return;
00652 
00653     /* --- if we didn't know its level before, we do now --- */
00654     if (id->id.unknown_level) {
00655         dc = id->id.unknown_level;
00656         remove_from_dll(current_agent(ids_with_unknown_level), dc, next, prev);
00657         free_with_pool(&current_agent(dl_cons_pool), dc);
00658         symbol_remove_ref(id);
00659         id->id.unknown_level = NIL;
00660         id->id.level = current_agent(walk_level);
00661         id->id.promotion_level = current_agent(walk_level);
00662     }
00663 
00664     /* -- scan through all preferences and wmes for all slots for this id -- */
00665     for (w = id->id.input_wmes; w != NIL; w = w->next)
00666         update_levels_if_needed(w->value);
00667     for (s = id->id.slots; s != NIL; s = s->next) {
00668         for (pref = s->all_preferences; pref != NIL; pref = pref->all_of_slot_next) {
00669             update_levels_if_needed(pref->value);
00670             if (preference_is_binary(pref->type))
00671                 update_levels_if_needed(pref->referent);
00672         }
00673         if (s->impasse_id)
00674             update_levels_if_needed(s->impasse_id);
00675         for (w = s->wmes; w != NIL; w = w->next)
00676             update_levels_if_needed(w->value);
00677     }                           /* end of for slots loop */
00678 }
00679 
00680 /* ----------------------------------------------
00681    Do all buffered demotions and gc's.
00682 ---------------------------------------------- */
00683 
00684 void do_demotion(void)
00685 {
00686     Symbol *g, *id;
00687     dl_cons *dc, *next_dc;
00688 
00689     /* --- scan through ids_with_unknown_level, move the ones with link_count==0
00690      *  over to disconnected_ids --- */
00691     for (dc = current_agent(ids_with_unknown_level); dc != NIL; dc = next_dc) {
00692         next_dc = dc->next;
00693         id = dc->item;
00694         if (id->id.link_count == 0) {
00695             remove_from_dll(current_agent(ids_with_unknown_level), dc, next, prev);
00696             insert_at_head_of_dll(current_agent(disconnected_ids), dc, next, prev);
00697         }
00698     }
00699 
00700     /* --- keep garbage collecting ids until nothing left to gc --- */
00701     current_agent(link_update_mode) = UPDATE_DISCONNECTED_IDS_LIST;
00702     while (current_agent(disconnected_ids)) {
00703         dc = current_agent(disconnected_ids);
00704         current_agent(disconnected_ids) = current_agent(disconnected_ids)->next;
00705         id = dc->item;
00706         free_with_pool(&current_agent(dl_cons_pool), dc);
00707         garbage_collect_id(id);
00708         symbol_remove_ref(id);
00709     }
00710     current_agent(link_update_mode) = UPDATE_LINKS_NORMALLY;
00711 
00712     /* --- if nothing's left with an unknown level, we're done --- */
00713     if (!current_agent(ids_with_unknown_level))
00714         return;
00715 
00716     /* --- do the mark --- */
00717     current_agent(highest_level_anything_could_fall_from) = LOWEST_POSSIBLE_GOAL_LEVEL;
00718     current_agent(lowest_level_anything_could_fall_to) = -1;
00719     current_agent(mark_tc_number) = get_new_tc_number();
00720     for (dc = current_agent(ids_with_unknown_level); dc != NIL; dc = dc->next) {
00721         id = dc->item;
00722         current_agent(level_at_which_marking_started) = id->id.level;
00723         mark_id_and_tc_as_unknown_level(id);
00724     }
00725 
00726     /* --- do the walk --- */
00727     g = current_agent(top_goal);
00728     for (;;) {
00729         if (!g)
00730             break;
00731         if (g->id.level > current_agent(lowest_level_anything_could_fall_to))
00732             break;
00733         if (g->id.level >= current_agent(highest_level_anything_could_fall_from)) {
00734             current_agent(walk_level) = g->id.level;
00735             current_agent(walk_tc_number) = get_new_tc_number();
00736             walk_and_update_levels(g);
00737         }
00738         g = g->id.lower_goal;
00739     }
00740 
00741     /* --- GC anything left with an unknown level after the walk --- */
00742     current_agent(link_update_mode) = JUST_UPDATE_COUNT;
00743     while (current_agent(ids_with_unknown_level)) {
00744         dc = current_agent(ids_with_unknown_level);
00745         current_agent(ids_with_unknown_level) = current_agent(ids_with_unknown_level)->next;
00746         id = dc->item;
00747         free_with_pool(&current_agent(dl_cons_pool), dc);
00748         id->id.unknown_level = NIL;     /* AGR 640:  GAP set to NIL because */
00749         /* symbol may still have pointers to it */
00750         garbage_collect_id(id);
00751         symbol_remove_ref(id);
00752     }
00753     current_agent(link_update_mode) = UPDATE_LINKS_NORMALLY;
00754 }
00755 
00756 /* ------------------------------------------------------------------
00757                        Do Buffered Link Changes
00758 
00759    This routine does all the buffered link (ownership) chages, updating
00760    the goal stack level on all identifiers and garbage collecting
00761    disconnected wmes.
00762 ------------------------------------------------------------------ */
00763 
00764 void do_buffered_link_changes(void)
00765 {
00766 
00767 #ifndef NO_TIMING_STUFF
00768 #ifdef DETAILED_TIMING_STATS
00769     struct timeval saved_start_tv;
00770 #endif
00771 #endif
00772 
00773     /* --- if no promotions or demotions are buffered, do nothing --- */
00774     if (!(current_agent(promoted_ids) || current_agent(ids_with_unknown_level) || current_agent(disconnected_ids)))
00775         return;
00776 
00777 #ifndef NO_TIMING_STUFF
00778 #ifdef DETAILED_TIMING_STATS
00779     start_timer(&saved_start_tv);
00780 #endif
00781 #endif
00782     do_promotion();
00783     do_demotion();
00784 #ifndef NO_TIMING_STUFF
00785 #ifdef DETAILED_TIMING_STATS
00786     stop_timer(&saved_start_tv, &current_agent(ownership_cpu_time[current_agent(current_phase)]));
00787 #endif
00788 #endif
00789 }
00790 
00791 /* **************************************************************************
00792 
00793                          Preference Semantics 
00794 
00795    Run_preference_semantics (slot *s, preference **result_candidates) examines
00796    the preferences for a given slot, and returns an impasse type for the
00797    slot.  The argument "result_candidates" is set to a list of candidate
00798    values for the slot--if the returned impasse type is NONE_IMPASSE_TYPE,
00799    this is the set of winners; otherwise it is the set of tied, conflicted,
00800    or constraint-failured values.  This list of values is a list of preferences
00801    for those values, linked via the "next_candidate" field on each preference
00802    structure.  If there is more than one preference for a given value,
00803    only one is returned in the result_candidates, with (first) require
00804    preferences being preferred over acceptable preferences, and (second)
00805    preferences from higher match goals being preferred over those from
00806    lower match goals.
00807 
00808    BUGBUG There is a problem here:  since the require/acceptable priority
00809    takes precedence over the match goal level priority, it's possible that
00810    we could return a require preference from lower in the goal stack than
00811    some acceptable preference.  If the goal stack gets popped soon
00812    afterwards (i.e., before the next time the slot is re-decided, I think),
00813    we would be left with a WME still in WM (not GC'd, because of the acceptable
00814    preference higher up) but with a trace pointing to a deallocated require
00815    preference.  This case is very obsure and unlikely to come up, but it
00816    could easily cause a core dump or worse.
00817    
00818    Require_preference_semantics() is a helper function for
00819    run_preference_semantics() that is used when there is at least one
00820    require preference for the slot.
00821 ************************************************************************** */
00822 
00823 byte require_preference_semantics(slot * s, preference ** result_candidates)
00824 {
00825     preference *p;
00826     preference *candidates;
00827     Symbol *value;
00828 
00829     /* --- collect set of required items into candidates list --- */
00830     for (p = s->preferences[REQUIRE_PREFERENCE_TYPE]; p != NIL; p = p->next)
00831         p->value->common.decider_flag = NOTHING_DECIDER_FLAG;
00832     candidates = NIL;
00833     for (p = s->preferences[REQUIRE_PREFERENCE_TYPE]; p != NIL; p = p->next) {
00834         if (p->value->common.decider_flag == NOTHING_DECIDER_FLAG) {
00835             p->next_candidate = candidates;
00836             candidates = p;
00837             /* --- unmark it, in order to prevent it from being added twice --- */
00838             p->value->common.decider_flag = CANDIDATE_DECIDER_FLAG;
00839         }
00840     }
00841     *result_candidates = candidates;
00842 
00843     /* --- if more than one required item, we have a constraint failure --- */
00844     if (candidates->next_candidate)
00845         return CONSTRAINT_FAILURE_IMPASSE_TYPE;
00846 
00847     /* --- just one require, check for require-prohibit impasse --- */
00848     value = candidates->value;
00849     for (p = s->preferences[PROHIBIT_PREFERENCE_TYPE]; p != NIL; p = p->next)
00850         if (p->value == value)
00851             return CONSTRAINT_FAILURE_IMPASSE_TYPE;
00852 
00853     /* --- the lone require is the winner --- */
00854     return NONE_IMPASSE_TYPE;
00855 }
00856 
00857 byte run_preference_semantics(slot * s, preference ** result_candidates)
00858 {
00859     preference *p, *p2, *cand, *prev_cand;
00860     bool match_found, not_all_indifferent, not_all_parallel;
00861     preference *candidates;
00862 
00863     /* --- if the slot has no preferences at all, things are trivial --- */
00864     if (!s->all_preferences) {
00865         if (!s->isa_context_slot)
00866             mark_slot_for_possible_removal(s);
00867         *result_candidates = NIL;
00868         return NONE_IMPASSE_TYPE;
00869     }
00870 
00871     /* === Requires === */
00872     if (s->preferences[REQUIRE_PREFERENCE_TYPE]) {
00873         return require_preference_semantics(s, result_candidates);
00874     }
00875 
00876     /* === Acceptables, Prohibits, Rejects === */
00877 
00878     /* --- mark everything that's acceptable, then unmark the prohibited
00879        and rejected items --- */
00880     for (p = s->preferences[ACCEPTABLE_PREFERENCE_TYPE]; p != NIL; p = p->next)
00881         p->value->common.decider_flag = CANDIDATE_DECIDER_FLAG;
00882     for (p = s->preferences[PROHIBIT_PREFERENCE_TYPE]; p != NIL; p = p->next)
00883         p->value->common.decider_flag = NOTHING_DECIDER_FLAG;
00884     for (p = s->preferences[REJECT_PREFERENCE_TYPE]; p != NIL; p = p->next)
00885         p->value->common.decider_flag = NOTHING_DECIDER_FLAG;
00886 
00887     /* --- now scan through acceptables and build the list of candidates --- */
00888     candidates = NIL;
00889     for (p = s->preferences[ACCEPTABLE_PREFERENCE_TYPE]; p != NIL; p = p->next) {
00890         if (p->value->common.decider_flag == CANDIDATE_DECIDER_FLAG) {
00891             p->next_candidate = candidates;
00892             candidates = p;
00893             /* --- unmark it, in order to prevent it from being added twice --- */
00894             p->value->common.decider_flag = NOTHING_DECIDER_FLAG;
00895         }
00896     }
00897 
00898     /* === Handling of attribute_preferences_mode 2 === */
00899 #ifndef SOAR_8_ONLY
00900     if (((current_agent(attribute_preferences_mode) == 2) ||
00901          (current_agent(operand2_mode) == TRUE)) && (!s->isa_context_slot)) {
00902 #else
00903     if (!s->isa_context_slot) {
00904 #endif
00905         *result_candidates = candidates;
00906         return NONE_IMPASSE_TYPE;
00907     }
00908 
00909     /* === If there are only 0 or 1 candidates, we're done === */
00910     if ((!candidates) || (!candidates->next_candidate)) {
00911         *result_candidates = candidates;
00912         return NONE_IMPASSE_TYPE;
00913     }
00914 
00915     /* === Better/Worse === */
00916     if (s->preferences[BETTER_PREFERENCE_TYPE] || s->preferences[WORSE_PREFERENCE_TYPE]) {
00917         Symbol *j, *k;
00918 
00919         /* -------------------- Algorithm to find conflicted set: 
00920            conflicted = {}
00921            for each (j > k):
00922            if j is (candidate or conflicted)
00923            and k is (candidate or conflicted)
00924            and at least one of j,k is a candidate
00925            then if (k > j) or (j < k) then
00926            conflicted += j, if not already true
00927            conflicted += k, if not already true
00928            candidate -= j, if not already true
00929            candidate -= k, if not already true
00930            for each (j < k):
00931            if j is (candidate or conflicted)
00932            and k is (candidate or conflicted)
00933            and at least one of j,k is a candidate
00934            then if (k < j)
00935            then
00936            conflicted += j, if not already true
00937            conflicted += k, if not already true
00938            candidate -= j, if not already true
00939            candidate -= k, if not already true
00940            ----------------------- */
00941 
00942         for (p = s->preferences[BETTER_PREFERENCE_TYPE]; p != NIL; p = p->next) {
00943             p->value->common.decider_flag = NOTHING_DECIDER_FLAG;
00944             p->referent->common.decider_flag = NOTHING_DECIDER_FLAG;
00945         }
00946         for (p = s->preferences[WORSE_PREFERENCE_TYPE]; p != NIL; p = p->next) {
00947             p->value->common.decider_flag = NOTHING_DECIDER_FLAG;
00948             p->referent->common.decider_flag = NOTHING_DECIDER_FLAG;
00949         }
00950         for (cand = candidates; cand != NIL; cand = cand->next_candidate) {
00951             cand->value->common.decider_flag = CANDIDATE_DECIDER_FLAG;
00952         }
00953         for (p = s->preferences[BETTER_PREFERENCE_TYPE]; p != NIL; p = p->next) {
00954             j = p->value;
00955             k = p->referent;
00956             if (j == k)
00957                 continue;
00958             if (j->common.decider_flag && k->common.decider_flag) {
00959                 if (k->common.decider_flag != CONFLICTED_DECIDER_FLAG)
00960                     k->common.decider_flag = FORMER_CANDIDATE_DECIDER_FLAG;
00961                 if ((j->common.decider_flag != CONFLICTED_DECIDER_FLAG) ||
00962                     (k->common.decider_flag != CONFLICTED_DECIDER_FLAG)) {
00963                     for (p2 = s->preferences[BETTER_PREFERENCE_TYPE]; p2; p2 = p2->next)
00964                         if ((p2->value == k) && (p2->referent == j)) {
00965                             j->common.decider_flag = CONFLICTED_DECIDER_FLAG;
00966                             k->common.decider_flag = CONFLICTED_DECIDER_FLAG;
00967                             break;
00968                         }
00969                     for (p2 = s->preferences[WORSE_PREFERENCE_TYPE]; p2; p2 = p2->next)
00970                         if ((p2->value == j) && (p2->referent == k)) {
00971                             j->common.decider_flag = CONFLICTED_DECIDER_FLAG;
00972                             k->common.decider_flag = CONFLICTED_DECIDER_FLAG;
00973                             break;
00974                         }
00975                 }
00976             }
00977         }
00978         for (p = s->preferences[WORSE_PREFERENCE_TYPE]; p != NIL; p = p->next) {
00979             j = p->value;
00980             k = p->referent;
00981             if (j == k)
00982                 continue;
00983             if (j->common.decider_flag && k->common.decider_flag) {
00984                 if (j->common.decider_flag != CONFLICTED_DECIDER_FLAG)
00985                     j->common.decider_flag = FORMER_CANDIDATE_DECIDER_FLAG;
00986                 if ((j->common.decider_flag != CONFLICTED_DECIDER_FLAG) ||
00987                     (k->common.decider_flag != CONFLICTED_DECIDER_FLAG)) {
00988                     for (p2 = s->preferences[WORSE_PREFERENCE_TYPE]; p2; p2 = p2->next)
00989                         if ((p2->value == k) && (p2->referent == j)) {
00990                             j->common.decider_flag = CONFLICTED_DECIDER_FLAG;
00991                             k->common.decider_flag = CONFLICTED_DECIDER_FLAG;
00992                             break;
00993                         }
00994                 }
00995             }
00996         }
00997 
00998         /* --- now scan through candidates list, look for conflicted stuff --- */
00999         for (cand = candidates; cand != NIL; cand = cand->next_candidate)
01000             if (cand->value->common.decider_flag == CONFLICTED_DECIDER_FLAG)
01001                 break;
01002         if (cand) {
01003             /* --- collect conflicted candidates into new candidates list --- */
01004             prev_cand = NIL;
01005             cand = candidates;
01006             while (cand) {
01007                 if (cand->value->common.decider_flag != CONFLICTED_DECIDER_FLAG) {
01008                     if (prev_cand)
01009                         prev_cand->next_candidate = cand->next_candidate;
01010                     else
01011                         candidates = cand->next_candidate;
01012                 } else {
01013                     prev_cand = cand;
01014                 }
01015                 cand = cand->next_candidate;
01016             }
01017             *result_candidates = candidates;
01018             return CONFLICT_IMPASSE_TYPE;
01019         }
01020         /* --- no conflicts found, remove former_candidates from candidates --- */
01021         prev_cand = NIL;
01022         cand = candidates;
01023         while (cand) {
01024             if (cand->value->common.decider_flag == FORMER_CANDIDATE_DECIDER_FLAG) {
01025                 if (prev_cand)
01026                     prev_cand->next_candidate = cand->next_candidate;
01027                 else
01028                     candidates = cand->next_candidate;
01029             } else {
01030                 prev_cand = cand;
01031             }
01032             cand = cand->next_candidate;
01033         }
01034     }
01035 
01036     /* === Bests === */
01037     if (s->preferences[BEST_PREFERENCE_TYPE]) {
01038         for (cand = candidates; cand != NIL; cand = cand->next_candidate)
01039             cand->value->common.decider_flag = NOTHING_DECIDER_FLAG;
01040         for (p = s->preferences[BEST_PREFERENCE_TYPE]; p != NIL; p = p->next)
01041             p->value->common.decider_flag = BEST_DECIDER_FLAG;
01042         prev_cand = NIL;
01043         for (cand = candidates; cand != NIL; cand = cand->next_candidate)
01044             if (cand->value->common.decider_flag == BEST_DECIDER_FLAG) {
01045                 if (prev_cand)
01046                     prev_cand->next_candidate = cand;
01047                 else
01048                     candidates = cand;
01049                 prev_cand = cand;
01050             }
01051         if (prev_cand)
01052             prev_cand->next_candidate = NIL;
01053     }
01054 
01055     /* === Worsts === */
01056     if (s->preferences[WORST_PREFERENCE_TYPE]) {
01057         for (cand = candidates; cand != NIL; cand = cand->next_candidate)
01058             cand->value->common.decider_flag = NOTHING_DECIDER_FLAG;
01059         for (p = s->preferences[WORST_PREFERENCE_TYPE]; p != NIL; p = p->next)
01060             p->value->common.decider_flag = WORST_DECIDER_FLAG;
01061         prev_cand = NIL;
01062         for (cand = candidates; cand != NIL; cand = cand->next_candidate)
01063             if (cand->value->common.decider_flag != WORST_DECIDER_FLAG) {
01064                 if (prev_cand)
01065                     prev_cand->next_candidate = cand;
01066                 else
01067                     candidates = cand;
01068                 prev_cand = cand;
01069             }
01070         if (prev_cand)
01071             prev_cand->next_candidate = NIL;
01072     }
01073 
01074     /* === If there are only 0 or 1 candidates, we're done === */
01075     if ((!candidates) || (!candidates->next_candidate)) {
01076         *result_candidates = candidates;
01077         return NONE_IMPASSE_TYPE;
01078     }
01079 
01080     /* === Indifferents === */
01081     for (cand = candidates; cand != NIL; cand = cand->next_candidate)
01082         cand->value->common.decider_flag = NOTHING_DECIDER_FLAG;
01083     for (p = s->preferences[UNARY_INDIFFERENT_PREFERENCE_TYPE]; p; p = p->next)
01084         p->value->common.decider_flag = UNARY_INDIFFERENT_DECIDER_FLAG;
01085 
01086 
01087          #ifdef NUMERIC_INDIFFERENCE
01088     /* REW: 2003-01-02 Behavior Variability Kernel Experiments
01089      We want to treat some binary indifferent prefs as unary indifferents,
01090      the second pref is really an int representing a probability value.
01091      So we identify these preferences here.
01092   */
01093         for (p=s->preferences[BINARY_INDIFFERENT_PREFERENCE_TYPE]; p; p=p->next)
01094     if((p->referent->fc.common_symbol_info.symbol_type == INT_CONSTANT_SYMBOL_TYPE) || 
01095            (p->referent->fc.common_symbol_info.symbol_type == FLOAT_CONSTANT_SYMBOL_TYPE))
01096      
01097       p->value->common.decider_flag = UNARY_INDIFFERENT_CONSTANT_DECIDER_FLAG;
01098   
01099   /* END: 2003-01-02 Behavior Variability Kernel Experiments  */
01100 
01101         #endif
01102 
01103     not_all_indifferent = FALSE;
01104     for (cand = candidates; cand != NIL; cand = cand->next_candidate) {
01105         /* --- if cand is unary indifferent, it's fine --- */
01106         if (cand->value->common.decider_flag == UNARY_INDIFFERENT_DECIDER_FLAG)
01107             continue;
01108 
01109         #ifdef NUMERIC_INDIFFERENCE
01110                 else if ( cand->value->common.decider_flag==UNARY_INDIFFERENT_CONSTANT_DECIDER_FLAG )
01111                 continue;
01112                 #endif
01113                 
01114                 /* --- check whether cand is binary indifferent to each other one --- */
01115         for (p = candidates; p != NIL; p = p->next_candidate) {
01116             if (p == cand)
01117                 continue;
01118             match_found = FALSE;
01119             for (p2 = s->preferences[BINARY_INDIFFERENT_PREFERENCE_TYPE]; p2 != NIL; p2 = p2->next)
01120                 if (((p2->value == cand->value) && (p2->referent == p->value)) ||
01121                     ((p2->value == p->value) && (p2->referent == cand->value))) {
01122                     match_found = TRUE;
01123                     break;
01124                 }
01125             if (!match_found) {
01126                 not_all_indifferent = TRUE;
01127                 break;
01128             }
01129         }                       /* end of for p loop */
01130         if (not_all_indifferent)
01131             break;
01132     }                           /* end of for cand loop */
01133 
01134     if (!not_all_indifferent) {
01135         /* --- items all indifferent, so just pick one of them to return --- */
01136         /* RBD 4/13/95 Removed code that looked for an existing value already in
01137            working memory for this slot, and returned it if found.  This was
01138            apparently an attempt to "stabilize" working memory if attribute
01139            preferences kept changing, but it ended up getting in the way, esp.
01140            with mutually indifferent operators were used with user-select
01141            random. */
01142         /* --- choose according to user-select --- */
01143         switch (current_agent(sysparams)[USER_SELECT_MODE_SYSPARAM]) {
01144         case USER_SELECT_FIRST:
01145             *result_candidates = candidates;
01146             break;
01147 /* AGR 615 begin */
01148         case USER_SELECT_LAST:
01149             /* The test to see if candidates is NIL is done just before the
01150                indifferent preferences processing begins.  The only place
01151                between there and here that candidates is changed is immediately
01152                followed by a return statement, so we can assume here that
01153                candidates is not NIL.  AGR 94.11.09 */
01154             for (cand = candidates; cand->next_candidate != NIL; cand = cand->next_candidate);
01155             *result_candidates = cand;
01156             break;
01157 /* AGR 615 end */
01158         case USER_SELECT_ASK:{
01159                 soar_apiAskCallbackData askd;
01160 
01161                 askd.candidates = candidates;
01162                 askd.selection = result_candidates;
01163 
01164                 if (soar_exists_callback(soar_agent, ASK_CALLBACK)) {
01165                     soar_invoke_first_callback(soar_agent, ASK_CALLBACK, (soar_call_data) & askd);
01166 
01167                     break;      /* ** prevent fallthrough ** */
01168                 } else {
01169                     print("\nError: \n");
01170                     print("  User Select ASK failed becuase no ask callback is defined\n");
01171                     print("  Setting to user select RANDOM\n");
01172                     set_sysparam(USER_SELECT_MODE_SYSPARAM, USER_SELECT_RANDOM);
01173                     current_agent(stop_soar) = TRUE;
01174 
01175                     /* ** intentiaonal fall through here... ** */
01176                 }
01177 
01178                 /* ** intentiaonal fall through here... ** */
01179             }
01180         case USER_SELECT_RANDOM:{
01181 
01182 #ifdef NUMERIC_INDIFFERENCE
01183                 /* REW: 2003-01-02 Behavior Variability Kernel Experiments */
01184                 cand = probabilistically_select(s, candidates);
01185                 if (!cand) {
01186                     *result_candidates = candidates;
01187                     return TIE_IMPASSE_TYPE;
01188                 }
01189                 *result_candidates = cand;
01190                 break;
01191 #else
01192                 int num_candidates, chosen_num;
01193                 num_candidates = 0;
01194 
01195                 for (cand = candidates; cand != NIL; cand = cand->next_candidate)
01196                     num_candidates++;
01197 
01198                 chosen_num = sys_random() % num_candidates;
01199 
01200                 cand = candidates;
01201                 while (chosen_num) {
01202                     cand = cand->next_candidate;
01203                     chosen_num--;
01204                 }
01205                 *result_candidates = cand;
01206                 break;
01207 #endif
01208             }
01209         default:
01210             {
01211                 char msg[MESSAGE_SIZE];
01212                 snprintf(msg, MESSAGE_SIZE, "decide.c: Error: bad value of user_select_mode: %ld\n",
01213                          current_agent(sysparams)[USER_SELECT_MODE_SYSPARAM]);
01214                 msg[MESSAGE_SIZE - 1] = 0;      /* snprintf doesn't set last char to null if output is truncated */
01215                 abort_with_fatal_error(msg);
01216             }
01217         }
01218         (*result_candidates)->next_candidate = NIL;
01219         return NONE_IMPASSE_TYPE;
01220     }
01221 
01222     /* --- items not all indifferent; for context slots this gives a tie --- */
01223     if (s->isa_context_slot) {
01224         *result_candidates = candidates;
01225         return TIE_IMPASSE_TYPE;
01226     }
01227 
01228     /* === Parallels === */
01229     for (cand = candidates; cand != NIL; cand = cand->next_candidate)
01230         cand->value->common.decider_flag = NOTHING_DECIDER_FLAG;
01231     for (p = s->preferences[UNARY_PARALLEL_PREFERENCE_TYPE]; p; p = p->next)
01232         p->value->common.decider_flag = UNARY_PARALLEL_DECIDER_FLAG;
01233     not_all_parallel = FALSE;
01234     for (cand = candidates; cand != NIL; cand = cand->next_candidate) {
01235         /* --- if cand is unary parallel, it's fine --- */
01236         if (cand->value->common.decider_flag == UNARY_PARALLEL_DECIDER_FLAG)
01237             continue;
01238         /* --- check whether cand is binary parallel to each other candidate --- */
01239         for (p = candidates; p != NIL; p = p->next_candidate) {
01240             if (p == cand)
01241                 continue;
01242             match_found = FALSE;
01243             for (p2 = s->preferences[BINARY_PARALLEL_PREFERENCE_TYPE]; p2 != NIL; p2 = p2->next)
01244                 if (((p2->value == cand->value) && (p2->referent == p->value)) ||
01245                     ((p2->value == p->value) && (p2->referent == cand->value))) {
01246                     match_found = TRUE;
01247                     break;
01248                 }
01249             if (!match_found) {
01250                 not_all_parallel = TRUE;
01251                 break;
01252             }
01253         }                       /* end of for p loop */
01254         if (not_all_parallel)
01255             break;
01256     }                           /* end of for cand loop */
01257 
01258     *result_candidates = candidates;
01259 
01260     if (!not_all_parallel) {
01261         /* --- items are all parallel, so return them all --- */
01262         return NONE_IMPASSE_TYPE;
01263     }
01264 
01265     /* --- otherwise we have a tie --- */
01266     return TIE_IMPASSE_TYPE;
01267 }
01268 
01269 byte run_preference_semantics_for_consistency_check(slot * s, preference ** result_candidates)
01270 {
01271     preference *p, *p2, *cand, *prev_cand;
01272     bool match_found, not_all_indifferent, not_all_parallel;
01273     preference *candidates;
01274 
01275     /* print("\n       Checking the preference semantics for inconsistencies....\n"); */
01276     /* --- if the slot has no preferences at all, things are trivial --- */
01277     if (!s->all_preferences) {
01278         if (!s->isa_context_slot)
01279             mark_slot_for_possible_removal(s);
01280         *result_candidates = NIL;
01281         return NONE_IMPASSE_TYPE;
01282     }
01283 
01284     /* === Requires === */
01285     if (s->preferences[REQUIRE_PREFERENCE_TYPE]) {
01286         return require_preference_semantics(s, result_candidates);
01287     }
01288 
01289     /* === Acceptables, Prohibits, Rejects === */
01290 
01291     /* --- mark everything that's acceptable, then unmark the prohibited
01292        and rejected items --- */
01293     for (p = s->preferences[ACCEPTABLE_PREFERENCE_TYPE]; p != NIL; p = p->next)
01294         p->value->common.decider_flag = CANDIDATE_DECIDER_FLAG;
01295     for (p = s->preferences[PROHIBIT_PREFERENCE_TYPE]; p != NIL; p = p->next)
01296         p->value->common.decider_flag = NOTHING_DECIDER_FLAG;
01297     for (p = s->preferences[REJECT_PREFERENCE_TYPE]; p != NIL; p = p->next)
01298         p->value->common.decider_flag = NOTHING_DECIDER_FLAG;
01299 
01300     /* --- now scan through acceptables and build the list of candidates --- */
01301     candidates = NIL;
01302     for (p = s->preferences[ACCEPTABLE_PREFERENCE_TYPE]; p != NIL; p = p->next) {
01303         if (p->value->common.decider_flag == CANDIDATE_DECIDER_FLAG) {
01304             p->next_candidate = candidates;
01305             candidates = p;
01306             /* --- unmark it, in order to prevent it from being added twice --- */
01307             p->value->common.decider_flag = NOTHING_DECIDER_FLAG;
01308         }
01309     }
01310 
01311     /* === Handling of attribute_preferences_mode 2 === */
01312 #ifndef SOAR_8_ONLY
01313     if (((current_agent(attribute_preferences_mode) == 2) ||
01314          (current_agent(operand2_mode) == TRUE)) && (!s->isa_context_slot)) {
01315 #else
01316     if (!s->isa_context_slot) {
01317 #endif
01318         *result_candidates = candidates;
01319         return NONE_IMPASSE_TYPE;
01320     }
01321 
01322     /* === If there are only 0 or 1 candidates, we're done === */
01323     if ((!candidates) || (!candidates->next_candidate)) {
01324         *result_candidates = candidates;
01325         return NONE_IMPASSE_TYPE;
01326     }
01327 
01328     /* === Better/Worse === */
01329     if (s->preferences[BETTER_PREFERENCE_TYPE] || s->preferences[WORSE_PREFERENCE_TYPE]) {
01330         Symbol *j, *k;
01331 
01332         /* -------------------- Algorithm to find conflicted set: 
01333            conflicted = {}
01334            for each (j > k):
01335            if j is (candidate or conflicted)
01336            and k is (candidate or conflicted)
01337            and at least one of j,k is a candidate
01338            then if (k > j) or (j < k) then
01339            conflicted += j, if not already true
01340            conflicted += k, if not already true
01341            candidate -= j, if not already true
01342            candidate -= k, if not already true
01343            for each (j < k):
01344            if j is (candidate or conflicted)
01345            and k is (candidate or conflicted)
01346            and at least one of j,k is a candidate
01347            then if (k < j)
01348            then
01349            conflicted += j, if not already true
01350            conflicted += k, if not already true
01351            candidate -= j, if not already true
01352            candidate -= k, if not already true
01353            ----------------------- */
01354 
01355         for (p = s->preferences[BETTER_PREFERENCE_TYPE]; p != NIL; p = p->next) {
01356             p->value->common.decider_flag = NOTHING_DECIDER_FLAG;
01357             p->referent->common.decider_flag = NOTHING_DECIDER_FLAG;
01358         }
01359         for (p = s->preferences[WORSE_PREFERENCE_TYPE]; p != NIL; p = p->next) {
01360             p->value->common.decider_flag = NOTHING_DECIDER_FLAG;
01361             p->referent->common.decider_flag = NOTHING_DECIDER_FLAG;
01362         }
01363         for (cand = candidates; cand != NIL; cand = cand->next_candidate) {
01364             cand->value->common.decider_flag = CANDIDATE_DECIDER_FLAG;
01365         }
01366         for (p = s->preferences[BETTER_PREFERENCE_TYPE]; p != NIL; p = p->next) {
01367             j = p->value;
01368             k = p->referent;
01369             if (j == k)
01370                 continue;
01371             if (j->common.decider_flag && k->common.decider_flag) {
01372                 if (k->common.decider_flag != CONFLICTED_DECIDER_FLAG)
01373                     k->common.decider_flag = FORMER_CANDIDATE_DECIDER_FLAG;
01374                 if ((j->common.decider_flag != CONFLICTED_DECIDER_FLAG) ||
01375                     (k->common.decider_flag != CONFLICTED_DECIDER_FLAG)) {
01376                     for (p2 = s->preferences[BETTER_PREFERENCE_TYPE]; p2; p2 = p2->next)
01377                         if ((p2->value == k) && (p2->referent == j)) {
01378                             j->common.decider_flag = CONFLICTED_DECIDER_FLAG;
01379                             k->common.decider_flag = CONFLICTED_DECIDER_FLAG;
01380                             break;
01381                         }
01382                     for (p2 = s->preferences[WORSE_PREFERENCE_TYPE]; p2; p2 = p2->next)
01383                         if ((p2->value == j) && (p2->referent == k)) {
01384                             j->common.decider_flag = CONFLICTED_DECIDER_FLAG;
01385                             k->common.decider_flag = CONFLICTED_DECIDER_FLAG;
01386                             break;
01387                         }
01388                 }
01389             }
01390         }
01391         for (p = s->preferences[WORSE_PREFERENCE_TYPE]; p != NIL; p = p->next) {
01392             j = p->value;
01393             k = p->referent;
01394             if (j == k)
01395                 continue;
01396             if (j->common.decider_flag && k->common.decider_flag) {
01397                 if (j->common.decider_flag != CONFLICTED_DECIDER_FLAG)
01398                     j->common.decider_flag = FORMER_CANDIDATE_DECIDER_FLAG;
01399                 if ((j->common.decider_flag != CONFLICTED_DECIDER_FLAG) ||
01400                     (k->common.decider_flag != CONFLICTED_DECIDER_FLAG)) {
01401                     for (p2 = s->preferences[WORSE_PREFERENCE_TYPE]; p2; p2 = p2->next)
01402                         if ((p2->value == k) && (p2->referent == j)) {
01403                             j->common.decider_flag = CONFLICTED_DECIDER_FLAG;
01404                             k->common.decider_flag = CONFLICTED_DECIDER_FLAG;
01405                             break;
01406                         }
01407                 }
01408             }
01409         }
01410 
01411         /* --- now scan through candidates list, look for conflicted stuff --- */
01412         for (cand = candidates; cand != NIL; cand = cand->next_candidate)
01413             if (cand->value->common.decider_flag == CONFLICTED_DECIDER_FLAG)
01414                 break;
01415         if (cand) {
01416             /* --- collect conflicted candidates into new candidates list --- */
01417             prev_cand = NIL;
01418             cand = candidates;
01419             while (cand) {
01420                 if (cand->value->common.decider_flag != CONFLICTED_DECIDER_FLAG) {
01421                     if (prev_cand)
01422                         prev_cand->next_candidate = cand->next_candidate;
01423                     else
01424                         candidates = cand->next_candidate;
01425                 } else {
01426                     prev_cand = cand;
01427                 }
01428                 cand = cand->next_candidate;
01429             }
01430             *result_candidates = candidates;
01431             return CONFLICT_IMPASSE_TYPE;
01432         }
01433         /* --- no conflicts found, remove former_candidates from candidates --- */
01434         prev_cand = NIL;
01435         cand = candidates;
01436         while (cand) {
01437             if (cand->value->common.decider_flag == FORMER_CANDIDATE_DECIDER_FLAG) {
01438                 if (prev_cand)
01439                     prev_cand->next_candidate = cand->next_candidate;
01440                 else
01441                     candidates = cand->next_candidate;
01442             } else {
01443                 prev_cand = cand;
01444             }
01445             cand = cand->next_candidate;
01446         }
01447     }
01448 
01449     /* === Bests === */
01450     if (s->preferences[BEST_PREFERENCE_TYPE]) {
01451         for (cand = candidates; cand != NIL; cand = cand->next_candidate)
01452             cand->value->common.decider_flag = NOTHING_DECIDER_FLAG;
01453         for (p = s->preferences[BEST_PREFERENCE_TYPE]; p != NIL; p = p->next)
01454             p->value->common.decider_flag = BEST_DECIDER_FLAG;
01455         prev_cand = NIL;
01456         for (cand = candidates; cand != NIL; cand = cand->next_candidate)
01457             if (cand->value->common.decider_flag == BEST_DECIDER_FLAG) {
01458                 if (prev_cand)
01459                     prev_cand->next_candidate = cand;
01460                 else
01461                     candidates = cand;
01462                 prev_cand = cand;
01463             }
01464         if (prev_cand)
01465             prev_cand->next_candidate = NIL;
01466     }
01467 
01468     /* === Worsts === */
01469     if (s->preferences[WORST_PREFERENCE_TYPE]) {
01470         for (cand = candidates; cand != NIL; cand = cand->next_candidate)
01471             cand->value->common.decider_flag = NOTHING_DECIDER_FLAG;
01472         for (p = s->preferences[WORST_PREFERENCE_TYPE]; p != NIL; p = p->next)
01473             p->value->common.decider_flag = WORST_DECIDER_FLAG;
01474         prev_cand = NIL;
01475         for (cand = candidates; cand != NIL; cand = cand->next_candidate)
01476             if (cand->value->common.decider_flag != WORST_DECIDER_FLAG) {
01477                 if (prev_cand)
01478                     prev_cand->next_candidate = cand;
01479                 else
01480                     candidates = cand;
01481                 prev_cand = cand;
01482             }
01483         if (prev_cand)
01484             prev_cand->next_candidate = NIL;
01485     }
01486 
01487     /* === If there are only 0 or 1 candidates, we're done === */
01488     if ((!candidates) || (!candidates->next_candidate)) {
01489         *result_candidates = candidates;
01490         return NONE_IMPASSE_TYPE;
01491     }
01492 
01493     /* === Indifferents === */
01494     for (cand = candidates; cand != NIL; cand = cand->next_candidate)
01495         cand->value->common.decider_flag = NOTHING_DECIDER_FLAG;
01496     for (p = s->preferences[UNARY_INDIFFERENT_PREFERENCE_TYPE]; p; p = p->next)
01497         p->value->common.decider_flag = UNARY_INDIFFERENT_DECIDER_FLAG;
01498 
01499     #ifdef NUMERIC_INDIFFERENCE
01500   /* REW: 2003-01-26 Behavior Variability Kernel Experiments
01501      We want to treat some binary indifferent prefs as unary indifferents,
01502      the second pref is really an int representing a probability value.
01503      So we identify these preferences here.
01504          -- want to guarantee decision is not interrupted by a new indiff pref
01505   */
01506   for (p=s->preferences[BINARY_INDIFFERENT_PREFERENCE_TYPE]; p; p=p->next)
01507     if( (p->referent->fc.common_symbol_info.symbol_type == INT_CONSTANT_SYMBOL_TYPE) ||
01508                                 (p->referent->fc.common_symbol_info.symbol_type == FLOAT_CONSTANT_SYMBOL_TYPE))
01509        
01510       p->value->common.decider_flag = UNARY_INDIFFERENT_CONSTANT_DECIDER_FLAG;
01511   /* END: 2003-01-02 Behavior Variability Kernel Experiments  */
01512 #endif
01513 
01514         not_all_indifferent = FALSE;
01515     for (cand = candidates; cand != NIL; cand = cand->next_candidate) {
01516         /* --- if cand is unary indifferent, it's fine --- */
01517         if (cand->value->common.decider_flag == UNARY_INDIFFERENT_DECIDER_FLAG)
01518             continue;
01519 
01520         #ifdef NUMERIC_INDIFFERENCE
01521                 else if ( cand->value->common.decider_flag==UNARY_INDIFFERENT_CONSTANT_DECIDER_FLAG )  {
01522       /* print("\n Ignoring this candidate because it has a constant value for the second pref"); */
01523       continue;
01524                 }
01525                 #endif
01526                 
01527                 /* --- check whether cand is binary indifferent to each other one --- */
01528         for (p = candidates; p != NIL; p = p->next_candidate) {
01529             if (p == cand)
01530                 continue;
01531             match_found = FALSE;
01532             for (p2 = s->preferences[BINARY_INDIFFERENT_PREFERENCE_TYPE]; p2 != NIL; p2 = p2->next)
01533                 if (((p2->value == cand->value) && (p2->referent == p->value)) ||
01534                     ((p2->value == p->value) && (p2->referent == cand->value))) {
01535                     match_found = TRUE;
01536                     break;
01537                 }
01538             if (!match_found) {
01539                 not_all_indifferent = TRUE;
01540                 break;
01541             }
01542         }                       /* end of for p loop */
01543         if (not_all_indifferent)
01544             break;
01545     }                           /* end of for cand loop */
01546 
01547     if (!not_all_indifferent) {
01548         /* --- items all indifferent, so just pick one of them to return --- */
01549         /* RBD 4/13/95 Removed code that looked for an existing value already in
01550            working memory for this slot, and returned it if found.  This was
01551            apparently an attempt to "stabilize" working memory if attribute
01552            preferences kept changing, but it ended up getting in the way, esp.
01553            with mutually indifferent operators were used with user-select
01554            random. */
01555         /* --- choose according to user-select ---  */
01556 
01557         /* REW: begin 09.15.96 */
01558         /* We don't care about the User Select mode in Operand2 for the
01559          * consistency check.   All we need to do is return the impasse type
01560          * (None because all preferences are indifferent) and return all the
01561          * candidates (rather than just one) because we don;t want to commit
01562          ourselves to single candidate at this point.
01563          */
01564 
01565         *result_candidates = candidates;
01566 
01567         /* We want the whole list of candidates, not just the one that would
01568          * be chosen FIRST (ie, the head of result_candidates is also first),
01569          * so we comment the next line.  */
01570         /* (*result_candidates)->next_candidate = NIL; */
01571         return NONE_IMPASSE_TYPE;
01572 
01573     }
01574 
01575     /* --- items not all indifferent; for context slots this gives a tie --- */
01576     if (s->isa_context_slot) {
01577         *result_candidates = candidates;
01578         return TIE_IMPASSE_TYPE;
01579     }
01580 
01581     /* === Parallels === */
01582     for (cand = candidates; cand != NIL; cand = cand->next_candidate)
01583         cand->value->common.decider_flag = NOTHING_DECIDER_FLAG;
01584     for (p = s->preferences[UNARY_PARALLEL_PREFERENCE_TYPE]; p; p = p->next)
01585         p->value->common.decider_flag = UNARY_PARALLEL_DECIDER_FLAG;
01586     not_all_parallel = FALSE;
01587     for (cand = candidates; cand != NIL; cand = cand->next_candidate) {
01588         /* --- if cand is unary parallel, it's fine --- */
01589         if (cand->value->common.decider_flag == UNARY_PARALLEL_DECIDER_FLAG)
01590             continue;
01591         /* --- check whether cand is binary parallel to each other candidate --- */
01592         for (p = candidates; p != NIL; p = p->next_candidate) {
01593             if (p == cand)
01594                 continue;
01595             match_found = FALSE;
01596             for (p2 = s->preferences[BINARY_PARALLEL_PREFERENCE_TYPE]; p2 != NIL; p2 = p2->next)
01597                 if (((p2->value == cand->value) && (p2->referent == p->value)) ||
01598                     ((p2->value == p->value) && (p2->referent == cand->value))) {
01599                     match_found = TRUE;
01600                     break;
01601                 }
01602             if (!match_found) {
01603                 not_all_parallel = TRUE;
01604                 break;
01605             }
01606         }                       /* end of for p loop */
01607         if (not_all_parallel)
01608             break;
01609     }                           /* end of for cand loop */
01610 
01611     *result_candidates = candidates;
01612 
01613     if (!not_all_parallel) {
01614         /* --- items are all parallel, so return them all --- */
01615         return NONE_IMPASSE_TYPE;
01616     }
01617 
01618     /* --- otherwise we have a tie --- */
01619     return TIE_IMPASSE_TYPE;
01620 }
01621 
01622 /* **************************************************************************
01623 
01624                       Decider and Impasser Routines
01625 
01626 ************************************************************************** */
01627 
01628 /* ------------------------------------------------------------------
01629                         Add Impasse Wme
01630   
01631    This creates a new wme and adds it to the given impasse object.
01632    "Id" indicates the goal/impasse id; (id ^attr value) is the impasse
01633    wme to be added.  The "preference" argument indicates the preference
01634    (if non-NIL) for backtracing.
01635 ------------------------------------------------------------------ */
01636 
01637 void add_impasse_wme(Symbol * id, Symbol * attr, Symbol * value, preference * p)
01638 {
01639     wme *w;
01640 
01641     w = make_wme(id, attr, value, FALSE);
01642     insert_at_head_of_dll(id->id.impasse_wmes, w, next, prev);
01643     w->preference = p;
01644     add_wme_to_wm(w);
01645 }
01646 
01647 /* ------------------------------------------------------------------
01648                          Create New Impasse
01649   
01650    This creates a new impasse, returning its identifier.  The caller is
01651    responsible for filling in either id->isa_impasse or id->isa_goal,
01652    and all the extra stuff for goal identifiers.
01653 ------------------------------------------------------------------ */
01654 
01655 Symbol *create_new_impasse(bool isa_goal, Symbol * object, Symbol * attr, byte impasse_type, goal_stack_level level)
01656 {
01657     Symbol *id;
01658 
01659     id = make_new_identifier((char) (isa_goal ? 'S' : 'I'), level);
01660     post_link_addition(NIL, id);        /* add the special link */
01661 
01662     add_impasse_wme(id, current_agent(type_symbol),
01663                     isa_goal ? current_agent(state_symbol) : current_agent(impasse_symbol), NIL);
01664 
01665     if (isa_goal)
01666         add_impasse_wme(id, current_agent(superstate_symbol), object, NIL);
01667     else
01668         add_impasse_wme(id, current_agent(object_symbol), object, NIL);
01669 
01670     if (attr)
01671         add_impasse_wme(id, current_agent(attribute_symbol), attr, NIL);
01672 
01673     switch (impasse_type) {
01674     case NONE_IMPASSE_TYPE:
01675         break;                  /* this happens only when creating the top goal */
01676     case CONSTRAINT_FAILURE_IMPASSE_TYPE:
01677         add_impasse_wme(id, current_agent(impasse_symbol), current_agent(constraint_failure_symbol), NIL);
01678         add_impasse_wme(id, current_agent(choices_symbol), current_agent(none_symbol), NIL);
01679         break;
01680     case CONFLICT_IMPASSE_TYPE:
01681         add_impasse_wme(id, current_agent(impasse_symbol), current_agent(conflict_symbol), NIL);
01682         add_impasse_wme(id, current_agent(choices_symbol), current_agent(multiple_symbol), NIL);
01683         break;
01684     case TIE_IMPASSE_TYPE:
01685         add_impasse_wme(id, current_agent(impasse_symbol), current_agent(tie_symbol), NIL);
01686         add_impasse_wme(id, current_agent(choices_symbol), current_agent(multiple_symbol), NIL);
01687         break;
01688     case NO_CHANGE_IMPASSE_TYPE:
01689         add_impasse_wme(id, current_agent(impasse_symbol), current_agent(no_change_symbol), NIL);
01690         add_impasse_wme(id, current_agent(choices_symbol), current_agent(none_symbol), NIL);
01691         break;
01692     }
01693     return id;
01694 }
01695 
01696 /* ------------------------------------------------------------------
01697                Create/Remove Attribute Impasse for Slot
01698   
01699    These routines create and remove an attribute impasse for a given
01700    slot.
01701 ------------------------------------------------------------------ */
01702 
01703 void create_new_attribute_impasse_for_slot(slot * s, byte impasse_type)
01704 {
01705     Symbol *id;
01706 
01707     s->impasse_type = impasse_type;
01708     id = create_new_impasse(FALSE, s->id, s->attr, impasse_type, ATTRIBUTE_IMPASSE_LEVEL);
01709     s->impasse_id = id;
01710     id->id.isa_impasse = TRUE;
01711 
01712 #ifndef FEW_CALLBACKS
01713     soar_invoke_callbacks(soar_agent, CREATE_NEW_ATTRIBUTE_IMPASSE_CALLBACK, (soar_call_data) s);
01714 #endif
01715 
01716 }
01717 
01718 void remove_existing_attribute_impasse_for_slot(slot * s)
01719 {
01720     Symbol *id;
01721 
01722 #ifndef FEW_CALLBACKS
01723     soar_invoke_callbacks(soar_agent, REMOVE_ATTRIBUTE_IMPASSE_CALLBACK, (soar_call_data) s);
01724 
01725 #endif
01726 
01727     id = s->impasse_id;
01728     s->impasse_id = NIL;
01729     s->impasse_type = NONE_IMPASSE_TYPE;
01730     remove_wme_list_from_wm(id->id.impasse_wmes);
01731     id->id.impasse_wmes = NIL;
01732     post_link_removal(NIL, id); /* remove the special link */
01733     symbol_remove_ref(id);
01734 }
01735 
01736 /* ------------------------------------------------------------------
01737             Fake Preferences for Goal ^Item Augmentations
01738   
01739    When we backtrace through a (goal ^item) augmentation, we want
01740    to backtrace to the acceptable preference wme in the supercontext
01741    corresponding to that ^item.  A slick way to do this automagically
01742    is to set the backtracing preference pointer on the (goal ^item)
01743    wme to be a "fake" preference for a "fake" instantiation.  The
01744    instantiation has as its LHS a list of one condition, which matched
01745    the acceptable preference wme in the supercontext.
01746 
01747    Make_fake_preference_for_goal_item() builds such a fake preference
01748    and instantiation, given a pointer to the supergoal and the
01749    acceptable/require preference for the value, and returns a pointer
01750    to the fake preference.  *** for Soar 7.3, we changed the fake
01751    preference to be ACCEPTABLE instead of REQUIRE.  This could
01752    potentially break some code, but it avoids the BUGBUG condition
01753    that can occur when you have a REQUIRE lower in the stack than an
01754    ACCEPTABLE but the goal stack gets popped while the WME backtrace
01755    still points to the REQUIRE, instead of the higher ACCEPTABLE.
01756    See the section above on Preference Semantics.  It also allows
01757    the GDS to backtrace through ^items properly.
01758    
01759    Remove_fake_preference_for_goal_item() is called to clean up the
01760    fake stuff once the (goal ^item) wme is no longer needed.
01761 ------------------------------------------------------------------ */
01762 
01763 preference *make_fake_preference_for_goal_item(Symbol * goal, preference * cand)
01764 {
01765     slot *s;
01766     wme *ap_wme;
01767     instantiation *inst;
01768     preference *pref;
01769     condition *cond;
01770 
01771     /* --- find the acceptable preference wme we want to backtrace to --- */
01772     s = cand->slot;
01773     for (ap_wme = s->acceptable_preference_wmes; ap_wme != NIL; ap_wme = ap_wme->next)
01774         if (ap_wme->value == cand->value)
01775             break;
01776     if (!ap_wme) {
01777         char msg[MESSAGE_SIZE];
01778         strncpy(msg, "decide.c: Internal error: couldn't find acceptable pref wme\n", MESSAGE_SIZE);
01779         msg[MESSAGE_SIZE - 1] = 0;
01780         abort_with_fatal_error(msg);
01781     }
01782     /* --- make the fake preference --- */
01783     /* kjc:  here's where we changed REQUIRE to ACCEPTABLE */
01784     pref = make_preference(ACCEPTABLE_PREFERENCE_TYPE, goal, current_agent(item_symbol), cand->value, NIL);
01785     symbol_add_ref(pref->id);
01786     symbol_add_ref(pref->attr);
01787     symbol_add_ref(pref->value);
01788     insert_at_head_of_dll(goal->id.preferences_from_goal, pref, all_of_goal_next, all_of_goal_prev);
01789     pref->on_goal_list = TRUE;
01790     preference_add_ref(pref);
01791     /* --- make the fake instantiation --- */
01792     allocate_with_pool(&current_agent(instantiation_pool), &inst);
01793     pref->inst = inst;
01794     pref->inst_next = pref->inst_prev = NIL;
01795     inst->preferences_generated = pref;
01796     inst->prod = NIL;
01797     inst->next = inst->prev = NIL;
01798     inst->rete_token = NIL;
01799     inst->rete_wme = NIL;
01800     inst->match_goal = goal;
01801     inst->match_goal_level = goal->id.level;
01802     inst->okay_to_variablize = TRUE;
01803     inst->backtrace_number = 0;
01804     inst->in_ms = FALSE;
01805     /* --- make the fake condition --- */
01806     allocate_with_pool(&current_agent(condition_pool), &cond);
01807     cond->type = POSITIVE_CONDITION;
01808     cond->next = cond->prev = NIL;
01809     inst->top_of_instantiated_conditions = cond;
01810     inst->bottom_of_instantiated_conditions = cond;
01811     inst->nots = NIL;
01812     cond->data.tests.id_test = make_equality_test(ap_wme->id);
01813     cond->data.tests.attr_test = make_equality_test(ap_wme->attr);
01814     cond->data.tests.value_test = make_equality_test(ap_wme->value);
01815     cond->test_for_acceptable_preference = TRUE;
01816     cond->bt.wme = ap_wme;
01817     wme_add_ref(ap_wme);
01818     cond->bt.level = ap_wme->id->id.level;
01819     cond->bt.trace = NIL;
01820     cond->bt.prohibits = NIL;
01821 
01822     /* --- return the fake preference --- */
01823     return pref;
01824 }
01825 
01826 void remove_fake_preference_for_goal_item(preference * pref)
01827 {
01828     preference_remove_ref(pref);        /* everything else happens automatically */
01829 }
01830 
01831 /* ------------------------------------------------------------------
01832                        Update Impasse Items
01833   
01834    This routine updates the set of ^item wmes on a goal or attribute
01835    impasse.  It takes the identifier of the goal/impasse, and a list
01836    of preferences (linked via the "next_candidate" field) for the new
01837    set of items that should be there.
01838 ------------------------------------------------------------------ */
01839 
01840 void update_impasse_items(Symbol * id, preference * items)
01841 {
01842     wme *w, *next_w;
01843     preference *cand;
01844     preference *bt_pref;
01845 
01846     /* --- reset flags on existing items to "NOTHING" --- */
01847     for (w = id->id.impasse_wmes; w != NIL; w = w->next)
01848         if (w->attr == current_agent(item_symbol))
01849             w->value->common.decider_flag = NOTHING_DECIDER_FLAG;
01850 
01851     /* --- mark set of desired items as "CANDIDATEs" --- */
01852     for (cand = items; cand != NIL; cand = cand->next_candidate)
01853         cand->value->common.decider_flag = CANDIDATE_DECIDER_FLAG;
01854 
01855     /* --- for each existing item:  if it's supposed to be there still, then
01856        mark it "ALREADY_EXISTING"; otherwise remove it --- */
01857     w = id->id.impasse_wmes;
01858     while (w) {
01859         next_w = w->next;
01860         if (w->attr == current_agent(item_symbol)) {
01861             if (w->value->common.decider_flag == CANDIDATE_DECIDER_FLAG) {
01862                 w->value->common.decider_flag = ALREADY_EXISTING_WME_DECIDER_FLAG;
01863                 w->value->common.a.decider_wme = w;     /* so we can update the pref later */
01864             } else {
01865                 remove_from_dll(id->id.impasse_wmes, w, next, prev);
01866                 if (id->id.isa_goal)
01867                     remove_fake_preference_for_goal_item(w->preference);
01868                 remove_wme_from_wm(w);
01869             }
01870         }
01871         w = next_w;
01872     }
01873 
01874     /* --- for each desired item:  if it doesn't ALREADY_EXIST, add it --- */
01875     for (cand = items; cand != NIL; cand = cand->next_candidate) {
01876         if (id->id.isa_goal)
01877             bt_pref = make_fake_preference_for_goal_item(id, cand);
01878         else
01879             bt_pref = cand;
01880         if (cand->value->common.decider_flag == ALREADY_EXISTING_WME_DECIDER_FLAG) {
01881             if (id->id.isa_goal)
01882                 remove_fake_preference_for_goal_item(cand->value->common.a.decider_wme->preference);
01883             cand->value->common.a.decider_wme->preference = bt_pref;
01884         } else {
01885             add_impasse_wme(id, current_agent(item_symbol), cand->value, bt_pref);
01886         }
01887     }
01888 }
01889 
01890 /* ------------------------------------------------------------------
01891                        Decide Non Context Slot
01892   
01893    This routine decides a given slot, which must be a non-context
01894    slot.  It calls run_preference_semantics() on the slot, then
01895    updates the wmes and/or impasse for the slot accordingly.
01896 ------------------------------------------------------------------ */
01897 
01898 void decide_non_context_slot(slot * s)
01899 {
01900     byte impasse_type;
01901     wme *w, *next_w;
01902     preference *candidates, *cand;
01903 #ifndef DONT_CALC_GDS_OR_BT
01904     preference *pref;
01905 #endif
01906 
01907     impasse_type = run_preference_semantics(s, &candidates);
01908 
01909     if (impasse_type == NONE_IMPASSE_TYPE) {
01910         /* --- no impasse, so remove any existing one and update the wmes --- */
01911         if (s->impasse_type != NONE_IMPASSE_TYPE)
01912             remove_existing_attribute_impasse_for_slot(s);
01913         /* --- reset marks on existing wme values to "NOTHING" --- */
01914         for (w = s->wmes; w != NIL; w = w->next)
01915             w->value->common.decider_flag = NOTHING_DECIDER_FLAG;
01916         /* --- set marks on desired values to "CANDIDATES" --- */
01917         for (cand = candidates; cand != NIL; cand = cand->next_candidate)
01918             cand->value->common.decider_flag = CANDIDATE_DECIDER_FLAG;
01919         /* --- for each existing wme, if we want it there, mark it as
01920            ALREADY_EXISTING; otherwise remove it --- */
01921         w = s->wmes;
01922         while (w) {
01923             next_w = w->next;
01924             if (w->value->common.decider_flag == CANDIDATE_DECIDER_FLAG) {
01925                 w->value->common.decider_flag = ALREADY_EXISTING_WME_DECIDER_FLAG;
01926                 w->value->common.a.decider_wme = w;     /* so we can set the pref later */
01927             } else {
01928                 remove_from_dll(s->wmes, w, next, prev);
01929 
01930 #ifndef DONT_CALC_GDS_OR_BT
01931                 /* REW: begin 09.15.96 */
01932 #ifndef SOAR_8_ONLY
01933                 if (current_agent(operand2_mode)) {
01934 #endif
01935                     if (w->gds) {
01936                         if (w->gds->goal != NIL) {
01937                             /* If the goal pointer is non-NIL, then goal is in the stack */
01938                             if (current_agent(soar_verbose_flag)) {
01939                                 print("\n          Removing goal %d because element in GDS changed.",
01940                                       w->gds->goal->id.level);
01941                                 print(" WME: ");
01942                                 print_wme(w);
01943                             }
01944                             gds_invalid_so_remove_goal(w);
01945                         }
01946                     }
01947 #ifndef SOAR_8_ONLY
01948                 }
01949 #endif
01950 #endif                          /* DONT_CALC_GDS_OR_BT */
01951                 /* REW: end   09.15.96 */
01952                 remove_wme_from_wm(w);
01953             }
01954             w = next_w;
01955         }                       /* end while (W) */
01956 
01957         /* --- for each desired value, if it's not already there, add it --- */
01958         for (cand = candidates; cand != NIL; cand = cand->next_candidate) {
01959             if (cand->value->common.decider_flag == ALREADY_EXISTING_WME_DECIDER_FLAG) {
01960                 /* REW: begin 11.22.97 */
01961                 /* print("\n This WME was marked as already existing...."); print_wme(cand->value->common.a.decider_wme); */
01962 
01963                 /* REW: end   11.22.97 */
01964                 cand->value->common.a.decider_wme->preference = cand;
01965             } else {
01966                 w = make_wme(cand->id, cand->attr, cand->value, FALSE);
01967                 insert_at_head_of_dll(s->wmes, w, next, prev);
01968                 w->preference = cand;
01969 
01970 #ifndef DONT_CALC_GDS_OR_BT
01971                 /* REW: begin 09.15.96 */
01972 #ifndef SOAR_8_ONLY
01973                 if (current_agent(operand2_mode)) {
01974 #endif
01975                     /* Whenever we add a WME to WM, we also want to check and see if
01976                        this new WME is o-supported.  If so, then we want to add the
01977                        supergoal dependencies of the new, o-supported element to the
01978                        goal in which the element was created (as long as the o_supported
01979                        element was not created in the top state -- the top goal has
01980                        no gds).  */
01981 
01982 #ifndef NO_TIMING_STUFF
01983 #ifdef DETAILED_TIMING_STATS
01984                     /* REW: begin 11.25.96 */
01985                     start_timer(&current_agent(start_gds_tv));
01986                     /* REW: end   11.25.96 */
01987 #endif
01988 #endif
01989                     current_agent(parent_list_head) = NIL;
01990 
01991                     /* If the working memory element being added is going to have
01992                        o_supported preferences and the instantion that created it
01993                        is not in the top_level_goal (where there is no GDS), then
01994                        loop over the preferences for this WME and determine which
01995                        WMEs should be added to the goal's GDS (the goal here being the
01996                        goal to which the added memory is attached). */
01997 
01998 #ifdef NO_TOP_JUST
01999 
02000                     if ((w->preference->o_supported == TRUE) && (w->preference->match_goal_level != 1)) {
02001 
02002                         if (w->preference->match_goal->id.gds == NIL) {
02003                             /* If there is no GDS yet for this goal,
02004                              * then we need to create one */
02005                             if (w->preference->match_goal_level == w->preference->id->id.level) {
02006 
02007                                 create_gds_for_goal(w->preference->match_goal);
02008 #else
02009                     if ((w->preference->o_supported == TRUE) && (w->preference->inst->match_goal_level != 1)) {
02010 
02011                         if (w->preference->inst->match_goal->id.gds == NIL) {
02012                             /* If there is no GDS yet for this goal,
02013                              * then we need to create one */
02014 
02015                             if (w->preference->inst->match_goal_level == w->preference->id->id.level) {
02016 
02017                                 create_gds_for_goal(w->preference->inst->match_goal);
02018 #endif
02019 
02020                                 /* REW: BUG When chunks and result instantiations both create
02021                                  * preferences for the same WME, then we only want to create
02022                                  * the GDS for the highest goal.  Right now I ensure that we
02023                                  * elaborate the correct GDS with the tests in the loop just
02024                                  * below this code, but the GDS creation above assumes that
02025                                  * the chunk will be first on the GDS list.  This order
02026                                  * appears to be always true, although I am not 100% certain
02027                                  * (I think it occurs this way because the chunk is
02028                                  * necessarily added to the instantiaton list after the
02029                                  * original instantiation and lists get built such older items
02030                                  * appear further from the head of the list) . If not true,
02031                                  * then we need to keep track of any GDS's that get created
02032                                  * here to remove them later if we find a higher match goal
02033                                  * for the WME. For now, the program just exits in this
02034                                  * situation; otherwise, we would build a GDS for the wrong
02035                                  * level and never elaborate it (resulting in a memory
02036                                  * leak). 
02037                                  */
02038                             } else {
02039                                 char msg[MESSAGE_SIZE];
02040                                 print_wme(w);
02041                                 print_preference(w->preference);
02042 #ifdef NO_TOP_JUST
02043                                 snprintf(msg, MESSAGE_SIZE,
02044                                          "**** (NO_TOP_JUST) Wanted to create a GDS for a WME level (%d) different from the instantiation level (%d).....Big problems....exiting....(instantiation = %p, inst->match_goal_level = %d)****\n\n",
02045                                          w->preference->id->id.level, w->preference->match_goal_level,
02046                                          w->preference->inst, w->preference->inst->match_goal_level);
02047                                 msg[MESSAGE_SIZE - 1] = 0;      /* snprintf doesn't set last char to null if output is truncated */
02048 #else
02049                                 snprintf(msg, MESSAGE_SIZE,
02050                                          "**** Wanted to create a GDS for a WME level (%d) different from the instantiation level (%d).....Big problems....exiting....****\n\n",
02051                                          w->preference->id->id.level, w->preference->inst->match_goal_level);
02052                                 msg[MESSAGE_SIZE - 1] = 0;      /* snprintf doesn't set last char to null if output is truncated */
02053 #endif
02054                                 abort_with_fatal_error(msg);
02055                             }
02056                         }
02057 
02058                         /* end if no GDS yet for goal... */
02059                         /* Loop over all the preferences for this WME:
02060                          *   If the instantiation that lead to the preference has not 
02061                          *         been already explored; OR
02062                          *   If the instantiation is not an subgoal instantiation
02063                          *          for a chunk instantiation we are already exploring
02064                          *   Then
02065                          *      Add the instantiation to a list of instantiations that
02066                          *          will be explored in elaborate_gds().
02067                          */
02068                         for (pref = w->preference; pref != NIL; pref = pref->next) {
02069 #ifdef DEBUG_GDS_HIGH
02070                             print("\n\n   ");
02071                             print_preference(pref);
02072                             print("   Goal level of preference: %d\n", pref->id->id.level);
02073 #endif
02074 
02075                             if (pref->inst->GDS_evaluated_already == FALSE) {
02076 #ifdef DEBUG_GDS_HIGH
02077                                 print_with_symbols("   Match goal lev of instantiation %y ", pref->inst->prod->name);
02078                                 print("is %d\n", pref->inst->match_goal_level);
02079 #endif
02080                                 if (pref->inst->match_goal_level > pref->id->id.level) {
02081 #ifdef DEBUG_GDS_HIGH
02082                                     print_with_symbols
02083                                         ("        %y  is simply the instantiation that led to a chunk.\n        Not adding it the current instantiations.\n",
02084                                          pref->inst->prod->name);
02085 #endif
02086 
02087                                 } else {
02088 #ifdef DEBUG_GDS_HIGH
02089                                     print_with_symbols("\n   Adding %y to list of parent instantiations\n",
02090                                                        pref->inst->prod->name);
02091 #endif
02092                                     uniquely_add_to_head_of_dll(pref->inst);
02093                                     pref->inst->GDS_evaluated_already = TRUE;
02094                                 }
02095                             }   /* end if GDS_evaluated_already is FALSE */
02096 #ifdef DEBUG_GDS_HIGH
02097                             else
02098                                 print_with_symbols("\n    Instantiation %y was already explored; skipping it\n",
02099                                                    pref->inst->prod->name);
02100 #endif
02101 
02102                         }       /* end of forloop over preferences for this wme */
02103 
02104 #ifdef DEBUG_GDS_HIGH
02105                         print("\n    CALLING ELABORATE GDS....\n");
02106 #endif
02107                         elaborate_gds();
02108 
02109                         /* technically, the list should be empty at this point ??? */
02110 
02111                         free_parent_list();
02112 #ifdef DEBUG_GDS_HIGH
02113                         print("    FINISHED ELABORATING GDS.\n\n");
02114 #endif
02115                     }
02116 
02117                     /* end if w->preference->o_supported == TRUE ... */
02118 #ifndef NO_TIMING_STUFF
02119 #ifdef DETAILED_TIMING_STATS
02120                     /* REW: begin 11.25.96 */
02121                     stop_timer(&current_agent(start_gds_tv),
02122                                &current_agent(gds_cpu_time[current_agent(current_phase)]));
02123                     /* REW: end   11.25.96 */
02124 #endif
02125 #endif
02126 #ifndef SOAR_8_ONLY
02127                 }               /* end if current_agent(OPERAND2_MODE) ... */
02128 #endif
02129 
02130 #endif                          /* DONT_CALC_GDS_OR_BT */
02131 
02132                 /* REW: end   09.15.96 */
02133 
02134                 add_wme_to_wm(w);
02135             }
02136         }
02137         return;
02138     }
02139 
02140     /* end of if impasse type == NONE */
02141     /* --- impasse type != NONE --- */
02142     if (s->wmes) {              /* --- remove any existing wmes --- */
02143         remove_wme_list_from_wm(s->wmes);
02144         s->wmes = NIL;
02145     }
02146     /* --- create and/or update impasse structure --- */
02147     if (s->impasse_type != NONE_IMPASSE_TYPE) {
02148         if (s->impasse_type != impasse_type) {
02149             remove_existing_attribute_impasse_for_slot(s);
02150             create_new_attribute_impasse_for_slot(s, impasse_type);
02151         }
02152         update_impasse_items(s->impasse_id, candidates);
02153     } else {
02154         create_new_attribute_impasse_for_slot(s, impasse_type);
02155         update_impasse_items(s->impasse_id, candidates);
02156     }
02157 }
02158 
02159 /* ------------------------------------------------------------------
02160                       Decide Non Context Slots
02161   
02162    This routine iterates through all changed non-context slots, and
02163    decides each one.
02164 ------------------------------------------------------------------ */
02165 
02166 void decide_non_context_slots(void)
02167 {
02168     dl_cons *dc;
02169     slot *s;
02170 
02171     while (current_agent(changed_slots)) {
02172         dc = current_agent(changed_slots);
02173         current_agent(changed_slots) = current_agent(changed_slots)->next;
02174         s = dc->item;
02175         decide_non_context_slot(s);
02176         s->changed = NIL;
02177         free_with_pool(&current_agent(dl_cons_pool), dc);
02178     }
02179 }
02180 
02181 /* ------------------------------------------------------------------
02182                       Context Slot Is Decidable
02183   
02184    This returns TRUE iff the given slot (which must be a context slot)
02185    is decidable.  A context slot is decidable if:
02186      - it has an installed value in WM and there is a reconsider
02187        preference for that value, or
02188      - it has no installed value but does have changed preferences
02189 ------------------------------------------------------------------ */
02190 
02191 bool context_slot_is_decidable(slot * s)
02192 {
02193     Symbol *v;
02194     preference *p;
02195 
02196     if (!s->wmes)
02197         return (bool) (s->changed != NIL);
02198     v = s->wmes->value;
02199     for (p = s->preferences[RECONSIDER_PREFERENCE_TYPE]; p != NIL; p = p->next)
02200         if (v == p->value)
02201             return TRUE;
02202     return FALSE;
02203 }
02204 
02205 /* ------------------------------------------------------------------
02206                       Remove WMEs For Context Slot
02207   
02208    This removes the wmes (there can only be 0 or 1 of them) for the
02209    given context slot.
02210 ------------------------------------------------------------------ */
02211 
02212 void remove_wmes_for_context_slot(slot * s)
02213 {
02214     wme *w;
02215 
02216     if (!s->wmes)
02217         return;
02218     /* Note that we only need to handle one wme--context slots never have
02219        more than one wme in them */
02220     w = s->wmes;
02221     preference_remove_ref(w->preference);
02222     remove_wme_from_wm(w);
02223     s->wmes = NIL;
02224 }
02225 
02226 /* ------------------------------------------------------------------
02227                  Remove Existing Context And Descendents
02228   
02229    This routine truncates the goal stack by removing the given goal
02230    and all its subgoals.  (If the given goal is the top goal, the
02231    entire context stack is removed.)
02232 ------------------------------------------------------------------ */
02233 
02234 void remove_existing_context_and_descendents(Symbol * goal)
02235 {
02236     preference *p;
02237 
02238     ms_change *head, *tail;     /* REW:   08.20.97 */
02239 
02240     /* --- remove descendents of this goal --- */
02241 #ifdef GOAL_SANITY_CHECK
02242 
02243     /*  printf ( "Goal id.level = %d\n", (goal->id.level) ); */
02244     if (goal->id.level < 0 || goal->id.level > 1000) {
02245         print("Warning: goal id is of a bizzare value: %d\n", goal->id.level);
02246         printf("Warning: goal id is of a bizzare value: %d\n", goal->id.level);
02247     }
02248 #endif
02249     if (goal->id.lower_goal)
02250         remove_existing_context_and_descendents(goal->id.lower_goal);
02251 
02252 #ifndef FEW_CALLBACKS
02253 
02254     /* --- invoke callback routine --- */
02255     soar_invoke_callbacks(soar_agent, POP_CONTEXT_STACK_CALLBACK, (soar_call_data) goal);
02256 
02257 #endif
02258     /* --- disconnect this goal from the goal stack --- */
02259     if (goal == current_agent(top_goal)) {
02260         current_agent(top_goal) = NIL;
02261         current_agent(bottom_goal) = NIL;
02262     } else {
02263         current_agent(bottom_goal) = goal->id.higher_goal;
02264         current_agent(bottom_goal)->id.lower_goal = NIL;
02265     }
02266 
02267     /* --- remove any preferences supported by this goal --- */
02268     while (goal->id.preferences_from_goal) {
02269         p = goal->id.preferences_from_goal;
02270         remove_from_dll(goal->id.preferences_from_goal, p, all_of_goal_next, all_of_goal_prev);
02271         p->on_goal_list = FALSE;
02272         if (!remove_preference_from_clones(p))
02273             if (p->in_tm)
02274                 remove_preference_from_tm(p);
02275     }
02276 
02277     /* --- remove wmes for this goal, and garbage collect --- */
02278     remove_wmes_for_context_slot(goal->id.operator_slot);
02279     update_impasse_items(goal, NIL);    /* causes items & fake pref's to go away */
02280     remove_wme_list_from_wm(goal->id.impasse_wmes);
02281     goal->id.impasse_wmes = NIL;
02282     /* REW: begin   09.15.96 */
02283     /* If there was a GDS for this goal, we want to set the pointer for the
02284        goal to NIL to indicate it no longer exists.  
02285        BUG: We probably also need to make certain that the GDS doesn't need
02286        to be free'd here as well. */
02287     if (goal->id.gds != NIL)
02288         goal->id.gds->goal = NIL;
02289     /* REW: end   09.15.96 */
02290 
02291     /* REW: begin 08.20.97 */
02292 
02293     /* If we remove a goal WME, then we have to transfer any already existing
02294        retractions to the nil-goal list on the current agent.  We should be
02295        able to do this more efficiently but the most obvious way (below) still
02296        requires scanning over the whole list (to set the goal pointer of each
02297        msc to NIL); therefore this solution should be acceptably efficient. */
02298 
02299     if (goal->id.ms_retractions) {      /* There's something on the retraction list */
02300 
02301         head = goal->id.ms_retractions;
02302         tail = head;
02303 
02304         /* find the tail of this list */
02305         while (tail->next_in_level) {
02306             tail->goal = NIL;   /* force the goal to be NIL */
02307             tail = tail->next_in_level;
02308         }
02309         tail->goal = NIL;
02310 
02311         if (current_agent(nil_goal_retractions)) {
02312             /* There are already retractions on the list */
02313 
02314             /* Append this list to front of NIL goal list */
02315             current_agent(nil_goal_retractions)->prev_in_level = tail;
02316             tail->next_in_level = current_agent(nil_goal_retractions);
02317             current_agent(nil_goal_retractions) = head;
02318 
02319         } else {                /* If no retractions, make this list the NIL goal list */
02320             current_agent(nil_goal_retractions) = head;
02321         }
02322     }
02323 
02324     /* REW: BUG
02325      * Tentative assertions can exist for removed goals.  However, it looks
02326      * like the removal forces a tentative retraction, which then leads to
02327      * the deletion of the tentative assertion.  However, I have not tested
02328      * such cases exhaustively -- I would guess that some processing may be
02329      * necessary for the assertions here at some point?
02330      */
02331 
02332     /* REW: end   08.20.97 */
02333 
02334     post_link_removal(NIL, goal);       /* remove the special link */
02335     symbol_remove_ref(goal);
02336 }
02337 
02338 /* ------------------------------------------------------------------
02339                          Create New Context
02340   
02341    This routine creates a new goal context (becoming the new bottom
02342    goal) below the current bottom goal.  If there is no current
02343    bottom goal, this routine creates a new goal and makes it both
02344    the top and bottom goal.
02345 ------------------------------------------------------------------ */
02346 
02347 void create_new_context(Symbol * attr_of_impasse, byte impasse_type)
02348 {
02349     Symbol *id;
02350 
02351     if (current_agent(bottom_goal)) {
02352         id = create_new_impasse(TRUE, current_agent(bottom_goal), attr_of_impasse, impasse_type, (goal_stack_level)
02353                                 (current_agent(bottom_goal)->id.level + 1));
02354         id->id.higher_goal = current_agent(bottom_goal);
02355         current_agent(bottom_goal)->id.lower_goal = id;
02356         current_agent(bottom_goal) = id;
02357         add_impasse_wme(id, current_agent(quiescence_symbol), current_agent(t_symbol), NIL);
02358     } else {
02359         id = create_new_impasse(TRUE, current_agent(nil_symbol), NIL, NONE_IMPASSE_TYPE, TOP_GOAL_LEVEL);
02360         current_agent(top_goal) = id;
02361         current_agent(bottom_goal) = id;
02362         current_agent(top_state) = current_agent(top_goal);
02363         id->id.higher_goal = NIL;
02364         id->id.lower_goal = NIL;
02365     }
02366     id->id.isa_goal = TRUE;
02367     id->id.operator_slot = make_slot(id, current_agent(operator_symbol));
02368     id->id.allow_bottom_up_chunks = TRUE;
02369 
02370 #ifndef FEW_CALLBACKS
02371 
02372     /* --- invoke callback routine --- */
02373     soar_invoke_callbacks(soar_agent, CREATE_NEW_CONTEXT_CALLBACK, (soar_call_data) id);
02374 
02375 #endif
02376 }
02377 
02378 /* ------------------------------------------------------------------
02379               Type and Attribute of Existing Impasse
02380   
02381    Given a goal, these routines return the type and attribute,
02382    respectively, of the impasse just below that goal context.  It
02383    does so by looking at the impasse wmes for the next lower goal
02384    in the goal stack.
02385 ------------------------------------------------------------------ */
02386 
02387 byte type_of_existing_impasse(Symbol * goal)
02388 {
02389     wme *w;
02390     char msg[MESSAGE_SIZE];
02391 
02392     if (!goal->id.lower_goal)
02393         return NONE_IMPASSE_TYPE;
02394     for (w = goal->id.lower_goal->id.impasse_wmes; w != NIL; w = w->next)
02395         if (w->attr == current_agent(impasse_symbol)) {
02396             if (w->value == current_agent(no_change_symbol))
02397                 return NO_CHANGE_IMPASSE_TYPE;
02398             if (w->value == current_agent(tie_symbol))
02399                 return TIE_IMPASSE_TYPE;
02400             if (w->value == current_agent(constraint_failure_symbol))
02401                 return CONSTRAINT_FAILURE_IMPASSE_TYPE;
02402             if (w->value == current_agent(conflict_symbol))
02403                 return CONFLICT_IMPASSE_TYPE;
02404             if (w->value == current_agent(none_symbol))
02405                 return NONE_IMPASSE_TYPE;
02406             strncpy(msg, "decide.c: Internal error: bad type of existing impasse.\n", MESSAGE_SIZE);
02407             msg[MESSAGE_SIZE - 1] = 0;
02408             abort_with_fatal_error(msg);
02409         }
02410     strncpy(msg, "decide.c: Internal error: couldn't find type of existing impasse.\n", MESSAGE_SIZE);
02411     msg[MESSAGE_SIZE - 1] = 0;
02412     abort_with_fatal_error(msg);
02413     return 0;                   /* unreachable, but without it, gcc -Wall warns here */
02414 }
02415 
02416 Symbol *attribute_of_existing_impasse(Symbol * goal)
02417 {
02418     wme *w;
02419 
02420     if (!goal->id.lower_goal)
02421         return NIL;
02422     for (w = goal->id.lower_goal->id.impasse_wmes; w != NIL; w = w->next)
02423         if (w->attr == current_agent(attribute_symbol))
02424             return w->value;
02425     {
02426         char msg[MESSAGE_SIZE];
02427         strncpy(msg, "decide.c: Internal error: couldn't find attribute of existing impasse.\n", MESSAGE_SIZE);
02428         msg[MESSAGE_SIZE - 1] = 0;
02429         abort_with_fatal_error(msg);
02430     }
02431     return NIL;                 /* unreachable, but without it, gcc -Wall warns here */
02432 }
02433 
02434 /* ------------------------------------------------------------------
02435                        Decide Context Slot
02436 
02437    This decides the given context slot.  It normally returns TRUE,
02438    but returns FALSE if the ONLY change as a result of the decision
02439    procedure was a change in the set of ^item's on the impasse below
02440    the given slot.
02441 ------------------------------------------------------------------ */
02442 
02443 bool decide_context_slot(Symbol * goal, slot * s)
02444 {
02445     byte impasse_type;
02446     Symbol *attribute_of_impasse;
02447     wme *w;
02448     preference *candidates;
02449     preference *temp;
02450 
02451     if (!context_slot_is_decidable(s)) {
02452         /* --- the only time we decide a slot that's not "decidable" is when it's
02453            the last slot in the entire context stack, in which case we have a
02454            no-change impasse there --- */
02455         impasse_type = NO_CHANGE_IMPASSE_TYPE;
02456         candidates = NIL;       /* we don't want any impasse ^item's later */
02457     } else {
02458         /* --- the slot is decidable, so run preference semantics on it --- */
02459         impasse_type = run_preference_semantics(s, &candidates);
02460         remove_wmes_for_context_slot(s);        /* must remove old wme before adding
02461                                                    the new one (if any) */
02462         if (impasse_type == NONE_IMPASSE_TYPE) {
02463             if (!candidates) {
02464                 /* --- no winner ==> no-change impasse on the previous slot --- */
02465                 impasse_type = NO_CHANGE_IMPASSE_TYPE;
02466             } else if (candidates->next_candidate) {
02467                 /* --- more than one winner ==> internal error --- */
02468                 char msg[MESSAGE_SIZE];
02469                 strncpy(msg, "decide.c: Internal error: more than one winner for context slot\n", MESSAGE_SIZE);
02470                 msg[MESSAGE_SIZE - 1] = 0;
02471                 abort_with_fatal_error(msg);
02472             }
02473         }
02474     }                           /* end if !context_slot_is_decidable  */
02475 
02476     /* --- mark the slot as not changed --- */
02477     s->changed = NIL;
02478 
02479     /* --- determine the attribute of the impasse (if there is no impasse,
02480      * this doesn't matter) --- */
02481     if (impasse_type == NO_CHANGE_IMPASSE_TYPE) {
02482         if (s->wmes) {
02483             attribute_of_impasse = s->attr;
02484         } else {
02485             attribute_of_impasse = current_agent(state_symbol);
02486         }
02487     } else {
02488         /* --- for all other kinds of impasses --- */
02489         attribute_of_impasse = s->attr;
02490     }
02491 
02492     /* --- remove wme's for lower slots of this context --- */
02493     if (attribute_of_impasse == current_agent(state_symbol)) {
02494         remove_wmes_for_context_slot(goal->id.operator_slot);
02495     }
02496 
02497     /* --- if we have a winner, remove any existing impasse and install the
02498        new value for the current slot --- */
02499     if (impasse_type == NONE_IMPASSE_TYPE) {
02500         for (temp = candidates; temp; temp = temp->next_candidate)
02501             preference_add_ref(temp);
02502         if (goal->id.lower_goal)
02503             remove_existing_context_and_descendents(goal->id.lower_goal);
02504         w = make_wme(s->id, s->attr, candidates->value, FALSE);
02505         insert_at_head_of_dll(s->wmes, w, next, prev);
02506         w->preference = candidates;
02507         preference_add_ref(w->preference);
02508         add_wme_to_wm(w);
02509         for (temp = candidates; temp; temp = temp->next_candidate)
02510             preference_remove_ref(temp);
02511         return TRUE;
02512     }
02513 
02514     /* --- no winner; if an impasse of the right type already existed, just
02515        update the ^item set on it --- */
02516     if ((impasse_type == type_of_existing_impasse(goal)) &&
02517         (attribute_of_impasse == attribute_of_existing_impasse(goal))) {
02518         update_impasse_items(goal->id.lower_goal, candidates);
02519         return FALSE;
02520     }
02521 
02522     /* --- no impasse already existed, or an impasse of the wrong type
02523        already existed --- */
02524     for (temp = candidates; temp; temp = temp->next_candidate)
02525         preference_add_ref(temp);
02526     if (goal->id.lower_goal)
02527         remove_existing_context_and_descendents(goal->id.lower_goal);
02528 
02529     /* REW: begin 10.24.97 */
02530 #ifndef SOAR_8_ONLY
02531     if (current_agent(operand2_mode) && current_agent(waitsnc) &&
02532         (impasse_type == NO_CHANGE_IMPASSE_TYPE) && (attribute_of_impasse == current_agent(state_symbol))) {
02533 #else
02534     if (current_agent(waitsnc) &&
02535         (impasse_type == NO_CHANGE_IMPASSE_TYPE) && (attribute_of_impasse == current_agent(state_symbol))) {
02536 #endif
02537         current_agent(waitsnc_detect) = TRUE;
02538         if (soar_exists_callback(soar_agent, WAIT_CALLBACK)) {
02539             soar_invoke_first_callback(soar_agent, WAIT_CALLBACK, NULL);
02540         }
02541 
02542     } else {
02543         /* REW: end     10.24.97 */
02544         create_new_context(attribute_of_impasse, impasse_type);
02545         update_impasse_items(goal->id.lower_goal, candidates);
02546     }
02547 
02548     for (temp = candidates; temp; temp = temp->next_candidate)
02549         preference_remove_ref(temp);
02550     return TRUE;
02551 }
02552 
02553 /* ------------------------------------------------------------------
02554                        Decide Context Slots
02555 
02556    This scans down the goal stack and runs the decision procedure on
02557    the appropriate context slots.
02558 ------------------------------------------------------------------ */
02559 
02560 void decide_context_slots(void)
02561 {
02562     Symbol *goal;
02563     slot *s;
02564 
02565     if (current_agent(highest_goal_whose_context_changed)) {
02566         goal = current_agent(highest_goal_whose_context_changed);
02567     } else
02568         /* no context changed, so jump right to the bottom */
02569         goal = current_agent(bottom_goal);
02570 
02571     s = goal->id.operator_slot;
02572 
02573     /* --- loop down context stack --- */
02574     for (;;) {
02575         /* --- find next slot to decide --- */
02576         for (;;) {
02577             if (context_slot_is_decidable(s))
02578                 break;
02579 
02580             if ((s == goal->id.operator_slot) || (!s->wmes)) {
02581                 /* --- no more slots to look at for this goal; have we reached
02582                    the last slot in whole stack? --- */
02583                 if (!goal->id.lower_goal)
02584                     break;
02585                 /* --- no, go down one level --- */
02586                 goal = goal->id.lower_goal;
02587                 s = goal->id.operator_slot;
02588             }
02589         }                       /* end of while (TRUE) find next slot to decide */
02590 
02591         /* --- now go and decide that slot --- */
02592         if (decide_context_slot(goal, s))
02593             break;
02594 
02595     }                           /* end of while (TRUE) loop down context stack */
02596     current_agent(highest_goal_whose_context_changed) = NIL;
02597 }
02598 
02599 /* **********************************************************************
02600 
02601                       Top-Level Decider Routines
02602 
02603    Init_decider() should be called at startup time to initialize this
02604    module.
02605 
02606    Do_buffered_wm_and_ownership_changes() does the end-of-phase processing
02607    of WM changes, ownership calculations, garbage collection, etc.
02608 
02609    Do_working_memory_phase() and do_decision_phase() are called from
02610    the top level to run those phases.
02611 
02612    Create_top_goal() creates the top goal in the goal stack.
02613    Clear_goal_stack() wipes out the whole goal stack--this is called
02614    during an init-soar.
02615 
02616    Print_lowest_slot_in_context_stack() is used for the watch 0 trace
02617    to print the context slot that was just decided.
02618 ********************************************************************** */
02619 
02620 void init_decider(void)
02621 {
02622     init_memory_pool(&current_agent(slot_pool), sizeof(slot), "slot");
02623     init_memory_pool(&current_agent(wme_pool), sizeof(wme), "wme");
02624     init_memory_pool(&current_agent(preference_pool), sizeof(preference), "preference");
02625 }
02626 
02627 void do_buffered_wm_and_ownership_changes(void)
02628 {
02629     do_buffered_acceptable_preference_wme_changes();
02630     do_buffered_link_changes();
02631     do_buffered_wm_changes();
02632     remove_garbage_slots();
02633 }
02634 
02635 void do_working_memory_phase(void)
02636 {
02637 
02638 #ifndef TRACE_CONTEXT_DECISIONS_ONLY
02639 
02640     if (current_agent(sysparams)[TRACE_PHASES_SYSPARAM]) {
02641 #ifndef SOAR_8_ONLY
02642         if (current_agent(operand2_mode) == TRUE) {
02643 #endif
02644             switch (current_agent(FIRING_TYPE)) {
02645             case PE_PRODS:
02646                 print("\t--- Change Working Memory (PE) ---\n");
02647                 break;
02648             case IE_PRODS:
02649                 print("\t--- Change Working Memory (IE) ---\n");
02650                 break;
02651             }
02652 #ifndef SOAR_8_ONLY
02653         }
02654 
02655         else
02656             print("\n--- Working Memory Phase ---\n");
02657 #endif
02658     }
02659 #endif
02660 
02661     decide_non_context_slots();
02662     do_buffered_wm_and_ownership_changes();
02663 }
02664 
02665 void do_decision_phase(void)
02666 {
02667 
02668 #ifndef TRACE_CONTEXT_DECISIONS_ONLY
02669 
02670     if (current_agent(sysparams)[TRACE_PHASES_SYSPARAM])
02671         print("\n--- Decision Phase ---\n");
02672 
02673 #endif
02674 
02675     decide_context_slots();
02676     do_buffered_wm_and_ownership_changes();
02677     /*
02678      * Bob provided a solution to fix WME's hanging around unsupported
02679      * for an elaboration cycle.
02680      */
02681     decide_non_context_slots();
02682     do_buffered_wm_and_ownership_changes();
02683 }
02684 
02685 void create_top_goal(void)
02686 {
02687     create_new_context(NIL, NONE_IMPASSE_TYPE);
02688     current_agent(highest_goal_whose_context_changed) = NIL;    /* nothing changed yet */
02689     do_buffered_wm_and_ownership_changes();
02690 }
02691 
02692 void clear_goal_stack(void)
02693 {
02694     if (!current_agent(top_goal))
02695         return;
02696     remove_existing_context_and_descendents(current_agent(top_goal));
02697     current_agent(highest_goal_whose_context_changed) = NIL;    /* nothing changed                                                                yet */
02698     do_buffered_wm_and_ownership_changes();
02699     current_agent(top_state) = NIL;
02700     do_input_cycle();           /* tell input functions that the top state is gone */
02701     do_output_cycle();          /* tell output functions that output commands are gone */
02702 }
02703 
02704 void print_lowest_slot_in_context_stack(void)
02705 {
02706 
02707     /* REW: begin 10.24.97 */
02708     /* This doesn't work yet so for now just print the last selection */
02709     if (current_agent(operand2_mode) && current_agent(waitsnc) && current_agent(waitsnc_detect)) {
02710 
02711         current_agent(waitsnc_detect) = FALSE;
02712         print_stack_trace(current_agent(wait_symbol), current_agent(bottom_goal), FOR_ANYTHING_TF, TRUE);
02713     } else {
02714 
02715         /* REW: end   10.24.97 */
02716 
02717         if (current_agent(bottom_goal)->id.operator_slot->wmes)
02718             print_stack_trace(current_agent(bottom_goal)->id.operator_slot->wmes->value,
02719                               current_agent(bottom_goal), FOR_OPERATORS_TF, TRUE);
02720 
02721         /* RCHONG: begin 10.11 */
02722         /*
02723            this coded is needed just so that when an ONC is created in OPERAND
02724            (i.e. if the previous goal's operator slot is not empty), it's stack
02725            trace line doesn't get a number.  this is done because in OPERAND,
02726            ONCs are detected for "free".
02727          */
02728 
02729         else {
02730 
02731             /* REW: begin 09.15.96 */
02732 #ifndef SOAR_8_ONLY
02733             if (current_agent(operand2_mode) == FALSE)
02734                 print_stack_trace(current_agent(bottom_goal), current_agent(bottom_goal), FOR_STATES_TF, TRUE);
02735             /* REW: end   09.15.96 */
02736 
02737             else {
02738 #endif
02739                 if (current_agent(d_cycle_count) == 0)
02740                     print_stack_trace(current_agent(bottom_goal), current_agent(bottom_goal), FOR_STATES_TF, TRUE);
02741                 else {
02742                     if (current_agent(bottom_goal)->id.higher_goal && 
02743                                                 current_agent(bottom_goal)->id.higher_goal->id.operator_slot->wmes) {
02744                         print_stack_trace(current_agent(bottom_goal), current_agent(bottom_goal), FOR_STATES_TF, FALSE);
02745                     } else {
02746                         print_stack_trace(current_agent(bottom_goal), current_agent(bottom_goal), FOR_STATES_TF, TRUE);
02747                     }
02748                 }
02749 #ifndef SOAR_8_ONLY
02750             }
02751 #endif
02752         }
02753     }
02754     /* RCHONG: end 10.11 */
02755 
02756 }
02757 
02758 /* REW: begin 09.15.96 */
02759 
02760 void uniquely_add_to_head_of_dll(instantiation * inst)
02761 {
02762 
02763     parent_inst *new_pi, *curr_pi;
02764 
02765     /* print("UNIQUE DLL:         scanning parent list...\n"); */
02766 
02767     for (curr_pi = current_agent(parent_list_head); curr_pi; curr_pi = curr_pi->next) {
02768         if (curr_pi->inst == inst) {
02769 #ifdef DEBUG_GDS
02770             print_with_symbols("UNIQUE DLL:            %y is already in parent list\n", curr_pi->inst->prod->name);
02771 #endif
02772             return;
02773         }
02774 #ifdef DEBUG_GDS
02775         print_with_symbols("UNIQUE DLL:            %y\n", curr_pi->inst->prod->name);
02776 #endif
02777     }                           /* end for loop */
02778 
02779     new_pi = (parent_inst *) malloc(sizeof(parent_inst));
02780     new_pi->next = NIL;
02781     new_pi->prev = NIL;
02782     new_pi->inst = inst;
02783 
02784     new_pi->next = current_agent(parent_list_head);
02785 
02786     if (current_agent(parent_list_head) != NIL)
02787         current_agent(parent_list_head)->prev = new_pi;
02788 
02789     current_agent(parent_list_head) = new_pi;
02790 #ifdef DEBUG_GDS
02791     print_with_symbols("UNIQUE DLL:         added: %y\n", inst->prod->name);
02792 #endif
02793 }
02794 
02795 void elaborate_gds()
02796 {
02797 
02798     wme *wme_matching_this_cond;
02799     goal_stack_level wme_goal_level;
02800     preference *pref_for_this_wme, *pref;
02801     condition *cond;
02802     parent_inst *curr_pi, *temp_pi;
02803     slot *s;
02804     instantiation *inst;
02805 
02806     for (curr_pi = current_agent(parent_list_head); curr_pi; curr_pi = temp_pi) {
02807 
02808         inst = curr_pi->inst;
02809 
02810 #ifdef DEBUG_GDS
02811         print_with_symbols("\n      EXPLORING INSTANTIATION: %y\n", curr_pi->inst->prod->name);
02812         print("      ");
02813         print_instantiation_with_wmes(curr_pi->inst, TIMETAG_WME_TRACE);
02814 #endif
02815 
02816         for (cond = inst->top_of_instantiated_conditions; cond != NIL; cond = cond->next) {
02817 
02818             if (cond->type != POSITIVE_CONDITION)
02819                 continue;
02820             /* We'll deal with negative instantiations after we get the
02821              * positive ones figured out */
02822 
02823             wme_matching_this_cond = cond->bt.wme;
02824             wme_goal_level = cond->bt.level;
02825             pref_for_this_wme = wme_matching_this_cond->preference;
02826 
02827 #ifdef DEBUG_GDS
02828             print("\n       wme_matching_this_cond at goal_level = %d : ", wme_goal_level);
02829             print_wme(wme_matching_this_cond);
02830 
02831             if (pref_for_this_wme) {
02832                 print("       pref_for_this_wme                        : ");
02833                 print_preference(pref_for_this_wme);
02834             }
02835 #endif
02836 
02837             /* WME is in a supergoal or is arch-supported WME
02838              *  (except for fake instantiations, which do have prefs, so
02839              *  they get handled under "wme is local and i-supported")
02840              */
02841             if ((pref_for_this_wme == NIL) || (wme_goal_level < inst->match_goal_level)) {
02842 
02843 #ifdef DEBUG_GDS
02844                 if (pref_for_this_wme == NIL) {
02845                     print("         this wme has no preferences (it's an arch-created wme)\n");
02846                 } else if (wme_goal_level < inst->match_goal_level) {
02847                     print("         this wme is in the supergoal\n");
02848                 }
02849                 print_with_symbols("inst->match_goal [%y]\n", inst->match_goal);
02850 #endif
02851 
02852                 if (wme_matching_this_cond->gds != NIL) {
02853                     /* Then we want to check and see if the old GDS value
02854                      * should be changed */
02855                     if (wme_matching_this_cond->gds->goal == NIL) {
02856                         /* The goal is NIL: meaning that the goal for the GDS
02857                          * is no longer around */
02858                         fast_remove_from_dll(wme_matching_this_cond->gds->wmes_in_gds,
02859                                              wme_matching_this_cond, wme, gds_next, gds_prev);
02860 
02861                         /* We have to check for GDS removal anytime we take a
02862                          * WME off the GDS wme list, not just when a WME is
02863                          * removed from memory. */
02864                         if (!wme_matching_this_cond->gds->wmes_in_gds) {
02865                             free_memory(wme_matching_this_cond->gds, MISCELLANEOUS_MEM_USAGE);
02866 #ifdef DEBUG_GDS
02867                             print("\n  REMOVING GDS FROM MEMORY.");
02868 #endif
02869                         }
02870                         wme_matching_this_cond->gds = inst->match_goal->id.gds;
02871                         insert_at_head_of_dll(wme_matching_this_cond->gds->wmes_in_gds,
02872                                               wme_matching_this_cond, gds_next, gds_prev);
02873 #ifdef DEBUG_GDS
02874                         print("\n       .....GDS' goal is NIL so switching from old to new GDS list....\n");
02875 #endif
02876 
02877                     } else if (wme_matching_this_cond->gds->goal->id.level > inst->match_goal_level) {
02878                         /* if the WME currently belongs to the GDS of a goal below
02879                          * the current one */
02880                         /* 1. Take WME off old (current) GDS list 
02881                          * 2. Check to see if old GDS WME list is empty.  If so,
02882                          *         remove(free) it.
02883                          * 3. Add WME to new GDS list
02884                          * 4. Update WME pointer to new GDS list
02885                          */
02886                         if (inst->match_goal_level == 1)
02887                             print("\n\n\n HELLO! HELLO! The inst->match_goal_level is 1");
02888 
02889                         fast_remove_from_dll(wme_matching_this_cond->gds->wmes_in_gds,
02890                                              wme_matching_this_cond, wme, gds_next, gds_prev);
02891                         if (!wme_matching_this_cond->gds->wmes_in_gds) {
02892                             free_memory(wme_matching_this_cond->gds, MISCELLANEOUS_MEM_USAGE);
02893 #ifdef DEBUG_GDS
02894                             print("\n  REMOVING GDS FROM MEMORY.");
02895 #endif
02896                         }
02897                         wme_matching_this_cond->gds = inst->match_goal->id.gds;
02898                         insert_at_head_of_dll(wme_matching_this_cond->gds->wmes_in_gds,
02899                                               wme_matching_this_cond, gds_next, gds_prev);
02900 #ifdef DEBUG_GDS
02901                         print("\n       ....switching from old to new GDS list....\n");
02902 #endif
02903                         wme_matching_this_cond->gds = inst->match_goal->id.gds;
02904                     }
02905                 } else {
02906                     /* We know that the WME should be in the GDS of the current
02907                      * goal if the WME's GDS does not already exist.
02908                      * (i.e., if NIL GDS) */
02909                     wme_matching_this_cond->gds = inst->match_goal->id.gds;
02910 
02911                     insert_at_head_of_dll(wme_matching_this_cond->gds->wmes_in_gds,
02912                                           wme_matching_this_cond, gds_next, gds_prev);
02913                     if (wme_matching_this_cond->gds->wmes_in_gds->gds_prev)
02914                         print("\nDEBUG DEBUG : The new header should never have a prev value.\n");
02915 #ifdef DEBUG_GDS
02916                     print_with_symbols("\n       ......WME did not have defined GDS.  Now adding to goal [%y].\n",
02917                                        wme_matching_this_cond->gds->goal);
02918 #endif
02919                 }               /* end else clause for "if wme_matching_this_cond->gds != NIL" */
02920 
02921 #ifdef DEBUG_GDS
02922                 print("            Added WME to GDS for goal = %d", wme_matching_this_cond->gds->goal->id.level);
02923                 print_with_symbols(" [%y]\n", wme_matching_this_cond->gds->goal);
02924 #endif
02925             }
02926             /* end "wme in supergoal or arch-supported" */
02927             else {
02928                 /* wme must be local */
02929 
02930                 /* if wme's pref is o-supported, then just ignore it and
02931                  * move to next condition */
02932                 if (pref_for_this_wme->o_supported == TRUE) {
02933 #ifdef DEBUG_GDS
02934                     print("         this wme is local and o-supported\n");
02935 #endif
02936                     continue;
02937                 }
02938 
02939                 else {
02940                     /* wme's pref is i-supported, so remember it's instantiation
02941                      * for later examination */
02942 
02943                     /* this test avoids "backtracing" through the top state */
02944                     if (inst->match_goal_level == 1) {
02945 #ifdef DEBUG_GDS
02946                         print("         don't back up through top state\n");
02947                         if (inst->prod)
02948                             if (inst->prod->name)
02949                                 print_with_symbols("         don't back up through top state for instantiation %y\n",
02950                                                    inst->prod->name);
02951 #endif
02952                         continue;
02953                     }
02954 
02955                     else {      /* (inst->match_goal_level != 1) */
02956 #ifdef DEBUG_GDS
02957                         print("         this wme is local and i-supported\n");
02958 #endif
02959                         s = find_slot(pref_for_this_wme->id, pref_for_this_wme->attr);
02960                         if (s == NIL) {
02961                             /* this must be an arch-wme from a fake instantiation */
02962 
02963 #ifdef DEBUG_GDS
02964                             print("here's the wme with no slot:\t");
02965                             print_wme(pref_for_this_wme->inst->top_of_instantiated_conditions->bt.wme);
02966 #endif
02967 
02968                             /* this is the same code as above, just using the 
02969                              * differently-named pointer.  it probably should
02970                              * be a subroutine */
02971                             {
02972                                 wme *fake_inst_wme_cond;
02973 
02974                                 fake_inst_wme_cond = pref_for_this_wme->inst->top_of_instantiated_conditions->bt.wme;
02975                                 if (fake_inst_wme_cond->gds != NIL) {
02976                                     /* Then we want to check and see if the old GDS
02977                                      * value should be changed */
02978                                     if (fake_inst_wme_cond->gds->goal == NIL) {
02979                                         /* The goal is NIL: meaning that the goal for
02980                                          * the GDS is no longer around */
02981 
02982                                         fast_remove_from_dll(fake_inst_wme_cond->gds->wmes_in_gds,
02983                                                              fake_inst_wme_cond, wme, gds_next, gds_prev);
02984 
02985                                         /* We have to check for GDS removal anytime we take
02986                                          * a WME off the GDS wme list, not just when a WME
02987                                          *is removed from memory. */
02988                                         if (!fake_inst_wme_cond->gds->wmes_in_gds) {
02989                                             free_memory(fake_inst_wme_cond->gds, MISCELLANEOUS_MEM_USAGE);
02990 #ifdef DEBUG_GDS
02991                                             print("\n  REMOVING GDS FROM MEMORY.");
02992 #endif
02993                                         }
02994 
02995                                         fake_inst_wme_cond->gds = inst->match_goal->id.gds;
02996                                         insert_at_head_of_dll(fake_inst_wme_cond->gds->wmes_in_gds,
02997                                                               fake_inst_wme_cond, gds_next, gds_prev);
02998 #ifdef DEBUG_GDS
02999                                         print
03000                                             ("\n       .....GDS' goal is NIL so switching from old to new GDS list....\n");
03001 #endif
03002                                     } else if (fake_inst_wme_cond->gds->goal->id.level > inst->match_goal_level) {
03003                                         /* if the WME currently belongs to the GDS of a
03004                                          *goal below the current one */
03005                                         /* 1. Take WME off old (current) GDS list 
03006                                          * 2. Check to see if old GDS WME list is empty.
03007                                          *    If so, remove(free) it.
03008                                          * 3. Add WME to new GDS list
03009                                          * 4. Update WME pointer to new GDS list
03010                                          */
03011                                         if (inst->match_goal_level == 1)
03012                                             print("\n\n\n\n\n HELLO! HELLO! The inst->match_goal_level is 1");
03013 
03014                                         fast_remove_from_dll(fake_inst_wme_cond->gds->wmes_in_gds,
03015                                                              fake_inst_wme_cond, wme, gds_next, gds_prev);
03016                                         if (!fake_inst_wme_cond->gds->wmes_in_gds) {
03017                                             free_memory(fake_inst_wme_cond->gds, MISCELLANEOUS_MEM_USAGE);
03018 #ifdef DEBUG_GDS
03019                                             print("\n  REMOVING GDS FROM MEMORY.");
03020 #endif
03021                                         }
03022 
03023                                         fake_inst_wme_cond->gds = inst->match_goal->id.gds;
03024                                         insert_at_head_of_dll(fake_inst_wme_cond->gds->wmes_in_gds,
03025                                                               fake_inst_wme_cond, gds_next, gds_prev);
03026 #ifdef DEBUG_GDS
03027                                         print("\n       .....switching from old to new GDS list....\n");
03028 #endif
03029                                         fake_inst_wme_cond->gds = inst->match_goal->id.gds;
03030                                     }
03031                                 } else {
03032                                     /* We know that the WME should be in the GDS of
03033                                      * the current goal if the WME's GDS does not
03034                                      * already exist. (i.e., if NIL GDS) */
03035                                     fake_inst_wme_cond->gds = inst->match_goal->id.gds;
03036 
03037                                     insert_at_head_of_dll(fake_inst_wme_cond->gds->wmes_in_gds,
03038                                                           fake_inst_wme_cond, gds_next, gds_prev);
03039                                     if (fake_inst_wme_cond->gds->wmes_in_gds->gds_prev)
03040                                         print("\nDEBUG DEBUG : The new header should never have a prev value.\n");
03041 #ifdef DEBUG_GDS
03042                                     print_with_symbols
03043                                         ("\n       ......WME did not have defined GDS.  Now adding to goal [%y].\n",
03044                                          fake_inst_wme_cond->gds->goal);
03045 #endif
03046                                 }
03047 #ifdef DEBUG_GDS
03048                                 print("            Added WME to GDS for goal = %d",
03049                                       fake_inst_wme_cond->gds->goal->id.level);
03050                                 print_with_symbols(" [%y]\n", fake_inst_wme_cond->gds->goal);
03051 #endif
03052                             }   /* matches { wme *fake_inst_wme_cond  */
03053                         } else {
03054 
03055                                                     /* this was the original "local & i-supported" action */
03056 
03057                                                     for (pref=s->preferences[ACCEPTABLE_PREFERENCE_TYPE];
03058                                                              pref;
03059                                                              pref=pref->next) {
03060 
03061 #ifdef DEBUG_GDS
03062                                                              print("           looking at pref for the wme: ");
03063                                                              print_preference(pref);
03064 #endif
03065 
03066                                                         if (pref->inst->GDS_evaluated_already == FALSE) {
03067 #ifdef DEBUG_GDS
03068                                                                 print_with_symbols("\n           adding inst that produced the pref to GDS: %y\n",pref->inst->prod->name);
03069 #endif
03070 
03071 
03072                                                                 /* REW: 2003-12-07 */
03073                                                                 /* If the preference comes from a lower level inst, then ignore it. */
03074                                                                 /* Preferences from lower levels must come from result instantiations;
03075                                                                 we just want to use the justification/chunk instantiations at the 
03076                                                                 match goal level*/
03077                                                         if (pref->inst->match_goal_level <= inst->match_goal_level) {
03078                                                                         uniquely_add_to_head_of_dll(pref->inst); 
03079                                                                 pref->inst->GDS_evaluated_already = TRUE;
03080                                                                 } else {
03081 #ifdef DEBUG_GDS 
03082                                                                         print_with_symbols("\n           ignoring inst %y because it is at a lower level than the GDS\n",pref->inst->prod->name);
03083 #endif
03084 
03085                                                 }
03086                                                 /* REW: 2003-12-07 */
03087 
03088 
03089                                                         } else {
03090 #ifdef DEBUG_GDS
03091                                                                 print("           the inst producing this pref was already explored; skipping it\n");
03092 #endif
03093     }
03094 
03095                             }   /* for pref = s->pref[ACCEPTABLE_PREF ... */
03096                         }
03097                     }
03098                 }
03099             }
03100 
03101         }                       /* for (cond = inst->top_of_instantiated_cond ...  */
03102 
03103         /* remove just used instantiation from list */
03104 
03105 #ifdef DEBUG_GDS
03106         print_with_symbols("\n      removing instantiation: %y\n", curr_pi->inst->prod->name);
03107 #endif
03108 
03109         if (curr_pi->next != NIL)
03110             curr_pi->next->prev = curr_pi->prev;
03111         if (curr_pi->prev != NIL)
03112             curr_pi->prev->next = curr_pi->next;
03113 
03114         if (current_agent(parent_list_head) == curr_pi)
03115             current_agent(parent_list_head) = curr_pi->next;
03116 
03117         temp_pi = curr_pi->next;
03118         free(curr_pi);
03119 
03120     }                           /* end of "for (curr_pi = current_agent(parent_list_head) ... */
03121 
03122     if (current_agent(parent_list_head) != NIL) {
03123 #ifdef DEBUG_GDS
03124         print("\n    RECURSING using these parents:\n");
03125         for (curr_pi = current_agent(parent_list_head); curr_pi; curr_pi = curr_pi->next) {
03126             print_with_symbols("      %y\n", curr_pi->inst->prod->name);
03127         }
03128 #endif
03129 
03130         /* recursively explore the parents of all the instantiations */
03131 
03132         elaborate_gds();
03133 
03134         /* free the parent instantiation list.  technically, the list
03135          * should be empty at this point ??? */
03136         free_parent_list();
03137     }
03138 
03139 }                               /* end of elaborate_gds   */
03140 
03141 /* REW BUG: this needs to be smarter to deal with wmes that get support from
03142 multiple instantiations.  for example ^enemy-out-there could be made by 50
03143 instantiations.  if one of those instantiations goes, should the goal be
03144 killed????  This routine says "yes" -- anytime a dependent item gets changed,
03145 we're gonna yank out the goal -- even when that i-supported element itself
03146 may not be removed (due to multiple preferences).  So, we'll say that this is
03147 a "twitchy" version of OPERAND2, and leave open the possibility that other
03148 approaches may be better */
03149 
03150 void gds_invalid_so_remove_goal(wme * w)
03151 {
03152 #ifndef NO_TIMING_STUFF
03153 #ifdef DETAILED_TIMING_STATS
03154     /* REW: begin 11.25.96 */
03155     start_timer(&current_agent(start_gds_tv));
03156     /* REW: end   11.25.96 */
03157 #endif
03158 #endif
03159 
03160     if (current_agent(soar_verbose_flag))
03161         soar_ecGDSPrint();
03162 
03163     /* REW: BUG.  I have no idea right now if this is a terrible hack or
03164      * actually what we want to do.  The idea here is that the context of
03165      * the immediately higher goal above a retraction should be marked as
03166      * having its context changed in order that the architecture doesn't
03167      * look below this level for context changes.  I think it's a hack b/c
03168      * it seems like there should aready be mechanisms for doing this in
03169      * the architecture but I couldn't find any.
03170      */
03171     /* Note: the inner 'if' is correct -- we only want to change
03172      * highest_goal_whose_context_changed if the pointer is currently at
03173      * or below (greater than) the goal which we are going to retract.
03174      * However, I'm not so sure about the outer 'else.'  If we don't set
03175      * this to the goal above the retraction, even if the current value
03176      * is NIL, we still seg fault in certain cases.  But setting it as we do 
03177      * in the inner 'if' seems to clear up the difficulty.
03178      */
03179 
03180     if (current_agent(highest_goal_whose_context_changed)) {
03181         if (current_agent(highest_goal_whose_context_changed)->id.level >= w->gds->goal->id.level) {
03182             current_agent(highest_goal_whose_context_changed) = w->gds->goal->id.higher_goal;
03183         }
03184     } else {
03185         /* If nothing has yet changed (highest_ ... = NIL) then set
03186          * the goal automatically */
03187         current_agent(highest_goal_whose_context_changed) = w->gds->goal->id.higher_goal;
03188     }
03189 
03190 #ifndef TRACE_CONTEXT_DECISIONS_ONLY
03191 
03192     if (current_agent(sysparams)[TRACE_OPERAND2_REMOVALS_SYSPARAM]) {
03193         print_with_symbols("\n    REMOVING GOAL [%y] due to change in GDS WME ", w->gds->goal);
03194         print_wme(w);
03195     }
03196 #endif
03197 
03198     remove_existing_context_and_descendents(w->gds->goal);
03199     /* BUG: Need to reset highest_goal here ??? */
03200 
03201     /* usually, we'd call do_buffered_wm_and_ownership_changes() here, but
03202      * we don't need to because it will be done at the end of the working
03203      * memory phase; cf. the end of do_working_memory_phase().
03204      */
03205 
03206 #ifndef NO_TIMING_STUFF
03207 #ifdef DETAILED_TIMING_STATS
03208     /* REW: begin 11.25.96 */
03209     stop_timer(&current_agent(start_gds_tv), &current_agent(gds_cpu_time[current_agent(current_phase)]));
03210     /* REW: end   11.25.96 */
03211 #endif
03212 #endif
03213 }
03214 
03215 void free_parent_list()
03216 {
03217     parent_inst *curr_pi;
03218 
03219     for (curr_pi = current_agent(parent_list_head); curr_pi; curr_pi = curr_pi->next)
03220         free(curr_pi);
03221 
03222     current_agent(parent_list_head) = NIL;
03223 }
03224 
03225 void create_gds_for_goal(Symbol * goal)
03226 {
03227     goal_dependency_set *gds;
03228 
03229     gds = allocate_memory(sizeof(goal_dependency_set), MISCELLANEOUS_MEM_USAGE);
03230     gds->goal = goal;
03231     gds->wmes_in_gds = NIL;
03232     goal->id.gds = gds;
03233 #ifdef DEBUG_GDS
03234     print_with_symbols("\nCreated GDS for goal [%y].\n", gds->goal);
03235 #endif
03236 }
03237 
03238 #ifdef NUMERIC_INDIFFERENCE
03239 
03240 /* REW: 2003-01-06 */
03241 /* This a helper function that sets the decider flag to candidate for
03242    all the items on the candidate list and initializes the counters 
03243    that will track the total probability distributions to zero.
03244 
03245    It's okay to muck with the 
03246    decider flags here because this will be called after the decision
03247    has been determined to be a choice among indifferent candidates.
03248 
03249    Note: the slot is only needed for debugging/data verification
03250 
03251    Note: slot parameter removed by voigtjr to quell compiler warnings
03252 */
03253 
03254 /* SAN: 2003-10-30 */
03255 /* Revised - this function also initializes candidate's value to default value for
03256    appropriate numeric-indifferent-mode 
03257 */
03258 
03259 /*void initialize_indifferent_candidates_for_probability_selection(slot *s, preference *candidates)*/
03260 void initialize_indifferent_candidates_for_probability_selection(preference * candidates)
03261 {
03262     preference *cand = 0;
03263 
03264     for (cand = candidates; cand != NIL; cand = cand->next_candidate) {
03265         /* print_with_symbols("\nInitializing candidate %y",cand->value); 
03266          */
03267         cand->value->common.decider_flag = CANDIDATE_DECIDER_FLAG;
03268         cand->total_preferences_for_candidate = 0;
03269                 cand->sum_of_probability = 0;
03270          
03271     }
03272 }
03273 
03274 /*unsigned int count_candidates(slot *s, preference *candidates)*/
03275 unsigned int count_candidates(preference * candidates)
03276 {
03277     unsigned int numCandidates = 0;
03278     preference *cand = 0;
03279 
03280     /*
03281        Count up the number of candidates
03282        REW: 2003-01-06
03283        I'm assuming that all of the candidates have unary or 
03284        unary+value (binary) indifferent preferences at this point.
03285        So we loop over the candidates list and count the number of
03286        elements in the list.
03287      */
03288 
03289     for (cand = candidates; cand != NIL; cand = cand->next_candidate)
03290         numCandidates++;
03291 
03292     return numCandidates;
03293 }
03294 
03295 /* Below is the Temperature, used to keep summed indifferent
03296    preferences within a reasonable range, since they will be used as
03297          an exponent to the number 10, and must be stored in a 64 bit double
03298 */
03299 #define TEMPERATURE 25.0
03300 
03301 preference *probabilistically_select(slot * s, preference * candidates)
03302 {
03303     preference *cand = 0;
03304     preference *pref = 0;
03305     double total_probability = 0;
03306     unsigned int numCandidates = 0;
03307     double selectedProbability = 0;
03308     double currentSumOfValues = 0;
03309     static int initialized_rand = 0;
03310     unsigned long rn = 0;
03311         double default_ni;
03312 
03313     /* initialized, but not referenced, so i commented them out:
03314        preference*    selectedCandidate=0;
03315        unsigned int   currentCandidate=0; */
03316 
03317     assert(s != 0);
03318     assert(candidates != 0);
03319 
03320     if (!initialized_rand) {
03321         srand((unsigned) time(NULL));
03322         initialized_rand = 1;
03323     }
03324     /*
03325        print("\nCandidates at top of probabilistically_select"); 
03326        print_candidates(candidates);  
03327      */
03328 
03329     /* s param uneccesary, commented out to quell compiler warning.  see comment
03330        block above the following function definitions
03331        initialize_indifferent_candidates_for_probability_selection(s, candidates);
03332        numCandidates = count_candidates(s,candidates); */
03333 
03334     initialize_indifferent_candidates_for_probability_selection(candidates);
03335     numCandidates = count_candidates(candidates);
03336 
03337     /*
03338        print("\n numCandidates = %d", numCandidates);
03339        print("\nCandidates before unary indifferent loop");
03340        print_candidates(candidates); 
03341      */
03342 
03343 
03344         switch (current_agent(numeric_indifferent_mode)) {
03345         case NUMERIC_INDIFFERENT_MODE_AVG:
03346                 default_ni = 50;
03347                 break;
03348 
03349         case NUMERIC_INDIFFERENT_MODE_SUM:
03350         default:
03351                 default_ni = 0;
03352                 break;
03353         }
03354     /*
03355        BUGBUGBUG 
03356        Next some error checking here to ensure that the binary preference
03357        is indeed really an indifferent+value preference....
03358        someday.
03359 
03360        also, precision loss (long to float conversion) here:
03361        value = (float)pref->referent->ic.value;
03362      */
03363 
03364     for (pref = s->preferences[BINARY_INDIFFERENT_PREFERENCE_TYPE]; pref != NIL; pref = pref->next) {
03365         /*print_with_symbols("\nPreference for %y", pref->value); */
03366         float value;
03367         if (pref->referent->common.symbol_type == FLOAT_CONSTANT_SYMBOL_TYPE) {
03368             value = pref->referent->fc.value;
03369         } else if (pref->referent->common.symbol_type == INT_CONSTANT_SYMBOL_TYPE) {
03370             value = (float) pref->referent->ic.value;
03371         } else
03372             continue;
03373         for (cand = candidates; cand != NIL; cand = cand->next_candidate) {
03374             /*print_with_symbols("\nConsidering candidate %y", cand->value); */
03375 
03376             if (cand->value == pref->value) {
03377                 cand->total_preferences_for_candidate += 1;
03378                 cand->sum_of_probability += value;
03379             }
03380         }
03381     }
03382 
03383         for (cand = candidates; cand != NIL; cand = cand->next_candidate) {
03384                 if (cand->total_preferences_for_candidate == 0) {
03385                         cand->sum_of_probability = default_ni;
03386                         cand->total_preferences_for_candidate = 1;
03387                 }
03388         }
03389 
03390     if (current_agent(numeric_indifferent_mode) == NUMERIC_INDIFFERENT_MODE_SUM) {
03391 
03392         total_probability = 0.0;
03393         for (cand = candidates; cand != NIL; cand = cand->next_candidate) {
03394 
03395             if (current_agent(sysparams)[TRACE_INDIFFERENT_SYSPARAM]){
03396                                 print_with_symbols("\n Candidate %y:  ", cand->value);
03397                            print("Value (Sum) = %f", exp(cand->sum_of_probability / TEMPERATURE));
03398                         }     
03399             /*  Total Probability represents the range of values, we expect
03400              *  the use of negative valued preferences, so its possible the
03401              *  sum is negative, here that means a fractional probability
03402              */
03403             total_probability += exp(cand->sum_of_probability / TEMPERATURE);
03404             /* print("\n   Total (Sum) Probability = %f", total_probability ); */
03405         }
03406 
03407         /* Now select the candidate */
03408 
03409         print("\n");
03410                 rn = rand();
03411         selectedProbability = ((double) rn / (double) RAND_MAX) * total_probability;
03412         currentSumOfValues = 0;
03413 
03414         for (cand = candidates; cand != NIL; cand = cand->next_candidate) {
03415 
03416             currentSumOfValues += exp(cand->sum_of_probability / TEMPERATURE);
03417 
03418             if (selectedProbability <= currentSumOfValues) {
03419                 /* 
03420                    print_with_symbols("\n    Returning (Sum) candidate %y", cand->value); 
03421                  */
03422 
03423                 return cand;
03424             }
03425         }
03426 
03427     } else if (current_agent(numeric_indifferent_mode) == NUMERIC_INDIFFERENT_MODE_AVG) {
03428 
03429         total_probability = 0.0;
03430         for (cand = candidates; cand != NIL; cand = cand->next_candidate) {
03431 
03432             if (current_agent(sysparams)[TRACE_INDIFFERENT_SYSPARAM]) {
03433                                 print_with_symbols("\n Candidate %y:  ", cand->value);  
03434                            print("Value (Avg) = %f", fabs(cand->sum_of_probability / cand->total_preferences_for_candidate));
03435                         }    
03436             /* Total probability represents the range of values that
03437              * we'll map into for selection.  Here we don't expect the use
03438              * of negative values, so we'll warn when we see one.
03439              */
03440 
03441             total_probability += fabs(cand->sum_of_probability / cand->total_preferences_for_candidate);
03442 
03443             if (cand->sum_of_probability < 0.0) {
03444                 print_with_symbols
03445                     ("WARNING: Candidate %y has a negative value, which is unexpected with 'numeric-indifferent-mode -avg'",
03446                      cand->value);
03447             }
03448             /* print("\n   Total (Avg) Probability = %f", total_probability ); */
03449         }
03450 
03451         /* Now select the candidate */
03452 
03453                 print("\n");
03454         rn = rand();
03455         selectedProbability = ((double) rn / (double) RAND_MAX) * total_probability;
03456         currentSumOfValues = 0;
03457 
03458         for (cand = candidates; cand != NIL; cand = cand->next_candidate) {
03459 
03460             currentSumOfValues += fabs(cand->sum_of_probability / cand->total_preferences_for_candidate);
03461 
03462             if (selectedProbability <= currentSumOfValues) {
03463                 /*
03464                    print_with_symbols("\n    Returning (Avg) candidate %y", cand->value); 
03465                  */
03466 
03467                 return cand;
03468             }
03469         }
03470 
03471     } else {
03472         print("\nERROR: Invalid Numeric Indifferent Mode!\n");
03473     }
03474 
03475     print("\nERROR: Probability Selection failed. This should never happen.\n");
03476     return NIL;
03477 
03478 }
03479 
03480 #endif

Generated on Thu Dec 11 13:00:16 2003 for Soar Kernel by doxygen 1.3.5