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.
		
		
		
		
		
			
		
			
				
					
					
						
							2177 lines
						
					
					
						
							64 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							2177 lines
						
					
					
						
							64 KiB
						
					
					
				
								/**
							 | 
						|
								  @file
							 | 
						|
								
							 | 
						|
								  @ingroup cudd
							 | 
						|
								
							 | 
						|
								  @brief Procedures to approximate a given %BDD.
							 | 
						|
								
							 | 
						|
								  @see cuddSubsetHB.c cuddSubsetSP.c cuddGenCof.c
							 | 
						|
								
							 | 
						|
								  @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
							 | 
						|
								
							 | 
						|
								*/
							 | 
						|
								
							 | 
						|
								#ifdef __STDC__
							 | 
						|
								#include <float.h>
							 | 
						|
								#else
							 | 
						|
								#define DBL_MAX_EXP 1024
							 | 
						|
								#endif
							 | 
						|
								#include "util.h"
							 | 
						|
								#include "cuddInt.h"
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Constant declarations                                                     */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								#define NOTHING		0
							 | 
						|
								#define REPLACE_T	1
							 | 
						|
								#define REPLACE_E	2
							 | 
						|
								#define REPLACE_N	3
							 | 
						|
								#define REPLACE_TT	4
							 | 
						|
								#define REPLACE_TE	5
							 | 
						|
								
							 | 
						|
								#define DONT_CARE	0
							 | 
						|
								#define CARE		1
							 | 
						|
								#define TOTAL_CARE	2
							 | 
						|
								#define CARE_ERROR	3
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Stucture declarations                                                     */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Type declarations                                                         */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 ** @brief Data structure to store the information on each node.
							 | 
						|
								 **
							 | 
						|
								 ** @details It keeps the number of minterms of the function rooted at
							 | 
						|
								 ** this node in terms of the number of variables specified by the
							 | 
						|
								 ** user; the number of minterms of the complement; the impact of the
							 | 
						|
								 ** number of minterms of this function on the number of minterms of
							 | 
						|
								 ** the root function; the reference count of the node from within the
							 | 
						|
								 ** root function; the flag that says whether the node intersects the
							 | 
						|
								 ** care set; the flag that says whether the node should be replaced
							 | 
						|
								 ** and how; the results of subsetting in both phases.
							 | 
						|
								 */
							 | 
						|
								typedef struct NodeData {
							 | 
						|
								    double mintermsP;		/**< minterms for the regular node */
							 | 
						|
								    double mintermsN;		/**< minterms for the complemented node */
							 | 
						|
								    int functionRef;		/**< references from within this function */
							 | 
						|
								    char care;			/**< node intersects care set */
							 | 
						|
								    char replace;		/**< replacement decision */
							 | 
						|
								    short int parity;		/**< 1: even; 2: odd; 3: both */
							 | 
						|
								    DdNode *resultP;		/**< result for even parity */
							 | 
						|
								    DdNode *resultN;		/**< result for odd parity */
							 | 
						|
								} NodeData;
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 **  @brief Main bookkeeping data structure for approximation algorithms.
							 | 
						|
								 */
							 | 
						|
								typedef struct ApproxInfo {
							 | 
						|
								    DdNode *one;		/**< one constant */
							 | 
						|
								    DdNode *zero;		/**< %BDD zero constant */
							 | 
						|
								    NodeData *page;		/**< per-node information */
							 | 
						|
								    DdHashTable *table;		/**< hash table to access the per-node info */
							 | 
						|
								    int index;			/**< index of the current node */
							 | 
						|
								    double max;			/**< max number of minterms */
							 | 
						|
								    int size;			/**< how many nodes are left */
							 | 
						|
								    double minterms;		/**< how many minterms are left */
							 | 
						|
								} ApproxInfo;
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 ** @brief Item of the queue used in the levelized traversal of the %BDD.
							 | 
						|
								 */
							 | 
						|
								typedef struct GlobalQueueItem {
							 | 
						|
								    struct GlobalQueueItem *next;
							 | 
						|
								    struct GlobalQueueItem *cnext;
							 | 
						|
								    DdNode *node;
							 | 
						|
								    double impactP;
							 | 
						|
								    double impactN;
							 | 
						|
								} GlobalQueueItem;
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 ** @brief Type of the item of the local queue.
							 | 
						|
								 */
							 | 
						|
								typedef struct LocalQueueItem {
							 | 
						|
								    struct LocalQueueItem *next;
							 | 
						|
								    struct LocalQueueItem *cnext;
							 | 
						|
								    DdNode *node;
							 | 
						|
								    int localRef;
							 | 
						|
								} LocalQueueItem;
							 | 
						|
								
							 | 
						|
								    
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Variable declarations                                                     */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Macro declarations                                                        */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								/** \cond */
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Static function prototypes                                                */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								static void updateParity (DdNode *node, ApproxInfo *info, int newparity);
							 | 
						|
								static NodeData * gatherInfoAux (DdNode *node, ApproxInfo *info, int parity);
							 | 
						|
								static ApproxInfo * gatherInfo (DdManager *dd, DdNode *node, int numVars, int parity);
							 | 
						|
								static int computeSavings (DdManager *dd, DdNode *f, DdNode *skip, ApproxInfo *info, DdLevelQueue *queue);
							 | 
						|
								static int updateRefs (DdManager *dd, DdNode *f, DdNode *skip, ApproxInfo *info, DdLevelQueue *queue);
							 | 
						|
								static int UAmarkNodes (DdManager *dd, DdNode *f, ApproxInfo *info, int threshold, int safe, double quality);
							 | 
						|
								static DdNode * UAbuildSubset (DdManager *dd, DdNode *node, ApproxInfo *info);
							 | 
						|
								static int RAmarkNodes (DdManager *dd, DdNode *f, ApproxInfo *info, int threshold, double quality);
							 | 
						|
								static int BAmarkNodes (DdManager *dd, DdNode *f, ApproxInfo *info, int threshold, double quality1, double quality0);
							 | 
						|
								static DdNode * RAbuildSubset (DdManager *dd, DdNode *node, ApproxInfo *info);
							 | 
						|
								static int BAapplyBias (DdManager *dd, DdNode *f, DdNode *b, ApproxInfo *info, DdHashTable *cache);
							 | 
						|
								
							 | 
						|
								/** \endcond */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Definition of exported functions                                          */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								  @brief Extracts a dense subset from a %BDD with Shiple's
							 | 
						|
								  underapproximation method.
							 | 
						|
								
							 | 
						|
								  @details This procedure uses a variant of Tom Shiple's
							 | 
						|
								  underapproximation method. The main difference from the original
							 | 
						|
								  method is that density is used as cost function.  The parameter
							 | 
						|
								  numVars is the maximum number of variables to be used in minterm
							 | 
						|
								  calculation.  The optimal number should be as close as possible to
							 | 
						|
								  the size of the support of f.  However, it is safe to pass the value
							 | 
						|
								  returned by Cudd_ReadSize for numVars when the number of variables
							 | 
						|
								  is under 1023.  If numVars is larger than 1023, it will cause
							 | 
						|
								  overflow. If a 0 parameter is passed then the procedure will compute
							 | 
						|
								  a value which will avoid overflow but will cause underflow with 2046
							 | 
						|
								  variables or more.
							 | 
						|
								
							 | 
						|
								  @return a pointer to the %BDD of the subset if successful; NULL if
							 | 
						|
								  the procedure runs out of memory.
							 | 
						|
								
							 | 
						|
								  @sideeffect None
							 | 
						|
								
							 | 
						|
								  @see Cudd_SubsetShortPaths Cudd_SubsetHeavyBranch Cudd_ReadSize
							 | 
						|
								
							 | 
						|
								*/
							 | 
						|
								DdNode *
							 | 
						|
								Cudd_UnderApprox(
							 | 
						|
								  DdManager * dd /**< manager */,
							 | 
						|
								  DdNode * f /**< function to be subset */,
							 | 
						|
								  int  numVars /**< number of variables in the support of f */,
							 | 
						|
								  int  threshold /**< when to stop approximation */,
							 | 
						|
								  int  safe /**< enforce safe approximation */,
							 | 
						|
								  double  quality /**< minimum improvement for accepted changes */)
							 | 
						|
								{
							 | 
						|
								    DdNode *subset;
							 | 
						|
								
							 | 
						|
								    do {
							 | 
						|
									dd->reordered = 0;
							 | 
						|
									subset = cuddUnderApprox(dd, f, numVars, threshold, safe, quality);
							 | 
						|
								    } while (dd->reordered == 1);
							 | 
						|
								    if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
							 | 
						|
								        dd->timeoutHandler(dd, dd->tohArg);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    return(subset);
							 | 
						|
								
							 | 
						|
								} /* end of Cudd_UnderApprox */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								  @brief Extracts a dense superset from a %BDD with Shiple's
							 | 
						|
								  underapproximation method.
							 | 
						|
								
							 | 
						|
								  @details The procedure is identical to the underapproximation
							 | 
						|
								  procedure except for the fact that it works on the complement of the
							 | 
						|
								  given function. Extracting the subset of the complement function is
							 | 
						|
								  equivalent to extracting the superset of the function.  The
							 | 
						|
								  parameter numVars is the maximum number of variables to be used in
							 | 
						|
								  minterm calculation.  The optimal number should be as close as
							 | 
						|
								  possible to the size of the support of f.  However, it is safe to
							 | 
						|
								  pass the value returned by Cudd_ReadSize for numVars when the number
							 | 
						|
								  of variables is under 1023.  If numVars is larger than 1023, it will
							 | 
						|
								  overflow. If a 0 parameter is passed then the procedure will compute
							 | 
						|
								  a value which will avoid overflow but will cause underflow with 2046
							 | 
						|
								  variables or more.
							 | 
						|
								  
							 | 
						|
								  @return a pointer to the %BDD of the superset if successful. NULL if
							 | 
						|
								  intermediate result causes the procedure to run out of memory.
							 | 
						|
								
							 | 
						|
								  @sideeffect None
							 | 
						|
								
							 | 
						|
								  @see Cudd_SupersetHeavyBranch Cudd_SupersetShortPaths Cudd_ReadSize
							 | 
						|
								
							 | 
						|
								*/
							 | 
						|
								DdNode *
							 | 
						|
								Cudd_OverApprox(
							 | 
						|
								  DdManager * dd /**< manager */,
							 | 
						|
								  DdNode * f /**< function to be superset */,
							 | 
						|
								  int  numVars /**< number of variables in the support of f */,
							 | 
						|
								  int  threshold /**< when to stop approximation */,
							 | 
						|
								  int  safe /**< enforce safe approximation */,
							 | 
						|
								  double  quality /**< minimum improvement for accepted changes */)
							 | 
						|
								{
							 | 
						|
								    DdNode *subset, *g;
							 | 
						|
								
							 | 
						|
								    g = Cudd_Not(f);    
							 | 
						|
								    do {
							 | 
						|
									dd->reordered = 0;
							 | 
						|
									subset = cuddUnderApprox(dd, g, numVars, threshold, safe, quality);
							 | 
						|
								    } while (dd->reordered == 1);
							 | 
						|
								    if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
							 | 
						|
								        dd->timeoutHandler(dd, dd->tohArg);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    return(Cudd_NotCond(subset, (subset != NULL)));
							 | 
						|
								    
							 | 
						|
								} /* end of Cudd_OverApprox */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								  @brief Extracts a dense subset from a %BDD with the remapping
							 | 
						|
								  underapproximation method.
							 | 
						|
								
							 | 
						|
								  @details This procedure uses a remapping technique and density as
							 | 
						|
								  the cost function.  The parameter numVars is the maximum number of
							 | 
						|
								  variables to be used in minterm calculation.  The optimal number
							 | 
						|
								  should be as close as possible to the size of the support of f.
							 | 
						|
								  However, it is safe to pass the value returned by Cudd_ReadSize for
							 | 
						|
								  numVars when the number of variables is under 1023.  If numVars is
							 | 
						|
								  larger than 1023, it will cause overflow. If a 0 parameter is passed
							 | 
						|
								  then the procedure will compute a value which will avoid overflow
							 | 
						|
								  but will cause underflow with 2046 variables or more.
							 | 
						|
								
							 | 
						|
								  @return a pointer to the %BDD of the subset if successful. NULL if
							 | 
						|
								  the procedure runs out of memory.
							 | 
						|
								  
							 | 
						|
								  @sideeffect None
							 | 
						|
								
							 | 
						|
								  @see Cudd_SubsetShortPaths Cudd_SubsetHeavyBranch Cudd_UnderApprox Cudd_ReadSize
							 | 
						|
								
							 | 
						|
								*/
							 | 
						|
								DdNode *
							 | 
						|
								Cudd_RemapUnderApprox(
							 | 
						|
								  DdManager * dd /**< manager */,
							 | 
						|
								  DdNode * f /**< function to be subset */,
							 | 
						|
								  int  numVars /**< number of variables in the support of f */,
							 | 
						|
								  int  threshold /**< when to stop approximation */,
							 | 
						|
								  double  quality /**< minimum improvement for accepted changes */)
							 | 
						|
								{
							 | 
						|
								    DdNode *subset;
							 | 
						|
								
							 | 
						|
								    do {
							 | 
						|
									dd->reordered = 0;
							 | 
						|
									subset = cuddRemapUnderApprox(dd, f, numVars, threshold, quality);
							 | 
						|
								    } while (dd->reordered == 1);
							 | 
						|
								    if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
							 | 
						|
								        dd->timeoutHandler(dd, dd->tohArg);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    return(subset);
							 | 
						|
								
							 | 
						|
								} /* end of Cudd_RemapUnderApprox */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								  @brief Extracts a dense superset from a %BDD with the remapping
							 | 
						|
								  underapproximation method.
							 | 
						|
								
							 | 
						|
								  @details The procedure is identical to the underapproximation
							 | 
						|
								  procedure except for the fact that it works on the complement of the
							 | 
						|
								  given function. Extracting the subset of the complement function is
							 | 
						|
								  equivalent to extracting the superset of the function. The parameter
							 | 
						|
								  numVars is the maximum number of variables to be used in minterm
							 | 
						|
								  calculation.  The optimal number should be as close as possible to
							 | 
						|
								  the size of the support of f.  However, it is safe to pass the value
							 | 
						|
								  returned by Cudd_ReadSize for numVars when the number of variables
							 | 
						|
								  is under 1023.  If numVars is larger than 1023, it will overflow. If
							 | 
						|
								  a 0 parameter is passed then the procedure will compute a value
							 | 
						|
								  which will avoid overflow but will cause underflow with 2046
							 | 
						|
								  variables or more.
							 | 
						|
								
							 | 
						|
								  @return a pointer to the %BDD of the superset if successful. NULL if
							 | 
						|
								  intermediate result causes the procedure to run out of memory.
							 | 
						|
								  
							 | 
						|
								  @sideeffect None
							 | 
						|
								
							 | 
						|
								  @see Cudd_SupersetHeavyBranch Cudd_SupersetShortPaths Cudd_ReadSize
							 | 
						|
								
							 | 
						|
								*/
							 | 
						|
								DdNode *
							 | 
						|
								Cudd_RemapOverApprox(
							 | 
						|
								  DdManager * dd /**< manager */,
							 | 
						|
								  DdNode * f /**< function to be superset */,
							 | 
						|
								  int  numVars /**< number of variables in the support of f */,
							 | 
						|
								  int  threshold /**< when to stop approximation */,
							 | 
						|
								  double  quality /**< minimum improvement for accepted changes */)
							 | 
						|
								{
							 | 
						|
								    DdNode *subset, *g;
							 | 
						|
								
							 | 
						|
								    g = Cudd_Not(f);    
							 | 
						|
								    do {
							 | 
						|
									dd->reordered = 0;
							 | 
						|
									subset = cuddRemapUnderApprox(dd, g, numVars, threshold, quality);
							 | 
						|
								    } while (dd->reordered == 1);
							 | 
						|
								    if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
							 | 
						|
								        dd->timeoutHandler(dd, dd->tohArg);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    return(Cudd_NotCond(subset, (subset != NULL)));
							 | 
						|
								    
							 | 
						|
								} /* end of Cudd_RemapOverApprox */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								  @brief Extracts a dense subset from a %BDD with the biased
							 | 
						|
								  underapproximation method.
							 | 
						|
								
							 | 
						|
								  @details This procedure uses a biased remapping technique and
							 | 
						|
								  density as the cost function. The bias is a function. This procedure
							 | 
						|
								  tries to approximate where the bias is 0 and preserve the given
							 | 
						|
								  function where the bias is 1.  The parameter numVars is the maximum
							 | 
						|
								  number of variables to be used in minterm calculation.  The optimal
							 | 
						|
								  number should be as close as possible to the size of the support of
							 | 
						|
								  f.  However, it is safe to pass the value returned by Cudd_ReadSize
							 | 
						|
								  for numVars when the number of variables is under 1023.  If numVars
							 | 
						|
								  is larger than 1023, it will cause overflow. If a 0 parameter is
							 | 
						|
								  passed then the procedure will compute a value which will avoid
							 | 
						|
								  overflow but will cause underflow with 2046 variables or more.
							 | 
						|
								
							 | 
						|
								  @return a pointer to the %BDD of the subset if successful. NULL if
							 | 
						|
								  the procedure runs out of memory.
							 | 
						|
								  
							 | 
						|
								  @sideeffect None
							 | 
						|
								
							 | 
						|
								  @see Cudd_SubsetShortPaths Cudd_SubsetHeavyBranch Cudd_UnderApprox
							 | 
						|
								  Cudd_RemapUnderApprox Cudd_ReadSize
							 | 
						|
								
							 | 
						|
								*/
							 | 
						|
								DdNode *
							 | 
						|
								Cudd_BiasedUnderApprox(
							 | 
						|
								  DdManager *dd /**< manager */,
							 | 
						|
								  DdNode *f /**< function to be subset */,
							 | 
						|
								  DdNode *b /**< bias function */,
							 | 
						|
								  int numVars /**< number of variables in the support of f */,
							 | 
						|
								  int threshold /**< when to stop approximation */,
							 | 
						|
								  double quality1 /**< minimum improvement for accepted changes when b=1 */,
							 | 
						|
								  double quality0 /**< minimum improvement for accepted changes when b=0 */)
							 | 
						|
								{
							 | 
						|
								    DdNode *subset;
							 | 
						|
								
							 | 
						|
								    do {
							 | 
						|
									dd->reordered = 0;
							 | 
						|
									subset = cuddBiasedUnderApprox(dd, f, b, numVars, threshold, quality1,
							 | 
						|
												       quality0);
							 | 
						|
								    } while (dd->reordered == 1);
							 | 
						|
								    if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
							 | 
						|
								        dd->timeoutHandler(dd, dd->tohArg);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    return(subset);
							 | 
						|
								
							 | 
						|
								} /* end of Cudd_BiasedUnderApprox */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								  @brief Extracts a dense superset from a %BDD with the biased
							 | 
						|
								  underapproximation method.
							 | 
						|
								
							 | 
						|
								  @details The procedure is identical to the underapproximation
							 | 
						|
								  procedure except for the fact that it works on the complement of the
							 | 
						|
								  given function. Extracting the subset of the complement function is
							 | 
						|
								  equivalent to extracting the superset of the function.  The
							 | 
						|
								  parameter numVars is the maximum number of variables to be used in
							 | 
						|
								  minterm calculation.  The optimal number should be as close as
							 | 
						|
								  possible to the size of the support of f.  However, it is safe to
							 | 
						|
								  pass the value returned by Cudd_ReadSize for numVars when the number
							 | 
						|
								  of variables is under 1023.  If numVars is larger than 1023, it will
							 | 
						|
								  overflow. If a 0 parameter is passed then the procedure will compute
							 | 
						|
								  a value which will avoid overflow but will cause underflow with 2046
							 | 
						|
								  variables or more.
							 | 
						|
								
							 | 
						|
								  @return a pointer to the %BDD of the superset if successful. NULL if
							 | 
						|
								  intermediate result causes the procedure to run out of memory.
							 | 
						|
								  
							 | 
						|
								  @sideeffect None
							 | 
						|
								
							 | 
						|
								  @see Cudd_SupersetHeavyBranch Cudd_SupersetShortPaths
							 | 
						|
								  Cudd_RemapOverApprox Cudd_BiasedUnderApprox Cudd_ReadSize
							 | 
						|
								
							 | 
						|
								*/
							 | 
						|
								DdNode *
							 | 
						|
								Cudd_BiasedOverApprox(
							 | 
						|
								  DdManager *dd /**< manager */,
							 | 
						|
								  DdNode *f /**< function to be superset */,
							 | 
						|
								  DdNode *b /**< bias function */,
							 | 
						|
								  int numVars /**< number of variables in the support of f */,
							 | 
						|
								  int threshold /**< when to stop approximation */,
							 | 
						|
								  double quality1 /**< minimum improvement for accepted changes when b=1*/,
							 | 
						|
								  double quality0 /**< minimum improvement for accepted changes when b=0 */)
							 | 
						|
								{
							 | 
						|
								    DdNode *subset, *g;
							 | 
						|
								
							 | 
						|
								    g = Cudd_Not(f);    
							 | 
						|
								    do {
							 | 
						|
									dd->reordered = 0;
							 | 
						|
									subset = cuddBiasedUnderApprox(dd, g, b, numVars, threshold, quality1,
							 | 
						|
												      quality0);
							 | 
						|
								    } while (dd->reordered == 1);
							 | 
						|
								    if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
							 | 
						|
								        dd->timeoutHandler(dd, dd->tohArg);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    return(Cudd_NotCond(subset, (subset != NULL)));
							 | 
						|
								    
							 | 
						|
								} /* end of Cudd_BiasedOverApprox */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Definition of internal functions                                          */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								  @brief Applies Tom Shiple's underappoximation algorithm.
							 | 
						|
								
							 | 
						|
								  @details Proceeds in three phases:
							 | 
						|
								  <ul>
							 | 
						|
								  <li> collect information on each node in the %BDD; this is done via DFS.
							 | 
						|
								  <li> traverse the %BDD in top-down fashion and compute for each node
							 | 
						|
								  whether its elimination increases density.
							 | 
						|
								  <li> traverse the %BDD via DFS and actually perform the elimination.
							 | 
						|
								  </ul>
							 | 
						|
								
							 | 
						|
								  @return the approximated %BDD if successful; NULL otherwise.
							 | 
						|
								
							 | 
						|
								  @sideeffect None
							 | 
						|
								
							 | 
						|
								  @see Cudd_UnderApprox
							 | 
						|
								
							 | 
						|
								*/
							 | 
						|
								DdNode *
							 | 
						|
								cuddUnderApprox(
							 | 
						|
								  DdManager * dd /**< %DD manager */,
							 | 
						|
								  DdNode * f /**< current %DD */,
							 | 
						|
								  int  numVars /**< maximum number of variables */,
							 | 
						|
								  int  threshold /**< threshold under which approximation stops */,
							 | 
						|
								  int  safe /**< enforce safe approximation */,
							 | 
						|
								  double  quality /**< minimum improvement for accepted changes */)
							 | 
						|
								{
							 | 
						|
								    ApproxInfo *info;
							 | 
						|
								    DdNode *subset;
							 | 
						|
								    int result;
							 | 
						|
								
							 | 
						|
								    if (f == NULL) {
							 | 
						|
									fprintf(dd->err, "Cannot subset, nil object\n");
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    if (Cudd_IsConstantInt(f)) {
							 | 
						|
									return(f);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /* Create table where node data are accessible via a hash table. */
							 | 
						|
								    info = gatherInfo(dd, f, numVars, safe);
							 | 
						|
								    if (info == NULL) {
							 | 
						|
									(void) fprintf(dd->err, "Out-of-memory; Cannot subset\n");
							 | 
						|
									dd->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /* Mark nodes that should be replaced by zero. */
							 | 
						|
								    result = UAmarkNodes(dd, f, info, threshold, safe, quality);
							 | 
						|
								    if (result == 0) {
							 | 
						|
									(void) fprintf(dd->err, "Out-of-memory; Cannot subset\n");
							 | 
						|
									FREE(info->page);
							 | 
						|
									cuddHashTableGenericQuit(info->table);
							 | 
						|
									FREE(info);
							 | 
						|
									dd->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /* Build the result. */
							 | 
						|
								    subset = UAbuildSubset(dd, f, info);
							 | 
						|
								#if 1
							 | 
						|
								    if (subset && info->size < Cudd_DagSize(subset))
							 | 
						|
									(void) fprintf(dd->err, "Wrong prediction: %d versus actual %d\n",
							 | 
						|
										       info->size, Cudd_DagSize(subset));
							 | 
						|
								#endif
							 | 
						|
								    FREE(info->page);
							 | 
						|
								    cuddHashTableGenericQuit(info->table);
							 | 
						|
								    FREE(info);
							 | 
						|
								
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
								    if (subset != NULL) {
							 | 
						|
									cuddRef(subset);
							 | 
						|
								#if 0
							 | 
						|
									(void) Cudd_DebugCheck(dd);
							 | 
						|
									(void) Cudd_CheckKeys(dd);
							 | 
						|
								#endif
							 | 
						|
									if (!Cudd_bddLeq(dd, subset, f)) {
							 | 
						|
									    (void) fprintf(dd->err, "Wrong subset\n");
							 | 
						|
									    dd->errorCode = CUDD_INTERNAL_ERROR;
							 | 
						|
									}
							 | 
						|
									cuddDeref(subset);
							 | 
						|
								    }
							 | 
						|
								#endif
							 | 
						|
								    return(subset);
							 | 
						|
								
							 | 
						|
								} /* end of cuddUnderApprox */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								  @brief Applies the remapping underappoximation algorithm.
							 | 
						|
								
							 | 
						|
								  @details Proceeds in three phases:
							 | 
						|
								  <ul>
							 | 
						|
								  <li> collect information on each node in the %BDD; this is done via DFS.
							 | 
						|
								  <li> traverse the %BDD in top-down fashion and compute for each node
							 | 
						|
								  whether remapping increases density.
							 | 
						|
								  <li> traverse the %BDD via DFS and actually perform the elimination.
							 | 
						|
								  </ul>
							 | 
						|
								
							 | 
						|
								  @return the approximated %BDD if successful; NULL otherwise.
							 | 
						|
								
							 | 
						|
								  @sideeffect None
							 | 
						|
								
							 | 
						|
								  @see Cudd_RemapUnderApprox
							 | 
						|
								
							 | 
						|
								*/
							 | 
						|
								DdNode *
							 | 
						|
								cuddRemapUnderApprox(
							 | 
						|
								  DdManager * dd /**< %DD manager */,
							 | 
						|
								  DdNode * f /**< current %DD */,
							 | 
						|
								  int  numVars /**< maximum number of variables */,
							 | 
						|
								  int  threshold /**< threshold under which approximation stops */,
							 | 
						|
								  double  quality /**< minimum improvement for accepted changes */)
							 | 
						|
								{
							 | 
						|
								    ApproxInfo *info;
							 | 
						|
								    DdNode *subset;
							 | 
						|
								    int result;
							 | 
						|
								
							 | 
						|
								    if (f == NULL) {
							 | 
						|
									fprintf(dd->err, "Cannot subset, nil object\n");
							 | 
						|
									dd->errorCode = CUDD_INVALID_ARG;
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    if (Cudd_IsConstantInt(f)) {
							 | 
						|
									return(f);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /* Create table where node data are accessible via a hash table. */
							 | 
						|
								    info = gatherInfo(dd, f, numVars, CUDD_TRUE);
							 | 
						|
								    if (info == NULL) {
							 | 
						|
									(void) fprintf(dd->err, "Out-of-memory; Cannot subset\n");
							 | 
						|
									dd->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /* Mark nodes that should be replaced by zero. */
							 | 
						|
								    result = RAmarkNodes(dd, f, info, threshold, quality);
							 | 
						|
								    if (result == 0) {
							 | 
						|
									(void) fprintf(dd->err, "Out-of-memory; Cannot subset\n");
							 | 
						|
									FREE(info->page);
							 | 
						|
									cuddHashTableGenericQuit(info->table);
							 | 
						|
									FREE(info);
							 | 
						|
									dd->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /* Build the result. */
							 | 
						|
								    subset = RAbuildSubset(dd, f, info);
							 | 
						|
								#if 1
							 | 
						|
								    if (subset && info->size < Cudd_DagSize(subset))
							 | 
						|
									(void) fprintf(dd->err, "Wrong prediction: %d versus actual %d\n",
							 | 
						|
										       info->size, Cudd_DagSize(subset));
							 | 
						|
								#endif
							 | 
						|
								    FREE(info->page);
							 | 
						|
								    cuddHashTableGenericQuit(info->table);
							 | 
						|
								    FREE(info);
							 | 
						|
								
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
								    if (subset != NULL) {
							 | 
						|
									cuddRef(subset);
							 | 
						|
								#if 0
							 | 
						|
									(void) Cudd_DebugCheck(dd);
							 | 
						|
									(void) Cudd_CheckKeys(dd);
							 | 
						|
								#endif
							 | 
						|
									if (!Cudd_bddLeq(dd, subset, f)) {
							 | 
						|
									    (void) fprintf(dd->err, "Wrong subset\n");
							 | 
						|
									}
							 | 
						|
									cuddDeref(subset);
							 | 
						|
									dd->errorCode = CUDD_INTERNAL_ERROR;
							 | 
						|
								    }
							 | 
						|
								#endif
							 | 
						|
								    return(subset);
							 | 
						|
								
							 | 
						|
								} /* end of cuddRemapUnderApprox */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								  @brief Applies the biased remapping underappoximation algorithm.
							 | 
						|
								
							 | 
						|
								  @details Proceeds in three phases:
							 | 
						|
								  <ul>
							 | 
						|
								  <li> collect information on each node in the %BDD; this is done via DFS.
							 | 
						|
								  <li> traverse the %BDD in top-down fashion and compute for each node
							 | 
						|
								  whether remapping increases density.
							 | 
						|
								  <li> traverse the %BDD via DFS and actually perform the elimination.
							 | 
						|
								  </ul>
							 | 
						|
								
							 | 
						|
								  @return the approximated %BDD if successful; NULL otherwise.
							 | 
						|
								
							 | 
						|
								  @sideeffect None
							 | 
						|
								
							 | 
						|
								  @see Cudd_BiasedUnderApprox
							 | 
						|
								
							 | 
						|
								*/
							 | 
						|
								DdNode *
							 | 
						|
								cuddBiasedUnderApprox(
							 | 
						|
								  DdManager *dd /**< %DD manager */,
							 | 
						|
								  DdNode *f /**< current %DD */,
							 | 
						|
								  DdNode *b /**< bias function */,
							 | 
						|
								  int numVars /**< maximum number of variables */,
							 | 
						|
								  int threshold /**< threshold under which approximation stops */,
							 | 
						|
								  double quality1 /**< minimum improvement for accepted changes when b=1 */,
							 | 
						|
								  double quality0 /**< minimum improvement for accepted changes when b=0 */)
							 | 
						|
								{
							 | 
						|
								    ApproxInfo *info;
							 | 
						|
								    DdNode *subset;
							 | 
						|
								    int result;
							 | 
						|
								    DdHashTable	*cache;
							 | 
						|
								
							 | 
						|
								    if (f == NULL) {
							 | 
						|
									fprintf(dd->err, "Cannot subset, nil object\n");
							 | 
						|
									dd->errorCode = CUDD_INVALID_ARG;
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    if (Cudd_IsConstantInt(f)) {
							 | 
						|
									return(f);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /* Create table where node data are accessible via a hash table. */
							 | 
						|
								    info = gatherInfo(dd, f, numVars, CUDD_TRUE);
							 | 
						|
								    if (info == NULL) {
							 | 
						|
									(void) fprintf(dd->err, "Out-of-memory; Cannot subset\n");
							 | 
						|
									dd->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    cache = cuddHashTableInit(dd,2,2);
							 | 
						|
								    result = BAapplyBias(dd, Cudd_Regular(f), b, info, cache);
							 | 
						|
								    if (result == CARE_ERROR) {
							 | 
						|
									(void) fprintf(dd->err, "Out-of-memory; Cannot subset\n");
							 | 
						|
									cuddHashTableQuit(cache);
							 | 
						|
									FREE(info->page);
							 | 
						|
									cuddHashTableGenericQuit(info->table);
							 | 
						|
									FREE(info);
							 | 
						|
									dd->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								    cuddHashTableQuit(cache);
							 | 
						|
								
							 | 
						|
								    /* Mark nodes that should be replaced by zero. */
							 | 
						|
								    result = BAmarkNodes(dd, f, info, threshold, quality1, quality0);
							 | 
						|
								    if (result == 0) {
							 | 
						|
									(void) fprintf(dd->err, "Out-of-memory; Cannot subset\n");
							 | 
						|
									FREE(info->page);
							 | 
						|
									cuddHashTableGenericQuit(info->table);
							 | 
						|
									FREE(info);
							 | 
						|
									dd->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /* Build the result. */
							 | 
						|
								    subset = RAbuildSubset(dd, f, info);
							 | 
						|
								#if 1
							 | 
						|
								    if (subset && info->size < Cudd_DagSize(subset))
							 | 
						|
									(void) fprintf(dd->err, "Wrong prediction: %d versus actual %d\n",
							 | 
						|
										       info->size, Cudd_DagSize(subset));
							 | 
						|
								#endif
							 | 
						|
								    FREE(info->page);
							 | 
						|
								    cuddHashTableGenericQuit(info->table);
							 | 
						|
								    FREE(info);
							 | 
						|
								
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
								    if (subset != NULL) {
							 | 
						|
									cuddRef(subset);
							 | 
						|
								#if 0
							 | 
						|
									(void) Cudd_DebugCheck(dd);
							 | 
						|
									(void) Cudd_CheckKeys(dd);
							 | 
						|
								#endif
							 | 
						|
									if (!Cudd_bddLeq(dd, subset, f)) {
							 | 
						|
									    (void) fprintf(dd->err, "Wrong subset\n");
							 | 
						|
									}
							 | 
						|
									cuddDeref(subset);
							 | 
						|
									dd->errorCode = CUDD_INTERNAL_ERROR;
							 | 
						|
								    }
							 | 
						|
								#endif
							 | 
						|
								    return(subset);
							 | 
						|
								
							 | 
						|
								} /* end of cuddBiasedUnderApprox */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Definition of static functions                                            */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								  @brief Recursively update the parity of the paths reaching a node.
							 | 
						|
								
							 | 
						|
								  @details Assumes that node is regular and propagates the invariant.
							 | 
						|
								
							 | 
						|
								  @sideeffect None
							 | 
						|
								
							 | 
						|
								  @see gatherInfoAux
							 | 
						|
								
							 | 
						|
								*/
							 | 
						|
								static void
							 | 
						|
								updateParity(
							 | 
						|
								  DdNode * node /**< function to analyze */,
							 | 
						|
								  ApproxInfo * info /**< info on %BDD */,
							 | 
						|
								  int newparity /**< new parity for node */)
							 | 
						|
								{
							 | 
						|
								    NodeData *infoN;
							 | 
						|
								    DdNode *E;
							 | 
						|
								
							 | 
						|
								    if ((infoN = (NodeData *) cuddHashTableGenericLookup(info->table, node)) == NULL)
							 | 
						|
								        return;
							 | 
						|
								    if ((infoN->parity & newparity) != 0) return;
							 | 
						|
								    infoN->parity |= (short) newparity;
							 | 
						|
								    if (Cudd_IsConstantInt(node)) return;
							 | 
						|
								    updateParity(cuddT(node),info,newparity);
							 | 
						|
								    E = cuddE(node);
							 | 
						|
								    if (Cudd_IsComplement(E)) {
							 | 
						|
									updateParity(Cudd_Not(E),info,3-newparity);
							 | 
						|
								    } else {
							 | 
						|
									updateParity(E,info,newparity);
							 | 
						|
								    }
							 | 
						|
								    return;
							 | 
						|
								
							 | 
						|
								} /* end of updateParity */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								  @brief Recursively counts minterms and computes reference counts
							 | 
						|
								  of each node in the %BDD.
							 | 
						|
								
							 | 
						|
								  @details Similar to the cuddCountMintermAux which recursively counts
							 | 
						|
								  the number of minterms for the dag rooted at each node in terms of
							 | 
						|
								  the total number of variables (max). It assumes that the node
							 | 
						|
								  pointer passed to it is regular and it maintains the invariant.
							 | 
						|
								
							 | 
						|
								  @sideeffect None
							 | 
						|
								
							 | 
						|
								  @see gatherInfo
							 | 
						|
								
							 | 
						|
								*/
							 | 
						|
								static NodeData *
							 | 
						|
								gatherInfoAux(
							 | 
						|
								  DdNode * node /**< function to analyze */,
							 | 
						|
								  ApproxInfo * info /**< info on %BDD */,
							 | 
						|
								  int parity /**< gather parity information */)
							 | 
						|
								{
							 | 
						|
								    DdNode	*N, *Nt, *Ne;
							 | 
						|
								    NodeData	*infoN, *infoT, *infoE;
							 | 
						|
								
							 | 
						|
								    N = Cudd_Regular(node);
							 | 
						|
								
							 | 
						|
								    /* Check whether entry for this node exists. */
							 | 
						|
								    if ((infoN = (NodeData *) cuddHashTableGenericLookup(info->table, N)) != NULL) {
							 | 
						|
									if (parity) {
							 | 
						|
									    /* Update parity and propagate. */
							 | 
						|
									    updateParity(N, info, 1 +  (int) Cudd_IsComplement(node));
							 | 
						|
									}
							 | 
						|
									return(infoN);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /* Compute the cofactors. */
							 | 
						|
								    Nt = Cudd_NotCond(cuddT(N), N != node);
							 | 
						|
								    Ne = Cudd_NotCond(cuddE(N), N != node);
							 | 
						|
								
							 | 
						|
								    infoT = gatherInfoAux(Nt, info, parity);
							 | 
						|
								    if (infoT == NULL) return(NULL);
							 | 
						|
								    infoE = gatherInfoAux(Ne, info, parity);
							 | 
						|
								    if (infoE == NULL) return(NULL);
							 | 
						|
								
							 | 
						|
								    infoT->functionRef++;
							 | 
						|
								    infoE->functionRef++;
							 | 
						|
								
							 | 
						|
								    /* Point to the correct location in the page. */
							 | 
						|
								    infoN = &(info->page[info->index++]);
							 | 
						|
								    infoN->parity |= (short) (1 + Cudd_IsComplement(node));
							 | 
						|
								
							 | 
						|
								    infoN->mintermsP = infoT->mintermsP/2;
							 | 
						|
								    infoN->mintermsN = infoT->mintermsN/2;
							 | 
						|
								    if (Cudd_IsComplement(Ne) ^ Cudd_IsComplement(node)) {
							 | 
						|
									infoN->mintermsP += infoE->mintermsN/2;
							 | 
						|
									infoN->mintermsN += infoE->mintermsP/2;
							 | 
						|
								    } else {
							 | 
						|
									infoN->mintermsP += infoE->mintermsP/2;
							 | 
						|
									infoN->mintermsN += infoE->mintermsN/2;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /* Insert entry for the node in the table. */
							 | 
						|
								    if (cuddHashTableGenericInsert(info->table, N, infoN) == 0) {
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								    return(infoN);
							 | 
						|
								
							 | 
						|
								} /* end of gatherInfoAux */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								  @brief Gathers information about each node.
							 | 
						|
								
							 | 
						|
								  @details Counts minterms and computes reference counts of each
							 | 
						|
								  node in the %BDD. The minterm count is separately computed for the
							 | 
						|
								  node and its complement. This is to avoid cancellation
							 | 
						|
								  errors.
							 | 
						|
								
							 | 
						|
								  @return a pointer to the data structure holding the information
							 | 
						|
								  gathered if successful; NULL otherwise.
							 | 
						|
								
							 | 
						|
								  @sideeffect None
							 | 
						|
								
							 | 
						|
								  @see cuddUnderApprox gatherInfoAux
							 | 
						|
								
							 | 
						|
								*/
							 | 
						|
								static ApproxInfo *
							 | 
						|
								gatherInfo(
							 | 
						|
								  DdManager * dd /* manager */,
							 | 
						|
								  DdNode * node /* function to be analyzed */,
							 | 
						|
								  int numVars /* number of variables node depends on */,
							 | 
						|
								  int parity /* gather parity information */)
							 | 
						|
								{
							 | 
						|
								    ApproxInfo * info;
							 | 
						|
								    NodeData * infoTop;
							 | 
						|
								
							 | 
						|
								    /* If user did not give numVars value, set it to the maximum
							 | 
						|
								    ** exponent that the pow function can take. The -1 is due to the
							 | 
						|
								    ** discrepancy in the value that pow takes and the value that
							 | 
						|
								    ** log gives.
							 | 
						|
								    */
							 | 
						|
								    if (numVars == 0) {
							 | 
						|
									numVars = DBL_MAX_EXP - 1;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    info = ALLOC(ApproxInfo,1);
							 | 
						|
								    if (info == NULL) {
							 | 
						|
									dd->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								    info->max = pow(2.0,(double) numVars);
							 | 
						|
								    info->one = DD_ONE(dd);
							 | 
						|
								    info->zero = Cudd_Not(info->one);
							 | 
						|
								    info->size = Cudd_DagSize(node);
							 | 
						|
								    /* All the information gathered will be stored in a contiguous
							 | 
						|
								    ** piece of memory, which is allocated here. This can be done
							 | 
						|
								    ** efficiently because we have counted the number of nodes of the
							 | 
						|
								    ** BDD. info->index points to the next available entry in the array
							 | 
						|
								    ** that stores the per-node information. */
							 | 
						|
								    info->page = ALLOC(NodeData,info->size);
							 | 
						|
								    if (info->page == NULL) {
							 | 
						|
									dd->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
									FREE(info);
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								    memset(info->page, 0, info->size * sizeof(NodeData)); /* clear all page */
							 | 
						|
								    info->table = cuddHashTableInit(dd,1,info->size);
							 | 
						|
								    if (info->table == NULL) {
							 | 
						|
									FREE(info->page);
							 | 
						|
									FREE(info);
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								    /* We visit the DAG in post-order DFS. Hence, the constant node is
							 | 
						|
								    ** in first position, and the root of the DAG is in last position. */
							 | 
						|
								
							 | 
						|
								    /* Info for the constant node: Initialize only fields different from 0. */
							 | 
						|
								    if (cuddHashTableGenericInsert(info->table, info->one, info->page) == 0) {
							 | 
						|
									FREE(info->page);
							 | 
						|
									cuddHashTableGenericQuit(info->table);
							 | 
						|
									FREE(info);
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								    info->page[0].mintermsP = info->max;
							 | 
						|
								    info->index = 1;
							 | 
						|
								
							 | 
						|
								    infoTop = gatherInfoAux(node,info,parity);
							 | 
						|
								    if (infoTop == NULL) {
							 | 
						|
									FREE(info->page);
							 | 
						|
									cuddHashTableGenericQuit(info->table);
							 | 
						|
									FREE(info);
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								    if (Cudd_IsComplement(node)) {
							 | 
						|
									info->minterms = infoTop->mintermsN;
							 | 
						|
								    } else {
							 | 
						|
									info->minterms = infoTop->mintermsP;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    infoTop->functionRef = 1;
							 | 
						|
								    return(info);
							 | 
						|
								
							 | 
						|
								} /* end of gatherInfo */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								  @brief Counts the nodes that would be eliminated if a given node
							 | 
						|
								  were replaced by zero.
							 | 
						|
								
							 | 
						|
								  @details This procedure uses a queue passed by the caller for
							 | 
						|
								  efficiency: since the queue is left empty at the endof the search,
							 | 
						|
								  it can be reused as is by the next search.
							 | 
						|
								
							 | 
						|
								  @return the count (always striclty positive) if successful; 0
							 | 
						|
								  otherwise.
							 | 
						|
								
							 | 
						|
								  @sideeffect None
							 | 
						|
								
							 | 
						|
								  @see UAmarkNodes RAmarkNodes BAmarkNodes
							 | 
						|
								
							 | 
						|
								*/
							 | 
						|
								static int
							 | 
						|
								computeSavings(
							 | 
						|
								  DdManager * dd,
							 | 
						|
								  DdNode * f,
							 | 
						|
								  DdNode * skip,
							 | 
						|
								  ApproxInfo * info,
							 | 
						|
								  DdLevelQueue * queue)
							 | 
						|
								{
							 | 
						|
								    NodeData *infoN;
							 | 
						|
								    LocalQueueItem *item;
							 | 
						|
								    DdNode *node;
							 | 
						|
								    int savings = 0;
							 | 
						|
								
							 | 
						|
								    node = Cudd_Regular(f);
							 | 
						|
								    if (node == NULL) return(0);
							 | 
						|
								    skip = Cudd_Regular(skip);
							 | 
						|
								    /* Insert the given node in the level queue. Its local reference
							 | 
						|
								    ** count is set equal to the function reference count so that the
							 | 
						|
								    ** search will continue from it when it is retrieved. */
							 | 
						|
								    item = (LocalQueueItem *)
							 | 
						|
									cuddLevelQueueFirst(queue,node,cuddI(dd,node->index));
							 | 
						|
								    if (item == NULL)
							 | 
						|
									return(0);
							 | 
						|
								    infoN = (NodeData *) cuddHashTableGenericLookup(info->table, node);
							 | 
						|
								    item->localRef = infoN->functionRef;
							 | 
						|
								
							 | 
						|
								    /* Process the queue. */
							 | 
						|
								    while ((item = (LocalQueueItem *) queue->first) != NULL) {
							 | 
						|
									node = item->node;
							 | 
						|
									if (node != skip) {
							 | 
						|
								            infoN = (NodeData *) cuddHashTableGenericLookup(info->table,node);
							 | 
						|
								            if (item->localRef == infoN->functionRef) {
							 | 
						|
								                /* This node is not shared. */
							 | 
						|
								                DdNode *nodeT, *nodeE;
							 | 
						|
								                savings++;
							 | 
						|
								                nodeT = cuddT(node);
							 | 
						|
								                if (!cuddIsConstant(nodeT)) {
							 | 
						|
								                    item = (LocalQueueItem *)
							 | 
						|
								                        cuddLevelQueueEnqueue(queue,nodeT,cuddI(dd,nodeT->index));
							 | 
						|
								                    if (item == NULL) return(0);
							 | 
						|
								                    item->localRef++;
							 | 
						|
								                }
							 | 
						|
								                nodeE = Cudd_Regular(cuddE(node));
							 | 
						|
								                if (!cuddIsConstant(nodeE)) {
							 | 
						|
								                    item = (LocalQueueItem *)
							 | 
						|
								                        cuddLevelQueueEnqueue(queue,nodeE,cuddI(dd,nodeE->index));
							 | 
						|
								                    if (item == NULL) return(0);
							 | 
						|
								                    item->localRef++;
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
									cuddLevelQueueDequeue(queue,cuddI(dd,node->index));
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
								    /* At the end of a local search the queue should be empty. */
							 | 
						|
								    assert(queue->size == 0);
							 | 
						|
								#endif
							 | 
						|
								    return(savings);
							 | 
						|
								
							 | 
						|
								} /* end of computeSavings */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								  @brief Update function reference counts to account for replacement.
							 | 
						|
								
							 | 
						|
								  @return the number of nodes saved if successful; 0 otherwise.
							 | 
						|
								
							 | 
						|
								  @sideeffect None
							 | 
						|
								
							 | 
						|
								  @see UAmarkNodes RAmarkNodes BAmarkNodes
							 | 
						|
								
							 | 
						|
								*/
							 | 
						|
								static int
							 | 
						|
								updateRefs(
							 | 
						|
								  DdManager * dd,
							 | 
						|
								  DdNode * f,
							 | 
						|
								  DdNode * skip,
							 | 
						|
								  ApproxInfo * info,
							 | 
						|
								  DdLevelQueue * queue)
							 | 
						|
								{
							 | 
						|
								    NodeData *infoN;
							 | 
						|
								    LocalQueueItem *item;
							 | 
						|
								    DdNode *node;
							 | 
						|
								    int savings = 0;
							 | 
						|
								
							 | 
						|
								    node = Cudd_Regular(f);
							 | 
						|
								    /* Insert the given node in the level queue. Its function reference
							 | 
						|
								    ** count is set equal to 0 so that the search will continue from it
							 | 
						|
								    ** when it is retrieved. */
							 | 
						|
								    item = (LocalQueueItem *) cuddLevelQueueFirst(queue,node,cuddI(dd,node->index));
							 | 
						|
								    if (item == NULL)
							 | 
						|
									return(0);
							 | 
						|
								    infoN = (NodeData *) cuddHashTableGenericLookup(info->table, node);
							 | 
						|
								    infoN->functionRef = 0;
							 | 
						|
								
							 | 
						|
								    if (skip != NULL) {
							 | 
						|
									/* Increase the function reference count of the node to be skipped
							 | 
						|
									** by 1 to account for the node pointing to it that will be created. */
							 | 
						|
									skip = Cudd_Regular(skip);
							 | 
						|
									infoN = (NodeData *) cuddHashTableGenericLookup(info->table, skip);
							 | 
						|
									infoN->functionRef++;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /* Process the queue. */
							 | 
						|
								    while ((item = (LocalQueueItem *) queue->first) != NULL) {
							 | 
						|
									node = item->node;
							 | 
						|
									infoN = (NodeData *) cuddHashTableGenericLookup(info->table,node);
							 | 
						|
									if (infoN->functionRef == 0) {
							 | 
						|
									    /* This node is not shared or to be be skipped. */
							 | 
						|
								            DdNode *nodeT, *nodeE;
							 | 
						|
								            savings++;
							 | 
						|
								            nodeT = cuddT(node);
							 | 
						|
								            if (!cuddIsConstant(nodeT)) {
							 | 
						|
								                item = (LocalQueueItem *)
							 | 
						|
								                    cuddLevelQueueEnqueue(queue,nodeT,cuddI(dd,nodeT->index));
							 | 
						|
								                if (item == NULL) return(0);
							 | 
						|
								                infoN = (NodeData *) cuddHashTableGenericLookup(info->table,nodeT);
							 | 
						|
								                infoN->functionRef--;
							 | 
						|
								            }
							 | 
						|
								            nodeE = Cudd_Regular(cuddE(node));
							 | 
						|
								            if (!cuddIsConstant(nodeE)) {
							 | 
						|
								                item = (LocalQueueItem *)
							 | 
						|
								                    cuddLevelQueueEnqueue(queue,nodeE,cuddI(dd,nodeE->index));
							 | 
						|
								                if (item == NULL) return(0);
							 | 
						|
								                infoN = (NodeData *) cuddHashTableGenericLookup(info->table,nodeE);
							 | 
						|
								                infoN->functionRef--;
							 | 
						|
								            }
							 | 
						|
									}
							 | 
						|
									cuddLevelQueueDequeue(queue,cuddI(dd,node->index));
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
								    /* At the end of a local search the queue should be empty. */
							 | 
						|
								    assert(queue->size == 0);
							 | 
						|
								#endif
							 | 
						|
								    return(savings);
							 | 
						|
								
							 | 
						|
								} /* end of updateRefs */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								  @brief Marks nodes for replacement by zero.
							 | 
						|
								
							 | 
						|
								  @return 1 if successful; 0 otherwise.
							 | 
						|
								
							 | 
						|
								  @sideeffect None
							 | 
						|
								
							 | 
						|
								  @see cuddUnderApprox
							 | 
						|
								
							 | 
						|
								*/
							 | 
						|
								static int
							 | 
						|
								UAmarkNodes(
							 | 
						|
								  DdManager * dd /**< manager */,
							 | 
						|
								  DdNode * f /**< function to be analyzed */,
							 | 
						|
								  ApproxInfo * info /**< info on %BDD */,
							 | 
						|
								  int  threshold /**< when to stop approximating */,
							 | 
						|
								  int  safe /**< enforce safe approximation */,
							 | 
						|
								  double  quality /**< minimum improvement for accepted changes */)
							 | 
						|
								{
							 | 
						|
								    DdLevelQueue *queue;
							 | 
						|
								    DdLevelQueue *localQueue;
							 | 
						|
								    NodeData *infoN;
							 | 
						|
								    GlobalQueueItem *item;
							 | 
						|
								    DdNode *node;
							 | 
						|
								    double numOnset;
							 | 
						|
								    double impactP, impactN;
							 | 
						|
								    int savings;
							 | 
						|
								
							 | 
						|
								#if 0
							 | 
						|
								    (void) printf("initial size = %d initial minterms = %g\n",
							 | 
						|
										  info->size, info->minterms);
							 | 
						|
								#endif
							 | 
						|
								    queue = cuddLevelQueueInit(dd->size,sizeof(GlobalQueueItem),info->size,dd);
							 | 
						|
								    if (queue == NULL) {
							 | 
						|
									return(0);
							 | 
						|
								    }
							 | 
						|
								    localQueue = cuddLevelQueueInit(dd->size,sizeof(LocalQueueItem),
							 | 
						|
												    dd->initSlots,dd);
							 | 
						|
								    if (localQueue == NULL) {
							 | 
						|
									cuddLevelQueueQuit(queue);
							 | 
						|
									return(0);
							 | 
						|
								    }
							 | 
						|
								    node = Cudd_Regular(f);
							 | 
						|
								    item = (GlobalQueueItem *) cuddLevelQueueEnqueue(queue,node,cuddI(dd,node->index));
							 | 
						|
								    if (item == NULL) {
							 | 
						|
									cuddLevelQueueQuit(queue);
							 | 
						|
									cuddLevelQueueQuit(localQueue);
							 | 
						|
									return(0);
							 | 
						|
								    }
							 | 
						|
								    if (Cudd_IsComplement(f)) {
							 | 
						|
									item->impactP = 0.0;
							 | 
						|
									item->impactN = 1.0;
							 | 
						|
								    } else {
							 | 
						|
									item->impactP = 1.0;
							 | 
						|
									item->impactN = 0.0;
							 | 
						|
								    }
							 | 
						|
								    while (queue->first != NULL) {
							 | 
						|
									/* If the size of the subset is below the threshold, quit. */
							 | 
						|
									if (info->size <= threshold)
							 | 
						|
									    break;
							 | 
						|
									item = (GlobalQueueItem *) queue->first;
							 | 
						|
									node = item->node;
							 | 
						|
									node = Cudd_Regular(node);
							 | 
						|
									infoN = (NodeData *) cuddHashTableGenericLookup(info->table, node);
							 | 
						|
									if (safe && infoN->parity == 3) {
							 | 
						|
									    cuddLevelQueueDequeue(queue,cuddI(dd,node->index));
							 | 
						|
									    continue;
							 | 
						|
									}
							 | 
						|
									impactP = item->impactP;
							 | 
						|
									impactN = item->impactN;
							 | 
						|
									numOnset = infoN->mintermsP * impactP + infoN->mintermsN * impactN;
							 | 
						|
									savings = computeSavings(dd,node,NULL,info,localQueue);
							 | 
						|
									if (savings == 0) {
							 | 
						|
									    cuddLevelQueueQuit(queue);
							 | 
						|
									    cuddLevelQueueQuit(localQueue);
							 | 
						|
									    return(0);
							 | 
						|
									}
							 | 
						|
									cuddLevelQueueDequeue(queue,cuddI(dd,node->index));
							 | 
						|
								#if 0
							 | 
						|
									(void) printf("node %p: impact = %g/%g numOnset = %g savings %d\n",
							 | 
						|
										      node, impactP, impactN, numOnset, savings);
							 | 
						|
								#endif
							 | 
						|
									if ((1 - numOnset / info->minterms) >
							 | 
						|
									    quality * (1 - (double) savings / info->size)) {
							 | 
						|
									    infoN->replace = CUDD_TRUE;
							 | 
						|
									    info->size -= savings;
							 | 
						|
									    info->minterms -=numOnset;
							 | 
						|
								#if 0
							 | 
						|
									    (void) printf("replace: new size = %d new minterms = %g\n",
							 | 
						|
											  info->size, info->minterms);
							 | 
						|
								#endif
							 | 
						|
									    savings -= updateRefs(dd,node,NULL,info,localQueue);
							 | 
						|
									    assert(savings == 0);
							 | 
						|
									    continue;
							 | 
						|
									}
							 | 
						|
									if (!cuddIsConstant(cuddT(node))) {
							 | 
						|
									    item = (GlobalQueueItem *) cuddLevelQueueEnqueue(queue,cuddT(node),
							 | 
						|
													 cuddI(dd,cuddT(node)->index));
							 | 
						|
									    item->impactP += impactP/2.0;
							 | 
						|
									    item->impactN += impactN/2.0;
							 | 
						|
									}
							 | 
						|
									if (!Cudd_IsConstantInt(cuddE(node))) {
							 | 
						|
									    item = (GlobalQueueItem *) cuddLevelQueueEnqueue(queue,Cudd_Regular(cuddE(node)),
							 | 
						|
													 cuddI(dd,Cudd_Regular(cuddE(node))->index));
							 | 
						|
									    if (Cudd_IsComplement(cuddE(node))) {
							 | 
						|
										item->impactP += impactN/2.0;
							 | 
						|
										item->impactN += impactP/2.0;
							 | 
						|
									    } else {
							 | 
						|
										item->impactP += impactP/2.0;
							 | 
						|
										item->impactN += impactN/2.0;
							 | 
						|
									    }
							 | 
						|
									}
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    cuddLevelQueueQuit(queue);
							 | 
						|
								    cuddLevelQueueQuit(localQueue);
							 | 
						|
								    return(1);
							 | 
						|
								
							 | 
						|
								} /* end of UAmarkNodes */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								  @brief Builds the subset %BDD. 
							 | 
						|
								
							 | 
						|
								  @details Based on the info table, replaces selected nodes by zero.
							 | 
						|
								
							 | 
						|
								  @return a pointer to the result if successful; NULL otherwise.
							 | 
						|
								
							 | 
						|
								  @sideeffect None
							 | 
						|
								
							 | 
						|
								  @see cuddUnderApprox
							 | 
						|
								
							 | 
						|
								*/
							 | 
						|
								static DdNode *
							 | 
						|
								UAbuildSubset(
							 | 
						|
								  DdManager * dd /**< %DD manager */,
							 | 
						|
								  DdNode * node /**< current node */,
							 | 
						|
								  ApproxInfo * info /**< node info */)
							 | 
						|
								{
							 | 
						|
								
							 | 
						|
								    DdNode *Nt, *Ne, *N, *t, *e, *r;
							 | 
						|
								    NodeData *infoN;
							 | 
						|
								
							 | 
						|
								    if (Cudd_IsConstantInt(node))
							 | 
						|
									return(node);
							 | 
						|
								
							 | 
						|
								    N = Cudd_Regular(node);
							 | 
						|
								
							 | 
						|
								    if ((infoN = (NodeData *) cuddHashTableGenericLookup(info->table, N)) != NULL) {
							 | 
						|
									if (infoN->replace == CUDD_TRUE) {
							 | 
						|
									    return(info->zero);
							 | 
						|
									}
							 | 
						|
									if (N == node ) {
							 | 
						|
									    if (infoN->resultP != NULL) {
							 | 
						|
										return(infoN->resultP);
							 | 
						|
									    }
							 | 
						|
									} else {
							 | 
						|
									    if (infoN->resultN != NULL) {
							 | 
						|
										return(infoN->resultN);
							 | 
						|
									    }
							 | 
						|
									}
							 | 
						|
								    } else {
							 | 
						|
									(void) fprintf(dd->err,
							 | 
						|
										       "Something is wrong, ought to be in info table\n");
							 | 
						|
									dd->errorCode = CUDD_INTERNAL_ERROR;
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    Nt = Cudd_NotCond(cuddT(N), Cudd_IsComplement(node));
							 | 
						|
								    Ne = Cudd_NotCond(cuddE(N), Cudd_IsComplement(node));
							 | 
						|
								
							 | 
						|
								    t = UAbuildSubset(dd, Nt, info);
							 | 
						|
								    if (t == NULL) {
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								    cuddRef(t);
							 | 
						|
								
							 | 
						|
								    e = UAbuildSubset(dd, Ne, info);
							 | 
						|
								    if (e == NULL) {
							 | 
						|
									Cudd_RecursiveDeref(dd,t);
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								    cuddRef(e);
							 | 
						|
								
							 | 
						|
								    if (Cudd_IsComplement(t)) {
							 | 
						|
									t = Cudd_Not(t);
							 | 
						|
									e = Cudd_Not(e);
							 | 
						|
									r = (t == e) ? t : cuddUniqueInter(dd, N->index, t, e);
							 | 
						|
									if (r == NULL) {
							 | 
						|
									    Cudd_RecursiveDeref(dd, e);
							 | 
						|
									    Cudd_RecursiveDeref(dd, t);
							 | 
						|
									    return(NULL);
							 | 
						|
									}
							 | 
						|
									r = Cudd_Not(r);
							 | 
						|
								    } else {
							 | 
						|
									r = (t == e) ? t : cuddUniqueInter(dd, N->index, t, e);
							 | 
						|
									if (r == NULL) {
							 | 
						|
									    Cudd_RecursiveDeref(dd, e);
							 | 
						|
									    Cudd_RecursiveDeref(dd, t);
							 | 
						|
									    return(NULL);
							 | 
						|
									}
							 | 
						|
								    }
							 | 
						|
								    cuddDeref(t);
							 | 
						|
								    cuddDeref(e);
							 | 
						|
								
							 | 
						|
								    if (N == node) {
							 | 
						|
									infoN->resultP = r;
							 | 
						|
								    } else {
							 | 
						|
									infoN->resultN = r;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    return(r);
							 | 
						|
								
							 | 
						|
								} /* end of UAbuildSubset */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								  @brief Marks nodes for remapping.
							 | 
						|
								
							 | 
						|
								  @return 1 if successful; 0 otherwise.
							 | 
						|
								
							 | 
						|
								  @sideeffect None
							 | 
						|
								
							 | 
						|
								  @see cuddRemapUnderApprox
							 | 
						|
								
							 | 
						|
								*/
							 | 
						|
								static int
							 | 
						|
								RAmarkNodes(
							 | 
						|
								  DdManager * dd /**< manager */,
							 | 
						|
								  DdNode * f /**< function to be analyzed */,
							 | 
						|
								  ApproxInfo * info /**< info on %BDD */,
							 | 
						|
								  int threshold /**< when to stop approximating */,
							 | 
						|
								  double quality /**< minimum improvement for accepted changes */)
							 | 
						|
								{
							 | 
						|
								    DdLevelQueue *queue;
							 | 
						|
								    DdLevelQueue *localQueue;
							 | 
						|
								    NodeData *infoN, *infoT, *infoE;
							 | 
						|
								    GlobalQueueItem *item;
							 | 
						|
								    DdNode *node, *T, *E;
							 | 
						|
								    DdNode *shared; /* grandchild shared by the two children of node */
							 | 
						|
								    double numOnset;
							 | 
						|
								    double impact, impactP, impactN;
							 | 
						|
								    double minterms;
							 | 
						|
								    int savings;
							 | 
						|
								    int replace;
							 | 
						|
								
							 | 
						|
								#if 0
							 | 
						|
								    (void) fprintf(dd->out,"initial size = %d initial minterms = %g\n",
							 | 
						|
										  info->size, info->minterms);
							 | 
						|
								#endif
							 | 
						|
								    queue = cuddLevelQueueInit(dd->size,sizeof(GlobalQueueItem),info->size,dd);
							 | 
						|
								    if (queue == NULL) {
							 | 
						|
									return(0);
							 | 
						|
								    }
							 | 
						|
								    localQueue = cuddLevelQueueInit(dd->size,sizeof(LocalQueueItem),
							 | 
						|
												    dd->initSlots,dd);
							 | 
						|
								    if (localQueue == NULL) {
							 | 
						|
									cuddLevelQueueQuit(queue);
							 | 
						|
									return(0);
							 | 
						|
								    }
							 | 
						|
								    /* Enqueue regular pointer to root and initialize impact. */
							 | 
						|
								    node = Cudd_Regular(f);
							 | 
						|
								    item = (GlobalQueueItem *)
							 | 
						|
									cuddLevelQueueEnqueue(queue,node,cuddI(dd,node->index));
							 | 
						|
								    if (item == NULL) {
							 | 
						|
									cuddLevelQueueQuit(queue);
							 | 
						|
									cuddLevelQueueQuit(localQueue);
							 | 
						|
									return(0);
							 | 
						|
								    }
							 | 
						|
								    if (Cudd_IsComplement(f)) {
							 | 
						|
									item->impactP = 0.0;
							 | 
						|
									item->impactN = 1.0;
							 | 
						|
								    } else {
							 | 
						|
									item->impactP = 1.0;
							 | 
						|
									item->impactN = 0.0;
							 | 
						|
								    }
							 | 
						|
								    /* The nodes retrieved here are guaranteed to be non-terminal.
							 | 
						|
								    ** The initial node is not terminal because constant nodes are
							 | 
						|
								    ** dealt with in the calling procedure. Subsequent nodes are inserted
							 | 
						|
								    ** only if they are not terminal. */
							 | 
						|
								    while ((item = (GlobalQueueItem *) queue->first) != NULL) {
							 | 
						|
									/* If the size of the subset is below the threshold, quit. */
							 | 
						|
									if (info->size <= threshold)
							 | 
						|
									    break;
							 | 
						|
									node = item->node;
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
									assert(item->impactP >= 0 && item->impactP <= 1.0);
							 | 
						|
									assert(item->impactN >= 0 && item->impactN <= 1.0);
							 | 
						|
									assert(!Cudd_IsComplement(node));
							 | 
						|
									assert(!Cudd_IsConstantInt(node));
							 | 
						|
								#endif
							 | 
						|
									if ((infoN = (NodeData *) cuddHashTableGenericLookup(info->table, node)) == NULL) {
							 | 
						|
									    cuddLevelQueueQuit(queue);
							 | 
						|
									    cuddLevelQueueQuit(localQueue);
							 | 
						|
									    return(0);
							 | 
						|
									}
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
									assert(infoN->parity >= 1 && infoN->parity <= 3);
							 | 
						|
								#endif
							 | 
						|
									if (infoN->parity == 3) {
							 | 
						|
									    /* This node can be reached through paths of different parity.
							 | 
						|
									    ** It is not safe to replace it, because remapping will give
							 | 
						|
									    ** an incorrect result, while replacement by 0 may cause node
							 | 
						|
									    ** splitting. */
							 | 
						|
									    cuddLevelQueueDequeue(queue,cuddI(dd,node->index));
							 | 
						|
									    continue;
							 | 
						|
									}
							 | 
						|
									T = cuddT(node);
							 | 
						|
									E = cuddE(node);
							 | 
						|
									shared = NULL;
							 | 
						|
									impactP = item->impactP;
							 | 
						|
									impactN = item->impactN;
							 | 
						|
									if (Cudd_bddLeq(dd,T,E)) {
							 | 
						|
									    /* Here we know that E is regular. */
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
									    assert(!Cudd_IsComplement(E));
							 | 
						|
								#endif
							 | 
						|
									    infoT = (NodeData *) cuddHashTableGenericLookup(info->table, T);
							 | 
						|
									    infoE = (NodeData *) cuddHashTableGenericLookup(info->table, E);
							 | 
						|
									    if (infoN->parity == 1) {
							 | 
						|
										impact = impactP;
							 | 
						|
										minterms = infoE->mintermsP/2.0 - infoT->mintermsP/2.0;
							 | 
						|
										if (infoE->functionRef == 1 && !cuddIsConstant(E)) {
							 | 
						|
										    savings = 1 + computeSavings(dd,E,NULL,info,localQueue);
							 | 
						|
										    if (savings == 1) {
							 | 
						|
											cuddLevelQueueQuit(queue);
							 | 
						|
											cuddLevelQueueQuit(localQueue);
							 | 
						|
											return(0);
							 | 
						|
										    }
							 | 
						|
										} else {
							 | 
						|
										    savings = 1;
							 | 
						|
										}
							 | 
						|
										replace = REPLACE_E;
							 | 
						|
									    } else {
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
										assert(infoN->parity == 2);
							 | 
						|
								#endif
							 | 
						|
										impact = impactN;
							 | 
						|
										minterms = infoT->mintermsN/2.0 - infoE->mintermsN/2.0;
							 | 
						|
										if (infoT->functionRef == 1 && !cuddIsConstant(T)) {
							 | 
						|
										    savings = 1 + computeSavings(dd,T,NULL,info,localQueue);
							 | 
						|
										    if (savings == 1) {
							 | 
						|
											cuddLevelQueueQuit(queue);
							 | 
						|
											cuddLevelQueueQuit(localQueue);
							 | 
						|
											return(0);
							 | 
						|
										    }
							 | 
						|
										} else {
							 | 
						|
										    savings = 1;
							 | 
						|
										}
							 | 
						|
										replace = REPLACE_T;
							 | 
						|
									    }
							 | 
						|
									    numOnset = impact * minterms;
							 | 
						|
									} else if (Cudd_bddLeq(dd,E,T)) {
							 | 
						|
									    /* Here E may be complemented. */
							 | 
						|
									    DdNode *Ereg = Cudd_Regular(E);
							 | 
						|
									    infoT = (NodeData *) cuddHashTableGenericLookup(info->table, T);
							 | 
						|
									    infoE = (NodeData *) cuddHashTableGenericLookup(info->table, Ereg);
							 | 
						|
									    if (infoN->parity == 1) {
							 | 
						|
										impact = impactP;
							 | 
						|
										minterms = infoT->mintermsP/2.0 -
							 | 
						|
										    ((E == Ereg) ? infoE->mintermsP : infoE->mintermsN)/2.0;
							 | 
						|
										if (infoT->functionRef == 1 && !cuddIsConstant(T)) {
							 | 
						|
										    savings = 1 + computeSavings(dd,T,NULL,info,localQueue);
							 | 
						|
										    if (savings == 1) {
							 | 
						|
											cuddLevelQueueQuit(queue);
							 | 
						|
											cuddLevelQueueQuit(localQueue);
							 | 
						|
											return(0);
							 | 
						|
										    }
							 | 
						|
										} else {
							 | 
						|
										    savings = 1;
							 | 
						|
										}
							 | 
						|
										replace = REPLACE_T;
							 | 
						|
									    } else {
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
										assert(infoN->parity == 2);
							 | 
						|
								#endif
							 | 
						|
										impact = impactN;
							 | 
						|
										minterms = ((E == Ereg) ? infoE->mintermsN :
							 | 
						|
											    infoE->mintermsP)/2.0 - infoT->mintermsN/2.0;
							 | 
						|
										if (infoE->functionRef == 1 && !cuddIsConstant(Ereg)) {
							 | 
						|
										    savings = 1 + computeSavings(dd,E,NULL,info,localQueue);
							 | 
						|
										    if (savings == 1) {
							 | 
						|
											cuddLevelQueueQuit(queue);
							 | 
						|
											cuddLevelQueueQuit(localQueue);
							 | 
						|
											return(0);
							 | 
						|
										    }
							 | 
						|
										} else {
							 | 
						|
										    savings = 1;
							 | 
						|
										}
							 | 
						|
										replace = REPLACE_E;
							 | 
						|
									    }
							 | 
						|
									    numOnset = impact * minterms;
							 | 
						|
									} else {
							 | 
						|
									    DdNode *Ereg = Cudd_Regular(E);
							 | 
						|
									    DdNode *TT = cuddT(T);
							 | 
						|
									    DdNode *ET = Cudd_NotCond(cuddT(Ereg), Cudd_IsComplement(E));
							 | 
						|
									    if (T->index == Ereg->index && TT == ET) {
							 | 
						|
										shared = TT;
							 | 
						|
										replace = REPLACE_TT;
							 | 
						|
									    } else {
							 | 
						|
										DdNode *TE = cuddE(T);
							 | 
						|
										DdNode *EE = Cudd_NotCond(cuddE(Ereg), Cudd_IsComplement(E));
							 | 
						|
										if (T->index == Ereg->index && TE == EE) {
							 | 
						|
										    shared = TE;
							 | 
						|
										    replace = REPLACE_TE;
							 | 
						|
										} else {
							 | 
						|
										    replace = REPLACE_N;
							 | 
						|
										}
							 | 
						|
									    }
							 | 
						|
									    numOnset = infoN->mintermsP * impactP + infoN->mintermsN * impactN;
							 | 
						|
									    savings = computeSavings(dd,node,shared,info,localQueue);
							 | 
						|
									    if (shared != NULL) {
							 | 
						|
										NodeData *infoS;
							 | 
						|
										infoS = (NodeData *) cuddHashTableGenericLookup(info->table, Cudd_Regular(shared));
							 | 
						|
										if (Cudd_IsComplement(shared)) {
							 | 
						|
										    numOnset -= (infoS->mintermsN * impactP +
							 | 
						|
											infoS->mintermsP * impactN)/2.0;
							 | 
						|
										} else {
							 | 
						|
										    numOnset -= (infoS->mintermsP * impactP +
							 | 
						|
											infoS->mintermsN * impactN)/2.0;
							 | 
						|
										}
							 | 
						|
										savings--;
							 | 
						|
									    }
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									cuddLevelQueueDequeue(queue,cuddI(dd,node->index));
							 | 
						|
								#if 0
							 | 
						|
									if (replace == REPLACE_T || replace == REPLACE_E)
							 | 
						|
									    (void) printf("node %p: impact = %g numOnset = %g savings %d\n",
							 | 
						|
											  node, impact, numOnset, savings);
							 | 
						|
									else
							 | 
						|
									    (void) printf("node %p: impact = %g/%g numOnset = %g savings %d\n",
							 | 
						|
											  node, impactP, impactN, numOnset, savings);
							 | 
						|
								#endif
							 | 
						|
									if ((1 - numOnset / info->minterms) >
							 | 
						|
									    quality * (1 - (double) savings / info->size)) {
							 | 
						|
									    infoN->replace = (char) replace;
							 | 
						|
									    info->size -= savings;
							 | 
						|
									    info->minterms -=numOnset;
							 | 
						|
								#if 0
							 | 
						|
									    (void) printf("remap(%d): new size = %d new minterms = %g\n",
							 | 
						|
											  replace, info->size, info->minterms);
							 | 
						|
								#endif
							 | 
						|
									    if (replace == REPLACE_N) {
							 | 
						|
										savings -= updateRefs(dd,node,NULL,info,localQueue);
							 | 
						|
									    } else if (replace == REPLACE_T) {
							 | 
						|
										savings -= updateRefs(dd,node,E,info,localQueue);
							 | 
						|
									    } else if (replace == REPLACE_E) {
							 | 
						|
										savings -= updateRefs(dd,node,T,info,localQueue);
							 | 
						|
									    } else {
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
										assert(replace == REPLACE_TT || replace == REPLACE_TE);
							 | 
						|
								#endif
							 | 
						|
										savings -= updateRefs(dd,node,shared,info,localQueue) - 1;
							 | 
						|
									    }
							 | 
						|
									    assert(savings == 0);
							 | 
						|
									} else {
							 | 
						|
									    replace = NOTHING;
							 | 
						|
									}
							 | 
						|
									if (replace == REPLACE_N) continue;
							 | 
						|
									if ((replace == REPLACE_E || replace == NOTHING) &&
							 | 
						|
									    !cuddIsConstant(cuddT(node))) {
							 | 
						|
									    item = (GlobalQueueItem *) cuddLevelQueueEnqueue(queue,cuddT(node),
							 | 
						|
													 cuddI(dd,cuddT(node)->index));
							 | 
						|
									    if (replace == REPLACE_E) {
							 | 
						|
										item->impactP += impactP;
							 | 
						|
										item->impactN += impactN;
							 | 
						|
									    } else {
							 | 
						|
										item->impactP += impactP/2.0;
							 | 
						|
										item->impactN += impactN/2.0;
							 | 
						|
									    }
							 | 
						|
									}
							 | 
						|
									if ((replace == REPLACE_T || replace == NOTHING) &&
							 | 
						|
									    !Cudd_IsConstantInt(cuddE(node))) {
							 | 
						|
									    item = (GlobalQueueItem *) cuddLevelQueueEnqueue(queue,Cudd_Regular(cuddE(node)),
							 | 
						|
													 cuddI(dd,Cudd_Regular(cuddE(node))->index));
							 | 
						|
									    if (Cudd_IsComplement(cuddE(node))) {
							 | 
						|
										if (replace == REPLACE_T) {
							 | 
						|
										    item->impactP += impactN;
							 | 
						|
										    item->impactN += impactP;
							 | 
						|
										} else {
							 | 
						|
										    item->impactP += impactN/2.0;
							 | 
						|
										    item->impactN += impactP/2.0;
							 | 
						|
										}
							 | 
						|
									    } else {
							 | 
						|
										if (replace == REPLACE_T) {
							 | 
						|
										    item->impactP += impactP;
							 | 
						|
										    item->impactN += impactN;
							 | 
						|
										} else {
							 | 
						|
										    item->impactP += impactP/2.0;
							 | 
						|
										    item->impactN += impactN/2.0;
							 | 
						|
										}
							 | 
						|
									    }
							 | 
						|
									}
							 | 
						|
									if ((replace == REPLACE_TT || replace == REPLACE_TE) &&
							 | 
						|
									    !Cudd_IsConstantInt(shared)) {
							 | 
						|
									    item = (GlobalQueueItem *) cuddLevelQueueEnqueue(queue,Cudd_Regular(shared),
							 | 
						|
													 cuddI(dd,Cudd_Regular(shared)->index));
							 | 
						|
									    if (Cudd_IsComplement(shared)) {
							 | 
						|
									        item->impactP += impactN;
							 | 
						|
										item->impactN += impactP;
							 | 
						|
									    } else {
							 | 
						|
									        item->impactP += impactP;
							 | 
						|
										item->impactN += impactN;
							 | 
						|
									    }
							 | 
						|
									}
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    cuddLevelQueueQuit(queue);
							 | 
						|
								    cuddLevelQueueQuit(localQueue);
							 | 
						|
								    return(1);
							 | 
						|
								
							 | 
						|
								} /* end of RAmarkNodes */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								  @brief Marks nodes for remapping.
							 | 
						|
								
							 | 
						|
								  @return 1 if successful; 0 otherwise.
							 | 
						|
								
							 | 
						|
								  @sideeffect None
							 | 
						|
								
							 | 
						|
								  @see cuddBiasedUnderApprox
							 | 
						|
								
							 | 
						|
								*/
							 | 
						|
								static int
							 | 
						|
								BAmarkNodes(
							 | 
						|
								  DdManager *dd /**< manager */,
							 | 
						|
								  DdNode *f /**< function to be analyzed */,
							 | 
						|
								  ApproxInfo *info /**< info on %BDD */,
							 | 
						|
								  int threshold /**< when to stop approximating */,
							 | 
						|
								  double quality1 /**< minimum improvement for accepted changes when b=1 */,
							 | 
						|
								  double quality0 /**< minimum improvement for accepted changes when b=0 */)
							 | 
						|
								{
							 | 
						|
								    DdLevelQueue *queue;
							 | 
						|
								    DdLevelQueue *localQueue;
							 | 
						|
								    NodeData *infoN, *infoT, *infoE;
							 | 
						|
								    GlobalQueueItem *item;
							 | 
						|
								    DdNode *node, *T, *E;
							 | 
						|
								    DdNode *shared; /* grandchild shared by the two children of node */
							 | 
						|
								    double numOnset;
							 | 
						|
								    double impact, impactP, impactN;
							 | 
						|
								    double minterms;
							 | 
						|
								    double quality;
							 | 
						|
								    int savings;
							 | 
						|
								    int replace;
							 | 
						|
								
							 | 
						|
								#if 0
							 | 
						|
								    (void) fprintf(dd->out,"initial size = %d initial minterms = %g\n",
							 | 
						|
										  info->size, info->minterms);
							 | 
						|
								#endif
							 | 
						|
								    queue = cuddLevelQueueInit(dd->size,sizeof(GlobalQueueItem),info->size,dd);
							 | 
						|
								    if (queue == NULL) {
							 | 
						|
									return(0);
							 | 
						|
								    }
							 | 
						|
								    localQueue = cuddLevelQueueInit(dd->size,sizeof(LocalQueueItem),
							 | 
						|
												    dd->initSlots,dd);
							 | 
						|
								    if (localQueue == NULL) {
							 | 
						|
									cuddLevelQueueQuit(queue);
							 | 
						|
									return(0);
							 | 
						|
								    }
							 | 
						|
								    /* Enqueue regular pointer to root and initialize impact. */
							 | 
						|
								    node = Cudd_Regular(f);
							 | 
						|
								    item = (GlobalQueueItem *)
							 | 
						|
									cuddLevelQueueEnqueue(queue,node,cuddI(dd,node->index));
							 | 
						|
								    if (item == NULL) {
							 | 
						|
									cuddLevelQueueQuit(queue);
							 | 
						|
									cuddLevelQueueQuit(localQueue);
							 | 
						|
									return(0);
							 | 
						|
								    }
							 | 
						|
								    if (Cudd_IsComplement(f)) {
							 | 
						|
									item->impactP = 0.0;
							 | 
						|
									item->impactN = 1.0;
							 | 
						|
								    } else {
							 | 
						|
									item->impactP = 1.0;
							 | 
						|
									item->impactN = 0.0;
							 | 
						|
								    }
							 | 
						|
								    /* The nodes retrieved here are guaranteed to be non-terminal.
							 | 
						|
								    ** The initial node is not terminal because constant nodes are
							 | 
						|
								    ** dealt with in the calling procedure. Subsequent nodes are inserted
							 | 
						|
								    ** only if they are not terminal. */
							 | 
						|
								    while (queue->first != NULL) {
							 | 
						|
									/* If the size of the subset is below the threshold, quit. */
							 | 
						|
									if (info->size <= threshold)
							 | 
						|
									    break;
							 | 
						|
									item = (GlobalQueueItem *) queue->first;
							 | 
						|
									node = item->node;
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
									assert(item->impactP >= 0 && item->impactP <= 1.0);
							 | 
						|
									assert(item->impactN >= 0 && item->impactN <= 1.0);
							 | 
						|
									assert(!Cudd_IsComplement(node));
							 | 
						|
									assert(!Cudd_IsConstantInt(node));
							 | 
						|
								#endif
							 | 
						|
									if ((infoN = (NodeData *) cuddHashTableGenericLookup(info->table, node)) == NULL) {
							 | 
						|
									    cuddLevelQueueQuit(queue);
							 | 
						|
									    cuddLevelQueueQuit(localQueue);
							 | 
						|
									    return(0);
							 | 
						|
									}
							 | 
						|
									quality = infoN->care ? quality1 : quality0;
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
									assert(infoN->parity >= 1 && infoN->parity <= 3);
							 | 
						|
								#endif
							 | 
						|
									if (infoN->parity == 3) {
							 | 
						|
									    /* This node can be reached through paths of different parity.
							 | 
						|
									    ** It is not safe to replace it, because remapping will give
							 | 
						|
									    ** an incorrect result, while replacement by 0 may cause node
							 | 
						|
									    ** splitting. */
							 | 
						|
									    cuddLevelQueueDequeue(queue,cuddI(dd,node->index));
							 | 
						|
									    continue;
							 | 
						|
									}
							 | 
						|
									T = cuddT(node);
							 | 
						|
									E = cuddE(node);
							 | 
						|
									shared = NULL;
							 | 
						|
									impactP = item->impactP;
							 | 
						|
									impactN = item->impactN;
							 | 
						|
									if (Cudd_bddLeq(dd,T,E)) {
							 | 
						|
									    /* Here we know that E is regular. */
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
									    assert(!Cudd_IsComplement(E));
							 | 
						|
								#endif
							 | 
						|
									    infoT = (NodeData *) cuddHashTableGenericLookup(info->table, T);
							 | 
						|
									    infoE = (NodeData *) cuddHashTableGenericLookup(info->table, E);
							 | 
						|
									    if (infoN->parity == 1) {
							 | 
						|
										impact = impactP;
							 | 
						|
										minterms = infoE->mintermsP/2.0 - infoT->mintermsP/2.0;
							 | 
						|
										if (infoE->functionRef == 1 && !Cudd_IsConstantInt(E)) {
							 | 
						|
										    savings = 1 + computeSavings(dd,E,NULL,info,localQueue);
							 | 
						|
										    if (savings == 1) {
							 | 
						|
											cuddLevelQueueQuit(queue);
							 | 
						|
											cuddLevelQueueQuit(localQueue);
							 | 
						|
											return(0);
							 | 
						|
										    }
							 | 
						|
										} else {
							 | 
						|
										    savings = 1;
							 | 
						|
										}
							 | 
						|
										replace = REPLACE_E;
							 | 
						|
									    } else {
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
										assert(infoN->parity == 2);
							 | 
						|
								#endif
							 | 
						|
										impact = impactN;
							 | 
						|
										minterms = infoT->mintermsN/2.0 - infoE->mintermsN/2.0;
							 | 
						|
										if (infoT->functionRef == 1 && !Cudd_IsConstantInt(T)) {
							 | 
						|
										    savings = 1 + computeSavings(dd,T,NULL,info,localQueue);
							 | 
						|
										    if (savings == 1) {
							 | 
						|
											cuddLevelQueueQuit(queue);
							 | 
						|
											cuddLevelQueueQuit(localQueue);
							 | 
						|
											return(0);
							 | 
						|
										    }
							 | 
						|
										} else {
							 | 
						|
										    savings = 1;
							 | 
						|
										}
							 | 
						|
										replace = REPLACE_T;
							 | 
						|
									    }
							 | 
						|
									    numOnset = impact * minterms;
							 | 
						|
									} else if (Cudd_bddLeq(dd,E,T)) {
							 | 
						|
									    /* Here E may be complemented. */
							 | 
						|
									    DdNode *Ereg = Cudd_Regular(E);
							 | 
						|
									    infoT = (NodeData *) cuddHashTableGenericLookup(info->table, T);
							 | 
						|
									    infoE = (NodeData *) cuddHashTableGenericLookup(info->table, Ereg);
							 | 
						|
									    if (infoN->parity == 1) {
							 | 
						|
										impact = impactP;
							 | 
						|
										minterms = infoT->mintermsP/2.0 -
							 | 
						|
										    ((E == Ereg) ? infoE->mintermsP : infoE->mintermsN)/2.0;
							 | 
						|
										if (infoT->functionRef == 1 && !Cudd_IsConstantInt(T)) {
							 | 
						|
										    savings = 1 + computeSavings(dd,T,NULL,info,localQueue);
							 | 
						|
										    if (savings == 1) {
							 | 
						|
											cuddLevelQueueQuit(queue);
							 | 
						|
											cuddLevelQueueQuit(localQueue);
							 | 
						|
											return(0);
							 | 
						|
										    }
							 | 
						|
										} else {
							 | 
						|
										    savings = 1;
							 | 
						|
										}
							 | 
						|
										replace = REPLACE_T;
							 | 
						|
									    } else {
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
										assert(infoN->parity == 2);
							 | 
						|
								#endif
							 | 
						|
										impact = impactN;
							 | 
						|
										minterms = ((E == Ereg) ? infoE->mintermsN :
							 | 
						|
											    infoE->mintermsP)/2.0 - infoT->mintermsN/2.0;
							 | 
						|
										if (infoE->functionRef == 1 && !Cudd_IsConstantInt(E)) {
							 | 
						|
										    savings = 1 + computeSavings(dd,E,NULL,info,localQueue);
							 | 
						|
										    if (savings == 1) {
							 | 
						|
											cuddLevelQueueQuit(queue);
							 | 
						|
											cuddLevelQueueQuit(localQueue);
							 | 
						|
											return(0);
							 | 
						|
										    }
							 | 
						|
										} else {
							 | 
						|
										    savings = 1;
							 | 
						|
										}
							 | 
						|
										replace = REPLACE_E;
							 | 
						|
									    }
							 | 
						|
									    numOnset = impact * minterms;
							 | 
						|
									} else {
							 | 
						|
									    DdNode *Ereg = Cudd_Regular(E);
							 | 
						|
									    DdNode *TT = cuddT(T);
							 | 
						|
									    DdNode *ET = Cudd_NotCond(cuddT(Ereg), Cudd_IsComplement(E));
							 | 
						|
									    if (T->index == Ereg->index && TT == ET) {
							 | 
						|
										shared = TT;
							 | 
						|
										replace = REPLACE_TT;
							 | 
						|
									    } else {
							 | 
						|
										DdNode *TE = cuddE(T);
							 | 
						|
										DdNode *EE = Cudd_NotCond(cuddE(Ereg), Cudd_IsComplement(E));
							 | 
						|
										if (T->index == Ereg->index && TE == EE) {
							 | 
						|
										    shared = TE;
							 | 
						|
										    replace = REPLACE_TE;
							 | 
						|
										} else {
							 | 
						|
										    replace = REPLACE_N;
							 | 
						|
										}
							 | 
						|
									    }
							 | 
						|
									    numOnset = infoN->mintermsP * impactP + infoN->mintermsN * impactN;
							 | 
						|
									    savings = computeSavings(dd,node,shared,info,localQueue);
							 | 
						|
									    if (shared != NULL) {
							 | 
						|
										NodeData *infoS;
							 | 
						|
										infoS = (NodeData *) cuddHashTableGenericLookup(info->table, Cudd_Regular(shared));
							 | 
						|
										if (Cudd_IsComplement(shared)) {
							 | 
						|
										    numOnset -= (infoS->mintermsN * impactP +
							 | 
						|
											infoS->mintermsP * impactN)/2.0;
							 | 
						|
										} else {
							 | 
						|
										    numOnset -= (infoS->mintermsP * impactP +
							 | 
						|
											infoS->mintermsN * impactN)/2.0;
							 | 
						|
										}
							 | 
						|
										savings--;
							 | 
						|
									    }
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									cuddLevelQueueDequeue(queue,cuddI(dd,node->index));
							 | 
						|
								#if 0
							 | 
						|
									if (replace == REPLACE_T || replace == REPLACE_E)
							 | 
						|
									    (void) printf("node %p: impact = %g numOnset = %g savings %d\n",
							 | 
						|
											  node, impact, numOnset, savings);
							 | 
						|
									else
							 | 
						|
									    (void) printf("node %p: impact = %g/%g numOnset = %g savings %d\n",
							 | 
						|
											  node, impactP, impactN, numOnset, savings);
							 | 
						|
								#endif
							 | 
						|
									if ((1 - numOnset / info->minterms) >
							 | 
						|
									    quality * (1 - (double) savings / info->size)) {
							 | 
						|
									    infoN->replace = (char) replace;
							 | 
						|
									    info->size -= savings;
							 | 
						|
									    info->minterms -=numOnset;
							 | 
						|
								#if 0
							 | 
						|
									    (void) printf("remap(%d): new size = %d new minterms = %g\n",
							 | 
						|
											  replace, info->size, info->minterms);
							 | 
						|
								#endif
							 | 
						|
									    if (replace == REPLACE_N) {
							 | 
						|
										savings -= updateRefs(dd,node,NULL,info,localQueue);
							 | 
						|
									    } else if (replace == REPLACE_T) {
							 | 
						|
										savings -= updateRefs(dd,node,E,info,localQueue);
							 | 
						|
									    } else if (replace == REPLACE_E) {
							 | 
						|
										savings -= updateRefs(dd,node,T,info,localQueue);
							 | 
						|
									    } else {
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
										assert(replace == REPLACE_TT || replace == REPLACE_TE);
							 | 
						|
								#endif
							 | 
						|
										savings -= updateRefs(dd,node,shared,info,localQueue) - 1;
							 | 
						|
									    }
							 | 
						|
									    assert(savings == 0);
							 | 
						|
									} else {
							 | 
						|
									    replace = NOTHING;
							 | 
						|
									}
							 | 
						|
									if (replace == REPLACE_N) continue;
							 | 
						|
									if ((replace == REPLACE_E || replace == NOTHING) &&
							 | 
						|
									    !cuddIsConstant(cuddT(node))) {
							 | 
						|
									    item = (GlobalQueueItem *) cuddLevelQueueEnqueue(queue,cuddT(node),
							 | 
						|
													 cuddI(dd,cuddT(node)->index));
							 | 
						|
									    if (replace == REPLACE_E) {
							 | 
						|
										item->impactP += impactP;
							 | 
						|
										item->impactN += impactN;
							 | 
						|
									    } else {
							 | 
						|
										item->impactP += impactP/2.0;
							 | 
						|
										item->impactN += impactN/2.0;
							 | 
						|
									    }
							 | 
						|
									}
							 | 
						|
									if ((replace == REPLACE_T || replace == NOTHING) &&
							 | 
						|
									    !Cudd_IsConstantInt(cuddE(node))) {
							 | 
						|
									    item = (GlobalQueueItem *) cuddLevelQueueEnqueue(queue,Cudd_Regular(cuddE(node)),
							 | 
						|
													 cuddI(dd,Cudd_Regular(cuddE(node))->index));
							 | 
						|
									    if (Cudd_IsComplement(cuddE(node))) {
							 | 
						|
										if (replace == REPLACE_T) {
							 | 
						|
										    item->impactP += impactN;
							 | 
						|
										    item->impactN += impactP;
							 | 
						|
										} else {
							 | 
						|
										    item->impactP += impactN/2.0;
							 | 
						|
										    item->impactN += impactP/2.0;
							 | 
						|
										}
							 | 
						|
									    } else {
							 | 
						|
										if (replace == REPLACE_T) {
							 | 
						|
										    item->impactP += impactP;
							 | 
						|
										    item->impactN += impactN;
							 | 
						|
										} else {
							 | 
						|
										    item->impactP += impactP/2.0;
							 | 
						|
										    item->impactN += impactN/2.0;
							 | 
						|
										}
							 | 
						|
									    }
							 | 
						|
									}
							 | 
						|
									if ((replace == REPLACE_TT || replace == REPLACE_TE) &&
							 | 
						|
									    !Cudd_IsConstantInt(shared)) {
							 | 
						|
									    item = (GlobalQueueItem *) cuddLevelQueueEnqueue(queue,Cudd_Regular(shared),
							 | 
						|
													 cuddI(dd,Cudd_Regular(shared)->index));
							 | 
						|
									    if (Cudd_IsComplement(shared)) {
							 | 
						|
										if (replace == REPLACE_T) {
							 | 
						|
										    item->impactP += impactN;
							 | 
						|
										    item->impactN += impactP;
							 | 
						|
										} else {
							 | 
						|
										    item->impactP += impactN/2.0;
							 | 
						|
										    item->impactN += impactP/2.0;
							 | 
						|
										}
							 | 
						|
									    } else {
							 | 
						|
										if (replace == REPLACE_T) {
							 | 
						|
										    item->impactP += impactP;
							 | 
						|
										    item->impactN += impactN;
							 | 
						|
										} else {
							 | 
						|
										    item->impactP += impactP/2.0;
							 | 
						|
										    item->impactN += impactN/2.0;
							 | 
						|
										}
							 | 
						|
									    }
							 | 
						|
									}
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    cuddLevelQueueQuit(queue);
							 | 
						|
								    cuddLevelQueueQuit(localQueue);
							 | 
						|
								    return(1);
							 | 
						|
								
							 | 
						|
								} /* end of BAmarkNodes */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								  @brief Builds the subset %BDD for cuddRemapUnderApprox.
							 | 
						|
								
							 | 
						|
								  @details Based on the info table, performs remapping or replacement
							 | 
						|
								  at selected nodes.
							 | 
						|
								
							 | 
						|
								  @return a pointer to the result if successful; NULL otherwise.
							 | 
						|
								
							 | 
						|
								  @sideeffect None
							 | 
						|
								
							 | 
						|
								  @see cuddRemapUnderApprox
							 | 
						|
								
							 | 
						|
								*/
							 | 
						|
								static DdNode *
							 | 
						|
								RAbuildSubset(
							 | 
						|
								  DdManager * dd /**< %DD manager */,
							 | 
						|
								  DdNode * node /**< current node */,
							 | 
						|
								  ApproxInfo * info /**< node info */)
							 | 
						|
								{
							 | 
						|
								    DdNode *Nt, *Ne, *N, *t, *e, *r;
							 | 
						|
								    NodeData *infoN;
							 | 
						|
								
							 | 
						|
								    if (Cudd_IsConstantInt(node))
							 | 
						|
									return(node);
							 | 
						|
								
							 | 
						|
								    N = Cudd_Regular(node);
							 | 
						|
								
							 | 
						|
								    Nt = Cudd_NotCond(cuddT(N), Cudd_IsComplement(node));
							 | 
						|
								    Ne = Cudd_NotCond(cuddE(N), Cudd_IsComplement(node));
							 | 
						|
								
							 | 
						|
								    if ((infoN = (NodeData *) cuddHashTableGenericLookup(info->table, N)) != NULL) {
							 | 
						|
									if (N == node ) {
							 | 
						|
									    if (infoN->resultP != NULL) {
							 | 
						|
										return(infoN->resultP);
							 | 
						|
									    }
							 | 
						|
									} else {
							 | 
						|
									    if (infoN->resultN != NULL) {
							 | 
						|
										return(infoN->resultN);
							 | 
						|
									    }
							 | 
						|
									}
							 | 
						|
									if (infoN->replace == REPLACE_T) {
							 | 
						|
									    r = RAbuildSubset(dd, Ne, info);
							 | 
						|
									    return(r);
							 | 
						|
									} else if (infoN->replace == REPLACE_E) {
							 | 
						|
									    r = RAbuildSubset(dd, Nt, info);
							 | 
						|
									    return(r);
							 | 
						|
									} else if (infoN->replace == REPLACE_N) {
							 | 
						|
									    return(info->zero);
							 | 
						|
									} else if (infoN->replace == REPLACE_TT) {
							 | 
						|
									    DdNode *Ntt = Cudd_NotCond(cuddT(cuddT(N)),
							 | 
						|
												       Cudd_IsComplement(node));
							 | 
						|
									    int index = cuddT(N)->index;
							 | 
						|
									    e = info->zero;
							 | 
						|
									    t = RAbuildSubset(dd, Ntt, info);
							 | 
						|
									    if (t == NULL) {
							 | 
						|
										return(NULL);
							 | 
						|
									    }
							 | 
						|
									    cuddRef(t);
							 | 
						|
									    if (Cudd_IsComplement(t)) {
							 | 
						|
										t = Cudd_Not(t);
							 | 
						|
										e = Cudd_Not(e);
							 | 
						|
										r = (t == e) ? t : cuddUniqueInter(dd, index, t, e);
							 | 
						|
										if (r == NULL) {
							 | 
						|
										    Cudd_RecursiveDeref(dd, t);
							 | 
						|
										    return(NULL);
							 | 
						|
										}
							 | 
						|
										r = Cudd_Not(r);
							 | 
						|
									    } else {
							 | 
						|
										r = (t == e) ? t : cuddUniqueInter(dd, index, t, e);
							 | 
						|
										if (r == NULL) {
							 | 
						|
										    Cudd_RecursiveDeref(dd, t);
							 | 
						|
										    return(NULL);
							 | 
						|
										}
							 | 
						|
									    }
							 | 
						|
									    cuddDeref(t);
							 | 
						|
									    return(r);
							 | 
						|
									} else if (infoN->replace == REPLACE_TE) {
							 | 
						|
									    DdNode *Nte = Cudd_NotCond(cuddE(cuddT(N)),
							 | 
						|
												       Cudd_IsComplement(node));
							 | 
						|
									    unsigned int index = cuddT(N)->index;
							 | 
						|
									    t = info->one;
							 | 
						|
									    e = RAbuildSubset(dd, Nte, info);
							 | 
						|
									    if (e == NULL) {
							 | 
						|
										return(NULL);
							 | 
						|
									    }
							 | 
						|
									    cuddRef(e);
							 | 
						|
									    e = Cudd_Not(e);
							 | 
						|
									    r = (t == e) ? t : cuddUniqueInter(dd, index, t, e);
							 | 
						|
									    if (r == NULL) {
							 | 
						|
										Cudd_RecursiveDeref(dd, e);
							 | 
						|
										return(NULL);
							 | 
						|
									    }
							 | 
						|
									    r =Cudd_Not(r);
							 | 
						|
									    cuddDeref(e);
							 | 
						|
									    return(r);
							 | 
						|
									}
							 | 
						|
								    } else {
							 | 
						|
									(void) fprintf(dd->err,
							 | 
						|
										       "Something is wrong, ought to be in info table\n");
							 | 
						|
									dd->errorCode = CUDD_INTERNAL_ERROR;
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    t = RAbuildSubset(dd, Nt, info);
							 | 
						|
								    if (t == NULL) {
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								    cuddRef(t);
							 | 
						|
								
							 | 
						|
								    e = RAbuildSubset(dd, Ne, info);
							 | 
						|
								    if (e == NULL) {
							 | 
						|
									Cudd_RecursiveDeref(dd,t);
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								    cuddRef(e);
							 | 
						|
								
							 | 
						|
								    if (Cudd_IsComplement(t)) {
							 | 
						|
									t = Cudd_Not(t);
							 | 
						|
									e = Cudd_Not(e);
							 | 
						|
									r = (t == e) ? t : cuddUniqueInter(dd, N->index, t, e);
							 | 
						|
									if (r == NULL) {
							 | 
						|
									    Cudd_RecursiveDeref(dd, e);
							 | 
						|
									    Cudd_RecursiveDeref(dd, t);
							 | 
						|
									    return(NULL);
							 | 
						|
									}
							 | 
						|
									r = Cudd_Not(r);
							 | 
						|
								    } else {
							 | 
						|
									r = (t == e) ? t : cuddUniqueInter(dd, N->index, t, e);
							 | 
						|
									if (r == NULL) {
							 | 
						|
									    Cudd_RecursiveDeref(dd, e);
							 | 
						|
									    Cudd_RecursiveDeref(dd, t);
							 | 
						|
									    return(NULL);
							 | 
						|
									}
							 | 
						|
								    }
							 | 
						|
								    cuddDeref(t);
							 | 
						|
								    cuddDeref(e);
							 | 
						|
								
							 | 
						|
								    if (N == node) {
							 | 
						|
									infoN->resultP = r;
							 | 
						|
								    } else {
							 | 
						|
									infoN->resultN = r;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    return(r);
							 | 
						|
								
							 | 
						|
								} /* end of RAbuildSubset */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								  @brief Finds don't care nodes by traversing f and b in parallel.
							 | 
						|
								
							 | 
						|
								  @return the care status of the visited f node if successful;
							 | 
						|
								  CARE_ERROR otherwise.
							 | 
						|
								
							 | 
						|
								  @sideeffect None
							 | 
						|
								
							 | 
						|
								  @see cuddBiasedUnderApprox
							 | 
						|
								
							 | 
						|
								*/
							 | 
						|
								static int
							 | 
						|
								BAapplyBias(
							 | 
						|
								  DdManager *dd,
							 | 
						|
								  DdNode *f,
							 | 
						|
								  DdNode *b,
							 | 
						|
								  ApproxInfo *info,
							 | 
						|
								  DdHashTable *cache)
							 | 
						|
								{
							 | 
						|
								    DdNode *one, *zero, *res;
							 | 
						|
								    DdNode *Ft, *Fe, *B, *Bt, *Be;
							 | 
						|
								    int topf, topb;
							 | 
						|
								    NodeData *infoF;
							 | 
						|
								    int careT, careE;
							 | 
						|
								
							 | 
						|
								    one = DD_ONE(dd);
							 | 
						|
								    zero = Cudd_Not(one);
							 | 
						|
								
							 | 
						|
								    if ((infoF = (NodeData *) cuddHashTableGenericLookup(info->table, f)) == NULL)
							 | 
						|
									return(CARE_ERROR);
							 | 
						|
								    if (f == one) return(TOTAL_CARE);
							 | 
						|
								    if (b == zero) return(infoF->care);
							 | 
						|
								    if (infoF->care == TOTAL_CARE) return(TOTAL_CARE);
							 | 
						|
								
							 | 
						|
								    if ((f->ref != 1 || Cudd_Regular(b)->ref != 1) &&
							 | 
						|
									(res = cuddHashTableLookup2(cache,f,b)) != NULL) {
							 | 
						|
									if (res->ref == 0) {
							 | 
						|
									    cache->manager->dead++;
							 | 
						|
									    cache->manager->constants.dead++;
							 | 
						|
									}
							 | 
						|
									return(infoF->care);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    topf = dd->perm[f->index];
							 | 
						|
								    B = Cudd_Regular(b);
							 | 
						|
								    topb = cuddI(dd,B->index);
							 | 
						|
								    if (topf <= topb) {
							 | 
						|
									Ft = cuddT(f); Fe = cuddE(f);
							 | 
						|
								    } else {
							 | 
						|
									Ft = Fe = f;
							 | 
						|
								    }
							 | 
						|
								    if (topb <= topf) {
							 | 
						|
									/* We know that b is not constant because f is not. */
							 | 
						|
									Bt = cuddT(B); Be = cuddE(B);
							 | 
						|
									if (Cudd_IsComplement(b)) {
							 | 
						|
									    Bt = Cudd_Not(Bt);
							 | 
						|
									    Be = Cudd_Not(Be);
							 | 
						|
									}
							 | 
						|
								    } else {
							 | 
						|
									Bt = Be = b;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    careT = BAapplyBias(dd, Ft, Bt, info, cache);
							 | 
						|
								    if (careT == CARE_ERROR)
							 | 
						|
									return(CARE_ERROR);
							 | 
						|
								    careE = BAapplyBias(dd, Cudd_Regular(Fe), Be, info, cache);
							 | 
						|
								    if (careE == CARE_ERROR)
							 | 
						|
									return(CARE_ERROR);
							 | 
						|
								    if (careT == TOTAL_CARE && careE == TOTAL_CARE) {
							 | 
						|
									infoF->care = TOTAL_CARE;
							 | 
						|
								    } else {
							 | 
						|
									infoF->care = CARE;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    if (f->ref != 1 || Cudd_Regular(b)->ref != 1) {
							 | 
						|
									ptrint fanout = (ptrint) f->ref * Cudd_Regular(b)->ref;
							 | 
						|
									cuddSatDec(fanout);
							 | 
						|
									if (!cuddHashTableInsert2(cache,f,b,one,fanout)) {
							 | 
						|
									    return(CARE_ERROR);
							 | 
						|
									}
							 | 
						|
								    }
							 | 
						|
								    return(infoF->care);
							 | 
						|
								
							 | 
						|
								} /* end of BAapplyBias */
							 |