static void CheckForPrimableJoins( void *theEnv, struct defrule *tempRule) { struct joinNode *joinPtr; struct partialMatch *theList; /*========================================*/ /* Loop through each of the rule's joins. */ /*========================================*/ for (joinPtr = tempRule->lastJoin; joinPtr != NULL; joinPtr = GetPreviousJoin(joinPtr)) { /*===============================*/ /* Update the join if necessary. */ /*===============================*/ if ((joinPtr->initialize) && (! joinPtr->marked)) /* GDR 6.05 */ { if (joinPtr->firstJoin == TRUE) { if (((struct patternNodeHeader *) GetPatternForJoin(joinPtr))->initialize == FALSE) { PrimeJoin(theEnv,joinPtr); joinPtr->marked = TRUE; /* GDR 6.05 */ } } else if (joinPtr->lastLevel->initialize == FALSE) { PrimeJoin(theEnv,joinPtr); joinPtr->marked = TRUE; /* GDR 6.05 */ } } /*================================================================*/ /* If the join is associated with a rule activation (i.e. partial */ /* matches that reach this join cause an activation to be placed */ /* on the agenda), then add activations to the agenda for the */ /* rule being incrementally reset. */ /*================================================================*/ else if (joinPtr->ruleToActivate == tempRule) { for (theList = joinPtr->beta; theList != NULL; theList = theList->next) { AddActivation(theEnv,tempRule,theList); } } } }
globle void PNLDrive( void *theEnv, struct joinNode *join, struct partialMatch *binds) { struct joinNode *listOfJoins; struct alphaMatch *tempAlpha; /*=======================================================*/ /* Create a pseudo-fact representing the facts which did */ /* not match the not CE associated with this join. */ /*=======================================================*/ tempAlpha = get_struct(theEnv,alphaMatch); tempAlpha->next = NULL; tempAlpha->matchingItem = NULL; tempAlpha->markers = NULL; /*===============================================*/ /* Store the pointer to the pseudo-fact directly */ /* in the beta memory partial match. */ /*===============================================*/ binds->counterf = FALSE; binds->binds[binds->bcount - 1].gm.theMatch = tempAlpha; /*====================================================*/ /* Activate the rule satisfied by this partial match. */ /*====================================================*/ if (join->ruleToActivate != NULL) AddActivation(theEnv,join->ruleToActivate,binds); /*========================================================*/ /* Send the merged partial match to all descendent joins. */ /*========================================================*/ listOfJoins = join->nextLevel; if (listOfJoins != NULL) { if (((struct joinNode *) (listOfJoins->rightSideEntryStructure)) == join) { NetworkAssert(theEnv,binds,listOfJoins,RHS); } else while (listOfJoins != NULL) { NetworkAssert(theEnv,binds,listOfJoins,LHS); listOfJoins = listOfJoins->rightDriveNode; } } }
static void PPDrive( void *theEnv, struct partialMatch *lhsBinds, struct partialMatch *rhsBinds, struct joinNode *join) { struct partialMatch *linker; struct joinNode *listOfJoins; /*==================================================*/ /* Merge the alpha and beta memory partial matches. */ /*==================================================*/ linker = MergePartialMatches(theEnv,lhsBinds,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(theEnv,join->ruleToActivate,linker); /*================================================*/ /* Send the new partial match to all child joins. */ /*================================================*/ listOfJoins = join->nextLevel; if (listOfJoins != NULL) { if (((struct joinNode *) (listOfJoins->rightSideEntryStructure)) == join) { NetworkAssert(theEnv,linker,listOfJoins,RHS); } else while (listOfJoins != NULL) { NetworkAssert(theEnv,linker,listOfJoins,LHS); listOfJoins = listOfJoins->rightDriveNode; } } return; }
globle intBool EnvRefresh( void *theEnv, void *theRule) { struct defrule *rulePtr; struct partialMatch *listOfMatches; unsigned long b; /*====================================*/ /* Refresh each disjunct of the rule. */ /*====================================*/ for (rulePtr = (struct defrule *) theRule; rulePtr != NULL; rulePtr = rulePtr->disjunct) { /*================================*/ /* Check each partial match that */ /* satisfies the LHS of the rule. */ /*================================*/ for (b = 0; b < rulePtr->lastJoin->leftMemory->size; b++) { for (listOfMatches = rulePtr->lastJoin->leftMemory->beta[b]; listOfMatches != NULL; listOfMatches = listOfMatches->nextInMemory) { /*=======================================================*/ /* If the partial match is associated with an activation */ /* (which it should always be), then place a new */ /* activation on the agenda if this partial matchdoesn't */ /* have an activation associated with it. */ /*=======================================================*/ if (((struct joinNode *) listOfMatches->owner)->ruleToActivate != NULL) { if (listOfMatches->marker == NULL) { AddActivation(theEnv,rulePtr,listOfMatches); } } } } } return(TRUE); }
void NegEntryRetract( struct joinNode *theJoin, struct partialMatch *theMatch, int duringRetract) { struct partialMatch *theLHS; int result; struct rdriveinfo *tempDR; struct alphaMatch *tempAlpha; struct joinNode *listOfJoins; /*===============================================*/ /* Loop through all LHS partial matches checking */ /* for sets that satisfied the join expression. */ /*===============================================*/ for (theLHS = theJoin->beta; theLHS != NULL; theLHS = theLHS->next) { /*===========================================================*/ /* Don't bother checking partial matches that are satisfied. */ /* We're looking for joins from which the removal of a */ /* partial match would satisfy the join. */ /*===========================================================*/ if (theLHS->counterf == FALSE) continue; /*==================================================*/ /* If the partial match being removed isn't the one */ /* preventing the LHS partial match from being */ /* satisifed, then don't bother processing it. */ /*==================================================*/ if (theLHS->binds[theLHS->bcount - 1].gm.theValue != (void *) theMatch) continue; /*======================================================*/ /* Try to find another RHS partial match which prevents */ /* the LHS partial match from being satisifed. */ /*======================================================*/ theLHS->binds[theLHS->bcount - 1].gm.theValue = NULL; result = FindNextConflictingAlphaMatch(theLHS,theMatch->next,theJoin); /*=========================================================*/ /* If the LHS partial match now has no RHS partial matches */ /* that conflict with it, then it satisfies the conditions */ /* of the RHS not CE. Create a partial match and send it */ /* to the joins below. */ /*=========================================================*/ if (result == FALSE) { /*===============================*/ /* Create the new partial match. */ /*===============================*/ theLHS->counterf = FALSE; tempAlpha = get_struct(alphaMatch); tempAlpha->next = NULL; tempAlpha->matchingItem = NULL; tempAlpha->markers = NULL; theLHS->binds[theLHS->bcount - 1].gm.theMatch = tempAlpha; /*==============================================*/ /* If partial matches from this join correspond */ /* to a rule activation, then add an activation */ /* to the agenda. */ /*==============================================*/ if (theJoin->ruleToActivate != NULL) { AddActivation(theJoin->ruleToActivate,theLHS); } /*=======================================================*/ /* Send the partial match to the list of joins following */ /* this join. If we're in the middle of a retract, add */ /* the partial match to the list of join activities that */ /* need to be processed later. If we're doing an assert, */ /* then the join activity can be processed immediately. */ /*=======================================================*/ listOfJoins = theJoin->nextLevel; if (listOfJoins != NULL) { if (((struct joinNode *) (listOfJoins->rightSideEntryStructure)) == theJoin) { NetworkAssert(theLHS,listOfJoins,RHS); } else { if (duringRetract) { tempDR = get_struct(rdriveinfo); tempDR->link = theLHS; tempDR->jlist = theJoin->nextLevel; tempDR->next = DriveRetractionList; DriveRetractionList = tempDR; } else while (listOfJoins != NULL) { NetworkAssert(theLHS,listOfJoins,LHS); listOfJoins = listOfJoins->rightDriveNode; } } } } } }
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 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; }