From aac0b98ba908bf3618842b66d973db7693700e13 Mon Sep 17 00:00:00 2001 From: swaits Date: Fri, 10 Aug 2007 23:43:15 +0000 Subject: [PATCH] renamed DE::Engine::CalculateError to DE::Engine::TestFitness added ErrorAccumulator to aid in calculating RMSE converted piecewiseapprox.cpp and polyapprox.cpp to use new pure virtual method name and ErrorAccumulator --- de.h | 25 +++++++++++++++++++++- de.inl | 52 ++++++++++++++++++++++++++++++++++++++++++++- piecewiseapprox.cpp | 24 +++++++-------------- polyapprox.cpp | 24 +++++++-------------- 4 files changed, 91 insertions(+), 34 deletions(-) diff --git a/de.h b/de.h index 1d4c767..7a04154 100644 --- a/de.h +++ b/de.h @@ -23,12 +23,35 @@ namespace DE void SetRange(unsigned int i, double minimum, double maximum); void SetRange(const Vector& minimum, const Vector& maximum); - virtual double CalculateError(const double testcase[DIM], bool& stop) = 0; + virtual double TestFitness(const double testcase[DIM], bool& stop) = 0; void Reset(); bool Solve(unsigned int maxgenerations = 1000000000); bool RunOneGeneration(); + public: + + // helper class for accumulating error and calculating + // root mean square error + class ErrorAccumulator + { + public: + ErrorAccumulator(); + virtual ~ErrorAccumulator(); + + void Clear(); + void AddTestCase(double expected, double actual); + double GetRMSE(); + + private: + + void CalculateError(); + + unsigned int num_tests; // # of test cases + double sum_error_squared; // sum of error^2 + double error_rmse; // root mean square error (-1 == "dirty" flag) + }; + private: // randomly select unique individuals diff --git a/de.inl b/de.inl index de8577d..8ddbab2 100644 --- a/de.inl +++ b/de.inl @@ -207,7 +207,7 @@ bool DE::Engine::RunOneGeneration() MakeTrial_randtobest1exp(candidate,trial); // determine fitness of trial individual - double trialfitness = CalculateError(trial,success); + double trialfitness = TestFitness(trial,success); // see if the trial improved current candidate in population if ( trialfitness < fitness[candidate] ) @@ -448,5 +448,55 @@ inline void DE::Engine::MakeTrial_rand2bin(unsigned int candidate, return; } + + + +template +inline DE::Engine::ErrorAccumulator::ErrorAccumulator() +{ + Clear(); +} + +template +inline DE::Engine::ErrorAccumulator::~ErrorAccumulator() +{ + // empty +} + +template +inline void DE::Engine::ErrorAccumulator::Clear() +{ + num_tests = 0; + sum_error_squared = 0.0; + error_rmse = 0.0; // initial error == zero +} + +template +inline void DE::Engine::ErrorAccumulator::AddTestCase(double expected, double actual) +{ + double e = expected - actual; // compute error + sum_error_squared += e * e; // add to sum of error^2 + num_tests += 1; // increment total test count + error_rmse = -1.0; // mark as dirty +} + +template +inline double DE::Engine::ErrorAccumulator::GetRMSE() +{ + if ( error_rmse < 0.0 ) // recalculate if set to "dirty" + CalculateError(); + + return error_rmse; +} + +template +inline void DE::Engine::ErrorAccumulator::CalculateError() +{ + // convert squared error to root mean squared error + error_rmse = sqrt(sum_error_squared / (double)num_tests); +} + + + #endif // __de_inl__ diff --git a/piecewiseapprox.cpp b/piecewiseapprox.cpp index f4b77ee..e8ab94f 100644 --- a/piecewiseapprox.cpp +++ b/piecewiseapprox.cpp @@ -39,37 +39,29 @@ class PolySearch: public DE::Engine { public: // this method is called by the DE::Engine::Solve() to test a single DE individual - double CalculateError(const double testcase[NUM_COEFFICIENTS], bool& stop) + double TestFitness(const double testcase[NUM_COEFFICIENTS], bool& stop) { - double error = 0.0; - unsigned int test_count = 0; + ErrorAccumulator e; // accumulate squared error for ( double i=-2.5;i<=2.5;i+=0.01 ) { // test - double test = CalculatePiecewise(i,NUM_COEFFICIENTS,testcase); - double actual = TargetFunction(i); + double actual = CalculatePiecewise(i,NUM_COEFFICIENTS,testcase); + double expected = TargetFunction(i); - // accumulate error^2 - double e = test - actual; - error += e * e; - - // inc test count (divisor to get from SE to MSE) - test_count++; + // accumulate error + e.AddTestCase(expected,actual); } - // convert SE to RMSE - error = sqrt(error / (double)test_count); - // set stop flag if the error is really low - if ( error < 0.0000001 ) + if ( e.GetRMSE() < 0.0000001 ) { stop = true; } // done - return error; + return e.GetRMSE(); } }; diff --git a/polyapprox.cpp b/polyapprox.cpp index 4316e29..ef03923 100644 --- a/polyapprox.cpp +++ b/polyapprox.cpp @@ -39,37 +39,29 @@ class PolySearch: public DE::Engine { public: // this method is called by the DE::Engine::Solve() to test a single DE individual - double CalculateError(const double testcase[NUM_COEFFICIENTS], bool& stop) + double TestFitness(const double testcase[NUM_COEFFICIENTS], bool& stop) { - double error = 0.0; - unsigned int test_count = 0; + ErrorAccumulator e; // accumulate squared error for ( double i=-1.25;i<=1.25;i+=0.001 ) { // test - double test = CalculatePolynomial(i,NUM_COEFFICIENTS,testcase); - double actual = TargetFunction(i); + double actual = CalculatePolynomial(i,NUM_COEFFICIENTS,testcase); + double expected = TargetFunction(i); - // accumulate error^2 - double e = test - actual; - error += e * e; - - // inc test count (divisor to get from SE to MSE) - test_count++; + // accumulate error + e.AddTestCase(expected, actual); } - // convert SE to RMSE - error = sqrt(error / (double)test_count); - // set stop flag if the error is really low - if ( error < 0.0000001 ) + if ( e.GetRMSE() < 0.0000001 ) { stop = true; } // done - return error; + return e.GetRMSE(); } };