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.
		
		
		
		
		
			
		
			
				
					
					
						
							2204 lines
						
					
					
						
							68 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							2204 lines
						
					
					
						
							68 KiB
						
					
					
				
								/**CFile***********************************************************************
							 | 
						|
								
							 | 
						|
								  FileName    [cuddApprox.c]
							 | 
						|
								
							 | 
						|
								  PackageName [cudd]
							 | 
						|
								
							 | 
						|
								  Synopsis    [Procedures to approximate a given BDD.]
							 | 
						|
								
							 | 
						|
								  Description [External procedures provided by this module:
							 | 
						|
								                <ul>
							 | 
						|
										<li> Cudd_UnderApprox()
							 | 
						|
										<li> Cudd_OverApprox()
							 | 
						|
										<li> Cudd_RemapUnderApprox()
							 | 
						|
										<li> Cudd_RemapOverApprox()
							 | 
						|
										<li> Cudd_BiasedUnderApprox()
							 | 
						|
										<li> Cudd_BiasedOverApprox()
							 | 
						|
										</ul>
							 | 
						|
									       Internal procedures included in this module:
							 | 
						|
										<ul>
							 | 
						|
										<li> cuddUnderApprox()
							 | 
						|
										<li> cuddRemapUnderApprox()
							 | 
						|
										<li> cuddBiasedUnderApprox()
							 | 
						|
										</ul>
							 | 
						|
									       Static procedures included in this module:
							 | 
						|
										<ul>
							 | 
						|
								                <li> updateParity()
							 | 
						|
										<li> gatherInfoAux()
							 | 
						|
										<li> gatherInfo()
							 | 
						|
										<li> computeSavings()
							 | 
						|
										<li> updateRefs()
							 | 
						|
										<li> UAmarkNodes()
							 | 
						|
										<li> UAbuildSubset()
							 | 
						|
										<li> RAmarkNodes()
							 | 
						|
										<li> BAmarkNodes()
							 | 
						|
										<li> RAbuildSubset()
							 | 
						|
								                <li> BAapplyBias()
							 | 
						|
										</ul>
							 | 
						|
										]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [cuddSubsetHB.c cuddSubsetSP.c cuddGenCof.c]
							 | 
						|
								
							 | 
						|
								  Author      [Fabio Somenzi]
							 | 
						|
								
							 | 
						|
								  Copyright   [Copyright (c) 1995-2012, 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.]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								
							 | 
						|
								#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                                                         */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								/* Data structure to store the information on each node. 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;
							 | 
						|
								
							 | 
						|
								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;
							 | 
						|
								
							 | 
						|
								/* 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;
							 | 
						|
								 
							 | 
						|
								typedef struct LocalQueueItem {
							 | 
						|
								    struct LocalQueueItem *next;
							 | 
						|
								    struct LocalQueueItem *cnext;
							 | 
						|
								    DdNode *node;
							 | 
						|
								    int localRef;
							 | 
						|
								} LocalQueueItem;
							 | 
						|
								
							 | 
						|
								    
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Variable declarations                                                     */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								#ifndef lint
							 | 
						|
								static char rcsid[] DD_UNUSED = "$Id: cuddApprox.c,v 1.31 2012/02/05 04:38:07 fabio Exp $";
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Macro declarations                                                        */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								/**AutomaticStart*************************************************************/
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* 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);
							 | 
						|
								
							 | 
						|
								/**AutomaticEnd***************************************************************/
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Definition of exported functions                                          */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis [Extracts a dense subset from a BDD with Shiple's
							 | 
						|
								  underapproximation method.]
							 | 
						|
								
							 | 
						|
								  Description [Extracts a dense subset from a BDD. 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.  Returns a pointer to the BDD of the subset if
							 | 
						|
								  successful. NULL if the procedure runs out of memory. 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.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [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);
							 | 
						|
								
							 | 
						|
								    return(subset);
							 | 
						|
								
							 | 
						|
								} /* end of Cudd_UnderApprox */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Extracts a dense superset from a BDD with Shiple's
							 | 
						|
								  underapproximation method.]
							 | 
						|
								
							 | 
						|
								  Description [Extracts a dense superset from a BDD. 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.
							 | 
						|
								  Returns a pointer to the BDD of the superset if successful. NULL if
							 | 
						|
								  intermediate result causes the procedure to run out of memory. 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.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [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);
							 | 
						|
								    
							 | 
						|
								    return(Cudd_NotCond(subset, (subset != NULL)));
							 | 
						|
								    
							 | 
						|
								} /* end of Cudd_OverApprox */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis [Extracts a dense subset from a BDD with the remapping
							 | 
						|
								  underapproximation method.]
							 | 
						|
								
							 | 
						|
								  Description [Extracts a dense subset from a BDD. This procedure uses
							 | 
						|
								  a remapping technique and density as the cost function.
							 | 
						|
								  Returns a pointer to the BDD of the subset if
							 | 
						|
								  successful. NULL if the procedure runs out of memory. 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.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [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);
							 | 
						|
								
							 | 
						|
								    return(subset);
							 | 
						|
								
							 | 
						|
								} /* end of Cudd_RemapUnderApprox */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Extracts a dense superset from a BDD with the remapping
							 | 
						|
								  underapproximation method.]
							 | 
						|
								
							 | 
						|
								  Description [Extracts a dense superset from a BDD. 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.
							 | 
						|
								  Returns a pointer to the BDD of the superset if successful. NULL if
							 | 
						|
								  intermediate result causes the procedure to run out of memory. 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.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [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);
							 | 
						|
								    
							 | 
						|
								    return(Cudd_NotCond(subset, (subset != NULL)));
							 | 
						|
								    
							 | 
						|
								} /* end of Cudd_RemapOverApprox */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis [Extracts a dense subset from a BDD with the biased
							 | 
						|
								  underapproximation method.]
							 | 
						|
								
							 | 
						|
								  Description [Extracts a dense subset from a BDD. 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.
							 | 
						|
								  Returns a pointer to the BDD of the subset if
							 | 
						|
								  successful. NULL if the procedure runs out of memory. 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.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [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);
							 | 
						|
								
							 | 
						|
								    return(subset);
							 | 
						|
								
							 | 
						|
								} /* end of Cudd_BiasedUnderApprox */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Extracts a dense superset from a BDD with the biased
							 | 
						|
								  underapproximation method.]
							 | 
						|
								
							 | 
						|
								  Description [Extracts a dense superset from a BDD. 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.
							 | 
						|
								  Returns a pointer to the BDD of the superset if successful. NULL if
							 | 
						|
								  intermediate result causes the procedure to run out of memory. 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.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [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);
							 | 
						|
								    
							 | 
						|
								    return(Cudd_NotCond(subset, (subset != NULL)));
							 | 
						|
								    
							 | 
						|
								} /* end of Cudd_BiasedOverApprox */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Definition of internal functions                                          */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Applies Tom Shiple's underappoximation algorithm.]
							 | 
						|
								
							 | 
						|
								  Description [Applies Tom Shiple's underappoximation algorithm. 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>
							 | 
						|
								  Returns the approximated BDD if successful; NULL otherwise.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [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_IsConstant(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 */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Applies the remapping underappoximation algorithm.]
							 | 
						|
								
							 | 
						|
								  Description [Applies the remapping underappoximation algorithm.
							 | 
						|
								  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>
							 | 
						|
								  Returns the approximated BDD if successful; NULL otherwise.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [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_IsConstant(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 */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Applies the biased remapping underappoximation algorithm.]
							 | 
						|
								
							 | 
						|
								  Description [Applies the biased remapping underappoximation algorithm.
							 | 
						|
								  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>
							 | 
						|
								  Returns the approximated BDD if successful; NULL otherwise.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [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_IsConstant(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                                            */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Recursively update the parity of the paths reaching a node.]
							 | 
						|
								
							 | 
						|
								  Description [Recursively update the parity of the paths reaching a node.
							 | 
						|
								  Assumes that node is regular and propagates the invariant.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [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_IsConstant(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 */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Recursively counts minterms and computes reference counts
							 | 
						|
								  of each node in the BDD.]
							 | 
						|
								
							 | 
						|
								  Description [Recursively counts minterms and computes reference
							 | 
						|
								  counts of each node in the BDD.  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.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [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 */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Gathers information about each node.]
							 | 
						|
								
							 | 
						|
								  Description [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. Returns a pointer to the data structure holding the
							 | 
						|
								  information gathered if successful; NULL otherwise.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [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);
							 | 
						|
									FREE(info);
							 | 
						|
									cuddHashTableGenericQuit(info->table);
							 | 
						|
									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 */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Counts the nodes that would be eliminated if a given node
							 | 
						|
								  were replaced by zero.]
							 | 
						|
								
							 | 
						|
								  Description [Counts the nodes that would be eliminated if a given
							 | 
						|
								  node were replaced by zero. 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. Returns
							 | 
						|
								  the count (always striclty positive) if successful; 0 otherwise.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [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);
							 | 
						|
								    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 */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Update function reference counts.]
							 | 
						|
								
							 | 
						|
								  Description [Update function reference counts to account for replacement.
							 | 
						|
								  Returns the number of nodes saved if successful; 0 otherwise.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [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 */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Marks nodes for replacement by zero.]
							 | 
						|
								
							 | 
						|
								  Description [Marks nodes for replacement by zero. Returns 1 if successful;
							 | 
						|
								  0 otherwise.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [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);
							 | 
						|
								    if (queue == NULL) {
							 | 
						|
									return(0);
							 | 
						|
								    }
							 | 
						|
								    localQueue = cuddLevelQueueInit(dd->size,sizeof(LocalQueueItem),
							 | 
						|
												    dd->initSlots);
							 | 
						|
								    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_IsConstant(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 */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Builds the subset BDD.] 
							 | 
						|
								
							 | 
						|
								  Description [Builds the subset BDD. Based on the info table,
							 | 
						|
								  replaces selected nodes by zero. Returns a pointer to the result if
							 | 
						|
								  successful; NULL otherwise.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [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_IsConstant(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 */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Marks nodes for remapping.]
							 | 
						|
								
							 | 
						|
								  Description [Marks nodes for remapping. Returns 1 if successful; 0
							 | 
						|
								  otherwise.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [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);
							 | 
						|
								    if (queue == NULL) {
							 | 
						|
									return(0);
							 | 
						|
								    }
							 | 
						|
								    localQueue = cuddLevelQueueInit(dd->size,sizeof(LocalQueueItem),
							 | 
						|
												    dd->initSlots);
							 | 
						|
								    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_IsConstant(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_IsConstant(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_IsConstant(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 */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Marks nodes for remapping.]
							 | 
						|
								
							 | 
						|
								  Description [Marks nodes for remapping. Returns 1 if successful; 0
							 | 
						|
								  otherwise.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [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);
							 | 
						|
								    if (queue == NULL) {
							 | 
						|
									return(0);
							 | 
						|
								    }
							 | 
						|
								    localQueue = cuddLevelQueueInit(dd->size,sizeof(LocalQueueItem),
							 | 
						|
												    dd->initSlots);
							 | 
						|
								    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_IsConstant(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_IsConstant(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_IsConstant(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_IsConstant(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_IsConstant(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_IsConstant(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_IsConstant(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 */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis [Builds the subset BDD for cuddRemapUnderApprox.]
							 | 
						|
								
							 | 
						|
								  Description [Builds the subset BDDfor cuddRemapUnderApprox.  Based
							 | 
						|
								  on the info table, performs remapping or replacement at selected
							 | 
						|
								  nodes. Returns a pointer to the result if successful; NULL
							 | 
						|
								  otherwise.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [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_IsConstant(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));
							 | 
						|
									    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 */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Finds don't care nodes.]
							 | 
						|
								
							 | 
						|
								  Description [Finds don't care nodes by traversing f and b in parallel.
							 | 
						|
								  Returns the care status of the visited f node if successful; CARE_ERROR
							 | 
						|
								  otherwise.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [cuddBiasedUnderApprox]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								static int
							 | 
						|
								BAapplyBias(
							 | 
						|
								  DdManager *dd,
							 | 
						|
								  DdNode *f,
							 | 
						|
								  DdNode *b,
							 | 
						|
								  ApproxInfo *info,
							 | 
						|
								  DdHashTable *cache)
							 | 
						|
								{
							 | 
						|
								    DdNode *one, *zero, *res;
							 | 
						|
								    DdNode *Ft, *Fe, *B, *Bt, *Be;
							 | 
						|
								    unsigned 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 */
							 |