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