upgraded leastsq
diff --git a/src/minimal_leastsq.cc b/src/minimal_leastsq.cc
index 2a73887..d63e6f6 100644
--- a/src/minimal_leastsq.cc
+++ b/src/minimal_leastsq.cc
@@ -20,37 +20,54 @@
#include <math.h>
// Internal function to calculate the different scalability forms
-double FittingCurve(double n, benchmark::BigO complexity) {
+std::function<double(int)> FittingCurve(benchmark::BigO complexity) {
switch (complexity) {
- case benchmark::oN:
- return n;
- case benchmark::oNSquared:
- return pow(n, 2);
- case benchmark::oNCubed:
- return pow(n, 3);
- case benchmark::oLogN:
- return log2(n);
- case benchmark::oNLogN:
- return n * log2(n);
- case benchmark::o1:
- default:
- return 1;
+ case benchmark::oN:
+ return [](int n) {return n; };
+ case benchmark::oNSquared:
+ return [](int n) {return n*n; };
+ case benchmark::oNCubed:
+ return [](int n) {return n*n*n; };
+ case benchmark::oLogN:
+ return [](int n) {return log2(n); };
+ case benchmark::oNLogN:
+ return [](int n) {return n * log2(n); };
+ case benchmark::o1:
+ default:
+ return [](int) {return 1; };
}
}
-// Internal function to find the coefficient for the high-order term in the
-// running time, by minimizing the sum of squares of relative error.
-// - n : Vector containing the size of the benchmark tests.
-// - time : Vector containing the times for the benchmark tests.
-// - complexity : Fitting curve.
+// Internal function to to return an string for the calculated complexity
+std::string GetBigOString(benchmark::BigO complexity) {
+ switch (complexity) {
+ case benchmark::oN:
+ return "* N";
+ case benchmark::oNSquared:
+ return "* N**2";
+ case benchmark::oNCubed:
+ return "* N**3";
+ case benchmark::oLogN:
+ return "* lgN";
+ case benchmark::oNLogN:
+ return "* NlgN";
+ case benchmark::o1:
+ return "* 1";
+ default:
+ return "";
+ }
+}
+
+// Find the coefficient for the high-order term in the running time, by minimizing the sum of squares of relative error, for the fitting curve given on the lambda expresion.
+// - n : Vector containing the size of the benchmark tests.
+// - time : Vector containing the times for the benchmark tests.
+// - fitting_curve : lambda expresion (e.g. [](int n) {return n; };).
// For a deeper explanation on the algorithm logic, look the README file at
// http://github.com/ismaelJimenez/Minimal-Cpp-Least-Squared-Fit
-LeastSq CalculateLeastSq(const std::vector<int>& n,
- const std::vector<double>& time,
- const benchmark::BigO complexity) {
- CHECK_NE(complexity, benchmark::oAuto);
-
+LeastSq CalculateLeastSq(const std::vector<int>& n,
+ const std::vector<double>& time,
+ std::function<double(int)> fitting_curve) {
double sigma_gn = 0;
double sigma_gn_squared = 0;
double sigma_time = 0;
@@ -58,7 +75,7 @@
// Calculate least square fitting parameter
for (size_t i = 0; i < n.size(); ++i) {
- double gn_i = FittingCurve(n[i], complexity);
+ double gn_i = fitting_curve(n[i]);
sigma_gn += gn_i;
sigma_gn_squared += gn_i * gn_i;
sigma_time += time[i];
@@ -66,26 +83,19 @@
}
LeastSq result;
- result.complexity = complexity;
// Calculate complexity.
- // o1 is treated as an special case
- if (complexity != benchmark::o1) {
- result.coef = sigma_time_gn / sigma_gn_squared;
- } else {
- result.coef = sigma_time / n.size();
- }
+ result.coef = sigma_time_gn / sigma_gn_squared;
// Calculate RMS
double rms = 0;
for (size_t i = 0; i < n.size(); ++i) {
- double fit = result.coef * FittingCurve(n[i], complexity);
+ double fit = result.coef * fitting_curve(n[i]);
rms += pow((time[i] - fit), 2);
}
- double mean = sigma_time / n.size();
-
// Normalized RMS by the mean of the observed values
+ double mean = sigma_time / n.size();
result.rms = sqrt(rms / n.size()) / mean;
return result;
@@ -105,24 +115,32 @@
CHECK_GE(n.size(), 2); // Do not compute fitting curve is less than two benchmark runs are given
CHECK_NE(complexity, benchmark::oNone);
+ LeastSq best_fit;
+
if(complexity == benchmark::oAuto) {
std::vector<benchmark::BigO> fit_curves = {
benchmark::oLogN, benchmark::oN, benchmark::oNLogN, benchmark::oNSquared,
benchmark::oNCubed };
// Take o1 as default best fitting curve
- LeastSq best_fit = CalculateLeastSq(n, time, benchmark::o1);
+ best_fit = CalculateLeastSq(n, time, FittingCurve(benchmark::o1));
+ best_fit.complexity = benchmark::o1;
+ best_fit.caption = GetBigOString(benchmark::o1);
// Compute all possible fitting curves and stick to the best one
for (const auto& fit : fit_curves) {
- LeastSq current_fit = CalculateLeastSq(n, time, fit);
+ LeastSq current_fit = CalculateLeastSq(n, time, FittingCurve(fit));
if (current_fit.rms < best_fit.rms) {
best_fit = current_fit;
+ best_fit.complexity = fit;
+ best_fit.caption = GetBigOString(fit);
}
}
-
- return best_fit;
+ } else {
+ best_fit = CalculateLeastSq(n, time, FittingCurve(complexity));
+ best_fit.complexity = complexity;
+ best_fit.caption = GetBigOString(complexity);
}
- return CalculateLeastSq(n, time, complexity);
+ return best_fit;
}
diff --git a/src/minimal_leastsq.h b/src/minimal_leastsq.h
index 0dc12b7..ee49ec9 100644
--- a/src/minimal_leastsq.h
+++ b/src/minimal_leastsq.h
@@ -21,6 +21,7 @@
#include "benchmark/benchmark_api.h"
#include <vector>
+#include <functional>
// This data structure will contain the result returned by MinimalLeastSq
// - coef : Estimated coeficient for the high-order term as
@@ -35,11 +36,13 @@
LeastSq() :
coef(0),
rms(0),
- complexity(benchmark::oNone) {}
+ complexity(benchmark::oNone),
+ caption("") {}
double coef;
double rms;
benchmark::BigO complexity;
+ std::string caption;
};
// Find the coefficient for the high-order term in the running time, by
@@ -48,4 +51,18 @@
const std::vector<double>& time,
const benchmark::BigO complexity = benchmark::oAuto);
+// This interface is currently not used from the oustide, but it has been provided
+// for future upgrades. If in the future it is not needed to support Cxx03, then
+// all the calculations could be upgraded to use lambdas because they are more
+// powerful and provide a cleaner inferface than enumerators, but complete
+// implementation with lambdas will not work for Cxx03 (e.g. lack of std::function).
+// In case lambdas are implemented, the interface would be like :
+// -> Complexity([](int n) {return n;};)
+// and any arbitrary and valid equation would be allowed, but the option to calculate
+// the best fit to the most common scalability curves will still be kept.
+LeastSq CalculateLeastSq(const std::vector<int>& n,
+ const std::vector<double>& time,
+ std::function<double(int)> fitting_curve);
+
+
#endif