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.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -0
  3. data/LICENSE.txt +1 -1
  4. data/lib/scs/ffi.rb +18 -0
  5. data/lib/scs/version.rb +1 -1
  6. data/vendor/scs/CITATION.cff +2 -3
  7. data/vendor/scs/CLAUDE.md +115 -0
  8. data/vendor/scs/CMakeLists.txt +330 -201
  9. data/vendor/scs/CONTRIBUTING.md +49 -0
  10. data/vendor/scs/Makefile +90 -43
  11. data/vendor/scs/README.md +96 -2
  12. data/vendor/scs/include/aa.h +59 -11
  13. data/vendor/scs/include/aa_stats.h +47 -0
  14. data/vendor/scs/include/cones.h +16 -7
  15. data/vendor/scs/include/glbopts.h +113 -26
  16. data/vendor/scs/include/linalg.h +5 -1
  17. data/vendor/scs/include/linsys.h +1 -2
  18. data/vendor/scs/include/normalize.h +6 -2
  19. data/vendor/scs/include/rw.h +9 -3
  20. data/vendor/scs/include/scs.h +17 -1
  21. data/vendor/scs/include/scs_blas.h +8 -0
  22. data/vendor/scs/include/scs_types.h +2 -2
  23. data/vendor/scs/include/scs_work.h +22 -1
  24. data/vendor/scs/include/util.h +3 -6
  25. data/vendor/scs/include/util_spectral_cones.h +3 -3
  26. data/vendor/scs/linsys/accelerate/direct/private.c +126 -0
  27. data/vendor/scs/linsys/accelerate/direct/private.h +34 -0
  28. data/vendor/scs/linsys/cpu/dense/private.c +250 -0
  29. data/vendor/scs/linsys/cpu/dense/private.h +31 -0
  30. data/vendor/scs/linsys/cpu/direct/private.c +86 -44
  31. data/vendor/scs/linsys/cpu/indirect/private.c +647 -113
  32. data/vendor/scs/linsys/cpu/indirect/private.h +28 -0
  33. data/vendor/scs/linsys/csparse.c +9 -3
  34. data/vendor/scs/linsys/csparse.h +4 -2
  35. data/vendor/scs/linsys/cudss/direct/private.c +77 -43
  36. data/vendor/scs/linsys/cudss/direct/private.h +33 -7
  37. data/vendor/scs/linsys/gpu/indirect/private.c +6 -2
  38. data/vendor/scs/linsys/mkl/direct/private.c +63 -31
  39. data/vendor/scs/linsys/mkl/direct/private.h +0 -1
  40. data/vendor/scs/linsys/scs_matrix.c +291 -165
  41. data/vendor/scs/linsys/scs_matrix.h +7 -9
  42. data/vendor/scs/scs.mk +35 -13
  43. data/vendor/scs/src/aa.c +673 -166
  44. data/vendor/scs/src/cones.c +545 -223
  45. data/vendor/scs/src/ctrlc.c +59 -16
  46. data/vendor/scs/src/exp_cone.c +70 -50
  47. data/vendor/scs/src/linalg.c +21 -2
  48. data/vendor/scs/src/normalize.c +24 -26
  49. data/vendor/scs/src/rw.c +596 -124
  50. data/vendor/scs/src/scs.c +990 -513
  51. data/vendor/scs/src/spectral_cones/logdeterminant/log_cone_IPM.c +240 -187
  52. data/vendor/scs/src/spectral_cones/logdeterminant/log_cone_Newton.c +108 -85
  53. data/vendor/scs/src/spectral_cones/logdeterminant/log_cone_wrapper.c +62 -63
  54. data/vendor/scs/src/spectral_cones/logdeterminant/logdet_cone.c +85 -78
  55. data/vendor/scs/src/spectral_cones/nuclear/ell1_cone.c +92 -97
  56. data/vendor/scs/src/spectral_cones/nuclear/nuclear_cone.c +39 -28
  57. data/vendor/scs/src/spectral_cones/sum-largest/sum_largest_cone.c +59 -40
  58. data/vendor/scs/src/spectral_cones/sum-largest/sum_largest_eval_cone.c +37 -29
  59. data/vendor/scs/src/spectral_cones/util_spectral_cones.c +12 -6
  60. data/vendor/scs/src/util.c +37 -7
  61. data/vendor/scs/test/mkl_interface_mismatch.c +97 -0
  62. data/vendor/scs/test/packaging/CMakeLists.txt +21 -0
  63. data/vendor/scs/test/packaging/consume.c +50 -0
  64. data/vendor/scs/test/problem_utils.h +9 -2
  65. data/vendor/scs/test/problems/dense_qp.h +64 -0
  66. data/vendor/scs/test/problems/hs21_tiny_qp.h +6 -2
  67. data/vendor/scs/test/problems/hs21_tiny_qp_rw.h +10 -2
  68. data/vendor/scs/test/problems/infeasible_lp.h +66 -0
  69. data/vendor/scs/test/problems/infeasible_socp.h +75 -0
  70. data/vendor/scs/test/problems/lp_update.h +110 -0
  71. data/vendor/scs/test/problems/qafiro_tiny_qp.h +3 -1
  72. data/vendor/scs/test/problems/rob_gauss_cov_est.h +6 -3
  73. data/vendor/scs/test/problems/small_qp.h +5 -0
  74. data/vendor/scs/test/problems/test_box_cone.h +92 -0
  75. data/vendor/scs/test/problems/test_dual_exp_cone.h +96 -0
  76. data/vendor/scs/test/problems/test_inaccurate.h +212 -0
  77. data/vendor/scs/test/problems/test_mixed_cones.h +113 -0
  78. data/vendor/scs/test/problems/test_normalize_roundtrip.h +279 -0
  79. data/vendor/scs/test/problems/test_power_cone.h +414 -0
  80. data/vendor/scs/test/problems/test_psd_metric.h +109 -0
  81. data/vendor/scs/test/problems/test_psd_n1.h +84 -0
  82. data/vendor/scs/test/problems/test_root_plus.h +191 -0
  83. data/vendor/scs/test/problems/test_rw_settings.h +112 -0
  84. data/vendor/scs/test/problems/test_soc_sizes.h +393 -0
  85. data/vendor/scs/test/problems/test_solver_options.h +558 -0
  86. data/vendor/scs/test/problems/test_validation.h +263 -24
  87. data/vendor/scs/test/problems/test_zero_cone.h +81 -0
  88. data/vendor/scs/test/problems/unbounded_lp.h +66 -0
  89. data/vendor/scs/test/problems/unbounded_socp.h +71 -0
  90. data/vendor/scs/test/run_from_file.c +6 -0
  91. data/vendor/scs/test/run_tests.c +71 -0
  92. data/vendor/scs/test/rw_settings.c +7 -0
  93. data/vendor/scs/test/spectral_cones_problems/test_ell1_and_nuc.h +128 -0
  94. data/vendor/scs/test/spectral_cones_problems/test_ell1_cone.h +115 -0
  95. metadata +35 -3
