tst_retrv.c

00001 /* File:      tst_retrv.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: tst_retrv.c,v 1.23 2006/01/12 21:33:53 tswift Exp $
00022 ** 
00023 */
00024 
00025 
00026 #include "xsb_config.h"
00027 #include "xsb_debug.h"
00028 
00029 #include <stdio.h>
00030 #include <stdlib.h>
00031 
00032 #include "auxlry.h"
00033 #include "cell_xsb.h"
00034 #include "inst_xsb.h"
00035 #include "register.h"
00036 #include "memory_xsb.h"
00037 #include "error_xsb.h"
00038 #include "psc_xsb.h"
00039 #include "deref.h"
00040 #include "binding.h"
00041 #include "cut_xsb.h"       /* trail frame field access macros */
00042 #include "sw_envs.h"
00043 #include "subp.h"          /* xsbBool unify(CTXTc Cell, Cell) */
00044 #include "table_stats.h"
00045 #include "trie_internals.h"
00046 #include "macro_xsb.h"
00047 #include "tst_aux.h"
00048 #include "tst_utils.h"
00049 #include "debug_xsb.h"
00050 #include "flags_xsb.h"
00051 #include "thread_xsb.h"
00052 
00053 /*  Data Structures and Related Macros
00054     ==================================  */
00055 
00056 /*
00057  *  Trailing
00058  *  --------
00059  *  Record bindings made during the search through the trie so that
00060  *  these variables can be unbound when an alternate path is explored.
00061  *  We will use XSB's system Trail to accomodate XSB's unification
00062  *  algorithm, which is needed at certain points in the collection
00063  *  process.
00064  */
00065 
00066 #ifndef MULTI_THREAD
00067 static CPtr *trail_base;    /* ptr to topmost used Cell on the system Trail;
00068                                the beginning of our local trail for this
00069                                operation. */
00070 
00071 static CPtr *orig_trreg;            
00072 static CPtr orig_hreg;      /* Markers for noting original values of WAM */
00073 static CPtr orig_hbreg;     /* registers so they can be reset upon exiting */
00074 static CPtr orig_ebreg;
00075 #endif
00076 
00077 /* 
00078  * Set backtrack registers to the tops of stacks to force trailing in
00079  * unify().  Save hreg as the heap may be used to construct bindings.
00080  */
00081 #define Save_and_Set_WAM_Registers      \
00082    orig_hbreg = hbreg;                  \
00083    orig_hreg = hbreg = hreg;            \
00084    orig_ebreg = ebreg;                  \
00085    ebreg = top_of_localstk;             \
00086    orig_trreg = trreg;                  \
00087    trreg = top_of_trail
00088 
00089 #define Restore_WAM_Registers           \
00090    trreg = orig_trreg;                  \
00091    hreg = orig_hreg;                    \
00092    hbreg = orig_hbreg;                  \
00093    ebreg = orig_ebreg
00094 
00095 /* TLS: 12/05.  There was an bug in the routine
00096    tst_collect_relevant_answers().  This routine used Bind_and_Trail
00097    or Bind_and_Conditionally Trail (see old copies below) to bind trie
00098    symbols to variables in the answer template (substitution factor).
00099    For some reason these macros trailed, but did not actually bind.
00100    This meant that answers were occasionlly being returned to subsumed
00101    calls that didn't actually unify with these calls.  It didn't seem
00102    to happen often -- only when an subsumed call S_d has a
00103    variable/variable binding that a subsuming call S_g does not have
00104    AND S_d and S_g are in the same SCC.  Apparently we have not often
00105    encountered both of these cases at the same time (or tested for
00106    them).
00107 */
00108 /*
00109  *  Create a binding and conditionally trail it.  TrieVarBindings[] cells
00110  *  are always trailed, while those in the WAM stacks are trailed based on
00111  *  the traditional trailing test.  As we traverse the TST and lay choice
00112  *  points, we update the hbreg as in the WAM since structures may be
00113  *  built on the heap for binding.  Therefore, this condition serves as in
00114  *  the WAM.
00115  */
00116 
00117 #define Trie_bind_copy(Addr,Val)                \
00118   Trie_Conditionally_Trail(Addr,Val);           \
00119   *(Addr) = Val
00120 
00121 #define Trie_Conditionally_Trail(Addr, Val)             \
00122    if ( IsUnboundTrieVar(Addr) || conditional(Addr) )   \
00123      { pushtrail0(Addr, Val) }
00124 
00125 #define Bind_and_Conditionally_Trail(Addr, Val) Trie_bind_copy(Addr,Val) \
00126 
00127 /*
00128  *  Create a binding and trail it.
00129  */
00130 #define Bind_and_Trail(Addr, Val)       pushtrail0(Addr, Val)   \
00131   *(Addr) = Val
00132 
00133 /*******************************************
00134 OLD VERSIONS
00135  * #define Bind_and_Trail(Addr, Val)    pushtrail0(Addr, Val)
00136 
00137  * #define Bind_and_Conditionally_Trail(Addr, Val)      \
00138  *  if ( IsUnboundTrieVar(Addr) || conditional(Addr) )  \
00139  *    { pushtrail0(Addr, Val) }
00140  *******************************************/
00141 
00142 
00143 #define Sys_Trail_Unwind(UnwindBase)      table_undo_bindings(UnwindBase)
00144 
00145 /* ------------------------------------------------------------------------- */
00146 
00147 /*
00148  *  tstCPStack
00149  *  ----------
00150  *  For saving state information so the search may resume from that
00151  *  point down an alternate path in the time-stamped trie.
00152  */
00153 
00154 #ifndef MULTI_THREAD
00155 static struct tstCPStack_t tstCPStack;
00156 #endif
00157 
00158 /* Use these to access the frame to which `top' points */
00159 #define tstCPF_AlternateNode    ((tstCPStack.top)->alt_node)
00160 #define tstCPF_TermStackTopIndex     ((tstCPStack.top)->ts_top_index)
00161 #define tstCPF_TSLogTopIndex         ((tstCPStack.top)->log_top_index)
00162 #define tstCPF_TrailTop         ((tstCPStack.top)->trail_top)
00163 #define tstCPF_HBreg            ((tstCPStack.top)->heap_bktrk)
00164 
00165 #define CPStack_IsEmpty    (tstCPStack.top == tstCPStack.base)
00166 #define CPStack_IsFull     (tstCPStack.top == tstCPStack.ceiling)
00167 
00168 void initCollectRelevantAnswers(CTXTdecl) {
00169 
00170   tstCPStack.ceiling = tstCPStack.base + TST_CPSTACK_SIZE;
00171 }
00172 
00173 #define CPStack_PushFrame(AlternateTSTN)                                \
00174    if ( IsNonNULL(AlternateTSTN) ) {                                    \
00175      CPStack_OverflowCheck                                              \
00176      tstCPF_AlternateNode = AlternateTSTN;                              \
00177      tstCPF_TermStackTopIndex = TermStack_Top - TermStack_Base + 1;     \
00178      tstCPF_TSLogTopIndex = TermStackLog_Top - TermStackLog_Base;       \
00179      tstCPF_TrailTop = trreg;                                           \
00180      tstCPF_HBreg = hbreg;                                              \
00181      hbreg = hreg;                                                      \
00182      tstCPStack.top++;                                                  \
00183    }
00184 
00185 #define CPStack_Pop     tstCPStack.top--
00186 
00187 /*
00188  *  Backtracking to a previous juncture in the trie.
00189  */
00190 #define TST_Backtrack                           \
00191    CPStack_Pop;                                 \
00192    ResetParentAndCurrentNodes;                  \
00193    RestoreTermStack;                            \
00194    Sys_Trail_Unwind(tstCPF_TrailTop);           \
00195    ResetHeap_fromCPF
00196 
00197 /*
00198  *  For continuing with forward execution.  When we match, we continue
00199  *  the search with the next subterm on the tstTermStack and the children
00200  *  of the trie node that was matched.
00201  */
00202 #define Descend_Into_TST_and_Continue_Search    \
00203    parentTSTN = cur_chain;                      \
00204    cur_chain = TSTN_Child(cur_chain);           \
00205    goto While_TSnotEmpty
00206 
00207 /*
00208  * Not really necessary to set the parent since it is only needed once a
00209  * leaf is reached and we step (too far) down into the trie, but that's
00210  * when its value is set.
00211  */
00212 #define ResetParentAndCurrentNodes              \
00213    cur_chain = tstCPF_AlternateNode;            \
00214    parentTSTN = TSTN_Parent(cur_chain)
00215 
00216 
00217 #define RestoreTermStack                        \
00218    TermStackLog_Unwind(tstCPF_TSLogTopIndex);   \
00219    TermStack_SetTOS(tstCPF_TermStackTopIndex)
00220 
00221 
00222 #define ResetHeap_fromCPF                       \
00223    hreg = hbreg;                                \
00224    hbreg = tstCPF_HBreg
00225 
00226 
00227 #define CPStack_OverflowCheck                                           \
00228    if (CPStack_IsFull)                                                  \
00229      TST_Collection_Error("tstCPStack overflow.", RequiresCleanup)
00230 
00231 /* ========================================================================= */
00232 
00233 /*  General Macro Utilities
00234     =======================  */
00235 
00236 /*
00237  *  Determine whether the TSTN's timestamp allows it to be selected.
00238  */
00239 #define IsValidTS(SymbolTS,CutoffTS)      (SymbolTS > CutoffTS)
00240 
00241 /*
00242  *  Create a new answer-list node, set it to point to an answer,  
00243  *  and place it at the head of a chain of answer-list nodes.
00244  *  For MT engine: use only for private,subsumed tables.
00245  */
00246 #define ALN_InsertAnswer(pAnsListHead,pAnswerNode) {                    \
00247     ALNptr newAnsListNode;                                              \
00248     New_Private_ALN(newAnsListNode,(void *)pAnswerNode,pAnsListHead);   \
00249     pAnsListHead = newAnsListNode;                                      \
00250   }
00251 
00252 /*
00253  *  Error handler for the collection algorithm.
00254  */
00255 #define RequiresCleanup    TRUE
00256 #define NoCleanupRequired  FALSE
00257 
00258 #define TST_Collection_Error(String, DoesRequireCleanup) {      \
00259    tstCollectionError(CTXTc String, DoesRequireCleanup);        \
00260    return NULL;                                                 \
00261  }
00262 
00263 static void tstCollectionError(CTXTdeclc char *string, xsbBool cleanup_needed) {
00264   fprintf(stderr, "Error encountered in Time-Stamped Trie "
00265           "Collection algorithm!\n");
00266   if (cleanup_needed) {
00267     Sys_Trail_Unwind(trail_base);
00268     Restore_WAM_Registers;
00269   }
00270   xsb_abort(string);
00271 }
00272 
00273 
00274 /* ========================================================================= */
00275 
00276 /*
00277  *  Algorithmic Shorthands
00278  *  ======================
00279  */
00280 
00281 
00282 #define backtrack      break
00283 
00284 
00285 /*
00286  *  Return the first TSTN in a chain with a valid timestamp (if one exists),
00287  *  otherwise return NULL.
00288  */
00289 #define Chain_NextValidTSTN(Chain,TS,tsAccessMacro)                     \
00290    while ( IsNonNULL(Chain) && (! IsValidTS(tsAccessMacro(Chain),TS)) ) \
00291      Chain = TSTN_Sibling(Chain)
00292 
00293 /*
00294  *  Return the next TSTN in the TSI with a valid timestamp (if one exists),
00295  *  otherwise return NULL.
00296  */
00297 #define TSI_NextValidTSTN(ValidTSIN,TS)                         \
00298    ( ( IsNonNULL(TSIN_Next(ValidTSIN)) &&                       \
00299        IsValidTS(TSIN_TimeStamp(TSIN_Next(ValidTSIN)),TS) )     \
00300      ? TSIN_TSTNode(TSIN_Next(ValidTSIN))                       \
00301      : NULL )
00302 
00303 /* ------------------------------------------------------------------------- */
00304 
00305 #define SetMatchAndUnifyChains(Symbol,SymChain,VarChain) {      \
00306                                                                 \
00307    TSTHTptr ht = (TSTHTptr)SymChain;                            \
00308    TSTNptr *buckets = TSTHT_BucketArray(ht);                    \
00309                                                                 \
00310    SymChain = buckets[TrieHash(Symbol,TSTHT_GetHashSeed(ht))];  \
00311    VarChain = buckets[TRIEVAR_BUCKET];                          \
00312  }
00313 
00314 /* ------------------------------------------------------------------------- */
00315 
00316 /* 
00317  *  Exact matches are only looked for in cases where the TSTN is hashed
00318  *  and the subterm hashes to a bucket different from TRIEVAR_BUCKET.
00319  *  Once a match has been found, there is no need to search further since
00320  *  there is only one occurrance of a symbol in any chain.  If the node's
00321  *  timestamp is valid then the state is saved, with bucket TRIEVAR_BUCKET
00322  *  as the TSTN continuation, and we branch back to the major loop of the
00323  *  algorithm.  If the timestamp is not valid, then we exit the loop.  If
00324  *  no match is found, then execution exits this block with a NULL
00325  *  cur_chain.  cur_chain may be NULL at block entry.
00326  *
00327  *  TermStack_PushOp is provided so that this macro can be used for all
00328  *  nonvariable symbols.  Constants pass in TermStack_NOOP, functors use
00329  *  TermStack_PushFunctorArgs(), and lists useTermStack_PushListArgs().
00330  */
00331 
00332 #define SearchChain_ExactMatch(SearchChain,TrieEncodedSubterm,TS,       \
00333                                ContChain,TermStack_PushOp)              \
00334    while ( IsNonNULL(SearchChain) ) {                                   \
00335      if ( TrieEncodedSubterm == TSTN_Symbol(SearchChain) ) {            \
00336        if ( IsValidTS(TSTN_GetTSfromTSIN(SearchChain),TS) ) {           \
00337          Chain_NextValidTSTN(ContChain,TS,TSTN_GetTSfromTSIN);          \
00338          CPStack_PushFrame(ContChain);                                  \
00339          TermStackLog_PushFrame;                                        \
00340          TermStack_PushOp;                                              \
00341          Descend_Into_TST_and_Continue_Search;                          \
00342        }                                                                \
00343        else                                                             \
00344          break;   /* matching symbol's TS is too old */                 \
00345      }                                                                  \
00346      SearchChain = TSTN_Sibling(SearchChain);                           \
00347    }
00348 
00349 /* ------------------------------------------------------------------------- */
00350 
00351 /*
00352  *  Overview:
00353  *  --------
00354  *  There are 4 cases when this operation should be used:
00355  *   1) Searching an unhashed chain.
00356  *   2) Searching bucket TRIEVAR_BUCKET after searching the hashed-to bucket.
00357  *   3) Searching bucket TRIEVAR_BUCKET which is also the hashed-to bucket.
00358  *   4) Searching some hashed chain that has been restored through
00359  *        backtracking.
00360  *
00361  *  (1) and (3) clearly require a general algorithm, capable of dealing
00362  *  with vars and nonvars alike.  (4) must use this since we may be
00363  *  continuing an instance of (3).  (2) also requires a deref followed by
00364  *  inspection, since a derefed variable may (or may not) lead to the
00365  *  symbol we are interested in.
00366  *
00367  *  Detail:
00368  *  --------
00369  *  'cur_chain' should be non-NULL upon entry.  Get_TS_Op allows
00370  *  this code to be used for both hashed and unhashed node chains as
00371  *  each requires a different procedure for locating a node's timestamp.
00372  *
00373  *  Nodes are first pruned by timestamp validity.  If the node's timestamp
00374  *  is valid and a unification is possible, the state is saved, with
00375  *  cur_chain's sibling as the TSTN continuation, and we branch back to
00376  *  the major loop of the algorithm.  Otherwise the chain is searched to
00377  *  completion, exiting the block when cur_chain is NULL.
00378  */
00379 
00380 #define SearchChain_UnifyWithConstant(Chain,Subterm,TS,Get_TS_Op) {     \
00381    Chain_NextValidTSTN(Chain,TS,Get_TS_Op);                             \
00382    while ( IsNonNULL(Chain) ) {                                         \
00383      alt_chain = TSTN_Sibling(Chain);                                   \
00384      Chain_NextValidTSTN(alt_chain,TS,Get_TS_Op);                       \
00385      symbol = TSTN_Symbol(Chain);                                       \
00386      TrieSymbol_Deref(symbol);                                          \
00387      if ( isref(symbol) ) {                                             \
00388        /*                                                               \
00389         *  Either an unbound TrieVar or some unbound prolog var.        \
00390         */                                                              \
00391        CPStack_PushFrame(alt_chain);                                    \
00392        Bind_and_Conditionally_Trail((CPtr)symbol, Subterm);             \
00393        TermStackLog_PushFrame;                                          \
00394        Descend_Into_TST_and_Continue_Search;                            \
00395      }                                                                  \
00396      else if (symbol == Subterm) {                                      \
00397        CPStack_PushFrame(alt_chain);                                    \
00398        TermStackLog_PushFrame;                                          \
00399        Descend_Into_TST_and_Continue_Search;                            \
00400      }                                                                  \
00401      Chain = alt_chain;                                                 \
00402    }                                                                    \
00403  }
00404 
00405 /* ------------------------------------------------------------------------- */
00406 
00407 /*
00408  *  Overview:
00409  *  --------
00410  *  There are 4 cases when this operation should be used:
00411  *   1) Searching an unhashed chain.
00412  *   2) Searching bucket TRIEVAR_BUCKET after searching the hashed-to bucket.
00413  *   3) Searching bucket TRIEVAR_BUCKET which is also the hashed-to bucket.
00414  *   4) Searching some hashed chain that has been restored through
00415  *        backtracking.
00416  *
00417  *  (1) and (3) clearly require a general algorithm, capable of dealing
00418  *  with vars and nonvars alike.  (4) must use this since we may be
00419  *  continuing an instance of (3).  (2) also requires a deref followed by
00420  *  inspection, since a derefed variable may (or may not) lead to the
00421  *  symbol we are interested in.
00422  *
00423  *  Detail:
00424  *  --------
00425  *  'cur_chain' should be non-NULL upon entry.  Get_TS_Op allows
00426  *  this code to be used for both hashed and unhashed node chains as
00427  *  each requires a different procedure for locating a node's timestamp.
00428  *
00429  *  Nodes are first pruned by timestamp validity.  If the node's timestamp
00430  *  is valid and a unification is possible, the state is saved, with
00431  *  cur_chain's sibling as the TSTN continuation, and we branch back to
00432  *  the major loop of the algorithm.  Otherwise the chain is searched to
00433  *  completion, exiting the block when cur_chain is NULL.
00434  */
00435 
00436 #define SearchChain_UnifyWithFunctor(Chain,Subterm,TS,Get_TS_Op) {        \
00437                                                                           \
00438    Cell sym_tag;                                                          \
00439                                                                           \
00440    Chain_NextValidTSTN(Chain,TS,Get_TS_Op);                               \
00441    while ( IsNonNULL(Chain) ) {                                           \
00442      alt_chain = TSTN_Sibling(Chain);                                     \
00443      Chain_NextValidTSTN(alt_chain,TS,Get_TS_Op);                         \
00444      symbol = TSTN_Symbol(Chain);                                         \
00445      sym_tag = TrieSymbolType(symbol);                                    \
00446      TrieSymbol_Deref(symbol);                                            \
00447      if ( isref(symbol) ) {                                               \
00448        /*                                                                 \
00449         * Either an unbound TrieVar or some unbound Prolog var.  The      \
00450         * variable is bound to the entire subterm (functor + args), so    \
00451         * we don't need to process its args; simply continue the search   \
00452         * through the trie.                                               \
00453         */                                                                \
00454        CPStack_PushFrame(alt_chain);                                      \
00455        Bind_and_Conditionally_Trail((CPtr)symbol, Subterm);               \
00456        TermStackLog_PushFrame;                                            \
00457        Descend_Into_TST_and_Continue_Search;                              \
00458      }                                                                    \
00459      else if ( IsTrieFunctor(symbol) ) {                                  \
00460        /*                                                                 \
00461         * Need to be careful here, because TrieVars may be bound to heap- \
00462         * resident structures and a deref of the trie symbol doesn't      \
00463         * tell you whether we have something in the trie or in the heap.  \
00464         */                                                                \
00465        if ( sym_tag == XSB_STRUCT ) {                                     \
00466          if ( get_str_psc(Subterm) == DecodeTrieFunctor(symbol) ) {       \
00467            /*                                                             \
00468             *  We must process the rest of the term ourselves.            \
00469             */                                                            \
00470            CPStack_PushFrame(alt_chain);                                  \
00471            TermStackLog_PushFrame;                                        \
00472            TermStack_PushFunctorArgs(Subterm);                            \
00473            Descend_Into_TST_and_Continue_Search;                          \
00474          }                                                                \
00475        }                                                                  \
00476        else {                                                             \
00477          /*                                                               \
00478           * We have a TrieVar bound to a heap XSB_STRUCT-term; use a      \
00479           * standard unification algorithm to check the match and         \
00480           * perform any additional unification.                           \
00481           */                                                              \
00482          if (unify(CTXTc Subterm, symbol)) {                              \
00483            CPStack_PushFrame(alt_chain);                                  \
00484            TermStackLog_PushFrame;                                        \
00485            Descend_Into_TST_and_Continue_Search;                          \
00486          }                                                                \
00487        }                                                                  \
00488      }                                                                    \
00489      Chain = alt_chain;                                                   \
00490    }                                                                      \
00491  }
00492 
00493 /* ------------------------------------------------------------------------- */
00494 
00495 /*
00496  *  Overview:
00497  *  --------
00498  *  Since in hashing environments LISTs only live in bucket 0, as do
00499  *  variables, there are only 2 cases to consider:
00500  *   1) Searching an unhashed chain (or subchain, via backtracking).
00501  *   2) Searching a hashed chain (or subchain, via backtracking).
00502  *
00503  *  Although there is at most only one LIST instance in a chain, there
00504  *  may be many variables, with both groups appearing in any order.
00505  *  Hence there is always the need to handle variables, which must be
00506  *  dereferenced to determine whether they are bound, and if so,
00507  *  whether they are bound to some LIST.
00508  *
00509  *  Detail:
00510  *  --------
00511  *  'cur_chain' should be non-NULL upon entry.  Get_TS_Op allows
00512  *  this code to be used for both hashed and unhashed node chains as
00513  *  each requires a different procedure for locating a node's timestamp.
00514  *
00515  *  Nodes are first pruned by timestamp validity.  If the node's timestamp
00516  *  is valid and a unification is possible, the state is saved, with
00517  *  cur_chain's sibling as the TSTN continuation, and we branch back to
00518  *  the major loop of the algorithm.  Otherwise the chain is searched to
00519  *  completion, exiting the block when cur_chain is NULL.
00520  */
00521 
00522 #define SearchChain_UnifyWithList(Chain,Subterm,TS,Get_TS_Op) {         \
00523                                                                         \
00524    Cell sym_tag;                                                        \
00525                                                                         \
00526    Chain_NextValidTSTN(Chain,TS,Get_TS_Op);                             \
00527    while ( IsNonNULL(Chain) ) {                                         \
00528      alt_chain = TSTN_Sibling(Chain);                                   \
00529      Chain_NextValidTSTN(alt_chain,TS,Get_TS_Op);                       \
00530      symbol = TSTN_Symbol(Chain);                                       \
00531      sym_tag = TrieSymbolType(symbol);                                  \
00532      TrieSymbol_Deref(symbol);                                          \
00533      if ( isref(symbol) ) {                                             \
00534        /*                                                               \
00535         * Either an unbound TrieVar or some unbound Prolog var.  The    \
00536         * variable is bound to the entire subterm ([First | Rest]), so  \
00537         * we don't need to process its args; simply continue the        \
00538         * search through the trie.                                      \
00539         */                                                              \
00540        CPStack_PushFrame(alt_chain);                                    \
00541        Bind_and_Conditionally_Trail((CPtr)symbol,Subterm);              \
00542        TermStackLog_PushFrame;                                          \
00543        Descend_Into_TST_and_Continue_Search;                            \
00544      }                                                                  \
00545      else if ( IsTrieList(symbol) ) {                                   \
00546        /*                                                               \
00547         * Need to be careful here, because XSB_TrieVars are bound to    \
00548         * heap- resident structures and a deref of the (trie) symbol    \
00549         * doesn't tell you whether we have something in the trie or in  \
00550         * the heap.                                                     \
00551         */                                                              \
00552        if ( sym_tag == XSB_LIST ) {                                     \
00553          /*                                                             \
00554           *  We must process the rest of the term ourselves.            \
00555           */                                                            \
00556          CPStack_PushFrame(alt_chain);                                  \
00557          TermStackLog_PushFrame;                                        \
00558          TermStack_PushListArgs(Subterm);                               \
00559          Descend_Into_TST_and_Continue_Search;                          \
00560        }                                                                \
00561        else {                                                           \
00562          /*                                                             \
00563           * We have a XSB_TrieVar bound to a heap LIST-term; use a      \
00564           * standard unification algorithm to check the match.          \
00565           */                                                            \
00566          if (unify(CTXTc Subterm, symbol)) {                            \
00567            CPStack_PushFrame(alt_chain);                                \
00568            TermStackLog_PushFrame;                                      \
00569            Descend_Into_TST_and_Continue_Search;                        \
00570          }                                                              \
00571        }                                                                \
00572      }                                                                  \
00573      Chain = alt_chain;                                                 \
00574    }                                                                    \
00575  }
00576  
00577 /* ------------------------------------------------------------------------- */
00578 
00579 /*
00580  *  Unify the timestamp-valid node 'cur_chain' with the variable subterm.
00581  */
00582 
00583 #define CurrentTSTN_UnifyWithVariable(Chain,Subterm,Continuation)          \
00584    CPStack_PushFrame(Continuation);                                        \
00585    TermStackLog_PushFrame;                                                 \
00586    symbol = TSTN_Symbol(Chain);                                            \
00587    TrieSymbol_Deref(symbol);                                               \
00588    switch(TrieSymbolType(symbol)) {                                        \
00589    case XSB_INT:                                                           \
00590    case XSB_FLOAT:                                                         \
00591    case XSB_STRING:                                                        \
00592      /*     printf("before %x %x \n",(CPtr)Subterm,symbol);     */      \
00593      Trie_bind_copy((CPtr)Subterm,symbol);                              \
00594      /*     printf("after %x\n",*(CPtr)Subterm);                */      \
00595      break;                                                                \
00596                                                                            \
00597    case XSB_STRUCT:                                                        \
00598      /*                                                                    \
00599       * Need to be careful here, because TrieVars are bound to heap-       \
00600       * resident structures and a deref of the (trie) symbol doesn't       \
00601       * tell you whether we have something in the trie or in the heap.     \
00602       */                                                                   \
00603      if ( IsTrieFunctor(TSTN_Symbol(Chain)) ) {                            \
00604        /*                                                                  \
00605         * Since the TSTN contains some f/n, create an f(X1,X2,...,Xn)      \
00606         * structure on the heap so that we can bind the subterm            \
00607         * variable to it.  Then use this algorithm to find bindings        \
00608         * for the unbound variables X1,...,Xn in the trie.                 \
00609         */                                                                 \
00610        CPtr heap_var_ptr;                                                  \
00611        int arity, i;                                                       \
00612        Psc symbolPsc;                                                      \
00613                                                                            \
00614        symbolPsc = (Psc)cs_val(symbol);                                    \
00615        arity = get_arity(symbolPsc);                                       \
00616        Trie_bind_copy((CPtr)Subterm,(Cell)hreg);                        \
00617        bld_cs(hreg, hreg + 1);                                             \
00618        bld_functor(++hreg, symbolPsc);                                     \
00619        for (heap_var_ptr = hreg + arity, i = 0;                            \
00620             i < arity;                                                     \
00621             heap_var_ptr--, i++) {                                         \
00622          bld_free(heap_var_ptr);                                           \
00623          TermStack_Push((Cell)heap_var_ptr);                               \
00624        }                                                                   \
00625        hreg = hreg + arity + 1;                                            \
00626      }                                                                     \
00627      else {                                                                \
00628        /*                                                                  \
00629         * We have a TrieVar bound to a heap-resident STRUCT.               \
00630         */                                                                 \
00631        Trie_bind_copy((CPtr)Subterm,symbol);                            \
00632      }                                                                  \
00633      break;                                                                \
00634                                                                            \
00635    case XSB_LIST:                                                          \
00636      if ( IsTrieList(TSTN_Symbol(Chain)) ) {                               \
00637        /*                                                                  \
00638         * Since the TSTN contains a (sub)list beginning, create a          \
00639         * [X1|X2] structure on the heap so that we can bind the            \
00640         * subterm variable to it.  Then use this algorithm to find         \
00641         * bindings for the unbound variables X1 & X2 in the trie.          \
00642         */                                                                 \
00643        Trie_bind_copy((CPtr)Subterm,(Cell)hreg);                                \
00644        bld_list(hreg, hreg + 1);                                           \
00645        hreg = hreg + 3;                                                    \
00646        bld_free(hreg - 1);                                                 \
00647        TermStack_Push((Cell)(hreg - 1));                                   \
00648        bld_free(hreg - 2);                                                 \
00649        TermStack_Push((Cell)(hreg - 2));                                   \
00650      }                                                                     \
00651      else {                                                                \
00652        /*                                                                  \
00653         * We have a TrieVar bound to a heap-resident LIST.                 \
00654         */                                                                 \
00655        Trie_bind_copy((CPtr)Subterm,symbol);                            \
00656      }                                                                     \
00657      break;                                                                \
00658                                                                            \
00659    case XSB_REF:                                                           \
00660    case XSB_REF1:                                                          \
00661      /*                                                                    \
00662       * The symbol is either an unbound TrieVar or some unbound Prolog     \
00663       * variable.  If it's an unbound TrieVar, we bind it to the           \
00664       * Prolog var.  Otherwise, binding direction is WAM-defined.          \
00665       */                                                                   \
00666      if (IsUnboundTrieVar(symbol)) {                                       \
00667        Bind_and_Trail((CPtr)symbol,Subterm);                               \
00668      }                                                                     \
00669      else                                                                  \
00670        unify(CTXTc symbol,Subterm);                                        \
00671      break;                                                                \
00672                                                                            \
00673    default:                                                                \
00674      fprintf(stderr, "subterm: unbound var (%ld),  symbol: unknown "       \
00675              "(%ld)\n", cell_tag(Subterm), TrieSymbolType(symbol));        \
00676      TST_Collection_Error("Trie symbol with bogus tag!", RequiresCleanup); \
00677      break;                                                                \
00678    }  /* END switch(symbol_tag) */                                         \
00679    Descend_Into_TST_and_Continue_Search
00680 
00681 
00682 /* ========================================================================= */
00683 
00684 
00685 /*
00686  * Purpose:
00687  * -------
00688  *  From a given Time-Stamped Answer Trie, collect those answers with
00689  *  timestamps greater than a given value and which unify with a given
00690  *  template.  The unifying answers are returned in a chain of Answer
00691  *  List Nodes.
00692  *  Note that this algorithm relies on the Time Stamp Indices of the
00693  *  TST (which are reclaimed from the table when a subgoal completes).
00694  *
00695  * Method:
00696  * ------
00697  *  Backtrack through the entire TST, using the TimeStamp to prune paths.
00698  *
00699  * Nefarious Detail (not integral to general understanding)
00700  * ----------------
00701  *  Only when we succeed with a match do we push a subterm onto the
00702  *  tstTermStackLog.  This is because if we don't succeed, we backtrack,
00703  *  which would mean we pushed it onto the tstTermStackLog just to be
00704  *  popped off and stored back in the tstTermStack, and in fact back to
00705  *  the same location where it already resides (it wouldn't have had a
00706  *  chance to be overwritten).
00707  *
00708  *  When we do succeed, we would like to record the subterm just
00709  *  consumed, but not any bindings created as a result of the match.
00710  *  In the code, we push a CPF before doing any of this recording.
00711  *  However, the log info is, in fact, saved.  */
00712 
00713 ALNptr tst_collect_relevant_answers(CTXTdeclc TSTNptr tstRoot, TimeStamp ts,
00714                                     int numTerms, CPtr termsRev) {
00715 
00716   /* numTerms -- size of Answer Template */
00717   /* termsRev -- Answer template (on heap) */
00718 
00719   ALNptr tstAnswerList;  /* for collecting leaves to be returned */
00720 
00721   TSTNptr cur_chain;     /* main ptr for stepping through siblings; under
00722                             normal (non-hashed) circumstances, variable and
00723                             non-variable symbols will appear in the same
00724                             chain */
00725   TSTNptr alt_chain;     /* special case ptr used for stepping through
00726                               siblings while looking for a match with
00727                               subterm */
00728   TSTNptr parentTSTN;    /* the parent of TSTNs in cur_ and alt_chain */
00729 
00730   Cell subterm;          /* the part of the term we are inspecting */
00731   Cell symbol;
00732 
00733 
00734 
00735   /* Check that a term was passed in
00736      ------------------------------- */
00737   if (numTerms < 1)
00738     TST_Collection_Error("Called with < 1 terms",NoCleanupRequired);
00739 
00740 
00741   /* Initialize data structures
00742      -------------------------- */
00743   TermStack_ResetTOS;
00744   TermStack_PushHighToLowVector(termsRev,numTerms);  /* AnsTempl -> TermStack */
00745   TermStackLog_ResetTOS;
00746   tstCPStack.top = tstCPStack.base;
00747   trail_base = top_of_trail;
00748   Save_and_Set_WAM_Registers;
00749 
00750   parentTSTN = tstRoot;
00751   cur_chain = TSTN_Child(tstRoot);
00752   tstAnswerList = NULL;
00753   symbol = 0;   /* suppress compiler warning */
00754 
00755 
00756   /* Major loop of the algorithm
00757      --------------------------- */
00758 
00759  While_TSnotEmpty:
00760   while ( ! TermStack_IsEmpty ) {
00761     TermStack_Pop(subterm);
00762     XSB_Deref(subterm);
00763     switch(cell_tag(subterm)) {
00764 
00765     /* SUBTERM IS A CONSTANT
00766        --------------------- */
00767     case XSB_INT:
00768     case XSB_FLOAT:
00769     case XSB_STRING:
00770       /*
00771        *  NOTE:  A Trie constant looks like a Prolog constant.
00772        */
00773       if ( IsHashHeader(cur_chain) ) {
00774         symbol = EncodeTrieConstant(subterm);
00775         SetMatchAndUnifyChains(symbol,cur_chain,alt_chain);
00776         if ( cur_chain != alt_chain ) {
00777           SearchChain_ExactMatch(cur_chain,symbol,ts,alt_chain,
00778                                  TermStack_NOOP);
00779           cur_chain = alt_chain;
00780         }
00781         if ( IsNULL(cur_chain) )
00782           backtrack;
00783       }
00784       if ( IsHashedNode(cur_chain) )
00785         SearchChain_UnifyWithConstant(cur_chain,subterm,ts,
00786                                       TSTN_GetTSfromTSIN)
00787       else
00788         SearchChain_UnifyWithConstant(cur_chain,subterm,ts,TSTN_TimeStamp)
00789       break;
00790 
00791     /* SUBTERM IS A STRUCTURE
00792        ---------------------- */
00793     case XSB_STRUCT:
00794       /*
00795        *  NOTE:  A trie XSB_STRUCT is a XSB_STRUCT-tagged PSC ptr,
00796        *  while a heap XSB_STRUCT is a XSB_STRUCT-tagged ptr to a PSC ptr.
00797        */
00798       if ( IsHashHeader(cur_chain) ) {
00799         symbol = EncodeTrieFunctor(subterm);
00800         SetMatchAndUnifyChains(symbol,cur_chain,alt_chain);
00801         if ( cur_chain != alt_chain ) {
00802           SearchChain_ExactMatch(cur_chain,symbol,ts,alt_chain,
00803                                  TermStack_PushFunctorArgs(subterm));
00804           cur_chain = alt_chain;
00805         }
00806         if ( IsNULL(cur_chain) )
00807           backtrack;
00808       }
00809       if ( IsHashedNode(cur_chain) )
00810         SearchChain_UnifyWithFunctor(cur_chain,subterm,ts,TSTN_GetTSfromTSIN)
00811       else
00812         SearchChain_UnifyWithFunctor(cur_chain,subterm,ts,TSTN_TimeStamp)
00813       break;
00814       
00815     /* SUBTERM IS A LIST
00816        ----------------- */
00817     case XSB_LIST:
00818       /*
00819        *  NOTE:  A trie XSB_LIST uses a plain XSB_LIST tag wherever a recursive
00820        *         substructure begins, while a heap XSB_LIST uses a XSB_LIST-
00821        *         tagged ptr to a pair of Cells, the first being the head
00822        *         and the second being the recursive tail, another XSB_LIST-
00823        *         tagged ptr.
00824        */
00825       if ( IsHashHeader(cur_chain) ) {
00826         symbol = EncodeTrieList(subterm);
00827         SetMatchAndUnifyChains(symbol,cur_chain,alt_chain);
00828         if ( cur_chain != alt_chain ) {
00829           SearchChain_ExactMatch(cur_chain,symbol,ts,alt_chain,
00830                                  TermStack_PushListArgs(subterm));
00831           cur_chain = alt_chain;
00832         }
00833         if ( IsNULL(cur_chain) )
00834           backtrack;
00835       }
00836       if ( IsHashedNode(cur_chain) )
00837         SearchChain_UnifyWithList(cur_chain,subterm,ts,TSTN_GetTSfromTSIN)
00838       else
00839         SearchChain_UnifyWithList(cur_chain,subterm,ts,TSTN_TimeStamp)
00840       break;
00841       
00842     /* SUBTERM IS AN UNBOUND VARIABLE
00843        ------------------------------ */
00844     case XSB_REF:
00845     case XSB_REF1:
00846       /*
00847        *  Since variables unify with any term, only prune based on
00848        *  timestamps.  For Hashed/HashRoot nodes we can use the TSI to
00849        *  prune timestamp-invalid nodes immediately, and so we search for
00850        *  timestamp-valid nodes for both cur_chain and alt_chain.  (If
00851        *  one cannot be found for alt_chain, then there is no reason, at a
00852        *  future time, to backtrack to this state.  Hence, alt_chain is
00853        *  given the value of NULL so that no CP is created.)  For an
00854        *  unhashed chain, we cannot use this trick, and so must pick them
00855        *  out of the chain via a linear search.  In fact, we only require
00856        *  cur_chain to be valid in this case.  In all cases, if a valid
00857        *  node cannot be found (for cur_chain), we backtrack.
00858        */
00859       if ( IsHashedNode(cur_chain) )
00860         /*
00861          *  Can only be here via backtracking...
00862          *  cur_chain should be valid by virtue that we only save valid
00863          *  hashed alt_chains.  Find the next valid TSTN in the chain.
00864          */
00865         alt_chain = TSI_NextValidTSTN(TSTN_GetTSIN(cur_chain),ts);
00866       else if ( IsHashHeader(cur_chain) ) {
00867         /* Can only be here if stepping down onto this level... */
00868         TSINptr tsin = TSTHT_IndexHead((TSTHTptr)cur_chain);
00869 
00870         if ( IsNULL(tsin) )
00871           TST_Collection_Error("TSI Structures don't exist", RequiresCleanup);
00872         if ( IsValidTS(TSIN_TimeStamp(tsin),ts) ) {
00873           cur_chain = TSIN_TSTNode(tsin);
00874           alt_chain = TSI_NextValidTSTN(tsin,ts);
00875         }
00876         else
00877           backtrack;
00878       }
00879       else {
00880         /*
00881          *  Can get here through forword OR backward execution...
00882          *  Find the next timestamp-valid node in this UnHashed chain.
00883          */
00884         Chain_NextValidTSTN(cur_chain,ts,TSTN_TimeStamp);
00885         if ( IsNULL(cur_chain) )
00886           backtrack;
00887         alt_chain = TSTN_Sibling(cur_chain);
00888         Chain_NextValidTSTN(alt_chain,ts,TSTN_TimeStamp);
00889       }
00890       CurrentTSTN_UnifyWithVariable(cur_chain,subterm,alt_chain);
00891       break;
00892 
00893     default:
00894       fprintf(stderr, "subterm: unknown (%ld),  symbol: ? (%ld)\n",
00895               cell_tag(subterm), TrieSymbolType(symbol));
00896       TST_Collection_Error("Trie symbol with bogus tag!", RequiresCleanup);
00897       break;
00898     } /* END switch(subterm_tag) */
00899 
00900     /*
00901      *  We've exhausted the possibilities of the subbranch at this level,
00902      *  and so need to backtrack to continue the search.  If there are no
00903      *  remaining choice point frames, then the TST has been completely
00904      *  searched and we return any answers found.
00905      */
00906 
00907     if ( CPStack_IsEmpty ) {
00908       Sys_Trail_Unwind(trail_base);
00909       Restore_WAM_Registers;
00910       return tstAnswerList;
00911     }
00912     TST_Backtrack;
00913 
00914   } /* END while( ! TermStack_IsEmpty ) */
00915 
00916   /*
00917    *  If the tstTermStack is empty, then we (should have) reached a leaf
00918    *  node whose corresponding term unifies with the Heap Term 'term'.  If
00919    *  a leaf is not reached, then we generate an error msg, and try to
00920    *  continue.
00921    */
00922 
00923   if ( ! IsLeafNode(parentTSTN) ) {
00924     xsb_warn("During collection of relevant answers for subsumed subgoal\n"
00925              "TermStack is empty but a leaf node was not reached");
00926     xsb_dbgmsg((LOG_DEBUG, "Root "));
00927     dbg_printTrieNode(LOG_DEBUG, stddbg, (BTNptr)tstRoot);
00928     xsb_dbgmsg((LOG_DEBUG, "Last "));
00929     dbg_printTrieNode(LOG_DEBUG, stddbg, (BTNptr)parentTSTN);
00930     dbg_printAnswerTemplate(LOG_DEBUG, stddbg, termsRev,numTerms);
00931     xsb_dbgmsg((LOG_DEBUG,
00932             "(* Note: this template may be partially instantiated *)\n"));
00933     fprintf(stdwarn, "Attempting to continue...\n");
00934   }
00935   else {
00936     //    printf("ans   ");printTriePath(stderr,parentTSTN,NO);printf("\n");
00937     ALN_InsertAnswer(tstAnswerList, parentTSTN);
00938   }
00939   if ( CPStack_IsEmpty ) {
00940     Sys_Trail_Unwind(trail_base);
00941     Restore_WAM_Registers;
00942     return tstAnswerList;
00943   }
00944   TST_Backtrack;
00945   goto While_TSnotEmpty;
00946 }

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