trie_lookup.c

00001 /* File:      trie_lookup.c
00002 ** Author(s): Ernie Johnson
00003 ** Contact:   xsb-contact@cs.sunysb.edu
00004 ** 
00005 ** Copyright (C) The Research Foundation of SUNY, 1986, 1993-1998
00006 ** 
00007 ** XSB is free software; you can redistribute it and/or modify it under the
00008 ** terms of the GNU Library General Public License as published by the Free
00009 ** Software Foundation; either version 2 of the License, or (at your option)
00010 ** any later version.
00011 ** 
00012 ** XSB is distributed in the hope that it will be useful, but WITHOUT ANY
00013 ** WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00014 ** FOR A PARTICULAR PURPOSE.  See the GNU Library General Public License for
00015 ** more details.
00016 ** 
00017 ** You should have received a copy of the GNU Library General Public License
00018 ** along with XSB; if not, write to the Free Software Foundation,
00019 ** Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00020 **
00021 ** $Id: trie_lookup.c,v 1.16 2005/12/12 18:44:54 dwarren Exp $
00022 ** 
00023 */
00024 
00025 
00026 #include "xsb_config.h"
00027 #include "xsb_debug.h"
00028 
00029 #include "debugs/debug_tries.h"
00030 
00031 #include <stdio.h>
00032 #include <stdlib.h>
00033 
00034 #include "auxlry.h"
00035 #include "cell_xsb.h"
00036 #include "error_xsb.h"
00037 #include "psc_xsb.h"
00038 #include "deref.h"
00039 #include "table_stats.h"
00040 #include "trie_internals.h"
00041 #include "tst_aux.h"
00042 #include "subp.h"
00043 #include "debug_xsb.h"
00044 #include "flags_xsb.h"
00045 #include "context.h"
00046 #include "memory_xsb.h"
00047 #if (defined(DEBUG_VERBOSE) || defined(DEBUG_ASSERTIONS))
00048 #include "tst_utils.h"
00049 #endif
00050 
00051 /****************************************************************************
00052 
00053    This file defines a set of functions for searching a trie.  These
00054    functions can be categorized into high-level interface functions:
00055 
00056      void *variant_trie_lookup(void *, int, CPtr, Cell[])
00057      void *subsumptive_trie_lookup(void *, int, CPtr, TriePathType *, Cell[])
00058 
00059    and low-level internal functions:
00060 
00061      void *var_trie_lookup(void *, xsbBool *, Cell *)
00062      void *iter_sub_trie_lookup(void *, TriePathType *)
00063      BTNptr rec_sub_trie_lookup(BTNptr, TriePathType *)
00064 
00065    The following simple invariants are enforced and enable the
00066    interoperability between these functions, higher-level wrappers,
00067    and those routines which perform a check/insert operation:
00068 
00069    * The interface routines assume a non-NULL trie pointer and accept
00070      a term set as an integer count and an array of terms.
00071    * The low-level routines assume a non-EMPTY trie, the term set to be
00072      on the TermStack, and appropriate initialization of any other
00073      required auxiliary data structure (trie stacks and arrays).
00074 
00075    Each function at a particular level should assure compliance with a
00076    lower-level's constraint before invocation of that lower-level
00077    function.
00078     
00079 ****************************************************************************/
00080 
00081 
00082 /*=========================================================================*/
00083 
00084 /*
00085  *                   Iterative Subsumptive Trie Lookup
00086  *                   =================================
00087  */
00088 
00089 /*-------------------------------------------------------------------------*/
00090 
00091 
00092 /*
00093  *                        Variant Continuation
00094  *                        --------------------
00095  *
00096  *  A subsumption-based search operation specifies that a variant entry
00097  *  be made in case no subsuming term set is present in the trie.  Since
00098  *  the lookup operation favors variant selection from the trie, we can
00099  *  utilize the work performed during the initial insurgence, up to the
00100  *  point where the trie deviated from (a variant of) the terms.  We
00101  *  note the last node which was successfully matched, the contents of
00102  *  the TermStack, and the bindings made to the term variables.  This
00103  *  information is sufficient to proceed, from the last successful
00104  *  pairing, with the insertion of new nodes into the trie to create a
00105  *  variant entry of the terms, if need be.
00106  */
00107 
00108 #ifndef MULTI_THREAD
00109 static struct VariantContinuation variant_cont;
00110 #endif
00111 
00112 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
00113 
00114 #define ContStack_ExpandOnOverflow(Stack,StackSize,NeededSize) {        \
00115                                                                         \
00116    size_t new_size;     /* in number of stack elements */               \
00117    void *p;                                                             \
00118                                                                         \
00119    if ( StackSize < NeededSize ) {                                      \
00120      new_size = 2 * StackSize;                                          \
00121      if ( new_size < NeededSize )                                       \
00122        new_size = new_size + NeededSize;                                \
00123      p = realloc(Stack,(new_size * sizeof(Stack[0])));                  \
00124      if ( IsNULL(p) )                                                   \
00125        return FALSE;                                                    \
00126      Stack = p;                                                         \
00127      StackSize = new_size;                                              \
00128    }                                                                    \
00129  }
00130 
00131 
00132 /*
00133  * This assumes that the state of the search is being saved when its
00134  * ONLY modification since the last successful match is the pop of the
00135  * failed-to-match subterm off of the TermStack (and a note in the
00136  * TermStackLog).  No additional bindings, stack ops, etc., have
00137  * occurred.  This assumes some knowledge of the workings of the
00138  * TermStack and Trail: that the top pointer points to the next
00139  * available location in the stack.
00140  */
00141 
00142 static xsbBool save_variant_continuation(CTXTdeclc BTNptr last_node_match) {
00143 
00144   int i;
00145   CPtr termptr, *binding;
00146 
00147   variant_cont.last_node_matched = last_node_match;
00148 
00149   /*
00150    * Include the subterm that couldn't be matched.
00151    */
00152   ContStack_ExpandOnOverflow(variant_cont.subterms.stack.ptr,
00153                              variant_cont.subterms.stack.size,
00154                              TermStack_NumTerms + 1);
00155   for ( termptr = TermStack_Base, i = 0;
00156         termptr <= TermStack_Top;
00157         termptr++, i++ )
00158     variant_cont.subterms.stack.ptr[i] = *termptr;
00159   variant_cont.subterms.num = i;
00160 
00161   ContStack_ExpandOnOverflow(variant_cont.bindings.stack.ptr,
00162                              variant_cont.bindings.stack.size,
00163                              Trail_NumBindings);
00164   i = 0;
00165   for ( binding = Trail_Base;  binding < Trail_Top;  binding++ ) {
00166     termptr = *binding;
00167     /*
00168      * Take only those bindings made to the call variables.
00169      * (Finding the value through a single deref is only possible if the
00170      *  original subterm was deref'ed before trailing.  Currently, this is
00171      *  the case, with trailing of unmarked callvars occuring in only one
00172      *  place in the code.)
00173      */
00174     if ( ! IsUnboundTrieVar(termptr) ) {
00175       variant_cont.bindings.stack.ptr[i].var = termptr;
00176       variant_cont.bindings.stack.ptr[i].value = *termptr;
00177       i++;
00178     }
00179   }
00180   variant_cont.bindings.num = i;
00181   return TRUE;
00182 }
00183 
00184 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
00185 
00186 /*
00187  * Restores the state of a trie search to the point from which insertion
00188  * is to begin.  This includes readying the term stack with the remaining
00189  * portion of the term set, restandardizing any variables already
00190  * encountered, and noting these bindings on the trail.
00191  */
00192 
00193 void *stl_restore_variant_cont(CTXTdecl) {
00194 
00195   int i;
00196 
00197   TermStack_ResetTOS;
00198   TermStack_PushArray(variant_cont.subterms.stack.ptr,
00199                       variant_cont.subterms.num);
00200 
00201   Trail_ResetTOS;
00202   for (i = 0; i < (int) variant_cont.bindings.num; i++) {
00203     Trail_Push(variant_cont.bindings.stack.ptr[i].var);
00204     bld_ref(variant_cont.bindings.stack.ptr[i].var,
00205             variant_cont.bindings.stack.ptr[i].value);
00206   }
00207   return (variant_cont.last_node_matched);
00208 }
00209 
00210 /*-------------------------------------------------------------------------*/
00211 
00212 /*
00213  *                   Points of Choice During the Search
00214  *                   ----------------------------------
00215  *
00216  *  State information is saved so the search may resume from that point
00217  *  down an alternate path in the trie.  This allows for an efficient
00218  *  iterative traversal of the trie.
00219  */
00220 
00221 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
00222 
00223 /* Choice Point Stack and Operations
00224    --------------------------------- */
00225 
00226 #ifndef MULTI_THREAD
00227 static struct tstCCPStack_t tstCCPStack;
00228 #endif
00229 
00230 /**** Use these to access the frame to which `top' points ****/
00231 #define CPF_AlternateNode       ((tstCCPStack.top)->alt_node)
00232 #define CPF_VariableChain       ((tstCCPStack.top)->var_chain)
00233 #define CPF_TermStackTopIndex   ((tstCCPStack.top)->termstk_top_index)
00234 #define CPF_TermStackLogTopIndex        ((tstCCPStack.top)->log_top_index)
00235 #define CPF_TrailTopIndex       ((tstCCPStack.top)->trail_top_index)
00236 
00237 /**** TST CP Stack Operations ****/
00238 #define CPStack_ResetTOS     tstCCPStack.top = tstCCPStack.base
00239 #define CPStack_IsEmpty      (tstCCPStack.top == tstCCPStack.base)
00240 #define CPStack_IsFull       (tstCCPStack.top == tstCCPStack.ceiling)
00241 #define CPStack_OverflowCheck                           \
00242    if (CPStack_IsFull)                                  \
00243      SubsumptiveTrieLookupError("tstCCPStack overflow!")
00244 
00245 /*
00246  *  All that is assumed on CP creation is that the term stack and log have
00247  *  been altered for the subterm under consideration.  Any additional changes
00248  *  necessary to continue the search, e.g., pushing functor args or trailing
00249  *  a variable, must be made AFTER a CPF is pushed.  In this way, the old
00250  *  state is still accessible.
00251  */
00252 
00253 #define CPStack_PushFrame(AltNode, VarChain) {  \
00254    CPStack_OverflowCheck;                       \
00255    CPF_AlternateNode = AltNode;                 \
00256    CPF_VariableChain = VarChain;                \
00257    CPF_TermStackTopIndex =                      \
00258      TermStack_Top - TermStack_Base + 1;        \
00259    CPF_TermStackLogTopIndex =                   \
00260      TermStackLog_Top - TermStackLog_Base - 1;  \
00261    CPF_TrailTopIndex = Trail_Top - Trail_Base;  \
00262    tstCCPStack.top++;                           \
00263  }
00264 
00265 /*
00266  *  Resume the state of a saved point of choice.
00267  */
00268 
00269 #define CPStack_PopFrame(CurNode,VarChain) {            \
00270    tstCCPStack.top--;                                   \
00271    CurNode = CPF_AlternateNode;                         \
00272    VarChain = CPF_VariableChain;                        \
00273    TermStackLog_Unwind(CPF_TermStackLogTopIndex);       \
00274    TermStack_SetTOS(CPF_TermStackTopIndex);             \
00275    Trail_Unwind(CPF_TrailTopIndex);                     \
00276  }
00277 
00278 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
00279 
00280 /* Manipulating Choice Points During the Search
00281    -------------------------------------------- */
00282 
00283 /*
00284  * Conditional Choice Points are used after successfully finding an
00285  * exact match between a non-variable Prolog subterm and a symbol in the
00286  * trie.  The condition is whether a TrieVar exists among the siblings
00287  * which could alternately be unified with the subterm.  This check can
00288  * be performed quickly and may result in the avoidance of choice point
00289  * creation.  (Whether the discovered variable is relevant is another
00290  * matter...)
00291  */
00292 
00293 #define Conditionally_Create_ChoicePoint(VariableChain) {       \
00294    BTNptr alternateBTN = VariableChain;                         \
00295                                                                 \
00296    while ( IsNonNULL(alternateBTN) ) {                          \
00297      if ( IsTrieVar(BTN_Symbol(alternateBTN)) ) {               \
00298        CPStack_PushFrame(alternateBTN, VariableChain)           \
00299        break;                                                   \
00300      }                                                          \
00301      alternateBTN = BTN_Sibling(alternateBTN);                  \
00302    }                                                            \
00303  }
00304 
00305 
00306 /*
00307  * We unconditionally lay a Choice Point whenever we've found a trievar
00308  * binding identical to the call's subterm.  A computation which may
00309  * result in avoiding CPF creation would be expensive (and useless if we
00310  * never return to this CPF), so it might be best to just lay one and
00311  * take your chances that we never use it.  If we do use it, however,
00312  * the additional overhead of having the main algorithm discover that it
00313  * is (nearly) useless isn't too high compared to the computation we
00314  * could have done.  The benefit is that we don't do it unless we have to.
00315  */
00316 
00317 #define Create_ChoicePoint(AlternateBTN,VariableChain)  \
00318    CPStack_PushFrame(AlternateBTN,VariableChain)
00319 
00320 
00321 /*
00322  * Resuming a point of choice additionally involves indicating to the
00323  * search algorithm what sort of pairings should be sought.
00324  */
00325 
00326 #define BacktrackSearch {                       \
00327    CPStack_PopFrame(pCurrentBTN,variableChain); \
00328    search_mode = MATCH_WITH_TRIEVAR;            \
00329  }
00330 
00331 /*-------------------------------------------------------------------------*/
00332 
00333 /*
00334  * Initialize the search's choice point stack, the structure for housing
00335  * the variant continuation, and the elements of the TrieVarBindings[]
00336  * array.
00337  */
00338 
00339 void initSubsumptiveLookup(CTXTdecl) {
00340 
00341   int i;
00342 
00343   tstCCPStack.ceiling = tstCCPStack.base + CALL_CPSTACK_SIZE;
00344 
00345   variant_cont.subterms.stack.ptr = NULL;
00346   variant_cont.bindings.stack.ptr = NULL;
00347   variant_cont.subterms.stack.size =
00348     variant_cont.bindings.stack.size = 0;
00349   
00350   /* set entries to unbound */
00351   for (i = 0; i < NUM_TRIEVARS; i++)
00352     TrieVarBindings[i] = (Cell)(TrieVarBindings + i);
00353 }
00354 
00355 /*-------------------------------------------------------------------------*/
00356 
00357 /* Error Handling
00358    -------------- */
00359 
00360 #define SubsumptiveTrieLookupError(String)   sub_trie_lookup_error(CTXTc String)
00361 
00362 static void sub_trie_lookup_error(CTXTdeclc char *string) {
00363   Trail_Unwind_All;
00364   xsb_abort("Subsumptive Check/Insert Operation:\n\t%s\n", string);
00365 }
00366 
00367 /*-------------------------------------------------------------------------*/
00368 
00369 /* Trie- and Prolog-Variable Handling
00370    ---------------------------------- */
00371 
00372 /*
00373  * A subsumptive trie-search algorithm requires that we track both
00374  * variables appearing in the Prolog terms (for handling nonlinearity of
00375  * these terms in case we have to insert them) and bindings made to the
00376  * trie variables during processing (for handling nonlinearity in a trie
00377  * path).  Therefore we take the following approach.  Prolog variables are
00378  * bound to cells of the VarEnumerator[] array, just as is done during
00379  * term interning.  For noting the bindings made to variables appearing in
00380  * the trie, we employ another array, called TrieVarBindings[], which will
00381  * maintain pointers to dereferenced subterms of the term set.  The Ith
00382  * TrieVar along a particular path is associated with TrieVarBindings[I].
00383  *
00384  * Given that I is the ID of the next unique trievar, upon encountering
00385  * the Jth never-before seen Prolog variable, this Prolog variable is
00386  * bound to the *Ith* cell of VarEnumerator, thereby standardizing it.
00387  * Notice that as a result of using subsumption, variables in the Prolog
00388  * terms can only be "matched" with variables in the trie, and hence there
00389  * will be at least as many variables in a subsuming path of the trie as
00390  * in the Prolog terms themselves.  Therefore, J <= I. As indicated above,
00391  * TrieVarBindings[I] gets the address of the Prolog variable.  By using
00392  * the same array indexer, I, we can determine from a standardized Prolog
00393  * variable the first trievar that has been bound to it, and this enables
00394  * us to find the actual address of this variable so that additional trie
00395  * variables may bind themselves to it, if necessary.  In this way, the
00396  * cells of TrieVarBindings[] is guaranteed to contain DEREFERENCED Prolog
00397  * terms.  (Note that additional dereferencing may lead one to a nonProlog
00398  * (non-Heap or non- Local Stack residing) variable.)
00399  */
00400 
00401 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
00402 
00403 /*
00404  *  Given a trievar number and a prolog subterm (not a VarEnumerator
00405  *  addr), bind the trievar to that subterm and trail the trievar.
00406  */
00407 #define TrieVar_BindToSubterm(TrieVarNum,Subterm)       \
00408    TrieVarBindings[TrieVarNum] = Subterm;               \
00409    Trail_Push(&TrieVarBindings[TrieVarNum])
00410 
00411 /*
00412  *  Given a TrieVar number and a marked PrologVar (bound to a
00413  *  VarEnumerator cell), bind the TrieVar to the variable subterm
00414  *  represented by the marked PrologVar, and trail the TrieVar.
00415  */
00416 #define TrieVar_BindToMarkedPrologVar(TrieVarNum,PrologVarMarker)       \
00417    TrieVarBindings[TrieVarNum] =                                        \
00418      TrieVarBindings[PrologVar_Index(PrologVarMarker)];                 \
00419    Trail_Push(&TrieVarBindings[TrieVarNum])
00420 
00421 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
00422 
00423 /*
00424  *  Given an unmarked, dereferenced Prolog variable and a TrieVar number,
00425  *  mark the variable with this number by setting it to point to the
00426  *  Index-th cell of the VarEnumerator array, and trail the variable.
00427  */
00428 #define PrologVar_MarkIt(DerefedVar,Index)      \
00429    StandardizeVariable(DerefedVar,Index);       \
00430    Trail_Push((CPtr)DerefedVar)
00431 
00432 /*
00433  *  Given a dereferenced Prolog variable, determine whether it has already
00434  *  been marked, i.e. seen during prior processing and hence bound to a
00435  *  VarEnumerator cell.
00436  */
00437 #define PrologVar_IsMarked(pDerefedPrologVar)   \
00438    IsStandardizedVariable(pDerefedPrologVar)
00439 
00440 /*
00441  *  Given an address into VarEnumerator, determine its index in this array.
00442  *  (This index will also correspond to the first trie variable that bound
00443  *   itself to it.)
00444  */
00445 #define PrologVar_Index(VarEnumAddr)  IndexOfStdVar(VarEnumAddr)
00446 
00447 
00448 /*-------------------------------------------------------------------------*/
00449 
00450 /* Algorithmic Shorthands
00451    ---------------------- */
00452 
00453 /*
00454  *  When first stepping onto a particular trie level, we may find
00455  *  ourselves either looking at a hash table header or a trie node in a
00456  *  simple chain.  Given the object first encountered at this level
00457  *  (pointed to by 'pCurrentBTN') and a trie-encoded symbol, determine
00458  *  the node chains on this level which would contain that symbol or
00459  *  contain any trie variables, should either exist.
00460  */
00461 
00462 #define Set_Matching_and_TrieVar_Chains(Symbol,MatchChain,VarChain)     \
00463    if ( IsNonNULL(pCurrentBTN) && IsHashHeader(pCurrentBTN) ) {         \
00464      BTNptr *buckets;                                                   \
00465      BTHTptr pBTHT;                                                     \
00466                                                                         \
00467      pBTHT = (BTHTptr)pCurrentBTN;                                      \
00468      buckets = BTHT_BucketArray(pBTHT);                                 \
00469      MatchChain = buckets[TrieHash(Symbol,BTHT_GetHashSeed(pBTHT))];    \
00470      VarChain = buckets[TRIEVAR_BUCKET];                                \
00471    }                                                                    \
00472    else    /* simple chain of nodes */                                  \
00473      VarChain = MatchChain = pCurrentBTN
00474 
00475 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
00476 
00477 /*
00478  *  As soon as it is known that no variant set of terms exists in the   
00479  *  trie, that component of the current state of the search which is
00480  *  useful for later insertion of the given set of terms is saved in
00481  *  the global VariantContinuation structure.
00482  */
00483 
00484 #define SetNoVariant(LastNodeMatched)                           \
00485    if (variant_path == YES) {                                   \
00486      if ( ! save_variant_continuation(CTXTc LastNodeMatched) )  \
00487        SubsumptiveTrieLookupError("Memory exhausted.");         \
00488      variant_path = NO;                                         \
00489    }
00490 
00491 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
00492 
00493 /* 
00494  *  Exact Matches for Non-Variable Subterms
00495  *  ---------------------------------------
00496  *  Exact matches for non-variable subterms of the call are always looked
00497  *  for first.  Once an exact match has been found, there is no need to
00498  *  search further, since there is at most one occurrence of a symbol at
00499  *  a level below a particular node.  Further exploration will
00500  *  concentrate on pairing the subterm with trie variables.
00501  *
00502  *  After a successful match, a choice point frame is laid, with
00503  *  VariableChain providing the trie-path continuation.  We step down onto
00504  *  the next level of the trie, below the matched node, and then branch
00505  *  back to the major loop of the algorithm.  If no match is found, then
00506  *  execution exits this block with a NULL MatchChain.  MatchChain may be
00507  *  NULL at block entry.
00508  *
00509  *  TermStack_PushOp is provided so that this macro can be used for
00510  *  constants, functor symbols, and lists.  Constants pass in a
00511  *  TermStack_NOOP, while functors use TermStack_PushFunctorArgs(), and
00512  *  lists use TermStack_PushListArgs().
00513  */
00514 
00515 #define NonVarSearchChain_ExactMatch(Symbol,MatchChain,VariableChain,   \
00516                                      TermStack_PushOp)                  \
00517                                                                         \
00518    while ( IsNonNULL(MatchChain) ) {                                    \
00519      if (Symbol == BTN_Symbol(MatchChain)) {                            \
00520        Conditionally_Create_ChoicePoint(VariableChain)                  \
00521        TermStack_PushOp                                                 \
00522        Descend_In_Trie_and_Continue(MatchChain);                        \
00523      }                                                                  \
00524      MatchChain = BTN_Sibling(MatchChain);                              \
00525    }
00526 
00527 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
00528 
00529 /* 
00530  *  Matching Non-Variable Subterms with Bound Trievars
00531  *  --------------------------------------------------
00532  *  After having either (1) failed to find an exact match for the
00533  *  call's non-variable subterm, or (2) backtracked to explore other
00534  *  unifications, we proceed to check for equality of the subterm and
00535  *  the bindings made to previously seen trievars.  (A trie variable
00536  *  whose first occurrence (along the path from the root to here) is
00537  *  at this level would, of course, not have a binding.)  There may be
00538  *  several trievars at a level with such a binding.
00539  *
00540  *  We check for true equality, meaning that variables appearing in both
00541  *  must be identical.  (This is because no part of the call may become
00542  *  futher instantiated as a result of the check/insert operation.)  If
00543  *  they are the same, we succeed, else we continue to look in the chain
00544  *  for a suitable trievar.  Processing a success entails (1) laying a
00545  *  choice point since there may be other pairings in this node chain, (2)
00546  *  moving to the child of the matching node, (3) resetting our search mode
00547  *  to exact matches, and (4) branching back to the major loop of the
00548  *  algorithm.
00549  *
00550  *  If no match is found, then execution exits this block with a NULL
00551  *  'CurNODE'.  'CurNODE' may be NULL at block entry.
00552  */
00553 
00554 #define NonVarSearchChain_BoundTrievar(Subterm,CurNODE,VarChain) {      \
00555                                                                         \
00556    int trievar_index;                                                   \
00557                                                                         \
00558    while ( IsNonNULL(CurNODE) ) {                                       \
00559      if ( IsTrieVar(BTN_Symbol(CurNODE)) &&                             \
00560           ! IsNewTrieVar(BTN_Symbol(CurNODE)) ) {                       \
00561        trievar_index = DecodeTrieVar(BTN_Symbol(CurNODE));              \
00562        if ( are_identical_terms(TrieVarBindings[trievar_index],         \
00563                                 Subterm) ) {                            \
00564          Create_ChoicePoint(BTN_Sibling(CurNODE),VarChain)              \
00565          Descend_In_Trie_and_Continue(CurNODE);                         \
00566        }                                                                \
00567      }                                                                  \
00568      CurNODE = BTN_Sibling(CurNODE);                                    \
00569    }                                                                    \
00570  }
00571 
00572 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
00573 
00574 /* 
00575  *  Matching Non-Variable Subterms with Unbound Trievars
00576  *  ----------------------------------------------------
00577  *  Unifying a call's non-variable subterm with an unbound trievar is
00578  *  the last pairing operation explored.  Only one unbound trievar may
00579  *  occur below a particular node; it is a new (first occurrence of this
00580  *  particular) variable lying along the subpath from the root to the
00581  *  current position in the trie.  Such trievars are tagged with a
00582  *  "first occurrence" marker.  If we don't find one, we exit with a
00583  *  NULL 'VarChain'.  (Node: Because of the hashing scheme, VarChain may
00584  *  contain symbols other than variables; furthermore, it may be empty
00585  *  altogether.)
00586  */
00587 
00588 #define NonVarSearchChain_UnboundTrievar(Subterm,VarChain) {    \
00589                                                                 \
00590    int trievar_index;                                           \
00591                                                                 \
00592    while ( IsNonNULL(VarChain) ) {                              \
00593      if ( IsTrieVar(BTN_Symbol(VarChain)) &&                    \
00594           IsNewTrieVar(BTN_Symbol(VarChain)) ) {                \
00595        trievar_index = DecodeTrieVar(BTN_Symbol(VarChain));     \
00596        TrieVar_BindToSubterm(trievar_index,Subterm);            \
00597        Descend_In_Trie_and_Continue(VarChain);                  \
00598      }                                                          \
00599      VarChain = BTN_Sibling(VarChain);                          \
00600    }                                                            \
00601  }
00602 
00603 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
00604 
00605 /* On a Successful Unification
00606  * ---------------------------
00607  * For continuing with forward execution.  When we find a successful
00608  * pairing, we continue the search with the next subterm on the
00609  * tstTermStack and the children of the trie node that was paired.
00610  */
00611 
00612 #define Descend_In_Trie_and_Continue(PairedBTN)      \
00613    pParentBTN = PairedBTN;                           \
00614    pCurrentBTN = BTN_Child(PairedBTN);               \
00615    search_mode = MATCH_SYMBOL_EXACTLY;               \
00616    goto While_TermStack_NotEmpty
00617 
00618 /*--------------------------------------------------------------------------*/
00619 
00620 /*
00621  *              Subsumptive Trie Lookup Operation (Iterative)
00622  *              ---------------------------------------------
00623  *
00624  * Search a branch of a NON-EMPTY trie for a path representing terms
00625  * which subsume the term set present on the TermStack.  The branch is
00626  * identified by a non-NULL pointer to a trie node which roots the
00627  * branch.  If such a path can be found, return a pointer to the leaf of
00628  * the trie representing this path and indicate the relationship between
00629  * the two sets of terms in the argument `pathType'.  If no such path
00630  * exists, then return NULL in addition to a corresponding value for
00631  * `pathType'.
00632  *
00633  * During the course of the search, once the given term set is known to
00634  * differ from any path in the trie, state information is noted in a
00635  * global structure to enable fast insertion of the given term set at a
00636  * later time, if desired.  Because of this ability, this function
00637  * serves as the basis of the *_subsumptive_search() routines.
00638  *
00639  * Stacks are assumed initialized at invocation and are left dirty upon
00640  * return.  It is up to the caller to prime the stacks before invocation
00641  * and clean up afterwards.  This provides a standard format for
00642  * accepting target terms and allows the caller to inspect the stacks
00643  * afterwards.  In particular, the variables appearing in the terms set,
00644  * as well as the bindings made to the trie variables which permit the
00645  * terms' subsumption by a trie path, are available to the caller.
00646  *
00647  * We can think of a subsumptive algorithm as only allowing one-way
00648  * bindings: from trie variable to subterm.  This particular algorithm
00649  * attempts to minimize the number of bindings needed to match terms
00650  * existing in the trie with those that are given.  This approach allows
00651  * it to immediately converge on a variant entry, should one exist.
00652  * Note, however, that this strategy is greedy, and so a global minimum
00653  * could be missed.  The general strategy for pairing the given term
00654  * set's subterms to trie symbols favors, in order:
00655  *   1) exact matches
00656  *   2) matches to bindings of previously bound trie variables
00657  *   3) pairings with unbound trie variables (causing new bindings)
00658  * The search terminates once the first such subsuming path is
00659  * encountered.
00660  */
00661 
00662 typedef enum Search_Strategy_Mode {
00663   MATCH_SYMBOL_EXACTLY, MATCH_WITH_TRIEVAR
00664 } SearchMode;
00665 
00666 
00667 void *iter_sub_trie_lookup(CTXTdeclc void *trieNode, TriePathType *pathType) {
00668 
00669   BTNptr pParentBTN;
00670 
00671   BTNptr pCurrentBTN;        /* Used for stepping through siblings while
00672                                 looking for a match with subterm */
00673 
00674   BTNptr variableChain;      /* Chain of nodes in which to search for
00675                                 variables in case we cannot find an exact
00676                                 match in the chain headed by pCurrentBTN */
00677 
00678   Cell subterm;              /* The part of the call we are inspecting */
00679 
00680   Cell symbol;               /* subterm, as it would appear in a trie node */
00681 
00682   int trievar_index;         /* temp for converting trievar num encoding */
00683 
00684   xsbBool variant_path;      /* Denotes whether the call is a variant of that
00685                                 represented by the current path.  Search state
00686                                 info is saved when its value changes from YES
00687                                 to NO.  This may only occur once as this
00688                                 procedure begins by looking for a variant
00689                                 representation of the call in the trie. */
00690 
00691   SearchMode search_mode;    /* Depending on the subterm, indicates which type
00692                                 of unifications we are interested in */
00693 
00694 
00695   pParentBTN = trieNode;
00696   CPStack_ResetTOS;
00697   pCurrentBTN = BTN_Child(pParentBTN);
00698   variableChain = NULL;   /* suppress compiler warning */
00699   variant_path = YES;
00700   search_mode = MATCH_SYMBOL_EXACTLY;
00701 
00702   /* Major loop of the algorithm
00703      --------------------------- */
00704  While_TermStack_NotEmpty:
00705 
00706   while ( ! TermStack_IsEmpty ) {
00707     TermStack_Pop(subterm);
00708     TermStackLog_PushFrame;
00709     XSB_Deref(subterm);
00710     switch(cell_tag(subterm)) {
00711       
00712     /* SUBTERM IS A CONSTANT
00713        --------------------- */
00714     case XSB_STRING:
00715     case XSB_INT:
00716     case XSB_FLOAT:
00717       /*
00718        *  NOTE:  A Trie constant looks like a Heap constant.
00719        */
00720       if (search_mode == MATCH_SYMBOL_EXACTLY) {
00721         symbol = EncodeTrieConstant(subterm);
00722         Set_Matching_and_TrieVar_Chains(symbol,pCurrentBTN,variableChain);
00723         NonVarSearchChain_ExactMatch(symbol, pCurrentBTN, variableChain,
00724                                      TermStack_NOOP)
00725         /*
00726          *  We've failed to find an exact match of the constant in a node
00727          *  of the trie, so now we consider bound trievars whose bindings
00728          *  exactly match the constant.
00729          */
00730         pCurrentBTN = variableChain;
00731         SetNoVariant(pParentBTN);
00732       }
00733       NonVarSearchChain_BoundTrievar(subterm,pCurrentBTN,variableChain);
00734         /*
00735          *  We've failed to find an exact match of the constant with a
00736          *  binding of a trievar.  Our last alternative is to bind an
00737          *  unbound trievar to this constant.
00738          */
00739       NonVarSearchChain_UnboundTrievar(subterm,variableChain);
00740       break;
00741 
00742 
00743     /* SUBTERM IS A STRUCTURE
00744        ---------------------- */
00745     case XSB_STRUCT:
00746       /*
00747        *  NOTE:  A trie XSB_STRUCT is a XSB_STRUCT-tagged PSC ptr, while a heap
00748        *          XSB_STRUCT is a XSB_STRUCT-tagged ptr to a PSC ptr.
00749        */
00750       if (search_mode == MATCH_SYMBOL_EXACTLY) {
00751         symbol = EncodeTrieFunctor(subterm);
00752         Set_Matching_and_TrieVar_Chains(symbol,pCurrentBTN,variableChain);
00753         NonVarSearchChain_ExactMatch(symbol, pCurrentBTN, variableChain,
00754                                      TermStack_PushFunctorArgs(subterm))
00755         /*
00756          *  We've failed to find an exact match of the functor's name in
00757          *  a node of the trie, so now we consider bound trievars whose
00758          *  bindings exactly match the subterm.
00759          */
00760         pCurrentBTN = variableChain;
00761         SetNoVariant(pParentBTN);
00762       }
00763       NonVarSearchChain_BoundTrievar(subterm,pCurrentBTN,variableChain);
00764         /*
00765          *  We've failed to find an exact match of the function expression
00766          *  with a binding of a trievar.  Our last alternative is to bind
00767          *  an unbound trievar to this subterm.
00768          */
00769       NonVarSearchChain_UnboundTrievar(subterm,variableChain);
00770       break;
00771 
00772       
00773     /* SUBTERM IS A LIST
00774        ----------------- */
00775     case XSB_LIST:
00776       /*
00777        *  NOTE:  A trie LIST uses a plain LIST tag wherever a recursive
00778        *         substructure begins, while a heap LIST uses a LIST-
00779        *         tagged ptr to a pair of Cells, the first being the head
00780        *         and the second being the recursive tail, possibly another
00781        *         LIST-tagged ptr.
00782        */
00783       if (search_mode == MATCH_SYMBOL_EXACTLY) {
00784         symbol = EncodeTrieList(subterm);
00785         Set_Matching_and_TrieVar_Chains(symbol,pCurrentBTN,variableChain);
00786         NonVarSearchChain_ExactMatch(symbol, pCurrentBTN, variableChain,
00787                                      TermStack_PushListArgs(subterm))
00788         /*
00789          *  We've failed to find a node in the trie with a XSB_LIST symbol, so
00790          *  now we consider bound trievars whose bindings exactly match the
00791          *  actual list subterm.
00792          */
00793         pCurrentBTN = variableChain;
00794         SetNoVariant(pParentBTN);
00795       }
00796       NonVarSearchChain_BoundTrievar(subterm,pCurrentBTN,variableChain);
00797         /*
00798          *  We've failed to find an exact match of the list with a binding
00799          *  of a trievar.  Our last alternative is to bind an unbound
00800          *  trievar to this subterm.
00801          */
00802       NonVarSearchChain_UnboundTrievar(subterm,variableChain);
00803       break;
00804       
00805 
00806     /* SUBTERM IS AN UNBOUND VARIABLE
00807        ------------------------------ */
00808     case XSB_REF:
00809     case XSB_REF1:
00810       /*
00811        *  A never-before-seen variable in the call must always match a
00812        *  free variable in the trie.  We can determine this by checking
00813        *  for a "first occurrence" tag in the trievar encoding.  Let Num
00814        *  be the index of this trievar variable.  Then we bind
00815        *  TrieVarBindings[Num] to 'subterm', the address of the deref'ed
00816        *  unbound call variable.  We also bind the call variable to
00817        *  VarEnumerator[Num] so that we can recognize that the call
00818        *  variable has already been seen.
00819        *
00820        *  When such a call variable is re-encountered, we know which
00821        *  trievar was the first to bind itself to this call variable: we
00822        *  used its index in marking the call variable when we bound it
00823        *  to VarEnumerator[Num].  This tagging scheme allows us to match
00824        *  additional unbound trie variables to it.  Recall that the
00825        *  TrieVarBindings array should contain *real* subterms, and not
00826        *  the callvar tags that we've constructed (the pointers into the
00827        *  VarEnumerator array).  So we must reconstruct a
00828        *  previously-seen variable's *real* address in order to bind a
00829        *  new trievar to it.  We can do this by computing the index of
00830        *  the trievar that first bound itself to it, and look in that
00831        *  cell of the TrieVarBindings array to get the call variable's
00832        *  *real* address.
00833        *
00834        *  Notice that this allows us to match variants.  For if we have
00835        *  a variant up to the point where we encounter a marked callvar,
00836        *  there can be at most one trievar which exactly matches it.  An
00837        *  unbound callvar, then, matches exactly only with an unbound
00838        *  trievar.  Therefore, only when a previously seen callvar must
00839        *  be paired with an unbound trievar to continue the search
00840        *  operation do we say that no variant exists.  (Just as is the
00841        *  case for other call subterm types, the lack of an exact match
00842        *  and its subsequent pairing with an unbound trievar destroys
00843        *  the possibility of a variant.)
00844        */
00845       if (search_mode == MATCH_SYMBOL_EXACTLY) {
00846         if ( IsNonNULL(pCurrentBTN) && IsHashHeader(pCurrentBTN) )
00847           pCurrentBTN = variableChain =
00848             BTHT_BucketArray((BTHTptr)pCurrentBTN)[TRIEVAR_BUCKET];
00849         else
00850           variableChain = pCurrentBTN;
00851 
00852         if ( ! PrologVar_IsMarked(subterm) ) {
00853           /*
00854            *  The subterm is a call variable that has not yet been seen
00855            *  (and hence is not tagged).  Therefore, it can only be paired
00856            *  with an unbound trievar, and there can only be one of these
00857            *  in a chain.  If we find it, apply the unification, mark the
00858            *  callvar, trail them both, and continue.  Otherwise, fail.
00859            *  Note we don't need to lay a CPF since this is the only
00860            *  possible pairing that could result.
00861            */
00862           while( IsNonNULL(pCurrentBTN) ) {
00863             if ( IsTrieVar(BTN_Symbol(pCurrentBTN)) &&
00864                  IsNewTrieVar(BTN_Symbol(pCurrentBTN)) ) {
00865               trievar_index = DecodeTrieVar(BTN_Symbol(pCurrentBTN));
00866               TrieVar_BindToSubterm(trievar_index,subterm);
00867               PrologVar_MarkIt(subterm,trievar_index);
00868               Descend_In_Trie_and_Continue(pCurrentBTN);
00869             }
00870             pCurrentBTN = BTN_Sibling(pCurrentBTN);
00871           }
00872           SetNoVariant(pParentBTN);
00873           break;     /* no pairing, so backtrack */
00874         }
00875       }
00876       /*
00877        *  We could be in a forward or backward execution mode.  In either
00878        *  case, the call variable has been seen before, and we first look
00879        *  to pair this occurrence of the callvar with a trievar that was
00880        *  previously bound to this particular callvar.  Note that there
00881        *  could be several such trievars.  Once we have exhausted this
00882        *  possibility, either immediately or through backtracking, we then
00883        *  allow the binding of an unbound trievar to this callvar.
00884        */
00885       while ( IsNonNULL(pCurrentBTN) ) {
00886         if ( IsTrieVar(BTN_Symbol(pCurrentBTN)) &&
00887              ! IsNewTrieVar(BTN_Symbol(pCurrentBTN)) ) {
00888           trievar_index = DecodeTrieVar(BTN_Symbol(pCurrentBTN));
00889           if ( are_identical_terms(TrieVarBindings[trievar_index],
00890                                       subterm) ) {
00891             Create_ChoicePoint(BTN_Sibling(pCurrentBTN),variableChain);
00892             Descend_In_Trie_and_Continue(pCurrentBTN);
00893           }
00894         }
00895         pCurrentBTN = BTN_Sibling(pCurrentBTN);
00896       }
00897       /*
00898        *  We may have arrived here under several circumstances, but notice
00899        *  that the path we are on cannot be a variant one.  In case the
00900        *  possibility of a variant entry being present was still viable up
00901        *  to now, we save state info in case we need to create a variant
00902        *  entry later.  We now go to our last alternative, that of
00903        *  checking for an unbound trievar to pair with the marked callvar.
00904        *  If one is found, we trail the trievar, create the binding, and
00905        *  continue.  No CPF need be created since there can be at most one
00906        *  new trievar below any given node.
00907        */
00908       SetNoVariant(pParentBTN);
00909 
00910       while( IsNonNULL(variableChain) ) {
00911         if ( IsTrieVar(BTN_Symbol(variableChain)) &&
00912              IsNewTrieVar(BTN_Symbol(variableChain)) ) {
00913           trievar_index = DecodeTrieVar(BTN_Symbol(variableChain));
00914           TrieVar_BindToMarkedPrologVar(trievar_index,subterm);
00915           Descend_In_Trie_and_Continue(variableChain);
00916         }
00917         variableChain = BTN_Sibling(variableChain);
00918       }
00919       break;
00920 
00921     case XSB_ATTV:
00922       xsb_table_error(CTXTc 
00923               "Attributed variables not yet implemented in calls to subsumptive tables.");
00924       break;
00925 
00926     /* SUBTERM HAS UNKNOWN CELL TAG
00927        ---------------------------- */
00928     default:
00929       TrieError_UnknownSubtermTag(subterm);
00930       break;
00931     } /* END switch(cell_tag(subterm)) */
00932 
00933     /*
00934      *  We've reached a dead-end since we were unable to match the
00935      *  current subterm to a trie node.  Therefore, we backtrack to
00936      *  continue the search, or, if there are no more choice point
00937      *  frames -- in which case the trie has been completely searched --
00938      *  we return and indicate that no subsuming path was found.
00939      */
00940     if (! CPStack_IsEmpty)
00941       BacktrackSearch
00942     else {
00943       *pathType = NO_PATH;
00944       return NULL;
00945     }
00946 
00947   } /* END while( ! TermStack_IsEmpty ) */
00948 
00949   /*
00950    *  The TermStack is empty, so we've reached a leaf node representing
00951    *  term(s) which subsumes the given term(s).  Return this leaf and an
00952    *  indication as to whether this path is a variant of or properly
00953    *  subsumes the given term(s).
00954    */
00955   if ( variant_path )
00956     *pathType = VARIANT_PATH;
00957   else
00958     *pathType = SUBSUMPTIVE_PATH;
00959   return pParentBTN;
00960 }
00961 
00962 /*=========================================================================*/
00963 
00964 /*
00965  *                         Variant Trie Lookup
00966  *                         ===================
00967  *
00968  * Searches a branch of a NON-EMPTY trie for a path containing the given
00969  * set of terms.  The branch is identified by a non-NULL pointer to a
00970  * trie node which roots the branch.  The terms, which are stored on the
00971  * Termstack, are compared against the symbols in the nodes lying BELOW
00972  * the given node.  The last node containing a symbol which matches a
00973  * subterm on the TermStack is returned.  If all the terms were matched,
00974  * then this node will be a leaf of the trie.  If no terms were mathced,
00975  * then this node will be the given node.  The second argument is set
00976  * appropriately to inform the caller whether the terms were found.  If
00977  * no matching path is found, then the term symbol which failed to match
00978  * with a trie node is set in the last argument.  If a path was found,
00979  * then the value of this argument is undefined.
00980  *
00981  * The TermStack and TrailStack are not cleared before returning control
00982  * to the caller.  Therefore, in the case of a failed lookup, these
00983  * stacks, together with the failed symbol, contain the remaining
00984  * information necessary to resume an insertion where the lookup
00985  * terminated.  In the case of success, the TrailStack contains the
00986  * variables appearing in the term set.
00987  *
00988  * This function is intended for internal use by the trie search and
00989  * lookup routines.
00990  */
00991 
00992 void *var_trie_lookup(CTXTdeclc void *branchRoot, xsbBool *wasFound,
00993                       Cell *failedSymbol) {
00994 
00995   BTNptr parent;        /* Last node containing a matched symbol */
00996 
00997   Cell symbol = 0;      /* Trie representation of current heap symbol,
00998                            used for matching/inserting into a TSTN */
00999 
01000   int std_var_num;      /* Next available TrieVar index; for standardizing
01001                            variables when interned */
01002 
01003 
01004 #ifdef DEBUG_ASSERTIONS
01005   if ( IsNULL(BTN_Child((BTNptr)branchRoot)) )
01006     TrieError_InterfaceInvariant("var_trie_lookup");
01007 #endif
01008 
01009   parent = branchRoot;
01010   std_var_num = Trail_NumBindings;
01011   while ( ! TermStack_IsEmpty ) {
01012 #ifdef DEBUG_ASSERTIONS
01013     if ( IsLeafNode(parent) )
01014       TrieError_TooManyTerms("var_trie_lookup");
01015 #endif
01016     ProcessNextSubtermFromTrieStacks(symbol,std_var_num);
01017     {
01018       BTNptr chain;
01019       int chain_length;
01020       if ( IsHashHeader(BTN_Child(parent)) ) {
01021         BTHTptr ht = BTN_GetHashHdr(parent);
01022         chain = *CalculateBucketForSymbol(ht,symbol);
01023       }
01024       else
01025         chain = BTN_Child(parent);
01026       SearchChainForSymbol(chain,symbol,chain_length);
01027       if ( IsNonNULL(chain) )
01028         parent = chain;
01029       else {
01030         *wasFound = FALSE;
01031         *failedSymbol = symbol;
01032         return parent;
01033       }
01034     }
01035   }
01036 #ifdef DEBUG_ASSERTIONS
01037   if ( ! IsLeafNode(parent) )
01038     TrieError_TooFewTerms("var_trie_lookup");
01039 #endif
01040   *wasFound = TRUE;
01041   return parent;
01042 }
01043 
01044 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
01045 
01046 /*
01047  * Given a term in the form of an arity and vector of subterms, if the
01048  * term is present in the given trie, returns a pointer to the leaf
01049  * representing the term, otherwise returns NULL.
01050  *
01051  * If the term is found and if an array (a non-NULL pointer) is supplied
01052  * in the last argument, then the variables in the term are copied into
01053  * it, with the 0th element containing the (unencoded) count.  The ith
01054  * encountered variable is placed in array element i.
01055  * 
01056  * Routine used in meta-predicates such as get_call()
01057  */
01058 
01059 void *variant_trie_lookup(CTXTdeclc void *trieRoot, int nTerms, CPtr termVector,
01060                           Cell varArray[]) {
01061 
01062   BTNptr trieNode;
01063   xsbBool wasFound;
01064   Cell symbol;
01065 
01066 
01067 #ifdef DEBUG_ASSERTIONS
01068   if ( IsNULL(trieRoot) || (nTerms < 0) )
01069     TrieError_InterfaceInvariant("variant_trie_lookup()");
01070 #endif
01071 
01072   if ( IsEmptyTrie((BTNptr)trieRoot) )
01073     return NULL;
01074 
01075   if ( nTerms > 0 ) {
01076     Trail_ResetTOS;
01077     TermStack_ResetTOS;
01078     TermStack_PushLowToHighVector(termVector,nTerms);
01079     trieNode = var_trie_lookup(CTXTc trieRoot,&wasFound,&symbol);
01080     if ( wasFound ) {
01081       if ( IsNonNULL(varArray) ) {
01082         int i;
01083 
01084         for ( i = 0;  i < (int) Trail_NumBindings;  i++ )
01085           varArray[i+1] = (Cell)Trail_Base[i];
01086         varArray[0] = i;
01087       }
01088     }
01089     else
01090       trieNode = NULL;
01091     Trail_Unwind_All;
01092   }
01093   else {
01094     trieNode = trie_escape_lookup(trieRoot);
01095     if ( IsNonNULL(trieNode) && IsNonNULL(varArray) )
01096       varArray[0] = 0;
01097   }
01098   return trieNode;
01099 }
01100 
01101 /*=========================================================================*/
01102 
01103 /*
01104  *                   Recursive Subsumptive Trie Lookup
01105  *                   =================================
01106  */
01107 
01108 
01109 /*
01110  * Searches a branch of a NON-EMPTY trie for a path which subsumes a
01111  * given set of terms.  The branch is identified by a non-NULL pointer
01112  * to a trie node which roots the branch.  The terms, which are stored
01113  * on the Termstack, are compared against the symbols in the nodes lying
01114  * BELOW the given node.  If a subsuming path is discovered, then
01115  * returns a pointer to the leaf identifying the path, otherwise returns
01116  * NULL.  The last argument describes the relationship between the
01117  * discovered path, if any, and the given terms.
01118  *
01119  * In addition to the TermStack, the following structures should also be
01120  * primed for use: tstTermStackLog, tstTrail, TrieVarBindings[], and
01121  * VarEnumerator[].
01122  */
01123 
01124 static BTNptr rec_sub_trie_lookup(CTXTdeclc BTNptr parent, TriePathType *pathType) {
01125 
01126   Cell subterm, symbol;
01127   BTNptr cur, match, var, leaf;
01128   int arity, trievar_index;
01129   CPtr args;
01130 
01131 
01132 #ifdef DEBUG_ASSERTIONS
01133   if ( IsNULL(parent) )
01134     TrieError_InterfaceInvariant("rec_sub_trie_lookup");
01135 #endif
01136 
01137   /*
01138    * Base Case:
01139    * ---------
01140    * We've paired a subterm with a term in the trie.  How this trie
01141    * term relates to the subterm will be set as we unroll the
01142    * recursion.  Return a handle for this trie term.
01143    */
01144   if ( TermStack_IsEmpty ) {
01145 #ifdef DEBUG_ASSERTIONS
01146     if ( ! IsLeafNode(parent) )
01147       TrieError_TooFewTerms("rec_sub_trie_lookup");
01148     xsb_dbgmsg((LOG_TRIE, "Base case: empty TermStack"));
01149 #endif
01150     return parent;
01151   }
01152 
01153 #ifdef DEBUG_ASSERTIONS
01154   if ( IsLeafNode(parent) )
01155     TrieError_TooManyTerms("rec_sub_trie_lookup");
01156 #endif
01157 
01158   /*
01159    * Recursive Case:
01160    * --------------
01161    * Find a pairing of the next subterm on the TermStack with a symbol
01162    * in the trie below 'parent.'  If one is found, then recurse.
01163    * Otherwise, signal the failure of the exploration of this branch
01164    * by returning NULL.
01165    */
01166   xsb_dbgmsg((LOG_TRIE, "Recursive case:"));
01167   TermStack_Pop(subterm);
01168   TermStackLog_PushFrame;
01169   XSB_Deref(subterm);
01170   if ( isref(subterm) ) {
01171 
01172     /* Handle Call Variables
01173        ===================== */
01174 
01175     if ( IsHashHeader(BTN_Child(parent)) )
01176       var = BTHT_BucketArray(BTN_GetHashHdr(parent))[TRIEVAR_BUCKET];
01177     else
01178       var = BTN_Child(parent);
01179 
01180     if ( ! IsStandardizedVariable(subterm) ) {
01181       xsb_dbgmsg((LOG_TRIE,"  Found new call variable: "));
01182 
01183       /*
01184        * Pair this free call variable with a new trie variable (there is at
01185        * most one of these among a set of child nodes).  Mark the call var to
01186        * indicate that it has already been seen, in case of repeated
01187        * occurrences in the call.  Bind the trie var to the call var and
01188        * trail them both.
01189        */
01190       for ( cur = var;  IsNonNULL(cur);  cur = BTN_Sibling(cur) )
01191         if ( IsTrieVar(BTN_Symbol(cur)) && IsNewTrieVar(BTN_Symbol(cur)) ) {
01192           xsb_dbgmsg((LOG_TRIE, "  Binding it to free trievar"));
01193           trievar_index = DecodeTrieVar(BTN_Symbol(cur));
01194           /*** TrieVar_BindToSubterm(trievar_index,subterm); ***/
01195           TrieVarBindings[trievar_index] = subterm;
01196           Trail_Push(&TrieVarBindings[trievar_index]);
01197           /*** CallVar_MarkIt(subterm,trievar_index); ***/
01198           StandardizeVariable(subterm,trievar_index);
01199           Trail_Push(subterm);
01200           leaf = rec_sub_trie_lookup(CTXTc cur,pathType);
01201           if ( IsNonNULL(leaf) ) {
01202             if ( *pathType == NO_PATH )
01203               *pathType = VARIANT_PATH;
01204             return leaf;
01205           }
01206           else {
01207           xsb_dbgmsg((LOG_TRIE, 
01208                      " Binding to free trievar didn't lead to valid path"));
01209             Trail_PopAndReset;
01210             Trail_PopAndReset;
01211             break;
01212           }
01213         }
01214       xsb_dbgmsg((LOG_TRIE, "No free trievar here"));
01215     }
01216     else {
01217       xsb_dbgmsg((LOG_TRIE, "  Found repeat call variable\n"
01218                  "  Option #1: Look to pair with repeat trie var"));
01219       /*
01220        * Option 1: Look for a nonlinear trie variable which has already been
01221        * --------  bound to this nonlinear call variable earlier in the
01222        *           search.  There may be more than one.
01223        */
01224       for ( cur = var;  IsNonNULL(cur);  cur = BTN_Sibling(cur) )
01225         if ( IsTrieVar(BTN_Symbol(cur)) &&
01226              ! IsNewTrieVar(BTN_Symbol(cur)) ) {
01227           trievar_index = DecodeTrieVar(BTN_Symbol(cur));
01228           /***********************************************
01229              could just compare
01230                  *(TrieVarBindings[trievar_index]) -to- subterm
01231                                   - OR -
01232                  TrieVarBindings[trievar_index]
01233                    -to- TrieVarBindings[IndexOfStdVar(subterm)]
01234           ***********************************************/
01235           if ( are_identical_terms(TrieVarBindings[trievar_index],
01236                                    subterm) ) {
01237             xsb_dbgmsg((LOG_TRIE, "  Found trivar with identical binding"));
01238             leaf = rec_sub_trie_lookup(CTXTc cur,pathType);
01239             if ( IsNonNULL(leaf) ) {
01240               /*
01241                * This may or may not be a variant path, depending on what has
01242                * happened higher-up in the trie.  We therefore make a
01243                * conservative "guess" and leave it to be determined at that
01244                * point during the recursive unrolling.
01245                */
01246               if ( *pathType == NO_PATH )
01247                 *pathType = VARIANT_PATH;
01248               return leaf;
01249             }
01250             else
01251               xsb_dbgmsg((LOG_TRIE, 
01252                          "  Pairing with identically bound trievar didn't lead"
01253                          " to valid path"));
01254           }
01255         }
01256       /*
01257        * Option 2: Bind the nonlinear call variable with an unbound trie
01258        * --------  variable.  There is only one of these in a sibling set.
01259        */    
01260       xsb_dbgmsg((LOG_TRIE, 
01261                  "  Option #2: Bind new trievar to repeat call var"));
01262       for ( cur = var;  IsNonNULL(cur);  cur = BTN_Sibling(cur) )
01263         if ( IsTrieVar(BTN_Symbol(cur)) && IsNewTrieVar(BTN_Symbol(cur)) ) {
01264           xsb_dbgmsg((LOG_TRIE, "    Found new trievar; binding it"));
01265           trievar_index = DecodeTrieVar(BTN_Symbol(cur));
01266           /*** TrieVar_BindToMarkedCallVar(trievar_index,subterm); ***/
01267           TrieVarBindings[trievar_index] =
01268             TrieVarBindings[IndexOfStdVar(subterm)];
01269           Trail_Push(&TrieVarBindings[trievar_index]);
01270           leaf = rec_sub_trie_lookup(CTXTc cur,pathType);
01271           if ( IsNonNULL(leaf) ) {
01272             *pathType = SUBSUMPTIVE_PATH;
01273             return leaf;
01274           }
01275           else {
01276       xsb_dbgmsg((LOG_TRIE, 
01277                  "    Binding new trievar to repeat callvar didn't lead to"
01278                  " valid path"));
01279             Trail_PopAndReset;
01280             break;
01281           }
01282         }
01283     }
01284   }
01285   else {
01286 
01287     /* Handle NonVariable Subterms
01288        =========================== */
01289     /*
01290      * The following should trie-encode the first symbol of subterm and
01291      * record any recursive components of subterm (for reconstitution later,
01292      * if needed).
01293      */
01294     if ( isconstant(subterm) ) {      /* XSB_INT, XSB_FLOAT, XSB_STRING */
01295       xsb_dbgmsg((LOG_TRIE, "  Found constant"));
01296       symbol = EncodeTrieConstant(subterm);
01297       arity = 0;
01298       args = NULL;
01299     }
01300     else if ( isconstr(subterm) ) {   /* XSB_STRUCT */
01301       xsb_dbgmsg((LOG_TRIE, "  Found structure"));
01302       symbol = EncodeTrieFunctor(subterm);
01303       arity = get_arity((Psc)*clref_val(subterm));
01304       args = clref_val(subterm) + 1;
01305     }
01306     else if ( islist(subterm) ) {     /* XSB_LIST */
01307       xsb_dbgmsg((LOG_TRIE, "  Found list"));
01308       symbol = EncodeTrieList(subterm);
01309       arity = 2;
01310       args = clref_val(subterm);
01311     }
01312     else {
01313       Trail_Unwind_All;
01314       xsb_abort("rec_sub_trie_lookup(): bad tag");
01315       *pathType = NO_PATH;
01316       return NULL;
01317     }
01318 
01319     /*
01320      * Determine the node chains below 'parent' where 'symbol' and trie
01321      * variables may exist.
01322      */
01323     if ( IsHashHeader(BTN_Child(parent)) ) {
01324       BTNptr *buckets;
01325       BTHTptr ht;
01326 
01327       ht = BTN_GetHashHdr(parent);
01328       buckets = BTHT_BucketArray(ht);
01329       match = buckets[TrieHash(symbol,BTHT_GetHashSeed(ht))];
01330       var = buckets[TRIEVAR_BUCKET];
01331     }
01332     else  /* the children are arranged as a simple chain of nodes */
01333       var = match = BTN_Child(parent);
01334 
01335     /*
01336      * Option 1: Look for an identical symbol in the trie.  There is at most
01337      * --------  one of these among a set of child nodes.
01338      */
01339     xsb_dbgmsg((LOG_TRIE, "  Nonvar Option #1: Find matching symbol in trie"));
01340     for ( cur = match;  IsNonNULL(cur);  cur = BTN_Sibling(cur) )
01341       if ( symbol == BTN_Symbol(cur) ) {
01342         int origTermStackTopIndex = TermStack_Top - TermStack_Base;
01343         xsb_dbgmsg((LOG_TRIE, "  Found matching trie symbol"));
01344         TermStack_PushLowToHighVector(args,arity);
01345         leaf = rec_sub_trie_lookup(CTXTc cur,pathType);
01346         if ( IsNonNULL(leaf) ) {
01347           if ( *pathType == NO_PATH )
01348             *pathType = VARIANT_PATH;
01349           return leaf;
01350         }
01351         else {
01352           /* Could not successfully continue from this match, so try another
01353              pairing, performed below.  Throw away whatever was pushed onto
01354              the TermStack above by resetting the top-of-stack pointer. */
01355           xsb_dbgmsg((LOG_TRIE, 
01356                      "  Matching trie symbol didn't lead to valid path"));
01357           TermStack_SetTOS(origTermStackTopIndex);
01358           break;
01359         }
01360       }
01361 
01362     /*
01363      * Option 2: Look for a trie variable which has already been bound to
01364      * --------  an identical symbol during this process.
01365      */
01366     xsb_dbgmsg((LOG_TRIE, 
01367                "  Nonvar Option #2: Match with previously bound trievar"));
01368     for ( cur = var;  IsNonNULL(cur);  cur = BTN_Sibling(cur) )
01369       if ( IsTrieVar(BTN_Symbol(cur)) && ! IsNewTrieVar(BTN_Symbol(cur)) ) {
01370         trievar_index = DecodeTrieVar(BTN_Symbol(cur));
01371         if ( are_identical_terms(TrieVarBindings[trievar_index],
01372                                     subterm) ) {
01373           xsb_dbgmsg((LOG_TRIE, "  Found trievar bound to matching symbol"));
01374           leaf = rec_sub_trie_lookup(CTXTc cur,pathType);
01375           if ( IsNonNULL(leaf) ) {
01376             *pathType = SUBSUMPTIVE_PATH;
01377             return leaf;
01378           }
01379           else
01380             xsb_dbgmsg((LOG_TRIE, "  Bound trievar didn't lead to valid path"));
01381         }
01382       }
01383 
01384     /*
01385      * Option 3: Bind the symbol with an unbound trie variable.
01386      * --------
01387      */
01388     xsb_dbgmsg((LOG_TRIE, "  Nonvar Option #3: Bind free trievar to symbol"));
01389     for ( cur = var;  IsNonNULL(cur);  cur = BTN_Sibling(cur) )
01390       if ( IsTrieVar(BTN_Symbol(cur)) && IsNewTrieVar(BTN_Symbol(cur)) ) {
01391         xsb_dbgmsg((LOG_TRIE, "  Binding free trievar to symbol"));
01392         trievar_index = DecodeTrieVar(BTN_Symbol(cur));
01393         /*** TrieVar_BindToSubterm(trievar_index,subterm); ***/
01394         TrieVarBindings[trievar_index] = subterm;
01395         Trail_Push(&TrieVarBindings[trievar_index]);
01396         leaf = rec_sub_trie_lookup(CTXTc cur,pathType);
01397         if ( IsNonNULL(leaf) ) {
01398           *pathType = SUBSUMPTIVE_PATH;
01399           return leaf;
01400         }
01401         else {
01402           /* Remove the binding from the variable created above, exit the
01403              loop, and drop through to fail; this was our last option.  Note
01404              that there is only one unbound trie variable per sibling set. */
01405           xsb_dbgmsg((LOG_TRIE, 
01406                      "Binding free trievar to symbol didn't lead to "
01407                      "valid path"));
01408           Trail_PopAndReset;
01409           break;
01410         }
01411       }
01412   }
01413 
01414   /* Nothing worked, so fail.  Make stacks same as when this was called. */
01415   xsb_dbgmsg((LOG_TRIE, "All options failed!"));
01416   TermStackLog_PopAndReset;
01417   *pathType = NO_PATH;
01418   return NULL;
01419 }
01420 
01421 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
01422 
01423 /*
01424  * Given a term as an arity and array of subterms, determines whether
01425  * there exists a subsuming path in the given trie.  A pointer to the
01426  * leaf of the discovered path, if any, is returned, and a flag is set
01427  * to indicate how the path relates to the subterm.
01428  */
01429 
01430 void *subsumptive_trie_lookup(CTXTdeclc void *trieRoot, int nTerms, CPtr termVector,
01431                               TriePathType *path_type, Cell subtermArray[]) {
01432 
01433   BTNptr leaf;
01434 
01435 
01436 #ifdef DEBUG_ASSERTIONS
01437   if ( IsNULL(trieRoot) || (nTerms < 0) )
01438     TrieError_InterfaceInvariant("subsumptive_trie_lookup()");
01439 #endif
01440 
01441   *path_type = NO_PATH;
01442   if ( IsEmptyTrie((BTNptr)trieRoot) )
01443     return NULL;
01444 
01445   if ( nTerms > 0) {
01446     Trail_ResetTOS;
01447     TermStackLog_ResetTOS;
01448     TermStack_ResetTOS;
01449     TermStack_PushLowToHighVector(termVector,nTerms);
01450     leaf = rec_sub_trie_lookup(CTXTc trieRoot, path_type);
01451     if ( IsNonNULL(leaf) && IsNonNULL(subtermArray) ) {
01452       int i;
01453       for ( i = 0;
01454             TrieVarBindings[i] != (Cell) (& TrieVarBindings[i]);
01455             i++ )
01456         subtermArray[i+1] = TrieVarBindings[i];
01457       subtermArray[0] = i;
01458     }
01459     Trail_Unwind_All;
01460     dbg_printTriePathType(LOG_TRIE, stddbg, *path_type, leaf);
01461   }
01462   else {
01463     leaf = trie_escape_lookup(trieRoot);
01464     if ( IsNonNULL(leaf) ) {
01465       *path_type = VARIANT_PATH;
01466       if ( IsNonNULL(subtermArray) )
01467         subtermArray[0] = 0;
01468     }
01469   }
01470   return leaf;
01471 }
01472 
01473 /*=========================================================================*/

Generated on Wed Jul 26 13:30:43 2006 for XSB by  doxygen 1.4.5