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.
		
		
		
		
		
			
		
			
				
					
					
						
							986 lines
						
					
					
						
							24 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							986 lines
						
					
					
						
							24 KiB
						
					
					
				| /** | |
|   @file | |
|  | |
|   @ingroup cudd | |
|  | |
|   @brief Functions for variable reordering by window permutation. | |
|  | |
|   @author Fabio Somenzi | |
|  | |
|   @copyright@parblock | |
|   Copyright (c) 1995-2015, Regents of the University of Colorado | |
|  | |
|   All rights reserved. | |
|  | |
|   Redistribution and use in source and binary forms, with or without | |
|   modification, are permitted provided that the following conditions | |
|   are met: | |
|  | |
|   Redistributions of source code must retain the above copyright | |
|   notice, this list of conditions and the following disclaimer. | |
|  | |
|   Redistributions in binary form must reproduce the above copyright | |
|   notice, this list of conditions and the following disclaimer in the | |
|   documentation and/or other materials provided with the distribution. | |
|  | |
|   Neither the name of the University of Colorado nor the names of its | |
|   contributors may be used to endorse or promote products derived from | |
|   this software without specific prior written permission. | |
|  | |
|   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
|   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
|   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
|   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
|   COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
|   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
|   BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
|   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | |
|   CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
|   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | |
|   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
|   POSSIBILITY OF SUCH DAMAGE. | |
|   @endparblock | |
|  | |
| */ | |
| 
 | |
| #include "util.h" | |
| #include "cuddInt.h" | |
|  | |
| /*---------------------------------------------------------------------------*/ | |
| /* Constant declarations                                                     */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Stucture declarations                                                     */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Type declarations                                                         */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Variable declarations                                                     */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Macro declarations                                                        */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| /** \cond */ | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Static function prototypes                                                */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| static int ddWindow2 (DdManager *table, int low, int high); | |
| static int ddWindowConv2 (DdManager *table, int low, int high); | |
| static int ddPermuteWindow3 (DdManager *table, int x); | |
| static int ddWindow3 (DdManager *table, int low, int high); | |
| static int ddWindowConv3 (DdManager *table, int low, int high); | |
| static int ddPermuteWindow4 (DdManager *table, int w); | |
| static int ddWindow4 (DdManager *table, int low, int high); | |
| static int ddWindowConv4 (DdManager *table, int low, int high); | |
| 
 | |
| /** \endcond */ | |
| 
 | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Definition of exported functions                                          */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Definition of internal functions                                          */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Reorders by applying the method of the sliding window. | |
