scs 0.2.3 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +11 -6
- data/lib/scs/ffi.rb +30 -13
- data/lib/scs/solver.rb +32 -9
- data/lib/scs/version.rb +1 -1
- data/vendor/scs/CITATION.cff +39 -0
- data/vendor/scs/CMakeLists.txt +7 -8
- data/vendor/scs/Makefile +24 -15
- data/vendor/scs/README.md +5 -263
- data/vendor/scs/include/aa.h +67 -23
- data/vendor/scs/include/cones.h +17 -17
- data/vendor/scs/include/glbopts.h +98 -32
- data/vendor/scs/include/linalg.h +2 -4
- data/vendor/scs/include/linsys.h +58 -44
- data/vendor/scs/include/normalize.h +3 -3
- data/vendor/scs/include/rw.h +8 -2
- data/vendor/scs/include/scs.h +293 -133
- data/vendor/scs/include/util.h +3 -15
- data/vendor/scs/linsys/cpu/direct/private.c +220 -224
- data/vendor/scs/linsys/cpu/direct/private.h +13 -7
- data/vendor/scs/linsys/cpu/direct/private.o +0 -0
- data/vendor/scs/linsys/cpu/indirect/private.c +177 -110
- data/vendor/scs/linsys/cpu/indirect/private.h +8 -4
- data/vendor/scs/linsys/cpu/indirect/private.o +0 -0
- data/vendor/scs/linsys/csparse.c +87 -0
- data/vendor/scs/linsys/csparse.h +34 -0
- data/vendor/scs/linsys/csparse.o +0 -0
- data/vendor/scs/linsys/external/amd/SuiteSparse_config.c +1 -1
- data/vendor/scs/linsys/external/amd/SuiteSparse_config.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_1.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_2.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_aat.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_control.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_defaults.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_dump.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_global.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_info.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_internal.h +1 -1
- data/vendor/scs/linsys/external/amd/amd_order.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_post_tree.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_postorder.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_preprocess.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_valid.o +0 -0
- data/vendor/scs/linsys/external/qdldl/changes +2 -0
- data/vendor/scs/linsys/external/qdldl/qdldl.c +29 -46
- data/vendor/scs/linsys/external/qdldl/qdldl.h +33 -41
- data/vendor/scs/linsys/external/qdldl/qdldl.o +0 -0
- data/vendor/scs/linsys/external/qdldl/qdldl_types.h +11 -3
- data/vendor/scs/linsys/gpu/gpu.c +31 -33
- data/vendor/scs/linsys/gpu/gpu.h +48 -31
- data/vendor/scs/linsys/gpu/indirect/private.c +338 -232
- data/vendor/scs/linsys/gpu/indirect/private.h +23 -14
- data/vendor/scs/linsys/scs_matrix.c +498 -0
- data/vendor/scs/linsys/scs_matrix.h +70 -0
- data/vendor/scs/linsys/scs_matrix.o +0 -0
- data/vendor/scs/scs.mk +13 -9
- data/vendor/scs/src/aa.c +384 -109
- data/vendor/scs/src/aa.o +0 -0
- data/vendor/scs/src/cones.c +440 -353
- data/vendor/scs/src/cones.o +0 -0
- data/vendor/scs/src/ctrlc.c +15 -5
- data/vendor/scs/src/ctrlc.o +0 -0
- data/vendor/scs/src/linalg.c +84 -28
- data/vendor/scs/src/linalg.o +0 -0
- data/vendor/scs/src/normalize.c +22 -64
- data/vendor/scs/src/normalize.o +0 -0
- data/vendor/scs/src/rw.c +160 -21
- data/vendor/scs/src/rw.o +0 -0
- data/vendor/scs/src/scs.c +767 -563
- data/vendor/scs/src/scs.o +0 -0
- data/vendor/scs/src/scs_indir.o +0 -0
- data/vendor/scs/src/scs_version.c +9 -3
- data/vendor/scs/src/scs_version.o +0 -0
- data/vendor/scs/src/util.c +37 -106
- data/vendor/scs/src/util.o +0 -0
- data/vendor/scs/test/minunit.h +17 -8
- data/vendor/scs/test/problem_utils.h +176 -14
- data/vendor/scs/test/problems/degenerate.h +130 -0
- data/vendor/scs/test/problems/hs21_tiny_qp.h +124 -0
- data/vendor/scs/test/problems/hs21_tiny_qp_rw.h +116 -0
- data/vendor/scs/test/problems/infeasible_tiny_qp.h +100 -0
- data/vendor/scs/test/problems/qafiro_tiny_qp.h +199 -0
- data/vendor/scs/test/problems/random_prob +0 -0
- data/vendor/scs/test/problems/random_prob.h +45 -0
- data/vendor/scs/test/problems/rob_gauss_cov_est.h +188 -31
- data/vendor/scs/test/problems/small_lp.h +13 -14
- data/vendor/scs/test/problems/test_fails.h +43 -0
- data/vendor/scs/test/problems/unbounded_tiny_qp.h +82 -0
- data/vendor/scs/test/random_socp_prob.c +54 -53
- data/vendor/scs/test/rng.h +109 -0
- data/vendor/scs/test/run_from_file.c +19 -10
- data/vendor/scs/test/run_tests.c +27 -3
- metadata +20 -8
- data/vendor/scs/linsys/amatrix.c +0 -305
- data/vendor/scs/linsys/amatrix.h +0 -36
- data/vendor/scs/linsys/amatrix.o +0 -0
- data/vendor/scs/test/data/small_random_socp +0 -0
- data/vendor/scs/test/problems/small_random_socp.h +0 -33
- data/vendor/scs/test/run_tests +0 -2
data/vendor/scs/src/scs.c
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
#include "scs.h"
|
|
2
|
-
|
|
3
2
|
#include "aa.h"
|
|
4
3
|
#include "ctrlc.h"
|
|
5
4
|
#include "glbopts.h"
|
|
@@ -7,88 +6,107 @@
|
|
|
7
6
|
#include "linsys.h"
|
|
8
7
|
#include "normalize.h"
|
|
9
8
|
#include "rw.h"
|
|
9
|
+
#include "scs_matrix.h"
|
|
10
10
|
#include "util.h"
|
|
11
11
|
|
|
12
|
-
SCS(timer) global_timer;
|
|
13
|
-
|
|
14
12
|
/* printing header */
|
|
15
13
|
static const char *HEADER[] = {
|
|
16
|
-
"
|
|
17
|
-
"
|
|
14
|
+
" iter ", " pri res ", " dua res ", " gap ",
|
|
15
|
+
" obj ", " scale ", " time (s)",
|
|
18
16
|
};
|
|
19
17
|
static const scs_int HSPACE = 9;
|
|
20
|
-
static const scs_int HEADER_LEN =
|
|
21
|
-
static const scs_int LINE_LEN =
|
|
22
|
-
|
|
23
|
-
static
|
|
18
|
+
static const scs_int HEADER_LEN = 7;
|
|
19
|
+
static const scs_int LINE_LEN = 66;
|
|
20
|
+
|
|
21
|
+
static void free_residuals(ScsResiduals *r) {
|
|
22
|
+
if (r) {
|
|
23
|
+
scs_free(r->ax);
|
|
24
|
+
scs_free(r->ax_s);
|
|
25
|
+
scs_free(r->px);
|
|
26
|
+
scs_free(r->aty);
|
|
27
|
+
scs_free(r->ax_s_btau);
|
|
28
|
+
scs_free(r->px_aty_ctau);
|
|
29
|
+
scs_free(r);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
24
32
|
|
|
25
33
|
static void free_work(ScsWork *w) {
|
|
26
34
|
if (w) {
|
|
27
35
|
scs_free(w->u);
|
|
28
|
-
scs_free(w->u_best);
|
|
29
36
|
scs_free(w->u_t);
|
|
30
|
-
scs_free(w->
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
scs_free(w->v_best);
|
|
34
|
-
scs_free(w->v_prev);
|
|
35
|
-
*/
|
|
37
|
+
scs_free(w->v);
|
|
38
|
+
scs_free(w->v_prev);
|
|
39
|
+
scs_free(w->rsk);
|
|
36
40
|
scs_free(w->h);
|
|
37
41
|
scs_free(w->g);
|
|
38
|
-
scs_free(w->
|
|
39
|
-
scs_free(w->
|
|
40
|
-
scs_free(w->
|
|
41
|
-
scs_free(w->
|
|
42
|
+
scs_free(w->b_normalized);
|
|
43
|
+
scs_free(w->c_normalized);
|
|
44
|
+
scs_free(w->rho_y_vec);
|
|
45
|
+
scs_free(w->lin_sys_warm_start);
|
|
46
|
+
if (w->cone_boundaries) {
|
|
47
|
+
scs_free(w->cone_boundaries);
|
|
48
|
+
}
|
|
42
49
|
if (w->scal) {
|
|
43
50
|
scs_free(w->scal->D);
|
|
44
51
|
scs_free(w->scal->E);
|
|
45
52
|
scs_free(w->scal);
|
|
46
53
|
}
|
|
54
|
+
SCS(free_sol)(w->xys_orig);
|
|
55
|
+
free_residuals(w->r_orig);
|
|
56
|
+
if (w->stgs->normalize) {
|
|
57
|
+
SCS(free_sol)(w->xys_normalized);
|
|
58
|
+
free_residuals(w->r_normalized);
|
|
59
|
+
}
|
|
47
60
|
scs_free(w);
|
|
48
61
|
}
|
|
49
62
|
}
|
|
50
63
|
|
|
51
|
-
static void print_init_header(const ScsData *d, const ScsCone *k
|
|
64
|
+
static void print_init_header(const ScsData *d, const ScsCone *k,
|
|
65
|
+
const ScsSettings *stgs) {
|
|
52
66
|
scs_int i;
|
|
53
|
-
ScsSettings *stgs = d->stgs;
|
|
54
67
|
char *cone_str = SCS(get_cone_header)(k);
|
|
55
|
-
char *lin_sys_method = SCS(get_lin_sys_method)(
|
|
68
|
+
const char *lin_sys_method = SCS(get_lin_sys_method)();
|
|
56
69
|
#ifdef USE_LAPACK
|
|
57
70
|
scs_int acceleration_lookback = stgs->acceleration_lookback;
|
|
71
|
+
scs_int acceleration_interval = stgs->acceleration_interval;
|
|
58
72
|
#else
|
|
59
73
|
scs_int acceleration_lookback = 0;
|
|
74
|
+
scs_int acceleration_interval = 0;
|
|
60
75
|
#endif
|
|
61
76
|
for (i = 0; i < LINE_LEN; ++i) {
|
|
62
77
|
scs_printf("-");
|
|
63
78
|
}
|
|
64
|
-
scs_printf(
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
SCS(version)());
|
|
79
|
+
scs_printf("\n\t SCS v%s - Splitting Conic Solver\n\t(c) Brendan "
|
|
80
|
+
"O'Donoghue, Stanford University, 2012\n",
|
|
81
|
+
SCS(version)());
|
|
68
82
|
for (i = 0; i < LINE_LEN; ++i) {
|
|
69
83
|
scs_printf("-");
|
|
70
84
|
}
|
|
71
85
|
scs_printf("\n");
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
scs_free(lin_sys_method);
|
|
75
|
-
}
|
|
76
|
-
if (stgs->normalize) {
|
|
77
|
-
scs_printf(
|
|
78
|
-
"eps = %.2e, alpha = %.2f, max_iters = %i, normalize = %i, "
|
|
79
|
-
"scale = %2.2f\nacceleration_lookback = %i, rho_x = %.2e\n",
|
|
80
|
-
stgs->eps, stgs->alpha, (int)stgs->max_iters, (int)stgs->normalize,
|
|
81
|
-
stgs->scale, (int)acceleration_lookback, stgs->rho_x);
|
|
82
|
-
} else {
|
|
83
|
-
scs_printf(
|
|
84
|
-
"eps = %.2e, alpha = %.2f, max_iters = %i, normalize = %i\n"
|
|
85
|
-
"acceleration_lookback = %i, rho_x = %.2e\n",
|
|
86
|
-
stgs->eps, stgs->alpha, (int)stgs->max_iters, (int)stgs->normalize,
|
|
87
|
-
(int)acceleration_lookback, stgs->rho_x);
|
|
88
|
-
}
|
|
89
|
-
scs_printf("Variables n = %i, constraints m = %i\n", (int)d->n, (int)d->m);
|
|
86
|
+
scs_printf("problem: variables n: %i, constraints m: %i\n", (int)d->n,
|
|
87
|
+
(int)d->m);
|
|
90
88
|
scs_printf("%s", cone_str);
|
|
91
89
|
scs_free(cone_str);
|
|
90
|
+
scs_printf("settings: eps_abs: %.1e, eps_rel: %.1e, eps_infeas: %.1e\n"
|
|
91
|
+
"\t alpha: %.2f, scale: %.2e, adaptive_scale: %i\n"
|
|
92
|
+
"\t max_iters: %i, normalize: %i, warm_start: %i\n",
|
|
93
|
+
/*, rho_x: %.2e\n", */
|
|
94
|
+
stgs->eps_abs, stgs->eps_rel, stgs->eps_infeas, stgs->alpha,
|
|
95
|
+
stgs->scale, (int)stgs->adaptive_scale, (int)stgs->max_iters,
|
|
96
|
+
(int)stgs->normalize, (int)stgs->warm_start);
|
|
97
|
+
/* , stgs->rho_x); */
|
|
98
|
+
if (stgs->acceleration_lookback != 0) {
|
|
99
|
+
scs_printf("\t acceleration_lookback: %i, acceleration_interval: %i\n",
|
|
100
|
+
(int)acceleration_lookback, (int)acceleration_interval);
|
|
101
|
+
}
|
|
102
|
+
if (stgs->time_limit_secs) {
|
|
103
|
+
scs_printf("\t time_limit_secs: %.2e\n", stgs->time_limit_secs);
|
|
104
|
+
}
|
|
105
|
+
if (lin_sys_method) {
|
|
106
|
+
scs_printf("lin-sys: %s\n\t nnz(A): %li, nnz(P): %li\n", lin_sys_method,
|
|
107
|
+
(long)d->A->p[d->A->n], d->P ? (long)d->P->p[d->P->n] : 0l);
|
|
108
|
+
}
|
|
109
|
+
|
|
92
110
|
#ifdef MATLAB_MEX_FILE
|
|
93
111
|
mexEvalString("drawnow;");
|
|
94
112
|
#endif
|
|
@@ -98,7 +116,7 @@ static void populate_on_failure(scs_int m, scs_int n, ScsSolution *sol,
|
|
|
98
116
|
ScsInfo *info, scs_int status_val,
|
|
99
117
|
const char *msg) {
|
|
100
118
|
if (info) {
|
|
101
|
-
info->
|
|
119
|
+
info->gap = NAN;
|
|
102
120
|
info->res_pri = NAN;
|
|
103
121
|
info->res_dual = NAN;
|
|
104
122
|
info->pobj = NAN;
|
|
@@ -111,17 +129,17 @@ static void populate_on_failure(scs_int m, scs_int n, ScsSolution *sol,
|
|
|
111
129
|
if (sol) {
|
|
112
130
|
if (n > 0) {
|
|
113
131
|
if (!sol->x) {
|
|
114
|
-
sol->x = (scs_float *)
|
|
132
|
+
sol->x = (scs_float *)scs_calloc(n, sizeof(scs_float));
|
|
115
133
|
}
|
|
116
134
|
SCS(scale_array)(sol->x, NAN, n);
|
|
117
135
|
}
|
|
118
136
|
if (m > 0) {
|
|
119
137
|
if (!sol->y) {
|
|
120
|
-
sol->y = (scs_float *)
|
|
138
|
+
sol->y = (scs_float *)scs_calloc(m, sizeof(scs_float));
|
|
121
139
|
}
|
|
122
140
|
SCS(scale_array)(sol->y, NAN, m);
|
|
123
141
|
if (!sol->s) {
|
|
124
|
-
sol->s = (scs_float *)
|
|
142
|
+
sol->s = (scs_float *)scs_calloc(m, sizeof(scs_float));
|
|
125
143
|
}
|
|
126
144
|
SCS(scale_array)(sol->s, NAN, m);
|
|
127
145
|
}
|
|
@@ -138,70 +156,90 @@ static scs_int failure(ScsWork *w, scs_int m, scs_int n, ScsSolution *sol,
|
|
|
138
156
|
return status;
|
|
139
157
|
}
|
|
140
158
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
w->
|
|
149
|
-
|
|
150
|
-
for (i = 0; i < n + m + 1; ++i) {
|
|
151
|
-
if (scs_isnan(w->u[i])) {
|
|
152
|
-
w->u[i] = 0;
|
|
153
|
-
}
|
|
154
|
-
if (scs_isnan(w->v[i])) {
|
|
155
|
-
w->v[i] = 0;
|
|
156
|
-
}
|
|
159
|
+
/* given x,y,s warm start, set v = [x; s / R + y; 1]
|
|
160
|
+
* where R = diag(w->rho_y_vec).
|
|
161
|
+
*/
|
|
162
|
+
static void warm_start_vars(ScsWork *w, ScsSolution *sol) {
|
|
163
|
+
scs_int n = w->n, m = w->m, i;
|
|
164
|
+
scs_float *v = w->v;
|
|
165
|
+
/* normalize the warm-start */
|
|
166
|
+
if (w->stgs->normalize) {
|
|
167
|
+
SCS(normalize_sol)(w, sol);
|
|
157
168
|
}
|
|
158
|
-
|
|
169
|
+
memcpy(v, sol->x, n * sizeof(scs_float));
|
|
170
|
+
for (i = 0; i < m; ++i) {
|
|
171
|
+
v[i + n] = sol->y[i] + sol->s[i] / w->rho_y_vec[i];
|
|
172
|
+
}
|
|
173
|
+
v[n + m] = 1.0; /* tau = 1 */
|
|
174
|
+
/* un-normalize so sol unchanged */
|
|
159
175
|
if (w->stgs->normalize) {
|
|
160
|
-
SCS(
|
|
176
|
+
SCS(un_normalize_sol)(w, sol);
|
|
161
177
|
}
|
|
162
178
|
}
|
|
163
179
|
|
|
164
|
-
static
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
for (i = 0; i < w->m; ++i) {
|
|
174
|
-
scale = w->stgs->normalize ? w->scal->D[i] / (w->sc_b * w->stgs->scale) : 1;
|
|
175
|
-
scale = scale * scale;
|
|
176
|
-
*nm_axs += (pr[i] * pr[i]) * scale;
|
|
177
|
-
pres += (pr[i] - w->b[i] * tau) * (pr[i] - w->b[i] * tau) * scale;
|
|
178
|
-
}
|
|
179
|
-
*nm_axs = SQRTF(*nm_axs);
|
|
180
|
-
return SQRTF(pres); /* SCS(norm)(Ax + s - b * tau) */
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
static scs_float calc_dual_resid(ScsWork *w, const scs_float *y,
|
|
184
|
-
const scs_float tau, scs_float *nm_a_ty) {
|
|
185
|
-
scs_int i;
|
|
186
|
-
scs_float dres = 0, scale, *dr = w->dr;
|
|
187
|
-
*nm_a_ty = 0;
|
|
188
|
-
memset(dr, 0, w->n * sizeof(scs_float));
|
|
189
|
-
SCS(accum_by_atrans)(w->A, w->p, y, dr); /* dr = A'y */
|
|
190
|
-
for (i = 0; i < w->n; ++i) {
|
|
191
|
-
scale = w->stgs->normalize ? w->scal->E[i] / (w->sc_c * w->stgs->scale) : 1;
|
|
192
|
-
scale = scale * scale;
|
|
193
|
-
*nm_a_ty += (dr[i] * dr[i]) * scale;
|
|
194
|
-
dres += (dr[i] + w->c[i] * tau) * (dr[i] + w->c[i] * tau) * scale;
|
|
180
|
+
static void compute_residuals(ScsResiduals *r, scs_int m, scs_int n) {
|
|
181
|
+
r->res_pri = SAFEDIV_POS(NORM(r->ax_s_btau, m), r->tau);
|
|
182
|
+
r->res_dual = SAFEDIV_POS(NORM(r->px_aty_ctau, n), r->tau);
|
|
183
|
+
r->res_unbdd_a = NAN;
|
|
184
|
+
r->res_unbdd_p = NAN;
|
|
185
|
+
r->res_infeas = NAN;
|
|
186
|
+
if (r->ctx_tau < 0) {
|
|
187
|
+
r->res_unbdd_a = SAFEDIV_POS(NORM(r->ax_s, m), -r->ctx_tau);
|
|
188
|
+
r->res_unbdd_p = SAFEDIV_POS(NORM(r->px, n), -r->ctx_tau);
|
|
195
189
|
}
|
|
196
|
-
|
|
197
|
-
|
|
190
|
+
if (r->bty_tau < 0) {
|
|
191
|
+
r->res_infeas = SAFEDIV_POS(NORM(r->aty, n), -r->bty_tau);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
static void unnormalize_residuals(ScsWork *w) {
|
|
196
|
+
ScsResiduals *r_n = w->r_normalized; /* normalized residuals */
|
|
197
|
+
ScsResiduals *r = w->r_orig; /* original problem residuals */
|
|
198
|
+
scs_float pd = w->scal->primal_scale * w->scal->dual_scale;
|
|
199
|
+
|
|
200
|
+
/* copy vars */
|
|
201
|
+
r->last_iter = r_n->last_iter;
|
|
202
|
+
r->tau = r_n->tau;
|
|
203
|
+
|
|
204
|
+
/* mem copy arrays */
|
|
205
|
+
memcpy(r->ax, r_n->ax, w->m * sizeof(scs_float));
|
|
206
|
+
memcpy(r->ax_s, r_n->ax_s, w->m * sizeof(scs_float));
|
|
207
|
+
memcpy(r->ax_s_btau, r_n->ax_s_btau, w->m * sizeof(scs_float));
|
|
208
|
+
memcpy(r->aty, r_n->aty, w->n * sizeof(scs_float));
|
|
209
|
+
memcpy(r->px, r_n->px, w->n * sizeof(scs_float));
|
|
210
|
+
memcpy(r->px_aty_ctau, r_n->px_aty_ctau, w->n * sizeof(scs_float));
|
|
211
|
+
|
|
212
|
+
/* unnormalize */
|
|
213
|
+
r->kap = r_n->kap / pd;
|
|
214
|
+
r->bty_tau = r_n->bty_tau / pd;
|
|
215
|
+
r->ctx_tau = r_n->ctx_tau / pd;
|
|
216
|
+
r->xt_p_x_tau = r_n->xt_p_x_tau / pd;
|
|
217
|
+
r->xt_p_x = r_n->xt_p_x / pd;
|
|
218
|
+
r->ctx = r_n->ctx / pd;
|
|
219
|
+
r->bty = r_n->bty / pd;
|
|
220
|
+
r->pobj = r_n->pobj / pd;
|
|
221
|
+
r->dobj = r_n->dobj / pd;
|
|
222
|
+
r->gap = r_n->gap / pd;
|
|
223
|
+
|
|
224
|
+
SCS(un_normalize_primal)(w, r->ax);
|
|
225
|
+
SCS(un_normalize_primal)(w, r->ax_s);
|
|
226
|
+
SCS(un_normalize_primal)(w, r->ax_s_btau);
|
|
227
|
+
SCS(un_normalize_dual)(w, r->aty);
|
|
228
|
+
SCS(un_normalize_dual)(w, r->px);
|
|
229
|
+
SCS(un_normalize_dual)(w, r->px_aty_ctau);
|
|
230
|
+
|
|
231
|
+
compute_residuals(r, w->m, w->n);
|
|
198
232
|
}
|
|
199
233
|
|
|
200
|
-
/* calculates un-normalized quantities */
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
scs_float nmpr_tau, nmdr_tau, nm_axs_tau, nm_a_ty_tau, ct_x, bt_y;
|
|
234
|
+
/* calculates un-normalized residual quantities */
|
|
235
|
+
/* this is somewhat slow but not a bottleneck */
|
|
236
|
+
static void populate_residual_struct(ScsWork *w, scs_int iter) {
|
|
204
237
|
scs_int n = w->n, m = w->m;
|
|
238
|
+
/* normalized x,y,s terms */
|
|
239
|
+
scs_float *x = w->xys_normalized->x;
|
|
240
|
+
scs_float *y = w->xys_normalized->y;
|
|
241
|
+
scs_float *s = w->xys_normalized->s;
|
|
242
|
+
ScsResiduals *r = w->r_normalized; /* normalized residuals */
|
|
205
243
|
|
|
206
244
|
/* checks if the residuals are unchanged by checking iteration */
|
|
207
245
|
if (r->last_iter == iter) {
|
|
@@ -209,272 +247,350 @@ static void calc_residuals(ScsWork *w, ScsResiduals *r, scs_int iter) {
|
|
|
209
247
|
}
|
|
210
248
|
r->last_iter = iter;
|
|
211
249
|
|
|
250
|
+
memcpy(x, w->u, n * sizeof(scs_float));
|
|
251
|
+
memcpy(y, &(w->u[n]), m * sizeof(scs_float));
|
|
252
|
+
memcpy(s, &(w->rsk[n]), m * sizeof(scs_float));
|
|
253
|
+
|
|
212
254
|
r->tau = ABS(w->u[n + m]);
|
|
213
|
-
r->kap = ABS(w->
|
|
214
|
-
|
|
255
|
+
r->kap = ABS(w->rsk[n + m]);
|
|
256
|
+
|
|
257
|
+
/**************** PRIMAL *********************/
|
|
258
|
+
memset(r->ax, 0, m * sizeof(scs_float));
|
|
259
|
+
/* ax = Ax */
|
|
260
|
+
SCS(accum_by_a)(w->A, x, r->ax);
|
|
261
|
+
|
|
262
|
+
memcpy(r->ax_s, r->ax, m * sizeof(scs_float));
|
|
263
|
+
/* ax_s = Ax + s */
|
|
264
|
+
SCS(add_scaled_array)(r->ax_s, s, m, 1.);
|
|
265
|
+
|
|
266
|
+
memcpy(r->ax_s_btau, r->ax_s, m * sizeof(scs_float));
|
|
267
|
+
/* ax_s_btau = Ax + s - b * tau */
|
|
268
|
+
SCS(add_scaled_array)(r->ax_s_btau, w->b_normalized, m, -r->tau);
|
|
269
|
+
|
|
270
|
+
/**************** DUAL *********************/
|
|
271
|
+
memset(r->px, 0, n * sizeof(scs_float));
|
|
272
|
+
if (w->P) {
|
|
273
|
+
/* px = Px */
|
|
274
|
+
SCS(accum_by_p)(w->P, x, r->px);
|
|
275
|
+
r->xt_p_x_tau = SCS(dot)(r->px, x, n);
|
|
276
|
+
} else {
|
|
277
|
+
r->xt_p_x_tau = 0.;
|
|
278
|
+
}
|
|
215
279
|
|
|
216
|
-
|
|
217
|
-
|
|
280
|
+
memset(r->aty, 0, n * sizeof(scs_float));
|
|
281
|
+
/* aty = A'y */
|
|
282
|
+
SCS(accum_by_atrans)(w->A, y, r->aty);
|
|
218
283
|
|
|
219
|
-
r->
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
r->
|
|
223
|
-
|
|
224
|
-
|
|
284
|
+
/* r->px_aty_ctau = Px */
|
|
285
|
+
memcpy(r->px_aty_ctau, r->px, n * sizeof(scs_float));
|
|
286
|
+
/* r->px_aty_ctau = Px + A'y */
|
|
287
|
+
SCS(add_scaled_array)(r->px_aty_ctau, r->aty, n, 1.);
|
|
288
|
+
/* r->px_aty_ctau = Px + A'y + c * tau */
|
|
289
|
+
SCS(add_scaled_array)(r->px_aty_ctau, w->c_normalized, n, r->tau);
|
|
225
290
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
r->
|
|
229
|
-
r->ct_x_by_tau < 0 ? w->nm_c * nm_axs_tau / -r->ct_x_by_tau : NAN;
|
|
291
|
+
/**************** OTHERS *****************/
|
|
292
|
+
r->bty_tau = SCS(dot)(y, w->b_normalized, m);
|
|
293
|
+
r->ctx_tau = SCS(dot)(x, w->c_normalized, n);
|
|
230
294
|
|
|
231
|
-
|
|
232
|
-
|
|
295
|
+
r->bty = SAFEDIV_POS(r->bty_tau, r->tau);
|
|
296
|
+
r->ctx = SAFEDIV_POS(r->ctx_tau, r->tau);
|
|
297
|
+
r->xt_p_x = SAFEDIV_POS(r->xt_p_x_tau, r->tau * r->tau);
|
|
233
298
|
|
|
234
|
-
r->
|
|
235
|
-
r->
|
|
236
|
-
r->
|
|
299
|
+
r->gap = ABS(r->xt_p_x + r->ctx + r->bty);
|
|
300
|
+
r->pobj = r->xt_p_x / 2. + r->ctx;
|
|
301
|
+
r->dobj = -r->xt_p_x / 2. - r->bty;
|
|
302
|
+
|
|
303
|
+
compute_residuals(r, m, n);
|
|
304
|
+
|
|
305
|
+
if (w->stgs->normalize) {
|
|
306
|
+
memcpy(w->xys_orig->x, w->xys_normalized->x, n * sizeof(scs_float));
|
|
307
|
+
memcpy(w->xys_orig->y, w->xys_normalized->y, m * sizeof(scs_float));
|
|
308
|
+
memcpy(w->xys_orig->s, w->xys_normalized->s, m * sizeof(scs_float));
|
|
309
|
+
SCS(un_normalize_sol)(w, w->xys_orig);
|
|
310
|
+
unnormalize_residuals(w);
|
|
311
|
+
}
|
|
237
312
|
}
|
|
238
313
|
|
|
239
314
|
static void cold_start_vars(ScsWork *w) {
|
|
240
315
|
scs_int l = w->n + w->m + 1;
|
|
241
|
-
memset(w->u, 0, l * sizeof(scs_float));
|
|
242
316
|
memset(w->v, 0, l * sizeof(scs_float));
|
|
243
|
-
w->
|
|
244
|
-
w->v[l - 1] = SQRTF((scs_float)l);
|
|
317
|
+
w->v[l - 1] = 1.;
|
|
245
318
|
}
|
|
246
319
|
|
|
247
|
-
/*
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
320
|
+
/* utility function that scales first n entries in inner prod by rho_x */
|
|
321
|
+
/* and last m entries by 1 / rho_y_vec, assumes length of array is n + m */
|
|
322
|
+
/* See .note_on_scale in repo for explanation */
|
|
323
|
+
static scs_float dot_with_diag_scaling(ScsWork *w, const scs_float *x,
|
|
324
|
+
const scs_float *y) {
|
|
325
|
+
scs_int i, n = w->n, len = w->n + w->m;
|
|
326
|
+
scs_float ip = 0.0;
|
|
327
|
+
for (i = 0; i < n; ++i) {
|
|
328
|
+
ip += w->stgs->rho_x * x[i] * y[i];
|
|
329
|
+
}
|
|
330
|
+
for (i = n; i < len; ++i) {
|
|
331
|
+
ip += x[i] * y[i] * w->rho_y_vec[i - n];
|
|
332
|
+
}
|
|
333
|
+
return ip;
|
|
334
|
+
}
|
|
261
335
|
|
|
262
|
-
|
|
336
|
+
static inline scs_float get_tau_scale(ScsWork *w) {
|
|
337
|
+
return TAU_FACTOR; /* TAU_FACTOR * w->scale; */
|
|
338
|
+
}
|
|
263
339
|
|
|
264
|
-
|
|
340
|
+
static scs_float root_plus(ScsWork *w, scs_float *p, scs_float *mu,
|
|
341
|
+
scs_float eta) {
|
|
342
|
+
scs_float b, c, tau, a, tau_scale;
|
|
343
|
+
tau_scale = get_tau_scale(w);
|
|
344
|
+
a = tau_scale + dot_with_diag_scaling(w, w->g, w->g);
|
|
345
|
+
b = (dot_with_diag_scaling(w, mu, w->g) -
|
|
346
|
+
2 * dot_with_diag_scaling(w, p, w->g) - eta * tau_scale);
|
|
347
|
+
c = dot_with_diag_scaling(w, p, p) - dot_with_diag_scaling(w, p, mu);
|
|
348
|
+
tau = (-b + SQRTF(MAX(b * b - 4 * a * c, 0.))) / (2 * a);
|
|
349
|
+
return tau;
|
|
350
|
+
}
|
|
265
351
|
|
|
352
|
+
/* status < 0 indicates failure */
|
|
353
|
+
static scs_int project_lin_sys(ScsWork *w, scs_int iter) {
|
|
354
|
+
scs_int n = w->n, m = w->m, l = n + m + 1, status, i;
|
|
355
|
+
scs_float *warm_start = SCS_NULL;
|
|
356
|
+
scs_float tol = -1.0; /* only used for indirect methods, overriden later */
|
|
357
|
+
memcpy(w->u_t, w->v, l * sizeof(scs_float));
|
|
358
|
+
SCS(scale_array)(w->u_t, w->stgs->rho_x, n);
|
|
359
|
+
for (i = n; i < l - 1; ++i) {
|
|
360
|
+
w->u_t[i] *= -w->rho_y_vec[i - n];
|
|
361
|
+
}
|
|
362
|
+
#if INDIRECT > 0
|
|
363
|
+
/* compute warm start using the cone projection output */
|
|
364
|
+
warm_start = w->lin_sys_warm_start;
|
|
365
|
+
memcpy(warm_start, w->u, (l - 1) * sizeof(scs_float));
|
|
366
|
+
/* warm_start = u[:n] + tau * g[:n] */
|
|
367
|
+
SCS(add_scaled_array)(warm_start, w->g, l - 1, w->u[l - 1]);
|
|
368
|
+
/* use normalized residuals to compute tolerance */
|
|
369
|
+
tol = MIN(CG_NORM(w->r_normalized->ax_s_btau, w->m),
|
|
370
|
+
CG_NORM(w->r_normalized->px_aty_ctau, w->n));
|
|
371
|
+
/* tol ~ O(1/k^(1+eps)) guarantees convergence */
|
|
372
|
+
/* use warm-start to calculate tolerance rather than w->u_t, since warm_start
|
|
373
|
+
* should be approximately equal to the true solution */
|
|
374
|
+
tol = CG_TOL_FACTOR * MIN(tol, CG_NORM(warm_start, w->n) /
|
|
375
|
+
POWF((scs_float)iter + 1, CG_RATE));
|
|
376
|
+
tol = MAX(CG_BEST_TOL, tol);
|
|
377
|
+
#endif
|
|
378
|
+
status = SCS(solve_lin_sys)(w->p, w->u_t, warm_start, tol);
|
|
379
|
+
if (iter < FEASIBLE_ITERS) {
|
|
380
|
+
w->u_t[l - 1] = 1.;
|
|
381
|
+
} else {
|
|
382
|
+
w->u_t[l - 1] = root_plus(w, w->u_t, w->v, w->v[l - 1]);
|
|
383
|
+
}
|
|
384
|
+
SCS(add_scaled_array)(w->u_t, w->g, l - 1, -w->u_t[l - 1]);
|
|
266
385
|
return status;
|
|
267
386
|
}
|
|
268
387
|
|
|
388
|
+
/* Compute the [r;s;kappa] iterate
|
|
389
|
+
*
|
|
390
|
+
* rsk^{k+1} = R ( u^{k+1} + v^k - 2 * u_t^{k+1} )
|
|
391
|
+
*
|
|
392
|
+
* uses Moreau decomposition to get projection onto dual cone
|
|
393
|
+
* since it depends on v^k MUST be called before update_dual_vars is done
|
|
394
|
+
* (no effect of w->stgs->alpha here).
|
|
395
|
+
*/
|
|
396
|
+
static void compute_rsk(ScsWork *w) {
|
|
397
|
+
scs_int i, l = w->m + w->n + 1;
|
|
398
|
+
/* r, should = 0 so skip */
|
|
399
|
+
/*
|
|
400
|
+
for (i = 0; i < w->n; ++i) {
|
|
401
|
+
w->rsk[i] = w->stgs->rho_x * (w->v[i] + w->u[i] - 2 * w->u_t[i]);
|
|
402
|
+
}
|
|
403
|
+
*/
|
|
404
|
+
/* s */
|
|
405
|
+
for (i = w->n; i < l - 1; ++i) {
|
|
406
|
+
w->rsk[i] = (w->v[i] + w->u[i] - 2 * w->u_t[i]) * w->rho_y_vec[i - w->n];
|
|
407
|
+
}
|
|
408
|
+
/* kappa, incorporates tau scaling parameter */
|
|
409
|
+
w->rsk[l - 1] =
|
|
410
|
+
get_tau_scale(w) * (w->v[l - 1] + w->u[l - 1] - 2 * w->u_t[l - 1]);
|
|
411
|
+
}
|
|
412
|
+
|
|
269
413
|
static void update_dual_vars(ScsWork *w) {
|
|
270
|
-
scs_int i,
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
414
|
+
scs_int i, l = w->n + w->m + 1;
|
|
415
|
+
scs_float a = w->stgs->alpha;
|
|
416
|
+
/* compute and store [r;s;kappa] */
|
|
417
|
+
compute_rsk(w);
|
|
418
|
+
for (i = 0; i < l; ++i) {
|
|
419
|
+
w->v[i] += a * (w->u[i] - w->u_t[i]);
|
|
275
420
|
}
|
|
276
421
|
}
|
|
277
422
|
|
|
278
423
|
/* status < 0 indicates failure */
|
|
279
424
|
static scs_int project_cones(ScsWork *w, const ScsCone *k, scs_int iter) {
|
|
280
|
-
scs_int i, n = w->n, l = n + w->m + 1, status;
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
w->u[i] = w->u_t[i] - w->v[i];
|
|
284
|
-
}
|
|
285
|
-
for (i = n; i < l; ++i) {
|
|
286
|
-
w->u[i] = w->stgs->alpha * w->u_t[i] + (1 - w->stgs->alpha) * w->u_prev[i] -
|
|
287
|
-
w->v[i];
|
|
425
|
+
scs_int i, n = w->n, l = w->n + w->m + 1, status;
|
|
426
|
+
for (i = 0; i < l; ++i) {
|
|
427
|
+
w->u[i] = 2 * w->u_t[i] - w->v[i];
|
|
288
428
|
}
|
|
289
429
|
/* u = [x;y;tau] */
|
|
290
|
-
status =
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
430
|
+
status = SCS(proj_dual_cone)(&(w->u[n]), k, w->cone_work, w->stgs->normalize);
|
|
431
|
+
if (iter < FEASIBLE_ITERS) {
|
|
432
|
+
w->u[l - 1] = 1.0;
|
|
433
|
+
} else {
|
|
434
|
+
w->u[l - 1] = MAX(w->u[l - 1], 0.);
|
|
294
435
|
}
|
|
295
|
-
|
|
296
436
|
return status;
|
|
297
437
|
}
|
|
298
438
|
|
|
299
|
-
static
|
|
300
|
-
strcpy(info->status, "Indeterminate");
|
|
301
|
-
SCS(scale_array)(sol->x, NAN, w->n);
|
|
302
|
-
SCS(scale_array)(sol->y, NAN, w->m);
|
|
303
|
-
SCS(scale_array)(sol->s, NAN, w->m);
|
|
304
|
-
return SCS_INDETERMINATE;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
static void sety(ScsWork *w, ScsSolution *sol) {
|
|
439
|
+
static void sety(const ScsWork *w, ScsSolution *sol) {
|
|
308
440
|
if (!sol->y) {
|
|
309
|
-
sol->y = (scs_float *)
|
|
441
|
+
sol->y = (scs_float *)scs_calloc(w->m, sizeof(scs_float));
|
|
310
442
|
}
|
|
311
443
|
memcpy(sol->y, &(w->u[w->n]), w->m * sizeof(scs_float));
|
|
312
444
|
}
|
|
313
445
|
|
|
314
|
-
|
|
446
|
+
/* s is contained in rsk */
|
|
447
|
+
static void sets(const ScsWork *w, ScsSolution *sol) {
|
|
315
448
|
if (!sol->s) {
|
|
316
|
-
sol->s = (scs_float *)
|
|
449
|
+
sol->s = (scs_float *)scs_calloc(w->m, sizeof(scs_float));
|
|
317
450
|
}
|
|
318
|
-
memcpy(sol->s, &(w->
|
|
451
|
+
memcpy(sol->s, &(w->rsk[w->n]), w->m * sizeof(scs_float));
|
|
319
452
|
}
|
|
320
453
|
|
|
321
|
-
static void setx(ScsWork *w, ScsSolution *sol) {
|
|
454
|
+
static void setx(const ScsWork *w, ScsSolution *sol) {
|
|
322
455
|
if (!sol->x) {
|
|
323
|
-
sol->x = (scs_float *)
|
|
456
|
+
sol->x = (scs_float *)scs_calloc(w->n, sizeof(scs_float));
|
|
324
457
|
}
|
|
325
458
|
memcpy(sol->x, w->u, w->n * sizeof(scs_float));
|
|
326
459
|
}
|
|
327
460
|
|
|
328
|
-
static
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
461
|
+
static void set_solved(const ScsWork *w, ScsSolution *sol, ScsInfo *info) {
|
|
462
|
+
SCS(scale_array)(sol->x, SAFEDIV_POS(1.0, w->r_orig->tau), w->n);
|
|
463
|
+
SCS(scale_array)(sol->y, SAFEDIV_POS(1.0, w->r_orig->tau), w->m);
|
|
464
|
+
SCS(scale_array)(sol->s, SAFEDIV_POS(1.0, w->r_orig->tau), w->m);
|
|
465
|
+
info->gap = w->r_orig->gap;
|
|
466
|
+
info->res_pri = w->r_orig->res_pri;
|
|
467
|
+
info->res_dual = w->r_orig->res_dual;
|
|
468
|
+
info->pobj = w->r_orig->xt_p_x / 2. + w->r_orig->ctx;
|
|
469
|
+
info->dobj = -w->r_orig->xt_p_x / 2. - w->r_orig->bty;
|
|
470
|
+
strcpy(info->status, "solved");
|
|
471
|
+
info->status_val = SCS_SOLVED;
|
|
335
472
|
}
|
|
336
473
|
|
|
337
|
-
static
|
|
338
|
-
|
|
339
|
-
if (w->best_max_residual < get_max_residual(r)) {
|
|
340
|
-
r->last_iter = -1; /* Forces residual recomputation. */
|
|
341
|
-
copy_from_best_iterate(w);
|
|
342
|
-
calc_residuals(w, r, iter);
|
|
343
|
-
setx(w, sol);
|
|
344
|
-
sety(w, sol);
|
|
345
|
-
sets(w, sol);
|
|
346
|
-
}
|
|
347
|
-
SCS(scale_array)(sol->x, SAFEDIV_POS(1.0, r->tau), w->n);
|
|
348
|
-
SCS(scale_array)(sol->y, SAFEDIV_POS(1.0, r->tau), w->m);
|
|
349
|
-
SCS(scale_array)(sol->s, SAFEDIV_POS(1.0, r->tau), w->m);
|
|
350
|
-
if (info->status_val == 0) {
|
|
351
|
-
strcpy(info->status, "Solved/Inaccurate");
|
|
352
|
-
return SCS_SOLVED_INACCURATE;
|
|
353
|
-
}
|
|
354
|
-
strcpy(info->status, "Solved");
|
|
355
|
-
return SCS_SOLVED;
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
static scs_int infeasible(ScsWork *w, ScsSolution *sol, ScsInfo *info,
|
|
359
|
-
scs_float bt_y) {
|
|
360
|
-
SCS(scale_array)(sol->y, -1 / bt_y, w->m);
|
|
474
|
+
static void set_infeasible(const ScsWork *w, ScsSolution *sol, ScsInfo *info) {
|
|
475
|
+
SCS(scale_array)(sol->y, -1 / w->r_orig->bty_tau, w->m);
|
|
361
476
|
SCS(scale_array)(sol->x, NAN, w->n);
|
|
362
477
|
SCS(scale_array)(sol->s, NAN, w->m);
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
478
|
+
info->gap = NAN;
|
|
479
|
+
info->res_pri = NAN;
|
|
480
|
+
info->res_dual = NAN;
|
|
481
|
+
info->pobj = INFINITY;
|
|
482
|
+
info->dobj = INFINITY;
|
|
483
|
+
strcpy(info->status, "infeasible");
|
|
484
|
+
info->status_val = SCS_INFEASIBLE;
|
|
369
485
|
}
|
|
370
486
|
|
|
371
|
-
static
|
|
372
|
-
|
|
373
|
-
SCS(scale_array)(sol->
|
|
374
|
-
SCS(scale_array)(sol->s, -1 / ct_x, w->m);
|
|
487
|
+
static void set_unbounded(const ScsWork *w, ScsSolution *sol, ScsInfo *info) {
|
|
488
|
+
SCS(scale_array)(sol->x, -1 / w->r_orig->ctx_tau, w->n);
|
|
489
|
+
SCS(scale_array)(sol->s, -1 / w->r_orig->ctx_tau, w->m);
|
|
375
490
|
SCS(scale_array)(sol->y, NAN, w->m);
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
static scs_int is_solved_status(scs_int status) {
|
|
385
|
-
return status == SCS_SOLVED || status == SCS_SOLVED_INACCURATE;
|
|
491
|
+
info->gap = NAN;
|
|
492
|
+
info->res_pri = NAN;
|
|
493
|
+
info->res_dual = NAN;
|
|
494
|
+
info->pobj = -INFINITY;
|
|
495
|
+
info->dobj = -INFINITY;
|
|
496
|
+
strcpy(info->status, "unbounded");
|
|
497
|
+
info->status_val = SCS_UNBOUNDED;
|
|
386
498
|
}
|
|
387
499
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
if (
|
|
402
|
-
info->
|
|
403
|
-
|
|
404
|
-
info->
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
} else if (is_unbounded_status(info->status_val)) {
|
|
408
|
-
info->rel_gap = NAN;
|
|
409
|
-
info->res_pri = NAN;
|
|
410
|
-
info->res_dual = NAN;
|
|
411
|
-
info->pobj = -INFINITY;
|
|
412
|
-
info->dobj = -INFINITY;
|
|
413
|
-
} else if (is_infeasible_status(info->status_val)) {
|
|
414
|
-
info->rel_gap = NAN;
|
|
415
|
-
info->res_pri = NAN;
|
|
416
|
-
info->res_dual = NAN;
|
|
417
|
-
info->pobj = INFINITY;
|
|
418
|
-
info->dobj = INFINITY;
|
|
500
|
+
/* not yet converged, take best guess */
|
|
501
|
+
static void set_unfinished(const ScsWork *w, ScsSolution *sol, ScsInfo *info) {
|
|
502
|
+
if (w->r_orig->tau > w->r_orig->kap) {
|
|
503
|
+
set_solved(w, sol, info);
|
|
504
|
+
info->status_val = SCS_SOLVED_INACCURATE;
|
|
505
|
+
} else if (w->r_orig->bty_tau < w->r_orig->ctx_tau) {
|
|
506
|
+
set_infeasible(w, sol, info);
|
|
507
|
+
info->status_val = SCS_INFEASIBLE_INACCURATE;
|
|
508
|
+
} else {
|
|
509
|
+
set_unbounded(w, sol, info);
|
|
510
|
+
info->status_val = SCS_UNBOUNDED_INACCURATE;
|
|
511
|
+
}
|
|
512
|
+
/* Append inaccurate to the status string */
|
|
513
|
+
if (w->time_limit_reached) {
|
|
514
|
+
strcat(info->status, " (inaccurate - reached time_limit_secs)");
|
|
515
|
+
} else if (info->iter >= w->stgs->max_iters) {
|
|
516
|
+
strcat(info->status, " (inaccurate - reached max_iters)");
|
|
517
|
+
} else {
|
|
518
|
+
scs_printf("ERROR: should not be in this state (1).\n");
|
|
419
519
|
}
|
|
420
520
|
}
|
|
421
521
|
|
|
422
522
|
/* sets solutions, re-scales by inner prods if infeasible or unbounded */
|
|
423
|
-
static void
|
|
424
|
-
|
|
425
|
-
scs_int l = w->n + w->m + 1;
|
|
426
|
-
calc_residuals(w, r, iter);
|
|
523
|
+
static void finalize(ScsWork *w, ScsSolution *sol, ScsInfo *info,
|
|
524
|
+
scs_int iter) {
|
|
427
525
|
setx(w, sol);
|
|
428
526
|
sety(w, sol);
|
|
429
527
|
sets(w, sol);
|
|
430
|
-
if (info->status_val == SCS_UNFINISHED) {
|
|
431
|
-
/* not yet converged, take best guess */
|
|
432
|
-
if (r->tau > INDETERMINATE_TOL && r->tau > r->kap) {
|
|
433
|
-
info->status_val = solved(w, sol, info, r, iter);
|
|
434
|
-
} else if (SCS(norm)(w->u, l) < INDETERMINATE_TOL * SQRTF((scs_float)l)) {
|
|
435
|
-
info->status_val = indeterminate(w, sol, info);
|
|
436
|
-
} else if (r->bt_y_by_tau < r->ct_x_by_tau) {
|
|
437
|
-
info->status_val = infeasible(w, sol, info, r->bt_y_by_tau);
|
|
438
|
-
} else {
|
|
439
|
-
info->status_val = unbounded(w, sol, info, r->ct_x_by_tau);
|
|
440
|
-
}
|
|
441
|
-
} else if (is_solved_status(info->status_val)) {
|
|
442
|
-
info->status_val = solved(w, sol, info, r, iter);
|
|
443
|
-
} else if (is_infeasible_status(info->status_val)) {
|
|
444
|
-
info->status_val = infeasible(w, sol, info, r->bt_y_by_tau);
|
|
445
|
-
} else {
|
|
446
|
-
info->status_val = unbounded(w, sol, info, r->ct_x_by_tau);
|
|
447
|
-
}
|
|
448
528
|
if (w->stgs->normalize) {
|
|
449
529
|
SCS(un_normalize_sol)(w, sol);
|
|
450
530
|
}
|
|
451
|
-
|
|
531
|
+
populate_residual_struct(w, iter);
|
|
532
|
+
info->setup_time = w->setup_time;
|
|
533
|
+
info->iter = iter;
|
|
534
|
+
info->res_infeas = w->r_orig->res_infeas;
|
|
535
|
+
info->res_unbdd_a = w->r_orig->res_unbdd_a;
|
|
536
|
+
info->res_unbdd_p = w->r_orig->res_unbdd_p;
|
|
537
|
+
info->scale = w->scale;
|
|
538
|
+
info->scale_updates = w->scale_updates;
|
|
539
|
+
info->rejected_accel_steps = w->rejected_accel_steps;
|
|
540
|
+
info->accepted_accel_steps = w->accepted_accel_steps;
|
|
541
|
+
info->comp_slack = ABS(SCS(dot)(sol->s, sol->y, w->m));
|
|
542
|
+
if (info->comp_slack >
|
|
543
|
+
1e-5 * MAX(SCS(norm_inf)(sol->s, w->m), SCS(norm_inf)(sol->y, w->m))) {
|
|
544
|
+
scs_printf("WARNING - large complementary slackness residual: %f\n",
|
|
545
|
+
info->comp_slack);
|
|
546
|
+
}
|
|
547
|
+
switch (info->status_val) {
|
|
548
|
+
case SCS_SOLVED:
|
|
549
|
+
set_solved(w, sol, info);
|
|
550
|
+
break;
|
|
551
|
+
case SCS_INFEASIBLE:
|
|
552
|
+
set_infeasible(w, sol, info);
|
|
553
|
+
break;
|
|
554
|
+
case SCS_UNBOUNDED:
|
|
555
|
+
set_unbounded(w, sol, info);
|
|
556
|
+
break;
|
|
557
|
+
case SCS_UNFINISHED: /* When SCS reaches max_iters or time_limit_secs */
|
|
558
|
+
set_unfinished(w, sol, info);
|
|
559
|
+
break;
|
|
560
|
+
default:
|
|
561
|
+
scs_printf("ERROR: should not be in this state (2).\n");
|
|
562
|
+
}
|
|
452
563
|
}
|
|
453
564
|
|
|
454
|
-
static void print_summary(ScsWork *w, scs_int i,
|
|
455
|
-
|
|
565
|
+
static void print_summary(ScsWork *w, scs_int i, SCS(timer) * solve_timer) {
|
|
566
|
+
ScsResiduals *r = w->r_orig;
|
|
456
567
|
scs_printf("%*i|", (int)strlen(HEADER[0]), (int)i);
|
|
457
568
|
scs_printf("%*.2e ", (int)HSPACE, r->res_pri);
|
|
458
569
|
scs_printf("%*.2e ", (int)HSPACE, r->res_dual);
|
|
459
|
-
scs_printf("%*.2e ", (int)HSPACE, r->
|
|
460
|
-
|
|
461
|
-
scs_printf("%*.2e ", (int)HSPACE,
|
|
462
|
-
scs_printf("%*.2e ", (int)HSPACE,
|
|
570
|
+
scs_printf("%*.2e ", (int)HSPACE, r->gap);
|
|
571
|
+
/* report mid point of primal and dual objective values */
|
|
572
|
+
scs_printf("%*.2e ", (int)HSPACE, 0.5 * (r->pobj + r->dobj));
|
|
573
|
+
scs_printf("%*.2e ", (int)HSPACE, w->scale);
|
|
463
574
|
scs_printf("%*.2e ", (int)HSPACE, SCS(tocq)(solve_timer) / 1e3);
|
|
464
575
|
scs_printf("\n");
|
|
465
576
|
|
|
466
|
-
#if
|
|
467
|
-
scs_printf("Norm u = %4f, ", SCS(
|
|
468
|
-
scs_printf("Norm u_t = %4f, ", SCS(
|
|
469
|
-
scs_printf("Norm v = %4f, ", SCS(
|
|
577
|
+
#if VERBOSITY > 0
|
|
578
|
+
scs_printf("Norm u = %4f, ", SCS(norm_2)(w->u, w->n + w->m + 1));
|
|
579
|
+
scs_printf("Norm u_t = %4f, ", SCS(norm_2)(w->u_t, w->n + w->m + 1));
|
|
580
|
+
scs_printf("Norm v = %4f, ", SCS(norm_2)(w->v, w->n + w->m + 1));
|
|
581
|
+
scs_printf("Norm x = %4f, ", SCS(norm_2)(w->xys_orig->x, w->n));
|
|
582
|
+
scs_printf("Norm y = %4f, ", SCS(norm_2)(w->xys_orig->y, w->m));
|
|
583
|
+
scs_printf("Norm s = %4f, ", SCS(norm_2)(w->xys_orig->s, w->m));
|
|
584
|
+
scs_printf("Norm |Ax + s| = %1.2e, ", SCS(norm_2)(r->ax_s, w->m));
|
|
470
585
|
scs_printf("tau = %4f, ", w->u[w->n + w->m]);
|
|
471
|
-
scs_printf("kappa = %4f, ", w->
|
|
472
|
-
scs_printf("|u - u_prev| = %1.2e, ",
|
|
473
|
-
SCS(norm_diff)(w->u, w->u_prev, w->n + w->m + 1));
|
|
586
|
+
scs_printf("kappa = %4f, ", w->rsk[w->n + w->m]);
|
|
474
587
|
scs_printf("|u - u_t| = %1.2e, ",
|
|
475
588
|
SCS(norm_diff)(w->u, w->u_t, w->n + w->m + 1));
|
|
476
589
|
scs_printf("res_infeas = %1.2e, ", r->res_infeas);
|
|
477
|
-
scs_printf("
|
|
590
|
+
scs_printf("res_unbdd_a = %1.2e, ", r->res_unbdd_a);
|
|
591
|
+
scs_printf("res_unbdd_p = %1.2e, ", r->res_unbdd_p);
|
|
592
|
+
scs_printf("ctx_tau = %1.2e, ", r->ctx_tau);
|
|
593
|
+
scs_printf("bty_tau = %1.2e\n", r->bty_tau);
|
|
478
594
|
#endif
|
|
479
595
|
|
|
480
596
|
#ifdef MATLAB_MEX_FILE
|
|
@@ -484,9 +600,6 @@ static void print_summary(ScsWork *w, scs_int i, ScsResiduals *r,
|
|
|
484
600
|
|
|
485
601
|
static void print_header(ScsWork *w, const ScsCone *k) {
|
|
486
602
|
scs_int i;
|
|
487
|
-
if (w->stgs->warm_start) {
|
|
488
|
-
scs_printf("SCS using variable warm-starting\n");
|
|
489
|
-
}
|
|
490
603
|
for (i = 0; i < LINE_LEN; ++i) {
|
|
491
604
|
scs_printf("-");
|
|
492
605
|
}
|
|
@@ -504,118 +617,37 @@ static void print_header(ScsWork *w, const ScsCone *k) {
|
|
|
504
617
|
#endif
|
|
505
618
|
}
|
|
506
619
|
|
|
507
|
-
static
|
|
508
|
-
ScsConeWork *c, scs_int m) {
|
|
509
|
-
scs_float dist;
|
|
510
|
-
scs_float *t = (scs_float *)scs_malloc(sizeof(scs_float) * m);
|
|
511
|
-
memcpy(t, y, m * sizeof(scs_float));
|
|
512
|
-
SCS(proj_dual_cone)(t, k, c, SCS_NULL, -1);
|
|
513
|
-
dist = SCS(norm_inf_diff)(t, y, m);
|
|
514
|
-
#if EXTRA_VERBOSE > 0
|
|
515
|
-
SCS(print_array)(y, m, "y");
|
|
516
|
-
SCS(print_array)(t, m, "proj_y");
|
|
517
|
-
scs_printf("dist = %4f\n", dist);
|
|
518
|
-
#endif
|
|
519
|
-
scs_free(t);
|
|
520
|
-
return dist;
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
/* via moreau */
|
|
524
|
-
static scs_float get_pri_cone_dist(const scs_float *s, const ScsCone *k,
|
|
525
|
-
ScsConeWork *c, scs_int m) {
|
|
526
|
-
scs_float dist;
|
|
527
|
-
scs_float *t = (scs_float *)scs_malloc(sizeof(scs_float) * m);
|
|
528
|
-
memcpy(t, s, m * sizeof(scs_float));
|
|
529
|
-
SCS(scale_array)(t, -1.0, m);
|
|
530
|
-
SCS(proj_dual_cone)(t, k, c, SCS_NULL, -1);
|
|
531
|
-
dist = SCS(norm_inf)(t, m); /* ||s - Pi_c(s)|| = ||Pi_c*(-s)|| */
|
|
532
|
-
#if EXTRA_VERBOSE > 0
|
|
533
|
-
SCS(print_array)(s, m, "s");
|
|
534
|
-
SCS(print_array)(t, m, "(s - proj_s)");
|
|
535
|
-
scs_printf("dist = %4f\n", dist);
|
|
536
|
-
#endif
|
|
537
|
-
scs_free(t);
|
|
538
|
-
return dist;
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
static char *get_accel_summary(ScsInfo *info, scs_float total_accel_time) {
|
|
542
|
-
char *str = (char *)scs_malloc(sizeof(char) * 64);
|
|
543
|
-
sprintf(str, "\tAcceleration: avg step time: %1.2es\n",
|
|
544
|
-
total_accel_time / (info->iter + 1) / 1e3);
|
|
545
|
-
return str;
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
static void print_footer(const ScsData *d, const ScsCone *k, ScsSolution *sol,
|
|
549
|
-
ScsWork *w, ScsInfo *info,
|
|
550
|
-
scs_float total_accel_time) {
|
|
620
|
+
static void print_footer(ScsInfo *info) {
|
|
551
621
|
scs_int i;
|
|
552
|
-
|
|
553
|
-
char *cone_str = SCS(get_cone_summary)(info, w->cone_work);
|
|
554
|
-
char *accel_str = get_accel_summary(info, total_accel_time);
|
|
622
|
+
|
|
555
623
|
for (i = 0; i < LINE_LEN; ++i) {
|
|
556
624
|
scs_printf("-");
|
|
557
625
|
}
|
|
558
|
-
scs_printf("\
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
if (lin_sys_str) {
|
|
567
|
-
scs_printf("%s", lin_sys_str);
|
|
568
|
-
scs_free(lin_sys_str);
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
if (cone_str) {
|
|
572
|
-
scs_printf("%s", cone_str);
|
|
573
|
-
scs_free(cone_str);
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
if (accel_str) {
|
|
577
|
-
scs_printf("%s", accel_str);
|
|
578
|
-
scs_free(accel_str);
|
|
579
|
-
}
|
|
626
|
+
scs_printf("\n");
|
|
627
|
+
scs_printf("status: %s\n", info->status);
|
|
628
|
+
scs_printf("timings: total: %1.2es = setup: %1.2es + solve: %1.2es\n",
|
|
629
|
+
(info->setup_time + info->solve_time) / 1e3,
|
|
630
|
+
info->setup_time / 1e3, info->solve_time / 1e3);
|
|
631
|
+
scs_printf("\t lin-sys: %1.2es, cones: %1.2es, accel: %1.2es\n",
|
|
632
|
+
info->lin_sys_time / 1e3, info->cone_time / 1e3,
|
|
633
|
+
info->accel_time / 1e3);
|
|
580
634
|
|
|
581
635
|
for (i = 0; i < LINE_LEN; ++i) {
|
|
582
636
|
scs_printf("-");
|
|
583
637
|
}
|
|
584
638
|
scs_printf("\n");
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
scs_printf("
|
|
592
|
-
|
|
593
|
-
scs_printf("Certificate of dual infeasibility:\n");
|
|
594
|
-
scs_printf("dist(s, K) = %.4e\n",
|
|
595
|
-
get_pri_cone_dist(sol->s, k, w->cone_work, d->m));
|
|
596
|
-
scs_printf("|Ax + s|_2 * |c|_2 = %.4e\n", info->res_unbdd);
|
|
597
|
-
scs_printf("c'x = %.4f\n", SCS(dot)(d->c, sol->x, d->n));
|
|
598
|
-
} else {
|
|
599
|
-
scs_printf("Error metrics:\n");
|
|
600
|
-
scs_printf("dist(s, K) = %.4e, dist(y, K*) = %.4e, s'y/|s||y| = %.4e\n",
|
|
601
|
-
get_pri_cone_dist(sol->s, k, w->cone_work, d->m),
|
|
602
|
-
get_dual_cone_dist(sol->y, k, w->cone_work, d->m),
|
|
603
|
-
SCS(dot)(sol->s, sol->y, d->m) / SCS(norm)(sol->s, d->m) /
|
|
604
|
-
SCS(norm)(sol->y, d->m));
|
|
605
|
-
scs_printf("primal res: |Ax + s - b|_2 / (1 + |b|_2) = %.4e\n",
|
|
606
|
-
info->res_pri);
|
|
607
|
-
scs_printf("dual res: |A'y + c|_2 / (1 + |c|_2) = %.4e\n",
|
|
608
|
-
info->res_dual);
|
|
609
|
-
scs_printf("rel gap: |c'x + b'y| / (1 + |c'x| + |b'y|) = %.4e\n",
|
|
610
|
-
info->rel_gap);
|
|
611
|
-
for (i = 0; i < LINE_LEN; ++i) {
|
|
612
|
-
scs_printf("-");
|
|
613
|
-
}
|
|
639
|
+
/* report mid point of primal and dual objective values */
|
|
640
|
+
scs_printf("objective = %.6f", 0.5 * (info->pobj + info->dobj));
|
|
641
|
+
switch (info->status_val) {
|
|
642
|
+
case SCS_SOLVED_INACCURATE:
|
|
643
|
+
case SCS_UNBOUNDED_INACCURATE:
|
|
644
|
+
case SCS_INFEASIBLE_INACCURATE:
|
|
645
|
+
scs_printf(" (inaccurate)");
|
|
646
|
+
default:
|
|
614
647
|
scs_printf("\n");
|
|
615
|
-
scs_printf("c'x = %.4f, -b'y = %.4f\n", info->pobj, info->dobj);
|
|
616
648
|
}
|
|
617
649
|
for (i = 0; i < LINE_LEN; ++i) {
|
|
618
|
-
scs_printf("
|
|
650
|
+
scs_printf("-");
|
|
619
651
|
}
|
|
620
652
|
scs_printf("\n");
|
|
621
653
|
#ifdef MATLAB_MEX_FILE
|
|
@@ -623,35 +655,55 @@ static void print_footer(const ScsData *d, const ScsCone *k, ScsSolution *sol,
|
|
|
623
655
|
#endif
|
|
624
656
|
}
|
|
625
657
|
|
|
626
|
-
static scs_int has_converged(ScsWork *w,
|
|
627
|
-
scs_float
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
658
|
+
static scs_int has_converged(ScsWork *w, scs_int iter) {
|
|
659
|
+
scs_float eps_abs = w->stgs->eps_abs;
|
|
660
|
+
scs_float eps_rel = w->stgs->eps_rel;
|
|
661
|
+
scs_float eps_infeas = w->stgs->eps_infeas;
|
|
662
|
+
scs_float grl, prl, drl;
|
|
663
|
+
|
|
664
|
+
ScsResiduals *r = w->r_orig;
|
|
665
|
+
scs_float *b = w->b_orig;
|
|
666
|
+
scs_float *c = w->c_orig;
|
|
667
|
+
scs_float *s = w->xys_orig->s;
|
|
668
|
+
|
|
669
|
+
if (r->tau > 0.) {
|
|
670
|
+
/* xt_p_x, ctx, bty already have tau divided out */
|
|
671
|
+
grl = MAX(MAX(ABS(r->xt_p_x), ABS(r->ctx)), ABS(r->bty));
|
|
672
|
+
/* s, ax, px, aty do *not* have tau divided out, so need to divide */
|
|
673
|
+
prl = MAX(MAX(NORM(b, w->m) * r->tau, NORM(s, w->m)), NORM(r->ax, w->m)) /
|
|
674
|
+
r->tau;
|
|
675
|
+
drl = MAX(MAX(NORM(c, w->n) * r->tau, NORM(r->px, w->n)),
|
|
676
|
+
NORM(r->aty, w->n)) /
|
|
677
|
+
r->tau;
|
|
678
|
+
if (isless(r->res_pri, eps_abs + eps_rel * prl) &&
|
|
679
|
+
isless(r->res_dual, eps_abs + eps_rel * drl) &&
|
|
680
|
+
isless(r->gap, eps_abs + eps_rel * grl)) {
|
|
681
|
+
return SCS_SOLVED;
|
|
682
|
+
}
|
|
631
683
|
}
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
if (isless(r->res_unbdd, eps) && iter > 0) {
|
|
684
|
+
if (isless(r->res_unbdd_a, eps_infeas) &&
|
|
685
|
+
isless(r->res_unbdd_p, eps_infeas)) {
|
|
635
686
|
return SCS_UNBOUNDED;
|
|
636
687
|
}
|
|
637
|
-
if (isless(r->res_infeas,
|
|
688
|
+
if (isless(r->res_infeas, eps_infeas)) {
|
|
638
689
|
return SCS_INFEASIBLE;
|
|
639
690
|
}
|
|
640
691
|
return 0;
|
|
641
692
|
}
|
|
642
693
|
|
|
643
|
-
|
|
644
|
-
|
|
694
|
+
#if NOVALIDATE == 0
|
|
695
|
+
static scs_int validate(const ScsData *d, const ScsCone *k,
|
|
696
|
+
const ScsSettings *stgs) {
|
|
645
697
|
if (d->m <= 0 || d->n <= 0) {
|
|
646
698
|
scs_printf("m and n must both be greater than 0; m = %li, n = %li\n",
|
|
647
699
|
(long)d->m, (long)d->n);
|
|
648
700
|
return -1;
|
|
649
701
|
}
|
|
650
702
|
if (d->m < d->n) {
|
|
651
|
-
scs_printf("WARN: m less than n, problem likely degenerate\n");
|
|
703
|
+
/* scs_printf("WARN: m less than n, problem likely degenerate\n"); */
|
|
652
704
|
/* return -1; */
|
|
653
705
|
}
|
|
654
|
-
if (SCS(validate_lin_sys)(d->A) < 0) {
|
|
706
|
+
if (SCS(validate_lin_sys)(d->A, d->P) < 0) {
|
|
655
707
|
scs_printf("invalid linear system input data\n");
|
|
656
708
|
return -1;
|
|
657
709
|
}
|
|
@@ -663,8 +715,16 @@ static scs_int validate(const ScsData *d, const ScsCone *k) {
|
|
|
663
715
|
scs_printf("max_iters must be positive\n");
|
|
664
716
|
return -1;
|
|
665
717
|
}
|
|
666
|
-
if (stgs->
|
|
667
|
-
scs_printf("
|
|
718
|
+
if (stgs->eps_abs < 0) {
|
|
719
|
+
scs_printf("eps_abs tolerance must be positive\n");
|
|
720
|
+
return -1;
|
|
721
|
+
}
|
|
722
|
+
if (stgs->eps_rel < 0) {
|
|
723
|
+
scs_printf("eps_rel tolerance must be positive\n");
|
|
724
|
+
return -1;
|
|
725
|
+
}
|
|
726
|
+
if (stgs->eps_infeas < 0) {
|
|
727
|
+
scs_printf("eps_infeas tolerance must be positive\n");
|
|
668
728
|
return -1;
|
|
669
729
|
}
|
|
670
730
|
if (stgs->alpha <= 0 || stgs->alpha >= 2) {
|
|
@@ -681,224 +741,374 @@ static scs_int validate(const ScsData *d, const ScsCone *k) {
|
|
|
681
741
|
}
|
|
682
742
|
return 0;
|
|
683
743
|
}
|
|
744
|
+
#endif
|
|
745
|
+
|
|
746
|
+
static ScsResiduals *init_residuals(const ScsData *d) {
|
|
747
|
+
ScsResiduals *r = (ScsResiduals *)scs_calloc(1, sizeof(ScsResiduals));
|
|
748
|
+
r->last_iter = -1;
|
|
749
|
+
r->ax = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
|
|
750
|
+
r->ax_s = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
|
|
751
|
+
r->ax_s_btau = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
|
|
752
|
+
r->px = (scs_float *)scs_calloc(d->n, sizeof(scs_float));
|
|
753
|
+
r->aty = (scs_float *)scs_calloc(d->n, sizeof(scs_float));
|
|
754
|
+
r->px_aty_ctau = (scs_float *)scs_calloc(d->n, sizeof(scs_float));
|
|
755
|
+
return r;
|
|
756
|
+
}
|
|
684
757
|
|
|
685
|
-
static ScsWork *init_work(const ScsData *d, const ScsCone *k
|
|
758
|
+
static ScsWork *init_work(const ScsData *d, const ScsCone *k,
|
|
759
|
+
const ScsSettings *stgs) {
|
|
686
760
|
ScsWork *w = (ScsWork *)scs_calloc(1, sizeof(ScsWork));
|
|
687
761
|
scs_int l = d->n + d->m + 1;
|
|
688
|
-
if (
|
|
689
|
-
print_init_header(d, k);
|
|
762
|
+
if (stgs->verbose) {
|
|
763
|
+
print_init_header(d, k, stgs);
|
|
690
764
|
}
|
|
691
765
|
if (!w) {
|
|
692
766
|
scs_printf("ERROR: allocating work failure\n");
|
|
693
767
|
return SCS_NULL;
|
|
694
768
|
}
|
|
695
769
|
/* get settings and dims from data struct */
|
|
696
|
-
w->
|
|
770
|
+
w->d = d;
|
|
771
|
+
w->k = k;
|
|
772
|
+
w->stgs = stgs;
|
|
773
|
+
w->scale = stgs->scale; /* initial scale, may be updated */
|
|
697
774
|
w->m = d->m;
|
|
698
775
|
w->n = d->n;
|
|
699
|
-
w->
|
|
776
|
+
w->last_scale_update_iter = 0;
|
|
777
|
+
w->sum_log_scale_factor = 0.;
|
|
778
|
+
w->n_log_scale_factor = 0;
|
|
779
|
+
w->scale_updates = 0;
|
|
780
|
+
w->time_limit_reached = 0;
|
|
700
781
|
/* allocate workspace: */
|
|
701
|
-
|
|
702
|
-
w->
|
|
703
|
-
w->
|
|
704
|
-
w->
|
|
705
|
-
w->
|
|
706
|
-
w->h = (scs_float *)
|
|
707
|
-
w->g = (scs_float *)
|
|
708
|
-
w->
|
|
709
|
-
w->
|
|
710
|
-
|
|
711
|
-
w->
|
|
712
|
-
|
|
713
|
-
|
|
782
|
+
w->u = (scs_float *)scs_calloc(l, sizeof(scs_float));
|
|
783
|
+
w->u_t = (scs_float *)scs_calloc(l, sizeof(scs_float));
|
|
784
|
+
w->v = (scs_float *)scs_calloc(l, sizeof(scs_float));
|
|
785
|
+
w->v_prev = (scs_float *)scs_calloc(l, sizeof(scs_float));
|
|
786
|
+
w->rsk = (scs_float *)scs_calloc(l, sizeof(scs_float));
|
|
787
|
+
w->h = (scs_float *)scs_calloc((l - 1), sizeof(scs_float));
|
|
788
|
+
w->g = (scs_float *)scs_calloc((l - 1), sizeof(scs_float));
|
|
789
|
+
w->lin_sys_warm_start = (scs_float *)scs_calloc((l - 1), sizeof(scs_float));
|
|
790
|
+
w->rho_y_vec = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
|
|
791
|
+
/* x,y,s struct */
|
|
792
|
+
w->xys_orig = (ScsSolution *)scs_calloc(1, sizeof(ScsSolution));
|
|
793
|
+
w->xys_orig->x = (scs_float *)scs_calloc(d->n, sizeof(scs_float));
|
|
794
|
+
w->xys_orig->s = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
|
|
795
|
+
w->xys_orig->y = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
|
|
796
|
+
w->r_orig = init_residuals(d);
|
|
797
|
+
|
|
798
|
+
w->A = d->A;
|
|
799
|
+
w->P = d->P;
|
|
800
|
+
|
|
801
|
+
w->b_orig = d->b;
|
|
802
|
+
w->c_orig = d->c;
|
|
803
|
+
w->b_normalized = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
|
|
804
|
+
w->c_normalized = (scs_float *)scs_calloc(d->n, sizeof(scs_float));
|
|
805
|
+
memcpy(w->b_normalized, w->b_orig, w->m * sizeof(scs_float));
|
|
806
|
+
memcpy(w->c_normalized, w->c_orig, w->n * sizeof(scs_float));
|
|
807
|
+
SCS(set_rho_y_vec)(k, w->scale, w->rho_y_vec, w->m);
|
|
808
|
+
|
|
809
|
+
if (!w->c_normalized) {
|
|
714
810
|
scs_printf("ERROR: work memory allocation failure\n");
|
|
715
811
|
return SCS_NULL;
|
|
716
812
|
}
|
|
717
|
-
|
|
718
|
-
w->v = &(w->u[l]);
|
|
719
|
-
w->v_best = &(w->u_best[l]);
|
|
720
|
-
w->v_prev = &(w->u_prev[l]);
|
|
721
|
-
w->A = d->A;
|
|
813
|
+
|
|
722
814
|
if (w->stgs->normalize) {
|
|
815
|
+
w->xys_normalized = (ScsSolution *)scs_calloc(1, sizeof(ScsSolution));
|
|
816
|
+
w->xys_normalized->x = (scs_float *)scs_calloc(d->n, sizeof(scs_float));
|
|
817
|
+
w->xys_normalized->s = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
|
|
818
|
+
w->xys_normalized->y = (scs_float *)scs_calloc(d->m, sizeof(scs_float));
|
|
819
|
+
w->r_normalized = init_residuals(d);
|
|
820
|
+
|
|
723
821
|
#ifdef COPYAMATRIX
|
|
724
|
-
if (!SCS(
|
|
822
|
+
if (!SCS(copy_matrix)(&(w->A), d->A)) {
|
|
725
823
|
scs_printf("ERROR: copy A matrix failed\n");
|
|
726
824
|
return SCS_NULL;
|
|
727
825
|
}
|
|
826
|
+
if (w->P && !SCS(copy_matrix)(&(w->P), d->P)) {
|
|
827
|
+
scs_printf("ERROR: copy P matrix failed\n");
|
|
828
|
+
return SCS_NULL;
|
|
829
|
+
}
|
|
728
830
|
#endif
|
|
729
|
-
|
|
730
|
-
SCS(
|
|
731
|
-
|
|
732
|
-
SCS(
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
scs_printf("SCS(norm) E = %4f\n", SCS(norm)(w->scal->E, d->n));
|
|
736
|
-
#endif
|
|
831
|
+
/* this allocates memory that must be freed */
|
|
832
|
+
w->cone_boundaries_len = SCS(set_cone_boundaries)(k, &w->cone_boundaries);
|
|
833
|
+
w->scal = (ScsScaling *)scs_calloc(1, sizeof(ScsScaling));
|
|
834
|
+
SCS(normalize)
|
|
835
|
+
(w->P, w->A, w->b_normalized, w->c_normalized, w->scal, w->cone_boundaries,
|
|
836
|
+
w->cone_boundaries_len);
|
|
737
837
|
} else {
|
|
838
|
+
w->xys_normalized = w->xys_orig;
|
|
839
|
+
w->r_normalized = w->r_orig;
|
|
840
|
+
w->cone_boundaries_len = 0;
|
|
841
|
+
w->cone_boundaries = SCS_NULL;
|
|
738
842
|
w->scal = SCS_NULL;
|
|
739
843
|
}
|
|
740
|
-
if (!(w->cone_work = SCS(init_cone)(k))) {
|
|
844
|
+
if (!(w->cone_work = SCS(init_cone)(k, w->scal, w->m))) {
|
|
741
845
|
scs_printf("ERROR: init_cone failure\n");
|
|
742
846
|
return SCS_NULL;
|
|
743
847
|
}
|
|
744
|
-
if (!(w->p =
|
|
848
|
+
if (!(w->p =
|
|
849
|
+
SCS(init_lin_sys_work)(w->A, w->P, w->rho_y_vec, w->stgs->rho_x))) {
|
|
745
850
|
scs_printf("ERROR: init_lin_sys_work failure\n");
|
|
746
851
|
return SCS_NULL;
|
|
747
852
|
}
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
853
|
+
/* Acceleration */
|
|
854
|
+
w->rejected_accel_steps = 0;
|
|
855
|
+
w->accepted_accel_steps = 0;
|
|
856
|
+
if (w->stgs->acceleration_lookback) {
|
|
857
|
+
/* TODO(HACK!) negative acceleration_lookback interpreted as type-II */
|
|
858
|
+
if (!(w->accel = aa_init(l, ABS(w->stgs->acceleration_lookback),
|
|
859
|
+
w->stgs->acceleration_lookback > 0,
|
|
860
|
+
w->stgs->acceleration_lookback > 0
|
|
861
|
+
? AA_REGULARIZATION_TYPE_1
|
|
862
|
+
: AA_REGULARIZATION_TYPE_2,
|
|
863
|
+
AA_RELAXATION, AA_SAFEGUARD_FACTOR,
|
|
864
|
+
AA_MAX_WEIGHT_NORM, VERBOSITY))) {
|
|
865
|
+
if (w->stgs->verbose) {
|
|
866
|
+
scs_printf("WARN: aa_init returned NULL, no acceleration applied.\n");
|
|
867
|
+
}
|
|
753
868
|
}
|
|
869
|
+
} else {
|
|
870
|
+
w->accel = SCS_NULL;
|
|
754
871
|
}
|
|
755
872
|
return w;
|
|
756
873
|
}
|
|
757
874
|
|
|
758
|
-
static
|
|
759
|
-
|
|
875
|
+
static void update_work_cache(ScsWork *w) {
|
|
876
|
+
/* g = (I + M)^{-1} h */
|
|
877
|
+
memcpy(w->g, w->h, (w->n + w->m) * sizeof(scs_float));
|
|
878
|
+
SCS(scale_array)(&(w->g[w->n]), -1., w->m);
|
|
879
|
+
SCS(solve_lin_sys)(w->p, w->g, SCS_NULL, CG_BEST_TOL);
|
|
880
|
+
return;
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
static scs_int update_work(const ScsData *d, ScsWork *w, ScsSolution *sol) {
|
|
760
884
|
/* before normalization */
|
|
761
885
|
scs_int n = d->n;
|
|
762
886
|
scs_int m = d->m;
|
|
763
|
-
|
|
764
|
-
w->nm_b = SCS(norm)(d->b, m);
|
|
765
|
-
w->nm_c = SCS(norm)(d->c, n);
|
|
766
|
-
memcpy(w->b, d->b, d->m * sizeof(scs_float));
|
|
767
|
-
memcpy(w->c, d->c, d->n * sizeof(scs_float));
|
|
768
|
-
|
|
769
|
-
#if EXTRA_VERBOSE > 0
|
|
770
|
-
SCS(print_array)(w->b, m, "b");
|
|
771
|
-
scs_printf("pre-normalized norm b = %4f\n", SCS(norm)(w->b, m));
|
|
772
|
-
SCS(print_array)(w->c, n, "c");
|
|
773
|
-
scs_printf("pre-normalized norm c = %4f\n", SCS(norm)(w->c, n));
|
|
774
|
-
#endif
|
|
775
|
-
if (w->stgs->normalize) {
|
|
776
|
-
SCS(normalize_b_c)(w);
|
|
777
|
-
#if EXTRA_VERBOSE > 0
|
|
778
|
-
SCS(print_array)(w->b, m, "bn");
|
|
779
|
-
scs_printf("sc_b = %4f\n", w->sc_b);
|
|
780
|
-
scs_printf("post-normalized norm b = %4f\n", SCS(norm)(w->b, m));
|
|
781
|
-
SCS(print_array)(w->c, n, "cn");
|
|
782
|
-
scs_printf("sc_c = %4f\n", w->sc_c);
|
|
783
|
-
scs_printf("post-normalized norm c = %4f\n", SCS(norm)(w->c, n));
|
|
784
|
-
#endif
|
|
785
|
-
}
|
|
786
887
|
if (w->stgs->warm_start) {
|
|
787
888
|
warm_start_vars(w, sol);
|
|
788
889
|
} else {
|
|
789
890
|
cold_start_vars(w);
|
|
790
891
|
}
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
memcpy(w->
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
w->g_th = SCS(dot)(w->h, w->g, n + m);
|
|
892
|
+
|
|
893
|
+
/* h = [c;b] */
|
|
894
|
+
memcpy(w->h, w->c_normalized, n * sizeof(scs_float));
|
|
895
|
+
memcpy(&(w->h[n]), w->b_normalized, m * sizeof(scs_float));
|
|
896
|
+
update_work_cache(w);
|
|
797
897
|
return 0;
|
|
798
898
|
}
|
|
799
899
|
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
scs_float v_norm_difference = SCS(norm_diff)(w->v, w->v_prev, l);
|
|
804
|
-
scs_float norm = SQRTF(SCS(norm_sq)(w->u, l) + SCS(norm_sq)(w->v, l));
|
|
805
|
-
scs_float norm_diff = SQRTF(u_norm_difference * u_norm_difference +
|
|
806
|
-
v_norm_difference * v_norm_difference);
|
|
807
|
-
return norm_diff / norm;
|
|
900
|
+
/* will update if the factor is outside of range */
|
|
901
|
+
scs_int should_update_rho_y_vec(scs_float factor, scs_int iter) {
|
|
902
|
+
return (factor > SQRTF(10.) || factor < 1. / SQRTF(10.));
|
|
808
903
|
}
|
|
809
904
|
|
|
810
|
-
static void
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
905
|
+
static void maybe_update_scale(ScsWork *w, const ScsCone *k, scs_int iter) {
|
|
906
|
+
scs_int i;
|
|
907
|
+
scs_float factor, new_scale;
|
|
908
|
+
|
|
909
|
+
ScsResiduals *r = w->r_orig;
|
|
910
|
+
ScsSolution *xys = w->xys_orig;
|
|
911
|
+
scs_float *b = w->b_orig;
|
|
912
|
+
scs_float *c = w->c_orig;
|
|
913
|
+
|
|
914
|
+
scs_int iters_since_last_update = iter - w->last_scale_update_iter;
|
|
915
|
+
/* ||Ax + s - b * tau|| */
|
|
916
|
+
scs_float relative_res_pri =
|
|
917
|
+
SAFEDIV_POS(SCALE_NORM(r->ax_s_btau, w->m),
|
|
918
|
+
MAX(MAX(SCALE_NORM(r->ax, w->m), SCALE_NORM(xys->s, w->m)),
|
|
919
|
+
SCALE_NORM(b, w->m) * r->tau));
|
|
920
|
+
/* ||Px + A'y + c * tau|| */
|
|
921
|
+
scs_float relative_res_dual =
|
|
922
|
+
SAFEDIV_POS(SCALE_NORM(r->px_aty_ctau, w->n),
|
|
923
|
+
MAX(MAX(SCALE_NORM(r->px, w->n), SCALE_NORM(r->aty, w->n)),
|
|
924
|
+
SCALE_NORM(c, w->n) * r->tau));
|
|
925
|
+
|
|
926
|
+
/* higher scale makes res_pri go down faster, so increase if res_pri larger */
|
|
927
|
+
w->sum_log_scale_factor += log(relative_res_pri) - log(relative_res_dual);
|
|
928
|
+
w->n_log_scale_factor++;
|
|
929
|
+
|
|
930
|
+
/* geometric mean */
|
|
931
|
+
factor =
|
|
932
|
+
SQRTF(exp(w->sum_log_scale_factor / (scs_float)(w->n_log_scale_factor)));
|
|
933
|
+
|
|
934
|
+
/* need at least RESCALING_MIN_ITERS since last update */
|
|
935
|
+
if (iters_since_last_update < RESCALING_MIN_ITERS) {
|
|
936
|
+
return;
|
|
937
|
+
}
|
|
938
|
+
new_scale = MIN(MAX(w->scale * factor, MIN_SCALE_VALUE), MAX_SCALE_VALUE);
|
|
939
|
+
if (new_scale == w->scale) {
|
|
940
|
+
return;
|
|
816
941
|
}
|
|
942
|
+
if (should_update_rho_y_vec(factor, iters_since_last_update)) {
|
|
943
|
+
w->scale_updates++;
|
|
944
|
+
w->sum_log_scale_factor = 0;
|
|
945
|
+
w->n_log_scale_factor = 0;
|
|
946
|
+
w->last_scale_update_iter = iter;
|
|
947
|
+
w->scale = new_scale;
|
|
948
|
+
SCS(set_rho_y_vec)(k, w->scale, w->rho_y_vec, w->m);
|
|
949
|
+
SCS(update_lin_sys_rho_y_vec)(w->p, w->rho_y_vec);
|
|
950
|
+
|
|
951
|
+
/* update pre-solved quantities */
|
|
952
|
+
update_work_cache(w);
|
|
953
|
+
|
|
954
|
+
/* reset acceleration so that old iterates aren't affecting new values */
|
|
955
|
+
if (w->accel) {
|
|
956
|
+
aa_reset(w->accel);
|
|
957
|
+
}
|
|
958
|
+
/* update v, using fact that rsk, u, u_t vectors should be the same */
|
|
959
|
+
/* solve: R (v^+ + u - 2u_t) = rsk => v^+ = R^-1 rsk + 2u_t - u */
|
|
960
|
+
/* only elements with scale on diag */
|
|
961
|
+
for (i = w->n; i < w->n + w->m; i++) {
|
|
962
|
+
w->v[i] = w->rsk[i] / w->rho_y_vec[i - w->n] + 2 * w->u_t[i] - w->u[i];
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
/* scs is homogeneous so scale the iterate to keep norm reasonable */
|
|
968
|
+
static inline void normalize_v(scs_float *v, scs_int len) {
|
|
969
|
+
scs_float v_norm = SCS(norm_2)(v, len); /* always l2 norm */
|
|
970
|
+
SCS(scale_array)(v, SQRTF((scs_float)len) * ITERATE_NORM / v_norm, len);
|
|
817
971
|
}
|
|
818
972
|
|
|
819
|
-
scs_int SCS(solve)(ScsWork *w,
|
|
820
|
-
ScsSolution *sol, ScsInfo *info) {
|
|
973
|
+
scs_int SCS(solve)(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
|
|
821
974
|
scs_int i;
|
|
822
|
-
SCS(timer) solve_timer, accel_timer;
|
|
823
|
-
scs_float total_accel_time = 0.0,
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
scs_printf("ERROR: SCS_NULL input\n");
|
|
975
|
+
SCS(timer) solve_timer, lin_sys_timer, cone_timer, accel_timer;
|
|
976
|
+
scs_float total_accel_time = 0.0, total_cone_time = 0.0,
|
|
977
|
+
total_lin_sys_time = 0.0;
|
|
978
|
+
if (!sol || !w || !info) {
|
|
979
|
+
scs_printf("ERROR: missing ScsWork, ScsSolution or ScsInfo input\n");
|
|
828
980
|
return SCS_FAILED;
|
|
829
981
|
}
|
|
982
|
+
scs_int l = w->m + w->n + 1;
|
|
983
|
+
const ScsData *d = w->d;
|
|
984
|
+
const ScsCone *k = w->k;
|
|
985
|
+
const ScsSettings *stgs = w->stgs;
|
|
830
986
|
/* initialize ctrl-c support */
|
|
831
987
|
scs_start_interrupt_listener();
|
|
832
988
|
SCS(tic)(&solve_timer);
|
|
833
989
|
info->status_val = SCS_UNFINISHED; /* not yet converged */
|
|
834
|
-
r.last_iter = -1;
|
|
835
990
|
update_work(d, w, sol);
|
|
836
991
|
|
|
837
992
|
if (w->stgs->verbose) {
|
|
838
993
|
print_header(w, k);
|
|
839
994
|
}
|
|
840
|
-
|
|
995
|
+
|
|
996
|
+
/* SCS */
|
|
841
997
|
for (i = 0; i < w->stgs->max_iters; ++i) {
|
|
842
|
-
/*
|
|
998
|
+
/* Accelerate here so that last step always projection onto cone */
|
|
843
999
|
/* this ensures the returned iterates always satisfy conic constraints */
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
1000
|
+
if (w->accel) {
|
|
1001
|
+
SCS(tic)(&accel_timer);
|
|
1002
|
+
if (i > 0 && i % w->stgs->acceleration_interval == 0) {
|
|
1003
|
+
/* v overwritten with AA output here */
|
|
1004
|
+
w->aa_norm = aa_apply(w->v, w->v_prev, w->accel);
|
|
1005
|
+
}
|
|
1006
|
+
total_accel_time += SCS(tocq)(&accel_timer);
|
|
851
1007
|
}
|
|
852
|
-
total_accel_time += SCS(tocq)(&accel_timer);
|
|
853
1008
|
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
1009
|
+
if (i >= FEASIBLE_ITERS) {
|
|
1010
|
+
/* normalize v *after* applying any acceleration */
|
|
1011
|
+
/* the input to the DR step should be normalized */
|
|
1012
|
+
normalize_v(w->v, l);
|
|
1013
|
+
}
|
|
858
1014
|
|
|
859
|
-
|
|
1015
|
+
/* store v_prev = v, *after* normalizing */
|
|
860
1016
|
memcpy(w->v_prev, w->v, l * sizeof(scs_float));
|
|
861
1017
|
|
|
1018
|
+
/* linear system solve */
|
|
1019
|
+
SCS(tic)(&lin_sys_timer);
|
|
862
1020
|
if (project_lin_sys(w, i) < 0) {
|
|
863
1021
|
return failure(w, w->m, w->n, sol, info, SCS_FAILED,
|
|
864
|
-
"error in project_lin_sys", "
|
|
1022
|
+
"error in project_lin_sys", "failure");
|
|
865
1023
|
}
|
|
1024
|
+
total_lin_sys_time += SCS(tocq)(&lin_sys_timer);
|
|
1025
|
+
|
|
1026
|
+
/* project onto the cones */
|
|
1027
|
+
SCS(tic)(&cone_timer);
|
|
866
1028
|
if (project_cones(w, k, i) < 0) {
|
|
867
1029
|
return failure(w, w->m, w->n, sol, info, SCS_FAILED,
|
|
868
|
-
"error in project_cones", "
|
|
1030
|
+
"error in project_cones", "failure");
|
|
869
1031
|
}
|
|
1032
|
+
total_cone_time += SCS(tocq)(&cone_timer);
|
|
870
1033
|
|
|
1034
|
+
/* dual variable step */
|
|
871
1035
|
update_dual_vars(w);
|
|
872
1036
|
|
|
873
|
-
if (
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
if ((info->status_val = has_converged(w,
|
|
1037
|
+
if (i % CONVERGED_INTERVAL == 0) {
|
|
1038
|
+
if (scs_is_interrupted()) {
|
|
1039
|
+
return failure(w, w->m, w->n, sol, info, SCS_SIGINT, "interrupted",
|
|
1040
|
+
"interrupted");
|
|
1041
|
+
}
|
|
1042
|
+
populate_residual_struct(w, i);
|
|
1043
|
+
if ((info->status_val = has_converged(w, i)) != 0) {
|
|
880
1044
|
break;
|
|
881
1045
|
}
|
|
882
|
-
|
|
1046
|
+
if (w->stgs->time_limit_secs) {
|
|
1047
|
+
if (SCS(tocq)(&solve_timer) > 1000. * w->stgs->time_limit_secs) {
|
|
1048
|
+
w->time_limit_reached = 1;
|
|
1049
|
+
break;
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
883
1052
|
}
|
|
884
1053
|
|
|
1054
|
+
/* AA safeguard check.
|
|
1055
|
+
* Perform safeguarding *after* convergence check to prevent safeguard
|
|
1056
|
+
* overwriting converged iterate, since safeguard is on `v` and convergence
|
|
1057
|
+
* is on `u`.
|
|
1058
|
+
*/
|
|
1059
|
+
if (w->accel && i % w->stgs->acceleration_interval == 0 && w->aa_norm > 0) {
|
|
1060
|
+
if (aa_safeguard(w->v, w->v_prev, w->accel) < 0) {
|
|
1061
|
+
/* TODO should we copy u from u_prev here too? Then move above, possibly
|
|
1062
|
+
* better residual calculation and scale updating. */
|
|
1063
|
+
w->rejected_accel_steps++;
|
|
1064
|
+
} else {
|
|
1065
|
+
w->accepted_accel_steps++;
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
/* Compute residuals. */
|
|
885
1070
|
if (w->stgs->verbose && i % PRINT_INTERVAL == 0) {
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
1071
|
+
populate_residual_struct(w, i);
|
|
1072
|
+
print_summary(w, i, &solve_timer);
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
/* If residuals are fresh then maybe compute new scale. */
|
|
1076
|
+
if (w->stgs->adaptive_scale && i == w->r_orig->last_iter) {
|
|
1077
|
+
maybe_update_scale(w, k, i);
|
|
889
1078
|
}
|
|
1079
|
+
|
|
1080
|
+
/* Log *after* updating scale so residual recalc does not affect alg */
|
|
1081
|
+
if (w->stgs->log_csv_filename) {
|
|
1082
|
+
/* calc residuals every iter if logging to csv */
|
|
1083
|
+
populate_residual_struct(w, i);
|
|
1084
|
+
SCS(log_data_to_csv)(d, k, stgs, w, i, &solve_timer);
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
/* Final logging after full run */
|
|
1089
|
+
if (w->stgs->log_csv_filename) {
|
|
1090
|
+
populate_residual_struct(w, i);
|
|
1091
|
+
SCS(log_data_to_csv)(d, k, stgs, w, i, &solve_timer);
|
|
890
1092
|
}
|
|
1093
|
+
|
|
891
1094
|
if (w->stgs->verbose) {
|
|
892
|
-
|
|
893
|
-
print_summary(w, i, &
|
|
1095
|
+
populate_residual_struct(w, i);
|
|
1096
|
+
print_summary(w, i, &solve_timer);
|
|
894
1097
|
}
|
|
1098
|
+
|
|
895
1099
|
/* populate solution vectors (unnormalized) and info */
|
|
896
|
-
|
|
1100
|
+
finalize(w, sol, info, i);
|
|
1101
|
+
|
|
1102
|
+
/* populate timings */
|
|
897
1103
|
info->solve_time = SCS(tocq)(&solve_timer);
|
|
1104
|
+
info->lin_sys_time = total_lin_sys_time;
|
|
1105
|
+
info->cone_time = total_cone_time;
|
|
1106
|
+
info->accel_time = total_accel_time;
|
|
898
1107
|
|
|
899
1108
|
if (w->stgs->verbose) {
|
|
900
|
-
print_footer(
|
|
1109
|
+
print_footer(info);
|
|
901
1110
|
}
|
|
1111
|
+
|
|
902
1112
|
scs_end_interrupt_listener();
|
|
903
1113
|
return info->status_val;
|
|
904
1114
|
}
|
|
@@ -908,9 +1118,10 @@ void SCS(finish)(ScsWork *w) {
|
|
|
908
1118
|
SCS(finish_cone)(w->cone_work);
|
|
909
1119
|
if (w->stgs && w->stgs->normalize) {
|
|
910
1120
|
#ifndef COPYAMATRIX
|
|
911
|
-
SCS(
|
|
1121
|
+
SCS(un_normalize)(w->A, w->P, w->scal);
|
|
912
1122
|
#else
|
|
913
|
-
SCS(
|
|
1123
|
+
SCS(free_scs_matrix)(w->A);
|
|
1124
|
+
SCS(free_scs_matrix)(w->P);
|
|
914
1125
|
#endif
|
|
915
1126
|
}
|
|
916
1127
|
if (w->p) {
|
|
@@ -923,55 +1134,48 @@ void SCS(finish)(ScsWork *w) {
|
|
|
923
1134
|
}
|
|
924
1135
|
}
|
|
925
1136
|
|
|
926
|
-
ScsWork *SCS(init)(const ScsData *d, const ScsCone *k,
|
|
927
|
-
|
|
928
|
-
SCS(tic)(&global_timer);
|
|
929
|
-
#endif
|
|
1137
|
+
ScsWork *SCS(init)(const ScsData *d, const ScsCone *k,
|
|
1138
|
+
const ScsSettings *stgs) {
|
|
930
1139
|
ScsWork *w;
|
|
931
1140
|
SCS(timer) init_timer;
|
|
932
1141
|
scs_start_interrupt_listener();
|
|
933
|
-
if (!d || !k
|
|
934
|
-
scs_printf("ERROR: Missing ScsData
|
|
1142
|
+
if (!d || !k) {
|
|
1143
|
+
scs_printf("ERROR: Missing ScsData or ScsCone input\n");
|
|
935
1144
|
return SCS_NULL;
|
|
936
1145
|
}
|
|
937
|
-
#if
|
|
938
|
-
|
|
939
|
-
SCS(print_cone_data)(k);
|
|
940
|
-
#endif
|
|
941
|
-
#ifndef NOVALIDATE
|
|
942
|
-
if (validate(d, k) < 0) {
|
|
1146
|
+
#if NOVALIDATE == 0
|
|
1147
|
+
if (validate(d, k, stgs) < 0) {
|
|
943
1148
|
scs_printf("ERROR: Validation returned failure\n");
|
|
944
1149
|
return SCS_NULL;
|
|
945
1150
|
}
|
|
946
1151
|
#endif
|
|
947
1152
|
SCS(tic)(&init_timer);
|
|
948
|
-
if (
|
|
949
|
-
SCS(write_data)(d, k);
|
|
1153
|
+
if (stgs->write_data_filename) {
|
|
1154
|
+
SCS(write_data)(d, k, stgs);
|
|
950
1155
|
}
|
|
951
|
-
w = init_work(d, k);
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
scs_printf("Setup time: %1.2es\n", info->setup_time / 1e3);
|
|
1156
|
+
w = init_work(d, k, stgs);
|
|
1157
|
+
if (w) {
|
|
1158
|
+
w->setup_time = SCS(tocq)(&init_timer);
|
|
955
1159
|
}
|
|
956
1160
|
scs_end_interrupt_listener();
|
|
957
1161
|
return w;
|
|
958
1162
|
}
|
|
959
1163
|
|
|
960
1164
|
/* this just calls SCS(init), SCS(solve), and SCS(finish) */
|
|
961
|
-
scs_int scs(const ScsData *d, const ScsCone *k,
|
|
962
|
-
ScsInfo *info) {
|
|
1165
|
+
scs_int scs(const ScsData *d, const ScsCone *k, const ScsSettings *stgs,
|
|
1166
|
+
ScsSolution *sol, ScsInfo *info) {
|
|
963
1167
|
scs_int status;
|
|
964
|
-
ScsWork *w = SCS(init)(d, k,
|
|
965
|
-
#if
|
|
1168
|
+
ScsWork *w = SCS(init)(d, k, stgs);
|
|
1169
|
+
#if VERBOSITY > 0
|
|
966
1170
|
scs_printf("size of scs_int = %lu, size of scs_float = %lu\n",
|
|
967
1171
|
sizeof(scs_int), sizeof(scs_float));
|
|
968
1172
|
#endif
|
|
969
1173
|
if (w) {
|
|
970
|
-
SCS(solve)(w,
|
|
1174
|
+
SCS(solve)(w, sol, info);
|
|
971
1175
|
status = info->status_val;
|
|
972
1176
|
} else {
|
|
973
1177
|
status = failure(SCS_NULL, d ? d->m : -1, d ? d->n : -1, sol, info,
|
|
974
|
-
SCS_FAILED, "could not initialize work", "
|
|
1178
|
+
SCS_FAILED, "could not initialize work", "failure");
|
|
975
1179
|
}
|
|
976
1180
|
SCS(finish)(w);
|
|
977
1181
|
return status;
|