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.
		
		
		
		
		
			
		
			
				
					
					
						
							556 lines
						
					
					
						
							17 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							556 lines
						
					
					
						
							17 KiB
						
					
					
				
								/**
							 | 
						|
								  @file
							 | 
						|
								
							 | 
						|
								  @ingroup nanotrav
							 | 
						|
								
							 | 
						|
								  @brief Symbolic shortest paths algorithms.
							 | 
						|
								
							 | 
						|
								  @details This file contains the functions that implement the
							 | 
						|
								  symbolic version of several shortest path algorithms described in the
							 | 
						|
								  JFM paper on ADDs.
							 | 
						|
								
							 | 
						|
								  @author Fabio Somenzi, Iris Bahar
							 | 
						|
								
							 | 
						|
								  @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"
							 | 
						|
								#include "cuddInt.h"
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Constant declarations                                                     */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Stucture declarations                                                     */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Type declarations                                                         */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Variable declarations                                                     */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Macro declarations                                                        */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								/** \cond */
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Static function prototypes                                                */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								static DdNode * ntrBellman (DdManager *dd, DdNode *D, DdNode *source, DdNode **x, DdNode **y, int vars, int pr);
							 | 
						|
								static DdNode * ntrWarshall (DdManager *dd, DdNode *D, DdNode **x, DdNode **y, int vars, int pr);
							 | 
						|
								static DdNode * ntrSquare (DdManager *dd, DdNode *D, DdNode **x, DdNode **y, DdNode **z, int vars, int pr, int st);
							 | 
						|
								
							 | 
						|
								/** \endcond */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Definition of exported functions                                          */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								  @brief Computes shortest paths in a state graph.
							 | 
						|
								
							 | 
						|
								  @details Computes shortest paths in the state transition graph of
							 | 
						|
								  a network.  Three methods are availabe:
							 | 
						|
								  <ul>
							 | 
						|
								  <li> Bellman-Ford algorithm for single-source shortest paths; the
							 | 
						|
								  algorithm computes the distance (number of transitions) from the initial
							 | 
						|
								  states to all states.
							 | 
						|
								  <li> Floyd-Warshall algorithm for all-pair shortest paths.
							 | 
						|
								  <li> Repeated squaring algorithm for all-pair shortest paths.
							 | 
						|
								  </ul>
							 | 
						|
								
							 | 
						|
								  @return 1 in case of success; 0 otherwise.
							 | 
						|
								
							 | 
						|
								  @sideeffect %ADD variables are created in the manager.
							 | 
						|
								
							 | 
						|
								*/
							 | 
						|
								int
							 | 
						|
								Ntr_ShortestPaths(
							 | 
						|
								  DdManager * dd,
							 | 
						|
								  BnetNetwork * net,
							 | 
						|
								  NtrOptions * option)
							 | 
						|
								{
							 | 
						|
								    NtrPartTR *TR;
							 | 
						|
								    DdNode *edges, *source, *res, *r, *q, *bddSource;
							 | 
						|
								    DdNode **xadd, **yadd, **zadd;
							 | 
						|
								    int i;
							 | 
						|
								    int pr = option->verb;
							 | 
						|
								    int algorithm = option->shortPath;
							 | 
						|
								    int selectiveTrace = option->selectiveTrace;
							 | 
						|
								    int nvars = net->nlatches;
							 | 
						|
								
							 | 
						|
								    /* Set background to infinity for shortest paths. */
							 | 
						|
								    Cudd_SetBackground(dd,Cudd_ReadPlusInfinity(dd));
							 | 
						|
								
							 | 
						|
								    /* Build the monolithic TR. */
							 | 
						|
								    TR = Ntr_buildTR(dd,net,option,NTR_IMAGE_MONO);
							 | 
						|
								
							 | 
						|
								    /* Build the ADD variable vectors for x and y. */
							 | 
						|
								    xadd = ALLOC(DdNode *, nvars);
							 | 
						|
								    yadd = ALLOC(DdNode *, nvars);
							 | 
						|
								    for(i = 0; i < nvars; i++) {
							 | 
						|
									q = Cudd_addIthVar(dd,TR->x[i]->index);
							 | 
						|
									Cudd_Ref(q);
							 | 
						|
									xadd[i] = q;
							 | 
						|
									q = Cudd_addIthVar(dd,TR->y[i]->index);
							 | 
						|
									Cudd_Ref(q);
							 | 
						|
									yadd[i] = q;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /* Convert the transition relation BDD into an ADD... */
							 | 
						|
								    q = Cudd_BddToAdd(dd,TR->part[0]);
							 | 
						|
								    Cudd_Ref(q);
							 | 
						|
								    /* ...replacing zeroes with infinities... */
							 | 
						|
								    r = Cudd_addIte(dd,q,Cudd_ReadOne(dd),Cudd_ReadPlusInfinity(dd));
							 | 
						|
								    Cudd_Ref(r);
							 | 
						|
								    Cudd_RecursiveDeref(dd,q);
							 | 
						|
								    /* ...and zeroing the diagonal. */
							 | 
						|
								    q = Cudd_addXeqy(dd,nvars,xadd,yadd);
							 | 
						|
								    Cudd_Ref(q);
							 | 
						|
								    edges = Cudd_addIte(dd,q,Cudd_ReadZero(dd),r);
							 | 
						|
								    Cudd_Ref(edges);
							 | 
						|
								    Cudd_RecursiveDeref(dd,r);
							 | 
						|
								    Cudd_RecursiveDeref(dd,q);
							 | 
						|
								
							 | 
						|
								    switch(algorithm) {
							 | 
						|
								    case NTR_SHORT_BELLMAN:
							 | 
						|
									bddSource = Ntr_initState(dd,net,option);
							 | 
						|
									source = Cudd_BddToAdd(dd,bddSource);
							 | 
						|
									Cudd_Ref(source);
							 | 
						|
									res = ntrBellman(dd,edges,source,xadd,yadd,nvars,pr);
							 | 
						|
									if (res == NULL) return(0);
							 | 
						|
									Cudd_Ref(res);
							 | 
						|
									Cudd_RecursiveDeref(dd,source);
							 | 
						|
									Cudd_RecursiveDeref(dd,bddSource);
							 | 
						|
									if (pr >= 0) {
							 | 
						|
									    (void) fprintf(stdout,"Distance Matrix");
							 | 
						|
									    Cudd_PrintDebug(dd,res,nvars,pr);
							 | 
						|
									}
							 | 
						|
									break;
							 | 
						|
								    case NTR_SHORT_FLOYD:
							 | 
						|
									res = ntrWarshall(dd,edges,xadd,yadd,nvars,pr);
							 | 
						|
									if (res == NULL) return(0);
							 | 
						|
									Cudd_Ref(res);
							 | 
						|
									if (pr >= 0) {
							 | 
						|
									    (void) fprintf(stdout,"Distance Matrix");
							 | 
						|
									    Cudd_PrintDebug(dd,res,2*nvars,pr);
							 | 
						|
									}
							 | 
						|
									break;
							 | 
						|
								    case NTR_SHORT_SQUARE:
							 | 
						|
									/* Create a third set of ADD variables. */
							 | 
						|
									zadd = ALLOC(DdNode *, nvars);
							 | 
						|
									for(i = 0; i < nvars; i++) {
							 | 
						|
									    int level;
							 | 
						|
									    level = Cudd_ReadIndex(dd,TR->x[i]->index);
							 | 
						|
									    q = Cudd_addNewVarAtLevel(dd,level);
							 | 
						|
									    Cudd_Ref(q);
							 | 
						|
									    zadd[i] = q;
							 | 
						|
									}
							 | 
						|
									/* Compute the shortest paths. */
							 | 
						|
									res = ntrSquare(dd,edges,zadd,yadd,xadd,nvars,pr,selectiveTrace);
							 | 
						|
									if (res == NULL) return(0);
							 | 
						|
									Cudd_Ref(res);
							 | 
						|
									/* Dispose of the extra variables. */
							 | 
						|
									for(i = 0; i < nvars; i++) {
							 | 
						|
									    Cudd_RecursiveDeref(dd,zadd[i]);
							 | 
						|
									}
							 | 
						|
									FREE(zadd);
							 | 
						|
									if (pr >= 0) {
							 | 
						|
									    (void) fprintf(stdout,"Distance Matrix");
							 | 
						|
									    Cudd_PrintDebug(dd,res,2*nvars,pr);
							 | 
						|
									}
							 | 
						|
									break;
							 | 
						|
								    default:
							 | 
						|
									(void) printf("Unrecognized method. Try again.\n");
							 | 
						|
									return(0);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /* Here we should compute the paths. */
							 | 
						|
								
							 | 
						|
								    /* Clean up. */
							 | 
						|
								    Ntr_freeTR(dd,TR);
							 | 
						|
								    Cudd_RecursiveDeref(dd,edges);
							 | 
						|
								    Cudd_RecursiveDeref(dd,res);
							 | 
						|
								    for(i = 0; i < nvars; i++) {
							 | 
						|
									Cudd_RecursiveDeref(dd,xadd[i]);
							 | 
						|
									Cudd_RecursiveDeref(dd,yadd[i]);
							 | 
						|
								    }
							 | 
						|
								    FREE(xadd);
							 | 
						|
								    FREE(yadd);
							 | 
						|
								
							 | 
						|
								    if (option->autoDyn & 1) {
							 | 
						|
									(void) printf("Order after short path computation\n");
							 | 
						|
									if (!Bnet_PrintOrder(net,dd)) return(0);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    return(1);
							 | 
						|
								
							 | 
						|
								} /* end of Ntr_ShortestPaths */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Definition of internal functions                                          */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Definition of static functions                                            */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								  @brief Bellman-Ford algorithm for single-source shortest paths.
							 | 
						|
								
							 | 
						|
								  @return the vector of the distances of all states from the initial
							 | 
						|
								  states.
							 | 
						|
								
							 | 
						|
								  @details In case of multiple initial states the distance for
							 | 
						|
								  each state is from the nearest initial state.  Negative-weight
							 | 
						|
								  cycles are detected, though only in the naive way.  (Lack of
							 | 
						|
								  convergence after nodes-1 iterations.)  In such a case, a constant
							 | 
						|
								  %ADD with value minus infinity is returned.  Bellman-Ford is based on
							 | 
						|
								  matrix-vector multiplication.  The matrix is the distance matrix
							 | 
						|
								  D(x,y), such that D(a,b) is the length of the arc connecting state a
							 | 
						|
								  to state b.  The vector V(x) stores the distances of all states from
							 | 
						|
								  the initial states.  The actual vector used in the matrix-vector
							 | 
						|
								  multiplication is diff(x), that holds those distances that have
							 | 
						|
								  changed during the last update.
							 | 
						|
								
							 | 
						|
								  @see ntrWarshall ntrSquare
							 | 
						|
								
							 | 
						|
								*/
							 | 
						|
								static DdNode *
							 | 
						|
								ntrBellman(
							 | 
						|
								  DdManager *dd,
							 | 
						|
								  DdNode *D,
							 | 
						|
								  DdNode *source,
							 | 
						|
								  DdNode **x,
							 | 
						|
								  DdNode **y,
							 | 
						|
								  int vars,
							 | 
						|
								  int pr)
							 | 
						|
								{
							 | 
						|
								    DdNode *u, *w, *V, *min, *diff;
							 | 
						|
								    DdApaNumber i, nodes, one;
							 | 
						|
								    int digits = vars + 1;
							 | 
						|
								
							 | 
						|
								    /* To avoid overflow when there are many variables, use APA. */
							 | 
						|
								    nodes = Cudd_NewApaNumber(digits);
							 | 
						|
								    Cudd_ApaPowerOfTwo(digits,nodes,vars);
							 | 
						|
								    i = Cudd_NewApaNumber(digits);
							 | 
						|
								    one = Cudd_NewApaNumber(digits);
							 | 
						|
								    Cudd_ApaSetToLiteral(digits,one,1);
							 | 
						|
								
							 | 
						|
								#if 0
							 | 
						|
								    /* Find the distances from the initial state along paths using one
							 | 
						|
								    ** arc. */
							 | 
						|
								    w = Cudd_Cofactor(dd,D,source); /* works only if source is a cube */
							 | 
						|
								    Cudd_Ref(w);
							 | 
						|
								    V = Cudd_addSwapVariables(dd,w,x,y,vars);
							 | 
						|
								    Cudd_Ref(V);
							 | 
						|
								    Cudd_RecursiveDeref(dd,w);
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    /* The initial states are at distance 0. The other states are
							 | 
						|
								    ** initially at infinite distance. */
							 | 
						|
								    V = Cudd_addIte(dd,source,Cudd_ReadZero(dd),Cudd_ReadPlusInfinity(dd));
							 | 
						|
								    Cudd_Ref(V);
							 | 
						|
								
							 | 
						|
								    /* Selective trace algorithm.  For the next update, only consider the
							 | 
						|
								    ** nodes whose distance has changed in the last update. */
							 | 
						|
								    diff = V;
							 | 
						|
								    Cudd_Ref(diff);
							 | 
						|
								
							 | 
						|
								    for (Cudd_ApaSetToLiteral(digits,i,1);
							 | 
						|
									 Cudd_ApaCompare(digits,i,digits,nodes) < 0;
							 | 
						|
									 Cudd_ApaAdd(digits,i,one,i)) {
							 | 
						|
									if (pr>2) {(void) printf("V"); Cudd_PrintDebug(dd,V,vars,pr);}
							 | 
						|
									/* Compute the distances via triangulation as a function of x. */
							 | 
						|
									w = Cudd_addTriangle(dd,diff,D,x,vars);
							 | 
						|
									Cudd_Ref(w);
							 | 
						|
									Cudd_RecursiveDeref(dd,diff);
							 | 
						|
									u = Cudd_addSwapVariables(dd,w,x,y,vars);
							 | 
						|
									Cudd_Ref(u);
							 | 
						|
									Cudd_RecursiveDeref(dd,w);
							 | 
						|
									if (pr>2) {(void) printf("u"); Cudd_PrintDebug(dd,u,vars,pr);}
							 | 
						|
								
							 | 
						|
									/* Take the minimum of the previous distances and those just
							 | 
						|
									** computed. */
							 | 
						|
									min = Cudd_addApply(dd,Cudd_addMinimum,V,u);
							 | 
						|
									Cudd_Ref(min);
							 | 
						|
									Cudd_RecursiveDeref(dd,u);
							 | 
						|
									if (pr>2) {(void) printf("min"); Cudd_PrintDebug(dd,min,vars,pr);}
							 | 
						|
								
							 | 
						|
									if (V == min) {		/* convergence */
							 | 
						|
									    Cudd_RecursiveDeref(dd,min);
							 | 
						|
									    if (pr>0) {
							 | 
						|
										(void) printf("Terminating after ");
							 | 
						|
										Cudd_ApaPrintDecimal(stdout,digits,i);
							 | 
						|
										(void) printf(" iterations\n");
							 | 
						|
									    }
							 | 
						|
									    break;
							 | 
						|
									}
							 | 
						|
									/* Find the distances that decreased. */
							 | 
						|
									diff = Cudd_addApply(dd,Cudd_addDiff,V,min);
							 | 
						|
									Cudd_Ref(diff);
							 | 
						|
									if (pr>2) {(void) printf("diff"); Cudd_PrintDebug(dd,diff,vars,pr);}
							 | 
						|
									Cudd_RecursiveDeref(dd,V);
							 | 
						|
									V = min;
							 | 
						|
								    }
							 | 
						|
								    /* Negative cycle detection. */
							 | 
						|
								    if (Cudd_ApaCompare(digits,i,digits,nodes) == 0 &&
							 | 
						|
									diff != Cudd_ReadPlusInfinity(dd)) {
							 | 
						|
									(void) printf("Negative cycle\n");
							 | 
						|
									Cudd_RecursiveDeref(dd,diff);
							 | 
						|
									Cudd_RecursiveDeref(dd,V);
							 | 
						|
									V = Cudd_ReadMinusInfinity(dd);
							 | 
						|
									Cudd_Ref(V);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    Cudd_Deref(V);
							 | 
						|
								    FREE(i);
							 | 
						|
								    FREE(nodes);
							 | 
						|
								    FREE(one);
							 | 
						|
								    return(V);
							 | 
						|
								
							 | 
						|
								} /* end of ntrBellman */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								  @brief Floyd-Warshall algorithm for all-pair shortest paths.
							 | 
						|
								*/
							 | 
						|
								static DdNode *
							 | 
						|
								ntrWarshall(
							 | 
						|
								  DdManager *dd,
							 | 
						|
								  DdNode *D,
							 | 
						|
								  DdNode **x,
							 | 
						|
								  DdNode **y,
							 | 
						|
								  int vars,
							 | 
						|
								  int pr)
							 | 
						|
								{
							 | 
						|
								    DdNode *one, *zero;
							 | 
						|
								    DdNode *xminterm,  *w, *V, *V2;
							 | 
						|
								    DdNode *P, *R;
							 | 
						|
								    int i;
							 | 
						|
								    int nodes;
							 | 
						|
								    int k,u;
							 | 
						|
								    long start_time;
							 | 
						|
								    if (vars > 30)
							 | 
						|
									nodes = 1000000000;
							 | 
						|
								    else
							 | 
						|
									nodes = 1 << vars;
							 | 
						|
								
							 | 
						|
								    one = DD_ONE(dd);
							 | 
						|
								    zero = DD_ZERO(dd);
							 | 
						|
								    Cudd_Ref(R = D);                        /* make copy of original matrix */
							 | 
						|
								
							 | 
						|
								    /* Extract pivot row and column from D */
							 | 
						|
								    start_time = util_cpu_time();
							 | 
						|
								    for (k = 0; k < nodes; k++) {
							 | 
						|
								        if (k % 10000 == 0) {
							 | 
						|
									    (void) printf("Starting iteration  %d  at time %s\n",
							 | 
						|
											  k,util_print_time(util_cpu_time() - start_time));
							 | 
						|
								        }
							 | 
						|
								        Cudd_Ref(xminterm = one);
							 | 
						|
								        u = k;
							 | 
						|
									for (i = vars-1; i >= 0; i--) {
							 | 
						|
									    if (u&1) {
							 | 
						|
									        Cudd_Ref(w = Cudd_addIte(dd,x[i],xminterm,zero));
							 | 
						|
									    } else {
							 | 
						|
									        Cudd_Ref(w = Cudd_addIte(dd,x[i],zero,xminterm));
							 | 
						|
									    }
							 | 
						|
									    Cudd_RecursiveDeref(dd,xminterm);
							 | 
						|
									    xminterm = w;
							 | 
						|
									    u >>= 1;
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									Cudd_Ref(V = Cudd_Cofactor(dd,R,xminterm));
							 | 
						|
									Cudd_RecursiveDeref(dd,xminterm);
							 | 
						|
									if (pr>2) {(void) printf("V"); Cudd_PrintDebug(dd,V,vars,pr);}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
									Cudd_Ref(xminterm = one);
							 | 
						|
									u = k;
							 | 
						|
									for (i = vars-1; i >= 0; i--) {
							 | 
						|
									    if (u&1) {
							 | 
						|
									        Cudd_Ref(w = Cudd_addIte(dd,y[i],xminterm,zero));
							 | 
						|
									    } else {
							 | 
						|
									        Cudd_Ref(w = Cudd_addIte(dd,y[i],zero,xminterm));
							 | 
						|
									    }
							 | 
						|
									    Cudd_RecursiveDeref(dd,xminterm);
							 | 
						|
									    xminterm = w;
							 | 
						|
									    u >>= 1;
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									Cudd_Ref(V2 = Cudd_Cofactor(dd,R,xminterm));
							 | 
						|
									Cudd_RecursiveDeref(dd,xminterm);
							 | 
						|
									if (pr>2) {(void) printf("V2"); Cudd_PrintDebug(dd,V2,vars,pr);}
							 | 
						|
								
							 | 
						|
									Cudd_Ref(P = Cudd_addOuterSum(dd,R,V,V2));
							 | 
						|
								
							 | 
						|
									Cudd_RecursiveDeref(dd,V);
							 | 
						|
									Cudd_RecursiveDeref(dd,V2);
							 | 
						|
									Cudd_RecursiveDeref(dd,R);
							 | 
						|
									R = P;
							 | 
						|
									if (pr>2) {(void) printf("R"); Cudd_PrintDebug(dd,R,vars,pr);}
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    Cudd_Deref(R);
							 | 
						|
								    return(R);
							 | 
						|
								
							 | 
						|
								} /* end of ntrWarshall */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								  @brief Repeated squaring algorithm for all-pairs shortest paths.
							 | 
						|
								*/
							 | 
						|
								static DdNode *
							 | 
						|
								ntrSquare(
							 | 
						|
								  DdManager *dd /**< manager */,
							 | 
						|
								  DdNode *D /**< D(z,y): distance matrix */,
							 | 
						|
								  DdNode **x /**< array of x variables */,
							 | 
						|
								  DdNode **y /**< array of y variables */,
							 | 
						|
								  DdNode **z /**< array of z variables */,
							 | 
						|
								  int vars /**< number of variables in each of the three arrays */,
							 | 
						|
								  int pr /**< verbosity level */,
							 | 
						|
								  int st /**< use the selective trace algorithm */)
							 | 
						|
								{
							 | 
						|
								    DdNode *zero;
							 | 
						|
								    DdNode *I;              /* identity matirix */
							 | 
						|
								    DdNode *w, *V, *P, *M, *R, *RT;
							 | 
						|
								    DdNode *diff, *min, *minDiag;
							 | 
						|
								    int n;
							 | 
						|
								    int neg;
							 | 
						|
								    long start_time;
							 | 
						|
								
							 | 
						|
								    zero = Cudd_ReadZero(dd);
							 | 
						|
								    /* Make a working copy of the original matrix. */
							 | 
						|
								    R = D;
							 | 
						|
								    Cudd_Ref(R);
							 | 
						|
								    I = Cudd_addXeqy(dd,vars,z,y);    /* identity matrix */
							 | 
						|
								    Cudd_Ref(I);
							 | 
						|
								
							 | 
						|
								    /* Make a copy of the matrix for the selective trace algorithm. */
							 | 
						|
								    diff = R;
							 | 
						|
								    Cudd_Ref(diff);
							 | 
						|
								
							 | 
						|
								    start_time = util_cpu_time();
							 | 
						|
								    for (n = vars; n >= 0; n--) {
							 | 
						|
									printf("Starting iteration %d at time %s\n",vars-n,
							 | 
						|
									       util_print_time(util_cpu_time() - start_time));
							 | 
						|
								
							 | 
						|
									/* Check for negative cycles: They are identified by negative
							 | 
						|
									** elements on the diagonal.
							 | 
						|
									*/
							 | 
						|
								
							 | 
						|
									/* Extract values from the diagonal. */
							 | 
						|
								        Cudd_Ref(w = Cudd_addIte(dd,I,R,zero));
							 | 
						|
									minDiag = Cudd_addFindMin(dd,w);	/* no need to ref */
							 | 
						|
									neg = Cudd_V(minDiag) < 0;
							 | 
						|
									Cudd_RecursiveDeref(dd,w);
							 | 
						|
									if (neg) {
							 | 
						|
									    Cudd_RecursiveDeref(dd,diff);
							 | 
						|
								            (void) printf("Negative cycle after %d iterations!\n",vars-n);
							 | 
						|
								            break;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
									/* Prepare the first operand of matrix multiplication:
							 | 
						|
									**   diff(z,y) -> RT(x,y) -> V(x,z)
							 | 
						|
									*/
							 | 
						|
								
							 | 
						|
									/* RT(x,y) */
							 | 
						|
									Cudd_Ref(RT = Cudd_addSwapVariables(dd,diff,x,z,vars));
							 | 
						|
									Cudd_RecursiveDeref(dd,diff);
							 | 
						|
									/* V(x,z) */
							 | 
						|
									Cudd_Ref(V = Cudd_addSwapVariables(dd,RT,y,z,vars));
							 | 
						|
									Cudd_RecursiveDeref(dd,RT);
							 | 
						|
									if (pr > 0) {
							 | 
						|
									    double pathcount;
							 | 
						|
									    (void) printf("V"); Cudd_PrintDebug(dd,V,2*vars,pr);
							 | 
						|
									    pathcount = Cudd_CountPath(V);
							 | 
						|
									    (void) printf("Path count = %g\n", pathcount);
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									/* V(x,z) * R(z,y) -> P(x,y) */
							 | 
						|
									Cudd_Ref(P = Cudd_addTriangle(dd,V,R,z,vars));
							 | 
						|
									Cudd_RecursiveDeref(dd,V);
							 | 
						|
									/* P(x,y) => M(z,y) */
							 | 
						|
									Cudd_Ref(M = Cudd_addSwapVariables(dd,P,x,z,vars));
							 | 
						|
									Cudd_RecursiveDeref(dd,P);
							 | 
						|
									if (pr>0) {(void) printf("M"); Cudd_PrintDebug(dd,M,2*vars,pr);}
							 | 
						|
								
							 | 
						|
									/* min(z,y) */
							 | 
						|
									Cudd_Ref(min = Cudd_addApply(dd,Cudd_addMinimum,R,M));
							 | 
						|
									Cudd_RecursiveDeref(dd,M);
							 | 
						|
								
							 | 
						|
									if (R == min) {
							 | 
						|
									    Cudd_RecursiveDeref(dd,min);
							 | 
						|
									    if (pr>0) {printf("Done after %d iterations\n",vars-n+1); }
							 | 
						|
									    break;
							 | 
						|
									}
							 | 
						|
									/* diff(z,y) */
							 | 
						|
									if (st) {
							 | 
						|
									    Cudd_Ref(diff = Cudd_addApply(dd,Cudd_addDiff,min,R));
							 | 
						|
									} else {
							 | 
						|
									    Cudd_Ref(diff = min);
							 | 
						|
									}
							 | 
						|
									Cudd_RecursiveDeref(dd,R);
							 | 
						|
									R = min;                  /* keep a copy of matrix at current iter. */
							 | 
						|
									if (pr > 0) {
							 | 
						|
									    double pathcount;
							 | 
						|
									    (void) printf("R"); Cudd_PrintDebug(dd,R,2*vars,pr);
							 | 
						|
									    pathcount = Cudd_CountPath(R);
							 | 
						|
									    (void) printf("Path count = %g\n", pathcount);
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if (n == 0) {
							 | 
						|
									    (void) printf("Negative cycle!\n");
							 | 
						|
									    break;
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
								    }
							 | 
						|
								    Cudd_RecursiveDeref(dd,I);
							 | 
						|
								    Cudd_Deref(R);
							 | 
						|
								    return(R);
							 | 
						|
								
							 | 
						|
								} /* end of ntrSquare */
							 |