ExplicitEquation::FitError ExplicitEquation::Fit(DataSource &series, double &r2) { r2 = 0; if (series.IsExplicit() || series.IsParam()) return InadequateDataSource; if (series.GetCount() < coeff.GetCount()) return SmallDataSource; ptrdiff_t numUnknowns = coeff.GetCount(); VectorXd x(numUnknowns); for (int i = 0; i < numUnknowns; ++i) x(i) = coeff[i]; Equation_functor functor; functor.series = &series; functor.fSource = this; functor.unknowns = numUnknowns; functor.datasetLen = series.GetCount(); NumericalDiff<Equation_functor> numDiff(functor); LevenbergMarquardt<NumericalDiff<Equation_functor> > lm(numDiff); // ftol is a nonnegative input variable that measures the relative error desired in the sum of squares lm.parameters.ftol = 1.E4*NumTraits<double>::epsilon(); // xtol is a nonnegative input variable that measures the relative error desired in the approximate solution lm.parameters.xtol = 1.E4*NumTraits<double>::epsilon(); lm.parameters.maxfev = maxFitFunctionEvaluations; int ret = lm.minimize(x); if (ret == LevenbergMarquardtSpace::ImproperInputParameters) return ExplicitEquation::ImproperInputParameters; if (ret == LevenbergMarquardtSpace::TooManyFunctionEvaluation) return TooManyFunctionEvaluation; double mean = series.AvgY(); double sse = 0, sst = 0; for (int64 i = 0; i < series.GetCount(); ++i) { double y = series.y(i); if (!IsNull(y)) { double res = y - f(series.x(i)); sse += res*res; double d = y - mean; sst += d*d; } } r2 = 1 - sse/sst; return NoError; }
ExplicitEquation::FitError SplineEquation::Fit(DataSource &data, double &r2) { Vector<Pointf> seriesRaw; for (int64 i = 0; i < data.GetCount(); ++i) { // Remove Nulls if (!IsNull(data.x(i)) && !IsNull(data.y(i))) seriesRaw << Pointf(data.x(i), data.y(i)); } if(seriesRaw.IsEmpty()) return InadequateDataSource; PointfLess less; Sort(seriesRaw, less); // Sort Vector<Pointf> series; for (int i = 1; i < seriesRaw.GetCount(); ++i) { // Remove points with duplicate x if (seriesRaw[i].x != seriesRaw[i - 1].x) series << seriesRaw[i]; } r2 = 0; int n = int(series.GetCount()) - 1; Buffer<double> h(n); for(int i = 0; i < n; ++i) h[i] = (series[i+1].x - series[i].x); Buffer<double> alpha(n); for(int i = 1; i < n; ++i) alpha[i] = (3.*(series[i+1].y - series[i].y)/h[i] - 3*(series[i].y - series[i-1].y)/h[i-1]); Buffer<double> c(n+1), l(n+1), mu(n+1), z(n+1); l[0] = 1; mu[0] = 0; z[0] = 0; for(int i = 1; i < n; ++i) { l[i] = 2.*(series[i+1].x - series[i-1].x) - h[i-1]*mu[i-1]; mu[i] = h[i]/l[i]; z[i] = (alpha[i] - h[i-1]*z[i-1])/l[i]; } l[n] = 1.; z[n] = 0; c[n] = 0; Buffer<double> b(n), d(n); for(int i = n-1; i >= 0; --i) { c[i] = z[i] - mu[i] * c[i+1]; b[i] = (series[i+1].y - series[i].y)/h[i] - h[i]*(c[i+1] + 2*c[i])/3.; d[i] = (c[i+1] - c[i])/3./h[i]; } ncoeff = n; coeff.Alloc(ncoeff); for(int i = 0; i < n; ++i) { coeff[i].x = series[i].x; coeff[i].a = series[i].y; coeff[i].b = b[i]; coeff[i].c = c[i]; coeff[i].d = d[i]; } return NoError; }