1+ //
2+ // Copyright (c) 2022 INRIA
3+ //
4+ #include < doctest.hpp>
5+ #include < Eigen/Core>
6+ #include < proxsuite/proxqp/dense/dense.hpp>
7+
8+ using T = double ;
9+ using namespace proxsuite ;
10+ using namespace proxsuite ::proxqp;
11+
12+ template <typename T, proxqp::Layout L>
13+ using Mat =
14+ Eigen::Matrix<T,
15+ Eigen::Dynamic,
16+ Eigen::Dynamic,
17+ (L == proxqp::colmajor) ? Eigen::ColMajor : Eigen::RowMajor>;
18+ template <typename T>
19+ using Vec = Eigen::Matrix<T, Eigen::Dynamic, 1 >;
20+
21+ DOCTEST_TEST_CASE (" 3 dim test case from cvxpy, check feasibility" )
22+ {
23+
24+ std::cout << " ---3 dim test case from cvxpy, check feasibility " << std::endl;
25+ T eps_abs = T (1e-9 );
26+ dense::isize dim = 3 ;
27+
28+ Mat<T, colmajor> H = Mat<T, colmajor>(dim, dim);
29+ H << 13.0 , 12.0 , -2.0 , 12.0 , 17.0 , 6.0 , -2.0 , 6.0 , 12.0 ;
30+
31+ Vec<T> g = Vec<T>(dim);
32+ g << -22.0 , -14.5 , 13.0 ;
33+
34+ Mat<T, colmajor> C = Mat<T, colmajor>(dim, dim);
35+ C << 1.0 , 0.0 , 0.0 , 0.0 , 1.0 , 0.0 , 0.0 , 0.0 , 1.0 ;
36+
37+ Vec<T> l = Vec<T>(dim);
38+ l << -1.0 , -1.0 , -1.0 ;
39+
40+ Vec<T> u = Vec<T>(dim);
41+ u << 1.0 , 1.0 , 1.0 ;
42+ Results<T> results = dense::solve<T>(H,
43+ g,
44+ std::nullopt ,
45+ std::nullopt ,
46+ C,
47+ u,
48+ l,
49+ std::nullopt ,
50+ std::nullopt ,
51+ std::nullopt ,
52+ eps_abs,
53+ 0 );
54+
55+ T pri_res = (dense::positive_part (C * results.x - u) +
56+ dense::negative_part (C * results.x - l))
57+ .lpNorm <Eigen::Infinity>();
58+ T dua_res =
59+ (H * results.x + g + C.transpose () * results.z ).lpNorm <Eigen::Infinity>();
60+ DOCTEST_CHECK (pri_res <= eps_abs);
61+ DOCTEST_CHECK (dua_res <= eps_abs);
62+
63+ std::cout << " primal residual: " << pri_res << std::endl;
64+ std::cout << " dual residual: " << dua_res << std::endl;
65+ std::cout << " total number of iteration: " << results.info .iter << std::endl;
66+ std::cout << " setup timing " << results.info .setup_time << " solve time "
67+ << results.info .solve_time << std::endl;
68+ }
69+
70+ DOCTEST_TEST_CASE (" simple test case from cvxpy, check feasibility" )
71+ {
72+
73+ std::cout << " ---simple test case from cvxpy, check feasibility "
74+ << std::endl;
75+ T eps_abs = T (1e-8 );
76+ dense::isize dim = 1 ;
77+
78+ Mat<T, colmajor> H = Mat<T, colmajor>(dim, dim);
79+ H << 20.0 ;
80+
81+ Vec<T> g = Vec<T>(dim);
82+ g << -10.0 ;
83+
84+ Mat<T, colmajor> C = Mat<T, colmajor>(dim, dim);
85+ C << 1.0 ;
86+
87+ Vec<T> l = Vec<T>(dim);
88+ l << 0.0 ;
89+
90+ Vec<T> u = Vec<T>(dim);
91+ u << 1.0 ;
92+ Results<T> results = dense::solve<T>(H,
93+ g,
94+ std::nullopt ,
95+ std::nullopt ,
96+ C,
97+ u,
98+ l,
99+ std::nullopt ,
100+ std::nullopt ,
101+ std::nullopt ,
102+ eps_abs,
103+ 0 );
104+
105+ T pri_res = (dense::positive_part (C * results.x - u) +
106+ dense::negative_part (C * results.x - l))
107+ .lpNorm <Eigen::Infinity>();
108+ T dua_res =
109+ (H * results.x + g + C.transpose () * results.z ).lpNorm <Eigen::Infinity>();
110+ T x_sol = 0.5 ;
111+
112+ DOCTEST_CHECK ((x_sol - results.x .coeff (0 , 0 )) <= eps_abs);
113+ DOCTEST_CHECK (pri_res <= eps_abs);
114+ DOCTEST_CHECK (dua_res <= eps_abs);
115+
116+ std::cout << " primal residual: " << pri_res << std::endl;
117+ std::cout << " dual residual: " << dua_res << std::endl;
118+ std::cout << " total number of iteration: " << results.info .iter << std::endl;
119+ std::cout << " setup timing " << results.info .setup_time << " solve time "
120+ << results.info .solve_time << std::endl;
121+ }
122+
123+ DOCTEST_TEST_CASE (" simple test case from cvxpy, init with solution, check that "
124+ " solver stays there" )
125+ {
126+
127+ std::cout << " ---simple test case from cvxpy, init with solution, check that "
128+ " solver stays there"
129+ << std::endl;
130+ T eps_abs = T (1e-4 );
131+ dense::isize dim = 1 ;
132+
133+ Mat<T, colmajor> H = Mat<T, colmajor>(dim, dim);
134+ H << 20.0 ;
135+
136+ Vec<T> g = Vec<T>(dim);
137+ g << -10.0 ;
138+
139+ Mat<T, colmajor> C = Mat<T, colmajor>(dim, dim);
140+ C << 1.0 ;
141+
142+ Vec<T> l = Vec<T>(dim);
143+ l << 0.0 ;
144+
145+ Vec<T> u = Vec<T>(dim);
146+ u << 1.0 ;
147+
148+ T x_sol = 0.5 ;
149+
150+ proxqp::isize n_in (1 );
151+ proxqp::isize n_eq (0 );
152+ proxqp::dense::QP<T> qp{ dim, n_eq, n_in };
153+ qp.settings .eps_abs = eps_abs;
154+
155+ qp.init (H, g, std::nullopt , std::nullopt , C, u, l);
156+
157+ dense::Vec<T> x = dense::Vec<T>(dim);
158+ dense::Vec<T> y = dense::Vec<T>(dim);
159+ dense::Vec<T> z = dense::Vec<T>(dim);
160+ x << 0.5 ;
161+ y << 0.0 ;
162+ z << 0.0 ;
163+ qp.solve (x, y, z);
164+
165+ T pri_res = (dense::positive_part (C * qp.results .x - u) +
166+ dense::negative_part (C * qp.results .x - l))
167+ .lpNorm <Eigen::Infinity>();
168+ T dua_res = (H * qp.results .x + g + C.transpose () * qp.results .z )
169+ .lpNorm <Eigen::Infinity>();
170+
171+ DOCTEST_CHECK (qp.results .info .iter <= 0 );
172+ DOCTEST_CHECK ((x_sol - qp.results .x .coeff (0 , 0 )) <= eps_abs);
173+ DOCTEST_CHECK (pri_res <= eps_abs);
174+ DOCTEST_CHECK (dua_res <= eps_abs);
175+
176+ std::cout << " primal residual: " << pri_res << std::endl;
177+ std::cout << " dual residual: " << dua_res << std::endl;
178+ std::cout << " total number of iteration: " << qp.results .info .iter
179+ << std::endl;
180+ std::cout << " setup timing " << qp.results .info .setup_time << " solve time "
181+ << qp.results .info .solve_time << std::endl;
182+ }
0 commit comments