#include #include #include #include #include #include "real_value.h" class RankingTest { public: RankingTest(eoParser &parser, eoEvalFuncCounter> &_eval, unsigned size = 100) : rng(0), popSize(size), seedParam(parser.createParam(uint32_t(time(0)), "seed", "Random seed", 'S')), pressureParam(parser.createParam(1.5, "pressure", "Selective pressure", 'p')), exponentParam(parser.createParam(1.0, "exponent", "Ranking exponent", 'e')), eval(_eval) { rng.reseed(seedParam.value()); initPopulation(); } void initPopulation() { pop.clear(); for (unsigned i = 0; i < popSize; ++i) { eoReal ind; ind.resize(1); ind[0] = rng.uniform(); pop.push_back(ind); } apply>(eval, pop); } const unsigned popSize; eoPop> pop; eoRng rng; double pressure() const { return pressureParam.value(); } double exponent() const { return exponentParam.value(); } private: eoValueParam &seedParam; eoValueParam &pressureParam; eoValueParam &exponentParam; eoEvalFuncCounter> eval; }; // Test case 1: Verify both implementations produce identical results void test_Consistency(eoParser &parser) { eoEvalFuncPtr, double, const std::vector &> mainEval(real_value); eoEvalFuncCounter> eval(mainEval); RankingTest fixture(parser, eval); eoRanking> ranking(fixture.pressure(), fixture.exponent()); eoRankingCached> rankingCached(fixture.pressure(), fixture.exponent()); ranking(fixture.pop); rankingCached(fixture.pop); const std::vector &values = ranking.value(); const std::vector &cachedValues = rankingCached.value(); for (unsigned i = 0; i < fixture.pop.size(); ++i) { if (abs(values[i] - cachedValues[i]) > 1e-9) { throw std::runtime_error("Inconsistent ranking values between implementations"); } } std::cout << "Test 1 passed: Both implementations produce identical results\n"; } // Test case 2: Test edge case with minimum population size void test_MinPopulationSize(eoParser &parser) { eoPop> smallPop; eoReal ind1, ind2; ind1.resize(1); ind1[0] = 0.5; ind2.resize(1); ind2[0] = 1.0; smallPop.push_back(ind1); smallPop.push_back(ind2); eoEvalFuncPtr, double, const std::vector &> mainEval(real_value); eoEvalFuncCounter> eval(mainEval); RankingTest fixture(parser, eval, 2); // Use fixture to get parameters eoRanking> ranking(fixture.pressure(), fixture.exponent()); eoRankingCached> rankingCached(fixture.pressure(), fixture.exponent()); apply>(eval, smallPop); ranking(smallPop); rankingCached(smallPop); if (ranking.value()[0] >= ranking.value()[1] || rankingCached.value()[0] >= rankingCached.value()[1]) { throw std::runtime_error("Invalid ranking for population size 2"); } std::cout << "Test 2 passed: Minimum population size handled correctly\n"; } // Test case 3: Verify caching actually works void test_CachingEffectiveness(eoParser &parser) { eoEvalFuncPtr, double, const std::vector &> mainEval(real_value); eoEvalFuncCounter> eval(mainEval); RankingTest fixture(parser, eval, 50); // Fixed size for cache test eoRankingCached> rankingCached(fixture.pressure(), fixture.exponent()); // First run - should compute all values rankingCached(fixture.pop); const auto firstValues = rankingCached.value(); // Modify fitness values but keep same population size for (auto &ind : fixture.pop) ind[0] = fixture.rng.uniform(); apply>(eval, fixture.pop); // Second run - should use cached coefficients rankingCached(fixture.pop); // Add one individual to invalidate cache eoReal newInd; newInd.resize(1); newInd[0] = fixture.rng.uniform(); fixture.pop.push_back(newInd); apply>(eval, fixture.pop); // Third run - should recompute coefficients rankingCached(fixture.pop); std::cout << "Test 3 passed: Caching mechanism properly invalidated\n"; } int main(int argc, char **argv) { try { eoParser parser(argc, argv); test_Consistency(parser); test_MinPopulationSize(parser); test_CachingEffectiveness(parser); return 0; } catch (std::exception &e) { std::cout << "Exception: " << e.what() << std::endl; return 1; } }