Citlali
Loading...
Searching...
No Matches
gauss_models.h
Go to the documentation of this file.
1#pragma once
2
3#include <ceres/ceres.h>
4#include <Eigen/Core>
5
7
8namespace engine_utils {
9
10template <typename Model>
11typename std::enable_if<Model::DimensionsAtCompileTime == 2, Model>::type
12create_model(const Eigen::VectorXd& params) {
13 Model g(params);
14 return g;
15}
16
17// a general functor, assuming X inputs and Y outputs
18template <typename _Scalar, int NX=Eigen::Dynamic, int NY=Eigen::Dynamic>
20 enum {
23 };
24
25 using Scalar = _Scalar;
26 using InputType = Eigen::Matrix<Scalar,InputsAtCompileTime, 1>;
27 using ValueType = Eigen::Matrix<Scalar,ValuesAtCompileTime, 1>;
28
29 constexpr static std::string_view name = "functor";
31 // default
33
34 int inputs() const { return m_inputs; }
35 int values() const { return m_values; }
36
38
39 template<typename OStream>
40 friend OStream &operator<<(OStream &os, const Self& f) {
41 return os << f.name << "<" << static_cast<int>(Self::InputsAtCompileTime) << ", " << static_cast<int>(Self::ValuesAtCompileTime) << ">(" << f.inputs() << ", " << f.values() << ")";
42 }
43
44protected:
47};
48
49
50// Model is a functor working on double (do we need model of other types?)
51// NP -- number of input parameters
52// ND -- number of demensions of input data
53template <int NP=Eigen::Dynamic, int ND=Eigen::Dynamic>
54struct Model: DenseFunctor<double, NP, Eigen::Dynamic> {
55 enum {
57 };
59 using DataType = Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>;
60 using InputDataType = Eigen::Matrix<double, Eigen::Dynamic, ND>;
61 using InputDataBasisType = Eigen::Matrix<double, Eigen::Dynamic, 1>;
62
63 constexpr static std::string_view name = "model";
64 // via known size of params
65 Model(int inputs): _Base(inputs, Eigen::Dynamic), params(inputs) {
66 }
67 // via copy of params
68 Model(const typename _Base::InputType& params): Model(static_cast<int>(params.size())) {this->params=params;}
69 // via initializer list of params
70 Model(std::initializer_list<double> params): Model(static_cast<int>(params.size())) {
71 int i = 0;
72 for (auto& p: params) {
73 this->params(i) = p;
74 ++i;
75 }
76 }
77 // default
79
81
82 // eval()
83 // should be defined to take (ndata, ndim) mesh and return vector of (ndata, 1)
84
85 // meshgrid()
86 // maybe be defined to convert input of (ndata_dim1, ... ndata_dimn) to (ndata, ndim) mesh
87
88 // operator()
89 // cound be defined to perform eval in nd shapes
90
91 // using DataType = ValueType;
92 // cound be defined to make it semantically clear for what data type it works with
93
94 template <typename T=InputDataType>
95 typename std::enable_if<ND == 2, T>::type meshgrid(const InputDataBasisType& x, const InputDataBasisType& y) const {
96 // column major
97 // [x0, y0,] [x1, y0] [x2, y0] ... [xn, y0] [x0, y1] ... [xn, yn]
98 const long nx = x.size(), ny = y.size();
99 InputDataType xy(nx * ny, 2);
100 // map xx [ny, nx] to the first column of xy
101 Eigen::Map<Eigen::MatrixXd> xx(xy.data(), ny, nx);
102 // map yy [ny, nx] to the second column of xy
103 Eigen::Map<Eigen::MatrixXd> yy(xy.data() + xy.rows(), ny, nx);
104 // populate xx such that each row is x
105 for (Eigen::Index i = 0; i < ny; ++i) {
106 xx.row(i) = x.transpose();
107 }
108 // populate yy such that each col is y
109 for (Eigen::Index j = 0; j < nx; ++j) {
110 yy.col(j) = y;
111 }
112 return xy;
113 }
114
115 typename Model::InputType transform(const typename Model::InputType& p) const {
116 return p;
117 }
118 typename Model::InputType inverseTransform(const typename Model::InputType& p) const {
119 return p;
120 }
121
122 struct Parameter {
123 std::string name = "unnammed";
124 bool fixed = false;
125 bool bounded = false;
126 double lower = - std::numeric_limits<double>::infinity();
127 double upper = std::numeric_limits<double>::infinity();
128 };
129};
130
131// 3 params, 1 dim
132struct Gaussian1D: Model<3, 1> {
133 constexpr static std::string_view name = "gaussian1d";
134 using Model<3, 1>::Model; // model constructors
135 Gaussian1D(double amplitude=1., double mean=0., double stddev=1.);
136
137 ValueType eval(const InputType& p, const InputDataType& x) const;
138 // no meshgrid needed here
139
140 // convinient methods
141 ValueType operator() (const InputType& p, const InputDataType& x) const;
143 std::vector<Parameter> param_settings{
144 {"amplitude"},
145 {"mean"},
146 {"stddev"},
147 };
148};
149
150struct Gaussian2D: Model<6, 2> {
151 constexpr static std::string_view name = "gaussian2d";
152 using Model<6, 2>::Model;
153 Gaussian2D(double amplitude=1., double xmean=0., double ymean=0., double xstddev=1., double ystddev=1., double theta=0.);
155
156 // operates on meshgrid xy of shape (ny * nx, 2), return a flat vector
157 ValueType eval(const InputType& p, const InputDataType& xy) const;
158
159 // convinient methods
160 // operates on x and y coords separately. return a (ny, nx) Eigen::Matrix
162 const InputType& p,
163 const InputDataBasisType& x,
164 const InputDataBasisType& y) const;
166 const InputDataBasisType& x,
167 const InputDataBasisType& y) const;
168
169 InputType transform(const InputType& p) const;
170 InputType inverseTransform(const InputType& p) const;
171 std::vector<Parameter> param_settings {
172 {"amplitude"},
173 {"xmean"},
174 {"ymean"},
175 {"xstddev"},
176 {"ystddev"},
177 {"theta"},
178 };
179};
180
182 constexpr static std::string_view name = "symmetricgaussian2d";
183 using Model<4, 2>::Model; // model constructors;
184 SymmetricGaussian2D(double amplitude=1., double xmean=0., double ymean=0., double stddev=1.);
186
187 // operates on meshgrid xy of shape (ny * nx, 2), return a flat vector
188 ValueType eval(const InputType& p, const InputDataType& xy) const;
189
190 // convinient methods
191 // operates on x and y coords separately. return a (ny, nx) Eigen::Matrix
193 const InputType& p,
194 const InputDataBasisType& x,
195 const InputDataBasisType& y) const;
197 const InputDataBasisType& x,
198 const InputDataBasisType& y) const;
199 std::vector<Parameter> param_settings{
200 {"amplitude"},
201 {"xmean"},
202 {"ymean"},
203 {"stddev"},
204 };
205};
206
207// Fitter is a functor that matches the data types of the Model.
208// Fitter relies on the eval() method
209template <typename _Model>
210struct Fitter: _Model::_Base {
211 using _Base = typename _Model::_Base;
212 using Model = _Model;
213
214 Fitter (const Model* model, int values): _Base(model->inputs(), values), m_model(model) {
215 }
216 Fitter (const Model* model): Fitter(model, Fitter::InputsAtCompileTime) {}
217
218 const Model* model() const {return m_model;}
219
220 const Eigen::Map<const typename Model::InputDataType>* xdata = nullptr; // set via meshgrid
221 const Eigen::Map<const typename Fitter::ValueType>* ydata = nullptr;
222 const Eigen::Map<const typename Fitter::ValueType>* sigma = nullptr;
223
224 // int operator()(const InputType &x, ValueType& fvec) { }
225 // should be defined in derived classes
226
227private:
228 const Model* m_model = nullptr;
229};
230
231using ceres::AutoDiffCostFunction;
232using ceres::CostFunction;
233using ceres::CauchyLoss;
234using ceres::Problem;
235using ceres::Solve;
236using ceres::Solver;
237using ceres::Covariance;
238
239// CeresAutoDiff Fitter provides concrete method for least-square minimization using ceres
240template <typename Model>
243 // the base constructors
244 using _Base::_Base;
245
246 template <typename T>
247 bool operator()(const T* const p, T* r) const {
248 auto cost2 = cos(p[5]) * cos(p[5]);
249 auto sint2 = sin(p[5]) * sin(p[5]);
250 auto sin2t = sin(2. * p[5]);
251 auto xstd2 = p[3] * p[3];
252 auto ystd2 = p[4] * p[4];
253 auto a = - 0.5 * ((cost2 / xstd2) + (sint2 / ystd2));
254 auto b = - 0.5 * ((sin2t / xstd2) - (sin2t / ystd2));
255 auto c = - 0.5 * ((sint2 / xstd2) + (cost2 / ystd2));
256
257 for (int i=0; i < this->values(); ++i){
258 if (this->sigma->coeffRef(i) != 0) {
259 r[i] = (
260 this->ydata->coeffRef(i) -
261 p[0] * exp(
262 pow(this->xdata->coeffRef(i, 0) - p[1], 2) * a +
263 (this->xdata->coeffRef(i, 0) - p[1]) * (this->xdata->coeffRef(i, 1) - p[2]) * b +
264 pow(this->xdata->coeffRef(i, 1) - p[2], 2) * c
265 )
266 ) / this->sigma->coeffRef(i);
267 }
268 // remove zero weights
269 else {
270 r[i] = (
271 this->ydata->coeffRef(i) -
272 p[0] * exp(
273 pow(this->xdata->coeffRef(i, 0) - p[1], 2) * a +
274 (this->xdata->coeffRef(i, 0) - p[1]) * (this->xdata->coeffRef(i, 1) - p[2]) * b +
275 pow(this->xdata->coeffRef(i, 1) - p[2], 2) * c
276 )
277 ) * this->sigma->coeffRef(i);
278 }
279 }
280 return true;
281 }
282
283 std::shared_ptr<Problem> createProblem(double* params) {
284 std::shared_ptr<Problem> problem = std::make_shared<Problem>();
285 problem->AddParameterBlock(params, this->model()->params.size());
286 return problem;
287 }
288};
289
290} // namespace engine_utils
Definition fitting.h:11
std::enable_if< Model::DimensionsAtCompileTime==2, Model >::type create_model(const Eigen::VectorXd &params)
Definition gauss_models.h:12
Definition gauss_models.h:241
std::shared_ptr< Problem > createProblem(double *params)
Definition gauss_models.h:283
bool operator()(const T *const p, T *r) const
Definition gauss_models.h:247
Definition gauss_models.h:19
int values() const
Definition gauss_models.h:35
int m_inputs
Definition gauss_models.h:45
int m_values
Definition gauss_models.h:46
friend OStream & operator<<(OStream &os, const Self &f)
Definition gauss_models.h:40
DenseFunctor(int inputs, int values)
Definition gauss_models.h:30
Eigen::Matrix< Scalar, InputsAtCompileTime, 1 > InputType
Definition gauss_models.h:26
static constexpr std::string_view name
Definition gauss_models.h:29
Eigen::Matrix< Scalar, ValuesAtCompileTime, 1 > ValueType
Definition gauss_models.h:27
_Scalar Scalar
Definition gauss_models.h:25
DenseFunctor()
Definition gauss_models.h:32
@ InputsAtCompileTime
Definition gauss_models.h:21
@ ValuesAtCompileTime
Definition gauss_models.h:22
int inputs() const
Definition gauss_models.h:34
Definition gauss_models.h:210
_Model Model
Definition gauss_models.h:212
const Model * m_model
Definition gauss_models.h:228
Fitter(const Model *model, int values)
Definition gauss_models.h:214
const Eigen::Map< const typename Fitter::ValueType > * sigma
Definition gauss_models.h:222
typename _Model::_Base _Base
Definition gauss_models.h:211
const Model * model() const
Definition gauss_models.h:218
const Eigen::Map< const typename Fitter::ValueType > * ydata
Definition gauss_models.h:221
const Eigen::Map< const typename Model::InputDataType > * xdata
Definition gauss_models.h:220
Fitter(const Model *model)
Definition gauss_models.h:216
Definition gauss_models.h:132
ValueType operator()(const InputType &p, const InputDataType &x) const
static constexpr std::string_view name
Definition gauss_models.h:133
ValueType eval(const InputType &p, const InputDataType &x) const
Definition gauss_models.cpp:12
std::vector< Parameter > param_settings
Definition gauss_models.h:143
Definition gauss_models.h:150
InputType inverseTransform(const InputType &p) const
Definition gauss_models.cpp:69
static constexpr std::string_view name
Definition gauss_models.h:151
InputType transform(const InputType &p) const
Definition gauss_models.cpp:60
ValueType eval(const InputType &p, const InputDataType &xy) const
Definition gauss_models.cpp:30
DataType operator()(const InputType &p, const InputDataBasisType &x, const InputDataBasisType &y) const
std::vector< Parameter > param_settings
Definition gauss_models.h:171
~Gaussian2D()
Definition gauss_models.h:154
Definition gauss_models.h:122
double lower
Definition gauss_models.h:126
double upper
Definition gauss_models.h:127
bool fixed
Definition gauss_models.h:124
std::string name
Definition gauss_models.h:123
bool bounded
Definition gauss_models.h:125
Definition gauss_models.h:54
Model::InputType params
Definition gauss_models.h:80
std::enable_if< ND==2, T >::type meshgrid(const InputDataBasisType &x, const InputDataBasisType &y) const
Definition gauss_models.h:95
Model(int inputs)
Definition gauss_models.h:65
static constexpr std::string_view name
Definition gauss_models.h:63
Model(const typename _Base::InputType &params)
Definition gauss_models.h:68
@ DimensionsAtCompileTime
Definition gauss_models.h:56
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic > DataType
Definition gauss_models.h:59
Model::InputType inverseTransform(const typename Model::InputType &p) const
Definition gauss_models.h:118
Model::InputType transform(const typename Model::InputType &p) const
Definition gauss_models.h:115
Eigen::Matrix< double, Eigen::Dynamic, ND > InputDataType
Definition gauss_models.h:60
Eigen::Matrix< double, Eigen::Dynamic, 1 > InputDataBasisType
Definition gauss_models.h:61
Model(std::initializer_list< double > params)
Definition gauss_models.h:70
Model()
Definition gauss_models.h:78
Definition gauss_models.h:181
ValueType eval(const InputType &p, const InputDataType &xy) const
Definition gauss_models.cpp:81
~SymmetricGaussian2D()
Definition gauss_models.h:185
DataType operator()(const InputType &p, const InputDataBasisType &x, const InputDataBasisType &y) const
static constexpr std::string_view name
Definition gauss_models.h:182
std::vector< Parameter > param_settings
Definition gauss_models.h:199