scs 0.2.2 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -0
- data/LICENSE.txt +18 -18
- data/README.md +19 -14
- data/lib/scs/ffi.rb +31 -20
- data/lib/scs/solver.rb +32 -9
- data/lib/scs/version.rb +1 -1
- data/vendor/scs/CITATION.cff +39 -0
- data/vendor/scs/CMakeLists.txt +320 -0
- data/vendor/scs/Makefile +32 -23
- data/vendor/scs/README.md +9 -218
- data/vendor/scs/include/aa.h +67 -23
- data/vendor/scs/include/cones.h +22 -19
- data/vendor/scs/include/glbopts.h +107 -79
- data/vendor/scs/include/linalg.h +3 -4
- data/vendor/scs/include/linsys.h +58 -44
- data/vendor/scs/include/normalize.h +6 -5
- data/vendor/scs/include/rw.h +8 -2
- data/vendor/scs/include/scs.h +257 -141
- data/vendor/scs/include/scs_types.h +34 -0
- data/vendor/scs/include/scs_work.h +83 -0
- data/vendor/scs/include/util.h +3 -15
- data/vendor/scs/linsys/cpu/direct/private.c +241 -232
- data/vendor/scs/linsys/cpu/direct/private.h +13 -7
- data/vendor/scs/linsys/cpu/indirect/private.c +194 -118
- data/vendor/scs/linsys/cpu/indirect/private.h +7 -4
- data/vendor/scs/linsys/csparse.c +87 -0
- data/vendor/scs/linsys/csparse.h +34 -0
- data/vendor/scs/linsys/external/amd/SuiteSparse_config.c +6 -6
- data/vendor/scs/linsys/external/amd/SuiteSparse_config.h +6 -1
- data/vendor/scs/linsys/external/amd/amd_internal.h +1 -1
- data/vendor/scs/linsys/external/amd/amd_order.c +5 -5
- data/vendor/scs/linsys/external/qdldl/changes +2 -0
- data/vendor/scs/linsys/external/qdldl/qdldl.c +29 -46
- data/vendor/scs/linsys/external/qdldl/qdldl.h +33 -41
- data/vendor/scs/linsys/external/qdldl/qdldl_types.h +11 -3
- data/vendor/scs/linsys/gpu/gpu.c +58 -21
- data/vendor/scs/linsys/gpu/gpu.h +70 -35
- data/vendor/scs/linsys/gpu/indirect/private.c +394 -157
- data/vendor/scs/linsys/gpu/indirect/private.h +27 -12
- data/vendor/scs/linsys/scs_matrix.c +478 -0
- data/vendor/scs/linsys/scs_matrix.h +70 -0
- data/vendor/scs/scs.mk +14 -10
- data/vendor/scs/src/aa.c +394 -110
- data/vendor/scs/src/cones.c +497 -359
- data/vendor/scs/src/ctrlc.c +15 -5
- data/vendor/scs/src/linalg.c +107 -26
- data/vendor/scs/src/normalize.c +30 -72
- data/vendor/scs/src/rw.c +202 -27
- data/vendor/scs/src/scs.c +769 -571
- data/vendor/scs/src/scs_version.c +11 -3
- data/vendor/scs/src/util.c +37 -106
- data/vendor/scs/test/minunit.h +22 -8
- data/vendor/scs/test/problem_utils.h +180 -25
- data/vendor/scs/test/problems/degenerate.h +130 -0
- data/vendor/scs/test/problems/hs21_tiny_qp.h +124 -0
- data/vendor/scs/test/problems/hs21_tiny_qp_rw.h +116 -0
- data/vendor/scs/test/problems/infeasible_tiny_qp.h +100 -0
- data/vendor/scs/test/problems/qafiro_tiny_qp.h +199 -0
- data/vendor/scs/test/problems/random_prob +0 -0
- data/vendor/scs/test/problems/random_prob.h +45 -0
- data/vendor/scs/test/problems/rob_gauss_cov_est.h +188 -31
- data/vendor/scs/test/problems/small_lp.h +14 -13
- data/vendor/scs/test/problems/small_qp.h +352 -0
- data/vendor/scs/test/problems/test_validation.h +43 -0
- data/vendor/scs/test/problems/unbounded_tiny_qp.h +82 -0
- data/vendor/scs/test/random_socp_prob.c +54 -53
- data/vendor/scs/test/rng.h +109 -0
- data/vendor/scs/test/run_from_file.c +20 -11
- data/vendor/scs/test/run_tests.c +35 -2
- metadata +29 -98
- data/vendor/scs/linsys/amatrix.c +0 -305
- data/vendor/scs/linsys/amatrix.h +0 -36
- data/vendor/scs/linsys/amatrix.o +0 -0
- data/vendor/scs/linsys/cpu/direct/private.o +0 -0
- data/vendor/scs/linsys/cpu/indirect/private.o +0 -0
- data/vendor/scs/linsys/external/amd/SuiteSparse_config.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_1.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_2.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_aat.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_control.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_defaults.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_dump.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_global.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_info.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_order.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_post_tree.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_postorder.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_preprocess.o +0 -0
- data/vendor/scs/linsys/external/amd/amd_valid.o +0 -0
- data/vendor/scs/linsys/external/qdldl/qdldl.o +0 -0
- data/vendor/scs/src/aa.o +0 -0
- data/vendor/scs/src/cones.o +0 -0
- data/vendor/scs/src/ctrlc.o +0 -0
- data/vendor/scs/src/linalg.o +0 -0
- data/vendor/scs/src/normalize.o +0 -0
- data/vendor/scs/src/rw.o +0 -0
- data/vendor/scs/src/scs.o +0 -0
- data/vendor/scs/src/scs_version.o +0 -0
- data/vendor/scs/src/util.o +0 -0
- data/vendor/scs/test/data/small_random_socp +0 -0
- data/vendor/scs/test/problems/small_random_socp.h +0 -33
- data/vendor/scs/test/run_tests +0 -2
data/vendor/scs/src/cones.c
CHANGED
|
@@ -1,80 +1,122 @@
|
|
|
1
1
|
#include "cones.h"
|
|
2
|
-
|
|
3
2
|
#include "linalg.h"
|
|
4
3
|
#include "scs.h"
|
|
5
4
|
#include "scs_blas.h" /* contains BLAS(X) macros and type info */
|
|
6
5
|
#include "util.h"
|
|
7
6
|
|
|
8
|
-
#define
|
|
9
|
-
#define
|
|
10
|
-
#define CONE_THRESH (1e-6)
|
|
7
|
+
#define CONE_TOL (1e-9)
|
|
8
|
+
#define CONE_THRESH (1e-8)
|
|
11
9
|
#define EXP_CONE_MAX_ITERS (100)
|
|
10
|
+
#define BOX_CONE_MAX_ITERS (25)
|
|
12
11
|
#define POW_CONE_MAX_ITERS (20)
|
|
13
12
|
|
|
13
|
+
/* Box cone limits (+ or -) taken to be INF */
|
|
14
|
+
#define MAX_BOX_VAL (1e15)
|
|
15
|
+
|
|
14
16
|
#ifdef USE_LAPACK
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
17
|
+
|
|
18
|
+
#ifdef __cplusplus
|
|
19
|
+
extern "C" {
|
|
20
|
+
#endif
|
|
21
|
+
|
|
22
|
+
void BLAS(syev)(const char *jobz, const char *uplo, blas_int *n, scs_float *a,
|
|
23
|
+
blas_int *lda, scs_float *w, scs_float *work, blas_int *lwork,
|
|
24
|
+
blas_int *info);
|
|
25
|
+
blas_int BLAS(syrk)(const char *uplo, const char *trans, const blas_int *n,
|
|
26
|
+
const blas_int *k, const scs_float *alpha,
|
|
27
|
+
const scs_float *a, const blas_int *lda,
|
|
28
|
+
const scs_float *beta, scs_float *c, const blas_int *ldc);
|
|
24
29
|
void BLAS(scal)(const blas_int *n, const scs_float *sa, scs_float *sx,
|
|
25
30
|
const blas_int *incx);
|
|
26
|
-
|
|
31
|
+
|
|
32
|
+
#ifdef __cplusplus
|
|
33
|
+
}
|
|
27
34
|
#endif
|
|
28
35
|
|
|
29
|
-
|
|
36
|
+
#endif
|
|
37
|
+
|
|
38
|
+
/* set the vector of rho y terms, based on scale and cones */
|
|
39
|
+
void SCS(set_r_y)(const ScsConeWork *c, scs_float scale, scs_float *r_y) {
|
|
40
|
+
scs_int i;
|
|
41
|
+
/* z cone */
|
|
42
|
+
for (i = 0; i < c->k->z; ++i) {
|
|
43
|
+
/* set rho_y small for z, similar to rho_x term, since z corresponds to
|
|
44
|
+
* dual free cone, this effectively decreases penalty on those entries
|
|
45
|
+
* and lets them be determined almost entirely by the linear system solve
|
|
46
|
+
*/
|
|
47
|
+
r_y[i] = 1.0 / (1000. * scale);
|
|
48
|
+
}
|
|
49
|
+
/* others */
|
|
50
|
+
for (i = c->k->z; i < c->m; ++i) {
|
|
51
|
+
r_y[i] = 1.0 / scale;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/* the function f aggregates the entries within each cone */
|
|
56
|
+
void SCS(enforce_cone_boundaries)(const ScsConeWork *c, scs_float *vec,
|
|
57
|
+
scs_float (*f)(const scs_float *, scs_int)) {
|
|
58
|
+
scs_int i, j, delta;
|
|
59
|
+
scs_int count = c->cone_boundaries[0];
|
|
60
|
+
scs_float wrk;
|
|
61
|
+
for (i = 1; i < c->cone_boundaries_len; ++i) {
|
|
62
|
+
delta = c->cone_boundaries[i];
|
|
63
|
+
wrk = f(&(vec[count]), delta);
|
|
64
|
+
for (j = count; j < count + delta; ++j) {
|
|
65
|
+
vec[j] = wrk;
|
|
66
|
+
}
|
|
67
|
+
count += delta;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
static inline scs_int get_sd_cone_size(scs_int s) {
|
|
72
|
+
return (s * (s + 1)) / 2;
|
|
73
|
+
}
|
|
30
74
|
|
|
31
75
|
/*
|
|
32
76
|
* boundaries will contain array of indices of rows of A corresponding to
|
|
33
77
|
* cone boundaries, boundaries[0] is starting index for cones of size strictly
|
|
34
|
-
* larger than 1
|
|
35
|
-
* returns length of boundaries array, boundaries malloc-ed here so should be
|
|
36
|
-
* freed
|
|
78
|
+
* larger than 1, boundaries malloc-ed here so should be freed.
|
|
37
79
|
*/
|
|
38
|
-
|
|
39
|
-
scs_int i, count = 0;
|
|
40
|
-
scs_int
|
|
41
|
-
|
|
42
|
-
b
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
80
|
+
void set_cone_boundaries(const ScsCone *k, ScsConeWork *c) {
|
|
81
|
+
scs_int i, s_cone_sz, count = 0;
|
|
82
|
+
scs_int cone_boundaries_len =
|
|
83
|
+
1 + k->qsize + k->ssize + k->ed + k->ep + k->psize;
|
|
84
|
+
scs_int *b = (scs_int *)scs_calloc(cone_boundaries_len, sizeof(scs_int));
|
|
85
|
+
/* cones that can be scaled independently */
|
|
86
|
+
b[count] = k->z + k->l + k->bsize;
|
|
87
|
+
count += 1; /* started at 0 now move to first entry */
|
|
88
|
+
for (i = 0; i < k->qsize; ++i) {
|
|
89
|
+
b[count + i] = k->q[i];
|
|
46
90
|
}
|
|
47
91
|
count += k->qsize;
|
|
48
92
|
for (i = 0; i < k->ssize; ++i) {
|
|
49
|
-
|
|
93
|
+
s_cone_sz = get_sd_cone_size(k->s[i]);
|
|
94
|
+
b[count + i] = s_cone_sz;
|
|
50
95
|
}
|
|
51
|
-
count += k->ssize;
|
|
96
|
+
count += k->ssize; /* add ssize here not ssize * (ssize + 1) / 2 */
|
|
97
|
+
/* exp cones */
|
|
52
98
|
for (i = 0; i < k->ep + k->ed; ++i) {
|
|
53
99
|
b[count + i] = 3;
|
|
54
100
|
}
|
|
55
101
|
count += k->ep + k->ed;
|
|
102
|
+
/* power cones */
|
|
56
103
|
for (i = 0; i < k->psize; ++i) {
|
|
57
104
|
b[count + i] = 3;
|
|
58
105
|
}
|
|
59
106
|
count += k->psize;
|
|
60
|
-
|
|
61
|
-
|
|
107
|
+
/* other cones */
|
|
108
|
+
c->cone_boundaries = b;
|
|
109
|
+
c->cone_boundaries_len = cone_boundaries_len;
|
|
62
110
|
}
|
|
63
111
|
|
|
64
112
|
static scs_int get_full_cone_dims(const ScsCone *k) {
|
|
65
|
-
scs_int i, c =
|
|
66
|
-
if (k->
|
|
67
|
-
c += k->f;
|
|
68
|
-
}
|
|
69
|
-
if (k->l) {
|
|
70
|
-
c += k->l;
|
|
71
|
-
}
|
|
72
|
-
if (k->qsize && k->q) {
|
|
113
|
+
scs_int i, c = k->z + k->l + k->bsize;
|
|
114
|
+
if (k->qsize) {
|
|
73
115
|
for (i = 0; i < k->qsize; ++i) {
|
|
74
116
|
c += k->q[i];
|
|
75
117
|
}
|
|
76
118
|
}
|
|
77
|
-
if (k->ssize
|
|
119
|
+
if (k->ssize) {
|
|
78
120
|
for (i = 0; i < k->ssize; ++i) {
|
|
79
121
|
c += get_sd_cone_size(k->s[i]);
|
|
80
122
|
}
|
|
@@ -85,7 +127,7 @@ static scs_int get_full_cone_dims(const ScsCone *k) {
|
|
|
85
127
|
if (k->ep) {
|
|
86
128
|
c += 3 * k->ep;
|
|
87
129
|
}
|
|
88
|
-
if (k->
|
|
130
|
+
if (k->psize) {
|
|
89
131
|
c += 3 * k->psize;
|
|
90
132
|
}
|
|
91
133
|
return c;
|
|
@@ -98,49 +140,61 @@ scs_int SCS(validate_cones)(const ScsData *d, const ScsCone *k) {
|
|
|
98
140
|
(long)get_full_cone_dims(k), (long)d->m);
|
|
99
141
|
return -1;
|
|
100
142
|
}
|
|
101
|
-
if (k->
|
|
102
|
-
scs_printf("free cone error\n");
|
|
143
|
+
if (k->z && k->z < 0) {
|
|
144
|
+
scs_printf("free cone dimension error\n");
|
|
103
145
|
return -1;
|
|
104
146
|
}
|
|
105
147
|
if (k->l && k->l < 0) {
|
|
106
|
-
scs_printf("lp cone error\n");
|
|
148
|
+
scs_printf("lp cone dimension error\n");
|
|
107
149
|
return -1;
|
|
108
150
|
}
|
|
151
|
+
if (k->bsize) {
|
|
152
|
+
if (k->bsize < 0) {
|
|
153
|
+
scs_printf("box cone dimension error\n");
|
|
154
|
+
return -1;
|
|
155
|
+
}
|
|
156
|
+
for (i = 0; i < k->bsize - 1; ++i) {
|
|
157
|
+
if (k->bl[i] > k->bu[i]) {
|
|
158
|
+
scs_printf("infeasible: box lower bound larger than upper bound\n");
|
|
159
|
+
return -1;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
109
163
|
if (k->qsize && k->q) {
|
|
110
164
|
if (k->qsize < 0) {
|
|
111
|
-
scs_printf("soc cone error\n");
|
|
165
|
+
scs_printf("soc cone dimension error\n");
|
|
112
166
|
return -1;
|
|
113
167
|
}
|
|
114
168
|
for (i = 0; i < k->qsize; ++i) {
|
|
115
169
|
if (k->q[i] < 0) {
|
|
116
|
-
scs_printf("soc cone error\n");
|
|
170
|
+
scs_printf("soc cone dimension error\n");
|
|
117
171
|
return -1;
|
|
118
172
|
}
|
|
119
173
|
}
|
|
120
174
|
}
|
|
121
175
|
if (k->ssize && k->s) {
|
|
122
176
|
if (k->ssize < 0) {
|
|
123
|
-
scs_printf("sd cone error\n");
|
|
177
|
+
scs_printf("sd cone dimension error\n");
|
|
124
178
|
return -1;
|
|
125
179
|
}
|
|
126
180
|
for (i = 0; i < k->ssize; ++i) {
|
|
127
181
|
if (k->s[i] < 0) {
|
|
128
|
-
scs_printf("sd cone error\n");
|
|
182
|
+
scs_printf("sd cone dimension error\n");
|
|
129
183
|
return -1;
|
|
130
184
|
}
|
|
131
185
|
}
|
|
132
186
|
}
|
|
133
187
|
if (k->ed && k->ed < 0) {
|
|
134
|
-
scs_printf("ep cone error\n");
|
|
188
|
+
scs_printf("ep cone dimension error\n");
|
|
135
189
|
return -1;
|
|
136
190
|
}
|
|
137
191
|
if (k->ep && k->ep < 0) {
|
|
138
|
-
scs_printf("ed cone error\n");
|
|
192
|
+
scs_printf("ed cone dimension error\n");
|
|
139
193
|
return -1;
|
|
140
194
|
}
|
|
141
195
|
if (k->psize && k->p) {
|
|
142
196
|
if (k->psize < 0) {
|
|
143
|
-
scs_printf("power cone error\n");
|
|
197
|
+
scs_printf("power cone dimension error\n");
|
|
144
198
|
return -1;
|
|
145
199
|
}
|
|
146
200
|
for (i = 0; i < k->psize; ++i) {
|
|
@@ -153,14 +207,6 @@ scs_int SCS(validate_cones)(const ScsData *d, const ScsCone *k) {
|
|
|
153
207
|
return 0;
|
|
154
208
|
}
|
|
155
209
|
|
|
156
|
-
char *SCS(get_cone_summary)(const ScsInfo *info, ScsConeWork *c) {
|
|
157
|
-
char *str = (char *)scs_malloc(sizeof(char) * 64);
|
|
158
|
-
sprintf(str, "\tCones: avg projection time: %1.2es\n",
|
|
159
|
-
c->total_cone_time / (info->iter + 1) / 1e3);
|
|
160
|
-
c->total_cone_time = 0.0;
|
|
161
|
-
return str;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
210
|
void SCS(finish_cone)(ScsConeWork *c) {
|
|
165
211
|
#ifdef USE_LAPACK
|
|
166
212
|
if (c->Xs) {
|
|
@@ -175,10 +221,19 @@ void SCS(finish_cone)(ScsConeWork *c) {
|
|
|
175
221
|
if (c->work) {
|
|
176
222
|
scs_free(c->work);
|
|
177
223
|
}
|
|
178
|
-
if (c->iwork) {
|
|
179
|
-
scs_free(c->iwork);
|
|
180
|
-
}
|
|
181
224
|
#endif
|
|
225
|
+
if (c->cone_boundaries) {
|
|
226
|
+
scs_free(c->cone_boundaries);
|
|
227
|
+
}
|
|
228
|
+
if (c->s) {
|
|
229
|
+
scs_free(c->s);
|
|
230
|
+
}
|
|
231
|
+
if (c->bu) {
|
|
232
|
+
scs_free(c->bu);
|
|
233
|
+
}
|
|
234
|
+
if (c->bl) {
|
|
235
|
+
scs_free(c->bl);
|
|
236
|
+
}
|
|
182
237
|
if (c) {
|
|
183
238
|
scs_free(c);
|
|
184
239
|
}
|
|
@@ -186,98 +241,99 @@ void SCS(finish_cone)(ScsConeWork *c) {
|
|
|
186
241
|
|
|
187
242
|
char *SCS(get_cone_header)(const ScsCone *k) {
|
|
188
243
|
char *tmp = (char *)scs_malloc(sizeof(char) * 512);
|
|
189
|
-
scs_int i, soc_vars,
|
|
190
|
-
sprintf(tmp, "
|
|
191
|
-
if (k->
|
|
192
|
-
sprintf(tmp + strlen(tmp), "\
|
|
193
|
-
(long)k->
|
|
244
|
+
scs_int i, soc_vars, sd_vars;
|
|
245
|
+
sprintf(tmp, "cones: ");
|
|
246
|
+
if (k->z) {
|
|
247
|
+
sprintf(tmp + strlen(tmp), "\t z: primal zero / dual free vars: %li\n",
|
|
248
|
+
(long)k->z);
|
|
194
249
|
}
|
|
195
250
|
if (k->l) {
|
|
196
|
-
sprintf(tmp + strlen(tmp), "\
|
|
251
|
+
sprintf(tmp + strlen(tmp), "\t l: linear vars: %li\n", (long)k->l);
|
|
252
|
+
}
|
|
253
|
+
if (k->bsize) {
|
|
254
|
+
sprintf(tmp + strlen(tmp), "\t b: box cone vars: %li\n", (long)(k->bsize));
|
|
197
255
|
}
|
|
198
256
|
soc_vars = 0;
|
|
199
|
-
soc_blks = 0;
|
|
200
257
|
if (k->qsize && k->q) {
|
|
201
|
-
soc_blks = k->qsize;
|
|
202
258
|
for (i = 0; i < k->qsize; i++) {
|
|
203
259
|
soc_vars += k->q[i];
|
|
204
260
|
}
|
|
205
|
-
sprintf(tmp + strlen(tmp), "\
|
|
206
|
-
(long)soc_vars, (long)
|
|
261
|
+
sprintf(tmp + strlen(tmp), "\t q: soc vars: %li, qsize: %li\n",
|
|
262
|
+
(long)soc_vars, (long)k->qsize);
|
|
207
263
|
}
|
|
208
264
|
sd_vars = 0;
|
|
209
|
-
sd_blks = 0;
|
|
210
265
|
if (k->ssize && k->s) {
|
|
211
|
-
sd_blks = k->ssize;
|
|
212
266
|
for (i = 0; i < k->ssize; i++) {
|
|
213
267
|
sd_vars += get_sd_cone_size(k->s[i]);
|
|
214
268
|
}
|
|
215
|
-
sprintf(tmp + strlen(tmp), "\
|
|
216
|
-
(long)
|
|
269
|
+
sprintf(tmp + strlen(tmp), "\t s: psd vars: %li, ssize: %li\n",
|
|
270
|
+
(long)sd_vars, (long)k->ssize);
|
|
217
271
|
}
|
|
218
272
|
if (k->ep || k->ed) {
|
|
219
|
-
sprintf(tmp + strlen(tmp), "\
|
|
273
|
+
sprintf(tmp + strlen(tmp), "\t e: exp vars: %li, dual exp vars: %li\n",
|
|
220
274
|
(long)(3 * k->ep), (long)(3 * k->ed));
|
|
221
275
|
}
|
|
222
276
|
if (k->psize && k->p) {
|
|
223
|
-
sprintf(tmp + strlen(tmp), "\
|
|
277
|
+
sprintf(tmp + strlen(tmp), "\t p: primal + dual power vars: %li\n",
|
|
224
278
|
(long)(3 * k->psize));
|
|
225
279
|
}
|
|
226
280
|
return tmp;
|
|
227
281
|
}
|
|
228
282
|
|
|
229
|
-
static scs_int is_simple_semi_definite_cone(scs_int *s, scs_int ssize) {
|
|
230
|
-
scs_int i;
|
|
231
|
-
for (i = 0; i < ssize; i++) {
|
|
232
|
-
if (s[i] > 2) {
|
|
233
|
-
return 0; /* false */
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
return 1; /* true */
|
|
237
|
-
}
|
|
238
|
-
|
|
239
283
|
static scs_float exp_newton_one_d(scs_float rho, scs_float y_hat,
|
|
240
|
-
scs_float z_hat) {
|
|
241
|
-
scs_float t = MAX(-z_hat, 1e-
|
|
242
|
-
scs_float f
|
|
284
|
+
scs_float z_hat, scs_float w) {
|
|
285
|
+
scs_float t_prev, t = MAX(w - z_hat, MAX(-z_hat, 1e-9));
|
|
286
|
+
scs_float f = 1., fp = 1.;
|
|
243
287
|
scs_int i;
|
|
244
288
|
for (i = 0; i < EXP_CONE_MAX_ITERS; ++i) {
|
|
289
|
+
t_prev = t;
|
|
245
290
|
f = t * (t + z_hat) / rho / rho - y_hat / rho + log(t / rho) + 1;
|
|
246
291
|
fp = (2 * t + z_hat) / rho / rho + 1 / t;
|
|
247
292
|
|
|
248
293
|
t = t - f / fp;
|
|
249
294
|
|
|
250
295
|
if (t <= -z_hat) {
|
|
251
|
-
|
|
296
|
+
t = -z_hat;
|
|
297
|
+
break;
|
|
252
298
|
} else if (t <= 0) {
|
|
253
|
-
|
|
254
|
-
|
|
299
|
+
t = 0;
|
|
300
|
+
break;
|
|
301
|
+
} else if (ABS(t - t_prev) < CONE_TOL) {
|
|
302
|
+
break;
|
|
303
|
+
} else if (SQRTF(f * f / fp) < CONE_TOL) {
|
|
255
304
|
break;
|
|
256
305
|
}
|
|
257
306
|
}
|
|
307
|
+
if (i == EXP_CONE_MAX_ITERS) {
|
|
308
|
+
scs_printf("warning: exp cone newton step hit maximum %i iters\n", (int)i);
|
|
309
|
+
scs_printf("rho=%1.5e; y_hat=%1.5e; z_hat=%1.5e; w=%1.5e; f=%1.5e, "
|
|
310
|
+
"fp=%1.5e, t=%1.5e, t_prev= %1.5e\n",
|
|
311
|
+
rho, y_hat, z_hat, w, f, fp, t, t_prev);
|
|
312
|
+
}
|
|
258
313
|
return t + z_hat;
|
|
259
314
|
}
|
|
260
315
|
|
|
261
|
-
static void exp_solve_for_x_with_rho(scs_float *v, scs_float *x,
|
|
262
|
-
scs_float rho) {
|
|
263
|
-
x[2] = exp_newton_one_d(rho, v[1], v[2]);
|
|
316
|
+
static void exp_solve_for_x_with_rho(const scs_float *v, scs_float *x,
|
|
317
|
+
scs_float rho, scs_float w) {
|
|
318
|
+
x[2] = exp_newton_one_d(rho, v[1], v[2], w);
|
|
264
319
|
x[1] = (x[2] - v[2]) * x[2] / rho;
|
|
265
320
|
x[0] = v[0] - rho;
|
|
266
321
|
}
|
|
267
322
|
|
|
268
|
-
static scs_float exp_calc_grad(scs_float *v, scs_float *x, scs_float rho
|
|
269
|
-
|
|
323
|
+
static scs_float exp_calc_grad(const scs_float *v, scs_float *x, scs_float rho,
|
|
324
|
+
scs_float w) {
|
|
325
|
+
exp_solve_for_x_with_rho(v, x, rho, w);
|
|
270
326
|
if (x[1] <= 1e-12) {
|
|
271
327
|
return x[0];
|
|
272
328
|
}
|
|
273
329
|
return x[0] + x[1] * log(x[1] / x[2]);
|
|
274
330
|
}
|
|
275
331
|
|
|
276
|
-
static void exp_get_rho_ub(scs_float *v, scs_float *x, scs_float *ub,
|
|
332
|
+
static void exp_get_rho_ub(const scs_float *v, scs_float *x, scs_float *ub,
|
|
277
333
|
scs_float *lb) {
|
|
278
334
|
*lb = 0;
|
|
279
335
|
*ub = 0.125;
|
|
280
|
-
while (exp_calc_grad(v, x, *ub) > 0) {
|
|
336
|
+
while (exp_calc_grad(v, x, *ub, v[1]) > 0) {
|
|
281
337
|
*lb = *ub;
|
|
282
338
|
(*ub) *= 2;
|
|
283
339
|
}
|
|
@@ -288,8 +344,6 @@ static scs_int proj_exp_cone(scs_float *v) {
|
|
|
288
344
|
scs_int i;
|
|
289
345
|
scs_float ub, lb, rho, g, x[3];
|
|
290
346
|
scs_float r = v[0], s = v[1], t = v[2];
|
|
291
|
-
scs_float tol = CONE_TOL; /* iter < 0 ? CONE_TOL : MAX(CONE_TOL, 1 /
|
|
292
|
-
POWF((iter + 1), CONE_RATE)); */
|
|
293
347
|
|
|
294
348
|
/* v in cl(Kexp) */
|
|
295
349
|
if ((s * exp(r / s) - t <= CONE_THRESH && s > 0) ||
|
|
@@ -298,8 +352,8 @@ static scs_int proj_exp_cone(scs_float *v) {
|
|
|
298
352
|
}
|
|
299
353
|
|
|
300
354
|
/* -v in Kexp^* */
|
|
301
|
-
if ((
|
|
302
|
-
(
|
|
355
|
+
if ((r > 0 && r * exp(s / r) + exp(1) * t <= CONE_THRESH) ||
|
|
356
|
+
(r == 0 && s <= 0 && t <= 0)) {
|
|
303
357
|
memset(v, 0, 3 * sizeof(scs_float));
|
|
304
358
|
return 0;
|
|
305
359
|
}
|
|
@@ -314,22 +368,24 @@ static scs_int proj_exp_cone(scs_float *v) {
|
|
|
314
368
|
/* iterative procedure to find projection, bisects on dual variable: */
|
|
315
369
|
exp_get_rho_ub(v, x, &ub, &lb); /* get starting upper and lower bounds */
|
|
316
370
|
for (i = 0; i < EXP_CONE_MAX_ITERS; ++i) {
|
|
317
|
-
rho = (ub + lb) / 2;
|
|
318
|
-
g = exp_calc_grad(v, x, rho); /* calculates gradient wrt dual var */
|
|
371
|
+
rho = (ub + lb) / 2; /* halfway between upper and lower bounds */
|
|
372
|
+
g = exp_calc_grad(v, x, rho, x[1]); /* calculates gradient wrt dual var */
|
|
319
373
|
if (g > 0) {
|
|
320
374
|
lb = rho;
|
|
321
375
|
} else {
|
|
322
376
|
ub = rho;
|
|
323
377
|
}
|
|
324
|
-
if (ub - lb <
|
|
378
|
+
if (ub - lb < CONE_TOL) {
|
|
325
379
|
break;
|
|
326
380
|
}
|
|
327
381
|
}
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
scs_printf("exponential cone proj iters %i\n", i);
|
|
382
|
+
#if VERBOSITY > 10
|
|
383
|
+
scs_printf("exponential cone proj iters %i\n", (int)i);
|
|
331
384
|
#endif
|
|
332
|
-
|
|
385
|
+
if (i == EXP_CONE_MAX_ITERS) {
|
|
386
|
+
scs_printf("warning: exp cone outer step hit maximum %i iters\n", (int)i);
|
|
387
|
+
scs_printf("r=%1.5e; s=%1.5e; t=%1.5e\n", r, s, t);
|
|
388
|
+
}
|
|
333
389
|
v[0] = x[0];
|
|
334
390
|
v[1] = x[1];
|
|
335
391
|
v[2] = x[2];
|
|
@@ -337,15 +393,13 @@ static scs_int proj_exp_cone(scs_float *v) {
|
|
|
337
393
|
}
|
|
338
394
|
|
|
339
395
|
static scs_int set_up_sd_cone_work_space(ScsConeWork *c, const ScsCone *k) {
|
|
340
|
-
#ifdef USE_LAPACK
|
|
341
396
|
scs_int i;
|
|
397
|
+
#ifdef USE_LAPACK
|
|
342
398
|
blas_int n_max = 0;
|
|
343
|
-
scs_float eig_tol = 1e-8;
|
|
344
399
|
blas_int neg_one = -1;
|
|
345
|
-
blas_int m = 0;
|
|
346
400
|
blas_int info = 0;
|
|
347
401
|
scs_float wkopt = 0.0;
|
|
348
|
-
#if
|
|
402
|
+
#if VERBOSITY > 0
|
|
349
403
|
#define _STR_EXPAND(tok) #tok
|
|
350
404
|
#define _STR(tok) _STR_EXPAND(tok)
|
|
351
405
|
scs_printf("BLAS(func) = '%s'\n", _STR(BLAS(func)));
|
|
@@ -359,102 +413,36 @@ static scs_int set_up_sd_cone_work_space(ScsConeWork *c, const ScsCone *k) {
|
|
|
359
413
|
c->Xs = (scs_float *)scs_calloc(n_max * n_max, sizeof(scs_float));
|
|
360
414
|
c->Z = (scs_float *)scs_calloc(n_max * n_max, sizeof(scs_float));
|
|
361
415
|
c->e = (scs_float *)scs_calloc(n_max, sizeof(scs_float));
|
|
362
|
-
c->liwork = 0;
|
|
363
416
|
|
|
364
|
-
|
|
365
|
-
(
|
|
366
|
-
|
|
367
|
-
&
|
|
417
|
+
/* workspace query */
|
|
418
|
+
BLAS(syev)
|
|
419
|
+
("Vectors", "Lower", &n_max, c->Xs, &n_max, SCS_NULL, &wkopt, &neg_one,
|
|
420
|
+
&info);
|
|
368
421
|
|
|
369
422
|
if (info != 0) {
|
|
370
|
-
scs_printf("FATAL:
|
|
423
|
+
scs_printf("FATAL: syev failure, info = %li\n", (long)info);
|
|
371
424
|
return -1;
|
|
372
425
|
}
|
|
373
|
-
c->lwork = (blas_int)(wkopt +
|
|
426
|
+
c->lwork = (blas_int)(wkopt + 1); /* +1 for int casting safety */
|
|
374
427
|
c->work = (scs_float *)scs_calloc(c->lwork, sizeof(scs_float));
|
|
375
|
-
c->iwork = (blas_int *)scs_calloc(c->liwork, sizeof(blas_int));
|
|
376
428
|
|
|
377
|
-
if (!c->Xs || !c->Z || !c->e || !c->work
|
|
429
|
+
if (!c->Xs || !c->Z || !c->e || !c->work) {
|
|
378
430
|
return -1;
|
|
379
431
|
}
|
|
380
432
|
return 0;
|
|
381
433
|
#else
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
ScsConeWork *SCS(init_cone)(const ScsCone *k) {
|
|
393
|
-
ScsConeWork *c = (ScsConeWork *)scs_calloc(1, sizeof(ScsConeWork));
|
|
394
|
-
#if EXTRA_VERBOSE > 0
|
|
395
|
-
scs_printf("init_cone\n");
|
|
396
|
-
#endif
|
|
397
|
-
c->total_cone_time = 0.0;
|
|
398
|
-
if (k->ssize && k->s) {
|
|
399
|
-
if (!is_simple_semi_definite_cone(k->s, k->ssize) &&
|
|
400
|
-
set_up_sd_cone_work_space(c, k) < 0) {
|
|
401
|
-
SCS(finish_cone)(c);
|
|
402
|
-
return SCS_NULL;
|
|
434
|
+
for (i = 0; i < k->ssize; i++) {
|
|
435
|
+
if (k->s[i] > 1) {
|
|
436
|
+
scs_printf(
|
|
437
|
+
"FATAL: Cannot solve SDPs without linked blas+lapack libraries\n");
|
|
438
|
+
scs_printf(
|
|
439
|
+
"Install blas+lapack and re-compile SCS with blas+lapack library "
|
|
440
|
+
"locations\n");
|
|
441
|
+
return -1;
|
|
403
442
|
}
|
|
404
443
|
}
|
|
405
|
-
#if EXTRA_VERBOSE > 0
|
|
406
|
-
scs_printf("init_cone complete\n");
|
|
407
|
-
#ifdef MATLAB_MEX_FILE
|
|
408
|
-
mexEvalString("drawnow;");
|
|
409
|
-
#endif
|
|
410
|
-
#endif
|
|
411
|
-
return c;
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
static scs_int project_2x2_sdc(scs_float *X) {
|
|
415
|
-
scs_float a, b, d, l1, l2, x1, x2, rad;
|
|
416
|
-
scs_float sqrt2 = SQRTF(2.0);
|
|
417
|
-
a = X[0];
|
|
418
|
-
b = X[1] / sqrt2;
|
|
419
|
-
d = X[2];
|
|
420
|
-
|
|
421
|
-
if (ABS(b) < 1e-6) { /* diagonal matrix */
|
|
422
|
-
X[0] = MAX(a, 0);
|
|
423
|
-
X[1] = 0;
|
|
424
|
-
X[2] = MAX(d, 0);
|
|
425
|
-
return 0;
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
rad = SQRTF((a - d) * (a - d) + 4 * b * b);
|
|
429
|
-
/* l1 >= l2 always, since rad >= 0 */
|
|
430
|
-
l1 = 0.5 * (a + d + rad);
|
|
431
|
-
l2 = 0.5 * (a + d - rad);
|
|
432
|
-
|
|
433
|
-
#if EXTRA_VERBOSE > 0
|
|
434
|
-
scs_printf(
|
|
435
|
-
"2x2 SD: a = %4f, b = %4f, (X[1] = %4f, X[2] = %4f), d = %4f, "
|
|
436
|
-
"rad = %4f, l1 = %4f, l2 = %4f\n",
|
|
437
|
-
a, b, X[1], X[2], d, rad, l1, l2);
|
|
438
|
-
#endif
|
|
439
|
-
|
|
440
|
-
if (l2 >= 0) { /* both eigs positive already */
|
|
441
|
-
return 0;
|
|
442
|
-
}
|
|
443
|
-
if (l1 <= 0) { /* both eigs negative, set to 0 */
|
|
444
|
-
X[0] = 0;
|
|
445
|
-
X[1] = 0;
|
|
446
|
-
X[2] = 0;
|
|
447
|
-
return 0;
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
/* l1 pos, l2 neg */
|
|
451
|
-
x1 = 1 / SQRTF(1 + (l1 - a) * (l1 - a) / b / b);
|
|
452
|
-
x2 = x1 * (l1 - a) / b;
|
|
453
|
-
|
|
454
|
-
X[0] = l1 * x1 * x1;
|
|
455
|
-
X[1] = (l1 * x1 * x2) * sqrt2;
|
|
456
|
-
X[2] = l1 * x2 * x2;
|
|
457
444
|
return 0;
|
|
445
|
+
#endif
|
|
458
446
|
}
|
|
459
447
|
|
|
460
448
|
/* size of X is get_sd_cone_size(n) */
|
|
@@ -462,45 +450,35 @@ static scs_int proj_semi_definite_cone(scs_float *X, const scs_int n,
|
|
|
462
450
|
ScsConeWork *c) {
|
|
463
451
|
/* project onto the positive semi-definite cone */
|
|
464
452
|
#ifdef USE_LAPACK
|
|
465
|
-
scs_int i;
|
|
466
|
-
blas_int one = 1;
|
|
467
|
-
blas_int m = 0;
|
|
453
|
+
scs_int i, first_idx;
|
|
468
454
|
blas_int nb = (blas_int)n;
|
|
455
|
+
blas_int ncols_z;
|
|
469
456
|
blas_int nb_plus_one = (blas_int)(n + 1);
|
|
470
|
-
blas_int
|
|
471
|
-
|
|
457
|
+
blas_int one_int = 1;
|
|
458
|
+
scs_float zero = 0., one = 1.;
|
|
472
459
|
scs_float sqrt2 = SQRTF(2.0);
|
|
473
|
-
scs_float
|
|
460
|
+
scs_float sqrt2_inv = 1.0 / sqrt2;
|
|
474
461
|
scs_float *Xs = c->Xs;
|
|
475
462
|
scs_float *Z = c->Z;
|
|
476
463
|
scs_float *e = c->e;
|
|
477
464
|
scs_float *work = c->work;
|
|
478
|
-
blas_int *iwork = c->iwork;
|
|
479
465
|
blas_int lwork = c->lwork;
|
|
480
|
-
blas_int liwork = c->liwork;
|
|
481
|
-
|
|
482
|
-
scs_float eig_tol = CONE_TOL; /* iter < 0 ? CONE_TOL : MAX(CONE_TOL, 1 /
|
|
483
|
-
POWF(iter + 1, CONE_RATE)); */
|
|
484
|
-
scs_float zero = 0.0;
|
|
485
466
|
blas_int info = 0;
|
|
486
|
-
scs_float
|
|
467
|
+
scs_float sq_eig_pos;
|
|
468
|
+
|
|
487
469
|
#endif
|
|
470
|
+
|
|
488
471
|
if (n == 0) {
|
|
489
472
|
return 0;
|
|
490
473
|
}
|
|
491
474
|
if (n == 1) {
|
|
492
|
-
|
|
493
|
-
X[0] = 0.0;
|
|
494
|
-
}
|
|
475
|
+
X[0] = MAX(X[0], 0.);
|
|
495
476
|
return 0;
|
|
496
477
|
}
|
|
497
|
-
|
|
498
|
-
return project_2x2_sdc(X);
|
|
499
|
-
}
|
|
478
|
+
|
|
500
479
|
#ifdef USE_LAPACK
|
|
501
480
|
|
|
502
|
-
|
|
503
|
-
/* expand lower triangular matrix to full matrix */
|
|
481
|
+
/* copy lower triangular matrix into full matrix */
|
|
504
482
|
for (i = 0; i < n; ++i) {
|
|
505
483
|
memcpy(&(Xs[i * (n + 1)]), &(X[i * n - ((i - 1) * i) / 2]),
|
|
506
484
|
(n - i) * sizeof(scs_float));
|
|
@@ -512,64 +490,59 @@ static scs_int proj_semi_definite_cone(scs_float *X, const scs_int n,
|
|
|
512
490
|
/* scale diags by sqrt(2) */
|
|
513
491
|
BLAS(scal)(&nb, &sqrt2, Xs, &nb_plus_one); /* not n_squared */
|
|
514
492
|
|
|
515
|
-
/* max-eig upper bounded by frobenius norm */
|
|
516
|
-
vupper = 1.1 * sqrt2 *
|
|
517
|
-
BLAS(nrm2)(&cone_sz, X,
|
|
518
|
-
&one); /* mult by factor to make sure is upper bound */
|
|
519
|
-
vupper = MAX(vupper, 0.01);
|
|
520
|
-
#if EXTRA_VERBOSE > 0
|
|
521
|
-
SCS(print_array)(Xs, n * n, "Xs");
|
|
522
|
-
SCS(print_array)(X, get_sd_cone_size(n), "X");
|
|
523
|
-
#endif
|
|
524
493
|
/* Solve eigenproblem, reuse workspaces */
|
|
525
|
-
BLAS(
|
|
526
|
-
("Vectors", "VInterval", "Lower", &nb, Xs, &nb, &zero, &vupper, SCS_NULL,
|
|
527
|
-
SCS_NULL, &eig_tol, &m, e, Z, &nb, SCS_NULL, work, &lwork, iwork, &liwork,
|
|
528
|
-
&info);
|
|
529
|
-
#if EXTRA_VERBOSE > 0
|
|
494
|
+
BLAS(syev)("Vectors", "Lower", &nb, Xs, &nb, e, work, &lwork, &info);
|
|
530
495
|
if (info != 0) {
|
|
531
|
-
scs_printf("WARN: LAPACK
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
496
|
+
scs_printf("WARN: LAPACK syev error, info = %i\n", (int)info);
|
|
497
|
+
if (info < 0) {
|
|
498
|
+
return info;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
first_idx = -1;
|
|
503
|
+
/* e is eigvals in ascending order, find first entry > 0 */
|
|
504
|
+
for (i = 0; i < n; ++i) {
|
|
505
|
+
if (e[i] > 0) {
|
|
506
|
+
first_idx = i;
|
|
507
|
+
break;
|
|
508
|
+
}
|
|
544
509
|
}
|
|
545
510
|
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
scs_float
|
|
549
|
-
|
|
511
|
+
if (first_idx == -1) {
|
|
512
|
+
/* there are no positive eigenvalues, set X to 0 and return */
|
|
513
|
+
memset(X, 0, sizeof(scs_float) * get_sd_cone_size(n));
|
|
514
|
+
return 0;
|
|
550
515
|
}
|
|
551
|
-
|
|
552
|
-
|
|
516
|
+
|
|
517
|
+
/* Z is matrix of eigenvectors with positive eigenvalues */
|
|
518
|
+
memcpy(Z, &Xs[first_idx * n], sizeof(scs_float) * n * (n - first_idx));
|
|
519
|
+
|
|
520
|
+
/* scale Z by sqrt(eig) */
|
|
521
|
+
for (i = first_idx; i < n; ++i) {
|
|
522
|
+
sq_eig_pos = SQRTF(e[i]);
|
|
523
|
+
BLAS(scal)(&nb, &sq_eig_pos, &Z[(i - first_idx) * n], &one_int);
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/* Xs = Z Z' = V E V' */
|
|
527
|
+
ncols_z = (blas_int)(n - first_idx);
|
|
528
|
+
BLAS(syrk)("Lower", "NoTrans", &nb, &ncols_z, &one, Z, &nb, &zero, Xs, &nb);
|
|
529
|
+
|
|
530
|
+
/* undo rescaling: scale diags by 1/sqrt(2) */
|
|
531
|
+
BLAS(scal)(&nb, &sqrt2_inv, Xs, &nb_plus_one); /* not n_squared */
|
|
532
|
+
|
|
553
533
|
/* extract just lower triangular matrix */
|
|
554
534
|
for (i = 0; i < n; ++i) {
|
|
555
535
|
memcpy(&(X[i * n - ((i - 1) * i) / 2]), &(Xs[i * (n + 1)]),
|
|
556
536
|
(n - i) * sizeof(scs_float));
|
|
557
537
|
}
|
|
558
|
-
|
|
559
|
-
#if EXTRA_VERBOSE > 0
|
|
560
|
-
SCS(print_array)(Xs, n * n, "Xs");
|
|
561
|
-
SCS(print_array)(X, get_sd_cone_size(n), "X");
|
|
562
|
-
#endif
|
|
538
|
+
return 0;
|
|
563
539
|
|
|
564
540
|
#else
|
|
565
|
-
scs_printf(
|
|
566
|
-
"FAILURE: solving SDP with > 2x2 matrices, but no blas/lapack "
|
|
567
|
-
"libraries were linked!\n");
|
|
541
|
+
scs_printf("FAILURE: solving SDP but no blas/lapack libraries were found!\n");
|
|
568
542
|
scs_printf("SCS will return nonsense!\n");
|
|
569
543
|
SCS(scale_array)(X, NAN, n);
|
|
570
544
|
return -1;
|
|
571
545
|
#endif
|
|
572
|
-
return 0;
|
|
573
546
|
}
|
|
574
547
|
|
|
575
548
|
static scs_float pow_calc_x(scs_float r, scs_float xh, scs_float rh,
|
|
@@ -594,6 +567,129 @@ static scs_float pow_calc_fp(scs_float x, scs_float y, scs_float dxdr,
|
|
|
594
567
|
1;
|
|
595
568
|
}
|
|
596
569
|
|
|
570
|
+
/*
|
|
571
|
+
* Routine to scale the limits of the box cone by the scaling diagonal mat D > 0
|
|
572
|
+
*
|
|
573
|
+
* want (t, s) \in K <==> (t', s') \in K'
|
|
574
|
+
*
|
|
575
|
+
* (t', s') = (d0 * t, D s) (overloading D to mean D[1:])
|
|
576
|
+
* (up to scalar scaling factor which we can ignore due to conic prooperty)
|
|
577
|
+
*
|
|
578
|
+
* K = { (t, s) | t * l <= s <= t * u, t >= 0 } =>
|
|
579
|
+
* { (t, s) | d0 * t * D l / d0 <= D s <= d0 * t D u / d0, t >= 0 } =>
|
|
580
|
+
* { (t', s') | t' * l' <= s' <= t' u', t >= 0 } = K'
|
|
581
|
+
* where l' = D l / d0, u' = D u / d0.
|
|
582
|
+
*/
|
|
583
|
+
static void normalize_box_cone(ScsConeWork *c, scs_float *D, scs_int bsize) {
|
|
584
|
+
scs_int j;
|
|
585
|
+
for (j = 0; j < bsize - 1; j++) {
|
|
586
|
+
if (c->bu[j] >= MAX_BOX_VAL) {
|
|
587
|
+
c->bu[j] = INFINITY;
|
|
588
|
+
} else {
|
|
589
|
+
c->bu[j] = D ? D[j + 1] * c->bu[j] / D[0] : c->bu[j];
|
|
590
|
+
}
|
|
591
|
+
if (c->bl[j] <= -MAX_BOX_VAL) {
|
|
592
|
+
c->bl[j] = -INFINITY;
|
|
593
|
+
} else {
|
|
594
|
+
c->bl[j] = D ? D[j + 1] * c->bl[j] / D[0] : c->bl[j];
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
/* Project onto { (t, s) | t * l <= s <= t * u, t >= 0 }, Newton's method on t
|
|
600
|
+
tx = [t; s], total length = bsize, under Euclidean metric 1/r_box.
|
|
601
|
+
*/
|
|
602
|
+
static scs_float proj_box_cone(scs_float *tx, const scs_float *bl,
|
|
603
|
+
const scs_float *bu, scs_int bsize,
|
|
604
|
+
scs_float t_warm_start, scs_float *r_box) {
|
|
605
|
+
scs_float *x, gt, ht, t_prev, t = t_warm_start;
|
|
606
|
+
scs_float rho_t = 1, *rho = SCS_NULL, r;
|
|
607
|
+
scs_int iter, j;
|
|
608
|
+
|
|
609
|
+
if (bsize == 1) { /* special case */
|
|
610
|
+
tx[0] = MAX(tx[0], 0.0);
|
|
611
|
+
return tx[0];
|
|
612
|
+
}
|
|
613
|
+
x = &(tx[1]);
|
|
614
|
+
|
|
615
|
+
if (r_box) {
|
|
616
|
+
rho_t = 1.0 / r_box[0];
|
|
617
|
+
rho = &(r_box[1]);
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
/* should only require about 5 or so iterations, 1 or 2 if warm-started */
|
|
621
|
+
for (iter = 0; iter < BOX_CONE_MAX_ITERS; iter++) {
|
|
622
|
+
t_prev = t;
|
|
623
|
+
gt = rho_t * (t - tx[0]); /* gradient */
|
|
624
|
+
ht = rho_t; /* hessian */
|
|
625
|
+
for (j = 0; j < bsize - 1; j++) {
|
|
626
|
+
r = rho ? 1.0 / rho[j] : 1.;
|
|
627
|
+
if (x[j] > t * bu[j]) {
|
|
628
|
+
gt += r * (t * bu[j] - x[j]) * bu[j]; /* gradient */
|
|
629
|
+
ht += r * bu[j] * bu[j]; /* hessian */
|
|
630
|
+
} else if (x[j] < t * bl[j]) {
|
|
631
|
+
gt += r * (t * bl[j] - x[j]) * bl[j]; /* gradient */
|
|
632
|
+
ht += r * bl[j] * bl[j]; /* hessian */
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
t = MAX(t - gt / MAX(ht, 1e-8), 0.); /* newton step */
|
|
636
|
+
#if VERBOSITY > 3
|
|
637
|
+
scs_printf("iter %i, t_new %1.3e, t_prev %1.3e, gt %1.3e, ht %1.3e\n", iter,
|
|
638
|
+
t, t_prev, gt, ht);
|
|
639
|
+
scs_printf("ABS(gt / (ht + 1e-6)) %.4e, ABS(t - t_prev) %.4e\n",
|
|
640
|
+
ABS(gt / (ht + 1e-6)), ABS(t - t_prev));
|
|
641
|
+
#endif
|
|
642
|
+
/* TODO: sometimes this check can fail (ie, declare convergence before it
|
|
643
|
+
* should) if ht is very large, which can happen with some pathological
|
|
644
|
+
* problems.
|
|
645
|
+
*/
|
|
646
|
+
if (ABS(gt / MAX(ht, 1e-6)) < 1e-12 * MAX(t, 1.) ||
|
|
647
|
+
ABS(t - t_prev) < 1e-11 * MAX(t, 1.)) {
|
|
648
|
+
break;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
if (iter == BOX_CONE_MAX_ITERS) {
|
|
652
|
+
scs_printf("warning: box cone proj hit maximum %i iters\n", (int)iter);
|
|
653
|
+
}
|
|
654
|
+
for (j = 0; j < bsize - 1; j++) {
|
|
655
|
+
if (x[j] > t * bu[j]) {
|
|
656
|
+
x[j] = t * bu[j];
|
|
657
|
+
} else if (x[j] < t * bl[j]) {
|
|
658
|
+
x[j] = t * bl[j];
|
|
659
|
+
}
|
|
660
|
+
/* x[j] unchanged otherwise */
|
|
661
|
+
}
|
|
662
|
+
tx[0] = t;
|
|
663
|
+
|
|
664
|
+
#if VERBOSITY > 3
|
|
665
|
+
scs_printf("box cone iters %i\n", (int)iter + 1);
|
|
666
|
+
#endif
|
|
667
|
+
return t;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
/* project onto SOC of size q*/
|
|
671
|
+
static void proj_soc(scs_float *x, scs_int q) {
|
|
672
|
+
if (q == 0) {
|
|
673
|
+
return;
|
|
674
|
+
}
|
|
675
|
+
if (q == 1) {
|
|
676
|
+
x[0] = MAX(x[0], 0.);
|
|
677
|
+
return;
|
|
678
|
+
}
|
|
679
|
+
scs_float v1 = x[0];
|
|
680
|
+
scs_float s = SCS(norm_2)(&(x[1]), q - 1);
|
|
681
|
+
scs_float alpha = (s + v1) / 2.0;
|
|
682
|
+
|
|
683
|
+
if (s <= v1) {
|
|
684
|
+
return;
|
|
685
|
+
} else if (s <= -v1) {
|
|
686
|
+
memset(&(x[0]), 0, q * sizeof(scs_float));
|
|
687
|
+
} else {
|
|
688
|
+
x[0] = alpha;
|
|
689
|
+
SCS(scale_array)(&(x[1]), alpha / s, q - 1);
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
|
|
597
693
|
static void proj_power_cone(scs_float *v, scs_float a) {
|
|
598
694
|
scs_float xh = v[0], yh = v[1], rh = ABS(v[2]);
|
|
599
695
|
scs_float x = 0.0, y = 0.0, r;
|
|
@@ -635,100 +731,93 @@ static void proj_power_cone(scs_float *v, scs_float a) {
|
|
|
635
731
|
v[2] = (v[2] < 0) ? -(r) : (r);
|
|
636
732
|
}
|
|
637
733
|
|
|
638
|
-
/*
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
scs_int
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
SCS(tic)(&proj_timer);
|
|
649
|
-
#endif
|
|
650
|
-
SCS(tic)(&cone_timer);
|
|
734
|
+
/* project onto the primal K cone in the paper */
|
|
735
|
+
/* the r_y vector determines the INVERSE metric, ie, project under the
|
|
736
|
+
* diag(r_y)^-1 norm.
|
|
737
|
+
*/
|
|
738
|
+
static scs_int proj_cone(scs_float *x, const ScsCone *k, ScsConeWork *c,
|
|
739
|
+
scs_int normalize, scs_float *r_y) {
|
|
740
|
+
scs_int i, status;
|
|
741
|
+
scs_int count = 0;
|
|
742
|
+
scs_float *r_box = SCS_NULL;
|
|
743
|
+
scs_float *bu, *bl;
|
|
651
744
|
|
|
652
|
-
if (k->
|
|
745
|
+
if (k->z) { /* doesn't use r_y */
|
|
746
|
+
/* project onto primal zero / dual free cone */
|
|
747
|
+
memset(x, 0, k->z * sizeof(scs_float));
|
|
748
|
+
count += k->z;
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
if (k->l) { /* doesn't use r_y */
|
|
653
752
|
/* project onto positive orthant */
|
|
654
753
|
for (i = count; i < count + k->l; ++i) {
|
|
655
|
-
|
|
656
|
-
x[i] = 0.0;
|
|
657
|
-
}
|
|
658
|
-
/* x[i] = (x[i] < 0.0) ? 0.0 : x[i]; */
|
|
754
|
+
x[i] = MAX(x[i], 0.0);
|
|
659
755
|
}
|
|
660
756
|
count += k->l;
|
|
661
|
-
#if EXTRA_VERBOSE > 0
|
|
662
|
-
scs_printf("pos orthant proj time: %1.2es\n", SCS(tocq)(&proj_timer) / 1e3);
|
|
663
|
-
SCS(tic)(&proj_timer);
|
|
664
|
-
#endif
|
|
665
757
|
}
|
|
666
758
|
|
|
667
|
-
if (k->
|
|
668
|
-
|
|
759
|
+
if (k->bsize) { /* DOES use r_y */
|
|
760
|
+
if (r_y) {
|
|
761
|
+
r_box = &(r_y[count]);
|
|
762
|
+
}
|
|
763
|
+
/* project onto box cone */
|
|
764
|
+
bu = normalize ? c->bu : k->bu;
|
|
765
|
+
bl = normalize ? c->bl : k->bl;
|
|
766
|
+
c->box_t_warm_start = proj_box_cone(&(x[count]), bl, bu, k->bsize,
|
|
767
|
+
c->box_t_warm_start, r_box);
|
|
768
|
+
count += k->bsize; /* since b = (t,s), len(s) = bsize - 1 */
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
if (k->qsize && k->q) { /* doesn't use r_y */
|
|
772
|
+
/* project onto second-order cones */
|
|
669
773
|
for (i = 0; i < k->qsize; ++i) {
|
|
670
|
-
|
|
671
|
-
continue;
|
|
672
|
-
}
|
|
673
|
-
if (k->q[i] == 1) {
|
|
674
|
-
if (x[count] < 0.0) {
|
|
675
|
-
x[count] = 0.0;
|
|
676
|
-
}
|
|
677
|
-
} else {
|
|
678
|
-
scs_float v1 = x[count];
|
|
679
|
-
scs_float s = SCS(norm)(&(x[count + 1]), k->q[i] - 1);
|
|
680
|
-
scs_float alpha = (s + v1) / 2.0;
|
|
681
|
-
|
|
682
|
-
if (s <= v1) { /* do nothing */
|
|
683
|
-
} else if (s <= -v1) {
|
|
684
|
-
memset(&(x[count]), 0, k->q[i] * sizeof(scs_float));
|
|
685
|
-
} else {
|
|
686
|
-
x[count] = alpha;
|
|
687
|
-
SCS(scale_array)(&(x[count + 1]), alpha / s, k->q[i] - 1);
|
|
688
|
-
}
|
|
689
|
-
}
|
|
774
|
+
proj_soc(&(x[count]), k->q[i]);
|
|
690
775
|
count += k->q[i];
|
|
691
776
|
}
|
|
692
|
-
#if EXTRA_VERBOSE > 0
|
|
693
|
-
scs_printf("SOC proj time: %1.2es\n", SCS(tocq)(&proj_timer) / 1e3);
|
|
694
|
-
SCS(tic)(&proj_timer);
|
|
695
|
-
#endif
|
|
696
777
|
}
|
|
697
778
|
|
|
698
|
-
if (k->ssize && k->s) {
|
|
699
|
-
/* project onto PSD
|
|
779
|
+
if (k->ssize && k->s) { /* doesn't use r_y */
|
|
780
|
+
/* project onto PSD cones */
|
|
700
781
|
for (i = 0; i < k->ssize; ++i) {
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
if (k->s[i] == 0) {
|
|
705
|
-
continue;
|
|
706
|
-
}
|
|
707
|
-
if (proj_semi_definite_cone(&(x[count]), k->s[i], c) < 0) {
|
|
708
|
-
return -1;
|
|
782
|
+
status = proj_semi_definite_cone(&(x[count]), k->s[i], c);
|
|
783
|
+
if (status < 0) {
|
|
784
|
+
return status;
|
|
709
785
|
}
|
|
710
786
|
count += get_sd_cone_size(k->s[i]);
|
|
711
787
|
}
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
if (k->ep) { /* doesn't use r_y */
|
|
791
|
+
/*
|
|
792
|
+
* exponential cone is not self dual, if s \in K
|
|
793
|
+
* then y \in K^* and so if K is the primal cone
|
|
794
|
+
* here we project onto K^*, via Moreau
|
|
795
|
+
* \Pi_C^*(y) = y + \Pi_C(-y)
|
|
796
|
+
*/
|
|
797
|
+
#ifdef _OPENMP
|
|
798
|
+
#pragma omp parallel for
|
|
715
799
|
#endif
|
|
800
|
+
for (i = 0; i < k->ep; ++i) {
|
|
801
|
+
proj_exp_cone(&(x[count + 3 * i]));
|
|
802
|
+
}
|
|
803
|
+
count += 3 * k->ep;
|
|
716
804
|
}
|
|
717
805
|
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
scs_int idx;
|
|
806
|
+
/* dual exponential cone */
|
|
807
|
+
if (k->ed) { /* doesn't use r_y */
|
|
721
808
|
/*
|
|
722
809
|
* exponential cone is not self dual, if s \in K
|
|
723
810
|
* then y \in K^* and so if K is the primal cone
|
|
724
811
|
* here we project onto K^*, via Moreau
|
|
725
812
|
* \Pi_C^*(y) = y + \Pi_C(-y)
|
|
726
813
|
*/
|
|
727
|
-
|
|
814
|
+
scs_int idx;
|
|
815
|
+
scs_float r, s, t;
|
|
816
|
+
SCS(scale_array)(&(x[count]), -1, 3 * k->ed); /* x = -x; */
|
|
728
817
|
#ifdef _OPENMP
|
|
729
818
|
#pragma omp parallel for private(r, s, t, idx)
|
|
730
819
|
#endif
|
|
731
|
-
for (i = 0; i < k->
|
|
820
|
+
for (i = 0; i < k->ed; ++i) {
|
|
732
821
|
idx = count + 3 * i;
|
|
733
822
|
r = x[idx];
|
|
734
823
|
s = x[idx + 1];
|
|
@@ -740,29 +829,10 @@ scs_int SCS(proj_dual_cone)(scs_float *x, const ScsCone *k, ScsConeWork *c,
|
|
|
740
829
|
x[idx + 1] -= s;
|
|
741
830
|
x[idx + 2] -= t;
|
|
742
831
|
}
|
|
743
|
-
count += 3 * k->ep;
|
|
744
|
-
#if EXTRA_VERBOSE > 0
|
|
745
|
-
scs_printf("EP proj time: %1.2es\n", SCS(tocq)(&proj_timer) / 1e3);
|
|
746
|
-
SCS(tic)(&proj_timer);
|
|
747
|
-
#endif
|
|
748
|
-
}
|
|
749
|
-
|
|
750
|
-
if (k->ed) {
|
|
751
|
-
/* exponential cone: */
|
|
752
|
-
#ifdef _OPENMP
|
|
753
|
-
#pragma omp parallel for
|
|
754
|
-
#endif
|
|
755
|
-
for (i = 0; i < k->ed; ++i) {
|
|
756
|
-
proj_exp_cone(&(x[count + 3 * i]));
|
|
757
|
-
}
|
|
758
832
|
count += 3 * k->ed;
|
|
759
|
-
#if EXTRA_VERBOSE > 0
|
|
760
|
-
scs_printf("ED proj time: %1.2es\n", SCS(tocq)(&proj_timer) / 1e3);
|
|
761
|
-
SCS(tic)(&proj_timer);
|
|
762
|
-
#endif
|
|
763
833
|
}
|
|
764
834
|
|
|
765
|
-
if (k->psize && k->p) {
|
|
835
|
+
if (k->psize && k->p) { /* doesn't use r_y */
|
|
766
836
|
scs_float v[3];
|
|
767
837
|
scs_int idx;
|
|
768
838
|
/* don't use openmp for power cone
|
|
@@ -770,18 +840,18 @@ scs_int SCS(proj_dual_cone)(scs_float *x, const ScsCone *k, ScsConeWork *c,
|
|
|
770
840
|
pragma omp parallel for private(v, idx)
|
|
771
841
|
endif
|
|
772
842
|
*/
|
|
773
|
-
for (i = 0; i < k->psize; ++i) {
|
|
843
|
+
for (i = 0; i < k->psize; ++i) { /* doesn't use r_y */
|
|
774
844
|
idx = count + 3 * i;
|
|
775
|
-
if (k->p[i]
|
|
776
|
-
/*
|
|
777
|
-
proj_power_cone(&(x[idx]),
|
|
845
|
+
if (k->p[i] >= 0) {
|
|
846
|
+
/* primal power cone */
|
|
847
|
+
proj_power_cone(&(x[idx]), k->p[i]);
|
|
778
848
|
} else {
|
|
779
|
-
/*
|
|
849
|
+
/* dual power cone, using Moreau */
|
|
780
850
|
v[0] = -x[idx];
|
|
781
851
|
v[1] = -x[idx + 1];
|
|
782
852
|
v[2] = -x[idx + 2];
|
|
783
853
|
|
|
784
|
-
proj_power_cone(v, k->p[i]);
|
|
854
|
+
proj_power_cone(v, -k->p[i]);
|
|
785
855
|
|
|
786
856
|
x[idx] += v[0];
|
|
787
857
|
x[idx + 1] += v[1];
|
|
@@ -789,14 +859,82 @@ scs_int SCS(proj_dual_cone)(scs_float *x, const ScsCone *k, ScsConeWork *c,
|
|
|
789
859
|
}
|
|
790
860
|
}
|
|
791
861
|
count += 3 * k->psize;
|
|
792
|
-
#if EXTRA_VERBOSE > 0
|
|
793
|
-
scs_printf("Power cone proj time: %1.2es\n", SCS(tocq)(&proj_timer) / 1e3);
|
|
794
|
-
SCS(tic)(&proj_timer);
|
|
795
|
-
#endif
|
|
796
862
|
}
|
|
797
863
|
/* project onto OTHER cones */
|
|
798
|
-
if (c) {
|
|
799
|
-
c->total_cone_time += SCS(tocq)(&cone_timer);
|
|
800
|
-
}
|
|
801
864
|
return 0;
|
|
802
865
|
}
|
|
866
|
+
|
|
867
|
+
ScsConeWork *SCS(init_cone)(const ScsCone *k, scs_int m) {
|
|
868
|
+
ScsConeWork *c = (ScsConeWork *)scs_calloc(1, sizeof(ScsConeWork));
|
|
869
|
+
c->k = k;
|
|
870
|
+
c->m = m;
|
|
871
|
+
c->scaled_cones = 0;
|
|
872
|
+
set_cone_boundaries(k, c);
|
|
873
|
+
c->s = (scs_float *)scs_calloc(m, sizeof(scs_float));
|
|
874
|
+
if (k->ssize && k->s) {
|
|
875
|
+
if (set_up_sd_cone_work_space(c, k) < 0) {
|
|
876
|
+
SCS(finish_cone)(c);
|
|
877
|
+
return SCS_NULL;
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
return c;
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
void scale_box_cone(const ScsCone *k, ScsConeWork *c, ScsScaling *scal) {
|
|
884
|
+
if (k->bsize && k->bu && k->bl) {
|
|
885
|
+
c->box_t_warm_start = 1.;
|
|
886
|
+
if (scal) {
|
|
887
|
+
c->bu = (scs_float *)scs_calloc(k->bsize - 1, sizeof(scs_float));
|
|
888
|
+
c->bl = (scs_float *)scs_calloc(k->bsize - 1, sizeof(scs_float));
|
|
889
|
+
memcpy(c->bu, k->bu, (k->bsize - 1) * sizeof(scs_float));
|
|
890
|
+
memcpy(c->bl, k->bl, (k->bsize - 1) * sizeof(scs_float));
|
|
891
|
+
/* also does some sanitizing */
|
|
892
|
+
normalize_box_cone(c, &(scal->D[k->z + k->l]), k->bsize);
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
/* Outward facing cone projection routine, performs projection in-place.
|
|
898
|
+
If normalize > 0 then will use normalized (equilibrated) cones if applicable.
|
|
899
|
+
|
|
900
|
+
Moreau decomposition for R-norm projections:
|
|
901
|
+
|
|
902
|
+
`x + R^{-1} \Pi_{C^*}^{R^{-1}} ( - R x ) = \Pi_C^R ( x )`
|
|
903
|
+
|
|
904
|
+
where \Pi^R_C is the projection onto C under the R-norm:
|
|
905
|
+
|
|
906
|
+
`||x||_R = \sqrt{x ' R x}`.
|
|
907
|
+
|
|
908
|
+
*/
|
|
909
|
+
scs_int SCS(proj_dual_cone)(scs_float *x, ScsConeWork *c, ScsScaling *scal,
|
|
910
|
+
scs_float *r_y) {
|
|
911
|
+
scs_int status, i;
|
|
912
|
+
const ScsCone *k = c->k;
|
|
913
|
+
|
|
914
|
+
if (!c->scaled_cones) {
|
|
915
|
+
scale_box_cone(k, c, scal);
|
|
916
|
+
c->scaled_cones = 1;
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
/* copy s = x */
|
|
920
|
+
memcpy(c->s, x, c->m * sizeof(scs_float));
|
|
921
|
+
|
|
922
|
+
/* x -> - Rx */
|
|
923
|
+
for (i = 0; i < c->m; ++i) {
|
|
924
|
+
x[i] *= r_y ? -r_y[i] : -1;
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
/* project -x onto cone, x -> \Pi_{C^*}^{R^{-1}}(-x) under r_y metric */
|
|
928
|
+
status = proj_cone(x, k, c, scal ? 1 : 0, r_y);
|
|
929
|
+
|
|
930
|
+
/* return x + R^{-1} \Pi_{C^*}^{R^{-1}} ( -x ) */
|
|
931
|
+
for (i = 0; i < c->m; ++i) {
|
|
932
|
+
if (r_y) {
|
|
933
|
+
x[i] = x[i] / r_y[i] + c->s[i];
|
|
934
|
+
} else {
|
|
935
|
+
x[i] += c->s[i];
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
return status;
|
|
940
|
+
}
|