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

osupport.c

Go to the documentation of this file.
00001 /*************************************************************************
00002  *
00003  *  file:  osupport.c
00004  *
00005  * =======================================================================
00006  * Calculate_support_for_instantiation_preferences() does run-time o-support
00007  * calculations -- it fills in pref->o_supported in each pref. on the
00008  * instantiation.  Calculate_compile_time_o_support() does the compile-time
00009  * version:  it takes the LHS and RHS, and fills in the a->support field in 
00010  * each RHS action with either UNKNOWN_SUPPORT, O_SUPPORT, or I_SUPPORT.
00011  * =======================================================================
00012  *
00013  * Copyright 1995-2003 Carnegie Mellon University,
00014  *                                                                               University of Michigan,
00015  *                                                                               University of Southern California/Information
00016  *                                                                               Sciences Institute. All rights reserved.
00017  *                                                                              
00018  * Redistribution and use in source and binary forms, with or without
00019  * modification, are permitted provided that the following conditions are met:
00020  *
00021  * 1.   Redistributions of source code must retain the above copyright notice,
00022  *              this list of conditions and the following disclaimer. 
00023  * 2.   Redistributions in binary form must reproduce the above copyright notice,
00024  *              this list of conditions and the following disclaimer in the documentation
00025  *              and/or other materials provided with the distribution. 
00026  *
00027  * THIS SOFTWARE IS PROVIDED BY THE SOAR CONSORTIUM ``AS IS'' AND ANY EXPRESS OR
00028  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00029  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
00030  * EVENT SHALL THE SOAR CONSORTIUM  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
00031  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00032  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00033  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00034  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00035  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00036  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00037  * The views and conclusions contained in the software and documentation are
00038  * those of the authors and should not be interpreted as representing official
00039  * policies, either expressed or implied, of Carnegie Mellon University, the
00040  * University of Michigan, the University of Southern California/Information
00041  * Sciences Institute, or the Soar consortium.
00042  * =======================================================================
00043  */
00044 
00045 /* =========================================================================
00046              O Support calculation routines.
00047    ========================================================================= */
00048 
00049 #include "soarkernel.h"
00050 #include <ctype.h>
00051 
00052 extern list *collect_root_variables(condition *, tc_number, bool);
00053 
00054 /* -----------------------------------------------------------------------
00055                   O-Support Transitive Closure Routines
00056 
00057    These routines are used by the o-support calculations to mark transitive
00058    closures through TM (= WM+PM) plus (optionally) the RHS-generated pref's.
00059 
00060    The caller should first call begin_os_tc (rhs_prefs_or_nil).  Then
00061    add_to_os_tc (id) should be called any number of times to add stuff
00062    to the TC.  (Note that the rhs_prefs shouldn't be modified between the
00063    begin_os_tc() call and the last add_to_os_tc() call.)
00064 
00065    Each identifier in the TC is marked with id.tc_num=o_support_tc; the
00066    caller can check for TC membership by looking at id.tc_num on any id.
00067 ----------------------------------------------------------------------- */
00068 
00069 #define add_to_os_tc_if_needed(sym) \
00070   { if ((sym)->common.symbol_type==IDENTIFIER_SYMBOL_TYPE) \
00071       add_to_os_tc (sym,FALSE); }
00072 
00073 #define add_to_os_tc_if_id(sym,flag) \
00074   { if ((sym)->common.symbol_type==IDENTIFIER_SYMBOL_TYPE) \
00075       add_to_os_tc (sym,flag); }
00076 
00077 /* SBH 4/14/93
00078  * For NNPSCM, we must exclude the operator slot from the transitive closure of a state.
00079  * Do that by passing a boolean argument, "isa_state" to this routine.
00080  * If it isa_state, check for the operator slot before the recursive call.
00081  */
00082 
00083 void add_to_os_tc(Symbol * id, bool isa_state)
00084 {
00085     slot *s;
00086     preference *pref;
00087     wme *w;
00088 
00089     /* --- if id is already in the TC, exit; else mark it as in the TC --- */
00090     if (id->id.tc_num == current_agent(o_support_tc))
00091         return;
00092     id->id.tc_num = current_agent(o_support_tc);
00093 
00094     /* --- scan through all preferences and wmes for all slots for this id --- */
00095     for (w = id->id.input_wmes; w != NIL; w = w->next)
00096         add_to_os_tc_if_needed(w->value);
00097     for (s = id->id.slots; s != NIL; s = s->next) {
00098         if ((!isa_state) || (s->attr != current_agent(operator_symbol))) {
00099             for (pref = s->all_preferences; pref != NIL; pref = pref->all_of_slot_next) {
00100                 add_to_os_tc_if_needed(pref->value);
00101                 if (preference_is_binary(pref->type))
00102                     add_to_os_tc_if_needed(pref->referent);
00103             }
00104             for (w = s->wmes; w != NIL; w = w->next)
00105                 add_to_os_tc_if_needed(w->value);
00106         }
00107     }                           /* end of for slots loop */
00108     /* --- now scan through RHS prefs and look for any with this id --- */
00109     for (pref = current_agent(rhs_prefs_from_instantiation); pref != NIL; pref = pref->inst_next) {
00110         if (pref->id == id) {
00111             if ((!isa_state) || (pref->attr != current_agent(operator_symbol))) {
00112                 add_to_os_tc_if_needed(pref->value);
00113                 if (preference_is_binary(pref->type))
00114                     add_to_os_tc_if_needed(pref->referent);
00115             }
00116         }
00117     }
00118     /* We don't need to worry about goal/impasse wmes here, since o-support tc's
00119        never start there and there's never a pointer to a goal or impasse from
00120        something else. */
00121 }
00122 
00123 void begin_os_tc(preference * rhs_prefs_or_nil)
00124 {
00125     current_agent(o_support_tc) = get_new_tc_number();
00126     current_agent(rhs_prefs_from_instantiation) = rhs_prefs_or_nil;
00127 }
00128 
00129 /* -----------------------------------------------------------------------
00130            Utilities for Testing Inclusion in the O-Support TC
00131 
00132    After a TC has been marked with the above routine, these utility
00133    routines are used for checking whether certain things are in the TC.
00134    Test_has_id_in_os_tc() checks whether a given test contains an equality
00135    test for any identifier in the TC, other than the identifier
00136    "excluded_sym".  Id_or_value_of_condition_list_is_in_os_tc() checks whether
00137    any id or value test in the given condition list (including id/value tests
00138    inside NCC's) has a test for an id in the TC.  In the case of value tests,
00139    the id is not allowed to be "sym_excluded_from_value".
00140 ----------------------------------------------------------------------- */
00141 
00142 bool test_has_id_in_os_tc(test t, Symbol * excluded_sym)
00143 {
00144     cons *c;
00145     Symbol *referent;
00146     complex_test *ct;
00147 
00148     if (test_is_blank_test(t))
00149         return FALSE;
00150     if (test_is_blank_or_equality_test(t)) {
00151         referent = referent_of_equality_test(t);
00152         if (referent->common.symbol_type == IDENTIFIER_SYMBOL_TYPE)
00153             if (referent->id.tc_num == current_agent(o_support_tc))
00154                 if (referent != excluded_sym)
00155                     return TRUE;
00156         return FALSE;
00157     }
00158     ct = complex_test_from_test(t);
00159     if (ct->type == CONJUNCTIVE_TEST) {
00160         for (c = ct->data.conjunct_list; c != NIL; c = c->rest)
00161             if (test_has_id_in_os_tc(c->first, excluded_sym))
00162                 return TRUE;
00163         return FALSE;
00164     }
00165     return FALSE;
00166 }
00167 
00168 bool id_or_value_of_condition_list_is_in_os_tc(condition * conds,
00169                                                Symbol * sym_excluded_from_value,
00170                                                Symbol * match_state_to_exclude_test_of_the_operator_off_of)
00171 {
00172     /* RBD 8/19/94 Under NNPSCM, when we use this routine to look for "something
00173        off the state", we want to exclude tests of (match_state ^operator _). */
00174     for (; conds != NIL; conds = conds->next) {
00175         switch (conds->type) {
00176         case POSITIVE_CONDITION:
00177         case NEGATIVE_CONDITION:
00178             if (test_includes_equality_test_for_symbol(conds->data.tests.id_test,
00179                                                        match_state_to_exclude_test_of_the_operator_off_of) &&
00180                 test_includes_equality_test_for_symbol(conds->data.tests.attr_test, current_agent(operator_symbol)))
00181                 break;
00182             if (test_has_id_in_os_tc(conds->data.tests.id_test, NIL))
00183                 return TRUE;
00184             if (test_has_id_in_os_tc(conds->data.tests.value_test, sym_excluded_from_value))
00185                 return TRUE;
00186             break;
00187         case CONJUNCTIVE_NEGATION_CONDITION:
00188             if (id_or_value_of_condition_list_is_in_os_tc(conds->data.ncc.top,
00189                                                           sym_excluded_from_value,
00190                                                           match_state_to_exclude_test_of_the_operator_off_of))
00191                 return TRUE;
00192             break;
00193         }
00194     }
00195     return FALSE;
00196 }
00197 
00198 /* -----------------------------------------------------------------------
00199 
00200    is_state_id
00201 
00202    GAP 10-6-94
00203 
00204    This routine checks to see if the identifier is one of the context
00205    objects i.e. it is the state somewhere in the context stack.
00206    This is used to ensure that O-support is not given to context objects 
00207    in super-states.
00208 
00209 ----------------------------------------------------------------------- */
00210 bool is_state_id(Symbol * sym, Symbol * match_state)
00211 {
00212     Symbol *c;
00213 
00214     for (c = current_agent(top_goal); c != match_state; c = c->id.lower_goal) {
00215         if (sym == c)
00216             return TRUE;
00217     }
00218 
00219     if (sym == match_state)
00220         return TRUE;
00221     else
00222         return FALSE;
00223 }
00224 
00225 /* -----------------------------------------------------------------------
00226                     Run-Time O-Support Calculation
00227 
00228    This routine calculates o-support for each preference for the given
00229    instantiation, filling in pref->o_supported (TRUE or FALSE) on each one.
00230 
00231    The following predicates are used for support calculations.  In the
00232    following, "lhs has some elt. ..." means the lhs has some id or value
00233    at any nesting level.
00234 
00235      lhs_oa_support:
00236        (1) does lhs test (match_goal ^operator match_operator NO) ?
00237        (2) mark TC (match_operator) using TM;
00238            does lhs has some elt. in TC but != match_operator ?
00239        (3) mark TC (match_state) using TM;
00240            does lhs has some elt. in TC ?
00241      lhs_oc_support:
00242        (1) mark TC (match_state) using TM;
00243            does lhs has some elt. in TC but != match_state ?
00244      lhs_om_support:
00245        (1) does lhs tests (match_goal ^operator) ?
00246        (2) mark TC (match_state) using TM;
00247            does lhs has some elt. in TC but != match_state ?
00248 
00249      rhs_oa_support:
00250        mark TC (match_state) using TM+RHS;
00251        if pref.id is in TC, give support
00252      rhs_oc_support:
00253        mark TC (inst.rhsoperators) using TM+RHS;
00254        if pref.id is in TC, give support
00255      rhs_om_support:
00256        mark TC (inst.lhsoperators) using TM+RHS;
00257        if pref.id is in TC, give support
00258 
00259    BUGBUG the code does a check of whether the lhs tests the match state via
00260           looking just at id and value fields of top-level positive cond's.
00261           It doesn't look at the attr field, or at any negative or NCC's.
00262           I'm not sure whether this is right or not.  (It's a pretty
00263           obscure case, though.)
00264 ----------------------------------------------------------------------- */
00265 
00266 /* RBD 8/91/94 changed calls to add_to_os_tc() in this routine to use
00267    add_to_os_tc_if_id() instead -- in case people use constant-symbols 
00268    (instead of objects) for states or operators */
00269 
00270 void calculate_support_for_instantiation_preferences(instantiation * inst)
00271 {
00272     Symbol *match_goal, *match_state, *match_operator;
00273     wme *match_operator_wme;
00274     bool lhs_tests_operator_installed;
00275     bool lhs_tests_operator_acceptable_or_installed;
00276     bool lhs_is_known_to_test_something_off_match_state;
00277     bool lhs_is_known_to_test_something_off_match_operator;
00278     bool rhs_does_an_operator_creation;
00279     bool oc_support_possible;
00280     bool om_support_possible;
00281     bool oa_support_possible;
00282     preference *rhs, *pref;
00283     wme *w;
00284     condition *lhs, *c;
00285 
00286 /* RCHONG: begin 10.11 */
00287 
00288     action *act;
00289     bool o_support, op_elab;
00290     bool operator_proposal;
00291     char action_attr[ACTION_ATTR_SIZE];
00292     int pass;
00293     wme *lowest_goal_wme;
00294 
00295 /* RCHONG: end 10.11 */
00296 
00297 /* REW: begin 09.15.96 */
00298 
00299 #ifndef SOAR_8_ONLY
00300     if (current_agent(operand2_mode) == TRUE) {
00301 #endif
00302 
00303         if (current_agent(soar_verbose_flag) == TRUE)
00304             print("\n      in calculate_support_for_instantiation_preferences:");
00305         o_support = FALSE;
00306         op_elab = FALSE;
00307 
00308 #if defined(OPTIMIZE_TOP_LEVEL_RESULTS) || defined(THIN_JUSTIFICATIONS)
00309         if (!inst->prod) {
00310             o_support = TRUE;
00311         } else if
00312 #else
00313         if
00314 #endif
00315             (inst->prod->declared_support == DECLARED_O_SUPPORT)
00316             o_support = TRUE;
00317         else if (inst->prod->declared_support == DECLARED_I_SUPPORT)
00318             o_support = FALSE;
00319         else if (inst->prod->declared_support == UNDECLARED_SUPPORT) {
00320 
00321             /*
00322                check if the instantiation is proposing an operator.  if it
00323                is, then this instantiation is i-supported.
00324              */
00325 
00326             operator_proposal = FALSE;
00327             for (act = inst->prod->action_list; act != NIL; act = act->next) {
00328                 if ((act->type == MAKE_ACTION) && (rhs_value_is_symbol(act->attr))) {
00329                     if ((strcmp(rhs_value_to_string(act->attr, action_attr, ACTION_ATTR_SIZE),
00330                                 "operator") == NIL) && (act->preference_type == ACCEPTABLE_PREFERENCE_TYPE)) {
00331                         /* REW: 09.30.96.  Bug fix (next line was
00332                            operator_proposal == TRUE;) */
00333                         operator_proposal = TRUE;
00334                         o_support = FALSE;
00335                         break;
00336                     }
00337                 }
00338             }
00339 
00340             if (operator_proposal == FALSE) {
00341 
00342                 /*
00343                    an operator wasn't being proposed, so now we need to test if
00344                    the operator is being tested on the LHS.
00345 
00346                    i'll need to make two passes over the wmes that pertain to
00347                    this instantiation.  the first pass looks for the lowest goal
00348                    identifier.  the second pass looks for a wme of the form:
00349 
00350                    (<lowest-goal-id> ^operator ...)
00351 
00352                    if such a wme is found, then this o-support = TRUE; FALSE otherwise.
00353 
00354                    this code is essentially identical to that in
00355                    p_node_left_addition() in rete.c.
00356 
00357                    BUGBUG this check only looks at positive conditions.  we
00358                    haven't really decided what testing the absence of the
00359                    operator will do.  this code assumes that such a productions
00360                    (instantiation) would get i-support.
00361                  */
00362 
00363                 lowest_goal_wme = NIL;
00364 
00365                 for (pass = 0; pass != 2; pass++) {
00366 
00367                     for (c = inst->top_of_instantiated_conditions; c != NIL; c = c->next) {
00368                         if (c->type == POSITIVE_CONDITION) {
00369                             w = c->bt.wme;
00370 
00371                             if (pass == 0) {
00372 
00373                                 if (w->id->id.isa_goal == TRUE) {
00374 
00375                                     if (lowest_goal_wme == NIL)
00376                                         lowest_goal_wme = w;
00377 
00378                                     else {
00379                                         if (w->id->id.level > lowest_goal_wme->id->id.level)
00380                                             lowest_goal_wme = w;
00381                                     }
00382                                 }
00383 
00384                             }
00385 
00386                             else {
00387                                 if ((w->attr == current_agent(operator_symbol)) &&
00388                                     (w->acceptable == FALSE) && (w->id == lowest_goal_wme->id)) {
00389 
00390                                     if (current_agent(o_support_calculation_type) == 3 ||
00391                                         current_agent(o_support_calculation_type) == 4) {
00392 
00393                                         /* iff RHS has only operator elaborations 
00394                                            then it's IE_PROD, otherwise PE_PROD, so
00395                                            look for non-op-elabs in the actions  KJC 1/00 */
00396 
00397                                         for (act = inst->prod->action_list; act != NIL; act = act->next) {
00398                                             if (act->type == MAKE_ACTION) {
00399                                                 if ((rhs_value_is_symbol(act->id)) &&
00400                                                     (rhs_value_to_symbol(act->id) == w->value)) {
00401                                                     op_elab = TRUE;
00402                                                 } else if (current_agent(o_support_calculation_type) == 4 &&
00403                                                            (rhs_value_is_reteloc(act->id)) &&
00404                                                            w->value ==
00405                                                            get_symbol_from_rete_loc((byte)
00406                                                                                     rhs_value_to_reteloc_levels_up(act->
00407                                                                                                                    id),
00408                                                                                     (byte)
00409                                                                                     rhs_value_to_reteloc_field_num(act->
00410                                                                                                                    id),
00411                                                                                     inst->rete_token, w)) {
00412                                                     op_elab = TRUE;
00413 
00414                                                 } else {
00415                                                     /* this is not an operator elaboration */
00416                                                     o_support = TRUE;
00417                                                 }
00418                                             }
00419                                         }
00420                                     } else {
00421                                         o_support = TRUE;
00422                                         break;
00423                                     }
00424                                 }
00425                             }
00426                         }
00427                     }
00428                 }
00429             }
00430         }
00431 
00432         /* KJC 01/00: Warn if operator elabs mixed w/ applications */
00433         if ((current_agent(o_support_calculation_type) == 3 ||
00434              current_agent(o_support_calculation_type) == 4) && (o_support == TRUE)) {
00435 
00436             if (op_elab == TRUE) {
00437 
00438                 /* warn user about mixed actions */
00439                 if (current_agent(o_support_calculation_type) == 3 && current_agent(sysparams)[PRINT_WARNINGS_SYSPARAM]) {
00440 
00441                     print_with_symbols
00442                         ("\nWARNING:  operator elaborations mixed with operator applications\nget o_support in prod %y",
00443                          inst->prod->name);
00444                     o_support = TRUE;
00445                 } else if (current_agent(o_support_calculation_type) == 4 &&
00446                            current_agent(sysparams)[PRINT_WARNINGS_SYSPARAM]) {
00447 
00448                     print_with_symbols
00449                         ("\nWARNING:  operator elaborations mixed with operator applications\nget i_support in prod %y",
00450                          inst->prod->name);
00451                     o_support = FALSE;
00452                 }
00453             }
00454 
00455         }
00456         /*
00457            assign every preference the correct support
00458          */
00459 
00460         for (pref = inst->preferences_generated; pref != NIL; pref = pref->inst_next)
00461             pref->o_supported = o_support;
00462 
00463         goto o_support_done;
00464 #ifndef SOAR_8_ONLY
00465     }
00466 #endif
00467 
00468 /* REW: end   09.15.96 */
00469 
00470     /* --- initialize by giving everything NO o_support --- */
00471     for (pref = inst->preferences_generated; pref != NIL; pref = pref->inst_next)
00472         pref->o_supported = FALSE;
00473 
00474     /* --- find the match goal, match state, and match operator --- */
00475     match_goal = inst->match_goal;
00476     if (!match_goal)
00477         goto o_support_done;    /* nothing gets o-support */
00478 
00479     match_state = match_goal;
00480 
00481     match_operator_wme = match_goal->id.operator_slot->wmes;
00482     if (match_operator_wme)
00483         match_operator = match_operator_wme->value;
00484     else
00485         match_operator = NIL;
00486 
00487     lhs = inst->top_of_instantiated_conditions;
00488     rhs = inst->preferences_generated;
00489 
00490     /* --- scan through rhs to look for various things --- */
00491     rhs_does_an_operator_creation = FALSE;
00492 
00493     for (pref = rhs; pref != NIL; pref = pref->inst_next) {
00494         if ((pref->id == match_goal) &&
00495             (pref->attr == current_agent(operator_symbol)) &&
00496             ((pref->type == ACCEPTABLE_PREFERENCE_TYPE) || (pref->type == REQUIRE_PREFERENCE_TYPE)))
00497             rhs_does_an_operator_creation = TRUE;
00498     }
00499 
00500     /* --- scan through lhs to look for various tests --- */
00501     lhs_tests_operator_acceptable_or_installed = FALSE;
00502     lhs_tests_operator_installed = FALSE;
00503     lhs_is_known_to_test_something_off_match_state = FALSE;
00504     lhs_is_known_to_test_something_off_match_operator = FALSE;
00505 
00506     for (c = lhs; c != NIL; c = c->next) {
00507         if (c->type != POSITIVE_CONDITION)
00508             continue;
00509         w = c->bt.wme;
00510         /* For NNPSCM, count something as "off the match state" only
00511            if it's not the OPERATOR. */
00512         if ((w->id == match_state) && (w->attr != current_agent(operator_symbol)))
00513             lhs_is_known_to_test_something_off_match_state = TRUE;
00514         if (w->id == match_operator)
00515             lhs_is_known_to_test_something_off_match_operator = TRUE;
00516         if (w == match_operator_wme)
00517             lhs_tests_operator_installed = TRUE;
00518         if ((w->id == match_goal) && (w->attr == current_agent(operator_symbol)))
00519             lhs_tests_operator_acceptable_or_installed = TRUE;
00520     }
00521 
00522     /* --- calcluate lhs support flags --- */
00523     oa_support_possible = lhs_tests_operator_installed;
00524     oc_support_possible = rhs_does_an_operator_creation;
00525     om_support_possible = lhs_tests_operator_acceptable_or_installed;
00526 
00527     if ((!oa_support_possible) && (!oc_support_possible) && (!om_support_possible))
00528         goto o_support_done;
00529 
00530     if (!lhs_is_known_to_test_something_off_match_state) {
00531         begin_os_tc(NIL);
00532         add_to_os_tc_if_id(match_state, TRUE);
00533         if (!id_or_value_of_condition_list_is_in_os_tc(lhs, match_state, match_state)) {
00534             oc_support_possible = FALSE;
00535             om_support_possible = FALSE;
00536         }
00537     }
00538 
00539     if (oa_support_possible) {
00540         if (!lhs_is_known_to_test_something_off_match_operator) {
00541             begin_os_tc(NIL);
00542             add_to_os_tc_if_id(match_operator, FALSE);
00543             if (!id_or_value_of_condition_list_is_in_os_tc(lhs, match_operator, NIL))
00544                 oa_support_possible = FALSE;
00545         }
00546     }
00547 
00548     /* --- look for rhs oa support --- */
00549     if (oa_support_possible) {
00550         begin_os_tc(rhs);
00551         add_to_os_tc_if_id(match_state, TRUE);
00552         for (pref = rhs; pref != NIL; pref = pref->inst_next) {
00553             if (pref->id->id.tc_num == current_agent(o_support_tc))
00554                 /* RBD 8/19/94 added extra NNPSCM test -- ^operator augs on the state
00555                    don't get o-support */
00556 /* AGR 639 begin 94.11.01 */
00557                 /* gap 10/6/94 You need to check the id on all preferences that have
00558                    an attribute of operator to see if this is an operator slot of a
00559                    context being modified. */
00560                 if (!((pref->attr == current_agent(operator_symbol)) && (is_state_id(pref->id, match_state))))
00561 /* AGR 639 end */
00562                     pref->o_supported = TRUE;
00563         }
00564     }
00565 
00566     /* --- look for rhs oc support --- */
00567     if (oc_support_possible) {
00568         begin_os_tc(rhs);
00569         for (pref = rhs; pref != NIL; pref = pref->inst_next) {
00570             if ((pref->id == match_goal) &&
00571                 (pref->attr == current_agent(operator_symbol)) &&
00572                 ((pref->type == ACCEPTABLE_PREFERENCE_TYPE) || (pref->type == REQUIRE_PREFERENCE_TYPE))) {
00573                 add_to_os_tc_if_id(pref->value, FALSE);
00574             }
00575         }
00576         for (pref = rhs; pref != NIL; pref = pref->inst_next) {
00577             /* SBH 6/23/94 */
00578             if ((pref->id->id.tc_num == current_agent(o_support_tc)) && (pref->id != match_state))
00579                 /* SBH: Added 2nd test to avoid circular assignment of o-support
00580                    to augmentations of the state: in, e.g.
00581                    (sp p2
00582                    (state <g> ^problem-space)(state <ig> ^problem-space.name top-ps)
00583                    -->
00584                    (<g> ^operator <o>)(<o> ^name opx ^circular-goal-test <ig>))
00585                    Here, the op acc. pref would get o-support (it's in the transitive
00586                    closure); this test rules it out.
00587 
00588                    BUGBUG: this is not fully general; it does not rule out assiging
00589                    o-support to substructures of the state that are in the TC of an
00590                    operator creation; e.g.
00591                    (sp p2
00592                    (state <g> ^problem-space)(state <ig> ^problem-space.name top-ps)
00593                    -->
00594                    (<g> ^operator <o> ^other <x>)
00595                    (<o> ^name opx ^circular-goal-test <ig>)
00596                    (<x> ^THIS-GETS-O-SUPPORT T))
00597                  */
00598                 /* end SBH 6/23/94 */
00599                 pref->o_supported = TRUE;
00600         }
00601     }
00602 
00603     /* --- look for rhs om support --- */
00604     if (om_support_possible) {
00605         begin_os_tc(rhs);
00606         for (c = inst->top_of_instantiated_conditions; c != NIL; c = c->next)
00607             if (c->type == POSITIVE_CONDITION) {
00608                 w = c->bt.wme;
00609                 if ((w->id == match_goal) && (w->attr == current_agent(operator_symbol)))
00610                     add_to_os_tc_if_id(w->value, FALSE);
00611             }
00612         for (pref = rhs; pref != NIL; pref = pref->inst_next)
00613             if (pref->id->id.tc_num == current_agent(o_support_tc))
00614                 pref->o_supported = TRUE;
00615     }
00616 
00617   o_support_done:{
00618     }
00619 }
00620 
00621 /* -----------------------------------------------------------------------
00622             Run-Time O-Support Calculation:  Doug Pearson's Scheme
00623 
00624    This routine calculates o-support for each preference for the given
00625    instantiation, filling in pref->o_supported (TRUE or FALSE) on each one.
00626 
00627    This is basically Doug's original scheme (from email August 16, 1994)
00628    modified by John's response (August 17) points #2 (don't give o-c
00629    support unless pref in TC of RHS op.) and #3 (all support calc's should
00630    be local to a goal).  In detail:
00631 
00632    For a particular preference p=(id ^attr ...) on the RHS of an
00633    instantiation [LHS,RHS]:
00634 
00635    RULE #1 (Context pref's): If id is the match state and attr="operator", 
00636    then p does NOT get o-support.  This rule overrides all other rules.
00637 
00638    RULE #2 (O-A support):  If LHS includes (match-state ^operator ...),
00639    then p gets o-support.
00640 
00641    RULE #3 (O-M support):  If LHS includes (match-state ^operator ... +),
00642    then p gets o-support.
00643 
00644    RULE #4 (O-C support): If RHS creates (match-state ^operator ... +/!),
00645    and p is in TC(RHS-operators, RHS), then p gets o-support.
00646 
00647    Here "TC" means transitive closure; the starting points for the TC are 
00648    all operators the RHS creates an acceptable/require preference for (i.e., 
00649    if the RHS includes (match-state ^operator such-and-such +/!), then 
00650    "such-and-such" is one of the starting points for the TC).  The TC
00651    is computed only through the preferences created by the RHS, not
00652    through any other existing preferences or WMEs.
00653 
00654    If none of rules 1-4 apply, then p does NOT get o-support.
00655 
00656    Note that rules 1 through 3 can be handled in linear time (linear in 
00657    the size of the LHS and RHS); rule 4 can be handled in time quadratic 
00658    in the size of the RHS (and typical behavior will probably be linear).
00659 ----------------------------------------------------------------------- */
00660 
00661 void dougs_calculate_support_for_instantiation_preferences(instantiation * inst)
00662 {
00663     Symbol *match_state;
00664     bool rule_2_or_3, anything_added;
00665     preference *rhs, *pref;
00666     wme *w;
00667     condition *lhs, *c;
00668 
00669     lhs = inst->top_of_instantiated_conditions;
00670     rhs = inst->preferences_generated;
00671     match_state = inst->match_goal;
00672 
00673     /* --- First, check whether rule 2 or 3 applies. --- */
00674     rule_2_or_3 = FALSE;
00675     for (c = lhs; c != NIL; c = c->next) {
00676         if (c->type != POSITIVE_CONDITION)
00677             continue;
00678         w = c->bt.wme;
00679         if ((w->id == match_state) && (w->attr == current_agent(operator_symbol))) {
00680             rule_2_or_3 = TRUE;
00681             break;
00682         }
00683     }
00684 
00685     /* --- Initialize all pref's according to rules 2 and 3 --- */
00686     for (pref = rhs; pref != NIL; pref = pref->inst_next)
00687         pref->o_supported = rule_2_or_3;
00688 
00689     /* --- If they didn't apply, check rule 4 --- */
00690     if (!rule_2_or_3) {
00691         current_agent(o_support_tc) = get_new_tc_number();
00692         /* BUGBUG With Doug's scheme, o_support_tc no longer needs to be a
00693            global variable -- it could simply be local to this procedure */
00694         anything_added = FALSE;
00695         /* --- look for RHS operators, add 'em (starting points) to the TC --- */
00696         for (pref = rhs; pref != NIL; pref = pref->inst_next) {
00697             if ((pref->id == match_state) &&
00698                 (pref->attr == current_agent(operator_symbol)) &&
00699                 ((pref->type == ACCEPTABLE_PREFERENCE_TYPE) ||
00700                  (pref->type == REQUIRE_PREFERENCE_TYPE)) &&
00701                 (pref->value->common.symbol_type == IDENTIFIER_SYMBOL_TYPE)) {
00702                 pref->value->id.tc_num = current_agent(o_support_tc);
00703                 anything_added = TRUE;
00704             }
00705         }
00706         /* --- Keep adding stuff to the TC until nothing changes anymore --- */
00707         while (anything_added) {
00708             anything_added = FALSE;
00709             for (pref = rhs; pref != NIL; pref = pref->inst_next) {
00710                 if (pref->id->id.tc_num != current_agent(o_support_tc))
00711                     continue;
00712                 if (pref->o_supported)
00713                     continue;   /* already added this thing */
00714                 pref->o_supported = TRUE;
00715                 anything_added = TRUE;
00716                 if (pref->value->common.symbol_type == IDENTIFIER_SYMBOL_TYPE)
00717                     pref->value->id.tc_num = current_agent(o_support_tc);
00718                 if ((preference_is_binary(pref->type)) &&
00719                     (pref->referent->common.symbol_type == IDENTIFIER_SYMBOL_TYPE))
00720                     pref->referent->id.tc_num = current_agent(o_support_tc);
00721             }
00722         }
00723     }
00724 
00725     /* --- Finally, use rule 1, which overrides all the other rules. --- */
00726     for (pref = rhs; pref != NIL; pref = pref->inst_next)
00727         if ((pref->id == match_state) && (pref->attr == current_agent(operator_symbol)))
00728             pref->o_supported = FALSE;
00729 }
00730 
00731 /* *********************************************************************
00732 
00733                    Compile-Time O-Support Calculations
00734 
00735 ********************************************************************* */
00736 
00737 /* ------------------------------------------------------------------
00738                          Test Is For Symbol
00739 
00740    This function determines whether a given symbol could be the match
00741    for a given test.  It returns YES if the symbol is the only symbol
00742    that could pass the test (i.e., the test *forces* that symbol to be
00743    present in WM), NO if the symbol couldn't possibly pass the test,
00744    and MAYBE if it can't tell for sure.  The symbol may be a variable;
00745    the test may contain variables.
00746 ------------------------------------------------------------------ */
00747 
00748 typedef enum yes_no_maybe_enum { YES, NO, MAYBE } yes_no_maybe;
00749 
00750 yes_no_maybe test_is_for_symbol(test t, Symbol * sym)
00751 {
00752     cons *c;
00753     yes_no_maybe temp;
00754     bool maybe_found;
00755     complex_test *ct;
00756     Symbol *referent;
00757 
00758     if (test_is_blank_test(t))
00759         return MAYBE;
00760 
00761     if (test_is_blank_or_equality_test(t)) {
00762         referent = referent_of_equality_test(t);
00763         if (referent == sym)
00764             return YES;
00765         if (referent->common.symbol_type == VARIABLE_SYMBOL_TYPE)
00766             return MAYBE;
00767         if (sym->common.symbol_type == VARIABLE_SYMBOL_TYPE)
00768             return MAYBE;
00769         return NO;
00770     }
00771 
00772     ct = complex_test_from_test(t);
00773 
00774     switch (ct->type) {
00775     case DISJUNCTION_TEST:
00776         if (sym->common.symbol_type == VARIABLE_SYMBOL_TYPE)
00777             return MAYBE;
00778         if (member_of_list(sym, ct->data.disjunction_list))
00779             return MAYBE;
00780         return NO;
00781     case CONJUNCTIVE_TEST:
00782         maybe_found = FALSE;
00783         for (c = ct->data.conjunct_list; c != NIL; c = c->rest) {
00784             temp = test_is_for_symbol(c->first, sym);
00785             if (temp == YES)
00786                 return YES;
00787             if (temp == MAYBE)
00788                 maybe_found = TRUE;
00789         }
00790         if (maybe_found)
00791             return MAYBE;
00792         return NO;
00793     default:                   /* goal/impasse tests, relational tests other than equality */
00794         return MAYBE;
00795     }
00796 }
00797 
00798 /* ------------------------------------------------------------------
00799                          Find Known Goals
00800 
00801    This routine looks at the LHS and returns a list of variables that
00802    are certain to be bound to goals.
00803 
00804    Note:  this uses the TC routines and clobbers any existing TC.
00805                          
00806    BUGBUG should follow ^object links up the goal stack if possible
00807 ------------------------------------------------------------------ */
00808 
00809 list *find_known_goals(condition * lhs)
00810 {
00811     tc_number tc;
00812     list *vars;
00813     condition *c;
00814 
00815     tc = get_new_tc_number();
00816     vars = NIL;
00817     for (c = lhs; c != NIL; c = c->next) {
00818         if (c->type != POSITIVE_CONDITION)
00819             continue;
00820         if (test_includes_goal_or_impasse_id_test(c->data.tests.id_test, TRUE, FALSE))
00821             add_bound_variables_in_test(c->data.tests.id_test, tc, &vars);
00822     }
00823     return vars;
00824 }
00825 
00826 /* ------------------------------------------------------------------
00827                   Find Compile Time Match Goal
00828 
00829    Given the LHS and a list of known goals (i.e., variables that must
00830    be bound to goals at run-time), this routine tries to determine
00831    which variable will be the match goal.  If successful, it returns
00832    that variable; if it can't tell which variable will be the match
00833    goal, it returns NIL.
00834 
00835    Note:  this uses the TC routines and clobbers any existing TC.
00836 ------------------------------------------------------------------ */
00837 
00838 Symbol *find_compile_time_match_goal(condition * lhs, list * known_goals)
00839 {
00840     tc_number tc;
00841     list *roots;
00842     list *root_goals;
00843     int num_root_goals;
00844     cons *c, *prev_c, *next_c;
00845     Symbol *result;
00846     condition *cond;
00847 
00848     /* --- find root variables --- */
00849     tc = get_new_tc_number();
00850     roots = collect_root_variables(lhs, tc, FALSE);
00851 
00852     /* --- intersect roots with known_goals, producing root_goals --- */
00853     root_goals = NIL;
00854     num_root_goals = 0;
00855     for (c = roots; c != NIL; c = c->rest)
00856         if (member_of_list(c->first, known_goals)) {
00857             push(c->first, root_goals);
00858             num_root_goals++;
00859         }
00860     free_list(roots);
00861 
00862     /* --- if more than one goal, remove any with "^object nil" --- */
00863     if (num_root_goals > 1) {
00864         for (cond = lhs; cond != NIL; cond = cond->next) {
00865             if ((cond->type == POSITIVE_CONDITION) &&
00866                 (test_is_for_symbol(cond->data.tests.attr_test, current_agent(superstate_symbol)) == YES) &&
00867                 (test_is_for_symbol(cond->data.tests.value_test, current_agent(nil_symbol)) == YES)) {
00868                 prev_c = NIL;
00869                 for (c = root_goals; c != NIL; c = next_c) {
00870                     next_c = c->rest;
00871                     if (test_is_for_symbol(cond->data.tests.id_test, c->first) == YES) {
00872                         /* --- remove c from the root_goals list --- */
00873                         if (prev_c)
00874                             prev_c->rest = next_c;
00875                         else
00876                             root_goals = next_c;
00877                         free_cons(c);
00878                         num_root_goals--;
00879                         if (num_root_goals == 1)
00880                             break;      /* be sure not to remove them all */
00881                     } else {
00882                         prev_c = c;
00883                     }
00884                 }               /* end of for (c) loop */
00885                 if (num_root_goals == 1)
00886                     break;      /* be sure not to remove them all */
00887             }
00888         }                       /* end of for (cond) loop */
00889     }
00890 
00891     /* --- if there's only one root goal, that's it! --- */
00892     if (num_root_goals == 1)
00893         result = root_goals->first;
00894     else
00895         result = NIL;
00896 
00897     /* --- clean up and return result --- */
00898     free_list(root_goals);
00899     return result;
00900 }
00901 
00902 /* ------------------------------------------------------------------
00903                        Find Thing Off Goal
00904 
00905    Given the LHS and a the match goal variable, this routine looks
00906    for a positive condition testing (goal ^attr) for the given attribute
00907    "attr".  If such a condition exists, and the value field contains
00908    an equality test for a variable, then that variable is returned.
00909    (If more than one such variable exists, one is chosen arbitrarily
00910    and returned.)  Otherwise the function returns NIL.
00911 
00912    Note:  this uses the TC routines and clobbers any existing TC.
00913 ------------------------------------------------------------------ */
00914 
00915 Symbol *find_thing_off_goal(condition * lhs, Symbol * goal, Symbol * attr)
00916 {
00917     condition *c;
00918     list *vars;
00919     tc_number tc;
00920     Symbol *result;
00921 
00922     for (c = lhs; c != NIL; c = c->next) {
00923         if (c->type != POSITIVE_CONDITION)
00924             continue;
00925         if (test_is_for_symbol(c->data.tests.id_test, goal) != YES)
00926             continue;
00927         if (test_is_for_symbol(c->data.tests.attr_test, attr) != YES)
00928             continue;
00929         if (c->test_for_acceptable_preference)
00930             continue;
00931         tc = get_new_tc_number();
00932         vars = NIL;
00933         add_bound_variables_in_test(c->data.tests.value_test, tc, &vars);
00934         if (vars) {
00935             result = vars->first;
00936             free_list(vars);
00937             return result;
00938         }
00939     }
00940     return NIL;
00941 }
00942 
00943 /* ------------------------------------------------------------------
00944                  Condition List Has Id Test For Sym
00945 
00946    This checks whether a given condition list has an equality test for
00947    a given symbol in the id field of any condition (at any nesting level
00948    within NCC's).
00949 ------------------------------------------------------------------ */
00950 
00951 bool condition_list_has_id_test_for_sym(condition * conds, Symbol * sym)
00952 {
00953     for (; conds != NIL; conds = conds->next) {
00954         switch (conds->type) {
00955         case POSITIVE_CONDITION:
00956         case NEGATIVE_CONDITION:
00957             if (test_includes_equality_test_for_symbol(conds->data.tests.id_test, sym))
00958                 return TRUE;
00959             break;
00960         case CONJUNCTIVE_NEGATION_CONDITION:
00961             if (condition_list_has_id_test_for_sym(conds->data.ncc.top, sym))
00962                 return TRUE;
00963             break;
00964         }
00965     }
00966     return FALSE;
00967 }
00968 
00969 /* SBH 7/1/94 #2 */
00970 
00971 /* ------------------------------------------------------------------
00972 
00973 ------------------------------------------------------------------ */
00974 
00975 bool match_state_tests_non_operator_slot(condition * conds, Symbol * match_state)
00976 {
00977     yes_no_maybe ynm;
00978 
00979     for (; conds != NIL; conds = conds->next) {
00980         switch (conds->type) {
00981         case POSITIVE_CONDITION:
00982         case NEGATIVE_CONDITION:
00983             if (test_includes_equality_test_for_symbol(conds->data.tests.id_test, match_state)) {
00984                 ynm = test_is_for_symbol(conds->data.tests.attr_test, current_agent(operator_symbol));
00985                 if (ynm == NO)
00986                     return TRUE;
00987             }
00988             break;
00989         case CONJUNCTIVE_NEGATION_CONDITION:
00990             if (match_state_tests_non_operator_slot(conds->data.ncc.top, match_state))
00991                 return TRUE;
00992             break;
00993         }
00994     }
00995     return FALSE;
00996 }
00997 
00998 /* end SBH 7/1/94 #2 */
00999 
01000 /* ------------------------------------------------------------------
01001                       Add TC Through LHS and RHS
01002 
01003    This enlarges a given TC by adding to it any connected conditions
01004    in the LHS or actions in the RHS.
01005 ------------------------------------------------------------------ */
01006 
01007 void add_tc_through_lhs_and_rhs(condition * lhs, action * rhs, tc_number tc, list ** id_list, list ** var_list)
01008 {
01009     condition *c;
01010     action *a;
01011     bool anything_changed;
01012 
01013     for (c = lhs; c != NIL; c = c->next)
01014         c->already_in_tc = FALSE;
01015     for (a = rhs; a != NIL; a = a->next)
01016         a->already_in_tc = FALSE;
01017 
01018     /* --- keep trying to add new stuff to the tc --- */
01019     for (;;) {
01020         anything_changed = FALSE;
01021         for (c = lhs; c != NIL; c = c->next)
01022             if (!c->already_in_tc)
01023                 if (cond_is_in_tc(c, tc)) {
01024                     add_cond_to_tc(c, tc, id_list, var_list);
01025                     c->already_in_tc = TRUE;
01026                     anything_changed = TRUE;
01027                 }
01028         for (a = rhs; a != NIL; a = a->next)
01029             if (!a->already_in_tc)
01030                 if (action_is_in_tc(a, tc)) {
01031                     add_action_to_tc(a, tc, id_list, var_list);
01032                     a->already_in_tc = TRUE;
01033                     anything_changed = TRUE;
01034                 }
01035         if (!anything_changed)
01036             break;
01037     }
01038 }
01039 
01040 /* -----------------------------------------------------------------------
01041                    Calculate Compile Time O-Support
01042 
01043    This takes the LHS and RHS, and fills in the a->support field in each
01044    RHS action with either UNKNOWN_SUPPORT, O_SUPPORT, or I_SUPPORT.
01045    (Actually, it only does this for MAKE_ACTION's--for FUNCALL_ACTION's,
01046    the support doesn't matter.)
01047 ----------------------------------------------------------------------- */
01048 
01049 void calculate_compile_time_o_support(condition * lhs, action * rhs)
01050 {
01051     list *known_goals;
01052     cons *c;
01053     Symbol *match_state, *match_operator;
01054     yes_no_maybe lhs_oa_support, lhs_oc_support, lhs_om_support;
01055     action *a;
01056     condition *cond;
01057     yes_no_maybe ynm;
01058     bool operator_found, possible_operator_found;
01059     tc_number tc;
01060 
01061     /* --- initialize:  mark all rhs actions as "unknown" --- */
01062     for (a = rhs; a != NIL; a = a->next)
01063         if (a->type == MAKE_ACTION)
01064             a->support = UNKNOWN_SUPPORT;
01065 
01066     /* --- if "operator" doesn't appear in any LHS attribute slot, and there
01067        are no RHS +/! makes for "operator", then nothing gets support --- */
01068     operator_found = FALSE;
01069     possible_operator_found = FALSE;
01070     for (cond = lhs; cond != NIL; cond = cond->next) {
01071         if (cond->type != POSITIVE_CONDITION)
01072             continue;
01073         ynm = test_is_for_symbol(cond->data.tests.attr_test, current_agent(operator_symbol));
01074         if (ynm == YES) {
01075             operator_found = possible_operator_found = TRUE;
01076             break;
01077         }
01078         if (ynm == MAYBE)
01079             possible_operator_found = TRUE;
01080     }
01081     if (!operator_found)
01082         for (a = rhs; a != NIL; a = a->next) {
01083             if (a->type != MAKE_ACTION)
01084                 continue;
01085             if (rhs_value_is_symbol(a->attr)) { /* RBD 3/29/95 general RHS attr's */
01086                 Symbol *attr;
01087                 attr = rhs_value_to_symbol(a->attr);
01088                 if (attr == current_agent(operator_symbol)) {
01089                     operator_found = possible_operator_found = TRUE;
01090                     break;
01091                 }
01092                 if (attr->common.symbol_type == VARIABLE_SYMBOL_TYPE)
01093                     possible_operator_found = TRUE;
01094             } else {
01095                 possible_operator_found = TRUE; /* for funcall, must play it safe */
01096             }
01097         }
01098     if (!possible_operator_found) {
01099         for (a = rhs; a != NIL; a = a->next) {
01100             if (a->type == MAKE_ACTION)
01101                 a->support = I_SUPPORT;
01102         }
01103         return;
01104     }
01105 
01106     /* --- find known goals; RHS augmentations of goals get no support --- */
01107     known_goals = find_known_goals(lhs);
01108     /* SBH: In NNPSCM, the only RHS-goal augmentations that can't get support are
01109        preferences for the "operator" slot. */
01110     for (c = known_goals; c != NIL; c = c->rest)
01111         for (a = rhs; a != NIL; a = a->next) {
01112             if (a->type != MAKE_ACTION)
01113                 continue;
01114             if (rhs_value_is_symbol(a->attr) && /* RBD 3/29/95 */
01115                 rhs_value_to_symbol(a->attr) == current_agent(operator_symbol) &&
01116                 (rhs_value_to_symbol(a->id) == c->first))
01117                 a->support = I_SUPPORT;
01118         }
01119 
01120     /* --- find match goal, state, and operator --- */
01121     match_state = find_compile_time_match_goal(lhs, known_goals);
01122     free_list(known_goals);
01123     if (!match_state)
01124         return;
01125     match_operator = find_thing_off_goal(lhs, match_state, current_agent(operator_symbol));
01126     /* --- If when checking (above) for "operator" appearing anywhere, we
01127        found a possible operator but not a definite operator, now go back and
01128        see if the possible operator was actually the match goal or match state;
01129        if so, it's not a possible operator.  (Note:  by "possible operator" I
01130        mean something appearing in the *attribute* field that might get bound
01131        to the symbol "operator".)  --- */
01132     if (possible_operator_found && !operator_found) {
01133         possible_operator_found = FALSE;
01134         for (cond = lhs; cond != NIL; cond = cond->next) {
01135             if (cond->type != POSITIVE_CONDITION)
01136                 continue;
01137             ynm = test_is_for_symbol(cond->data.tests.attr_test, current_agent(operator_symbol));
01138             if ((ynm != NO) && (test_is_for_symbol(cond->data.tests.attr_test, match_state) != YES)) {
01139                 possible_operator_found = TRUE;
01140                 break;
01141             }
01142         }
01143         if (!possible_operator_found) {
01144             for (a = rhs; a != NIL; a = a->next) {
01145                 if (a->type != MAKE_ACTION)
01146                     continue;
01147                 /* we're looking for "operator" augs of goals only, and match_state
01148                    couldn't get bound to a goal */
01149                 if (rhs_value_to_symbol(a->id) == match_state)
01150                     continue;
01151                 if (rhs_value_is_symbol(a->attr)) {     /* RBD 3/29/95 */
01152                     Symbol *attr;
01153                     attr = rhs_value_to_symbol(a->attr);
01154                     if ((attr->common.symbol_type == VARIABLE_SYMBOL_TYPE) && (attr != match_state)) {
01155                         possible_operator_found = TRUE;
01156                         break;
01157                     }
01158                 } else {        /* RBD 3/29/95 */
01159                     possible_operator_found = TRUE;
01160                     break;
01161                 }
01162             }
01163         }
01164         if (!possible_operator_found) {
01165             for (a = rhs; a != NIL; a = a->next)
01166                 if (a->type == MAKE_ACTION)
01167                     a->support = I_SUPPORT;
01168             return;
01169         }
01170     }
01171 
01172     /* --- calculate LHS support predicates --- */
01173     lhs_oa_support = MAYBE;
01174     if (match_operator)
01175 
01176 /* SBH 7/1/94 #2 */
01177         if ((condition_list_has_id_test_for_sym(lhs, match_operator)) &&
01178             (match_state_tests_non_operator_slot(lhs, match_state)))
01179 /* end SBH 7/1/94 #2 */
01180 
01181             lhs_oa_support = YES;
01182 
01183     lhs_oc_support = MAYBE;
01184     lhs_om_support = MAYBE;
01185 
01186 /* SBH 7/1/94 #2 */
01187     /* For NNPSCM, must test that there is a test of a non-operator slot off 
01188        of the match_state. */
01189     if (match_state_tests_non_operator_slot(lhs, match_state)) {
01190 /* end SBH 7/1/94 #2 */
01191 
01192         lhs_oc_support = YES;
01193         for (cond = lhs; cond != NIL; cond = cond->next) {
01194             if (cond->type != POSITIVE_CONDITION)
01195                 continue;
01196             if (test_is_for_symbol(cond->data.tests.id_test, match_state) != YES)
01197                 continue;
01198             if (test_is_for_symbol(cond->data.tests.attr_test, current_agent(operator_symbol))
01199                 != YES)
01200                 continue;
01201             lhs_om_support = YES;
01202             break;
01203         }
01204     }
01205 
01206     if (lhs_oa_support == YES) {        /* --- look for RHS o-a support --- */
01207         /* --- do TC(match_state) --- */
01208         tc = get_new_tc_number();
01209         add_symbol_to_tc(match_state, tc, NIL, NIL);
01210         add_tc_through_lhs_and_rhs(lhs, rhs, tc, NIL, NIL);
01211 
01212         /* --- any action with id in the TC gets support --- */
01213         for (a = rhs; a != NIL; a = a->next) {
01214 
01215             if (action_is_in_tc(a, tc)) {
01216                 /* SBH 7/1/94 Avoid resetting of support that was previously set to I_SUPPORT. */
01217                 /* gap 10/6/94 If the action has an attribue of operator, then you
01218                    don't know if it should get o-support until run time because of
01219                    the vagaries of knowing when this is matching a context object
01220                    or not. */
01221                 if (rhs_value_is_symbol(a->attr) && (rhs_value_to_symbol(a->attr) == current_agent(operator_symbol))) {
01222                     if (a->support != I_SUPPORT)
01223                         a->support = UNKNOWN_SUPPORT;
01224                 } else {
01225                     if (a->support != I_SUPPORT)
01226                         a->support = O_SUPPORT;
01227                 }
01228                 /* end SBH 7/1/94 */
01229             }
01230         }
01231     }
01232 
01233     if (lhs_oc_support == YES) {        /* --- look for RHS o-c support --- */
01234         /* --- do TC(rhs operators) --- */
01235         tc = get_new_tc_number();
01236         for (a = rhs; a != NIL; a = a->next) {
01237             if (a->type != MAKE_ACTION)
01238                 continue;
01239             if ((rhs_value_to_symbol(a->id) == match_state) &&
01240                 (rhs_value_is_symbol(a->attr)) &&
01241                 (rhs_value_to_symbol(a->attr) == current_agent(operator_symbol)) &&
01242                 ((a->preference_type == ACCEPTABLE_PREFERENCE_TYPE) ||
01243                  (a->preference_type == REQUIRE_PREFERENCE_TYPE))) {
01244                 if (rhs_value_is_symbol(a->value)) {
01245                     add_symbol_to_tc(rhs_value_to_symbol(a->value), tc, NIL, NIL);
01246                 }
01247             }
01248         }
01249         add_tc_through_lhs_and_rhs(lhs, rhs, tc, NIL, NIL);
01250 
01251         /* --- any action with id in the TC gets support --- */
01252         for (a = rhs; a != NIL; a = a->next)
01253 
01254             if (action_is_in_tc(a, tc)) {
01255 
01256                 /* SBH 6/7/94:
01257                    Make sure the action is not already marked as "I_SUPPORT".  This
01258                    avoids giving o-support in the case where the operator
01259                    points back to the goal, thus adding the goal to the TC,
01260                    thus adding the operator proposal itself to the TC; thus
01261                    giving o-support to an operator proposal.
01262                  */
01263                 if (a->support != I_SUPPORT)
01264                     a->support = O_SUPPORT;
01265                 /* End SBH 6/7/94 */
01266 
01267                 /* REW: begin 09.15.96 */
01268                 /*
01269                    in operand, operator proposals are now only i-supported.
01270                  */
01271 
01272 #ifndef SOAR_8_ONLY
01273                 if (current_agent(operand2_mode) == TRUE) {
01274 #endif
01275                     if (current_agent(soar_verbose_flag) == TRUE)
01276                         print("\n         operator creation: setting a->support to I_SUPPORT");
01277 
01278                     a->support = I_SUPPORT;
01279 #ifndef SOAR_8_ONLY
01280                 }
01281 #endif
01282                 /* REW: end   09.15.96 */
01283 
01284             }
01285     }
01286 
01287     if (lhs_om_support == YES) {        /* --- look for RHS o-m support --- */
01288         /* --- do TC(lhs operators) --- */
01289         tc = get_new_tc_number();
01290         for (cond = lhs; cond != NIL; cond = cond->next) {
01291             if (cond->type != POSITIVE_CONDITION)
01292                 continue;
01293             if (test_is_for_symbol(cond->data.tests.id_test, match_state) == YES)
01294                 if (test_is_for_symbol(cond->data.tests.attr_test, current_agent(operator_symbol))
01295                     == YES)
01296                     add_bound_variables_in_test(cond->data.tests.value_test, tc, NIL);
01297         }
01298         add_tc_through_lhs_and_rhs(lhs, rhs, tc, NIL, NIL);
01299 
01300         /* --- any action with id in the TC gets support --- */
01301         for (a = rhs; a != NIL; a = a->next)
01302 
01303             if (action_is_in_tc(a, tc)) {
01304                 /* SBH 7/1/94 Avoid resetting of support that was previously set to I_SUPPORT. */
01305                 if (a->support != I_SUPPORT)
01306                     a->support = O_SUPPORT;
01307                 /* end SBH 7/1/94 */
01308             }
01309     }
01310 }

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