Graphviz  2.31.20130525.0447
lib/neatogen/dijkstra.c
Go to the documentation of this file.
00001 /* $Id$ $Revision$ */
00002 /* vim:set shiftwidth=4 ts=8: */
00003 
00004 /*************************************************************************
00005  * Copyright (c) 2011 AT&T Intellectual Property 
00006  * All rights reserved. This program and the accompanying materials
00007  * are made available under the terms of the Eclipse Public License v1.0
00008  * which accompanies this distribution, and is available at
00009  * http://www.eclipse.org/legal/epl-v10.html
00010  *
00011  * Contributors: See CVS logs. Details at http://www.graphviz.org/
00012  *************************************************************************/
00013 
00014 
00015 /******************************************
00016 
00017         Dijkstra algorithm
00018         Computes single-source distances for
00019         weighted graphs
00020 
00021 ******************************************/
00022 
00023 
00024 #include "bfs.h"
00025 #include "dijkstra.h"
00026 #include <limits.h>
00027 #include <stdlib.h>
00028 /* #include <math.h> */
00029 
00030 #define MAX_DIST (double)INT_MAX
00031 
00032 typedef DistType Word;
00033 
00034 #define LOOP while(TRUE)
00035 
00036 /* This heap class is suited to the Dijkstra alg.
00037    data[i]=vertexNum <==> index[vertexNum]=i
00038 */
00039 
00040 #define left(i) (2*(i))
00041 #define right(i) (2*(i)+1)
00042 #define parent(i) ((i)/2)
00043 #define insideHeap(h,i) ((i)<h->heapSize)
00044 #define greaterPriority(h,i,j,dist) (dist[h->data[i]]<dist[h->data[j]])
00045 #define assign(h,i,j,index) {h->data[i]=h->data[j]; index[h->data[i]]=i;}
00046 #define exchange(h,i,j,index) {int temp; \
00047                 temp=h->data[i]; \
00048                 h->data[i]=h->data[j]; \
00049                 h->data[j]=temp; \
00050                 index[h->data[i]]=i; \
00051                 index[h->data[j]]=j; \
00052 }
00053 
00054 typedef struct {
00055     int *data;
00056     int heapSize;
00057 } heap;
00058 
00059 static void heapify(heap * h, int i, int index[], Word dist[])
00060 {
00061     int l, r, largest;
00062     while (1) {
00063         l = left(i);
00064         r = right(i);
00065         if (insideHeap(h, l) && greaterPriority(h, l, i, dist))
00066             largest = l;
00067         else
00068             largest = i;
00069         if (insideHeap(h, r) && greaterPriority(h, r, largest, dist))
00070             largest = r;
00071 
00072         if (largest == i)
00073             break;
00074 
00075         exchange(h, largest, i, index);
00076         i = largest;
00077     }
00078 }
00079 
00080 #ifdef OBSOLETE
00081 /* originally, the code called mkHeap to allocate space, then
00082  * initHeap to realloc the space. This is silly.
00083  * Now we just call initHeap.
00084  */
00085 static void mkHeap(heap * h, int size)
00086 {
00087     h->data = N_GNEW(size, int);
00088     h->heapSize = 0;
00089 }
00090 #endif
00091 
00092 static void freeHeap(heap * h)
00093 {
00094     if (h->data) free(h->data);
00095 }
00096 
00097 static void
00098 initHeap(heap * h, int startVertex, int index[], Word dist[], int n)
00099 {
00100     int i, count;
00101     int j;    /* We cannot use an unsigned value in this loop */
00102     /* h->data=(int*) realloc(h->data, (n-1)*sizeof(int)); */
00103     if (n == 1) h->data = NULL;
00104     else h->data = N_GNEW(n - 1, int);
00105     h->heapSize = n - 1;
00106 
00107     for (count = 0, i = 0; i < n; i++)
00108         if (i != startVertex) {
00109             h->data[count] = i;
00110             index[i] = count;
00111             count++;
00112         }
00113 
00114     for (j = (n - 1) / 2; j >= 0; j--)
00115         heapify(h, j, index, dist);
00116 }
00117 
00118 static boolean extractMax(heap * h, int *max, int index[], Word dist[])
00119 {
00120     if (h->heapSize == 0)
00121         return FALSE;
00122 
00123     *max = h->data[0];
00124     h->data[0] = h->data[h->heapSize - 1];
00125     index[h->data[0]] = 0;
00126     h->heapSize--;
00127     heapify(h, 0, index, dist);
00128 
00129     return TRUE;
00130 }
00131 
00132 static void
00133 increaseKey(heap * h, int increasedVertex, Word newDist, int index[],
00134             Word dist[])
00135 {
00136     int placeInHeap;
00137     int i;
00138 
00139     if (dist[increasedVertex] <= newDist)
00140         return;
00141 
00142     placeInHeap = index[increasedVertex];
00143 
00144     dist[increasedVertex] = newDist;
00145 
00146     i = placeInHeap;
00147     while (i > 0 && dist[h->data[parent(i)]] > newDist) {       /* can write here: greaterPriority(i,parent(i),dist) */
00148         assign(h, i, parent(i), index);
00149         i = parent(i);
00150     }
00151     h->data[i] = increasedVertex;
00152     index[increasedVertex] = i;
00153 }
00154 
00155 void dijkstra(int vertex, vtx_data * graph, int n, DistType * dist)
00156 {
00157     int i;
00158     heap H;
00159     int closestVertex, neighbor;
00160     DistType closestDist, prevClosestDist = INT_MAX;
00161     static int *index;
00162 
00163 #ifdef OBSOLETE
00164     mkHeap(&H, n);
00165 #endif
00166     index = (int *) realloc(index, n * sizeof(int));
00167 
00168     /* initial distances with edge weights: */
00169     for (i = 0; i < n; i++)
00170         dist[i] = (DistType) MAX_DIST;
00171     dist[vertex] = 0;
00172     for (i = 1; i < graph[vertex].nedges; i++)
00173         dist[graph[vertex].edges[i]] = (DistType) graph[vertex].ewgts[i];
00174 
00175     initHeap(&H, vertex, index, dist, n);
00176 
00177     while (extractMax(&H, &closestVertex, index, dist)) {
00178         closestDist = dist[closestVertex];
00179         if (closestDist == MAX_DIST)
00180             break;
00181         for (i = 1; i < graph[closestVertex].nedges; i++) {
00182             neighbor = graph[closestVertex].edges[i];
00183             increaseKey(&H, neighbor,
00184                         closestDist +
00185                         (DistType) graph[closestVertex].ewgts[i], index,
00186                         dist);
00187         }
00188         prevClosestDist = closestDist;
00189     }
00190 
00191     /* For dealing with disconnected graphs: */
00192     for (i = 0; i < n; i++)
00193         if (dist[i] == MAX_DIST)        /* 'i' is not connected to 'vertex' */
00194             dist[i] = prevClosestDist + 10;
00195     freeHeap(&H);
00196 }
00197 
00198  /* Dijkstra bounded to nodes in *unweighted* radius */
00199 int
00200 dijkstra_bounded(int vertex, vtx_data * graph, int n, DistType * dist,
00201                  int bound, int *visited_nodes)
00202  /* make dijkstra, but consider only nodes whose *unweighted* distance from 'vertex'  */
00203  /* is at most 'bound' */
00204  /* MON-EFFICIENT implementation, see below. */
00205 {
00206     int num_visited_nodes;
00207     int i;
00208     static boolean *node_in_neighborhood = NULL;
00209     static int size = 0;
00210     static int *index;
00211     Queue Q;
00212     heap H;
00213     int closestVertex, neighbor;
00214     DistType closestDist;
00215     int num_found = 0;
00216 
00217     /* first, perform BFS to find the nodes in the region */
00218     mkQueue(&Q, n);
00219     /* remember that dist should be init. with -1's */
00220     for (i = 0; i < n; i++) {
00221         dist[i] = -1;           /* far, TOO COSTLY (O(n))! */
00222     }
00223     num_visited_nodes =
00224         bfs_bounded(vertex, graph, n, dist, &Q, bound, visited_nodes);
00225     if (size < n) {
00226         node_in_neighborhood =
00227             (boolean *) realloc(node_in_neighborhood, n * sizeof(boolean));
00228         for (i = size; i < n; i++) {
00229             node_in_neighborhood[i] = FALSE;
00230         }
00231         size = n;
00232     }
00233     for (i = 0; i < num_visited_nodes; i++) {
00234         node_in_neighborhood[visited_nodes[i]] = TRUE;
00235     }
00236 
00237 
00238 #ifdef OBSOLETE
00239     mkHeap(&H, n);
00240 #endif
00241     index = (int *) realloc(index, n * sizeof(int));
00242 
00243     /* initial distances with edge weights: */
00244     for (i = 0; i < n; i++)     /* far, TOO COSTLY (O(n))! */
00245         dist[i] = (DistType) MAX_DIST;
00246     dist[vertex] = 0;
00247     for (i = 1; i < graph[vertex].nedges; i++)
00248         dist[graph[vertex].edges[i]] = (DistType) graph[vertex].ewgts[i];
00249 
00250     /* again, TOO COSTLY (O(n)) to put all nodes in heap! */
00251     initHeap(&H, vertex, index, dist, n); 
00252 
00253     while (num_found < num_visited_nodes
00254            && extractMax(&H, &closestVertex, index, dist)) {
00255         if (node_in_neighborhood[closestVertex]) {
00256             num_found++;
00257         }
00258         closestDist = dist[closestVertex];
00259         if (closestDist == MAX_DIST)
00260             break;
00261         for (i = 1; i < graph[closestVertex].nedges; i++) {
00262             neighbor = graph[closestVertex].edges[i];
00263             increaseKey(&H, neighbor,
00264                         closestDist +
00265                         (DistType) graph[closestVertex].ewgts[i], index,
00266                         dist);
00267         }
00268     }
00269 
00270     /* restore initial false-status of 'node_in_neighborhood' */
00271     for (i = 0; i < num_visited_nodes; i++) {
00272         node_in_neighborhood[visited_nodes[i]] = FALSE;
00273     }
00274     freeHeap(&H);
00275     freeQueue(&Q);
00276     return num_visited_nodes;
00277 }
00278 
00279 static void heapify_f(heap * h, int i, int index[], float dist[])
00280 {
00281     int l, r, largest;
00282     while (1) {
00283         l = left(i);
00284         r = right(i);
00285         if (insideHeap(h, l) && greaterPriority(h, l, i, dist))
00286             largest = l;
00287         else
00288             largest = i;
00289         if (insideHeap(h, r) && greaterPriority(h, r, largest, dist))
00290             largest = r;
00291 
00292         if (largest == i)
00293             break;
00294 
00295         exchange(h, largest, i, index);
00296         i = largest;
00297     }
00298 }
00299 
00300 static void
00301 initHeap_f(heap * h, int startVertex, int index[], float dist[], int n)
00302 {
00303     int i, count;
00304     int j;                      /* We cannot use an unsigned value in this loop */
00305     h->data = N_GNEW(n - 1, int);
00306     h->heapSize = n - 1;
00307 
00308     for (count = 0, i = 0; i < n; i++)
00309         if (i != startVertex) {
00310             h->data[count] = i;
00311             index[i] = count;
00312             count++;
00313         }
00314 
00315     for (j = (n - 1) / 2; j >= 0; j--)
00316         heapify_f(h, j, index, dist);
00317 }
00318 
00319 static boolean extractMax_f(heap * h, int *max, int index[], float dist[])
00320 {
00321     if (h->heapSize == 0)
00322         return FALSE;
00323 
00324     *max = h->data[0];
00325     h->data[0] = h->data[h->heapSize - 1];
00326     index[h->data[0]] = 0;
00327     h->heapSize--;
00328     heapify_f(h, 0, index, dist);
00329 
00330     return TRUE;
00331 }
00332 
00333 static void
00334 increaseKey_f(heap * h, int increasedVertex, float newDist, int index[],
00335               float dist[])
00336 {
00337     int placeInHeap;
00338     int i;
00339 
00340     if (dist[increasedVertex] <= newDist)
00341         return;
00342 
00343     placeInHeap = index[increasedVertex];
00344 
00345     dist[increasedVertex] = newDist;
00346 
00347     i = placeInHeap;
00348     while (i > 0 && dist[h->data[parent(i)]] > newDist) {       /* can write here: greaterPriority(i,parent(i),dist) */
00349         assign(h, i, parent(i), index);
00350         i = parent(i);
00351     }
00352     h->data[i] = increasedVertex;
00353     index[increasedVertex] = i;
00354 }
00355 
00356 /* dijkstra_f:
00357  * Weighted shortest paths from vertex.
00358  * Assume graph is connected.
00359  */
00360 void dijkstra_f(int vertex, vtx_data * graph, int n, float *dist)
00361 {
00362     int i;
00363     heap H;
00364     int closestVertex = 0, neighbor;
00365     float closestDist;
00366     int *index;
00367 
00368 #ifdef OBSOLETE
00369     mkHeap(&H, n);
00370 #endif
00371     index = N_GNEW(n, int);
00372 
00373     /* initial distances with edge weights: */
00374     for (i = 0; i < n; i++)
00375         dist[i] = MAXFLOAT;
00376     dist[vertex] = 0;
00377     for (i = 1; i < graph[vertex].nedges; i++)
00378         dist[graph[vertex].edges[i]] = graph[vertex].ewgts[i];
00379 
00380     initHeap_f(&H, vertex, index, dist, n);
00381 
00382     while (extractMax_f(&H, &closestVertex, index, dist)) {
00383         closestDist = dist[closestVertex];
00384         if (closestDist == MAXFLOAT)
00385             break;
00386         for (i = 1; i < graph[closestVertex].nedges; i++) {
00387             neighbor = graph[closestVertex].edges[i];
00388             increaseKey_f(&H, neighbor,
00389                           closestDist + graph[closestVertex].ewgts[i],
00390                           index, dist);
00391         }
00392     }
00393 
00394     freeHeap(&H);
00395     free(index);
00396 }