scs 0.2.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 (106) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +12 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +98 -0
  5. data/ext/scs/extconf.rb +29 -0
  6. data/lib/scs.rb +17 -0
  7. data/lib/scs/ffi.rb +117 -0
  8. data/lib/scs/solver.rb +173 -0
  9. data/lib/scs/version.rb +3 -0
  10. data/vendor/scs/LICENSE.txt +21 -0
  11. data/vendor/scs/Makefile +164 -0
  12. data/vendor/scs/README.md +222 -0
  13. data/vendor/scs/include/aa.h +56 -0
  14. data/vendor/scs/include/cones.h +46 -0
  15. data/vendor/scs/include/ctrlc.h +33 -0
  16. data/vendor/scs/include/glbopts.h +177 -0
  17. data/vendor/scs/include/linalg.h +26 -0
  18. data/vendor/scs/include/linsys.h +64 -0
  19. data/vendor/scs/include/normalize.h +18 -0
  20. data/vendor/scs/include/rw.h +17 -0
  21. data/vendor/scs/include/scs.h +161 -0
  22. data/vendor/scs/include/scs_blas.h +51 -0
  23. data/vendor/scs/include/util.h +65 -0
  24. data/vendor/scs/linsys/amatrix.c +305 -0
  25. data/vendor/scs/linsys/amatrix.h +36 -0
  26. data/vendor/scs/linsys/amatrix.o +0 -0
  27. data/vendor/scs/linsys/cpu/direct/private.c +366 -0
  28. data/vendor/scs/linsys/cpu/direct/private.h +26 -0
  29. data/vendor/scs/linsys/cpu/direct/private.o +0 -0
  30. data/vendor/scs/linsys/cpu/indirect/private.c +256 -0
  31. data/vendor/scs/linsys/cpu/indirect/private.h +31 -0
  32. data/vendor/scs/linsys/cpu/indirect/private.o +0 -0
  33. data/vendor/scs/linsys/external/amd/LICENSE.txt +934 -0
  34. data/vendor/scs/linsys/external/amd/SuiteSparse_config.c +469 -0
  35. data/vendor/scs/linsys/external/amd/SuiteSparse_config.h +254 -0
  36. data/vendor/scs/linsys/external/amd/SuiteSparse_config.o +0 -0
  37. data/vendor/scs/linsys/external/amd/amd.h +400 -0
  38. data/vendor/scs/linsys/external/amd/amd_1.c +180 -0
  39. data/vendor/scs/linsys/external/amd/amd_1.o +0 -0
  40. data/vendor/scs/linsys/external/amd/amd_2.c +1842 -0
  41. data/vendor/scs/linsys/external/amd/amd_2.o +0 -0
  42. data/vendor/scs/linsys/external/amd/amd_aat.c +184 -0
  43. data/vendor/scs/linsys/external/amd/amd_aat.o +0 -0
  44. data/vendor/scs/linsys/external/amd/amd_control.c +64 -0
  45. data/vendor/scs/linsys/external/amd/amd_control.o +0 -0
  46. data/vendor/scs/linsys/external/amd/amd_defaults.c +37 -0
  47. data/vendor/scs/linsys/external/amd/amd_defaults.o +0 -0
  48. data/vendor/scs/linsys/external/amd/amd_dump.c +179 -0
  49. data/vendor/scs/linsys/external/amd/amd_dump.o +0 -0
  50. data/vendor/scs/linsys/external/amd/amd_global.c +16 -0
  51. data/vendor/scs/linsys/external/amd/amd_global.o +0 -0
  52. data/vendor/scs/linsys/external/amd/amd_info.c +119 -0
  53. data/vendor/scs/linsys/external/amd/amd_info.o +0 -0
  54. data/vendor/scs/linsys/external/amd/amd_internal.h +304 -0
  55. data/vendor/scs/linsys/external/amd/amd_order.c +199 -0
  56. data/vendor/scs/linsys/external/amd/amd_order.o +0 -0
  57. data/vendor/scs/linsys/external/amd/amd_post_tree.c +120 -0
  58. data/vendor/scs/linsys/external/amd/amd_post_tree.o +0 -0
  59. data/vendor/scs/linsys/external/amd/amd_postorder.c +206 -0
  60. data/vendor/scs/linsys/external/amd/amd_postorder.o +0 -0
  61. data/vendor/scs/linsys/external/amd/amd_preprocess.c +118 -0
  62. data/vendor/scs/linsys/external/amd/amd_preprocess.o +0 -0
  63. data/vendor/scs/linsys/external/amd/amd_valid.c +92 -0
  64. data/vendor/scs/linsys/external/amd/amd_valid.o +0 -0
  65. data/vendor/scs/linsys/external/amd/changes +11 -0
  66. data/vendor/scs/linsys/external/qdldl/LICENSE +201 -0
  67. data/vendor/scs/linsys/external/qdldl/README.md +120 -0
  68. data/vendor/scs/linsys/external/qdldl/changes +4 -0
  69. data/vendor/scs/linsys/external/qdldl/qdldl.c +298 -0
  70. data/vendor/scs/linsys/external/qdldl/qdldl.h +177 -0
  71. data/vendor/scs/linsys/external/qdldl/qdldl.o +0 -0
  72. data/vendor/scs/linsys/external/qdldl/qdldl_types.h +21 -0
  73. data/vendor/scs/linsys/gpu/gpu.c +41 -0
  74. data/vendor/scs/linsys/gpu/gpu.h +85 -0
  75. data/vendor/scs/linsys/gpu/indirect/private.c +304 -0
  76. data/vendor/scs/linsys/gpu/indirect/private.h +36 -0
  77. data/vendor/scs/scs.mk +181 -0
  78. data/vendor/scs/src/aa.c +224 -0
  79. data/vendor/scs/src/aa.o +0 -0
  80. data/vendor/scs/src/cones.c +802 -0
  81. data/vendor/scs/src/cones.o +0 -0
  82. data/vendor/scs/src/ctrlc.c +77 -0
  83. data/vendor/scs/src/ctrlc.o +0 -0
  84. data/vendor/scs/src/linalg.c +84 -0
  85. data/vendor/scs/src/linalg.o +0 -0
  86. data/vendor/scs/src/normalize.c +93 -0
  87. data/vendor/scs/src/normalize.o +0 -0
  88. data/vendor/scs/src/rw.c +167 -0
  89. data/vendor/scs/src/rw.o +0 -0
  90. data/vendor/scs/src/scs.c +978 -0
  91. data/vendor/scs/src/scs.o +0 -0
  92. data/vendor/scs/src/scs_version.c +5 -0
  93. data/vendor/scs/src/scs_version.o +0 -0
  94. data/vendor/scs/src/util.c +196 -0
  95. data/vendor/scs/src/util.o +0 -0
  96. data/vendor/scs/test/data/small_random_socp +0 -0
  97. data/vendor/scs/test/minunit.h +13 -0
  98. data/vendor/scs/test/problem_utils.h +93 -0
  99. data/vendor/scs/test/problems/rob_gauss_cov_est.h +85 -0
  100. data/vendor/scs/test/problems/small_lp.h +50 -0
  101. data/vendor/scs/test/problems/small_random_socp.h +33 -0
  102. data/vendor/scs/test/random_socp_prob.c +171 -0
  103. data/vendor/scs/test/run_from_file.c +69 -0
  104. data/vendor/scs/test/run_tests +2 -0
  105. data/vendor/scs/test/run_tests.c +32 -0
  106. metadata +203 -0
