vendor/scs/src/scs.c in scs-0.2.3 vs vendor/scs/src/scs.c in scs-0.3.0
- old
+ new
@@ -1,106 +1,124 @@
#include "scs.h"
-
#include "aa.h"
#include "ctrlc.h"
#include "glbopts.h"
#include "linalg.h"
#include "linsys.h"
#include "normalize.h"
#include "rw.h"
+#include "scs_matrix.h"
#include "util.h"
-SCS(timer) global_timer;
-
/* printing header */
static const char *HEADER[] = {
- " Iter ", " pri res ", " dua res ", " rel gap ",
- " pri obj ", " dua obj ", " kap/tau ", " time (s)",
+ " iter ", " pri res ", " dua res ", " gap ",
+ " obj ", " scale ", " time (s)",
};
static const scs_int HSPACE = 9;
-static const scs_int HEADER_LEN = 8;
-static const scs_int LINE_LEN = 76;
+static const scs_int HEADER_LEN = 7;
+static const scs_int LINE_LEN = 66;
-static scs_int scs_isnan(scs_float x) { return (x == NAN || x != x); }
+static void free_residuals(ScsResiduals *r) {
+ if (r) {
+ scs_free(r->ax);
+ scs_free(r->ax_s);
+ scs_free(r->px);
+ scs_free(r->aty);
+ scs_free(r->ax_s_btau);
+ scs_free(r->px_aty_ctau);
+ scs_free(r);
+ }
+}
static void free_work(ScsWork *w) {
if (w) {
scs_free(w->u);
- scs_free(w->u_best);
scs_free(w->u_t);
- scs_free(w->u_prev);
- /* Don't need these because u*, v* are contiguous in mem
- scs_free(w->v);
- scs_free(w->v_best);
- scs_free(w->v_prev);
- */
+ scs_free(w->v);
+ scs_free(w->v_prev);
+ scs_free(w->rsk);
scs_free(w->h);
scs_free(w->g);
- scs_free(w->b);
- scs_free(w->c);
- scs_free(w->pr);
- scs_free(w->dr);
+ scs_free(w->b_normalized);
+ scs_free(w->c_normalized);
+ scs_free(w->rho_y_vec);
+ scs_free(w->lin_sys_warm_start);
+ if (w->cone_boundaries) {
+ scs_free(w->cone_boundaries);
+ }
if (w->scal) {
scs_free(w->scal->D);
scs_free(w->scal->E);
scs_free(w->scal);
}
+ SCS(free_sol)(w->xys_orig);
+ free_residuals(w->r_orig);
+ if (w->stgs->normalize) {
+ SCS(free_sol)(w->xys_normalized);
+ free_residuals(w->r_normalized);
+ }
scs_free(w);
}
}
-static void print_init_header(const ScsData *d, const ScsCone *k) {
+static void print_init_header(const ScsData *d, const ScsCone *k,
+ const ScsSettings *stgs) {
scs_int i;
- ScsSettings *stgs = d->stgs;
char *cone_str = SCS(get_cone_header)(k);
- char *lin_sys_method = SCS(get_lin_sys_method)(d->A, d->stgs);
+ const char *lin_sys_method = SCS(get_lin_sys_method)();
#ifdef USE_LAPACK
scs_int acceleration_lookback = stgs->acceleration_lookback;
+ scs_int acceleration_interval = stgs->acceleration_interval;
#else
scs_int acceleration_lookback = 0;
+ scs_int acceleration_interval = 0;
#endif
for (i = 0; i < LINE_LEN; ++i) {
scs_printf("-");
}
- scs_printf(
- "\n\tSCS v%s - Splitting Conic Solver\n\t(c) Brendan "
- "O'Donoghue, Stanford University, 2012\n",
- SCS(version)());
+ scs_printf("\n\t SCS v%s - Splitting Conic Solver\n\t(c) Brendan "
+ "O'Donoghue, Stanford University, 2012\n",
+ SCS(version)());
for (i = 0; i < LINE_LEN; ++i) {
scs_printf("-");
}
scs_printf("\n");
- if (lin_sys_method) {
- scs_printf("Lin-sys: %s\n", lin_sys_method);
- scs_free(lin_sys_method);
- }
- if (stgs->normalize) {
- scs_printf(
- "eps = %.2e, alpha = %.2f, max_iters = %i, normalize = %i, "
- "scale = %2.2f\nacceleration_lookback = %i, rho_x = %.2e\n",
- stgs->eps, stgs->alpha, (int)stgs->max_iters, (int)stgs->normalize,
- stgs->scale, (int)acceleration_lookback, stgs->rho_x);
- } else {
- scs_printf(
- "eps = %.2e, alpha = %.2f, max_iters = %i, normalize = %i\n"
- "acceleration_lookback = %i, rho_x = %.2e\n",
- stgs->eps, stgs->alpha, (int)stgs->max_iters, (int)stgs->normalize,
- (int)acceleration_lookback, stgs->rho_x);
- }
- scs_printf("Variables n = %i, constraints m = %i\n", (int)d->n, (int)d->m);
+ scs_printf("problem: variables n: %i, constraints m: %i\n", (int)d->n,
+ (int)d->m);
scs_printf("%s", cone_str);
scs_free(cone_str);
+ scs_printf("settings: eps_abs: %.1e, eps_rel: %.1e, eps_infeas: %.1e\n"
+ "\t alpha: %.2f, scale: %.2e, adaptive_scale: %i\n"
+ "\t max_iters: %i, normalize: %i, warm_start: %i\n",
+ /*, rho_x: %.2e\n", */
+ stgs->eps_abs, stgs->eps_rel, stgs->eps_infeas, stgs->alpha,
+ stgs->scale, (int)stgs->adaptive_scale, (int)stgs->max_iters,
+ (int)stgs->normalize, (int)stgs->warm_start);
+ /* , stgs->rho_x); */
+ if (stgs->acceleration_lookback != 0) {
+ scs_printf("\t acceleration_lookback: %i, acceleration_interval: %i\n",
+ (int)acceleration_lookback, (int)acceleration_interval);
+ }
+ if (stgs->time_limit_secs) {
+ scs_printf("\t time_limit_secs: %.2e\n", stgs->time_limit_secs);
+ }
+ if (lin_sys_method) {
+ scs_printf("lin-sys: %s\n\t nnz(A): %li, nnz(P): %li\n", lin_sys_method,
+ (long)d->A->p[d->A->n], d->P ? (long)d->P->p[d->P->n] : 0l);
+ }
+
#ifdef MATLAB_MEX_FILE
mexEvalString("drawnow;");
#endif
}
static void populate_on_failure(scs_int m, scs_int n, ScsSolution *sol,
ScsInfo *info, scs_int status_val,
const char *msg) {
if (info) {
- info->rel_gap = NAN;
+ info->gap = NAN;
info->res_pri = NAN;
info->res_dual = NAN;
info->pobj = NAN;
info->dobj = NAN;
info->iter = -1;
@@ -109,21 +127,21 @@
strcpy(info->status, msg);
}
if (sol) {
if (n > 0) {
if (!sol->x) {
- sol->x = (scs_float *)scs_malloc(sizeof(scs_float) * n);
+ sol->x = (scs_float *)scs_calloc(n, sizeof(scs_float));
}
SCS(scale_array)(sol->x, NAN, n);
}
if (m > 0) {
if (!sol->y) {
- sol->y = (scs_float *)scs_malloc(sizeof(scs_float) * m);
+ sol->y = (scs_float *)scs_calloc(m, sizeof(scs_float));
}
SCS(scale_array)(sol->y, NAN, m);
if (!sol->s) {
- sol->s = (scs_float *)scs_malloc(sizeof(scs_float) * m);
+ sol->s = (scs_float *)scs_calloc(m, sizeof(scs_float));
}
SCS(scale_array)(sol->s, NAN, m);
}
}
}
@@ -136,359 +154,454 @@
scs_printf("Failure:%s\n", msg);
scs_end_interrupt_listener();
return status;
}
-static void warm_start_vars(ScsWork *w, const ScsSolution *sol) {
- scs_int i, n = w->n, m = w->m;
- memset(w->v, 0, n * sizeof(scs_float));
- memcpy(w->u, sol->x, n * sizeof(scs_float));
- memcpy(&(w->u[n]), sol->y, m * sizeof(scs_float));
- memcpy(&(w->v[n]), sol->s, m * sizeof(scs_float));
- w->u[n + m] = 1.0;
- w->v[n + m] = 0.0;
-#ifndef NOVALIDATE
- for (i = 0; i < n + m + 1; ++i) {
- if (scs_isnan(w->u[i])) {
- w->u[i] = 0;
- }
- if (scs_isnan(w->v[i])) {
- w->v[i] = 0;
- }
+/* given x,y,s warm start, set v = [x; s / R + y; 1]
+ * where R = diag(w->rho_y_vec).
+ */
+static void warm_start_vars(ScsWork *w, ScsSolution *sol) {
+ scs_int n = w->n, m = w->m, i;
+ scs_float *v = w->v;
+ /* normalize the warm-start */
+ if (w->stgs->normalize) {
+ SCS(normalize_sol)(w, sol);
}
-#endif
+ memcpy(v, sol->x, n * sizeof(scs_float));
+ for (i = 0; i < m; ++i) {
+ v[i + n] = sol->y[i] + sol->s[i] / w->rho_y_vec[i];
+ }
+ v[n + m] = 1.0; /* tau = 1 */
+ /* un-normalize so sol unchanged */
if (w->stgs->normalize) {
- SCS(normalize_warm_start)(w);
+ SCS(un_normalize_sol)(w, sol);
}
}
-static scs_float calc_primal_resid(ScsWork *w, const scs_float *x,
- const scs_float *s, const scs_float tau,
- scs_float *nm_axs) {
- scs_int i;
- scs_float pres = 0, scale, *pr = w->pr;
- *nm_axs = 0;
- memset(pr, 0, w->m * sizeof(scs_float));
- SCS(accum_by_a)(w->A, w->p, x, pr);
- SCS(add_scaled_array)(pr, s, w->m, 1.0); /* pr = Ax + s */
- for (i = 0; i < w->m; ++i) {
- scale = w->stgs->normalize ? w->scal->D[i] / (w->sc_b * w->stgs->scale) : 1;
- scale = scale * scale;
- *nm_axs += (pr[i] * pr[i]) * scale;
- pres += (pr[i] - w->b[i] * tau) * (pr[i] - w->b[i] * tau) * scale;
+static void compute_residuals(ScsResiduals *r, scs_int m, scs_int n) {
+ r->res_pri = SAFEDIV_POS(NORM(r->ax_s_btau, m), r->tau);
+ r->res_dual = SAFEDIV_POS(NORM(r->px_aty_ctau, n), r->tau);
+ r->res_unbdd_a = NAN;
+ r->res_unbdd_p = NAN;
+ r->res_infeas = NAN;
+ if (r->ctx_tau < 0) {
+ r->res_unbdd_a = SAFEDIV_POS(NORM(r->ax_s, m), -r->ctx_tau);
+ r->res_unbdd_p = SAFEDIV_POS(NORM(r->px, n), -r->ctx_tau);
}
- *nm_axs = SQRTF(*nm_axs);
- return SQRTF(pres); /* SCS(norm)(Ax + s - b * tau) */
+ if (r->bty_tau < 0) {
+ r->res_infeas = SAFEDIV_POS(NORM(r->aty, n), -r->bty_tau);
+ }
}
-static scs_float calc_dual_resid(ScsWork *w, const scs_float *y,
- const scs_float tau, scs_float *nm_a_ty) {
- scs_int i;
- scs_float dres = 0, scale, *dr = w->dr;
- *nm_a_ty = 0;
- memset(dr, 0, w->n * sizeof(scs_float));
- SCS(accum_by_atrans)(w->A, w->p, y, dr); /* dr = A'y */
- for (i = 0; i < w->n; ++i) {
- scale = w->stgs->normalize ? w->scal->E[i] / (w->sc_c * w->stgs->scale) : 1;
- scale = scale * scale;
- *nm_a_ty += (dr[i] * dr[i]) * scale;
- dres += (dr[i] + w->c[i] * tau) * (dr[i] + w->c[i] * tau) * scale;
- }
- *nm_a_ty = SQRTF(*nm_a_ty);
- return SQRTF(dres); /* SCS(norm)(A'y + c * tau) */
+static void unnormalize_residuals(ScsWork *w) {
+ ScsResiduals *r_n = w->r_normalized; /* normalized residuals */
+ ScsResiduals *r = w->r_orig; /* original problem residuals */
+ scs_float pd = w->scal->primal_scale * w->scal->dual_scale;
+
+ /* copy vars */
+ r->last_iter = r_n->last_iter;
+ r->tau = r_n->tau;
+
+ /* mem copy arrays */
+ memcpy(r->ax, r_n->ax, w->m * sizeof(scs_float));
+ memcpy(r->ax_s, r_n->ax_s, w->m * sizeof(scs_float));
+ memcpy(r->ax_s_btau, r_n->ax_s_btau, w->m * sizeof(scs_float));
+ memcpy(r->aty, r_n->aty, w->n * sizeof(scs_float));
+ memcpy(r->px, r_n->px, w->n * sizeof(scs_float));
+ memcpy(r->px_aty_ctau, r_n->px_aty_ctau, w->n * sizeof(scs_float));
+
+ /* unnormalize */
+ r->kap = r_n->kap / pd;
+ r->bty_tau = r_n->bty_tau / pd;
+ r->ctx_tau = r_n->ctx_tau / pd;
+ r->xt_p_x_tau = r_n->xt_p_x_tau / pd;
+ r->xt_p_x = r_n->xt_p_x / pd;
+ r->ctx = r_n->ctx / pd;
+ r->bty = r_n->bty / pd;
+ r->pobj = r_n->pobj / pd;
+ r->dobj = r_n->dobj / pd;
+ r->gap = r_n->gap / pd;
+
+ SCS(un_normalize_primal)(w, r->ax);
+ SCS(un_normalize_primal)(w, r->ax_s);
+ SCS(un_normalize_primal)(w, r->ax_s_btau);
+ SCS(un_normalize_dual)(w, r->aty);
+ SCS(un_normalize_dual)(w, r->px);
+ SCS(un_normalize_dual)(w, r->px_aty_ctau);
+
+ compute_residuals(r, w->m, w->n);
}
-/* calculates un-normalized quantities */
-static void calc_residuals(ScsWork *w, ScsResiduals *r, scs_int iter) {
- scs_float *x = w->u, *y = &(w->u[w->n]), *s = &(w->v[w->n]);
- scs_float nmpr_tau, nmdr_tau, nm_axs_tau, nm_a_ty_tau, ct_x, bt_y;
+/* calculates un-normalized residual quantities */
+/* this is somewhat slow but not a bottleneck */
+static void populate_residual_struct(ScsWork *w, scs_int iter) {
scs_int n = w->n, m = w->m;
+ /* normalized x,y,s terms */
+ scs_float *x = w->xys_normalized->x;
+ scs_float *y = w->xys_normalized->y;
+ scs_float *s = w->xys_normalized->s;
+ ScsResiduals *r = w->r_normalized; /* normalized residuals */
/* checks if the residuals are unchanged by checking iteration */
if (r->last_iter == iter) {
return;
}
r->last_iter = iter;
+ memcpy(x, w->u, n * sizeof(scs_float));
+ memcpy(y, &(w->u[n]), m * sizeof(scs_float));
+ memcpy(s, &(w->rsk[n]), m * sizeof(scs_float));
+
r->tau = ABS(w->u[n + m]);
- r->kap = ABS(w->v[n + m]) /
- (w->stgs->normalize ? (w->stgs->scale * w->sc_c * w->sc_b) : 1);
+ r->kap = ABS(w->rsk[n + m]);
- nmpr_tau = calc_primal_resid(w, x, s, r->tau, &nm_axs_tau);
- nmdr_tau = calc_dual_resid(w, y, r->tau, &nm_a_ty_tau);
+ /**************** PRIMAL *********************/
+ memset(r->ax, 0, m * sizeof(scs_float));
+ /* ax = Ax */
+ SCS(accum_by_a)(w->A, x, r->ax);
- r->bt_y_by_tau =
- SCS(dot)(y, w->b, m) /
- (w->stgs->normalize ? (w->stgs->scale * w->sc_c * w->sc_b) : 1);
- r->ct_x_by_tau =
- SCS(dot)(x, w->c, n) /
- (w->stgs->normalize ? (w->stgs->scale * w->sc_c * w->sc_b) : 1);
+ memcpy(r->ax_s, r->ax, m * sizeof(scs_float));
+ /* ax_s = Ax + s */
+ SCS(add_scaled_array)(r->ax_s, s, m, 1.);
- r->res_infeas =
- r->bt_y_by_tau < 0 ? w->nm_b * nm_a_ty_tau / -r->bt_y_by_tau : NAN;
- r->res_unbdd =
- r->ct_x_by_tau < 0 ? w->nm_c * nm_axs_tau / -r->ct_x_by_tau : NAN;
+ memcpy(r->ax_s_btau, r->ax_s, m * sizeof(scs_float));
+ /* ax_s_btau = Ax + s - b * tau */
+ SCS(add_scaled_array)(r->ax_s_btau, w->b_normalized, m, -r->tau);
- bt_y = SAFEDIV_POS(r->bt_y_by_tau, r->tau);
- ct_x = SAFEDIV_POS(r->ct_x_by_tau, r->tau);
+ /**************** DUAL *********************/
+ memset(r->px, 0, n * sizeof(scs_float));
+ if (w->P) {
+ /* px = Px */
+ SCS(accum_by_p)(w->P, x, r->px);
+ r->xt_p_x_tau = SCS(dot)(r->px, x, n);
+ } else {
+ r->xt_p_x_tau = 0.;
+ }
- r->res_pri = SAFEDIV_POS(nmpr_tau / (1 + w->nm_b), r->tau);
- r->res_dual = SAFEDIV_POS(nmdr_tau / (1 + w->nm_c), r->tau);
- r->rel_gap = ABS(ct_x + bt_y) / (1 + ABS(ct_x) + ABS(bt_y));
+ memset(r->aty, 0, n * sizeof(scs_float));
+ /* aty = A'y */
+ SCS(accum_by_atrans)(w->A, y, r->aty);
+
+ /* r->px_aty_ctau = Px */
+ memcpy(r->px_aty_ctau, r->px, n * sizeof(scs_float));
+ /* r->px_aty_ctau = Px + A'y */
+ SCS(add_scaled_array)(r->px_aty_ctau, r->aty, n, 1.);
+ /* r->px_aty_ctau = Px + A'y + c * tau */
+ SCS(add_scaled_array)(r->px_aty_ctau, w->c_normalized, n, r->tau);
+
+ /**************** OTHERS *****************/
+ r->bty_tau = SCS(dot)(y, w->b_normalized, m);
+ r->ctx_tau = SCS(dot)(x, w->c_normalized, n);
+
+ r->bty = SAFEDIV_POS(r->bty_tau, r->tau);
+ r->ctx = SAFEDIV_POS(r->ctx_tau, r->tau);
+ r->xt_p_x = SAFEDIV_POS(r->xt_p_x_tau, r->tau * r->tau);
+
+ r->gap = ABS(r->xt_p_x + r->ctx + r->bty);
+ r->pobj = r->xt_p_x / 2. + r->ctx;
+ r->dobj = -r->xt_p_x / 2. - r->bty;
+
+ compute_residuals(r, m, n);
+
+ if (w->stgs->normalize) {
+ memcpy(w->xys_orig->x, w->xys_normalized->x, n * sizeof(scs_float));
+ memcpy(w->xys_orig->y, w->xys_normalized->y, m * sizeof(scs_float));
+ memcpy(w->xys_orig->s, w->xys_normalized->s, m * sizeof(scs_float));
+ SCS(un_normalize_sol)(w, w->xys_orig);
+ unnormalize_residuals(w);
+ }
}
static void cold_start_vars(ScsWork *w) {
scs_int l = w->n + w->m + 1;
- memset(w->u, 0, l * sizeof(scs_float));
memset(w->v, 0, l * sizeof(scs_float));
- w->u[l - 1] = SQRTF((scs_float)l);
- w->v[l - 1] = SQRTF((scs_float)l);
+ w->v[l - 1] = 1.;
}
-/* status < 0 indicates failure */
-static scs_int project_lin_sys(ScsWork *w, scs_int iter) {
- /* ut = u + v */
+/* utility function that scales first n entries in inner prod by rho_x */
+/* and last m entries by 1 / rho_y_vec, assumes length of array is n + m */
+/* See .note_on_scale in repo for explanation */
+static scs_float dot_with_diag_scaling(ScsWork *w, const scs_float *x,
+ const scs_float *y) {
+ scs_int i, n = w->n, len = w->n + w->m;
+ scs_float ip = 0.0;
+ for (i = 0; i < n; ++i) {
+ ip += w->stgs->rho_x * x[i] * y[i];
+ }
+ for (i = n; i < len; ++i) {
+ ip += x[i] * y[i] * w->rho_y_vec[i - n];
+ }
+ return ip;
+}
- scs_int n = w->n, m = w->m, l = n + m + 1, status;
- memcpy(w->u_t, w->u, l * sizeof(scs_float));
- SCS(add_scaled_array)(w->u_t, w->v, l, 1.0);
+static inline scs_float get_tau_scale(ScsWork *w) {
+ return TAU_FACTOR; /* TAU_FACTOR * w->scale; */
+}
- SCS(scale_array)(w->u_t, w->stgs->rho_x, n);
+static scs_float root_plus(ScsWork *w, scs_float *p, scs_float *mu,
+ scs_float eta) {
+ scs_float b, c, tau, a, tau_scale;
+ tau_scale = get_tau_scale(w);
+ a = tau_scale + dot_with_diag_scaling(w, w->g, w->g);
+ b = (dot_with_diag_scaling(w, mu, w->g) -
+ 2 * dot_with_diag_scaling(w, p, w->g) - eta * tau_scale);
+ c = dot_with_diag_scaling(w, p, p) - dot_with_diag_scaling(w, p, mu);
+ tau = (-b + SQRTF(MAX(b * b - 4 * a * c, 0.))) / (2 * a);
+ return tau;
+}
- SCS(add_scaled_array)(w->u_t, w->h, l - 1, -w->u_t[l - 1]);
- SCS(add_scaled_array)
- (w->u_t, w->h, l - 1, -SCS(dot)(w->u_t, w->g, l - 1) / (w->g_th + 1));
- SCS(scale_array)(&(w->u_t[n]), -1, m);
-
- status = SCS(solve_lin_sys)(w->A, w->stgs, w->p, w->u_t, w->u, iter);
-
- w->u_t[l - 1] += SCS(dot)(w->u_t, w->h, l - 1);
-
+/* status < 0 indicates failure */
+static scs_int project_lin_sys(ScsWork *w, scs_int iter) {
+ scs_int n = w->n, m = w->m, l = n + m + 1, status, i;
+ scs_float *warm_start = SCS_NULL;
+ scs_float tol = -1.0; /* only used for indirect methods, overriden later */
+ memcpy(w->u_t, w->v, l * sizeof(scs_float));
+ SCS(scale_array)(w->u_t, w->stgs->rho_x, n);
+ for (i = n; i < l - 1; ++i) {
+ w->u_t[i] *= -w->rho_y_vec[i - n];
+ }
+#if INDIRECT > 0
+ /* compute warm start using the cone projection output */
+ warm_start = w->lin_sys_warm_start;
+ memcpy(warm_start, w->u, (l - 1) * sizeof(scs_float));
+ /* warm_start = u[:n] + tau * g[:n] */
+ SCS(add_scaled_array)(warm_start, w->g, l - 1, w->u[l - 1]);
+ /* use normalized residuals to compute tolerance */
+ tol = MIN(CG_NORM(w->r_normalized->ax_s_btau, w->m),
+ CG_NORM(w->r_normalized->px_aty_ctau, w->n));
+ /* tol ~ O(1/k^(1+eps)) guarantees convergence */
+ /* use warm-start to calculate tolerance rather than w->u_t, since warm_start
+ * should be approximately equal to the true solution */
+ tol = CG_TOL_FACTOR * MIN(tol, CG_NORM(warm_start, w->n) /
+ POWF((scs_float)iter + 1, CG_RATE));
+ tol = MAX(CG_BEST_TOL, tol);
+#endif
+ status = SCS(solve_lin_sys)(w->p, w->u_t, warm_start, tol);
+ if (iter < FEASIBLE_ITERS) {
+ w->u_t[l - 1] = 1.;
+ } else {
+ w->u_t[l - 1] = root_plus(w, w->u_t, w->v, w->v[l - 1]);
+ }
+ SCS(add_scaled_array)(w->u_t, w->g, l - 1, -w->u_t[l - 1]);
return status;
}
+/* Compute the [r;s;kappa] iterate
+ *
+ * rsk^{k+1} = R ( u^{k+1} + v^k - 2 * u_t^{k+1} )
+ *
+ * uses Moreau decomposition to get projection onto dual cone
+ * since it depends on v^k MUST be called before update_dual_vars is done
+ * (no effect of w->stgs->alpha here).
+ */
+static void compute_rsk(ScsWork *w) {
+ scs_int i, l = w->m + w->n + 1;
+ /* r, should = 0 so skip */
+ /*
+ for (i = 0; i < w->n; ++i) {
+ w->rsk[i] = w->stgs->rho_x * (w->v[i] + w->u[i] - 2 * w->u_t[i]);
+ }
+ */
+ /* s */
+ for (i = w->n; i < l - 1; ++i) {
+ w->rsk[i] = (w->v[i] + w->u[i] - 2 * w->u_t[i]) * w->rho_y_vec[i - w->n];
+ }
+ /* kappa, incorporates tau scaling parameter */
+ w->rsk[l - 1] =
+ get_tau_scale(w) * (w->v[l - 1] + w->u[l - 1] - 2 * w->u_t[l - 1]);
+}
+
static void update_dual_vars(ScsWork *w) {
- scs_int i, n = w->n, l = n + w->m + 1;
- /* this does not relax 'x' variable */
- for (i = n; i < l; ++i) {
- w->v[i] += (w->u[i] - w->stgs->alpha * w->u_t[i] -
- (1.0 - w->stgs->alpha) * w->u_prev[i]);
+ scs_int i, l = w->n + w->m + 1;
+ scs_float a = w->stgs->alpha;
+ /* compute and store [r;s;kappa] */
+ compute_rsk(w);
+ for (i = 0; i < l; ++i) {
+ w->v[i] += a * (w->u[i] - w->u_t[i]);
}
}
/* status < 0 indicates failure */
static scs_int project_cones(ScsWork *w, const ScsCone *k, scs_int iter) {
- scs_int i, n = w->n, l = n + w->m + 1, status;
- /* this does not relax 'x' variable */
- for (i = 0; i < n; ++i) {
- w->u[i] = w->u_t[i] - w->v[i];
+ scs_int i, n = w->n, l = w->n + w->m + 1, status;
+ for (i = 0; i < l; ++i) {
+ w->u[i] = 2 * w->u_t[i] - w->v[i];
}
- for (i = n; i < l; ++i) {
- w->u[i] = w->stgs->alpha * w->u_t[i] + (1 - w->stgs->alpha) * w->u_prev[i] -
- w->v[i];
- }
/* u = [x;y;tau] */
- status =
- SCS(proj_dual_cone)(&(w->u[n]), k, w->cone_work, &(w->u_prev[n]), iter);
- if (w->u[l - 1] < 0.0) {
- w->u[l - 1] = 0.0;
+ status = SCS(proj_dual_cone)(&(w->u[n]), k, w->cone_work, w->stgs->normalize);
+ if (iter < FEASIBLE_ITERS) {
+ w->u[l - 1] = 1.0;
+ } else {
+ w->u[l - 1] = MAX(w->u[l - 1], 0.);
}
-
return status;
}
-static scs_int indeterminate(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
- strcpy(info->status, "Indeterminate");
- SCS(scale_array)(sol->x, NAN, w->n);
- SCS(scale_array)(sol->y, NAN, w->m);
- SCS(scale_array)(sol->s, NAN, w->m);
- return SCS_INDETERMINATE;
-}
-
-static void sety(ScsWork *w, ScsSolution *sol) {
+static void sety(const ScsWork *w, ScsSolution *sol) {
if (!sol->y) {
- sol->y = (scs_float *)scs_malloc(sizeof(scs_float) * w->m);
+ sol->y = (scs_float *)scs_calloc(w->m, sizeof(scs_float));
}
memcpy(sol->y, &(w->u[w->n]), w->m * sizeof(scs_float));
}
-static void sets(ScsWork *w, ScsSolution *sol) {
+/* s is contained in rsk */
+static void sets(const ScsWork *w, ScsSolution *sol) {
if (!sol->s) {
- sol->s = (scs_float *)scs_malloc(sizeof(scs_float) * w->m);
+ sol->s = (scs_float *)scs_calloc(w->m, sizeof(scs_float));
}
- memcpy(sol->s, &(w->v[w->n]), w->m * sizeof(scs_float));
+ memcpy(sol->s, &(w->rsk[w->n]), w->m * sizeof(scs_float));
}
-static void setx(ScsWork *w, ScsSolution *sol) {
+static void setx(const ScsWork *w, ScsSolution *sol) {
if (!sol->x) {
- sol->x = (scs_float *)scs_malloc(sizeof(scs_float) * w->n);
+ sol->x = (scs_float *)scs_calloc(w->n, sizeof(scs_float));
}
memcpy(sol->x, w->u, w->n * sizeof(scs_float));
}
-static scs_float get_max_residual(ScsResiduals *r) {
- return MAX(r->rel_gap, MAX(r->res_pri, r->res_dual));
+static void set_solved(const ScsWork *w, ScsSolution *sol, ScsInfo *info) {
+ SCS(scale_array)(sol->x, SAFEDIV_POS(1.0, w->r_orig->tau), w->n);
+ SCS(scale_array)(sol->y, SAFEDIV_POS(1.0, w->r_orig->tau), w->m);
+ SCS(scale_array)(sol->s, SAFEDIV_POS(1.0, w->r_orig->tau), w->m);
+ info->gap = w->r_orig->gap;
+ info->res_pri = w->r_orig->res_pri;
+ info->res_dual = w->r_orig->res_dual;
+ info->pobj = w->r_orig->xt_p_x / 2. + w->r_orig->ctx;
+ info->dobj = -w->r_orig->xt_p_x / 2. - w->r_orig->bty;
+ strcpy(info->status, "solved");
+ info->status_val = SCS_SOLVED;
}
-static void copy_from_best_iterate(ScsWork *w) {
- memcpy(w->u, w->u_best, (w->m + w->n + 1) * sizeof(scs_float));
- memcpy(w->v, w->v_best, (w->m + w->n + 1) * sizeof(scs_float));
-}
-
-static scs_int solved(ScsWork *w, ScsSolution *sol, ScsInfo *info,
- ScsResiduals *r, scs_int iter) {
- if (w->best_max_residual < get_max_residual(r)) {
- r->last_iter = -1; /* Forces residual recomputation. */
- copy_from_best_iterate(w);
- calc_residuals(w, r, iter);
- setx(w, sol);
- sety(w, sol);
- sets(w, sol);
- }
- SCS(scale_array)(sol->x, SAFEDIV_POS(1.0, r->tau), w->n);
- SCS(scale_array)(sol->y, SAFEDIV_POS(1.0, r->tau), w->m);
- SCS(scale_array)(sol->s, SAFEDIV_POS(1.0, r->tau), w->m);
- if (info->status_val == 0) {
- strcpy(info->status, "Solved/Inaccurate");
- return SCS_SOLVED_INACCURATE;
- }
- strcpy(info->status, "Solved");
- return SCS_SOLVED;
-}
-
-static scs_int infeasible(ScsWork *w, ScsSolution *sol, ScsInfo *info,
- scs_float bt_y) {
- SCS(scale_array)(sol->y, -1 / bt_y, w->m);
+static void set_infeasible(const ScsWork *w, ScsSolution *sol, ScsInfo *info) {
+ SCS(scale_array)(sol->y, -1 / w->r_orig->bty_tau, w->m);
SCS(scale_array)(sol->x, NAN, w->n);
SCS(scale_array)(sol->s, NAN, w->m);
- if (info->status_val == 0) {
- strcpy(info->status, "Infeasible/Inaccurate");
- return SCS_INFEASIBLE_INACCURATE;
- }
- strcpy(info->status, "Infeasible");
- return SCS_INFEASIBLE;
+ info->gap = NAN;
+ info->res_pri = NAN;
+ info->res_dual = NAN;
+ info->pobj = INFINITY;
+ info->dobj = INFINITY;
+ strcpy(info->status, "infeasible");
+ info->status_val = SCS_INFEASIBLE;
}
-static scs_int unbounded(ScsWork *w, ScsSolution *sol, ScsInfo *info,
- scs_float ct_x) {
- SCS(scale_array)(sol->x, -1 / ct_x, w->n);
- SCS(scale_array)(sol->s, -1 / ct_x, w->m);
+static void set_unbounded(const ScsWork *w, ScsSolution *sol, ScsInfo *info) {
+ SCS(scale_array)(sol->x, -1 / w->r_orig->ctx_tau, w->n);
+ SCS(scale_array)(sol->s, -1 / w->r_orig->ctx_tau, w->m);
SCS(scale_array)(sol->y, NAN, w->m);
- if (info->status_val == 0) {
- strcpy(info->status, "Unbounded/Inaccurate");
- return SCS_UNBOUNDED_INACCURATE;
- }
- strcpy(info->status, "Unbounded");
- return SCS_UNBOUNDED;
+ info->gap = NAN;
+ info->res_pri = NAN;
+ info->res_dual = NAN;
+ info->pobj = -INFINITY;
+ info->dobj = -INFINITY;
+ strcpy(info->status, "unbounded");
+ info->status_val = SCS_UNBOUNDED;
}
-static scs_int is_solved_status(scs_int status) {
- return status == SCS_SOLVED || status == SCS_SOLVED_INACCURATE;
-}
-
-static scs_int is_infeasible_status(scs_int status) {
- return status == SCS_INFEASIBLE || status == SCS_INFEASIBLE_INACCURATE;
-}
-
-static scs_int is_unbounded_status(scs_int status) {
- return status == SCS_UNBOUNDED || status == SCS_UNBOUNDED_INACCURATE;
-}
-
-static void get_info(ScsWork *w, ScsSolution *sol, ScsInfo *info,
- ScsResiduals *r, scs_int iter) {
- info->iter = iter;
- info->res_infeas = r->res_infeas;
- info->res_unbdd = r->res_unbdd;
- if (is_solved_status(info->status_val)) {
- info->rel_gap = r->rel_gap;
- info->res_pri = r->res_pri;
- info->res_dual = r->res_dual;
- info->pobj = r->ct_x_by_tau / r->tau;
- info->dobj = -r->bt_y_by_tau / r->tau;
- } else if (is_unbounded_status(info->status_val)) {
- info->rel_gap = NAN;
- info->res_pri = NAN;
- info->res_dual = NAN;
- info->pobj = -INFINITY;
- info->dobj = -INFINITY;
- } else if (is_infeasible_status(info->status_val)) {
- info->rel_gap = NAN;
- info->res_pri = NAN;
- info->res_dual = NAN;
- info->pobj = INFINITY;
- info->dobj = INFINITY;
+/* not yet converged, take best guess */
+static void set_unfinished(const ScsWork *w, ScsSolution *sol, ScsInfo *info) {
+ if (w->r_orig->tau > w->r_orig->kap) {
+ set_solved(w, sol, info);
+ info->status_val = SCS_SOLVED_INACCURATE;
+ } else if (w->r_orig->bty_tau < w->r_orig->ctx_tau) {
+ set_infeasible(w, sol, info);
+ info->status_val = SCS_INFEASIBLE_INACCURATE;
+ } else {
+ set_unbounded(w, sol, info);
+ info->status_val = SCS_UNBOUNDED_INACCURATE;
}
+ /* Append inaccurate to the status string */
+ if (w->time_limit_reached) {
+ strcat(info->status, " (inaccurate - reached time_limit_secs)");
+ } else if (info->iter >= w->stgs->max_iters) {
+ strcat(info->status, " (inaccurate - reached max_iters)");
+ } else {
+ scs_printf("ERROR: should not be in this state (1).\n");
+ }
}
/* sets solutions, re-scales by inner prods if infeasible or unbounded */
-static void get_solution(ScsWork *w, ScsSolution *sol, ScsInfo *info,
- ScsResiduals *r, scs_int iter) {
- scs_int l = w->n + w->m + 1;
- calc_residuals(w, r, iter);
+static void finalize(ScsWork *w, ScsSolution *sol, ScsInfo *info,
+ scs_int iter) {
setx(w, sol);
sety(w, sol);
sets(w, sol);
- if (info->status_val == SCS_UNFINISHED) {
- /* not yet converged, take best guess */
- if (r->tau > INDETERMINATE_TOL && r->tau > r->kap) {
- info->status_val = solved(w, sol, info, r, iter);
- } else if (SCS(norm)(w->u, l) < INDETERMINATE_TOL * SQRTF((scs_float)l)) {
- info->status_val = indeterminate(w, sol, info);
- } else if (r->bt_y_by_tau < r->ct_x_by_tau) {
- info->status_val = infeasible(w, sol, info, r->bt_y_by_tau);
- } else {
- info->status_val = unbounded(w, sol, info, r->ct_x_by_tau);
- }
- } else if (is_solved_status(info->status_val)) {
- info->status_val = solved(w, sol, info, r, iter);
- } else if (is_infeasible_status(info->status_val)) {
- info->status_val = infeasible(w, sol, info, r->bt_y_by_tau);
- } else {
- info->status_val = unbounded(w, sol, info, r->ct_x_by_tau);
- }
if (w->stgs->normalize) {
SCS(un_normalize_sol)(w, sol);
}
- get_info(w, sol, info, r, iter);
+ populate_residual_struct(w, iter);
+ info->setup_time = w->setup_time;
+ info->iter = iter;
+ info->res_infeas = w->r_orig->res_infeas;
+ info->res_unbdd_a = w->r_orig->res_unbdd_a;
+ info->res_unbdd_p = w->r_orig->res_unbdd_p;
+ info->scale = w->scale;
+ info->scale_updates = w->scale_updates;
+ info->rejected_accel_steps = w->rejected_accel_steps;
+ info->accepted_accel_steps = w->accepted_accel_steps;
+ info->comp_slack = ABS(SCS(dot)(sol->s, sol->y, w->m));
+ if (info->comp_slack >
+ 1e-5 * MAX(SCS(norm_inf)(sol->s, w->m), SCS(norm_inf)(sol->y, w->m))) {
+ scs_printf("WARNING - large complementary slackness residual: %f\n",
+ info->comp_slack);
+ }
+ switch (info->status_val) {
+ case SCS_SOLVED:
+ set_solved(w, sol, info);
+ break;
+ case SCS_INFEASIBLE:
+ set_infeasible(w, sol, info);
+ break;
+ case SCS_UNBOUNDED:
+ set_unbounded(w, sol, info);
+ break;
+ case SCS_UNFINISHED: /* When SCS reaches max_iters or time_limit_secs */
+ set_unfinished(w, sol, info);
+ break;
+ default:
+ scs_printf("ERROR: should not be in this state (2).\n");
+ }
}
-static void print_summary(ScsWork *w, scs_int i, ScsResiduals *r,
- SCS(timer) * solve_timer) {
+static void print_summary(ScsWork *w, scs_int i, SCS(timer) * solve_timer) {
+ ScsResiduals *r = w->r_orig;
scs_printf("%*i|", (int)strlen(HEADER[0]), (int)i);
scs_printf("%*.2e ", (int)HSPACE, r->res_pri);
scs_printf("%*.2e ", (int)HSPACE, r->res_dual);
- scs_printf("%*.2e ", (int)HSPACE, r->rel_gap);
- scs_printf("%*.2e ", (int)HSPACE, SAFEDIV_POS(r->ct_x_by_tau, r->tau));
- scs_printf("%*.2e ", (int)HSPACE, SAFEDIV_POS(-r->bt_y_by_tau, r->tau));
- scs_printf("%*.2e ", (int)HSPACE, SAFEDIV_POS(r->kap, r->tau));
+ scs_printf("%*.2e ", (int)HSPACE, r->gap);
+ /* report mid point of primal and dual objective values */
+ scs_printf("%*.2e ", (int)HSPACE, 0.5 * (r->pobj + r->dobj));
+ scs_printf("%*.2e ", (int)HSPACE, w->scale);
scs_printf("%*.2e ", (int)HSPACE, SCS(tocq)(solve_timer) / 1e3);
scs_printf("\n");
-#if EXTRA_VERBOSE > 0
- scs_printf("Norm u = %4f, ", SCS(norm)(w->u, w->n + w->m + 1));
- scs_printf("Norm u_t = %4f, ", SCS(norm)(w->u_t, w->n + w->m + 1));
- scs_printf("Norm v = %4f, ", SCS(norm)(w->v, w->n + w->m + 1));
+#if VERBOSITY > 0
+ scs_printf("Norm u = %4f, ", SCS(norm_2)(w->u, w->n + w->m + 1));
+ scs_printf("Norm u_t = %4f, ", SCS(norm_2)(w->u_t, w->n + w->m + 1));
+ scs_printf("Norm v = %4f, ", SCS(norm_2)(w->v, w->n + w->m + 1));
+ scs_printf("Norm x = %4f, ", SCS(norm_2)(w->xys_orig->x, w->n));
+ scs_printf("Norm y = %4f, ", SCS(norm_2)(w->xys_orig->y, w->m));
+ scs_printf("Norm s = %4f, ", SCS(norm_2)(w->xys_orig->s, w->m));
+ scs_printf("Norm |Ax + s| = %1.2e, ", SCS(norm_2)(r->ax_s, w->m));
scs_printf("tau = %4f, ", w->u[w->n + w->m]);
- scs_printf("kappa = %4f, ", w->v[w->n + w->m]);
- scs_printf("|u - u_prev| = %1.2e, ",
- SCS(norm_diff)(w->u, w->u_prev, w->n + w->m + 1));
+ scs_printf("kappa = %4f, ", w->rsk[w->n + w->m]);
scs_printf("|u - u_t| = %1.2e, ",
SCS(norm_diff)(w->u, w->u_t, w->n + w->m + 1));
scs_printf("res_infeas = %1.2e, ", r->res_infeas);
- scs_printf("res_unbdd = %1.2e\n", r->res_unbdd);
+ scs_printf("res_unbdd_a = %1.2e, ", r->res_unbdd_a);
+ scs_printf("res_unbdd_p = %1.2e, ", r->res_unbdd_p);
+ scs_printf("ctx_tau = %1.2e, ", r->ctx_tau);
+ scs_printf("bty_tau = %1.2e\n", r->bty_tau);
#endif
#ifdef MATLAB_MEX_FILE
mexEvalString("drawnow;");
#endif
}
static void print_header(ScsWork *w, const ScsCone *k) {
scs_int i;
- if (w->stgs->warm_start) {
- scs_printf("SCS using variable warm-starting\n");
- }
for (i = 0; i < LINE_LEN; ++i) {
scs_printf("-");
}
scs_printf("\n");
for (i = 0; i < HEADER_LEN - 1; ++i) {
@@ -502,158 +615,97 @@
#ifdef MATLAB_MEX_FILE
mexEvalString("drawnow;");
#endif
}
-static scs_float get_dual_cone_dist(const scs_float *y, const ScsCone *k,
- ScsConeWork *c, scs_int m) {
- scs_float dist;
- scs_float *t = (scs_float *)scs_malloc(sizeof(scs_float) * m);
- memcpy(t, y, m * sizeof(scs_float));
- SCS(proj_dual_cone)(t, k, c, SCS_NULL, -1);
- dist = SCS(norm_inf_diff)(t, y, m);
-#if EXTRA_VERBOSE > 0
- SCS(print_array)(y, m, "y");
- SCS(print_array)(t, m, "proj_y");
- scs_printf("dist = %4f\n", dist);
-#endif
- scs_free(t);
- return dist;
-}
-
-/* via moreau */
-static scs_float get_pri_cone_dist(const scs_float *s, const ScsCone *k,
- ScsConeWork *c, scs_int m) {
- scs_float dist;
- scs_float *t = (scs_float *)scs_malloc(sizeof(scs_float) * m);
- memcpy(t, s, m * sizeof(scs_float));
- SCS(scale_array)(t, -1.0, m);
- SCS(proj_dual_cone)(t, k, c, SCS_NULL, -1);
- dist = SCS(norm_inf)(t, m); /* ||s - Pi_c(s)|| = ||Pi_c*(-s)|| */
-#if EXTRA_VERBOSE > 0
- SCS(print_array)(s, m, "s");
- SCS(print_array)(t, m, "(s - proj_s)");
- scs_printf("dist = %4f\n", dist);
-#endif
- scs_free(t);
- return dist;
-}
-
-static char *get_accel_summary(ScsInfo *info, scs_float total_accel_time) {
- char *str = (char *)scs_malloc(sizeof(char) * 64);
- sprintf(str, "\tAcceleration: avg step time: %1.2es\n",
- total_accel_time / (info->iter + 1) / 1e3);
- return str;
-}
-
-static void print_footer(const ScsData *d, const ScsCone *k, ScsSolution *sol,
- ScsWork *w, ScsInfo *info,
- scs_float total_accel_time) {
+static void print_footer(ScsInfo *info) {
scs_int i;
- char *lin_sys_str = SCS(get_lin_sys_summary)(w->p, info);
- char *cone_str = SCS(get_cone_summary)(info, w->cone_work);
- char *accel_str = get_accel_summary(info, total_accel_time);
+
for (i = 0; i < LINE_LEN; ++i) {
scs_printf("-");
}
- scs_printf("\nStatus: %s\n", info->status);
- if (info->iter == w->stgs->max_iters) {
- scs_printf(
- "Hit max_iters, solution may be inaccurate, returning best found "
- "solution.\n");
- }
- scs_printf("Timing: Solve time: %1.2es\n", info->solve_time / 1e3);
+ scs_printf("\n");
+ scs_printf("status: %s\n", info->status);
+ scs_printf("timings: total: %1.2es = setup: %1.2es + solve: %1.2es\n",
+ (info->setup_time + info->solve_time) / 1e3,
+ info->setup_time / 1e3, info->solve_time / 1e3);
+ scs_printf("\t lin-sys: %1.2es, cones: %1.2es, accel: %1.2es\n",
+ info->lin_sys_time / 1e3, info->cone_time / 1e3,
+ info->accel_time / 1e3);
- if (lin_sys_str) {
- scs_printf("%s", lin_sys_str);
- scs_free(lin_sys_str);
- }
-
- if (cone_str) {
- scs_printf("%s", cone_str);
- scs_free(cone_str);
- }
-
- if (accel_str) {
- scs_printf("%s", accel_str);
- scs_free(accel_str);
- }
-
for (i = 0; i < LINE_LEN; ++i) {
scs_printf("-");
}
scs_printf("\n");
-
- if (is_infeasible_status(info->status_val)) {
- scs_printf("Certificate of primal infeasibility:\n");
- scs_printf("dist(y, K*) = %.4e\n",
- get_dual_cone_dist(sol->y, k, w->cone_work, d->m));
- scs_printf("|A'y|_2 * |b|_2 = %.4e\n", info->res_infeas);
- scs_printf("b'y = %.4f\n", SCS(dot)(d->b, sol->y, d->m));
- } else if (is_unbounded_status(info->status_val)) {
- scs_printf("Certificate of dual infeasibility:\n");
- scs_printf("dist(s, K) = %.4e\n",
- get_pri_cone_dist(sol->s, k, w->cone_work, d->m));
- scs_printf("|Ax + s|_2 * |c|_2 = %.4e\n", info->res_unbdd);
- scs_printf("c'x = %.4f\n", SCS(dot)(d->c, sol->x, d->n));
- } else {
- scs_printf("Error metrics:\n");
- scs_printf("dist(s, K) = %.4e, dist(y, K*) = %.4e, s'y/|s||y| = %.4e\n",
- get_pri_cone_dist(sol->s, k, w->cone_work, d->m),
- get_dual_cone_dist(sol->y, k, w->cone_work, d->m),
- SCS(dot)(sol->s, sol->y, d->m) / SCS(norm)(sol->s, d->m) /
- SCS(norm)(sol->y, d->m));
- scs_printf("primal res: |Ax + s - b|_2 / (1 + |b|_2) = %.4e\n",
- info->res_pri);
- scs_printf("dual res: |A'y + c|_2 / (1 + |c|_2) = %.4e\n",
- info->res_dual);
- scs_printf("rel gap: |c'x + b'y| / (1 + |c'x| + |b'y|) = %.4e\n",
- info->rel_gap);
- for (i = 0; i < LINE_LEN; ++i) {
- scs_printf("-");
- }
+ /* report mid point of primal and dual objective values */
+ scs_printf("objective = %.6f", 0.5 * (info->pobj + info->dobj));
+ switch (info->status_val) {
+ case SCS_SOLVED_INACCURATE:
+ case SCS_UNBOUNDED_INACCURATE:
+ case SCS_INFEASIBLE_INACCURATE:
+ scs_printf(" (inaccurate)");
+ default:
scs_printf("\n");
- scs_printf("c'x = %.4f, -b'y = %.4f\n", info->pobj, info->dobj);
}
for (i = 0; i < LINE_LEN; ++i) {
- scs_printf("=");
+ scs_printf("-");
}
scs_printf("\n");
#ifdef MATLAB_MEX_FILE
mexEvalString("drawnow;");
#endif
}
-static scs_int has_converged(ScsWork *w, ScsResiduals *r, scs_int iter) {
- scs_float eps = w->stgs->eps;
- if (isless(r->res_pri, eps) && isless(r->res_dual, eps) &&
- isless(r->rel_gap, eps)) {
- return SCS_SOLVED;
+static scs_int has_converged(ScsWork *w, scs_int iter) {
+ scs_float eps_abs = w->stgs->eps_abs;
+ scs_float eps_rel = w->stgs->eps_rel;
+ scs_float eps_infeas = w->stgs->eps_infeas;
+ scs_float grl, prl, drl;
+
+ ScsResiduals *r = w->r_orig;
+ scs_float *b = w->b_orig;
+ scs_float *c = w->c_orig;
+ scs_float *s = w->xys_orig->s;
+
+ if (r->tau > 0.) {
+ /* xt_p_x, ctx, bty already have tau divided out */
+ grl = MAX(MAX(ABS(r->xt_p_x), ABS(r->ctx)), ABS(r->bty));
+ /* s, ax, px, aty do *not* have tau divided out, so need to divide */
+ prl = MAX(MAX(NORM(b, w->m) * r->tau, NORM(s, w->m)), NORM(r->ax, w->m)) /
+ r->tau;
+ drl = MAX(MAX(NORM(c, w->n) * r->tau, NORM(r->px, w->n)),
+ NORM(r->aty, w->n)) /
+ r->tau;
+ if (isless(r->res_pri, eps_abs + eps_rel * prl) &&
+ isless(r->res_dual, eps_abs + eps_rel * drl) &&
+ isless(r->gap, eps_abs + eps_rel * grl)) {
+ return SCS_SOLVED;
+ }
}
- /* Add iter > 0 to avoid strange edge case where infeasible point found
- * right at start of run `out/demo_SOCP_indirect 2 0.1 0.3 1506264403` */
- if (isless(r->res_unbdd, eps) && iter > 0) {
+ if (isless(r->res_unbdd_a, eps_infeas) &&
+ isless(r->res_unbdd_p, eps_infeas)) {
return SCS_UNBOUNDED;
}
- if (isless(r->res_infeas, eps) && iter > 0) {
+ if (isless(r->res_infeas, eps_infeas)) {
return SCS_INFEASIBLE;
}
return 0;
}
-static scs_int validate(const ScsData *d, const ScsCone *k) {
- ScsSettings *stgs = d->stgs;
+#if NOVALIDATE == 0
+static scs_int validate(const ScsData *d, const ScsCone *k,
+ const ScsSettings *stgs) {
if (d->m <= 0 || d->n <= 0) {
scs_printf("m and n must both be greater than 0; m = %li, n = %li\n",
(long)d->m, (long)d->n);
return -1;
}
if (d->m < d->n) {
- scs_printf("WARN: m less than n, problem likely degenerate\n");
+ /* scs_printf("WARN: m less than n, problem likely degenerate\n"); */
/* return -1; */
}
- if (SCS(validate_lin_sys)(d->A) < 0) {
+ if (SCS(validate_lin_sys)(d->A, d->P) < 0) {
scs_printf("invalid linear system input data\n");
return -1;
}
if (SCS(validate_cones)(d, k) < 0) {
scs_printf("cone validation error\n");
@@ -661,14 +713,22 @@
}
if (stgs->max_iters <= 0) {
scs_printf("max_iters must be positive\n");
return -1;
}
- if (stgs->eps <= 0) {
- scs_printf("eps tolerance must be positive\n");
+ if (stgs->eps_abs < 0) {
+ scs_printf("eps_abs tolerance must be positive\n");
return -1;
}
+ if (stgs->eps_rel < 0) {
+ scs_printf("eps_rel tolerance must be positive\n");
+ return -1;
+ }
+ if (stgs->eps_infeas < 0) {
+ scs_printf("eps_infeas tolerance must be positive\n");
+ return -1;
+ }
if (stgs->alpha <= 0 || stgs->alpha >= 2) {
scs_printf("alpha must be in (0,2)\n");
return -1;
}
if (stgs->rho_x <= 0) {
@@ -679,240 +739,391 @@
scs_printf("scale must be positive (1 works well).\n");
return -1;
}
return 0;
}
+#endif
-static ScsWork *init_work(const ScsData *d, const ScsCone *k) {
+static ScsResiduals *init_residuals(const ScsData *d) {
+ ScsResiduals *r = (ScsResiduals *)scs_calloc(1, sizeof(ScsResiduals));
+ r->last_iter = -1;
+ r->ax = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
+ r->ax_s = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
+ r->ax_s_btau = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
+ r->px = (scs_float *)scs_calloc(d->n, sizeof(scs_float));
+ r->aty = (scs_float *)scs_calloc(d->n, sizeof(scs_float));
+ r->px_aty_ctau = (scs_float *)scs_calloc(d->n, sizeof(scs_float));
+ return r;
+}
+
+static ScsWork *init_work(const ScsData *d, const ScsCone *k,
+ const ScsSettings *stgs) {
ScsWork *w = (ScsWork *)scs_calloc(1, sizeof(ScsWork));
scs_int l = d->n + d->m + 1;
- if (d->stgs->verbose) {
- print_init_header(d, k);
+ if (stgs->verbose) {
+ print_init_header(d, k, stgs);
}
if (!w) {
scs_printf("ERROR: allocating work failure\n");
return SCS_NULL;
}
/* get settings and dims from data struct */
- w->stgs = d->stgs;
+ w->d = d;
+ w->k = k;
+ w->stgs = stgs;
+ w->scale = stgs->scale; /* initial scale, may be updated */
w->m = d->m;
w->n = d->n;
- w->best_max_residual = INFINITY;
+ w->last_scale_update_iter = 0;
+ w->sum_log_scale_factor = 0.;
+ w->n_log_scale_factor = 0;
+ w->scale_updates = 0;
+ w->time_limit_reached = 0;
/* allocate workspace: */
- /* u* include v* values */
- w->u = (scs_float *)scs_malloc(2 * l * sizeof(scs_float));
- w->u_best = (scs_float *)scs_malloc(2 * l * sizeof(scs_float));
- w->u_t = (scs_float *)scs_malloc(l * sizeof(scs_float));
- w->u_prev = (scs_float *)scs_malloc(2 * l * sizeof(scs_float));
- w->h = (scs_float *)scs_malloc((l - 1) * sizeof(scs_float));
- w->g = (scs_float *)scs_malloc((l - 1) * sizeof(scs_float));
- w->pr = (scs_float *)scs_malloc(d->m * sizeof(scs_float));
- w->dr = (scs_float *)scs_malloc(d->n * sizeof(scs_float));
- w->b = (scs_float *)scs_malloc(d->m * sizeof(scs_float));
- w->c = (scs_float *)scs_malloc(d->n * sizeof(scs_float));
- if (!w->u || !w->u_t || !w->u_prev || !w->h || !w->g || !w->pr || !w->dr ||
- !w->b || !w->c) {
+ w->u = (scs_float *)scs_calloc(l, sizeof(scs_float));
+ w->u_t = (scs_float *)scs_calloc(l, sizeof(scs_float));
+ w->v = (scs_float *)scs_calloc(l, sizeof(scs_float));
+ w->v_prev = (scs_float *)scs_calloc(l, sizeof(scs_float));
+ w->rsk = (scs_float *)scs_calloc(l, sizeof(scs_float));
+ w->h = (scs_float *)scs_calloc((l - 1), sizeof(scs_float));
+ w->g = (scs_float *)scs_calloc((l - 1), sizeof(scs_float));
+ w->lin_sys_warm_start = (scs_float *)scs_calloc((l - 1), sizeof(scs_float));
+ w->rho_y_vec = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
+ /* x,y,s struct */
+ w->xys_orig = (ScsSolution *)scs_calloc(1, sizeof(ScsSolution));
+ w->xys_orig->x = (scs_float *)scs_calloc(d->n, sizeof(scs_float));
+ w->xys_orig->s = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
+ w->xys_orig->y = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
+ w->r_orig = init_residuals(d);
+
+ w->A = d->A;
+ w->P = d->P;
+
+ w->b_orig = d->b;
+ w->c_orig = d->c;
+ w->b_normalized = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
+ w->c_normalized = (scs_float *)scs_calloc(d->n, sizeof(scs_float));
+ memcpy(w->b_normalized, w->b_orig, w->m * sizeof(scs_float));
+ memcpy(w->c_normalized, w->c_orig, w->n * sizeof(scs_float));
+ SCS(set_rho_y_vec)(k, w->scale, w->rho_y_vec, w->m);
+
+ if (!w->c_normalized) {
scs_printf("ERROR: work memory allocation failure\n");
return SCS_NULL;
}
- /* make u,v and u_prev,v_prev contiguous in memory */
- w->v = &(w->u[l]);
- w->v_best = &(w->u_best[l]);
- w->v_prev = &(w->u_prev[l]);
- w->A = d->A;
+
if (w->stgs->normalize) {
+ w->xys_normalized = (ScsSolution *)scs_calloc(1, sizeof(ScsSolution));
+ w->xys_normalized->x = (scs_float *)scs_calloc(d->n, sizeof(scs_float));
+ w->xys_normalized->s = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
+ w->xys_normalized->y = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
+ w->r_normalized = init_residuals(d);
+
#ifdef COPYAMATRIX
- if (!SCS(copy_a_matrix)(&(w->A), d->A)) {
+ if (!SCS(copy_matrix)(&(w->A), d->A)) {
scs_printf("ERROR: copy A matrix failed\n");
return SCS_NULL;
}
+ if (w->P && !SCS(copy_matrix)(&(w->P), d->P)) {
+ scs_printf("ERROR: copy P matrix failed\n");
+ return SCS_NULL;
+ }
#endif
- w->scal = (ScsScaling *)scs_malloc(sizeof(ScsScaling));
- SCS(normalize_a)(w->A, w->stgs, k, w->scal);
-#if EXTRA_VERBOSE > 0
- SCS(print_array)(w->scal->D, d->m, "D");
- scs_printf("SCS(norm) D = %4f\n", SCS(norm)(w->scal->D, d->m));
- SCS(print_array)(w->scal->E, d->n, "E");
- scs_printf("SCS(norm) E = %4f\n", SCS(norm)(w->scal->E, d->n));
-#endif
+ /* this allocates memory that must be freed */
+ w->cone_boundaries_len = SCS(set_cone_boundaries)(k, &w->cone_boundaries);
+ w->scal = (ScsScaling *)scs_calloc(1, sizeof(ScsScaling));
+ SCS(normalize)
+ (w->P, w->A, w->b_normalized, w->c_normalized, w->scal, w->cone_boundaries,
+ w->cone_boundaries_len);
} else {
+ w->xys_normalized = w->xys_orig;
+ w->r_normalized = w->r_orig;
+ w->cone_boundaries_len = 0;
+ w->cone_boundaries = SCS_NULL;
w->scal = SCS_NULL;
}
- if (!(w->cone_work = SCS(init_cone)(k))) {
+ if (!(w->cone_work = SCS(init_cone)(k, w->scal, w->m))) {
scs_printf("ERROR: init_cone failure\n");
return SCS_NULL;
}
- if (!(w->p = SCS(init_lin_sys_work)(w->A, w->stgs))) {
+ if (!(w->p =
+ SCS(init_lin_sys_work)(w->A, w->P, w->rho_y_vec, w->stgs->rho_x))) {
scs_printf("ERROR: init_lin_sys_work failure\n");
return SCS_NULL;
}
- if (!(w->accel =
- aa_init(2 * (w->m + w->n + 1), ABS(w->stgs->acceleration_lookback),
- w->stgs->acceleration_lookback >= 0))) {
- if (w->stgs->verbose) {
- scs_printf("WARN: aa_init returned NULL, no acceleration applied.\n");
+ /* Acceleration */
+ w->rejected_accel_steps = 0;
+ w->accepted_accel_steps = 0;
+ if (w->stgs->acceleration_lookback) {
+ /* TODO(HACK!) negative acceleration_lookback interpreted as type-II */
+ if (!(w->accel = aa_init(l, ABS(w->stgs->acceleration_lookback),
+ w->stgs->acceleration_lookback > 0,
+ w->stgs->acceleration_lookback > 0
+ ? AA_REGULARIZATION_TYPE_1
+ : AA_REGULARIZATION_TYPE_2,
+ AA_RELAXATION, AA_SAFEGUARD_FACTOR,
+ AA_MAX_WEIGHT_NORM, VERBOSITY))) {
+ if (w->stgs->verbose) {
+ scs_printf("WARN: aa_init returned NULL, no acceleration applied.\n");
+ }
}
+ } else {
+ w->accel = SCS_NULL;
}
return w;
}
-static scs_int update_work(const ScsData *d, ScsWork *w,
- const ScsSolution *sol) {
+static void update_work_cache(ScsWork *w) {
+ /* g = (I + M)^{-1} h */
+ memcpy(w->g, w->h, (w->n + w->m) * sizeof(scs_float));
+ SCS(scale_array)(&(w->g[w->n]), -1., w->m);
+ SCS(solve_lin_sys)(w->p, w->g, SCS_NULL, CG_BEST_TOL);
+ return;
+}
+
+static scs_int update_work(const ScsData *d, ScsWork *w, ScsSolution *sol) {
/* before normalization */
scs_int n = d->n;
scs_int m = d->m;
-
- w->nm_b = SCS(norm)(d->b, m);
- w->nm_c = SCS(norm)(d->c, n);
- memcpy(w->b, d->b, d->m * sizeof(scs_float));
- memcpy(w->c, d->c, d->n * sizeof(scs_float));
-
-#if EXTRA_VERBOSE > 0
- SCS(print_array)(w->b, m, "b");
- scs_printf("pre-normalized norm b = %4f\n", SCS(norm)(w->b, m));
- SCS(print_array)(w->c, n, "c");
- scs_printf("pre-normalized norm c = %4f\n", SCS(norm)(w->c, n));
-#endif
- if (w->stgs->normalize) {
- SCS(normalize_b_c)(w);
-#if EXTRA_VERBOSE > 0
- SCS(print_array)(w->b, m, "bn");
- scs_printf("sc_b = %4f\n", w->sc_b);
- scs_printf("post-normalized norm b = %4f\n", SCS(norm)(w->b, m));
- SCS(print_array)(w->c, n, "cn");
- scs_printf("sc_c = %4f\n", w->sc_c);
- scs_printf("post-normalized norm c = %4f\n", SCS(norm)(w->c, n));
-#endif
- }
if (w->stgs->warm_start) {
warm_start_vars(w, sol);
} else {
cold_start_vars(w);
}
- memcpy(w->h, w->c, n * sizeof(scs_float));
- memcpy(&(w->h[n]), w->b, m * sizeof(scs_float));
- memcpy(w->g, w->h, (n + m) * sizeof(scs_float));
- SCS(solve_lin_sys)(w->A, w->stgs, w->p, w->g, SCS_NULL, -1);
- SCS(scale_array)(&(w->g[n]), -1, m);
- w->g_th = SCS(dot)(w->h, w->g, n + m);
+
+ /* h = [c;b] */
+ memcpy(w->h, w->c_normalized, n * sizeof(scs_float));
+ memcpy(&(w->h[n]), w->b_normalized, m * sizeof(scs_float));
+ update_work_cache(w);
return 0;
}
-static scs_float iterate_norm_diff(ScsWork *w) {
- scs_int l = w->m + w->n + 1;
- scs_float u_norm_difference = SCS(norm_diff)(w->u, w->u_prev, l);
- scs_float v_norm_difference = SCS(norm_diff)(w->v, w->v_prev, l);
- scs_float norm = SQRTF(SCS(norm_sq)(w->u, l) + SCS(norm_sq)(w->v, l));
- scs_float norm_diff = SQRTF(u_norm_difference * u_norm_difference +
- v_norm_difference * v_norm_difference);
- return norm_diff / norm;
+/* will update if the factor is outside of range */
+scs_int should_update_rho_y_vec(scs_float factor, scs_int iter) {
+ return (factor > SQRTF(10.) || factor < 1. / SQRTF(10.));
}
-static void update_best_iterate(ScsWork *w, ScsResiduals *r) {
- scs_float max_residual = get_max_residual(r);
- if (w->best_max_residual > max_residual) {
- w->best_max_residual = max_residual;
- memcpy(w->u_best, w->u, (w->m + w->n + 1) * sizeof(scs_float));
- memcpy(w->v_best, w->v, (w->m + w->n + 1) * sizeof(scs_float));
+static void maybe_update_scale(ScsWork *w, const ScsCone *k, scs_int iter) {
+ scs_int i;
+ scs_float factor, new_scale;
+
+ ScsResiduals *r = w->r_orig;
+ ScsSolution *xys = w->xys_orig;
+ scs_float *b = w->b_orig;
+ scs_float *c = w->c_orig;
+
+ scs_int iters_since_last_update = iter - w->last_scale_update_iter;
+ /* ||Ax + s - b * tau|| */
+ scs_float relative_res_pri =
+ SAFEDIV_POS(SCALE_NORM(r->ax_s_btau, w->m),
+ MAX(MAX(SCALE_NORM(r->ax, w->m), SCALE_NORM(xys->s, w->m)),
+ SCALE_NORM(b, w->m) * r->tau));
+ /* ||Px + A'y + c * tau|| */
+ scs_float relative_res_dual =
+ SAFEDIV_POS(SCALE_NORM(r->px_aty_ctau, w->n),
+ MAX(MAX(SCALE_NORM(r->px, w->n), SCALE_NORM(r->aty, w->n)),
+ SCALE_NORM(c, w->n) * r->tau));
+
+ /* higher scale makes res_pri go down faster, so increase if res_pri larger */
+ w->sum_log_scale_factor += log(relative_res_pri) - log(relative_res_dual);
+ w->n_log_scale_factor++;
+
+ /* geometric mean */
+ factor =
+ SQRTF(exp(w->sum_log_scale_factor / (scs_float)(w->n_log_scale_factor)));
+
+ /* need at least RESCALING_MIN_ITERS since last update */
+ if (iters_since_last_update < RESCALING_MIN_ITERS) {
+ return;
}
+ new_scale = MIN(MAX(w->scale * factor, MIN_SCALE_VALUE), MAX_SCALE_VALUE);
+ if (new_scale == w->scale) {
+ return;
+ }
+ if (should_update_rho_y_vec(factor, iters_since_last_update)) {
+ w->scale_updates++;
+ w->sum_log_scale_factor = 0;
+ w->n_log_scale_factor = 0;
+ w->last_scale_update_iter = iter;
+ w->scale = new_scale;
+ SCS(set_rho_y_vec)(k, w->scale, w->rho_y_vec, w->m);
+ SCS(update_lin_sys_rho_y_vec)(w->p, w->rho_y_vec);
+
+ /* update pre-solved quantities */
+ update_work_cache(w);
+
+ /* reset acceleration so that old iterates aren't affecting new values */
+ if (w->accel) {
+ aa_reset(w->accel);
+ }
+ /* update v, using fact that rsk, u, u_t vectors should be the same */
+ /* solve: R (v^+ + u - 2u_t) = rsk => v^+ = R^-1 rsk + 2u_t - u */
+ /* only elements with scale on diag */
+ for (i = w->n; i < w->n + w->m; i++) {
+ w->v[i] = w->rsk[i] / w->rho_y_vec[i - w->n] + 2 * w->u_t[i] - w->u[i];
+ }
+ }
}
-scs_int SCS(solve)(ScsWork *w, const ScsData *d, const ScsCone *k,
- ScsSolution *sol, ScsInfo *info) {
+/* scs is homogeneous so scale the iterate to keep norm reasonable */
+static inline void normalize_v(scs_float *v, scs_int len) {
+ scs_float v_norm = SCS(norm_2)(v, len); /* always l2 norm */
+ SCS(scale_array)(v, SQRTF((scs_float)len) * ITERATE_NORM / v_norm, len);
+}
+
+scs_int SCS(solve)(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
scs_int i;
- SCS(timer) solve_timer, accel_timer;
- scs_float total_accel_time = 0.0, total_norm;
- ScsResiduals r;
- scs_int l = w->m + w->n + 1;
- if (!d || !k || !sol || !info || !w || !d->b || !d->c) {
- scs_printf("ERROR: SCS_NULL input\n");
+ SCS(timer) solve_timer, lin_sys_timer, cone_timer, accel_timer;
+ scs_float total_accel_time = 0.0, total_cone_time = 0.0,
+ total_lin_sys_time = 0.0;
+ if (!sol || !w || !info) {
+ scs_printf("ERROR: missing ScsWork, ScsSolution or ScsInfo input\n");
return SCS_FAILED;
}
+ scs_int l = w->m + w->n + 1;
+ const ScsData *d = w->d;
+ const ScsCone *k = w->k;
+ const ScsSettings *stgs = w->stgs;
/* initialize ctrl-c support */
scs_start_interrupt_listener();
SCS(tic)(&solve_timer);
info->status_val = SCS_UNFINISHED; /* not yet converged */
- r.last_iter = -1;
update_work(d, w, sol);
if (w->stgs->verbose) {
print_header(w, k);
}
- /* scs: */
+
+ /* SCS */
for (i = 0; i < w->stgs->max_iters; ++i) {
- /* accelerate here so that last step always projection onto cone */
+ /* Accelerate here so that last step always projection onto cone */
/* this ensures the returned iterates always satisfy conic constraints */
- /* this relies on the fact that u and v are contiguous in memory */
- SCS(tic)(&accel_timer);
- if (i > 0 && aa_apply(w->u, w->u_prev, w->accel) != 0) {
- /*
- return failure(w, w->m, w->n, sol, info, SCS_FAILED,
- "error in accelerate", "Failure");
- */
+ if (w->accel) {
+ SCS(tic)(&accel_timer);
+ if (i > 0 && i % w->stgs->acceleration_interval == 0) {
+ /* v overwritten with AA output here */
+ w->aa_norm = aa_apply(w->v, w->v_prev, w->accel);
+ }
+ total_accel_time += SCS(tocq)(&accel_timer);
}
- total_accel_time += SCS(tocq)(&accel_timer);
- /* scs is homogeneous so scale the iterates to keep norm reasonable */
- total_norm = SQRTF(SCS(norm_sq)(w->u, l) + SCS(norm_sq)(w->v, l));
- SCS(scale_array)(w->u, SQRTF((scs_float)l) * ITERATE_NORM / total_norm, l);
- SCS(scale_array)(w->v, SQRTF((scs_float)l) * ITERATE_NORM / total_norm, l);
+ if (i >= FEASIBLE_ITERS) {
+ /* normalize v *after* applying any acceleration */
+ /* the input to the DR step should be normalized */
+ normalize_v(w->v, l);
+ }
- memcpy(w->u_prev, w->u, l * sizeof(scs_float));
+ /* store v_prev = v, *after* normalizing */
memcpy(w->v_prev, w->v, l * sizeof(scs_float));
+ /* linear system solve */
+ SCS(tic)(&lin_sys_timer);
if (project_lin_sys(w, i) < 0) {
return failure(w, w->m, w->n, sol, info, SCS_FAILED,
- "error in project_lin_sys", "Failure");
+ "error in project_lin_sys", "failure");
}
+ total_lin_sys_time += SCS(tocq)(&lin_sys_timer);
+
+ /* project onto the cones */
+ SCS(tic)(&cone_timer);
if (project_cones(w, k, i) < 0) {
return failure(w, w->m, w->n, sol, info, SCS_FAILED,
- "error in project_cones", "Failure");
+ "error in project_cones", "failure");
}
+ total_cone_time += SCS(tocq)(&cone_timer);
+ /* dual variable step */
update_dual_vars(w);
- if (scs_is_interrupted()) {
- return failure(w, w->m, w->n, sol, info, SCS_SIGINT, "Interrupted",
- "Interrupted");
- }
- if (i % CONVERGED_INTERVAL == 0 || iterate_norm_diff(w) < 1e-10) {
- calc_residuals(w, &r, i);
- if ((info->status_val = has_converged(w, &r, i)) != 0) {
+ if (i % CONVERGED_INTERVAL == 0) {
+ if (scs_is_interrupted()) {
+ return failure(w, w->m, w->n, sol, info, SCS_SIGINT, "interrupted",
+ "interrupted");
+ }
+ populate_residual_struct(w, i);
+ if ((info->status_val = has_converged(w, i)) != 0) {
break;
}
- update_best_iterate(w, &r);
+ if (w->stgs->time_limit_secs) {
+ if (SCS(tocq)(&solve_timer) > 1000. * w->stgs->time_limit_secs) {
+ w->time_limit_reached = 1;
+ break;
+ }
+ }
}
+ /* AA safeguard check.
+ * Perform safeguarding *after* convergence check to prevent safeguard
+ * overwriting converged iterate, since safeguard is on `v` and convergence
+ * is on `u`.
+ */
+ if (w->accel && i % w->stgs->acceleration_interval == 0 && w->aa_norm > 0) {
+ if (aa_safeguard(w->v, w->v_prev, w->accel) < 0) {
+ /* TODO should we copy u from u_prev here too? Then move above, possibly
+ * better residual calculation and scale updating. */
+ w->rejected_accel_steps++;
+ } else {
+ w->accepted_accel_steps++;
+ }
+ }
+
+ /* Compute residuals. */
if (w->stgs->verbose && i % PRINT_INTERVAL == 0) {
- calc_residuals(w, &r, i);
- update_best_iterate(w, &r);
- print_summary(w, i, &r, &solve_timer);
+ populate_residual_struct(w, i);
+ print_summary(w, i, &solve_timer);
}
+
+ /* If residuals are fresh then maybe compute new scale. */
+ if (w->stgs->adaptive_scale && i == w->r_orig->last_iter) {
+ maybe_update_scale(w, k, i);
+ }
+
+ /* Log *after* updating scale so residual recalc does not affect alg */
+ if (w->stgs->log_csv_filename) {
+ /* calc residuals every iter if logging to csv */
+ populate_residual_struct(w, i);
+ SCS(log_data_to_csv)(d, k, stgs, w, i, &solve_timer);
+ }
}
+
+ /* Final logging after full run */
+ if (w->stgs->log_csv_filename) {
+ populate_residual_struct(w, i);
+ SCS(log_data_to_csv)(d, k, stgs, w, i, &solve_timer);
+ }
+
if (w->stgs->verbose) {
- calc_residuals(w, &r, i);
- print_summary(w, i, &r, &solve_timer);
+ populate_residual_struct(w, i);
+ print_summary(w, i, &solve_timer);
}
+
/* populate solution vectors (unnormalized) and info */
- get_solution(w, sol, info, &r, i);
+ finalize(w, sol, info, i);
+
+ /* populate timings */
info->solve_time = SCS(tocq)(&solve_timer);
+ info->lin_sys_time = total_lin_sys_time;
+ info->cone_time = total_cone_time;
+ info->accel_time = total_accel_time;
if (w->stgs->verbose) {
- print_footer(d, k, sol, w, info, total_accel_time);
+ print_footer(info);
}
+
scs_end_interrupt_listener();
return info->status_val;
}
void SCS(finish)(ScsWork *w) {
if (w) {
SCS(finish_cone)(w->cone_work);
if (w->stgs && w->stgs->normalize) {
#ifndef COPYAMATRIX
- SCS(un_normalize_a)(w->A, w->stgs, w->scal);
+ SCS(un_normalize)(w->A, w->P, w->scal);
#else
- SCS(free_a_matrix)(w->A);
+ SCS(free_scs_matrix)(w->A);
+ SCS(free_scs_matrix)(w->P);
#endif
}
if (w->p) {
SCS(free_lin_sys_work)(w->p);
}
@@ -921,58 +1132,51 @@
}
free_work(w);
}
}
-ScsWork *SCS(init)(const ScsData *d, const ScsCone *k, ScsInfo *info) {
-#if EXTRA_VERBOSE > 1
- SCS(tic)(&global_timer);
-#endif
+ScsWork *SCS(init)(const ScsData *d, const ScsCone *k,
+ const ScsSettings *stgs) {
ScsWork *w;
SCS(timer) init_timer;
scs_start_interrupt_listener();
- if (!d || !k || !info) {
- scs_printf("ERROR: Missing ScsData, ScsCone or ScsInfo input\n");
+ if (!d || !k) {
+ scs_printf("ERROR: Missing ScsData or ScsCone input\n");
return SCS_NULL;
}
-#if EXTRA_VERBOSE > 0
- SCS(print_data)(d);
- SCS(print_cone_data)(k);
-#endif
-#ifndef NOVALIDATE
- if (validate(d, k) < 0) {
+#if NOVALIDATE == 0
+ if (validate(d, k, stgs) < 0) {
scs_printf("ERROR: Validation returned failure\n");
return SCS_NULL;
}
#endif
SCS(tic)(&init_timer);
- if (d->stgs->write_data_filename) {
- SCS(write_data)(d, k);
+ if (stgs->write_data_filename) {
+ SCS(write_data)(d, k, stgs);
}
- w = init_work(d, k);
- info->setup_time = SCS(tocq)(&init_timer);
- if (d->stgs->verbose) {
- scs_printf("Setup time: %1.2es\n", info->setup_time / 1e3);
+ w = init_work(d, k, stgs);
+ if (w) {
+ w->setup_time = SCS(tocq)(&init_timer);
}
scs_end_interrupt_listener();
return w;
}
/* this just calls SCS(init), SCS(solve), and SCS(finish) */
-scs_int scs(const ScsData *d, const ScsCone *k, ScsSolution *sol,
- ScsInfo *info) {
+scs_int scs(const ScsData *d, const ScsCone *k, const ScsSettings *stgs,
+ ScsSolution *sol, ScsInfo *info) {
scs_int status;
- ScsWork *w = SCS(init)(d, k, info);
-#if EXTRA_VERBOSE > 0
+ ScsWork *w = SCS(init)(d, k, stgs);
+#if VERBOSITY > 0
scs_printf("size of scs_int = %lu, size of scs_float = %lu\n",
sizeof(scs_int), sizeof(scs_float));
#endif
if (w) {
- SCS(solve)(w, d, k, sol, info);
+ SCS(solve)(w, sol, info);
status = info->status_val;
} else {
status = failure(SCS_NULL, d ? d->m : -1, d ? d->n : -1, sol, info,
- SCS_FAILED, "could not initialize work", "Failure");
+ SCS_FAILED, "could not initialize work", "failure");
}
SCS(finish)(w);
return status;
}