00001 /*******************************************************/ 00002 /* "C" Language Integrated Production System */ 00003 /* */ 00004 /* CLIPS Version 6.30 10/19/06 */ 00005 /* */ 00006 /* LOGICAL DEPENDENCIES MODULE */ 00007 /*******************************************************/ 00008 00009 /*************************************************************/ 00010 /* Purpose: Provide support routines for managing truth */ 00011 /* maintenance using the logical conditional element. */ 00012 /* */ 00013 /* Principal Programmer(s): */ 00014 /* Gary D. Riley */ 00015 /* */ 00016 /* Contributing Programmer(s): */ 00017 /* */ 00018 /* Revision History: */ 00019 /* */ 00020 /* 6.24: Removed LOGICAL_DEPENDENCIES compilation flag. */ 00021 /* */ 00022 /* Renamed BOOLEAN macro type to intBool. */ 00023 /* */ 00024 /* Rule with exists CE has incorrect activation. */ 00025 /* DR0867 */ 00026 /* */ 00027 /* 6.30: Added support for hashed alpha memories. */ 00028 /* */ 00029 /*************************************************************/ 00030 00031 #define _LGCLDPND_SOURCE_ 00032 00033 #include <stdio.h> 00034 #define _STDIO_INCLUDED_ 00035 00036 #include "setup.h" 00037 00038 #if DEFRULE_CONSTRUCT 00039 00040 #include "memalloc.h" 00041 #include "router.h" 00042 #include "envrnmnt.h" 00043 #include "evaluatn.h" 00044 #include "engine.h" 00045 #include "reteutil.h" 00046 #include "pattern.h" 00047 #include "argacces.h" 00048 #include "factmngr.h" 00049 00050 #if OBJECT_SYSTEM 00051 #include "insfun.h" 00052 #endif 00053 00054 #include "lgcldpnd.h" 00055 00056 /***************************************/ 00057 /* LOCAL INTERNAL FUNCTION DEFINITIONS */ 00058 /***************************************/ 00059 00060 static struct dependency *DetachAssociatedDependencies(void *,struct dependency *,void *); 00061 00062 /***********************************************************************/ 00063 /* AddLogicalDependencies: Adds the logical dependency links between a */ 00064 /* data entity (such as a fact or instance) and the partial match */ 00065 /* which logically supports that data entity. If a data entity is */ 00066 /* unconditionally asserted (i.e. the global variable TheLogicalJoin */ 00067 /* is NULL), then existing logical support for the data entity is no */ 00068 /* longer needed and it is removed. If a data entity is already */ 00069 /* unconditionally supported and that data entity is conditionally */ 00070 /* asserted (i.e. the global variable TheLogicalJoin is not NULL), */ 00071 /* then the logical support is ignored. Otherwise, the partial match */ 00072 /* is linked to the data entity and the data entity is linked to the */ 00073 /* partial match. Note that the word assert is used to refer to */ 00074 /* creating a fact with the assert command and creating an instance */ 00075 /* with the make-instance command. */ 00076 /***********************************************************************/ 00077 globle intBool AddLogicalDependencies( 00078 void *theEnv, 00079 struct patternEntity *theEntity, 00080 int existingEntity) 00081 { 00082 struct partialMatch *theBinds; 00083 struct dependency *newDependency; 00084 00085 /*==============================================*/ 00086 /* If the rule has no logical patterns, then no */ 00087 /* dependencies have to be established. */ 00088 /*==============================================*/ 00089 00090 if (EngineData(theEnv)->TheLogicalJoin == NULL) 00091 { 00092 if (existingEntity) RemoveEntityDependencies(theEnv,theEntity); 00093 return(TRUE); 00094 } 00095 else if (existingEntity && (theEntity->dependents == NULL)) 00096 { return(TRUE); } 00097 00098 /*===========================================================*/ 00099 /* Retrieve the partial match in the logical join associated */ 00100 /* with activation partial match (retrieved when the run */ 00101 /* command was initiated). If the partial match's parent */ 00102 /* links have been removed, then the partial match must have */ 00103 /* been deleted by a previous RHS action and the dependency */ 00104 /* link should not be added. */ 00105 /*===========================================================*/ 00106 00107 theBinds = EngineData(theEnv)->TheLogicalBind; 00108 if (theBinds == NULL) return(FALSE); 00109 if ((theBinds->leftParent == NULL) && (theBinds->rightParent == NULL)) 00110 { return(FALSE); } 00111 00112 /*==============================================================*/ 00113 /* Add a dependency link between the partial match and the data */ 00114 /* entity. The dependency links are stored in the partial match */ 00115 /* behind the data entities stored in the partial match and the */ 00116 /* activation link, if any. */ 00117 /*==============================================================*/ 00118 00119 newDependency = get_struct(theEnv,dependency); 00120 newDependency->dPtr = (void *) theEntity; 00121 newDependency->next = (struct dependency *) theBinds->dependents; 00122 theBinds->dependents = (void *) newDependency; 00123 00124 /*================================================================*/ 00125 /* Add a dependency link between the entity and the partialMatch. */ 00126 /*================================================================*/ 00127 00128 newDependency = get_struct(theEnv,dependency); 00129 newDependency->dPtr = (void *) theBinds; 00130 newDependency->next = (struct dependency *) theEntity->dependents; 00131 theEntity->dependents = (void *) newDependency; 00132 00133 /*==================================================================*/ 00134 /* Return TRUE to indicate that the data entity should be asserted. */ 00135 /*==================================================================*/ 00136 00137 return(TRUE); 00138 } 00139 00140 /************************************************************************/ 00141 /* FindLogicalBind: Finds the partial match associated with the logical */ 00142 /* CE which will provide logical support for a data entity asserted */ 00143 /* from the currently executing rule. The function is called when */ 00144 /* creating logical support links between the data entity and */ 00145 /* supporting partial matches. */ 00146 /************************************************************************/ 00147 globle struct partialMatch *FindLogicalBind( 00148 struct joinNode *theJoin, 00149 struct partialMatch *theBinds) 00150 { 00151 struct partialMatch *compPtr; 00152 00153 /*========================================================*/ 00154 /* Follow the parent link of the activation back through */ 00155 /* the join network until the join containing the logical */ 00156 /* partial match is found. The partial match at this */ 00157 /* join will have the dependency link assigned to it. */ 00158 /*========================================================*/ 00159 00160 for (compPtr = theBinds; 00161 compPtr != NULL; 00162 compPtr = compPtr->leftParent) 00163 { 00164 if (compPtr->owner == theJoin) 00165 { return(compPtr); } 00166 } 00167 00168 return(NULL); 00169 } 00170 00171 /*********************************************************************/ 00172 /* RemoveEntityDependencies: Removes all logical support links from */ 00173 /* a pattern entity that point to partial matches or other pattern */ 00174 /* entities. Also removes the associated links from the partial */ 00175 /* matches or pattern entities which point back to the pattern */ 00176 /* entities. */ 00177 /*********************************************************************/ 00178 globle void RemoveEntityDependencies( 00179 void *theEnv, 00180 struct patternEntity *theEntity) 00181 { 00182 struct dependency *fdPtr, *nextPtr, *theList; 00183 struct partialMatch *theBinds; 00184 00185 /*===============================*/ 00186 /* Get the list of dependencies. */ 00187 /*===============================*/ 00188 00189 fdPtr = (struct dependency *) theEntity->dependents; 00190 00191 /*========================================*/ 00192 /* Loop through each of the dependencies. */ 00193 /*========================================*/ 00194 00195 while (fdPtr != NULL) 00196 { 00197 /*===============================*/ 00198 /* Remember the next dependency. */ 00199 /*===============================*/ 00200 00201 nextPtr = fdPtr->next; 00202 00203 /*================================================================*/ 00204 /* Remove the link between the data entity and the partial match. */ 00205 /*================================================================*/ 00206 00207 theBinds = (struct partialMatch *) fdPtr->dPtr; 00208 theList = (struct dependency *) theBinds->dependents; 00209 theList = DetachAssociatedDependencies(theEnv,theList,(void *) theEntity); 00210 theBinds->dependents = (void *) theList; 00211 00212 /*========================*/ 00213 /* Return the dependency. */ 00214 /*========================*/ 00215 00216 rtn_struct(theEnv,dependency,fdPtr); 00217 00218 /*=================================*/ 00219 /* Move on to the next dependency. */ 00220 /*=================================*/ 00221 00222 fdPtr = nextPtr; 00223 } 00224 00225 /*=====================================================*/ 00226 /* Set the dependency list of the data entity to NULL. */ 00227 /*=====================================================*/ 00228 00229 theEntity->dependents = NULL; 00230 } 00231 00232 /********************************************************************/ 00233 /* ReturnEntityDependencies: Removes all logical support links from */ 00234 /* a pattern entity. This is unidirectional. The links from the */ 00235 /* the partial match to the entity are not removed. */ 00236 /********************************************************************/ 00237 globle void ReturnEntityDependencies( 00238 void *theEnv, 00239 struct patternEntity *theEntity) 00240 { 00241 struct dependency *fdPtr, *nextPtr; 00242 00243 fdPtr = (struct dependency *) theEntity->dependents; 00244 00245 while (fdPtr != NULL) 00246 { 00247 nextPtr = fdPtr->next; 00248 rtn_struct(theEnv,dependency,fdPtr); 00249 fdPtr = nextPtr; 00250 } 00251 00252 theEntity->dependents = NULL; 00253 } 00254 00255 /*******************************************************************/ 00256 /* DetachAssociatedDependencies: Removes all logical support links */ 00257 /* which pointer to a pattern entity from a list of dependencies */ 00258 /* (which may be associated with either a partial match or */ 00259 /* another pattern entity). Does not remove links which point in */ 00260 /* the other direction. */ 00261 /*******************************************************************/ 00262 static struct dependency *DetachAssociatedDependencies( 00263 void *theEnv, 00264 struct dependency *theList, 00265 void *theEntity) 00266 { 00267 struct dependency *fdPtr, *nextPtr, *lastPtr = NULL; 00268 00269 fdPtr = theList; 00270 00271 while (fdPtr != NULL) 00272 { 00273 if (fdPtr->dPtr == theEntity) 00274 { 00275 nextPtr = fdPtr->next; 00276 if (lastPtr == NULL) theList = nextPtr; 00277 else lastPtr->next = nextPtr; 00278 rtn_struct(theEnv,dependency,fdPtr); 00279 fdPtr = nextPtr; 00280 } 00281 else 00282 { 00283 lastPtr = fdPtr; 00284 fdPtr = fdPtr->next; 00285 } 00286 } 00287 00288 return(theList); 00289 } 00290 00291 /**************************************************************************/ 00292 /* RemovePMDependencies: Removes all logical support links from a partial */ 00293 /* match that point to any data entities. Also removes the associated */ 00294 /* links from the data entities which point back to the partial match. */ 00295 /**************************************************************************/ 00296 globle void RemovePMDependencies( 00297 void *theEnv, 00298 struct partialMatch *theBinds) 00299 { 00300 struct dependency *fdPtr, *nextPtr, *theList; 00301 struct patternEntity *theEntity; 00302 00303 fdPtr = (struct dependency *) theBinds->dependents; 00304 00305 while (fdPtr != NULL) 00306 { 00307 nextPtr = fdPtr->next; 00308 00309 theEntity = (struct patternEntity *) fdPtr->dPtr; 00310 00311 theList = (struct dependency *) theEntity->dependents; 00312 theList = DetachAssociatedDependencies(theEnv,theList,(void *) theBinds); 00313 theEntity->dependents = (void *) theList; 00314 00315 rtn_struct(theEnv,dependency,fdPtr); 00316 fdPtr = nextPtr; 00317 } 00318 00319 theBinds->dependents = NULL; 00320 } 00321 00322 /************************************************************/ 00323 /* DestroyPMDependencies: Removes all logical support links */ 00324 /* from a partial match that point to any data entities. */ 00325 /************************************************************/ 00326 globle void DestroyPMDependencies( 00327 void *theEnv, 00328 struct partialMatch *theBinds) 00329 { 00330 struct dependency *fdPtr, *nextPtr; 00331 00332 fdPtr = (struct dependency *) theBinds->dependents; 00333 00334 while (fdPtr != NULL) 00335 { 00336 nextPtr = fdPtr->next; 00337 00338 rtn_struct(theEnv,dependency,fdPtr); 00339 fdPtr = nextPtr; 00340 } 00341 00342 theBinds->dependents = NULL; 00343 } 00344 00345 /************************************************************************/ 00346 /* RemoveLogicalSupport: Removes the dependency links between a partial */ 00347 /* match and the data entities it logically supports. Also removes */ 00348 /* the associated links from the data entities which point back to */ 00349 /* the partial match by calling DetachAssociatedEntityDependencies. */ 00350 /* If an entity has all of its logical support removed as a result of */ 00351 /* this procedure, the dependency link from the partial match is */ 00352 /* added to the list of unsupported data entities so that the entity */ 00353 /* will be deleted as a result of losing its logical support. */ 00354 /************************************************************************/ 00355 globle void RemoveLogicalSupport( 00356 void *theEnv, 00357 struct partialMatch *theBinds) 00358 { 00359 struct dependency *dlPtr, *tempPtr, *theList; 00360 struct patternEntity *theEntity; 00361 00362 /*========================================*/ 00363 /* If the partial match has no associated */ 00364 /* dependencies, then return. */ 00365 /*========================================*/ 00366 00367 if (theBinds->dependents == NULL) return; 00368 00369 /*=======================================*/ 00370 /* Loop through each of the dependencies */ 00371 /* attached to the partial match. */ 00372 /*=======================================*/ 00373 00374 dlPtr = (struct dependency *) theBinds->dependents; 00375 00376 while (dlPtr != NULL) 00377 { 00378 /*===============================*/ 00379 /* Remember the next dependency. */ 00380 /*===============================*/ 00381 00382 tempPtr = dlPtr->next; 00383 00384 /*==========================================================*/ 00385 /* Determine the data entity associated with the dependency */ 00386 /* structure and delete its dependency references to this */ 00387 /* partial match. */ 00388 /*==========================================================*/ 00389 00390 theEntity = (struct patternEntity *) dlPtr->dPtr; 00391 00392 theList = (struct dependency *) theEntity->dependents; 00393 theList = DetachAssociatedDependencies(theEnv,theList,(void *) theBinds); 00394 theEntity->dependents = (void *) theList; 00395 00396 /*==============================================================*/ 00397 /* If the data entity has lost all of its logical support, then */ 00398 /* add the dependency structure from the partial match to the */ 00399 /* list of unsupported data entities to be deleted. Otherwise, */ 00400 /* just delete the dependency structure. */ 00401 /*==============================================================*/ 00402 00403 if (theEntity->dependents == NULL) 00404 { 00405 (*theEntity->theInfo->base.incrementBusyCount)(theEnv,theEntity); 00406 dlPtr->next = EngineData(theEnv)->UnsupportedDataEntities; 00407 EngineData(theEnv)->UnsupportedDataEntities = dlPtr; 00408 } 00409 else 00410 { rtn_struct(theEnv,dependency,dlPtr); } 00411 00412 /*==================================*/ 00413 /* Move on to the next dependency. */ 00414 /*==================================*/ 00415 00416 dlPtr = tempPtr; 00417 } 00418 00419 /*=====================================*/ 00420 /* The partial match no longer has any */ 00421 /* dependencies associated with it. */ 00422 /*=====================================*/ 00423 00424 theBinds->dependents = NULL; 00425 } 00426 00427 /********************************************************************/ 00428 /* ForceLogicalRetractions: Deletes the data entities found on the */ 00429 /* list of items that have lost their logical support. The delete */ 00430 /* function associated with each data entity is called to delete */ 00431 /* that data entity. Calling the delete function may in turn */ 00432 /* add more data entities to the list of data entities which have */ 00433 /* lost their logical support. */ 00434 /********************************************************************/ 00435 globle void ForceLogicalRetractions( 00436 void *theEnv) 00437 { 00438 struct dependency *tempPtr; 00439 struct patternEntity *theEntity; 00440 00441 /*===================================================*/ 00442 /* Don't reenter this function once it's called. Any */ 00443 /* new additions to the list of items to be deleted */ 00444 /* as a result of losing their logical support will */ 00445 /* be handled properly. */ 00446 /*===================================================*/ 00447 00448 if (EngineData(theEnv)->alreadyEntered) return; 00449 EngineData(theEnv)->alreadyEntered = TRUE; 00450 00451 /*=======================================================*/ 00452 /* Continue to delete the first item on the list as long */ 00453 /* as one exists. This is done because new items may be */ 00454 /* placed at the beginning of the list as other data */ 00455 /* entities are deleted. */ 00456 /*=======================================================*/ 00457 00458 while (EngineData(theEnv)->UnsupportedDataEntities != NULL) 00459 { 00460 /*==========================================*/ 00461 /* Determine the data entity to be deleted. */ 00462 /*==========================================*/ 00463 00464 theEntity = (struct patternEntity *) EngineData(theEnv)->UnsupportedDataEntities->dPtr; 00465 00466 /*================================================*/ 00467 /* Remove the dependency structure from the list. */ 00468 /*================================================*/ 00469 00470 tempPtr = EngineData(theEnv)->UnsupportedDataEntities; 00471 EngineData(theEnv)->UnsupportedDataEntities = EngineData(theEnv)->UnsupportedDataEntities->next; 00472 rtn_struct(theEnv,dependency,tempPtr); 00473 00474 /*=========================*/ 00475 /* Delete the data entity. */ 00476 /*=========================*/ 00477 00478 (*theEntity->theInfo->base.decrementBusyCount)(theEnv,theEntity); 00479 (*theEntity->theInfo->base.deleteFunction)(theEnv,theEntity); 00480 } 00481 00482 /*============================================*/ 00483 /* Deletion of items on the list is complete. */ 00484 /*============================================*/ 00485 00486 EngineData(theEnv)->alreadyEntered = FALSE; 00487 } 00488 00489 /****************************************************************/ 00490 /* Dependencies: C access routine for the dependencies command. */ 00491 /****************************************************************/ 00492 globle void Dependencies( 00493 void *theEnv, 00494 struct patternEntity *theEntity) 00495 { 00496 struct dependency *fdPtr; 00497 00498 /*=========================================*/ 00499 /* If the data entity has no dependencies, */ 00500 /* then print "None" and return. */ 00501 /*=========================================*/ 00502 00503 if (theEntity->dependents == NULL) 00504 { 00505 EnvPrintRouter(theEnv,WDISPLAY,"None\n"); 00506 return; 00507 } 00508 00509 /*============================================*/ 00510 /* Loop through the list of the data entities */ 00511 /* dependencies and print them. */ 00512 /*============================================*/ 00513 00514 for (fdPtr = (struct dependency *) theEntity->dependents; 00515 fdPtr != NULL; 00516 fdPtr = fdPtr->next) 00517 { 00518 if (GetHaltExecution(theEnv) == TRUE) return; 00519 PrintPartialMatch(theEnv,WDISPLAY,(struct partialMatch *) fdPtr->dPtr); 00520 EnvPrintRouter(theEnv,WDISPLAY,"\n"); 00521 } 00522 } 00523 00524 /************************************************************/ 00525 /* Dependents: C access routine for the dependents command. */ 00526 /************************************************************/ 00527 globle void Dependents( 00528 void *theEnv, 00529 struct patternEntity *theEntity) 00530 { 00531 struct patternEntity *entityPtr = NULL; 00532 struct patternParser *theParser = NULL; 00533 struct dependency *fdPtr; 00534 struct partialMatch *theBinds; 00535 int found = FALSE; 00536 00537 /*=================================*/ 00538 /* Loop through every data entity. */ 00539 /*=================================*/ 00540 00541 for (GetNextPatternEntity(theEnv,&theParser,&entityPtr); 00542 entityPtr != NULL; 00543 GetNextPatternEntity(theEnv,&theParser,&entityPtr)) 00544 { 00545 if (GetHaltExecution(theEnv) == TRUE) return; 00546 00547 /*====================================*/ 00548 /* Loop through every dependency link */ 00549 /* associated with the data entity. */ 00550 /*====================================*/ 00551 00552 for (fdPtr = (struct dependency *) entityPtr->dependents; 00553 fdPtr != NULL; 00554 fdPtr = fdPtr->next) 00555 { 00556 if (GetHaltExecution(theEnv) == TRUE) return; 00557 00558 /*=====================================================*/ 00559 /* If the data entity which was the argument passed to */ 00560 /* the dependents command is contained in one of the */ 00561 /* partial matches of the data entity currently being */ 00562 /* examined, then the data entity being examined is a */ 00563 /* dependent. Print the data entity and then move on */ 00564 /* to the next data entity. */ 00565 /*=====================================================*/ 00566 00567 theBinds = (struct partialMatch *) fdPtr->dPtr; 00568 if (FindEntityInPartialMatch(theEntity,theBinds) == TRUE) 00569 { 00570 if (found) EnvPrintRouter(theEnv,WDISPLAY,","); 00571 (*entityPtr->theInfo->base.shortPrintFunction)(theEnv,WDISPLAY,entityPtr); 00572 found = TRUE; 00573 break; 00574 } 00575 } 00576 } 00577 00578 /*=================================================*/ 00579 /* If no dependents were found, then print "None." */ 00580 /* Otherwise print a carriage return after the */ 00581 /* list of dependents. */ 00582 /*=================================================*/ 00583 00584 if (! found) EnvPrintRouter(theEnv,WDISPLAY,"None\n"); 00585 else EnvPrintRouter(theEnv,WDISPLAY,"\n"); 00586 } 00587 00588 #if DEBUGGING_FUNCTIONS 00589 00590 /*********************************************/ 00591 /* DependenciesCommand: H/L access routine */ 00592 /* for the dependencies command. */ 00593 /*********************************************/ 00594 globle void DependenciesCommand( 00595 void *theEnv) 00596 { 00597 DATA_OBJECT item; 00598 void *ptr; 00599 00600 if (EnvArgCountCheck(theEnv,"dependencies",EXACTLY,1) == -1) return; 00601 00602 ptr = GetFactOrInstanceArgument(theEnv,1,&item,"dependencies"); 00603 00604 if (ptr == NULL) return; 00605 00606 #if DEFRULE_CONSTRUCT 00607 Dependencies(theEnv,(struct patternEntity *) ptr); 00608 #else 00609 EnvPrintRouter(theEnv,WDISPLAY,"None\n"); 00610 #endif 00611 } 00612 00613 /*******************************************/ 00614 /* DependentsCommand: H/L access routine */ 00615 /* for the dependents command. */ 00616 /*******************************************/ 00617 globle void DependentsCommand( 00618 void *theEnv) 00619 { 00620 DATA_OBJECT item; 00621 void *ptr; 00622 00623 if (EnvArgCountCheck(theEnv,"dependents",EXACTLY,1) == -1) return; 00624 00625 ptr = GetFactOrInstanceArgument(theEnv,1,&item,"dependents"); 00626 00627 if (ptr == NULL) return; 00628 00629 #if DEFRULE_CONSTRUCT 00630 Dependents(theEnv,(struct patternEntity *) ptr); 00631 #else 00632 EnvPrintRouter(theEnv,WDISPLAY,"None\n"); 00633 #endif 00634 } 00635 00636 #endif /* DEBUGGING_FUNCTIONS */ 00637 00638 #endif /* DEFRULE_CONSTRUCT */ 00639
1.5.6