blob: f89aea0bf50c9a604b6e53fd37fd50d2f5a74915 [file] [log] [blame]
Austin Schuh9049e202022-02-20 17:34:16 -08001#include "kkt.h"
2
3#ifndef EMBEDDED
4
5
6csc* form_KKT(const csc *P,
7 const csc *A,
8 c_int format,
9 c_float param1,
10 c_float *param2,
11 c_int *PtoKKT,
12 c_int *AtoKKT,
13 c_int **Pdiag_idx,
14 c_int *Pdiag_n,
15 c_int *param2toKKT) {
16 c_int nKKT, nnzKKTmax; // Size, number of nonzeros and max number of nonzeros
17 // in KKT matrix
18 csc *KKT_trip, *KKT; // KKT matrix in triplet format and CSC format
19 c_int ptr, i, j; // Counters for elements (i,j) and index pointer
20 c_int zKKT = 0; // Counter for total number of elements in P and in
21 // KKT
22 c_int *KKT_TtoC; // Pointer to vector mapping from KKT in triplet form
23 // to CSC
24
25 // Get matrix dimensions
26 nKKT = P->m + A->m;
27
28 // Get maximum number of nonzero elements (only upper triangular part)
29 nnzKKTmax = P->p[P->n] + // Number of elements in P
30 P->m + // Number of elements in param1 * I
31 A->p[A->n] + // Number of nonzeros in A
32 A->m; // Number of elements in - diag(param2)
33
34 // Preallocate KKT matrix in triplet format
35 KKT_trip = csc_spalloc(nKKT, nKKT, nnzKKTmax, 1, 1);
36
37 if (!KKT_trip) return OSQP_NULL; // Failed to preallocate matrix
38
39 // Allocate vector of indices on the diagonal. Worst case it has m elements
40 if (Pdiag_idx != OSQP_NULL) {
41 (*Pdiag_idx) = c_malloc(P->m * sizeof(c_int));
42 *Pdiag_n = 0; // Set 0 diagonal elements to start
43 }
44
45 // Allocate Triplet matrices
46 // P + param1 I
47 for (j = 0; j < P->n; j++) { // cycle over columns
48 // No elements in column j => add diagonal element param1
49 if (P->p[j] == P->p[j + 1]) {
50 KKT_trip->i[zKKT] = j;
51 KKT_trip->p[zKKT] = j;
52 KKT_trip->x[zKKT] = param1;
53 zKKT++;
54 }
55
56 for (ptr = P->p[j]; ptr < P->p[j + 1]; ptr++) { // cycle over rows
57 // Get current row
58 i = P->i[ptr];
59
60 // Add element of P
61 KKT_trip->i[zKKT] = i;
62 KKT_trip->p[zKKT] = j;
63 KKT_trip->x[zKKT] = P->x[ptr];
64
65 if (PtoKKT != OSQP_NULL) PtoKKT[ptr] = zKKT; // Update index from P to
66 // KKTtrip
67
68 if (i == j) { // P has a diagonal element,
69 // add param1
70 KKT_trip->x[zKKT] += param1;
71
72 // If index vector pointer supplied -> Store the index
73 if (Pdiag_idx != OSQP_NULL) {
74 (*Pdiag_idx)[*Pdiag_n] = ptr;
75 (*Pdiag_n)++;
76 }
77 }
78 zKKT++;
79
80 // Add diagonal param1 in case
81 if ((i < j) && // Diagonal element not reached
82 (ptr + 1 == P->p[j + 1])) { // last element of column j
83 // Add diagonal element param1
84 KKT_trip->i[zKKT] = j;
85 KKT_trip->p[zKKT] = j;
86 KKT_trip->x[zKKT] = param1;
87 zKKT++;
88 }
89 }
90 }
91
92 if (Pdiag_idx != OSQP_NULL) {
93 // Realloc Pdiag_idx so that it contains exactly *Pdiag_n diagonal elements
94 (*Pdiag_idx) = c_realloc((*Pdiag_idx), (*Pdiag_n) * sizeof(c_int));
95 }
96
97
98 // A' at top right
99 for (j = 0; j < A->n; j++) { // Cycle over columns of A
100 for (ptr = A->p[j]; ptr < A->p[j + 1]; ptr++) {
101 KKT_trip->p[zKKT] = P->m + A->i[ptr]; // Assign column index from
102 // row index of A
103 KKT_trip->i[zKKT] = j; // Assign row index from
104 // column index of A
105 KKT_trip->x[zKKT] = A->x[ptr]; // Assign A value element
106
107 if (AtoKKT != OSQP_NULL) AtoKKT[ptr] = zKKT; // Update index from A to
108 // KKTtrip
109 zKKT++;
110 }
111 }
112
113 // - diag(param2) at bottom right
114 for (j = 0; j < A->m; j++) {
115 KKT_trip->i[zKKT] = j + P->n;
116 KKT_trip->p[zKKT] = j + P->n;
117 KKT_trip->x[zKKT] = -param2[j];
118
119 if (param2toKKT != OSQP_NULL) param2toKKT[j] = zKKT; // Update index from
120 // param2 to KKTtrip
121 zKKT++;
122 }
123
124 // Allocate number of nonzeros
125 KKT_trip->nz = zKKT;
126
127 // Convert triplet matrix to csc format
128 if (!PtoKKT && !AtoKKT && !param2toKKT) {
129 // If no index vectors passed, do not store KKT mapping from Trip to CSC/CSR
130 if (format == 0) KKT = triplet_to_csc(KKT_trip, OSQP_NULL);
131 else KKT = triplet_to_csr(KKT_trip, OSQP_NULL);
132 }
133 else {
134 // Allocate vector of indices from triplet to csc
135 KKT_TtoC = c_malloc((zKKT) * sizeof(c_int));
136
137 if (!KKT_TtoC) {
138 // Error in allocating KKT_TtoC vector
139 csc_spfree(KKT_trip);
140 c_free(*Pdiag_idx);
141 return OSQP_NULL;
142 }
143
144 // Store KKT mapping from Trip to CSC/CSR
145 if (format == 0)
146 KKT = triplet_to_csc(KKT_trip, KKT_TtoC);
147 else
148 KKT = triplet_to_csr(KKT_trip, KKT_TtoC);
149
150 // Update vectors of indices from P, A, param2 to KKT (now in CSC format)
151 if (PtoKKT != OSQP_NULL) {
152 for (i = 0; i < P->p[P->n]; i++) {
153 PtoKKT[i] = KKT_TtoC[PtoKKT[i]];
154 }
155 }
156
157 if (AtoKKT != OSQP_NULL) {
158 for (i = 0; i < A->p[A->n]; i++) {
159 AtoKKT[i] = KKT_TtoC[AtoKKT[i]];
160 }
161 }
162
163 if (param2toKKT != OSQP_NULL) {
164 for (i = 0; i < A->m; i++) {
165 param2toKKT[i] = KKT_TtoC[param2toKKT[i]];
166 }
167 }
168
169 // Free mapping
170 c_free(KKT_TtoC);
171 }
172
173 // Clean matrix in triplet format and return result
174 csc_spfree(KKT_trip);
175
176 return KKT;
177}
178
179#endif /* ifndef EMBEDDED */
180
181
182#if EMBEDDED != 1
183
184void update_KKT_P(csc *KKT,
185 const csc *P,
186 const c_int *PtoKKT,
187 const c_float param1,
188 const c_int *Pdiag_idx,
189 const c_int Pdiag_n) {
190 c_int i, j; // Iterations
191
192 // Update elements of KKT using P
193 for (i = 0; i < P->p[P->n]; i++) {
194 KKT->x[PtoKKT[i]] = P->x[i];
195 }
196
197 // Update diagonal elements of KKT by adding sigma
198 for (i = 0; i < Pdiag_n; i++) {
199 j = Pdiag_idx[i]; // Extract index of the element on the
200 // diagonal
201 KKT->x[PtoKKT[j]] += param1;
202 }
203}
204
205void update_KKT_A(csc *KKT, const csc *A, const c_int *AtoKKT) {
206 c_int i; // Iterations
207
208 // Update elements of KKT using A
209 for (i = 0; i < A->p[A->n]; i++) {
210 KKT->x[AtoKKT[i]] = A->x[i];
211 }
212}
213
214void update_KKT_param2(csc *KKT, const c_float *param2,
215 const c_int *param2toKKT, const c_int m) {
216 c_int i; // Iterations
217
218 // Update elements of KKT using param2
219 for (i = 0; i < m; i++) {
220 KKT->x[param2toKKT[i]] = -param2[i];
221 }
222}
223
224#endif // EMBEDDED != 1