The examples we have seen until now are simple optimization problems with no data. The original purpose of least squares and non-linear least squares analysis was fitting curves to data. It is only appropriate that we now consider an example of such a problem\footnote{The full code and data for this example can be found in
\texttt{examples/data\_fitting.cc}. It contains data generated by sampling the curve $y = e^{0.3x +0.1}$ and adding Gaussian noise with standard deviation $\sigma=0.2$.}. Let us fit some data to the curve
\begin{equation}
y = e^{mx + c}.
\end{equation}
We begin by defining a templated object to evaluate the residual. There will be a residual for each observation.
\begin{minted}[mathescape]{c++}
class ExponentialResidual {
public:
ExponentialResidual(double x, double y)
: x_(x), y_(y) {}
template <typename T> bool operator()(const T* const m,
%\caption{Templated functor to compute the residual for the exponential model fitting problem. Note that one instance of the functor is responsible for computing the residual for one observation.}
%\label{listing:exponentialresidual}
%\end{listing}
Assuming the observations are in a $2n$ sized array called \texttt{data}, the problem construction is a simple matter of creating a \texttt{CostFunction} for every observation.
\clearpage
\begin{minted}{c++}
double m = 0.0;
double c = 0.0;
Problem problem;
for (int i = 0; i < kNumObservations; ++i) {
problem.AddResidualBlock(
new AutoDiffCostFunction<ExponentialResidual, 1, 1, 1>(
new ExponentialResidual(data[2 * i], data[2 * i + 1])),
NULL,
&m, &c);
}
\end{minted}
Compiling and running \texttt{data\_fitting.cc} gives us
Final cost: 1.056751e+00, Termination: FUNCTION_TOLERANCE.
Initial m: 0 c: 0
Final m: 0.291861 c: 0.131439
\end{minted}
\begin{figure}[t]
\begin{center}
\includegraphics[width=\textwidth]{fit.pdf}
\caption{Least squares data fitting to the curve $y = e^{0.3x +0.1}$. Observations were generated by sampling this curve uniformly in the interval $x=(0,5)$ and adding Gaussian noise with $\sigma=0.2$.\label{fig:exponential}}
\end{center}
\end{figure}
Starting from parameter values $m =0, c=0$ with an initial objective function value of $121.173$ Ceres finds a solution $m=0.291861, c =0.131439$ with an objective function value of $1.05675$. These values are a a bit different than the parameters of the original model $m=0.3, c=0.1$, but this is expected. When reconstructing a curve from noisy data, we expect to see such deviations. Indeed, if you were to evaluate the objective function for $m=0.3, c=0.1$, the fit is worse with an objective function value of 1.082425. Figure~\ref{fig:exponential} illustrates the fit.