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
@@ -1,8 +1,8 @@
1
- #include "glbopts.h" // for scs_printf
1
+ #include "glbopts.h" /* for scs_printf */
2
2
  #include "linalg.h"
3
3
  #include "scs_blas.h"
4
4
  #include "util_spectral_cones.h"
5
- #include <string.h> // for memcpy
5
+ #include <string.h> /* for memcpy */
6
6
 
7
7
  /*
8
8
  * Spectral matrix cone projections, from "Projection onto Spectral Matrix
@@ -33,18 +33,23 @@
33
33
  #define TERMINATE_DUE_TO_ZEROS -5
34
34
  #define MAX_GRAD_STEPS_REACHED -6
35
35
 
36
- // the CALLER of this function must make sure that the arguments belong to the
37
- // domain
36
+ /*
37
+ * the CALLER of this function must make sure that the arguments belong to the
38
+ * domain
39
+ */
38
40
  static scs_float obj_val(const scs_float *u, scs_float t0, scs_float v0,
39
41
  const scs_float *x0, scs_int n) {
40
42
  scs_float v = u[0];
41
43
  const scs_float *x = u + 1;
44
+ scs_float sx;
45
+ scs_float obj;
46
+ scs_int i;
42
47
 
43
48
  assert(v > 0 && min_vec(x, n) > 0);
44
49
 
45
- scs_float sx = -(v * sum_log(x, n) - n * v * log(v));
46
- scs_float obj = 0.5 * (sx - t0) * (sx - t0) + 0.5 * (v - v0) * (v - v0);
47
- for (scs_int i = 0; i < n; ++i) {
50
+ sx = -(v * sum_log(x, n) - n * v * log(v));
51
+ obj = 0.5 * (sx - t0) * (sx - t0) + 0.5 * (v - v0) * (v - v0);
52
+ for (i = 0; i < n; ++i) {
48
53
  obj += 0.5 * (x[i] - x0[i]) * (x[i] - x0[i]);
49
54
  }
50
55
  return obj;
@@ -58,17 +63,27 @@ scs_int log_cone_Newton(scs_float t0, scs_float v0, const scs_float *x0,
58
63
  scs_float *x = u + 2;
59
64
  scs_int n_plus_one = n + 1;
60
65
 
61
- // -------------------------------------------------------------------------
62
- // check cone membership and special cases with analytic projections
63
- // -------------------------------------------------------------------------
66
+ /* check cone membership and special cases with analytic projections */
64
67
  bool ix_x0_non_neg = true;
65
68
  bool is_x0_pos = true;
66
69
  scs_int i = 0;
70
+
71
+ scs_float obj_old;
72
+ scs_float *grad;
73
+ scs_float *d;
74
+ scs_float *w;
75
+ scs_float *du;
76
+ scs_float *temp1;
77
+ scs_float *u_new;
78
+ size_t num_grad_steps;
79
+ scs_int iter;
80
+ scs_float newton_decrement;
81
+
67
82
  while (ix_x0_non_neg || is_x0_pos) {
68
- if (x[i] < 0) {
83
+ if (x0[i] < 0) {
69
84
  ix_x0_non_neg = false;
70
85
  is_x0_pos = false;
71
- } else if (x[i] == 0) {
86
+ } else if (x0[i] == 0) {
72
87
  is_x0_pos = false;
73
88
  }
74
89
 
@@ -78,7 +93,7 @@ scs_int log_cone_Newton(scs_float t0, scs_float v0, const scs_float *x0,
78
93
  ++i;
79
94
  }
80
95
 
81
- // if (t0, v0, x0) belongs to cone
96
+ /* if (t0, v0, x0) belongs to cone */
82
97
  if ((v0 > 0 && is_x0_pos && -v0 * (sum_log(x0, n) - n * log(v0)) <= t0) ||
83
98
  (v0 == 0 && ix_x0_non_neg && t0 >= 0)) {
84
99
  *t = t0;
@@ -89,7 +104,7 @@ scs_int log_cone_Newton(scs_float t0, scs_float v0, const scs_float *x0,
89
104
  return 0;
90
105
  }
91
106
 
92
- // if (t0, v0, x0) belongs to negative dual cone
107
+ /* if (t0, v0, x0) belongs to negative dual cone */
93
108
  if (t0 < 0 && is_negative(x0, n)) {
94
109
  scs_float sum = -n;
95
110
  for (i = 0; i < n; ++i) {
@@ -100,14 +115,16 @@ scs_int log_cone_Newton(scs_float t0, scs_float v0, const scs_float *x0,
100
115
  if (v0 <= sum) {
101
116
  memset(u, 0, (n + 2) * sizeof(*x0));
102
117
  stats->iter = IN_NEGATIVE_DUAL_CONE;
103
- // if 0 is the solution we should not use it to warmstart the next
104
- // iteration
118
+ /*
119
+ * if 0 is the solution we should not use it to warmstart the next
120
+ * iteration
121
+ */
105
122
  *warm_start = false;
106
123
  return 0;
107
124
  }
108
125
  }
109
126
 
110
- // special case with analytic solution
127
+ /* special case with analytic solution */
111
128
  if (v0 <= 0 && t0 >= 0) {
112
129
  *t = t0;
113
130
  *v = 0;
@@ -117,84 +134,94 @@ scs_int log_cone_Newton(scs_float t0, scs_float v0, const scs_float *x0,
117
134
  return 0;
118
135
  }
119
136
 
120
- // ----------------------------------------------------------------------
121
- // if 'warm_start' is false we initialize in the point
122
- // (v, x) = (max(v0, MIN_INIT_LOG_CONE), max(x0, MIN_INIT_LOG_CONE)),
123
- // otherwise it is assumed that 'proj' has already been
124
- // initialized / warmstarted.
125
- // ----------------------------------------------------------------------
137
+ /*
138
+ * if 'warm_start' is false we initialize in the point
139
+ * (v, x) = (max(v0, MIN_INIT_LOG_CONE), max(x0, MIN_INIT_LOG_CONE)),
140
+ * otherwise it is assumed that 'proj' has already been
141
+ * initialized / warmstarted.
142
+ */
126
143
  if (!(*warm_start)) {
127
144
  *v = (v0 > MIN_INIT_LOG_CONE) ? v0 : MIN_INIT_LOG_CONE;
128
145
 
129
- for (scs_int i = 0; i < n; ++i) {
146
+ for (i = 0; i < n; ++i) {
130
147
  x[i] = (x0[i] > MIN_INIT_LOG_CONE) ? x0[i] : MIN_INIT_LOG_CONE;
131
148
  }
132
149
  }
133
150
 
134
- scs_float obj_old = obj_val(u + 1, t0, v0, x0, n);
135
-
136
- // -----------------------------
137
- // parse workspace
138
- // -----------------------------
139
- scs_float *grad = workspace;
140
- scs_float *d = grad + n_plus_one;
141
- scs_float *w = d + n_plus_one;
142
- scs_float *du = w + n_plus_one;
143
- scs_float *temp1 = du + n_plus_one;
144
- scs_float *u_new = du + n_plus_one + 1;
145
-
146
- size_t num_grad_steps = 0;
147
- scs_int iter = 0;
148
- scs_float newton_decrement = 0;
151
+ obj_old = obj_val(u + 1, t0, v0, x0, n);
152
+
153
+ /* parse workspace */
154
+ grad = workspace;
155
+ d = grad + n_plus_one;
156
+ w = d + n_plus_one;
157
+ du = w + n_plus_one;
158
+ temp1 = du + n_plus_one;
159
+ u_new = du + n_plus_one + 1;
160
+
161
+ num_grad_steps = 0;
162
+ iter = 0;
163
+ newton_decrement = 0;
149
164
  for (iter = 1; iter <= MAX_ITER_NEWTON; ++iter) {
150
- // A small value on v indicates that Newton's method converges to the
151
- // origin. In this case we should abort and apply an IPM.
165
+ scs_float temp0;
166
+ scs_float a;
167
+ scs_float c;
168
+ scs_float v_inv;
169
+ scs_float av;
170
+ scs_float nominator;
171
+ scs_float denominator;
172
+ scs_float ratio;
173
+ scs_float dirDer;
174
+ scs_float step_size;
175
+ scs_float new_obj;
176
+
177
+ /*
178
+ * A small value on v indicates that Newton's method converges to the
179
+ * origin. In this case we should abort and apply an IPM.
180
+ */
152
181
  if (*v < MIN_V) {
153
182
  stats->iter = TERMINATE_DUE_TO_ZEROS;
154
183
  return -1;
155
184
  }
156
185
 
157
- // -------------------------------------------------------------------
158
- // To avoid pathological cases where some components of
159
- // x approach 0 we use a minimum threshold.
160
- // -------------------------------------------------------------------
161
- for (scs_int i = 0; i < n; i++) {
186
+ /*
187
+ * To avoid pathological cases where some components of
188
+ * x approach 0 we use a minimum threshold.
189
+ */
190
+ for (i = 0; i < n; i++) {
162
191
  x[i] = MAX(x[i], MIN_X);
163
192
  }
164
193
 
165
- // ----------------------------------------------------------------
166
- // compute gradient and Hessian
167
- // ----------------------------------------------------------------
194
+ /* compute gradient and Hessian */
168
195
  assert(*v > MIN_FLOAT && min_vec(x, n) > MIN_FLOAT);
169
- scs_float temp0 = -sum_log(x, n) + n * log(*v);
170
- scs_float a = (*v) * temp0 - t0;
171
- scs_float c = temp0 + n;
196
+ temp0 = -sum_log(x, n) + n * log(*v);
197
+ a = (*v) * temp0 - t0;
198
+ c = temp0 + n;
172
199
 
173
200
  grad[0] = a * c + (*v) - v0;
174
- scs_float v_inv = 1 / (*v);
201
+ v_inv = 1 / (*v);
175
202
  d[0] = 1 + a * (-a * (v_inv * v_inv) + n * v_inv - 2 * c * v_inv);
176
203
  w[0] = -(a + (*v) * c) * v_inv;
177
- scs_float av = a * (*v);
204
+ av = a * (*v);
178
205
 
179
206
  for (i = 1; i < n + 1; ++i) {
180
- assert(x[i - 1] > 0);
181
207
  scs_float x_inv = 1 / x[i - 1];
208
+ assert(x[i - 1] > 0);
182
209
  grad[i] = -av * x_inv + x[i - 1] - x0[i - 1];
183
210
  d[i] = 1 + av * (x_inv * x_inv);
184
211
  w[i] = (*v) * x_inv;
185
212
  }
186
213
 
187
- // ----------------------------------------------------------------------
188
- // Solve for Newton step. I have seen a scenario when the variable
189
- // 'denominator' becomes 0. This occurred when Newton's method
190
- // converged to the origin and the IPM was necessary
191
- // to converge to the correct point. We therefore abort when the
192
- // denominator becomes very close to 0, since this may indicate
193
- // that Newton's method is converging to the wrong point and in this
194
- // case it is necessary to apply an IPM.
195
- // ----------------------------------------------------------------------
196
- scs_float nominator = 0;
197
- scs_float denominator = 1;
214
+ /*
215
+ * Solve for Newton step. I have seen a scenario when the variable
216
+ * 'denominator' becomes 0. This occurred when Newton's method
217
+ * converged to the origin and the IPM was necessary
218
+ * to converge to the correct point. We therefore abort when the
219
+ * denominator becomes very close to 0, since this may indicate
220
+ * that Newton's method is converging to the wrong point and in this
221
+ * case it is necessary to apply an IPM.
222
+ */
223
+ nominator = 0;
224
+ denominator = 1;
198
225
  for (i = 0; i < n + 1; ++i) {
199
226
  assert(fabs(d[i]) > MIN_FLOAT);
200
227
  du[i] = -grad[i] / d[i];
@@ -208,15 +235,15 @@ scs_int log_cone_Newton(scs_float t0, scs_float v0, const scs_float *x0,
208
235
  return -1;
209
236
  }
210
237
 
211
- scs_float ratio = -nominator / denominator;
238
+ ratio = -nominator / denominator;
212
239
  SCS(add_scaled_array)(du, temp1, n_plus_one, ratio);
213
240
 
214
- // --------------------------------------------------------------------
215
- // if the Newton direction is not descent we use the negative gradient
216
- // as the search direction, provided that it hasn't been used many times
217
- // before.
218
- // --------------------------------------------------------------------
219
- scs_float dirDer = SCS(dot)(grad, du, n_plus_one);
241
+ /*
242
+ * if the Newton direction is not descent we use the negative gradient
243
+ * as the search direction, provided that it hasn't been used many times
244
+ * before.
245
+ */
246
+ dirDer = SCS(dot)(grad, du, n_plus_one);
220
247
  if (dirDer > 0) {
221
248
  if (num_grad_steps >= MAX_GRAD_STEPS) {
222
249
  stats->iter = MAX_GRAD_STEPS_REACHED;
@@ -232,18 +259,14 @@ scs_int log_cone_Newton(scs_float t0, scs_float v0, const scs_float *x0,
232
259
  }
233
260
  }
234
261
 
235
- // --------------------------------------------------------
236
- // compute Newton decrement and check termination criteria
237
- // -------------------------------------------------------
262
+ /* compute Newton decrement and check termination criteria */
238
263
  newton_decrement = -dirDer;
239
264
  if (newton_decrement <= 2 * TOL_NEWTON) {
240
265
  break;
241
266
  }
242
267
 
243
- // --------------------------------------------------
244
- // find largest step size with respect to the domain
245
- // --------------------------------------------------
246
- scs_float step_size = 1;
268
+ /* find largest step size with respect to the domain */
269
+ step_size = 1;
247
270
  for (i = 0; i < n + 1; i++) {
248
271
  if (du[i] < 0) {
249
272
  scs_float max_step = -0.99 * u[i + 1] / du[i];
@@ -251,13 +274,13 @@ scs_int log_cone_Newton(scs_float t0, scs_float v0, const scs_float *x0,
251
274
  }
252
275
  }
253
276
 
254
- // -------------------------------------------------
255
- // backtracking line search. First two lines do
256
- // u_new = u + t * du;
257
- // -------------------------------------------------
277
+ /*
278
+ * backtracking line search. First two lines do
279
+ * u_new = u + t * du;
280
+ */
258
281
  memcpy(u_new + 1, u + 1, n_plus_one * sizeof(*u));
259
282
  SCS(add_scaled_array)(u_new + 1, du, n_plus_one, step_size);
260
- scs_float new_obj = obj_val(u_new + 1, t0, v0, x0, n);
283
+ new_obj = obj_val(u_new + 1, t0, v0, x0, n);
261
284
  while ((1 - LINESEARCH_RELATIVE_TOL) * new_obj >
262
285
  obj_old + ALPHA_NEWTON * step_size * dirDer) {
263
286
  step_size *= BETA_NEWTON;
@@ -28,17 +28,17 @@
28
28
  * Last modified: 25 August 2024.
29
29
  */
30
30
 
31
- // forward declare from log_cone_Newton.c
31
+ /* forward declare from log_cone_Newton.c */
32
32
  scs_int log_cone_Newton(scs_float t0, scs_float v0, const scs_float *x0,
33
33
  scs_float *proj, scs_int n, scs_float *workspace,
34
34
  Newton_stats *stats, bool *warm_start);
35
35
 
36
- // forward declare form log_cone_IPM.c
36
+ /* forward declare form log_cone_IPM.c */
37
37
  scs_int log_cone_IPM(scs_float t0, scs_float v0, scs_float *x0, scs_float *u1,
38
38
  scs_int n, scs_float *workspace, Newton_stats *stats,
39
39
  scs_int variant);
40
40
 
41
- // forward declare from this file
41
+ /* forward declare from this file */
42
42
  static void check_opt_cond_log_cone(const scs_float *tvx, scs_float t0,
43
43
  scs_float v0, const scs_float *x0,
44
44
  scs_int n, scs_float residuals[3],
@@ -48,17 +48,17 @@ scs_int log_cone_proj_wrapper(scs_float t0, scs_float v0, scs_float *x0,
48
48
  scs_float *proj, scs_int n, scs_float *workspace,
49
49
  Newton_stats *stats, bool *warm_start) {
50
50
  scs_int status;
51
- // -----------------------------------------------------------------------
52
- // 1. Solve problem with Newton's method. From Lagrange multiplier theory
53
- // we know that the t-component of the projection must always be greater
54
- // than t0, so if proj[0] < t0 it means that Newton's method has converged
55
- // to wrong point. We return if proj[0] >= t0 and the residuals suggest
56
- // that we converged to the correct point.
57
- // 2. We warmstart Newton using the solution of the previous iteration
58
- // except for the first iteration.
59
- // 3. The current implementation of the warmstart assumes that there is only
60
- // one spectral matrix cone so 'proj' isn't overwritten.
61
- // ------------------------------------------------------------------------
51
+ /*
52
+ * 1. Solve problem with Newton's method. From Lagrange multiplier theory
53
+ * we know that the t-component of the projection must always be greater
54
+ * than t0, so if proj[0] < t0 it means that Newton's method has converged
55
+ * to wrong point. We return if proj[0] >= t0 and the residuals suggest
56
+ * that we converged to the correct point.
57
+ * 2. We warmstart Newton using the solution of the previous iteration
58
+ * except for the first iteration.
59
+ * 3. The current implementation of the warmstart assumes that there is only
60
+ * one spectral matrix cone so 'proj' isn't overwritten.
61
+ */
62
62
  status = log_cone_Newton(t0, v0, x0, proj, n, workspace, stats, warm_start);
63
63
 
64
64
  if (proj[0] >= t0 - 0.1 * fabs(t0)) {
@@ -74,14 +74,14 @@ scs_int log_cone_proj_wrapper(scs_float t0, scs_float v0, scs_float *x0,
74
74
  return 0;
75
75
  }
76
76
 
77
- // ------------------------------------------------------------------------
78
- // Solve problem with primal-dual IPM incorporating Mehrotra's correction
79
- // etc.
80
- // ------------------------------------------------------------------------
77
+ /*
78
+ * Solve problem with primal-dual IPM incorporating Mehrotra's correction
79
+ * etc.
80
+ */
81
81
  status = log_cone_IPM(t0, v0, x0, proj, n, workspace, stats, 0);
82
82
  check_opt_cond_log_cone(proj, t0, v0, x0, n, stats->residuals, workspace);
83
83
 
84
- *warm_start = true; // next iteration Newton should be warmstarted
84
+ *warm_start = true; /* next iteration Newton should be warmstarted */
85
85
 
86
86
  if (status == 0 && stats->residuals[0] < DUAL_FEAS_TOL &&
87
87
  stats->residuals[1] < PRI_FEAS_TOL &&
@@ -90,15 +90,15 @@ scs_int log_cone_proj_wrapper(scs_float t0, scs_float v0, scs_float *x0,
90
90
  return 0;
91
91
  }
92
92
 
93
- // ------------------------------------------------------------------------
94
- // Solve problem with primal-dual IPM without Mehrotra's correction
95
- // etc. (In all experiments in the paper by Cederberg and Boyd,
96
- // the IPM above solves the problem correctly so the code below never
97
- // runs. However, during development I ran into a (possibly pathological
98
- // case) where the first IPM fails. If this happens we run below another
99
- // version. This version of the IPM solves the problem that the first version
100
- // failed on.)
101
- // ------------------------------------------------------------------------
93
+ /*
94
+ * Solve problem with primal-dual IPM without Mehrotra's correction
95
+ * etc. (In all experiments in the paper by Cederberg and Boyd,
96
+ * the IPM above solves the problem correctly so the code below never
97
+ * runs. However, during development I ran into a (possibly pathological
98
+ * case) where the first IPM fails. If this happens we run below another
99
+ * version. This version of the IPM solves the problem that the first version
100
+ * failed on.)
101
+ */
102
102
  status = log_cone_IPM(t0, v0, x0, proj, n, workspace, stats, 1);
103
103
  check_opt_cond_log_cone(proj, t0, v0, x0, n, stats->residuals, workspace);
104
104
 
@@ -110,71 +110,73 @@ scs_int log_cone_proj_wrapper(scs_float t0, scs_float v0, scs_float *x0,
110
110
  }
111
111
 
112
112
  #ifdef SPECTRAL_DEBUG
113
- scs_printf("FAILURE: logarithmic cone projection");
114
- scs_printf("dual_res / pri_res / comp / iter: %.3e, %.3e, %.3e, %d\n",
115
- stats->residuals[0], stats->residuals[1], stats->residuals[2],
116
- stats->iter);
117
-
118
- scs_printf("Projecting the following point:\n %.10e, %.10e", t0, v0);
119
- for (scs_int i = 0; i < n; i++) {
120
- scs_printf(" %.10e", x0[i]);
113
+ {
114
+ scs_int i;
115
+ scs_printf("FAILURE: logarithmic cone projection");
116
+ scs_printf("dual_res / pri_res / comp / iter: %.3e, %.3e, %.3e, %d\n",
117
+ stats->residuals[0], stats->residuals[1], stats->residuals[2],
118
+ stats->iter);
119
+
120
+ scs_printf("Projecting the following point:\n %.10e, %.10e", t0, v0);
121
+ for (i = 0; i < n; i++) {
122
+ scs_printf(" %.10e", x0[i]);
123
+ }
124
+ scs_printf("\n");
121
125
  }
122
- scs_printf("\n");
123
126
  #endif
124
127
 
125
128
  return -1;
126
129
  }
127
130
 
128
- // tvx = [t, v, x].
131
+ /* tvx = [t, v, x]. */
129
132
  static void check_opt_cond_log_cone(const scs_float *tvx, scs_float t0,
130
133
  scs_float v0, const scs_float *x0,
131
134
  scs_int n, scs_float residuals[3],
132
135
  scs_float *dualx) {
133
136
  scs_float pri_res, dual_res, complementarity;
134
-
135
- // -------------------------------------------------------
136
- // Compute Lagrange multiplier
137
- // -------------------------------------------------------
138
- scs_float dualt = tvx[0] - t0;
137
+ scs_float dualt;
138
+ scs_float dualv;
139
+ scs_int i;
140
+ scs_float dual_norm;
141
+ scs_float pri_norm;
142
+ double scale;
143
+
144
+ /* Compute Lagrange multiplier */
145
+ dualt = tvx[0] - t0;
139
146
  if (fabs(dualt) < DUAL_T_THRESHOLD) {
140
147
  dualt = DUAL_T_THRESHOLD;
141
148
  }
142
- scs_float dualv = tvx[1] - v0;
143
- for (scs_int i = 0; i < n; ++i) {
149
+ dualv = tvx[1] - v0;
150
+ for (i = 0; i < n; ++i) {
144
151
  dualx[i] = tvx[i + 2] - x0[i];
145
152
  if (fabs(dualx[i]) < DUAL_X_THRESHOLD) {
146
153
  dualx[i] = DUAL_X_THRESHOLD;
147
154
  }
148
155
  }
149
156
 
150
- // ---------------------------------------------------------------------
151
- // Compute complementarity measure
152
- // ---------------------------------------------------------------------
157
+ /* Compute complementarity measure */
153
158
  complementarity =
154
159
  tvx[0] * dualt + tvx[1] * dualv + SCS(dot)(dualx, tvx + 2, n);
155
160
 
156
- // ----------------------------------------------------------------------
157
- // Compute primal feasibility measure
158
- // ----------------------------------------------------------------------
161
+ /* Compute primal feasibility measure */
159
162
  if (tvx[1] > 0 && is_pos(tvx + 2, n)) {
160
163
  pri_res = -tvx[1] * (sum_log(tvx + 2, n) - n * log(tvx[1])) - tvx[0];
161
164
  } else {
165
+ const scs_float *xi;
162
166
  pri_res = tvx[1] * tvx[1];
163
167
 
164
168
  if (tvx[0] < 0) {
165
169
  pri_res += tvx[0] * tvx[0];
166
170
  }
167
171
 
168
- for (const scs_float *xi = tvx + 2; xi < tvx + 2 + n; ++xi) {
172
+ for (xi = tvx + 2; xi < tvx + 2 + n; ++xi) {
169
173
  if (*xi < 0) {
170
174
  pri_res += (*xi) * (*xi);
171
175
  }
172
176
  }
173
177
  }
174
178
 
175
- // ----------------------------------------------------------------------
176
- // Compute dual feasibility measure
177
- // ----------------------------------------------------------------------
179
+ /* Compute dual feasibility measure */
178
180
  if (dualt > 0 && is_pos(dualx, n)) {
179
181
  dual_res = dualt * (n * log(dualt) - n - sum_log(dualx, n)) - dualv;
180
182
  } else {
@@ -184,22 +186,19 @@ static void check_opt_cond_log_cone(const scs_float *tvx, scs_float t0,
184
186
  dual_res += dualv * dualv;
185
187
  }
186
188
 
187
- for (scs_int i = 0; i < n; i++) {
189
+ for (i = 0; i < n; i++) {
188
190
  if (dualx[i] < 0) {
189
191
  dual_res += dualx[i] * dualx[i];
190
192
  }
191
193
  }
192
194
  }
193
195
 
194
- // --------------------------------------------------------
195
- // Normalize the residuals and assign the result
196
- // --------------------------------------------------------
197
- scs_float dual_norm =
196
+ /* Normalize the residuals and assign the result */
197
+ dual_norm =
198
198
  sqrt(dualt * dualt + dualv * dualv + SCS(norm_sq)(dualx, n));
199
- scs_float pri_norm = SCS(norm_2)(tvx, n + 2);
199
+ pri_norm = SCS(norm_2)(tvx, n + 2);
200
200
  residuals[0] = dual_res / MAX(dual_norm, 1.0);
201
201
  residuals[1] = pri_res / MAX(pri_norm, 1.0);
202
- double scale = MAX(pri_norm, 1.0);
202
+ scale = MAX(pri_norm, 1.0);
203
203
  residuals[2] = complementarity / MAX(scale, dual_norm);
204
204
  }
205
-