test_lin_alg.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. #include <stdio.h>
  2. #include "osqp.h"
  3. #include "minunit.h"
  4. #include "lin_alg/data.h"
  5. static const char* test_constr_sparse_mat() {
  6. c_float *Adns; // Conversion to dense matrix
  7. lin_alg_sols_data *data = generate_problem_lin_alg_sols_data();
  8. // Convert sparse to dense
  9. Adns = csc_to_dns(data->test_sp_matrix_A);
  10. // Compute norm of the elementwise difference with
  11. mu_assert("Linear algebra tests: error in constructing sparse/dense matrix!",
  12. vec_norm_inf_diff(Adns, data->test_sp_matrix_Adns,
  13. data->test_sp_matrix_A->m *
  14. data->test_sp_matrix_A->n) < TESTS_TOL);
  15. // Free memory
  16. c_free(Adns); // because of vars from file matrices.h
  17. clean_problem_lin_alg_sols_data(data);
  18. return 0;
  19. }
  20. static const char* test_vec_operations() {
  21. c_float norm_inf, vecprod; // normInf;
  22. c_float *ew_reciprocal;
  23. c_float *add_scaled;
  24. c_float *vec_ew_max_vec_test, *vec_ew_min_vec_test;
  25. lin_alg_sols_data *data = generate_problem_lin_alg_sols_data();
  26. // Add scaled
  27. add_scaled = vec_copy(data->test_vec_ops_v1, data->test_vec_ops_n);
  28. vec_add_scaled(add_scaled,
  29. add_scaled,
  30. data->test_vec_ops_v2,
  31. data->test_vec_ops_n,
  32. data->test_vec_ops_sc);
  33. mu_assert(
  34. "Linear algebra tests: error in vector operation, adding scaled vector",
  35. vec_norm_inf_diff(add_scaled, data->test_vec_ops_add_scaled,
  36. data->test_vec_ops_n) < TESTS_TOL);
  37. // Norm_inf of the difference
  38. mu_assert(
  39. "Linear algebra tests: error in vector operation, norm_inf of difference",
  40. c_absval(vec_norm_inf_diff(data->test_vec_ops_v1,
  41. data->test_vec_ops_v2,
  42. data->test_vec_ops_n) -
  43. data->test_vec_ops_norm_inf_diff) <
  44. TESTS_TOL);
  45. // norm_inf
  46. norm_inf = vec_norm_inf(data->test_vec_ops_v1, data->test_vec_ops_n);
  47. mu_assert("Linear algebra tests: error in vector operation, norm_inf",
  48. c_absval(norm_inf - data->test_vec_ops_norm_inf) < TESTS_TOL);
  49. // Elementwise reciprocal
  50. ew_reciprocal = (c_float *)c_malloc(data->test_vec_ops_n * sizeof(c_float));
  51. vec_ew_recipr(data->test_vec_ops_v1, ew_reciprocal, data->test_vec_ops_n);
  52. mu_assert(
  53. "Linear algebra tests: error in vector operation, elementwise reciprocal",
  54. vec_norm_inf_diff(ew_reciprocal, data->test_vec_ops_ew_reciprocal,
  55. data->test_vec_ops_n) < TESTS_TOL);
  56. // Vector product
  57. vecprod = vec_prod(data->test_vec_ops_v1,
  58. data->test_vec_ops_v2,
  59. data->test_vec_ops_n);
  60. mu_assert("Linear algebra tests: error in vector operation, vector product",
  61. c_absval(vecprod - data->test_vec_ops_vec_prod) < TESTS_TOL);
  62. // Elementwise maximum between two vectors
  63. vec_ew_max_vec_test =
  64. (c_float *)c_malloc(data->test_vec_ops_n * sizeof(c_float));
  65. vec_ew_max_vec(data->test_vec_ops_v1,
  66. data->test_vec_ops_v2,
  67. vec_ew_max_vec_test,
  68. data->test_vec_ops_n);
  69. mu_assert(
  70. "Linear algebra tests: error in vector operation, elementwise maximum between vectors",
  71. vec_norm_inf_diff(vec_ew_max_vec_test, data->test_vec_ops_ew_max_vec,
  72. data
  73. ->test_vec_ops_n) < TESTS_TOL);
  74. // Elementwise minimum between two vectors
  75. vec_ew_min_vec_test =
  76. (c_float *)c_malloc(data->test_vec_ops_n * sizeof(c_float));
  77. vec_ew_min_vec(data->test_vec_ops_v1,
  78. data->test_vec_ops_v2,
  79. vec_ew_min_vec_test,
  80. data->test_vec_ops_n);
  81. mu_assert(
  82. "Linear algebra tests: error in vector operation, elementwise minimum between vectors",
  83. vec_norm_inf_diff(vec_ew_min_vec_test, data->test_vec_ops_ew_min_vec,
  84. data
  85. ->test_vec_ops_n) < TESTS_TOL);
  86. // cleanup
  87. c_free(add_scaled);
  88. c_free(ew_reciprocal);
  89. c_free(vec_ew_min_vec_test);
  90. c_free(vec_ew_max_vec_test);
  91. clean_problem_lin_alg_sols_data(data);
  92. return 0;
  93. }
  94. static const char* test_mat_operations() {
  95. csc *Ad, *dA; // Matrices used for tests
  96. // csc *A_ewsq, *A_ewabs; // Matrices used for tests
  97. c_int exitflag = 0;
  98. // c_float trace, fro_sq;
  99. c_float *inf_norm_cols_rows_test;
  100. lin_alg_sols_data *data = generate_problem_lin_alg_sols_data();
  101. // Copy matrices
  102. Ad = copy_csc_mat(data->test_mat_ops_A);
  103. dA = copy_csc_mat(data->test_mat_ops_A);
  104. // Premultiply matrix A
  105. mat_premult_diag(dA, data->test_mat_ops_d);
  106. mu_assert(
  107. "Linear algebra tests: error in matrix operation, premultiply diagonal",
  108. is_eq_csc(dA, data->test_mat_ops_prem_diag, TESTS_TOL));
  109. // Postmultiply matrix A
  110. mat_postmult_diag(Ad, data->test_mat_ops_d);
  111. mu_assert(
  112. "Linear algebra tests: error in matrix operation, postmultiply diagonal",
  113. is_eq_csc(Ad, data->test_mat_ops_postm_diag, TESTS_TOL));
  114. // Maximum norm over columns
  115. inf_norm_cols_rows_test =
  116. (c_float *)c_malloc(data->test_mat_ops_n * sizeof(c_float));
  117. mat_inf_norm_cols(data->test_mat_ops_A, inf_norm_cols_rows_test);
  118. mu_assert(
  119. "Linear algebra tests: error in matrix operation, max norm over columns",
  120. vec_norm_inf_diff(inf_norm_cols_rows_test, data->test_mat_ops_inf_norm_cols,
  121. data
  122. ->test_mat_ops_n) < TESTS_TOL);
  123. // Maximum norm over rows
  124. mat_inf_norm_rows(data->test_mat_ops_A, inf_norm_cols_rows_test);
  125. mu_assert("Linear algebra tests: error in matrix operation, max norm over rows",
  126. vec_norm_inf_diff(inf_norm_cols_rows_test,
  127. data->test_mat_ops_inf_norm_rows,
  128. data
  129. ->test_mat_ops_n) < TESTS_TOL);
  130. // cleanup
  131. c_free(inf_norm_cols_rows_test);
  132. csc_spfree(Ad);
  133. csc_spfree(dA);
  134. clean_problem_lin_alg_sols_data(data);
  135. return 0;
  136. }
  137. static const char* test_mat_vec_multiplication() {
  138. c_float *Ax, *ATy, *Px, *Ax_cum, *ATy_cum, *Px_cum;
  139. lin_alg_sols_data *data = generate_problem_lin_alg_sols_data();
  140. // Allocate vectors
  141. Ax = (c_float *)c_malloc(data->test_mat_vec_m * sizeof(c_float));
  142. ATy = (c_float *)c_malloc(data->test_mat_vec_n * sizeof(c_float));
  143. Px = (c_float *)c_malloc(data->test_mat_vec_n * sizeof(c_float));
  144. // Matrix-vector multiplication: y = Ax
  145. mat_vec(data->test_mat_vec_A, data->test_mat_vec_x, Ax, 0);
  146. mu_assert(
  147. "Linear algebra tests: error in matrix-vector operation, matrix-vector multiplication",
  148. vec_norm_inf_diff(Ax, data->test_mat_vec_Ax,
  149. data->test_mat_vec_m) < TESTS_TOL);
  150. // Cumulative matrix-vector multiplication: y += Ax
  151. Ax_cum = vec_copy(data->test_mat_vec_y, data->test_mat_vec_m);
  152. mat_vec(data->test_mat_vec_A, data->test_mat_vec_x, Ax_cum, 1);
  153. mu_assert(
  154. "Linear algebra tests: error in matrix-vector operation, cumulative matrix-vector multiplication",
  155. vec_norm_inf_diff(Ax_cum, data->test_mat_vec_Ax_cum,
  156. data->test_mat_vec_m) < TESTS_TOL);
  157. // Matrix-transpose-vector multiplication: x = A'*y
  158. mat_tpose_vec(data->test_mat_vec_A, data->test_mat_vec_y, ATy, 0, 0);
  159. mu_assert(
  160. "Linear algebra tests: error in matrix-vector operation, matrix-transpose-vector multiplication",
  161. vec_norm_inf_diff(ATy, data->test_mat_vec_ATy,
  162. data->test_mat_vec_n) < TESTS_TOL);
  163. // Cumulative matrix-transpose-vector multiplication: x += A'*y
  164. ATy_cum = vec_copy(data->test_mat_vec_x, data->test_mat_vec_n);
  165. mat_tpose_vec(data->test_mat_vec_A, data->test_mat_vec_y, ATy_cum, 1, 0);
  166. mu_assert(
  167. "Linear algebra tests: error in matrix-vector operation, cumulative matrix-transpose-vector multiplication",
  168. vec_norm_inf_diff(ATy_cum, data->test_mat_vec_ATy_cum,
  169. data->test_mat_vec_n) < TESTS_TOL);
  170. // Symmetric-matrix-vector multiplication (only upper part is stored)
  171. mat_vec(data->test_mat_vec_Pu, data->test_mat_vec_x, Px, 0); // upper
  172. // traingular
  173. // part
  174. mat_tpose_vec(data->test_mat_vec_Pu, data->test_mat_vec_x, Px, 1, 1); // lower
  175. // traingular
  176. // part
  177. // (without
  178. // diagonal)
  179. mu_assert(
  180. "Linear algebra tests: error in matrix-vector operation, symmetric matrix-vector multiplication",
  181. vec_norm_inf_diff(Px, data->test_mat_vec_Px,
  182. data->test_mat_vec_n) < TESTS_TOL);
  183. // Cumulative symmetric-matrix-vector multiplication
  184. Px_cum = vec_copy(data->test_mat_vec_x, data->test_mat_vec_n);
  185. mat_vec(data->test_mat_vec_Pu, data->test_mat_vec_x, Px_cum, 1); // upper
  186. // traingular
  187. // part
  188. mat_tpose_vec(data->test_mat_vec_Pu, data->test_mat_vec_x, Px_cum, 1, 1); // lower
  189. // traingular
  190. // part
  191. // (without
  192. // diagonal)
  193. mu_assert(
  194. "Linear algebra tests: error in matrix-vector operation, cumulative symmetric matrix-vector multiplication",
  195. vec_norm_inf_diff(Px_cum, data->test_mat_vec_Px_cum,
  196. data->test_mat_vec_n) < TESTS_TOL);
  197. // cleanup
  198. c_free(Ax);
  199. c_free(ATy);
  200. c_free(Px);
  201. c_free(Ax_cum);
  202. c_free(ATy_cum);
  203. c_free(Px_cum);
  204. clean_problem_lin_alg_sols_data(data);
  205. return 0;
  206. }
  207. static const char* test_extract_upper_triangular() {
  208. c_float *inf_norm_cols_test;
  209. lin_alg_sols_data *data = generate_problem_lin_alg_sols_data();
  210. // Extract upper triangular part
  211. csc *Ptriu = csc_to_triu(data->test_mat_extr_triu_P);
  212. mu_assert("Linear algebra tests: error in forming upper triangular matrix!",
  213. is_eq_csc(data->test_mat_extr_triu_Pu, Ptriu, TESTS_TOL));
  214. // Compute infinity norm over columns of the original matrix by using the
  215. // upper triangular part only
  216. inf_norm_cols_test = (c_float *)c_malloc(data->test_mat_extr_triu_n
  217. * sizeof(c_float));
  218. mat_inf_norm_cols_sym_triu(Ptriu, inf_norm_cols_test);
  219. mu_assert(
  220. "Linear algebra tests: error in forming upper triangular matrix, infinity norm over columns",
  221. vec_norm_inf_diff(inf_norm_cols_test,
  222. data->test_mat_extr_triu_P_inf_norm_cols,
  223. data->test_mat_extr_triu_n) < TESTS_TOL);
  224. // Cleanup
  225. c_free(inf_norm_cols_test);
  226. csc_spfree(Ptriu);
  227. clean_problem_lin_alg_sols_data(data);
  228. return 0;
  229. }
  230. static const char* test_quad_form_upper_triang() {
  231. c_float quad_form_t;
  232. lin_alg_sols_data *data = generate_problem_lin_alg_sols_data();
  233. // Compute quadratic form
  234. quad_form_t = quad_form(data->test_qpform_Pu, data->test_qpform_x);
  235. mu_assert(
  236. "Linear algebra tests: error in computing quadratic form using upper triangular matrix!",
  237. (c_absval(quad_form_t - data->test_qpform_value) < TESTS_TOL));
  238. // cleanup
  239. clean_problem_lin_alg_sols_data(data);
  240. return 0;
  241. }
  242. static const char* test_lin_alg()
  243. {
  244. mu_run_test(test_constr_sparse_mat);
  245. mu_run_test(test_vec_operations);
  246. mu_run_test(test_mat_operations);
  247. mu_run_test(test_mat_vec_multiplication);
  248. mu_run_test(test_extract_upper_triangular);
  249. mu_run_test(test_quad_form_upper_triang);
  250. return 0;
  251. }