Skip to content

Commit 7aed8d0

Browse files
authored
Merge pull request #115 from fabinsch/topic/add-unittest
Assert primal/dual residual and dual gap != nan + add unittest
2 parents bda7c8f + 83e8a53 commit 7aed8d0

File tree

4 files changed

+55
-0
lines changed

4 files changed

+55
-0
lines changed

include/proxsuite/proxqp/dense/solver.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1317,6 +1317,11 @@ qp_solve( //
13171317
<< std::endl;
13181318
}
13191319
qpwork.dirty = true;
1320+
1321+
assert(!std::isnan(qpresults.info.pri_res));
1322+
assert(!std::isnan(qpresults.info.dua_res));
1323+
assert(!std::isnan(qpresults.info.duality_gap));
1324+
13201325
PROXSUITE_EIGEN_MALLOC_ALLOWED();
13211326
}
13221327

include/proxsuite/proxqp/sparse/solver.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
#define PROXSUITE_PROXQP_SPARSE_SOLVER_HPP
88

99
#include <chrono>
10+
#include <cmath>
11+
1012
#include <proxsuite/linalg/dense/core.hpp>
1113
#include <proxsuite/linalg/sparse/core.hpp>
1214
#include <proxsuite/linalg/sparse/factorize.hpp>
@@ -1409,6 +1411,10 @@ qp_solve(Results<T>& results,
14091411
<< std::endl;
14101412
}
14111413

1414+
assert(!std::isnan(results.info.pri_res));
1415+
assert(!std::isnan(results.info.dua_res));
1416+
assert(!std::isnan(results.info.duality_gap));
1417+
14121418
work.set_dirty();
14131419
}
14141420
} // namespace sparse
768 Bytes
Binary file not shown.

test/src/dense_qp_solve.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
#
22
# Copyright (c) 2022, INRIA
33
#
4+
import os
45
import proxsuite
56
import numpy as np
67
import scipy.sparse as spa
8+
import scipy.io as spio
79
import unittest
810

911

@@ -368,6 +370,48 @@ def test_initializing_with_None(self):
368370
)
369371
)
370372

373+
def test_solve_qpsolvers_problem(self):
374+
print(
375+
"------------------------test case from qpsolvers with equality constraint and upper bound inequality constraints"
376+
)
377+
file_path = os.path.dirname(os.path.realpath(__file__))
378+
data_path = os.path.join(file_path, "..", "data")
379+
m = spio.loadmat(
380+
os.path.join(data_path, "simple_qp_with_inifinity_lower_bound.mat"),
381+
squeeze_me=True,
382+
)
383+
P = m["P"].astype(float)
384+
q = m["q"].astype(float)
385+
A = m["A"].astype(float).reshape((1, 3))
386+
b = np.array([m["b"]]).reshape((1,))
387+
C = m["C"].astype(float)
388+
l = m["l"].astype(float)
389+
u = m["u"].astype(float)
390+
391+
results = proxsuite.proxqp.dense.solve(P, q, A, b, C, l, u, verbose=False)
392+
print("optimal x: {}".format(results.x))
393+
394+
dua_res = normInf(
395+
P @ results.x + q + A.transpose() @ results.y + C.transpose() @ results.z
396+
)
397+
pri_res = max(
398+
normInf(A @ results.x - b),
399+
normInf(
400+
np.maximum(C @ results.x - u, 0) + np.minimum(C @ results.x - l, 0)
401+
),
402+
)
403+
assert dua_res <= 1e-5
404+
assert pri_res <= 1e-5
405+
406+
print("--n = {} ; n_eq = {} ; n_in = {}".format(3, 1, 3))
407+
print("dual residual = {} ".format(dua_res))
408+
print("total number of iteration: {}".format(results.info.iter))
409+
print(
410+
"setup timing = {} ; solve time = {}".format(
411+
results.info.setup_time, results.info.solve_time
412+
)
413+
)
414+
371415

372416
if __name__ == "__main__":
373417
unittest.main()

0 commit comments

Comments
 (0)