scs 0.3.1 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- 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);
|