1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
19 std::vector
<double> mVariables
;
22 template <typename DataProvider
> class DifferentialEvolutionAlgorithm
24 static constexpr double mnDifferentialWeight
= 0.5; // [0, 2]
25 static constexpr double mnCrossoverProbability
= 0.9; // [0, 1]
27 static constexpr double constAcceptedPrecision
= 0.000000001;
29 DataProvider
& mrDataProvider
;
31 size_t mnPopulationSize
;
32 std::vector
<Individual
> maPopulation
;
34 std::random_device maRandomDevice
;
35 std::mt19937 maGenerator
;
36 size_t mnDimensionality
;
38 std::uniform_int_distribution
<> maRandomPopulation
;
39 std::uniform_int_distribution
<> maRandomDimensionality
;
40 std::uniform_real_distribution
<> maRandom01
;
42 Individual maBestCandidate
;
48 DifferentialEvolutionAlgorithm(DataProvider
& rDataProvider
, size_t nPopulationSize
)
49 : mrDataProvider(rDataProvider
)
50 , mnPopulationSize(nPopulationSize
)
51 , maGenerator(maRandomDevice())
52 , mnDimensionality(mrDataProvider
.getDimensionality())
53 , maRandomPopulation(0, mnPopulationSize
- 1)
54 , maRandomDimensionality(0, mnDimensionality
- 1)
55 , maRandom01(0.0, 1.0)
56 , mfBestFitness(std::numeric_limits
<double>::lowest())
62 std::vector
<double> const& getResult() { return maBestCandidate
.mVariables
; }
64 int getGeneration() { return mnGeneration
; }
66 int getLastChange() { return mnLastChange
; }
73 maBestCandidate
.mVariables
.clear();
75 // Initialize population with individuals that have been initialized with uniform random
77 // uniform noise means random value inside your search space
78 maPopulation
.reserve(mnPopulationSize
);
79 for (size_t i
= 0; i
< mnPopulationSize
; ++i
)
81 maPopulation
.emplace_back();
82 Individual
& rIndividual
= maPopulation
.back();
83 mrDataProvider
.initializeVariables(rIndividual
.mVariables
, maGenerator
);
87 // Calculate one generation
90 bool bBestChanged
= false;
92 for (size_t agentIndex
= 0; agentIndex
< mnPopulationSize
; ++agentIndex
)
94 // calculate new candidate solution
96 // pick random point from population
97 size_t x
= agentIndex
; // randomPopulation(generator);
100 // create a copy of chosen random agent in population
101 Individual
& rOriginal
= maPopulation
[x
];
102 Individual
aCandidate(rOriginal
);
104 // pick three different random points from population
107 a
= maRandomPopulation(maGenerator
);
112 b
= maRandomPopulation(maGenerator
);
113 } while (b
== x
|| b
== a
);
117 c
= maRandomPopulation(maGenerator
);
119 } while (c
== x
|| c
== a
|| c
== b
);
121 size_t randomIndex
= maRandomDimensionality(maGenerator
);
123 for (size_t index
= 0; index
< mnDimensionality
; ++index
)
125 double randomCrossoverProbability
= maRandom01(maGenerator
);
126 if (index
== randomIndex
|| randomCrossoverProbability
< mnCrossoverProbability
)
128 double fVarA
= maPopulation
[a
].mVariables
[index
];
129 double fVarB
= maPopulation
[b
].mVariables
[index
];
130 double fVarC
= maPopulation
[c
].mVariables
[index
];
132 double fNewValue
= fVarA
+ mnDifferentialWeight
* (fVarB
- fVarC
);
133 fNewValue
= mrDataProvider
.boundVariable(index
, fNewValue
);
134 aCandidate
.mVariables
[index
] = fNewValue
;
138 double fCandidateFitness
= mrDataProvider
.calculateFitness(aCandidate
.mVariables
);
140 // see if is better than original, if so replace
141 if (fCandidateFitness
> mrDataProvider
.calculateFitness(rOriginal
.mVariables
))
143 maPopulation
[x
] = std::move(aCandidate
);
145 if (fCandidateFitness
> mfBestFitness
)
147 if (std::abs(fCandidateFitness
- mfBestFitness
) > constAcceptedPrecision
)
150 mnLastChange
= mnGeneration
;
152 mfBestFitness
= fCandidateFitness
;
153 maBestCandidate
= maPopulation
[x
];
162 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */