refactor leastsq into complexity

This commit is contained in:
Ismael 2016-05-25 22:57:52 +02:00
parent 087f0d3f1b
commit 2f61f8aee0
6 changed files with 86 additions and 116 deletions

View File

@ -1,7 +1,26 @@
// Copyright 2016 Ismael Jimenez Martinez. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Source project : https://github.com/ismaelJimenez/cpp.leastsq
// Adapted to be used with google benchmark
#ifndef COMPLEXITY_H_
#define COMPLEXITY_H_
#include <string>
#include <vector>
#include <functional>
namespace benchmark {
@ -19,24 +38,34 @@ enum BigO {
oAuto
};
inline std::string GetBigO(BigO complexity) {
switch (complexity) {
case oN:
return "* N";
case oNSquared:
return "* N**2";
case oNCubed:
return "* N**3";
case oLogN:
return "* lgN";
case oNLogN:
return "* NlgN";
case o1:
return "* 1";
default:
return "";
}
}
// This data structure will contain the result returned by MinimalLeastSq
// - coef : Estimated coeficient for the high-order term as
// interpolated from data.
// - rms : Normalized Root Mean Squared Error.
// - complexity : Scalability form (e.g. oN, oNLogN). In case a scalability
// form has been provided to MinimalLeastSq this will return
// the same value. In case BigO::oAuto has been selected, this
// parameter will return the best fitting curve detected.
struct LeastSq {
LeastSq() :
coef(0),
rms(0),
complexity(benchmark::oNone) {}
double coef;
double rms;
benchmark::BigO complexity;
};
// Function to to return an string for the calculated complexity
std::string GetBigOString(benchmark::BigO complexity);
// Find the coefficient for the high-order term in the running time, by
// minimizing the sum of squares of relative error.
LeastSq MinimalLeastSq(const std::vector<int>& n,
const std::vector<double>& time,
const benchmark::BigO complexity = benchmark::oAuto);
} // end namespace benchmark
#endif // COMPLEXITY_H_

View File

@ -5,7 +5,7 @@ include_directories(${PROJECT_SOURCE_DIR}/src)
set(SOURCE_FILES "benchmark.cc" "colorprint.cc" "commandlineflags.cc"
"console_reporter.cc" "csv_reporter.cc" "json_reporter.cc"
"log.cc" "reporter.cc" "sleep.cc" "string_util.cc"
"sysinfo.cc" "walltime.cc" "minimal_leastsq.cc")
"sysinfo.cc" "walltime.cc" "complexity.cc")
# Determine the correct regular expression engine to use
if(HAVE_STD_REGEX)
set(RE_FILES "re_std.cc")

View File

