scs 0.3.1 → 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 +4 -0
- data/README.md +8 -8
- data/lib/scs/ffi.rb +1 -7
- data/lib/scs/version.rb +1 -1
- data/vendor/scs/CITATION.cff +1 -1
- data/vendor/scs/CMakeLists.txt +55 -7
- data/vendor/scs/Makefile +9 -9
- data/vendor/scs/README.md +2 -1
- data/vendor/scs/include/aa.h +1 -1
- data/vendor/scs/include/cones.h +14 -11
- data/vendor/scs/include/glbopts.h +26 -64
- data/vendor/scs/include/linalg.h +2 -1
- data/vendor/scs/include/linsys.h +13 -13
- data/vendor/scs/include/normalize.h +6 -5
- data/vendor/scs/include/scs.h +43 -87
- data/vendor/scs/include/scs_types.h +34 -0
- data/vendor/scs/include/scs_work.h +83 -0
- data/vendor/scs/linsys/cpu/direct/private.c +86 -73
- data/vendor/scs/linsys/cpu/direct/private.h +2 -2
- data/vendor/scs/linsys/cpu/indirect/private.c +42 -33
- data/vendor/scs/linsys/cpu/indirect/private.h +1 -2
- data/vendor/scs/linsys/csparse.c +3 -3
- 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_order.c +5 -5
- data/vendor/scs/linsys/gpu/gpu.h +8 -11
- data/vendor/scs/linsys/gpu/indirect/private.c +72 -49
- data/vendor/scs/linsys/gpu/indirect/private.h +14 -13
- data/vendor/scs/linsys/scs_matrix.c +26 -46
- data/vendor/scs/linsys/scs_matrix.h +4 -4
- data/vendor/scs/scs.mk +1 -1
- data/vendor/scs/src/aa.c +13 -4
- data/vendor/scs/src/cones.c +143 -92
- data/vendor/scs/src/linalg.c +25 -0
- data/vendor/scs/src/normalize.c +26 -26
- data/vendor/scs/src/rw.c +48 -12
- data/vendor/scs/src/scs.c +104 -110
- data/vendor/scs/src/scs_version.c +8 -6
- data/vendor/scs/src/util.c +1 -1
- data/vendor/scs/test/minunit.h +6 -1
- data/vendor/scs/test/problem_utils.h +28 -35
- data/vendor/scs/test/problems/degenerate.h +1 -1
- data/vendor/scs/test/problems/hs21_tiny_qp.h +1 -1
- data/vendor/scs/test/problems/hs21_tiny_qp_rw.h +1 -1
- data/vendor/scs/test/problems/infeasible_tiny_qp.h +1 -1
- data/vendor/scs/test/problems/qafiro_tiny_qp.h +3 -3
- data/vendor/scs/test/problems/random_prob.h +1 -1
- data/vendor/scs/test/problems/rob_gauss_cov_est.h +1 -1
- data/vendor/scs/test/problems/small_lp.h +3 -1
- data/vendor/scs/test/problems/small_qp.h +352 -0
- data/vendor/scs/test/problems/{test_fails.h → test_validation.h} +3 -3
- data/vendor/scs/test/problems/unbounded_tiny_qp.h +1 -1
- data/vendor/scs/test/random_socp_prob.c +1 -1
- data/vendor/scs/test/run_from_file.c +1 -1
- data/vendor/scs/test/run_tests.c +23 -14
- metadata +8 -5
data/vendor/scs/src/scs.c
CHANGED
@@ -7,6 +7,7 @@
|
|
7
7
|
#include "normalize.h"
|
8
8
|
#include "rw.h"
|
9
9
|
#include "scs_matrix.h"
|
10
|
+
#include "scs_work.h"
|
10
11
|
#include "util.h"
|
11
12
|
|
12
13
|
/* printing header */
|
@@ -41,11 +42,8 @@ static void free_work(ScsWork *w) {
|
|
41
42
|
scs_free(w->g);
|
42
43
|
scs_free(w->b_normalized);
|
43
44
|
scs_free(w->c_normalized);
|
44
|
-
scs_free(w->rho_y_vec);
|
45
45
|
scs_free(w->lin_sys_warm_start);
|
46
|
-
|
47
|
-
scs_free(w->cone_boundaries);
|
48
|
-
}
|
46
|
+
scs_free(w->diag_r);
|
49
47
|
if (w->scal) {
|
50
48
|
scs_free(w->scal->D);
|
51
49
|
scs_free(w->scal->E);
|
@@ -53,7 +51,7 @@ static void free_work(ScsWork *w) {
|
|
53
51
|
}
|
54
52
|
SCS(free_sol)(w->xys_orig);
|
55
53
|
free_residuals(w->r_orig);
|
56
|
-
if (w->stgs->normalize) {
|
54
|
+
if (w->stgs && w->stgs->normalize) {
|
57
55
|
SCS(free_sol)(w->xys_normalized);
|
58
56
|
free_residuals(w->r_normalized);
|
59
57
|
}
|
@@ -78,7 +76,7 @@ static void print_init_header(const ScsData *d, const ScsCone *k,
|
|
78
76
|
}
|
79
77
|
scs_printf("\n\t SCS v%s - Splitting Conic Solver\n\t(c) Brendan "
|
80
78
|
"O'Donoghue, Stanford University, 2012\n",
|
81
|
-
|
79
|
+
scs_version());
|
82
80
|
for (i = 0; i < LINE_LEN; ++i) {
|
83
81
|
scs_printf("-");
|
84
82
|
}
|
@@ -157,23 +155,22 @@ static scs_int failure(ScsWork *w, scs_int m, scs_int n, ScsSolution *sol,
|
|
157
155
|
}
|
158
156
|
|
159
157
|
/* given x,y,s warm start, set v = [x; s / R + y; 1]
|
160
|
-
* where R = diag(w->rho_y_vec).
|
161
158
|
*/
|
162
159
|
static void warm_start_vars(ScsWork *w, ScsSolution *sol) {
|
163
160
|
scs_int n = w->n, m = w->m, i;
|
164
161
|
scs_float *v = w->v;
|
165
162
|
/* normalize the warm-start */
|
166
163
|
if (w->stgs->normalize) {
|
167
|
-
SCS(normalize_sol)(w, sol);
|
164
|
+
SCS(normalize_sol)(w->scal, sol);
|
168
165
|
}
|
169
166
|
memcpy(v, sol->x, n * sizeof(scs_float));
|
170
167
|
for (i = 0; i < m; ++i) {
|
171
|
-
v[i + n] = sol->y[i] + sol->s[i] / w->
|
168
|
+
v[i + n] = sol->y[i] + sol->s[i] / w->diag_r[i + n];
|
172
169
|
}
|
173
170
|
v[n + m] = 1.0; /* tau = 1 */
|
174
171
|
/* un-normalize so sol unchanged */
|
175
172
|
if (w->stgs->normalize) {
|
176
|
-
SCS(un_normalize_sol)(w, sol);
|
173
|
+
SCS(un_normalize_sol)(w->scal, sol);
|
177
174
|
}
|
178
175
|
}
|
179
176
|
|
@@ -221,12 +218,12 @@ static void unnormalize_residuals(ScsWork *w) {
|
|
221
218
|
r->dobj = r_n->dobj / pd;
|
222
219
|
r->gap = r_n->gap / pd;
|
223
220
|
|
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);
|
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);
|
230
227
|
|
231
228
|
compute_residuals(r, w->m, w->n);
|
232
229
|
}
|
@@ -306,7 +303,7 @@ static void populate_residual_struct(ScsWork *w, scs_int iter) {
|
|
306
303
|
memcpy(w->xys_orig->x, w->xys_normalized->x, n * sizeof(scs_float));
|
307
304
|
memcpy(w->xys_orig->y, w->xys_normalized->y, m * sizeof(scs_float));
|
308
305
|
memcpy(w->xys_orig->s, w->xys_normalized->s, m * sizeof(scs_float));
|
309
|
-
SCS(un_normalize_sol)(w, w->xys_orig);
|
306
|
+
SCS(un_normalize_sol)(w->scal, w->xys_orig);
|
310
307
|
unnormalize_residuals(w);
|
311
308
|
}
|
312
309
|
}
|
@@ -317,47 +314,34 @@ static void cold_start_vars(ScsWork *w) {
|
|
317
314
|
w->v[l - 1] = 1.;
|
318
315
|
}
|
319
316
|
|
320
|
-
/* utility function that
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
const scs_float *y) {
|
325
|
-
scs_int i, n = w->n, len = w->n + w->m;
|
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;
|
326
321
|
scs_float ip = 0.0;
|
327
|
-
for (i = 0; i < n; ++i) {
|
328
|
-
ip +=
|
329
|
-
}
|
330
|
-
for (i = n; i < len; ++i) {
|
331
|
-
ip += x[i] * y[i] * w->rho_y_vec[i - n];
|
322
|
+
for (i = 0; i < w->n + w->m; ++i) {
|
323
|
+
ip += x[i] * y[i] * w->diag_r[i];
|
332
324
|
}
|
333
325
|
return ip;
|
334
326
|
}
|
335
327
|
|
336
|
-
static inline scs_float get_tau_scale(ScsWork *w) {
|
337
|
-
return TAU_FACTOR; /* TAU_FACTOR * w->scale; */
|
338
|
-
}
|
339
|
-
|
340
328
|
static scs_float root_plus(ScsWork *w, scs_float *p, scs_float *mu,
|
341
329
|
scs_float eta) {
|
342
|
-
scs_float b, c,
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
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;
|
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);
|
350
335
|
}
|
351
336
|
|
352
337
|
/* status < 0 indicates failure */
|
353
338
|
static scs_int project_lin_sys(ScsWork *w, scs_int iter) {
|
354
339
|
scs_int n = w->n, m = w->m, l = n + m + 1, status, i;
|
355
340
|
scs_float *warm_start = SCS_NULL;
|
356
|
-
scs_float tol = -1.0; /* only used for indirect methods,
|
341
|
+
scs_float tol = -1.0; /* only used for indirect methods, overridden later */
|
357
342
|
memcpy(w->u_t, w->v, l * sizeof(scs_float));
|
358
|
-
|
359
|
-
|
360
|
-
w->u_t[i] *= -w->rho_y_vec[i - n];
|
343
|
+
for (i = 0; i < l - 1; ++i) {
|
344
|
+
w->u_t[i] *= (i < n ? 1 : -1) * w->diag_r[i];
|
361
345
|
}
|
362
346
|
#if INDIRECT > 0
|
363
347
|
/* compute warm start using the cone projection output */
|
@@ -395,28 +379,15 @@ static scs_int project_lin_sys(ScsWork *w, scs_int iter) {
|
|
395
379
|
*/
|
396
380
|
static void compute_rsk(ScsWork *w) {
|
397
381
|
scs_int i, l = w->m + w->n + 1;
|
398
|
-
|
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];
|
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];
|
407
384
|
}
|
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
385
|
}
|
412
386
|
|
413
387
|
static void update_dual_vars(ScsWork *w) {
|
414
388
|
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
389
|
for (i = 0; i < l; ++i) {
|
419
|
-
w->v[i] +=
|
390
|
+
w->v[i] += w->stgs->alpha * (w->u[i] - w->u_t[i]);
|
420
391
|
}
|
421
392
|
}
|
422
393
|
|
@@ -427,7 +398,8 @@ static scs_int project_cones(ScsWork *w, const ScsCone *k, scs_int iter) {
|
|
427
398
|
w->u[i] = 2 * w->u_t[i] - w->v[i];
|
428
399
|
}
|
429
400
|
/* u = [x;y;tau] */
|
430
|
-
status =
|
401
|
+
status =
|
402
|
+
SCS(proj_dual_cone)(&(w->u[n]), w->cone_work, w->scal, &(w->diag_r[n]));
|
431
403
|
if (iter < FEASIBLE_ITERS) {
|
432
404
|
w->u[l - 1] = 1.0;
|
433
405
|
} else {
|
@@ -526,7 +498,7 @@ static void finalize(ScsWork *w, ScsSolution *sol, ScsInfo *info,
|
|
526
498
|
sety(w, sol);
|
527
499
|
sets(w, sol);
|
528
500
|
if (w->stgs->normalize) {
|
529
|
-
SCS(un_normalize_sol)(w, sol);
|
501
|
+
SCS(un_normalize_sol)(w->scal, sol);
|
530
502
|
}
|
531
503
|
populate_residual_struct(w, iter);
|
532
504
|
info->setup_time = w->setup_time;
|
@@ -578,6 +550,7 @@ static void print_summary(ScsWork *w, scs_int i, SCS(timer) * solve_timer) {
|
|
578
550
|
scs_printf("Norm u = %4f, ", SCS(norm_2)(w->u, w->n + w->m + 1));
|
579
551
|
scs_printf("Norm u_t = %4f, ", SCS(norm_2)(w->u_t, w->n + w->m + 1));
|
580
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));
|
581
554
|
scs_printf("Norm x = %4f, ", SCS(norm_2)(w->xys_orig->x, w->n));
|
582
555
|
scs_printf("Norm y = %4f, ", SCS(norm_2)(w->xys_orig->y, w->m));
|
583
556
|
scs_printf("Norm s = %4f, ", SCS(norm_2)(w->xys_orig->s, w->m));
|
@@ -739,6 +712,10 @@ static scs_int validate(const ScsData *d, const ScsCone *k,
|
|
739
712
|
scs_printf("scale must be positive (1 works well).\n");
|
740
713
|
return -1;
|
741
714
|
}
|
715
|
+
if (stgs->acceleration_interval <= 0) {
|
716
|
+
scs_printf("acceleration_interval must be positive (10 works well).\n");
|
717
|
+
return -1;
|
718
|
+
}
|
742
719
|
return 0;
|
743
720
|
}
|
744
721
|
#endif
|
@@ -755,6 +732,18 @@ static ScsResiduals *init_residuals(const ScsData *d) {
|
|
755
732
|
return r;
|
756
733
|
}
|
757
734
|
|
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
|
+
|
758
747
|
static ScsWork *init_work(const ScsData *d, const ScsCone *k,
|
759
748
|
const ScsSettings *stgs) {
|
760
749
|
ScsWork *w = (ScsWork *)scs_calloc(1, sizeof(ScsWork));
|
@@ -787,7 +776,7 @@ static ScsWork *init_work(const ScsData *d, const ScsCone *k,
|
|
787
776
|
w->h = (scs_float *)scs_calloc((l - 1), sizeof(scs_float));
|
788
777
|
w->g = (scs_float *)scs_calloc((l - 1), sizeof(scs_float));
|
789
778
|
w->lin_sys_warm_start = (scs_float *)scs_calloc((l - 1), sizeof(scs_float));
|
790
|
-
w->
|
779
|
+
w->diag_r = (scs_float *)scs_calloc(l, sizeof(scs_float));
|
791
780
|
/* x,y,s struct */
|
792
781
|
w->xys_orig = (ScsSolution *)scs_calloc(1, sizeof(ScsSolution));
|
793
782
|
w->xys_orig->x = (scs_float *)scs_calloc(d->n, sizeof(scs_float));
|
@@ -804,7 +793,12 @@ static ScsWork *init_work(const ScsData *d, const ScsCone *k,
|
|
804
793
|
w->c_normalized = (scs_float *)scs_calloc(d->n, sizeof(scs_float));
|
805
794
|
memcpy(w->b_normalized, w->b_orig, w->m * sizeof(scs_float));
|
806
795
|
memcpy(w->c_normalized, w->c_orig, w->n * sizeof(scs_float));
|
807
|
-
|
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);
|
808
802
|
|
809
803
|
if (!w->c_normalized) {
|
810
804
|
scs_printf("ERROR: work memory allocation failure\n");
|
@@ -829,24 +823,14 @@ static ScsWork *init_work(const ScsData *d, const ScsCone *k,
|
|
829
823
|
}
|
830
824
|
#endif
|
831
825
|
/* this allocates memory that must be freed */
|
832
|
-
w->
|
833
|
-
|
834
|
-
SCS(normalize)
|
835
|
-
(w->P, w->A, w->b_normalized, w->c_normalized, w->scal, w->cone_boundaries,
|
836
|
-
w->cone_boundaries_len);
|
826
|
+
w->scal = SCS(normalize_a_p)(w->P, w->A, w->b_normalized, w->c_normalized,
|
827
|
+
w->cone_work);
|
837
828
|
} else {
|
838
829
|
w->xys_normalized = w->xys_orig;
|
839
830
|
w->r_normalized = w->r_orig;
|
840
|
-
w->cone_boundaries_len = 0;
|
841
|
-
w->cone_boundaries = SCS_NULL;
|
842
831
|
w->scal = SCS_NULL;
|
843
832
|
}
|
844
|
-
if (!(w->
|
845
|
-
scs_printf("ERROR: init_cone failure\n");
|
846
|
-
return SCS_NULL;
|
847
|
-
}
|
848
|
-
if (!(w->p =
|
849
|
-
SCS(init_lin_sys_work)(w->A, w->P, w->rho_y_vec, w->stgs->rho_x))) {
|
833
|
+
if (!(w->p = SCS(init_lin_sys_work)(w->A, w->P, w->diag_r))) {
|
850
834
|
scs_printf("ERROR: init_lin_sys_work failure\n");
|
851
835
|
return SCS_NULL;
|
852
836
|
}
|
@@ -898,11 +882,11 @@ static scs_int update_work(const ScsData *d, ScsWork *w, ScsSolution *sol) {
|
|
898
882
|
}
|
899
883
|
|
900
884
|
/* will update if the factor is outside of range */
|
901
|
-
scs_int
|
885
|
+
scs_int should_update_r(scs_float factor, scs_int iter) {
|
902
886
|
return (factor > SQRTF(10.) || factor < 1. / SQRTF(10.));
|
903
887
|
}
|
904
888
|
|
905
|
-
static void
|
889
|
+
static void update_scale(ScsWork *w, const ScsCone *k, scs_int iter) {
|
906
890
|
scs_int i;
|
907
891
|
scs_float factor, new_scale;
|
908
892
|
|
@@ -939,14 +923,18 @@ static void maybe_update_scale(ScsWork *w, const ScsCone *k, scs_int iter) {
|
|
939
923
|
if (new_scale == w->scale) {
|
940
924
|
return;
|
941
925
|
}
|
942
|
-
if (
|
926
|
+
if (should_update_r(factor, iters_since_last_update)) {
|
943
927
|
w->scale_updates++;
|
944
928
|
w->sum_log_scale_factor = 0;
|
945
929
|
w->n_log_scale_factor = 0;
|
946
930
|
w->last_scale_update_iter = iter;
|
947
931
|
w->scale = new_scale;
|
948
|
-
|
949
|
-
|
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);
|
950
938
|
|
951
939
|
/* update pre-solved quantities */
|
952
940
|
update_work_cache(w);
|
@@ -956,10 +944,11 @@ static void maybe_update_scale(ScsWork *w, const ScsCone *k, scs_int iter) {
|
|
956
944
|
aa_reset(w->accel);
|
957
945
|
}
|
958
946
|
/* update v, using fact that rsk, u, u_t vectors should be the same */
|
959
|
-
/* solve: R (v^+ + u - 2u_t) = rsk
|
960
|
-
|
961
|
-
|
962
|
-
|
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];
|
963
952
|
}
|
964
953
|
}
|
965
954
|
}
|
@@ -970,7 +959,7 @@ static inline void normalize_v(scs_float *v, scs_int len) {
|
|
970
959
|
SCS(scale_array)(v, SQRTF((scs_float)len) * ITERATE_NORM / v_norm, len);
|
971
960
|
}
|
972
961
|
|
973
|
-
scs_int
|
962
|
+
scs_int scs_solve(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
|
974
963
|
scs_int i;
|
975
964
|
SCS(timer) solve_timer, lin_sys_timer, cone_timer, accel_timer;
|
976
965
|
scs_float total_accel_time = 0.0, total_cone_time = 0.0,
|
@@ -986,6 +975,7 @@ scs_int SCS(solve)(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
|
|
986
975
|
/* initialize ctrl-c support */
|
987
976
|
scs_start_interrupt_listener();
|
988
977
|
SCS(tic)(&solve_timer);
|
978
|
+
strcpy(info->lin_sys_solver, SCS(get_lin_sys_method)());
|
989
979
|
info->status_val = SCS_UNFINISHED; /* not yet converged */
|
990
980
|
update_work(d, w, sol);
|
991
981
|
|
@@ -1015,7 +1005,7 @@ scs_int SCS(solve)(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
|
|
1015
1005
|
/* store v_prev = v, *after* normalizing */
|
1016
1006
|
memcpy(w->v_prev, w->v, l * sizeof(scs_float));
|
1017
1007
|
|
1018
|
-
|
1008
|
+
/******************* linear system solve ********************/
|
1019
1009
|
SCS(tic)(&lin_sys_timer);
|
1020
1010
|
if (project_lin_sys(w, i) < 0) {
|
1021
1011
|
return failure(w, w->m, w->n, sol, info, SCS_FAILED,
|
@@ -1023,7 +1013,7 @@ scs_int SCS(solve)(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
|
|
1023
1013
|
}
|
1024
1014
|
total_lin_sys_time += SCS(tocq)(&lin_sys_timer);
|
1025
1015
|
|
1026
|
-
|
1016
|
+
/****************** project onto the cones ******************/
|
1027
1017
|
SCS(tic)(&cone_timer);
|
1028
1018
|
if (project_cones(w, k, i) < 0) {
|
1029
1019
|
return failure(w, w->m, w->n, sol, info, SCS_FAILED,
|
@@ -1031,8 +1021,9 @@ scs_int SCS(solve)(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
|
|
1031
1021
|
}
|
1032
1022
|
total_cone_time += SCS(tocq)(&cone_timer);
|
1033
1023
|
|
1034
|
-
/* dual
|
1035
|
-
|
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);
|
1036
1027
|
|
1037
1028
|
if (i % CONVERGED_INTERVAL == 0) {
|
1038
1029
|
if (scs_is_interrupted()) {
|
@@ -1051,6 +1042,21 @@ scs_int SCS(solve)(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
|
|
1051
1042
|
}
|
1052
1043
|
}
|
1053
1044
|
|
1045
|
+
/* Compute residuals. */
|
1046
|
+
if (w->stgs->verbose && i % PRINT_INTERVAL == 0) {
|
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
|
+
|
1054
1060
|
/* AA safeguard check.
|
1055
1061
|
* Perform safeguarding *after* convergence check to prevent safeguard
|
1056
1062
|
* overwriting converged iterate, since safeguard is on `v` and convergence
|
@@ -1066,17 +1072,6 @@ scs_int SCS(solve)(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
|
|
1066
1072
|
}
|
1067
1073
|
}
|
1068
1074
|
|
1069
|
-
/* Compute residuals. */
|
1070
|
-
if (w->stgs->verbose && i % PRINT_INTERVAL == 0) {
|
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);
|
1078
|
-
}
|
1079
|
-
|
1080
1075
|
/* Log *after* updating scale so residual recalc does not affect alg */
|
1081
1076
|
if (w->stgs->log_csv_filename) {
|
1082
1077
|
/* calc residuals every iter if logging to csv */
|
@@ -1113,12 +1108,12 @@ scs_int SCS(solve)(ScsWork *w, ScsSolution *sol, ScsInfo *info) {
|
|
1113
1108
|
return info->status_val;
|
1114
1109
|
}
|
1115
1110
|
|
1116
|
-
void
|
1111
|
+
void scs_finish(ScsWork *w) {
|
1117
1112
|
if (w) {
|
1118
1113
|
SCS(finish_cone)(w->cone_work);
|
1119
1114
|
if (w->stgs && w->stgs->normalize) {
|
1120
1115
|
#ifndef COPYAMATRIX
|
1121
|
-
SCS(
|
1116
|
+
SCS(un_normalize_a_p)(w->A, w->P, w->scal);
|
1122
1117
|
#else
|
1123
1118
|
SCS(free_scs_matrix)(w->A);
|
1124
1119
|
SCS(free_scs_matrix)(w->P);
|
@@ -1134,8 +1129,7 @@ void SCS(finish)(ScsWork *w) {
|
|
1134
1129
|
}
|
1135
1130
|
}
|
1136
1131
|
|
1137
|
-
ScsWork *
|
1138
|
-
const ScsSettings *stgs) {
|
1132
|
+
ScsWork *scs_init(const ScsData *d, const ScsCone *k, const ScsSettings *stgs) {
|
1139
1133
|
ScsWork *w;
|
1140
1134
|
SCS(timer) init_timer;
|
1141
1135
|
scs_start_interrupt_listener();
|
@@ -1161,22 +1155,22 @@ ScsWork *SCS(init)(const ScsData *d, const ScsCone *k,
|
|
1161
1155
|
return w;
|
1162
1156
|
}
|
1163
1157
|
|
1164
|
-
/* this just calls
|
1158
|
+
/* this just calls scs_init, scs_solve, and scs_finish */
|
1165
1159
|
scs_int scs(const ScsData *d, const ScsCone *k, const ScsSettings *stgs,
|
1166
1160
|
ScsSolution *sol, ScsInfo *info) {
|
1167
1161
|
scs_int status;
|
1168
|
-
ScsWork *w =
|
1162
|
+
ScsWork *w = scs_init(d, k, stgs);
|
1169
1163
|
#if VERBOSITY > 0
|
1170
1164
|
scs_printf("size of scs_int = %lu, size of scs_float = %lu\n",
|
1171
1165
|
sizeof(scs_int), sizeof(scs_float));
|
1172
1166
|
#endif
|
1173
1167
|
if (w) {
|
1174
|
-
|
1168
|
+
scs_solve(w, sol, info);
|
1175
1169
|
status = info->status_val;
|
1176
1170
|
} else {
|
1177
1171
|
status = failure(SCS_NULL, d ? d->m : -1, d ? d->n : -1, sol, info,
|
1178
1172
|
SCS_FAILED, "could not initialize work", "failure");
|
1179
1173
|
}
|
1180
|
-
|
1174
|
+
scs_finish(w);
|
1181
1175
|
return status;
|
1182
1176
|
}
|
@@ -1,11 +1,13 @@
|
|
1
|
+
#ifdef __cplusplus
|
2
|
+
extern "C" {
|
3
|
+
#endif
|
4
|
+
|
1
5
|
#include "glbopts.h"
|
2
6
|
|
3
|
-
const char *
|
7
|
+
const char *scs_version(void) {
|
4
8
|
return SCS_VERSION;
|
5
9
|
}
|
6
|
-
|
7
|
-
|
8
|
-
}
|
9
|
-
size_t SCS(sizeof_float)(void) {
|
10
|
-
return sizeof(scs_float);
|
10
|
+
|
11
|
+
#ifdef __cplusplus
|
11
12
|
}
|
13
|
+
#endif
|
data/vendor/scs/src/util.c
CHANGED
@@ -106,7 +106,7 @@ void SCS(free_sol)(ScsSolution *sol) {
|
|
106
106
|
}
|
107
107
|
|
108
108
|
/* assumes stgs already allocated memory */
|
109
|
-
void
|
109
|
+
void scs_set_default_settings(ScsSettings *stgs) {
|
110
110
|
/* These constants are defined in include/glbopts.h */
|
111
111
|
stgs->max_iters = MAX_ITERS;
|
112
112
|
stgs->eps_abs = EPS_ABS;
|
data/vendor/scs/test/minunit.h
CHANGED
@@ -13,10 +13,15 @@
|
|
13
13
|
if (!(test)) \
|
14
14
|
return message; \
|
15
15
|
} while (0)
|
16
|
-
#define mu_run_test(test)
|
16
|
+
#define mu_run_test(test) _mu_run_test(#test, test)
|
17
|
+
|
18
|
+
#define _mu_run_test(name, test) \
|
17
19
|
do { \
|
20
|
+
scs_printf("*********************************************************\n"); \
|
21
|
+
scs_printf("Running test: %s\n", name); \
|
18
22
|
const char *message = test(); \
|
19
23
|
tests_run++; \
|
24
|
+
scs_printf("*********************************************************\n"); \
|
20
25
|
if (message) \
|
21
26
|
return message; \
|
22
27
|
} while (0)
|
@@ -10,21 +10,11 @@
|
|
10
10
|
#include "scs_matrix.h"
|
11
11
|
#include "util.h"
|
12
12
|
|
13
|
-
#define
|
14
|
-
#ifdef DLONG
|
15
|
-
#ifdef _WIN64
|
16
|
-
/* this is a Microsoft extension, but also works with min_g_w-w64 */
|
17
|
-
#define INTRW "%I64d"
|
18
|
-
#else
|
19
|
-
#define INTRW "%ld"
|
20
|
-
#endif
|
21
|
-
#else
|
22
|
-
#define INTRW "%i"
|
23
|
-
#endif
|
13
|
+
#define _MAX_RAND_VAL (1073741823) /* 2^30 - 1 */
|
24
14
|
|
25
15
|
/* uniform random number in [-1,1] */
|
26
16
|
static scs_float rand_scs_float(void) {
|
27
|
-
return 2 * (((scs_float)ran_arr_next()) /
|
17
|
+
return 2 * (((scs_float)ran_arr_next()) / _MAX_RAND_VAL) - 1; /* in [-1, 1] */
|
28
18
|
}
|
29
19
|
|
30
20
|
void gen_random_prob_data(scs_int nnz, scs_int col_nnz, ScsData *d, ScsCone *k,
|
@@ -51,8 +41,8 @@ void gen_random_prob_data(scs_int nnz, scs_int col_nnz, ScsData *d, ScsCone *k,
|
|
51
41
|
for (i = 0; i < m; i++) {
|
52
42
|
y[i] = z[i] = rand_scs_float();
|
53
43
|
}
|
54
|
-
tmp_cone_work = SCS(init_cone)(k,
|
55
|
-
SCS(proj_dual_cone)(y,
|
44
|
+
tmp_cone_work = SCS(init_cone)(k, m);
|
45
|
+
SCS(proj_dual_cone)(y, tmp_cone_work, SCS_NULL, SCS_NULL);
|
56
46
|
SCS(finish_cone(tmp_cone_work));
|
57
47
|
|
58
48
|
for (i = 0; i < m; i++) {
|
@@ -88,25 +78,25 @@ void gen_random_prob_data(scs_int nnz, scs_int col_nnz, ScsData *d, ScsCone *k,
|
|
88
78
|
scs_free(z);
|
89
79
|
}
|
90
80
|
|
91
|
-
static scs_float get_dual_cone_dist(const scs_float *y,
|
92
|
-
|
81
|
+
static scs_float get_dual_cone_dist(const scs_float *y, ScsConeWork *c,
|
82
|
+
scs_int m) {
|
93
83
|
scs_float dist;
|
94
84
|
scs_float *t = (scs_float *)scs_calloc(m, sizeof(scs_float));
|
95
85
|
memcpy(t, y, m * sizeof(scs_float));
|
96
|
-
SCS(proj_dual_cone)(t,
|
86
|
+
SCS(proj_dual_cone)(t, c, SCS_NULL, SCS_NULL);
|
97
87
|
dist = SCS(norm_inf_diff)(t, y, m);
|
98
88
|
scs_free(t);
|
99
89
|
return dist;
|
100
90
|
}
|
101
91
|
|
102
92
|
/* via moreau */
|
103
|
-
static scs_float get_pri_cone_dist(const scs_float *s,
|
104
|
-
|
93
|
+
static scs_float get_pri_cone_dist(const scs_float *s, ScsConeWork *c,
|
94
|
+
scs_int m) {
|
105
95
|
scs_float dist;
|
106
96
|
scs_float *t = (scs_float *)scs_calloc(m, sizeof(scs_float));
|
107
97
|
memcpy(t, s, m * sizeof(scs_float));
|
108
98
|
SCS(scale_array)(t, -1.0, m);
|
109
|
-
SCS(proj_dual_cone)(t,
|
99
|
+
SCS(proj_dual_cone)(t, c, SCS_NULL, SCS_NULL);
|
110
100
|
dist = SCS(norm_inf)(t, m); /* ||s - Pi_c(s)|| = ||Pi_c*(-s)|| */
|
111
101
|
scs_free(t);
|
112
102
|
return dist;
|
@@ -123,11 +113,11 @@ const char *verify_solution_correct(ScsData *d, ScsCone *k, ScsSettings *stgs,
|
|
123
113
|
scs_float *c = d->c;
|
124
114
|
scs_float *b = d->b;
|
125
115
|
|
126
|
-
scs_float *primal = scs_calloc(m, sizeof(scs_float));
|
127
|
-
scs_float *ax = scs_calloc(m, sizeof(scs_float));
|
128
|
-
scs_float *dual = scs_calloc(n, sizeof(scs_float));
|
129
|
-
scs_float *px = scs_calloc(n, sizeof(scs_float));
|
130
|
-
scs_float *aty = scs_calloc(n, sizeof(scs_float));
|
116
|
+
scs_float *primal = (scs_float *)scs_calloc(m, sizeof(scs_float));
|
117
|
+
scs_float *ax = (scs_float *)scs_calloc(m, sizeof(scs_float));
|
118
|
+
scs_float *dual = (scs_float *)scs_calloc(n, sizeof(scs_float));
|
119
|
+
scs_float *px = (scs_float *)scs_calloc(n, sizeof(scs_float));
|
120
|
+
scs_float *aty = (scs_float *)scs_calloc(n, sizeof(scs_float));
|
131
121
|
|
132
122
|
scs_float res_pri, res_dual, res_infeas, res_unbdd_a, res_unbdd_p;
|
133
123
|
scs_float ctx, bty, xt_p_x, gap, pobj, dobj, sty;
|
@@ -135,7 +125,7 @@ const char *verify_solution_correct(ScsData *d, ScsCone *k, ScsSettings *stgs,
|
|
135
125
|
|
136
126
|
scs_float sdist = NAN, ydist = NAN;
|
137
127
|
|
138
|
-
ScsConeWork *cone_work = SCS(init_cone)(k,
|
128
|
+
ScsConeWork *cone_work = SCS(init_cone)(k, m);
|
139
129
|
|
140
130
|
/**************** PRIMAL *********************/
|
141
131
|
memset(ax, 0, m * sizeof(scs_float));
|
@@ -182,10 +172,10 @@ const char *verify_solution_correct(ScsData *d, ScsCone *k, ScsSettings *stgs,
|
|
182
172
|
/**************** CONES *****************/
|
183
173
|
|
184
174
|
if (status == SCS_SOLVED || status == SCS_UNBOUNDED) {
|
185
|
-
sdist = get_pri_cone_dist(sol->s,
|
175
|
+
sdist = get_pri_cone_dist(sol->s, cone_work, m);
|
186
176
|
}
|
187
177
|
if (status == SCS_SOLVED || status == SCS_INFEASIBLE) {
|
188
|
-
ydist = get_dual_cone_dist(sol->y,
|
178
|
+
ydist = get_dual_cone_dist(sol->y, cone_work, m);
|
189
179
|
}
|
190
180
|
|
191
181
|
/**************** OTHERS *****************/
|
@@ -215,14 +205,17 @@ const char *verify_solution_correct(ScsData *d, ScsCone *k, ScsSettings *stgs,
|
|
215
205
|
/**************** ASSERTS *****************/
|
216
206
|
if (status == SCS_SOLVED) {
|
217
207
|
mu_assert_less("Primal residual ERROR", ABS(res_pri - info->res_pri),
|
218
|
-
1e-
|
208
|
+
1e-11);
|
219
209
|
mu_assert_less("Dual residual ERROR", ABS(res_dual - info->res_dual),
|
220
|
-
1e-
|
221
|
-
mu_assert_less("Gap ERROR", ABS(gap - info->gap), 1e-
|
222
|
-
mu_assert_less("Primal obj ERROR", ABS(pobj - info->pobj),
|
223
|
-
|
210
|
+
1e-11);
|
211
|
+
mu_assert_less("Gap ERROR", ABS(gap - info->gap), 1e-8 * (1 + ABS(gap)));
|
212
|
+
mu_assert_less("Primal obj ERROR", ABS(pobj - info->pobj),
|
213
|
+
1e-9 * (1 + ABS(pobj)));
|
214
|
+
mu_assert_less("Dual obj ERROR", ABS(dobj - info->dobj),
|
215
|
+
1e-9 * (1 + ABS(dobj)));
|
224
216
|
/* slightly looser tol */
|
225
|
-
mu_assert_less("Complementary slackness ERROR", ABS(sty),
|
217
|
+
mu_assert_less("Complementary slackness ERROR", ABS(sty),
|
218
|
+
1e-8 * MAX(NORM(s, m), NORM(y, m)));
|
226
219
|
mu_assert_less("s cone dist ERROR", ABS(sdist), 1e-5);
|
227
220
|
mu_assert_less("y cone dist ERROR", ABS(ydist), 1e-5);
|
228
221
|
|
@@ -230,7 +223,7 @@ const char *verify_solution_correct(ScsData *d, ScsCone *k, ScsSettings *stgs,
|
|
230
223
|
stgs->eps_abs + stgs->eps_rel * prl);
|
231
224
|
mu_assert_less("Dual feas ERROR", res_dual,
|
232
225
|
stgs->eps_abs + stgs->eps_rel * drl);
|
233
|
-
mu_assert_less("Gap ERROR", gap, stgs->eps_abs + stgs->eps_rel * grl);
|
226
|
+
mu_assert_less("Gap feas ERROR", gap, stgs->eps_abs + stgs->eps_rel * grl);
|
234
227
|
|
235
228
|
} else if (status == SCS_INFEASIBLE) {
|
236
229
|
mu_assert_less("Infeas ERROR", ABS(res_infeas - info->res_infeas), 1e-8);
|