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.
		
		
		
		
		
			
		
			
				
					
					
						
							1365 lines
						
					
					
						
							38 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							1365 lines
						
					
					
						
							38 KiB
						
					
					
				| /**CFile*********************************************************************** | |
|  | |
|   FileName    [cuddLinear.c] | |
|  | |
|   PackageName [cudd] | |
|  | |
|   Synopsis    [Functions for DD reduction by linear transformations.] | |
|  | |
|   Description [ Internal procedures included in this module: | |
| 		<ul> | |
| 		<li> cuddLinearAndSifting() | |
| 		<li> cuddLinearInPlace() | |
| 		<li> cuddUpdateInteractionMatrix() | |
| 		<li> cuddInitLinear() | |
| 		<li> cuddResizeLinear() | |
| 		</ul> | |
| 	Static procedures included in this module: | |
| 		<ul> | |
| 		<li> ddLinearUniqueCompare() | |
| 		<li> ddLinearAndSiftingAux() | |
| 		<li> ddLinearAndSiftingUp() | |
| 		<li> ddLinearAndSiftingDown() | |
| 		<li> ddLinearAndSiftingBackward() | |
| 		<li> ddUndoMoves() | |
| 		<li> cuddXorLinear() | |
| 		</ul>] | |
|  | |
|   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.] | |
|  | |
| ******************************************************************************/ | |
| 
 | |
| #include "util.h" | |
| #include "cuddInt.h" | |
|  | |
| /*---------------------------------------------------------------------------*/ | |
| /* Constant declarations                                                     */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| #define CUDD_SWAP_MOVE 0 | |
| #define CUDD_LINEAR_TRANSFORM_MOVE 1 | |
| #define CUDD_INVERSE_TRANSFORM_MOVE 2 | |
| #if SIZEOF_LONG == 8 | |
| #define BPL 64 | |
| #define LOGBPL 6 | |
| #else | |
| #define BPL 32 | |
| #define LOGBPL 5 | |
| #endif | |
|  | |
| /*---------------------------------------------------------------------------*/ | |
| /* Stucture declarations                                                     */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Type declarations                                                         */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Variable declarations                                                     */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| #ifndef lint | |
| static char rcsid[] DD_UNUSED = "$Id: cuddLinear.c,v 1.29 2012/02/05 01:07:19 fabio Exp $"; | |
| #endif | |
|  | |
| static	int	*entry; | |
| 
 | |
| #ifdef DD_STATS | |
| extern	int	ddTotalNumberSwapping; | |
| extern	int	ddTotalNISwaps; | |
| static	int	ddTotalNumberLinearTr; | |
| #endif | |
|  | |
| #ifdef DD_DEBUG | |
| static	int	zero = 0; | |
| #endif | |
|  | |
| /*---------------------------------------------------------------------------*/ | |
| /* Macro declarations                                                        */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| /**AutomaticStart*************************************************************/ | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Static function prototypes                                                */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| static int ddLinearUniqueCompare (int *ptrX, int *ptrY); | |
| static int ddLinearAndSiftingAux (DdManager *table, int x, int xLow, int xHigh); | |
| static Move * ddLinearAndSiftingUp (DdManager *table, int y, int xLow, Move *prevMoves); | |
| static Move * ddLinearAndSiftingDown (DdManager *table, int x, int xHigh, Move *prevMoves); | |
| static int ddLinearAndSiftingBackward (DdManager *table, int size, Move *moves); | |
| static Move* ddUndoMoves (DdManager *table, Move *moves); | |
| static void cuddXorLinear (DdManager *table, int x, int y); | |
| 
 | |
| /**AutomaticEnd***************************************************************/ | |
| 
 | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Definition of exported functions                                          */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Prints the linear transform matrix.] | |
