| /*===================================================================*/ |
| // |
| // 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 |
| |