WPILibC++ 2027.0.0-alpha-4
Loading...
Searching...
No Matches
filter.hpp
Go to the documentation of this file.
1// Copyright (c) Sleipnir contributors
2
3#pragma once
4
5#include <algorithm>
6#include <cmath>
7#include <limits>
8#include <utility>
9
10#include <Eigen/Core>
11#include <gch/small_vector.hpp>
12
13// See docs/algorithms.md#Works_cited for citation definitions.
14
15namespace slp {
16
17/// Filter entry consisting of cost and constraint violation.
18///
19/// @tparam Scalar Scalar type.
20template <typename Scalar>
22 /// Type alias for dense vector.
23 using DenseVector = Eigen::Vector<Scalar, Eigen::Dynamic>;
24
25 /// The cost function's value
26 Scalar cost{0};
27
28 /// The constraint violation
30
31 constexpr FilterEntry() = default;
32
33 /// Constructs a FilterEntry.
34 ///
35 /// @param cost The cost function's value.
36 /// @param constraint_violation The constraint violation.
39
40 /// Constructs a Newton's method filter entry.
41 ///
42 /// @param f The cost function value.
43 explicit FilterEntry(Scalar f) : FilterEntry{f, Scalar(0)} {}
44
45 /// Constructs a Sequential Quadratic Programming filter entry.
46 ///
47 /// @param f The cost function value.
48 /// @param c_e The equality constraint values (nonzero means violation).
49 FilterEntry(Scalar f, const DenseVector& c_e)
50 : FilterEntry{f, c_e.template lpNorm<1>()} {}
51
52 /// Constructs an interior-point method filter entry.
53 ///
54 /// @param f The cost function value.
55 /// @param s The inequality constraint slack variables.
56 /// @param c_e The equality constraint values (nonzero means violation).
57 /// @param c_i The inequality constraint values (negative means violation).
58 /// @param μ The barrier parameter.
59 FilterEntry(Scalar f, DenseVector& s, const DenseVector& c_e,
60 const DenseVector& c_i, Scalar μ)
61 : FilterEntry{f - μ * s.array().log().sum(),
62 c_e.template lpNorm<1>() + (c_i - s).template lpNorm<1>()} {
63 }
64};
65
66/// Step filter.
67///
68/// See the section on filters in chapter 15 of [1].
69///
70/// @tparam Scalar Scalar type.
71template <typename Scalar>
72class Filter {
73 public:
74 /// The maximum constraint violation
76
77 /// Constructs an empty filter.
79 // Initial filter entry rejects constraint violations above max
80 m_filter.emplace_back(std::numeric_limits<Scalar>::infinity(),
82 }
83
84 /// Resets the filter.
85 void reset() {
86 m_filter.clear();
87
88 // Initial filter entry rejects constraint violations above max
89 m_filter.emplace_back(std::numeric_limits<Scalar>::infinity(),
91 }
92
93 /// Adds a new entry to the filter.
94 ///
95 /// @param entry The entry to add to the filter.
96 void add(const FilterEntry<Scalar>& entry) {
97 // Remove dominated entries
98 erase_if(m_filter, [&](const auto& elem) {
99 return entry.cost <= elem.cost &&
100 entry.constraint_violation <= elem.constraint_violation;
101 });
102
103 m_filter.push_back(entry);
104 }
105
106 /// Adds a new entry to the filter.
107 ///
108 /// @param entry The entry to add to the filter.
109 void add(FilterEntry<Scalar>&& entry) {
110 // Remove dominated entries
111 erase_if(m_filter, [&](const auto& elem) {
112 return entry.cost <= elem.cost &&
113 entry.constraint_violation <= elem.constraint_violation;
114 });
115
116 m_filter.push_back(entry);
117 }
118
119 /// Returns true if the given iterate is accepted by the filter.
120 ///
121 /// @param entry The entry to attempt adding to the filter.
122 /// @param α The step size (0, 1].
123 /// @return True if the given iterate is accepted by the filter.
124 bool try_add(const FilterEntry<Scalar>& entry, Scalar α) {
125 if (is_acceptable(entry, α)) {
126 add(entry);
127 return true;
128 } else {
129 return false;
130 }
131 }
132
133 /// Returns true if the given iterate is accepted by the filter.
134 ///
135 /// @param entry The entry to attempt adding to the filter.
136 /// @param α The step size (0, 1].
137 /// @return True if the given iterate is accepted by the filter.
138 bool try_add(FilterEntry<Scalar>&& entry, Scalar α) {
139 if (is_acceptable(entry, α)) {
140 add(std::move(entry));
141 return true;
142 } else {
143 return false;
144 }
145 }
146
147 /// Returns true if the given entry is acceptable to the filter.
148 ///
149 /// @param entry The entry to check.
150 /// @param α The step size (0, 1].
151 /// @return True if the given entry is acceptable to the filter.
152 bool is_acceptable(const FilterEntry<Scalar>& entry, Scalar α) {
153 using std::isfinite;
154 using std::pow;
155
156 if (!isfinite(entry.cost) || !isfinite(entry.constraint_violation)) {
157 return false;
158 }
159
160 Scalar ϕ = pow(α, Scalar(1.5));
161
162 // If current filter entry is better than all prior ones in some respect,
163 // accept it.
164 //
165 // See equation (2.13) of [4].
166 return std::ranges::all_of(m_filter, [&](const auto& elem) {
167 return entry.cost <= elem.cost - ϕ * γ_cost * elem.constraint_violation ||
168 entry.constraint_violation <=
169 (Scalar(1) - ϕ * γ_constraint) * elem.constraint_violation;
170 });
171 }
172
173 /// Returns the most recently added filter entry.
174 ///
175 /// @return The most recently added filter entry.
176 const FilterEntry<Scalar>& back() const { return m_filter.back(); }
177
178 private:
179 static constexpr Scalar γ_cost{1e-8};
180 static constexpr Scalar γ_constraint{1e-5};
181
183};
184
185} // namespace slp
void add(const FilterEntry< Scalar > &entry)
Adds a new entry to the filter.
Definition filter.hpp:96
const FilterEntry< Scalar > & back() const
Returns the most recently added filter entry.
Definition filter.hpp:176
bool is_acceptable(const FilterEntry< Scalar > &entry, Scalar α)
Returns true if the given entry is acceptable to the filter.
Definition filter.hpp:152
Filter()
Constructs an empty filter.
Definition filter.hpp:78
bool try_add(const FilterEntry< Scalar > &entry, Scalar α)
Returns true if the given iterate is accepted by the filter.
Definition filter.hpp:124
bool try_add(FilterEntry< Scalar > &&entry, Scalar α)
Returns true if the given iterate is accepted by the filter.
Definition filter.hpp:138
Scalar max_constraint_violation
The maximum constraint violation.
Definition filter.hpp:75
void reset()
Resets the filter.
Definition filter.hpp:85
void add(FilterEntry< Scalar > &&entry)
Adds a new entry to the filter.
Definition filter.hpp:109
wpi::util::SmallVector< T > small_vector
Definition small_vector.hpp:10
Definition expression_graph.hpp:11
Variable< Scalar > log(const Variable< Scalar > &x)
log() for Variables.
Definition variable.hpp:503
Variable< Scalar > pow(const ScalarLike auto &base, const Variable< Scalar > &power)
pow() for Variables.
Definition variable.hpp:522
Filter entry consisting of cost and constraint violation.
Definition filter.hpp:21
FilterEntry(Scalar f)
Constructs a Newton's method filter entry.
Definition filter.hpp:43
Scalar cost
The cost function's value.
Definition filter.hpp:26
FilterEntry(Scalar f, DenseVector &s, const DenseVector &c_e, const DenseVector &c_i, Scalar μ)
Constructs an interior-point method filter entry.
Definition filter.hpp:59
Eigen::Vector< Scalar, Eigen::Dynamic > DenseVector
Type alias for dense vector.
Definition filter.hpp:23
constexpr FilterEntry()=default
Scalar constraint_violation
The constraint violation.
Definition filter.hpp:29
constexpr FilterEntry(Scalar cost, Scalar constraint_violation)
Constructs a FilterEntry.
Definition filter.hpp:37
FilterEntry(Scalar f, const DenseVector &c_e)
Constructs a Sequential Quadratic Programming filter entry.
Definition filter.hpp:49