forked from RobotLocomotion/drake
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbinding.h
185 lines (161 loc) · 5.45 KB
/
binding.h
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
#pragma once
#include <cstdint>
#include <memory>
#include <ostream>
#include <sstream>
#include <string>
#include <utility>
#include "drake/common/drake_copyable.h"
#include "drake/common/fmt_ostream.h"
#include "drake/common/hash.h"
#include "drake/solvers/decision_variable.h"
#include "drake/solvers/evaluator_base.h"
namespace drake {
namespace solvers {
/**
* A binding on constraint type C is a mapping of the decision
* variables onto the inputs of C. This allows the constraint to operate
* on a vector made up of different elements of the decision variables.
*/
template <typename C>
class Binding {
public:
DRAKE_DEFAULT_COPY_AND_MOVE_AND_ASSIGN(Binding)
Binding(const std::shared_ptr<C>& c,
const Eigen::Ref<const VectorXDecisionVariable>& v)
: evaluator_(c), vars_(v) {
DRAKE_DEMAND(c->num_vars() == v.rows() || c->num_vars() == Eigen::Dynamic);
}
/**
* Concatenates each VectorDecisionVariable object in @p v into a single
* column vector, binds this column vector of decision variables with
* the constraint @p c.
*/
Binding(const std::shared_ptr<C>& c, const VariableRefList& v)
: evaluator_(c) {
vars_ = ConcatenateVariableRefList(v);
DRAKE_DEMAND(c->num_vars() == vars_.rows() ||
c->num_vars() == Eigen::Dynamic);
}
template <typename U>
Binding(const Binding<U>& b,
typename std::enable_if_t<
std::is_convertible_v<std::shared_ptr<U>, std::shared_ptr<C>>>* =
nullptr)
: Binding(b.evaluator(), b.variables()) {}
[[nodiscard]] const std::shared_ptr<C>& evaluator() const {
return evaluator_;
}
[[nodiscard]] const VectorXDecisionVariable& variables() const {
return vars_;
}
/**
* Returns true iff the given @p var is included in this Binding. */
[[nodiscard]] bool ContainsVariable(const symbolic::Variable& var) const {
for (int i = 0; i < vars_.rows(); ++i) {
if (vars_(i).equal_to(var)) {
return true;
}
}
return false;
}
/**
* Returns the number of variables associated with this evaluator.
*/
[[nodiscard]] size_t GetNumElements() const {
// TODO(ggould-tri) assumes that no index appears more than once in the
// view, which is nowhere asserted (but seems assumed elsewhere).
return vars_.size();
}
/**
* Returns string representation of Binding.
*/
[[nodiscard]] std::string to_string() const {
std::ostringstream os;
os << *this;
return os.str();
}
/** Returns a LaTeX description of this Binding. Does not include any
* characters to enter/exit math mode; you might want, e.g. "$$" +
* evaluator.ToLatex() + "$$". */
std::string ToLatex(int precision = 3) const {
return evaluator()->ToLatex(variables(), precision);
}
/**
* Compare two bindings based on their evaluator pointers and the bound
* variables.
*/
[[nodiscard]] bool operator==(const Binding<C>& other) const {
if (this->evaluator().get() != other.evaluator().get()) {
return false;
}
if (vars_.rows() != other.vars_.rows()) {
return false;
}
for (int i = 0; i < vars_.rows(); ++i) {
if (!vars_(i).equal_to(other.vars_(i))) {
return false;
}
}
return true;
}
[[nodiscard]] bool operator!=(const Binding<C>& other) const {
return !((*this) == (other));
}
/** Implements the @ref hash_append concept. */
template <class HashAlgorithm>
friend void hash_append(HashAlgorithm& hasher,
const Binding<C>& item) noexcept {
using drake::hash_append;
const EvaluatorBase* const base = item.evaluator().get();
hash_append(hasher, reinterpret_cast<std::uintptr_t>(base));
// We follow the pattern in
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3980.html#hash_append_vector
// to append the hash for a std::vector, first to append all its elements,
// and then append the vector size.
for (int i = 0; i < item.variables().rows(); ++i) {
hash_append(hasher, item.variables()(i));
}
hash_append(hasher, item.variables().rows());
}
private:
std::shared_ptr<C> evaluator_;
VectorXDecisionVariable vars_;
};
/**
* Print out the Binding.
*/
template <typename C>
std::ostream& operator<<(std::ostream& os, const Binding<C>& binding) {
return binding.evaluator()->Display(os, binding.variables());
}
namespace internal {
/*
* Create binding, inferring the type from the provided pointer.
* @tparam C Cost or Constraint type to be bound.
* @note Since this forwards arguments, this will not be usable with
* `std::intializer_list`.
*/
template <typename C, typename... Args>
[[nodiscard]] Binding<C> CreateBinding(const std::shared_ptr<C>& c,
Args&&... args) {
return Binding<C>(c, std::forward<Args>(args)...);
}
template <typename To, typename From>
[[nodiscard]] Binding<To> BindingDynamicCast(const Binding<From>& binding) {
auto constraint = std::dynamic_pointer_cast<To>(binding.evaluator());
DRAKE_DEMAND(constraint != nullptr);
return Binding<To>(constraint, binding.variables());
}
} // namespace internal
} // namespace solvers
} // namespace drake
namespace std {
template <typename C>
struct hash<drake::solvers::Binding<C>> : public drake::DefaultHash {};
} // namespace std
// TODO(jwnimmer-tri) Add a real formatter and deprecate the operator<<.
namespace fmt {
template <typename C>
struct formatter<drake::solvers::Binding<C>> : drake::ostream_formatter {};
} // namespace fmt