globle intBool EnvDeleteActivation( void *theEnv, void *theActivation) { if (theActivation == NULL) RemoveAllActivations(theEnv); else RemoveActivation(theEnv,(struct activation *) theActivation,TRUE,TRUE); return(TRUE); }
globle void ClearRuleFromAgenda( void *theEnv, void *vTheRule) { struct defrule *theRule = (struct defrule *) vTheRule; struct defrule *tempRule; struct activation *agendaPtr, *agendaNext; /*============================================*/ /* Get a pointer to the agenda for the module */ /* in which the rule is contained. */ /*============================================*/ agendaPtr = ((struct defruleModule *) theRule->header.whichModule)->agenda; /*==============================================*/ /* Loop through every activation on the agenda. */ /*==============================================*/ while (agendaPtr != NULL) { agendaNext = agendaPtr->next; /*========================================================*/ /* Check each disjunct of the rule against the activation */ /* to determine if the activation points to the rule. If */ /* it does, then remove the activation from the agenda. */ /*========================================================*/ for (tempRule = theRule; tempRule != NULL; tempRule = tempRule->disjunct) { if (agendaPtr->theRule == tempRule) { RemoveActivation(theEnv,agendaPtr,TRUE,TRUE); break; } } agendaPtr = agendaNext; } }
globle void RemoveAllActivations( void *theEnv) { struct activation *tempPtr, *theActivation; struct salienceGroup *theGroup, *tempGroup; theActivation = GetDefruleModuleItem(theEnv,NULL)->agenda; while (theActivation != NULL) { tempPtr = theActivation->next; RemoveActivation(theEnv,theActivation,TRUE,TRUE); theActivation = tempPtr; } theGroup = GetDefruleModuleItem(theEnv,NULL)->groupings; while (theGroup != NULL) { tempGroup = theGroup->next; rtn_struct(theEnv,salienceGroup,theGroup); theGroup = tempGroup; } }
static struct partialMatch *RemovePartialMatches( struct alphaMatch *theAlphaNode, struct partialMatch *listOfPMs, struct partialMatch **deleteHead, int position, struct partialMatch **returnLast) { struct partialMatch *head, *lastPM, *nextPM; struct partialMatch *lastDelete = NULL; /*====================================================*/ /* Initialize pointers used for creating the new list */ /* of partial matches and the list of partial matches */ /* to be deleted. */ /*====================================================*/ head = listOfPMs; lastPM = listOfPMs; *deleteHead = NULL; /*==========================================*/ /* Loop through each of the partial matches */ /* and determine if it needs to be deleted. */ /*==========================================*/ while (listOfPMs != NULL) { if ((listOfPMs->counterf == TRUE) && (position == (listOfPMs->bcount - 1))) { lastPM = listOfPMs; listOfPMs = listOfPMs->next; } /*=====================================================*/ /* Otherwise, if the specified position in the partial */ /* match contains the specified data entity, then */ /* remove the partial match from the list and add it */ /* to a deletion list. */ /*=====================================================*/ else if (listOfPMs->binds[position].gm.theMatch == theAlphaNode) { /*===================================================*/ /* If the partial match has an activation associated */ /* with it, then return the activation. */ /*===================================================*/ if ((listOfPMs->activationf) ? (listOfPMs->binds[listOfPMs->bcount].gm.theValue != NULL) : FALSE) { RemoveActivation((struct activation *) listOfPMs->binds[listOfPMs->bcount].gm.theValue,TRUE,TRUE); } /*==================================================*/ /* If the partial match is at the head of the list */ /* of matches, then use the following deletion code */ /* for the head of the list. */ /*==================================================*/ if (listOfPMs == head) { /*===================================*/ /* Remember the new beginning of the */ /* new list of partial matches. */ /*===================================*/ nextPM = listOfPMs->next; /*=============================================*/ /* Add the partial match to the deletion list. */ /*=============================================*/ if (*deleteHead == NULL) { *deleteHead = listOfPMs; } else { lastDelete->next = listOfPMs; } listOfPMs->next = NULL; lastDelete = listOfPMs; /*================================================*/ /* Update the head and tail pointers for the new */ /* list of partial matches as well as the pointer */ /* to the next partial match to be examined. */ /*================================================*/ listOfPMs = nextPM; head = listOfPMs; lastPM = head; } /*======================================*/ /* Otherwise, use the following code to */ /* delete the partial match. */ /*======================================*/ else { /*========================================*/ /* Detach the partial match being deleted */ /* from the new list of partial matches. */ /*========================================*/ lastPM->next = listOfPMs->next; /*=============================================*/ /* Add the partial match to the deletion list. */ /*=============================================*/ if (*deleteHead == NULL) { *deleteHead = listOfPMs; } else { lastDelete->next = listOfPMs; } listOfPMs->next = NULL; lastDelete = listOfPMs; /*=============================*/ /* Move on to the next partial */ /* match to be examined. */ /*=============================*/ listOfPMs = lastPM->next; } } /*==============================================*/ /* Otherwise, the partial match should be added */ /* to the new list of partial matches. */ /*==============================================*/ else { lastPM = listOfPMs; listOfPMs = listOfPMs->next; } } /*===============================================*/ /* Return the last partial match in the new list */ /* of partial matches via one of the function's */ /* parameters. */ /*===============================================*/ *returnLast = lastPM; /*=====================================================*/ /* Return the head of the new list of partial matches. */ /*=====================================================*/ return(head); }
static void PNRDrive( struct joinNode *join, struct partialMatch *lhsBinds, struct partialMatch *rhsBinds) { struct joinNode *listOfJoins; /*==================================================*/ /* If the partial match already has a partial match */ /* in the alpha memory which prevents it from being */ /* satisfied, then don't do anything. */ /*==================================================*/ if (lhsBinds->counterf == TRUE) return; /*=================================================*/ /* Set the counterf flag to indicate that an alpha */ /* memory partial match is preventing the beta */ /* memory partial match from being satisfied. */ /*=================================================*/ lhsBinds->counterf = TRUE; /*===================================================================*/ /* If the partial match caused an activation, remove the activation. */ /*===================================================================*/ if ((lhsBinds->activationf) ? (lhsBinds->binds[lhsBinds->bcount].gm.theValue != NULL) : FALSE) { RemoveActivation((struct activation *) lhsBinds->binds[lhsBinds->bcount].gm.theValue,TRUE,TRUE); } /*===========================================================*/ /* The counterf flag was FALSE. This means that a pointer to */ /* the pseudo-fact matching the not CE is stored directly in */ /* the partial match. Determine the ID of this pseudo-fact */ /* and remove all partial matches from descendent joins that */ /* contain the ID. */ /*===========================================================*/ if (join->joinFromTheRight) /* DR0834 */ { RetractCheckDriveRetractions(lhsBinds->binds[lhsBinds->bcount - 1].gm.theMatch, (int) join->depth-1); } listOfJoins = join->nextLevel; if (listOfJoins != NULL) { if (((struct joinNode *) (listOfJoins->rightSideEntryStructure)) == join) { NegEntryRetract(listOfJoins,lhsBinds,FALSE); } else while (listOfJoins != NULL) { PosEntryRetract(listOfJoins, lhsBinds->binds[lhsBinds->bcount - 1].gm.theMatch, lhsBinds,(int) join->depth-1,FALSE); listOfJoins = listOfJoins->rightDriveNode; } } /*=========================================================================*/ /* Remove any logical dependency links associated with this partial match. */ /*=========================================================================*/ #if LOGICAL_DEPENDENCIES if (lhsBinds->dependentsf) RemoveLogicalSupport(lhsBinds); #endif /*========================================*/ /* Put the pseudo-fact on a garbage list. */ /*========================================*/ lhsBinds->binds[lhsBinds->bcount - 1].gm.theMatch->next = GarbageAlphaMatches; GarbageAlphaMatches = lhsBinds->binds[lhsBinds->bcount - 1].gm.theMatch; /*========================================================*/ /* Store the partial match from the alpha memory that is */ /* preventing the LHS partial match from being satisfied. */ /*========================================================*/ lhsBinds->binds[lhsBinds->bcount - 1].gm.theValue = (void *) rhsBinds; }
globle long int EnvRun( void *theEnv, long int runLimit) { long int rulesFired = 0; DATA_OBJECT result; struct callFunctionItem *theRunFunction; #if DEBUGGING_FUNCTIONS unsigned long maxActivations = 0, sumActivations = 0; #if DEFTEMPLATE_CONSTRUCT unsigned long maxFacts = 0, sumFacts = 0; #endif #if OBJECT_SYSTEM unsigned long maxInstances = 0, sumInstances = 0; #endif double endTime, startTime = 0.0; unsigned long tempValue; #endif unsigned int i; struct patternEntity *theMatchingItem; struct partialMatch *theBasis; ACTIVATION *theActivation; char *ruleFiring; #if PROFILING_FUNCTIONS struct profileFrameInfo profileFrame; #endif /*=====================================================*/ /* Make sure the run command is not already executing. */ /*=====================================================*/ if (EngineData(theEnv)->AlreadyRunning) return(0); EngineData(theEnv)->AlreadyRunning = TRUE; /*================================*/ /* Set up statistics information. */ /*================================*/ #if DEBUGGING_FUNCTIONS if (EngineData(theEnv)->WatchStatistics) { #if DEFTEMPLATE_CONSTRUCT maxFacts = GetNumberOfFacts(theEnv); sumFacts = maxFacts; #endif #if OBJECT_SYSTEM maxInstances = GetGlobalNumberOfInstances(theEnv); sumInstances = maxInstances; #endif maxActivations = GetNumberOfActivations(theEnv); sumActivations = maxActivations; startTime = gentime(); } #endif /*=============================*/ /* Set up execution variables. */ /*=============================*/ if (EvaluationData(theEnv)->CurrentEvaluationDepth == 0) SetHaltExecution(theEnv,FALSE); EngineData(theEnv)->HaltRules = FALSE; /*=====================================================*/ /* Fire rules until the agenda is empty, the run limit */ /* has been reached, or a rule execution error occurs. */ /*=====================================================*/ theActivation = NextActivationToFire(theEnv); while ((theActivation != NULL) && (runLimit != 0) && (EvaluationData(theEnv)->HaltExecution == FALSE) && (EngineData(theEnv)->HaltRules == FALSE)) { /*===========================================*/ /* Detach the activation from the agenda and */ /* determine which rule is firing. */ /*===========================================*/ DetachActivation(theEnv,theActivation); ruleFiring = EnvGetActivationName(theEnv,theActivation); theBasis = (struct partialMatch *) GetActivationBasis(theActivation); EngineData(theEnv)->ExecutingRule = (struct defrule *) GetActivationRule(theActivation); /*=============================================*/ /* Update the number of rules that have fired. */ /*=============================================*/ rulesFired++; if (runLimit > 0) { runLimit--; } /*==================================*/ /* If rules are being watched, then */ /* print an information message. */ /*==================================*/ #if DEBUGGING_FUNCTIONS if (EngineData(theEnv)->ExecutingRule->watchFiring) { char printSpace[60]; sprintf(printSpace,"FIRE %4ld ",rulesFired); EnvPrintRouter(theEnv,WTRACE,printSpace); EnvPrintRouter(theEnv,WTRACE,ruleFiring); EnvPrintRouter(theEnv,WTRACE,": "); PrintPartialMatch(theEnv,WTRACE,theBasis); EnvPrintRouter(theEnv,WTRACE,"\n"); } #endif /*=================================================*/ /* Remove the link between the activation and the */ /* completed match for the rule. Set the busy flag */ /* for the completed match to TRUE (so the match */ /* upon which our RHS variables are dependent is */ /* not deleted while our rule is firing). Set up */ /* the global pointers to the completed match for */ /* routines which do variable extractions. */ /*=================================================*/ theBasis->binds[theBasis->bcount].gm.theValue = NULL; theBasis->busy = TRUE; EngineData(theEnv)->GlobalLHSBinds = theBasis; EngineData(theEnv)->GlobalRHSBinds = NULL; /*===================================================================*/ /* Increment the count for each of the facts/objects associated with */ /* the rule activation so that the facts/objects cannot be deleted */ /* by garbage collection while the rule is executing. */ /*===================================================================*/ for (i = 0; i < theBasis->bcount; i++) { theMatchingItem = theBasis->binds[i].gm.theMatch->matchingItem; if (theMatchingItem != NULL) { (*theMatchingItem->theInfo->incrementBasisCount)(theEnv,theMatchingItem); } } /*====================================================*/ /* Execute the rule's right hand side actions. If the */ /* rule has logical CEs, set up the pointer to the */ /* rules logical join so the assert command will */ /* attach the appropriate dependencies to the facts. */ /*====================================================*/ EngineData(theEnv)->TheLogicalJoin = EngineData(theEnv)->ExecutingRule->logicalJoin; EvaluationData(theEnv)->CurrentEvaluationDepth++; SetEvaluationError(theEnv,FALSE); EngineData(theEnv)->ExecutingRule->executing = TRUE; #if PROFILING_FUNCTIONS StartProfile(theEnv,&profileFrame, &EngineData(theEnv)->ExecutingRule->header.usrData, ProfileFunctionData(theEnv)->ProfileConstructs); #endif EvaluateProcActions(theEnv,EngineData(theEnv)->ExecutingRule->header.whichModule->theModule, EngineData(theEnv)->ExecutingRule->actions,EngineData(theEnv)->ExecutingRule->localVarCnt, &result,NULL); #if PROFILING_FUNCTIONS EndProfile(theEnv,&profileFrame); #endif EngineData(theEnv)->ExecutingRule->executing = FALSE; SetEvaluationError(theEnv,FALSE); EvaluationData(theEnv)->CurrentEvaluationDepth--; EngineData(theEnv)->TheLogicalJoin = NULL; /*=====================================================*/ /* If rule execution was halted, then print a message. */ /*=====================================================*/ #if DEBUGGING_FUNCTIONS if ((EvaluationData(theEnv)->HaltExecution) || (EngineData(theEnv)->HaltRules && EngineData(theEnv)->ExecutingRule->watchFiring)) #else if ((EvaluationData(theEnv)->HaltExecution) || (EngineData(theEnv)->HaltRules)) #endif { PrintErrorID(theEnv,"PRCCODE",4,FALSE); EnvPrintRouter(theEnv,WERROR,"Execution halted during the actions of defrule "); EnvPrintRouter(theEnv,WERROR,ruleFiring); EnvPrintRouter(theEnv,WERROR,".\n"); } /*===================================================================*/ /* Decrement the count for each of the facts/objects associated with */ /* the rule activation. If the last match for the activation */ /* is from a not CE, then we need to make sure that the last */ /* match is an actual match for the CE and not a counter. */ /*===================================================================*/ theBasis->busy = FALSE; for (i = 0; i < (theBasis->bcount - 1); i++) { theMatchingItem = theBasis->binds[i].gm.theMatch->matchingItem; if (theMatchingItem != NULL) { (*theMatchingItem->theInfo->decrementBasisCount)(theEnv,theMatchingItem); } } i = (unsigned) (theBasis->bcount - 1); if (theBasis->counterf == FALSE) { theMatchingItem = theBasis->binds[i].gm.theMatch->matchingItem; if (theMatchingItem != NULL) { (*theMatchingItem->theInfo->decrementBasisCount)(theEnv,theMatchingItem); } } /*========================================*/ /* Return the agenda node to free memory. */ /*========================================*/ RemoveActivation(theEnv,theActivation,FALSE,FALSE); /*======================================*/ /* Get rid of partial matches discarded */ /* while executing the rule's RHS. */ /*======================================*/ FlushGarbagePartialMatches(theEnv); /*==================================*/ /* Get rid of other garbage created */ /* while executing the rule's RHS. */ /*==================================*/ PeriodicCleanup(theEnv,FALSE,TRUE); /*==========================*/ /* Keep up with statistics. */ /*==========================*/ #if DEBUGGING_FUNCTIONS if (EngineData(theEnv)->WatchStatistics) { #if DEFTEMPLATE_CONSTRUCT tempValue = GetNumberOfFacts(theEnv); if (tempValue > maxFacts) maxFacts = tempValue; sumFacts += tempValue; #endif #if OBJECT_SYSTEM tempValue = GetGlobalNumberOfInstances(theEnv); if (tempValue > maxInstances) maxInstances = tempValue; sumInstances += tempValue; #endif tempValue = GetNumberOfActivations(theEnv); if (tempValue > maxActivations) maxActivations = tempValue; sumActivations += tempValue; } #endif /*==================================*/ /* Update saliences if appropriate. */ /*==================================*/ if (EnvGetSalienceEvaluation(theEnv) == EVERY_CYCLE) EnvRefreshAgenda(theEnv,NULL); /*========================================*/ /* Execute the list of functions that are */ /* to be called after each rule firing. */ /*========================================*/ for (theRunFunction = EngineData(theEnv)->ListOfRunFunctions; theRunFunction != NULL; theRunFunction = theRunFunction->next) { if (theRunFunction->environmentAware) { (*theRunFunction->func)(theEnv); } else { ((void (*)(void))(*theRunFunction->func))(); } } /*========================================*/ /* If a return was issued on the RHS of a */ /* rule, then remove *that* rule's module */ /* from the focus stack */ /*========================================*/ if (ProcedureFunctionData(theEnv)->ReturnFlag == TRUE) { RemoveFocus(theEnv,EngineData(theEnv)->ExecutingRule->header.whichModule->theModule); } ProcedureFunctionData(theEnv)->ReturnFlag = FALSE; /*========================================*/ /* Determine the next activation to fire. */ /*========================================*/ theActivation = (struct activation *) NextActivationToFire(theEnv); /*==============================*/ /* Check for a rule breakpoint. */ /*==============================*/ if (theActivation != NULL) { if (((struct defrule *) GetActivationRule(theActivation))->afterBreakpoint) { EngineData(theEnv)->HaltRules = TRUE; EnvPrintRouter(theEnv,WDIALOG,"Breaking on rule "); EnvPrintRouter(theEnv,WDIALOG,EnvGetActivationName(theEnv,theActivation)); EnvPrintRouter(theEnv,WDIALOG,".\n"); } } } /*=====================================================*/ /* Make sure run functions are executed at least once. */ /*=====================================================*/ if (rulesFired == 0) { for (theRunFunction = EngineData(theEnv)->ListOfRunFunctions; theRunFunction != NULL; theRunFunction = theRunFunction->next) { if (theRunFunction->environmentAware) { (*theRunFunction->func)(theEnv); } else { ((void (*)(void))(*theRunFunction->func))(); } } } /*======================================================*/ /* If rule execution was halted because the rule firing */ /* limit was reached, then print a message. */ /*======================================================*/ if (runLimit == rulesFired) { EnvPrintRouter(theEnv,WDIALOG,"rule firing limit reached\n"); } /*==============================*/ /* Restore execution variables. */ /*==============================*/ EngineData(theEnv)->ExecutingRule = NULL; EngineData(theEnv)->HaltRules = FALSE; /*=================================================*/ /* Print out statistics if they are being watched. */ /*=================================================*/ #if DEBUGGING_FUNCTIONS if (EngineData(theEnv)->WatchStatistics) { char printSpace[60]; endTime = gentime(); PrintLongInteger(theEnv,WDIALOG,rulesFired); EnvPrintRouter(theEnv,WDIALOG," rules fired"); #if (! GENERIC) if (startTime != endTime) { EnvPrintRouter(theEnv,WDIALOG," Run time is "); PrintFloat(theEnv,WDIALOG,endTime - startTime); EnvPrintRouter(theEnv,WDIALOG," seconds.\n"); PrintFloat(theEnv,WDIALOG,(double) rulesFired / (endTime - startTime)); EnvPrintRouter(theEnv,WDIALOG," rules per second.\n"); } else { EnvPrintRouter(theEnv,WDIALOG,"\n"); } #endif #if DEFTEMPLATE_CONSTRUCT sprintf(printSpace,"%ld mean number of facts (%ld maximum).\n", (long) (((double) sumFacts / (rulesFired + 1)) + 0.5), maxFacts); EnvPrintRouter(theEnv,WDIALOG,printSpace); #endif #if OBJECT_SYSTEM sprintf(printSpace,"%ld mean number of instances (%ld maximum).\n", (long) (((double) sumInstances / (rulesFired + 1)) + 0.5), maxInstances); EnvPrintRouter(theEnv,WDIALOG,printSpace); #endif sprintf(printSpace,"%ld mean number of activations (%ld maximum).\n", (long) (((double) sumActivations / (rulesFired + 1)) + 0.5), maxActivations); EnvPrintRouter(theEnv,WDIALOG,printSpace); } #endif /*==========================================*/ /* The current module should be the current */ /* focus when the run finishes. */ /*==========================================*/ if (EngineData(theEnv)->CurrentFocus != NULL) { if (EngineData(theEnv)->CurrentFocus->theModule != ((struct defmodule *) EnvGetCurrentModule(theEnv))) { EnvSetCurrentModule(theEnv,(void *) EngineData(theEnv)->CurrentFocus->theModule); } } /*===================================*/ /* Return the number of rules fired. */ /*===================================*/ EngineData(theEnv)->AlreadyRunning = FALSE; return(rulesFired); }