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.
		
		
		
		
		
			
		
			
				
					
					
						
							1555 lines
						
					
					
						
							55 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							1555 lines
						
					
					
						
							55 KiB
						
					
					
				| /** | |
|   @file | |
|  | |
|   @ingroup nanotrav | |
|  | |
|   @brief Symbolic maxflow algorithm. | |
|  | |
|   @details This file contains the functions that implement the | |
|   symbolic version of Dinits's maxflow algorithm described in the | |
|   ICCAD93 paper. The present implementation differs from the algorithm | |
|   described in the paper in that more than one matching techniques is | |
|   used. The technique of the paper is the one applied to | |
|   hourglass-type bilayers here. | |
|  | |
|   @author Fabio Somenzi, Gary Hachtel | |
|  | |
|   @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 "ntr.h" | |
|  | |
| /*---------------------------------------------------------------------------*/ | |
| /* Constant declarations                                                     */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| #define MAXPHASE 1000 | |
| #define MAXLAYER 1000 | |
| #define MAXFPIT  100000 | |
| #define MANY_TIMES 3.0 | |
|  | |
| #define PRUNE		/* If defined, enables pruning of E */ | |
|  | |
| /*---------------------------------------------------------------------------*/ | |
| /* Stucture declarations                                                     */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Type declarations                                                         */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| /** | |
|    @brief Structure to hold statistics. | |
| */ | |
| typedef struct flowStatsStruct { | |
|     int pr;			/**< level of verbosity */ | |
|     long start_time;		/**< cpu time when the covering started */ | |
|     int phases;			/**< number of phases */ | |
|     int layers;			/**< number of layers */ | |
|     int fpit;			/**< number of fixed point iterations */ | |
| } flowStats; | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Variable declarations                                                     */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| static DdNode *xcube, *ycube, *zcube; | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Macro declarations                                                        */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| /** \cond */ | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Static function prototypes                                                */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| static void maximal_pull (DdManager *bdd, int l, DdNode *ty, DdNode **neW, DdNode **U, DdNode *E, DdNode **F, DdNode **x, DdNode **y, DdNode **z, int n, DdNode *pryz, DdNode *prxz, flowStats *stats); | |
| static void propagate_maximal_flow (DdManager *bdd, int m, DdNode **neW, DdNode **U, DdNode **x, DdNode **y, DdNode **z, int n, DdNode *pryz, DdNode *prxz, flowStats *stats); | |
| static void trellis (DdManager *bdd, int m, DdNode **neW, DdNode **U, DdNode **x, DdNode **y, DdNode **z, int n, DdNode *pryz, DdNode *prxz, flowStats *stats); | |
| static void rhombus (DdManager *bdd, int m, DdNode **neW, DdNode **U, DdNode **x, DdNode **y, DdNode **z, int n, DdNode *pryz, DdNode *prxz, flowStats *stats); | |
| static void hourglass (DdManager *bdd, int m, DdNode **neW, DdNode **U, DdNode **x, DdNode **y, DdNode **z, int n, DdNode *pryz, DdNode *prxz, flowStats *stats); | |
| static void maximal_push (DdManager *bdd, int l, DdNode **U, DdNode **F, DdNode **x, DdNode **y, DdNode **z, int n, DdNode *pryz, DdNode *prxz, flowStats *stats); | |
| static void trellisPush (DdManager *bdd, int m, DdNode **U, DdNode **x, DdNode **y, DdNode **z, int n, DdNode *pryz, DdNode *prxz, flowStats *stats); | |
| static void rhombusPush (DdManager *bdd, int m, DdNode **U, DdNode **x, DdNode **y, DdNode **z, int n, DdNode *pryz, DdNode *prxz, flowStats *stats); | |
| static void hourglassPush (DdManager *bdd, int m, DdNode **U, DdNode **x, DdNode **y, DdNode **z, int n, DdNode *pryz, DdNode *prxz, flowStats *stats); | |
| 
 | |
| /** \endcond */ | |
| 
 | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Definition of exported functions                                          */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Symbolic Dinit's algorithm. | |
