39#include <boost/date_time/posix_time/posix_time.hpp>
40#include <boost/make_shared.hpp>
51 return left.cost < right.cost;
55template <
class I>
void randomize(I begin, I end,
const MersenneTwisterUniformRng& rng) {
56 Size n =
static_cast<Size
>(end - begin);
57 for (Size i = n - 1; i > 0; --i) {
58 std::swap(begin[i], begin[rng.nextInt32() % (i + 1)]);
67 QL_REQUIRE(
maxTime_.length() == 15,
"maxTime (" <<
maxTime_ <<
") must have format YYYYMMDDTHHMMSS");
68 std::string ts = to_iso_string(boost::posix_time::microsec_clock::local_time()).substr(0, 15);
73 EndCriteria::Type ecType;
79 "wrong upper bound size in differential evolution configuration");
86 "wrong lower bound size in differential evolution configuration");
93 std::vector<Candidate> population;
96 for (Size i = 0; i < population.size(); ++i) {
98 QL_REQUIRE(population[i].values.size() == p.
currentValue().size(),
99 "wrong values size in initial population");
108 std::partial_sort(population.begin(), population.begin() + 1, population.end(), sort_by_cost());
110 Real fxOld = population.front().cost;
111 Size iteration = 0, stationaryPointIteration = 0;
114 while (!endCriteria.checkMaxIterations(iteration++, ecType) && !
checkMaxTime()) {
116 std::partial_sort(population.begin(), population.begin() + 1, population.end(), sort_by_cost());
119 Real fxNew = population.front().cost;
120 if (endCriteria.checkStationaryFunctionValue(fxOld, fxNew, stationaryPointIteration, ecType))
127 ecType = EndCriteria::Type::Unknown;
133 std::vector<Candidate> mirrorPopulation;
134 std::vector<Candidate> oldPopulation = population;
138 case QuantLib::DifferentialEvolution::Rand1Standard: {
139 randomize(population.begin(), population.end(),
rng_);
140 std::vector<Candidate> shuffledPop1 = population;
141 randomize(population.begin(), population.end(),
rng_);
142 std::vector<Candidate> shuffledPop2 = population;
143 randomize(population.begin(), population.end(),
rng_);
144 mirrorPopulation = shuffledPop1;
146 for (Size popIter = 0; popIter < population.size(); popIter++) {
147 population[popIter].values =
148 population[popIter].values +
149 configuration().stepsizeWeight * (shuffledPop1[popIter].values - shuffledPop2[popIter].values);
153 case QuantLib::DifferentialEvolution::BestMemberWithJitter: {
154 randomize(population.begin(), population.end(),
rng_);
155 std::vector<Candidate> shuffledPop1 = population;
156 randomize(population.begin(), population.end(),
rng_);
157 Array jitter(population[0].values.size(), 0.0);
159 for (Size popIter = 0; popIter < population.size(); popIter++) {
160 for (
double& jitterIter : jitter) {
161 jitterIter =
rng_.nextReal();
163 population[popIter].values =
164 bestMemberEver_.values + (shuffledPop1[popIter].values - population[popIter].values) *
167 mirrorPopulation = std::vector<Candidate>(population.size(),
bestMemberEver_);
170 case QuantLib::DifferentialEvolution::CurrentToBest2Diffs: {
171 randomize(population.begin(), population.end(),
rng_);
172 std::vector<Candidate> shuffledPop1 = population;
173 randomize(population.begin(), population.end(),
rng_);
175 for (Size popIter = 0; popIter < population.size(); popIter++) {
176 population[popIter].values =
177 oldPopulation[popIter].values +
179 configuration().stepsizeWeight * (population[popIter].values - shuffledPop1[popIter].values);
181 mirrorPopulation = shuffledPop1;
184 case QuantLib::DifferentialEvolution::Rand1DiffWithPerVectorDither: {
185 randomize(population.begin(), population.end(),
rng_);
186 std::vector<Candidate> shuffledPop1 = population;
187 randomize(population.begin(), population.end(),
rng_);
188 std::vector<Candidate> shuffledPop2 = population;
189 randomize(population.begin(), population.end(),
rng_);
190 mirrorPopulation = shuffledPop1;
191 Array FWeight = Array(population.front().values.size(), 0.0);
192 for (
double& fwIter : FWeight)
194 for (Size popIter = 0; popIter < population.size(); popIter++) {
195 population[popIter].values =
196 population[popIter].values + FWeight * (shuffledPop1[popIter].values - shuffledPop2[popIter].values);
200 case QuantLib::DifferentialEvolution::Rand1DiffWithDither: {
201 randomize(population.begin(), population.end(),
rng_);
202 std::vector<Candidate> shuffledPop1 = population;
203 randomize(population.begin(), population.end(),
rng_);
204 std::vector<Candidate> shuffledPop2 = population;
205 randomize(population.begin(), population.end(),
rng_);
206 mirrorPopulation = shuffledPop1;
208 for (Size popIter = 0; popIter < population.size(); popIter++) {
209 population[popIter].values =
210 population[popIter].values + FWeight * (shuffledPop1[popIter].values - shuffledPop2[popIter].values);
214 case QuantLib::DifferentialEvolution::EitherOrWithOptimalRecombination: {
215 randomize(population.begin(), population.end(),
rng_);
216 std::vector<Candidate> shuffledPop1 = population;
217 randomize(population.begin(), population.end(),
rng_);
218 std::vector<Candidate> shuffledPop2 = population;
219 randomize(population.begin(), population.end(),
rng_);
220 mirrorPopulation = shuffledPop1;
221 Real probFWeight = 0.5;
222 if (
rng_.nextReal() < probFWeight) {
223 for (Size popIter = 0; popIter < population.size(); popIter++) {
224 population[popIter].values =
225 oldPopulation[popIter].values +
226 configuration().stepsizeWeight * (shuffledPop1[popIter].values - shuffledPop2[popIter].values);
230 for (Size popIter = 0; popIter < population.size(); popIter++) {
231 population[popIter].values =
232 oldPopulation[popIter].values + K * (shuffledPop1[popIter].values - shuffledPop2[popIter].values -
233 2.0 * population[popIter].values);
238 case QuantLib::DifferentialEvolution::Rand1SelfadaptiveWithRotation: {
239 randomize(population.begin(), population.end(),
rng_);
240 std::vector<Candidate> shuffledPop1 = population;
241 randomize(population.begin(), population.end(),
rng_);
242 std::vector<Candidate> shuffledPop2 = population;
243 randomize(population.begin(), population.end(),
rng_);
244 mirrorPopulation = shuffledPop1;
248 for (Size popIter = 0; popIter < population.size(); popIter++) {
249 if (
rng_.nextReal() < 0.1) {
252 population[popIter].values =
254 currGenSizeWeights_[popIter] * (shuffledPop1[popIter].values - shuffledPop2[popIter].values);
260 QL_FAIL(
"Unknown strategy (" << Integer(
configuration().strategy) <<
")");
263 crossover(oldPopulation, population, population, mirrorPopulation, p);
267 std::vector<Candidate>& population,
268 const std::vector<Candidate>& mutantPopulation,
269 const std::vector<Candidate>& mirrorPopulation,
Problem_MT& p)
const {
277 std::vector<Array> crossoverMask(population.size(), Array(population.front().values.size(), 1.0));
278 std::vector<Array> invCrossoverMask = crossoverMask;
283 for (Size popIter = 0; popIter < population.size(); popIter++) {
284 population[popIter].values = oldPopulation[popIter].values * invCrossoverMask[popIter] +
285 mutantPopulation[popIter].values * crossoverMask[popIter];
288 for (Size memIter = 0; memIter < population[popIter].values.size(); memIter++) {
289 if (population[popIter].values[memIter] >
upperBound_[memIter])
290 population[popIter].values[memIter] =
292 rng_.nextReal() * (mirrorPopulation[popIter].values[memIter] -
upperBound_[memIter]);
293 if (population[popIter].values[memIter] <
lowerBound_[memIter])
294 population[popIter].values[memIter] =
296 rng_.nextReal() * (mirrorPopulation[popIter].values[memIter] -
lowerBound_[memIter]);
306 Worker(std::vector<Candidate>& p,
const Size s,
const Size e,
const QuantLib::ext::shared_ptr<CostFunction> c)
307 : population(p), start(s), end(e), costFunction(c) {}
309 for (Size popIter = start; popIter < end; popIter++) {
312 population[popIter].cost = costFunction->value(population[popIter].values);
314 population[popIter].cost = QL_MAX_REAL;
316 if (!std::isfinite(population[popIter].cost))
317 population[popIter].cost = QL_MAX_REAL;
320 std::vector<Candidate>& population;
321 const Size start, end;
322 const QuantLib::ext::shared_ptr<CostFunction> costFunction;
326 QL_REQUIRE(threads > 0,
"DifferentialEvolution_MT: number of available threads is zero");
328 std::vector<Size> chunks(threads, std::max<Size>(population.size() / threads, 1));
329 int rest = population.size() - threads * chunks[0];
332 while (i < chunks.size() && rest > 0) {
339 std::vector<QuantLib::ext::shared_ptr<std::thread>> workers(threads);
342 for (Size thread = 0; thread < threads; ++thread) {
343 end = std::min(start + chunks[thread], population.size());
344 Worker worker(population, start, end, p.
costFunctions()[thread]);
345 workers[thread] = QuantLib::ext::make_shared<std::thread>(worker);
349 for (Size thread = 0; thread < threads; ++thread) {
350 workers[thread]->join();
355 const Array& mutationProbabilities)
const {
356 for (Size cmIter = 0; cmIter < crossoverMask.size(); cmIter++) {
357 for (Size memIter = 0; memIter < crossoverMask[cmIter].size(); memIter++) {
358 if (
rng_.nextReal() < mutationProbabilities[cmIter]) {
359 invCrossoverMask[cmIter][memIter] = 0.0;
361 crossoverMask[cmIter][memIter] = 0.0;
370 case DifferentialEvolution::Normal:
372 case DifferentialEvolution::Binomial:
373 mutationProbabilities =
374 currGenCrossover_ * (1.0 - 1.0 / population.front().values.size()) + 1.0 / population.front().values.size();
376 case DifferentialEvolution::Exponential:
378 mutationProbabilities[coIter] =
379 (1.0 - std::pow(
currGenCrossover_[coIter], (
int)population.front().values.size())) /
384 QL_FAIL(
"Unknown crossover type (" << Integer(
configuration().crossoverType) <<
")");
387 return mutationProbabilities;
391 randomize(a.begin(), a.end(),
rng_);
399 Real sizeWeightLowerBound = 0.1, sizeWeightUpperBound = 0.9;
402 Real sizeWeightChangeProb = 0.1;
404 if (
rng_.nextReal() < sizeWeightChangeProb)
410 Real crossoverChangeProb = 0.1;
412 if (
rng_.nextReal() < crossoverChangeProb)
422 for (Size j = 1; j < population.size(); ++j) {
425 population[j].values[i] = l + (u - l) *
rng_.nextReal();
Candidate bestMemberEver_
void crossover(const std::vector< Candidate > &oldPopulation, std::vector< Candidate > &population, const std::vector< Candidate > &mutantPopulation, const std::vector< Candidate > &mirrorPopulation, Problem_MT &p) const
const Configuration & configuration() const
void adaptCrossover() const
void getCrossoverMask(std::vector< Array > &crossoverMask, std::vector< Array > &invCrossoverMask, const Array &mutationProbabilities) const
virtual EndCriteria::Type minimize(Problem_MT &p, const EndCriteria &endCriteria) override
minimize the optimization problem P
MersenneTwisterUniformRng rng_
bool checkMaxTime() const
void calculateNextGeneration(std::vector< Candidate > &population, Problem_MT &p) const
Array currGenSizeWeights_
Array getMutationProbabilities(const std::vector< Candidate > &population) const
DifferentialEvolution::Candidate Candidate
Array rotateArray(Array inputArray) const
void fillInitialPopulation(std::vector< Candidate > &population, const Problem_MT &p) const
void adaptSizeWeights() const
void updateCost(std::vector< Candidate > &population, Problem_MT &p) const
Constrained optimization problem.
const Array & currentValue() const
current value of the local minimum
const std::vector< QuantLib::ext::shared_ptr< CostFunction > > & costFunctions() const
Cost funcionts.
Constraint & constraint() const
Constraint.
void setFunctionValue(Real functionValue)
void setCurrentValue(const Array ¤tValue)
Multithreaded version of QL class.