libstp
Robotics library for Botball
Loading...
Searching...
No Matches
differential_evolution.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <cstdint>
4#include <vector>
5
6// Port of Framework/DifferentialEvolution/DifferentialEvolution.ts and
7// IDifferentialEvolutionRating.ts — a DE/rand/1/bin global optimizer.
8//
9// DETERMINISM: the TypeScript original calls the non-seedable Math.random().
10// To make parity tests reproducible, randomness is injected through a
11// constructor-provided seed driving a mulberry32 PRNG (Rng below). mulberry32
12// is bit-exact across the JS golden-value harness and this C++ implementation,
13// so a given (seed, rating) pair yields identical optimizer trajectories in
14// both. The DE algorithm itself is unchanged from the TS:
15// NUM_CANDIDATES_FACTOR = 12, WEIGHTING_FACTOR_FIX = 0.8,
16// dither in [0.5, 1.0], CROSSOVER_PROBABILITY = 0.8, greedy selection,
17// distinct A/B/C index draws, guaranteed mutation at a random index.
18
20{
21
24{
25public:
26 virtual ~IDifferentialEvolutionRating() = default;
27 virtual double rateCandidate(const std::vector<double>& paramList) = 0;
28};
29
36class Rng
37{
38public:
39 explicit Rng(std::uint32_t seed) : state_(seed) {}
40
42 double next();
43
44private:
45 std::uint32_t state_;
46};
47
52{
53public:
61 int numParams,
62 bool dither = false,
63 std::uint32_t seed = 0xC0FFEEu);
64
66 [[nodiscard]] std::vector<double> getBestCandidate() const;
67
69 void createCandidates(const std::vector<double>& initMinParams,
70 const std::vector<double>& initMaxParams,
71 const std::vector<double>& limitMinParams,
72 const std::vector<double>& limitMaxParams);
73
76
77private:
78 struct Candidate
79 {
80 std::vector<double> paramList;
81 double rating{0};
82
83 explicit Candidate(int numParams)
84 : paramList(static_cast<std::size_t>(numParams), 0.0)
85 {
86 }
87 };
88
89 static constexpr int kNumCandidatesFactor = 12;
90 static constexpr double kWeightingFactorMin = 0.5;
91 static constexpr double kWeightingFactorMax = 1.0;
92 static constexpr double kWeightingFactorFix = 0.8;
93 static constexpr double kCrossoverProbability = 0.8;
94
95 void createCandidate(Candidate& c,
96 const std::vector<double>& minParams,
97 const std::vector<double>& maxParams);
98
99 [[nodiscard]] Candidate mutateAndCrossover(const Candidate& self,
100 const Candidate& a,
101 const Candidate& b,
102 const Candidate& c,
103 double weightingFactor,
104 double crossoverProbability,
105 const std::vector<double>& minParams,
106 const std::vector<double>& maxParams);
107
108 [[nodiscard]] std::size_t getRandomCandidateIndex();
109 void getThreeRandomCandidates(std::size_t currentIdx,
110 std::size_t& idxA,
111 std::size_t& idxB,
112 std::size_t& idxC);
113
114 IDifferentialEvolutionRating& rating_;
115 int num_params_;
116 bool dither_;
117 Rng rng_;
118
119 std::vector<Candidate> candidate_list_;
120 std::vector<Candidate> temp_candidate_list_;
121
122 std::vector<double> limit_min_params_;
123 std::vector<double> limit_max_params_;
124};
125
126} // namespace libstp::autotune::control
std::vector< double > getBestCandidate() const
Best (lowest-rated) parameter vector found so far.
void evolutionStep()
One generation of mutation / crossover / greedy selection.
void createCandidates(const std::vector< double > &initMinParams, const std::vector< double > &initMaxParams, const std::vector< double > &limitMinParams, const std::vector< double > &limitMaxParams)
Seed the population uniformly in [initMin, initMax] and rate it.
DifferentialEvolution(IDifferentialEvolutionRating &rating, int numParams, bool dither=false, std::uint32_t seed=0xC0FFEEu)
Cost function to minimise. Port of IDifferentialEvolutionRating.
virtual double rateCandidate(const std::vector< double > &paramList)=0
double next()
Uniform double in [0, 1), bit-identical to the JS mulberry32.