hierarchy.c 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141
  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. // //
  12. // This file contains the functions //
  13. // for constructing and managing the //
  14. // hierarchy structure //
  15. // //
  16. ///////////////////////////////////////
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <math.h>
  21. #include <time.h>
  22. #include <assert.h>
  23. #include <common/arith.h>
  24. #include <topfish/hierarchy.h>
  25. #include <util/alloc.h>
  26. /////////////////////////
  27. // Some utilities for //
  28. // 'maxmatch(..)' //
  29. /////////////////////////
  30. static double
  31. unweighted_common_fraction(v_data * graph, int v, int u, float *v_vector)
  32. {
  33. // returns: |N(v) & N(u)| / |N(v) or N(u)|
  34. // v_vector[i]>0 <==> i is neighbor of v or is v itself
  35. int neighbor;
  36. int num_shared_neighbors = 0;
  37. int j;
  38. for (j = 0; j < graph[u].nedges; j++) {
  39. neighbor = graph[u].edges[j];
  40. if (v_vector[neighbor] > 0) {
  41. // a shared neighobr
  42. num_shared_neighbors++;
  43. }
  44. }
  45. // parallel to the weighted version:
  46. //return 2*num_shared_neighbors/(graph[v].nedges+graph[u].nedges);
  47. // more natural
  48. return ((double) num_shared_neighbors) / (graph[v].nedges +
  49. graph[u].nedges -
  50. num_shared_neighbors);
  51. }
  52. static void fill_neighbors_vec(v_data *graph, int vtx, float *vtx_vec) {
  53. int j;
  54. if (graph[0].ewgts != NULL) {
  55. for (j = 0; j < graph[vtx].nedges; j++) {
  56. vtx_vec[graph[vtx].edges[j]] = fabsf(graph[vtx].ewgts[j]); // use fabsf for the self loop
  57. }
  58. } else {
  59. for (j = 0; j < graph[vtx].nedges; j++) {
  60. vtx_vec[graph[vtx].edges[j]] = 1;
  61. }
  62. }
  63. }
  64. static void
  65. fill_neighbors_vec_unweighted(v_data * graph, int vtx, float *vtx_vec)
  66. {
  67. // a node is a neighbor of itself!
  68. int j;
  69. for (j = 0; j < graph[vtx].nedges; j++) {
  70. vtx_vec[graph[vtx].edges[j]] = 1;
  71. }
  72. }
  73. static void empty_neighbors_vec(v_data * graph, int vtx, float *vtx_vec)
  74. {
  75. int j;
  76. for (j = 0; j < graph[vtx].nedges; j++) {
  77. vtx_vec[graph[vtx].edges[j]] = 0;
  78. }
  79. }
  80. static int dist3(v_data * graph, int node1, int node2)
  81. {
  82. // succeeds if the graph theoretic distance between the nodes is no more than 3
  83. int i, j, k;
  84. int u, v;
  85. for (i = 1; i < graph[node1].nedges; i++) {
  86. u = graph[node1].edges[i];
  87. if (u == node2) {
  88. return 1;
  89. }
  90. for (j = 1; j < graph[u].nedges; j++) {
  91. v = graph[u].edges[j];
  92. if (v == node2) {
  93. return 1;
  94. }
  95. for (k = 1; k < graph[v].nedges; k++) {
  96. if (graph[v].edges[k] == node2) {
  97. return 1;
  98. }
  99. }
  100. }
  101. }
  102. return 0;
  103. }
  104. #define A 1.0
  105. #define B 1.0
  106. #define C 3.0
  107. #define D 1.0
  108. static double ddist(ex_vtx_data * geom_graph, int v, int u)
  109. {
  110. // Euclidean distance between nodes 'v' and 'u'
  111. double x_v = geom_graph[v].x_coord, y_v = geom_graph[v].y_coord,
  112. x_u = geom_graph[u].x_coord, y_u = geom_graph[u].y_coord;
  113. return hypot(x_v - x_u, y_v - y_u);
  114. }
  115. extern void quicksort_place(double *, int *, size_t size);
  116. static int
  117. maxmatch(v_data * graph, /* array of vtx data for graph */
  118. ex_vtx_data * geom_graph, /* array of vtx data for graph */
  119. int nvtxs, /* number of vertices in graph */
  120. int *mflag, /* flag indicating vtx selected or not */
  121. int dist2_limit
  122. )
  123. /*
  124. Compute a matching of the nodes set.
  125. The matching is not based only on the edge list of 'graph',
  126. which might be too small,
  127. but on the wider edge list of 'geom_graph' (which includes 'graph''s edges)
  128. We match nodes that are close both in the graph-theoretical sense and
  129. in the geometry sense (in the layout)
  130. */
  131. {
  132. int *order; /* random ordering of vertices */
  133. int *iptr, *jptr; /* loops through integer arrays */
  134. int vtx; /* vertex to process next */
  135. int neighbor; /* neighbor of a vertex */
  136. int nmerged = 0; /* number of edges in matching */
  137. int i, j; /* loop counters */
  138. float max_norm_edge_weight;
  139. double inv_size;
  140. double *matchability = gv_calloc(nvtxs, sizeof(double));
  141. double min_edge_len;
  142. double closest_val = -1, val;
  143. int closest_neighbor;
  144. float *vtx_vec = gv_calloc(nvtxs, sizeof(float));
  145. float *weighted_vtx_vec = gv_calloc(nvtxs, sizeof(float));
  146. // gather statistics, to enable normalizing the values
  147. double avg_edge_len = 0, avg_deg_2 = 0;
  148. int nedges = 0;
  149. for (i = 0; i < nvtxs; i++) {
  150. avg_deg_2 += graph[i].nedges;
  151. for (j = 1; j < graph[i].nedges; j++) {
  152. avg_edge_len += ddist(geom_graph, i, graph[i].edges[j]);
  153. nedges++;
  154. }
  155. }
  156. avg_edge_len /= nedges;
  157. avg_deg_2 /= nvtxs;
  158. avg_deg_2 *= avg_deg_2;
  159. // the normalized edge weight of edge <v,u> is defined as:
  160. // weight(<v,u>)/sqrt(size(v)*size(u))
  161. // Now we compute the maximal normalized weight
  162. if (graph[0].ewgts != NULL) {
  163. max_norm_edge_weight = -1;
  164. for (i = 0; i < nvtxs; i++) {
  165. inv_size = sqrt(1.0 / geom_graph[i].size);
  166. for (j = 1; j < graph[i].nedges; j++) {
  167. if (graph[i].ewgts[j] * inv_size /
  168. sqrt((float) geom_graph[graph[i].edges[j]].size) >
  169. max_norm_edge_weight) {
  170. max_norm_edge_weight =
  171. (float) (graph[i].ewgts[j] * inv_size /
  172. sqrt((double)
  173. geom_graph[graph[i].edges[j]].size));
  174. }
  175. }
  176. }
  177. } else {
  178. max_norm_edge_weight = 1;
  179. }
  180. /* Now determine the order of the vertices. */
  181. iptr = order = gv_calloc(nvtxs, sizeof(int));
  182. jptr = mflag;
  183. for (i = 0; i < nvtxs; i++) {
  184. *(iptr++) = i;
  185. *(jptr++) = -1;
  186. }
  187. // Option 2: sort the nodes beginning with the ones highly approriate for matching
  188. #ifdef DEBUG
  189. srand(0);
  190. #endif
  191. for (i = 0; i < nvtxs; i++) {
  192. vtx = order[i];
  193. matchability[vtx] = graph[vtx].nedges; // we less want to match high degree nodes
  194. matchability[vtx] += geom_graph[vtx].size; // we less want to match large sized nodes
  195. min_edge_len = 1e99;
  196. for (j = 1; j < graph[vtx].nedges; j++) {
  197. min_edge_len =
  198. MIN(min_edge_len,
  199. ddist(geom_graph, vtx,
  200. graph[vtx].edges[j]) / avg_edge_len);
  201. }
  202. matchability[vtx] += min_edge_len; // we less want to match distant nodes
  203. matchability[vtx] += ((double) rand()) / RAND_MAX; // add some randomness
  204. }
  205. quicksort_place(matchability, order, nvtxs);
  206. free(matchability);
  207. // Start determining the matched pairs
  208. for (i = 0; i < nvtxs; i++) {
  209. vtx_vec[i] = 0;
  210. }
  211. for (i = 0; i < nvtxs; i++) {
  212. weighted_vtx_vec[i] = 0;
  213. }
  214. // relative weights of the different criteria
  215. for (i = 0; i < nvtxs; i++) {
  216. vtx = order[i];
  217. if (mflag[vtx] >= 0) { /* already matched. */
  218. continue;
  219. }
  220. inv_size = sqrt(1.0 / geom_graph[vtx].size);
  221. fill_neighbors_vec(graph, vtx, weighted_vtx_vec);
  222. fill_neighbors_vec_unweighted(graph, vtx, vtx_vec);
  223. closest_neighbor = -1;
  224. /*
  225. We match node i with the "closest" neighbor, based on 4 criteria:
  226. (1) (Weighted) fraction of common neighbors (measured on orig. graph)
  227. (2) AvgDeg*AvgDeg/(deg(vtx)*deg(neighbor)) (degrees measured on orig. graph)
  228. (3) AvgEdgeLen/dist(vtx,neighbor)
  229. (4) Weight of normalized direct connection between nodes (measured on orig. graph)
  230. */
  231. for (j = 1; j < geom_graph[vtx].nedges; j++) {
  232. neighbor = geom_graph[vtx].edges[j];
  233. if (mflag[neighbor] >= 0) { /* already matched. */
  234. continue;
  235. }
  236. // (1):
  237. val =
  238. A * unweighted_common_fraction(graph, vtx, neighbor,
  239. vtx_vec);
  240. if (val == 0 && (dist2_limit || !dist3(graph, vtx, neighbor))) {
  241. // graph theoretical distance is larger than 3 (or 2 if '!dist3(graph, vtx, neighbor)' is commented)
  242. // nodes cannot be matched
  243. continue;
  244. }
  245. // (2)
  246. val +=
  247. B * avg_deg_2 / (graph[vtx].nedges *
  248. graph[neighbor].nedges);
  249. // (3)
  250. val += C * avg_edge_len / ddist(geom_graph, vtx, neighbor);
  251. // (4)
  252. val +=
  253. (weighted_vtx_vec[neighbor] * inv_size /
  254. sqrt((float) geom_graph[neighbor].size)) /
  255. max_norm_edge_weight;
  256. if (val > closest_val || closest_neighbor == -1) {
  257. closest_neighbor = neighbor;
  258. closest_val = val;
  259. }
  260. }
  261. if (closest_neighbor != -1) {
  262. mflag[vtx] = closest_neighbor;
  263. mflag[closest_neighbor] = vtx;
  264. nmerged++;
  265. }
  266. empty_neighbors_vec(graph, vtx, vtx_vec);
  267. empty_neighbors_vec(graph, vtx, weighted_vtx_vec);
  268. }
  269. free(order);
  270. free(vtx_vec);
  271. free(weighted_vtx_vec);
  272. return (nmerged);
  273. }
  274. /* Construct mapping from original graph nodes to coarsened graph nodes */
  275. static void makev2cv(int *mflag, /* flag indicating vtx selected or not */
  276. int nvtxs, /* number of vtxs in original graph */
  277. int *v2cv, /* mapping from vtxs to coarsened vtxs */
  278. int *cv2v /* mapping from coarsened vtxs to vtxs */
  279. )
  280. {
  281. int i, j; /* loop counters */
  282. j = 0;
  283. for (i = 0; i < nvtxs; i++) {
  284. if (mflag[i] < 0) { // unmatched node
  285. v2cv[i] = j;
  286. cv2v[2 * j] = i;
  287. cv2v[2 * j + 1] = -1;
  288. j++;
  289. } else if (mflag[i] > i) { // matched node
  290. v2cv[i] = j;
  291. v2cv[mflag[i]] = j;
  292. cv2v[2 * j] = i;
  293. cv2v[2 * j + 1] = mflag[i];
  294. j++;
  295. }
  296. }
  297. }
  298. static int make_coarse_graph(v_data * graph, /* array of vtx data for graph */
  299. int nedges, /* number of edges in graph */
  300. v_data ** cgp, /* coarsened version of graph */
  301. int cnvtxs, /* number of vtxs in coarsened graph */
  302. int *v2cv, /* mapping from vtxs to coarsened vtxs */
  303. int *cv2v /* mapping from coarsened vtxs to vtxs */
  304. )
  305. // This function takes the information about matched pairs
  306. // and use it to contract these pairs and build a coarse graph
  307. {
  308. int j, cv, v, neighbor, cv_nedges;
  309. int cnedges = 0; /* number of edges in coarsened graph */
  310. v_data *cgraph; /* coarsened version of graph */
  311. int *index = gv_calloc(cnvtxs, sizeof(int));
  312. float intra_weight;
  313. /* An upper bound on the number of coarse graph edges. */
  314. int maxCnedges = nedges; // do not subtract (nvtxs-cnvtxs) because we do not contract only along edges
  315. int *edges;
  316. float *eweights;
  317. /* Now allocate space for the new graph. Overeallocate and realloc later. */
  318. cgraph = gv_calloc(cnvtxs, sizeof(v_data));
  319. edges = gv_calloc(2 * maxCnedges + cnvtxs, sizeof(int));
  320. eweights = gv_calloc(2 * maxCnedges + cnvtxs, sizeof(float));
  321. if (graph[0].ewgts != NULL) {
  322. // use edge weights
  323. for (cv = 0; cv < cnvtxs; cv++) {
  324. intra_weight = 0;
  325. cgraph[cv].edges = edges;
  326. cgraph[cv].ewgts = eweights;
  327. cv_nedges = 1;
  328. v = cv2v[2 * cv];
  329. for (j = 1; j < graph[v].nedges; j++) {
  330. neighbor = v2cv[graph[v].edges[j]];
  331. if (neighbor == cv) {
  332. intra_weight = 2 * graph[v].ewgts[j]; // count both directions of the intra-edge
  333. continue;
  334. }
  335. if (index[neighbor] == 0) { // new neighbor
  336. index[neighbor] = cv_nedges;
  337. cgraph[cv].edges[cv_nedges] = neighbor;
  338. cgraph[cv].ewgts[cv_nedges] = graph[v].ewgts[j];
  339. cv_nedges++;
  340. } else {
  341. cgraph[cv].ewgts[index[neighbor]] += graph[v].ewgts[j];
  342. }
  343. }
  344. cgraph[cv].ewgts[0] = graph[v].ewgts[0];
  345. if ((v = cv2v[2 * cv + 1]) != -1) {
  346. for (j = 1; j < graph[v].nedges; j++) {
  347. neighbor = v2cv[graph[v].edges[j]];
  348. if (neighbor == cv)
  349. continue;
  350. if (index[neighbor] == 0) { // new neighbor
  351. index[neighbor] = cv_nedges;
  352. cgraph[cv].edges[cv_nedges] = neighbor;
  353. cgraph[cv].ewgts[cv_nedges] = graph[v].ewgts[j];
  354. cv_nedges++;
  355. } else {
  356. cgraph[cv].ewgts[index[neighbor]] +=
  357. graph[v].ewgts[j];
  358. }
  359. }
  360. cgraph[cv].ewgts[0] += graph[v].ewgts[0] + intra_weight;
  361. }
  362. cgraph[cv].nedges = cv_nedges;
  363. cgraph[cv].edges[0] = cv;
  364. edges += cv_nedges;
  365. eweights += cv_nedges;
  366. cnedges += cv_nedges;
  367. for (j = 1; j < cgraph[cv].nedges; j++)
  368. index[cgraph[cv].edges[j]] = 0;
  369. }
  370. } else { // fine graph is unweighted
  371. int internal_weight = 0;
  372. for (cv = 0; cv < cnvtxs; cv++) {
  373. cgraph[cv].edges = edges;
  374. cgraph[cv].ewgts = eweights;
  375. cv_nedges = 1;
  376. v = cv2v[2 * cv];
  377. for (j = 1; j < graph[v].nedges; j++) {
  378. neighbor = v2cv[graph[v].edges[j]];
  379. if (neighbor == cv) {
  380. internal_weight = 2;
  381. continue;
  382. }
  383. if (index[neighbor] == 0) { // new neighbor
  384. index[neighbor] = cv_nedges;
  385. cgraph[cv].edges[cv_nedges] = neighbor;
  386. cgraph[cv].ewgts[cv_nedges] = -1;
  387. cv_nedges++;
  388. } else {
  389. cgraph[cv].ewgts[index[neighbor]]--;
  390. }
  391. }
  392. cgraph[cv].ewgts[0] = (float) graph[v].edges[0]; // this is our trick to store the weights on the diag in an unweighted graph
  393. if ((v = cv2v[2 * cv + 1]) != -1) {
  394. for (j = 1; j < graph[v].nedges; j++) {
  395. neighbor = v2cv[graph[v].edges[j]];
  396. if (neighbor == cv)
  397. continue;
  398. if (index[neighbor] == 0) { // new neighbor
  399. index[neighbor] = cv_nedges;
  400. cgraph[cv].edges[cv_nedges] = neighbor;
  401. cgraph[cv].ewgts[cv_nedges] = -1;
  402. cv_nedges++;
  403. } else {
  404. cgraph[cv].ewgts[index[neighbor]]--;
  405. }
  406. }
  407. // we subtract the weight of the intra-edge that was counted twice
  408. cgraph[cv].ewgts[0] +=
  409. (float) graph[v].edges[0] - internal_weight;
  410. // In a case the edge weights are defined as positive:
  411. //cgraph[cv].ewgts[0] += (float) graph[v].edges[0]+internal_weight;
  412. }
  413. cgraph[cv].nedges = cv_nedges;
  414. cgraph[cv].edges[0] = cv;
  415. edges += cv_nedges;
  416. eweights += cv_nedges;
  417. cnedges += cv_nedges;
  418. for (j = 1; j < cgraph[cv].nedges; j++)
  419. index[cgraph[cv].edges[j]] = 0;
  420. }
  421. }
  422. cnedges -= cnvtxs;
  423. cnedges /= 2;
  424. free(index);
  425. *cgp = cgraph;
  426. return cnedges;
  427. }
  428. static int
  429. make_coarse_ex_graph (
  430. ex_vtx_data * graph, /* array of vtx data for graph */
  431. int nedges, /* number of edges in graph */
  432. ex_vtx_data ** cgp, /* coarsened version of graph */
  433. int cnvtxs, /* number of vtxs in coarsened graph */
  434. int *v2cv, /* mapping from vtxs to coarsened vtxs */
  435. int *cv2v /* mapping from coarsened vtxs to vtxs */
  436. )
  437. // This function takes the information about matched pairs
  438. // and use it to contract these pairs and build a coarse ex_graph
  439. {
  440. int cnedges; /* number of edges in coarsened graph */
  441. ex_vtx_data *cgraph; /* coarsened version of graph */
  442. int j, cv, v, neighbor, cv_nedges;
  443. int *index = gv_calloc(cnvtxs, sizeof(int));
  444. int *edges;
  445. /* An upper bound on the number of coarse graph edges. */
  446. cnedges = nedges;
  447. /* Now allocate space for the new graph. Overeallocate and realloc later. */
  448. cgraph = gv_calloc(cnvtxs, sizeof(ex_vtx_data));
  449. edges = gv_calloc(2 * cnedges + cnvtxs, sizeof(int));
  450. for (cv = 0; cv < cnvtxs; cv++) {
  451. cgraph[cv].edges = edges;
  452. cv_nedges = 1;
  453. v = cv2v[2 * cv];
  454. for (j = 1; j < graph[v].nedges; j++) {
  455. neighbor = v2cv[graph[v].edges[j]];
  456. if (neighbor == cv) {
  457. continue;
  458. }
  459. if (index[neighbor] == 0) { // new neighbor
  460. index[neighbor] = cv_nedges;
  461. cgraph[cv].edges[cv_nedges] = neighbor;
  462. cv_nedges++;
  463. }
  464. }
  465. cgraph[cv].size = graph[v].size;
  466. cgraph[cv].x_coord = graph[v].x_coord;
  467. cgraph[cv].y_coord = graph[v].y_coord;
  468. if ((v = cv2v[2 * cv + 1]) != -1) {
  469. for (j = 1; j < graph[v].nedges; j++) {
  470. neighbor = v2cv[graph[v].edges[j]];
  471. if (neighbor == cv)
  472. continue;
  473. if (index[neighbor] == 0) { // new neighbor
  474. index[neighbor] = cv_nedges;
  475. cgraph[cv].edges[cv_nedges] = neighbor;
  476. cv_nedges++;
  477. }
  478. }
  479. // compute new coord's as a weighted average of the old ones
  480. cgraph[cv].x_coord =
  481. (cgraph[cv].size * cgraph[cv].x_coord +
  482. graph[v].size * graph[v].x_coord) / (cgraph[cv].size +
  483. graph[v].size);
  484. cgraph[cv].y_coord =
  485. (cgraph[cv].size * cgraph[cv].y_coord +
  486. graph[v].size * graph[v].y_coord) / (cgraph[cv].size +
  487. graph[v].size);
  488. cgraph[cv].size += graph[v].size;
  489. }
  490. cgraph[cv].nedges = cv_nedges;
  491. cgraph[cv].edges[0] = cv;
  492. edges += cv_nedges;
  493. for (j = 1; j < cgraph[cv].nedges; j++)
  494. index[cgraph[cv].edges[j]] = 0;
  495. }
  496. free(index);
  497. *cgp = cgraph;
  498. return cnedges;
  499. }
  500. static void
  501. coarsen_match (
  502. v_data * graph, /* graph to be matched */
  503. ex_vtx_data* geom_graph, /* another graph (with coords) on the same nodes */
  504. int nvtxs, /* number of vertices in graph */
  505. int nedges, /* number of edges in graph */
  506. int geom_nedges, /* number of edges in geom_graph */
  507. v_data ** cgraph, /* coarsened version of graph */
  508. ex_vtx_data ** cgeom_graph, /* coarsened version of geom_graph */
  509. int *cnp, /* number of vtxs in coarsened graph */
  510. int *cnedges, /* number of edges in coarsened graph */
  511. int *cgeom_nedges, /* number of edges in coarsened geom_graph */
  512. int **v2cvp, /* reference from vertices to coarse vertices */
  513. int **cv2vp, /* reference from vertices to coarse vertices */
  514. int dist2_limit
  515. )
  516. /*
  517. * This function gets two graphs with the same node set and
  518. * constructs two corresponding coarsened graphs of about
  519. * half the size
  520. */
  521. {
  522. int *mflag; /* flag indicating vtx matched or not */
  523. int nmerged; /* number of edges contracted */
  524. int *v2cv; /* reference from vertices to coarse vertices */
  525. int *cv2v; /* reference from vertices to coarse vertices */
  526. int cnvtxs;
  527. /* Allocate and initialize space. */
  528. mflag = gv_calloc(nvtxs, sizeof(int));
  529. /* Find a maximal matching in the graphs */
  530. nmerged = maxmatch(graph, geom_graph, nvtxs, mflag, dist2_limit);
  531. /* Now construct coarser graph by contracting along matching edges. */
  532. /* Pairs of values in mflag array indicate matched vertices. */
  533. /* A negative value indicates that vertex is unmatched. */
  534. *cnp = cnvtxs = nvtxs - nmerged;
  535. *v2cvp = v2cv = gv_calloc(nvtxs, sizeof(int));
  536. *cv2vp = cv2v = gv_calloc(2 * cnvtxs, sizeof(int));
  537. makev2cv(mflag, nvtxs, v2cv, cv2v);
  538. free(mflag);
  539. *cnedges = make_coarse_graph(graph, nedges, cgraph, cnvtxs, v2cv, cv2v);
  540. *cgeom_nedges = make_coarse_ex_graph(geom_graph, geom_nedges, cgeom_graph,
  541. cnvtxs, v2cv, cv2v);
  542. }
  543. static v_data *cpGraph(v_data * graph, int n, int nedges)
  544. {
  545. float *ewgts = NULL;
  546. int i, j;
  547. if (graph == NULL || n == 0) {
  548. return NULL;
  549. }
  550. v_data *cpGraph = gv_calloc(n, sizeof(v_data));
  551. int *edges = gv_calloc(2 * nedges + n, sizeof(int));
  552. if (graph[0].ewgts != NULL) {
  553. ewgts = gv_calloc(2 * nedges + n, sizeof(float));
  554. }
  555. for (i = 0; i < n; i++) {
  556. cpGraph[i] = graph[i];
  557. cpGraph[i].edges = edges;
  558. cpGraph[i].ewgts = ewgts;
  559. for (j = 0; j < graph[i].nedges; j++) {
  560. edges[j] = graph[i].edges[j];
  561. }
  562. edges += graph[i].nedges;
  563. if (ewgts != NULL) {
  564. for (j = 0; j < graph[i].nedges; j++) {
  565. ewgts[j] = graph[i].ewgts[j];
  566. }
  567. ewgts += graph[i].nedges;
  568. }
  569. }
  570. return cpGraph;
  571. }
  572. static ex_vtx_data *cpExGraph(ex_vtx_data * graph, int n, int nedges)
  573. {
  574. int i, j;
  575. if (graph == NULL || n == 0) {
  576. return NULL;
  577. }
  578. ex_vtx_data *cpGraph = gv_calloc(n, sizeof(ex_vtx_data));
  579. int *edges = gv_calloc(2 * nedges + n, sizeof(int));
  580. for (i = 0; i < n; i++) {
  581. cpGraph[i] = graph[i];
  582. cpGraph[i].edges = edges;
  583. for (j = 0; j < graph[i].nedges; j++) {
  584. edges[j] = graph[i].edges[j];
  585. }
  586. edges += graph[i].nedges;
  587. }
  588. return cpGraph;
  589. }
  590. Hierarchy *create_hierarchy(v_data * graph, int nvtxs, int nedges,
  591. ex_vtx_data * geom_graph, int ngeom_edges,
  592. hierparms_t* parms)
  593. {
  594. int cur_level;
  595. Hierarchy *hierarchy = gv_alloc(sizeof(Hierarchy));
  596. int cngeom_edges = ngeom_edges;
  597. ex_vtx_data *geom_graph_level;
  598. int nodeIndex = 0;
  599. int i, j;
  600. static const int min_nvtxs = 20;
  601. int nlevels = MAX(5, 10 * (int) log((float) (nvtxs / min_nvtxs))); // just an estimate
  602. hierarchy->graphs = gv_calloc(nlevels, sizeof(v_data*));
  603. hierarchy->geom_graphs = gv_calloc(nlevels, sizeof(ex_vtx_data*));
  604. hierarchy->nvtxs = gv_calloc(nlevels, sizeof(int));
  605. hierarchy->nedges = gv_calloc(nlevels, sizeof(int));
  606. hierarchy->v2cv = gv_calloc(nlevels, sizeof(int*));
  607. hierarchy->cv2v = gv_calloc(nlevels, sizeof(int*));
  608. hierarchy->graphs[0] = cpGraph(graph, nvtxs, nedges);
  609. hierarchy->geom_graphs[0] = cpExGraph(geom_graph, nvtxs, ngeom_edges);
  610. hierarchy->nvtxs[0] = nvtxs;
  611. hierarchy->nedges[0] = nedges;
  612. for (cur_level = 0;
  613. hierarchy->nvtxs[cur_level] > min_nvtxs
  614. && cur_level < 50 /*nvtxs/10 */ ; cur_level++) {
  615. if (cur_level == nlevels - 1) { // we have to allocate more space
  616. hierarchy->graphs =
  617. gv_recalloc(hierarchy->graphs, nlevels, nlevels * 2, sizeof(v_data*));
  618. hierarchy->geom_graphs =
  619. gv_recalloc(hierarchy->geom_graphs, nlevels, nlevels * 2, sizeof(ex_vtx_data*));
  620. hierarchy->nvtxs = gv_recalloc(hierarchy->nvtxs, nlevels, nlevels * 2, sizeof(int));
  621. hierarchy->nedges = gv_recalloc(hierarchy->nedges, nlevels, nlevels * 2, sizeof(int));
  622. hierarchy->v2cv = gv_recalloc(hierarchy->v2cv, nlevels, nlevels * 2, sizeof(int*));
  623. hierarchy->cv2v = gv_recalloc(hierarchy->cv2v, nlevels, nlevels * 2, sizeof(int*));
  624. nlevels *= 2;
  625. }
  626. ngeom_edges = cngeom_edges;
  627. coarsen_match
  628. (hierarchy->graphs[cur_level],
  629. hierarchy->geom_graphs[cur_level],
  630. hierarchy->nvtxs[cur_level], hierarchy->nedges[cur_level],
  631. ngeom_edges, &hierarchy->graphs[cur_level + 1],
  632. &hierarchy->geom_graphs[cur_level + 1],
  633. &hierarchy->nvtxs[cur_level + 1],
  634. &hierarchy->nedges[cur_level + 1], &cngeom_edges,
  635. &hierarchy->v2cv[cur_level], &hierarchy->cv2v[cur_level + 1],
  636. parms->dist2_limit);
  637. }
  638. hierarchy->nlevels = cur_level + 1;
  639. // assign consecutive global identifiers to all nodes on hierarchy
  640. for (i = 0; i < hierarchy->nlevels; i++) {
  641. geom_graph_level = hierarchy->geom_graphs[i];
  642. for (j = 0; j < hierarchy->nvtxs[i]; j++) {
  643. geom_graph_level[j].globalIndex = nodeIndex;
  644. nodeIndex++;
  645. }
  646. }
  647. hierarchy->maxNodeIndex = nodeIndex;
  648. return hierarchy;
  649. }
  650. static double
  651. dist_from_foci(ex_vtx_data * graph, int node, int *foci, int num_foci)
  652. {
  653. // compute minimum distance of 'node' from the set 'foci'
  654. int i;
  655. double distance = ddist(graph, node, foci[0]);
  656. for (i = 1; i < num_foci; i++) {
  657. distance = MIN(distance, ddist(graph, node, foci[i]));
  658. }
  659. return distance;
  660. }
  661. /* set_active_levels:
  662. * Compute the "active level" field of each node in the hierarchy.
  663. * Note that if the active level is lower than the node's level, the node
  664. * is "split" in the presentation; if the active level is higher than
  665. * the node's level, then the node is aggregated into a coarser node.
  666. * If the active level equals the node's level then the node is currently shown
  667. */
  668. void
  669. set_active_levels(Hierarchy * hierarchy, int *foci_nodes, int num_foci,
  670. levelparms_t* parms)
  671. {
  672. int n, i;
  673. int *nodes;
  674. double *distances;
  675. ex_vtx_data *graph;
  676. int level;
  677. int group_size;
  678. int thresh;
  679. int vtx;
  680. ex_vtx_data *cgraph;
  681. int *cv2v;
  682. int v, u;
  683. int min_level = 0;
  684. graph = hierarchy->geom_graphs[min_level]; // finest graph
  685. n = hierarchy->nvtxs[min_level];
  686. // compute distances from foci nodes
  687. nodes = gv_calloc(n, sizeof(int));
  688. distances = gv_calloc(n, sizeof(double));
  689. for (i = 0; i < n; i++) {
  690. nodes[i] = i;
  691. distances[i] = dist_from_foci(graph, i, foci_nodes, num_foci);
  692. }
  693. // sort nodes according to their distance from foci
  694. quicksort_place(distances, nodes, n);
  695. /* compute *desired* levels of fine nodes by distributing them into buckets
  696. * The sizes of the buckets is a geometric series with
  697. * factor: 'coarsening_rate'
  698. */
  699. level = min_level;
  700. group_size = parms->num_fine_nodes * num_foci;
  701. thresh = group_size;
  702. for (i = 0; i < n; i++) {
  703. vtx = nodes[i];
  704. if (i > thresh && level < hierarchy->nlevels - 1) {
  705. level++;
  706. group_size = (int) (group_size * parms->coarsening_rate);
  707. thresh += group_size;
  708. }
  709. graph[vtx].active_level = level;
  710. }
  711. // Fine-to-coarse sweep:
  712. //----------------------
  713. // Propagate levels to all coarse nodes and determine final levels
  714. // at lowest meeting points. Note that nodes can be active in
  715. // lower (finer) levels than what originally desired, since if 'u'
  716. // and 'v' are merged, than the active level of '{u,v}' will be
  717. // the minimum of the active levels of 'u' and 'v'
  718. for (level = min_level + 1; level < hierarchy->nlevels; level++) {
  719. cgraph = hierarchy->geom_graphs[level];
  720. graph = hierarchy->geom_graphs[level - 1];
  721. cv2v = hierarchy->cv2v[level];
  722. n = hierarchy->nvtxs[level];
  723. for (i = 0; i < n; i++) {
  724. v = cv2v[2 * i];
  725. u = cv2v[2 * i + 1];
  726. if (u >= 0) { // cv is decomposed from 2 fine nodes
  727. if (graph[v].active_level < level
  728. || graph[u].active_level < level) {
  729. // At least one of the nodes should be active at a lower level,
  730. // in this case both children are active at a lower level
  731. // and we don't wait till they are merged
  732. graph[v].active_level =
  733. MIN(graph[v].active_level, level - 1);
  734. graph[u].active_level =
  735. MIN(graph[u].active_level, level - 1);
  736. }
  737. // The node with the finer (lower) active level determines the coarse active level
  738. cgraph[i].active_level =
  739. MIN(graph[v].active_level, graph[u].active_level);
  740. } else {
  741. cgraph[i].active_level = graph[v].active_level;
  742. }
  743. }
  744. }
  745. // Coarse-to-fine sweep:
  746. //----------------------
  747. // Propagate final levels all the way to fine nodes
  748. for (level = hierarchy->nlevels - 1; level > 0; level--) {
  749. cgraph = hierarchy->geom_graphs[level];
  750. graph = hierarchy->geom_graphs[level - 1];
  751. cv2v = hierarchy->cv2v[level];
  752. n = hierarchy->nvtxs[level];
  753. for (i = 0; i < n; i++) {
  754. if (cgraph[i].active_level < level) {
  755. continue;
  756. }
  757. // active level has been already reached, copy level to children
  758. v = cv2v[2 * i];
  759. u = cv2v[2 * i + 1];
  760. graph[v].active_level = cgraph[i].active_level;
  761. if (u >= 0) {
  762. graph[u].active_level = cgraph[i].active_level;
  763. }
  764. }
  765. }
  766. free(nodes);
  767. free(distances);
  768. }
  769. /* findClosestActiveNode:
  770. * Given (x,y) in physical coords, check if node is closer to this point
  771. * than previous setting. If so, reset values.
  772. * If node is not active, recurse down finer levels.
  773. * Return closest distance squared.
  774. */
  775. static double
  776. findClosestActiveNode(Hierarchy * hierarchy, int node,
  777. int level, double x, double y,
  778. double closest_dist, int *closest_node,
  779. int *closest_node_level)
  780. {
  781. ex_vtx_data *graph;
  782. graph = hierarchy->geom_graphs[level];
  783. if (graph[node].active_level == level)
  784. { // node is active
  785. double delx = x - graph[node].physical_x_coord;
  786. double dely = y - graph[node].physical_y_coord;
  787. double dist = delx*delx + dely*dely;
  788. if (dist < closest_dist)
  789. {
  790. closest_dist = dist;
  791. *closest_node = node;
  792. *closest_node_level = level;
  793. }
  794. return closest_dist;
  795. }
  796. closest_dist =
  797. findClosestActiveNode(hierarchy, hierarchy->cv2v[level][2 * node],
  798. level - 1, x, y, closest_dist, closest_node,
  799. closest_node_level);
  800. if (hierarchy->cv2v[level][2 * node + 1] >= 0) {
  801. closest_dist =
  802. findClosestActiveNode(hierarchy,
  803. hierarchy->cv2v[level][2 * node + 1],
  804. level - 1, x, y, closest_dist,
  805. closest_node, closest_node_level);
  806. }
  807. return closest_dist;
  808. }
  809. /* find_leftmost_descendant:
  810. * Given coarse node in given level, return representative node
  811. * in lower level cur_level.
  812. */
  813. static int
  814. find_leftmost_descendant(Hierarchy * hierarchy, int node, int level,
  815. int cur_level)
  816. {
  817. while (level > cur_level)
  818. {
  819. node = hierarchy->cv2v[level--][2 * node];
  820. }
  821. return node;
  822. }
  823. /* find_closest_active_node:
  824. * Given x and y in physical coordinate system, determine closest
  825. * actual node in graph. Store this in closest_fine_node, and return
  826. * distance squared.
  827. */
  828. double
  829. find_closest_active_node(Hierarchy * hierarchy, double x, double y,
  830. int *closest_fine_node)
  831. {
  832. int i, closest_node, closest_node_level;
  833. int top_level = hierarchy->nlevels - 1;
  834. double min_dist = 1e20;
  835. for (i = 0; i < hierarchy->nvtxs[top_level]; i++)
  836. {
  837. min_dist = findClosestActiveNode(hierarchy, i, top_level, x, y,min_dist, &closest_node, &closest_node_level);
  838. }
  839. *closest_fine_node =find_leftmost_descendant(hierarchy, closest_node,closest_node_level, 0);
  840. return min_dist;
  841. }
  842. int
  843. init_ex_graph(v_data * graph1, v_data * graph2, int n,
  844. double *x_coords, double *y_coords, ex_vtx_data ** gp)
  845. {
  846. // build ex_graph from the union of edges in 'graph1' and 'graph2'
  847. // note that this function does not destroy the input graphs
  848. ex_vtx_data *geom_graph;
  849. int nedges1 = 0, nedges2 = 0;
  850. int nedges = 0;
  851. int i, j, k, l, first_nedges;
  852. int neighbor;
  853. for (i = 0; i < n; i++) {
  854. nedges1 += graph1[i].nedges;
  855. nedges2 += graph2[i].nedges;
  856. }
  857. int *edges = gv_calloc(nedges1 + nedges2, sizeof(int));
  858. *gp = geom_graph = gv_calloc(n, sizeof(ex_vtx_data));
  859. for (i = 0; i < n; i++) {
  860. geom_graph[i].edges = edges;
  861. geom_graph[i].size = 1;
  862. geom_graph[i].x_coord = (float) x_coords[i];
  863. geom_graph[i].y_coord = (float) y_coords[i];
  864. geom_graph[i].edges[0] = i;
  865. for (j = 1; j < graph1[i].nedges; j++) {
  866. edges[j] = graph1[i].edges[j];
  867. }
  868. first_nedges = k = graph1[i].nedges;
  869. for (j = 1; j < graph2[i].nedges; j++) {
  870. neighbor = graph2[i].edges[j];
  871. for (l = 1; l < first_nedges; l++) {
  872. if (edges[l] == neighbor) { // already existed neighbor
  873. break;
  874. }
  875. }
  876. if (l == first_nedges) { // neighbor wasn't found
  877. edges[k++] = neighbor;
  878. }
  879. }
  880. geom_graph[i].nedges = k;
  881. edges += k;
  882. nedges += k;
  883. }
  884. nedges /= 2;
  885. return nedges;
  886. }
  887. /* extract_active_logical_coords:
  888. * Preorder scan the hierarchy tree, and extract the logical coordinates of
  889. * all active nodes
  890. * Store (universal) coords in x_coords and y_coords and increment index.
  891. * Return index.
  892. */
  893. size_t extract_active_logical_coords(Hierarchy *hierarchy, int node, int level,
  894. double *x_coords, double *y_coords,
  895. size_t counter) {
  896. ex_vtx_data *graph = hierarchy->geom_graphs[level];
  897. if (graph[node].active_level == level) { // node is active
  898. x_coords[counter] = graph[node].x_coord;
  899. y_coords[counter++] = graph[node].y_coord;
  900. return counter;
  901. }
  902. counter =
  903. extract_active_logical_coords(hierarchy,
  904. hierarchy->cv2v[level][2 * node],
  905. level - 1, x_coords, y_coords,
  906. counter);
  907. if (hierarchy->cv2v[level][2 * node + 1] >= 0) {
  908. counter =
  909. extract_active_logical_coords(hierarchy,
  910. hierarchy->cv2v[level][2 * node +
  911. 1],
  912. level - 1, x_coords, y_coords,
  913. counter);
  914. }
  915. return counter;
  916. }
  917. /* set_active_physical_coords:
  918. * Preorder scan the hierarchy tree, and set the physical coordinates
  919. * of all active nodes
  920. */
  921. int
  922. set_active_physical_coords(Hierarchy * hierarchy, int node, int level,
  923. double *x_coords, double *y_coords, int counter)
  924. {
  925. ex_vtx_data *graph = hierarchy->geom_graphs[level];
  926. if (graph[node].active_level == level) { // node is active
  927. graph[node].physical_x_coord = (float) x_coords[counter];
  928. graph[node].physical_y_coord = (float) y_coords[counter++];
  929. return counter;
  930. }
  931. counter =
  932. set_active_physical_coords(hierarchy,
  933. hierarchy->cv2v[level][2*node],
  934. level - 1, x_coords, y_coords, counter);
  935. if (hierarchy->cv2v[level][2 * node + 1] >= 0) {
  936. counter =
  937. set_active_physical_coords(hierarchy,
  938. hierarchy->cv2v[level][2*node + 1],
  939. level - 1, x_coords, y_coords,
  940. counter);
  941. }
  942. return counter;
  943. }
  944. /* find_physical_coords:
  945. * find the 'physical_coords' of the active-ancestor of 'node'
  946. */
  947. void
  948. find_physical_coords(Hierarchy * hierarchy, int level, int node, double *x,
  949. double *y)
  950. {
  951. int active_level = hierarchy->geom_graphs[level][node].active_level;
  952. while (active_level > level) {
  953. node = hierarchy->v2cv[level][node];
  954. level++;
  955. }
  956. *x = hierarchy->geom_graphs[level][node].physical_x_coord;
  957. *y = hierarchy->geom_graphs[level][node].physical_y_coord;
  958. }
  959. void
  960. find_active_ancestor_info(Hierarchy * hierarchy, int level, int node, int *levell,int *nodee)
  961. {
  962. int active_level = hierarchy->geom_graphs[level][node].active_level;
  963. while (active_level > level) {
  964. node = hierarchy->v2cv[level][node];
  965. level++;
  966. }
  967. *nodee = node;
  968. *levell = level;
  969. }
  970. /* find_old_physical_coords:
  971. * find the 'old_physical_coords' of the old active-ancestor of 'node'
  972. */
  973. void
  974. find_old_physical_coords(Hierarchy * hierarchy, int level, int node, double *x,
  975. double *y)
  976. {
  977. int active_level = hierarchy->geom_graphs[level][node].old_active_level;
  978. while (active_level > level) {
  979. node = hierarchy->v2cv[level][node];
  980. level++;
  981. }
  982. *x = hierarchy->geom_graphs[level][node].old_physical_x_coord;
  983. *y = hierarchy->geom_graphs[level][node].old_physical_y_coord;
  984. }
  985. /* find_active_ancestor:
  986. * find the 'ancestorIndex' of the active-ancestor of 'node'
  987. * Return negative if node's active_level < level.
  988. */
  989. int
  990. find_active_ancestor(Hierarchy * hierarchy, int level, int node)
  991. {
  992. int active_level = hierarchy->geom_graphs[level][node].active_level;
  993. while (active_level > level) {
  994. node = hierarchy->v2cv[level][node];
  995. level++;
  996. }
  997. if (active_level == level)
  998. return hierarchy->geom_graphs[level][node].globalIndex;
  999. else
  1000. return -1;
  1001. }
  1002. void init_active_level(Hierarchy* hierarchy, int level)
  1003. {
  1004. int i,j;
  1005. ex_vtx_data* graph;
  1006. for (i=0; i<hierarchy->nlevels; i++) {
  1007. graph = hierarchy->geom_graphs[i];
  1008. for (j=0; j<hierarchy->nvtxs[i]; j++) {
  1009. graph->active_level = level;
  1010. graph++;
  1011. }
  1012. }
  1013. }