quad_prog_solve.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  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. #include <cgraph/list.h>
  11. #include <neatogen/digcola.h>
  12. #include <stdint.h>
  13. #include <util/alloc.h>
  14. #ifdef DIGCOLA
  15. #include <math.h>
  16. #include <stdbool.h>
  17. #include <stdlib.h>
  18. #include <time.h>
  19. #include <stdio.h>
  20. #include <float.h>
  21. #include <assert.h>
  22. #include <neatogen/matrix_ops.h>
  23. #include <neatogen/kkutils.h>
  24. #include <neatogen/quad_prog_solver.h>
  25. /// are two values equal, within a reasonable tolerance?
  26. static bool equals(float a, float b) {
  27. const float TOLERANCE = 1e-2;
  28. return fabsf(a - b) < TOLERANCE;
  29. }
  30. float **unpackMatrix(float *packedMat, int n)
  31. {
  32. int i, j, k;
  33. float **mat = gv_calloc(n, sizeof(float *));
  34. mat[0] = gv_calloc(n * n, sizeof(float));
  35. set_vector_valf(n * n, 0, mat[0]);
  36. for (i = 1; i < n; i++) {
  37. mat[i] = mat[0] + i * n;
  38. }
  39. for (i = 0, k = 0; i < n; i++) {
  40. for (j = i; j < n; j++, k++) {
  41. mat[j][i] = mat[i][j] = packedMat[k];
  42. }
  43. }
  44. return mat;
  45. }
  46. static void
  47. ensureMonotonicOrderingWithGaps(float *place, int n, int *ordering,
  48. int *levels, int num_levels,
  49. float levels_gap)
  50. {
  51. /* ensure that levels are separated in the initial layout and that
  52. * places are monotonic increasing within layer
  53. */
  54. int i;
  55. int node, level, max_in_level;
  56. float lower_bound = -1e9f;
  57. level = -1;
  58. max_in_level = 0;
  59. for (i = 0; i < n; i++) {
  60. if (i >= max_in_level) {
  61. /* we are entering a new level */
  62. level++;
  63. if (level == num_levels) {
  64. /* last_level */
  65. max_in_level = n;
  66. } else {
  67. max_in_level = levels[level];
  68. }
  69. lower_bound =
  70. i > 0 ? place[ordering[i - 1]] + levels_gap : -1e9f;
  71. quicksort_placef(place, ordering, i, max_in_level - 1);
  72. }
  73. node = ordering[i];
  74. if (place[node] < lower_bound) {
  75. place[node] = lower_bound;
  76. }
  77. }
  78. }
  79. DEFINE_LIST(ints, int)
  80. void
  81. constrained_majorization_new_with_gaps(CMajEnv * e, float *b,
  82. float **coords,
  83. int cur_axis, int max_iterations,
  84. float levels_gap)
  85. {
  86. float *place = coords[cur_axis];
  87. int n = e->n;
  88. float **lap = e->A;
  89. int *ordering = e->ordering;
  90. int *levels = e->levels;
  91. int num_levels = e->num_levels;
  92. float new_place_i;
  93. bool converged = false;
  94. float upper_bound, lower_bound;
  95. int node;
  96. int left, right;
  97. float cur_place;
  98. float des_place_block;
  99. float block_deg;
  100. float toBlockConnectivity;
  101. float *lap_node;
  102. float *desired_place;
  103. float *prefix_desired_place;
  104. float *suffix_desired_place;
  105. int first_next_level;
  106. int level = -1, max_in_level = 0;
  107. float *gap;
  108. float target_place;
  109. if (max_iterations <= 0) {
  110. return;
  111. }
  112. ensureMonotonicOrderingWithGaps(place, n, ordering, levels, num_levels,
  113. levels_gap);
  114. /* it is important that in 'ordering' nodes are always sorted by layers,
  115. * and within a layer by 'place'
  116. */
  117. /* the desired place of each individual node in the current block */
  118. desired_place = e->fArray1;
  119. /* the desired place of each prefix of current block */
  120. prefix_desired_place = e->fArray2;
  121. /* the desired place of each suffix of current block */
  122. suffix_desired_place = e->fArray3;
  123. /* current block (nodes connected by active constraints) */
  124. ints_t block = {0};
  125. int *lev = gv_calloc(n, sizeof(int)); // level of each node
  126. for (int i = 0; i < n; i++) {
  127. if (i >= max_in_level) {
  128. /* we are entering a new level */
  129. level++;
  130. if (level == num_levels) {
  131. /* last_level */
  132. max_in_level = n;
  133. } else {
  134. max_in_level = levels[level];
  135. }
  136. }
  137. node = ordering[i];
  138. lev[node] = level;
  139. }
  140. /* displacement of block's nodes from block's reference point */
  141. gap = e->fArray4;
  142. for (int counter = 0; counter < max_iterations && !converged; counter++) {
  143. converged = true;
  144. lower_bound = -1e9; /* no lower bound for first level */
  145. for (left = 0; left < n; left = right) {
  146. double max_movement;
  147. double movement;
  148. float prefix_des_place, suffix_des_place;
  149. /* compute a block 'ordering[left]...ordering[right-1]' of
  150. * nodes connected with active constraints
  151. */
  152. cur_place = place[ordering[left]];
  153. target_place = cur_place;
  154. gap[ordering[left]] = 0;
  155. for (right = left + 1; right < n; right++) {
  156. if (lev[right] > lev[right - 1]) {
  157. /* we are entering a new level */
  158. target_place += levels_gap; /* note that 'levels_gap' may be negative */
  159. }
  160. node = ordering[right];
  161. /* not sure if this is better than 'place[node]!=target_place' */
  162. if (fabs(place[node] - target_place) > 1e-9) {
  163. break;
  164. }
  165. gap[node] = place[node] - cur_place;
  166. }
  167. /* compute desired place of block's reference point according
  168. * to each node in the block:
  169. */
  170. for (int i = left; i < right; i++) {
  171. node = ordering[i];
  172. new_place_i = -b[node];
  173. lap_node = lap[node];
  174. for (int j = 0; j < n; j++) {
  175. if (j == node) {
  176. continue;
  177. }
  178. new_place_i += lap_node[j] * place[j];
  179. }
  180. desired_place[node] =
  181. new_place_i / (-lap_node[node]) - gap[node];
  182. }
  183. /* reorder block by levels, and within levels
  184. * by "relaxed" desired position
  185. */
  186. ints_clear(&block);
  187. first_next_level = 0;
  188. for (int i = left; i < right; i = first_next_level) {
  189. level = lev[ordering[i]];
  190. if (level == num_levels) {
  191. /* last_level */
  192. first_next_level = right;
  193. } else {
  194. first_next_level = MIN(right, levels[level]);
  195. }
  196. /* First, collect all nodes with desired places smaller
  197. * than current place
  198. */
  199. for (int j = i; j < first_next_level; j++) {
  200. node = ordering[j];
  201. if (desired_place[node] < cur_place) {
  202. ints_append(&block, node);
  203. }
  204. }
  205. /* Second, collect all nodes with desired places equal
  206. * to current place
  207. */
  208. for (int j = i; j < first_next_level; j++) {
  209. node = ordering[j];
  210. if (desired_place[node] == cur_place) {
  211. ints_append(&block, node);
  212. }
  213. }
  214. /* Third, collect all nodes with desired places greater
  215. * than current place
  216. */
  217. for (int j = i; j < first_next_level; j++) {
  218. node = ordering[j];
  219. if (desired_place[node] > cur_place) {
  220. ints_append(&block, node);
  221. }
  222. }
  223. }
  224. /* loop through block and compute desired places of its prefixes */
  225. des_place_block = 0;
  226. block_deg = 0;
  227. for (size_t i = 0; i < ints_size(&block); i++) {
  228. node = ints_get(&block, i);
  229. toBlockConnectivity = 0;
  230. lap_node = lap[node];
  231. for (size_t j = 0; j < i; j++) {
  232. toBlockConnectivity -= lap_node[ints_get(&block, j)];
  233. }
  234. toBlockConnectivity *= 2;
  235. /* update block stats */
  236. des_place_block =
  237. (block_deg * des_place_block +
  238. (-lap_node[node]) * desired_place[node] +
  239. toBlockConnectivity * cur_place) / (block_deg -
  240. lap_node[node] +
  241. toBlockConnectivity);
  242. prefix_desired_place[i] = des_place_block;
  243. block_deg += toBlockConnectivity - lap_node[node];
  244. }
  245. if (n >= 0 && ints_size(&block) == (size_t)n) {
  246. /* fix is needed since denominator was 0 in this case */
  247. prefix_desired_place[n - 1] = cur_place; /* a "neutral" value */
  248. }
  249. /* loop through block and compute desired places of its suffixes */
  250. des_place_block = 0;
  251. block_deg = 0;
  252. for (size_t i = ints_size(&block) - 1; i != SIZE_MAX; i--) {
  253. node = ints_get(&block, i);
  254. toBlockConnectivity = 0;
  255. lap_node = lap[node];
  256. for (size_t j = i + 1; j < ints_size(&block); j++) {
  257. toBlockConnectivity -= lap_node[ints_get(&block, j)];
  258. }
  259. toBlockConnectivity *= 2;
  260. /* update block stats */
  261. des_place_block =
  262. (block_deg * des_place_block +
  263. (-lap_node[node]) * desired_place[node] +
  264. toBlockConnectivity * cur_place) / (block_deg -
  265. lap_node[node] +
  266. toBlockConnectivity);
  267. suffix_desired_place[i] = des_place_block;
  268. block_deg += toBlockConnectivity - lap_node[node];
  269. }
  270. if (n >= 0 && ints_size(&block) == (size_t)n) {
  271. /* fix is needed since denominator was 0 in this case */
  272. suffix_desired_place[0] = cur_place; /* a "neutral" value? */
  273. }
  274. /* now, find best place to split block */
  275. size_t best_i = SIZE_MAX;
  276. max_movement = 0;
  277. for (size_t i = 0; i < ints_size(&block); i++) {
  278. suffix_des_place = suffix_desired_place[i];
  279. prefix_des_place =
  280. i > 0 ? prefix_desired_place[i - 1] : suffix_des_place;
  281. /* limit moves to ensure that the prefix is placed before the suffix */
  282. if (suffix_des_place < prefix_des_place) {
  283. if (suffix_des_place < cur_place) {
  284. if (prefix_des_place > cur_place) {
  285. prefix_des_place = cur_place;
  286. }
  287. suffix_des_place = prefix_des_place;
  288. } else if (prefix_des_place > cur_place) {
  289. prefix_des_place = suffix_des_place;
  290. }
  291. }
  292. movement =
  293. (float)(ints_size(&block) - i) * fabs(suffix_des_place - cur_place) +
  294. (float)i * fabs(prefix_des_place - cur_place);
  295. if (movement > max_movement) {
  296. max_movement = movement;
  297. best_i = i;
  298. }
  299. }
  300. /* Actually move prefix and suffix */
  301. if (best_i != SIZE_MAX) {
  302. suffix_des_place = suffix_desired_place[best_i];
  303. prefix_des_place =
  304. best_i >
  305. 0 ? prefix_desired_place[best_i -
  306. 1] : suffix_des_place;
  307. /* compute right border of feasible move */
  308. if (right >= n) {
  309. /* no nodes after current block */
  310. upper_bound = 1e9;
  311. } else {
  312. /* notice that we have to deduct 'gap[block[block_len-1]]'
  313. * since all computations should be relative to
  314. * the block's reference point
  315. */
  316. if (lev[ordering[right]] > lev[ordering[right - 1]]) {
  317. upper_bound =
  318. place[ordering[right]] - levels_gap -
  319. gap[ints_get(&block, ints_size(&block) - 1)];
  320. } else {
  321. upper_bound =
  322. place[ordering[right]] -
  323. gap[ints_get(&block, ints_size(&block) - 1)];
  324. }
  325. }
  326. suffix_des_place = fminf(suffix_des_place, upper_bound);
  327. prefix_des_place = fmaxf(prefix_des_place, lower_bound);
  328. /* limit moves to ensure that the prefix is placed before the suffix */
  329. if (suffix_des_place < prefix_des_place) {
  330. if (suffix_des_place < cur_place) {
  331. if (prefix_des_place > cur_place) {
  332. prefix_des_place = cur_place;
  333. }
  334. suffix_des_place = prefix_des_place;
  335. } else if (prefix_des_place > cur_place) {
  336. prefix_des_place = suffix_des_place;
  337. }
  338. }
  339. /* move prefix: */
  340. for (size_t i = 0; i < best_i; i++) {
  341. place[ints_get(&block, i)] = prefix_des_place + gap[ints_get(&block, i)];
  342. }
  343. /* move suffix: */
  344. for (size_t i = best_i; i < ints_size(&block); i++) {
  345. place[ints_get(&block, i)] = suffix_des_place + gap[ints_get(&block, i)];
  346. }
  347. /* compute lower bound for next block */
  348. if (right < n
  349. && lev[ordering[right]] > lev[ordering[right - 1]]) {
  350. lower_bound = place[ints_get(&block, ints_size(&block) - 1)] + levels_gap;
  351. } else {
  352. lower_bound = place[ints_get(&block, ints_size(&block) - 1)];
  353. }
  354. /* reorder 'ordering' to reflect change of places
  355. * Note that it is enough to reorder the level where
  356. * the split was done
  357. */
  358. for (int i = left; i < right; i++) {
  359. ordering[i] = ints_get(&block, i - (size_t)left);
  360. }
  361. converged &= equals(prefix_des_place, cur_place)
  362. && equals(suffix_des_place, cur_place);
  363. } else {
  364. /* no movement */
  365. /* compute lower bound for next block */
  366. if (right < n
  367. && lev[ordering[right]] > lev[ordering[right - 1]]) {
  368. lower_bound = place[ints_get(&block, ints_size(&block) - 1)] + levels_gap;
  369. } else {
  370. lower_bound = place[ints_get(&block, ints_size(&block) - 1)];
  371. }
  372. }
  373. }
  374. orthog1f(n, place); /* for numerical stability, keep ||place|| small */
  375. }
  376. free(lev);
  377. ints_free(&block);
  378. }
  379. void deleteCMajEnv(CMajEnv * e)
  380. {
  381. free(e->A[0]);
  382. free(e->A);
  383. free(e->fArray1);
  384. free(e->fArray2);
  385. free(e->fArray3);
  386. free(e->fArray4);
  387. free(e);
  388. }
  389. CMajEnv *initConstrainedMajorization(float *packedMat, int n,
  390. int *ordering, int *levels,
  391. int num_levels)
  392. {
  393. CMajEnv *e = gv_alloc(sizeof(CMajEnv));
  394. e->n = n;
  395. e->ordering = ordering;
  396. e->levels = levels;
  397. e->num_levels = num_levels;
  398. e->A = unpackMatrix(packedMat, n);
  399. e->fArray1 = gv_calloc(n, sizeof(float));
  400. e->fArray2 = gv_calloc(n, sizeof(float));
  401. e->fArray3 = gv_calloc(n, sizeof(float));
  402. e->fArray4 = gv_calloc(n, sizeof(float));
  403. return e;
  404. }
  405. #endif /* DIGCOLA */