You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							470 lines
						
					
					
						
							12 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							470 lines
						
					
					
						
							12 KiB
						
					
					
				| /** | |
|   @file | |
|  | |
|   @ingroup cudd | |
|  | |
|   @brief Correlation between BDDs. | |
|  | |
|   @author Fabio Somenzi | |
|  | |
|   @copyright@parblock | |
|   Copyright (c) 1995-2015, Regents of the University of Colorado | |
|  | |
|   All rights reserved. | |
|  | |
|   Redistribution and use in source and binary forms, with or without | |
|   modification, are permitted provided that the following conditions | |
|   are met: | |
|  | |
|   Redistributions of source code must retain the above copyright | |
|   notice, this list of conditions and the following disclaimer. | |
|  | |
|   Redistributions in binary form must reproduce the above copyright | |
|   notice, this list of conditions and the following disclaimer in the | |
|   documentation and/or other materials provided with the distribution. | |
|  | |
|   Neither the name of the University of Colorado nor the names of its | |
|   contributors may be used to endorse or promote products derived from | |
|   this software without specific prior written permission. | |
|  | |
|   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
|   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
|   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
|   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
|   COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
|   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
|   BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
|   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | |
|   CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
|   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | |
|   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
|   POSSIBILITY OF SUCH DAMAGE. | |
|   @endparblock | |
|  | |
| */ | |
| 
 | |
| #include "util.h" | |
| #include "cuddInt.h" | |
|  | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Constant declarations                                                     */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Stucture declarations                                                     */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Type declarations                                                         */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| /** Type of hash-table key. */ | |
| typedef struct hashEntry { | |
|     DdNode *f; | |
|     DdNode *g; | |
| } HashEntry; | |
| 
 | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Variable declarations                                                     */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| #ifdef CORREL_STATS | |
| static	int	num_calls; | |
| #endif | |
|  | |
| /*---------------------------------------------------------------------------*/ | |
| /* Macro declarations                                                        */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| /** \cond */ | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Static function prototypes                                                */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| static double bddCorrelationAux (DdManager *dd, DdNode *f, DdNode *g, st_table *table); | |
| static double bddCorrelationWeightsAux (DdManager *dd, DdNode *f, DdNode *g, double *prob, st_table *table); | |
| static int CorrelCompare (const void *key1, const void *key2); | |
| static int CorrelHash (void const *key, int modulus); | |
| static enum st_retval CorrelCleanUp (void *key, void *value, void *arg); | |
| 
 | |