@ -15,43 +15,45 @@
// Source project : https://github.com/ismaelJimenez/cpp.leastsq
// Adapted to be used with google benchmark
#include "minimal_leastsq.h"
#include "benchmark/complexity.h"
#include "check.h"
#include <math.h>
namespace benchmark {
// Internal function to calculate the different scalability forms
std::function<double(int)> FittingCurve(benchmark::BigO complexity) {
std::function<double(int)> FittingCurve(BigO complexity) {
switch (complexity) {
case benchmark::oN:
case oN:
return [](int n) {return n; };
case benchmark::oNSquared:
case oNSquared:
return [](int n) {return n*n; };
case benchmark::oNCubed:
case oNCubed:
return [](int n) {return n*n*n; };
case benchmark::oLogN:
case oLogN:
return [](int n) {return log2(n); };
case benchmark::oNLogN:
case oNLogN:
return [](int n) {return n * log2(n); };
case benchmark::o1:
case o1:
default:
return [](int) {return 1; };
}
}
// Internal function to to return an string for the calculated complexity
std::string GetBigOString(benchmark::BigO complexity) {
// Function to to return an string for the calculated complexity
std::string GetBigOString(BigO complexity) {
switch (complexity) {
case benchmark::oN:
case oN:
return "* N";
case benchmark::oNSquared:
case oNSquared:
return "* N**2";
case benchmark::oNCubed:
case oNCubed:
return "* N**3";
case benchmark::oLogN:
case oLogN:
return "* lgN";
case benchmark::oNLogN:
case oNLogN:
return "* NlgN";
case benchmark::o1:
case o1:
return "* 1";
default:
return "";
@ -65,6 +67,16 @@ std::string GetBigOString(benchmark::BigO complexity) {
// For a deeper explanation on the algorithm logic, look the README file at
// http://github.com/ismaelJimenez/Minimal-Cpp-Least-Squared-Fit
// 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) {
@ -110,22 +122,20 @@ LeastSq CalculateLeastSq(const std::vector<int>& n,
// fitting curve.
LeastSq MinimalLeastSq(const std::vector<int>& n,
const std::vector<double>& time,
const benchmark::BigO complexity) {
const BigO complexity) {
CHECK_EQ(n.size(), time.size());
CHECK_GE(n.size(), 2); // Do not compute fitting curve is less than two benchmark runs are given
CHECK_NE(complexity, benchmark::oNone);
CHECK_NE(complexity, oNone);
LeastSq best_fit;
if(complexity == benchmark::oAuto) {
std::vector<benchmark::BigO> fit_curves = {
benchmark::oLogN, benchmark::oN, benchmark::oNLogN, benchmark::oNSquared,
benchmark::oNCubed };
if(complexity == oAuto) {
std::vector<BigO> fit_curves = {
oLogN, oN, oNLogN, oNSquared, oNCubed };
// Take o1 as default best fitting curve
best_fit = CalculateLeastSq(n, time, FittingCurve(benchmark::o1));
best_fit.complexity = benchmark::o1;
best_fit.caption = GetBigOString(benchmark::o1);
best_fit = CalculateLeastSq(n, time, FittingCurve(o1));
best_fit.complexity = o1;
// Compute all possible fitting curves and stick to the best one
for (const auto& fit : fit_curves) {
@ -133,14 +143,14 @@ LeastSq MinimalLeastSq(const std::vector<int>& n,
if (current_fit.rms < best_fit.rms) {
best_fit = current_fit;
best_fit.complexity = fit;
best_fit.caption = GetBigOString(fit);
}
}
} else {
best_fit = CalculateLeastSq(n, time, FittingCurve(complexity));
best_fit.complexity = complexity;
best_fit.caption = GetBigOString(complexity);
}
return best_fit;
}
} // end namespace benchmark

View File

@ -117,7 +117,7 @@ void ConsoleReporter::PrintRunData(const Run& result) {
name_field_width_, result.benchmark_name.c_str());
if(result.report_big_o) {
std::string big_o = result.report_big_o ? GetBigO(result.complexity) : "";
std::string big_o = result.report_big_o ? GetBigOString(result.complexity) : "";
ColorPrintf(COLOR_YELLOW, "%10.4f %s %10.4f %s ",
result.real_accumulated_time * multiplier,
big_o.c_str(),

View File

@ -1,68 +0,0 @@
// Copyright 2016 Ismael Jimenez Martinez. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Source project : https://github.com/ismaelJimenez/cpp.leastsq
// Adapted to be used with google benchmark
#if !defined(MINIMAL_LEASTSQ_H_)
#define MINIMAL_LEASTSQ_H_
#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
// interpolated from data.
// - rms : Normalized Root Mean Squared Error.
// - complexity : Scalability form (e.g. oN, oNLogN). In case a scalability
// form has been provided to MinimalLeastSq this will return
// the same value. In case BigO::oAuto has been selected, this
// parameter will return the best fitting curve detected.
struct LeastSq {
LeastSq() :
coef(0),
rms(0),
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
// minimizing the sum of squares of relative error.
LeastSq MinimalLeastSq(const std::vector<int>& n,
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

View File

@ -13,7 +13,6 @@
// limitations under the License.
#include "benchmark/reporter.h"
#include "minimal_leastsq.h"
#include <cstdlib>
#include <vector>