spring_electrical.c 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215
  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 "config.h"
  11. #include <cgraph/list.h>
  12. #include <sparse/SparseMatrix.h>
  13. #include <sfdpgen/spring_electrical.h>
  14. #include <sparse/QuadTree.h>
  15. #include <sfdpgen/Multilevel.h>
  16. #include <sfdpgen/post_process.h>
  17. #include <neatogen/overlap.h>
  18. #include <common/types.h>
  19. #include <common/arith.h>
  20. #include <math.h>
  21. #include <common/globals.h>
  22. #include <stdbool.h>
  23. #include <stddef.h>
  24. #include <string.h>
  25. #include <time.h>
  26. #include <util/agxbuf.h>
  27. #include <util/alloc.h>
  28. #include <util/bitarray.h>
  29. /// another parameter
  30. /// fₐ(i, j) = C × dist(i , j)² ÷ K × dᵢⱼ, fᵣ(i, j) = K³⁻ᵖ ÷ dist(i, j)⁻ᵖ
  31. static const double C = 0.2;
  32. /// cut off size above which quadtree approximation is used
  33. static const int quadtree_size = 45;
  34. /// Barnes-Hutt constant,
  35. /// if width(snode) ÷ dist[i, snode] < bh, treat snode as a supernode.
  36. static const double bh = 0.6;
  37. /// minimum different between two subsequence config before terminating.
  38. /// ||x - xold||_∞ < tol ÷ K
  39. static const double tol = 0.001;
  40. static const double cool = 0.90;
  41. spring_electrical_control spring_electrical_control_new(void){
  42. spring_electrical_control ctrl;
  43. ctrl = gv_alloc(sizeof(struct spring_electrical_control_struct));
  44. ctrl->p = AUTOP;/*a negativve number default to -1. repulsive force = dist^p */
  45. ctrl->random_start = true; // whether to apply SE from a random layout, or from existing layout
  46. ctrl->K = -1;/* the natural distance. If K < 0, K will be set to the average distance of an edge */
  47. ctrl->multilevels = 0;/* if <=1, single level */
  48. ctrl->max_qtree_level = 10;/* max level of quadtree */
  49. ctrl->maxiter = 500;
  50. ctrl->step = 0.1;
  51. ctrl->adaptive_cooling = true;
  52. ctrl->random_seed = 123;
  53. ctrl->beautify_leaves = false;
  54. ctrl->smoothing = SMOOTHING_NONE;
  55. ctrl->overlap = 0;
  56. ctrl->do_shrinking = true;
  57. ctrl->tscheme = QUAD_TREE_HYBRID;
  58. ctrl->initial_scaling = -4;
  59. ctrl->rotation = 0.;
  60. ctrl->edge_labeling_scheme = 0;
  61. return ctrl;
  62. }
  63. void spring_electrical_control_delete(spring_electrical_control ctrl){
  64. free(ctrl);
  65. }
  66. static char* smoothings[] = {
  67. "NONE", "STRESS_MAJORIZATION_GRAPH_DIST", "STRESS_MAJORIZATION_AVG_DIST", "STRESS_MAJORIZATION_POWER_DIST", "SPRING", "TRIANGLE", "RNG"
  68. };
  69. static char* tschemes[] = {
  70. "NONE", "NORMAL", "FAST", "HYBRID"
  71. };
  72. void spring_electrical_control_print(spring_electrical_control ctrl){
  73. fprintf (stderr, "spring_electrical_control:\n");
  74. fprintf (stderr, " repulsive exponent: %.03f\n", ctrl->p);
  75. fprintf(stderr, " random start %d seed %d\n", (int)ctrl->random_start,
  76. ctrl->random_seed);
  77. fprintf (stderr, " K : %.03f C : %.03f\n", ctrl->K, C);
  78. fprintf (stderr, " max levels %d\n", ctrl->multilevels);
  79. fprintf (stderr, " quadtree size %d max_level %d\n", quadtree_size, ctrl->max_qtree_level);
  80. fprintf (stderr, " Barnes-Hutt constant %.03f tolerance %.03f maxiter %d\n", bh, tol, ctrl->maxiter);
  81. fprintf(stderr, " cooling %.03f step size %.03f adaptive %d\n", cool,
  82. ctrl->step, (int)ctrl->adaptive_cooling);
  83. fprintf (stderr, " beautify_leaves %d node weights %d rotation %.03f\n",
  84. (int)ctrl->beautify_leaves, 0, ctrl->rotation);
  85. fprintf (stderr, " smoothing %s overlap %d initial_scaling %.03f do_shrinking %d\n",
  86. smoothings[ctrl->smoothing], ctrl->overlap, ctrl->initial_scaling, (int)ctrl->do_shrinking);
  87. fprintf (stderr, " octree scheme %s\n", tschemes[ctrl->tscheme]);
  88. fprintf (stderr, " edge_labeling_scheme %d\n", ctrl->edge_labeling_scheme);
  89. }
  90. enum { MAX_I = 20, OPT_UP = 1, OPT_DOWN = -1, OPT_INIT = 0 };
  91. typedef struct {
  92. int i;
  93. double work[MAX_I + 1];
  94. int direction;
  95. } oned_optimizer;
  96. static oned_optimizer oned_optimizer_new(int i){
  97. oned_optimizer opt = {0};
  98. opt.i = i;
  99. opt.direction = OPT_INIT;
  100. return opt;
  101. }
  102. static void oned_optimizer_train(oned_optimizer *opt, double work) {
  103. int i = opt->i;
  104. assert(i >= 0);
  105. opt->work[i] = work;
  106. if (opt->direction == OPT_INIT){
  107. if (opt->i == MAX_I){
  108. opt->direction = OPT_DOWN;
  109. opt->i = opt->i - 1;
  110. } else {
  111. opt->direction = OPT_UP;
  112. opt->i = MIN(MAX_I, opt->i + 1);
  113. }
  114. } else if (opt->direction == OPT_UP){
  115. assert(i >= 1);
  116. if (opt->work[i] < opt->work[i-1] && opt->i < MAX_I){
  117. opt->i = MIN(MAX_I, opt->i + 1);
  118. } else {
  119. (opt->i)--;
  120. opt->direction = OPT_DOWN;
  121. }
  122. } else {
  123. assert(i < MAX_I);
  124. if (opt->work[i] < opt->work[i+1] && opt->i > 0){
  125. opt->i = MAX(0, opt->i-1);
  126. } else {
  127. (opt->i)++;
  128. opt->direction = OPT_UP;
  129. }
  130. }
  131. }
  132. static int oned_optimizer_get(const oned_optimizer opt) {
  133. return opt.i;
  134. }
  135. double average_edge_length(SparseMatrix A, int dim, double *coord){
  136. double dist = 0, d;
  137. int *ia = A->ia, *ja = A->ja, i, j, k;
  138. assert(SparseMatrix_is_symmetric(A, true));
  139. if (ia[A->m] == 0) return 1;
  140. for (i = 0; i < A->m; i++){
  141. for (j = ia[i]; j < ia[i+1]; j++){
  142. d = 0;
  143. for (k = 0; k < dim; k++){
  144. d += (coord[dim*i+k] - coord[dim*ja[j]])*(coord[dim*i+k] - coord[dim*ja[j]]);
  145. }
  146. dist += sqrt(d);
  147. }
  148. }
  149. return dist/ia[A->m];
  150. }
  151. static double update_step(bool adaptive_cooling, double step, double Fnorm,
  152. double Fnorm0) {
  153. if (!adaptive_cooling) {
  154. return cool*step;
  155. }
  156. if (Fnorm >= Fnorm0){
  157. step = cool*step;
  158. } else if (Fnorm > 0.95*Fnorm0){
  159. // step = step;
  160. } else {
  161. step = 0.99*step/cool;
  162. }
  163. return step;
  164. }
  165. #define node_degree(i) (ia[(i)+1] - ia[(i)])
  166. static void set_leaves(double *x, int dim, double dist, double ang, int i, int j){
  167. x[dim*j] = cos(ang)*dist + x[dim*i];
  168. x[dim*j+1] = sin(ang)*dist + x[dim*i+1];
  169. }
  170. DEFINE_LIST(ints, int)
  171. static void beautify_leaves(int dim, SparseMatrix A, double *x){
  172. int m = A->m, i, j, *ia = A->ia, *ja = A->ja;
  173. int p;
  174. double dist;
  175. double step;
  176. assert(!SparseMatrix_has_diagonal(A));
  177. bitarray_t checked = bitarray_new(m);
  178. for (i = 0; i < m; i++){
  179. if (ia[i+1] - ia[i] != 1) continue;
  180. if (bitarray_get(checked, i)) continue;
  181. p = ja[ia[i]];
  182. if (!bitarray_get(checked, p)) {
  183. bitarray_set(&checked, p, true);
  184. dist = 0;
  185. ints_t leaves = {0};
  186. for (j = ia[p]; j < ia[p+1]; j++){
  187. if (node_degree(ja[j]) == 1){
  188. bitarray_set(&checked, ja[j], true);
  189. dist += distance(x, dim, p, ja[j]);
  190. ints_append(&leaves, ja[j]);
  191. }
  192. }
  193. assert(!ints_is_empty(&leaves));
  194. dist /= (double)ints_size(&leaves);
  195. double ang1 = 0;
  196. double ang2 = 2 * M_PI;
  197. const double pad = 0.1; // fudge factor to account for the size and
  198. // placement of the nodes themselves
  199. ang1 += pad;
  200. ang2 -= pad;
  201. assert(ang2 >= ang1);
  202. step = 0.;
  203. if (ints_size(&leaves) > 1) step = (ang2 - ang1) / (double)ints_size(&leaves);
  204. for (size_t k = 0; k < ints_size(&leaves); k++) {
  205. set_leaves(x, dim, dist, ang1, p, ints_get(&leaves, k));
  206. ang1 += step;
  207. }
  208. ints_free(&leaves);
  209. }
  210. }
  211. bitarray_reset(&checked);
  212. }
  213. void spring_electrical_embedding_fast(int dim, SparseMatrix A0, spring_electrical_control ctrl, double *x, int *flag){
  214. /* x is a point to a 1D array, x[i*dim+j] gives the coordinate of the i-th node at dimension j. */
  215. SparseMatrix A = A0;
  216. int m, n;
  217. int i, j, k;
  218. double p = ctrl->p, K = ctrl->K, CRK, maxiter = ctrl->maxiter, step = ctrl->step, KP;
  219. int *ia = NULL, *ja = NULL;
  220. double *f = NULL, dist, F, Fnorm = 0, Fnorm0;
  221. int iter = 0;
  222. const bool adaptive_cooling = ctrl->adaptive_cooling;
  223. double counts[4], *force = NULL;
  224. #ifdef TIME
  225. clock_t start, end, start0;
  226. double qtree_cpu = 0, qtree_new_cpu = 0;
  227. double total_cpu = 0;
  228. start0 = clock();
  229. #endif
  230. int max_qtree_level = ctrl->max_qtree_level;
  231. if (!A || maxiter <= 0) return;
  232. m = A->m, n = A->n;
  233. if (n <= 0 || dim <= 0) return;
  234. oned_optimizer qtree_level_optimizer = oned_optimizer_new(max_qtree_level);
  235. *flag = 0;
  236. if (m != n) {
  237. *flag = ERROR_NOT_SQUARE_MATRIX;
  238. goto RETURN;
  239. }
  240. assert(A->format == FORMAT_CSR);
  241. A = SparseMatrix_symmetrize(A, true);
  242. ia = A->ia;
  243. ja = A->ja;
  244. if (ctrl->random_start){
  245. srand(ctrl->random_seed);
  246. for (i = 0; i < dim*n; i++) x[i] = drand();
  247. }
  248. if (K < 0){
  249. ctrl->K = K = average_edge_length(A, dim, x);
  250. }
  251. if (p >= 0) ctrl->p = p = -1;
  252. KP = pow(K, 1 - p);
  253. CRK = pow(C, (2.-p)/3.)/K;
  254. force = gv_calloc(dim * n, sizeof(double));
  255. do {
  256. iter++;
  257. Fnorm0 = Fnorm;
  258. Fnorm = 0.;
  259. max_qtree_level = oned_optimizer_get(qtree_level_optimizer);
  260. #ifdef TIME
  261. start = clock();
  262. #endif
  263. QuadTree qt = QuadTree_new_from_point_list(dim, n, max_qtree_level, x);
  264. #ifdef TIME
  265. qtree_new_cpu += ((double) (clock() - start))/CLOCKS_PER_SEC;
  266. #endif
  267. /* repulsive force */
  268. #ifdef TIME
  269. start = clock();
  270. #endif
  271. QuadTree_get_repulsive_force(qt, force, x, bh, p, KP, counts);
  272. #ifdef TIME
  273. end = clock();
  274. qtree_cpu += ((double) (end - start)) / CLOCKS_PER_SEC;
  275. #endif
  276. /* attractive force C^((2-p)/3) ||x_i-x_j||/K * (x_j - x_i) */
  277. for (i = 0; i < n; i++){
  278. f = &(force[i*dim]);
  279. for (j = ia[i]; j < ia[i+1]; j++){
  280. if (ja[j] == i) continue;
  281. dist = distance(x, dim, i, ja[j]);
  282. for (k = 0; k < dim; k++){
  283. f[k] -= CRK*(x[i*dim+k] - x[ja[j]*dim+k])*dist;
  284. }
  285. }
  286. }
  287. /* move */
  288. for (i = 0; i < n; i++){
  289. f = &(force[i*dim]);
  290. F = 0.;
  291. for (k = 0; k < dim; k++) F += f[k]*f[k];
  292. F = sqrt(F);
  293. Fnorm += F;
  294. if (F > 0) for (k = 0; k < dim; k++) f[k] /= F;
  295. for (k = 0; k < dim; k++) x[i*dim+k] += step*f[k];
  296. }/* done vertex i */
  297. if (qt) {
  298. #ifdef TIME
  299. start = clock();
  300. #endif
  301. QuadTree_delete(qt);
  302. #ifdef TIME
  303. end = clock();
  304. qtree_new_cpu += ((double) (end - start)) / CLOCKS_PER_SEC;
  305. #endif
  306. oned_optimizer_train(&qtree_level_optimizer,
  307. counts[0] + 0.85 * counts[1] + 3.3 * counts[2]);
  308. } else {
  309. if (Verbose) {
  310. fprintf(stderr, "\r iter = %d, step = %f Fnorm = %f nz = %d K = %f ",iter, step, Fnorm, A->nz,K);
  311. }
  312. }
  313. step = update_step(adaptive_cooling, step, Fnorm, Fnorm0);
  314. } while (step > tol && iter < maxiter);
  315. #ifdef DEBUG_PRINT
  316. if (Verbose) {
  317. fprintf(stderr, "\n iter = %d, step = %f Fnorm = %f nz = %d K = %f ",iter, step, Fnorm, A->nz, K);
  318. }
  319. #endif
  320. if (ctrl->beautify_leaves) beautify_leaves(dim, A, x);
  321. #ifdef TIME
  322. total_cpu += ((double) (clock() - start0)) / CLOCKS_PER_SEC;
  323. if (Verbose) fprintf(stderr, "\n time for qtree = %f, qtree_force = %f, total cpu = %f\n",qtree_new_cpu, qtree_cpu, total_cpu);
  324. #endif
  325. RETURN:
  326. ctrl->max_qtree_level = max_qtree_level;
  327. if (A != A0) SparseMatrix_delete(A);
  328. free(force);
  329. }
  330. static void spring_electrical_embedding_slow(int dim, SparseMatrix A0, spring_electrical_control ctrl, double *x, int *flag){
  331. /* a version that does vertex moves in one go, instead of one at a time, use for debugging the fast version. Quadtree is not used. */
  332. /* x is a point to a 1D array, x[i*dim+j] gives the coordinate of the i-th node at dimension j. */
  333. SparseMatrix A = A0;
  334. int m, n;
  335. int i, j, k;
  336. double p = ctrl->p, K = ctrl->K, CRK, maxiter = ctrl->maxiter, step = ctrl->step, KP;
  337. int *ia = NULL, *ja = NULL;
  338. double *f = NULL, dist, F, Fnorm = 0, Fnorm0;
  339. int iter = 0;
  340. const bool adaptive_cooling = ctrl->adaptive_cooling;
  341. double *force;
  342. #ifdef TIME
  343. clock_t start, end, start0, start2;
  344. double total_cpu = 0;
  345. start0 = clock();
  346. #endif
  347. fprintf(stderr,"spring_electrical_embedding_slow");
  348. if (!A || maxiter <= 0) return;
  349. m = A->m, n = A->n;
  350. if (n <= 0 || dim <= 0) return;
  351. force = gv_calloc(n *dim, sizeof(double));
  352. *flag = 0;
  353. if (m != n) {
  354. *flag = ERROR_NOT_SQUARE_MATRIX;
  355. goto RETURN;
  356. }
  357. assert(A->format == FORMAT_CSR);
  358. A = SparseMatrix_symmetrize(A, true);
  359. ia = A->ia;
  360. ja = A->ja;
  361. if (ctrl->random_start){
  362. srand(ctrl->random_seed);
  363. for (i = 0; i < dim*n; i++) x[i] = drand();
  364. }
  365. if (K < 0){
  366. ctrl->K = K = average_edge_length(A, dim, x);
  367. }
  368. if (p >= 0) ctrl->p = p = -1;
  369. KP = pow(K, 1 - p);
  370. CRK = pow(C, (2.-p)/3.)/K;
  371. f = gv_calloc(dim, sizeof(double));
  372. do {
  373. for (i = 0; i < dim*n; i++) force[i] = 0;
  374. iter++;
  375. Fnorm0 = Fnorm;
  376. Fnorm = 0.;
  377. #ifdef TIME
  378. start2 = clock();
  379. #endif
  380. for (i = 0; i < n; i++){
  381. for (k = 0; k < dim; k++) f[k] = 0.;
  382. /* repulsive force K^(1 - p)/||x_i-x_j||^(1 - p) (x_i - x_j) */
  383. for (j = 0; j < n; j++){
  384. if (j == i) continue;
  385. dist = distance_cropped(x, dim, i, j);
  386. for (k = 0; k < dim; k++){
  387. f[k] += KP*(x[i*dim+k] - x[j*dim+k])/pow(dist, 1.- p);
  388. }
  389. }
  390. for (k = 0; k < dim; k++) force[i*dim+k] += f[k];
  391. }
  392. for (i = 0; i < n; i++){
  393. for (k = 0; k < dim; k++) f[k] = 0.;
  394. /* attractive force C^((2-p)/3) ||x_i-x_j||/K * (x_j - x_i) */
  395. for (j = ia[i]; j < ia[i+1]; j++){
  396. if (ja[j] == i) continue;
  397. dist = distance(x, dim, i, ja[j]);
  398. for (k = 0; k < dim; k++){
  399. f[k] -= CRK*(x[i*dim+k] - x[ja[j]*dim+k])*dist;
  400. }
  401. }
  402. for (k = 0; k < dim; k++) force[i*dim+k] += f[k];
  403. }
  404. for (i = 0; i < n; i++){
  405. /* normalize force */
  406. for (k = 0; k < dim; k++) f[k] = force[i*dim+k];
  407. F = 0.;
  408. for (k = 0; k < dim; k++) F += f[k]*f[k];
  409. F = sqrt(F);
  410. Fnorm += F;
  411. if (F > 0) for (k = 0; k < dim; k++) f[k] /= F;
  412. for (k = 0; k < dim; k++) x[i*dim+k] += step*f[k];
  413. }/* done vertex i */
  414. step = update_step(adaptive_cooling, step, Fnorm, Fnorm0);
  415. } while (step > tol && iter < maxiter);
  416. #ifdef DEBUG_PRINT
  417. if (Verbose) {
  418. fprintf(stderr, "iter = %d, step = %f Fnorm = %f nsuper = 0 nz = %d K = %f ",iter, step, Fnorm, A->nz,K);
  419. }
  420. #endif
  421. if (ctrl->beautify_leaves) beautify_leaves(dim, A, x);
  422. #ifdef TIME
  423. total_cpu += ((double) (clock() - start0)) / CLOCKS_PER_SEC;
  424. if (Verbose) fprintf(stderr, "time for supernode = 0, total cpu = %f\n", total_cpu);
  425. #endif
  426. RETURN:
  427. if (A != A0) SparseMatrix_delete(A);
  428. free(f);
  429. free(force);
  430. }
  431. void spring_electrical_embedding(int dim, SparseMatrix A0, spring_electrical_control ctrl, double *x, int *flag){
  432. /* x is a point to a 1D array, x[i*dim+j] gives the coordinate of the i-th node at dimension j. */
  433. SparseMatrix A = A0;
  434. int m, n;
  435. int i, j, k;
  436. double p = ctrl->p, K = ctrl->K, CRK, maxiter = ctrl->maxiter, step = ctrl->step, KP;
  437. int *ia = NULL, *ja = NULL;
  438. double *f = NULL, dist, F, Fnorm = 0, Fnorm0;
  439. int iter = 0;
  440. const bool adaptive_cooling = ctrl->adaptive_cooling;
  441. bool USE_QT = false;
  442. int nsuper = 0, nsupermax = 10;
  443. double *center = NULL, *supernode_wgts = NULL, *distances = NULL, nsuper_avg, counts = 0, counts_avg = 0;
  444. #ifdef TIME
  445. clock_t start, end, start0, start2;
  446. double qtree_cpu = 0;
  447. double total_cpu = 0;
  448. start0 = clock();
  449. #endif
  450. int max_qtree_level = ctrl->max_qtree_level;
  451. oned_optimizer qtree_level_optimizer = {0};
  452. if (!A || maxiter <= 0) return;
  453. m = A->m, n = A->n;
  454. if (n <= 0 || dim <= 0) return;
  455. if (n >= quadtree_size) {
  456. USE_QT = true;
  457. qtree_level_optimizer = oned_optimizer_new(max_qtree_level);
  458. center = gv_calloc(nsupermax * dim, sizeof(double));
  459. supernode_wgts = gv_calloc(nsupermax, sizeof(double));
  460. distances = gv_calloc(nsupermax, sizeof(double));
  461. }
  462. *flag = 0;
  463. if (m != n) {
  464. *flag = ERROR_NOT_SQUARE_MATRIX;
  465. goto RETURN;
  466. }
  467. assert(A->format == FORMAT_CSR);
  468. A = SparseMatrix_symmetrize(A, true);
  469. ia = A->ia;
  470. ja = A->ja;
  471. if (ctrl->random_start){
  472. srand(ctrl->random_seed);
  473. for (i = 0; i < dim*n; i++) x[i] = drand();
  474. }
  475. if (K < 0){
  476. ctrl->K = K = average_edge_length(A, dim, x);
  477. }
  478. if (p >= 0) ctrl->p = p = -1;
  479. KP = pow(K, 1 - p);
  480. CRK = pow(C, (2.-p)/3.)/K;
  481. f = gv_calloc(dim, sizeof(double));
  482. do {
  483. iter++;
  484. Fnorm0 = Fnorm;
  485. Fnorm = 0.;
  486. nsuper_avg = 0;
  487. counts_avg = 0;
  488. QuadTree qt = NULL;
  489. if (USE_QT) {
  490. max_qtree_level = oned_optimizer_get(qtree_level_optimizer);
  491. qt = QuadTree_new_from_point_list(dim, n, max_qtree_level, x);
  492. }
  493. #ifdef TIME
  494. start2 = clock();
  495. #endif
  496. for (i = 0; i < n; i++){
  497. for (k = 0; k < dim; k++) f[k] = 0.;
  498. /* attractive force C^((2-p)/3) ||x_i-x_j||/K * (x_j - x_i) */
  499. for (j = ia[i]; j < ia[i+1]; j++){
  500. if (ja[j] == i) continue;
  501. dist = distance(x, dim, i, ja[j]);
  502. for (k = 0; k < dim; k++){
  503. f[k] -= CRK*(x[i*dim+k] - x[ja[j]*dim+k])*dist;
  504. }
  505. }
  506. /* repulsive force K^(1 - p)/||x_i-x_j||^(1 - p) (x_i - x_j) */
  507. if (USE_QT){
  508. #ifdef TIME
  509. start = clock();
  510. #endif
  511. QuadTree_get_supernodes(qt, bh, &(x[dim*i]), i, &nsuper, &nsupermax,
  512. &center, &supernode_wgts, &distances, &counts);
  513. #ifdef TIME
  514. end = clock();
  515. qtree_cpu += ((double) (end - start)) / CLOCKS_PER_SEC;
  516. #endif
  517. counts_avg += counts;
  518. nsuper_avg += nsuper;
  519. for (j = 0; j < nsuper; j++){
  520. dist = MAX(distances[j], MINDIST);
  521. for (k = 0; k < dim; k++){
  522. f[k] += supernode_wgts[j]*KP*(x[i*dim+k] - center[j*dim+k])/pow(dist, 1.- p);
  523. }
  524. }
  525. } else {
  526. for (j = 0; j < n; j++){
  527. if (j == i) continue;
  528. dist = distance_cropped(x, dim, i, j);
  529. for (k = 0; k < dim; k++){
  530. f[k] += KP*(x[i*dim+k] - x[j*dim+k])/pow(dist, 1.- p);
  531. }
  532. }
  533. }
  534. /* normalize force */
  535. F = 0.;
  536. for (k = 0; k < dim; k++) F += f[k]*f[k];
  537. F = sqrt(F);
  538. Fnorm += F;
  539. if (F > 0) for (k = 0; k < dim; k++) f[k] /= F;
  540. for (k = 0; k < dim; k++) x[i*dim+k] += step*f[k];
  541. }/* done vertex i */
  542. if (qt) {
  543. QuadTree_delete(qt);
  544. nsuper_avg /= n;
  545. counts_avg /= n;
  546. oned_optimizer_train(&qtree_level_optimizer, 5 * nsuper_avg + counts_avg);
  547. }
  548. step = update_step(adaptive_cooling, step, Fnorm, Fnorm0);
  549. } while (step > tol && iter < maxiter);
  550. #ifdef DEBUG_PRINT
  551. if (Verbose) {
  552. if (USE_QT){
  553. fprintf(stderr, "iter = %d, step = %f Fnorm = %f qt_level = %d nsuper = %d nz = %d K = %f ",iter, step, Fnorm, max_qtree_level, (int) nsuper_avg,A->nz,K);
  554. } else {
  555. fprintf(stderr, "iter = %d, step = %f Fnorm = %f nsuper = %d nz = %d K = %f ",iter, step, Fnorm, (int) nsuper_avg,A->nz,K);
  556. }
  557. }
  558. #endif
  559. if (ctrl->beautify_leaves) beautify_leaves(dim, A, x);
  560. #ifdef TIME
  561. total_cpu += ((double) (clock() - start0)) / CLOCKS_PER_SEC;
  562. if (Verbose) fprintf(stderr, "time for supernode = %f, total cpu = %f\n",qtree_cpu, total_cpu);
  563. #endif
  564. RETURN:
  565. if (USE_QT) {
  566. ctrl->max_qtree_level = max_qtree_level;
  567. }
  568. if (A != A0) SparseMatrix_delete(A);
  569. free(f);
  570. free(center);
  571. free(supernode_wgts);
  572. free(distances);
  573. }
  574. void spring_electrical_spring_embedding(int dim, SparseMatrix A0, SparseMatrix D, spring_electrical_control ctrl, double *x, int *flag){
  575. /* x is a point to a 1D array, x[i*dim+j] gives the coordinate of the i-th node at dimension j. Same as the spring-electrical except we also
  576. introduce force due to spring length
  577. */
  578. SparseMatrix A = A0;
  579. int m, n;
  580. int i, j, k;
  581. double p = ctrl->p, K = ctrl->K, CRK, maxiter = ctrl->maxiter, step = ctrl->step, KP;
  582. int *ia = NULL, *ja = NULL;
  583. int *id = NULL, *jd = NULL;
  584. double *d;
  585. double *xold = NULL;
  586. double *f = NULL, dist, F, Fnorm = 0, Fnorm0;
  587. int iter = 0;
  588. const bool adaptive_cooling = ctrl->adaptive_cooling;
  589. bool USE_QT = false;
  590. int nsuper = 0, nsupermax = 10;
  591. double *center = NULL, *supernode_wgts = NULL, *distances = NULL, counts = 0;
  592. int max_qtree_level = 10;
  593. if (!A || maxiter <= 0) return;
  594. m = A->m, n = A->n;
  595. if (n <= 0 || dim <= 0) return;
  596. if (n >= quadtree_size) {
  597. USE_QT = true;
  598. center = gv_calloc(nsupermax * dim, sizeof(double));
  599. supernode_wgts = gv_calloc(nsupermax, sizeof(double));
  600. distances = gv_calloc(nsupermax, sizeof(double));
  601. }
  602. *flag = 0;
  603. if (m != n) {
  604. *flag = ERROR_NOT_SQUARE_MATRIX;
  605. goto RETURN;
  606. }
  607. assert(A->format == FORMAT_CSR);
  608. A = SparseMatrix_symmetrize(A, true);
  609. ia = A->ia;
  610. ja = A->ja;
  611. id = D->ia;
  612. jd = D->ja;
  613. d = D->a;
  614. if (ctrl->random_start){
  615. srand(ctrl->random_seed);
  616. for (i = 0; i < dim*n; i++) x[i] = drand();
  617. }
  618. if (K < 0){
  619. ctrl->K = K = average_edge_length(A, dim, x);
  620. }
  621. if (p >= 0) ctrl->p = p = -1;
  622. KP = pow(K, 1 - p);
  623. CRK = pow(C, (2.-p)/3.)/K;
  624. f = gv_calloc(dim, sizeof(double));
  625. xold = gv_calloc(dim * n, sizeof(double));
  626. do {
  627. iter++;
  628. memcpy(xold, x, sizeof(double)*dim*n);
  629. Fnorm0 = Fnorm;
  630. Fnorm = 0.;
  631. QuadTree qt = NULL;
  632. if (USE_QT) {
  633. qt = QuadTree_new_from_point_list(dim, n, max_qtree_level, x);
  634. }
  635. for (i = 0; i < n; i++){
  636. for (k = 0; k < dim; k++) f[k] = 0.;
  637. /* attractive force C^((2-p)/3) ||x_i-x_j||/K * (x_j - x_i) */
  638. for (j = ia[i]; j < ia[i+1]; j++){
  639. if (ja[j] == i) continue;
  640. dist = distance(x, dim, i, ja[j]);
  641. for (k = 0; k < dim; k++){
  642. f[k] -= CRK*(x[i*dim+k] - x[ja[j]*dim+k])*dist;
  643. }
  644. }
  645. for (j = id[i]; j < id[i+1]; j++){
  646. if (jd[j] == i) continue;
  647. dist = distance_cropped(x, dim, i, jd[j]);
  648. for (k = 0; k < dim; k++){
  649. if (dist < d[j]){
  650. f[k] += 0.2*CRK*(x[i*dim+k] - x[jd[j]*dim+k])*(dist - d[j])*(dist - d[j])/dist;
  651. } else {
  652. f[k] -= 0.2*CRK*(x[i*dim+k] - x[jd[j]*dim+k])*(dist - d[j])*(dist - d[j])/dist;
  653. }
  654. /* f[k] -= 0.2*CRK*(x[i*dim+k] - x[jd[j]*dim+k])*(dist - d[j]);*/
  655. }
  656. }
  657. /* repulsive force K^(1 - p)/||x_i-x_j||^(1 - p) (x_i - x_j) */
  658. if (USE_QT){
  659. QuadTree_get_supernodes(qt, bh, &(x[dim*i]), i, &nsuper, &nsupermax,
  660. &center, &supernode_wgts, &distances, &counts);
  661. for (j = 0; j < nsuper; j++){
  662. dist = MAX(distances[j], MINDIST);
  663. for (k = 0; k < dim; k++){
  664. f[k] += supernode_wgts[j]*KP*(x[i*dim+k] - center[j*dim+k])/pow(dist, 1.- p);
  665. }
  666. }
  667. } else {
  668. for (j = 0; j < n; j++){
  669. if (j == i) continue;
  670. dist = distance_cropped(x, dim, i, j);
  671. for (k = 0; k < dim; k++){
  672. f[k] += KP*(x[i*dim+k] - x[j*dim+k])/pow(dist, 1.- p);
  673. }
  674. }
  675. }
  676. /* normalize force */
  677. F = 0.;
  678. for (k = 0; k < dim; k++) F += f[k]*f[k];
  679. F = sqrt(F);
  680. Fnorm += F;
  681. if (F > 0) for (k = 0; k < dim; k++) f[k] /= F;
  682. for (k = 0; k < dim; k++) x[i*dim+k] += step*f[k];
  683. }/* done vertex i */
  684. if (qt) QuadTree_delete(qt);
  685. step = update_step(adaptive_cooling, step, Fnorm, Fnorm0);
  686. } while (step > tol && iter < maxiter);
  687. if (ctrl->beautify_leaves) beautify_leaves(dim, A, x);
  688. RETURN:
  689. free(xold);
  690. if (A != A0) SparseMatrix_delete(A);
  691. free(f);
  692. free(center);
  693. free(supernode_wgts);
  694. free(distances);
  695. }
  696. static void interpolate_coord(int dim, SparseMatrix A, double *x) {
  697. int i, j, k, *ia = A->ia, *ja = A->ja, nz;
  698. double alpha = 0.5, beta;
  699. double *y = gv_calloc(dim, sizeof(double));
  700. for (i = 0; i < A->m; i++){
  701. for (k = 0; k < dim; k++) y[k] = 0;
  702. nz = 0;
  703. for (j = ia[i]; j < ia[i+1]; j++){
  704. if (ja[j] == i) continue;
  705. nz++;
  706. for (k = 0; k < dim; k++){
  707. y[k] += x[ja[j]*dim + k];
  708. }
  709. }
  710. if (nz > 0){
  711. beta = (1-alpha)/nz;
  712. for (k = 0; k < dim; k++) x[i*dim+k] = alpha*x[i*dim+k] + beta*y[k];
  713. }
  714. }
  715. free(y);
  716. }
  717. static void prolongate(int dim, SparseMatrix A, SparseMatrix P, SparseMatrix R, double *x, double *y, double delta){
  718. int nc, *ia, *ja, i, j, k;
  719. SparseMatrix_multiply_dense(P, x, y, dim);
  720. interpolate_coord(dim, A, y);
  721. nc = R->m;
  722. ia = R->ia;
  723. ja = R->ja;
  724. for (i = 0; i < nc; i++){
  725. for (j = ia[i]+1; j < ia[i+1]; j++){
  726. for (k = 0; k < dim; k++){
  727. y[ja[j]*dim + k] += delta*(drand() - 0.5);
  728. }
  729. }
  730. }
  731. }
  732. static bool power_law_graph(SparseMatrix A) {
  733. int m, max = 0, i, *ia = A->ia, *ja = A->ja, j, deg;
  734. bool res = false;
  735. m = A->m;
  736. int *mask = gv_calloc(m + 1, sizeof(int));
  737. for (i = 0; i < m + 1; i++){
  738. mask[i] = 0;
  739. }
  740. for (i = 0; i < m; i++){
  741. deg = 0;
  742. for (j = ia[i]; j < ia[i+1]; j++){
  743. if (i == ja[j]) continue;
  744. deg++;
  745. }
  746. mask[deg]++;
  747. max = MAX(max, mask[deg]);
  748. }
  749. if (mask[1] > 0.8*max && mask[1] > 0.3*m) res = true;
  750. free(mask);
  751. return res;
  752. }
  753. void pcp_rotate(int n, int dim, double *x){
  754. int i, k,l;
  755. double y[4], axis[2], center[2], dist, x0, x1;
  756. assert(dim == 2);
  757. for (i = 0; i < dim*dim; i++) y[i] = 0;
  758. for (i = 0; i < dim; i++) center[i] = 0;
  759. for (i = 0; i < n; i++){
  760. for (k = 0; k < dim; k++){
  761. center[k] += x[i*dim+k];
  762. }
  763. }
  764. for (i = 0; i < dim; i++) center[i] /= n;
  765. for (i = 0; i < n; i++){
  766. for (k = 0; k < dim; k++){
  767. x[dim*i+k] = x[dim*i+k] - center[k];
  768. }
  769. }
  770. for (i = 0; i < n; i++){
  771. for (k = 0; k < dim; k++){
  772. for (l = 0; l < dim; l++){
  773. y[dim*k+l] += x[i*dim+k]*x[i*dim+l];
  774. }
  775. }
  776. }
  777. if (y[1] == 0) {
  778. axis[0] = 0; axis[1] = 1;
  779. } else {
  780. /* Eigensystem[{{x0, x1}, {x1, x3}}] =
  781. {{(x0 + x3 - Sqrt[x0^2 + 4*x1^2 - 2*x0*x3 + x3^2])/2,
  782. (x0 + x3 + Sqrt[x0^2 + 4*x1^2 - 2*x0*x3 + x3^2])/2},
  783. {{-(-x0 + x3 + Sqrt[x0^2 + 4*x1^2 - 2*x0*x3 + x3^2])/(2*x1), 1},
  784. {-(-x0 + x3 - Sqrt[x0^2 + 4*x1^2 - 2*x0*x3 + x3^2])/(2*x1), 1}}}
  785. */
  786. axis[0] = -(-y[0] + y[3] - sqrt(y[0]*y[0]+4*y[1]*y[1]-2*y[0]*y[3]+y[3]*y[3]))/(2*y[1]);
  787. axis[1] = 1;
  788. }
  789. dist = sqrt(1+axis[0]*axis[0]);
  790. axis[0] = axis[0]/dist;
  791. axis[1] = axis[1]/dist;
  792. for (i = 0; i < n; i++){
  793. x0 = x[dim*i]*axis[0]+x[dim*i+1]*axis[1];
  794. x1 = -x[dim*i]*axis[1]+x[dim*i+1]*axis[0];
  795. x[dim*i] = x0;
  796. x[dim*i + 1] = x1;
  797. }
  798. }
  799. static void rotate(int n, int dim, double *x, double angle){
  800. int i, k;
  801. double axis[2], center[2], x0, x1;
  802. double radian = 3.14159/180;
  803. assert(dim == 2);
  804. for (i = 0; i < dim; i++) center[i] = 0;
  805. for (i = 0; i < n; i++){
  806. for (k = 0; k < dim; k++){
  807. center[k] += x[i*dim+k];
  808. }
  809. }
  810. for (i = 0; i < dim; i++) center[i] /= n;
  811. for (i = 0; i < n; i++){
  812. for (k = 0; k < dim; k++){
  813. x[dim*i+k] = x[dim*i+k] - center[k];
  814. }
  815. }
  816. axis[0] = cos(-angle*radian);
  817. axis[1] = sin(-angle*radian);
  818. for (i = 0; i < n; i++){
  819. x0 = x[dim*i]*axis[0]+x[dim*i+1]*axis[1];
  820. x1 = -x[dim*i]*axis[1]+x[dim*i+1]*axis[0];
  821. x[dim*i] = x0;
  822. x[dim*i + 1] = x1;
  823. }
  824. }
  825. static void attach_edge_label_coordinates(int dim, SparseMatrix A, int n_edge_label_nodes, int *edge_label_nodes, double *x, double *x2){
  826. int i, ii, j, k;
  827. int nnodes = 0;
  828. double len;
  829. int *mask = gv_calloc(A->m, sizeof(int));
  830. for (i = 0; i < A->m; i++) mask[i] = 1;
  831. for (i = 0; i < n_edge_label_nodes; i++) {
  832. if (edge_label_nodes[i] >= 0 && edge_label_nodes[i] < A->m) mask[edge_label_nodes[i]] = -1;
  833. }
  834. for (i = 0; i < A->m; i++) {
  835. if (mask[i] >= 0) mask[i] = nnodes++;
  836. }
  837. for (i = 0; i < A->m; i++){
  838. if (mask[i] >= 0){
  839. for (k = 0; k < dim; k++) x[i*dim+k] = x2[mask[i]*dim+k];
  840. }
  841. }
  842. for (i = 0; i < n_edge_label_nodes; i++){
  843. ii = edge_label_nodes[i];
  844. len = A->ia[ii+1] - A->ia[ii];
  845. assert(len >= 2); /* should just be 2 */
  846. assert(mask[ii] < 0);
  847. for (k = 0; k < dim; k++) {
  848. x[ii*dim+k] = 0;
  849. }
  850. for (j = A->ia[ii]; j < A->ia[ii+1]; j++){
  851. for (k = 0; k < dim; k++){
  852. x[ii*dim+k] += x[(A->ja[j])*dim+k];
  853. }
  854. }
  855. for (k = 0; k < dim; k++) {
  856. x[ii*dim+k] /= len;
  857. }
  858. }
  859. free(mask);
  860. }
  861. static SparseMatrix shorting_edge_label_nodes(SparseMatrix A, int n_edge_label_nodes, int *edge_label_nodes){
  862. int i, id = 0, nz, j, jj, ii;
  863. int *ia = A->ia, *ja = A->ja, *irn = NULL, *jcn = NULL;
  864. SparseMatrix B;
  865. int *mask = gv_calloc(A->m, sizeof(int));
  866. for (i = 0; i < A->m; i++) mask[i] = 1;
  867. for (i = 0; i < n_edge_label_nodes; i++){
  868. mask[edge_label_nodes[i]] = -1;
  869. }
  870. for (i = 0; i < A->m; i++) {
  871. if (mask[i] > 0) mask[i] = id++;
  872. }
  873. nz = 0;
  874. for (i = 0; i < A->m; i++){
  875. if (mask[i] < 0) continue;
  876. for (j = ia[i]; j < ia[i+1]; j++){
  877. if (mask[ja[j]] >= 0) {
  878. nz++;
  879. continue;
  880. }
  881. ii = ja[j];
  882. for (jj = ia[ii]; jj < ia[ii+1]; jj++){
  883. if (ja[jj] != i && mask[ja[jj]] >= 0) nz++;
  884. }
  885. }
  886. }
  887. if (nz > 0) {
  888. irn = gv_calloc(nz, sizeof(int));
  889. jcn = gv_calloc(nz, sizeof(int));
  890. }
  891. nz = 0;
  892. for (i = 0; i < A->m; i++){
  893. if (mask[i] < 0) continue;
  894. for (j = ia[i]; j < ia[i+1]; j++){
  895. if (mask[ja[j]] >= 0) {
  896. irn[nz] = mask[i];
  897. jcn[nz++] = mask[ja[j]];
  898. continue;
  899. }
  900. ii = ja[j];
  901. for (jj = ia[ii]; jj < ia[ii+1]; jj++){
  902. if (ja[jj] != i && mask[ja[jj]] >= 0) {
  903. irn[nz] = mask[i];
  904. jcn[nz++] = mask[ja[jj]];
  905. }
  906. }
  907. }
  908. }
  909. B = SparseMatrix_from_coordinate_arrays(nz, id, id, irn, jcn, NULL, MATRIX_TYPE_PATTERN, sizeof(double));
  910. free(irn);
  911. free(jcn);
  912. free(mask);
  913. return B;
  914. }
  915. void multilevel_spring_electrical_embedding(int dim, SparseMatrix A0,
  916. spring_electrical_control ctrl,
  917. double *label_sizes, double *x,
  918. int n_edge_label_nodes,
  919. int *edge_label_nodes, int *flag) {
  920. int n;
  921. SparseMatrix A = A0, P = NULL;
  922. Multilevel grid, grid0;
  923. double *xc = NULL, *xf = NULL;
  924. struct spring_electrical_control_struct ctrl0;
  925. #ifdef TIME
  926. clock_t cpu;
  927. #endif
  928. ctrl0 = *ctrl;
  929. #ifdef TIME
  930. cpu = clock();
  931. #endif
  932. *flag = 0;
  933. if (!A) return;
  934. n = A->n;
  935. if (n <= 0 || dim <= 0) return;
  936. if (!SparseMatrix_is_symmetric(A, false) || A->type != MATRIX_TYPE_REAL){
  937. A = SparseMatrix_get_real_adjacency_matrix_symmetrized(A);
  938. } else {
  939. A = SparseMatrix_remove_diagonal(A);
  940. }
  941. /* we first generate a layout discarding (shorting) the edge labels nodes, then assign the edge label nodes at the average of their neighbors */
  942. if ((ctrl->edge_labeling_scheme == ELSCHEME_STRAIGHTLINE_PENALTY || ctrl->edge_labeling_scheme == ELSCHEME_STRAIGHTLINE_PENALTY2)
  943. && n_edge_label_nodes > 0){
  944. SparseMatrix A2;
  945. double *x2 = gv_calloc(A->m * dim, sizeof(double));
  946. A2 = shorting_edge_label_nodes(A, n_edge_label_nodes, edge_label_nodes);
  947. multilevel_spring_electrical_embedding(dim, A2, ctrl, NULL, x2, 0, NULL, flag);
  948. assert(!(*flag));
  949. attach_edge_label_coordinates(dim, A, n_edge_label_nodes, edge_label_nodes, x, x2);
  950. remove_overlap(dim, A, x, label_sizes, ctrl->overlap, ctrl->initial_scaling,
  951. ctrl->edge_labeling_scheme, n_edge_label_nodes, edge_label_nodes, A, ctrl->do_shrinking);
  952. SparseMatrix_delete(A2);
  953. free(x2);
  954. if (A != A0) SparseMatrix_delete(A);
  955. return;
  956. }
  957. Multilevel_control mctrl = {.maxlevel = ctrl->multilevels};
  958. grid0 = Multilevel_new(A, mctrl);
  959. grid = Multilevel_get_coarsest(grid0);
  960. if (Multilevel_is_finest(grid)){
  961. xc = x;
  962. } else {
  963. xc = gv_calloc(grid->n * dim, sizeof(double));
  964. }
  965. const bool plg = power_law_graph(A);
  966. if (ctrl->p == AUTOP){
  967. ctrl->p = -1;
  968. if (plg) ctrl->p = -1.8;
  969. }
  970. do {
  971. #ifdef DEBUG_PRINT
  972. if (Verbose) {
  973. print_padding(grid->level);
  974. if (Multilevel_is_coarsest(grid)){
  975. fprintf(stderr, "coarsest level -- %d, n = %d\n", grid->level, grid->n);
  976. } else {
  977. fprintf(stderr, "level -- %d, n = %d\n", grid->level, grid->n);
  978. }
  979. }
  980. #endif
  981. if (ctrl->tscheme == QUAD_TREE_NONE){
  982. spring_electrical_embedding_slow(dim, grid->A, ctrl, xc, flag);
  983. } else if (ctrl->tscheme == QUAD_TREE_FAST || (ctrl->tscheme == QUAD_TREE_HYBRID && grid->A->m > QUAD_TREE_HYBRID_SIZE)){
  984. if (ctrl->tscheme == QUAD_TREE_HYBRID && grid->A->m > 10 && Verbose){
  985. fprintf(stderr, "QUAD_TREE_HYBRID, size larger than %d, switch to fast quadtree", QUAD_TREE_HYBRID_SIZE);
  986. }
  987. spring_electrical_embedding_fast(dim, grid->A, ctrl, xc, flag);
  988. } else {
  989. spring_electrical_embedding(dim, grid->A, ctrl, xc, flag);
  990. }
  991. if (Multilevel_is_finest(grid)) break;
  992. if (*flag) {
  993. free(xc);
  994. goto RETURN;
  995. }
  996. P = grid->P;
  997. grid = grid->prev;
  998. if (Multilevel_is_finest(grid)){
  999. xf = x;
  1000. } else {
  1001. xf = gv_calloc(grid->n * dim, sizeof(double));
  1002. }
  1003. prolongate(dim, grid->A, P, grid->R, xc, xf, (ctrl->K)*0.001);
  1004. free(xc);
  1005. xc = xf;
  1006. ctrl->random_start = false;
  1007. ctrl->K = ctrl->K * 0.75;
  1008. ctrl->adaptive_cooling = false;
  1009. ctrl->step = .1;
  1010. } while (grid);
  1011. #ifdef TIME
  1012. if (Verbose)
  1013. fprintf(stderr, "layout time %f\n",((double) (clock() - cpu)) / CLOCKS_PER_SEC);
  1014. cpu = clock();
  1015. #endif
  1016. post_process_smoothing(dim, A, ctrl, x);
  1017. if (Verbose) fprintf(stderr, "ctrl->overlap=%d\n",ctrl->overlap);
  1018. /* rotation has to be done before overlap removal, since rotation could induce overlaps */
  1019. if (dim == 2){
  1020. pcp_rotate(n, dim, x);
  1021. }
  1022. if (ctrl->rotation != 0) rotate(n, dim, x, ctrl->rotation);
  1023. remove_overlap(dim, A, x, label_sizes, ctrl->overlap, ctrl->initial_scaling,
  1024. ctrl->edge_labeling_scheme, n_edge_label_nodes, edge_label_nodes, A, ctrl->do_shrinking);
  1025. RETURN:
  1026. *ctrl = ctrl0;
  1027. if (A != A0) SparseMatrix_delete(A);
  1028. Multilevel_delete(grid0);
  1029. }