48#define quad_prog_tol 1e-4
54constrained_majorization_vpsc(CMajEnvVPSC * e,
float *b,
float *place,
58 float *g, *old_place, *d;
62 const size_t n = e->nv + e->nldv;
63 bool converged =
false;
65 static int call_no = 0;
68 if (max_iterations == 0)
71 old_place = e->fArray2;
74 for (
size_t i = 0; i < n; i++) {
78 for (
size_t i = 0; i < n; i++) {
83 float prev_stress = 0;
84 for (
size_t i = 0; i < n; i++) {
85 prev_stress += 2 * b[i] * place[i];
86 for (
size_t j = 0; j < n; j++) {
87 prev_stress -= e->A[i][j] * place[j] * place[i];
90 FILE *logfile = fopen(
"constrained_majorization_log",
"a");
93 for (counter = 0; counter < max_iterations && !converged; counter++) {
96 float numerator = 0, denominator = 0, r;
99 for (
size_t i = 0; i < n; i++) {
100 old_place[i] = place[i];
102 for (
size_t j = 0; j < n; j++) {
103 g[i] -= 2 * e->A[i][j] * place[j];
106 for (
size_t i = 0; i < n; i++) {
107 numerator += g[i] * g[i];
109 for (
size_t j = 0; j < n; j++) {
110 r += 2 * e->A[i][j] * g[j];
112 denominator -= r * g[i];
114 if (denominator != 0)
115 alpha = numerator / denominator;
118 for (
size_t i = 0; i < n; i++) {
119 place[i] -=
alpha * g[i];
123 for (
size_t i = 0; i < n; i++) {
127 for (
size_t i = 0; i < n; i++) {
134 for (
size_t i = 0; i < n; i++) {
135 d[i] = place[i] - old_place[i];
138 numerator = 0, denominator = 0;
139 for (
size_t i = 0; i < n; i++) {
140 numerator += g[i] * d[i];
142 for (
size_t j = 0; j < n; j++) {
143 r += 2 * e->A[i][j] * d[j];
145 denominator += r * d[i];
148 beta = numerator / denominator;
152 for (
size_t i = 0; i < n; i++) {
156 if (beta > 0 && beta < 1.0) {
157 place[i] = old_place[i] + beta * d[i];
159 test += fabsf(place[i] - old_place[i]);
163 for (
size_t i = 0; i < n; i++) {
164 stress += 2 * b[i] * place[i];
165 for (
size_t j = 0; j < n; j++) {
166 stress -= e->A[i][j] * place[j] * place[i];
169 fprintf(logfile,
"%d: stress=%f, test=%f, %s\n", call_no, stress,
170 test, (stress >= prev_stress) ?
"No Improvement" :
"");
171 prev_stress = stress;
173 if (test > quad_prog_tol) {
184static DigColaLevel *assign_digcola_levels(
const int *ordering,
size_t n,
186 size_t num_divisions);
196CMajEnvVPSC *initCMajVPSC(
int n,
float *packedMat,
vtx_data *
graph,
197 ipsep_options * opt,
int diredges)
200 CMajEnvVPSC *e =
gv_alloc(
sizeof(CMajEnvVPSC));
204 e->nldv = 2 * opt->clusters.nclusters;
210 for (
int i = 0; i < n; i++) {
216 fprintf(stderr,
" generate edge constraints...\n");
217 for (
size_t i = 0; i < e->nv; i++) {
218 for (
size_t j = 1; j <
graph[i].nedges; j++) {
219 if (
graph[i].edists[j] > 0) {
226 for (
size_t i = 0; i < e->nv; i++) {
227 for (
size_t j = 1; j <
graph[i].nedges; j++) {
229 int v =
graph[i].edges[j];
230 if (
graph[i].edists[j] > 0) {
236 }
else if (diredges == 2) {
237 int *ordering =
NULL, *ls =
NULL, cvar;
239 DigColaLevel *levels;
242 if (compute_hierarchy(
graph, e->nv, 1e-2, 1e-1,
NULL, &ordering, &ls,
243 &e->ndv))
return NULL;
244 levels = assign_digcola_levels(ordering, e->nv, ls, e->ndv);
247 fprintf(stderr,
"Found %" PRISIZE_T " DiG-CoLa boundaries\n", e->ndv);
249 get_num_digcola_constraints(levels, e->ndv + 1) + e->ndv - 1;
253 for (
int i = 0; i < n; i++) {
258 for (
size_t i = 0; i < e->ndv; i++) {
263 halfgap = opt->edge_gap;
264 for (
size_t i = 0; i < e->ndv; i++) {
267 for (
int j = 0; j < levels[i].num_nodes; j++) {
273 for (
int j = 0; j < levels[i + 1].num_nodes; j++) {
276 e->vs[levels[i + 1].nodes[j]], halfgap);
280 for (
size_t i = 0; i < e->ndv - 1; i++) {
285 if (opt->clusters.nclusters > 0) {
287 const size_t nConCs = 2 * opt->clusters.nvars;
289 for (
size_t i = 0; i < e->gm; i++) {
294 for (
size_t i = 0; i < opt->clusters.nclusters; i++) {
295 for (
size_t j = 0; j < opt->clusters.clustersizes[i]; j++) {
296 Variable *v = e->vs[opt->clusters.clusters[i][j]];
297 Variable *cl = e->vs[e->nv + 2 * i];
298 Variable *cr = e->vs[e->nv + 2 * i + 1];
308 e->vpsc =
newIncVPSC(n + e->ndv, e->vs, e->gm, e->gcs);
312 if (packedMat !=
NULL) {
313 e->A = unpackMatrix(packedMat, n);
316 e->fArray1 =
gv_calloc(n,
sizeof(
float));
317 e->fArray2 =
gv_calloc(n,
sizeof(
float));
318 e->fArray3 =
gv_calloc(n,
sizeof(
float));
321 " initCMajVPSC done: %" PRISIZE_T " global constraints generated.\n",
326void deleteCMajEnvVPSC(CMajEnvVPSC * e)
334 if (e->cs != e->gcs && e->gcs !=
NULL)
337 for (
size_t i = 0; i < e->nv + e->nldv + e->ndv; i++) {
359void generateNonoverlapConstraints(CMajEnvVPSC * e,
363 bool transitiveClosure,
368 size_t n = e->nv + e->nldv;
370 bool genclusters = opt->clusters.nclusters > 0;
373 n -= 2 * opt->clusters.nclusters;
379 nsizeScale *= 1.0001f;
381 for (
size_t i = 0; i < n; i++) {
383 coords[0][i] - nsizeScale * opt->nsize[i].x / 2.0 -
386 coords[0][i] + nsizeScale * opt->nsize[i].x / 2.0 +
389 coords[1][i] - nsizeScale * opt->nsize[i].y / 2.0 -
392 coords[1][i] + nsizeScale * opt->nsize[i].y / 2.0 +
398 int* cm =
gv_calloc(opt->clusters.nclusters + 1,
sizeof(
int));
399 for (
size_t i = 0; i < opt->clusters.nclusters; i++) {
400 const size_t cn = opt->clusters.clustersizes[i];
405 container.
LL.
x = container.
LL.
y = DBL_MAX;
406 container.
UR.
x = container.
UR.
y = -DBL_MAX;
407 for (
size_t j = 0; j < cn; j++) {
408 int iv = opt->clusters.clusters[i][j];
410 B2BF(bb[iv], cbb[j]);
413 B2BF(container, opt->clusters.bb[i]);
414 cvs[cn] = e->vs[n + 2 * i];
415 cvs[cn + 1] = e->vs[n + 2 * i + 1];
416 B2BF(container, cbb[cn]);
417 B2BF(container, cbb[cn + 1]);
419 cbb[cn].
UR.
x = container.
LL.
x + 0.0001;
420 cbb[cn + 1].
LL.
x = container.
UR.
x - 0.0001;
425 cbb[cn].
UR.
y = container.
LL.
y + 0.0001;
426 cbb[cn + 1].
LL.
y = container.
UR.
y - 0.0001;
435 const size_t cn = opt->clusters.ntoplevel + opt->clusters.nclusters;
438 for (
size_t i = 0; i < opt->clusters.ntoplevel; i++) {
439 int iv = opt->clusters.toplevel[i];
441 B2BF(bb[iv], cbb[i]);
444 for (
size_t i = opt->clusters.ntoplevel; i < cn; i++) {
445 assert(i <= INT_MAX);
447 const size_t j = i - opt->clusters.ntoplevel;
448 B2BF(opt->clusters.bb[j], cbb[i]);
451 const size_t i = opt->clusters.nclusters;
456 const size_t i = opt->clusters.nclusters;
460 for (
size_t i = opt->clusters.ntoplevel; i < cn; i++) {
462 const size_t j = i - opt->clusters.ntoplevel;
470 dgap = -(cbb[i].
UR.
x - cbb[i].
LL.
x) / 2.0;
472 dgap = -(cbb[i].
UR.
y - cbb[i].
LL.
y) / 2.0;
500 mol += cm[opt->clusters.nclusters];
505 for (
size_t i = 0; i < opt->clusters.nclusters + 1; i++) {
507 for (
int j = 0; j < cm[i]; j++) {
508 *csolptr++ = cscl[i][j];
525 for (
size_t i = e->gm; i < e->m; i++) {
544 for (
size_t i = 0; i < e->m; i++) {
546 e->cs[i] = e->gcs[i];
548 e->cs[i] = csol[i - e->gm];
555 fprintf(stderr,
" generated %" PRISIZE_T " constraints\n", e->m);
556 e->vpsc =
newIncVPSC(e->nv + e->nldv + e->ndv, e->vs, e->m, e->cs);
564void removeoverlaps(
int n,
float **coords, ipsep_options * opt)
567 CMajEnvVPSC *e = initCMajVPSC(n,
NULL,
NULL, opt, 0);
568 generateNonoverlapConstraints(e, 1.0, coords, 0,
true, opt);
570 for (i = 0; i < n; i++) {
573 generateNonoverlapConstraints(e, 1.0, coords, 1,
false, opt);
575 for (i = 0; i < n; i++) {
578 deleteCMajEnvVPSC(e);
584static DigColaLevel *assign_digcola_levels(
const int *ordering,
size_t n,
586 size_t num_divisions) {
588 DigColaLevel *l =
gv_calloc(num_divisions + 1,
sizeof(DigColaLevel));
590 l[0].num_nodes = level_inds[0];
591 l[0].nodes =
gv_calloc(l[0].num_nodes,
sizeof(
int));
592 for (
int i = 0; i < l[0].num_nodes; i++) {
593 l[0].nodes[i] = ordering[i];
596 for (
size_t i = 1; i < num_divisions; i++) {
597 l[i].num_nodes = level_inds[i] - level_inds[i - 1];
598 l[i].nodes =
gv_calloc(l[i].num_nodes,
sizeof(
int));
599 for (j = 0; j < l[i].num_nodes; j++) {
600 l[i].nodes[j] = ordering[level_inds[i - 1] + j];
604 if (num_divisions > 0) {
605 l[num_divisions].num_nodes = n - level_inds[num_divisions - 1];
606 l[num_divisions].nodes =
gv_calloc(l[num_divisions].num_nodes,
sizeof(
int));
607 for (
int i = 0; i < l[num_divisions].num_nodes; i++) {
608 l[num_divisions].nodes[i] =
609 ordering[level_inds[num_divisions - 1] + i];
619int get_num_digcola_constraints(DigColaLevel *levels,
size_t num_levels) {
621 for (
size_t i = 1; i < num_levels; i++) {
622 nc += levels[i].num_nodes + levels[i - 1].num_nodes;
624 nc += levels[0].num_nodes + levels[num_levels - 1].num_nodes;
Memory allocation wrappers that exit on failure.
static void * gv_calloc(size_t nmemb, size_t size)
static void * gv_alloc(size_t size)
void setVariableDesiredPos(Variable *v, double desiredPos)
int genYConstraints(size_t n, boxf *bb, Variable **vs, Constraint ***cs)
Variable * newVariable(int id, double desiredPos, double weight)
Bridge for C programs to access solve_VPSC (which is in C++)
Constraint ** newConstraints(int m)
void deleteConstraint(Constraint *c)
VPSC * newIncVPSC(int n, Variable *vs[], int m, Constraint *cs[])
void deleteVariable(Variable *v)
Constraint * newConstraint(Variable *left, Variable *right, double gap)
void remapInConstraints(Variable *u, Variable *v, double dgap)
void remapOutConstraints(Variable *u, Variable *v, double dgap)
double getVariablePos(const Variable *v)
void deleteConstraints(size_t m, Constraint **cs)
void satisfyVPSC(VPSC *vpsc)
void deleteVPSC(VPSC *vpsc)
void solveVPSC(VPSC *vpsc)
int genXConstraints(size_t n, boxf *bb, Variable **vs, Constraint ***cs, bool transitiveClosure)
geometric functions (e.g. on points and boxes)
Agraph_t * graph(char *name)
Arithmetic helper functions.
static bool is_exactly_zero(double v)
is a value precisely 0.0?
static bool is_exactly_equal(double a, double b)
are two values precisely the same?
A constraint determines a minimum or exact spacing required between two variables.