blob: f89aea0bf50c9a604b6e53fd37fd50d2f5a74915 [file] [log] [blame]
#include "kkt.h"
#ifndef EMBEDDED
csc* form_KKT(const csc *P,
const csc *A,
c_int format,
c_float param1,
c_float *param2,
c_int *PtoKKT,
c_int *AtoKKT,
c_int **Pdiag_idx,
c_int *Pdiag_n,
c_int *param2toKKT) {
c_int nKKT, nnzKKTmax; // Size, number of nonzeros and max number of nonzeros
// in KKT matrix
csc *KKT_trip, *KKT; // KKT matrix in triplet format and CSC format
c_int ptr, i, j; // Counters for elements (i,j) and index pointer
c_int zKKT = 0; // Counter for total number of elements in P and in
// KKT
c_int *KKT_TtoC; // Pointer to vector mapping from KKT in triplet form
// to CSC
// Get matrix dimensions
nKKT = P->m + A->m;
// Get maximum number of nonzero elements (only upper triangular part)
nnzKKTmax = P->p[P->n] + // Number of elements in P
P->m + // Number of elements in param1 * I
A->p[A->n] + // Number of nonzeros in A
A->m; // Number of elements in - diag(param2)
// Preallocate KKT matrix in triplet format
KKT_trip = csc_spalloc(nKKT, nKKT, nnzKKTmax, 1, 1);
if (!KKT_trip) return OSQP_NULL; // Failed to preallocate matrix
// Allocate vector of indices on the diagonal. Worst case it has m elements
if (Pdiag_idx != OSQP_NULL) {
(*Pdiag_idx) = c_malloc(P->m * sizeof(c_int));
*Pdiag_n = 0; // Set 0 diagonal elements to start
}
// Allocate Triplet matrices
// P + param1 I
for (j = 0; j < P->n; j++) { // cycle over columns
// No elements in column j => add diagonal element param1
if (P->p[j] == P->p[j + 1]) {
KKT_trip->i[zKKT] = j;
KKT_trip->p[zKKT] = j;
KKT_trip->x[zKKT] = param1;
zKKT++;
}
for (ptr = P->p[j]; ptr < P->p[j + 1]; ptr++) { // cycle over rows
// Get current row
i = P->i[ptr];
// Add element of P
KKT_trip->i[zKKT] = i;
KKT_trip->p[zKKT] = j;
KKT_trip->x[zKKT] = P->x[ptr];
if (PtoKKT != OSQP_NULL) PtoKKT[ptr] = zKKT; // Update index from P to
// KKTtrip
if (i == j) { // P has a diagonal element,
// add param1
KKT_trip->x[zKKT] += param1;
// If index vector pointer supplied -> Store the index
if (Pdiag_idx != OSQP_NULL) {
(*Pdiag_idx)[*Pdiag_n] = ptr;
(*Pdiag_n)++;
}
}
zKKT++;
// Add diagonal param1 in case
if ((i < j) && // Diagonal element not reached
(ptr + 1 == P->p[j + 1])) { // last element of column j
// Add diagonal element param1
KKT_trip->i[zKKT] = j;
KKT_trip->p[zKKT] = j;
KKT_trip->x[zKKT] = param1;
zKKT++;
}
}
}
if (Pdiag_idx != OSQP_NULL) {
// Realloc Pdiag_idx so that it contains exactly *Pdiag_n diagonal elements
(*Pdiag_idx) = c_realloc((*Pdiag_idx), (*Pdiag_n) * sizeof(c_int));
}
// A' at top right
for (j = 0; j < A->n; j++) { // Cycle over columns of A
for (ptr = A->p[j]; ptr < A->p[j + 1]; ptr++) {
KKT_trip->p[zKKT] = P->m + A->i[ptr]; // Assign column index from
// row index of A
KKT_trip->i[zKKT] = j; // Assign row index from
// column index of A
KKT_trip->x[zKKT] = A->x[ptr]; // Assign A value element
if (AtoKKT != OSQP_NULL) AtoKKT[ptr] = zKKT; // Update index from A to
// KKTtrip
zKKT++;
}
}
// - diag(param2) at bottom right
for (j = 0; j < A->m; j++) {
KKT_trip->i[zKKT] = j + P->n;
KKT_trip->p[zKKT] = j + P->n;
KKT_trip->x[zKKT] = -param2[j];
if (param2toKKT != OSQP_NULL) param2toKKT[j] = zKKT; // Update index from
// param2 to KKTtrip
zKKT++;
}
// Allocate number of nonzeros
KKT_trip->nz = zKKT;
// Convert triplet matrix to csc format
if (!PtoKKT && !AtoKKT && !param2toKKT) {
// If no index vectors passed, do not store KKT mapping from Trip to CSC/CSR
if (format == 0) KKT = triplet_to_csc(KKT_trip, OSQP_NULL);
else KKT = triplet_to_csr(KKT_trip, OSQP_NULL);
}
else {
// Allocate vector of indices from triplet to csc
KKT_TtoC = c_malloc((zKKT) * sizeof(c_int));
if (!KKT_TtoC) {
// Error in allocating KKT_TtoC vector
csc_spfree(KKT_trip);
c_free(*Pdiag_idx);
return OSQP_NULL;
}
// Store KKT mapping from Trip to CSC/CSR
if (format == 0)
KKT = triplet_to_csc(KKT_trip, KKT_TtoC);
else
KKT = triplet_to_csr(KKT_trip, KKT_TtoC);
// Update vectors of indices from P, A, param2 to KKT (now in CSC format)
if (PtoKKT != OSQP_NULL) {
for (i = 0; i < P->p[P->n]; i++) {
PtoKKT[i] = KKT_TtoC[PtoKKT[i]];
}
}
if (AtoKKT != OSQP_NULL) {
for (i = 0; i < A->p[A->n]; i++) {
AtoKKT[i] = KKT_TtoC[AtoKKT[i]];
}
}
if (param2toKKT != OSQP_NULL) {
for (i = 0; i < A->m; i++) {
param2toKKT[i] = KKT_TtoC[param2toKKT[i]];
}
}
// Free mapping
c_free(KKT_TtoC);
}
// Clean matrix in triplet format and return result
csc_spfree(KKT_trip);
return KKT;
}
#endif /* ifndef EMBEDDED */
#if EMBEDDED != 1
void update_KKT_P(csc *KKT,
const csc *P,
const c_int *PtoKKT,
const c_float param1,
const c_int *Pdiag_idx,
const c_int Pdiag_n) {
c_int i, j; // Iterations
// Update elements of KKT using P
for (i = 0; i < P->p[P->n]; i++) {
KKT->x[PtoKKT[i]] = P->x[i];
}
// Update diagonal elements of KKT by adding sigma
for (i = 0; i < Pdiag_n; i++) {
j = Pdiag_idx[i]; // Extract index of the element on the
// diagonal
KKT->x[PtoKKT[j]] += param1;
}
}
void update_KKT_A(csc *KKT, const csc *A, const c_int *AtoKKT) {
c_int i; // Iterations
// Update elements of KKT using A
for (i = 0; i < A->p[A->n]; i++) {
KKT->x[AtoKKT[i]] = A->x[i];
}
}
void update_KKT_param2(csc *KKT, const c_float *param2,
const c_int *param2toKKT, const c_int m) {
c_int i; // Iterations
// Update elements of KKT using param2
for (i = 0; i < m; i++) {
KKT->x[param2toKKT[i]] = -param2[i];
}
}
#endif // EMBEDDED != 1