scs 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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