blob: a678ceb42b70e3b89324803fc9335de361583e2c [file] [log] [blame]
Austin Schuh9049e202022-02-20 17:34:16 -08001#include "cs.h"
2
3
4static void* csc_malloc(c_int n, c_int size) {
5 return c_malloc(n * size);
6}
7
8static void* csc_calloc(c_int n, c_int size) {
9 return c_calloc(n, size);
10}
11
12csc* csc_matrix(c_int m, c_int n, c_int nzmax, c_float *x, c_int *i, c_int *p)
13{
14 csc *M = (csc *)c_malloc(sizeof(csc));
15
16 if (!M) return OSQP_NULL;
17
18 M->m = m;
19 M->n = n;
20 M->nz = -1;
21 M->nzmax = nzmax;
22 M->x = x;
23 M->i = i;
24 M->p = p;
25 return M;
26}
27
28csc* csc_spalloc(c_int m, c_int n, c_int nzmax, c_int values, c_int triplet) {
29 csc *A = csc_calloc(1, sizeof(csc)); /* allocate the csc struct */
30
31 if (!A) return OSQP_NULL; /* out of memory */
32
33 A->m = m; /* define dimensions and nzmax */
34 A->n = n;
35 A->nzmax = nzmax = c_max(nzmax, 1);
36 A->nz = triplet ? 0 : -1; /* allocate triplet or comp.col */
37 A->p = csc_malloc(triplet ? nzmax : n + 1, sizeof(c_int));
38 A->i = csc_malloc(nzmax, sizeof(c_int));
39 A->x = values ? csc_malloc(nzmax, sizeof(c_float)) : OSQP_NULL;
40 if (!A->p || !A->i || (values && !A->x)){
41 csc_spfree(A);
42 return OSQP_NULL;
43 } else return A;
44}
45
46void csc_spfree(csc *A) {
47 if (A){
48 if (A->p) c_free(A->p);
49 if (A->i) c_free(A->i);
50 if (A->x) c_free(A->x);
51 c_free(A);
52 }
53}
54
55csc* triplet_to_csc(const csc *T, c_int *TtoC) {
56 c_int m, n, nz, p, k, *Cp, *Ci, *w, *Ti, *Tj;
57 c_float *Cx, *Tx;
58 csc *C;
59
60 m = T->m;
61 n = T->n;
62 Ti = T->i;
63 Tj = T->p;
64 Tx = T->x;
65 nz = T->nz;
66 C = csc_spalloc(m, n, nz, Tx != OSQP_NULL, 0); /* allocate result */
67 w = csc_calloc(n, sizeof(c_int)); /* get workspace */
68
69 if (!C || !w) return csc_done(C, w, OSQP_NULL, 0); /* out of memory */
70
71 Cp = C->p;
72 Ci = C->i;
73 Cx = C->x;
74
75 for (k = 0; k < nz; k++) w[Tj[k]]++; /* column counts */
76 csc_cumsum(Cp, w, n); /* column pointers */
77
78 for (k = 0; k < nz; k++) {
79 Ci[p = w[Tj[k]]++] = Ti[k]; /* A(i,j) is the pth entry in C */
80
81 if (Cx) {
82 Cx[p] = Tx[k];
83
84 if (TtoC != OSQP_NULL) TtoC[k] = p; // Assign vector of indices
85 }
86 }
87 return csc_done(C, w, OSQP_NULL, 1); /* success; free w and return C */
88}
89
90csc* triplet_to_csr(const csc *T, c_int *TtoC) {
91 c_int m, n, nz, p, k, *Cp, *Cj, *w, *Ti, *Tj;
92 c_float *Cx, *Tx;
93 csc *C;
94
95 m = T->m;
96 n = T->n;
97 Ti = T->i;
98 Tj = T->p;
99 Tx = T->x;
100 nz = T->nz;
101 C = csc_spalloc(m, n, nz, Tx != OSQP_NULL, 0); /* allocate result */
102 w = csc_calloc(m, sizeof(c_int)); /* get workspace */
103
104 if (!C || !w) return csc_done(C, w, OSQP_NULL, 0); /* out of memory */
105
106 Cp = C->p;
107 Cj = C->i;
108 Cx = C->x;
109
110 for (k = 0; k < nz; k++) w[Ti[k]]++; /* row counts */
111 csc_cumsum(Cp, w, m); /* row pointers */
112
113 for (k = 0; k < nz; k++) {
114 Cj[p = w[Ti[k]]++] = Tj[k]; /* A(i,j) is the pth entry in C */
115
116 if (Cx) {
117 Cx[p] = Tx[k];
118
119 if (TtoC != OSQP_NULL) TtoC[k] = p; // Assign vector of indices
120 }
121 }
122 return csc_done(C, w, OSQP_NULL, 1); /* success; free w and return C */
123}
124
125c_int csc_cumsum(c_int *p, c_int *c, c_int n) {
126 c_int i, nz = 0;
127
128 if (!p || !c) return -1; /* check inputs */
129
130 for (i = 0; i < n; i++)
131 {
132 p[i] = nz;
133 nz += c[i];
134 c[i] = p[i];
135 }
136 p[n] = nz;
137 return nz; /* return sum (c [0..n-1]) */
138}
139
140c_int* csc_pinv(c_int const *p, c_int n) {
141 c_int k, *pinv;
142
143 if (!p) return OSQP_NULL; /* p = OSQP_NULL denotes identity */
144
145 pinv = csc_malloc(n, sizeof(c_int)); /* allocate result */
146
147 if (!pinv) return OSQP_NULL; /* out of memory */
148
149 for (k = 0; k < n; k++) pinv[p[k]] = k; /* invert the permutation */
150 return pinv; /* return result */
151}
152
153csc* csc_symperm(const csc *A, const c_int *pinv, c_int *AtoC, c_int values) {
154 c_int i, j, p, q, i2, j2, n, *Ap, *Ai, *Cp, *Ci, *w;
155 c_float *Cx, *Ax;
156 csc *C;
157
158 n = A->n;
159 Ap = A->p;
160 Ai = A->i;
161 Ax = A->x;
162 C = csc_spalloc(n, n, Ap[n], values && (Ax != OSQP_NULL),
163 0); /* alloc result*/
164 w = csc_calloc(n, sizeof(c_int)); /* get workspace */
165
166 if (!C || !w) return csc_done(C, w, OSQP_NULL, 0); /* out of memory */
167
168 Cp = C->p;
169 Ci = C->i;
170 Cx = C->x;
171
172 for (j = 0; j < n; j++) /* count entries in each column of C */
173 {
174 j2 = pinv ? pinv[j] : j; /* column j of A is column j2 of C */
175
176 for (p = Ap[j]; p < Ap[j + 1]; p++) {
177 i = Ai[p];
178
179 if (i > j) continue; /* skip lower triangular part of A */
180 i2 = pinv ? pinv[i] : i; /* row i of A is row i2 of C */
181 w[c_max(i2, j2)]++; /* column count of C */
182 }
183 }
184 csc_cumsum(Cp, w, n); /* compute column pointers of C */
185
186 for (j = 0; j < n; j++) {
187 j2 = pinv ? pinv[j] : j; /* column j of A is column j2 of C */
188
189 for (p = Ap[j]; p < Ap[j + 1]; p++) {
190 i = Ai[p];
191
192 if (i > j) continue; /* skip lower triangular
193 part of A*/
194 i2 = pinv ? pinv[i] : i; /* row i of A is row i2
195 of C */
196 Ci[q = w[c_max(i2, j2)]++] = c_min(i2, j2);
197
198 if (Cx) Cx[q] = Ax[p];
199
200 if (AtoC) { // If vector AtoC passed, store values of the mappings
201 AtoC[p] = q;
202 }
203 }
204 }
205 return csc_done(C, w, OSQP_NULL, 1); /* success; free workspace, return C */
206}
207
208csc* copy_csc_mat(const csc *A) {
209 csc *B = csc_spalloc(A->m, A->n, A->p[A->n], 1, 0);
210
211 if (!B) return OSQP_NULL;
212
213 prea_int_vec_copy(A->p, B->p, A->n + 1);
214 prea_int_vec_copy(A->i, B->i, A->p[A->n]);
215 prea_vec_copy(A->x, B->x, A->p[A->n]);
216
217 return B;
218}
219
220void prea_copy_csc_mat(const csc *A, csc *B) {
221 prea_int_vec_copy(A->p, B->p, A->n + 1);
222 prea_int_vec_copy(A->i, B->i, A->p[A->n]);
223 prea_vec_copy(A->x, B->x, A->p[A->n]);
224
225 B->nzmax = A->nzmax;
226}
227
228csc* csc_done(csc *C, void *w, void *x, c_int ok) {
229 c_free(w); /* free workspace */
230 c_free(x);
231 if (ok) return C;
232 else {
233 csc_spfree(C);
234 return OSQP_NULL;
235 }
236}
237
238csc* csc_to_triu(csc *M) {
239 csc *M_trip; // Matrix in triplet format
240 csc *M_triu; // Resulting upper triangular matrix
241 c_int nnzorigM; // Number of nonzeros from original matrix M
242 c_int nnzmaxM; // Estimated maximum number of elements of upper triangular M
243 c_int n; // Dimension of M
244 c_int ptr, i, j; // Counters for (i,j) and index in M
245 c_int z_M = 0; // Counter for elements in M_trip
246
247
248 // Check if matrix is square
249 if (M->m != M->n) {
250#ifdef PRINTING
251 c_eprint("Matrix M not square");
252#endif /* ifdef PRINTING */
253 return OSQP_NULL;
254 }
255 n = M->n;
256
257 // Get number of nonzeros full M
258 nnzorigM = M->p[n];
259
260 // Estimate nnzmaxM
261 // Number of nonzero elements in original M + diagonal part.
262 // -> Full matrix M as input: estimate is half the number of total elements +
263 // diagonal = .5 * (nnzorigM + n)
264 // -> Upper triangular matrix M as input: estimate is the number of total
265 // elements + diagonal = nnzorigM + n
266 // The maximum between the two is nnzorigM + n
267 nnzmaxM = nnzorigM + n;
268
269 // OLD
270 // nnzmaxM = n*(n+1)/2; // Full upper triangular matrix (This version
271 // allocates too much memory!)
272 // nnzmaxM = .5 * (nnzorigM + n); // half of the total elements + diagonal
273
274 // Allocate M_trip
275 M_trip = csc_spalloc(n, n, nnzmaxM, 1, 1); // Triplet format
276
277 if (!M_trip) {
278#ifdef PRINTING
279 c_eprint("Upper triangular matrix extraction failed (out of memory)");
280#endif /* ifdef PRINTING */
281 return OSQP_NULL;
282 }
283
284 // Fill M_trip with only elements in M which are in the upper triangular
285 for (j = 0; j < n; j++) { // Cycle over columns
286 for (ptr = M->p[j]; ptr < M->p[j + 1]; ptr++) {
287 // Get row index
288 i = M->i[ptr];
289
290 // Assign element only if in the upper triangular
291 if (i <= j) {
292 // c_print("\nM(%i, %i) = %.4f", M->i[ptr], j, M->x[ptr]);
293
294 M_trip->i[z_M] = i;
295 M_trip->p[z_M] = j;
296 M_trip->x[z_M] = M->x[ptr];
297
298 // Increase counter for the number of elements
299 z_M++;
300 }
301 }
302 }
303
304 // Set number of nonzeros
305 M_trip->nz = z_M;
306
307 // Convert triplet matrix to csc format
308 M_triu = triplet_to_csc(M_trip, OSQP_NULL);
309
310 // Assign number of nonzeros of full matrix to triu M
311 M_triu->nzmax = nnzmaxM;
312
313 // Cleanup and return result
314 csc_spfree(M_trip);
315
316 // Return matrix in triplet form
317 return M_triu;
318}