void better_start(void) { /* Calculates a better starting point, using a similar approach to CVXOPT. */ /* Not yet speed optimized. */ int i; double *x, *s, *z, *y; double alpha; work.block_33[0] = -1; /* Make sure sinvz is 1 to make hijacked KKT system ok. */ for (i = 0; i < 84; i++) work.s_inv_z[i] = 1; fill_KKT(); ldl_factor(); fillrhs_start(); /* Borrow work.lhs_aff for the solution. */ ldl_solve(work.rhs, work.lhs_aff); /* Don't do any refinement for now. Precision doesn't matter too much. */ x = work.lhs_aff; s = work.lhs_aff + 114; z = work.lhs_aff + 198; y = work.lhs_aff + 282; /* Just set x and y as is. */ for (i = 0; i < 114; i++) work.x[i] = x[i]; for (i = 0; i < 12; i++) work.y[i] = y[i]; /* Now complete the initialization. Start with s. */ /* Must have alpha > max(z). */ alpha = -1e99; for (i = 0; i < 84; i++) if (alpha < z[i]) alpha = z[i]; if (alpha < 0) { for (i = 0; i < 84; i++) work.s[i] = -z[i]; } else { alpha += 1; for (i = 0; i < 84; i++) work.s[i] = -z[i] + alpha; } /* Now initialize z. */ /* Now must have alpha > max(-z). */ alpha = -1e99; for (i = 0; i < 84; i++) if (alpha < -z[i]) alpha = -z[i]; if (alpha < 0) { for (i = 0; i < 84; i++) work.z[i] = z[i]; } else { alpha += 1; for (i = 0; i < 84; i++) work.z[i] = z[i] + alpha; } }
void refine(double *target, double *var) { int i, j; double *residual = work.buffer; double norm2; double *new_var = work.buffer2; for (j = 0; j < settings.refine_steps; j++) { norm2 = 0; matrix_multiply(residual, var); for (i = 0; i < 179; i++) { residual[i] = residual[i] - target[i]; norm2 += residual[i]*residual[i]; } #ifndef ZERO_LIBRARY_MODE if (settings.verbose_refinement) { if (j == 0) printf("Initial residual before refinement has norm squared %.6g.\n", norm2); else printf("After refinement we get squared norm %.6g.\n", norm2); } #endif /* Solve to find new_var = KKT \ (target - A*var). */ ldl_solve(residual, new_var); /* Update var += new_var, or var += KKT \ (target - A*var). */ for (i = 0; i < 179; i++) { var[i] -= new_var[i]; } } #ifndef ZERO_LIBRARY_MODE if (settings.verbose_refinement) { /* Check the residual once more, but only if we're reporting it, since */ /* it's expensive. */ norm2 = 0; matrix_multiply(residual, var); for (i = 0; i < 179; i++) { residual[i] = residual[i] - target[i]; norm2 += residual[i]*residual[i]; } if (j == 0) printf("Initial residual before refinement has norm squared %.6g.\n", norm2); else printf("After refinement we get squared norm %.6g.\n", norm2); } #endif }
long solve(void) { int i; int iter; double *dx, *ds, *dy, *dz; double minval; double alpha; work.converged = 0; setup_pointers(); pre_ops(); #ifndef ZERO_LIBRARY_MODE if (settings.verbose) printf("iter objv gap |Ax-b| |Gx+s-h| step\n"); #endif fillq(); fillh(); fillb(); if (settings.better_start) better_start(); else set_start(); for (iter = 0; iter < settings.max_iters; iter++) { for (i = 0; i < 84; i++) { work.s_inv[i] = 1.0 / work.s[i]; work.s_inv_z[i] = work.s_inv[i]*work.z[i]; } work.block_33[0] = 0; fill_KKT(); ldl_factor(); /* Affine scaling directions. */ fillrhs_aff(); ldl_solve(work.rhs, work.lhs_aff); refine(work.rhs, work.lhs_aff); /* Centering plus corrector directions. */ fillrhs_cc(); ldl_solve(work.rhs, work.lhs_cc); refine(work.rhs, work.lhs_cc); /* Add the two together and store in aff. */ for (i = 0; i < 294; i++) work.lhs_aff[i] += work.lhs_cc[i]; /* Rename aff to reflect its new meaning. */ dx = work.lhs_aff; ds = work.lhs_aff + 114; dz = work.lhs_aff + 198; dy = work.lhs_aff + 282; /* Find min(min(ds./s), min(dz./z)). */ minval = 0; for (i = 0; i < 84; i++) if (ds[i] < minval*work.s[i]) minval = ds[i]/work.s[i]; for (i = 0; i < 84; i++) if (dz[i] < minval*work.z[i]) minval = dz[i]/work.z[i]; /* Find alpha. */ if (-0.99 < minval) alpha = 1; else alpha = -0.99/minval; /* Update the primal and dual variables. */ for (i = 0; i < 114; i++) work.x[i] += alpha*dx[i]; for (i = 0; i < 84; i++) work.s[i] += alpha*ds[i]; for (i = 0; i < 84; i++) work.z[i] += alpha*dz[i]; for (i = 0; i < 12; i++) work.y[i] += alpha*dy[i]; work.gap = eval_gap(); work.eq_resid_squared = calc_eq_resid_squared(); work.ineq_resid_squared = calc_ineq_resid_squared(); #ifndef ZERO_LIBRARY_MODE if (settings.verbose) { work.optval = eval_objv(); printf("%3d %10.3e %9.2e %9.2e %9.2e % 6.4f\n", iter+1, work.optval, work.gap, sqrt(work.eq_resid_squared), sqrt(work.ineq_resid_squared), alpha); } #endif /* Test termination conditions. Requires optimality, and satisfied */ /* constraints. */ if ( (work.gap < settings.eps) && (work.eq_resid_squared <= settings.resid_tol*settings.resid_tol) && (work.ineq_resid_squared <= settings.resid_tol*settings.resid_tol) ) { work.converged = 1; work.optval = eval_objv(); return iter+1; } } return iter; }