Graphviz  2.31.20130523.0446
lib/neatogen/quad_prog_vpsc.c
Go to the documentation of this file.
00001 /* $Id$ $Revision$ */
00002 /* vim:set shiftwidth=4 ts=8: */
00003 
00020 /**********************************************************
00021  *
00022  * Solve a quadratic function f(X) = X' e->A X + b X
00023  * subject to a set of separation constraints e->cs
00024  *
00025  * Tim Dwyer, 2006
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 /* #define CONMAJ_LOGGING 1 */
00043 #define quad_prog_tol 1e-4
00044 
00045 /*
00046  * Use gradient-projection to solve Variable Placement with Separation Constraints problem.
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     /* for laplacian computation need number of real vars and those
00055      * dummy vars included in lap
00056      */
00057     int n = e->nv + e->nldv;
00058     boolean converged = FALSE;
00059 #ifdef CONMAJ_LOGGING
00060     static int call_no = 0;
00061 #endif                          /* CONMAJ_LOGGING */
00062 
00063     if (max_iterations == 0)
00064         return 0;
00065     g = e->fArray1;
00066     old_place = e->fArray2;
00067     d = e->fArray3;
00068     /* fprintf(stderr,"Entered: constrained_majorization_vpsc, #constraints=%d\n",e->m); */
00069     if (e->m > 0) {
00070         for (i = 0; i < n; i++) {
00071             setVariableDesiredPos(e->vs[i], place[i]);
00072         }
00073         /* fprintf(stderr,"  calling satisfyVPSC...\n"); */
00074         satisfyVPSC(e->vpsc);
00075         for (i = 0; i < n; i++) {
00076             place[i] = getVariablePos(e->vs[i]);
00077             /* fprintf(stderr,"vs[%d]=%f\n",i,place[i]); */
00078         }
00079         /* fprintf(stderr,"    done.\n"); */
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     /* fprintf(logfile,"grad proj %d: stress=%f\n",call_no,prev_stress); */
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         /* fprintf(stderr,"."); */
00099         converged = TRUE;
00100         /* find steepest descent direction */
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         if (denominator != 0)
00117             alpha = numerator / denominator;
00118         else
00119             alpha = 1.0;
00120         for (i = 0; i < n; i++) {
00121             place[i] -= alpha * g[i];
00122         }
00123         if (e->m > 0) {
00124             /* project to constraint boundary */
00125             for (i = 0; i < n; i++) {
00126                 setVariableDesiredPos(e->vs[i], place[i]);
00127             }
00128             satisfyVPSC(e->vpsc);
00129             for (i = 0; i < n; i++) {
00130                 place[i] = getVariablePos(e->vs[i]);
00131             }
00132         }
00133         /* set place to the intersection of old_place-g and boundary and 
00134          * compute d, the vector from intersection pnt to projection pnt
00135          */
00136         for (i = 0; i < n; i++) {
00137             d[i] = place[i] - old_place[i];
00138         }
00139         /* now compute beta */
00140         numerator = 0, denominator = 0;
00141         for (i = 0; i < n; i++) {
00142             numerator += g[i] * d[i];
00143             r = 0;
00144             for (j = 0; j < n; j++) {
00145                 r += 2 * e->A[i][j] * d[j];
00146             }
00147             denominator += r * d[i];
00148         }
00149         if (denominator != 0.0)
00150             beta = numerator / denominator;
00151         else
00152             beta = 1.0;
00153 
00154         for (i = 0; i < n; i++) {
00155             /* beta > 1.0 takes us back outside the feasible region
00156              * beta < 0 clearly not useful and may happen due to numerical imp.
00157              */
00158             if (beta > 0 && beta < 1.0) {
00159                 place[i] = old_place[i] + beta * d[i];
00160             }
00161             test += fabs(place[i] - old_place[i]);
00162         }
00163 #ifdef CONMAJ_LOGGING
00164         float stress = 0;
00165         for (i = 0; i < n; i++) {
00166             stress += 2 * b[i] * place[i];
00167             for (j = 0; j < n; j++) {
00168                 stress -= e->A[i][j] * place[j] * place[i];
00169             }
00170         }
00171         fprintf(logfile, "%d: stress=%f, test=%f, %s\n", call_no, stress,
00172                 test, (stress >= prev_stress) ? "No Improvement" : "");
00173         prev_stress = stress;
00174 #endif
00175         if (test > quad_prog_tol) {
00176             converged = FALSE;
00177         }
00178     }
00179 #ifdef CONMAJ_LOGGING
00180     call_no++;
00181     fclose(logfile);
00182 #endif
00183     return counter;
00184 }
00185 
00186 /*
00187  * Set up environment and global constraints (dir-edge constraints, containment constraints
00188  * etc).
00189  *
00190  * diredges: 0=no dir edge constraints
00191  *           1=one separation constraint for each edge (in acyclic subgraph)
00192  *           2=DiG-CoLa level constraints
00193  */
00194 CMajEnvVPSC *initCMajVPSC(int n, float *packedMat, vtx_data * graph,
00195                           ipsep_options * opt, int diredges)
00196 {
00197     int i, j;
00198     /* nv is the number of real nodes */
00199     int nConCs;
00200     /* fprintf(stderr,"Entered initCMajVPSC\n"); */
00201     CMajEnvVPSC *e = GNEW(CMajEnvVPSC);
00202     e->A = NULL;
00203     e->packedMat = packedMat;
00204     /* if we have clusters then we'll need two constraints for each var in
00205      * a cluster */
00206     e->nldv = 2 * opt->clusters->nclusters;
00207     e->nv = n - e->nldv;
00208     e->ndv = 0;
00209 
00210     e->gcs = NULL;
00211     e->vs = N_GNEW(n, Variable *);
00212     for (i = 0; i < n; i++) {
00213         e->vs[i] = newVariable(i, 1.0, 1.0);
00214     }
00215     e->gm = 0;
00216     if (diredges == 1) {
00217         if (Verbose)
00218             fprintf(stderr, "  generate edge constraints...\n");
00219         for (i = 0; i < e->nv; i++) {
00220             for (j = 1; j < graph[i].nedges; j++) {
00221                 /* fprintf(stderr,"edist=%f\n",graph[i].edists[j]); */
00222                 if (graph[i].edists[j] > 0.01) {
00223                     e->gm++;
00224                 }
00225             }
00226         }
00227         e->gcs = newConstraints(e->gm);
00228         e->gm = 0;
00229         for (i = 0; i < e->nv; i++) {
00230             for (j = 1; j < graph[i].nedges; j++) {
00231                 int u = i, v = graph[i].edges[j];
00232                 if (graph[i].edists[j] > 0) {
00233                     e->gcs[e->gm++] =
00234                         newConstraint(e->vs[u], e->vs[v], opt->edge_gap);
00235                 }
00236             }
00237         }
00238     } else if (diredges == 2) {
00239         int *ordering = NULL, *ls = NULL, cvar;
00240         double halfgap;
00241         DigColaLevel *levels;
00242         Variable **vs = e->vs;
00243         /* e->ndv is the number of dummy variables required, one for each boundary */
00244         if (compute_hierarchy(graph, e->nv, 1e-2, 1e-1, NULL, &ordering, &ls,
00245                           &e->ndv)) return NULL;
00246         levels = assign_digcola_levels(ordering, e->nv, ls, e->ndv);
00247         if (Verbose)
00248             fprintf(stderr, "Found %d DiG-CoLa boundaries\n", e->ndv);
00249         e->gm =
00250             get_num_digcola_constraints(levels, e->ndv + 1) + e->ndv - 1;
00251         e->gcs = newConstraints(e->gm);
00252         e->gm = 0;
00253         e->vs = N_GNEW(n + e->ndv, Variable *);
00254         for (i = 0; i < n; i++) {
00255             e->vs[i] = vs[i];
00256         }
00257         free(vs);
00258         /* create dummy vars */
00259         for (i = 0; i < e->ndv; i++) {
00260             /* dummy vars should have 0 weight */
00261             cvar = n + i;
00262             e->vs[cvar] = newVariable(cvar, 1.0, 0.000001);
00263         }
00264         halfgap = opt->edge_gap;
00265         for (i = 0; i < e->ndv; i++) {
00266             cvar = n + i;
00267             /* outgoing constraints for each var in level below boundary */
00268             for (j = 0; j < levels[i].num_nodes; j++) {
00269                 e->gcs[e->gm++] =
00270                     newConstraint(e->vs[levels[i].nodes[j]], e->vs[cvar],
00271                                   halfgap);
00272             }
00273             /* incoming constraints for each var in level above boundary */
00274             for (j = 0; j < levels[i + 1].num_nodes; j++) {
00275                 e->gcs[e->gm++] =
00276                     newConstraint(e->vs[cvar],
00277                                   e->vs[levels[i + 1].nodes[j]], halfgap);
00278             }
00279         }
00280         /* constraints between adjacent boundary dummy vars */
00281         for (i = 0; i < e->ndv - 1; i++) {
00282             e->gcs[e->gm++] =
00283                 newConstraint(e->vs[n + i], e->vs[n + i + 1], 0);
00284         }
00285     }
00286     /* fprintf(stderr,"  generate edge constraints... done: n=%d,m=%d\n",e->n,e->gm); */
00287     if (opt->clusters->nclusters > 0) {
00288         /* fprintf(stderr,"  generate cluster containment constraints...\n"); */
00289         Constraint **ecs = e->gcs;
00290         nConCs = 2 * opt->clusters->nvars;
00291         e->gcs = newConstraints(e->gm + nConCs);
00292         for (i = 0; i < e->gm; i++) {
00293             e->gcs[i] = ecs[i];
00294         }
00295         if (ecs != NULL)
00296             deleteConstraints(0, ecs);
00297         for (i = 0; i < opt->clusters->nclusters; i++) {
00298             for (j = 0; j < opt->clusters->clustersizes[i]; j++) {
00299                 Variable *v = e->vs[opt->clusters->clusters[i][j]];
00300                 Variable *cl = e->vs[e->nv + 2 * i];
00301                 Variable *cr = e->vs[e->nv + 2 * i + 1];
00302                 e->gcs[e->gm++] = newConstraint(cl, v, 0);
00303                 e->gcs[e->gm++] = newConstraint(v, cr, 0);
00304             }
00305         }
00306         /* fprintf(stderr,"  containment constraints... done: \n"); */
00307     }
00308 
00309     e->m = 0;
00310     e->cs = NULL;
00311     if (e->gm > 0) {
00312         e->vpsc = newIncVPSC(n + e->ndv, e->vs, e->gm, e->gcs);
00313         e->m = e->gm;
00314         e->cs = e->gcs;
00315     }
00316     if (packedMat != NULL) {
00317         e->A = unpackMatrix(packedMat, n);
00318     }
00319 #ifdef MOSEK
00320     e->mosekEnv = NULL;
00321     if (opt->mosek) {
00322         e->mosekEnv =
00323             mosek_init_sep(e->packedMat, n, e->ndv, e->gcs, e->gm);
00324     }
00325 #endif
00326 
00327     e->fArray1 = N_GNEW(n, float);
00328     e->fArray2 = N_GNEW(n, float);
00329     e->fArray3 = N_GNEW(n, float);
00330     if (Verbose)
00331         fprintf(stderr,
00332                 "  initCMajVPSC done: %d global constraints generated.\n",
00333                 e->m);
00334     return e;
00335 }
00336 
00337 void deleteCMajEnvVPSC(CMajEnvVPSC * e)
00338 {
00339     int i;
00340     if (e->A != NULL) {
00341         free(e->A[0]);
00342         free(e->A);
00343     }
00344     if (e->m > 0) {
00345         deleteVPSC(e->vpsc);
00346         if (e->cs != e->gcs && e->gcs != NULL)
00347             deleteConstraints(0, e->gcs);
00348         deleteConstraints(e->m, e->cs);
00349         for (i = 0; i < e->nv + e->nldv + e->ndv; i++) {
00350             deleteVariable(e->vs[i]);
00351         }
00352         free(e->vs);
00353     }
00354     free(e->fArray1);
00355     free(e->fArray2);
00356     free(e->fArray3);
00357 #ifdef MOSEK
00358     if (e->mosekEnv) {
00359         mosek_delete(e->mosekEnv);
00360     }
00361 #endif                          /* MOSEK */
00362     free(e);
00363 }
00364 
00365 /* generate non-overlap constraints inside each cluster, including dummy
00366  * nodes at bounds of cluster
00367  * generate constraints again for top level nodes and clusters treating
00368  * clusters as rectangles of dim (l,r,b,t)
00369  * for each cluster map in-constraints to l out-constraints to r 
00370  *
00371  * For now, we'll keep the global containment constraints already
00372  * generated for each cluster, and simply generate non-overlap constraints
00373  * for all nodes and then an additional set of non-overlap constraints for
00374  * clusters that we'll map back to the dummy vars as above.
00375  */
00376 void generateNonoverlapConstraints(CMajEnvVPSC * e,
00377                                    float nsizeScale,
00378                                    float **coords,
00379                                    int k,
00380                                    boolean transitiveClosure,
00381                                    ipsep_options * opt)
00382 {
00383     Constraint **csol, **csolptr;
00384     int i, j, mol = 0;
00385     int n = e->nv + e->nldv;
00386 #ifdef WIN32
00387     boxf* bb = N_GNEW (n, boxf);
00388 #else
00389     boxf bb[n];
00390 #endif
00391     boolean genclusters = opt->clusters->nclusters > 0;
00392     if (genclusters) {
00393         /* n is the number of real variables, not dummy cluster vars */
00394         n -= 2 * opt->clusters->nclusters;
00395     }
00396     if (k == 0) {
00397         /* grow a bit in the x dimension, so that if overlap is resolved
00398          * horizontally then it won't be considered overlapping vertically
00399          */
00400         nsizeScale *= 1.0001;
00401     }
00402     for (i = 0; i < n; i++) {
00403         bb[i].LL.x =
00404             coords[0][i] - nsizeScale * opt->nsize[i].x / 2.0 -
00405             opt->gap.x / 2.0;
00406         bb[i].UR.x =
00407             coords[0][i] + nsizeScale * opt->nsize[i].x / 2.0 +
00408             opt->gap.x / 2.0;
00409         bb[i].LL.y =
00410             coords[1][i] - nsizeScale * opt->nsize[i].y / 2.0 -
00411             opt->gap.y / 2.0;
00412         bb[i].UR.y =
00413             coords[1][i] + nsizeScale * opt->nsize[i].y / 2.0 +
00414             opt->gap.y / 2.0;
00415     }
00416     if (genclusters) {
00417 #ifdef WIN32
00418         Constraint ***cscl = N_GNEW(opt->clusters->nclusters + 1, Constraint**);
00419         int* cm = N_GNEW(opt->clusters->nclusters + 1, int);
00420 #else
00421         Constraint **cscl[opt->clusters->nclusters + 1];
00422         int cm[opt->clusters->nclusters + 1];
00423 #endif
00424         for (i = 0; i < opt->clusters->nclusters; i++) {
00425             int cn = opt->clusters->clustersizes[i];
00426 #ifdef WIN32
00427             Variable** cvs = N_GNEW(cn + 2, Variable*);
00428             boxf* cbb = N_GNEW(cn + 2, boxf);
00429 #else
00430             Variable *cvs[cn + 2];
00431             boxf cbb[cn + 2];
00432 #endif
00433             /* compute cluster bounding bb */
00434             boxf container;
00435             container.LL.x = container.LL.y = DBL_MAX;
00436             container.UR.x = container.UR.y = -DBL_MAX;
00437             for (j = 0; j < cn; j++) {
00438                 int iv = opt->clusters->clusters[i][j];
00439                 cvs[j] = e->vs[iv];
00440                 B2BF(bb[iv], cbb[j]);
00441                 EXPANDBB(container, bb[iv]);
00442             }
00443             B2BF(container, opt->clusters->bb[i]);
00444             cvs[cn] = e->vs[n + 2 * i];
00445             cvs[cn + 1] = e->vs[n + 2 * i + 1];
00446             B2BF(container, cbb[cn]);
00447             B2BF(container, cbb[cn + 1]);
00448             if (k == 0) {
00449                 cbb[cn].UR.x = container.LL.x + 0.0001;
00450                 cbb[cn + 1].LL.x = container.UR.x - 0.0001;
00451                 cm[i] =
00452                     genXConstraints(cn + 2, cbb, cvs, &cscl[i],
00453                                     transitiveClosure);
00454             } else {
00455                 cbb[cn].UR.y = container.LL.y + 0.0001;
00456                 cbb[cn + 1].LL.y = container.UR.y - 0.0001;
00457                 cm[i] = genYConstraints(cn + 2, cbb, cvs, &cscl[i]);
00458             }
00459             mol += cm[i];
00460 #ifdef WIN32
00461             free (cvs);
00462             free (cbb);
00463 #endif
00464         }
00465         /* generate top level constraints */
00466         {
00467             int cn = opt->clusters->ntoplevel + opt->clusters->nclusters;
00468 #ifdef WIN32
00469             Variable** cvs = N_GNEW(cn,Variable*);
00470             boxf* cbb = N_GNEW(cn, boxf);
00471 #else
00472             Variable *cvs[cn];
00473             boxf cbb[cn];
00474 #endif
00475             for (i = 0; i < opt->clusters->ntoplevel; i++) {
00476                 int iv = opt->clusters->toplevel[i];
00477                 cvs[i] = e->vs[iv];
00478                 B2BF(bb[iv], cbb[i]);
00479             }
00480             /* make dummy variables for clusters */
00481             for (i = opt->clusters->ntoplevel; i < cn; i++) {
00482                 cvs[i] = newVariable(123 + i, 1, 1);
00483                 j = i - opt->clusters->ntoplevel;
00484                 B2BF(opt->clusters->bb[j], cbb[i]);
00485             }
00486             i = opt->clusters->nclusters;
00487             if (k == 0) {
00488                 cm[i] =
00489                     genXConstraints(cn, cbb, cvs, &cscl[i],
00490                                     transitiveClosure);
00491             } else {
00492                 cm[i] = genYConstraints(cn, cbb, cvs, &cscl[i]);
00493             }
00494             /* remap constraints from tmp dummy vars to cluster l and r vars */
00495             for (i = opt->clusters->ntoplevel; i < cn; i++) {
00496                 double dgap;
00497                 j = i - opt->clusters->ntoplevel;
00498                 /* dgap is the change in required constraint gap.
00499                  * since we are going from a source rectangle the size
00500                  * of the cluster bounding box to a zero width (in x dim,
00501                  * zero height in y dim) rectangle, the change will be
00502                  * half the bb width.
00503                  */
00504                 if (k == 0) {
00505                     dgap = -(cbb[i].UR.x - cbb[i].LL.x) / 2.0;
00506                 } else {
00507                     dgap = -(cbb[i].UR.y - cbb[i].LL.y) / 2.0;
00508                 }
00509                 remapInConstraints(cvs[i], e->vs[n + 2 * j], dgap);
00510                 remapOutConstraints(cvs[i], e->vs[n + 2 * j + 1], dgap);
00511                 /* there may be problems with cycles between
00512                  * cluster non-overlap and diredge constraints,
00513                  * to resolve:
00514                  * 
00515                  * for each constraint c:v->cvs[i]:
00516                  *   if exists diredge constraint u->v where u in c:
00517                  *     remap v->cl to cr->v (gap = height(v)/2)
00518                  *
00519                  * in = getInConstraints(cvs[i])
00520                  * for(c : in) {
00521                  *   assert(c.right==cvs[i]);
00522                  *   vin = getOutConstraints(v=c.left)
00523                  *   for(d : vin) {
00524                  *     if(d.left.cluster==i):
00525                  *       tmp = d.left
00526                  *       d.left = d.right
00527                  *       d.right = tmp
00528                  *       d.gap = height(d.right)/2
00529                  *   }
00530                  * }
00531                  *       
00532                  */
00533                 deleteVariable(cvs[i]);
00534             }
00535             mol += cm[opt->clusters->nclusters];
00536 #ifdef WIN32
00537             free (cvs);
00538             free (cbb);
00539 #endif
00540         }
00541         csolptr = csol = newConstraints(mol);
00542         for (i = 0; i < opt->clusters->nclusters + 1; i++) {
00543             /* copy constraints into csol */
00544             for (j = 0; j < cm[i]; j++) {
00545                 *csolptr++ = cscl[i][j];
00546             }
00547             deleteConstraints(0, cscl[i]);
00548         }
00549 #ifdef WIN32
00550         free (cscl);
00551         free (cm);
00552 #endif
00553     } else {
00554         if (k == 0) {
00555             mol = genXConstraints(n, bb, e->vs, &csol, transitiveClosure);
00556         } else {
00557             mol = genYConstraints(n, bb, e->vs, &csol);
00558         }
00559     }
00560     /* remove constraints from previous iteration */
00561     if (e->m > 0) {
00562         /* can't reuse instance of VPSC when constraints change! */
00563         deleteVPSC(e->vpsc);
00564         for (i = e->gm == 0 ? 0 : e->gm; i < e->m; i++) {
00565             /* delete previous overlap constraints */
00566             deleteConstraint(e->cs[i]);
00567         }
00568         /* just delete the array, not the elements */
00569         if (e->cs != e->gcs)
00570             deleteConstraints(0, e->cs);
00571     }
00572     /* if we have no global constraints then the overlap constraints
00573      * are all we have to worry about.
00574      * Otherwise, we have to copy the global and overlap constraints 
00575      * into the one array
00576      */
00577     if (e->gm == 0) {
00578         e->m = mol;
00579         e->cs = csol;
00580     } else {
00581         e->m = mol + e->gm;
00582         e->cs = newConstraints(e->m);
00583         for (i = 0; i < e->m; i++) {
00584             if (i < e->gm) {
00585                 e->cs[i] = e->gcs[i];
00586             } else {
00587                 e->cs[i] = csol[i - e->gm];
00588             }
00589         }
00590         /* just delete the array, not the elements */
00591         deleteConstraints(0, csol);
00592     }
00593     if (Verbose)
00594         fprintf(stderr, "  generated %d constraints\n", e->m);
00595     e->vpsc = newIncVPSC(e->nv + e->nldv + e->ndv, e->vs, e->m, e->cs);
00596 #ifdef MOSEK
00597     if (opt->mosek) {
00598         if (e->mosekEnv != NULL) {
00599             mosek_delete(e->mosekEnv);
00600         }
00601         e->mosekEnv =
00602             mosek_init_sep(e->packedMat, e->nv + e->nldv, e->ndv, e->cs,
00603                            e->m);
00604     }
00605 #endif
00606 #ifdef WIN32
00607     free (bb);
00608 #endif
00609 }
00610 
00611 /*
00612  * Statically remove overlaps, that is remove all overlaps by moving each node as
00613  * little as possible.
00614  */
00615 void removeoverlaps(int n, float **coords, ipsep_options * opt)
00616 {
00617     int i;
00618     CMajEnvVPSC *e = initCMajVPSC(n, NULL, NULL, opt, 0);
00619     generateNonoverlapConstraints(e, 1.0, coords, 0, TRUE, opt);
00620     solveVPSC(e->vpsc);
00621     for (i = 0; i < n; i++) {
00622         coords[0][i] = getVariablePos(e->vs[i]);
00623     }
00624     generateNonoverlapConstraints(e, 1.0, coords, 1, FALSE, opt);
00625     solveVPSC(e->vpsc);
00626     for (i = 0; i < n; i++) {
00627         coords[1][i] = getVariablePos(e->vs[i]);
00628     }
00629     deleteCMajEnvVPSC(e);
00630 }
00631 
00632 /*
00633  unpack the "ordering" array into an array of DigColaLevel
00634 */
00635 DigColaLevel *assign_digcola_levels(int *ordering, int n, int *level_inds,
00636                                     int num_divisions)
00637 {
00638     int i, j;
00639     DigColaLevel *l = N_GNEW(num_divisions + 1, DigColaLevel);
00640     /* first level */
00641     l[0].num_nodes = level_inds[0];
00642     l[0].nodes = N_GNEW(l[0].num_nodes, int);
00643     for (i = 0; i < l[0].num_nodes; i++) {
00644         l[0].nodes[i] = ordering[i];
00645     }
00646     /* second through second last level */
00647     for (i = 1; i < num_divisions; i++) {
00648         l[i].num_nodes = level_inds[i] - level_inds[i - 1];
00649         l[i].nodes = N_GNEW(l[i].num_nodes, int);
00650         for (j = 0; j < l[i].num_nodes; j++) {
00651             l[i].nodes[j] = ordering[level_inds[i - 1] + j];
00652         }
00653     }
00654     /* last level */
00655     if (num_divisions > 0) {
00656         l[num_divisions].num_nodes = n - level_inds[num_divisions - 1];
00657         l[num_divisions].nodes = N_GNEW(l[num_divisions].num_nodes, int);
00658         for (i = 0; i < l[num_divisions].num_nodes; i++) {
00659             l[num_divisions].nodes[i] =
00660                 ordering[level_inds[num_divisions - 1] + i];
00661         }
00662     }
00663     return l;
00664 }
00665 void delete_digcola_levels(DigColaLevel * l, int num_levels)
00666 {
00667     int i;
00668     for (i = 0; i < num_levels; i++) {
00669         free(l[i].nodes);
00670     }
00671     free(l);
00672 }
00673 void print_digcola_levels(FILE * logfile, DigColaLevel * levels,
00674                           int num_levels)
00675 {
00676     int i, j;
00677     fprintf(logfile, "levels:\n");
00678     for (i = 0; i < num_levels; i++) {
00679         fprintf(logfile, "  l[%d]:", i);
00680         for (j = 0; j < levels[i].num_nodes; j++) {
00681             fprintf(logfile, "%d ", levels[i].nodes[j]);
00682         }
00683         fprintf(logfile, "\n");
00684     }
00685 }
00686 
00687 /*********************
00688 get number of separation constraints based on the number of nodes in each level
00689 ie, num_sep_constraints = sum_i^{num_levels-1} (|L[i]|+|L[i+1]|)
00690 **********************/
00691 int get_num_digcola_constraints(DigColaLevel * levels, int num_levels)
00692 {
00693     int i, nc = 0;
00694     for (i = 1; i < num_levels; i++) {
00695         nc += levels[i].num_nodes + levels[i - 1].num_nodes;
00696     }
00697     nc += levels[0].num_nodes + levels[num_levels - 1].num_nodes;
00698     return nc;
00699 }
00700 
00701 #endif                          /* IPSEPCOLA */