scs 0.2.2 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -0
  3. data/LICENSE.txt +18 -18
  4. data/README.md +19 -14
  5. data/lib/scs/ffi.rb +31 -20
  6. data/lib/scs/solver.rb +32 -9
  7. data/lib/scs/version.rb +1 -1
  8. data/vendor/scs/CITATION.cff +39 -0
  9. data/vendor/scs/CMakeLists.txt +320 -0
  10. data/vendor/scs/Makefile +32 -23
  11. data/vendor/scs/README.md +9 -218
  12. data/vendor/scs/include/aa.h +67 -23
  13. data/vendor/scs/include/cones.h +22 -19
  14. data/vendor/scs/include/glbopts.h +107 -79
  15. data/vendor/scs/include/linalg.h +3 -4
  16. data/vendor/scs/include/linsys.h +58 -44
  17. data/vendor/scs/include/normalize.h +6 -5
  18. data/vendor/scs/include/rw.h +8 -2
  19. data/vendor/scs/include/scs.h +257 -141
  20. data/vendor/scs/include/scs_types.h +34 -0
  21. data/vendor/scs/include/scs_work.h +83 -0
  22. data/vendor/scs/include/util.h +3 -15
  23. data/vendor/scs/linsys/cpu/direct/private.c +241 -232
  24. data/vendor/scs/linsys/cpu/direct/private.h +13 -7
  25. data/vendor/scs/linsys/cpu/indirect/private.c +194 -118
  26. data/vendor/scs/linsys/cpu/indirect/private.h +7 -4
  27. data/vendor/scs/linsys/csparse.c +87 -0
  28. data/vendor/scs/linsys/csparse.h +34 -0
  29. data/vendor/scs/linsys/external/amd/SuiteSparse_config.c +6 -6
  30. data/vendor/scs/linsys/external/amd/SuiteSparse_config.h +6 -1
  31. data/vendor/scs/linsys/external/amd/amd_internal.h +1 -1
  32. data/vendor/scs/linsys/external/amd/amd_order.c +5 -5
  33. data/vendor/scs/linsys/external/qdldl/changes +2 -0
  34. data/vendor/scs/linsys/external/qdldl/qdldl.c +29 -46
  35. data/vendor/scs/linsys/external/qdldl/qdldl.h +33 -41
  36. data/vendor/scs/linsys/external/qdldl/qdldl_types.h +11 -3
  37. data/vendor/scs/linsys/gpu/gpu.c +58 -21
  38. data/vendor/scs/linsys/gpu/gpu.h +70 -35
  39. data/vendor/scs/linsys/gpu/indirect/private.c +394 -157
  40. data/vendor/scs/linsys/gpu/indirect/private.h +27 -12
  41. data/vendor/scs/linsys/scs_matrix.c +478 -0
  42. data/vendor/scs/linsys/scs_matrix.h +70 -0
  43. data/vendor/scs/scs.mk +14 -10
  44. data/vendor/scs/src/aa.c +394 -110
  45. data/vendor/scs/src/cones.c +497 -359
  46. data/vendor/scs/src/ctrlc.c +15 -5
  47. data/vendor/scs/src/linalg.c +107 -26
  48. data/vendor/scs/src/normalize.c +30 -72
  49. data/vendor/scs/src/rw.c +202 -27
  50. data/vendor/scs/src/scs.c +769 -571
  51. data/vendor/scs/src/scs_version.c +11 -3
  52. data/vendor/scs/src/util.c +37 -106
  53. data/vendor/scs/test/minunit.h +22 -8
  54. data/vendor/scs/test/problem_utils.h +180 -25
  55. data/vendor/scs/test/problems/degenerate.h +130 -0
  56. data/vendor/scs/test/problems/hs21_tiny_qp.h +124 -0
  57. data/vendor/scs/test/problems/hs21_tiny_qp_rw.h +116 -0
  58. data/vendor/scs/test/problems/infeasible_tiny_qp.h +100 -0
  59. data/vendor/scs/test/problems/qafiro_tiny_qp.h +199 -0
  60. data/vendor/scs/test/problems/random_prob +0 -0
  61. data/vendor/scs/test/problems/random_prob.h +45 -0
  62. data/vendor/scs/test/problems/rob_gauss_cov_est.h +188 -31
  63. data/vendor/scs/test/problems/small_lp.h +14 -13
  64. data/vendor/scs/test/problems/small_qp.h +352 -0
  65. data/vendor/scs/test/problems/test_validation.h +43 -0
  66. data/vendor/scs/test/problems/unbounded_tiny_qp.h +82 -0
  67. data/vendor/scs/test/random_socp_prob.c +54 -53
  68. data/vendor/scs/test/rng.h +109 -0
  69. data/vendor/scs/test/run_from_file.c +20 -11
  70. data/vendor/scs/test/run_tests.c +35 -2
  71. metadata +29 -98
  72. data/vendor/scs/linsys/amatrix.c +0 -305
  73. data/vendor/scs/linsys/amatrix.h +0 -36
  74. data/vendor/scs/linsys/amatrix.o +0 -0
  75. data/vendor/scs/linsys/cpu/direct/private.o +0 -0
  76. data/vendor/scs/linsys/cpu/indirect/private.o +0 -0
  77. data/vendor/scs/linsys/external/amd/SuiteSparse_config.o +0 -0
  78. data/vendor/scs/linsys/external/amd/amd_1.o +0 -0
  79. data/vendor/scs/linsys/external/amd/amd_2.o +0 -0
  80. data/vendor/scs/linsys/external/amd/amd_aat.o +0 -0
  81. data/vendor/scs/linsys/external/amd/amd_control.o +0 -0
  82. data/vendor/scs/linsys/external/amd/amd_defaults.o +0 -0
  83. data/vendor/scs/linsys/external/amd/amd_dump.o +0 -0
  84. data/vendor/scs/linsys/external/amd/amd_global.o +0 -0
  85. data/vendor/scs/linsys/external/amd/amd_info.o +0 -0
  86. data/vendor/scs/linsys/external/amd/amd_order.o +0 -0
  87. data/vendor/scs/linsys/external/amd/amd_post_tree.o +0 -0
  88. data/vendor/scs/linsys/external/amd/amd_postorder.o +0 -0
  89. data/vendor/scs/linsys/external/amd/amd_preprocess.o +0 -0
  90. data/vendor/scs/linsys/external/amd/amd_valid.o +0 -0
  91. data/vendor/scs/linsys/external/qdldl/qdldl.o +0 -0
  92. data/vendor/scs/src/aa.o +0 -0
  93. data/vendor/scs/src/cones.o +0 -0
  94. data/vendor/scs/src/ctrlc.o +0 -0
  95. data/vendor/scs/src/linalg.o +0 -0
  96. data/vendor/scs/src/normalize.o +0 -0
  97. data/vendor/scs/src/rw.o +0 -0
  98. data/vendor/scs/src/scs.o +0 -0
  99. data/vendor/scs/src/scs_version.o +0 -0
  100. data/vendor/scs/src/util.o +0 -0
  101. data/vendor/scs/test/data/small_random_socp +0 -0
  102. data/vendor/scs/test/problems/small_random_socp.h +0 -33
  103. data/vendor/scs/test/run_tests +0 -2
