Austin Schuh | 9049e20 | 2022-02-20 17:34:16 -0800 | [diff] [blame] | 1 | #include "kkt.h" |
| 2 | |
| 3 | #ifndef EMBEDDED |
| 4 | |
| 5 | |
| 6 | csc* 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 | |
| 184 | void 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 | |
| 205 | void 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 | |
| 214 | void 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 |