tizen 2.4 release
[external/clips.git] / src / agenda.c
1    /*******************************************************/
2    /*      "C" Language Integrated Production System      */
3    /*                                                     */
4    /*             CLIPS Version 6.30  08/22/14            */
5    /*                                                     */
6    /*                    AGENDA MODULE                    */
7    /*******************************************************/
8
9 /*************************************************************/
10 /* Purpose:                                                  */
11 /*   Provides functionality for examining, manipulating,     */
12 /*   adding, and removing activations from the agenda.       */
13 /*                                                           */
14 /* Principal Programmer(s):                                  */
15 /*      Gary D. Riley                                        */
16 /*                                                           */
17 /* Contributing Programmer(s):                               */
18 /*      Brian L. Dantes                                      */
19 /*                                                           */
20 /* Revision History:                                         */
21 /*      6.23: Corrected compilation errors for files         */
22 /*            generated by constructs-to-c. DR0861           */
23 /*                                                           */
24 /*      6.24: Removed CONFLICT_RESOLUTION_STRATEGIES         */
25 /*            and DYNAMIC_SALIENCE compilation flags.        */
26 /*                                                           */
27 /*            Renamed BOOLEAN macro type to intBool.         */
28 /*                                                           */
29 /*            Added EnvGetActivationBasisPPForm function.    */
30 /*                                                           */
31 /*      6.30: Added salience groups to improve performance   */
32 /*            with large numbers of activations of different */
33 /*            saliences.                                     */
34 /*                                                           */
35 /*            Borland C (IBM_TBC) and Metrowerks CodeWarrior */
36 /*            (MAC_MCW, IBM_MCW) are no longer supported.    */
37 /*                                                           */
38 /*            Support for long long integers.                */
39 /*                                                           */
40 /*            Added const qualifiers to remove C++           */
41 /*            deprecation warnings.                          */
42 /*                                                           */
43 /*            Converted API macros to function calls.        */
44 /*                                                           */
45 /*************************************************************/
46
47 #define _AGENDA_SOURCE_
48
49 #include <stdio.h>
50 #define _STDIO_INCLUDED_
51 #include <string.h>
52
53 #include "setup.h"
54
55 #if DEFRULE_CONSTRUCT
56
57 #include "argacces.h"
58 #include "constant.h"
59 #include "crstrtgy.h"
60 #include "engine.h"
61 #include "envrnmnt.h"
62 #include "extnfunc.h"
63 #include "memalloc.h"
64 #include "moduldef.h"
65 #include "modulutl.h"
66 #include "multifld.h"
67 #include "reteutil.h"
68 #include "retract.h"
69 #include "router.h"
70 #include "rulebsc.h"
71 #include "ruledef.h"
72 #include "strngrtr.h"
73 #include "sysdep.h"
74 #include "watch.h"
75
76 #include "agenda.h"
77
78 /***************************************/
79 /* LOCAL INTERNAL FUNCTION DEFINITIONS */
80 /***************************************/
81
82    static void                    PrintActivation(void *,const char *,void *);
83    static void                    AgendaClearFunction(void *);
84    static const char             *SalienceEvaluationName(int);
85    static int                     EvaluateSalience(void *,void *);
86    static struct salienceGroup   *ReuseOrCreateSalienceGroup(void *,struct defruleModule *,int);
87    static struct salienceGroup   *FindSalienceGroup(struct defruleModule *,int);
88    static void                    RemoveActivationFromGroup(void *,struct activation *,struct defruleModule *);
89
90 /*************************************************/
91 /* InitializeAgenda: Initializes the activations */
92 /*   watch item and the H/L commands for         */
93 /*   manipulating the agenda.                    */
94 /*************************************************/
95 globle void InitializeAgenda(
96   void *theEnv)
97   {
98    AllocateEnvironmentData(theEnv,AGENDA_DATA,sizeof(struct agendaData),NULL);
99
100    AgendaData(theEnv)->SalienceEvaluation = WHEN_DEFINED;
101
102    AgendaData(theEnv)->Strategy = DEFAULT_STRATEGY;
103
104    EnvAddClearFunction(theEnv,"agenda",AgendaClearFunction,0);
105 #if DEBUGGING_FUNCTIONS
106    AddWatchItem(theEnv,"activations",1,&AgendaData(theEnv)->WatchActivations,40,DefruleWatchAccess,DefruleWatchPrint);
107 #endif
108 #if ! RUN_TIME
109    EnvDefineFunction2(theEnv,"refresh", 'v', PTIEF RefreshCommand, "RefreshCommand", "11w");
110
111    EnvDefineFunction2(theEnv,"refresh-agenda",'v',
112                    PTIEF RefreshAgendaCommand,"RefreshAgendaCommand", "01w");
113    EnvDefineFunction2(theEnv,"get-salience-evaluation",'w',
114                    PTIEF GetSalienceEvaluationCommand,
115                    "GetSalienceEvaluationCommand", "00");
116    EnvDefineFunction2(theEnv,"set-salience-evaluation",'w',
117                    PTIEF SetSalienceEvaluationCommand,
118                    "SetSalienceEvaluationCommand",
119                    "11w");
120
121 #if DEBUGGING_FUNCTIONS
122    EnvDefineFunction2(theEnv,"agenda", 'v', PTIEF AgendaCommand, "AgendaCommand", "01w");
123 #endif
124 #endif
125   }
126
127 /*****************************************************************/
128 /* AddActivation: Creates a rule activation to be added to the   */
129 /*   Agenda and links the activation with its associated partial */
130 /*   match. The function PlaceActivation is then called to place */
131 /*   the activation on the Agenda. Typically called when all     */
132 /*   patterns on the LHS of a rule have been satisfied.          */
133 /*****************************************************************/
134 globle void AddActivation(
135   void *theEnv,
136   void *vTheRule,
137   void *vBinds)
138   {
139    struct activation *newActivation;
140    struct defrule *theRule = (struct defrule *) vTheRule;
141    struct partialMatch *binds = (struct partialMatch *) vBinds;
142    struct defruleModule *theModuleItem;
143    struct salienceGroup *theGroup;
144
145    /*=======================================*/
146    /* Focus on the module if the activation */
147    /* is from an auto-focus rule.           */
148    /*=======================================*/
149
150    if (theRule->autoFocus)
151      { EnvFocus(theEnv,(void *) theRule->header.whichModule->theModule); }
152
153    /*=======================================================*/
154    /* Create the activation. The activation stores pointers */
155    /* to its associated partial match and defrule. The      */
156    /* activation is given a time tag, its salience is       */
157    /* evaluated, and it is assigned a random number for use */
158    /* with the random conflict resolution strategy.         */
159    /*=======================================================*/
160
161    newActivation = get_struct(theEnv,activation);
162    newActivation->theRule = theRule;
163    newActivation->basis = binds;
164    newActivation->timetag = AgendaData(theEnv)->CurrentTimetag++;
165    newActivation->salience = EvaluateSalience(theEnv,theRule);
166
167    newActivation->randomID = genrand();
168    newActivation->prev = NULL;
169    newActivation->next = NULL;
170
171    AgendaData(theEnv)->NumberOfActivations++;
172
173    /*=======================================================*/
174    /* Point the partial match to the activation to complete */
175    /* the link between the join network and the agenda.     */
176    /*=======================================================*/
177
178    binds->marker = (void *) newActivation;
179
180    /*====================================================*/
181    /* If activations are being watch, display a message. */
182    /*====================================================*/
183
184 #if DEBUGGING_FUNCTIONS
185    if (newActivation->theRule->watchActivation)
186      {
187       EnvPrintRouter(theEnv,WTRACE,"==> Activation ");
188       PrintActivation(theEnv,WTRACE,(void *) newActivation);
189       EnvPrintRouter(theEnv,WTRACE,"\n");
190      }
191 #endif
192
193     /*=====================================*/
194     /* Place the activation on the agenda. */
195     /*=====================================*/
196
197     theModuleItem = (struct defruleModule *) theRule->header.whichModule;
198
199     theGroup = ReuseOrCreateSalienceGroup(theEnv,theModuleItem,newActivation->salience);
200
201     PlaceActivation(theEnv,&(theModuleItem->agenda),newActivation,theGroup);
202    }
203
204 /***************************************************************/
205 /* ReuseOrCreateSalienceGroup: */
206 /***************************************************************/
207 static struct salienceGroup *ReuseOrCreateSalienceGroup(
208   void *theEnv,
209   struct defruleModule *theRuleModule,
210   int salience)
211   {
212    struct salienceGroup *theGroup, *lastGroup, *newGroup;
213
214    for (lastGroup = NULL, theGroup = theRuleModule->groupings;
215         theGroup != NULL;
216         lastGroup = theGroup, theGroup = theGroup->next)
217      {
218       if (theGroup->salience == salience)
219         { return(theGroup); }
220
221       if (theGroup->salience < salience)
222         { break; }
223      }
224
225    newGroup = get_struct(theEnv,salienceGroup);
226    newGroup->salience = salience;
227    newGroup->first = NULL;
228    newGroup->last = NULL;
229    newGroup->next = theGroup;
230    newGroup->prev = lastGroup;
231
232    if (newGroup->next != NULL)
233      { newGroup->next->prev = newGroup; }
234
235    if (newGroup->prev != NULL)
236      { newGroup->prev->next = newGroup; }
237
238    if (lastGroup == NULL)
239      { theRuleModule->groupings = newGroup; }
240
241    return newGroup;
242   }
243
244 /***************************************************************/
245 /* FindSalienceGroup: */
246 /***************************************************************/
247 static struct salienceGroup *FindSalienceGroup(
248   struct defruleModule *theRuleModule,
249   int salience)
250   {
251    struct salienceGroup *theGroup;
252
253    for (theGroup = theRuleModule->groupings;
254         theGroup != NULL;
255         theGroup = theGroup->next)
256      {
257       if (theGroup->salience == salience)
258         { return(theGroup); }
259
260       if (theGroup->salience < salience)
261         { break; }
262      }
263
264    return NULL;
265   }
266
267 /***************************************************************/
268 /* ClearRuleFromAgenda: Clears the agenda of a specified rule. */
269 /***************************************************************/
270 globle void ClearRuleFromAgenda(
271   void *theEnv,
272   void *vTheRule)
273   {
274    struct defrule *theRule = (struct defrule *) vTheRule;
275    struct defrule *tempRule;
276    struct activation *agendaPtr, *agendaNext;
277
278    /*============================================*/
279    /* Get a pointer to the agenda for the module */
280    /* in which the rule is contained.            */
281    /*============================================*/
282
283    agendaPtr = ((struct defruleModule *) theRule->header.whichModule)->agenda;
284
285    /*==============================================*/
286    /* Loop through every activation on the agenda. */
287    /*==============================================*/
288
289    while (agendaPtr != NULL)
290      {
291       agendaNext = agendaPtr->next;
292
293       /*========================================================*/
294       /* Check each disjunct of the rule against the activation */
295       /* to determine if the activation points to the rule. If  */
296       /* it does, then remove the activation from the agenda.   */
297       /*========================================================*/
298
299       for (tempRule = theRule;
300            tempRule != NULL;
301            tempRule = tempRule->disjunct)
302         {
303          if (agendaPtr->theRule == tempRule)
304            {
305             RemoveActivation(theEnv,agendaPtr,TRUE,TRUE);
306             break;
307            }
308         }
309
310       agendaPtr = agendaNext;
311      }
312   }
313
314 /****************************************************************/
315 /* EnvGetNextActivation: Returns an activation from the Agenda. */
316 /*   If its argument is NULL, then the first activation on the  */
317 /*   Agenda is returned. If its argument is not NULL, the next  */
318 /*   activation after the argument is returned.                 */
319 /****************************************************************/
320 globle void *EnvGetNextActivation(
321   void *theEnv,
322   void *actPtr)
323   {
324    struct defruleModule *theModuleItem;
325
326    if (actPtr == NULL)
327      {
328       theModuleItem = (struct defruleModule *) GetModuleItem(theEnv,NULL,DefruleData(theEnv)->DefruleModuleIndex);
329       if (theModuleItem == NULL) return(NULL);
330       return((void *) theModuleItem->agenda);
331      }
332    else
333      { return((void *) (((struct activation *) actPtr)->next)); }
334   }
335
336 /***********************************************/
337 /* EnvGetActivationBasis: Returns the basis of */
338 /*   the rule associated with an activation.   */
339 /***********************************************/
340 globle struct partialMatch *EnvGetActivationBasis(
341   void *theEnv,
342   void *actPtr)
343   {
344 #if MAC_XCD
345 #pragma unused(theEnv)
346 #endif
347    return ((struct activation *) actPtr)->basis;
348   }
349
350 /*********************************************/
351 /* EnvGetActivationName: Returns the name of */
352 /*   the rule associated with an activation. */
353 /*********************************************/
354 globle const char *EnvGetActivationName(
355   void *theEnv,
356   void *actPtr)
357   {
358 #if MAC_XCD
359 #pragma unused(theEnv)
360 #endif
361
362    return(ValueToString(((struct activation *) actPtr)->theRule->header.name));
363   }
364
365 /******************************************/
366 /* EnvGetActivationRule: Returns the rule */
367 /*   associated with an activation.       */
368 /******************************************/
369 globle struct defrule *EnvGetActivationRule(
370   void *theEnv,
371   void *actPtr)
372   {
373 #if MAC_XCD
374 #pragma unused(theEnv)
375 #endif
376    return ((struct activation *) actPtr)->theRule;
377   }
378
379 /**************************************************/
380 /* EnvGetActivationSalience: Returns the salience */
381 /*   of the rule associated with an activation.   */
382 /**************************************************/
383 globle int EnvGetActivationSalience(
384   void *theEnv,
385   void *actPtr)
386   {
387 #if MAC_XCD
388 #pragma unused(theEnv)
389 #endif
390    return ((struct activation *) actPtr)->salience;
391   }
392
393 /**************************************/
394 /* EnvSetActivationSalience: Sets the */
395 /*   salience value of an activation. */
396 /**************************************/
397 globle int EnvSetActivationSalience(
398   void *theEnv,
399   void *actPtr,
400   int value)
401   {
402    int temp;
403 #if MAC_XCD
404 #pragma unused(theEnv)
405 #endif
406
407    temp = ((struct activation *) actPtr)->salience;
408    ((struct activation *) actPtr)->salience = value;
409    return(temp);
410   }
411
412 /**********************************************/
413 /* EnvGetActivationPPForm: Returns the pretty */
414 /*   print representation of an activation.   */
415 /**********************************************/
416 globle void EnvGetActivationPPForm(
417   void *theEnv,
418   char *buffer,
419   size_t bufferLength,
420   void *theActivation)
421   {
422    OpenStringDestination(theEnv,"ActPPForm",buffer,bufferLength);
423    PrintActivation(theEnv,"ActPPForm",(void *) theActivation);
424    CloseStringDestination(theEnv,"ActPPForm");
425   }
426
427 /****************************************************/
428 /* EnvGetActivationBasisPPForm: Returns the pretty  */
429 /*   print representation of an activation's basis. */
430 /****************************************************/
431 globle void EnvGetActivationBasisPPForm(
432   void *theEnv,
433   char *buffer,
434   size_t bufferLength,
435   void *vTheActivation)
436   {
437    struct activation *theActivation = (struct activation *) vTheActivation;
438
439    OpenStringDestination(theEnv,"ActPPForm",buffer,bufferLength);
440    PrintPartialMatch(theEnv,"ActPPForm",theActivation->basis);
441    CloseStringDestination(theEnv,"ActPPForm");
442   }
443
444 /********************************************/
445 /* MoveActivationToTop: Moves the specified */
446 /*   activation to the top of the agenda.   */
447 /********************************************/
448 globle intBool MoveActivationToTop(
449   void *theEnv,
450   void *vtheActivation)
451   {
452    struct activation *prevPtr;
453    struct activation *theActivation = (struct activation *) vtheActivation;
454    struct defruleModule *theModuleItem;
455
456    /*====================================*/
457    /* Determine the module of the agenda */
458    /* in which the activation is stored. */
459    /*====================================*/
460
461    theModuleItem = (struct defruleModule *) theActivation->theRule->header.whichModule;
462
463    /*============================================*/
464    /* If the activation is already at the top of */
465    /* the agenda, then nothing needs to be done. */
466    /*============================================*/
467
468    if (theActivation == theModuleItem->agenda) return(FALSE);
469
470    /*=================================================*/
471    /* Update the pointers of the activation preceding */
472    /* and following the activation being moved.       */
473    /*=================================================*/
474
475    prevPtr = theActivation->prev;
476    prevPtr->next = theActivation->next;
477    if (theActivation->next != NULL) theActivation->next->prev = prevPtr;
478
479    /*=======================================================*/
480    /* Move the activation and then update its pointers, the */
481    /* pointers of the activation following it, and the      */
482    /* module pointer to the top activation on the agenda.   */
483    /*=======================================================*/
484
485    theActivation->next = theModuleItem->agenda;
486    theModuleItem->agenda->prev = theActivation;
487    theActivation->prev = NULL;
488    theModuleItem->agenda = theActivation;
489
490    /*=============================*/
491    /* Mark the agenda as changed. */
492    /*=============================*/
493
494    AgendaData(theEnv)->AgendaChanged = TRUE;
495
496    return(TRUE);
497   }
498
499 /**********************************************/
500 /* EnvDeleteActivation: Removes the specified */
501 /*   activation from the agenda.              */
502 /**********************************************/
503 globle intBool EnvDeleteActivation(
504   void *theEnv,
505   void *theActivation)
506   {
507    if (theActivation == NULL) RemoveAllActivations(theEnv);
508    else RemoveActivation(theEnv,(struct activation *) theActivation,TRUE,TRUE);
509
510    return(TRUE);
511   }
512
513 /*******************************************************/
514 /* DetachActivation: Detaches the specified activation */
515 /*   from the list of activations on the Agenda.       */
516 /*******************************************************/
517 globle intBool DetachActivation(
518   void *theEnv,
519   void *vTheActivation)
520   {
521    struct defruleModule *theModuleItem;
522    struct activation *theActivation = (struct activation *) vTheActivation;
523
524    /*============================*/
525    /* A NULL pointer is invalid. */
526    /*============================*/
527
528    if (theActivation == NULL) SystemError(theEnv,"AGENDA",1);
529
530    /*====================================*/
531    /* Determine the module of the agenda */
532    /* in which the activation is stored. */
533    /*====================================*/
534
535    theModuleItem = (struct defruleModule *) theActivation->theRule->header.whichModule;
536
537    RemoveActivationFromGroup(theEnv,theActivation,theModuleItem);
538
539    /*========================================================*/
540    /* If the activation is the top activation on the agenda, */
541    /* then update the module pointer to agenda.              */
542    /*========================================================*/
543
544    if (theActivation == theModuleItem->agenda)
545      { theModuleItem->agenda = theActivation->next; }
546
547    /*==================================================*/
548    /* Update the pointers in the preceding activation. */
549    /*==================================================*/
550
551    if (theActivation->prev != NULL)
552      { theActivation->prev->next = theActivation->next; }
553
554    /*==================================================*/
555    /* Update the pointers in the following activation. */
556    /*==================================================*/
557
558    if (theActivation->next != NULL)
559      { theActivation->next->prev = theActivation->prev; }
560
561    /*=================================================*/
562    /* Update the pointers in the detached activation. */
563    /*=================================================*/
564
565    theActivation->prev = NULL;
566    theActivation->next = NULL;
567
568    /*=============================*/
569    /* Mark the agenda as changed. */
570    /*=============================*/
571
572    AgendaData(theEnv)->AgendaChanged = TRUE;
573
574    return(TRUE);
575   }
576
577 /****************************************************************************/
578 /* PrintActivation: Prints an activation in a "pretty" format. Salience,    */
579 /*   rule name, and the partial match which activated the rule are printed. */
580 /****************************************************************************/
581 static void PrintActivation(
582   void *theEnv,
583   const char *logicalName,
584   void *vTheActivation)
585   {
586    struct activation *theActivation = (struct activation *) vTheActivation;
587    char printSpace[20];
588
589    gensprintf(printSpace,"%-6d ",theActivation->salience);
590    EnvPrintRouter(theEnv,logicalName,printSpace);
591    EnvPrintRouter(theEnv,logicalName,ValueToString(theActivation->theRule->header.name));
592    EnvPrintRouter(theEnv,logicalName,": ");
593    PrintPartialMatch(theEnv,logicalName,theActivation->basis);
594   }
595
596 /*******************************/
597 /* EnvAgenda: C access routine */
598 /*   for the agenda command.   */
599 /*******************************/
600 globle void EnvAgenda(
601   void *theEnv,
602   const char *logicalName,
603   void *vTheModule)
604   {
605    struct defmodule *theModule = (struct defmodule *) vTheModule;
606
607    ListItemsDriver(theEnv,logicalName,theModule,"activation","activations",
608                    EnvGetNextActivation,NULL,PrintActivation,NULL);
609   }
610
611 /*******************************************************************/
612 /* RemoveActivation: Returns an activation and its associated data */
613 /*   structures to the Memory Manager. Links to other activations  */
614 /*   and partial matches may also be updated.                      */
615 /*******************************************************************/
616 globle void RemoveActivation(
617   void *theEnv,
618   void *vTheActivation,
619   int updateAgenda,
620   int updateLinks)
621   {
622    struct defruleModule *theModuleItem;
623    struct activation *theActivation = (struct activation *) vTheActivation;
624
625    /*====================================*/
626    /* Determine the module of the agenda */
627    /* in which the activation is stored. */
628    /*====================================*/
629
630    theModuleItem = (struct defruleModule *) theActivation->theRule->header.whichModule;
631
632    /*=================================*/
633    /* Update the agenda if necessary. */
634    /*=================================*/
635
636    if (updateAgenda == TRUE)
637      {
638       RemoveActivationFromGroup(theEnv,theActivation,theModuleItem);
639
640       /*===============================================*/
641       /* Update the pointer links between activations. */
642       /*===============================================*/
643
644       if (theActivation->prev == NULL)
645         {
646          theModuleItem->agenda = theModuleItem->agenda->next;
647          if (theModuleItem->agenda != NULL) theModuleItem->agenda->prev = NULL;
648         }
649       else
650         {
651          theActivation->prev->next = theActivation->next;
652          if (theActivation->next != NULL)
653            { theActivation->next->prev = theActivation->prev; }
654         }
655
656       /*===================================*/
657       /* Indicate removal of activation if */
658       /* activations are being watched.    */
659       /*===================================*/
660
661 #if DEBUGGING_FUNCTIONS
662       if (theActivation->theRule->watchActivation)
663         {
664          EnvPrintRouter(theEnv,WTRACE,"<== Activation ");
665          PrintActivation(theEnv,WTRACE,(void *) theActivation);
666          EnvPrintRouter(theEnv,WTRACE,"\n");
667         }
668 #endif
669
670       /*=============================*/
671       /* Mark the agenda as changed. */
672       /*=============================*/
673
674       AgendaData(theEnv)->AgendaChanged = TRUE;
675      }
676
677    /*============================================*/
678    /* Update join and agenda links if necessary. */
679    /*============================================*/
680
681    if ((updateLinks == TRUE) && (theActivation->basis != NULL))
682      { theActivation->basis->marker = NULL; }
683
684    /*================================================*/
685    /* Return the activation to the free memory pool. */
686    /*================================================*/
687
688    AgendaData(theEnv)->NumberOfActivations--;
689
690    rtn_struct(theEnv,activation,theActivation);
691   }
692
693 /**************************************************************/
694 /* RemoveActivationFromGroup:      */
695 /**************************************************************/
696 static void RemoveActivationFromGroup(
697   void *theEnv,
698   struct activation *theActivation,
699   struct defruleModule *theRuleModule)
700   {
701    struct salienceGroup *theGroup;
702
703    theGroup = FindSalienceGroup(theRuleModule,theActivation->salience);
704    if (theGroup == NULL) return;
705
706    if (theActivation == theGroup->first)
707      {
708       /*====================================================*/
709       /* If the activation is the only remaining activation */
710       /* in the group, then the group needs to be removed.  */
711       /*====================================================*/
712
713       if (theActivation == theGroup->last)
714         {
715          if (theGroup->prev == NULL)
716            { theRuleModule->groupings = theGroup->next; }
717          else
718            { theGroup->prev->next = theGroup->next; }
719
720          if (theGroup->next != NULL)
721            { theGroup->next->prev = theGroup->prev; }
722
723          rtn_struct(theEnv,salienceGroup,theGroup);
724         }
725
726       /*======================================================*/
727       /* Otherwise this is the first activation in the group, */
728       /* but there are other activations which follow.        */
729       /*======================================================*/
730
731       else
732         { theGroup->first = theActivation->next; }
733      }
734    else
735      {
736       /*====================================================*/
737       /* Otherwise if the activation isn't the first in the */
738       /* group, then check to see if it's the last.         */
739       /*====================================================*/
740
741       if (theActivation == theGroup->last)
742         { theGroup->last = theActivation->prev; }
743
744       /*==================================================*/
745       /* Otherwise the activation is in the middle of the */
746       /* group and no first/last updates are needed.      */
747       /*==================================================*/
748
749       else
750         { return; }
751      }
752   }
753
754 /**************************************************************/
755 /* AgendaClearFunction: Agenda clear routine for use with the */
756 /*   clear command. Resets the current time tag to zero.      */
757 /**************************************************************/
758 static void AgendaClearFunction(
759   void *theEnv)
760   {
761    AgendaData(theEnv)->CurrentTimetag = 0;
762   }
763
764 /*************************************************/
765 /* RemoveAllActivations: Removes all activations */
766 /*   from the agenda of the current module.      */
767 /*************************************************/
768 globle void RemoveAllActivations(
769   void *theEnv)
770   {
771    struct activation *tempPtr, *theActivation;
772    struct salienceGroup *theGroup, *tempGroup;
773
774    theActivation = GetDefruleModuleItem(theEnv,NULL)->agenda;
775    while (theActivation != NULL)
776      {
777       tempPtr = theActivation->next;
778       RemoveActivation(theEnv,theActivation,TRUE,TRUE);
779       theActivation = tempPtr;
780      }
781
782    theGroup = GetDefruleModuleItem(theEnv,NULL)->groupings;
783    while (theGroup != NULL)
784      {
785       tempGroup = theGroup->next;
786       rtn_struct(theEnv,salienceGroup,theGroup);
787       theGroup = tempGroup;
788      }
789  }
790
791 /*********************************************************/
792 /* EnvGetAgendaChanged: Returns the value of the boolean */
793 /*   flag which indicates whether any changes have been  */
794 /*   made to the agenda.                                 */
795 /*********************************************************/
796 globle int EnvGetAgendaChanged(
797   void *theEnv)
798   {
799    return(AgendaData(theEnv)->AgendaChanged);
800   }
801
802 /*****************************************************************/
803 /* EnvSetAgendaChanged: Sets the value of the boolean flag which */
804 /*   indicates whether any changes have been made to the agenda. */
805 /*****************************************************************/
806 globle void EnvSetAgendaChanged(
807   void *theEnv,
808   int value)
809   {
810    AgendaData(theEnv)->AgendaChanged = value;
811   }
812
813 /**********************************************************/
814 /* EnvReorderAgenda: Completely reorders the agenda based */
815 /*   on the current conflict resolution strategy.         */
816 /**********************************************************/
817 globle void EnvReorderAgenda(
818   void *theEnv,
819   void *vTheModule)
820   {
821    struct activation *theActivation, *tempPtr;
822    struct defmodule *theModule = (struct defmodule *) vTheModule;
823    int allModules = FALSE;
824    struct defruleModule *theModuleItem;
825    struct salienceGroup *theGroup, *tempGroup;
826
827    /*=============================================*/
828    /* If the module specified is a NULL pointer,  */
829    /* then every module has its agenda reordered. */
830    /*=============================================*/
831
832    if (theModule == NULL)
833      {
834       allModules = TRUE;
835       theModule = (struct defmodule *) EnvGetNextDefmodule(theEnv,NULL);
836      }
837
838    /*========================*/
839    /* Reorder the agenda(s). */
840    /*========================*/
841
842    for (;
843         theModule != NULL;
844         theModule = (struct defmodule *) EnvGetNextDefmodule(theEnv,theModule))
845      {
846       /*=================================*/
847       /* Get the list of activations and */
848       /* remove them from the agenda.    */
849       /*=================================*/
850
851       theModuleItem = GetDefruleModuleItem(theEnv,theModule);
852       theActivation = theModuleItem->agenda;
853       theModuleItem->agenda = NULL;
854
855       theGroup = theModuleItem->groupings;
856       while (theGroup != NULL)
857         {
858          tempGroup = theGroup->next;
859          rtn_struct(theEnv,salienceGroup,theGroup);
860          theGroup = tempGroup;
861         }
862
863       theModuleItem->groupings = NULL;
864
865       /*=========================================*/
866       /* Reorder the activations by placing them */
867       /* back on the agenda one by one.          */
868       /*=========================================*/
869
870       while (theActivation != NULL)
871         {
872          tempPtr = theActivation->next;
873          theActivation->next = NULL;
874          theActivation->prev = NULL;
875          theGroup = ReuseOrCreateSalienceGroup(theEnv,theModuleItem,theActivation->salience);
876          PlaceActivation(theEnv,&(theModuleItem->agenda),theActivation,theGroup);
877          theActivation = tempPtr;
878         }
879
880       /*===============================================*/
881       /* Return if only one agenda is being reordered. */
882       /*===============================================*/
883
884       if (! allModules) return;
885      }
886   }
887
888 /****************************************************/
889 /* GetNumberOfActivations: Returns the value of the */
890 /*   total number of activations on all agendas.    */
891 /****************************************************/
892 globle unsigned long GetNumberOfActivations(
893   void *theEnv)
894   {
895    return(AgendaData(theEnv)->NumberOfActivations);
896   }
897
898 /******************************************************/
899 /* RefreshCommand: H/L Command for refreshing a rule. */
900 /*   Syntax: (refresh <defrule-name>)                 */
901 /******************************************************/
902 globle void RefreshCommand(
903   void *theEnv)
904   {
905    const char *ruleName;
906    void *rulePtr;
907
908    /*===========================*/
909    /* Get the name of the rule. */
910    /*===========================*/
911
912    ruleName = GetConstructName(theEnv,"refresh","rule name");
913    if (ruleName == NULL) return;
914
915    /*===============================*/
916    /* Determine if the rule exists. */
917    /*===============================*/
918
919    rulePtr = EnvFindDefrule(theEnv,ruleName);
920    if (rulePtr == NULL)
921      {
922       CantFindItemErrorMessage(theEnv,"defrule",ruleName);
923       return;
924      }
925
926    /*===================*/
927    /* Refresh the rule. */
928    /*===================*/
929
930    EnvRefresh(theEnv,rulePtr);
931   }
932
933 /************************************************************/
934 /* EnvRefresh: Refreshes a defrule. Activations of the rule */
935 /*   that have already been fired are added to the agenda.  */
936 /************************************************************/
937 globle intBool EnvRefresh(
938   void *theEnv,
939   void *theRule)
940   {
941    struct defrule *rulePtr;
942    struct partialMatch *listOfMatches;
943    unsigned long b;
944
945    /*====================================*/
946    /* Refresh each disjunct of the rule. */
947    /*====================================*/
948
949    for (rulePtr = (struct defrule *) theRule;
950         rulePtr != NULL;
951         rulePtr = rulePtr->disjunct)
952      {
953       /*================================*/
954       /* Check each partial match that  */
955       /* satisfies the LHS of the rule. */
956       /*================================*/
957
958       for (b = 0; b < rulePtr->lastJoin->leftMemory->size; b++)
959         {
960          for (listOfMatches = rulePtr->lastJoin->leftMemory->beta[b];
961               listOfMatches != NULL;
962               listOfMatches = listOfMatches->nextInMemory)
963            {
964             /*=======================================================*/
965             /* If the partial match is associated with an activation */
966             /* (which it should always be), then place a new         */
967             /* activation on the agenda if this partial matchdoesn't */
968             /* have an activation associated with it.                */
969             /*=======================================================*/
970
971             if (((struct joinNode *) listOfMatches->owner)->ruleToActivate != NULL)
972               {
973                if (listOfMatches->marker == NULL)
974                  { AddActivation(theEnv,rulePtr,listOfMatches); }
975               }
976            }
977         }
978      }
979
980    return(TRUE);
981   }
982
983 /**********************************************/
984 /* RefreshAgendaCommand: H/L access routine   */
985 /*   for the refresh-agenda command.          */
986 /**********************************************/
987 globle void RefreshAgendaCommand(
988   void *theEnv)
989   {
990    int numArgs, error;
991    struct defmodule *theModule;
992
993    /*==============================================*/
994    /* This function can have at most one argument. */
995    /*==============================================*/
996
997    if ((numArgs = EnvArgCountCheck(theEnv,"refresh-agenda",NO_MORE_THAN,1)) == -1) return;
998
999    /*===============================================================*/
1000    /* If a module name is specified, then the agenda of that module */
1001    /* is refreshed. Otherwise, the agenda of the current module is  */
1002    /* refreshed.                                                    */
1003    /*===============================================================*/
1004
1005    if (numArgs == 1)
1006      {
1007       theModule = GetModuleName(theEnv,"refresh-agenda",1,&error);
1008       if (error) return;
1009      }
1010    else
1011      { theModule = ((struct defmodule *) EnvGetCurrentModule(theEnv)); }
1012
1013    /*===============================================*/
1014    /* Refresh the agenda of the appropriate module. */
1015    /*===============================================*/
1016
1017    EnvRefreshAgenda(theEnv,theModule);
1018   }
1019
1020 /**************************************/
1021 /* EnvRefreshAgenda: C access routine */
1022 /*   for the refresh-agenda command.  */
1023 /**************************************/
1024 globle void EnvRefreshAgenda(
1025   void *theEnv,
1026   void *vTheModule)
1027   {
1028    struct activation *theActivation;
1029    struct defmodule *theModule = (struct defmodule *) vTheModule;
1030    intBool oldValue;
1031    int allModules = FALSE;
1032
1033    /*==========================*/
1034    /* Save the current module. */
1035    /*==========================*/
1036
1037    SaveCurrentModule(theEnv);
1038
1039    /*=============================================*/
1040    /* If the module specified is a NULL pointer,  */
1041    /* then every module has its agenda refreshed. */
1042    /*=============================================*/
1043
1044    if (theModule == NULL)
1045      {
1046       allModules = TRUE;
1047       theModule = (struct defmodule *) EnvGetNextDefmodule(theEnv,NULL);
1048      }
1049
1050    /*=======================================================*/
1051    /* Remember the current setting for salience evaluation. */
1052    /* To perform the refresh, the when activated setting is */
1053    /* used to recompute the salience values.                */
1054    /*=======================================================*/
1055
1056    oldValue = EnvGetSalienceEvaluation(theEnv);
1057    EnvSetSalienceEvaluation(theEnv,WHEN_ACTIVATED);
1058
1059    /*========================*/
1060    /* Refresh the agenda(s). */
1061    /*========================*/
1062
1063    for (;
1064         theModule != NULL;
1065         theModule = (struct defmodule *) EnvGetNextDefmodule(theEnv,theModule))
1066      {
1067       /*=========================================*/
1068       /* Change the current module to the module */
1069       /* of the agenda being refreshed.          */
1070       /*=========================================*/
1071
1072       EnvSetCurrentModule(theEnv,(void *) theModule);
1073
1074       /*================================================================*/
1075       /* Recompute the salience values for the current module's agenda. */
1076       /*================================================================*/
1077
1078       for (theActivation = (struct activation *) EnvGetNextActivation(theEnv,NULL);
1079            theActivation != NULL;
1080            theActivation = (struct activation *) EnvGetNextActivation(theEnv,theActivation))
1081         { theActivation->salience = EvaluateSalience(theEnv,theActivation->theRule); }
1082
1083       /*======================================================*/
1084       /* Reorder the agenda based on the new salience values. */
1085       /*======================================================*/
1086
1087       EnvReorderAgenda(theEnv,theModule);
1088
1089       /*===============================================*/
1090       /* Return if only one agenda is being refreshed. */
1091       /*===============================================*/
1092
1093       if (! allModules)
1094         {
1095          EnvSetSalienceEvaluation(theEnv,oldValue);
1096          RestoreCurrentModule(theEnv);
1097          return;
1098         }
1099      }
1100
1101    /*==========================================*/
1102    /* Restore the salience evaluation setting. */
1103    /*==========================================*/
1104
1105    EnvSetSalienceEvaluation(theEnv,oldValue);
1106
1107    /*=============================*/
1108    /* Restore the current module. */
1109    /*=============================*/
1110
1111    RestoreCurrentModule(theEnv);
1112   }
1113
1114 /*********************************************************/
1115 /* SetSalienceEvaluationCommand: H/L Command for setting */
1116 /*   the salience evaluation behavior.                   */
1117 /*   Syntax: (set-salience-evaluation-behavior <symbol>) */
1118 /*********************************************************/
1119 globle void *SetSalienceEvaluationCommand(
1120   void *theEnv)
1121   {
1122    DATA_OBJECT argPtr;
1123    const char *argument;
1124    const char *oldValue;
1125
1126    /*==================================================*/
1127    /* Get the current setting for salience evaluation. */
1128    /*==================================================*/
1129
1130    oldValue = SalienceEvaluationName(EnvGetSalienceEvaluation(theEnv));
1131
1132    /*=========================================*/
1133    /* This function expects a single argument */
1134    /* which must be a symbol.                 */
1135    /*=========================================*/
1136
1137    if (EnvArgCountCheck(theEnv,"set-salience-evaluation",EXACTLY,1) == -1)
1138      { return((SYMBOL_HN *) EnvAddSymbol(theEnv,oldValue)); }
1139
1140    if (EnvArgTypeCheck(theEnv,"set-salience-evaluation",1,SYMBOL,&argPtr) == FALSE)
1141      { return((SYMBOL_HN *) EnvAddSymbol(theEnv,oldValue)); }
1142
1143    /*=============================================================*/
1144    /* The allowed symbols to pass as an argument to this function */
1145    /* are when-defined, when-activated, and every-cycle.          */
1146    /*=============================================================*/
1147
1148    argument = DOToString(argPtr);
1149
1150    if (strcmp(argument,"when-defined") == 0)
1151      { EnvSetSalienceEvaluation(theEnv,WHEN_DEFINED); }
1152    else if (strcmp(argument,"when-activated") == 0)
1153      { EnvSetSalienceEvaluation(theEnv,WHEN_ACTIVATED); }
1154    else if (strcmp(argument,"every-cycle") == 0)
1155      { EnvSetSalienceEvaluation(theEnv,EVERY_CYCLE); }
1156    else
1157      {
1158       ExpectedTypeError1(theEnv,"set-salience-evaluation",1,
1159       "symbol with value when-defined, when-activated, or every-cycle");
1160       return((SYMBOL_HN *) EnvAddSymbol(theEnv,oldValue));
1161      }
1162
1163    /*=================================================*/
1164    /* Return the old setting for salience evaluation. */
1165    /*=================================================*/
1166
1167    return((SYMBOL_HN *) EnvAddSymbol(theEnv,oldValue));
1168   }
1169
1170 /*********************************************************/
1171 /* GetSalienceEvaluationCommand: H/L Command for getting */
1172 /*   the salience evaluation behavior.                   */
1173 /*   Syntax: (get-salience-evaluation-behavior)          */
1174 /*********************************************************/
1175 globle void *GetSalienceEvaluationCommand(
1176   void *theEnv)
1177   {
1178    EnvArgCountCheck(theEnv,"get-salience-evaluation",EXACTLY,0);
1179
1180    return((SYMBOL_HN *) EnvAddSymbol(theEnv,SalienceEvaluationName(EnvGetSalienceEvaluation(theEnv))));
1181   }
1182
1183 /*****************************************************************/
1184 /* SalienceEvaluationName: Given the integer value corresponding */
1185 /*   to a specified salience evaluation behavior, returns a      */
1186 /*   character string of the behavior's name.                    */
1187 /*****************************************************************/
1188 static const char *SalienceEvaluationName(
1189   int strategy)
1190   {
1191    const char *sname;
1192
1193    switch (strategy)
1194      {
1195       case WHEN_DEFINED:
1196         sname = "when-defined";
1197         break;
1198       case WHEN_ACTIVATED:
1199         sname = "when-activated";
1200         break;
1201       case EVERY_CYCLE:
1202         sname = "every-cycle";
1203         break;
1204       default:
1205         sname = "unknown";
1206         break;
1207      }
1208
1209    return(sname);
1210   }
1211
1212 /****************************************************************/
1213 /* EnvGetSalienceEvaluation: Returns the value of current type  */
1214 /*  of salience evaluation (e.g., when defined, when activated, */
1215 /*  or every cycle).                                            */
1216 /****************************************************************/
1217 globle intBool EnvGetSalienceEvaluation(
1218   void *theEnv)
1219   {
1220    return(AgendaData(theEnv)->SalienceEvaluation);
1221   }
1222
1223 /***********************************************/
1224 /* EnvSetSalienceEvaluation: Sets the value of */
1225 /*   the current type of salience evaluation.  */
1226 /***********************************************/
1227 globle intBool EnvSetSalienceEvaluation(
1228   void *theEnv,
1229   int value)
1230   {
1231    int ov;
1232
1233    ov = AgendaData(theEnv)->SalienceEvaluation;
1234    AgendaData(theEnv)->SalienceEvaluation = value;
1235    return(ov);
1236   }
1237
1238 /*****************************************************************/
1239 /* EvaluateSalience: Returns the salience value of the specified */
1240 /*   defrule. If salience evaluation is currently set to         */
1241 /*   when-defined, then the current value of the rule's salience */
1242 /*   is returned. Otherwise the salience expression associated   */
1243 /*   with the rule is reevaluated, the value is stored as the    */
1244 /*   rule's current salience, and it is then returned.           */
1245 /*****************************************************************/
1246 static int EvaluateSalience(
1247   void *theEnv,
1248   void *vPtr)
1249   {
1250    struct defrule *rPtr = (struct defrule *) vPtr;
1251    DATA_OBJECT salienceValue;
1252    int salience;
1253
1254   /*==================================================*/
1255   /* If saliences are only being evaluated when rules */
1256   /* are defined, then just return the last salience  */
1257   /* value evaluated for the rule.                    */
1258   /*==================================================*/
1259
1260   if (EnvGetSalienceEvaluation(theEnv) == WHEN_DEFINED)
1261     { return(rPtr->salience); }
1262
1263   /*=================================================================*/
1264   /* If the rule's salience value was defined as an integer constant */
1265   /* (i.e., not an expression or global variable which could change  */
1266   /* on reevaluation), then just return the salience value computed  */
1267   /* for the rule when it was defined.                               */
1268   /*=================================================================*/
1269
1270   if (rPtr->dynamicSalience == NULL) return(rPtr->salience);
1271
1272   /*====================================================*/
1273   /* Reevaluate the rule's salience. If an error occurs */
1274   /* during evaluation, print an error message.         */
1275   /*====================================================*/
1276
1277   SetEvaluationError(theEnv,FALSE);
1278   if (EvaluateExpression(theEnv,rPtr->dynamicSalience,&salienceValue))
1279     {
1280      SalienceInformationError(theEnv,"defrule",ValueToString(rPtr->header.name));
1281      return(rPtr->salience);
1282     }
1283
1284   /*========================================*/
1285   /* The salience value must be an integer. */
1286   /*========================================*/
1287
1288   if (salienceValue.type != INTEGER)
1289     {
1290      SalienceNonIntegerError(theEnv);
1291      SalienceInformationError(theEnv,"defrule",ValueToString(rPtr->header.name));
1292      SetEvaluationError(theEnv,TRUE);
1293      return(rPtr->salience);
1294     }
1295
1296   /*==========================================*/
1297   /* The salience value must fall between the */
1298   /* minimum and maximum allowed values.      */
1299   /*==========================================*/
1300
1301   salience = (int) ValueToLong(salienceValue.value);
1302
1303   if ((salience > MAX_DEFRULE_SALIENCE) || (salience < MIN_DEFRULE_SALIENCE))
1304     {
1305      SalienceRangeError(theEnv,MIN_DEFRULE_SALIENCE,MAX_DEFRULE_SALIENCE);
1306      SetEvaluationError(theEnv,TRUE);
1307      SalienceInformationError(theEnv,"defrule",ValueToString(((struct defrule *) rPtr)->header.name));
1308      return(rPtr->salience);
1309     }
1310
1311   /*===================================*/
1312   /* Store the new salience value with */
1313   /* the rule and return this value.   */
1314   /*===================================*/
1315
1316   rPtr->salience = salience;
1317   return(rPtr->salience);
1318  }
1319
1320 #if DEBUGGING_FUNCTIONS
1321
1322 /***********************************************/
1323 /* AgendaCommand: Prints out the agenda of the */
1324 /*   rules that are ready to fire.             */
1325 /*   Syntax: (agenda)                          */
1326 /***********************************************/
1327 globle void AgendaCommand(
1328   void *theEnv)
1329   {
1330    int numArgs, error;
1331    struct defmodule *theModule;
1332
1333    /*==============================================*/
1334    /* This function can have at most one argument. */
1335    /*==============================================*/
1336
1337    if ((numArgs = EnvArgCountCheck(theEnv,"agenda",NO_MORE_THAN,1)) == -1) return;
1338
1339    /*===============================================================*/
1340    /* If a module name is specified, then the agenda of that module */
1341    /* is displayed. Otherwise, the agenda of the current module is  */
1342    /* displayed.                                                    */
1343    /*===============================================================*/
1344
1345    if (numArgs == 1)
1346      {
1347       theModule = GetModuleName(theEnv,"agenda",1,&error);
1348       if (error) return;
1349      }
1350    else
1351      { theModule = ((struct defmodule *) EnvGetCurrentModule(theEnv)); }
1352
1353    /*===============================================*/
1354    /* Display the agenda of the appropriate module. */
1355    /*===============================================*/
1356
1357    EnvAgenda(theEnv,WDISPLAY,theModule);
1358   }
1359
1360 #endif /* DEBUGGING_FUNCTIONS */
1361
1362 /*#####################################*/
1363 /* ALLOW_ENVIRONMENT_GLOBALS Functions */
1364 /*#####################################*/
1365
1366 #if ALLOW_ENVIRONMENT_GLOBALS
1367
1368 globle void Agenda(
1369   const char *logicalName,
1370   void *vTheModule)
1371   {
1372    EnvAgenda(GetCurrentEnvironment(),logicalName,vTheModule);
1373   }
1374
1375 globle intBool DeleteActivation(
1376   void *theActivation)
1377   {
1378    return EnvDeleteActivation(GetCurrentEnvironment(),theActivation);
1379   }
1380
1381 globle struct partialMatch *GetActivationBasis(
1382   void *actPtr)
1383   {
1384    return EnvGetActivationBasis(GetCurrentEnvironment(),actPtr);
1385   }
1386
1387 globle const char *GetActivationName(
1388   void *actPtr)
1389   {
1390    return EnvGetActivationName(GetCurrentEnvironment(),actPtr);
1391   }
1392
1393 globle void GetActivationPPForm(
1394   char *buffer,
1395   unsigned bufferLength,
1396   void *theActivation)
1397   {
1398    EnvGetActivationPPForm(GetCurrentEnvironment(),buffer,bufferLength,theActivation);
1399   }
1400
1401 globle struct defrule *GetActivationRule(
1402   void *actPtr)
1403   {
1404    return EnvGetActivationRule(GetCurrentEnvironment(),actPtr);
1405   }
1406
1407 globle int GetActivationSalience(
1408   void *actPtr)
1409   {
1410    return EnvGetActivationSalience(GetCurrentEnvironment(),actPtr);
1411   }
1412
1413 globle int GetAgendaChanged()
1414   {
1415    return EnvGetAgendaChanged(GetCurrentEnvironment());
1416   }
1417
1418 globle void *GetNextActivation(
1419   void *actPtr)
1420   {
1421    return EnvGetNextActivation(GetCurrentEnvironment(),actPtr);
1422   }
1423
1424 globle intBool Refresh(
1425   void *theRule)
1426   {
1427    return EnvRefresh(GetCurrentEnvironment(),theRule);
1428   }
1429
1430 globle void RefreshAgenda(
1431   void *vTheModule)
1432   {
1433    EnvRefreshAgenda(GetCurrentEnvironment(),vTheModule);
1434   }
1435
1436 globle void ReorderAgenda(
1437   void *vTheModule)
1438   {
1439    EnvReorderAgenda(GetCurrentEnvironment(),vTheModule);
1440   }
1441
1442 globle void SetAgendaChanged(
1443   int value)
1444   {
1445    EnvSetAgendaChanged(GetCurrentEnvironment(),value);
1446   }
1447
1448 globle int SetActivationSalience(
1449   void *actPtr,
1450   int value)
1451   {
1452    return EnvSetActivationSalience(GetCurrentEnvironment(),actPtr,value);
1453   }
1454
1455 globle intBool GetSalienceEvaluation()
1456   {
1457    return EnvGetSalienceEvaluation(GetCurrentEnvironment());
1458   }
1459
1460 globle intBool SetSalienceEvaluation(
1461   int value)
1462   {
1463    return EnvSetSalienceEvaluation(GetCurrentEnvironment(),value);
1464   }
1465
1466 #endif
1467
1468 #endif /* DEFRULE_CONSTRUCT */
1469