globle void NetworkAssert( void *theEnv, struct partialMatch *binds, struct joinNode *join) { /*=========================================================*/ /* If an incremental reset is being performed and the join */ /* is not part of the network to be reset, then return. */ /*=========================================================*/ #if (! BLOAD_ONLY) && (! RUN_TIME) if (EngineData(theEnv)->IncrementalResetInProgress && (join->initialize == FALSE)) return; #endif /*==================================================*/ /* Use a special routine if this is the first join. */ /*==================================================*/ if (join->firstJoin) { EmptyDrive(theEnv,join,binds); return; } /*================================*/ /* Enter the join from the right. */ /*================================*/ NetworkAssertRight(theEnv,binds,join); return; }
globle void NetworkAssert( struct partialMatch *binds, struct joinNode *join, int enterDirection) { struct partialMatch *lhsBinds = NULL, *rhsBinds = NULL; struct partialMatch *comparePMs = NULL, *newBinds; int exprResult; /*=========================================================*/ /* If an incremental reset is being performed and the join */ /* is not part of the network to be reset, then return. */ /*=========================================================*/ #if INCREMENTAL_RESET && (! BLOAD_ONLY) && (! RUN_TIME) if (IncrementalResetInProgress && (join->initialize == FALSE)) return; #endif /*=========================================================*/ /* If the associated LHS pattern is a not CE or the join */ /* is a nand join, then we need an additional field in the */ /* partial match to keep track of the pseudo fact if one */ /* is created. The partial match is automatically stored */ /* in the beta memory and the counterf slot is used to */ /* determine if it is an actual partial match. If counterf */ /* is TRUE, there are one or more fact or instances */ /* keeping the not or nand join from being satisfied. */ /*=========================================================*/ if ((enterDirection == LHS) && ((join->patternIsNegated) || (join->joinFromTheRight))) { newBinds = AddSingleMatch(binds,NULL, (join->ruleToActivate == NULL) ? 0 : 1, (int) join->logicalJoin); newBinds->notOriginf = TRUE; newBinds->counterf = TRUE; binds = newBinds; binds->next = join->beta; join->beta = binds; } /*==================================================*/ /* Use a special routine if this is the first join. */ /*==================================================*/ if (join->firstJoin) { EmptyDrive(join,binds); return; } /*==================================================*/ /* Initialize some variables used to indicate which */ /* side is being compared to the new partial match. */ /*==================================================*/ if (enterDirection == LHS) { if (join->joinFromTheRight) { comparePMs = ((struct joinNode *) join->rightSideEntryStructure)->beta;} else { comparePMs = ((struct patternNodeHeader *) join->rightSideEntryStructure)->alphaMemory; } lhsBinds = binds; } else if (enterDirection == RHS) { if (join->patternIsNegated || join->joinFromTheRight) { comparePMs = join->beta; } else { comparePMs = join->lastLevel->beta; } rhsBinds = binds; } else { SystemError("DRIVE",1); ExitRouter(EXIT_FAILURE); } /*===================================================*/ /* Compare each set of binds on the opposite side of */ /* the join with the set of binds that entered this */ /* join. If the binds don't mismatch, then perform */ /* the appropriate action for the logic of the join. */ /*===================================================*/ while (comparePMs != NULL) { /*===========================================================*/ /* Initialize some variables pointing to the partial matches */ /* in the LHS and RHS of the join. In addition, check for */ /* certain conditions under which the partial match can be */ /* skipped since it's not a "real" partial match. */ /*===========================================================*/ if (enterDirection == RHS) { lhsBinds = comparePMs; /*=====================================================*/ /* The partial matches entering from the LHS of a join */ /* are stored in the beta memory of the previous join */ /* (unless the current join is a join from the right */ /* or is attached to a not CE). If the previous join */ /* is a join from the right or associated with a not */ /* CE, then some of its partial matches in its beta */ /* memory will not be "real" partial matches. That is, */ /* there may be a partial match in the alpha memory */ /* that prevents the partial match from satisfying the */ /* join's conditions. If this is the case, then the */ /* counterf flag in the partial match will be set to */ /* TRUE and in this case, we move on to the next */ /* partial match to be checked. */ /*=====================================================*/ if (lhsBinds->counterf && (join->patternIsNegated == FALSE) && (join->joinFromTheRight == FALSE)) { comparePMs = comparePMs->next; continue; } /*==================================================*/ /* If the join is associated with a not CE or has a */ /* join from the right, then the LHS partial match */ /* currently being checked may already have a */ /* partial match from the alpha memory preventing */ /* it from being satisfied. If this is the case, */ /* then move on to the next partial match in the */ /* beta memory of the join. */ /*==================================================*/ if ((join->patternIsNegated || join->joinFromTheRight) && (lhsBinds->counterf)) { comparePMs = comparePMs->next; continue; } } else { rhsBinds = comparePMs; } /*========================================================*/ /* If the join has no expression associated with it, then */ /* the new partial match derived from the LHS and RHS */ /* partial matches is valid. In the event that the join */ /* is a join from the right, it must also be checked that */ /* the RHS partial match is the same partial match that */ /* the LHS partial match was generated from. Each LHS */ /* partial match in a join from the right corresponds */ /* uniquely to a partial match from the RHS of the join. */ /* To determine whether the LHS partial match is the one */ /* associated with the RHS partial match, we compare the */ /* the entity addresses found in the partial matches to */ /* make sure they're equal. */ /*========================================================*/ if (join->networkTest == NULL) { exprResult = TRUE; if (join->joinFromTheRight) { int i; for (i = 0; i < (int) (lhsBinds->bcount - 1); i++) { if (lhsBinds->binds[i].gm.theMatch != rhsBinds->binds[i].gm.theMatch) { exprResult = FALSE; break; } } } } /*=========================================================*/ /* If the join has an expression associated with it, then */ /* evaluate the expression to determine if the new partial */ /* match derived from the LHS and RHS partial matches is */ /* valid (i.e. variable bindings are consistent and */ /* predicate expressions evaluate to TRUE). */ /*=========================================================*/ else { exprResult = EvaluateJoinExpression(join->networkTest,lhsBinds,rhsBinds,join); if (EvaluationError) { if (join->patternIsNegated) exprResult = TRUE; SetEvaluationError(FALSE); } } /*====================================================*/ /* If the join expression evaluated to TRUE (i.e. */ /* there were no conflicts between variable bindings, */ /* all tests were satisfied, etc.), then perform the */ /* appropriate action given the logic of this join. */ /*====================================================*/ if (exprResult != FALSE) { /*==============================================*/ /* Use the PPDrive routine when the join isn't */ /* associated with a not CE and it doesn't have */ /* a join from the right. */ /*==============================================*/ if ((join->patternIsNegated == FALSE) && (join->joinFromTheRight == FALSE)) { PPDrive(lhsBinds,rhsBinds,join); } /*=====================================================*/ /* Use the PNRDrive routine when the new partial match */ /* enters from the RHS of the join and the join either */ /* is associated with a not CE or has a join from the */ /* right. */ /*=====================================================*/ else if (enterDirection == RHS) { PNRDrive(join,comparePMs,rhsBinds); } /*===========================================================*/ /* If the new partial match entered from the LHS of the join */ /* and the join is either associated with a not CE or the */ /* join has a join from the right, then mark the LHS partial */ /* match indicating that there is a RHS partial match */ /* preventing this join from being satisfied. Once this has */ /* happened, the other RHS partial matches don't have to be */ /* tested since it only takes one partial match to prevent */ /* the LHS from being satisfied. */ /*===========================================================*/ else if (enterDirection == LHS) { binds->binds[binds->bcount - 1].gm.theValue = (void *) rhsBinds; comparePMs = NULL; continue; } } /*====================================*/ /* Move on to the next partial match. */ /*====================================*/ comparePMs = comparePMs->next; } /*==================================================================*/ /* If a join with an associated not CE or join from the right was */ /* entered from the LHS side of the join, and the join expression */ /* failed for all sets of matches for the new bindings on the LHS */ /* side (there was no RHS partial match preventing the LHS partial */ /* match from being satisfied), then the LHS partial match appended */ /* with an pseudo-fact that represents the instance of the not */ /* pattern or join from the right that was satisfied should be sent */ /* to the joins below this join. */ /*==================================================================*/ if ((join->patternIsNegated || join->joinFromTheRight) && (enterDirection == LHS) && (binds->binds[binds->bcount - 1].gm.theValue == NULL)) { PNLDrive(join,binds); } return; }
globle void NetworkAssertRight( void *theEnv, struct partialMatch *rhsBinds, struct joinNode *join) { struct partialMatch *lhsBinds, *nextBind; int exprResult, restore = FALSE; struct partialMatch *oldLHSBinds = NULL; struct partialMatch *oldRHSBinds = NULL; struct joinNode *oldJoin = NULL; /*=========================================================*/ /* If an incremental reset is being performed and the join */ /* is not part of the network to be reset, then return. */ /*=========================================================*/ #if (! BLOAD_ONLY) && (! RUN_TIME) if (EngineData(theEnv)->IncrementalResetInProgress && (join->initialize == FALSE)) return; #endif if (join->firstJoin) { EmptyDrive(theEnv,join,rhsBinds); return; } /*=====================================================*/ /* The partial matches entering from the LHS of a join */ /* are stored in the left beta memory of the join. */ /*=====================================================*/ lhsBinds = GetLeftBetaMemory(join,rhsBinds->hashValue); #if DEVELOPER if (lhsBinds != NULL) { EngineData(theEnv)->rightToLeftLoops++; } #endif /*====================================*/ /* Set up the evaluation environment. */ /*====================================*/ if (lhsBinds != NULL) { oldLHSBinds = EngineData(theEnv)->GlobalLHSBinds; oldRHSBinds = EngineData(theEnv)->GlobalRHSBinds; oldJoin = EngineData(theEnv)->GlobalJoin; EngineData(theEnv)->GlobalRHSBinds = rhsBinds; EngineData(theEnv)->GlobalJoin = join; restore = TRUE; } /*===================================================*/ /* Compare each set of binds on the opposite side of */ /* the join with the set of binds that entered this */ /* join. If the binds don't mismatch, then perform */ /* the appropriate action for the logic of the join. */ /*===================================================*/ while (lhsBinds != NULL) { nextBind = lhsBinds->nextInMemory; join->memoryCompares++; /*===========================================================*/ /* Initialize some variables pointing to the partial matches */ /* in the LHS and RHS of the join. */ /*===========================================================*/ if (lhsBinds->hashValue != rhsBinds->hashValue) { #if DEVELOPER if (join->leftMemory->size == 1) { EngineData(theEnv)->betaHashListSkips++; } else { EngineData(theEnv)->betaHashHTSkips++; } if (lhsBinds->marker != NULL) { EngineData(theEnv)->unneededMarkerCompare++; } #endif lhsBinds = nextBind; continue; } /*===============================================================*/ /* If there already is an associated RHS partial match stored in */ /* the LHS partial match from the beta memory of this join, then */ /* the exists/nand CE has already been satisfied and we can move */ /* on to the next partial match found in the beta memory. */ /*===============================================================*/ if (lhsBinds->marker != NULL) { #if DEVELOPER EngineData(theEnv)->unneededMarkerCompare++; #endif lhsBinds = nextBind; continue; } /*===================================================*/ /* If the join has no expression associated with it, */ /* then the new partial match derived from the LHS */ /* and RHS partial matches is valid. */ /*===================================================*/ if (join->networkTest == NULL) { exprResult = TRUE; } /*=========================================================*/ /* If the join has an expression associated with it, then */ /* evaluate the expression to determine if the new partial */ /* match derived from the LHS and RHS partial matches is */ /* valid (i.e. variable bindings are consistent and */ /* predicate expressions evaluate to TRUE). */ /*=========================================================*/ else { #if DEVELOPER EngineData(theEnv)->rightToLeftComparisons++; #endif EngineData(theEnv)->GlobalLHSBinds = lhsBinds; exprResult = EvaluateJoinExpression(theEnv,join->networkTest,join); if (EvaluationData(theEnv)->EvaluationError) { if (join->patternIsNegated) exprResult = TRUE; SetEvaluationError(theEnv,FALSE); } #if DEVELOPER if (exprResult) { EngineData(theEnv)->rightToLeftSucceeds++; } #endif } if ((join->secondaryNetworkTest != NULL) && exprResult) { EngineData(theEnv)->GlobalLHSBinds = lhsBinds; exprResult = EvaluateJoinExpression(theEnv,join->secondaryNetworkTest,join); if (EvaluationData(theEnv)->EvaluationError) { SetEvaluationError(theEnv,FALSE); } } /*====================================================*/ /* If the join expression evaluated to TRUE (i.e. */ /* there were no conflicts between variable bindings, */ /* all tests were satisfied, etc.), then perform the */ /* appropriate action given the logic of this join. */ /*====================================================*/ if (exprResult != FALSE) { if (join->patternIsExists) { AddBlockedLink(lhsBinds,rhsBinds); PPDrive(theEnv,lhsBinds,NULL,join); } else if (join->patternIsNegated || join->joinFromTheRight) { AddBlockedLink(lhsBinds,rhsBinds); if (lhsBinds->children != NULL) { PosEntryRetractBeta(theEnv,lhsBinds,lhsBinds->children); } /* if (lhsBinds->dependents != NULL) { RemoveLogicalSupport(theEnv,lhsBinds); } */ } else { PPDrive(theEnv,lhsBinds,rhsBinds,join); } } /*====================================*/ /* Move on to the next partial match. */ /*====================================*/ lhsBinds = nextBind; } /*=========================================*/ /* Restore the old evaluation environment. */ /*=========================================*/ if (restore) { EngineData(theEnv)->GlobalLHSBinds = oldLHSBinds; EngineData(theEnv)->GlobalRHSBinds = oldRHSBinds; EngineData(theEnv)->GlobalJoin = oldJoin; } return; }