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

chunk.c

Go to the documentation of this file.
00001 /*************************************************************************
00002  *
00003  *  file:  chunk.c
00004  *
00005  * =======================================================================
00006  *  Supports the learning mechanism in Soar.  Learning can be set
00007  *  on | off | only | except (for other choices see soarCommands.c: learn).
00008  *  If set to "only" | "except" users must specify rhs functions in
00009  *  productions: dont-learn | force-learn.   See rhsfun.c
00010  * =======================================================================
00011  *
00012  * Copyright 1995-2003 Carnegie Mellon University,
00013  *                                                                               University of Michigan,
00014  *                                                                               University of Southern California/Information
00015  *                                                                               Sciences Institute. All rights reserved.
00016  *                                                                              
00017  * Redistribution and use in source and binary forms, with or without
00018  * modification, are permitted provided that the following conditions are met:
00019  *
00020  * 1.   Redistributions of source code must retain the above copyright notice,
00021  *              this list of conditions and the following disclaimer. 
00022  * 2.   Redistributions in binary form must reproduce the above copyright notice,
00023  *              this list of conditions and the following disclaimer in the documentation
00024  *              and/or other materials provided with the distribution. 
00025  *
00026  * THIS SOFTWARE IS PROVIDED BY THE SOAR CONSORTIUM ``AS IS'' AND ANY EXPRESS OR
00027  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00028  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
00029  * EVENT SHALL THE SOAR CONSORTIUM  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
00030  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00031  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00032  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00033  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00034  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00035  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00036  * The views and conclusions contained in the software and documentation are
00037  * those of the authors and should not be interpreted as representing official
00038  * policies, either expressed or implied, of Carnegie Mellon University, the
00039  * University of Michigan, the University of Southern California/Information
00040  * Sciences Institute, or the Soar consortium.
00041  * =======================================================================
00042  */
00043 
00044 /* ====================================================================
00045 
00046                           Chunking Routines
00047 
00048    ==================================================================== */
00049 
00050 #include "soarkernel.h"
00051 #include <ctype.h>
00052 #include "soar_core_utils.h"
00053 #include "explain.h"
00054 
00055 extern byte type_of_existing_impasse(Symbol * goal);
00056 extern wme *find_impasse_wme(Symbol * id, Symbol * attr);
00057 extern void find_match_goal(instantiation * inst);
00058 
00059 /* =====================================================================
00060 
00061                            Results Calculation
00062 
00063    Get_results_for_instantiation() finds and returns the result preferences
00064    for a given instantiation.  This is the main routine here.
00065 
00066    The results are accumulated in the list "results," linked via the
00067    "next_result" field of the preference structures.  (BUGBUG: to save
00068    space, just use conses for this.)
00069 
00070    Add_pref_to_results() adds a preference to the results.
00071    Add_results_for_id() adds any preferences for the given identifier.
00072    Identifiers are marked with results_tc_number as they are added.
00073 ===================================================================== */
00074 
00075 void add_results_for_id(Symbol * id);
00076 #ifdef DONT_CALC_GDS_OR_BT
00077 static void add_named_superstate_attribute_to_grounds(instantiation * inst, char *name);
00078 #endif
00079 
00080 #ifdef SINGLE_THIN_JUSTIFICATION
00081 void deallocate_inst_members_to_be_rewritten(instantiation * inst);
00082 void second_stage_chunk_instantiation(instantiation * inst);
00083 void re_fill_in_instantiation_stuff_for_modified_lhs(instantiation * inst, bool need_to_do_support_calculations);
00084 
00085 #endif                          /* SINGLE_THIN_JUSTIFICATION */
00086 
00087 #define add_results_if_needed(sym) \
00088   { if ((sym)->common.symbol_type==IDENTIFIER_SYMBOL_TYPE) \
00089       if ( ((sym)->id.level >= current_agent(results_match_goal_level)) && \
00090            ((sym)->id.tc_num != current_agent(results_tc_number)) ) \
00091         add_results_for_id(sym); }
00092 
00093 void add_pref_to_results(preference * pref)
00094 {
00095     preference *p;
00096 
00097     /* --- if an equivalent pref is already a result, don't add this one --- */
00098     for (p = current_agent(results); p != NIL; p = p->next_result) {
00099         if (p->id != pref->id)
00100             continue;
00101         if (p->attr != pref->attr)
00102             continue;
00103         if (p->value != pref->value)
00104             continue;
00105         if (p->type != pref->type)
00106             continue;
00107         if (preference_is_unary(pref->type))
00108             return;
00109         if (p->referent != pref->referent)
00110             continue;
00111         return;
00112     }
00113 
00114 #ifdef NO_TOP_JUST
00115     /* --- if pref isn't at the right level, find a clone that is --- */
00116     if (pref->match_goal_level != current_agent(results_match_goal_level)) {
00117         for (p = pref->next_clone; p != NIL; p = p->next_clone)
00118             if (p->match_goal_level == current_agent(results_match_goal_level))
00119                 break;
00120         if (!p)
00121             for (p = pref->prev_clone; p != NIL; p = p->prev_clone)
00122                 if (p->match_goal_level == current_agent(results_match_goal_level))
00123                     break;
00124         if (!p)
00125             return;             /* if can't find one, it isn't a result */
00126         pref = p;
00127     }
00128 #else
00129 
00130     /* --- if pref isn't at the right level, find a clone that is --- */
00131     if (pref->inst->match_goal_level != current_agent(results_match_goal_level)) {
00132         for (p = pref->next_clone; p != NIL; p = p->next_clone)
00133             if (p->inst->match_goal_level == current_agent(results_match_goal_level))
00134                 break;
00135         if (!p)
00136             for (p = pref->prev_clone; p != NIL; p = p->prev_clone)
00137                 if (p->inst->match_goal_level == current_agent(results_match_goal_level))
00138                     break;
00139         if (!p)
00140             return;             /* if can't find one, it isn't a result */
00141         pref = p;
00142     }
00143 #endif
00144 
00145     /* --- add this preference to the result list --- */
00146     pref->next_result = current_agent(results);
00147     current_agent(results) = pref;
00148 
00149     /* --- follow transitive closuse through value, referent links --- */
00150     add_results_if_needed(pref->value);
00151     if (preference_is_binary(pref->type))
00152         add_results_if_needed(pref->referent);
00153 }
00154 
00155 void add_results_for_id(Symbol * id)
00156 {
00157     slot *s;
00158     preference *pref;
00159     wme *w;
00160 
00161     id->id.tc_num = current_agent(results_tc_number);
00162 
00163     /* --- scan through all preferences and wmes for all slots for this id --- */
00164     for (w = id->id.input_wmes; w != NIL; w = w->next)
00165         add_results_if_needed(w->value);
00166     for (s = id->id.slots; s != NIL; s = s->next) {
00167         for (pref = s->all_preferences; pref != NIL; pref = pref->all_of_slot_next)
00168             add_pref_to_results(pref);
00169         for (w = s->wmes; w != NIL; w = w->next)
00170             add_results_if_needed(w->value);
00171     }                           /* end of for slots loop */
00172     /* --- now scan through extra prefs and look for any with this id --- */
00173     for (pref = current_agent(extra_result_prefs_from_instantiation); pref != NIL; pref = pref->inst_next) {
00174         if (pref->id == id)
00175             add_pref_to_results(pref);
00176     }
00177 }
00178 
00179 preference *get_results_for_instantiation(instantiation * inst)
00180 {
00181     preference *pref;
00182 
00183     current_agent(results) = NIL;
00184     current_agent(results_match_goal_level) = inst->match_goal_level;
00185     current_agent(results_tc_number) = get_new_tc_number();
00186     current_agent(extra_result_prefs_from_instantiation) = inst->preferences_generated;
00187     for (pref = inst->preferences_generated; pref != NIL; pref = pref->inst_next)
00188         if ((pref->id->id.level < current_agent(results_match_goal_level)) &&
00189             (pref->id->id.tc_num != current_agent(results_tc_number))) {
00190             add_pref_to_results(pref);
00191 
00192         }
00193     return current_agent(results);
00194 }
00195 
00196 /* =====================================================================
00197 
00198                   Variablizing Conditions and Results
00199 
00200    Variablizing of conditions is done by walking over a condition list
00201    and destructively modifying it, replacing tests of identifiers with
00202    tests of tests of variables.  The identifier-to-variable mapping is
00203    built as we go along:  identifiers that have already been assigned
00204    a variablization are marked with id.tc_num==variablization_tc, and
00205    id.variablization points to the corresponding variable.
00206 
00207    Variablizing of results can't be done destructively because we need
00208    to convert the results--preferences--into actions.  This is done
00209    by copy_and_variablize_result_list(), which takes the result preferences
00210    and returns an action list.
00211 
00212    The global variable "variablize_this_chunk" indicates whether to
00213    variablize at all.  This flag is set to TRUE or FALSE before and during
00214    backtracing.  FALSE means the new production will become a justification;
00215    TRUE means it will be a chunk.
00216 ===================================================================== */
00217 
00218 void variablize_symbol(Symbol ** sym)
00219 {
00220     char prefix[2];
00221     Symbol *var;
00222 
00223     if ((*sym)->common.symbol_type != IDENTIFIER_SYMBOL_TYPE)
00224         return;
00225     if (!current_agent(variablize_this_chunk))
00226         return;
00227 
00228     if ((*sym)->id.tc_num == current_agent(variablization_tc)) {
00229         /* --- it's already been variablized, so use the existing variable --- */
00230         var = (*sym)->id.variablization;
00231         symbol_remove_ref(*sym);
00232         *sym = var;
00233         symbol_add_ref(var);
00234         return;
00235     }
00236 
00237     /* --- need to create a new variable --- */
00238     (*sym)->id.tc_num = current_agent(variablization_tc);
00239     prefix[0] = (char) tolower((*sym)->id.name_letter);
00240     prefix[1] = 0;
00241     var = generate_new_variable(prefix);
00242     (*sym)->id.variablization = var;
00243     symbol_remove_ref(*sym);
00244     *sym = var;
00245 }
00246 
00247 void variablize_test(test * t)
00248 {
00249     cons *c;
00250     complex_test *ct;
00251 
00252     if (test_is_blank_test(*t))
00253         return;
00254     if (test_is_blank_or_equality_test(*t)) {
00255         variablize_symbol((Symbol **) t);
00256         /* Warning: this relies on the representation of tests */
00257         return;
00258     }
00259 
00260     ct = complex_test_from_test(*t);
00261 
00262     switch (ct->type) {
00263     case GOAL_ID_TEST:
00264     case IMPASSE_ID_TEST:
00265     case DISJUNCTION_TEST:
00266         return;
00267     case CONJUNCTIVE_TEST:
00268         for (c = ct->data.conjunct_list; c != NIL; c = c->rest)
00269             variablize_test((test *) (&(c->first)));
00270         return;
00271     default:                   /* relational tests other than equality */
00272         variablize_symbol(&(ct->data.referent));
00273         return;
00274     }
00275 }
00276 
00277 void variablize_condition_list(condition * cond)
00278 {
00279     for (; cond != NIL; cond = cond->next) {
00280         switch (cond->type) {
00281         case POSITIVE_CONDITION:
00282         case NEGATIVE_CONDITION:
00283             variablize_test(&(cond->data.tests.id_test));
00284             variablize_test(&(cond->data.tests.attr_test));
00285             variablize_test(&(cond->data.tests.value_test));
00286             break;
00287         case CONJUNCTIVE_NEGATION_CONDITION:
00288             variablize_condition_list(cond->data.ncc.top);
00289             break;
00290         }
00291     }
00292 }
00293 
00294 action *copy_and_variablize_result_list(preference * pref)
00295 {
00296     action *a;
00297     Symbol *temp;
00298 
00299     if (!pref)
00300         return NIL;
00301     allocate_with_pool(&current_agent(action_pool), &a);
00302     a->type = MAKE_ACTION;
00303 
00304     temp = pref->id;
00305     symbol_add_ref(temp);
00306     variablize_symbol(&temp);
00307     a->id = symbol_to_rhs_value(temp);
00308 
00309     temp = pref->attr;
00310     symbol_add_ref(temp);
00311     variablize_symbol(&temp);
00312     a->attr = symbol_to_rhs_value(temp);
00313 
00314     temp = pref->value;
00315     symbol_add_ref(temp);
00316     variablize_symbol(&temp);
00317     a->value = symbol_to_rhs_value(temp);
00318 
00319     a->preference_type = pref->type;
00320 
00321     if (preference_is_binary(pref->type)) {
00322         temp = pref->referent;
00323         symbol_add_ref(temp);
00324         variablize_symbol(&temp);
00325         a->referent = symbol_to_rhs_value(temp);
00326     }
00327 
00328     a->next = copy_and_variablize_result_list(pref->next_result);
00329     return a;
00330 }
00331 
00332 /* ====================================================================
00333 
00334      Chunk Conditions, and Chunk Conditions Set Manipulation Routines
00335 
00336    These structures have two uses.  First, for every ground condition,
00337    one of these structures maintains certain information about it--
00338    pointers to the original (instantiation's) condition, the chunks's
00339    instantiation's condition, and the variablized condition, etc.
00340 
00341    Second, for negated conditions, these structures are entered into
00342    a hash table with keys hash_condition(this_cond).  This hash table
00343    is used so we can add a new negated condition to the set of negated
00344    potentials quickly--we don't want to add a duplicate of a negated
00345    condition that's already there, and the hash table lets us quickly
00346    determine whether a duplicate is already there.
00347 
00348    I used one type of structure for both of these uses, (1) for simplicity
00349    and (2) to avoid having to do a second allocation when we move
00350    negated conditions over to the ground set.
00351 ==================================================================== */
00352 
00353 /* --------------------------------------------------------------------
00354                       Chunk Cond Set Routines
00355 
00356    Init_chunk_cond_set() initializes a given chunk_cond_set to be empty.
00357    
00358    Make_chunk_cond_for_condition() takes a condition and returns a
00359    chunk_cond for it, for use in a chunk_cond_set.  This is used only
00360    for the negated conditions, not grounds.
00361 
00362    Add_to_chunk_cond_set() adds a given chunk_cond to a given chunk_cond_set
00363    and returns TRUE if the condition isn't already in the set.  If the 
00364    condition is already in the set, the routine deallocates the given
00365    chunk_cond and returns FALSE.
00366 
00367    Remove_from_chunk_cond_set() removes a given chunk_cond from a given
00368    chunk_cond_set, but doesn't deallocate it.
00369 -------------------------------------------------------------------- */
00370 
00371                              /* set of all negated conditions we encounter
00372                                 during backtracing--these are all potentials
00373                                 and (some of them) are added to the grounds
00374                                 in one pass at the end of the backtracing */
00375 
00376 void init_chunk_cond_set(chunk_cond_set * set)
00377 {
00378     int i;
00379 
00380     set->all = NIL;
00381     for (i = 0; i < CHUNK_COND_HASH_TABLE_SIZE; i++)
00382         set->table[i] = NIL;
00383 }
00384 
00385 chunk_cond *make_chunk_cond_for_condition(condition * cond)
00386 {
00387     chunk_cond *cc;
00388     unsigned long remainder, hv;
00389 
00390     allocate_with_pool(&current_agent(chunk_cond_pool), &cc);
00391     cc->cond = cond;
00392     cc->hash_value = hash_condition(cond);
00393     remainder = cc->hash_value;
00394     hv = 0;
00395     while (remainder) {
00396         hv ^= (remainder & masks_for_n_low_order_bits[LOG_2_CHUNK_COND_HASH_TABLE_SIZE]);
00397         remainder = remainder >> LOG_2_CHUNK_COND_HASH_TABLE_SIZE;
00398     }
00399     cc->compressed_hash_value = hv;
00400     return cc;
00401 }
00402 
00403 bool add_to_chunk_cond_set(chunk_cond_set * set, chunk_cond * new_cc)
00404 {
00405     chunk_cond *old;
00406 
00407     for (old = set->table[new_cc->compressed_hash_value]; old != NIL; old = old->next_in_bucket)
00408         if (old->hash_value == new_cc->hash_value)
00409             if (conditions_are_equal(old->cond, new_cc->cond))
00410                 break;
00411     if (old) {
00412         /* --- the new condition was already in the set; so don't add it --- */
00413         free_with_pool(&current_agent(chunk_cond_pool), new_cc);
00414         return FALSE;
00415     }
00416     /* --- add new_cc to the table --- */
00417     insert_at_head_of_dll(set->all, new_cc, next, prev);
00418     insert_at_head_of_dll(set->table[new_cc->compressed_hash_value], new_cc, next_in_bucket, prev_in_bucket);
00419     return TRUE;
00420 }
00421 
00422 void remove_from_chunk_cond_set(chunk_cond_set * set, chunk_cond * cc)
00423 {
00424     remove_from_dll(set->all, cc, next, prev);
00425     remove_from_dll(set->table[cc->compressed_hash_value], cc, next_in_bucket, prev_in_bucket);
00426 }
00427 
00428 /* ==================================================================== 
00429 
00430                  Other Miscellaneous Chunking Routines
00431 
00432 ==================================================================== */
00433 
00434 /* --------------------------------------------------------------------
00435             Build Chunk Conds For Grounds And Add Negateds
00436        
00437    This routine is called once backtracing is finished.  It goes through
00438    the ground conditions and builds a chunk_cond (see above) for each
00439    one.  The chunk_cond includes two new copies of the condition:  one
00440    to be used for the initial instantiation of the chunk, and one to
00441    be (variablized and) used for the chunk itself.
00442 
00443    This routine also goes through the negated conditions and adds to
00444    the ground set (again building chunk_cond's) any negated conditions
00445    that are connected to the grounds.
00446 
00447    At exit, the "dest_top" and "dest_bottom" arguments are set to point
00448    to the first and last chunk_cond in the ground set.  The "tc_to_use"
00449    argument is the tc number that this routine will use to mark the
00450    TC of the ground set.  At exit, this TC indicates the set of identifiers
00451    in the grounds.  (This is used immediately afterwards to figure out
00452    which Nots must be added to the chunk.)
00453 -------------------------------------------------------------------- */
00454 
00455 void build_chunk_conds_for_grounds_and_add_negateds(chunk_cond ** dest_top,
00456                                                     chunk_cond ** dest_bottom, tc_number tc_to_use)
00457 {
00458     cons *c;
00459     condition *ground;
00460     chunk_cond *cc, *first_cc, *prev_cc;
00461 
00462     first_cc = NIL;             /* unnecessary, but gcc -Wall warns without it */
00463 
00464     /* --- build instantiated conds for grounds and setup their TC --- */
00465     prev_cc = NIL;
00466     while (current_agent(grounds)) {
00467         c = current_agent(grounds);
00468         current_agent(grounds) = current_agent(grounds)->rest;
00469         ground = c->first;
00470         free_cons(c);
00471         /* --- make the instantiated condition --- */
00472         allocate_with_pool(&current_agent(chunk_cond_pool), &cc);
00473         cc->cond = ground;
00474         cc->instantiated_cond = copy_condition(cc->cond);
00475         cc->variablized_cond = copy_condition(cc->cond);
00476         if (prev_cc) {
00477             prev_cc->next = cc;
00478             cc->prev = prev_cc;
00479             cc->variablized_cond->prev = prev_cc->variablized_cond;
00480             prev_cc->variablized_cond->next = cc->variablized_cond;
00481         } else {
00482             first_cc = cc;
00483             cc->prev = NIL;
00484             cc->variablized_cond->prev = NIL;
00485         }
00486         prev_cc = cc;
00487         /* --- add this in to the TC --- */
00488         add_cond_to_tc(ground, tc_to_use, NIL, NIL);
00489     }
00490 
00491 #ifndef TRACE_CONTEXT_DECISIONS_ONLY
00492 
00493     /* --- scan through negated conditions and check which ones are connected
00494        to the grounds --- */
00495     if (current_agent(sysparams)[TRACE_BACKTRACING_SYSPARAM])
00496         print_string("\n\n*** Adding Grounded Negated Conditions ***\n");
00497 #endif
00498 
00499     while (current_agent(negated_set).all) {
00500         cc = current_agent(negated_set).all;
00501         remove_from_chunk_cond_set(&current_agent(negated_set), cc);
00502         if (cond_is_in_tc(cc->cond, tc_to_use)) {
00503 
00504 #ifndef TRACE_CONTEXT_DECISIONS_ONLY
00505             /* --- negated cond is in the TC, so add it to the grounds --- */
00506             if (current_agent(sysparams)[TRACE_BACKTRACING_SYSPARAM]) {
00507                 print_string("\n-->Moving to grounds: ");
00508                 print_condition(cc->cond);
00509             }
00510 #endif
00511 
00512             cc->instantiated_cond = copy_condition(cc->cond);
00513             cc->variablized_cond = copy_condition(cc->cond);
00514             if (prev_cc) {
00515                 prev_cc->next = cc;
00516                 cc->prev = prev_cc;
00517                 cc->variablized_cond->prev = prev_cc->variablized_cond;
00518                 prev_cc->variablized_cond->next = cc->variablized_cond;
00519             } else {
00520                 first_cc = cc;
00521                 cc->prev = NIL;
00522                 cc->variablized_cond->prev = NIL;
00523             }
00524             prev_cc = cc;
00525         } else {
00526             /* --- not in TC, so discard the condition --- */
00527             free_with_pool(&current_agent(chunk_cond_pool), cc);
00528         }
00529     }
00530 
00531     if (prev_cc) {
00532         prev_cc->next = NIL;
00533         prev_cc->variablized_cond->next = NIL;
00534     } else {
00535         first_cc = NIL;
00536     }
00537 
00538     *dest_top = first_cc;
00539     *dest_bottom = prev_cc;
00540 }
00541 
00542 /* --------------------------------------------------------------------
00543                   Get Nots For Instantiated Conditions
00544 
00545    This routine looks through all the Nots in the instantiations in
00546    instantiations_with_nots, and returns copies of the ones involving
00547    pairs of identifiers in the grounds.  Before this routine is called,
00548    the ids in the grounds must be marked with "tc_of_grounds."  
00549 -------------------------------------------------------------------- */
00550 
00551 not *get_nots_for_instantiated_conditions(list * instantiations_with_nots, tc_number tc_of_grounds)
00552 {
00553     cons *c;
00554     instantiation *inst;
00555     not *n1, *n2, *new_not, *collected_nots;
00556 
00557     /* --- collect nots for which both id's are marked --- */
00558     collected_nots = NIL;
00559     while (instantiations_with_nots) {
00560         c = instantiations_with_nots;
00561         instantiations_with_nots = c->rest;
00562         inst = c->first;
00563         free_cons(c);
00564         for (n1 = inst->nots; n1 != NIL; n1 = n1->next) {
00565             /* --- Are both id's marked? If no, goto next loop iteration --- */
00566             if (n1->s1->id.tc_num != tc_of_grounds)
00567                 continue;
00568             if (n1->s2->id.tc_num != tc_of_grounds)
00569                 continue;
00570             /* --- If the pair already in collected_nots, goto next iteration --- */
00571             for (n2 = collected_nots; n2 != NIL; n2 = n2->next) {
00572                 if ((n2->s1 == n1->s1) && (n2->s2 == n1->s2))
00573                     break;
00574                 if ((n2->s1 == n1->s2) && (n2->s2 == n1->s1))
00575                     break;
00576             }
00577             if (n2)
00578                 continue;
00579             /* --- Add the pair to collected_nots --- */
00580             allocate_with_pool(&current_agent(not_pool), &new_not);
00581             new_not->next = collected_nots;
00582             collected_nots = new_not;
00583             new_not->s1 = n1->s1;
00584             symbol_add_ref(new_not->s1);
00585             new_not->s2 = n1->s2;
00586             symbol_add_ref(new_not->s2);
00587         }                       /* end of for n1 */
00588     }                           /* end of while instantiations_with_nots */
00589 
00590     return collected_nots;
00591 }
00592 
00593 /* --------------------------------------------------------------------
00594               Variablize Nots And Insert Into Conditions
00595              
00596    This routine goes through the given list of Nots and, for each one,
00597    inserts a variablized copy of it into the given condition list at
00598    the earliest possible location.  (The given condition list should
00599    be the previously-variablized condition list that will become the
00600    chunk's LHS.)  The given condition list is destructively modified;
00601    the given Not list is unchanged.
00602 -------------------------------------------------------------------- */
00603 
00604 void variablize_nots_and_insert_into_conditions(not * nots, condition * conds)
00605 {
00606     not *n;
00607     Symbol *var1, *var2;
00608     test t;
00609     complex_test *ct;
00610     condition *c;
00611     bool added_it;
00612 
00613     /* --- don't bother Not-ifying justifications --- */
00614     if (!current_agent(variablize_this_chunk))
00615         return;
00616 
00617     for (n = nots; n != NIL; n = n->next) {
00618         var1 = n->s1->id.variablization;
00619         var2 = n->s2->id.variablization;
00620         /* --- find where var1 is bound, and add "<> var2" to that test --- */
00621         allocate_with_pool(&current_agent(complex_test_pool), &ct);
00622         t = make_test_from_complex_test(ct);
00623         ct->type = NOT_EQUAL_TEST;
00624         ct->data.referent = var2;
00625         symbol_add_ref(var2);
00626         added_it = FALSE;
00627         for (c = conds; c != NIL; c = c->next) {
00628             if (c->type != POSITIVE_CONDITION)
00629                 continue;
00630             if (test_includes_equality_test_for_symbol(c->data.tests.id_test, var1)) {
00631                 add_new_test_to_test(&(c->data.tests.id_test), t);
00632                 added_it = TRUE;
00633                 break;
00634             }
00635             if (test_includes_equality_test_for_symbol(c->data.tests.attr_test, var1)) {
00636                 add_new_test_to_test(&(c->data.tests.attr_test), t);
00637                 added_it = TRUE;
00638                 break;
00639             }
00640             if (test_includes_equality_test_for_symbol(c->data.tests.value_test, var1)) {
00641                 add_new_test_to_test(&(c->data.tests.value_test), t);
00642                 added_it = TRUE;
00643                 break;
00644             }
00645         }
00646         if (!added_it) {
00647             char msg[MESSAGE_SIZE];
00648             strncpy(msg, "chunk.c: Internal error: couldn't add Not test to chunk\n", MESSAGE_SIZE);
00649             msg[MESSAGE_SIZE - 1] = 0;
00650             abort_with_fatal_error(msg);
00651         }
00652     }                           /* end of for n=nots */
00653 }
00654 
00655 /* --------------------------------------------------------------------
00656                      Add Goal or Impasse Tests
00657 
00658    This routine adds goal id or impasse id tests to the variablized
00659    conditions.  For each id in the grounds that happens to be the
00660    identifier of a goal or impasse, we add a goal/impasse id test
00661    to the variablized conditions, to make sure that in the resulting
00662    chunk, the variablization of that id is constrained to match against
00663    a goal/impasse.  (Note:  actually, in the current implementation of
00664    chunking, it's impossible for an impasse id to end up in the ground
00665    set.  So part of this code is unnecessary.)
00666 -------------------------------------------------------------------- */
00667 
00668 void add_goal_or_impasse_tests(chunk_cond * all_ccs)
00669 {
00670     chunk_cond *cc;
00671     tc_number tc;               /* mark each id as we add a test for it, so we don't add
00672                                    a test for the same id in two different places */
00673     Symbol *id;
00674     test t;
00675     complex_test *ct;
00676 
00677     tc = get_new_tc_number();
00678     for (cc = all_ccs; cc != NIL; cc = cc->next) {
00679         if (cc->instantiated_cond->type != POSITIVE_CONDITION)
00680             continue;
00681         id = referent_of_equality_test(cc->instantiated_cond->data.tests.id_test);
00682         if ((id->id.isa_goal || id->id.isa_impasse) && (id->id.tc_num != tc)) {
00683             allocate_with_pool(&current_agent(complex_test_pool), &ct);
00684             ct->type = (char) ((id->id.isa_goal) ? GOAL_ID_TEST : IMPASSE_ID_TEST);
00685             t = make_test_from_complex_test(ct);
00686             add_new_test_to_test(&(cc->variablized_cond->data.tests.id_test), t);
00687             id->id.tc_num = tc;
00688         }
00689     }
00690 }
00691 
00692 /* --------------------------------------------------------------------
00693                     Reorder Instantiated Conditions
00694 
00695    The Rete routines require the instantiated conditions (on the
00696    instantiation structure) to be in the same order as the original
00697    conditions from which the Rete was built.  This means that the
00698    initial instantiation of the chunk must have its conditions in
00699    the same order as the variablized conditions.  The trouble is,
00700    the variablized conditions get rearranged by the reorderer.  So,
00701    after reordering, we have to rearrange the instantiated conditions
00702    to put them in the same order as the now-scrambled variablized ones.
00703    This routine does this.
00704 
00705    Okay, so the obvious way is to have each variablized condition (VCond)
00706    point to the corresponding instantiated condition (ICond).  Then after
00707    reordering the VConds, we'd scan through the VConds and say
00708       VCond->Icond->next = VCond->next->Icond
00709       VCond->Icond->prev = VCond->prev->Icond
00710    (with some extra checks for the first and last VCond in the list).
00711 
00712    The problem with this is that it takes an extra 4 bytes per condition,
00713    for the "ICond" field.  Conditions were taking up a lot of memory in
00714    my test cases, so I wanted to shrink them.  This routine avoids needing
00715    the 4 extra bytes by using the following trick:  first "swap out" 4
00716    bytes from each VCond; then use that 4 bytes for the "ICond" field.
00717    Now run the above algorithm.  Finally, swap those original 4 bytes
00718    back in.
00719 -------------------------------------------------------------------- */
00720 
00721 void reorder_instantiated_conditions(chunk_cond * top_cc, condition ** dest_inst_top, condition ** dest_inst_bottom)
00722 {
00723     chunk_cond *cc;
00724 
00725     /* --- Step 1:  swap prev pointers out of variablized conds into chunk_conds,
00726        and swap pointer to the corresponding instantiated conds into the
00727        variablized conds' prev pointers --- */
00728     for (cc = top_cc; cc != NIL; cc = cc->next) {
00729         cc->saved_prev_pointer_of_variablized_cond = cc->variablized_cond->prev;
00730         cc->variablized_cond->prev = cc->instantiated_cond;
00731     }
00732 
00733     /* --- Step 2:  do the reordering of the instantiated conds --- */
00734     for (cc = top_cc; cc != NIL; cc = cc->next) {
00735         if (cc->variablized_cond->next) {
00736             cc->instantiated_cond->next = cc->variablized_cond->next->prev;
00737         } else {
00738             cc->instantiated_cond->next = NIL;
00739             *dest_inst_bottom = cc->instantiated_cond;
00740         }
00741 
00742         if (cc->saved_prev_pointer_of_variablized_cond) {
00743             cc->instantiated_cond->prev = cc->saved_prev_pointer_of_variablized_cond->prev;
00744         } else {
00745             cc->instantiated_cond->prev = NIL;
00746             *dest_inst_top = cc->instantiated_cond;
00747         }
00748     }
00749 
00750     /* --- Step 3:  restore the prev pointers on variablized conds --- */
00751     for (cc = top_cc; cc != NIL; cc = cc->next) {
00752         cc->variablized_cond->prev = cc->saved_prev_pointer_of_variablized_cond;
00753     }
00754 }
00755 
00756 /* --------------------------------------------------------------------
00757                        Make Clones of Results
00758 
00759    When we build the initial instantiation of the new chunk, we have
00760    to fill in preferences_generated with *copies* of all the result
00761    preferences.  These copies are clones of the results.  This routine
00762    makes these clones and fills in chunk_inst->preferences_generated.
00763 -------------------------------------------------------------------- */
00764 
00765 void make_clones_of_results(preference * results, instantiation * chunk_inst)
00766 {
00767     preference *p, *result_p;
00768 
00769     chunk_inst->preferences_generated = NIL;
00770     for (result_p = results; result_p != NIL; result_p = result_p->next_result) {
00771         /* --- copy the preference --- */
00772         p = make_preference(result_p->type, result_p->id, result_p->attr, result_p->value, result_p->referent);
00773         symbol_add_ref(p->id);
00774         symbol_add_ref(p->attr);
00775         symbol_add_ref(p->value);
00776         if (preference_is_binary(p->type))
00777             symbol_add_ref(p->referent);
00778         /* --- put it onto the list for chunk_inst --- */
00779         p->inst = chunk_inst;
00780         insert_at_head_of_dll(chunk_inst->preferences_generated, p, inst_next, inst_prev);
00781         /* --- insert it into the list of clones for this preference --- */
00782         p->next_clone = result_p;
00783         p->prev_clone = result_p->prev_clone;
00784         result_p->prev_clone = p;
00785         if (p->prev_clone)
00786             p->prev_clone->next_clone = p;
00787     }
00788 }
00789 
00790 /* kjh (B14) begin */
00791 Symbol *find_goal_at_goal_stack_level(goal_stack_level level)
00792 {
00793     Symbol *g;
00794 
00795     for (g = current_agent(top_goal); g != NIL; g = g->id.lower_goal)
00796         if (g->id.level == level)
00797             return (g);
00798     return (NIL);
00799 }
00800 
00801 Symbol *find_impasse_wme_value(Symbol * id, Symbol * attr)
00802 {
00803     wme *w;
00804 
00805     for (w = id->id.impasse_wmes; w != NIL; w = w->next)
00806         if (w->attr == attr)
00807             return w->value;
00808     return NIL;
00809 }
00810 
00811 #define NAME_SIZE 512
00812 #define IMPASS_NAME_SIZE 32
00813 Symbol *generate_chunk_name_sym_constant(instantiation * inst)
00814 {
00815     char name[NAME_SIZE];
00816     char impass_name[IMPASS_NAME_SIZE];
00817     Symbol *generated_name;
00818     Symbol *goal;
00819     byte impasse_type;
00820     preference *p;
00821     goal_stack_level lowest_result_level;
00822 
00823     if (!current_agent(sysparams)[USE_LONG_CHUNK_NAMES])
00824         return (generate_new_sym_constant(current_agent(chunk_name_prefix), &current_agent(chunk_count)));
00825 
00826     lowest_result_level = current_agent(top_goal)->id.level;
00827     for (p = inst->preferences_generated; p != NIL; p = p->inst_next)
00828         if (p->id->id.level > lowest_result_level)
00829             lowest_result_level = p->id->id.level;
00830 
00831     goal = find_goal_at_goal_stack_level(lowest_result_level);
00832 
00833     if (goal) {
00834         impasse_type = type_of_existing_impasse(goal);
00835 
00836         /* Note that in this switch statement we set the impasse_name variable "safely" using strncpy.
00837            strncpy automatically null terminates the copy unless it was truncated.  To be safe, then,
00838            we always put a NULL character at the end of the array. In this case, we can do this after
00839            the if/else statements instead of right after every strncpy since the result of every
00840            strncpy gets funneled past there.
00841          */
00842         switch (impasse_type) {
00843         case NONE_IMPASSE_TYPE:
00844             print("Internal error: impasse_type is NONE_IMPASSE_TYPE during chunk creation.\n");
00845             strncpy(impass_name, "unknownimpasse", IMPASS_NAME_SIZE);
00846             break;
00847         case CONSTRAINT_FAILURE_IMPASSE_TYPE:
00848             strncpy(impass_name, "cfailure", IMPASS_NAME_SIZE);
00849             break;
00850         case CONFLICT_IMPASSE_TYPE:
00851             strncpy(impass_name, "conflict", IMPASS_NAME_SIZE);
00852             break;
00853         case TIE_IMPASSE_TYPE:
00854             strncpy(impass_name, "tie", IMPASS_NAME_SIZE);
00855             break;
00856         case NO_CHANGE_IMPASSE_TYPE:
00857             {
00858                 Symbol *sym;
00859 
00860                 if ((sym = find_impasse_wme_value(goal->id.lower_goal, current_agent(attribute_symbol))) == NIL) {
00861 #ifdef DEBUG_CHUNK_NAMES
00862                     print("Internal error: Failed to find ^attribute impasse wme.\n");
00863                     do_print_for_identifier(goal->id.lower_goal, 1, 0);
00864 #endif
00865                     strncpy(impass_name, "unknownimpasse", IMPASS_NAME_SIZE);
00866                 } else if (sym == current_agent(operator_symbol)) {
00867                     strncpy(impass_name, "opnochange", IMPASS_NAME_SIZE);
00868                 } else if (sym == current_agent(state_symbol)) {
00869                     strncpy(impass_name, "snochange", IMPASS_NAME_SIZE);
00870                 } else {
00871 #ifdef DEBUG_CHUNK_NAMES
00872                     print("Internal error: ^attribute impasse wme has unexpected value.\n");
00873 #endif
00874                     strncpy(impass_name, "unknownimpasse", IMPASS_NAME_SIZE);
00875                 }
00876             }
00877             break;
00878         default:
00879             print("Internal error: encountered unknown impasse_type: %d.\n", impasse_type);
00880             strncpy(impass_name, "unknownimpasse", IMPASS_NAME_SIZE);
00881             break;
00882         }
00883     } else {
00884         print("Internal error: Failed to determine impasse type.\n");
00885         strncpy(impass_name, "unknownimpasse", IMPASS_NAME_SIZE);
00886     }
00887     impass_name[IMPASS_NAME_SIZE - 1] = 0;
00888 
00889     snprintf(name, NAME_SIZE, "%s-%lu*d%lu*%s*%lu",
00890              current_agent(chunk_name_prefix),
00891              current_agent(chunk_count++), current_agent(d_cycle_count), impass_name, current_agent(chunks_this_d_cycle)
00892         );
00893     name[NAME_SIZE - 1] = 0;    /* snprintf doesn't set last char to null if output is truncated */
00894 
00895     /* Any user who named a production like this deserves to be burned, but we'll have mercy: */
00896     if (find_sym_constant(name)) {
00897         unsigned long collision_count;
00898 
00899         collision_count = 1;
00900         print("Warning: generated chunk name already exists.  Will find unique name.\n");
00901         do {
00902             snprintf(name, NAME_SIZE, "%s-%lu*d%lu*%s*%lu*%lu",
00903                      current_agent(chunk_name_prefix),
00904                      current_agent(chunk_count++),
00905                      current_agent(d_cycle_count), impass_name, current_agent(chunks_this_d_cycle), collision_count++);
00906             name[NAME_SIZE - 1] = 0;    /* snprintf doesn't set last char to null if output is truncated */
00907         } while (find_sym_constant(name));
00908     }
00909 
00910     generated_name = make_sym_constant(name);
00911     return generated_name;
00912 }
00913 
00914 /* kjh (B14) end */
00915 
00916 /* ====================================================================
00917 
00918                         Chunk Instantiation
00919 
00920    This the main chunking routine.  It takes an instantiation, and a
00921    flag "allow_variablization"--if FALSE, the chunk will not be
00922    variablized.  (If TRUE, it may still not be variablized, due to
00923    chunk-free-problem-spaces, ^quiescence t, etc.)
00924 ==================================================================== */
00925 
00926 void chunk_instantiation(instantiation * inst, bool allow_variablization)
00927 {
00928     goal_stack_level grounds_level;
00929     preference *results, *pref;
00930     instantiation *chunk_inst;
00931     Symbol *prod_name;
00932     byte prod_type;
00933     bool print_name, print_prod;
00934 
00935     condition *lhs_top, *lhs_bottom;
00936     not *nots;
00937     chunk_cond *top_cc, *bottom_cc;
00938     explain_chunk_str temp_explain_chunk;
00939 
00940 #if !defined(THIN_JUSTIFICATIONS) || defined(MAKE_PRODUCTION_FOR_THIN_JUSTS)
00941     production *prod;
00942     action *rhs;
00943 #endif
00944 
00945 #ifndef THIN_JUSTIFICATIONS
00946     byte rete_addition_result;
00947 #endif
00948 
00949 #if !defined(NO_TIMING_STUFF) && defined(DETAILED_TIMING_STATS)
00950     struct timeval saved_start_tv;
00951 #endif
00952 
00953     /* These two lines quell compiler warnings */
00954     temp_explain_chunk.conds = NULL;
00955     temp_explain_chunk.actions = NULL;
00956 
00957     /* --- if it only matched an attribute impasse, don't chunk --- */
00958     if (!inst->match_goal)
00959         return;
00960 
00961 #ifdef WATCH_PREFS_GENERATED
00962     print("\nPreferences Generated for instantiation at top of ci\n");
00963     print_instantiation_with_wmes(inst, TIMETAG_WME_TRACE);
00964     print("\n   Instantiation Match Goal Level = %d", inst->match_goal_level);
00965     print("\n---------------------------------------------\n");
00966     for (pref = inst->preferences_generated; pref != NIL; pref = pref->inst_next) {
00967         watchful_print_preference(pref);
00968         print("Reference count = %d\n", pref->reference_count);
00969     }
00970     print("\n");
00971 #endif
00972 
00973     /* --- if no preference is above the match goal level, exit --- */
00974     for (pref = inst->preferences_generated; pref != NIL; pref = pref->inst_next) {
00975         if (pref->id->id.level < inst->match_goal_level)
00976             break;
00977     }
00978     if (!pref)
00979         return;
00980 
00981 #ifndef NO_TIMING_STUFF
00982 #ifdef DETAILED_TIMING_STATS
00983     start_timer(&saved_start_tv);
00984 #endif
00985 #endif
00986 
00987 /* REW: begin 09.15.96 */
00988 
00989     /*
00990 
00991        in OPERAND, we only wanna built a chunk for the top goal; i.e. no
00992        intermediate chunks are build.  we're essentially creating
00993        "top-down chunking"; just the opposite of the "bottom-up chunking"
00994        that is available through a soar prompt-level comand.
00995 
00996        (why do we do this??  i don't remember...)
00997 
00998        we accomplish this by forcing only justifications to be built for
00999        subgoal chunks.  and when we're about to build the top level
01000        result, we make a chunk.  a cheat, but it appears to work.  of
01001        course, this only kicks in if learning is turned on.
01002 
01003        i get the behavior i want by twiddling the allow_variablization
01004        flag.  i set it to FALSE for intermediate results.  then for the
01005        last (top-most) result, i set it to whatever it was when the
01006        function was called.
01007 
01008        by the way, i need the lower level justificiations because they
01009        support the upper level justifications; i.e. a justification at
01010        level i supports the justification at level i-1.  i'm talkin' outa
01011        my butt here since i don't know that for a fact.  it's just that
01012        i tried building only the top level chunk and ignored the
01013        intermediate justifications and the system complained.  my
01014        explanation seemed reasonable, at the moment.
01015 
01016      */
01017 
01018 #ifndef DONT_ALLOW_VARIABLIZATION
01019 
01020 #ifndef SOAR_8_ONLY
01021     if (current_agent(operand2_mode) == TRUE) {
01022 #endif
01023 
01024         if (current_agent(sysparams)[LEARNING_ON_SYSPARAM] == TRUE) {
01025             if (pref->id->id.level < (inst->match_goal_level - 1)) {
01026                 allow_variablization = FALSE;
01027                 inst->okay_to_variablize = FALSE;
01028 
01029                 if (current_agent(soar_verbose_flag) == TRUE)
01030                     print("\n   in chunk_instantiation: making justification only");
01031             }
01032 
01033             else {
01034                 allow_variablization = (bool) current_agent(sysparams)[LEARNING_ON_SYSPARAM];
01035                 inst->okay_to_variablize = (byte) current_agent(sysparams)[LEARNING_ON_SYSPARAM];
01036 
01037                 if (current_agent(soar_verbose_flag) == TRUE)
01038                     print("\n   in chunk_instantiation: resetting allow_variablization to %s",
01039                           ((allow_variablization) ? "TRUE" : "FALSE"));
01040             }
01041         }
01042 
01043 #ifndef SOAR_8_ONLY
01044     }
01045 #endif
01046 
01047 #else                           /* DONT_ALLOW_VARIABLIZATION */
01048 
01049     inst->okay_to_variablize = FALSE;
01050 
01051 #endif                          /* DONT_ALLOW_VARIABLIZATION */
01052 
01053 /* REW: end   09.15.96 */
01054 
01055     results = get_results_for_instantiation(inst);
01056 
01057     if (!results)
01058         goto chunking_done;
01059 
01060 #ifdef OPTIMIZE_TOP_LEVEL_RESULTS
01061     {
01062         preference *the_temp_pref;
01063         bool optimize = TRUE;
01064         Symbol *top_level_goal = NIL;
01065 
01066         for (the_temp_pref = inst->preferences_generated; the_temp_pref != NIL;
01067              the_temp_pref = the_temp_pref->inst_next) {
01068             if (the_temp_pref->id->id.level != 1) {
01069                 optimize = FALSE;
01070             } else if (!top_level_goal && the_temp_pref->id->id.isa_goal) {
01071                 top_level_goal = the_temp_pref->id;
01072             }
01073 
01074         }
01075 
01076         if (optimize) {
01077 
01078             /*
01079                print( "Optimizing this result.\n" );
01080                printf( "Optimizing this result.\n" );
01081              */
01082 
01083             allocate_with_pool(&current_agent(instantiation_pool), &chunk_inst);
01084             chunk_inst->prod = NIL;
01085             chunk_inst->top_of_instantiated_conditions = NIL;
01086             chunk_inst->bottom_of_instantiated_conditions = NIL;
01087             chunk_inst->nots = NIL;
01088             chunk_inst->GDS_evaluated_already = FALSE;
01089             chunk_inst->okay_to_variablize = FALSE;
01090 
01091             make_clones_of_results(results, chunk_inst);
01092             fill_in_new_instantiation_stuff(chunk_inst, FALSE);
01093 
01094             for (the_temp_pref = chunk_inst->preferences_generated;
01095                  the_temp_pref != NIL; the_temp_pref = the_temp_pref->inst_next) {
01096                 /*
01097                    if ( the_temp_pref->o_supported == FALSE ) {
01098                    printf( "Warning: Optimizing a result with I-supported results.\n" );
01099                    }
01100                  */
01101                 the_temp_pref->o_supported = TRUE;
01102                 the_temp_pref->match_goal_level = 1;
01103                 the_temp_pref->match_goal = top_level_goal;
01104 
01105             }
01106             /*
01107                printf( "Inst = %p\n", inst );
01108                printf( "Setting Chunk_inst (%p) match goal to 1\n", chunk_inst );
01109              */
01110             chunk_inst->match_goal = top_level_goal;
01111             chunk_inst->match_goal_level = 1;
01112             chunk_inst->in_ms = TRUE;
01113             chunk_inst->next = current_agent(newly_created_instantiations);
01114             current_agent(newly_created_instantiations) = chunk_inst;
01115 
01116             goto chunking_done;
01117 
01118         }
01119     }
01120 #endif
01121 
01122 #ifdef WATCH_RESULTS
01123     {
01124         preference *the_temp_pref;
01125 
01126         print("\nResults for instantiaition:\n");
01127         print_instantiation_with_wmes(inst, TIMETAG_WME_TRACE);
01128         print("\n---------------------------\n");
01129         for (the_temp_pref = results; the_temp_pref != NIL; the_temp_pref = the_temp_pref->next_result) {
01130             watchful_print_preference(the_temp_pref);
01131             print("References for id at top of chunk_inst = %d\n", the_temp_pref->id->common.reference_count);
01132 
01133         }
01134         print("\n");
01135     }
01136 #endif
01137 
01138 #ifdef WATCH_INST_CONDS
01139     print_with_symbols("\nIn chunk_instantiation.\nInst which will be chunked is: %y -- conditions:\n",
01140                        inst->prod->name);
01141     print("Address %p\n", inst);
01142     print_condition_list(inst->top_of_instantiated_conditions, 2, TRUE);
01143     if (inst->top_of_instantiated_conditions == NIL) {
01144         print("There are no pointers here...\n");
01145     }
01146 #endif
01147 
01148     /* --- update flags on goal stack for bottom-up chunking --- */
01149     {
01150         Symbol *g;
01151         for (g = inst->match_goal->id.higher_goal; g && g->id.allow_bottom_up_chunks; g = g->id.higher_goal)
01152             g->id.allow_bottom_up_chunks = FALSE;
01153     }
01154 
01155     grounds_level = (short) (inst->match_goal_level - 1);
01156 
01157     current_agent(backtrace_number)++;
01158     if (current_agent(backtrace_number) == 0)
01159         current_agent(backtrace_number) = 1;
01160     current_agent(grounds_tc)++;
01161     if (current_agent(grounds_tc) == 0)
01162         current_agent(grounds_tc) = 1;
01163     current_agent(potentials_tc)++;
01164     if (current_agent(potentials_tc) == 0)
01165         current_agent(potentials_tc) = 1;
01166     current_agent(locals_tc)++;
01167     if (current_agent(locals_tc) == 0)
01168         current_agent(locals_tc) = 1;
01169     current_agent(grounds) = NIL;
01170     current_agent(positive_potentials) = NIL;
01171     current_agent(locals) = NIL;
01172     current_agent(instantiations_with_nots) = NIL;
01173 
01174 #ifndef DONT_ALLOW_VARIABLIZATION
01175 
01176     if (allow_variablization && (!current_agent(sysparams)[LEARNING_ALL_GOALS_SYSPARAM]))
01177         allow_variablization = inst->match_goal->id.allow_bottom_up_chunks;
01178 
01179 #endif                          /* DONT_ALLOW_VARIABLIZATION */
01180 
01181     /* DJP : Need to initialize chunk_free_flag to be FALSE, as default before
01182        looking for problem spaces and setting the chunk_free_flag below  */
01183 
01184     current_agent(chunk_free_flag) = FALSE;
01185     /* DJP : Noticed this also isn't set if no ps_name */
01186     current_agent(chunky_flag) = FALSE;
01187 
01188 #ifndef DONT_ALLOW_VARIABLIZATION
01189 
01190     /* --- check whether ps name is in chunk_free_problem_spaces --- */
01191     if (allow_variablization) {
01192 
01193         /* KJC new implementation of learn cmd:  old SPECIFY ==> ONLY,
01194          * old ON ==> EXCEPT,  now ON is just ON always
01195          * checking if state is chunky or chunk-free...
01196          */
01197         if (current_agent(sysparams)[LEARNING_EXCEPT_SYSPARAM]) {
01198             if (member_of_list(inst->match_goal, current_agent(chunk_free_problem_spaces))) {
01199                 allow_variablization = FALSE;
01200                 current_agent(chunk_free_flag) = TRUE;
01201             }
01202         } else if (current_agent(sysparams)[LEARNING_ONLY_SYSPARAM]) {
01203             if (member_of_list(inst->match_goal, current_agent(chunky_problem_spaces))) {
01204                 allow_variablization = TRUE;
01205                 current_agent(chunky_flag) = TRUE;
01206             } else {
01207                 allow_variablization = FALSE;
01208                 current_agent(chunky_flag) = FALSE;
01209             }
01210         }
01211     }
01212     /* end KJC mods */
01213     current_agent(variablize_this_chunk) = allow_variablization;
01214 
01215 #else                           /* DONT_ALLOW_VARIABLIZATION */
01216 
01217     current_agent(variablize_this_chunk) = FALSE;
01218 #endif                          /* DONT_ALLOW_VARIABLIZATION */
01219 
01220 #ifndef THIN_JUSTIFICATIONS
01221 
01222     /* Start a new structure for this potential chunk */
01223 
01224     if (current_agent(sysparams)[EXPLAIN_SYSPARAM]) {
01225         temp_explain_chunk.conds = NULL;
01226         temp_explain_chunk.actions = NULL;
01227         temp_explain_chunk.backtrace = NULL;
01228         temp_explain_chunk.name[0] = '\0';
01229         temp_explain_chunk.all_grounds = NIL;
01230         temp_explain_chunk.next_chunk = NULL;
01231         reset_backtrace_list();
01232     }
01233 #endif                          /* !THIN_JUSTIFICATIONS */
01234 
01235 #ifndef NO_BACKTRACING
01236 #ifndef DONT_CALC_GDS_OR_BT
01237 
01238     /* --- backtrace through the instantiation that produced each result --- */
01239     for (pref = results; pref != NIL; pref = pref->next_result) {
01240 
01241 #ifndef TRACE_CONTEXT_DECISIONS_ONLY
01242         if (current_agent(sysparams)[TRACE_BACKTRACING_SYSPARAM]) {
01243             print_string("\nFor result preference ");
01244             print_preference(pref);
01245             print_string(" ");
01246         }
01247 #endif
01248 
01249 #ifdef NO_TOP_JUST
01250         if (pref->inst)
01251             backtrace_through_instantiation(pref->inst, grounds_level, NULL, 0);
01252 
01253 #else
01254         backtrace_through_instantiation(pref->inst, grounds_level, NULL, 0);
01255 
01256 #endif
01257 
01258     }
01259 
01260 #else
01261     add_named_superstate_attribute_to_grounds(inst, "superstate");
01262 #endif
01263 
01264 #endif                          /* NO_BACKTRACING */
01265 
01266     current_agent(quiescence_t_flag) = FALSE;
01267 
01268     for (;;) {
01269         trace_locals(grounds_level);
01270         trace_grounded_potentials();
01271         if (!trace_ungrounded_potentials(grounds_level))
01272             break;
01273     }
01274     free_list(current_agent(positive_potentials));
01275 
01276     /* --- backtracing done; collect the grounds into the chunk --- */
01277     {
01278         tc_number tc_for_grounds;
01279         tc_for_grounds = get_new_tc_number();
01280         build_chunk_conds_for_grounds_and_add_negateds(&top_cc, &bottom_cc, tc_for_grounds);
01281         nots = get_nots_for_instantiated_conditions(current_agent(instantiations_with_nots), tc_for_grounds);
01282     }
01283 
01284     /* --- get symbol for name of new chunk or justification --- */
01285 
01286 #ifndef DONT_ALLOW_VARIABLIZATION
01287 
01288     if (current_agent(variablize_this_chunk)) {
01289         /* kjh (B14) begin */
01290         current_agent(chunks_this_d_cycle)++;
01291         prod_name = generate_chunk_name_sym_constant(inst);
01292         /* kjh (B14) end */
01293 
01294         prod_type = CHUNK_PRODUCTION_TYPE;
01295         print_name = (bool) current_agent(sysparams)[TRACE_CHUNK_NAMES_SYSPARAM];
01296         print_prod = (bool) current_agent(sysparams)[TRACE_CHUNKS_SYSPARAM];
01297 
01298     } else {
01299 
01300 #endif                          /* DONT_ALLOW_VARIABLIZATION */
01301 
01302 #ifdef THIN_JUSTIFICATIONS
01303         prod_name = generate_new_sym_constant("temp-justification-", &current_agent(justification_count));
01304 #else
01305         prod_name = generate_new_sym_constant("justification-", &current_agent(justification_count));
01306 #endif                          /* THIN_JUSTIFICATIONS */
01307 
01308         prod_type = JUSTIFICATION_PRODUCTION_TYPE;
01309         print_name = (bool) current_agent(sysparams)[TRACE_JUSTIFICATION_NAMES_SYSPARAM];
01310         print_prod = (bool) current_agent(sysparams)[TRACE_JUSTIFICATIONS_SYSPARAM];
01311 
01312 #ifndef DONT_ALLOW_VARIABLIZATION
01313     }
01314 #endif                          /* DONT_ALLOW_VARIABLIZATION */
01315 
01316     /* AGR 617/634 begin */
01317     if (print_name) {
01318         if (get_printer_output_column() != 1)
01319             print("\n");
01320         print_with_symbols("Building %y", prod_name);
01321 
01322 #if defined(THIN_JUSTIFICATIONS) && !defined(MAKE_PRODUCTION_FOR_THIN_JUSTS)
01323         print("...thin justification, no prod");
01324 #endif
01325 
01326     }
01327     /* AGR 617/634 end */
01328 
01329     /* --- if there aren't any grounds, exit --- */
01330     if (!top_cc) {
01331         if (current_agent(sysparams)[PRINT_WARNINGS_SYSPARAM])
01332             print_string(" Warning: chunk has no grounds, ignoring it.");
01333         goto chunking_done;
01334     }
01335 #ifndef DONT_ALLOW_VARIABLIZATION
01336 
01337     /* MVP 6-8-94 */
01338     if (current_agent(chunks_this_d_cycle) > (unsigned long) current_agent(sysparams)[MAX_CHUNKS_SYSPARAM]) {
01339         if (current_agent(sysparams)[PRINT_WARNINGS_SYSPARAM])
01340             print("\nWarning: reached max-chunks! Halting system.");
01341         current_agent(max_chunks_reached) = TRUE;
01342         goto chunking_done;
01343     }
01344 #endif                          /* DONT_ALLOW_VARIABLIZATION */
01345 
01346     /* --- variablize it --- */
01347     lhs_top = top_cc->variablized_cond;
01348     lhs_bottom = bottom_cc->variablized_cond;
01349     reset_variable_generator(lhs_top, NIL);
01350     current_agent(variablization_tc) = get_new_tc_number();
01351     variablize_condition_list(lhs_top);
01352     variablize_nots_and_insert_into_conditions(nots, lhs_top);
01353 #if !defined(THIN_JUSTIFICATIONS) || defined(MAKE_PRODUCTION_FOR_THIN_JUSTS)
01354     rhs = copy_and_variablize_result_list(results);
01355 #endif
01356 
01357     /* --- add goal/impasse tests to it --- */
01358     add_goal_or_impasse_tests(top_cc);
01359 
01360     /* --- reorder lhs and make the production --- */
01361 #if !defined(THIN_JUSTIFICATIONS) || defined(MAKE_PRODUCTION_FOR_THIN_JUSTS)
01362 
01363     prod = make_production(prod_type, prod_name, &lhs_top, &lhs_bottom, &rhs, FALSE);
01364 
01365     if (!prod) {
01366         print("\nUnable to reorder this chunk:\n  ");
01367         print_condition_list(lhs_top, 2, FALSE);
01368         print("\n  -->\n   ");
01369         print_action_list(rhs, 3, FALSE);
01370         print("\n\n(Ignoring this chunk.  Weird things could happen from now on...)\n");
01371         goto chunking_done;     /* this leaks memory but who cares */
01372     }
01373 #endif                          /* !THIN_JUSTIFICATIONS || MAKE_PRODUCTION_FOR_THIN_JUSTS */
01374 
01375     {
01376         condition *inst_lhs_top, *inst_lhs_bottom;
01377 
01378         reorder_instantiated_conditions(top_cc, &inst_lhs_top, &inst_lhs_bottom);
01379 
01380         /* Record the list of grounds in the order they will appear in the chunk */
01381         if (current_agent(sysparams)[EXPLAIN_SYSPARAM])
01382             temp_explain_chunk.all_grounds = inst_lhs_top;      /* Not a copy yet */
01383 
01384         allocate_with_pool(&current_agent(instantiation_pool), &chunk_inst);
01385 
01386 #if !defined(THIN_JUSTIFICATIONS) || defined(MAKE_PRODUCTION_FOR_THIN_JUSTS)
01387         chunk_inst->prod = prod;
01388 #else
01389         chunk_inst->prod = NIL;
01390 #endif                          /* !THIN_JUSTIFICATIONS || MAKE_PRODUCTION_FOR_THIN_JUSTS */
01391 
01392         chunk_inst->top_of_instantiated_conditions = inst_lhs_top;
01393 
01394 #ifdef WATCH_SSCI_CONDS
01395 
01396         print("\nCreating temp-justification: ");
01397 
01398         if (chunk_inst->prod)
01399             print_with_symbols("%y...conditions:\n", chunk_inst->prod->name);
01400         else
01401             print("(nil) ... conditions:\n");
01402 
01403         print("Address %p\n", chunk_inst);
01404         print_condition_list(chunk_inst->top_of_instantiated_conditions, 2, TRUE);
01405         if (chunk_inst->top_of_instantiated_conditions == NIL) {
01406             print("There are no pointers here...\n");
01407         }
01408 #endif
01409 
01410         chunk_inst->bottom_of_instantiated_conditions = inst_lhs_bottom;
01411         chunk_inst->nots = nots;
01412         chunk_inst->GDS_evaluated_already = FALSE;      /* REW:  09.15.96 */
01413 
01414         /* If:
01415            - you don't want to variablize this chunk, and
01416            - the reason is ONLY that it's chunk free, and
01417            - NOT that it's also quiescence, then
01418            it's okay to variablize through this instantiation later.
01419          */
01420 
01421         /* AGR MVL1 begin */
01422         if (!current_agent(sysparams)[LEARNING_ONLY_SYSPARAM]) {
01423             if ((!current_agent(variablize_this_chunk))
01424                 && (current_agent(chunk_free_flag))
01425                 && (!current_agent(quiescence_t_flag)))
01426                 chunk_inst->okay_to_variablize = TRUE;
01427             else
01428                 chunk_inst->okay_to_variablize = current_agent(variablize_this_chunk);
01429         } else {
01430             if ((!current_agent(variablize_this_chunk))
01431                 && (!current_agent(chunky_flag))
01432                 && (!current_agent(quiescence_t_flag)))
01433                 chunk_inst->okay_to_variablize = TRUE;
01434             else
01435                 chunk_inst->okay_to_variablize = current_agent(variablize_this_chunk);
01436         }
01437         /* AGR MVL1 end */
01438 
01439         chunk_inst->in_ms = TRUE;       /* set TRUE for now, we'll find out later... */
01440 
01441         /* Increments symbol reference counts */
01442         make_clones_of_results(results, chunk_inst);
01443 
01444         fill_in_new_instantiation_stuff(chunk_inst, TRUE);
01445 
01446     }                           /* matches { condition *inst_lhs_top, *inst_lhs_bottom ...  */
01447 
01448 #ifdef WARN_IF_RESULT_IS_I_SUPPORTED
01449     /* 
01450      * SW 110499
01451      *
01452      * When we use the Soar-lite feature of not adding justifications
01453      * to the rete, we bump up against a potential problem:
01454      * Without a production in the rete, there is no way to know
01455      * when an instantiation should be retracted (I think!).  As a result,
01456      * we can end up with a huge memory leak.  We get around this by assuming
01457      * that subgoal results are o-supported.  If this is the case, we
01458      * can safely remove the instantiations once the preferences have been
01459      * asserted.  However, this could influence the way certain Soar programs 
01460      * run.  As a result, it may or may not be desireable to actually force
01461      * subgoal results to be o-supported without telling anyone...
01462      */
01463 
01464     for (pref = chunk_inst->preferences_generated; pref != NIL; pref = pref->inst_next) {
01465         if (pref->o_supported == FALSE) {
01466             print("Warning: Result is not natively o-supported. ");
01467 #ifdef THIN_JUSTIFICATIONS
01468 #ifdef ALLOW_I_SUPPORTED_SUBGOAL_RESULTS_WITH_THIN_JUSTS
01469             print("This may produce memory leaks.\n");
01470 #else
01471             print("O-support will be forced.\n");
01472 #endif
01473 #endif                          /* THIN_JUSTIFICATIONS */
01474 
01475             watchful_print_preference(pref);
01476         }
01477     }
01478 #endif                          /* WARN_IF_RESULT_IS_I_SUPPORTED */
01479 
01480 #if defined(DONT_CALC_GDS_OR_BT) || (defined(THIN_JUSTIFICATIONS) && !defined(ALLOW_I_SUPPORTED_SUBGOAL_RESULTS_WITH_THIN_JUSTS))
01481 
01482     /* DJP Now force all results to be o-supported */
01483     /* Have to wait till the clone preferences are created */
01484     for (pref = chunk_inst->preferences_generated; pref != NIL; pref = pref->inst_next)
01485 
01486         pref->o_supported = TRUE;       /* These preferences are all results */
01487 
01488 #endif
01489 
01490 #ifndef THIN_JUSTIFICATIONS
01491 
01492     /* RBD 4/6/95 Need to copy cond's and actions for the production here,
01493        otherwise some of the variables might get deallocated by the call to
01494        add_production_to_rete() when it throws away chunk variable names. */
01495     if (current_agent(sysparams)[EXPLAIN_SYSPARAM]) {
01496         condition *new_top, *new_bottom;
01497         copy_condition_list(lhs_top, &new_top, &new_bottom);
01498         temp_explain_chunk.conds = new_top;
01499         temp_explain_chunk.actions = copy_and_variablize_result_list(results);
01500     }
01501 
01502     rete_addition_result = add_production_to_rete(prod, lhs_top, chunk_inst, print_name);
01503 
01504 #ifdef WATCH_CHUNK_INST
01505     if (rete_addition_result == REFRACTED_INST_MATCHED)
01506         print("\nAdded chunk/justification to rete -- result: MATCHED\n");
01507     else if (rete_addition_result == REFRACTED_INST_DID_NOT_MATCH)
01508         print("\nAdded chunk/justification to rete -- result: DID NOT MATCH\n");
01509     else
01510         print("\nAdded chunk/justification to rete -- result: DUPLICATE\n");
01511 #endif
01512 
01513     /* If didn't immediately excise the chunk from the rete net   
01514        then record the temporary structure in the list of explained chunks. */
01515 
01516     if (current_agent(sysparams)[EXPLAIN_SYSPARAM]) {
01517         if ((rete_addition_result != DUPLICATE_PRODUCTION) &&
01518             ((prod_type != JUSTIFICATION_PRODUCTION_TYPE) || (rete_addition_result != REFRACTED_INST_DID_NOT_MATCH))) {
01519             strncpy(temp_explain_chunk.name, prod_name->sc.name, PROD_NAME_SIZE);
01520             temp_explain_chunk.name[PROD_NAME_SIZE - 1] = 0;
01521             explain_add_temp_to_chunk_list(&temp_explain_chunk);
01522         } else {
01523             /* RBD 4/6/95 if excised the chunk, discard previously-copied stuff */
01524             deallocate_condition_list(temp_explain_chunk.conds);
01525             deallocate_action_list(temp_explain_chunk.actions);
01526         }
01527     }
01528     /* --- deallocate chunks conds and variablized conditions --- */
01529     deallocate_condition_list(lhs_top);
01530     {
01531         chunk_cond *cc;
01532         while (top_cc) {
01533             cc = top_cc;
01534             top_cc = cc->next;
01535             free_with_pool(&current_agent(chunk_cond_pool), cc);
01536         }
01537     }
01538 
01539     if (print_prod && (rete_addition_result != DUPLICATE_PRODUCTION)) {
01540         print_string("\n");
01541         print_production(prod, FALSE);
01542     }
01543 
01544     if (rete_addition_result == DUPLICATE_PRODUCTION) {
01545         excise_production(prod, FALSE);
01546     } else if ((prod_type == JUSTIFICATION_PRODUCTION_TYPE) && (rete_addition_result == REFRACTED_INST_DID_NOT_MATCH)) {
01547         excise_production(prod, FALSE);
01548     }
01549 
01550     if (rete_addition_result != REFRACTED_INST_MATCHED) {
01551         /* --- it didn't match, or it was a duplicate production --- */
01552         /* --- tell the firer it didn't match, so it'll only assert the
01553            o-supported preferences --- */
01554         chunk_inst->in_ms = FALSE;
01555     }
01556 #else                           /* THIN_JUSTIFICATIONS */
01557 
01558     /* I think this will take care of the 102099 Memory Leak */
01559     /* --- deallocate chunks conds and variablized conditions --- */
01560     deallocate_condition_list(lhs_top);
01561 #ifdef DONT_CALC_GDS_OR_BT
01562     /* SW NOTE See the note in add_named_superstate_attribute_to_grounds */
01563     deallocate_condition_list(top_cc->cond);
01564 #endif
01565     {
01566         chunk_cond *cc;
01567         while (top_cc) {
01568             cc = top_cc;
01569             top_cc = cc->next;
01570             free_with_pool(&current_agent(chunk_cond_pool), cc);
01571         }
01572     }
01573 
01574     if (print_prod) {
01575         print_string("\n -- Justification (not added to rete) -- \n");
01576         {
01577             preference *the_temp_pref;
01578 
01579             print("\nResults for instantiaition:\n");
01580             print_instantiation_with_wmes(chunk_inst, FULL_WME_TRACE);
01581             print("\n---------------------------\n");
01582             for (the_temp_pref = chunk_inst->preferences_generated;
01583                  the_temp_pref != NIL; the_temp_pref = the_temp_pref->inst_next) {
01584                 watchful_print_preference(the_temp_pref);
01585             }
01586             print("\n");
01587         }
01588 
01589     }
01590 #endif                          /* !THIN_JUSTIFICATIONS */
01591 
01592     /* SW 090799 These two lines of code are necessary for the GDS... */
01593     /* --- assert the preferences --- */
01594     chunk_inst->next = current_agent(newly_created_instantiations);
01595     current_agent(newly_created_instantiations) = chunk_inst;
01596 
01597     /* MVP 6-8-94 */
01598     if (!current_agent(max_chunks_reached))
01599 #ifndef THIN_JUSTIFICATIONS
01600         chunk_instantiation(chunk_inst, current_agent(variablize_this_chunk));
01601 
01602 #else                           /* THIN_JUSTIFICATIONS */
01603 
01604         if (chunk_inst->isa_ssci_inst != TRUE) {
01605             chunk_inst->isa_ssci_inst = TRUE;
01606         }
01607 #ifdef WATCH_SSCI_INSTS
01608 
01609     print("\nCreating an SSCI instantiation: ");
01610     if (chunk_inst->prod)
01611         print_with_symbols("%y\n", chunk_inst->prod->name);
01612     else
01613         print("(nil)\n");
01614 
01615 #endif                          /* WATCH_SSCI_INSTS */
01616 
01617 #ifdef SINGLE_THIN_JUSTIFICATION
01618     second_stage_chunk_instantiation(chunk_inst);
01619 
01620 #else                           /* !SINGLE_THIN_JUSTIFICATION --> THIN_JUSTIFICATIONS */
01621 
01622     /*
01623      * 102699 
01624      * we can use a recursive call to chunk_inst as opposed to ssci
01625      * to avoid the tr.soar memory leak.  Today, I will try to fix 
01626      * ssci
01627      */
01628     chunk_instantiation(chunk_inst, FALSE);
01629 
01630 #endif                          /* SINGLE_THIN_JUSTIFICATION */
01631 
01632 #endif                          /* !THIN_JUSTIFICATION */
01633 
01634 #ifndef NO_TIMING_STUFF
01635 #ifdef DETAILED_TIMING_STATS
01636     stop_timer(&saved_start_tv, &current_agent(chunking_cpu_time[current_agent(current_phase)]));
01637 #endif
01638 #endif
01639 
01640     return;
01641 
01642   chunking_done:{
01643     }
01644 
01645 #ifndef NO_TIMING_STUFF
01646 #ifdef DETAILED_TIMING_STATS
01647     stop_timer(&saved_start_tv, &current_agent(chunking_cpu_time[current_agent(current_phase)]));
01648 #endif
01649 #endif
01650 
01651 }
01652 
01653 #ifdef SINGLE_THIN_JUSTIFICATION
01654 
01655 void second_stage_chunk_instantiation(instantiation * inst)
01656 {
01657     goal_stack_level grounds_level;
01658     preference *results, *pref;
01659     bool print_name, print_prod;
01660     condition *lhs_top, *lhs_bottom;
01661     not *nots;
01662     chunk_cond *top_cc, *bottom_cc;
01663 
01664     /* --- if it only matched an attribute impasse, don't chunk --- */
01665     if (!inst->match_goal)
01666         return;
01667 
01668 #ifdef WATCH_PREFS_GENERATED
01669     print("\nPreferences Generated for instantiation at top of sscii\n");
01670     print_instantiation_with_wmes(inst, TIMETAG_WME_TRACE);
01671     print("\n   Instantiation Match Goal Level = %d", inst->match_goal_level);
01672     print("\n---------------------------------------------\n");
01673     for (pref = inst->preferences_generated; pref != NIL; pref = pref->inst_next) {
01674         watchful_print_preference(pref);
01675         print("Reference count = %d\n", pref->reference_count);
01676     }
01677     print("\n");
01678 #endif
01679 
01680     /* --- if no preference is above the match goal level, exit --- */
01681     for (pref = inst->preferences_generated; pref != NIL; pref = pref->inst_next) {
01682         if (pref->id->id.level < inst->match_goal_level)
01683             break;
01684     }
01685     if (!pref)
01686         return;
01687     inst->okay_to_variablize = FALSE;
01688 
01689     results = get_results_for_instantiation(inst);
01690 
01691 #ifdef WATCH_RESULTS
01692     {
01693         preference *the_temp_pref;
01694 
01695         print("\nResults for instantiaition:\n");
01696         print_instantiation_with_wmes(inst, TIMETAG_WME_TRACE);
01697         print("\n---------------------------\n");
01698         for (the_temp_pref = results; the_temp_pref != NIL; the_temp_pref = the_temp_pref->next_result) {
01699             watchful_print_preference(the_temp_pref);
01700 
01701         }
01702         print("\n");
01703     }
01704 #endif
01705 
01706     if (!results)
01707         goto chunking_done;
01708 
01709     /* --- update flags on goal stack for bottom-up chunking --- */
01710     {
01711         Symbol *g;
01712         for (g = inst->match_goal->id.higher_goal; g && g->id.allow_bottom_up_chunks; g = g->id.higher_goal)
01713             g->id.allow_bottom_up_chunks = FALSE;
01714     }
01715 
01716     grounds_level = inst->match_goal_level - 1;
01717 
01718     current_agent(backtrace_number)++;
01719     if (current_agent(backtrace_number) == 0)
01720         current_agent(backtrace_number) = 1;
01721     current_agent(grounds_tc)++;
01722     if (current_agent(grounds_tc) == 0)
01723         current_agent(grounds_tc) = 1;
01724     current_agent(potentials_tc)++;
01725     if (current_agent(potentials_tc) == 0)
01726         current_agent(potentials_tc) = 1;
01727     current_agent(locals_tc)++;
01728     if (current_agent(locals_tc) == 0)
01729         current_agent(locals_tc) = 1;
01730     current_agent(grounds) = NIL;
01731     current_agent(positive_potentials) = NIL;
01732     current_agent(locals) = NIL;
01733     current_agent(instantiations_with_nots) = NIL;
01734 
01735     /* DJP : Need to initialize chunk_free_flag to be FALSE, as default before
01736        looking for problem spaces and setting the chunk_free_flag below  */
01737 
01738     current_agent(chunk_free_flag) = FALSE;
01739     /* DJP : Noticed this also isn't set if no ps_name */
01740     current_agent(chunky_flag) = FALSE;
01741 
01742     current_agent(variablize_this_chunk) = FALSE;
01743 
01744 #ifndef NO_BACKTRACING
01745 #ifndef DONT_CALC_GDS_OR_BT
01746 
01747     /* --- backtrace through the instantiation that produced each result --- */
01748     for (pref = results; pref != NIL; pref = pref->next_result) {
01749 
01750 #ifndef TRACE_CONTEXT_DECISIONS_ONLY
01751         if (current_agent(sysparams)[TRACE_BACKTRACING_SYSPARAM]) {
01752             print_string("\nFor result preference ");
01753             print_preference(pref);
01754             print_string(" ");
01755         }
01756 #endif
01757 
01758         if (pref->inst)
01759             backtrace_through_instantiation(pref->inst, grounds_level, NULL, 0);
01760 
01761     }
01762 
01763 #else
01764     add_named_superstate_attribute_to_grounds(inst, "superstate");
01765 #endif
01766 
01767 #endif                          /* NO_BACKTRACING */
01768 
01769     current_agent(quiescence_t_flag) = FALSE;
01770 
01771     while (TRUE) {
01772         trace_locals(grounds_level);
01773         trace_grounded_potentials();
01774         if (!trace_ungrounded_potentials(grounds_level))
01775             break;
01776     }
01777     free_list(current_agent(positive_potentials));
01778 
01779     /* --- backtracing done; collect the grounds into the chunk --- */
01780     {
01781         tc_number tc_for_grounds;
01782         tc_for_grounds = get_new_tc_number();
01783         build_chunk_conds_for_grounds_and_add_negateds(&top_cc, &bottom_cc, tc_for_grounds);
01784         nots = get_nots_for_instantiated_conditions(current_agent(instantiations_with_nots), tc_for_grounds);
01785     }
01786 
01787     /* --- get symbol for name of new chunk or justification --- */
01788 #ifdef MAKE_PRODUCTION_FOR_THIN_JUSTS
01789     if (inst->prod->type != JUSTIFICATION_PRODUCTION_TYPE) {
01790         print("Warning (1)\n");
01791     }
01792 #endif
01793 
01794     print_name = current_agent(sysparams)[TRACE_JUSTIFICATION_NAMES_SYSPARAM];
01795     print_prod = current_agent(sysparams)[TRACE_JUSTIFICATIONS_SYSPARAM];
01796 
01797 #ifdef WATCH_SSCI_INSTS
01798 
01799     print("Rebuiding ");
01800     if (inst->prod)
01801         print_with_symbols("%y\n", inst->prod->name);
01802     else
01803         print("an SSCI inst.\n");
01804 
01805 #endif
01806 
01807     /* AGR 617/634 begin */
01808     if (print_name) {
01809         if (get_printer_output_column() != 1)
01810             print("\n");
01811         print("Rebuiding ");
01812         if (inst->prod)
01813             print_with_symbols("%y\n", inst->prod->name);
01814         else
01815             print("an SSCI inst.\n");
01816 
01817     }
01818     /* AGR 617/634 end */
01819 
01820     /* --- if there aren't any grounds, exit --- */
01821     if (!top_cc) {
01822         if (current_agent(sysparams)[PRINT_WARNINGS_SYSPARAM])
01823             print_string(" Warning: chunk has no grounds, ignoring it.");
01824 
01825     }
01826 
01827     /* --- variablize it --- */
01828     lhs_top = top_cc->variablized_cond;
01829     lhs_bottom = bottom_cc->variablized_cond;
01830     reset_variable_generator(lhs_top, NIL);
01831     current_agent(variablization_tc) = get_new_tc_number();
01832     variablize_condition_list(lhs_top);
01833     variablize_nots_and_insert_into_conditions(nots, lhs_top);
01834     /*
01835      * no need to make a rhs, since there's no justification being
01836      * built
01837      */
01838 
01839     /* --- add goal/impasse tests to it --- */
01840     add_goal_or_impasse_tests(top_cc);
01841 
01842     /* --- reorder lhs and make the production --- */
01843 
01844     {
01845         condition *inst_lhs_top, *inst_lhs_bottom;
01846 
01847         reorder_instantiated_conditions(top_cc, &inst_lhs_top, &inst_lhs_bottom);
01848         deallocate_inst_members_to_be_rewritten(inst);
01849 
01850         /* 
01851          * now fill in the new conditions for this level
01852          */
01853         inst->top_of_instantiated_conditions = inst_lhs_top;
01854         inst->bottom_of_instantiated_conditions = inst_lhs_bottom;
01855         inst->nots = nots;
01856 
01857 #ifdef WATCH_SSCI_CONDS
01858 
01859         print("Rebuiding temp-just: ");
01860         if (inst->prod)
01861             print_with_symbols("%y ... conditions:\n", inst->prod->name);
01862         else
01863             print(" (nil) ... conditions: \n");
01864         print("Address %p\n", inst);
01865         print_condition_list(inst->top_of_instantiated_conditions, 2, TRUE);
01866         if (inst->top_of_instantiated_conditions == NIL) {
01867             print("There are no pointers here...\n");
01868         }
01869 #endif
01870 
01871         re_fill_in_instantiation_stuff_for_modified_lhs(inst, TRUE);
01872 
01873     }                           /* matches { condition *inst_lhs_top, *inst_lhs_bottom ...  */
01874 
01875 #ifdef WARN_IF_RESULT_IS_I_SUPPORTED
01876     /* 
01877      * SW 110499
01878      * See the note with the same date in chunk_instantiation
01879      */
01880     for (pref = inst->preferences_generated; pref != NIL; pref = pref->inst_next) {
01881         if (pref->o_supported == FALSE) {
01882             print("Warning: Result is not natively o-supported. ");
01883 
01884 #ifdef ALLOW_I_SUPPORTED_SUBGOAL_RESULTS_WITH_THIN_JUSTS
01885             print("This may produce memory leaks.\n");
01886 #else
01887             print("O-support will be forced.\n");
01888 #endif
01889 
01890             watchful_print_preference(pref);
01891         }
01892     }
01893 #endif                          /* WARN_IF_RESULT_IS_I_SUPPORTED */
01894 
01895     /* --- deallocate chunks conds and variablized conditions --- */
01896     deallocate_condition_list(lhs_top);
01897 #ifdef DONT_CALC_GDS_OR_BT
01898     /* SW NOTE See the note in add_named_superstate_attribute_to_ground  */
01899     deallocate_condition_list(top_cc->cond);
01900 #endif
01901 
01902     {
01903         chunk_cond *cc;
01904         while (top_cc) {
01905             cc = top_cc;
01906             top_cc = cc->next;
01907             free_with_pool(&current_agent(chunk_cond_pool), cc);
01908         }
01909     }
01910 
01911     /* finally, recurse... */
01912     second_stage_chunk_instantiation(inst);
01913 
01914   chunking_done:{
01915     }
01916 
01917 }
01918 
01919 void deallocate_inst_members_to_be_rewritten(instantiation * inst)
01920 {
01921 
01922     goal_stack_level level;
01923     condition *cond;
01924 
01925     level = inst->match_goal_level;
01926 
01927     /* SW 102799 -- memory leak fix
01928      * We need to do some freeing of old conditions and such.
01929      * moreover, we need to free up some references to wmes and
01930      * preferences in the backtracing structures.  That's 
01931      * what's going on here (I stole this code from fill_in_new_inst_stuff)
01932      */
01933 
01934     for (cond = inst->top_of_instantiated_conditions; cond != NIL; cond = cond->next)
01935         if (cond->type == POSITIVE_CONDITION) {
01936 
01937 #ifdef NO_TOP_LEVEL_REFS
01938             if (level > 1) {
01939                 wme_remove_ref(cond->bt.wme);
01940             }
01941 #ifdef DEBUG_NO_TOP_LEVEL_REFS
01942             else {
01943                 print("NO_TOP_LEVEL_REFS(4): Not removing reference to tt =%lu ref =%lu\n",
01944                       cond->bt.wme->timetag, cond->bt.wme->reference_count);
01945             }
01946 #endif
01947 
01948 #else
01949             wme_remove_ref(cond->bt.wme);
01950 #endif
01951             if (cond->bt.trace) {
01952 
01953 #ifdef NO_TOP_JUST
01954                 if (cond->bt.trace->match_goal_level > level)
01955                     cond->bt.trace = find_clone_for_level(cond->bt.trace, level);
01956 #else
01957 
01958                 if (cond->bt.trace->inst->match_goal_level > level)
01959                     cond->bt.trace = find_clone_for_level(cond->bt.trace, level);
01960 #endif
01961 
01962                 /* begin SW 7.7.99 */
01963 #ifdef NO_TOP_LEVEL_REFS
01964                 if ((cond->bt.trace) && (level > 1)) {
01965                     preference_remove_ref(cond->bt.trace);
01966                 }
01967 #ifdef DEBUG_NO_TOP_LEVEL_REFS
01968                 else {
01969                     print("NO_TOP_LEVEL_REFS (5): Not removing reference to  rf = %lu\n",
01970                           cond->bt.trace->reference_count);
01971                     print("NO_TOP_LEVEL_REFS (5): cond->bt.trace = \n");
01972                     print_preference(cond->bt.trace);
01973                 }
01974 #endif
01975 
01976 #else
01977                 if (cond->bt.trace)
01978                     preference_remove_ref(cond->bt.trace);
01979 #endif
01980             }
01981 
01982         }
01983 
01984     {
01985         preference *pr, *p, *np;
01986         /*
01987            printf( "Trying to remove old preferences generated from match goal\n" );
01988          */
01989         if (inst->match_goal) {
01990             for (p = inst->match_goal->id.preferences_from_goal; p != NIL; p = np) {
01991 
01992                 np = p->all_of_goal_next;
01993                 for (pr = inst->preferences_generated; pr != NIL; pr = pr->inst_next) {
01994                     if (p == pr) {
01995                         /*
01996                            printf ("Found prefernces in old match goal, removing\n");
01997                          */
01998                         remove_from_dll(inst->match_goal->id.preferences_from_goal,
01999                                         pr, all_of_goal_next, all_of_goal_prev);
02000                         break;
02001                     }
02002                 }
02003             }
02004         }
02005     }
02006 
02007     /* SW 102799
02008      * now those icky backtracing structures are all been ready 
02009      * to be deallocated (we've decremented reference counts)
02010      * and we can free the old conditions (which were valid at
02011      * the previous depth in the goal stack, but probably aren't 
02012      * here)
02013      */
02014     deallocate_condition_list(inst->top_of_instantiated_conditions);
02015     deallocate_list_of_nots(inst->nots);
02016 
02017 }
02018 
02019 /* 
02020  * Currently, this is copied directy from 
02021  * fill_in_new_instantiation_stuff  This can be incorporated into the orig.
02022  */
02023 void re_fill_in_instantiation_stuff_for_modified_lhs(instantiation * inst, bool need_to_do_support_calculations)
02024 {
02025     condition *cond;
02026     preference *p;
02027     goal_stack_level level;
02028 
02029 #if 0
02030 #ifdef TRY_SSCI_PROD_NIL
02031     if (inst->prod)
02032 #endif
02033         production_add_ref(inst->prod);
02034 #endif
02035 
02036     find_match_goal(inst);
02037 
02038     level = inst->match_goal_level;
02039 
02040 #ifdef NO_TOP_JUST
02041     /* Record goal information as we may discard pref->inst later      */
02042     /* This list of preferences will catch the productions results and */
02043     /* clone preferences (I believe).                                  */
02044 
02045     for (p = inst->preferences_generated; p != NIL; p = p->inst_next) {
02046         p->match_goal = inst->match_goal;       /* NIL if from attribute impasse */
02047         p->match_goal_level = inst->match_goal_level;
02048     }
02049 
02050     /* This may be a SWBUG.  I removed a '}' here. */
02051 #endif
02052 
02053     /* 
02054 
02055        Note: since we'll never backtrace through instantiations at the top
02056        level, it might make sense to not increment the reference counts
02057        on the wmes and preferences here if the instantiation is at the top
02058        level.  As it stands now, we could gradually accumulate garbage at
02059        the top level if we have a never-ending sequence of production
02060        firings at the top level that chain on each other's results.  (E.g.,
02061        incrementing a counter on every decision cycle.)  I'm leaving it this
02062        way for now, because if we go to S-Support, we'll (I think) need to
02063        save these around (maybe). 
02064 
02065      */
02066 
02067     for (cond = inst->top_of_instantiated_conditions; cond != NIL; cond = cond->next)
02068         if (cond->type == POSITIVE_CONDITION) {
02069 
02070             /* begin SW 7.7.99 */
02071 
02072 #ifdef NO_TOP_LEVEL_REFS
02073             if (level > 1) {
02074                 wme_add_ref(cond->bt.wme);
02075             }
02076 #ifdef DEBUG_NO_TOP_LEVEL_REFS
02077             else {
02078                 print("NO_TOP_LEVEL_REFS (1): Not adding reference to tt =%lu  ref =%lu\n",
02079                       cond->bt.wme->timetag, cond->bt.wme->reference_count);
02080             }
02081 #endif
02082 
02083 #else
02084             wme_add_ref(cond->bt.wme);
02085 #endif
02086 
02087             /* --- if trace is for a lower level, find one for this level --- */
02088             if (cond->bt.trace) {
02089 
02090 #ifdef NO_TOP_JUST
02091                 if (cond->bt.trace->match_goal_level > level)
02092                     cond->bt.trace = find_clone_for_level(cond->bt.trace, level);
02093 #else
02094 
02095                 if (cond->bt.trace->inst->match_goal_level > level)
02096                     cond->bt.trace = find_clone_for_level(cond->bt.trace, level);
02097 #endif
02098 
02099                 /* begin SW 7.7.99 */
02100 #ifdef NO_TOP_LEVEL_REFS
02101                 if ((cond->bt.trace) && (level > 1)) {
02102                     preference_add_ref(cond->bt.trace);
02103                 }
02104 #ifdef DEBUG_NO_TOP_LEVEL_REFS
02105                 else {
02106                     print("NO_TOP_LEVEL_REFS (2): Not adding reference to  rf = %lu\n",
02107                           cond->bt.trace->reference_count);
02108                     print("NO_TOP_LEVEL_REFS (2): cond->bt.trace = \n");
02109                     print_preference(cond->bt.trace);
02110                 }
02111 #endif
02112 
02113 #else
02114                 if (cond->bt.trace)
02115                     preference_add_ref(cond->bt.trace);
02116 #endif
02117             }
02118 
02119         }
02120 
02121     /* endif SW 7.7.99 */
02122 
02123     if (inst->match_goal) {
02124         for (p = inst->preferences_generated; p != NIL; p = p->inst_next) {
02125             insert_at_head_of_dll(inst->match_goal->id.preferences_from_goal, p, all_of_goal_next, all_of_goal_prev);
02126             p->on_goal_list = TRUE;
02127         }
02128     }
02129 
02130     inst->backtrace_number = 0;
02131 
02132     if (current_agent(o_support_calculation_type) == 0) {
02133         /* --- do calc's the normal Soar 6 way --- */
02134         if (need_to_do_support_calculations)
02135             calculate_support_for_instantiation_preferences(inst);
02136     } else if (current_agent(o_support_calculation_type) == 1) {
02137         if (need_to_do_support_calculations)
02138             calculate_support_for_instantiation_preferences(inst);
02139         /* --- do calc's both ways, warn on differences --- */
02140         if ((inst->prod->declared_support != DECLARED_O_SUPPORT) &&
02141             (inst->prod->declared_support != DECLARED_I_SUPPORT)) {
02142             /* --- At this point, we've done them the normal way.  To look for
02143                differences, save o-support flags on a list, then do Doug's
02144                calculations, then compare and restore saved flags. --- */
02145             list *saved_flags;
02146             preference *pref;
02147             bool difference_found;
02148             saved_flags = NIL;
02149             for (pref = inst->preferences_generated; pref != NIL; pref = pref->inst_next)
02150                 push((pref->o_supported ? pref : NIL), saved_flags);
02151             saved_flags = destructively_reverse_list(saved_flags);
02152             dougs_calculate_support_for_instantiation_preferences(inst);
02153             difference_found = FALSE;
02154             for (pref = inst->preferences_generated; pref != NIL; pref = pref->inst_next) {
02155                 cons *c;
02156                 bool b;
02157                 c = saved_flags;
02158                 saved_flags = c->rest;
02159                 b = (c->first ? TRUE : FALSE);
02160                 free_cons(c);
02161                 if (pref->o_supported != b)
02162                     difference_found = TRUE;
02163                 pref->o_supported = b;
02164             }
02165             if (difference_found) {
02166                 print_with_symbols("\n*** O-support difference found in production %y", inst->prod->name);
02167             }
02168         }
02169     } else {
02170         /* --- do calc's Doug's way --- */
02171         if ((inst->prod->declared_support != DECLARED_O_SUPPORT) &&
02172             (inst->prod->declared_support != DECLARED_I_SUPPORT)) {
02173             dougs_calculate_support_for_instantiation_preferences(inst);
02174         }
02175     }
02176 }
02177 
02178 #endif                          /* SINGLE_THIN_JUSTIFICATION */
02179 
02180 /* --------------------------------------------------------------------
02181 
02182                         Chunker Initialization
02183 
02184    Init_chunker() is called at startup time to do initialization here.
02185 -------------------------------------------------------------------- */
02186 
02187 void init_chunker(void)
02188 {
02189     init_memory_pool(&current_agent(chunk_cond_pool), sizeof(chunk_cond), "chunk condition");
02190     init_chunk_cond_set(&current_agent(negated_set));
02191 }
02192 
02193 #ifdef DONT_CALC_GDS_OR_BT
02194 
02195 /* DJP */
02196 /* We're going to create a dummy justification with just one condition.   */
02197 /* The condition will be the named attribute (usually the problem-space)  */
02198 /* passed to this routine.  This function finds the WME in the superstate */
02199 /* and then builds a condition to match it, as if that condition had come */
02200 /* through backtracing for a chunk.                                       */
02201 /* Yes, it's really ugly.                                                 */
02202 /* SW NOTE
02203  * 
02204  * This function works by finding the superstate attribute and adding
02205  * it to the grounds of the new instantiation (justification/chunk) 
02206  * By doing this, it avoids backtracing altogether, however in this
02207  * routine, unlike within backtrace_through_instantiation, the grounds
02208  * consisits of conditions (actually only one) that are fabricated on
02209  * the spot, as opposed to conditions from other real instantiations
02210  * Therefore, in a normal, backtracing version the grounds are just pointers
02211  * to conditions that some other inst owns, in this case no one else owns
02212  * the conds so we need to do some extra trickery to avoid a memory leak.
02213  * this is done in chunk_instantiation (and second_stage_chunk_instantiation)
02214  */
02215 static void add_named_superstate_attribute_to_grounds(instantiation * inst, char *name)
02216 {
02217     Symbol *target;
02218     wme *ps;
02219     slot *the_slot;
02220     condition *ps_cond;
02221 
02222     /* Find the target WME */
02223     target = find_sym_constant(name);
02224 
02225     if (!target)
02226         target = current_agent(superstate_symbol);
02227 
02228     the_slot = find_slot(inst->match_goal->id.higher_goal, target);
02229 
02230     if (the_slot) {
02231         ps = the_slot->wmes;
02232     } else {
02233         ps = find_impasse_wme(inst->match_goal->id.higher_goal, target);
02234     }
02235 
02236     if (ps == NIL) {
02237         print("\nNo Chunks Hack: Whoops, couldn't find %s in superstate.\n", name);
02238         return;
02239     }
02240 
02241     /* Now try to build a condition for this WME */
02242 
02243     /* This will be de-alloced when free the grounds list */
02244     allocate_with_pool(&current_agent(condition_pool), &ps_cond);
02245 
02246     ps_cond->prev = NIL;
02247     ps_cond->next = NIL;
02248     ps_cond->type = POSITIVE_CONDITION;
02249 
02250     ps_cond->data.tests.id_test = make_equality_test(ps->id);
02251     ps_cond->data.tests.attr_test = make_equality_test(ps->attr);
02252     ps_cond->data.tests.value_test = make_equality_test(ps->value);
02253     ps_cond->test_for_acceptable_preference = ps->acceptable;
02254 
02255     ps_cond->bt.wme = ps;
02256     ps_cond->bt.level = inst->match_goal_level - 1;     /* Set to superstate level */
02257 
02258     ps_cond->bt.trace = NIL;    /* Maybe this needs to be a preference for the PS slot ? */
02259     ps_cond->bt.prohibits = NIL;
02260 
02261     push((ps_cond), current_agent(grounds));    /* Add it to the grounds list */
02262 
02263 }
02264 
02265 #endif
02266 /* 031799 SW End */

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