post_process.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970
  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 <time.h>
  12. #include <string.h>
  13. #include <math.h>
  14. #include <stdbool.h>
  15. #include <stdlib.h>
  16. #include <common/types.h>
  17. #include <common/globals.h>
  18. #include <sfdpgen/sparse_solve.h>
  19. #include <sfdpgen/post_process.h>
  20. #include <neatogen/overlap.h>
  21. #include <sfdpgen/spring_electrical.h>
  22. #include <neatogen/call_tri.h>
  23. #include <sfdpgen/sfdp.h>
  24. #include <util/alloc.h>
  25. #include <util/exit.h>
  26. #include <util/unused.h>
  27. #define node_degree(i) (ia[(i)+1] - ia[(i)])
  28. static SparseMatrix ideal_distance_matrix(SparseMatrix A, int dim, double *x){
  29. /* find the ideal distance between edges, either 1, or |N[i] \Union N[j]| - |N[i] \Intersection N[j]|
  30. */
  31. SparseMatrix D;
  32. int *ia, *ja, i, j, k, l, nz;
  33. double *d;
  34. double len, di, sum, sumd;
  35. assert(SparseMatrix_is_symmetric(A, false));
  36. D = SparseMatrix_copy(A);
  37. ia = D->ia;
  38. ja = D->ja;
  39. if (D->type != MATRIX_TYPE_REAL){
  40. free(D->a);
  41. D->type = MATRIX_TYPE_REAL;
  42. D->a = gv_calloc(D->nz, sizeof(double));
  43. }
  44. d = D->a;
  45. int *mask = gv_calloc(D->m, sizeof(int));
  46. for (i = 0; i < D->m; i++) mask[i] = -1;
  47. for (i = 0; i < D->m; i++){
  48. di = node_degree(i);
  49. mask[i] = i;
  50. for (j = ia[i]; j < ia[i+1]; j++){
  51. if (i == ja[j]) continue;
  52. mask[ja[j]] = i;
  53. }
  54. for (j = ia[i]; j < ia[i+1]; j++){
  55. k = ja[j];
  56. if (i == k) continue;
  57. len = di + node_degree(k);
  58. for (l = ia[k]; l < ia[k+1]; l++){
  59. if (mask[ja[l]] == i) len--;
  60. }
  61. d[j] = len;
  62. assert(len > 0);
  63. }
  64. }
  65. sum = 0; sumd = 0;
  66. nz = 0;
  67. for (i = 0; i < D->m; i++){
  68. for (j = ia[i]; j < ia[i+1]; j++){
  69. if (i == ja[j]) continue;
  70. nz++;
  71. sum += distance(x, dim, i, ja[j]);
  72. sumd += d[j];
  73. }
  74. }
  75. sum /= nz; sumd /= nz;
  76. sum = sum/sumd;
  77. for (i = 0; i < D->m; i++){
  78. for (j = ia[i]; j < ia[i+1]; j++){
  79. if (i == ja[j]) continue;
  80. d[j] = sum*d[j];
  81. }
  82. }
  83. free(mask);
  84. return D;
  85. }
  86. StressMajorizationSmoother StressMajorizationSmoother2_new(SparseMatrix A, int dim, double lambda0, double *x,
  87. int ideal_dist_scheme){
  88. /* use up to dist 2 neighbor. This is used in overcoming pherical effect with ideal distance of
  89. 2-neighbors equal graph distance etc.
  90. */
  91. int i, j, k, l, m = A->m, *ia = A->ia, *ja = A->ja, *iw, *jw, *id, *jd;
  92. int nz;
  93. double *d, *w, *lambda;
  94. double diag_d, diag_w, dist, s = 0, stop = 0, sbot = 0;
  95. SparseMatrix ID;
  96. assert(SparseMatrix_is_symmetric(A, false));
  97. ID = ideal_distance_matrix(A, dim, x);
  98. StressMajorizationSmoother sm = gv_alloc(sizeof(struct StressMajorizationSmoother_struct));
  99. sm->scaling = 1.;
  100. sm->data = NULL;
  101. sm->scheme = SM_SCHEME_NORMAL;
  102. sm->tol_cg = 0.01;
  103. sm->maxit_cg = floor(sqrt(A->m));
  104. lambda = sm->lambda = gv_calloc(m, sizeof(double));
  105. for (i = 0; i < m; i++) sm->lambda[i] = lambda0;
  106. int *mask = gv_calloc(m, sizeof(int));
  107. double *avg_dist = gv_calloc(m, sizeof(double));
  108. for (i = 0; i < m ;i++){
  109. avg_dist[i] = 0;
  110. nz = 0;
  111. for (j = ia[i]; j < ia[i+1]; j++){
  112. if (i == ja[j]) continue;
  113. avg_dist[i] += distance(x, dim, i, ja[j]);
  114. nz++;
  115. }
  116. assert(nz > 0);
  117. avg_dist[i] /= nz;
  118. }
  119. for (i = 0; i < m; i++) mask[i] = -1;
  120. nz = 0;
  121. for (i = 0; i < m; i++){
  122. mask[i] = i;
  123. for (j = ia[i]; j < ia[i+1]; j++){
  124. k = ja[j];
  125. if (mask[k] != i){
  126. mask[k] = i;
  127. nz++;
  128. }
  129. }
  130. for (j = ia[i]; j < ia[i+1]; j++){
  131. k = ja[j];
  132. for (l = ia[k]; l < ia[k+1]; l++){
  133. if (mask[ja[l]] != i){
  134. mask[ja[l]] = i;
  135. nz++;
  136. }
  137. }
  138. }
  139. }
  140. sm->Lw = SparseMatrix_new(m, m, nz + m, MATRIX_TYPE_REAL, FORMAT_CSR);
  141. sm->Lwd = SparseMatrix_new(m, m, nz + m, MATRIX_TYPE_REAL, FORMAT_CSR);
  142. if (!(sm->Lw) || !(sm->Lwd)) {
  143. StressMajorizationSmoother_delete(sm);
  144. return NULL;
  145. }
  146. iw = sm->Lw->ia; jw = sm->Lw->ja;
  147. w = sm->Lw->a;
  148. d = sm->Lwd->a;
  149. id = sm->Lwd->ia; jd = sm->Lwd->ja;
  150. iw[0] = id[0] = 0;
  151. nz = 0;
  152. for (i = 0; i < m; i++){
  153. mask[i] = i+m;
  154. diag_d = diag_w = 0;
  155. for (j = ia[i]; j < ia[i+1]; j++){
  156. k = ja[j];
  157. if (mask[k] != i+m){
  158. mask[k] = i+m;
  159. jw[nz] = k;
  160. if (ideal_dist_scheme == IDEAL_GRAPH_DIST){
  161. dist = 1;
  162. } else if (ideal_dist_scheme == IDEAL_AVG_DIST){
  163. dist = (avg_dist[i] + avg_dist[k])*0.5;
  164. } else if (ideal_dist_scheme == IDEAL_POWER_DIST){
  165. dist = pow(distance_cropped(x,dim,i,k),.4);
  166. } else {
  167. fprintf(stderr,"ideal_dist_scheme value wrong");
  168. assert(0);
  169. graphviz_exit(1);
  170. }
  171. /*
  172. w[nz] = -1./(ia[i+1]-ia[i]+ia[ja[j]+1]-ia[ja[j]]);
  173. w[nz] = -2./(avg_dist[i]+avg_dist[k]);*/
  174. /* w[nz] = -1.;*//* use unit weight for now, later can try 1/(deg(i)+deg(k)) */
  175. w[nz] = -1/(dist*dist);
  176. diag_w += w[nz];
  177. jd[nz] = k;
  178. /*
  179. d[nz] = w[nz]*distance(x,dim,i,k);
  180. d[nz] = w[nz]*dd[j];
  181. d[nz] = w[nz]*(avg_dist[i] + avg_dist[k])*0.5;
  182. */
  183. d[nz] = w[nz]*dist;
  184. stop += d[nz]*distance(x,dim,i,k);
  185. sbot += d[nz]*dist;
  186. diag_d += d[nz];
  187. nz++;
  188. }
  189. }
  190. /* distance 2 neighbors */
  191. for (j = ia[i]; j < ia[i+1]; j++){
  192. k = ja[j];
  193. for (l = ia[k]; l < ia[k+1]; l++){
  194. if (mask[ja[l]] != i+m){
  195. mask[ja[l]] = i+m;
  196. if (ideal_dist_scheme == IDEAL_GRAPH_DIST){
  197. dist = 2;
  198. } else if (ideal_dist_scheme == IDEAL_AVG_DIST){
  199. dist = (avg_dist[i] + 2*avg_dist[k] + avg_dist[ja[l]])*0.5;
  200. } else if (ideal_dist_scheme == IDEAL_POWER_DIST){
  201. dist = pow(distance_cropped(x,dim,i,ja[l]),.4);
  202. } else {
  203. fprintf(stderr,"ideal_dist_scheme value wrong");
  204. assert(0);
  205. graphviz_exit(1);
  206. }
  207. jw[nz] = ja[l];
  208. /*
  209. w[nz] = -1/(ia[i+1]-ia[i]+ia[ja[l]+1]-ia[ja[l]]);
  210. w[nz] = -2/(avg_dist[i] + 2*avg_dist[k] + avg_dist[ja[l]]);*/
  211. /* w[nz] = -1.;*//* use unit weight for now, later can try 1/(deg(i)+deg(k)) */
  212. w[nz] = -1/(dist*dist);
  213. diag_w += w[nz];
  214. jd[nz] = ja[l];
  215. /*
  216. d[nz] = w[nz]*(distance(x,dim,i,k)+distance(x,dim,k,ja[l]));
  217. d[nz] = w[nz]*(dd[j]+dd[l]);
  218. d[nz] = w[nz]*(avg_dist[i] + 2*avg_dist[k] + avg_dist[ja[l]])*0.5;
  219. */
  220. d[nz] = w[nz]*dist;
  221. stop += d[nz]*distance(x,dim,ja[l],k);
  222. sbot += d[nz]*dist;
  223. diag_d += d[nz];
  224. nz++;
  225. }
  226. }
  227. }
  228. jw[nz] = i;
  229. lambda[i] *= (-diag_w);/* alternatively don't do that then we have a constant penalty term scaled by lambda0 */
  230. w[nz] = -diag_w + lambda[i];
  231. jd[nz] = i;
  232. d[nz] = -diag_d;
  233. nz++;
  234. iw[i+1] = nz;
  235. id[i+1] = nz;
  236. }
  237. s = stop/sbot;
  238. for (i = 0; i < nz; i++) d[i] *= s;
  239. sm->scaling = s;
  240. sm->Lw->nz = nz;
  241. sm->Lwd->nz = nz;
  242. free(mask);
  243. free(avg_dist);
  244. SparseMatrix_delete(ID);
  245. return sm;
  246. }
  247. StressMajorizationSmoother SparseStressMajorizationSmoother_new(SparseMatrix A, int dim, double *x) {
  248. /* solve a stress model to achieve the ideal distance among a sparse set of edges recorded in A.
  249. A must be a real matrix.
  250. */
  251. int i, j, k, m = A->m, *ia, *ja, *iw, *jw, *id, *jd;
  252. int nz;
  253. double *d, *w, *lambda;
  254. double diag_d, diag_w, *a, dist, s = 0, stop = 0, sbot = 0;
  255. double xdot = 0;
  256. assert(SparseMatrix_is_symmetric(A, false) && A->type == MATRIX_TYPE_REAL);
  257. /* if x is all zero, make it random */
  258. for (i = 0; i < m*dim; i++) xdot += x[i]*x[i];
  259. if (xdot == 0){
  260. for (i = 0; i < m*dim; i++) x[i] = 72*drand();
  261. }
  262. ia = A->ia;
  263. ja = A->ja;
  264. a = A->a;
  265. StressMajorizationSmoother sm = gv_alloc(sizeof(struct StressMajorizationSmoother_struct));
  266. sm->scaling = 1.;
  267. sm->data = NULL;
  268. sm->scheme = SM_SCHEME_NORMAL;
  269. sm->D = A;
  270. sm->tol_cg = 0.01;
  271. sm->maxit_cg = floor(sqrt(A->m));
  272. lambda = sm->lambda = gv_calloc(m, sizeof(double));
  273. nz = A->nz;
  274. sm->Lw = SparseMatrix_new(m, m, nz + m, MATRIX_TYPE_REAL, FORMAT_CSR);
  275. sm->Lwd = SparseMatrix_new(m, m, nz + m, MATRIX_TYPE_REAL, FORMAT_CSR);
  276. if (!(sm->Lw) || !(sm->Lwd)) {
  277. StressMajorizationSmoother_delete(sm);
  278. return NULL;
  279. }
  280. iw = sm->Lw->ia; jw = sm->Lw->ja;
  281. id = sm->Lwd->ia; jd = sm->Lwd->ja;
  282. w = sm->Lw->a;
  283. d = sm->Lwd->a;
  284. iw[0] = id[0] = 0;
  285. nz = 0;
  286. for (i = 0; i < m; i++){
  287. diag_d = diag_w = 0;
  288. for (j = ia[i]; j < ia[i+1]; j++){
  289. k = ja[j];
  290. if (k != i){
  291. jw[nz] = k;
  292. dist = a[j];
  293. w[nz] = -1;
  294. diag_w += w[nz];
  295. jd[nz] = k;
  296. d[nz] = w[nz]*dist;
  297. stop += d[nz]*distance(x,dim,i,k);
  298. sbot += d[nz]*dist;
  299. diag_d += d[nz];
  300. nz++;
  301. }
  302. }
  303. jw[nz] = i;
  304. lambda[i] *= (-diag_w);/* alternatively don't do that then we have a constant penalty term scaled by lambda0 */
  305. w[nz] = -diag_w + lambda[i];
  306. jd[nz] = i;
  307. d[nz] = -diag_d;
  308. nz++;
  309. iw[i+1] = nz;
  310. id[i+1] = nz;
  311. }
  312. s = stop/sbot;
  313. if (s == 0) {
  314. StressMajorizationSmoother_delete(sm);
  315. return NULL;
  316. }
  317. for (i = 0; i < nz; i++) d[i] *= s;
  318. sm->scaling = s;
  319. sm->Lw->nz = nz;
  320. sm->Lwd->nz = nz;
  321. return sm;
  322. }
  323. static double total_distance(int m, int dim, double* x, double* y){
  324. double total = 0, dist = 0;
  325. int i, j;
  326. for (i = 0; i < m; i++){
  327. dist = 0.;
  328. for (j = 0; j < dim; j++){
  329. dist += (y[i*dim+j] - x[i*dim+j])*(y[i*dim+j] - x[i*dim+j]);
  330. }
  331. total += sqrt(dist);
  332. }
  333. return total;
  334. }
  335. void SparseStressMajorizationSmoother_delete(SparseStressMajorizationSmoother sm){
  336. StressMajorizationSmoother_delete(sm);
  337. }
  338. double SparseStressMajorizationSmoother_smooth(SparseStressMajorizationSmoother sm, int dim, double *x, int maxit_sm){
  339. return StressMajorizationSmoother_smooth(sm, dim, x, maxit_sm);
  340. }
  341. static void get_edge_label_matrix(relative_position_constraints data, int m, int dim, double *x, SparseMatrix *LL, double **rhs){
  342. int edge_labeling_scheme = data->edge_labeling_scheme;
  343. int n_constr_nodes = data->n_constr_nodes;
  344. int *constr_nodes = data->constr_nodes;
  345. SparseMatrix A_constr = data->A_constr;
  346. int *ia = A_constr->ia, *ja = A_constr->ja, ii, jj, nz, l, ll, i, j;
  347. int *irn = data->irn, *jcn = data->jcn;
  348. double *val = data->val, dist, kk, k;
  349. double *x00 = NULL;
  350. SparseMatrix Lc = NULL;
  351. double constr_penalty = data->constr_penalty;
  352. if (edge_labeling_scheme == ELSCHEME_PENALTY || edge_labeling_scheme == ELSCHEME_STRAIGHTLINE_PENALTY){
  353. /* for an node with two neighbors j--i--k, and assume i needs to be between j and k, then the contribution to P is
  354. . i j k
  355. i 1 -0.5 -0.5
  356. j -0.5 0.25 0.25
  357. k -0.5 0.25 0.25
  358. in general, if i has m neighbors j, k, ..., then
  359. p_ii = 1
  360. p_jj = 1/m^2
  361. p_ij = -1/m
  362. p jk = 1/m^2
  363. . i j k
  364. i 1 -1/m -1/m ...
  365. j -1/m 1/m^2 1/m^2 ...
  366. k -1/m 1/m^2 1/m^2 ...
  367. */
  368. if (!irn){
  369. assert((!jcn) && (!val));
  370. nz = 0;
  371. for (i = 0; i < n_constr_nodes; i++){
  372. ii = constr_nodes[i];
  373. k = ia[ii+1] - ia[ii];/*usually k = 2 */
  374. nz += (int)((k+1)*(k+1));
  375. }
  376. irn = data->irn = gv_calloc(nz, sizeof(int));
  377. jcn = data->jcn = gv_calloc(nz, sizeof(int));
  378. val = data->val = gv_calloc(nz, sizeof(double));
  379. }
  380. nz = 0;
  381. for (i = 0; i < n_constr_nodes; i++){
  382. ii = constr_nodes[i];
  383. jj = ja[ia[ii]]; ll = ja[ia[ii] + 1];
  384. if (jj == ll) continue; /* do not do loops */
  385. dist = distance_cropped(x, dim, jj, ll);
  386. dist *= dist;
  387. k = ia[ii+1] - ia[ii];/* usually k = 2 */
  388. kk = k*k;
  389. irn[nz] = ii; jcn[nz] = ii; val[nz++] = constr_penalty/(dist);
  390. k = constr_penalty/(k*dist); kk = constr_penalty/(kk*dist);
  391. for (j = ia[ii]; j < ia[ii+1]; j++){
  392. irn[nz] = ii; jcn[nz] = ja[j]; val[nz++] = -k;
  393. }
  394. for (j = ia[ii]; j < ia[ii+1]; j++){
  395. jj = ja[j];
  396. irn[nz] = jj; jcn[nz] = ii; val[nz++] = -k;
  397. for (l = ia[ii]; l < ia[ii+1]; l++){
  398. ll = ja[l];
  399. irn[nz] = jj; jcn[nz] = ll; val[nz++] = kk;
  400. }
  401. }
  402. }
  403. Lc = SparseMatrix_from_coordinate_arrays(nz, m, m, irn, jcn, val, MATRIX_TYPE_REAL, sizeof(double));
  404. } else if (edge_labeling_scheme == ELSCHEME_PENALTY2 || edge_labeling_scheme == ELSCHEME_STRAIGHTLINE_PENALTY2){
  405. /* for an node with two neighbors j--i--k, and assume i needs to be between the old position of j and k, then the contribution to P is
  406. 1/d_jk, and to the right hand side: {0,...,average_position_of_i's neighbor if i is an edge node,...}
  407. */
  408. if (!irn){
  409. assert((!jcn) && (!val));
  410. nz = n_constr_nodes;
  411. irn = data->irn = gv_calloc(nz, sizeof(int));
  412. jcn = data->jcn = gv_calloc(nz, sizeof(int));
  413. val = data->val = gv_calloc(nz, sizeof(double));
  414. }
  415. x00 = gv_calloc(m * dim, sizeof(double));
  416. nz = 0;
  417. for (i = 0; i < n_constr_nodes; i++){
  418. ii = constr_nodes[i];
  419. jj = ja[ia[ii]]; ll = ja[ia[ii] + 1];
  420. dist = distance_cropped(x, dim, jj, ll);
  421. irn[nz] = ii; jcn[nz] = ii; val[nz++] = constr_penalty/(dist);
  422. for (j = ia[ii]; j < ia[ii+1]; j++){
  423. jj = ja[j];
  424. for (l = 0; l < dim; l++){
  425. x00[ii*dim+l] += x[jj*dim+l];
  426. }
  427. }
  428. for (l = 0; l < dim; l++) {
  429. x00[ii*dim+l] *= constr_penalty/(dist)/(ia[ii+1] - ia[ii]);
  430. }
  431. }
  432. Lc = SparseMatrix_from_coordinate_arrays(nz, m, m, irn, jcn, val, MATRIX_TYPE_REAL, sizeof(double));
  433. }
  434. *LL = Lc;
  435. *rhs = x00;
  436. }
  437. static UNUSED double get_stress(int m, int dim, int *iw, int *jw, double *w,
  438. double *d, double *x, double scaling) {
  439. int i, j;
  440. double res = 0., dist;
  441. /* we use the fact that d_ij = w_ij*graph_dist(i,j). Also, d_ij and x are scalinged by *scaling, so divide by it to get actual unscaled streee. */
  442. for (i = 0; i < m; i++){
  443. for (j = iw[i]; j < iw[i+1]; j++){
  444. if (i == jw[j]) {
  445. continue;
  446. }
  447. dist = d[j]/w[j];/* both negative*/
  448. res += -w[j]*(dist - distance(x, dim, i, jw[j]))*(dist - distance(x, dim, i, jw[j]));
  449. }
  450. }
  451. return 0.5*res/scaling/scaling;
  452. }
  453. double StressMajorizationSmoother_smooth(StressMajorizationSmoother sm, int dim, double *x, int maxit_sm) {
  454. SparseMatrix Lw = sm->Lw, Lwd = sm->Lwd, Lwdd = NULL;
  455. int i, j, k, m, *id, *jd, *iw, *jw, idiag, iter = 0;
  456. double *w, *dd, *d, *y = NULL, *x0 = NULL, *x00 = NULL, diag, diff = 1, *lambda = sm->lambda;
  457. SparseMatrix Lc = NULL;
  458. double dij, dist;
  459. const double tol = 0.001;
  460. Lwdd = SparseMatrix_copy(Lwd);
  461. m = Lw->m;
  462. x0 = calloc(dim*m, sizeof(double));
  463. if (!x0) goto RETURN;
  464. memcpy(x0, x, sizeof(double)*dim*m);
  465. y = calloc(dim*m, sizeof(double));
  466. if (!y) goto RETURN;
  467. id = Lwd->ia; jd = Lwd->ja;
  468. d = Lwd->a;
  469. dd = Lwdd->a;
  470. w = Lw->a;
  471. iw = Lw->ia; jw = Lw->ja;
  472. #ifdef DEBUG_PRINT
  473. if (Verbose) fprintf(stderr, "initial stress = %f\n", get_stress(m, dim, iw, jw, w, d, x, sm->scaling));
  474. #else
  475. (void)iw;
  476. (void)jw;
  477. #endif
  478. /* for the additional matrix L due to the position constraints */
  479. if (sm->scheme == SM_SCHEME_NORMAL_ELABEL){
  480. get_edge_label_matrix(sm->data, m, dim, x, &Lc, &x00);
  481. if (Lc) Lw = SparseMatrix_add(Lw, Lc);
  482. }
  483. while (iter++ < maxit_sm && diff > tol){
  484. for (i = 0; i < m; i++){
  485. idiag = -1;
  486. diag = 0.;
  487. for (j = id[i]; j < id[i+1]; j++){
  488. if (i == jd[j]) {
  489. idiag = j;
  490. continue;
  491. }
  492. dist = distance(x, dim, i, jd[j]);
  493. if (d[j] == 0){
  494. dd[j] = 0;
  495. } else {
  496. if (dist == 0){
  497. dij = d[j]/w[j];/* the ideal distance */
  498. /* perturb so points do not sit at the same place */
  499. for (k = 0; k < dim; k++) x[jd[j]*dim+k] += 0.0001*(drand()+.0001)*dij;
  500. dist = distance(x, dim, i, jd[j]);
  501. }
  502. dd[j] = d[j]/dist;
  503. }
  504. diag += dd[j];
  505. }
  506. assert(idiag >= 0);
  507. dd[idiag] = -diag;
  508. }
  509. /* solve (Lw+lambda*I) x = Lwdd y + lambda x0 */
  510. SparseMatrix_multiply_dense(Lwdd, x, y, dim);
  511. if (lambda){/* is there a penalty term? */
  512. for (i = 0; i < m; i++){
  513. for (j = 0; j < dim; j++){
  514. y[i*dim+j] += lambda[i]*x0[i*dim+j];
  515. }
  516. }
  517. }
  518. /* additional term added to the rhs */
  519. switch (sm->scheme){
  520. case SM_SCHEME_NORMAL_ELABEL: {
  521. for (i = 0; i < m; i++){
  522. for (j = 0; j < dim; j++){
  523. y[i*dim+j] += x00[i*dim+j];
  524. }
  525. }
  526. break;
  527. }
  528. default:
  529. break;
  530. }
  531. #ifdef DEBUG_PRINT
  532. if (Verbose) {
  533. fprintf(stderr, "stress1 = %g\n",get_stress(m, dim, iw, jw, w, d, x, sm->scaling));
  534. }
  535. #endif
  536. SparseMatrix_solve(Lw, dim, x, y, sm->tol_cg, sm->maxit_cg);
  537. #ifdef DEBUG_PRINT
  538. if (Verbose) fprintf(stderr, "stress2 = %g\n",get_stress(m, dim, iw, jw, w, d, y, sm->scaling));
  539. #endif
  540. diff = total_distance(m, dim, x, y)/sqrt(vector_product(m*dim, x, x));
  541. #ifdef DEBUG_PRINT
  542. if (Verbose){
  543. fprintf(stderr, "Outer iter = %d, cg res = %g, ||x_{k+1}-x_k||/||x_k|| = %g\n",iter, res, diff);
  544. }
  545. #endif
  546. memcpy(x, y, sizeof(double)*m*dim);
  547. }
  548. #ifdef DEBUG
  549. _statistics[1] += iter-1;
  550. #endif
  551. #ifdef DEBUG_PRINT
  552. if (Verbose) fprintf(stderr, "iter = %d, final stress = %f\n", iter, get_stress(m, dim, iw, jw, w, d, x, sm->scaling));
  553. #endif
  554. RETURN:
  555. SparseMatrix_delete(Lwdd);
  556. if (Lc) {
  557. SparseMatrix_delete(Lc);
  558. SparseMatrix_delete(Lw);
  559. }
  560. free(x0);
  561. free(y);
  562. free(x00);
  563. return diff;
  564. }
  565. void StressMajorizationSmoother_delete(StressMajorizationSmoother sm){
  566. if (!sm) return;
  567. if (sm->Lw) SparseMatrix_delete(sm->Lw);
  568. if (sm->Lwd) SparseMatrix_delete(sm->Lwd);
  569. free(sm->lambda);
  570. if (sm->data) sm->data_deallocator(sm->data);
  571. free(sm);
  572. }
  573. TriangleSmoother TriangleSmoother_new(SparseMatrix A, int dim, double *x,
  574. bool use_triangularization) {
  575. int i, j, k, m = A->m, *ia = A->ia, *ja = A->ja, *iw, *jw, jdiag, nz;
  576. SparseMatrix B;
  577. double *d, *w, diag_d, diag_w, dist;
  578. double s = 0, stop = 0, sbot = 0;
  579. assert(SparseMatrix_is_symmetric(A, false));
  580. double *avg_dist = gv_calloc(m, sizeof(double));
  581. for (i = 0; i < m ;i++){
  582. avg_dist[i] = 0;
  583. nz = 0;
  584. for (j = ia[i]; j < ia[i+1]; j++){
  585. if (i == ja[j]) continue;
  586. avg_dist[i] += distance(x, dim, i, ja[j]);
  587. nz++;
  588. }
  589. assert(nz > 0);
  590. avg_dist[i] /= nz;
  591. }
  592. TriangleSmoother sm = gv_alloc(sizeof(struct TriangleSmoother_struct));
  593. sm->scaling = 1;
  594. sm->data = NULL;
  595. sm->scheme = SM_SCHEME_NORMAL;
  596. sm->tol_cg = 0.01;
  597. sm->maxit_cg = floor(sqrt(A->m));
  598. double *lambda = sm->lambda = gv_calloc(m, sizeof(double));
  599. if (m > 2){
  600. if (use_triangularization){
  601. B= call_tri(m, x);
  602. } else {
  603. B= call_tri2(m, dim, x);
  604. }
  605. } else {
  606. B = SparseMatrix_copy(A);
  607. }
  608. sm->Lw = SparseMatrix_add(A, B);
  609. SparseMatrix_delete(B);
  610. sm->Lwd = SparseMatrix_copy(sm->Lw);
  611. if (!(sm->Lw) || !(sm->Lwd)) {
  612. TriangleSmoother_delete(sm);
  613. return NULL;
  614. }
  615. iw = sm->Lw->ia; jw = sm->Lw->ja;
  616. w = sm->Lw->a;
  617. d = sm->Lwd->a;
  618. for (i = 0; i < m; i++){
  619. diag_d = diag_w = 0;
  620. jdiag = -1;
  621. for (j = iw[i]; j < iw[i+1]; j++){
  622. k = jw[j];
  623. if (k == i){
  624. jdiag = j;
  625. continue;
  626. }
  627. /* w[j] = -1./(ia[i+1]-ia[i]+ia[ja[j]+1]-ia[ja[j]]);
  628. w[j] = -2./(avg_dist[i]+avg_dist[k]);
  629. w[j] = -1.*/;/* use unit weight for now, later can try 1/(deg(i)+deg(k)) */
  630. dist = pow(distance_cropped(x,dim,i,k),0.6);
  631. w[j] = 1/(dist*dist);
  632. diag_w += w[j];
  633. /* d[j] = w[j]*distance(x,dim,i,k);
  634. d[j] = w[j]*(avg_dist[i] + avg_dist[k])*0.5;*/
  635. d[j] = w[j]*dist;
  636. stop += d[j]*distance(x,dim,i,k);
  637. sbot += d[j]*dist;
  638. diag_d += d[j];
  639. }
  640. lambda[i] *= (-diag_w);
  641. assert(jdiag >= 0);
  642. w[jdiag] = -diag_w + lambda[i];
  643. d[jdiag] = -diag_d;
  644. }
  645. s = stop/sbot;
  646. for (i = 0; i < iw[m]; i++) d[i] *= s;
  647. sm->scaling = s;
  648. free(avg_dist);
  649. return sm;
  650. }
  651. void TriangleSmoother_delete(TriangleSmoother sm){
  652. StressMajorizationSmoother_delete(sm);
  653. }
  654. void TriangleSmoother_smooth(TriangleSmoother sm, int dim, double *x){
  655. StressMajorizationSmoother_smooth(sm, dim, x, 50);
  656. }
  657. /* ================================ spring and spring-electrical based smoother ================ */
  658. SpringSmoother SpringSmoother_new(SparseMatrix A, int dim, spring_electrical_control ctrl, double *x){
  659. int i, j, k, l, m = A->m, *ia = A->ia, *ja = A->ja, *id, *jd;
  660. int nz;
  661. double *d, *dd;
  662. SparseMatrix ID = NULL;
  663. assert(SparseMatrix_is_symmetric(A, false));
  664. ID = ideal_distance_matrix(A, dim, x);
  665. dd = ID->a;
  666. SpringSmoother sm = gv_alloc(sizeof(struct SpringSmoother_struct));
  667. int *mask = gv_calloc(m, sizeof(int));
  668. double *avg_dist = gv_calloc(m, sizeof(double));
  669. for (i = 0; i < m ;i++){
  670. avg_dist[i] = 0;
  671. nz = 0;
  672. for (j = ia[i]; j < ia[i+1]; j++){
  673. if (i == ja[j]) continue;
  674. avg_dist[i] += distance(x, dim, i, ja[j]);
  675. nz++;
  676. }
  677. assert(nz > 0);
  678. avg_dist[i] /= nz;
  679. }
  680. for (i = 0; i < m; i++) mask[i] = -1;
  681. nz = 0;
  682. for (i = 0; i < m; i++){
  683. mask[i] = i;
  684. for (j = ia[i]; j < ia[i+1]; j++){
  685. k = ja[j];
  686. if (mask[k] != i){
  687. mask[k] = i;
  688. nz++;
  689. }
  690. }
  691. for (j = ia[i]; j < ia[i+1]; j++){
  692. k = ja[j];
  693. for (l = ia[k]; l < ia[k+1]; l++){
  694. if (mask[ja[l]] != i){
  695. mask[ja[l]] = i;
  696. nz++;
  697. }
  698. }
  699. }
  700. }
  701. sm->D = SparseMatrix_new(m, m, nz, MATRIX_TYPE_REAL, FORMAT_CSR);
  702. if (!(sm->D)){
  703. SpringSmoother_delete(sm);
  704. return NULL;
  705. }
  706. id = sm->D->ia; jd = sm->D->ja;
  707. d = sm->D->a;
  708. id[0] = 0;
  709. nz = 0;
  710. for (i = 0; i < m; i++){
  711. mask[i] = i+m;
  712. for (j = ia[i]; j < ia[i+1]; j++){
  713. k = ja[j];
  714. if (mask[k] != i+m){
  715. mask[k] = i+m;
  716. jd[nz] = k;
  717. d[nz] = (avg_dist[i] + avg_dist[k])*0.5;
  718. d[nz] = dd[j];
  719. nz++;
  720. }
  721. }
  722. for (j = ia[i]; j < ia[i+1]; j++){
  723. k = ja[j];
  724. for (l = ia[k]; l < ia[k+1]; l++){
  725. if (mask[ja[l]] != i+m){
  726. mask[ja[l]] = i+m;
  727. jd[nz] = ja[l];
  728. d[nz] = (avg_dist[i] + 2*avg_dist[k] + avg_dist[ja[l]])*0.5;
  729. d[nz] = dd[j]+dd[l];
  730. nz++;
  731. }
  732. }
  733. }
  734. id[i+1] = nz;
  735. }
  736. sm->D->nz = nz;
  737. sm->ctrl = spring_electrical_control_new();
  738. *(sm->ctrl) = *ctrl;
  739. sm->ctrl->random_start = false;
  740. sm->ctrl->multilevels = 1;
  741. sm->ctrl->step /= 2;
  742. sm->ctrl->maxiter = 20;
  743. free(mask);
  744. free(avg_dist);
  745. SparseMatrix_delete(ID);
  746. return sm;
  747. }
  748. void SpringSmoother_delete(SpringSmoother sm){
  749. if (!sm) return;
  750. if (sm->D) SparseMatrix_delete(sm->D);
  751. if (sm->ctrl) spring_electrical_control_delete(sm->ctrl);
  752. }
  753. void SpringSmoother_smooth(SpringSmoother sm, SparseMatrix A, int dim, double *x){
  754. int flag = 0;
  755. spring_electrical_spring_embedding(dim, A, sm->D, sm->ctrl, x, &flag);
  756. assert(!flag);
  757. }
  758. /*=============================== end of spring and spring-electrical based smoother =========== */
  759. void post_process_smoothing(int dim, SparseMatrix A, spring_electrical_control ctrl, double *x) {
  760. #ifdef TIME
  761. clock_t cpu;
  762. #endif
  763. #ifdef TIME
  764. cpu = clock();
  765. #endif
  766. switch (ctrl->smoothing){
  767. case SMOOTHING_RNG:
  768. case SMOOTHING_TRIANGLE:{
  769. TriangleSmoother sm;
  770. if (A->m > 2) { /* triangles need at least 3 nodes */
  771. if (ctrl->smoothing == SMOOTHING_RNG){
  772. sm = TriangleSmoother_new(A, dim, x, false);
  773. } else {
  774. sm = TriangleSmoother_new(A, dim, x, true);
  775. }
  776. TriangleSmoother_smooth(sm, dim, x);
  777. TriangleSmoother_delete(sm);
  778. }
  779. break;
  780. }
  781. case SMOOTHING_STRESS_MAJORIZATION_GRAPH_DIST:
  782. case SMOOTHING_STRESS_MAJORIZATION_POWER_DIST:
  783. case SMOOTHING_STRESS_MAJORIZATION_AVG_DIST:
  784. {
  785. StressMajorizationSmoother sm;
  786. int dist_scheme = IDEAL_AVG_DIST;
  787. if (ctrl->smoothing == SMOOTHING_STRESS_MAJORIZATION_GRAPH_DIST){
  788. dist_scheme = IDEAL_GRAPH_DIST;
  789. } else if (ctrl->smoothing == SMOOTHING_STRESS_MAJORIZATION_AVG_DIST){
  790. dist_scheme = IDEAL_AVG_DIST;
  791. } else if (ctrl->smoothing == SMOOTHING_STRESS_MAJORIZATION_POWER_DIST){
  792. dist_scheme = IDEAL_POWER_DIST;
  793. }
  794. sm = StressMajorizationSmoother2_new(A, dim, 0.05, x, dist_scheme);
  795. StressMajorizationSmoother_smooth(sm, dim, x, 50);
  796. StressMajorizationSmoother_delete(sm);
  797. break;
  798. }
  799. case SMOOTHING_SPRING:{
  800. SpringSmoother sm = SpringSmoother_new(A, dim, ctrl, x);
  801. SpringSmoother_smooth(sm, A, dim, x);
  802. SpringSmoother_delete(sm);
  803. break;
  804. }
  805. }/* end switch between smoothing methods */
  806. #ifdef TIME
  807. if (Verbose) fprintf(stderr, "post processing %f\n",((double) (clock() - cpu)) / CLOCKS_PER_SEC);
  808. #endif
  809. }