scs 0.3.0 → 0.4.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 (92) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +14 -0
  3. data/README.md +42 -13
  4. data/lib/scs/ffi.rb +1 -7
  5. data/lib/scs/matrix.rb +72 -0
  6. data/lib/scs/solver.rb +19 -26
  7. data/lib/scs/version.rb +1 -1
  8. data/lib/scs.rb +1 -0
  9. data/vendor/scs/CITATION.cff +1 -1
  10. data/vendor/scs/CMakeLists.txt +55 -7
  11. data/vendor/scs/Makefile +9 -9
  12. data/vendor/scs/README.md +4 -1
  13. data/vendor/scs/include/aa.h +1 -1
  14. data/vendor/scs/include/cones.h +17 -12
  15. data/vendor/scs/include/glbopts.h +27 -66
  16. data/vendor/scs/include/linalg.h +2 -1
  17. data/vendor/scs/include/linsys.h +13 -13
  18. data/vendor/scs/include/normalize.h +7 -5
  19. data/vendor/scs/include/rw.h +3 -3
  20. data/vendor/scs/include/scs.h +85 -106
  21. data/vendor/scs/include/scs_types.h +34 -0
  22. data/vendor/scs/include/scs_work.h +80 -0
  23. data/vendor/scs/include/util.h +3 -1
  24. data/vendor/scs/linsys/cpu/direct/private.c +86 -73
  25. data/vendor/scs/linsys/cpu/direct/private.h +2 -2
  26. data/vendor/scs/linsys/cpu/indirect/private.c +42 -33
  27. data/vendor/scs/linsys/cpu/indirect/private.h +1 -2
  28. data/vendor/scs/linsys/csparse.c +3 -3
  29. data/vendor/scs/linsys/external/amd/LICENSE.txt +0 -897
  30. data/vendor/scs/linsys/external/amd/SuiteSparse_config.c +9 -7
  31. data/vendor/scs/linsys/external/amd/SuiteSparse_config.h +1 -1
  32. data/vendor/scs/linsys/external/amd/amd_order.c +5 -5
  33. data/vendor/scs/linsys/gpu/gpu.h +8 -11
  34. data/vendor/scs/linsys/gpu/indirect/private.c +72 -49
  35. data/vendor/scs/linsys/gpu/indirect/private.h +14 -13
  36. data/vendor/scs/linsys/scs_matrix.c +55 -104
  37. data/vendor/scs/linsys/scs_matrix.h +5 -4
  38. data/vendor/scs/scs.mk +1 -5
  39. data/vendor/scs/src/aa.c +13 -8
  40. data/vendor/scs/src/cones.c +197 -108
  41. data/vendor/scs/src/linalg.c +25 -0
  42. data/vendor/scs/src/normalize.c +75 -26
  43. data/vendor/scs/src/rw.c +74 -30
  44. data/vendor/scs/src/scs.c +300 -264
  45. data/vendor/scs/src/scs_version.c +8 -6
  46. data/vendor/scs/src/util.c +27 -13
  47. data/vendor/scs/test/minunit.h +6 -1
  48. data/vendor/scs/test/problem_utils.h +28 -35
  49. data/vendor/scs/test/problems/degenerate.h +2 -1
  50. data/vendor/scs/test/problems/hs21_tiny_qp.h +2 -1
  51. data/vendor/scs/test/problems/hs21_tiny_qp_rw.h +6 -2
  52. data/vendor/scs/test/problems/infeasible_tiny_qp.h +2 -1
  53. data/vendor/scs/test/problems/qafiro_tiny_qp.h +5 -4
  54. data/vendor/scs/test/problems/random_prob.h +6 -2
  55. data/vendor/scs/test/problems/rob_gauss_cov_est.h +9 -2
  56. data/vendor/scs/test/problems/small_lp.h +7 -2
  57. data/vendor/scs/test/problems/small_qp.h +387 -0
  58. data/vendor/scs/test/problems/{test_fails.h → test_validation.h} +7 -4
  59. data/vendor/scs/test/problems/unbounded_tiny_qp.h +4 -4
  60. data/vendor/scs/test/random_socp_prob.c +4 -2
  61. data/vendor/scs/test/run_from_file.c +16 -4
  62. data/vendor/scs/test/run_tests.c +23 -14
  63. metadata +10 -35
  64. data/vendor/scs/linsys/cpu/direct/private.o +0 -0
  65. data/vendor/scs/linsys/cpu/indirect/private.o +0 -0
  66. data/vendor/scs/linsys/csparse.o +0 -0
  67. data/vendor/scs/linsys/external/amd/SuiteSparse_config.o +0 -0
  68. data/vendor/scs/linsys/external/amd/amd_1.o +0 -0
  69. data/vendor/scs/linsys/external/amd/amd_2.o +0 -0
  70. data/vendor/scs/linsys/external/amd/amd_aat.o +0 -0
  71. data/vendor/scs/linsys/external/amd/amd_control.o +0 -0
  72. data/vendor/scs/linsys/external/amd/amd_defaults.o +0 -0
  73. data/vendor/scs/linsys/external/amd/amd_dump.o +0 -0
  74. data/vendor/scs/linsys/external/amd/amd_global.o +0 -0
  75. data/vendor/scs/linsys/external/amd/amd_info.o +0 -0
  76. data/vendor/scs/linsys/external/amd/amd_order.o +0 -0
  77. data/vendor/scs/linsys/external/amd/amd_post_tree.o +0 -0
  78. data/vendor/scs/linsys/external/amd/amd_postorder.o +0 -0
  79. data/vendor/scs/linsys/external/amd/amd_preprocess.o +0 -0
  80. data/vendor/scs/linsys/external/amd/amd_valid.o +0 -0
  81. data/vendor/scs/linsys/external/qdldl/qdldl.o +0 -0
  82. data/vendor/scs/linsys/scs_matrix.o +0 -0
  83. data/vendor/scs/src/aa.o +0 -0
  84. data/vendor/scs/src/cones.o +0 -0
  85. data/vendor/scs/src/ctrlc.o +0 -0
  86. data/vendor/scs/src/linalg.o +0 -0
  87. data/vendor/scs/src/normalize.o +0 -0
  88. data/vendor/scs/src/rw.o +0 -0
  89. data/vendor/scs/src/scs.o +0 -0
  90. data/vendor/scs/src/scs_indir.o +0 -0
  91. data/vendor/scs/src/scs_version.o +0 -0
  92. data/vendor/scs/src/util.o +0 -0