|  | |
|   @details@parblock | |
|   This function implements Dinits's algorithm for (0-1) | |
|   max flow, using BDDs and a symbolic technique to trace multiple | |
|   edge-disjoint augmenting paths to complete a phase. The outer | |
|   forever loop is over phases, and the inner forever loop is to | |
|   propagate a (not yet) maximal flow of edge-disjoint augmenting paths | |
|   from one layer to the previous. The subprocedure call implements a | |
|   least fixed point iteration to compute a (not yet) maximal flow | |
|   update between layers. At the end of each phase (except the last | |
|   one) the flow is actually pushed from the source to the sink. | |
|  | |
|   Data items: | |
|     <ul> | |
|     <li> sx(ty)	BDD representations of s(t). | |
|     <li> x(y)	The variables encoding the from(to)-node u(v) of an | |
| 		edge (u,v) in the given digraph. | |
|     <li> z	Another set of variables. | |
|     <li> E(x,y)	The edge relation. | |
|     <li> F(x,y) %BDD representation of the current flow, initialized to 0 | |
| 		for each arc, and updated by +1, -1, or 0 at the | |
| 		end of each phase. | |
|     <li> Ms Mt	The maximum flow, that is, the cardinality of a minimum cut, | |
| 		measured at the source and at the sink, respectively. | |
| 		The two values should be identical. | |
|     <li> reached The set of nodes already visited in the BFS of the digraph. | |
|     <li> fos	fanout of the source node s. | |
|     <li> fit	fanin of the sink node t. | |
|     </ul> | |
|    | |
|   @endparblock | |
|  | |
|   @sideeffect The flow realtion F and the cutset relation cut are returned | |
|   as side effects. | |
|  | |
| */ | |
| double | |
| Ntr_maximum01Flow( | |
|   DdManager * bdd /**< manager */, | |
|   DdNode * sx /**< source node */, | |
|   DdNode * ty /**< sink node */, | |
|   DdNode * E /**< edge relation */, | |
|   DdNode ** F /**< flow relation */, | |
|   DdNode ** cut /**< cutset relation */, | |
|   DdNode ** x /**< array of row variables */, | |
|   DdNode ** y /**< array of column variables */, | |
|   DdNode ** z /**< arrays of auxiliary variables */, | |
|   int  n /**< number of variables in each array */, | |
|   int  pr /**< verbosity level */) | |
| { | |
|     flowStats stats; | |
|     DdNode *one, *zero, | |
| #ifdef PRUNE | |
| 	     *EDC,	    /* Edge don't care set */ | |
| #endif | |
| 	     *reached,      /* states reached through useful edges */ | |
| 	     *fos, *fit,    /* fanout of source, fanin of sink */ | |
| 	     *rF, *rB, *tx, | |
| 	     *I, *P, | |
| 	     *w, *p, *q, *r,/* intemediate results */ | |
| 	     *pryz, *prxz,  /* priority functions for disjoint path tracing */ | |
| 	     **neW, **U;    /* arrays of BDDs for flow propagation */ | |
|     int	     i, j, l; | |
|     double   Ms, Mt; | |
| 
 | |
|     /* Initialize debugging structure. */ | |
|     stats.pr = pr; | |
|     stats.start_time = util_cpu_time(); | |
|     stats.phases = 0; | |
|     stats.layers = 0; | |
|     stats.fpit = 0; | |
| 
 | |
|     /* Allocate arrays for new (just reached vertex sets) | |
|     ** and U (useful edge sets). | |
|     */ | |
|     U   = ALLOC(DdNode *, ((unsigned) MAXLAYER)); | |
|     neW = ALLOC(DdNode *, ((unsigned) MAXLAYER)); | |
| 
 | |
|     one = Cudd_ReadOne(bdd); | |
|     zero = Cudd_Not(one); | |
| 
 | |
|     /* Initialize xcube, ycube, and zcube (for abstractions). */ | |
|     Cudd_Ref(xcube = Cudd_bddComputeCube(bdd,x,NULL,n)); | |
|     Cudd_Ref(ycube = Cudd_bddComputeCube(bdd,y,NULL,n)); | |
|     Cudd_Ref(zcube = Cudd_bddComputeCube(bdd,z,NULL,n)); | |
| 
 | |
|     /* Build the BDD for the priority functions. */ | |
|     Cudd_Ref(pryz = Cudd_Dxygtdxz(bdd, n, x, y, z)); | |
|     Cudd_Ref(prxz = Cudd_Dxygtdyz(bdd, n, x, y, z)); | |
|     /* Now "randomize" by shuffling the x variables in pryz and the y | |
|     ** variables in prxz. | |
|     */ | |
|     Cudd_Ref(p = Cudd_bddAdjPermuteX(bdd,pryz,x,n)); | |
|     Cudd_RecursiveDeref(bdd,pryz); | |
|     pryz = p; | |
|     if(pr>2){(void) fprintf(stdout,"pryz");Cudd_PrintDebug(bdd,pryz,n*3,pr);} | |
|     Cudd_Ref(p = Cudd_bddAdjPermuteX(bdd,prxz,y,n)); | |
|     Cudd_RecursiveDeref(bdd,prxz); | |
|     prxz = p; | |
|     if(pr>2){(void) fprintf(stdout,"prxz");Cudd_PrintDebug(bdd,prxz,n*3,pr);} | |
| 
 | |
| #ifdef PRUNE | |
|     /* Build the edge don't care set and prune E. The edge don't care | |
|     ** set consists of the edges into the source(s), the edges out of the | |
|     ** sink(s), and the self-loops. These edges cannot contribute to the | |
|     ** maximum flow. | |
|     */ | |
|     Cudd_Ref(p = Cudd_bddSwapVariables(bdd, sx, x, y, n)); | |
|     Cudd_Ref(q = Cudd_bddSwapVariables(bdd, ty, x, y, n)); | |
|     Cudd_Ref(r = Cudd_bddOr(bdd, p, q)); | |
|     Cudd_RecursiveDeref(bdd,p); | |
|     Cudd_RecursiveDeref(bdd,q); | |
|     Cudd_Ref(p = Cudd_Xeqy(bdd, n, x, y)); | |
|     Cudd_Ref(EDC = Cudd_bddOr(bdd, p, r)); | |
|     Cudd_RecursiveDeref(bdd,p); | |
|     Cudd_RecursiveDeref(bdd,r); | |
|     if(pr>2){(void) fprintf(stdout,"EDC");Cudd_PrintDebug(bdd,EDC,n<<1,pr);} | |
|     Cudd_Ref(p = Cudd_bddAnd(bdd, E, Cudd_Not(EDC))); | |
|     Cudd_RecursiveDeref(bdd,EDC); | |
|     if(pr>0){(void) fprintf(stdout,"Given  E");Cudd_PrintDebug(bdd,E,n<<1,pr);} | |
|     E = p; | |
|     if(pr>0){(void) fprintf(stdout,"Pruned E");Cudd_PrintDebug(bdd,E,n<<1,pr);} | |
| #endif | |
|  | |
|     /* Compute fanin of sink node t: it is an upper bound for the flow. */ | |
|     Cudd_Ref(fit = Cudd_bddAnd(bdd, E, ty)); | |
|     if (pr>2) { | |
| 	/* Compute fanout of source node s. */ | |
| 	Cudd_Ref(fos = Cudd_bddAnd(bdd, E, sx)); | |
| 	(void) fprintf(stdout,"fos");Cudd_PrintDebug(bdd,fos,n<<1,pr); | |
| 	Cudd_RecursiveDeref(bdd,fos); | |
| 
 | |
| 	(void) fprintf(stdout,"fit");Cudd_PrintDebug(bdd,fit,n<<1,pr); | |
|     } | |
|     /* t(x) is used to check for termination of forward traversal. */ | |
|     Cudd_Ref(tx = Cudd_bddSwapVariables(bdd, ty, x, y, n)); | |
| 
 | |
|     /* \KW{Procedure}\ \ \PC{maximum\_flow}$(s,t,E(x,y)) */ | |
|     Cudd_Ref(*F = zero); | |
| 
 | |
|     for (i = 1; i < MAXPHASE; i++) { | |
| 	stats.phases++; | |
| 	if(pr>0){(void) fprintf(stdout,"## Starting Phase %d at time = %s\n",i, | |
| 		util_print_time(util_cpu_time() - stats.start_time));} | |
| 	/* new[0](x) = s(x);U^0(x,y)=E(x,y)\cdot s(x) \cdot \overline{F(x,y)}; | |
| 	** reached=s; new[1](x)=\exists_xU^0(x,y); | |
| 	*/ | |
| 	Cudd_Ref(neW[0] = sx); | |
| 	Cudd_Ref(p = Cudd_bddAnd(bdd, sx, Cudd_Not(*F))); | |
| 	Cudd_Ref(U[0] = Cudd_bddAnd(bdd, p, E)); | |
| 	Cudd_RecursiveDeref(bdd,p); | |
| 	Cudd_Ref(reached = sx); | |
| 	Cudd_Ref(r = Cudd_bddExistAbstract(bdd, U[0], xcube)); | |
| 	Cudd_RecursiveDeref(bdd,U[0]); | |
| 	Cudd_Ref(q = Cudd_bddSwapVariables(bdd, r, x, y, n)); | |
| 	Cudd_RecursiveDeref(bdd,r); | |
| 	Cudd_Ref(neW[1] = Cudd_bddAnd(bdd, q, Cudd_Not(reached))); | |
| 	Cudd_RecursiveDeref(bdd,q); | |
| 	if(pr>0) { | |
| 	    (void) fprintf(stdout,"neW[1]");Cudd_PrintDebug(bdd,neW[1],n,pr); | |
| 	} | |
| 	for (l = 1; l < MAXLAYER; l++) { | |
| 	    if (neW[l] == zero) {	/* flow is maximum */ | |
| 		/* cut=reached(x) \cdot E(x,y) \cdot \overline{reached(y)} */ | |
| 		Cudd_Ref(p = Cudd_bddAnd(bdd, reached, E)); | |
| 		Cudd_Ref(q = Cudd_bddSwapVariables(bdd, reached, x, y, n)); | |
| 		Cudd_Ref(*cut = Cudd_bddAnd(bdd, p, Cudd_Not(q))); | |
| 		Cudd_RecursiveDeref(bdd,p); | |
| 		Cudd_RecursiveDeref(bdd,q); | |
| 		Cudd_RecursiveDeref(bdd,reached); | |
| 		for (j = 0; j <= l; j++) | |
| 		    Cudd_RecursiveDeref(bdd,neW[j]); | |
| 		goto endPhases; | |
| 	    } | |
| 	    /* As soon as we touch one sink node we stop traversal. | |
| 	    ** \KW{if} ($t\cdot new^{l} \neq 0$) | |
| 	    */ | |
| 	    if (!Cudd_bddLeq(bdd, tx, Cudd_Not(neW[l]))) { | |
| 		Cudd_RecursiveDeref(bdd,reached); | |
| 		maximal_pull(bdd,l-1,ty,neW,U,E,F,x,y,z,n,pryz,prxz,&stats); | |
| 		goto endLayers; | |
| 	    } | |
| 	    stats.layers++; | |
| 	    if(pr>2){(void) fprintf(stdout,"===== Layer %d =====\n",l);} | |
| 	    /* reached(x) = reached(x) + new^l(x) */ | |
| 	    Cudd_Ref(w = Cudd_bddOr(bdd, reached, neW[l])); | |
| 	    Cudd_RecursiveDeref(bdd,reached); | |
| 	    reached = w; | |
| 	    /* I(y) = \exists_x((E(x,y) \cdot \overline{F(x,y)}) | |
| 	    **        \cdot new^l(x)) | |
| 	    */ | |
| 	    Cudd_Ref(p = Cudd_bddAnd(bdd, E, Cudd_Not(*F))); | |
| 	    Cudd_Ref(I = Cudd_bddAndAbstract(bdd, p, neW[l], xcube)); | |
| 	    if(pr>3){(void) fprintf(stdout,"I");Cudd_PrintDebug(bdd,I,n,pr);} | |
| 	    Cudd_RecursiveDeref(bdd,p); | |
| 	    /* rF(x)= I(x) \cdot \overline{reached(x)}) */ | |
| 	    Cudd_Ref(p = Cudd_bddSwapVariables(bdd, I, x, y, n)); | |
| 	    Cudd_RecursiveDeref(bdd,I); | |
| 	    Cudd_Ref(rF = Cudd_bddAnd(bdd, p, Cudd_Not(reached))); | |
| 	    Cudd_RecursiveDeref(bdd,p); | |
| 	    if(pr>2){(void) fprintf(stdout,"rF");Cudd_PrintDebug(bdd,rF,n,pr);} | |
| 	    /* P(x) = \exists_{y}(F(x,y) \cdot new^l(y)) */ | |
| 	    Cudd_Ref(p = Cudd_bddSwapVariables(bdd, neW[l], x, y, n)); | |
| 	    Cudd_Ref(P = Cudd_bddAndAbstract(bdd, *F, p, ycube)); | |
| 	    Cudd_RecursiveDeref(bdd,p); | |
| 	    /* rB(x) = P(x) \cdot \overline{reached(x)}) */ | |
| 	    Cudd_Ref(rB = Cudd_bddAnd(bdd, P, Cudd_Not(reached))); | |
| 	    Cudd_RecursiveDeref(bdd,P); | |
| 	    if(pr>2){(void) fprintf(stdout,"rB");Cudd_PrintDebug(bdd,rB,n,pr);} | |
| 	    /* new^{l+1}(x) = rF(x) + rB(x) */ | |
| 	    Cudd_Ref(neW[l+1] = Cudd_bddOr(bdd, rF, rB)); | |
| 	    Cudd_RecursiveDeref(bdd,rB); | |
| 	    Cudd_RecursiveDeref(bdd,rF); | |
| 	    if(pr>0) { | |
| 		(void) fprintf(stdout,"new[%d]",l+1); | |
| 		Cudd_PrintDebug(bdd,neW[l+1],n,pr); | |
| 	    } | |
| 	} /* start next layer */ | |
| 	if (l==MAXLAYER) (void) fprintf(stderr,"ERROR! MAXLAYER exceeded.\n"); | |
| 	exit(3); | |
| endLayers: | |
| 	maximal_push(bdd, l-1, U, F, x, y, z, n, pryz, prxz, &stats); | |
| 	for (j = 0; j < l; j++) { | |
| 	    Cudd_RecursiveDeref(bdd,U[j]); | |
| 	    Cudd_RecursiveDeref(bdd,neW[j]); | |
| 	} | |
| 	Cudd_RecursiveDeref(bdd,neW[l]); | |
| 	if (pr > 0) { | |
| 	    Cudd_Ref(p = Cudd_bddAnd(bdd, sx, *F)); | |
| 	    Ms=Cudd_CountMinterm(bdd, p, n<<1); | |
| 	    (void) fprintf(stdout,"# Flow out of s: %g\n", Ms); | |
| 	    Cudd_RecursiveDeref(bdd,p); | |
| 	} | |
| 	if (Cudd_bddLeq(bdd, fit, *F)) { | |
| 	    Cudd_Ref(*cut = fit); | |
| 	    goto endPhases; | |
| 	} | |
|     } /* start next phase */ | |
|     if (i == MAXPHASE) (void) fprintf(stderr,"ERROR! MAXPHASE exceeded.\n"); | |
| 
 | |
|     /* Last phase is completed --- print flow results. */ | |
| endPhases: | |
|     Cudd_RecursiveDeref(bdd,tx); | |
| 
 | |
|     Cudd_Ref(q = Cudd_bddAnd(bdd, *F, sx)); | |
|     Ms = Cudd_CountMinterm(bdd, q, n<<1); | |
|     Cudd_RecursiveDeref(bdd,q); | |
| 
 | |
|     Cudd_Ref(q = Cudd_bddAnd(bdd, *F, ty)); | |
|     Mt = Cudd_CountMinterm(bdd, q, n<<1); | |
|     Cudd_RecursiveDeref(bdd,q); | |
| 
 | |
|     if (pr>1) (void) fprintf(stdout,"Mt= %g, Ms= %g \n", Mt, Ms); | |
| 
 | |
|     if (pr>3){(void) fprintf(stdout,"pryz");Cudd_PrintDebug(bdd,pryz,n*3,pr);} | |
|     if (pr>3){(void) fprintf(stdout,"prxz");Cudd_PrintDebug(bdd,prxz,n*3,pr);} | |
| 
 | |
|     if (pr>0) { | |
| 	(void) fprintf(stdout,"#### Stats for maximum_flow ####\n"); | |
| 	(void) fprintf(stdout,"%d variables %d of which x[i]\n", Cudd_ReadSize(bdd), n); | |
| 	(void) fprintf(stdout,"time       = %s\n", | |
| 		util_print_time(util_cpu_time() - stats.start_time)); | |
| 	(void) fprintf(stdout,"phases     = %d\n", stats.phases); | |
| 	(void) fprintf(stdout,"layers     = %d\n", stats.layers); | |
| 	(void) fprintf(stdout,"FP iter.   = %d\n", stats.fpit); | |
|     } | |
| 
 | |
|     Cudd_RecursiveDeref(bdd,fit); | |
|     Cudd_RecursiveDeref(bdd,pryz); | |
|     Cudd_RecursiveDeref(bdd,prxz); | |
|     Cudd_RecursiveDeref(bdd,xcube); | |
|     Cudd_RecursiveDeref(bdd,ycube); | |
|     Cudd_RecursiveDeref(bdd,zcube); | |
| #ifdef PRUNE | |
|     Cudd_RecursiveDeref(bdd,E); | |
| #endif | |
|  | |
|     FREE(U); | |
|     FREE(neW); | |
| 
 | |
|     return(Ms); | |
| 
 | |
| } /* end of Ntr_maximum01Flow */ | |
| 
 | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Definition of internal functions                                          */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Definition of static functions                                            */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Selects set of edge-disjoint paths from layered network. | |