| /** \endcond */ | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Definition of exported functions                                          */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Computes the correlation of f and g. | |
|  | |
|   @details If f == g, their correlation is 1. If f == g', their | |
|   correlation is 0. | |
|  | |
|   @return the fraction of minterms in the ON-set of the EXNOR of f and | |
|   g.  If it runs out of memory, returns (double)CUDD_OUT_OF_MEM. | |
|  | |
|   @sideeffect None | |
|  | |
|   @see Cudd_bddCorrelationWeights | |
|  | |
| */ | |
| double | |
| Cudd_bddCorrelation( | |
|   DdManager * manager, | |
|   DdNode * f, | |
|   DdNode * g) | |
| { | |
|     st_table	*table; | |
|     double	correlation; | |
| 
 | |
| #ifdef CORREL_STATS | |
|     num_calls = 0; | |
| #endif | |
|  | |
|     table = st_init_table(CorrelCompare,CorrelHash); | |
|     if (table == NULL) return((double)CUDD_OUT_OF_MEM); | |
|     correlation = bddCorrelationAux(manager,f,g,table); | |
|     st_foreach(table, CorrelCleanUp, NIL(void)); | |
|     st_free_table(table); | |
|     return(correlation); | |
| 
 | |
| } /* end of Cudd_bddCorrelation */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Computes the correlation of f and g for given input | |
|   probabilities. | |
|  | |
|   @details On input, prob\[i\] is supposed to contain the probability | |
|   of the i-th input variable to be 1.  If f == g, their correlation is | |
|   1. If f == g', their correlation is 0.  The correlation of f and the | |
|   constant one gives the probability of f. | |
|  | |
|   @return the probability that f and g have the same value. If it runs | |
|   out of memory, returns (double)CUDD_OUT_OF_MEM. | |
|  | |
|   @sideeffect None | |
|  | |
|   @see Cudd_bddCorrelation | |
|  | |
| */ | |
| double | |
| Cudd_bddCorrelationWeights( | |
|   DdManager * manager, | |
|   DdNode * f, | |
|   DdNode * g, | |
|   double * prob) | |
| { | |
|     st_table	*table; | |
|     double	correlation; | |
| 
 | |
| #ifdef CORREL_STATS | |
|     num_calls = 0; | |
| #endif | |
|  | |
|     table = st_init_table(CorrelCompare,CorrelHash); | |
|     if (table == NULL) return((double)CUDD_OUT_OF_MEM); | |
|     correlation = bddCorrelationWeightsAux(manager,f,g,prob,table); | |
|     st_foreach(table, CorrelCleanUp, NIL(void)); | |
|     st_free_table(table); | |
|     return(correlation); | |
| 
 | |
| } /* end of Cudd_bddCorrelationWeights */ | |
| 
 | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Definition of internal functions                                          */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Definition of static functions                                            */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Performs the recursive step of Cudd_bddCorrelation. | |
