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

production.c

Go to the documentation of this file.
00001 /*************************************************************************
00002  *
00003  *  file:  production.c
00004  *
00005  * ====================================================================
00006  *                    Production Utilities for Soar 6
00007  *
00008  * This file contains various utility routines for manipulating 
00009  * productions and parts of productions:  tests, conditions, actions,
00010  * etc.  Also includes the reorderer and compile-time o-support calculations.
00011  * parser.c loads productions.
00012  * Init_production_utilities() should be called before anything else here.
00013  * =======================================================================
00014  *
00015  * Copyright 1995-2003 Carnegie Mellon University,
00016  *                                                                               University of Michigan,
00017  *                                                                               University of Southern California/Information
00018  *                                                                               Sciences Institute. All rights reserved.
00019  *                                                                              
00020  * Redistribution and use in source and binary forms, with or without
00021  * modification, are permitted provided that the following conditions are met:
00022  *
00023  * 1.   Redistributions of source code must retain the above copyright notice,
00024  *              this list of conditions and the following disclaimer. 
00025  * 2.   Redistributions in binary form must reproduce the above copyright notice,
00026  *              this list of conditions and the following disclaimer in the documentation
00027  *              and/or other materials provided with the distribution. 
00028  *
00029  * THIS SOFTWARE IS PROVIDED BY THE SOAR CONSORTIUM ``AS IS'' AND ANY EXPRESS OR
00030  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00031  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
00032  * EVENT SHALL THE SOAR CONSORTIUM  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
00033  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00034  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00035  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00036  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00037  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00038  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00039  * The views and conclusions contained in the software and documentation are
00040  * those of the authors and should not be interpreted as representing official
00041  * policies, either expressed or implied, of Carnegie Mellon University, the
00042  * University of Michigan, the University of Southern California/Information
00043  * Sciences Institute, or the Soar consortium.
00044  * =======================================================================
00045  */
00046 
00047 #include "soarkernel.h"
00048 #include <ctype.h>
00049 
00050 /* comment out the following line to supress compile-time o-support
00051    calculations */
00052 /* RCHONG: begin 10.11 */
00053 /* #define DO_COMPILE_TIME_O_SUPPORT_CALCS */
00054 /* RCHONG: end 10.11 */
00055 
00056 /* uncomment the following line to get printouts of names of productions
00057    that can't be fully compile-time o-support evaluated */
00058 /* #define LIST_COMPILE_TIME_O_SUPPORT_FAILURES */
00059 
00060 void init_production_utilities(void)
00061 {
00062     init_memory_pool(&current_agent(complex_test_pool), sizeof(complex_test), "complex test");
00063     init_memory_pool(&current_agent(condition_pool), sizeof(condition), "condition");
00064     init_memory_pool(&current_agent(production_pool), sizeof(production), "production");
00065     init_memory_pool(&current_agent(action_pool), sizeof(action), "action");
00066     init_memory_pool(&current_agent(not_pool), sizeof(not), "not");
00067     init_reorderer();
00068 }
00069 
00070 /* ********************************************************************
00071 
00072            Utility Routines for Various Parts of Productions
00073 
00074 ******************************************************************** */
00075 
00076 /* ====================================================================
00077 
00078               Utilities for Symbols and Lists of Symbols
00079 
00080 ==================================================================== */
00081 
00082 /* -----------------------------------------------------------------
00083                        First Letter From Symbol
00084 
00085    When creating dummy variables or identifiers, we try to give them
00086    names that start with a "reasonable" letter.  For example, ^foo <dummy>
00087    becomes ^foo <f*37>, where the variable starts with "f" because
00088    the attribute test starts with "f" also.  This routine looks at
00089    a symbol and tries to figure out a reasonable choice of starting
00090    letter for a variable or identifier to follow it.  If it can't
00091    find a reasonable choice, it returns '*'.
00092 ----------------------------------------------------------------- */
00093 
00094 char first_letter_from_symbol(Symbol * sym)
00095 {
00096     switch (sym->common.symbol_type) {
00097     case VARIABLE_SYMBOL_TYPE:
00098         return *(sym->var.name + 1);
00099     case IDENTIFIER_SYMBOL_TYPE:
00100         return sym->id.name_letter;
00101     case SYM_CONSTANT_SYMBOL_TYPE:
00102         return *(sym->sc.name);
00103     default:
00104         return '*';
00105     }
00106 }
00107 
00108 /* -----------------------------------------------------------------
00109    Find first letter of test, or '*' if nothing appropriate.
00110    (See comments on first_letter_from_symbol for more explanation.)
00111 ----------------------------------------------------------------- */
00112 
00113 char first_letter_from_test(test t)
00114 {
00115     complex_test *ct;
00116     cons *c;
00117     char ch;
00118 
00119     if (test_is_blank_test(t))
00120         return '*';
00121     if (test_is_blank_or_equality_test(t))
00122         return first_letter_from_symbol(referent_of_equality_test(t));
00123 
00124     ct = complex_test_from_test(t);
00125     switch (ct->type) {
00126     case GOAL_ID_TEST:
00127         return 's';
00128     case IMPASSE_ID_TEST:
00129         return 'i';
00130     case CONJUNCTIVE_TEST:
00131         for (c = ct->data.conjunct_list; c != NIL; c = c->rest) {
00132             ch = first_letter_from_test(c->first);
00133             if (ch != '*')
00134                 return ch;
00135         }
00136         return '*';
00137     default:                   /* disjunction tests, and relational tests other than equality */
00138         return '*';
00139     }
00140 }
00141 
00142 /* ----------------------------------------------------------------
00143    Takes a list of symbols and returns a copy of the same list,
00144    incrementing the reference count on each symbol in the list.
00145 ---------------------------------------------------------------- */
00146 
00147 list *copy_symbol_list_adding_references(list * sym_list)
00148 {
00149     cons *c, *first, *prev;
00150 
00151     if (!sym_list)
00152         return NIL;
00153     allocate_cons(&first);
00154     first->first = sym_list->first;
00155     symbol_add_ref((Symbol *) (first->first));
00156     sym_list = sym_list->rest;
00157     prev = first;
00158     while (sym_list) {
00159         allocate_cons(&c);
00160         prev->rest = c;
00161         c->first = sym_list->first;
00162         symbol_add_ref((Symbol *) (c->first));
00163         sym_list = sym_list->rest;
00164         prev = c;
00165     }
00166     prev->rest = NIL;
00167     return first;
00168 }
00169 
00170 /* ----------------------------------------------------------------
00171    Frees a list of symbols, decrementing their reference counts.
00172 ---------------------------------------------------------------- */
00173 
00174 void deallocate_symbol_list_removing_references(list * sym_list)
00175 {
00176     cons *c;
00177 
00178     while (sym_list) {
00179         c = sym_list;
00180         sym_list = sym_list->rest;
00181         symbol_remove_ref((Symbol *) (c->first));
00182         free_cons(c);
00183     }
00184 }
00185 
00186 /* =================================================================
00187 
00188                       Utility Routines for Tests
00189 
00190 ================================================================= */
00191 
00192 /* --- This just copies a consed list of tests. --- */
00193 list *copy_test_list(cons * c)
00194 {
00195     cons *new_c;
00196 
00197     if (!c)
00198         return NIL;
00199     allocate_cons(&new_c);
00200     new_c->first = copy_test(c->first);
00201     new_c->rest = copy_test_list(c->rest);
00202     return new_c;
00203 }
00204 
00205 /* ----------------------------------------------------------------
00206    Takes a test and returns a new copy of it.
00207 ---------------------------------------------------------------- */
00208 
00209 test copy_test(test t)
00210 {
00211     Symbol *referent;
00212     complex_test *ct, *new_ct;
00213 
00214     if (test_is_blank_test(t))
00215         return make_blank_test();
00216 
00217     if (test_is_blank_or_equality_test(t)) {
00218         referent = referent_of_equality_test(t);
00219         return make_equality_test(referent);
00220     }
00221 
00222     ct = complex_test_from_test(t);
00223 
00224     allocate_with_pool(&current_agent(complex_test_pool), &new_ct);
00225     new_ct->type = ct->type;
00226     switch (ct->type) {
00227     case GOAL_ID_TEST:
00228     case IMPASSE_ID_TEST:
00229         break;
00230     case DISJUNCTION_TEST:
00231         new_ct->data.disjunction_list = copy_symbol_list_adding_references(ct->data.disjunction_list);
00232         break;
00233     case CONJUNCTIVE_TEST:
00234         new_ct->data.conjunct_list = copy_test_list(ct->data.conjunct_list);
00235         break;
00236     default:                   /* relational tests other than equality */
00237         new_ct->data.referent = ct->data.referent;
00238         symbol_add_ref(ct->data.referent);
00239         break;
00240     }
00241     return make_test_from_complex_test(new_ct);
00242 }
00243 
00244 /* ----------------------------------------------------------------
00245    Same as copy_test(), only it doesn't include goal or impasse tests
00246    in the new copy.  The caller should initialize the two flags to FALSE
00247    before calling this routine; it sets them to TRUE if it finds a goal
00248    or impasse test.
00249 ---------------------------------------------------------------- */
00250 
00251 test copy_test_removing_goal_impasse_tests(test t, bool * removed_goal, bool * removed_impasse)
00252 {
00253     complex_test *ct, *new_ct;
00254     cons *c;
00255     test new_t, temp;
00256 
00257     if (test_is_blank_or_equality_test(t))
00258         return copy_test(t);
00259 
00260     ct = complex_test_from_test(t);
00261 
00262     switch (ct->type) {
00263     case GOAL_ID_TEST:
00264         *removed_goal = TRUE;
00265         return make_blank_test();
00266     case IMPASSE_ID_TEST:
00267         *removed_impasse = TRUE;
00268         return make_blank_test();
00269 
00270     case CONJUNCTIVE_TEST:
00271         new_t = make_blank_test();
00272         for (c = ct->data.conjunct_list; c != NIL; c = c->rest) {
00273             temp = copy_test_removing_goal_impasse_tests(c->first, removed_goal, removed_impasse);
00274             if (!test_is_blank_test(temp))
00275                 add_new_test_to_test(&new_t, temp);
00276         }
00277         if (test_is_complex_test(new_t)) {
00278             new_ct = complex_test_from_test(new_t);
00279             if (new_ct->type == CONJUNCTIVE_TEST)
00280                 new_ct->data.conjunct_list = destructively_reverse_list(new_ct->data.conjunct_list);
00281         }
00282         return new_t;
00283 
00284     default:                   /* relational tests other than equality */
00285         return copy_test(t);
00286     }
00287 }
00288 
00289 /* ----------------------------------------------------------------
00290    Deallocates a test.
00291 ---------------------------------------------------------------- */
00292 
00293 void deallocate_test(test t)
00294 {
00295     cons *c, *next_c;
00296     complex_test *ct;
00297 
00298     if (test_is_blank_test(t))
00299         return;
00300     if (test_is_blank_or_equality_test(t)) {
00301         symbol_remove_ref(referent_of_equality_test(t));
00302         return;
00303     }
00304 
00305     ct = complex_test_from_test(t);
00306 
00307     switch (ct->type) {
00308     case GOAL_ID_TEST:
00309     case IMPASSE_ID_TEST:
00310         break;
00311     case DISJUNCTION_TEST:
00312         deallocate_symbol_list_removing_references(ct->data.disjunction_list);
00313         break;
00314     case CONJUNCTIVE_TEST:
00315         c = ct->data.conjunct_list;
00316         while (c) {
00317             next_c = c->rest;
00318             deallocate_test(c->first);
00319             free_cons(c);
00320             c = next_c;
00321         }
00322         break;
00323     default:                   /* relational tests other than equality */
00324         symbol_remove_ref(ct->data.referent);
00325         break;
00326     }
00327     free_with_pool(&current_agent(complex_test_pool), ct);
00328 }
00329 
00330 /* --- Macro for doing this (usually) without procedure call overhead. --- */
00331 #define quickly_deallocate_test(t) { \
00332   if (! test_is_blank_test(t)) { \
00333     if (test_is_blank_or_equality_test(t)) { \
00334       symbol_remove_ref (referent_of_equality_test(t)); \
00335     } else { \
00336       deallocate_test (t); } } }
00337 
00338 /* ----------------------------------------------------------------
00339    Destructively modifies the first test (t) by adding the second
00340    one (add_me) to it (usually as a new conjunct).  The first test
00341    need not be a conjunctive test.
00342 ---------------------------------------------------------------- */
00343 
00344 void add_new_test_to_test(test * t, test add_me)
00345 {
00346     complex_test *ct = NULL;
00347     cons *c;
00348     bool already_a_conjunctive_test;
00349 
00350     if (test_is_blank_test(add_me))
00351         return;
00352 
00353     if (test_is_blank_test(*t)) {
00354         *t = add_me;
00355         return;
00356     }
00357 
00358     /* --- if *t isn't already a conjunctive test, make it into one --- */
00359     already_a_conjunctive_test = FALSE;
00360     if (test_is_complex_test(*t)) {
00361         ct = complex_test_from_test(*t);
00362         if (ct->type == CONJUNCTIVE_TEST)
00363             already_a_conjunctive_test = TRUE;
00364     }
00365 
00366     if (!already_a_conjunctive_test) {
00367         allocate_with_pool(&current_agent(complex_test_pool), &ct);
00368         ct->type = CONJUNCTIVE_TEST;
00369         allocate_cons(&c);
00370         ct->data.conjunct_list = c;
00371         c->first = *t;
00372         c->rest = NIL;
00373         *t = make_test_from_complex_test(ct);
00374     }
00375     /* --- at this point, ct points to the complex test structure for *t --- */
00376 
00377     /* --- now add add_me to the conjunct list --- */
00378     allocate_cons(&c);
00379     c->first = add_me;
00380     c->rest = ct->data.conjunct_list;
00381     ct->data.conjunct_list = c;
00382 }
00383 
00384 /* ----------------------------------------------------------------
00385    Same as add_new_test_to_test(), only has no effect if the second
00386    test is already included in the first one.
00387 ---------------------------------------------------------------- */
00388 
00389 void add_new_test_to_test_if_not_already_there(test * t, test add_me)
00390 {
00391     complex_test *ct;
00392     cons *c;
00393 
00394     if (tests_are_equal(*t, add_me)) {
00395         deallocate_test(add_me);
00396         return;
00397     }
00398 
00399     if (test_is_complex_test(*t)) {
00400         ct = complex_test_from_test(*t);
00401         if (ct->type == CONJUNCTIVE_TEST)
00402             for (c = ct->data.conjunct_list; c != NIL; c = c->rest)
00403                 if (tests_are_equal(c->first, add_me)) {
00404                     deallocate_test(add_me);
00405                     return;
00406                 }
00407     }
00408 
00409     add_new_test_to_test(t, add_me);
00410 }
00411 
00412 /* ----------------------------------------------------------------
00413    Returns TRUE iff the two tests are identical.
00414 ---------------------------------------------------------------- */
00415 
00416 bool tests_are_equal(test t1, test t2)
00417 {
00418     cons *c1, *c2;
00419     complex_test *ct1, *ct2;
00420 
00421     if (test_is_blank_or_equality_test(t1))
00422         return (bool) (t1 == t2);       /* Warning: this relies on the representation of tests */
00423 
00424     ct1 = complex_test_from_test(t1);
00425     ct2 = complex_test_from_test(t2);
00426 
00427     if (ct1->type != ct2->type)
00428         return FALSE;
00429 
00430     switch (ct1->type) {
00431     case GOAL_ID_TEST:
00432         return TRUE;
00433     case IMPASSE_ID_TEST:
00434         return TRUE;
00435 
00436     case DISJUNCTION_TEST:
00437         for (c1 = ct1->data.disjunction_list, c2 = ct2->data.disjunction_list;
00438              ((c1 != NIL) && (c2 != NIL)); c1 = c1->rest, c2 = c2->rest)
00439             if (c1->first != c2->first)
00440                 return FALSE;
00441         if (c1 == c2)
00442             return TRUE;        /* make sure they both hit end-of-list */
00443         return FALSE;
00444 
00445     case CONJUNCTIVE_TEST:
00446         for (c1 = ct1->data.conjunct_list, c2 = ct2->data.conjunct_list;
00447              ((c1 != NIL) && (c2 != NIL)); c1 = c1->rest, c2 = c2->rest)
00448             if (!tests_are_equal(c1->first, c2->first))
00449                 return FALSE;
00450         if (c1 == c2)
00451             return TRUE;        /* make sure they both hit end-of-list */
00452         return FALSE;
00453 
00454     default:                   /* relational tests other than equality */
00455         if (ct1->data.referent == ct2->data.referent)
00456             return TRUE;
00457         return FALSE;
00458     }
00459 }
00460 
00461 /* ----------------------------------------------------------------
00462    Returns a hash value for the given test.
00463 ---------------------------------------------------------------- */
00464 
00465 unsigned long hash_test(test t)
00466 {
00467     complex_test *ct;
00468     cons *c;
00469     unsigned long result;
00470 
00471     if (test_is_blank_test(t))
00472         return 0;
00473 
00474     if (test_is_blank_or_equality_test(t))
00475         return (referent_of_equality_test(t))->common.hash_id;
00476 
00477     ct = complex_test_from_test(t);
00478 
00479     switch (ct->type) {
00480     case GOAL_ID_TEST:
00481         return 34894895;        /* just use some unusual number */
00482     case IMPASSE_ID_TEST:
00483         return 2089521;
00484     case DISJUNCTION_TEST:
00485         result = 7245;
00486         for (c = ct->data.conjunct_list; c != NIL; c = c->rest)
00487             result = result + ((Symbol *) (c->first))->common.hash_id;
00488         return result;
00489     case CONJUNCTIVE_TEST:
00490         result = 100276;
00491         for (c = ct->data.disjunction_list; c != NIL; c = c->rest)
00492             result = result + hash_test(c->first);
00493         return result;
00494     case NOT_EQUAL_TEST:
00495     case LESS_TEST:
00496     case GREATER_TEST:
00497     case LESS_OR_EQUAL_TEST:
00498     case GREATER_OR_EQUAL_TEST:
00499     case SAME_TYPE_TEST:
00500         return (ct->type << 24) + ct->data.referent->common.hash_id;
00501     default:
00502         {
00503             char msg[MESSAGE_SIZE];
00504             strncpy(msg, "production.c: Error: bad test type in hash_test\n", MESSAGE_SIZE);
00505             msg[MESSAGE_SIZE - 1] = 0;
00506             abort_with_fatal_error(msg);
00507         }
00508     }
00509     return 0;                   /* unreachable, but without it, gcc -Wall warns here */
00510 }
00511 
00512 /****************************/
00513   /* ----------------------------------------------------------------
00514      This returns a boolean that indicates that one condition is
00515      greater than another in some ordering of the conditions. The ordering
00516      is dependent upon the hash-value of each of the tests in the
00517      condition.
00518      ------------------------------------------------------------------ */
00519 
00520 #define NON_EQUAL_TEST_RETURN_VAL 0     /* some unusual number */
00521 
00522 unsigned long canonical_test(test t)
00523 {
00524     Symbol *sym;
00525 
00526     if (test_is_blank_test(t))
00527         return NON_EQUAL_TEST_RETURN_VAL;
00528 
00529     if (test_is_blank_or_equality_test(t)) {
00530         sym = referent_of_equality_test(t);
00531         if (sym->common.symbol_type == SYM_CONSTANT_SYMBOL_TYPE ||
00532             sym->common.symbol_type == INT_CONSTANT_SYMBOL_TYPE ||
00533             sym->common.symbol_type == FLOAT_CONSTANT_SYMBOL_TYPE) {
00534             return (sym->common.hash_id);
00535         } else
00536             return NON_EQUAL_TEST_RETURN_VAL;
00537     }
00538     return NON_EQUAL_TEST_RETURN_VAL;
00539 }
00540 
00541 #define CANONICAL_TEST_ORDER canonical_test
00542 
00543 /*
00544 #define CANONICAL_TEST_ORDER hash_test
00545 */
00546 
00547 bool canonical_cond_greater(condition * c1, condition * c2)
00548 /*
00549 
00550  Original:  676,362 total rete nodes (1 dummy + 560045 positive + 4
00551             unhashed positive + 2374 negative + 113938 p_nodes)
00552 
00553 The following notation describes the order of tests and the relation
00554 of the hash_test that was used. IAV< means test the (I)d field first
00555 then the (A)ttribute field, then the (V)alue field. and use less than
00556 as the ordering constraint. The actual ordering constraint should not
00557 make any difference.
00558 
00559  IAV<:  737,605 total rete nodes (1 dummy + 617394 positive + 3
00560             unhashed positive + 6269 negative + 113938 p_nodes)
00561 
00562 Realized that the identifier will always be a variable and thus
00563 shouldn't be part of the ordering.
00564 
00565 Changed to put all negative tests in front of cost 1 tests list.
00566    That is always break ties of cost 1 with a negative test if
00567    it exists.
00568 
00569 Changed so that canonical_test_order returns a negative -1 when
00570 comparing anything but constants. Also fixed a bug.
00571 
00572 Consistency checks:
00573 
00574  Original:  676,362 total rete nodes (1 dummy + 560045 positive + 4
00575             unhashed positive + 2374 negative + 113938 p_nodes)
00576     Still holds with 1 optimization in and always returning False
00577 
00578  Remove 1:  720,126 total rete nodes (1 dummy + 605760 positive + 4
00579             unhashed positive +  423 negative + 113938 p_nodes)
00580     Always returning False causes the first item in the tie list to
00581        be picked.
00582 
00583  Surprise:  637,482 total rete nodes (1 dummy + 523251 positive + 3
00584             unhashed positive +  289 negative + 113938 p_nodes)
00585     Without 1 optimization and always returning True. Causes the
00586       last item in 1-tie list to be picked.
00587 
00588  In the following tests ht means hash test provided the canonical
00589  value. ct means that the routine constant test provided the canonical
00590  value. ct provides a value for non constant equality tests. I tried
00591  both 0 and a big number (B)  with no difference noted.
00592 
00593   ht_AV<:   714,427 total rete nodes (1 dummy + 600197 positive + 2
00594             unhashed positive +  289 negative + 113938 p_nodes)
00595 
00596   ht_AV>:   709,637 total rete nodes (1 dummy + 595305 positive + 3
00597             unhashed positive +  390 negative + 113938 p_nodes)
00598 
00599   ct0_AV>:  709,960 total rete nodes (1 dummy + 595628 positive + 3
00600             unhashed positive +  390 negative + 113938 p_nodes)
00601 
00602   ct0_AV<:  714,162 total rete nodes (1 dummy + 599932 positive + 2
00603             unhashed positive +  289 negative + 113938 p_nodes)
00604 
00605   ctB_AV>:  709,960 total rete nodes (1 dummy + 595628 positive + 3
00606             unhashed positive +  390 negative + 113938 p_nodes)
00607 
00608   ctB_AV<:  714,162 total rete nodes (1 dummy + 599932 positive + 2
00609             unhashed positive +  289 negative + 113938 p_nodes)
00610 
00611   ctB_VA>:  691,193 total rete nodes (1 dummy + 576861 positive + 3
00612             unhashed positive +  390 negative + 113938 p_nodes)
00613 
00614   ctB_VA<:  704,539 total rete nodes (1 dummy + 590309 positive + 2
00615             unhashed positive +  289 negative + 113938 p_nodes)
00616 
00617   ct0_VA<:  744,604 total rete nodes (1 dummy + 630374 positive + 2
00618             unhashed positive +  289 negative + 113938 p_nodes)
00619 
00620   ct0_VA>:  672,367 total rete nodes (1 dummy + 558035 positive + 3
00621             unhashed positive +  390 negative + 113938 p_nodes)
00622 
00623    ht_VA>:  727,742 total rete nodes (1 dummy + 613517 positive + 3
00624             unhashed positive +  283 negative + 113938 p_nodes)
00625 
00626    ht_VA<:  582,559 total rete nodes (1 dummy + 468328 positive + 3
00627             unhashed positive +  289 negative + 113938 p_nodes)
00628 
00629 Changed  < to > 10/5/92*/
00630 {
00631     unsigned long test_order_1, test_order_2;
00632 
00633     if ((test_order_1 = CANONICAL_TEST_ORDER(c1->data.tests.attr_test)) <
00634         (test_order_2 = CANONICAL_TEST_ORDER(c2->data.tests.attr_test))) {
00635         return TRUE;
00636     } else if (test_order_1 == test_order_2 &&
00637                CANONICAL_TEST_ORDER(c1->data.tests.value_test) < CANONICAL_TEST_ORDER(c2->data.tests.value_test)) {
00638         return TRUE;
00639     }
00640     return FALSE;
00641 }
00642 
00643 /* ----------------------------------------------------------------
00644    Returns TRUE iff the test contains an equality test for the given
00645    symbol.  If sym==NIL, returns TRUE iff the test contains any
00646    equality test.
00647 ---------------------------------------------------------------- */
00648 
00649 bool test_includes_equality_test_for_symbol(test t, Symbol * sym)
00650 {
00651     cons *c;
00652     complex_test *ct;
00653 
00654     if (test_is_blank_test(t))
00655         return FALSE;
00656 
00657     if (test_is_blank_or_equality_test(t)) {
00658         if (sym)
00659             return (bool) (referent_of_equality_test(t) == sym);
00660         return TRUE;
00661     }
00662 
00663     ct = complex_test_from_test(t);
00664 
00665     if (ct->type == CONJUNCTIVE_TEST) {
00666         for (c = ct->data.conjunct_list; c != NIL; c = c->rest)
00667             if (test_includes_equality_test_for_symbol(c->first, sym))
00668                 return TRUE;
00669     }
00670     return FALSE;
00671 }
00672 
00673 /* ----------------------------------------------------------------
00674    Looks for goal or impasse tests (as directed by the two flag
00675    parameters) in the given test, and returns TRUE if one is found.
00676 ---------------------------------------------------------------- */
00677 
00678 bool test_includes_goal_or_impasse_id_test(test t, bool look_for_goal, bool look_for_impasse)
00679 {
00680     complex_test *ct;
00681     cons *c;
00682 
00683     if (test_is_blank_or_equality_test(t))
00684         return FALSE;
00685     ct = complex_test_from_test(t);
00686     if (look_for_goal && (ct->type == GOAL_ID_TEST))
00687         return TRUE;
00688     if (look_for_impasse && (ct->type == IMPASSE_ID_TEST))
00689         return TRUE;
00690     if (ct->type == CONJUNCTIVE_TEST) {
00691         for (c = ct->data.conjunct_list; c != NIL; c = c->rest)
00692             if (test_includes_goal_or_impasse_id_test(c->first, look_for_goal, look_for_impasse))
00693                 return TRUE;
00694         return FALSE;
00695     }
00696     return FALSE;
00697 }
00698 
00699 /* ----------------------------------------------------------------
00700    Looks through a test, and returns a new copy of the first equality
00701    test it finds.  Signals an error if there is no equality test in
00702    the given test.
00703 ---------------------------------------------------------------- */
00704 
00705 test copy_of_equality_test_found_in_test(test t)
00706 {
00707     complex_test *ct;
00708     cons *c;
00709     char msg[MESSAGE_SIZE];
00710 
00711     if (test_is_blank_test(t)) {
00712         strncpy(msg, "Internal error: can't find equality test in test\n", MESSAGE_SIZE);
00713         msg[MESSAGE_SIZE - 1] = 0;
00714         abort_with_fatal_error(msg);
00715     }
00716     if (test_is_blank_or_equality_test(t))
00717         return copy_test(t);
00718     ct = complex_test_from_test(t);
00719     if (ct->type == CONJUNCTIVE_TEST) {
00720         for (c = ct->data.conjunct_list; c != NIL; c = c->rest)
00721             if ((!test_is_blank_test((test) (c->first))) && (test_is_blank_or_equality_test((test) (c->first))))
00722                 return copy_test(c->first);
00723     }
00724     strncpy(msg, "Internal error: can't find equality test in test\n", MESSAGE_SIZE);
00725     msg[MESSAGE_SIZE - 1] = 0;
00726     abort_with_fatal_error(msg);
00727     return 0;                   /* unreachable, but without it, gcc -Wall warns here */
00728 }
00729 
00730 /* =================================================================
00731 
00732                   Utility Routines for Conditions
00733 
00734 ================================================================= */
00735 
00736 /* ----------------------------------------------------------------
00737    Deallocates a condition list (including any NCC's and tests in it).
00738 ---------------------------------------------------------------- */
00739 
00740 void deallocate_condition_list(condition * cond_list)
00741 {
00742     condition *c;
00743 
00744     while (cond_list) {
00745         c = cond_list;
00746 
00747         cond_list = cond_list->next;
00748         if (c->type == CONJUNCTIVE_NEGATION_CONDITION) {
00749             deallocate_condition_list(c->data.ncc.top);
00750         } else {                /* positive and negative conditions */
00751             quickly_deallocate_test(c->data.tests.id_test);
00752             quickly_deallocate_test(c->data.tests.attr_test);
00753             quickly_deallocate_test(c->data.tests.value_test);
00754         }
00755         free_with_pool(&current_agent(condition_pool), c);
00756     }
00757 }
00758 
00759 /* ----------------------------------------------------------------
00760    Returns a new copy of the given condition.
00761 ---------------------------------------------------------------- */
00762 
00763 condition *copy_condition(condition * cond)
00764 {
00765     condition *new;
00766 
00767     if (!cond)
00768         return NIL;
00769     allocate_with_pool(&current_agent(condition_pool), &new);
00770     new->type = cond->type;
00771 
00772     switch (cond->type) {
00773     case POSITIVE_CONDITION:
00774         new->bt = cond->bt;
00775         /* ... and fall through to next case */
00776     case NEGATIVE_CONDITION:
00777         new->data.tests.id_test = copy_test(cond->data.tests.id_test);
00778         new->data.tests.attr_test = copy_test(cond->data.tests.attr_test);
00779         new->data.tests.value_test = copy_test(cond->data.tests.value_test);
00780         new->test_for_acceptable_preference = cond->test_for_acceptable_preference;
00781         break;
00782     case CONJUNCTIVE_NEGATION_CONDITION:
00783         copy_condition_list(cond->data.ncc.top, &(new->data.ncc.top), &(new->data.ncc.bottom));
00784         break;
00785     }
00786     return new;
00787 }
00788 
00789 /* ----------------------------------------------------------------
00790    Copies the given condition list, returning pointers to the
00791    top-most and bottom-most conditions in the new copy.
00792 ---------------------------------------------------------------- */
00793 
00794 void copy_condition_list(condition * top_cond, condition ** dest_top, condition ** dest_bottom)
00795 {
00796     condition *new, *prev;
00797 
00798     prev = NIL;
00799     while (top_cond) {
00800         new = copy_condition(top_cond);
00801         if (prev)
00802             prev->next = new;
00803         else
00804             *dest_top = new;
00805         new->prev = prev;
00806         prev = new;
00807         top_cond = top_cond->next;
00808     }
00809     if (prev)
00810         prev->next = NIL;
00811     else
00812         *dest_top = NIL;
00813     *dest_bottom = prev;
00814 }
00815 
00816 /* ----------------------------------------------------------------
00817    Returns TRUE iff the two conditions are identical.
00818 ---------------------------------------------------------------- */
00819 
00820 bool conditions_are_equal(condition * c1, condition * c2)
00821 {
00822     if (c1->type != c2->type)
00823         return FALSE;
00824     switch (c1->type) {
00825     case POSITIVE_CONDITION:
00826     case NEGATIVE_CONDITION:
00827         if (!tests_are_equal(c1->data.tests.id_test, c2->data.tests.id_test))
00828             return FALSE;
00829         if (!tests_are_equal(c1->data.tests.attr_test, c2->data.tests.attr_test))
00830             return FALSE;
00831         if (!tests_are_equal(c1->data.tests.value_test, c2->data.tests.value_test))
00832             return FALSE;
00833         if (c1->test_for_acceptable_preference != c2->test_for_acceptable_preference)
00834             return FALSE;
00835         return TRUE;
00836 
00837     case CONJUNCTIVE_NEGATION_CONDITION:
00838         for (c1 = c1->data.ncc.top, c2 = c2->data.ncc.top; ((c1 != NIL) && (c2 != NIL)); c1 = c1->next, c2 = c2->next)
00839             if (!conditions_are_equal(c1, c2))
00840                 return FALSE;
00841         if (c1 == c2)
00842             return TRUE;        /* make sure they both hit end-of-list */
00843         return FALSE;
00844     }
00845     return FALSE;               /* unreachable, but without it, gcc -Wall warns here */
00846 }
00847 
00848 /* ----------------------------------------------------------------
00849    Returns a hash value for the given condition.
00850 ---------------------------------------------------------------- */
00851 
00852 unsigned long hash_condition(condition * cond)
00853 {
00854     unsigned long result;
00855     condition *c;
00856 
00857     switch (cond->type) {
00858     case POSITIVE_CONDITION:
00859         result = hash_test(cond->data.tests.id_test);
00860         result = (result << 24) | (result >> 8);
00861         result ^= hash_test(cond->data.tests.attr_test);
00862         result = (result << 24) | (result >> 8);
00863         result ^= hash_test(cond->data.tests.value_test);
00864         if (cond->test_for_acceptable_preference)
00865             result++;
00866         break;
00867     case NEGATIVE_CONDITION:
00868         result = 1267818;
00869         result ^= hash_test(cond->data.tests.id_test);
00870         result = (result << 24) | (result >> 8);
00871         result ^= hash_test(cond->data.tests.attr_test);
00872         result = (result << 24) | (result >> 8);
00873         result ^= hash_test(cond->data.tests.value_test);
00874         if (cond->test_for_acceptable_preference)
00875             result++;
00876         break;
00877     case CONJUNCTIVE_NEGATION_CONDITION:
00878         result = 82348149;
00879         for (c = cond->data.ncc.top; c != NIL; c = c->next) {
00880             result ^= hash_condition(c);
00881             result = (result << 24) | (result >> 8);
00882         }
00883         break;
00884     default:
00885         {
00886             char msg[MESSAGE_SIZE];
00887             strncpy(msg, "Internal error: bad cond type in hash_condition\n", MESSAGE_SIZE);
00888             msg[MESSAGE_SIZE - 1] = 0;
00889             abort_with_fatal_error(msg);
00890         }
00891         result = 0;             /* unreachable, but gcc -Wall warns without it */
00892     }
00893     return result;
00894 }
00895 
00896 /* =================================================================
00897 
00898               Utility Routines for Actions and RHS Values
00899 
00900 ================================================================= */
00901 
00902 /* ----------------------------------------------------------------
00903    Deallocates the given rhs_value.
00904 ---------------------------------------------------------------- */
00905 
00906 void deallocate_rhs_value(rhs_value rv)
00907 {
00908     cons *c;
00909     list *fl;
00910 
00911     if (rhs_value_is_reteloc(rv))
00912         return;
00913     if (rhs_value_is_unboundvar(rv))
00914         return;
00915     if (rhs_value_is_funcall(rv)) {
00916         fl = rhs_value_to_funcall_list(rv);
00917         for (c = fl->rest; c != NIL; c = c->rest)
00918             deallocate_rhs_value(c->first);
00919         free_list(fl);
00920     } else {
00921         symbol_remove_ref(rhs_value_to_symbol(rv));
00922     }
00923 }
00924 
00925 /* ----------------------------------------------------------------
00926    Returns a new copy of the given rhs_value.
00927 ---------------------------------------------------------------- */
00928 
00929 rhs_value copy_rhs_value(rhs_value rv)
00930 {
00931     cons *c, *new_c, *prev_new_c;
00932     list *fl, *new_fl;
00933 
00934     if (rhs_value_is_reteloc(rv))
00935         return rv;
00936     if (rhs_value_is_unboundvar(rv))
00937         return rv;
00938     if (rhs_value_is_funcall(rv)) {
00939         fl = rhs_value_to_funcall_list(rv);
00940         allocate_cons(&new_fl);
00941         new_fl->first = fl->first;
00942         prev_new_c = new_fl;
00943         for (c = fl->rest; c != NIL; c = c->rest) {
00944             allocate_cons(&new_c);
00945             new_c->first = copy_rhs_value(c->first);
00946             prev_new_c->rest = new_c;
00947             prev_new_c = new_c;
00948         }
00949         prev_new_c->rest = NIL;
00950         return funcall_list_to_rhs_value(new_fl);
00951     } else {
00952         symbol_add_ref(rhs_value_to_symbol(rv));
00953         return rv;
00954     }
00955 }
00956 
00957 /* ----------------------------------------------------------------
00958    Deallocates the given action (singly-linked) list.
00959 ---------------------------------------------------------------- */
00960 
00961 void deallocate_action_list(action * actions)
00962 {
00963     action *a;
00964 
00965     while (actions) {
00966         a = actions;
00967         actions = actions->next;
00968         if (a->type == FUNCALL_ACTION) {
00969             deallocate_rhs_value(a->value);
00970         } else {
00971             /* --- make actions --- */
00972             deallocate_rhs_value(a->id);
00973             deallocate_rhs_value(a->attr);
00974             deallocate_rhs_value(a->value);
00975             if (preference_is_binary(a->preference_type))
00976                 deallocate_rhs_value(a->referent);
00977         }
00978         free_with_pool(&current_agent(action_pool), a);
00979     }
00980 }
00981 
00982 /* -----------------------------------------------------------------
00983    Find first letter of rhs_value, or '*' if nothing appropriate.
00984    (See comments on first_letter_from_symbol for more explanation.)
00985 ----------------------------------------------------------------- */
00986 
00987 char first_letter_from_rhs_value(rhs_value rv)
00988 {
00989     if (rhs_value_is_symbol(rv))
00990         return first_letter_from_symbol(rhs_value_to_symbol(rv));
00991     return '*';                 /* function calls, reteloc's, unbound variables */
00992 }
00993 
00994 /* =================================================================
00995 
00996                     Utility Routines for Nots
00997 
00998 ================================================================= */
00999 
01000 /* ----------------------------------------------------------------
01001    Deallocates the given (singly-linked) list of Nots.
01002 ---------------------------------------------------------------- */
01003 
01004 void deallocate_list_of_nots(not * nots)
01005 {
01006     not *temp;
01007 
01008     while (nots) {
01009         temp = nots;
01010         nots = nots->next;
01011         symbol_remove_ref(temp->s1);
01012         symbol_remove_ref(temp->s2);
01013         free_with_pool(&current_agent(not_pool), temp);
01014     }
01015 }
01016 
01017 /* *********************************************************************
01018 
01019                     Transitive Closure Utilities
01020 
01021 ********************************************************************* */
01022 
01023 /* =====================================================================
01024 
01025               Increment TC Counter and Return New TC Number
01026 
01027    Get_new_tc_number() is called from lots of places.  Any time we need
01028    to mark a set of identifiers and/or variables, we get a new tc_number
01029    by calling this routine, then proceed to mark various ids or vars
01030    by setting the sym->id.tc_num or sym->var.tc_num fields.
01031 
01032    A global tc number counter is maintained and incremented by this
01033    routine in order to generate a different tc_number each time.  If
01034    the counter ever wraps around back to 0, we bump it up to 1 and
01035    reset the the tc_num fields on all existing identifiers and variables
01036    to 0.
01037 ===================================================================== */
01038 
01039 tc_number current_tc_number = 0;
01040 
01041 tc_number get_new_tc_number(void)
01042 {
01043     current_tc_number++;
01044     if (current_tc_number == 0) {
01045         reset_id_and_variable_tc_numbers();
01046         current_tc_number = 1;
01047     }
01048     return current_tc_number;
01049 }
01050 
01051 /* =====================================================================
01052 
01053                Marking, Unmarking, and Collecting Symbols
01054 
01055    Sometimes in addition to marking symbols using their tc_num fields,
01056    we also want to build up a list of the symbols we've marked.  So,
01057    many routines in this file take an "id_list" or "var_list" argument.
01058    This argument should be NIL if no such list is desired.  If non-NIL,
01059    it should point to the header of the linked list being built.
01060 
01061    Mark_identifier_if_unmarked() and mark_variable_if_unmarked() are
01062    macros for adding id's and var's to the set of symbols.
01063 
01064    Unmark_identifiers_and_free_list() unmarks all the id's in the given
01065    list, and deallocates the list.  Unmark_variables_and_free_list()
01066    is similar, only the list should be a list of variables rather than
01067    identifiers.
01068 
01069    Symbol_is_constant_or_marked_variable() tests whether the given symbol
01070    is either a constant (non-variable) or a variable marked with the
01071    given tc number.
01072 ===================================================================== */
01073 
01074 #define mark_identifier_if_unmarked(ident,tc,id_list) { \
01075   if ((ident)->id.tc_num != (tc)) { \
01076     (ident)->id.tc_num = (tc); \
01077     if (id_list) push ((ident),(*(id_list))); } }
01078 
01079 #define mark_variable_if_unmarked(v,tc,var_list) { \
01080   if ((v)->var.tc_num != (tc)) { \
01081     (v)->var.tc_num = (tc); \
01082     if (var_list) push ((v),(*(var_list))); } }
01083 
01084 void unmark_identifiers_and_free_list(list * id_list)
01085 {
01086     cons *next;
01087     Symbol *sym;
01088 
01089     while (id_list) {
01090         sym = id_list->first;
01091         next = id_list->rest;
01092         free_cons(id_list);
01093         sym->id.tc_num = 0;
01094         id_list = next;
01095     }
01096 }
01097 
01098 void unmark_variables_and_free_list(list * var_list)
01099 {
01100     cons *next;
01101     Symbol *sym;
01102 
01103     while (var_list) {
01104         sym = var_list->first;
01105         next = var_list->rest;
01106         free_cons(var_list);
01107         sym->var.tc_num = 0;
01108         var_list = next;
01109     }
01110 }
01111 
01112 /* =====================================================================
01113 
01114    Finding the variables bound in tests, conditions, and condition lists
01115 
01116    These routines collect the variables that are bound in tests, etc.  Their
01117    "var_list" arguments should either be NIL or else should point to
01118    the header of the list of marked variables being constructed.
01119 ===================================================================== */
01120 
01121 void add_bound_variables_in_test(test t, tc_number tc, list ** var_list)
01122 {
01123     cons *c;
01124     Symbol *referent;
01125     complex_test *ct;
01126 
01127     if (test_is_blank_test(t))
01128         return;
01129 
01130     if (test_is_blank_or_equality_test(t)) {
01131         referent = referent_of_equality_test(t);
01132         if (referent->common.symbol_type == VARIABLE_SYMBOL_TYPE)
01133             mark_variable_if_unmarked(referent, tc, var_list);
01134         return;
01135     }
01136 
01137     ct = complex_test_from_test(t);
01138     if (ct->type == CONJUNCTIVE_TEST) {
01139         for (c = ct->data.conjunct_list; c != NIL; c = c->rest)
01140             add_bound_variables_in_test(c->first, tc, var_list);
01141     }
01142 }
01143 
01144 void add_bound_variables_in_condition(condition * c, tc_number tc, list ** var_list)
01145 {
01146     if (c->type != POSITIVE_CONDITION)
01147         return;
01148     add_bound_variables_in_test(c->data.tests.id_test, tc, var_list);
01149     add_bound_variables_in_test(c->data.tests.attr_test, tc, var_list);
01150     add_bound_variables_in_test(c->data.tests.value_test, tc, var_list);
01151 }
01152 
01153 void add_bound_variables_in_condition_list(condition * cond_list, tc_number tc, list ** var_list)
01154 {
01155     condition *c;
01156 
01157     for (c = cond_list; c != NIL; c = c->next)
01158         add_bound_variables_in_condition(c, tc, var_list);
01159 }
01160 
01161 /* =====================================================================
01162 
01163    Finding all variables from tests, conditions, and condition lists
01164 
01165    These routines collect all the variables in tests, etc.  Their
01166    "var_list" arguments should either be NIL or else should point to
01167    the header of the list of marked variables being constructed.
01168 ===================================================================== */
01169 
01170 void add_all_variables_in_test(test t, tc_number tc, list ** var_list)
01171 {
01172     cons *c;
01173     Symbol *referent;
01174     complex_test *ct;
01175 
01176     if (test_is_blank_test(t))
01177         return;
01178 
01179     if (test_is_blank_or_equality_test(t)) {
01180         referent = referent_of_equality_test(t);
01181         if (referent->common.symbol_type == VARIABLE_SYMBOL_TYPE)
01182             mark_variable_if_unmarked(referent, tc, var_list);
01183         return;
01184     }
01185 
01186     ct = complex_test_from_test(t);
01187 
01188     switch (ct->type) {
01189     case GOAL_ID_TEST:
01190     case IMPASSE_ID_TEST:
01191     case DISJUNCTION_TEST:
01192         break;
01193 
01194     case CONJUNCTIVE_TEST:
01195         for (c = ct->data.conjunct_list; c != NIL; c = c->rest)
01196             add_all_variables_in_test(c->first, tc, var_list);
01197         break;
01198 
01199     default:
01200         /* --- relational tests other than equality --- */
01201         referent = ct->data.referent;
01202         if (referent->common.symbol_type == VARIABLE_SYMBOL_TYPE)
01203             mark_variable_if_unmarked(referent, tc, var_list);
01204         break;
01205     }
01206 }
01207 
01208 void add_all_variables_in_condition_list(condition * cond_list, tc_number tc, list ** var_list);
01209 
01210 void add_all_variables_in_condition(condition * c, tc_number tc, list ** var_list)
01211 {
01212     if (c->type == CONJUNCTIVE_NEGATION_CONDITION) {
01213         add_all_variables_in_condition_list(c->data.ncc.top, tc, var_list);
01214     } else {
01215         add_all_variables_in_test(c->data.tests.id_test, tc, var_list);
01216         add_all_variables_in_test(c->data.tests.attr_test, tc, var_list);
01217         add_all_variables_in_test(c->data.tests.value_test, tc, var_list);
01218     }
01219 }
01220 
01221 void add_all_variables_in_condition_list(condition * cond_list, tc_number tc, list ** var_list)
01222 {
01223     condition *c;
01224 
01225     for (c = cond_list; c != NIL; c = c->next)
01226         add_all_variables_in_condition(c, tc, var_list);
01227 }
01228 
01229 /* =====================================================================
01230 
01231    Finding all variables from rhs_value's, actions, and action lists
01232 
01233    These routines collect all the variables in rhs_value's, etc.  Their
01234    "var_list" arguments should either be NIL or else should point to
01235    the header of the list of marked variables being constructed.
01236 
01237    Warning: These are part of the reorderer and handle only productions
01238    in non-reteloc, etc. format.  They don't handle reteloc's or
01239    RHS unbound variables.
01240 ===================================================================== */
01241 
01242 void add_all_variables_in_rhs_value(rhs_value rv, tc_number tc, list ** var_list)
01243 {
01244     list *fl;
01245     cons *c;
01246     Symbol *sym;
01247 
01248     if (rhs_value_is_symbol(rv)) {
01249         /* --- ordinary values (i.e., symbols) --- */
01250         sym = rhs_value_to_symbol(rv);
01251         if (sym->common.symbol_type == VARIABLE_SYMBOL_TYPE)
01252             mark_variable_if_unmarked(sym, tc, var_list);
01253     } else {
01254         /* --- function calls --- */
01255         fl = rhs_value_to_funcall_list(rv);
01256         for (c = fl->rest; c != NIL; c = c->rest)
01257             add_all_variables_in_rhs_value(c->first, tc, var_list);
01258     }
01259 }
01260 
01261 void add_all_variables_in_action(action * a, tc_number tc, list ** var_list)
01262 {
01263     Symbol *id;
01264 
01265     if (a->type == MAKE_ACTION) {
01266         /* --- ordinary make actions --- */
01267         id = rhs_value_to_symbol(a->id);
01268         if (id->common.symbol_type == VARIABLE_SYMBOL_TYPE)
01269             mark_variable_if_unmarked(id, tc, var_list);
01270         add_all_variables_in_rhs_value(a->attr, tc, var_list);
01271         add_all_variables_in_rhs_value(a->value, tc, var_list);
01272         if (preference_is_binary(a->preference_type))
01273             add_all_variables_in_rhs_value(a->referent, tc, var_list);
01274     } else {
01275         /* --- function call actions --- */
01276         add_all_variables_in_rhs_value(a->value, tc, var_list);
01277     }
01278 }
01279 
01280 void add_all_variables_in_action_list(action * actions, tc_number tc, list ** var_list)
01281 {
01282     action *a;
01283 
01284     for (a = actions; a != NIL; a = a->next)
01285         add_all_variables_in_action(a, tc, var_list);
01286 }
01287 
01288 /* ====================================================================
01289 
01290               Transitive Closure for Conditions and Actions
01291 
01292    These routines do transitive closure calculations for tests,
01293    conditions, actions, etc.
01294 
01295    Usage: 
01296      1. Set my_tc = get_new_tc_number() to start a new TC
01297      2. (optional) If you want linked lists of symbols in the TC, initialize
01298         id_list=NIL and var_list=NIL.
01299         If you're not using id_list and/or var_list, give NIL for "&id_list"
01300         and/or "&var_list" in the function calls below.
01301      3. (optional) setup any id's or var's that you want to include in the
01302         initial TC, by calling 
01303            add_symbol_to_tc (sym, my_tc, &id_list, &var_list)
01304         (If not using id_list or var_list, you can just mark
01305          sym->{id,var}.tc_num = my_tc instead.)
01306      4. To do the work you want, use any of the following any number of times:
01307             add_cond_to_tc (cond, my_tc, &id_list, &var_list);
01308             add_action_to_tc (cond, my_tc, &id_list, &var_list);
01309             result = cond_is_in_tc (cond, my_tc);
01310             result = action_is_in_tc (action, my_tc);
01311      5. When finished, free the cons cells in id_list and var_list (but
01312         don't call symbol_remove_ref() on the symbols in them).
01313 
01314   Warning:  actions must not contain reteloc's or rhs unbound variables here.
01315 ==================================================================== */
01316 
01317 void add_symbol_to_tc(Symbol * sym, tc_number tc, list ** id_list, list ** var_list)
01318 {
01319     if (sym->common.symbol_type == VARIABLE_SYMBOL_TYPE) {
01320         mark_variable_if_unmarked(sym, tc, var_list);
01321     } else if (sym->common.symbol_type == IDENTIFIER_SYMBOL_TYPE) {
01322         mark_identifier_if_unmarked(sym, tc, id_list);
01323     }
01324 }
01325 
01326 void add_test_to_tc(test t, tc_number tc, list ** id_list, list ** var_list)
01327 {
01328     cons *c;
01329     complex_test *ct;
01330 
01331     if (test_is_blank_test(t))
01332         return;
01333 
01334     if (test_is_blank_or_equality_test(t)) {
01335         add_symbol_to_tc(referent_of_equality_test(t), tc, id_list, var_list);
01336         return;
01337     }
01338 
01339     ct = complex_test_from_test(t);
01340     if (ct->type == CONJUNCTIVE_TEST) {
01341         for (c = ct->data.conjunct_list; c != NIL; c = c->rest)
01342             add_test_to_tc(c->first, tc, id_list, var_list);
01343     }
01344 }
01345 
01346 void add_cond_to_tc(condition * c, tc_number tc, list ** id_list, list ** var_list)
01347 {
01348     if (c->type == POSITIVE_CONDITION) {
01349         add_test_to_tc(c->data.tests.id_test, tc, id_list, var_list);
01350         add_test_to_tc(c->data.tests.value_test, tc, id_list, var_list);
01351     }
01352 }
01353 
01354 void add_action_to_tc(action * a, tc_number tc, list ** id_list, list ** var_list)
01355 {
01356     if (a->type != MAKE_ACTION)
01357         return;
01358     add_symbol_to_tc(rhs_value_to_symbol(a->id), tc, id_list, var_list);
01359     if (rhs_value_is_symbol(a->value))
01360         add_symbol_to_tc(rhs_value_to_symbol(a->value), tc, id_list, var_list);
01361     if (preference_is_binary(a->preference_type))
01362         if (rhs_value_is_symbol(a->referent))
01363             add_symbol_to_tc(rhs_value_to_symbol(a->referent), tc, id_list, var_list);
01364 }
01365 
01366 bool symbol_is_in_tc(Symbol * sym, tc_number tc)
01367 {
01368     if (sym->common.symbol_type == VARIABLE_SYMBOL_TYPE)
01369         return (bool) (sym->var.tc_num == tc);
01370     if (sym->common.symbol_type == IDENTIFIER_SYMBOL_TYPE)
01371         return (bool) (sym->id.tc_num == tc);
01372     return FALSE;
01373 }
01374 
01375 bool test_is_in_tc(test t, tc_number tc)
01376 {
01377     cons *c;
01378     complex_test *ct;
01379 
01380     if (test_is_blank_test(t))
01381         return FALSE;
01382     if (test_is_blank_or_equality_test(t)) {
01383         return symbol_is_in_tc(referent_of_equality_test(t), tc);
01384     }
01385 
01386     ct = complex_test_from_test(t);
01387     if (ct->type == CONJUNCTIVE_TEST) {
01388         for (c = ct->data.conjunct_list; c != NIL; c = c->rest)
01389             if (test_is_in_tc(c->first, tc))
01390                 return TRUE;
01391         return FALSE;
01392     }
01393     return FALSE;
01394 }
01395 
01396 bool cond_is_in_tc(condition * cond, tc_number tc)
01397 {
01398     condition *c;
01399     bool anything_changed;
01400     bool result;
01401     list *new_ids, *new_vars;
01402 
01403     if (cond->type != CONJUNCTIVE_NEGATION_CONDITION)
01404         return test_is_in_tc(cond->data.tests.id_test, tc);
01405 
01406     /* --- conjunctive negations:  keep trying to add stuff to the TC --- */
01407     new_ids = NIL;
01408     new_vars = NIL;
01409     for (c = cond->data.ncc.top; c != NIL; c = c->next)
01410         c->already_in_tc = FALSE;
01411     for (;;) {
01412         anything_changed = FALSE;
01413         for (c = cond->data.ncc.top; c != NIL; c = c->next)
01414             if (!c->already_in_tc)
01415                 if (cond_is_in_tc(c, tc)) {
01416                     add_cond_to_tc(c, tc, &new_ids, &new_vars);
01417                     c->already_in_tc = TRUE;
01418                     anything_changed = TRUE;
01419                 }
01420         if (!anything_changed)
01421             break;
01422     }
01423 
01424     /* --- complete TC found, look for anything that didn't get hit --- */
01425     result = TRUE;
01426     for (c = cond->data.ncc.top; c != NIL; c = c->next)
01427         if (!c->already_in_tc)
01428             result = FALSE;
01429 
01430     /* --- unmark identifiers and variables that we just marked --- */
01431     unmark_identifiers_and_free_list(new_ids);
01432     unmark_variables_and_free_list(new_vars);
01433 
01434     return result;
01435 }
01436 
01437 bool action_is_in_tc(action * a, tc_number tc)
01438 {
01439     if (a->type != MAKE_ACTION)
01440         return FALSE;
01441     return symbol_is_in_tc(rhs_value_to_symbol(a->id), tc);
01442 }
01443 
01444 /* *********************************************************************
01445 
01446                          Variable Generator
01447 
01448    These routines are used for generating new variables.  The variables
01449    aren't necessarily "completely" new--they might occur in some existing
01450    production.  But we usually need to make sure the new variables don't
01451    overlap with those already used in a *certain* production--for instance,
01452    when variablizing a chunk, we don't want to introduce a new variable that
01453    conincides with the name of a variable already in an NCC in the chunk.
01454    
01455    To use these routines, first call reset_variable_generator(), giving
01456    it lists of conditions and actions whose variables should not be
01457    used.  Then call generate_new_variable() any number of times; each
01458    time, you give it a string to use as the prefix for the new variable's
01459    name.  The prefix string should not include the opening "<".
01460 ********************************************************************* */
01461 
01462 void reset_variable_generator(condition * conds_with_vars_to_avoid, action * actions_with_vars_to_avoid)
01463 {
01464     tc_number tc;
01465     list *var_list;
01466     cons *c;
01467     int i;
01468 
01469     /* --- reset counts, and increment the gensym number --- */
01470     for (i = 0; i < 26; i++)
01471         current_agent(gensymed_variable_count)[i] = 1;
01472     current_agent(current_variable_gensym_number)++;
01473     if (current_agent(current_variable_gensym_number) == 0) {
01474         reset_variable_gensym_numbers();
01475         current_agent(current_variable_gensym_number) = 1;
01476     }
01477 
01478     /* --- mark all variables in the given conds and actions --- */
01479     tc = get_new_tc_number();
01480     var_list = NIL;
01481     add_all_variables_in_condition_list(conds_with_vars_to_avoid, tc, &var_list);
01482     add_all_variables_in_action_list(actions_with_vars_to_avoid, tc, &var_list);
01483     for (c = var_list; c != NIL; c = c->rest)
01484         ((Symbol *) (c->first))->var.gensym_number = current_agent(current_variable_gensym_number);
01485     free_list(var_list);
01486 }
01487 
01488 #define NAME_BUF_SIZE 200
01489 Symbol *generate_new_variable(char *prefix)
01490 {
01491     char name[NAME_BUF_SIZE];   /* that ought to be long enough! */
01492     Symbol *new;
01493     char first_letter;
01494 
01495     first_letter = *prefix;
01496     if (isalpha(first_letter)) {
01497         if (isupper(first_letter))
01498             first_letter = (char) tolower(first_letter);
01499     } else {
01500         first_letter = 'v';
01501     }
01502 
01503     for (;;) {
01504         snprintf(name, NAME_BUF_SIZE, "<%s%lu>", prefix, current_agent(gensymed_variable_count)[first_letter - 'a']++);
01505         name[NAME_BUF_SIZE - 1] = 0;    /* snprintf doesn't set last char to null if output is truncated */
01506         new = make_variable(name);
01507         if (new->var.gensym_number != current_agent(current_variable_gensym_number))
01508             break;
01509         symbol_remove_ref(new);
01510     }
01511 
01512     new->var.current_binding_value = NIL;
01513     new->var.gensym_number = current_agent(current_variable_gensym_number);
01514     return new;
01515 }
01516 
01517 /* *********************************************************************
01518 
01519                          Production Management
01520 
01521     Make_production() does reordering, compile-time o-support calc's,
01522     and builds and returns a production structure for a new production.
01523     It does not enter the production into the Rete net, however.
01524     The "type" argument should be one of USER_PRODUCTION_TYPE, etc.
01525     The flag "reorder_nccs" tells whether to recursively reorder
01526     the subconditions of NCC's--this is not necessary for newly
01527     built chunks, as their NCC's are copies of other NCC's in SP's that
01528     have already been reordered.  If any error occurs, make_production()
01529     returns NIL.
01530 
01531     Deallocate_production() and excise_production() do just what they
01532     say.  Normally deallocate_production() should be invoked only via
01533     the production_remove_ref() macro.
01534 ********************************************************************* */
01535 
01536 extern char *name_of_production_being_reordered;
01537 
01538 production *make_production(byte type,
01539                             Symbol * name,
01540                             condition ** lhs_top, condition ** lhs_bottom, action ** rhs_top, bool reorder_nccs)
01541 {
01542     production *p;
01543     tc_number tc;
01544     action *a;
01545 
01546     name_of_production_being_reordered = name->sc.name;
01547 
01548     if (type != JUSTIFICATION_PRODUCTION_TYPE) {
01549         reset_variable_generator(*lhs_top, *rhs_top);
01550         tc = get_new_tc_number();
01551         add_bound_variables_in_condition_list(*lhs_top, tc, NIL);
01552         if (!reorder_action_list(rhs_top, tc))
01553             return NIL;
01554         if (!reorder_lhs(lhs_top, lhs_bottom, reorder_nccs))
01555             return NIL;
01556 
01557 #ifdef DO_COMPILE_TIME_O_SUPPORT_CALCS
01558         calculate_compile_time_o_support(*lhs_top, *rhs_top);
01559 #ifdef LIST_COMPILE_TIME_O_SUPPORT_FAILURES
01560         for (a = *rhs_top; a != NIL; a = a->next)
01561             if ((a->type == MAKE_ACTION) && (a->support == UNKNOWN_SUPPORT))
01562                 break;
01563         if (a)
01564             print_with_symbols("\nCan't classify %y\n", name);
01565 #endif
01566 #else
01567         for (a = *rhs_top; a != NIL; a = a->next)
01568             a->support = UNKNOWN_SUPPORT;
01569 #endif
01570     } else {
01571         /* --- for justifications --- */
01572         /* force run-time o-support (it'll only be done once) */
01573 
01574         for (a = *rhs_top; a != NIL; a = a->next)
01575             a->support = UNKNOWN_SUPPORT;
01576     }
01577 
01578     allocate_with_pool(&current_agent(production_pool), &p);
01579     p->name = name;
01580     if (name->sc.production) {
01581         print("Internal error: make_production called with name %s\n", name_of_production_being_reordered);
01582         print("for which a production already exists\n");
01583     }
01584     name->sc.production = p;
01585     p->documentation = NIL;
01586     p->filename = NIL;
01587     p->firing_count = 0;
01588     p->reference_count = 1;
01589     insert_at_head_of_dll(current_agent(all_productions_of_type)[type], p, next, prev);
01590     current_agent(num_productions_of_type)[type]++;
01591     p->type = type;
01592     p->declared_support = UNDECLARED_SUPPORT;
01593 
01594 #ifndef TRACE_CONTEXT_DECISIONS_ONLY
01595     p->trace_firings = FALSE;
01596 #endif
01597     p->p_node = NIL;            /* it's not in the Rete yet */
01598     p->action_list = *rhs_top;
01599     p->rhs_unbound_variables = NIL;     /* the Rete fills this in */
01600     p->instantiations = NIL;
01601     p->interrupt = FALSE;
01602 
01603     return p;
01604 }
01605 
01606 void deallocate_production(production * prod)
01607 {
01608     if (prod->instantiations) {
01609         char msg[MESSAGE_SIZE];
01610         strncpy(msg, "Internal error: deallocating prod. that still has inst's\n", MESSAGE_SIZE);
01611         msg[MESSAGE_SIZE - 1] = 0;
01612         abort_with_fatal_error(msg);
01613     }
01614 #ifdef WATCH_PRODUCTIONS
01615     print_with_symbols("DEALLOCATING PRODUCTION: %y\n", prod->name);
01616 #endif
01617     deallocate_action_list(prod->action_list);
01618     /* RBD 3/28/95 the following line used to use free_list(), leaked memory */
01619     deallocate_symbol_list_removing_references(prod->rhs_unbound_variables);
01620     symbol_remove_ref(prod->name);
01621     if (prod->documentation)
01622         free_memory_block_for_string(prod->documentation);
01623     /* next line, kjh CUSP(B11) */
01624     if (prod->filename)
01625         free_memory_block_for_string(prod->filename);
01626     free_with_pool(&current_agent(production_pool), prod);
01627 }
01628 
01629 void excise_production(production * prod, bool print_sharp_sign)
01630 {
01631 
01632 #ifndef TRACE_CONTEXT_DECISIONS_ONLY
01633     if (prod->trace_firings)
01634         remove_pwatch(prod);
01635 #endif
01636 #ifdef WATCH_PRODUCTIONS
01637     print_with_symbols("EXCISING PRODUCTION: %y\n", prod->name);
01638     print("Productions has reference count %d\n", prod->reference_count);
01639 #endif
01640 
01641     remove_from_dll(current_agent(all_productions_of_type)[prod->type], prod, next, prev);
01642     current_agent(num_productions_of_type)[prod->type]--;
01643     if (print_sharp_sign)
01644         print("#");
01645     if (prod->p_node)
01646         excise_production_from_rete(prod);
01647     prod->name->sc.production = NIL;
01648     production_remove_ref(prod);
01649 }

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