CMP++: Uncertainty Quantification & Bayesian Calibration
Loading...
Searching...
No Matches
optimization.h
Go to the documentation of this file.
1
6#pragma once
7
8#include <functional>
9#include <vector>
10#include <cmath>
11#include <Eigen/Dense>
12#include <nlopt.hpp>
13
18namespace cmp {
19
39 public:
40 // Gradient-free constructor
41 explicit ObjectiveFunctor(std::function<double(Eigen::Ref<const Eigen::VectorXd>)> fval)
42 : fval_only_(std::move(fval)), fval_grad_inplace_(nullptr), use_gradient_(false) {}
43
44 // Gradient-based constructor
45 explicit ObjectiveFunctor(std::function<double(Eigen::Ref<const Eigen::VectorXd>, Eigen::Ref<Eigen::VectorXd>)> fval_grad)
46 : fval_only_(nullptr), fval_grad_inplace_(std::move(fval_grad)), use_gradient_(true) {}
47
52 void setLogScale(const std::vector<bool>& log_scale) {
53 log_scale_ = log_scale;
54 }
55
56 const std::vector<bool>& getLogScale() const {
57 return log_scale_;
58 }
59
60 // Call operator evaluated by NLoptCallback
61 double operator()(Eigen::Ref<const Eigen::VectorXd> x_opt, Eigen::Ref<Eigen::VectorXd> grad_opt) const {
62 // 1. Transform optimizer-space parameters to physical real-space parameters
63 Eigen::VectorXd x_real = mapToReal(x_opt);
64
65 double val;
66 if(use_gradient_ && grad_opt.size() > 0) {
67 // 2. Evaluate the user's function with real parameters
68 val = fval_grad_inplace_(x_real, grad_opt);
69 // 3. Chain Rule: d/dx_opt = d/dx_real * dx_real/dx_opt
70 mapGradientToOpt(x_real, grad_opt);
71 } else if(use_gradient_) {
72 Eigen::VectorXd dummy_grad(x_opt.size());
73 val = fval_grad_inplace_(x_real, dummy_grad);
74 } else {
75 val = fval_only_(x_real);
76 }
77 return val;
78 }
79
80 // Static Callback for NLopt Objective
81 static double NLoptCallback(const std::vector<double> &x, std::vector<double> &grad, void *data) {
82 ObjectiveFunctor* functor = static_cast<ObjectiveFunctor*>(data);
83 Eigen::Map<const Eigen::VectorXd> x_eig(x.data(), x.size());
84 Eigen::Map<Eigen::VectorXd> grad_map(grad.data(), grad.size());
85 return (*functor)(x_eig, grad_map);
86 }
87
92 bool usesGradient() const {
93 return use_gradient_;
94 }
95
96 // --- Constraints Section ---
97 void addInequalityConstraint(std::function<double(Eigen::Ref<const Eigen::VectorXd>, Eigen::Ref<Eigen::VectorXd>)> g) {
98 ineq_constraints_.push_back(std::move(g));
99 }
100
101 void addEqualityConstraint(std::function<double(Eigen::Ref<const Eigen::VectorXd>, Eigen::Ref<Eigen::VectorXd>)> h) {
102 eq_constraints_.push_back(std::move(h));
103 }
104
113
114 // Unified static wrapper for evaluating constraints with log-scaling awareness
115 static double NLoptConstraintWrapper(const std::vector<double> &x, std::vector<double> &grad, void *data) {
116 ConstraintContext* ctx = static_cast<ConstraintContext*>(data);
117 Eigen::Map<const Eigen::VectorXd> x_opt(x.data(), x.size());
118 Eigen::Map<Eigen::VectorXd> grad_opt(grad.data(), grad.size());
119
120 return ctx->functor->evaluateConstraint(ctx->index, ctx->is_inequality, x_opt, grad_opt);
121 }
122
123 std::vector<std::function<double(Eigen::Ref<const Eigen::VectorXd>, Eigen::Ref<Eigen::VectorXd>)>> getInequalityConstraints() const {
124 return ineq_constraints_;
125 }
126
127 std::vector<std::function<double(Eigen::Ref<const Eigen::VectorXd>, Eigen::Ref<Eigen::VectorXd>)>> getEqualityConstraints() const {
128 return eq_constraints_;
129 }
130
131
132
133 private:
134 std::function<double(Eigen::Ref<const Eigen::VectorXd>)> fval_only_;
135 std::function<double(Eigen::Ref<const Eigen::VectorXd>, Eigen::Ref<Eigen::VectorXd>)> fval_grad_inplace_;
136
137 std::vector<std::function<double(Eigen::Ref<const Eigen::VectorXd>, Eigen::Ref<Eigen::VectorXd>)>> ineq_constraints_;
138 std::vector<std::function<double(Eigen::Ref<const Eigen::VectorXd>, Eigen::Ref<Eigen::VectorXd>)>> eq_constraints_;
139
141 std::vector<bool> log_scale_;
142
159 Eigen::VectorXd mapToReal(Eigen::Ref<const Eigen::VectorXd> x_opt) const {
160 if(log_scale_.empty()) return x_opt;
161 Eigen::VectorXd x_real = x_opt;
162 for(int i = 0; i < x_real.size(); ++i) {
163 if(i < (int)log_scale_.size() && log_scale_[i]) {
164 x_real(i) = std::exp(x_opt(i));
165 }
166 }
167 return x_real;
168 }
169
182 void mapGradientToOpt(Eigen::Ref<const Eigen::VectorXd> x_real, Eigen::Ref<Eigen::VectorXd> grad_real) const {
183 if(log_scale_.empty() || grad_real.size() == 0) return;
184 for(int i = 0; i < grad_real.size(); ++i) {
185 if(i < (int)log_scale_.size() && log_scale_[i]) {
186 // If x_real = exp(x_opt), then d(x_real)/d(x_opt) = exp(x_opt) = x_real
187 grad_real(i) = grad_real(i) * x_real(i);
188 }
189 }
190 }
191
201 double evaluateConstraint(size_t index, bool is_ineq, Eigen::Ref<const Eigen::VectorXd> x_opt, Eigen::Ref<Eigen::VectorXd> grad_opt) const {
202 Eigen::VectorXd x_real = mapToReal(x_opt);
203 double val = 0.0;
204
205 const auto& constraint_func = is_ineq ? ineq_constraints_[index] : eq_constraints_[index];
206
207 if(grad_opt.size() > 0) {
208 val = constraint_func(x_real, grad_opt);
209 mapGradientToOpt(x_real, grad_opt);
210 } else {
211 Eigen::VectorXd dummy_grad(x_opt.size());
212 val = constraint_func(x_real, dummy_grad);
213 }
214 return val;
215 }
216};
217
222double nlopt_max(cmp::ObjectiveFunctor &f, Eigen::Ref<Eigen::VectorXd> x0, const Eigen::Ref<const Eigen::VectorXd> &lb, const Eigen::Ref<const Eigen::VectorXd> &ub, nlopt::algorithm alg = nlopt::LN_SBPLX, double ftol_rel = 1e-6);
223
224} // namespace cmp
Functor wrapper for NLopt with automatic, transparent parameter space mapping (e.g....
Definition optimization.h:38
std::vector< std::function< double(Eigen::Ref< const Eigen::VectorXd >, Eigen::Ref< Eigen::VectorXd >)> > ineq_constraints_
Collection of inequality constraint functions.
Definition optimization.h:137
const std::vector< bool > & getLogScale() const
Definition optimization.h:56
std::function< double(Eigen::Ref< const Eigen::VectorXd >)> fval_only_
Pointer to a gradient-free objective function.
Definition optimization.h:134
ObjectiveFunctor(std::function< double(Eigen::Ref< const Eigen::VectorXd >, Eigen::Ref< Eigen::VectorXd >)> fval_grad)
Definition optimization.h:45
std::vector< bool > log_scale_
Mask indicating which parameter dimensions are optimized in log-scale.
Definition optimization.h:141
std::vector< std::function< double(Eigen::Ref< const Eigen::VectorXd >, Eigen::Ref< Eigen::VectorXd >)> > getInequalityConstraints() const
Definition optimization.h:123
void addEqualityConstraint(std::function< double(Eigen::Ref< const Eigen::VectorXd >, Eigen::Ref< Eigen::VectorXd >)> h)
Definition optimization.h:101
bool usesGradient() const
Checks if the functor utilizes gradient information.
Definition optimization.h:92
ObjectiveFunctor(std::function< double(Eigen::Ref< const Eigen::VectorXd >)> fval)
Definition optimization.h:41
void mapGradientToOpt(Eigen::Ref< const Eigen::VectorXd > x_real, Eigen::Ref< Eigen::VectorXd > grad_real) const
Transforms gradients from real space back to optimization space using the chain rule.
Definition optimization.h:182
bool use_gradient_
Flag indicating whether the objective function uses gradient information.
Definition optimization.h:140
std::vector< std::function< double(Eigen::Ref< const Eigen::VectorXd >, Eigen::Ref< Eigen::VectorXd >)> > getEqualityConstraints() const
Definition optimization.h:127
std::function< double(Eigen::Ref< const Eigen::VectorXd >, Eigen::Ref< Eigen::VectorXd >)> fval_grad_inplace_
Pointer to a gradient-based objective function.
Definition optimization.h:135
double operator()(Eigen::Ref< const Eigen::VectorXd > x_opt, Eigen::Ref< Eigen::VectorXd > grad_opt) const
Definition optimization.h:61
std::vector< std::function< double(Eigen::Ref< const Eigen::VectorXd >, Eigen::Ref< Eigen::VectorXd >)> > eq_constraints_
Collection of equality constraint functions.
Definition optimization.h:138
static double NLoptCallback(const std::vector< double > &x, std::vector< double > &grad, void *data)
Definition optimization.h:81
void setLogScale(const std::vector< bool > &log_scale)
Set which parameters should be optimized in log-space.
Definition optimization.h:52
double evaluateConstraint(size_t index, bool is_ineq, Eigen::Ref< const Eigen::VectorXd > x_opt, Eigen::Ref< Eigen::VectorXd > grad_opt) const
Evaluates a constraint while properly translating inputs and mapping output gradients.
Definition optimization.h:201
static double NLoptConstraintWrapper(const std::vector< double > &x, std::vector< double > &grad, void *data)
Definition optimization.h:115
void addInequalityConstraint(std::function< double(Eigen::Ref< const Eigen::VectorXd >, Eigen::Ref< Eigen::VectorXd >)> g)
Definition optimization.h:97
Eigen::VectorXd mapToReal(Eigen::Ref< const Eigen::VectorXd > x_opt) const
Maps parameters from optimization space (potentially log-scaled) to physical space.
Definition optimization.h:159
Definition classifier.h:17
double nlopt_max(cmp::ObjectiveFunctor &f, Eigen::Ref< Eigen::VectorXd > x0, const Eigen::Ref< const Eigen::VectorXd > &lb, const Eigen::Ref< const Eigen::VectorXd > &ub, nlopt::algorithm alg=nlopt::LN_SBPLX, double ftol_rel=1e-6)
Global helper function to execute NLopt maximization, managing the log-scaling wrapper....
Definition optimization.cpp:3
Context struct for NLopt constraint evaluation callback.
Definition optimization.h:108
size_t index
Index of the constraint in the vector.
Definition optimization.h:110
bool is_inequality
True if it is an inequality constraint, false if equality.
Definition optimization.h:111
ObjectiveFunctor * functor
Pointer to the parent functor.
Definition optimization.h:109