PANOC-ALM main
Nonconvex constrained optimization
include/panoc-alm/util/problem.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "box.hpp"
4
5#include <cassert>
6#include <chrono>
7#include <functional>
8#include <memory>
9#include <type_traits>
10
11namespace pa {
12
26struct Problem {
27 unsigned int n;
28 unsigned int m;
31
35 using f_sig = real_t(crvec x);
42 using grad_f_sig = void(crvec x, rvec grad_fx);
48 using g_sig = void(crvec x, rvec gx);
59 using grad_g_prod_sig = void(crvec x, crvec y, rvec grad_gxy);
70 using grad_gi_sig = void(crvec x, unsigned i, rvec grad_gi);
83 using hess_L_prod_sig = void(crvec x, crvec y, crvec v, rvec Hv);
92 using hess_L_sig = void(crvec x, crvec y, rmat H);
93
95 std::function<f_sig> f;
97 std::function<grad_f_sig> grad_f;
99 std::function<g_sig> g;
101 std::function<grad_g_prod_sig> grad_g_prod;
103 std::function<grad_gi_sig> grad_gi;
106 std::function<hess_L_prod_sig> hess_L_prod;
108 std::function<hess_L_sig> hess_L;
109
110 Problem() = default;
111 Problem(unsigned int n, unsigned int m)
112 : n(n), m(m), C{vec::Constant(n, +inf), vec::Constant(n, -inf)},
113 D{vec::Constant(m, +inf), vec::Constant(m, -inf)} {}
114 Problem(unsigned n, unsigned int m, Box C, Box D, std::function<f_sig> f,
115 std::function<grad_f_sig> grad_f, std::function<g_sig> g,
116 std::function<grad_g_prod_sig> grad_g_prod,
117 std::function<grad_gi_sig> grad_gi,
118 std::function<hess_L_prod_sig> hess_L_prod,
119 std::function<hess_L_sig> hess_L)
120 : n(n), m(m), C(std::move(C)), D(std::move(D)), f(std::move(f)),
121 grad_f(std::move(grad_f)), g(std::move(g)),
122 grad_g_prod(std::move(grad_g_prod)), grad_gi(std::move(grad_gi)),
123 hess_L_prod(std::move(hess_L_prod)), hess_L(std::move(hess_L)) {}
124};
125
127 public:
128 ParamWrapper(unsigned p) : param(vec::Constant(p, NaN)) {}
129
131
132 virtual ~ParamWrapper() = default;
133 virtual void wrap(Problem &) = 0;
134 virtual std::shared_ptr<ParamWrapper> clone() const = 0;
135};
136
137class ProblemWithParam : public Problem {
138 public:
139 using Problem::Problem;
141 : Problem(o), wrapper(o.wrapper ? o.wrapper->clone() : nullptr) {
142 wrapper->wrap(*this);
143 }
145 static_cast<Problem &>(*this) = static_cast<const Problem &>(o);
146 if (o.wrapper) {
147 this->wrapper = o.wrapper->clone();
148 this->wrapper->wrap(*this);
149 }
150 return *this;
151 }
154
156 assert(p.size() == wrapper->param.size());
157 wrapper->param = p;
158 }
159 void set_param(vec &&p) {
160 assert(p.size() == wrapper->param.size());
161 wrapper->param = std::move(p);
162 }
163 vec &get_param() { return wrapper->param; }
164 const vec &get_param() const { return wrapper->param; }
165
166 std::shared_ptr<ParamWrapper> wrapper;
167};
168
170 unsigned f{};
171 unsigned grad_f{};
172 unsigned g{};
173 unsigned grad_g_prod{};
174 unsigned grad_gi{};
175 unsigned hess_L_prod{};
176 unsigned hess_L{};
177
178 struct EvalTimer {
179 std::chrono::nanoseconds f{};
180 std::chrono::nanoseconds grad_f{};
181 std::chrono::nanoseconds g{};
182 std::chrono::nanoseconds grad_g_prod{};
183 std::chrono::nanoseconds grad_gi{};
184 std::chrono::nanoseconds hess_L_prod{};
185 std::chrono::nanoseconds hess_L{};
187
188 void reset() { *this = {}; }
189};
190
192 a.f += b.f;
193 a.grad_f += b.grad_f;
194 a.g += b.g;
195 a.grad_g_prod += b.grad_g_prod;
196 a.grad_gi += b.grad_gi;
197 a.hess_L_prod += b.hess_L_prod;
198 a.hess_L += b.hess_L;
199 return a;
200}
201
203 const EvalCounter::EvalTimer &b) {
204 a.f += b.f;
205 a.grad_f += b.grad_f;
206 a.g += b.g;
207 a.grad_g_prod += b.grad_g_prod;
208 a.grad_gi += b.grad_gi;
209 a.hess_L_prod += b.hess_L_prod;
210 a.hess_L += b.hess_L;
211 return a;
212}
213
215 return a += b;
216}
217
218template <class ProblemT>
219class ProblemWithCounters : public ProblemT {
220 public:
221 ProblemWithCounters(ProblemT &&p) : ProblemT(std::move(p)) {
222 attach_counters(*this);
223 }
224 ProblemWithCounters(const ProblemT &p) : ProblemT(p) {
225 attach_counters(*this);
226 }
227
232
233 public:
234 std::shared_ptr<EvalCounter> evaluations = std::make_shared<EvalCounter>();
235
236 private:
238};
239
240template <class ProblemT>
243
244 const static auto timed = [](auto &time, const auto &f) -> decltype(f()) {
245 if constexpr (std::is_same_v<decltype(f()), void>) {
246 auto t0 = std::chrono::steady_clock::now();
247 f();
248 auto t1 = std::chrono::steady_clock::now();
249 time += t1 - t0;
250 } else {
251 auto t0 = std::chrono::steady_clock::now();
252 auto res = f();
253 auto t1 = std::chrono::steady_clock::now();
254 time += t1 - t0;
255 return res;
256 }
257 };
258
259 wc.f = [ev{wc.evaluations}, f{std::move(wc.f)}](crvec x) {
260 ++ev->f;
261 return timed(ev->time.f, [&] { return f(x); });
262 };
263 wc.grad_f = [ev{wc.evaluations}, grad_f{std::move(wc.grad_f)}](crvec x,
264 rvec grad) {
265 ++ev->grad_f;
266 timed(ev->time.grad_f, [&] { grad_f(x, grad); });
267 };
268 wc.g = [ev{wc.evaluations}, g{std::move(wc.g)}](crvec x, rvec gx) {
269 ++ev->g;
270 timed(ev->time.g, [&] { g(x, gx); });
271 };
272 wc.grad_g_prod = [ev{wc.evaluations},
273 grad_g_prod{std::move(wc.grad_g_prod)}](crvec x, crvec y,
274 rvec grad) {
275 ++ev->grad_g_prod;
276 timed(ev->time.grad_g_prod, [&] { grad_g_prod(x, y, grad); });
277 };
278 wc.grad_gi = [ev{wc.evaluations}, grad_gi{std::move(wc.grad_gi)}](
279 crvec x, unsigned i, rvec grad) {
280 ++ev->grad_g_prod;
281 timed(ev->time.grad_g_prod, [&] { grad_gi(x, i, grad); });
282 };
283 wc.hess_L_prod = [ev{wc.evaluations},
284 hess_L_prod{std::move(wc.hess_L_prod)}](
285 crvec x, crvec y, crvec v, rvec Hv) {
286 ++ev->hess_L_prod;
287 timed(ev->time.hess_L_prod, [&] { hess_L_prod(x, y, v, Hv); });
288 };
289 wc.hess_L = [ev{wc.evaluations},
290 hess_L{std::move(wc.hess_L)}](crvec x, crvec y, rmat H) {
291 ++ev->hess_L;
292 timed(ev->time.hess_L, [&] { hess_L(x, y, H); });
293 };
294}
295
300class ProblemOnlyD : public Problem {
301 public:
302 ProblemOnlyD(Problem &&p) : original(std::move(p)) { transform(); }
304
305 private:
306 Problem original; // TODO: Keeping this copy around is unnecessary.
308
309 void transform();
310};
311
312} // namespace pa
virtual void wrap(Problem &)=0
virtual ~ParamWrapper()=default
virtual std::shared_ptr< ParamWrapper > clone() const =0
Moves the state constraints in the set C to the set D, resulting in an unconstraint inner problem.
void transform()
Definition: problem.cpp:5
ProblemWithCounters(const ProblemWithCounters &)=delete
ProblemWithCounters & operator=(ProblemWithCounters &&)=default
std::shared_ptr< EvalCounter > evaluations
ProblemWithCounters(ProblemWithCounters &&)=default
ProblemWithCounters & operator=(const ProblemWithCounters &)=delete
static void attach_counters(ProblemWithCounters &)
std::shared_ptr< ParamWrapper > wrapper
ProblemWithParam & operator=(ProblemWithParam &&)=default
ProblemWithParam(const ProblemWithParam &o)
ProblemWithParam & operator=(const ProblemWithParam &o)
ProblemWithParam(ProblemWithParam &&)=default
H
Definition: main.py:8
Definition: alm.hpp:9
InnerStatsAccumulator< PANOCStats > & operator+=(InnerStatsAccumulator< PANOCStats > &acc, const PANOCStats &s)
Eigen::Ref< const vec > crvec
Default type for immutable references to vectors.
Definition: vec.hpp:18
constexpr real_t NaN
Not a number.
Definition: vec.hpp:28
constexpr real_t inf
Definition: vec.hpp:26
realvec vec
Default type for vectors.
Definition: vec.hpp:14
Eigen::Ref< mat > rmat
Default type for mutable references to matrices.
Definition: vec.hpp:22
double real_t
Default floating point type.
Definition: vec.hpp:8
EvalCounter operator+(EvalCounter a, const EvalCounter &b)
Eigen::Ref< vec > rvec
Default type for mutable references to vectors.
Definition: vec.hpp:16
Definition: box.hpp:7
hess_L_prod
Definition: test.py:66
grad_g_prod
Definition: test.py:54
struct pa::EvalCounter::EvalTimer time
Problem description for minimization problems.
Box C
Constraints of the decision variables, .
std::function< hess_L_sig > hess_L
Hessian of the Lagrangian function .
void(crvec x, crvec y, crvec v, rvec Hv) hess_L_prod_sig
Signature of the function that evaluates the Hessian of the Lagrangian multiplied by a vector .
std::function< f_sig > f
Cost function .
std::function< grad_gi_sig > grad_gi
Gradient of a specific constraint .
unsigned int m
Number of constraints, dimension of g(x) and z.
void(crvec x, rvec grad_fx) grad_f_sig
Signature of the function that evaluates the gradient of the cost function .
Problem(unsigned int n, unsigned int m)
Problem()=default
std::function< grad_f_sig > grad_f
Gradient of the cost function .
unsigned int n
Number of decision variables, dimension of x.
void(crvec x, unsigned i, rvec grad_gi) grad_gi_sig
Signature of the function that evaluates the gradient of one specific constraints .
std::function< hess_L_prod_sig > hess_L_prod
Hessian of the Lagrangian function times vector .
std::function< g_sig > g
Constraint function .
real_t(crvec x) f_sig
Signature of the function that evaluates the cost .
void(crvec x, crvec y, rmat H) hess_L_sig
Signature of the function that evaluates the Hessian of the Lagrangian .
Problem(unsigned n, unsigned int m, Box C, Box D, std::function< f_sig > f, std::function< grad_f_sig > grad_f, std::function< g_sig > g, std::function< grad_g_prod_sig > grad_g_prod, std::function< grad_gi_sig > grad_gi, std::function< hess_L_prod_sig > hess_L_prod, std::function< hess_L_sig > hess_L)
Box D
Other constraints, .
std::function< grad_g_prod_sig > grad_g_prod
Gradient of the constraint function times vector .
void(crvec x, crvec y, rvec grad_gxy) grad_g_prod_sig
Signature of the function that evaluates the gradient of the constraints times a vector .
void(crvec x, rvec gx) g_sig
Signature of the function that evaluates the constraints .