test_update_matrices.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. #include <stdio.h>
  2. #include "osqp.h"
  3. #include "cs.h"
  4. #include "util.h"
  5. #include "minunit.h"
  6. #include "kkt.h"
  7. #include "lin_sys.h"
  8. #include "update_matrices/data.h"
  9. static const char* test_form_KKT() {
  10. update_matrices_sols_data *data;
  11. c_float sigma, *rho_vec, *rho_inv_vec;
  12. c_int m, *PtoKKT, *AtoKKT, *Pdiag_idx, Pdiag_n;
  13. csc *KKT;
  14. // Load problem data
  15. data = generate_problem_update_matrices_sols_data();
  16. // Define rho_vec and sigma to form KKT
  17. sigma = data->test_form_KKT_sigma;
  18. m = data->test_form_KKT_A->m;
  19. rho_vec = (c_float*) c_calloc(m, sizeof(c_float));
  20. rho_inv_vec = (c_float*) c_calloc(m, sizeof(c_float));
  21. vec_add_scalar(rho_vec, data->test_form_KKT_rho, m);
  22. vec_ew_recipr(rho_vec, rho_inv_vec, m);
  23. // Allocate vectors of indices
  24. PtoKKT = (c_int*) c_malloc((data->test_form_KKT_Pu->p[data->test_form_KKT_Pu->n]) *
  25. sizeof(c_int));
  26. AtoKKT = (c_int*) c_malloc((data->test_form_KKT_A->p[data->test_form_KKT_A->n]) *
  27. sizeof(c_int));
  28. // Form KKT matrix storing the index vectors
  29. KKT = form_KKT(data->test_form_KKT_Pu,
  30. data->test_form_KKT_A,
  31. 0,
  32. sigma,
  33. rho_inv_vec,
  34. PtoKKT,
  35. AtoKKT,
  36. &Pdiag_idx,
  37. &Pdiag_n,
  38. OSQP_NULL);
  39. // Assert if KKT matrix is the same as predicted one
  40. mu_assert("Update matrices: error in forming KKT matrix!",
  41. is_eq_csc(KKT, data->test_form_KKT_KKTu, TESTS_TOL));
  42. // Update KKT matrix with new P and new A
  43. update_KKT_P(KKT, data->test_form_KKT_Pu_new, PtoKKT, sigma, Pdiag_idx,
  44. Pdiag_n);
  45. update_KKT_A(KKT, data->test_form_KKT_A_new, AtoKKT);
  46. // Assert if KKT matrix is the same as predicted one
  47. mu_assert("Update matrices: error in updating KKT matrix!",
  48. is_eq_csc(KKT, data->test_form_KKT_KKTu_new, TESTS_TOL));
  49. // Cleanup
  50. clean_problem_update_matrices_sols_data(data);
  51. c_free(Pdiag_idx);
  52. csc_spfree(KKT);
  53. c_free(rho_vec);
  54. c_free(rho_inv_vec);
  55. c_free(AtoKKT);
  56. c_free(PtoKKT);
  57. return 0;
  58. }
  59. static const char* test_update() {
  60. c_int i, nnzP, nnzA;
  61. update_matrices_sols_data *data;
  62. OSQPData *problem;
  63. OSQPWorkspace *work;
  64. OSQPSettings *settings;
  65. c_int exitflag;
  66. // Update matrix P
  67. c_int *Px_new_idx;
  68. // Update matrix A
  69. c_int *Ax_new_idx;
  70. // Load problem data
  71. data = generate_problem_update_matrices_sols_data();
  72. // Generate first problem data
  73. problem = (OSQPData*) c_malloc(sizeof(OSQPData));
  74. problem->P = data->test_solve_Pu;
  75. problem->q = data->test_solve_q;
  76. problem->A = data->test_solve_A;
  77. problem->l = data->test_solve_l;
  78. problem->u = data->test_solve_u;
  79. problem->n = data->test_solve_Pu->n;
  80. problem->m = data->test_solve_A->m;
  81. // Define Solver settings as default
  82. // Problem settings
  83. settings = (OSQPSettings *)c_malloc(sizeof(OSQPSettings));
  84. osqp_set_default_settings(settings);
  85. settings->max_iter = 1000;
  86. settings->alpha = 1.6;
  87. settings->verbose = 1;
  88. // Setup workspace
  89. exitflag = osqp_setup(&work, problem, settings);
  90. // Setup correct
  91. mu_assert("Update matrices: original problem, setup error!", exitflag == 0);
  92. // Solve Problem
  93. osqp_solve(work);
  94. // Compare solver statuses
  95. mu_assert("Update matrices: original problem, error in solver status!",
  96. work->info->status_val == data->test_solve_status);
  97. // Compare primal solutions
  98. mu_assert("Update matrices: original problem, error in primal solution!",
  99. vec_norm_inf_diff(work->solution->x, data->test_solve_x,
  100. data->n) < TESTS_TOL);
  101. // Compare dual solutions
  102. mu_assert("Update matrices: original problem, error in dual solution!",
  103. vec_norm_inf_diff(work->solution->y, data->test_solve_y,
  104. data->m) < TESTS_TOL);
  105. // Update P
  106. nnzP = data->test_solve_Pu->p[data->test_solve_Pu->n];
  107. Px_new_idx = (c_int*) c_malloc(nnzP * sizeof(c_int));
  108. // Generate indices going from beginning to end of P
  109. for (i = 0; i < nnzP; i++) {
  110. Px_new_idx[i] = i;
  111. }
  112. osqp_update_P(work, data->test_solve_Pu_new->x, Px_new_idx, nnzP);
  113. // Solve Problem
  114. osqp_solve(work);
  115. // Compare solver statuses
  116. mu_assert("Update matrices: problem with updating P, error in solver status!",
  117. work->info->status_val == data->test_solve_P_new_status);
  118. // Compare primal solutions
  119. mu_assert("Update matrices: problem with updating P, error in primal solution!",
  120. vec_norm_inf_diff(work->solution->x, data->test_solve_P_new_x,
  121. data->n) < TESTS_TOL);
  122. // Compare dual solutions
  123. mu_assert("Update matrices: problem with updating P, error in dual solution!",
  124. vec_norm_inf_diff(work->solution->y, data->test_solve_P_new_y,
  125. data->m) < TESTS_TOL);
  126. // Cleanup and setup workspace
  127. osqp_cleanup(work);
  128. exitflag = osqp_setup(&work, problem, settings);
  129. // Update P (all indices)
  130. osqp_update_P(work, data->test_solve_Pu_new->x, OSQP_NULL, nnzP);
  131. // Solve Problem
  132. osqp_solve(work);
  133. // Compare solver statuses
  134. mu_assert("Update matrices: problem with updating P (all indices), error in solver status!",
  135. work->info->status_val == data->test_solve_P_new_status);
  136. // Compare primal solutions
  137. mu_assert("Update matrices: problem with updating P (all indices), error in primal solution!",
  138. vec_norm_inf_diff(work->solution->x, data->test_solve_P_new_x,
  139. data->n) < TESTS_TOL);
  140. // Compare dual solutions
  141. mu_assert("Update matrices: problem with updating P (all indices), error in dual solution!",
  142. vec_norm_inf_diff(work->solution->y, data->test_solve_P_new_y,
  143. data->m) < TESTS_TOL);
  144. // Cleanup and setup workspace
  145. osqp_cleanup(work);
  146. exitflag = osqp_setup(&work, problem, settings);
  147. // Update A
  148. nnzA = data->test_solve_A->p[data->test_solve_A->n];
  149. Ax_new_idx = (c_int*) c_malloc(nnzA * sizeof(c_int));
  150. // Generate indices going from beginning to end of A
  151. for (i = 0; i < nnzA; i++) {
  152. Ax_new_idx[i] = i;
  153. }
  154. osqp_update_A(work, data->test_solve_A_new->x, Ax_new_idx, nnzA);
  155. // Solve Problem
  156. osqp_solve(work);
  157. // Compare solver statuses
  158. mu_assert("Update matrices: problem with updating A, error in solver status!",
  159. work->info->status_val == data->test_solve_A_new_status);
  160. // Compare primal solutions
  161. mu_assert("Update matrices: problem with updating A, error in primal solution!",
  162. vec_norm_inf_diff(work->solution->x, data->test_solve_A_new_x,
  163. data->n) < TESTS_TOL);
  164. // Compare dual solutions
  165. mu_assert("Update matrices: problem with updating A, error in dual solution!",
  166. vec_norm_inf_diff(work->solution->y, data->test_solve_A_new_y,
  167. data->m) < TESTS_TOL);
  168. // Cleanup and setup workspace
  169. osqp_cleanup(work);
  170. exitflag = osqp_setup(&work, problem, settings);
  171. // Update A (all indices)
  172. osqp_update_A(work, data->test_solve_A_new->x, OSQP_NULL, nnzA);
  173. // Solve Problem
  174. osqp_solve(work);
  175. // Compare solver statuses
  176. mu_assert("Update matrices: problem with updating A (all indices), error in solver status!",
  177. work->info->status_val == data->test_solve_A_new_status);
  178. // Compare primal solutions
  179. mu_assert("Update matrices: problem with updating A (all indices), error in primal solution!",
  180. vec_norm_inf_diff(work->solution->x, data->test_solve_A_new_x,
  181. data->n) < TESTS_TOL);
  182. // Compare dual solutions
  183. mu_assert("Update matrices: problem with updating A (all indices), error in dual solution!",
  184. vec_norm_inf_diff(work->solution->y, data->test_solve_A_new_y,
  185. data->m) < TESTS_TOL);
  186. // Cleanup and setup workspace
  187. osqp_cleanup(work);
  188. exitflag = osqp_setup(&work, problem, settings);
  189. // Update P and A
  190. osqp_update_P_A(work, data->test_solve_Pu_new->x, Px_new_idx, nnzP,
  191. data->test_solve_A_new->x, Ax_new_idx, nnzA);
  192. // Solve Problem
  193. osqp_solve(work);
  194. // Compare solver statuses
  195. mu_assert(
  196. "Update matrices: problem with updating P and A, error in solver status!",
  197. work->info->status_val == data->test_solve_P_A_new_status);
  198. // Compare primal solutions
  199. mu_assert(
  200. "Update matrices: problem with updating P and A, error in primal solution!",
  201. vec_norm_inf_diff(work->solution->x, data->test_solve_P_A_new_x,
  202. data->n) < TESTS_TOL);
  203. // Compare dual solutions
  204. mu_assert(
  205. "Update matrices: problem with updating P and A, error in dual solution!",
  206. vec_norm_inf_diff(work->solution->y, data->test_solve_P_A_new_y,
  207. data->m) < TESTS_TOL * TESTS_TOL);
  208. // Cleanup and setup workspace
  209. osqp_cleanup(work);
  210. exitflag = osqp_setup(&work, problem, settings);
  211. // Update P and A (all indices)
  212. osqp_update_P_A(work, data->test_solve_Pu_new->x, OSQP_NULL, nnzP,
  213. data->test_solve_A_new->x, OSQP_NULL, nnzA);
  214. // Solve Problem
  215. osqp_solve(work);
  216. // Compare solver statuses
  217. mu_assert(
  218. "Update matrices: problem with updating P and A (all indices), error in solver status!",
  219. work->info->status_val == data->test_solve_P_A_new_status);
  220. // Compare primal solutions
  221. mu_assert(
  222. "Update matrices: problem with updating P and A (all indices), error in primal solution!",
  223. vec_norm_inf_diff(work->solution->x, data->test_solve_P_A_new_x,
  224. data->n) < TESTS_TOL);
  225. // Compare dual solutions
  226. mu_assert(
  227. "Update matrices: problem with updating P and A (all indices), error in dual solution!",
  228. vec_norm_inf_diff(work->solution->y, data->test_solve_P_A_new_y,
  229. data->m) < TESTS_TOL * TESTS_TOL);
  230. // Cleanup problems
  231. osqp_cleanup(work);
  232. clean_problem_update_matrices_sols_data(data);
  233. c_free(problem);
  234. c_free(settings);
  235. c_free(Ax_new_idx);
  236. c_free(Px_new_idx);
  237. return 0;
  238. }
  239. #ifdef ENABLE_MKL_PARDISO
  240. static char* test_update_pardiso() {
  241. c_int i, nnzP, nnzA, exitflag;
  242. update_matrices_sols_data *data;
  243. OSQPData *problem;
  244. OSQPWorkspace *work;
  245. OSQPSettings *settings;
  246. // Update matrix P
  247. c_int *Px_new_idx;
  248. // Update matrix A
  249. c_int *Ax_new_idx;
  250. // Load problem data
  251. data = generate_problem_update_matrices_sols_data();
  252. // Generate first problem data
  253. problem = c_malloc(sizeof(OSQPData));
  254. problem->P = data->test_solve_Pu;
  255. problem->q = data->test_solve_q;
  256. problem->A = data->test_solve_A;
  257. problem->l = data->test_solve_l;
  258. problem->u = data->test_solve_u;
  259. problem->n = data->test_solve_Pu->n;
  260. problem->m = data->test_solve_A->m;
  261. // Define Solver settings as default
  262. // Problem settings
  263. settings = (OSQPSettings *)c_malloc(sizeof(OSQPSettings));
  264. osqp_set_default_settings(settings);
  265. settings->max_iter = 1000;
  266. settings->alpha = 1.6;
  267. settings->verbose = 1;
  268. settings->linsys_solver = MKL_PARDISO_SOLVER;
  269. // Setup workspace
  270. exitflag = osqp_setup(&work, problem, settings);
  271. // Setup correct
  272. mu_assert("Update matrices: original problem, setup error!", exitflag == 0);
  273. // Solve Problem
  274. osqp_solve(work);
  275. // Compare solver statuses
  276. mu_assert("Update matrices: original problem, error in solver status!",
  277. work->info->status_val == data->test_solve_status);
  278. // Compare primal solutions
  279. mu_assert("Update matrices: original problem, error in primal solution!",
  280. vec_norm_inf_diff(work->solution->x, data->test_solve_x,
  281. data->n) < TESTS_TOL);
  282. // Compare dual solutions
  283. mu_assert("Update matrices: original problem, error in dual solution!",
  284. vec_norm_inf_diff(work->solution->y, data->test_solve_y,
  285. data->m) < TESTS_TOL);
  286. // Update P
  287. nnzP = data->test_solve_Pu->p[data->test_solve_Pu->n];
  288. Px_new_idx = c_malloc(nnzP * sizeof(c_int)); // Generate indices going from
  289. // beginning to end of P
  290. for (i = 0; i < nnzP; i++) {
  291. Px_new_idx[i] = i;
  292. }
  293. osqp_update_P(work, data->test_solve_Pu_new->x, Px_new_idx, nnzP);
  294. // Solve Problem
  295. osqp_solve(work);
  296. // Compare solver statuses
  297. mu_assert("Update matrices: problem with P updated, error in solver status!",
  298. work->info->status_val == data->test_solve_P_new_status);
  299. // Compare primal solutions
  300. mu_assert("Update matrices: problem with P updated, error in primal solution!",
  301. vec_norm_inf_diff(work->solution->x, data->test_solve_P_new_x,
  302. data->n) < TESTS_TOL);
  303. // Compare dual solutions
  304. mu_assert("Update matrices: problem with P updated, error in dual solution!",
  305. vec_norm_inf_diff(work->solution->y, data->test_solve_P_new_y,
  306. data->m) < TESTS_TOL);
  307. // Update A
  308. nnzA = data->test_solve_A->p[data->test_solve_A->n];
  309. Ax_new_idx = c_malloc(nnzA * sizeof(c_int)); // Generate indices going from
  310. // beginning to end of P
  311. for (i = 0; i < nnzA; i++) {
  312. Ax_new_idx[i] = i;
  313. }
  314. // Cleanup and setup workspace
  315. osqp_cleanup(work);
  316. exitflag = osqp_setup(&work, problem, settings);
  317. osqp_update_A(work, data->test_solve_A_new->x, Ax_new_idx, nnzA);
  318. // Solve Problem
  319. osqp_solve(work);
  320. // Compare solver statuses
  321. mu_assert("Update matrices: problem with A updated, error in solver status!",
  322. work->info->status_val == data->test_solve_A_new_status);
  323. // Compare primal solutions
  324. mu_assert("Update matrices: problem with A updated, error in primal solution!",
  325. vec_norm_inf_diff(work->solution->x, data->test_solve_A_new_x,
  326. data->n) < TESTS_TOL);
  327. // Compare dual solutions
  328. mu_assert("Update matrices: problem with A updated, error in dual solution!",
  329. vec_norm_inf_diff(work->solution->y, data->test_solve_A_new_y,
  330. data->m) < TESTS_TOL);
  331. // Cleanup and setup workspace
  332. osqp_cleanup(work);
  333. exitflag = osqp_setup(&work, problem, settings);
  334. osqp_update_P_A(work, data->test_solve_Pu_new->x, Px_new_idx, nnzP,
  335. data->test_solve_A_new->x, Ax_new_idx, nnzA);
  336. // Solve Problem
  337. osqp_solve(work);
  338. // Compare solver statuses
  339. mu_assert(
  340. "Update matrices: problem with P and A updated, error in solver status!",
  341. work->info->status_val == data->test_solve_P_A_new_status);
  342. // Compare primal solutions
  343. mu_assert(
  344. "Update matrices: problem with P and A updated, error in primal solution!",
  345. vec_norm_inf_diff(work->solution->x, data->test_solve_P_A_new_x,
  346. data->n) < TESTS_TOL);
  347. // Compare dual solutions
  348. mu_assert(
  349. "Update matrices: problem with P and A updated, error in dual solution!",
  350. vec_norm_inf_diff(work->solution->y, data->test_solve_P_A_new_y,
  351. data->m) < TESTS_TOL * TESTS_TOL);
  352. // Cleanup problems
  353. osqp_cleanup(work);
  354. clean_problem_update_matrices_sols_data(data);
  355. c_free(problem);
  356. c_free(settings);
  357. c_free(Ax_new_idx);
  358. c_free(Px_new_idx);
  359. return 0;
  360. }
  361. #endif
  362. static const char* test_update_matrices()
  363. {
  364. mu_run_test(test_form_KKT);
  365. mu_run_test(test_update);
  366. #ifdef ENABLE_MKL_PARDISO
  367. mu_run_test(test_update_pardiso);
  368. #endif
  369. return 0;
  370. }