dijkstra.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. /*************************************************************************
  2. * Copyright (c) 2011 AT&T Intellectual Property
  3. * All rights reserved. This program and the accompanying materials
  4. * are made available under the terms of the Eclipse Public License v1.0
  5. * which accompanies this distribution, and is available at
  6. * https://www.eclipse.org/legal/epl-v10.html
  7. *
  8. * Contributors: Details at https://graphviz.org
  9. *************************************************************************/
  10. /******************************************
  11. Dijkstra algorithm
  12. Computes single-source distances for
  13. weighted graphs
  14. ******************************************/
  15. #include <assert.h>
  16. #include <float.h>
  17. #include <neatogen/bfs.h>
  18. #include <neatogen/dijkstra.h>
  19. #include <limits.h>
  20. #include <stdbool.h>
  21. #include <stdlib.h>
  22. #include <util/alloc.h>
  23. #include <util/bitarray.h>
  24. typedef DistType Word;
  25. #define MAX_DIST ((DistType)INT_MAX)
  26. /* This heap class is suited to the Dijkstra alg.
  27. data[i]=vertexNum <==> index[vertexNum]=i
  28. */
  29. #define left(i) (2*(i))
  30. #define right(i) (2*(i)+1)
  31. #define parent(i) ((i)/2)
  32. #define insideHeap(h,i) ((i)<h->heapSize)
  33. #define greaterPriority(h,i,j,dist) (dist[h->data[i]]<dist[h->data[j]])
  34. #define assign(h,i,j,index) {h->data[i]=h->data[j]; index[h->data[i]]=i;}
  35. #define exchange(h,i,j,index) {int temp; \
  36. temp=h->data[i]; \
  37. h->data[i]=h->data[j]; \
  38. h->data[j]=temp; \
  39. index[h->data[i]]=i; \
  40. index[h->data[j]]=j; \
  41. }
  42. typedef struct {
  43. int *data;
  44. int heapSize;
  45. } heap;
  46. static void heapify(heap * h, int i, int index[], Word dist[])
  47. {
  48. int l, r, largest;
  49. while (1) {
  50. l = left(i);
  51. r = right(i);
  52. if (insideHeap(h, l) && greaterPriority(h, l, i, dist))
  53. largest = l;
  54. else
  55. largest = i;
  56. if (insideHeap(h, r) && greaterPriority(h, r, largest, dist))
  57. largest = r;
  58. if (largest == i)
  59. break;
  60. exchange(h, largest, i, index);
  61. i = largest;
  62. }
  63. }
  64. static void freeHeap(heap * h)
  65. {
  66. free(h->data);
  67. }
  68. static void
  69. initHeap(heap * h, int startVertex, int index[], Word dist[], int n)
  70. {
  71. int i, count;
  72. int j; /* We cannot use an unsigned value in this loop */
  73. if (n == 1) h->data = NULL;
  74. else h->data = gv_calloc(n - 1, sizeof(int));
  75. h->heapSize = n - 1;
  76. for (count = 0, i = 0; i < n; i++)
  77. if (i != startVertex) {
  78. h->data[count] = i;
  79. index[i] = count;
  80. count++;
  81. }
  82. for (j = (n - 1) / 2; j >= 0; j--)
  83. heapify(h, j, index, dist);
  84. }
  85. static bool extractMax(heap * h, int *max, int index[], Word dist[])
  86. {
  87. if (h->heapSize == 0)
  88. return false;
  89. *max = h->data[0];
  90. h->data[0] = h->data[h->heapSize - 1];
  91. index[h->data[0]] = 0;
  92. h->heapSize--;
  93. heapify(h, 0, index, dist);
  94. return true;
  95. }
  96. static void
  97. increaseKey(heap * h, int increasedVertex, Word newDist, int index[],
  98. Word dist[])
  99. {
  100. int placeInHeap;
  101. int i;
  102. if (dist[increasedVertex] <= newDist)
  103. return;
  104. placeInHeap = index[increasedVertex];
  105. dist[increasedVertex] = newDist;
  106. i = placeInHeap;
  107. while (i > 0 && dist[h->data[parent(i)]] > newDist) { /* can write here: greaterPriority(i,parent(i),dist) */
  108. assign(h, i, parent(i), index);
  109. i = parent(i);
  110. }
  111. h->data[i] = increasedVertex;
  112. index[increasedVertex] = i;
  113. }
  114. void dijkstra(int vertex, vtx_data * graph, int n, DistType * dist)
  115. {
  116. heap H;
  117. int closestVertex, neighbor;
  118. DistType closestDist, prevClosestDist = MAX_DIST;
  119. int *index = gv_calloc(n, sizeof(int));
  120. /* initial distances with edge weights: */
  121. for (int i = 0; i < n; i++)
  122. dist[i] = MAX_DIST;
  123. dist[vertex] = 0;
  124. for (size_t i = 1; i < graph[vertex].nedges; i++)
  125. dist[graph[vertex].edges[i]] = (DistType) graph[vertex].ewgts[i];
  126. initHeap(&H, vertex, index, dist, n);
  127. while (extractMax(&H, &closestVertex, index, dist)) {
  128. closestDist = dist[closestVertex];
  129. if (closestDist == MAX_DIST)
  130. break;
  131. for (size_t i = 1; i < graph[closestVertex].nedges; i++) {
  132. neighbor = graph[closestVertex].edges[i];
  133. increaseKey(&H, neighbor, closestDist +
  134. (DistType)graph[closestVertex].ewgts[i], index, dist);
  135. }
  136. prevClosestDist = closestDist;
  137. }
  138. /* For dealing with disconnected graphs: */
  139. for (int i = 0; i < n; i++)
  140. if (dist[i] == MAX_DIST) /* 'i' is not connected to 'vertex' */
  141. dist[i] = prevClosestDist + 10;
  142. freeHeap(&H);
  143. free(index);
  144. }
  145. static void heapify_f(heap * h, int i, int index[], float dist[])
  146. {
  147. int l, r, largest;
  148. while (1) {
  149. l = left(i);
  150. r = right(i);
  151. if (insideHeap(h, l) && greaterPriority(h, l, i, dist))
  152. largest = l;
  153. else
  154. largest = i;
  155. if (insideHeap(h, r) && greaterPriority(h, r, largest, dist))
  156. largest = r;
  157. if (largest == i)
  158. break;
  159. exchange(h, largest, i, index);
  160. i = largest;
  161. }
  162. }
  163. static void
  164. initHeap_f(heap * h, int startVertex, int index[], float dist[], int n)
  165. {
  166. int i, count;
  167. int j; /* We cannot use an unsigned value in this loop */
  168. h->data = gv_calloc(n - 1, sizeof(int));
  169. h->heapSize = n - 1;
  170. for (count = 0, i = 0; i < n; i++)
  171. if (i != startVertex) {
  172. h->data[count] = i;
  173. index[i] = count;
  174. count++;
  175. }
  176. for (j = (n - 1) / 2; j >= 0; j--)
  177. heapify_f(h, j, index, dist);
  178. }
  179. static bool extractMax_f(heap * h, int *max, int index[], float dist[])
  180. {
  181. if (h->heapSize == 0)
  182. return false;
  183. *max = h->data[0];
  184. h->data[0] = h->data[h->heapSize - 1];
  185. index[h->data[0]] = 0;
  186. h->heapSize--;
  187. heapify_f(h, 0, index, dist);
  188. return true;
  189. }
  190. static void
  191. increaseKey_f(heap * h, int increasedVertex, float newDist, int index[],
  192. float dist[])
  193. {
  194. int placeInHeap;
  195. int i;
  196. if (dist[increasedVertex] <= newDist)
  197. return;
  198. placeInHeap = index[increasedVertex];
  199. dist[increasedVertex] = newDist;
  200. i = placeInHeap;
  201. while (i > 0 && dist[h->data[parent(i)]] > newDist) { /* can write here: greaterPriority(i,parent(i),dist) */
  202. assign(h, i, parent(i), index);
  203. i = parent(i);
  204. }
  205. h->data[i] = increasedVertex;
  206. index[increasedVertex] = i;
  207. }
  208. /* dijkstra_f:
  209. * Weighted shortest paths from vertex.
  210. * Assume graph is connected.
  211. */
  212. void dijkstra_f(int vertex, vtx_data * graph, int n, float *dist)
  213. {
  214. heap H;
  215. int closestVertex = 0, neighbor;
  216. float closestDist;
  217. int *index = gv_calloc(n, sizeof(int));
  218. /* initial distances with edge weights: */
  219. for (int i = 0; i < n; i++)
  220. dist[i] = FLT_MAX;
  221. dist[vertex] = 0;
  222. for (size_t i = 1; i < graph[vertex].nedges; i++)
  223. dist[graph[vertex].edges[i]] = graph[vertex].ewgts[i];
  224. initHeap_f(&H, vertex, index, dist, n);
  225. while (extractMax_f(&H, &closestVertex, index, dist)) {
  226. closestDist = dist[closestVertex];
  227. if (closestDist == FLT_MAX)
  228. break;
  229. for (size_t i = 1; i < graph[closestVertex].nedges; i++) {
  230. neighbor = graph[closestVertex].edges[i];
  231. increaseKey_f(&H, neighbor, closestDist + graph[closestVertex].ewgts[i],
  232. index, dist);
  233. }
  234. }
  235. freeHeap(&H);
  236. free(index);
  237. }
  238. // single source shortest paths that also builds terms as it goes
  239. // mostly copied from dijkstra_f above
  240. // returns the number of terms built
  241. int dijkstra_sgd(graph_sgd *graph, int source, term_sgd *terms) {
  242. heap h;
  243. int *indices = gv_calloc(graph->n, sizeof(int));
  244. float *dists = gv_calloc(graph->n, sizeof(float));
  245. for (size_t i= 0; i < graph->n; i++) {
  246. dists[i] = FLT_MAX;
  247. }
  248. dists[source] = 0;
  249. for (size_t i = graph->sources[source]; i < graph->sources[source + 1];
  250. i++) {
  251. size_t target = graph->targets[i];
  252. dists[target] = graph->weights[i];
  253. }
  254. assert(graph->n <= INT_MAX);
  255. initHeap_f(&h, source, indices, dists, (int)graph->n);
  256. int closest = 0, offset = 0;
  257. while (extractMax_f(&h, &closest, indices, dists)) {
  258. float d = dists[closest];
  259. if (d == FLT_MAX) {
  260. break;
  261. }
  262. // if the target is fixed then always create a term as shortest paths are not calculated from there
  263. // if not fixed then only create a term if the target index is lower
  264. if (bitarray_get(graph->pinneds, closest) || closest<source) {
  265. terms[offset].i = source;
  266. terms[offset].j = closest;
  267. terms[offset].d = d;
  268. terms[offset].w = 1 / (d*d);
  269. offset++;
  270. }
  271. for (size_t i = graph->sources[closest]; i < graph->sources[closest + 1];
  272. i++) {
  273. size_t target = graph->targets[i];
  274. float weight = graph->weights[i];
  275. assert(target <= (size_t)INT_MAX);
  276. increaseKey_f(&h, (int)target, d+weight, indices, dists);
  277. }
  278. }
  279. freeHeap(&h);
  280. free(indices);
  281. free(dists);
  282. return offset;
  283. }