defoundry 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. defoundry-0.1.0/ALGORITHM_AUDIT.md +556 -0
  2. defoundry-0.1.0/LICENSE +21 -0
  3. defoundry-0.1.0/MANIFEST.in +9 -0
  4. defoundry-0.1.0/MIGRATION.md +134 -0
  5. defoundry-0.1.0/PKG-INFO +357 -0
  6. defoundry-0.1.0/README.md +323 -0
  7. defoundry-0.1.0/RELEASE.md +84 -0
  8. defoundry-0.1.0/defoundry.egg-info/PKG-INFO +357 -0
  9. defoundry-0.1.0/defoundry.egg-info/SOURCES.txt +74 -0
  10. defoundry-0.1.0/defoundry.egg-info/dependency_links.txt +1 -0
  11. defoundry-0.1.0/defoundry.egg-info/requires.txt +14 -0
  12. defoundry-0.1.0/defoundry.egg-info/top_level.txt +1 -0
  13. defoundry-0.1.0/differential_evolution/__init__.py +134 -0
  14. defoundry-0.1.0/differential_evolution/_numeric.py +73 -0
  15. defoundry-0.1.0/differential_evolution/benchmarks.py +208 -0
  16. defoundry-0.1.0/differential_evolution/boundaries.py +133 -0
  17. defoundry-0.1.0/differential_evolution/compat.py +193 -0
  18. defoundry-0.1.0/differential_evolution/crossover_rates.py +100 -0
  19. defoundry-0.1.0/differential_evolution/crossovers.py +194 -0
  20. defoundry-0.1.0/differential_evolution/diversity.py +347 -0
  21. defoundry-0.1.0/differential_evolution/history.py +55 -0
  22. defoundry-0.1.0/differential_evolution/initializers.py +678 -0
  23. defoundry-0.1.0/differential_evolution/jde.py +61 -0
  24. defoundry-0.1.0/differential_evolution/mutation.py +653 -0
  25. defoundry-0.1.0/differential_evolution/optimizer.py +501 -0
  26. defoundry-0.1.0/differential_evolution/population_schedules.py +104 -0
  27. defoundry-0.1.0/differential_evolution/protocols.py +37 -0
  28. defoundry-0.1.0/differential_evolution/py.typed +0 -0
  29. defoundry-0.1.0/differential_evolution/result.py +48 -0
  30. defoundry-0.1.0/differential_evolution/scales.py +143 -0
  31. defoundry-0.1.0/differential_evolution/shade.py +350 -0
  32. defoundry-0.1.0/docs/_static/custom.css +7 -0
  33. defoundry-0.1.0/docs/algorithm_reference.rst +485 -0
  34. defoundry-0.1.0/docs/api/adaptation.rst +15 -0
  35. defoundry-0.1.0/docs/api/crossover.rst +16 -0
  36. defoundry-0.1.0/docs/api/diversity.rst +17 -0
  37. defoundry-0.1.0/docs/api/index.rst +16 -0
  38. defoundry-0.1.0/docs/api/initialization.rst +16 -0
  39. defoundry-0.1.0/docs/api/mutation.rst +22 -0
  40. defoundry-0.1.0/docs/api/solvers.rst +14 -0
  41. defoundry-0.1.0/docs/api/utilities.rst +24 -0
  42. defoundry-0.1.0/docs/citation_and_license.rst +28 -0
  43. defoundry-0.1.0/docs/concepts.rst +142 -0
  44. defoundry-0.1.0/docs/conf.py +69 -0
  45. defoundry-0.1.0/docs/customization.rst +87 -0
  46. defoundry-0.1.0/docs/developer_guide.rst +76 -0
  47. defoundry-0.1.0/docs/discrepancies.rst +159 -0
  48. defoundry-0.1.0/docs/examples.rst +117 -0
  49. defoundry-0.1.0/docs/index.rst +33 -0
  50. defoundry-0.1.0/docs/installation.rst +70 -0
  51. defoundry-0.1.0/docs/introduction.rst +68 -0
  52. defoundry-0.1.0/docs/practical_guides.rst +94 -0
  53. defoundry-0.1.0/docs/quickstart.rst +85 -0
  54. defoundry-0.1.0/docs/references.bib +80 -0
  55. defoundry-0.1.0/docs/references.rst +7 -0
  56. defoundry-0.1.0/docs/review_fixes.md +301 -0
  57. defoundry-0.1.0/examples/__init__.py +1 -0
  58. defoundry-0.1.0/examples/basic_usage.py +38 -0
  59. defoundry-0.1.0/examples/custom_components.py +32 -0
  60. defoundry-0.1.0/examples/diversity_measures.py +55 -0
  61. defoundry-0.1.0/examples/population_initialization.py +53 -0
  62. defoundry-0.1.0/main.py +5 -0
  63. defoundry-0.1.0/population_initialization.py +85 -0
  64. defoundry-0.1.0/pyproject.toml +58 -0
  65. defoundry-0.1.0/scripts/check_distribution.py +88 -0
  66. defoundry-0.1.0/setup.cfg +4 -0
  67. defoundry-0.1.0/testing_functions.py +42 -0
  68. defoundry-0.1.0/tests/test_differential_evolution.py +873 -0
  69. defoundry-0.1.0/tests/test_message_regressions.py +105 -0
  70. defoundry-0.1.0/tests/test_project_review.py +178 -0
  71. defoundry-0.1.0/tests/test_review_regressions.py +347 -0
  72. defoundry-0.1.0/tests/test_round3_regressions.py +96 -0
  73. defoundry-0.1.0/tests/test_round4_regressions.py +179 -0
  74. defoundry-0.1.0/tests/test_round5_regressions.py +237 -0
  75. defoundry-0.1.0/tests/test_round6_regressions.py +158 -0
  76. defoundry-0.1.0/tests/test_shade_ranking.py +59 -0