@@ -0,0 +1,366 @@
1
+ #include "private.h"
2
+
3
+ struct SPARSE_MATRIX /* matrix in compressed-column or triplet form */
4
+ {
5
+ scs_int nzmax; /* maximum number of entries */
6
+ scs_int m; /* number of rows */
7
+ scs_int n; /* number of columns */
8
+ scs_int *p; /* column pointers (size n+1) or col indices (size nzmax) */
9
+ scs_int *i; /* row indices, size nzmax */
10
+ scs_float *x; /* numerical values, size nzmax */
11
+ scs_int nz; /* # of entries in triplet matrix, -1 for compressed-col */
12
+ };
13
+
14
+ char *SCS(get_lin_sys_method)(const ScsMatrix *A, const ScsSettings *stgs) {
15
+ char *tmp = (char *)scs_malloc(sizeof(char) * 128);
16
+ sprintf(tmp, "sparse-direct, nnz in A = %li", (long)A->p[A->n]);
17
+ return tmp;
18
+ }
19
+
20
+ char *SCS(get_lin_sys_summary)(ScsLinSysWork *p, const ScsInfo *info) {
21
+ char *str = (char *)scs_malloc(sizeof(char) * 128);
22
+ scs_int n = p->L->n;
23
+ sprintf(str, "\tLin-sys: nnz in L factor: %li, avg solve time: %1.2es\n",
24
+ (long)(p->L->p[n] + n), p->total_solve_time / (info->iter + 1) / 1e3);
25
+ p->total_solve_time = 0;
26
+ return str;
27
+ }
28
+
29
+ /* wrapper for free */
30
+ static void *cs_free(void *p) {
31
+ if (p) {
32
+ scs_free(p);
33
+ } /* free p if it is not already SCS_NULL */
34
+ return SCS_NULL; /* return SCS_NULL to simplify the use of cs_free */
35
+ }
36
+
37
+ static _cs *cs_spfree(_cs *A) {
38
+ if (!A) {
39
+ return SCS_NULL;
40
+ } /* do nothing if A already SCS_NULL */
41
+ cs_free(A->p);
42
+ cs_free(A->i);
43
+ cs_free(A->x);
44
+ return (_cs *)cs_free(A); /* free the _cs struct and return SCS_NULL */
45
+ }
46
+
47
+ void SCS(free_lin_sys_work)(ScsLinSysWork *p) {
48
+ if (p) {
49
+ cs_spfree(p->L);
50
+ scs_free(p->P);
51
+ scs_free(p->Dinv);
52
+ scs_free(p->bp);
53
+ scs_free(p);
54
+ }
55
+ }
56
+
57
+ static _cs *cs_spalloc(scs_int m, scs_int n, scs_int nzmax, scs_int values,
58
+ scs_int triplet) {
59
+ _cs *A = (_cs *)scs_calloc(1, sizeof(_cs)); /* allocate the _cs struct */
60
+ if (!A) {
61
+ return SCS_NULL;
62
+ } /* out of memory */
63
+ A->m = m; /* define dimensions and nzmax */
64
+ A->n = n;
65
+ A->nzmax = nzmax = MAX(nzmax, 1);
66
+ A->nz = triplet ? 0 : -1; /* allocate triplet or comp.col */
67
+ A->p = (scs_int *)scs_malloc((triplet ? nzmax : n + 1) * sizeof(scs_int));
68
+ A->i = (scs_int *)scs_malloc(nzmax * sizeof(scs_int));
69
+ A->x = values ? (scs_float *)scs_malloc(nzmax * sizeof(scs_float)) : SCS_NULL;
70
+ return (!A->p || !A->i || (values && !A->x)) ? cs_spfree(A) : A;
71
+ }
72
+
73
+ static _cs *cs_done(_cs *C, void *w, void *x, scs_int ok) {
74
+ cs_free(w); /* free workspace */
75
+ cs_free(x);
76
+ return ok ? C : cs_spfree(C); /* return result if OK, else free it */
77
+ }
78
+
79
+ /* C = compressed-column form of a triplet matrix T */
80
+ static _cs *cs_compress(const _cs *T) {
81
+ scs_int m, n, nz, p, k, *Cp, *Ci, *w, *Ti, *Tj;
82
+ scs_float *Cx, *Tx;
83
+ _cs *C;
84
+ m = T->m;
85
+ n = T->n;
86
+ Ti = T->i;
87
+ Tj = T->p;
88
+ Tx = T->x;
89
+ nz = T->nz;
90
+ C = cs_spalloc(m, n, nz, Tx != SCS_NULL, 0); /* allocate result */
91
+ w = (scs_int *)scs_calloc(n, sizeof(scs_int)); /* get workspace */
92
+ if (!C || !w) {
93
+ return cs_done(C, w, SCS_NULL, 0);
94
+ } /* out of memory */
95
+ Cp = C->p;
96
+ Ci = C->i;
97
+ Cx = C->x;
98
+ for (k = 0; k < nz; k++) w[Tj[k]]++; /* column counts */
99
+ SCS(cumsum)(Cp, w, n); /* column pointers */
100
+ for (k = 0; k < nz; k++) {
101
+ Ci[p = w[Tj[k]]++] = Ti[k]; /* A(i,j) is the pth entry in C */
102
+ if (Cx) {
103
+ Cx[p] = Tx[k];
104
+ }
105
+ }
106
+ return cs_done(C, w, SCS_NULL, 1); /* success; free w and return C */
107
+ }
108
+
109
+ static _cs *form_kkt(const ScsMatrix *A, const ScsSettings *s) {
110
+ /* ONLY UPPER TRIANGULAR PART IS STUFFED
111
+ * forms column compressed KKT matrix
112
+ * assumes column compressed form A matrix
113
+ *
114
+ * forms upper triangular part of [I A'; A -I]
115
+ */
116
+ scs_int j, k, kk;
117
+ _cs *K_cs;
118
+ /* I at top left */
119
+ const scs_int Anz = A->p[A->n];
120
+ const scs_int Knzmax = A->n + A->m + Anz;
121
+ _cs *K = cs_spalloc(A->m + A->n, A->m + A->n, Knzmax, 1, 1);
122
+
123
+ #if EXTRA_VERBOSE > 0
124
+ scs_printf("forming KKT\n");
125
+ #endif
126
+
127
+ if (!K) {
128
+ return SCS_NULL;
129
+ }
130
+ kk = 0;
131
+ for (k = 0; k < A->n; k++) {
132
+ K->i[kk] = k;
133
+ K->p[kk] = k;
134
+ K->x[kk] = s->rho_x;
135
+ kk++;
136
+ }
137
+ /* A^T at top right : CCS: */
138
+ for (j = 0; j < A->n; j++) {
139
+ for (k = A->p[j]; k < A->p[j + 1]; k++) {
140
+ K->p[kk] = A->i[k] + A->n;
141
+ K->i[kk] = j;
142
+ K->x[kk] = A->x[k];
143
+ kk++;
144
+ }
145
+ }
146
+ /* -I at bottom right */
147
+ for (k = 0; k < A->m; k++) {
148
+ K->i[kk] = k + A->n;
149
+ K->p[kk] = k + A->n;
150
+ K->x[kk] = -1;
151
+ kk++;
152
+ }
153
+ /* assert kk == Knzmax */
154
+ K->nz = Knzmax;
155
+ K_cs = cs_compress(K);
156
+ cs_spfree(K);
157
+ return K_cs;
158
+ }
159
+
160
+ static scs_int _ldl_init(_cs *A, scs_int *P, scs_float **info) {
161
+ *info = (scs_float *)scs_malloc(AMD_INFO * sizeof(scs_float));
162
+ return amd_order(A->n, A->p, A->i, P, (scs_float *)SCS_NULL, *info);
163
+ }
164
+
165
+ static scs_int _ldl_factor(_cs *A, _cs **L, scs_float **Dinv) {
166
+ scs_int factor_status, n = A->n;
167
+ scs_int *etree = (scs_int *)scs_malloc(n * sizeof(scs_int));
168
+ scs_int *Lnz = (scs_int *)scs_malloc(n * sizeof(scs_int));
169
+ scs_int *iwork = (scs_int *)scs_malloc(3 * n * sizeof(scs_int));
170
+ scs_float *D, *fwork;
171
+ scs_int *bwork;
172
+ (*L)->p = (scs_int *)scs_malloc((1 + n) * sizeof(scs_int));
173
+ (*L)->nzmax = QDLDL_etree(n, A->p, A->i, iwork, Lnz, etree);
174
+ if ((*L)->nzmax < 0) {
175
+ scs_printf("Error in elimination tree calculation.\n");
176
+ scs_free(Lnz);
177
+ scs_free(iwork);
178
+ scs_free(etree);
179
+ scs_free((*L)->p);
180
+ return (*L)->nzmax;
181
+ }
182
+
183
+ (*L)->x = (scs_float *)scs_malloc((*L)->nzmax * sizeof(scs_float));
184
+ (*L)->i = (scs_int *)scs_malloc((*L)->nzmax * sizeof(scs_int));
185
+ *Dinv = (scs_float *)scs_malloc(n * sizeof(scs_float));
186
+ D = (scs_float *)scs_malloc(n * sizeof(scs_float));
187
+ bwork = (scs_int *)scs_malloc(n * sizeof(scs_int));
188
+ fwork = (scs_float *)scs_malloc(n * sizeof(scs_float));
189
+
190
+ #if EXTRA_VERBOSE > 0
191
+ scs_printf("numeric factorization\n");
192
+ #endif
193
+ factor_status = QDLDL_factor(n, A->p, A->i, A->x, (*L)->p, (*L)->i, (*L)->x,
194
+ D, *Dinv, Lnz, etree, bwork, iwork, fwork);
195
+ #if EXTRA_VERBOSE > 0
196
+ scs_printf("finished numeric factorization\n");
197
+ #endif
198
+
199
+ scs_free(Lnz);
200
+ scs_free(iwork);
201
+ scs_free(etree);
202
+ scs_free(D);
203
+ scs_free(bwork);
204
+ scs_free(fwork);
205
+ return factor_status;
206
+ }
207
+
208
+ static void _ldl_perm(scs_int n, scs_float *x, scs_float *b, scs_int *P) {
209
+ scs_int j;
210
+ for (j = 0; j < n; j++) x[j] = b[P[j]];
211
+ }
212
+
213
+ static void _ldl_permt(scs_int n, scs_float *x, scs_float *b, scs_int *P) {
214
+ scs_int j;
215
+ for (j = 0; j < n; j++) x[P[j]] = b[j];
216
+ }
217
+
218
+ static void _ldl_solve(scs_float *b, _cs *L, scs_float *Dinv, scs_int *P,
219
+ scs_float *bp) {
220
+ /* solves PLDL'P' x = b for x */
221
+ scs_int n = L->n;
222
+ _ldl_perm(n, bp, b, P);
223
+ QDLDL_solve(n, L->p, L->i, L->x, Dinv, bp);
224
+ _ldl_permt(n, b, bp, P);
225
+ }
226
+
227
+ void SCS(accum_by_atrans)(const ScsMatrix *A, ScsLinSysWork *p,
228
+ const scs_float *x, scs_float *y) {
229
+ SCS(_accum_by_atrans)(A->n, A->x, A->i, A->p, x, y);
230
+ }
231
+
232
+ void SCS(accum_by_a)(const ScsMatrix *A, ScsLinSysWork *p, const scs_float *x,
233
+ scs_float *y) {
234
+ SCS(_accum_by_a)(A->n, A->x, A->i, A->p, x, y);
235
+ }
236
+
237
+ static scs_int *cs_pinv(scs_int const *p, scs_int n) {
238
+ scs_int k, *pinv;
239
+ if (!p) {
240
+ return SCS_NULL;
241
+ } /* p = SCS_NULL denotes identity */
242
+ pinv = (scs_int *)scs_malloc(n * sizeof(scs_int)); /* allocate result */
243
+ if (!pinv) {
244
+ return SCS_NULL;
245
+ } /* out of memory */
246
+ for (k = 0; k < n; k++) pinv[p[k]] = k; /* invert the permutation */
247
+ return pinv; /* return result */
248
+ }
249
+
250
+ static _cs *cs_symperm(const _cs *A, const scs_int *pinv, scs_int values) {
251
+ scs_int i, j, p, q, i2, j2, n, *Ap, *Ai, *Cp, *Ci, *w;
252
+ scs_float *Cx, *Ax;
253
+ _cs *C;
254
+ n = A->n;
255
+ Ap = A->p;
256
+ Ai = A->i;
257
+ Ax = A->x;
258
+ C = cs_spalloc(n, n, Ap[n], values && (Ax != SCS_NULL), 0); /* alloc result*/
259
+ w = (scs_int *)scs_calloc(n, sizeof(scs_int)); /* get workspace */
260
+ if (!C || !w) {
261
+ return cs_done(C, w, SCS_NULL, 0);
262
+ } /* out of memory */
263
+ Cp = C->p;
264
+ Ci = C->i;
265
+ Cx = C->x;
266
+ for (j = 0; j < n; j++) /* count entries in each column of C */
267
+ {
268
+ j2 = pinv ? pinv[j] : j; /* column j of A is column j2 of C */
269
+ for (p = Ap[j]; p < Ap[j + 1]; p++) {
270
+ i = Ai[p];
271
+ if (i > j) {
272
+ continue;
273
+ } /* skip lower triangular part of A */
274
+ i2 = pinv ? pinv[i] : i; /* row i of A is row i2 of C */
275
+ w[MAX(i2, j2)]++; /* column count of C */
276
+ }
277
+ }
278
+ SCS(cumsum)(Cp, w, n); /* compute column pointers of C */
279
+ for (j = 0; j < n; j++) {
280
+ j2 = pinv ? pinv[j] : j; /* column j of A is column j2 of C */
281
+ for (p = Ap[j]; p < Ap[j + 1]; p++) {
282
+ i = Ai[p];
283
+ if (i > j) {
284
+ continue;
285
+ } /* skip lower triangular part of A*/
286
+ i2 = pinv ? pinv[i] : i; /* row i of A is row i2 of C */
287
+ Ci[q = w[MAX(i2, j2)]++] = MIN(i2, j2);
288
+ if (Cx) {
289
+ Cx[q] = Ax[p];
290
+ }
291
+ }
292
+ }
293
+ return cs_done(C, w, SCS_NULL, 1); /* success; free workspace, return C */
294
+ }
295
+
296
+ static scs_int factorize(const ScsMatrix *A, const ScsSettings *stgs,
297
+ ScsLinSysWork *p) {
298
+ scs_float *info;
299
+ scs_int *Pinv, amd_status, ldl_status;
300
+ _cs *C, *K = form_kkt(A, stgs);
301
+ if (!K) {
302
+ return -1;
303
+ }
304
+ amd_status = _ldl_init(K, p->P, &info);
305
+ if (amd_status < 0) {
306
+ return amd_status;
307
+ }
308
+ #if EXTRA_VERBOSE > 0
309
+ if (stgs->verbose) {
310
+ scs_printf("Matrix factorization info:\n");
311
+ amd_info(info);
312
+ }
313
+ #endif
314
+ Pinv = cs_pinv(p->P, A->n + A->m);
315
+ C = cs_symperm(K, Pinv, 1);
316
+ ldl_status = _ldl_factor(C, &p->L, &p->Dinv);
317
+ cs_spfree(C);
318
+ cs_spfree(K);
319
+ scs_free(Pinv);
320
+ scs_free(info);
321
+ return ldl_status;
322
+ }
323
+
324
+ ScsLinSysWork *SCS(init_lin_sys_work)(const ScsMatrix *A,
325
+ const ScsSettings *stgs) {
326
+ ScsLinSysWork *p = (ScsLinSysWork *)scs_calloc(1, sizeof(ScsLinSysWork));
327
+ scs_int n_plus_m = A->n + A->m;
328
+ p->P = (scs_int *)scs_malloc(sizeof(scs_int) * n_plus_m);
329
+ p->L = (_cs *)scs_malloc(sizeof(_cs));
330
+ p->bp = (scs_float *)scs_malloc(n_plus_m * sizeof(scs_float));
331
+ p->L->m = n_plus_m;
332
+ p->L->n = n_plus_m;
333
+ p->L->nz = -1;
334
+
335
+ if (factorize(A, stgs, p) < 0) {
336
+ SCS(free_lin_sys_work)(p);
337
+ return SCS_NULL;
338
+ }
339
+ p->total_solve_time = 0.0;
340
+ return p;
341
+ }
342
+
343
+ scs_int SCS(solve_lin_sys)(const ScsMatrix *A, const ScsSettings *stgs,
344
+ ScsLinSysWork *p, scs_float *b, const scs_float *s,
345
+ scs_int iter) {
346
+ /* returns solution to linear system */
347
+ /* Ax = b with solution stored in b */
348
+ SCS(timer) linsys_timer;
349
+ SCS(tic)(&linsys_timer);
350
+ _ldl_solve(b, p->L, p->Dinv, p->P, p->bp);
351
+ p->total_solve_time += SCS(tocq)(&linsys_timer);
352
+ #if EXTRA_VERBOSE > 0
353
+ scs_printf("linsys solve time: %1.2es\n", SCS(tocq)(&linsys_timer) / 1e3);
354
+ #endif
355
+ return 0;
356
+ }
357
+
358
+ void SCS(normalize_a)(ScsMatrix *A, const ScsSettings *stgs, const ScsCone *k,
359
+ ScsScaling *scal) {
360
+ SCS(_normalize_a)(A, stgs, k, scal);
361
+ }
362
+
363
+ void SCS(un_normalize_a)(ScsMatrix *A, const ScsSettings *stgs,
364
+ const ScsScaling *scal) {
365
+ SCS(_un_normalize_a)(A, stgs, scal);
366
+ }
@@ -0,0 +1,26 @@
1
+ #ifndef PRIV_H_GUARD
2
+ #define PRIV_H_GUARD
3
+
4
+ #ifdef __cplusplus
5
+ extern "C" {
6
+ #endif
7
+
8
+ #include "amatrix.h"
9
+ #include "external/amd/amd.h"
10
+ #include "external/qdldl/qdldl.h"
11
+ #include "glbopts.h"
12
+ #include "scs.h"
13
+
14
+ typedef struct SPARSE_MATRIX _cs;
15
+ struct SCS_LIN_SYS_WORK {
16
+ _cs *L; /* KKT, and factorization matrix L resp. */
17
+ scs_float *Dinv; /* inverse diagonal matrix of factorization */
18
+ scs_int *P; /* permutation of KKT matrix for factorization */
19
+ scs_float *bp; /* workspace memory for solves */
20
+ scs_float total_solve_time; /* reporting */
21
+ };
22
+
23
+ #ifdef __cplusplus
24
+ }
25
+ #endif
26
+ #endif
@@ -0,0 +1,256 @@
1
+ #include "private.h"
2
+
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;
11
+ }
12
+
13
+ char *SCS(get_lin_sys_summary)(ScsLinSysWork *p, const ScsInfo *info) {
14
+ 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);
19
+ p->tot_cg_its = 0;
20
+ p->total_solve_time = 0;
21
+ return str;
22
+ }
23
+
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;
28
+ scs_float *M = p->M;
29
+
30
+ #if EXTRA_VERBOSE > 0
31
+ scs_printf("getting pre-conditioner\n");
32
+ #endif
33
+
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; */
38
+ }
39
+
40
+ #if EXTRA_VERBOSE > 0
41
+ scs_printf("finished getting pre-conditioner\n");
42
+ #endif
43
+ }
44
+
45
+ static void transpose(const ScsMatrix *A, ScsLinSysWork *p) {
46
+ scs_int *Ci = p->At->i;
47
+ scs_int *Cp = p->At->p;
48
+ scs_float *Cx = p->At->x;
49
+ scs_int m = A->m;
50
+ scs_int n = A->n;
51
+
52
+ scs_int *Ap = A->p;
53
+ scs_int *Ai = A->i;
54
+ scs_float *Ax = A->x;
55
+
56
+ scs_int i, j, q, *z, c1, c2;
57
+ #if EXTRA_VERBOSE > 0
58
+ SCS(timer) transpose_timer;
59
+ scs_printf("transposing A\n");
60
+ SCS(tic)(&transpose_timer);
61
+ #endif
62
+
63
+ 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 */
66
+
67
+ for (j = 0; j < n; j++) {
68
+ c1 = Ap[j];
69
+ c2 = Ap[j + 1];
70
+ for (i = c1; i < c2; i++) {
71
+ q = z[Ai[i]];
72
+ Ci[q] = j; /* place A(i,j) as entry C(j,i) */
73
+ Cx[q] = Ax[i];
74
+ z[Ai[i]]++;
75
+ }
76
+ }
77
+ scs_free(z);
78
+
79
+ #if EXTRA_VERBOSE > 0
80
+ scs_printf("finished transposing A, time: %1.2es\n",
81
+ SCS(tocq)(&transpose_timer) / 1e3);
82
+ #endif
83
+ }
84
+
85
+ void SCS(free_lin_sys_work)(ScsLinSysWork *p) {
86
+ if (p) {
87
+ scs_free(p->p);
88
+ scs_free(p->r);
89
+ scs_free(p->Gp);
90
+ scs_free(p->tmp);
91
+ if (p->At) {
92
+ scs_free(p->At->i);
93
+ scs_free(p->At->x);
94
+ scs_free(p->At->p);
95
+ scs_free(p->At);
96
+ }
97
+ scs_free(p->z);
98
+ scs_free(p->M);
99
+ scs_free(p);
100
+ }
101
+ }
102
+
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);
112
+ }
113
+
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);
117
+ }
118
+
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);
122
+ }
123
+
124
+ static void apply_pre_conditioner(scs_float *M, scs_float *z, scs_float *r,
125
+ scs_int n, scs_float *ipzr) {
126
+ scs_int i;
127
+ *ipzr = 0;
128
+ for (i = 0; i < n; ++i) {
129
+ z[i] = r[i] * M[i];
130
+ *ipzr += z[i] * r[i];
131
+ }
132
+ }
133
+
134
+ ScsLinSysWork *SCS(init_lin_sys_work)(const ScsMatrix *A,
135
+ const ScsSettings *stgs) {
136
+ 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));
141
+
142
+ /* memory for A transpose */
143
+ p->At = (ScsMatrix *)scs_malloc(sizeof(ScsMatrix));
144
+ p->At->m = A->n;
145
+ 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));
149
+ transpose(A, p);
150
+
151
+ /* 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);
155
+
156
+ p->total_solve_time = 0;
157
+ p->tot_cg_its = 0;
158
+ if (!p->p || !p->r || !p->Gp || !p->tmp || !p->At || !p->At->i || !p->At->p ||
159
+ !p->At->x) {
160
+ SCS(free_lin_sys_work)(p);
161
+ return SCS_NULL;
162
+ }
163
+ return p;
164
+ }
165
+
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,
169
+ scs_int max_its, scs_float tol) {
170
+ scs_int i, n = A->n;
171
+ scs_float ipzr, ipzr_old, alpha;
172
+ scs_float *p = pr->p; /* cg direction */
173
+ scs_float *Gp = pr->Gp; /* updated CG direction */
174
+ scs_float *r = pr->r; /* cg residual */
175
+ scs_float *z = pr->z; /* for preconditioning */
176
+ scs_float *M = pr->M; /* inverse diagonal preconditioner */
177
+
178
+ if (s == SCS_NULL) {
179
+ memcpy(r, b, n * sizeof(scs_float));
180
+ memset(b, 0, n * sizeof(scs_float));
181
+ } 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);
185
+ memcpy(b, s, n * sizeof(scs_float));
186
+ }
187
+
188
+ /* check to see if we need to run CG at all */
189
+ if (SCS(norm)(r, n) < MIN(tol, 1e-18)) {
190
+ return 0;
191
+ }
192
+
193
+ apply_pre_conditioner(M, z, r, n, &ipzr);
194
+ memcpy(p, z, n * sizeof(scs_float));
195
+
196
+ for (i = 0; i < max_its; ++i) {
197
+ mat_vec(A, stgs, pr, p, Gp);
198
+ alpha = ipzr / SCS(dot)(p, Gp, n);
199
+ SCS(add_scaled_array)(b, p, n, alpha);
200
+ SCS(add_scaled_array)(r, Gp, n, -alpha);
201
+
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);
206
+ #endif
207
+ return i + 1;
208
+ }
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);
214
+ }
215
+ return i;
216
+ }
217
+
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;
239
+ }
240
+
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);
244
+ #endif
245
+ return 0;
246
+ }
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
+ }