scs 0.2.0 → 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 +17 -0
- data/LICENSE.txt +18 -18
- data/README.md +28 -9
- data/ext/scs/extconf.rb +29 -0
- data/lib/scs/ffi.rb +30 -13
- data/lib/scs/solver.rb +32 -14
- data/lib/scs/version.rb +1 -1
- data/vendor/scs/CITATION.cff +39 -0
- data/vendor/scs/CMakeLists.txt +272 -0
- data/vendor/scs/Makefile +24 -15
- data/vendor/scs/README.md +8 -216
- 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 +58 -21
- data/vendor/scs/linsys/gpu/gpu.h +66 -28
- data/vendor/scs/linsys/gpu/indirect/private.c +368 -154
- data/vendor/scs/linsys/gpu/indirect/private.h +26 -12
- 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 +161 -22
- data/vendor/scs/src/rw.o +0 -0
- data/vendor/scs/src/scs.c +768 -561
- 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 +30 -73
- data/ext/scs/Rakefile +0 -11
- 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
|
-
|
|
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;
|
|
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;
|
|
356
472
|
}
|
|
357
473
|
|
|
358
|
-
static
|
|
359
|
-
|
|
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,34 +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
|
-
|
|
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
|
+
}
|
|
630
683
|
}
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
if (r->res_unbdd < eps && iter > 0) {
|
|
684
|
+
if (isless(r->res_unbdd_a, eps_infeas) &&
|
|
685
|
+
isless(r->res_unbdd_p, eps_infeas)) {
|
|
634
686
|
return SCS_UNBOUNDED;
|
|
635
687
|
}
|
|
636
|
-
if (r->res_infeas
|
|
688
|
+
if (isless(r->res_infeas, eps_infeas)) {
|
|
637
689
|
return SCS_INFEASIBLE;
|
|
638
690
|
}
|
|
639
691
|
return 0;
|
|
640
692
|
}
|
|
641
693
|
|
|
642
|
-
|
|
643
|
-
|
|
694
|
+
#if NOVALIDATE == 0
|
|
695
|
+
static scs_int validate(const ScsData *d, const ScsCone *k,
|
|
696
|
+
const ScsSettings *stgs) {
|
|
644
697
|
if (d->m <= 0 || d->n <= 0) {
|
|
645
698
|
scs_printf("m and n must both be greater than 0; m = %li, n = %li\n",
|
|
646
699
|
(long)d->m, (long)d->n);
|
|
647
700
|
return -1;
|
|
648
701
|
}
|
|
649
702
|
if (d->m < d->n) {
|
|
650
|
-
scs_printf("WARN: m less than n, problem likely degenerate\n");
|
|
703
|
+
/* scs_printf("WARN: m less than n, problem likely degenerate\n"); */
|
|
651
704
|
/* return -1; */
|
|
652
705
|
}
|
|
653
|
-
if (SCS(validate_lin_sys)(d->A) < 0) {
|
|
706
|
+
if (SCS(validate_lin_sys)(d->A, d->P) < 0) {
|
|
654
707
|
scs_printf("invalid linear system input data\n");
|
|
655
708
|
return -1;
|
|
656
709
|
}
|
|
@@ -662,8 +715,16 @@ static scs_int validate(const ScsData *d, const ScsCone *k) {
|
|
|
662
715
|
scs_printf("max_iters must be positive\n");
|
|
663
716
|
return -1;
|
|
664
717
|
}
|
|
665
|
-
if (stgs->
|
|
666
|
-
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");
|
|
667
728
|
return -1;
|
|
668
729
|
}
|
|
669
730
|
if (stgs->alpha <= 0 || stgs->alpha >= 2) {
|
|
@@ -680,222 +741,374 @@ static scs_int validate(const ScsData *d, const ScsCone *k) {
|
|
|
680
741
|
}
|
|
681
742
|
return 0;
|
|
682
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
|
+
}
|
|
683
757
|
|
|
684
|
-
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) {
|
|
685
760
|
ScsWork *w = (ScsWork *)scs_calloc(1, sizeof(ScsWork));
|
|
686
761
|
scs_int l = d->n + d->m + 1;
|
|
687
|
-
if (
|
|
688
|
-
print_init_header(d, k);
|
|
762
|
+
if (stgs->verbose) {
|
|
763
|
+
print_init_header(d, k, stgs);
|
|
689
764
|
}
|
|
690
765
|
if (!w) {
|
|
691
766
|
scs_printf("ERROR: allocating work failure\n");
|
|
692
767
|
return SCS_NULL;
|
|
693
768
|
}
|
|
694
769
|
/* get settings and dims from data struct */
|
|
695
|
-
w->
|
|
770
|
+
w->d = d;
|
|
771
|
+
w->k = k;
|
|
772
|
+
w->stgs = stgs;
|
|
773
|
+
w->scale = stgs->scale; /* initial scale, may be updated */
|
|
696
774
|
w->m = d->m;
|
|
697
775
|
w->n = d->n;
|
|
698
|
-
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;
|
|
699
781
|
/* allocate workspace: */
|
|
700
|
-
|
|
701
|
-
w->
|
|
702
|
-
w->
|
|
703
|
-
w->
|
|
704
|
-
w->
|
|
705
|
-
w->h = (scs_float *)
|
|
706
|
-
w->g = (scs_float *)
|
|
707
|
-
w->
|
|
708
|
-
w->
|
|
709
|
-
|
|
710
|
-
w->
|
|
711
|
-
|
|
712
|
-
|
|
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) {
|
|
713
810
|
scs_printf("ERROR: work memory allocation failure\n");
|
|
714
811
|
return SCS_NULL;
|
|
715
812
|
}
|
|
716
|
-
|
|
717
|
-
w->v = &(w->u[l]);
|
|
718
|
-
w->v_best = &(w->u_best[l]);
|
|
719
|
-
w->v_prev = &(w->u_prev[l]);
|
|
720
|
-
w->A = d->A;
|
|
813
|
+
|
|
721
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
|
+
|
|
722
821
|
#ifdef COPYAMATRIX
|
|
723
|
-
if (!SCS(
|
|
822
|
+
if (!SCS(copy_matrix)(&(w->A), d->A)) {
|
|
724
823
|
scs_printf("ERROR: copy A matrix failed\n");
|
|
725
824
|
return SCS_NULL;
|
|
726
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
|
+
}
|
|
727
830
|
#endif
|
|
728
|
-
|
|
729
|
-
SCS(
|
|
730
|
-
|
|
731
|
-
SCS(
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
scs_printf("SCS(norm) E = %4f\n", SCS(norm)(w->scal->E, d->n));
|
|
735
|
-
#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);
|
|
736
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;
|
|
737
842
|
w->scal = SCS_NULL;
|
|
738
843
|
}
|
|
739
|
-
if (!(w->cone_work = SCS(init_cone)(k))) {
|
|
844
|
+
if (!(w->cone_work = SCS(init_cone)(k, w->scal, w->m))) {
|
|
740
845
|
scs_printf("ERROR: init_cone failure\n");
|
|
741
846
|
return SCS_NULL;
|
|
742
847
|
}
|
|
743
|
-
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))) {
|
|
744
850
|
scs_printf("ERROR: init_lin_sys_work failure\n");
|
|
745
851
|
return SCS_NULL;
|
|
746
852
|
}
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
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
|
+
}
|
|
868
|
+
}
|
|
869
|
+
} else {
|
|
870
|
+
w->accel = SCS_NULL;
|
|
751
871
|
}
|
|
752
872
|
return w;
|
|
753
873
|
}
|
|
754
874
|
|
|
755
|
-
static
|
|
756
|
-
|
|
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) {
|
|
757
884
|
/* before normalization */
|
|
758
885
|
scs_int n = d->n;
|
|
759
886
|
scs_int m = d->m;
|
|
760
|
-
|
|
761
|
-
w->nm_b = SCS(norm)(d->b, m);
|
|
762
|
-
w->nm_c = SCS(norm)(d->c, n);
|
|
763
|
-
memcpy(w->b, d->b, d->m * sizeof(scs_float));
|
|
764
|
-
memcpy(w->c, d->c, d->n * sizeof(scs_float));
|
|
765
|
-
|
|
766
|
-
#if EXTRA_VERBOSE > 0
|
|
767
|
-
SCS(print_array)(w->b, m, "b");
|
|
768
|
-
scs_printf("pre-normalized norm b = %4f\n", SCS(norm)(w->b, m));
|
|
769
|
-
SCS(print_array)(w->c, n, "c");
|
|
770
|
-
scs_printf("pre-normalized norm c = %4f\n", SCS(norm)(w->c, n));
|
|
771
|
-
#endif
|
|
772
|
-
if (w->stgs->normalize) {
|
|
773
|
-
SCS(normalize_b_c)(w);
|
|
774
|
-
#if EXTRA_VERBOSE > 0
|
|
775
|
-
SCS(print_array)(w->b, m, "bn");
|
|
776
|
-
scs_printf("sc_b = %4f\n", w->sc_b);
|
|
777
|
-
scs_printf("post-normalized norm b = %4f\n", SCS(norm)(w->b, m));
|
|
778
|
-
SCS(print_array)(w->c, n, "cn");
|
|
779
|
-
scs_printf("sc_c = %4f\n", w->sc_c);
|
|
780
|
-
scs_printf("post-normalized norm c = %4f\n", SCS(norm)(w->c, n));
|
|
781
|
-
#endif
|
|
782
|
-
}
|
|
783
887
|
if (w->stgs->warm_start) {
|
|
784
888
|
warm_start_vars(w, sol);
|
|
785
889
|
} else {
|
|
786
890
|
cold_start_vars(w);
|
|
787
891
|
}
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
memcpy(w->
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
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);
|
|
794
897
|
return 0;
|
|
795
898
|
}
|
|
796
899
|
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
scs_float v_norm_difference = SCS(norm_diff)(w->v, w->v_prev, l);
|
|
801
|
-
scs_float norm = SQRTF(SCS(norm_sq)(w->u, l) + SCS(norm_sq)(w->v, l));
|
|
802
|
-
scs_float norm_diff = SQRTF(u_norm_difference * u_norm_difference +
|
|
803
|
-
v_norm_difference * v_norm_difference);
|
|
804
|
-
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.));
|
|
805
903
|
}
|
|
806
904
|
|
|
807
|
-
static void
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
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;
|
|
813
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);
|
|
814
971
|
}
|
|
815
972
|
|
|
816
|
-
scs_int SCS(solve)(ScsWork *w,
|
|
817
|
-
ScsSolution *sol, ScsInfo *info) {
|
|
973
|
+
scs_int SCS(solve)(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
|
|
818
974
|
scs_int i;
|
|
819
|
-
SCS(timer) solve_timer, accel_timer;
|
|
820
|
-
scs_float total_accel_time = 0.0,
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
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");
|
|
825
980
|
return SCS_FAILED;
|
|
826
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;
|
|
827
986
|
/* initialize ctrl-c support */
|
|
828
987
|
scs_start_interrupt_listener();
|
|
829
988
|
SCS(tic)(&solve_timer);
|
|
830
989
|
info->status_val = SCS_UNFINISHED; /* not yet converged */
|
|
831
|
-
r.last_iter = -1;
|
|
832
990
|
update_work(d, w, sol);
|
|
833
991
|
|
|
834
992
|
if (w->stgs->verbose) {
|
|
835
993
|
print_header(w, k);
|
|
836
994
|
}
|
|
837
|
-
|
|
995
|
+
|
|
996
|
+
/* SCS */
|
|
838
997
|
for (i = 0; i < w->stgs->max_iters; ++i) {
|
|
839
|
-
/*
|
|
998
|
+
/* Accelerate here so that last step always projection onto cone */
|
|
840
999
|
/* this ensures the returned iterates always satisfy conic constraints */
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
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);
|
|
848
1007
|
}
|
|
849
|
-
total_accel_time += SCS(tocq)(&accel_timer);
|
|
850
1008
|
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
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
|
+
}
|
|
855
1014
|
|
|
856
|
-
|
|
1015
|
+
/* store v_prev = v, *after* normalizing */
|
|
857
1016
|
memcpy(w->v_prev, w->v, l * sizeof(scs_float));
|
|
858
1017
|
|
|
1018
|
+
/* linear system solve */
|
|
1019
|
+
SCS(tic)(&lin_sys_timer);
|
|
859
1020
|
if (project_lin_sys(w, i) < 0) {
|
|
860
1021
|
return failure(w, w->m, w->n, sol, info, SCS_FAILED,
|
|
861
|
-
"error in project_lin_sys", "
|
|
1022
|
+
"error in project_lin_sys", "failure");
|
|
862
1023
|
}
|
|
1024
|
+
total_lin_sys_time += SCS(tocq)(&lin_sys_timer);
|
|
1025
|
+
|
|
1026
|
+
/* project onto the cones */
|
|
1027
|
+
SCS(tic)(&cone_timer);
|
|
863
1028
|
if (project_cones(w, k, i) < 0) {
|
|
864
1029
|
return failure(w, w->m, w->n, sol, info, SCS_FAILED,
|
|
865
|
-
"error in project_cones", "
|
|
1030
|
+
"error in project_cones", "failure");
|
|
866
1031
|
}
|
|
1032
|
+
total_cone_time += SCS(tocq)(&cone_timer);
|
|
867
1033
|
|
|
1034
|
+
/* dual variable step */
|
|
868
1035
|
update_dual_vars(w);
|
|
869
1036
|
|
|
870
|
-
if (
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
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) {
|
|
877
1044
|
break;
|
|
878
1045
|
}
|
|
879
|
-
|
|
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
|
+
}
|
|
880
1052
|
}
|
|
881
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. */
|
|
882
1070
|
if (w->stgs->verbose && i % PRINT_INTERVAL == 0) {
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
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);
|
|
886
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);
|
|
887
1092
|
}
|
|
1093
|
+
|
|
888
1094
|
if (w->stgs->verbose) {
|
|
889
|
-
|
|
890
|
-
print_summary(w, i, &
|
|
1095
|
+
populate_residual_struct(w, i);
|
|
1096
|
+
print_summary(w, i, &solve_timer);
|
|
891
1097
|
}
|
|
1098
|
+
|
|
892
1099
|
/* populate solution vectors (unnormalized) and info */
|
|
893
|
-
|
|
1100
|
+
finalize(w, sol, info, i);
|
|
1101
|
+
|
|
1102
|
+
/* populate timings */
|
|
894
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;
|
|
895
1107
|
|
|
896
1108
|
if (w->stgs->verbose) {
|
|
897
|
-
print_footer(
|
|
1109
|
+
print_footer(info);
|
|
898
1110
|
}
|
|
1111
|
+
|
|
899
1112
|
scs_end_interrupt_listener();
|
|
900
1113
|
return info->status_val;
|
|
901
1114
|
}
|
|
@@ -905,9 +1118,10 @@ void SCS(finish)(ScsWork *w) {
|
|
|
905
1118
|
SCS(finish_cone)(w->cone_work);
|
|
906
1119
|
if (w->stgs && w->stgs->normalize) {
|
|
907
1120
|
#ifndef COPYAMATRIX
|
|
908
|
-
SCS(
|
|
1121
|
+
SCS(un_normalize)(w->A, w->P, w->scal);
|
|
909
1122
|
#else
|
|
910
|
-
SCS(
|
|
1123
|
+
SCS(free_scs_matrix)(w->A);
|
|
1124
|
+
SCS(free_scs_matrix)(w->P);
|
|
911
1125
|
#endif
|
|
912
1126
|
}
|
|
913
1127
|
if (w->p) {
|
|
@@ -920,55 +1134,48 @@ void SCS(finish)(ScsWork *w) {
|
|
|
920
1134
|
}
|
|
921
1135
|
}
|
|
922
1136
|
|
|
923
|
-
ScsWork *SCS(init)(const ScsData *d, const ScsCone *k,
|
|
924
|
-
|
|
925
|
-
SCS(tic)(&global_timer);
|
|
926
|
-
#endif
|
|
1137
|
+
ScsWork *SCS(init)(const ScsData *d, const ScsCone *k,
|
|
1138
|
+
const ScsSettings *stgs) {
|
|
927
1139
|
ScsWork *w;
|
|
928
1140
|
SCS(timer) init_timer;
|
|
929
1141
|
scs_start_interrupt_listener();
|
|
930
|
-
if (!d || !k
|
|
931
|
-
scs_printf("ERROR: Missing ScsData
|
|
1142
|
+
if (!d || !k) {
|
|
1143
|
+
scs_printf("ERROR: Missing ScsData or ScsCone input\n");
|
|
932
1144
|
return SCS_NULL;
|
|
933
1145
|
}
|
|
934
|
-
#if
|
|
935
|
-
|
|
936
|
-
SCS(print_cone_data)(k);
|
|
937
|
-
#endif
|
|
938
|
-
#ifndef NOVALIDATE
|
|
939
|
-
if (validate(d, k) < 0) {
|
|
1146
|
+
#if NOVALIDATE == 0
|
|
1147
|
+
if (validate(d, k, stgs) < 0) {
|
|
940
1148
|
scs_printf("ERROR: Validation returned failure\n");
|
|
941
1149
|
return SCS_NULL;
|
|
942
1150
|
}
|
|
943
1151
|
#endif
|
|
944
1152
|
SCS(tic)(&init_timer);
|
|
945
|
-
if (
|
|
946
|
-
SCS(write_data)(d, k);
|
|
1153
|
+
if (stgs->write_data_filename) {
|
|
1154
|
+
SCS(write_data)(d, k, stgs);
|
|
947
1155
|
}
|
|
948
|
-
w = init_work(d, k);
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
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);
|
|
952
1159
|
}
|
|
953
1160
|
scs_end_interrupt_listener();
|
|
954
1161
|
return w;
|
|
955
1162
|
}
|
|
956
1163
|
|
|
957
1164
|
/* this just calls SCS(init), SCS(solve), and SCS(finish) */
|
|
958
|
-
scs_int scs(const ScsData *d, const ScsCone *k,
|
|
959
|
-
ScsInfo *info) {
|
|
1165
|
+
scs_int scs(const ScsData *d, const ScsCone *k, const ScsSettings *stgs,
|
|
1166
|
+
ScsSolution *sol, ScsInfo *info) {
|
|
960
1167
|
scs_int status;
|
|
961
|
-
ScsWork *w = SCS(init)(d, k,
|
|
962
|
-
#if
|
|
1168
|
+
ScsWork *w = SCS(init)(d, k, stgs);
|
|
1169
|
+
#if VERBOSITY > 0
|
|
963
1170
|
scs_printf("size of scs_int = %lu, size of scs_float = %lu\n",
|
|
964
1171
|
sizeof(scs_int), sizeof(scs_float));
|
|
965
1172
|
#endif
|
|
966
1173
|
if (w) {
|
|
967
|
-
SCS(solve)(w,
|
|
1174
|
+
SCS(solve)(w, sol, info);
|
|
968
1175
|
status = info->status_val;
|
|
969
1176
|
} else {
|
|
970
1177
|
status = failure(SCS_NULL, d ? d->m : -1, d ? d->n : -1, sol, info,
|
|
971
|
-
SCS_FAILED, "could not initialize work", "
|
|
1178
|
+
SCS_FAILED, "could not initialize work", "failure");
|
|
972
1179
|
}
|
|
973
1180
|
SCS(finish)(w);
|
|
974
1181
|
return status;
|