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

recmem.c

Go to the documentation of this file.
00001 /*************************************************************************
00002  *
00003  *  file:  recmem.c
00004  *
00005  * =======================================================================
00006  *  
00007  *             Recognition Memory (Firer and Chunker) Routines
00008  *                 (Does not include the Rete net)
00009  *
00010  * Init_firer() and init_chunker() should be called at startup time, to
00011  * do initialization.
00012  *
00013  * Do_preference_phase() runs the entire preference phase.  This is called
00014  * from the top-level control in main.c.
00015  *
00016  * Possibly_deallocate_instantiation() checks whether an instantiation
00017  * can be deallocated yet, and does so if possible.  This is used whenever
00018  * the (implicit) reference count on the instantiation decreases.
00019  * =======================================================================
00020  *
00021  * Copyright 1995-2003 Carnegie Mellon University,
00022  *                                                                               University of Michigan,
00023  *                                                                               University of Southern California/Information
00024  *                                                                               Sciences Institute. All rights reserved.
00025  *                                                                              
00026  * Redistribution and use in source and binary forms, with or without
00027  * modification, are permitted provided that the following conditions are met:
00028  *
00029  * 1.   Redistributions of source code must retain the above copyright notice,
00030  *              this list of conditions and the following disclaimer. 
00031  * 2.   Redistributions in binary form must reproduce the above copyright notice,
00032  *              this list of conditions and the following disclaimer in the documentation
00033  *              and/or other materials provided with the distribution. 
00034  *
00035  * THIS SOFTWARE IS PROVIDED BY THE SOAR CONSORTIUM ``AS IS'' AND ANY EXPRESS OR
00036  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00037  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
00038  * EVENT SHALL THE SOAR CONSORTIUM  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
00039  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00040  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00041  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00042  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00043  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00044  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00045  * The views and conclusions contained in the software and documentation are
00046  * those of the authors and should not be interpreted as representing official
00047  * policies, either expressed or implied, of Carnegie Mellon University, the
00048  * University of Michigan, the University of Southern California/Information
00049  * Sciences Institute, or the Soar consortium.
00050  * =======================================================================
00051  */
00052 
00053 #include "soarkernel.h"
00054 #include <ctype.h>
00055 
00056 #ifdef __hpux
00057 #ifndef _INCLUDE_POSIX_SOURCE
00058 #define _INCLUDE_POSIX_SOURCE
00059 #endif
00060 #define _INCLUDE_XOPEN_SOURCE
00061 #define _INCLUDE_HPUX_SOURCE
00062 #include <sys/types.h>
00063 #undef  _INCLUDE_POSIX_SOURCE
00064 #undef  _INCLUDE_XOPEN_SOURCE
00065 #endif                          /* __hpux */
00066 #if !defined(__SC__) && !defined(THINK_C) && !defined(WIN32) && !defined(MACINTOSH)
00067 #include <sys/time.h>
00068 #endif                          /* !__SC__ && !THINK_C && !WIN32 */
00069 #ifdef __hpux
00070 #undef _INCLUDE_HPUX_SOURCE
00071 #endif                          /* __hpux */
00072 
00073 /* Uncomment the following line to get instantiation printouts */
00074 /* #define DEBUG_INSTANTIATIONS */
00075 
00076 #ifdef NO_TOP_JUST
00077 void remove_top_level_justifications(instantiation * inst);
00078 #endif
00079 
00080 /* mvp 5-17-94 */
00081 /* --------------------------------------------------------------------------
00082             Build Prohibit Preference List for Backtracing
00083 --------------------------------------------------------------------------*/
00084 
00085 void build_prohibits_list(instantiation * inst)
00086 {
00087     condition *cond;
00088     preference *pref, *new_pref;
00089 
00090     for (cond = inst->top_of_instantiated_conditions; cond != NIL; cond = cond->next) {
00091         cond->bt.prohibits = NIL;
00092         if (cond->type == POSITIVE_CONDITION && cond->bt.trace) {
00093             if (cond->bt.trace->slot) {
00094                 pref = cond->bt.trace->slot->preferences[PROHIBIT_PREFERENCE_TYPE];
00095                 while (pref) {
00096                     new_pref = NIL;
00097                     if (pref->inst->match_goal_level == inst->match_goal_level && pref->in_tm) {
00098                         push(pref, cond->bt.prohibits);
00099                         preference_add_ref(pref);
00100                     } else {
00101                         new_pref = find_clone_for_level(pref, inst->match_goal_level);
00102                         if (new_pref) {
00103                             if (new_pref->in_tm) {
00104                                 push(new_pref, cond->bt.prohibits);
00105                                 preference_add_ref(new_pref);
00106                             }
00107                         }
00108                     }
00109                     pref = pref->next;
00110                 }
00111             }
00112         }
00113     }
00114 }
00115 
00116 /* -----------------------------------------------------------------------
00117                          Find Clone For Level
00118 
00119    This routines take a given preference and finds the clone of it whose
00120    match goal is at the given goal_stack_level.  (This is used to find the
00121    proper preference to backtrace through.)  If the given preference
00122    itself is at the right level, it is returned.  If there is no clone at
00123    the right level, NIL is returned.
00124 ----------------------------------------------------------------------- */
00125 
00126 preference *find_clone_for_level(preference * p, goal_stack_level level)
00127 {
00128     preference *clone;
00129 
00130     if (!p) {
00131         /* --- if the wme doesn't even have a preference on it, we can't backtrace
00132            at all (this happens with I/O and some architecture-created wmes --- */
00133         return NIL;
00134     }
00135 
00136     /* --- look at pref and all of its clones, find one at the right level --- */
00137 
00138 #ifdef NO_TOP_JUST
00139     if (p->match_goal_level == level)
00140         return p;
00141 
00142     for (clone = p->next_clone; clone != NIL; clone = clone->next_clone)
00143         if (clone->match_goal_level == level)
00144             return clone;
00145 
00146     for (clone = p->prev_clone; clone != NIL; clone = clone->prev_clone)
00147         if (clone->match_goal_level == level)
00148             return clone;
00149 #else
00150 
00151     if (p->inst->match_goal_level == level)
00152         return p;
00153 
00154     for (clone = p->next_clone; clone != NIL; clone = clone->next_clone)
00155         if (clone->inst->match_goal_level == level)
00156             return clone;
00157 
00158     for (clone = p->prev_clone; clone != NIL; clone = clone->prev_clone)
00159         if (clone->inst->match_goal_level == level)
00160             return clone;
00161 
00162 #endif
00163 
00164     /* --- if none was at the right level, we can't backtrace at all --- */
00165     return NIL;
00166 }
00167 
00168 /* =======================================================================
00169 
00170                            Firer Utilities
00171 
00172 ======================================================================= */
00173 
00174 /* -----------------------------------------------------------------------
00175                              Find Match Goal
00176 
00177    Given an instantiation, this routines looks at the instantiated
00178    conditions to find its match goal.  It fills in inst->match_goal and
00179    inst->match_goal_level.  If there is a match goal, match_goal is set
00180    to point to the goal identifier.  If no goal was matched, match_goal
00181    is set to NIL and match_goal_level is set to ATTRIBUTE_IMPASSE_LEVEL.
00182 ----------------------------------------------------------------------- */
00183 
00184 void find_match_goal(instantiation * inst)
00185 {
00186     Symbol *lowest_goal_so_far;
00187     goal_stack_level lowest_level_so_far;
00188     condition *cond;
00189     Symbol *id;
00190 
00191     lowest_goal_so_far = NIL;
00192     lowest_level_so_far = -1;
00193     for (cond = inst->top_of_instantiated_conditions; cond != NIL; cond = cond->next)
00194         if (cond->type == POSITIVE_CONDITION) {
00195             id = cond->bt.wme->id;
00196             if (id->id.isa_goal)
00197                 if (cond->bt.level > lowest_level_so_far) {
00198                     lowest_goal_so_far = id;
00199                     lowest_level_so_far = cond->bt.level;
00200                 }
00201         }
00202 
00203     inst->match_goal = lowest_goal_so_far;
00204     if (lowest_goal_so_far)
00205         inst->match_goal_level = lowest_level_so_far;
00206     else
00207         inst->match_goal_level = ATTRIBUTE_IMPASSE_LEVEL;
00208 }
00209 
00210 /* -----------------------------------------------------------------------
00211 
00212                Executing the RHS Actions of an Instantiation
00213 
00214    Execute_action() executes a given RHS action.  For MAKE_ACTION's, it
00215    returns the created preference structure, or NIL if an error occurs.
00216    For FUNCALL_ACTION's, it returns NIL.
00217 
00218    Instantiate_rhs_value() returns the (symbol) instantiation of an
00219    rhs_value, or NIL if an error occurs.  It takes a new_id_level
00220    argument indicating what goal_stack_level a new id is to be created
00221    at, in case a gensym is needed for the instantiation of a variable.
00222    (BUGBUG I'm not sure this is really needed.)
00223 
00224    As rhs unbound variables are encountered, they are instantiated with
00225    new gensyms.  These gensyms are then stored in the rhs_variable_bindings
00226    array, so if the same unbound variable is encountered a second time
00227    it will be instantiated with the same gensym.
00228 ----------------------------------------------------------------------- */
00229 
00230 long firer_highest_rhs_unboundvar_index;
00231 
00232 Symbol *instantiate_rhs_value(rhs_value rv, goal_stack_level new_id_level,
00233                               char new_id_letter, struct token_struct *tok, wme * w)
00234 {
00235     list *fl;
00236     list *arglist;
00237     cons *c, *prev_c, *arg_cons;
00238     rhs_function *rf;
00239     Symbol *result;
00240     bool nil_arg_found;
00241 
00242     if (rhs_value_is_symbol(rv)) {
00243         result = rhs_value_to_symbol(rv);
00244         symbol_add_ref(result);
00245         return result;
00246     }
00247 
00248     if (rhs_value_is_unboundvar(rv)) {
00249         long index;
00250         Symbol *sym;
00251 
00252         index = rhs_value_to_unboundvar(rv);
00253         if (firer_highest_rhs_unboundvar_index < index)
00254             firer_highest_rhs_unboundvar_index = index;
00255         sym = *(current_agent(rhs_variable_bindings) + index);
00256 
00257         if (!sym) {
00258             sym = make_new_identifier(new_id_letter, new_id_level);
00259             *(current_agent(rhs_variable_bindings) + index) = sym;
00260             return sym;
00261         } else if (sym->common.symbol_type == VARIABLE_SYMBOL_TYPE) {
00262             new_id_letter = *(sym->var.name + 1);
00263             sym = make_new_identifier(new_id_letter, new_id_level);
00264             *(current_agent(rhs_variable_bindings) + index) = sym;
00265             return sym;
00266         } else {
00267             symbol_add_ref(sym);
00268             return sym;
00269         }
00270     }
00271 
00272     if (rhs_value_is_reteloc(rv)) {
00273         result = get_symbol_from_rete_loc((unsigned short) rhs_value_to_reteloc_levels_up(rv),
00274                                           (byte) rhs_value_to_reteloc_field_num(rv), tok, w);
00275         symbol_add_ref(result);
00276         return result;
00277     }
00278 
00279     fl = rhs_value_to_funcall_list(rv);
00280     rf = fl->first;
00281 
00282     /* --- build up a list of the argument values --- */
00283     prev_c = NIL;
00284     nil_arg_found = FALSE;
00285     arglist = NIL;              /* unnecessary, but gcc -Wall warns without it */
00286     for (arg_cons = fl->rest; arg_cons != NIL; arg_cons = arg_cons->rest) {
00287         allocate_cons(&c);
00288         c->first = instantiate_rhs_value(arg_cons->first, new_id_level, new_id_letter, tok, w);
00289         if (!c->first)
00290             nil_arg_found = TRUE;
00291         if (prev_c)
00292             prev_c->rest = c;
00293         else
00294             arglist = c;
00295         prev_c = c;
00296     }
00297     if (prev_c)
00298         prev_c->rest = NIL;
00299     else
00300         arglist = NIL;
00301 
00302     /* --- if all args were ok, call the function --- */
00303     if (!nil_arg_found)
00304         result = (*(rf->f)) (arglist);
00305     else
00306         result = NIL;
00307 
00308     /* --- scan through arglist, dereference symbols and deallocate conses --- */
00309     for (c = arglist; c != NIL; c = c->rest)
00310         if (c->first)
00311             symbol_remove_ref((Symbol *) (c->first));
00312     free_list(arglist);
00313 
00314     return result;
00315 }
00316 
00317 preference *execute_action(action * a, struct token_struct * tok, wme * w)
00318 {
00319     Symbol *id, *attr, *value, *referent;
00320     char first_letter;
00321 
00322     if (a->type == FUNCALL_ACTION) {
00323         value = instantiate_rhs_value(a->value, -1, 'v', tok, w);
00324         if (value)
00325             symbol_remove_ref(value);
00326         return NIL;
00327     }
00328 
00329     attr = NIL;
00330     value = NIL;
00331     referent = NIL;
00332 
00333     id = instantiate_rhs_value(a->id, -1, 's', tok, w);
00334     if (!id)
00335         goto abort_execute_action;
00336     if (id->common.symbol_type != IDENTIFIER_SYMBOL_TYPE) {
00337         print_with_symbols("Error: RHS makes a preference for %y (not an identifier)\n", id);
00338         goto abort_execute_action;
00339     }
00340 
00341     attr = instantiate_rhs_value(a->attr, id->id.level, 'a', tok, w);
00342     if (!attr)
00343         goto abort_execute_action;
00344 
00345     first_letter = first_letter_from_symbol(attr);
00346 
00347     value = instantiate_rhs_value(a->value, id->id.level, first_letter, tok, w);
00348     if (!value)
00349         goto abort_execute_action;
00350 
00351     if (preference_is_binary(a->preference_type)) {
00352         referent = instantiate_rhs_value(a->referent, id->id.level, first_letter, tok, w);
00353         if (!referent)
00354             goto abort_execute_action;
00355     }
00356 
00357     /* --- RBD 4/17/95 added stuff to handle attribute_preferences_mode --- */
00358     if (((a->preference_type != ACCEPTABLE_PREFERENCE_TYPE) &&
00359          (a->preference_type != REJECT_PREFERENCE_TYPE)) &&
00360         (!(id->id.isa_goal && (attr == current_agent(operator_symbol))))) {
00361 
00362 #ifndef SOAR_8_ONLY
00363         if ((current_agent(attribute_preferences_mode) == 2) || (current_agent(operand2_mode) == TRUE)) {
00364 #endif
00365             print_with_symbols("\nError: attribute preference other than +/- for %y ^%y -- ignoring it.", id, attr);
00366             goto abort_execute_action;
00367 
00368 #ifndef SOAR_8_ONLY
00369         } else if (current_agent(attribute_preferences_mode) == 1) {
00370             print_with_symbols("\nWarning: attribute preference other than +/- for %y ^%y.", id, attr);
00371         }
00372 #endif
00373 
00374     }
00375 
00376     return make_preference(a->preference_type, id, attr, value, referent);
00377 
00378   abort_execute_action:        /* control comes here when some error occurred */
00379     if (id)
00380         symbol_remove_ref(id);
00381     if (attr)
00382         symbol_remove_ref(attr);
00383     if (value)
00384         symbol_remove_ref(value);
00385     if (referent)
00386         symbol_remove_ref(referent);
00387     return NIL;
00388 }
00389 
00390 /* -----------------------------------------------------------------------
00391                     Fill In New Instantiation Stuff
00392 
00393    This routine fills in a newly created instantiation structure with
00394    various information.   At input, the instantiation should have:
00395      - preferences_generated filled in; 
00396      - instantiated conditions filled in;
00397      - top-level positive conditions should have bt.wme, bt.level, and
00398        bt.trace filled in, but bt.wme and bt.trace shouldn't have their
00399        reference counts incremented yet.
00400 
00401    This routine does the following:
00402      - increments reference count on production;
00403      - fills in match_goal and match_goal_level;
00404      - for each top-level positive cond:
00405          replaces bt.trace with the preference for the correct level,
00406          updates reference counts on bt.pref and bt.wmetraces and wmes
00407      - for each preference_generated, adds that pref to the list of all
00408        pref's for the match goal
00409      - fills in backtrace_number;   
00410      - if "need_to_do_support_calculations" is TRUE, calculates o-support
00411        for preferences_generated;
00412 ----------------------------------------------------------------------- */
00413 
00414 void fill_in_new_instantiation_stuff(instantiation * inst, bool need_to_do_support_calculations)
00415 {
00416     condition *cond;
00417     preference *p;
00418     goal_stack_level level;
00419 
00420 #if defined(OPTIMIZE_TOP_LEVEL_RESULTS) || ( defined(THIN_JUSTIFICATIONS) && !defined(MAKE_PRODUCTION_FOR_THIN_JUSTS))
00421     if (inst->prod)
00422 #endif
00423         production_add_ref(inst->prod);
00424 
00425     find_match_goal(inst);
00426 
00427     level = inst->match_goal_level;
00428 
00429 #ifdef NO_TOP_JUST
00430     /* Record goal information as we may discard pref->inst later      */
00431     /* This list of preferences will catch the productions results and */
00432     /* clone preferences (I believe).                                  */
00433 
00434     for (p = inst->preferences_generated; p != NIL; p = p->inst_next) {
00435         p->match_goal = inst->match_goal;       /* NIL if from attribute impasse */
00436         p->match_goal_level = inst->match_goal_level;
00437     }
00438 
00439 #endif                          /* NO_TOP_JUST */
00440 
00441     /* 
00442 
00443        Note: since we'll never backtrace through instantiations at the top
00444        level, it might make sense to not increment the reference counts
00445        on the wmes and preferences here if the instantiation is at the top
00446        level.  As it stands now, we could gradually accumulate garbage at
00447        the top level if we have a never-ending sequence of production
00448        firings at the top level that chain on each other's results.  (E.g.,
00449        incrementing a counter on every decision cycle.)  I'm leaving it this
00450        way for now, because if we go to S-Support, we'll (I think) need to
00451        save these around (maybe). 
00452 
00453      */
00454 
00455     for (cond = inst->top_of_instantiated_conditions; cond != NIL; cond = cond->next)
00456         if (cond->type == POSITIVE_CONDITION) {
00457 
00458             /* begin SW 7.7.99 */
00459 
00460 #ifdef NO_TOP_LEVEL_REFS
00461             if (level > 1) {
00462                 wme_add_ref(cond->bt.wme);
00463             }
00464 #else
00465             wme_add_ref(cond->bt.wme);
00466 #endif
00467 
00468             /* --- if trace is for a lower level, find one for this level --- */
00469             if (cond->bt.trace) {
00470 
00471 #ifdef NO_TOP_JUST
00472                 if (cond->bt.trace->match_goal_level > level)
00473                     cond->bt.trace = find_clone_for_level(cond->bt.trace, level);
00474 #else
00475 
00476                 if (cond->bt.trace->inst->match_goal_level > level)
00477                     cond->bt.trace = find_clone_for_level(cond->bt.trace, level);
00478 #endif
00479 
00480                 /* begin SW 7.7.99 */
00481 #ifdef NO_TOP_LEVEL_REFS
00482                 if ((cond->bt.trace) && (level > 1)) {
00483                     preference_add_ref(cond->bt.trace);
00484                 }
00485 #else
00486                 if (cond->bt.trace)
00487                     preference_add_ref(cond->bt.trace);
00488 #endif
00489             }
00490 
00491         }
00492 
00493     /* endif SW 7.7.99 */
00494 
00495     if (inst->match_goal) {
00496         for (p = inst->preferences_generated; p != NIL; p = p->inst_next) {
00497             insert_at_head_of_dll(inst->match_goal->id.preferences_from_goal, p, all_of_goal_next, all_of_goal_prev);
00498             p->on_goal_list = TRUE;
00499         }
00500     }
00501     inst->backtrace_number = 0;
00502 
00503     if (current_agent(o_support_calculation_type) == 0 ||
00504         current_agent(o_support_calculation_type) == 3 || current_agent(o_support_calculation_type) == 4) {
00505         /* --- do calc's the normal Soar 6 way --- */
00506         if (need_to_do_support_calculations)
00507             calculate_support_for_instantiation_preferences(inst);
00508     } else if (current_agent(o_support_calculation_type) == 1) {
00509         if (need_to_do_support_calculations)
00510             calculate_support_for_instantiation_preferences(inst);
00511         /* --- do calc's both ways, warn on differences --- */
00512         if ((inst->prod->declared_support != DECLARED_O_SUPPORT) &&
00513             (inst->prod->declared_support != DECLARED_I_SUPPORT)) {
00514             /* --- At this point, we've done them the normal way.  To look for
00515                differences, save o-support flags on a list, then do Doug's
00516                calculations, then compare and restore saved flags. --- */
00517             list *saved_flags;
00518             preference *pref;
00519             bool difference_found;
00520             saved_flags = NIL;
00521             for (pref = inst->preferences_generated; pref != NIL; pref = pref->inst_next)
00522                 push((pref->o_supported ? pref : NIL), saved_flags);
00523             saved_flags = destructively_reverse_list(saved_flags);
00524             dougs_calculate_support_for_instantiation_preferences(inst);
00525             difference_found = FALSE;
00526             for (pref = inst->preferences_generated; pref != NIL; pref = pref->inst_next) {
00527                 cons *c;
00528                 bool b;
00529                 c = saved_flags;
00530                 saved_flags = c->rest;
00531                 b = (bool) (c->first ? TRUE : FALSE);
00532                 free_cons(c);
00533                 if (pref->o_supported != b)
00534                     difference_found = TRUE;
00535                 pref->o_supported = b;
00536             }
00537             if (difference_found) {
00538                 print_with_symbols("\n*** O-support difference found in production %y", inst->prod->name);
00539             }
00540         }
00541     } else {
00542         /* --- do calc's Doug's way --- */
00543         if ((inst->prod->declared_support != DECLARED_O_SUPPORT) &&
00544             (inst->prod->declared_support != DECLARED_I_SUPPORT)) {
00545             dougs_calculate_support_for_instantiation_preferences(inst);
00546         }
00547     }
00548 }
00549 
00550 /* =======================================================================
00551 
00552                           Main Firer Routines
00553 
00554    Init_firer() should be called at startup time.  Do_preference_phase()
00555    is called from the top level to run the whole preference phase.
00556 
00557    Preference phase follows this sequence:
00558 
00559    (1) Productions are fired for new matches.  As productions are fired,
00560    their instantiations are stored on the list newly_created_instantiations,
00561    linked via the "next" fields in the instantiation structure.  No
00562    preferences are actually asserted yet.
00563    
00564    (2) Instantiations are retracted; their preferences are retracted.
00565 
00566    (3) Preferences (except o-rejects) from newly_created_instantiations
00567    are asserted, and these instantiations are removed from the 
00568    newly_created_instantiations list and moved over to the per-production
00569    lists of instantiations of that production.
00570 
00571    (4) Finally, o-rejects are processed.
00572 
00573          Note: Using the O_REJECTS_FIRST flag, step (4) becomes step (2b)
00574 ======================================================================= */
00575 
00576 void init_firer(void)
00577 {
00578     init_memory_pool(&current_agent(instantiation_pool), sizeof(instantiation), "instantiation");
00579 }
00580 
00581 /* --- Macro returning TRUE iff we're supposed to trace firings for the
00582    given instantiation, which should have the "prod" field filled in. --- */
00583 
00584 #ifndef TRACE_CONTEXT_DECISIONS_ONLY
00585 
00586 #define trace_firings_of_inst(inst) \
00587   ((inst)->prod && \
00588    (current_agent(sysparams)[TRACE_FIRINGS_OF_USER_PRODS_SYSPARAM+(inst)->prod->type] || \
00589     ((inst)->prod->trace_firings)))
00590 
00591 #endif
00592 
00593 /* -----------------------------------------------------------------------
00594                          Create Instantiation
00595 
00596    This builds the instantiation for a new match, and adds it to
00597    newly_created_instantiations.  It also calls chunk_instantiation() to
00598    do any necessary chunk or justification building.
00599 ----------------------------------------------------------------------- */
00600 
00601 void create_instantiation(production * prod, struct token_struct *tok, wme * w)
00602 {
00603     instantiation *inst;
00604     condition *cond;
00605     preference *pref;
00606     action *a;
00607     cons *c;
00608     bool need_to_do_support_calculations;
00609     bool trace_it;
00610     long index;
00611     Symbol **cell;
00612 
00613 #ifdef BUG_139_WORKAROUND
00614     /* RPM workaround for bug #139: don't fire justifications */
00615     if (prod->type == JUSTIFICATION_PRODUCTION_TYPE) {
00616         return;
00617     }
00618 #endif
00619 
00620     allocate_with_pool(&current_agent(instantiation_pool), &inst);
00621     inst->next = current_agent(newly_created_instantiations);
00622     current_agent(newly_created_instantiations) = inst;
00623     inst->prod = prod;
00624     inst->rete_token = tok;
00625     inst->rete_wme = w;
00626     inst->okay_to_variablize = TRUE;
00627     inst->in_ms = TRUE;
00628 
00629     /* REW: begin   09.15.96 */
00630     /*  We want to initialize the GDS_evaluated_already flag
00631      *  when a new instantiation is created.
00632      */
00633 
00634     inst->GDS_evaluated_already = FALSE;
00635 
00636 #ifndef SOAR_8_ONLY
00637     if (current_agent(operand2_mode) == TRUE) {
00638 #endif
00639         if (current_agent(soar_verbose_flag) == TRUE)
00640             print_with_symbols("\n   in create_instantiation: %y", inst->prod->name);
00641 #ifndef SOAR_8_ONLY
00642     }
00643 #endif
00644     /* REW: end   09.15.96 */
00645 
00646     current_agent(production_being_fired) = inst->prod;
00647     prod->firing_count++;
00648     current_agent(production_firing_count)++;
00649 
00650     /* --- build the instantiated conditions, and bind LHS variables --- */
00651     p_node_to_conditions_and_nots(prod->p_node, tok, w,
00652                                   &(inst->top_of_instantiated_conditions),
00653                                   &(inst->bottom_of_instantiated_conditions), &(inst->nots), NIL);
00654 
00655     /* --- record the level of each of the wmes that was positively tested --- */
00656     for (cond = inst->top_of_instantiated_conditions; cond != NIL; cond = cond->next) {
00657         if (cond->type == POSITIVE_CONDITION) {
00658             cond->bt.level = cond->bt.wme->id->id.level;
00659             cond->bt.trace = cond->bt.wme->preference;
00660 
00661         }
00662     }
00663 
00664 #ifndef TRACE_CONTEXT_DECISIONS_ONLY
00665 
00666     /* --- print trace info --- */
00667     trace_it = (bool) trace_firings_of_inst(inst);
00668     if (trace_it) {
00669         if (get_printer_output_column() != 1)
00670             print("\n");        /* AGR 617/634 */
00671         print("Firing ");
00672         print_instantiation_with_wmes
00673             (inst, (wme_trace_type) current_agent(sysparams)[TRACE_FIRINGS_WME_TRACE_TYPE_SYSPARAM]);
00674     }
00675 #endif
00676 
00677     /* --- initialize rhs_variable_bindings array with names of variables
00678        (if there are any stored on the production -- for chunks there won't
00679        be any) --- */
00680     index = 0;
00681     cell = current_agent(rhs_variable_bindings);
00682     for (c = prod->rhs_unbound_variables; c != NIL; c = c->rest) {
00683         *(cell++) = c->first;
00684         index++;
00685     }
00686     firer_highest_rhs_unboundvar_index = index - 1;
00687 
00688     /* 7.1/8 merge: Not sure about this.  This code in 704, but not in either 7.1 or 703/soar8 */
00689     /* --- Before executing the RHS actions, tell the user that the -- */
00690     /* --- phase has changed to output by printing the arrow --- */
00691 
00692 #ifndef TRACE_CONTEXT_DECISIONS_ONLY
00693 
00694     if (trace_it && current_agent(sysparams)[TRACE_FIRINGS_PREFERENCES_SYSPARAM]) {
00695         print(" -->\n");
00696     }
00697 #endif
00698 
00699     /* --- execute the RHS actions, collect the results --- */
00700     inst->preferences_generated = NIL;
00701     need_to_do_support_calculations = FALSE;
00702     for (a = prod->action_list; a != NIL; a = a->next) {
00703         pref = execute_action(a, tok, w);
00704         if (pref) {
00705             pref->inst = inst;
00706             insert_at_head_of_dll(inst->preferences_generated, pref, inst_next, inst_prev);
00707             if (inst->prod->declared_support == DECLARED_O_SUPPORT)
00708                 pref->o_supported = TRUE;
00709             else if (inst->prod->declared_support == DECLARED_I_SUPPORT)
00710                 pref->o_supported = FALSE;
00711 
00712             else {
00713 
00714 #ifndef SOAR_8_ONLY
00715                 if (current_agent(operand2_mode) == TRUE) {
00716 #endif
00717                     pref->o_supported = (bool) ((current_agent(FIRING_TYPE) == PE_PRODS) ? TRUE : FALSE);
00718 
00719 #ifndef SOAR_8_ONLY
00720                 }
00721 
00722                 /* REW: end   09.15.96 */
00723 
00724                 else {
00725                     if (a->support == O_SUPPORT)
00726                         pref->o_supported = TRUE;
00727                     else if (a->support == I_SUPPORT)
00728                         pref->o_supported = FALSE;
00729                     else {
00730                         need_to_do_support_calculations = TRUE;
00731                         if (current_agent(soar_verbose_flag) == TRUE)
00732                             print("\n\nin create_instantiation():  need_to_do_support_calculations == TRUE!!!\n\n");
00733                     }
00734 
00735                 }
00736 #endif
00737 
00738             }
00739         }
00740     }
00741 
00742     /* --- reset rhs_variable_bindings array to all zeros --- */
00743     index = 0;
00744     cell = current_agent(rhs_variable_bindings);
00745     while (index++ <= firer_highest_rhs_unboundvar_index)
00746         *(cell++) = NIL;
00747 
00748     /* --- fill in lots of other stuff --- */
00749     fill_in_new_instantiation_stuff(inst, need_to_do_support_calculations);
00750 
00751 #ifndef TRACE_CONTEXT_DECISIONS_ONLY
00752 
00753     /* --- print trace info: printing preferences --- */
00754     /* Note: can't move this up, since fill_in_new_instantiation_stuff gives
00755        the o-support info for the preferences we're about to print */
00756     if (trace_it && current_agent(sysparams)[TRACE_FIRINGS_PREFERENCES_SYSPARAM]) {
00757         for (pref = inst->preferences_generated; pref != NIL; pref = pref->inst_next) {
00758             print(" ");
00759             print_preference(pref);
00760         }
00761     }
00762 #endif
00763 
00764     /* mvp 5-17-94 */
00765     build_prohibits_list(inst);
00766 
00767     current_agent(production_being_fired) = NIL;
00768 
00769     /* --- build chunks/justifications if necessary --- */
00770     chunk_instantiation(inst, (bool) current_agent(sysparams)[LEARNING_ON_SYSPARAM]);
00771 
00772     /* MVP 6-8-94 */
00773     if (!current_agent(system_halted)) {
00774 
00775 #ifndef FEW_CALLBACKS
00776         /* --- invoke callback function --- */
00777         soar_invoke_callbacks(soar_agent, FIRING_CALLBACK, (soar_call_data) inst);
00778 #endif
00779     }
00780 }
00781 
00782 /* -----------------------------------------------------------------------
00783                         Deallocate Instantiation
00784 
00785    This deallocates the given instantiation.  This should only be invoked
00786    via the possibly_deallocate_instantiation() macro.
00787 ----------------------------------------------------------------------- */
00788 
00789 void deallocate_instantiation(instantiation * inst)
00790 {
00791     condition *cond;
00792 
00793     /* mvp 5-17-94 */
00794     list *c, *c_old;
00795     preference *pref;
00796     goal_stack_level level;
00797 
00798     level = inst->match_goal_level;
00799 
00800 #ifdef DEBUG_INSTANTIATIONS
00801     if (inst->prod)
00802         print_with_symbols("\nDeallocate instantiation of %y", inst->prod->name);
00803 #endif
00804 
00805 #ifdef WATCH_SSCI_INSTS
00806     if (inst->isa_ssci_inst == TRUE) {
00807         if (inst->prod) {
00808             print_with_symbols("\nDeallocating an SSCI instantiation: %y", inst->prod->name);
00809             print("Production has %d references\n", inst->prod->reference_count);
00810         } else
00811             print_with_symbols("\nDeallocating an SSCI instantiation whose production has already been excised\n");
00812 
00813     }
00814 #endif
00815 
00816     for (cond = inst->top_of_instantiated_conditions; cond != NIL; cond = cond->next)
00817         if (cond->type == POSITIVE_CONDITION) {
00818 
00819             /* mvp 6-22-94, modified 94.01.17 by AGR with lotsa help from GAP */
00820             if (cond->bt.prohibits) {
00821                 c_old = c = cond->bt.prohibits;
00822                 cond->bt.prohibits = NIL;
00823                 for (; c != NIL; c = c->rest) {
00824                     pref = (preference *) c->first;
00825 
00826 #ifdef NO_TOP_LEVEL_REFS
00827                     /* Note, we can probably speed this up with a variable */
00828                     if (level > 1)
00829 #endif
00830                         preference_remove_ref(pref);
00831                 }
00832                 free_list(c_old);
00833             }
00834             /* mvp done */
00835 
00836 #ifdef NO_TOP_LEVEL_REFS
00837             if (level > 1) {
00838                 wme_remove_ref(cond->bt.wme);
00839                 if (cond->bt.trace)
00840                     preference_remove_ref(cond->bt.trace);
00841             }
00842 #else
00843             wme_remove_ref(cond->bt.wme);
00844             if (cond->bt.trace)
00845                 preference_remove_ref(cond->bt.trace);
00846 
00847 #endif
00848 
00849         }
00850 
00851     deallocate_condition_list(inst->top_of_instantiated_conditions);
00852     deallocate_list_of_nots(inst->nots);
00853 
00854     if (inst->prod)
00855         production_remove_ref(inst->prod);
00856 
00857     free_with_pool(&current_agent(instantiation_pool), inst);
00858 }
00859 
00860 /* -----------------------------------------------------------------------
00861                          Retract Instantiation
00862 
00863    This retracts the given instantiation.
00864 ----------------------------------------------------------------------- */
00865 
00866 void retract_instantiation(instantiation * inst)
00867 {
00868     preference *pref, *next;
00869     bool retracted_a_preference;
00870 
00871 #ifndef TRACE_CONTEXT_DECISIONS_ONLY
00872     bool trace_it;
00873 #endif
00874 
00875 #ifndef FEW_CALLBACKS
00876     /* --- invoke callback function --- */
00877     soar_invoke_callbacks(soar_agent, RETRACTION_CALLBACK, (soar_call_data) inst);
00878 #endif
00879 
00880     retracted_a_preference = FALSE;
00881 
00882 #ifndef TRACE_CONTEXT_DECISIONS_ONLY
00883 
00884     trace_it = (bool) trace_firings_of_inst(inst);
00885 #endif
00886 
00887     /* --- retract any preferences that are in TM and aren't o-supported --- */
00888     pref = inst->preferences_generated;
00889     while (pref != NIL) {
00890         next = pref->inst_next;
00891         if (pref->in_tm && (!pref->o_supported)) {
00892 
00893 #ifndef TRACE_CONTEXT_DECISIONS_ONLY
00894 
00895             if (trace_it) {
00896                 if (!retracted_a_preference) {
00897                     if (get_printer_output_column() != 1)
00898                         print("\n");    /* AGR 617/634 */
00899                     print("Retracting ");
00900                     print_instantiation_with_wmes
00901                         (inst, (wme_trace_type) current_agent(sysparams)[TRACE_FIRINGS_WME_TRACE_TYPE_SYSPARAM]);
00902                     if (current_agent(sysparams)[TRACE_FIRINGS_PREFERENCES_SYSPARAM])
00903                         print(" -->");
00904                 }
00905                 if (current_agent(sysparams)[TRACE_FIRINGS_PREFERENCES_SYSPARAM]) {
00906                     print(" ");
00907                     print_preference(pref);
00908                 }
00909             }
00910 #endif
00911 
00912             remove_preference_from_tm(pref);
00913             retracted_a_preference = TRUE;
00914         }
00915         pref = next;
00916     }
00917 
00918     /* --- remove inst from list of instantiations of this production --- */
00919 #if defined(OPTIMIZE_TOP_LEVEL_RESULTS) || (defined(THIN_JUSTIFICATIONS) && !defined(MAKE_PRODUCTION_FOR_THIN_JUSTS))
00920     if (inst->prod)
00921 #endif
00922         remove_from_dll(inst->prod->instantiations, inst, next, prev);
00923 
00924     /* --- if retracting a justification, excise it --- */
00925     /*
00926      * if the reference_count on the production is 1 (or less) then the
00927      * only thing supporting this justification is the instantiation, hence
00928      * it has already been excised, and doing it again is wrong.
00929      */
00930 
00931 #ifdef WATCH_SSCI_INSTS
00932     if (inst->isa_ssci_inst) {
00933         print("Retracting SSCI instantiation...");
00934         if (inst->prod)
00935             print(" prod ref cound = %d\n", inst->prod->reference_count);
00936         else
00937             print("\n");
00938     }
00939 #endif
00940 
00941 #if defined(OPTIMIZE_TOP_LEVEL_RESULTS) || (defined(THIN_JUSTIFICATIONS) && !defined(MAKE_PRODUCTION_FOR_THIN_JUSTS))
00942     if (inst->prod && inst->prod->type == JUSTIFICATION_PRODUCTION_TYPE && inst->prod->reference_count > 1) {
00943 #else
00944 
00945     if (inst->prod->type == JUSTIFICATION_PRODUCTION_TYPE && inst->prod->reference_count > 1) {
00946 #endif
00947 
00948         excise_production(inst->prod, FALSE);
00949         /*inst->prod = NIL; */
00950     }
00951 
00952     /* --- mark as no longer in MS, and possibly deallocate  --- */
00953     inst->in_ms = FALSE;
00954     possibly_deallocate_instantiation(inst);
00955 }
00956 
00957 /* -----------------------------------------------------------------------
00958                          Assert New Preferences
00959 
00960    This routine scans through newly_created_instantiations, asserting
00961    each preference generated except for o-rejects.  It also removes
00962    each instantiation from newly_created_instantiations, linking each
00963    onto the list of instantiations for that particular production.
00964    O-rejects are bufferred and handled after everything else.
00965          
00966    Note that some instantiations on newly_created_instantiations are not
00967    in the match set--for the initial instantiations of chunks/justifications,
00968    if they don't match WM, we have to assert the o-supported preferences
00969    and throw away the rest.
00970 
00971          Note also that this ordering is different if the compile-time
00972          flag 'O_REJECTS_FIRST' is defined.  In this situation, o-rejects are 
00973          processed before other prefrences.
00974 ----------------------------------------------------------------------- */
00975 
00976 void assert_new_preferences(void)
00977 {
00978     instantiation *inst, *next_inst;
00979     preference *pref, *next_pref;
00980     preference *o_rejects;
00981 #if defined(WATCH_INSTS_WITH_O_PREFS) || defined(REMOVE_INSTS_WITH_O_PREFS) || defined(OPTIMIZE_TOP_LEVEL_RESULTS) || defined(THIN_JUSTIFICATIONS)
00982     bool is_fully_o_supported;
00983 
00984 #endif
00985 
00986     o_rejects = NIL;
00987 
00988     /* REW: begin 09.15.96 */
00989 #ifndef SOAR_8_ONLY
00990     if ((current_agent(operand2_mode) == TRUE) &&
00991 #else
00992     if (
00993 #endif
00994            (current_agent(soar_verbose_flag) == TRUE))
00995         print("\n   in assert_new_preferences:");
00996     /* REW: end   09.15.96 */
00997 
00998 #ifdef O_REJECTS_FIRST
00999     {
01000 
01001         slot *s;
01002         preference *p, *next_p;
01003 
01004         /* Do an initial loop to process o-rejects, then re-loop
01005            to process normal preferences.  No buffering should be needed.
01006          */
01007         for (inst = current_agent(newly_created_instantiations); inst != NIL; inst = next_inst) {
01008             next_inst = inst->next;
01009 
01010             for (pref = inst->preferences_generated; pref != NIL; pref = next_pref) {
01011                 next_pref = pref->inst_next;
01012                 if ((pref->type == REJECT_PREFERENCE_TYPE) && (pref->o_supported)) {
01013                     /* --- o-reject: just put it in the buffer for later --- */
01014 
01015                     s = find_slot(pref->id, pref->attr);
01016                     if (s) {
01017                         /* --- remove all pref's in the slot that have the same value --- */
01018                         p = s->all_preferences;
01019                         while (p) {
01020                             next_p = p->all_of_slot_next;
01021                             if (p->value == pref->value)
01022                                 remove_preference_from_tm(p);
01023                             p = next_p;
01024                         }
01025                     }
01026                 }
01027             }
01028         }
01029     }
01030 #endif
01031 
01032     for (inst = current_agent(newly_created_instantiations); inst != NIL; inst = next_inst) {
01033         next_inst = inst->next;
01034 
01035 #if defined(OPTIMIZE_TOP_LEVEL_RESULTS) || (defined(THIN_JUSTIFICATIONS) && !defined(MAKE_PRODUCTION_FOR_THIN_JUSTS))
01036         if (inst->in_ms && inst->prod)
01037 #else
01038         if (inst->in_ms)
01039 #endif
01040             insert_at_head_of_dll(inst->prod->instantiations, inst, next, prev);
01041 
01042         /* REW: begin 09.15.96 */
01043 #ifndef SOAR_8_ONLY
01044         if (current_agent(operand2_mode) == TRUE) {
01045 #endif
01046             if (current_agent(soar_verbose_flag) == TRUE) {
01047                 if (inst->prod)
01048                     print_with_symbols("\n      asserting instantiation: %y\n", inst->prod->name);
01049                 else
01050                     print("\n     asserting a Thin Instantiaion.\n");
01051             }
01052 #ifndef SOAR_8_ONLY
01053         }
01054 #endif
01055         /* REW: end   09.15.96 */
01056 
01057         for (pref = inst->preferences_generated; pref != NIL; pref = next_pref) {
01058             next_pref = pref->inst_next;
01059 
01060             if ((pref->type == REJECT_PREFERENCE_TYPE) && (pref->o_supported)) {
01061                 /* --- o-reject: just put it in the buffer for later --- */
01062 #ifndef O_REJECTS_FIRST
01063                 pref->next = o_rejects;
01064                 o_rejects = pref;
01065 #endif
01066 
01067                 /* REW: begin 09.15.96 */
01068                 /* No knowledge retrieval necessary in Operand2 */
01069                 /* REW: end   09.15.96 */
01070 
01071             } else if (inst->in_ms || pref->o_supported) {
01072                 /* --- normal case --- */
01073                 add_preference_to_tm(pref);
01074 
01075                 /* REW: begin 09.15.96 */
01076                 /* No knowledge retrieval necessary in Operand2 */
01077                 /* REW: end   09.15.96 */
01078 
01079             } else {
01080                 /* --- inst. is refracted chunk, and pref. is not o-supported:
01081                    remove the preference --- */
01082                 /* --- first splice it out of the clones list--otherwise we might
01083                    accidentally deallocate some clone that happens to have refcount==0
01084                    just because it hasn't been asserted yet --- */
01085                 if (pref->next_clone)
01086                     pref->next_clone->prev_clone = pref->prev_clone;
01087                 if (pref->prev_clone)
01088                     pref->prev_clone->next_clone = pref->next_clone;
01089                 pref->next_clone = pref->prev_clone = NIL;
01090                 /* --- now add then remove ref--this should result in deallocation */
01091                 preference_add_ref(pref);
01092                 preference_remove_ref(pref);
01093             }
01094         }
01095 
01096 #if defined(WATCH_INSTS_WITH_O_PREFS) || defined(REMOVE_INSTS_WITH_O_PREFS) || defined(THIN_JUSTIFICATIONS) || defined(WATCH_SSCI_INSTS) || defined(OPTIMIZE_TOP_LEVEL_RESULTS)
01097         is_fully_o_supported = TRUE;
01098 
01099         /*
01100            print( "Checking o-support on rhs of inst\n" );
01101            print_instantiation_with_wmes( inst, FULL_WME_TRACE );
01102          */
01103 
01104         for (pref = inst->preferences_generated; pref != NIL; pref = pref->inst_next) {
01105             if (pref->o_supported == FALSE) {
01106 
01107                 /*
01108                    if ( inst->isa_ssci_inst ) {
01109                    print( "This preference is not osupported\n" );
01110                    watchful_print_preference( pref );
01111                    }
01112                  */
01113 
01114                 is_fully_o_supported = FALSE;
01115                 break;
01116             }
01117         }
01118 
01119 #ifdef WATCH_SSCI_INSTS
01120         if (inst->isa_ssci_inst == TRUE) {
01121             if (inst->prod) {
01122                 print_with_symbols("\nThe SSCI instantiation of %y\n", inst->prod->name);
01123                 print_instantiation_with_wmes(inst, FULL_WME_TRACE);
01124 
01125             } else {
01126                 print("\nAn SSCI inst with a nil production\n");
01127             }
01128             if (is_fully_o_supported) {
01129                 print("at %p has FULLY o-supported results\n", inst);
01130             } else {
01131                 print("at %p has i-supported results\n", inst);
01132                 for (pref = inst->preferences_generated; pref != NIL; pref = pref->inst_next) {
01133                     watchful_print_preference(pref);
01134                 }
01135             }
01136         }
01137 #endif
01138 
01139         /* 
01140          * If an instantiation produces all o-supported preferences,
01141          * and we're not going to do backtracing (via learning or otherwise)
01142          * then we don't need to keep the instantiation around.
01143          * At this point, I think all of the preferences should have been
01144          * asserted, so hopefully we can just remove it...
01145          * There are a number of possbile build options defining what gets
01146          * removed these all interact at this point in the code, making 
01147          * everything extrememly tricky: 
01148          * REMOVE_INSTS_WITH_O_PREFS removes everything
01149          * 
01150          *
01151          */
01152 #ifdef REMOVE_INSTS_WITH_O_PREFS
01153         if (is_fully_o_supported)
01154             retract_instantiation(inst);
01155 
01156 #else                           /* !REMOVE_INSTS_WITH_O_PREFS */
01157 #if defined(OPTIMIZE_TOP_LEVEL_RESULTS)
01158 
01159         /* 
01160          *Remove everything with !inst->prod.  
01161          * This includes everyting made during OPTIMIZE_TOP_LEVEL_RESULT
01162          * AND everything made in THIN_JUSTIFICATIONS as long as
01163          * MAKE_PROD_FOR_THIN_JUSTS is not defined.
01164          */
01165         if (is_fully_o_supported && !inst->prod)
01166             retract_instantiation(inst);
01167 
01168 #if defined(THIN_JUSTIFICATIONS) && defined(MAKE_PRODUCTION_FOR_THIN_JUSTS)
01169         /* 
01170          * The only way to determine what has been made in THIN_JUSTIFICATIONS
01171          * is by checking isa_ssci_inst. Because isa_ssci_inst is not
01172          * set for those made during OPTIMIZE_TOP_LEVEL_RESULTS, we
01173          * dont have to worry about removing these guys twice.
01174          */
01175         if (is_fully_o_supported && inst->isa_ssci_inst == TRUE)
01176             retract_instantiation(inst);
01177 #endif
01178 
01179 #else                           /* !OPTIMIZE_TOP_LEVEL_RESULTS */
01180         /* 
01181          * If we dont OPTIMIZE_TOP_LEVEL_RESULTS, then we only need to deal 
01182          * with things made as a result of THIN_JUSTIFICATIONS.  Of course, 
01183          * this still means 2 situations.
01184          */
01185 #if defined(THIN_JUSTIFICATIONS) && defined(MAKE_PRODUCTION_FOR_THIN_JUSTS)
01186         if (is_fully_o_supported && inst->isa_ssci_inst == TRUE)
01187             retract_instantiation(inst);
01188 
01189 #elif defined(THIN_JUSTIFICATIONS) && !defined(MAKE_PRODUCTION_FOR_THIN_JUSTS)
01190         if (is_fully_o_supported && !inst->prod) {
01191             retract_instantiation(inst);
01192         }
01193 #endif
01194 
01195 #endif                          /* OPTIMIZE_TOP_LEVEL_RESULTS */
01196 
01197 #endif                          /* REMOVE_INSTS_WITH_O_PREFS */
01198 
01199 #endif
01200 
01201 #ifdef NO_TOP_JUST
01202 
01203 #ifdef REMOVE_INSTS_WITH_O_PREFS
01204         if (inst && inst->prod)
01205 #else
01206         if (inst->prod)
01207 #endif                          /* REMOVE_INSTS_WITH_O_PREFS */
01208             if (inst->prod->type == JUSTIFICATION_PRODUCTION_TYPE)
01209                 remove_top_level_justifications(inst);
01210 
01211 #endif                          /* NO_TOP_JUST */
01212 
01213     }
01214 #ifndef O_REJECTS_FIRST
01215     if (o_rejects)
01216         process_o_rejects_and_deallocate_them(o_rejects);
01217 #endif
01218 }
01219 
01220 /* -----------------------------------------------------------------------
01221                           Do Preference Phase
01222 
01223    This routine is called from the top level to run the preference phase.
01224 ----------------------------------------------------------------------- */
01225 
01226 void do_preference_phase(void)
01227 {
01228     production *prod;
01229     struct token_struct *tok;
01230     wme *w;
01231     instantiation *inst;
01232 
01233 #ifndef TRACE_CONTEXT_DECISIONS_ONLY
01234 
01235 /* AGR 617/634:  These are 2 bug reports that report the same problem,
01236    namely that when 2 chunk firings happen in succession, there is an
01237    extra newline printed out.  The simple fix is to monitor
01238    get_printer_output_column and see if it's at the beginning of a line
01239    or not when we're ready to print a newline.  94.11.14 */
01240 
01241     if (current_agent(sysparams)[TRACE_PHASES_SYSPARAM]) {
01242 #ifndef SOAR_8_ONLY
01243         if (current_agent(operand2_mode) == TRUE) {
01244 #endif
01245             switch (current_agent(FIRING_TYPE)) {
01246             case PE_PRODS:
01247                 print("\t--- Firing Productions (PE) ---\n");
01248                 break;
01249             case IE_PRODS:
01250                 print("\t--- Firing Productions (IE) ---\n");
01251                 break;
01252             }
01253 #ifndef SOAR_8_ONLY
01254         }
01255 
01256         else
01257             print("\n--- Preference Phase ---\n");
01258 #endif
01259     }
01260 
01261 #endif
01262 
01263     current_agent(newly_created_instantiations) = NIL;
01264 
01265     /* MVP 6-8-94 */
01266     while (get_next_assertion(&prod, &tok, &w)) {
01267         if (current_agent(max_chunks_reached)) {
01268             current_agent(system_halted) = TRUE;
01269             return;
01270         }
01271 
01272         create_instantiation(prod, tok, w);
01273     }
01274 
01275     assert_new_preferences();
01276 
01277     while (get_next_retraction(&inst))
01278         retract_instantiation(inst);
01279 
01280 /* REW: begin 08.20.97 */
01281 
01282     /*  In Waterfall, if there are nil goal retractions, then we want to 
01283        retract them as well, even though they are not associated with any
01284        particular goal (because their goal has been deleted). The 
01285        functionality of this separte routine could have been easily 
01286        combined in get_next_retraction but I wanted to highlight the 
01287        distinction between regualr retractions (those that can be 
01288        mapped onto a goal) and nil goal retractions that require a
01289        special data strucutre (because they don't appear on any goal) 
01290        REW.  */
01291 
01292 #ifndef SOAR_8_ONLY
01293     if (current_agent(operand2_mode) && current_agent(nil_goal_retractions)) {
01294 #else
01295     if (current_agent(nil_goal_retractions)) {
01296 #endif
01297         while (get_next_nil_goal_retraction(&inst))
01298             retract_instantiation(inst);
01299     }
01300 
01301 /* REW: end   08.20.97 */
01302 
01303 }
01304 
01305 #ifdef NO_TOP_JUST
01306 
01307 /* --------------------------------------------------------------------
01308 
01309                         Remove Top Level Justifications
01310 
01311    Go through the newly created instantiations and delete any that are
01312    top level justifications for o-supported preferences.
01313 
01314    The tricky part about this is the timing:
01315    1. We need to wait till after assert_new_preferences or the preferences
01316       from the justifications won't show up at all.
01317       Unfortunately, assert_new_preferences clears the list
01318       "newly_created_instantiations" as it works.
01319    2. We want to excise, retract and deallocate the instantiation.
01320       Excise production causes the rete to mark the instantiation for retraction.
01321       When it retracts, if its "preferences generated" list is empty and
01322       if the ref count on the instantiation is just 1, it'll be deallocated.
01323 
01324    This means, we have to slide this removal process into the assert_new_preferences
01325    loop.  That way the preferences get added, we excise the justification,
01326    mark all the preferences it created as having no instantiations supporting
01327    them and set the inst->preferences_generated list to nil.  The rete
01328    adds the justification to the list of retractions which are processed
01329    right after assert_new_preferences.  If everything goes to plan, the
01330    justification is pulled out and de-allocated and bingo we're done. DJP 5/8/96.
01331 
01332 -------------------------------------------------------------------- */
01333 
01334 void remove_top_level_justifications(instantiation * inst)
01335 {
01336     preference *pref;
01337     bool all_o_supported, remove_just;
01338 #ifdef NO_JUSTS_BELOW_OSUPPORT
01339     bool masked;
01340     slot *s;
01341     preference *p2;
01342 #endif
01343 
01344     /* Top level justifications of o-supported preferences can be safely  */
01345     /* removed as they serve no purpose.                                  */
01346 
01347     /* It *may* also be safe to remove justifications that are lower than      */
01348     /* an o-supported preference in the goal stack.  This *may* also cause     */
01349     /* problems for the chunker in some (hopefully rare) cases of backtracing. */
01350     /* If it does, we should turn off the "NO_JUSTS_BELOW_OSUPPORT flag.       */
01351 
01352     /* First thing to check is whether the justification was already excised  */
01353     /* because it failed to match.  I think we can do this by checking the    */
01354     /* production pointer in the name's symbol.  Anyway, if it's been excised */
01355     /* we don't need to try to excise it again :)                             */
01356 
01357     if (!inst->prod->name->sc.production)
01358         return;
01359 
01360     /* This routine is only called for justifications */
01361     /* First, we'll see if the justification is top level and only produced */
01362     /* o-supported prefs : */
01363 
01364     remove_just = FALSE;
01365     if (inst->match_goal_level <= TOP_GOAL_LEVEL) {
01366         all_o_supported = TRUE;
01367         for (pref = inst->preferences_generated; (pref != NIL && all_o_supported); pref = pref->inst_next)
01368             if (!pref->o_supported)
01369                 all_o_supported = FALSE;
01370         if (all_o_supported)
01371             remove_just = TRUE;
01372     }
01373 
01374     /* If we have a justification and for each of its preferences, there          */
01375     /* is an identical o-supported preference at a higher level in the goal stack */
01376     /* then we can remove this justification.                                     */
01377 
01378 #ifdef NO_JUSTS_BELOW_OSUPPORT
01379     if (inst->match_goal_level > TOP_GOAL_LEVEL) {
01380         remove_just = TRUE;
01381         for (pref = inst->preferences_generated; (pref != NIL && remove_just); pref = pref->inst_next) {
01382             s = pref->slot;
01383             masked = FALSE;
01384             if (s) {
01385                 /* Is there an o-supported pref for this same value higher in the stack ? */
01386                 for (p2 = s->preferences[pref->type]; (p2 != NIL && !masked); p2 = p2->next)
01387                     if (p2->match_goal_level < pref->match_goal_level && p2->o_supported == TRUE && p2->value == pref->value)   /* Can we compare these pointers ? */
01388                         masked = TRUE;
01389                 if (!masked)
01390                     remove_just = FALSE;
01391             }
01392         }
01393     }
01394 #endif
01395 
01396     if (remove_just) {
01397 
01398 #ifndef TRACE_CONTEXT_DECISIONS_ONLY
01399         if (current_agent(sysparams)[TRACE_JUSTIFICATIONS_SYSPARAM])
01400             print_with_symbols("\nRemoving %y", inst->prod->name);
01401 #endif
01402 
01403         excise_production(inst->prod, FALSE);
01404 
01405         /* Excising the production causes the rete to line it up for retracting */
01406         /* This will happen after assert_new_preferences has finished its work. */
01407 
01408         /* Now remove all trace of this justification by reseting the pointers */
01409         /* for each preference.  This also means a lot of little changes all   */
01410         /* over Soar to cover the situation where pref->inst is nil.           */
01411 
01412         for (pref = inst->preferences_generated; pref != NIL; pref = pref->inst_next)
01413             pref->inst = NIL;
01414 
01415         /* Finally, reset the preferences generated list.               */
01416         /* This way, when the justification retracts, Soar will reclaim */
01417         /* the memory.                                                  */
01418         inst->preferences_generated = NIL;
01419         inst->in_ms = FALSE;    /* This should always be correct, right? */
01420     }
01421 }
01422 
01423 #endif

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