|  | |
|   Description [Prints the linear transform matrix. Returns 1 in case of | |
|   success; 0 otherwise.] | |
|  | |
|   SideEffects [none] | |
|  | |
|   SeeAlso     [] | |
|  | |
| ******************************************************************************/ | |
| int | |
| Cudd_PrintLinear( | |
|   DdManager * table) | |
| { | |
|     int i,j,k; | |
|     int retval; | |
|     int nvars = table->linearSize; | |
|     int wordsPerRow = ((nvars - 1) >> LOGBPL) + 1; | |
|     long word; | |
| 
 | |
|     for (i = 0; i < nvars; i++) { | |
| 	for (j = 0; j < wordsPerRow; j++) { | |
| 	    word = table->linear[i*wordsPerRow + j]; | |
| 	    for (k = 0; k < BPL; k++) { | |
| 		retval = fprintf(table->out,"%ld",word & 1); | |
| 		if (retval == 0) return(0); | |
| 		word >>= 1; | |
| 	    } | |
| 	} | |
| 	retval = fprintf(table->out,"\n"); | |
| 	if (retval == 0) return(0); | |
|     } | |
|     return(1); | |
| 
 | |
| } /* end of Cudd_PrintLinear */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Reads an entry of the linear transform matrix.] | |
|  | |
|   Description [Reads an entry of the linear transform matrix.] | |
|  | |
|   SideEffects [none] | |
|  | |
|   SeeAlso     [] | |
|  | |
| ******************************************************************************/ | |
| int | |
| Cudd_ReadLinear( | |
|   DdManager * table /* CUDD manager */, | |
|   int  x /* row index */, | |
|   int  y /* column index */) | |
| { | |
|     int nvars = table->size; | |
|     int wordsPerRow = ((nvars - 1) >> LOGBPL) + 1; | |
|     long word; | |
|     int bit; | |
|     int result; | |
| 
 | |
|     assert(table->size == table->linearSize); | |
| 
 | |
|     word = wordsPerRow * x + (y >> LOGBPL); | |
|     bit  = y & (BPL-1); | |
|     result = (int) ((table->linear[word] >> bit) & 1); | |
|     return(result); | |
| 
 | |
| } /* end of Cudd_ReadLinear */ | |
| 
 | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Definition of internal functions                                          */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [BDD reduction based on combination of sifting and linear | |
|   transformations.] | |
|  | |
|   Description [BDD reduction based on combination of sifting and linear | |
|   transformations.  Assumes that no dead nodes are present. | |
|     <ol> | |
|     <li> Order all the variables according to the number of entries | |
|     in each unique table. | |
|     <li> Sift the variable up and down, remembering each time the | |
|     total size of the DD heap. At each position, linear transformation | |
|     of the two adjacent variables is tried and is accepted if it reduces | |
|     the size of the DD. | |
|     <li> Select the best permutation. | |
|     <li> Repeat 3 and 4 for all variables. | |
|     </ol> | |
|   Returns 1 if successful; 0 otherwise.] | |
|  | |
|   SideEffects [None] | |
|  | |
| ******************************************************************************/ | |
| int | |
| cuddLinearAndSifting( | |
|   DdManager * table, | |
|   int  lower, | |
|   int  upper) | |
| { | |
|     int		i; | |
|     int		*var; | |
|     int		size; | |
|     int		x; | |
|     int		result; | |
| #ifdef DD_STATS | |
|     int		previousSize; | |
| #endif | |
|  | |
| #ifdef DD_STATS | |
|     ddTotalNumberLinearTr = 0; | |
| #endif | |
|  | |
|     size = table->size; | |
| 
 | |
|     var = NULL; | |
|     entry = NULL; | |
|     if (table->linear == NULL) { | |
| 	result = cuddInitLinear(table); | |
| 	if (result == 0) goto cuddLinearAndSiftingOutOfMem; | |
| #if 0 | |
| 	(void) fprintf(table->out,"\n"); | |
| 	result = Cudd_PrintLinear(table); | |
| 	if (result == 0) goto cuddLinearAndSiftingOutOfMem; | |
| #endif | |
|     } else if (table->size != table->linearSize) { | |
| 	result = cuddResizeLinear(table); | |
| 	if (result == 0) goto cuddLinearAndSiftingOutOfMem; | |
| #if 0 | |
| 	(void) fprintf(table->out,"\n"); | |
| 	result = Cudd_PrintLinear(table); | |
| 	if (result == 0) goto cuddLinearAndSiftingOutOfMem; | |
| #endif | |
|     } | |
| 
 | |
|     /* Find order in which to sift variables. */ | |
|     entry = ALLOC(int,size); | |
|     if (entry == NULL) { | |
| 	table->errorCode = CUDD_MEMORY_OUT; | |
| 	goto cuddLinearAndSiftingOutOfMem; | |
|     } | |
|     var = ALLOC(int,size); | |
|     if (var == NULL) { | |
| 	table->errorCode = CUDD_MEMORY_OUT; | |
| 	goto cuddLinearAndSiftingOutOfMem; | |
|     } | |
| 
 | |
|     for (i = 0; i < size; i++) { | |
| 	x = table->perm[i]; | |
| 	entry[i] = table->subtables[x].keys; | |
| 	var[i] = i; | |
|     } | |
| 
 | |
|     qsort((void *)var,size,sizeof(int),(DD_QSFP)ddLinearUniqueCompare); | |
| 
 | |
|     /* Now sift. */ | |
|     for (i = 0; i < ddMin(table->siftMaxVar,size); i++) { | |
| 	x = table->perm[var[i]]; | |
| 	if (x < lower || x > upper) continue; | |
| #ifdef DD_STATS | |
| 	previousSize = table->keys - table->isolated; | |
| #endif | |
| 	result = ddLinearAndSiftingAux(table,x,lower,upper); | |
| 	if (!result) goto cuddLinearAndSiftingOutOfMem; | |
| #ifdef DD_STATS | |
| 	if (table->keys < (unsigned) previousSize + table->isolated) { | |
| 	    (void) fprintf(table->out,"-"); | |
| 	} else if (table->keys > (unsigned) previousSize + table->isolated) { | |
| 	    (void) fprintf(table->out,"+");	/* should never happen */ | |
| 	    (void) fprintf(table->out,"\nSize increased from %d to %d while sifting variable %d\n", previousSize, table->keys - table->isolated, var[i]); | |
| 	} else { | |
| 	    (void) fprintf(table->out,"="); | |
| 	} | |
| 	fflush(table->out); | |
| #endif | |
| #ifdef DD_DEBUG | |
| 	(void) Cudd_DebugCheck(table); | |
| #endif | |
|     } | |
| 
 | |
|     FREE(var); | |
|     FREE(entry); | |
| 
 | |
| #ifdef DD_STATS | |
|     (void) fprintf(table->out,"\n#:L_LINSIFT %8d: linear trans.", | |
| 		   ddTotalNumberLinearTr); | |
| #endif | |
|  | |
|     return(1); | |
| 
 | |
| cuddLinearAndSiftingOutOfMem: | |
| 
 | |
|     if (entry != NULL) FREE(entry); | |
|     if (var != NULL) FREE(var); | |
| 
 | |
|     return(0); | |
| 
 | |
| } /* end of cuddLinearAndSifting */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Linearly combines two adjacent variables.] | |
|  | |
|   Description [Linearly combines two adjacent variables. Specifically, | |
|   replaces the top variable with the exclusive nor of the two variables. | |
|   It assumes that no dead nodes are present on entry to this | |
|   procedure.  The procedure then guarantees that no dead nodes will be | |
|   present when it terminates.  cuddLinearInPlace assumes that x < | |
|   y.  Returns the number of keys in the table if successful; 0 | |
|   otherwise.] | |
|  | |
|   SideEffects [The two subtables corrresponding to variables x and y are | |
|   modified. The global counters of the unique table are also affected.] | |
|  | |
|   SeeAlso     [cuddSwapInPlace] | |
|  | |
| ******************************************************************************/ | |
| int | |
| cuddLinearInPlace( | |
|   DdManager * table, | |
|   int  x, | |
|   int  y) | |
| { | |
|     DdNodePtr *xlist, *ylist; | |
|     int    xindex, yindex; | |
|     int    xslots, yslots; | |
|     int    xshift, yshift; | |
|     int    oldxkeys, oldykeys; | |
|     int    newxkeys, newykeys; | |
|     int    comple, newcomplement; | |
|     int    i; | |
|     int    posn; | |
|     int    isolated; | |
|     DdNode *f,*f0,*f1,*f01,*f00,*f11,*f10,*newf1,*newf0; | |
|     DdNode *g,*next,*last; | |
|     DdNodePtr *previousP; | |
|     DdNode *tmp; | |
|     DdNode *sentinel = &(table->sentinel); | |
| #ifdef DD_DEBUG | |
|     int    count, idcheck; | |
| #endif | |
|  | |
| #ifdef DD_DEBUG | |
|     assert(x < y); | |
|     assert(cuddNextHigh(table,x) == y); | |
|     assert(table->subtables[x].keys != 0); | |
|     assert(table->subtables[y].keys != 0); | |
|     assert(table->subtables[x].dead == 0); | |
|     assert(table->subtables[y].dead == 0); | |
| #endif | |
|  | |
|     xindex = table->invperm[x]; | |
|     yindex = table->invperm[y]; | |
| 
 | |
|     if (cuddTestInteract(table,xindex,yindex)) { | |
| #ifdef DD_STATS | |
| 	ddTotalNumberLinearTr++; | |
| #endif | |
| 	/* Get parameters of x subtable. */ | |
| 	xlist = table->subtables[x].nodelist; | |
| 	oldxkeys = table->subtables[x].keys; | |
| 	xslots = table->subtables[x].slots; | |
| 	xshift = table->subtables[x].shift; | |
| 
 | |
| 	/* Get parameters of y subtable. */ | |
| 	ylist = table->subtables[y].nodelist; | |
| 	oldykeys = table->subtables[y].keys; | |
| 	yslots = table->subtables[y].slots; | |
| 	yshift = table->subtables[y].shift; | |
| 
 | |
| 	newxkeys = 0; | |
| 	newykeys = oldykeys; | |
| 
 | |
| 	/* Check whether the two projection functions involved in this | |
| 	** swap are isolated. At the end, we'll be able to tell how many | |
| 	** isolated projection functions are there by checking only these | |
| 	** two functions again. This is done to eliminate the isolated | |
| 	** projection functions from the node count. | |
| 	*/ | |
| 	isolated = - ((table->vars[xindex]->ref == 1) + | |
| 		     (table->vars[yindex]->ref == 1)); | |
| 
 | |
| 	/* The nodes in the x layer are put in a chain. | |
| 	** The chain is handled as a FIFO; g points to the beginning and | |
| 	** last points to the end. | |
| 	*/ | |
| 	g = NULL; | |
| #ifdef DD_DEBUG | |
| 	last = NULL; | |
| #endif | |
| 	for (i = 0; i < xslots; i++) { | |
| 	    f = xlist[i]; | |
| 	    if (f == sentinel) continue; | |
| 	    xlist[i] = sentinel; | |
| 	    if (g == NULL) { | |
| 		g = f; | |
| 	    } else { | |
| 		last->next = f; | |
| 	    } | |
| 	    while ((next = f->next) != sentinel) { | |
| 		f = next; | |
| 	    } /* while there are elements in the collision chain */ | |
| 	    last = f; | |
| 	} /* for each slot of the x subtable */ | |
| #ifdef DD_DEBUG | |
| 	/* last is always assigned in the for loop because there is at | |
| 	** least one key */ | |
| 	assert(last != NULL); | |
| #endif | |
| 	last->next = NULL; | |
| 
 | |
| #ifdef DD_COUNT | |
| 	table->swapSteps += oldxkeys; | |
| #endif | |
| 	/* Take care of the x nodes that must be re-expressed. | |
| 	** They form a linked list pointed by g. | |
| 	*/ | |
| 	f = g; | |
| 	while (f != NULL) { | |
| 	    next = f->next; | |
| 	    /* Find f1, f0, f11, f10, f01, f00. */ | |
| 	    f1 = cuddT(f); | |
| #ifdef DD_DEBUG | |
| 	    assert(!(Cudd_IsComplement(f1))); | |
| #endif | |
| 	    if ((int) f1->index == yindex) { | |
| 		f11 = cuddT(f1); f10 = cuddE(f1); | |
| 	    } else { | |
| 		f11 = f10 = f1; | |
| 	    } | |
| #ifdef DD_DEBUG | |
| 	    assert(!(Cudd_IsComplement(f11))); | |
| #endif | |
| 	    f0 = cuddE(f); | |
| 	    comple = Cudd_IsComplement(f0); | |
| 	    f0 = Cudd_Regular(f0); | |
| 	    if ((int) f0->index == yindex) { | |
| 		f01 = cuddT(f0); f00 = cuddE(f0); | |
| 	    } else { | |
| 		f01 = f00 = f0; | |
| 	    } | |
| 	    if (comple) { | |
| 		f01 = Cudd_Not(f01); | |
| 		f00 = Cudd_Not(f00); | |
| 	    } | |
| 	    /* Decrease ref count of f1. */ | |
| 	    cuddSatDec(f1->ref); | |
| 	    /* Create the new T child. */ | |
| 	    if (f11 == f00) { | |
| 		newf1 = f11; | |
| 		cuddSatInc(newf1->ref); | |
| 	    } else { | |
| 		/* Check ylist for triple (yindex,f11,f00). */ | |
| 		posn = ddHash(f11, f00, yshift); | |
| 		/* For each element newf1 in collision list ylist[posn]. */ | |
| 		previousP = &(ylist[posn]); | |
| 		newf1 = *previousP; | |
| 		while (f11 < cuddT(newf1)) { | |
| 		    previousP = &(newf1->next); | |
| 		    newf1 = *previousP; | |
| 		} | |
| 		while (f11 == cuddT(newf1) && f00 < cuddE(newf1)) { | |
| 		    previousP = &(newf1->next); | |
| 		    newf1 = *previousP; | |
| 		} | |
| 		if (cuddT(newf1) == f11 && cuddE(newf1) == f00) { | |
| 		    cuddSatInc(newf1->ref); | |
| 		} else { /* no match */ | |
| 		    newf1 = cuddDynamicAllocNode(table); | |
| 		    if (newf1 == NULL) | |
| 			goto cuddLinearOutOfMem; | |
| 		    newf1->index = yindex; newf1->ref = 1; | |
| 		    cuddT(newf1) = f11; | |
| 		    cuddE(newf1) = f00; | |
| 		    /* Insert newf1 in the collision list ylist[posn]; | |
| 		    ** increase the ref counts of f11 and f00. | |
| 		    */ | |
| 		    newykeys++; | |
| 		    newf1->next = *previousP; | |
| 		    *previousP = newf1; | |
| 		    cuddSatInc(f11->ref); | |
| 		    tmp = Cudd_Regular(f00); | |
| 		    cuddSatInc(tmp->ref); | |
| 		} | |
| 	    } | |
| 	    cuddT(f) = newf1; | |
| #ifdef DD_DEBUG | |
| 	    assert(!(Cudd_IsComplement(newf1))); | |
| #endif | |
|  | |
| 	    /* Do the same for f0, keeping complement dots into account. */ | |
| 	    /* decrease ref count of f0 */ | |
| 	    tmp = Cudd_Regular(f0); | |
| 	    cuddSatDec(tmp->ref); | |
| 	    /* create the new E child */ | |
| 	    if (f01 == f10) { | |
| 		newf0 = f01; | |
| 		tmp = Cudd_Regular(newf0); | |
| 		cuddSatInc(tmp->ref); | |
| 	    } else { | |
| 		/* make sure f01 is regular */ | |
| 		newcomplement = Cudd_IsComplement(f01); | |
| 		if (newcomplement) { | |
| 		    f01 = Cudd_Not(f01); | |
| 		    f10 = Cudd_Not(f10); | |
| 		} | |
| 		/* Check ylist for triple (yindex,f01,f10). */ | |
| 		posn = ddHash(f01, f10, yshift); | |
| 		/* For each element newf0 in collision list ylist[posn]. */ | |
| 		previousP = &(ylist[posn]); | |
| 		newf0 = *previousP; | |
| 		while (f01 < cuddT(newf0)) { | |
| 		    previousP = &(newf0->next); | |
| 		    newf0 = *previousP; | |
| 		} | |
| 		while (f01 == cuddT(newf0) && f10 < cuddE(newf0)) { | |
| 		    previousP = &(newf0->next); | |
| 		    newf0 = *previousP; | |
| 		} | |
| 		if (cuddT(newf0) == f01 && cuddE(newf0) == f10) { | |
| 		    cuddSatInc(newf0->ref); | |
| 		} else { /* no match */ | |
| 		    newf0 = cuddDynamicAllocNode(table); | |
| 		    if (newf0 == NULL) | |
| 			goto cuddLinearOutOfMem; | |
| 		    newf0->index = yindex; newf0->ref = 1; | |
| 		    cuddT(newf0) = f01; | |
| 		    cuddE(newf0) = f10; | |
| 		    /* Insert newf0 in the collision list ylist[posn]; | |
| 		    ** increase the ref counts of f01 and f10. | |
| 		    */ | |
| 		    newykeys++; | |
| 		    newf0->next = *previousP; | |
| 		    *previousP = newf0; | |
| 		    cuddSatInc(f01->ref); | |
| 		    tmp = Cudd_Regular(f10); | |
| 		    cuddSatInc(tmp->ref); | |
| 		} | |
| 		if (newcomplement) { | |
| 		    newf0 = Cudd_Not(newf0); | |
| 		} | |
| 	    } | |
| 	    cuddE(f) = newf0; | |
| 
 | |
| 	    /* Re-insert the modified f in xlist. | |
| 	    ** The modified f does not already exists in xlist. | |
| 	    ** (Because of the uniqueness of the cofactors.) | |
| 	    */ | |
| 	    posn = ddHash(newf1, newf0, xshift); | |
| 	    newxkeys++; | |
| 	    previousP = &(xlist[posn]); | |
| 	    tmp = *previousP; | |
| 	    while (newf1 < cuddT(tmp)) { | |
| 		previousP = &(tmp->next); | |
| 		tmp = *previousP; | |
| 	    } | |
| 	    while (newf1 == cuddT(tmp) && newf0 < cuddE(tmp)) { | |
| 		previousP = &(tmp->next); | |
| 		tmp = *previousP; | |
| 	    } | |
| 	    f->next = *previousP; | |
| 	    *previousP = f; | |
| 	    f = next; | |
| 	} /* while f != NULL */ | |
| 
 | |
| 	/* GC the y layer. */ | |
| 
 | |
| 	/* For each node f in ylist. */ | |
| 	for (i = 0; i < yslots; i++) { | |
| 	    previousP = &(ylist[i]); | |
| 	    f = *previousP; | |
| 	    while (f != sentinel) { | |
| 		next = f->next; | |
| 		if (f->ref == 0) { | |
| 		    tmp = cuddT(f); | |
| 		    cuddSatDec(tmp->ref); | |
| 		    tmp = Cudd_Regular(cuddE(f)); | |
| 		    cuddSatDec(tmp->ref); | |
| 		    cuddDeallocNode(table,f); | |
| 		    newykeys--; | |
| 		} else { | |
| 		    *previousP = f; | |
| 		    previousP = &(f->next); | |
| 		} | |
| 		f = next; | |
| 	    } /* while f */ | |
| 	    *previousP = sentinel; | |
| 	} /* for every collision list */ | |
| 
 | |
| #ifdef DD_DEBUG | |
| #if 0 | |
| 	(void) fprintf(table->out,"Linearly combining %d and %d\n",x,y); | |
| #endif | |
| 	count = 0; | |
| 	idcheck = 0; | |
| 	for (i = 0; i < yslots; i++) { | |
| 	    f = ylist[i]; | |
| 	    while (f != sentinel) { | |
| 		count++; | |
| 		if (f->index != (DdHalfWord) yindex) | |
| 		    idcheck++; | |
| 		f = f->next; | |
| 	    } | |
| 	} | |
| 	if (count != newykeys) { | |
| 	    fprintf(table->err,"Error in finding newykeys\toldykeys = %d\tnewykeys = %d\tactual = %d\n",oldykeys,newykeys,count); | |
| 	} | |
| 	if (idcheck != 0) | |
| 	    fprintf(table->err,"Error in id's of ylist\twrong id's = %d\n",idcheck); | |
| 	count = 0; | |
| 	idcheck = 0; | |
| 	for (i = 0; i < xslots; i++) { | |
| 	    f = xlist[i]; | |
| 	    while (f != sentinel) { | |
| 		count++; | |
| 		if (f->index != (DdHalfWord) xindex) | |
| 		    idcheck++; | |
| 		f = f->next; | |
| 	    } | |
| 	} | |
| 	if (count != newxkeys || newxkeys != oldxkeys) { | |
| 	    fprintf(table->err,"Error in finding newxkeys\toldxkeys = %d \tnewxkeys = %d \tactual = %d\n",oldxkeys,newxkeys,count); | |
| 	} | |
| 	if (idcheck != 0) | |
| 	    fprintf(table->err,"Error in id's of xlist\twrong id's = %d\n",idcheck); | |
| #endif | |
|  | |
| 	isolated += (table->vars[xindex]->ref == 1) + | |
| 		    (table->vars[yindex]->ref == 1); | |
| 	table->isolated += isolated; | |
| 
 | |
| 	/* Set the appropriate fields in table. */ | |
| 	table->subtables[y].keys = newykeys; | |
| 
 | |
| 	/* Here we should update the linear combination table | |
| 	** to record that x <- x EXNOR y. This is done by complementing | |
| 	** the (x,y) entry of the table. | |
| 	*/ | |
| 
 | |
| 	table->keys += newykeys - oldykeys; | |
| 
 | |
| 	cuddXorLinear(table,xindex,yindex); | |
|     } | |
| 
 | |
| #ifdef DD_DEBUG | |
|     if (zero) { | |
| 	(void) Cudd_DebugCheck(table); | |
|     } | |
| #endif | |
|  | |
|     return(table->keys - table->isolated); | |
| 
 | |
| cuddLinearOutOfMem: | |
|     (void) fprintf(table->err,"Error: cuddLinearInPlace out of memory\n"); | |
| 
 | |
|     return (0); | |
| 
 | |
| } /* end of cuddLinearInPlace */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Updates the interaction matrix.] | |
|  | |
|   Description [] | |
|  | |
|   SideEffects [none] | |
|  | |
|   SeeAlso     [] | |
|  | |
| ******************************************************************************/ | |
| void | |
| cuddUpdateInteractionMatrix( | |
|   DdManager * table, | |
|   int  xindex, | |
|   int  yindex) | |
| { | |
|     int i; | |
|     for (i = 0; i < yindex; i++) { | |
| 	if (i != xindex && cuddTestInteract(table,i,yindex)) { | |
| 	    if (i < xindex) { | |
| 		cuddSetInteract(table,i,xindex); | |
| 	    } else { | |
| 		cuddSetInteract(table,xindex,i); | |
| 	    } | |
| 	} | |
|     } | |
|     for (i = yindex+1; i < table->size; i++) { | |
| 	if (i != xindex && cuddTestInteract(table,yindex,i)) { | |
| 	    if (i < xindex) { | |
| 		cuddSetInteract(table,i,xindex); | |
| 	    } else { | |
| 		cuddSetInteract(table,xindex,i); | |
| 	    } | |
| 	} | |
|     } | |
| 
 | |
| } /* end of cuddUpdateInteractionMatrix */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Initializes the linear transform matrix.] | |
|  | |
|   Description [Initializes the linear transform matrix.  Returns 1 if | |
|   successful; 0 otherwise.] | |
|  | |
|   SideEffects [none] | |
|  | |
|   SeeAlso     [] | |
|  | |
| ******************************************************************************/ | |
| int | |
| cuddInitLinear( | |
|   DdManager * table) | |
| { | |
|     int words; | |
|     int wordsPerRow; | |
|     int nvars; | |
|     int word; | |
|     int bit; | |
|     int i; | |
|     long *linear; | |
| 
 | |
|     nvars = table->size; | |
|     wordsPerRow = ((nvars - 1) >> LOGBPL) + 1; | |
|     words = wordsPerRow * nvars; | |
|     table->linear = linear = ALLOC(long,words); | |
|     if (linear == NULL) { | |
| 	table->errorCode = CUDD_MEMORY_OUT; | |
| 	return(0); | |
|     } | |
|     table->memused += words * sizeof(long); | |
|     table->linearSize = nvars; | |
|     for (i = 0; i < words; i++) linear[i] = 0; | |
|     for (i = 0; i < nvars; i++) { | |
| 	word = wordsPerRow * i + (i >> LOGBPL); | |
| 	bit  = i & (BPL-1); | |
| 	linear[word] = 1 << bit; | |
|     } | |
|     return(1); | |
| 
 | |
| } /* end of cuddInitLinear */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Resizes the linear transform matrix.] | |
|  | |
|   Description [Resizes the linear transform matrix.  Returns 1 if | |
|   successful; 0 otherwise.] | |
|  | |
|   SideEffects [none] | |
|  | |
|   SeeAlso     [] | |
|  | |
| ******************************************************************************/ | |
| int | |
| cuddResizeLinear( | |
|   DdManager * table) | |
| { | |
|     int words,oldWords; | |
|     int wordsPerRow,oldWordsPerRow; | |
|     int nvars,oldNvars; | |
|     int word,oldWord; | |
|     int bit; | |
|     int i,j; | |
|     long *linear,*oldLinear; | |
| 
 | |
|     oldNvars = table->linearSize; | |
|     oldWordsPerRow = ((oldNvars - 1) >> LOGBPL) + 1; | |
|     oldWords = oldWordsPerRow * oldNvars; | |
|     oldLinear = table->linear; | |
| 
 | |
|     nvars = table->size; | |
|     wordsPerRow = ((nvars - 1) >> LOGBPL) + 1; | |
|     words = wordsPerRow * nvars; | |
|     table->linear = linear = ALLOC(long,words); | |
|     if (linear == NULL) { | |
| 	table->errorCode = CUDD_MEMORY_OUT; | |
| 	return(0); | |
|     } | |
|     table->memused += (words - oldWords) * sizeof(long); | |
|     for (i = 0; i < words; i++) linear[i] = 0; | |
| 
 | |
|     /* Copy old matrix. */ | |
|     for (i = 0; i < oldNvars; i++) { | |
| 	for (j = 0; j < oldWordsPerRow; j++) { | |
| 	    oldWord = oldWordsPerRow * i + j; | |
| 	    word = wordsPerRow * i + j; | |
| 	    linear[word] = oldLinear[oldWord]; | |
| 	} | |
|     } | |
|     FREE(oldLinear); | |
| 
 | |
|     /* Add elements to the diagonal. */ | |
|     for (i = oldNvars; i < nvars; i++) { | |
| 	word = wordsPerRow * i + (i >> LOGBPL); | |
| 	bit  = i & (BPL-1); | |
| 	linear[word] = 1 << bit; | |
|     } | |
|     table->linearSize = nvars; | |
| 
 | |
|     return(1); | |
| 
 | |
| } /* end of cuddResizeLinear */ | |
| 
 | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Definition of static functions                                            */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Comparison function used by qsort.] | |
