globle intBool EvaluateSecondaryNetworkTest( void *theEnv, struct partialMatch *leftMatch, struct joinNode *joinPtr) { int joinExpr; struct partialMatch *oldLHSBinds; struct partialMatch *oldRHSBinds; struct joinNode *oldJoin; if (joinPtr->secondaryNetworkTest == NULL) { return(TRUE); } #if DEVELOPER EngineData(theEnv)->rightToLeftComparisons++; #endif oldLHSBinds = EngineData(theEnv)->GlobalLHSBinds; oldRHSBinds = EngineData(theEnv)->GlobalRHSBinds; oldJoin = EngineData(theEnv)->GlobalJoin; EngineData(theEnv)->GlobalLHSBinds = leftMatch; EngineData(theEnv)->GlobalRHSBinds = NULL; EngineData(theEnv)->GlobalJoin = joinPtr; joinExpr = EvaluateJoinExpression(theEnv,joinPtr->secondaryNetworkTest,joinPtr); EvaluationData(theEnv)->EvaluationError = FALSE; EngineData(theEnv)->GlobalLHSBinds = oldLHSBinds; EngineData(theEnv)->GlobalRHSBinds = oldRHSBinds; EngineData(theEnv)->GlobalJoin = oldJoin; return(joinExpr); }
static BOOLEAN FindNextConflictingAlphaMatch( struct partialMatch *theBind, struct partialMatch *possibleConflicts, struct joinNode *theJoin) { int i, result; /*=====================================================*/ /* If we're dealing with a join from the right, then */ /* we need to check the entire beta memory of the join */ /* from the right (a join doesn't have an end of queue */ /* pointer like a pattern data structure has). */ /*=====================================================*/ if (theJoin->joinFromTheRight) { possibleConflicts = ((struct joinNode *) theJoin->rightSideEntryStructure)->beta; } /*====================================*/ /* Check each of the possible partial */ /* matches which could conflict. */ /*====================================*/ for (; possibleConflicts != NULL; possibleConflicts = possibleConflicts->next) { /*=====================================*/ /* Initially indicate that the partial */ /* match doesn't conflict. */ /*=====================================*/ result = FALSE; /*====================================================*/ /* A partial match with the counterf flag set is not */ /* yet a "real" partial match, so ignore it. When the */ /* counterf flag is set that means that the partial */ /* match is associated with a not CE that has a data */ /* entity preventing it from being satsified. */ /*====================================================*/ if (possibleConflicts->counterf) { /* Do Nothing */ } /*======================================================*/ /* 6.05 Bug Fix. It is possible that a pattern entity */ /* (e.g., instance) in a partial match is 'out of date' */ /* with respect to the lazy evaluation scheme use by */ /* negated patterns. In other words, the object may */ /* have changed since it was last pushed through the */ /* network, and thus the partial match may be invalid. */ /* If so, the partial match must be ignored here. */ /*======================================================*/ else if (PartialMatchDefunct(possibleConflicts)) { /* Do Nothing */ } /*==================================================*/ /* If the join doesn't have a network expression to */ /* be evaluated, then partial match conflicts. If */ /* the partial match is retrieved from a join from */ /* the right, the RHS partial match must correspond */ /* to the partial match in the beta memory of the */ /* join being examined (in a join associated with a */ /* not CE, each partial match in the beta memory of */ /* the join corresponds uniquely to a partial match */ /* in either the alpha memory from the RHS or in */ /* the beta memory of a join from the right). */ /*==================================================*/ else if (theJoin->networkTest == NULL) { result = TRUE; if (theJoin->joinFromTheRight) { for (i = 0; i < (int) (theBind->bcount - 1); i++) { if (possibleConflicts->binds[i].gm.theMatch != theBind->binds[i].gm.theMatch) { result = FALSE; break; } } } } /*=================================================*/ /* Otherwise, if the join has a network expression */ /* to evaluate, then evaluate it. */ /*=================================================*/ else { result = EvaluateJoinExpression(theJoin->networkTest,theBind, possibleConflicts,theJoin); if (EvaluationError) { result = TRUE; EvaluationError = FALSE; } } /*==============================================*/ /* If the network expression evaluated to TRUE, */ /* then partial match being examined conflicts. */ /* Point the beta memory partial match to the */ /* conflicting partial match and return TRUE to */ /* indicate a conflict was found. */ /*==============================================*/ if (result != FALSE) { theBind->binds[theBind->bcount - 1].gm.theValue = (void *) possibleConflicts; return(TRUE); } } /*========================*/ /* No conflict was found. */ /*========================*/ return(FALSE); }
static void EmptyDrive( struct joinNode *join, struct partialMatch *rhsBinds) { struct partialMatch *linker; struct joinNode *listOfJoins; int joinExpr; /*======================================================*/ /* Determine if the alpha memory partial match satifies */ /* the join expression. If it doesn't then no further */ /* action is taken. */ /*======================================================*/ if (join->networkTest != NULL) { joinExpr = EvaluateJoinExpression(join->networkTest,NULL,rhsBinds,join); EvaluationError = FALSE; if (joinExpr == FALSE) return; } /*===========================================================*/ /* The first join of a rule cannot be connected to a NOT CE. */ /*===========================================================*/ if (join->patternIsNegated == TRUE) { SystemError("DRIVE",2); ExitRouter(EXIT_FAILURE); } /*=========================================================*/ /* If the join's RHS entry is associated with a pattern CE */ /* (positive entry), then copy the alpha memory partial */ /* match and send it to all child joins. */ /*=========================================================*/ linker = CopyPartialMatch(rhsBinds, (join->ruleToActivate == NULL) ? 0 : 1, (int) join->logicalJoin); /*=======================================================*/ /* Add the partial match to the beta memory of the join. */ /*=======================================================*/ linker->next = join->beta; join->beta = linker; /*====================================================*/ /* Activate the rule satisfied by this partial match. */ /*====================================================*/ if (join->ruleToActivate != NULL) AddActivation(join->ruleToActivate,linker); /*============================================*/ /* Send the partial match to all child joins. */ /*============================================*/ listOfJoins = join->nextLevel; while (listOfJoins != NULL) { NetworkAssert(linker,listOfJoins,LHS); listOfJoins = listOfJoins->rightDriveNode; } }
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 BOOLEAN EvaluateJoinExpression( struct expr *joinExpr, struct partialMatch *lbinds, struct partialMatch *rbinds, struct joinNode *joinPtr) { DATA_OBJECT theResult; int andLogic, result = TRUE; struct partialMatch *oldLHSBinds; struct partialMatch *oldRHSBinds; struct joinNode *oldJoin; /*======================================*/ /* A NULL expression evaluates to TRUE. */ /*======================================*/ if (joinExpr == NULL) return(TRUE); /*=========================================*/ /* Initialize some of the global variables */ /* used when evaluating expressions. */ /*=========================================*/ oldLHSBinds = GlobalLHSBinds; oldRHSBinds = GlobalRHSBinds; oldJoin = GlobalJoin; GlobalLHSBinds = lbinds; GlobalRHSBinds = rbinds; GlobalJoin = joinPtr; /*=====================================================*/ /* Partial matches stored in joins that are associated */ /* with a not CE contain an additional slot shouldn't */ /* be considered when evaluating expressions. Since */ /* joins that have joins from the right don't have any */ /* expression, we don't have to do this for partial */ /* matches contained in these joins. */ /*=====================================================*/ if (joinPtr->patternIsNegated) lbinds->bcount--; /*====================================================*/ /* Initialize some variables which allow this routine */ /* to avoid calling the "and" and "or" functions if */ /* they are the first part of the expression to be */ /* evaluated. Most of the join expressions do not use */ /* deeply nested and/or functions so this technique */ /* speeds up evaluation. */ /*====================================================*/ if (joinExpr->value == PTR_AND) { andLogic = TRUE; joinExpr = joinExpr->argList; } else if (joinExpr->value == PTR_OR) { andLogic = FALSE; joinExpr = joinExpr->argList; } else { andLogic = TRUE; } /*=========================================*/ /* Evaluate each of the expressions linked */ /* together in the join expression. */ /*=========================================*/ while (joinExpr != NULL) { /*================================*/ /* Evaluate a primitive function. */ /*================================*/ if ((PrimitivesArray[joinExpr->type] == NULL) ? FALSE : PrimitivesArray[joinExpr->type]->evaluateFunction != NULL) { struct expr *oldArgument; oldArgument = CurrentExpression; CurrentExpression = joinExpr; result = (*PrimitivesArray[joinExpr->type]->evaluateFunction)(joinExpr->value,&theResult); CurrentExpression = oldArgument; } /*=============================*/ /* Evaluate the "or" function. */ /*=============================*/ else if (joinExpr->value == PTR_OR) { result = FALSE; if (EvaluateJoinExpression(joinExpr,lbinds,rbinds,joinPtr) == TRUE) { if (EvaluationError) { if (joinPtr->patternIsNegated) lbinds->bcount++; GlobalLHSBinds = oldLHSBinds; GlobalRHSBinds = oldRHSBinds; GlobalJoin = oldJoin; return(FALSE); } result = TRUE; } else if (EvaluationError) { if (joinPtr->patternIsNegated) lbinds->bcount++; GlobalLHSBinds = oldLHSBinds; GlobalRHSBinds = oldRHSBinds; GlobalJoin = oldJoin; return(FALSE); } } /*==============================*/ /* Evaluate the "and" function. */ /*==============================*/ else if (joinExpr->value == PTR_AND) { result = TRUE; if (EvaluateJoinExpression(joinExpr,lbinds,rbinds,joinPtr) == FALSE) { if (EvaluationError) { if (joinPtr->patternIsNegated) lbinds->bcount++; GlobalLHSBinds = oldLHSBinds; GlobalRHSBinds = oldRHSBinds; GlobalJoin = oldJoin; return(FALSE); } result = FALSE; } else if (EvaluationError) { if (joinPtr->patternIsNegated) lbinds->bcount++; GlobalLHSBinds = oldLHSBinds; GlobalRHSBinds = oldRHSBinds; GlobalJoin = oldJoin; return(FALSE); } } /*==========================================================*/ /* Evaluate all other expressions using EvaluateExpression. */ /*==========================================================*/ else { EvaluateExpression(joinExpr,&theResult); if (EvaluationError) { JoinNetErrorMessage(joinPtr); if (joinPtr->patternIsNegated) lbinds->bcount++; GlobalLHSBinds = oldLHSBinds; GlobalRHSBinds = oldRHSBinds; GlobalJoin = oldJoin; return(FALSE); } if ((theResult.value == FalseSymbol) && (theResult.type == SYMBOL)) { result = FALSE; } else { result = TRUE; } } /*====================================*/ /* Handle the short cut evaluation of */ /* the "and" and "or" functions. */ /*====================================*/ if ((andLogic == TRUE) && (result == FALSE)) { if (joinPtr->patternIsNegated) lbinds->bcount++; GlobalLHSBinds = oldLHSBinds; GlobalRHSBinds = oldRHSBinds; GlobalJoin = oldJoin; return(FALSE); } else if ((andLogic == FALSE) && (result == TRUE)) { if (joinPtr->patternIsNegated) lbinds->bcount++; GlobalLHSBinds = oldLHSBinds; GlobalRHSBinds = oldRHSBinds; GlobalJoin = oldJoin; return(TRUE); } /*==============================================*/ /* Move to the next expression to be evaluated. */ /*==============================================*/ joinExpr = joinExpr->nextArg; } /*=======================================*/ /* Restore some of the global variables. */ /*=======================================*/ GlobalLHSBinds = oldLHSBinds; GlobalRHSBinds = oldRHSBinds; GlobalJoin = oldJoin; /*=====================================*/ /* Restore the count value for the LHS */ /* binds if it had to be modified. */ /*=====================================*/ if (joinPtr->patternIsNegated) lbinds->bcount++; /*=================================================*/ /* Return the result of evaluating the expression. */ /*=================================================*/ return(result); }
static void EmptyDrive( void *theEnv, struct joinNode *join, struct partialMatch *rhsBinds) { struct partialMatch *linker, *existsParent = NULL, *notParent; struct joinLink *listOfJoins; int joinExpr; unsigned long hashValue; struct partialMatch *oldLHSBinds; struct partialMatch *oldRHSBinds; struct joinNode *oldJoin; /*======================================================*/ /* Determine if the alpha memory partial match satifies */ /* the join expression. If it doesn't then no further */ /* action is taken. */ /*======================================================*/ join->memoryCompares++; if (join->networkTest != NULL) { #if DEVELOPER EngineData(theEnv)->rightToLeftComparisons++; #endif oldLHSBinds = EngineData(theEnv)->GlobalLHSBinds; oldRHSBinds = EngineData(theEnv)->GlobalRHSBinds; oldJoin = EngineData(theEnv)->GlobalJoin; EngineData(theEnv)->GlobalLHSBinds = NULL; EngineData(theEnv)->GlobalRHSBinds = rhsBinds; EngineData(theEnv)->GlobalJoin = join; joinExpr = EvaluateJoinExpression(theEnv,join->networkTest,join); EvaluationData(theEnv)->EvaluationError = FALSE; EngineData(theEnv)->GlobalLHSBinds = oldLHSBinds; EngineData(theEnv)->GlobalRHSBinds = oldRHSBinds; EngineData(theEnv)->GlobalJoin = oldJoin; if (joinExpr == FALSE) return; } if (join->secondaryNetworkTest != NULL) { #if DEVELOPER EngineData(theEnv)->rightToLeftComparisons++; #endif oldLHSBinds = EngineData(theEnv)->GlobalLHSBinds; oldRHSBinds = EngineData(theEnv)->GlobalRHSBinds; oldJoin = EngineData(theEnv)->GlobalJoin; EngineData(theEnv)->GlobalLHSBinds = NULL; EngineData(theEnv)->GlobalRHSBinds = rhsBinds; EngineData(theEnv)->GlobalJoin = join; joinExpr = EvaluateJoinExpression(theEnv,join->secondaryNetworkTest,join); EvaluationData(theEnv)->EvaluationError = FALSE; EngineData(theEnv)->GlobalLHSBinds = oldLHSBinds; EngineData(theEnv)->GlobalRHSBinds = oldRHSBinds; EngineData(theEnv)->GlobalJoin = oldJoin; if (joinExpr == FALSE) return; } /*========================================================*/ /* Handle a negated first pattern or join from the right. */ /*========================================================*/ if (join->patternIsNegated || (join->joinFromTheRight && (! join->patternIsExists))) /* reorder to remove patternIsExists test */ { notParent = join->leftMemory->beta[0]; if (notParent->marker != NULL) { return; } AddBlockedLink(notParent,rhsBinds); if (notParent->children != NULL) { PosEntryRetractBeta(theEnv,notParent,notParent->children); } /* if (notParent->dependents != NULL) { RemoveLogicalSupport(theEnv,notParent); } */ return; } /*=====================================================*/ /* For exists CEs used as the first pattern of a rule, */ /* a special partial match in the left memory of the */ /* join is used to track the RHS partial match */ /* satisfying the CE. */ /*=====================================================*/ /* TBD reorder */ if (join->patternIsExists) { existsParent = join->leftMemory->beta[0]; if (existsParent->marker != NULL) { return; } AddBlockedLink(existsParent,rhsBinds); } /*============================================*/ /* Send the partial match to all child joins. */ /*============================================*/ listOfJoins = join->nextLinks; if (listOfJoins == NULL) return; while (listOfJoins != NULL) { /*===================================================================*/ /* An exists CE as the first pattern of a rule can generate at most */ /* one partial match, so if there's already a partial match in the */ /* beta memory nothing further needs to be done. Since there are no */ /* variable bindings which child joins can use for indexing, the */ /* partial matches will always be stored in the bucket with index 0. */ /* Although an exists is associated with a specific fact/instance */ /* (through its rightParent link) that allows it to be satisfied, */ /* the bindings in the partial match will be empty for this CE. */ /*===================================================================*/ if (join->patternIsExists) { linker = CreateEmptyPartialMatch(theEnv); } /*=============================================================*/ /* Othewise just copy the partial match from the alpha memory. */ /*=============================================================*/ else { linker = CopyPartialMatch(theEnv,rhsBinds); } /*================================================*/ /* Determine the hash value of the partial match. */ /*================================================*/ if (listOfJoins->enterDirection == LHS) { if (listOfJoins->join->leftHash != NULL) { hashValue = BetaMemoryHashValue(theEnv,listOfJoins->join->leftHash,linker,NULL,listOfJoins->join); } else { hashValue = 0; } } else { if (listOfJoins->join->rightHash != NULL) { hashValue = BetaMemoryHashValue(theEnv,listOfJoins->join->rightHash,linker,NULL,listOfJoins->join); } else { hashValue = 0; } } /*=======================================================*/ /* Add the partial match to the beta memory of the join. */ /*=======================================================*/ if (join->patternIsExists) { UpdateBetaPMLinks(theEnv,linker,existsParent,NULL,listOfJoins->join,hashValue,listOfJoins->enterDirection); } else { UpdateBetaPMLinks(theEnv,linker,NULL,rhsBinds,listOfJoins->join,hashValue,listOfJoins->enterDirection); } if (listOfJoins->enterDirection == LHS) { NetworkAssertLeft(theEnv,linker,listOfJoins->join); } else { NetworkAssertRight(theEnv,linker,listOfJoins->join); } listOfJoins = listOfJoins->next; } }
globle intBool EvaluateJoinExpression( void *theEnv, struct expr *joinExpr, struct joinNode *joinPtr) { DATA_OBJECT theResult; int andLogic, result = TRUE; /*======================================*/ /* A NULL expression evaluates to TRUE. */ /*======================================*/ if (joinExpr == NULL) return(TRUE); /*====================================================*/ /* Initialize some variables which allow this routine */ /* to avoid calling the "and" and "or" functions if */ /* they are the first part of the expression to be */ /* evaluated. Most of the join expressions do not use */ /* deeply nested and/or functions so this technique */ /* speeds up evaluation. */ /*====================================================*/ if (joinExpr->value == ExpressionData(theEnv)->PTR_AND) { andLogic = TRUE; joinExpr = joinExpr->argList; } else if (joinExpr->value == ExpressionData(theEnv)->PTR_OR) { andLogic = FALSE; joinExpr = joinExpr->argList; } else { andLogic = TRUE; } /*=========================================*/ /* Evaluate each of the expressions linked */ /* together in the join expression. */ /*=========================================*/ while (joinExpr != NULL) { /*================================*/ /* Evaluate a primitive function. */ /*================================*/ if ((EvaluationData(theEnv)->PrimitivesArray[joinExpr->type] == NULL) ? FALSE : EvaluationData(theEnv)->PrimitivesArray[joinExpr->type]->evaluateFunction != NULL) { struct expr *oldArgument; oldArgument = EvaluationData(theEnv)->CurrentExpression; EvaluationData(theEnv)->CurrentExpression = joinExpr; result = (*EvaluationData(theEnv)->PrimitivesArray[joinExpr->type]->evaluateFunction)(theEnv,joinExpr->value,&theResult); EvaluationData(theEnv)->CurrentExpression = oldArgument; } /*=============================*/ /* Evaluate the "or" function. */ /*=============================*/ else if (joinExpr->value == ExpressionData(theEnv)->PTR_OR) { result = FALSE; if (EvaluateJoinExpression(theEnv,joinExpr,joinPtr) == TRUE) { if (EvaluationData(theEnv)->EvaluationError) { return(FALSE); } result = TRUE; } else if (EvaluationData(theEnv)->EvaluationError) { return(FALSE); } } /*==============================*/ /* Evaluate the "and" function. */ /*==============================*/ else if (joinExpr->value == ExpressionData(theEnv)->PTR_AND) { result = TRUE; if (EvaluateJoinExpression(theEnv,joinExpr,joinPtr) == FALSE) { if (EvaluationData(theEnv)->EvaluationError) { return(FALSE); } result = FALSE; } else if (EvaluationData(theEnv)->EvaluationError) { return(FALSE); } } /*==========================================================*/ /* Evaluate all other expressions using EvaluateExpression. */ /*==========================================================*/ else { EvaluateExpression(theEnv,joinExpr,&theResult); if (EvaluationData(theEnv)->EvaluationError) { JoinNetErrorMessage(theEnv,joinPtr); return(FALSE); } if ((theResult.value == EnvFalseSymbol(theEnv)) && (theResult.type == SYMBOL)) { result = FALSE; } else { result = TRUE; } } /*====================================*/ /* Handle the short cut evaluation of */ /* the "and" and "or" functions. */ /*====================================*/ if ((andLogic == TRUE) && (result == FALSE)) { return(FALSE); } else if ((andLogic == FALSE) && (result == TRUE)) { return(TRUE); } /*==============================================*/ /* Move to the next expression to be evaluated. */ /*==============================================*/ joinExpr = joinExpr->nextArg; } /*=================================================*/ /* Return the result of evaluating the expression. */ /*=================================================*/ return(result); }
globle void NetworkAssertLeft( void *theEnv, struct partialMatch *lhsBinds, struct joinNode *join) { struct partialMatch *rhsBinds; int exprResult, restore = FALSE; unsigned long entryHashValue; 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 /*===================================*/ /* The only action for the last join */ /* of a rule is to activate it. */ /*===================================*/ if (join->ruleToActivate != NULL) { AddActivation(theEnv,join->ruleToActivate,lhsBinds); return; } /*==================================================*/ /* Initialize some variables used to indicate which */ /* side is being compared to the new partial match. */ /*==================================================*/ entryHashValue = lhsBinds->hashValue; if (join->joinFromTheRight) { rhsBinds = GetRightBetaMemory(join,entryHashValue); } else { rhsBinds = GetAlphaMemory(theEnv,(struct patternNodeHeader *) join->rightSideEntryStructure,entryHashValue); } #if DEVELOPER if (rhsBinds != NULL) { EngineData(theEnv)->leftToRightLoops++; } #endif /*====================================*/ /* Set up the evaluation environment. */ /*====================================*/ if ((rhsBinds != NULL) || (join->secondaryNetworkTest != NULL)) { oldLHSBinds = EngineData(theEnv)->GlobalLHSBinds; oldRHSBinds = EngineData(theEnv)->GlobalRHSBinds; oldJoin = EngineData(theEnv)->GlobalJoin; EngineData(theEnv)->GlobalLHSBinds = lhsBinds; 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 (rhsBinds != NULL) { join->memoryCompares++; /*===================================================*/ /* 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)->leftToRightComparisons++; #endif EngineData(theEnv)->GlobalRHSBinds = rhsBinds; exprResult = EvaluateJoinExpression(theEnv,join->networkTest,join); if (EvaluationData(theEnv)->EvaluationError) { if (join->patternIsNegated) exprResult = TRUE; SetEvaluationError(theEnv,FALSE); } #if DEVELOPER if (exprResult) { EngineData(theEnv)->leftToRightSucceeds++; } #endif } // Bug Fix - Need to evaluate secondary network test for exists CE 0881 if ((join->secondaryNetworkTest != NULL) && exprResult && join->patternIsExists) { EngineData(theEnv)->GlobalRHSBinds = rhsBinds; 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) { /*==============================================*/ /* 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->patternIsExists == FALSE) && (join->joinFromTheRight == FALSE)) { PPDrive(theEnv,lhsBinds,rhsBinds,join); } /*==================================================*/ /* At most, one partial match will be generated for */ /* a match from the right memory of an exists CE. */ /*==================================================*/ else if (join->patternIsExists) { AddBlockedLink(lhsBinds,rhsBinds); PPDrive(theEnv,lhsBinds,NULL,join); EngineData(theEnv)->GlobalLHSBinds = oldLHSBinds; EngineData(theEnv)->GlobalRHSBinds = oldRHSBinds; EngineData(theEnv)->GlobalJoin = oldJoin; return; } /*===========================================================*/ /* 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 { AddBlockedLink(lhsBinds,rhsBinds); break; } } /*====================================*/ /* Move on to the next partial match. */ /*====================================*/ rhsBinds = rhsBinds->nextInMemory; } /*==================================================================*/ /* 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) && (! join->patternIsExists) && (lhsBinds->marker == NULL)) { if (join->secondaryNetworkTest != NULL) { EngineData(theEnv)->GlobalRHSBinds = NULL; exprResult = EvaluateJoinExpression(theEnv,join->secondaryNetworkTest,join); if (EvaluationData(theEnv)->EvaluationError) { SetEvaluationError(theEnv,FALSE); } if (exprResult) { PPDrive(theEnv,lhsBinds,NULL,join); } } else { PPDrive(theEnv,lhsBinds,NULL,join); } } /*=========================================*/ /* Restore the old evaluation environment. */ /*=========================================*/ if (restore) { EngineData(theEnv)->GlobalLHSBinds = oldLHSBinds; EngineData(theEnv)->GlobalRHSBinds = oldRHSBinds; EngineData(theEnv)->GlobalJoin = oldJoin; } 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; }