1 #include "cs.h"
2 
3 
csc_malloc(c_int n,c_int size)4 static void* csc_malloc(c_int n, c_int size) {
5   return c_malloc(n * size);
6 }
7 
csc_calloc(c_int n,c_int size)8 static void* csc_calloc(c_int n, c_int size) {
9   return c_calloc(n, size);
10 }
11 
csc_matrix(c_int m,c_int n,c_int nzmax,c_float * x,c_int * i,c_int * p)12 csc* 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 
csc_spalloc(c_int m,c_int n,c_int nzmax,c_int values,c_int triplet)28 csc* 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 
csc_spfree(csc * A)46 void 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 
triplet_to_csc(const csc * T,c_int * TtoC)55 csc* 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 
triplet_to_csr(const csc * T,c_int * TtoC)90 csc* 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 
csc_cumsum(c_int * p,c_int * c,c_int n)125 c_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 
csc_pinv(c_int const * p,c_int n)140 c_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 
csc_symperm(const csc * A,const c_int * pinv,c_int * AtoC,c_int values)153 csc* 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 
copy_csc_mat(const csc * A)208 csc* 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 
prea_copy_csc_mat(const csc * A,csc * B)220 void 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 
csc_done(csc * C,void * w,void * x,c_int ok)228 csc* 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 
csc_to_triu(csc * M)238 csc* 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 }
319