|  | |
|   Description [Comparison function used by qsort to order the | |
|   variables according to the number of keys in the subtables. | |
|   Returns the difference in number of keys between the two | |
|   variables being compared.] | |
|  | |
|   SideEffects [None] | |
|  | |
| ******************************************************************************/ | |
| static int | |
| ddLinearUniqueCompare( | |
|   int * ptrX, | |
|   int * ptrY) | |
| { | |
| #if 0 | |
|     if (entry[*ptrY] == entry[*ptrX]) { | |
| 	return((*ptrX) - (*ptrY)); | |
|     } | |
| #endif | |
|     return(entry[*ptrY] - entry[*ptrX]); | |
| 
 | |
| } /* end of ddLinearUniqueCompare */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Given xLow <= x <= xHigh moves x up and down between the | |
|   boundaries.] | |
|  | |
|   Description [Given xLow <= x <= xHigh moves x up and down between the | |
|   boundaries. At each step a linear transformation is tried, and, if it | |
|   decreases the size of the DD, it is accepted. Finds the best position | |
|   and does the required changes.  Returns 1 if successful; 0 otherwise.] | |
|  | |
|   SideEffects [None] | |
|  | |
| ******************************************************************************/ | |
| static int | |
| ddLinearAndSiftingAux( | |
|   DdManager * table, | |
|   int  x, | |
|   int  xLow, | |
|   int  xHigh) | |
| { | |
| 
 | |
|     Move	*move; | |
|     Move	*moveUp;		/* list of up moves */ | |
|     Move	*moveDown;		/* list of down moves */ | |
|     int		initialSize; | |
|     int		result; | |
| 
 | |
|     initialSize = table->keys - table->isolated; | |
| 
 | |
|     moveDown = NULL; | |
|     moveUp = NULL; | |
| 
 | |
|     if (x == xLow) { | |
| 	moveDown = ddLinearAndSiftingDown(table,x,xHigh,NULL); | |
| 	/* At this point x --> xHigh unless bounding occurred. */ | |
| 	if (moveDown == (Move *) CUDD_OUT_OF_MEM) goto ddLinearAndSiftingAuxOutOfMem; | |
| 	/* Move backward and stop at best position. */ | |
| 	result = ddLinearAndSiftingBackward(table,initialSize,moveDown); | |
| 	if (!result) goto ddLinearAndSiftingAuxOutOfMem; | |
| 
 | |
|     } else if (x == xHigh) { | |
| 	moveUp = ddLinearAndSiftingUp(table,x,xLow,NULL); | |
| 	/* At this point x --> xLow unless bounding occurred. */ | |
| 	if (moveUp == (Move *) CUDD_OUT_OF_MEM) goto ddLinearAndSiftingAuxOutOfMem; | |
| 	/* Move backward and stop at best position. */ | |
| 	result = ddLinearAndSiftingBackward(table,initialSize,moveUp); | |
| 	if (!result) goto ddLinearAndSiftingAuxOutOfMem; | |
| 
 | |
|     } else if ((x - xLow) > (xHigh - x)) { /* must go down first: shorter */ | |
| 	moveDown = ddLinearAndSiftingDown(table,x,xHigh,NULL); | |
| 	/* At this point x --> xHigh unless bounding occurred. */ | |
| 	if (moveDown == (Move *) CUDD_OUT_OF_MEM) goto ddLinearAndSiftingAuxOutOfMem; | |
| 	moveUp = ddUndoMoves(table,moveDown); | |
| #ifdef DD_DEBUG | |
| 	assert(moveUp == NULL || moveUp->x == x); | |
| #endif | |
| 	moveUp = ddLinearAndSiftingUp(table,x,xLow,moveUp); | |
| 	if (moveUp == (Move *) CUDD_OUT_OF_MEM) goto ddLinearAndSiftingAuxOutOfMem; | |
| 	/* Move backward and stop at best position. */ | |
| 	result = ddLinearAndSiftingBackward(table,initialSize,moveUp); | |
| 	if (!result) goto ddLinearAndSiftingAuxOutOfMem; | |
| 
 | |
|     } else { /* must go up first: shorter */ | |
| 	moveUp = ddLinearAndSiftingUp(table,x,xLow,NULL); | |
| 	/* At this point x --> xLow unless bounding occurred. */ | |
| 	if (moveUp == (Move *) CUDD_OUT_OF_MEM) goto ddLinearAndSiftingAuxOutOfMem; | |
| 	moveDown = ddUndoMoves(table,moveUp); | |
| #ifdef DD_DEBUG | |
| 	assert(moveDown == NULL || moveDown->y == x); | |
| #endif | |
| 	moveDown = ddLinearAndSiftingDown(table,x,xHigh,moveDown); | |
| 	if (moveDown == (Move *) CUDD_OUT_OF_MEM) goto ddLinearAndSiftingAuxOutOfMem; | |
| 	/* Move backward and stop at best position. */ | |
| 	result = ddLinearAndSiftingBackward(table,initialSize,moveDown); | |
| 	if (!result) goto ddLinearAndSiftingAuxOutOfMem; | |
|     } | |
| 
 | |
|     while (moveDown != NULL) { | |
| 	move = moveDown->next; | |
| 	cuddDeallocMove(table, moveDown); | |
| 	moveDown = move; | |
|     } | |
|     while (moveUp != NULL) { | |
| 	move = moveUp->next; | |
| 	cuddDeallocMove(table, moveUp); | |
| 	moveUp = move; | |
|     } | |
| 
 | |
|     return(1); | |
| 
 | |
| ddLinearAndSiftingAuxOutOfMem: | |
|     while (moveDown != NULL) { | |
| 	move = moveDown->next; | |
| 	cuddDeallocMove(table, moveDown); | |
| 	moveDown = move; | |
|     } | |
|     while (moveUp != NULL) { | |
| 	move = moveUp->next; | |
| 	cuddDeallocMove(table, moveUp); | |
| 	moveUp = move; | |
|     } | |
| 
 | |
|     return(0); | |
| 
 | |
| } /* end of ddLinearAndSiftingAux */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Sifts a variable up and applies linear transformations.] | |
|  | |
|   Description [Sifts a variable up and applies linear transformations. | |
|   Moves y up until either it reaches the bound (xLow) or the size of | |
|   the DD heap increases too much.  Returns the set of moves in case of | |
|   success; NULL if memory is full.] | |
|  | |
|   SideEffects [None] | |
|  | |
| ******************************************************************************/ | |
| static Move * | |
| ddLinearAndSiftingUp( | |
|   DdManager * table, | |
|   int  y, | |
|   int  xLow, | |
|   Move * prevMoves) | |
| { | |
|     Move	*moves; | |
|     Move	*move; | |
|     int		x; | |
|     int		size, newsize; | |
|     int		limitSize; | |
|     int		xindex, yindex; | |
|     int		isolated; | |
|     int		L;	/* lower bound on DD size */ | |
| #ifdef DD_DEBUG | |
|     int checkL; | |
|     int z; | |
|     int zindex; | |
| #endif | |
|  | |
|     moves = prevMoves; | |
|     yindex = table->invperm[y]; | |
| 
 | |
|     /* Initialize the lower bound. | |
|     ** The part of the DD below y will not change. | |
|     ** The part of the DD above y that does not interact with y will not | |
|     ** change. The rest may vanish in the best case, except for | |
|     ** the nodes at level xLow, which will not vanish, regardless. | |
|     */ | |
|     limitSize = L = table->keys - table->isolated; | |
|     for (x = xLow + 1; x < y; x++) { | |
| 	xindex = table->invperm[x]; | |
| 	if (cuddTestInteract(table,xindex,yindex)) { | |
| 	    isolated = table->vars[xindex]->ref == 1; | |
| 	    L -= table->subtables[x].keys - isolated; | |
| 	} | |
|     } | |
|     isolated = table->vars[yindex]->ref == 1; | |
|     L -= table->subtables[y].keys - isolated; | |
| 
 | |
|     x = cuddNextLow(table,y); | |
|     while (x >= xLow && L <= limitSize) { | |
| 	xindex = table->invperm[x]; | |
| #ifdef DD_DEBUG | |
| 	checkL = table->keys - table->isolated; | |
| 	for (z = xLow + 1; z < y; z++) { | |
| 	    zindex = table->invperm[z]; | |
| 	    if (cuddTestInteract(table,zindex,yindex)) { | |
| 		isolated = table->vars[zindex]->ref == 1; | |
| 		checkL -= table->subtables[z].keys - isolated; | |
| 	    } | |
| 	} | |
| 	isolated = table->vars[yindex]->ref == 1; | |
| 	checkL -= table->subtables[y].keys - isolated; | |
| 	if (L != checkL) { | |
| 	    (void) fprintf(table->out, "checkL(%d) != L(%d)\n",checkL,L); | |
| 	} | |
| #endif | |
| 	size = cuddSwapInPlace(table,x,y); | |
| 	if (size == 0) goto ddLinearAndSiftingUpOutOfMem; | |
| 	newsize = cuddLinearInPlace(table,x,y); | |
| 	if (newsize == 0) goto ddLinearAndSiftingUpOutOfMem; | |
| 	move = (Move *) cuddDynamicAllocNode(table); | |
| 	if (move == NULL) goto ddLinearAndSiftingUpOutOfMem; | |
| 	move->x = x; | |
| 	move->y = y; | |
| 	move->next = moves; | |
| 	moves = move; | |
| 	move->flags = CUDD_SWAP_MOVE; | |
| 	if (newsize >= size) { | |
| 	    /* Undo transformation. The transformation we apply is | |
| 	    ** its own inverse. Hence, we just apply the transformation | |
| 	    ** again. | |
| 	    */ | |
| 	    newsize = cuddLinearInPlace(table,x,y); | |
| 	    if (newsize == 0) goto ddLinearAndSiftingUpOutOfMem; | |
| #ifdef DD_DEBUG | |
| 	    if (newsize != size) { | |
| 		(void) fprintf(table->out,"Change in size after identity transformation! From %d to %d\n",size,newsize); | |
| 	    } | |
| #endif | |
| 	} else if (cuddTestInteract(table,xindex,yindex)) { | |
| 	    size = newsize; | |
| 	    move->flags = CUDD_LINEAR_TRANSFORM_MOVE; | |
| 	    cuddUpdateInteractionMatrix(table,xindex,yindex); | |
| 	} | |
| 	move->size = size; | |
| 	/* Update the lower bound. */ | |
| 	if (cuddTestInteract(table,xindex,yindex)) { | |
| 	    isolated = table->vars[xindex]->ref == 1; | |
| 	    L += table->subtables[y].keys - isolated; | |
| 	} | |
| 	if ((double) size > (double) limitSize * table->maxGrowth) break; | |
| 	if (size < limitSize) limitSize = size; | |
| 	y = x; | |
| 	x = cuddNextLow(table,y); | |
|     } | |
|     return(moves); | |
| 
 | |
| ddLinearAndSiftingUpOutOfMem: | |
|     while (moves != NULL) { | |
| 	move = moves->next; | |
| 	cuddDeallocMove(table, moves); | |
| 	moves = move; | |
|     } | |
|     return((Move *) CUDD_OUT_OF_MEM); | |
| 
 | |
| } /* end of ddLinearAndSiftingUp */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Sifts a variable down and applies linear transformations.] | |
|  | |
|   Description [Sifts a variable down and applies linear | |
|   transformations. Moves x down until either it reaches the bound | |
|   (xHigh) or the size of the DD heap increases too much. Returns the | |
|   set of moves in case of success; NULL if memory is full.] | |
|  | |
|   SideEffects [None] | |
|  | |
| ******************************************************************************/ | |
| static Move * | |
| ddLinearAndSiftingDown( | |
|   DdManager * table, | |
|   int  x, | |
|   int  xHigh, | |
|   Move * prevMoves) | |
| { | |
|     Move	*moves; | |
|     Move	*move; | |
|     int		y; | |
|     int		size, newsize; | |
|     int		R;	/* upper bound on node decrease */ | |
|     int		limitSize; | |
|     int		xindex, yindex; | |
|     int		isolated; | |
| #ifdef DD_DEBUG | |
|     int		checkR; | |
|     int		z; | |
|     int		zindex; | |
| #endif | |
|  | |
|     moves = prevMoves; | |
|     /* Initialize R */ | |
|     xindex = table->invperm[x]; | |
|     limitSize = size = table->keys - table->isolated; | |
|     R = 0; | |
|     for (y = xHigh; y > x; y--) { | |
| 	yindex = table->invperm[y]; | |
| 	if (cuddTestInteract(table,xindex,yindex)) { | |
| 	    isolated = table->vars[yindex]->ref == 1; | |
| 	    R += table->subtables[y].keys - isolated; | |
| 	} | |
|     } | |
| 
 | |
|     y = cuddNextHigh(table,x); | |
|     while (y <= xHigh && size - R < limitSize) { | |
| #ifdef DD_DEBUG | |
| 	checkR = 0; | |
| 	for (z = xHigh; z > x; z--) { | |
| 	    zindex = table->invperm[z]; | |
| 	    if (cuddTestInteract(table,xindex,zindex)) { | |
| 		isolated = table->vars[zindex]->ref == 1; | |
| 		checkR += table->subtables[z].keys - isolated; | |
| 	    } | |
| 	} | |
| 	if (R != checkR) { | |
| 	    (void) fprintf(table->out, "checkR(%d) != R(%d)\n",checkR,R); | |
| 	} | |
| #endif | |
| 	/* Update upper bound on node decrease. */ | |
| 	yindex = table->invperm[y]; | |
| 	if (cuddTestInteract(table,xindex,yindex)) { | |
| 	    isolated = table->vars[yindex]->ref == 1; | |
| 	    R -= table->subtables[y].keys - isolated; | |
| 	} | |
| 	size = cuddSwapInPlace(table,x,y); | |
| 	if (size == 0) goto ddLinearAndSiftingDownOutOfMem; | |
| 	newsize = cuddLinearInPlace(table,x,y); | |
| 	if (newsize == 0) goto ddLinearAndSiftingDownOutOfMem; | |
| 	move = (Move *) cuddDynamicAllocNode(table); | |
| 	if (move == NULL) goto ddLinearAndSiftingDownOutOfMem; | |
| 	move->x = x; | |
| 	move->y = y; | |
| 	move->next = moves; | |
| 	moves = move; | |
| 	move->flags = CUDD_SWAP_MOVE; | |
| 	if (newsize >= size) { | |
| 	    /* Undo transformation. The transformation we apply is | |
| 	    ** its own inverse. Hence, we just apply the transformation | |
| 	    ** again. | |
| 	    */ | |
| 	    newsize = cuddLinearInPlace(table,x,y); | |
| 	    if (newsize == 0) goto ddLinearAndSiftingDownOutOfMem; | |
| 	    if (newsize != size) { | |
| 		(void) fprintf(table->out,"Change in size after identity transformation! From %d to %d\n",size,newsize); | |
| 	    } | |
| 	} else if (cuddTestInteract(table,xindex,yindex)) { | |
| 	    size = newsize; | |
| 	    move->flags = CUDD_LINEAR_TRANSFORM_MOVE; | |
| 	    cuddUpdateInteractionMatrix(table,xindex,yindex); | |
| 	} | |
| 	move->size = size; | |
| 	if ((double) size > (double) limitSize * table->maxGrowth) break; | |
| 	if (size < limitSize) limitSize = size; | |
| 	x = y; | |
| 	y = cuddNextHigh(table,x); | |
|     } | |
|     return(moves); | |
| 
 | |
| ddLinearAndSiftingDownOutOfMem: | |
|     while (moves != NULL) { | |
| 	move = moves->next; | |
| 	cuddDeallocMove(table, moves); | |
| 	moves = move; | |
|     } | |
|     return((Move *) CUDD_OUT_OF_MEM); | |
| 
 | |
| } /* end of ddLinearAndSiftingDown */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Given a set of moves, returns the DD heap to the order | |
|   giving the minimum size.] | |
|  | |
|   Description [Given a set of moves, returns the DD heap to the | |
|   position giving the minimum size. In case of ties, returns to the | |
|   closest position giving the minimum size. Returns 1 in case of | |
|   success; 0 otherwise.] | |
|  | |
|   SideEffects [None] | |
|  | |
| ******************************************************************************/ | |
| static int | |
| ddLinearAndSiftingBackward( | |
|   DdManager * table, | |
|   int  size, | |
|   Move * moves) | |
| { | |
|     Move *move; | |
|     int	res; | |
| 
 | |
|     for (move = moves; move != NULL; move = move->next) { | |
| 	if (move->size < size) { | |
| 	    size = move->size; | |
| 	} | |
|     } | |
| 
 | |
|     for (move = moves; move != NULL; move = move->next) { | |
| 	if (move->size == size) return(1); | |
| 	if (move->flags == CUDD_LINEAR_TRANSFORM_MOVE) { | |
| 	    res = cuddLinearInPlace(table,(int)move->x,(int)move->y); | |
| 	    if (!res) return(0); | |
| 	} | |
| 	res = cuddSwapInPlace(table,(int)move->x,(int)move->y); | |
| 	if (!res) return(0); | |
| 	if (move->flags == CUDD_INVERSE_TRANSFORM_MOVE) { | |
| 	    res = cuddLinearInPlace(table,(int)move->x,(int)move->y); | |
| 	    if (!res) return(0); | |
| 	} | |
|     } | |
| 
 | |
|     return(1); | |
| 
 | |
| } /* end of ddLinearAndSiftingBackward */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Given a set of moves, returns the DD heap to the order | |
|   in effect before the moves.] | |
|  | |
|   Description [Given a set of moves, returns the DD heap to the | |
|   order in effect before the moves.  Returns 1 in case of success; | |
|   0 otherwise.] | |
|  | |
|   SideEffects [None] | |
|  | |
| ******************************************************************************/ | |
| static Move* | |
| ddUndoMoves( | |
|   DdManager * table, | |
|   Move * moves) | |
| { | |
|     Move *invmoves = NULL; | |
|     Move *move; | |
|     Move *invmove; | |
|     int	size; | |
| 
 | |
|     for (move = moves; move != NULL; move = move->next) { | |
| 	invmove = (Move *) cuddDynamicAllocNode(table); | |
| 	if (invmove == NULL) goto ddUndoMovesOutOfMem; | |
| 	invmove->x = move->x; | |
| 	invmove->y = move->y; | |
| 	invmove->next = invmoves; | |
| 	invmoves = invmove; | |
| 	if (move->flags == CUDD_SWAP_MOVE) { | |
| 	    invmove->flags = CUDD_SWAP_MOVE; | |
| 	    size = cuddSwapInPlace(table,(int)move->x,(int)move->y); | |
| 	    if (!size) goto ddUndoMovesOutOfMem; | |
| 	} else if (move->flags == CUDD_LINEAR_TRANSFORM_MOVE) { | |
| 	    invmove->flags = CUDD_INVERSE_TRANSFORM_MOVE; | |
| 	    size = cuddLinearInPlace(table,(int)move->x,(int)move->y); | |
| 	    if (!size) goto ddUndoMovesOutOfMem; | |
| 	    size = cuddSwapInPlace(table,(int)move->x,(int)move->y); | |
| 	    if (!size) goto ddUndoMovesOutOfMem; | |
| 	} else { /* must be CUDD_INVERSE_TRANSFORM_MOVE */ | |
| #ifdef DD_DEBUG | |
| 	    (void) fprintf(table->err,"Unforseen event in ddUndoMoves!\n"); | |
| #endif | |
| 	    invmove->flags = CUDD_LINEAR_TRANSFORM_MOVE; | |
| 	    size = cuddSwapInPlace(table,(int)move->x,(int)move->y); | |
| 	    if (!size) goto ddUndoMovesOutOfMem; | |
| 	    size = cuddLinearInPlace(table,(int)move->x,(int)move->y); | |
| 	    if (!size) goto ddUndoMovesOutOfMem; | |
| 	} | |
| 	invmove->size = size; | |
|     } | |
| 
 | |
|     return(invmoves); | |
| 
 | |
| ddUndoMovesOutOfMem: | |
|     while (invmoves != NULL) { | |
| 	move = invmoves->next; | |
| 	cuddDeallocMove(table, invmoves); | |
| 	invmoves = move; | |
|     } | |
|     return((Move *) CUDD_OUT_OF_MEM); | |
| 
 | |
| } /* end of ddUndoMoves */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [XORs two rows of the linear transform matrix.] | |
|  | |
|   Description [XORs two rows of the linear transform matrix and replaces | |
|   the first row with the result.] | |
|  | |
|   SideEffects [none] | |
|  | |
|   SeeAlso     [] | |
|  | |
| ******************************************************************************/ | |
| static void | |
| cuddXorLinear( | |
|   DdManager * table, | |
|   int  x, | |
|   int  y) | |
| { | |
|     int i; | |
|     int nvars = table->size; | |
|     int wordsPerRow = ((nvars - 1) >> LOGBPL) + 1; | |
|     int xstart = wordsPerRow * x; | |
|     int ystart = wordsPerRow * y; | |
|     long *linear = table->linear; | |
| 
 | |
|     for (i = 0; i < wordsPerRow; i++) { | |
| 	linear[xstart+i] ^= linear[ystart+i]; | |
|     } | |
| 
 | |
| } /* end of cuddXorLinear */
 |