@@ -0,0 +1,556 @@
1
+ > Historical refactor audit. The current behavior supersedes the formulas and
2
+ > exclusion rules below where noted in [review fixes](docs/review_fixes.md).
3
+ > In particular, the old DirectedMutation attribution/formula is withdrawn;
4
+ > Best-family exclusions, initialization, and SHADE/L-SHADE rules changed.
5
+
6
+ # Algorithm Audit
7
+
8
+ ## Scope
9
+
10
+ This audit covers the Differential Evolution variants and crossover behavior implemented in the original repository:
11
+
12
+ - `DE/rand/1`
13
+ - `DE/rand/2`
14
+ - `DE/best/1`
15
+ - `DE/best/2`
16
+ - `DE/current-to-best/1`
17
+ - `DE/current-to-best/2`
18
+ - `DE/current-to-rand/1`
19
+ - `DE/current-to-rand/2`
20
+ - binomial crossover
21
+
22
+ It also covers the newly added `TrigonometricMutation` component because its mathematical meaning needs explicit documentation.
23
+
24
+ The original README also claimed a Sobol initializer. The original implementation was incomplete and mathematically invalid; it has now been replaced with a correct Bratley-Fox-style Sobol implementation for the first 40 dimensions.
25
+
26
+ ## Canonical references
27
+
28
+ - R. Storn and K. Price, "Differential Evolution - A Simple and Efficient Heuristic for Global Optimization over Continuous Spaces," *Journal of Global Optimization*, 1997. DOI: https://doi.org/10.1023/A:1008202821328
29
+ - K. Price, R. Storn, and J. Lampinen, *Differential Evolution: A Practical Approach to Global Optimization*, Springer, 2005. DOI: https://doi.org/10.1007/3-540-31306-0
30
+ - S. Das and P. N. Suganthan, "Differential Evolution: A Survey of the State-of-the-Art," *IEEE Transactions on Evolutionary Computation*, 2011. DOI: https://doi.org/10.1109/TEVC.2010.2059031
31
+
32
+ Notation below follows the standard DE literature:
33
+
34
+ - `x_i,g`: target vector for index `i` in generation `g`
35
+ - `v_i,g`: donor vector
36
+ - `u_i,g`: trial vector
37
+ - `x_best,g`: best vector in the current generation
38
+ - `F`: differential weight
39
+ - `CR`: crossover rate
40
+ - `r1`, `r2`, ...: sampled population indices
41
+
42
+ ## Summary of confirmed defects in the original implementation
43
+
44
+ 1. Binomial crossover was implemented incorrectly.
45
+ - Original condition: keep the target coordinate when `cr > crossover or random_dimension != dimension`.
46
+ - Because `random_dimension != dimension` is true for all but one coordinate, the donor vector could only contribute in at most one coordinate.
47
+ - Canonical binomial crossover must independently consider every coordinate and force at least one donor coordinate.
48
+
49
+ 2. Candidate index sampling was incorrect.
50
+ - The original code used `sample(range(self.population_size - 1), 6)`.
51
+ - This excluded the last population member from ever being sampled.
52
+ - It also failed to express the actual exclusion constraints directly.
53
+
54
+ 3. Mutation and crossover were entangled.
55
+ - Mutation was computed per-coordinate inside the crossover loop.
56
+ - This prevented independent composition of mutation and crossover components.
57
+
58
+ 4. The implementation relied on implicit global RNG state.
59
+ - The original code used `numpy.random` module functions directly.
60
+ - Reproducibility depended on global state rather than explicit user-controlled RNG input.
61
+
62
+ 5. Objective evaluations were duplicated and uncounted.
63
+ - Individuals were re-evaluated repeatedly inside `evolve()` and `get_best()`.
64
+ - Evaluation counting was not tracked.
65
+
66
+ 6. Boundary handling was not actually implemented.
67
+ - A comment claimed boundary repair, but no repair logic existed.
68
+
69
+ 7. The generation update loop did not make the execution model explicit.
70
+ - The original `get_best()` was called before the loop, which was correct for generation-level best use.
71
+ - However, mutation/crossover logic was interleaved tightly enough that invariants were hard to verify.
72
+
73
+ 8. The old Sobol initializer was not a valid Sobol sequence implementation.
74
+ - It used bitwise XOR operators where exponentiation-like logic was intended.
75
+ - It did not match standard Sobol direction-number construction.
76
+ - It reused one scalar across every coordinate of a point.
77
+
78
+ ## Variant-by-variant audit
79
+
80
+ ### `DE/rand/1`
81
+
82
+ - Current repository name: `DE/rand/1`
83
+ - Canonical donor formula: `v_i,g = x_r1,g + F * (x_r2,g - x_r3,g)`
84
+ - Intended base vector: random
85
+ - Sampled indices:
86
+ - `r1`, `r2`, `r3` must be mutually distinct
87
+ - `r1`, `r2`, `r3` must exclude `i`
88
+ - Minimum valid population size: 4
89
+ - Target exclusion: yes
90
+ - Original implementation correctness:
91
+ - Mutation formula was correct.
92
+ - Index sampling had the shared defect described above.
93
+ - Change made:
94
+ - Preserved the formula.
95
+ - Replaced sampling with centralized distinct-index sampling.
96
+
97
+ ### `DE/rand/2`
98
+
99
+ - Current repository name: `DE/rand/2`
100
+ - Canonical donor formula: `v_i,g = x_r1,g + F * (x_r2,g - x_r3,g) + F * (x_r4,g - x_r5,g)`
101
+ - Intended base vector: random
102
+ - Sampled indices:
103
+ - `r1` through `r5` mutually distinct
104
+ - all exclude `i`
105
+ - Minimum valid population size: 6
106
+ - Target exclusion: yes
107
+ - Original implementation correctness:
108
+ - Mutation formula was correct.
109
+ - Index sampling had the shared defect described above.
110
+ - Change made:
111
+ - Preserved the formula.
112
+ - Replaced sampling with centralized distinct-index sampling.
113
+
114
+ ### `DE/best/1`
115
+
116
+ - Current repository name: `DE/best/1`
117
+ - Canonical donor formula: `v_i,g = x_best,g + F * (x_r1,g - x_r2,g)`
118
+ - Intended base vector: best vector from the current generation snapshot
119
+ - Sampled indices:
120
+ - `r1`, `r2` distinct
121
+ - `r1`, `r2` exclude `i`
122
+ - in this refactor, `r1`, `r2` also exclude `best_index` so the sampled vectors are distinct from the base vector when possible
123
+ - Minimum valid population size:
124
+ - 3 when `i` is the best index
125
+ - 4 otherwise
126
+ - Target exclusion: yes for sampled indices; the base vector may equal the target when the target is best
127
+ - Original implementation correctness:
128
+ - Mutation formula was correct.
129
+ - Index sampling had the shared defect described above.
130
+ - Change made:
131
+ - Preserved the formula.
132
+ - Made best-vector timing explicit and used centralized sampling.
133
+
134
+ ### `DE/best/2`
135
+
136
+ - Current repository name: `DE/best/2`
137
+ - Canonical donor formula: `v_i,g = x_best,g + F * (x_r1,g - x_r2,g) + F * (x_r3,g - x_r4,g)`
138
+ - Intended base vector: best vector from the current generation snapshot
139
+ - Sampled indices:
140
+ - `r1` through `r4` mutually distinct
141
+ - sampled indices exclude `i`
142
+ - sampled indices exclude `best_index` in the refactor
143
+ - Minimum valid population size:
144
+ - 5 when `i` is the best index
145
+ - 6 otherwise
146
+ - Target exclusion: yes for sampled indices; base may equal target if target is best
147
+ - Original implementation correctness:
148
+ - Mutation formula was correct.
149
+ - Index sampling had the shared defect described above.
150
+ - Change made:
151
+ - Preserved the formula.
152
+ - Made best-vector timing explicit and used centralized sampling.
153
+
154
+ ### `DE/current-to-best/1`
155
+
156
+ - Current repository name: `DE/current-to-best/1`
157
+ - Canonical donor formula: `v_i,g = x_i,g + F * (x_best,g - x_i,g) + F * (x_r1,g - x_r2,g)`
158
+ - Original repository formula: `x_i,g + F_best * (x_best,g - x_i,g) + F_diff * (x_r1,g - x_r2,g)`
159
+ - Intended base vector: current target vector
160
+ - Sampled indices:
161
+ - `r1`, `r2` distinct
162
+ - sampled indices exclude `i`
163
+ - sampled indices exclude `best_index` in the refactor
164
+ - Minimum valid population size:
165
+ - 3 when `i` is the best index
166
+ - 4 otherwise
167
+ - Target exclusion: yes for sampled difference indices
168
+ - Original implementation correctness:
169
+ - The structure was correct.
170
+ - The use of two scale factors under the canonical name is a project-specific extension or ambiguity, not a mathematical bug.
171
+ - Index sampling had the shared defect described above.
172
+ - Change made:
173
+ - Preserved the two-factor behavior through `CurrentToBest1(scale, difference_scale=...)`.
174
+ - The default new API treats `difference_scale=None` as the canonical single-`F` form.
175
+
176
+ ### `DE/current-to-best/2`
177
+
178
+ - Current repository name: `DE/current-to-best/2`
179
+ - Canonical donor formula: `v_i,g = x_i,g + F * (x_best,g - x_i,g) + F * (x_r1,g - x_r2,g) + F * (x_r3,g - x_r4,g)`
180
+ - Original repository formula: `x_i,g + F_best * (x_best,g - x_i,g) + F_diff * (x_r1,g - x_r2,g) + F_diff * (x_r3,g - x_r4,g)`
181
+ - Intended base vector: current target vector
182
+ - Sampled indices:
183
+ - `r1` through `r4` mutually distinct
184
+ - sampled indices exclude `i`
185
+ - sampled indices exclude `best_index` in the refactor
186
+ - Minimum valid population size:
187
+ - 5 when `i` is the best index
188
+ - 6 otherwise
189
+ - Target exclusion: yes for sampled difference indices
190
+ - Original implementation correctness:
191
+ - The structure was correct.
192
+ - The two-factor choice is a documented extension or ambiguity rather than a sign error.
193
+ - Index sampling had the shared defect described above.
194
+ - Change made:
195
+ - Preserved the old two-factor behavior in the compatibility layer.
196
+ - Exposed the canonical single-`F` form in the new API when `difference_scale` is omitted.
197
+
198
+ ### `DE/current-to-rand/1`
199
+
200
+ - Current repository name: `DE/current-to-rand/1`
201
+ - Common donor formula in the DE literature: `v_i,g = x_i,g + K * (x_r1,g - x_i,g) + F * (x_r2,g - x_r3,g)`
202
+ - Intended base vector: current target vector attracted toward a random vector
203
+ - Sampled indices:
204
+ - `r1`, `r2`, `r3` mutually distinct
205
+ - all exclude `i`
206
+ - Minimum valid population size: 4
207
+ - Target exclusion: yes for sampled indices
208
+ - Original implementation correctness:
209
+ - The donor formula matched a recognized current-to-rand structure.
210
+ - The implementation then applied binomial crossover, which is mathematically possible but not the canonical presentation in much of the literature.
211
+ - Index sampling had the shared defect described above.
212
+ - Change made:
213
+ - Preserved the donor formula as an independent mutation component.
214
+ - Documented that pairing with `IdentityCrossover` is the closest built-in representation of the standard no-extra-crossover form.
215
+ - Pairing with binomial or exponential crossover remains available as a noncanonical but explicit composition.
216
+
217
+ ### `DE/current-to-rand/2`
218
+
219
+ - Current repository name: `DE/current-to-rand/2`
220
+ - Project donor formula: `v_i,g = x_i,g + K * (x_r1,g - x_i,g) + F * (x_r2,g - x_r3,g) + F * (x_r4,g - x_r5,g)`
221
+ - Intended base vector: current target vector attracted toward a random vector
222
+ - Sampled indices:
223
+ - `r1` through `r5` mutually distinct
224
+ - all exclude `i`
225
+ - Minimum valid population size: 6
226
+ - Target exclusion: yes for sampled indices
227
+ - Original implementation correctness:
228
+ - The formula is a defensible project-specific extension of the current-to-rand family.
229
+ - It is not one of the most standard named variants in the original DE papers.
230
+ - Index sampling had the shared defect described above.
231
+ - Change made:
232
+ - Preserved the formula as a built-in strategy.
233
+ - Documented it as a project-specific extension rather than silently rebranding it as canonical.
234
+
235
+ ### `TrigonometricMutation`
236
+
237
+ - Current package name: `TrigonometricMutation`
238
+ - Canonical source:
239
+ - H.-Y. Fan and J. Lampinen, "A trigonometric mutation operation to differential evolution," *Journal of Global Optimization*, 2003. DOI: https://doi.org/10.1023/A:1024653025686
240
+ - Canonical hybrid structure:
241
+ - sample mutually distinct `r1`, `r2`, `r3`, excluding `i`
242
+ - with probability `p_m`, use the trigonometric donor
243
+ - otherwise use `DE/rand/1`
244
+ - Trigonometric donor formula:
245
+ - `v_i,g = (x_r1,g + x_r2,g + x_r3,g)/3`
246
+ - `+ (p2 - p1) * (x_r1,g - x_r2,g)`
247
+ - `+ (p3 - p2) * (x_r2,g - x_r3,g)`
248
+ - `+ (p1 - p3) * (x_r3,g - x_r1,g)`
249
+ - where `p1 = |f_r1| / (|f_r1| + |f_r2| + |f_r3|)`, and likewise for `p2`, `p3`
250
+ - Intended base vectors: three randomly sampled vectors, weighted by objective values
251
+ - Sampled indices:
252
+ - `r1`, `r2`, `r3` must be mutually distinct
253
+ - all exclude `i`
254
+ - Minimum valid population size: 4
255
+ - Target exclusion: yes
256
+ - Original repository correctness:
257
+ - not implemented
258
+ - Change made:
259
+ - added the canonical Fan-Lampinen hybrid form as a composable mutation component
260
+ - when the selected absolute fitness sum is zero, equal weights `1/3` are used to avoid division by zero
261
+ - when the selected fitness data are non-finite, the implementation falls back to `DE/rand/1`
262
+
263
+ ### `DirectedMutation`
264
+
265
+ - Current package name: `DirectedMutation`
266
+ - Canonical source:
267
+ - H.-Y. Fan and J. Lampinen, "A trigonometric mutation operation to differential evolution," *Journal of Global Optimization*, 2003. DOI: https://doi.org/10.1023/A:1024653025686
268
+ - Directed donor formula:
269
+ - sample mutually distinct `r1`, `r2`, `r3`, excluding `i`
270
+ - reorder them so `f(x_b) <= f(x_w1) <= f(x_w2)`
271
+ - `v_i,g = x_b + ((1 - f_b) / f_w1) * (x_b - x_w1) + ((1 - f_b) / f_w2) * (x_b - x_w2)`
272
+ - Intended base vector: the best vector among the three sampled vectors
273
+ - Sampled indices:
274
+ - `r1`, `r2`, `r3` must be mutually distinct
275
+ - all exclude `i`
276
+ - Minimum valid population size: 4
277
+ - Target exclusion: yes
278
+ - Original repository correctness:
279
+ - not implemented
280
+ - Change made:
281
+ - added the directed mutation as a composable component
282
+ - because the canonical coefficients are undefined for non-positive or non-finite worse objective values, the implementation falls back to `DE/rand/1` in those cases
283
+
284
+ ### `NeighborhoodSearchMutation`
285
+
286
+ - Current package name: `NeighborhoodSearchMutation`
287
+ - Canonical source:
288
+ - Z. Yang, J. He, and X. Yao, "Making a Difference to Differential Evolution," in *Advances in Metaheuristics for Hard Optimization*, Springer, 2008.
289
+ - The same NSDE definition is summarized in Yang, Tang, and Yao, "Differential evolution for high-dimensional function optimization," and the Information Sciences 2008 DECC-G paper.
290
+ - Canonical donor formula:
291
+ - `v_i,g = x_r1,g + d_i * N(0.5, 0.5)` with probability `0.5`
292
+ - `v_i,g = x_r1,g + d_i * delta` otherwise
293
+ - where `d_i = x_r2,g - x_r3,g`
294
+ - `delta` is a Cauchy random variable with scale parameter `1`
295
+ - Intended base vector: random
296
+ - Sampled indices:
297
+ - `r1`, `r2`, `r3` mutually distinct
298
+ - all exclude `i`
299
+ - Minimum valid population size: 4
300
+ - Target exclusion: yes
301
+ - Original repository correctness:
302
+ - not implemented
303
+ - Change made:
304
+ - added NSDE as a dedicated mutation component with configurable Gaussian probability, Gaussian parameters, and Cauchy scale
305
+ - crossover remains an independent component, so `NeighborhoodSearchMutation` can be paired with binomial, exponential, or identity crossover
306
+
307
+ ## Crossover audit
308
+
309
+ ### Binomial crossover
310
+
311
+ - Current repository name: `binomial`
312
+ - Canonical trial formula:
313
+ - Choose `j_rand` uniformly from `{0, ..., D - 1}`
314
+ - For each coordinate `j`, use donor coordinate when `rand_j < CR` or `j == j_rand`
315
+ - Otherwise keep the target coordinate
316
+ - Target vector exclusion: not applicable
317
+ - Minimum valid dimensionality: 1
318
+ - Required invariant: at least one coordinate must come from the donor
319
+ - Original implementation correctness:
320
+ - Incorrect.
321
+ - The condition was reversed and tied to `random_dimension != dimension`, which forced almost every coordinate to remain from the target.
322
+ - `CR = 1` did not produce an all-donor trial vector.
323
+ - `CR = 0` only worked accidentally for one coordinate, but for the wrong reason.
324
+ - Change made:
325
+ - Reimplemented canonical binomial crossover.
326
+ - Added deterministic tests for `CR = 0`, `CR = 1`, and donor-coordinate guarantees.
327
+
328
+ ### Exponential crossover
329
+
330
+ - Current repository status: implemented in the refactor
331
+ - Canonical trial formula:
332
+ - Choose a starting coordinate `j_start`
333
+ - Copy a contiguous cyclic block from donor to target
334
+ - Always copy at least one donor coordinate
335
+ - Continue while fresh uniform samples are less than `CR`, until `D` coordinates have been copied
336
+ - Original implementation correctness:
337
+ - Not applicable; no implementation existed.
338
+ - Change made:
339
+ - Added a correct cyclic exponential crossover operator with deterministic tests.
340
+
341
+ ## Execution-model audit
342
+
343
+ ### Best-vector timing
344
+
345
+ - Canonical requirement:
346
+ - The generation best used in `best/*` and `current-to-best/*` must come from the unmodified generation snapshot.
347
+ - Original implementation:
348
+ - `get_best()` was called once before the per-target loop, which was correct.
349
+ - The code structure made this easy to miss during maintenance.
350
+ - Change made:
351
+ - The refactor snapshots both population and fitness at the start of each generation and passes `best_index` and `best_vector` through `MutationContext`.
352
+
353
+ ### Immediate versus generational updates
354
+
355
+ - Canonical requirement:
356
+ - Trial-vector generation for all targets in generation `g` should use the same original generation snapshot.
357
+ - Original implementation:
358
+ - Replacement wrote into `self.population[idx]` during the loop.
359
+ - The mutation formula happened to rely only on the sampled vectors, and sampled indices were drawn before replacement, but the code did not make the generation snapshot explicit.
360
+ - Change made:
361
+ - The optimizer now creates `population_snapshot` and `fitness_snapshot` and writes winners into a separate `next_population`.
362
+
363
+ ### RNG handling
364
+
365
+ - Original implementation:
366
+ - Used module-level NumPy RNG functions directly.
367
+ - Change made:
368
+ - The refactor uses an explicit RNG object, defaulting to `random.Random(seed)`.
369
+ - A run is reproducible when created with the same seed.
370
+
371
+ ## Sobol initialization audit
372
+
373
+ ### Original implementation status
374
+
375
+ - File: the former `sobol_initialization` in [population_initialization.py](population_initialization.py)
376
+ - Result: incorrect
377
+ - Reasons:
378
+ - It did not implement the standard direction-number recurrence.
379
+ - It used Python's `^` operator, which is bitwise XOR, in places where the apparent intent was arithmetic recurrence.
380
+ - It constructed one scalar quasirandom number and copied it into all coordinates, which is not a valid multi-dimensional Sobol sequence.
381
+
382
+ ### Replacement implementation
383
+
384
+ - New component: `SobolInitializer` in [initializers.py](differential_evolution/initializers.py)
385
+ - Construction:
386
+ - Uses the Bratley-Fox recurrence with primitive polynomials and initial direction numbers.
387
+ - Generates the first `n` points including the zero vector.
388
+ - Supports dimensions 1 through 40.
389
+ - Sampling properties:
390
+ - deterministic
391
+ - independent of the optimizer RNG
392
+ - scaled coordinate-wise into the user-provided bounds
393
+
394
+ ### Verified behavior
395
+
396
+ - The first eight points in 2D match the standard sequence:
397
+ - `(0, 0)`
398
+ - `(1/2, 1/2)`
399
+ - `(3/4, 1/4)`
400
+ - `(1/4, 3/4)`
401
+ - `(3/8, 3/8)`
402
+ - `(7/8, 7/8)`
403
+ - `(5/8, 1/8)`
404
+ - `(1/8, 5/8)`
405
+
406
+ ## Additional non-DE corrections
407
+
408
+ - `ackley_function` in the original repository omitted the `0.5` factor inside the square root for the 2-D form documented in its own docstring.
409
+ - `schaffer_n2_function` used `x^2 + y^2` inside the sine term, while the documented function is based on `x^2 - y^2`.
410
+ - `testing_functions.himmelblaus_function` was renamed internally to the conventional `himmelblau_function`, with a compatibility alias preserved.
411
+
412
+ ## Remaining limitations
413
+
414
+ - Sobol initialization currently supports only the first 40 dimensions, matching the embedded direction-number table.
415
+ - The optimizer currently supports minimization only.
416
+ - Boundary handling is explicit but limited to `none`, `clip`, and `random reset`.
417
+ - No separate stopping-criterion protocol has been added yet beyond `max_generations`; the control flow is separated cleanly enough that this can be added later without changing mutation or crossover APIs.
418
+
419
+ ## Population diversity measures
420
+
421
+ The package now supports optional generation-by-generation recording of several diversity measures. These are diagnostics only; they do not alter selection or parameter updates.
422
+
423
+ - `PopulationDiameter`:
424
+ - `max_{i,j} ||x_i - x_j||`
425
+ - `PopulationRadius`:
426
+ - `max_i ||x_i - c||`, where `c` is the population center
427
+ - `AverageDistanceAroundPopulationCenter`:
428
+ - `(1 / N) * sum_i ||x_i - c||`
429
+ - `AverageDistanceAroundAllIndividuals`:
430
+ - `(1 / N) * sum_i [(1 / N) * sum_j ||x_i - x_j||]`
431
+ - `AveragePairwiseDistance`:
432
+ - `(2 / (N * (N - 1))) * sum_{i < j} ||x_i - x_j||`
433
+ - `PopulationCoherence`:
434
+ - `||c_g - c_{g-1}|| / [(1 / N) * sum_i ||x_i,g - x_i,g-1||]`
435
+ - defined as `0` for the first recorded generation
436
+ - `DimensionalVariance`:
437
+ - the mean per-dimension variance around the population center
438
+ - `AggregatedDistribution`:
439
+ - project-specific definition
440
+ - each coordinate is normalized into `[0, 1]`, partitioned into `ceil(sqrt(N))` bins, and summarized by the variance-to-mean ratio of the marginal occupancy counts
441
+
442
+ Two of these measures are intentionally both present even though they are closely related:
443
+
444
+ - `AverageDistanceAroundAllIndividuals` includes self-zero terms and counts ordered pairs
445
+ - `AveragePairwiseDistance` averages over unordered distinct pairs only
446
+
447
+ ## Population reduction schedules
448
+
449
+ ### `LinearPopulationReduction`
450
+
451
+ - Current package name: `LinearPopulationReduction`
452
+ - Canonical inspiration:
453
+ - R. Tanabe and A. Fukunaga, "Improving the Search Performance of SHADE Using Linear Population Size Reduction," *2014 IEEE Congress on Evolutionary Computation*. DOI: https://doi.org/10.1109/CEC.2014.6900380
454
+ - Implemented rule:
455
+ - let `progress` be `NFE / MAX_NFE` when `max_evaluations` is provided
456
+ - otherwise let `progress` be `generation / max_generations`
457
+ - `NP(progress) = round(NP_init + (NP_min - NP_init) * progress)`
458
+ - Survivor selection:
459
+ - after each generation, remove the worst individuals by current fitness until the target size is reached
460
+ - Compatibility constraint:
461
+ - `NP_min` must stay large enough for the chosen mutation strategy
462
+
463
+ ### `HyperbolicTangentPopulationReduction`
464
+
465
+ - Current package name: `HyperbolicTangentPopulationReduction`
466
+ - Canonical status:
467
+ - this is a documented project-specific nonlinear schedule inspired by tanh-based population reduction papers
468
+ - Implemented rule:
469
+ - map normalized progress into `[start, end]`
470
+ - convert it with a normalized `tanh` curve
471
+ - interpolate population size between `NP_init` and `NP_min`
472
+ - Survivor selection:
473
+ - worst individuals by current fitness are removed, as in the linear schedule
474
+
475
+ ### Execution-model note
476
+
477
+ - Population reduction is applied after each completed generation step.
478
+ - If `max_evaluations` cuts a generation short, the processed subset is accepted, then the reduction schedule is applied to the resulting population state.
479
+
480
+ ## SHADE and L-SHADE
481
+
482
+ ### `SHADE`
483
+
484
+ - Current package name: `SHADE`
485
+ - Canonical sources:
486
+ - R. Tanabe and A. Fukunaga, "Success-History Based Parameter Adaptation for Differential Evolution," *2013 IEEE Congress on Evolutionary Computation*. DOI: https://doi.org/10.1109/CEC.2013.6557555
487
+ - Implemented mutation/crossover core:
488
+ - `current-to-pbest/1/bin`
489
+ - `v_i,g = x_i,g + F_i * (x_pbest,g - x_i,g) + F_i * (x_r1,g - x_r2,g)`
490
+ - Parameter generation:
491
+ - choose a memory slot `r_i`
492
+ - sample `F_i` from a Cauchy distribution centered at `M_F[r_i]` with scale `0.1`, resampling while `F_i <= 0` and clipping at `1`
493
+ - sample `CR_i` from a normal distribution centered at `M_CR[r_i]` with standard deviation `0.1`, clipping into `[0, 1]`
494
+ - `pbest` selection:
495
+ - sample `p_i` from `U(2 / NP, p_max)` with `p_max = 0.2` by default
496
+ - choose `x_pbest` uniformly from the top `ceil(p_i * NP)` individuals, excluding the target when possible
497
+ - Archive:
498
+ - stores replaced parent vectors
499
+ - contributes candidate `r2`
500
+ - is randomly trimmed to the configured maximum size
501
+ - Memory update:
502
+ - uses weighted Lehmer mean for successful `F`
503
+ - uses weighted arithmetic mean for successful `CR`
504
+ - weights are proportional to objective improvement
505
+
506
+ ### `LSHADE`
507
+
508
+ - Current package name: `LSHADE`
509
+ - Canonical source:
510
+ - R. Tanabe and A. Fukunaga, "Improving the Search Performance of SHADE Using Linear Population Size Reduction," *2014 IEEE Congress on Evolutionary Computation*. DOI: https://doi.org/10.1109/CEC.2014.6900380
511
+ - Implemented extension:
512
+ - full `SHADE` machinery
513
+ - linear population size reduction schedule
514
+ - Project decision:
515
+ - `LSHADE` is exposed as a dedicated optimizer class rather than as a preset on the generic DE optimizer, because the success-history memory and archive are integral algorithmic components, not optional add-ons
516
+
517
+ ## Scale-factor extensions
518
+
519
+ ### `RandomizedScaleFactor`
520
+
521
+ - Current package name: `RandomizedScaleFactor`
522
+ - Interpretation used:
523
+ - uniform dither of the differential weight
524
+ - a fresh `F ~ Uniform(lower, upper)` is sampled for each target mutation
525
+ - Canonical status:
526
+ - a standard DE control-parameter randomization technique
527
+ - the exact per-generation versus per-vector sampling choice varies in the literature
528
+ - Decision made:
529
+ - this package uses per-target sampling because it composes cleanly with the mutation-component API and is easy to test
530
+
531
+ ### `AdaptiveScaleFactor`
532
+
533
+ - Current package name: `AdaptiveScaleFactor`
534
+ - Canonical source for the interpretation:
535
+ - J. Brest, S. Greiner, B. Boskovic, M. Mernik, and V. Zumer, "Self-Adapting Control Parameters in Differential Evolution: A Comparative Study on Numerical Benchmark Problems," *IEEE Transactions on Evolutionary Computation*, 2006. DOI: https://doi.org/10.1109/TEVC.2006.872133
536
+ - Interpretation used:
537
+ - jDE-style self-adaptation of the scale factor `F`
538
+ - each individual carries its own current `F_i`
539
+ - before mutating target `i`, a new candidate `F_i'` is proposed with probability `tau`
540
+ - if the trial vector wins selection, `F_i'` replaces `F_i`; otherwise the previous `F_i` is retained
541
+ - Decision made:
542
+ - this package now also implements the matching `CR_i` adaptation on the crossover side
543
+
544
+ ### `AdaptiveCrossoverRate`
545
+
546
+ - Current package name: `AdaptiveCrossoverRate`
547
+ - Canonical source for the interpretation:
548
+ - J. Brest, S. Greiner, B. Boskovic, M. Mernik, and V. Zumer, "Self-Adapting Control Parameters in Differential Evolution: A Comparative Study on Numerical Benchmark Problems," *IEEE Transactions on Evolutionary Computation*, 2006. DOI: https://doi.org/10.1109/TEVC.2006.872133
549
+ - Interpretation used:
550
+ - jDE-style self-adaptation of the crossover rate `CR`
551
+ - each individual carries its own `CR_i`
552
+ - before crossover for target `i`, a new candidate `CR_i'` is proposed with probability `tau`
553
+ - if the trial vector wins selection, `CR_i'` replaces `CR_i`; otherwise the previous `CR_i` is retained
554
+ - Decision made:
555
+ - the controller is implemented independently of the crossover operator so it can drive binomial or exponential crossover
556
+ - the `jde_rand_1_bin()` helper returns the mutation/crossover pairing closest to Brest et al.'s published jDE setup
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Honza
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,9 @@
1
+ include LICENSE README.md MIGRATION.md ALGORITHM_AUDIT.md RELEASE.md
2
+ include main.py population_initialization.py testing_functions.py
3
+ recursive-include tests *.py
4
+ recursive-include examples *.py
5
+ recursive-include scripts *.py
6
+ recursive-include docs *.rst *.md *.py *.bib *.css
7
+ prune docs/_build
8
+ prune docs/api/generated
9
+ global-exclude __pycache__ *.py[cod]