Skip to content

Commit f3ebf1e

Browse files
Add active_set function
1 parent 0918771 commit f3ebf1e

2 files changed

Lines changed: 119 additions & 1 deletion

File tree

src/active_set.cpp

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
#include "default_types.h"
2+
#include <igl/active_set.h>
3+
#include <nanobind/nanobind.h>
4+
#include <nanobind/ndarray.h>
5+
#include <nanobind/eigen/dense.h>
6+
#include <nanobind/eigen/sparse.h>
7+
8+
namespace nb = nanobind;
9+
using namespace nb::literals;
10+
11+
namespace pyigl
12+
{
13+
// Wrapper for active_set function
14+
auto active_set(
15+
const Eigen::SparseMatrixN &A,
16+
const nb::DRef<const Eigen::VectorXN> &B,
17+
const nb::DRef<const Eigen::VectorXI> &known,
18+
const nb::DRef<const Eigen::VectorXN> &Y,
19+
const Eigen::SparseMatrixN &Aeq,
20+
const nb::DRef<const Eigen::VectorXN> &Beq,
21+
const Eigen::SparseMatrixN &Aieq,
22+
const nb::DRef<const Eigen::VectorXN> &Bieq,
23+
const nb::DRef<const Eigen::VectorXN> &lx,
24+
const nb::DRef<const Eigen::VectorXN> &ux,
25+
const bool Auu_pd,
26+
const int max_iter,
27+
const double inactive_threshold,
28+
const double constraint_threshold,
29+
const double solution_diff_threshold)
30+
{
31+
igl::active_set_params params;
32+
params.Auu_pd = Auu_pd;
33+
params.max_iter = max_iter;
34+
params.inactive_threshold = inactive_threshold;
35+
params.constraint_threshold = constraint_threshold;
36+
params.solution_diff_threshold = solution_diff_threshold;
37+
38+
Eigen::VectorXN Z;
39+
igl::SolverStatus status = igl::active_set(
40+
A, B, known, Y, Aeq, Beq, Aieq, Bieq, lx, ux, params, Z);
41+
42+
if(status == igl::SOLVER_STATUS_ERROR)
43+
{
44+
throw std::runtime_error("active_set: solver failed");
45+
}
46+
return Z;
47+
}
48+
}
49+
50+
// Bind the wrapper to the Python module
51+
void bind_active_set(nb::module_ &m)
52+
{
53+
igl::active_set_params params;
54+
m.def(
55+
"active_set",
56+
&pyigl::active_set,
57+
"A"_a,
58+
"B"_a,
59+
"known"_a = Eigen::VectorXI(),
60+
"Y"_a = Eigen::VectorXN(),
61+
"Aeq"_a = Eigen::SparseMatrixN(),
62+
"Beq"_a = Eigen::VectorXN(),
63+
"Aieq"_a = Eigen::SparseMatrixN(),
64+
"Bieq"_a = Eigen::VectorXN(),
65+
"lx"_a = Eigen::VectorXN(),
66+
"ux"_a = Eigen::VectorXN(),
67+
"Auu_pd"_a = params.Auu_pd,
68+
"max_iter"_a = params.max_iter,
69+
"inactive_threshold"_a = params.inactive_threshold,
70+
"constraint_threshold"_a = params.constraint_threshold,
71+
"solution_diff_threshold"_a = params.solution_diff_threshold,
72+
R"(Minimize a convex quadratic energy subject to linear constraints.
73+
74+
Solves:
75+
min 0.5 * Z' * A * Z + Z' * B
76+
Z
77+
subject to
78+
Z(known) = Y
79+
Aeq * Z = Beq
80+
Aieq * Z <= Bieq
81+
lx <= Z <= ux
82+
83+
@param[in] A n by n matrix of quadratic coefficients
84+
@param[in] B n by 1 column of linear coefficients
85+
@param[in] known list of indices to known rows in Z
86+
@param[in] Y list of fixed values corresponding to known rows in Z
87+
@param[in] Aeq meq by n list of linear equality constraint coefficients
88+
@param[in] Beq meq by 1 list of linear equality constraint constant values
89+
@param[in] Aieq mieq by n list of linear inequality constraint coefficients
90+
@param[in] Bieq mieq by 1 list of linear inequality constraint constant values
91+
@param[in] lx n by 1 list of lower bounds [] implies -Inf
92+
@param[in] ux n by 1 list of upper bounds [] implies Inf
93+
@param[in] Auu_pd whether Auu is positive definite {false}
94+
@param[in] max_iter maximum number of iterations {100}
95+
@param[in] inactive_threshold threshold on Lagrange multiplier values {1e-14}
96+
@param[in] constraint_threshold threshold on constraint violation {1e-14}
97+
@param[in] solution_diff_threshold threshold on solution difference {1e-14}
98+
@return Z n by 1 solution vector)"
99+
);
100+
}

tests/test_all.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,25 @@ def test_min_quad():
258258
data = igl.min_quad_with_fixed_data()
259259
igl.min_quad_with_fixed_precompute(A,known,Aeq,True,data)
260260
Z = igl.min_quad_with_fixed_solve(data,B,Y,Beq)
261-
261+
262+
def test_active_set():
263+
V,F,T = single_tet()
264+
n = V.shape[0]
265+
A = -igl.cotmatrix(V,F)
266+
B = np.zeros(n,dtype=np.float64)
267+
known = np.array([0,1],dtype=np.int64)
268+
Y = np.array([0.0,1.0],dtype=np.float64)
269+
Aeq = scipy.sparse.csc_matrix((0,n),dtype=np.float64)
270+
Beq = np.array([],dtype=np.float64)
271+
Aieq = scipy.sparse.csc_matrix((0,n),dtype=np.float64)
272+
Bieq = np.array([],dtype=np.float64)
273+
lx = np.array([],dtype=np.float64)
274+
ux = np.array([],dtype=np.float64)
275+
Z = igl.active_set(A,B,known,Y,Aeq,Beq,Aieq,Bieq,lx,ux)
276+
assert Z.shape[0] == n
277+
assert Z[0] == pytest.approx(0.0)
278+
assert Z[1] == pytest.approx(1.0)
279+
262280
def test_volume():
263281
V = np.array([[0,0,0],[1,0,0],[0,1,0],[0,0,1]],dtype=np.float64)
264282
T = np.array([[0,1,2,3]],dtype=np.int64)

0 commit comments

Comments
 (0)