@@ -0,0 +1,414 @@
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
+ * Power cone test: maximize t = (x1 * x2)^0.5 subject to x1 + x2 = 4.
10
+ * Equivalently: min -t s.t. (x1, x2, t) in K_pow(0.5), x1+x2=4.
11
+ * Optimal: x1 = x2 = 2, t = 2, obj = -2.
12
+ *
13
+ * SCS form: min c'v, Av + s = b, s in K
14
+ * Variables v = [x1, x2, t] (n=3), m=4
15
+ * Constraints:
16
+ * Row 0 (zero cone): x1 + x2 = 4
17
+ * Rows 1-3 (power): s[1:4] = (x1, x2, t) in K_pow(0.5)
18
+ *
19
+ * A cols (CSC):
20
+ * col 0 (x1): row 0 -> +1, row 1 -> -1
21
+ * col 1 (x2): row 0 -> +1, row 2 -> -1
22
+ * col 2 (t): row 3 -> -1
23
+ */
24
+ static const char *test_power_cone(void) {
25
+ ScsCone *k = (ScsCone *)scs_calloc(1, sizeof(ScsCone));
26
+ ScsData *d = (ScsData *)scs_calloc(1, sizeof(ScsData));
27
+ ScsSettings *stgs = (ScsSettings *)scs_calloc(1, sizeof(ScsSettings));
28
+ ScsSolution *sol = (ScsSolution *)scs_calloc(1, sizeof(ScsSolution));
29
+ ScsInfo info = {0};
30
+ scs_int exitflag;
31
+ scs_float perr, derr;
32
+ scs_int success;
33
+ const char *fail;
34
+
35
+ scs_float opt = -2.0;
36
+
37
+ scs_float Ax[] = {1.0, -1.0, 1.0, -1.0, -1.0};
38
+ scs_int Ai[] = {0, 1, 0, 2, 3};
39
+ scs_int Ap[] = {0, 2, 4, 5};
40
+
41
+ scs_float b[] = {4.0, 0.0, 0.0, 0.0};
42
+ scs_float c[] = {0.0, 0.0, -1.0};
43
+
44
+ scs_float p[] = {0.5};
45
+
46
+ scs_int m = 4, n = 3;
47
+
48
+ d->m = m;
49
+ d->n = n;
50
+ d->b = b;
51
+ d->c = c;
52
+
53
+ d->A = (ScsMatrix *)scs_calloc(1, sizeof(ScsMatrix));
54
+ d->A->m = m;
55
+ d->A->n = n;
56
+ d->A->x = Ax;
57
+ d->A->i = Ai;
58
+ d->A->p = Ap;
59
+
60
+ k->z = 1;
61
+ k->psize = 1;
62
+ k->p = p;
63
+
64
+ scs_set_default_settings(stgs);
65
+ stgs->eps_abs = 1e-6;
66
+ stgs->eps_rel = 1e-6;
67
+
68
+ exitflag = scs(d, k, stgs, sol, &info);
69
+
70
+ perr = info.pobj - opt;
71
+ derr = info.dobj - opt;
72
+
73
+ scs_printf("primal obj error %4e\n", perr);
74
+ scs_printf("dual obj error %4e\n", derr);
75
+
76
+ success = ABS(perr) < 1e-4 && ABS(derr) < 1e-4 && exitflag == SCS_SOLVED;
77
+ mu_assert("test_power_cone: SCS failed to produce SCS_SOLVED", success);
78
+ fail = verify_solution_correct(d, k, stgs, &info, sol, exitflag);
79
+
80
+ /* warm start */
81
+ stgs->warm_start = 1;
82
+ exitflag = scs(d, k, stgs, sol, &info);
83
+ mu_assert("test_power_cone: warm-start failure", info.iter <= 25);
84
+ success = ABS(info.pobj - opt) < 1e-4 && exitflag == SCS_SOLVED;
85
+ mu_assert("test_power_cone: SCS warm-start failed", success);
86
+
87
+ SCS(free_sol)(sol);
88
+ scs_free(d->A);
89
+ scs_free(k);
90
+ scs_free(stgs);
91
+ scs_free(d);
92
+ return fail;
93
+ }
94
+
95
+ /*
96
+ * Power cone test with p=0.9: exercises a non-symmetric power parameter.
97
+ * Problem: maximize t = x^0.9 * y^0.1 s.t. x = 1, y = 1.
98
+ * K_pow(0.9): x^0.9 * y^0.1 >= |t|, x,y >= 0.
99
+ * Optimal: t* = 1^0.9 * 1^0.1 = 1, obj = -1.
100
+ *
101
+ * Variables [x, y, t] (n=3), m=5:
102
+ * Row 0 (zero): x = 1 -> A[0,0]=1, b[0]=1
103
+ * Row 1 (zero): y = 1 -> A[1,1]=1, b[1]=1
104
+ * Rows 2-4 (power p=0.9): (x, y, t) in K_pow(0.9)
105
+ *
106
+ * A cols (CSC):
107
+ * col 0 (x): row 0 -> +1, row 2 -> -1
108
+ * col 1 (y): row 1 -> +1, row 3 -> -1
109
+ * col 2 (t): row 4 -> -1
110
+ */
111
+ static const char *test_power_cone_p09(void) {
112
+ ScsCone *k = (ScsCone *)scs_calloc(1, sizeof(ScsCone));
113
+ ScsData *d = (ScsData *)scs_calloc(1, sizeof(ScsData));
114
+ ScsSettings *stgs = (ScsSettings *)scs_calloc(1, sizeof(ScsSettings));
115
+ ScsSolution *sol = (ScsSolution *)scs_calloc(1, sizeof(ScsSolution));
116
+ ScsInfo info = {0};
117
+ scs_int exitflag;
118
+ scs_float perr, derr;
119
+ scs_int success;
120
+ const char *fail;
121
+
122
+ scs_float opt = -1.0; /* 1^0.9 * 1^0.1 = 1 */
123
+
124
+ scs_float Ax_p[] = {1.0, -1.0, 1.0, -1.0, -1.0};
125
+ scs_int Ai_p[] = {0, 2, 1, 3, 4};
126
+ scs_int Ap_p[] = {0, 2, 4, 5};
127
+
128
+ scs_float b_p[] = {1.0, 1.0, 0.0, 0.0, 0.0};
129
+ scs_float c_p[] = {0.0, 0.0, -1.0};
130
+
131
+ scs_float pp[] = {0.9};
132
+
133
+ scs_int m = 5, n = 3;
134
+
135
+ d->m = m;
136
+ d->n = n;
137
+ d->b = b_p;
138
+ d->c = c_p;
139
+
140
+ d->A = (ScsMatrix *)scs_calloc(1, sizeof(ScsMatrix));
141
+ d->A->m = m;
142
+ d->A->n = n;
143
+ d->A->x = Ax_p;
144
+ d->A->i = Ai_p;
145
+ d->A->p = Ap_p;
146
+
147
+ k->z = 2;
148
+ k->psize = 1;
149
+ k->p = pp;
150
+
151
+ scs_set_default_settings(stgs);
152
+ stgs->eps_abs = 1e-6;
153
+ stgs->eps_rel = 1e-6;
154
+
155
+ exitflag = scs(d, k, stgs, sol, &info);
156
+
157
+ perr = info.pobj - opt;
158
+ derr = info.dobj - opt;
159
+
160
+ scs_printf("primal obj error %4e\n", perr);
161
+ scs_printf("dual obj error %4e\n", derr);
162
+
163
+ success = ABS(perr) < 1e-4 && ABS(derr) < 1e-4 && exitflag == SCS_SOLVED;
164
+ mu_assert("test_power_cone_p09: SCS failed to produce SCS_SOLVED", success);
165
+ fail = verify_solution_correct(d, k, stgs, &info, sol, exitflag);
166
+
167
+ SCS(free_sol)(sol);
168
+ scs_free(d->A);
169
+ scs_free(k);
170
+ scs_free(stgs);
171
+ scs_free(d);
172
+ return fail;
173
+ }
174
+
175
+ /*
176
+ * Dual power cone test (p < 0 in SCS signals dual cone).
177
+ *
178
+ * For p[i] < 0, cones.c projects onto the dual of K_pow(-p[i]) via Moreau:
179
+ * Pi_{K*}(x) = x + Pi_K(-x).
180
+ *
181
+ * K_pow(0.5)* = {(u,v,w): 2*sqrt(u*v) >= |w|, u,v >= 0}.
182
+ * Problem: maximize w s.t. (u, v, w) in K_pow(0.5)*, u = 1, v = 1.
183
+ * With u=v=1: max w = 2*sqrt(1) = 2, obj = -2.
184
+ *
185
+ * Variables [u, v, w] (n=3), m=5:
186
+ * Row 0 (zero): u = 1 -> A[0,0]=1, b[0]=1
187
+ * Row 1 (zero): v = 1 -> A[1,1]=1, b[1]=1
188
+ * Rows 2-4 (dual power p=-0.5): (u, v, w) in K_pow(0.5)*
189
+ *
190
+ * A cols (CSC):
191
+ * col 0 (u): row 0 -> +1, row 2 -> -1
192
+ * col 1 (v): row 1 -> +1, row 3 -> -1
193
+ * col 2 (w): row 4 -> -1
194
+ */
195
+ static const char *test_dual_power_cone(void) {
196
+ ScsCone *k = (ScsCone *)scs_calloc(1, sizeof(ScsCone));
197
+ ScsData *d = (ScsData *)scs_calloc(1, sizeof(ScsData));
198
+ ScsSettings *stgs = (ScsSettings *)scs_calloc(1, sizeof(ScsSettings));
199
+ ScsSolution *sol = (ScsSolution *)scs_calloc(1, sizeof(ScsSolution));
200
+ ScsInfo info = {0};
201
+ scs_int exitflag;
202
+ scs_float perr, derr;
203
+ scs_int success;
204
+ const char *fail;
205
+
206
+ scs_float opt = -2.0;
207
+
208
+ scs_float Ax_d[] = {1.0, -1.0, 1.0, -1.0, -1.0};
209
+ scs_int Ai_d[] = {0, 2, 1, 3, 4};
210
+ scs_int Ap_d[] = {0, 2, 4, 5};
211
+
212
+ scs_float b_d[] = {1.0, 1.0, 0.0, 0.0, 0.0};
213
+ scs_float c_d[] = {0.0, 0.0, -1.0};
214
+
215
+ scs_float pd[] = {-0.5}; /* negative = dual of K_pow(0.5) */
216
+
217
+ scs_int m = 5, n = 3;
218
+
219
+ d->m = m;
220
+ d->n = n;
221
+ d->b = b_d;
222
+ d->c = c_d;
223
+
224
+ d->A = (ScsMatrix *)scs_calloc(1, sizeof(ScsMatrix));
225
+ d->A->m = m;
226
+ d->A->n = n;
227
+ d->A->x = Ax_d;
228
+ d->A->i = Ai_d;
229
+ d->A->p = Ap_d;
230
+
231
+ k->z = 2;
232
+ k->psize = 1;
233
+ k->p = pd;
234
+
235
+ scs_set_default_settings(stgs);
236
+ stgs->eps_abs = 1e-6;
237
+ stgs->eps_rel = 1e-6;
238
+
239
+ exitflag = scs(d, k, stgs, sol, &info);
240
+
241
+ perr = info.pobj - opt;
242
+ derr = info.dobj - opt;
243
+
244
+ scs_printf("primal obj error %4e\n", perr);
245
+ scs_printf("dual obj error %4e\n", derr);
246
+
247
+ success = ABS(perr) < 1e-4 && ABS(derr) < 1e-4 && exitflag == SCS_SOLVED;
248
+ mu_assert("test_dual_power_cone: SCS failed to produce SCS_SOLVED", success);
249
+ fail = verify_solution_correct(d, k, stgs, &info, sol, exitflag);
250
+
251
+ SCS(free_sol)(sol);
252
+ scs_free(d->A);
253
+ scs_free(k);
254
+ scs_free(stgs);
255
+ scs_free(d);
256
+ return fail;
257
+ }
258
+
259
+ /*
260
+ * Infeasible power cone: (x, y, z) in K_pow(0.5) with x = -1 (impossible
261
+ * since x must be >= 0 in the power cone).
262
+ *
263
+ * Variables v = [x, y, z] (n=3), m=4
264
+ * Row 0 (zero cone): x = -1 → A[0,0]=1, b[0]=-1, s[0]=0 → x=-1
265
+ * Rows 1-3 (power): s[1:4] = (x, y, z) in K_pow(0.5)
266
+ *
267
+ * A:
268
+ * col 0 (x): row 0 -> +1, row 1 -> -1
269
+ * col 1 (y): row 2 -> -1
270
+ * col 2 (z): row 3 -> -1
271
+ */
272
+ static const char *test_power_cone_infeasible(void) {
273
+ ScsCone *k = (ScsCone *)scs_calloc(1, sizeof(ScsCone));
274
+ ScsData *d = (ScsData *)scs_calloc(1, sizeof(ScsData));
275
+ ScsSettings *stgs = (ScsSettings *)scs_calloc(1, sizeof(ScsSettings));
276
+ ScsSolution *sol = (ScsSolution *)scs_calloc(1, sizeof(ScsSolution));
277
+ ScsInfo info = {0};
278
+ scs_int exitflag;
279
+ const char *fail;
280
+
281
+ scs_float Ax[] = {1.0, -1.0, -1.0, -1.0};
282
+ scs_int Ai[] = {0, 1, 2, 3};
283
+ scs_int Ap[] = {0, 2, 3, 4};
284
+
285
+ scs_float b[] = {-1.0, 0.0, 0.0, 0.0};
286
+ scs_float c[] = {0.0, 0.0, -1.0};
287
+
288
+ scs_float p[] = {0.5};
289
+
290
+ scs_int m = 4, n = 3;
291
+
292
+ d->m = m;
293
+ d->n = n;
294
+ d->b = b;
295
+ d->c = c;
296
+
297
+ d->A = (ScsMatrix *)scs_calloc(1, sizeof(ScsMatrix));
298
+ d->A->m = m;
299
+ d->A->n = n;
300
+ d->A->x = Ax;
301
+ d->A->i = Ai;
302
+ d->A->p = Ap;
303
+
304
+ k->z = 1;
305
+ k->psize = 1;
306
+ k->p = p;
307
+
308
+ scs_set_default_settings(stgs);
309
+ stgs->eps_abs = 1e-6;
310
+ stgs->eps_rel = 1e-6;
311
+ stgs->eps_infeas = 1e-9;
312
+
313
+ exitflag = scs(d, k, stgs, sol, &info);
314
+
315
+ mu_assert("test_power_cone_infeasible: expected SCS_INFEASIBLE",
316
+ exitflag == SCS_INFEASIBLE);
317
+ fail = verify_solution_correct(d, k, stgs, &info, sol, exitflag);
318
+
319
+ SCS(free_sol)(sol);
320
+ scs_free(d->A);
321
+ scs_free(k);
322
+ scs_free(stgs);
323
+ scs_free(d);
324
+ return fail;
325
+ }
326
+
327
+ /*
328
+ * Multiple power cones test (psize=2): exercises the loop over k->psize in
329
+ * proj_cones, including both primal and dual cone variants.
330
+ *
331
+ * Two independent power cone constraints:
332
+ * Cone 1 (p=0.5): (x1, x2, t1) in K_pow(0.5), x1=1, x2=1 -> t1*=1
333
+ * Cone 2 (p=-0.5): (y1, y2, t2) in K_pow(0.5)*, y1=1, y2=1 -> t2*=2
334
+ * (Dual K_pow(0.5)*: 2*sqrt(y1*y2) >= |t2|, so t2* = 2*sqrt(1) = 2.)
335
+ *
336
+ * Problem: minimize -(t1 + t2)
337
+ * Optimal: t1* = 1, t2* = 2, obj* = -3.
338
+ *
339
+ * Variables [x1, x2, t1, y1, y2, t2] (n=6), m=10:
340
+ * Rows 0-3 (z=4): x1=1, x2=1, y1=1, y2=1
341
+ * Rows 4-6 (p=0.5): (x1, x2, t1)
342
+ * Rows 7-9 (p=-0.5): (y1, y2, t2)
343
+ *
344
+ * A cols (CSC):
345
+ * col 0 (x1): row 0 -> +1, row 4 -> -1
346
+ * col 1 (x2): row 1 -> +1, row 5 -> -1
347
+ * col 2 (t1): row 6 -> -1
348
+ * col 3 (y1): row 2 -> +1, row 7 -> -1
349
+ * col 4 (y2): row 3 -> +1, row 8 -> -1
350
+ * col 5 (t2): row 9 -> -1
351
+ */
352
+ static const char *test_multi_power(void) {
353
+ ScsCone *k = (ScsCone *)scs_calloc(1, sizeof(ScsCone));
354
+ ScsData *d = (ScsData *)scs_calloc(1, sizeof(ScsData));
355
+ ScsSettings *stgs = (ScsSettings *)scs_calloc(1, sizeof(ScsSettings));
356
+ ScsSolution *sol = (ScsSolution *)scs_calloc(1, sizeof(ScsSolution));
357
+ ScsInfo info = {0};
358
+ scs_int exitflag;
359
+ scs_float perr, derr;
360
+ scs_int success;
361
+ const char *fail;
362
+
363
+ scs_float opt = -3.0;
364
+
365
+ scs_float Axmp[] = {1.0,-1.0, 1.0,-1.0, -1.0, 1.0,-1.0, 1.0,-1.0, -1.0};
366
+ scs_int Aimp[] = {0, 4, 1, 5, 6, 2, 7, 3, 8, 9};
367
+ scs_int Apmp[] = {0, 2, 4, 5, 7, 9, 10};
368
+
369
+ scs_float bmp[] = {1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
370
+ scs_float cmp[] = {0.0, 0.0, -1.0, 0.0, 0.0, -1.0};
371
+
372
+ scs_float pmp[] = {0.5, -0.5}; /* primal K_pow(0.5) then dual K_pow(0.5)* */
373
+
374
+ scs_int m = 10, n = 6;
375
+
376
+ d->m = m;
377
+ d->n = n;
378
+ d->b = bmp;
379
+ d->c = cmp;
380
+
381
+ d->A = (ScsMatrix *)scs_calloc(1, sizeof(ScsMatrix));
382
+ d->A->m = m;
383
+ d->A->n = n;
384
+ d->A->x = Axmp;
385
+ d->A->i = Aimp;
386
+ d->A->p = Apmp;
387
+
388
+ k->z = 4;
389
+ k->psize = 2;
390
+ k->p = pmp;
391
+
392
+ scs_set_default_settings(stgs);
393
+ stgs->eps_abs = 1e-6;
394
+ stgs->eps_rel = 1e-6;
395
+
396
+ exitflag = scs(d, k, stgs, sol, &info);
397
+
398
+ perr = info.pobj - opt;
399
+ derr = info.dobj - opt;
400
+
401
+ scs_printf("primal obj error %4e\n", perr);
402
+ scs_printf("dual obj error %4e\n", derr);
403
+
404
+ success = ABS(perr) < 1e-4 && ABS(derr) < 1e-4 && exitflag == SCS_SOLVED;
405
+ mu_assert("test_multi_power: SCS failed to produce SCS_SOLVED", success);
406
+ fail = verify_solution_correct(d, k, stgs, &info, sol, exitflag);
407
+
408
+ SCS(free_sol)(sol);
409
+ scs_free(d->A);
410
+ scs_free(k);
411
+ scs_free(stgs);
412
+ scs_free(d);
413
+ return fail;
414
+ }
@@ -0,0 +1,109 @@
1
+ #include "cones.h"
2
+ #include "glbopts.h"
3
+ #include "linalg.h"
4
+ #include "minunit.h"
5
+ #include "scs.h"
6
+ #include "util.h"
7
+
8
+ /* Tests for the PSD diagonal-congruence (rank-one svec-diagonal) metric.
9
+ *
10
+ * 1. enforce_cone_boundaries on a PSD block must return exactly
11
+ * rank-one weights w_ij = delta_i * delta_j within clamp bounds.
12
+ * 2. proj_dual_cone under such a metric must produce a Moreau split
13
+ * x = out - R^{-1} p with out in K, p in K*, and <out, p> = 0.
14
+ * Memberships are verified with metric-free Euclidean projections.
15
+ */
16
+
17
+ #define PSD_N (7)
18
+ #define PSD_M ((PSD_N * (PSD_N + 1)) / 2)
19
+
20
+ static scs_int psd_svec_idx(scs_int i, scs_int j, scs_int n) {
21
+ return j * n - (j * (j - 1)) / 2 + (i - j);
22
+ }
23
+
24
+ /* deterministic LCG so the test has no platform variance */
25
+ static scs_float psd_rand(scs_int *state) {
26
+ *state = (scs_int)((1103515245u * (unsigned long)*state + 12345u) &
27
+ 0x7fffffffu);
28
+ return 2.0 * ((scs_float)*state / (scs_float)0x7fffffff) - 1.0;
29
+ }
30
+
31
+ static const char *test_psd_metric(void) {
32
+ ScsCone *k = (ScsCone *)scs_calloc(1, sizeof(ScsCone));
33
+ ScsConeWork *cw, *eucl;
34
+ scs_int s_dims[1] = {PSD_N};
35
+ scs_float r_y[PSD_M], prof[PSD_M], delta[PSD_N];
36
+ scs_float x[PSD_M], out[PSD_M], p[PSD_M], chk[PSD_M];
37
+ scs_float dot, nrm, dist;
38
+ scs_int i, j, seed = 12345;
39
+
40
+ k->ssize = 1;
41
+ k->s = s_dims;
42
+ cw = SCS(init_cone)(k, PSD_M);
43
+ eucl = SCS(init_cone)(k, PSD_M);
44
+ mu_assert("psd_metric: cone init failed", cw && eucl);
45
+
46
+ /* --- 1. rank-one fit --- */
47
+ for (i = 0; i < PSD_M; ++i) {
48
+ prof[i] = exp(1.5 * psd_rand(&seed)); /* arbitrary positive profile */
49
+ }
50
+ SCS(enforce_cone_boundaries)(cw, prof, &SCS(mean), 1);
51
+ for (i = 0; i < PSD_N; ++i) {
52
+ delta[i] = SQRTF(prof[psd_svec_idx(i, i, PSD_N)]);
53
+ }
54
+ for (j = 0; j < PSD_N; ++j) {
55
+ for (i = j; i < PSD_N; ++i) {
56
+ scs_float w = prof[psd_svec_idx(i, j, PSD_N)];
57
+ mu_assert("psd_metric: fit not rank-one",
58
+ ABS(w - delta[i] * delta[j]) <= 1e-12 * (1. + ABS(w)));
59
+ mu_assert("psd_metric: fit outside clamp bounds",
60
+ w >= DIAG_SCALE_MULT_MIN * (1. - 1e-12) &&
61
+ w <= DIAG_SCALE_MULT_MAX * (1. + 1e-12));
62
+ }
63
+ }
64
+
65
+ /* --- 2. Moreau split under the fitted metric --- */
66
+ memcpy(r_y, prof, PSD_M * sizeof(scs_float));
67
+ for (i = 0; i < PSD_M; ++i) {
68
+ x[i] = 2.0 * psd_rand(&seed);
69
+ }
70
+ memcpy(out, x, PSD_M * sizeof(scs_float));
71
+ mu_assert("psd_metric: projection failed",
72
+ SCS(proj_dual_cone)(out, cw, SCS_NULL, r_y) == 0);
73
+
74
+ /* p = R (out - x) must lie in K* (= K); out must lie in K. */
75
+ for (i = 0; i < PSD_M; ++i) {
76
+ p[i] = r_y[i] * (out[i] - x[i]);
77
+ }
78
+ memcpy(chk, out, PSD_M * sizeof(scs_float));
79
+ SCS(proj_dual_cone)(chk, eucl, SCS_NULL, SCS_NULL);
80
+ dist = SCS(norm_inf_diff)(chk, out, PSD_M);
81
+ nrm = SCS(norm_inf)(out, PSD_M);
82
+ mu_assert("psd_metric: primal part not in cone", dist <= 1e-9 * (1. + nrm));
83
+
84
+ memcpy(chk, p, PSD_M * sizeof(scs_float));
85
+ SCS(proj_dual_cone)(chk, eucl, SCS_NULL, SCS_NULL);
86
+ dist = SCS(norm_inf_diff)(chk, p, PSD_M);
87
+ nrm = SCS(norm_inf)(p, PSD_M);
88
+ mu_assert("psd_metric: dual part not in cone", dist <= 1e-9 * (1. + nrm));
89
+
90
+ dot = SCS(dot)(out, p, PSD_M);
91
+ mu_assert("psd_metric: Moreau parts not orthogonal",
92
+ ABS(dot) <= 1e-9 * (1. + SCS(norm_inf)(x, PSD_M)));
93
+
94
+ /* uniform metric must reproduce the Euclidean projection exactly */
95
+ for (i = 0; i < PSD_M; ++i) {
96
+ r_y[i] = 0.25;
97
+ out[i] = x[i];
98
+ chk[i] = x[i];
99
+ }
100
+ SCS(proj_dual_cone)(out, cw, SCS_NULL, r_y);
101
+ SCS(proj_dual_cone)(chk, eucl, SCS_NULL, SCS_NULL);
102
+ mu_assert("psd_metric: uniform metric deviates from Euclidean",
103
+ SCS(norm_inf_diff)(chk, out, PSD_M) <= 1e-13);
104
+
105
+ SCS(finish_cone)(cw);
106
+ SCS(finish_cone)(eucl);
107
+ scs_free(k);
108
+ return 0;
109
+ }
@@ -0,0 +1,84 @@
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
+ * Test PSD cone with n=1 (scalar SDP): exercises the fast path
10
+ * proj_semi_definite_cone(X, n=1) which just does X[0] = MAX(X[0], 0)
11
+ * without calling LAPACK eigendecomposition. Works without USE_LAPACK.
12
+ *
13
+ * Problem: minimize x
14
+ * subject to x >= 1 (via 1x1 PSD cone)
15
+ *
16
+ * Formulation: Ax + s = b, s in S^1_+
17
+ * A = [[-1]], b = [-1], c = [1], n=1, m=1
18
+ * s = x - 1, s >= 0 => x >= 1
19
+ * Optimal: x = 1, obj = 1.
20
+ *
21
+ * k->ssize = 1, k->s = [1] (one 1x1 PSD block)
22
+ * PSD(1) contributes 1*(1+1)/2 = 1 entry in the constraint vector.
23
+ */
24
+ static const char *test_psd_n1(void) {
25
+ ScsCone *k = (ScsCone *)scs_calloc(1, sizeof(ScsCone));
26
+ ScsData *d = (ScsData *)scs_calloc(1, sizeof(ScsData));
27
+ ScsSettings *stgs = (ScsSettings *)scs_calloc(1, sizeof(ScsSettings));
28
+ ScsSolution *sol = (ScsSolution *)scs_calloc(1, sizeof(ScsSolution));
29
+ ScsInfo info = {0};
30
+ scs_int exitflag;
31
+ scs_float perr, derr;
32
+ scs_int success;
33
+ const char *fail;
34
+
35
+ scs_float opt = 1.0;
36
+
37
+ scs_float Ax[] = {-1.0};
38
+ scs_int Ai[] = {0};
39
+ scs_int Ap[] = {0, 1};
40
+
41
+ scs_float b[] = {-1.0};
42
+ scs_float c[] = {1.0};
43
+
44
+ scs_int s_arr[] = {1}; /* one 1x1 PSD block */
45
+ scs_int m = 1, n = 1;
46
+
47
+ d->m = m;
48
+ d->n = n;
49
+ d->b = b;
50
+ d->c = c;
51
+
52
+ d->A = (ScsMatrix *)scs_calloc(1, sizeof(ScsMatrix));
53
+ d->A->m = m;
54
+ d->A->n = n;
55
+ d->A->x = Ax;
56
+ d->A->i = Ai;
57
+ d->A->p = Ap;
58
+
59
+ k->ssize = 1;
60
+ k->s = s_arr;
61
+
62
+ scs_set_default_settings(stgs);
63
+ stgs->eps_abs = 1e-6;
64
+ stgs->eps_rel = 1e-6;
65
+
66
+ exitflag = scs(d, k, stgs, sol, &info);
67
+
68
+ perr = info.pobj - opt;
69
+ derr = info.dobj - opt;
70
+
71
+ scs_printf("primal obj error %4e\n", perr);
72
+ scs_printf("dual obj error %4e\n", derr);
73
+
74
+ success = ABS(perr) < 1e-4 && ABS(derr) < 1e-4 && exitflag == SCS_SOLVED;
75
+ mu_assert("test_psd_n1: SCS failed to produce SCS_SOLVED", success);
76
+ fail = verify_solution_correct(d, k, stgs, &info, sol, exitflag);
77
+
78
+ SCS(free_sol)(sol);
79
+ scs_free(d->A);
80
+ scs_free(k);
81
+ scs_free(stgs);
82
+ scs_free(d);
83
+ return fail;
84
+ }