lib/dgRange.c

Go to the documentation of this file.
00001 /* dgRange - stuff to tell if a graph which has a range
00002  * of values associated with each edge is internally consistent.  
00003  * See comment under bfGraphFromRangeGraph for details. */
00004 
00005 #include "common.h"
00006 #include "diGraph.h"
00007 
00008 static char const rcsid[] = "$Id: dgRange.c,v 1.3 2003/05/06 07:33:42 kate Exp $";
00009 
00010 struct bfEdge
00011 /* An edge in a (lightweight) Belman Ford graph. */
00012    {
00013    struct bfEdge *next;    /* Pointer to next element. */
00014    int distance;           /* Distance - may be negative. */
00015    struct bfVertex *in;    /* Connecting node. */
00016    struct bfVertex *out;   /* Connecting node. */
00017    };
00018 
00019 struct bfVertex
00020 /* A node in a (lightweight) Belman Ford graph. */
00021    {
00022    int position;               /* Currently assigned position. */
00023    struct bfEdge *waysOut;     /* Ways out. */
00024    };
00025 
00026 struct bfGraph
00027 /* A lightweight, but fixed sized graph for Belman Ford algorithm. */
00028     {
00029     int vertexCount;             /* Number of vertices */
00030     struct bfVertex *vertices;   /* Array of vertices. */
00031     int edgeCount;               /* Number of edges. */
00032     struct bfEdge *edges;        /* Array of edges. */
00033     };
00034 
00035 struct bfRange 
00036 /* Min and max distances allowed for an edge. */
00037    {
00038    int minDist, maxDist;
00039    };
00040 
00041 static void bfGraphFree(struct bfGraph **pGraph)
00042 /* Free up Belman-Ford graph. */
00043 {
00044 struct bfGraph *graph = *pGraph;
00045 if (graph != NULL)
00046     {
00047     freeMem(graph->vertices);
00048     freeMem(graph->edges);
00049     freez(pGraph);
00050     }
00051 }
00052 
00053 static struct bfGraph *bfGraphFromRangeGraph(struct diGraph *rangeGraph, 
00054    boolean (*findEdgeRange)(struct dgEdge *edge, int *retMin, int *retMax),
00055    struct dgNode *a, struct dgNode *b, int abMin, int abMax)
00056 /* Construct a directed graph with two edges for each
00057  * edge of the range graph.  Where the range graph
00058  * has the following info:
00059  *     sourceNode destNode minDistance maxDistance
00060  *    -------------------------------------------
00061  *         A         B         2          5
00062  * The bfGraph would have:
00063  *     sourceNode destNode   edgeVal  meaning
00064  *    --------------------------------------------
00065  *         A         B         5     D(A) - D(B) <= 5 
00066  *         B         A        -2     D(B) - D(A) <= -2
00067  * Furthermore the bfGraph introduces a new node,
00068  * "zero", which has a zero-valued connection to
00069  * all other nodes.
00070  *
00071  * This graph can then be processed via the Bellman-
00072  * Ford algorithm (see p. 532 of Cormen,Leiserson and
00073  * Rivest's Introduction to Algorithms, MIT Press 1990)
00074  * to see if the bfGraph, and by extension the range
00075  * graph, is consistent.
00076  */
00077 {
00078 struct bfGraph *bfGraph;
00079 struct bfVertex *vertices, *freeVertex, *newSource, *newDest, *zeroVertex;
00080 struct bfEdge *edges, *newEdge, *freeEdge;
00081 struct dgNode *oldSource, *oldDest, *oldNode;
00082 int oldEdgeCount = dlCount(rangeGraph->edgeList);
00083 int oldVertexCount = 0;
00084 
00085 /* Coopt topoOrder field to store unique ID for each
00086  * node, starting at 1.  (We'll reserve 0 for the
00087  * node we insert - the Belman Ford "zero" node.)*/
00088 for (oldNode = rangeGraph->nodeList; oldNode != NULL; oldNode = oldNode->next)
00089     oldNode->topoOrder = ++oldVertexCount;
00090 
00091 /* Allocate space for new graph. */
00092 AllocVar(bfGraph);
00093 bfGraph->vertexCount = oldVertexCount + 1;
00094 bfGraph->vertices = freeVertex = AllocArray(vertices, bfGraph->vertexCount);
00095 bfGraph->edgeCount = 2*oldEdgeCount + oldVertexCount;
00096 if (a != NULL)
00097   bfGraph->edgeCount += 2;
00098 bfGraph->edges = freeEdge = AllocArray(edges, bfGraph->edgeCount);
00099 
00100 /* Get zero vertex. */
00101 zeroVertex = freeVertex++;
00102 
00103 /* Scan through old graph and add vertices to new graph. */
00104 for (oldSource = rangeGraph->nodeList; oldSource != NULL; 
00105     oldSource = oldSource->next)
00106     {
00107     struct dgConnection *dgConn;
00108     int rangeMin, rangeMax;
00109 
00110     /* Allocate new source vertex. */
00111     newSource = freeVertex++;
00112 
00113     /* Make connection from zero vertex to this one. */
00114     newEdge = freeEdge++;
00115     newEdge->distance = 0;
00116     newEdge->in = zeroVertex;
00117     newEdge->out = newSource;
00118     slAddHead(&zeroVertex->waysOut, newEdge);
00119 
00120     /* Loop through all ways out of source. */
00121     for (dgConn = oldSource->nextList; dgConn != NULL; dgConn = dgConn->next)
00122         {
00123         /* Find destination vertex and size range of edge. */
00124         if ((*findEdgeRange)(dgConn->edgeOnList->val, &rangeMin, &rangeMax))
00125             {
00126             oldDest = dgConn->node;
00127             newDest = &vertices[oldDest->topoOrder];
00128 
00129             /* Make two new edges corresponding to old edge. */
00130             newEdge = freeEdge++;
00131             newEdge->distance = rangeMax;
00132             newEdge->in = newSource;
00133             newEdge->out = newDest;
00134             slAddHead(&newSource->waysOut, newEdge);
00135             newEdge = freeEdge++;
00136             newEdge->distance = -rangeMin;
00137             newEdge->in = newDest;
00138             newEdge->out = newSource;
00139             slAddHead(&newDest->waysOut, newEdge);
00140             }
00141         }
00142     }
00143 /* Add additional pair of edges for extra range if applicable. */
00144 if (a != NULL)
00145     {
00146     newSource = &vertices[a->topoOrder];
00147     newDest = &vertices[b->topoOrder];
00148     newEdge = freeEdge++;
00149     newEdge->distance = abMax;
00150     newEdge->in = newSource;
00151     newEdge->out = newDest;
00152     slAddHead(&newSource->waysOut, newEdge);
00153     newEdge = freeEdge++;
00154     newEdge->distance = -abMin;
00155     newEdge->in = newDest;
00156     newEdge->out = newSource;
00157     slAddHead(&newDest->waysOut, newEdge);
00158     }
00159 bfGraph->edgeCount = freeEdge - bfGraph->edges;
00160 return bfGraph;
00161 }
00162 
00163 static boolean bfCheckGraph(struct bfGraph *graph)
00164 /* Run Belman-Ford algorithm to check graph for consistency. */
00165 {
00166 struct bfVertex *vertices = graph->vertices, *in, *out;
00167 int vertexCount = graph->vertexCount;
00168 int edgeCount = graph->edgeCount;
00169 struct bfEdge *edges = graph->edges, *edge;
00170 int i, edgeIx;
00171 int maxIterations = vertexCount - 1;
00172 boolean anyChange = FALSE;
00173 int newPos;
00174 
00175 for (i=0; i<vertexCount; ++i)
00176     vertices[i].position = 0x3fffffff;    /* Mighty big number. */
00177 for (i=0; i<maxIterations; ++i)
00178     {
00179     anyChange = FALSE;
00180     for (edgeIx = 0, edge = edges; edgeIx < edgeCount; ++edgeIx, ++edge)
00181         {
00182         in = edge->in;
00183         out = edge->out;
00184         newPos = in->position + edge->distance;
00185         if (newPos < out->position)
00186             {
00187             out->position = newPos;
00188             anyChange = TRUE;
00189             }
00190         }
00191     if (!anyChange)
00192         break;
00193     }
00194 return !anyChange;
00195 }
00196 
00197 boolean dgAddedRangeConsistent(struct diGraph *rangeGraph,
00198    struct dgNode *a, struct dgNode *b, int abMin, int abMax,
00199    boolean (*findEdgeRange)(struct dgEdge *edge, int *retMin, int *retMax) )
00200 /* Return TRUE if graph with a range of allowable distances associated
00201  * with each edge would be internally consistent if add edge from a to b
00202  * with given min/max values. */
00203 {
00204 struct bfGraph *bfGraph;
00205 boolean ok; 
00206 
00207 bfGraph = bfGraphFromRangeGraph(rangeGraph, findEdgeRange, a, b, abMin, abMax);
00208 ok = bfCheckGraph(bfGraph);
00209 bfGraphFree(&bfGraph);
00210 return ok;
00211 }
00212 
00213 boolean dgRangesConsistent(struct diGraph *rangeGraph,
00214    boolean (*findEdgeRange)(struct dgEdge *edge, int *retMin, int *retMax) )
00215 /* Return TRUE if graph with a range of allowable distances associated
00216  * with each edge is internally consistent. */
00217 {
00218 return dgAddedRangeConsistent(rangeGraph, NULL, NULL, 0, 0, findEdgeRange);
00219 }
00220 

Generated on Tue Dec 25 18:39:30 2007 for blat by  doxygen 1.5.2