// ch13_differential_evolution.cpp // Companion code for Chapter 13: Optimization and Data Fitting. // Standalone C++11; standard library only; console output without plotting. // Compile: c++ -std=c++11 -O2 -Wall -Wextra -pedantic ch13_differential_evolution.cpp -o ch13_differential_evolution // Edit the example settings in main(); routines above main() can be reused. // Fixed seeds reproduce runs with the same standard-library implementation. // Random distributions need not give identical sequences across compilers/languages. #include #include #include #include #include #include #include #include #include #include #include #include #include using Vec = std::vector; using Mat = std::vector; using Function = std::function; using ScalarFunction = std::function; const double pi = std::acos(-1.0); void require(bool condition, const std::string& message) { if (!condition) throw std::invalid_argument(message); } void finite_vector(const Vec& x) { require(!x.empty(), "A nonempty vector is required."); for (double v : x) require(std::isfinite(v), "Data must be finite."); } void check_bounds(const Vec& lo, const Vec& hi) { finite_vector(lo); finite_vector(hi); require(lo.size() == hi.size(), "Bounds must have matching dimensions."); for (std::size_t j=0; jlo[j] && std::isfinite(hi[j]-lo[j]), "Require finite upper > lower."); } double objective_value(double value) { require(std::isfinite(value), "Objective must return a finite real scalar."); return value; } double clip(double x, double lo, double hi) { return std::max(lo,std::min(hi,x)); } Vec linspace(double a, double b, int n) { require(n>=2, "Grid needs at least two points."); Vec x(n); for (int i=0; i uniform{0.0,1.0}; std::normal_distribution normal{0.0,1.0}; explicit Random(unsigned int seed) : engine(seed) {} double u() { return uniform(engine); } double z() { return normal(engine); } int index(int n) { return std::uniform_int_distribution(0,n-1)(engine); } }; struct Result { Vec point; double value=0.0; long long evaluations=0; int iterations=0; std::string status; }; void print_result(const Result& r) { std::cout << std::setprecision(12); for (std::size_t j=0; j=4 && generations>0 && F>0 && F<=2 && CR>=0 && CR<=1, "Invalid DE settings."); Mat pop(n,Vec(d)); Vec values(n); for (int i=0;i(std::min_element(values.begin(),values.end())-values.begin()); Vec best=pop[idx]; Mat next=pop; Vec next_values=values; for (int i=0;i(d)); Vec trial=pop[i]; for (std::size_t j=0;j(j)==forced) trial[j]=pop[i][j]+F*(best[j]-pop[i][j])+F*(pop[a][j]-pop[b][j]); if (!std::isfinite(trial[j]) || trial[j]hi[j]) trial[j]=lo[j]+(hi[j]-lo[j])*rng.u(); } double ft=objective_value(f(trial)); if (ft<=values[i]) { next[i]=trial; next_values[i]=ft; } } pop=next; values=next_values; } int idx=static_cast(std::min_element(values.begin(),values.end())-values.begin()); Result r; r.point=pop[idx]; r.value=values[idx]; r.iterations=generations; r.evaluations=static_cast(n)*(generations+1LL); r.status="Search budget completed."; return r; } int main() { try { const unsigned int seed = 3; Random rng(seed); // Alternative: comment out the previous line and seed from system entropy. // Random rng(std::random_device{}()); Function f=[](const Vec& p) { double sum=0; for (double x:p) sum+=(x-.5)*(x-.5)+10*(1-std::cos(2*pi*(x-.5))); return sum; }; Vec lower={-4.5,-4.5},upper={5.5,5.5}; int population_size=50,max_generations=400; double F=.9,CR=.9; print_result(differential_evolution(f,lower,upper,rng,population_size,max_generations,F,CR)); std::cout << "Repeat with other seeds; global optimality is not guaranteed.\n"; return 0; } catch (const std::exception& e) { std::cerr << "Error: " << e.what() << '\n'; return 1; } }