/
quadratic_fit.cpp
147 lines (114 loc) · 3.57 KB
/
quadratic_fit.cpp
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
/// Inputs : [ (x0,y0), (x1,y1), .... ].
// The loss-function is going to be the usual square-error. Which we try to minimize.
/// Will fit a non linear function.
#include <iostream>
#include <Eigen/Core>
using namespace std;
using namespace Eigen;
#include <ceres/ceres.h>
using namespace ceres;
#include "utilities.h"
class ResidueCallback: public ceres::IterationCallback {
public:
ResidueCallback( double * _params) {
params = _params;
}
virtual ceres::CallbackReturnType operator()( const ceres::IterationSummary& summary )
{
cout << summary.iteration << " cost=" << summary.cost << endl;
printMatrix1d( "itr"+to_string(summary.iteration)+".txt", params, 3 );
return ceres::SOLVER_CONTINUE;
}
private:
double * params;
};
// Quadratic Least Squares Residue
class LeastSquaresResidueQ {
public:
LeastSquaresResidueQ( double x, double y ) { this->x = x; this->y = y;}
template <typename T>
bool operator()( const T* const params , T* residual ) const {
T a = params[0];
T b = params[1];
T c = params[2];
residual[0] = y - (a*x*x + b*x + c);
return true;
}
static ceres::CostFunction* Create(double _x, double _y)
{
return ( new ceres::AutoDiffCostFunction<LeastSquaresResidueQ,1,3>
(
new LeastSquaresResidueQ(_x,_y)
)
);
}
private:
double x, y;
};
// Quadratic Least Squares Residue with switching constraints. (Is able to identify outliers)
class LeastSquaresResidueQSwitchingConstraint {
public:
LeastSquaresResidueQSwitchingConstraint( double x, double y ) { this->x = x; this->y = y;}
template <typename T>
bool operator()( const T* const params , const T* const s, T* residual ) const {
T a = params[0];
T b = params[1];
T c = params[2];
residual[0] = s[0] * ( y - (a*x*x + b*x + c) );
residual[1] = T(10.) * (T(1.0) - s[0]);
return true;
}
static ceres::CostFunction* Create(double _x, double _y)
{
return ( new ceres::AutoDiffCostFunction<LeastSquaresResidueQSwitchingConstraint,2,3,1>
(
new LeastSquaresResidueQSwitchingConstraint(_x,_y)
)
);
}
private:
double x, y;
};
int main()
{
//
// Generate Data
MatrixXd M;
generate_quadratic_data( M );
printEigenMatrix( "M.txt", M);
//
// Initial Guess
double param[3] = {5.,7.,1.0};
cout << "initial estimates\n";
printMatrix1d( "init.txt", param, 3 );
double * switches = new double[M.rows()];
for( int i=0 ; i< M.rows() ; i++ ) switches[i] = 1.0;
//
// Setup Residue terms
ceres::Problem problem;
int NQ = M.rows() ;
for( int i=0 ; i<NQ ; i++ )
{
CostFunction* cost_function = LeastSquaresResidueQ::Create( M(i,0), M(i,1) );
problem.AddResidualBlock( cost_function, NULL, param );
// problem.AddResidualBlock( cost_function, new ceres::CauchyLoss(.01), param );
// CostFunction* cost_function = LeastSquaresResidueQSwitchingConstraint::Create( M(i,0), M(i,1) );
// problem.AddResidualBlock( cost_function, NULL, param, &switches[i] );
// problem.AddResidualBlock( cost_function, new ceres::CauchyLoss(.01), param, &switches[i] );
}
//
// Run
Solver::Options options;
options.minimizer_progress_to_stdout = false;
Solver::Summary summary;
// Call back
ResidueCallback callback(param);
options.callbacks.push_back(&callback);
options.update_state_every_iteration = true;
ceres::Solve(options, &problem, &summary);
std::cout << summary.BriefReport() << "\n";
cout << "final_estimates\n";
printMatrix1d( "final.txt", param, 3 );
printMatrix1d( "switches.txt", switches, M.rows() );
delete [] switches;
}