Squashed 'third_party/osqp/' content from commit 33454b3e23

Change-Id: I056df0582ca06664e86554c341a94c47ab932001
git-subtree-dir: third_party/osqp
git-subtree-split: 33454b3e236f1f44193bfbbb6b8c8e71f8f04e9a
Signed-off-by: Austin Schuh <austin.linux@gmail.com>
diff --git a/tests/update_matrices/CMakeLists.txt b/tests/update_matrices/CMakeLists.txt
new file mode 100644
index 0000000..2d10bd8
--- /dev/null
+++ b/tests/update_matrices/CMakeLists.txt
@@ -0,0 +1,13 @@
+get_directory_property(headers
+                        DIRECTORY ${PROJECT_SOURCE_DIR}/tests
+                        DEFINITION headers)
+
+set(headers ${headers}
+${CMAKE_CURRENT_SOURCE_DIR}/test_update_matrices.h PARENT_SCOPE)
+
+get_directory_property(codegen_headers
+                        DIRECTORY ${PROJECT_SOURCE_DIR}/tests
+                        DEFINITION codegen_headers)
+
+set(codegen_headers ${codegen_headers}
+        ${CMAKE_CURRENT_SOURCE_DIR}/data.h PARENT_SCOPE)
diff --git a/tests/update_matrices/__init__.py b/tests/update_matrices/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/update_matrices/__init__.py
diff --git a/tests/update_matrices/generate_problem.py b/tests/update_matrices/generate_problem.py
new file mode 100644
index 0000000..d801fc7
--- /dev/null
+++ b/tests/update_matrices/generate_problem.py
@@ -0,0 +1,109 @@
+import numpy as np
+from scipy import sparse
+import utils.codegen_utils as cu
+from numpy.random import Generator, PCG64
+
+# Set random seed for reproducibility
+rg = Generator(PCG64(2))
+
+# Define tests
+n = 5
+m = 8
+test_form_KKT_n = n
+test_form_KKT_m = m
+p = 0.7
+
+test_form_KKT_A = sparse.random(test_form_KKT_m, test_form_KKT_n, density=p, format='csc', random_state=rg)
+test_form_KKT_P = sparse.random(n, n, density=p, random_state=rg)
+test_form_KKT_P = (test_form_KKT_P @ test_form_KKT_P.T).tocsc() + sparse.eye(n, format='csc')
+test_form_KKT_Pu = sparse.triu(test_form_KKT_P, format='csc')
+test_form_KKT_rho = 1.6
+test_form_KKT_sigma = 0.1
+test_form_KKT_KKT = sparse.bmat([[test_form_KKT_P + test_form_KKT_sigma *
+                                  sparse.eye(test_form_KKT_n), test_form_KKT_A.T],
+                                 [test_form_KKT_A, -1./test_form_KKT_rho *
+                                  sparse.eye(test_form_KKT_m)]], format='csc')
+test_form_KKT_KKTu = sparse.triu(test_form_KKT_KKT, format='csc')
+
+
+# Create new P, A and KKT
+test_form_KKT_A_new = test_form_KKT_A.copy()
+test_form_KKT_A_new.data += rg.standard_normal(test_form_KKT_A_new.nnz)
+test_form_KKT_Pu_new = test_form_KKT_Pu.copy()
+test_form_KKT_Pu_new.data += 0.1 * rg.standard_normal(test_form_KKT_Pu_new.nnz)
+test_form_KKT_P_new = test_form_KKT_Pu_new + test_form_KKT_Pu_new.T - sparse.diags(test_form_KKT_Pu_new.diagonal())
+
+test_form_KKT_KKT_new = sparse.bmat([[test_form_KKT_P_new + test_form_KKT_sigma *
+                                      sparse.eye(test_form_KKT_n), test_form_KKT_A_new.T],
+                                     [test_form_KKT_A_new, -1./test_form_KKT_rho *
+                                      sparse.eye(test_form_KKT_m)]], format='csc')
+test_form_KKT_KKTu_new = sparse.triu(test_form_KKT_KKT_new, format='csc')
+
+
+# Test solve problem with initial P and A
+test_solve_P = test_form_KKT_P.copy()
+test_solve_Pu = test_form_KKT_Pu.copy()
+test_solve_q = rg.standard_normal(n)
+test_solve_A = test_form_KKT_A.copy()
+test_solve_l = -30 + rg.standard_normal(m)
+test_solve_u = 30 + rg.standard_normal(m)
+
+
+# Define new P
+test_solve_P_new = test_form_KKT_P_new.copy()
+test_solve_Pu_new = test_form_KKT_Pu_new.copy()
+
+
+# Define new A
+test_solve_A_new = test_form_KKT_A_new.copy()
+
+
+# Generate test data and solutions
+data = {'test_form_KKT_n': test_form_KKT_n,
+        'test_form_KKT_m': test_form_KKT_m,
+        'test_form_KKT_A': test_form_KKT_A,
+        'test_form_KKT_Pu': test_form_KKT_Pu,
+        'test_form_KKT_rho': test_form_KKT_rho,
+        'test_form_KKT_sigma': test_form_KKT_sigma,
+        'test_form_KKT_KKT': test_form_KKT_KKT,
+        'test_form_KKT_KKTu': test_form_KKT_KKTu,
+        'test_form_KKT_A_new': test_form_KKT_A_new,
+        'test_form_KKT_Pu_new': test_form_KKT_Pu_new,
+        'test_form_KKT_KKT_new': test_form_KKT_KKT_new,
+        'test_form_KKT_KKTu_new': test_form_KKT_KKTu_new,
+        'test_solve_Pu': test_solve_Pu,
+        'test_solve_q': test_solve_q,
+        'test_solve_A': test_solve_A,
+        'test_solve_l': test_solve_l,
+        'test_solve_u': test_solve_u,
+        'n': n,
+        'm': m,
+        'test_solve_x': np.array([-4.61725223e-01, 7.97298788e-01,
+                                  5.55470173e-04,  3.37603740e-01,
+                                  -1.14060693e+00]),
+        'test_solve_y': np.zeros(m),
+        'test_solve_obj_value': -1.885431747787806,
+        'test_solve_status': 'optimal',
+        'test_solve_Pu_new': test_solve_Pu_new,
+        'test_solve_P_new_x': np.array([-0.48845963, 0.70997599, -0.09017696,
+                                        0.33176037, -1.01867464]),
+        'test_solve_P_new_y': np.zeros(m),
+        'test_solve_P_new_obj_value': -1.7649689689774013,
+        'test_solve_P_new_status': 'optimal',
+        'test_solve_A_new': test_solve_A_new,
+        'test_solve_A_new_x': np.array([-4.61725223e-01, 7.97298788e-01,
+                                        5.55470173e-04, 3.37603740e-01,
+                                        -1.14060693e+00]),
+        'test_solve_A_new_y': np.zeros(m),
+        'test_solve_A_new_obj_value': -1.8854317477878062,
+        'test_solve_A_new_status': 'optimal',
+        'test_solve_P_A_new_x': np.array([-0.48845963, 0.70997599, -0.09017696,
+                                          0.33176037, -1.01867464]),
+        'test_solve_P_A_new_y': np.zeros(m),
+        'test_solve_P_A_new_obj_value': -1.764968968977401,
+        'test_solve_P_A_new_status': 'optimal'
+        }
+
+
+# Generate test data
+cu.generate_data('update_matrices', data)
diff --git a/tests/update_matrices/test_update_matrices.h b/tests/update_matrices/test_update_matrices.h
new file mode 100644
index 0000000..bb347a6
--- /dev/null
+++ b/tests/update_matrices/test_update_matrices.h
@@ -0,0 +1,471 @@
+#include <stdio.h>
+#include "osqp.h"
+#include "cs.h"
+#include "util.h"
+#include "osqp_tester.h"
+#include "kkt.h"
+#include "lin_sys.h"
+
+
+#include "update_matrices/data.h"
+
+
+void test_form_KKT() {
+  update_matrices_sols_data *data;
+  c_float sigma, *rho_vec, *rho_inv_vec;
+  c_int   m, *PtoKKT, *AtoKKT, *Pdiag_idx, Pdiag_n;
+  csc    *KKT;
+
+  // Load problem data
+  data = generate_problem_update_matrices_sols_data();
+
+  // Define rho_vec and sigma to form KKT
+  sigma       = data->test_form_KKT_sigma;
+  m           = data->test_form_KKT_A->m;
+  rho_vec     = (c_float*) c_calloc(m, sizeof(c_float));
+  rho_inv_vec = (c_float*) c_calloc(m, sizeof(c_float));
+  vec_add_scalar(rho_vec, data->test_form_KKT_rho, m);
+  vec_ew_recipr(rho_vec, rho_inv_vec, m);
+
+  // Allocate vectors of indices
+  PtoKKT = (c_int*) c_malloc((data->test_form_KKT_Pu->p[data->test_form_KKT_Pu->n]) *
+                    sizeof(c_int));
+  AtoKKT = (c_int*) c_malloc((data->test_form_KKT_A->p[data->test_form_KKT_A->n]) *
+                    sizeof(c_int));
+
+  // Form KKT matrix storing the index vectors
+  KKT = form_KKT(data->test_form_KKT_Pu,
+                 data->test_form_KKT_A,
+                 0,
+                 sigma,
+                 rho_inv_vec,
+                 PtoKKT,
+                 AtoKKT,
+                 &Pdiag_idx,
+                 &Pdiag_n,
+                 OSQP_NULL);
+
+  // Assert if KKT matrix is the same as predicted one
+  mu_assert("Update matrices: error in forming KKT matrix!",
+            is_eq_csc(KKT, data->test_form_KKT_KKTu, TESTS_TOL));
+
+  // Update KKT matrix with new P and new A
+  update_KKT_P(KKT, data->test_form_KKT_Pu_new, PtoKKT, sigma, Pdiag_idx,
+               Pdiag_n);
+  update_KKT_A(KKT, data->test_form_KKT_A_new, AtoKKT);
+
+
+  // Assert if KKT matrix is the same as predicted one
+  mu_assert("Update matrices: error in updating KKT matrix!",
+            is_eq_csc(KKT, data->test_form_KKT_KKTu_new, TESTS_TOL));
+
+
+  // Cleanup
+  clean_problem_update_matrices_sols_data(data);
+  c_free(Pdiag_idx);
+  csc_spfree(KKT);
+  c_free(rho_vec);
+  c_free(rho_inv_vec);
+  c_free(AtoKKT);
+  c_free(PtoKKT);
+}
+
+void test_update() {
+  c_int i, nnzP, nnzA;
+  update_matrices_sols_data *data;
+  OSQPData *problem;
+  OSQPWorkspace *work;
+  OSQPSettings  *settings;
+  c_int exitflag;
+
+  // Update matrix P
+  c_int *Px_new_idx;
+
+  // Update matrix A
+  c_int *Ax_new_idx;
+
+  // Load problem data
+  data = generate_problem_update_matrices_sols_data();
+
+  // Generate first problem data
+  problem    = (OSQPData*) c_malloc(sizeof(OSQPData));
+  problem->P = data->test_solve_Pu;
+  problem->q = data->test_solve_q;
+  problem->A = data->test_solve_A;
+  problem->l = data->test_solve_l;
+  problem->u = data->test_solve_u;
+  problem->n = data->test_solve_Pu->n;
+  problem->m = data->test_solve_A->m;
+
+
+  // Define Solver settings as default
+  // Problem settings
+  settings = (OSQPSettings *)c_malloc(sizeof(OSQPSettings));
+  osqp_set_default_settings(settings);
+  settings->max_iter = 1000;
+  settings->alpha    = 1.6;
+  settings->verbose  = 1;
+
+  // Setup workspace
+  exitflag = osqp_setup(&work, problem, settings);
+
+  // Setup correct
+  mu_assert("Update matrices: original problem, setup error!", exitflag == 0);
+
+  // Solve Problem
+  osqp_solve(work);
+
+  // Compare solver statuses
+  mu_assert("Update matrices: original problem, error in solver status!",
+            work->info->status_val == data->test_solve_status);
+
+  // Compare primal solutions
+  mu_assert("Update matrices: original problem, error in primal solution!",
+            vec_norm_inf_diff(work->solution->x, data->test_solve_x,
+                              data->n) < TESTS_TOL);
+
+  // Compare dual solutions
+  mu_assert("Update matrices: original problem, error in dual solution!",
+            vec_norm_inf_diff(work->solution->y, data->test_solve_y,
+                              data->m) < TESTS_TOL);
+
+
+  // Update P
+  nnzP       = data->test_solve_Pu->p[data->test_solve_Pu->n];
+  Px_new_idx = (c_int*) c_malloc(nnzP * sizeof(c_int));
+
+  // Generate indices going from beginning to end of P
+  for (i = 0; i < nnzP; i++) {
+    Px_new_idx[i] = i;
+  }
+
+  osqp_update_P(work, data->test_solve_Pu_new->x, Px_new_idx, nnzP);
+
+  // Solve Problem
+  osqp_solve(work);
+
+  // Compare solver statuses
+  mu_assert("Update matrices: problem with updating P, error in solver status!",
+            work->info->status_val == data->test_solve_P_new_status);
+
+  // Compare primal solutions
+  mu_assert("Update matrices: problem with updating P, error in primal solution!",
+            vec_norm_inf_diff(work->solution->x, data->test_solve_P_new_x,
+                              data->n) < TESTS_TOL);
+
+  // Compare dual solutions
+  mu_assert("Update matrices: problem with updating P, error in dual solution!",
+            vec_norm_inf_diff(work->solution->y, data->test_solve_P_new_y,
+                              data->m) < TESTS_TOL);
+
+  // Cleanup and setup workspace
+  osqp_cleanup(work);
+  exitflag = osqp_setup(&work, problem, settings);
+
+
+  // Update P (all indices)
+  osqp_update_P(work, data->test_solve_Pu_new->x, OSQP_NULL, nnzP);
+
+  // Solve Problem
+  osqp_solve(work);
+
+  // Compare solver statuses
+  mu_assert("Update matrices: problem with updating P (all indices), error in solver status!",
+            work->info->status_val == data->test_solve_P_new_status);
+
+  // Compare primal solutions
+  mu_assert("Update matrices: problem with updating P (all indices), error in primal solution!",
+            vec_norm_inf_diff(work->solution->x, data->test_solve_P_new_x,
+                              data->n) < TESTS_TOL);
+
+  // Compare dual solutions
+  mu_assert("Update matrices: problem with updating P (all indices), error in dual solution!",
+            vec_norm_inf_diff(work->solution->y, data->test_solve_P_new_y,
+                              data->m) < TESTS_TOL);
+
+  // Cleanup and setup workspace
+  osqp_cleanup(work);
+  exitflag = osqp_setup(&work, problem, settings);
+
+
+  // Update A
+  nnzA       = data->test_solve_A->p[data->test_solve_A->n];
+  Ax_new_idx = (c_int*) c_malloc(nnzA * sizeof(c_int));
+
+  // Generate indices going from beginning to end of A
+  for (i = 0; i < nnzA; i++) {
+    Ax_new_idx[i] = i;
+  }
+
+  osqp_update_A(work, data->test_solve_A_new->x, Ax_new_idx, nnzA);
+
+  // Solve Problem
+  osqp_solve(work);
+
+  // Compare solver statuses
+  mu_assert("Update matrices: problem with updating A, error in solver status!",
+            work->info->status_val == data->test_solve_A_new_status);
+
+  // Compare primal solutions
+  mu_assert("Update matrices: problem with updating A, error in primal solution!",
+            vec_norm_inf_diff(work->solution->x, data->test_solve_A_new_x,
+                              data->n) < TESTS_TOL);
+
+  // Compare dual solutions
+  mu_assert("Update matrices: problem with updating A, error in dual solution!",
+            vec_norm_inf_diff(work->solution->y, data->test_solve_A_new_y,
+                              data->m) < TESTS_TOL);
+
+  // Cleanup and setup workspace
+  osqp_cleanup(work);
+  exitflag = osqp_setup(&work, problem, settings);
+
+
+  // Update A (all indices)
+  osqp_update_A(work, data->test_solve_A_new->x, OSQP_NULL, nnzA);
+
+  // Solve Problem
+  osqp_solve(work);
+
+  // Compare solver statuses
+  mu_assert("Update matrices: problem with updating A (all indices), error in solver status!",
+            work->info->status_val == data->test_solve_A_new_status);
+
+  // Compare primal solutions
+  mu_assert("Update matrices: problem with updating A (all indices), error in primal solution!",
+            vec_norm_inf_diff(work->solution->x, data->test_solve_A_new_x,
+                              data->n) < TESTS_TOL);
+
+  // Compare dual solutions
+  mu_assert("Update matrices: problem with updating A (all indices), error in dual solution!",
+            vec_norm_inf_diff(work->solution->y, data->test_solve_A_new_y,
+                              data->m) < TESTS_TOL);
+
+
+  // Cleanup and setup workspace
+  osqp_cleanup(work);
+  exitflag = osqp_setup(&work, problem, settings);
+
+  // Update P and A
+  osqp_update_P_A(work, data->test_solve_Pu_new->x, Px_new_idx, nnzP,
+                  data->test_solve_A_new->x, Ax_new_idx, nnzA);
+
+  // Solve Problem
+  osqp_solve(work);
+
+  // Compare solver statuses
+  mu_assert(
+    "Update matrices: problem with updating P and A, error in solver status!",
+    work->info->status_val == data->test_solve_P_A_new_status);
+
+  // Compare primal solutions
+  mu_assert(
+    "Update matrices: problem with updating P and A, error in primal solution!",
+    vec_norm_inf_diff(work->solution->x, data->test_solve_P_A_new_x,
+                      data->n) < TESTS_TOL);
+
+  // Compare dual solutions
+  mu_assert(
+    "Update matrices: problem with updating P and A, error in dual solution!",
+    vec_norm_inf_diff(work->solution->y, data->test_solve_P_A_new_y,
+                      data->m) < TESTS_TOL);
+
+  // Cleanup and setup workspace
+  osqp_cleanup(work);
+  exitflag = osqp_setup(&work, problem, settings);
+
+
+  // Update P and A (all indices)
+  osqp_update_P_A(work, data->test_solve_Pu_new->x, OSQP_NULL, nnzP,
+                  data->test_solve_A_new->x, OSQP_NULL, nnzA);
+
+  // Solve Problem
+  osqp_solve(work);
+
+  // Compare solver statuses
+  mu_assert(
+    "Update matrices: problem with updating P and A (all indices), error in solver status!",
+    work->info->status_val == data->test_solve_P_A_new_status);
+
+  // Compare primal solutions
+  mu_assert(
+    "Update matrices: problem with updating P and A (all indices), error in primal solution!",
+    vec_norm_inf_diff(work->solution->x, data->test_solve_P_A_new_x,
+                      data->n) < TESTS_TOL);
+
+  // Compare dual solutions
+  mu_assert(
+    "Update matrices: problem with updating P and A (all indices), error in dual solution!",
+    vec_norm_inf_diff(work->solution->y, data->test_solve_P_A_new_y,
+                      data->m) < TESTS_TOL);
+
+
+  // Cleanup problems
+  osqp_cleanup(work);
+  clean_problem_update_matrices_sols_data(data);
+  c_free(problem);
+  c_free(settings);
+  c_free(Ax_new_idx);
+  c_free(Px_new_idx);
+}
+
+#ifdef ENABLE_MKL_PARDISO
+void test_update_pardiso() {
+  c_int i, nnzP, nnzA, exitflag;
+  update_matrices_sols_data *data;
+  OSQPData *problem;
+  OSQPWorkspace *work;
+  OSQPSettings  *settings;
+
+  // Update matrix P
+  c_int *Px_new_idx;
+
+  // Update matrix A
+  c_int *Ax_new_idx;
+
+  // Load problem data
+  data = generate_problem_update_matrices_sols_data();
+
+  // Generate first problem data
+  problem    = (OSQPData*)c_malloc(sizeof(OSQPData));
+  problem->P = data->test_solve_Pu;
+  problem->q = data->test_solve_q;
+  problem->A = data->test_solve_A;
+  problem->l = data->test_solve_l;
+  problem->u = data->test_solve_u;
+  problem->n = data->test_solve_Pu->n;
+  problem->m = data->test_solve_A->m;
+
+
+  // Define Solver settings as default
+  // Problem settings
+  settings = (OSQPSettings *)c_malloc(sizeof(OSQPSettings));
+  osqp_set_default_settings(settings);
+  settings->max_iter      = 1000;
+  settings->alpha         = 1.6;
+  settings->verbose       = 1;
+  settings->linsys_solver = MKL_PARDISO_SOLVER;
+
+  // Setup workspace
+  exitflag = osqp_setup(&work, problem, settings);
+
+  // Setup correct
+  mu_assert("Update matrices: original problem, setup error!", exitflag == 0);
+
+  // Solve Problem
+  osqp_solve(work);
+
+  // Compare solver statuses
+  mu_assert("Update matrices: original problem, error in solver status!",
+            work->info->status_val == data->test_solve_status);
+
+  // Compare primal solutions
+  mu_assert("Update matrices: original problem, error in primal solution!",
+            vec_norm_inf_diff(work->solution->x, data->test_solve_x,
+                              data->n) < TESTS_TOL);
+
+  // Compare dual solutions
+  mu_assert("Update matrices: original problem, error in dual solution!",
+            vec_norm_inf_diff(work->solution->y, data->test_solve_y,
+                              data->m) < TESTS_TOL);
+
+
+  // Update P
+  nnzP       = data->test_solve_Pu->p[data->test_solve_Pu->n];
+  Px_new_idx = (c_int*)c_malloc(nnzP * sizeof(c_int)); // Generate indices going from
+                                               // beginning to end of P
+
+  for (i = 0; i < nnzP; i++) {
+    Px_new_idx[i] = i;
+  }
+
+  osqp_update_P(work, data->test_solve_Pu_new->x, Px_new_idx, nnzP);
+
+  // Solve Problem
+  osqp_solve(work);
+
+  // Compare solver statuses
+  mu_assert("Update matrices: problem with P updated, error in solver status!",
+            work->info->status_val == data->test_solve_P_new_status);
+
+  // Compare primal solutions
+  mu_assert("Update matrices: problem with P updated, error in primal solution!",
+            vec_norm_inf_diff(work->solution->x, data->test_solve_P_new_x,
+                              data->n) < TESTS_TOL);
+
+  // Compare dual solutions
+  mu_assert("Update matrices: problem with P updated, error in dual solution!",
+            vec_norm_inf_diff(work->solution->y, data->test_solve_P_new_y,
+                              data->m) < TESTS_TOL);
+
+
+  // Update A
+  nnzA       = data->test_solve_A->p[data->test_solve_A->n];
+  Ax_new_idx = (c_int*)c_malloc(nnzA * sizeof(c_int)); // Generate indices going from
+                                               // beginning to end of P
+
+  for (i = 0; i < nnzA; i++) {
+    Ax_new_idx[i] = i;
+  }
+
+  // Cleanup and setup workspace
+  osqp_cleanup(work);
+  exitflag = osqp_setup(&work, problem, settings);
+
+  osqp_update_A(work, data->test_solve_A_new->x, Ax_new_idx, nnzA);
+
+  // Solve Problem
+  osqp_solve(work);
+
+  // Compare solver statuses
+  mu_assert("Update matrices: problem with A updated, error in solver status!",
+            work->info->status_val == data->test_solve_A_new_status);
+
+  // Compare primal solutions
+  mu_assert("Update matrices: problem with A updated, error in primal solution!",
+            vec_norm_inf_diff(work->solution->x, data->test_solve_A_new_x,
+                              data->n) < TESTS_TOL);
+
+  // Compare dual solutions
+  mu_assert("Update matrices: problem with A updated, error in dual solution!",
+            vec_norm_inf_diff(work->solution->y, data->test_solve_A_new_y,
+                              data->m) < TESTS_TOL);
+
+
+  // Cleanup and setup workspace
+  osqp_cleanup(work);
+  exitflag = osqp_setup(&work, problem, settings);
+
+  osqp_update_P_A(work, data->test_solve_Pu_new->x, Px_new_idx, nnzP,
+                  data->test_solve_A_new->x, Ax_new_idx, nnzA);
+
+  // Solve Problem
+  osqp_solve(work);
+
+  // Compare solver statuses
+  mu_assert(
+    "Update matrices: problem with P and A updated, error in solver status!",
+    work->info->status_val == data->test_solve_P_A_new_status);
+
+  // Compare primal solutions
+  mu_assert(
+    "Update matrices: problem with P and A updated, error in primal solution!",
+    vec_norm_inf_diff(work->solution->x, data->test_solve_P_A_new_x,
+                      data->n) < TESTS_TOL);
+
+  // Compare dual solutions
+  mu_assert(
+    "Update matrices: problem with P and A updated, error in dual solution!",
+    vec_norm_inf_diff(work->solution->y, data->test_solve_P_A_new_y,
+                      data->m) < TESTS_TOL);
+
+
+  // Cleanup problems
+  osqp_cleanup(work);
+  clean_problem_update_matrices_sols_data(data);
+  c_free(problem);
+  c_free(settings);
+  c_free(Ax_new_idx);
+  c_free(Px_new_idx);
+}
+#endif
\ No newline at end of file