/*******************************************************/ /* "C" Language Integrated Production System */ /* */ /* CLIPS Version 6.40 10/03/19 */ /* */ /* AGENDA MODULE */ /*******************************************************/ /*************************************************************/ /* Purpose: */ /* Provides functionality for examining, manipulating, */ /* adding, and removing activations from the agenda. */ /* */ /* Principal Programmer(s): */ /* Gary D. Riley */ /* */ /* Contributing Programmer(s): */ /* Brian L. Dantes */ /* */ /* Revision History: */ /* 6.23: Corrected compilation errors for files */ /* generated by constructs-to-c. DR0861 */ /* */ /* 6.24: Removed CONFLICT_RESOLUTION_STRATEGIES */ /* and DYNAMIC_SALIENCE compilation flags. */ /* */ /* Renamed BOOLEAN macro type to intBool. */ /* */ /* Added EnvGetActivationBasisPPForm function. */ /* */ /* 6.30: Added salience groups to improve performance */ /* with large numbers of activations of different */ /* saliences. */ /* */ /* Borland C (IBM_TBC) and Metrowerks CodeWarrior */ /* (MAC_MCW, IBM_MCW) are no longer supported. */ /* */ /* Support for long long integers. */ /* */ /* Added const qualifiers to remove C++ */ /* deprecation warnings. */ /* */ /* Converted API macros to function calls. */ /* */ /* 6.40: Added Env prefix to GetEvaluationError and */ /* SetEvaluationError functions. */ /* */ /* Pragma once and other inclusion changes. */ /* */ /* Added support for booleans with . */ /* */ /* Removed use of void pointers for specific */ /* data structures. */ /* */ /* ALLOW_ENVIRONMENT_GLOBALS no longer supported. */ /* */ /* UDF redesign. */ /* */ /*************************************************************/ #include #include #include "setup.h" #if DEFRULE_CONSTRUCT #include "argacces.h" #include "constant.h" #include "crstrtgy.h" #include "engine.h" #include "envrnmnt.h" #include "extnfunc.h" #include "memalloc.h" #include "moduldef.h" #include "modulutl.h" #include "multifld.h" #include "prntutil.h" #include "reteutil.h" #include "retract.h" #include "router.h" #include "rulebsc.h" #include "ruledef.h" #include "strngrtr.h" #include "sysdep.h" #include "watch.h" #include "agenda.h" /***************************************/ /* LOCAL INTERNAL FUNCTION DEFINITIONS */ /***************************************/ static void PrintActivation(Environment *,const char *,Activation *); static void AgendaClearFunction(Environment *,void *); static const char *SalienceEvaluationName(SalienceEvaluationType); static int EvaluateSalience(Environment *,Defrule *); static struct salienceGroup *ReuseOrCreateSalienceGroup(Environment *,struct defruleModule *,int); static struct salienceGroup *FindSalienceGroup(struct defruleModule *,int); static void RemoveActivationFromGroup(Environment *,Activation *,struct defruleModule *); /*************************************************/ /* InitializeAgenda: Initializes the activations */ /* watch item and the H/L commands for */ /* manipulating the agenda. */ /*************************************************/ void InitializeAgenda( Environment *theEnv) { AllocateEnvironmentData(theEnv,AGENDA_DATA,sizeof(struct agendaData),NULL); AgendaData(theEnv)->SalienceEvaluation = WHEN_DEFINED; AgendaData(theEnv)->Strategy = DEFAULT_STRATEGY; AddClearFunction(theEnv,"agenda",AgendaClearFunction,0,NULL); #if DEBUGGING_FUNCTIONS AddWatchItem(theEnv,"activations",1,&AgendaData(theEnv)->WatchActivations,40,DefruleWatchAccess,DefruleWatchPrint); #endif #if ! RUN_TIME AddUDF(theEnv,"refresh","v",1,1,"y",RefreshCommand,"RefreshCommand",NULL); AddUDF(theEnv,"refresh-agenda","v",0,1,"y",RefreshAgendaCommand,"RefreshAgendaCommand",NULL); AddUDF(theEnv,"get-salience-evaluation","y",0,0,NULL,GetSalienceEvaluationCommand,"GetSalienceEvaluationCommand",NULL); AddUDF(theEnv,"set-salience-evaluation","y",1,1,"y",SetSalienceEvaluationCommand,"SetSalienceEvaluationCommand",NULL); #if DEBUGGING_FUNCTIONS AddUDF(theEnv,"agenda","v",0,1,"y",AgendaCommand,"AgendaCommand",NULL); #endif #endif } /*****************************************************************/ /* AddActivation: Creates a rule activation to be added to the */ /* Agenda and links the activation with its associated partial */ /* match. The function PlaceActivation is then called to place */ /* the activation on the Agenda. Typically called when all */ /* patterns on the LHS of a rule have been satisfied. */ /*****************************************************************/ void AddActivation( Environment *theEnv, Defrule *theRule, PartialMatch *binds) { Activation *newActivation; struct defruleModule *theModuleItem; struct salienceGroup *theGroup; /*=======================================*/ /* Focus on the module if the activation */ /* is from an auto-focus rule. */ /*=======================================*/ if (theRule->autoFocus) { Focus(theRule->header.whichModule->theModule); } /*=======================================================*/ /* Create the activation. The activation stores pointers */ /* to its associated partial match and defrule. The */ /* activation is given a time tag, its salience is */ /* evaluated, and it is assigned a random number for use */ /* with the random conflict resolution strategy. */ /*=======================================================*/ newActivation = get_struct(theEnv,activation); newActivation->theRule = theRule; newActivation->basis = binds; newActivation->timetag = AgendaData(theEnv)->CurrentTimetag++; newActivation->salience = EvaluateSalience(theEnv,theRule); newActivation->randomID = genrand(); newActivation->prev = NULL; newActivation->next = NULL; AgendaData(theEnv)->NumberOfActivations++; /*=======================================================*/ /* Point the partial match to the activation to complete */ /* the link between the join network and the agenda. */ /*=======================================================*/ binds->marker = newActivation; /*====================================================*/ /* If activations are being watch, display a message. */ /*====================================================*/ #if DEBUGGING_FUNCTIONS if (newActivation->theRule->watchActivation && (! ConstructData(theEnv)->ClearReadyInProgress) && (! ConstructData(theEnv)->ClearInProgress)) { WriteString(theEnv,STDOUT,"==> Activation "); PrintActivation(theEnv,STDOUT,newActivation); WriteString(theEnv,STDOUT,"\n"); } #endif /*=====================================*/ /* Place the activation on the agenda. */ /*=====================================*/ theModuleItem = (struct defruleModule *) theRule->header.whichModule; theGroup = ReuseOrCreateSalienceGroup(theEnv,theModuleItem,newActivation->salience); PlaceActivation(theEnv,&(theModuleItem->agenda),newActivation,theGroup); } /*******************************/ /* ReuseOrCreateSalienceGroup: */ /*******************************/ static struct salienceGroup *ReuseOrCreateSalienceGroup( Environment *theEnv, struct defruleModule *theRuleModule, int salience) { struct salienceGroup *theGroup, *lastGroup, *newGroup; for (lastGroup = NULL, theGroup = theRuleModule->groupings; theGroup != NULL; lastGroup = theGroup, theGroup = theGroup->next) { if (theGroup->salience == salience) { return(theGroup); } if (theGroup->salience < salience) { break; } } newGroup = get_struct(theEnv,salienceGroup); newGroup->salience = salience; newGroup->first = NULL; newGroup->last = NULL; newGroup->next = theGroup; newGroup->prev = lastGroup; if (newGroup->next != NULL) { newGroup->next->prev = newGroup; } if (newGroup->prev != NULL) { newGroup->prev->next = newGroup; } if (lastGroup == NULL) { theRuleModule->groupings = newGroup; } return newGroup; } /**********************/ /* FindSalienceGroup: */ /**********************/ static struct salienceGroup *FindSalienceGroup( struct defruleModule *theRuleModule, int salience) { struct salienceGroup *theGroup; for (theGroup = theRuleModule->groupings; theGroup != NULL; theGroup = theGroup->next) { if (theGroup->salience == salience) { return(theGroup); } if (theGroup->salience < salience) { break; } } return NULL; } /***************************************************************/ /* ClearRuleFromAgenda: Clears the agenda of a specified rule. */ /***************************************************************/ void ClearRuleFromAgenda( Environment *theEnv, Defrule *theRule) { 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; } } /***************************************************************/ /* GetNextActivation: Returns an activation from the Agenda. */ /* If its argument is NULL, then the first activation on the */ /* Agenda is returned. If its argument is not NULL, the next */ /* activation after the argument is returned. */ /***************************************************************/ Activation *GetNextActivation( Environment *theEnv, Activation *actPtr) { struct defruleModule *theModuleItem; if (actPtr == NULL) { theModuleItem = (struct defruleModule *) GetModuleItem(theEnv,NULL,DefruleData(theEnv)->DefruleModuleIndex); if (theModuleItem == NULL) return NULL; return theModuleItem->agenda; } else { return actPtr->next; } } /*********************************************/ /* GetActivationBasis: Returns the basis of */ /* the rule associated with an activation. */ /*********************************************/ struct partialMatch *GetActivationBasis( Environment *theEnv, Activation *actPtr) { #if MAC_XCD #pragma unused(theEnv) #endif return actPtr->basis; } /*********************************************/ /* ActivationRuleName: Returns the name of */ /* the rule associated with an activation. */ /*********************************************/ const char *ActivationRuleName( Activation *actPtr) { return actPtr->theRule->header.name->contents; } /***************************************/ /* GetActivationRule: Returns the rule */ /* associated with an activation. */ /***************************************/ Defrule *GetActivationRule( Environment *theEnv, Activation *actPtr) { #if MAC_XCD #pragma unused(theEnv) #endif return actPtr->theRule; } /************************************************/ /* ActivationGetSalience: Returns the salience */ /* of the rule associated with an activation. */ /************************************************/ int ActivationGetSalience( Activation *actPtr) { return actPtr->salience; } /**************************************/ /* ActivationSetSalience: Sets the */ /* salience value of an activation. */ /**************************************/ int ActivationSetSalience( Activation *actPtr, int value) { int temp; if (value > MAX_DEFRULE_SALIENCE) { value = MAX_DEFRULE_SALIENCE; } else if (value < MIN_DEFRULE_SALIENCE) { value = MIN_DEFRULE_SALIENCE; } temp = actPtr->salience; actPtr->salience = value; return temp; } /********************************************/ /* ActivationPPForm: Returns the pretty */ /* print representation of an activation. */ /********************************************/ void ActivationPPForm( Activation *theActivation, StringBuilder *theSB) { Environment *theEnv = theActivation->theRule->header.env; OpenStringBuilderDestination(theEnv,"ActPPForm",theSB); PrintActivation(theEnv,"ActPPForm",theActivation); CloseStringBuilderDestination(theEnv,"ActPPForm"); } /****************************************************/ /* GetActivationBasisPPForm: Returns the pretty */ /* print representation of an activation's basis. */ /****************************************************/ void GetActivationBasisPPForm( Environment *theEnv, char *buffer, size_t bufferLength, Activation *theActivation) { OpenStringDestination(theEnv,"ActPPForm",buffer,bufferLength); PrintPartialMatch(theEnv,"ActPPForm",theActivation->basis); CloseStringDestination(theEnv,"ActPPForm"); } /********************************************/ /* MoveActivationToTop: Moves the specified */ /* activation to the top of the agenda. */ /********************************************/ bool MoveActivationToTop( Environment *theEnv, Activation *theActivation) { struct activation *prevPtr; struct defruleModule *theModuleItem; /*====================================*/ /* Determine the module of the agenda */ /* in which the activation is stored. */ /*====================================*/ theModuleItem = (struct defruleModule *) theActivation->theRule->header.whichModule; /*============================================*/ /* If the activation is already at the top of */ /* the agenda, then nothing needs to be done. */ /*============================================*/ if (theActivation == theModuleItem->agenda) return false; /*=================================================*/ /* Update the pointers of the activation preceding */ /* and following the activation being moved. */ /*=================================================*/ prevPtr = theActivation->prev; prevPtr->next = theActivation->next; if (theActivation->next != NULL) theActivation->next->prev = prevPtr; /*=======================================================*/ /* Move the activation and then update its pointers, the */ /* pointers of the activation following it, and the */ /* module pointer to the top activation on the agenda. */ /*=======================================================*/ theActivation->next = theModuleItem->agenda; theModuleItem->agenda->prev = theActivation; theActivation->prev = NULL; theModuleItem->agenda = theActivation; /*=============================*/ /* Mark the agenda as changed. */ /*=============================*/ AgendaData(theEnv)->AgendaChanged = true; return true; } /*******************************************/ /* DeleteActivation: Removes the specified */ /* activation from the agenda. */ /*******************************************/ void DeleteActivation( Activation *theActivation) { RemoveActivation(theActivation->theRule->header.env,theActivation,true,true); } /*************************************************/ /* DeleteAllActivations: Removes all activations */ /* from the agenda of the specified module. */ /*************************************************/ void DeleteAllActivations( Defmodule *theModule) { struct activation *tempPtr, *theActivation; struct salienceGroup *theGroup, *tempGroup; Environment *theEnv = theModule->header.env; 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; } } /*******************************************************/ /* DetachActivation: Detaches the specified activation */ /* from the list of activations on the Agenda. */ /*******************************************************/ bool DetachActivation( Environment *theEnv, Activation *theActivation) { struct defruleModule *theModuleItem; /*============================*/ /* A NULL pointer is invalid. */ /*============================*/ if (theActivation == NULL) SystemError(theEnv,"AGENDA",1); /*====================================*/ /* Determine the module of the agenda */ /* in which the activation is stored. */ /*====================================*/ theModuleItem = (struct defruleModule *) theActivation->theRule->header.whichModule; RemoveActivationFromGroup(theEnv,theActivation,theModuleItem); /*========================================================*/ /* If the activation is the top activation on the agenda, */ /* then update the module pointer to agenda. */ /*========================================================*/ if (theActivation == theModuleItem->agenda) { theModuleItem->agenda = theActivation->next; } /*==================================================*/ /* Update the pointers in the preceding activation. */ /*==================================================*/ if (theActivation->prev != NULL) { theActivation->prev->next = theActivation->next; } /*==================================================*/ /* Update the pointers in the following activation. */ /*==================================================*/ if (theActivation->next != NULL) { theActivation->next->prev = theActivation->prev; } /*=================================================*/ /* Update the pointers in the detached activation. */ /*=================================================*/ theActivation->prev = NULL; theActivation->next = NULL; /*=============================*/ /* Mark the agenda as changed. */ /*=============================*/ AgendaData(theEnv)->AgendaChanged = true; return true; } /****************************************************************************/ /* PrintActivation: Prints an activation in a "pretty" format. Salience, */ /* rule name, and the partial match which activated the rule are printed. */ /****************************************************************************/ static void PrintActivation( Environment *theEnv, const char *logicalName, Activation *theActivation) { char printSpace[20]; gensprintf(printSpace,"%-6d ",theActivation->salience); WriteString(theEnv,logicalName,printSpace); WriteString(theEnv,logicalName,theActivation->theRule->header.name->contents); WriteString(theEnv,logicalName,": "); PrintPartialMatch(theEnv,logicalName,theActivation->basis); } /*****************************/ /* Agenda: C access routine */ /* for the agenda command. */ /*****************************/ void Agenda( Environment *theEnv, const char *logicalName, Defmodule *theModule) { ListItemsDriver(theEnv,logicalName,theModule,"activation","activations", (GetNextItemFunction *) GetNextActivation, NULL, (PrintItemFunction *) PrintActivation, NULL); } /*******************************************************************/ /* RemoveActivation: Returns an activation and its associated data */ /* structures to the Memory Manager. Links to other activations */ /* and partial matches may also be updated. */ /*******************************************************************/ void RemoveActivation( Environment *theEnv, Activation *theActivation, bool updateAgenda, bool updateLinks) { struct defruleModule *theModuleItem; /*====================================*/ /* Determine the module of the agenda */ /* in which the activation is stored. */ /*====================================*/ theModuleItem = (struct defruleModule *) theActivation->theRule->header.whichModule; /*=================================*/ /* Update the agenda if necessary. */ /*=================================*/ if (updateAgenda == true) { RemoveActivationFromGroup(theEnv,theActivation,theModuleItem); /*===============================================*/ /* Update the pointer links between activations. */ /*===============================================*/ if (theActivation->prev == NULL) { theModuleItem->agenda = theModuleItem->agenda->next; if (theModuleItem->agenda != NULL) theModuleItem->agenda->prev = NULL; } else { theActivation->prev->next = theActivation->next; if (theActivation->next != NULL) { theActivation->next->prev = theActivation->prev; } } /*===================================*/ /* Indicate removal of activation if */ /* activations are being watched. */ /*===================================*/ #if DEBUGGING_FUNCTIONS if (theActivation->theRule->watchActivation && (! ConstructData(theEnv)->ClearReadyInProgress) && (! ConstructData(theEnv)->ClearInProgress)) { WriteString(theEnv,STDOUT,"<== Activation "); PrintActivation(theEnv,STDOUT,theActivation); WriteString(theEnv,STDOUT,"\n"); } #endif /*=============================*/ /* Mark the agenda as changed. */ /*=============================*/ AgendaData(theEnv)->AgendaChanged = true; } /*============================================*/ /* Update join and agenda links if necessary. */ /*============================================*/ if ((updateLinks == true) && (theActivation->basis != NULL)) { theActivation->basis->marker = NULL; } /*================================================*/ /* Return the activation to the free memory pool. */ /*================================================*/ AgendaData(theEnv)->NumberOfActivations--; rtn_struct(theEnv,activation,theActivation); } /******************************/ /* RemoveActivationFromGroup: */ /******************************/ static void RemoveActivationFromGroup( Environment *theEnv, Activation *theActivation, struct defruleModule *theRuleModule) { struct salienceGroup *theGroup; theGroup = FindSalienceGroup(theRuleModule,theActivation->salience); if (theGroup == NULL) return; if (theActivation == theGroup->first) { /*====================================================*/ /* If the activation is the only remaining activation */ /* in the group, then the group needs to be removed. */ /*====================================================*/ if (theActivation == theGroup->last) { if (theGroup->prev == NULL) { theRuleModule->groupings = theGroup->next; } else { theGroup->prev->next = theGroup->next; } if (theGroup->next != NULL) { theGroup->next->prev = theGroup->prev; } rtn_struct(theEnv,salienceGroup,theGroup); } /*======================================================*/ /* Otherwise this is the first activation in the group, */ /* but there are other activations which follow. */ /*======================================================*/ else { theGroup->first = theActivation->next; } } else { /*====================================================*/ /* Otherwise if the activation isn't the first in the */ /* group, then check to see if it's the last. */ /*====================================================*/ if (theActivation == theGroup->last) { theGroup->last = theActivation->prev; } /*==================================================*/ /* Otherwise the activation is in the middle of the */ /* group and no first/last updates are needed. */ /*==================================================*/ else { return; } } } /**************************************************************/ /* AgendaClearFunction: Agenda clear routine for use with the */ /* clear command. Resets the current time tag to zero. */ /**************************************************************/ static void AgendaClearFunction( Environment *theEnv, void *context) { AgendaData(theEnv)->CurrentTimetag = 1; } /*************************************************/ /* RemoveAllActivations: Removes all activations */ /* from the agenda of the current module. */ /*************************************************/ void RemoveAllActivations( Environment *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; } } /**********************************************/ /* GetAgendaChanged: Returns the value of the */ /* boolean flag which indicates whether any */ /* changes have been made to the agenda. */ /**********************************************/ bool GetAgendaChanged( Environment *theEnv) { return(AgendaData(theEnv)->AgendaChanged); } /*****************************************************************/ /* SetAgendaChanged: Sets the value of the boolean flag which */ /* indicates whether any changes have been made to the agenda. */ /*****************************************************************/ void SetAgendaChanged( Environment *theEnv, bool value) { AgendaData(theEnv)->AgendaChanged = value; } /**********************/ /* ReorderAllAgendas: */ /**********************/ void ReorderAllAgendas( Environment *theEnv) { Defmodule *theModule; for (theModule = GetNextDefmodule(theEnv,NULL); theModule != NULL; theModule = GetNextDefmodule(theEnv,theModule)) { ReorderAgenda(theModule); } } /*******************************************************/ /* ReorderAgenda: Completely reorders the agenda based */ /* on the current conflict resolution strategy. */ /*******************************************************/ void ReorderAgenda( Defmodule *theModule) { struct activation *theActivation, *tempPtr; struct defruleModule *theModuleItem; struct salienceGroup *theGroup, *tempGroup; Environment *theEnv; if (theModule == NULL) return; theEnv = theModule->header.env; /*=================================*/ /* Get the list of activations and */ /* remove them from the agenda. */ /*=================================*/ theModuleItem = GetDefruleModuleItem(theEnv,theModule); theActivation = theModuleItem->agenda; theModuleItem->agenda = NULL; theGroup = theModuleItem->groupings; while (theGroup != NULL) { tempGroup = theGroup->next; rtn_struct(theEnv,salienceGroup,theGroup); theGroup = tempGroup; } theModuleItem->groupings = NULL; /*=========================================*/ /* Reorder the activations by placing them */ /* back on the agenda one by one. */ /*=========================================*/ while (theActivation != NULL) { tempPtr = theActivation->next; theActivation->next = NULL; theActivation->prev = NULL; theGroup = ReuseOrCreateSalienceGroup(theEnv,theModuleItem,theActivation->salience); PlaceActivation(theEnv,&(theModuleItem->agenda),theActivation,theGroup); theActivation = tempPtr; } } /****************************************************/ /* GetNumberOfActivations: Returns the value of the */ /* total number of activations on all agendas. */ /****************************************************/ unsigned long GetNumberOfActivations( Environment *theEnv) { return(AgendaData(theEnv)->NumberOfActivations); } /******************************************************/ /* RefreshCommand: H/L Command for refreshing a rule. */ /* Syntax: (refresh ) */ /******************************************************/ void RefreshCommand( Environment *theEnv, UDFContext *context, UDFValue *returnValue) { const char *ruleName; Defrule *rulePtr; /*===========================*/ /* Get the name of the rule. */ /*===========================*/ ruleName = GetConstructName(context,"refresh","rule name"); if (ruleName == NULL) return; /*===============================*/ /* Determine if the rule exists. */ /*===============================*/ rulePtr = FindDefrule(theEnv,ruleName); if (rulePtr == NULL) { CantFindItemErrorMessage(theEnv,"defrule",ruleName,true); return; } /*===================*/ /* Refresh the rule. */ /*===================*/ Refresh(rulePtr); } /***********************************************************/ /* Refresh: Refreshes a defrule. Activations of the rule */ /* that have already been fired are added to the agenda. */ /***********************************************************/ void Refresh( Defrule *theRule) { Defrule *rulePtr; struct partialMatch *listOfMatches; unsigned long b; Environment *theEnv = theRule->header.env; /*====================================*/ /* Refresh each disjunct of the rule. */ /*====================================*/ for (rulePtr = 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); } } } } } } /**********************************************/ /* RefreshAgendaCommand: H/L access routine */ /* for the refresh-agenda command. */ /**********************************************/ void RefreshAgendaCommand( Environment *theEnv, UDFContext *context, UDFValue *returnValue) { unsigned int numArgs; bool error; Defmodule *theModule; /*==============================================*/ /* This function can have at most one argument. */ /*==============================================*/ numArgs = UDFArgumentCount(context); /*===============================================================*/ /* If a module name is specified, then the agenda of that module */ /* is refreshed. Otherwise, the agenda of the current module is */ /* refreshed. */ /*===============================================================*/ if (numArgs == 1) { theModule = GetModuleName(context,1,&error); if (error) return; } else { theModule = GetCurrentModule(theEnv); } /*===============================================*/ /* Refresh the agenda of the appropriate module. */ /*===============================================*/ if (theModule == NULL) { RefreshAllAgendas(theEnv); } else { RefreshAgenda(theModule); } } /**********************/ /* RefreshAllAgendas: */ /**********************/ void RefreshAllAgendas( Environment *theEnv) { Defmodule *theModule; for (theModule = GetNextDefmodule(theEnv,NULL); theModule != NULL; theModule = GetNextDefmodule(theEnv,theModule)) { RefreshAgenda(theModule); } } /*************************************/ /* RefreshAgenda: C access routine */ /* for the refresh-agenda command. */ /*************************************/ void RefreshAgenda( Defmodule *theModule) { Activation *theActivation; SalienceEvaluationType oldValue; Environment *theEnv; if (theModule == NULL) return; theEnv = theModule->header.env; /*=====================================*/ /* If embedded, clear the error flags. */ /*=====================================*/ if (EvaluationData(theEnv)->CurrentExpression == NULL) { ResetErrorFlags(theEnv); } /*==========================*/ /* Save the current module. */ /*==========================*/ SaveCurrentModule(theEnv); /*=======================================================*/ /* Remember the current setting for salience evaluation. */ /* To perform the refresh, the when activated setting is */ /* used to recompute the salience values. */ /*=======================================================*/ oldValue = GetSalienceEvaluation(theEnv); SetSalienceEvaluation(theEnv,WHEN_ACTIVATED); /*============================*/ /* Change the current module. */ /*============================*/ SetCurrentModule(theEnv,theModule); /*================================================================*/ /* Recompute the salience values for the current module's agenda. */ /*================================================================*/ for (theActivation = GetNextActivation(theEnv,NULL); theActivation != NULL; theActivation = GetNextActivation(theEnv,theActivation)) { theActivation->salience = EvaluateSalience(theEnv,theActivation->theRule); } /*======================================================*/ /* Reorder the agenda based on the new salience values. */ /*======================================================*/ ReorderAgenda(theModule); /*==========================================*/ /* Restore the salience evaluation setting. */ /*==========================================*/ SetSalienceEvaluation(theEnv,oldValue); /*=============================*/ /* Restore the current module. */ /*=============================*/ RestoreCurrentModule(theEnv); } /*********************************************************/ /* SetSalienceEvaluationCommand: H/L Command for setting */ /* the salience evaluation behavior. */ /* Syntax: (set-salience-evaluation-behavior ) */ /*********************************************************/ void SetSalienceEvaluationCommand( Environment *theEnv, UDFContext *context, UDFValue *returnValue) { UDFValue value; const char *argument; const char *oldValue; /*==================================================*/ /* Get the current setting for salience evaluation. */ /*==================================================*/ oldValue = SalienceEvaluationName(GetSalienceEvaluation(theEnv)); /*=========================================*/ /* This function expects a single argument */ /* which must be a symbol. */ /*=========================================*/ if (! UDFFirstArgument(context,SYMBOL_BIT,&value)) { return; } /*=============================================================*/ /* The allowed symbols to pass as an argument to this function */ /* are when-defined, when-activated, and every-cycle. */ /*=============================================================*/ argument = value.lexemeValue->contents; if (strcmp(argument,"when-defined") == 0) { SetSalienceEvaluation(theEnv,WHEN_DEFINED); } else if (strcmp(argument,"when-activated") == 0) { SetSalienceEvaluation(theEnv,WHEN_ACTIVATED); } else if (strcmp(argument,"every-cycle") == 0) { SetSalienceEvaluation(theEnv,EVERY_CYCLE); } else { UDFInvalidArgumentMessage(context, "symbol with value when-defined, when-activated, or every-cycle"); returnValue->lexemeValue = CreateSymbol(theEnv,oldValue); return; } /*=================================================*/ /* Return the old setting for salience evaluation. */ /*=================================================*/ returnValue->lexemeValue = CreateSymbol(theEnv,oldValue); } /*********************************************************/ /* GetSalienceEvaluationCommand: H/L Command for getting */ /* the salience evaluation behavior. */ /* Syntax: (get-salience-evaluation-behavior) */ /*********************************************************/ void GetSalienceEvaluationCommand( Environment *theEnv, UDFContext *context, UDFValue *returnValue) { returnValue->lexemeValue = CreateSymbol(theEnv,SalienceEvaluationName(GetSalienceEvaluation(theEnv))); } /*****************************************************************/ /* SalienceEvaluationName: Given the integer value corresponding */ /* to a specified salience evaluation behavior, returns a */ /* character string of the behavior's name. */ /*****************************************************************/ static const char *SalienceEvaluationName( SalienceEvaluationType strategy) { const char *sname; switch (strategy) { case WHEN_DEFINED: sname = "when-defined"; break; case WHEN_ACTIVATED: sname = "when-activated"; break; case EVERY_CYCLE: sname = "every-cycle"; break; default: sname = "unknown"; break; } return sname; } /*******************************************************/ /* GetSalienceEvaluation: Returns the value of current */ /* type of salience evaluation (e.g., when defined, */ /* when activated, or every cycle). */ /*******************************************************/ SalienceEvaluationType GetSalienceEvaluation( Environment *theEnv) { return AgendaData(theEnv)->SalienceEvaluation; } /**********************************************/ /* SetSalienceEvaluation: Sets the value of */ /* the current type of salience evaluation. */ /**********************************************/ SalienceEvaluationType SetSalienceEvaluation( Environment *theEnv, SalienceEvaluationType value) { SalienceEvaluationType ov; ov = AgendaData(theEnv)->SalienceEvaluation; AgendaData(theEnv)->SalienceEvaluation = value; return ov; } /*****************************************************************/ /* EvaluateSalience: Returns the salience value of the specified */ /* defrule. If salience evaluation is currently set to */ /* when-defined, then the current value of the rule's salience */ /* is returned. Otherwise the salience expression associated */ /* with the rule is reevaluated, the value is stored as the */ /* rule's current salience, and it is then returned. */ /*****************************************************************/ static int EvaluateSalience( Environment *theEnv, Defrule *theDefrule) { UDFValue salienceValue; long long salience; /*==================================================*/ /* If saliences are only being evaluated when rules */ /* are defined, then just return the last salience */ /* value evaluated for the rule. */ /*==================================================*/ if (GetSalienceEvaluation(theEnv) == WHEN_DEFINED) { return theDefrule->salience; } /*=================================================================*/ /* If the rule's salience value was defined as an integer constant */ /* (i.e., not an expression or global variable which could change */ /* on reevaluation), then just return the salience value computed */ /* for the rule when it was defined. */ /*=================================================================*/ if (theDefrule->dynamicSalience == NULL) return theDefrule->salience; /*====================================================*/ /* Reevaluate the rule's salience. If an error occurs */ /* during evaluation, print an error message. */ /*====================================================*/ SetEvaluationError(theEnv,false); if (EvaluateExpression(theEnv,theDefrule->dynamicSalience,&salienceValue)) { SalienceInformationError(theEnv,"defrule",theDefrule->header.name->contents); return theDefrule->salience; } /*========================================*/ /* The salience value must be an integer. */ /*========================================*/ if (salienceValue.header->type != INTEGER_TYPE) { SalienceNonIntegerError(theEnv); SalienceInformationError(theEnv,"defrule",theDefrule->header.name->contents); SetEvaluationError(theEnv,true); return theDefrule->salience; } /*==========================================*/ /* The salience value must fall between the */ /* minimum and maximum allowed values. */ /*==========================================*/ salience = salienceValue.integerValue->contents; if ((salience > MAX_DEFRULE_SALIENCE) || (salience < MIN_DEFRULE_SALIENCE)) { SalienceRangeError(theEnv,MIN_DEFRULE_SALIENCE,MAX_DEFRULE_SALIENCE); SetEvaluationError(theEnv,true); SalienceInformationError(theEnv,"defrule",theDefrule->header.name->contents); return theDefrule->salience; } /*===================================*/ /* Store the new salience value with */ /* the rule and return this value. */ /*===================================*/ theDefrule->salience = (int) salience; return theDefrule->salience; } #if DEBUGGING_FUNCTIONS /***********************************************/ /* AgendaCommand: Prints out the agenda of the */ /* rules that are ready to fire. */ /* Syntax: (agenda) */ /***********************************************/ void AgendaCommand( Environment *theEnv, UDFContext *context, UDFValue *returnValue) { unsigned int numArgs; bool error; Defmodule *theModule; /*===============================================================*/ /* If a module name is specified, then the agenda of that module */ /* is displayed. Otherwise, the agenda of the current module is */ /* displayed. */ /*===============================================================*/ numArgs = UDFArgumentCount(context); if (numArgs == 1) { theModule = GetModuleName(context,1,&error); if (error) return; } else { theModule = GetCurrentModule(theEnv); } /*===============================================*/ /* Display the agenda of the appropriate module. */ /*===============================================*/ Agenda(theEnv,STDOUT,theModule); } #endif /* DEBUGGING_FUNCTIONS */ #endif /* DEFRULE_CONSTRUCT */