@@ -1,43 +1,57 @@
1
1
  #include "private.h"
2
+ #include "linsys.h"
3
+ #include "util.h"
4
+ #include <limits.h>
2
5
 
3
- #define CG_BEST_TOL 1e-9
4
- #define CG_MIN_TOL 1e-1
5
-
6
- char *SCS(get_lin_sys_method)(const ScsMatrix *A, const ScsSettings *stgs) {
7
- char *str = (char *)scs_malloc(sizeof(char) * 128);
8
- sprintf(str, "sparse-indirect, nnz in A = %li, CG tol ~ 1/iter^(%2.2f)",
9
- (long)A->p[A->n], stgs->cg_rate);
10
- return str;
6
+ const char *SCS(get_lin_sys_method)() {
7
+ return "sparse-indirect";
11
8
  }
12
9
 
10
+ /*
13
11
  char *SCS(get_lin_sys_summary)(ScsLinSysWork *p, const ScsInfo *info) {
14
12
  char *str = (char *)scs_malloc(sizeof(char) * 128);
15
- sprintf(str,
16
- "\tLin-sys: avg # CG iterations: %2.2f, avg solve time: %1.2es\n",
17
- (scs_float)p->tot_cg_its / (info->iter + 1),
18
- p->total_solve_time / (info->iter + 1) / 1e3);
13
+ sprintf(str, "lin-sys: avg cg its: %2.2f\n",
14
+ (scs_float)p->tot_cg_its / (info->iter + 1));
19
15
  p->tot_cg_its = 0;
20
- p->total_solve_time = 0;
21
16
  return str;
22
17
  }
18
+ */
23
19
 
24
- /* M = inv ( diag ( RHO_X * I + A'A ) ) */
25
- static void get_preconditioner(const ScsMatrix *A, const ScsSettings *stgs,
26
- ScsLinSysWork *p) {
27
- scs_int i;
20
+ /* Not possible to do this on the fly due to M_ii += a_i' (R_y)^-1 a_i */
21
+ /* set M = inv ( diag ( R_x + P + A' R_y^{-1} A ) ) */
22
+ static void set_preconditioner(ScsLinSysWork *p) {
23
+ scs_int i, k;
28
24
  scs_float *M = p->M;
25
+ const ScsMatrix *A = p->A;
26
+ const ScsMatrix *P = p->P;
29
27
 
30
- #if EXTRA_VERBOSE > 0
28
+ #if VERBOSITY > 0
31
29
  scs_printf("getting pre-conditioner\n");
32
30
  #endif
33
31
 
34
- for (i = 0; i < A->n; ++i) {
35
- M[i] = 1 / (stgs->rho_x +
36
- SCS(norm_sq)(&(A->x[A->p[i]]), A->p[i + 1] - A->p[i]));
37
- /* M[i] = 1; */
32
+ /* M_ii = (R_x)_i + P_ii + a_i' (R_y)^-1 a_i */
33
+ for (i = 0; i < A->n; ++i) { /* cols */
34
+ /* M_ii = (R_x)_i */
35
+ M[i] = p->diag_r[i];
36
+ /* M_ii += a_i' (R_y)^-1 a_i */
37
+ for (k = A->p[i]; k < A->p[i + 1]; ++k) {
38
+ /* A->i[k] is row of entry k with value A->x[k] */
39
+ M[i] += A->x[k] * A->x[k] / p->diag_r[A->n + A->i[k]];
40
+ }
41
+ if (P) {
42
+ for (k = P->p[i]; k < P->p[i + 1]; k++) {
43
+ /* diagonal element only */
44
+ if (P->i[k] == i) { /* row == col */
45
+ /* M_ii += P_ii */
46
+ M[i] += P->x[k];
47
+ break;
48
+ }
49
+ }
50
+ }
51
+ /* finally invert for pre-conditioner */
52
+ M[i] = 1. / M[i];
38
53
  }
39
-
40
- #if EXTRA_VERBOSE > 0
54
+ #if VERBOSITY > 0
41
55
  scs_printf("finished getting pre-conditioner\n");
42
56
  #endif
43
57
  }
@@ -54,15 +68,16 @@ static void transpose(const ScsMatrix *A, ScsLinSysWork *p) {
54
68
  scs_float *Ax = A->x;
55
69
 
56
70
  scs_int i, j, q, *z, c1, c2;
57
- #if EXTRA_VERBOSE > 0
71
+ #if VERBOSITY > 0
58
72
  SCS(timer) transpose_timer;
59
73
  scs_printf("transposing A\n");
60
74
  SCS(tic)(&transpose_timer);
61
75
  #endif
62
76
 
63
77
  z = (scs_int *)scs_calloc(m, sizeof(scs_int));
64
- for (i = 0; i < Ap[n]; i++) z[Ai[i]]++; /* row counts */
65
- SCS(cumsum)(Cp, z, m); /* row pointers */
78
+ for (i = 0; i < Ap[n]; i++)
79
+ z[Ai[i]]++; /* row counts */
80
+ SCS(cumsum)(Cp, z, m); /* row pointers */
66
81
 
67
82
  for (j = 0; j < n; j++) {
68
83
  c1 = Ap[j];
@@ -76,7 +91,7 @@ static void transpose(const ScsMatrix *A, ScsLinSysWork *p) {
76
91
  }
77
92
  scs_free(z);
78
93
 
79
- #if EXTRA_VERBOSE > 0
94
+ #if VERBOSITY > 0
80
95
  scs_printf("finished transposing A, time: %1.2es\n",
81
96
  SCS(tocq)(&transpose_timer) / 1e3);
82
97
  #endif
@@ -100,60 +115,86 @@ void SCS(free_lin_sys_work)(ScsLinSysWork *p) {
100
115
  }
101
116
  }
102
117
 
103
- /*y = (RHO_X * I + A'A)x */
104
- static void mat_vec(const ScsMatrix *A, const ScsSettings *s, ScsLinSysWork *p,
105
- const scs_float *x, scs_float *y) {
106
- scs_float *tmp = p->tmp;
107
- memset(tmp, 0, A->m * sizeof(scs_float));
108
- SCS(accum_by_a)(A, p, x, tmp);
109
- memset(y, 0, A->n * sizeof(scs_float));
110
- SCS(accum_by_atrans)(A, p, tmp, y);
111
- SCS(add_scaled_array)(y, x, A->n, s->rho_x);
118
+ /* vec -> R_y^{-1} vec */
119
+ static void scale_by_r_y_inv(scs_float *vec, ScsLinSysWork *p) {
120
+ scs_int i;
121
+ for (i = 0; i < p->m; ++i) {
122
+ vec[i] /= p->diag_r[p->n + i];
123
+ }
124
+ }
125
+
126
+ /* y += R_x * x */
127
+ static void accum_by_r_x(scs_float *y, const scs_float *x, ScsLinSysWork *p) {
128
+ scs_int i;
129
+ for (i = 0; i < p->n; ++i) {
130
+ y[i] += p->diag_r[i] * x[i];
131
+ }
112
132
  }
113
133
 
114
- void SCS(accum_by_atrans)(const ScsMatrix *A, ScsLinSysWork *p,
115
- const scs_float *x, scs_float *y) {
116
- SCS(_accum_by_atrans)(A->n, A->x, A->i, A->p, x, y);
134
+ /* we use a different accum_by_a here for speed */
135
+ static void accum_by_a(ScsLinSysWork *p, const scs_float *x, scs_float *y) {
136
+ SCS(accum_by_atrans)(p->At, x, y);
117
137
  }
118
138
 
119
- void SCS(accum_by_a)(const ScsMatrix *A, ScsLinSysWork *p, const scs_float *x,
120
- scs_float *y) {
121
- SCS(_accum_by_atrans)(p->At->n, p->At->x, p->At->i, p->At->p, x, y);
139
+ /* y = (R_x + P + A' R_y^{-1} A) x */
140
+ static void mat_vec(const ScsMatrix *A, const ScsMatrix *P, ScsLinSysWork *p,
141
+ const scs_float *x, scs_float *y) {
142
+ scs_float *z = p->tmp;
143
+ memset(z, 0, A->m * sizeof(scs_float)); /* z = 0 */
144
+ memset(y, 0, A->n * sizeof(scs_float)); /* y = 0 */
145
+ if (P) {
146
+ SCS(accum_by_p)(P, x, y); /* y = Px */
147
+ }
148
+ accum_by_a(p, x, z); /* z = Ax */
149
+ scale_by_r_y_inv(z, p); /* z = R_y^{-1} A x */
150
+ SCS(accum_by_atrans)(A, z, y); /* y += A'z, y = Px + A' R_y^{-1} Ax */
151
+ /* y = R_x * x + Px + A' R_y^{-1} A * x */
152
+ accum_by_r_x(y, x, p);
122
153
  }
123
154
 
124
- static void apply_pre_conditioner(scs_float *M, scs_float *z, scs_float *r,
125
- scs_int n, scs_float *ipzr) {
155
+ static void apply_pre_conditioner(scs_float *z, scs_float *r, scs_int n,
156
+ ScsLinSysWork *pr) {
126
157
  scs_int i;
127
- *ipzr = 0;
158
+ scs_float *M = pr->M;
128
159
  for (i = 0; i < n; ++i) {
129
160
  z[i] = r[i] * M[i];
130
- *ipzr += z[i] * r[i];
131
161
  }
132
162
  }
133
163
 
134
- ScsLinSysWork *SCS(init_lin_sys_work)(const ScsMatrix *A,
135
- const ScsSettings *stgs) {
164
+ /* no need to update anything in this case */
165
+ void SCS(update_lin_sys_diag_r)(ScsLinSysWork *p, const scs_float *diag_r) {
166
+ p->diag_r = diag_r; /* this isn't needed but do it to be safe */
167
+ set_preconditioner(p);
168
+ }
169
+
170
+ ScsLinSysWork *SCS(init_lin_sys_work)(const ScsMatrix *A, const ScsMatrix *P,
171
+ const scs_float *diag_r) {
136
172
  ScsLinSysWork *p = (ScsLinSysWork *)scs_calloc(1, sizeof(ScsLinSysWork));
137
- p->p = (scs_float *)scs_malloc((A->n) * sizeof(scs_float));
138
- p->r = (scs_float *)scs_malloc((A->n) * sizeof(scs_float));
139
- p->Gp = (scs_float *)scs_malloc((A->n) * sizeof(scs_float));
140
- p->tmp = (scs_float *)scs_malloc((A->m) * sizeof(scs_float));
173
+ p->A = A;
174
+ p->P = P;
175
+ p->m = A->m;
176
+ p->n = A->n;
177
+
178
+ p->p = (scs_float *)scs_calloc((A->n), sizeof(scs_float));
179
+ p->r = (scs_float *)scs_calloc((A->n), sizeof(scs_float));
180
+ p->Gp = (scs_float *)scs_calloc((A->n), sizeof(scs_float));
181
+ p->tmp = (scs_float *)scs_calloc((A->m), sizeof(scs_float));
141
182
 
142
183
  /* memory for A transpose */
143
- p->At = (ScsMatrix *)scs_malloc(sizeof(ScsMatrix));
184
+ p->At = (ScsMatrix *)scs_calloc(1, sizeof(ScsMatrix));
144
185
  p->At->m = A->n;
145
186
  p->At->n = A->m;
146
- p->At->i = (scs_int *)scs_malloc((A->p[A->n]) * sizeof(scs_int));
147
- p->At->p = (scs_int *)scs_malloc((A->m + 1) * sizeof(scs_int));
148
- p->At->x = (scs_float *)scs_malloc((A->p[A->n]) * sizeof(scs_float));
187
+ p->At->i = (scs_int *)scs_calloc((A->p[A->n]), sizeof(scs_int));
188
+ p->At->p = (scs_int *)scs_calloc((A->m + 1), sizeof(scs_int));
189
+ p->At->x = (scs_float *)scs_calloc((A->p[A->n]), sizeof(scs_float));
149
190
  transpose(A, p);
150
191
 
151
192
  /* preconditioner memory */
152
- p->z = (scs_float *)scs_malloc((A->n) * sizeof(scs_float));
153
- p->M = (scs_float *)scs_malloc((A->n) * sizeof(scs_float));
154
- get_preconditioner(A, stgs, p);
193
+ p->diag_r = diag_r;
194
+ p->z = (scs_float *)scs_calloc(A->n, sizeof(scs_float));
195
+ p->M = (scs_float *)scs_calloc(A->n, sizeof(scs_float));
196
+ set_preconditioner(p);
155
197
 
156
- p->total_solve_time = 0;
157
198
  p->tot_cg_its = 0;
158
199
  if (!p->p || !p->r || !p->Gp || !p->tmp || !p->At || !p->At->i || !p->At->p ||
159
200
  !p->At->x) {
@@ -163,94 +204,129 @@ ScsLinSysWork *SCS(init_lin_sys_work)(const ScsMatrix *A,
163
204
  return p;
164
205
  }
165
206
 
166
- /* solves (I+A'A)x = b, s warm start, solution stored in b */
167
- static scs_int pcg(const ScsMatrix *A, const ScsSettings *stgs,
168
- ScsLinSysWork *pr, const scs_float *s, scs_float *b,
207
+ /* solves (R_x * I + P + A' R_y^{-1} A)x = b, s warm start, solution in b */
208
+ static scs_int pcg(ScsLinSysWork *pr, const scs_float *s, scs_float *b,
169
209
  scs_int max_its, scs_float tol) {
170
- scs_int i, n = A->n;
171
- scs_float ipzr, ipzr_old, alpha;
210
+ scs_int i, n = pr->n;
211
+ scs_float ztr, ztr_prev, alpha;
172
212
  scs_float *p = pr->p; /* cg direction */
173
213
  scs_float *Gp = pr->Gp; /* updated CG direction */
174
214
  scs_float *r = pr->r; /* cg residual */
175
215
  scs_float *z = pr->z; /* for preconditioning */
176
- scs_float *M = pr->M; /* inverse diagonal preconditioner */
177
216
 
178
- if (s == SCS_NULL) {
217
+ const ScsMatrix *A = pr->A;
218
+ const ScsMatrix *P = pr->P;
219
+
220
+ if (!s) {
221
+ /* take s = 0 */
222
+ /* r = b */
179
223
  memcpy(r, b, n * sizeof(scs_float));
224
+ /* b = 0 */
180
225
  memset(b, 0, n * sizeof(scs_float));
181
226
  } else {
182
- mat_vec(A, stgs, pr, s, r);
183
- SCS(add_scaled_array)(r, b, n, -1);
184
- SCS(scale_array)(r, -1, n);
227
+ /* r = Mat * s */
228
+ mat_vec(A, P, pr, s, r);
229
+ /* r = Mat * s - b */
230
+ SCS(add_scaled_array)(r, b, n, -1.);
231
+ /* r = b - Mat * s */
232
+ SCS(scale_array)(r, -1., n);
233
+ /* b = s */
185
234
  memcpy(b, s, n * sizeof(scs_float));
186
235
  }
187
236
 
188
237
  /* check to see if we need to run CG at all */
189
- if (SCS(norm)(r, n) < MIN(tol, 1e-18)) {
238
+ if (CG_NORM(r, n) < MAX(tol, 1e-12)) {
190
239
  return 0;
191
240
  }
192
241
 
193
- apply_pre_conditioner(M, z, r, n, &ipzr);
242
+ /* z = M r (M is inverse preconditioner) */
243
+ apply_pre_conditioner(z, r, n, pr);
244
+ /* ztr = z'r */
245
+ ztr = SCS(dot)(z, r, n);
246
+ /* p = z */
194
247
  memcpy(p, z, n * sizeof(scs_float));
195
248
 
196
249
  for (i = 0; i < max_its; ++i) {
197
- mat_vec(A, stgs, pr, p, Gp);
198
- alpha = ipzr / SCS(dot)(p, Gp, n);
250
+ /* Gp = Mat * p */
251
+ mat_vec(A, P, pr, p, Gp);
252
+ /* alpha = z'r / p'G p */
253
+ alpha = ztr / SCS(dot)(p, Gp, n);
254
+ /* b += alpha * p */
199
255
  SCS(add_scaled_array)(b, p, n, alpha);
256
+ /* r -= alpha * G p */
200
257
  SCS(add_scaled_array)(r, Gp, n, -alpha);
201
258
 
202
- if (SCS(norm)(r, n) < tol) {
203
- #if EXTRA_VERBOSE > 0
204
- scs_printf("tol: %.4e, resid: %.4e, iters: %li\n", tol, SCS(norm)(r, n),
205
- (long)i + 1);
259
+ #if VERBOSITY > 3
260
+ scs_printf("tol: %.4e, resid: %.4e, iters: %li\n", tol, CG_NORM(r, n),
261
+ (long)i + 1);
206
262
  #endif
263
+ if (CG_NORM(r, n) < tol) {
207
264
  return i + 1;
208
265
  }
209
- ipzr_old = ipzr;
210
- apply_pre_conditioner(M, z, r, n, &ipzr);
211
-
212
- SCS(scale_array)(p, ipzr / ipzr_old, n);
213
- SCS(add_scaled_array)(p, z, n, 1);
266
+ /* z = M r (M is inverse preconditioner) */
267
+ apply_pre_conditioner(z, r, n, pr);
268
+ ztr_prev = ztr;
269
+ /* ztr = z'r */
270
+ ztr = SCS(dot)(z, r, n);
271
+ /* p = beta * p, where beta = ztr / ztr_prev */
272
+ SCS(scale_array)(p, ztr / ztr_prev, n);
273
+ /* p = z + beta * p */
274
+ SCS(add_scaled_array)(p, z, n, 1.);
214
275
  }
215
276
  return i;
216
277
  }
217
278
 
218
- scs_int SCS(solve_lin_sys)(const ScsMatrix *A, const ScsSettings *stgs,
219
- ScsLinSysWork *p, scs_float *b, const scs_float *s,
220
- scs_int iter) {
221
- scs_int cg_its;
222
- SCS(timer) linsys_timer;
223
- scs_float cg_tol =
224
- SCS(norm)(b, A->n) *
225
- (iter < 0 ? CG_BEST_TOL
226
- : CG_MIN_TOL / POWF((scs_float)iter + 1, stgs->cg_rate));
227
-
228
- SCS(tic)(&linsys_timer);
229
- /* solves Mx = b, for x but stores result in b */
230
- /* s contains warm-start (if available) */
231
- SCS(accum_by_atrans)(A, p, &(b[A->n]), b);
232
- /* solves (I+A'A)x = b, s warm start, solution stored in b */
233
- cg_its = pcg(A, stgs, p, s, b, A->n, MAX(cg_tol, CG_BEST_TOL));
234
- SCS(scale_array)(&(b[A->n]), -1, A->m);
235
- SCS(accum_by_a)(A, p, b, &(b[A->n]));
236
-
237
- if (iter >= 0) {
238
- p->tot_cg_its += cg_its;
279
+ /* solves Mx = b, for x but stores result in b */
280
+ /* s contains warm-start (if available) */
281
+ /*
282
+ * [x] = [R_x + P A' ]^{-1} [rx]
283
+ * [y] [ A -R_y ] [ry]
284
+ *
285
+ * becomes:
286
+ *
287
+ * x = (R_x + P + A' R_y^{-1} A)^{-1} (rx + A' R_y^{-1} ry)
288
+ * y = R_y^{-1} (Ax - ry)
289
+ *
290
+ */
291
+ scs_int SCS(solve_lin_sys)(ScsLinSysWork *p, scs_float *b, const scs_float *s,
292
+ scs_float tol) {
293
+ scs_int cg_its, max_iters;
294
+
295
+ if (tol <= 0.) {
296
+ scs_printf("Warning: tol = %4f <= 0, likely compiled without setting "
297
+ "INDIRECT flag.\n",
298
+ tol);
239
299
  }
240
300
 
241
- p->total_solve_time += SCS(tocq)(&linsys_timer);
242
- #if EXTRA_VERBOSE > 0
243
- scs_printf("linsys solve time: %1.2es\n", SCS(tocq)(&linsys_timer) / 1e3);
301
+ if (CG_NORM(b, p->n + p->m) <= 1e-12) {
302
+ memset(b, 0, (p->n + p->m) * sizeof(scs_float));
303
+ return 0;
304
+ }
305
+
306
+ /* use p->tmp here, and in mat_vec, can do both since they don't overlap */
307
+ /* b = [rx; ry] */
308
+ /* tmp = ry */
309
+ memcpy(p->tmp, &(b[p->n]), p->m * sizeof(scs_float));
310
+ /* tmp = R_y^{-1} * ry */
311
+ scale_by_r_y_inv(p->tmp, p);
312
+ /* b[:n] = rx + A' R_y^{-1} ry */
313
+ SCS(accum_by_atrans)(p->A, p->tmp, b);
314
+ /* set max_iters to 10 * n (though in theory n is enough for any tol) */
315
+ max_iters = 10 * p->n;
316
+ /* solves (R_x + P + A' R_y^{-1} A)x = b, s warm start, solution stored in
317
+ * b */
318
+ cg_its = pcg(p, s, b, max_iters, tol); /* b[:n] = x */
319
+
320
+ /* b[n:] = -ry */
321
+ SCS(scale_array)(&(b[p->n]), -1., p->m);
322
+ /* b[n:] = Ax - ry */
323
+ accum_by_a(p, b, &(b[p->n]));
324
+ /* b[n:] = R_y^{-1} (Ax - ry) = y */
325
+ scale_by_r_y_inv(&(b[p->n]), p);
326
+ p->tot_cg_its += cg_its;
327
+ #if VERBOSITY > 1
328
+ scs_printf("tol %.3e\n", tol);
329
+ scs_printf("cg_its %i\n", (int)cg_its);
244
330
  #endif
245
331
  return 0;
246
332
  }
247
-
248
- void SCS(normalize_a)(ScsMatrix *A, const ScsSettings *stgs, const ScsCone *k,
249
- ScsScaling *scal) {
250
- SCS(_normalize_a)(A, stgs, k, scal);
251
- }
252
-
253
- void SCS(un_normalize_a)(ScsMatrix *A, const ScsSettings *stgs,
254
- const ScsScaling *scal) {
255
- SCS(_un_normalize_a)(A, stgs, scal);
256
- }
@@ -5,24 +5,27 @@
5
5
  extern "C" {
6
6
  #endif
7
7
 
8
- #include <math.h>
9
- #include "amatrix.h"
10
8
  #include "glbopts.h"
11
9
  #include "linalg.h"
12
10
  #include "scs.h"
11
+ #include "scs_matrix.h"
12
+ #include <math.h>
13
13
 
14
14
  struct SCS_LIN_SYS_WORK {
15
+ scs_int n, m; /* linear system dimensions */
15
16
  scs_float *p; /* cg iterate */
16
17
  scs_float *r; /* cg residual */
17
18
  scs_float *Gp;
18
19
  scs_float *tmp;
19
- ScsMatrix *At;
20
+ const ScsMatrix *A; /* does *not* own this memory */
21
+ const ScsMatrix *P; /* does *not* own this memory */
22
+ ScsMatrix *At; /* does own this memory */
20
23
  /* preconditioning */
21
24
  scs_float *z;
22
25
  scs_float *M;
23
26
  /* reporting */
24
27
  scs_int tot_cg_its;
25
- scs_float total_solve_time;
28
+ const scs_float *diag_r;
26
29
  };
27
30
 
28
31
  #ifdef __cplusplus
@@ -0,0 +1,87 @@
1
+ /* Routines modified from CSparse, T. Davis et al */
2
+
3
+ #include "csparse.h"
4
+
5
+ csc *SCS(cs_spalloc)(scs_int m, scs_int n, scs_int nzmax, scs_int values,
6
+ scs_int triplet) {
7
+ csc *A = (csc *)scs_calloc(1, sizeof(csc)); /* allocate the csc struct */
8
+ if (!A) {
9
+ return SCS_NULL;
10
+ } /* out of memory */
11
+ A->m = m; /* define dimensions and nzmax */
12
+ A->n = n;
13
+ A->nzmax = nzmax = MAX(nzmax, 1);
14
+ A->nz = triplet ? 0 : -1; /* allocate triplet or comp.col */
15
+ A->p = (scs_int *)scs_calloc((triplet ? nzmax : n + 1), sizeof(scs_int));
16
+ A->i = (scs_int *)scs_calloc(nzmax, sizeof(scs_int));
17
+ A->x = values ? (scs_float *)scs_calloc(nzmax, sizeof(scs_float)) : SCS_NULL;
18
+ return (!A->p || !A->i || (values && !A->x)) ? SCS(cs_spfree)(A) : A;
19
+ }
20
+
21
+ csc *SCS(cs_done)(csc *C, void *w, void *x, scs_int ok) {
22
+ scs_free(w); /* free workspace */
23
+ scs_free(x);
24
+ return ok ? C : SCS(cs_spfree)(C); /* return result if OK, else free it */
25
+ }
26
+
27
+ /* C = compressed-column form of a triplet matrix T */
28
+ csc *SCS(cs_compress)(const csc *T, scs_int *idx_mapping) {
29
+ scs_int m, n, nz, p, k, *Cp, *Ci, *w, *Ti, *Tj;
30
+ scs_float *Cx, *Tx;
31
+ csc *C;
32
+ m = T->m;
33
+ n = T->n;
34
+ Ti = T->i;
35
+ Tj = T->p;
36
+ Tx = T->x;
37
+ nz = T->nz;
38
+ C = SCS(cs_spalloc)(m, n, nz, Tx != SCS_NULL, 0); /* allocate result */
39
+ w = (scs_int *)scs_calloc(n, sizeof(scs_int)); /* get workspace */
40
+ if (!C || !w) {
41
+ return SCS(cs_done)(C, w, SCS_NULL, 0);
42
+ } /* out of memory */
43
+ Cp = C->p;
44
+ Ci = C->i;
45
+ Cx = C->x;
46
+ for (k = 0; k < nz; k++) {
47
+ w[Tj[k]]++; /* column counts */
48
+ }
49
+ SCS(cumsum)(Cp, w, n); /* column pointers */
50
+ for (k = 0; k < nz; k++) {
51
+ Ci[p = w[Tj[k]]++] = Ti[k]; /* A(i,j) is the pth entry in C */
52
+ if (idx_mapping) {
53
+ idx_mapping[k] = p;
54
+ } /* old to new indices */
55
+ if (Cx) {
56
+ Cx[p] = Tx[k];
57
+ }
58
+ }
59
+ return SCS(cs_done)(C, w, SCS_NULL, 1); /* success; free w and return C */
60
+ }
61
+
62
+ scs_float SCS(cumsum)(scs_int *p, scs_int *c, scs_int n) {
63
+ scs_int i, nz = 0;
64
+ scs_float nz2 = 0;
65
+ if (!p || !c) {
66
+ return (-1);
67
+ } /* check inputs */
68
+ for (i = 0; i < n; i++) {
69
+ p[i] = nz;
70
+ nz += c[i];
71
+ nz2 += c[i]; /* also in scs_float to avoid scs_int overflow */
72
+ c[i] = p[i]; /* also copy p[0..n-1] back into c[0..n-1]*/
73
+ }
74
+ p[n] = nz;
75
+ return nz2; /* return sum (c [0..n-1]) */
76
+ }
77
+
78
+ csc *SCS(cs_spfree)(csc *A) {
79
+ if (!A) {
80
+ return SCS_NULL;
81
+ } /* do nothing if A already SCS_NULL */
82
+ scs_free(A->p);
83
+ scs_free(A->i);
84
+ scs_free(A->x);
85
+ scs_free(A);
86
+ return (csc *)SCS_NULL; /* free the csc struct and return SCS_NULL */
87
+ }
@@ -0,0 +1,34 @@
1
+ /* Routines modified from CSparse, T. Davis et al */
2
+
3
+ #ifndef CS_H_GUARD
4
+ #define CS_H_GUARD
5
+
6
+ #ifdef __cplusplus
7
+ extern "C" {
8
+ #endif
9
+
10
+ #include "glbopts.h"
11
+ #include "scs.h"
12
+
13
+ /* matrix in compressed-column or triplet form */
14
+ typedef struct SPARSE_MATRIX {
15
+ scs_int nzmax; /* maximum number of entries */
16
+ scs_int m; /* number of rows */
17
+ scs_int n; /* number of columns */
18
+ scs_int *p; /* column pointers (size n+1) or col indices (size nzmax) */
19
+ scs_int *i; /* row indices, size nzmax */
20
+ scs_float *x; /* numerical values, size nzmax */
21
+ scs_int nz; /* # of entries in triplet matrix, -1 for compressed-col */
22
+ } csc;
23
+
24
+ csc *SCS(cs_spalloc)(scs_int m, scs_int n, scs_int nzmax, scs_int values,
25
+ scs_int triplet);
26
+ csc *SCS(cs_done)(csc *C, void *w, void *x, scs_int ok);
27
+ csc *SCS(cs_compress)(const csc *T, scs_int *idx_mapping);
28
+ scs_float SCS(cumsum)(scs_int *p, scs_int *c, scs_int n);
29
+ csc *SCS(cs_spfree)(csc *A);
30
+
31
+ #ifdef __cplusplus
32
+ }
33
+ #endif
34
+ #endif
@@ -18,7 +18,6 @@
18
18
 
19
19
  #ifdef MATLAB_MEX_FILE
20
20
  #include "mex.h"
21
- #include "matrix.h"
22
21
  #endif
23
22
 
24
23
  #ifndef NULL
@@ -51,7 +50,7 @@
51
50
 
52
51
  struct SuiteSparse_config_struct SuiteSparse_config =
53
52
  {
54
- _scs_malloc, _scs_calloc, _scs_realloc, _scs_free, _scs_printf,
53
+ scs_malloc, scs_calloc, scs_realloc, scs_free, _scs_printf,
55
54
  SuiteSparse_hypot,
56
55
  SuiteSparse_divcomplex
57
56
 
@@ -73,12 +72,13 @@ struct SuiteSparse_config_struct SuiteSparse_config =
73
72
  SuiteSparse_start be called prior to calling any SuiteSparse function.
74
73
  */
75
74
 
75
+
76
76
  void SuiteSparse_start ( void )
77
77
  {
78
- SuiteSparse_config.malloc_func = _scs_malloc ;
79
- SuiteSparse_config.calloc_func = _scs_calloc ;
80
- SuiteSparse_config.realloc_func = _scs_realloc ;
81
- SuiteSparse_config.free_func = _scs_free ;
78
+ SuiteSparse_config.malloc_func = scs_malloc ;
79
+ SuiteSparse_config.calloc_func = scs_calloc ;
80
+ SuiteSparse_config.realloc_func = scs_realloc ;
81
+ SuiteSparse_config.free_func = scs_free ;
82
82
  SuiteSparse_config.printf_func = _scs_printf ;
83
83
  /* math functions */
84
84
  SuiteSparse_config.hypot_func = SuiteSparse_hypot ;
@@ -44,7 +44,7 @@ extern "C" {
44
44
 
45
45
  #include <limits.h>
46
46
  #include <stdlib.h>
47
- #include "scs.h"
47
+ #include "glbopts.h"
48
48
  #include "ctrlc.h"
49
49
 
50
50
  /* ========================================================================== */
@@ -71,6 +71,11 @@ extern "C" {
71
71
  #define SuiteSparse_long_id "%" SuiteSparse_long_idd
72
72
  #endif
73
73
 
74
+ #ifndef _scs_printf
75
+ #define _scs_printf scs_printf
76
+ #endif
77
+
78
+
74
79
  /* ========================================================================== */
75
80
  /* === SuiteSparse_config parameters and functions ========================== */
76
81
  /* ========================================================================== */
@@ -66,7 +66,7 @@
66
66
  /* ------------------------------------------------------------------------- */
67
67
 
68
68
  #ifdef MATLAB_MEX_FILE
69
- #include "matrix.h"
69
+ #include "scs_matrix.h"
70
70
  #include "mex.h"
71
71
  #endif
72
72
 
@@ -89,8 +89,8 @@ GLOBAL Int AMD_order
89
89
  }
90
90
 
91
91
  /* allocate two size-n integer workspaces */
92
- Len = SuiteSparse_malloc (n, sizeof (Int)) ;
93
- Pinv = SuiteSparse_malloc (n, sizeof (Int)) ;
92
+ Len = (Int *)SuiteSparse_malloc (n, sizeof (Int)) ;
93
+ Pinv = (Int *)SuiteSparse_malloc (n, sizeof (Int)) ;
94
94
  mem += n ;
95
95
  mem += n ;
96
96
  if (!Len || !Pinv)
@@ -106,8 +106,8 @@ GLOBAL Int AMD_order
106
106
  {
107
107
  /* sort the input matrix and remove duplicate entries */
108
108
  AMD_DEBUG1 (("Matrix is jumbled\n")) ;
109
- Rp = SuiteSparse_malloc (n+1, sizeof (Int)) ;
110
- Ri = SuiteSparse_malloc (nz, sizeof (Int)) ;
109
+ Rp = (Int *)SuiteSparse_malloc (n+1, sizeof (Int)) ;
110
+ Ri = (Int *)SuiteSparse_malloc (nz, sizeof (Int)) ;
111
111
  mem += (n+1) ;
112
112
  mem += MAX (nz,1) ;
113
113
  if (!Rp || !Ri)
@@ -160,7 +160,7 @@ GLOBAL Int AMD_order
160
160
  ok = ok && (slen < Int_MAX) ; /* S[i] for Int i must be OK */
161
161
  if (ok)
162
162
  {
163
- S = SuiteSparse_malloc (slen, sizeof (Int)) ;
163
+ S = (Int *)SuiteSparse_malloc (slen, sizeof (Int)) ;
164
164
  }
165
165
  AMD_DEBUG1 (("slen %g\n", (scs_float) slen)) ;
166
166
  if (!S)