|  | |
|   @details Tries all possible permutations to the variables in a | |
|   window that slides from low to high. The size of the window is | |
|   determined by submethod.  Assumes that no dead nodes are present. | |
|  | |
|   @return 1 in case of success; 0 otherwise. | |
|  | |
|   @sideeffect None | |
|  | |
| */ | |
| int | |
| cuddWindowReorder( | |
|   DdManager * table /**< %DD table */, | |
|   int low /**< lowest index to reorder */, | |
|   int high /**< highest index to reorder */, | |
|   Cudd_ReorderingType submethod /**< window reordering option */) | |
| { | |
| 
 | |
|     int res; | |
| #ifdef DD_DEBUG | |
|     int supposedOpt; | |
| #endif | |
|  | |
|     switch (submethod) { | |
|     case CUDD_REORDER_WINDOW2: | |
| 	res = ddWindow2(table,low,high); | |
| 	break; | |
|     case CUDD_REORDER_WINDOW3: | |
| 	res = ddWindow3(table,low,high); | |
| 	break; | |
|     case CUDD_REORDER_WINDOW4: | |
| 	res = ddWindow4(table,low,high); | |
| 	break; | |
|     case CUDD_REORDER_WINDOW2_CONV: | |
| 	res = ddWindowConv2(table,low,high); | |
| 	break; | |
|     case CUDD_REORDER_WINDOW3_CONV: | |
| 	res = ddWindowConv3(table,low,high); | |
| #ifdef DD_DEBUG | |
| 	supposedOpt = (int) (table->keys - table->isolated); | |
| 	res = ddWindow3(table,low,high); | |
| 	if (table->keys - table->isolated != (unsigned) supposedOpt) { | |
| 	    (void) fprintf(table->err, "Convergence failed! (%d != %d)\n", | |
| 			   table->keys - table->isolated, supposedOpt); | |
| 	} | |
| #endif | |
| 	break; | |
|     case CUDD_REORDER_WINDOW4_CONV: | |
| 	res = ddWindowConv4(table,low,high); | |
| #ifdef DD_DEBUG | |
| 	supposedOpt = (int) (table->keys - table->isolated); | |
| 	res = ddWindow4(table,low,high); | |
| 	if (table->keys - table->isolated != (unsigned) supposedOpt) { | |
| 	    (void) fprintf(table->err,"Convergence failed! (%d != %d)\n", | |
| 			   table->keys - table->isolated, supposedOpt); | |
| 	} | |
| #endif | |
| 	break; | |
|     default: return(0); | |
|     } | |
| 
 | |
|     return(res); | |
| 
 | |
| } /* end of cuddWindowReorder */ | |
| 
 | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Definition of static functions                                            */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| /** | |
|   @brief Reorders by applying a sliding window of width 2. | |
|  | |
|   @details Tries both permutations of the variables in a window that | |
|   slides from low to high.  Assumes that no dead nodes are present. | |
|  | |
|   @return 1 in case of success; 0 otherwise. | |
|  | |
|   @sideeffect None | |
|  | |
| */ | |
| static int | |
| ddWindow2( | |
|   DdManager * table, | |
|   int  low, | |
|   int  high) | |
| { | |
| 
 | |
|     int x; | |
|     int res; | |
|     int size; | |
| 
 | |
| #ifdef DD_DEBUG | |
|     assert(low >= 0 && high < table->size); | |
| #endif | |
|  | |
|     if (high-low < 1) return(0); | |
| 
 | |
|     res = (int) (table->keys - table->isolated); | |
|     for (x = low; x < high; x++) { | |
| 	size = res; | |
| 	res = cuddSwapInPlace(table,x,x+1); | |
| 	if (res == 0) return(0); | |
| 	if (res >= size) { /* no improvement: undo permutation */ | |
| 	    res = cuddSwapInPlace(table,x,x+1); | |
| 	    if (res == 0) return(0); | |
| 	} | |
| #ifdef DD_STATS | |
| 	if (res < size) { | |
| 	    (void) fprintf(table->out,"-"); | |
| 	} else { | |
| 	    (void) fprintf(table->out,"="); | |
| 	} | |
| 	fflush(table->out); | |
| #endif | |
|     } | |
| 
 | |
|     return(1); | |
| 
 | |
| } /* end of ddWindow2 */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Reorders by repeatedly applying a sliding window of width 2. | |
|  | |
|   @details Tries both permutations of the variables in a window that | |
|   slides from low to high.  Assumes that no dead nodes are present. | |
|   Uses an event-driven approach to determine convergence. | |
|  | |
|   @return 1 in case of success; 0 otherwise. | |
|  | |
|   @sideeffect None | |
|  | |
| */ | |
| static int | |
| ddWindowConv2( | |
|   DdManager * table, | |
|   int  low, | |
|   int  high) | |
| { | |
|     int x; | |
|     int res; | |
|     int nwin; | |
|     int newevent; | |
|     int *events; | |
|     int size; | |
| 
 | |
| #ifdef DD_DEBUG | |
|     assert(low >= 0 && high < table->size); | |
| #endif | |
|  | |
|     if (high-low < 1) return(ddWindowConv2(table,low,high)); | |
| 
 | |
|     nwin = high-low; | |
|     events = ALLOC(int,nwin); | |
|     if (events == NULL) { | |
| 	table->errorCode = CUDD_MEMORY_OUT; | |
| 	return(0); | |
|     } | |
|     for (x=0; x<nwin; x++) { | |
| 	events[x] = 1; | |
|     } | |
| 
 | |
|     res = (int) (table->keys - table->isolated); | |
|     do { | |
| 	newevent = 0; | |
| 	for (x=0; x<nwin; x++) { | |
| 	    if (events[x]) { | |
| 		size = res; | |
| 		res = cuddSwapInPlace(table,x+low,x+low+1); | |
| 		if (res == 0) { | |
| 		    FREE(events); | |
| 		    return(0); | |
| 		} | |
| 		if (res >= size) { /* no improvement: undo permutation */ | |
| 		    res = cuddSwapInPlace(table,x+low,x+low+1); | |
| 		    if (res == 0) { | |
| 			FREE(events); | |
| 			return(0); | |
| 		    } | |
| 		} | |
| 		if (res < size) { | |
| 		    if (x < nwin-1)	events[x+1] = 1; | |
| 		    if (x > 0)		events[x-1] = 1; | |
| 		    newevent = 1; | |
| 		} | |
| 		events[x] = 0; | |
| #ifdef DD_STATS | |
| 		if (res < size) { | |
| 		    (void) fprintf(table->out,"-"); | |
| 		} else { | |
| 		    (void) fprintf(table->out,"="); | |
| 		} | |
| 		fflush(table->out); | |
| #endif | |
| 	    } | |
| 	} | |
| #ifdef DD_STATS | |
| 	if (newevent) { | |
| 	    (void) fprintf(table->out,"|"); | |
| 	    fflush(table->out); | |
| 	} | |
| #endif | |
|     } while (newevent); | |
| 
 | |
|     FREE(events); | |
| 
 | |
|     return(1); | |
| 
 | |
| } /* end of ddWindowConv3 */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Tries all the permutations of the three variables between | |
|   x and x+2 and retains the best. | |
|  | |
|   @details Assumes that no dead nodes are present. | |
|  | |
|   @return the index of the best permutation (1-6) in case of success; | |
|   0 otherwise. | |
|  | |
|   @sideeffect None | |
|  | |
| */ | |
| static int | |
| ddPermuteWindow3( | |
|   DdManager * table, | |
|   int  x) | |
| { | |
|     int y,z; | |
|     int	size,sizeNew; | |
|     int	best; | |
| 
 | |
| #ifdef DD_DEBUG | |
|     assert(table->dead == 0); | |
|     assert(x+2 < table->size); | |
| #endif | |
|  | |
|     size = (int) (table->keys - table->isolated); | |
|     y = x+1; z = y+1; | |
| 
 | |
|     /* The permutation pattern is: | |
|     ** (x,y)(y,z) | |
|     ** repeated three times to get all 3! = 6 permutations. | |
|     */ | |
| #define ABC 1 | |
|     best = ABC; | |
| 
 | |
| #define	BAC 2 | |
|     sizeNew = cuddSwapInPlace(table,x,y); | |
|     if (sizeNew < size) { | |
| 	if (sizeNew == 0) return(0); | |
| 	best = BAC; | |
| 	size = sizeNew; | |
|     } | |
| #define BCA 3 | |
|     sizeNew = cuddSwapInPlace(table,y,z); | |
|     if (sizeNew < size) { | |
| 	if (sizeNew == 0) return(0); | |
| 	best = BCA; | |
| 	size = sizeNew; | |
|     } | |
| #define CBA 4 | |
|     sizeNew = cuddSwapInPlace(table,x,y); | |
|     if (sizeNew < size) { | |
| 	if (sizeNew == 0) return(0); | |
| 	best = CBA; | |
| 	size = sizeNew; | |
|     } | |
| #define CAB 5 | |
|     sizeNew = cuddSwapInPlace(table,y,z); | |
|     if (sizeNew < size) { | |
| 	if (sizeNew == 0) return(0); | |
| 	best = CAB; | |
| 	size = sizeNew; | |
|     } | |
| #define ACB 6 | |
|     sizeNew = cuddSwapInPlace(table,x,y); | |
|     if (sizeNew < size) { | |
| 	if (sizeNew == 0) return(0); | |
| 	best = ACB; | |
| 	size = sizeNew; | |
|     } | |
| 
 | |
|     /* Now take the shortest route to the best permuytation. | |
|     ** The initial permutation is ACB. | |
|     */ | |
|     switch(best) { | |
|     case BCA: if (!cuddSwapInPlace(table,y,z)) return(0); | |
|     case CBA: if (!cuddSwapInPlace(table,x,y)) return(0); | |
|     case ABC: if (!cuddSwapInPlace(table,y,z)) return(0); | |
|     case ACB: break; | |
|     case BAC: if (!cuddSwapInPlace(table,y,z)) return(0); | |
|     case CAB: if (!cuddSwapInPlace(table,x,y)) return(0); | |
| 	       break; | |
|     default: return(0); | |
|     } | |
| 
 | |
| #ifdef DD_DEBUG | |
|     assert(table->keys - table->isolated == (unsigned) size); | |
| #endif | |
|  | |
|     return(best); | |
| 
 | |
| } /* end of ddPermuteWindow3 */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Reorders by applying a sliding window of width 3. | |
|  | |
|   @details Tries all possible permutations to the variables in a | |
|   window that slides from low to high.  Assumes that no dead nodes are | |
|   present. | |
|  | |
|   @return 1 in case of success; 0 otherwise. | |
|  | |
|   @sideeffect None | |
|  | |
| */ | |
| static int | |
| ddWindow3( | |
|   DdManager * table, | |
|   int  low, | |
|   int  high) | |
| { | |
| 
 | |
|     int x; | |
|     int res; | |
| 
 | |
| #ifdef DD_DEBUG | |
|     assert(low >= 0 && high < table->size); | |
| #endif | |
|  | |
|     if (high-low < 2) return(ddWindow2(table,low,high)); | |
| 
 | |
|     for (x = low; x+1 < high; x++) { | |
| 	res = ddPermuteWindow3(table,x); | |
| 	if (res == 0) return(0); | |
| #ifdef DD_STATS | |
| 	if (res == ABC) { | |
| 	    (void) fprintf(table->out,"="); | |
| 	} else { | |
| 	    (void) fprintf(table->out,"-"); | |
| 	} | |
| 	fflush(table->out); | |
| #endif | |
|     } | |
| 
 | |
|     return(1); | |
| 
 | |
| } /* end of ddWindow3 */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Reorders by repeatedly applying a sliding window of width 3. | |
|  | |
|   @details Tries all possible permutations to the variables in a | |
|   window that slides from low to high.  Assumes that no dead nodes are | |
|   present.  Uses an event-driven approach to determine convergence. | |
|  | |
|   @return 1 in case of success; 0 otherwise. | |
|  | |
|   @sideeffect None | |
|  | |
| */ | |
| static int | |
| ddWindowConv3( | |
|   DdManager * table, | |
|   int  low, | |
|   int  high) | |
| { | |
|     int x; | |
|     int res; | |
|     int nwin; | |
|     int newevent; | |
|     int *events; | |
| 
 | |
| #ifdef DD_DEBUG | |
|     assert(low >= 0 && high < table->size); | |
| #endif | |
|  | |
|     if (high-low < 2) return(ddWindowConv2(table,low,high)); | |
| 
 | |
|     nwin = high-low-1; | |
|     events = ALLOC(int,nwin); | |
|     if (events == NULL) { | |
| 	table->errorCode = CUDD_MEMORY_OUT; | |
| 	return(0); | |
|     } | |
|     for (x=0; x<nwin; x++) { | |
| 	events[x] = 1; | |
|     } | |
| 
 | |
|     do { | |
| 	newevent = 0; | |
| 	for (x=0; x<nwin; x++) { | |
| 	    if (events[x]) { | |
| 		res = ddPermuteWindow3(table,x+low); | |
| 		switch (res) { | |
| 		case ABC: | |
| 		    break; | |
| 		case BAC: | |
| 		    if (x < nwin-1)	events[x+1] = 1; | |
| 		    if (x > 1)		events[x-2] = 1; | |
| 		    newevent = 1; | |
| 		    break; | |
| 		case BCA: | |
| 		case CBA: | |
| 		case CAB: | |
| 		    if (x < nwin-2)	events[x+2] = 1; | |
| 		    if (x < nwin-1)	events[x+1] = 1; | |
| 		    if (x > 0)		events[x-1] = 1; | |
| 		    if (x > 1)		events[x-2] = 1; | |
| 		    newevent = 1; | |
| 		    break; | |
| 		case ACB: | |
| 		    if (x < nwin-2)	events[x+2] = 1; | |
| 		    if (x > 0)		events[x-1] = 1; | |
| 		    newevent = 1; | |
| 		    break; | |
| 		default: | |
| 		    FREE(events); | |
| 		    return(0); | |
| 		} | |
| 		events[x] = 0; | |
| #ifdef DD_STATS | |
| 		if (res == ABC) { | |
| 		    (void) fprintf(table->out,"="); | |
| 		} else { | |
| 		    (void) fprintf(table->out,"-"); | |
| 		} | |
| 		fflush(table->out); | |
| #endif | |
| 	    } | |
| 	} | |
| #ifdef DD_STATS | |
| 	if (newevent) { | |
| 	    (void) fprintf(table->out,"|"); | |
| 	    fflush(table->out); | |
| 	} | |
| #endif | |
|     } while (newevent); | |
| 
 | |
|     FREE(events); | |
| 
 | |
|     return(1); | |
| 
 | |
| } /* end of ddWindowConv3 */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Tries all the permutations of the four variables between w | |
|   and w+3 and retains the best. | |
|  | |
|   @details Assumes that no dead nodes are present. | |
|  | |
|   @return the index of the best permutation (1-24) in case of success; | |
|   0 otherwise. | |
|  | |
|   @sideeffect None | |
|  | |
| */ | |
| static int | |
| ddPermuteWindow4( | |
|   DdManager * table, | |
|   int  w) | |
| { | |
|     int x,y,z; | |
|     int	size,sizeNew; | |
|     int	best; | |
| 
 | |
| #ifdef DD_DEBUG | |
|     assert(table->dead == 0); | |
|     assert(w+3 < table->size); | |
| #endif | |
|  | |
|     size = (int) (table->keys - table->isolated); | |
|     x = w+1; y = x+1; z = y+1; | |
| 
 | |
|     /* The permutation pattern is: | |
|      * (w,x)(y,z)(w,x)(x,y) | |
|      * (y,z)(w,x)(y,z)(x,y) | |
|      * repeated three times to get all 4! = 24 permutations. | |
|      * This gives a hamiltonian circuit of Cayley's graph. | |
|      * The codes to the permutation are assigned in topological order. | |
|      * The permutations at lower distance from the final permutation are | |
|      * assigned lower codes. This way we can choose, between | |
|      * permutations that give the same size, one that requires the minimum | |
|      * number of swaps from the final permutation of the hamiltonian circuit. | |
|      * There is an exception to this rule: ABCD is given Code 1, to | |
|      * avoid oscillation when convergence is sought. | |
|      */ | |
| #define ABCD 1 | |
|     best = ABCD; | |
| 
 | |
| #define	BACD 7 | |
|     sizeNew = cuddSwapInPlace(table,w,x); | |
|     if (sizeNew < size) { | |
| 	if (sizeNew == 0) return(0); | |
| 	best = BACD; | |
| 	size = sizeNew; | |
|     } | |
| #define BADC 13 | |
|     sizeNew = cuddSwapInPlace(table,y,z); | |
|     if (sizeNew < size) { | |
| 	if (sizeNew == 0) return(0); | |
| 	best = BADC; | |
| 	size = sizeNew; | |
|     } | |
| #define ABDC 8 | |
|     sizeNew = cuddSwapInPlace(table,w,x); | |
|     if (sizeNew < size || (sizeNew == size && ABDC < best)) { | |
| 	if (sizeNew == 0) return(0); | |
| 	best = ABDC; | |
| 	size = sizeNew; | |
|     } | |
| #define ADBC 14 | |
|     sizeNew = cuddSwapInPlace(table,x,y); | |
|     if (sizeNew < size) { | |
| 	if (sizeNew == 0) return(0); | |
| 	best = ADBC; | |
| 	size = sizeNew; | |
|     } | |
| #define ADCB 9 | |
|     sizeNew = cuddSwapInPlace(table,y,z); | |
|     if (sizeNew < size || (sizeNew == size && ADCB < best)) { | |
| 	if (sizeNew == 0) return(0); | |
| 	best = ADCB; | |
| 	size = sizeNew; | |
|     } | |
| #define DACB 15 | |
|     sizeNew = cuddSwapInPlace(table,w,x); | |
|     if (sizeNew < size) { | |
| 	if (sizeNew == 0) return(0); | |
| 	best = DACB; | |
| 	size = sizeNew; | |
|     } | |
| #define DABC 20 | |
|     sizeNew = cuddSwapInPlace(table,y,z); | |
|     if (sizeNew < size) { | |
| 	if (sizeNew == 0) return(0); | |
| 	best = DABC; | |
| 	size = sizeNew; | |
|     } | |
| #define DBAC 23 | |
|     sizeNew = cuddSwapInPlace(table,x,y); | |
|     if (sizeNew < size) { | |
| 	if (sizeNew == 0) return(0); | |
| 	best = DBAC; | |
| 	size = sizeNew; | |
|     } | |
| #define BDAC 19 | |
|     sizeNew = cuddSwapInPlace(table,w,x); | |
|     if (sizeNew < size || (sizeNew == size && BDAC < best)) { | |
| 	if (sizeNew == 0) return(0); | |
| 	best = BDAC; | |
| 	size = sizeNew; | |
|     } | |
| #define BDCA 21 | |
|     sizeNew = cuddSwapInPlace(table,y,z); | |
|     if (sizeNew < size || (sizeNew == size && BDCA < best)) { | |
| 	if (sizeNew == 0) return(0); | |
| 	best = BDCA; | |
| 	size = sizeNew; | |
|     } | |
| #define DBCA 24 | |
|     sizeNew = cuddSwapInPlace(table,w,x); | |
|     if (sizeNew < size) { | |
| 	if (sizeNew == 0) return(0); | |
| 	best = DBCA; | |
| 	size = sizeNew; | |
|     } | |
| #define DCBA 22 | |
|     sizeNew = cuddSwapInPlace(table,x,y); | |
|     if (sizeNew < size || (sizeNew == size && DCBA < best)) { | |
| 	if (sizeNew == 0) return(0); | |
| 	best = DCBA; | |
| 	size = sizeNew; | |
|     } | |
| #define DCAB 18 | |
|     sizeNew = cuddSwapInPlace(table,y,z); | |
|     if (sizeNew < size || (sizeNew == size && DCAB < best)) { | |
| 	if (sizeNew == 0) return(0); | |
| 	best = DCAB; | |
| 	size = sizeNew; | |
|     } | |
| #define CDAB 12 | |
|     sizeNew = cuddSwapInPlace(table,w,x); | |
|     if (sizeNew < size || (sizeNew == size && CDAB < best)) { | |
| 	if (sizeNew == 0) return(0); | |
| 	best = CDAB; | |
| 	size = sizeNew; | |
|     } | |
| #define CDBA 17 | |
|     sizeNew = cuddSwapInPlace(table,y,z); | |
|     if (sizeNew < size || (sizeNew == size && CDBA < best)) { | |
| 	if (sizeNew == 0) return(0); | |
| 	best = CDBA; | |
| 	size = sizeNew; | |
|     } | |
| #define CBDA 11 | |
|     sizeNew = cuddSwapInPlace(table,x,y); | |
|     if (sizeNew < size || (sizeNew == size && CBDA < best)) { | |
| 	if (sizeNew == 0) return(0); | |
| 	best = CBDA; | |
| 	size = sizeNew; | |
|     } | |
| #define BCDA 16 | |
|     sizeNew = cuddSwapInPlace(table,w,x); | |
|     if (sizeNew < size || (sizeNew == size && BCDA < best)) { | |
| 	if (sizeNew == 0) return(0); | |
| 	best = BCDA; | |
| 	size = sizeNew; | |
|     } | |
| #define BCAD 10 | |
|     sizeNew = cuddSwapInPlace(table,y,z); | |
|     if (sizeNew < size || (sizeNew == size && BCAD < best)) { | |
| 	if (sizeNew == 0) return(0); | |
| 	best = BCAD; | |
| 	size = sizeNew; | |
|     } | |
| #define CBAD 5 | |
|     sizeNew = cuddSwapInPlace(table,w,x); | |
|     if (sizeNew < size || (sizeNew == size && CBAD < best)) { | |
| 	if (sizeNew == 0) return(0); | |
| 	best = CBAD; | |
| 	size = sizeNew; | |
|     } | |
| #define CABD 3 | |
|     sizeNew = cuddSwapInPlace(table,x,y); | |
|     if (sizeNew < size || (sizeNew == size && CABD < best)) { | |
| 	if (sizeNew == 0) return(0); | |
| 	best = CABD; | |
| 	size = sizeNew; | |
|     } | |
| #define CADB 6 | |
|     sizeNew = cuddSwapInPlace(table,y,z); | |
|     if (sizeNew < size || (sizeNew == size && CADB < best)) { | |
| 	if (sizeNew == 0) return(0); | |
| 	best = CADB; | |
| 	size = sizeNew; | |
|     } | |
| #define ACDB 4 | |
|     sizeNew = cuddSwapInPlace(table,w,x); | |
|     if (sizeNew < size || (sizeNew == size && ACDB < best)) { | |
| 	if (sizeNew == 0) return(0); | |
| 	best = ACDB; | |
| 	size = sizeNew; | |
|     } | |
| #define ACBD 2 | |
|     sizeNew = cuddSwapInPlace(table,y,z); | |
|     if (sizeNew < size || (sizeNew == size && ACBD < best)) { | |
| 	if (sizeNew == 0) return(0); | |
| 	best = ACBD; | |
| 	size = sizeNew; | |
|     } | |
| 
 | |
|     /* Now take the shortest route to the best permutation. | |
|     ** The initial permutation is ACBD. | |
|     */ | |
|     switch(best) { | |
|     case DBCA: if (!cuddSwapInPlace(table,y,z)) return(0); | |
|     case BDCA: if (!cuddSwapInPlace(table,x,y)) return(0); | |
|     case CDBA: if (!cuddSwapInPlace(table,w,x)) return(0); | |
|     case ADBC: if (!cuddSwapInPlace(table,y,z)) return(0); | |
|     case ABDC: if (!cuddSwapInPlace(table,x,y)) return(0); | |
|     case ACDB: if (!cuddSwapInPlace(table,y,z)) return(0); | |
|     case ACBD: break; | |
|     case DCBA: if (!cuddSwapInPlace(table,y,z)) return(0); | |
|     case BCDA: if (!cuddSwapInPlace(table,x,y)) return(0); | |
|     case CBDA: if (!cuddSwapInPlace(table,w,x)) return(0); | |
| 	       if (!cuddSwapInPlace(table,x,y)) return(0); | |
| 	       if (!cuddSwapInPlace(table,y,z)) return(0); | |
| 	       break; | |
|     case DBAC: if (!cuddSwapInPlace(table,x,y)) return(0); | |
|     case DCAB: if (!cuddSwapInPlace(table,w,x)) return(0); | |
|     case DACB: if (!cuddSwapInPlace(table,y,z)) return(0); | |
|     case BACD: if (!cuddSwapInPlace(table,x,y)) return(0); | |
|     case CABD: if (!cuddSwapInPlace(table,w,x)) return(0); | |
| 	       break; | |
|     case DABC: if (!cuddSwapInPlace(table,y,z)) return(0); | |
|     case BADC: if (!cuddSwapInPlace(table,x,y)) return(0); | |
|     case CADB: if (!cuddSwapInPlace(table,w,x)) return(0); | |
| 	       if (!cuddSwapInPlace(table,y,z)) return(0); | |
| 	       break; | |
|     case BDAC: if (!cuddSwapInPlace(table,x,y)) return(0); | |
|     case CDAB: if (!cuddSwapInPlace(table,w,x)) return(0); | |
|     case ADCB: if (!cuddSwapInPlace(table,y,z)) return(0); | |
|     case ABCD: if (!cuddSwapInPlace(table,x,y)) return(0); | |
| 	       break; | |
|     case BCAD: if (!cuddSwapInPlace(table,x,y)) return(0); | |
|     case CBAD: if (!cuddSwapInPlace(table,w,x)) return(0); | |
| 	       if (!cuddSwapInPlace(table,x,y)) return(0); | |
| 	       break; | |
|     default: return(0); | |
|     } | |
| 
 | |
| #ifdef DD_DEBUG | |
|     assert(table->keys - table->isolated == (unsigned) size); | |
| #endif | |
|  | |
|     return(best); | |
| 
 | |
| } /* end of ddPermuteWindow4 */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Reorders by applying a sliding window of width 4. | |
|  | |
|   @details Tries all possible permutations to the variables in a | |
|   window that slides from low to high.  Assumes that no dead nodes are | |
|   present. | |
|  | |
|   @return 1 in case of success; 0 otherwise. | |
|  | |
|   @sideeffect None | |
|  | |
| */ | |
| static int | |
| ddWindow4( | |
|   DdManager * table, | |
|   int  low, | |
|   int  high) | |
| { | |
| 
 | |
|     int w; | |
|     int res; | |
| 
 | |
| #ifdef DD_DEBUG | |
|     assert(low >= 0 && high < table->size); | |
| #endif | |
|  | |
|     if (high-low < 3) return(ddWindow3(table,low,high)); | |
| 
 | |
|     for (w = low; w+2 < high; w++) { | |
| 	res = ddPermuteWindow4(table,w); | |
| 	if (res == 0) return(0); | |
| #ifdef DD_STATS | |
| 	if (res == ABCD) { | |
| 	    (void) fprintf(table->out,"="); | |
| 	} else { | |
| 	    (void) fprintf(table->out,"-"); | |
| 	} | |
| 	fflush(table->out); | |
| #endif | |
|     } | |
| 
 | |
|     return(1); | |
| 
 | |
| } /* end of ddWindow4 */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Reorders by repeatedly applying a sliding window of width 4. | |
|  | |
|   @details Tries all possible permutations to the variables in a | |
|   window that slides from low to high.  Assumes that no dead nodes are | |
|   present.  Uses an event-driven approach to determine convergence. | |
|  | |
|   @return 1 in case of success; 0 otherwise. | |
|  | |
|   @sideeffect None | |
|  | |
| */ | |
| static int | |
| ddWindowConv4( | |
|   DdManager * table, | |
|   int  low, | |
|   int  high) | |
| { | |
|     int x; | |
|     int res; | |
|     int nwin; | |
|     int newevent; | |
|     int *events; | |
| 
 | |
| #ifdef DD_DEBUG | |
|     assert(low >= 0 && high < table->size); | |
| #endif | |
|  | |
|     if (high-low < 3) return(ddWindowConv3(table,low,high)); | |
| 
 | |
|     nwin = high-low-2; | |
|     events = ALLOC(int,nwin); | |
|     if (events == NULL) { | |
| 	table->errorCode = CUDD_MEMORY_OUT; | |
| 	return(0); | |
|     } | |
|     for (x=0; x<nwin; x++) { | |
| 	events[x] = 1; | |
|     } | |
| 
 | |
|     do { | |
| 	newevent = 0; | |
| 	for (x=0; x<nwin; x++) { | |
| 	    if (events[x]) { | |
| 		res = ddPermuteWindow4(table,x+low); | |
| 		switch (res) { | |
| 		case ABCD: | |
| 		    break; | |
| 		case BACD: | |
| 		    if (x < nwin-1)	events[x+1] = 1; | |
| 		    if (x > 2)		events[x-3] = 1; | |
| 		    newevent = 1; | |
| 		    break; | |
| 		case BADC: | |
| 		    if (x < nwin-3)	events[x+3] = 1; | |
| 		    if (x < nwin-1)	events[x+1] = 1; | |
| 		    if (x > 0)		events[x-1] = 1; | |
| 		    if (x > 2)		events[x-3] = 1; | |
| 		    newevent = 1; | |
| 		    break; | |
| 		case ABDC: | |
| 		    if (x < nwin-3)	events[x+3] = 1; | |
| 		    if (x > 0)		events[x-1] = 1; | |
| 		    newevent = 1; | |
| 		    break; | |
| 		case ADBC: | |
| 		case ADCB: | |
| 		case ACDB: | |
| 		    if (x < nwin-3)	events[x+3] = 1; | |
| 		    if (x < nwin-2)	events[x+2] = 1; | |
| 		    if (x > 0)		events[x-1] = 1; | |
| 		    if (x > 1)		events[x-2] = 1; | |
| 		    newevent = 1; | |
| 		    break; | |
| 		case DACB: | |
| 		case DABC: | |
| 		case DBAC: | |
| 		case BDAC: | |
| 		case BDCA: | |
| 		case DBCA: | |
| 		case DCBA: | |
| 		case DCAB: | |
| 		case CDAB: | |
| 		case CDBA: | |
| 		case CBDA: | |
| 		case BCDA: | |
| 		case CADB: | |
| 		    if (x < nwin-3)	events[x+3] = 1; | |
| 		    if (x < nwin-2)	events[x+2] = 1; | |
| 		    if (x < nwin-1)	events[x+1] = 1; | |
| 		    if (x > 0)		events[x-1] = 1; | |
| 		    if (x > 1)		events[x-2] = 1; | |
| 		    if (x > 2)		events[x-3] = 1; | |
| 		    newevent = 1; | |
| 		    break; | |
| 		case BCAD: | |
| 		case CBAD: | |
| 		case CABD: | |
| 		    if (x < nwin-2)	events[x+2] = 1; | |
| 		    if (x < nwin-1)	events[x+1] = 1; | |
| 		    if (x > 1)		events[x-2] = 1; | |
| 		    if (x > 2)		events[x-3] = 1; | |
| 		    newevent = 1; | |
| 		    break; | |
| 		case ACBD: | |
| 		    if (x < nwin-2)	events[x+2] = 1; | |
| 		    if (x > 1)		events[x-2] = 1; | |
| 		    newevent = 1; | |
| 		    break; | |
| 		default: | |
| 		    FREE(events); | |
| 		    return(0); | |
| 		} | |
| 		events[x] = 0; | |
| #ifdef DD_STATS | |
| 		if (res == ABCD) { | |
| 		    (void) fprintf(table->out,"="); | |
| 		} else { | |
| 		    (void) fprintf(table->out,"-"); | |
| 		} | |
| 		fflush(table->out); | |
| #endif | |
| 	    } | |
| 	} | |
| #ifdef DD_STATS | |
| 	if (newevent) { | |
| 	    (void) fprintf(table->out,"|"); | |
| 	    fflush(table->out); | |
| 	} | |
| #endif | |
|     } while (newevent); | |
| 
 | |
|     FREE(events); | |
| 
 | |
|     return(1); | |
| 
 | |
| } /* end of ddWindowConv4 */
 |