@@ -18,10 +18,11 @@ void SCS(free_lin_sys_work)(ScsLinSysWork *p) {
18
18
  if (p) {
19
19
  SCS(cs_spfree)(p->L);
20
20
  SCS(cs_spfree)(p->kkt);
21
+ scs_free(p->diag_p);
21
22
  scs_free(p->perm);
22
23
  scs_free(p->Dinv);
23
24
  scs_free(p->bp);
24
- scs_free(p->rho_y_vec_idxs);
25
+ scs_free(p->diag_r_idxs);
25
26
  scs_free(p->Lnz);
26
27
  scs_free(p->iwork);
27
28
  scs_free(p->etree);
@@ -32,9 +33,8 @@ void SCS(free_lin_sys_work)(ScsLinSysWork *p) {
32
33
  }
33
34
  }
34
35
 
35
- static csc *form_kkt(const ScsMatrix *A, const ScsMatrix *P,
36
- scs_float *rho_y_vec, scs_int *rho_y_vec_idxs,
37
- scs_float rho_x) {
36
+ static csc *form_kkt(const ScsMatrix *A, const ScsMatrix *P, scs_float *diag_p,
37
+ const scs_float *diag_r, scs_int *diag_r_idxs) {
38
38
  /* ONLY UPPER TRIANGULAR PART IS STUFFED
39
39
  * forms column compressed kkt matrix
40
40
  * assumes column compressed form A matrix
@@ -42,7 +42,7 @@ static csc *form_kkt(const ScsMatrix *A, const ScsMatrix *P,
42
42
  * forms upper triangular part of [(I + P) A'; A -I]
43
43
  * P : n x n, A: m x n.
44
44
  */
45
- scs_int i, j, k, kk;
45
+ scs_int h, i, j, count;
46
46
  csc *Kcsc, *K;
47
47
  scs_int n = A->n;
48
48
  scs_int m = A->m;
@@ -65,72 +65,80 @@ static csc *form_kkt(const ScsMatrix *A, const ScsMatrix *P,
65
65
  return SCS_NULL;
66
66
  }
67
67
 
68
- kk = 0; /* element counter */
68
+ count = 0; /* element counter */
69
69
  if (P) {
70
- /* I + P in top left */
71
- for (j = 0; j < P->n; j++) { /* cols */
70
+ /* R_x + P in top left */
71
+ for (j = 0; j < n; j++) { /* cols */
72
+ diag_p[j] = 0.;
72
73
  /* empty column, add diagonal */
73
74
  if (P->p[j] == P->p[j + 1]) {
74
- K->i[kk] = j;
75
- K->p[kk] = j;
76
- K->x[kk] = rho_x;
77
- kk++;
75
+ K->i[count] = j;
76
+ K->p[count] = j;
77
+ K->x[count] = diag_r[j];
78
+ diag_r_idxs[j] = count; /* store the indices where diag_r occurs */
79
+ count++;
78
80
  }
79
- for (k = P->p[j]; k < P->p[j + 1]; k++) {
80
- i = P->i[k]; /* row */
81
+ for (h = P->p[j]; h < P->p[j + 1]; h++) {
82
+ i = P->i[h]; /* row */
81
83
  if (i > j) { /* only upper triangular needed */
82
84
  break;
83
85
  }
84
- K->i[kk] = i;
85
- K->p[kk] = j;
86
- K->x[kk] = P->x[k];
86
+ K->i[count] = i;
87
+ K->p[count] = j;
88
+ K->x[count] = P->x[h];
87
89
  if (i == j) {
88
90
  /* P has diagonal element */
89
- K->x[kk] += rho_x;
91
+ diag_p[j] = P->x[h];
92
+ K->x[count] += diag_r[j];
93
+ diag_r_idxs[j] = count; /* store the indices where diag_r occurs */
90
94
  }
91
- kk++;
95
+ count++;
92
96
  /* reached the end without adding diagonal, do it now */
93
- if ((i < j) && (k + 1 == P->p[j + 1] || P->i[k + 1] > j)) {
94
- K->i[kk] = j;
95
- K->p[kk] = j;
96
- K->x[kk] = rho_x;
97
- kk++;
97
+ if ((i < j) && (h + 1 == P->p[j + 1] || P->i[h + 1] > j)) {
98
+ K->i[count] = j;
99
+ K->p[count] = j;
100
+ K->x[count] = diag_r[j];
101
+ diag_r_idxs[j] = count; /* store the indices where diag_r occurs */
102
+ count++;
98
103
  }
99
104
  }
100
105
  }
101
106
  } else {
102
- /* rho_x * I in top left */
103
- for (k = 0; k < A->n; k++) {
104
- K->i[kk] = k;
105
- K->p[kk] = k;
106
- K->x[kk] = rho_x;
107
- kk++;
107
+ /* R_x in top left */
108
+ for (j = 0; j < n; j++) {
109
+ diag_p[j] = 0.;
110
+ K->i[count] = j;
111
+ K->p[count] = j;
112
+ K->x[count] = diag_r[j];
113
+ diag_r_idxs[j] = count; /* store the indices where diag_r occurs */
114
+ count++;
108
115
  }
109
116
  }
110
117
 
111
118
  /* A^T at top right */
112
119
  for (j = 0; j < n; j++) {
113
- for (k = A->p[j]; k < A->p[j + 1]; k++) {
114
- K->p[kk] = A->i[k] + n;
115
- K->i[kk] = j;
116
- K->x[kk] = A->x[k];
117
- kk++;
120
+ for (h = A->p[j]; h < A->p[j + 1]; h++) {
121
+ K->p[count] = A->i[h] + n;
122
+ K->i[count] = j;
123
+ K->x[count] = A->x[h];
124
+ count++;
118
125
  }
119
126
  }
120
127
 
121
- /* -rho_y_vec * I at bottom right */
122
- for (k = 0; k < m; k++) {
123
- K->i[kk] = k + n;
124
- K->p[kk] = k + n;
125
- K->x[kk] = -rho_y_vec[k];
126
- rho_y_vec_idxs[k] = kk; /* store the indices where rho_y_vec occurs */
127
- kk++;
128
+ /* -R_y at bottom right */
129
+ for (j = 0; j < m; j++) {
130
+ K->i[count] = j + n;
131
+ K->p[count] = j + n;
132
+ K->x[count] = -diag_r[j + n];
133
+ diag_r_idxs[j + n] = count; /* store the indices where diag_r occurs */
134
+ count++;
128
135
  }
129
- K->nz = kk;
130
- idx_mapping = (scs_int *)scs_malloc(K->nz * sizeof(scs_int));
136
+
137
+ K->nz = count;
138
+ idx_mapping = (scs_int *)scs_calloc(K->nz, sizeof(scs_int));
131
139
  Kcsc = SCS(cs_compress)(K, idx_mapping);
132
- for (i = 0; i < A->m; i++) {
133
- rho_y_vec_idxs[i] = idx_mapping[rho_y_vec_idxs[i]];
140
+ for (i = 0; i < m + n; i++) {
141
+ diag_r_idxs[i] = idx_mapping[diag_r_idxs[i]];
134
142
  }
135
143
  SCS(cs_spfree)(K);
136
144
  scs_free(idx_mapping);
@@ -138,7 +146,7 @@ static csc *form_kkt(const ScsMatrix *A, const ScsMatrix *P,
138
146
  }
139
147
 
140
148
  static scs_int _ldl_init(csc *A, scs_int *P, scs_float **info) {
141
- *info = (scs_float *)scs_malloc(AMD_INFO * sizeof(scs_float));
149
+ *info = (scs_float *)scs_calloc(AMD_INFO, sizeof(scs_float));
142
150
  return amd_order(A->n, A->p, A->i, P, (scs_float *)SCS_NULL, *info);
143
151
  }
144
152
 
@@ -146,10 +154,10 @@ static scs_int _ldl_init(csc *A, scs_int *P, scs_float **info) {
146
154
  static scs_int ldl_prepare(ScsLinSysWork *p) {
147
155
  csc *kkt = p->kkt, *L = p->L;
148
156
  scs_int n = kkt->n;
149
- p->etree = (scs_int *)scs_malloc(n * sizeof(scs_int));
150
- p->Lnz = (scs_int *)scs_malloc(n * sizeof(scs_int));
151
- p->iwork = (scs_int *)scs_malloc(3 * n * sizeof(scs_int));
152
- L->p = (scs_int *)scs_malloc((1 + n) * sizeof(scs_int));
157
+ p->etree = (scs_int *)scs_calloc(n, sizeof(scs_int));
158
+ p->Lnz = (scs_int *)scs_calloc(n, sizeof(scs_int));
159
+ p->iwork = (scs_int *)scs_calloc(3 * n, sizeof(scs_int));
160
+ L->p = (scs_int *)scs_calloc((1 + n), sizeof(scs_int));
153
161
  L->nzmax = QDLDL_etree(n, kkt->p, kkt->i, p->iwork, p->Lnz, p->etree);
154
162
  if (L->nzmax < 0) {
155
163
  scs_printf("Error in elimination tree calculation.\n");
@@ -161,12 +169,12 @@ static scs_int ldl_prepare(ScsLinSysWork *p) {
161
169
  return L->nzmax;
162
170
  }
163
171
 
164
- L->x = (scs_float *)scs_malloc(L->nzmax * sizeof(scs_float));
165
- L->i = (scs_int *)scs_malloc(L->nzmax * sizeof(scs_int));
166
- p->Dinv = (scs_float *)scs_malloc(n * sizeof(scs_float));
167
- p->D = (scs_float *)scs_malloc(n * sizeof(scs_float));
168
- p->bwork = (scs_int *)scs_malloc(n * sizeof(scs_int));
169
- p->fwork = (scs_float *)scs_malloc(n * sizeof(scs_float));
172
+ L->x = (scs_float *)scs_calloc(L->nzmax, sizeof(scs_float));
173
+ L->i = (scs_int *)scs_calloc(L->nzmax, sizeof(scs_int));
174
+ p->Dinv = (scs_float *)scs_calloc(n, sizeof(scs_float));
175
+ p->D = (scs_float *)scs_calloc(n, sizeof(scs_float));
176
+ p->bwork = (scs_int *)scs_calloc(n, sizeof(scs_int));
177
+ p->fwork = (scs_float *)scs_calloc(n, sizeof(scs_float));
170
178
  return L->nzmax;
171
179
  }
172
180
 
@@ -223,7 +231,7 @@ static scs_int *cs_pinv(scs_int const *p, scs_int n) {
223
231
  if (!p) {
224
232
  return SCS_NULL;
225
233
  } /* p = SCS_NULL denotes identity */
226
- pinv = (scs_int *)scs_malloc(n * sizeof(scs_int)); /* allocate result */
234
+ pinv = (scs_int *)scs_calloc(n, sizeof(scs_int)); /* allocate result */
227
235
  if (!pinv) {
228
236
  return SCS_NULL;
229
237
  } /* out of memory */
@@ -283,10 +291,10 @@ static csc *cs_symperm(const csc *A, const scs_int *pinv, scs_int *idx_mapping,
283
291
  }
284
292
 
285
293
  static csc *permute_kkt(const ScsMatrix *A, const ScsMatrix *P,
286
- ScsLinSysWork *p, scs_float *rho_y_vec) {
294
+ ScsLinSysWork *p, const scs_float *diag_r) {
287
295
  scs_float *info;
288
296
  scs_int *Pinv, amd_status, *idx_mapping, i;
289
- csc *kkt_perm, *kkt = form_kkt(A, P, rho_y_vec, p->rho_y_vec_idxs, p->rho_x);
297
+ csc *kkt_perm, *kkt = form_kkt(A, P, p->diag_p, diag_r, p->diag_r_idxs);
290
298
  if (!kkt) {
291
299
  return SCS_NULL;
292
300
  }
@@ -300,10 +308,10 @@ static csc *permute_kkt(const ScsMatrix *A, const ScsMatrix *P,
300
308
  amd_info(info);
301
309
  #endif
302
310
  Pinv = cs_pinv(p->perm, A->n + A->m);
303
- idx_mapping = (scs_int *)scs_malloc(kkt->nzmax * sizeof(scs_int));
311
+ idx_mapping = (scs_int *)scs_calloc(kkt->nzmax, sizeof(scs_int));
304
312
  kkt_perm = cs_symperm(kkt, Pinv, idx_mapping, 1);
305
- for (i = 0; i < A->m; i++) {
306
- p->rho_y_vec_idxs[i] = idx_mapping[p->rho_y_vec_idxs[i]];
313
+ for (i = 0; i < A->n + A->m; i++) {
314
+ p->diag_r_idxs[i] = idx_mapping[p->diag_r_idxs[i]];
307
315
  }
308
316
  SCS(cs_spfree)(kkt);
309
317
  scs_free(Pinv);
@@ -312,10 +320,15 @@ static csc *permute_kkt(const ScsMatrix *A, const ScsMatrix *P,
312
320
  return kkt_perm;
313
321
  }
314
322
 
315
- void SCS(update_lin_sys_rho_y_vec)(ScsLinSysWork *p, scs_float *rho_y_vec) {
323
+ void SCS(update_lin_sys_diag_r)(ScsLinSysWork *p, const scs_float *diag_r) {
316
324
  scs_int i, ldl_status;
317
- for (i = 0; i < p->m; ++i) {
318
- p->kkt->x[p->rho_y_vec_idxs[i]] = -rho_y_vec[i];
325
+ for (i = 0; i < p->n; ++i) {
326
+ /* top left is R_x + P, bottom right is -R_y */
327
+ p->kkt->x[p->diag_r_idxs[i]] = p->diag_p[i] + diag_r[i];
328
+ }
329
+ for (i = p->n; i < p->n + p->m; ++i) {
330
+ /* top left is R_x + P, bottom right is -R_y */
331
+ p->kkt->x[p->diag_r_idxs[i]] = -diag_r[i];
319
332
  }
320
333
  ldl_status = ldl_factor(p, p->n);
321
334
  if (ldl_status < 0) {
@@ -327,21 +340,21 @@ void SCS(update_lin_sys_rho_y_vec)(ScsLinSysWork *p, scs_float *rho_y_vec) {
327
340
  }
328
341
 
329
342
  ScsLinSysWork *SCS(init_lin_sys_work)(const ScsMatrix *A, const ScsMatrix *P,
330
- scs_float *rho_y_vec, scs_float rho_x) {
343
+ const scs_float *diag_r) {
331
344
  ScsLinSysWork *p = (ScsLinSysWork *)scs_calloc(1, sizeof(ScsLinSysWork));
332
345
  scs_int n_plus_m = A->n + A->m, ldl_status, ldl_prepare_status;
333
346
  p->m = A->m;
334
347
  p->n = A->n;
335
- p->rho_x = rho_x;
336
- p->perm = (scs_int *)scs_malloc(sizeof(scs_int) * n_plus_m);
337
- p->L = (csc *)scs_malloc(sizeof(csc));
338
- p->bp = (scs_float *)scs_malloc(n_plus_m * sizeof(scs_float));
339
- p->rho_y_vec_idxs = (scs_int *)scs_malloc(A->m * sizeof(scs_int));
348
+ p->diag_p = (scs_float *)scs_calloc(A->n, sizeof(scs_float));
349
+ p->perm = (scs_int *)scs_calloc(sizeof(scs_int), n_plus_m);
350
+ p->L = (csc *)scs_calloc(1, sizeof(csc));
351
+ p->bp = (scs_float *)scs_calloc(n_plus_m, sizeof(scs_float));
352
+ p->diag_r_idxs = (scs_int *)scs_calloc(n_plus_m, sizeof(scs_int));
340
353
  p->factorizations = 0;
341
354
  p->L->m = n_plus_m;
342
355
  p->L->n = n_plus_m;
343
356
  p->L->nz = -1;
344
- p->kkt = permute_kkt(A, P, p, rho_y_vec);
357
+ p->kkt = permute_kkt(A, P, p, diag_r);
345
358
  ldl_prepare_status = ldl_prepare(p);
346
359
  ldl_status = ldl_factor(p, A->n);
347
360
  if (ldl_prepare_status < 0 || ldl_status < 0) {
@@ -18,12 +18,12 @@ struct SCS_LIN_SYS_WORK {
18
18
  scs_float *Dinv; /* inverse diagonal matrix of factorization */
19
19
  scs_int *perm; /* permutation of KKT matrix for factorization */
20
20
  scs_float *bp; /* workspace memory for solves */
21
- scs_int *rho_y_vec_idxs;
21
+ scs_int *diag_r_idxs;
22
22
  scs_int factorizations;
23
23
  /* ldl factorization workspace */
24
24
  scs_float *D, *fwork;
25
25
  scs_int *etree, *iwork, *Lnz, *bwork;
26
- scs_float rho_x;
26
+ scs_float *diag_p;
27
27
  };
28
28
 
29
29
  #ifdef __cplusplus
@@ -17,7 +17,8 @@ char *SCS(get_lin_sys_summary)(ScsLinSysWork *p, const ScsInfo *info) {
17
17
  }
18
18
  */
19
19
 
20
- /* set M = inv ( diag ( rho_x * I + P + A' R_y^{-1} A ) ) */
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 ) ) */
21
22
  static void set_preconditioner(ScsLinSysWork *p) {
22
23
  scs_int i, k;
23
24
  scs_float *M = p->M;
@@ -28,22 +29,26 @@ static void set_preconditioner(ScsLinSysWork *p) {
28
29
  scs_printf("getting pre-conditioner\n");
29
30
  #endif
30
31
 
32
+ /* M_ii = (R_x)_i + P_ii + a_i' (R_y)^-1 a_i */
31
33
  for (i = 0; i < A->n; ++i) { /* cols */
32
- M[i] = p->rho_x;
33
- /* diag(A' R_y^{-1} A) */
34
+ /* M_ii = (R_x)_i */
35
+ M[i] = p->diag_r[i];
36
+ /* M_ii += a_i' (R_y)^-1 a_i */
34
37
  for (k = A->p[i]; k < A->p[i + 1]; ++k) {
35
38
  /* A->i[k] is row of entry k with value A->x[k] */
36
- M[i] += A->x[k] * A->x[k] / p->rho_y_vec[A->i[k]];
39
+ M[i] += A->x[k] * A->x[k] / p->diag_r[A->n + A->i[k]];
37
40
  }
38
41
  if (P) {
39
42
  for (k = P->p[i]; k < P->p[i + 1]; k++) {
40
43
  /* diagonal element only */
41
44
  if (P->i[k] == i) { /* row == col */
45
+ /* M_ii += P_ii */
42
46
  M[i] += P->x[k];
43
47
  break;
44
48
  }
45
49
  }
46
50
  }
51
+ /* finally invert for pre-conditioner */
47
52
  M[i] = 1. / M[i];
48
53
  }
49
54
  #if VERBOSITY > 0
@@ -111,10 +116,18 @@ void SCS(free_lin_sys_work)(ScsLinSysWork *p) {
111
116
  }
112
117
 
113
118
  /* vec -> R_y^{-1} vec */
114
- static void scale_by_diag_r(scs_float *vec, ScsLinSysWork *p) {
119
+ static void scale_by_r_y_inv(scs_float *vec, ScsLinSysWork *p) {
115
120
  scs_int i;
116
121
  for (i = 0; i < p->m; ++i) {
117
- vec[i] /= p->rho_y_vec[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];
118
131
  }
119
132
  }
120
133
 
@@ -123,7 +136,7 @@ static void accum_by_a(ScsLinSysWork *p, const scs_float *x, scs_float *y) {
123
136
  SCS(accum_by_atrans)(p->At, x, y);
124
137
  }
125
138
 
126
- /* y = (rho_x * I + P + A' R_y^{-1} A) x */
139
+ /* y = (R_x + P + A' R_y^{-1} A) x */
127
140
  static void mat_vec(const ScsMatrix *A, const ScsMatrix *P, ScsLinSysWork *p,
128
141
  const scs_float *x, scs_float *y) {
129
142
  scs_float *z = p->tmp;
@@ -133,10 +146,10 @@ static void mat_vec(const ScsMatrix *A, const ScsMatrix *P, ScsLinSysWork *p,
133
146
  SCS(accum_by_p)(P, x, y); /* y = Px */
134
147
  }
135
148
  accum_by_a(p, x, z); /* z = Ax */
136
- scale_by_diag_r(z, p); /* z = R_y^{-1} A x */
149
+ scale_by_r_y_inv(z, p); /* z = R_y^{-1} A x */
137
150
  SCS(accum_by_atrans)(A, z, y); /* y += A'z, y = Px + A' R_y^{-1} Ax */
138
- /* y = rho_x * x + Px + A' R_y^{-1} A x */
139
- SCS(add_scaled_array)(y, x, A->n, p->rho_x);
151
+ /* y = R_x * x + Px + A' R_y^{-1} A * x */
152
+ accum_by_r_x(y, x, p);
140
153
  }
141
154
 
142
155
  static void apply_pre_conditioner(scs_float *z, scs_float *r, scs_int n,
@@ -149,36 +162,35 @@ static void apply_pre_conditioner(scs_float *z, scs_float *r, scs_int n,
149
162
  }
150
163
 
151
164
  /* no need to update anything in this case */
152
- void SCS(update_lin_sys_rho_y_vec)(ScsLinSysWork *p, scs_float *rho_y_vec) {
153
- p->rho_y_vec = rho_y_vec; /* this isn't needed but do it to be safe */
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 */
154
167
  set_preconditioner(p);
155
168
  }
156
169
 
157
170
  ScsLinSysWork *SCS(init_lin_sys_work)(const ScsMatrix *A, const ScsMatrix *P,
158
- scs_float *rho_y_vec, scs_float rho_x) {
171
+ const scs_float *diag_r) {
159
172
  ScsLinSysWork *p = (ScsLinSysWork *)scs_calloc(1, sizeof(ScsLinSysWork));
160
173
  p->A = A;
161
174
  p->P = P;
162
175
  p->m = A->m;
163
176
  p->n = A->n;
164
- p->rho_x = rho_x;
165
177
 
166
- p->p = (scs_float *)scs_malloc((A->n) * sizeof(scs_float));
167
- p->r = (scs_float *)scs_malloc((A->n) * sizeof(scs_float));
168
- p->Gp = (scs_float *)scs_malloc((A->n) * sizeof(scs_float));
169
- p->tmp = (scs_float *)scs_malloc((A->m) * sizeof(scs_float));
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));
170
182
 
171
183
  /* memory for A transpose */
172
- p->At = (ScsMatrix *)scs_malloc(sizeof(ScsMatrix));
184
+ p->At = (ScsMatrix *)scs_calloc(1, sizeof(ScsMatrix));
173
185
  p->At->m = A->n;
174
186
  p->At->n = A->m;
175
- p->At->i = (scs_int *)scs_malloc((A->p[A->n]) * sizeof(scs_int));
176
- p->At->p = (scs_int *)scs_malloc((A->m + 1) * sizeof(scs_int));
177
- 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));
178
190
  transpose(A, p);
179
191
 
180
192
  /* preconditioner memory */
181
- p->rho_y_vec = rho_y_vec;
193
+ p->diag_r = diag_r;
182
194
  p->z = (scs_float *)scs_calloc(A->n, sizeof(scs_float));
183
195
  p->M = (scs_float *)scs_calloc(A->n, sizeof(scs_float));
184
196
  set_preconditioner(p);
@@ -192,8 +204,7 @@ ScsLinSysWork *SCS(init_lin_sys_work)(const ScsMatrix *A, const ScsMatrix *P,
192
204
  return p;
193
205
  }
194
206
 
195
- /* solves (rho_x * I + P + A' R_y^{-1} A)x = b, s warm start, solution stored in
196
- * b */
207
+ /* solves (R_x * I + P + A' R_y^{-1} A)x = b, s warm start, solution in b */
197
208
  static scs_int pcg(ScsLinSysWork *pr, const scs_float *s, scs_float *b,
198
209
  scs_int max_its, scs_float tol) {
199
210
  scs_int i, n = pr->n;
@@ -268,14 +279,12 @@ static scs_int pcg(ScsLinSysWork *pr, const scs_float *s, scs_float *b,
268
279
  /* solves Mx = b, for x but stores result in b */
269
280
  /* s contains warm-start (if available) */
270
281
  /*
271
- * [x] = [rho_x I + P A' ]^{-1} [rx]
272
- * [y] [ A -R_y ] [ry]
273
- *
274
- * R_y = diag(rho_y_vec)
282
+ * [x] = [R_x + P A' ]^{-1} [rx]
283
+ * [y] [ A -R_y ] [ry]
275
284
  *
276
285
  * becomes:
277
286
  *
278
- * x = (rho_x I + P + A' R_y^{-1} A)^{-1} (rx + A' R_y^{-1} ry)
287
+ * x = (R_x + P + A' R_y^{-1} A)^{-1} (rx + A' R_y^{-1} ry)
279
288
  * y = R_y^{-1} (Ax - ry)
280
289
  *
281
290
  */
@@ -299,12 +308,12 @@ scs_int SCS(solve_lin_sys)(ScsLinSysWork *p, scs_float *b, const scs_float *s,
299
308
  /* tmp = ry */
300
309
  memcpy(p->tmp, &(b[p->n]), p->m * sizeof(scs_float));
301
310
  /* tmp = R_y^{-1} * ry */
302
- scale_by_diag_r(p->tmp, p);
311
+ scale_by_r_y_inv(p->tmp, p);
303
312
  /* b[:n] = rx + A' R_y^{-1} ry */
304
313
  SCS(accum_by_atrans)(p->A, p->tmp, b);
305
314
  /* set max_iters to 10 * n (though in theory n is enough for any tol) */
306
315
  max_iters = 10 * p->n;
307
- /* solves (rho_x I + P + A' R_y^{-1} A)x = b, s warm start, solution stored in
316
+ /* solves (R_x + P + A' R_y^{-1} A)x = b, s warm start, solution stored in
308
317
  * b */
309
318
  cg_its = pcg(p, s, b, max_iters, tol); /* b[:n] = x */
310
319
 
@@ -313,7 +322,7 @@ scs_int SCS(solve_lin_sys)(ScsLinSysWork *p, scs_float *b, const scs_float *s,
313
322
  /* b[n:] = Ax - ry */
314
323
  accum_by_a(p, b, &(b[p->n]));
315
324
  /* b[n:] = R_y^{-1} (Ax - ry) = y */
316
- scale_by_diag_r(&(b[p->n]), p);
325
+ scale_by_r_y_inv(&(b[p->n]), p);
317
326
  p->tot_cg_its += cg_its;
318
327
  #if VERBOSITY > 1
319
328
  scs_printf("tol %.3e\n", tol);
@@ -25,8 +25,7 @@ struct SCS_LIN_SYS_WORK {
25
25
  scs_float *M;
26
26
  /* reporting */
27
27
  scs_int tot_cg_its;
28
- scs_float *rho_y_vec;
29
- scs_float rho_x;
28
+ const scs_float *diag_r;
30
29
  };
31
30
 
32
31
  #ifdef __cplusplus
@@ -12,9 +12,9 @@ csc *SCS(cs_spalloc)(scs_int m, scs_int n, scs_int nzmax, scs_int values,
12
12
  A->n = n;
13
13
  A->nzmax = nzmax = MAX(nzmax, 1);
14
14
  A->nz = triplet ? 0 : -1; /* allocate triplet or comp.col */
15
- A->p = (scs_int *)scs_malloc((triplet ? nzmax : n + 1) * sizeof(scs_int));
16
- A->i = (scs_int *)scs_malloc(nzmax * sizeof(scs_int));
17
- A->x = values ? (scs_float *)scs_malloc(nzmax * sizeof(scs_float)) : SCS_NULL;
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
18
  return (!A->p || !A->i || (values && !A->x)) ? SCS(cs_spfree)(A) : A;
19
19
  }
20
20