Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sparse add linear constraint #20361

Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 34 additions & 2 deletions bindings/pydrake/solvers/solvers_py_mathematicalprogram.cc
Original file line number Diff line number Diff line change
Expand Up @@ -883,14 +883,26 @@ void BindMathematicalProgram(py::module m) {
const Eigen::Ref<const VectorXDecisionVariable>&)>(
&MathematicalProgram::AddLinearConstraint),
py::arg("A"), py::arg("lb"), py::arg("ub"), py::arg("vars"),
doc.MathematicalProgram.AddLinearConstraint.doc_4args_A_lb_ub_vars)
doc.MathematicalProgram.AddLinearConstraint.doc_4args_A_lb_ub_dense)
.def("AddLinearConstraint",
static_cast<Binding<LinearConstraint> (MathematicalProgram::*)(
const Eigen::Ref<const Eigen::RowVectorXd>&, double, double,
const Eigen::Ref<const VectorXDecisionVariable>&)>(
&MathematicalProgram::AddLinearConstraint),
py::arg("a"), py::arg("lb"), py::arg("ub"), py::arg("vars"),
doc.MathematicalProgram.AddLinearConstraint.doc_4args_a_lb_ub_vars)
// Ensure that the sparse version is bound last as otherwise the lambda
// captures the MatrixX and RowVectorX cases.
.def(
"AddLinearConstraint",
[](MathematicalProgram* self, const Eigen::SparseMatrix<double>& A,
const Eigen::Ref<const Eigen::VectorXd>& lb,
const Eigen::Ref<const Eigen::VectorXd>& ub,
const Eigen::Ref<const VectorXDecisionVariable>& vars) {
return self->AddLinearConstraint(A, lb, ub, vars);
},
py::arg("A"), py::arg("lb"), py::arg("ub"), py::arg("vars"),
doc.MathematicalProgram.AddLinearConstraint.doc_4args_A_lb_ub_sparse)
.def("AddLinearConstraint",
static_cast<Binding<LinearConstraint> (MathematicalProgram::*)(
const Expression&, double, double)>(
Expand Down Expand Up @@ -925,7 +937,27 @@ void BindMathematicalProgram(py::module m) {
&MathematicalProgram::AddLinearEqualityConstraint),
py::arg("Aeq"), py::arg("beq"), py::arg("vars"),
doc.MathematicalProgram.AddLinearEqualityConstraint
.doc_3args_Aeq_beq_vars)
.doc_3args_A_b_dense)
.def("AddLinearEqualityConstraint",
static_cast<Binding<LinearEqualityConstraint> (
MathematicalProgram::*)(
const Eigen::Ref<const Eigen::RowVectorXd>&, double,
const Eigen::Ref<const VectorXDecisionVariable>&)>(
&MathematicalProgram::AddLinearEqualityConstraint),
py::arg("a"), py::arg("beq"), py::arg("vars"),
doc.MathematicalProgram.AddLinearConstraint.doc_4args_a_lb_ub_vars)
// Ensure that the sparse version is bound last as otherwise the lambda
// captures the MatrixX and RowVectorX cases.
.def(
"AddLinearEqualityConstraint",
[](MathematicalProgram* self, const Eigen::SparseMatrix<double>& Aeq,
const Eigen::Ref<const Eigen::VectorXd>& beq,
const Eigen::Ref<const VectorXDecisionVariable>& vars) {
return self->AddLinearEqualityConstraint(Aeq, beq, vars);
},
py::arg("Aeq"), py::arg("beq"), py::arg("vars"),
doc.MathematicalProgram.AddLinearEqualityConstraint
.doc_3args_A_b_sparse)
.def("AddLinearEqualityConstraint",
static_cast<Binding<LinearEqualityConstraint> (
MathematicalProgram::*)(const Expression&, double)>(
Expand Down
19 changes: 15 additions & 4 deletions bindings/pydrake/solvers/test/mathematicalprogram_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -778,21 +778,32 @@ def test_linear_constraints(self):
x = prog.NewContinuousVariables(2, 'x')
lb = [0., 0.]
ub = [1., 1.]

A_sparse = scipy.sparse.csc_matrix(
(np.array([2, 1., 3]), np.array([0, 1, 0]),
np.array([0, 2, 2, 3])), shape=(2, 2))

prog.AddBoundingBoxConstraint(lb, ub, x)
prog.AddBoundingBoxConstraint(0., 1., x[0])
prog.AddBoundingBoxConstraint(0., 1., x)
prog.AddLinearConstraint(A=np.eye(2), lb=np.zeros(2), ub=np.ones(2),
vars=x)
prog.AddLinearConstraint(A=A_sparse, lb=np.zeros(2), ub=np.ones(2),
vars=x)
prog.AddLinearConstraint(a=[1, 1], lb=0, ub=0, vars=x)
prog.AddLinearConstraint(e=x[0], lb=0, ub=1)
prog.AddLinearConstraint(v=x, lb=[0, 0], ub=[1, 1])
prog.AddLinearConstraint(f=(x[0] == 0))

prog.AddLinearEqualityConstraint(np.eye(2), np.zeros(2), x)
prog.AddLinearEqualityConstraint(x[0] == 1)
prog.AddLinearEqualityConstraint(x[0] + x[1], 1)
prog.AddLinearEqualityConstraint(Aeq=np.eye(2), beq=np.zeros(2),
vars=x)
prog.AddLinearEqualityConstraint(Aeq=A_sparse, beq=np.zeros(2),
vars=x)
prog.AddLinearEqualityConstraint(a=[1, 1], beq=0, vars=x)
prog.AddLinearEqualityConstraint(f=x[0] == 1)
prog.AddLinearEqualityConstraint(e=x[0] + x[1], b=1)
prog.AddLinearEqualityConstraint(
2 * x[:2] + np.array([0, 1]), np.array([3, 2]))
v=2 * x[:2] + np.array([0, 1]), b=np.array([3, 2]))

def test_constraint_set_bounds(self):
prog = mp.MathematicalProgram()
Expand Down
16 changes: 16 additions & 0 deletions solvers/mathematical_program.cc
Original file line number Diff line number Diff line change
Expand Up @@ -879,6 +879,14 @@ Binding<LinearConstraint> MathematicalProgram::AddLinearConstraint(
return AddConstraint(make_shared<LinearConstraint>(A, lb, ub), vars);
}

Binding<LinearConstraint> MathematicalProgram::AddLinearConstraint(
const Eigen::Ref<const Eigen::SparseMatrix<double>>& A,
const Eigen::Ref<const Eigen::VectorXd>& lb,
const Eigen::Ref<const Eigen::VectorXd>& ub,
const Eigen::Ref<const VectorXDecisionVariable>& vars) {
return AddConstraint(make_shared<LinearConstraint>(A, lb, ub), vars);
}

Binding<LinearEqualityConstraint> MathematicalProgram::AddConstraint(
const Binding<LinearEqualityConstraint>& binding) {
DRAKE_ASSERT(binding.evaluator()->GetDenseA().cols() ==
Expand Down Expand Up @@ -910,6 +918,14 @@ MathematicalProgram::AddLinearEqualityConstraint(
return AddConstraint(make_shared<LinearEqualityConstraint>(Aeq, beq), vars);
}

Binding<LinearEqualityConstraint>
MathematicalProgram::AddLinearEqualityConstraint(
const Eigen::Ref<const Eigen::SparseMatrix<double>>& Aeq,
const Eigen::Ref<const Eigen::VectorXd>& beq,
const Eigen::Ref<const VectorXDecisionVariable>& vars) {
return AddConstraint(make_shared<LinearEqualityConstraint>(Aeq, beq), vars);
}

Binding<BoundingBoxConstraint> MathematicalProgram::AddConstraint(
const Binding<BoundingBoxConstraint>& binding) {
if (!CheckBinding(binding)) {
Expand Down
72 changes: 66 additions & 6 deletions solvers/mathematical_program.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <vector>

#include <Eigen/Core>
#include <Eigen/SparseCore>

#include "drake/common/autodiff.h"
#include "drake/common/drake_assert.h"
Expand Down Expand Up @@ -1448,6 +1449,8 @@ class MathematicalProgram {
/**
* Adds linear constraints referencing potentially a subset
* of the decision variables (defined in the vars parameter).
*
* @exclude_from_pydrake_mkdoc{Not bound in pydrake.}
*/
Binding<LinearConstraint> AddLinearConstraint(
const Eigen::Ref<const Eigen::MatrixXd>& A,
Expand All @@ -1457,16 +1460,44 @@ class MathematicalProgram {
return AddLinearConstraint(A, lb, ub, ConcatenateVariableRefList(vars));
}

/**
* Adds sparse linear constraints referencing potentially a subset
* of the decision variables (defined in the vars parameter).
*
* @exclude_from_pydrake_mkdoc{Not bound in pydrake.}
*/
Binding<LinearConstraint> AddLinearConstraint(
const Eigen::Ref<const Eigen::SparseMatrix<double>>& A,
const Eigen::Ref<const Eigen::VectorXd>& lb,
const Eigen::Ref<const Eigen::VectorXd>& ub,
const VariableRefList& vars) {
return AddLinearConstraint(A, lb, ub, ConcatenateVariableRefList(vars));
}

/**
* Adds linear constraints referencing potentially a subset
* of the decision variables (defined in the vars parameter).
*
* @pydrake_mkdoc_identifier{4args_A_lb_ub_dense}
*/
Binding<LinearConstraint> AddLinearConstraint(
const Eigen::Ref<const Eigen::MatrixXd>& A,
const Eigen::Ref<const Eigen::VectorXd>& lb,
const Eigen::Ref<const Eigen::VectorXd>& ub,
const Eigen::Ref<const VectorXDecisionVariable>& vars);

/**
* Adds sparse linear constraints referencing potentially a subset
* of the decision variables (defined in the vars parameter).
*
* @pydrake_mkdoc_identifier{4args_A_lb_ub_sparse}
*/
Binding<LinearConstraint> AddLinearConstraint(
const Eigen::Ref<const Eigen::SparseMatrix<double>>& A,
const Eigen::Ref<const Eigen::VectorXd>& lb,
const Eigen::Ref<const Eigen::VectorXd>& ub,
const Eigen::Ref<const VectorXDecisionVariable>& vars);

/**
* Adds one row of linear constraint referencing potentially a
* subset of the decision variables (defined in the vars parameter).
Expand Down Expand Up @@ -1496,7 +1527,9 @@ class MathematicalProgram {
Binding<LinearConstraint> AddLinearConstraint(
const Eigen::Ref<const Eigen::RowVectorXd>& a, double lb, double ub,
const Eigen::Ref<const VectorXDecisionVariable>& vars) {
return AddLinearConstraint(a, Vector1d(lb), Vector1d(ub), vars);
return AddLinearConstraint(
Eigen::Map<const Eigen::MatrixXd>(a.data(), 1, a.size()), Vector1d(lb),
Vector1d(ub), vars);
}

/**
Expand Down Expand Up @@ -1706,6 +1739,20 @@ class MathematicalProgram {
ConcatenateVariableRefList(vars));
}

/** AddLinearEqualityConstraint
*
* Adds linear equality constraints referencing potentially a subset of
* the decision variables using a sparse A matrix.
* @exclude_from_pydrake_mkdoc{Not bound in pydrake.}
*/
Binding<LinearEqualityConstraint> AddLinearEqualityConstraint(
const Eigen::Ref<const Eigen::SparseMatrix<double>>& Aeq,
const Eigen::Ref<const Eigen::VectorXd>& beq,
const VariableRefList& vars) {
return AddLinearEqualityConstraint(Aeq, beq,
ConcatenateVariableRefList(vars));
}

/** AddLinearEqualityConstraint
*
* Adds linear equality constraints referencing potentially a subset of
Expand All @@ -1724,12 +1771,25 @@ class MathematicalProgram {
* // x(0) + x(1) = 3
* prog.AddLinearEqualityConstraint(Aeq, beq, x.head<2>());
* @endcode
*
* @pydrake_mkdoc_identifier{3args_A_b_dense}
*/
Binding<LinearEqualityConstraint> AddLinearEqualityConstraint(
const Eigen::Ref<const Eigen::MatrixXd>& Aeq,
const Eigen::Ref<const Eigen::VectorXd>& beq,
const Eigen::Ref<const VectorXDecisionVariable>& vars);

/** AddLinearEqualityConstraint
*
* Adds linear equality constraints referencing potentially a subset of
* the decision variables using a sparse A matrix.
* @pydrake_mkdoc_identifier{3args_A_b_sparse}
*/
Binding<LinearEqualityConstraint> AddLinearEqualityConstraint(
const Eigen::Ref<const Eigen::SparseMatrix<double>>& Aeq,
const Eigen::Ref<const Eigen::VectorXd>& beq,
const Eigen::Ref<const VectorXDecisionVariable>& vars);

/**
* Adds one row of linear equality constraint referencing potentially a subset
* of decision variables.
Expand All @@ -1745,8 +1805,8 @@ class MathematicalProgram {
Binding<LinearEqualityConstraint> AddLinearEqualityConstraint(
const Eigen::Ref<const Eigen::RowVectorXd>& a, double beq,
const VariableRefList& vars) {
return AddConstraint(std::make_shared<LinearEqualityConstraint>(a, beq),
ConcatenateVariableRefList(vars));
return AddLinearEqualityConstraint(a, beq,
ConcatenateVariableRefList(vars));
}

/**
Expand All @@ -1758,13 +1818,13 @@ class MathematicalProgram {
* @param a A row vector.
* @param beq A scalar.
* @param vars The decision variables on which the constraint is imposed.
*
* @exclude_from_pydrake_mkdoc{Not bound in pydrake.}
*/
Binding<LinearEqualityConstraint> AddLinearEqualityConstraint(
const Eigen::Ref<const Eigen::RowVectorXd>& a, double beq,
const Eigen::Ref<const VectorXDecisionVariable>& vars) {
return AddLinearEqualityConstraint(a, Vector1d(beq), vars);
return AddLinearEqualityConstraint(
Eigen::Map<const Eigen::MatrixXd>(a.data(), 1, a.size()), Vector1d(beq),
vars);
}

/**
Expand Down
Loading