scs 0.5.6 → 0.6.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 +5 -0
- data/LICENSE.txt +1 -1
- data/lib/scs/ffi.rb +18 -0
- data/lib/scs/version.rb +1 -1
- data/vendor/scs/CITATION.cff +2 -3
- data/vendor/scs/CLAUDE.md +115 -0
- data/vendor/scs/CMakeLists.txt +330 -201
- data/vendor/scs/CONTRIBUTING.md +49 -0
- data/vendor/scs/Makefile +90 -43
- data/vendor/scs/README.md +96 -2
- data/vendor/scs/include/aa.h +59 -11
- data/vendor/scs/include/aa_stats.h +47 -0
- data/vendor/scs/include/cones.h +16 -7
- data/vendor/scs/include/glbopts.h +113 -26
- data/vendor/scs/include/linalg.h +5 -1
- data/vendor/scs/include/linsys.h +1 -2
- data/vendor/scs/include/normalize.h +6 -2
- data/vendor/scs/include/rw.h +9 -3
- data/vendor/scs/include/scs.h +17 -1
- data/vendor/scs/include/scs_blas.h +8 -0
- data/vendor/scs/include/scs_types.h +2 -2
- data/vendor/scs/include/scs_work.h +22 -1
- data/vendor/scs/include/util.h +3 -6
- data/vendor/scs/include/util_spectral_cones.h +3 -3
- data/vendor/scs/linsys/accelerate/direct/private.c +126 -0
- data/vendor/scs/linsys/accelerate/direct/private.h +34 -0
- data/vendor/scs/linsys/cpu/dense/private.c +250 -0
- data/vendor/scs/linsys/cpu/dense/private.h +31 -0
- data/vendor/scs/linsys/cpu/direct/private.c +86 -44
- data/vendor/scs/linsys/cpu/indirect/private.c +647 -113
- data/vendor/scs/linsys/cpu/indirect/private.h +28 -0
- data/vendor/scs/linsys/csparse.c +9 -3
- data/vendor/scs/linsys/csparse.h +4 -2
- data/vendor/scs/linsys/cudss/direct/private.c +77 -43
- data/vendor/scs/linsys/cudss/direct/private.h +33 -7
- data/vendor/scs/linsys/gpu/indirect/private.c +6 -2
- data/vendor/scs/linsys/mkl/direct/private.c +63 -31
- data/vendor/scs/linsys/mkl/direct/private.h +0 -1
- data/vendor/scs/linsys/scs_matrix.c +291 -165
- data/vendor/scs/linsys/scs_matrix.h +7 -9
- data/vendor/scs/scs.mk +35 -13
- data/vendor/scs/src/aa.c +673 -166
- data/vendor/scs/src/cones.c +545 -223
- data/vendor/scs/src/ctrlc.c +59 -16
- data/vendor/scs/src/exp_cone.c +70 -50
- data/vendor/scs/src/linalg.c +21 -2
- data/vendor/scs/src/normalize.c +24 -26
- data/vendor/scs/src/rw.c +596 -124
- data/vendor/scs/src/scs.c +990 -513
- data/vendor/scs/src/spectral_cones/logdeterminant/log_cone_IPM.c +240 -187
- data/vendor/scs/src/spectral_cones/logdeterminant/log_cone_Newton.c +108 -85
- data/vendor/scs/src/spectral_cones/logdeterminant/log_cone_wrapper.c +62 -63
- data/vendor/scs/src/spectral_cones/logdeterminant/logdet_cone.c +85 -78
- data/vendor/scs/src/spectral_cones/nuclear/ell1_cone.c +92 -97
- data/vendor/scs/src/spectral_cones/nuclear/nuclear_cone.c +39 -28
- data/vendor/scs/src/spectral_cones/sum-largest/sum_largest_cone.c +59 -40
- data/vendor/scs/src/spectral_cones/sum-largest/sum_largest_eval_cone.c +37 -29
- data/vendor/scs/src/spectral_cones/util_spectral_cones.c +12 -6
- data/vendor/scs/src/util.c +37 -7
- data/vendor/scs/test/mkl_interface_mismatch.c +97 -0
- data/vendor/scs/test/packaging/CMakeLists.txt +21 -0
- data/vendor/scs/test/packaging/consume.c +50 -0
- data/vendor/scs/test/problem_utils.h +9 -2
- data/vendor/scs/test/problems/dense_qp.h +64 -0
- data/vendor/scs/test/problems/hs21_tiny_qp.h +6 -2
- data/vendor/scs/test/problems/hs21_tiny_qp_rw.h +10 -2
- data/vendor/scs/test/problems/infeasible_lp.h +66 -0
- data/vendor/scs/test/problems/infeasible_socp.h +75 -0
- data/vendor/scs/test/problems/lp_update.h +110 -0
- data/vendor/scs/test/problems/qafiro_tiny_qp.h +3 -1
- data/vendor/scs/test/problems/rob_gauss_cov_est.h +6 -3
- data/vendor/scs/test/problems/small_qp.h +5 -0
- data/vendor/scs/test/problems/test_box_cone.h +92 -0
- data/vendor/scs/test/problems/test_dual_exp_cone.h +96 -0
- data/vendor/scs/test/problems/test_inaccurate.h +212 -0
- data/vendor/scs/test/problems/test_mixed_cones.h +113 -0
- data/vendor/scs/test/problems/test_normalize_roundtrip.h +279 -0
- data/vendor/scs/test/problems/test_power_cone.h +414 -0
- data/vendor/scs/test/problems/test_psd_metric.h +109 -0
- data/vendor/scs/test/problems/test_psd_n1.h +84 -0
- data/vendor/scs/test/problems/test_root_plus.h +191 -0
- data/vendor/scs/test/problems/test_rw_settings.h +112 -0
- data/vendor/scs/test/problems/test_soc_sizes.h +393 -0
- data/vendor/scs/test/problems/test_solver_options.h +558 -0
- data/vendor/scs/test/problems/test_validation.h +263 -24
- data/vendor/scs/test/problems/test_zero_cone.h +81 -0
- data/vendor/scs/test/problems/unbounded_lp.h +66 -0
- data/vendor/scs/test/problems/unbounded_socp.h +71 -0
- data/vendor/scs/test/run_from_file.c +6 -0
- data/vendor/scs/test/run_tests.c +71 -0
- data/vendor/scs/test/rw_settings.c +7 -0
- data/vendor/scs/test/spectral_cones_problems/test_ell1_and_nuc.h +128 -0
- data/vendor/scs/test/spectral_cones_problems/test_ell1_cone.h +115 -0
- metadata +35 -3
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
#include "glbopts.h"
|
|
2
|
+
#include "linalg.h"
|
|
3
|
+
#include "minunit.h"
|
|
4
|
+
#include "scs.h"
|
|
5
|
+
|
|
6
|
+
/*
|
|
7
|
+
* Test that the stable fused single-loop root_plus computation gives the same
|
|
8
|
+
* result as the original five-separate-dot_r formulation on well-conditioned
|
|
9
|
+
* cases and improves a cancellation-prone quadratic.
|
|
10
|
+
*
|
|
11
|
+
* root_plus solves: tau = (-b + sqrt(b^2 - 4ac)) / (2a)
|
|
12
|
+
* where a = tau_scale + g'Rg
|
|
13
|
+
* b = mu'Rg - 2 p'Rg - eta * tau_scale
|
|
14
|
+
* c = p'Rp - p'Rmu
|
|
15
|
+
* and x'Ry = sum_i x[i]*y[i]*r[i] (R-weighted dot product)
|
|
16
|
+
*
|
|
17
|
+
* The old code computed a, b, c via five separate dot_r calls.
|
|
18
|
+
* The new code computes all five weighted dot products in one fused loop.
|
|
19
|
+
* Both must produce the same quadratic formula result.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/* Old implementation: separate weighted dot products */
|
|
23
|
+
static scs_float dot_r_ref(const scs_float *x, const scs_float *y,
|
|
24
|
+
const scs_float *r, scs_int nm) {
|
|
25
|
+
scs_int i;
|
|
26
|
+
scs_float ip = 0.0;
|
|
27
|
+
for (i = 0; i < nm; ++i) {
|
|
28
|
+
ip += x[i] * y[i] * r[i];
|
|
29
|
+
}
|
|
30
|
+
return ip;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
static scs_float root_plus_old(const scs_float *g, const scs_float *p,
|
|
34
|
+
const scs_float *mu, const scs_float *r,
|
|
35
|
+
scs_int nm, scs_float tau_scale,
|
|
36
|
+
scs_float eta) {
|
|
37
|
+
scs_float a, b, c, rad;
|
|
38
|
+
a = tau_scale + dot_r_ref(g, g, r, nm);
|
|
39
|
+
b = dot_r_ref(mu, g, r, nm) - 2 * dot_r_ref(p, g, r, nm) -
|
|
40
|
+
eta * tau_scale;
|
|
41
|
+
c = dot_r_ref(p, p, r, nm) - dot_r_ref(p, mu, r, nm);
|
|
42
|
+
rad = b * b - 4 * a * c;
|
|
43
|
+
return (-b + SQRTF(MAX(rad, 0.))) / (2 * a);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
static scs_float root_plus_stable_coeffs(scs_float a, scs_float b,
|
|
47
|
+
scs_float c) {
|
|
48
|
+
scs_float rad, sqrt_rad, q;
|
|
49
|
+
if (!isfinite(a) || !isfinite(b) || !isfinite(c) || a <= 0.) {
|
|
50
|
+
return NAN;
|
|
51
|
+
}
|
|
52
|
+
rad = b * b - 4 * a * c;
|
|
53
|
+
if (!isfinite(rad)) {
|
|
54
|
+
return NAN;
|
|
55
|
+
}
|
|
56
|
+
if (rad < 0.) {
|
|
57
|
+
return -b / (2 * a);
|
|
58
|
+
}
|
|
59
|
+
sqrt_rad = SQRTF(rad);
|
|
60
|
+
if (b <= 0.) {
|
|
61
|
+
return (-b + sqrt_rad) / (2 * a);
|
|
62
|
+
}
|
|
63
|
+
q = -0.5 * (b + sqrt_rad);
|
|
64
|
+
return q != 0. ? c / q : 0.;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* New implementation: fused single loop with stable quadratic formula */
|
|
68
|
+
static scs_float root_plus_new(const scs_float *g, const scs_float *p,
|
|
69
|
+
const scs_float *mu, const scs_float *r,
|
|
70
|
+
scs_int nm, scs_float tau_scale,
|
|
71
|
+
scs_float eta) {
|
|
72
|
+
scs_int i;
|
|
73
|
+
scs_float gg = 0., mug = 0., pg = 0., pp = 0., pmu = 0.;
|
|
74
|
+
scs_float a, b, c;
|
|
75
|
+
for (i = 0; i < nm; ++i) {
|
|
76
|
+
scs_float ri = r[i], gi = g[i], pi = p[i], mui = mu[i];
|
|
77
|
+
gg += gi * gi * ri;
|
|
78
|
+
mug += mui * gi * ri;
|
|
79
|
+
pg += pi * gi * ri;
|
|
80
|
+
pp += pi * pi * ri;
|
|
81
|
+
pmu += pi * mui * ri;
|
|
82
|
+
}
|
|
83
|
+
a = tau_scale + gg;
|
|
84
|
+
b = mug - 2 * pg - eta * tau_scale;
|
|
85
|
+
c = pp - pmu;
|
|
86
|
+
return root_plus_stable_coeffs(a, b, c);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
static const char *test_root_plus_equivalence(void) {
|
|
90
|
+
/* Test with several hand-crafted input vectors */
|
|
91
|
+
scs_int nm;
|
|
92
|
+
scs_float tau_scale, eta, old_val, new_val, err;
|
|
93
|
+
|
|
94
|
+
/* Test case 1: small vector */
|
|
95
|
+
{
|
|
96
|
+
scs_float g1[] = {1.0, -2.0, 0.5};
|
|
97
|
+
scs_float p1[] = {0.3, 0.7, -0.1};
|
|
98
|
+
scs_float mu1[] = {-0.5, 1.2, 0.8};
|
|
99
|
+
scs_float r1[] = {2.0, 0.5, 1.5};
|
|
100
|
+
nm = 3;
|
|
101
|
+
tau_scale = 1.0;
|
|
102
|
+
eta = 0.5;
|
|
103
|
+
old_val = root_plus_old(g1, p1, mu1, r1, nm, tau_scale, eta);
|
|
104
|
+
new_val = root_plus_new(g1, p1, mu1, r1, nm, tau_scale, eta);
|
|
105
|
+
err = ABS(old_val - new_val);
|
|
106
|
+
scs_printf("root_plus case 1: old=%.12e new=%.12e err=%.2e\n",
|
|
107
|
+
old_val, new_val, err);
|
|
108
|
+
mu_assert("root_plus case 1 mismatch", err < 1e-12 * MAX(ABS(old_val), 1.));
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/* Test case 2: larger vector with mixed signs */
|
|
112
|
+
{
|
|
113
|
+
scs_float g2[] = {-0.1, 3.0, -2.5, 0.7, 1.1, -0.3, 0.9, -1.4};
|
|
114
|
+
scs_float p2[] = {0.5, -0.8, 1.2, -0.4, 0.6, 2.1, -1.0, 0.3};
|
|
115
|
+
scs_float mu2[] = {1.0, -1.5, 0.3, 0.8, -0.2, 0.7, 1.3, -0.6};
|
|
116
|
+
scs_float r2[] = {0.1, 1.0, 3.0, 0.5, 2.0, 0.8, 1.5, 0.3};
|
|
117
|
+
nm = 8;
|
|
118
|
+
tau_scale = 2.5;
|
|
119
|
+
eta = -0.3;
|
|
120
|
+
old_val = root_plus_old(g2, p2, mu2, r2, nm, tau_scale, eta);
|
|
121
|
+
new_val = root_plus_new(g2, p2, mu2, r2, nm, tau_scale, eta);
|
|
122
|
+
err = ABS(old_val - new_val);
|
|
123
|
+
scs_printf("root_plus case 2: old=%.12e new=%.12e err=%.2e\n",
|
|
124
|
+
old_val, new_val, err);
|
|
125
|
+
mu_assert("root_plus case 2 mismatch", err < 1e-12 * MAX(ABS(old_val), 1.));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/* Test case 3: large tau_scale dominates */
|
|
129
|
+
{
|
|
130
|
+
scs_float g3[] = {0.01, -0.02};
|
|
131
|
+
scs_float p3[] = {100.0, -50.0};
|
|
132
|
+
scs_float mu3[] = {200.0, 300.0};
|
|
133
|
+
scs_float r3[] = {1.0, 1.0};
|
|
134
|
+
nm = 2;
|
|
135
|
+
tau_scale = 1e6;
|
|
136
|
+
eta = 1.0;
|
|
137
|
+
old_val = root_plus_old(g3, p3, mu3, r3, nm, tau_scale, eta);
|
|
138
|
+
new_val = root_plus_new(g3, p3, mu3, r3, nm, tau_scale, eta);
|
|
139
|
+
err = ABS(old_val - new_val);
|
|
140
|
+
scs_printf("root_plus case 3: old=%.12e new=%.12e err=%.2e\n",
|
|
141
|
+
old_val, new_val, err);
|
|
142
|
+
mu_assert("root_plus case 3 mismatch", err < 1e-10 * MAX(ABS(old_val), 1.));
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/* Test case 4: near-zero discriminant */
|
|
146
|
+
{
|
|
147
|
+
scs_float g4[] = {1.0, 0.0, 0.0, 0.0, 0.0};
|
|
148
|
+
scs_float p4[] = {0.0, 0.0, 0.0, 0.0, 0.0};
|
|
149
|
+
scs_float mu4[] = {0.0, 0.0, 0.0, 0.0, 0.0};
|
|
150
|
+
scs_float r4[] = {1.0, 1.0, 1.0, 1.0, 1.0};
|
|
151
|
+
nm = 5;
|
|
152
|
+
tau_scale = 1.0;
|
|
153
|
+
eta = 0.0;
|
|
154
|
+
old_val = root_plus_old(g4, p4, mu4, r4, nm, tau_scale, eta);
|
|
155
|
+
new_val = root_plus_new(g4, p4, mu4, r4, nm, tau_scale, eta);
|
|
156
|
+
err = ABS(old_val - new_val);
|
|
157
|
+
scs_printf("root_plus case 4: old=%.12e new=%.12e err=%.2e\n",
|
|
158
|
+
old_val, new_val, err);
|
|
159
|
+
mu_assert("root_plus case 4 mismatch", err < 1e-14);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/* Test case 5: varying r weights spanning orders of magnitude */
|
|
163
|
+
{
|
|
164
|
+
scs_float g5[] = {0.5, -1.3, 2.1, -0.7, 0.9, 1.1};
|
|
165
|
+
scs_float p5[] = {-0.2, 0.8, -1.5, 0.4, -0.6, 1.0};
|
|
166
|
+
scs_float mu5[] = {0.3, -0.9, 0.6, 1.2, -0.8, 0.1};
|
|
167
|
+
scs_float r5[] = {1e-4, 1e-2, 1.0, 1e2, 1e4, 1e6};
|
|
168
|
+
nm = 6;
|
|
169
|
+
tau_scale = 0.01;
|
|
170
|
+
eta = 2.0;
|
|
171
|
+
old_val = root_plus_old(g5, p5, mu5, r5, nm, tau_scale, eta);
|
|
172
|
+
new_val = root_plus_new(g5, p5, mu5, r5, nm, tau_scale, eta);
|
|
173
|
+
err = ABS(old_val - new_val);
|
|
174
|
+
scs_printf("root_plus case 5: old=%.12e new=%.12e err=%.2e\n",
|
|
175
|
+
old_val, new_val, err);
|
|
176
|
+
mu_assert("root_plus case 5 mismatch", err < 1e-10 * MAX(ABS(old_val), 1.));
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/* Test case 6: cancellation-prone direct formula */
|
|
180
|
+
{
|
|
181
|
+
scs_float stable_val, expected;
|
|
182
|
+
stable_val = root_plus_stable_coeffs(1., 1e8, 1.);
|
|
183
|
+
expected = -1e-8;
|
|
184
|
+
err = ABS(stable_val - expected);
|
|
185
|
+
scs_printf("root_plus case 6: stable=%.12e expected=%.12e err=%.2e\n",
|
|
186
|
+
stable_val, expected, err);
|
|
187
|
+
mu_assert("root_plus case 6 cancellation", err < 1e-14);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return 0;
|
|
191
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
#include <stdint.h>
|
|
2
|
+
#include <string.h>
|
|
3
|
+
|
|
4
|
+
#include "cones.h"
|
|
5
|
+
#include "glbopts.h"
|
|
6
|
+
#include "minunit.h"
|
|
7
|
+
#include "rw.h"
|
|
8
|
+
#include "scs.h"
|
|
9
|
+
#include "util.h"
|
|
10
|
+
|
|
11
|
+
/* Round-trip nondefault settings through write_data/read_data, then
|
|
12
|
+
* verify the reader is robust to files stamped by OTHER 3.3.x builds:
|
|
13
|
+
* the settings-block layout is keyed off a numeric version comparison
|
|
14
|
+
* (>= 3.3.0), not exact string equality, and the extension section
|
|
15
|
+
* carries its own schema version. */
|
|
16
|
+
|
|
17
|
+
static const char *test_rw_settings(void) {
|
|
18
|
+
ScsCone *k = (ScsCone *)scs_calloc(1, sizeof(ScsCone));
|
|
19
|
+
ScsData *d = (ScsData *)scs_calloc(1, sizeof(ScsData));
|
|
20
|
+
ScsSettings *stgs = (ScsSettings *)scs_calloc(1, sizeof(ScsSettings));
|
|
21
|
+
ScsCone *k2 = SCS_NULL;
|
|
22
|
+
ScsData *d2 = SCS_NULL;
|
|
23
|
+
ScsSettings *stgs2 = SCS_NULL;
|
|
24
|
+
const char *fname = "test_rw_settings_data";
|
|
25
|
+
scs_int pass;
|
|
26
|
+
|
|
27
|
+
/* tiny LP: 1 var, 1 nonneg row */
|
|
28
|
+
scs_float Ax[1] = {1.0};
|
|
29
|
+
scs_int Ai[1] = {0};
|
|
30
|
+
scs_int Ap[2] = {0, 1};
|
|
31
|
+
scs_float b[1] = {1.0};
|
|
32
|
+
scs_float c[1] = {1.0};
|
|
33
|
+
ScsMatrix A = {Ax, Ai, Ap, 1, 1};
|
|
34
|
+
d->m = 1;
|
|
35
|
+
d->n = 1;
|
|
36
|
+
d->A = &A;
|
|
37
|
+
d->b = b;
|
|
38
|
+
d->c = c;
|
|
39
|
+
k->l = 1;
|
|
40
|
+
|
|
41
|
+
scs_set_default_settings(stgs);
|
|
42
|
+
/* nondefaults across both layout regions and the extension section */
|
|
43
|
+
stgs->adaptive_diag_scale = 0; /* v2 extension field */
|
|
44
|
+
stgs->time_limit_secs = 123.5; /* v1 extension field */
|
|
45
|
+
stgs->acceleration_type_1 = 0; /* post-3.3.0 stgs-block field */
|
|
46
|
+
stgs->acceleration_regularization = 3e-9;
|
|
47
|
+
stgs->eps_abs = 2.5e-7;
|
|
48
|
+
stgs->write_data_filename = fname;
|
|
49
|
+
|
|
50
|
+
SCS(write_data)(d, k, stgs);
|
|
51
|
+
|
|
52
|
+
mu_assert("rw_settings: read failed",
|
|
53
|
+
SCS(read_data)(fname, &d2, &k2, &stgs2) == 0);
|
|
54
|
+
/* Binary serialization preserves the stored values exactly in either
|
|
55
|
+
* precision; comparing against double literals would fail with SFLOAT. */
|
|
56
|
+
pass = stgs2->adaptive_diag_scale == stgs->adaptive_diag_scale &&
|
|
57
|
+
stgs2->time_limit_secs == stgs->time_limit_secs &&
|
|
58
|
+
stgs2->acceleration_type_1 == stgs->acceleration_type_1 &&
|
|
59
|
+
stgs2->acceleration_regularization == stgs->acceleration_regularization &&
|
|
60
|
+
stgs2->eps_abs == stgs->eps_abs;
|
|
61
|
+
mu_assert("rw_settings: nondefault round-trip lost a setting", pass);
|
|
62
|
+
SCS(free_data)(d2);
|
|
63
|
+
SCS(free_cone)(k2);
|
|
64
|
+
scs_free(stgs2);
|
|
65
|
+
d2 = SCS_NULL;
|
|
66
|
+
k2 = SCS_NULL;
|
|
67
|
+
stgs2 = SCS_NULL;
|
|
68
|
+
|
|
69
|
+
/* Patch the embedded version string to an adjacent 3.3.x build (3.3.9,
|
|
70
|
+
* padded) and re-read: everything must still parse, since the settings
|
|
71
|
+
* layout is keyed off the numeric major.minor, not the exact string. */
|
|
72
|
+
{
|
|
73
|
+
FILE *f = fopen(fname, "r+b");
|
|
74
|
+
long pos = 2 * (long)sizeof(uint32_t); /* int_sz, float_sz */
|
|
75
|
+
uint32_t ver_len;
|
|
76
|
+
char patched[16];
|
|
77
|
+
mu_assert("rw_settings: reopen failed", f != SCS_NULL);
|
|
78
|
+
fseek(f, pos, SEEK_SET);
|
|
79
|
+
mu_assert("rw_settings: read ver len",
|
|
80
|
+
fread(&ver_len, sizeof(uint32_t), 1, f) == 1);
|
|
81
|
+
mu_assert("rw_settings: unexpected version length",
|
|
82
|
+
ver_len >= 5 && ver_len < 16);
|
|
83
|
+
/* C requires a positioning call between a read and a write on an
|
|
84
|
+
* update stream; Windows enforces it. */
|
|
85
|
+
fseek(f, 0, SEEK_CUR);
|
|
86
|
+
memset(patched, '9', ver_len); /* "3.3.99...": an adjacent 3.3.x */
|
|
87
|
+
patched[0] = '3';
|
|
88
|
+
patched[1] = '.';
|
|
89
|
+
patched[2] = '3';
|
|
90
|
+
patched[3] = '.';
|
|
91
|
+
mu_assert("rw_settings: patch write",
|
|
92
|
+
fwrite(patched, 1, ver_len, f) == ver_len);
|
|
93
|
+
fclose(f);
|
|
94
|
+
}
|
|
95
|
+
mu_assert("rw_settings: adjacent-version read failed",
|
|
96
|
+
SCS(read_data)(fname, &d2, &k2, &stgs2) == 0);
|
|
97
|
+
pass = stgs2->adaptive_diag_scale == stgs->adaptive_diag_scale &&
|
|
98
|
+
stgs2->time_limit_secs == stgs->time_limit_secs &&
|
|
99
|
+
stgs2->acceleration_type_1 == stgs->acceleration_type_1 &&
|
|
100
|
+
stgs2->acceleration_regularization == stgs->acceleration_regularization &&
|
|
101
|
+
stgs2->eps_abs == stgs->eps_abs;
|
|
102
|
+
mu_assert("rw_settings: adjacent-version read lost a setting", pass);
|
|
103
|
+
SCS(free_data)(d2);
|
|
104
|
+
SCS(free_cone)(k2);
|
|
105
|
+
scs_free(stgs2);
|
|
106
|
+
|
|
107
|
+
remove(fname);
|
|
108
|
+
scs_free(stgs);
|
|
109
|
+
scs_free(d);
|
|
110
|
+
scs_free(k);
|
|
111
|
+
return 0;
|
|
112
|
+
}
|
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
#include "glbopts.h"
|
|
2
|
+
#include "linalg.h"
|
|
3
|
+
#include "minunit.h"
|
|
4
|
+
#include "problem_utils.h"
|
|
5
|
+
#include "scs.h"
|
|
6
|
+
#include "util.h"
|
|
7
|
+
|
|
8
|
+
/*
|
|
9
|
+
* SOC size-1 test: proj_soc with q=1 reduces to x[0] = MAX(x[0], 0), i.e.
|
|
10
|
+
* the non-negative orthant for a single scalar.
|
|
11
|
+
* Problem: min t s.t. t in SOC_1 (t >= 0), t = 1.5
|
|
12
|
+
* Optimal: t = 1.5, obj = 1.5.
|
|
13
|
+
*
|
|
14
|
+
* Variables [t] (n=1), m=2:
|
|
15
|
+
* Row 0 (zero): t = 1.5 -> A[0,0]=1, b[0]=1.5
|
|
16
|
+
* Row 1 (SOC_1): s[1] = t -> A[1,0]=-1, b[1]=0
|
|
17
|
+
*/
|
|
18
|
+
static const char *test_soc_size1(void) {
|
|
19
|
+
ScsCone *k = (ScsCone *)scs_calloc(1, sizeof(ScsCone));
|
|
20
|
+
ScsData *d = (ScsData *)scs_calloc(1, sizeof(ScsData));
|
|
21
|
+
ScsSettings *stgs = (ScsSettings *)scs_calloc(1, sizeof(ScsSettings));
|
|
22
|
+
ScsSolution *sol = (ScsSolution *)scs_calloc(1, sizeof(ScsSolution));
|
|
23
|
+
ScsInfo info = {0};
|
|
24
|
+
scs_int exitflag;
|
|
25
|
+
scs_float perr, derr;
|
|
26
|
+
scs_int success;
|
|
27
|
+
const char *fail;
|
|
28
|
+
|
|
29
|
+
scs_float opt = 1.5;
|
|
30
|
+
|
|
31
|
+
scs_float Ax[] = {1.0, -1.0};
|
|
32
|
+
scs_int Ai[] = {0, 1};
|
|
33
|
+
scs_int Ap[] = {0, 2};
|
|
34
|
+
|
|
35
|
+
scs_float b[] = {1.5, 0.0};
|
|
36
|
+
scs_float c[] = {1.0};
|
|
37
|
+
|
|
38
|
+
scs_int q[] = {1};
|
|
39
|
+
scs_int m = 2, n = 1;
|
|
40
|
+
|
|
41
|
+
d->m = m;
|
|
42
|
+
d->n = n;
|
|
43
|
+
d->b = b;
|
|
44
|
+
d->c = c;
|
|
45
|
+
|
|
46
|
+
d->A = (ScsMatrix *)scs_calloc(1, sizeof(ScsMatrix));
|
|
47
|
+
d->A->m = m;
|
|
48
|
+
d->A->n = n;
|
|
49
|
+
d->A->x = Ax;
|
|
50
|
+
d->A->i = Ai;
|
|
51
|
+
d->A->p = Ap;
|
|
52
|
+
|
|
53
|
+
k->z = 1;
|
|
54
|
+
k->qsize = 1;
|
|
55
|
+
k->q = q;
|
|
56
|
+
|
|
57
|
+
scs_set_default_settings(stgs);
|
|
58
|
+
stgs->eps_abs = 1e-6;
|
|
59
|
+
stgs->eps_rel = 1e-6;
|
|
60
|
+
|
|
61
|
+
exitflag = scs(d, k, stgs, sol, &info);
|
|
62
|
+
|
|
63
|
+
perr = info.pobj - opt;
|
|
64
|
+
derr = info.dobj - opt;
|
|
65
|
+
|
|
66
|
+
scs_printf("primal obj error %4e\n", perr);
|
|
67
|
+
scs_printf("dual obj error %4e\n", derr);
|
|
68
|
+
|
|
69
|
+
success = ABS(perr) < 1e-4 && ABS(derr) < 1e-4 && exitflag == SCS_SOLVED;
|
|
70
|
+
mu_assert("test_soc_size1: SCS failed to produce SCS_SOLVED", success);
|
|
71
|
+
fail = verify_solution_correct(d, k, stgs, &info, sol, exitflag);
|
|
72
|
+
|
|
73
|
+
SCS(free_sol)(sol);
|
|
74
|
+
scs_free(d->A);
|
|
75
|
+
scs_free(k);
|
|
76
|
+
scs_free(stgs);
|
|
77
|
+
scs_free(d);
|
|
78
|
+
return fail;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/*
|
|
82
|
+
* SOC size-2 test: exercises the q=2 fast path in proj_soc.
|
|
83
|
+
* min t s.t. (t, x) in SOC_2 (t >= |x|), x = 1.5
|
|
84
|
+
* Optimal: t = 1.5, obj = 1.5.
|
|
85
|
+
*
|
|
86
|
+
* Variables [t, x] (n=2), m=3:
|
|
87
|
+
* Row 0 (zero): x = 1.5 → A[0,1]=1, b[0]=1.5
|
|
88
|
+
* Rows 1-2 (SOC_2): s[1:3] = (t, x) in SOC_2
|
|
89
|
+
* row 1: -t+s1=0 → s1=t
|
|
90
|
+
* row 2: -x+s2=0 → s2=x
|
|
91
|
+
*/
|
|
92
|
+
static const char *test_soc_size2(void) {
|
|
93
|
+
ScsCone *k = (ScsCone *)scs_calloc(1, sizeof(ScsCone));
|
|
94
|
+
ScsData *d = (ScsData *)scs_calloc(1, sizeof(ScsData));
|
|
95
|
+
ScsSettings *stgs = (ScsSettings *)scs_calloc(1, sizeof(ScsSettings));
|
|
96
|
+
ScsSolution *sol = (ScsSolution *)scs_calloc(1, sizeof(ScsSolution));
|
|
97
|
+
ScsInfo info = {0};
|
|
98
|
+
scs_int exitflag;
|
|
99
|
+
scs_float perr, derr;
|
|
100
|
+
scs_int success;
|
|
101
|
+
const char *fail;
|
|
102
|
+
|
|
103
|
+
scs_float opt = 1.5;
|
|
104
|
+
|
|
105
|
+
scs_float Ax[] = {-1.0, 1.0, -1.0};
|
|
106
|
+
scs_int Ai[] = {1, 0, 2};
|
|
107
|
+
scs_int Ap[] = {0, 1, 3};
|
|
108
|
+
|
|
109
|
+
scs_float b[] = {1.5, 0.0, 0.0};
|
|
110
|
+
scs_float c[] = {1.0, 0.0};
|
|
111
|
+
|
|
112
|
+
scs_int q[] = {2};
|
|
113
|
+
scs_int m = 3, n = 2;
|
|
114
|
+
|
|
115
|
+
d->m = m;
|
|
116
|
+
d->n = n;
|
|
117
|
+
d->b = b;
|
|
118
|
+
d->c = c;
|
|
119
|
+
|
|
120
|
+
d->A = (ScsMatrix *)scs_calloc(1, sizeof(ScsMatrix));
|
|
121
|
+
d->A->m = m;
|
|
122
|
+
d->A->n = n;
|
|
123
|
+
d->A->x = Ax;
|
|
124
|
+
d->A->i = Ai;
|
|
125
|
+
d->A->p = Ap;
|
|
126
|
+
|
|
127
|
+
k->z = 1;
|
|
128
|
+
k->qsize = 1;
|
|
129
|
+
k->q = q;
|
|
130
|
+
|
|
131
|
+
scs_set_default_settings(stgs);
|
|
132
|
+
stgs->eps_abs = 1e-6;
|
|
133
|
+
stgs->eps_rel = 1e-6;
|
|
134
|
+
|
|
135
|
+
exitflag = scs(d, k, stgs, sol, &info);
|
|
136
|
+
|
|
137
|
+
perr = info.pobj - opt;
|
|
138
|
+
derr = info.dobj - opt;
|
|
139
|
+
|
|
140
|
+
scs_printf("primal obj error %4e\n", perr);
|
|
141
|
+
scs_printf("dual obj error %4e\n", derr);
|
|
142
|
+
|
|
143
|
+
success = ABS(perr) < 1e-4 && ABS(derr) < 1e-4 && exitflag == SCS_SOLVED;
|
|
144
|
+
mu_assert("test_soc_size2: SCS failed to produce SCS_SOLVED", success);
|
|
145
|
+
fail = verify_solution_correct(d, k, stgs, &info, sol, exitflag);
|
|
146
|
+
|
|
147
|
+
SCS(free_sol)(sol);
|
|
148
|
+
scs_free(d->A);
|
|
149
|
+
scs_free(k);
|
|
150
|
+
scs_free(stgs);
|
|
151
|
+
scs_free(d);
|
|
152
|
+
return fail;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/*
|
|
156
|
+
* SOC size-3 test: exercises the q=3 fast path in proj_soc.
|
|
157
|
+
* min t s.t. (t, x1, x2) in SOC_3 (t >= sqrt(x1^2+x2^2)),
|
|
158
|
+
* x1 = 1, x2 = 2
|
|
159
|
+
* Optimal: t = sqrt(5), obj = sqrt(5).
|
|
160
|
+
*
|
|
161
|
+
* Variables [t, x1, x2] (n=3), m=5:
|
|
162
|
+
* Row 0 (zero): x1 = 1 → A[0,1]=1, b[0]=1
|
|
163
|
+
* Row 1 (zero): x2 = 2 → A[1,2]=1, b[1]=2
|
|
164
|
+
* Rows 2-4 (SOC_3): s[2:5] = (t,x1,x2) in SOC_3
|
|
165
|
+
* row 2: -t+s2=0, row 3: -x1+s3=0, row 4: -x2+s4=0
|
|
166
|
+
*/
|
|
167
|
+
static const char *test_soc_size3(void) {
|
|
168
|
+
ScsCone *k = (ScsCone *)scs_calloc(1, sizeof(ScsCone));
|
|
169
|
+
ScsData *d = (ScsData *)scs_calloc(1, sizeof(ScsData));
|
|
170
|
+
ScsSettings *stgs = (ScsSettings *)scs_calloc(1, sizeof(ScsSettings));
|
|
171
|
+
ScsSolution *sol = (ScsSolution *)scs_calloc(1, sizeof(ScsSolution));
|
|
172
|
+
ScsInfo info = {0};
|
|
173
|
+
scs_int exitflag;
|
|
174
|
+
scs_float perr, derr;
|
|
175
|
+
scs_int success;
|
|
176
|
+
const char *fail;
|
|
177
|
+
|
|
178
|
+
scs_float opt = 2.2360679774997896; /* sqrt(5) */
|
|
179
|
+
|
|
180
|
+
scs_float Ax[] = {-1.0, 1.0, -1.0, 1.0, -1.0};
|
|
181
|
+
scs_int Ai[] = {2, 0, 3, 1, 4};
|
|
182
|
+
scs_int Ap[] = {0, 1, 3, 5};
|
|
183
|
+
|
|
184
|
+
scs_float b[] = {1.0, 2.0, 0.0, 0.0, 0.0};
|
|
185
|
+
scs_float c[] = {1.0, 0.0, 0.0};
|
|
186
|
+
|
|
187
|
+
scs_int q[] = {3};
|
|
188
|
+
scs_int m = 5, n = 3;
|
|
189
|
+
|
|
190
|
+
d->m = m;
|
|
191
|
+
d->n = n;
|
|
192
|
+
d->b = b;
|
|
193
|
+
d->c = c;
|
|
194
|
+
|
|
195
|
+
d->A = (ScsMatrix *)scs_calloc(1, sizeof(ScsMatrix));
|
|
196
|
+
d->A->m = m;
|
|
197
|
+
d->A->n = n;
|
|
198
|
+
d->A->x = Ax;
|
|
199
|
+
d->A->i = Ai;
|
|
200
|
+
d->A->p = Ap;
|
|
201
|
+
|
|
202
|
+
k->z = 2;
|
|
203
|
+
k->qsize = 1;
|
|
204
|
+
k->q = q;
|
|
205
|
+
|
|
206
|
+
scs_set_default_settings(stgs);
|
|
207
|
+
stgs->eps_abs = 1e-6;
|
|
208
|
+
stgs->eps_rel = 1e-6;
|
|
209
|
+
|
|
210
|
+
exitflag = scs(d, k, stgs, sol, &info);
|
|
211
|
+
|
|
212
|
+
perr = info.pobj - opt;
|
|
213
|
+
derr = info.dobj - opt;
|
|
214
|
+
|
|
215
|
+
scs_printf("primal obj error %4e\n", perr);
|
|
216
|
+
scs_printf("dual obj error %4e\n", derr);
|
|
217
|
+
|
|
218
|
+
success = ABS(perr) < 1e-4 && ABS(derr) < 1e-4 && exitflag == SCS_SOLVED;
|
|
219
|
+
mu_assert("test_soc_size3: SCS failed to produce SCS_SOLVED", success);
|
|
220
|
+
fail = verify_solution_correct(d, k, stgs, &info, sol, exitflag);
|
|
221
|
+
|
|
222
|
+
SCS(free_sol)(sol);
|
|
223
|
+
scs_free(d->A);
|
|
224
|
+
scs_free(k);
|
|
225
|
+
scs_free(stgs);
|
|
226
|
+
scs_free(d);
|
|
227
|
+
return fail;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/*
|
|
231
|
+
* SOC size-5 test: exercises the general (q>3) code path in proj_soc.
|
|
232
|
+
* min t s.t. (t, x1, x2, x3, x4) in SOC_5 (t >= ||(x1..x4)||),
|
|
233
|
+
* xi = 1 for i=1..4.
|
|
234
|
+
* Optimal: t = sqrt(4) = 2, obj = 2.
|
|
235
|
+
*
|
|
236
|
+
* Variables [t, x1, x2, x3, x4] (n=5), m=9:
|
|
237
|
+
* Rows 0-3 (zero, 4 equalities): xi = 1
|
|
238
|
+
* Rows 4-8 (SOC_5): (t, x1, ..., x4) in SOC_5
|
|
239
|
+
*
|
|
240
|
+
* A cols (CSC):
|
|
241
|
+
* col 0 (t): row 4 -> -1
|
|
242
|
+
* col 1 (x1): row 0 -> +1, row 5 -> -1
|
|
243
|
+
* col 2 (x2): row 1 -> +1, row 6 -> -1
|
|
244
|
+
* col 3 (x3): row 2 -> +1, row 7 -> -1
|
|
245
|
+
* col 4 (x4): row 3 -> +1, row 8 -> -1
|
|
246
|
+
*/
|
|
247
|
+
static const char *test_soc_size5(void) {
|
|
248
|
+
ScsCone *k = (ScsCone *)scs_calloc(1, sizeof(ScsCone));
|
|
249
|
+
ScsData *d = (ScsData *)scs_calloc(1, sizeof(ScsData));
|
|
250
|
+
ScsSettings *stgs = (ScsSettings *)scs_calloc(1, sizeof(ScsSettings));
|
|
251
|
+
ScsSolution *sol = (ScsSolution *)scs_calloc(1, sizeof(ScsSolution));
|
|
252
|
+
ScsInfo info = {0};
|
|
253
|
+
scs_int exitflag;
|
|
254
|
+
scs_float perr, derr;
|
|
255
|
+
scs_int success;
|
|
256
|
+
const char *fail;
|
|
257
|
+
|
|
258
|
+
scs_float opt = 2.0; /* sqrt(1^2 + 1^2 + 1^2 + 1^2) = 2 */
|
|
259
|
+
|
|
260
|
+
scs_float Ax5[] = {-1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0};
|
|
261
|
+
scs_int Ai5[] = {4, 0, 5, 1, 6, 2, 7, 3, 8};
|
|
262
|
+
scs_int Ap5[] = {0, 1, 3, 5, 7, 9};
|
|
263
|
+
|
|
264
|
+
scs_float b5[] = {1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0};
|
|
265
|
+
scs_float c5[] = {1.0, 0.0, 0.0, 0.0, 0.0};
|
|
266
|
+
|
|
267
|
+
scs_int q5[] = {5};
|
|
268
|
+
scs_int m = 9, n = 5;
|
|
269
|
+
|
|
270
|
+
d->m = m;
|
|
271
|
+
d->n = n;
|
|
272
|
+
d->b = b5;
|
|
273
|
+
d->c = c5;
|
|
274
|
+
|
|
275
|
+
d->A = (ScsMatrix *)scs_calloc(1, sizeof(ScsMatrix));
|
|
276
|
+
d->A->m = m;
|
|
277
|
+
d->A->n = n;
|
|
278
|
+
d->A->x = Ax5;
|
|
279
|
+
d->A->i = Ai5;
|
|
280
|
+
d->A->p = Ap5;
|
|
281
|
+
|
|
282
|
+
k->z = 4;
|
|
283
|
+
k->qsize = 1;
|
|
284
|
+
k->q = q5;
|
|
285
|
+
|
|
286
|
+
scs_set_default_settings(stgs);
|
|
287
|
+
stgs->eps_abs = 1e-6;
|
|
288
|
+
stgs->eps_rel = 1e-6;
|
|
289
|
+
|
|
290
|
+
exitflag = scs(d, k, stgs, sol, &info);
|
|
291
|
+
|
|
292
|
+
perr = info.pobj - opt;
|
|
293
|
+
derr = info.dobj - opt;
|
|
294
|
+
|
|
295
|
+
scs_printf("primal obj error %4e\n", perr);
|
|
296
|
+
scs_printf("dual obj error %4e\n", derr);
|
|
297
|
+
|
|
298
|
+
success = ABS(perr) < 1e-4 && ABS(derr) < 1e-4 && exitflag == SCS_SOLVED;
|
|
299
|
+
mu_assert("test_soc_size5: SCS failed to produce SCS_SOLVED", success);
|
|
300
|
+
fail = verify_solution_correct(d, k, stgs, &info, sol, exitflag);
|
|
301
|
+
|
|
302
|
+
SCS(free_sol)(sol);
|
|
303
|
+
scs_free(d->A);
|
|
304
|
+
scs_free(k);
|
|
305
|
+
scs_free(stgs);
|
|
306
|
+
scs_free(d);
|
|
307
|
+
return fail;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/*
|
|
311
|
+
* Multiple SOC cones test (qsize=2): exercises the loop over k->qsize in
|
|
312
|
+
* proj_cones.
|
|
313
|
+
*
|
|
314
|
+
* Problem: minimize t1 + t2
|
|
315
|
+
* subject to (t1, x1, x2) in SOC_3 (t1 >= sqrt(x1^2+x2^2))
|
|
316
|
+
* (t2, x3) in SOC_2 (t2 >= |x3|)
|
|
317
|
+
* x1=1, x2=1, x3=2
|
|
318
|
+
* Optimal: t1* = sqrt(2), t2* = 2, obj* = sqrt(2)+2 ~= 3.41421.
|
|
319
|
+
*
|
|
320
|
+
* Variables [t1, x1, x2, t2, x3] (n=5), m=8:
|
|
321
|
+
* Rows 0-2 (z=3): x1=1, x2=1, x3=2
|
|
322
|
+
* Rows 3-5 (SOC_3): (t1, x1, x2)
|
|
323
|
+
* Rows 6-7 (SOC_2): (t2, x3)
|
|
324
|
+
*
|
|
325
|
+
* A cols (CSC):
|
|
326
|
+
* col 0 (t1): row 3 -> -1
|
|
327
|
+
* col 1 (x1): row 0 -> +1, row 4 -> -1
|
|
328
|
+
* col 2 (x2): row 1 -> +1, row 5 -> -1
|
|
329
|
+
* col 3 (t2): row 6 -> -1
|
|
330
|
+
* col 4 (x3): row 2 -> +1, row 7 -> -1
|
|
331
|
+
*/
|
|
332
|
+
static const char *test_multi_soc(void) {
|
|
333
|
+
ScsCone *k = (ScsCone *)scs_calloc(1, sizeof(ScsCone));
|
|
334
|
+
ScsData *d = (ScsData *)scs_calloc(1, sizeof(ScsData));
|
|
335
|
+
ScsSettings *stgs = (ScsSettings *)scs_calloc(1, sizeof(ScsSettings));
|
|
336
|
+
ScsSolution *sol = (ScsSolution *)scs_calloc(1, sizeof(ScsSolution));
|
|
337
|
+
ScsInfo info = {0};
|
|
338
|
+
scs_int exitflag;
|
|
339
|
+
scs_float perr, derr;
|
|
340
|
+
scs_int success;
|
|
341
|
+
const char *fail;
|
|
342
|
+
|
|
343
|
+
scs_float opt = 3.41421356237309504; /* sqrt(2) + 2 */
|
|
344
|
+
|
|
345
|
+
scs_float Axm[] = {-1.0, 1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0};
|
|
346
|
+
scs_int Aim[] = {3, 0, 4, 1, 5, 6, 2, 7};
|
|
347
|
+
scs_int Apm[] = {0, 1, 3, 5, 6, 8};
|
|
348
|
+
|
|
349
|
+
scs_float bm[] = {1.0, 1.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0};
|
|
350
|
+
scs_float cm[] = {1.0, 0.0, 0.0, 1.0, 0.0};
|
|
351
|
+
|
|
352
|
+
scs_int qm[] = {3, 2};
|
|
353
|
+
scs_int m = 8, n = 5;
|
|
354
|
+
|
|
355
|
+
d->m = m;
|
|
356
|
+
d->n = n;
|
|
357
|
+
d->b = bm;
|
|
358
|
+
d->c = cm;
|
|
359
|
+
|
|
360
|
+
d->A = (ScsMatrix *)scs_calloc(1, sizeof(ScsMatrix));
|
|
361
|
+
d->A->m = m;
|
|
362
|
+
d->A->n = n;
|
|
363
|
+
d->A->x = Axm;
|
|
364
|
+
d->A->i = Aim;
|
|
365
|
+
d->A->p = Apm;
|
|
366
|
+
|
|
367
|
+
k->z = 3;
|
|
368
|
+
k->qsize = 2;
|
|
369
|
+
k->q = qm;
|
|
370
|
+
|
|
371
|
+
scs_set_default_settings(stgs);
|
|
372
|
+
stgs->eps_abs = 1e-6;
|
|
373
|
+
stgs->eps_rel = 1e-6;
|
|
374
|
+
|
|
375
|
+
exitflag = scs(d, k, stgs, sol, &info);
|
|
376
|
+
|
|
377
|
+
perr = info.pobj - opt;
|
|
378
|
+
derr = info.dobj - opt;
|
|
379
|
+
|
|
380
|
+
scs_printf("primal obj error %4e\n", perr);
|
|
381
|
+
scs_printf("dual obj error %4e\n", derr);
|
|
382
|
+
|
|
383
|
+
success = ABS(perr) < 1e-4 && ABS(derr) < 1e-4 && exitflag == SCS_SOLVED;
|
|
384
|
+
mu_assert("test_multi_soc: SCS failed to produce SCS_SOLVED", success);
|
|
385
|
+
fail = verify_solution_correct(d, k, stgs, &info, sol, exitflag);
|
|
386
|
+
|
|
387
|
+
SCS(free_sol)(sol);
|
|
388
|
+
scs_free(d->A);
|
|
389
|
+
scs_free(k);
|
|
390
|
+
scs_free(stgs);
|
|
391
|
+
scs_free(d);
|
|
392
|
+
return fail;
|
|
393
|
+
}
|