blob: 29e41bd416a119ffce2e6776c7a3fd2c40d2ca53 [file] [log] [blame]
/*===================================================================*/
//
// place_qpsolver.c
//
// Philip Chong
// pchong@cadence.com
//
/*===================================================================*/
#include <assert.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include "place_qpsolver.h"
ABC_NAMESPACE_IMPL_START
#undef QPS_DEBUG
#define QPS_TOL 1.0e-3
#define QPS_EPS (QPS_TOL * QPS_TOL)
#define QPS_MAX_TOL 0.1
#define QPS_LOOP_TOL 1.0e-3
#define QPS_RELAX_ITER 180
#define QPS_MAX_ITER 200
#define QPS_STEPSIZE_RETRIES 2
#define QPS_MINSTEP 1.0e-6
#define QPS_DEC_CHANGE 0.01
#define QPS_PRECON
#define QPS_PRECON_EPS 1.0e-9
#undef QPS_HOIST
#if defined(QPS_DEBUG)
#define QPS_DEBUG_FILE "/tmp/qps_debug.log"
#endif
#if 0
/* ii is an array [0..p->num_cells-1] of indices from cells of original
problem to modified problem variables. If ii[k] >= 0, cell is an
independent cell; ii[k], ii[k]+1 are the indices of the corresponding
variables for the modified problem. If ii[k] == -1, cell is a fixed
cell. If ii[k] <= -2, cell is a dependent cell; -(ii[k]+2) is the index
of the corresponding COG constraint. */
int *ii;
/* gt is an array [0..p->cog_num-1] of indices from COG constraints to
locations in the gl array (in qps_problem_t). gt[k] is the offset into
gl where the kth constraint begins. */
int *gt;
/* n is the number of variables in the modified problem. n should be twice
the number of independent cells. */
int n;
qps_float_t *cp; /* current location during CG iteration */
qps_float_t f; /* value of cost function at p */
#endif
/**********************************************************************/
static void
qps_settp(qps_problem_t * p)
{
/* Fill in the p->priv_tp array with the current locations of all cells
(independent, dependent and fixed). */
int i;
int t, u;
int pr;
qps_float_t rx, ry;
qps_float_t ta;
int *ii = p->priv_ii;
qps_float_t *tp = p->priv_tp;
qps_float_t *cp = p->priv_cp;
/* do independent and fixed cells first */
for (i = p->num_cells; i--;) {
t = ii[i];
if (t >= 0) { /* indep cell */
tp[i * 2] = cp[t];
tp[i * 2 + 1] = cp[t + 1];
}
else if (t == -1) { /* fixed cell */
tp[i * 2] = p->x[i];
tp[i * 2 + 1] = p->y[i];
}
}
/* now do dependent cells */
for (i = p->num_cells; i--;) {
if (ii[i] < -1) {
t = -(ii[i] + 2); /* index of COG constraint */
ta = 0.0;
rx = 0.0;
ry = 0.0;
pr = p->priv_gt[t];
while ((u = p->cog_list[pr++]) >= 0) {
ta += p->area[u];
if (u != i) {
rx -= p->area[u] * tp[u * 2];
ry -= p->area[u] * tp[u * 2 + 1];
}
}
rx += p->cog_x[t] * ta;
ry += p->cog_y[t] * ta;
tp[i * 2] = rx / p->area[i];
tp[i * 2 + 1] = ry / p->area[i];
}
}
#if (QPS_DEBUG > 5)
fprintf(p->priv_fp, "### qps_settp()\n");
for (i = 0; i < p->num_cells; i++) {
fprintf(p->priv_fp, "%f %f\n", tp[i * 2], tp[i * 2 + 1]);
}
#endif
}
/**********************************************************************/
static qps_float_t
qps_func(qps_problem_t * p)
{
/* Return f(p). qps_settp() should have already been called before
entering here */
int j, k;
int pr;
qps_float_t jx, jy, tx, ty;
qps_float_t f;
qps_float_t w;
#if !defined(QPS_HOIST)
int i;
int st;
qps_float_t kx, ky, sx, sy;
qps_float_t t;
#endif
qps_float_t *tp = p->priv_tp;
f = 0.0;
pr = 0;
for (j = 0; j < p->num_cells; j++) {
jx = tp[j * 2];
jy = tp[j * 2 + 1];
while ((k = p->priv_cc[pr]) >= 0) {
w = p->priv_cw[pr];
tx = tp[k * 2] - jx;
ty = tp[k * 2 + 1] - jy;
f += w * (tx * tx + ty * ty);
pr++;
}
pr++;
}
p->f = f;
#if !defined(QPS_HOIST)
/* loop penalties */
pr = 0;
for (i = 0; i < p->loop_num; i++) {
t = 0.0;
j = st = p->loop_list[pr++];
jx = sx = tp[j * 2];
jy = sy = tp[j * 2 + 1];
while ((k = p->loop_list[pr]) >= 0) {
kx = tp[k * 2];
ky = tp[k * 2 + 1];
tx = jx - kx;
ty = jy - ky;
t += tx * tx + ty * ty;
j = k;
jx = kx;
jy = ky;
pr++;
}
tx = jx - sx;
ty = jy - sy;
t += tx * tx + ty * ty;
t -= p->loop_max[i];
#if (QPS_DEBUG > 5)
fprintf(p->priv_fp, "### qps_penalty() %d %f %f\n",
i, p->loop_max[i], t);
#endif
p->priv_lt[i] = t;
f += p->loop_penalty[i] * t;
pr++;
}
#endif /* QPS_HOIST */
if (p->max_enable) {
for (j = p->num_cells; j--;) {
f += p->priv_mxl[j] * (-tp[j * 2]);
f += p->priv_mxh[j] * (tp[j * 2] - p->max_x);
f += p->priv_myl[j] * (-tp[j * 2 + 1]);
f += p->priv_myh[j] * (tp[j * 2 + 1] - p->max_y);
}
}
#if (QPS_DEBUG > 5)
fprintf(p->priv_fp, "### qps_func() %f %f\n", f, p->f);
#endif
return f;
}
/**********************************************************************/
static void
qps_dfunc(qps_problem_t * p, qps_float_t * d)
{
/* Set d to grad f(p). First computes partial derivatives wrt all cells
then finds gradient wrt only the independent cells. qps_settp() should
have already been called before entering here */
int i, j, k;
int pr = 0;
qps_float_t jx, jy, kx, ky, tx, ty;
int ji, ki;
qps_float_t w;
#if !defined(QPS_HOIST)
qps_float_t sx, sy;
int st;
#endif
qps_float_t *tp = p->priv_tp;
qps_float_t *tp2 = p->priv_tp2;
/* compute partials and store in tp2 */
for (i = p->num_cells; i--;) {
tp2[i * 2] = 0.0;
tp2[i * 2 + 1] = 0.0;
}
for (j = 0; j < p->num_cells; j++) {
jx = tp[j * 2];
jy = tp[j * 2 + 1];
while ((k = p->priv_cc[pr]) >= 0) {
w = 2.0 * p->priv_cw[pr];
kx = tp[k * 2];
ky = tp[k * 2 + 1];
tx = w * (jx - kx);
ty = w * (jy - ky);
tp2[j * 2] += tx;
tp2[k * 2] -= tx;
tp2[j * 2 + 1] += ty;
tp2[k * 2 + 1] -= ty;
pr++;
}
pr++;
}
#if !defined(QPS_HOIST)
/* loop penalties */
pr = 0;
for (i = 0; i < p->loop_num; i++) {
j = st = p->loop_list[pr++];
jx = sx = tp[j * 2];
jy = sy = tp[j * 2 + 1];
w = 2.0 * p->loop_penalty[i];
while ((k = p->loop_list[pr]) >= 0) {
kx = tp[k * 2];
ky = tp[k * 2 + 1];
tx = w * (jx - kx);
ty = w * (jy - ky);
tp2[j * 2] += tx;
tp2[k * 2] -= tx;
tp2[j * 2 + 1] += ty;
tp2[k * 2 + 1] -= ty;
j = k;
jx = kx;
jy = ky;
pr++;
}
tx = w * (jx - sx);
ty = w * (jy - sy);
tp2[j * 2] += tx;
tp2[st * 2] -= tx;
tp2[j * 2 + 1] += ty;
tp2[st * 2 + 1] -= ty;
pr++;
}
#endif /* QPS_HOIST */
if (p->max_enable) {
for (j = p->num_cells; j--;) {
tp2[j * 2] += p->priv_mxh[j] - p->priv_mxl[j];
tp2[j * 2 + 1] += p->priv_myh[j] - p->priv_myl[j];
}
}
#if (QPS_DEBUG > 5)
fprintf(p->priv_fp, "### qps_dfunc() partials\n");
for (j = 0; j < p->num_cells; j++) {
fprintf(p->priv_fp, "%f %f\n", tp2[j * 2], tp2[j * 2 + 1]);
}
#endif
/* translate partials to independent variables */
for (j = p->priv_n; j--;) {
d[j] = 0.0;
}
for (j = p->num_cells; j--;) {
ji = p->priv_ii[j];
if (ji >= 0) { /* indep var */
d[ji] += tp2[j * 2];
d[ji + 1] += tp2[j * 2 + 1];
}
else if (ji < -1) { /* dependent variable */
ji = -(ji + 2); /* get COG index */
pr = p->priv_gt[ji];
while ((k = p->cog_list[pr]) >= 0) {
ki = p->priv_ii[k];
if (ki >= 0) {
w = p->priv_gw[pr];
#if (QPS_DEBUG > 0)
assert(fabs(w - p->area[k] / p->area[j]) < 1.0e-6);
#endif
d[ki] -= tp2[j * 2] * w;
d[ki + 1] -= tp2[j * 2 + 1] * w;
}
pr++;
}
}
}
#if (QPS_DEBUG > 5)
fprintf(p->priv_fp, "### qps_dfunc() gradient\n");
for (j = 0; j < p->priv_n; j++) {
fprintf(p->priv_fp, "%f\n", d[j]);
}
#endif
}
/**********************************************************************/
static void
qps_linmin(qps_problem_t * p, qps_float_t dgg, qps_float_t * h)
{
/* Perform line minimization. p->priv_cp is the current location, h is
direction of the gradient. Updates p->priv_cp to line minimal position
based on formulas from "Handbook of Applied Optimization", Pardalos and
Resende, eds., Oxford Univ. Press, 2002. qps_settp() should have
already been called before entering here. Since p->priv_cp is changed,
p->priv_tp array becomes invalid following this routine. */
int i, j, k;
int pr;
int ji, ki;
qps_float_t jx, jy, kx, ky;
qps_float_t f = 0.0;
qps_float_t w;
#if !defined(QPS_HOIST)
int st;
qps_float_t sx, sy, tx, ty;
qps_float_t t;
#endif
qps_float_t *tp = p->priv_tp;
/* translate h vector to partials over all variables and store in tp */
for (i = p->num_cells; i--;) {
tp[i * 2] = 0.0;
tp[i * 2 + 1] = 0.0;
}
for (j = p->num_cells; j--;) {
ji = p->priv_ii[j];
if (ji >= 0) { /* indep cell */
tp[j * 2] = h[ji];
tp[j * 2 + 1] = h[ji + 1];
}
else if (ji < -1) { /* dep cell */
ji = -(ji + 2); /* get COG index */
pr = p->priv_gt[ji];
while ((k = p->cog_list[pr]) >= 0) {
ki = p->priv_ii[k];
if (ki >= 0) {
w = p->priv_gw[pr];
#if (QPS_DEBUG > 0)
assert(fabs(w - p->area[k] / p->area[j]) < 1.0e-6);
#endif
tp[j * 2] -= h[ki] * w;
tp[j * 2 + 1] -= h[ki + 1] * w;
}
pr++;
}
}
}
/* take product x^T Z^T C Z x */
pr = 0;
for (j = 0; j < p->num_cells; j++) {
jx = tp[j * 2];
jy = tp[j * 2 + 1];
while ((k = p->priv_cc[pr]) >= 0) {
w = p->priv_cw[pr];
kx = tp[k * 2] - jx;
ky = tp[k * 2 + 1] - jy;
f += w * (kx * kx + ky * ky);
pr++;
}
pr++;
}
#if !defined(QPS_HOIST)
/* add loop penalties */
pr = 0;
for (i = 0; i < p->loop_num; i++) {
t = 0.0;
j = st = p->loop_list[pr++];
jx = sx = tp[j * 2];
jy = sy = tp[j * 2 + 1];
while ((k = p->loop_list[pr]) >= 0) {
kx = tp[k * 2];
ky = tp[k * 2 + 1];
tx = jx - kx;
ty = jy - ky;
t += tx * tx + ty * ty;
j = k;
jx = kx;
jy = ky;
pr++;
}
tx = jx - sx;
ty = jy - sy;
t += tx * tx + ty * ty;
f += p->loop_penalty[i] * t;
pr++;
}
#endif /* QPS_HOIST */
#if (QPS_DEBUG > 0)
assert(f);
#endif
/* compute step size */
f = (dgg / f) / 2.0;
for (j = p->priv_n; j--;) {
p->priv_cp[j] += f * h[j];
}
#if (QPS_DEBUG > 5)
fprintf(p->priv_fp, "### qps_linmin() step %f\n", f);
for (j = 0; j < p->priv_n; j++) {
fprintf(p->priv_fp, "%f\n", p->priv_cp[j]);
}
#endif
}
/**********************************************************************/
static void
qps_cgmin(qps_problem_t * p)
{
/* Perform CG minimization. Mostly from "Numerical Recipes", Press et al.,
Cambridge Univ. Press, 1992, with some changes to help performance in
our restricted problem domain. */
qps_float_t fp, gg, dgg, gam;
qps_float_t t;
int i, j;
int n = p->priv_n;
qps_float_t *g = p->priv_g;
qps_float_t *h = p->priv_h;
qps_float_t *xi = p->priv_xi;
qps_settp(p);
fp = qps_func(p);
qps_dfunc(p, g);
dgg = 0.0;
for (j = n; j--;) {
g[j] = -g[j];
h[j] = g[j];
#if defined(QPS_PRECON)
h[j] *= p->priv_pcgt[j];
#endif
dgg += g[j] * h[j];
}
for (i = 0; i < 2 * n; i++) {
#if (QPS_DEBUG > 5)
fprintf(p->priv_fp, "### qps_cgmin() top\n");
for (j = 0; j < p->priv_n; j++) {
fprintf(p->priv_fp, "%f\n", p->priv_cp[j]);
}
#endif
if (dgg == 0.0) {
break;
}
qps_linmin(p, dgg, h);
qps_settp(p);
p->priv_f = qps_func(p);
if (fabs((p->priv_f) - fp) <=
(fabs(p->priv_f) + fabs(fp) + QPS_EPS) * QPS_TOL / 2.0) {
break;
}
fp = p->priv_f;
qps_dfunc(p, xi);
gg = dgg;
dgg = 0.0;
for (j = n; j--;) {
t = xi[j] * xi[j];
#if defined(QPS_PRECON)
t *= p->priv_pcgt[j];
#endif
dgg += t;
}
gam = dgg / gg;
for (j = n; j--;) {
g[j] = -xi[j];
t = g[j];
#if defined(QPS_PRECON)
t *= p->priv_pcgt[j];
#endif
h[j] = t + gam * h[j];
}
}
#if (QPS_DEBUG > 0)
fprintf(p->priv_fp, "### CG ITERS=%d %d %d\n", i, p->cog_num, p->loop_num);
#endif
if (i == 2 * n) {
fprintf(stderr, "### Too many iterations in qps_cgmin()\n");
#if defined(QPS_DEBUG)
fprintf(p->priv_fp, "### Too many iterations in qps_cgmin()\n");
#endif
}
}
/**********************************************************************/
void
qps_init(qps_problem_t * p)
{
int i, j;
int pr, pw;
#if defined(QPS_DEBUG)
p->priv_fp = fopen(QPS_DEBUG_FILE, "a");
assert(p->priv_fp);
#endif
#if (QPS_DEBUG > 5)
fprintf(p->priv_fp, "### n=%d gn=%d ln=%d\n", p->num_cells, p->cog_num,
p->loop_num);
pr = 0;
fprintf(p->priv_fp, "### (c w) values\n");
for (i = 0; i < p->num_cells; i++) {
fprintf(p->priv_fp, "net %d: ", i);
while (p->connect[pr] >= 0) {
fprintf(p->priv_fp, "(%d %f) ", p->connect[pr], p->edge_weight[pr]);
pr++;
}
fprintf(p->priv_fp, "(-1 -1.0)\n");
pr++;
}
fprintf(p->priv_fp, "### (x y f) values\n");
for (i = 0; i < p->num_cells; i++) {
fprintf(p->priv_fp, "cell %d: (%f %f %d)\n", i, p->x[i], p->y[i],
p->fixed[i]);
}
#if 0
if (p->cog_num) {
fprintf(p->priv_fp, "### ga values\n");
for (i = 0; i < p->num_cells; i++) {
fprintf(p->priv_fp, "cell %d: (%f)\n", i, p->area[i]);
}
}
pr = 0;
fprintf(p->priv_fp, "### gl values\n");
for (i = 0; i < p->cog_num; i++) {
fprintf(p->priv_fp, "cog %d: ", i);
while (p->cog_list[pr] >= 0) {
fprintf(p->priv_fp, "%d ", p->cog_list[pr]);
pr++;
}
fprintf(p->priv_fp, "-1\n");
pr++;
}
fprintf(p->priv_fp, "### (gx gy) values\n");
for (i = 0; i < p->cog_num; i++) {
fprintf(p->priv_fp, "cog %d: (%f %f)\n", i, p->cog_x[i], p->cog_y[i]);
}
#endif
#endif /* QPS_DEBUG */
p->priv_ii = (int *)malloc(p->num_cells * sizeof(int));
assert(p->priv_ii);
p->max_enable = 0;
p->priv_fopt = 0.0;
/* canonify c and w */
pr = pw = 0;
for (i = 0; i < p->num_cells; i++) {
while ((j = p->connect[pr]) >= 0) {
if (j > i) {
pw++;
}
pr++;
}
pw++;
pr++;
}
p->priv_cc = (int *)malloc(pw * sizeof(int));
assert(p->priv_cc);
p->priv_cr = (int *)malloc(p->num_cells * sizeof(int));
assert(p->priv_cr);
p->priv_cw = (qps_float_t*)malloc(pw * sizeof(qps_float_t));
assert(p->priv_cw);
p->priv_ct = (qps_float_t*)malloc(pw * sizeof(qps_float_t));
assert(p->priv_ct);
p->priv_cm = pw;
pr = pw = 0;
for (i = 0; i < p->num_cells; i++) {
p->priv_cr[i] = pw;
while ((j = p->connect[pr]) >= 0) {
if (j > i) {
p->priv_cc[pw] = p->connect[pr];
p->priv_ct[pw] = p->edge_weight[pr];
pw++;
}
pr++;
}
p->priv_cc[pw] = -1;
p->priv_ct[pw] = -1.0;
pw++;
pr++;
}
assert(pw == p->priv_cm);
/* temp arrays for function eval */
p->priv_tp = (qps_float_t *) malloc(4 * p->num_cells * sizeof(qps_float_t));
assert(p->priv_tp);
p->priv_tp2 = p->priv_tp + 2 * p->num_cells;
}
/**********************************************************************/
static qps_float_t
qps_estopt(qps_problem_t * p)
{
int i, j, cell;
qps_float_t r;
qps_float_t *t1, *t2;
qps_float_t t;
if (p->max_enable) {
r = 0.0;
t1 = (qps_float_t *) malloc(2 * p->num_cells * sizeof(qps_float_t));
#if (QPS_DEBUG > 0)
assert(t1);
#endif
for (i = 2 * p->num_cells; i--;) {
t1[i] = 0.0;
}
j = 0;
for (i = 0; i < p->cog_num; i++) {
while ((cell = p->cog_list[j]) >= 0) {
t1[cell * 2] = p->cog_x[i];
t1[cell * 2 + 1] = p->cog_y[i];
j++;
}
j++;
}
t2 = p->priv_tp;
p->priv_tp = t1;
r = qps_func(p);
p->priv_tp = t2;
free(t1);
t = (p->max_x * p->max_x + p->max_y * p->max_y);
t *= p->num_cells;
for (i = p->num_cells; i--;) {
if (p->fixed[i]) {
r += t;
}
}
}
else {
r = p->priv_f;
}
if (p->loop_num) {
/* FIXME hacky */
r *= 8.0;
}
return r;
}
/**********************************************************************/
static void
qps_solve_inner(qps_problem_t * p)
{
int i;
qps_float_t t;
qps_float_t z;
qps_float_t pm1, pm2, tp;
qps_float_t *tw;
#if defined(QPS_HOIST)
int j, k;
qps_float_t jx, jy, kx, ky, sx, sy, tx, ty;
int pr, st;
#endif
tw = p->priv_cw;
#if defined(QPS_HOIST)
if (!p->loop_num) {
p->priv_cw = p->priv_ct;
}
else {
for(i=p->priv_cm; i--;) {
p->priv_cw[i] = p->priv_ct[i];
}
/* augment with loop penalties */
pr = 0;
for (i = 0; i < p->loop_num; i++) {
while ((j = p->priv_la[pr++]) != -1) {
if (j >= 0) {
p->priv_cw[j] += p->loop_penalty[i];
}
}
pr++;
}
}
#else /* !QPS_HOIST */
p->priv_cw = p->priv_ct;
#endif /* QPS_HOIST */
qps_cgmin(p);
if (p->max_enable || p->loop_num) {
if (p->max_enable == 1 || (p->loop_num && p->loop_k == 0)) {
p->priv_eps = 2.0;
p->priv_fmax = p->priv_f;
p->priv_fprev = p->priv_f;
p->priv_fopt = qps_estopt(p);
p->priv_pn = 0;
p->loop_fail = 0;
}
else {
if (p->priv_f < p->priv_fprev &&
(p->priv_fprev - p->priv_f) >
QPS_DEC_CHANGE * fabs(p->priv_fprev)) {
if (p->priv_pn++ >= QPS_STEPSIZE_RETRIES) {
p->priv_eps /= 2.0;
p->priv_pn = 0;
}
}
p->priv_fprev = p->priv_f;
if (p->priv_fmax < p->priv_f) {
p->priv_fmax = p->priv_f;
}
if (p->priv_f >= p->priv_fopt) {
p->priv_fopt = p->priv_fmax * 2.0;
p->loop_fail |= 2;
#if (QPS_DEBUG > 0)
fprintf(p->priv_fp, "### warning: changing fopt\n");
#endif
}
}
#if (QPS_DEBUG > 0)
fprintf(p->priv_fp, "### max_stat %.2e %.2e %.2e %.2e\n",
p->priv_f, p->priv_eps, p->priv_fmax, p->priv_fopt);
fflush(p->priv_fp);
#endif
}
p->loop_done = 1;
if (p->loop_num) {
#if (QPS_DEBUG > 0)
fprintf(p->priv_fp, "### begin_update %d\n", p->loop_k);
#endif
p->loop_k++;
#if defined(QPS_HOIST)
/* calc loop penalties */
pr = 0;
for (i = 0; i < p->loop_num; i++) {
t = 0.0;
j = st = p->loop_list[pr++];
jx = sx = p->priv_tp[j * 2];
jy = sy = p->priv_tp[j * 2 + 1];
while ((k = p->loop_list[pr]) >= 0) {
kx = p->priv_tp[k * 2];
ky = p->priv_tp[k * 2 + 1];
tx = jx - kx;
ty = jy - ky;
t += tx * tx + ty * ty;
j = k;
jx = kx;
jy = ky;
pr++;
}
tx = jx - sx;
ty = jy - sy;
t += tx * tx + ty * ty;
p->priv_lt[i] = t - p->loop_max[i];
pr++;
}
#endif /* QPS_HOIST */
/* check KKT conditions */
#if (QPS_DEBUG > 1)
for (i = p->loop_num; i--;) {
if (p->loop_penalty[i] != 0.0) {
fprintf(p->priv_fp, "### penalty %d %.2e\n", i, p->loop_penalty[i]);
}
}
#endif
t = 0.0;
for (i = p->loop_num; i--;) {
if (p->priv_lt[i] > 0.0 || p->loop_penalty[i] > 0.0) {
t += p->priv_lt[i] * p->priv_lt[i];
}
if (fabs(p->priv_lt[i]) < QPS_LOOP_TOL) {
#if (QPS_DEBUG > 4)
fprintf(p->priv_fp, "### skip %d %f\n", i, p->priv_lt[i]);
#endif
continue;
}
z = QPS_LOOP_TOL * p->loop_max[i];
if (p->priv_lt[i] > z || (p->loop_k < QPS_RELAX_ITER &&
p->loop_penalty[i] * p->priv_lt[i] < -z)) {
p->loop_done = 0;
#if (QPS_DEBUG > 1)
fprintf(p->priv_fp, "### not_done %d %f %f %f %f\n", i,
p->priv_lt[i], z, p->loop_max[i], p->loop_penalty[i]);
#endif
}
#if (QPS_DEBUG > 5)
else {
fprintf(p->priv_fp, "### done %d %f %f %f %f\n", i,
p->priv_lt[i], z, p->loop_max[i], p->loop_penalty[i]);
}
#endif
}
/* update penalties */
if (!p->loop_done) {
t = p->priv_eps * (p->priv_fopt - p->priv_f) / t;
tp = 0.0;
for (i = p->loop_num; i--;) {
pm1 = p->loop_penalty[i];
#if (QPS_DEBUG > 5)
fprintf(p->priv_fp, "### update %d %.2e %.2e %.2e %.2e %.2e\n", i,
t, p->priv_lt[i], t * p->priv_lt[i], pm1, p->loop_max[i]);
#endif
p->loop_penalty[i] += t * p->priv_lt[i];
if (p->loop_penalty[i] < 0.0) {
p->loop_penalty[i] = 0.0;
}
pm2 = p->loop_penalty[i];
tp += fabs(pm1 - pm2);
}
#if (QPS_DEBUG > 4)
fprintf(p->priv_fp, "### penalty mag %f\n", tp);
#endif
}
}
p->max_done = 1;
if (p->max_enable) {
#if (QPS_DEBUG > 4)
fprintf(p->priv_fp, "### begin_max_update %d\n", p->max_enable);
#endif
t = 0.0;
for (i = p->num_cells; i--;) {
z = -(p->x[i]);
t += z * z;
if (z > QPS_TOL || (p->max_enable < QPS_RELAX_ITER &&
p->priv_mxl[i] * z < -QPS_MAX_TOL)) {
p->max_done = 0;
#if (QPS_DEBUG > 4)
fprintf(p->priv_fp, "### nxl %d %f %f\n", i, z, p->priv_mxl[i]);
#endif
}
z = (p->x[i] - p->max_x);
t += z * z;
if (z > QPS_TOL || (p->max_enable < QPS_RELAX_ITER &&
p->priv_mxh[i] * z < -QPS_MAX_TOL)) {
p->max_done = 0;
#if (QPS_DEBUG > 4)
fprintf(p->priv_fp, "### nxh %d %f %f\n", i, z, p->priv_mxh[i]);
#endif
}
z = -(p->y[i]);
t += z * z;
if (z > QPS_TOL || (p->max_enable < QPS_RELAX_ITER &&
p->priv_myl[i] * z < -QPS_MAX_TOL)) {
p->max_done = 0;
#if (QPS_DEBUG > 4)
fprintf(p->priv_fp, "### nyl %d %f %f\n", i, z, p->priv_myl[i]);
#endif
}
z = (p->y[i] - p->max_y);
t += z * z;
if (z > QPS_TOL || (p->max_enable < QPS_RELAX_ITER &&
p->priv_myh[i] * z < -QPS_MAX_TOL)) {
p->max_done = 0;
#if (QPS_DEBUG > 4)
fprintf(p->priv_fp, "### nyh %d %f %f\n", i, z, p->priv_myh[i]);
#endif
}
}
#if (QPS_DEBUG > 4)
fprintf(p->priv_fp, "### max_done %d %f\n", p->max_done, t);
#endif
if (!p->max_done) {
t = p->priv_eps * (p->priv_fopt - p->priv_f) / t;
tp = 0.0;
for (i = p->num_cells; i--;) {
z = -(p->x[i]);
pm1 = p->priv_mxl[i];
p->priv_mxl[i] += t * z;
if (p->priv_mxl[i] < 0.0) {
p->priv_mxl[i] = 0.0;
}
pm2 = p->priv_mxl[i];
tp += fabs(pm1 - pm2);
z = (p->x[i] - p->max_x);
pm1 = p->priv_mxh[i];
p->priv_mxh[i] += t * z;
if (p->priv_mxh[i] < 0.0) {
p->priv_mxh[i] = 0.0;
}
pm2 = p->priv_mxh[i];
tp += fabs(pm1 - pm2);
z = -(p->y[i]);
pm1 = p->priv_myl[i];
p->priv_myl[i] += t * z;
if (p->priv_myl[i] < 0.0) {
p->priv_myl[i] = 0.0;
}
pm2 = p->priv_myl[i];
tp += fabs(pm1 - pm2);
z = (p->y[i] - p->max_y);
pm1 = p->priv_myh[i];
p->priv_myh[i] += t * z;
if (p->priv_myh[i] < 0.0) {
p->priv_myh[i] = 0.0;
}
pm2 = p->priv_myh[i];
tp += fabs(pm1 - pm2);
}
}
#if (QPS_DEBUG > 4)
for (i = p->num_cells; i--;) {
fprintf(p->priv_fp, "### max_penalty %d %f %f %f %f\n", i,
p->priv_mxl[i], p->priv_mxh[i], p->priv_myl[i], p->priv_myh[i]);
}
#endif
p->max_enable++;
}
if (p->loop_k >= QPS_MAX_ITER || p->priv_eps < QPS_MINSTEP) {
p->loop_fail |= 1;
}
if (p->loop_fail) {
p->loop_done = 1;
}
p->priv_cw = tw;
}
/**********************************************************************/
void
qps_solve(qps_problem_t * p)
{
int i, j;
int pr, pw;
qps_float_t bk;
int tk;
#if defined(QPS_PRECON)
int c;
qps_float_t t;
#endif
#if defined(QPS_HOIST)
int k;
int st;
int m1, m2;
#endif
if (p->max_enable) {
p->priv_mxl = (qps_float_t *)
malloc(4 * p->num_cells * sizeof(qps_float_t));
assert(p->priv_mxl);
p->priv_mxh = p->priv_mxl + p->num_cells;
p->priv_myl = p->priv_mxl + 2 * p->num_cells;
p->priv_myh = p->priv_mxl + 3 * p->num_cells;
for (i = 4 * p->num_cells; i--;) {
p->priv_mxl[i] = 0.0;
}
}
/* flag fixed cells with -1 */
for (i = p->num_cells; i--;) {
p->priv_ii[i] = (p->fixed[i]) ? (-1) : (0);
}
/* read gl and set up dependent variables */
if (p->cog_num) {
p->priv_gt = (int *)malloc(p->cog_num * sizeof(int));
assert(p->priv_gt);
p->priv_gm = (qps_float_t*)malloc(p->cog_num * sizeof(qps_float_t));
assert(p->priv_gm);
pr = 0;
for (i = 0; i < p->cog_num; i++) {
tk = -1;
bk = -1.0;
pw = pr;
while ((j = p->cog_list[pr++]) >= 0) {
if (!p->fixed[j]) {
/* use largest entry for numerical stability; see Gordian paper */
if (p->area[j] > bk) {
tk = j;
bk = p->area[j];
}
}
}
assert(bk > 0.0);
/* dependent variables have index=(-2-COG_constraint) */
p->priv_ii[tk] = -2 - i;
p->priv_gt[i] = pw;
p->priv_gm[i] = bk;
}
p->priv_gw = (qps_float_t*)malloc(pr * sizeof(qps_float_t));
assert(p->priv_gw);
pr = 0;
for (i = 0; i < p->cog_num; i++) {
while ((j = p->cog_list[pr]) >= 0) {
p->priv_gw[pr] = p->area[j] / p->priv_gm[i];
pr++;
}
p->priv_gw[pr] = -1.0;
pr++;
}
}
/* set up indexes from independent floating cells to variables */
p->priv_n = 0;
for (i = p->num_cells; i--;) {
if (!p->priv_ii[i]) {
p->priv_ii[i] = 2 * (p->priv_n++);
}
}
p->priv_n *= 2;
#if (QPS_DEBUG > 5)
for (i = 0; i < p->num_cells; i++) {
fprintf(p->priv_fp, "### ii %d %d\n", i, p->priv_ii[i]);
}
#endif
#if defined(QPS_PRECON)
p->priv_pcg = (qps_float_t *) malloc(p->num_cells * sizeof(qps_float_t));
assert(p->priv_pcg);
p->priv_pcgt = (qps_float_t *) malloc(p->priv_n * sizeof(qps_float_t));
assert(p->priv_pcgt);
for (i = p->num_cells; i--;) {
p->priv_pcg[i] = 0.0;
}
pr = 0;
for (i = 0; i < p->num_cells; i++) {
while ((c = p->priv_cc[pr]) >= 0) {
t = p->priv_ct[pr];
p->priv_pcg[i] += t;
p->priv_pcg[c] += t;
pr++;
}
pr++;
}
pr = 0;
for (i = 0; i < p->loop_num; i++) {
t = 2.0 * p->loop_penalty[i];
while ((c = p->loop_list[pr++]) >= 0) {
p->priv_pcg[c] += t;
}
pr++;
}
#if (QPS_DEBUG > 6)
for (i = p->num_cells; i--;) {
fprintf(p->priv_fp, "### precon %d %.2e\n", i, p->priv_pcg[i]);
}
#endif
for (i = p->priv_n; i--;) {
p->priv_pcgt[i] = 0.0;
}
for (i = 0; i < p->num_cells; i++) {
c = p->priv_ii[i];
if (c >= 0) {
t = p->priv_pcg[i];
p->priv_pcgt[c] += t;
p->priv_pcgt[c + 1] += t;
}
#if 0
else if (c < -1) {
pr = p->priv_gt[-(c+2)];
while ((j = p->cog_list[pr++]) >= 0) {
ji = p->priv_ii[j];
if (ji >= 0) {
w = p->area[j] / p->area[i];
t = w * w * p->priv_pcg[i];
p->priv_pcgt[ji] += t;
p->priv_pcgt[ji + 1] += t;
}
}
}
#endif
}
for (i = 0; i < p->priv_n; i++) {
t = p->priv_pcgt[i];
if (fabs(t) < QPS_PRECON_EPS || fabs(t) > 1.0/QPS_PRECON_EPS) {
p->priv_pcgt[i] = 1.0;
}
else {
p->priv_pcgt[i] = 1.0 / p->priv_pcgt[i];
}
}
#endif
/* allocate variable storage */
p->priv_cp = (qps_float_t *) malloc(4 * p->priv_n * sizeof(qps_float_t));
assert(p->priv_cp);
/* temp arrays for cg */
p->priv_g = p->priv_cp + p->priv_n;
p->priv_h = p->priv_cp + 2 * p->priv_n;
p->priv_xi = p->priv_cp + 3 * p->priv_n;
/* set values */
for (i = p->num_cells; i--;) {
if (p->priv_ii[i] >= 0) {
p->priv_cp[p->priv_ii[i]] = p->x[i];
p->priv_cp[p->priv_ii[i] + 1] = p->y[i];
}
}
if (p->loop_num) {
p->priv_lt = (qps_float_t *) malloc(p->loop_num * sizeof(qps_float_t));
assert(p->priv_lt);
#if defined(QPS_HOIST)
pr = 0;
for (i=p->loop_num; i--;) {
while (p->loop_list[pr++] >= 0) {
}
pr++;
}
p->priv_lm = pr;
p->priv_la = (int *) malloc(pr * sizeof(int));
assert(p->priv_la);
pr = 0;
for (i = 0; i < p->loop_num; i++) {
j = st = p->loop_list[pr++];
while ((k = p->loop_list[pr]) >= 0) {
if (j > k) {
m1 = k;
m2 = j;
}
else {
assert(k > j);
m1 = j;
m2 = k;
}
pw = p->priv_cr[m1];
while (p->priv_cc[pw] != m2) {
/* assert(p->priv_cc[pw] >= 0); */
if (p->priv_cc[pw] < 0) {
pw = -2;
break;
}
pw++;
}
p->priv_la[pr-1] = pw;
j = k;
pr++;
}
if (j > st) {
m1 = st;
m2 = j;
}
else {
assert(st > j);
m1 = j;
m2 = st;
}
pw = p->priv_cr[m1];
while (p->priv_cc[pw] != m2) {
/* assert(p->priv_cc[pw] >= 0); */
if (p->priv_cc[pw] < 0) {
pw = -2;
break;
}
pw++;
}
p->priv_la[pr-1] = pw;
p->priv_la[pr] = -1;
pr++;
}
#endif /* QPS_HOIST */
}
do {
qps_solve_inner(p);
} while (!p->loop_done || !p->max_done);
/* retrieve values */
/* qps_settp() should have already been called at this point */
for (i = p->num_cells; i--;) {
p->x[i] = p->priv_tp[i * 2];
p->y[i] = p->priv_tp[i * 2 + 1];
}
#if (QPS_DEBUG > 5)
for (i = p->num_cells; i--;) {
fprintf(p->priv_fp, "### cloc %d %f %f\n", i, p->x[i], p->y[i]);
}
#endif
free(p->priv_cp);
if (p->max_enable) {
free(p->priv_mxl);
}
if (p->cog_num) {
free(p->priv_gt);
free(p->priv_gm);
free(p->priv_gw);
}
if(p->loop_num) {
free(p->priv_lt);
#if defined(QPS_HOIST)
free(p->priv_la);
#endif
}
#if defined(QPS_PRECON)
free(p->priv_pcg);
free(p->priv_pcgt);
#endif
}
/**********************************************************************/
void
qps_clean(qps_problem_t * p)
{
free(p->priv_tp);
free(p->priv_ii);
free(p->priv_cc);
free(p->priv_cr);
free(p->priv_cw);
free(p->priv_ct);
#if defined(QPS_DEBUG)
fclose(p->priv_fp);
#endif /* QPS_DEBUG */
}
/**********************************************************************/
ABC_NAMESPACE_IMPL_END