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 /*=========================================================================*/