|  | |
|   @return the fraction of minterms in the ON-set of the EXNOR of f and | |
|   g. | |
|  | |
|   @sideeffect None | |
|  | |
|   @see bddCorrelationWeightsAux | |
|  | |
| */ | |
| static double | |
| bddCorrelationAux( | |
|   DdManager * dd, | |
|   DdNode * f, | |
|   DdNode * g, | |
|   st_table * table) | |
| { | |
|     DdNode	*Fv, *Fnv, *G, *Gv, *Gnv; | |
|     double	min, *pmin, min1, min2; | |
|     void        *dummy; | |
|     HashEntry	*entry; | |
|     int topF, topG; | |
| 
 | |
|     statLine(dd); | |
| #ifdef CORREL_STATS | |
|     num_calls++; | |
| #endif | |
|  | |
|     /* Terminal cases: only work for BDDs. */ | |
|     if (f == g) return(1.0); | |
|     if (f == Cudd_Not(g)) return(0.0); | |
| 
 | |
|     /* Standardize call using the following properties: | |
|     **     (f EXNOR g)   = (g EXNOR f) | |
|     **     (f' EXNOR g') = (f EXNOR g). | |
|     */ | |
|     if (f > g) { | |
| 	DdNode *tmp = f; | |
| 	f = g; g = tmp; | |
|     } | |
|     if (Cudd_IsComplement(f)) { | |
| 	f = Cudd_Not(f); | |
| 	g = Cudd_Not(g); | |
|     } | |
|     /* From now on, f is regular. */ | |
|      | |
|     entry = ALLOC(HashEntry,1); | |
|     if (entry == NULL) { | |
| 	dd->errorCode = CUDD_MEMORY_OUT; | |
| 	return(CUDD_OUT_OF_MEM); | |
|     } | |
|     entry->f = f; entry->g = g; | |
| 
 | |
|     /* We do not use the fact that | |
|     ** correlation(f,g') = 1 - correlation(f,g) | |
|     ** to minimize the risk of cancellation. | |
|     */ | |
|     if (st_lookup(table, entry, &dummy)) { | |
|         min = *(double *) dummy; | |
| 	FREE(entry); | |
| 	return(min); | |
|     } | |
| 
 | |
|     G = Cudd_Regular(g); | |
|     topF = cuddI(dd,f->index); topG = cuddI(dd,G->index); | |
|     if (topF <= topG) { Fv = cuddT(f); Fnv = cuddE(f); } else { Fv = Fnv = f; } | |
|     if (topG <= topF) { Gv = cuddT(G); Gnv = cuddE(G); } else { Gv = Gnv = G; } | |
| 
 | |
|     if (g != G) { | |
| 	Gv = Cudd_Not(Gv); | |
| 	Gnv = Cudd_Not(Gnv); | |
|     } | |
| 
 | |
|     min1 = bddCorrelationAux(dd, Fv, Gv, table) / 2.0; | |
|     if (min1 == (double)CUDD_OUT_OF_MEM) { | |
| 	FREE(entry); | |
| 	return(CUDD_OUT_OF_MEM); | |
|     } | |
|     min2 = bddCorrelationAux(dd, Fnv, Gnv, table) / 2.0;  | |
|     if (min2 == (double)CUDD_OUT_OF_MEM) { | |
| 	FREE(entry); | |
| 	return(CUDD_OUT_OF_MEM); | |
|     } | |
|     min = (min1+min2); | |
|      | |
|     pmin = ALLOC(double,1); | |
|     if (pmin == NULL) { | |
| 	dd->errorCode = CUDD_MEMORY_OUT; | |
| 	return((double)CUDD_OUT_OF_MEM); | |
|     } | |
|     *pmin = min; | |
| 
 | |
|     if (st_insert(table, entry, pmin) == ST_OUT_OF_MEM) { | |
| 	FREE(entry); | |
| 	FREE(pmin); | |
| 	return((double)CUDD_OUT_OF_MEM); | |
|     } | |
|     return(min); | |
| 
 | |
| } /* end of bddCorrelationAux */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Performs the recursive step of Cudd_bddCorrelationWeigths. | |
|  | |
|   @sideeffect None | |
|  | |
|   @see bddCorrelationAux | |
|  | |
| */ | |
| static double | |
| bddCorrelationWeightsAux( | |
|   DdManager * dd, | |
|   DdNode * f, | |
|   DdNode * g, | |
|   double * prob, | |
|   st_table * table) | |
| { | |
|     DdNode	*Fv, *Fnv, *G, *Gv, *Gnv; | |
|     double	min, *pmin, min1, min2; | |
|     void        *dummy; | |
|     HashEntry	*entry; | |
|     int		topF, topG; | |
|     unsigned	index; | |
| 
 | |
|     statLine(dd); | |
| #ifdef CORREL_STATS | |
|     num_calls++; | |
| #endif | |
|  | |
|     /* Terminal cases: only work for BDDs. */ | |
|     if (f == g) return(1.0); | |
|     if (f == Cudd_Not(g)) return(0.0); | |
| 
 | |
|     /* Standardize call using the following properties: | |
|     **     (f EXNOR g)   = (g EXNOR f) | |
|     **     (f' EXNOR g') = (f EXNOR g). | |
|     */ | |
|     if (f > g) { | |
| 	DdNode *tmp = f; | |
| 	f = g; g = tmp; | |
|     } | |
|     if (Cudd_IsComplement(f)) { | |
| 	f = Cudd_Not(f); | |
| 	g = Cudd_Not(g); | |
|     } | |
|     /* From now on, f is regular. */ | |
|      | |
|     entry = ALLOC(HashEntry,1); | |
|     if (entry == NULL) { | |
| 	dd->errorCode = CUDD_MEMORY_OUT; | |
| 	return((double)CUDD_OUT_OF_MEM); | |
|     } | |
|     entry->f = f; entry->g = g; | |
| 
 | |
|     /* We do not use the fact that | |
|     ** correlation(f,g') = 1 - correlation(f,g) | |
|     ** to minimize the risk of cancellation. | |
|     */ | |
|     if (st_lookup(table, entry, &dummy)) { | |
| 	min = *(double *) dummy; | |
| 	FREE(entry); | |
| 	return(min); | |
|     } | |
| 
 | |
|     G = Cudd_Regular(g); | |
|     topF = cuddI(dd,f->index); topG = cuddI(dd,G->index); | |
|     if (topF <= topG) { | |
| 	Fv = cuddT(f); Fnv = cuddE(f); | |
| 	index = f->index; | |
|     } else { | |
| 	Fv = Fnv = f; | |
| 	index = G->index; | |
|     } | |
|     if (topG <= topF) { Gv = cuddT(G); Gnv = cuddE(G); } else { Gv = Gnv = G; } | |
| 
 | |
|     if (g != G) { | |
| 	Gv = Cudd_Not(Gv); | |
| 	Gnv = Cudd_Not(Gnv); | |
|     } | |
| 
 | |
|     min1 = bddCorrelationWeightsAux(dd, Fv, Gv, prob, table) * prob[index]; | |
|     if (min1 == (double)CUDD_OUT_OF_MEM) { | |
| 	FREE(entry); | |
| 	return((double)CUDD_OUT_OF_MEM); | |
|     } | |
|     min2 = bddCorrelationWeightsAux(dd, Fnv, Gnv, prob, table) * (1.0 - prob[index]);  | |
|     if (min2 == (double)CUDD_OUT_OF_MEM) { | |
| 	FREE(entry); | |
| 	return((double)CUDD_OUT_OF_MEM); | |
|     } | |
|     min = (min1+min2); | |
|      | |
|     pmin = ALLOC(double,1); | |
|     if (pmin == NULL) { | |
| 	dd->errorCode = CUDD_MEMORY_OUT; | |
| 	return((double)CUDD_OUT_OF_MEM); | |
|     } | |
|     *pmin = min; | |
| 
 | |
|     if (st_insert(table, entry, pmin) == ST_OUT_OF_MEM) { | |
| 	FREE(entry); | |
| 	FREE(pmin); | |
| 	return((double)CUDD_OUT_OF_MEM); | |
|     } | |
|     return(min); | |
| 
 | |
| } /* end of bddCorrelationWeightsAux */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Compares two hash table entries. | |
|  | |
|   @return 0 if they are identical; 1 otherwise. | |
|  | |
|   @sideeffect None | |
|  | |
| */ | |
| static int | |
| CorrelCompare( | |
|   void const * key1, | |
|   void const * key2) | |
| { | |
|     HashEntry const *entry1 = (HashEntry const *) key1; | |
|     HashEntry const *entry2 = (HashEntry const *) key2; | |
|     if (entry1->f != entry2->f || entry1->g != entry2->g) return(1); | |
| 
 | |
|     return(0); | |
| 
 | |
| } /* end of CorrelCompare */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Hashes a hash table entry. | |
|  | |
|   @details It is patterned after st_strhash. | |
|  | |
|   @return a value between 0 and modulus. | |
|  | |
|   @sideeffect None | |
|  | |
| */ | |
| static int | |
| CorrelHash( | |
|   void const * key, | |
|   int  modulus) | |
| { | |
|     HashEntry const *entry = (HashEntry const *) key; | |
|     int val = 0; | |
| 
 | |
|     val = (int) (((ptrint)entry->f)*997 + ((ptrint)entry->g)); | |
| 
 | |
|     return ((val < 0) ? -val : val) % modulus; | |
| 
 | |
| } /* end of CorrelHash */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Frees memory associated with hash table. | |
|  | |
|   @return ST_CONTINUE. | |
|  | |
|   @sideeffect None | |
|  | |
| */ | |
| static enum st_retval | |
| CorrelCleanUp( | |
|   void * key, | |
|   void * value, | |
|   void * arg) | |
| { | |
|     double	  *d = (double *) value; | |
|     HashEntry *entry = (HashEntry *) key; | |
| 
 | |
|     (void) arg; /* avoid warning */ | |
|     FREE(entry); | |
|     FREE(d); | |
|     return ST_CONTINUE; | |
| 
 | |
| } /* end of CorrelCleanUp */
 |