scs 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +3 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +84 -0
  5. data/ext/scs/Rakefile +11 -0
  6. data/lib/scs/ffi.rb +117 -0
  7. data/lib/scs/solver.rb +178 -0
  8. data/lib/scs/version.rb +3 -0
  9. data/lib/scs.rb +17 -0
  10. data/vendor/scs/LICENSE.txt +21 -0
  11. data/vendor/scs/Makefile +164 -0
  12. data/vendor/scs/README.md +220 -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 +975 -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
+ }
@@ -0,0 +1,31 @@
1
+ #ifndef PRIV_H_GUARD
2
+ #define PRIV_H_GUARD
3
+
4
+ #ifdef __cplusplus
5
+ extern "C" {
6
+ #endif
7
+
8
+ #include <math.h>
9
+ #include "amatrix.h"
10
+ #include "glbopts.h"
11
+ #include "linalg.h"
12
+ #include "scs.h"
13
+
14
+ struct SCS_LIN_SYS_WORK {
15
+ scs_float *p; /* cg iterate */
16
+ scs_float *r; /* cg residual */
17
+ scs_float *Gp;
18
+ scs_float *tmp;
19
+ ScsMatrix *At;
20
+ /* preconditioning */
21
+ scs_float *z;
22
+ scs_float *M;
23
+ /* reporting */
24
+ scs_int tot_cg_its;
25
+ scs_float total_solve_time;
26
+ };
27
+
28
+ #ifdef __cplusplus
29
+ }
30
+ #endif
31
+ #endif