forked from RobotLocomotion/drake
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcreate_cost.cc
125 lines (108 loc) · 4.09 KB
/
create_cost.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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#include "drake/solvers/create_cost.h"
#include <algorithm>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "drake/common/unused.h"
#include "drake/solvers/symbolic_extraction.h"
namespace drake {
namespace solvers {
namespace internal {
using std::make_shared;
using std::numeric_limits;
using std::ostringstream;
using std::runtime_error;
using std::set;
using std::shared_ptr;
using std::unordered_map;
using std::vector;
using symbolic::Expression;
using symbolic::Formula;
using symbolic::Variable;
using internal::DecomposeLinearExpression;
using internal::DecomposeQuadraticPolynomial;
using internal::ExtractAndAppendVariablesFromExpression;
using internal::ExtractVariablesFromExpression;
using internal::SymbolicError;
namespace {
Binding<QuadraticCost> DoParseQuadraticCost(
const symbolic::Polynomial& poly, const VectorXDecisionVariable& vars_vec,
const unordered_map<Variable::Id, int>& map_var_to_index) {
// We want to write the expression e in the form 0.5 * x' * Q * x + b' * x + c
// TODO(hongkai.dai): use a sparse matrix to represent Q and b.
Eigen::MatrixXd Q(vars_vec.size(), vars_vec.size());
Eigen::VectorXd b(vars_vec.size());
double constant_term;
DecomposeQuadraticPolynomial(poly, map_var_to_index, &Q, &b, &constant_term);
return CreateBinding(make_shared<QuadraticCost>(Q, b, constant_term),
vars_vec);
}
Binding<LinearCost> DoParseLinearCost(
const Expression &e,
const VectorXDecisionVariable& vars_vec,
const unordered_map<Variable::Id, int>& map_var_to_index) {
Eigen::RowVectorXd c(vars_vec.size());
double constant_term{};
DecomposeLinearExpression(e, map_var_to_index, c, &constant_term);
return CreateBinding(make_shared<LinearCost>(c.transpose(), constant_term),
vars_vec);
}
} // anonymous namespace
Binding<LinearCost> ParseLinearCost(const Expression& e) {
auto p = ExtractVariablesFromExpression(e);
return DoParseLinearCost(e, p.first, p.second);
}
Binding<QuadraticCost> ParseQuadraticCost(const Expression& e) {
// First build an Eigen vector, that contains all the bound variables.
auto p = ExtractVariablesFromExpression(e);
const auto& vars_vec = p.first;
const auto& map_var_to_index = p.second;
// Now decomposes the expression into coefficients and monomials.
const symbolic::Polynomial poly{e};
return DoParseQuadraticCost(poly, vars_vec, map_var_to_index);
}
Binding<PolynomialCost> ParsePolynomialCost(const symbolic::Expression& e) {
if (!e.is_polynomial()) {
ostringstream oss;
oss << "Expression" << e
<< " is not a polynomial. ParsePolynomialCost"
" only supports polynomial expression.\n";
throw runtime_error(oss.str());
}
const symbolic::Variables& vars = e.GetVariables();
const Polynomiald polynomial = e.ToPolynomial();
vector<Polynomiald::VarType> polynomial_vars(vars.size());
VectorXDecisionVariable var_vec(vars.size());
int polynomial_var_count = 0;
for (const auto& var : vars) {
polynomial_vars[polynomial_var_count] = var.get_id();
var_vec[polynomial_var_count] = var;
++polynomial_var_count;
}
return CreateBinding(make_shared<PolynomialCost>(
Vector1<Polynomiald>(polynomial), polynomial_vars),
var_vec);
}
Binding<Cost> ParseCost(const symbolic::Expression& e) {
if (!e.is_polynomial()) {
ostringstream oss;
oss << "Expression " << e << " is not a polynomial. ParseCost does not"
<< " support non-polynomial expression.\n";
throw runtime_error(oss.str());
}
const symbolic::Polynomial poly{e};
const int total_degree{poly.TotalDegree()};
auto e_extracted = ExtractVariablesFromExpression(e);
const VectorXDecisionVariable& vars_vec = e_extracted.first;
const auto& map_var_to_index = e_extracted.second;
if (total_degree > 2) {
return ParsePolynomialCost(e);
} else if (total_degree == 2) {
return DoParseQuadraticCost(poly, vars_vec, map_var_to_index);
} else {
return DoParseLinearCost(e, vars_vec, map_var_to_index);
}
}
} // namespace internal
} // namespace solvers
} // namespace drake