|  | |
|   @details maximal_pull is called when the BFS constructing the | |
|   layered graph reaches a sink. At this point the new sets of the | |
|   BFS have been formed, and we know every vertex in these sets is | |
|   reachable from the source vertex (or vertices) s. The new sets are | |
|   used to compute the set of useful edges exiting each layer to the | |
|   right. In each layer, propagate_maximal_flow is called to select a | |
|   maximal subset of these useful edges. This subset is then used to | |
|   prune new and U. | |
|  | |
|   @sideeffect None | |
|  | |
|   @see maximal_push | |
|  | |
| */ | |
| static void | |
| maximal_pull( | |
|   DdManager * bdd /**< manager */, | |
|   int  l /**< depth of layered network for current phase */, | |
|   DdNode * ty /**< sink node */, | |
|   DdNode ** neW /**< array of BFS layers */, | |
|   DdNode ** U /**< array of useful edges */, | |
|   DdNode * E /**< edge relation */, | |
|   DdNode ** F /**< flow relation */, | |
|   DdNode ** x /**< array of variables for rows and columns */, | |
|   DdNode ** y /**< array of variables for rows and columns */, | |
|   DdNode ** z /**< array of variables for rows and columns */, | |
|   int  n /**< number of x variables */, | |
|   DdNode * pryz /**< priority function */, | |
|   DdNode * prxz /**< priority function */, | |
|   flowStats * stats /**< statistics */) | |
| { | |
|     DdNode *p, *q, *r, | |
| 	   *UF, *UB; | |
|     int	   m, | |
| 	   pr;		/* Print control */ | |
| 
 | |
|     pr = stats->pr; | |
| 
 | |
|     /* The useful edges of the last layer are all the empty edges into | |
|     ** the sink(s) from new[l]. | |
|     ** U^{l}(x,y) = t(y)\cdot \overline{F(x,y)}\cdot E(x,y)\cdot new^{l}(x) | |
|     */ | |
|     Cudd_Ref(p = Cudd_bddAnd(bdd, E, Cudd_Not(*F))); | |
|     Cudd_Ref(q = Cudd_bddAnd(bdd, neW[l], p)); | |
|     Cudd_RecursiveDeref(bdd,p); | |
|     Cudd_Ref(U[l] = Cudd_bddAnd(bdd, ty, q)); | |
|     Cudd_RecursiveDeref(bdd,q); | |
|     if(pr>1){(void) fprintf(stdout,"U[%d]",l);Cudd_PrintDebug(bdd,U[l],n<<1,pr);} | |
|     /* Eliminate from new[l] the states with no paths to the sink(s). | |
|     ** new^{l}(x)=\exists_y U^{l}(x,y) | |
|     */ | |
|     Cudd_RecursiveDeref(bdd,neW[l]); | |
|     Cudd_Ref(neW[l] = Cudd_bddExistAbstract(bdd, U[l], ycube)); | |
| 
 | |
|     for (m = l; m >= 1; m--) { | |
| 	/* Find usable backward edges from level m-1 to level m. | |
| 	** UB(x,y) = new^{m}(x) \cdot F(x,y) \cdot new^{m-1}(y) | |
| 	*/ | |
| 	Cudd_Ref(r = Cudd_bddSwapVariables(bdd, neW[m-1], x, y, n)); | |
| 	Cudd_Ref(q = Cudd_bddAnd(bdd, r, *F)); | |
| 	Cudd_RecursiveDeref(bdd,r); | |
| 	Cudd_Ref(UB = Cudd_bddAnd(bdd, neW[m], q)); | |
| 	Cudd_RecursiveDeref(bdd,q); | |
| 	if(pr>2){(void) fprintf(stdout,"UB");Cudd_PrintDebug(bdd,UB,n<<1,pr);} | |
| 	/* Find usable forward edges. | |
| 	** UF(x,y) = new^{m}(y) \cdot \overline{F(x,y)} \cdot E(x,y) | |
| 	** \cdot new^{m-1}(x) | |
| 	*/ | |
| 	Cudd_Ref(p = Cudd_bddAnd(bdd, E, Cudd_Not(*F))); | |
| 	Cudd_Ref(q = Cudd_bddAnd(bdd, neW[m-1], p)); | |
| 	Cudd_RecursiveDeref(bdd,p); | |
| 	Cudd_Ref(r = Cudd_bddSwapVariables(bdd, neW[m], x, y, n)); | |
| 	Cudd_Ref(UF = Cudd_bddAnd(bdd, r, q)); | |
| 	Cudd_RecursiveDeref(bdd,q); | |
| 	Cudd_RecursiveDeref(bdd,r); | |
| 	if(pr>2){(void) fprintf(stdout,"UF");Cudd_PrintDebug(bdd,UF,n<<1,pr);} | |
| 	/* U^{m-1}(x,y) = UB(y,x) + UF(x,y) */ | |
| 	Cudd_Ref(r = Cudd_bddSwapVariables(bdd, UB, x, y, n)); | |
| 	Cudd_RecursiveDeref(bdd,UB); | |
| 	Cudd_Ref(U[m-1] = Cudd_bddOr(bdd, UF, r)); | |
| 	Cudd_RecursiveDeref(bdd,UF); | |
| 	Cudd_RecursiveDeref(bdd,r); | |
| 	if(pr>2){(void)fprintf(stdout,"U[%d]",m-1); | |
| 		Cudd_PrintDebug(bdd,U[m-1],n<<1,pr);} | |
| 	/* new[m-1](x) = \exists_{y}U^{m-1}(x,y) */ | |
| 	Cudd_RecursiveDeref(bdd,neW[m-1]); | |
| 	Cudd_Ref(neW[m-1] = Cudd_bddExistAbstract(bdd, U[m-1], ycube)); | |
| 	/* Compute maximal disjoint interlayer edge set. */ | |
| 	propagate_maximal_flow(bdd, m, neW, U, x, y, z, n, pryz, prxz, stats); | |
| 	if(pr>0) { | |
| 	    (void)fprintf(stdout,"U[%d]",m-1); | |
| 	    Cudd_PrintDebug(bdd,U[m-1],n<<1,pr); | |
| 	} | |
|     } /* prune next layer */ | |
| 
 | |
|     return; | |
| 
 | |
| } /* end of maximal_pull */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Pulls flow though a layer. | |
|  | |
|   @details propagate_maximal_flow only | |
|   affects U[m-1 and new[m-1].  At the end of this function, the edges | |
|   in U[m] are guaranteed to drain all the flow supplied by the edges | |
|   in U[m-1]. This effect is obtained by pruning U[m-1]. After the | |
|   pruned U[m-1] is computed, new[m-1] is updated to keep track of what | |
|   nodes are still useful. | |
|  | |
|   The pruning is performed without actually measuring the in-potential | |
|   and the out-potential of each node. Instead, pairs of nodes from U[m-1] | |
|   and U[m] are matched. To avoid counting, the procedure computes sets of | |
|   paths that connect layer m-1 to layer m+1 and are edge-disjoint. | |
|  | |
|   Two paths from layer m-1 to layer m+1 are disjoint if they have distinct | |
|   end-point or if they have distinct middle points. What condition to | |
|   enforce depends on the "shape" of the layers.] | |
|  | |
|   @sideeffect Changes U[m-1 and new[m-1]] | |
|  | |
|   @see trellis rhombus hourglass | |
|  | |
| */ | |
| static void | |
| propagate_maximal_flow( | |
|   DdManager * bdd /**< %DD manager */, | |
|   int  m /**< center of current bilayer */, | |
|   DdNode ** neW /**< array of reachable or useful nodes */, | |
|   DdNode ** U /**< array of usable or useful edges */, | |
|   DdNode ** x /**< array of variables for rows and columns */, | |
|   DdNode ** y /**< array of variables for rows and columns */, | |
|   DdNode ** z /**< array of variables for rows and columns */, | |
|   int  n /**< number of x variables */, | |
|   DdNode * pryz /**< priority function */, | |
|   DdNode * prxz /**< priority function */, | |
|   flowStats * stats /**< statistics */) | |
| { | |
|     DdNode *rN; | |
|     double   mtl, mtc, mtr;	/* minterms for left, center, right levels */ | |
|     int      pr;		/* print control */ | |
| 
 | |
|     pr = stats->pr; | |
| 
 | |
|     mtl = Cudd_CountMinterm(bdd, neW[m-1], n); | |
|     mtc = Cudd_CountMinterm(bdd, neW[m], n); | |
| 
 | |
|     /* rN(y) = \exists_x U^{m}(x,y) */ | |
|     Cudd_Ref(rN = Cudd_bddExistAbstract(bdd, U[m], xcube)); | |
|     mtr = Cudd_CountMinterm(bdd, rN, n); | |
|     Cudd_RecursiveDeref(bdd,rN); | |
| 
 | |
|     if (pr > 0) { | |
| 	(void) fprintf(stdout, "layer = %d mtl = %g  mtc = %g  mtr = %g", | |
| 		       m, mtl, mtc, mtr); | |
|     } | |
| 
 | |
|     if ((mtc > MANY_TIMES * mtl) || (mtc > MANY_TIMES * mtr)) { | |
| 	if (pr>0) (void) fprintf(stdout, " R\n"); | |
| 	rhombus(bdd, m, neW, U, x, y, z, n, pryz, prxz, stats); | |
|     } else if (mtr > MANY_TIMES * mtc) { | |
| 	if (pr>0) (void) fprintf(stdout, " H\n"); | |
| 	hourglass(bdd, m, neW, U, x, y, z, n, pryz, prxz, stats); | |
|     } else { | |
| 	if (pr>0) (void) fprintf(stdout, " T\n"); | |
| 	trellis(bdd, m, neW, U, x, y, z, n, pryz, prxz, stats); | |
|     } | |
|     return; | |
| 
 | |
| } /* end of propagate_maximal_flow */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Selects edges from a trellis-type bilayer. | |
|  | |
|   @details Used to pull flow.  First a matching is found in the left | |
|   layer. Then the paths are extended (if possible) through the right | |
|   layer. This process is repeated until a maximal flow is found. | |
|  | |
|   @sideeffect None | |
|  | |
|   @see rhombus hourglass trellisPush | |
|  | |
| */ | |
| static void | |
| trellis( | |
|   DdManager * bdd /**< %DD manager */, | |
|   int  m /**< center level of current bilayer */, | |
|   DdNode ** neW /**< array of node levels */, | |
|   DdNode ** U /**< array of edge layers */, | |
|   DdNode ** x /**< array of variables for rows and columns */, | |
|   DdNode ** y /**< array of variables for rows and columns */, | |
|   DdNode ** z /**< array of variables for rows and columns */, | |
|   int  n /**< number of x variables */, | |
|   DdNode * pryz /**< priority function */, | |
|   DdNode * prxz /**< priority function */, | |
|   flowStats * stats /**< statistics */) | |
| { | |
|     DdNode *one, *zero, | |
| 	     *p, *q, *r, | |
| 	     *Uin,		/* edges to be matched from U[m-1] */ | |
| 	     *Uout,		/* edges to be matched from U[m] */ | |
| 	     *P, | |
| 	     *LU, *RU,		/* left-unique and right-unique sets of edges */ | |
| 	     *D, | |
| 	     *Ml, *Mr;		/* nodes matched from left and right */ | |
|     int      k, | |
| 	     pr;		/* print control */ | |
| 
 | |
|     pr = stats->pr; | |
| 
 | |
|     one = Cudd_ReadOne(bdd); | |
|     zero = Cudd_Not(one); | |
| 
 | |
|     /*Uout(x,y)=U^m(x,y)*/ | |
|     Cudd_Ref(Uout = U[m]); | |
|     if(pr>3){(void)fprintf(stdout,"Uout");Cudd_PrintDebug(bdd,Uout,n<<1,pr);} | |
|     /*Uin(x,y)=U^{m-1}(x,y)*/ | |
|     Cudd_Ref(Uin = U[m-1]); | |
|     if(pr>3){(void)fprintf(stdout,"Uin");Cudd_PrintDebug(bdd,Uin,n<<1,pr);} | |
| 
 | |
|     for(k = 0; k < MAXFPIT; k++) { | |
| 	stats->fpit++; | |
| 	/*LU(x,y)=Uin(x,y)\cdot\overline{\exists_{z}(Uin(z,y)\cdot\Pi(x,z))}*/ | |
| 	Cudd_Ref(p = Cudd_bddSwapVariables(bdd, Uin, x, z, n)); | |
| 	Cudd_Ref(r = Cudd_bddAndAbstract(bdd, p, prxz, zcube)); | |
| 	Cudd_RecursiveDeref(bdd,p); | |
| 	Cudd_Ref(LU = Cudd_bddAnd(bdd, Uin, Cudd_Not(r))); | |
| 	Cudd_RecursiveDeref(bdd,r); | |
| 	if(pr>3){(void)fprintf(stdout,"LU");Cudd_PrintDebug(bdd,LU,n<<1,pr);} | |
| 	/*D(x,y)= LU(x,y)\cdot \overline{\exists_{z}(LU(x,z)\cdot \Pi(y,z))}*/ | |
| 	Cudd_Ref(p = Cudd_bddSwapVariables(bdd, LU, y, z, n)); | |
| 	Cudd_Ref(r = Cudd_bddAndAbstract(bdd, p, pryz, zcube)); | |
| 	Cudd_RecursiveDeref(bdd,p); | |
| 	Cudd_Ref(D = Cudd_bddAnd(bdd, LU, Cudd_Not(r))); | |
| 	Cudd_RecursiveDeref(bdd,r); | |
| 	Cudd_RecursiveDeref(bdd,LU); | |
| 	if(pr>3){(void)fprintf(stdout,"D");Cudd_PrintDebug(bdd,D,n<<1,pr);} | |
| 	/*Ml(y)=\exists_{x}D(x,y)*/ | |
| 	Cudd_Ref(Ml = Cudd_bddExistAbstract(bdd, D, xcube)); | |
| 	if(pr>3){(void)fprintf(stdout,"Ml");Cudd_PrintDebug(bdd,Ml,n,pr);} | |
| 	/*P(x,y)=Ml(x)\cdot Uout(x,y)*/ | |
| 	Cudd_Ref(p = Cudd_bddSwapVariables(bdd, Ml, x, y, n)); | |
| 	Cudd_Ref(P = Cudd_bddAnd(bdd, p, Uout)); | |
| 	Cudd_RecursiveDeref(bdd,p); | |
| 	Cudd_RecursiveDeref(bdd,Ml); | |
| 	if(pr>3){(void)fprintf(stdout,"P");Cudd_PrintDebug(bdd,P,n<<1,pr);} | |
| 	/*RU(x,y)= P(x,y)\cdot \overline{\exists_{z}(P(x,z)\cdot \Pi(y,z))}*/ | |
| 	Cudd_Ref(p = Cudd_bddSwapVariables(bdd, P, y, z, n)); | |
| 	Cudd_Ref(r = Cudd_bddAndAbstract(bdd, p, pryz, zcube)); | |
| 	Cudd_RecursiveDeref(bdd,p); | |
| 	Cudd_Ref(RU = Cudd_bddAnd(bdd, P, Cudd_Not(r))); | |
| 	Cudd_RecursiveDeref(bdd,r); | |
| 	Cudd_RecursiveDeref(bdd,P); | |
| 	if(pr>3){(void)fprintf(stdout,"RU");Cudd_PrintDebug(bdd,RU,n<<1,pr);} | |
| 	/*Mr(x)=\exists_{y}RU(x,y)*/ | |
| 	Cudd_Ref(Mr = Cudd_bddExistAbstract(bdd, RU, ycube)); | |
| 	if(pr>3){(void)fprintf(stdout,"Mr");Cudd_PrintDebug(bdd,Mr,n,pr);} | |
| 	/*D(x,y)=D(x,y)\cdot Mr(y)*/ | |
| 	Cudd_Ref(p = Cudd_bddSwapVariables(bdd, Mr, x, y, n)); | |
| 	Cudd_RecursiveDeref(bdd,Mr); | |
| 	Cudd_Ref(q = Cudd_bddAnd(bdd, D, p)); | |
| 	Cudd_RecursiveDeref(bdd,p); | |
| 	Cudd_RecursiveDeref(bdd,D); | |
| 	D = q; | |
| 	if(pr>3){(void)fprintf(stdout,"D");Cudd_PrintDebug(bdd,D,n<<1,pr);} | |
| 	/*Uin(x,y)=Uin(x,y)-D(x,y)*/ | |
| 	Cudd_Ref(p = Cudd_bddAnd(bdd, Uin, Cudd_Not(D))); | |
| 	Cudd_RecursiveDeref(bdd,Uin); | |
| 	Uin = p; | |
| 	if(pr>3){(void)fprintf(stdout,"Uin");Cudd_PrintDebug(bdd,Uin,n<<1,pr);} | |
| 	/*Uout(x,y)=Uout(x,y)-RU(x,y)*/ | |
| 	Cudd_Ref(p = Cudd_bddAnd(bdd, Uout, Cudd_Not(RU))); | |
| 	Cudd_RecursiveDeref(bdd,Uout); | |
| 	Cudd_RecursiveDeref(bdd,RU); | |
| 	Uout = p; | |
| 	if(pr>3){(void)fprintf(stdout,"Uout");Cudd_PrintDebug(bdd,Uout,n<<1,pr);} | |
| 	/*\KW{if}(($D(x,y)=zero$)~~\KW{or}~~($Uin(x,y)=zero$)~~\KW{or} | |
| 	  ($Uout(x,y)=zero$))~~KW{break}*/ | |
| 	if ((D == zero)||(Uin == zero)||(Uout == zero)) { | |
| 	    Cudd_RecursiveDeref(bdd,D); | |
| 	    break; | |
| 	} | |
| 	Cudd_RecursiveDeref(bdd,D); | |
| 
 | |
|     } /* Next least fixed point iteration with smaller Uin and Uout */ | |
|     if (k == MAXFPIT) (void) fprintf(stderr, | |
| 	"Trellis: WARNING! MAXFPIT (%d) exceeded processing Layer %d.\n", | |
| 	MAXFPIT, m); | |
| 
 | |
|     if (Uin != zero) { | |
| 	/* $U^{m-1}(x,y) = U^{m-1}(x,y)-Uin(x,y)$*/ | |
| 	Cudd_Ref(p = Cudd_bddAnd(bdd, U[m-1], Cudd_Not(Uin))); | |
| 	Cudd_RecursiveDeref(bdd,U[m-1]); | |
| 	U[m-1] = p; | |
| 	/* $new^{m-1}(x,y) = \esists_yU^{m-1}(x,y)$*/ | |
| 	Cudd_RecursiveDeref(bdd,neW[m-1]); | |
| 	Cudd_Ref(neW[m-1] = Cudd_bddExistAbstract(bdd, U[m-1], ycube)); | |
|     } | |
|     if(pr>2){(void)fprintf(stdout,"U[%d]",m-1); Cudd_PrintDebug(bdd,U[m-1],n<<1,pr);} | |
|     if(pr>2){(void)fprintf(stdout,"new[%d]",m-1); | |
| 		Cudd_PrintDebug(bdd,neW[m-1],n,pr);} | |
| 
 | |
|     Cudd_RecursiveDeref(bdd,Uin); | |
|     Cudd_RecursiveDeref(bdd,Uout); | |
| 
 | |
|     return; | |
| 
 | |
| } /* end of trellis */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Selects edges from a rhombus-type bilayer. | |
|  | |
|   @details Used to pull flow.  Makes the left layer left-unique and | |
|   the right layer right-unique. Prunes and repeats until convergence | |
|   to a maximal flow. It makes sure that all intermediate points of the | |
|   two-arc paths are disjoint at each iteration. | |
|  | |
|   @sideeffect None | |
|  | |
|   @see trellis hourglass rhombusPush | |
|  | |
| */ | |
| static void | |
| rhombus( | |
|   DdManager * bdd /**< %DD manager */, | |
|   int  m /**< center of current bilayer */, | |
|   DdNode ** neW /**< array for flow propagation */, | |
|   DdNode ** U /**< array for flow propagation */, | |
|   DdNode ** x /**< array of variables for rows and columns */, | |
|   DdNode ** y /**< array of variables for rows and columns */, | |
|   DdNode ** z /**< array of variables for rows and columns */, | |
|   int  n /**< number of x variables */, | |
|   DdNode * pryz /**< priority function */, | |
|   DdNode * prxz /**< priority function */, | |
|   flowStats * stats /**< statistics */) | |
| { | |
|     DdNode *one, *zero, | |
| 	     *p, *q, *r, | |
| 	     *Uin,		/* edges to be matched from U[m-1] */ | |
| 	     *Uout,		/* edges to be matched from U[m] */ | |
| 	     *P, | |
| 	     *LU, *RU,		/* left-unique and right-unique sets of edges */ | |
| 	     *Ml, *Mr;		/* nodes matched from left and right */ | |
|     int      k, | |
| 	     pr;		/* print control */ | |
| 
 | |
|     pr = stats->pr; | |
| 
 | |
|     one = Cudd_ReadOne(bdd); | |
|     zero = Cudd_Not(one); | |
| 
 | |
|     /*Uout(x,y)=U^m(x,y)*/ | |
|     Cudd_Ref(Uout = U[m]); | |
|     if(pr>3){(void)fprintf(stdout,"Uout");Cudd_PrintDebug(bdd,Uout,n<<1,pr);} | |
| 
 | |
|     /*Uin(x,y)=U^{m-1}(x,y)*/ | |
|     Cudd_Ref(Uin = U[m-1]); | |
|     if(pr>3){(void)fprintf(stdout,"Uin");Cudd_PrintDebug(bdd,Uin,n<<1,pr);} | |
| 
 | |
|     for(k = 0; k < MAXFPIT; k++) { | |
| 	stats->fpit++; | |
| 	/*LU(x,y)=Uin(x,y)\cdot\overline{\exists_{z}(Uin(z,y)\cdot\Pi(x,z))}*/ | |
| 	Cudd_Ref(p = Cudd_bddSwapVariables(bdd, Uin, x, z, n)); | |
| 	Cudd_Ref(r = Cudd_bddAndAbstract(bdd, p, prxz, zcube)); | |
| 	Cudd_RecursiveDeref(bdd,p); | |
| 	Cudd_Ref(LU = Cudd_bddAnd(bdd, Uin, Cudd_Not(r))); | |
| 	Cudd_RecursiveDeref(bdd,r); | |
| 	if(pr>3){(void)fprintf(stdout,"LU");Cudd_PrintDebug(bdd,LU,n<<1,pr);} | |
| 	/*Ml(y)=\exists_{x}LU(x,y)*/ | |
| 	Cudd_Ref(Ml = Cudd_bddExistAbstract(bdd, LU, xcube)); | |
| 	if(pr>3){(void)fprintf(stdout,"Ml");Cudd_PrintDebug(bdd,Ml,n,pr);} | |
| 	/*P(x,y)=Ml(x)\cdot Uout(x,y)*/ | |
| 	Cudd_Ref(p = Cudd_bddSwapVariables(bdd, Ml, x, y, n)); | |
| 	Cudd_Ref(P = Cudd_bddAnd(bdd, p, Uout)); | |
| 	Cudd_RecursiveDeref(bdd,p); | |
| 	Cudd_RecursiveDeref(bdd,Ml); | |
| 	if(pr>3){(void)fprintf(stdout,"P");Cudd_PrintDebug(bdd,P,n<<1,pr);} | |
| 	/*RU(x,y)= P(x,y)\cdot \overline{\exists_{z}(P(x,z)\cdot \Pi(y,z))}*/ | |
| 	Cudd_Ref(p = Cudd_bddSwapVariables(bdd, P, y, z, n)); | |
| 	Cudd_Ref(r = Cudd_bddAndAbstract(bdd, p, pryz, zcube)); | |
| 	Cudd_RecursiveDeref(bdd,p); | |
| 	Cudd_Ref(RU = Cudd_bddAnd(bdd, P, Cudd_Not(r))); | |
| 	Cudd_RecursiveDeref(bdd,r); | |
| 	Cudd_RecursiveDeref(bdd,P); | |
| 	if(pr>3){(void)fprintf(stdout,"RU");Cudd_PrintDebug(bdd,RU,n<<1,pr);} | |
| 	/*Mr(x)=\exists_{y}RU(x,y)*/ | |
| 	Cudd_Ref(Mr = Cudd_bddExistAbstract(bdd, RU, ycube)); | |
| 	if(pr>3){(void)fprintf(stdout,"Mr");Cudd_PrintDebug(bdd,Mr,n,pr);} | |
| 	/*LU(x,y)=LU(x,y)\cdot Mr(y)*/ | |
| 	Cudd_Ref(p = Cudd_bddSwapVariables(bdd, Mr, x, y, n)); | |
| 	Cudd_RecursiveDeref(bdd,Mr); | |
| 	Cudd_Ref(q = Cudd_bddAnd(bdd, LU, p)); | |
| 	Cudd_RecursiveDeref(bdd,p); | |
| 	Cudd_RecursiveDeref(bdd,LU); | |
| 	LU = q; | |
| 	if(pr>3){(void)fprintf(stdout,"LU");Cudd_PrintDebug(bdd,LU,n<<1,pr);} | |
| 	/*Uin(x,y)=Uin(x,y)-LU(x,y)*/ | |
| 	Cudd_Ref(p = Cudd_bddAnd(bdd, Uin, Cudd_Not(LU))); | |
| 	Cudd_RecursiveDeref(bdd,Uin); | |
| 	Uin = p; | |
| 	if(pr>3){(void)fprintf(stdout,"Uin");Cudd_PrintDebug(bdd,Uin,n<<1,pr);} | |
| 	/*Uout(x,y)=Uout(x,y)-RU(x,y)*/ | |
| 	Cudd_Ref(p = Cudd_bddAnd(bdd, Uout, Cudd_Not(RU))); | |
| 	Cudd_RecursiveDeref(bdd,Uout); | |
| 	Cudd_RecursiveDeref(bdd,RU); | |
| 	Uout = p; | |
| 	if(pr>3){(void)fprintf(stdout,"Uout");Cudd_PrintDebug(bdd,Uout,n<<1,pr);} | |
| 	/*\KW{if}(($LU(x,y)=zero$)~~\KW{or}~~($Uin(x,y)=zero$)~~\KW{or} | |
| 	  ($Uout(x,y)=zero$))~~KW{break}*/ | |
| 	if((LU == zero)||(Uin == zero)||(Uout == zero)) { | |
| 	    Cudd_RecursiveDeref(bdd,LU); | |
| 	    break; | |
| 	} | |
| 	Cudd_RecursiveDeref(bdd,LU); | |
| 
 | |
|     } /* Next least fixed point iteration with smaller Uin and Uout */ | |
|     if (k == MAXFPIT) (void) fprintf(stderr, | |
| 	"Rhombus: WARNING! MAXFPIT (%d) exceeded processing Layer %d.\n", | |
| 	MAXFPIT, m); | |
| 
 | |
|     if (Uin != zero) { | |
| 	/* $U^{m-1}(x,y) = U^{m-1}(x,y)-Uin(x,y)$*/ | |
| 	Cudd_Ref(p = Cudd_bddAnd(bdd, U[m-1], Cudd_Not(Uin))); | |
| 	Cudd_RecursiveDeref(bdd,U[m-1]); | |
| 	U[m-1] = p; | |
| 	/* $new^{m-1}(x,y) = \esists_yU^{m-1}(x,y)$*/ | |
| 	Cudd_RecursiveDeref(bdd,neW[m-1]); | |
| 	Cudd_Ref(neW[m-1] = Cudd_bddExistAbstract(bdd, U[m-1], ycube)); | |
|     } | |
|     if(pr>2){(void)fprintf(stdout,"U[%d]",m-1); Cudd_PrintDebug(bdd,U[m-1],n<<1,pr);} | |
|     if(pr>2){ | |
| 	(void)fprintf(stdout,"new[%d]",m-1); | |
| 	Cudd_PrintDebug(bdd,neW[m-1],n,pr); | |
|     } | |
|     Cudd_RecursiveDeref(bdd,Uin); | |
|     Cudd_RecursiveDeref(bdd,Uout); | |
| 
 | |
|     return; | |
| 
 | |
| } /* end of rhombus */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Selects edges from a hourglass-type bilayer. | |
|  | |
|   @details Used to pull flow.  Method described in paper. More | |
|   general, but more expensive than the others. | |
|  | |
|   @sideeffect None | |
|  | |
|   @see trellis rhombus hourglassPush | |
|  | |
| */ | |
| static void | |
| hourglass( | |
|   DdManager * bdd /**< %DD manager */, | |
|   int  m /**< center level of current bilayer */, | |
|   DdNode ** neW /**< array for flow propagation */, | |
|   DdNode ** U /**< array for flow propagation */, | |
|   DdNode ** x /**< array of variables for rows and columns */, | |
|   DdNode ** y /**< array of variables for rows and columns */, | |
|   DdNode ** z /**< array of variables for rows and columns */, | |
|   int  n /**< number of x variables */, | |
|   DdNode * pryz /**< priority function */, | |
|   DdNode * prxz /**< priority function */, | |
|   flowStats * stats /**< statistics */) | |
| { | |
|     DdNode *one, *zero, | |
| 	     *przy, | |
| 	     *p, *q, *r, | |
| 	     *Uin,		/* edges to be matched from U[m-1] */ | |
| 	     *Uout,		/* edges to be matched from U[m] */ | |
| 	     *P, *Q, | |
| 	     *PA, *D; | |
|     int      k, | |
| 	     pr;		/* print control */ | |
| 
 | |
|     pr = stats->pr; | |
| 
 | |
|     one = Cudd_ReadOne(bdd); | |
|     zero = Cudd_Not(one); | |
| 
 | |
|     /* Build priority function. */ | |
|     Cudd_Ref(p = Cudd_bddSwapVariables(bdd, pryz, y, z, n)); | |
|     Cudd_Ref(przy = Cudd_bddAdjPermuteX(bdd,p,x,n)); | |
|     Cudd_RecursiveDeref(bdd,p); | |
|     if(pr>2){(void)fprintf(stdout,"przy");Cudd_PrintDebug(bdd,przy,n*3,pr);} | |
| 
 | |
|     /*Uout(x,y)=U^m(x,y)*/ | |
|     Cudd_Ref(Uout = U[m]); | |
|     if(pr>1){(void)fprintf(stdout,"Uout");Cudd_PrintDebug(bdd,Uout,n<<1,pr);} | |
| 
 | |
|     /*Uin(x,y)=U^{m-1}(x,y)*/ | |
|     Cudd_Ref(Uin = U[m-1]); | |
|     if(pr>1){(void)fprintf(stdout,"Uin");Cudd_PrintDebug(bdd,Uin,n<<1,pr);} | |
| 
 | |
|     for(k = 0; k < MAXFPIT; k++) { | |
| 	stats->fpit++; | |
| 	/*P(x,y,z)=Uin(x,y)\cdot Uout(y,z)*/ | |
| 	Cudd_Ref(p = Cudd_bddSwapVariables(bdd, Uout, y, z, n)); | |
| 	if(pr>2){(void)fprintf(stdout,"p");Cudd_PrintDebug(bdd,p,n<<1,pr);} | |
| 	Cudd_Ref(q = Cudd_bddSwapVariables(bdd, p, x, y, n)); | |
| 	Cudd_RecursiveDeref(bdd,p); | |
| 	if(pr>2){(void)fprintf(stdout,"q");Cudd_PrintDebug(bdd,q,n<<1,pr);} | |
| 	Cudd_Ref(P = Cudd_bddAnd(bdd, Uin, q)); | |
| 	Cudd_RecursiveDeref(bdd,q); | |
| 	if(pr>1){(void)fprintf(stdout,"P");Cudd_PrintDebug(bdd,P,n*3,pr);} | |
| 	/*PA(x,z)=\exists_yP(x,y,z)*/ | |
| 	Cudd_Ref(PA = Cudd_bddExistAbstract(bdd, P, ycube)); | |
| 	if(pr>2){(void)fprintf(stdout,"PA");Cudd_PrintDebug(bdd,PA,n<<1,pr);} | |
| 	if(pr>3) { | |
| 	    Cudd_Ref(p = Cudd_bddExistAbstract(bdd, PA, xcube)); | |
| 	    (void) fprintf(stdout,"p");Cudd_PrintDebug(bdd,p,n,pr); | |
| 	    Cudd_RecursiveDeref(bdd,p); | |
| 	    Cudd_Ref(p = Cudd_bddExistAbstract(bdd, PA, zcube)); | |
| 	    (void) fprintf(stdout,"p");Cudd_PrintDebug(bdd,p,n,pr); | |
| 	    Cudd_RecursiveDeref(bdd,p); | |
| 	} | |
| 	/*Q(x,z)= PA(x,z)\cdot \overline{\exists_{y}(PA(x,y)\cdot \Pi(z,y))}*/ | |
| 	Cudd_Ref(p = Cudd_bddSwapVariables(bdd, PA, y, z, n)); | |
| 	Cudd_Ref(r = Cudd_bddAndAbstract(bdd, p, przy, ycube)); | |
| 	Cudd_RecursiveDeref(bdd,p); | |
| 	Cudd_Ref(Q = Cudd_bddAnd(bdd, PA, Cudd_Not(r))); | |
| 	Cudd_RecursiveDeref(bdd,r); | |
| 	Cudd_RecursiveDeref(bdd,PA); | |
| 	if(pr>2){(void)fprintf(stdout,"Q");Cudd_PrintDebug(bdd,Q,n<<1,pr);} | |
| 	if(pr>3) { | |
| 	    Cudd_Ref(p = Cudd_bddExistAbstract(bdd, Q, xcube)); | |
| 	    (void) fprintf(stdout,"p");Cudd_PrintDebug(bdd,p,n,pr); | |
| 	    Cudd_RecursiveDeref(bdd,p); | |
| 	} | |
| 	/*D(x,z)= Q(x,z)\cdot \overline{\exists_{y}(Q(y,z)\cdot \Pi(x,y))}*/ | |
| 	Cudd_Ref(p = Cudd_bddSwapVariables(bdd, Q, x, y, n)); | |
| 	Cudd_Ref(q = Cudd_bddSwapVariables(bdd, prxz, y, z, n)); | |
| 	Cudd_Ref(r = Cudd_bddAndAbstract(bdd, p, q, ycube)); | |
| 	Cudd_RecursiveDeref(bdd,p); | |
| 	Cudd_RecursiveDeref(bdd,q); | |
| 	Cudd_Ref(D = Cudd_bddAnd(bdd, Q, Cudd_Not(r))); | |
| 	Cudd_RecursiveDeref(bdd,r); | |
| 	Cudd_RecursiveDeref(bdd,Q); | |
| 	if(pr>1){(void)fprintf(stdout,"D");Cudd_PrintDebug(bdd,D,n<<1,pr);} | |
| 	/*P(x,y,z)=P(x,y,z)\cdot D(x,z)*/ | |
| 	Cudd_Ref(p = Cudd_bddAnd(bdd, P, D)); | |
| 	Cudd_RecursiveDeref(bdd,D); | |
| 	Cudd_RecursiveDeref(bdd,P); | |
| 	P = p; | |
| 	if(pr>2){(void)fprintf(stdout,"P");Cudd_PrintDebug(bdd,P,n*3,pr);} | |
| 	/*Uin(x,y)=Uin(x,y)-\exists_zP(x,y,z)*/ | |
| 	Cudd_Ref(p = Cudd_bddExistAbstract(bdd, P, zcube)); | |
| 	if(pr>3){(void)fprintf(stdout,"p");Cudd_PrintDebug(bdd,p,n<<1,pr);} | |
| 	Cudd_Ref(q = Cudd_bddAnd(bdd, Uin, Cudd_Not(p))); | |
| 	Cudd_RecursiveDeref(bdd,p); | |
| 	Cudd_RecursiveDeref(bdd,Uin); | |
| 	Uin = q; | |
| 	if(pr>1){(void)fprintf(stdout,"Uin");Cudd_PrintDebug(bdd,Uin,n<<1,pr);} | |
| 	/*Uout(x,y)=Uout(x,y)-\exists_zP(z,x,y)*/ | |
| 	Cudd_Ref(p = Cudd_bddSwapVariables(bdd, P, x, y, n)); | |
| 	if(pr>3){(void)fprintf(stdout,"p");Cudd_PrintDebug(bdd,p,n*3,pr);} | |
| 	Cudd_Ref(r = Cudd_bddSwapVariables(bdd, p, y, z, n)); | |
| 	Cudd_RecursiveDeref(bdd,p); | |
| 	if(pr>3){(void)fprintf(stdout,"r");Cudd_PrintDebug(bdd,r,n*3,pr);} | |
| 	Cudd_Ref(p = Cudd_bddExistAbstract(bdd, r, zcube)); | |
| 	Cudd_RecursiveDeref(bdd,r); | |
| 	if(pr>3){(void)fprintf(stdout,"p");Cudd_PrintDebug(bdd,p,n<<1,pr);} | |
| 	Cudd_Ref(q = Cudd_bddAnd(bdd, Uout, Cudd_Not(p))); | |
| 	Cudd_RecursiveDeref(bdd,p); | |
| 	Cudd_RecursiveDeref(bdd,Uout); | |
| 	Uout = q; | |
| 	if(pr>1){(void)fprintf(stdout,"Uout");Cudd_PrintDebug(bdd,Uout,n<<1,pr);} | |
| 	/*\KW{if}(($P(x,y,z)=zero$)~~\KW{or}~~($Uin(x,y)=zero$)~~\KW{or} | |
| 	  ($Uout(x,y)=zero$))~~KW{break}*/ | |
| 	if((P == zero)||(Uin == zero)||(Uout == zero)) { | |
| 	    Cudd_RecursiveDeref(bdd,P); | |
| 	    break; | |
| 	} | |
| 	Cudd_RecursiveDeref(bdd,P); | |
| 
 | |
|     } /* Next least fixed point iteration with smaller P */ | |
|     if (k == MAXFPIT) (void) fprintf(stderr, | |
| 	"Hourglass: WARNING! MAXFPIT (%d) exceeded processing Layer %d.\n", | |
| 	MAXFPIT, m); | |
| 
 | |
|     if (Uin != zero) { | |
| 	/* $U^{m-1}(x,y) = U^{m-1}(x,y)-Uin(x,y)$*/ | |
| 	Cudd_Ref(p = Cudd_bddAnd(bdd, U[m-1], Cudd_Not(Uin))); | |
| 	Cudd_RecursiveDeref(bdd,U[m-1]); | |
| 	U[m-1] = p; | |
| 	/* $new^{m-1}(x,y) = \esists_yU^{m-1}(x,y)$*/ | |
| 	Cudd_RecursiveDeref(bdd,neW[m-1]); | |
| 	Cudd_Ref(neW[m-1] = Cudd_bddExistAbstract(bdd, U[m-1], ycube)); | |
|     } | |
|     if(pr>1){(void)fprintf(stdout,"U[%d]",m-1); Cudd_PrintDebug(bdd,U[m-1],n<<1,pr);} | |
|     if(pr>1){(void)fprintf(stdout,"new[%d]",m-1); | |
| 	     Cudd_PrintDebug(bdd,neW[m-1],n,pr);} | |
| 
 | |
|     Cudd_RecursiveDeref(bdd,Uin); | |
|     Cudd_RecursiveDeref(bdd,Uout); | |
|     Cudd_RecursiveDeref(bdd,przy); | |
| 
 | |
|     return; | |
| 
 | |
| } /* end of hourglass */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Pushes flow through useful edges. | |
|  | |
|   @details Pushes flow from the source(s) to the sink(s) through | |
|   useful edges. | |
|  | |
|   @sideeffect None | |
|  | |
| */ | |
| static void | |
| maximal_push( | |
|   DdManager * bdd /**< %DD manager */, | |
|   int  l /**< Depth of layered network for current phase */, | |
|   DdNode ** U /**< array of edge sets for flow propagation */, | |
|   DdNode ** F /**< edge and flow relations */, | |
|   DdNode ** x /**< array of variables for rows and columns */, | |
|   DdNode ** y /**< array of variables for rows and columns */, | |
|   DdNode ** z /**< array of variables for rows and columns */, | |
|   int  n /**< number of x variables */, | |
|   DdNode * pryz /**< priority function */, | |
|   DdNode * prxz /**< priority function */, | |
|   flowStats * stats /**< statistics */) | |
| { | |
|     DdNode *p, *q, *r, | |
| 	   *UT, | |
| 	   *lN, *cN, *rN; /* left, center, right nodes of bilayer */ | |
|     double mtl, mtc, mtr; | |
|     int    m, | |
| 	   pr;	  /* print control */ | |
| 
 | |
|     pr = stats->pr; | |
| 
 | |
|     if (l == 0) { | |
| 	/* F(x,y) = F(x,y) + U^{0}(x,y) */ | |
| 	Cudd_Ref(q = Cudd_bddOr(bdd, *F, U[0])); | |
| 	Cudd_RecursiveDeref(bdd,*F); | |
| 	*F = q; | |
| 	if(pr>3){(void) fprintf(stdout,"F");Cudd_PrintDebug(bdd,*F,n<<1,pr);} | |
| 	return; | |
|     } | |
| 
 | |
|     for (m = 1; m < l; m++) { | |
| 	/* lN(x) = \exists_y U^{m-1}(x,y) */ | |
| 	Cudd_Ref(lN = Cudd_bddExistAbstract(bdd, U[m-1], ycube)); | |
| 	mtl = Cudd_CountMinterm(bdd, lN, n); | |
| 	Cudd_RecursiveDeref(bdd,lN); | |
| 
 | |
| 	/* cN(y) = \exists_x U^{m-1}(x,y) */ | |
| 	Cudd_Ref(cN = Cudd_bddExistAbstract(bdd, U[m-1], xcube)); | |
| 	mtc = Cudd_CountMinterm(bdd, cN, n); | |
| 	Cudd_RecursiveDeref(bdd,cN); | |
| 
 | |
| 	/* rN(y) = \exists_x U^{m}(x,y) */ | |
| 	Cudd_Ref(rN = Cudd_bddExistAbstract(bdd, U[m], xcube)); | |
| 	mtr = Cudd_CountMinterm(bdd, rN, n); | |
| 	Cudd_RecursiveDeref(bdd,rN); | |
| 
 | |
| 	if (pr > 0) { | |
| 	    (void) fprintf(stdout, "layer = %d mtl = %g  mtc = %g  mtr = %g", | |
| 			   m, mtl, mtc, mtr); | |
| 	} | |
| 	if ((mtc > MANY_TIMES * mtl) && !(mtr > MANY_TIMES * mtl)) { | |
| 	    if (pr>0) (void) fprintf(stdout, " R\n"); | |
| 	    rhombusPush(bdd, m, U, x, y, z, n, pryz, prxz, stats); | |
| 	} else if (mtl > MANY_TIMES * mtc) { | |
| 	    if (pr>0) (void) fprintf(stdout, " H\n"); | |
| 	    hourglassPush(bdd, m, U, x, y, z, n, pryz, prxz, stats); | |
| 	} else { | |
| 	    if (pr>0) (void) fprintf(stdout, " T\n"); | |
| 	    trellisPush(bdd, m, U, x, y, z, n, pryz, prxz, stats); | |
| 	} | |
| 
 | |
| 	/* F(x,y) = F(x,y) + U^{m-1}(x,y) \cdot \overline{F(y,x)} */ | |
| 	Cudd_Ref(p = Cudd_bddSwapVariables(bdd, *F, x, y, n)); | |
| 	Cudd_Ref(q = Cudd_bddAnd(bdd, Cudd_Not(p), U[m-1])); | |
| 	Cudd_RecursiveDeref(bdd,p); | |
| 	Cudd_Ref(r = Cudd_bddOr(bdd, *F, q)); | |
| 	Cudd_RecursiveDeref(bdd,q); | |
| 	Cudd_RecursiveDeref(bdd,*F); | |
| 	*F = r; | |
| 	if(pr>3){(void) fprintf(stdout,"F");Cudd_PrintDebug(bdd,*F,n<<1,pr);} | |
| 
 | |
| 	/* F(x,y) = F(x,y) - U^{m-1}(y,x) */ | |
| 	Cudd_Ref(r = Cudd_bddSwapVariables(bdd, U[m-1], x, y, n)); | |
| 	Cudd_Ref(q = Cudd_bddAnd(bdd, *F, Cudd_Not(r))); | |
| 	Cudd_RecursiveDeref(bdd,r); | |
| 	Cudd_RecursiveDeref(bdd,*F); | |
| 	*F = q; | |
| 	if(pr>3){(void) fprintf(stdout,"F");Cudd_PrintDebug(bdd,*F,n<<1,pr);} | |
| 
 | |
|     } /* Push maximal flow to next layer */ | |
| 
 | |
|     /*F(x,y)=F(x,y)+U^{l-1}(x,y)\cdot\overline{F(y,x)}*/ | |
|     Cudd_Ref(p = Cudd_bddSwapVariables(bdd, *F, x, y, n)); | |
|     Cudd_Ref(q = Cudd_bddAnd(bdd, Cudd_Not(p), U[l-1])); | |
|     Cudd_RecursiveDeref(bdd,p); | |
|     Cudd_Ref(r = Cudd_bddOr(bdd, *F, q)); | |
|     Cudd_RecursiveDeref(bdd,q); | |
|     Cudd_RecursiveDeref(bdd,*F); | |
|     *F = r; | |
|     if(pr>3){(void) fprintf(stdout,"F");Cudd_PrintDebug(bdd,*F,n<<1,pr);} | |
| 
 | |
|     /*F(y,x)=F(y,x)-U^{l-1}(x,y)*/ | |
|     Cudd_Ref(r = Cudd_bddSwapVariables(bdd, U[l-1], x, y, n)); | |
|     Cudd_Ref(q = Cudd_bddAnd(bdd, *F, Cudd_Not(r))); | |
|     Cudd_RecursiveDeref(bdd,r); | |
|     Cudd_RecursiveDeref(bdd,*F); | |
|     *F = q; | |
|     if(pr>1){(void) fprintf(stdout,"F");Cudd_PrintDebug(bdd,*F,n<<1,pr);} | |
| 
 | |
|     /*UT(x,y)=\exists_y(U^{l-1}(y,x))\cdot U^{l}(x,y)*/ | |
|     Cudd_Ref(p = Cudd_bddExistAbstract(bdd, U[l-1], xcube)); | |
|     if(pr>4){(void) fprintf(stdout,"p");Cudd_PrintDebug(bdd,p,n,pr);} | |
|     Cudd_Ref(q = Cudd_bddSwapVariables(bdd, p, x, y, n)); | |
|     Cudd_RecursiveDeref(bdd,p); | |
|     if(pr>4){(void) fprintf(stdout,"q");Cudd_PrintDebug(bdd,q,n,pr);} | |
|     Cudd_Ref(UT = Cudd_bddAnd(bdd, U[l], q)); | |
|     Cudd_RecursiveDeref(bdd,q); | |
|     if(pr>2){(void) fprintf(stdout,"UT");Cudd_PrintDebug(bdd,UT,n<<1,pr);} | |
| 
 | |
|     /*F(x,y)=F(x,y)+UT(x,y)\cdot\overline{F(y,x)}*/ | |
|     Cudd_Ref(p = Cudd_bddSwapVariables(bdd, *F, x, y, n)); | |
|     Cudd_Ref(q = Cudd_bddAnd(bdd, Cudd_Not(p), UT)); | |
|     Cudd_RecursiveDeref(bdd,p); | |
|     Cudd_Ref(r = Cudd_bddOr(bdd, *F, q)); | |
|     Cudd_RecursiveDeref(bdd,q); | |
|     Cudd_RecursiveDeref(bdd,*F); | |
|     *F = r; | |
|     if(pr>3){(void) fprintf(stdout,"F");Cudd_PrintDebug(bdd,*F,n<<1,pr);} | |
| 
 | |
|     /*F(y,x)=F(y,x)-UT(x,y)*/ | |
|     Cudd_Ref(r = Cudd_bddSwapVariables(bdd, UT, x, y, n)); | |
|     Cudd_RecursiveDeref(bdd,UT); | |
|     Cudd_Ref(q = Cudd_bddAnd(bdd, *F, Cudd_Not(r))); | |
|     Cudd_RecursiveDeref(bdd,r); | |
|     Cudd_RecursiveDeref(bdd,*F); | |
|     *F = q; | |
|     if(pr>1){(void) fprintf(stdout,"F");Cudd_PrintDebug(bdd,*F,n<<1,pr);} | |
| 
 | |
|     return; | |
| 
 | |
| } /* end of maximal_push */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Pushes flow through a trellis. | |
|  | |
|   @sideeffect None | |
|  | |
| */ | |
| static void | |
| trellisPush( | |
|   DdManager * bdd /**< %DD manager */, | |
|   int  m /**< Current layer */, | |
|   DdNode ** U /**< Array of edge sets for flow propagation */, | |
|   DdNode ** x /**< Array of variables for rows and columns */, | |
|   DdNode ** y /**< Array of variables for rows and columns */, | |
|   DdNode ** z /**< Array of variables for rows and columns */, | |
|   int  n /**< Number of x variables */, | |
|   DdNode * pryz /**< Priority function */, | |
|   DdNode * prxz /**< Priority function */, | |
|   flowStats * stats /**< statistics */) | |
| { | |
|     DdNode *one, *zero, | |
| 	     *p, *r, | |
| 	     *Uin,              /* Edges to be matched from U[m-1] */ | |
| 	     *Uout,             /* Edges to be matched from U[m] */ | |
| 	     *RU, *LU, | |
| 	     *P, | |
| 	     *Ml; | |
| 
 | |
|     int      i, | |
| 	     pr;	  /* Print control */ | |
| 
 | |
|     pr = stats->pr; | |
| 
 | |
|     one = Cudd_ReadOne(bdd); | |
|     zero = Cudd_Not(one); | |
| 
 | |
|     /*Uout(x,y)=U^m(x,y)*/ | |
|     Cudd_Ref(Uout = U[m]); | |
|     if(pr>3){(void)fprintf(stdout,"Uout");Cudd_PrintDebug(bdd,Uout,n<<1,pr);} | |
| 
 | |
|     /*Uin(x,y)=U^{m-1}(x,y)*/ | |
|     Cudd_Ref(Uin = U[m-1]); | |
|     if(pr>3){(void)fprintf(stdout,"Uin");Cudd_PrintDebug(bdd,Uin,n<<1,pr);} | |
| 
 | |
|     for(i=0; i<MAXFPIT; i++) { | |
| 	stats->fpit++; | |
| 	/*LU(x,y)=Uin(x,y)\cdot\overline{\exists_{z}(Uin(z,y)\cdot\Pi(x,z))}*/ | |
| 	Cudd_Ref(p = Cudd_bddSwapVariables(bdd, Uin, x, z, n)); | |
| 	Cudd_Ref(r = Cudd_bddAndAbstract(bdd, p, prxz, zcube)); | |
| 	Cudd_RecursiveDeref(bdd,p); | |
| 	Cudd_Ref(LU = Cudd_bddAnd(bdd, Uin, Cudd_Not(r))); | |
| 	Cudd_RecursiveDeref(bdd,r); | |
| 	if(pr>3){(void)fprintf(stdout,"LU");Cudd_PrintDebug(bdd,LU,n<<1,pr);} | |
| 
 | |
| 	/*Ml(y)=\exists_{x}LU(x,y)*/ | |
| 	Cudd_Ref(Ml = Cudd_bddExistAbstract(bdd, LU, xcube)); | |
| 	if(pr>3){(void)fprintf(stdout,"Ml");Cudd_PrintDebug(bdd,Ml,n,pr);} | |
| 
 | |
| 	/*P(x,y)=Ml(x)\cdot Uout(x,y)*/ | |
| 	Cudd_Ref(p = Cudd_bddSwapVariables(bdd, Ml, x, y, n)); | |
| 	Cudd_Ref(P = Cudd_bddAnd(bdd, p, Uout)); | |
| 	Cudd_RecursiveDeref(bdd,p); | |
| 	Cudd_RecursiveDeref(bdd,Ml); | |
| 	if(pr>3){(void)fprintf(stdout,"P");Cudd_PrintDebug(bdd,P,n<<1,pr);} | |
| 
 | |
| 	/*RU(x,y)= P(x,y)\cdot \overline{\exists_{z}(P(x,z)\cdot \Pi(y,z))}*/ | |
| 	Cudd_Ref(p = Cudd_bddSwapVariables(bdd, P, y, z, n)); | |
| 	Cudd_Ref(r = Cudd_bddAndAbstract(bdd, p, pryz, zcube)); | |
| 	Cudd_RecursiveDeref(bdd,p); | |
| 	Cudd_Ref(RU = Cudd_bddAnd(bdd, P, Cudd_Not(r))); | |
| 	Cudd_RecursiveDeref(bdd,r); | |
| 	Cudd_RecursiveDeref(bdd,P); | |
| 	if(pr>3){(void)fprintf(stdout,"RU");Cudd_PrintDebug(bdd,RU,n<<1,pr);} | |
| 
 | |
| 	/*Uin(x,y)=Uin(x,y)-LU(x,y)*/ | |
| 	Cudd_Ref(p = Cudd_bddAnd(bdd, Uin, Cudd_Not(LU))); | |
| 	Cudd_RecursiveDeref(bdd,Uin); | |
| 	Uin = p; | |
| 	if(pr>3){(void)fprintf(stdout,"Uin");Cudd_PrintDebug(bdd,Uin,n<<1,pr);} | |
| 
 | |
| 	/*Uout(x,y)=Uout(x,y)-RU(x,y)*/ | |
| 	Cudd_Ref(p = Cudd_bddAnd(bdd, Uout, Cudd_Not(RU))); | |
| 	Cudd_RecursiveDeref(bdd,Uout); | |
| 	Cudd_RecursiveDeref(bdd,RU); | |
| 	Uout = p; | |
| 	if(pr>3){(void)fprintf(stdout,"Uout");Cudd_PrintDebug(bdd,Uout,n<<1,pr);} | |
| 
 | |
| 	/*\KW{if}(($LU(x,y)=zero$)~~\KW{or}~~($Uin(x,y)=zero$))~~KW{break}*/ | |
| 	if((LU == zero)||(Uin == zero)) { | |
| 	    Cudd_RecursiveDeref(bdd,LU); | |
| 	    break; | |
| 	} | |
| 
 | |
| 	Cudd_RecursiveDeref(bdd,LU); | |
| 
 | |
|     } /* Next least fixed point iteration with smaller Uin and Uout */ | |
|     if (i == MAXFPIT) (void) fprintf(stderr, | |
| 	"TrellisPush: ERROR! MAXFPIT (%d) exceeded at layer %d.\n", | |
| 	MAXFPIT, m); | |
| 
 | |
|     /* $U^{m}(x,y) = U^{m}(x,y)-Uout(x,y)$*/ | |
|     if (Uout != zero) { | |
| 	Cudd_Ref(p = Cudd_bddAnd(bdd, U[m], Cudd_Not(Uout))); | |
| 	Cudd_RecursiveDeref(bdd,U[m]); | |
| 	U[m] = p; | |
| 	if(pr>3){(void)fprintf(stdout,"U[%d]",m); | |
| 	    Cudd_PrintDebug(bdd,U[m],n<<1,pr);} | |
|     } | |
| 
 | |
|     Cudd_RecursiveDeref(bdd,Uin); | |
|     Cudd_RecursiveDeref(bdd,Uout); | |
| 
 | |
| } /* end of trellisPush */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Pushes flow through a rhombus. | |
|  | |
|   @sideeffect None | |
|  | |
| */ | |
| static void | |
| rhombusPush( | |
|   DdManager * bdd /**< %DD manager */, | |
|   int  m /**< Current layer */, | |
|   DdNode ** U /**< Array of edge sets for flow propagation */, | |
|   DdNode ** x /**< Array of variables for rows and columns */, | |
|   DdNode ** y /**< Array of variables for rows and columns */, | |
|   DdNode ** z /**< Array of variables for rows and columns */, | |
|   int  n /**< Number of x variables */, | |
|   DdNode * pryz /**< Priority function */, | |
|   DdNode * prxz /**< Priority function */, | |
|   flowStats * stats /**< statistics */) | |
| { | |
|     DdNode *one, *zero, | |
| 	     *p, *r, | |
| 	     *Uin,              /* Edges to be matched from U[m-1] */ | |
| 	     *Uout,             /* Edges to be matched from U[m] */ | |
| 	     *RU, *LU, | |
| 	     *P, | |
| 	     *Ml; | |
| 
 | |
|     int      i, | |
| 	     pr;	  /* Print control */ | |
| 
 | |
|     pr = stats->pr; | |
| 
 | |
|     one = Cudd_ReadOne(bdd); | |
|     zero = Cudd_Not(one); | |
| 
 | |
|     /*Uout(x,y)=U^m(x,y)*/ | |
|     Cudd_Ref(Uout = U[m]); | |
|     if(pr>3){(void)fprintf(stdout,"Uout");Cudd_PrintDebug(bdd,Uout,n<<1,pr);} | |
| 
 | |
|     /*Uin(x,y)=U^{m-1}(x,y)*/ | |
|     Cudd_Ref(Uin = U[m-1]); | |
|     if(pr>3){(void)fprintf(stdout,"Uin");Cudd_PrintDebug(bdd,Uin,n<<1,pr);} | |
| 
 | |
|     for(i = 0; i < MAXFPIT; i++) { | |
| 	stats->fpit++; | |
| 	/*RU(x,y)=Uin(x,y)\cdot\overline{\exists_{z}(Uin(x,z)\cdot\Pi(y,z))}*/ | |
| 	Cudd_Ref(p = Cudd_bddSwapVariables(bdd, Uin, y, z, n)); | |
| 	Cudd_Ref(r = Cudd_bddAndAbstract(bdd, p, pryz, zcube)); | |
| 	Cudd_RecursiveDeref(bdd,p); | |
| 	Cudd_Ref(RU = Cudd_bddAnd(bdd, Uin, Cudd_Not(r))); | |
| 	Cudd_RecursiveDeref(bdd,r); | |
| 	if(pr>3){(void)fprintf(stdout,"RU");Cudd_PrintDebug(bdd,RU,n<<1,pr);} | |
| 
 | |
| 	/*Ml(y)=\exists_{x}RU(x,y)*/ | |
| 	Cudd_Ref(Ml = Cudd_bddExistAbstract(bdd, RU, xcube)); | |
| 	if(pr>3){(void)fprintf(stdout,"Ml");Cudd_PrintDebug(bdd,Ml,n,pr);} | |
| 
 | |
| 	/*P(x,y)=Ml(x)\cdot Uout(x,y)*/ | |
| 	Cudd_Ref(p = Cudd_bddSwapVariables(bdd, Ml, x, y, n)); | |
| 	Cudd_Ref(P = Cudd_bddAnd(bdd, p, Uout)); | |
| 	Cudd_RecursiveDeref(bdd,p); | |
| 	Cudd_RecursiveDeref(bdd,Ml); | |
| 	if(pr>3){(void)fprintf(stdout,"P");Cudd_PrintDebug(bdd,P,n<<1,pr);} | |
| 
 | |
| 	/*LU(x,y)= P(x,y)\cdot \overline{\exists_{z}(P(z,y)\cdot \Pi(x,z))}*/ | |
| 	Cudd_Ref(p = Cudd_bddSwapVariables(bdd, P, x, z, n)); | |
| 	Cudd_Ref(r = Cudd_bddAndAbstract(bdd, p, prxz, zcube)); | |
| 	Cudd_RecursiveDeref(bdd,p); | |
| 	Cudd_Ref(LU = Cudd_bddAnd(bdd, P, Cudd_Not(r))); | |
| 	Cudd_RecursiveDeref(bdd,r); | |
| 	Cudd_RecursiveDeref(bdd,P); | |
| 	if(pr>3){(void)fprintf(stdout,"LU");Cudd_PrintDebug(bdd,LU,n<<1,pr);} | |
| 
 | |
| 	/*Uin(x,y)=Uin(x,y)-RU(x,y)*/ | |
| 	Cudd_Ref(p = Cudd_bddAnd(bdd, Uin, Cudd_Not(RU))); | |
| 	Cudd_RecursiveDeref(bdd,Uin); | |
| 	Uin = p; | |
| 	if(pr>3){(void)fprintf(stdout,"Uin");Cudd_PrintDebug(bdd,Uin,n<<1,pr);} | |
| 
 | |
| 	/*Uout(x,y)=Uout(x,y)-LU(x,y)*/ | |
| 	Cudd_Ref(p = Cudd_bddAnd(bdd, Uout, Cudd_Not(LU))); | |
| 	Cudd_RecursiveDeref(bdd,Uout); | |
| 	Cudd_RecursiveDeref(bdd,LU); | |
| 	Uout = p; | |
| 	if(pr>3){(void)fprintf(stdout,"Uout");Cudd_PrintDebug(bdd,Uout,n<<1,pr);} | |
| 
 | |
| 	/*\KW{if}(($RU(x,y)=zero$)~~\KW{or}~~($Uin(x,y)=zero$))~~KW{break}*/ | |
| 	if((RU == zero)||(Uin == zero)) { | |
| 	    Cudd_RecursiveDeref(bdd,RU); | |
| 	    break; | |
| 	} | |
| 
 | |
| 	Cudd_RecursiveDeref(bdd,RU); | |
| 
 | |
|     } /* Next least fixed point iteration with smaller Uin and Uout */ | |
|     if (i == MAXFPIT) (void) fprintf(stderr, | |
| 	"RhombusPush: ERROR! MAXFPIT (%d) exceeded at layer %d.\n", | |
| 	MAXFPIT, m); | |
| 
 | |
|     /* $U^{m}(x,y) = U^{m}(x,y)-Uout(x,y)$*/ | |
|     if (Uout != zero) { | |
| 	Cudd_Ref(p = Cudd_bddAnd(bdd, U[m], Cudd_Not(Uout))); | |
| 	Cudd_RecursiveDeref(bdd,U[m]); | |
| 	U[m] = p; | |
| 	if(pr>3){(void)fprintf(stdout,"U[%d]",m); | |
| 	    Cudd_PrintDebug(bdd,U[m],n<<1,pr);} | |
|     } | |
| 
 | |
|     Cudd_RecursiveDeref(bdd,Uin); | |
|     Cudd_RecursiveDeref(bdd,Uout); | |
| 
 | |
|     return; | |
| 
 | |
| } /* end of rhombusPush */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Pushes flow through an hourglass. | |
|  | |
|   @sideeffect None | |
|  | |
| */ | |
| static void | |
| hourglassPush( | |
|   DdManager * bdd /**< %DD manager */, | |
|   int  m /**< Current layer */, | |
|   DdNode ** U /**< Array of edge sets for flow propagation */, | |
|   DdNode ** x /**< Array of variables for rows and columns */, | |
|   DdNode ** y /**< Array of variables for rows and columns */, | |
|   DdNode ** z /**< Array of variables for rows and columns */, | |
|   int  n /**< Number of x variables */, | |
|   DdNode * pryz /**< Priority function */, | |
|   DdNode * prxz /**< Priority function */, | |
|   flowStats * stats /**< statistics */) | |
| { | |
|     DdNode *one, *zero, | |
| 	     *przy, | |
| 	     *p, *q, *r, | |
| 	     *Uin,              /* Edges to be matched from U[m-1] */ | |
| 	     *Uout,             /* Edges to be matched from U[m] */ | |
| 	     *P, *Q, | |
| 	     *PA, *D; | |
| 
 | |
|     int      i, | |
| 	     pr;	  /* Print control */ | |
| 
 | |
|     pr = stats->pr; | |
| 
 | |
|     one = Cudd_ReadOne(bdd); | |
|     zero = Cudd_Not(one); | |
| 
 | |
|     /* Build priority function. */ | |
|     Cudd_Ref(p = Cudd_bddSwapVariables(bdd, pryz, y, z, n)); | |
|     Cudd_Ref(przy = Cudd_bddAdjPermuteX(bdd,p,x,n)); | |
|     Cudd_RecursiveDeref(bdd,p); | |
|     if(pr>2){(void)fprintf(stdout,"przy");Cudd_PrintDebug(bdd,przy,n*3,pr);} | |
| 
 | |
|     /*Uout(x,y)=U^m(x,y)*/ | |
|     Cudd_Ref(Uout = U[m]); | |
|     if(pr>3){(void)fprintf(stdout,"Uout");Cudd_PrintDebug(bdd,Uout,n<<1,pr);} | |
| 
 | |
|     /*Uin(x,y)=U^{m-1}(x,y)*/ | |
|     Cudd_Ref(Uin = U[m-1]); | |
|     if(pr>3){(void)fprintf(stdout,"Uin");Cudd_PrintDebug(bdd,Uin,n<<1,pr);} | |
| 
 | |
|     for(i = 0; i < MAXFPIT; i++) { | |
| 	stats->fpit++; | |
| 	/*P(x,y,z)=Uin(x,y)\cdot Uout(y,z)*/ | |
| 	Cudd_Ref(p = Cudd_bddSwapVariables(bdd, Uout, y, z, n)); | |
| 	if(pr>2){(void)fprintf(stdout,"p");Cudd_PrintDebug(bdd,p,n<<1,pr);} | |
| 	Cudd_Ref(q = Cudd_bddSwapVariables(bdd, p, x, y, n)); | |
| 	Cudd_RecursiveDeref(bdd,p); | |
| 	if(pr>2){(void)fprintf(stdout,"q");Cudd_PrintDebug(bdd,q,n<<1,pr);} | |
| 	Cudd_Ref(P = Cudd_bddAnd(bdd, Uin, q)); | |
| 	Cudd_RecursiveDeref(bdd,q); | |
| 	if(pr>1){(void)fprintf(stdout,"P");Cudd_PrintDebug(bdd,P,n*3,pr);} | |
| 
 | |
| 	/*PA(x,z)=\exists_yP(x,y,z)*/ | |
| 	Cudd_Ref(PA = Cudd_bddExistAbstract(bdd, P, ycube)); | |
| 	if(pr>2){(void)fprintf(stdout,"PA");Cudd_PrintDebug(bdd,PA,n<<1,pr);} | |
| 	if(pr>3) { | |
| 	    Cudd_Ref(p = Cudd_bddExistAbstract(bdd, PA, xcube)); | |
| 	    (void) fprintf(stdout,"p");Cudd_PrintDebug(bdd,p,n,pr); | |
| 	    Cudd_RecursiveDeref(bdd,p); | |
| 	    Cudd_Ref(p = Cudd_bddExistAbstract(bdd, PA, zcube)); | |
| 	    (void) fprintf(stdout,"p");Cudd_PrintDebug(bdd,p,n,pr); | |
| 	    Cudd_RecursiveDeref(bdd,p); | |
| 	} | |
| 
 | |
| 	/*Q(x,z)= PA(x,z)\cdot \overline{\exists_{y}(PA(x,y)\cdot \Pi(z,y))}*/ | |
| 	Cudd_Ref(p = Cudd_bddSwapVariables(bdd, PA, y, z, n)); | |
| 	Cudd_Ref(r = Cudd_bddAndAbstract(bdd, p, przy, ycube)); | |
| 	Cudd_RecursiveDeref(bdd,p); | |
| 	Cudd_Ref(Q = Cudd_bddAnd(bdd, PA, Cudd_Not(r))); | |
| 	Cudd_RecursiveDeref(bdd,r); | |
| 	Cudd_RecursiveDeref(bdd,PA); | |
| 	if(pr>2){(void)fprintf(stdout,"Q");Cudd_PrintDebug(bdd,Q,n<<1,pr);} | |
| 	if(pr>3) { | |
| 	    Cudd_Ref(p = Cudd_bddExistAbstract(bdd, Q, xcube)); | |
| 	    (void) fprintf(stdout,"p");Cudd_PrintDebug(bdd,p,n,pr); | |
| 	    Cudd_RecursiveDeref(bdd,p); | |
| 	} | |
| 
 | |
| 	/*D(x,z)= Q(x,z)\cdot \overline{\exists_{y}(Q(y,z)\cdot \Pi(x,y))}*/ | |
| 	Cudd_Ref(p = Cudd_bddSwapVariables(bdd, Q, x, y, n)); | |
| 	Cudd_Ref(q = Cudd_bddSwapVariables(bdd, prxz, y, z, n)); | |
| 	Cudd_Ref(r = Cudd_bddAndAbstract(bdd, p, q, ycube)); | |
| 	Cudd_RecursiveDeref(bdd,p); | |
| 	Cudd_RecursiveDeref(bdd,q); | |
| 	Cudd_Ref(D = Cudd_bddAnd(bdd, Q, Cudd_Not(r))); | |
| 	Cudd_RecursiveDeref(bdd,r); | |
| 	Cudd_RecursiveDeref(bdd,Q); | |
| 	if(pr>1){(void)fprintf(stdout,"D");Cudd_PrintDebug(bdd,D,n<<1,pr);} | |
| 
 | |
| 	/*P(x,y,z)=P(x,y,z)\cdot D(x,z)*/ | |
| 	Cudd_Ref(p = Cudd_bddAnd(bdd, P, D)); | |
| 	Cudd_RecursiveDeref(bdd,D); | |
| 	Cudd_RecursiveDeref(bdd,P); | |
| 	P = p; | |
| 	if(pr>2){(void)fprintf(stdout,"P");Cudd_PrintDebug(bdd,P,n*3,pr);} | |
| 
 | |
| 	/*Uin(x,y)=Uin(x,y)-\exists_zP(x,y,z)*/ | |
| 	Cudd_Ref(p = Cudd_bddExistAbstract(bdd, P, zcube)); | |
| 	if(pr>3){(void)fprintf(stdout,"p");Cudd_PrintDebug(bdd,p,n<<1,pr);} | |
| 	Cudd_Ref(q = Cudd_bddAnd(bdd, Uin, Cudd_Not(p))); | |
| 	Cudd_RecursiveDeref(bdd,p); | |
| 	Cudd_RecursiveDeref(bdd,Uin); | |
| 	Uin = q; | |
| 	if(pr>1){(void)fprintf(stdout,"Uin");Cudd_PrintDebug(bdd,Uin,n<<1,pr);} | |
| 
 | |
| 	/*Uout(x,y)=Uout(x,y)-\exists_zP(z,x,y)*/ | |
| 	Cudd_Ref(p = Cudd_bddSwapVariables(bdd, P, x, y, n)); | |
| 	if(pr>3){(void)fprintf(stdout,"p");Cudd_PrintDebug(bdd,p,n*3,pr);} | |
| 	Cudd_Ref(r = Cudd_bddSwapVariables(bdd, p, y, z, n)); | |
| 	Cudd_RecursiveDeref(bdd,p); | |
| 	if(pr>3){(void)fprintf(stdout,"r");Cudd_PrintDebug(bdd,r,n*3,pr);} | |
| 	Cudd_Ref(p = Cudd_bddExistAbstract(bdd, r, zcube)); | |
| 	Cudd_RecursiveDeref(bdd,r); | |
| 	if(pr>3){(void)fprintf(stdout,"p");Cudd_PrintDebug(bdd,p,n<<1,pr);} | |
| 	Cudd_Ref(q = Cudd_bddAnd(bdd, Uout, Cudd_Not(p))); | |
| 	Cudd_RecursiveDeref(bdd,p); | |
| 	Cudd_RecursiveDeref(bdd,Uout); | |
| 	Uout = q; | |
| 	if(pr>1){(void)fprintf(stdout,"Uout");Cudd_PrintDebug(bdd,Uout,n<<1,pr);} | |
| 
 | |
| 	/*\KW{if}(($P(x,y,z)=zero$)~~\KW{or}~~($Uin(x,y)=zero$)~~\KW{or} | |
| 	  ($Uout(x,y)=zero$))~~KW{break}*/ | |
| 	if((P == zero)||(Uin == zero)||(Uout == zero)) { | |
| 	    Cudd_RecursiveDeref(bdd,P); | |
| 	    break; | |
| 	} | |
| 
 | |
| 	Cudd_RecursiveDeref(bdd,P); | |
| 
 | |
|     } /* Next least fixed point iteration with smaller P */ | |
|     if (i == MAXFPIT) (void) fprintf(stderr, | |
| 	"HourglassPush: ERROR! MAXFPIT (%d) exceeded at layer %d.\n", | |
| 	MAXFPIT, m); | |
| 
 | |
|     /* $U^{m}(x,y) = U^{m}(x,y)-Uout(x,y)$*/ | |
|     if (Uout != zero) { | |
| 	Cudd_Ref(p = Cudd_bddAnd(bdd, U[m], Cudd_Not(Uout))); | |
| 	Cudd_RecursiveDeref(bdd,U[m]); | |
| 	U[m] = p; | |
|     } | |
|     if(pr>1){(void)fprintf(stdout,"U[%d]",m); Cudd_PrintDebug(bdd,U[m],n<<1,pr);} | |
| 
 | |
|     Cudd_RecursiveDeref(bdd,Uin); | |
|     Cudd_RecursiveDeref(bdd,Uout); | |
|     Cudd_RecursiveDeref(bdd,przy); | |
| 
 | |
|     return; | |
| 
 | |
| } /* end of hourglassPush */
 |