forked from RobotLocomotion/drake
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlinear_system_solver.cc
87 lines (72 loc) · 2.93 KB
/
linear_system_solver.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include "drake/solvers/linear_system_solver.h"
#include <cstring>
#include <limits>
#include <memory>
#include <vector>
#include "drake/common/drake_assert.h"
#include "drake/common/never_destroyed.h"
#include "drake/solvers/mathematical_program.h"
namespace drake {
namespace solvers {
bool LinearSystemSolver::is_available() { return true; }
SolutionResult LinearSystemSolver::Solve(MathematicalProgram& prog) const {
size_t num_constraints = 0;
for (auto const& binding : prog.linear_equality_constraints()) {
num_constraints += binding.evaluator()->A().rows();
}
DRAKE_ASSERT(prog.generic_constraints().empty());
DRAKE_ASSERT(prog.generic_costs().empty());
DRAKE_ASSERT(prog.quadratic_costs().empty());
DRAKE_ASSERT(prog.linear_constraints().empty());
DRAKE_ASSERT(prog.bounding_box_constraints().empty());
DRAKE_ASSERT(prog.linear_complementarity_constraints().empty());
Eigen::MatrixXd Aeq = Eigen::MatrixXd::Zero(num_constraints, prog.num_vars());
// TODO(naveenoid) : use a sparse matrix here?
Eigen::VectorXd beq(num_constraints);
size_t constraint_index = 0;
for (auto const& binding : prog.linear_equality_constraints()) {
auto const& c = binding.evaluator();
size_t n = c->A().rows();
for (int i = 0; i < static_cast<int>(binding.GetNumElements()); ++i) {
size_t variable_index =
prog.FindDecisionVariableIndex(binding.variables()(i));
Aeq.block(constraint_index, variable_index, n, 1) = c->A().col(i);
}
beq.segment(constraint_index, n) =
c->lower_bound(); // = c->upper_bound() since it's an equality
// constraint
constraint_index += n;
}
// least-squares solution
const Eigen::VectorXd least_square_sol =
Aeq.jacobiSvd(Eigen::ComputeThinU | Eigen::ComputeThinV).solve(beq);
SolverResult solver_result(id());
solver_result.set_decision_variable_values(least_square_sol);
if (beq.isApprox(Aeq * least_square_sol)) {
solver_result.set_optimal_cost(0.);
prog.SetSolverResult(solver_result);
return SolutionResult::kSolutionFound;
} else {
solver_result.set_optimal_cost(MathematicalProgram::kGlobalInfeasibleCost);
prog.SetSolverResult(solver_result);
return SolutionResult::kInfeasibleConstraints;
}
}
SolverId LinearSystemSolver::solver_id() const { return id(); }
SolverId LinearSystemSolver::id() {
static const never_destroyed<SolverId> singleton{"Linear system"};
return singleton.access();
}
bool LinearSystemSolver::AreProgramAttributesSatisfied(
const MathematicalProgram& prog) const {
return ProgramAttributesSatisfied(prog);
}
bool LinearSystemSolver::ProgramAttributesSatisfied(
const MathematicalProgram& prog) {
static const never_destroyed<ProgramAttributes> solver_capability(
std::initializer_list<ProgramAttribute>{
ProgramAttribute::kLinearEqualityConstraint});
return prog.required_capabilities() == solver_capability.access();
}
} // namespace solvers
} // namespace drake