00001
00002
00003
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "digcola.h"
00029 #ifdef IPSEPCOLA
00030 #include <math.h>
00031 #include <stdlib.h>
00032 #include <time.h>
00033 #include <stdio.h>
00034 #include <float.h>
00035 #include <assert.h>
00036 #include "matrix_ops.h"
00037 #include "kkutils.h"
00038 #include <csolve_VPSC.h>
00039 #include "quad_prog_vpsc.h"
00040 #include "quad_prog_solver.h"
00041
00042
00043 #define quad_prog_tol 1e-4
00044
00045
00046
00047
00048 int
00049 constrained_majorization_vpsc(CMajEnvVPSC * e, float *b, float *place,
00050 int max_iterations)
00051 {
00052 int i, j, counter;
00053 float *g, *old_place, *d;
00054
00055
00056
00057 int n = e->nv + e->nldv;
00058 boolean converged = FALSE;
00059 #ifdef CONMAJ_LOGGING
00060 static int call_no = 0;
00061 #endif
00062
00063 if (max_iterations == 0)
00064 return 0;
00065 g = e->fArray1;
00066 old_place = e->fArray2;
00067 d = e->fArray3;
00068
00069 if (e->m > 0) {
00070 for (i = 0; i < n; i++) {
00071 setVariableDesiredPos(e->vs[i], place[i]);
00072 }
00073
00074 satisfyVPSC(e->vpsc);
00075 for (i = 0; i < n; i++) {
00076 place[i] = getVariablePos(e->vs[i]);
00077
00078 }
00079
00080 }
00081 #ifdef CONMAJ_LOGGING
00082 float prev_stress = 0;
00083 for (i = 0; i < n; i++) {
00084 prev_stress += 2 * b[i] * place[i];
00085 for (j = 0; j < n; j++) {
00086 prev_stress -= e->A[i][j] * place[j] * place[i];
00087 }
00088 }
00089 FILE *logfile = fopen("constrained_majorization_log", "a");
00090
00091
00092 #endif
00093
00094 for (counter = 0; counter < max_iterations && !converged; counter++) {
00095 float test = 0;
00096 float alpha, beta;
00097 float numerator = 0, denominator = 0, r;
00098
00099 converged = TRUE;
00100
00101 for (i = 0; i < n; i++) {
00102 old_place[i] = place[i];
00103 g[i] = 2 * b[i];
00104 for (j = 0; j < n; j++) {
00105 g[i] -= 2 * e->A[i][j] * place[j];
00106 }
00107 }
00108 for (i = 0; i < n; i++) {
00109 numerator += g[i] * g[i];
00110 r = 0;
00111 for (j = 0; j < n; j++) {
00112 r += 2 * e->A[i][j] * g[j];
00113 }
00114 denominator -= r * g[i];
00115 }
00116 alpha = numerator / denominator;
00117 for (i = 0; i < n; i++) {
00118 place[i] -= alpha * g[i];
00119 }
00120 if (e->m > 0) {
00121
00122 for (i = 0; i < n; i++) {
00123 setVariableDesiredPos(e->vs[i], place[i]);
00124 }
00125 satisfyVPSC(e->vpsc);
00126 for (i = 0; i < n; i++) {
00127 place[i] = getVariablePos(e->vs[i]);
00128 }
00129 }
00130
00131
00132
00133 for (i = 0; i < n; i++) {
00134 d[i] = place[i] - old_place[i];
00135 }
00136
00137 numerator = 0, denominator = 0;
00138 for (i = 0; i < n; i++) {
00139 numerator += g[i] * d[i];
00140 r = 0;
00141 for (j = 0; j < n; j++) {
00142 r += 2 * e->A[i][j] * d[j];
00143 }
00144 denominator += r * d[i];
00145 }
00146 beta = numerator / denominator;
00147
00148 for (i = 0; i < n; i++) {
00149
00150
00151
00152 if (beta > 0 && beta < 1.0) {
00153 place[i] = old_place[i] + beta * d[i];
00154 }
00155 test += fabs(place[i] - old_place[i]);
00156 }
00157 #ifdef CONMAJ_LOGGING
00158 float stress = 0;
00159 for (i = 0; i < n; i++) {
00160 stress += 2 * b[i] * place[i];
00161 for (j = 0; j < n; j++) {
00162 stress -= e->A[i][j] * place[j] * place[i];
00163 }
00164 }
00165 fprintf(logfile, "%d: stress=%f, test=%f, %s\n", call_no, stress,
00166 test, (stress >= prev_stress) ? "No Improvement" : "");
00167 prev_stress = stress;
00168 #endif
00169 if (test > quad_prog_tol) {
00170 converged = FALSE;
00171 }
00172 }
00173 #ifdef CONMAJ_LOGGING
00174 call_no++;
00175 fclose(logfile);
00176 #endif
00177 return counter;
00178 }
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188 CMajEnvVPSC *initCMajVPSC(int n, float *packedMat, vtx_data * graph,
00189 ipsep_options * opt, int diredges)
00190 {
00191 int i, j;
00192
00193 int nConCs;
00194
00195 CMajEnvVPSC *e = GNEW(CMajEnvVPSC);
00196 e->A = NULL;
00197 e->packedMat = packedMat;
00198
00199
00200 e->nldv = 2 * opt->clusters->nclusters;
00201 e->nv = n - e->nldv;
00202 e->ndv = 0;
00203
00204 e->gcs = NULL;
00205 e->vs = N_GNEW(n, Variable *);
00206 for (i = 0; i < n; i++) {
00207 e->vs[i] = newVariable(i, 1.0, 1.0);
00208 }
00209 e->gm = 0;
00210 if (diredges == 1) {
00211 if (Verbose)
00212 fprintf(stderr, " generate edge constraints...\n");
00213 for (i = 0; i < e->nv; i++) {
00214 for (j = 1; j < graph[i].nedges; j++) {
00215
00216 if (graph[i].edists[j] > 0.01) {
00217 e->gm++;
00218 }
00219 }
00220 }
00221 e->gcs = newConstraints(e->gm);
00222 e->gm = 0;
00223 for (i = 0; i < e->nv; i++) {
00224 for (j = 1; j < graph[i].nedges; j++) {
00225 int u = i, v = graph[i].edges[j];
00226 if (graph[i].edists[j] > 0) {
00227 e->gcs[e->gm++] =
00228 newConstraint(e->vs[u], e->vs[v], opt->edge_gap);
00229 }
00230 }
00231 }
00232 } else if (diredges == 2) {
00233 int *ordering = NULL, *ls = NULL, cvar;
00234 double halfgap;
00235 DigColaLevel *levels;
00236 Variable **vs = e->vs;
00237
00238 compute_hierarchy(graph, n, 1e-2, 1e-1, NULL, &ordering, &ls,
00239 &e->ndv);
00240 levels = assign_digcola_levels(ordering, n, ls, e->ndv);
00241 if (Verbose)
00242 fprintf(stderr, "Found %d DiG-CoLa boundaries\n", e->ndv);
00243 e->gm =
00244 get_num_digcola_constraints(levels, e->ndv + 1) + e->ndv - 1;
00245 e->gcs = newConstraints(e->gm);
00246 e->gm = 0;
00247 e->vs = N_GNEW(n + e->ndv, Variable *);
00248 for (i = 0; i < n; i++) {
00249 e->vs[i] = vs[i];
00250 }
00251 free(vs);
00252
00253 for (i = 0; i < e->ndv; i++) {
00254
00255 cvar = n + i;
00256 e->vs[cvar] = newVariable(cvar, 1.0, 0.000001);
00257 }
00258 halfgap = opt->edge_gap;
00259 for (i = 0; i < e->ndv; i++) {
00260 cvar = n + i;
00261
00262 for (j = 0; j < levels[i].num_nodes; j++) {
00263 e->gcs[e->gm++] =
00264 newConstraint(e->vs[levels[i].nodes[j]], e->vs[cvar],
00265 halfgap);
00266 }
00267
00268 for (j = 0; j < levels[i + 1].num_nodes; j++) {
00269 e->gcs[e->gm++] =
00270 newConstraint(e->vs[cvar],
00271 e->vs[levels[i + 1].nodes[j]], halfgap);
00272 }
00273 }
00274
00275 for (i = 0; i < e->ndv - 1; i++) {
00276 e->gcs[e->gm++] =
00277 newConstraint(e->vs[n + i], e->vs[n + i + 1], 0);
00278 }
00279 }
00280
00281 if (opt->clusters->nclusters > 0) {
00282
00283 Constraint **ecs = e->gcs;
00284 nConCs = 2 * opt->clusters->nvars;
00285 e->gcs = newConstraints(e->gm + nConCs);
00286 for (i = 0; i < e->gm; i++) {
00287 e->gcs[i] = ecs[i];
00288 }
00289 if (ecs != NULL)
00290 deleteConstraints(0, ecs);
00291 for (i = 0; i < opt->clusters->nclusters; i++) {
00292 for (j = 0; j < opt->clusters->clustersizes[i]; j++) {
00293 Variable *v = e->vs[opt->clusters->clusters[i][j]];
00294 Variable *cl = e->vs[e->nv + 2 * i];
00295 Variable *cr = e->vs[e->nv + 2 * i + 1];
00296 e->gcs[e->gm++] = newConstraint(cl, v, 0);
00297 e->gcs[e->gm++] = newConstraint(v, cr, 0);
00298 }
00299 }
00300
00301 }
00302
00303 e->m = 0;
00304 e->cs = NULL;
00305 if (e->gm > 0) {
00306 e->vpsc = newIncVPSC(n + e->ndv, e->vs, e->gm, e->gcs);
00307 e->m = e->gm;
00308 e->cs = e->gcs;
00309 }
00310 if (packedMat != NULL) {
00311 e->A = unpackMatrix(packedMat, n);
00312 }
00313 #ifdef MOSEK
00314 e->mosekEnv = NULL;
00315 if (opt->mosek) {
00316 e->mosekEnv =
00317 mosek_init_sep(e->packedMat, n, e->ndv, e->gcs, e->gm);
00318 }
00319 #endif
00320
00321 e->fArray1 = N_GNEW(n, float);
00322 e->fArray2 = N_GNEW(n, float);
00323 e->fArray3 = N_GNEW(n, float);
00324 if (Verbose)
00325 fprintf(stderr,
00326 " initCMajVPSC done: %d global constraints generated.\n",
00327 e->m);
00328 return e;
00329 }
00330
00331 void deleteCMajEnvVPSC(CMajEnvVPSC * e)
00332 {
00333 int i;
00334 if (e->A != NULL) {
00335 free(e->A[0]);
00336 free(e->A);
00337 }
00338 if (e->m > 0) {
00339 deleteVPSC(e->vpsc);
00340 if (e->cs != e->gcs && e->gcs != NULL)
00341 deleteConstraints(0, e->gcs);
00342 deleteConstraints(e->m, e->cs);
00343 for (i = 0; i < e->nv + e->nldv + e->ndv; i++) {
00344 deleteVariable(e->vs[i]);
00345 }
00346 free(e->vs);
00347 }
00348 free(e->fArray1);
00349 free(e->fArray2);
00350 free(e->fArray3);
00351 #ifdef MOSEK
00352 if (e->mosekEnv) {
00353 mosek_delete(e->mosekEnv);
00354 }
00355 #endif
00356 free(e);
00357 }
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370 void generateNonoverlapConstraints(CMajEnvVPSC * e,
00371 float nsizeScale,
00372 float **coords,
00373 int k,
00374 boolean transitiveClosure,
00375 ipsep_options * opt)
00376 {
00377 Constraint **csol, **csolptr;
00378 int i, j, mol = 0;
00379 int n = e->nv + e->nldv;
00380 #ifdef WIN32
00381 boxf* bb = N_GNEW (n, boxf);
00382 #else
00383 boxf bb[n];
00384 #endif
00385 boolean genclusters = opt->clusters->nclusters > 0;
00386 if (genclusters) {
00387
00388 n -= 2 * opt->clusters->nclusters;
00389 }
00390 if (k == 0) {
00391
00392
00393
00394 nsizeScale *= 1.0001;
00395 }
00396 for (i = 0; i < n; i++) {
00397 bb[i].LL.x =
00398 coords[0][i] - nsizeScale * opt->nsize[i].x / 2.0 -
00399 opt->gap.x / 2.0;
00400 bb[i].UR.x =
00401 coords[0][i] + nsizeScale * opt->nsize[i].x / 2.0 +
00402 opt->gap.x / 2.0;
00403 bb[i].LL.y =
00404 coords[1][i] - nsizeScale * opt->nsize[i].y / 2.0 -
00405 opt->gap.y / 2.0;
00406 bb[i].UR.y =
00407 coords[1][i] + nsizeScale * opt->nsize[i].y / 2.0 +
00408 opt->gap.y / 2.0;
00409 }
00410 if (genclusters) {
00411 #ifdef WIN32
00412 Constraint ***cscl = N_GNEW(opt->clusters->nclusters + 1, Constraint**);
00413 int* cm = N_GNEW(opt->clusters->nclusters + 1, int);
00414 #else
00415 Constraint **cscl[opt->clusters->nclusters + 1];
00416 int cm[opt->clusters->nclusters + 1];
00417 #endif
00418 for (i = 0; i < opt->clusters->nclusters; i++) {
00419 int cn = opt->clusters->clustersizes[i];
00420 #ifdef WIN32
00421 Variable** cvs = N_GNEW(cn + 2, Variable*);
00422 boxf* cbb = N_GNEW(cn + 2, boxf);
00423 #else
00424 Variable *cvs[cn + 2];
00425 boxf cbb[cn + 2];
00426 #endif
00427
00428 boxf container;
00429 container.LL.x = container.LL.y = DBL_MAX;
00430 container.UR.x = container.UR.y = -DBL_MAX;
00431 for (j = 0; j < cn; j++) {
00432 int iv = opt->clusters->clusters[i][j];
00433 cvs[j] = e->vs[iv];
00434 B2BF(bb[iv], cbb[j]);
00435 EXPANDBB(container, bb[iv]);
00436 }
00437 B2BF(container, opt->clusters->bb[i]);
00438 cvs[cn] = e->vs[n + 2 * i];
00439 cvs[cn + 1] = e->vs[n + 2 * i + 1];
00440 B2BF(container, cbb[cn]);
00441 B2BF(container, cbb[cn + 1]);
00442 if (k == 0) {
00443 cbb[cn].UR.x = container.LL.x + 0.0001;
00444 cbb[cn + 1].LL.x = container.UR.x - 0.0001;
00445 cm[i] =
00446 genXConstraints(cn + 2, cbb, cvs, &cscl[i],
00447 transitiveClosure);
00448 } else {
00449 cbb[cn].UR.y = container.LL.y + 0.0001;
00450 cbb[cn + 1].LL.y = container.UR.y - 0.0001;
00451 cm[i] = genYConstraints(cn + 2, cbb, cvs, &cscl[i]);
00452 }
00453 mol += cm[i];
00454 #ifdef WIN32
00455 free (cvs);
00456 free (cbb);
00457 #endif
00458 }
00459
00460 {
00461 int cn = opt->clusters->ntoplevel + opt->clusters->nclusters;
00462 #ifdef WIN32
00463 Variable** cvs = N_GNEW(cn,Variable*);
00464 boxf* cbb = N_GNEW(cn, boxf);
00465 #else
00466 Variable *cvs[cn];
00467 boxf cbb[cn];
00468 #endif
00469 for (i = 0; i < opt->clusters->ntoplevel; i++) {
00470 int iv = opt->clusters->toplevel[i];
00471 cvs[i] = e->vs[iv];
00472 B2BF(bb[iv], cbb[i]);
00473 }
00474
00475 for (i = opt->clusters->ntoplevel; i < cn; i++) {
00476 cvs[i] = newVariable(123 + i, 1, 1);
00477 j = i - opt->clusters->ntoplevel;
00478 B2BF(opt->clusters->bb[j], cbb[i]);
00479 }
00480 i = opt->clusters->nclusters;
00481 if (k == 0) {
00482 cm[i] =
00483 genXConstraints(cn, cbb, cvs, &cscl[i],
00484 transitiveClosure);
00485 } else {
00486 cm[i] = genYConstraints(cn, cbb, cvs, &cscl[i]);
00487 }
00488
00489 for (i = opt->clusters->ntoplevel; i < cn; i++) {
00490 double dgap;
00491 j = i - opt->clusters->ntoplevel;
00492
00493
00494
00495
00496
00497
00498 if (k == 0) {
00499 dgap = -(cbb[i].UR.x - cbb[i].LL.x) / 2.0;
00500 } else {
00501 dgap = -(cbb[i].UR.y - cbb[i].LL.y) / 2.0;
00502 }
00503 remapInConstraints(cvs[i], e->vs[n + 2 * j], dgap);
00504 remapOutConstraints(cvs[i], e->vs[n + 2 * j + 1], dgap);
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527 deleteVariable(cvs[i]);
00528 }
00529 mol += cm[opt->clusters->nclusters];
00530 #ifdef WIN32
00531 free (cvs);
00532 free (cbb);
00533 #endif
00534 }
00535 csolptr = csol = newConstraints(mol);
00536 for (i = 0; i < opt->clusters->nclusters + 1; i++) {
00537
00538 for (j = 0; j < cm[i]; j++) {
00539 *csolptr++ = cscl[i][j];
00540 }
00541 deleteConstraints(0, cscl[i]);
00542 }
00543 #ifdef WIN32
00544 free (cscl);
00545 free (cm);
00546 #endif
00547 } else {
00548 if (k == 0) {
00549 mol = genXConstraints(n, bb, e->vs, &csol, transitiveClosure);
00550 } else {
00551 mol = genYConstraints(n, bb, e->vs, &csol);
00552 }
00553 }
00554
00555 if (e->m > 0) {
00556
00557 deleteVPSC(e->vpsc);
00558 for (i = e->gm == 0 ? 0 : e->gm; i < e->m; i++) {
00559
00560 deleteConstraint(e->cs[i]);
00561 }
00562
00563 if (e->cs != e->gcs)
00564 deleteConstraints(0, e->cs);
00565 }
00566
00567
00568
00569
00570
00571 if (e->gm == 0) {
00572 e->m = mol;
00573 e->cs = csol;
00574 } else {
00575 e->m = mol + e->gm;
00576 e->cs = newConstraints(e->m);
00577 for (i = 0; i < e->m; i++) {
00578 if (i < e->gm) {
00579 e->cs[i] = e->gcs[i];
00580 } else {
00581 e->cs[i] = csol[i - e->gm];
00582 }
00583 }
00584
00585 deleteConstraints(0, csol);
00586 }
00587 if (Verbose)
00588 fprintf(stderr, " generated %d constraints\n", e->m);
00589 e->vpsc = newIncVPSC(e->nv + e->nldv + e->ndv, e->vs, e->m, e->cs);
00590 #ifdef MOSEK
00591 if (opt->mosek) {
00592 if (e->mosekEnv != NULL) {
00593 mosek_delete(e->mosekEnv);
00594 }
00595 e->mosekEnv =
00596 mosek_init_sep(e->packedMat, e->nv + e->nldv, e->ndv, e->cs,
00597 e->m);
00598 }
00599 #endif
00600 #ifdef WIN32
00601 free (bb);
00602 #endif
00603 }
00604
00605
00606
00607
00608
00609 void removeoverlaps(int n, float **coords, ipsep_options * opt)
00610 {
00611 int i;
00612 CMajEnvVPSC *e = initCMajVPSC(n, NULL, NULL, opt, 0);
00613 generateNonoverlapConstraints(e, 1.0, coords, 0, TRUE, opt);
00614 solveVPSC(e->vpsc);
00615 for (i = 0; i < n; i++) {
00616 coords[0][i] = getVariablePos(e->vs[i]);
00617 }
00618 generateNonoverlapConstraints(e, 1.0, coords, 1, FALSE, opt);
00619 solveVPSC(e->vpsc);
00620 for (i = 0; i < n; i++) {
00621 coords[1][i] = getVariablePos(e->vs[i]);
00622 }
00623 deleteCMajEnvVPSC(e);
00624 }
00625
00626
00627
00628
00629 DigColaLevel *assign_digcola_levels(int *ordering, int n, int *level_inds,
00630 int num_divisions)
00631 {
00632 int i, j;
00633 DigColaLevel *l = N_GNEW(num_divisions + 1, DigColaLevel);
00634
00635 l[0].num_nodes = level_inds[0];
00636 l[0].nodes = N_GNEW(l[0].num_nodes, int);
00637 for (i = 0; i < l[0].num_nodes; i++) {
00638 l[0].nodes[i] = ordering[i];
00639 }
00640
00641 for (i = 1; i < num_divisions; i++) {
00642 l[i].num_nodes = level_inds[i] - level_inds[i - 1];
00643 l[i].nodes = N_GNEW(l[i].num_nodes, int);
00644 for (j = 0; j < l[i].num_nodes; j++) {
00645 l[i].nodes[j] = ordering[level_inds[i - 1] + j];
00646 }
00647 }
00648
00649 if (num_divisions > 0) {
00650 l[num_divisions].num_nodes = n - level_inds[num_divisions - 1];
00651 l[num_divisions].nodes = N_GNEW(l[num_divisions].num_nodes, int);
00652 for (i = 0; i < l[num_divisions].num_nodes; i++) {
00653 l[num_divisions].nodes[i] =
00654 ordering[level_inds[num_divisions - 1] + i];
00655 }
00656 }
00657 return l;
00658 }
00659 void delete_digcola_levels(DigColaLevel * l, int num_levels)
00660 {
00661 int i;
00662 for (i = 0; i < num_levels; i++) {
00663 free(l[i].nodes);
00664 }
00665 free(l);
00666 }
00667 void print_digcola_levels(FILE * logfile, DigColaLevel * levels,
00668 int num_levels)
00669 {
00670 int i, j;
00671 fprintf(logfile, "levels:\n");
00672 for (i = 0; i < num_levels; i++) {
00673 fprintf(logfile, " l[%d]:", i);
00674 for (j = 0; j < levels[i].num_nodes; j++) {
00675 fprintf(logfile, "%d ", levels[i].nodes[j]);
00676 }
00677 fprintf(logfile, "\n");
00678 }
00679 }
00680
00681
00682
00683
00684
00685 int get_num_digcola_constraints(DigColaLevel * levels, int num_levels)
00686 {
00687 int i, nc = 0;
00688 for (i = 1; i < num_levels; i++) {
00689 nc += levels[i].num_nodes + levels[i - 1].num_nodes;
00690 }
00691 nc += levels[0].num_nodes + levels[num_levels - 1].num_nodes;
00692 return nc;
00693 }
00694
00695 #endif