From f12d4fa6b6ecf4b48ace6fbda33b9e425eba551b Mon Sep 17 00:00:00 2001 From: Someguy Date: Thu, 1 Oct 2026 06:59:12 +0300 Subject: [PATCH 01/16] feat(problems): shift and rotation wrappers, and seventeen CEC, BBOB and classic functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Shifted and Rotated make instances of any problem on Real genomes from a seed, as the CEC and BBOB suites do. The new functions: the sum of different powers, step, quartic (with noise drawn from the genome, or without), the two penalized functions, the high-conditioned elliptic, bent cigar, discus, BBOB's different powers, Büche-Rastrigin, non-continuous Rastrigin, Weierstrass, Katsuura, HappyCat, HGBat, Schaffer's F7 and the rotated hyper-ellipsoid. --- src/problems.rs | 66 +- src/problems/classic.rs | 1199 +++++++++++++++++++++++++++++++++++++ src/problems/transform.rs | 507 ++++++++++++++++ 3 files changed, 1771 insertions(+), 1 deletion(-) create mode 100644 src/problems/transform.rs diff --git a/src/problems.rs b/src/problems.rs index 39f54ae5..efd5f4d8 100644 --- a/src/problems.rs +++ b/src/problems.rs @@ -64,6 +64,30 @@ //! | [`Langermann`] | 2 | [0, 10] | −4.15581 at (2.79340, 1.59723), best known | //! | [`ShekelFoxholes`] | 2 | [−65.536, 65.536] | 0.99800 near (−32, −32), best known | //! | [`Kowalik`] | 4 | [−5, 5] | 3.07486e-4 at (0.19283, 0.19084, 0.12312, 0.13577), best known | +//! | [`SumOfDifferentPowers`] | any (30) | [−1, 1] | 0 at the origin | +//! | [`Step`] | any (30) | [−100, 100] | 0 on [−0.5, 0.5)ⁿ | +//! | [`Quartic`] | any (30) | [−1.28, 1.28] | 0 at the origin, without noise | +//! | [`Penalized1`] | any (30) | [−50, 50] | 0 at (−1, …, −1) | +//! | [`Penalized2`] | any (30) | [−50, 50] | 0 at (1, …, 1) | +//! | [`HighConditionedElliptic`] | 2 or more (30) | [−100, 100] | 0 at the origin | +//! | [`BentCigar`] | 2 or more (30) | [−100, 100] | 0 at the origin | +//! | [`Discus`] | 2 or more (30) | [−100, 100] | 0 at the origin | +//! | [`DifferentPowers`] | 2 or more (30) | [−5, 5] | 0 at the origin | +//! | [`BucheRastrigin`] | 2 or more (30) | [−5, 5] | 0 at the origin | +//! | [`NonContinuousRastrigin`] | any (30) | [−5.12, 5.12] | 0 at the origin | +//! | [`Weierstrass`] | any (30) | [−0.5, 0.5] | 0 at the origin | +//! | [`Katsuura`] | any (30) | [−5, 5] | 0 at the origin, and wherever every gene is a multiple of 1/2 | +//! | [`HappyCat`] | any (30) | [−5, 5] | 0 at (−1, …, −1) | +//! | [`HgBat`] | any (30) | [−5, 5] | 0 at (−1, …, −1) | +//! | [`SchafferF7`] | 2 or more (30) | [−100, 100] | 0 at the origin | +//! | [`RotatedHyperEllipsoid`] | any (30) | [−65.536, 65.536] | 0 at the origin | +//! +//! Two wrappers make instances of any of them, as the CEC and BBOB suites do: [`Shifted`] moves +//! the optimum to a point drawn from a seed, and [`Rotated`] turns the function about its +//! optimum by an orthogonal matrix drawn from a seed, so that the genes interact. The shifted and +//! the shifted rotated Rastrigin of CEC 2005 (F9 and F10) are +//! `Shifted::new(Rastrigin::new(n), seed)` and `Rotated::new(Shifted::new(Rastrigin::new(n), seed), seed)`, +//! with genoxide's own shift and matrix rather than the report's data files. //! //! The classic functions but [`Eggholder`], [`Schwefel2_21`] and [`Schwefel2_22`], which aren't //! differentiable everywhere, supply their analytic gradient to the algorithms that want one (see @@ -112,6 +136,22 @@ //! optimisation problems. *International Journal of Mathematical Modelling and Numerical //! Optimisation* 4(2): 150-194. arXiv:1308.4008 //! +//! The functions of the CEC competitions and of BBOB are taken from their reports, which define +//! them: +//! +//! - Suganthan, P. N., Hansen, N., Liang, J. J., Deb, K., Chen, Y.-P., Auger, A. and Tiwari, S. +//! (2005). *Problem Definitions and Evaluation Criteria for the CEC 2005 Special Session on +//! Real-Parameter Optimization.* Nanyang Technological University and KanGAL report 2005005 +//! - Hansen, N., Finck, S., Ros, R. and Auger, A. (2009). *Real-Parameter Black-Box Optimization +//! Benchmarking 2009: Noiseless Functions Definitions.* INRIA research report RR-6829 +//! - Liang, J. J., Qu, B. Y. and Suganthan, P. N. (2013). *Problem Definitions and Evaluation +//! Criteria for the CEC 2014 Special Session and Competition on Single Objective +//! Real-Parameter Numerical Optimization.* Zhengzhou University and Nanyang Technological +//! University, technical report 201311 +//! - Awad, N. H., Ali, M. Z., Suganthan, P. N., Liang, J. J. and Qu, B. Y. (2016). *Problem +//! Definitions and Evaluation Criteria for the CEC 2017 Special Session and Competition on +//! Single Objective Real-Parameter Numerical Optimization.* Nanyang Technological University +//! //! Optima not given to full precision by the sources are derived from the formulas, and the docs //! say how. //! @@ -125,6 +165,7 @@ mod classic; pub mod control; pub mod engineering; mod gradients; +mod transform; pub use classic::{ Ackley, AxisParallelEllipsoid, Branin, GoldsteinPrice, Griewank, Himmelblau, Levy, Michalewicz, @@ -135,7 +176,13 @@ pub use classic::{ Beale, Bohachevsky1, Bohachevsky2, Bohachevsky3, Booth, DixonPrice, Kowalik, Langermann, Matyas, Powell, Schwefel2_21, Schwefel2_22, ShekelFoxholes, ThreeHumpCamel, Trid, }; +pub use classic::{ + BentCigar, BucheRastrigin, DifferentPowers, Discus, HappyCat, HgBat, HighConditionedElliptic, + Katsuura, NonContinuousRastrigin, Penalized1, Penalized2, Quartic, RotatedHyperEllipsoid, + SchafferF7, Step, SumOfDifferentPowers, Weierstrass, +}; pub use classic::{Easom, Eggholder, Hartmann3, Hartmann6, SchafferF6, Shekel5, Shekel7, Shekel10}; +pub use transform::{Rotated, Shifted}; use crate::constraint::{at_most, equal}; use crate::engine::{Extras, FitnessFunction, IntoFitness, Provided}; @@ -479,6 +526,23 @@ pub fn all() -> Vec> { boxed(Langermann), boxed(ShekelFoxholes), boxed(Kowalik), + boxed(SumOfDifferentPowers::default()), + boxed(Step::default()), + boxed(Quartic::default()), + boxed(Penalized1::default()), + boxed(Penalized2::default()), + boxed(HighConditionedElliptic::default()), + boxed(BentCigar::default()), + boxed(Discus::default()), + boxed(DifferentPowers::default()), + boxed(BucheRastrigin::default()), + boxed(NonContinuousRastrigin::default()), + boxed(Weierstrass::default()), + boxed(Katsuura::default()), + boxed(HappyCat::default()), + boxed(HgBat::default()), + boxed(SchafferF7::default()), + boxed(RotatedHyperEllipsoid::default()), boxed(cec2006::G01), boxed(cec2006::G02), boxed(cec2006::G03::default()), @@ -523,7 +587,7 @@ mod tests { #[test] fn the_registry_describes_every_problem() { let problems = all(); - assert_eq!(problems.len(), 71); + assert_eq!(problems.len(), 88); let names: HashSet<_> = problems.iter().map(|problem| problem.name()).collect(); assert_eq!(names.len(), problems.len(), "names are unique"); let mut rng = StreamRng::seed_from_u64(0); diff --git a/src/problems/classic.rs b/src/problems/classic.rs index 464a6898..53c45a7c 100644 --- a/src/problems/classic.rs +++ b/src/problems/classic.rs @@ -2481,6 +2481,930 @@ impl Problem for Kowalik { } } +// ---- the CEC and BBOB functions, and the other scalable functions of batch 10b ---------------- + +const YAO_LIU_LIN: &str = "Yao, X., Liu, Y. and Lin, G. (1999). Evolutionary programming made \ + faster. IEEE Transactions on Evolutionary Computation 3(2): 82-102."; +const YAO_LIU_LIN_URL: &str = "https://doi.org/10.1109/4235.771163"; +const MOLGA_SMUTNICKI: &str = + "Molga, M. and Smutnicki, C. (2005). Test functions for optimization needs."; +const CEC_2005: &str = "Suganthan, P. N., Hansen, N., Liang, J. J., Deb, K., Chen, Y.-P., Auger, \ + A. and Tiwari, S. (2005). Problem Definitions and Evaluation Criteria for \ + the CEC 2005 Special Session on Real-Parameter Optimization. Technical \ + report, Nanyang Technological University, Singapore, and KanGAL report \ + 2005005, IIT Kanpur."; +const CEC_2005_URL: &str = "https://github.com/P-N-Suganthan/CEC2005"; +const CEC_2014: &str = "Liang, J. J., Qu, B. Y. and Suganthan, P. N. (2013). Problem Definitions \ + and Evaluation Criteria for the CEC 2014 Special Session and Competition \ + on Single Objective Real-Parameter Numerical Optimization. Technical \ + report 201311, Computational Intelligence Laboratory, Zhengzhou \ + University, and Nanyang Technological University, Singapore."; +const CEC_2014_URL: &str = "https://github.com/P-N-Suganthan/CEC2014"; +const BBOB: &str = "Hansen, N., Finck, S., Ros, R. and Auger, A. (2009). Real-Parameter \ + Black-Box Optimization Benchmarking 2009: Noiseless Functions Definitions. \ + Research report RR-6829, INRIA."; +const BBOB_URL: &str = "https://hal.inria.fr/inria-00362633"; + +// the Problem of a scalable function with uniform bounds and a proven minimum 0 at `at` in every +// gene +macro_rules! scalable_problem { + ( + $name:ident, bounds: $low:literal ..= $high:literal, at: $at:expr, + reference: $reference:expr $(, url: $url:expr)? $(,)? + ) => { + impl Problem for $name { + type Representation = Real; + + fn name(&self) -> &'static str { + stringify!($name) + } + + fn representation(&self) -> Real { + uniform(self.dimensions, $low, $high) + } + + fn optimum(&self) -> Option> { + Some(Optimum::proven(0.0, vec![repeated(self.dimensions, $at)])) + } + + fn reference(&self) -> &'static str { + $reference + } + + $( + fn reference_url(&self) -> Option<&'static str> { + Some($url) + } + )? + } + }; +} + +scalable!( + /// The sum of different powers, `Σ |xᵢ|^(i+1)` (i from 1): unimodal, and the flatter near the + /// minimum the later the gene. + /// + /// Bounds [−1, 1]ⁿ; minimum 0 at the origin; 30 dimensions by default. + /// + /// Its origin is unknown: definition and bounds as Molga and Smutnicki (2005, section 2.8) + /// give them. Not yet checked against an original + /// ([#168](https://github.com/tachsin/genoxide/issues/168)). + SumOfDifferentPowers, + "SumOfDifferentPowers", + 1, + 30 +); + +impl FitnessFunction for SumOfDifferentPowers { + type Output = f64; + + fn evaluate(&self, x: &Reals) -> f64 { + x.iter() + .enumerate() + .map(|(i, xi)| math::powi(xi.abs(), i as i32 + 2)) + .sum() + } +} + +scalable_problem!( + SumOfDifferentPowers, + bounds: -1.0..=1.0, + at: 0.0, + reference: MOLGA_SMUTNICKI, +); + +scalable!( + /// The step function, `Σ ⌊xᵢ + 0.5⌋²`: a sphere of flat steps, whose gradient is 0 almost + /// everywhere. + /// + /// Bounds [−100, 100]ⁿ; minimum 0 on the whole cube [−0.5, 0.5)ⁿ, here at the origin; 30 + /// dimensions by default. + /// + /// Yao, X., Liu, Y. and Lin, G. (1999). Evolutionary programming made faster. *IEEE + /// Transactions on Evolutionary Computation* 3(2): 82-102, function f6 (table I and the + /// appendix, read): its definition, bounds and dimension. De Jong's (1975) F3, which it is + /// often credited to, is another step function, `Σ ⌊xᵢ⌋` on [−5.12, 5.12]⁵, with its + /// minimum at a corner. + Step, + "Step", + 1, + 30 +); + +impl FitnessFunction for Step { + type Output = f64; + + fn evaluate(&self, x: &Reals) -> f64 { + x.iter() + .map(|xi| { + let step = (xi + 0.5).floor(); + step * step + }) + .sum() + } +} + +scalable_problem!( + Step, + bounds: -100.0..=100.0, + at: 0.0, + reference: YAO_LIU_LIN, + url: YAO_LIU_LIN_URL, +); + +/// The quartic function, `Σ i xᵢ⁴` (i from 1), De Jong's F4, without noise or with it. +/// +/// Bounds [−1.28, 1.28]ⁿ; minimum 0 at the origin, without noise; 30 dimensions by default. The +/// function is flat near the minimum: at 0.01 from it in every gene, it's below 10⁻⁵. +/// +/// Yao, Liu and Lin (1999, f7) add a uniform random number in [0, 1) to each evaluation, so that +/// an algorithm can't use differences smaller than the noise. A fitness function is deterministic +/// in genoxide (a copy of a genome inherits its fitness), so [`noisy`](Quartic::noisy) draws the +/// noise from a generator seeded with the genome's bits: the same genome always gets the same +/// noise, and two genomes, however close, independent noises. Its minimum isn't known (it's the +/// smallest noise near the origin), so [`optimum`](Problem::optimum) is `None`. +/// +/// De Jong, K. A. (1975). *An Analysis of the Behavior of a Class of Genetic Adaptive Systems.* +/// PhD thesis, University of Michigan, function F4, with Gaussian noise, in 30 dimensions on +/// [−1.28, 1.28]: as restated by Yao, Liu and Lin (1999, f7, table I and the appendix, read), +/// whose definition, uniform noise and bounds these are. Not yet checked against De Jong's +/// thesis ([#168](https://github.com/tachsin/genoxide/issues/168)). +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub struct Quartic { + dimensions: usize, + noisy: bool, +} + +impl Quartic { + /// The function in `dimensions` dimensions, at least 1, without noise. + /// + /// # Panics + /// + /// If `dimensions` is 0. + pub fn new(dimensions: usize) -> Self { + assert!( + dimensions >= 1, + "Quartic needs at least 1 dimensions, got {dimensions}" + ); + Self { + dimensions, + noisy: false, + } + } + + /// The function in `dimensions` dimensions, at least 1, with Yao, Liu and Lin's uniform noise + /// in [0, 1), drawn from the genome. + /// + /// # Panics + /// + /// If `dimensions` is 0. + pub fn noisy(dimensions: usize) -> Self { + Self { + noisy: true, + ..Self::new(dimensions) + } + } + + /// The number of dimensions. + pub fn dimensions(&self) -> usize { + self.dimensions + } + + /// Whether the evaluations have noise. + pub fn is_noisy(&self) -> bool { + self.noisy + } +} + +impl Default for Quartic { + /// The function in 30 dimensions, without noise. + fn default() -> Self { + Self::new(30) + } +} + +// SplitMix64's finalizer: a well-mixed 64-bit value from another +fn mix(mut z: u64) -> u64 { + z = (z ^ (z >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9); + z = (z ^ (z >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB); + z ^ (z >> 31) +} + +// a number in [0, 1) that depends only on the bits of `x` +fn genome_noise(x: &Reals) -> f64 { + let hash = x.iter().fold(0x9E37_79B9_7F4A_7C15, |hash, xi| { + mix(hash ^ xi.to_bits()).wrapping_add(0x9E37_79B9_7F4A_7C15) + }); + (mix(hash) >> 11) as f64 / (1u64 << 53) as f64 +} + +impl FitnessFunction for Quartic { + type Output = f64; + + fn evaluate(&self, x: &Reals) -> f64 { + let quartic: f64 = x + .iter() + .enumerate() + .map(|(i, xi)| (i + 1) as f64 * math::powi(*xi, 4)) + .sum(); + if self.noisy { + quartic + genome_noise(x) + } else { + quartic + } + } +} + +impl Problem for Quartic { + type Representation = Real; + + fn name(&self) -> &'static str { + "Quartic" + } + + fn representation(&self) -> Real { + uniform(self.dimensions, -1.28, 1.28) + } + + /// 0 at the origin without noise; not known with noise. + fn optimum(&self) -> Option> { + (!self.noisy).then(|| Optimum::proven(0.0, vec![repeated(self.dimensions, 0.0)])) + } + + fn reference(&self) -> &'static str { + "De Jong, K. A. (1975). An Analysis of the Behavior of a Class of Genetic Adaptive \ + Systems. PhD thesis, University of Michigan. As restated in Yao, X., Liu, Y. and Lin, G. \ + (1999). Evolutionary programming made faster. IEEE Transactions on Evolutionary \ + Computation 3(2): 82-102." + } + + fn reference_url(&self) -> Option<&'static str> { + Some("https://hdl.handle.net/2027.42/4507") + } +} + +// the penalty u(x, a, k, m) of Yao, Liu and Lin's penalized functions: k (|x| − a)^m outside +// [−a, a], 0 inside +fn penalty(x: f64, a: f64, k: f64, m: i32) -> f64 { + if x.abs() > a { + k * math::powi(x.abs() - a, m) + } else { + 0.0 + } +} + +// sin² x +fn sin_squared(x: f64) -> f64 { + math::powi(math::sin(x), 2) +} + +scalable!( + /// The first generalized penalized function: with `yᵢ = 1 + (xᵢ + 1) / 4`, + /// `(π / n) {10 sin²(πy₁) + Σᵢ₌₁ⁿ⁻¹ (yᵢ − 1)² [1 + 10 sin²(πyᵢ₊₁)] + (yₙ − 1)²} + /// + Σ u(xᵢ, 10, 100, 4)`, where `u(x, a, k, m)` is `k (|x| − a)^m` outside [−a, a] and 0 + /// inside: Levy's function with a penalty beyond ±10. + /// + /// Bounds [−50, 50]ⁿ; minimum 0 at (−1, …, −1), where every yᵢ is 1 (every term is at least + /// 0); 30 dimensions by default. + /// + /// Yao, X., Liu, Y. and Lin, G. (1999). Evolutionary programming made faster. *IEEE + /// Transactions on Evolutionary Computation* 3(2): 82-102, function f12 (table I and the + /// appendix, read), whose appendix misprints the minimizer as (1, …, 1). The function is + /// usually credited to Levy and Montalvo's tunneling papers (1985), not read. + Penalized1, + "Penalized1", + 1, + 30 +); + +impl FitnessFunction for Penalized1 { + type Output = f64; + + fn evaluate(&self, x: &Reals) -> f64 { + let n = x.len(); + let y: Vec = x.iter().map(|xi| 1.0 + (xi + 1.0) / 4.0).collect(); + let (Some(&first), Some(&last)) = (y.first(), y.last()) else { + return 0.0; + }; + let middle: f64 = y + .windows(2) + .map(|pair| math::powi(pair[0] - 1.0, 2) * (1.0 + 10.0 * sin_squared(PI * pair[1]))) + .sum(); + let levy = 10.0 * sin_squared(PI * first) + middle + math::powi(last - 1.0, 2); + let penalties: f64 = x.iter().map(|&xi| penalty(xi, 10.0, 100.0, 4)).sum(); + PI / n as f64 * levy + penalties + } +} + +scalable_problem!( + Penalized1, + bounds: -50.0..=50.0, + at: -1.0, + reference: YAO_LIU_LIN, + url: YAO_LIU_LIN_URL, +); + +scalable!( + /// The second generalized penalized function, + /// `0.1 {sin²(3πx₁) + Σᵢ₌₁ⁿ⁻¹ (xᵢ − 1)² [1 + sin²(3πxᵢ₊₁)] + (xₙ − 1)² [1 + sin²(2πxₙ)]} + /// + Σ u(xᵢ, 5, 100, 4)`, where `u(x, a, k, m)` is `k (|x| − a)^m` outside [−a, a] and 0 + /// inside. + /// + /// Bounds [−50, 50]ⁿ; minimum 0 at (1, …, 1) (every term is at least 0); 30 dimensions by + /// default. + /// + /// Yao, X., Liu, Y. and Lin, G. (1999). Evolutionary programming made faster. *IEEE + /// Transactions on Evolutionary Computation* 3(2): 82-102, function f13 (table I and the + /// appendix, read). Table I prints the last term's `(xₙ − 1)` without its square, which the + /// appendix has: without it, the function would have no minimum at (1, …, 1). Usually + /// credited to Levy and Montalvo's tunneling papers (1985), not read. + Penalized2, + "Penalized2", + 1, + 30 +); + +impl FitnessFunction for Penalized2 { + type Output = f64; + + fn evaluate(&self, x: &Reals) -> f64 { + let (Some(&first), Some(&last)) = (x.first(), x.last()) else { + return 0.0; + }; + let middle: f64 = x + .windows(2) + .map(|pair| math::powi(pair[0] - 1.0, 2) * (1.0 + sin_squared(3.0 * PI * pair[1]))) + .sum(); + let end = math::powi(last - 1.0, 2) * (1.0 + sin_squared(2.0 * PI * last)); + let penalties: f64 = x.iter().map(|&xi| penalty(xi, 5.0, 100.0, 4)).sum(); + 0.1 * (sin_squared(3.0 * PI * first) + middle + end) + penalties + } +} + +scalable_problem!( + Penalized2, + bounds: -50.0..=50.0, + at: 1.0, + reference: YAO_LIU_LIN, + url: YAO_LIU_LIN_URL, +); + +// 10⁶ to the power (i − 1) / (n − 1), for gene i from 0: from 1 for the first gene to 10⁶ for +// the last +fn conditioning(i: usize, n: usize) -> f64 { + math::powf(1e6, i as f64 / (n - 1) as f64) +} + +scalable!( + /// The high-conditioned elliptic function, `Σ (10⁶)^((i−1)/(n−1)) xᵢ²` (i from 1): an + /// ellipsoid whose axes grow from 1 to 10³ in length, so that its condition number is 10⁶. + /// + /// Bounds [−100, 100]ⁿ; minimum 0 at the origin; at least 2 dimensions, 30 by default. + /// + /// Suganthan, P. N., Hansen, N., Liang, J. J., Deb, K., Chen, Y.-P., Auger, A. and Tiwari, S. + /// (2005). *Problem Definitions and Evaluation Criteria for the CEC 2005 Special Session on + /// Real-Parameter Optimization*, function F3 (read), shifted and rotated there: its + /// definition and bounds, as the CEC 2014 and 2017 reports' basic function. BBOB's f2 and + /// f10 (Hansen, Finck, Ros and Auger 2009) are the same ellipsoid, with an oscillation + /// T_osz that genoxide doesn't apply; [`Shifted`](super::Shifted) and + /// [`Rotated`](super::Rotated) give CEC 2005's form. + HighConditionedElliptic, + "HighConditionedElliptic", + 2, + 30 +); + +impl FitnessFunction for HighConditionedElliptic { + type Output = f64; + + fn evaluate(&self, x: &Reals) -> f64 { + let n = x.len(); + x.iter() + .enumerate() + .map(|(i, xi)| conditioning(i, n) * xi * xi) + .sum() + } +} + +scalable_problem!( + HighConditionedElliptic, + bounds: -100.0..=100.0, + at: 0.0, + reference: CEC_2005, + url: CEC_2005_URL, +); + +scalable!( + /// The bent cigar, `x₁² + 10⁶ Σᵢ₌₂ⁿ xᵢ²`: a long narrow ridge along the first axis, a + /// thousand times wider than it's high, that a search has to follow to the minimum. + /// + /// Bounds [−100, 100]ⁿ; minimum 0 at the origin; at least 2 dimensions, 30 by default. + /// + /// Hansen, N., Finck, S., Ros, R. and Auger, A. (2009). *Real-Parameter Black-Box + /// Optimization Benchmarking 2009: Noiseless Functions Definitions.* INRIA research report + /// RR-6829, function f12 (read), which composes it with an asymmetric transformation and two + /// rotations. This is its plain form and bounds, the basic function of the CEC 2014 report + /// (Liang, Qu and Suganthan 2013, function 2, read) and the CEC 2017 report (Awad et al. + /// 2016, function 1, read), which shift and rotate it as [`Shifted`](super::Shifted) and + /// [`Rotated`](super::Rotated) do. + BentCigar, + "BentCigar", + 2, + 30 +); + +impl FitnessFunction for BentCigar { + type Output = f64; + + fn evaluate(&self, x: &Reals) -> f64 { + let Some((first, rest)) = x.split_first() else { + return 0.0; + }; + first * first + 1e6 * rest.iter().map(|xi| xi * xi).sum::() + } +} + +scalable_problem!( + BentCigar, + bounds: -100.0..=100.0, + at: 0.0, + reference: BBOB, + url: BBOB_URL, +); + +scalable!( + /// The discus, `10⁶ x₁² + Σᵢ₌₂ⁿ xᵢ²`: a sphere squashed along the first axis, so that one + /// direction is a thousand times more sensitive than the others. + /// + /// Bounds [−100, 100]ⁿ; minimum 0 at the origin; at least 2 dimensions, 30 by default. + /// + /// Hansen, N., Finck, S., Ros, R. and Auger, A. (2009). *Real-Parameter Black-Box + /// Optimization Benchmarking 2009: Noiseless Functions Definitions.* INRIA research report + /// RR-6829, function f11 (read), which composes it with an oscillation and a rotation. This + /// is its plain form and bounds, the basic function of the CEC 2014 report (Liang, Qu and + /// Suganthan 2013, function 3, read) and the CEC 2017 report (Awad et al. 2016, function 11, + /// read). + Discus, + "Discus", + 2, + 30 +); + +impl FitnessFunction for Discus { + type Output = f64; + + fn evaluate(&self, x: &Reals) -> f64 { + let Some((first, rest)) = x.split_first() else { + return 0.0; + }; + 1e6 * first * first + rest.iter().map(|xi| xi * xi).sum::() + } +} + +scalable_problem!( + Discus, + bounds: -100.0..=100.0, + at: 0.0, + reference: BBOB, + url: BBOB_URL, +); + +scalable!( + /// BBOB's different powers, `√(Σ |xᵢ|^(2 + 4 (i−1)/(n−1)))` (i from 1): the exponents grow + /// from 2 to 6, so the genes' sensitivities drift further apart the nearer the minimum. + /// + /// Bounds [−5, 5]ⁿ; minimum 0 at the origin; at least 2 dimensions, 30 by default. + /// + /// Hansen, N., Finck, S., Ros, R. and Auger, A. (2009). *Real-Parameter Black-Box + /// Optimization Benchmarking 2009: Noiseless Functions Definitions.* INRIA research report + /// RR-6829, function f14 (read): its definition, without the rotation, and its search + /// domain. Not the [`SumOfDifferentPowers`], `Σ |xᵢ|^(i+1)`. + DifferentPowers, + "DifferentPowers", + 2, + 30 +); + +impl FitnessFunction for DifferentPowers { + type Output = f64; + + fn evaluate(&self, x: &Reals) -> f64 { + let n = x.len(); + let exponent = |i: usize| 2.0 + 4.0 * i as f64 / (n.max(2) - 1) as f64; + x.iter() + .enumerate() + .map(|(i, xi)| math::powf(xi.abs(), exponent(i))) + .sum::() + .sqrt() + } +} + +scalable_problem!( + DifferentPowers, + bounds: -5.0..=5.0, + at: 0.0, + reference: BBOB, + url: BBOB_URL, +); + +// BBOB's oscillation T_osz of one value: the identity, but for small smooth wiggles that scale +// with the value +fn oscillation(x: f64) -> f64 { + if x == 0.0 { + return 0.0; + } + let logarithm = math::ln(x.abs()); + let (c1, c2) = if x > 0.0 { (10.0, 7.9) } else { (5.5, 3.1) }; + let wiggle = 0.049 * (math::sin(c1 * logarithm) + math::sin(c2 * logarithm)); + x.signum() * math::exp(logarithm + wiggle) +} + +scalable!( + /// The Büche-Rastrigin function, `10 (n − Σ cos 2πzᵢ) + Σ zᵢ² + 100 Σ max(0, |xᵢ| − 5)²`, + /// with `zᵢ = sᵢ T_osz(xᵢ)`: Rastrigin's function made asymmetric, with steeper walls on the + /// positive side of every other gene. + /// + /// T_osz is BBOB's oscillation, `sign(x) exp(x̂ + 0.049 (sin c₁x̂ + sin c₂x̂))` with + /// `x̂ = ln |x|` (and T_osz(0) = 0), c₁ = 10 and c₂ = 7.9 for x > 0, c₁ = 5.5 and c₂ = 3.1 + /// otherwise. The scale `sᵢ` is `10^((i−1) / (2 (n−1)))` (i from 1), times 10 where + /// T_osz(xᵢ) > 0 and i is odd. + /// + /// Bounds [−5, 5]ⁿ; minimum 0 at the origin; at least 2 dimensions, 30 by default. + /// + /// Hansen, N., Finck, S., Ros, R. and Auger, A. (2009). *Real-Parameter Black-Box + /// Optimization Benchmarking 2009: Noiseless Functions Definitions.* INRIA research report + /// RR-6829, function f4 (read): its definition, with its optimum at the origin and no offset + /// (xᵒᵖᵗ = 0, fᵒᵖᵗ = 0), and its search domain. The penalty is 0 within the bounds. + BucheRastrigin, + "BucheRastrigin", + 2, + 30 +); + +impl FitnessFunction for BucheRastrigin { + type Output = f64; + + fn evaluate(&self, x: &Reals) -> f64 { + let n = x.len(); + let mut cosines = 0.0; + let mut squares = 0.0; + let mut penalty = 0.0; + for (i, &xi) in x.iter().enumerate() { + let oscillated = oscillation(xi); + let mut scale = math::powf(10.0, 0.5 * i as f64 / (n.max(2) - 1) as f64); + // i from 0 here: the odd genes from 1 are the even ones from 0 + if oscillated > 0.0 && i % 2 == 0 { + scale *= 10.0; + } + let z = scale * oscillated; + cosines += math::cos(2.0 * PI * z); + squares += z * z; + penalty += math::powi((xi.abs() - 5.0).max(0.0), 2); + } + 10.0 * (n as f64 - cosines) + squares + 100.0 * penalty + } +} + +scalable_problem!( + BucheRastrigin, + bounds: -5.0..=5.0, + at: 0.0, + reference: BBOB, + url: BBOB_URL, +); + +scalable!( + /// The non-continuous Rastrigin function, `Σ (yᵢ² − 10 cos 2πyᵢ + 10)`, where `yᵢ = xᵢ` if + /// `|xᵢ| < 1/2` and `round(2xᵢ) / 2` otherwise: Rastrigin's function, flat between the + /// half-integers away from the origin, with as many local minima. + /// + /// Bounds [−5.12, 5.12]ⁿ; minimum 0 at the origin; 30 dimensions by default. `round` rounds + /// halves away from 0, as MATLAB's does. + /// + /// Liang, J. J., Qin, A. K., Suganthan, P. N. and Baskar, S. (2006). Comprehensive learning + /// particle swarm optimizer for global optimization of multimodal functions. *IEEE + /// Transactions on Evolutionary Computation* 10(3): 281-295, function f7 and table II + /// (read): its definition, bounds and minimum. The CEC 2017 report composes it with BBOB's + /// transformations, which genoxide doesn't apply. + NonContinuousRastrigin, + "NonContinuousRastrigin", + 1, + 30 +); + +impl FitnessFunction for NonContinuousRastrigin { + type Output = f64; + + fn evaluate(&self, x: &Reals) -> f64 { + x.iter() + .map(|&xi| { + let y = if xi.abs() < 0.5 { + xi + } else { + (2.0 * xi).round() / 2.0 + }; + y * y - 10.0 * math::cos(2.0 * PI * y) + 10.0 + }) + .sum() + } +} + +scalable_problem!( + NonContinuousRastrigin, + bounds: -5.12..=5.12, + at: 0.0, + reference: "Liang, J. J., Qin, A. K., Suganthan, P. N. and Baskar, S. (2006). Comprehensive \ + learning particle swarm optimizer for global optimization of multimodal \ + functions. IEEE Transactions on Evolutionary Computation 10(3): 281-295.", + url: "https://doi.org/10.1109/TEVC.2005.857610", +); + +// Weierstrass's a, b and k_max +const WEIERSTRASS_A: f64 = 0.5; +const WEIERSTRASS_B: f64 = 3.0; +const WEIERSTRASS_TERMS: i32 = 21; + +// Σₖ aᵏ cos(2π bᵏ (x + 0.5)), k from 0 to k_max +fn weierstrass_sum(x: f64) -> f64 { + (0..WEIERSTRASS_TERMS) + .map(|k| { + let (ak, bk) = (math::powi(WEIERSTRASS_A, k), math::powi(WEIERSTRASS_B, k)); + ak * math::cos(2.0 * PI * bk * (x + 0.5)) + }) + .sum() +} + +scalable!( + /// The Weierstrass function, `Σᵢ Σₖ aᵏ cos(2π bᵏ (xᵢ + 0.5)) − n Σₖ aᵏ cos(π bᵏ)` with + /// a = 0.5, b = 3 and k from 0 to 20: continuous, but differentiable only on a set of + /// points, a fractal of ripples within ripples. + /// + /// Bounds [−0.5, 0.5]ⁿ; minimum 0 at the origin (at every integer point without bounds); + /// 30 dimensions by default. Each gene's sum is at least −Σ aᵏ, reached where every cosine + /// is −1, at the integers, and the second term is −n Σ aᵏ, since every bᵏ is odd. + /// + /// Suganthan, P. N., Hansen, N., Liang, J. J., Deb, K., Chen, Y.-P., Auger, A. and Tiwari, S. + /// (2005). *Problem Definitions and Evaluation Criteria for the CEC 2005 Special Session on + /// Real-Parameter Optimization*, function F11 (read), shifted and rotated there: its + /// definition, constants and bounds, which Liang, Qin, Suganthan and Baskar (2006, f5) and + /// the CEC 2014 report restate. BBOB's f16 (Hansen et al. 2009) is another form, with 12 + /// terms and a cube. After Weierstrass's (1872) continuous nowhere-differentiable function. + Weierstrass, + "Weierstrass", + 1, + 30 +); + +impl FitnessFunction for Weierstrass { + type Output = f64; + + fn evaluate(&self, x: &Reals) -> f64 { + // the same sum at 0, so that the minimum is exactly 0 + let offset = x.len() as f64 * weierstrass_sum(0.0); + x.iter().map(|&xi| weierstrass_sum(xi)).sum::() - offset + } +} + +scalable_problem!( + Weierstrass, + bounds: -0.5..=0.5, + at: 0.0, + reference: CEC_2005, + url: CEC_2005_URL, +); + +scalable!( + /// Katsuura's function, + /// `(10 / n²) Πᵢ (1 + i Σⱼ₌₁³² |2ʲxᵢ − round(2ʲxᵢ)| / 2ʲ)^(10 / n^1.2) − 10 / n²` + /// (i from 1): rugged everywhere, continuous but nowhere differentiable, and highly + /// repetitive. + /// + /// Bounds [−5, 5]ⁿ; minimum 0 at the origin, and at every point whose genes are multiples + /// of 1/2 (where every term of the inner sums is 0): 21ⁿ global minima in the box. 30 + /// dimensions by default. + /// + /// Hansen, N., Finck, S., Ros, R. and Auger, A. (2009). *Real-Parameter Black-Box + /// Optimization Benchmarking 2009: Noiseless Functions Definitions.* INRIA research report + /// RR-6829, function f23 (read), "based on the idea" of Katsuura, H. (1991). Continuous + /// nowhere-differentiable functions: an application of contraction mappings. *The American + /// Mathematical Monthly* 98(5): 411-416 (not read). BBOB adds a penalty outside [−5, 5]ⁿ, + /// 0 within it, and a rotation and scaling; this is the plain form, the basic function of + /// the CEC 2014 report (Liang, Qu and Suganthan 2013, function 10, read), with BBOB's + /// search domain (the CEC 2014 report scales its [−100, 100] to the same [−5, 5]). + Katsuura, + "Katsuura", + 1, + 30 +); + +impl FitnessFunction for Katsuura { + type Output = f64; + + fn evaluate(&self, x: &Reals) -> f64 { + let n = x.len() as f64; + let exponent = 10.0 / math::powf(n, 1.2); + let product: f64 = x + .iter() + .enumerate() + .map(|(i, &xi)| { + let sum: f64 = (1..=32) + .map(|j| { + let power = math::powi(2.0, j); + let scaled = power * xi; + (scaled - scaled.round()).abs() / power + }) + .sum(); + math::powf(1.0 + (i + 1) as f64 * sum, exponent) + }) + .product(); + 10.0 / (n * n) * product - 10.0 / (n * n) + } +} + +scalable_problem!( + Katsuura, + bounds: -5.0..=5.0, + at: 0.0, + reference: BBOB, + url: BBOB_URL, +); + +scalable!( + /// HappyCat, `|Σ xᵢ² − n|^(1/4) + (½ Σ xᵢ² + Σ xᵢ) / n + ½`: a sphere of radius √n where the + /// first term is 0, a groove that curves around to the minimum, and a slope that leads along + /// it. + /// + /// Bounds [−5, 5]ⁿ; minimum 0 at (−1, …, −1), the only one: the second part is + /// `Σ (xᵢ + 1)² / (2n)`, 0 only there, where the first is 0 too. 30 dimensions by default. + /// + /// Beyer, H.-G. and Finck, S. (2012). HappyCat: a simple function class where well-known + /// direct search algorithms do fail. *Parallel Problem Solving from Nature, PPSN XII*, LNCS + /// 7491: 367-376, which couldn't be read. Its function has a parameter α that shapes the + /// groove, and its experiments use α = 1/8 (as later papers that cite it say); if α is the + /// exponent of `(Σ xᵢ² − n)²`, as it's usually written, α = 1/8 is this function's 1/4 on the + /// absolute value, which couldn't be confirmed. Definition as in the CEC 2014 report (Liang, + /// Qu and Suganthan 2013, function 11, read), which cites Beyer and Finck and scales its + /// search space [−100, 100] by 5/100, to this one, [−5, 5]. Not yet checked against the + /// original ([#168](https://github.com/tachsin/genoxide/issues/168)). + HappyCat, + "HappyCat", + 1, + 30 +); + +// Σ xᵢ² and Σ xᵢ +fn squares_and_sum(x: &Reals) -> (f64, f64) { + x.iter().fold((0.0, 0.0), |(squares, sum), xi| { + (squares + xi * xi, sum + xi) + }) +} + +impl FitnessFunction for HappyCat { + type Output = f64; + + fn evaluate(&self, x: &Reals) -> f64 { + let n = x.len() as f64; + let (squares, sum) = squares_and_sum(x); + math::powf((squares - n).abs(), 0.25) + (0.5 * squares + sum) / n + 0.5 + } +} + +scalable_problem!( + HappyCat, + bounds: -5.0..=5.0, + at: -1.0, + reference: "Beyer, H.-G. and Finck, S. (2012). HappyCat: a simple function class where \ + well-known direct search algorithms do fail. Parallel Problem Solving from \ + Nature, PPSN XII, LNCS 7491: 367-376.", + url: "https://doi.org/10.1007/978-3-642-32937-1_37", +); + +scalable!( + /// HGBat, `|(Σ xᵢ²)² − (Σ xᵢ)²|^(1/2) + (½ Σ xᵢ² + Σ xᵢ) / n + ½`: HappyCat's relative, whose + /// first term is 0 on a cone, `‖x‖² = |Σ xᵢ|`, instead of a sphere. + /// + /// Bounds [−5, 5]ⁿ; minimum 0 at (−1, …, −1), the only one: the second part is + /// `Σ (xᵢ + 1)² / (2n)`, 0 only there, where the first is 0 too. 30 dimensions by default. + /// + /// Liang, J. J., Qu, B. Y. and Suganthan, P. N. (2013). *Problem Definitions and Evaluation + /// Criteria for the CEC 2014 Special Session and Competition on Single Objective + /// Real-Parameter Numerical Optimization.* Technical report 201311, Zhengzhou University and + /// Nanyang Technological University, function 12 (read): its definition, and its search space + /// [−100, 100] scaled by 5/100 to this one, [−5, 5]. The report gives no other source; it's + /// usually credited to Beyer and Finck too, whose paper couldn't be read. + HgBat, + "HgBat", + 1, + 30 +); + +impl FitnessFunction for HgBat { + type Output = f64; + + fn evaluate(&self, x: &Reals) -> f64 { + let n = x.len() as f64; + let (squares, sum) = squares_and_sum(x); + (squares * squares - sum * sum).abs().sqrt() + (0.5 * squares + sum) / n + 0.5 + } +} + +scalable_problem!( + HgBat, + bounds: -5.0..=5.0, + at: -1.0, + reference: CEC_2014, + url: CEC_2014_URL, +); + +scalable!( + /// Schaffer's F7, in n dimensions: + /// `((1 / (n − 1)) Σᵢ₌₁ⁿ⁻¹ √sᵢ (1 + sin²(50 sᵢ^(1/5))))²` with `sᵢ = √(xᵢ² + xᵢ₊₁²)`: rings + /// of ripples around the minimum, whose frequency and amplitude change with the distance. + /// + /// Bounds [−100, 100]ⁿ; minimum 0 at the origin; at least 2 dimensions, 30 by default. + /// + /// Schaffer, J. D., Caruana, R. A., Eshelman, L. J. and Das, R. (1989). A study of control + /// parameters affecting online performance of genetic algorithms for function optimization. + /// *Proceedings of the Third International Conference on Genetic Algorithms*, Morgan + /// Kaufmann: 51-60, which couldn't be read; its F7 has two dimensions. This n-dimensional + /// form is BBOB's f17 (Hansen, Finck, Ros and Auger 2009, read), without its transformations + /// and penalty; the bounds are Schaffer's F6's ([`SchafferF6`]). The CEC 2017 report + /// (Awad et al. 2016, function 19, read) prints `sin` for `sin²`, and scales its search space + /// to [−0.5, 0.5]. Not yet checked against the original + /// ([#168](https://github.com/tachsin/genoxide/issues/168)). + SchafferF7, + "SchafferF7", + 2, + 30 +); + +impl FitnessFunction for SchafferF7 { + type Output = f64; + + fn evaluate(&self, x: &Reals) -> f64 { + let pairs = x.len().saturating_sub(1).max(1) as f64; + let sum: f64 = x + .windows(2) + .map(|pair| { + let s = (pair[0] * pair[0] + pair[1] * pair[1]).sqrt(); + s.sqrt() * (1.0 + sin_squared(50.0 * math::powf(s, 0.2))) + }) + .sum(); + math::powi(sum / pairs, 2) + } +} + +scalable_problem!( + SchafferF7, + bounds: -100.0..=100.0, + at: 0.0, + reference: "Schaffer, J. D., Caruana, R. A., Eshelman, L. J. and Das, R. (1989). A study of \ + control parameters affecting online performance of genetic algorithms for \ + function optimization. Proceedings of the Third International Conference on \ + Genetic Algorithms, Morgan Kaufmann: 51-60.", +); + +scalable!( + /// The rotated hyper-ellipsoid, `Σᵢ Σⱼ≤ᵢ xⱼ²`, as Molga and Smutnicki (2005) define it. + /// + /// Despite its name, it isn't rotated: gene j appears in the n − j + 1 sums from i = j on, so + /// the function is `Σⱼ (n − j + 1) xⱼ²`, an axis-parallel ellipsoid whose weights fall from n + /// to 1 (the [`AxisParallelEllipsoid`] reversed). The ellipsoid rotated with respect to the + /// axes is Schwefel's problem 1.2, `Σᵢ (Σⱼ≤ᵢ xⱼ)²` ([`Schwefel1_2`]), which Molga and + /// Smutnicki describe; [`Rotated`](super::Rotated) rotates this one. + /// + /// Bounds [−65.536, 65.536]ⁿ; minimum 0 at the origin; 30 dimensions by default. + /// + /// Its origin is unknown: definition and bounds as Molga and Smutnicki (2005, section 2.3, + /// read) give them. Not yet checked against an original + /// ([#168](https://github.com/tachsin/genoxide/issues/168)). + RotatedHyperEllipsoid, + "RotatedHyperEllipsoid", + 1, + 30 +); + +impl FitnessFunction for RotatedHyperEllipsoid { + type Output = f64; + + fn evaluate(&self, x: &Reals) -> f64 { + let mut prefix = 0.0; + let mut sum = 0.0; + for xi in x.iter() { + prefix += xi * xi; + sum += prefix; + } + sum + } +} + +scalable_problem!( + RotatedHyperEllipsoid, + bounds: -65.536..=65.536, + at: 0.0, + reference: MOLGA_SMUTNICKI, +); + #[cfg(test)] mod tests { use super::*; @@ -3330,4 +4254,279 @@ mod tests { } } } + + // ---- batch 10b ---- + + #[test] + fn sum_of_different_powers() { + check_optimum(&SumOfDifferentPowers::new(5)); + // 1² + |−1|³ + 0.5⁴ + let problem = SumOfDifferentPowers::new(3); + assert_eq!(problem.evaluate(&at(&[1.0, -1.0, 0.5])), 2.0625); + assert_eq!(problem.representation().bounds()[2], -1.0..=1.0); + assert_eq!(SumOfDifferentPowers::default().dimensions(), 30); + } + + #[test] + fn step() { + check_optimum(&Step::new(5)); + let problem = Step::new(3); + // ⌊0.99⌋ = 0, ⌊0⌋ = 0, ⌊2⌋ = 2: the cube [−0.5, 0.5) is flat at 0 + assert_eq!(problem.evaluate(&at(&[0.49, -0.5, 1.5])), 4.0); + assert_eq!(problem.evaluate(&at(&[0.49, -0.5, 0.0])), 0.0); + // ⌊−0.01⌋ = −1 + assert_eq!(problem.evaluate(&at(&[-0.51, 0.0, 0.0])), 1.0); + assert_eq!(problem.representation().bounds()[0], -100.0..=100.0); + } + + #[test] + fn quartic() { + check_optimum(&Quartic::new(5)); + // 1 + 2 + 3 + let ones = at(&[1.0, 1.0, 1.0]); + assert_eq!(Quartic::new(3).evaluate(&ones), 6.0); + assert_eq!( + Quartic::default().representation().bounds()[0], + -1.28..=1.28 + ); + assert!(!Quartic::default().is_noisy()); + // the noise is in [0, 1), the same for the same genome, and another for another + let noisy = Quartic::noisy(3); + assert!(noisy.is_noisy()); + assert!(noisy.optimum().is_none()); + let value = noisy.evaluate(&ones); + assert!((6.0..7.0).contains(&value)); + assert_eq!(noisy.evaluate(&ones), value); + assert_ne!(noisy.evaluate(&at(&[1.0, 1.0, 1.0 + f64::EPSILON])), value); + let mut rng = StreamRng::seed_from_u64(3); + let real = Real::uniform(3, -1e-9..=1e-9).expect("valid"); + let noises: Vec = (0..1_000) + .map(|_| noisy.evaluate(&real.random_genome(&mut rng))) + .collect(); + let mean = noises.iter().sum::() / noises.len() as f64; + assert!((mean - 0.5).abs() < 0.05, "{mean}"); + assert!(noises.iter().all(|noise| (0.0..1.0).contains(noise))); + } + + #[test] + #[should_panic(expected = "Quartic needs at least 1 dimensions, got 0")] + fn quartic_needs_a_dimension() { + let _ = Quartic::noisy(0); + } + + #[test] + fn penalized() { + check_optimum(&Penalized1::new(5)); + check_optimum(&Penalized2::new(5)); + assert_eq!( + Penalized1::default().representation().bounds()[0], + -50.0..=50.0 + ); + // at x = 11, y = 4: π (10 sin² 4π + 3²), and the penalty 100 (11 − 10)⁴ + let value = Penalized1::new(1).evaluate(&at(&[11.0])); + assert_close(value, 9.0 * PI + 100.0, 1e-12); + // Yao, Liu and Lin's appendix gives (1, …, 1) as the minimizer: there y = 1.5, and the + // value is (π / 2) (10 + 0.25 · 11 + 0.25) + let value = Penalized1::new(2).evaluate(&at(&[1.0, 1.0])); + assert_close(value, PI / 2.0 * 13.0, 1e-12); + // 0.1 (sin² 0 + (0 − 1)² (1 + sin² 0) + (0 − 1)² (1 + sin² 0)) + assert_close(Penalized2::new(2).evaluate(&at(&[0.0, 0.0])), 0.2, 1e-12); + // 0.1 (sin² 18π + 25 (1 + sin² 3π) + 0) and the penalty 100 (6 − 5)⁴ + let value = Penalized2::new(2).evaluate(&at(&[6.0, 1.0])); + assert_close(value, 102.5, 1e-12); + } + + #[test] + fn ill_conditioned_quadratics() { + check_optimum(&HighConditionedElliptic::new(5)); + check_optimum(&BentCigar::new(5)); + check_optimum(&Discus::new(5)); + check_optimum(&RotatedHyperEllipsoid::new(5)); + // the weights 1, 10³ and 10⁶ + let elliptic = HighConditionedElliptic::new(3); + assert_eq!(elliptic.evaluate(&at(&[1.0, 0.0, 0.0])), 1.0); + assert_close(elliptic.evaluate(&at(&[0.0, 1.0, 0.0])), 1e3, 1e-14); + assert_eq!(elliptic.evaluate(&at(&[0.0, 0.0, 1.0])), 1e6); + let ones = at(&[1.0, 1.0, 1.0]); + assert_eq!(BentCigar::new(3).evaluate(&ones), 1.0 + 2e6); + assert_eq!(Discus::new(3).evaluate(&ones), 1e6 + 2.0); + // Σⱼ (n − j + 1) xⱼ²: 3 + 2 + 1, and the axis-parallel ellipsoid reversed + let ellipsoid = RotatedHyperEllipsoid::new(3); + assert_eq!(ellipsoid.evaluate(&ones), 6.0); + assert_eq!(ellipsoid.evaluate(&at(&[1.0, 0.0, 0.0])), 3.0); + assert_eq!(ellipsoid.evaluate(&at(&[0.0, 0.0, 2.0])), 4.0); + let x = at(&[0.5, -1.5, 2.5, 3.0]); + let reversed: Reals = x.iter().rev().copied().collect(); + assert_eq!( + RotatedHyperEllipsoid::new(4).evaluate(&x), + AxisParallelEllipsoid::new(4).evaluate(&reversed) + ); + assert_eq!(ellipsoid.representation().bounds()[0], -65.536..=65.536); + assert_eq!( + BentCigar::default().representation().bounds()[0], + -100.0..=100.0 + ); + } + + #[test] + #[should_panic(expected = "HighConditionedElliptic needs at least 2 dimensions")] + fn the_elliptic_function_needs_two_dimensions() { + let _ = HighConditionedElliptic::new(1); + } + + #[test] + fn different_powers() { + check_optimum(&DifferentPowers::new(5)); + let problem = DifferentPowers::new(3); + // the exponents 2, 4 and 6 + assert_close(problem.evaluate(&at(&[1.0, 1.0, 1.0])), 3f64.sqrt(), 1e-15); + assert_close(problem.evaluate(&at(&[0.5, 0.0, 0.0])), 0.5, 1e-15); + assert_close(problem.evaluate(&at(&[0.0, 0.5, 0.0])), 0.25, 1e-15); + assert_close(problem.evaluate(&at(&[0.0, 0.0, -0.5])), 0.125, 1e-15); + assert_eq!(problem.representation().bounds()[0], -5.0..=5.0); + } + + #[test] + fn buche_rastrigin() { + check_optimum(&BucheRastrigin::new(5)); + // T_osz(±1) = ±1; the first gene, odd from 1, positive: z₁ = 10, so 10 (2 − 2) + 100 + let problem = BucheRastrigin::new(2); + assert_close(problem.evaluate(&at(&[1.0, 0.0])), 100.0, 1e-12); + // negative: z₁ = −1, so 10 (2 − 2) + 1 + assert_close(problem.evaluate(&at(&[-1.0, 0.0])), 1.0, 1e-12); + // T_osz keeps the sign, is the identity at ±1, and oscillates around it elsewhere + assert_eq!(oscillation(0.0), 0.0); + assert_close(oscillation(1.0), 1.0, 1e-15); + assert_close(oscillation(-1.0), -1.0, 1e-15); + for x in [1e-3, 0.3, 2.0, 7.5] { + assert!(oscillation(x) > 0.0 && oscillation(-x) < 0.0); + assert!((oscillation(x) / x - 1.0).abs() < 0.11); + } + // the penalty outside [−5, 5]: 100 (6 − 5)², besides the Rastrigin part + let x = at(&[0.0, -6.0]); + let z = 10f64.sqrt() * oscillation(-6.0); + let rastrigin = 10.0 * (2.0 - 1.0 - math::cos(2.0 * PI * z)) + z * z; + assert_close(problem.evaluate(&x), rastrigin + 100.0, 1e-12); + } + + #[test] + fn non_continuous_rastrigin() { + check_optimum(&NonContinuousRastrigin::new(5)); + let f = |x: f64| NonContinuousRastrigin::new(1).evaluate(&at(&[x])); + // below 1/2, Rastrigin's function + assert_close(f(0.3), Rastrigin::new(1).evaluate(&at(&[0.3])), 1e-12); + // from 1/2, round(2x) / 2: 0.7 → 0.5, where the value is 0.25 + 10 + 10 + assert_close(f(0.7), 20.25, 1e-12); + // 0.75 → 1 and −0.75 → −1, rounding halves away from 0, where the value is 1 + assert_close(f(0.75), 1.0, 1e-12); + assert_close(f(-0.75), 1.0, 1e-12); + assert_eq!(f(1.1), f(1.2)); + } + + #[test] + fn weierstrass() { + check_optimum(&Weierstrass::new(5)); + let f = |x: f64| Weierstrass::new(1).evaluate(&at(&[x])); + // at the bound 0.5, every cosine is 1, against −1 at 0: 2 Σ 0.5ᵏ = 4 (1 − 2⁻²¹) + assert_close(f(0.5), 4.0 * (1.0 - 0.5f64.powi(21)), 1e-12); + // at the integers, 0 again + assert!(f(1.0).abs() < 1e-9 && f(-2.0).abs() < 1e-9); + assert_eq!( + Weierstrass::default().representation().bounds()[0], + -0.5..=0.5 + ); + } + + #[test] + fn katsuura() { + check_optimum(&Katsuura::new(5)); + let f = |x: f64| Katsuura::new(1).evaluate(&at(&[x])); + // 2 · 0.25 is 0.5 from an integer; 4 · 0.25 and higher are integers: the sum is 0.25, + // and the value 10 · 1.25¹⁰ − 10 + assert_close(f(0.25), 10.0 * 1.25f64.powi(10) - 10.0, 1e-12); + // the multiples of 1/2 are global minima + for x in [0.5, -1.5, 3.0, 5.0] { + assert_eq!(f(x), 0.0); + } + assert!(f(0.3) > 0.0); + } + + #[test] + fn happy_cat_and_hg_bat() { + check_optimum(&HappyCat::new(5)); + check_optimum(&HgBat::new(5)); + // |0 − 2|^(1/4) + 0 + ½ + assert_close( + HappyCat::new(2).evaluate(&at(&[0.0, 0.0])), + 2f64.powf(0.25) + 0.5, + 1e-15, + ); + // on the sphere Σ xᵢ² = n, the first term is 0: (1 + 2) / 2 + ½ + assert_eq!(HappyCat::new(2).evaluate(&at(&[1.0, 1.0])), 2.0); + // |4 − 4|^(1/2) + 3 / 2 + ½, and |4 − 0|^(1/2) + 1 / 2 + ½ + assert_eq!(HgBat::new(2).evaluate(&at(&[1.0, 1.0])), 2.0); + assert_eq!(HgBat::new(2).evaluate(&at(&[1.0, -1.0])), 3.0); + assert_eq!(HappyCat::default().representation().bounds()[0], -5.0..=5.0); + // the minimum (−1, …, −1) is the only point where the second part, Σ (xᵢ + 1)² / 2n, + // is 0 + let mut rng = StreamRng::seed_from_u64(5); + let real = HappyCat::new(4).representation(); + for _ in 0..1000 { + let x = real.random_genome(&mut rng); + let part = x.iter().map(|xi| (xi + 1.0) * (xi + 1.0)).sum::() / 8.0; + assert!(HappyCat::new(4).evaluate(&x) >= part - 1e-12); + assert!(HgBat::new(4).evaluate(&x) >= part - 1e-12); + } + } + + #[test] + fn schaffer_f7() { + check_optimum(&SchafferF7::new(5)); + // in 2 dimensions at (1, 0): s = 1, and ((1 + sin² 50))² + let expected = math::powi(1.0 + math::powi(math::sin(50.0), 2), 2); + assert_close( + SchafferF7::new(2).evaluate(&at(&[1.0, 0.0])), + expected, + 1e-15, + ); + // the mean of the pairs, squared: (0, 1, 0) has two pairs with s = 1 + assert_close( + SchafferF7::new(3).evaluate(&at(&[0.0, 1.0, 0.0])), + expected, + 1e-15, + ); + assert_eq!( + SchafferF7::default().representation().bounds()[0], + -100.0..=100.0 + ); + } + + // sign changes and permutations of the genes don't change the functions of batch 10b that + // are symmetric + #[test] + fn symmetric_functions_of_batch_10b() { + let mut rng = StreamRng::seed_from_u64(9); + let real = Real::uniform(6, -0.5..=0.5).expect("valid"); + for _ in 0..200 { + let x = real.random_genome(&mut rng); + let negated: Reals = x.iter().map(|xi| -xi).collect(); + let reversed: Reals = x.iter().rev().copied().collect(); + let sign = |f: &dyn Fn(&Reals) -> f64| assert_close(f(&x), f(&negated), 1e-12); + let order = |f: &dyn Fn(&Reals) -> f64| assert_close(f(&x), f(&reversed), 1e-12); + sign(&|x| SumOfDifferentPowers::new(6).evaluate(x)); + sign(&|x| HighConditionedElliptic::new(6).evaluate(x)); + sign(&|x| BentCigar::new(6).evaluate(x)); + sign(&|x| Discus::new(6).evaluate(x)); + sign(&|x| DifferentPowers::new(6).evaluate(x)); + sign(&|x| NonContinuousRastrigin::new(6).evaluate(x)); + sign(&|x| Weierstrass::new(6).evaluate(x)); + sign(&|x| SchafferF7::new(6).evaluate(x)); + sign(&|x| RotatedHyperEllipsoid::new(6).evaluate(x)); + order(&|x| NonContinuousRastrigin::new(6).evaluate(x)); + order(&|x| Weierstrass::new(6).evaluate(x)); + order(&|x| SchafferF7::new(6).evaluate(x)); + order(&|x| HappyCat::new(6).evaluate(x)); + order(&|x| HgBat::new(6).evaluate(x)); + } + } } diff --git a/src/problems/transform.rs b/src/problems/transform.rs new file mode 100644 index 00000000..478b2851 --- /dev/null +++ b/src/problems/transform.rs @@ -0,0 +1,507 @@ +//! The shift and the rotation that the CEC and BBOB suites apply to their functions: wrappers that +//! make an instance of any problem on [`Real`] genomes, generated from a seed. + +use super::{Constraints, Optimum, Problem}; +use crate::Objective; +use crate::StreamRng; +use crate::engine::FitnessFunction; +use crate::genome::{Real, Reals, Representation}; + +// the streams of the seed's generator from which the shift and the rotation are drawn, so that a +// problem shifted and rotated with the same seed gets independent ones +const SHIFT_STREAM: u64 = 1; +const ROTATION_STREAM: u64 = 2; + +// the point that a transformation keeps in place, or moves: the first solution of the problem's +// optimum, or the center of its box when the optimum isn't known +fn anchor>(problem: &P) -> Vec { + match problem.optimum() { + Some(optimum) if !optimum.solutions().is_empty() => optimum.solutions()[0].to_vec(), + _ => problem + .representation() + .bounds() + .iter() + .map(|range| (range.start() + range.end()) / 2.0) + .collect(), + } +} + +// the optimum of a wrapped problem, its solutions moved by `moved`, keeping those in the box +fn moved_optimum( + optimum: Option>, + real: &Real, + moved: impl Fn(&[f64]) -> Reals, +) -> Option> { + let optimum = optimum?; + let solutions: Vec = optimum + .solutions() + .iter() + .map(|solution| moved(solution)) + .filter(|solution| real.validate(solution).is_ok()) + .collect(); + Some(if optimum.is_proven() { + Optimum::proven(optimum.value(), solutions) + } else { + Optimum::best_known(optimum.value(), solutions) + }) +} + +/// A problem shifted by a random vector: `f(x − o)`, where `f` is the wrapped problem and `o` a +/// shift generated from a seed, as the CEC and BBOB suites shift their functions, so that the +/// optimum is neither at the center of the box nor on its diagonal. +/// +/// The shift moves the first solution of the wrapped problem's optimum (the center of the box if +/// the optimum isn't known) to a point drawn uniformly from the middle 80% of each gene's range: +/// the CEC 2005, 2013, 2014 and 2017 suites draw their shifted optima from [−80, 80]ⁿ in +/// [−100, 100]ⁿ, and BBOB from [−4, 4]ⁿ in [−5, 5]ⁿ. The bounds are the wrapped problem's. +/// +/// The optimum keeps its value, and its solutions are shifted (those that the shift moves out of +/// the box are dropped). That holds when the wrapped problem's minimum is its minimum over all of +/// ℝⁿ, as for the functions that CEC and BBOB shift, such as [`Rastrigin`](super::Rastrigin) and +/// [`HighConditionedElliptic`](super::HighConditionedElliptic), but not for a function whose +/// minimum is only the lowest in its box: shifted, [`Schwefel2_26`](super::Schwefel2_26) brings +/// lower values from outside its box into it. The name and the reference are the wrapped +/// problem's, and so is the constraint violation of a constrained problem, at `x − o`. +/// +/// ``` +/// use genoxide::genome::Representation; +/// use genoxide::problems::{Problem, Rastrigin, Shifted}; +/// +/// let problem = Shifted::new(Rastrigin::new(10), 1); +/// let optimum = problem.optimum().expect("known"); +/// // the minimum 0, at the shift +/// assert_eq!(optimum.value(), 0.0); +/// assert_eq!(&optimum.solutions()[0][..], problem.shift()); +/// assert!(problem.representation().validate(&optimum.solutions()[0]).is_ok()); +/// ``` +#[derive(Clone, Debug, PartialEq)] +pub struct Shifted

{ + problem: P, + seed: u64, + shift: Vec, +} + +impl> Shifted

{ + /// `problem` shifted by a vector generated from `seed`: the same seed gives the same shift on + /// every platform. + pub fn new(problem: P, seed: u64) -> Self { + let real = problem.representation(); + let anchor = anchor(&problem); + let mut rng = StreamRng::seed_from_u64(seed).derive(SHIFT_STREAM); + let shift = real + .bounds() + .iter() + .zip(anchor) + .map(|(range, anchor)| { + let (low, high) = (*range.start(), *range.end()); + let target = low + (high - low) * (0.1 + 0.8 * rng.unit_f64()); + target - anchor + }) + .collect(); + Self { + problem, + seed, + shift, + } + } + + /// The wrapped problem. + pub fn problem(&self) -> &P { + &self.problem + } + + /// The seed of the shift. + pub fn seed(&self) -> u64 { + self.seed + } + + /// The shift `o`, a value per gene: the wrapped problem is evaluated at `x − o`. + pub fn shift(&self) -> &[f64] { + &self.shift + } + + // the point at which the wrapped problem is evaluated + fn unshifted(&self, x: &Reals) -> Reals { + x.iter().zip(&self.shift).map(|(xi, oi)| xi - oi).collect() + } +} + +impl> FitnessFunction for Shifted

{ + type Output = P::Output; + + fn evaluate(&self, x: &Reals) -> P::Output { + self.problem.evaluate(&self.unshifted(x)) + } +} + +impl> Problem for Shifted

{ + type Representation = Real; + + /// The wrapped problem's name: a shift makes an instance of the same function. + fn name(&self) -> &'static str { + self.problem.name() + } + + fn representation(&self) -> Real { + self.problem.representation() + } + + fn objective(&self) -> Objective { + self.problem.objective() + } + + /// The wrapped problem's optimum, its solutions shifted. + fn optimum(&self) -> Option> { + moved_optimum(self.problem.optimum(), &self.representation(), |solution| { + solution + .iter() + .zip(&self.shift) + .map(|(s, o)| s + o) + .collect() + }) + } + + fn reference(&self) -> &'static str { + self.problem.reference() + } + + fn reference_url(&self) -> Option<&'static str> { + self.problem.reference_url() + } + + fn constraints(&self, genome: &Reals) -> Constraints { + self.problem.constraints(&self.unshifted(genome)) + } +} + +/// A problem rotated by a random orthogonal matrix: `f(c + M (x − c))`, where `f` is the wrapped +/// problem, `M` an orthogonal matrix generated from a seed and `c` the first solution of the +/// wrapped problem's optimum, so that the genes interact and a search can't optimize them one at +/// a time. +/// +/// `M` is generated as BBOB generates its rotations (Hansen, Finck, Ros and Auger 2009, section +/// 0.2): a matrix of standard normal numbers, whose rows are made orthonormal by Gram-Schmidt +/// orthonormalization (here twice over, for orthogonality to the precision of `f64`). Like BBOB's +/// and the CEC suites', it may reflect as well as rotate. It turns about the optimum, as CEC 2005 +/// does with `z = (x − o) M` and BBOB with `z = R (x − xᵒᵖᵗ)`, so the optimum stays where it is: +/// its first solution, with its value. Other solutions are rotated about it (those that the +/// rotation moves out of the box are dropped). Without a known optimum, `c` is the center of the +/// box. +/// +/// The bounds are the wrapped problem's: points of the box can map to points outside it, where +/// the wrapped function must be defined, and a function whose minimum is only the lowest in its +/// box can have lower values there, as for [`Shifted`]. The name and the reference are the wrapped +/// problem's, and so is the constraint violation of a constrained problem, at `c + M (x − c)`. +/// +/// Rotating a shifted problem gives CEC 2005's shifted rotated functions, `f((x − o) M)`, e.g. its +/// F10, the shifted rotated Rastrigin, whose rotation turns about the shifted optimum: +/// +/// ``` +/// use genoxide::prelude::*; +/// use genoxide::problems::{Problem, Rastrigin, Rotated, Shifted}; +/// +/// let problem = Rotated::new(Shifted::new(Rastrigin::new(5), 1), 1); +/// let optimum = problem.optimum().expect("known"); +/// assert_eq!(&optimum.solutions()[0][..], problem.problem().shift()); +/// let cmaes = Cmaes::builder(problem.representation()) +/// .restarts(cmaes::Restarts::Ipop) +/// .minimize() +/// .seed(1) +/// .build()?; +/// let outcome = Engine::new(cmaes, problem) +/// .stop_when(Stop::target(1e-8).or(Stop::evaluations(200_000))) +/// .run()?; +/// assert_eq!(outcome.stop_reason(), StopReason::Target); +/// # Ok::<(), genoxide::Error>(()) +/// ``` +#[derive(Clone, Debug, PartialEq)] +pub struct Rotated

{ + problem: P, + seed: u64, + center: Vec, + // row-major, n × n + matrix: Vec, +} + +impl> Rotated

{ + /// `problem` rotated by a matrix generated from `seed`: the same seed gives the same matrix + /// on every platform. + pub fn new(problem: P, seed: u64) -> Self { + let center = anchor(&problem); + let matrix = orthogonal(center.len(), seed); + Self { + problem, + seed, + center, + matrix, + } + } + + /// The wrapped problem. + pub fn problem(&self) -> &P { + &self.problem + } + + /// The seed of the rotation. + pub fn seed(&self) -> u64 { + self.seed + } + + /// The orthogonal matrix `M`, row by row: `n × n` values, row `i` from `i n` on. + pub fn matrix(&self) -> &[f64] { + &self.matrix + } + + /// The point `c` that the rotation turns about: the wrapped problem's first optimal solution, + /// or the center of the box if its optimum isn't known. + pub fn center(&self) -> &[f64] { + &self.center + } + + // the point at which the wrapped problem is evaluated: c + M (x − c) + fn rotated(&self, x: &Reals) -> Reals { + let n = self.center.len(); + let difference: Vec = x.iter().zip(&self.center).map(|(xi, ci)| xi - ci).collect(); + self.matrix + .chunks_exact(n.max(1)) + .zip(&self.center) + .map(|(row, ci)| ci + row.iter().zip(&difference).map(|(m, d)| m * d).sum::()) + .collect() + } +} + +// an n × n orthogonal matrix, row-major: standard normal numbers from `seed`, whose rows are made +// orthonormal by modified Gram-Schmidt, applied twice +fn orthogonal(n: usize, seed: u64) -> Vec { + let mut rng = StreamRng::seed_from_u64(seed).derive(ROTATION_STREAM); + let mut matrix = vec![0.0; n * n]; + let mut i = 0; + while i < n { + let (done, rest) = matrix.split_at_mut(i * n); + let row = &mut rest[..n]; + for value in row.iter_mut() { + *value = rng.normal(); + } + for _ in 0..2 { + for previous in done.chunks_exact(n) { + let dot: f64 = row.iter().zip(previous).map(|(a, b)| a * b).sum(); + for (value, p) in row.iter_mut().zip(previous) { + *value -= dot * p; + } + } + } + let norm = row.iter().map(|value| value * value).sum::().sqrt(); + // a row in the span of the others has probability 0: draw it again + if norm > 1e-8 { + for value in row.iter_mut() { + *value /= norm; + } + i += 1; + } + } + matrix +} + +impl> FitnessFunction for Rotated

{ + type Output = P::Output; + + fn evaluate(&self, x: &Reals) -> P::Output { + self.problem.evaluate(&self.rotated(x)) + } +} + +impl> Problem for Rotated

{ + type Representation = Real; + + /// The wrapped problem's name: a rotation makes an instance of the same function. + fn name(&self) -> &'static str { + self.problem.name() + } + + fn representation(&self) -> Real { + self.problem.representation() + } + + fn objective(&self) -> Objective { + self.problem.objective() + } + + /// The wrapped problem's optimum, its solutions rotated about the first: `c + Mᵀ (s − c)`. + fn optimum(&self) -> Option> { + let n = self.center.len(); + moved_optimum(self.problem.optimum(), &self.representation(), |solution| { + let difference: Vec = solution + .iter() + .zip(&self.center) + .map(|(s, c)| s - c) + .collect(); + (0..n) + .map(|j| { + let column = (0..n).map(|i| self.matrix[i * n + j] * difference[i]); + self.center[j] + column.sum::() + }) + .collect() + }) + } + + fn reference(&self) -> &'static str { + self.problem.reference() + } + + fn reference_url(&self) -> Option<&'static str> { + self.problem.reference_url() + } + + fn constraints(&self, genome: &Reals) -> Constraints { + self.problem.constraints(&self.rotated(genome)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::problems::cec2006::G06; + use crate::problems::{Branin, Rastrigin, Rosenbrock, Sphere}; + + fn assert_close(actual: f64, expected: f64, tolerance: f64) { + assert!( + (actual - expected).abs() <= tolerance * expected.abs().max(1.0), + "{actual} is not {expected}" + ); + } + + #[test] + fn a_shift_moves_the_optimum_into_the_middle_of_the_box() { + for seed in 0..50 { + let problem = Shifted::new(Rosenbrock::new(6), seed); + let optimum = problem.optimum().expect("known"); + assert_eq!(optimum.value(), 0.0); + assert!(optimum.is_proven()); + let solution = &optimum.solutions()[0]; + // in the middle 80% of [−30, 30] + assert!(solution.iter().all(|x| x.abs() <= 24.0), "{solution:?}"); + // the wrapped minimum (1, …, 1), shifted + for (x, o) in solution.iter().zip(problem.shift()) { + assert_close(*x, 1.0 + o, 1e-15); + } + assert_close(problem.evaluate(solution), 0.0, 1e-12); + assert_eq!(problem.seed(), seed); + } + // the same seed, the same shift; another seed, another shift + let a = Shifted::new(Sphere::new(3), 7); + assert_eq!(a, Shifted::new(Sphere::new(3), 7)); + assert_ne!(a.shift(), Shifted::new(Sphere::new(3), 8).shift()); + // f(x − o) + let x = Reals::from(vec![1.0, 2.0, 3.0]); + let expected: f64 = x + .iter() + .zip(a.shift()) + .map(|(x, o)| (x - o) * (x - o)) + .sum(); + assert_eq!(a.evaluate(&x), expected); + assert_eq!(a.name(), "Sphere"); + assert_eq!(a.representation(), Sphere::new(3).representation()); + } + + // fixed values, so that a change of the generator shows + #[test] + fn shifts_and_rotations_are_the_same_everywhere() { + // in the middle 80% of [−100, 100] + let shift = Shifted::new(Sphere::new(2), 1).shift().to_vec(); + assert_eq!(shift, [46.23653733062747, 24.878588135984046]); + // a rotation by about 193°: its determinant is 0.9736² + 0.2285² = 1 + let rotation = Rotated::new(Sphere::new(2), 1).matrix().to_vec(); + let expected = [ + -0.9735519448992744, + 0.22846577551756006, + -0.2284657755175601, + -0.9735519448992744, + ]; + assert_eq!(rotation, expected); + } + + #[test] + fn rotations_are_orthogonal() { + for (n, seed) in [(1, 0), (2, 1), (5, 2), (30, 3), (100, 4)] { + let problem = Rotated::new(Sphere::new(n), seed); + let m = problem.matrix(); + for i in 0..n { + for j in 0..n { + let dot: f64 = (0..n).map(|k| m[i * n + k] * m[j * n + k]).sum(); + let expected = if i == j { 1.0 } else { 0.0 }; + assert!((dot - expected).abs() < 1e-14, "{n}: {i} {j} {dot}"); + } + } + // a sphere about the origin doesn't change + let x: Reals = (0..n).map(|i| i as f64 - 1.5).collect(); + assert_close(problem.evaluate(&x), Sphere::new(n).evaluate(&x), 1e-12); + } + assert_ne!( + Rotated::new(Sphere::new(4), 1).matrix(), + Rotated::new(Sphere::new(4), 2).matrix() + ); + } + + #[test] + fn a_rotation_keeps_the_optimum_in_place() { + let problem = Rotated::new(Rosenbrock::new(5), 3); + let optimum = problem.optimum().expect("known"); + assert_eq!(&optimum.solutions()[0][..], &[1.0; 5]); + assert_eq!(problem.center(), &[1.0; 5]); + assert_eq!(problem.evaluate(&optimum.solutions()[0]), 0.0); + // the other points move: the wrapped function at c + M (x − c) + let x = Reals::from(vec![0.0; 5]); + let m = problem.matrix(); + let y: Reals = (0..5) + .map(|i| 1.0 + (0..5).map(|j| -m[i * 5 + j]).sum::()) + .collect(); + assert_close(problem.evaluate(&x), Rosenbrock::new(5).evaluate(&y), 1e-12); + } + + // CEC 2005's F10: Rastrigin, shifted, then rotated about the shifted optimum + #[test] + fn shifted_and_rotated_rastrigin() { + let problem = Rotated::new(Shifted::new(Rastrigin::new(10), 5), 5); + let shift = problem.problem().shift().to_vec(); + let optimum = problem.optimum().expect("known"); + assert_eq!(optimum.solutions()[0].to_vec(), shift); + assert_close(problem.evaluate(&optimum.solutions()[0]), 0.0, 1e-12); + // f(M (x − o)): at x = o + Mᵀ e₁, the wrapped Rastrigin sees e₁, where it's 1 + let m = problem.matrix(); + let x: Reals = (0..10).map(|j| shift[j] + m[j]).collect(); + assert_close(problem.evaluate(&x), 1.0, 1e-9); + } + + // several solutions: those that leave the box are dropped; the first stays + #[test] + fn other_solutions_move_with_the_first() { + for seed in 0..20 { + let rotated = Rotated::new(Branin, seed); + let optimum = rotated.optimum().expect("known"); + assert!(!optimum.solutions().is_empty()); + for solution in optimum.solutions() { + assert_close(rotated.evaluate(solution), optimum.value(), 1e-9); + } + let shifted = Shifted::new(Branin, seed); + for solution in shifted.optimum().expect("known").solutions() { + assert_close(shifted.evaluate(solution), optimum.value(), 1e-9); + } + } + } + + #[test] + fn constraints_are_transformed_too() { + let problem = Shifted::new(G06, 2); + let optimum = problem.optimum().expect("known"); + let solution = &optimum.solutions()[0]; + let unshifted: Reals = solution + .iter() + .zip(problem.shift()) + .map(|(x, o)| x - o) + .collect(); + assert_eq!(problem.constraints(solution), G06.constraints(&unshifted)); + let rotated = Rotated::new(G06, 2); + let center = Reals::from(rotated.center().to_vec()); + assert_eq!(rotated.constraints(¢er), G06.constraints(¢er)); + } +} From af4ce2e5298d91df36176e3850c643c5fa97154d Mon Sep 17 00:00:00 2001 From: Someguy Date: Thu, 1 Oct 2026 07:21:07 +0300 Subject: [PATCH 02/16] feat(python): the functions of batch 10b, and the Shifted and Rotated wrappers gx.problems gains the seventeen new functions and Shifted and Rotated, which wrap any single-objective problem on real genomes and give their shift, or their matrix and center, from Rust. --- python/genoxide/problems/__init__.py | 403 +++++++++++++++++++++++++++ python/src/problems.rs | 231 ++++++++++++++- python/tests/test_problems.py | 114 +++++++- 3 files changed, 743 insertions(+), 5 deletions(-) diff --git a/python/genoxide/problems/__init__.py b/python/genoxide/problems/__init__.py index fe64ce77..a38d3b08 100644 --- a/python/genoxide/problems/__init__.py +++ b/python/genoxide/problems/__init__.py @@ -48,6 +48,15 @@ result = de.run(problem, evaluations=20_000) print(result.best_fitness, result.violation, problem.design(result.best_genome)) +Two wrappers make instances of the single-objective problems, as the CEC and BBOB suites do: +:class:`Shifted` moves the optimum to a point drawn from a seed, and :class:`Rotated` turns the +function about its optimum by an orthogonal matrix drawn from a seed, so that the genes +interact:: + + problem = gx.problems.Rotated(gx.problems.Shifted(gx.problems.Rastrigin(10), seed=1), seed=1) + cmaes = gx.Cmaes(problem.genome, restarts="ipop", objective="minimize", seed=1) + result = cmaes.run(problem, target=problem.optimum.value + 1e-8, evaluations=200_000) + All problems here are minimized, on :class:`genoxide.Real` genomes except the gear train's :class:`genoxide.Integer` and :class:`Zdt5`'s :class:`genoxide.Binary`. Each class's docstring gives @@ -128,6 +137,25 @@ "Langermann", "ShekelFoxholes", "Kowalik", + "SumOfDifferentPowers", + "Step", + "Quartic", + "Penalized1", + "Penalized2", + "HighConditionedElliptic", + "BentCigar", + "Discus", + "DifferentPowers", + "BucheRastrigin", + "NonContinuousRastrigin", + "Weierstrass", + "Katsuura", + "HappyCat", + "HgBat", + "SchafferF7", + "RotatedHyperEllipsoid", + "Shifted", + "Rotated", # multi-objective "Zdt1", "Zdt2", @@ -1135,6 +1163,381 @@ class Kowalik(Problem[Real]): _type: ClassVar[str] = "kowalik" +@dataclass(frozen=True) +class SumOfDifferentPowers(_Scalable): + """The sum of different powers, ``Σ |xᵢ|^(i+1)`` (i from 1): unimodal, and the flatter near + the minimum the later the gene. + + Bounds [-1, 1]ⁿ; minimum 0 at the origin. ``dimensions`` is at least 1. + + Its origin is unknown: definition and bounds as Molga and Smutnicki (2005, section 2.8) give + them; not yet checked against an original (#168). + """ + + dimensions: int = 30 + _type: ClassVar[str] = "sum_of_different_powers" + + +@dataclass(frozen=True) +class Step(_Scalable): + """The step function, ``Σ ⌊xᵢ + 0.5⌋²``: a sphere of flat steps, whose gradient is 0 almost + everywhere. + + Bounds [-100, 100]ⁿ; minimum 0 on the whole cube [-0.5, 0.5)ⁿ, here at the origin. + ``dimensions`` is at least 1. + + Yao, X., Liu, Y. and Lin, G. (1999). Evolutionary programming made faster. IEEE Transactions + on Evolutionary Computation 3(2): 82-102, function f6. De Jong's (1975) F3, which it's often + credited to, is another step function, ``Σ ⌊xᵢ⌋`` on [-5.12, 5.12]⁵. + """ + + dimensions: int = 30 + _type: ClassVar[str] = "step" + + +@dataclass(frozen=True) +class Quartic(_Scalable): + """The quartic function, ``Σ i xᵢ⁴`` (i from 1), De Jong's F4, without noise or with it. + + Bounds [-1.28, 1.28]ⁿ; minimum 0 at the origin, without noise. ``dimensions`` is at least 1. + + With ``noisy=True``, a uniform random number in [0, 1) is added, as Yao, Liu and Lin (1999, + f7) do, drawn from a generator seeded with the genome's bits, so that the function stays + deterministic: the same genome always gets the same noise. Its minimum is then unknown, and + ``optimum`` is None. + + De Jong, K. A. (1975). An Analysis of the Behavior of a Class of Genetic Adaptive Systems. PhD + thesis, University of Michigan, function F4, with Gaussian noise: as restated by Yao, Liu and + Lin (1999, f7), whose definition, uniform noise and bounds these are. Not yet checked against + De Jong's thesis (#168). + """ + + dimensions: int = 30 + noisy: bool = False + _type: ClassVar[str] = "quartic" + + def _describe(self) -> dict[str, Any]: + if not isinstance(self.noisy, (bool, np.bool_)): + raise ValueError(f"Quartic.noisy is True or False, not {self.noisy!r}") + return {**super()._describe(), "noisy": bool(self.noisy)} + + +@dataclass(frozen=True) +class Penalized1(_Scalable): + """The first generalized penalized function: with ``yᵢ = 1 + (xᵢ + 1) / 4``, + ``(π / n) {10 sin²(πy₁) + Σᵢ₌₁ⁿ⁻¹ (yᵢ − 1)² [1 + 10 sin²(πyᵢ₊₁)] + (yₙ − 1)²} + + Σ u(xᵢ, 10, 100, 4)``, where ``u(x, a, k, m)`` is ``k (|x| − a)^m`` outside [-a, a] and 0 + inside. + + Bounds [-50, 50]ⁿ; minimum 0 at (−1, …, −1). ``dimensions`` is at least 1. + + Yao, X., Liu, Y. and Lin, G. (1999). Evolutionary programming made faster. IEEE Transactions + on Evolutionary Computation 3(2): 82-102, function f12, whose appendix misprints the + minimizer as (1, …, 1). + """ + + dimensions: int = 30 + _type: ClassVar[str] = "penalized1" + + +@dataclass(frozen=True) +class Penalized2(_Scalable): + """The second generalized penalized function, + ``0.1 {sin²(3πx₁) + Σᵢ₌₁ⁿ⁻¹ (xᵢ − 1)² [1 + sin²(3πxᵢ₊₁)] + (xₙ − 1)² [1 + sin²(2πxₙ)]} + + Σ u(xᵢ, 5, 100, 4)``, where ``u(x, a, k, m)`` is ``k (|x| − a)^m`` outside [-a, a] and 0 + inside. + + Bounds [-50, 50]ⁿ; minimum 0 at (1, …, 1). ``dimensions`` is at least 1. + + Yao, X., Liu, Y. and Lin, G. (1999). Evolutionary programming made faster. IEEE Transactions + on Evolutionary Computation 3(2): 82-102, function f13; its table I drops the square of the + last term's (xₙ − 1), which its appendix has. + """ + + dimensions: int = 30 + _type: ClassVar[str] = "penalized2" + + +@dataclass(frozen=True) +class HighConditionedElliptic(_Scalable): + """The high-conditioned elliptic function, ``Σ (10⁶)^((i−1)/(n−1)) xᵢ²`` (i from 1): an + ellipsoid with a condition number of 10⁶. + + Bounds [-100, 100]ⁿ; minimum 0 at the origin. ``dimensions`` is at least 2. + + Suganthan, P. N., Hansen, N., Liang, J. J., Deb, K., Chen, Y.-P., Auger, A. and Tiwari, S. + (2005). Problem Definitions and Evaluation Criteria for the CEC 2005 Special Session on + Real-Parameter Optimization, function F3, shifted and rotated there (see :class:`Shifted` and + :class:`Rotated`). + """ + + dimensions: int = 30 + _type: ClassVar[str] = "high_conditioned_elliptic" + _minimum: ClassVar[int] = 2 + + +@dataclass(frozen=True) +class BentCigar(_Scalable): + """The bent cigar, ``x₁² + 10⁶ Σᵢ₌₂ⁿ xᵢ²``: a long narrow ridge along the first axis. + + Bounds [-100, 100]ⁿ; minimum 0 at the origin. ``dimensions`` is at least 2. + + Hansen, N., Finck, S., Ros, R. and Auger, A. (2009). Real-Parameter Black-Box Optimization + Benchmarking 2009: Noiseless Functions Definitions. INRIA research report RR-6829, function + f12, there with an asymmetric transformation and two rotations; this plain form and the + bounds are the CEC 2014 and 2017 reports' basic function. + """ + + dimensions: int = 30 + _type: ClassVar[str] = "bent_cigar" + _minimum: ClassVar[int] = 2 + + +@dataclass(frozen=True) +class Discus(_Scalable): + """The discus, ``10⁶ x₁² + Σᵢ₌₂ⁿ xᵢ²``: one direction a thousand times more sensitive than + the others. + + Bounds [-100, 100]ⁿ; minimum 0 at the origin. ``dimensions`` is at least 2. + + Hansen, N., Finck, S., Ros, R. and Auger, A. (2009). Real-Parameter Black-Box Optimization + Benchmarking 2009: Noiseless Functions Definitions. INRIA research report RR-6829, function + f11, there with an oscillation and a rotation; this plain form and the bounds are the CEC 2014 + and 2017 reports' basic function. + """ + + dimensions: int = 30 + _type: ClassVar[str] = "discus" + _minimum: ClassVar[int] = 2 + + +@dataclass(frozen=True) +class DifferentPowers(_Scalable): + """BBOB's different powers, ``√(Σ |xᵢ|^(2 + 4 (i−1)/(n−1)))`` (i from 1): exponents from 2 + to 6. + + Bounds [-5, 5]ⁿ; minimum 0 at the origin. ``dimensions`` is at least 2. Not + :class:`SumOfDifferentPowers`. + + Hansen, N., Finck, S., Ros, R. and Auger, A. (2009). Real-Parameter Black-Box Optimization + Benchmarking 2009: Noiseless Functions Definitions. INRIA research report RR-6829, function + f14, without its rotation. + """ + + dimensions: int = 30 + _type: ClassVar[str] = "different_powers" + _minimum: ClassVar[int] = 2 + + +@dataclass(frozen=True) +class BucheRastrigin(_Scalable): + """The Büche-Rastrigin function, ``10 (n − Σ cos 2πzᵢ) + Σ zᵢ² + 100 Σ max(0, |xᵢ| − 5)²`` + with ``zᵢ = sᵢ T_osz(xᵢ)``: Rastrigin's function made asymmetric. + + T_osz is BBOB's oscillation, and ``sᵢ = 10^((i−1) / (2 (n−1)))``, times 10 where xᵢ > 0 and i + is odd. Bounds [-5, 5]ⁿ; minimum 0 at the origin. ``dimensions`` is at least 2. + + Hansen, N., Finck, S., Ros, R. and Auger, A. (2009). Real-Parameter Black-Box Optimization + Benchmarking 2009: Noiseless Functions Definitions. INRIA research report RR-6829, function + f4, with its optimum at the origin and no offset. + """ + + dimensions: int = 30 + _type: ClassVar[str] = "buche_rastrigin" + _minimum: ClassVar[int] = 2 + + +@dataclass(frozen=True) +class NonContinuousRastrigin(_Scalable): + """The non-continuous Rastrigin function, ``Σ (yᵢ² − 10 cos 2πyᵢ + 10)``, where ``yᵢ = xᵢ`` if + ``|xᵢ| < 1/2`` and ``round(2xᵢ) / 2`` otherwise (halves rounded away from 0). + + Bounds [-5.12, 5.12]ⁿ; minimum 0 at the origin. ``dimensions`` is at least 1. + + Liang, J. J., Qin, A. K., Suganthan, P. N. and Baskar, S. (2006). Comprehensive learning + particle swarm optimizer for global optimization of multimodal functions. IEEE Transactions on + Evolutionary Computation 10(3): 281-295, function f7. + """ + + dimensions: int = 30 + _type: ClassVar[str] = "non_continuous_rastrigin" + + +@dataclass(frozen=True) +class Weierstrass(_Scalable): + """The Weierstrass function, ``Σᵢ Σₖ aᵏ cos(2π bᵏ (xᵢ + 0.5)) − n Σₖ aᵏ cos(π bᵏ)`` with + a = 0.5, b = 3 and k from 0 to 20: continuous, differentiable only on a set of points. + + Bounds [-0.5, 0.5]ⁿ; minimum 0 at the origin. ``dimensions`` is at least 1. + + Suganthan, P. N., Hansen, N., Liang, J. J., Deb, K., Chen, Y.-P., Auger, A. and Tiwari, S. + (2005). Problem Definitions and Evaluation Criteria for the CEC 2005 Special Session on + Real-Parameter Optimization, function F11, shifted and rotated there. BBOB's f16 is another + form. + """ + + dimensions: int = 30 + _type: ClassVar[str] = "weierstrass" + + +@dataclass(frozen=True) +class Katsuura(_Scalable): + """Katsuura's function, + ``(10 / n²) Πᵢ (1 + i Σⱼ₌₁³² |2ʲxᵢ − round(2ʲxᵢ)| / 2ʲ)^(10 / n^1.2) − 10 / n²``: rugged + everywhere, continuous but nowhere differentiable. + + Bounds [-5, 5]ⁿ; minimum 0 at the origin, and wherever every gene is a multiple of 1/2. + ``dimensions`` is at least 1. + + Hansen, N., Finck, S., Ros, R. and Auger, A. (2009). Real-Parameter Black-Box Optimization + Benchmarking 2009: Noiseless Functions Definitions. INRIA research report RR-6829, function + f23, after Katsuura, H. (1991), The American Mathematical Monthly 98(5): 411-416 (not read); + the plain form of the CEC 2014 report's basic function. + """ + + dimensions: int = 30 + _type: ClassVar[str] = "katsuura" + + +@dataclass(frozen=True) +class HappyCat(_Scalable): + """HappyCat, ``|Σ xᵢ² − n|^(1/4) + (½ Σ xᵢ² + Σ xᵢ) / n + ½``: a groove along a sphere that + curves around to the minimum. + + Bounds [-5, 5]ⁿ; minimum 0 at (−1, …, −1), the only one. ``dimensions`` is at least 1. + + Beyer, H.-G. and Finck, S. (2012). HappyCat: a simple function class where well-known direct + search algorithms do fail. PPSN XII, LNCS 7491: 367-376, which couldn't be read. Definition as + in the CEC 2014 report (function 11), whose [-100, 100] is scaled by 5/100 to these bounds. + Not yet checked against the original (#168). + """ + + dimensions: int = 30 + _type: ClassVar[str] = "happy_cat" + + +@dataclass(frozen=True) +class HgBat(_Scalable): + """HGBat, ``|(Σ xᵢ²)² − (Σ xᵢ)²|^(1/2) + (½ Σ xᵢ² + Σ xᵢ) / n + ½``: HappyCat's relative, + with a groove along a cone. + + Bounds [-5, 5]ⁿ; minimum 0 at (−1, …, −1), the only one. ``dimensions`` is at least 1. + + Liang, J. J., Qu, B. Y. and Suganthan, P. N. (2013). Problem Definitions and Evaluation + Criteria for the CEC 2014 Special Session and Competition on Single Objective Real-Parameter + Numerical Optimization. Technical report 201311, Zhengzhou University and Nanyang + Technological University, function 12, whose [-100, 100] is scaled by 5/100 to these bounds. + """ + + dimensions: int = 30 + _type: ClassVar[str] = "hg_bat" + + +@dataclass(frozen=True) +class SchafferF7(_Scalable): + """Schaffer's F7 in n dimensions, ``((1 / (n − 1)) Σᵢ₌₁ⁿ⁻¹ √sᵢ (1 + sin²(50 sᵢ^(1/5))))²`` + with ``sᵢ = √(xᵢ² + xᵢ₊₁²)``: rings of ripples around the minimum. + + Bounds [-100, 100]ⁿ; minimum 0 at the origin. ``dimensions`` is at least 2. + + Schaffer, J. D., Caruana, R. A., Eshelman, L. J. and Das, R. (1989). A study of control + parameters affecting online performance of genetic algorithms for function optimization. + Proceedings of the Third International Conference on Genetic Algorithms: 51-60, which couldn't + be read. This n-dimensional form is BBOB's f17 without its transformations; the bounds are + Schaffer's F6's. Not yet checked against the original (#168). + """ + + dimensions: int = 30 + _type: ClassVar[str] = "schaffer_f7" + _minimum: ClassVar[int] = 2 + + +@dataclass(frozen=True) +class RotatedHyperEllipsoid(_Scalable): + """The rotated hyper-ellipsoid, ``Σᵢ Σⱼ≤ᵢ xⱼ²``, as Molga and Smutnicki (2005, section 2.3) + define it. + + Despite its name, it isn't rotated: it's ``Σⱼ (n − j + 1) xⱼ²``, an axis-parallel ellipsoid; + :class:`Schwefel1_2` is the rotated one, and :class:`Rotated` rotates this one. Bounds + [-65.536, 65.536]ⁿ; minimum 0 at the origin. ``dimensions`` is at least 1. + + Its origin is unknown; not yet checked against an original (#168). + """ + + dimensions: int = 30 + _type: ClassVar[str] = "rotated_hyper_ellipsoid" + + +def _wrapped(name: str, problem: Any) -> dict[str, Any]: + """The description of the problem a wrapper wraps.""" + if not isinstance(problem, Problem): + raise ValueError(f"{name}.problem is a single-objective problem of genoxide.problems, not {problem!r}") + return problem._describe() + + +@dataclass(frozen=True) +class Shifted(Problem[Real]): + """``problem`` shifted by a vector generated from ``seed``: ``f(x − o)``, as the CEC and BBOB + suites shift their functions. + + The shift moves the first solution of the problem's optimum (the center of its box if the + optimum isn't known) to a point drawn uniformly from the middle 80% of each gene's range, as + CEC draws its shifted optima from [-80, 80]ⁿ in [-100, 100]ⁿ and BBOB from [-4, 4]ⁿ in + [-5, 5]ⁿ. The bounds, the name and the reference are the problem's; the optimum keeps its + value, its solutions shifted (those that leave the box are dropped). That holds when the + problem's minimum is its minimum over all of ℝⁿ, as for the functions that CEC and BBOB shift, + not for one whose minimum is only the lowest in its box, such as :class:`Schwefel2_26`. The + same seed gives the same shift as Rust's ``problems::Shifted`` on every platform. + """ + + problem: Problem[Real] + seed: int + _type: ClassVar[str] = "shifted" + + def _describe(self) -> dict[str, Any]: + problem = _wrapped("Shifted", self.problem) + return {"type": self._type, "problem": problem, "seed": _whole("Shifted.seed", self.seed)} + + @property + def shift(self) -> np.ndarray: + """The shift ``o``, a value per gene: the problem is evaluated at ``x − o``.""" + return cast(np.ndarray, self._info["shift"]) + + +@dataclass(frozen=True) +class Rotated(Problem[Real]): + """``problem`` rotated by an orthogonal matrix generated from ``seed``: ``f(c + M (x − c))``, + where ``c`` is the first solution of the problem's optimum (the center of its box if the + optimum isn't known), so that the genes interact. + + ``M`` is generated as BBOB generates its rotations: standard normal numbers whose rows are + made orthonormal by Gram-Schmidt orthonormalization; it may reflect as well as rotate. It + turns about the optimum, as CEC 2005 and BBOB do, so the optimum stays in place with its + value. Rotating a :class:`Shifted` problem gives CEC 2005's shifted rotated functions, such as + its F10, ``Rotated(Shifted(Rastrigin(n), seed), seed)``. The bounds, the name and the + reference are the problem's. The same seed gives the same matrix as Rust's + ``problems::Rotated`` on every platform. + """ + + problem: Problem[Real] + seed: int + _type: ClassVar[str] = "rotated" + + def _describe(self) -> dict[str, Any]: + problem = _wrapped("Rotated", self.problem) + return {"type": self._type, "problem": problem, "seed": _whole("Rotated.seed", self.seed)} + + @property + def matrix(self) -> np.ndarray: + """The orthogonal matrix ``M``, n × n.""" + return cast(np.ndarray, self._info["matrix"]) + + @property + def center(self) -> np.ndarray: + """The point ``c`` that the rotation turns about.""" + return cast(np.ndarray, self._info["center"]) + + # ---- multi-objective problems ------------------------------------------------------------------- diff --git a/python/src/problems.rs b/python/src/problems.rs index d70f5e3d..69645c2d 100644 --- a/python/src/problems.rs +++ b/python/src/problems.rs @@ -20,7 +20,7 @@ use pyo3::types::PyDict; use serde::Deserialize; /// A problem, as `_describe()` of a `gx.problems` class gives it. -#[derive(Debug, Deserialize)] +#[derive(Clone, Debug, Deserialize)] #[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)] pub enum Config { Sphere { @@ -100,6 +100,68 @@ pub enum Config { Langermann {}, ShekelFoxholes {}, Kowalik {}, + SumOfDifferentPowers { + dimensions: usize, + }, + Step { + dimensions: usize, + }, + Quartic { + dimensions: usize, + noisy: bool, + }, + Penalized1 { + dimensions: usize, + }, + Penalized2 { + dimensions: usize, + }, + HighConditionedElliptic { + dimensions: usize, + }, + BentCigar { + dimensions: usize, + }, + Discus { + dimensions: usize, + }, + DifferentPowers { + dimensions: usize, + }, + BucheRastrigin { + dimensions: usize, + }, + NonContinuousRastrigin { + dimensions: usize, + }, + Weierstrass { + dimensions: usize, + }, + Katsuura { + dimensions: usize, + }, + HappyCat { + dimensions: usize, + }, + HgBat { + dimensions: usize, + }, + SchafferF7 { + dimensions: usize, + }, + RotatedHyperEllipsoid { + dimensions: usize, + }, + /// A single-objective problem on real genomes, shifted. + Shifted { + problem: Box, + seed: u64, + }, + /// A single-objective problem on real genomes, rotated. + Rotated { + problem: Box, + seed: u64, + }, G01 {}, G02 {}, G03 { @@ -1265,6 +1327,84 @@ fn build(config: Config) -> Result { Config::Langermann {} => problems::boxed(problems::Langermann), Config::ShekelFoxholes {} => problems::boxed(problems::ShekelFoxholes), Config::Kowalik {} => problems::boxed(problems::Kowalik), + Config::SumOfDifferentPowers { dimensions } => problems::boxed( + problems::SumOfDifferentPowers::new(at_least(dimensions, 1, "SumOfDifferentPowers")?), + ), + Config::Step { dimensions } => { + problems::boxed(problems::Step::new(at_least(dimensions, 1, "Step")?)) + } + Config::Quartic { dimensions, noisy } => { + let dimensions = at_least(dimensions, 1, "Quartic")?; + if noisy { + problems::boxed(problems::Quartic::noisy(dimensions)) + } else { + problems::boxed(problems::Quartic::new(dimensions)) + } + } + Config::Penalized1 { dimensions } => problems::boxed(problems::Penalized1::new(at_least( + dimensions, + 1, + "Penalized1", + )?)), + Config::Penalized2 { dimensions } => problems::boxed(problems::Penalized2::new(at_least( + dimensions, + 1, + "Penalized2", + )?)), + Config::HighConditionedElliptic { dimensions } => { + problems::boxed(problems::HighConditionedElliptic::new(at_least( + dimensions, + 2, + "HighConditionedElliptic", + )?)) + } + Config::BentCigar { dimensions } => problems::boxed(problems::BentCigar::new(at_least( + dimensions, + 2, + "BentCigar", + )?)), + Config::Discus { dimensions } => { + problems::boxed(problems::Discus::new(at_least(dimensions, 2, "Discus")?)) + } + Config::DifferentPowers { dimensions } => problems::boxed(problems::DifferentPowers::new( + at_least(dimensions, 2, "DifferentPowers")?, + )), + Config::BucheRastrigin { dimensions } => problems::boxed(problems::BucheRastrigin::new( + at_least(dimensions, 2, "BucheRastrigin")?, + )), + Config::NonContinuousRastrigin { dimensions } => { + problems::boxed(problems::NonContinuousRastrigin::new(at_least( + dimensions, + 1, + "NonContinuousRastrigin", + )?)) + } + Config::Weierstrass { dimensions } => problems::boxed(problems::Weierstrass::new( + at_least(dimensions, 1, "Weierstrass")?, + )), + Config::Katsuura { dimensions } => problems::boxed(problems::Katsuura::new(at_least( + dimensions, 1, "Katsuura", + )?)), + Config::HappyCat { dimensions } => problems::boxed(problems::HappyCat::new(at_least( + dimensions, 1, "HappyCat", + )?)), + Config::HgBat { dimensions } => { + problems::boxed(problems::HgBat::new(at_least(dimensions, 1, "HgBat")?)) + } + Config::SchafferF7 { dimensions } => problems::boxed(problems::SchafferF7::new(at_least( + dimensions, + 2, + "SchafferF7", + )?)), + Config::RotatedHyperEllipsoid { dimensions } => problems::boxed( + problems::RotatedHyperEllipsoid::new(at_least(dimensions, 1, "RotatedHyperEllipsoid")?), + ), + Config::Shifted { problem, seed } => { + problems::boxed(problems::Shifted::new(wrapped(*problem, "Shifted")?, seed)) + } + Config::Rotated { problem, seed } => { + problems::boxed(problems::Rotated::new(wrapped(*problem, "Rotated")?, seed)) + } Config::G01 {} => problems::boxed(cec2006::G01), Config::G02 {} => problems::boxed(cec2006::G02), Config::G03 { tolerance } => { @@ -1329,6 +1469,83 @@ fn build(config: Config) -> Result { })) } +// a single-objective problem on real genomes behind `DynProblem`, as a `Problem`, for the +// wrappers +struct Wrapped(Box); + +impl FitnessFunction for Wrapped { + type Output = Fitness; + + fn evaluate(&self, genome: &Reals) -> Fitness { + self.0.evaluate(genome) + } +} + +impl problems::Problem for Wrapped { + type Representation = Real; + + fn name(&self) -> &'static str { + self.0.name() + } + + fn representation(&self) -> Real { + self.0.real() + } + + fn objective(&self) -> Objective { + self.0.objective() + } + + fn optimum(&self) -> Option> { + self.0.optimum() + } + + fn reference(&self) -> &'static str { + self.0.reference() + } + + fn reference_url(&self) -> Option<&'static str> { + self.0.reference_url() + } + + fn constraints(&self, genome: &Reals) -> Constraints { + self.0.constraints(genome) + } +} + +// the problem that a wrapper (`name`) wraps: a single-objective one on real genomes +fn wrapped(config: Config, name: &str) -> Result { + match build(config)? { + Problem::Single(problem) => Ok(Wrapped(problem)), + _ => Err(format!( + "{name} wraps a single-objective problem on real genomes" + )), + } +} + +// the shift of a shifted problem, and the matrix and center of a rotated one, for their Python +// classes +fn transformation<'py>(py: Python<'py>, config: Config, info: &Bound<'py, PyDict>) -> PyResult<()> { + match config { + Config::Shifted { problem, seed } => { + let problem = wrapped(*problem, "Shifted").map_err(PyValueError::new_err)?; + let shifted = problems::Shifted::new(problem, seed); + info.set_item("shift", PyArray1::from_slice(py, shifted.shift()))?; + } + Config::Rotated { problem, seed } => { + let problem = wrapped(*problem, "Rotated").map_err(PyValueError::new_err)?; + let rotated = problems::Rotated::new(problem, seed); + let n = rotated.center().len(); + let matrix = Array2::from_shape_vec((n, n), rotated.matrix().to_vec()) + .map_err(|error| PyValueError::new_err(error.to_string()))?; + info.set_item("matrix", matrix.into_pyarray(py))?; + info.set_item("center", PyArray1::from_slice(py, rotated.center()))?; + } + _ => {} + } + Ok(()) +} + // an equality tolerance: the report's by default, and finite and at least 0 otherwise fn equality_tolerance(tolerance: Option) -> Result { match tolerance { @@ -1342,12 +1559,16 @@ fn equality_tolerance(tolerance: Option) -> Result { /// The problem that `description` (JSON) describes. pub fn parse(description: &str) -> PyResult { + build(config(description)?).map_err(PyValueError::new_err) +} + +// the description of a problem, from JSON +fn config(description: &str) -> PyResult { let mut json = serde_json::Deserializer::from_str(description); - let config: Config = serde_path_to_error::deserialize(&mut json).map_err(|error| { + serde_path_to_error::deserialize(&mut json).map_err(|error| { let (path, error) = (error.path().to_string(), error.into_inner()); PyValueError::new_err(format!("invalid problem `{path}`: {error}")) - })?; - build(config).map_err(PyValueError::new_err) + }) } // a genome per row, as numpy arrays of the problem's dimensions @@ -1391,6 +1612,7 @@ fn matrix<'py, const M: usize>(py: Python<'py>, points: &[[f64; M]]) -> Bound<'p #[pyfunction] pub fn problem_info<'py>(py: Python<'py>, problem: &str) -> PyResult> { let info = PyDict::new(py); + let description = problem; match parse(problem)? { Problem::Single(problem) => { info.set_item("name", problem.name())?; @@ -1423,6 +1645,7 @@ pub fn problem_info<'py>(py: Python<'py>, problem: &str) -> PyResult { let integer = problem.integer(); diff --git a/python/tests/test_problems.py b/python/tests/test_problems.py index 8e1050d8..347efb9f 100644 --- a/python/tests/test_problems.py +++ b/python/tests/test_problems.py @@ -50,8 +50,28 @@ gx.problems.Langermann, gx.problems.ShekelFoxholes, gx.problems.Kowalik, + gx.problems.SumOfDifferentPowers, + gx.problems.Step, + gx.problems.Quartic, + gx.problems.Penalized1, + gx.problems.Penalized2, + gx.problems.HighConditionedElliptic, + gx.problems.BentCigar, + gx.problems.Discus, + gx.problems.DifferentPowers, + gx.problems.BucheRastrigin, + gx.problems.NonContinuousRastrigin, + gx.problems.Weierstrass, + gx.problems.Katsuura, + gx.problems.HappyCat, + gx.problems.HgBat, + gx.problems.SchafferF7, + gx.problems.RotatedHyperEllipsoid, ] +# the wrappers, which make an instance of another problem +WRAPPERS = [gx.problems.Shifted, gx.problems.Rotated] + # the problems whose minimum is known numerically, not proven NUMERICAL = { "Hartmann3", @@ -204,7 +224,7 @@ def test_the_classes_are_the_rust_registry(): assert set(names[len(two) :]) <= set(three) assert three == gx._genoxide.multi_problem_names(3) assert gx._genoxide.multi_problem_names(5)[0] == "WaterResourcePlanning" - classes = PROBLEMS + MULTI_PROBLEMS + BINARY_PROBLEMS + classes = PROBLEMS + MULTI_PROBLEMS + BINARY_PROBLEMS + WRAPPERS assert sorted(cls.__name__ for cls in classes) == sorted( name for name in gx.problems.__all__ if name not in ("Problem", "MultiProblem", "Optimum") ) @@ -328,6 +348,95 @@ def test_values_of_the_functions_of_batch_10(): assert gx.problems.Kowalik().genome == gx.Real((-5.0, 5.0), length=4) +def test_values_of_the_functions_of_batch_10b(): + assert gx.problems.SumOfDifferentPowers(3)([1, -1, 0.5]) == 2.0625 + # the cube [-0.5, 0.5) is flat at 0 + assert gx.problems.Step(3)([0.49, -0.5, 1.5]) == 4 + assert gx.problems.Step(3)([0.49, -0.5, 0.0]) == 0 + assert gx.problems.Quartic(3)([1, 1, 1]) == 6 + # the noise is in [0, 1), and the same for the same genome; no known minimum + noisy = gx.problems.Quartic(3, noisy=True) + assert 6 <= noisy([1, 1, 1]) < 7 + assert noisy([1, 1, 1]) == noisy([1, 1, 1]) + assert noisy.optimum is None + assert list(gx.problems.Penalized1(3).optimum.solutions[0]) == [-1, -1, -1] + assert gx.problems.Penalized1(1)([11]) == pytest.approx(9 * math.pi + 100) + assert gx.problems.Penalized2(2)([6, 1]) == pytest.approx(102.5) + assert gx.problems.HighConditionedElliptic(3)([0, 0, 1]) == 1e6 + assert gx.problems.BentCigar(3)([1, 1, 1]) == 1 + 2e6 + assert gx.problems.Discus(3)([1, 1, 1]) == 1e6 + 2 + assert gx.problems.DifferentPowers(3)([0, 0, -0.5]) == pytest.approx(0.125) + assert gx.problems.BucheRastrigin(2)([1, 0]) == pytest.approx(100) + assert gx.problems.BucheRastrigin(2)([-1, 0]) == pytest.approx(1) + assert gx.problems.NonContinuousRastrigin(1)([0.7]) == pytest.approx(20.25) + assert gx.problems.Weierstrass(1)([0.5]) == pytest.approx(4 * (1 - 0.5**21)) + assert gx.problems.Katsuura(1)([0.25]) == pytest.approx(10 * 1.25**10 - 10) + assert gx.problems.Katsuura(2)([0.5, -1.5]) == 0 + assert gx.problems.HappyCat(2)([1, 1]) == 2 + assert gx.problems.HgBat(2)([1, -1]) == 3 + assert list(gx.problems.HappyCat(2).optimum.solutions[0]) == [-1, -1] + assert gx.problems.SchafferF7(2)([1, 0]) == pytest.approx((1 + math.sin(50) ** 2) ** 2) + # Σⱼ (n − j + 1) xⱼ²: not rotated, despite its name + assert gx.problems.RotatedHyperEllipsoid(3)([1, 0, 0]) == 3 + assert gx.problems.RotatedHyperEllipsoid(3)([0, 0, 1]) == 1 + assert gx.problems.Weierstrass().genome == gx.Real((-0.5, 0.5), length=30) + assert gx.problems.RotatedHyperEllipsoid(2).genome == gx.Real((-65.536, 65.536), length=2) + + +def test_shifted_and_rotated_problems(): + shifted = gx.problems.Shifted(gx.problems.Rastrigin(5), seed=1) + assert shifted.name == "Rastrigin" + assert shifted.genome == gx.Real((-5.12, 5.12), length=5) + assert shifted.reference == gx.problems.Rastrigin().reference + # the minimum, moved to the shift, in the middle 80% of the box + optimum = shifted.optimum + assert optimum.value == 0 and optimum.proven + assert np.array_equal(optimum.solutions[0], shifted.shift) + assert np.all(np.abs(shifted.shift) <= 0.8 * 5.12) + assert shifted(shifted.shift) == 0 + x = np.array([0.5, -1.0, 2.0, 0.0, 1.5]) + assert shifted(x) == gx.problems.Rastrigin(5)(x - shifted.shift) + # the same seed, the same shift, as in Rust; another, another + assert np.array_equal(gx.problems.Shifted(gx.problems.Sphere(2), 1).shift, [46.23653733062747, 24.878588135984046]) + assert not np.array_equal(gx.problems.Shifted(gx.problems.Rastrigin(5), 2).shift, shifted.shift) + # CEC 2005's F10: rotated about the shifted minimum + rotated = gx.problems.Rotated(shifted, seed=1) + matrix = rotated.matrix + assert matrix.shape == (5, 5) + assert np.allclose(matrix @ matrix.T, np.eye(5), atol=1e-14) + assert np.array_equal(rotated.center, shifted.shift) + assert np.array_equal(rotated.optimum.solutions[0], shifted.shift) + y = shifted.shift + matrix @ (x - shifted.shift) + assert rotated(x) == pytest.approx(shifted(y), rel=1e-12) + assert np.array_equal(gx.problems.Rotated(gx.problems.Sphere(2), 1).matrix.ravel(), [-0.9735519448992744, 0.22846577551756006, -0.2284657755175601, -0.9735519448992744]) + # constrained problems shift too, with their violation: at G06's minimum, both constraints + # are active, and x − o rounds to a point outside one of them by 6e-14 + g06 = gx.problems.Shifted(gx.problems.cec2006.G06(), seed=3) + score, violation = g06(g06.optimum.solutions[0]) + assert score == pytest.approx(g06.optimum.value) and violation < 1e-12 + # a native run, the same as a run with Python calls + cmaes = gx.Cmaes(rotated.genome, objective="minimize", seed=2) + native = cmaes.run(rotated, generations=40) + python = cmaes.run(lambda x: rotated(x), generations=40) + assert native.best_fitness == python.best_fitness + assert np.array_equal(native.best_genome, python.best_genome) + + +@pytest.mark.parametrize( + "problem, message", + [ + (gx.problems.Shifted(lambda x: 0.0, seed=1), "Shifted.problem is a single-objective problem of genoxide.problems"), + (gx.problems.Rotated(gx.problems.Sphere(2), seed=-1), "Rotated.seed is at least 0, not -1"), + (gx.problems.Shifted(gx.problems.Zdt1(), seed=1), "Shifted.problem is a single-objective problem"), + (gx.problems.Rotated(gx.problems.engineering.GearTrain(), seed=1), "Rotated wraps a single-objective problem on real genomes"), + (gx.problems.Quartic(3, noisy=1), "Quartic.noisy is True or False, not 1"), + ], +) +def test_wrong_wrappers_are_errors(problem, message): + with pytest.raises(ValueError, match=message): + problem.genome + + def test_sizes(): assert gx.problems.Rastrigin().dimensions == 30 assert gx.problems.Michalewicz().dimensions == 10 @@ -348,6 +457,9 @@ def test_sizes(): (gx.problems.Trid(1), "Trid.dimensions is at least 2, not 1"), (gx.problems.Powell(2), "Powell.dimensions is at least 4, not 2"), (gx.problems.Powell(6), "Powell.dimensions is a multiple of 4, not 6"), + (gx.problems.BentCigar(1), "BentCigar.dimensions is at least 2, not 1"), + (gx.problems.SchafferF7(1), "SchafferF7.dimensions is at least 2, not 1"), + (gx.problems.Shifted(gx.problems.Sphere(0), seed=1), "Sphere.dimensions is at least 1, not 0"), (gx.problems.Sphere(2.0), "Sphere.dimensions is a whole number"), (gx.problems.Sphere(2**40), "Sphere.dimensions is at most 16777216, not 1099511627776"), ], From 18e2ec2cbbb5b52d7c857d5a9d359f5b9b797834 Mon Sep 17 00:00:00 2001 From: Someguy Date: Thu, 1 Oct 2026 17:03:03 +0300 Subject: [PATCH 03/16] docs: room in the examples' order for batch 10b --- examples/ackley/README.md | 2 +- examples/beale/README.md | 2 +- examples/bnh/README.md | 2 +- examples/bohachevsky1/README.md | 2 +- examples/bohachevsky2/README.md | 2 +- examples/bohachevsky3/README.md | 2 +- examples/booth/README.md | 2 +- examples/branin/README.md | 2 +- examples/c1_dtlz1_3obj/README.md | 2 +- examples/c1_dtlz3_3obj/README.md | 2 +- examples/c2_dtlz2_3obj/README.md | 2 +- examples/c3_dtlz1_3obj/README.md | 2 +- examples/c3_dtlz4_3obj/README.md | 2 +- examples/cantilever_beam/README.md | 2 +- examples/car_side_impact/README.md | 2 +- examples/cec2006_g01/README.md | 2 +- examples/cec2006_g02/README.md | 2 +- examples/cec2006_g03/README.md | 2 +- examples/cec2006_g04/README.md | 2 +- examples/cec2006_g05/README.md | 2 +- examples/cec2006_g06/README.md | 2 +- examples/cec2006_g07/README.md | 2 +- examples/cec2006_g08/README.md | 2 +- examples/cec2006_g09/README.md | 2 +- examples/cec2006_g10/README.md | 2 +- examples/cec2006_g11/README.md | 2 +- examples/cec2006_g12/README.md | 2 +- examples/cec2006_g13/README.md | 2 +- examples/cec2006_g14/README.md | 2 +- examples/cec2006_g15/README.md | 2 +- examples/cec2006_g16/README.md | 2 +- examples/cec2006_g17/README.md | 2 +- examples/cec2006_g18/README.md | 2 +- examples/cec2006_g19/README.md | 2 +- examples/cec2006_g20/README.md | 2 +- examples/cec2006_g21/README.md | 2 +- examples/cec2006_g22/README.md | 2 +- examples/cec2006_g23/README.md | 2 +- examples/cec2006_g24/README.md | 2 +- examples/constr/README.md | 2 +- examples/convex_c2_dtlz2_3obj/README.md | 2 +- examples/ctp1/README.md | 2 +- examples/ctp2/README.md | 2 +- examples/ctp3/README.md | 2 +- examples/ctp4/README.md | 2 +- examples/ctp5/README.md | 2 +- examples/ctp6/README.md | 2 +- examples/ctp7/README.md | 2 +- examples/ctp8/README.md | 2 +- examples/dtlz1_3obj/README.md | 2 +- examples/dtlz2_3obj/README.md | 2 +- examples/dtlz3_3obj/README.md | 2 +- examples/dtlz4_3obj/README.md | 2 +- examples/dtlz5_3obj/README.md | 2 +- examples/dtlz6_3obj/README.md | 2 +- examples/dtlz7_3obj/README.md | 2 +- examples/easom/README.md | 2 +- examples/eggholder/README.md | 2 +- examples/fonseca_fleming/README.md | 2 +- examples/gear_train/README.md | 2 +- examples/goldstein_price/README.md | 2 +- examples/griewank/README.md | 2 +- examples/hartmann3/README.md | 2 +- examples/hartmann6/README.md | 2 +- examples/himmelblau/README.md | 2 +- examples/kowalik/README.md | 2 +- examples/kursawe/README.md | 2 +- examples/langermann/README.md | 2 +- examples/levy/README.md | 2 +- examples/matyas/README.md | 2 +- examples/michalewicz/README.md | 2 +- examples/osy/README.md | 2 +- examples/poloni/README.md | 2 +- examples/pressure_vessel/README.md | 2 +- examples/rastrigin/README.md | 2 +- examples/rosenbrock/README.md | 2 +- examples/schaffer1/README.md | 2 +- examples/schaffer2/README.md | 2 +- examples/schaffer_f6/README.md | 2 +- examples/schwefel_2_26/README.md | 2 +- examples/shekel10/README.md | 2 +- examples/shekel5/README.md | 2 +- examples/shekel7/README.md | 2 +- examples/shekel_foxholes/README.md | 2 +- examples/six_hump_camel/README.md | 2 +- examples/speed_reducer/README.md | 2 +- examples/srn/README.md | 2 +- examples/styblinski_tang/README.md | 2 +- examples/tension_compression_spring/README.md | 2 +- examples/three_bar_truss/README.md | 2 +- examples/three_hump_camel/README.md | 2 +- examples/tnk/README.md | 2 +- examples/viennet1/README.md | 2 +- examples/viennet2/README.md | 2 +- examples/viennet3/README.md | 2 +- examples/welded_beam/README.md | 2 +- examples/wfg1/README.md | 2 +- examples/wfg2/README.md | 2 +- examples/wfg3/README.md | 2 +- examples/wfg4/README.md | 2 +- examples/wfg5/README.md | 2 +- examples/wfg6/README.md | 2 +- examples/wfg7/README.md | 2 +- examples/wfg8/README.md | 2 +- examples/wfg9/README.md | 2 +- examples/zdt1/README.md | 2 +- examples/zdt2/README.md | 2 +- examples/zdt3/README.md | 2 +- examples/zdt4/README.md | 2 +- examples/zdt5/README.md | 2 +- examples/zdt6/README.md | 2 +- 111 files changed, 111 insertions(+), 111 deletions(-) diff --git a/examples/ackley/README.md b/examples/ackley/README.md index 9b8771e8..818eca06 100644 --- a/examples/ackley/README.md +++ b/examples/ackley/README.md @@ -6,7 +6,7 @@ reference: "Ackley, D. H. (1987). A Connectionist Machine for Genetic Hillclimbi reference_url: "https://doi.org/10.1007/978-1-4613-1997-9" optimum: "0 (at the origin)" languages: [rust, python] -order: 54 +order: 64 trace_note: "Recorded from another run: PSO with a ring topology in 2 dimensions, so that the population can be drawn on the function's contour." --- diff --git a/examples/beale/README.md b/examples/beale/README.md index 43f6f990..8b40b704 100644 --- a/examples/beale/README.md +++ b/examples/beale/README.md @@ -6,7 +6,7 @@ reference: "Beale, E. M. L. (1958). On an Iterative Method for Finding a Local M reference_url: "" optimum: "0 at (3, 0.5)" languages: [rust, python] -order: 63 +order: 73 --- # Beale diff --git a/examples/bnh/README.md b/examples/bnh/README.md index f4bffd99..fef69c71 100644 --- a/examples/bnh/README.md +++ b/examples/bnh/README.md @@ -6,7 +6,7 @@ reference: "Binh, T. T. and Korn, U. (1997). MOBES: a multiobjective evolution s reference_url: "" optimum: "the front f = (8t², 2(t − 5)²) for t in [0, 5]; hypervolume 9883.33 (reference point (210, 55))" languages: [rust, python] -order: 141 +order: 161 --- # BNH, a constrained two-objective problem diff --git a/examples/bohachevsky1/README.md b/examples/bohachevsky1/README.md index c790a237..2fccce46 100644 --- a/examples/bohachevsky1/README.md +++ b/examples/bohachevsky1/README.md @@ -6,7 +6,7 @@ reference: "Bohachevsky, I. O., Johnson, M. E. and Stein, M. L. (1986). Generali reference_url: "https://doi.org/10.1080/00401706.1986.10488128" optimum: "0 at (0, 0)" languages: [rust, python] -order: 66 +order: 76 family: Bohachevsky tab: Bohachevsky 1 --- diff --git a/examples/bohachevsky2/README.md b/examples/bohachevsky2/README.md index 2afcbad3..c3abd6a9 100644 --- a/examples/bohachevsky2/README.md +++ b/examples/bohachevsky2/README.md @@ -6,7 +6,7 @@ reference: "Bohachevsky, I. O., Johnson, M. E. and Stein, M. L. (1986). Generali reference_url: "https://doi.org/10.1080/00401706.1986.10488128" optimum: "0 at (0, 0)" languages: [rust, python] -order: 67 +order: 77 family: Bohachevsky tab: Bohachevsky 2 --- diff --git a/examples/bohachevsky3/README.md b/examples/bohachevsky3/README.md index c789bb62..21e23228 100644 --- a/examples/bohachevsky3/README.md +++ b/examples/bohachevsky3/README.md @@ -6,7 +6,7 @@ reference: "Bohachevsky, I. O., Johnson, M. E. and Stein, M. L. (1986). Generali reference_url: "https://doi.org/10.1080/00401706.1986.10488128" optimum: "0 at (0, 0)" languages: [rust, python] -order: 68 +order: 78 family: Bohachevsky tab: Bohachevsky 3 --- diff --git a/examples/booth/README.md b/examples/booth/README.md index e6e3f072..3a7b3bc6 100644 --- a/examples/booth/README.md +++ b/examples/booth/README.md @@ -6,7 +6,7 @@ reference: "Jamil, M. and Yang, X.-S. (2013). A literature survey of benchmark f reference_url: "https://doi.org/10.1504/IJMMNO.2013.055204" optimum: "0 at (1, 3)" languages: [rust, python] -order: 64 +order: 74 --- # Booth diff --git a/examples/branin/README.md b/examples/branin/README.md index b3c16795..1868064c 100644 --- a/examples/branin/README.md +++ b/examples/branin/README.md @@ -6,7 +6,7 @@ reference: "Branin, F. H. (1972). Widely convergent method for finding multiple reference_url: "https://doi.org/10.1147/rd.165.0504" optimum: "0.397887 (at three points)" languages: [rust, python] -order: 59 +order: 69 --- # Branin diff --git a/examples/c1_dtlz1_3obj/README.md b/examples/c1_dtlz1_3obj/README.md index f367cc21..5bb18c19 100644 --- a/examples/c1_dtlz1_3obj/README.md +++ b/examples/c1_dtlz1_3obj/README.md @@ -6,7 +6,7 @@ reference: "Jain, H. and Deb, K. (2014). An evolutionary many-objective optimiza reference_url: https://doi.org/10.1109/TEVC.2013.2281534 optimum: "DTLZ1's front, the plane f₁ + f₂ + f₃ = 1/2, all feasible; the 91 target points' hypervolume is 1.1204 in objectives scaled by the nadir point (reference point (1.1, 1.1, 1.1))" languages: [rust, python] -order: 173 +order: 193 family: C-DTLZ tab: C1-DTLZ1 --- diff --git a/examples/c1_dtlz3_3obj/README.md b/examples/c1_dtlz3_3obj/README.md index 72e1833f..4c0c7f5e 100644 --- a/examples/c1_dtlz3_3obj/README.md +++ b/examples/c1_dtlz3_3obj/README.md @@ -6,7 +6,7 @@ reference: "Jain, H. and Deb, K. (2014). An evolutionary many-objective optimiza reference_url: https://doi.org/10.1109/TEVC.2013.2281534 optimum: "DTLZ3's front, the unit sphere, all feasible; the 91 target points' hypervolume is 0.7449 (reference point (1.1, 1.1, 1.1))" languages: [rust, python] -order: 174 +order: 194 family: C-DTLZ tab: C1-DTLZ3 --- diff --git a/examples/c2_dtlz2_3obj/README.md b/examples/c2_dtlz2_3obj/README.md index ddb66866..ece03228 100644 --- a/examples/c2_dtlz2_3obj/README.md +++ b/examples/c2_dtlz2_3obj/README.md @@ -6,7 +6,7 @@ reference: "Jain, H. and Deb, K. (2014). An evolutionary many-objective optimiza reference_url: https://doi.org/10.1109/TEVC.2013.2281534 optimum: "the parts of the unit sphere within 0.4 of (1, 0, 0), (0, 1, 0), (0, 0, 1) and (1, 1, 1)/√3; the 58 feasible target points' hypervolume is 0.6535 (reference point (1.1, 1.1, 1.1))" languages: [rust, python] -order: 175 +order: 195 family: C-DTLZ tab: C2-DTLZ2 --- diff --git a/examples/c3_dtlz1_3obj/README.md b/examples/c3_dtlz1_3obj/README.md index 29acbf14..6dc1a9db 100644 --- a/examples/c3_dtlz1_3obj/README.md +++ b/examples/c3_dtlz1_3obj/README.md @@ -6,7 +6,7 @@ reference: "Jain, H. and Deb, K. (2014). An evolutionary many-objective optimiza reference_url: https://doi.org/10.1109/TEVC.2013.2281534 optimum: "the front f₁ + f₂ + f₃ + min fⱼ = 1, three planes from the unit vectors to (1/4, 1/4, 1/4); the 91 target points' hypervolume is 1.1624 (reference point (1.1, 1.1, 1.1))" languages: [rust, python] -order: 177 +order: 197 family: C-DTLZ tab: C3-DTLZ1 --- diff --git a/examples/c3_dtlz4_3obj/README.md b/examples/c3_dtlz4_3obj/README.md index 69a89e82..69e55b64 100644 --- a/examples/c3_dtlz4_3obj/README.md +++ b/examples/c3_dtlz4_3obj/README.md @@ -6,7 +6,7 @@ reference: "Jain, H. and Deb, K. (2014). An evolutionary many-objective optimiza reference_url: https://doi.org/10.1109/TEVC.2013.2281534 optimum: "the front minⱼ [fⱼ²/4 + Σ_{i≠j} fᵢ²] = 1, three ellipsoids from 2 × the unit vectors to (2/3, 2/3, 2/3); the 91 target points' hypervolume is 1.0598 in objectives scaled by the nadir point (reference point (1.1, 1.1, 1.1))" languages: [rust, python] -order: 178 +order: 198 family: C-DTLZ tab: C3-DTLZ4 --- diff --git a/examples/cantilever_beam/README.md b/examples/cantilever_beam/README.md index 23ac089e..3d1eca83 100644 --- a/examples/cantilever_beam/README.md +++ b/examples/cantilever_beam/README.md @@ -6,7 +6,7 @@ reference: "Fleury, C. and Braibant, V. (1986). Structural optimization: a new d reference_url: https://doi.org/10.1002/nme.1620230307 optimum: "1.339956361 (weight), proven" languages: [rust, python] -order: 95 +order: 115 --- # Cantilever beam diff --git a/examples/car_side_impact/README.md b/examples/car_side_impact/README.md index b2b87412..8fecfdc0 100644 --- a/examples/car_side_impact/README.md +++ b/examples/car_side_impact/README.md @@ -6,7 +6,7 @@ reference: "Gu, L., Yang, R. J., Tho, C. H., Makowski, M., Faruque, O. and Li, Y reference_url: https://doi.org/10.1504/IJVD.2001.005210 optimum: "23.585658 (weight), best known" languages: [rust, python] -order: 96 +order: 116 --- # Car side impact diff --git a/examples/cec2006_g01/README.md b/examples/cec2006_g01/README.md index e90d5b9e..85a23903 100644 --- a/examples/cec2006_g01/README.md +++ b/examples/cec2006_g01/README.md @@ -6,7 +6,7 @@ reference: "Liang, J. J., Runarsson, T. P., Mezura-Montes, E., Clerc, M., Sugant reference_url: "https://github.com/P-N-Suganthan/CEC2006" optimum: "−15 at (1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 1), proven" languages: [rust, python] -order: 97 +order: 117 family: "CEC 2006" tab: g01 --- diff --git a/examples/cec2006_g02/README.md b/examples/cec2006_g02/README.md index 394697cc..f3ac1533 100644 --- a/examples/cec2006_g02/README.md +++ b/examples/cec2006_g02/README.md @@ -6,7 +6,7 @@ reference: "Liang, J. J., Runarsson, T. P., Mezura-Montes, E., Clerc, M., Sugant reference_url: "https://github.com/P-N-Suganthan/CEC2006" optimum: "−0.80361910412559, best known (not proven)" languages: [rust, python] -order: 98 +order: 118 family: "CEC 2006" tab: g02 --- diff --git a/examples/cec2006_g03/README.md b/examples/cec2006_g03/README.md index 84286277..f3d14b34 100644 --- a/examples/cec2006_g03/README.md +++ b/examples/cec2006_g03/README.md @@ -6,7 +6,7 @@ reference: "Liang, J. J., Runarsson, T. P., Mezura-Montes, E., Clerc, M., Sugant reference_url: "https://github.com/P-N-Suganthan/CEC2006" optimum: "−1.0005001 (−1.0001⁵) at xi = 0.316244 for the report's tolerance 0.0001, proven" languages: [rust, python] -order: 99 +order: 119 family: "CEC 2006" tab: g03 --- diff --git a/examples/cec2006_g04/README.md b/examples/cec2006_g04/README.md index b342254c..0b0e8361 100644 --- a/examples/cec2006_g04/README.md +++ b/examples/cec2006_g04/README.md @@ -6,7 +6,7 @@ reference: "Liang, J. J., Runarsson, T. P., Mezura-Montes, E., Clerc, M., Sugant reference_url: "https://github.com/P-N-Suganthan/CEC2006" optimum: "−30665.53867178332 (proven)" languages: [rust, python] -order: 100 +order: 120 family: "CEC 2006" tab: g04 --- diff --git a/examples/cec2006_g05/README.md b/examples/cec2006_g05/README.md index 744ca112..b43c6c44 100644 --- a/examples/cec2006_g05/README.md +++ b/examples/cec2006_g05/README.md @@ -6,7 +6,7 @@ reference: "Liang, J. J., Runarsson, T. P., Mezura-Montes, E., Clerc, M., Sugant reference_url: "https://github.com/P-N-Suganthan/CEC2006" optimum: "5126.4967140071 (best known, with the equalities met within 0.0001)" languages: [rust, python] -order: 101 +order: 121 family: "CEC 2006" tab: g05 --- diff --git a/examples/cec2006_g06/README.md b/examples/cec2006_g06/README.md index a7219db6..d905a8fd 100644 --- a/examples/cec2006_g06/README.md +++ b/examples/cec2006_g06/README.md @@ -6,7 +6,7 @@ reference: "Liang, J. J., Runarsson, T. P., Mezura-Montes, E., Clerc, M., Sugant reference_url: "https://github.com/P-N-Suganthan/CEC2006" optimum: "−6961.81387558015 (proven)" languages: [rust, python] -order: 102 +order: 122 family: "CEC 2006" tab: g06 --- diff --git a/examples/cec2006_g07/README.md b/examples/cec2006_g07/README.md index fdf4d732..5814db39 100644 --- a/examples/cec2006_g07/README.md +++ b/examples/cec2006_g07/README.md @@ -6,7 +6,7 @@ reference: "Liang, J. J., Runarsson, T. P., Mezura-Montes, E., Clerc, M., Sugant reference_url: "https://github.com/P-N-Suganthan/CEC2006" optimum: "24.30620906818 (proven)" languages: [rust, python] -order: 103 +order: 123 family: "CEC 2006" tab: g07 --- diff --git a/examples/cec2006_g08/README.md b/examples/cec2006_g08/README.md index 9978ccc8..1058ba8d 100644 --- a/examples/cec2006_g08/README.md +++ b/examples/cec2006_g08/README.md @@ -6,7 +6,7 @@ reference: "Liang, J. J., Runarsson, T. P., Mezura-Montes, E., Clerc, M., Sugant reference_url: "https://github.com/P-N-Suganthan/CEC2006" optimum: "−0.0958250414180359 (proven)" languages: [rust, python] -order: 104 +order: 124 family: "CEC 2006" tab: g08 --- diff --git a/examples/cec2006_g09/README.md b/examples/cec2006_g09/README.md index 98af926a..66cb7825 100644 --- a/examples/cec2006_g09/README.md +++ b/examples/cec2006_g09/README.md @@ -6,7 +6,7 @@ reference: "Liang, J. J., Runarsson, T. P., Mezura-Montes, E., Clerc, M., Sugant reference_url: "https://github.com/P-N-Suganthan/CEC2006" optimum: "680.630057374402 (proven)" languages: [rust, python] -order: 105 +order: 125 family: "CEC 2006" tab: g09 --- diff --git a/examples/cec2006_g10/README.md b/examples/cec2006_g10/README.md index 43e17581..d241627e 100644 --- a/examples/cec2006_g10/README.md +++ b/examples/cec2006_g10/README.md @@ -6,7 +6,7 @@ reference: "Liang, J. J., Runarsson, T. P., Mezura-Montes, E., Clerc, M., Sugant reference_url: "https://github.com/P-N-Suganthan/CEC2006" optimum: "7049.24802052867 (proven)" languages: [rust, python] -order: 106 +order: 126 family: "CEC 2006" tab: g10 --- diff --git a/examples/cec2006_g11/README.md b/examples/cec2006_g11/README.md index 4a0cedd9..d8537188 100644 --- a/examples/cec2006_g11/README.md +++ b/examples/cec2006_g11/README.md @@ -6,7 +6,7 @@ reference: "Liang, J. J., Runarsson, T. P., Mezura-Montes, E., Clerc, M., Sugant reference_url: "https://github.com/P-N-Suganthan/CEC2006" optimum: "0.7499 (3/4 − 0.0001) at (±0.707036, 0.5) for the report's tolerance 0.0001, proven" languages: [rust, python] -order: 107 +order: 127 family: "CEC 2006" tab: g11 --- diff --git a/examples/cec2006_g12/README.md b/examples/cec2006_g12/README.md index 6dfd97fc..1783c379 100644 --- a/examples/cec2006_g12/README.md +++ b/examples/cec2006_g12/README.md @@ -6,7 +6,7 @@ reference: "Liang, J. J., Runarsson, T. P., Mezura-Montes, E., Clerc, M., Sugant reference_url: "https://github.com/P-N-Suganthan/CEC2006" optimum: "−1 at (5, 5, 5) (proven)" languages: [rust, python] -order: 108 +order: 128 family: "CEC 2006" tab: g12 --- diff --git a/examples/cec2006_g13/README.md b/examples/cec2006_g13/README.md index a0f46191..6b4adf7f 100644 --- a/examples/cec2006_g13/README.md +++ b/examples/cec2006_g13/README.md @@ -6,7 +6,7 @@ reference: "Liang, J. J., Runarsson, T. P., Mezura-Montes, E., Clerc, M., Sugant reference_url: "https://github.com/P-N-Suganthan/CEC2006" optimum: "0.053941514041898 (best known, with the equalities met within 0.0001)" languages: [rust, python] -order: 109 +order: 129 family: "CEC 2006" tab: g13 --- diff --git a/examples/cec2006_g14/README.md b/examples/cec2006_g14/README.md index 4b4bcc9e..64cbe410 100644 --- a/examples/cec2006_g14/README.md +++ b/examples/cec2006_g14/README.md @@ -6,7 +6,7 @@ reference: "Liang, J. J., Runarsson, T. P., Mezura-Montes, E., Clerc, M., Sugant reference_url: "https://github.com/P-N-Suganthan/CEC2006" optimum: "−47.7648884594915 (best known, with the equalities met within 0.0001)" languages: [rust, python] -order: 110 +order: 130 family: "CEC 2006" tab: g14 --- diff --git a/examples/cec2006_g15/README.md b/examples/cec2006_g15/README.md index db236150..643d6a66 100644 --- a/examples/cec2006_g15/README.md +++ b/examples/cec2006_g15/README.md @@ -6,7 +6,7 @@ reference: "Liang, J. J., Runarsson, T. P., Mezura-Montes, E., Clerc, M., Sugant reference_url: "https://github.com/P-N-Suganthan/CEC2006" optimum: "961.715022289961 (best known, with the equalities met within 0.0001)" languages: [rust, python] -order: 111 +order: 131 family: "CEC 2006" tab: g15 --- diff --git a/examples/cec2006_g16/README.md b/examples/cec2006_g16/README.md index 6c22b12e..3fc31952 100644 --- a/examples/cec2006_g16/README.md +++ b/examples/cec2006_g16/README.md @@ -6,7 +6,7 @@ reference: "Liang, J. J., Runarsson, T. P., Mezura-Montes, E., Clerc, M., Sugant reference_url: "https://github.com/P-N-Suganthan/CEC2006" optimum: "−1.90515525853479 (best known)" languages: [rust, python] -order: 112 +order: 132 family: "CEC 2006" tab: g16 --- diff --git a/examples/cec2006_g17/README.md b/examples/cec2006_g17/README.md index 30860314..c164838e 100644 --- a/examples/cec2006_g17/README.md +++ b/examples/cec2006_g17/README.md @@ -6,7 +6,7 @@ reference: "Liang, J. J., Runarsson, T. P., Mezura-Montes, E., Clerc, M., Sugant reference_url: "https://github.com/P-N-Suganthan/CEC2006" optimum: "8853.5338748065 (best known, with the equalities met within 0.0001; the report prints 8853.53967480648)" languages: [rust, python] -order: 113 +order: 133 family: "CEC 2006" tab: g17 --- diff --git a/examples/cec2006_g18/README.md b/examples/cec2006_g18/README.md index 59230ff0..27543a05 100644 --- a/examples/cec2006_g18/README.md +++ b/examples/cec2006_g18/README.md @@ -6,7 +6,7 @@ reference: "Liang, J. J., Runarsson, T. P., Mezura-Montes, E., Clerc, M., Sugant reference_url: "https://github.com/P-N-Suganthan/CEC2006" optimum: "−0.866025403784439, −√3/2 (best known)" languages: [rust, python] -order: 114 +order: 134 family: "CEC 2006" tab: g18 --- diff --git a/examples/cec2006_g19/README.md b/examples/cec2006_g19/README.md index 14688a52..0d565a5b 100644 --- a/examples/cec2006_g19/README.md +++ b/examples/cec2006_g19/README.md @@ -6,7 +6,7 @@ reference: "Liang, J. J., Runarsson, T. P., Mezura-Montes, E., Clerc, M., Sugant reference_url: "https://github.com/P-N-Suganthan/CEC2006" optimum: "32.6555929502463 (best known)" languages: [rust, python] -order: 115 +order: 135 family: "CEC 2006" tab: g19 --- diff --git a/examples/cec2006_g20/README.md b/examples/cec2006_g20/README.md index 871e828c..93600747 100644 --- a/examples/cec2006_g20/README.md +++ b/examples/cec2006_g20/README.md @@ -6,7 +6,7 @@ reference: "Liang, J. J., Runarsson, T. P., Mezura-Montes, E., Clerc, M., Sugant reference_url: "https://github.com/P-N-Suganthan/CEC2006" optimum: "none feasible; the report's best known, 0.2049794002, violates a constraint by 0.1438" languages: [rust, python] -order: 116 +order: 136 family: "CEC 2006" tab: g20 --- diff --git a/examples/cec2006_g21/README.md b/examples/cec2006_g21/README.md index 594220f6..7363cc67 100644 --- a/examples/cec2006_g21/README.md +++ b/examples/cec2006_g21/README.md @@ -6,7 +6,7 @@ reference: "Liang, J. J., Runarsson, T. P., Mezura-Montes, E., Clerc, M., Sugant reference_url: "https://github.com/P-N-Suganthan/CEC2006" optimum: "193.724510070035 (best known, with the equalities met within 0.0001)" languages: [rust, python] -order: 117 +order: 137 family: "CEC 2006" tab: g21 --- diff --git a/examples/cec2006_g22/README.md b/examples/cec2006_g22/README.md index 3302bb1a..2e969507 100644 --- a/examples/cec2006_g22/README.md +++ b/examples/cec2006_g22/README.md @@ -6,7 +6,7 @@ reference: "Liang, J. J., Runarsson, T. P., Mezura-Montes, E., Clerc, M., Sugant reference_url: "https://github.com/P-N-Suganthan/CEC2006" optimum: "236.430975504001 (the report's best known, with the equalities met within 0.0001); 236.370313314566 with every equality met exactly" languages: [rust, python] -order: 118 +order: 138 family: "CEC 2006" tab: g22 --- diff --git a/examples/cec2006_g23/README.md b/examples/cec2006_g23/README.md index 7ca743c1..f2222c38 100644 --- a/examples/cec2006_g23/README.md +++ b/examples/cec2006_g23/README.md @@ -6,7 +6,7 @@ reference: "Liang, J. J., Runarsson, T. P., Mezura-Montes, E., Clerc, M., Sugant reference_url: "https://github.com/P-N-Suganthan/CEC2006" optimum: "−400.055099999999584 (best known, with the equalities met within 0.0001)" languages: [rust, python] -order: 119 +order: 139 family: "CEC 2006" tab: g23 --- diff --git a/examples/cec2006_g24/README.md b/examples/cec2006_g24/README.md index 0a0d873d..69627933 100644 --- a/examples/cec2006_g24/README.md +++ b/examples/cec2006_g24/README.md @@ -6,7 +6,7 @@ reference: "Liang, J. J., Runarsson, T. P., Mezura-Montes, E., Clerc, M., Sugant reference_url: "https://github.com/P-N-Suganthan/CEC2006" optimum: "−5.50801327159536 (proven)" languages: [rust, python] -order: 120 +order: 140 family: "CEC 2006" tab: g24 --- diff --git a/examples/constr/README.md b/examples/constr/README.md index 4616a3af..8e3786b2 100644 --- a/examples/constr/README.md +++ b/examples/constr/README.md @@ -6,7 +6,7 @@ reference: "Deb, K., Pratap, A., Agarwal, S. and Meyarivan, T. (2002). A fast an reference_url: https://doi.org/10.1109/4235.996017 optimum: "the front f₂ = 7/f₁ − 9 for f₁ in [7/18, 2/3], then f₂ = 1/f₁ for f₁ in [2/3, 1]; hypervolume 5.3327 (reference point (1.1, 10))" languages: [rust, python] -order: 145 +order: 165 --- # CONSTR diff --git a/examples/convex_c2_dtlz2_3obj/README.md b/examples/convex_c2_dtlz2_3obj/README.md index 3a56ff14..70227b78 100644 --- a/examples/convex_c2_dtlz2_3obj/README.md +++ b/examples/convex_c2_dtlz2_3obj/README.md @@ -6,7 +6,7 @@ reference: "Jain, H. and Deb, K. (2014). An evolutionary many-objective optimiza reference_url: https://doi.org/10.1109/TEVC.2013.2281534 optimum: "the convex front f₃ + √f₁ + √f₂ = 1 outside the cylinder of radius 0.225 around the diagonal; the 47 feasible target points' hypervolume is 1.2546 (reference point (1.1, 1.1, 1.1))" languages: [rust, python] -order: 176 +order: 196 family: C-DTLZ tab: convex C2-DTLZ2 --- diff --git a/examples/ctp1/README.md b/examples/ctp1/README.md index 6dd4666f..c724bfd6 100644 --- a/examples/ctp1/README.md +++ b/examples/ctp1/README.md @@ -6,7 +6,7 @@ reference: "Deb, K., Pratap, A. and Meyarivan, T. (2001). Constrained test probl reference_url: https://doi.org/10.1007/3-540-44719-9_20 optimum: "the front f₂ = max(e^−f₁, 0.858 e^−0.541f₁, 0.728 e^−0.295f₁) for f₁ in [0, 1]; hypervolume 0.8829 in objectives scaled by the ideal and nadir points (reference point (1.1, 1.1))" languages: [rust, python] -order: 165 +order: 185 family: CTP --- diff --git a/examples/ctp2/README.md b/examples/ctp2/README.md index aa3bb110..3ad398d1 100644 --- a/examples/ctp2/README.md +++ b/examples/ctp2/README.md @@ -6,7 +6,7 @@ reference: "Deb, K., Pratap, A. and Meyarivan, T. (2001). Constrained test probl reference_url: https://doi.org/10.1007/3-540-44719-9_20 optimum: "13 disconnected pieces of the constraint's boundary, from (0, 1) to (0.9845, 0.2872); hypervolume 0.6901 in objectives scaled by the ideal and nadir points (reference point (1.1, 1.1))" languages: [rust, python] -order: 166 +order: 186 family: CTP --- diff --git a/examples/ctp3/README.md b/examples/ctp3/README.md index eef2d75c..e931d11f 100644 --- a/examples/ctp3/README.md +++ b/examples/ctp3/README.md @@ -6,7 +6,7 @@ reference: "Deb, K., Pratap, A. and Meyarivan, T. (2001). Constrained test probl reference_url: https://doi.org/10.1007/3-540-44719-9_20 optimum: "13 points on the line f₂ = 1 − tan(0.2π) f₁, from (0, 1) to (0.9708, 0.2947); hypervolume 0.6683 in objectives scaled by the ideal and nadir points (reference point (1.1, 1.1))" languages: [rust, python] -order: 167 +order: 187 family: CTP --- diff --git a/examples/ctp4/README.md b/examples/ctp4/README.md index 47db859d..cf83b402 100644 --- a/examples/ctp4/README.md +++ b/examples/ctp4/README.md @@ -6,7 +6,7 @@ reference: "Deb, K., Pratap, A. and Meyarivan, T. (2001). Constrained test probl reference_url: https://doi.org/10.1007/3-540-44719-9_20 optimum: "13 points on the line f₂ = 1 − tan(0.2π) f₁, from (0, 1) to (0.9708, 0.2947); hypervolume 0.6683 in objectives scaled by the ideal and nadir points (reference point (1.1, 1.1))" languages: [rust, python] -order: 168 +order: 188 family: CTP --- diff --git a/examples/ctp5/README.md b/examples/ctp5/README.md index 81ecb447..1da569e2 100644 --- a/examples/ctp5/README.md +++ b/examples/ctp5/README.md @@ -6,7 +6,7 @@ reference: "Deb, K., Pratap, A. and Meyarivan, T. (2001). Constrained test probl reference_url: https://doi.org/10.1007/3-540-44719-9_20 optimum: "a piece of the constraint's boundary from (0, 1) to f₁ = 0.2558, and 15 points on the line f₂ = 1 − tan(0.2π) f₁ at √(k/10) along it, the last at (0.9908, 0.2801); hypervolume 0.6613 in objectives scaled by the ideal and nadir points (reference point (1.1, 1.1))" languages: [rust, python] -order: 169 +order: 189 family: CTP --- diff --git a/examples/ctp6/README.md b/examples/ctp6/README.md index f525c817..1574c484 100644 --- a/examples/ctp6/README.md +++ b/examples/ctp6/README.md @@ -6,7 +6,7 @@ reference: "Deb, K., Pratap, A. and Meyarivan, T. (2001). Constrained test probl reference_url: https://doi.org/10.1007/3-540-44719-9_20 optimum: "one piece of a constraint boundary, from (0, 3.6958) to (1, 0.8813); hypervolume 0.7124 in objectives scaled by the ideal and nadir points (reference point (1.1, 1.1))" languages: [rust, python] -order: 170 +order: 190 family: CTP --- diff --git a/examples/ctp7/README.md b/examples/ctp7/README.md index 3e96f4d1..6e678605 100644 --- a/examples/ctp7/README.md +++ b/examples/ctp7/README.md @@ -6,7 +6,7 @@ reference: "Deb, K., Pratap, A. and Meyarivan, T. (2001). Constrained test probl reference_url: https://doi.org/10.1007/3-540-44719-9_20 optimum: "six pieces of the curve f₂ = 1 − √f₁, the last ending at (1, 0), and the point (0, 1.0446); hypervolume 0.8443 in objectives scaled by the ideal and nadir points (reference point (1.1, 1.1))" languages: [rust, python] -order: 171 +order: 191 family: CTP --- diff --git a/examples/ctp8/README.md b/examples/ctp8/README.md index 9a22e715..7d91456c 100644 --- a/examples/ctp8/README.md +++ b/examples/ctp8/README.md @@ -6,7 +6,7 @@ reference: "Deb, K. (2001). Multi-Objective Optimization Using Evolutionary Algo reference_url: "" optimum: "three pieces of CTP6's front, from (0, 3.6958) to (0.1345, 3.3128), (0.3263, 2.7686) to (0.4790, 2.3372) and (0.6823, 1.7654) to (0.8229, 1.3727); hypervolume 0.6540 in objectives scaled by the ideal and nadir points (reference point (1.1, 1.1))" languages: [rust, python] -order: 172 +order: 192 family: CTP --- diff --git a/examples/dtlz1_3obj/README.md b/examples/dtlz1_3obj/README.md index 14bf779a..d1296dbc 100644 --- a/examples/dtlz1_3obj/README.md +++ b/examples/dtlz1_3obj/README.md @@ -6,7 +6,7 @@ reference: "Deb, K., Thiele, L., Laumanns, M. and Zitzler, E. (2002). Scalable m reference_url: https://doi.org/10.1109/CEC.2002.1007032 optimum: "the plane f₁ + f₂ + f₃ = 0.5; hypervolume 0.1455 (reference point (0.55, 0.55, 0.55))" languages: [rust, python] -order: 155 +order: 175 family: DTLZ tab: DTLZ1 --- diff --git a/examples/dtlz2_3obj/README.md b/examples/dtlz2_3obj/README.md index 70fd25f9..3df2aac2 100644 --- a/examples/dtlz2_3obj/README.md +++ b/examples/dtlz2_3obj/README.md @@ -6,7 +6,7 @@ reference: "Deb, K., Thiele, L., Laumanns, M. and Zitzler, E. (2002). Scalable m reference_url: https://doi.org/10.1109/CEC.2002.1007032 optimum: "hypervolume 0.8074 (reference point (1.1, 1.1, 1.1))" languages: [rust, python] -order: 156 +order: 176 family: DTLZ tab: DTLZ2 --- diff --git a/examples/dtlz3_3obj/README.md b/examples/dtlz3_3obj/README.md index 2d3e1221..ca3dab14 100644 --- a/examples/dtlz3_3obj/README.md +++ b/examples/dtlz3_3obj/README.md @@ -6,7 +6,7 @@ reference: "Deb, K., Thiele, L., Laumanns, M. and Zitzler, E. (2002). Scalable m reference_url: https://doi.org/10.1109/CEC.2002.1007032 optimum: "the unit sphere's eighth with f ≥ 0; hypervolume 0.8074 (reference point (1.1, 1.1, 1.1))" languages: [rust, python] -order: 157 +order: 177 family: DTLZ tab: DTLZ3 --- diff --git a/examples/dtlz4_3obj/README.md b/examples/dtlz4_3obj/README.md index 76ba74ba..41d78ac3 100644 --- a/examples/dtlz4_3obj/README.md +++ b/examples/dtlz4_3obj/README.md @@ -6,7 +6,7 @@ reference: "Deb, K., Thiele, L., Laumanns, M. and Zitzler, E. (2002). Scalable m reference_url: https://doi.org/10.1109/CEC.2002.1007032 optimum: "the unit sphere's eighth with f ≥ 0; hypervolume 0.8074 (reference point (1.1, 1.1, 1.1))" languages: [rust, python] -order: 158 +order: 178 family: DTLZ tab: DTLZ4 --- diff --git a/examples/dtlz5_3obj/README.md b/examples/dtlz5_3obj/README.md index 80e3d40e..cd32dd75 100644 --- a/examples/dtlz5_3obj/README.md +++ b/examples/dtlz5_3obj/README.md @@ -6,7 +6,7 @@ reference: "Deb, K., Thiele, L., Laumanns, M. and Zitzler, E. (2001). Scalable T reference_url: https://sop.tik.ee.ethz.ch/publicationListFiles/dtlz2001a.pdf optimum: "the curve f₁ = f₂ = cos θ / √2, f₃ = sin θ for θ in [0, π/2]; hypervolume 0.1349 (reference point (0.7778, 0.7778, 1.1))" languages: [rust, python] -order: 159 +order: 179 family: DTLZ tab: DTLZ5 --- diff --git a/examples/dtlz6_3obj/README.md b/examples/dtlz6_3obj/README.md index f2c3f03b..816fd78f 100644 --- a/examples/dtlz6_3obj/README.md +++ b/examples/dtlz6_3obj/README.md @@ -6,7 +6,7 @@ reference: "Deb, K., Thiele, L., Laumanns, M. and Zitzler, E. (2001). Scalable T reference_url: https://sop.tik.ee.ethz.ch/publicationListFiles/dtlz2001a.pdf optimum: "the curve f₁ = f₂ = cos θ / √2, f₃ = sin θ for θ in [0, π/2]; hypervolume 0.1349 (reference point (0.7778, 0.7778, 1.1))" languages: [rust, python] -order: 160 +order: 180 family: DTLZ tab: DTLZ6 --- diff --git a/examples/dtlz7_3obj/README.md b/examples/dtlz7_3obj/README.md index 641fa739..170f20d8 100644 --- a/examples/dtlz7_3obj/README.md +++ b/examples/dtlz7_3obj/README.md @@ -6,7 +6,7 @@ reference: "Deb, K., Thiele, L., Laumanns, M. and Zitzler, E. (2001). Scalable T reference_url: https://sop.tik.ee.ethz.ch/publicationListFiles/dtlz2001a.pdf optimum: "f₃ = 6 − φ(f₁) − φ(f₂), φ(f) = f (1 + sin 3πf), with f₁ and f₂ in [0, 0.2514] or (0.6316, 0.8594]; hypervolume 1.7392 (reference point (0.9453, 0.9453, 6.6))" languages: [rust, python] -order: 161 +order: 181 family: DTLZ tab: DTLZ7 --- diff --git a/examples/easom/README.md b/examples/easom/README.md index 9fe6f5d1..caf8ff83 100644 --- a/examples/easom/README.md +++ b/examples/easom/README.md @@ -6,7 +6,7 @@ reference: "Easom, E. E. (1990). A Survey of Global Optimization Techniques. M.E reference_url: "" optimum: "−1 at (π, π)" languages: [rust, python] -order: 77 +order: 87 --- # Easom diff --git a/examples/eggholder/README.md b/examples/eggholder/README.md index ac9cd466..b496feba 100644 --- a/examples/eggholder/README.md +++ b/examples/eggholder/README.md @@ -6,7 +6,7 @@ reference: "Whitley, D., Rana, S., Dzubera, J. and Mathias, K. (1996). Evaluatin reference_url: "https://doi.org/10.1016/0004-3702(95)00124-7" optimum: "−959.6407 at (512, 404.2318) (best known)" languages: [rust, python] -order: 78 +order: 88 --- # Eggholder diff --git a/examples/fonseca_fleming/README.md b/examples/fonseca_fleming/README.md index 98d19dbc..4bee1c0d 100644 --- a/examples/fonseca_fleming/README.md +++ b/examples/fonseca_fleming/README.md @@ -6,7 +6,7 @@ reference: "Fonseca, C. M. and Fleming, P. J. (1995). An overview of evolutionar reference_url: https://doi.org/10.1162/evco.1995.3.1.1 optimum: "the front (1 − exp(−(s − 1)²), 1 − exp(−(s + 1)²)) for s in [−1, 1]; hypervolume 0.5521 (reference point (1.1, 1.1))" languages: [rust, python] -order: 138 +order: 158 --- # Fonseca-Fleming diff --git a/examples/gear_train/README.md b/examples/gear_train/README.md index 070a6da2..e797f9d0 100644 --- a/examples/gear_train/README.md +++ b/examples/gear_train/README.md @@ -6,7 +6,7 @@ reference: "Sandgren, E. (1990). Nonlinear integer and discrete programming in m reference_url: https://doi.org/10.1115/1.2912596 optimum: "2.700857e-12 (squared error of the ratio)" languages: [rust, python] -order: 126 +order: 146 --- # Gear train design diff --git a/examples/goldstein_price/README.md b/examples/goldstein_price/README.md index 990e0622..c70a93bc 100644 --- a/examples/goldstein_price/README.md +++ b/examples/goldstein_price/README.md @@ -6,7 +6,7 @@ reference: "Goldstein, A. A. and Price, J. F. (1971). On descent from local mini reference_url: "https://doi.org/10.1090/S0025-5718-1971-0312365-X" optimum: "3 (at (0, −1))" languages: [rust, python] -order: 60 +order: 70 --- # Goldstein-Price diff --git a/examples/griewank/README.md b/examples/griewank/README.md index 4cc51460..60195595 100644 --- a/examples/griewank/README.md +++ b/examples/griewank/README.md @@ -6,7 +6,7 @@ reference: "Griewank, A. O. (1981). Generalized descent for global optimization. reference_url: "https://doi.org/10.1007/BF00933356" optimum: "0 (at the origin)" languages: [rust, python] -order: 56 +order: 66 trace_note: "Recorded from another run: CMA-ES with IPOP restarts in 2 dimensions, with a budget of 50,000 evaluations, so that the population can be drawn on the function's contour." --- diff --git a/examples/hartmann3/README.md b/examples/hartmann3/README.md index 57205250..539efdf0 100644 --- a/examples/hartmann3/README.md +++ b/examples/hartmann3/README.md @@ -6,7 +6,7 @@ reference: "Hartman, J. K. (1973). Some experiments in global optimization. Nava reference_url: "https://doi.org/10.1002/nav.3800200316" optimum: "−3.86278 at (0.11461, 0.55565, 0.85255) (best known)" languages: [rust, python] -order: 69 +order: 79 family: Hartmann tab: 3-D --- diff --git a/examples/hartmann6/README.md b/examples/hartmann6/README.md index 4977e79d..96b2a7e7 100644 --- a/examples/hartmann6/README.md +++ b/examples/hartmann6/README.md @@ -6,7 +6,7 @@ reference: "Hartman, J. K. (1973). Some experiments in global optimization. Nava reference_url: "https://doi.org/10.1002/nav.3800200316" optimum: "−3.32237 at (0.20169, 0.15001, 0.47687, 0.27533, 0.31165, 0.65730) (best known)" languages: [rust, python] -order: 70 +order: 80 family: Hartmann tab: 6-D --- diff --git a/examples/himmelblau/README.md b/examples/himmelblau/README.md index fc4e2d9e..10a3403e 100644 --- a/examples/himmelblau/README.md +++ b/examples/himmelblau/README.md @@ -6,7 +6,7 @@ reference: "Himmelblau, D. M. (1972). Applied Nonlinear Programming. McGraw-Hill reference_url: "" optimum: "0 (at four points)" languages: [rust, python] -order: 58 +order: 68 --- # Himmelblau's function diff --git a/examples/kowalik/README.md b/examples/kowalik/README.md index 0a74d202..8ec7a71d 100644 --- a/examples/kowalik/README.md +++ b/examples/kowalik/README.md @@ -6,7 +6,7 @@ reference: "Kowalik, J. S. and Osborne, M. R. (1968). Methods for Unconstrained reference_url: "https://doi.org/10.1109/4235.771163" optimum: "3.07486e-4 at (0.19283, 0.19084, 0.12312, 0.13577) (best known)" languages: [rust, python] -order: 76 +order: 86 --- # Kowalik diff --git a/examples/kursawe/README.md b/examples/kursawe/README.md index 9e6940c1..053f1f5a 100644 --- a/examples/kursawe/README.md +++ b/examples/kursawe/README.md @@ -6,7 +6,7 @@ reference: "Kursawe, F. (1991). A variant of evolution strategies for vector opt reference_url: https://doi.org/10.1007/BFb0029752 optimum: "not known in closed form; a reference front from much longer runs has hypervolume 37.3489 (reference point (−14, 1))" languages: [rust, python] -order: 139 +order: 159 --- # Kursawe's disconnected front diff --git a/examples/langermann/README.md b/examples/langermann/README.md index 6502df3c..9765896b 100644 --- a/examples/langermann/README.md +++ b/examples/langermann/README.md @@ -6,7 +6,7 @@ reference: "Bersini, H., Dorigo, M., Langerman, S., Seront, G. and Gambardella, reference_url: "https://doi.org/10.1109/ICEC.1996.542670" optimum: "−4.15581 at (2.79340, 1.59723) (best known)" languages: [rust, python] -order: 75 +order: 85 --- # Langermann diff --git a/examples/levy/README.md b/examples/levy/README.md index f347d3ea..2b2230d5 100644 --- a/examples/levy/README.md +++ b/examples/levy/README.md @@ -6,7 +6,7 @@ reference: "Levy, A. V. and Montalvo, A. (1985). The tunneling algorithm for the reference_url: "https://doi.org/10.1137/0906002" optimum: "0 (at (1, …, 1))" languages: [rust, python] -order: 51 +order: 61 trace_note: "Recorded from another run: L-SHADE in 2 dimensions, so that the population can be drawn on the function's contour." --- diff --git a/examples/matyas/README.md b/examples/matyas/README.md index 221497fa..731cab9e 100644 --- a/examples/matyas/README.md +++ b/examples/matyas/README.md @@ -6,7 +6,7 @@ reference: "Jamil, M. and Yang, X.-S. (2013). A literature survey of benchmark f reference_url: "https://doi.org/10.1504/IJMMNO.2013.055204" optimum: "0 at (0, 0)" languages: [rust, python] -order: 65 +order: 75 --- # Matyas diff --git a/examples/michalewicz/README.md b/examples/michalewicz/README.md index d05052cb..4b31f2b6 100644 --- a/examples/michalewicz/README.md +++ b/examples/michalewicz/README.md @@ -6,7 +6,7 @@ reference: "Michalewicz, Z. (1992). Genetic Algorithms + Data Structures = Evolu reference_url: "" optimum: "−9.66015 in 10 dimensions (computed a gene at a time)" languages: [rust, python] -order: 53 +order: 63 trace_note: "Recorded from another run: L-SHADE in 2 dimensions, so that the population can be drawn on the function's contour." --- diff --git a/examples/osy/README.md b/examples/osy/README.md index 8e2dbbf2..b53998d4 100644 --- a/examples/osy/README.md +++ b/examples/osy/README.md @@ -6,7 +6,7 @@ reference: "Osyczka, A. and Kundu, S. (1995). A new method to solve generalized reference_url: https://doi.org/10.1007/BF01743536 optimum: "a front in five pieces, from (−274, 76) to (−42, 4); hypervolume 16546.1 (reference point (−20, 85))" languages: [rust, python] -order: 144 +order: 164 --- # OSY (Osyczka and Kundu) diff --git a/examples/poloni/README.md b/examples/poloni/README.md index a9fe31eb..b4a83d65 100644 --- a/examples/poloni/README.md +++ b/examples/poloni/README.md @@ -6,7 +6,7 @@ reference: "Poloni, C., Giurgevich, A., Onesti, L. and Pediroda, V. (2000). Hybr reference_url: https://doi.org/10.1016/S0045-7825(99)00394-1 optimum: "not known in closed form; a fine grid gives hypervolume 444.57 (reference point (18.4, 27.5))" languages: [rust, python] -order: 140 +order: 160 --- # Poloni diff --git a/examples/pressure_vessel/README.md b/examples/pressure_vessel/README.md index 4d8ba4d0..2d99274b 100644 --- a/examples/pressure_vessel/README.md +++ b/examples/pressure_vessel/README.md @@ -6,7 +6,7 @@ reference: "Sandgren, E. (1990). Nonlinear integer and discrete programming in m reference_url: https://doi.org/10.1115/1.2912596 optimum: "6059.714335 (cost)" languages: [rust, python] -order: 90 +order: 110 --- # Pressure vessel design diff --git a/examples/rastrigin/README.md b/examples/rastrigin/README.md index 65587648..a729b85b 100644 --- a/examples/rastrigin/README.md +++ b/examples/rastrigin/README.md @@ -6,7 +6,7 @@ reference: "Rastrigin, L. A. (1974). Systems of Extremal Control. Nauka, Moscow, reference_url: "https://doi.org/10.1016/S0167-8191(05)80052-3" optimum: "0 (at the origin)" languages: [rust, python] -order: 55 +order: 65 trace_note: "Recorded from another run: L-SHADE in 2 dimensions, so that the population can be drawn on the function's contour." --- diff --git a/examples/rosenbrock/README.md b/examples/rosenbrock/README.md index 78deaaff..ba2086b1 100644 --- a/examples/rosenbrock/README.md +++ b/examples/rosenbrock/README.md @@ -6,7 +6,7 @@ reference: "Rosenbrock, H. H. (1960). An automatic method for finding the greate reference_url: "https://doi.org/10.1093/comjnl/3.3.175" optimum: "0 (at (1, …, 1))" languages: [rust, python] -order: 50 +order: 60 trace_note: "Recorded from another run: CMA-ES in 2 dimensions, so that the population can be drawn on the function's contour." --- diff --git a/examples/schaffer1/README.md b/examples/schaffer1/README.md index 5e8e98b1..d667b601 100644 --- a/examples/schaffer1/README.md +++ b/examples/schaffer1/README.md @@ -6,7 +6,7 @@ reference: "Schaffer, J. D. (1985). Multiple objective optimization with vector reference_url: "" optimum: "the front f₂ = (√f₁ − 2)² for f₁ in [0, 4]; hypervolume 16.693 (reference point (4.4, 4.4))" languages: [rust, python] -order: 136 +order: 156 family: Schaffer --- diff --git a/examples/schaffer2/README.md b/examples/schaffer2/README.md index e8b98708..9f8c70d8 100644 --- a/examples/schaffer2/README.md +++ b/examples/schaffer2/README.md @@ -6,7 +6,7 @@ reference: "Schaffer, J. D. (1985). Multiple objective optimization with vector reference_url: "" optimum: "the front f₂ = (f₁ − 3)² for f₁ in [−1, 0) and f₂ = (f₁ − 1)² for f₁ in [0, 1]; hypervolume 26.053 (reference point (1.2, 17.6))" languages: [rust, python] -order: 137 +order: 157 family: Schaffer --- diff --git a/examples/schaffer_f6/README.md b/examples/schaffer_f6/README.md index bf664b15..4fe3ed61 100644 --- a/examples/schaffer_f6/README.md +++ b/examples/schaffer_f6/README.md @@ -6,7 +6,7 @@ reference: "Schaffer, J. D., Caruana, R. A., Eshelman, L. J. and Das, R. (1989). reference_url: "" optimum: "0 at the origin" languages: [rust, python] -order: 79 +order: 89 --- # Schaffer F6 diff --git a/examples/schwefel_2_26/README.md b/examples/schwefel_2_26/README.md index 4de4faba..e020134b 100644 --- a/examples/schwefel_2_26/README.md +++ b/examples/schwefel_2_26/README.md @@ -6,7 +6,7 @@ reference: "Schwefel, H.-P. (1981). Numerical Optimization of Computer Models. W reference_url: "" optimum: "−12569.4866 in 30 dimensions (every gene 420.9687)" languages: [rust, python] -order: 57 +order: 67 family: Schwefel trace_note: "Recorded from another run: L-SHADE in 2 dimensions, so that the population can be drawn on the function's contour." --- diff --git a/examples/shekel10/README.md b/examples/shekel10/README.md index 6f2bdf0c..9ab53981 100644 --- a/examples/shekel10/README.md +++ b/examples/shekel10/README.md @@ -6,7 +6,7 @@ reference: "Shekel, J. (1971). Test functions for multimodal search techniques. reference_url: "" optimum: "−10.53641 near (4, 4, 4, 4) (best known)" languages: [rust, python] -order: 73 +order: 83 family: Shekel tab: Shekel 10 --- diff --git a/examples/shekel5/README.md b/examples/shekel5/README.md index a2135ca2..2a4e1e53 100644 --- a/examples/shekel5/README.md +++ b/examples/shekel5/README.md @@ -6,7 +6,7 @@ reference: "Shekel, J. (1971). Test functions for multimodal search techniques. reference_url: "" optimum: "−10.15320 near (4, 4, 4, 4) (best known)" languages: [rust, python] -order: 71 +order: 81 family: Shekel tab: Shekel 5 --- diff --git a/examples/shekel7/README.md b/examples/shekel7/README.md index e634fa24..c1d0d480 100644 --- a/examples/shekel7/README.md +++ b/examples/shekel7/README.md @@ -6,7 +6,7 @@ reference: "Shekel, J. (1971). Test functions for multimodal search techniques. reference_url: "" optimum: "−10.40294 near (4, 4, 4, 4) (best known)" languages: [rust, python] -order: 72 +order: 82 family: Shekel tab: Shekel 7 --- diff --git a/examples/shekel_foxholes/README.md b/examples/shekel_foxholes/README.md index 928e3a85..67413884 100644 --- a/examples/shekel_foxholes/README.md +++ b/examples/shekel_foxholes/README.md @@ -6,7 +6,7 @@ reference: "De Jong, K. A. (1975). An Analysis of the Behavior of a Class of Gen reference_url: "https://hdl.handle.net/2027.42/4507" optimum: "0.99800 at (−31.97833, −31.97833) (best known)" languages: [rust, python] -order: 74 +order: 84 --- # Shekel's foxholes diff --git a/examples/six_hump_camel/README.md b/examples/six_hump_camel/README.md index 8f6247e7..e0c15030 100644 --- a/examples/six_hump_camel/README.md +++ b/examples/six_hump_camel/README.md @@ -6,7 +6,7 @@ reference: "Dixon, L. C. W. and Szegö, G. P. (eds.) (1978). Towards Global Opti reference_url: "" optimum: "−1.0316285 (at two points)" languages: [rust, python] -order: 61 +order: 71 --- # Six-hump camel diff --git a/examples/speed_reducer/README.md b/examples/speed_reducer/README.md index 2dc2de0d..f6846bdf 100644 --- a/examples/speed_reducer/README.md +++ b/examples/speed_reducer/README.md @@ -6,7 +6,7 @@ reference: "Golinski, J. (1970). Optimal synthesis problems solved by means of n reference_url: https://doi.org/10.1016/0022-2569(70)90064-9 optimum: "2996.348165 (weight), best known" languages: [rust, python] -order: 93 +order: 113 --- # Speed reducer diff --git a/examples/srn/README.md b/examples/srn/README.md index 9fec5d60..c813edbd 100644 --- a/examples/srn/README.md +++ b/examples/srn/README.md @@ -6,7 +6,7 @@ reference: "Srinivas, N. and Deb, K. (1994). Multiobjective optimization using n reference_url: https://doi.org/10.1162/evco.1994.2.3.221 optimum: "a front in three pieces, from (10.1, 2.61) to (222.97, −217.74); hypervolume 35478.6 (reference point (245, 25))" languages: [rust, python] -order: 142 +order: 162 --- # SRN (Srinivas and Deb) diff --git a/examples/styblinski_tang/README.md b/examples/styblinski_tang/README.md index df939852..d9cc3e61 100644 --- a/examples/styblinski_tang/README.md +++ b/examples/styblinski_tang/README.md @@ -6,7 +6,7 @@ reference: "Styblinski, M. A. and Tang, T.-S. (1990). Experiments in nonconvex o reference_url: "https://doi.org/10.1016/0893-6080(90)90029-K" optimum: "−1174.98 in 30 dimensions (−39.1662 n, at xᵢ ≈ −2.9035)" languages: [rust, python] -order: 52 +order: 62 trace_note: "Recorded from another run: CMA-ES with IPOP restarts in 2 dimensions, so that the population can be drawn on the function's contour." --- diff --git a/examples/tension_compression_spring/README.md b/examples/tension_compression_spring/README.md index c068c21e..19ec09bc 100644 --- a/examples/tension_compression_spring/README.md +++ b/examples/tension_compression_spring/README.md @@ -6,7 +6,7 @@ reference: "Belegundu, A. D. (1982). A Study of Mathematical Programming Methods reference_url: "" optimum: "0.01266523278831971 (weight), best known" languages: [rust, python] -order: 92 +order: 112 --- # Tension/compression spring diff --git a/examples/three_bar_truss/README.md b/examples/three_bar_truss/README.md index cd9a4718..0925d6d1 100644 --- a/examples/three_bar_truss/README.md +++ b/examples/three_bar_truss/README.md @@ -6,7 +6,7 @@ reference: "Nowacki, H. (1974). Optimization in pre-contract ship design. In Com reference_url: "" optimum: "263.895843 (volume, cm³)" languages: [rust, python] -order: 94 +order: 114 --- # Three-bar truss diff --git a/examples/three_hump_camel/README.md b/examples/three_hump_camel/README.md index 00da29c5..e5e0163e 100644 --- a/examples/three_hump_camel/README.md +++ b/examples/three_hump_camel/README.md @@ -6,7 +6,7 @@ reference: "Jamil, M. and Yang, X.-S. (2013). A literature survey of benchmark f reference_url: "https://doi.org/10.1504/IJMMNO.2013.055204" optimum: "0 at (0, 0)" languages: [rust, python] -order: 62 +order: 72 --- # Three-hump camel diff --git a/examples/tnk/README.md b/examples/tnk/README.md index 48fd098f..848182c9 100644 --- a/examples/tnk/README.md +++ b/examples/tnk/README.md @@ -6,7 +6,7 @@ reference: "Tanaka, M., Watanabe, H., Furukawa, Y. and Tanino, T. (1995). GA-bas reference_url: https://doi.org/10.1109/ICSMC.1995.537993 optimum: "a front in five pieces on the first constraint's boundary, from (0.0417, 1.0384) to (1.0384, 0.0417); hypervolume 0.6551 (reference point (1.2, 1.2))" languages: [rust, python] -order: 143 +order: 163 --- # TNK (Tanaka) diff --git a/examples/viennet1/README.md b/examples/viennet1/README.md index f65e53e0..d4e55425 100644 --- a/examples/viennet1/README.md +++ b/examples/viennet1/README.md @@ -6,7 +6,7 @@ reference: "Viennet, R., Fonteix, C. and Marc, I. (1996). Multicriteria optimiza reference_url: https://doi.org/10.1080/00207729608929211 optimum: "the image of the triangle with corners (0, 1), (0, −1) and (1, 0); hypervolume about 33.52 (reference point (4.4, 5.4, 4.2))" languages: [rust, python] -order: 162 +order: 182 family: Viennet --- diff --git a/examples/viennet2/README.md b/examples/viennet2/README.md index ce06f2fa..5578fff2 100644 --- a/examples/viennet2/README.md +++ b/examples/viennet2/README.md @@ -6,7 +6,7 @@ reference: "Viennet, R., Fonteix, C. and Marc, I. (1996). Multicriteria optimiza reference_url: https://doi.org/10.1080/00207729608929211 optimum: "not known in closed form; hypervolume about 0.7744 (reference point (4.3697, −16.4242, −11.9584))" languages: [rust, python] -order: 163 +order: 183 family: Viennet --- diff --git a/examples/viennet3/README.md b/examples/viennet3/README.md index 104c239a..5f8b7864 100644 --- a/examples/viennet3/README.md +++ b/examples/viennet3/README.md @@ -6,7 +6,7 @@ reference: "Viennet, R., Fonteix, C. and Marc, I. (1996). Multicriteria optimiza reference_url: https://doi.org/10.1080/00207729608929211 optimum: "not known in closed form: two curves; hypervolume about 5.3255 (reference point (9.016, 17.2407, 0.2036))" languages: [rust, python] -order: 164 +order: 184 family: Viennet --- diff --git a/examples/welded_beam/README.md b/examples/welded_beam/README.md index 4b4f43d9..2cfdec9f 100644 --- a/examples/welded_beam/README.md +++ b/examples/welded_beam/README.md @@ -6,7 +6,7 @@ reference: "Ragsdell, K. M. and Phillips, D. T. (1976). Optimal design of a clas reference_url: https://doi.org/10.1115/1.3438995 optimum: "1.7248523085993899 (seven constraints) and 2.3811341169090015 (five constraints), best known" languages: [rust, python] -order: 91 +order: 111 trace_note: "Recorded from the seeded run below, on the first form, WeldedBeam." --- diff --git a/examples/wfg1/README.md b/examples/wfg1/README.md index e112c544..55c13670 100644 --- a/examples/wfg1/README.md +++ b/examples/wfg1/README.md @@ -6,7 +6,7 @@ reference: "Huband, S., Hingston, P., Barone, L. and While, L. (2006). A review reference_url: https://doi.org/10.1109/TEVC.2005.861417 optimum: "the front f₁ = 2 (1 − cos(x₁π/2)), f₂ = 4 (1 − x₁ + sin(10πx₁) / 10π) for x₁ in [0, 1]; hypervolume 6.7857 (reference point (2.2, 4.4)); no genome reaches it in double precision: the closest front a genome can have is the front moved by 0.0695, hypervolume 6.3321" languages: [rust, python] -order: 146 +order: 166 family: WFG --- diff --git a/examples/wfg2/README.md b/examples/wfg2/README.md index 79ce45ad..bf01feca 100644 --- a/examples/wfg2/README.md +++ b/examples/wfg2/README.md @@ -6,7 +6,7 @@ reference: "Huband, S., Hingston, P., Barone, L. and While, L. (2006). A review reference_url: https://doi.org/10.1109/TEVC.2005.861417 optimum: "six regions of the curve f₁ = 2 (1 − cos(x₁π/2)), f₂ = 4 (1 − x₁ cos²(5πx₁)); hypervolume 6.1511 (reference point (2.2, 4.4))" languages: [rust, python] -order: 147 +order: 167 family: WFG --- diff --git a/examples/wfg3/README.md b/examples/wfg3/README.md index 55869edc..9faf129e 100644 --- a/examples/wfg3/README.md +++ b/examples/wfg3/README.md @@ -6,7 +6,7 @@ reference: "Huband, S., Hingston, P., Barone, L. and While, L. (2006). A review reference_url: https://doi.org/10.1109/TEVC.2005.861417 optimum: "the segment from (0, 4) to (2, 0); hypervolume 5.68 (reference point (2.2, 4.4))" languages: [rust, python] -order: 148 +order: 168 family: WFG --- diff --git a/examples/wfg4/README.md b/examples/wfg4/README.md index 5deab5e5..7e6be8f9 100644 --- a/examples/wfg4/README.md +++ b/examples/wfg4/README.md @@ -6,7 +6,7 @@ reference: "Huband, S., Hingston, P., Barone, L. and While, L. (2006). A review reference_url: https://doi.org/10.1109/TEVC.2005.861417 optimum: "the front (f₁ / 2)² + (f₂ / 4)² = 1, a quarter ellipse from (0, 4) to (2, 0); hypervolume 3.3968 (reference point (2.2, 4.4))" languages: [rust, python] -order: 149 +order: 169 family: WFG --- diff --git a/examples/wfg5/README.md b/examples/wfg5/README.md index 9504c565..94bd0103 100644 --- a/examples/wfg5/README.md +++ b/examples/wfg5/README.md @@ -6,7 +6,7 @@ reference: "Huband, S., Hingston, P., Barone, L. and While, L. (2006). A review reference_url: https://doi.org/10.1109/TEVC.2005.861417 optimum: "the front (f₁ / 2)² + (f₂ / 4)² = 1, a quarter ellipse from (0, 4) to (2, 0); hypervolume 3.3968 (reference point (2.2, 4.4))" languages: [rust, python] -order: 150 +order: 170 family: WFG --- diff --git a/examples/wfg6/README.md b/examples/wfg6/README.md index 3fda3bd3..806074cc 100644 --- a/examples/wfg6/README.md +++ b/examples/wfg6/README.md @@ -6,7 +6,7 @@ reference: "Huband, S., Hingston, P., Barone, L. and While, L. (2006). A review reference_url: https://doi.org/10.1109/TEVC.2005.861417 optimum: "the front (f₁ / 2)² + (f₂ / 4)² = 1, a quarter ellipse from (0, 4) to (2, 0); hypervolume 3.3968 (reference point (2.2, 4.4))" languages: [rust, python] -order: 151 +order: 171 family: WFG --- diff --git a/examples/wfg7/README.md b/examples/wfg7/README.md index 9c40d8cc..7a70443b 100644 --- a/examples/wfg7/README.md +++ b/examples/wfg7/README.md @@ -6,7 +6,7 @@ reference: "Huband, S., Hingston, P., Barone, L. and While, L. (2006). A review reference_url: https://doi.org/10.1109/TEVC.2005.861417 optimum: "the quarter ellipse (f₁/2)² + (f₂/4)² = 1; hypervolume 3.3968 (reference point (2.2, 4.4))" languages: [rust, python] -order: 152 +order: 172 family: WFG --- diff --git a/examples/wfg8/README.md b/examples/wfg8/README.md index 8fef7cb2..7acf3350 100644 --- a/examples/wfg8/README.md +++ b/examples/wfg8/README.md @@ -6,7 +6,7 @@ reference: "Huband, S., Hingston, P., Barone, L. and While, L. (2006). A review reference_url: https://doi.org/10.1109/TEVC.2005.861417 optimum: "the quarter ellipse (f₁/2)² + (f₂/4)² = 1; hypervolume 3.3968 (reference point (2.2, 4.4))" languages: [rust, python] -order: 153 +order: 173 family: WFG --- diff --git a/examples/wfg9/README.md b/examples/wfg9/README.md index 7457ab5c..4921d09c 100644 --- a/examples/wfg9/README.md +++ b/examples/wfg9/README.md @@ -6,7 +6,7 @@ reference: "Huband, S., Hingston, P., Barone, L. and While, L. (2006). A review reference_url: https://doi.org/10.1109/TEVC.2005.861417 optimum: "the quarter ellipse (f₁/2)² + (f₂/4)² = 1; hypervolume 3.3968 (reference point (2.2, 4.4))" languages: [rust, python] -order: 154 +order: 174 family: WFG --- diff --git a/examples/zdt1/README.md b/examples/zdt1/README.md index 8e16c8cf..0fb3ad3e 100644 --- a/examples/zdt1/README.md +++ b/examples/zdt1/README.md @@ -6,7 +6,7 @@ reference: "Zitzler, E., Deb, K. and Thiele, L. (2000). Comparison of multiobjec reference_url: https://doi.org/10.1162/106365600568202 optimum: "hypervolume 0.8767 (reference point (1.1, 1.1))" languages: [rust, python] -order: 130 +order: 150 family: ZDT --- diff --git a/examples/zdt2/README.md b/examples/zdt2/README.md index 4357aed8..40c1ae62 100644 --- a/examples/zdt2/README.md +++ b/examples/zdt2/README.md @@ -6,7 +6,7 @@ reference: "Zitzler, E., Deb, K. and Thiele, L. (2000). Comparison of multiobjec reference_url: https://doi.org/10.1162/106365600568202 optimum: "the front f₂ = 1 − f₁² for f₁ in [0, 1]; hypervolume 0.5433 (reference point (1.1, 1.1))" languages: [rust, python] -order: 131 +order: 151 family: ZDT --- diff --git a/examples/zdt3/README.md b/examples/zdt3/README.md index e61c9cb6..6c189bd6 100644 --- a/examples/zdt3/README.md +++ b/examples/zdt3/README.md @@ -6,7 +6,7 @@ reference: "Zitzler, E., Deb, K. and Thiele, L. (2000). Comparison of multiobjec reference_url: https://doi.org/10.1162/106365600568202 optimum: "five pieces of f₂ = 1 − √f₁ − f₁ sin(10π f₁); hypervolume 1.3318 (reference point (1.1, 1.1))" languages: [rust, python] -order: 132 +order: 152 family: ZDT --- diff --git a/examples/zdt4/README.md b/examples/zdt4/README.md index 9504f7a5..1b44af0c 100644 --- a/examples/zdt4/README.md +++ b/examples/zdt4/README.md @@ -6,7 +6,7 @@ reference: "Zitzler, E., Deb, K. and Thiele, L. (2000). Comparison of multiobjec reference_url: https://doi.org/10.1162/106365600568202 optimum: "the front f₂ = 1 − √f₁ for f₁ in [0, 1]; hypervolume 0.8767 (reference point (1.1, 1.1))" languages: [rust, python] -order: 133 +order: 153 family: ZDT --- diff --git a/examples/zdt5/README.md b/examples/zdt5/README.md index dc593fad..cfd2cb45 100644 --- a/examples/zdt5/README.md +++ b/examples/zdt5/README.md @@ -6,7 +6,7 @@ reference: "Zitzler, E., Deb, K. and Thiele, L. (2000). Comparison of multiobjec reference_url: https://doi.org/10.1162/106365600568202 optimum: "31 points f₂ = 10 / f₁ for f₁ = 1, 2, …, 31; hypervolume 323.15 (reference point (34.1, 11))" languages: [rust, python] -order: 134 +order: 154 family: ZDT --- diff --git a/examples/zdt6/README.md b/examples/zdt6/README.md index e654ba42..d2171697 100644 --- a/examples/zdt6/README.md +++ b/examples/zdt6/README.md @@ -6,7 +6,7 @@ reference: "Zitzler, E., Deb, K. and Thiele, L. (2000). Comparison of multiobjec reference_url: https://doi.org/10.1162/106365600568202 optimum: "the front f₂ = 1 − f₁² for f₁ from 0.2808 to 1; hypervolume 0.5079 (reference point (1.1, 1.1))" languages: [rust, python] -order: 135 +order: 155 family: ZDT --- From 46436aaf7ca6d1a9b22ff56b42a69b6fe69cf20d Mon Sep 17 00:00:00 2001 From: Someguy Date: Thu, 1 Oct 2026 17:03:46 +0300 Subject: [PATCH 04/16] feat(site): contours of batch 10b's functions, and of rotated functions --- .../projects/genoxide/player/contour.js | 86 +++++++++++++++++++ .../genoxide/player/plots/ContourPlot.jsx | 11 ++- site/lib/projects/genoxide/examples.js | 1 + 3 files changed, 95 insertions(+), 3 deletions(-) diff --git a/site/components/projects/genoxide/player/contour.js b/site/components/projects/genoxide/player/contour.js index 5d01ddb2..56dfb337 100644 --- a/site/components/projects/genoxide/player/contour.js +++ b/site/components/projects/genoxide/player/contour.js @@ -83,8 +83,94 @@ export const FUNCTIONS = { schwefel_2_21: (x, y) => Math.max(Math.abs(x), Math.abs(y)), schwefel_2_22: (x, y) => Math.abs(x) + Math.abs(y) + Math.abs(x * y), trid: (x, y) => (x - 1) ** 2 + (y - 1) ** 2 - x * y, + // the functions of batch 10b, in 2 dimensions + sum_of_different_powers: (x, y) => Math.abs(x) ** 2 + Math.abs(y) ** 3, + step: (x, y) => Math.floor(x + 0.5) ** 2 + Math.floor(y + 0.5) ** 2, + quartic: (x, y) => x ** 4 + 2 * y ** 4, + penalized1: (x, y) => { + const [y1, y2] = [1 + (x + 1) / 4, 1 + (y + 1) / 4]; + const levy = 10 * Math.sin(Math.PI * y1) ** 2 + (y1 - 1) ** 2 * (1 + 10 * Math.sin(Math.PI * y2) ** 2) + (y2 - 1) ** 2; + return (Math.PI / 2) * levy + penalty(x, 10, 100, 4) + penalty(y, 10, 100, 4); + }, + penalized2: (x, y) => + 0.1 * (Math.sin(3 * Math.PI * x) ** 2 + (x - 1) ** 2 * (1 + Math.sin(3 * Math.PI * y) ** 2) + (y - 1) ** 2 * (1 + Math.sin(2 * Math.PI * y) ** 2)) + + penalty(x, 5, 100, 4) + + penalty(y, 5, 100, 4), + high_conditioned_elliptic: (x, y) => x * x + 1e6 * y * y, + bent_cigar: (x, y) => x * x + 1e6 * y * y, + discus: (x, y) => 1e6 * x * x + y * y, + different_powers: (x, y) => Math.sqrt(Math.abs(x) ** 2 + Math.abs(y) ** 6), + buche_rastrigin: (x, y) => { + // the first gene's scale is 10 on its positive side; the second's is √10 + const z1 = (oscillation(x) > 0 ? 10 : 1) * oscillation(x); + const z2 = Math.sqrt(10) * oscillation(y); + const outside = Math.max(0, Math.abs(x) - 5) ** 2 + Math.max(0, Math.abs(y) - 5) ** 2; + return 10 * (2 - Math.cos(2 * Math.PI * z1) - Math.cos(2 * Math.PI * z2)) + z1 * z1 + z2 * z2 + 100 * outside; + }, + non_continuous_rastrigin: (x, y) => { + const step = (v) => (Math.abs(v) < 0.5 ? v : Math.sign(v) * Math.round(Math.abs(2 * v)) / 2); + const [a, b] = [step(x), step(y)]; + return 20 + a * a - 10 * Math.cos(2 * Math.PI * a) + b * b - 10 * Math.cos(2 * Math.PI * b); + }, + weierstrass: (x, y) => weierstrass(x) + weierstrass(y) - 2 * weierstrass(0), + katsuura: (x, y) => { + const factor = (v, i) => { + let sum = 0; + for (let j = 1; j <= 32; j++) { + const scaled = 2 ** j * v; + sum += Math.abs(scaled - Math.sign(scaled) * Math.round(Math.abs(scaled))) / 2 ** j; + } + return (1 + i * sum) ** (10 / 2 ** 1.2); + }; + return 2.5 * factor(x, 1) * factor(y, 2) - 2.5; + }, + happy_cat: (x, y) => { + const squares = x * x + y * y; + return Math.abs(squares - 2) ** 0.25 + (0.5 * squares + x + y) / 2 + 0.5; + }, + hg_bat: (x, y) => { + const squares = x * x + y * y; + return Math.sqrt(Math.abs(squares * squares - (x + y) ** 2)) + (0.5 * squares + x + y) / 2 + 0.5; + }, + schaffer_f7: (x, y) => { + const s = Math.sqrt(x * x + y * y); + return (Math.sqrt(s) * (1 + Math.sin(50 * s ** 0.2) ** 2)) ** 2; + }, + rotated_hyper_ellipsoid: (x, y) => 2 * x * x + y * y, }; +/** + * `f` rotated as genoxide's `problems::Rotated` rotates it: at `c + M (p − c)`, for the + * `rotation` of a trace's problem (`{ matrix, center }`, a 2 × 2 matrix by rows); `f` itself + * without one. + */ +export function rotated(f, rotation) { + if (!f || !rotation) return f; + const [[a, b], [c, d]] = rotation.matrix; + const [cx, cy] = rotation.center; + return (x, y) => f(cx + a * (x - cx) + b * (y - cy), cy + c * (x - cx) + d * (y - cy)); +} + +// Yao, Liu and Lin's penalty u(x, a, k, m) +function penalty(x, a, k, m) { + return Math.abs(x) > a ? k * (Math.abs(x) - a) ** m : 0; +} + +// BBOB's oscillation T_osz of one value +function oscillation(x) { + if (x === 0) return 0; + const logarithm = Math.log(Math.abs(x)); + const [c1, c2] = x > 0 ? [10, 7.9] : [5.5, 3.1]; + return Math.sign(x) * Math.exp(logarithm + 0.049 * (Math.sin(c1 * logarithm) + Math.sin(c2 * logarithm))); +} + +// a gene's part of the Weierstrass function, a = 0.5, b = 3, k from 0 to 20 +function weierstrass(x) { + let sum = 0; + for (let k = 0; k <= 20; k++) sum += 0.5 ** k * Math.cos(2 * Math.PI * 3 ** k * (x + 0.5)); + return sum; +} + // Langermann's function in 2 dimensions (Molga and Smutnicki's constants), and the centers of // Shekel's foxholes (De Jong's F5), x₁ varying first const LANGERMANN_A = [ diff --git a/site/components/projects/genoxide/player/plots/ContourPlot.jsx b/site/components/projects/genoxide/player/plots/ContourPlot.jsx index 17f41ef4..2f090359 100644 --- a/site/components/projects/genoxide/player/plots/ContourPlot.jsx +++ b/site/components/projects/genoxide/player/plots/ContourPlot.jsx @@ -3,7 +3,7 @@ import { useEffect, useId, useMemo, useState } from "react"; import { categorical, formatValue, linear, resolveColor, ticks } from "../chart-kit"; import { Axes, Legend, Marker, PlotBox, TipRows, Tooltip, nearest, pointerIn } from "../chart-parts"; -import { FUNCTIONS, contourLegend, gridImage, isoline, sample } from "../contour"; +import { FUNCTIONS, contourLegend, gridImage, isoline, rotated, sample } from "../contour"; const GRID = 140; const LEVELS = [0.12, 0.24, 0.36, 0.48, 0.6, 0.72, 0.84]; @@ -14,7 +14,8 @@ const LEVELS = [0.12, 0.24, 0.36, 0.48, 0.6, 0.72, 0.84]; * `compact` (a panel of a grid) leaves the legend to the grid. Optionally, * `problem.labels` names the axes and the field (`{ x, y, f }`: a function * of more than 2 variables is drawn as a slice or a projection), and - * `problem.minima_label` the minima, when they aren't proven global. + * `problem.minima_label` the minima, when they aren't proven global, and `problem.rotation` + * (`{ matrix, center }`) a function rotated as genoxide's `problems::Rotated` rotates it. * A local method's frames can add `state.simplex` (its vertices, drawn as a * polygon: Nelder-Mead's triangle) and `state.ends` (where its runs before * converged), and `problem.population_label` names the points (e.g. "simplex"). @@ -24,7 +25,11 @@ export default function ContourPlot({ trace, frame, dark, compact = false }) { const [image, setImage] = useState(null); const clip = `clip${useId().replace(/[^a-zA-Z0-9_-]/g, "")}`; const problem = trace.problem ?? {}; - const f = FUNCTIONS[problem.function] ?? null; + const rotationKey = JSON.stringify(problem.rotation ?? null); + const f = useMemo( + () => rotated(FUNCTIONS[problem.function] ?? null, JSON.parse(rotationKey)), + [problem.function, rotationKey], + ); const bounds = problem.bounds ?? [ [-5, 5], [-5, 5], diff --git a/site/lib/projects/genoxide/examples.js b/site/lib/projects/genoxide/examples.js index 74407555..25d41ad2 100644 --- a/site/lib/projects/genoxide/examples.js +++ b/site/lib/projects/genoxide/examples.js @@ -258,6 +258,7 @@ const FAMILY_SUMMARIES = { Hartmann: "Hartmann's function, four Gaussian wells in the unit cube, in 3 and 6 dimensions.", Shekel: "Shekel's function in 4 dimensions, with 5, 7 or 10 narrow wells.", Schwefel: "Two of the problems of Schwefel's book: a rotated ellipsoid and a deceptive function.", + Penalized: "Yao, Liu and Lin's two penalized functions: a grid of shallow wells over the box, and a steep wall near its bounds.", Schaffer: "One variable and two objectives, from the paper of the first multi-objective genetic algorithm, VEGA.", Viennet: "Three objectives of two variables, with curved and split Pareto fronts.", "N-Queens": From 83db3ed2031745b2d74ecf0c8dd662983cb0e6ae Mon Sep 17 00:00:00 2001 From: Someguy Date: Thu, 1 Oct 2026 17:03:47 +0300 Subject: [PATCH 05/16] docs(examples): an example per function of batch 10b Seventeen examples, each in Rust and Python with its output and trace: the unimodal functions compare CMA-ES, sep-CMA-ES, DE, PSO and a GA as they are and shifted and rotated, and the multimodal ones count the runs that reach the minimum from ten seeds each. --- examples/README.md | 17 ++ examples/bent_cigar/README.md | 85 ++++++ examples/bent_cigar/main.py | 97 +++++++ examples/bent_cigar/main.rs | 151 ++++++++++ examples/bent_cigar/output.txt | 15 + examples/bent_cigar/trace.json | 102 +++++++ examples/bent_cigar/trace.py | 189 +++++++++++++ examples/bent_cigar/trace.rs | 260 +++++++++++++++++ examples/buche_rastrigin/README.md | 83 ++++++ examples/buche_rastrigin/main.py | 86 ++++++ examples/buche_rastrigin/main.rs | 118 ++++++++ examples/buche_rastrigin/output.txt | 8 + examples/buche_rastrigin/trace.json | 102 +++++++ examples/buche_rastrigin/trace.py | 189 +++++++++++++ examples/buche_rastrigin/trace.rs | 261 +++++++++++++++++ examples/different_powers/README.md | 84 ++++++ examples/different_powers/main.py | 97 +++++++ examples/different_powers/main.rs | 151 ++++++++++ examples/different_powers/output.txt | 15 + examples/different_powers/trace.json | 102 +++++++ examples/different_powers/trace.py | 190 +++++++++++++ examples/different_powers/trace.rs | 264 ++++++++++++++++++ examples/discus/README.md | 84 ++++++ examples/discus/main.py | 97 +++++++ examples/discus/main.rs | 151 ++++++++++ examples/discus/output.txt | 15 + examples/discus/trace.json | 102 +++++++ examples/discus/trace.py | 190 +++++++++++++ examples/discus/trace.rs | 264 ++++++++++++++++++ examples/happy_cat/README.md | 81 ++++++ examples/happy_cat/main.py | 86 ++++++ examples/happy_cat/main.rs | 118 ++++++++ examples/happy_cat/output.txt | 8 + examples/happy_cat/trace.json | 102 +++++++ examples/happy_cat/trace.py | 189 +++++++++++++ examples/happy_cat/trace.rs | 261 +++++++++++++++++ examples/hg_bat/README.md | 76 +++++ examples/hg_bat/main.py | 86 ++++++ examples/hg_bat/main.rs | 118 ++++++++ examples/hg_bat/output.txt | 8 + examples/hg_bat/trace.json | 102 +++++++ examples/hg_bat/trace.py | 189 +++++++++++++ examples/hg_bat/trace.rs | 261 +++++++++++++++++ examples/high_conditioned_elliptic/README.md | 91 ++++++ examples/high_conditioned_elliptic/main.py | 97 +++++++ examples/high_conditioned_elliptic/main.rs | 151 ++++++++++ examples/high_conditioned_elliptic/output.txt | 15 + examples/high_conditioned_elliptic/trace.json | 102 +++++++ examples/high_conditioned_elliptic/trace.py | 190 +++++++++++++ examples/high_conditioned_elliptic/trace.rs | 264 ++++++++++++++++++ examples/katsuura/README.md | 90 ++++++ examples/katsuura/main.py | 85 ++++++ examples/katsuura/main.rs | 117 ++++++++ examples/katsuura/output.txt | 8 + examples/katsuura/trace.json | 102 +++++++ examples/katsuura/trace.py | 189 +++++++++++++ examples/katsuura/trace.rs | 261 +++++++++++++++++ examples/non_continuous_rastrigin/README.md | 79 ++++++ examples/non_continuous_rastrigin/main.py | 86 ++++++ examples/non_continuous_rastrigin/main.rs | 118 ++++++++ examples/non_continuous_rastrigin/output.txt | 8 + examples/non_continuous_rastrigin/trace.json | 102 +++++++ examples/non_continuous_rastrigin/trace.py | 189 +++++++++++++ examples/non_continuous_rastrigin/trace.rs | 261 +++++++++++++++++ examples/penalized1/README.md | 81 ++++++ examples/penalized1/main.py | 86 ++++++ examples/penalized1/main.rs | 118 ++++++++ examples/penalized1/output.txt | 8 + examples/penalized1/trace.json | 73 +++++ examples/penalized1/trace.py | 189 +++++++++++++ examples/penalized1/trace.rs | 261 +++++++++++++++++ examples/penalized2/README.md | 81 ++++++ examples/penalized2/main.py | 85 ++++++ examples/penalized2/main.rs | 117 ++++++++ examples/penalized2/output.txt | 8 + examples/penalized2/trace.json | 68 +++++ examples/penalized2/trace.py | 189 +++++++++++++ examples/penalized2/trace.rs | 261 +++++++++++++++++ examples/quartic/README.md | 90 ++++++ examples/quartic/main.py | 125 +++++++++ examples/quartic/main.rs | 194 +++++++++++++ examples/quartic/output.txt | 15 + examples/quartic/trace.json | 20 ++ examples/quartic/trace.py | 189 +++++++++++++ examples/quartic/trace.rs | 260 +++++++++++++++++ examples/rotated_hyper_ellipsoid/README.md | 94 +++++++ examples/rotated_hyper_ellipsoid/main.py | 97 +++++++ examples/rotated_hyper_ellipsoid/main.rs | 151 ++++++++++ examples/rotated_hyper_ellipsoid/output.txt | 15 + examples/rotated_hyper_ellipsoid/trace.json | 59 ++++ examples/rotated_hyper_ellipsoid/trace.py | 190 +++++++++++++ examples/rotated_hyper_ellipsoid/trace.rs | 264 ++++++++++++++++++ examples/schaffer_f7/README.md | 78 ++++++ examples/schaffer_f7/main.py | 86 ++++++ examples/schaffer_f7/main.rs | 118 ++++++++ examples/schaffer_f7/output.txt | 8 + examples/schaffer_f7/trace.json | 102 +++++++ examples/schaffer_f7/trace.py | 189 +++++++++++++ examples/schaffer_f7/trace.rs | 261 +++++++++++++++++ examples/step/README.md | 78 ++++++ examples/step/main.py | 93 ++++++ examples/step/main.rs | 147 ++++++++++ examples/step/output.txt | 8 + examples/step/trace.json | 21 ++ examples/step/trace.py | 189 +++++++++++++ examples/step/trace.rs | 260 +++++++++++++++++ examples/sum_of_different_powers/README.md | 91 ++++++ examples/sum_of_different_powers/main.py | 97 +++++++ examples/sum_of_different_powers/main.rs | 151 ++++++++++ examples/sum_of_different_powers/output.txt | 15 + examples/sum_of_different_powers/trace.json | 36 +++ examples/sum_of_different_powers/trace.py | 189 +++++++++++++ examples/sum_of_different_powers/trace.rs | 260 +++++++++++++++++ examples/weierstrass/README.md | 78 ++++++ examples/weierstrass/main.py | 86 ++++++ examples/weierstrass/main.rs | 118 ++++++++ examples/weierstrass/output.txt | 8 + examples/weierstrass/trace.json | 102 +++++++ examples/weierstrass/trace.py | 189 +++++++++++++ examples/weierstrass/trace.rs | 261 +++++++++++++++++ 120 files changed, 14566 insertions(+) create mode 100644 examples/bent_cigar/README.md create mode 100644 examples/bent_cigar/main.py create mode 100644 examples/bent_cigar/main.rs create mode 100644 examples/bent_cigar/output.txt create mode 100644 examples/bent_cigar/trace.json create mode 100644 examples/bent_cigar/trace.py create mode 100644 examples/bent_cigar/trace.rs create mode 100644 examples/buche_rastrigin/README.md create mode 100644 examples/buche_rastrigin/main.py create mode 100644 examples/buche_rastrigin/main.rs create mode 100644 examples/buche_rastrigin/output.txt create mode 100644 examples/buche_rastrigin/trace.json create mode 100644 examples/buche_rastrigin/trace.py create mode 100644 examples/buche_rastrigin/trace.rs create mode 100644 examples/different_powers/README.md create mode 100644 examples/different_powers/main.py create mode 100644 examples/different_powers/main.rs create mode 100644 examples/different_powers/output.txt create mode 100644 examples/different_powers/trace.json create mode 100644 examples/different_powers/trace.py create mode 100644 examples/different_powers/trace.rs create mode 100644 examples/discus/README.md create mode 100644 examples/discus/main.py create mode 100644 examples/discus/main.rs create mode 100644 examples/discus/output.txt create mode 100644 examples/discus/trace.json create mode 100644 examples/discus/trace.py create mode 100644 examples/discus/trace.rs create mode 100644 examples/happy_cat/README.md create mode 100644 examples/happy_cat/main.py create mode 100644 examples/happy_cat/main.rs create mode 100644 examples/happy_cat/output.txt create mode 100644 examples/happy_cat/trace.json create mode 100644 examples/happy_cat/trace.py create mode 100644 examples/happy_cat/trace.rs create mode 100644 examples/hg_bat/README.md create mode 100644 examples/hg_bat/main.py create mode 100644 examples/hg_bat/main.rs create mode 100644 examples/hg_bat/output.txt create mode 100644 examples/hg_bat/trace.json create mode 100644 examples/hg_bat/trace.py create mode 100644 examples/hg_bat/trace.rs create mode 100644 examples/high_conditioned_elliptic/README.md create mode 100644 examples/high_conditioned_elliptic/main.py create mode 100644 examples/high_conditioned_elliptic/main.rs create mode 100644 examples/high_conditioned_elliptic/output.txt create mode 100644 examples/high_conditioned_elliptic/trace.json create mode 100644 examples/high_conditioned_elliptic/trace.py create mode 100644 examples/high_conditioned_elliptic/trace.rs create mode 100644 examples/katsuura/README.md create mode 100644 examples/katsuura/main.py create mode 100644 examples/katsuura/main.rs create mode 100644 examples/katsuura/output.txt create mode 100644 examples/katsuura/trace.json create mode 100644 examples/katsuura/trace.py create mode 100644 examples/katsuura/trace.rs create mode 100644 examples/non_continuous_rastrigin/README.md create mode 100644 examples/non_continuous_rastrigin/main.py create mode 100644 examples/non_continuous_rastrigin/main.rs create mode 100644 examples/non_continuous_rastrigin/output.txt create mode 100644 examples/non_continuous_rastrigin/trace.json create mode 100644 examples/non_continuous_rastrigin/trace.py create mode 100644 examples/non_continuous_rastrigin/trace.rs create mode 100644 examples/penalized1/README.md create mode 100644 examples/penalized1/main.py create mode 100644 examples/penalized1/main.rs create mode 100644 examples/penalized1/output.txt create mode 100644 examples/penalized1/trace.json create mode 100644 examples/penalized1/trace.py create mode 100644 examples/penalized1/trace.rs create mode 100644 examples/penalized2/README.md create mode 100644 examples/penalized2/main.py create mode 100644 examples/penalized2/main.rs create mode 100644 examples/penalized2/output.txt create mode 100644 examples/penalized2/trace.json create mode 100644 examples/penalized2/trace.py create mode 100644 examples/penalized2/trace.rs create mode 100644 examples/quartic/README.md create mode 100644 examples/quartic/main.py create mode 100644 examples/quartic/main.rs create mode 100644 examples/quartic/output.txt create mode 100644 examples/quartic/trace.json create mode 100644 examples/quartic/trace.py create mode 100644 examples/quartic/trace.rs create mode 100644 examples/rotated_hyper_ellipsoid/README.md create mode 100644 examples/rotated_hyper_ellipsoid/main.py create mode 100644 examples/rotated_hyper_ellipsoid/main.rs create mode 100644 examples/rotated_hyper_ellipsoid/output.txt create mode 100644 examples/rotated_hyper_ellipsoid/trace.json create mode 100644 examples/rotated_hyper_ellipsoid/trace.py create mode 100644 examples/rotated_hyper_ellipsoid/trace.rs create mode 100644 examples/schaffer_f7/README.md create mode 100644 examples/schaffer_f7/main.py create mode 100644 examples/schaffer_f7/main.rs create mode 100644 examples/schaffer_f7/output.txt create mode 100644 examples/schaffer_f7/trace.json create mode 100644 examples/schaffer_f7/trace.py create mode 100644 examples/schaffer_f7/trace.rs create mode 100644 examples/step/README.md create mode 100644 examples/step/main.py create mode 100644 examples/step/main.rs create mode 100644 examples/step/output.txt create mode 100644 examples/step/trace.json create mode 100644 examples/step/trace.py create mode 100644 examples/step/trace.rs create mode 100644 examples/sum_of_different_powers/README.md create mode 100644 examples/sum_of_different_powers/main.py create mode 100644 examples/sum_of_different_powers/main.rs create mode 100644 examples/sum_of_different_powers/output.txt create mode 100644 examples/sum_of_different_powers/trace.json create mode 100644 examples/sum_of_different_powers/trace.py create mode 100644 examples/sum_of_different_powers/trace.rs create mode 100644 examples/weierstrass/README.md create mode 100644 examples/weierstrass/main.py create mode 100644 examples/weierstrass/main.rs create mode 100644 examples/weierstrass/output.txt create mode 100644 examples/weierstrass/trace.json create mode 100644 examples/weierstrass/trace.py create mode 100644 examples/weierstrass/trace.rs diff --git a/examples/README.md b/examples/README.md index 11bbfebe..8f38e23f 100644 --- a/examples/README.md +++ b/examples/README.md @@ -48,6 +48,14 @@ python examples/tsp_berlin52/main.py | [Trid](trid/) | continuous | Rust, Python | [tachsin.gr](https://tachsin.gr/projects/genoxide/examples/trid) | | [Dixon-Price](dixon_price/) | continuous | Rust, Python | [tachsin.gr](https://tachsin.gr/projects/genoxide/examples/dixon-price) | | [Powell](powell/) | continuous | Rust, Python | [tachsin.gr](https://tachsin.gr/projects/genoxide/examples/powell) | +| [Sum of different powers](sum_of_different_powers/) | continuous | Rust, Python | [tachsin.gr](https://tachsin.gr/projects/genoxide/examples/sum-of-different-powers) | +| [Step](step/) | continuous | Rust, Python | [tachsin.gr](https://tachsin.gr/projects/genoxide/examples/step) | +| [Quartic](quartic/) | continuous | Rust, Python | [tachsin.gr](https://tachsin.gr/projects/genoxide/examples/quartic) | +| [Rotated hyper-ellipsoid](rotated_hyper_ellipsoid/) | continuous | Rust, Python | [tachsin.gr](https://tachsin.gr/projects/genoxide/examples/rotated-hyper-ellipsoid) | +| [High-conditioned elliptic](high_conditioned_elliptic/) | continuous | Rust, Python | [tachsin.gr](https://tachsin.gr/projects/genoxide/examples/high-conditioned-elliptic) | +| [Bent cigar](bent_cigar/) | continuous | Rust, Python | [tachsin.gr](https://tachsin.gr/projects/genoxide/examples/bent-cigar) | +| [Discus](discus/) | continuous | Rust, Python | [tachsin.gr](https://tachsin.gr/projects/genoxide/examples/discus) | +| [Different powers](different_powers/) | continuous | Rust, Python | [tachsin.gr](https://tachsin.gr/projects/genoxide/examples/different-powers) | | [Rosenbrock](rosenbrock/) | continuous | Rust, Python | [tachsin.gr](https://tachsin.gr/projects/genoxide/examples/rosenbrock) | | [Levy](levy/) | continuous | Rust, Python | [tachsin.gr](https://tachsin.gr/projects/genoxide/examples/levy) | | [Styblinski-Tang](styblinski_tang/) | continuous | Rust, Python | [tachsin.gr](https://tachsin.gr/projects/genoxide/examples/styblinski-tang) | @@ -78,6 +86,15 @@ python examples/tsp_berlin52/main.py | [Easom](easom/) | continuous | Rust, Python | [tachsin.gr](https://tachsin.gr/projects/genoxide/examples/easom) | | [Eggholder](eggholder/) | continuous | Rust, Python | [tachsin.gr](https://tachsin.gr/projects/genoxide/examples/eggholder) | | [Schaffer F6](schaffer_f6/) | continuous | Rust, Python | [tachsin.gr](https://tachsin.gr/projects/genoxide/examples/schaffer-f6) | +| [Schaffer F7](schaffer_f7/) | continuous | Rust, Python | [tachsin.gr](https://tachsin.gr/projects/genoxide/examples/schaffer-f7) | +| [Penalized 1](penalized1/) | continuous | Rust, Python | [tachsin.gr](https://tachsin.gr/projects/genoxide/examples/penalized1) | +| [Penalized 2](penalized2/) | continuous | Rust, Python | [tachsin.gr](https://tachsin.gr/projects/genoxide/examples/penalized2) | +| [Büche-Rastrigin](buche_rastrigin/) | continuous | Rust, Python | [tachsin.gr](https://tachsin.gr/projects/genoxide/examples/buche-rastrigin) | +| [Non-continuous Rastrigin](non_continuous_rastrigin/) | continuous | Rust, Python | [tachsin.gr](https://tachsin.gr/projects/genoxide/examples/non-continuous-rastrigin) | +| [Weierstrass](weierstrass/) | continuous | Rust, Python | [tachsin.gr](https://tachsin.gr/projects/genoxide/examples/weierstrass) | +| [Katsuura](katsuura/) | continuous | Rust, Python | [tachsin.gr](https://tachsin.gr/projects/genoxide/examples/katsuura) | +| [HappyCat](happy_cat/) | continuous | Rust, Python | [tachsin.gr](https://tachsin.gr/projects/genoxide/examples/happy-cat) | +| [HGBat](hg_bat/) | continuous | Rust, Python | [tachsin.gr](https://tachsin.gr/projects/genoxide/examples/hg-bat) | | [Pressure vessel design](pressure_vessel/) | constrained | Rust, Python | [tachsin.gr](https://tachsin.gr/projects/genoxide/examples/pressure-vessel) | | [Welded beam design](welded_beam/) | constrained | Rust, Python | [tachsin.gr](https://tachsin.gr/projects/genoxide/examples/welded-beam) | | [Tension/compression spring](tension_compression_spring/) | constrained | Rust, Python | [tachsin.gr](https://tachsin.gr/projects/genoxide/examples/tension-compression-spring) | diff --git a/examples/bent_cigar/README.md b/examples/bent_cigar/README.md new file mode 100644 index 00000000..ba0bb702 --- /dev/null +++ b/examples/bent_cigar/README.md @@ -0,0 +1,85 @@ +--- +title: Bent cigar +category: continuous +summary: Minimize a narrow ridge, a thousand times longer than wide, in 30 dimensions, as it is and shifted and rotated, and compare CMA-ES, sep-CMA-ES, DE, PSO and a GA. +reference: "Hansen, N., Finck, S., Ros, R. and Auger, A. (2009). Real-Parameter Black-Box Optimization Benchmarking 2009: Noiseless Functions Definitions. INRIA research report RR-6829." +reference_url: "https://hal.inria.fr/inria-00362633" +optimum: "0 (at the origin)" +languages: [rust, python] +order: 55 +trace_note: "Recorded from another run: CMA-ES in 2 dimensions, so that the population can be drawn on the function's contour." +--- + +# Bent cigar + +## The problem + +The bent cigar squares the first gene, and the others a million times more: + +```text +f(x) = x₁² + 10⁶ Σᵢ₌₂ⁿ xᵢ², each xᵢ in [−100, 100] +``` + +Its minimum is 0, at the origin. Here n = 30. It's BBOB's f12 (Hansen et al. 2009), which bends it +with an asymmetric transformation and rotates it twice; this plain form and the bounds are the CEC +2014 (Liang, Qu and Suganthan 2013, function 2) and CEC 2017 (Awad et al. 2016, function 1) +reports' basic function, which those suites shift and rotate. + +## What makes it hard + +The function is a ridge: low only near the line along the first axis, a thousand times narrower +than long. A search has to find the ridge, then follow it to the minimum, with steps a thousand +times longer along it than across it, in a single direction. As it is, that direction is a gene's +axis. Shifted and rotated, it's a random one, and the search has to learn it. + +## Representation + +A `Real` genome of 30 genes: the point x itself. The fitness is f(x), to minimize. The function is +genoxide's `problems::BentCigar`, which brings its bounds and its minimum, and the shifted and rotated +instance `problems::Rotated::new(problems::Shifted::new(function, 1), 1)`, which keeps them. + +## Algorithm + +Five algorithms, each with a budget of 10,000 evaluations per dimension, 300,000 in all, and a +target of 1e-8, from seed 1: + +- CMA-ES (Hansen and Ostermeier, 2001, Evolutionary Computation 9(2): 159-195), which samples a + population of 14 from a normal distribution and adapts its mean, its step size and its covariance + matrix, from a step size of 0.3 of each gene's range and a random start; +- sep-CMA-ES (Ros and Hansen, 2008, PPSN X: 296-305), the same with a diagonal covariance matrix: a + scale per gene but no correlations; +- differential evolution with genoxide's defaults, SHADE (Tanabe and Fukunaga, CEC 2013), with a + population of 100; +- particle swarm optimization (Kennedy and Eberhart, 1995), 40 particles with Clerc and Kennedy's + constriction coefficients and a global topology; +- a real-coded genetic algorithm: a population of 100, tournaments of 3, simulated binary crossover + (Deb and Agrawal, 1995) with η = 15 and polynomial mutation with η = 20 at a rate of 1/30 per + gene. + +The second table runs the same algorithms on the function shifted and rotated, with genoxide's +`problems::Shifted` and `problems::Rotated` and seed 1: the minimum moves to a random point in the +middle 80% of the box, and an orthogonal matrix, drawn from normal numbers made orthonormal by +Gram-Schmidt as BBOB draws its rotations, turns the function about it. That's how the CEC and BBOB +suites use the function, with their own data; genoxide generates its instances instead. + +## Output + +The first line gives the dimension and the budget. Then two tables, the function as it is and shifted and rotated: a row per algorithm, the +evaluations it had used when its best error first reached each value of the heading, and the best +error it found, to two significant digits. A dash is an error not reached. The function is +evaluated with genoxide's portable math, so the runs are the same on every platform, and in Python, +`run` evaluates it in Rust, so both versions print the same. + +[The project page](https://tachsin.gr/projects/genoxide/examples/bent-cigar) plays back another +run: CMA-ES on the function in 2 dimensions, x₁² + 10⁶ x₂², not rotated (in 2 dimensions, it's the +high-conditioned elliptic function), so that the population can be drawn on its contour. It meets +the target after 756 evaluations. + +## Good results + +The minimum is 0. As it is, sep-CMA-ES reaches 1e-8 after 8,316 evaluations and CMA-ES after +13,482; SHADE takes 42,800 and PSO 47,600. The genetic algorithm ends at 210. + +Shifted and rotated, CMA-ES takes 13,902 evaluations, about as many: it learns the ridge's +direction. SHADE gets there after 171,700, four times as many as before, and the others fail: +sep-CMA-ES ends at 680, the genetic algorithm at 470 and PSO at 5,700. diff --git a/examples/bent_cigar/main.py b/examples/bent_cigar/main.py new file mode 100644 index 00000000..95d2f738 --- /dev/null +++ b/examples/bent_cigar/main.py @@ -0,0 +1,97 @@ +"""Bent cigar: minimize a narrow ridge, a thousand times longer than wide, in 30 dimensions, +as it is and shifted and rotated, as in the CEC 2014 and 2017 suites. + +Compares how fast CMA-ES, with a full and with a diagonal covariance matrix (sep-CMA-ES), +differential evolution, particle swarm optimization and a real-coded genetic algorithm close in on +the minimum, 0 at the origin: the evaluations each takes until its error is at most 1, 1e-2, 1e-4, 1e-6 and 1e-8. +The function is genoxide's `problems::BentCigar`. Then the same on the function shifted and rotated, with genoxide's `problems::Shifted` +and `problems::Rotated`, as the CEC and BBOB suites transform it. + +With ``GENOXIDE_TRACE=``, it also writes a trace of a run for the plot on the example's page, +with trace.py. + + python examples/bent_cigar/main.py +""" + +import genoxide as gx + +from trace import record_small + +DIMENSIONS = 30 +BUDGET = 10_000 * DIMENSIONS +# the errors at which the table gives each run's evaluations +ERRORS = [1e0, 1e-2, 1e-4, 1e-6, 1e-8] +COLUMNS = ["1", "1e-2", "1e-4", "1e-6", "1e-8"] + + +def error_text(error): + """An error to two significant digits, as Rust writes it: 9.9e-9.""" + mantissa, exponent = f"{error:.1e}".split("e") + return f"{mantissa}e{int(exponent)}" + + +class Reached: + """The evaluations after the first generation whose best error was at most each of ERRORS, + for a function whose minimum is ``minimum``.""" + + def __init__(self, minimum): + self.minimum = minimum + self.evaluations = [None] * len(ERRORS) + + def record(self, progress): + if progress.best_fitness is None: + return + error = progress.best_fitness - self.minimum + for i, bound in enumerate(ERRORS): + if self.evaluations[i] is None and error <= bound: + self.evaluations[i] = progress.evaluations + + def print(self, name, result): + """A row of the table: the evaluations, "-" for an error not reached, and the best + error.""" + cells = ["-" if reached is None else str(reached) for reached in self.evaluations] + # rounding can put a solution a few ulps below the minimum + cells.append(error_text(max(result.best_fitness - self.minimum, 0.0))) + print(f"{name:<10}" + "".join(f"{cell:>9}" for cell in cells)) + + +def compare(name, problem): + """The table of the five algorithms on ``problem``, after a line that names it.""" + minimum = problem.optimum.value + print(f"{name}: evaluations until the error is at most") + print(f"{'algorithm':<10}" + "".join(f"{column:>9}" for column in COLUMNS) + f"{'best':>9}") + genome = problem.genome + for label, algorithm in ( + ("CMA-ES", gx.Cmaes(genome, objective="minimize", seed=1)), + ("sep-CMA-ES", gx.Cmaes(genome, covariance="diagonal", objective="minimize", seed=1)), + ("DE", gx.De(genome, objective="minimize", seed=1)), + ("PSO", gx.Pso(genome, population_size=40, objective="minimize", seed=1)), + ( + "GA", + gx.Ga( + genome, + population_size=100, + select=gx.Tournament(3), + crossover=gx.SimulatedBinaryCrossover(15.0), + mutation=gx.PolynomialMutation(20.0, rate=1 / DIMENSIONS), + objective="minimize", + seed=1, + ), + ), + ): + reached = Reached(minimum) + result = algorithm.run( + problem, target=minimum + 1e-8, evaluations=BUDGET, on_generation=reached.record + ) + reached.print(label, result) + + +print(f"Bent cigar in {DIMENSIONS} dimensions, {BUDGET} evaluations at most") +compare("Bent cigar", gx.problems.BentCigar(DIMENSIONS)) +# the CEC 2014 and 2017 suites' form, with genoxide's own shift and rotation +rotated = gx.problems.Rotated(gx.problems.Shifted(gx.problems.BentCigar(DIMENSIONS), seed=1), seed=1) +compare("Shifted and rotated (seed 1)", rotated) + +# with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate run in +# 2 dimensions: the plot is the function's contour +record_small() diff --git a/examples/bent_cigar/main.rs b/examples/bent_cigar/main.rs new file mode 100644 index 00000000..4607de45 --- /dev/null +++ b/examples/bent_cigar/main.rs @@ -0,0 +1,151 @@ +//! Bent cigar: minimize a narrow ridge, a thousand times longer than wide, in 30 dimensions, +//! as it is and shifted and rotated, as in the CEC 2014 and 2017 suites. +//! +//! Compares how fast CMA-ES, with a full and with a diagonal covariance matrix (sep-CMA-ES), +//! differential evolution, particle swarm optimization and a real-coded genetic algorithm close in +//! on the minimum, 0 at the origin: the evaluations each takes until its error is at most 1, 1e-2, 1e-4, 1e-6 and 1e-8. +//! The function is genoxide's `problems::BentCigar`. Then the same on the function shifted and rotated, with genoxide's `problems::Shifted` +//! and `problems::Rotated`, as the CEC and BBOB suites transform it. +//! +//! With `GENOXIDE_TRACE=`, it also writes a trace of a run for the plot on the example's +//! page, with `trace.rs`. +//! +//! ```text +//! cargo run --release --example bent_cigar +//! ``` + +mod trace; + +use genoxide::observer::Snapshot; +use genoxide::prelude::*; +use genoxide::problems::{BentCigar, Problem, Rotated, Shifted}; + +const DIMENSIONS: usize = 30; +const BUDGET: u64 = 10_000 * DIMENSIONS as u64; +// the errors at which the table gives each run's evaluations +const ERRORS: [f64; 5] = [1e0, 1e-2, 1e-4, 1e-6, 1e-8]; +const COLUMNS: [&str; 5] = ["1", "1e-2", "1e-4", "1e-6", "1e-8"]; + +fn main() -> Result<()> { + println!("Bent cigar in {DIMENSIONS} dimensions, {BUDGET} evaluations at most"); + compare("Bent cigar", &BentCigar::new(DIMENSIONS))?; + // the CEC 2014 and 2017 suites' form, with genoxide's own shift and rotation + let rotated = Rotated::new(Shifted::new(BentCigar::new(DIMENSIONS), 1), 1); + compare("Shifted and rotated (seed 1)", &rotated)?; + // with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate + // run in 2 dimensions: the plot is the function's contour + trace::record_small()?; + Ok(()) +} + +// the table of the five algorithms on `problem`, after a line that names it +fn compare

(name: &str, problem: &P) -> Result<()> +where + P: Problem + FitnessFunction + Clone, +{ + let minimum = problem.optimum().expect("known").value(); + let stop = || Stop::target(minimum + 1e-8).or(Stop::evaluations(BUDGET)); + println!("{name}: evaluations until the error is at most"); + print!("{:<10}", "algorithm"); + COLUMNS.iter().for_each(|column| print!("{column:>9}")); + println!("{:>9}", "best"); + + for (name, covariance) in [ + ("CMA-ES", cmaes::Covariance::Full), + ("sep-CMA-ES", cmaes::Covariance::Diagonal), + ] { + let cmaes = Cmaes::builder(problem.representation()) + .covariance(covariance) + .minimize() + .seed(1) + .build()?; + let mut reached = Reached::new(minimum); + let outcome = Engine::new(cmaes, problem.clone()) + .stop_when(stop()) + .on_generation(|snapshot| reached.record(snapshot)) + .run()?; + reached.print(name, &outcome); + } + + let de = De::builder(problem.representation()) + .minimize() + .seed(1) + .build()?; + let mut reached = Reached::new(minimum); + let outcome = Engine::new(de, problem.clone()) + .stop_when(stop()) + .on_generation(|snapshot| reached.record(snapshot)) + .run()?; + reached.print("DE", &outcome); + + let pso = Pso::builder(problem.representation()) + .population_size(40) + .minimize() + .seed(1) + .build()?; + let mut reached = Reached::new(minimum); + let outcome = Engine::new(pso, problem.clone()) + .stop_when(stop()) + .on_generation(|snapshot| reached.record(snapshot)) + .run()?; + reached.print("PSO", &outcome); + + let ga = Ga::builder(problem.representation()) + .population_size(100) + .select(Tournament::new(3)?) + .crossover(SimulatedBinaryCrossover::new(15.0)?) + .mutate(PolynomialMutation::per_gene(1.0 / DIMENSIONS as f64, 20.0)?) + .minimize() + .seed(1) + .build()?; + let mut reached = Reached::new(minimum); + let outcome = Engine::new(ga, problem.clone()) + .stop_when(stop()) + .on_generation(|snapshot| reached.record(snapshot)) + .run()?; + reached.print("GA", &outcome); + Ok(()) +} + +// the evaluations after the first generation whose best error was at most each of ERRORS, for a +// function whose minimum is `minimum` +struct Reached { + minimum: f64, + evaluations: [Option; 5], +} + +impl Reached { + fn new(minimum: f64) -> Self { + let evaluations = [None; 5]; + Self { + minimum, + evaluations, + } + } + + fn record(&mut self, snapshot: &Snapshot<'_, Reals>) { + let progress = snapshot.progress(); + let Some(best) = progress.best().and_then(Fitness::score) else { + return; + }; + let error = best - self.minimum; + for (reached, bound) in self.evaluations.iter_mut().zip(ERRORS) { + if reached.is_none() && error <= bound { + *reached = Some(progress.evaluations()); + } + } + } + + // a row of the table: the evaluations, "-" for an error not reached, and the best error + fn print(&self, name: &str, outcome: &Outcome) { + print!("{name:<10}"); + for reached in self.evaluations { + let reached = reached.map_or("-".to_string(), |evaluations| evaluations.to_string()); + print!("{reached:>9}"); + } + // rounding can put a solution a few ulps below the minimum + let best = outcome.best_fitness().score().expect("valid"); + let error = (best - self.minimum).max(0.0); + println!("{:>9}", format!("{error:.1e}")); + } +} diff --git a/examples/bent_cigar/output.txt b/examples/bent_cigar/output.txt new file mode 100644 index 00000000..6d925f21 --- /dev/null +++ b/examples/bent_cigar/output.txt @@ -0,0 +1,15 @@ +Bent cigar in 30 dimensions, 300000 evaluations at most +Bent cigar: evaluations until the error is at most +algorithm 1 1e-2 1e-4 1e-6 1e-8 best +CMA-ES 10318 11144 11830 12600 13482 8.8e-9 +sep-CMA-ES 5460 6118 6804 7602 8316 9.5e-9 +DE 25200 29600 33900 38300 42800 9.0e-9 +PSO 22200 28080 35240 40720 47600 9.6e-9 +GA - - - - - 2.1e2 +Shifted and rotated (seed 1): evaluations until the error is at most +algorithm 1 1e-2 1e-4 1e-6 1e-8 best +CMA-ES 10570 11452 12292 13034 13902 5.6e-9 +sep-CMA-ES - - - - - 6.8e2 +DE 111700 124400 138800 154500 171700 9.9e-9 +PSO - - - - - 5.7e3 +GA - - - - - 4.7e2 diff --git a/examples/bent_cigar/trace.json b/examples/bent_cigar/trace.json new file mode 100644 index 00000000..bf72b373 --- /dev/null +++ b/examples/bent_cigar/trace.json @@ -0,0 +1,102 @@ +{"example":"bent_cigar","format":1,"log_y":true,"objective":"minimize","optimum":0.0,"plot":"contour","problem":{"bounds":[[-100.0,100.0],[-100.0,100.0]],"function":"bent_cigar","minima":[[0.0,0.0]]},"x_label":"evaluations","y_label":"error","frames":[ +{"best":598490000.0,"evaluations":6,"generation":0,"median":4501140000.0,"state":{"best":[-80.5712,-24.4639],"population":[[-80.5712,-24.4639],[21.9455,-61.072],[-54.0471,75.3763],[-21.4189,-92.999],[-75.1217,-72.6119],[42.8992,-28.5787]]}}, +{"best":62605700.0,"evaluations":12,"generation":1,"median":257744000.0,"state":{"best":[39.5285,-7.91228],"population":[[-90.9939,-9.39983],[39.5285,-7.91228],[10.1794,-42.8745],[-40.0234,19.3266],[-81.0734,-83.1636],[-30.7438,11.915]]}}, +{"best":117940.0,"evaluations":24,"generation":3,"median":1342320000.0,"state":{"best":[-79.216,-0.334163],"population":[[16.6112,43.691],[-33.555,-65.1745],[-79.1408,27.852],[-43.9972,-21.358],[-35.9944,77.9305],[-79.216,-0.334163]]}}, +{"best":117940.0,"evaluations":30,"generation":4,"median":1791070000.0,"state":{"best":[-79.216,-0.334163],"population":[[27.2708,-43.4438],[-17.2535,-55.453],[-39.6589,-53.5083],[-11.262,-41.1677],[-96.9282,17.1585],[-53.333,39.2585]]}}, +{"best":117940.0,"evaluations":36,"generation":5,"median":276958000.0,"state":{"best":[-79.216,-0.334163],"population":[[-82.6636,27.8157],[-88.6192,80.1011],[-69.7402,-15.295],[-37.3414,-17.8877],[-74.8589,10.0403],[-92.5493,-13.9]]}}, +{"best":117940.0,"evaluations":42,"generation":6,"median":785150000.0,"state":{"best":[-79.216,-0.334163],"population":[[-55.3845,-48.3014],[-79.2405,56.7922],[-70.7872,25.9192],[-77.3672,29.9747],[-59.9148,12.266],[-62.5027,10.3842]]}}, +{"best":117940.0,"evaluations":54,"generation":8,"median":269789000.0,"state":{"best":[-79.216,-0.334163],"population":[[-54.9771,-5.11078],[-49.4083,9.48323],[-84.3282,-22.8249],[-39.5748,-21.2048],[-65.4051,2.72164],[-97.9473,36.793]]}}, +{"best":117940.0,"evaluations":60,"generation":9,"median":228991000.0,"state":{"best":[-79.216,-0.334163],"population":[[-78.1548,32.7262],[-51.6814,20.4741],[-87.9702,2.60369],[-62.9029,18.9741],[-43.5277,9.89736],[-60.7882,2.26641]]}}, +{"best":117940.0,"evaluations":66,"generation":10,"median":56428900.0,"state":{"best":[-79.216,-0.334163],"population":[[-71.5746,5.4452],[-95.5985,18.9988],[-62.4581,-6.76008],[-74.7696,-4.34382],[-58.3109,18.7817],[-73.4016,-8.19451]]}}, +{"best":117940.0,"evaluations":72,"generation":11,"median":64784200.0,"state":{"best":[-79.216,-0.334163],"population":[[-83.7519,10.078],[-58.6726,0.492983],[-77.0586,-1.38854],[-73.5926,-13.8872],[-80.0694,19.7937],[-65.8544,-5.2906]]}}, +{"best":30702.8,"evaluations":84,"generation":13,"median":81251900.0,"state":{"best":[-58.543,0.165153],"population":[[-67.5477,-7.99864],[-65.6014,-10.4737],[-36.3194,9.9389],[-51.4489,7.32479],[-58.543,0.165153],[-38.8179,9.9257]]}}, +{"best":30702.8,"evaluations":90,"generation":14,"median":20583500.0,"state":{"best":[-58.543,0.165153],"population":[[-71.0281,8.76422],[-70.4627,2.80559],[-64.9934,-3.0185],[-77.8867,-5.49436],[-75.4281,3.31167],[-48.736,8.92136]]}}, +{"best":13841.5,"evaluations":96,"generation":15,"median":1775270.0,"state":{"best":[-85.2292,-0.0811019],"population":[[-73.7855,-1.63945],[-65.6907,11.1486],[-72.6103,0.833147],[-85.2292,-0.0811019],[-58.4899,0.924053],[-86.5516,-2.21045]]}}, +{"best":13841.5,"evaluations":102,"generation":16,"median":6150240.0,"state":{"best":[-85.2292,-0.0811019],"population":[[-93.7427,5.85934],[-77.9958,6.10815],[-60.0418,1.16776],[-56.0089,0.169726],[-63.8063,1.75366],[-74.7694,3.0357]]}}, +{"best":13841.5,"evaluations":114,"generation":18,"median":11964400.0,"state":{"best":[-85.2292,-0.0811019],"population":[[-82.8026,3.07682],[-56.3806,-0.783554],[-67.4083,4.77993],[-79.5176,3.80116],[-70.8431,0.237137],[-88.6394,-4.13644]]}}, +{"best":13841.5,"evaluations":120,"generation":19,"median":1642220.0,"state":{"best":[-85.2292,-0.0811019],"population":[[-57.2379,1.373],[-77.2274,-1.08771],[-64.8183,0.649109],[-70.3519,1.74131],[-70.6206,-1.17943],[-84.3494,-2.42461]]}}, +{"best":12812.6,"evaluations":126,"generation":20,"median":824169.0,"state":{"best":[-80.5629,0.0795125],"population":[[-67.555,-0.727298],[-69.3631,-0.416047],[-76.2488,2.25174],[-72.5789,-2.55798],[-53.6271,-1.05448],[-80.5629,0.0795125]]}}, +{"best":6955.79,"evaluations":132,"generation":21,"median":1118240.0,"state":{"best":[-77.9525,-0.0296514],"population":[[-77.9525,-0.0296514],[-83.5135,1.26637],[-73.6378,1.29255],[-73.0391,0.677271],[-67.2946,-2.15789],[-79.979,-0.78703]]}}, +{"best":6955.79,"evaluations":144,"generation":23,"median":191215.0,"state":{"best":[-77.9525,-0.0296514],"population":[[-80.9998,0.311532],[-84.9766,0.0165611],[-84.6106,0.0141314],[-91.0545,0.716281],[-93.4453,-0.519696],[-97.8871,1.07153]]}}, +{"best":6955.79,"evaluations":150,"generation":24,"median":1836350.0,"state":{"best":[-77.9525,-0.0296514],"population":[[-87.462,-0.106722],[-86.5301,-1.63611],[-85.9366,1.13874],[-84.2191,-0.642273],[-83.5195,1.53676],[-87.6136,-1.83805]]}}, +{"best":6955.79,"evaluations":156,"generation":25,"median":113056.0,"state":{"best":[-77.9525,-0.0296514],"population":[[-82.4792,0.341522],[-79.1901,-0.705707],[-81.3153,-0.131553],[-75.6812,0.311359],[-87.0434,-0.847828],[-73.0124,-0.112468]]}}, +{"best":6955.79,"evaluations":168,"generation":27,"median":367214.0,"state":{"best":[-77.9525,-0.0296514],"population":[[-92.9291,-0.608027],[-91.6892,-0.585953],[-83.5394,0.59086],[-89.5114,-0.725993],[-90.9665,0.625048],[-98.5924,-0.167298]]}}, +{"best":6955.79,"evaluations":174,"generation":28,"median":387580.0,"state":{"best":[-77.9525,-0.0296514],"population":[[-90.7734,0.958083],[-97.1325,0.248646],[-70.6514,0.0571216],[-88.5434,0.396194],[-87.6875,-0.776312],[-97.3754,-1.27204]]}}, +{"best":6955.79,"evaluations":180,"generation":29,"median":58851.0,"state":{"best":[-77.9525,-0.0296514],"population":[[-91.6878,-0.301488],[-72.4352,1.00736],[-77.1299,0.0404489],[-87.2386,0.0340333],[-83.6918,-0.106752],[-76.1438,0.949344]]}}, +{"best":6955.79,"evaluations":186,"generation":30,"median":49628.7,"state":{"best":[-77.9525,-0.0296514],"population":[[-89.2528,0.30741],[-82.2111,-0.0143444],[-82.4239,-0.483401],[-68.4301,-0.266465],[-67.5101,-0.13789],[-81.7651,0.0838274]]}}, +{"best":6951.41,"evaluations":198,"generation":32,"median":13752.0,"state":{"best":[-80.8007,-0.0205584],"population":[[-79.2312,0.209352],[-85.4996,0.0828077],[-80.8007,-0.0205584],[-81.9072,-0.0814125],[-85.3272,-0.0282378],[-81.0944,-0.288382]]}}, +{"best":6853.48,"evaluations":204,"generation":33,"median":13833.8,"state":{"best":[-82.7857,-9.2758e-05],"population":[[-85.0952,0.0752685],[-82.1116,0.114771],[-82.7857,-9.2758e-05],[-87.5713,-0.0842161],[-84.6924,0.217984],[-80.8618,-0.0192984]]}}, +{"best":6853.48,"evaluations":210,"generation":34,"median":8010.49,"state":{"best":[-82.7857,-9.2758e-05],"population":[[-81.978,0.131162],[-81.6713,-0.0451223],[-80.2245,-0.0730049],[-83.2617,-0.0195513],[-83.5255,0.0035412],[-82.2304,0.0213087]]}}, +{"best":6853.48,"evaluations":216,"generation":35,"median":9346.26,"state":{"best":[-82.7857,-9.2758e-05],"population":[[-82.9462,-0.0557162],[-82.6724,-0.0141608],[-83.5274,-0.059764],[-83.6024,-0.0414581],[-83.8225,-0.0655545],[-81.2676,0.0224677]]}}, +{"best":6802.63,"evaluations":228,"generation":37,"median":7300.18,"state":{"best":[-81.2687,-0.0140726],"population":[[-82.6652,-0.0218414],[-81.1276,0.0228137],[-83.2931,0.0662018],[-82.9059,-0.0204053],[-81.2687,-0.0140726],[-81.9207,0.0333884]]}}, +{"best":6258.7,"evaluations":234,"generation":38,"median":8291.59,"state":{"best":[-78.7908,0.00712106],"population":[[-81.1852,0.0433668],[-81.2317,-0.0461513],[-82.4623,-0.0878551],[-80.5029,0.0159033],[-78.7908,0.00712106],[-81.6575,-0.0379936]]}}, +{"best":6258.7,"evaluations":240,"generation":39,"median":8123.47,"state":{"best":[-78.7908,0.00712106],"population":[[-79.1508,0.0274898],[-80.8253,0.0481015],[-80.4438,0.0666599],[-79.9623,0.0535868],[-80.7514,0.0296593],[-80.2138,0.0304918]]}}, +{"best":6258.7,"evaluations":246,"generation":40,"median":9728.52,"state":{"best":[-78.7908,0.00712106],"population":[[-82.3655,-0.0201702],[-77.8413,0.101571],[-81.3077,-0.0242382],[-76.8764,0.0451559],[-78.5388,0.0831178],[-79.3207,0.0722235]]}}, +{"best":6258.7,"evaluations":258,"generation":42,"median":6809.2,"state":{"best":[-78.7908,0.00712106],"population":[[-81.0201,0.0025782],[-81.03,0.0108713],[-82.3551,0.00306043],[-81.0015,0.0172345],[-82.2163,-0.00819448],[-81.6744,-0.068131]]}}, +{"best":6258.7,"evaluations":264,"generation":43,"median":6637.76,"state":{"best":[-78.7908,0.00712106],"population":[[-81.0424,0.027233],[-81.211,-0.00491396],[-81.4435,0.00480571],[-80.4684,-0.00939139],[-81.4147,0.00596387],[-80.2317,0.002271]]}}, +{"best":6258.7,"evaluations":270,"generation":44,"median":6843.86,"state":{"best":[-78.7908,0.00712106],"population":[[-80.3555,0.0292011],[-82.48,-0.000356434],[-81.2987,-0.0125298],[-81.3518,-0.0274736],[-78.5601,-0.0175522],[-80.7999,-0.0188684]]}}, +{"best":6022.41,"evaluations":276,"generation":45,"median":7040.45,"state":{"best":[-77.3975,-0.00565985],"population":[[-80.343,-0.0226195],[-78.514,0.0422284],[-79.833,-0.0272203],[-80.424,-0.0552112],[-77.3975,-0.00565985],[-78.3121,0.0155434]]}}, +{"best":6022.41,"evaluations":288,"generation":47,"median":8880.0,"state":{"best":[-77.3975,-0.00565985],"population":[[-77.404,0.0251284],[-75.6561,0.0520055],[-78.5613,0.0869949],[-81.5968,0.0517064],[-80.3637,0.0697708],[-77.7393,-0.0271208]]}}, +{"best":5627.54,"evaluations":294,"generation":48,"median":6360.63,"state":{"best":[-74.5249,-0.00857821],"population":[[-74.5249,-0.00857821],[-76.6318,0.0670815],[-77.1706,0.0194435],[-77.865,-0.0180261],[-78.606,-0.0257417],[-76.6856,0.00517943]]}}, +{"best":5390.16,"evaluations":300,"generation":49,"median":6281.71,"state":{"best":[-73.3515,-0.00311572],"population":[[-73.0251,-0.0321512],[-77.2766,0.0494974],[-73.9342,-0.0229282],[-73.6585,-0.0277755],[-75.2977,0.0265813],[-73.3515,-0.00311572]]}}, +{"best":4697.91,"evaluations":312,"generation":51,"median":5990.08,"state":{"best":[-68.2949,0.00580685],"population":[[-62.2469,0.0496523],[-71.6394,0.0225376],[-75.0735,0.062451],[-75.9627,0.0822464],[-66.9132,-0.0289256],[-68.2949,0.00580685]]}}, +{"best":4697.91,"evaluations":318,"generation":52,"median":7400.13,"state":{"best":[-68.2949,0.00580685],"population":[[-69.7786,0.0785913],[-67.6353,-0.0655781],[-76.3333,-0.00992287],[-58.5667,0.0866709],[-76.3299,-0.00144907],[-75.6869,-0.00595487]]}}, +{"best":4697.91,"evaluations":324,"generation":53,"median":5967.71,"state":{"best":[-68.2949,0.00580685],"population":[[-70.6374,0.0560258],[-65.7887,-0.0411461],[-73.41,0.00245613],[-75.0236,0.0169033],[-64.7486,0.0304863],[-73.8221,-0.0924298]]}}, +{"best":4697.91,"evaluations":330,"generation":54,"median":6308.41,"state":{"best":[-68.2949,0.00580685],"population":[[-78.3769,0.033086],[-72.1196,-0.00310599],[-80.4808,0.0743373],[-61.4909,0.0617234],[-71.468,-0.0154816],[-55.3025,0.0481751]]}}, +{"best":3718.7,"evaluations":342,"generation":56,"median":4999.02,"state":{"best":[-60.3408,-0.00881464],"population":[[-65.515,-0.0326646],[-70.9882,0.00779266],[-77.4575,-0.0549969],[-61.1286,0.0174353],[-60.3408,-0.00881464],[-63.0306,-0.0304161]]}}, +{"best":2644.09,"evaluations":348,"generation":57,"median":3471.11,"state":{"best":[-49.9136,0.0123584],"population":[[-52.4791,-0.0068603],[-44.212,0.0435639],[-57.8674,0.036602],[-50.5962,0.023016],[-63.697,-0.0325449],[-49.9136,0.0123584]]}}, +{"best":2257.61,"evaluations":354,"generation":58,"median":4037.33,"state":{"best":[-45.7839,0.0127061],"population":[[-71.2625,-0.0181813],[-60.7124,-0.0232277],[-68.5927,0.0293665],[-54.7213,0.0292355],[-45.7839,0.0127061],[-38.433,-0.0309864]]}}, +{"best":2257.61,"evaluations":360,"generation":59,"median":5326.39,"state":{"best":[-45.7839,0.0127061],"population":[[-60.3729,0.0459275],[-34.9832,-0.0861524],[-45.3081,0.0533455],[-54.362,0.00195649],[-15.7798,0.0598592],[-76.362,-0.0346208]]}}, +{"best":683.729,"evaluations":372,"generation":61,"median":5607.75,"state":{"best":[-17.1265,-0.0197588],"population":[[-3.6939,-0.0689515],[-11.7821,-0.0788333],[-23.7681,-0.103133],[-68.0342,-0.0152757],[-41.5401,-0.0427242],[-31.3405,-0.17507]]}}, +{"best":683.729,"evaluations":378,"generation":62,"median":3029.63,"state":{"best":[-17.1265,-0.0197588],"population":[[-18.2688,-0.048919],[-31.4041,-0.0201566],[-9.18643,0.0380793],[-46.8469,-0.0337315],[-22.1694,-0.092056],[-48.3339,-0.138763]]}}, +{"best":503.125,"evaluations":384,"generation":63,"median":1811.64,"state":{"best":[-22.3994,-0.00118015],"population":[[-22.3994,-0.00118015],[-31.5691,-0.0224864],[-25.0518,-0.0631579],[-38.1276,-0.0277435],[-24.808,-0.0124063],[-7.90404,0.0453713]]}}, +{"best":55.5981,"evaluations":390,"generation":64,"median":1907.29,"state":{"best":[6.7512,-0.00316535],"population":[[-20.8008,0.04101],[-34.6077,-0.0309328],[-31.632,-0.0264483],[6.7512,-0.00316535],[-9.96754,-0.0501525],[-26.3374,0.000952545]]}}, +{"best":35.6172,"evaluations":402,"generation":66,"median":835.865,"state":{"best":[-0.606388,-0.00593712],"population":[[49.0809,0.102968],[13.0253,-0.0156312],[15.5932,-0.00138893],[44.3844,0.0537891],[3.29917,-0.0353108],[-0.606388,-0.00593712]]}}, +{"best":35.6172,"evaluations":408,"generation":67,"median":2411.28,"state":{"best":[-0.606388,-0.00593712],"population":[[-41.9819,-0.0731621],[-24.542,0.0213457],[26.6039,0.0561973],[21.0694,0.0288235],[16.2926,0.0266695],[-35.3853,0.0479138]]}}, +{"best":28.1761,"evaluations":414,"generation":68,"median":655.664,"state":{"best":[2.21416,-0.00482427],"population":[[-16.1316,-0.00102374],[23.841,-0.0326772],[14.1099,0.0135456],[31.3871,0.0193336],[-0.349551,-0.0304735],[2.21416,-0.00482427]]}}, +{"best":17.0853,"evaluations":420,"generation":69,"median":530.496,"state":{"best":[-4.09656,0.000550968],"population":[[-16.5315,-0.026366],[3.72732,-0.0236147],[-4.09656,0.000550968],[-8.5729,0.00374223],[-1.97556,0.022035],[19.8477,-0.0138676]]}}, +{"best":17.0853,"evaluations":432,"generation":71,"median":113.334,"state":{"best":[-4.09656,0.000550968],"population":[[13.9752,0.00421534],[4.91785,-0.00659914],[-7.32295,0.0142518],[-7.43597,0.00851852],[0.805822,-0.00692817],[-6.66991,0.00737034]]}}, +{"best":17.0853,"evaluations":438,"generation":72,"median":251.996,"state":{"best":[-4.09656,0.000550968],"population":[[-11.9214,-0.0152332],[-11.5744,-0.00925368],[-10.6924,-0.0125299],[0.968041,-0.0141649],[0.955548,0.0183607],[0.293206,0.0152506]]}}, +{"best":17.0853,"evaluations":444,"generation":73,"median":222.271,"state":{"best":[-4.09656,0.000550968],"population":[[-11.3537,-0.0099721],[6.27093,0.00415853],[-11.8018,-0.0398166],[4.40943,-0.0069336],[-7.65059,-0.0243761],[-10.3212,-0.0104721]]}}, +{"best":17.0853,"evaluations":450,"generation":74,"median":203.391,"state":{"best":[-4.09656,0.000550968],"population":[[3.83909,-0.0117652],[17.2074,-0.000188435],[10.2346,0.00717319],[9.65043,0.0125479],[-1.40607,0.00959129],[5.49459,0.0206019]]}}, +{"best":5.83158,"evaluations":462,"generation":76,"median":29.962,"state":{"best":[-1.84989,-0.00155226],"population":[[2.69734,-0.00852813],[4.00059,0.00432963],[-1.84989,-0.00155226],[2.88653,-0.00410386],[3.95369,0.00937259],[-4.23785,-0.000885367]]}}, +{"best":5.83158,"evaluations":468,"generation":77,"median":24.8684,"state":{"best":[-1.84989,-0.00155226],"population":[[-2.04944,0.00202036],[6.29089,-0.00324602],[0.715092,0.00547634],[-1.12331,0.00462022],[-3.09566,-0.0022674],[-4.02858,-0.00330138]]}}, +{"best":5.83158,"evaluations":474,"generation":78,"median":18.4084,"state":{"best":[-1.84989,-0.00155226],"population":[[-0.52115,0.00619783],[-3.22827,0.00557267],[-4.53556,0.000802571],[-3.84532,-0.000902754],[-0.91032,-0.00352503],[-1.55048,0.00243516]]}}, +{"best":0.51115,"evaluations":486,"generation":80,"median":13.5256,"state":{"best":[-0.502237,0.00050883],"population":[[-0.502237,0.00050883],[-1.70036,-0.000805872],[-0.764494,0.000708083],[-1.24405,-0.00550895],[-3.57639,-0.00560027],[-3.09192,-0.00373503]]}}, +{"best":0.277427,"evaluations":492,"generation":81,"median":6.86818,"state":{"best":[0.0807642,-0.000520485],"population":[[1.5324,0.00119959],[-3.81837,0.000588991],[-2.84102,0.00222158],[-2.71893,0.000487969],[0.0807642,-0.000520485],[-2.26267,0.00099298]]}}, +{"best":0.027156,"evaluations":498,"generation":82,"median":3.9389,"state":{"best":[0.0622262,-0.000152591],"population":[[1.62939,0.00130496],[0.752381,-0.00171868],[0.0622262,-0.000152591],[-0.500739,-0.00492343],[-0.796734,-0.000974134],[2.60329,-0.00151824]]}}, +{"best":0.027156,"evaluations":504,"generation":83,"median":1.89117,"state":{"best":[0.0622262,-0.000152591],"population":[[-0.132057,0.00135889],[-0.60525,-0.00124579],[0.0403893,-0.0024463],[1.13391,-0.00331998],[0.347852,0.000975297],[-0.904734,-0.000203203]]}}, +{"best":0.027156,"evaluations":516,"generation":85,"median":0.837855,"state":{"best":[0.0622262,-0.000152591],"population":[[0.514547,0.00040959],[0.833912,-0.000677018],[-0.953142,0.000159907],[0.269018,-0.000818102],[0.482084,0.00103294],[-0.536075,0.000212173]]}}, +{"best":0.00234034,"evaluations":522,"generation":86,"median":0.879619,"state":{"best":[0.0482039,-4.08943e-06],"population":[[-0.0722627,-0.00126285],[0.0482039,-4.08943e-06],[-0.661055,-0.000412138],[-0.259248,0.00108461],[-0.629723,0.000782441],[-0.521531,0.000691721]]}}, +{"best":0.00234034,"evaluations":528,"generation":87,"median":0.33621,"state":{"best":[0.0482039,-4.08943e-06],"population":[[0.139974,0.000287781],[-0.318819,-0.00042628],[-0.330556,-0.000865981],[-0.0769054,-0.000415488],[-0.539916,-0.000523531],[0.0859881,0.00061779]]}}, +{"best":0.00234034,"evaluations":534,"generation":88,"median":0.116093,"state":{"best":[0.0482039,-4.08943e-06],"population":[[0.234778,-0.000144508],[0.211679,0.000611622],[-0.059116,0.000439521],[0.197029,0.000120623],[-0.121178,0.000319301],[0.167707,0.000295674]]}}, +{"best":0.00234034,"evaluations":546,"generation":90,"median":0.0531208,"state":{"best":[0.0482039,-4.08943e-06],"population":[[-0.0803581,0.00013377],[0.126925,0.000356926],[-0.0887206,-0.000306407],[0.2805,-5.66554e-05],[-0.0357988,-0.00014327],[0.104704,0.000103802]]}}, +{"best":0.00234034,"evaluations":552,"generation":91,"median":0.0381444,"state":{"best":[0.0482039,-4.08943e-06],"population":[[-0.0169047,0.000206733],[-0.0974447,0.00020906],[0.172598,5.89436e-05],[0.36019,0.000240089],[0.0670052,0.000155184],[0.0209227,0.000124251]]}}, +{"best":0.00143569,"evaluations":558,"generation":92,"median":0.0290171,"state":{"best":[0.0175291,3.35919e-05],"population":[[0.0621337,0.000375629],[0.216314,2.02342e-05],[0.0175291,3.35919e-05],[0.0314738,6.86305e-05],[0.111476,0.000185992],[0.0773428,7.09399e-05]]}}, +{"best":0.00143569,"evaluations":564,"generation":93,"median":0.0216332,"state":{"best":[0.0175291,3.35919e-05],"population":[[0.0949453,7.94711e-05],[-0.0390098,-6.02165e-05],[0.0980942,0.000192903],[0.0962091,0.000126035],[-0.173024,1.76819e-05],[0.129087,3.82367e-05]]}}, +{"best":0.00117576,"evaluations":576,"generation":95,"median":0.00742448,"state":{"best":[-0.0318191,-1.27788e-05],"population":[[-0.0386573,-2.89062e-05],[0.202052,0.000133515],[-0.0615896,8.28076e-05],[0.12372,-9.08444e-05],[0.0277323,5.85619e-05],[-0.0318191,-1.27788e-05]]}}, +{"best":0.00117576,"evaluations":582,"generation":96,"median":0.00559203,"state":{"best":[-0.0318191,-1.27788e-05],"population":[[0.000195249,-7.2634e-05],[-0.0310432,7.03182e-05],[0.0622732,2.17419e-05],[0.0243575,-3.66443e-05],[0.0383824,7.50641e-05],[0.0963481,2.28277e-06]]}}, +{"best":0.000363295,"evaluations":588,"generation":97,"median":0.00520915,"state":{"best":[0.0155873,-1.09695e-05],"population":[[-0.00666766,0.00012651],[0.101675,0.00017142],[-0.0371046,-4.01393e-05],[0.0607415,-5.42725e-05],[0.0155873,-1.09695e-05],[0.00216305,-6.14702e-05]]}}, +{"best":0.000363295,"evaluations":594,"generation":98,"median":0.00223086,"state":{"best":[0.0155873,-1.09695e-05],"population":[[0.0100895,-3.87039e-05],[-0.0833474,-2.06038e-06],[0.00683695,-2.00349e-05],[-0.00979742,-5.04596e-05],[0.0160473,-6.57847e-05],[-0.0364885,-2.20942e-05]]}}, +{"best":1.63123e-05,"evaluations":606,"generation":100,"median":0.000336789,"state":{"best":[0.00154724,3.73073e-06],"population":[[0.014739,6.72333e-06],[-0.00963054,-7.77498e-06],[-0.00829912,-1.10951e-05],[0.023475,5.15435e-07],[-0.0199395,-3.68123e-06],[0.0337073,-2.8214e-05]]}}, +{"best":1.63123e-05,"evaluations":612,"generation":101,"median":0.000460045,"state":{"best":[0.00154724,3.73073e-06],"population":[[0.021501,-2.29709e-06],[0.00805036,-1.96904e-05],[-0.0167208,-1.17279e-05],[0.011845,-1.90976e-05],[-0.0122665,-1.66622e-05],[0.0330976,-9.34992e-06]]}}, +{"best":1.63123e-05,"evaluations":618,"generation":102,"median":0.00118137,"state":{"best":[0.00154724,3.73073e-06],"population":[[-0.036299,-1.27656e-06],[-0.0187296,-2.6319e-05],[-0.0176058,5.01678e-06],[-0.0409426,-1.41782e-06],[-0.037551,-2.28562e-05],[-0.000658326,-3.14341e-05]]}}, +{"best":1.63123e-05,"evaluations":630,"generation":104,"median":0.000137701,"state":{"best":[0.00154724,3.73073e-06],"population":[[0.0110143,-1.64975e-07],[-0.00195553,-1.9939e-05],[-0.0031198,-3.11664e-06],[-0.00765044,-5.43696e-06],[0.00973881,-1.58902e-05],[-0.00208742,-1.22353e-05]]}}, +{"best":2.91366e-06,"evaluations":636,"generation":105,"median":0.000116204,"state":{"best":[-0.00169955,-1.58764e-07],"population":[[-0.00169955,-1.58764e-07],[-0.00460944,-8.69186e-06],[-0.0205329,-9.94477e-06],[-0.0103063,-4.29273e-06],[0.0029823,-1.81522e-05],[0.00319645,-9.87637e-06]]}}, +{"best":1.02319e-06,"evaluations":642,"generation":106,"median":4.68401e-05,"state":{"best":[-0.00101113,-2.8424e-08],"population":[[0.00831728,-6.75761e-07],[-0.010228,-1.0218e-05],[0.00190444,2.38802e-06],[0.00280659,4.02111e-06],[0.00201168,-1.06909e-05],[-0.00101113,-2.8424e-08]]}}, +{"best":1.02319e-06,"evaluations":648,"generation":107,"median":1.61155e-05,"state":{"best":[-0.00101113,-2.8424e-08],"population":[[0.000164527,2.11687e-06],[-0.00333905,-2.84234e-06],[-0.000351901,1.19405e-06],[-0.000368004,3.58712e-06],[-0.00101029,6.2365e-06],[0.000107034,-6.89033e-06]]}}, +{"best":1.02319e-06,"evaluations":660,"generation":109,"median":2.31399e-05,"state":{"best":[-0.00101113,-2.8424e-08],"population":[[0.000847018,-2.51709e-06],[0.00273853,2.15137e-06],[0.00596869,-4.96643e-07],[0.000431932,4.71062e-06],[-0.00144833,-4.66966e-06],[0.00500821,9.23907e-06]]}}, +{"best":4.1445e-07,"evaluations":666,"generation":110,"median":1.30591e-05,"state":{"best":[0.000565485,-3.07695e-07],"population":[[-0.000904501,3.23559e-06],[0.00121613,-4.34084e-06],[0.00152566,3.53602e-06],[-0.00117258,5.87134e-07],[0.000565485,-3.07695e-07],[0.00314443,-3.79683e-06]]}}, +{"best":4.1445e-07,"evaluations":672,"generation":111,"median":1.47259e-05,"state":{"best":[0.000565485,-3.07695e-07],"population":[[-0.000318864,5.68905e-06],[0.00368524,2.83199e-06],[-0.00274249,-3.08319e-06],[0.00276886,-2.18124e-06],[-0.00196901,-2.91761e-06],[0.00080921,-1.56582e-06]]}}, +{"best":4.1445e-07,"evaluations":678,"generation":112,"median":1.49671e-05,"state":{"best":[0.000565485,-3.07695e-07],"population":[[0.00174477,-5.50812e-06],[-0.000795438,-2.8106e-06],[-0.00156572,-4.53275e-06],[-0.00145722,-4.11677e-06],[0.000910413,-2.11765e-06],[-0.00177911,-2.77447e-06]]}}, +{"best":2.32147e-08,"evaluations":690,"generation":114,"median":3.77159e-06,"state":{"best":[3.40538e-05,-1.4851e-07],"population":[[-0.000718497,3.24822e-07],[0.00361255,-3.93079e-06],[0.000412942,1.471e-06],[-0.000914404,2.57694e-06],[3.40538e-05,-1.4851e-07],[-0.00227717,1.52662e-07]]}}, +{"best":2.32147e-08,"evaluations":696,"generation":115,"median":2.24336e-06,"state":{"best":[3.40538e-05,-1.4851e-07],"population":[[-0.00132642,1.35248e-08],[0.000867408,2.72311e-06],[0.000360279,3.53865e-06],[-0.000981819,6.42385e-07],[0.000393512,1.84707e-07],[0.00120054,-1.13396e-06]]}}, +{"best":2.32147e-08,"evaluations":702,"generation":116,"median":7.49187e-07,"state":{"best":[3.40538e-05,-1.4851e-07],"population":[[8.47048e-05,1.49104e-06],[0.00019025,-4.15232e-07],[-0.000178214,-4.41218e-07],[0.000300831,1.77479e-06],[0.000383038,3.39566e-07],[-0.00107565,2.81656e-07]]}}, +{"best":2.32147e-08,"evaluations":708,"generation":117,"median":1.45318e-06,"state":{"best":[3.40538e-05,-1.4851e-07],"population":[[2.39112e-05,-1.66426e-06],[-0.000566275,-3.93122e-07],[-0.000973194,-4.34476e-07],[0.000296075,-6.35877e-07],[0.000537912,1.21702e-06],[3.36458e-05,-1.76234e-06]]}}, +{"best":2.32147e-08,"evaluations":720,"generation":119,"median":9.70918e-07,"state":{"best":[3.40538e-05,-1.4851e-07],"population":[[-0.000509604,-3.15078e-08],[-0.00129162,8.61418e-07],[-0.000938669,-3.81255e-07],[-0.000955641,-4.61676e-08],[-0.000867595,-7.01959e-07],[-0.000583019,-1.98061e-07]]}}, +{"best":2.32147e-08,"evaluations":726,"generation":120,"median":8.71044e-07,"state":{"best":[3.40538e-05,-1.4851e-07],"population":[[-0.000916304,5.11482e-07],[-0.000109926,1.36936e-07],[-0.00109254,-1.97177e-08],[-0.000800533,2.61464e-09],[-0.000317968,1.92103e-07],[-0.000512592,-1.29052e-06]]}}, +{"best":1.22058e-08,"evaluations":732,"generation":121,"median":3.20013e-07,"state":{"best":[-9.53281e-05,-5.58424e-08],"population":[[-0.000132131,-6.90341e-07],[-0.000513202,-3.64728e-07],[-9.53281e-05,-5.58424e-08],[-0.000244283,3.29517e-09],[-8.10453e-05,1.13099e-06],[-0.000192269,4.54595e-07]]}}, +{"best":1.22058e-08,"evaluations":738,"generation":122,"median":2.1241e-07,"state":{"best":[-9.53281e-05,-5.58424e-08],"population":[[-0.000112911,-1.10641e-06],[-0.000414624,-3.33497e-07],[1.14154e-05,-2.33081e-07],[0.000158273,-3.21917e-08],[-0.000345906,1.48442e-07],[-0.000333193,-5.46245e-07]]}}, +{"best":1.22058e-08,"evaluations":750,"generation":124,"median":7.67537e-08,"state":{"best":[-9.53281e-05,-5.58424e-08],"population":[[-7.47094e-05,-8.98717e-08],[0.000158404,3.21239e-07],[-0.000164503,-3.64562e-08],[0.000326758,-4.30297e-08],[-0.000384194,-3.11489e-07],[-0.000189868,-9.39963e-08]]}}, +{"best":4.31002e-09,"evaluations":756,"generation":125,"median":1.68029e-07,"state":{"best":[-2.111e-05,6.21642e-08],"population":[[-0.000697891,1.5802e-07],[-2.111e-05,6.21642e-08],[-0.000236991,-2.58434e-07],[0.000234481,-3.97649e-07],[-0.000609517,-1.87998e-07],[0.000149676,-1.02056e-07]]}} +]} diff --git a/examples/bent_cigar/trace.py b/examples/bent_cigar/trace.py new file mode 100644 index 00000000..7e11aaa8 --- /dev/null +++ b/examples/bent_cigar/trace.py @@ -0,0 +1,189 @@ +"""The trace for the plot on the example's page, written to the file that ``GENOXIDE_TRACE`` +names. The plot draws the population on the function's contour, which needs two dimensions: the +trace is of a separate run of CMA-ES in 2 dimensions, with a budget of +20,000 evaluations, in at most 100 frames. The Rust example writes the same file.""" + +import json +import math +import os + +import genoxide as gx + + +def record_small(): + """Runs CMA-ES in 2 dimensions and writes its trace, if ``GENOXIDE_TRACE`` is set.""" + path = os.environ.get("GENOXIDE_TRACE") + if not path: + return + problem = gx.problems.BentCigar(2) + minimum = problem.optimum.value + budget = 20_000 + cmaes = gx.Cmaes(problem.genome, objective="minimize", seed=1) + frames = Frames(100) + + def record(progress): + state = {"population": progress.population.tolist(), "best": progress.best_genome.tolist()} + frames.push(frame(progress, state, minimum)) + + cmaes.run(problem, target=minimum + 1e-8, evaluations=budget, on_generation=record) + low, high = problem.genome.bounds + settings = { + "format": 1, + "example": "bent_cigar", + "objective": "minimize", + "x_label": "evaluations", + "y_label": "error", + "log_y": True, + "optimum": 0.0, + "plot": "contour", + "problem": { + "function": "bent_cigar", + "bounds": [[float(low), float(high)]] * 2, + "minima": problem.optimum.solutions.tolist(), + }, + } + write(path, settings, frames.to_list()) + + +def frame(progress, state, minimum): + """The frame of a generation: its progress, the errors of its best and of its population's + median to ``minimum`` (rounding can put a solution a few ulps below it), and ``state``.""" + + def error(value): + return None if value is None else max(value - minimum, 0.0) + + return { + "generation": progress.generation, + "evaluations": progress.evaluations, + "best": error(progress.best_fitness), + "median": error(median(progress.scores)), + "state": state, + } + + +def median(scores): + """The median of the valid scores, None without any.""" + scores = sorted(float(score) for score in scores if not math.isnan(score)) + middle = len(scores) // 2 + if not scores: + return None + return scores[middle] if len(scores) % 2 else (scores[middle - 1] + scores[middle]) / 2 + + +# ---- the same in every example's trace ---------------------------------------------------------- + + +class Frames: + """The frames of at most ``most`` generations, from the part of the run where what the page + plots changes: the frames after the last change are left out (a run that reached its target, + or a front that no longer moves), and the rest are spread evenly over the generations up to + it. While the run goes, up to 8 × ``most`` frames are kept: every ``every``-th generation, + with ``every`` doubling whenever there are that many, and the last one.""" + + def __init__(self, most): + self.most, self.every, self.kept, self.last = most, 1, [], None + + def push(self, frame): + if frame["generation"] % self.every: + self.last = frame + return + self.kept.append(frame) + self.last = None + if len(self.kept) == 8 * self.most: + self.every *= 2 + self.kept = [kept for kept in self.kept if kept["generation"] % self.every == 0] + + def to_list(self): + frames = self.kept + ([self.last] if self.last else []) + active = frames[: last_change(frames) + 1] + count, most = len(active), max(self.most, 2) + if count <= most: + return active + return [active[(i * (count - 1) + (most - 1) // 2) // (most - 1)] for i in range(most)] + + +def last_change(frames): + """The index of the frame after which nothing the page plots changes. To 3 significant + digits, as a plot shows them: the best, the median and, for a single objective (a numeric + best), the state; to within a hundredth of their range over the run: a front's + hypervolumes, in the state or in a grid's series.""" + if not frames: + return 0 + last = len(frames) - 1 + number = lambda value: isinstance(value, (int, float)) and not isinstance(value, bool) + single = any(number(frame.get("best")) for frame in frames) + + def measures(frame): + values = [] + state = frame.get("state") + hypervolume = state.get("hypervolume") if isinstance(state, dict) else None + for value in (hypervolume, frame.get("series")): + if number(value): + values.append(float(value)) + elif isinstance(value, dict): + values.extend(float(v) for _, v in sorted(value.items()) if number(v)) + return values + + measured = [measures(frame) for frame in frames] + end = measured[last] + tolerance = [] + for k in range(len(end)): + values = [values[k] for values in measured if k < len(values)] + tolerance.append((max(values) - min(values)) / 100.0) + + def same(frame, final, key, flush=False): + return coarse(frame.get(key), flush) == coarse(final.get(key), flush) + + def settled(i): + frame, final = frames[i], frames[last] + return ( + same(frame, final, "best") + and same(frame, final, "median") + and (not single or same(frame, final, "state", flush=True)) + and len(measured[i]) == len(end) + and all(abs(v - e) <= t for v, e, t in zip(measured[i], end, tolerance)) + ) + + first = last + while first > 0 and settled(first - 1): + first -= 1 + return first + + +def coarse(value, flush=False): + """``value`` with its numbers to 3 significant digits, as precisely as a plot shows them: two + frames whose plotted values agree to that precision look the same. With ``flush``, for the + solutions a plot draws on their ranges, numbers below 1e-6 in size count as 0.""" + if isinstance(value, float): + if flush and abs(value) < 1e-6: + value = 0.0 + return f"{value:.2e}" + if isinstance(value, (list, tuple)): + return "[" + ",".join(coarse(item, flush) for item in value) + "]" + if isinstance(value, dict): + items = sorted(value.items()) + return "{" + ",".join(f"{key}:{coarse(item, flush)}" for key, item in items) + "}" + return json.dumps(value) + + +def write(path, settings, frames): + """Writes the settings and the frames to ``path``, a frame per line.""" + lines = ",\n".join(map(to_json, frames)) + with open(path, "w", encoding="utf-8", newline="\n") as file: + file.write(f'{to_json(settings)[:-1]},"frames":[\n{lines}\n]}}\n') + + +def to_json(value): + """Compact JSON with sorted keys, and numbers rounded to 6 significant digits, as the Rust + example writes it.""" + return json.dumps(rounded(value), sort_keys=True, separators=(",", ":"), ensure_ascii=False) + + +def rounded(value): + if isinstance(value, dict): + return {key: rounded(item) for key, item in value.items()} + if isinstance(value, (list, tuple)): + return [rounded(item) for item in value] + if isinstance(value, float): + return float(f"{value:.5e}") if math.isfinite(value) else None + return value diff --git a/examples/bent_cigar/trace.rs b/examples/bent_cigar/trace.rs new file mode 100644 index 00000000..398eb590 --- /dev/null +++ b/examples/bent_cigar/trace.rs @@ -0,0 +1,260 @@ +//! The trace for the plot on the example's page, written to the file that `GENOXIDE_TRACE` names. +//! The plot draws the population on the function's contour, which needs two dimensions: the trace +//! is of a separate run of CMA-ES in 2 dimensions, with a budget of +//! 20,000 evaluations, in at most 100 frames. The Python example writes the same +//! file. + +use genoxide::observer::Snapshot; +use genoxide::prelude::*; +use genoxide::problems::{BentCigar, Problem}; +use serde_json::{Value, json}; + +// runs CMA-ES in 2 dimensions and writes its trace, if GENOXIDE_TRACE is set +pub fn record_small() -> Result<()> { + let Ok(path) = std::env::var("GENOXIDE_TRACE") else { + return Ok(()); + }; + let problem = BentCigar::new(2); + let optimum = problem.optimum().expect("known"); + let minimum = optimum.value(); + let budget = 20_000; + let cmaes = Cmaes::builder(problem.representation()) + .minimize() + .seed(1) + .build()?; + let mut frames = Frames::new(100); + Engine::new(cmaes, problem.clone()) + .stop_when(Stop::target(minimum + 1e-8).or(Stop::evaluations(budget))) + .on_generation(|snapshot| { + let population = snapshot.population().iter().map(|x| &x.genome()[..]); + let population: Vec<&[f64]> = population.collect(); + let best = &snapshot.best().genome()[..]; + let state = json!({ "population": population, "best": best }); + frames.push(frame(snapshot, state, minimum)); + }) + .run()?; + let bounds = problem.representation().bounds().to_vec(); + let bounds: Vec<[f64; 2]> = bounds.iter().map(|b| [*b.start(), *b.end()]).collect(); + let minima: Vec<&[f64]> = optimum.solutions().iter().map(|x| &x[..]).collect(); + let settings = json!({ + "format": 1, + "example": "bent_cigar", + "objective": "minimize", + "x_label": "evaluations", + "y_label": "error", + "log_y": true, + "optimum": 0.0, + "plot": "contour", + "problem": { + "function": "bent_cigar", + "bounds": bounds, + "minima": minima, + }, + }); + write(&path, settings, frames.into_vec()); + Ok(()) +} + +// the frame of a generation: its progress, the errors of its best and of its population's median +// to `minimum` (rounding can put a solution a few ulps below it), and `state` +fn frame(snapshot: &Snapshot<'_, Reals>, state: Value, minimum: f64) -> Value { + let progress = snapshot.progress(); + let error = |value: f64| (value - minimum).max(0.0); + let population = snapshot.population().iter(); + let scores = population.filter_map(|individual| individual.fitness()?.score()); + json!({ + "generation": progress.generation(), + "evaluations": progress.evaluations(), + "best": progress.best().and_then(Fitness::score).map(error), + "median": median(scores.collect()).map(error), + "state": state, + }) +} + +// the median of the scores, None without any +fn median(mut scores: Vec) -> Option { + scores.sort_by(f64::total_cmp); + let middle = scores.len() / 2; + match scores.len() { + 0 => None, + n if n % 2 == 1 => Some(scores[middle]), + _ => Some((scores[middle - 1] + scores[middle]) / 2.0), + } +} + +// ---- the same in every example's trace --------------------------------------------------------- + +// the frames of at most `most` generations, from the part of the run where what the page plots +// changes: the frames after the last change are left out (a run that reached its target, or a +// front that no longer moves), and the rest are spread evenly over the generations up to it. While +// the run goes, up to 8 × `most` frames are kept: every `every`-th generation, with `every` +// doubling whenever there are that many, and the last one. +struct Frames { + most: usize, + every: u64, + kept: Vec<(u64, Value)>, + last: Option<(u64, Value)>, +} + +impl Frames { + fn new(most: usize) -> Self { + let (every, kept, last) = (1, Vec::new(), None); + Self { + most, + every, + kept, + last, + } + } + + fn push(&mut self, frame: Value) { + let generation = frame["generation"].as_u64().expect("a generation"); + if !generation.is_multiple_of(self.every) { + self.last = Some((generation, frame)); + return; + } + self.kept.push((generation, frame)); + self.last = None; + if self.kept.len() == 8 * self.most { + self.every *= 2; + let every = self.every; + self.kept.retain(|(generation, _)| generation % every == 0); + } + } + + fn into_vec(self) -> Vec { + let frames = self.kept.into_iter().chain(self.last); + let frames: Vec = frames.map(|(_, frame)| frame).collect(); + let active = &frames[..=last_change(&frames)]; + let (count, most) = (active.len(), self.most.max(2)); + if count <= most { + return active.to_vec(); + } + let at = |i: usize| active[(i * (count - 1) + (most - 1) / 2) / (most - 1)].clone(); + (0..most).map(at).collect() + } +} + +// the index of the frame after which nothing the page plots changes. To 3 significant digits, as +// a plot shows them: the best, the median and, for a single objective (a numeric best), the state; +// to within a hundredth of their range over the run: a front's hypervolumes, in the state or in a +// grid's series +fn last_change(frames: &[Value]) -> usize { + let Some(last) = frames.len().checked_sub(1) else { + return 0; + }; + let single = frames.iter().any(|frame| frame["best"].is_number()); + let measures = |frame: &Value| -> Vec { + let mut values = Vec::new(); + for value in [&frame["state"]["hypervolume"], &frame["series"]] { + match value { + Value::Number(number) => values.extend(number.as_f64()), + Value::Object(map) => values.extend(map.values().filter_map(Value::as_f64)), + _ => {} + } + } + values + }; + let measured: Vec> = frames.iter().map(measures).collect(); + let end = &measured[last]; + let tolerance: Vec = (0..end.len()) + .map(|k| { + let values = measured.iter().filter_map(|values| values.get(k).copied()); + let (low, high) = values.fold((f64::INFINITY, f64::NEG_INFINITY), |(low, high), v| { + (low.min(v), high.max(v)) + }); + (high - low) / 100.0 + }) + .collect(); + let settled = |i: usize| { + let (frame, final_frame) = (&frames[i], &frames[last]); + let same = + |key: &str, flush: bool| coarse(&frame[key], flush) == coarse(&final_frame[key], flush); + same("best", false) + && same("median", false) + && (!single || same("state", true)) + && measured[i].len() == end.len() + && measured[i] + .iter() + .zip(end) + .zip(&tolerance) + .all(|((value, end), tolerance)| (value - end).abs() <= *tolerance) + }; + let mut first = last; + while first > 0 && settled(first - 1) { + first -= 1; + } + first +} + +// `value` with its numbers to 3 significant digits, as precisely as a plot shows them: two frames +// whose plotted values agree to that precision look the same. With `flush`, for the solutions a +// plot draws on their ranges, numbers below 1e-6 in size count as 0 +fn coarse(value: &Value, flush: bool) -> String { + let join = |items: Vec| items.join(","); + match value { + Value::Number(number) if number.is_f64() => { + let number = number.as_f64().expect("f64"); + let number = if flush && number.abs() < 1e-6 { + 0.0 + } else { + number + }; + format!("{number:.2e}") + } + Value::Array(items) => { + format!( + "[{}]", + join(items.iter().map(|item| coarse(item, flush)).collect()) + ) + } + Value::Object(map) => { + let entry = |(key, item): (&String, &Value)| format!("{key}:{}", coarse(item, flush)); + format!("{{{}}}", join(map.iter().map(entry).collect())) + } + other => other.to_string(), + } +} + +// writes the settings and the frames to `path`, a frame per line +fn write(path: &str, settings: Value, frames: Vec) { + let frames: Vec = frames.iter().map(to_json).collect(); + let settings = to_json(&settings); + let head = &settings[..settings.len() - 1]; + let text = format!("{head},\"frames\":[\n{}\n]}}\n", frames.join(",\n")); + std::fs::write(path, text).expect("the trace is written"); +} + +// compact JSON with sorted keys, and numbers rounded to 6 significant digits and written as +// Python writes them (7542.0, 1e-08): the Python example writes the same file +fn to_json(value: &Value) -> String { + let join = |items: Vec| items.join(","); + match value { + Value::Number(number) if number.is_f64() => python_float(number.as_f64().expect("f64")), + Value::Array(items) => format!("[{}]", join(items.iter().map(to_json).collect())), + Value::Object(map) => { + let entry = + |(key, item): (&String, &Value)| format!("{}:{}", json!(key), to_json(item)); + format!("{{{}}}", join(map.iter().map(entry).collect())) + } + other => other.to_string(), + } +} + +fn python_float(value: f64) -> String { + let rounded: f64 = format!("{value:.5e}").parse().expect("a number"); + let shortest = format!("{rounded:e}"); + let (mantissa, exponent) = shortest.split_once('e').expect("an exponent"); + let exponent: i32 = exponent.parse().expect("an exponent"); + if (-4..16).contains(&exponent) { + let text = rounded.to_string(); + if text.contains('.') { + text + } else { + text + ".0" + } + } else { + let sign = if exponent < 0 { '-' } else { '+' }; + format!("{mantissa}e{sign}{:02}", exponent.abs()) + } +} diff --git a/examples/buche_rastrigin/README.md b/examples/buche_rastrigin/README.md new file mode 100644 index 00000000..f4452c46 --- /dev/null +++ b/examples/buche_rastrigin/README.md @@ -0,0 +1,83 @@ +--- +title: Büche-Rastrigin +category: continuous +summary: Minimize BBOB's Büche-Rastrigin function, an asymmetric Rastrigin, in 10 dimensions, with CMA-ES without and with restarts, DE, PSO and a GA from 10 seeds each. +reference: "Hansen, N., Finck, S., Ros, R. and Auger, A. (2009). Real-Parameter Black-Box Optimization Benchmarking 2009: Noiseless Functions Definitions. INRIA research report RR-6829." +reference_url: "https://hal.inria.fr/inria-00362633" +optimum: "0 (at the origin)" +languages: [rust, python] +order: 93 +trace_note: "Recorded from another run: CMA-ES with IPOP restarts in 2 dimensions, so that the population can be drawn on the function's contour." +--- + +# Büche-Rastrigin + +## The problem + +The Büche-Rastrigin function is Rastrigin's function of scaled and slightly bent genes, with a +penalty outside the box: + +```text +f(x) = 10 (n − Σ cos 2πzᵢ) + Σ zᵢ² + 100 Σ max(0, |xᵢ| − 5)², zᵢ = sᵢ T_osz(xᵢ) +each xᵢ in [−5, 5] +``` + +T_osz is BBOB's oscillation, `sign(x) exp(x̂ + 0.049 (sin c₁x̂ + sin c₂x̂))` with x̂ = ln |x|, +c₁ = 10 and c₂ = 7.9 for positive x, 5.5 and 3.1 otherwise: the identity, with small smooth +wiggles. The scale sᵢ grows from 1 to √10 along the genes, and is ten times larger where xᵢ > 0 +and i is odd. Its minimum is 0, at the origin. Here n = 10. It's BBOB's f4 (Hansen et al. 2009), +with its optimum at the origin and no offset, and BBOB's search domain. + +## What makes it hard + +Rastrigin's function has a local minimum near every integer point, roughly 10ⁿ of them in the box. +Here, on the positive side of the odd genes, the scale is ten times larger: the wells are ten times +narrower and the slope ten times steeper, so the landscape is lopsided. BBOB built it to deceive +search operators that are symmetric about the current point, which expect the minimum's basin to +look the same on both sides. + +## Representation + +A `Real` genome of 10 genes, each in [−5, 5]: the point x itself. The fitness is f(x), to +minimize. The function is genoxide's `problems::BucheRastrigin`, which brings its bounds and its +minimum. + +## Algorithm + +Five algorithms, each from seeds 1 to 10, with a budget of 10,000 evaluations per dimension, +100,000 per run, and a target of 1e-8: + +- CMA-ES (Hansen and Ostermeier, 2001, Evolutionary Computation 9(2): 159-195), which samples a + population of 10 from a normal distribution and adapts its mean, its step size and its covariance + matrix, from a step size of 0.3 of each gene's range and a random start; +- the same with IPOP restarts (Auger and Hansen, 2005, IEEE CEC 2005: 1769-1776): a run that has + converged starts again from a random point with twice the population; +- differential evolution with genoxide's defaults, SHADE (Tanabe and Fukunaga, CEC 2013), with a + population of 100 and its restarts on stagnation; +- particle swarm optimization (Kennedy and Eberhart, 1995), 40 particles with Clerc and Kennedy's + constriction coefficients and a global topology; +- a real-coded genetic algorithm: a population of 100, tournaments of 3, simulated binary crossover + (Deb and Agrawal, 1995) with η = 15 and polynomial mutation with η = 20 at a rate of 1/10 per + gene. + +## Output + +The first line gives the dimension, the seeds and the budget. Then a row per algorithm: how many +of its 10 runs reached the minimum, to within 1e-8, the median of their evaluations (a dash if none +did), and the median of every run's best error, to two significant digits. The function is +evaluated with genoxide's portable math, so the runs are the same on every platform, and in Python, +`run` evaluates it in Rust, so both versions print the same. + +[The project page](https://tachsin.gr/projects/genoxide/examples/buche-rastrigin) plays back another run: +CMA-ES with IPOP restarts on the function in 2 dimensions, so that the population +can be drawn on its contour. Within 20,000 evaluations it restarts 6 times, up to a population of +384, and ends at an error of 0.36: it doesn't reach the minimum in 2 dimensions either. + +## Good results + +The minimum is 0. SHADE reaches it in all 10 runs, after a median of 66,650 evaluations: its +differences between members of the population take the wells' spacing, and its restarts on +stagnation free it from the local minima it falls into. No other algorithm reaches it. CMA-ES ends +in a local minimum with a median error of 18, and 6.0 with IPOP restarts; PSO's median run ends at +7.5. The genetic algorithm, whose mutation changes one gene at a time, gets close, to a median error +of 2.2e-4, but doesn't reach 1e-8 within the budget. diff --git a/examples/buche_rastrigin/main.py b/examples/buche_rastrigin/main.py new file mode 100644 index 00000000..7d9aef84 --- /dev/null +++ b/examples/buche_rastrigin/main.py @@ -0,0 +1,86 @@ +"""Büche-Rastrigin: minimize BBOB's Büche-Rastrigin function, an asymmetric Rastrigin, in 10 +dimensions. + +Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), +differential evolution (SHADE), particle swarm optimization and a real-coded genetic algorithm from +10 seeds each, and counts the runs that reach the minimum, 0 at the origin, to within 1e-8. The +function is genoxide's `problems::BucheRastrigin`, which run evaluates in Rust. + +With ``GENOXIDE_TRACE=``, it also writes a trace of a run for the plot on the example's page, +with trace.py. + + python examples/buche_rastrigin/main.py +""" + +import genoxide as gx + +from trace import record_small + +DIMENSIONS = 10 +SEEDS = 10 +BUDGET = 10_000 * DIMENSIONS +# a run stops once its error to the minimum is at most this +ERROR = 1e-8 +ALGORITHMS = ["CMA-ES", "CMA-ES with IPOP", "DE", "PSO", "GA"] + + +def build(name, genome, seed): + """The algorithm called ``name``, on ``genome``, from ``seed``.""" + if name == "CMA-ES": + return gx.Cmaes(genome, objective="minimize", seed=seed) + if name == "CMA-ES with IPOP": + return gx.Cmaes(genome, restarts="ipop", objective="minimize", seed=seed) + if name == "DE": + return gx.De(genome, objective="minimize", seed=seed) + if name == "PSO": + return gx.Pso(genome, population_size=40, objective="minimize", seed=seed) + return gx.Ga( + genome, + population_size=100, + select=gx.Tournament(3), + crossover=gx.SimulatedBinaryCrossover(15.0), + mutation=gx.PolynomialMutation(20.0, rate=1 / DIMENSIONS), + objective="minimize", + seed=seed, + ) + + +def median(values): + """The median of ``values``, None without any.""" + values = sorted(values) + middle = len(values) // 2 + if not values: + return None + return values[middle] if len(values) % 2 else (values[middle - 1] + values[middle]) / 2 + + +def error_text(error): + """An error to two significant digits, as Rust writes it: 9.9e-9.""" + mantissa, exponent = f"{error:.1e}".split("e") + return f"{mantissa}e{int(exponent)}" + + +problem = gx.problems.BucheRastrigin(DIMENSIONS) +minimum = problem.optimum.value +print(f"Büche-Rastrigin in {DIMENSIONS} dimensions, {SEEDS} seeds, {BUDGET} evaluations at most per run") +print("algorithm at min evaluations median error") +for name in ALGORITHMS: + # the evaluations of the runs that reach the minimum, and every run's best error + evaluations, errors = [], [] + for seed in range(1, SEEDS + 1): + result = build(name, problem.genome, seed).run( + problem, target=minimum + ERROR, evaluations=BUDGET + ) + if result.stop_reason == "target": + evaluations.append(float(result.evaluations)) + # rounding can put a solution a few ulps below the minimum + errors.append(max(result.best_fitness - minimum, 0.0)) + reached = f"{len(evaluations)}/{SEEDS}" + middle = median(evaluations) + evaluations_text = "-" if middle is None else f"{middle:.0f}" + print(f"{name:<16} {reached:>6} {evaluations_text:>11} {error_text(median(errors)):>12}") +print("evaluations: the median of the runs that reach the minimum") + +# with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate run in +# 2 dimensions: the plot is the function's contour +record_small() diff --git a/examples/buche_rastrigin/main.rs b/examples/buche_rastrigin/main.rs new file mode 100644 index 00000000..f0c34529 --- /dev/null +++ b/examples/buche_rastrigin/main.rs @@ -0,0 +1,118 @@ +//! Büche-Rastrigin: minimize BBOB's Büche-Rastrigin function, an asymmetric Rastrigin, in 10 +//! dimensions. +//! +//! Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), +//! differential evolution (SHADE), particle swarm optimization and a real-coded genetic algorithm +//! from 10 seeds each, and counts the runs that reach the minimum, 0 at the origin, to within +//! 1e-8. The function is genoxide's `problems::BucheRastrigin`. +//! +//! With `GENOXIDE_TRACE=`, it also writes a trace of a run for the plot on the example's +//! page, with `trace.rs`. +//! +//! ```text +//! cargo run --release --example buche_rastrigin +//! ``` + +mod trace; + +use genoxide::prelude::*; +use genoxide::problems::{BucheRastrigin, Problem}; + +const DIMENSIONS: usize = 10; +const SEEDS: u64 = 10; +const BUDGET: u64 = 10_000 * DIMENSIONS as u64; +// a run stops once its error to the minimum is at most this +const ERROR: f64 = 1e-8; +const ALGORITHMS: [&str; 5] = ["CMA-ES", "CMA-ES with IPOP", "DE", "PSO", "GA"]; + +fn main() -> Result<()> { + let problem = BucheRastrigin::new(DIMENSIONS); + let minimum = problem.optimum().expect("known").value(); + println!( + "Büche-Rastrigin in {DIMENSIONS} dimensions, {SEEDS} seeds, {BUDGET} evaluations at most per run" + ); + println!("algorithm at min evaluations median error"); + for algorithm in ALGORITHMS { + // the evaluations of the runs that reach the minimum, and every run's best error + let mut evaluations = Vec::new(); + let mut errors = Vec::new(); + for seed in 1..=SEEDS { + let outcome = run(algorithm, problem, seed, minimum + ERROR)?; + if outcome.stop_reason() == StopReason::Target { + evaluations.push(outcome.evaluations() as f64); + } + // rounding can put a solution a few ulps below the minimum + let best = outcome.best_fitness().score().expect("valid"); + errors.push((best - minimum).max(0.0)); + } + let reached = format!("{}/{SEEDS}", evaluations.len()); + let evaluations = median(evaluations).map_or("-".to_string(), |e| format!("{e:.0}")); + let error = median(errors).expect("a run"); + println!( + "{algorithm:<16} {reached:>6} {evaluations:>11} {:>12}", + format!("{error:.1e}") + ); + } + println!("evaluations: the median of the runs that reach the minimum"); + + // with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate + // run in 2 dimensions: the plot is the function's contour + trace::record_small()?; + Ok(()) +} + +// a run of `algorithm` from `seed`, until its best is at most `target` or it has used BUDGET +// evaluations +fn run(algorithm: &str, problem: BucheRastrigin, seed: u64, target: f64) -> Result> { + let real = problem.representation(); + let stop = Stop::target(target).or(Stop::evaluations(BUDGET)); + match algorithm { + "CMA-ES" | "CMA-ES with IPOP" => { + let restarts = if algorithm == "CMA-ES" { + cmaes::Restarts::Never + } else { + cmaes::Restarts::Ipop + }; + let cmaes = Cmaes::builder(real) + .restarts(restarts) + .minimize() + .seed(seed) + .build()?; + Engine::new(cmaes, problem).stop_when(stop).run() + } + "DE" => { + let de = De::builder(real).minimize().seed(seed).build()?; + Engine::new(de, problem).stop_when(stop).run() + } + "PSO" => { + let pso = Pso::builder(real) + .population_size(40) + .minimize() + .seed(seed) + .build()?; + Engine::new(pso, problem).stop_when(stop).run() + } + _ => { + let ga = Ga::builder(real) + .population_size(100) + .select(Tournament::new(3)?) + .crossover(SimulatedBinaryCrossover::new(15.0)?) + .mutate(PolynomialMutation::per_gene(1.0 / DIMENSIONS as f64, 20.0)?) + .minimize() + .seed(seed) + .build()?; + Engine::new(ga, problem).stop_when(stop).run() + } + } +} + +// the median of `values`, None without any +fn median(mut values: Vec) -> Option { + values.sort_by(f64::total_cmp); + let middle = values.len() / 2; + match values.len() { + 0 => None, + n if n % 2 == 1 => Some(values[middle]), + _ => Some((values[middle - 1] + values[middle]) / 2.0), + } +} diff --git a/examples/buche_rastrigin/output.txt b/examples/buche_rastrigin/output.txt new file mode 100644 index 00000000..882887e9 --- /dev/null +++ b/examples/buche_rastrigin/output.txt @@ -0,0 +1,8 @@ +Büche-Rastrigin in 10 dimensions, 10 seeds, 100000 evaluations at most per run +algorithm at min evaluations median error +CMA-ES 0/10 - 1.8e1 +CMA-ES with IPOP 0/10 - 6.0e0 +DE 10/10 66650 9.4e-9 +PSO 0/10 - 7.5e0 +GA 0/10 - 2.2e-4 +evaluations: the median of the runs that reach the minimum diff --git a/examples/buche_rastrigin/trace.json b/examples/buche_rastrigin/trace.json new file mode 100644 index 00000000..acbbf98b --- /dev/null +++ b/examples/buche_rastrigin/trace.json @@ -0,0 +1,102 @@ +{"example":"buche_rastrigin","format":1,"log_y":true,"objective":"minimize","optimum":0.0,"plot":"contour","problem":{"bounds":[[-5.0,5.0],[-5.0,5.0]],"function":"buche_rastrigin","minima":[[0.0,0.0]]},"x_label":"evaluations","y_label":"error","frames":[ +{"best":38.5189,"evaluations":6,"generation":0,"median":204.597,"state":{"best":[-4.02856,-1.2232],"population":[[-4.02856,-1.2232],[1.09727,-3.0536],[-2.70235,3.76881],[-1.07094,-4.64995],[-3.75609,-3.6306],[2.14496,-1.42894]]}}, +{"best":19.5342,"evaluations":30,"generation":4,"median":35.1189,"state":{"best":[-1.06412,-0.908929],"population":[[-1.06412,-0.908929],[1.11452,-1.89185],[-2.86564,-0.472477],[-1.5256,0.630814],[-2.99447,-1.92215],[-1.80853,-0.844545]]}}, +{"best":16.2315,"evaluations":60,"generation":9,"median":35.9006,"state":{"best":[-1.67249,0.601154],"population":[[-3.07833,-0.168084],[-1.67977,-0.487031],[-2.43718,0.518132],[-3.38354,1.9142],[-2.83239,1.76438],[-1.76485,0.931299]]}}, +{"best":11.7926,"evaluations":84,"generation":13,"median":30.1581,"state":{"best":[-1.9735,0.625166],"population":[[-1.46497,0.181998],[-2.17184,-1.43959],[-0.891764,-0.488468],[-2.51191,-1.02244],[-1.02142,0.453091],[-1.14621,0.600651]]}}, +{"best":6.42893,"evaluations":108,"generation":17,"median":46.2076,"state":{"best":[-0.103156,-0.667539],"population":[[0.595435,-0.304217],[0.677827,-0.76818],[0.458843,0.0695869],[-0.0121645,1.08543],[-1.17535,1.78024],[-1.82384,0.390061]]}}, +{"best":6.42893,"evaluations":138,"generation":22,"median":26.6365,"state":{"best":[-0.103156,-0.667539],"population":[[-1.60722,0.943055],[-1.57898,0.786458],[-1.21192,0.0334189],[-2.1755,0.501873],[-2.27613,0.226632],[-2.21661,0.74901]]}}, +{"best":1.24015,"evaluations":162,"generation":26,"median":24.8735,"state":{"best":[-0.993816,0.0110848],"population":[[-1.27501,-0.261168],[-1.54601,-0.636913],[-1.05128,0.275079],[-1.79776,-0.447471],[-1.11966,0.0456083],[-0.558293,0.761442]]}}, +{"best":1.24015,"evaluations":192,"generation":31,"median":15.0918,"state":{"best":[-0.993816,0.0110848],"population":[[-0.861507,-0.00730298],[-1.01016,0.380262],[-0.973546,0.819547],[-1.32641,0.783091],[-1.35728,0.673015],[-1.02753,0.29314]]}}, +{"best":1.24015,"evaluations":216,"generation":35,"median":9.71802,"state":{"best":[-0.993816,0.0110848],"population":[[-0.94219,0.0916229],[-0.921895,0.386249],[-0.967779,0.456424],[-0.870561,0.317447],[-0.865369,0.275082],[-0.913972,0.267744]]}}, +{"best":1.24015,"evaluations":240,"generation":39,"median":7.88488,"state":{"best":[-0.993816,0.0110848],"population":[[-0.978408,0.21477],[-0.965028,0.392368],[-0.913939,0.464992],[-1.00015,0.275084],[-1.06253,0.306868],[-0.950291,0.372586]]}}, +{"best":1.24015,"evaluations":270,"generation":44,"median":3.25555,"state":{"best":[-0.993816,0.0110848],"population":[[-0.986685,0.349494],[-0.965173,0.307033],[-0.985764,0.314066],[-0.924101,0.31681],[-0.985412,0.31606],[-0.923178,0.33581]]}}, +{"best":1.24015,"evaluations":294,"generation":48,"median":6.63832,"state":{"best":[-0.993816,0.0110848],"population":[[-0.998218,0.284443],[-1.02067,0.274857],[-1.01538,0.242045],[-0.980959,0.251726],[-0.996441,0.245511],[-0.974974,0.315098]]}}, +{"best":1.24015,"evaluations":318,"generation":52,"median":2.12077,"state":{"best":[-0.993816,0.0110848],"population":[[-0.993022,0.32855],[-1.00774,0.304955],[-1.01825,0.302653],[-1.02194,0.303257],[-0.993642,0.308563],[-0.999789,0.310007]]}}, +{"best":1.24015,"evaluations":348,"generation":57,"median":2.00044,"state":{"best":[-0.993816,0.0110848],"population":[[-0.99589,0.303439],[-1.00126,0.304672],[-1.00024,0.297069],[-0.997076,0.309211],[-0.994946,0.30736],[-0.994825,0.304568]]}}, +{"best":1.24015,"evaluations":372,"generation":61,"median":2.00056,"state":{"best":[-0.993816,0.0110848],"population":[[-0.992829,0.305156],[-0.994879,0.304224],[-0.996489,0.304764],[-0.992074,0.310406],[-1.00166,0.304099],[-0.99852,0.301941]]}}, +{"best":1.24015,"evaluations":396,"generation":65,"median":1.99348,"state":{"best":[-0.993816,0.0110848],"population":[[-0.997197,0.307475],[-0.99849,0.304558],[-0.998066,0.304819],[-0.99215,0.307042],[-0.994243,0.304846],[-0.997568,0.305932]]}}, +{"best":1.24015,"evaluations":426,"generation":70,"median":1.99009,"state":{"best":[-0.993816,0.0110848],"population":[[-0.99702,0.305103],[-0.996261,0.305334],[-0.996692,0.305577],[-0.99688,0.305576],[-0.996727,0.305881],[-0.995699,0.305619]]}}, +{"best":1.24015,"evaluations":450,"generation":74,"median":1.98999,"state":{"best":[-0.993816,0.0110848],"population":[[-0.996789,0.305547],[-0.996199,0.305825],[-0.99671,0.305205],[-0.996231,0.305687],[-0.99661,0.305408],[-0.99675,0.305548]]}}, +{"best":1.24015,"evaluations":480,"generation":79,"median":1.98992,"state":{"best":[-0.993816,0.0110848],"population":[[-0.996446,0.305672],[-0.996509,0.305662],[-0.996531,0.305621],[-0.996511,0.305608],[-0.996437,0.30559],[-0.996463,0.305639]]}}, +{"best":1.24015,"evaluations":504,"generation":83,"median":1.98992,"state":{"best":[-0.993816,0.0110848],"population":[[-0.996448,0.305625],[-0.996461,0.305591],[-0.996483,0.305607],[-0.996483,0.305554],[-0.996501,0.305596],[-0.996416,0.305596]]}}, +{"best":1.24015,"evaluations":528,"generation":87,"median":1.98992,"state":{"best":[-0.993816,0.0110848],"population":[[-0.99645,0.3056],[-0.996448,0.305614],[-0.99647,0.305608],[-0.996459,0.305625],[-0.99647,0.305621],[-0.996467,0.30562]]}}, +{"best":1.24015,"evaluations":558,"generation":92,"median":1.98992,"state":{"best":[-0.993816,0.0110848],"population":[[-0.996453,0.305616],[-0.996454,0.305616],[-0.996449,0.305614],[-0.996446,0.305616],[-0.996451,0.305615],[-0.996452,0.305615]]}}, +{"best":1.24015,"evaluations":582,"generation":96,"median":1.98992,"state":{"best":[-0.993816,0.0110848],"population":[[-0.99645,0.305614],[-0.996443,0.305616],[-0.996451,0.305615],[-0.996445,0.305614],[-0.996449,0.305615],[-0.99645,0.305614]]}}, +{"best":1.24015,"evaluations":606,"generation":100,"median":1.98992,"state":{"best":[-0.993816,0.0110848],"population":[[-0.99645,0.305614],[-0.99645,0.305614],[-0.99645,0.305615],[-0.996451,0.305614],[-0.996451,0.305614],[-0.996452,0.305615]]}}, +{"best":1.24015,"evaluations":636,"generation":105,"median":1.98992,"state":{"best":[-0.993816,0.0110848],"population":[[-0.99645,0.305614],[-0.996451,0.305614],[-0.996451,0.305614],[-0.996451,0.305614],[-0.99645,0.305614],[-0.996451,0.305614]]}}, +{"best":1.24015,"evaluations":660,"generation":109,"median":1.98992,"state":{"best":[-0.993816,0.0110848],"population":[[-0.996451,0.305614],[-0.99645,0.305614],[-0.996451,0.305614],[-0.996451,0.305614],[-0.996451,0.305614],[-0.99645,0.305614]]}}, +{"best":1.24015,"evaluations":684,"generation":113,"median":1.98992,"state":{"best":[-0.993816,0.0110848],"population":[[-0.99645,0.305614],[-0.996451,0.305614],[-0.996451,0.305614],[-0.996451,0.305614],[-0.99645,0.305614],[-0.996451,0.305614]]}}, +{"best":1.24015,"evaluations":714,"generation":118,"median":1.98992,"state":{"best":[-0.993816,0.0110848],"population":[[-0.996451,0.305614],[-0.996451,0.305614],[-0.996451,0.305614],[-0.996451,0.305614],[-0.996451,0.305614],[-0.996451,0.305614]]}}, +{"best":1.24015,"evaluations":738,"generation":122,"median":1.98992,"state":{"best":[-0.993816,0.0110848],"population":[[-0.996451,0.305614],[-0.996451,0.305614],[-0.996451,0.305614],[-0.996451,0.305614],[-0.996451,0.305614],[-0.996451,0.305614]]}}, +{"best":1.24015,"evaluations":768,"generation":127,"median":1.98992,"state":{"best":[-0.993816,0.0110848],"population":[[-0.996451,0.305614],[-0.996451,0.305614],[-0.996451,0.305614],[-0.996451,0.305614],[-0.996451,0.305614],[-0.996451,0.305614]]}}, +{"best":1.24015,"evaluations":792,"generation":131,"median":1.98992,"state":{"best":[-0.993816,0.0110848],"population":[[-0.996451,0.305614],[-0.996451,0.305614],[-0.996451,0.305614],[-0.996451,0.305614],[-0.996451,0.305614],[-0.996451,0.305614]]}}, +{"best":1.24015,"evaluations":828,"generation":135,"median":72.6447,"state":{"best":[-0.993816,0.0110848],"population":[[-1.71983,-2.55729],[-2.92793,4.15862],[-1.6117,-2.31666],[2.6511,-3.31707],[-3.04096,-0.0655026],[-3.53319,-1.3888],[-0.789684,0.111184],[-0.946083,-0.657731],[2.72766,-0.620113],[1.70556,1.79578],[-0.0334979,-1.13051],[-0.640806,3.05682]]}}, +{"best":1.24015,"evaluations":888,"generation":140,"median":31.3982,"state":{"best":[-0.993816,0.0110848],"population":[[-2.127,0.829842],[-2.03674,-1.06363],[-2.58304,0.767421],[-3.32782,-0.414329],[-2.2987,-0.592089],[-2.54674,-0.346006],[-2.52741,0.50564],[-2.37021,0.0933152],[-1.98987,-0.669386],[-1.81023,-1.23098],[-1.28889,-0.542525],[-2.13064,0.21859]]}}, +{"best":1.24015,"evaluations":936,"generation":144,"median":24.0669,"state":{"best":[-0.993816,0.0110848],"population":[[-1.90425,0.135746],[-2.21513,0.690239],[-1.49568,0.0516427],[-1.37876,0.397265],[-2.12825,0.389955],[-1.71542,-0.327949],[-2.13776,0.66425],[-1.63976,-0.595207],[-1.79564,-0.101804],[-2.65444,0.176596],[-2.49856,0.327543],[-1.6353,-0.131572]]}}, +{"best":1.24015,"evaluations":984,"generation":148,"median":23.908,"state":{"best":[-0.993816,0.0110848],"population":[[-1.91708,0.37865],[-1.88741,0.217024],[-1.94561,0.477299],[-2.03428,0.294324],[-1.79428,0.146503],[-1.84091,0.147568],[-1.93333,0.362304],[-1.82057,0.157939],[-1.8582,0.166395],[-1.93864,0.165794],[-1.95745,0.146986],[-1.78824,0.38559]]}}, +{"best":1.24015,"evaluations":1044,"generation":153,"median":12.6324,"state":{"best":[-0.993816,0.0110848],"population":[[-1.95036,0.519524],[-1.88882,0.319904],[-1.8292,0.466454],[-1.89829,0.287389],[-1.90407,0.33813],[-1.97987,0.384821],[-1.83755,0.220618],[-1.89315,0.201263],[-1.95986,0.347285],[-1.83628,0.227987],[-1.88368,0.32744],[-1.89213,0.238494]]}}, +{"best":1.24015,"evaluations":1092,"generation":157,"median":6.11111,"state":{"best":[-0.993816,0.0110848],"population":[[-1.8919,0.337079],[-1.88724,0.285793],[-1.89056,0.328439],[-1.89855,0.300551],[-1.87571,0.325152],[-1.86243,0.306038],[-1.89436,0.31721],[-1.89327,0.261043],[-1.90111,0.296633],[-1.88428,0.290156],[-1.89089,0.309483],[-1.87878,0.325566]]}}, +{"best":1.24015,"evaluations":1140,"generation":161,"median":7.08696,"state":{"best":[-0.993816,0.0110848],"population":[[-1.95225,0.280961],[-1.89207,0.262487],[-1.92795,0.277475],[-2.02623,0.23157],[-1.98183,0.347685],[-1.98527,0.322012],[-1.94837,0.263636],[-1.83705,0.333729],[-1.92323,0.256658],[-1.91635,0.338883],[-2.05506,0.321684],[-1.86799,0.305456]]}}, +{"best":1.24015,"evaluations":1200,"generation":166,"median":5.0383,"state":{"best":[-0.993816,0.0110848],"population":[[-1.94055,0.313608],[-1.94427,0.310642],[-1.94185,0.309739],[-1.95912,0.30619],[-1.99664,0.313971],[-1.96295,0.300398],[-1.96872,0.29867],[-1.96591,0.310893],[-1.94069,0.297303],[-1.9545,0.305695],[-1.94689,0.302502],[-1.98573,0.305784]]}}, +{"best":1.24015,"evaluations":1248,"generation":170,"median":4.97908,"state":{"best":[-0.993816,0.0110848],"population":[[-1.9611,0.305681],[-1.9646,0.303587],[-1.95735,0.30438],[-1.94798,0.303727],[-1.95848,0.305936],[-1.95526,0.303354],[-1.96195,0.306309],[-1.9584,0.306825],[-1.95,0.30611],[-1.95073,0.303663],[-1.95102,0.305067],[-1.94933,0.307285]]}}, +{"best":1.24015,"evaluations":1308,"generation":175,"median":4.97513,"state":{"best":[-0.993816,0.0110848],"population":[[-1.95668,0.305947],[-1.95547,0.305874],[-1.95442,0.306132],[-1.95707,0.305154],[-1.95703,0.3061],[-1.95726,0.30591],[-1.95622,0.305299],[-1.95556,0.305743],[-1.95679,0.305987],[-1.95536,0.305991],[-1.95441,0.305827],[-1.95531,0.305192]]}}, +{"best":1.24015,"evaluations":1356,"generation":179,"median":4.9748,"state":{"best":[-0.993816,0.0110848],"population":[[-1.95586,0.305579],[-1.95643,0.305403],[-1.95578,0.305638],[-1.95643,0.305271],[-1.9561,0.305632],[-1.95605,0.305557],[-1.9557,0.305545],[-1.95588,0.305798],[-1.95552,0.306064],[-1.95558,0.305547],[-1.95595,0.305628],[-1.95577,0.305555]]}}, +{"best":1.24015,"evaluations":1404,"generation":183,"median":4.97479,"state":{"best":[-0.993816,0.0110848],"population":[[-1.95569,0.305634],[-1.95561,0.305597],[-1.95592,0.305596],[-1.95597,0.305622],[-1.95594,0.305623],[-1.95589,0.305571],[-1.95568,0.305589],[-1.95577,0.305609],[-1.9558,0.30565],[-1.95577,0.305665],[-1.95563,0.30562],[-1.95592,0.305656]]}}, +{"best":1.24015,"evaluations":1464,"generation":188,"median":4.97479,"state":{"best":[-0.993816,0.0110848],"population":[[-1.95584,0.305615],[-1.95583,0.305616],[-1.95582,0.30562],[-1.95585,0.305608],[-1.95582,0.305617],[-1.95586,0.305626],[-1.95587,0.305613],[-1.95585,0.305622],[-1.95581,0.305621],[-1.95583,0.305613],[-1.95584,0.305613],[-1.95589,0.305614]]}}, +{"best":1.24015,"evaluations":1512,"generation":192,"median":4.97479,"state":{"best":[-0.993816,0.0110848],"population":[[-1.95585,0.305617],[-1.95583,0.305617],[-1.95585,0.305617],[-1.95583,0.305612],[-1.95584,0.305615],[-1.95584,0.305614],[-1.95584,0.305614],[-1.95584,0.305616],[-1.95584,0.305617],[-1.95585,0.305614],[-1.95585,0.305614],[-1.95584,0.305614]]}}, +{"best":1.24015,"evaluations":1560,"generation":196,"median":4.97479,"state":{"best":[-0.993816,0.0110848],"population":[[-1.95584,0.305614],[-1.95584,0.305614],[-1.95584,0.305615],[-1.95584,0.305615],[-1.95584,0.305615],[-1.95584,0.305615],[-1.95584,0.305615],[-1.95584,0.305615],[-1.95584,0.305615],[-1.95584,0.305615],[-1.95585,0.305615],[-1.95584,0.305615]]}}, +{"best":1.24015,"evaluations":1620,"generation":201,"median":4.97479,"state":{"best":[-0.993816,0.0110848],"population":[[-1.95584,0.305614],[-1.95584,0.305614],[-1.95584,0.305614],[-1.95584,0.305614],[-1.95584,0.305615],[-1.95584,0.305614],[-1.95584,0.305614],[-1.95584,0.305614],[-1.95584,0.305615],[-1.95584,0.305614],[-1.95584,0.305614],[-1.95584,0.305614]]}}, +{"best":1.24015,"evaluations":1668,"generation":205,"median":4.97479,"state":{"best":[-0.993816,0.0110848],"population":[[-1.95584,0.305614],[-1.95584,0.305614],[-1.95584,0.305614],[-1.95584,0.305614],[-1.95584,0.305614],[-1.95584,0.305614],[-1.95584,0.305614],[-1.95584,0.305614],[-1.95584,0.305614],[-1.95584,0.305614],[-1.95584,0.305614],[-1.95584,0.305614]]}}, +{"best":1.24015,"evaluations":1716,"generation":209,"median":4.97479,"state":{"best":[-0.993816,0.0110848],"population":[[-1.95584,0.305614],[-1.95584,0.305614],[-1.95584,0.305614],[-1.95584,0.305614],[-1.95584,0.305614],[-1.95584,0.305614],[-1.95584,0.305614],[-1.95584,0.305614],[-1.95584,0.305614],[-1.95584,0.305614],[-1.95584,0.305614],[-1.95584,0.305614]]}}, +{"best":1.24015,"evaluations":1776,"generation":214,"median":4.97479,"state":{"best":[-0.993816,0.0110848],"population":[[-1.95584,0.305614],[-1.95584,0.305614],[-1.95584,0.305614],[-1.95584,0.305614],[-1.95584,0.305614],[-1.95584,0.305614],[-1.95584,0.305614],[-1.95584,0.305614],[-1.95584,0.305614],[-1.95584,0.305614],[-1.95584,0.305614],[-1.95584,0.305614]]}}, +{"best":1.24015,"evaluations":1848,"generation":218,"median":124.716,"state":{"best":[-0.993816,0.0110848],"population":[[-2.06213,-0.466738],[1.33048,3.22092],[-2.7221,-1.94524],[-0.0787546,-4.20575],[3.14885,-1.57212],[-2.87977,-4.25482],[-2.1752,2.45162],[2.62885,2.30573],[1.57499,2.24473],[3.96848,-0.995837],[-3.97654,0.184618],[-1.25668,-1.51795],[-4.96982,1.35943],[-3.18258,-1.39747],[-4.76721,-3.28738],[-3.86707,-1.61703],[1.1285,-2.98019],[-3.34918,2.2907],[-1.04844,-0.828834],[-0.639768,-4.38414],[-3.66388,1.05821],[-4.6615,-4.32616],[-4.7857,2.04027],[1.28881,2.315]]}}, +{"best":1.24015,"evaluations":1968,"generation":223,"median":30.6624,"state":{"best":[-0.993816,0.0110848],"population":[[-0.162918,0.142952],[-1.20808,1.26917],[-1.21883,0.79042],[-1.3061,0.179375],[-1.68203,-0.400134],[-1.56725,-0.400341],[-0.9348,1.02508],[-1.86015,-0.00861064],[-0.387647,0.432777],[-0.00362853,0.0242382],[-1.62312,-1.02737],[-2.54677,1.09908],[-1.83378,-0.0697086],[-0.0678997,0.286314],[-2.29372,-0.0317125],[-0.726082,1.40195],[-1.19356,0.284341],[-1.21128,1.22922],[-1.62059,-0.0118575],[-0.426442,0.799323],[-2.76332,-0.245323],[-2.70484,0.0594516],[-1.83773,0.708386],[-1.64237,-0.491215]]}}, +{"best":1.24015,"evaluations":2064,"generation":227,"median":25.1454,"state":{"best":[-0.993816,0.0110848],"population":[[-0.889708,0.165427],[-2.49967,0.688558],[-1.03088,0.104292],[-1.25014,0.0377247],[-0.263714,-0.530317],[-1.20224,0.1254],[0.480067,-0.154598],[-1.33541,-0.425134],[-0.534694,-0.196563],[-0.1339,-0.553687],[-1.57234,-0.245915],[-0.196404,0.0997938],[-1.4507,0.575123],[0.0510744,-0.389385],[-3.58414,0.527428],[-1.74154,-0.275068],[-1.41723,-0.667984],[-2.28761,0.137571],[-0.905718,0.118553],[-0.561541,-0.206306],[-1.33523,0.290519],[-1.46277,0.0288072],[-2.36826,-0.268496],[-0.680104,-0.0601975]]}}, +{"best":1.24015,"evaluations":2160,"generation":231,"median":23.7681,"state":{"best":[-0.993816,0.0110848],"population":[[-0.836492,-0.110828],[-2.09201,-0.0195737],[-1.38294,-0.289281],[-1.70042,0.0670463],[-1.44541,0.0798104],[-0.847122,-0.0163457],[-1.36816,-0.26218],[-0.702429,0.0571374],[-1.02318,0.10897],[-1.58622,-0.0791032],[-1.39673,-0.0983585],[-0.850082,0.0831096],[-1.90309,0.0155226],[-1.57983,0.0748247],[-1.58132,0.136566],[-2.50706,0.0742074],[-1.64316,0.194241],[-1.61148,0.14799],[-1.47254,0.155411],[-1.35139,0.0196758],[-2.35462,0.371264],[-0.964873,0.0240552],[-0.612183,-0.0242394],[-1.22993,-0.0890278]]}}, +{"best":1.24015,"evaluations":2280,"generation":236,"median":12.9579,"state":{"best":[-0.993816,0.0110848],"population":[[-0.731422,0.0588725],[-0.735624,0.0192507],[-1.09923,-0.0278081],[-0.679176,0.00771133],[-0.895027,0.0461585],[-1.22133,0.0577462],[-0.87742,-0.00641522],[-0.945826,0.0224924],[-0.92369,0.018019],[-0.766776,-0.0204703],[-0.609349,0.0289361],[-1.11868,0.00446667],[-1.07985,0.051656],[-1.29182,0.0242973],[-1.51363,-0.0299686],[-1.15916,-0.00427494],[-0.422023,-0.00429575],[-0.88496,-0.0211209],[-0.661421,0.0265756],[-1.48256,0.0537152],[-1.28787,-0.0395128],[-0.832809,-0.0369975],[-0.991391,-0.0244175],[-1.05356,-0.0649567]]}}, +{"best":1.02722,"evaluations":2376,"generation":240,"median":2.30244,"state":{"best":[-1.00312,-0.00274075],"population":[[-0.978435,-0.0157274],[-0.958098,0.0120369],[-0.958633,-0.00644442],[-1.05282,-0.0067884],[-0.925132,-0.00826766],[-0.94194,-0.00211794],[-1.0181,-0.00900756],[-0.930004,-0.0018234],[-0.8855,0.0198886],[-0.944479,0.0109527],[-1.00003,0.00382715],[-0.958258,0.00121499],[-0.935889,-0.014479],[-1.00565,0.0248718],[-1.00616,0.00441364],[-0.966933,-0.0254356],[-1.02911,4.02663e-05],[-1.04674,0.0177867],[-0.955683,-0.0257352],[-0.959043,0.000295894],[-0.945965,-0.0274205],[-0.884835,-0.00438092],[-0.884303,-0.00221741],[-1.0077,-0.0246936]]}}, +{"best":0.997205,"evaluations":2472,"generation":244,"median":1.05028,"state":{"best":[-0.994081,6.15963e-05],"population":[[-1.01417,0.000433194],[-0.996825,0.00395855],[-0.983427,0.00887307],[-0.991707,0.0045205],[-0.985255,0.00203513],[-0.984859,-0.00541127],[-0.988487,0.0064729],[-0.98367,0.000101392],[-0.998362,0.00269797],[-0.992707,-0.000737889],[-1.00069,0.00248261],[-0.998903,-0.00176163],[-0.996712,-0.00263153],[-1.01534,0.00169716],[-1.00281,0.00363975],[-0.97422,0.00356851],[-0.987776,-0.00174417],[-1.01194,0.00572756],[-0.99412,0.00186774],[-0.981516,-0.000365541],[-0.992687,-0.00185808],[-0.995531,0.00248229],[-1.00793,-0.00429988],[-0.98473,0.00031861]]}}, +{"best":0.994965,"evaluations":2592,"generation":249,"median":0.996079,"state":{"best":[-0.996407,4.64976e-05],"population":[[-0.997819,0.000622126],[-0.999379,0.00119215],[-0.994545,0.000361325],[-0.994795,0.000492401],[-0.99705,-4.01683e-05],[-0.995084,-0.000589419],[-0.997194,0.000383289],[-0.997378,0.000700962],[-0.996258,0.000272538],[-0.997147,8.74924e-05],[-0.998434,-0.000245521],[-0.996028,0.000490245],[-0.994044,-0.000389124],[-0.996799,-0.000605758],[-0.997491,0.00032806],[-0.995264,0.000513936],[-0.996293,-0.00017436],[-0.996282,9.02278e-05],[-0.994962,-0.00035969],[-0.994534,-0.000567859],[-0.995767,0.00134399],[-0.998367,9.86143e-05],[-0.996402,0.000406592],[-0.997248,-0.000565965]]}}, +{"best":0.99496,"evaluations":2688,"generation":253,"median":0.995003,"state":{"best":[-0.996507,5.19724e-06],"population":[[-0.996288,-0.000185924],[-0.996775,1.93579e-05],[-0.99658,-0.000190722],[-0.996405,0.000162461],[-0.996404,-0.000149261],[-0.996996,-0.000113202],[-0.996764,5.15666e-05],[-0.996335,-4.5904e-05],[-0.996427,-5.66409e-05],[-0.996358,-6.40997e-05],[-0.996123,-4.06243e-06],[-0.99702,-5.34567e-05],[-0.996475,0.000210094],[-0.996728,-1.82793e-05],[-0.996236,4.7566e-05],[-0.996119,-0.000171724],[-0.996434,-7.86507e-05],[-0.996238,-5.1749e-05],[-0.996668,-4.58422e-05],[-0.996585,4.47633e-05],[-0.996568,0.000221898],[-0.995875,6.91199e-05],[-0.996684,0.0001092],[-0.996311,-0.000114558]]}}, +{"best":0.994959,"evaluations":2784,"generation":257,"median":0.994961,"state":{"best":[-0.996455,2.72609e-06],"population":[[-0.996488,1.55345e-05],[-0.996483,2.37139e-05],[-0.996386,-2.28043e-05],[-0.996513,2.30329e-05],[-0.996523,2.03008e-05],[-0.996531,-3.24608e-05],[-0.996385,-5.20683e-08],[-0.996441,-3.01709e-05],[-0.996458,1.896e-05],[-0.996511,1.74053e-05],[-0.996517,1.96029e-05],[-0.996509,-5.02352e-06],[-0.996438,-1.52726e-05],[-0.996397,5.41603e-06],[-0.996409,-1.8747e-05],[-0.996513,-1.01152e-05],[-0.996382,-2.2758e-05],[-0.996439,4.67005e-05],[-0.99641,4.05303e-05],[-0.99659,3.77253e-05],[-0.996417,2.65043e-05],[-0.996427,-5.04632e-06],[-0.996493,-2.21236e-05],[-0.996449,9.01375e-06]]}}, +{"best":0.994959,"evaluations":2904,"generation":262,"median":0.994959,"state":{"best":[-0.99645,7.20321e-09],"population":[[-0.996442,2.73464e-06],[-0.99645,8.35546e-07],[-0.996449,4.71844e-07],[-0.996454,1.68979e-06],[-0.996446,-2.17955e-06],[-0.996454,5.09229e-07],[-0.996453,6.19726e-07],[-0.996454,7.2311e-07],[-0.996452,-4.16771e-07],[-0.996452,-3.54953e-07],[-0.996448,2.69238e-07],[-0.99646,4.8728e-06],[-0.996448,-5.68043e-07],[-0.99645,1.31443e-06],[-0.996455,-1.72492e-06],[-0.996457,1.21542e-06],[-0.996443,-3.82389e-06],[-0.99644,-9.1716e-07],[-0.996448,-3.13965e-07],[-0.996451,-5.11026e-06],[-0.996453,1.02114e-06],[-0.996456,-2.33011e-06],[-0.996442,8.18267e-07],[-0.996446,1.02238e-06]]}}, +{"best":0.994959,"evaluations":3000,"generation":266,"median":0.994959,"state":{"best":[-0.996451,-7.65198e-08],"population":[[-0.99645,-1.07463e-07],[-0.996451,-8.28179e-08],[-0.99645,-1.19605e-07],[-0.996451,9.98664e-08],[-0.99645,3.16973e-07],[-0.99645,-1.20384e-08],[-0.996451,9.7354e-08],[-0.99645,-2.08835e-07],[-0.996451,2.30639e-08],[-0.99645,-1.64983e-07],[-0.996451,-5.49396e-07],[-0.99645,-2.65207e-07],[-0.99645,2.97726e-07],[-0.996451,-3.1809e-07],[-0.996451,1.24117e-07],[-0.996451,-2.69143e-08],[-0.99645,1.28013e-07],[-0.996449,-3.70687e-07],[-0.996451,3.59721e-07],[-0.99645,-5.42451e-09],[-0.996451,2.02637e-10],[-0.99645,-2.39973e-08],[-0.996451,-5.35717e-07],[-0.996451,-1.08084e-07]]}}, +{"best":0.994959,"evaluations":3120,"generation":271,"median":0.994959,"state":{"best":[-0.996451,3.4315e-10],"population":[[-0.996451,-1.97003e-08],[-0.996451,3.01564e-08],[-0.99645,2.30359e-08],[-0.996451,5.81171e-08],[-0.99645,-6.63241e-08],[-0.996451,4.35625e-09],[-0.99645,-1.20237e-08],[-0.996451,-8.79684e-08],[-0.996451,7.85664e-08],[-0.99645,-7.09574e-09],[-0.99645,2.41601e-08],[-0.996451,-3.79206e-09],[-0.996451,-7.58013e-08],[-0.996451,-4.61611e-08],[-0.99645,-5.16051e-08],[-0.996451,3.4315e-10],[-0.996451,3.83286e-08],[-0.99645,1.0069e-08],[-0.996451,-1.36219e-08],[-0.996451,1.78954e-08],[-0.996451,-2.5606e-08],[-0.996451,-6.03424e-08],[-0.996451,1.66494e-08],[-0.99645,-2.53509e-08]]}}, +{"best":0.994959,"evaluations":3216,"generation":275,"median":0.994959,"state":{"best":[-0.996451,1.80444e-10],"population":[[-0.996451,-2.91753e-09],[-0.996451,-1.60268e-09],[-0.996451,-3.38253e-10],[-0.996451,6.46479e-09],[-0.996451,2.99391e-09],[-0.996451,5.27746e-09],[-0.996451,-5.03005e-09],[-0.996451,-1.60641e-09],[-0.996451,4.86243e-09],[-0.996451,1.54136e-09],[-0.996451,-3.26917e-09],[-0.996451,4.466e-09],[-0.996451,-1.41759e-09],[-0.996451,-4.69336e-09],[-0.996451,-5.7939e-09],[-0.996451,2.52503e-09],[-0.996451,-1.43679e-09],[-0.996451,4.08815e-09],[-0.996451,7.4132e-09],[-0.996451,3.42757e-11],[-0.996451,-8.3344e-11],[-0.996451,-7.91487e-09],[-0.996451,-5.33804e-09],[-0.996451,-5.06311e-09]]}}, +{"best":0.994959,"evaluations":3312,"generation":279,"median":0.994959,"state":{"best":[-0.996451,1.44467e-10],"population":[[-0.996451,-1.70971e-09],[-0.996451,1.10277e-09],[-0.996451,-2.43072e-09],[-0.996451,8.11137e-10],[-0.996451,-1.35564e-09],[-0.996451,1.13034e-09],[-0.996451,-7.83038e-10],[-0.996451,-2.5718e-10],[-0.996451,-1.27716e-09],[-0.996451,9.13425e-10],[-0.996451,5.83054e-10],[-0.996451,1.44467e-10],[-0.996451,-6.63251e-10],[-0.996451,-1.21968e-10],[-0.996451,-1.53639e-09],[-0.996451,1.00734e-09],[-0.996451,-1.67235e-09],[-0.996451,-8.99512e-11],[-0.996451,2.84581e-10],[-0.996451,-6.50315e-11],[-0.996451,2.85452e-11],[-0.996451,-1.51101e-09],[-0.996451,4.74913e-10],[-0.996451,1.15391e-10]]}}, +{"best":0.994959,"evaluations":3480,"generation":284,"median":109.838,"state":{"best":[-0.996451,1.44467e-10],"population":[[-4.50874,1.48152],[-0.104672,-0.699883],[0.495538,-2.71609],[-3.40564,-0.0992302],[1.05328,2.99149],[1.43656,4.82598],[-2.62141,3.82207],[-4.33774,0.523717],[2.43831,2.75769],[-2.3294,-0.788272],[-0.660573,-0.5381],[-1.13933,3.18175],[2.49348,-1.80846],[0.210657,1.70436],[-0.0879387,3.7174],[0.970336,3.79595],[-2.14332,-2.17253],[0.146755,4.62745],[0.807526,-2.67677],[-3.01088,-1.82016],[-3.30749,0.0679888],[2.1863,1.91896],[-2.97122,-1.80945],[0.0765346,-4.179],[-3.42701,-1.90993],[-3.31472,2.42519],[4.28443,-2.31003],[2.1147,4.62582],[-1.02443,1.68281],[-4.42009,-1.83356],[-1.36162,-0.698077],[0.436864,-1.39509],[-0.733695,0.713167],[-2.06598,2.3517],[-2.11049,-3.71657],[-1.85818,3.66977],[1.46746,3.54188],[-3.1318,4.88219],[-0.2834,3.60974],[2.46689,4.21806],[-4.76775,1.50476],[-4.39824,-3.06869],[-4.41043,0.603735],[-3.75731,0.506439],[2.11281,0.154762],[-2.04522,2.28962],[2.2805,-0.00447629],[2.98517,3.79258]]}}, +{"best":0.994959,"evaluations":3672,"generation":288,"median":23.5726,"state":{"best":[-0.996451,1.44467e-10],"population":[[-1.69477,-0.0349461],[-0.331242,-0.123159],[-0.147416,0.113019],[-2.41706,0.887418],[0.0168465,0.106227],[-2.11278,0.421318],[-1.01007,0.021323],[-2.9202,0.778429],[-2.71411,0.262859],[-2.34067,-0.395532],[-2.57581,0.022708],[0.220943,-0.50602],[-1.21415,-0.289863],[0.147425,-0.436464],[-0.181628,-0.484979],[-2.02078,0.0905082],[-2.46421,0.0532166],[-1.04382,-0.410973],[-1.88169,-1.00391],[-3.32263,0.148784],[-1.21941,-0.0731322],[-1.47482,-0.152455],[-1.44227,-0.230479],[-1.277,-0.498264],[-1.0021,0.25534],[-0.0564862,0.106078],[-2.74791,-0.518778],[-0.0611947,0.0170802],[-1.27511,0.278004],[-2.1758,0.546237],[-0.250315,-0.713364],[-1.5031,-0.156052],[0.217135,0.617466],[-0.269443,-0.0658935],[-0.74079,-0.171342],[1.09874,-0.0325877],[-1.8344,-0.527981],[-0.855266,-0.672201],[-0.848355,0.00143339],[-0.544965,-0.692074],[-0.815264,-0.697824],[-0.901787,-0.373062],[-0.418098,0.0310545],[-0.0748199,0.616179],[-1.68468,0.86152],[-1.4619,0.254327],[-1.65255,0.19996],[-1.42643,0.0957968]]}}, +{"best":0.994959,"evaluations":3864,"generation":292,"median":25.4321,"state":{"best":[-0.996451,1.44467e-10],"population":[[0.845817,-0.129535],[-0.343926,-0.319013],[-0.435883,-1.10684],[-1.85518,-0.102466],[-0.754851,-0.115494],[-0.965539,-1.22034],[-1.5621,0.0639749],[-0.829631,-0.51143],[-0.713743,-0.144045],[-0.885057,-0.323669],[-0.300168,-0.310148],[-0.846078,0.299331],[0.192134,-0.293147],[-1.34695,-0.272636],[-0.922436,-1.00771],[-2.22988,0.0326791],[0.841155,-0.391094],[0.643843,-1.13314],[0.170488,-0.732791],[-0.735211,-0.304657],[-0.776158,-0.228167],[-1.22017,-0.23037],[-0.727131,0.0883091],[-1.1412,-0.276089],[-1.55883,0.278467],[-1.27583,0.5084],[1.48215,-1.05658],[-0.515756,-0.0995727],[-0.945279,-0.112833],[-1.64331,0.583317],[0.92149,-1.575],[-0.138276,-0.0986465],[-0.0881774,0.430703],[1.09528,-0.33422],[-0.73558,-0.161239],[0.0498514,-0.0561892],[-0.0213392,-0.0658735],[-0.33274,-0.4918],[-0.378184,-0.454816],[-0.336243,-0.749546],[-0.645988,-0.636998],[0.162195,-0.593542],[-1.60192,-0.73445],[-0.755603,-0.166666],[-0.452812,-0.172425],[-0.720913,0.33566],[-0.262779,0.194667],[-0.25801,-0.590315]]}}, +{"best":0.358813,"evaluations":4104,"generation":297,"median":21.3931,"state":{"best":[-0.0158853,-0.012466],"population":[[-0.412887,-0.28875],[-0.42994,0.0309083],[-0.678464,-0.362034],[-0.749142,-0.0168907],[-0.250081,-0.37317],[-1.2226,0.050521],[-0.700118,-0.192397],[-0.890476,-0.0122634],[-1.48758,-0.023606],[-0.813945,-0.213206],[-0.974045,-0.134532],[-1.36304,-0.0390501],[-1.13401,0.00326555],[-0.752543,-0.0576902],[-0.355147,-0.0455545],[-0.876194,-0.23596],[-0.942393,-0.0773344],[-0.620559,0.0379607],[-0.554625,-0.048487],[-0.0698907,-0.262506],[-1.37968,-0.106693],[0.348686,-0.354511],[-0.490454,-0.112513],[-0.0739637,-0.203489],[-0.365687,-0.168922],[-0.462807,-0.164646],[-1.49374,-0.123664],[-0.943408,0.00450801],[-0.641064,-0.15376],[-0.0768274,-0.276244],[0.0189291,-0.181888],[-0.834483,0.000860127],[-0.524516,-0.41019],[-1.3401,0.131916],[-0.330205,0.0508618],[-1.08345,-0.108799],[-0.659028,-0.238178],[-0.720284,-0.0696886],[-1.24857,-0.0151873],[-0.810115,-0.0817383],[-0.39135,-0.182223],[-0.876761,-0.203246],[-0.795588,-0.0897232],[-1.26572,0.0477023],[-0.865375,-0.206728],[-0.791048,-0.0325313],[-1.2479,0.0911391],[-1.02912,-0.099988]]}}, +{"best":0.358813,"evaluations":4296,"generation":301,"median":19.1828,"state":{"best":[-0.0158853,-0.012466],"population":[[-1.06433,-0.204985],[-0.0942555,0.0344761],[-0.200639,-0.0329631],[-1.32066,-0.128773],[-1.4632,0.0232832],[-0.315085,-0.283206],[-0.4996,0.0234854],[-0.293844,-0.00920616],[-0.610265,-0.173979],[-0.204241,0.0337607],[0.317036,0.0512307],[0.0958137,0.0174014],[-1.48792,-0.0911745],[-0.28529,-0.0364232],[-0.55318,0.0941699],[-0.412548,0.271101],[-0.648931,-0.0213746],[-0.955861,-0.0119233],[-0.484733,-0.130206],[-1.07052,0.248527],[-0.7284,0.0658051],[-0.925085,0.333918],[-0.729515,-0.00335284],[-1.81618,-0.166164],[-0.461516,-0.0434176],[-0.38998,0.0544106],[-0.889288,0.169837],[-0.901222,-0.0974624],[-0.295247,-0.0893808],[-1.12131,0.241008],[-0.187078,0.0295792],[-0.0935793,0.0389558],[-0.367069,-0.0582494],[0.623572,-0.0350447],[-0.766797,0.227393],[-1.16306,-0.073282],[-1.29834,0.0916898],[-0.348754,-0.285135],[0.205968,-0.0897544],[0.613544,-0.000890475],[-0.200093,-0.155435],[-1.15212,0.0662495],[-0.654713,-0.0686095],[0.200564,-0.0501883],[-0.985125,-0.217868],[0.0516272,-0.147671],[-0.142368,0.249393],[-1.78189,-0.0890729]]}}, +{"best":0.358813,"evaluations":4488,"generation":305,"median":21.4701,"state":{"best":[-0.0158853,-0.012466],"population":[[-0.375675,-0.176419],[-0.893556,0.173217],[-0.400699,0.00729684],[-1.13703,0.0321113],[-0.563396,-0.159959],[-0.374027,-0.0453086],[-0.186114,0.0448026],[0.25845,-0.202914],[-0.52098,0.133615],[-0.528371,0.0422574],[-0.625844,0.0476043],[-1.40133,0.053373],[-0.834828,0.0236279],[-0.0856714,0.0486852],[-0.296851,-0.0290526],[-0.320157,0.134536],[-0.660624,-0.21097],[-0.146655,0.0724304],[-1.12781,-0.0828582],[-0.272142,0.0309078],[0.561089,0.0251555],[-0.998103,-0.0900241],[-0.538325,-0.0867211],[-0.965963,-0.071183],[-0.573504,0.153744],[-0.996713,0.128525],[-1.0762,0.065134],[-1.06241,-0.0793093],[-1.11582,0.100502],[0.0924877,-0.0232337],[-0.350716,0.217419],[-0.810121,-0.00695707],[-0.700392,-0.0580628],[-0.527903,0.242454],[-0.49454,-0.0916125],[-0.630245,-0.0263109],[-0.915216,0.171655],[-0.320056,-0.125391],[-0.300099,-0.0169035],[0.0816849,0.0270198],[-0.697059,0.00479605],[-0.700219,0.004824],[-0.629668,0.110664],[-0.548674,-0.0133807],[-0.563543,-0.107005],[-0.868098,0.0728344],[-0.418034,0.0327834],[-0.566595,-0.0803156]]}}, +{"best":0.358813,"evaluations":4728,"generation":310,"median":14.4989,"state":{"best":[-0.0158853,-0.012466],"population":[[-0.973112,0.0120776],[-1.1048,-0.00367744],[-0.943808,-0.0161924],[-1.39943,-0.0156035],[-0.808592,0.0122319],[-0.850195,-0.00700984],[-0.523671,0.0498426],[-0.927969,0.0549124],[-0.970996,0.00816505],[-1.30502,-0.019321],[-0.986087,-0.0414553],[-0.898352,0.0081497],[-0.656818,-0.0480916],[-0.927868,-0.049205],[-0.75061,-0.0073229],[-0.890806,-0.038084],[-0.532721,-0.0164381],[-1.42579,0.0275624],[-1.02134,-0.0026936],[-1.2759,0.0515353],[-0.675,-0.0157086],[-1.12186,-0.00527834],[-1.18102,0.0391365],[-1.47105,-0.0420326],[-0.685704,-0.0322145],[-0.769011,-0.0513016],[-0.495966,-0.0668944],[-1.10804,0.0340617],[-1.13664,0.0221968],[-0.606268,0.00951313],[-1.38738,0.0209257],[-1.15916,-0.13426],[-0.968055,-0.0167294],[-0.322202,-0.0136051],[-0.916531,0.0686868],[-0.849071,0.00819789],[-0.609288,0.00313941],[-0.3215,0.0334635],[-1.10937,-0.0496083],[-1.08188,-0.011122],[-0.587482,0.0151792],[-0.83459,-0.016299],[-0.655707,-0.0151139],[-0.695257,0.0341114],[-1.17124,0.00580608],[-0.706929,-0.0222562],[-0.896368,-0.000158504],[-1.29795,-0.00114823]]}}, +{"best":0.358813,"evaluations":4920,"generation":314,"median":1.0828,"state":{"best":[-0.0158853,-0.012466],"population":[[-0.976643,-0.00392857],[-1.00788,4.07801e-05],[-0.989105,-0.00030994],[-1.00026,-0.0110032],[-1.00966,-9.03724e-05],[-0.994729,-0.0104833],[-0.99906,-0.00665842],[-0.989245,0.00500651],[-0.993252,0.00138764],[-0.988488,-0.000652024],[-0.984854,0.00219889],[-1.00623,-0.000428495],[-0.997732,0.00793318],[-1.01743,0.00492885],[-1.01459,-0.00674452],[-1.00519,0.0049486],[-0.99581,-0.000649919],[-1.0011,-0.00722772],[-0.994914,-0.00686994],[-1.01658,-0.00265592],[-0.970812,-0.00373679],[-1.00061,-0.000576934],[-0.985028,-0.00617568],[-0.999045,0.00295636],[-0.996489,-0.00598298],[-0.987258,0.00379057],[-0.973158,0.00205679],[-1.01272,-0.000518634],[-1.0005,0.0101253],[-1.00353,-0.00590789],[-1.01148,-0.00153854],[-1.01842,0.00380061],[-0.990939,-0.00835096],[-1.00481,-0.00133149],[-1.00613,-0.00105494],[-0.991808,0.00705122],[-1.00186,-0.0092418],[-0.987655,-0.000970581],[-1.011,-0.00252837],[-0.986638,-0.0103721],[-0.993133,-0.00154882],[-0.986318,0.00762187],[-0.997797,0.00188474],[-1.0171,-0.00950647],[-0.989096,-0.000306331],[-0.987169,-0.00181771],[-0.989991,0.00194441],[-0.977228,-0.00168002]]}}, +{"best":0.358813,"evaluations":5160,"generation":319,"median":0.995071,"state":{"best":[-0.0158853,-0.012466],"population":[[-0.996369,-0.000335671],[-0.996991,0.000168165],[-0.996346,-4.94125e-05],[-0.996267,6.72784e-05],[-0.995976,-6.51719e-05],[-0.995943,-0.000159831],[-0.996266,-8.32463e-05],[-0.995946,-0.000393603],[-0.996243,-6.49519e-05],[-0.996626,-0.000168069],[-0.996922,-0.000139353],[-0.997168,0.00012965],[-0.997121,-2.42959e-05],[-0.996169,-0.000115951],[-0.996243,-0.000198746],[-0.996199,-4.04184e-05],[-0.99659,-2.89001e-05],[-0.997232,0.000156735],[-0.996528,-1.28622e-05],[-0.997015,-0.000199888],[-0.996618,0.000161251],[-0.997484,6.59444e-05],[-0.996639,0.00034337],[-0.996634,-0.000340377],[-0.995815,0.000287472],[-0.996973,9.69496e-05],[-0.996857,-1.10295e-06],[-0.995899,-0.000195557],[-0.996805,1.06661e-05],[-0.996131,8.30414e-06],[-0.996434,-0.000204282],[-0.997082,-8.27115e-05],[-0.996264,-0.00024364],[-0.996758,0.000112571],[-0.996422,-0.000319982],[-0.995949,-0.000245523],[-0.997003,9.34749e-05],[-0.996548,0.000123471],[-0.996726,-8.43608e-05],[-0.995616,-0.000229305],[-0.997035,-0.00014222],[-0.996518,3.54143e-05],[-0.995687,-0.000151589],[-0.996898,-0.000307395],[-0.996975,8.71713e-06],[-0.996679,-7.13009e-05],[-0.996592,-8.3075e-05],[-0.996517,-0.000118702]]}}, +{"best":0.358813,"evaluations":5352,"generation":323,"median":0.99496,"state":{"best":[-0.0158853,-0.012466],"population":[[-0.996487,-1.2599e-05],[-0.996546,-1.46952e-05],[-0.996452,-9.70977e-06],[-0.996472,8.37326e-06],[-0.996425,6.48449e-06],[-0.996449,8.96943e-06],[-0.996493,-2.6034e-06],[-0.996482,2.62351e-05],[-0.996477,2.57871e-05],[-0.996437,-1.31568e-05],[-0.996511,-1.94145e-05],[-0.996402,3.06814e-05],[-0.996425,2.23953e-05],[-0.996502,-5.37152e-06],[-0.996439,-1.30897e-05],[-0.996475,2.57118e-05],[-0.996415,-6.90175e-06],[-0.996431,-1.43123e-05],[-0.996481,9.85841e-06],[-0.996434,2.13143e-05],[-0.996495,1.08114e-06],[-0.996438,-1.65752e-05],[-0.996517,-2.33992e-06],[-0.99643,-2.60763e-05],[-0.996498,-2.09693e-05],[-0.99649,1.1047e-05],[-0.996496,9.37249e-06],[-0.99642,1.94691e-05],[-0.99645,1.18518e-05],[-0.99645,8.04205e-06],[-0.9965,9.25604e-06],[-0.996393,1.14664e-06],[-0.996392,-9.20673e-06],[-0.996445,-2.34167e-06],[-0.996441,-2.06013e-05],[-0.996516,2.37568e-06],[-0.996427,-5.86692e-06],[-0.996428,3.47844e-07],[-0.996523,9.35289e-06],[-0.996514,-9.31259e-06],[-0.996418,2.50703e-05],[-0.99644,-4.49692e-05],[-0.996424,-1.15698e-05],[-0.996454,-1.18284e-05],[-0.996447,-1.39313e-05],[-0.99637,2.32127e-05],[-0.996474,-1.04364e-05],[-0.996449,-6.24965e-06]]}}, +{"best":0.358813,"evaluations":5544,"generation":327,"median":0.994959,"state":{"best":[-0.0158853,-0.012466],"population":[[-0.996452,-1.45672e-06],[-0.996448,2.6815e-07],[-0.99645,7.25043e-07],[-0.996449,-1.3416e-06],[-0.996455,7.31591e-07],[-0.99645,8.1581e-07],[-0.996449,5.1814e-07],[-0.996445,1.67192e-07],[-0.996449,4.5721e-07],[-0.99645,3.47383e-07],[-0.996447,6.91597e-07],[-0.99645,1.00039e-06],[-0.996448,1.11784e-06],[-0.99645,-7.96317e-08],[-0.996449,1.78636e-08],[-0.996448,1.26925e-06],[-0.996453,9.06472e-07],[-0.996446,-1.59413e-08],[-0.996453,-3.10283e-07],[-0.99645,1.91818e-06],[-0.996452,-1.31857e-06],[-0.996448,6.69267e-07],[-0.996449,-1.13703e-06],[-0.996445,8.11133e-08],[-0.996447,-2.1843e-07],[-0.996448,-3.17206e-07],[-0.99645,2.27729e-06],[-0.99645,-1.34819e-06],[-0.996447,-6.98735e-07],[-0.996453,8.39484e-07],[-0.996446,1.86622e-07],[-0.996447,-9.16701e-08],[-0.996446,4.33619e-07],[-0.996453,1.25383e-06],[-0.996449,-6.79954e-07],[-0.996449,-1.15054e-07],[-0.996451,-4.16521e-07],[-0.996451,7.1136e-07],[-0.996449,1.41518e-06],[-0.996451,9.73482e-07],[-0.996446,-2.30407e-06],[-0.996453,-8.59486e-07],[-0.99645,-1.47495e-06],[-0.996449,-5.14913e-08],[-0.996449,1.15028e-06],[-0.996449,3.58974e-07],[-0.996448,-1.62333e-07],[-0.996453,7.86625e-07]]}}, +{"best":0.358813,"evaluations":5784,"generation":332,"median":0.994959,"state":{"best":[-0.0158853,-0.012466],"population":[[-0.99645,9.3636e-08],[-0.996451,-3.29076e-08],[-0.99645,2.92127e-08],[-0.996451,9.92255e-08],[-0.996451,2.62704e-08],[-0.996451,3.76276e-08],[-0.99645,4.49195e-08],[-0.996451,3.2292e-08],[-0.99645,2.15145e-08],[-0.996451,-3.30571e-08],[-0.99645,-1.39704e-08],[-0.996451,-7.27497e-09],[-0.996451,8.5243e-08],[-0.996451,1.06786e-08],[-0.99645,1.29081e-07],[-0.99645,4.80734e-08],[-0.996451,-7.60245e-08],[-0.996451,-1.38635e-08],[-0.996451,-2.37562e-08],[-0.99645,3.41829e-08],[-0.996451,7.32298e-08],[-0.99645,-2.66924e-08],[-0.99645,-4.99263e-08],[-0.996451,2.86651e-09],[-0.996451,1.33477e-08],[-0.996451,5.06636e-08],[-0.99645,7.70372e-08],[-0.996451,-8.77227e-09],[-0.99645,-6.65946e-09],[-0.996451,4.39411e-08],[-0.99645,-1.19502e-08],[-0.996451,1.44053e-09],[-0.996451,3.46152e-08],[-0.996451,1.21095e-09],[-0.996451,-6.89051e-08],[-0.996451,-5.85197e-08],[-0.996451,-1.87499e-08],[-0.996451,1.76285e-08],[-0.996451,8.51433e-08],[-0.996451,-1.2104e-08],[-0.996451,8.78915e-08],[-0.99645,-4.73139e-09],[-0.99645,2.37513e-08],[-0.99645,3.55347e-08],[-0.996451,7.74981e-08],[-0.99645,-7.4811e-09],[-0.99645,5.83125e-08],[-0.99645,-1.56786e-08]]}}, +{"best":0.358813,"evaluations":5976,"generation":336,"median":0.994959,"state":{"best":[-0.0158853,-0.012466],"population":[[-0.996451,-2.23005e-09],[-0.996451,-2.90506e-09],[-0.996451,-3.60272e-09],[-0.996451,-3.83257e-09],[-0.996451,-4.33685e-09],[-0.996451,-4.99692e-10],[-0.996451,-1.60096e-09],[-0.996451,5.0242e-10],[-0.996451,-2.14246e-09],[-0.996451,-3.01102e-09],[-0.996451,-2.18679e-09],[-0.996451,8.51118e-10],[-0.996451,-9.90656e-10],[-0.996451,-6.04869e-09],[-0.996451,-1.69032e-09],[-0.996451,-1.4547e-09],[-0.996451,3.59134e-09],[-0.996451,2.54175e-09],[-0.996451,-9.85246e-10],[-0.996451,1.07052e-09],[-0.996451,3.47705e-09],[-0.996451,-2.3974e-09],[-0.996451,-5.78189e-09],[-0.996451,4.07462e-10],[-0.996451,-3.01903e-10],[-0.996451,-6.48062e-09],[-0.996451,-1.44532e-09],[-0.996451,6.39898e-10],[-0.996451,-1.09174e-09],[-0.996451,2.31381e-09],[-0.996451,-4.83777e-09],[-0.996451,1.62486e-09],[-0.996451,2.99622e-09],[-0.996451,-1.1477e-10],[-0.996451,-2.11458e-09],[-0.996451,-8.15533e-10],[-0.996451,-1.43384e-09],[-0.996451,6.41396e-10],[-0.996451,6.51151e-10],[-0.996451,1.28932e-09],[-0.996451,-3.71277e-09],[-0.996451,4.13453e-09],[-0.996451,5.69939e-10],[-0.996451,-3.50142e-09],[-0.996451,1.7292e-09],[-0.996451,-1.93905e-09],[-0.996451,-2.34754e-09],[-0.996451,-6.96487e-09]]}}, +{"best":0.358813,"evaluations":6168,"generation":340,"median":0.994959,"state":{"best":[-0.0158853,-0.012466],"population":[[-0.996451,3.83785e-10],[-0.996451,3.39265e-10],[-0.996451,2.00338e-10],[-0.996451,-3.21113e-10],[-0.996451,2.04562e-10],[-0.996451,-1.88397e-10],[-0.996451,2.13119e-10],[-0.996451,-5.82197e-10],[-0.996451,1.45016e-10],[-0.996451,-5.51044e-11],[-0.996451,-5.38752e-10],[-0.996451,1.17437e-10],[-0.996451,3.84421e-11],[-0.996451,-7.12532e-11],[-0.996451,-1.44054e-11],[-0.996451,-1.12673e-10],[-0.996451,-2.83792e-10],[-0.996451,1.90514e-12],[-0.996451,2.43868e-10],[-0.996451,-3.97825e-10],[-0.996451,-6.6775e-11],[-0.996451,8.8467e-11],[-0.996451,1.35541e-10],[-0.996451,-4.50605e-10],[-0.996451,-3.03126e-10],[-0.996451,-6.09806e-11],[-0.996451,-1.35733e-10],[-0.996451,7.31717e-11],[-0.996451,-2.02464e-10],[-0.996451,2.21869e-10],[-0.996451,4.3209e-11],[-0.996451,1.6438e-10],[-0.996451,8.01004e-11],[-0.996451,-1.38058e-11],[-0.996451,1.53833e-11],[-0.996451,2.5979e-10],[-0.996451,-1.23601e-10],[-0.996451,5.82645e-11],[-0.996451,-5.52296e-11],[-0.996451,-1.19277e-10],[-0.996451,-2.57909e-11],[-0.996451,-2.94815e-10],[-0.996451,-2.74188e-10],[-0.996451,-4.51655e-10],[-0.996451,2.73013e-10],[-0.996451,-2.11281e-10],[-0.996451,3.01712e-10],[-0.996451,-5.76668e-11]]}}, +{"best":0.358813,"evaluations":6504,"generation":345,"median":38.4612,"state":{"best":[-0.0158853,-0.012466],"population":[[0.898135,0.318723],[-0.0678464,0.15087],[-2.60592,-1.03992],[-0.176605,-0.229507],[-3.7007,2.89959],[-4.24121,-0.0556037],[-1.93529,-0.0829867],[0.030206,-0.0536613],[-2.56931,0.889213],[-2.54803,-1.58617],[1.36979,-1.29763],[-4.24229,2.23811],[-1.28905,-0.0853145],[-0.626683,0.204516],[-2.84231,0.114024],[1.16253,0.653663],[0.539003,0.562458],[-4.19145,-0.808721],[-2.17908,-0.261193],[-0.951917,-0.421962],[-1.46642,-0.524048],[-3.25549,1.8286],[-3.41963,-0.803138],[-2.39248,0.0611431],[-3.73915,0.841076],[0.214641,-0.562417],[-3.48834,-0.189849],[-3.63905,-1.70851],[-2.14403,0.976593],[-3.34625,-1.37876],[-2.69817,-0.818216],[-1.65459,-0.88959],[-4.27197,1.30982],[-2.90212,-0.135961],[-0.517331,0.514593],[-4.494,-0.109405],[-1.03788,0.123852],[-3.98737,0.612886],[-1.08306,-1.09899],[-0.585618,0.752008],[-2.81332,0.064343],[-2.45005,1.18753],[-1.37523,0.929054],[-3.74629,1.5818],[-2.63249,-0.741505],[-1.10915,0.182813],[-1.79266,-0.605391],[0.662953,0.279848],[2.7771,-2.35368],[-4.34527,-0.832729],[-1.93404,0.535349],[-1.77848,-2.29519],[-1.88997,0.668623],[-1.02587,0.261048],[-4.46404,1.0662],[-0.63264,-0.159448],[0.167883,1.30033],[-2.82576,1.32308],[-0.620287,-0.17767],[-0.496329,0.0138723],[-2.46481,2.66512],[-0.858839,-0.568789],[0.67309,0.696883],[0.440676,0.798846],[-0.150961,1.78869],[-1.12797,-0.0714523],[2.16594,0.0878825],[-3.09601,-0.307212],[-3.34554,-0.0608426],[-1.12227,0.647883],[-1.89888,1.56693],[-1.33799,2.04374],[0.425695,0.335434],[-0.774909,-1.17943],[-0.133599,-1.08257],[-1.43535,-0.543772],[-1.86583,-1.30837],[-1.3914,0.377957],[-4.73956,0.665023],[-0.674713,-0.171751],[-1.89349,-0.72389],[1.33006,-0.326508],[-1.08775,0.206872],[-1.4577,-1.26585],[-3.03004,0.557558],[0.152172,0.971459],[-1.26511,-0.666142],[1.65419,0.163687],[-0.779142,-0.171323],[-2.29229,-1.07033],[-1.61581,-1.7348],[-0.951805,-0.782808],[-2.2424,-0.98421],[-3.52358,-0.606047],[-0.486593,2.52782],[-0.510606,-0.408176]]}}, +{"best":0.358813,"evaluations":6888,"generation":349,"median":22.3129,"state":{"best":[-0.0158853,-0.012466],"population":[[-0.723107,-0.463478],[-2.14325,-0.252235],[-1.36948,-0.0790201],[-0.71823,-0.979298],[-0.988235,-0.507698],[-1.16065,-0.433571],[-1.6162,-0.192007],[-1.12046,-0.256604],[-2.00039,0.000900452],[-1.9205,-0.0153549],[-0.568704,-0.720663],[-1.08083,-0.799375],[-1.40176,-0.167432],[-1.24559,-0.318779],[-1.7864,-0.319564],[-1.91256,0.287796],[-1.31533,-0.080859],[-1.74202,-0.458879],[-1.04112,-0.410462],[-1.59538,-0.00369676],[-0.712996,-0.407536],[-1.75442,0.167359],[-1.43775,0.010533],[-0.495183,-0.315626],[-1.70079,0.0802627],[-2.40472,0.404233],[-1.94133,-0.214095],[-1.81001,0.183199],[-0.61228,-0.715325],[-1.49247,-0.28506],[-1.62004,0.03389],[-0.781502,-0.412749],[-1.02846,-0.228502],[-1.61157,-0.650175],[-0.701197,-0.288712],[-1.81442,-0.169245],[-1.4025,-0.083159],[-0.622125,-0.528873],[-0.740569,-0.33512],[-2.3425,-0.0847523],[-1.45513,-0.645862],[-1.40533,-0.012118],[-1.95528,-0.437525],[-0.895935,-0.402808],[-1.52003,-0.160477],[-0.611227,-0.282332],[-1.32146,-0.177119],[-1.8195,-0.301231],[-2.38656,0.089198],[-1.28991,0.473477],[-2.33347,0.309823],[-1.59831,-0.234305],[-1.73663,-0.568922],[-1.05964,-0.128222],[-1.90742,-0.141245],[-0.789627,-0.0146031],[-1.3625,-0.156653],[-1.17181,-0.00823009],[-1.50414,-0.307703],[-1.00212,-0.351399],[-2.59718,0.334591],[-1.70193,-0.229551],[-1.4195,-0.208343],[-1.21668,0.0450406],[-2.51151,-0.0349932],[-2.11002,-0.104642],[-1.65966,-0.435548],[-1.16874,-0.00769997],[-0.989721,-0.256954],[-1.21356,-0.311615],[-0.768643,-0.506349],[-1.09675,-0.213517],[-1.52738,-0.616666],[-1.59033,-0.372064],[-1.23262,-0.339362],[-0.746458,-0.418874],[-1.15536,-0.417287],[-0.891384,-0.395969],[-1.11853,-0.124017],[-0.582212,-0.407625],[-1.24085,0.200407],[-1.94126,0.384877],[-0.247805,-0.592928],[-1.51004,-0.0513845],[-1.42133,-0.113866],[-0.725655,-0.122545],[-2.06557,-0.350889],[-0.896805,-0.615039],[-1.20729,-0.129843],[-2.10003,0.0153599],[-2.00636,0.114396],[-1.2199,-0.157089],[-0.94309,-0.366509],[-2.16845,0.0354203],[-1.91715,-0.258392],[-1.95112,0.0562972]]}}, +{"best":0.358813,"evaluations":7272,"generation":353,"median":20.7288,"state":{"best":[-0.0158853,-0.012466],"population":[[-2.07699,0.0627375],[-1.56994,-0.170668],[-1.71816,-0.0150907],[-1.26849,-0.157076],[-1.43596,-0.237677],[-1.55935,-0.0563392],[-1.62688,-0.0430708],[-1.98446,0.00633046],[-1.57097,-0.127491],[-1.50533,-0.0777753],[-1.84498,-0.0809043],[-0.700957,-0.391124],[-2.33298,0.167678],[-1.43932,-0.217929],[-1.94021,-0.0157305],[-1.77398,0.0651881],[-1.55727,-0.0830361],[-2.14641,0.188895],[-2.32377,0.191916],[-1.84488,-0.0431748],[-1.66524,-0.0832467],[-1.70626,-0.0900802],[-1.98672,-0.0472787],[-2.62431,0.185708],[-1.26238,-0.220471],[-2.03488,0.0678115],[-0.880859,-0.35021],[-1.91741,0.0228067],[-1.82895,-0.104336],[-1.33174,-0.197319],[-1.85311,-0.106822],[-2.10337,-0.08234],[-1.73644,-0.0416535],[-1.36909,-0.147478],[-1.79205,-0.0201678],[-1.90161,0.022784],[-1.92712,-0.00338684],[-1.8452,-0.0846011],[-1.38888,-0.21402],[-1.48552,-0.0254218],[-1.34945,-0.171854],[-1.79942,-0.0466143],[-1.96031,0.000717349],[-1.39038,-0.15656],[-1.54525,-0.108586],[-2.40333,0.209563],[-0.996156,-0.443623],[-1.44833,-0.0782022],[-2.15824,0.103443],[-1.22471,-0.197754],[-1.48737,-0.0968659],[-1.07404,-0.196388],[-1.78509,-0.119234],[-0.981314,-0.267105],[-1.50289,-0.0317033],[-2.03352,0.0314168],[-1.83773,-0.0519387],[-0.992586,-0.378057],[-1.15547,-0.292479],[-1.98088,0.0838435],[-1.86423,-0.0320109],[-1.65449,-0.0594978],[-1.58976,-0.114923],[-2.07665,0.108804],[-1.91309,-0.0601258],[-1.95454,0.102794],[-2.02205,-0.0855996],[-1.45005,-0.139096],[-1.32275,-0.100728],[-0.953767,-0.406153],[-1.09056,-0.296338],[-1.82218,-0.00837459],[-1.87232,-0.0813786],[-1.08085,-0.260512],[-2.17221,0.119692],[-2.30875,0.203664],[-1.7899,0.0163947],[-2.09294,-0.0633709],[-1.65485,-0.09155],[-1.12143,-0.274068],[-1.56971,-0.217652],[-2.09246,0.0890566],[-2.30238,0.158767],[-1.4286,-0.142311],[-1.34227,-0.254649],[-0.948168,-0.299421],[-1.36157,-0.160999],[-2.15659,0.0330159],[-2.42341,0.291159],[-1.98193,0.0609873],[-1.43969,-0.210688],[-1.4721,-0.23116],[-1.34184,-0.182807],[-1.82663,-0.0369502],[-2.26943,0.0957333],[-1.30509,-0.199547]]}}, +{"best":0.358813,"evaluations":7752,"generation":358,"median":9.71657,"state":{"best":[-0.0158853,-0.012466],"population":[[-1.92107,0.0200896],[-1.81693,-0.0259795],[-1.66089,-0.086981],[-2.18095,0.0909383],[-1.75011,-0.0727634],[-1.82137,-0.0480895],[-2.14929,0.0606769],[-1.70269,-0.0562668],[-1.79713,-0.0621651],[-1.90472,0.0155842],[-1.83108,-0.0120999],[-1.92294,-0.00654409],[-1.95154,-0.0149767],[-1.79553,-0.0587097],[-1.76453,-0.0681972],[-1.72169,-0.0398656],[-1.95569,0.0248096],[-2.07416,0.0340746],[-2.16998,0.0748426],[-1.87122,-0.00464696],[-1.71195,-0.0828713],[-1.99541,-0.0321871],[-2.01781,0.021177],[-1.62631,-0.0759961],[-2.30765,0.101133],[-1.98427,0.0332087],[-2.43398,0.11602],[-1.7799,-0.0665218],[-1.75416,-0.036649],[-2.0879,0.0354377],[-1.56631,-0.121791],[-1.93999,0.01673],[-1.95998,0.00453519],[-2.02018,0.0389077],[-2.25016,0.0477455],[-1.81917,-0.0484188],[-1.51778,-0.135363],[-1.8975,0.00184329],[-2.44172,0.174697],[-1.94753,0.00690006],[-2.08024,0.0351903],[-1.86127,-0.0344431],[-1.97125,-0.0363828],[-2.07034,0.0235496],[-2.24818,0.0921218],[-1.61543,-0.14122],[-2.22213,0.0467948],[-2.06654,0.0305934],[-2.24044,0.117512],[-1.66381,-0.068665],[-1.95491,-0.00418722],[-1.9544,0.0325942],[-1.99566,0.0430415],[-2.26563,0.0860512],[-2.34546,0.186751],[-2.01939,0.00693536],[-1.95772,0.00260225],[-2.27085,0.0693231],[-1.58055,-0.113027],[-1.7868,-0.0260255],[-1.91503,-0.0472598],[-2.18761,0.0661262],[-1.7802,-0.0181776],[-2.0564,-0.00412799],[-2.10602,0.10112],[-1.85652,-0.00284561],[-2.17795,0.0749469],[-1.98564,0.00692205],[-1.70273,-0.0479106],[-1.7349,-0.0629272],[-1.80917,-0.0555776],[-1.86172,-0.0340675],[-2.06153,0.0572604],[-1.79475,-0.0305521],[-1.95823,0.01965],[-1.98016,0.0461542],[-2.06716,0.0257339],[-2.0951,0.074503],[-2.12984,0.0645592],[-2.20413,0.0966702],[-1.8345,0.0124552],[-1.97513,0.0251842],[-1.84692,0.0217237],[-1.59915,-0.0755747],[-2.12376,0.0379714],[-1.96252,0.0121948],[-2.86974,0.300729],[-2.0833,0.0145521],[-1.98756,0.0582422],[-1.94139,0.0282194],[-1.95032,-0.0132466],[-1.70683,-0.0650069],[-1.63258,-0.047775],[-1.78155,-0.0405611],[-1.95988,0.00536459],[-1.66703,-0.0734338]]}}, +{"best":0.358813,"evaluations":8136,"generation":362,"median":4.00458,"state":{"best":[-0.0158853,-0.012466],"population":[[-1.98694,0.00273374],[-1.95077,-0.00155718],[-1.97127,0.000604776],[-1.98642,0.00530717],[-1.94532,-0.0015932],[-1.94039,-0.00315328],[-1.95817,0.00123477],[-1.96221,0.00278491],[-1.93823,-0.00145808],[-1.96323,0.00206674],[-1.94579,0.000833668],[-1.95339,-0.00327389],[-1.96154,0.00123191],[-1.93679,-0.00172593],[-1.94434,-0.000597135],[-1.9411,-0.00242978],[-1.95783,-0.00171324],[-1.9633,0.000182008],[-1.98477,0.00319893],[-1.93356,-0.00172544],[-1.92702,-0.00424274],[-1.93182,-0.00552023],[-1.93258,-0.0021688],[-1.97422,0.000952869],[-1.9565,0.00065226],[-2.00526,0.00778392],[-1.94451,0.00149244],[-1.95379,-0.00040128],[-1.95828,0.0024911],[-1.97589,0.00222965],[-1.97547,0.00247079],[-1.95162,0.000128479],[-1.94607,-0.00380818],[-1.96873,-9.17449e-05],[-1.94805,0.000279164],[-1.95536,-0.00184731],[-1.94561,-0.0027735],[-1.96674,0.000887258],[-1.96935,0.00427949],[-1.96025,0.00400333],[-1.92608,-0.00345382],[-1.97001,0.00356764],[-1.9497,0.00174469],[-1.94198,0.0017721],[-1.93567,-0.000923805],[-1.95099,-0.00195986],[-1.95481,-0.00421989],[-1.95075,0.00204084],[-1.95927,0.00348165],[-1.94804,-0.000576662],[-1.94714,0.00139051],[-1.94705,0.00223476],[-1.93885,-0.00560571],[-1.96159,0.000811985],[-1.95541,-0.00229344],[-1.95241,-0.000141795],[-1.92786,-0.00109023],[-1.97169,-0.000385962],[-1.92178,-0.0026207],[-1.96725,-0.00175074],[-1.96663,0.00689521],[-1.97925,0.00230499],[-1.94982,0.000916791],[-1.95641,3.18642e-05],[-1.96792,0.0049425],[-1.92875,0.000484542],[-1.95773,-0.000212062],[-1.93157,-0.00015971],[-1.96904,0.000908181],[-1.9823,0.00537829],[-1.96034,0.000240099],[-1.95475,0.00213127],[-1.93054,-0.00112951],[-1.94591,-0.00106355],[-1.9668,-0.0021064],[-1.95946,0.000726758],[-1.98025,0.00296878],[-1.95593,-0.000582524],[-1.96879,0.00329374],[-1.94631,-0.00471768],[-1.97379,0.00437724],[-1.93111,-0.00188909],[-1.9401,-0.00175118],[-1.97552,0.00289425],[-1.9461,-0.000618258],[-1.95033,-0.00393719],[-1.956,-0.00086157],[-1.96044,0.000352624],[-1.93897,0.000747109],[-1.92985,-0.00407747],[-1.97164,0.00256968],[-1.98056,0.00128286],[-1.94422,0.00294542],[-1.94884,-0.000552221],[-1.94064,-2.92426e-05],[-1.95816,-6.10711e-05]]}}, +{"best":0.358813,"evaluations":8616,"generation":367,"median":3.97985,"state":{"best":[-0.0158853,-0.012466],"population":[[-1.95537,3.46463e-05],[-1.95564,-2.25621e-05],[-1.9556,2.53225e-05],[-1.95619,1.59041e-05],[-1.95645,3.05995e-05],[-1.95597,9.66472e-06],[-1.95621,9.01095e-05],[-1.95617,-3.50845e-05],[-1.95557,-4.36664e-06],[-1.95539,-2.84978e-05],[-1.9549,7.07666e-05],[-1.95471,9.3187e-06],[-1.95646,8.46584e-05],[-1.95546,5.78704e-05],[-1.95638,-7.01348e-05],[-1.95588,2.61644e-05],[-1.95636,0.000142433],[-1.95582,3.50107e-05],[-1.95524,0.000149913],[-1.95579,0.000141547],[-1.95514,-9.04026e-06],[-1.95562,-2.47458e-05],[-1.956,3.63648e-05],[-1.95594,3.47392e-05],[-1.95578,2.2487e-05],[-1.95517,4.38439e-05],[-1.95655,6.13556e-05],[-1.9552,1.68292e-05],[-1.95541,2.06241e-07],[-1.9557,9.24832e-05],[-1.95536,9.23404e-05],[-1.95556,1.11624e-05],[-1.95607,9.05206e-05],[-1.95503,7.01453e-05],[-1.95605,4.46744e-05],[-1.95568,0.000119771],[-1.95528,-3.71203e-06],[-1.95533,5.65701e-05],[-1.95524,-3.60105e-05],[-1.95438,-1.32693e-05],[-1.95557,5.52621e-05],[-1.95487,-2.59077e-05],[-1.95563,-5.95013e-05],[-1.95605,3.37249e-05],[-1.95553,-6.24692e-05],[-1.95631,-1.00943e-05],[-1.95569,-8.68986e-06],[-1.95628,4.20752e-05],[-1.95563,-0.000101531],[-1.95611,9.40269e-05],[-1.95525,-2.46425e-05],[-1.95521,7.22783e-05],[-1.95567,4.93089e-05],[-1.95494,5.01786e-05],[-1.95579,-3.87755e-05],[-1.95546,1.35427e-05],[-1.95516,8.47664e-05],[-1.95459,0.000101829],[-1.9558,2.83655e-05],[-1.95499,4.85239e-05],[-1.95578,7.4961e-05],[-1.95578,5.82544e-05],[-1.956,2.01899e-05],[-1.95545,-3.58787e-06],[-1.95612,-7.05739e-06],[-1.95576,2.0096e-05],[-1.95621,-4.19303e-05],[-1.95597,2.18749e-05],[-1.95558,0.000112239],[-1.95545,1.08388e-05],[-1.95489,0.000134817],[-1.95504,4.48189e-05],[-1.95534,6.0546e-05],[-1.9558,-4.19609e-05],[-1.95563,-3.71401e-05],[-1.95554,1.67237e-05],[-1.95526,-2.3111e-05],[-1.95436,2.32566e-05],[-1.95608,3.15334e-05],[-1.9561,2.49922e-05],[-1.95605,2.40041e-05],[-1.9555,0.000152395],[-1.95591,-3.41896e-05],[-1.95621,7.2122e-06],[-1.95628,-4.21477e-05],[-1.95631,1.6037e-05],[-1.95606,4.13796e-05],[-1.95555,0.000125952],[-1.95602,3.325e-05],[-1.95497,2.79274e-05],[-1.95597,1.48856e-06],[-1.95568,8.65736e-05],[-1.95622,0.000103684],[-1.95585,4.06501e-05],[-1.95603,-4.60166e-05],[-1.95465,-1.51542e-05]]}}, +{"best":0.358813,"evaluations":9000,"generation":371,"median":3.97983,"state":{"best":[-0.0158853,-0.012466],"population":[[-1.95586,-1.52331e-05],[-1.95581,1.13869e-05],[-1.95568,1.21578e-05],[-1.95613,-5.45157e-06],[-1.95596,-3.89383e-06],[-1.9557,3.17655e-06],[-1.95583,-9.63461e-06],[-1.9558,-1.34308e-05],[-1.95583,-1.35607e-05],[-1.95571,2.02156e-05],[-1.95592,-2.16241e-07],[-1.95582,2.95809e-06],[-1.95572,3.4911e-05],[-1.95576,2.8772e-06],[-1.95575,1.08349e-06],[-1.9559,1.28321e-05],[-1.95615,-2.31772e-05],[-1.95578,-2.07364e-06],[-1.95585,-2.92646e-06],[-1.95586,2.30632e-06],[-1.95588,3.39507e-06],[-1.95607,-3.88431e-05],[-1.95589,-1.19639e-05],[-1.9559,-1.10235e-06],[-1.95587,6.62959e-06],[-1.95575,-5.63001e-06],[-1.95602,-1.83341e-05],[-1.95569,-7.36804e-06],[-1.95572,-3.42274e-06],[-1.95585,-2.6694e-05],[-1.95594,-2.11596e-05],[-1.95576,1.10122e-05],[-1.95582,8.65044e-06],[-1.9559,2.07093e-07],[-1.95594,-9.91881e-07],[-1.95579,5.54467e-06],[-1.95601,-5.35945e-06],[-1.95601,-1.28716e-05],[-1.95591,-1.19547e-05],[-1.95594,-1.07489e-05],[-1.95586,7.86412e-07],[-1.95579,1.40204e-05],[-1.9558,-3.652e-06],[-1.95578,-1.0321e-06],[-1.95584,5.39392e-06],[-1.95598,-1.31641e-06],[-1.95607,-1.69523e-05],[-1.95584,-8.22038e-06],[-1.9557,1.43263e-05],[-1.95578,1.60667e-05],[-1.95589,1.30745e-05],[-1.9557,1.70594e-05],[-1.95577,-3.72759e-06],[-1.95582,-1.34761e-06],[-1.95588,1.42865e-06],[-1.95596,-1.10868e-05],[-1.95597,-1.36058e-06],[-1.95578,9.44964e-06],[-1.95582,1.56927e-05],[-1.95581,1.0995e-05],[-1.95587,-1.44971e-05],[-1.95598,6.06886e-06],[-1.95582,5.19356e-06],[-1.95583,1.99004e-05],[-1.95599,-5.26444e-06],[-1.95592,7.64595e-06],[-1.95599,2.5261e-06],[-1.95586,-1.30704e-05],[-1.95588,1.95949e-05],[-1.95588,-1.2911e-05],[-1.95602,-1.52285e-05],[-1.95597,-2.26862e-05],[-1.956,-4.90013e-06],[-1.95587,-7.81365e-06],[-1.95581,2.96868e-06],[-1.95589,-2.7514e-06],[-1.95588,-8.87262e-07],[-1.95594,-3.10608e-05],[-1.95566,-9.21865e-06],[-1.95594,-7.99245e-06],[-1.95601,-1.75206e-05],[-1.95578,1.46152e-05],[-1.95598,-1.18441e-05],[-1.95584,4.86005e-06],[-1.95585,3.7449e-08],[-1.95583,1.13159e-05],[-1.9558,-1.02949e-06],[-1.9559,5.6945e-06],[-1.95584,1.8016e-05],[-1.95586,9.02953e-06],[-1.95588,3.66382e-06],[-1.95587,1.25863e-05],[-1.95587,1.18826e-06],[-1.95592,-7.92274e-06],[-1.95571,6.24866e-06],[-1.95573,-6.88743e-06]]}}, +{"best":0.358813,"evaluations":9384,"generation":375,"median":3.97983,"state":{"best":[-0.0158853,-0.012466],"population":[[-1.95584,-6.66543e-07],[-1.95584,3.7998e-07],[-1.95584,-2.49561e-07],[-1.95584,2.33212e-07],[-1.95584,-8.95989e-07],[-1.95585,-7.12785e-07],[-1.95584,-7.18383e-07],[-1.95584,-3.75644e-07],[-1.95584,-1.96526e-08],[-1.95584,-2.56137e-07],[-1.95584,9.68162e-07],[-1.95585,1.36737e-07],[-1.95584,2.52998e-07],[-1.95584,1.79016e-06],[-1.95584,-5.77464e-07],[-1.95584,3.0255e-07],[-1.95584,1.1142e-06],[-1.95584,-2.34718e-07],[-1.95585,-1.50606e-06],[-1.95584,6.47342e-07],[-1.95584,-2.72648e-07],[-1.95584,2.9188e-08],[-1.95585,2.37944e-07],[-1.95585,-7.9103e-07],[-1.95584,-4.05461e-07],[-1.95584,1.05798e-06],[-1.95584,-7.2724e-07],[-1.95585,-1.3575e-06],[-1.95584,5.53785e-07],[-1.95585,2.09373e-07],[-1.95584,-2.87149e-07],[-1.95584,-2.9005e-07],[-1.95584,1.67019e-07],[-1.95584,-1.01404e-06],[-1.95584,8.09515e-07],[-1.95584,8.37656e-07],[-1.95584,-1.14095e-06],[-1.95584,-4.71763e-07],[-1.95584,2.11813e-07],[-1.95585,2.48353e-08],[-1.95584,-1.20921e-07],[-1.95584,7.61147e-07],[-1.95584,3.92095e-07],[-1.95584,-1.24965e-06],[-1.95584,-6.02278e-07],[-1.95584,3.12281e-07],[-1.95584,-4.99692e-07],[-1.95585,3.8748e-07],[-1.95584,1.75066e-06],[-1.95584,-3.33816e-07],[-1.95585,1.83991e-07],[-1.95584,-1.42507e-07],[-1.95584,7.22178e-11],[-1.95584,-6.21368e-07],[-1.95584,9.83272e-07],[-1.95584,-4.2461e-07],[-1.95584,-3.5145e-07],[-1.95584,1.49093e-07],[-1.95584,8.61693e-07],[-1.95584,8.73949e-07],[-1.95584,-4.76758e-07],[-1.95584,-1.20978e-07],[-1.95585,-2.12306e-06],[-1.95584,1.16867e-07],[-1.95584,-3.32831e-07],[-1.95584,2.41645e-07],[-1.95585,-6.80636e-07],[-1.95584,-3.67419e-07],[-1.95584,-1.46453e-07],[-1.95584,-1.16947e-06],[-1.95585,-8.49888e-07],[-1.95585,-9.72652e-07],[-1.95584,1.53701e-06],[-1.95584,2.40704e-07],[-1.95584,7.01454e-07],[-1.95584,-1.34269e-06],[-1.95584,1.12991e-06],[-1.95584,1.70333e-06],[-1.95584,1.87485e-06],[-1.95584,-3.49405e-07],[-1.95585,-1.04801e-06],[-1.95584,9.14085e-07],[-1.95585,-7.94412e-07],[-1.95584,-1.2196e-06],[-1.95584,-4.67151e-07],[-1.95584,1.2894e-07],[-1.95584,3.74982e-07],[-1.95584,4.05931e-07],[-1.95585,-1.16365e-06],[-1.95584,3.44983e-07],[-1.95584,-1.8495e-06],[-1.95584,-6.92272e-07],[-1.95584,-4.07398e-07],[-1.95584,-1.45996e-06],[-1.95584,-5.94943e-07],[-1.95584,-4.87221e-07]]}}, +{"best":0.358813,"evaluations":9864,"generation":380,"median":3.97983,"state":{"best":[-0.0158853,-0.012466],"population":[[-1.95584,1.57432e-09],[-1.95584,-1.64264e-09],[-1.95584,1.86503e-09],[-1.95584,1.56662e-08],[-1.95584,2.70459e-09],[-1.95584,-1.02718e-08],[-1.95584,-5.38125e-09],[-1.95584,1.76898e-08],[-1.95584,2.51485e-08],[-1.95584,4.07617e-09],[-1.95584,1.64913e-09],[-1.95584,5.22663e-09],[-1.95584,9.13824e-09],[-1.95584,1.55766e-08],[-1.95584,-7.2113e-10],[-1.95584,1.89865e-08],[-1.95584,8.36535e-09],[-1.95584,6.66024e-09],[-1.95584,5.83887e-09],[-1.95584,-1.01867e-08],[-1.95584,1.2426e-08],[-1.95584,-9.00492e-09],[-1.95584,1.11168e-08],[-1.95584,1.14117e-08],[-1.95584,1.70879e-08],[-1.95584,-3.64391e-09],[-1.95584,1.10398e-08],[-1.95584,2.4574e-09],[-1.95584,2.84684e-10],[-1.95584,-1.04604e-08],[-1.95584,7.28502e-10],[-1.95584,8.91632e-09],[-1.95584,-8.15485e-09],[-1.95584,3.27295e-10],[-1.95584,-7.43362e-09],[-1.95584,4.55733e-09],[-1.95584,3.18037e-09],[-1.95584,3.32963e-09],[-1.95584,1.99399e-09],[-1.95584,-7.93681e-09],[-1.95584,4.89438e-09],[-1.95584,-5.55904e-09],[-1.95584,-4.26816e-09],[-1.95584,-1.94866e-09],[-1.95584,2.30842e-08],[-1.95584,7.23884e-09],[-1.95584,1.27554e-08],[-1.95584,7.04912e-09],[-1.95584,6.22934e-10],[-1.95584,1.77227e-08],[-1.95584,1.38311e-08],[-1.95584,6.46974e-09],[-1.95584,-1.4866e-08],[-1.95584,8.43537e-10],[-1.95584,2.96985e-09],[-1.95584,1.05898e-08],[-1.95584,-1.96645e-09],[-1.95584,6.66557e-09],[-1.95584,9.94574e-09],[-1.95584,-1.14014e-08],[-1.95584,4.91467e-09],[-1.95584,1.44173e-08],[-1.95584,7.68449e-09],[-1.95584,1.09523e-08],[-1.95584,6.6658e-09],[-1.95584,1.32234e-08],[-1.95584,-3.22437e-09],[-1.95584,5.14604e-09],[-1.95584,-3.66653e-09],[-1.95584,8.71175e-09],[-1.95584,-5.14919e-10],[-1.95584,2.15563e-09],[-1.95584,9.35718e-10],[-1.95584,7.39267e-09],[-1.95584,1.38147e-11],[-1.95584,1.41685e-08],[-1.95584,1.04335e-08],[-1.95584,1.02534e-08],[-1.95584,8.80411e-09],[-1.95584,-9.55115e-09],[-1.95584,-3.91004e-10],[-1.95584,-3.451e-10],[-1.95584,-4.56345e-09],[-1.95584,-1.43729e-08],[-1.95584,7.72773e-09],[-1.95584,-4.15539e-09],[-1.95584,7.77487e-09],[-1.95584,1.08353e-08],[-1.95584,-1.35204e-08],[-1.95584,1.49256e-09],[-1.95584,1.58219e-08],[-1.95584,-4.01809e-09],[-1.95584,-3.48996e-10],[-1.95584,8.68062e-09],[-1.95584,-3.98352e-10],[-1.95584,1.07075e-08]]}}, +{"best":0.358813,"evaluations":10248,"generation":384,"median":3.97983,"state":{"best":[-0.0158853,-0.012466],"population":[[-1.95584,-6.86541e-10],[-1.95584,9.15788e-10],[-1.95584,-6.52302e-10],[-1.95584,8.49274e-10],[-1.95584,-2.05073e-10],[-1.95584,-3.82693e-10],[-1.95584,-1.81856e-10],[-1.95584,-6.94689e-11],[-1.95584,-1.817e-10],[-1.95584,-6.36148e-10],[-1.95584,-7.99323e-10],[-1.95584,4.78895e-10],[-1.95584,-2.63887e-11],[-1.95584,-1.09666e-09],[-1.95584,-3.87077e-11],[-1.95584,-4.34585e-10],[-1.95584,9.64241e-10],[-1.95584,-3.92672e-10],[-1.95584,-5.38086e-10],[-1.95584,3.99814e-11],[-1.95584,-9.81284e-10],[-1.95584,4.92298e-10],[-1.95584,-5.63736e-11],[-1.95584,8.52846e-10],[-1.95584,-3.57062e-10],[-1.95584,-1.5091e-10],[-1.95584,-2.85421e-10],[-1.95584,1.67649e-10],[-1.95584,5.63199e-10],[-1.95584,1.02733e-09],[-1.95584,2.075e-10],[-1.95584,-4.92736e-10],[-1.95584,-6.27574e-10],[-1.95584,-5.35674e-10],[-1.95584,3.43357e-10],[-1.95584,8.18021e-11],[-1.95584,2.79687e-10],[-1.95584,2.07834e-12],[-1.95584,5.30846e-10],[-1.95584,-2.92875e-10],[-1.95584,-2.76392e-10],[-1.95584,-2.88972e-10],[-1.95584,6.55227e-11],[-1.95584,-1.00209e-09],[-1.95584,-5.32319e-10],[-1.95584,-1.78329e-10],[-1.95584,-5.7052e-10],[-1.95584,-8.07684e-10],[-1.95584,-2.38438e-10],[-1.95584,3.5415e-10],[-1.95584,6.62848e-10],[-1.95584,1.12016e-09],[-1.95584,-5.43437e-10],[-1.95584,4.69484e-10],[-1.95584,-1.25599e-10],[-1.95584,-3.76384e-10],[-1.95584,-1.26994e-09],[-1.95584,8.25713e-10],[-1.95584,-7.80153e-10],[-1.95584,6.75441e-10],[-1.95584,6.41944e-10],[-1.95584,6.58183e-10],[-1.95584,9.4726e-11],[-1.95584,-1.5952e-10],[-1.95584,7.29425e-10],[-1.95584,4.78293e-11],[-1.95584,-4.49234e-10],[-1.95584,6.38897e-10],[-1.95584,6.36458e-10],[-1.95584,-8.11378e-10],[-1.95584,1.47843e-10],[-1.95584,1.38746e-10],[-1.95584,1.00336e-09],[-1.95584,-7.41523e-10],[-1.95584,7.95382e-10],[-1.95584,4.8804e-10],[-1.95584,-1.18908e-10],[-1.95584,2.32269e-10],[-1.95584,-2.88551e-10],[-1.95584,-6.62276e-10],[-1.95584,1.63949e-11],[-1.95584,7.89094e-10],[-1.95584,7.92833e-10],[-1.95584,-5.75164e-10],[-1.95584,-8.1303e-11],[-1.95584,7.12044e-11],[-1.95584,-3.77138e-11],[-1.95584,8.54064e-10],[-1.95584,-1.06569e-10],[-1.95584,-7.929e-10],[-1.95584,-6.25385e-10],[-1.95584,5.3956e-11],[-1.95584,1.04347e-10],[-1.95584,5.78938e-10],[-1.95584,-1.55636e-10],[-1.95584,1.47526e-10]]}}, +{"best":0.358813,"evaluations":10728,"generation":388,"median":708.93,"state":{"best":[-0.0158853,-0.012466],"population":[[2.11093,-1.39327],[0.919168,1.02924],[1.52543,-4.5401],[3.03546,-1.68021],[2.54975,-3.44076],[4.01292,-4.48704],[-0.0133595,-0.23556],[3.37354,3.8904],[4.37771,-0.938421],[1.7045,-1.66534],[1.97313,-0.837035],[1.36676,-4.79386],[2.29044,1.90421],[0.714813,-3.4147],[1.6369,-4.1885],[4.57525,-0.880601],[2.31066,-4.78714],[2.69756,-3.05284],[3.65667,-1.4515],[1.34265,-4.86357],[3.40076,-0.466372],[3.7098,-4.62854],[4.25608,-2.5419],[0.297252,-3.64233],[2.1045,-2.34644],[1.6713,-4.52908],[-1.53913,-4.64457],[2.72714,-3.41826],[-1.65663,-4.40383],[2.41492,-3.18953],[-0.0583123,-3.20718],[3.51303,-3.68065],[3.26746,-3.99782],[2.28687,-2.38838],[2.09421,-4.01088],[4.77844,0.0827323],[3.43146,-1.53954],[3.98393,-4.65726],[1.90765,-4.5433],[-3.02624,-2.86039],[4.9433,0.314865],[2.72348,-0.0719183],[4.85589,-3.48765],[4.21364,-1.6422],[3.65161,-0.585627],[2.69483,-2.4701],[4.85193,-1.48841],[2.30361,-2.63122],[1.75189,-3.71887],[2.17464,-3.92177],[4.54398,-4.78227],[2.25003,-2.85039],[0.0243351,-3.23814],[1.67035,-4.10412],[1.08273,0.415512],[0.27576,-0.624914],[1.75328,-3.33979],[3.91636,2.97575],[4.04663,-1.55575],[3.50315,2.99766],[3.34838,-2.6833],[-2.207,-4.94245],[3.4279,-4.23406],[0.126677,-1.54697],[2.86845,-4.5196],[3.7066,-3.72457],[0.900463,-3.58251],[2.41746,-3.76113],[3.90337,-3.50189],[4.65816,-2.85829],[4.47787,-0.813017],[3.60194,1.05644],[0.826954,-4.27212],[2.41726,3.64796],[1.88356,-4.41671],[-0.305391,-1.54328],[1.31334,2.76732],[4.95356,-0.836783],[2.21231,-3.82442],[4.09939,-4.0041],[4.55574,-1.9413],[-0.213515,-4.67698],[1.55916,-0.366825],[4.98256,1.23871],[1.52573,-1.40717],[3.57737,-2.35354],[1.67581,-2.76132],[4.00053,-0.670915],[3.40668,-3.93565],[1.3364,4.43211],[1.91404,-4.81624],[1.4089,-0.961611],[-0.562721,-4.13029],[-0.766452,-4.61849],[2.4741,-1.1124],[3.84128,-4.94234],[3.35263,-3.87429],[2.94355,-0.461695],[-3.71864,-4.74532],[1.99672,0.203336],[-1.24817,-3.24094],[3.08519,-0.344872],[-0.942815,-2.14266],[1.58438,1.43865],[-1.40621,3.64637],[4.70544,-3.42821],[1.89804,-1.49536],[1.77565,-3.2155],[3.91051,-0.428086],[-1.41288,-2.74923],[-0.516057,-2.46034],[4.5832,-1.03775],[-1.26196,-2.69966],[0.583025,-2.23226],[0.942248,-1.35429],[2.52768,-1.62309],[4.01884,-4.08435],[2.03789,1.75326],[2.73481,-2.80581],[2.34345,-1.81477],[2.85804,0.0937296],[2.82341,-2.9847],[-1.59023,-0.118729],[-1.59325,-1.63989],[2.64092,-0.599935],[-0.0128654,-1.71521],[2.39007,-3.08257],[3.59503,-2.91245],[1.33876,-1.05154],[0.834485,3.62371],[-0.63528,1.53737],[0.585654,-3.03456],[-2.23247,-3.53012],[4.0939,-4.44954],[1.90156,0.0698614],[4.7429,-2.29824],[-1.59027,-2.6346],[2.90663,2.14076],[2.03435,0.0544131],[0.115307,0.350401],[4.34052,-4.30905],[-1.26754,-3.15778],[0.913949,-2.59077],[-0.116003,-1.23285],[3.75997,2.25925],[2.83708,0.390035],[1.87221,-1.40507],[3.07093,-3.15021],[4.74541,-1.44951],[-1.14877,-3.4903],[-2.24788,-1.2341],[4.58294,-4.82143],[-1.44177,-2.65606],[-3.45074,-1.01073],[3.62394,-3.35887],[2.26116,-2.17756],[4.29435,-3.13407],[3.92544,-0.245654],[4.89755,-4.27971],[1.45785,-4.78487],[4.61293,-1.3468],[2.85371,-2.83107],[3.6793,-1.92406],[1.24592,-3.48754],[4.39697,-4.37213],[1.9849,0.302445],[0.0271128,-4.70944],[3.24061,4.21514],[2.93169,-2.74975],[0.320735,0.928639],[0.898254,-1.75114],[4.8759,-4.36591],[-0.468634,0.0605355],[0.498789,-3.15237],[3.36343,-2.24968],[4.61444,-3.43019],[2.66496,-4.94193],[-0.493592,-1.77882],[3.36465,-3.21591],[1.79111,-0.372929],[0.156608,-1.86269],[0.917459,-3.15077],[4.14914,-1.35248],[-0.605959,-1.36668],[3.84066,-4.98283],[3.19709,-4.78396],[3.67896,-1.04735],[4.73287,-2.8486],[3.28013,-4.19587],[3.57556,-4.19323],[4.85651,-2.25991],[4.178,-3.20106]]}}, +{"best":0.358813,"evaluations":11688,"generation":393,"median":24.1609,"state":{"best":[-0.0158853,-0.012466],"population":[[-0.706309,-0.476853],[-1.01496,-0.382993],[-1.51241,-0.3463],[-1.12775,-0.111094],[-1.6386,-0.244897],[-1.9324,0.416016],[-1.33966,-0.61852],[-2.38634,0.287003],[-3.69588,0.658469],[-2.61533,-0.47623],[-1.5714,0.324386],[-1.47942,-0.0432956],[-1.85318,0.517296],[-1.37849,0.197443],[-1.92643,-0.0789954],[-2.03521,0.165651],[-2.49629,0.945822],[0.0502958,-1.11383],[-1.10681,-0.467707],[-1.55661,0.00896465],[-2.57406,0.0473106],[-1.8757,-0.125938],[-1.20813,-0.357278],[-1.95941,0.0456504],[-0.787154,-0.771199],[-1.56922,0.243373],[-0.892337,0.0276561],[-2.41327,0.3079],[-2.60385,0.0385694],[-2.66482,-0.126574],[-1.68766,-0.916301],[-0.765902,-0.403052],[-2.51205,0.342846],[-2.24554,0.129583],[-1.26803,0.00761504],[-0.48458,-0.284123],[-2.52009,0.412043],[-1.17001,0.404366],[-0.631179,-0.299265],[-1.69528,-0.216268],[-1.84758,-0.161357],[-1.53965,0.120028],[-1.13104,-0.137469],[-1.15947,0.56489],[-0.432898,-0.495648],[-1.55444,-0.294466],[-1.75175,0.404799],[-0.903955,-0.819764],[-1.56156,-0.41481],[-2.05303,0.667144],[-1.82008,-0.0652034],[-3.26692,0.274937],[-0.849653,0.376957],[-0.327817,-0.790263],[-1.21803,-0.806207],[-1.54064,-0.507749],[-2.15971,-0.211565],[-0.769599,-0.53818],[-1.22754,-0.180438],[-0.65669,0.10777],[-1.07976,0.925154],[-1.48165,-0.614252],[-2.69514,0.353288],[-0.576118,-0.204914],[-1.62163,-0.271245],[-3.78688,-0.314614],[-2.05328,-0.185047],[-1.91677,0.554119],[-2.17418,0.0745899],[-1.62513,0.839218],[-2.02013,0.0965543],[-2.68751,0.564468],[-2.72294,-0.00322983],[-1.62515,-0.063912],[-1.83977,-0.663067],[-1.67591,-0.22483],[-0.444016,-0.218963],[-0.828035,0.170269],[-0.697941,-0.425961],[-1.20931,-0.0628597],[-1.97424,0.70795],[-0.859931,-0.586202],[-1.78829,0.38538],[-2.79955,0.617882],[-2.47942,1.46321],[-1.06178,-0.397014],[-1.57528,-0.232996],[-1.42716,0.611378],[-1.95891,0.016158],[-0.813223,0.457256],[-1.35125,0.433306],[-1.88906,0.413565],[-0.190829,-0.144055],[-1.83856,-0.0292935],[-2.61337,0.556356],[-0.963058,0.180516],[-0.835923,-0.556071],[-2.09155,0.185943],[-2.7359,-0.111907],[-2.16659,-0.275288],[-1.81716,0.499413],[-2.40956,-0.0131899],[-1.2286,-0.383216],[-1.76971,0.0182194],[-1.70915,-0.177027],[-1.42023,-0.0800959],[-1.73811,0.450366],[-0.841308,-0.776451],[-2.88171,-0.0748126],[-2.55536,0.159922],[-0.769833,-1.2907],[-0.662328,0.204988],[-0.871671,-0.826135],[-1.65821,-0.332717],[-1.09801,-0.200221],[-1.47532,0.516061],[-1.14083,-0.602239],[-2.0438,-0.227742],[-0.199735,-0.202498],[-2.81332,0.211723],[-2.05183,-0.0649139],[-1.05441,0.224903],[-2.45196,0.27999],[-0.435955,-0.664607],[-2.09643,-0.116446],[-2.01612,-0.31101],[-0.0331978,-0.431498],[-1.46889,-0.244438],[-1.98205,-0.0788668],[-1.77017,-0.198951],[-1.14396,-0.272848],[-1.37247,0.214314],[-1.56805,-0.372203],[-1.71245,-0.0585211],[0.434033,-0.573836],[-2.86625,0.549212],[-2.41874,0.331661],[-1.41622,-0.227927],[-2.61495,0.205793],[-0.700601,-0.423127],[-2.09862,0.201538],[-1.44507,-0.379672],[-1.03098,0.0752986],[0.644181,-1.00785],[-1.70425,-0.127837],[-0.784527,-0.591796],[-0.781668,-0.300981],[-2.65618,0.814039],[-2.67207,0.134308],[-2.05957,-0.00619587],[-1.48582,-0.381381],[-2.12671,-0.0373843],[-2.49052,0.4551],[-1.46321,0.279638],[-1.77049,0.823451],[-3.48292,0.854231],[-2.20595,0.0285415],[-0.728461,0.131395],[-1.08371,0.070688],[-1.2769,0.0478782],[-1.06362,-0.719857],[-0.917719,-0.202705],[-2.19557,-0.0162748],[-2.48844,0.575053],[-2.354,-0.206682],[-1.46577,-0.154681],[-1.45661,-0.265861],[-1.50016,0.372269],[-1.23263,0.661168],[-1.96464,-0.290844],[-2.26004,0.283967],[-1.9297,0.0800917],[-2.17411,0.574037],[-2.28829,-0.292558],[-0.734582,-1.02532],[-2.03601,-0.404335],[-1.43593,-0.234424],[-1.17422,0.453233],[-2.19175,0.0869439],[-1.61709,-0.682633],[-2.04741,-0.573974],[-2.78474,0.477567],[-2.19957,0.552342],[-1.09195,-0.336058],[-0.810096,-0.253501],[-1.60696,0.0834117],[-1.58899,-0.954686],[-1.61976,0.621996],[-1.42633,-0.450153],[-2.08682,0.129168],[-2.05534,0.729049],[-0.995921,-0.235091]]}}, +{"best":0.358813,"evaluations":12456,"generation":397,"median":19.0553,"state":{"best":[-0.0158853,-0.012466],"population":[[-2.33377,-0.0668612],[-1.80901,-0.233899],[-1.81684,-0.263165],[-2.36679,0.334949],[-1.63591,-0.353801],[-1.87294,-0.193528],[-1.72687,0.0328814],[-1.75985,-0.0238675],[-1.85664,-0.013819],[-1.47645,-0.137788],[-2.28972,0.0339372],[-1.79841,0.21814],[-1.62136,-0.0523129],[-1.95666,-0.103133],[-2.14571,0.365365],[-1.69575,-0.0867843],[-2.07465,-0.233477],[-1.65958,-0.391592],[-1.66898,0.300088],[-1.44183,-0.119553],[-2.04419,-0.145332],[-1.59376,-0.259185],[-1.47392,-0.437962],[-1.9266,0.152933],[-2.10289,0.167792],[-1.95582,-0.0105545],[-1.89369,0.31203],[-2.27276,-0.0258349],[-1.90037,-0.213926],[-2.16994,-0.00106789],[-1.79729,0.0814629],[-1.78213,0.00714846],[-1.94872,-0.0253681],[-2.12689,-0.268281],[-2.00976,-0.106276],[-1.11149,0.0323845],[-1.3337,0.337842],[-2.38898,0.0725657],[-1.74608,0.181694],[-1.96608,-0.15433],[-1.69747,-0.334911],[-1.75098,0.141826],[-2.31034,-0.0225793],[-1.88413,-0.0349397],[-2.04478,-0.0815408],[-1.55553,-0.276005],[-1.90085,0.05732],[-1.85343,-0.278954],[-1.53159,-0.198103],[-2.12889,0.0509588],[-1.12491,0.23962],[-1.67698,-0.00735766],[-1.95726,0.0564697],[-2.42046,-0.290977],[-1.52975,-0.298107],[-1.86495,0.0280305],[-1.63229,-0.580219],[-2.10346,0.436321],[-1.94998,0.236496],[-2.07448,0.227224],[-2.00737,-0.245217],[-2.22034,-0.385465],[-1.86767,0.186681],[-2.07287,-0.127984],[-2.07659,0.127673],[-1.87985,0.0191322],[-1.68798,0.32721],[-2.09033,0.18817],[-1.55932,0.110517],[-1.88637,0.246994],[-1.59313,-0.00496544],[-2.37864,0.0511702],[-1.67618,-0.149205],[-2.04467,-0.127272],[-1.76672,-0.190302],[-1.72886,-0.0416198],[-1.97385,-0.373528],[-1.75642,0.246924],[-2.0287,0.237498],[-2.36128,0.135401],[-1.64085,0.308773],[-1.38626,0.132523],[-1.60507,0.146842],[-1.7468,0.159906],[-1.56737,-0.0247685],[-1.83485,-0.112455],[-2.04998,0.478394],[-1.78578,0.121519],[-2.26574,0.130166],[-1.41088,-0.158604],[-2.09702,-0.0763204],[-1.94279,-0.190412],[-1.85505,0.38905],[-1.94746,0.311078],[-2.33086,-0.302691],[-1.57812,-0.294572],[-2.34196,0.22846],[-2.1286,-0.0272428],[-1.87852,0.0740749],[-2.13646,0.283069],[-1.64382,0.162369],[-2.5101,-0.0643372],[-2.05754,0.109706],[-1.69914,-0.161979],[-1.78934,0.174573],[-2.12277,-0.0432076],[-2.43796,0.166691],[-1.9849,0.116883],[-1.15165,-0.0757136],[-1.97197,-0.149443],[-1.75629,-0.268233],[-1.96049,-0.245129],[-1.69499,-0.159392],[-2.24609,0.124125],[-2.58746,0.112426],[-1.84119,-0.0736891],[-1.7096,0.5676],[-2.30418,0.0105692],[-2.12099,-0.208552],[-1.97557,0.379474],[-2.09126,-0.369809],[-2.17745,0.363446],[-2.2696,0.153055],[-2.28679,0.0324358],[-1.69624,-0.0432223],[-1.65088,-0.268339],[-1.76962,0.0276748],[-1.87216,0.25723],[-2.24185,-0.128531],[-1.88895,-0.237274],[-2.3839,0.176621],[-1.48996,0.418566],[-1.87708,0.254083],[-2.35011,0.18383],[-1.74523,0.183853],[-2.01369,0.114458],[-2.08679,-0.0757196],[-1.83859,-0.0664303],[-1.89638,0.0489177],[-1.84161,0.016626],[-1.97007,0.130243],[-1.81553,0.117931],[-2.21588,0.0683368],[-1.30618,-0.370474],[-1.55439,-0.417661],[-1.91843,-0.0982931],[-2.46948,-0.106488],[-1.73837,0.286878],[-1.49822,-0.1068],[-1.66206,-0.141081],[-1.8038,-0.00436139],[-1.83363,-0.218619],[-1.78725,0.275971],[-1.64646,-0.121284],[-1.50308,-0.205142],[-2.04342,0.0482522],[-1.99931,-0.0595084],[-1.88639,-0.144802],[-2.16765,-0.117858],[-1.94354,-0.107724],[-1.60639,0.131263],[-2.20962,0.282245],[-1.93101,0.00810549],[-2.41766,0.352314],[-1.80106,-0.171262],[-1.68461,0.0871766],[-1.61941,-0.322688],[-1.69031,0.14303],[-1.66169,-0.533517],[-2.20331,0.0268492],[-2.03794,-0.192842],[-1.88385,0.0129615],[-1.77513,-0.0348656],[-1.28151,-0.213409],[-1.94858,-0.0177673],[-1.80261,-0.138662],[-2.4086,0.212421],[-1.74653,0.118716],[-2.19592,-0.283952],[-2.06499,-0.303213],[-2.13561,-0.444272],[-1.82059,0.146125],[-1.89349,-0.665761],[-1.87731,0.235771],[-1.90733,0.497546],[-1.99284,0.0765124],[-1.75846,0.109532],[-1.92047,-0.105873],[-1.98337,0.113856],[-1.76695,0.436479],[-1.30325,-0.320454],[-1.84513,-0.238702]]}}, +{"best":0.358813,"evaluations":13224,"generation":401,"median":6.84654,"state":{"best":[-0.0158853,-0.012466],"population":[[-1.96342,-0.0549266],[-1.98981,-0.0312904],[-1.96046,-0.0254899],[-1.88423,0.00406884],[-1.85273,0.00561444],[-1.84539,-0.0203521],[-1.98112,-0.0482097],[-1.83242,-0.0198177],[-1.91118,-0.045481],[-1.96707,0.0215569],[-1.9756,-0.00270323],[-2.08771,0.0930488],[-1.89835,0.0159583],[-1.86495,0.0407948],[-1.94775,0.00219169],[-2.07521,0.00332669],[-1.99925,0.0982777],[-1.89281,0.00824512],[-1.96327,0.0497557],[-1.95014,0.0230534],[-1.94341,-0.0516916],[-1.85402,0.0258708],[-2.04674,-0.0704331],[-1.87597,-0.0720766],[-1.90936,0.0971271],[-1.98683,0.0723911],[-1.99185,-0.0239371],[-1.94475,-0.00130136],[-1.88719,-0.0367463],[-2.05919,0.0904685],[-1.90238,0.0437612],[-1.90095,0.0314511],[-2.02514,-0.0252296],[-2.01187,-0.0209565],[-1.93659,0.0543668],[-1.95631,-0.00619044],[-1.89145,-0.0497874],[-1.93377,0.0672403],[-1.93175,0.0359444],[-1.9599,0.00700552],[-2.0713,-0.0554413],[-2.00012,0.035131],[-1.98825,0.0508428],[-2.00758,0.0490819],[-1.94079,-0.0022901],[-2.07308,-0.0750845],[-1.95676,-0.0240981],[-1.94608,-0.0409375],[-1.90952,0.114061],[-1.95252,0.0637069],[-2.04022,0.0700163],[-2.08241,-0.0402073],[-1.95969,-0.0302536],[-1.92736,-0.0249314],[-1.94078,0.0530539],[-2.06811,-0.0133478],[-1.99643,0.0748882],[-1.96081,-0.117782],[-2.05926,0.0380448],[-1.87014,0.0253833],[-1.96228,0.0406734],[-1.94736,0.0768961],[-1.91611,0.0484511],[-2.02757,0.0290509],[-1.99502,-0.0187351],[-1.98877,0.0847299],[-1.95733,-0.0249044],[-1.88562,-0.0581526],[-1.8965,0.0670202],[-1.87821,-0.074993],[-2.00155,-0.035926],[-1.84856,-0.0164827],[-1.93863,-0.0695641],[-1.98536,0.0879092],[-1.94737,0.0634124],[-1.92143,0.0122886],[-1.96495,0.00635167],[-2.00051,0.0247244],[-1.9416,-0.000109706],[-2.06359,0.0850239],[-2.0357,-0.0211666],[-1.93627,0.0130678],[-1.90415,0.0669865],[-1.93079,0.0123733],[-1.96936,-0.0443651],[-1.94416,0.0795311],[-1.93815,0.00983154],[-1.87708,0.023528],[-1.92527,-0.013652],[-1.99449,-0.0390083],[-1.90209,-0.0394042],[-1.95722,0.0911688],[-2.06839,-0.00118143],[-1.88517,-0.0536525],[-2.04957,-0.0626699],[-1.85689,-0.036626],[-1.87732,0.020448],[-1.98283,-0.0220479],[-1.97393,-0.0270624],[-1.93263,-0.0277693],[-1.87001,0.066805],[-2.06939,0.00756557],[-1.91075,-0.00896295],[-2.05521,0.052366],[-1.99323,-0.0724117],[-2.02741,0.112936],[-1.91533,-0.00929006],[-1.96585,0.0260105],[-1.91768,0.0160742],[-1.89727,-0.00596894],[-1.94557,-0.024235],[-1.97389,0.00541246],[-1.89198,0.0351086],[-1.96405,-0.0267979],[-1.88231,-0.0235587],[-1.96869,0.0224844],[-1.92256,0.000426243],[-1.79563,-0.0223237],[-2.04199,-0.0204223],[-1.88666,0.00508034],[-1.97906,0.0240365],[-1.82282,-0.00114631],[-2.00561,0.0874819],[-1.86136,0.116986],[-1.96781,-0.00824953],[-1.98157,-0.0424968],[-1.79966,-0.03831],[-1.95185,0.0758241],[-1.97241,0.0597807],[-1.9781,-0.0363604],[-2.06467,0.0241232],[-2.01384,0.0197479],[-1.92648,-0.0231566],[-2.03941,0.0514475],[-1.95497,0.00469877],[-1.88395,-0.0283255],[-1.96828,-0.0555357],[-1.83256,0.0358019],[-2.02625,0.0334954],[-2.00439,-0.0803829],[-1.8996,-0.00632192],[-1.90357,-0.030003],[-1.93228,-0.00405144],[-1.88843,0.0457741],[-2.02302,0.0435996],[-1.86476,-0.00156059],[-1.96456,0.0503344],[-1.97817,0.00857087],[-1.94367,-0.0130535],[-1.88878,-0.0369016],[-2.06827,-0.0829018],[-1.8487,-0.0685072],[-1.87822,0.0228204],[-1.96196,0.112933],[-1.83157,-0.0377437],[-1.93266,-0.0441937],[-2.0274,-0.0133747],[-1.84313,0.0600302],[-1.94082,-0.0391469],[-2.0102,-0.0716886],[-2.01609,0.0658908],[-1.86238,-0.023418],[-1.89855,-0.0294619],[-1.86996,-0.0563613],[-1.90695,0.0833608],[-1.9525,0.079097],[-1.95152,0.0403973],[-1.96254,0.0141546],[-1.96214,0.0400152],[-1.90651,-0.0364035],[-1.90996,0.0358355],[-1.99902,0.0150091],[-1.84954,0.0423037],[-1.99071,0.0540587],[-2.03117,0.0509534],[-2.01149,-0.110945],[-2.07299,0.0135301],[-1.93358,-0.00128508],[-1.89959,0.0406163],[-1.95135,0.036527],[-1.97393,-0.0863376],[-1.76968,-0.0353838],[-1.94334,-0.00310531],[-1.91023,0.0367234],[-1.84886,0.0520754],[-1.99249,0.0483048],[-1.96853,0.00624074],[-1.96177,-0.0840496],[-1.89427,0.00354885],[-1.93458,0.026811],[-1.95087,-0.0870065],[-1.95512,0.037653]]}}, +{"best":0.358813,"evaluations":14184,"generation":406,"median":3.98127,"state":{"best":[-0.0158853,-0.012466],"population":[[-1.95436,-0.000474201],[-1.95807,-0.000858393],[-1.95263,0.000456191],[-1.95489,-0.000145679],[-1.95875,0.000255189],[-1.95504,-6.55445e-06],[-1.9595,8.47778e-05],[-1.95132,4.76348e-05],[-1.95629,-5.48165e-05],[-1.95749,-0.000173975],[-1.95375,0.000551604],[-1.95786,0.000303886],[-1.95487,0.000227729],[-1.95484,5.72764e-05],[-1.95642,0.000715616],[-1.95665,-9.75758e-05],[-1.95603,-9.75727e-05],[-1.96089,2.21511e-05],[-1.96006,0.000286225],[-1.95327,-0.000621134],[-1.95581,-0.00122722],[-1.95242,0.0005387],[-1.95394,-0.00030116],[-1.9549,0.000874897],[-1.95825,0.000758845],[-1.95506,-0.000263528],[-1.95917,-0.000724838],[-1.95619,0.000662247],[-1.95363,0.00105397],[-1.95542,0.000509133],[-1.95694,-0.000660296],[-1.95693,-0.000445328],[-1.95633,-0.00157545],[-1.96161,-0.000677663],[-1.95335,-0.000684033],[-1.95887,-0.000586705],[-1.95845,-8.18197e-05],[-1.95459,-0.000923994],[-1.95979,-0.000315954],[-1.95164,0.000303635],[-1.96103,7.93123e-05],[-1.9618,-0.000644405],[-1.9559,-0.00135483],[-1.95266,-0.000733175],[-1.95347,-0.000268046],[-1.95259,8.27299e-05],[-1.96098,-0.00109051],[-1.95354,0.00031086],[-1.95124,0.00131884],[-1.96186,-0.000548544],[-1.9528,7.04718e-05],[-1.95405,0.000921342],[-1.95313,-0.000186079],[-1.95398,0.0010732],[-1.9594,0.000812959],[-1.95548,-0.00114309],[-1.95288,-5.03347e-05],[-1.95398,0.000329311],[-1.95003,0.000231734],[-1.95888,9.95755e-05],[-1.95349,0.000443244],[-1.95342,-6.26069e-05],[-1.9549,0.000238382],[-1.95177,-0.000579126],[-1.95144,-0.000217779],[-1.95325,0.000343553],[-1.95938,-0.00101357],[-1.95172,-6.22559e-05],[-1.95586,0.000185812],[-1.95204,2.79304e-05],[-1.95969,-0.000647466],[-1.95754,-0.00079258],[-1.94681,3.92101e-05],[-1.95733,0.00107479],[-1.95574,-0.000341439],[-1.95445,4.22601e-05],[-1.95337,-0.000127403],[-1.95979,-0.000602583],[-1.95523,0.000594345],[-1.95905,-0.000894006],[-1.95831,0.000207769],[-1.95808,0.000689694],[-1.95747,-0.000384154],[-1.95567,0.000935368],[-1.95867,-0.000174972],[-1.95242,-0.001081],[-1.96066,0.000471774],[-1.95455,-0.00132532],[-1.94783,0.000161424],[-1.95579,0.000366407],[-1.95613,0.000359505],[-1.9544,-0.000910909],[-1.95922,-0.000355471],[-1.95369,-0.000144111],[-1.95201,0.000919798],[-1.95249,-0.0002347],[-1.95964,-0.000461695],[-1.95159,0.00105085],[-1.95697,-0.000269588],[-1.95586,0.000146631],[-1.95589,0.000102115],[-1.95588,0.000200425],[-1.95348,0.000759366],[-1.95778,0.000554554],[-1.95666,0.00133136],[-1.95066,0.00088499],[-1.95718,0.000412057],[-1.95632,0.000122602],[-1.95672,0.000626699],[-1.95482,0.000129151],[-1.95346,-0.00144513],[-1.95818,-0.000165746],[-1.95578,-0.00135692],[-1.95113,0.000892624],[-1.94878,0.00035546],[-1.95542,0.000687753],[-1.9616,-1.03747e-05],[-1.95152,-0.000209585],[-1.95757,-0.000154025],[-1.95461,0.000466106],[-1.95902,-0.000499649],[-1.95943,0.000240088],[-1.95219,0.00118469],[-1.95164,0.000620811],[-1.95418,-0.000780816],[-1.95466,-0.000648709],[-1.95728,-0.00105433],[-1.95349,-0.000287776],[-1.95499,-0.000653585],[-1.95815,0.000752097],[-1.95926,0.00112003],[-1.95852,-0.000433771],[-1.95829,0.000854682],[-1.95863,-0.000377589],[-1.9558,-0.000164367],[-1.95739,3.43079e-05],[-1.95286,0.000874345],[-1.95194,-0.000741298],[-1.95362,0.000221011],[-1.9571,-0.000182435],[-1.95459,-0.000257703],[-1.95929,-0.000421115],[-1.95833,0.000165993],[-1.95446,-0.000833233],[-1.95745,-0.00137774],[-1.9535,-0.000380225],[-1.95999,-1.0228e-05],[-1.95364,4.24184e-05],[-1.95206,-0.000230736],[-1.95591,1.94662e-05],[-1.95854,-0.00106622],[-1.95605,0.000645774],[-1.95565,-0.00112549],[-1.95197,0.000670724],[-1.95815,-0.000865952],[-1.95012,-0.000250525],[-1.95616,-4.62003e-05],[-1.95039,0.000449844],[-1.95066,-0.000291657],[-1.95433,-0.00091748],[-1.95215,0.000433628],[-1.95793,-0.000708916],[-1.95702,-0.000916151],[-1.94783,-0.0002345],[-1.95652,0.000240775],[-1.96259,-0.000230924],[-1.95949,0.000992407],[-1.95474,0.00136531],[-1.95819,0.000607561],[-1.95065,0.000122713],[-1.95572,4.91487e-05],[-1.95655,-0.000693201],[-1.9545,0.000315198],[-1.95782,0.000852449],[-1.9517,-0.000464229],[-1.9573,0.000438247],[-1.9608,-0.00125217],[-1.9568,0.000287694],[-1.95769,0.00119302],[-1.95579,-0.000794265],[-1.95783,-4.00624e-05],[-1.95538,0.000963317],[-1.95203,0.000592182],[-1.95676,-0.000425351],[-1.95176,-0.000517506],[-1.96218,0.00063732],[-1.95324,-0.000420344],[-1.956,-0.000348988],[-1.95743,1.13518e-05],[-1.95526,0.000786088],[-1.95872,-0.000686469],[-1.95313,5.43225e-05]]}}, +{"best":0.358813,"evaluations":14952,"generation":410,"median":3.97983,"state":{"best":[-0.0158853,-0.012466],"population":[[-1.95572,1.98587e-06],[-1.95581,3.80834e-06],[-1.95565,1.08335e-05],[-1.95586,2.17677e-05],[-1.95583,-1.38535e-05],[-1.95593,-2.99803e-05],[-1.95578,2.96286e-05],[-1.95586,-1.46879e-05],[-1.95563,3.21284e-05],[-1.95588,-5.79696e-05],[-1.95589,-2.29861e-05],[-1.95587,-8.89899e-06],[-1.95571,2.20483e-05],[-1.9559,3.04573e-06],[-1.95583,-3.43747e-05],[-1.95551,1.93405e-05],[-1.95577,7.97458e-06],[-1.95593,3.99159e-06],[-1.95571,-3.03857e-05],[-1.95582,-5.73823e-06],[-1.9557,-7.1381e-06],[-1.95594,-2.80123e-05],[-1.95618,1.02926e-05],[-1.95597,-2.69072e-05],[-1.95557,2.82215e-05],[-1.95564,-8.51769e-06],[-1.95573,2.90707e-05],[-1.95565,7.0056e-06],[-1.95589,-7.92071e-05],[-1.95602,-2.5565e-05],[-1.95574,6.74069e-06],[-1.95548,2.24875e-05],[-1.9558,2.23898e-05],[-1.9559,-4.19886e-05],[-1.95605,1.07169e-05],[-1.95601,-3.97329e-05],[-1.95591,-1.06871e-05],[-1.95579,-1.19898e-05],[-1.95581,-3.46012e-05],[-1.95593,-1.83031e-06],[-1.95582,-7.21615e-07],[-1.9559,2.95382e-06],[-1.95601,-1.11889e-06],[-1.95568,1.23142e-05],[-1.95588,-1.39678e-05],[-1.95596,-2.96683e-05],[-1.95572,-2.34624e-06],[-1.95572,2.31818e-05],[-1.95594,-2.06258e-06],[-1.95578,-2.18738e-05],[-1.95587,-7.14013e-06],[-1.95564,6.46982e-05],[-1.95582,1.145e-05],[-1.95575,1.17499e-05],[-1.95595,-1.73816e-05],[-1.95572,4.46745e-06],[-1.95597,1.23733e-05],[-1.9557,5.37396e-05],[-1.95569,-1.5384e-05],[-1.95577,-6.86616e-06],[-1.95578,3.06572e-05],[-1.95588,-5.0781e-06],[-1.95581,4.78744e-06],[-1.95592,1.41956e-05],[-1.95594,2.61823e-05],[-1.95576,-1.1502e-05],[-1.9561,-2.30757e-05],[-1.95598,-3.5763e-05],[-1.95593,-2.19868e-06],[-1.9557,3.31996e-05],[-1.9557,-1.22917e-05],[-1.95599,-2.80035e-05],[-1.95573,2.08366e-05],[-1.95558,5.85381e-05],[-1.95574,1.94745e-05],[-1.95601,2.48874e-05],[-1.95586,2.29078e-06],[-1.95577,2.89929e-05],[-1.95591,3.63068e-05],[-1.95577,8.08379e-06],[-1.95588,2.68137e-05],[-1.95577,4.01298e-06],[-1.95608,-2.72129e-05],[-1.95598,2.06311e-05],[-1.95579,4.00293e-05],[-1.95593,1.20473e-05],[-1.95581,3.10039e-05],[-1.95567,-1.40953e-06],[-1.95544,3.12476e-05],[-1.9558,8.82309e-06],[-1.95585,-3.40369e-06],[-1.95588,1.63437e-05],[-1.95574,1.59022e-07],[-1.95571,3.21333e-05],[-1.95591,4.19242e-05],[-1.95586,5.60531e-06],[-1.95583,-3.08208e-05],[-1.95609,-4.51339e-05],[-1.95575,5.69524e-06],[-1.95585,4.2833e-06],[-1.9558,2.05769e-05],[-1.95564,4.07113e-05],[-1.9559,2.27309e-06],[-1.95573,9.14924e-06],[-1.95594,-1.02466e-05],[-1.95557,-4.16711e-06],[-1.95568,-6.90024e-06],[-1.95582,1.76441e-05],[-1.95625,2.15037e-06],[-1.95562,1.58778e-05],[-1.95576,5.79274e-06],[-1.95565,-3.05969e-05],[-1.95581,-4.82259e-06],[-1.95577,-2.20529e-06],[-1.9558,2.47654e-05],[-1.95597,-1.60689e-05],[-1.95594,-3.59161e-07],[-1.95572,3.70789e-05],[-1.95577,-1.06035e-05],[-1.95591,3.3419e-05],[-1.95617,-4.14124e-05],[-1.95593,-6.42133e-06],[-1.95599,-2.48098e-05],[-1.95583,1.14545e-05],[-1.95585,-1.74307e-06],[-1.95572,3.68651e-05],[-1.95595,-4.4542e-06],[-1.95574,1.24797e-05],[-1.9558,1.10006e-05],[-1.95583,-1.25933e-05],[-1.95593,-1.92651e-05],[-1.95581,-1.4234e-05],[-1.9558,3.12677e-05],[-1.95608,-1.85908e-05],[-1.95583,1.22772e-06],[-1.95591,-1.12394e-05],[-1.95576,2.56385e-05],[-1.95572,1.08549e-05],[-1.95612,-3.32845e-05],[-1.95589,-2.43837e-06],[-1.95601,-2.91254e-05],[-1.95565,-1.32507e-05],[-1.95611,-5.9773e-05],[-1.95607,-3.80639e-05],[-1.95583,-3.34929e-05],[-1.95596,-1.36597e-05],[-1.95584,7.88917e-07],[-1.95564,3.28918e-06],[-1.95593,-3.96376e-05],[-1.95557,-2.24026e-05],[-1.95579,5.17802e-06],[-1.95595,-1.52916e-07],[-1.95578,-5.23582e-05],[-1.95564,2.59088e-05],[-1.95574,-3.90696e-06],[-1.95579,3.55195e-05],[-1.95577,9.13119e-07],[-1.95583,-1.82469e-06],[-1.95577,5.32163e-07],[-1.95591,8.13955e-06],[-1.95573,-6.17816e-06],[-1.95593,3.04909e-05],[-1.95558,3.49725e-06],[-1.9558,-1.94609e-05],[-1.95597,1.60469e-05],[-1.95577,-1.23603e-05],[-1.95597,3.33679e-06],[-1.95597,-5.1899e-05],[-1.95583,-9.42834e-06],[-1.95603,-9.41024e-06],[-1.95602,1.3436e-05],[-1.95583,-9.36733e-06],[-1.95578,5.63978e-05],[-1.95556,7.78139e-06],[-1.95582,3.98186e-05],[-1.95595,-1.31259e-05],[-1.95599,-1.90525e-05],[-1.9558,-2.72635e-05],[-1.95568,-6.08977e-06],[-1.95595,8.45668e-06],[-1.95606,-5.20014e-05],[-1.95593,-1.35811e-05],[-1.95598,-3.3415e-05],[-1.95584,-3.24824e-06],[-1.95589,3.46503e-05],[-1.95594,-1.23672e-06],[-1.95576,4.41952e-06],[-1.95593,1.17039e-05],[-1.95569,1.54705e-05],[-1.95582,2.9312e-05],[-1.95575,7.02864e-06],[-1.95581,-2.45588e-05]]}}, +{"best":0.358813,"evaluations":15912,"generation":415,"median":3.97983,"state":{"best":[-0.0158853,-0.012466],"population":[[-1.95584,-1.72134e-07],[-1.95584,-1.72396e-07],[-1.95584,-1.01275e-07],[-1.95585,-8.8225e-07],[-1.95585,-2.91347e-07],[-1.95585,-1.46563e-07],[-1.95584,-3.30553e-07],[-1.95584,-3.78626e-07],[-1.95584,-1.24299e-07],[-1.95584,1.64873e-07],[-1.95583,5.76375e-07],[-1.95584,-1.36231e-08],[-1.95585,-2.32285e-07],[-1.95584,8.21772e-07],[-1.95584,5.81729e-07],[-1.95584,2.8443e-07],[-1.95584,-3.16422e-07],[-1.95585,4.15569e-08],[-1.95584,-9.00295e-07],[-1.95584,5.14813e-07],[-1.95584,4.43594e-07],[-1.95584,-1.37519e-07],[-1.95584,-1.79291e-07],[-1.95585,-3.49321e-07],[-1.95584,-4.44216e-07],[-1.95583,-9.99984e-07],[-1.95584,4.21571e-07],[-1.95585,-5.24961e-07],[-1.95584,5.52645e-07],[-1.95583,3.61064e-07],[-1.95585,6.30669e-09],[-1.95584,-8.21613e-08],[-1.95584,-2.90328e-07],[-1.95584,-1.6631e-07],[-1.95584,3.32372e-07],[-1.95584,-2.2323e-07],[-1.95584,7.75157e-07],[-1.95585,-3.64671e-07],[-1.95585,4.92632e-08],[-1.95585,1.44185e-06],[-1.95585,-3.10346e-07],[-1.95584,8.26842e-08],[-1.95584,-8.31526e-07],[-1.95585,1.45249e-07],[-1.95584,-8.39071e-07],[-1.95585,7.24232e-08],[-1.95583,6.43943e-07],[-1.95584,2.82373e-07],[-1.95584,-1.16372e-06],[-1.95584,-2.254e-07],[-1.95584,1.35331e-07],[-1.95584,-1.12571e-06],[-1.95585,8.8951e-08],[-1.95584,1.71243e-07],[-1.95584,2.19073e-07],[-1.95584,2.63662e-07],[-1.95584,-9.94706e-08],[-1.95584,3.20797e-07],[-1.95584,-2.77137e-07],[-1.95584,-7.58512e-07],[-1.95584,8.24992e-07],[-1.95584,-1.87108e-07],[-1.95584,1.46368e-07],[-1.95585,-1.39243e-08],[-1.95585,-4.23216e-07],[-1.95584,-4.9365e-07],[-1.95584,-2.83166e-08],[-1.95584,-1.57083e-07],[-1.95584,5.713e-07],[-1.95584,1.41765e-07],[-1.95585,7.74146e-07],[-1.95584,-2.24662e-07],[-1.95584,9.10006e-09],[-1.95584,-6.48427e-07],[-1.95584,-3.29644e-07],[-1.95584,5.7302e-07],[-1.95585,-1.4263e-08],[-1.95584,5.46308e-07],[-1.95584,-1.7886e-07],[-1.95584,2.51417e-07],[-1.95585,2.52278e-07],[-1.95584,-1.53109e-07],[-1.95584,-3.05211e-08],[-1.95585,-2.96394e-07],[-1.95585,4.22786e-07],[-1.95584,-9.14772e-07],[-1.95585,4.59065e-07],[-1.95584,-2.74179e-07],[-1.95584,-5.76463e-07],[-1.95585,6.14655e-07],[-1.95585,-4.94037e-07],[-1.95584,-3.36131e-07],[-1.95584,4.40523e-08],[-1.95584,-5.73764e-07],[-1.95583,2.0102e-07],[-1.95584,-2.74714e-07],[-1.95585,-4.94659e-07],[-1.95584,-3.65256e-07],[-1.95584,2.6716e-07],[-1.95584,-2.0125e-07],[-1.95585,-7.43042e-07],[-1.95585,-1.17112e-06],[-1.95584,-6.39141e-07],[-1.95585,-4.37923e-07],[-1.95585,-3.58928e-07],[-1.95585,-1.01787e-06],[-1.95584,-3.75583e-07],[-1.95584,4.28118e-07],[-1.95584,1.66752e-07],[-1.95584,-8.05051e-08],[-1.95584,-7.46528e-07],[-1.95584,2.51943e-08],[-1.95584,-3.80947e-08],[-1.95585,-8.96668e-07],[-1.95584,-7.71751e-07],[-1.95584,-5.62859e-07],[-1.95584,1.53796e-07],[-1.95585,-6.84258e-07],[-1.95584,-3.15545e-08],[-1.95584,-6.69711e-07],[-1.95585,-9.11425e-07],[-1.95585,2.76195e-07],[-1.95584,-7.14442e-08],[-1.95584,-1.36459e-07],[-1.95584,1.98868e-07],[-1.95585,9.89737e-08],[-1.95585,1.90447e-07],[-1.95584,-4.6165e-07],[-1.95584,8.71758e-07],[-1.95585,-2.62437e-07],[-1.95584,-5.22466e-07],[-1.95584,-3.37798e-07],[-1.95584,-3.28914e-07],[-1.95585,-7.10763e-07],[-1.95585,-1.1741e-06],[-1.95585,2.77769e-07],[-1.95585,2.37098e-08],[-1.95585,-4.19858e-07],[-1.95584,-1.88771e-07],[-1.95585,-5.71449e-07],[-1.95584,3.71787e-07],[-1.95585,3.7073e-07],[-1.95584,-7.19687e-07],[-1.95584,-4.10406e-07],[-1.95585,-7.89896e-07],[-1.95584,-3.86052e-07],[-1.95584,-8.85517e-07],[-1.95584,1.0713e-06],[-1.95585,-6.31397e-07],[-1.95584,-1.33826e-07],[-1.95584,-1.1958e-07],[-1.95584,2.44707e-07],[-1.95584,3.04622e-07],[-1.95584,-7.75993e-07],[-1.95583,-1.2435e-07],[-1.95585,9.53356e-08],[-1.95585,-4.92725e-07],[-1.95584,2.91671e-08],[-1.95584,8.12586e-07],[-1.95584,2.49717e-07],[-1.95584,-2.29047e-07],[-1.95584,1.55695e-07],[-1.95584,4.55459e-07],[-1.95584,2.29136e-07],[-1.95585,-6.23897e-07],[-1.95583,1.9012e-07],[-1.95584,5.71158e-07],[-1.95584,-1.71509e-07],[-1.95584,4.23489e-07],[-1.95584,7.77794e-07],[-1.95585,1.75683e-07],[-1.95585,1.55068e-08],[-1.95584,-4.00436e-07],[-1.95584,2.37543e-07],[-1.95584,8.46645e-07],[-1.95584,6.09229e-09],[-1.95585,-1.12479e-07],[-1.95584,-4.86915e-07],[-1.95584,4.33698e-07],[-1.95584,1.63631e-07],[-1.95584,3.80523e-07],[-1.95584,6.08522e-07],[-1.95584,1.02799e-07],[-1.95584,-1.22637e-07],[-1.95583,1.04731e-06],[-1.95585,-3.19262e-07],[-1.95584,2.74091e-07],[-1.95584,3.87041e-07],[-1.95584,-5.53012e-07],[-1.95584,-1.56863e-07],[-1.95585,3.97246e-07],[-1.95584,1.2717e-09]]}}, +{"best":0.358813,"evaluations":16680,"generation":419,"median":3.97983,"state":{"best":[-0.0158853,-0.012466],"population":[[-1.95584,1.29285e-08],[-1.95584,-6.35188e-08],[-1.95584,-4.42529e-08],[-1.95584,-3.99671e-08],[-1.95584,-5.62366e-08],[-1.95584,2.80318e-08],[-1.95584,-1.24098e-08],[-1.95584,1.50672e-08],[-1.95584,-8.57727e-08],[-1.95584,7.43996e-09],[-1.95584,-3.64327e-10],[-1.95584,-3.74935e-08],[-1.95584,1.4209e-08],[-1.95584,-7.33594e-08],[-1.95584,2.38165e-08],[-1.95584,-8.54719e-09],[-1.95584,-6.93712e-08],[-1.95584,-1.41546e-08],[-1.95584,1.04573e-08],[-1.95584,-6.86548e-09],[-1.95584,1.39951e-08],[-1.95584,2.0984e-08],[-1.95584,2.30759e-08],[-1.95584,-9.18913e-09],[-1.95584,3.67631e-08],[-1.95584,2.88751e-10],[-1.95584,-9.46249e-09],[-1.95584,1.1203e-08],[-1.95584,-2.96318e-08],[-1.95584,1.13221e-08],[-1.95584,-5.55288e-08],[-1.95584,-6.50434e-08],[-1.95584,-3.52268e-08],[-1.95584,1.2428e-08],[-1.95584,4.94925e-08],[-1.95584,-7.46222e-08],[-1.95584,6.47334e-09],[-1.95584,-4.57639e-10],[-1.95584,-4.42549e-08],[-1.95584,-2.12344e-08],[-1.95584,-5.20417e-08],[-1.95584,-3.4751e-08],[-1.95584,-5.91553e-08],[-1.95584,-2.40904e-08],[-1.95584,-5.5974e-08],[-1.95584,2.51389e-08],[-1.95584,-1.91e-08],[-1.95584,-3.68669e-09],[-1.95584,-2.50376e-08],[-1.95584,-8.45242e-08],[-1.95584,1.43299e-08],[-1.95584,2.36871e-08],[-1.95584,-3.43429e-09],[-1.95584,-4.274e-09],[-1.95584,-8.53309e-09],[-1.95584,-5.42258e-09],[-1.95584,-4.92943e-08],[-1.95584,-8.50124e-09],[-1.95584,-5.93302e-08],[-1.95584,-2.15556e-08],[-1.95584,-1.92403e-09],[-1.95584,-2.65733e-08],[-1.95584,-5.18719e-08],[-1.95584,-3.49348e-08],[-1.95584,3.27087e-09],[-1.95584,3.47629e-08],[-1.95584,-5.86052e-08],[-1.95584,-1.88821e-08],[-1.95584,-1.21065e-08],[-1.95584,4.08991e-08],[-1.95584,-2.62194e-08],[-1.95584,-1.24523e-09],[-1.95584,-2.98248e-09],[-1.95584,-7.12957e-09],[-1.95584,-4.73042e-08],[-1.95584,-1.22678e-08],[-1.95584,9.35309e-09],[-1.95584,-6.68763e-08],[-1.95584,2.26237e-08],[-1.95584,-3.99841e-08],[-1.95584,1.05462e-09],[-1.95584,-7.48341e-09],[-1.95584,1.09828e-09],[-1.95584,2.60613e-08],[-1.95584,-6.38847e-08],[-1.95584,-2.57115e-08],[-1.95584,-3.5144e-08],[-1.95584,3.45615e-08],[-1.95584,6.17503e-09],[-1.95584,4.50364e-09],[-1.95584,-7.92017e-09],[-1.95584,-1.54246e-08],[-1.95584,-4.32493e-08],[-1.95584,-2.3828e-08],[-1.95584,-9.94145e-10],[-1.95584,-3.54236e-08],[-1.95584,-5.86569e-08],[-1.95584,-1.30138e-08],[-1.95584,-1.19704e-09],[-1.95584,-6.05177e-08],[-1.95584,-1.81302e-08],[-1.95584,1.07337e-08],[-1.95584,-6.78066e-10],[-1.95584,2.35353e-09],[-1.95584,-2.05551e-08],[-1.95584,-1.49941e-08],[-1.95584,-5.33717e-08],[-1.95584,1.93033e-08],[-1.95584,2.00213e-08],[-1.95584,6.21211e-08],[-1.95584,3.97927e-09],[-1.95584,1.35641e-08],[-1.95584,-1.29535e-08],[-1.95584,-4.24574e-08],[-1.95584,-2.66088e-08],[-1.95584,6.39626e-08],[-1.95584,-3.13576e-08],[-1.95584,-3.87101e-09],[-1.95584,-5.6508e-09],[-1.95584,1.11894e-08],[-1.95584,3.40528e-12],[-1.95584,-5.03485e-08],[-1.95584,-5.13324e-08],[-1.95584,1.53497e-08],[-1.95584,-4.17397e-09],[-1.95584,-2.42997e-08],[-1.95584,2.42732e-08],[-1.95584,2.4684e-08],[-1.95584,-1.91487e-08],[-1.95584,6.93995e-09],[-1.95584,-4.40723e-08],[-1.95584,2.58845e-08],[-1.95584,1.63996e-08],[-1.95584,3.8179e-08],[-1.95584,-2.56586e-08],[-1.95584,-4.21086e-08],[-1.95584,-3.94431e-08],[-1.95584,6.04064e-08],[-1.95584,2.59933e-08],[-1.95584,-2.32069e-08],[-1.95584,1.44791e-08],[-1.95584,-1.65116e-08],[-1.95584,2.73899e-08],[-1.95584,-1.09226e-08],[-1.95584,-3.20146e-08],[-1.95584,-5.86718e-08],[-1.95584,-3.2724e-08],[-1.95584,-3.16507e-08],[-1.95584,-3.28991e-08],[-1.95584,-2.52672e-08],[-1.95584,-7.19825e-09],[-1.95584,2.06765e-09],[-1.95584,-5.90993e-08],[-1.95584,-1.42284e-08],[-1.95584,-1.08262e-09],[-1.95584,1.06535e-08],[-1.95584,1.87856e-08],[-1.95584,-5.05399e-08],[-1.95584,-7.1959e-08],[-1.95584,-2.3652e-08],[-1.95584,-8.97924e-09],[-1.95584,-3.44646e-08],[-1.95584,8.61497e-10],[-1.95584,1.68004e-08],[-1.95584,-3.29646e-08],[-1.95584,-2.10546e-08],[-1.95584,-2.85615e-08],[-1.95584,-6.38659e-09],[-1.95584,8.60005e-09],[-1.95584,8.09212e-09],[-1.95584,3.59338e-08],[-1.95584,-1.57387e-08],[-1.95584,2.31717e-08],[-1.95584,2.92838e-09],[-1.95584,-2.11525e-08],[-1.95584,-5.82464e-09],[-1.95584,-2.73015e-08],[-1.95584,2.94054e-10],[-1.95584,5.73937e-10],[-1.95584,-2.85971e-09],[-1.95584,-1.88705e-08],[-1.95584,6.0022e-09],[-1.95584,3.62821e-08],[-1.95584,-2.74443e-08],[-1.95584,-3.90196e-08],[-1.95584,-2.42011e-08],[-1.95584,-1.33425e-08],[-1.95584,-6.0989e-08],[-1.95584,-1.10644e-08],[-1.95584,-1.6113e-09],[-1.95584,1.03999e-09],[-1.95584,-5.35982e-08]]}}, +{"best":0.358813,"evaluations":17448,"generation":423,"median":3.97983,"state":{"best":[-0.0158853,-0.012466],"population":[[-1.95584,1.49306e-09],[-1.95584,7.83754e-09],[-1.95584,7.71295e-10],[-1.95584,-2.73493e-09],[-1.95584,-9.08278e-10],[-1.95584,3.56168e-09],[-1.95584,-5.05534e-10],[-1.95584,-1.62145e-09],[-1.95584,-2.25686e-11],[-1.95584,-2.46365e-09],[-1.95584,-2.10996e-09],[-1.95584,-4.09247e-09],[-1.95584,-1.9084e-09],[-1.95584,-1.92793e-09],[-1.95584,2.6965e-09],[-1.95584,-3.38305e-09],[-1.95584,-5.30514e-09],[-1.95584,-1.00487e-10],[-1.95584,-3.21496e-09],[-1.95584,3.29275e-09],[-1.95584,-7.91386e-10],[-1.95584,-1.0399e-09],[-1.95584,-2.2165e-09],[-1.95584,-1.29237e-09],[-1.95584,-2.62223e-10],[-1.95584,-3.96561e-09],[-1.95584,-1.9292e-09],[-1.95584,-5.27534e-10],[-1.95584,5.20774e-09],[-1.95584,3.4281e-09],[-1.95584,4.46528e-09],[-1.95584,4.88804e-09],[-1.95584,-3.44326e-09],[-1.95584,4.23722e-10],[-1.95584,2.12014e-09],[-1.95584,2.35958e-10],[-1.95584,7.48144e-10],[-1.95584,9.54204e-10],[-1.95584,-4.67477e-09],[-1.95584,9.29401e-09],[-1.95584,2.78536e-09],[-1.95584,2.87112e-09],[-1.95584,1.01097e-09],[-1.95584,2.40133e-09],[-1.95584,3.40339e-09],[-1.95584,-9.01484e-10],[-1.95584,2.62592e-09],[-1.95584,4.579e-09],[-1.95584,-3.56379e-10],[-1.95584,-8.73803e-09],[-1.95584,-3.70666e-09],[-1.95584,4.09117e-09],[-1.95584,-2.56067e-09],[-1.95584,3.19128e-09],[-1.95584,-3.5287e-09],[-1.95584,2.02592e-09],[-1.95584,-8.84972e-11],[-1.95584,-2.67978e-09],[-1.95584,5.54824e-10],[-1.95584,-2.10628e-09],[-1.95584,-1.13063e-09],[-1.95584,1.51342e-09],[-1.95584,-2.71735e-09],[-1.95584,-8.4147e-09],[-1.95584,-1.35662e-09],[-1.95584,2.98572e-09],[-1.95584,2.08341e-09],[-1.95584,-4.41606e-09],[-1.95584,-5.04762e-09],[-1.95584,-1.45768e-09],[-1.95584,1.27104e-09],[-1.95584,3.65477e-10],[-1.95584,4.4944e-09],[-1.95584,-2.84752e-09],[-1.95584,4.07576e-10],[-1.95584,-6.97998e-10],[-1.95584,8.71769e-10],[-1.95584,-5.41281e-10],[-1.95584,-4.57257e-09],[-1.95584,9.5448e-10],[-1.95584,5.14538e-09],[-1.95584,2.5512e-09],[-1.95584,3.65936e-09],[-1.95584,-1.1798e-09],[-1.95584,9.99273e-10],[-1.95584,2.38259e-09],[-1.95584,-5.50733e-09],[-1.95584,-1.02194e-11],[-1.95584,1.45625e-09],[-1.95584,-5.61951e-09],[-1.95584,9.98623e-10],[-1.95584,1.17973e-10],[-1.95584,-6.32065e-10],[-1.95584,4.91815e-10],[-1.95584,9.50566e-10],[-1.95584,-1.77985e-09],[-1.95584,1.43404e-09],[-1.95584,2.22396e-09],[-1.95584,-2.56312e-09],[-1.95584,-8.25049e-10],[-1.95584,-2.00993e-09],[-1.95584,4.56063e-09],[-1.95584,2.91087e-09],[-1.95584,2.04834e-09],[-1.95584,-3.02092e-09],[-1.95584,4.80461e-09],[-1.95584,-1.40852e-09],[-1.95584,3.73944e-10],[-1.95584,-1.33656e-09],[-1.95584,-6.58852e-10],[-1.95584,-1.99666e-09],[-1.95584,8.848e-10],[-1.95584,1.83936e-09],[-1.95584,2.15292e-09],[-1.95584,2.53535e-09],[-1.95584,-4.96393e-10],[-1.95584,6.15441e-09],[-1.95584,3.63628e-09],[-1.95584,1.20761e-09],[-1.95584,3.28277e-09],[-1.95584,4.43584e-09],[-1.95584,-2.3693e-10],[-1.95584,3.30462e-09],[-1.95584,-2.76622e-09],[-1.95584,-1.39332e-10],[-1.95584,-2.24509e-09],[-1.95584,1.43814e-09],[-1.95584,2.96541e-10],[-1.95584,-4.99636e-10],[-1.95584,3.15245e-09],[-1.95584,-3.69339e-09],[-1.95584,2.53555e-09],[-1.95584,1.95181e-09],[-1.95584,-4.28501e-10],[-1.95584,-1.328e-09],[-1.95584,2.45366e-09],[-1.95584,5.17518e-10],[-1.95584,-7.56835e-10],[-1.95584,3.29441e-10],[-1.95584,4.86693e-09],[-1.95584,-7.62614e-10],[-1.95584,-7.72827e-10],[-1.95584,1.18919e-09],[-1.95584,-2.98789e-09],[-1.95584,3.93804e-10],[-1.95584,-1.32905e-09],[-1.95584,-2.80136e-09],[-1.95584,7.52931e-10],[-1.95584,-1.34732e-09],[-1.95584,2.67919e-09],[-1.95584,-1.54109e-09],[-1.95584,-1.10599e-09],[-1.95584,3.13963e-09],[-1.95584,4.83593e-09],[-1.95584,-3.61754e-10],[-1.95584,-4.4196e-09],[-1.95584,-2.32956e-09],[-1.95584,-2.98577e-09],[-1.95584,2.4344e-10],[-1.95584,-3.669e-09],[-1.95584,3.394e-09],[-1.95584,1.43488e-09],[-1.95584,1.10647e-09],[-1.95584,-3.03495e-09],[-1.95584,-5.37845e-11],[-1.95584,1.89533e-10],[-1.95584,4.27888e-10],[-1.95584,1.9125e-09],[-1.95584,1.71859e-09],[-1.95584,-5.59438e-09],[-1.95584,-7.17034e-10],[-1.95584,1.06675e-10],[-1.95584,-4.13615e-09],[-1.95584,4.00973e-09],[-1.95584,-3.66593e-09],[-1.95584,-4.43322e-09],[-1.95584,2.23241e-09],[-1.95584,-2.3701e-09],[-1.95584,2.0981e-09],[-1.95584,1.58579e-09],[-1.95584,7.36823e-10],[-1.95584,-1.17973e-09],[-1.95584,-2.41358e-09],[-1.95584,2.4412e-10],[-1.95584,-5.36774e-09],[-1.95584,-2.72449e-09],[-1.95584,-2.81836e-09],[-1.95584,3.85189e-09],[-1.95584,-1.09291e-09],[-1.95584,2.84247e-09],[-1.95584,-5.11243e-09],[-1.95584,-1.89111e-10]]}}, +{"best":0.358813,"evaluations":18600,"generation":428,"median":98.4087,"state":{"best":[-0.0158853,-0.012466],"population":[[1.92098,4.18021],[-0.143956,4.06811],[0.650978,-2.40637],[0.970625,-3.10479],[-0.475176,1.67864],[3.10336,3.63118],[0.171793,2.30699],[4.14223,1.07676],[-1.30483,4.82219],[-0.0665246,4.04011],[2.03006,-1.85483],[1.14274,-1.11445],[1.56955,-3.13549],[-2.74478,-4.52936],[2.09903,1.44981],[1.66082,-1.94912],[-1.39979,-2.31492],[2.50399,-0.885654],[-0.765027,-0.994353],[1.94588,-2.7763],[-0.967746,1.05264],[-1.6013,-1.77097],[1.98426,-0.806921],[0.0658382,0.62624],[-2.79951,-2.37756],[-0.405797,0.110513],[-1.10893,3.49961],[-3.39658,-1.75839],[1.16146,-1.39464],[-0.992538,4.49221],[2.3079,-0.740758],[-3.77033,2.78465],[-2.93652,1.0626],[3.28009,3.63424],[-1.0694,-1.47786],[-0.442792,0.118763],[0.638335,-0.475347],[-0.318228,1.14281],[1.73411,-2.44783],[-3.89259,-0.762469],[-0.806884,4.53714],[-4.31093,-2.54431],[-1.15301,-1.61238],[-0.391304,4.94824],[-4.5759,1.90417],[0.548203,-0.157154],[2.65083,4.84272],[-3.21533,1.43098],[2.89874,4.19716],[4.9639,1.72065],[-1.71202,-0.562357],[-3.36413,3.71507],[0.195314,-1.25986],[-1.14603,4.67281],[3.57463,-2.34615],[-1.74928,2.02081],[-1.9987,-0.424477],[-0.455878,-1.67136],[2.58445,-1.36624],[-0.702349,1.52205],[0.218836,1.39676],[-1.37395,0.472623],[-0.536082,-1.25781],[-1.82993,2.01214],[-4.00427,4.26311],[-0.211867,0.603377],[4.92362,-4.52624],[1.49731,-3.56903],[2.82257,2.34905],[-3.62721,0.752153],[-2.06896,2.3362],[-3.47913,1.74799],[0.144297,1.06475],[-2.87651,0.53689],[-1.53745,-0.863916],[-4.51643,3.34957],[-1.54701,-0.714918],[-1.87193,1.26015],[0.396098,0.884395],[0.765121,3.68585],[-0.625103,1.66622],[-0.4506,1.52763],[-0.437573,0.881677],[-0.540419,1.1642],[3.97765,0.607165],[1.31528,-2.04027],[-2.12754,-1.03997],[-2.49747,-0.061258],[0.540153,3.40611],[-3.01382,1.66016],[1.36894,-0.682795],[1.71593,0.406618],[4.78574,1.48876],[4.14516,-2.38117],[0.483857,0.325067],[3.91386,-1.16862],[-4.39778,0.625099],[3.90584,-2.27874],[-0.390063,1.72724],[-3.70358,-4.34607],[2.81431,3.50708],[0.938934,-0.243134],[-1.61673,-3.63642],[2.8891,1.33026],[1.90191,3.43539],[0.210209,2.51721],[-1.27942,0.378448],[-1.06705,2.90824],[-4.38603,-2.02787],[-3.05387,0.62594],[4.73427,0.499549],[2.15162,0.179315],[-2.47573,0.831905],[3.01506,-4.63734],[-3.54575,-1.85207],[-4.31012,1.74425],[2.7974,3.99902],[-2.65665,0.521525],[2.73772,2.35313],[-0.442561,-0.224486],[-0.917891,3.15485],[-1.40474,-1.59586],[-3.0266,0.320117],[3.28075,-1.82968],[-1.66275,-1.17416],[-2.81845,-2.94481],[1.1168,-0.0813939],[2.06584,4.26333],[-1.88134,-1.48886],[-4.54124,2.5987],[0.142063,2.51462],[0.015016,-1.21665],[-1.54587,-1.33217],[0.441051,-0.158775],[-0.0809661,-3.2707],[0.618007,0.7456],[-2.58988,-2.13046],[1.15581,0.204007],[-3.6457,3.08861],[-1.68519,2.85494],[-3.42216,0.911289],[0.626989,0.419817],[0.319259,1.09911],[-1.97708,-2.51847],[2.71691,-2.03218],[3.55015,-2.33112],[0.619057,-2.00889],[2.38672,-2.25547],[-2.19056,0.00944392],[0.590274,0.208805],[2.25634,0.714178],[-2.38714,2.68374],[3.84584,1.68392],[-0.909744,1.14912],[-2.47832,0.602095],[-2.04768,4.79183],[-3.71096,-1.20703],[-0.969999,-4.91819],[-0.791743,-0.985717],[-2.20646,3.96753],[1.60592,-1.92641],[0.182486,1.4673],[-4.28686,-1.50552],[-2.70393,1.90019],[-1.93128,1.20537],[-0.512861,0.249723],[3.63359,-2.45882],[-2.06222,0.410069],[-4.48438,0.161605],[0.3295,2.05206],[-3.6976,0.0976821],[-1.32143,1.0706],[-2.99599,-2.7052],[1.71608,-0.688037],[1.2003,-1.01095],[-0.30436,-1.51657],[-3.03746,0.25689],[-2.22183,-1.59023],[-1.23162,3.37437],[-4.21196,-4.30714],[3.20987,-2.16717],[-3.55444,-0.920936],[-2.89134,-2.8788],[-4.248,1.50185],[2.12895,-1.44087],[-4.15794,4.98522],[3.44919,-1.55882],[-0.342268,1.05546],[-2.51414,-1.43064],[-3.54117,-1.07899],[-3.79172,-4.13277],[-1.2002,3.75655],[-3.31522,-0.813071],[-0.657965,1.76197],[-0.185782,2.62475],[1.26306,-2.97557],[-3.98718,3.55931],[0.0323802,-2.07],[-3.53112,-4.06798],[0.953979,-3.49118],[0.617281,0.907271],[3.36413,2.3846],[-1.03922,-1.75055],[1.41737,4.25184],[0.122686,-3.49038],[-2.73783,2.80199],[-2.6534,2.33107],[-1.55446,4.93737],[-3.2868,0.906459],[0.747441,-4.49903],[0.0602813,2.5137],[-2.56905,0.112907],[1.48531,-1.96087],[-0.316341,3.43177],[3.54673,1.8239],[0.625106,1.36073],[-3.80484,4.47041],[-0.51366,-1.8423],[2.7617,-3.03473],[1.39212,2.38628],[-1.16864,-3.5773],[4.95267,4.11275],[-2.47423,-1.46128],[-3.57821,1.71474],[-2.88861,1.89988],[1.38461,0.536535],[0.365579,0.0173216],[-1.0991,2.14201],[-4.8302,-0.404632],[-0.267499,1.86307],[-2.19999,-4.44666],[-3.1503,-2.40069],[-3.012,0.0412354],[0.576856,2.13775],[-0.90794,-3.23044],[0.664798,4.39472],[-3.77909,2.63982],[2.61977,0.170925],[1.9072,0.820232],[2.61566,0.343491],[-0.495564,2.96135],[-3.89393,-3.5039],[-2.2988,-1.78764],[1.07462,0.319477],[-4.37083,3.94001],[3.128,-2.9944],[-1.44621,0.271877],[0.944905,0.196394],[-1.04025,1.29923],[-0.593246,-4.18262],[-3.23465,2.07733],[-3.72356,-3.18872],[1.3079,1.34229],[-1.51501,-0.229773],[3.59697,0.400485],[-3.5954,2.75083],[-1.6194,3.22883],[-4.28798,3.17891],[1.74396,-1.28787],[3.13477,0.18532],[-3.88682,-0.496181],[0.961011,2.33987],[4.47527,3.04279],[0.00153654,-1.65438],[-3.30017,1.58386],[-1.02249,1.44298],[-1.47999,-3.71836],[0.275951,-2.39364],[4.60818,-2.26172],[-0.0395094,2.9231],[3.26172,-2.68253],[-0.606924,2.51012],[2.62668,1.94435],[-3.36192,-3.9383],[-1.70573,3.76069],[-2.60827,0.451958],[-0.661881,0.719451],[-1.24418,-1.41942],[4.3874,0.234074],[-0.598643,2.12913],[1.52061,-1.5447],[0.501449,-1.21958],[-0.692688,0.0830347],[-0.729718,-0.386723],[0.519155,1.66779],[3.85838,2.56796],[-2.64457,1.71203],[-3.75507,2.06656],[-0.0115955,1.83935],[3.23398,1.92905],[-2.7282,-3.59811],[4.9191,2.80182],[-4.3693,1.65853],[0.0130411,3.57919],[-0.0399775,1.91714],[-1.64202,-1.39433],[-1.1568,2.08266],[-2.42597,2.07062],[-1.50178,-2.57326],[3.03818,-3.23498],[0.506033,1.81362],[-0.959601,0.979981],[-2.94322,3.8788],[-1.07011,-4.16981],[1.37894,0.849659],[-3.27998,-0.953891],[-0.673427,-2.37159],[-2.72618,1.7423],[-0.706188,0.558013],[-0.692059,4.59248],[3.58157,3.51263],[-4.00187,1.6423],[-0.371392,-0.0896644],[0.731872,-1.55305],[4.60411,1.38197],[-1.32049,-2.61468],[-0.37788,-0.190002],[-1.79872,0.733423],[-3.41156,1.85784],[1.71673,2.48413],[0.494193,0.0959009],[4.16661,4.75633],[0.987292,0.872461],[-0.855031,1.11159],[-0.934175,1.57576],[1.63213,1.03194],[-2.22277,4.74715],[0.518967,0.81702],[3.059,-4.28583],[0.91224,-1.96121],[-0.327517,0.234766],[0.341249,-1.26548],[-0.111466,3.67985],[-3.65267,1.43063],[0.132904,-0.687677],[-4.94667,-0.837032],[-2.1818,0.119191],[-4.88661,0.922892],[-2.12321,-2.22831],[-4.37355,2.21108],[-3.77765,0.337802],[-2.56461,-4.25467],[-1.96372,-4.23114],[1.00993,2.75948],[3.02629,-1.94372],[2.02588,-0.28366],[-0.0300108,0.707443],[3.12009,-2.52603],[-4.71041,-1.5745],[-3.01567,-1.8133],[-2.36529,-2.23567],[-4.41438,2.40655],[3.81161,3.07811],[1.8367,1.22617],[4.66854,-0.558323],[1.94411,1.31626],[-0.895145,1.92438],[-1.33681,-0.349626],[1.08758,0.634683],[-3.63271,-0.226274],[-3.8862,-1.53807],[1.86167,2.36513],[-0.61636,4.26449],[-3.13755,-3.68549],[-2.84751,-2.97849],[-1.28129,-2.2548],[-2.76609,-2.75773],[2.54094,1.94459],[-1.16009,2.63117],[-1.34392,0.812969],[-1.3714,0.33791],[-0.599034,3.41176],[1.51388,2.59791],[2.51536,0.647427],[3.91453,0.118761],[-4.19011,-1.21666],[-4.07623,-1.05108],[0.439781,2.42678],[0.520372,1.90052],[-2.86908,-1.12526],[1.28188,3.39625],[-3.54005,3.49663],[3.03865,4.78429],[2.17451,-2.03797]]}}, +{"best":0.358813,"evaluations":20136,"generation":432,"median":23.8568,"state":{"best":[-0.0158853,-0.012466],"population":[[-0.0542216,0.254174],[-2.42761,-0.0626261],[0.0815924,0.269089],[-0.0655053,0.192843],[0.642673,-0.388537],[-1.62456,0.247186],[-0.149039,0.602859],[-1.86405,0.157291],[-1.04601,0.215423],[-1.51049,0.11611],[-1.57345,0.104462],[-2.31813,-0.064019],[-1.1546,-0.0279472],[-0.137929,0.623323],[-2.95653,-0.0606778],[-2.24603,0.0365289],[-1.7659,0.51686],[-1.1268,-0.24947],[-0.169028,0.205697],[-1.45016,0.217513],[-1.80902,-0.0421087],[-2.26409,0.606865],[0.824132,-0.0601988],[-0.33031,0.833192],[-2.38244,0.345551],[-1.35258,0.184498],[-0.0960404,0.21659],[-1.23188,1.02872],[-1.83638,-0.304526],[-2.86736,0.238625],[-0.355338,-0.0481464],[-0.350247,0.353278],[-1.49606,0.0376118],[-0.403519,0.384558],[-1.73199,0.0374814],[-1.83077,0.0945034],[-0.517146,0.0723645],[-1.07685,-0.0276733],[-1.31396,-0.129326],[-1.44329,0.167289],[-3.18425,-0.0836689],[-1.7728,0.272699],[-1.75717,0.196409],[-0.998606,-0.0943294],[-1.02372,-0.698185],[-2.28316,0.0404487],[-0.980488,0.183747],[-2.48349,-0.457961],[-2.0432,0.264891],[-0.225934,0.102916],[-1.7083,0.506828],[-0.724943,0.215928],[-3.53032,-0.253764],[0.0770377,0.0173703],[-1.18335,0.357196],[-1.12901,-0.0180803],[-0.0485428,0.0631692],[0.0985247,-0.148775],[-1.63468,0.344604],[-1.40562,0.00854196],[-1.66261,0.457508],[-2.49799,0.583859],[-0.568633,0.281916],[-2.83544,-0.772944],[-0.991754,0.47374],[-2.93115,-0.0731825],[-0.740396,-0.631826],[-0.218024,-0.520093],[-2.30912,-0.55772],[-1.46804,0.298929],[0.0949127,0.0957355],[-1.09225,0.0255465],[-1.28396,0.0688384],[-0.818024,0.128952],[-0.860439,0.268443],[-0.0873471,0.164315],[-2.0338,0.419473],[-3.05686,-0.464535],[-0.397419,0.233429],[-0.215514,0.284094],[-0.85037,0.90487],[-0.741765,-0.1472],[-1.88015,0.331726],[-2.93193,0.424738],[-2.47334,-0.0518512],[-0.905738,0.0288015],[-1.67348,0.241154],[-2.05794,0.480472],[-2.85345,-0.457965],[-1.79774,-0.164113],[-1.61916,-0.144501],[-2.67292,0.167781],[-2.59959,0.323346],[-1.35297,0.24152],[-1.78723,-0.00205363],[-2.48862,0.444762],[-1.97975,0.189761],[-1.64256,-0.0973675],[-1.42518,0.012008],[-0.484883,0.284863],[-0.497225,-0.673329],[-0.869777,0.52462],[-2.48194,0.355471],[-0.735553,0.163978],[-2.42845,-0.0914162],[-0.992291,-0.151847],[-0.251676,-0.121265],[0.41894,0.247299],[-1.33388,0.67443],[-1.90838,0.113871],[-2.1731,0.284602],[-0.0754672,-0.686971],[-1.32982,-0.0485606],[-2.12878,0.358938],[-1.72749,-0.215782],[-0.395061,0.254319],[-0.45411,0.841839],[-0.658249,0.377129],[-1.63596,-0.0984188],[-1.07421,0.275799],[-1.53893,0.453707],[-1.3685,0.497978],[-1.48307,0.654043],[-1.98032,0.571454],[-1.43082,-0.288464],[-0.350328,0.156067],[-0.621778,0.00033483],[-2.53364,-0.0904029],[0.0916817,-0.0462783],[-1.18643,0.620616],[0.522354,0.62332],[-0.680314,0.340549],[-1.65932,-0.354185],[-1.64532,-0.189182],[-0.986496,0.178494],[-1.63609,-0.838925],[-0.643145,-0.0205172],[-1.81836,-0.541082],[-2.09298,0.596699],[-0.710793,0.22814],[-0.24678,0.0449167],[-2.84934,0.411803],[-2.01214,0.105683],[-0.629571,0.187243],[-0.474845,0.55581],[-2.28091,-0.397405],[-0.447562,0.613937],[0.278213,0.373703],[-0.0381932,-0.0685189],[-1.63798,0.627696],[-1.19997,0.524821],[-3.4482,-0.170699],[-1.69832,0.162976],[-1.11722,0.309327],[-0.74843,-0.0404744],[-1.09569,0.0602148],[-1.51212,0.529121],[0.0813192,0.0455754],[-2.37969,0.105376],[1.18902,0.299382],[-1.84292,-0.221307],[-0.707626,-0.061389],[-1.62392,-0.258133],[-2.36613,0.203179],[-1.5788,0.324159],[-1.52093,0.1508],[-1.97804,-0.328482],[-1.18891,0.429475],[-0.593705,0.544466],[0.096307,-0.3196],[-1.65302,-0.387781],[-1.09268,-0.155603],[-1.7384,-0.0377805],[-1.21392,0.25603],[-0.153762,0.377356],[-1.57014,0.128823],[-0.674386,0.25841],[-0.176676,-0.279407],[-1.6692,0.361354],[0.46288,-0.462176],[-1.67428,0.874696],[-1.62471,0.240492],[-0.782477,-0.373061],[-1.30453,0.506111],[-1.91371,0.250652],[-1.83625,-0.237789],[-1.42919,0.205565],[-2.27095,-0.1929],[-1.07964,0.0337981],[-1.22868,0.330212],[-0.738102,-0.272219],[-2.03052,0.00069213],[-1.29779,0.447895],[-1.58055,0.966223],[0.151737,0.169441],[-1.74012,0.69792],[0.478209,-0.0060748],[-0.358442,0.00968975],[-0.888546,0.125509],[-1.10704,-0.156793],[-0.543528,0.393465],[-0.68382,0.231807],[-1.80488,-0.197024],[-2.22905,0.120983],[-1.38528,0.0817274],[-1.41667,0.579261],[-1.86213,0.161166],[-1.77908,0.773864],[-1.53737,-0.13599],[-1.22889,-0.31666],[-1.47244,-0.399322],[-1.20265,-0.210357],[-1.8592,0.632634],[-1.27439,-0.101097],[-1.08781,0.866478],[-0.796831,0.331475],[-1.89434,0.175033],[-0.15377,-0.144041],[-1.09817,0.288775],[-1.64803,-0.051824],[0.558064,0.218657],[-0.429232,0.333537],[-2.02292,-0.0143699],[-1.17989,0.362281],[-1.01574,0.29905],[-2.46125,0.306138],[-1.90003,0.236334],[-2.20098,-0.102841],[-2.03672,0.337223],[-3.31995,0.348413],[-1.17863,-0.0513422],[-0.655317,0.183288],[-1.62916,0.289012],[-2.55782,0.237841],[-0.214912,0.321198],[-2.35069,-0.365084],[-1.25223,0.133357],[-2.50857,-0.240808],[-3.06946,-0.722063],[-0.970358,0.627871],[-0.591578,0.793744],[-1.70185,-0.541937],[-2.00222,0.186178],[-0.683753,0.739234],[-2.66789,0.473725],[-1.17559,-0.319364],[-1.56444,-0.176048],[-1.2837,0.447238],[-1.71595,-0.0965078],[-3.68727,-0.287054],[0.378919,0.400056],[0.316126,0.610882],[-0.81741,0.0943644],[-0.486327,0.259415],[-1.83027,0.357613],[-1.34997,0.791513],[-1.62093,-0.224229],[-1.66126,-0.283117],[0.00285112,-0.253891],[-1.7505,0.06635],[-2.09438,0.222291],[-1.50156,0.0579242],[-1.189,-0.395742],[-0.107257,-0.123977],[-2.20083,0.236395],[-2.48829,-0.229303],[-1.40032,0.0738656],[-0.812883,0.522581],[-0.670953,0.65308],[-1.33108,-0.111478],[-1.82955,-0.374115],[-1.8648,-0.29935],[-1.60851,0.0427967],[-1.55831,0.117245],[-1.73632,0.0202981],[-0.712279,0.213602],[-0.191852,-0.20264],[-0.446194,0.12849],[-0.388295,0.298643],[-1.05635,0.19755],[-2.64447,0.253028],[-0.50157,0.42484],[-1.55584,0.374995],[-0.00249874,0.15777],[0.185627,0.105723],[-0.233907,0.28372],[-0.920351,0.269015],[-3.38103,0.19082],[0.639547,0.0576623],[-1.02206,0.348249],[-2.07128,0.114853],[-1.03144,0.194105],[-2.58818,0.264105],[-1.19857,0.177363],[-0.462712,-0.120578],[-0.950034,-0.133454],[-1.16958,0.2678],[-0.94374,0.272415],[-1.19431,0.490912],[-1.33903,0.0893425],[-1.51236,-0.0453864],[-0.936723,-0.240487],[-1.36568,0.59652],[-3.46383,0.151384],[-1.06695,0.0606113],[-0.0466325,0.483501],[-1.50015,-0.410118],[-1.46086,0.174368],[-1.0276,0.560878],[-0.989088,0.226023],[-0.520717,0.423878],[0.131951,0.137982],[-1.82709,0.508111],[-1.61951,0.494776],[-0.0476826,0.411675],[0.307516,0.76885],[-2.19776,0.0737874],[-0.880875,0.106106],[-1.99535,-0.136227],[-2.3398,0.401219],[-2.437,0.195868],[-0.656556,0.363093],[0.0273672,0.321924],[-2.80104,0.170904],[-2.44442,-0.208818],[-1.06031,0.111649],[-2.37858,0.195842],[-2.4359,0.519708],[-1.95176,-0.27603],[-0.0976499,-0.96529],[-1.32912,0.0852959],[-2.23213,0.207186],[-0.832881,-0.214259],[-0.889673,0.00964941],[-3.54445,0.0107937],[0.149219,0.595582],[-2.09394,0.404949],[-0.967641,0.439815],[-1.02666,0.601747],[-2.20909,0.0415876],[-1.56232,0.128803],[-1.09226,0.209306],[-0.582702,0.460987],[-1.17163,-0.0844094],[-2.1527,-0.0417403],[-1.27119,0.098447],[-1.13235,0.122737],[-0.510701,-0.100615],[-1.55219,0.295974],[-1.12907,0.304852],[-0.103452,0.503339],[0.0208976,0.359208],[-2.92136,-0.0552217],[-0.59897,-0.148706],[-1.74574,-0.0631883],[-0.832044,-0.136894],[-1.59883,0.0496832],[-2.70578,0.0225568],[-2.5953,-0.345944],[-1.68839,-0.0111121],[-1.1766,-0.0185579],[0.582864,0.41764],[-2.53912,-0.399511],[-0.75689,0.140922],[-1.68645,0.0206252],[-1.68691,-0.419965],[-1.87166,0.220456],[-1.64424,0.780834],[-0.512974,0.259928],[-2.0334,0.267025],[-2.00879,-0.0287616],[-1.69757,-0.00601593],[-2.72265,-0.0235625],[-1.04731,-0.251729],[0.485076,0.836904],[-1.36743,0.422258],[-1.36933,0.326498],[-1.91867,-0.00596259],[-1.34165,-0.340265],[-1.31297,-0.222377],[0.344349,0.00747277],[-0.194624,0.530926],[-0.760139,-0.351106],[-1.72384,-0.0250547]]}} +]} diff --git a/examples/buche_rastrigin/trace.py b/examples/buche_rastrigin/trace.py new file mode 100644 index 00000000..bff23fd4 --- /dev/null +++ b/examples/buche_rastrigin/trace.py @@ -0,0 +1,189 @@ +"""The trace for the plot on the example's page, written to the file that ``GENOXIDE_TRACE`` +names. The plot draws the population on the function's contour, which needs two dimensions: the +trace is of a separate run of CMA-ES with IPOP restarts in 2 dimensions, with a budget of +20,000 evaluations, in at most 100 frames. The Rust example writes the same file.""" + +import json +import math +import os + +import genoxide as gx + + +def record_small(): + """Runs CMA-ES with IPOP restarts in 2 dimensions and writes its trace, if ``GENOXIDE_TRACE`` is set.""" + path = os.environ.get("GENOXIDE_TRACE") + if not path: + return + problem = gx.problems.BucheRastrigin(2) + minimum = problem.optimum.value + budget = 20_000 + cmaes = gx.Cmaes(problem.genome, restarts="ipop", objective="minimize", seed=1) + frames = Frames(100) + + def record(progress): + state = {"population": progress.population.tolist(), "best": progress.best_genome.tolist()} + frames.push(frame(progress, state, minimum)) + + cmaes.run(problem, target=minimum + 1e-8, evaluations=budget, on_generation=record) + low, high = problem.genome.bounds + settings = { + "format": 1, + "example": "buche_rastrigin", + "objective": "minimize", + "x_label": "evaluations", + "y_label": "error", + "log_y": True, + "optimum": 0.0, + "plot": "contour", + "problem": { + "function": "buche_rastrigin", + "bounds": [[float(low), float(high)]] * 2, + "minima": problem.optimum.solutions.tolist(), + }, + } + write(path, settings, frames.to_list()) + + +def frame(progress, state, minimum): + """The frame of a generation: its progress, the errors of its best and of its population's + median to ``minimum`` (rounding can put a solution a few ulps below it), and ``state``.""" + + def error(value): + return None if value is None else max(value - minimum, 0.0) + + return { + "generation": progress.generation, + "evaluations": progress.evaluations, + "best": error(progress.best_fitness), + "median": error(median(progress.scores)), + "state": state, + } + + +def median(scores): + """The median of the valid scores, None without any.""" + scores = sorted(float(score) for score in scores if not math.isnan(score)) + middle = len(scores) // 2 + if not scores: + return None + return scores[middle] if len(scores) % 2 else (scores[middle - 1] + scores[middle]) / 2 + + +# ---- the same in every example's trace ---------------------------------------------------------- + + +class Frames: + """The frames of at most ``most`` generations, from the part of the run where what the page + plots changes: the frames after the last change are left out (a run that reached its target, + or a front that no longer moves), and the rest are spread evenly over the generations up to + it. While the run goes, up to 8 × ``most`` frames are kept: every ``every``-th generation, + with ``every`` doubling whenever there are that many, and the last one.""" + + def __init__(self, most): + self.most, self.every, self.kept, self.last = most, 1, [], None + + def push(self, frame): + if frame["generation"] % self.every: + self.last = frame + return + self.kept.append(frame) + self.last = None + if len(self.kept) == 8 * self.most: + self.every *= 2 + self.kept = [kept for kept in self.kept if kept["generation"] % self.every == 0] + + def to_list(self): + frames = self.kept + ([self.last] if self.last else []) + active = frames[: last_change(frames) + 1] + count, most = len(active), max(self.most, 2) + if count <= most: + return active + return [active[(i * (count - 1) + (most - 1) // 2) // (most - 1)] for i in range(most)] + + +def last_change(frames): + """The index of the frame after which nothing the page plots changes. To 3 significant + digits, as a plot shows them: the best, the median and, for a single objective (a numeric + best), the state; to within a hundredth of their range over the run: a front's + hypervolumes, in the state or in a grid's series.""" + if not frames: + return 0 + last = len(frames) - 1 + number = lambda value: isinstance(value, (int, float)) and not isinstance(value, bool) + single = any(number(frame.get("best")) for frame in frames) + + def measures(frame): + values = [] + state = frame.get("state") + hypervolume = state.get("hypervolume") if isinstance(state, dict) else None + for value in (hypervolume, frame.get("series")): + if number(value): + values.append(float(value)) + elif isinstance(value, dict): + values.extend(float(v) for _, v in sorted(value.items()) if number(v)) + return values + + measured = [measures(frame) for frame in frames] + end = measured[last] + tolerance = [] + for k in range(len(end)): + values = [values[k] for values in measured if k < len(values)] + tolerance.append((max(values) - min(values)) / 100.0) + + def same(frame, final, key, flush=False): + return coarse(frame.get(key), flush) == coarse(final.get(key), flush) + + def settled(i): + frame, final = frames[i], frames[last] + return ( + same(frame, final, "best") + and same(frame, final, "median") + and (not single or same(frame, final, "state", flush=True)) + and len(measured[i]) == len(end) + and all(abs(v - e) <= t for v, e, t in zip(measured[i], end, tolerance)) + ) + + first = last + while first > 0 and settled(first - 1): + first -= 1 + return first + + +def coarse(value, flush=False): + """``value`` with its numbers to 3 significant digits, as precisely as a plot shows them: two + frames whose plotted values agree to that precision look the same. With ``flush``, for the + solutions a plot draws on their ranges, numbers below 1e-6 in size count as 0.""" + if isinstance(value, float): + if flush and abs(value) < 1e-6: + value = 0.0 + return f"{value:.2e}" + if isinstance(value, (list, tuple)): + return "[" + ",".join(coarse(item, flush) for item in value) + "]" + if isinstance(value, dict): + items = sorted(value.items()) + return "{" + ",".join(f"{key}:{coarse(item, flush)}" for key, item in items) + "}" + return json.dumps(value) + + +def write(path, settings, frames): + """Writes the settings and the frames to ``path``, a frame per line.""" + lines = ",\n".join(map(to_json, frames)) + with open(path, "w", encoding="utf-8", newline="\n") as file: + file.write(f'{to_json(settings)[:-1]},"frames":[\n{lines}\n]}}\n') + + +def to_json(value): + """Compact JSON with sorted keys, and numbers rounded to 6 significant digits, as the Rust + example writes it.""" + return json.dumps(rounded(value), sort_keys=True, separators=(",", ":"), ensure_ascii=False) + + +def rounded(value): + if isinstance(value, dict): + return {key: rounded(item) for key, item in value.items()} + if isinstance(value, (list, tuple)): + return [rounded(item) for item in value] + if isinstance(value, float): + return float(f"{value:.5e}") if math.isfinite(value) else None + return value diff --git a/examples/buche_rastrigin/trace.rs b/examples/buche_rastrigin/trace.rs new file mode 100644 index 00000000..3e04e21c --- /dev/null +++ b/examples/buche_rastrigin/trace.rs @@ -0,0 +1,261 @@ +//! The trace for the plot on the example's page, written to the file that `GENOXIDE_TRACE` names. +//! The plot draws the population on the function's contour, which needs two dimensions: the trace +//! is of a separate run of CMA-ES with IPOP restarts in 2 dimensions, with a budget of +//! 20,000 evaluations, in at most 100 frames. The Python example writes the same +//! file. + +use genoxide::observer::Snapshot; +use genoxide::prelude::*; +use genoxide::problems::{BucheRastrigin, Problem}; +use serde_json::{Value, json}; + +// runs CMA-ES with IPOP restarts in 2 dimensions and writes its trace, if GENOXIDE_TRACE is set +pub fn record_small() -> Result<()> { + let Ok(path) = std::env::var("GENOXIDE_TRACE") else { + return Ok(()); + }; + let problem = BucheRastrigin::new(2); + let optimum = problem.optimum().expect("known"); + let minimum = optimum.value(); + let budget = 20_000; + let cmaes = Cmaes::builder(problem.representation()) + .restarts(cmaes::Restarts::Ipop) + .minimize() + .seed(1) + .build()?; + let mut frames = Frames::new(100); + Engine::new(cmaes, problem.clone()) + .stop_when(Stop::target(minimum + 1e-8).or(Stop::evaluations(budget))) + .on_generation(|snapshot| { + let population = snapshot.population().iter().map(|x| &x.genome()[..]); + let population: Vec<&[f64]> = population.collect(); + let best = &snapshot.best().genome()[..]; + let state = json!({ "population": population, "best": best }); + frames.push(frame(snapshot, state, minimum)); + }) + .run()?; + let bounds = problem.representation().bounds().to_vec(); + let bounds: Vec<[f64; 2]> = bounds.iter().map(|b| [*b.start(), *b.end()]).collect(); + let minima: Vec<&[f64]> = optimum.solutions().iter().map(|x| &x[..]).collect(); + let settings = json!({ + "format": 1, + "example": "buche_rastrigin", + "objective": "minimize", + "x_label": "evaluations", + "y_label": "error", + "log_y": true, + "optimum": 0.0, + "plot": "contour", + "problem": { + "function": "buche_rastrigin", + "bounds": bounds, + "minima": minima, + }, + }); + write(&path, settings, frames.into_vec()); + Ok(()) +} + +// the frame of a generation: its progress, the errors of its best and of its population's median +// to `minimum` (rounding can put a solution a few ulps below it), and `state` +fn frame(snapshot: &Snapshot<'_, Reals>, state: Value, minimum: f64) -> Value { + let progress = snapshot.progress(); + let error = |value: f64| (value - minimum).max(0.0); + let population = snapshot.population().iter(); + let scores = population.filter_map(|individual| individual.fitness()?.score()); + json!({ + "generation": progress.generation(), + "evaluations": progress.evaluations(), + "best": progress.best().and_then(Fitness::score).map(error), + "median": median(scores.collect()).map(error), + "state": state, + }) +} + +// the median of the scores, None without any +fn median(mut scores: Vec) -> Option { + scores.sort_by(f64::total_cmp); + let middle = scores.len() / 2; + match scores.len() { + 0 => None, + n if n % 2 == 1 => Some(scores[middle]), + _ => Some((scores[middle - 1] + scores[middle]) / 2.0), + } +} + +// ---- the same in every example's trace --------------------------------------------------------- + +// the frames of at most `most` generations, from the part of the run where what the page plots +// changes: the frames after the last change are left out (a run that reached its target, or a +// front that no longer moves), and the rest are spread evenly over the generations up to it. While +// the run goes, up to 8 × `most` frames are kept: every `every`-th generation, with `every` +// doubling whenever there are that many, and the last one. +struct Frames { + most: usize, + every: u64, + kept: Vec<(u64, Value)>, + last: Option<(u64, Value)>, +} + +impl Frames { + fn new(most: usize) -> Self { + let (every, kept, last) = (1, Vec::new(), None); + Self { + most, + every, + kept, + last, + } + } + + fn push(&mut self, frame: Value) { + let generation = frame["generation"].as_u64().expect("a generation"); + if !generation.is_multiple_of(self.every) { + self.last = Some((generation, frame)); + return; + } + self.kept.push((generation, frame)); + self.last = None; + if self.kept.len() == 8 * self.most { + self.every *= 2; + let every = self.every; + self.kept.retain(|(generation, _)| generation % every == 0); + } + } + + fn into_vec(self) -> Vec { + let frames = self.kept.into_iter().chain(self.last); + let frames: Vec = frames.map(|(_, frame)| frame).collect(); + let active = &frames[..=last_change(&frames)]; + let (count, most) = (active.len(), self.most.max(2)); + if count <= most { + return active.to_vec(); + } + let at = |i: usize| active[(i * (count - 1) + (most - 1) / 2) / (most - 1)].clone(); + (0..most).map(at).collect() + } +} + +// the index of the frame after which nothing the page plots changes. To 3 significant digits, as +// a plot shows them: the best, the median and, for a single objective (a numeric best), the state; +// to within a hundredth of their range over the run: a front's hypervolumes, in the state or in a +// grid's series +fn last_change(frames: &[Value]) -> usize { + let Some(last) = frames.len().checked_sub(1) else { + return 0; + }; + let single = frames.iter().any(|frame| frame["best"].is_number()); + let measures = |frame: &Value| -> Vec { + let mut values = Vec::new(); + for value in [&frame["state"]["hypervolume"], &frame["series"]] { + match value { + Value::Number(number) => values.extend(number.as_f64()), + Value::Object(map) => values.extend(map.values().filter_map(Value::as_f64)), + _ => {} + } + } + values + }; + let measured: Vec> = frames.iter().map(measures).collect(); + let end = &measured[last]; + let tolerance: Vec = (0..end.len()) + .map(|k| { + let values = measured.iter().filter_map(|values| values.get(k).copied()); + let (low, high) = values.fold((f64::INFINITY, f64::NEG_INFINITY), |(low, high), v| { + (low.min(v), high.max(v)) + }); + (high - low) / 100.0 + }) + .collect(); + let settled = |i: usize| { + let (frame, final_frame) = (&frames[i], &frames[last]); + let same = + |key: &str, flush: bool| coarse(&frame[key], flush) == coarse(&final_frame[key], flush); + same("best", false) + && same("median", false) + && (!single || same("state", true)) + && measured[i].len() == end.len() + && measured[i] + .iter() + .zip(end) + .zip(&tolerance) + .all(|((value, end), tolerance)| (value - end).abs() <= *tolerance) + }; + let mut first = last; + while first > 0 && settled(first - 1) { + first -= 1; + } + first +} + +// `value` with its numbers to 3 significant digits, as precisely as a plot shows them: two frames +// whose plotted values agree to that precision look the same. With `flush`, for the solutions a +// plot draws on their ranges, numbers below 1e-6 in size count as 0 +fn coarse(value: &Value, flush: bool) -> String { + let join = |items: Vec| items.join(","); + match value { + Value::Number(number) if number.is_f64() => { + let number = number.as_f64().expect("f64"); + let number = if flush && number.abs() < 1e-6 { + 0.0 + } else { + number + }; + format!("{number:.2e}") + } + Value::Array(items) => { + format!( + "[{}]", + join(items.iter().map(|item| coarse(item, flush)).collect()) + ) + } + Value::Object(map) => { + let entry = |(key, item): (&String, &Value)| format!("{key}:{}", coarse(item, flush)); + format!("{{{}}}", join(map.iter().map(entry).collect())) + } + other => other.to_string(), + } +} + +// writes the settings and the frames to `path`, a frame per line +fn write(path: &str, settings: Value, frames: Vec) { + let frames: Vec = frames.iter().map(to_json).collect(); + let settings = to_json(&settings); + let head = &settings[..settings.len() - 1]; + let text = format!("{head},\"frames\":[\n{}\n]}}\n", frames.join(",\n")); + std::fs::write(path, text).expect("the trace is written"); +} + +// compact JSON with sorted keys, and numbers rounded to 6 significant digits and written as +// Python writes them (7542.0, 1e-08): the Python example writes the same file +fn to_json(value: &Value) -> String { + let join = |items: Vec| items.join(","); + match value { + Value::Number(number) if number.is_f64() => python_float(number.as_f64().expect("f64")), + Value::Array(items) => format!("[{}]", join(items.iter().map(to_json).collect())), + Value::Object(map) => { + let entry = + |(key, item): (&String, &Value)| format!("{}:{}", json!(key), to_json(item)); + format!("{{{}}}", join(map.iter().map(entry).collect())) + } + other => other.to_string(), + } +} + +fn python_float(value: f64) -> String { + let rounded: f64 = format!("{value:.5e}").parse().expect("a number"); + let shortest = format!("{rounded:e}"); + let (mantissa, exponent) = shortest.split_once('e').expect("an exponent"); + let exponent: i32 = exponent.parse().expect("an exponent"); + if (-4..16).contains(&exponent) { + let text = rounded.to_string(); + if text.contains('.') { + text + } else { + text + ".0" + } + } else { + let sign = if exponent < 0 { '-' } else { '+' }; + format!("{mantissa}e{sign}{:02}", exponent.abs()) + } +} diff --git a/examples/different_powers/README.md b/examples/different_powers/README.md new file mode 100644 index 00000000..1b6d8e6e --- /dev/null +++ b/examples/different_powers/README.md @@ -0,0 +1,84 @@ +--- +title: Different powers +category: continuous +summary: Minimize BBOB's different powers in 30 dimensions, exponents from 2 to 6 under a square root, as it is and shifted and rotated, and compare CMA-ES, sep-CMA-ES, DE, PSO and a GA. +reference: "Hansen, N., Finck, S., Ros, R. and Auger, A. (2009). Real-Parameter Black-Box Optimization Benchmarking 2009: Noiseless Functions Definitions. INRIA research report RR-6829." +reference_url: "https://hal.inria.fr/inria-00362633" +optimum: "0 (at the origin)" +languages: [rust, python] +order: 57 +trace_note: "Recorded from another run: CMA-ES in 2 dimensions on the function rotated with seed 1, so that the population can be drawn on the function's contour." +--- + +# Different powers + +## The problem + +BBOB's different powers raises each gene's absolute value to a power from 2 to 6, and takes the +square root of the sum: + +```text +f(x) = √(Σ |xᵢ|^(2 + 4 (i−1)/(n−1))), i from 1 to n, each xᵢ in [−5, 5] +``` + +Its minimum is 0, at the origin. Here n = 30. It's BBOB's f14 (Hansen et al. 2009), which rotates +it, with its search domain. It isn't the sum of different powers of Molga and Smutnicki, with +powers 2 to n + 1 and no square root. + +## What makes it hard + +Near the minimum, the genes' sensitivities drift apart: an error of 1e-8, under the square root, +needs the first gene within 10⁻⁸ of 0, but allows the last one, with its sixth power, to be +10⁻²·⁷ ≈ 0.002 away. The closer the search gets, the more different the scales it needs, so a +search must keep adapting them. Shifted and rotated, every direction mixes the powers. + +## Representation + +A `Real` genome of 30 genes: the point x itself. The fitness is f(x), to minimize. The function is +genoxide's `problems::DifferentPowers`, which brings its bounds and its minimum, and the shifted and rotated +instance `problems::Rotated::new(problems::Shifted::new(function, 1), 1)`, which keeps them. + +## Algorithm + +Five algorithms, each with a budget of 10,000 evaluations per dimension, 300,000 in all, and a +target of 1e-8, from seed 1: + +- CMA-ES (Hansen and Ostermeier, 2001, Evolutionary Computation 9(2): 159-195), which samples a + population of 14 from a normal distribution and adapts its mean, its step size and its covariance + matrix, from a step size of 0.3 of each gene's range and a random start; +- sep-CMA-ES (Ros and Hansen, 2008, PPSN X: 296-305), the same with a diagonal covariance matrix: a + scale per gene but no correlations; +- differential evolution with genoxide's defaults, SHADE (Tanabe and Fukunaga, CEC 2013), with a + population of 100; +- particle swarm optimization (Kennedy and Eberhart, 1995), 40 particles with Clerc and Kennedy's + constriction coefficients and a global topology; +- a real-coded genetic algorithm: a population of 100, tournaments of 3, simulated binary crossover + (Deb and Agrawal, 1995) with η = 15 and polynomial mutation with η = 20 at a rate of 1/30 per + gene. + +The second table runs the same algorithms on the function shifted and rotated, with genoxide's +`problems::Shifted` and `problems::Rotated` and seed 1: the minimum moves to a random point in the +middle 80% of the box, and an orthogonal matrix, drawn from normal numbers made orthonormal by +Gram-Schmidt as BBOB draws its rotations, turns the function about it. That's how the CEC and BBOB +suites use the function, with their own data; genoxide generates its instances instead. + +## Output + +The first line gives the dimension and the budget. Then two tables, the function as it is and shifted and rotated: a row per algorithm, the +evaluations it had used when its best error first reached each value of the heading, and the best +error it found, to two significant digits. A dash is an error not reached. The function is +evaluated with genoxide's portable math, so the runs are the same on every platform, and in Python, +`run` evaluates it in Rust, so both versions print the same. + +[The project page](https://tachsin.gr/projects/genoxide/examples/different-powers) plays back another +run: CMA-ES on the function in 2 dimensions, √(x₁² + x₂⁶), rotated with seed 1, so that the +population can be drawn on its contour. It meets the target after 714 evaluations. + +## Good results + +The minimum is 0. As it is, sep-CMA-ES reaches 1e-8 first, after 7,420 evaluations, then PSO +(23,080), SHADE (30,000) and CMA-ES (47,208); the genetic algorithm ends at 1.3e-6. + +Shifted and rotated, only CMA-ES reaches 1e-8, after 48,734 evaluations, about as many as before. +sep-CMA-ES ends at 3.9e-5, SHADE at 1.1e-5, PSO at 1.6e-4 and the genetic algorithm at 3.1e-3: +their scales per gene, or steps along the axes, no longer fit. diff --git a/examples/different_powers/main.py b/examples/different_powers/main.py new file mode 100644 index 00000000..bbed857e --- /dev/null +++ b/examples/different_powers/main.py @@ -0,0 +1,97 @@ +"""Different powers: minimize BBOB's different powers in 30 dimensions, exponents from 2 to 6 under +a square root, as it is and shifted and rotated, as BBOB does. + +Compares how fast CMA-ES, with a full and with a diagonal covariance matrix (sep-CMA-ES), +differential evolution, particle swarm optimization and a real-coded genetic algorithm close in on +the minimum, 0 at the origin: the evaluations each takes until its error is at most 1, 1e-2, 1e-4, 1e-6 and 1e-8. +The function is genoxide's `problems::DifferentPowers`. Then the same on the function shifted and rotated, with genoxide's `problems::Shifted` +and `problems::Rotated`, as the CEC and BBOB suites transform it. + +With ``GENOXIDE_TRACE=``, it also writes a trace of a run for the plot on the example's page, +with trace.py. + + python examples/different_powers/main.py +""" + +import genoxide as gx + +from trace import record_small + +DIMENSIONS = 30 +BUDGET = 10_000 * DIMENSIONS +# the errors at which the table gives each run's evaluations +ERRORS = [1e0, 1e-2, 1e-4, 1e-6, 1e-8] +COLUMNS = ["1", "1e-2", "1e-4", "1e-6", "1e-8"] + + +def error_text(error): + """An error to two significant digits, as Rust writes it: 9.9e-9.""" + mantissa, exponent = f"{error:.1e}".split("e") + return f"{mantissa}e{int(exponent)}" + + +class Reached: + """The evaluations after the first generation whose best error was at most each of ERRORS, + for a function whose minimum is ``minimum``.""" + + def __init__(self, minimum): + self.minimum = minimum + self.evaluations = [None] * len(ERRORS) + + def record(self, progress): + if progress.best_fitness is None: + return + error = progress.best_fitness - self.minimum + for i, bound in enumerate(ERRORS): + if self.evaluations[i] is None and error <= bound: + self.evaluations[i] = progress.evaluations + + def print(self, name, result): + """A row of the table: the evaluations, "-" for an error not reached, and the best + error.""" + cells = ["-" if reached is None else str(reached) for reached in self.evaluations] + # rounding can put a solution a few ulps below the minimum + cells.append(error_text(max(result.best_fitness - self.minimum, 0.0))) + print(f"{name:<10}" + "".join(f"{cell:>9}" for cell in cells)) + + +def compare(name, problem): + """The table of the five algorithms on ``problem``, after a line that names it.""" + minimum = problem.optimum.value + print(f"{name}: evaluations until the error is at most") + print(f"{'algorithm':<10}" + "".join(f"{column:>9}" for column in COLUMNS) + f"{'best':>9}") + genome = problem.genome + for label, algorithm in ( + ("CMA-ES", gx.Cmaes(genome, objective="minimize", seed=1)), + ("sep-CMA-ES", gx.Cmaes(genome, covariance="diagonal", objective="minimize", seed=1)), + ("DE", gx.De(genome, objective="minimize", seed=1)), + ("PSO", gx.Pso(genome, population_size=40, objective="minimize", seed=1)), + ( + "GA", + gx.Ga( + genome, + population_size=100, + select=gx.Tournament(3), + crossover=gx.SimulatedBinaryCrossover(15.0), + mutation=gx.PolynomialMutation(20.0, rate=1 / DIMENSIONS), + objective="minimize", + seed=1, + ), + ), + ): + reached = Reached(minimum) + result = algorithm.run( + problem, target=minimum + 1e-8, evaluations=BUDGET, on_generation=reached.record + ) + reached.print(label, result) + + +print(f"Different powers in {DIMENSIONS} dimensions, {BUDGET} evaluations at most") +compare("Different powers", gx.problems.DifferentPowers(DIMENSIONS)) +# BBOB's f14, with genoxide's own shift and rotation +rotated = gx.problems.Rotated(gx.problems.Shifted(gx.problems.DifferentPowers(DIMENSIONS), seed=1), seed=1) +compare("Shifted and rotated (seed 1)", rotated) + +# with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate run in +# 2 dimensions: the plot is the function's contour +record_small() diff --git a/examples/different_powers/main.rs b/examples/different_powers/main.rs new file mode 100644 index 00000000..86814c70 --- /dev/null +++ b/examples/different_powers/main.rs @@ -0,0 +1,151 @@ +//! Different powers: minimize BBOB's different powers in 30 dimensions, exponents from 2 to 6 under +//! a square root, as it is and shifted and rotated, as BBOB does. +//! +//! Compares how fast CMA-ES, with a full and with a diagonal covariance matrix (sep-CMA-ES), +//! differential evolution, particle swarm optimization and a real-coded genetic algorithm close in +//! on the minimum, 0 at the origin: the evaluations each takes until its error is at most 1, 1e-2, 1e-4, 1e-6 and 1e-8. +//! The function is genoxide's `problems::DifferentPowers`. Then the same on the function shifted and rotated, with genoxide's `problems::Shifted` +//! and `problems::Rotated`, as the CEC and BBOB suites transform it. +//! +//! With `GENOXIDE_TRACE=`, it also writes a trace of a run for the plot on the example's +//! page, with `trace.rs`. +//! +//! ```text +//! cargo run --release --example different_powers +//! ``` + +mod trace; + +use genoxide::observer::Snapshot; +use genoxide::prelude::*; +use genoxide::problems::{DifferentPowers, Problem, Rotated, Shifted}; + +const DIMENSIONS: usize = 30; +const BUDGET: u64 = 10_000 * DIMENSIONS as u64; +// the errors at which the table gives each run's evaluations +const ERRORS: [f64; 5] = [1e0, 1e-2, 1e-4, 1e-6, 1e-8]; +const COLUMNS: [&str; 5] = ["1", "1e-2", "1e-4", "1e-6", "1e-8"]; + +fn main() -> Result<()> { + println!("Different powers in {DIMENSIONS} dimensions, {BUDGET} evaluations at most"); + compare("Different powers", &DifferentPowers::new(DIMENSIONS))?; + // BBOB's f14, with genoxide's own shift and rotation + let rotated = Rotated::new(Shifted::new(DifferentPowers::new(DIMENSIONS), 1), 1); + compare("Shifted and rotated (seed 1)", &rotated)?; + // with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate + // run in 2 dimensions: the plot is the function's contour + trace::record_small()?; + Ok(()) +} + +// the table of the five algorithms on `problem`, after a line that names it +fn compare

(name: &str, problem: &P) -> Result<()> +where + P: Problem + FitnessFunction + Clone, +{ + let minimum = problem.optimum().expect("known").value(); + let stop = || Stop::target(minimum + 1e-8).or(Stop::evaluations(BUDGET)); + println!("{name}: evaluations until the error is at most"); + print!("{:<10}", "algorithm"); + COLUMNS.iter().for_each(|column| print!("{column:>9}")); + println!("{:>9}", "best"); + + for (name, covariance) in [ + ("CMA-ES", cmaes::Covariance::Full), + ("sep-CMA-ES", cmaes::Covariance::Diagonal), + ] { + let cmaes = Cmaes::builder(problem.representation()) + .covariance(covariance) + .minimize() + .seed(1) + .build()?; + let mut reached = Reached::new(minimum); + let outcome = Engine::new(cmaes, problem.clone()) + .stop_when(stop()) + .on_generation(|snapshot| reached.record(snapshot)) + .run()?; + reached.print(name, &outcome); + } + + let de = De::builder(problem.representation()) + .minimize() + .seed(1) + .build()?; + let mut reached = Reached::new(minimum); + let outcome = Engine::new(de, problem.clone()) + .stop_when(stop()) + .on_generation(|snapshot| reached.record(snapshot)) + .run()?; + reached.print("DE", &outcome); + + let pso = Pso::builder(problem.representation()) + .population_size(40) + .minimize() + .seed(1) + .build()?; + let mut reached = Reached::new(minimum); + let outcome = Engine::new(pso, problem.clone()) + .stop_when(stop()) + .on_generation(|snapshot| reached.record(snapshot)) + .run()?; + reached.print("PSO", &outcome); + + let ga = Ga::builder(problem.representation()) + .population_size(100) + .select(Tournament::new(3)?) + .crossover(SimulatedBinaryCrossover::new(15.0)?) + .mutate(PolynomialMutation::per_gene(1.0 / DIMENSIONS as f64, 20.0)?) + .minimize() + .seed(1) + .build()?; + let mut reached = Reached::new(minimum); + let outcome = Engine::new(ga, problem.clone()) + .stop_when(stop()) + .on_generation(|snapshot| reached.record(snapshot)) + .run()?; + reached.print("GA", &outcome); + Ok(()) +} + +// the evaluations after the first generation whose best error was at most each of ERRORS, for a +// function whose minimum is `minimum` +struct Reached { + minimum: f64, + evaluations: [Option; 5], +} + +impl Reached { + fn new(minimum: f64) -> Self { + let evaluations = [None; 5]; + Self { + minimum, + evaluations, + } + } + + fn record(&mut self, snapshot: &Snapshot<'_, Reals>) { + let progress = snapshot.progress(); + let Some(best) = progress.best().and_then(Fitness::score) else { + return; + }; + let error = best - self.minimum; + for (reached, bound) in self.evaluations.iter_mut().zip(ERRORS) { + if reached.is_none() && error <= bound { + *reached = Some(progress.evaluations()); + } + } + } + + // a row of the table: the evaluations, "-" for an error not reached, and the best error + fn print(&self, name: &str, outcome: &Outcome) { + print!("{name:<10}"); + for reached in self.evaluations { + let reached = reached.map_or("-".to_string(), |evaluations| evaluations.to_string()); + print!("{reached:>9}"); + } + // rounding can put a solution a few ulps below the minimum + let best = outcome.best_fitness().score().expect("valid"); + let error = (best - self.minimum).max(0.0); + println!("{:>9}", format!("{error:.1e}")); + } +} diff --git a/examples/different_powers/output.txt b/examples/different_powers/output.txt new file mode 100644 index 00000000..03801ea0 --- /dev/null +++ b/examples/different_powers/output.txt @@ -0,0 +1,15 @@ +Different powers in 30 dimensions, 300000 evaluations at most +Different powers: evaluations until the error is at most +algorithm 1 1e-2 1e-4 1e-6 1e-8 best +CMA-ES 798 2954 12026 27342 47208 9.9e-9 +sep-CMA-ES 812 2240 3864 5558 7420 9.9e-9 +DE 4800 11100 16500 23400 30000 7.1e-9 +PSO 2720 8000 13000 17680 23080 9.6e-9 +GA 4280 18230 82461 - - 1.3e-6 +Shifted and rotated (seed 1): evaluations until the error is at most +algorithm 1 1e-2 1e-4 1e-6 1e-8 best +CMA-ES 1078 3010 12488 28714 48734 9.6e-9 +sep-CMA-ES 1064 2772 99750 - - 3.9e-5 +DE 5500 15500 63200 - - 1.1e-5 +PSO 6760 23760 - - - 1.6e-4 +GA 6702 65310 - - - 3.1e-3 diff --git a/examples/different_powers/trace.json b/examples/different_powers/trace.json new file mode 100644 index 00000000..8b816644 --- /dev/null +++ b/examples/different_powers/trace.json @@ -0,0 +1,102 @@ +{"example":"different_powers","format":1,"log_y":true,"objective":"minimize","optimum":0.0,"plot":"contour","problem":{"bounds":[[-5.0,5.0],[-5.0,5.0]],"function":"different_powers","minima":[[0.0,0.0]],"rotation":{"center":[0.0,0.0],"matrix":[[-0.973552,0.228466],[-0.228466,-0.973552]]}},"x_label":"evaluations","y_label":"error","frames":[ +{"best":2.52311,"evaluations":6,"generation":0,"median":24.4417,"state":{"best":[2.14496,-1.42894],"population":[[-4.02856,-1.2232],[1.09727,-3.0536],[-2.70235,3.76881],[-1.07094,-4.64995],[-3.75609,-3.6306],[2.14496,-1.42894]]}}, +{"best":0.797558,"evaluations":12,"generation":1,"median":4.33668,"state":{"best":[0.173862,0.911386],"population":[[-2.39339,-0.53549],[4.18068,-0.460566],[2.70245,-2.22152],[0.173862,0.911386],[-4.0865,1.92524],[-1.89372,-4.25078]]}}, +{"best":0.797558,"evaluations":18,"generation":2,"median":22.7265,"state":{"best":[0.173862,0.911386],"population":[[-0.0643983,2.62445],[0.875074,2.43043],[-4.50249,1.67169],[-4.41938,4.15864],[-3.51316,4.93281],[0.715003,-4.16082]]}}, +{"best":0.797558,"evaluations":30,"generation":4,"median":3.68649,"state":{"best":[0.173862,0.911386],"population":[[-3.29248,3.03371],[-1.38133,0.778033],[-0.940062,-2.26552],[-2.22299,-0.0635557],[0.564956,-1.53481],[-4.64211,0.675574]]}}, +{"best":0.797558,"evaluations":36,"generation":5,"median":3.94645,"state":{"best":[0.173862,0.911386],"population":[[-1.18733,1.9608],[-3.50093,-0.544455],[-1.87417,0.46576],[-2.66099,1.99215],[-3.37294,-0.188141],[-3.04035,2.42007]]}}, +{"best":0.797558,"evaluations":42,"generation":6,"median":4.45564,"state":{"best":[0.173862,0.911386],"population":[[-1.85976,-2.13145],[-3.86851,2.1621],[-3.85933,1.0747],[-1.66469,2.93892],[-1.65519,1.43362],[-3.65896,2.022]]}}, +{"best":0.797558,"evaluations":48,"generation":7,"median":2.81022,"state":{"best":[0.173862,0.911386],"population":[[-2.02552,2.55794],[-1.48815,1.64318],[-3.68015,0.47122],[-1.6187,1.59032],[-1.30381,0.0757771],[-1.60943,1.70541]]}}, +{"best":0.797558,"evaluations":54,"generation":8,"median":2.21001,"state":{"best":[0.173862,0.911386],"population":[[-3.34352,2.19487],[-3.91211,0.0780821],[-1.66617,-0.146072],[-1.22937,0.8745],[-2.53761,1.38738],[-0.728952,-0.900077]]}}, +{"best":0.436756,"evaluations":66,"generation":10,"median":2.09848,"state":{"best":[0.4278,0.615547],"population":[[-1.73976,2.40191],[-0.0913383,1.36722],[-2.29268,0.579212],[-0.778819,1.37979],[0.4278,0.615547],[-0.620716,0.296044]]}}, +{"best":0.436756,"evaluations":72,"generation":11,"median":2.92227,"state":{"best":[0.4278,0.615547],"population":[[0.269368,0.897931],[1.54871,2.60745],[-0.93508,0.638346],[-0.740604,1.764],[1.68263,-1.19308],[-1.12691,1.83631]]}}, +{"best":0.162638,"evaluations":78,"generation":12,"median":1.47771,"state":{"best":[0.0450751,-0.441826],"population":[[-0.98756,1.60348],[1.27911,1.02254],[-0.331853,0.645542],[0.0450751,-0.441826],[-0.718119,2.52068],[0.678616,0.42026]]}}, +{"best":0.162638,"evaluations":84,"generation":13,"median":1.01629,"state":{"best":[0.0450751,-0.441826],"population":[[0.116083,1.00405],[0.910953,-0.209364],[-0.667802,-0.463147],[1.91979,-0.366977],[-0.882645,0.66037],[2.02889,-1.04527]]}}, +{"best":0.162638,"evaluations":90,"generation":14,"median":0.641493,"state":{"best":[0.0450751,-0.441826],"population":[[0.389621,0.746768],[0.2187,0.861004],[-0.558438,-1.29643],[0.0900065,-0.715081],[0.209361,-0.0435227],[-0.438327,-1.22856]]}}, +{"best":0.162638,"evaluations":96,"generation":15,"median":0.860725,"state":{"best":[0.0450751,-0.441826],"population":[[0.971679,-0.652308],[0.760139,-0.11927],[0.355996,0.340026],[0.795134,0.72628],[0.975514,-0.102824],[0.0817448,-0.946339]]}}, +{"best":0.0178748,"evaluations":108,"generation":17,"median":0.426707,"state":{"best":[-0.0140676,-0.137372],"population":[[-0.718167,-0.325025],[-0.295836,0.0180659],[0.512233,0.0316955],[0.686763,0.042829],[0.370927,-0.00368375],[-0.0140676,-0.137372]]}}, +{"best":0.0178748,"evaluations":114,"generation":18,"median":0.278679,"state":{"best":[-0.0140676,-0.137372],"population":[[0.0480658,-0.291677],[0.224009,0.208909],[0.562915,-0.055462],[0.119557,-0.693107],[0.397806,-0.515234],[0.0605878,0.149639]]}}, +{"best":0.00430469,"evaluations":120,"generation":19,"median":0.162016,"state":{"best":[0.0296161,0.140011],"population":[[0.0538593,-0.227925],[-0.13298,0.380216],[-0.273267,-0.208899],[-0.0358775,-0.254484],[0.0296161,0.140011],[0.54059,0.322023]]}}, +{"best":0.00430469,"evaluations":126,"generation":20,"median":0.12483,"state":{"best":[0.0296161,0.140011],"population":[[-0.169362,-0.00862537],[0.186429,0.0171171],[-0.0432173,-0.0143119],[-0.0191145,-0.138108],[0.106799,0.075422],[0.332498,0.0602621]]}}, +{"best":0.00430469,"evaluations":132,"generation":21,"median":0.119944,"state":{"best":[0.0296161,0.140011],"population":[[0.0039678,-0.00233383],[0.0167105,-0.0499212],[-0.016496,-0.375286],[0.187988,0.127525],[-0.20834,0.162931],[0.174616,-0.205418]]}}, +{"best":0.00430469,"evaluations":144,"generation":23,"median":0.0559546,"state":{"best":[0.0296161,0.140011],"population":[[0.0715924,-2.76075e-05],[0.0193316,-0.102312],[-0.054904,-0.152008],[-0.150398,-0.217113],[0.0420828,0.0533858],[0.0867726,-0.134172]]}}, +{"best":0.00136697,"evaluations":150,"generation":24,"median":0.0238168,"state":{"best":[-0.0208527,-0.0835691],"population":[[-0.0457309,-0.0841813],[-0.0208527,-0.0835691],[-0.0225119,-0.0824418],[-0.0073544,-0.128678],[0.0301674,-0.0859428],[0.0170144,-0.162124]]}}, +{"best":0.00136697,"evaluations":156,"generation":25,"median":0.0178255,"state":{"best":[-0.0208527,-0.0835691],"population":[[-0.00625427,-0.0864946],[0.0245068,-0.0206208],[-0.0394344,-0.135781],[-0.00586265,-0.0578631],[-0.0569053,-0.14785],[0.0328624,-0.0142249]]}}, +{"best":0.00136697,"evaluations":162,"generation":26,"median":0.0105403,"state":{"best":[-0.0208527,-0.0835691],"population":[[-0.0320116,-0.0916014],[-0.024202,-0.0580962],[-0.0277364,-0.0768607],[-0.0473462,-0.0824121],[-0.00387701,-0.063732],[-0.0472907,-0.0672109]]}}, +{"best":0.00136697,"evaluations":168,"generation":27,"median":0.00924445,"state":{"best":[-0.0208527,-0.0835691],"population":[[-0.0268532,-0.0688776],[0.00733683,-0.0607642],[0.000678325,-0.0324527],[-0.02154,-0.0968646],[-0.00176948,-0.097438],[-0.0148234,-0.0775697]]}}, +{"best":0.00136697,"evaluations":180,"generation":29,"median":0.0108929,"state":{"best":[-0.0208527,-0.0835691],"population":[[-0.0400265,-0.121042],[-0.0261661,-0.109321],[-0.0173131,-0.118114],[-0.00525722,-0.0781376],[-0.0478303,-0.0880096],[-0.0355958,-0.107082]]}}, +{"best":0.00136697,"evaluations":186,"generation":30,"median":0.00641003,"state":{"best":[-0.0208527,-0.0835691],"population":[[-0.0270593,-0.0925287],[-0.0144776,-0.0826641],[-0.00856884,-0.103691],[-0.0390086,-0.135578],[-0.0259831,-0.107358],[-0.0158892,-0.112103]]}}, +{"best":0.00136697,"evaluations":192,"generation":31,"median":0.00383481,"state":{"best":[-0.0208527,-0.0835691],"population":[[-0.0181293,-0.0948578],[-0.0306551,-0.117181],[-0.0180827,-0.115427],[-0.0209079,-0.0987645],[-0.0159515,-0.0814993],[-0.0302786,-0.0801674]]}}, +{"best":0.00078052,"evaluations":198,"generation":32,"median":0.00372498,"state":{"best":[-0.0207778,-0.0891636],"population":[[-0.0260254,-0.0850392],[-0.0200208,-0.0973289],[-0.0207778,-0.0891636],[-0.0170533,-0.0921913],[-0.0175934,-0.100668],[-0.0187087,-0.0872524]]}}, +{"best":0.00078052,"evaluations":204,"generation":33,"median":0.00187289,"state":{"best":[-0.0207778,-0.0891636],"population":[[-0.0194385,-0.0764506],[-0.0185483,-0.0816525],[-0.0271337,-0.0959928],[-0.01927,-0.0946925],[-0.0223853,-0.086236],[-0.0204571,-0.084174]]}}, +{"best":0.00078052,"evaluations":216,"generation":35,"median":0.00153671,"state":{"best":[-0.0207778,-0.0891636],"population":[[-0.0208068,-0.103282],[-0.0214173,-0.0884516],[-0.0231449,-0.0996578],[-0.0204807,-0.0842566],[-0.0219607,-0.0804489],[-0.018765,-0.0880071]]}}, +{"best":0.000651469,"evaluations":222,"generation":36,"median":0.000994842,"state":{"best":[-0.0197601,-0.083511],"population":[[-0.0199452,-0.0875963],[-0.0213744,-0.0878015],[-0.0203123,-0.0819368],[-0.0211968,-0.0847507],[-0.0195936,-0.0821127],[-0.0197601,-0.083511]]}}, +{"best":0.000651469,"evaluations":228,"generation":37,"median":0.00158325,"state":{"best":[-0.0197601,-0.083511],"population":[[-0.0180875,-0.0790744],[-0.021891,-0.0830916],[-0.0161293,-0.0823193],[-0.0202646,-0.0823365],[-0.0227291,-0.0884532],[-0.0163564,-0.0727718]]}}, +{"best":0.000651469,"evaluations":234,"generation":38,"median":0.00206587,"state":{"best":[-0.0197601,-0.083511],"population":[[-0.0191996,-0.0831463],[-0.0123607,-0.072803],[-0.0159844,-0.0744178],[-0.0210012,-0.0804688],[-0.0193314,-0.0922735],[-0.0156269,-0.0750822]]}}, +{"best":0.000651469,"evaluations":240,"generation":39,"median":0.0010061,"state":{"best":[-0.0197601,-0.083511],"population":[[-0.0190133,-0.076494],[-0.0201424,-0.085696],[-0.0209285,-0.0898031],[-0.0158636,-0.0710561],[-0.0115314,-0.063654],[-0.0205114,-0.0832844]]}}, +{"best":0.000651469,"evaluations":252,"generation":41,"median":0.00164619,"state":{"best":[-0.0197601,-0.083511],"population":[[-0.0206722,-0.0912349],[-0.0210436,-0.0910442],[-0.0178931,-0.0848749],[-0.0238264,-0.0945544],[-0.0183464,-0.0838828],[-0.0227268,-0.0883757]]}}, +{"best":0.000651469,"evaluations":258,"generation":42,"median":0.000964467,"state":{"best":[-0.0197601,-0.083511],"population":[[-0.0225806,-0.095359],[-0.0219451,-0.0946857],[-0.0190152,-0.0876532],[-0.023449,-0.105434],[-0.0204403,-0.0878365],[-0.0215431,-0.0935219]]}}, +{"best":0.000651469,"evaluations":264,"generation":43,"median":0.00089351,"state":{"best":[-0.0197601,-0.083511],"population":[[-0.0190643,-0.0855859],[-0.0197304,-0.0849083],[-0.0215607,-0.0910487],[-0.0218603,-0.0922418],[-0.0211552,-0.0930767],[-0.0221017,-0.0931041]]}}, +{"best":0.000595554,"evaluations":270,"generation":44,"median":0.000740452,"state":{"best":[-0.0187054,-0.0805316],"population":[[-0.0202562,-0.0879308],[-0.0187054,-0.0805316],[-0.0211971,-0.0902036],[-0.0200607,-0.0859738],[-0.0203338,-0.0876521],[-0.0200931,-0.0843053]]}}, +{"best":0.000595554,"evaluations":276,"generation":45,"median":0.000896777,"state":{"best":[-0.0187054,-0.0805316],"population":[[-0.0191532,-0.0830454],[-0.0193615,-0.0803531],[-0.0207721,-0.0887279],[-0.0183204,-0.0856635],[-0.0182324,-0.0814427],[-0.0174504,-0.0784245]]}}, +{"best":0.000590525,"evaluations":282,"generation":46,"median":0.00070147,"state":{"best":[-0.018708,-0.0804834],"population":[[-0.0188102,-0.0758895],[-0.0182319,-0.0791934],[-0.0188354,-0.0820784],[-0.0222825,-0.0926206],[-0.018708,-0.0804834],[-0.0172564,-0.0756702]]}}, +{"best":0.000590525,"evaluations":294,"generation":48,"median":0.000707136,"state":{"best":[-0.018708,-0.0804834],"population":[[-0.0200728,-0.0857579],[-0.017315,-0.0759141],[-0.0191586,-0.081715],[-0.0201186,-0.084291],[-0.020429,-0.0876072],[-0.0190343,-0.0842197]]}}, +{"best":0.000550703,"evaluations":300,"generation":49,"median":0.000594536,"state":{"best":[-0.0179176,-0.0773559],"population":[[-0.0194014,-0.084783],[-0.0179176,-0.0773559],[-0.0186243,-0.0780003],[-0.0201578,-0.0856404],[-0.0189083,-0.0810499],[-0.0178843,-0.0774712]]}}, +{"best":0.00046031,"evaluations":306,"generation":50,"median":0.00050219,"state":{"best":[-0.0176107,-0.0751439],"population":[[-0.0169025,-0.074195],[-0.0178893,-0.0769225],[-0.0176107,-0.0751439],[-0.018851,-0.0819235],[-0.0177089,-0.0759481],[-0.0176376,-0.0755436]]}}, +{"best":0.000400996,"evaluations":312,"generation":51,"median":0.000512316,"state":{"best":[-0.0168537,-0.0717856],"population":[[-0.0183255,-0.0779967],[-0.0178402,-0.0750504],[-0.0168537,-0.0717856],[-0.0172393,-0.075596],[-0.0184504,-0.0772842],[-0.0166927,-0.0714778]]}}, +{"best":0.000400996,"evaluations":318,"generation":52,"median":0.000713516,"state":{"best":[-0.0168537,-0.0717856],"population":[[-0.0171587,-0.0741457],[-0.0173039,-0.0709454],[-0.0193532,-0.0803041],[-0.0173412,-0.0746171],[-0.0177889,-0.0777812],[-0.0181295,-0.0795961]]}}, +{"best":0.000376503,"evaluations":330,"generation":54,"median":0.000521819,"state":{"best":[-0.0160168,-0.0688262],"population":[[-0.0159749,-0.0698351],[-0.0159282,-0.0695101],[-0.0184241,-0.0782566],[-0.0164684,-0.0684172],[-0.0168964,-0.071981],[-0.0171135,-0.0733043]]}}, +{"best":0.000315375,"evaluations":336,"generation":55,"median":0.000523922,"state":{"best":[-0.0152341,-0.0643677],"population":[[-0.0183911,-0.0769173],[-0.0152341,-0.0643677],[-0.017012,-0.0741137],[-0.0163423,-0.0702757],[-0.0178269,-0.0780571],[-0.0177662,-0.0752787]]}}, +{"best":0.000258806,"evaluations":342,"generation":56,"median":0.000359227,"state":{"best":[-0.0145564,-0.0618992],"population":[[-0.0147518,-0.0627664],[-0.0165067,-0.068748],[-0.015644,-0.0649478],[-0.0154355,-0.0649189],[-0.0145564,-0.0618992],[-0.0163057,-0.0693796]]}}, +{"best":0.00021336,"evaluations":348,"generation":57,"median":0.00031455,"state":{"best":[-0.0135186,-0.0573394],"population":[[-0.0152391,-0.065026],[-0.0136138,-0.0571341],[-0.0135186,-0.0573394],[-0.0151064,-0.0655523],[-0.0122082,-0.0532801],[-0.0158086,-0.067156]]}}, +{"best":0.00021336,"evaluations":354,"generation":58,"median":0.000395115,"state":{"best":[-0.0135186,-0.0573394],"population":[[-0.013646,-0.0572069],[-0.0121722,-0.0510076],[-0.0136439,-0.0564635],[-0.0170046,-0.0703137],[-0.0162348,-0.0689205],[-0.0155614,-0.0647948]]}}, +{"best":0.000133545,"evaluations":366,"generation":60,"median":0.000337669,"state":{"best":[-0.0111122,-0.0470399],"population":[[-0.0113472,-0.0475481],[-0.00770324,-0.0307966],[-0.0143507,-0.0625305],[-0.00501445,-0.0193685],[-0.0145479,-0.0621883],[-0.011291,-0.0485709]]}}, +{"best":0.000133545,"evaluations":372,"generation":61,"median":0.000496796,"state":{"best":[-0.0111122,-0.0470399],"population":[[-0.0147728,-0.0612711],[-0.00984071,-0.0442417],[-0.00765002,-0.0301515],[-0.00766553,-0.0310556],[-0.00929165,-0.0386522],[-0.013874,-0.0564002]]}}, +{"best":6.80223e-05,"evaluations":378,"generation":62,"median":0.000463076,"state":{"best":[-0.00918242,-0.0390338],"population":[[-0.00918242,-0.0390338],[-0.00437012,-0.0167946],[-0.00585073,-0.0219465],[-0.00547997,-0.0207214],[-0.00439041,-0.0164827],[-0.0103012,-0.0453984]]}}, +{"best":6.80223e-05,"evaluations":384,"generation":63,"median":0.000227704,"state":{"best":[-0.00918242,-0.0390338],"population":[[-0.0079847,-0.0350611],[-2.2259e-06,0.00132815],[-0.00883947,-0.0370297],[-0.0106961,-0.0460777],[-0.0136732,-0.0582183],[-0.0101666,-0.0445469]]}}, +{"best":4.61822e-05,"evaluations":390,"generation":64,"median":0.000108788,"state":{"best":[-0.00708917,-0.0303613],"population":[[-0.00862384,-0.0360892],[-0.00708917,-0.0303613],[-0.0105798,-0.0451732],[-0.00977926,-0.0420357],[-0.00800295,-0.0338223],[-0.00962609,-0.0416593]]}}, +{"best":3.2956e-05,"evaluations":402,"generation":66,"median":0.000146968,"state":{"best":[-0.00732116,-0.0312036],"population":[[-0.00363056,-0.0143337],[-0.00787213,-0.0338549],[-0.00866814,-0.0364551],[-0.00663069,-0.0272303],[-0.00678774,-0.0285711],[-0.00900413,-0.0376609]]}}, +{"best":3.2956e-05,"evaluations":408,"generation":67,"median":0.00015702,"state":{"best":[-0.00732116,-0.0312036],"population":[[-0.00377399,-0.0153045],[-0.00884006,-0.0371247],[-0.0127165,-0.0535408],[-0.00695356,-0.0294184],[-0.00766799,-0.0324626],[-0.0101966,-0.0426804]]}}, +{"best":3.2956e-05,"evaluations":414,"generation":68,"median":0.000112479,"state":{"best":[-0.00732116,-0.0312036],"population":[[-0.00623314,-0.0262487],[-0.0073102,-0.0310395],[-0.00519617,-0.0226355],[-0.00856625,-0.0370234],[-0.00941084,-0.03966],[-0.00843902,-0.0355214]]}}, +{"best":3.2956e-05,"evaluations":420,"generation":69,"median":0.000139625,"state":{"best":[-0.00732116,-0.0312036],"population":[[-0.00798781,-0.0337573],[-0.00901103,-0.0391101],[-0.00636972,-0.0273196],[-0.00490768,-0.0200642],[-0.00660095,-0.0276834],[-0.00664501,-0.0275059]]}}, +{"best":1.43981e-05,"evaluations":426,"generation":70,"median":3.71196e-05,"state":{"best":[-0.00543494,-0.0231369],"population":[[-0.00543494,-0.0231369],[-0.0060841,-0.0259111],[-0.00620892,-0.0266948],[-0.00613219,-0.0259571],[-0.00695423,-0.0296801],[-0.00709051,-0.0303608]]}}, +{"best":1.40689e-05,"evaluations":438,"generation":72,"median":6.38085e-05,"state":{"best":[-0.00541333,-0.0230872],"population":[[-0.00600019,-0.025345],[-0.00379013,-0.0162597],[-0.00588579,-0.0247669],[-0.00540514,-0.0229748],[-0.00706588,-0.0304438],[-0.0066952,-0.0288602]]}}, +{"best":7.93372e-06,"evaluations":444,"generation":73,"median":8.68173e-05,"state":{"best":[-0.00419893,-0.017871],"population":[[-0.00462723,-0.0197447],[-0.00580726,-0.0250284],[-0.00431874,-0.0189161],[-0.00487918,-0.0213011],[-0.00455373,-0.0198714],[-0.00419893,-0.017871]]}}, +{"best":7.93372e-06,"evaluations":450,"generation":74,"median":6.44916e-05,"state":{"best":[-0.00419893,-0.017871],"population":[[-0.00695285,-0.0296803],[-0.00664431,-0.0283856],[-0.00470324,-0.0203862],[-0.00589603,-0.0248181],[-0.00133455,-0.00601911],[-0.00468317,-0.0197092]]}}, +{"best":7.93372e-06,"evaluations":456,"generation":75,"median":5.19467e-05,"state":{"best":[-0.00419893,-0.017871],"population":[[-0.0050796,-0.0218667],[-0.00675895,-0.0291402],[-0.00506595,-0.0216391],[-0.00547239,-0.022863],[-0.00706423,-0.0299267],[-0.00783807,-0.0332533]]}}, +{"best":7.93372e-06,"evaluations":462,"generation":76,"median":3.68995e-05,"state":{"best":[-0.00419893,-0.017871],"population":[[-0.00724875,-0.031049],[-0.0080159,-0.0341651],[-0.00535472,-0.0227591],[-0.00659808,-0.0282301],[-0.00499235,-0.0213707],[-0.00650066,-0.0275669]]}}, +{"best":7.93372e-06,"evaluations":468,"generation":77,"median":2.10526e-05,"state":{"best":[-0.00419893,-0.017871],"population":[[-0.00425821,-0.0181187],[-0.00580167,-0.0246156],[-0.00404365,-0.0171654],[-0.00581689,-0.0247027],[-0.00539081,-0.023073],[-0.00467281,-0.0198486]]}}, +{"best":7.93372e-06,"evaluations":480,"generation":79,"median":1.26882e-05,"state":{"best":[-0.00419893,-0.017871],"population":[[-0.00506345,-0.0215616],[-0.00497855,-0.0212208],[-0.00600345,-0.0255167],[-0.00609769,-0.0259977],[-0.00524067,-0.0223624],[-0.00483998,-0.0206256]]}}, +{"best":5.67958e-06,"evaluations":486,"generation":80,"median":9.48057e-06,"state":{"best":[-0.00380526,-0.0162296],"population":[[-0.00419736,-0.0178477],[-0.00505388,-0.0215259],[-0.00374313,-0.0158151],[-0.0042771,-0.0182328],[-0.00380526,-0.0162296],[-0.00457742,-0.0194975]]}}, +{"best":4.15963e-06,"evaluations":492,"generation":81,"median":9.33414e-06,"state":{"best":[-0.00304178,-0.0129468],"population":[[-0.0028291,-0.0119546],[-0.00317972,-0.0135955],[-0.00458572,-0.0195222],[-0.00434257,-0.0185336],[-0.00466291,-0.0198639],[-0.00304178,-0.0129468]]}}, +{"best":4.15963e-06,"evaluations":498,"generation":82,"median":2.06957e-05,"state":{"best":[-0.00304178,-0.0129468],"population":[[-0.00255422,-0.0109519],[-0.0031901,-0.0136451],[-0.00360774,-0.0152617],[-0.0041519,-0.0178233],[-0.00470285,-0.0201294],[-0.00394325,-0.0168839]]}}, +{"best":3.47686e-06,"evaluations":504,"generation":83,"median":1.14229e-05,"state":{"best":[-0.00241729,-0.010315],"population":[[-0.00241729,-0.010315],[-0.00363733,-0.0156475],[-0.00351371,-0.0149545],[-0.00179178,-0.0076619],[-0.00297709,-0.0127587],[-4.96935e-05,-0.000305699]]}}, +{"best":1.28488e-06,"evaluations":516,"generation":85,"median":7.94321e-06,"state":{"best":[-0.0011561,-0.00493202],"population":[[-0.00307039,-0.0130486],[-0.00255129,-0.0109283],[-0.00233477,-0.00988228],[-0.00316058,-0.0134373],[-0.000645595,-0.00272788],[-0.00131939,-0.00559149]]}}, +{"best":1.28488e-06,"evaluations":522,"generation":86,"median":2.01678e-05,"state":{"best":[-0.0011561,-0.00493202],"population":[[-0.00221021,-0.00927534],[-0.000577762,-0.00242071],[-0.001658,-0.00696766],[0.000283291,0.00135244],[-0.00199384,-0.00857187],[0.000227689,0.00104928]]}}, +{"best":1.28488e-06,"evaluations":528,"generation":87,"median":1.1259e-05,"state":{"best":[-0.0011561,-0.00493202],"population":[[-0.00249959,-0.0105812],[-0.00171144,-0.00733159],[0.00255341,0.0109275],[-0.000342358,-0.00140753],[0.000222211,0.000882373],[-0.0030767,-0.0131256]]}}, +{"best":1.28488e-06,"evaluations":534,"generation":88,"median":6.1961e-06,"state":{"best":[-0.0011561,-0.00493202],"population":[[-0.00359623,-0.0154078],[-0.00337267,-0.0144404],[-0.00290802,-0.0123656],[-0.00144171,-0.00617004],[-0.000381382,-0.00164276],[-0.00132727,-0.00564564]]}}, +{"best":1.28488e-06,"evaluations":540,"generation":89,"median":6.30027e-06,"state":{"best":[-0.0011561,-0.00493202],"population":[[-0.000231159,-0.00102322],[-0.00243499,-0.0103522],[-0.000385437,-0.0016047],[-0.00266194,-0.0113321],[-0.00236685,-0.010116],[-0.00120763,-0.00512272]]}}, +{"best":1.28488e-06,"evaluations":552,"generation":91,"median":5.29542e-06,"state":{"best":[-0.0011561,-0.00493202],"population":[[-0.00216216,-0.00925252],[-0.000413637,-0.00177779],[-0.00214708,-0.00917439],[-0.00283323,-0.012068],[-0.000428729,-0.00184791],[-0.00107161,-0.00453165]]}}, +{"best":8.72769e-07,"evaluations":558,"generation":92,"median":3.25751e-06,"state":{"best":[-0.00216826,-0.00923872],"population":[[-0.00155387,-0.00663477],[-0.00216826,-0.00923872],[-0.00266332,-0.0113615],[-0.00274334,-0.0117135],[-0.00193558,-0.00823396],[-0.00245639,-0.010428]]}}, +{"best":8.72769e-07,"evaluations":564,"generation":93,"median":2.01557e-06,"state":{"best":[-0.00216826,-0.00923872],"population":[[-0.00238635,-0.0101715],[-0.00232442,-0.00991268],[-0.00302079,-0.0128748],[-0.00145744,-0.00618753],[-0.00167386,-0.00714121],[-0.00180418,-0.00769445]]}}, +{"best":6.77061e-07,"evaluations":570,"generation":94,"median":1.46838e-06,"state":{"best":[-0.00198527,-0.00846049],"population":[[-0.00229176,-0.00976324],[-0.00198527,-0.00846049],[-0.00223074,-0.00950122],[-0.00184149,-0.00785927],[-0.00262076,-0.0111632],[-0.00239086,-0.0101835]]}}, +{"best":6.77061e-07,"evaluations":576,"generation":95,"median":2.3836e-06,"state":{"best":[-0.00198527,-0.00846049],"population":[[-0.00212478,-0.00907472],[-0.0020083,-0.0085463],[-0.00234973,-0.0100065],[-0.00193865,-0.0082581],[-0.00263926,-0.0112524],[-0.00229316,-0.0097606]]}}, +{"best":6.77061e-07,"evaluations":588,"generation":97,"median":1.38852e-06,"state":{"best":[-0.00198527,-0.00846049],"population":[[-0.00238401,-0.0101627],[-0.00226308,-0.00965346],[-0.00199207,-0.00848785],[-0.00243818,-0.0103923],[-0.0022284,-0.00948915],[-0.00208185,-0.00886817]]}}, +{"best":6.77061e-07,"evaluations":594,"generation":98,"median":1.57427e-06,"state":{"best":[-0.00198527,-0.00846049],"population":[[-0.00221912,-0.00945098],[-0.00201568,-0.00857833],[-0.0024836,-0.0105884],[-0.00253573,-0.0108014],[-0.00205096,-0.00874458],[-0.00194963,-0.0083035]]}}, +{"best":5.97754e-07,"evaluations":600,"generation":99,"median":7.98092e-07,"state":{"best":[-0.00192377,-0.00819783],"population":[[-0.00203858,-0.00868678],[-0.00192377,-0.00819783],[-0.00193838,-0.00825663],[-0.00212093,-0.00904534],[-0.00200702,-0.00854993],[-0.0019072,-0.00812562]]}}, +{"best":5.97754e-07,"evaluations":606,"generation":100,"median":7.13329e-07,"state":{"best":[-0.00192377,-0.00819783],"population":[[-0.0017785,-0.0075763],[-0.00195023,-0.00831323],[-0.0020003,-0.00852319],[-0.00201966,-0.00860636],[-0.00205593,-0.00876131],[-0.00187913,-0.00800942]]}}, +{"best":5.97754e-07,"evaluations":612,"generation":101,"median":8.24154e-07,"state":{"best":[-0.00192377,-0.00819783],"population":[[-0.00201328,-0.00858214],[-0.00212815,-0.00907344],[-0.00201405,-0.0085809],[-0.00197103,-0.00840017],[-0.00195806,-0.0083447],[-0.00198698,-0.00846445]]}}, +{"best":5.58252e-07,"evaluations":624,"generation":103,"median":7.42598e-07,"state":{"best":[-0.00186841,-0.00796127],"population":[[-0.00189353,-0.00806821],[-0.00189915,-0.00808784],[-0.0019906,-0.00848446],[-0.00186841,-0.00796127],[-0.00200474,-0.00854245],[-0.00199331,-0.00849659]]}}, +{"best":5.53373e-07,"evaluations":630,"generation":104,"median":6.31007e-07,"state":{"best":[-0.00184774,-0.00787443],"population":[[-0.00186454,-0.00794719],[-0.00180275,-0.00767963],[-0.00184774,-0.00787443],[-0.00190125,-0.00810128],[-0.00187673,-0.00799774],[-0.00189008,-0.00805249]]}}, +{"best":4.58685e-07,"evaluations":636,"generation":105,"median":5.8807e-07,"state":{"best":[-0.00176078,-0.00750299],"population":[[-0.00185941,-0.00792236],[-0.00179813,-0.00766266],[-0.00188432,-0.00802813],[-0.00176078,-0.00750299],[-0.00187922,-0.00800863],[-0.00186802,-0.00796154]]}}, +{"best":4.23181e-07,"evaluations":642,"generation":106,"median":5.48828e-07,"state":{"best":[-0.00171488,-0.00730747],"population":[[-0.00165933,-0.00706864],[-0.00171488,-0.00730747],[-0.00181822,-0.00774771],[-0.00172153,-0.00733616],[-0.00173672,-0.00740419],[-0.00178503,-0.00760799]]}}, +{"best":4.23181e-07,"evaluations":648,"generation":107,"median":6.1802e-07,"state":{"best":[-0.00171488,-0.00730747],"population":[[-0.00151035,-0.00643423],[-0.00162367,-0.00691725],[-0.00173874,-0.00740551],[-0.00161436,-0.00688196],[-0.00182793,-0.00778799],[-0.00185826,-0.00791697]]}}, +{"best":2.72914e-07,"evaluations":654,"generation":108,"median":4.94187e-07,"state":{"best":[-0.0014617,-0.00622836],"population":[[-0.00129889,-0.00553079],[-0.00166983,-0.0071136],[-0.00160544,-0.00683956],[-0.0014617,-0.00622836],[-0.00157782,-0.00672204],[-0.0016582,-0.00706475]]}}, +{"best":2.21872e-07,"evaluations":666,"generation":110,"median":7.14908e-07,"state":{"best":[-0.00136862,-0.00583229],"population":[[-0.00127048,-0.00541792],[-0.000959306,-0.00408467],[-0.00105127,-0.0044787],[-0.00135919,-0.00578892],[-0.00107043,-0.00455558],[-0.00161664,-0.00688805]]}}, +{"best":1.19511e-07,"evaluations":672,"generation":111,"median":5.34923e-07,"state":{"best":[-0.000815535,-0.00347569],"population":[[-0.000815535,-0.00347569],[-0.00178895,-0.00761671],[-0.00169105,-0.00720769],[-0.000851982,-0.00362973],[-0.00166553,-0.00709569],[-0.00142135,-0.00605888]]}}, +{"best":1.19511e-07,"evaluations":678,"generation":112,"median":8.7105e-07,"state":{"best":[-0.000815535,-0.00347569],"population":[[-0.000976873,-0.00416369],[-0.000278846,-0.00118633],[-0.00207073,-0.00882311],[-0.00126915,-0.0054012],[-0.000316981,-0.00135604],[-0.000244371,-0.00103706]]}}, +{"best":1.19511e-07,"evaluations":684,"generation":113,"median":7.5392e-07,"state":{"best":[-0.000815535,-0.00347569],"population":[[-0.000267068,-0.00114219],[-0.000426951,-0.00181829],[4.15802e-08,2.70801e-06],[-0.000719141,-0.00306676],[-0.000358888,-0.00153372],[-0.000449112,-0.00191785]]}}, +{"best":3.3453e-08,"evaluations":690,"generation":114,"median":3.89289e-07,"state":{"best":[-0.000599515,-0.00255481],"population":[[-0.000409639,-0.00174392],[-0.000365418,-0.00156092],[-0.00129771,-0.00552863],[-0.000599515,-0.00255481],[-9.56915e-05,-0.000406019],[-0.000931018,-0.00396928]]}}, +{"best":3.3453e-08,"evaluations":702,"generation":116,"median":4.14843e-07,"state":{"best":[-0.000599515,-0.00255481],"population":[[-0.000616392,-0.00262685],[-0.000696291,-0.00297092],[-0.000636819,-0.00271615],[-0.00114041,-0.00485787],[-0.00130826,-0.00557396],[-0.000755992,-0.00322329]]}}, +{"best":2.79813e-08,"evaluations":708,"generation":117,"median":2.40679e-07,"state":{"best":[-0.000678195,-0.00288992],"population":[[-0.000859792,-0.00366274],[-0.000633815,-0.0026987],[-0.00113609,-0.00484029],[-0.000683371,-0.00291116],[-0.000678195,-0.00288992],[-0.00120285,-0.00512426]]}}, +{"best":9.88887e-09,"evaluations":714,"generation":118,"median":2.12661e-07,"state":{"best":[-0.000447705,-0.00190776],"population":[[-0.000721122,-0.00307179],[-0.000714005,-0.00304359],[-0.000447705,-0.00190776],[-0.000711037,-0.00303073],[-0.000703485,-0.00299925],[-0.000658962,-0.00280737]]}} +]} diff --git a/examples/different_powers/trace.py b/examples/different_powers/trace.py new file mode 100644 index 00000000..e021e169 --- /dev/null +++ b/examples/different_powers/trace.py @@ -0,0 +1,190 @@ +"""The trace for the plot on the example's page, written to the file that ``GENOXIDE_TRACE`` +names. The plot draws the population on the function's contour, which needs two dimensions: the +trace is of a separate run of CMA-ES in 2 dimensions, rotated with seed 1, with a budget of +20,000 evaluations, in at most 100 frames. The Rust example writes the same file.""" + +import json +import math +import os + +import genoxide as gx + + +def record_small(): + """Runs CMA-ES in 2 dimensions and writes its trace, if ``GENOXIDE_TRACE`` is set.""" + path = os.environ.get("GENOXIDE_TRACE") + if not path: + return + problem = gx.problems.Rotated(gx.problems.DifferentPowers(2), seed=1) + minimum = problem.optimum.value + budget = 20_000 + cmaes = gx.Cmaes(problem.genome, objective="minimize", seed=1) + frames = Frames(100) + + def record(progress): + state = {"population": progress.population.tolist(), "best": progress.best_genome.tolist()} + frames.push(frame(progress, state, minimum)) + + cmaes.run(problem, target=minimum + 1e-8, evaluations=budget, on_generation=record) + low, high = problem.genome.bounds + settings = { + "format": 1, + "example": "different_powers", + "objective": "minimize", + "x_label": "evaluations", + "y_label": "error", + "log_y": True, + "optimum": 0.0, + "plot": "contour", + "problem": { + "function": "different_powers", + "bounds": [[float(low), float(high)]] * 2, + "minima": problem.optimum.solutions.tolist(), + "rotation": {"matrix": problem.matrix.tolist(), "center": problem.center.tolist()}, + }, + } + write(path, settings, frames.to_list()) + + +def frame(progress, state, minimum): + """The frame of a generation: its progress, the errors of its best and of its population's + median to ``minimum`` (rounding can put a solution a few ulps below it), and ``state``.""" + + def error(value): + return None if value is None else max(value - minimum, 0.0) + + return { + "generation": progress.generation, + "evaluations": progress.evaluations, + "best": error(progress.best_fitness), + "median": error(median(progress.scores)), + "state": state, + } + + +def median(scores): + """The median of the valid scores, None without any.""" + scores = sorted(float(score) for score in scores if not math.isnan(score)) + middle = len(scores) // 2 + if not scores: + return None + return scores[middle] if len(scores) % 2 else (scores[middle - 1] + scores[middle]) / 2 + + +# ---- the same in every example's trace ---------------------------------------------------------- + + +class Frames: + """The frames of at most ``most`` generations, from the part of the run where what the page + plots changes: the frames after the last change are left out (a run that reached its target, + or a front that no longer moves), and the rest are spread evenly over the generations up to + it. While the run goes, up to 8 × ``most`` frames are kept: every ``every``-th generation, + with ``every`` doubling whenever there are that many, and the last one.""" + + def __init__(self, most): + self.most, self.every, self.kept, self.last = most, 1, [], None + + def push(self, frame): + if frame["generation"] % self.every: + self.last = frame + return + self.kept.append(frame) + self.last = None + if len(self.kept) == 8 * self.most: + self.every *= 2 + self.kept = [kept for kept in self.kept if kept["generation"] % self.every == 0] + + def to_list(self): + frames = self.kept + ([self.last] if self.last else []) + active = frames[: last_change(frames) + 1] + count, most = len(active), max(self.most, 2) + if count <= most: + return active + return [active[(i * (count - 1) + (most - 1) // 2) // (most - 1)] for i in range(most)] + + +def last_change(frames): + """The index of the frame after which nothing the page plots changes. To 3 significant + digits, as a plot shows them: the best, the median and, for a single objective (a numeric + best), the state; to within a hundredth of their range over the run: a front's + hypervolumes, in the state or in a grid's series.""" + if not frames: + return 0 + last = len(frames) - 1 + number = lambda value: isinstance(value, (int, float)) and not isinstance(value, bool) + single = any(number(frame.get("best")) for frame in frames) + + def measures(frame): + values = [] + state = frame.get("state") + hypervolume = state.get("hypervolume") if isinstance(state, dict) else None + for value in (hypervolume, frame.get("series")): + if number(value): + values.append(float(value)) + elif isinstance(value, dict): + values.extend(float(v) for _, v in sorted(value.items()) if number(v)) + return values + + measured = [measures(frame) for frame in frames] + end = measured[last] + tolerance = [] + for k in range(len(end)): + values = [values[k] for values in measured if k < len(values)] + tolerance.append((max(values) - min(values)) / 100.0) + + def same(frame, final, key, flush=False): + return coarse(frame.get(key), flush) == coarse(final.get(key), flush) + + def settled(i): + frame, final = frames[i], frames[last] + return ( + same(frame, final, "best") + and same(frame, final, "median") + and (not single or same(frame, final, "state", flush=True)) + and len(measured[i]) == len(end) + and all(abs(v - e) <= t for v, e, t in zip(measured[i], end, tolerance)) + ) + + first = last + while first > 0 and settled(first - 1): + first -= 1 + return first + + +def coarse(value, flush=False): + """``value`` with its numbers to 3 significant digits, as precisely as a plot shows them: two + frames whose plotted values agree to that precision look the same. With ``flush``, for the + solutions a plot draws on their ranges, numbers below 1e-6 in size count as 0.""" + if isinstance(value, float): + if flush and abs(value) < 1e-6: + value = 0.0 + return f"{value:.2e}" + if isinstance(value, (list, tuple)): + return "[" + ",".join(coarse(item, flush) for item in value) + "]" + if isinstance(value, dict): + items = sorted(value.items()) + return "{" + ",".join(f"{key}:{coarse(item, flush)}" for key, item in items) + "}" + return json.dumps(value) + + +def write(path, settings, frames): + """Writes the settings and the frames to ``path``, a frame per line.""" + lines = ",\n".join(map(to_json, frames)) + with open(path, "w", encoding="utf-8", newline="\n") as file: + file.write(f'{to_json(settings)[:-1]},"frames":[\n{lines}\n]}}\n') + + +def to_json(value): + """Compact JSON with sorted keys, and numbers rounded to 6 significant digits, as the Rust + example writes it.""" + return json.dumps(rounded(value), sort_keys=True, separators=(",", ":"), ensure_ascii=False) + + +def rounded(value): + if isinstance(value, dict): + return {key: rounded(item) for key, item in value.items()} + if isinstance(value, (list, tuple)): + return [rounded(item) for item in value] + if isinstance(value, float): + return float(f"{value:.5e}") if math.isfinite(value) else None + return value diff --git a/examples/different_powers/trace.rs b/examples/different_powers/trace.rs new file mode 100644 index 00000000..58aad82a --- /dev/null +++ b/examples/different_powers/trace.rs @@ -0,0 +1,264 @@ +//! The trace for the plot on the example's page, written to the file that `GENOXIDE_TRACE` names. +//! The plot draws the population on the function's contour, which needs two dimensions: the trace +//! is of a separate run of CMA-ES in 2 dimensions, rotated with seed 1, with a budget of +//! 20,000 evaluations, in at most 100 frames. The Python example writes the same +//! file. + +use genoxide::observer::Snapshot; +use genoxide::prelude::*; +use genoxide::problems::{DifferentPowers, Problem, Rotated}; +use serde_json::{Value, json}; + +// runs CMA-ES in 2 dimensions and writes its trace, if GENOXIDE_TRACE is set +pub fn record_small() -> Result<()> { + let Ok(path) = std::env::var("GENOXIDE_TRACE") else { + return Ok(()); + }; + let problem = Rotated::new(DifferentPowers::new(2), 1); + let optimum = problem.optimum().expect("known"); + let minimum = optimum.value(); + let budget = 20_000; + let cmaes = Cmaes::builder(problem.representation()) + .minimize() + .seed(1) + .build()?; + let mut frames = Frames::new(100); + Engine::new(cmaes, problem.clone()) + .stop_when(Stop::target(minimum + 1e-8).or(Stop::evaluations(budget))) + .on_generation(|snapshot| { + let population = snapshot.population().iter().map(|x| &x.genome()[..]); + let population: Vec<&[f64]> = population.collect(); + let best = &snapshot.best().genome()[..]; + let state = json!({ "population": population, "best": best }); + frames.push(frame(snapshot, state, minimum)); + }) + .run()?; + let bounds = problem.representation().bounds().to_vec(); + let bounds: Vec<[f64; 2]> = bounds.iter().map(|b| [*b.start(), *b.end()]).collect(); + let minima: Vec<&[f64]> = optimum.solutions().iter().map(|x| &x[..]).collect(); + let settings = json!({ + "format": 1, + "example": "different_powers", + "objective": "minimize", + "x_label": "evaluations", + "y_label": "error", + "log_y": true, + "optimum": 0.0, + "plot": "contour", + "problem": { + "function": "different_powers", + "bounds": bounds, + "minima": minima, + "rotation": { + "matrix": problem.matrix().chunks(2).collect::>(), + "center": problem.center(), + }, + }, + }); + write(&path, settings, frames.into_vec()); + Ok(()) +} + +// the frame of a generation: its progress, the errors of its best and of its population's median +// to `minimum` (rounding can put a solution a few ulps below it), and `state` +fn frame(snapshot: &Snapshot<'_, Reals>, state: Value, minimum: f64) -> Value { + let progress = snapshot.progress(); + let error = |value: f64| (value - minimum).max(0.0); + let population = snapshot.population().iter(); + let scores = population.filter_map(|individual| individual.fitness()?.score()); + json!({ + "generation": progress.generation(), + "evaluations": progress.evaluations(), + "best": progress.best().and_then(Fitness::score).map(error), + "median": median(scores.collect()).map(error), + "state": state, + }) +} + +// the median of the scores, None without any +fn median(mut scores: Vec) -> Option { + scores.sort_by(f64::total_cmp); + let middle = scores.len() / 2; + match scores.len() { + 0 => None, + n if n % 2 == 1 => Some(scores[middle]), + _ => Some((scores[middle - 1] + scores[middle]) / 2.0), + } +} + +// ---- the same in every example's trace --------------------------------------------------------- + +// the frames of at most `most` generations, from the part of the run where what the page plots +// changes: the frames after the last change are left out (a run that reached its target, or a +// front that no longer moves), and the rest are spread evenly over the generations up to it. While +// the run goes, up to 8 × `most` frames are kept: every `every`-th generation, with `every` +// doubling whenever there are that many, and the last one. +struct Frames { + most: usize, + every: u64, + kept: Vec<(u64, Value)>, + last: Option<(u64, Value)>, +} + +impl Frames { + fn new(most: usize) -> Self { + let (every, kept, last) = (1, Vec::new(), None); + Self { + most, + every, + kept, + last, + } + } + + fn push(&mut self, frame: Value) { + let generation = frame["generation"].as_u64().expect("a generation"); + if !generation.is_multiple_of(self.every) { + self.last = Some((generation, frame)); + return; + } + self.kept.push((generation, frame)); + self.last = None; + if self.kept.len() == 8 * self.most { + self.every *= 2; + let every = self.every; + self.kept.retain(|(generation, _)| generation % every == 0); + } + } + + fn into_vec(self) -> Vec { + let frames = self.kept.into_iter().chain(self.last); + let frames: Vec = frames.map(|(_, frame)| frame).collect(); + let active = &frames[..=last_change(&frames)]; + let (count, most) = (active.len(), self.most.max(2)); + if count <= most { + return active.to_vec(); + } + let at = |i: usize| active[(i * (count - 1) + (most - 1) / 2) / (most - 1)].clone(); + (0..most).map(at).collect() + } +} + +// the index of the frame after which nothing the page plots changes. To 3 significant digits, as +// a plot shows them: the best, the median and, for a single objective (a numeric best), the state; +// to within a hundredth of their range over the run: a front's hypervolumes, in the state or in a +// grid's series +fn last_change(frames: &[Value]) -> usize { + let Some(last) = frames.len().checked_sub(1) else { + return 0; + }; + let single = frames.iter().any(|frame| frame["best"].is_number()); + let measures = |frame: &Value| -> Vec { + let mut values = Vec::new(); + for value in [&frame["state"]["hypervolume"], &frame["series"]] { + match value { + Value::Number(number) => values.extend(number.as_f64()), + Value::Object(map) => values.extend(map.values().filter_map(Value::as_f64)), + _ => {} + } + } + values + }; + let measured: Vec> = frames.iter().map(measures).collect(); + let end = &measured[last]; + let tolerance: Vec = (0..end.len()) + .map(|k| { + let values = measured.iter().filter_map(|values| values.get(k).copied()); + let (low, high) = values.fold((f64::INFINITY, f64::NEG_INFINITY), |(low, high), v| { + (low.min(v), high.max(v)) + }); + (high - low) / 100.0 + }) + .collect(); + let settled = |i: usize| { + let (frame, final_frame) = (&frames[i], &frames[last]); + let same = + |key: &str, flush: bool| coarse(&frame[key], flush) == coarse(&final_frame[key], flush); + same("best", false) + && same("median", false) + && (!single || same("state", true)) + && measured[i].len() == end.len() + && measured[i] + .iter() + .zip(end) + .zip(&tolerance) + .all(|((value, end), tolerance)| (value - end).abs() <= *tolerance) + }; + let mut first = last; + while first > 0 && settled(first - 1) { + first -= 1; + } + first +} + +// `value` with its numbers to 3 significant digits, as precisely as a plot shows them: two frames +// whose plotted values agree to that precision look the same. With `flush`, for the solutions a +// plot draws on their ranges, numbers below 1e-6 in size count as 0 +fn coarse(value: &Value, flush: bool) -> String { + let join = |items: Vec| items.join(","); + match value { + Value::Number(number) if number.is_f64() => { + let number = number.as_f64().expect("f64"); + let number = if flush && number.abs() < 1e-6 { + 0.0 + } else { + number + }; + format!("{number:.2e}") + } + Value::Array(items) => { + format!( + "[{}]", + join(items.iter().map(|item| coarse(item, flush)).collect()) + ) + } + Value::Object(map) => { + let entry = |(key, item): (&String, &Value)| format!("{key}:{}", coarse(item, flush)); + format!("{{{}}}", join(map.iter().map(entry).collect())) + } + other => other.to_string(), + } +} + +// writes the settings and the frames to `path`, a frame per line +fn write(path: &str, settings: Value, frames: Vec) { + let frames: Vec = frames.iter().map(to_json).collect(); + let settings = to_json(&settings); + let head = &settings[..settings.len() - 1]; + let text = format!("{head},\"frames\":[\n{}\n]}}\n", frames.join(",\n")); + std::fs::write(path, text).expect("the trace is written"); +} + +// compact JSON with sorted keys, and numbers rounded to 6 significant digits and written as +// Python writes them (7542.0, 1e-08): the Python example writes the same file +fn to_json(value: &Value) -> String { + let join = |items: Vec| items.join(","); + match value { + Value::Number(number) if number.is_f64() => python_float(number.as_f64().expect("f64")), + Value::Array(items) => format!("[{}]", join(items.iter().map(to_json).collect())), + Value::Object(map) => { + let entry = + |(key, item): (&String, &Value)| format!("{}:{}", json!(key), to_json(item)); + format!("{{{}}}", join(map.iter().map(entry).collect())) + } + other => other.to_string(), + } +} + +fn python_float(value: f64) -> String { + let rounded: f64 = format!("{value:.5e}").parse().expect("a number"); + let shortest = format!("{rounded:e}"); + let (mantissa, exponent) = shortest.split_once('e').expect("an exponent"); + let exponent: i32 = exponent.parse().expect("an exponent"); + if (-4..16).contains(&exponent) { + let text = rounded.to_string(); + if text.contains('.') { + text + } else { + text + ".0" + } + } else { + let sign = if exponent < 0 { '-' } else { '+' }; + format!("{mantissa}e{sign}{:02}", exponent.abs()) + } +} diff --git a/examples/discus/README.md b/examples/discus/README.md new file mode 100644 index 00000000..cb84062b --- /dev/null +++ b/examples/discus/README.md @@ -0,0 +1,84 @@ +--- +title: Discus +category: continuous +summary: Minimize a sphere squashed along one axis, a thousand times more sensitive than the others, in 30 dimensions, as it is and shifted and rotated, and compare CMA-ES, sep-CMA-ES, DE, PSO and a GA. +reference: "Hansen, N., Finck, S., Ros, R. and Auger, A. (2009). Real-Parameter Black-Box Optimization Benchmarking 2009: Noiseless Functions Definitions. INRIA research report RR-6829." +reference_url: "https://hal.inria.fr/inria-00362633" +optimum: "0 (at the origin)" +languages: [rust, python] +order: 56 +trace_note: "Recorded from another run: CMA-ES in 2 dimensions on the function rotated with seed 1, so that the population can be drawn on the function's contour." +--- + +# Discus + +## The problem + +The discus squares the first gene a million times more than the others: + +```text +f(x) = 10⁶ x₁² + Σᵢ₌₂ⁿ xᵢ², each xᵢ in [−100, 100] +``` + +Its minimum is 0, at the origin. Here n = 30. It's BBOB's f11 (Hansen et al. 2009), with an +oscillation and a rotation there; this plain form and the bounds are the CEC 2014 (Liang, Qu and +Suganthan 2013, function 3) and CEC 2017 (Awad et al. 2016, function 11) reports' basic function, +which those suites shift and rotate. + +## What makes it hard + +The level sets are discs: one direction is a thousand times more sensitive than all the others. A +step that suits the 29 flat directions overshoots in the steep one, and a step that suits the +steep one crawls in the others: a search has to give that one direction its own scale. As it is, +the direction is a gene's axis; shifted and rotated, a random one. + +## Representation + +A `Real` genome of 30 genes: the point x itself. The fitness is f(x), to minimize. The function is +genoxide's `problems::Discus`, which brings its bounds and its minimum, and the shifted and rotated +instance `problems::Rotated::new(problems::Shifted::new(function, 1), 1)`, which keeps them. + +## Algorithm + +Five algorithms, each with a budget of 10,000 evaluations per dimension, 300,000 in all, and a +target of 1e-8, from seed 1: + +- CMA-ES (Hansen and Ostermeier, 2001, Evolutionary Computation 9(2): 159-195), which samples a + population of 14 from a normal distribution and adapts its mean, its step size and its covariance + matrix, from a step size of 0.3 of each gene's range and a random start; +- sep-CMA-ES (Ros and Hansen, 2008, PPSN X: 296-305), the same with a diagonal covariance matrix: a + scale per gene but no correlations; +- differential evolution with genoxide's defaults, SHADE (Tanabe and Fukunaga, CEC 2013), with a + population of 100; +- particle swarm optimization (Kennedy and Eberhart, 1995), 40 particles with Clerc and Kennedy's + constriction coefficients and a global topology; +- a real-coded genetic algorithm: a population of 100, tournaments of 3, simulated binary crossover + (Deb and Agrawal, 1995) with η = 15 and polynomial mutation with η = 20 at a rate of 1/30 per + gene. + +The second table runs the same algorithms on the function shifted and rotated, with genoxide's +`problems::Shifted` and `problems::Rotated` and seed 1: the minimum moves to a random point in the +middle 80% of the box, and an orthogonal matrix, drawn from normal numbers made orthonormal by +Gram-Schmidt as BBOB draws its rotations, turns the function about it. That's how the CEC and BBOB +suites use the function, with their own data; genoxide generates its instances instead. + +## Output + +The first line gives the dimension and the budget. Then two tables, the function as it is and shifted and rotated: a row per algorithm, the +evaluations it had used when its best error first reached each value of the heading, and the best +error it found, to two significant digits. A dash is an error not reached. The function is +evaluated with genoxide's portable math, so the runs are the same on every platform, and in Python, +`run` evaluates it in Rust, so both versions print the same. + +[The project page](https://tachsin.gr/projects/genoxide/examples/discus) plays back another +run: CMA-ES on the function in 2 dimensions, 10⁶ x₁² + x₂², rotated with seed 1, so that the +population can be drawn on its contour. It meets the target after 684 evaluations. + +## Good results + +The minimum is 0. As it is, sep-CMA-ES reaches 1e-8 after 6,594 evaluations; PSO takes 27,720, +CMA-ES 29,778 and SHADE 33,800. The genetic algorithm ends at 0.075. + +Shifted and rotated, CMA-ES takes 29,288 evaluations, as many as before. SHADE reaches 1e-4 after +268,800 evaluations and ends at 6.5·10⁻⁶; sep-CMA-ES ends at 3.7·10⁴, PSO at 2,500 and the genetic +algorithm at 640. diff --git a/examples/discus/main.py b/examples/discus/main.py new file mode 100644 index 00000000..25fe7ea8 --- /dev/null +++ b/examples/discus/main.py @@ -0,0 +1,97 @@ +"""Discus: minimize a sphere squashed along one axis, a thousand times more sensitive than +the others, in 30 dimensions, as it is and shifted and rotated. + +Compares how fast CMA-ES, with a full and with a diagonal covariance matrix (sep-CMA-ES), +differential evolution, particle swarm optimization and a real-coded genetic algorithm close in on +the minimum, 0 at the origin: the evaluations each takes until its error is at most 1, 1e-2, 1e-4, 1e-6 and 1e-8. +The function is genoxide's `problems::Discus`. Then the same on the function shifted and rotated, with genoxide's `problems::Shifted` +and `problems::Rotated`, as the CEC and BBOB suites transform it. + +With ``GENOXIDE_TRACE=``, it also writes a trace of a run for the plot on the example's page, +with trace.py. + + python examples/discus/main.py +""" + +import genoxide as gx + +from trace import record_small + +DIMENSIONS = 30 +BUDGET = 10_000 * DIMENSIONS +# the errors at which the table gives each run's evaluations +ERRORS = [1e0, 1e-2, 1e-4, 1e-6, 1e-8] +COLUMNS = ["1", "1e-2", "1e-4", "1e-6", "1e-8"] + + +def error_text(error): + """An error to two significant digits, as Rust writes it: 9.9e-9.""" + mantissa, exponent = f"{error:.1e}".split("e") + return f"{mantissa}e{int(exponent)}" + + +class Reached: + """The evaluations after the first generation whose best error was at most each of ERRORS, + for a function whose minimum is ``minimum``.""" + + def __init__(self, minimum): + self.minimum = minimum + self.evaluations = [None] * len(ERRORS) + + def record(self, progress): + if progress.best_fitness is None: + return + error = progress.best_fitness - self.minimum + for i, bound in enumerate(ERRORS): + if self.evaluations[i] is None and error <= bound: + self.evaluations[i] = progress.evaluations + + def print(self, name, result): + """A row of the table: the evaluations, "-" for an error not reached, and the best + error.""" + cells = ["-" if reached is None else str(reached) for reached in self.evaluations] + # rounding can put a solution a few ulps below the minimum + cells.append(error_text(max(result.best_fitness - self.minimum, 0.0))) + print(f"{name:<10}" + "".join(f"{cell:>9}" for cell in cells)) + + +def compare(name, problem): + """The table of the five algorithms on ``problem``, after a line that names it.""" + minimum = problem.optimum.value + print(f"{name}: evaluations until the error is at most") + print(f"{'algorithm':<10}" + "".join(f"{column:>9}" for column in COLUMNS) + f"{'best':>9}") + genome = problem.genome + for label, algorithm in ( + ("CMA-ES", gx.Cmaes(genome, objective="minimize", seed=1)), + ("sep-CMA-ES", gx.Cmaes(genome, covariance="diagonal", objective="minimize", seed=1)), + ("DE", gx.De(genome, objective="minimize", seed=1)), + ("PSO", gx.Pso(genome, population_size=40, objective="minimize", seed=1)), + ( + "GA", + gx.Ga( + genome, + population_size=100, + select=gx.Tournament(3), + crossover=gx.SimulatedBinaryCrossover(15.0), + mutation=gx.PolynomialMutation(20.0, rate=1 / DIMENSIONS), + objective="minimize", + seed=1, + ), + ), + ): + reached = Reached(minimum) + result = algorithm.run( + problem, target=minimum + 1e-8, evaluations=BUDGET, on_generation=reached.record + ) + reached.print(label, result) + + +print(f"Discus in {DIMENSIONS} dimensions, {BUDGET} evaluations at most") +compare("Discus", gx.problems.Discus(DIMENSIONS)) +# the CEC 2014 and 2017 suites' form, with genoxide's own shift and rotation +rotated = gx.problems.Rotated(gx.problems.Shifted(gx.problems.Discus(DIMENSIONS), seed=1), seed=1) +compare("Shifted and rotated (seed 1)", rotated) + +# with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate run in +# 2 dimensions: the plot is the function's contour +record_small() diff --git a/examples/discus/main.rs b/examples/discus/main.rs new file mode 100644 index 00000000..72f422c3 --- /dev/null +++ b/examples/discus/main.rs @@ -0,0 +1,151 @@ +//! Discus: minimize a sphere squashed along one axis, a thousand times more sensitive than +//! the others, in 30 dimensions, as it is and shifted and rotated. +//! +//! Compares how fast CMA-ES, with a full and with a diagonal covariance matrix (sep-CMA-ES), +//! differential evolution, particle swarm optimization and a real-coded genetic algorithm close in +//! on the minimum, 0 at the origin: the evaluations each takes until its error is at most 1, 1e-2, 1e-4, 1e-6 and 1e-8. +//! The function is genoxide's `problems::Discus`. Then the same on the function shifted and rotated, with genoxide's `problems::Shifted` +//! and `problems::Rotated`, as the CEC and BBOB suites transform it. +//! +//! With `GENOXIDE_TRACE=`, it also writes a trace of a run for the plot on the example's +//! page, with `trace.rs`. +//! +//! ```text +//! cargo run --release --example discus +//! ``` + +mod trace; + +use genoxide::observer::Snapshot; +use genoxide::prelude::*; +use genoxide::problems::{Discus, Problem, Rotated, Shifted}; + +const DIMENSIONS: usize = 30; +const BUDGET: u64 = 10_000 * DIMENSIONS as u64; +// the errors at which the table gives each run's evaluations +const ERRORS: [f64; 5] = [1e0, 1e-2, 1e-4, 1e-6, 1e-8]; +const COLUMNS: [&str; 5] = ["1", "1e-2", "1e-4", "1e-6", "1e-8"]; + +fn main() -> Result<()> { + println!("Discus in {DIMENSIONS} dimensions, {BUDGET} evaluations at most"); + compare("Discus", &Discus::new(DIMENSIONS))?; + // the CEC 2014 and 2017 suites' form, with genoxide's own shift and rotation + let rotated = Rotated::new(Shifted::new(Discus::new(DIMENSIONS), 1), 1); + compare("Shifted and rotated (seed 1)", &rotated)?; + // with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate + // run in 2 dimensions: the plot is the function's contour + trace::record_small()?; + Ok(()) +} + +// the table of the five algorithms on `problem`, after a line that names it +fn compare

(name: &str, problem: &P) -> Result<()> +where + P: Problem + FitnessFunction + Clone, +{ + let minimum = problem.optimum().expect("known").value(); + let stop = || Stop::target(minimum + 1e-8).or(Stop::evaluations(BUDGET)); + println!("{name}: evaluations until the error is at most"); + print!("{:<10}", "algorithm"); + COLUMNS.iter().for_each(|column| print!("{column:>9}")); + println!("{:>9}", "best"); + + for (name, covariance) in [ + ("CMA-ES", cmaes::Covariance::Full), + ("sep-CMA-ES", cmaes::Covariance::Diagonal), + ] { + let cmaes = Cmaes::builder(problem.representation()) + .covariance(covariance) + .minimize() + .seed(1) + .build()?; + let mut reached = Reached::new(minimum); + let outcome = Engine::new(cmaes, problem.clone()) + .stop_when(stop()) + .on_generation(|snapshot| reached.record(snapshot)) + .run()?; + reached.print(name, &outcome); + } + + let de = De::builder(problem.representation()) + .minimize() + .seed(1) + .build()?; + let mut reached = Reached::new(minimum); + let outcome = Engine::new(de, problem.clone()) + .stop_when(stop()) + .on_generation(|snapshot| reached.record(snapshot)) + .run()?; + reached.print("DE", &outcome); + + let pso = Pso::builder(problem.representation()) + .population_size(40) + .minimize() + .seed(1) + .build()?; + let mut reached = Reached::new(minimum); + let outcome = Engine::new(pso, problem.clone()) + .stop_when(stop()) + .on_generation(|snapshot| reached.record(snapshot)) + .run()?; + reached.print("PSO", &outcome); + + let ga = Ga::builder(problem.representation()) + .population_size(100) + .select(Tournament::new(3)?) + .crossover(SimulatedBinaryCrossover::new(15.0)?) + .mutate(PolynomialMutation::per_gene(1.0 / DIMENSIONS as f64, 20.0)?) + .minimize() + .seed(1) + .build()?; + let mut reached = Reached::new(minimum); + let outcome = Engine::new(ga, problem.clone()) + .stop_when(stop()) + .on_generation(|snapshot| reached.record(snapshot)) + .run()?; + reached.print("GA", &outcome); + Ok(()) +} + +// the evaluations after the first generation whose best error was at most each of ERRORS, for a +// function whose minimum is `minimum` +struct Reached { + minimum: f64, + evaluations: [Option; 5], +} + +impl Reached { + fn new(minimum: f64) -> Self { + let evaluations = [None; 5]; + Self { + minimum, + evaluations, + } + } + + fn record(&mut self, snapshot: &Snapshot<'_, Reals>) { + let progress = snapshot.progress(); + let Some(best) = progress.best().and_then(Fitness::score) else { + return; + }; + let error = best - self.minimum; + for (reached, bound) in self.evaluations.iter_mut().zip(ERRORS) { + if reached.is_none() && error <= bound { + *reached = Some(progress.evaluations()); + } + } + } + + // a row of the table: the evaluations, "-" for an error not reached, and the best error + fn print(&self, name: &str, outcome: &Outcome) { + print!("{name:<10}"); + for reached in self.evaluations { + let reached = reached.map_or("-".to_string(), |evaluations| evaluations.to_string()); + print!("{reached:>9}"); + } + // rounding can put a solution a few ulps below the minimum + let best = outcome.best_fitness().score().expect("valid"); + let error = (best - self.minimum).max(0.0); + println!("{:>9}", format!("{error:.1e}")); + } +} diff --git a/examples/discus/output.txt b/examples/discus/output.txt new file mode 100644 index 00000000..f23f33b7 --- /dev/null +++ b/examples/discus/output.txt @@ -0,0 +1,15 @@ +Discus in 30 dimensions, 300000 evaluations at most +Discus: evaluations until the error is at most +algorithm 1 1e-2 1e-4 1e-6 1e-8 best +CMA-ES 22442 24990 26978 28532 29778 1.0e-8 +sep-CMA-ES 3766 4424 5138 5852 6594 9.0e-9 +DE 14600 19600 24100 29300 33800 9.8e-9 +PSO 12400 16240 20040 23560 27720 8.3e-9 +GA 119237 - - - - 7.5e-2 +Shifted and rotated (seed 1): evaluations until the error is at most +algorithm 1 1e-2 1e-4 1e-6 1e-8 best +CMA-ES 23408 25564 26824 28210 29288 9.5e-9 +sep-CMA-ES - - - - - 3.7e4 +DE 159900 216600 268800 - - 6.5e-6 +PSO - - - - - 2.5e3 +GA - - - - - 6.4e2 diff --git a/examples/discus/trace.json b/examples/discus/trace.json new file mode 100644 index 00000000..aab100f6 --- /dev/null +++ b/examples/discus/trace.json @@ -0,0 +1,102 @@ +{"example":"discus","format":1,"log_y":true,"objective":"minimize","optimum":0.0,"plot":"contour","problem":{"bounds":[[-100.0,100.0],[-100.0,100.0]],"function":"discus","minima":[[0.0,0.0]],"rotation":{"center":[0.0,0.0],"matrix":[[-0.973552,0.228466],[-0.228466,-0.973552]]}},"x_label":"evaluations","y_label":"error","frames":[ +{"best":164885.0,"evaluations":6,"generation":0,"median":2764850000.0,"state":{"best":[-21.4189,-92.999],"population":[[-80.5712,-24.4639],[21.9455,-61.072],[-54.0471,75.3763],[-21.4189,-92.999],[-75.1217,-72.6119],[42.8992,-28.5787]]}}, +{"best":164885.0,"evaluations":12,"generation":1,"median":1999680000.0,"state":{"best":[-21.4189,-92.999],"population":[[-47.7399,-63.2852],[58.6925,-62.0722],[34.7603,-90.5816],[-6.17681,-39.8607],[-75.1509,-23.4467],[1.39012,-45.9044]]}}, +{"best":164885.0,"evaluations":18,"generation":2,"median":3609190000.0,"state":{"best":[-21.4189,-92.999],"population":[[4.60162,-16.6428],[-68.5512,-33.1501],[-71.792,-2.17173],[-92.0236,-58.5878],[-60.6057,8.63219],[14.0245,-98.6665]]}}, +{"best":50078.6,"evaluations":24,"generation":3,"median":462415000.0,"state":{"best":[-9.00249,-39.3254],"population":[[-22.8463,-94.252],[-21.3654,-28.4156],[42.5365,-26.0615],[19.8544,-89.0881],[-9.00249,-39.3254],[12.2774,-65.1388]]}}, +{"best":50078.6,"evaluations":36,"generation":5,"median":228006000.0,"state":{"best":[-9.00249,-39.3254],"population":[[-24.098,-27.3746],[-59.8595,-12.8594],[2.93986,-20.7435],[-32.0862,-38.7679],[3.11118,-42.0984],[-8.78591,-60.8341]]}}, +{"best":50078.6,"evaluations":42,"generation":6,"median":61049000.0,"state":{"best":[-9.00249,-39.3254],"population":[[-2.53784,-49.6251],[3.88381,-63.7644],[-9.67122,-39.5315],[2.55298,-40.9749],[-17.3559,-45.0991],[-6.04724,-45.9468]]}}, +{"best":50078.6,"evaluations":48,"generation":7,"median":18713100.0,"state":{"best":[-9.00249,-39.3254],"population":[[-9.06151,-31.2454],[-16.0441,-17.3892],[-18.5111,-38.2649],[-9.28286,-28.279],[-19.6992,-59.7459],[-8.10505,-23.0743]]}}, +{"best":50078.6,"evaluations":54,"generation":8,"median":30515800.0,"state":{"best":[-9.00249,-39.3254],"population":[[-15.0588,-18.3197],[2.95933,-13.7816],[-1.84484,-25.0611],[-10.9068,-12.1034],[-2.404,-22.0525],[-2.41696,-32.041]]}}, +{"best":50078.6,"evaluations":60,"generation":9,"median":91938000.0,"state":{"best":[-9.00249,-39.3254],"population":[[-13.7209,-25.4221],[3.87058,-25.9608],[0.131985,-40.9146],[4.36928,-24.9921],[-6.54762,5.58571],[-24.2502,-9.31931]]}}, +{"best":50078.6,"evaluations":66,"generation":10,"median":33657900.0,"state":{"best":[-9.00249,-39.3254],"population":[[-17.5699,-23.037],[-7.68074,-16.9568],[-13.9111,-1.39934],[-15.6393,-37.8394],[-9.45452,-18.8415],[-2.20274,-14.0661]]}}, +{"best":50078.6,"evaluations":72,"generation":11,"median":49277300.0,"state":{"best":[-9.00249,-39.3254],"population":[[-19.3216,-11.7222],[-3.3077,-30.6374],[-4.25445,-7.92458],[-4.13651,22.5536],[1.95035,14.7381],[8.70167,-8.53221]]}}, +{"best":50078.6,"evaluations":84,"generation":13,"median":37835900.0,"state":{"best":[-9.00249,-39.3254],"population":[[-3.48202,21.1759],[9.19644,34.3807],[-4.3009,-40.7971],[7.3185,40.7321],[15.3788,-2.79434],[-11.9211,-20.0612]]}}, +{"best":50078.6,"evaluations":90,"generation":14,"median":36635900.0,"state":{"best":[-9.00249,-39.3254],"population":[[12.4918,37.735],[9.90285,67.07],[13.4881,-17.8168],[-0.306103,26.2628],[3.17354,-11.8499],[-5.43698,16.4716]]}}, +{"best":50078.6,"evaluations":96,"generation":15,"median":253917000.0,"state":{"best":[-9.00249,-39.3254],"population":[[22.3096,72.7487],[-18.4267,10.9664],[22.7601,32.7756],[-18.3763,35.5605],[35.6213,77.653],[35.5494,86.4278]]}}, +{"best":50078.6,"evaluations":102,"generation":16,"median":183387000.0,"state":{"best":[-9.00249,-39.3254],"population":[[-2.51619,15.8015],[17.1276,31.5035],[33.7396,65.5282],[0.205817,16.5141],[19.5468,10.4516],[31.0623,49.5553]]}}, +{"best":50078.6,"evaluations":108,"generation":17,"median":95773600.0,"state":{"best":[-9.00249,-39.3254],"population":[[13.8,40.9016],[26.5716,50.8443],[9.70228,1.94818],[-17.5762,-21.3657],[9.48564,33.6561],[-21.0574,-43.7131]]}}, +{"best":50078.6,"evaluations":114,"generation":18,"median":24490400.0,"state":{"best":[-9.00249,-39.3254],"population":[[13.026,33.9824],[21.0023,34.7649],[5.7302,37.5345],[25.3936,44.5068],[4.45829,-2.79783],[-1.89316,1.04318]]}}, +{"best":50078.6,"evaluations":120,"generation":19,"median":53257500.0,"state":{"best":[-9.00249,-39.3254],"population":[[-6.55659,15.2335],[-6.06415,21.3145],[-6.39039,11.2557],[-5.13845,1.75571],[2.46127,6.29666],[11.1158,36.2691]]}}, +{"best":50078.6,"evaluations":132,"generation":21,"median":8217410.0,"state":{"best":[-9.00249,-39.3254],"population":[[-4.25485,-5.08032],[-0.213782,-2.11142],[3.78004,14.3795],[14.4595,31.5548],[-1.51774,5.55507],[8.86605,16.6546]]}}, +{"best":31044.7,"evaluations":138,"generation":22,"median":505374.0,"state":{"best":[-1.19957,-4.34071],"population":[[-0.513866,1.26256],[-1.19957,-4.34071],[3.58348,9.09653],[8.28767,13.4274],[2.3487,8.83804],[2.11718,6.29325]]}}, +{"best":31044.7,"evaluations":144,"generation":23,"median":5459660.0,"state":{"best":[-1.19957,-4.34071],"population":[[-3.01725,-15.4823],[7.14772,16.889],[-1.80221,9.04068],[3.2886,-1.53707],[0.305215,-0.563641],[-1.11112,-9.74089]]}}, +{"best":31044.7,"evaluations":150,"generation":24,"median":1558990.0,"state":{"best":[-1.19957,-4.34071],"population":[[-4.12743,-14.0445],[-3.09236,-10.1941],[0.954364,7.80549],[1.39587,-1.75193],[3.81991,5.35076],[-0.251537,-7.83612]]}}, +{"best":404.083,"evaluations":156,"generation":25,"median":2997060.0,"state":{"best":[1.1727,4.91203],"population":[[-6.46576,-20.5103],[-11.4815,-31.4183],[1.1727,4.91203],[-0.463009,-12.438],[-4.38064,-10.5901],[-2.89014,-8.96371]]}}, +{"best":404.083,"evaluations":162,"generation":26,"median":542668.0,"state":{"best":[1.1727,4.91203],"population":[[-0.470801,-0.241526],[-0.810161,-4.83933],[1.74807,2.08791],[-0.47182,-7.46889],[0.215338,-0.0439924],[3.79048,11.9479]]}}, +{"best":404.083,"evaluations":168,"generation":27,"median":320751.0,"state":{"best":[1.1727,4.91203],"population":[[-2.12797,-8.49343],[1.19086,2.91806],[-3.20574,-10.9335],[3.9648,10.4009],[-1.74751,-4.78212],[0.100579,2.70678]]}}, +{"best":89.856,"evaluations":180,"generation":29,"median":337268.0,"state":{"best":[-0.581882,-2.51947],"population":[[2.03027,5.43446],[-0.538254,-4.0339],[0.375763,-2.99482],[0.234023,-1.19418],[0.83169,0.808326],[0.720555,0.738348]]}}, +{"best":89.856,"evaluations":186,"generation":30,"median":172922.0,"state":{"best":[-0.581882,-2.51947],"population":[[-1.09461,-4.8938],[0.714822,-0.0658991],[-0.758458,-5.22205],[0.534034,-2.42503],[-1.85458,-7.60037],[-0.765565,-4.89459]]}}, +{"best":89.856,"evaluations":192,"generation":31,"median":161427.0,"state":{"best":[-0.581882,-2.51947],"population":[[-1.59714,-8.47034],[0.198835,-1.55346],[-2.41454,-5.89273],[-2.28574,-7.99755],[-0.833675,-3.07307],[0.0927786,-1.37875]]}}, +{"best":89.856,"evaluations":198,"generation":32,"median":82243.4,"state":{"best":[-0.581882,-2.51947],"population":[[-0.383057,-3.73381],[-2.33637,-8.04824],[-1.10575,-4.54249],[-0.872948,-4.85606],[-0.788066,-4.20421],[-2.18614,-7.95243]]}}, +{"best":89.856,"evaluations":204,"generation":33,"median":31015.4,"state":{"best":[-0.581882,-2.51947],"population":[[-1.27013,-6.22449],[-0.918293,-4.38202],[-0.270194,-2.29504],[-0.749203,-2.46593],[-0.937972,-2.98874],[-1.05912,-4.79586]]}}, +{"best":89.856,"evaluations":210,"generation":34,"median":9039.14,"state":{"best":[-0.581882,-2.51947],"population":[[-0.879181,-3.91379],[-0.822401,-4.13031],[-1.02332,-4.96004],[-0.769984,-3.68703],[-0.667781,-3.12948],[-0.758623,-3.65817]]}}, +{"best":89.856,"evaluations":216,"generation":35,"median":6858.75,"state":{"best":[-0.581882,-2.51947],"population":[[-1.20697,-4.51058],[-0.904695,-4.20861],[-0.819619,-3.41287],[-0.705704,-3.16097],[-0.732943,-3.6264],[-0.393691,-2.04833]]}}, +{"best":76.7078,"evaluations":228,"generation":37,"median":2497.17,"state":{"best":[-0.965785,-4.08181],"population":[[-1.2166,-4.96376],[-0.833234,-3.49387],[-0.810169,-3.15409],[-0.847304,-3.82569],[-0.891516,-4.0354],[-0.965785,-4.08181]]}}, +{"best":21.8324,"evaluations":234,"generation":38,"median":514.165,"state":{"best":[-0.813385,-3.47922],"population":[[-0.813385,-3.47922],[-0.891436,-3.73123],[-0.794724,-3.48798],[-0.825205,-3.61075],[-0.778724,-3.4683],[-0.983432,-3.88348]]}}, +{"best":21.8324,"evaluations":240,"generation":39,"median":4936.08,"state":{"best":[-0.813385,-3.47922],"population":[[-0.708724,-3.43402],[-0.832984,-3.4723],[-1.01642,-4.01696],[-0.544507,-2.62012],[-0.926122,-3.89822],[-0.636365,-3.24345]]}}, +{"best":21.8324,"evaluations":246,"generation":40,"median":596.747,"state":{"best":[-0.813385,-3.47922],"population":[[-0.817213,-3.54105],[-0.948373,-3.81397],[-0.989088,-4.27686],[-0.814556,-3.5655],[-0.866788,-3.52753],[-0.952007,-3.94112]]}}, +{"best":21.8324,"evaluations":252,"generation":41,"median":760.081,"state":{"best":[-0.813385,-3.47922],"population":[[-0.977333,-4.15041],[-0.773537,-3.39004],[-0.650476,-3.07605],[-0.931013,-3.89395],[-0.950944,-3.7622],[-0.782106,-3.47365]]}}, +{"best":20.3903,"evaluations":258,"generation":42,"median":83.3624,"state":{"best":[-1.03074,-4.39135],"population":[[-0.985728,-4.13488],[-0.997253,-4.29153],[-1.03074,-4.39135],[-1.01633,-4.30466],[-0.969513,-4.18245],[-0.977384,-4.17557]]}}, +{"best":20.3903,"evaluations":264,"generation":43,"median":2065.61,"state":{"best":[-1.03074,-4.39135],"population":[[-0.890995,-4.06461],[-1.17197,-4.78669],[-0.895297,-4.00311],[-1.07644,-4.35742],[-1.12925,-4.6776],[-1.09984,-4.62464]]}}, +{"best":20.3903,"evaluations":276,"generation":45,"median":474.702,"state":{"best":[-1.03074,-4.39135],"population":[[-1.1191,-4.67056],[-1.15847,-4.82471],[-1.1461,-4.91244],[-1.18801,-4.93667],[-1.09035,-4.68138],[-0.797115,-3.48535]]}}, +{"best":20.3903,"evaluations":282,"generation":46,"median":199.782,"state":{"best":[-1.03074,-4.39135],"population":[[-1.22071,-5.20231],[-1.05155,-4.53651],[-1.10902,-4.79622],[-1.01088,-4.2859],[-1.11461,-4.81554],[-1.06833,-4.49126]]}}, +{"best":20.3903,"evaluations":288,"generation":47,"median":913.34,"state":{"best":[-1.03074,-4.39135],"population":[[-1.33169,-5.63221],[-1.1745,-5.24217],[-1.09093,-4.76641],[-1.00212,-4.41276],[-1.03585,-4.22514],[-1.04849,-4.53652]]}}, +{"best":20.3903,"evaluations":294,"generation":48,"median":716.391,"state":{"best":[-1.03074,-4.39135],"population":[[-1.20032,-5.17823],[-1.51477,-6.31812],[-1.16975,-5.01173],[-1.03146,-4.49315],[-1.25072,-5.14617],[-1.37306,-5.72131]]}}, +{"best":20.3903,"evaluations":300,"generation":49,"median":417.363,"state":{"best":[-1.03074,-4.39135],"population":[[-1.04166,-4.54927],[-1.11481,-4.89031],[-1.25627,-5.40595],[-1.24917,-5.28876],[-1.31238,-5.626],[-1.0202,-4.48456]]}}, +{"best":20.3903,"evaluations":306,"generation":50,"median":96.1714,"state":{"best":[-1.03074,-4.39135],"population":[[-1.30106,-5.52415],[-1.38215,-5.80124],[-1.44718,-6.14326],[-1.33491,-5.77677],[-1.38987,-5.96322],[-1.16739,-4.99654]]}}, +{"best":20.3903,"evaluations":312,"generation":51,"median":126.105,"state":{"best":[-1.03074,-4.39135],"population":[[-1.18867,-5.00508],[-1.36433,-5.76714],[-1.24551,-5.30431],[-1.15085,-4.94273],[-1.12873,-4.87371],[-1.21278,-5.15983]]}}, +{"best":20.3903,"evaluations":324,"generation":53,"median":71.628,"state":{"best":[-1.03074,-4.39135],"population":[[-1.22512,-5.21273],[-1.26081,-5.41095],[-1.30224,-5.50666],[-1.21904,-5.19573],[-1.28206,-5.47204],[-1.27327,-5.36788]]}}, +{"best":20.3903,"evaluations":330,"generation":54,"median":39.0202,"state":{"best":[-1.03074,-4.39135],"population":[[-1.29147,-5.45801],[-1.24201,-5.29646],[-1.26004,-5.38439],[-1.27156,-5.43506],[-1.21971,-5.18569],[-1.2405,-5.27615]]}}, +{"best":20.3903,"evaluations":336,"generation":55,"median":48.5406,"state":{"best":[-1.03074,-4.39135],"population":[[-1.28566,-5.47229],[-1.20341,-5.13254],[-1.2238,-5.2358],[-1.30662,-5.5315],[-1.22883,-5.25622],[-1.22709,-5.24765]]}}, +{"best":20.3903,"evaluations":342,"generation":56,"median":34.7342,"state":{"best":[-1.03074,-4.39135],"population":[[-1.26553,-5.37879],[-1.22255,-5.19492],[-1.23538,-5.26101],[-1.24071,-5.28566],[-1.25971,-5.34437],[-1.1873,-5.06594]]}}, +{"best":20.3903,"evaluations":348,"generation":57,"median":38.4132,"state":{"best":[-1.03074,-4.39135],"population":[[-1.21392,-5.18964],[-1.19369,-5.09837],[-1.23629,-5.2837],[-1.22692,-5.21861],[-1.18698,-5.07011],[-1.21882,-5.17683]]}}, +{"best":20.3903,"evaluations":354,"generation":58,"median":29.1944,"state":{"best":[-1.03074,-4.39135],"population":[[-1.20947,-5.14032],[-1.20738,-5.13956],[-1.19285,-5.08855],[-1.22466,-5.21436],[-1.223,-5.20884],[-1.19746,-5.10116]]}}, +{"best":20.3903,"evaluations":360,"generation":59,"median":28.8498,"state":{"best":[-1.03074,-4.39135],"population":[[-1.18088,-5.03718],[-1.20659,-5.14895],[-1.164,-4.98138],[-1.21472,-5.17119],[-1.19754,-5.09976],[-1.18281,-5.04229]]}}, +{"best":20.3903,"evaluations":366,"generation":60,"median":31.2891,"state":{"best":[-1.03074,-4.39135],"population":[[-1.18539,-5.0446],[-1.21973,-5.17942],[-1.21339,-5.16562],[-1.20535,-5.12564],[-1.167,-4.97861],[-1.1984,-5.09621]]}}, +{"best":20.3903,"evaluations":378,"generation":62,"median":28.1147,"state":{"best":[-1.03074,-4.39135],"population":[[-1.19399,-5.0927],[-1.09934,-4.68068],[-1.19498,-5.08961],[-1.16312,-4.95942],[-1.19157,-5.06098],[-1.14452,-4.89149]]}}, +{"best":20.3903,"evaluations":384,"generation":63,"median":26.9295,"state":{"best":[-1.03074,-4.39135],"population":[[-1.06714,-4.53087],[-1.06832,-4.54301],[-1.09193,-4.64645],[-1.15425,-4.88884],[-1.125,-4.80172],[-1.0592,-4.51817]]}}, +{"best":15.4028,"evaluations":390,"generation":64,"median":22.4811,"state":{"best":[-0.823931,-3.51769],"population":[[-0.96936,-4.1189],[-0.960322,-4.08571],[-0.931641,-3.97142],[-1.10691,-4.74674],[-1.0418,-4.45216],[-0.823931,-3.51769]]}}, +{"best":15.4028,"evaluations":396,"generation":65,"median":37.7316,"state":{"best":[-0.823931,-3.51769],"population":[[-0.84146,-3.56847],[-0.96383,-4.10891],[-1.14253,-4.83718],[-0.936698,-4.0161],[-0.691327,-2.93488],[-0.559814,-2.41334]]}}, +{"best":3.14154,"evaluations":402,"generation":66,"median":17.6229,"state":{"best":[-0.372323,-1.58348],"population":[[-0.809233,-3.4363],[-0.683191,-2.92215],[-0.372323,-1.58348],[-0.664658,-2.85918],[-0.735735,-3.12937],[-1.10082,-4.64203]]}}, +{"best":3.14154,"evaluations":408,"generation":67,"median":120.868,"state":{"best":[-0.372323,-1.58348],"population":[[-1.16241,-4.93108],[-0.231173,-1.04016],[-0.270548,-1.19222],[-0.272499,-1.00065],[0.267716,1.21115],[-0.62491,-2.67262]]}}, +{"best":3.14154,"evaluations":414,"generation":68,"median":153.427,"state":{"best":[-0.372323,-1.58348],"population":[[-0.97555,-4.11201],[-0.611937,-2.54215],[-0.654702,-2.76725],[-1.02813,-4.31875],[0.0802091,0.370654],[-0.98711,-4.15014]]}}, +{"best":3.14154,"evaluations":426,"generation":70,"median":141.22,"state":{"best":[-0.372323,-1.58348],"population":[[0.179152,0.691005],[-0.734281,-3.17423],[-0.925616,-3.89089],[-0.662617,-2.779],[-0.656049,-2.76031],[-1.04231,-4.51039]]}}, +{"best":3.14154,"evaluations":432,"generation":71,"median":95.3447,"state":{"best":[-0.372323,-1.58348],"population":[[-0.470713,-2.01849],[-0.0060146,0.0516414],[-0.511786,-2.12849],[-0.509403,-2.08098],[-0.114428,-0.463436],[-0.366788,-1.5352]]}}, +{"best":3.14154,"evaluations":438,"generation":72,"median":10.8326,"state":{"best":[-0.372323,-1.58348],"population":[[-0.141826,-0.640701],[-0.0911006,-0.380344],[-0.402419,-1.71741],[-0.457559,-1.96115],[-0.642209,-2.72904],[-0.138132,-0.543606]]}}, +{"best":1.17959,"evaluations":444,"generation":73,"median":48.1032,"state":{"best":[-0.11396,-0.489829],"population":[[-0.354256,-1.48821],[-0.11396,-0.489829],[-0.483848,-1.99418],[-0.0492243,-0.171114],[-0.24731,-1.02024],[0.357132,1.4964]]}}, +{"best":1.17959,"evaluations":450,"generation":74,"median":18.7587,"state":{"best":[-0.11396,-0.489829],"population":[[-0.147539,-0.598294],[-0.0420091,-0.174319],[-0.449035,-1.93027],[-0.360956,-1.55736],[-0.0650892,-0.282633],[-0.337913,-1.45776]]}}, +{"best":1.17959,"evaluations":456,"generation":75,"median":43.8154,"state":{"best":[-0.11396,-0.489829],"population":[[0.0395137,0.125149],[-0.0727758,-0.349585],[-0.00631245,-0.0652837],[0.078539,0.329732],[-0.541016,-2.29547],[-0.484831,-2.05942]]}}, +{"best":1.17959,"evaluations":462,"generation":76,"median":14.7467,"state":{"best":[-0.11396,-0.489829],"population":[[-0.167543,-0.731356],[-0.306539,-1.28455],[0.253945,1.05429],[-0.155783,-0.649344],[0.0495149,0.196242],[-0.156864,-0.683984]]}}, +{"best":0.0863695,"evaluations":474,"generation":78,"median":1.61147,"state":{"best":[0.0568072,0.24138],"population":[[-0.0503934,-0.212563],[-0.155783,-0.667099],[-0.0212145,-0.0968724],[-0.145776,-0.612382],[0.0382726,0.161237],[-0.120017,-0.503587]]}}, +{"best":0.0863695,"evaluations":480,"generation":79,"median":2.06424,"state":{"best":[0.0568072,0.24138],"population":[[0.130407,0.554794],[-0.0487196,-0.201976],[-0.00731182,-0.0379793],[0.0667704,0.285405],[-0.12328,-0.518141],[-0.0355463,-0.162378]]}}, +{"best":0.0863695,"evaluations":486,"generation":80,"median":0.719728,"state":{"best":[0.0568072,0.24138],"population":[[0.00550647,0.0251489],[0.199229,0.864614],[-0.0340502,-0.137704],[-0.0365141,-0.1517],[0.0799228,0.339478],[0.0906327,0.383216]]}}, +{"best":0.0863695,"evaluations":492,"generation":81,"median":0.518507,"state":{"best":[0.0568072,0.24138],"population":[[-0.0644646,-0.269899],[-0.0754174,-0.321486],[0.0171819,0.0697117],[0.0608265,0.256521],[0.144998,0.619774],[0.00859495,0.038755]]}}, +{"best":0.00344084,"evaluations":498,"generation":82,"median":0.545201,"state":{"best":[-0.00102911,-0.00412923],"population":[[0.104252,0.45095],[0.0360674,0.152339],[0.0945647,0.400139],[-0.00102911,-0.00412923],[0.0807792,0.348454],[0.0431292,0.180784]]}}, +{"best":0.00344084,"evaluations":504,"generation":83,"median":0.188908,"state":{"best":[-0.00102911,-0.00412923],"population":[[-0.03699,-0.155921],[-0.0165621,-0.0713485],[-0.0437286,-0.185095],[0.0954346,0.405956],[0.0783954,0.328946],[0.0394388,0.16417]]}}, +{"best":0.00344084,"evaluations":510,"generation":84,"median":0.47076,"state":{"best":[-0.00102911,-0.00412923],"population":[[-0.0249145,-0.102999],[-0.0494688,-0.21514],[-0.0735781,-0.316249],[-0.0401658,-0.173993],[-0.00235452,-0.00916268],[-0.046587,-0.200639]]}}, +{"best":0.00344084,"evaluations":522,"generation":86,"median":0.0270531,"state":{"best":[-0.00102911,-0.00412923],"population":[[-0.0277773,-0.118294],[0.013388,0.0563982],[0.0383264,0.163223],[0.0607826,0.259962],[-0.0179193,-0.0758274],[-0.00646582,-0.0284181]]}}, +{"best":0.00344084,"evaluations":528,"generation":87,"median":0.0392124,"state":{"best":[-0.00102911,-0.00412923],"population":[[-0.02666,-0.112483],[-0.0430561,-0.182832],[0.00671272,0.029132],[-0.00661308,-0.0275474],[-0.0398677,-0.16792],[-0.0146859,-0.062292]]}}, +{"best":0.00344084,"evaluations":534,"generation":88,"median":0.0515486,"state":{"best":[-0.00102911,-0.00412923],"population":[[-0.0152958,-0.0640431],[0.00766353,0.0340499],[-0.0193477,-0.0829383],[0.00697449,0.0304828],[-0.0275545,-0.116263],[-0.0178348,-0.0760297]]}}, +{"best":0.00344084,"evaluations":540,"generation":89,"median":0.0329544,"state":{"best":[-0.00102911,-0.00412923],"population":[[0.0214167,0.0911463],[-0.0100511,-0.0426288],[-0.0039673,-0.0177828],[-0.0397963,-0.169706],[-0.0343405,-0.147031],[-0.0313547,-0.13416]]}}, +{"best":0.000918539,"evaluations":546,"generation":90,"median":0.00754067,"state":{"best":[0.00553636,0.0235118],"population":[[-0.0107776,-0.045365],[0.00553636,0.0235118],[0.017349,0.0738383],[0.00682306,0.0293385],[0.00672328,0.0282567],[-0.0200531,-0.084972]]}}, +{"best":0.000918539,"evaluations":552,"generation":91,"median":0.00469005,"state":{"best":[0.00553636,0.0235118],"population":[[0.0152777,0.0654613],[-0.0129039,-0.0546843],[-0.00926723,-0.0396598],[0.00509773,0.0220098],[-0.00544793,-0.0234914],[-0.00166783,-0.00687514]]}}, +{"best":0.000137904,"evaluations":558,"generation":92,"median":0.00209162,"state":{"best":[-0.00188937,-0.00801446],"population":[[0.00373083,0.0159329],[-0.0118854,-0.0504174],[0.00412495,0.01744],[-0.00188937,-0.00801446],[-0.011408,-0.0489144],[0.0100827,0.0428307]]}}, +{"best":0.000137904,"evaluations":570,"generation":94,"median":0.00096498,"state":{"best":[-0.00188937,-0.00801446],"population":[[-0.00660722,-0.0282192],[-0.00729434,-0.0312329],[-0.000369214,-0.00144397],[-0.00482689,-0.0202288],[-0.00429614,-0.0182846],[-0.00364162,-0.0155464]]}}, +{"best":7.45197e-05,"evaluations":576,"generation":95,"median":0.000513952,"state":{"best":[-0.00149745,-0.00640549],"population":[[-0.0125626,-0.0534969],[0.00166099,0.00729185],[-0.000312424,-0.00137631],[-0.00149745,-0.00640549],[-0.00521848,-0.0221495],[-0.00124044,-0.00525019]]}}, +{"best":7.45197e-05,"evaluations":582,"generation":96,"median":0.000437803,"state":{"best":[-0.00149745,-0.00640549],"population":[[-0.00190609,-0.0080616],[0.00149462,0.00629062],[-0.00531686,-0.0225878],[-0.0033064,-0.0140254],[-0.00168477,-0.00738737],[-0.000449317,-0.00182175]]}}, +{"best":7.25823e-05,"evaluations":588,"generation":97,"median":0.000563428,"state":{"best":[0.000279103,0.00122621],"population":[[-0.00328305,-0.0139192],[0.000279103,0.00122621],[-0.00579477,-0.0247111],[-0.0027918,-0.0117893],[-0.00224754,-0.00949534],[-0.00148759,-0.00621619]]}}, +{"best":5.82612e-05,"evaluations":594,"generation":98,"median":0.000330134,"state":{"best":[-0.00108462,-0.00464794],"population":[[-0.00108462,-0.00464794],[-0.002834,-0.0118665],[-0.00412507,-0.0176258],[0.00205986,0.00890965],[-0.00264309,-0.0112236],[-0.00142463,-0.00609004]]}}, +{"best":1.13027e-05,"evaluations":600,"generation":99,"median":0.000270015,"state":{"best":[0.000689255,0.00294353],"population":[[0.000689255,0.00294353],[-0.00372936,-0.0159119],[-0.00165031,-0.00697045],[-0.000199511,-0.000822125],[-0.00338396,-0.0143787],[-0.000840561,-0.00348991]]}}, +{"best":1.00239e-06,"evaluations":606,"generation":100,"median":0.000139896,"state":{"best":[-0.000207256,-0.000885007],"population":[[-0.00429539,-0.0183468],[-0.0048457,-0.0205935],[0.000270247,0.00110299],[0.00133945,0.00575575],[-0.000207256,-0.000885007],[0.00114776,0.00488333]]}}, +{"best":3.7624e-07,"evaluations":618,"generation":102,"median":1.79784e-05,"state":{"best":[0.000139722,0.000595588],"population":[[-0.000114974,-0.00048626],[-0.000258096,-0.00110173],[-0.000526445,-0.00224828],[0.000782307,0.00331518],[0.000258482,0.00106747],[-0.000838721,-0.0036268]]}}, +{"best":3.7624e-07,"evaluations":624,"generation":103,"median":1.86052e-05,"state":{"best":[0.000139722,0.000595588],"population":[[-0.000331326,-0.00139854],[1.61959e-05,5.82682e-05],[0.000120722,0.000505457],[-0.000113345,-0.000459753],[-0.000143962,-0.00063554],[0.000786476,0.00338864]]}}, +{"best":3.7624e-07,"evaluations":630,"generation":104,"median":1.01939e-05,"state":{"best":[0.000139722,0.000595588],"population":[[1.13919e-05,6.43298e-05],[0.000395217,0.00168975],[0.000128918,0.00053411],[0.000391908,0.00167874],[0.000262029,0.00110527],[0.000216969,0.000950297]]}}, +{"best":3.7624e-07,"evaluations":636,"generation":105,"median":2.15401e-05,"state":{"best":[0.000139722,0.000595588],"population":[[-0.000143779,-0.000631617],[0.000765279,0.00326182],[-0.000249388,-0.00106305],[-0.000163863,-0.000721922],[0.000552441,0.00233543],[0.00102795,0.00439991]]}}, +{"best":2.2623e-07,"evaluations":642,"generation":106,"median":3.23373e-06,"state":{"best":[-3.89272e-05,-0.000167819],"population":[[0.000269914,0.00114075],[-3.89272e-05,-0.000167819],[0.000102658,0.00042944],[2.53005e-05,0.000113679],[5.16395e-05,0.000228823],[0.000390192,0.00166245]]}}, +{"best":1.25063e-07,"evaluations":648,"generation":107,"median":2.97165e-06,"state":{"best":[-7.14107e-05,-0.000305018],"population":[[-9.43311e-05,-0.000391421],[0.00045382,0.00193786],[-7.14107e-05,-0.000305018],[-2.16181e-05,-9.61437e-05],[0.000385231,0.00165455],[0.000215232,0.000919345]]}}, +{"best":1.25063e-07,"evaluations":654,"generation":108,"median":1.50608e-06,"state":{"best":[-7.14107e-05,-0.000305018],"population":[[-0.000110583,-0.000472204],[8.46791e-05,0.000359456],[5.47538e-05,0.000221812],[-4.32e-05,-0.000189938],[0.000342065,0.00146283],[0.000142828,0.000612521]]}}, +{"best":7.94895e-08,"evaluations":666,"generation":110,"median":2.24037e-07,"state":{"best":[-5.41643e-05,-0.000231472],"population":[[-0.000102779,-0.000438052],[-3.19261e-06,-1.51982e-05],[-8.36493e-05,-0.000356741],[-0.000139239,-0.000593863],[-0.000203539,-0.000868485],[0.000105933,0.000452159]]}}, +{"best":6.11367e-08,"evaluations":672,"generation":111,"median":3.02535e-07,"state":{"best":[-4.16658e-05,-0.000178276],"population":[[-3.11992e-06,-1.69795e-05],[3.27621e-05,0.00014051],[-4.16658e-05,-0.000178276],[3.20029e-05,0.000134516],[-9.42266e-06,-4.46514e-05],[0.00010749,0.000459914]]}}, +{"best":5.51171e-08,"evaluations":678,"generation":112,"median":1.41727e-07,"state":{"best":[-2.09399e-05,-8.82827e-05],"population":[[5.38695e-05,0.000229911],[-2.09399e-05,-8.82827e-05],[4.89318e-05,0.000211306],[-8.32708e-05,-0.000355263],[7.9288e-05,0.000337234],[-0.000138355,-0.000588032]]}}, +{"best":1.24807e-09,"evaluations":684,"generation":113,"median":1.64807e-07,"state":{"best":[-2.43957e-06,-1.02481e-05],"population":[[-8.67331e-05,-0.000370669],[8.85773e-05,0.00037837],[-8.15625e-05,-0.000347183],[-3.03172e-05,-0.000130184],[-2.43957e-06,-1.02481e-05],[8.60207e-05,0.0003686]]}} +]} diff --git a/examples/discus/trace.py b/examples/discus/trace.py new file mode 100644 index 00000000..1e111d91 --- /dev/null +++ b/examples/discus/trace.py @@ -0,0 +1,190 @@ +"""The trace for the plot on the example's page, written to the file that ``GENOXIDE_TRACE`` +names. The plot draws the population on the function's contour, which needs two dimensions: the +trace is of a separate run of CMA-ES in 2 dimensions, rotated with seed 1, with a budget of +20,000 evaluations, in at most 100 frames. The Rust example writes the same file.""" + +import json +import math +import os + +import genoxide as gx + + +def record_small(): + """Runs CMA-ES in 2 dimensions and writes its trace, if ``GENOXIDE_TRACE`` is set.""" + path = os.environ.get("GENOXIDE_TRACE") + if not path: + return + problem = gx.problems.Rotated(gx.problems.Discus(2), seed=1) + minimum = problem.optimum.value + budget = 20_000 + cmaes = gx.Cmaes(problem.genome, objective="minimize", seed=1) + frames = Frames(100) + + def record(progress): + state = {"population": progress.population.tolist(), "best": progress.best_genome.tolist()} + frames.push(frame(progress, state, minimum)) + + cmaes.run(problem, target=minimum + 1e-8, evaluations=budget, on_generation=record) + low, high = problem.genome.bounds + settings = { + "format": 1, + "example": "discus", + "objective": "minimize", + "x_label": "evaluations", + "y_label": "error", + "log_y": True, + "optimum": 0.0, + "plot": "contour", + "problem": { + "function": "discus", + "bounds": [[float(low), float(high)]] * 2, + "minima": problem.optimum.solutions.tolist(), + "rotation": {"matrix": problem.matrix.tolist(), "center": problem.center.tolist()}, + }, + } + write(path, settings, frames.to_list()) + + +def frame(progress, state, minimum): + """The frame of a generation: its progress, the errors of its best and of its population's + median to ``minimum`` (rounding can put a solution a few ulps below it), and ``state``.""" + + def error(value): + return None if value is None else max(value - minimum, 0.0) + + return { + "generation": progress.generation, + "evaluations": progress.evaluations, + "best": error(progress.best_fitness), + "median": error(median(progress.scores)), + "state": state, + } + + +def median(scores): + """The median of the valid scores, None without any.""" + scores = sorted(float(score) for score in scores if not math.isnan(score)) + middle = len(scores) // 2 + if not scores: + return None + return scores[middle] if len(scores) % 2 else (scores[middle - 1] + scores[middle]) / 2 + + +# ---- the same in every example's trace ---------------------------------------------------------- + + +class Frames: + """The frames of at most ``most`` generations, from the part of the run where what the page + plots changes: the frames after the last change are left out (a run that reached its target, + or a front that no longer moves), and the rest are spread evenly over the generations up to + it. While the run goes, up to 8 × ``most`` frames are kept: every ``every``-th generation, + with ``every`` doubling whenever there are that many, and the last one.""" + + def __init__(self, most): + self.most, self.every, self.kept, self.last = most, 1, [], None + + def push(self, frame): + if frame["generation"] % self.every: + self.last = frame + return + self.kept.append(frame) + self.last = None + if len(self.kept) == 8 * self.most: + self.every *= 2 + self.kept = [kept for kept in self.kept if kept["generation"] % self.every == 0] + + def to_list(self): + frames = self.kept + ([self.last] if self.last else []) + active = frames[: last_change(frames) + 1] + count, most = len(active), max(self.most, 2) + if count <= most: + return active + return [active[(i * (count - 1) + (most - 1) // 2) // (most - 1)] for i in range(most)] + + +def last_change(frames): + """The index of the frame after which nothing the page plots changes. To 3 significant + digits, as a plot shows them: the best, the median and, for a single objective (a numeric + best), the state; to within a hundredth of their range over the run: a front's + hypervolumes, in the state or in a grid's series.""" + if not frames: + return 0 + last = len(frames) - 1 + number = lambda value: isinstance(value, (int, float)) and not isinstance(value, bool) + single = any(number(frame.get("best")) for frame in frames) + + def measures(frame): + values = [] + state = frame.get("state") + hypervolume = state.get("hypervolume") if isinstance(state, dict) else None + for value in (hypervolume, frame.get("series")): + if number(value): + values.append(float(value)) + elif isinstance(value, dict): + values.extend(float(v) for _, v in sorted(value.items()) if number(v)) + return values + + measured = [measures(frame) for frame in frames] + end = measured[last] + tolerance = [] + for k in range(len(end)): + values = [values[k] for values in measured if k < len(values)] + tolerance.append((max(values) - min(values)) / 100.0) + + def same(frame, final, key, flush=False): + return coarse(frame.get(key), flush) == coarse(final.get(key), flush) + + def settled(i): + frame, final = frames[i], frames[last] + return ( + same(frame, final, "best") + and same(frame, final, "median") + and (not single or same(frame, final, "state", flush=True)) + and len(measured[i]) == len(end) + and all(abs(v - e) <= t for v, e, t in zip(measured[i], end, tolerance)) + ) + + first = last + while first > 0 and settled(first - 1): + first -= 1 + return first + + +def coarse(value, flush=False): + """``value`` with its numbers to 3 significant digits, as precisely as a plot shows them: two + frames whose plotted values agree to that precision look the same. With ``flush``, for the + solutions a plot draws on their ranges, numbers below 1e-6 in size count as 0.""" + if isinstance(value, float): + if flush and abs(value) < 1e-6: + value = 0.0 + return f"{value:.2e}" + if isinstance(value, (list, tuple)): + return "[" + ",".join(coarse(item, flush) for item in value) + "]" + if isinstance(value, dict): + items = sorted(value.items()) + return "{" + ",".join(f"{key}:{coarse(item, flush)}" for key, item in items) + "}" + return json.dumps(value) + + +def write(path, settings, frames): + """Writes the settings and the frames to ``path``, a frame per line.""" + lines = ",\n".join(map(to_json, frames)) + with open(path, "w", encoding="utf-8", newline="\n") as file: + file.write(f'{to_json(settings)[:-1]},"frames":[\n{lines}\n]}}\n') + + +def to_json(value): + """Compact JSON with sorted keys, and numbers rounded to 6 significant digits, as the Rust + example writes it.""" + return json.dumps(rounded(value), sort_keys=True, separators=(",", ":"), ensure_ascii=False) + + +def rounded(value): + if isinstance(value, dict): + return {key: rounded(item) for key, item in value.items()} + if isinstance(value, (list, tuple)): + return [rounded(item) for item in value] + if isinstance(value, float): + return float(f"{value:.5e}") if math.isfinite(value) else None + return value diff --git a/examples/discus/trace.rs b/examples/discus/trace.rs new file mode 100644 index 00000000..cbe57984 --- /dev/null +++ b/examples/discus/trace.rs @@ -0,0 +1,264 @@ +//! The trace for the plot on the example's page, written to the file that `GENOXIDE_TRACE` names. +//! The plot draws the population on the function's contour, which needs two dimensions: the trace +//! is of a separate run of CMA-ES in 2 dimensions, rotated with seed 1, with a budget of +//! 20,000 evaluations, in at most 100 frames. The Python example writes the same +//! file. + +use genoxide::observer::Snapshot; +use genoxide::prelude::*; +use genoxide::problems::{Discus, Problem, Rotated}; +use serde_json::{Value, json}; + +// runs CMA-ES in 2 dimensions and writes its trace, if GENOXIDE_TRACE is set +pub fn record_small() -> Result<()> { + let Ok(path) = std::env::var("GENOXIDE_TRACE") else { + return Ok(()); + }; + let problem = Rotated::new(Discus::new(2), 1); + let optimum = problem.optimum().expect("known"); + let minimum = optimum.value(); + let budget = 20_000; + let cmaes = Cmaes::builder(problem.representation()) + .minimize() + .seed(1) + .build()?; + let mut frames = Frames::new(100); + Engine::new(cmaes, problem.clone()) + .stop_when(Stop::target(minimum + 1e-8).or(Stop::evaluations(budget))) + .on_generation(|snapshot| { + let population = snapshot.population().iter().map(|x| &x.genome()[..]); + let population: Vec<&[f64]> = population.collect(); + let best = &snapshot.best().genome()[..]; + let state = json!({ "population": population, "best": best }); + frames.push(frame(snapshot, state, minimum)); + }) + .run()?; + let bounds = problem.representation().bounds().to_vec(); + let bounds: Vec<[f64; 2]> = bounds.iter().map(|b| [*b.start(), *b.end()]).collect(); + let minima: Vec<&[f64]> = optimum.solutions().iter().map(|x| &x[..]).collect(); + let settings = json!({ + "format": 1, + "example": "discus", + "objective": "minimize", + "x_label": "evaluations", + "y_label": "error", + "log_y": true, + "optimum": 0.0, + "plot": "contour", + "problem": { + "function": "discus", + "bounds": bounds, + "minima": minima, + "rotation": { + "matrix": problem.matrix().chunks(2).collect::>(), + "center": problem.center(), + }, + }, + }); + write(&path, settings, frames.into_vec()); + Ok(()) +} + +// the frame of a generation: its progress, the errors of its best and of its population's median +// to `minimum` (rounding can put a solution a few ulps below it), and `state` +fn frame(snapshot: &Snapshot<'_, Reals>, state: Value, minimum: f64) -> Value { + let progress = snapshot.progress(); + let error = |value: f64| (value - minimum).max(0.0); + let population = snapshot.population().iter(); + let scores = population.filter_map(|individual| individual.fitness()?.score()); + json!({ + "generation": progress.generation(), + "evaluations": progress.evaluations(), + "best": progress.best().and_then(Fitness::score).map(error), + "median": median(scores.collect()).map(error), + "state": state, + }) +} + +// the median of the scores, None without any +fn median(mut scores: Vec) -> Option { + scores.sort_by(f64::total_cmp); + let middle = scores.len() / 2; + match scores.len() { + 0 => None, + n if n % 2 == 1 => Some(scores[middle]), + _ => Some((scores[middle - 1] + scores[middle]) / 2.0), + } +} + +// ---- the same in every example's trace --------------------------------------------------------- + +// the frames of at most `most` generations, from the part of the run where what the page plots +// changes: the frames after the last change are left out (a run that reached its target, or a +// front that no longer moves), and the rest are spread evenly over the generations up to it. While +// the run goes, up to 8 × `most` frames are kept: every `every`-th generation, with `every` +// doubling whenever there are that many, and the last one. +struct Frames { + most: usize, + every: u64, + kept: Vec<(u64, Value)>, + last: Option<(u64, Value)>, +} + +impl Frames { + fn new(most: usize) -> Self { + let (every, kept, last) = (1, Vec::new(), None); + Self { + most, + every, + kept, + last, + } + } + + fn push(&mut self, frame: Value) { + let generation = frame["generation"].as_u64().expect("a generation"); + if !generation.is_multiple_of(self.every) { + self.last = Some((generation, frame)); + return; + } + self.kept.push((generation, frame)); + self.last = None; + if self.kept.len() == 8 * self.most { + self.every *= 2; + let every = self.every; + self.kept.retain(|(generation, _)| generation % every == 0); + } + } + + fn into_vec(self) -> Vec { + let frames = self.kept.into_iter().chain(self.last); + let frames: Vec = frames.map(|(_, frame)| frame).collect(); + let active = &frames[..=last_change(&frames)]; + let (count, most) = (active.len(), self.most.max(2)); + if count <= most { + return active.to_vec(); + } + let at = |i: usize| active[(i * (count - 1) + (most - 1) / 2) / (most - 1)].clone(); + (0..most).map(at).collect() + } +} + +// the index of the frame after which nothing the page plots changes. To 3 significant digits, as +// a plot shows them: the best, the median and, for a single objective (a numeric best), the state; +// to within a hundredth of their range over the run: a front's hypervolumes, in the state or in a +// grid's series +fn last_change(frames: &[Value]) -> usize { + let Some(last) = frames.len().checked_sub(1) else { + return 0; + }; + let single = frames.iter().any(|frame| frame["best"].is_number()); + let measures = |frame: &Value| -> Vec { + let mut values = Vec::new(); + for value in [&frame["state"]["hypervolume"], &frame["series"]] { + match value { + Value::Number(number) => values.extend(number.as_f64()), + Value::Object(map) => values.extend(map.values().filter_map(Value::as_f64)), + _ => {} + } + } + values + }; + let measured: Vec> = frames.iter().map(measures).collect(); + let end = &measured[last]; + let tolerance: Vec = (0..end.len()) + .map(|k| { + let values = measured.iter().filter_map(|values| values.get(k).copied()); + let (low, high) = values.fold((f64::INFINITY, f64::NEG_INFINITY), |(low, high), v| { + (low.min(v), high.max(v)) + }); + (high - low) / 100.0 + }) + .collect(); + let settled = |i: usize| { + let (frame, final_frame) = (&frames[i], &frames[last]); + let same = + |key: &str, flush: bool| coarse(&frame[key], flush) == coarse(&final_frame[key], flush); + same("best", false) + && same("median", false) + && (!single || same("state", true)) + && measured[i].len() == end.len() + && measured[i] + .iter() + .zip(end) + .zip(&tolerance) + .all(|((value, end), tolerance)| (value - end).abs() <= *tolerance) + }; + let mut first = last; + while first > 0 && settled(first - 1) { + first -= 1; + } + first +} + +// `value` with its numbers to 3 significant digits, as precisely as a plot shows them: two frames +// whose plotted values agree to that precision look the same. With `flush`, for the solutions a +// plot draws on their ranges, numbers below 1e-6 in size count as 0 +fn coarse(value: &Value, flush: bool) -> String { + let join = |items: Vec| items.join(","); + match value { + Value::Number(number) if number.is_f64() => { + let number = number.as_f64().expect("f64"); + let number = if flush && number.abs() < 1e-6 { + 0.0 + } else { + number + }; + format!("{number:.2e}") + } + Value::Array(items) => { + format!( + "[{}]", + join(items.iter().map(|item| coarse(item, flush)).collect()) + ) + } + Value::Object(map) => { + let entry = |(key, item): (&String, &Value)| format!("{key}:{}", coarse(item, flush)); + format!("{{{}}}", join(map.iter().map(entry).collect())) + } + other => other.to_string(), + } +} + +// writes the settings and the frames to `path`, a frame per line +fn write(path: &str, settings: Value, frames: Vec) { + let frames: Vec = frames.iter().map(to_json).collect(); + let settings = to_json(&settings); + let head = &settings[..settings.len() - 1]; + let text = format!("{head},\"frames\":[\n{}\n]}}\n", frames.join(",\n")); + std::fs::write(path, text).expect("the trace is written"); +} + +// compact JSON with sorted keys, and numbers rounded to 6 significant digits and written as +// Python writes them (7542.0, 1e-08): the Python example writes the same file +fn to_json(value: &Value) -> String { + let join = |items: Vec| items.join(","); + match value { + Value::Number(number) if number.is_f64() => python_float(number.as_f64().expect("f64")), + Value::Array(items) => format!("[{}]", join(items.iter().map(to_json).collect())), + Value::Object(map) => { + let entry = + |(key, item): (&String, &Value)| format!("{}:{}", json!(key), to_json(item)); + format!("{{{}}}", join(map.iter().map(entry).collect())) + } + other => other.to_string(), + } +} + +fn python_float(value: f64) -> String { + let rounded: f64 = format!("{value:.5e}").parse().expect("a number"); + let shortest = format!("{rounded:e}"); + let (mantissa, exponent) = shortest.split_once('e').expect("an exponent"); + let exponent: i32 = exponent.parse().expect("an exponent"); + if (-4..16).contains(&exponent) { + let text = rounded.to_string(); + if text.contains('.') { + text + } else { + text + ".0" + } + } else { + let sign = if exponent < 0 { '-' } else { '+' }; + format!("{mantissa}e{sign}{:02}", exponent.abs()) + } +} diff --git a/examples/happy_cat/README.md b/examples/happy_cat/README.md new file mode 100644 index 00000000..294e23cd --- /dev/null +++ b/examples/happy_cat/README.md @@ -0,0 +1,81 @@ +--- +title: HappyCat +category: continuous +summary: Minimize HappyCat, a groove that curves around to the minimum, in 10 dimensions, with CMA-ES without and with restarts, DE, PSO and a GA from 10 seeds each. +reference: "Beyer, H.-G. and Finck, S. (2012). HappyCat: a simple function class where well-known direct search algorithms do fail. Parallel Problem Solving from Nature, PPSN XII, LNCS 7491: 367-376." +reference_url: "https://doi.org/10.1007/978-3-642-32937-1_37" +optimum: "0 (at (−1, …, −1))" +languages: [rust, python] +order: 97 +trace_note: "Recorded from another run: CMA-ES with IPOP restarts in 2 dimensions, so that the population can be drawn on the function's contour." +--- + +# HappyCat + +## The problem + +HappyCat adds a slope to the distance from a sphere of radius √n: + +```text +f(x) = |Σ xᵢ² − n|^(1/4) + (½ Σ xᵢ² + Σ xᵢ) / n + ½, each xᵢ in [−5, 5] +``` + +Its minimum is 0, at (−1, …, −1), the only one: the second part is Σ (xᵢ + 1)² / (2n), 0 only +there, where the first is 0 too. Here n = 10. It's Beyer and Finck's (2012) function, which +couldn't be read: its parameter α shapes the groove, and its experiments use α = 1/8, which would +be this function's 1/4 if α is the exponent of (Σ xᵢ² − n)², as it's usually written; that couldn't +be confirmed. genoxide takes the definition from the CEC 2014 report (Liang, Qu and Suganthan 2013, +function 11), which cites Beyer and Finck and scales its search space [−100, 100] by 5/100, to +[−5, 5]. The original is still to be checked (issue #168). + +## What makes it hard + +The first term is 0 on the sphere Σ xᵢ² = n and rises steeply, as a fourth root, away from it: a +narrow groove around the sphere. The slope along the groove is gentle, and the minimum lies in the +groove. A search falls into the groove at once, then has to follow it around the sphere; its steps +must be small across the groove and large along it, a direction that curves as it goes. Beyer and +Finck built it as a simple function on which well-known direct search methods fail: they stall in +the groove. The shape of its contour in two dimensions gave it its name. + +## Representation + +A `Real` genome of 10 genes, each in [−5, 5]: the point x itself. The fitness is f(x), to +minimize. The function is genoxide's `problems::HappyCat`, which brings its bounds and its minimum. + +## Algorithm + +Five algorithms, each from seeds 1 to 10, with a budget of 10,000 evaluations per dimension, +100,000 per run, and a target of 1e-8: + +- CMA-ES (Hansen and Ostermeier, 2001, Evolutionary Computation 9(2): 159-195), which samples a + population of 10 from a normal distribution and adapts its mean, its step size and its covariance + matrix, from a step size of 0.3 of each gene's range and a random start; +- the same with IPOP restarts (Auger and Hansen, 2005, IEEE CEC 2005: 1769-1776): a run that has + converged starts again from a random point with twice the population; +- differential evolution with genoxide's defaults, SHADE (Tanabe and Fukunaga, CEC 2013), with a + population of 100 and its restarts on stagnation; +- particle swarm optimization (Kennedy and Eberhart, 1995), 40 particles with Clerc and Kennedy's + constriction coefficients and a global topology; +- a real-coded genetic algorithm: a population of 100, tournaments of 3, simulated binary crossover + (Deb and Agrawal, 1995) with η = 15 and polynomial mutation with η = 20 at a rate of 1/10 per + gene. + +## Output + +The first line gives the dimension, the seeds and the budget. Then a row per algorithm: how many +of its 10 runs reached the minimum, to within 1e-8, the median of their evaluations (a dash if none +did), and the median of every run's best error, to two significant digits. The function is +evaluated with genoxide's portable math, so the runs are the same on every platform, and in Python, +`run` evaluates it in Rust, so both versions print the same. + +[The project page](https://tachsin.gr/projects/genoxide/examples/happy-cat) plays back another run: +CMA-ES with IPOP restarts on the function in 2 dimensions, so that the population +can be drawn on its contour. Within 20,000 evaluations it ends at an error of 1.7e-4, in the groove near the minimum: +it doesn't reach the target in 2 dimensions either. + +## Good results + +No algorithm reaches the minimum to within 1e-8: that's the function's point. CMA-ES with IPOP +restarts comes closest, with a median error of 5.4·10⁻³; CMA-ES without restarts ends at +9.4·10⁻², the genetic algorithm at 7.8·10⁻², SHADE at 0.10 and PSO at 0.14. They all reach the +groove, and stall in it, short of the minimum. diff --git a/examples/happy_cat/main.py b/examples/happy_cat/main.py new file mode 100644 index 00000000..6e75757f --- /dev/null +++ b/examples/happy_cat/main.py @@ -0,0 +1,86 @@ +"""HappyCat: minimize HappyCat, a groove that curves around a sphere to the minimum, in 10 +dimensions. + +Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), +differential evolution (SHADE), particle swarm optimization and a real-coded genetic algorithm from +10 seeds each, and counts the runs that reach the minimum, 0 at (−1, …, −1), to within 1e-8. The +function is genoxide's `problems::HappyCat`, which run evaluates in Rust. + +With ``GENOXIDE_TRACE=``, it also writes a trace of a run for the plot on the example's page, +with trace.py. + + python examples/happy_cat/main.py +""" + +import genoxide as gx + +from trace import record_small + +DIMENSIONS = 10 +SEEDS = 10 +BUDGET = 10_000 * DIMENSIONS +# a run stops once its error to the minimum is at most this +ERROR = 1e-8 +ALGORITHMS = ["CMA-ES", "CMA-ES with IPOP", "DE", "PSO", "GA"] + + +def build(name, genome, seed): + """The algorithm called ``name``, on ``genome``, from ``seed``.""" + if name == "CMA-ES": + return gx.Cmaes(genome, objective="minimize", seed=seed) + if name == "CMA-ES with IPOP": + return gx.Cmaes(genome, restarts="ipop", objective="minimize", seed=seed) + if name == "DE": + return gx.De(genome, objective="minimize", seed=seed) + if name == "PSO": + return gx.Pso(genome, population_size=40, objective="minimize", seed=seed) + return gx.Ga( + genome, + population_size=100, + select=gx.Tournament(3), + crossover=gx.SimulatedBinaryCrossover(15.0), + mutation=gx.PolynomialMutation(20.0, rate=1 / DIMENSIONS), + objective="minimize", + seed=seed, + ) + + +def median(values): + """The median of ``values``, None without any.""" + values = sorted(values) + middle = len(values) // 2 + if not values: + return None + return values[middle] if len(values) % 2 else (values[middle - 1] + values[middle]) / 2 + + +def error_text(error): + """An error to two significant digits, as Rust writes it: 9.9e-9.""" + mantissa, exponent = f"{error:.1e}".split("e") + return f"{mantissa}e{int(exponent)}" + + +problem = gx.problems.HappyCat(DIMENSIONS) +minimum = problem.optimum.value +print(f"HappyCat in {DIMENSIONS} dimensions, {SEEDS} seeds, {BUDGET} evaluations at most per run") +print("algorithm at min evaluations median error") +for name in ALGORITHMS: + # the evaluations of the runs that reach the minimum, and every run's best error + evaluations, errors = [], [] + for seed in range(1, SEEDS + 1): + result = build(name, problem.genome, seed).run( + problem, target=minimum + ERROR, evaluations=BUDGET + ) + if result.stop_reason == "target": + evaluations.append(float(result.evaluations)) + # rounding can put a solution a few ulps below the minimum + errors.append(max(result.best_fitness - minimum, 0.0)) + reached = f"{len(evaluations)}/{SEEDS}" + middle = median(evaluations) + evaluations_text = "-" if middle is None else f"{middle:.0f}" + print(f"{name:<16} {reached:>6} {evaluations_text:>11} {error_text(median(errors)):>12}") +print("evaluations: the median of the runs that reach the minimum") + +# with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate run in +# 2 dimensions: the plot is the function's contour +record_small() diff --git a/examples/happy_cat/main.rs b/examples/happy_cat/main.rs new file mode 100644 index 00000000..bcb568bc --- /dev/null +++ b/examples/happy_cat/main.rs @@ -0,0 +1,118 @@ +//! HappyCat: minimize HappyCat, a groove that curves around a sphere to the minimum, in 10 +//! dimensions. +//! +//! Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), +//! differential evolution (SHADE), particle swarm optimization and a real-coded genetic algorithm +//! from 10 seeds each, and counts the runs that reach the minimum, 0 at (−1, …, −1), to within +//! 1e-8. The function is genoxide's `problems::HappyCat`. +//! +//! With `GENOXIDE_TRACE=`, it also writes a trace of a run for the plot on the example's +//! page, with `trace.rs`. +//! +//! ```text +//! cargo run --release --example happy_cat +//! ``` + +mod trace; + +use genoxide::prelude::*; +use genoxide::problems::{HappyCat, Problem}; + +const DIMENSIONS: usize = 10; +const SEEDS: u64 = 10; +const BUDGET: u64 = 10_000 * DIMENSIONS as u64; +// a run stops once its error to the minimum is at most this +const ERROR: f64 = 1e-8; +const ALGORITHMS: [&str; 5] = ["CMA-ES", "CMA-ES with IPOP", "DE", "PSO", "GA"]; + +fn main() -> Result<()> { + let problem = HappyCat::new(DIMENSIONS); + let minimum = problem.optimum().expect("known").value(); + println!( + "HappyCat in {DIMENSIONS} dimensions, {SEEDS} seeds, {BUDGET} evaluations at most per run" + ); + println!("algorithm at min evaluations median error"); + for algorithm in ALGORITHMS { + // the evaluations of the runs that reach the minimum, and every run's best error + let mut evaluations = Vec::new(); + let mut errors = Vec::new(); + for seed in 1..=SEEDS { + let outcome = run(algorithm, problem, seed, minimum + ERROR)?; + if outcome.stop_reason() == StopReason::Target { + evaluations.push(outcome.evaluations() as f64); + } + // rounding can put a solution a few ulps below the minimum + let best = outcome.best_fitness().score().expect("valid"); + errors.push((best - minimum).max(0.0)); + } + let reached = format!("{}/{SEEDS}", evaluations.len()); + let evaluations = median(evaluations).map_or("-".to_string(), |e| format!("{e:.0}")); + let error = median(errors).expect("a run"); + println!( + "{algorithm:<16} {reached:>6} {evaluations:>11} {:>12}", + format!("{error:.1e}") + ); + } + println!("evaluations: the median of the runs that reach the minimum"); + + // with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate + // run in 2 dimensions: the plot is the function's contour + trace::record_small()?; + Ok(()) +} + +// a run of `algorithm` from `seed`, until its best is at most `target` or it has used BUDGET +// evaluations +fn run(algorithm: &str, problem: HappyCat, seed: u64, target: f64) -> Result> { + let real = problem.representation(); + let stop = Stop::target(target).or(Stop::evaluations(BUDGET)); + match algorithm { + "CMA-ES" | "CMA-ES with IPOP" => { + let restarts = if algorithm == "CMA-ES" { + cmaes::Restarts::Never + } else { + cmaes::Restarts::Ipop + }; + let cmaes = Cmaes::builder(real) + .restarts(restarts) + .minimize() + .seed(seed) + .build()?; + Engine::new(cmaes, problem).stop_when(stop).run() + } + "DE" => { + let de = De::builder(real).minimize().seed(seed).build()?; + Engine::new(de, problem).stop_when(stop).run() + } + "PSO" => { + let pso = Pso::builder(real) + .population_size(40) + .minimize() + .seed(seed) + .build()?; + Engine::new(pso, problem).stop_when(stop).run() + } + _ => { + let ga = Ga::builder(real) + .population_size(100) + .select(Tournament::new(3)?) + .crossover(SimulatedBinaryCrossover::new(15.0)?) + .mutate(PolynomialMutation::per_gene(1.0 / DIMENSIONS as f64, 20.0)?) + .minimize() + .seed(seed) + .build()?; + Engine::new(ga, problem).stop_when(stop).run() + } + } +} + +// the median of `values`, None without any +fn median(mut values: Vec) -> Option { + values.sort_by(f64::total_cmp); + let middle = values.len() / 2; + match values.len() { + 0 => None, + n if n % 2 == 1 => Some(values[middle]), + _ => Some((values[middle - 1] + values[middle]) / 2.0), + } +} diff --git a/examples/happy_cat/output.txt b/examples/happy_cat/output.txt new file mode 100644 index 00000000..7f0af747 --- /dev/null +++ b/examples/happy_cat/output.txt @@ -0,0 +1,8 @@ +HappyCat in 10 dimensions, 10 seeds, 100000 evaluations at most per run +algorithm at min evaluations median error +CMA-ES 0/10 - 9.4e-2 +CMA-ES with IPOP 0/10 - 5.4e-3 +DE 0/10 - 1.0e-1 +PSO 0/10 - 1.4e-1 +GA 0/10 - 7.8e-2 +evaluations: the median of the runs that reach the minimum diff --git a/examples/happy_cat/trace.json b/examples/happy_cat/trace.json new file mode 100644 index 00000000..7c27abdc --- /dev/null +++ b/examples/happy_cat/trace.json @@ -0,0 +1,102 @@ +{"example":"happy_cat","format":1,"log_y":true,"objective":"minimize","optimum":0.0,"plot":"contour","problem":{"bounds":[[-5.0,5.0],[-5.0,5.0]],"function":"happy_cat","minima":[[-1.0,-1.0]]},"x_label":"evaluations","y_label":"error","frames":[ +{"best":3.86286,"evaluations":6,"generation":0,"median":4.88172,"state":{"best":[1.09727,-3.0536],"population":[[-4.02856,-1.2232],[1.09727,-3.0536],[-2.70235,3.76881],[-1.07094,-4.64995],[-3.75609,-3.6306],[2.14496,-1.42894]]}}, +{"best":0.827934,"evaluations":42,"generation":6,"median":1.26391,"state":{"best":[-0.824785,-0.932495],"population":[[-0.499198,-1.46196],[-1.64215,-1.15879],[0.233641,-1.17716],[-0.824785,-0.932495],[-1.0115,-1.67237],[-0.273724,-3.0083]]}}, +{"best":0.654691,"evaluations":84,"generation":13,"median":0.997434,"state":{"best":[-0.972296,-1.11117],"population":[[-0.936446,-0.65749],[-1.1772,-1.42245],[-1.51161,-0.789871],[-0.654437,-1.01827],[-1.21015,-1.10312],[-1.00052,-1.45115]]}}, +{"best":0.64249,"evaluations":120,"generation":19,"median":1.01229,"state":{"best":[-1.22204,-0.618334],"population":[[-1.05868,-1.02873],[-0.777988,-1.07147],[-0.668084,-0.791531],[-1.1784,-0.257704],[-0.874499,-0.101826],[-0.241924,-1.00409]]}}, +{"best":0.205299,"evaluations":162,"generation":26,"median":0.523587,"state":{"best":[-0.975817,-1.02275],"population":[[-1.11308,-0.791684],[-0.956289,-0.92641],[-1.10661,-0.854705],[-1.28166,-0.66056],[-0.975817,-1.02275],[-1.18291,-0.799414]]}}, +{"best":0.205299,"evaluations":198,"generation":32,"median":0.398627,"state":{"best":[-0.975817,-1.02275],"population":[[-1.16543,-0.814317],[-1.14512,-0.812414],[-1.1693,-0.791672],[-1.05913,-0.950452],[-1.06455,-0.905026],[-1.15018,-0.821127]]}}, +{"best":0.132289,"evaluations":240,"generation":39,"median":0.281339,"state":{"best":[-1.17653,-0.78461],"population":[[-1.16495,-0.80358],[-1.19976,-0.752806],[-1.16645,-0.79741],[-1.18078,-0.771078],[-1.18004,-0.778479],[-1.17225,-0.795191]]}}, +{"best":0.123698,"evaluations":276,"generation":45,"median":0.179915,"state":{"best":[-1.15496,-0.816042],"population":[[-1.15454,-0.815556],[-1.15491,-0.816957],[-1.15838,-0.81022],[-1.17817,-0.782488],[-1.15266,-0.819595],[-1.16378,-0.803281]]}}, +{"best":0.123698,"evaluations":312,"generation":51,"median":0.162837,"state":{"best":[-1.15496,-0.816042],"population":[[-1.14754,-0.826656],[-1.15355,-0.817327],[-1.15456,-0.815418],[-1.15012,-0.82309],[-1.15349,-0.818747],[-1.14086,-0.835624]]}}, +{"best":0.0967516,"evaluations":354,"generation":58,"median":0.129005,"state":{"best":[-1.15539,-0.81549],"population":[[-1.15607,-0.814451],[-1.15027,-0.822835],[-1.15051,-0.82245],[-1.15558,-0.815387],[-1.15539,-0.81549],[-1.15007,-0.822779]]}}, +{"best":0.0737064,"evaluations":390,"generation":64,"median":0.136458,"state":{"best":[-1.1535,-0.818205],"population":[[-1.16222,-0.805894],[-1.15643,-0.813842],[-1.15865,-0.810842],[-1.16554,-0.801173],[-1.15834,-0.811447],[-1.15661,-0.813826]]}}, +{"best":0.0440117,"evaluations":432,"generation":71,"median":0.0878596,"state":{"best":[-1.15623,-0.814323],"population":[[-1.15764,-0.81235],[-1.15766,-0.81233],[-1.1583,-0.811398],[-1.15787,-0.812008],[-1.15774,-0.812172],[-1.15787,-0.812023]]}}, +{"best":0.0440117,"evaluations":468,"generation":77,"median":0.0641992,"state":{"best":[-1.15623,-0.814323],"population":[[-1.15786,-0.812021],[-1.15774,-0.812184],[-1.15764,-0.812317],[-1.15752,-0.812492],[-1.15797,-0.811859],[-1.15775,-0.812161]]}}, +{"best":0.0342418,"evaluations":510,"generation":84,"median":0.047935,"state":{"best":[-1.15781,-0.812081],"population":[[-1.15785,-0.81202],[-1.15788,-0.811974],[-1.15792,-0.811921],[-1.15788,-0.811982],[-1.15789,-0.811975],[-1.15794,-0.81189]]}}, +{"best":0.02512,"evaluations":546,"generation":90,"median":0.0354734,"state":{"best":[-1.158,-0.811817],"population":[[-1.15807,-0.811717],[-1.15803,-0.811767],[-1.15803,-0.811768],[-1.15794,-0.811894],[-1.15802,-0.811776],[-1.15793,-0.811907]]}}, +{"best":0.02512,"evaluations":588,"generation":97,"median":0.0367278,"state":{"best":[-1.158,-0.811817],"population":[[-1.15792,-0.811922],[-1.15794,-0.811891],[-1.15795,-0.811886],[-1.15795,-0.811878],[-1.15795,-0.811879],[-1.15794,-0.811903]]}}, +{"best":0.0205877,"evaluations":624,"generation":103,"median":0.0369324,"state":{"best":[-1.15788,-0.811981],"population":[[-1.15786,-0.812015],[-1.15784,-0.812034],[-1.15784,-0.812038],[-1.1579,-0.811956],[-1.15783,-0.812046],[-1.15787,-0.811999]]}}, +{"best":0.0205877,"evaluations":660,"generation":109,"median":0.0270423,"state":{"best":[-1.15788,-0.811981],"population":[[-1.15789,-0.811961],[-1.15789,-0.811969],[-1.15794,-0.811893],[-1.1579,-0.811952],[-1.15791,-0.811941],[-1.15792,-0.811919]]}}, +{"best":0.019632,"evaluations":702,"generation":116,"median":0.025236,"state":{"best":[-1.1579,-0.811949],"population":[[-1.15791,-0.811939],[-1.1579,-0.811951],[-1.15792,-0.811929],[-1.1579,-0.811953],[-1.1579,-0.811946],[-1.15792,-0.811927]]}}, +{"best":0.019632,"evaluations":738,"generation":122,"median":0.024339,"state":{"best":[-1.1579,-0.811949],"population":[[-1.1579,-0.811956],[-1.15789,-0.811963],[-1.1579,-0.811949],[-1.1579,-0.811959],[-1.15788,-0.81198],[-1.15789,-0.811971]]}}, +{"best":0.0189572,"evaluations":780,"generation":129,"median":0.0200374,"state":{"best":[-1.1579,-0.811947],"population":[[-1.1579,-0.811956],[-1.1579,-0.811955],[-1.1579,-0.811959],[-1.1579,-0.811955],[-1.1579,-0.811953],[-1.1579,-0.811952]]}}, +{"best":0.0169959,"evaluations":816,"generation":135,"median":0.0185323,"state":{"best":[-1.1579,-0.811953],"population":[[-1.1579,-0.811953],[-1.1579,-0.811954],[-1.1579,-0.811953],[-1.1579,-0.811954],[-1.1579,-0.811955],[-1.1579,-0.811953]]}}, +{"best":0.0162863,"evaluations":858,"generation":142,"median":0.0179872,"state":{"best":[-1.1579,-0.811952],"population":[[-1.1579,-0.811953],[-1.1579,-0.811953],[-1.1579,-0.811952],[-1.1579,-0.811953],[-1.1579,-0.811952],[-1.1579,-0.811952]]}}, +{"best":0.0156956,"evaluations":894,"generation":148,"median":0.0169296,"state":{"best":[-1.1579,-0.811952],"population":[[-1.1579,-0.811953],[-1.1579,-0.811952],[-1.1579,-0.811953],[-1.1579,-0.811952],[-1.1579,-0.811952],[-1.1579,-0.811952]]}}, +{"best":0.0156956,"evaluations":930,"generation":154,"median":0.016774,"state":{"best":[-1.1579,-0.811952],"population":[[-1.1579,-0.811952],[-1.1579,-0.811952],[-1.1579,-0.811952],[-1.1579,-0.811952],[-1.1579,-0.811953],[-1.1579,-0.811952]]}}, +{"best":0.0156956,"evaluations":972,"generation":161,"median":0.0164634,"state":{"best":[-1.1579,-0.811952],"population":[[-1.1579,-0.811952],[-1.1579,-0.811952],[-1.1579,-0.811952],[-1.1579,-0.811952],[-1.1579,-0.811952],[-1.1579,-0.811952]]}}, +{"best":0.0155195,"evaluations":1008,"generation":167,"median":0.0160166,"state":{"best":[-1.1579,-0.811952],"population":[[-1.1579,-0.811952],[-1.1579,-0.811952],[-1.1579,-0.811952],[-1.1579,-0.811952],[-1.1579,-0.811952],[-1.1579,-0.811952]]}}, +{"best":0.0153727,"evaluations":1050,"generation":174,"median":0.0156927,"state":{"best":[-1.1579,-0.811952],"population":[[-1.1579,-0.811952],[-1.1579,-0.811952],[-1.1579,-0.811952],[-1.1579,-0.811952],[-1.1579,-0.811952],[-1.1579,-0.811952]]}}, +{"best":0.0153727,"evaluations":1086,"generation":180,"median":0.0156539,"state":{"best":[-1.1579,-0.811952],"population":[[-1.1579,-0.811952],[-1.1579,-0.811952],[-1.1579,-0.811952],[-1.1579,-0.811952],[-1.1579,-0.811952],[-1.1579,-0.811952]]}}, +{"best":0.0153493,"evaluations":1128,"generation":187,"median":0.0155416,"state":{"best":[-1.1579,-0.811952],"population":[[-1.1579,-0.811952],[-1.1579,-0.811952],[-1.1579,-0.811952],[-1.1579,-0.811952],[-1.1579,-0.811952],[-1.1579,-0.811952]]}}, +{"best":0.0152463,"evaluations":1164,"generation":193,"median":0.0153945,"state":{"best":[-1.1579,-0.811952],"population":[[-1.1579,-0.811952],[-1.1579,-0.811952],[-1.1579,-0.811952],[-1.1579,-0.811952],[-1.1579,-0.811952],[-1.1579,-0.811952]]}}, +{"best":0.0152463,"evaluations":1212,"generation":199,"median":7.22833,"state":{"best":[-1.1579,-0.811952],"population":[[-2.61273,3.33791],[3.72986,-2.40333],[3.5865,4.26529],[-2.92781,-2.06503],[-0.389522,-4.81231],[3.01824,-0.434356],[-0.297747,-2.52555],[-4.00551,-0.347776],[3.04405,-3.00523],[2.58519,3.25227],[2.74634,2.98433],[3.35775,-4.20554]]}}, +{"best":0.0152463,"evaluations":1296,"generation":206,"median":1.01147,"state":{"best":[-1.1579,-0.811952],"population":[[-0.920984,-1.23214],[-0.663634,-1.4724],[-0.555636,-0.856108],[-1.19132,0.364988],[-0.495807,-1.50919],[1.10585,-0.32103],[0.548263,-1.06449],[-1.12937,0.181587],[-1.23977,-0.947795],[-0.516428,-1.08934],[0.936027,-1.15347],[-0.86711,-1.22988]]}}, +{"best":0.0152463,"evaluations":1368,"generation":212,"median":0.661957,"state":{"best":[-1.1579,-0.811952],"population":[[-1.01091,-1.21063],[-0.995836,-0.968624],[-1.09762,-0.977064],[-0.983787,-0.949918],[-1.12084,-1.13962],[-1.02248,-0.749634],[-1.0912,-0.834318],[-1.01747,-1.08998],[-0.957256,-1.07019],[-0.911145,-1.00498],[-0.814304,-0.743413],[-1.06858,-0.800556]]}}, +{"best":0.0152463,"evaluations":1452,"generation":219,"median":0.358676,"state":{"best":[-1.1579,-0.811952],"population":[[-1.00917,-0.978457],[-0.962252,-1.03395],[-0.995082,-0.992903],[-0.972641,-1.04203],[-0.940016,-1.06053],[-1.02083,-0.994418],[-0.937042,-1.04552],[-0.970089,-1.03058],[-0.998127,-0.964178],[-0.9384,-1.06309],[-1.01679,-0.977741],[-0.980654,-1.01855]]}}, +{"best":0.0152463,"evaluations":1524,"generation":225,"median":0.266961,"state":{"best":[-1.1579,-0.811952],"population":[[-0.987266,-1.01],[-0.964386,-1.03518],[-0.986055,-1.01242],[-0.966566,-1.02942],[-0.962108,-1.03093],[-0.984397,-1.01638],[-0.981272,-1.01412],[-0.983167,-1.02161],[-0.995937,-1.00651],[-1.01123,-0.994052],[-0.993444,-1.0043],[-0.965036,-1.03558]]}}, +{"best":0.0152463,"evaluations":1608,"generation":232,"median":0.158617,"state":{"best":[-1.1579,-0.811952],"population":[[-0.98179,-1.01837],[-0.978594,-1.02155],[-0.984732,-1.01533],[-0.991432,-1.00851],[-0.979955,-1.01876],[-1.00445,-0.995853],[-0.998374,-1.0015],[-0.977267,-1.02189],[-0.984082,-1.01584],[-0.995662,-1.004],[-0.987522,-1.01209],[-1.00083,-0.999795]]}}, +{"best":0.0152463,"evaluations":1680,"generation":238,"median":0.121518,"state":{"best":[-1.1579,-0.811952],"population":[[-0.982292,-1.01721],[-1.00746,-0.992506],[-0.995601,-1.00451],[-0.997053,-1.00304],[-0.990682,-1.00928],[-0.994638,-1.00534],[-1.00341,-0.99636],[-0.987997,-1.01201],[-0.979175,-1.02048],[-0.992488,-1.00757],[-0.981012,-1.01885],[-0.993179,-1.00686]]}}, +{"best":0.0152463,"evaluations":1764,"generation":245,"median":0.063938,"state":{"best":[-1.1579,-0.811952],"population":[[-0.998337,-1.00167],[-0.996504,-1.00348],[-1.00143,-0.998587],[-0.995438,-1.00453],[-0.998779,-1.00121],[-0.997368,-1.00263],[-1.00052,-0.999463],[-0.99495,-1.00497],[-0.996237,-1.00374],[-0.99907,-1.00092],[-0.997765,-1.0022],[-0.999411,-1.00059]]}}, +{"best":0.0152463,"evaluations":1836,"generation":251,"median":0.0505785,"state":{"best":[-1.1579,-0.811952],"population":[[-0.997163,-1.00283],[-0.998895,-1.0011],[-0.997832,-1.00217],[-0.998971,-1.00103],[-0.996153,-1.00383],[-0.997704,-1.00228],[-0.997377,-1.00261],[-0.996966,-1.00303],[-0.997411,-1.00258],[-0.998435,-1.00157],[-0.998132,-1.00187],[-0.999598,-1.00041]]}}, +{"best":0.0152463,"evaluations":1908,"generation":257,"median":0.0383907,"state":{"best":[-1.1579,-0.811952],"population":[[-0.999211,-1.00079],[-0.99855,-1.00145],[-0.997574,-1.00242],[-0.998822,-1.00118],[-0.99943,-1.00057],[-0.999234,-1.00077],[-0.998412,-1.00159],[-0.997441,-1.00255],[-0.998807,-1.00119],[-0.997636,-1.00236],[-0.999122,-1.00088],[-0.997727,-1.00227]]}}, +{"best":0.00977377,"evaluations":1992,"generation":264,"median":0.0262835,"state":{"best":[-0.998907,-1.00109],"population":[[-0.998837,-1.00116],[-0.999123,-1.00088],[-0.999035,-1.00096],[-0.998867,-1.00113],[-0.999008,-1.00099],[-0.999633,-1.00037],[-0.999145,-1.00085],[-0.998837,-1.00116],[-0.999032,-1.00097],[-0.998956,-1.00104],[-0.999554,-1.00045],[-0.999204,-1.0008]]}}, +{"best":0.00622046,"evaluations":2064,"generation":270,"median":0.0161456,"state":{"best":[-0.999263,-1.00074],"population":[[-0.999163,-1.00084],[-0.999066,-1.00093],[-0.999152,-1.00085],[-0.999205,-1.00079],[-0.99909,-1.00091],[-0.999208,-1.00079],[-0.999289,-1.00071],[-0.999212,-1.00079],[-0.999205,-1.00079],[-0.999109,-1.00089],[-0.999145,-1.00085],[-0.999214,-1.00079]]}}, +{"best":0.00478276,"evaluations":2148,"generation":277,"median":0.00968844,"state":{"best":[-0.999112,-1.00089],"population":[[-0.999155,-1.00084],[-0.999153,-1.00085],[-0.999146,-1.00085],[-0.999138,-1.00086],[-0.999195,-1.0008],[-0.999117,-1.00088],[-0.999098,-1.0009],[-0.999131,-1.00087],[-0.999171,-1.00083],[-0.999159,-1.00084],[-0.999103,-1.0009],[-0.999107,-1.00089]]}}, +{"best":0.00265375,"evaluations":2220,"generation":283,"median":0.00684692,"state":{"best":[-0.999133,-1.00087],"population":[[-0.999123,-1.00088],[-0.99914,-1.00086],[-0.999168,-1.00083],[-0.999141,-1.00086],[-0.999165,-1.00083],[-0.999156,-1.00084],[-0.999163,-1.00084],[-0.999138,-1.00086],[-0.999164,-1.00084],[-0.999133,-1.00087],[-0.999141,-1.00086],[-0.999141,-1.00086]]}}, +{"best":0.000945657,"evaluations":2304,"generation":290,"median":0.00348152,"state":{"best":[-0.999143,-1.00086],"population":[[-0.999144,-1.00086],[-0.999145,-1.00085],[-0.999145,-1.00085],[-0.999137,-1.00086],[-0.999138,-1.00086],[-0.999145,-1.00085],[-0.999145,-1.00085],[-0.999142,-1.00086],[-0.999141,-1.00086],[-0.999141,-1.00086],[-0.999144,-1.00086],[-0.999142,-1.00086]]}}, +{"best":0.000945657,"evaluations":2376,"generation":296,"median":0.00219812,"state":{"best":[-0.999143,-1.00086],"population":[[-0.999136,-1.00086],[-0.999132,-1.00087],[-0.999138,-1.00086],[-0.999139,-1.00086],[-0.999138,-1.00086],[-0.999136,-1.00086],[-0.999139,-1.00086],[-0.999137,-1.00086],[-0.999138,-1.00086],[-0.999136,-1.00086],[-0.999139,-1.00086],[-0.999132,-1.00087]]}}, +{"best":0.000945657,"evaluations":2448,"generation":302,"median":0.00220507,"state":{"best":[-0.999143,-1.00086],"population":[[-0.999135,-1.00086],[-0.999135,-1.00086],[-0.999135,-1.00086],[-0.999134,-1.00086],[-0.999137,-1.00086],[-0.999136,-1.00086],[-0.999138,-1.00086],[-0.999138,-1.00086],[-0.999137,-1.00086],[-0.999141,-1.00086],[-0.999138,-1.00086],[-0.999132,-1.00087]]}}, +{"best":0.000685103,"evaluations":2532,"generation":309,"median":0.00128766,"state":{"best":[-0.999135,-1.00086],"population":[[-0.999135,-1.00086],[-0.999136,-1.00086],[-0.999135,-1.00086],[-0.999136,-1.00086],[-0.999135,-1.00086],[-0.999135,-1.00086],[-0.999135,-1.00086],[-0.999135,-1.00086],[-0.999134,-1.00086],[-0.999136,-1.00086],[-0.999136,-1.00086],[-0.999136,-1.00086]]}}, +{"best":0.000437212,"evaluations":2604,"generation":315,"median":0.000735938,"state":{"best":[-0.999135,-1.00086],"population":[[-0.999136,-1.00086],[-0.999135,-1.00086],[-0.999136,-1.00086],[-0.999136,-1.00086],[-0.999135,-1.00086],[-0.999135,-1.00086],[-0.999135,-1.00086],[-0.999135,-1.00086],[-0.999135,-1.00086],[-0.999135,-1.00086],[-0.999136,-1.00086],[-0.999136,-1.00086]]}}, +{"best":0.00027602,"evaluations":2688,"generation":322,"median":0.000467772,"state":{"best":[-0.999136,-1.00086],"population":[[-0.999136,-1.00086],[-0.999136,-1.00086],[-0.999135,-1.00086],[-0.999136,-1.00086],[-0.999136,-1.00086],[-0.999136,-1.00086],[-0.999136,-1.00086],[-0.999135,-1.00086],[-0.999135,-1.00086],[-0.999136,-1.00086],[-0.999136,-1.00086],[-0.999136,-1.00086]]}}, +{"best":0.000173007,"evaluations":2760,"generation":328,"median":0.000288158,"state":{"best":[-0.999136,-1.00086],"population":[[-0.999136,-1.00086],[-0.999136,-1.00086],[-0.999136,-1.00086],[-0.999136,-1.00086],[-0.999136,-1.00086],[-0.999136,-1.00086],[-0.999136,-1.00086],[-0.999136,-1.00086],[-0.999136,-1.00086],[-0.999136,-1.00086],[-0.999136,-1.00086],[-0.999136,-1.00086]]}}, +{"best":0.000173007,"evaluations":2928,"generation":335,"median":0.923919,"state":{"best":[-0.999136,-1.00086],"population":[[-0.72973,-0.876592],[-1.35749,-0.608589],[-0.565709,-1.30432],[-1.72156,-1.39957],[-1.12604,-0.901686],[-1.11228,-1.13199],[-0.87027,-0.573163],[-0.683928,-1.10943],[-1.34231,-0.519443],[-0.0422836,-0.122499],[-0.855124,-0.461286],[-1.48505,-1.43211],[-0.60047,-0.429863],[-1.00923,-1.21881],[-0.766975,-0.980744],[-1.28275,-1.14322],[-1.42139,-0.0701156],[-0.835671,-1.75883],[-1.58406,-0.775288],[-0.865815,-1.00656],[-1.24633,-0.840183],[-0.11285,-0.12919],[-0.862694,-0.78371],[-0.397964,0.169313]]}}, +{"best":0.000173007,"evaluations":3072,"generation":341,"median":0.592305,"state":{"best":[-0.999136,-1.00086],"population":[[-1.01911,-1.00394],[-0.853076,-1.12273],[-0.927647,-0.984227],[-0.914967,-1.07434],[-1.18746,-0.953171],[-0.871699,-1.36579],[-1.14697,-0.741974],[-1.01001,-0.979169],[-0.869527,-1.116],[-0.69788,-1.26645],[-1.35353,-0.632687],[-0.868367,-1.16702],[-0.961566,-1.1412],[-1.08947,-0.949896],[-0.969931,-1.13063],[-1.01296,-0.959112],[-1.03217,-1.00122],[-1.1876,-0.796037],[-0.963256,-0.833074],[-0.96969,-0.991673],[-1.23164,-0.797288],[-1.01722,-1.10748],[-0.848893,-1.26995],[-1.11597,-0.890503]]}}, +{"best":0.000173007,"evaluations":3216,"generation":347,"median":0.309858,"state":{"best":[-0.999136,-1.00086],"population":[[-1.00849,-0.98149],[-1.00645,-0.984161],[-0.972646,-1.02722],[-0.999416,-0.995848],[-0.929906,-1.06734],[-1.00022,-1.00475],[-0.946544,-1.05537],[-0.984615,-1.01389],[-0.964712,-1.02946],[-0.956569,-1.05016],[-1.0092,-0.996574],[-1.03621,-0.964288],[-1.04203,-0.962841],[-0.915688,-1.07603],[-1.0312,-0.968202],[-0.987378,-1.00378],[-0.987997,-1.01629],[-0.97927,-1.0135],[-1.02884,-0.974013],[-1.00391,-0.999936],[-1.03806,-0.962022],[-0.950202,-1.04862],[-0.942805,-1.05159],[-0.987308,-1.01978]]}}, +{"best":0.000173007,"evaluations":3384,"generation":354,"median":0.180882,"state":{"best":[-0.999136,-1.00086],"population":[[-0.978035,-1.02017],[-1.01533,-0.986284],[-0.978594,-1.02035],[-0.960706,-1.03811],[-0.982897,-1.01579],[-1.0201,-0.981512],[-0.953431,-1.04429],[-0.974725,-1.0239],[-0.933006,-1.06345],[-0.99754,-1.00252],[-0.957647,-1.04057],[-0.968068,-1.03019],[-0.977093,-1.02226],[-0.968912,-1.02931],[-0.966212,-1.03121],[-0.967567,-1.03155],[-0.95912,-1.03888],[-0.984099,-1.01535],[-0.921649,-1.07343],[-0.990194,-1.01049],[-0.999665,-1.0008],[-0.930652,-1.06521],[-0.959807,-1.03859],[-0.996363,-1.00396]]}}, +{"best":0.000173007,"evaluations":3528,"generation":360,"median":0.125756,"state":{"best":[-0.999136,-1.00086],"population":[[-0.974419,-1.02474],[-0.991573,-1.00889],[-0.980572,-1.01914],[-0.99186,-1.00846],[-0.979946,-1.01956],[-0.958305,-1.04034],[-0.974201,-1.02509],[-0.983625,-1.01607],[-0.984193,-1.01577],[-0.965223,-1.03349],[-0.96958,-1.02914],[-0.970456,-1.02881],[-0.993358,-1.00736],[-0.977754,-1.02177],[-0.957318,-1.04102],[-0.985934,-1.01418],[-0.961307,-1.03743],[-0.968595,-1.03055],[-0.954995,-1.04329],[-0.980369,-1.01932],[-0.966684,-1.03214],[-0.973519,-1.02551],[-0.959012,-1.03934],[-0.96702,-1.03186]]}}, +{"best":0.000173007,"evaluations":3696,"generation":367,"median":0.0870226,"state":{"best":[-0.999136,-1.00086],"population":[[-0.968414,-1.0306],[-0.954874,-1.04333],[-0.967139,-1.03179],[-0.957309,-1.04108],[-0.974355,-1.02501],[-0.967258,-1.03168],[-0.96822,-1.03081],[-0.976423,-1.02305],[-0.972388,-1.02689],[-0.953026,-1.04506],[-0.968404,-1.03062],[-0.967202,-1.0317],[-0.965767,-1.03311],[-0.972799,-1.02646],[-0.960701,-1.03785],[-0.956332,-1.04197],[-0.969555,-1.02954],[-0.966177,-1.03267],[-0.962566,-1.03613],[-0.966317,-1.03253],[-0.968835,-1.03016],[-0.960466,-1.03806],[-0.963215,-1.03552],[-0.967315,-1.03165]]}}, +{"best":0.000173007,"evaluations":3840,"generation":373,"median":0.0459457,"state":{"best":[-0.999136,-1.00086],"population":[[-0.966352,-1.03256],[-0.966338,-1.03256],[-0.968058,-1.03095],[-0.968044,-1.03097],[-0.970332,-1.02882],[-0.968704,-1.03034],[-0.968804,-1.03026],[-0.969931,-1.02919],[-0.968739,-1.03031],[-0.968638,-1.0304],[-0.968857,-1.0302],[-0.967996,-1.03101],[-0.968918,-1.03014],[-0.967272,-1.03169],[-0.969549,-1.02955],[-0.968781,-1.03028],[-0.970911,-1.02827],[-0.966295,-1.03261],[-0.966444,-1.03247],[-0.96722,-1.03174],[-0.968639,-1.03041],[-0.968714,-1.03033],[-0.969369,-1.02972],[-0.968702,-1.03034]]}}, +{"best":0.000173007,"evaluations":4008,"generation":380,"median":0.028233,"state":{"best":[-0.999136,-1.00086],"population":[[-0.968129,-1.03089],[-0.968503,-1.03053],[-0.967935,-1.03107],[-0.968594,-1.03045],[-0.968864,-1.0302],[-0.968448,-1.03059],[-0.968467,-1.03057],[-0.968393,-1.03064],[-0.968328,-1.0307],[-0.968976,-1.03009],[-0.968563,-1.03048],[-0.969219,-1.02986],[-0.968115,-1.0309],[-0.968415,-1.03062],[-0.968496,-1.03054],[-0.968806,-1.03025],[-0.967986,-1.03102],[-0.968484,-1.03055],[-0.968617,-1.03043],[-0.968813,-1.03024],[-0.968886,-1.03017],[-0.968417,-1.03062],[-0.968221,-1.0308],[-0.968394,-1.03064]]}}, +{"best":0.000173007,"evaluations":4152,"generation":386,"median":0.0202651,"state":{"best":[-0.999136,-1.00086],"population":[[-0.968199,-1.03082],[-0.968126,-1.03089],[-0.968443,-1.03059],[-0.968053,-1.03096],[-0.968404,-1.03063],[-0.968149,-1.03087],[-0.967979,-1.03103],[-0.96834,-1.03069],[-0.967909,-1.03109],[-0.968106,-1.03091],[-0.967944,-1.03106],[-0.968348,-1.03068],[-0.968794,-1.03026],[-0.968266,-1.03076],[-0.968931,-1.03013],[-0.968398,-1.03063],[-0.968225,-1.0308],[-0.968676,-1.03037],[-0.968565,-1.03048],[-0.968118,-1.0309],[-0.968529,-1.03051],[-0.96785,-1.03115],[-0.968287,-1.03074],[-0.968058,-1.03095]]}}, +{"best":0.000173007,"evaluations":4296,"generation":392,"median":0.01448,"state":{"best":[-0.999136,-1.00086],"population":[[-0.968548,-1.03049],[-0.968279,-1.03075],[-0.968264,-1.03076],[-0.968361,-1.03067],[-0.968366,-1.03066],[-0.968246,-1.03078],[-0.968407,-1.03063],[-0.968224,-1.0308],[-0.968205,-1.03081],[-0.96826,-1.03076],[-0.968064,-1.03095],[-0.968337,-1.03069],[-0.968418,-1.03061],[-0.968443,-1.03059],[-0.968259,-1.03076],[-0.968147,-1.03087],[-0.968066,-1.03095],[-0.968228,-1.03079],[-0.968414,-1.03062],[-0.968317,-1.03071],[-0.968148,-1.03087],[-0.968384,-1.03065],[-0.968178,-1.03084],[-0.968213,-1.03081]]}}, +{"best":0.000173007,"evaluations":4464,"generation":399,"median":0.00853245,"state":{"best":[-0.999136,-1.00086],"population":[[-0.968304,-1.03072],[-0.968287,-1.03074],[-0.968339,-1.03069],[-0.96829,-1.03073],[-0.968363,-1.03067],[-0.968306,-1.03072],[-0.968287,-1.03074],[-0.968269,-1.03075],[-0.968224,-1.0308],[-0.968302,-1.03072],[-0.968303,-1.03072],[-0.968313,-1.03071],[-0.968389,-1.03064],[-0.968333,-1.03069],[-0.968259,-1.03076],[-0.96828,-1.03074],[-0.968283,-1.03074],[-0.968315,-1.03071],[-0.968265,-1.03076],[-0.968362,-1.03067],[-0.968278,-1.03075],[-0.968195,-1.03082],[-0.968349,-1.03068],[-0.968304,-1.03072]]}}, +{"best":0.000173007,"evaluations":4608,"generation":405,"median":0.00643305,"state":{"best":[-0.999136,-1.00086],"population":[[-0.968278,-1.03075],[-0.968289,-1.03074],[-0.968304,-1.03072],[-0.96835,-1.03068],[-0.968312,-1.03071],[-0.968345,-1.03068],[-0.968322,-1.03071],[-0.968356,-1.03067],[-0.968313,-1.03071],[-0.96833,-1.0307],[-0.968312,-1.03071],[-0.968308,-1.03072],[-0.968329,-1.0307],[-0.96831,-1.03072],[-0.968321,-1.03071],[-0.968329,-1.0307],[-0.968266,-1.03076],[-0.968342,-1.03069],[-0.968313,-1.03071],[-0.968295,-1.03073],[-0.968338,-1.03069],[-0.968304,-1.03072],[-0.968292,-1.03073],[-0.968295,-1.03073]]}}, +{"best":0.000173007,"evaluations":4776,"generation":412,"median":0.00415754,"state":{"best":[-0.999136,-1.00086],"population":[[-0.96831,-1.03072],[-0.968317,-1.03071],[-0.968321,-1.03071],[-0.968329,-1.0307],[-0.968315,-1.03071],[-0.968321,-1.03071],[-0.968319,-1.03071],[-0.968316,-1.03071],[-0.968331,-1.0307],[-0.968324,-1.0307],[-0.968313,-1.03071],[-0.968324,-1.0307],[-0.968329,-1.0307],[-0.968318,-1.03071],[-0.968319,-1.03071],[-0.968324,-1.0307],[-0.968315,-1.03071],[-0.968313,-1.03071],[-0.96832,-1.03071],[-0.968314,-1.03071],[-0.968319,-1.03071],[-0.968315,-1.03071],[-0.968322,-1.03071],[-0.968339,-1.03069]]}}, +{"best":0.000173007,"evaluations":4920,"generation":418,"median":0.00291958,"state":{"best":[-0.999136,-1.00086],"population":[[-0.968318,-1.03071],[-0.968317,-1.03071],[-0.968315,-1.03071],[-0.968312,-1.03071],[-0.968321,-1.03071],[-0.968318,-1.03071],[-0.968319,-1.03071],[-0.96832,-1.03071],[-0.968322,-1.0307],[-0.968316,-1.03071],[-0.968319,-1.03071],[-0.968319,-1.03071],[-0.968316,-1.03071],[-0.968318,-1.03071],[-0.968315,-1.03071],[-0.96832,-1.03071],[-0.968315,-1.03071],[-0.968317,-1.03071],[-0.968315,-1.03071],[-0.968318,-1.03071],[-0.968322,-1.03071],[-0.968316,-1.03071],[-0.968315,-1.03071],[-0.968316,-1.03071]]}}, +{"best":0.000173007,"evaluations":5088,"generation":425,"median":0.0016141,"state":{"best":[-0.999136,-1.00086],"population":[[-0.968317,-1.03071],[-0.968318,-1.03071],[-0.968316,-1.03071],[-0.968316,-1.03071],[-0.968317,-1.03071],[-0.968316,-1.03071],[-0.968318,-1.03071],[-0.968317,-1.03071],[-0.968316,-1.03071],[-0.968316,-1.03071],[-0.968317,-1.03071],[-0.968316,-1.03071],[-0.968316,-1.03071],[-0.968316,-1.03071],[-0.968318,-1.03071],[-0.968316,-1.03071],[-0.968316,-1.03071],[-0.968318,-1.03071],[-0.968317,-1.03071],[-0.968318,-1.03071],[-0.968318,-1.03071],[-0.968317,-1.03071],[-0.968318,-1.03071],[-0.968318,-1.03071]]}}, +{"best":0.000173007,"evaluations":5232,"generation":431,"median":0.0013168,"state":{"best":[-0.999136,-1.00086],"population":[[-0.968317,-1.03071],[-0.968317,-1.03071],[-0.968317,-1.03071],[-0.968316,-1.03071],[-0.968316,-1.03071],[-0.968316,-1.03071],[-0.968316,-1.03071],[-0.968316,-1.03071],[-0.968316,-1.03071],[-0.968317,-1.03071],[-0.968316,-1.03071],[-0.968317,-1.03071],[-0.968317,-1.03071],[-0.968317,-1.03071],[-0.968317,-1.03071],[-0.968316,-1.03071],[-0.968317,-1.03071],[-0.968316,-1.03071],[-0.968316,-1.03071],[-0.968316,-1.03071],[-0.968317,-1.03071],[-0.968317,-1.03071],[-0.968316,-1.03071],[-0.968316,-1.03071]]}}, +{"best":0.000173007,"evaluations":5400,"generation":438,"median":0.000984664,"state":{"best":[-0.999136,-1.00086],"population":[[-0.968317,-1.03071],[-0.968317,-1.03071],[-0.968316,-1.03071],[-0.968316,-1.03071],[-0.968316,-1.03071],[-0.968317,-1.03071],[-0.968317,-1.03071],[-0.968316,-1.03071],[-0.968317,-1.03071],[-0.968317,-1.03071],[-0.968317,-1.03071],[-0.968317,-1.03071],[-0.968316,-1.03071],[-0.968316,-1.03071],[-0.968317,-1.03071],[-0.968317,-1.03071],[-0.968316,-1.03071],[-0.968317,-1.03071],[-0.968316,-1.03071],[-0.968317,-1.03071],[-0.968316,-1.03071],[-0.968317,-1.03071],[-0.968316,-1.03071],[-0.968316,-1.03071]]}}, +{"best":0.000173007,"evaluations":5664,"generation":444,"median":1.27047,"state":{"best":[-0.999136,-1.00086],"population":[[-1.16491,-0.760341],[-0.126973,-1.42244],[-0.93683,-1.56427],[-1.50562,-0.218351],[-0.647444,-1.09646],[-1.28908,-2.04612],[-0.299217,-0.624404],[0.133851,-1.65936],[0.118198,-0.796625],[-0.406816,-0.499928],[-0.131729,0.396404],[-1.63999,0.169007],[-1.05619,-2.87723],[-2.2047,-1.37962],[-1.46905,0.478028],[-0.716291,-0.193895],[-0.935278,-1.37162],[-1.42076,-1.39671],[-1.63798,-0.609167],[-0.302033,-1.10932],[-1.71039,-0.771948],[1.29756,-1.25727],[-2.06881,-1.44968],[-1.07145,-1.13027],[-2.58652,-0.994329],[0.0973199,0.41952],[-1.48373,-1.31123],[-0.781907,-2.01621],[-1.77658,1.07853],[-1.59532,-1.10208],[-1.0802,0.0477215],[0.377958,0.503639],[-1.06414,-1.54035],[-0.361912,-0.332697],[-0.349035,0.523794],[0.230768,-0.386146],[-1.12734,-0.683024],[-0.47654,-0.757901],[-1.26607,-0.65908],[-0.278875,0.474246],[-1.43969,-0.0758715],[0.672428,-1.05453],[-1.14969,-0.631877],[-0.862449,-0.330219],[-1.13355,-1.86454],[-0.625133,-1.03231],[0.500867,-0.161584],[-1.07964,-0.629614]]}}, +{"best":0.000173007,"evaluations":5952,"generation":450,"median":0.542016,"state":{"best":[-0.999136,-1.00086],"population":[[-1.13175,-0.818507],[-1.08868,-0.867635],[-0.95185,-0.964993],[-1.1446,-0.850928],[-0.899659,-1.02439],[-0.89355,-1.09531],[-0.914301,-1.05947],[-1.06887,-0.888889],[-0.914161,-1.11925],[-1.03444,-0.978556],[-0.954825,-1.0122],[-0.975096,-0.975432],[-1.09233,-0.921875],[-0.85957,-1.14879],[-0.935735,-1.07667],[-0.828568,-1.1334],[-0.960268,-0.967626],[-0.987905,-0.918901],[-1.1318,-0.876573],[-0.805372,-1.0598],[-1.03243,-1.07619],[-0.84573,-1.11271],[-1.03219,-0.938879],[-1.02256,-0.917775],[-0.946347,-1.01325],[-1.18485,-0.720724],[-0.716172,-1.16384],[-1.02103,-0.984845],[-0.946074,-1.12758],[-1.15991,-0.864024],[-1.17627,-0.808537],[-1.14109,-0.900098],[-1.08201,-0.806483],[-1.12051,-0.730666],[-0.959829,-0.934776],[-1.02551,-0.895177],[-1.24137,-0.783135],[-0.883423,-1.0635],[-0.998775,-1.03551],[-1.00344,-0.917942],[-1.09981,-1.02484],[-1.22569,-0.67181],[-0.986248,-1.01327],[-1.23083,-0.856417],[-1.00608,-0.941485],[-1.00339,-0.966733],[-1.21375,-0.746381],[-0.853725,-1.16001]]}}, +{"best":0.000173007,"evaluations":6288,"generation":457,"median":0.251747,"state":{"best":[-0.999136,-1.00086],"population":[[-0.963935,-1.03235],[-0.960126,-1.03785],[-0.95655,-1.04351],[-0.909561,-1.09082],[-0.979817,-1.01991],[-0.992174,-1.01086],[-1.00919,-0.989942],[-0.938355,-1.06123],[-0.972561,-1.0293],[-0.962572,-1.03877],[-0.937855,-1.05954],[-1.00717,-0.994369],[-0.983212,-1.01419],[-0.953253,-1.04713],[-0.994052,-1.00671],[-1.05418,-0.94758],[-1.0211,-0.979066],[-0.976615,-1.02243],[-0.971733,-1.02829],[-0.972183,-1.02309],[-0.999874,-0.997612],[-1.00519,-0.994491],[-0.968433,-1.03453],[-0.976261,-1.02529],[-1.01498,-0.982995],[-0.985892,-1.01557],[-0.923896,-1.07173],[-0.99753,-0.997822],[-0.989202,-1.0096],[-0.98083,-1.0209],[-0.968143,-1.02954],[-1.02797,-0.970185],[-1.00572,-0.998246],[-0.942018,-1.05292],[-0.986739,-1.01303],[-0.977142,-1.02356],[-0.98797,-1.00944],[-0.959295,-1.044],[-0.963934,-1.03845],[-1.01556,-0.979998],[-0.994466,-1.004],[-0.993573,-1.00676],[-0.99805,-1.00153],[-0.948082,-1.0484],[-1.01242,-0.984295],[-0.987496,-1.0106],[-0.973869,-1.02207],[-0.992424,-1.00968]]}}, +{"best":0.000173007,"evaluations":6576,"generation":463,"median":0.113116,"state":{"best":[-0.999136,-1.00086],"population":[[-0.988752,-1.01138],[-0.990513,-1.0096],[-0.995097,-1.00487],[-0.985487,-1.01432],[-0.987086,-1.01284],[-0.982739,-1.01686],[-0.986157,-1.01368],[-0.977804,-1.0219],[-0.991716,-1.00818],[-0.980332,-1.01924],[-0.98898,-1.01086],[-0.975178,-1.02429],[-0.978619,-1.02085],[-0.98958,-1.0103],[-0.985005,-1.0149],[-0.973493,-1.02601],[-0.992657,-1.00735],[-0.973171,-1.02606],[-0.983429,-1.01625],[-0.982698,-1.01707],[-0.985522,-1.01401],[-0.98977,-1.01019],[-0.97467,-1.02477],[-0.987725,-1.0118],[-0.984596,-1.01511],[-0.987893,-1.01177],[-0.971563,-1.02764],[-0.994586,-1.00564],[-0.990991,-1.0089],[-0.972043,-1.02738],[-0.987613,-1.01223],[-0.982174,-1.0173],[-0.985883,-1.01384],[-0.988328,-1.01157],[-0.985823,-1.01396],[-0.992733,-1.00722],[-0.978716,-1.02096],[-1.005,-0.995163],[-0.97941,-1.02008],[-0.999554,-1.00067],[-0.98619,-1.01365],[-0.984894,-1.01504],[-0.974527,-1.02492],[-0.991589,-1.00826],[-0.992162,-1.00774],[-0.98812,-1.01159],[-0.993489,-1.00662],[-0.995804,-1.0043]]}}, +{"best":0.000173007,"evaluations":6912,"generation":470,"median":0.0674339,"state":{"best":[-0.999136,-1.00086],"population":[[-0.985787,-1.01402],[-0.983485,-1.01626],[-0.985394,-1.0144],[-0.984211,-1.01552],[-0.979467,-1.02014],[-0.985965,-1.01383],[-0.987819,-1.01206],[-0.980073,-1.01955],[-0.982087,-1.01761],[-0.984393,-1.01539],[-0.984386,-1.01537],[-0.986062,-1.01373],[-0.985753,-1.01407],[-0.982968,-1.01676],[-0.987302,-1.01254],[-0.978638,-1.02092],[-0.980771,-1.01887],[-0.983925,-1.01582],[-0.982897,-1.0168],[-0.979417,-1.02017],[-0.987895,-1.01198],[-0.98122,-1.01841],[-0.981673,-1.018],[-0.985918,-1.01388],[-0.988617,-1.0113],[-0.98385,-1.01589],[-0.983111,-1.0166],[-0.983896,-1.01585],[-0.98899,-1.01087],[-0.986312,-1.0135],[-0.984279,-1.01547],[-0.982964,-1.01673],[-0.985362,-1.01441],[-0.985716,-1.01407],[-0.985662,-1.01414],[-0.985445,-1.01434],[-0.986648,-1.01317],[-0.985648,-1.01414],[-0.983595,-1.01614],[-0.98817,-1.0117],[-0.987498,-1.01236],[-0.982769,-1.01692],[-0.981955,-1.01773],[-0.985164,-1.01461],[-0.98536,-1.01441],[-0.984128,-1.01562],[-0.977314,-1.02221],[-0.984549,-1.01523]]}}, +{"best":0.000173007,"evaluations":7200,"generation":476,"median":0.0480081,"state":{"best":[-0.999136,-1.00086],"population":[[-0.983819,-1.01592],[-0.984508,-1.01526],[-0.986046,-1.01376],[-0.985074,-1.01471],[-0.981226,-1.01843],[-0.984419,-1.01534],[-0.981775,-1.0179],[-0.984447,-1.01531],[-0.983099,-1.01662],[-0.983561,-1.01617],[-0.986857,-1.01298],[-0.983769,-1.01597],[-0.984516,-1.01525],[-0.983285,-1.01643],[-0.982728,-1.01698],[-0.98491,-1.01487],[-0.98606,-1.01375],[-0.983721,-1.01602],[-0.98154,-1.01813],[-0.984519,-1.01524],[-0.978618,-1.02095],[-0.981714,-1.01796],[-0.985057,-1.01473],[-0.981992,-1.01769],[-0.982794,-1.01691],[-0.986127,-1.01369],[-0.983492,-1.01624],[-0.984709,-1.01506],[-0.983103,-1.01661],[-0.98182,-1.01786],[-0.982156,-1.01753],[-0.985173,-1.01462],[-0.983301,-1.01642],[-0.982706,-1.017],[-0.98593,-1.01388],[-0.984839,-1.01494],[-0.983198,-1.01652],[-0.984267,-1.01549],[-0.985349,-1.01444],[-0.984214,-1.01554],[-0.982344,-1.01735],[-0.984184,-1.01556],[-0.982482,-1.01721],[-0.985407,-1.01439],[-0.98492,-1.01486],[-0.984404,-1.01536],[-0.984651,-1.01512],[-0.982635,-1.01707]]}}, +{"best":0.000173007,"evaluations":7536,"generation":483,"median":0.0239159,"state":{"best":[-0.999136,-1.00086],"population":[[-0.983206,-1.01652],[-0.983588,-1.01615],[-0.983348,-1.01638],[-0.984214,-1.01554],[-0.984125,-1.01563],[-0.983326,-1.0164],[-0.983859,-1.01588],[-0.983443,-1.01629],[-0.983473,-1.01626],[-0.983326,-1.0164],[-0.983696,-1.01604],[-0.983316,-1.01641],[-0.983947,-1.0158],[-0.983462,-1.01627],[-0.983103,-1.01662],[-0.982969,-1.01675],[-0.983565,-1.01617],[-0.983597,-1.01614],[-0.984463,-1.0153],[-0.983603,-1.01613],[-0.983944,-1.0158],[-0.983718,-1.01602],[-0.983641,-1.0161],[-0.983664,-1.01607],[-0.983081,-1.01664],[-0.983751,-1.01599],[-0.983621,-1.01612],[-0.983469,-1.01626],[-0.983246,-1.01648],[-0.983981,-1.01577],[-0.983366,-1.01636],[-0.983467,-1.01626],[-0.983929,-1.01582],[-0.983311,-1.01641],[-0.98343,-1.0163],[-0.983598,-1.01614],[-0.983493,-1.01624],[-0.983613,-1.01612],[-0.983647,-1.01609],[-0.98343,-1.0163],[-0.983386,-1.01634],[-0.983342,-1.01639],[-0.983667,-1.01607],[-0.983823,-1.01592],[-0.983961,-1.01579],[-0.983547,-1.01619],[-0.983313,-1.01641],[-0.983697,-1.01604]]}}, +{"best":0.000173007,"evaluations":7824,"generation":489,"median":0.0128226,"state":{"best":[-0.999136,-1.00086],"population":[[-0.983709,-1.01603],[-0.983819,-1.01592],[-0.983676,-1.01606],[-0.983699,-1.01604],[-0.983676,-1.01606],[-0.983823,-1.01592],[-0.983624,-1.01611],[-0.983601,-1.01613],[-0.983789,-1.01595],[-0.983618,-1.01612],[-0.983789,-1.01595],[-0.983842,-1.0159],[-0.983682,-1.01606],[-0.983671,-1.01607],[-0.983646,-1.01609],[-0.98369,-1.01605],[-0.983767,-1.01597],[-0.983681,-1.01606],[-0.983685,-1.01605],[-0.983892,-1.01585],[-0.983688,-1.01605],[-0.98367,-1.01607],[-0.983613,-1.01612],[-0.983634,-1.0161],[-0.983693,-1.01605],[-0.983654,-1.01608],[-0.983708,-1.01603],[-0.983836,-1.01591],[-0.98377,-1.01597],[-0.983709,-1.01603],[-0.983673,-1.01607],[-0.983611,-1.01612],[-0.983761,-1.01598],[-0.983647,-1.01609],[-0.983709,-1.01603],[-0.983818,-1.01592],[-0.983779,-1.01596],[-0.983774,-1.01597],[-0.983898,-1.01585],[-0.983582,-1.01615],[-0.983553,-1.01618],[-0.983661,-1.01608],[-0.983686,-1.01605],[-0.983757,-1.01598],[-0.983595,-1.01614],[-0.983676,-1.01606],[-0.98364,-1.0161],[-0.983713,-1.01603]]}}, +{"best":0.000173007,"evaluations":8112,"generation":495,"median":0.00826574,"state":{"best":[-0.999136,-1.00086],"population":[[-0.983735,-1.016],[-0.983749,-1.01599],[-0.983752,-1.01599],[-0.983693,-1.01604],[-0.983707,-1.01603],[-0.983713,-1.01603],[-0.983709,-1.01603],[-0.983737,-1.016],[-0.983767,-1.01597],[-0.983711,-1.01603],[-0.983739,-1.016],[-0.983726,-1.01601],[-0.983773,-1.01597],[-0.983662,-1.01607],[-0.983739,-1.016],[-0.983728,-1.01601],[-0.983676,-1.01606],[-0.983704,-1.01603],[-0.983763,-1.01598],[-0.983727,-1.01601],[-0.983697,-1.01604],[-0.983724,-1.01602],[-0.98374,-1.016],[-0.983705,-1.01603],[-0.983669,-1.01607],[-0.983696,-1.01604],[-0.983758,-1.01598],[-0.983745,-1.016],[-0.983742,-1.016],[-0.983783,-1.01596],[-0.983707,-1.01603],[-0.983723,-1.01602],[-0.983759,-1.01598],[-0.983709,-1.01603],[-0.983685,-1.01605],[-0.983719,-1.01602],[-0.983715,-1.01602],[-0.983728,-1.01601],[-0.983745,-1.01599],[-0.983756,-1.01598],[-0.983621,-1.01612],[-0.983656,-1.01608],[-0.98374,-1.016],[-0.983712,-1.01603],[-0.983681,-1.01606],[-0.983678,-1.01606],[-0.983702,-1.01604],[-0.983748,-1.01599]]}}, +{"best":0.000173007,"evaluations":8448,"generation":502,"median":0.00477214,"state":{"best":[-0.999136,-1.00086],"population":[[-0.983729,-1.01601],[-0.983727,-1.01601],[-0.983722,-1.01602],[-0.983702,-1.01604],[-0.983747,-1.01599],[-0.983703,-1.01604],[-0.98371,-1.01603],[-0.983719,-1.01602],[-0.983708,-1.01603],[-0.983715,-1.01602],[-0.983731,-1.01601],[-0.983698,-1.01604],[-0.983731,-1.01601],[-0.983719,-1.01602],[-0.983706,-1.01603],[-0.983707,-1.01603],[-0.983704,-1.01603],[-0.983676,-1.01606],[-0.983715,-1.01602],[-0.983692,-1.01605],[-0.983717,-1.01602],[-0.983731,-1.01601],[-0.983714,-1.01603],[-0.983739,-1.016],[-0.983719,-1.01602],[-0.983738,-1.016],[-0.983717,-1.01602],[-0.983733,-1.01601],[-0.983705,-1.01603],[-0.983703,-1.01604],[-0.983718,-1.01602],[-0.983695,-1.01604],[-0.983722,-1.01602],[-0.983711,-1.01603],[-0.983702,-1.01604],[-0.983683,-1.01605],[-0.983723,-1.01602],[-0.983696,-1.01604],[-0.983722,-1.01602],[-0.983722,-1.01602],[-0.983729,-1.01601],[-0.983711,-1.01603],[-0.983733,-1.01601],[-0.983721,-1.01602],[-0.983736,-1.016],[-0.983728,-1.01601],[-0.983715,-1.01602],[-0.983711,-1.01603]]}}, +{"best":0.000173007,"evaluations":8736,"generation":508,"median":0.00400825,"state":{"best":[-0.999136,-1.00086],"population":[[-0.983718,-1.01602],[-0.983708,-1.01603],[-0.983727,-1.01601],[-0.983718,-1.01602],[-0.983714,-1.01603],[-0.983708,-1.01603],[-0.983726,-1.01601],[-0.983726,-1.01601],[-0.983712,-1.01603],[-0.983708,-1.01603],[-0.983733,-1.01601],[-0.983722,-1.01602],[-0.983712,-1.01603],[-0.983725,-1.01601],[-0.983724,-1.01602],[-0.983723,-1.01602],[-0.983725,-1.01601],[-0.983721,-1.01602],[-0.983737,-1.016],[-0.983716,-1.01602],[-0.9837,-1.01604],[-0.983737,-1.016],[-0.983722,-1.01602],[-0.983727,-1.01601],[-0.983711,-1.01603],[-0.983733,-1.01601],[-0.983709,-1.01603],[-0.983726,-1.01601],[-0.983748,-1.01599],[-0.983725,-1.01601],[-0.983699,-1.01604],[-0.983726,-1.01601],[-0.983713,-1.01603],[-0.983728,-1.01601],[-0.983718,-1.01602],[-0.983718,-1.01602],[-0.983716,-1.01602],[-0.983725,-1.01601],[-0.983708,-1.01603],[-0.983713,-1.01603],[-0.983711,-1.01603],[-0.983721,-1.01602],[-0.983719,-1.01602],[-0.98372,-1.01602],[-0.983717,-1.01602],[-0.983713,-1.01603],[-0.983709,-1.01603],[-0.983705,-1.01603]]}}, +{"best":0.000173007,"evaluations":9072,"generation":515,"median":0.00244577,"state":{"best":[-0.999136,-1.00086],"population":[[-0.983718,-1.01602],[-0.983718,-1.01602],[-0.983716,-1.01602],[-0.983716,-1.01602],[-0.983713,-1.01603],[-0.983714,-1.01603],[-0.983713,-1.01603],[-0.983713,-1.01603],[-0.983727,-1.01601],[-0.983721,-1.01602],[-0.983719,-1.01602],[-0.983717,-1.01602],[-0.983715,-1.01602],[-0.98372,-1.01602],[-0.983719,-1.01602],[-0.983719,-1.01602],[-0.983722,-1.01602],[-0.983719,-1.01602],[-0.983717,-1.01602],[-0.983719,-1.01602],[-0.983712,-1.01603],[-0.983718,-1.01602],[-0.983716,-1.01602],[-0.98372,-1.01602],[-0.983719,-1.01602],[-0.983718,-1.01602],[-0.983722,-1.01602],[-0.983715,-1.01602],[-0.983716,-1.01602],[-0.983711,-1.01603],[-0.983718,-1.01602],[-0.983717,-1.01602],[-0.983715,-1.01602],[-0.983718,-1.01602],[-0.983712,-1.01603],[-0.983715,-1.01602],[-0.983709,-1.01603],[-0.983718,-1.01602],[-0.98372,-1.01602],[-0.983718,-1.01602],[-0.983719,-1.01602],[-0.983716,-1.01602],[-0.983712,-1.01603],[-0.983719,-1.01602],[-0.983718,-1.01602],[-0.983717,-1.01602],[-0.983719,-1.01602],[-0.983715,-1.01602]]}}, +{"best":0.000173007,"evaluations":9360,"generation":521,"median":0.00154937,"state":{"best":[-0.999136,-1.00086],"population":[[-0.983719,-1.01602],[-0.983717,-1.01602],[-0.983719,-1.01602],[-0.983717,-1.01602],[-0.983718,-1.01602],[-0.98372,-1.01602],[-0.98372,-1.01602],[-0.983719,-1.01602],[-0.983717,-1.01602],[-0.983719,-1.01602],[-0.983721,-1.01602],[-0.98372,-1.01602],[-0.983719,-1.01602],[-0.983718,-1.01602],[-0.983721,-1.01602],[-0.983716,-1.01602],[-0.983719,-1.01602],[-0.983718,-1.01602],[-0.983719,-1.01602],[-0.983718,-1.01602],[-0.98372,-1.01602],[-0.983716,-1.01602],[-0.983716,-1.01602],[-0.983716,-1.01602],[-0.983718,-1.01602],[-0.983718,-1.01602],[-0.983718,-1.01602],[-0.983717,-1.01602],[-0.983718,-1.01602],[-0.983719,-1.01602],[-0.983719,-1.01602],[-0.983717,-1.01602],[-0.983719,-1.01602],[-0.983717,-1.01602],[-0.983717,-1.01602],[-0.98372,-1.01602],[-0.983721,-1.01602],[-0.983718,-1.01602],[-0.983718,-1.01602],[-0.983717,-1.01602],[-0.983718,-1.01602],[-0.983721,-1.01602],[-0.983716,-1.01602],[-0.98372,-1.01602],[-0.983719,-1.01602],[-0.983716,-1.01602],[-0.983719,-1.01602],[-0.983718,-1.01602]]}}, +{"best":0.000173007,"evaluations":9696,"generation":528,"median":0.000998025,"state":{"best":[-0.999136,-1.00086],"population":[[-0.983718,-1.01602],[-0.983718,-1.01602],[-0.983718,-1.01602],[-0.983718,-1.01602],[-0.983719,-1.01602],[-0.983719,-1.01602],[-0.983718,-1.01602],[-0.983718,-1.01602],[-0.983719,-1.01602],[-0.983718,-1.01602],[-0.983719,-1.01602],[-0.983718,-1.01602],[-0.983719,-1.01602],[-0.983719,-1.01602],[-0.983718,-1.01602],[-0.983718,-1.01602],[-0.983718,-1.01602],[-0.983719,-1.01602],[-0.983718,-1.01602],[-0.983718,-1.01602],[-0.983718,-1.01602],[-0.983719,-1.01602],[-0.983719,-1.01602],[-0.983719,-1.01602],[-0.983718,-1.01602],[-0.983718,-1.01602],[-0.983719,-1.01602],[-0.983718,-1.01602],[-0.983719,-1.01602],[-0.983719,-1.01602],[-0.983719,-1.01602],[-0.983718,-1.01602],[-0.983717,-1.01602],[-0.983719,-1.01602],[-0.983718,-1.01602],[-0.983719,-1.01602],[-0.983717,-1.01602],[-0.983719,-1.01602],[-0.983718,-1.01602],[-0.983719,-1.01602],[-0.983719,-1.01602],[-0.983718,-1.01602],[-0.983719,-1.01602],[-0.983718,-1.01602],[-0.983719,-1.01602],[-0.983719,-1.01602],[-0.983719,-1.01602],[-0.983718,-1.01602]]}}, +{"best":0.000173007,"evaluations":9984,"generation":534,"median":0.000715284,"state":{"best":[-0.999136,-1.00086],"population":[[-0.983719,-1.01602],[-0.983719,-1.01602],[-0.983718,-1.01602],[-0.983719,-1.01602],[-0.983718,-1.01602],[-0.983718,-1.01602],[-0.983719,-1.01602],[-0.983719,-1.01602],[-0.983719,-1.01602],[-0.983719,-1.01602],[-0.983718,-1.01602],[-0.983719,-1.01602],[-0.983718,-1.01602],[-0.983719,-1.01602],[-0.983719,-1.01602],[-0.983719,-1.01602],[-0.983718,-1.01602],[-0.983719,-1.01602],[-0.983718,-1.01602],[-0.983719,-1.01602],[-0.983719,-1.01602],[-0.983719,-1.01602],[-0.983719,-1.01602],[-0.983719,-1.01602],[-0.983719,-1.01602],[-0.983718,-1.01602],[-0.983719,-1.01602],[-0.983718,-1.01602],[-0.983719,-1.01602],[-0.983719,-1.01602],[-0.983719,-1.01602],[-0.983719,-1.01602],[-0.983719,-1.01602],[-0.983719,-1.01602],[-0.983719,-1.01602],[-0.983718,-1.01602],[-0.983719,-1.01602],[-0.983719,-1.01602],[-0.983719,-1.01602],[-0.983719,-1.01602],[-0.983718,-1.01602],[-0.983719,-1.01602],[-0.983719,-1.01602],[-0.983719,-1.01602],[-0.983719,-1.01602],[-0.983719,-1.01602],[-0.983719,-1.01602],[-0.983719,-1.01602]]}}, +{"best":0.000173007,"evaluations":10368,"generation":540,"median":3.40599,"state":{"best":[-0.999136,-1.00086],"population":[[-2.3742,-0.30854],[2.49392,-1.12484],[4.31833,0.220283],[-1.70389,-4.41977],[4.76595,2.86992],[1.58234,-0.177973],[2.11168,-1.52464],[-2.94414,-1.07882],[-2.39061,-1.05534],[-0.112577,-1.55065],[-2.42575,-3.53969],[1.08157,-1.76786],[-1.9276,-1.34996],[-0.435157,-1.00393],[-0.988568,-4.78486],[3.47542,1.07061],[4.21414,-1.27101],[-1.02589,-1.54004],[1.20004,-3.38785],[-2.49978,-3.88689],[-0.219607,-3.22174],[1.19095,-2.85966],[-1.09908,1.56724],[-1.85069,-0.945386],[3.95106,-3.22286],[-0.804374,1.79022],[-3.48074,-2.26681],[-2.09298,0.583868],[-2.70095,-2.05808],[-4.07995,-2.94082],[-3.8209,-0.885616],[-2.56044,-4.65466],[0.776388,-0.431482],[1.72054,-0.0491898],[1.72389,0.508928],[2.77278,-3.3158],[-3.77484,-0.270986],[2.42827,-2.24217],[-1.43959,-1.40823],[4.77192,-0.729445],[0.211213,-1.0439],[1.25647,-4.85202],[-3.12738,0.478097],[2.11459,-2.40082],[-0.88288,-0.665231],[3.25704,-3.35627],[0.0880999,-0.569875],[3.6867,-2.36985],[3.4687,2.10245],[-2.36123,-0.218343],[-2.13356,-2.72485],[1.16233,-0.148626],[-3.85206,-4.42036],[-3.06927,-0.62102],[-0.251881,0.165631],[-0.766837,-2.48781],[-1.52516,-1.3181],[0.625358,-0.541965],[1.24181,-2.92807],[-2.74277,-2.55941],[-2.32644,-3.10788],[-1.13313,0.322769],[-3.31022,-0.456516],[4.14044,-2.38595],[2.84021,-3.63437],[-4.16496,0.707028],[-2.01625,1.83675],[2.9699,-4.97608],[2.98455,-2.45442],[-1.63131,0.330583],[-1.7975,-4.94946],[-4.24917,-1.42056],[-2.95108,-0.131461],[2.74039,0.329558],[-2.89634,-0.853955],[2.64585,-1.25361],[1.53634,-2.9581],[-1.90854,-0.417436],[-3.64724,0.349684],[-1.2975,-1.57395],[0.160379,-2.61397],[-3.34748,-0.410427],[2.68625,-0.273299],[-0.198847,-3.29288],[4.63623,0.628529],[0.172288,-0.460159],[-0.832837,0.567137],[2.88332,-1.32619],[1.02741,-1.84789],[-4.87398,-1.28572],[-2.16321,-2.07971],[-0.65932,-0.217396],[-2.85245,-0.62174],[3.54196,-2.20909],[-1.26128,-1.32513],[4.83554,-2.46774]]}}, +{"best":0.000173007,"evaluations":11040,"generation":547,"median":0.559113,"state":{"best":[-0.999136,-1.00086],"population":[[-1.09089,-0.893538],[-0.990652,-0.887585],[-0.998114,-0.942876],[-1.12045,-0.867559],[-0.854413,-1.09597],[-1.09142,-0.988384],[-1.13775,-0.903914],[-0.735534,-1.19915],[-0.77703,-1.18689],[-1.12777,-0.943848],[-0.993818,-0.991129],[-0.927147,-1.12703],[-0.732109,-1.25635],[-1.11291,-0.954907],[-0.927171,-1.01299],[-0.890724,-1.08862],[-0.998383,-1.0193],[-0.885255,-1.08571],[-0.863892,-1.27832],[-0.925243,-1.01376],[-1.20525,-0.815287],[-1.00757,-0.979504],[-0.833865,-1.10261],[-1.07185,-0.951105],[-0.799058,-1.15136],[-0.840434,-1.101],[-0.980658,-1.0214],[-1.21403,-0.886044],[-1.11896,-0.96928],[-0.970034,-0.956337],[-0.953851,-0.984979],[-1.13721,-0.933317],[-0.921842,-1.07529],[-0.969841,-1.01836],[-1.01685,-0.960594],[-1.04172,-1.06937],[-1.09244,-0.95049],[-1.03675,-1.00487],[-1.0608,-0.935271],[-0.869058,-1.04645],[-0.996772,-1.12203],[-1.00386,-0.980406],[-1.23395,-0.732793],[-1.11646,-0.882899],[-1.02445,-0.950332],[-1.32541,-0.650135],[-1.1111,-0.942123],[-1.00256,-0.971006],[-0.743163,-1.19313],[-1.01447,-0.922089],[-0.901319,-1.13747],[-0.764469,-1.12328],[-0.990259,-0.945746],[-0.939355,-1.09362],[-1.14799,-0.925785],[-0.599573,-1.35789],[-1.11584,-0.828035],[-1.07943,-0.843293],[-0.789262,-1.18016],[-0.953456,-1.01862],[-0.844414,-1.11974],[-1.10995,-0.953381],[-1.09015,-0.8004],[-0.967588,-0.904433],[-0.831649,-1.06047],[-1.00713,-0.935132],[-0.860468,-1.06494],[-1.25386,-0.80367],[-1.2416,-0.705936],[-1.28154,-0.741784],[-0.749771,-1.20657],[-0.935698,-0.956354],[-0.865067,-1.14383],[-0.877344,-1.02076],[-1.32189,-0.613972],[-0.989104,-0.936516],[-1.11014,-0.907845],[-1.32754,-0.585556],[-1.01313,-0.95773],[-0.887735,-1.10888],[-1.02872,-0.929125],[-1.06754,-0.901146],[-0.91923,-0.997427],[-1.08499,-0.854947],[-0.8778,-1.01716],[-1.0714,-0.884494],[-1.16159,-0.897621],[-0.969529,-1.00632],[-1.00693,-0.935319],[-1.00272,-1.00793],[-1.09482,-0.911103],[-0.680084,-1.26422],[-0.925195,-1.07893],[-1.21475,-0.726459],[-0.702841,-1.15976],[-1.07191,-0.885793]]}}, +{"best":0.000173007,"evaluations":11616,"generation":553,"median":0.337583,"state":{"best":[-0.999136,-1.00086],"population":[[-0.971334,-1.01362],[-0.91902,-1.09246],[-1.05112,-0.960646],[-1.08301,-0.913778],[-1.07108,-0.919539],[-0.961819,-1.04132],[-1.00089,-0.999398],[-1.03446,-0.952902],[-0.936717,-1.05899],[-0.92915,-1.07169],[-0.973745,-1.02888],[-0.995659,-0.997158],[-1.04233,-0.943153],[-1.03978,-0.950749],[-0.995736,-1.00288],[-0.993423,-0.991707],[-0.94595,-1.03991],[-0.975552,-1.01444],[-1.09248,-0.911089],[-0.98296,-1.01622],[-1.00309,-0.983707],[-0.955901,-1.03066],[-1.06416,-0.944739],[-0.982658,-1.01431],[-1.00479,-1.00722],[-0.99849,-0.996439],[-0.958316,-1.04655],[-1.04787,-0.963188],[-0.965462,-1.044],[-1.05452,-0.937582],[-1.08658,-0.908374],[-1.01021,-0.9825],[-0.981997,-1.01049],[-0.980265,-1.0251],[-1.02583,-0.973032],[-1.11102,-0.87381],[-1.06125,-0.92799],[-1.02675,-0.971571],[-0.960786,-1.03212],[-1.00636,-0.984913],[-1.02962,-0.971427],[-1.03215,-0.957896],[-1.13569,-0.861839],[-1.03414,-0.96529],[-1.02955,-0.972769],[-1.03062,-0.979045],[-0.998722,-0.994734],[-1.00824,-0.987916],[-1.04148,-0.958919],[-1.08478,-0.913875],[-0.945343,-1.0538],[-1.00475,-0.977128],[-0.938675,-1.05621],[-0.993053,-1.0122],[-0.966552,-1.02615],[-1.05212,-0.947429],[-1.02403,-0.980014],[-1.05404,-0.952758],[-1.09665,-0.884319],[-1.02118,-0.977474],[-1.02556,-0.959254],[-1.0554,-0.94734],[-0.967478,-1.01638],[-1.02873,-0.967904],[-0.986916,-1.016],[-0.98697,-1.01273],[-1.02091,-0.965808],[-0.962234,-1.02419],[-1.04105,-0.945023],[-1.03688,-0.965277],[-0.954474,-1.06224],[-1.02324,-0.956518],[-1.03127,-0.971271],[-1.0007,-0.999033],[-1.05992,-0.930618],[-0.990717,-1.00222],[-0.885424,-1.11011],[-1.11913,-0.860753],[-0.989279,-1.01211],[-0.956174,-1.04588],[-0.947417,-1.05932],[-0.990408,-1.00085],[-1.07079,-0.925792],[-1.1537,-0.846296],[-1.02651,-0.966443],[-1.02935,-0.957469],[-0.968881,-1.01958],[-1.06388,-0.945374],[-1.08168,-0.920321],[-0.980757,-1.01773],[-1.12545,-0.870274],[-1.01061,-0.981918],[-0.938144,-1.05915],[-1.01828,-0.981602],[-1.08337,-0.920839],[-1.00797,-1.00039]]}}, +{"best":0.000173007,"evaluations":12288,"generation":560,"median":0.157423,"state":{"best":[-0.999136,-1.00086],"population":[[-1.04136,-0.957205],[-1.03859,-0.960677],[-1.04067,-0.958021],[-1.02407,-0.975266],[-0.995804,-1.00433],[-1.02662,-0.972345],[-1.04268,-0.956123],[-1.04668,-0.95185],[-1.02388,-0.974915],[-1.01081,-0.988539],[-1.02138,-0.978162],[-1.01349,-0.986359],[-1.01625,-0.983212],[-1.0515,-0.947098],[-0.998018,-1.00188],[-1.03129,-0.967871],[-1.02329,-0.975799],[-1.00217,-0.997455],[-1.01619,-0.983513],[-1.02328,-0.975807],[-1.00748,-0.992416],[-1.0304,-0.968721],[-1.02341,-0.97569],[-1.00396,-0.99601],[-1.00218,-0.997428],[-1.0269,-0.971903],[-1.02784,-0.971076],[-1.02481,-0.974262],[-0.987269,-1.01288],[-1.00729,-0.992558],[-1.01659,-0.982572],[-1.03978,-0.958883],[-1.0029,-0.996729],[-1.00985,-0.990066],[-0.999858,-1.00018],[-1.02049,-0.978946],[-0.997617,-1.0024],[-1.02345,-0.976066],[-0.999019,-1.00128],[-1.02592,-0.973385],[-1.02282,-0.976509],[-1.04863,-0.94969],[-0.97978,-1.02068],[-1.00392,-0.995804],[-1.01132,-0.988207],[-1.00048,-0.999729],[-1.05685,-0.941421],[-1.02142,-0.97728],[-1.01651,-0.982381],[-0.983806,-1.01662],[-1.00727,-0.992437],[-1.00099,-0.998592],[-1.00856,-0.990794],[-1.01064,-0.988804],[-1.05807,-0.940324],[-1.03531,-0.963293],[-1.02365,-0.975476],[-1.00957,-0.989795],[-1.0152,-0.98428],[-1.03601,-0.963231],[-1.00305,-0.997168],[-1.01595,-0.983379],[-1.03653,-0.962502],[-1.03186,-0.967225],[-1.00493,-0.995444],[-1.03661,-0.96232],[-1.02827,-0.971018],[-1.01214,-0.987451],[-1.02695,-0.972012],[-1.03477,-0.96392],[-1.00926,-0.990052],[-1.00391,-0.996062],[-1.02639,-0.972702],[-1.02133,-0.977924],[-1.03197,-0.967291],[-1.01901,-0.980669],[-1.01003,-0.989725],[-1.03964,-0.958992],[-1.02133,-0.977968],[-1.03937,-0.959534],[-1.03886,-0.960001],[-1.02668,-0.972601],[-1.01767,-0.981477],[-0.989015,-1.0108],[-1.03803,-0.960892],[-1.01812,-0.98108],[-1.00477,-0.995072],[-1.02317,-0.97603],[-1.0074,-0.992537],[-1.02507,-0.973886],[-1.0341,-0.965187],[-1.01143,-0.988062],[-1.04639,-0.952219],[-1.04091,-0.95757],[-1.04188,-0.956747],[-1.02588,-0.973071]]}}, +{"best":0.000173007,"evaluations":12864,"generation":566,"median":0.100865,"state":{"best":[-0.999136,-1.00086],"population":[[-1.01611,-0.983491],[-1.01895,-0.98063],[-1.0023,-0.997721],[-1.01579,-0.983734],[-1.01872,-0.980899],[-1.02191,-0.977628],[-1.02136,-0.978172],[-1.01464,-0.985116],[-1.02875,-0.970653],[-1.02003,-0.979505],[-1.02601,-0.973347],[-1.02207,-0.977456],[-1.00662,-0.993356],[-1.00883,-0.990998],[-1.02327,-0.976187],[-1.02319,-0.976334],[-1.01854,-0.981103],[-1.0059,-0.994041],[-1.02629,-0.97313],[-1.02031,-0.979161],[-1.02245,-0.977078],[-1.02335,-0.976151],[-1.0087,-0.991095],[-1.02505,-0.974436],[-1.0216,-0.977935],[-1.01419,-0.985587],[-1.01603,-0.983689],[-1.01624,-0.983448],[-1.01788,-0.981849],[-1.01712,-0.98245],[-1.00914,-0.990772],[-1.01614,-0.983611],[-1.01939,-0.980191],[-1.00664,-0.993257],[-1.01754,-0.982153],[-1.02383,-0.975595],[-1.02628,-0.973163],[-1.00605,-0.993972],[-1.01716,-0.982594],[-1.02109,-0.978425],[-1.02206,-0.977527],[-1.02667,-0.97281],[-1.01172,-0.988083],[-1.01221,-0.987539],[-1.01667,-0.982988],[-1.00688,-0.993067],[-1.01878,-0.980742],[-1.02234,-0.977166],[-1.01752,-0.982068],[-1.01314,-0.986656],[-1.01524,-0.984499],[-1.01707,-0.982581],[-1.02512,-0.974251],[-1.01976,-0.979797],[-1.01097,-0.989036],[-1.00318,-0.996998],[-1.01651,-0.983056],[-1.00993,-0.989967],[-1.02094,-0.978593],[-1.02482,-0.974659],[-1.01112,-0.988737],[-1.01888,-0.980629],[-1.01701,-0.982656],[-1.01922,-0.980346],[-1.02235,-0.977235],[-1.01439,-0.985344],[-1.024,-0.975469],[-1.01994,-0.979719],[-1.01577,-0.983869],[-1.00497,-0.995211],[-1.01511,-0.984654],[-1.01471,-0.985001],[-1.02733,-0.971914],[-1.02286,-0.976713],[-1.01506,-0.984663],[-1.03167,-0.967627],[-1.00434,-0.995635],[-1.00939,-0.990472],[-1.01032,-0.989491],[-1.02382,-0.97562],[-1.02905,-0.97019],[-1.01042,-0.989433],[-1.02073,-0.978787],[-1.01325,-0.986477],[-1.0154,-0.984311],[-1.00536,-0.994683],[-1.01155,-0.988224],[-1.01104,-0.988872],[-1.00875,-0.991147],[-1.0146,-0.985198],[-1.01708,-0.982469],[-1.01926,-0.98038],[-1.02056,-0.978967],[-1.02095,-0.978631],[-1.01639,-0.983328],[-1.02741,-0.971938]]}}, +{"best":0.000173007,"evaluations":13536,"generation":573,"median":0.064013,"state":{"best":[-0.999136,-1.00086],"population":[[-1.01546,-0.984299],[-1.0153,-0.98447],[-1.01275,-0.987075],[-1.01615,-0.983585],[-1.0207,-0.978883],[-1.01125,-0.988615],[-1.01041,-0.989483],[-1.01576,-0.983974],[-1.01562,-0.984121],[-1.01684,-0.982863],[-1.01395,-0.985853],[-1.01645,-0.983266],[-1.01831,-0.981354],[-1.02169,-0.977859],[-1.01251,-0.987316],[-1.0164,-0.983323],[-1.01509,-0.984682],[-1.0144,-0.985381],[-1.01478,-0.984984],[-1.01705,-0.982659],[-1.02007,-0.979538],[-1.01179,-0.988075],[-1.01754,-0.98216],[-1.01817,-0.981495],[-1.01444,-0.985342],[-1.01199,-0.98787],[-1.0134,-0.986437],[-1.01359,-0.986209],[-1.01649,-0.983214],[-1.01438,-0.985403],[-1.01347,-0.986319],[-1.02102,-0.978555],[-1.01657,-0.983134],[-1.01378,-0.986033],[-1.01822,-0.981447],[-1.01798,-0.981708],[-1.01457,-0.985223],[-1.01378,-0.986008],[-1.01598,-0.983771],[-1.01241,-0.987442],[-1.0174,-0.982292],[-1.01209,-0.987773],[-1.01327,-0.986558],[-1.01423,-0.985547],[-1.01542,-0.984335],[-1.01229,-0.987547],[-1.00969,-0.99023],[-1.01237,-0.987491],[-1.01644,-0.983275],[-1.01392,-0.985875],[-1.01155,-0.988337],[-1.01548,-0.984268],[-1.01452,-0.985251],[-1.01118,-0.988691],[-1.01469,-0.985083],[-1.01667,-0.983043],[-1.01207,-0.987775],[-1.01213,-0.987707],[-1.01506,-0.984692],[-1.01834,-0.98133],[-1.01245,-0.987391],[-1.0173,-0.982399],[-1.01015,-0.989746],[-1.01312,-0.9867],[-1.01749,-0.982207],[-1.01146,-0.988397],[-1.01792,-0.981759],[-1.01868,-0.980965],[-1.01595,-0.98379],[-1.01389,-0.985903],[-1.01724,-0.982461],[-1.01015,-0.989774],[-1.01509,-0.984688],[-1.01402,-0.985781],[-1.02154,-0.97803],[-1.01539,-0.984335],[-1.01827,-0.981399],[-1.01099,-0.988902],[-1.01829,-0.981375],[-1.01809,-0.981564],[-1.01132,-0.988556],[-1.01881,-0.980832],[-1.01624,-0.983509],[-1.01269,-0.987155],[-1.01421,-0.985579],[-1.01547,-0.98428],[-1.01356,-0.986252],[-1.01671,-0.983011],[-1.01591,-0.983818],[-1.0175,-0.982195],[-1.01643,-0.983288],[-1.01475,-0.985025],[-1.01356,-0.986234],[-1.01982,-0.97979],[-1.01516,-0.984621],[-1.0168,-0.982933]]}}, +{"best":0.000173007,"evaluations":14112,"generation":579,"median":0.044199,"state":{"best":[-0.999136,-1.00086],"population":[[-1.01522,-0.984545],[-1.0149,-0.984869],[-1.0163,-0.98343],[-1.01493,-0.984841],[-1.01432,-0.985473],[-1.01458,-0.9852],[-1.01497,-0.984801],[-1.01325,-0.986576],[-1.01621,-0.983527],[-1.01501,-0.984753],[-1.01442,-0.985369],[-1.01557,-0.984178],[-1.01361,-0.986198],[-1.01692,-0.982788],[-1.0167,-0.983015],[-1.01609,-0.983645],[-1.0166,-0.983118],[-1.01413,-0.985663],[-1.01446,-0.985332],[-1.01521,-0.984552],[-1.01586,-0.983886],[-1.01633,-0.983398],[-1.01596,-0.983775],[-1.01446,-0.985334],[-1.01867,-0.980989],[-1.0158,-0.983948],[-1.01443,-0.985355],[-1.01623,-0.983499],[-1.01432,-0.98547],[-1.01482,-0.984954],[-1.01321,-0.986613],[-1.01555,-0.984206],[-1.01424,-0.985555],[-1.01512,-0.984654],[-1.01382,-0.985989],[-1.01574,-0.984001],[-1.01604,-0.983693],[-1.01494,-0.984832],[-1.01498,-0.984792],[-1.01545,-0.984308],[-1.01549,-0.984263],[-1.01252,-0.987323],[-1.01462,-0.98516],[-1.01401,-0.985788],[-1.01548,-0.984274],[-1.01567,-0.984084],[-1.01682,-0.982893],[-1.01569,-0.984054],[-1.01422,-0.985571],[-1.01476,-0.985019],[-1.01632,-0.983412],[-1.01777,-0.981913],[-1.01738,-0.982311],[-1.0163,-0.98343],[-1.0164,-0.983321],[-1.01504,-0.984728],[-1.01587,-0.983871],[-1.01553,-0.984222],[-1.01471,-0.985072],[-1.01624,-0.983495],[-1.01392,-0.985884],[-1.01628,-0.983451],[-1.01308,-0.986753],[-1.01468,-0.985099],[-1.01707,-0.982639],[-1.01412,-0.985673],[-1.01554,-0.984211],[-1.01401,-0.985787],[-1.01534,-0.984423],[-1.01279,-0.987042],[-1.01435,-0.985441],[-1.01504,-0.984735],[-1.01535,-0.984411],[-1.01653,-0.983191],[-1.0172,-0.982496],[-1.01443,-0.985354],[-1.01436,-0.985434],[-1.01431,-0.985485],[-1.0138,-0.986003],[-1.01822,-0.981457],[-1.01632,-0.983411],[-1.01507,-0.984692],[-1.01377,-0.986034],[-1.01451,-0.985277],[-1.01551,-0.984238],[-1.01491,-0.984862],[-1.01371,-0.986099],[-1.017,-0.982708],[-1.01667,-0.983048],[-1.01719,-0.982512],[-1.01658,-0.983143],[-1.0148,-0.984971],[-1.01533,-0.984423],[-1.01563,-0.984118],[-1.0135,-0.986321],[-1.01483,-0.984946]]}}, +{"best":0.000173007,"evaluations":14784,"generation":586,"median":0.0266441,"state":{"best":[-0.999136,-1.00086],"population":[[-1.01381,-0.985996],[-1.01538,-0.984378],[-1.01424,-0.985558],[-1.01569,-0.984058],[-1.01441,-0.985384],[-1.01349,-0.986327],[-1.0155,-0.984258],[-1.01467,-0.98511],[-1.01382,-0.985982],[-1.01435,-0.985443],[-1.01509,-0.984674],[-1.01543,-0.984328],[-1.0138,-0.986004],[-1.01526,-0.9845],[-1.01506,-0.984711],[-1.01464,-0.985141],[-1.014,-0.9858],[-1.01525,-0.984514],[-1.01481,-0.984965],[-1.01462,-0.985158],[-1.01485,-0.984928],[-1.01475,-0.985034],[-1.0141,-0.9857],[-1.01426,-0.985538],[-1.01493,-0.984848],[-1.01521,-0.984553],[-1.01406,-0.985743],[-1.01386,-0.98595],[-1.01496,-0.984816],[-1.0153,-0.984464],[-1.01492,-0.984851],[-1.01518,-0.984589],[-1.01489,-0.984889],[-1.01555,-0.984204],[-1.01498,-0.984787],[-1.01414,-0.985661],[-1.01441,-0.985381],[-1.01529,-0.984468],[-1.01413,-0.985665],[-1.01447,-0.985317],[-1.01377,-0.986039],[-1.01534,-0.984422],[-1.01369,-0.986122],[-1.01444,-0.985345],[-1.01489,-0.984888],[-1.01385,-0.985957],[-1.01531,-0.984451],[-1.01501,-0.984756],[-1.01485,-0.984928],[-1.01445,-0.985334],[-1.01404,-0.985756],[-1.01417,-0.985625],[-1.01478,-0.984995],[-1.01391,-0.98589],[-1.01453,-0.985256],[-1.01401,-0.985788],[-1.01438,-0.985415],[-1.01488,-0.984892],[-1.01549,-0.984266],[-1.01518,-0.984589],[-1.0137,-0.986115],[-1.0155,-0.984253],[-1.01499,-0.984777],[-1.0148,-0.984978],[-1.0153,-0.984465],[-1.01421,-0.985586],[-1.01545,-0.984305],[-1.01426,-0.985532],[-1.0155,-0.984258],[-1.01561,-0.984147],[-1.0145,-0.985286],[-1.01488,-0.9849],[-1.01489,-0.984886],[-1.01553,-0.98423],[-1.0137,-0.986107],[-1.01498,-0.984791],[-1.01528,-0.984487],[-1.01466,-0.985126],[-1.01349,-0.986329],[-1.01414,-0.98566],[-1.01377,-0.986035],[-1.01468,-0.985103],[-1.01442,-0.985366],[-1.01504,-0.984733],[-1.01479,-0.984992],[-1.01526,-0.984507],[-1.01545,-0.984307],[-1.0155,-0.984252],[-1.01385,-0.985959],[-1.01474,-0.985038],[-1.01526,-0.984506],[-1.01518,-0.984587],[-1.01516,-0.984605],[-1.01569,-0.984064],[-1.01446,-0.985324],[-1.01487,-0.984903]]}}, +{"best":0.000173007,"evaluations":15360,"generation":592,"median":0.019672,"state":{"best":[-0.999136,-1.00086],"population":[[-1.01469,-0.985093],[-1.01501,-0.984766],[-1.01503,-0.984743],[-1.01488,-0.984891],[-1.01472,-0.985063],[-1.0151,-0.984664],[-1.01456,-0.985223],[-1.01476,-0.985021],[-1.01451,-0.985273],[-1.01491,-0.984863],[-1.01464,-0.98514],[-1.01467,-0.985107],[-1.01574,-0.984008],[-1.01509,-0.984683],[-1.01501,-0.984761],[-1.01531,-0.984454],[-1.01506,-0.984715],[-1.01466,-0.985124],[-1.01486,-0.98492],[-1.01487,-0.984906],[-1.01478,-0.984999],[-1.01482,-0.984955],[-1.01452,-0.985269],[-1.01498,-0.984789],[-1.0151,-0.984666],[-1.01448,-0.985303],[-1.01497,-0.984806],[-1.01457,-0.985211],[-1.0155,-0.98426],[-1.01505,-0.984723],[-1.01489,-0.984887],[-1.01463,-0.985148],[-1.01472,-0.98506],[-1.01524,-0.984522],[-1.01483,-0.984948],[-1.01476,-0.985023],[-1.01468,-0.985103],[-1.01528,-0.984482],[-1.01489,-0.984882],[-1.015,-0.984767],[-1.01507,-0.984694],[-1.01441,-0.985384],[-1.01503,-0.984736],[-1.01467,-0.985111],[-1.01506,-0.984705],[-1.01453,-0.985258],[-1.01487,-0.98491],[-1.01575,-0.983997],[-1.01497,-0.984797],[-1.0148,-0.984982],[-1.01481,-0.984969],[-1.01455,-0.985231],[-1.01528,-0.984488],[-1.0145,-0.985285],[-1.01516,-0.984603],[-1.01488,-0.984897],[-1.01499,-0.984777],[-1.01526,-0.984505],[-1.01475,-0.985025],[-1.01483,-0.984951],[-1.01472,-0.985062],[-1.01468,-0.985101],[-1.01478,-0.985001],[-1.01494,-0.984832],[-1.01507,-0.984696],[-1.01493,-0.984844],[-1.01461,-0.985176],[-1.01475,-0.985028],[-1.01512,-0.984644],[-1.01487,-0.984905],[-1.01416,-0.985642],[-1.01468,-0.985103],[-1.01473,-0.985049],[-1.01493,-0.984841],[-1.01484,-0.984932],[-1.01454,-0.985242],[-1.01425,-0.985549],[-1.01512,-0.984651],[-1.01494,-0.98483],[-1.01447,-0.98532],[-1.01484,-0.984941],[-1.01476,-0.985015],[-1.01456,-0.985227],[-1.0144,-0.985391],[-1.01501,-0.984761],[-1.01489,-0.984889],[-1.01514,-0.984631],[-1.01475,-0.985025],[-1.0145,-0.985287],[-1.01507,-0.9847],[-1.01503,-0.984737],[-1.01463,-0.985149],[-1.01428,-0.985512],[-1.01464,-0.985142],[-1.01435,-0.985437],[-1.01476,-0.985017]]}}, +{"best":0.000173007,"evaluations":15936,"generation":598,"median":0.0127319,"state":{"best":[-0.999136,-1.00086],"population":[[-1.01479,-0.984984],[-1.01474,-0.985044],[-1.01481,-0.984967],[-1.01473,-0.98505],[-1.01467,-0.985115],[-1.01484,-0.984936],[-1.01472,-0.985061],[-1.01477,-0.985011],[-1.01473,-0.985054],[-1.01474,-0.985035],[-1.01473,-0.985051],[-1.01487,-0.984907],[-1.01486,-0.984912],[-1.01493,-0.984842],[-1.01476,-0.985018],[-1.01479,-0.984987],[-1.01476,-0.98502],[-1.01487,-0.984903],[-1.01483,-0.984946],[-1.01481,-0.984964],[-1.01476,-0.985024],[-1.01479,-0.984988],[-1.01486,-0.984912],[-1.01487,-0.984906],[-1.01482,-0.984961],[-1.01458,-0.985206],[-1.01489,-0.984881],[-1.01476,-0.98502],[-1.01479,-0.984989],[-1.01476,-0.985022],[-1.01492,-0.98485],[-1.01505,-0.984723],[-1.01477,-0.985006],[-1.01463,-0.985151],[-1.01477,-0.985013],[-1.01468,-0.985096],[-1.015,-0.984773],[-1.01476,-0.985021],[-1.0148,-0.984981],[-1.01493,-0.98484],[-1.01467,-0.985115],[-1.01476,-0.985018],[-1.0148,-0.984975],[-1.01482,-0.984961],[-1.01477,-0.985013],[-1.01464,-0.985145],[-1.01482,-0.98496],[-1.01476,-0.985023],[-1.01479,-0.984992],[-1.01489,-0.984883],[-1.01487,-0.984901],[-1.01479,-0.984988],[-1.01492,-0.984858],[-1.01486,-0.984917],[-1.01483,-0.984947],[-1.01501,-0.984757],[-1.01476,-0.985014],[-1.01489,-0.984889],[-1.0148,-0.984973],[-1.01486,-0.984916],[-1.01479,-0.984984],[-1.01483,-0.984947],[-1.01485,-0.984926],[-1.01484,-0.984937],[-1.01483,-0.984944],[-1.0149,-0.984871],[-1.0148,-0.984979],[-1.01498,-0.984793],[-1.01487,-0.984906],[-1.01495,-0.984822],[-1.01489,-0.984883],[-1.01475,-0.985034],[-1.01466,-0.985118],[-1.01495,-0.984824],[-1.01473,-0.985052],[-1.01495,-0.984826],[-1.01493,-0.984845],[-1.01481,-0.984971],[-1.01475,-0.985027],[-1.01479,-0.984985],[-1.01488,-0.984892],[-1.01495,-0.98482],[-1.0149,-0.984879],[-1.01491,-0.984862],[-1.01489,-0.98488],[-1.0148,-0.984974],[-1.01481,-0.984972],[-1.01497,-0.984799],[-1.01482,-0.984958],[-1.01482,-0.984954],[-1.01485,-0.984921],[-1.01494,-0.984837],[-1.01477,-0.985008],[-1.01468,-0.985097],[-1.01479,-0.984986],[-1.01487,-0.984906]]}}, +{"best":0.000173007,"evaluations":16608,"generation":605,"median":0.00622674,"state":{"best":[-0.999136,-1.00086],"population":[[-1.01485,-0.984924],[-1.01482,-0.984954],[-1.0148,-0.98498],[-1.01485,-0.984929],[-1.0148,-0.984982],[-1.01482,-0.984957],[-1.01483,-0.984945],[-1.01482,-0.984956],[-1.01484,-0.984938],[-1.01483,-0.984947],[-1.01486,-0.984916],[-1.01485,-0.984931],[-1.01483,-0.984948],[-1.01481,-0.984964],[-1.01482,-0.984952],[-1.01482,-0.984955],[-1.01487,-0.984907],[-1.0148,-0.984974],[-1.01482,-0.984953],[-1.01485,-0.98493],[-1.01483,-0.984945],[-1.01484,-0.984937],[-1.01485,-0.984924],[-1.01482,-0.984959],[-1.01481,-0.984965],[-1.01485,-0.984926],[-1.01483,-0.984943],[-1.01483,-0.984946],[-1.01484,-0.98494],[-1.01482,-0.984954],[-1.01483,-0.984951],[-1.01482,-0.984961],[-1.01485,-0.984925],[-1.01485,-0.984926],[-1.01481,-0.984964],[-1.01483,-0.984945],[-1.01482,-0.984958],[-1.01483,-0.984945],[-1.01482,-0.984957],[-1.01482,-0.98496],[-1.01484,-0.98494],[-1.01482,-0.984953],[-1.01482,-0.984952],[-1.01481,-0.984968],[-1.01485,-0.984926],[-1.01486,-0.984911],[-1.01483,-0.984949],[-1.01484,-0.984933],[-1.01482,-0.984954],[-1.01485,-0.98493],[-1.01484,-0.984936],[-1.01483,-0.984942],[-1.01481,-0.984968],[-1.01482,-0.98496],[-1.01484,-0.984939],[-1.01481,-0.984965],[-1.01482,-0.984953],[-1.01484,-0.984941],[-1.01484,-0.984939],[-1.01481,-0.984963],[-1.01485,-0.984921],[-1.01484,-0.984941],[-1.01484,-0.984931],[-1.01484,-0.984936],[-1.01485,-0.984921],[-1.01484,-0.984932],[-1.01482,-0.98496],[-1.01484,-0.984934],[-1.01486,-0.984919],[-1.0148,-0.984976],[-1.01483,-0.984947],[-1.01482,-0.984954],[-1.01481,-0.984972],[-1.01483,-0.984949],[-1.01482,-0.984962],[-1.01481,-0.984964],[-1.01485,-0.984927],[-1.01484,-0.984934],[-1.01482,-0.984959],[-1.01484,-0.984938],[-1.01481,-0.984966],[-1.01483,-0.984948],[-1.01484,-0.984935],[-1.01485,-0.984931],[-1.01483,-0.984948],[-1.01483,-0.984948],[-1.01484,-0.984938],[-1.01483,-0.984949],[-1.01482,-0.984956],[-1.01485,-0.984927],[-1.01483,-0.98495],[-1.01482,-0.984953],[-1.01484,-0.984934],[-1.01481,-0.984968],[-1.01481,-0.984963],[-1.01484,-0.984937]]}}, +{"best":0.000173007,"evaluations":17184,"generation":611,"median":0.00311389,"state":{"best":[-0.999136,-1.00086],"population":[[-1.01484,-0.984932],[-1.01483,-0.984944],[-1.01484,-0.984941],[-1.01483,-0.984944],[-1.01484,-0.984939],[-1.01483,-0.984944],[-1.01483,-0.984946],[-1.01484,-0.984933],[-1.01484,-0.98494],[-1.01484,-0.984938],[-1.01483,-0.984946],[-1.01483,-0.984943],[-1.01483,-0.984944],[-1.01484,-0.984938],[-1.01483,-0.984942],[-1.01484,-0.984933],[-1.01484,-0.984936],[-1.01483,-0.984947],[-1.01484,-0.984936],[-1.01484,-0.984935],[-1.01483,-0.984942],[-1.01483,-0.984942],[-1.01484,-0.984933],[-1.01484,-0.984941],[-1.01483,-0.984942],[-1.01484,-0.98494],[-1.01483,-0.984945],[-1.01484,-0.984941],[-1.01484,-0.98494],[-1.01484,-0.984937],[-1.01483,-0.984949],[-1.01483,-0.984946],[-1.01482,-0.984952],[-1.01483,-0.984942],[-1.01483,-0.984943],[-1.01483,-0.984942],[-1.01484,-0.984938],[-1.01484,-0.984938],[-1.01482,-0.984955],[-1.01483,-0.984942],[-1.01483,-0.984942],[-1.01484,-0.984939],[-1.01483,-0.984944],[-1.01483,-0.984942],[-1.01484,-0.984939],[-1.01484,-0.984937],[-1.01483,-0.984945],[-1.01483,-0.984945],[-1.01484,-0.984938],[-1.01483,-0.984942],[-1.01483,-0.984944],[-1.01483,-0.984943],[-1.01483,-0.984942],[-1.01484,-0.984938],[-1.01483,-0.984947],[-1.01483,-0.984946],[-1.01483,-0.984944],[-1.01484,-0.984939],[-1.01484,-0.984935],[-1.01484,-0.98494],[-1.01483,-0.984952],[-1.01483,-0.984942],[-1.01484,-0.98494],[-1.01483,-0.984943],[-1.01484,-0.984935],[-1.01483,-0.984945],[-1.01484,-0.98494],[-1.01483,-0.984942],[-1.01484,-0.984937],[-1.01484,-0.984937],[-1.01484,-0.984939],[-1.01484,-0.98494],[-1.01484,-0.984937],[-1.01484,-0.984939],[-1.01484,-0.984936],[-1.01484,-0.984935],[-1.01483,-0.984943],[-1.01483,-0.984945],[-1.01483,-0.984942],[-1.01484,-0.984941],[-1.01484,-0.984936],[-1.01484,-0.984936],[-1.01483,-0.984942],[-1.01483,-0.984942],[-1.01484,-0.984939],[-1.01483,-0.984946],[-1.01483,-0.984943],[-1.01484,-0.984938],[-1.01484,-0.984938],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984939],[-1.01483,-0.984949],[-1.01483,-0.984948],[-1.01484,-0.98494],[-1.01483,-0.984942]]}}, +{"best":0.000173007,"evaluations":17856,"generation":618,"median":0.00161161,"state":{"best":[-0.999136,-1.00086],"population":[[-1.01483,-0.984942],[-1.01484,-0.984941],[-1.01484,-0.98494],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984942],[-1.01484,-0.984939],[-1.01483,-0.984943],[-1.01484,-0.98494],[-1.01483,-0.984944],[-1.01484,-0.984939],[-1.01484,-0.98494],[-1.01484,-0.98494],[-1.01484,-0.984941],[-1.01483,-0.984942],[-1.01483,-0.984944],[-1.01484,-0.984939],[-1.01484,-0.98494],[-1.01484,-0.984939],[-1.01484,-0.984941],[-1.01483,-0.984944],[-1.01484,-0.98494],[-1.01484,-0.98494],[-1.01484,-0.98494],[-1.01483,-0.984942],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01483,-0.984942],[-1.01484,-0.98494],[-1.01484,-0.984941],[-1.01484,-0.984939],[-1.01484,-0.98494],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.98494],[-1.01484,-0.984938],[-1.01484,-0.984939],[-1.01484,-0.984938],[-1.01483,-0.984943],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984939],[-1.01484,-0.984939],[-1.01483,-0.984943],[-1.01484,-0.984941],[-1.01484,-0.984939],[-1.01484,-0.984941],[-1.01483,-0.984943],[-1.01483,-0.984943],[-1.01483,-0.984944],[-1.01483,-0.984944],[-1.01484,-0.98494],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01483,-0.984942],[-1.01483,-0.984943],[-1.01484,-0.984939],[-1.01483,-0.984943],[-1.01483,-0.984942],[-1.01483,-0.984942],[-1.01483,-0.984943],[-1.01483,-0.984943],[-1.01483,-0.984942],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01483,-0.984943],[-1.01484,-0.98494],[-1.01484,-0.984936],[-1.01484,-0.984939],[-1.01483,-0.984944],[-1.01484,-0.98494],[-1.01483,-0.984942],[-1.01484,-0.98494],[-1.01483,-0.984942],[-1.01483,-0.984942],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01483,-0.984942],[-1.01484,-0.98494],[-1.01484,-0.984937],[-1.01483,-0.984942],[-1.01483,-0.984944],[-1.01483,-0.984942],[-1.01484,-0.984939],[-1.01484,-0.984939],[-1.01484,-0.984941],[-1.01483,-0.984943],[-1.01483,-0.984942],[-1.01483,-0.984942],[-1.01484,-0.98494],[-1.01484,-0.984941],[-1.01484,-0.98494],[-1.01484,-0.984941]]}}, +{"best":0.000173007,"evaluations":18432,"generation":624,"median":0.00101757,"state":{"best":[-0.999136,-1.00086],"population":[[-1.01484,-0.984941],[-1.01484,-0.98494],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.98494],[-1.01484,-0.98494],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.98494],[-1.01484,-0.984941],[-1.01484,-0.98494],[-1.01484,-0.98494],[-1.01483,-0.984942],[-1.01484,-0.984941],[-1.01484,-0.984942],[-1.01484,-0.98494],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.98494],[-1.01484,-0.984941],[-1.01483,-0.984942],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01483,-0.984942],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.98494],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01483,-0.984942],[-1.01484,-0.984941],[-1.01484,-0.98494],[-1.01484,-0.98494],[-1.01484,-0.984941],[-1.01483,-0.984942],[-1.01484,-0.984941],[-1.01484,-0.98494],[-1.01483,-0.984942],[-1.01484,-0.984941],[-1.01483,-0.984942],[-1.01484,-0.98494],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01483,-0.984942],[-1.01484,-0.98494],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.98494],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.98494],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01483,-0.984942],[-1.01484,-0.984941],[-1.01484,-0.98494],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.98494],[-1.01484,-0.984941],[-1.01483,-0.984942],[-1.01484,-0.98494],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01483,-0.984942]]}}, +{"best":0.000173007,"evaluations":19104,"generation":631,"median":0.000560055,"state":{"best":[-0.999136,-1.00086],"population":[[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941],[-1.01484,-0.984941]]}}, +{"best":0.000173007,"evaluations":20160,"generation":637,"median":0.774738,"state":{"best":[-0.999136,-1.00086],"population":[[-0.799736,-1.14621],[-0.830763,-0.905386],[-1.38836,-0.550317],[-1.03946,-0.961254],[-0.876182,-1.3307],[-0.348293,-1.57823],[-0.87197,-1.04012],[-1.31097,-0.60145],[-0.630304,-1.56237],[-0.773296,-1.03175],[-0.924689,-0.79123],[-0.923754,-0.856194],[-1.19532,-0.723962],[-0.832873,-1.29036],[-1.45153,-0.594002],[-0.982802,-1.14114],[-0.636985,-1.05576],[-0.907775,-1.12921],[-0.637215,-1.08887],[-0.868548,-0.694479],[-1.10523,-1.05129],[-1.05202,-1.25136],[-1.2955,-0.458316],[-0.876162,-0.930209],[-0.903767,-0.814089],[-1.02986,-0.931193],[-0.835672,-1.07653],[-0.568268,-1.20545],[-1.24118,-0.417629],[-1.08226,-0.775924],[-1.39846,-0.327235],[-1.11771,-1.01164],[-0.864977,-1.0551],[-1.26532,-0.633344],[-1.42662,-0.763128],[-1.50263,-0.5286],[-0.734114,-0.921643],[-0.852691,-0.763104],[-0.863965,-0.862731],[-0.501134,-1.50802],[-0.493621,-1.25901],[-0.831061,-1.46803],[-1.00396,-0.995055],[-1.24296,-0.0703708],[-0.673315,-0.938204],[-0.844156,-1.2303],[-1.26129,-0.581615],[-0.420691,-1.26121],[-0.739775,-1.33695],[-0.89414,-0.614148],[-0.803943,-1.22026],[-0.817714,-0.889202],[-1.0145,-0.6624],[-1.44343,-0.58786],[-1.16484,-0.655427],[-1.03929,-0.758874],[-0.921644,-1.21428],[-0.710218,-1.37188],[-0.774768,-1.04937],[-1.08154,-1.00421],[-0.584121,-1.15852],[-1.35821,-0.763389],[-0.943492,-0.866073],[-0.683688,-1.08104],[-1.04335,-0.886028],[-0.693536,-1.28545],[-1.04003,-0.725075],[-0.819299,-0.930835],[-0.462382,-1.14302],[-0.610813,-1.03074],[-0.949863,-0.831971],[-0.970273,-1.04567],[-0.813469,-1.26483],[-0.488658,-1.56959],[-0.927277,-1.05632],[-1.39395,-0.374707],[-0.280435,-1.41864],[-1.25752,-0.665598],[-0.817298,-1.16074],[-1.10352,-0.75706],[-0.988789,-1.08957],[-1.23797,-0.539545],[-0.371093,-1.48406],[-0.629715,-1.17414],[-0.67003,-1.21568],[-1.40119,-0.748323],[-0.359389,-1.39601],[-0.942051,-0.974138],[-1.09552,-0.787406],[-0.549223,-1.50987],[-0.870437,-1.24955],[-1.3606,-0.376855],[-1.09001,-0.719292],[-1.03676,-0.905768],[-0.903375,-1.08386],[-1.1341,-0.714702],[-0.940759,-0.953151],[-1.03186,-0.821878],[-0.322767,-1.40588],[-0.821775,-0.884513],[-0.512947,-1.3862],[-0.519535,-1.45393],[-1.07326,-0.936052],[-0.77415,-1.13772],[-1.53303,-0.393691],[-1.17265,-0.693369],[-0.763053,-0.931593],[-0.536427,-1.1988],[-0.838628,-0.97453],[-0.894927,-0.669539],[-0.759905,-1.30728],[-1.70703,-0.311935],[-1.0557,-0.914446],[-0.936816,-0.951773],[-1.40532,-0.72773],[-1.0128,-0.863994],[-0.932519,-1.2704],[-0.941532,-0.7007],[-0.998761,-0.664423],[-1.00855,-0.697486],[-0.930543,-1.05115],[-0.621413,-1.1552],[-0.948174,-0.85245],[-0.710779,-1.06401],[-1.00424,-0.97048],[-0.934681,-0.820647],[-1.26229,-0.16887],[-0.46246,-1.16845],[-0.855105,-1.17249],[-1.41317,-0.79189],[-0.578472,-1.33041],[-1.0789,-1.01434],[-1.82481,-0.036835],[-1.54047,-0.253679],[-1.01843,-0.854728],[-0.839606,-1.3396],[-1.22434,-0.336823],[-1.28849,-0.907372],[-1.1042,-0.820749],[-0.781559,-1.21257],[-0.865817,-0.955133],[-0.834733,-1.11194],[-0.707522,-1.0302],[-0.929363,-1.24814],[-0.576675,-1.47426],[-1.16081,-0.880514],[-0.684392,-1.64797],[-1.07346,-0.610921],[-0.970533,-0.986211],[-0.629442,-1.40964],[-1.38935,-0.51231],[-0.897136,-1.0523],[-0.896743,-0.974913],[-0.696726,-1.40389],[-1.1686,-0.585557],[-0.696744,-0.957083],[-0.582708,-1.62842],[-1.09115,-0.351691],[-1.1511,-0.87691],[-1.0814,-0.87819],[-1.28907,-0.455353],[-0.91304,-1.131],[-0.876773,-1.03468],[-0.808684,-1.32911],[-1.06628,-1.2453],[-0.601959,-1.39732],[-1.23053,-0.596503],[-0.825906,-0.918804],[-1.10519,-0.828132],[-1.18254,-0.829654],[-1.04031,-1.18656],[-0.939139,-1.2347],[-1.7622,-0.282988],[-0.941924,-0.619849],[-1.18409,-0.76066],[-0.539567,-1.01334],[-1.28788,-0.562819],[-1.00647,-1.23839],[-0.93592,-0.955349],[-1.23161,-0.674655],[-0.556802,-1.36306],[-0.754113,-1.54247],[-0.985815,-1.48322],[-0.915339,-1.1202],[-0.893112,-0.98797],[-1.06714,-0.853071],[-0.734046,-0.95356],[-0.586007,-1.28626],[-0.855924,-1.20819],[-0.432334,-1.73455],[-0.878223,-1.13922],[-0.948084,-1.34086]]}} +]} diff --git a/examples/happy_cat/trace.py b/examples/happy_cat/trace.py new file mode 100644 index 00000000..44691e1b --- /dev/null +++ b/examples/happy_cat/trace.py @@ -0,0 +1,189 @@ +"""The trace for the plot on the example's page, written to the file that ``GENOXIDE_TRACE`` +names. The plot draws the population on the function's contour, which needs two dimensions: the +trace is of a separate run of CMA-ES with IPOP restarts in 2 dimensions, with a budget of +20,000 evaluations, in at most 100 frames. The Rust example writes the same file.""" + +import json +import math +import os + +import genoxide as gx + + +def record_small(): + """Runs CMA-ES with IPOP restarts in 2 dimensions and writes its trace, if ``GENOXIDE_TRACE`` is set.""" + path = os.environ.get("GENOXIDE_TRACE") + if not path: + return + problem = gx.problems.HappyCat(2) + minimum = problem.optimum.value + budget = 20_000 + cmaes = gx.Cmaes(problem.genome, restarts="ipop", objective="minimize", seed=1) + frames = Frames(100) + + def record(progress): + state = {"population": progress.population.tolist(), "best": progress.best_genome.tolist()} + frames.push(frame(progress, state, minimum)) + + cmaes.run(problem, target=minimum + 1e-8, evaluations=budget, on_generation=record) + low, high = problem.genome.bounds + settings = { + "format": 1, + "example": "happy_cat", + "objective": "minimize", + "x_label": "evaluations", + "y_label": "error", + "log_y": True, + "optimum": 0.0, + "plot": "contour", + "problem": { + "function": "happy_cat", + "bounds": [[float(low), float(high)]] * 2, + "minima": problem.optimum.solutions.tolist(), + }, + } + write(path, settings, frames.to_list()) + + +def frame(progress, state, minimum): + """The frame of a generation: its progress, the errors of its best and of its population's + median to ``minimum`` (rounding can put a solution a few ulps below it), and ``state``.""" + + def error(value): + return None if value is None else max(value - minimum, 0.0) + + return { + "generation": progress.generation, + "evaluations": progress.evaluations, + "best": error(progress.best_fitness), + "median": error(median(progress.scores)), + "state": state, + } + + +def median(scores): + """The median of the valid scores, None without any.""" + scores = sorted(float(score) for score in scores if not math.isnan(score)) + middle = len(scores) // 2 + if not scores: + return None + return scores[middle] if len(scores) % 2 else (scores[middle - 1] + scores[middle]) / 2 + + +# ---- the same in every example's trace ---------------------------------------------------------- + + +class Frames: + """The frames of at most ``most`` generations, from the part of the run where what the page + plots changes: the frames after the last change are left out (a run that reached its target, + or a front that no longer moves), and the rest are spread evenly over the generations up to + it. While the run goes, up to 8 × ``most`` frames are kept: every ``every``-th generation, + with ``every`` doubling whenever there are that many, and the last one.""" + + def __init__(self, most): + self.most, self.every, self.kept, self.last = most, 1, [], None + + def push(self, frame): + if frame["generation"] % self.every: + self.last = frame + return + self.kept.append(frame) + self.last = None + if len(self.kept) == 8 * self.most: + self.every *= 2 + self.kept = [kept for kept in self.kept if kept["generation"] % self.every == 0] + + def to_list(self): + frames = self.kept + ([self.last] if self.last else []) + active = frames[: last_change(frames) + 1] + count, most = len(active), max(self.most, 2) + if count <= most: + return active + return [active[(i * (count - 1) + (most - 1) // 2) // (most - 1)] for i in range(most)] + + +def last_change(frames): + """The index of the frame after which nothing the page plots changes. To 3 significant + digits, as a plot shows them: the best, the median and, for a single objective (a numeric + best), the state; to within a hundredth of their range over the run: a front's + hypervolumes, in the state or in a grid's series.""" + if not frames: + return 0 + last = len(frames) - 1 + number = lambda value: isinstance(value, (int, float)) and not isinstance(value, bool) + single = any(number(frame.get("best")) for frame in frames) + + def measures(frame): + values = [] + state = frame.get("state") + hypervolume = state.get("hypervolume") if isinstance(state, dict) else None + for value in (hypervolume, frame.get("series")): + if number(value): + values.append(float(value)) + elif isinstance(value, dict): + values.extend(float(v) for _, v in sorted(value.items()) if number(v)) + return values + + measured = [measures(frame) for frame in frames] + end = measured[last] + tolerance = [] + for k in range(len(end)): + values = [values[k] for values in measured if k < len(values)] + tolerance.append((max(values) - min(values)) / 100.0) + + def same(frame, final, key, flush=False): + return coarse(frame.get(key), flush) == coarse(final.get(key), flush) + + def settled(i): + frame, final = frames[i], frames[last] + return ( + same(frame, final, "best") + and same(frame, final, "median") + and (not single or same(frame, final, "state", flush=True)) + and len(measured[i]) == len(end) + and all(abs(v - e) <= t for v, e, t in zip(measured[i], end, tolerance)) + ) + + first = last + while first > 0 and settled(first - 1): + first -= 1 + return first + + +def coarse(value, flush=False): + """``value`` with its numbers to 3 significant digits, as precisely as a plot shows them: two + frames whose plotted values agree to that precision look the same. With ``flush``, for the + solutions a plot draws on their ranges, numbers below 1e-6 in size count as 0.""" + if isinstance(value, float): + if flush and abs(value) < 1e-6: + value = 0.0 + return f"{value:.2e}" + if isinstance(value, (list, tuple)): + return "[" + ",".join(coarse(item, flush) for item in value) + "]" + if isinstance(value, dict): + items = sorted(value.items()) + return "{" + ",".join(f"{key}:{coarse(item, flush)}" for key, item in items) + "}" + return json.dumps(value) + + +def write(path, settings, frames): + """Writes the settings and the frames to ``path``, a frame per line.""" + lines = ",\n".join(map(to_json, frames)) + with open(path, "w", encoding="utf-8", newline="\n") as file: + file.write(f'{to_json(settings)[:-1]},"frames":[\n{lines}\n]}}\n') + + +def to_json(value): + """Compact JSON with sorted keys, and numbers rounded to 6 significant digits, as the Rust + example writes it.""" + return json.dumps(rounded(value), sort_keys=True, separators=(",", ":"), ensure_ascii=False) + + +def rounded(value): + if isinstance(value, dict): + return {key: rounded(item) for key, item in value.items()} + if isinstance(value, (list, tuple)): + return [rounded(item) for item in value] + if isinstance(value, float): + return float(f"{value:.5e}") if math.isfinite(value) else None + return value diff --git a/examples/happy_cat/trace.rs b/examples/happy_cat/trace.rs new file mode 100644 index 00000000..36c337b8 --- /dev/null +++ b/examples/happy_cat/trace.rs @@ -0,0 +1,261 @@ +//! The trace for the plot on the example's page, written to the file that `GENOXIDE_TRACE` names. +//! The plot draws the population on the function's contour, which needs two dimensions: the trace +//! is of a separate run of CMA-ES with IPOP restarts in 2 dimensions, with a budget of +//! 20,000 evaluations, in at most 100 frames. The Python example writes the same +//! file. + +use genoxide::observer::Snapshot; +use genoxide::prelude::*; +use genoxide::problems::{HappyCat, Problem}; +use serde_json::{Value, json}; + +// runs CMA-ES with IPOP restarts in 2 dimensions and writes its trace, if GENOXIDE_TRACE is set +pub fn record_small() -> Result<()> { + let Ok(path) = std::env::var("GENOXIDE_TRACE") else { + return Ok(()); + }; + let problem = HappyCat::new(2); + let optimum = problem.optimum().expect("known"); + let minimum = optimum.value(); + let budget = 20_000; + let cmaes = Cmaes::builder(problem.representation()) + .restarts(cmaes::Restarts::Ipop) + .minimize() + .seed(1) + .build()?; + let mut frames = Frames::new(100); + Engine::new(cmaes, problem.clone()) + .stop_when(Stop::target(minimum + 1e-8).or(Stop::evaluations(budget))) + .on_generation(|snapshot| { + let population = snapshot.population().iter().map(|x| &x.genome()[..]); + let population: Vec<&[f64]> = population.collect(); + let best = &snapshot.best().genome()[..]; + let state = json!({ "population": population, "best": best }); + frames.push(frame(snapshot, state, minimum)); + }) + .run()?; + let bounds = problem.representation().bounds().to_vec(); + let bounds: Vec<[f64; 2]> = bounds.iter().map(|b| [*b.start(), *b.end()]).collect(); + let minima: Vec<&[f64]> = optimum.solutions().iter().map(|x| &x[..]).collect(); + let settings = json!({ + "format": 1, + "example": "happy_cat", + "objective": "minimize", + "x_label": "evaluations", + "y_label": "error", + "log_y": true, + "optimum": 0.0, + "plot": "contour", + "problem": { + "function": "happy_cat", + "bounds": bounds, + "minima": minima, + }, + }); + write(&path, settings, frames.into_vec()); + Ok(()) +} + +// the frame of a generation: its progress, the errors of its best and of its population's median +// to `minimum` (rounding can put a solution a few ulps below it), and `state` +fn frame(snapshot: &Snapshot<'_, Reals>, state: Value, minimum: f64) -> Value { + let progress = snapshot.progress(); + let error = |value: f64| (value - minimum).max(0.0); + let population = snapshot.population().iter(); + let scores = population.filter_map(|individual| individual.fitness()?.score()); + json!({ + "generation": progress.generation(), + "evaluations": progress.evaluations(), + "best": progress.best().and_then(Fitness::score).map(error), + "median": median(scores.collect()).map(error), + "state": state, + }) +} + +// the median of the scores, None without any +fn median(mut scores: Vec) -> Option { + scores.sort_by(f64::total_cmp); + let middle = scores.len() / 2; + match scores.len() { + 0 => None, + n if n % 2 == 1 => Some(scores[middle]), + _ => Some((scores[middle - 1] + scores[middle]) / 2.0), + } +} + +// ---- the same in every example's trace --------------------------------------------------------- + +// the frames of at most `most` generations, from the part of the run where what the page plots +// changes: the frames after the last change are left out (a run that reached its target, or a +// front that no longer moves), and the rest are spread evenly over the generations up to it. While +// the run goes, up to 8 × `most` frames are kept: every `every`-th generation, with `every` +// doubling whenever there are that many, and the last one. +struct Frames { + most: usize, + every: u64, + kept: Vec<(u64, Value)>, + last: Option<(u64, Value)>, +} + +impl Frames { + fn new(most: usize) -> Self { + let (every, kept, last) = (1, Vec::new(), None); + Self { + most, + every, + kept, + last, + } + } + + fn push(&mut self, frame: Value) { + let generation = frame["generation"].as_u64().expect("a generation"); + if !generation.is_multiple_of(self.every) { + self.last = Some((generation, frame)); + return; + } + self.kept.push((generation, frame)); + self.last = None; + if self.kept.len() == 8 * self.most { + self.every *= 2; + let every = self.every; + self.kept.retain(|(generation, _)| generation % every == 0); + } + } + + fn into_vec(self) -> Vec { + let frames = self.kept.into_iter().chain(self.last); + let frames: Vec = frames.map(|(_, frame)| frame).collect(); + let active = &frames[..=last_change(&frames)]; + let (count, most) = (active.len(), self.most.max(2)); + if count <= most { + return active.to_vec(); + } + let at = |i: usize| active[(i * (count - 1) + (most - 1) / 2) / (most - 1)].clone(); + (0..most).map(at).collect() + } +} + +// the index of the frame after which nothing the page plots changes. To 3 significant digits, as +// a plot shows them: the best, the median and, for a single objective (a numeric best), the state; +// to within a hundredth of their range over the run: a front's hypervolumes, in the state or in a +// grid's series +fn last_change(frames: &[Value]) -> usize { + let Some(last) = frames.len().checked_sub(1) else { + return 0; + }; + let single = frames.iter().any(|frame| frame["best"].is_number()); + let measures = |frame: &Value| -> Vec { + let mut values = Vec::new(); + for value in [&frame["state"]["hypervolume"], &frame["series"]] { + match value { + Value::Number(number) => values.extend(number.as_f64()), + Value::Object(map) => values.extend(map.values().filter_map(Value::as_f64)), + _ => {} + } + } + values + }; + let measured: Vec> = frames.iter().map(measures).collect(); + let end = &measured[last]; + let tolerance: Vec = (0..end.len()) + .map(|k| { + let values = measured.iter().filter_map(|values| values.get(k).copied()); + let (low, high) = values.fold((f64::INFINITY, f64::NEG_INFINITY), |(low, high), v| { + (low.min(v), high.max(v)) + }); + (high - low) / 100.0 + }) + .collect(); + let settled = |i: usize| { + let (frame, final_frame) = (&frames[i], &frames[last]); + let same = + |key: &str, flush: bool| coarse(&frame[key], flush) == coarse(&final_frame[key], flush); + same("best", false) + && same("median", false) + && (!single || same("state", true)) + && measured[i].len() == end.len() + && measured[i] + .iter() + .zip(end) + .zip(&tolerance) + .all(|((value, end), tolerance)| (value - end).abs() <= *tolerance) + }; + let mut first = last; + while first > 0 && settled(first - 1) { + first -= 1; + } + first +} + +// `value` with its numbers to 3 significant digits, as precisely as a plot shows them: two frames +// whose plotted values agree to that precision look the same. With `flush`, for the solutions a +// plot draws on their ranges, numbers below 1e-6 in size count as 0 +fn coarse(value: &Value, flush: bool) -> String { + let join = |items: Vec| items.join(","); + match value { + Value::Number(number) if number.is_f64() => { + let number = number.as_f64().expect("f64"); + let number = if flush && number.abs() < 1e-6 { + 0.0 + } else { + number + }; + format!("{number:.2e}") + } + Value::Array(items) => { + format!( + "[{}]", + join(items.iter().map(|item| coarse(item, flush)).collect()) + ) + } + Value::Object(map) => { + let entry = |(key, item): (&String, &Value)| format!("{key}:{}", coarse(item, flush)); + format!("{{{}}}", join(map.iter().map(entry).collect())) + } + other => other.to_string(), + } +} + +// writes the settings and the frames to `path`, a frame per line +fn write(path: &str, settings: Value, frames: Vec) { + let frames: Vec = frames.iter().map(to_json).collect(); + let settings = to_json(&settings); + let head = &settings[..settings.len() - 1]; + let text = format!("{head},\"frames\":[\n{}\n]}}\n", frames.join(",\n")); + std::fs::write(path, text).expect("the trace is written"); +} + +// compact JSON with sorted keys, and numbers rounded to 6 significant digits and written as +// Python writes them (7542.0, 1e-08): the Python example writes the same file +fn to_json(value: &Value) -> String { + let join = |items: Vec| items.join(","); + match value { + Value::Number(number) if number.is_f64() => python_float(number.as_f64().expect("f64")), + Value::Array(items) => format!("[{}]", join(items.iter().map(to_json).collect())), + Value::Object(map) => { + let entry = + |(key, item): (&String, &Value)| format!("{}:{}", json!(key), to_json(item)); + format!("{{{}}}", join(map.iter().map(entry).collect())) + } + other => other.to_string(), + } +} + +fn python_float(value: f64) -> String { + let rounded: f64 = format!("{value:.5e}").parse().expect("a number"); + let shortest = format!("{rounded:e}"); + let (mantissa, exponent) = shortest.split_once('e').expect("an exponent"); + let exponent: i32 = exponent.parse().expect("an exponent"); + if (-4..16).contains(&exponent) { + let text = rounded.to_string(); + if text.contains('.') { + text + } else { + text + ".0" + } + } else { + let sign = if exponent < 0 { '-' } else { '+' }; + format!("{mantissa}e{sign}{:02}", exponent.abs()) + } +} diff --git a/examples/hg_bat/README.md b/examples/hg_bat/README.md new file mode 100644 index 00000000..62a3c532 --- /dev/null +++ b/examples/hg_bat/README.md @@ -0,0 +1,76 @@ +--- +title: HGBat +category: continuous +summary: Minimize HGBat, a groove that curves around to the minimum, in 10 dimensions, with CMA-ES without and with restarts, DE, PSO and a GA from 10 seeds each. +reference: "Liang, J. J., Qu, B. Y. and Suganthan, P. N. (2013). Problem Definitions and Evaluation Criteria for the CEC 2014 Special Session and Competition on Single Objective Real-Parameter Numerical Optimization. Technical report 201311, Zhengzhou University and Nanyang Technological University." +reference_url: "https://github.com/P-N-Suganthan/CEC2014" +optimum: "0 (at (−1, …, −1))" +languages: [rust, python] +order: 98 +trace_note: "Recorded from another run: CMA-ES with IPOP restarts in 2 dimensions, so that the population can be drawn on the function's contour." +--- + +# HGBat + +## The problem + +HGBat is HappyCat's relative, with the difference of two squares in the first term: + +```text +f(x) = |(Σ xᵢ²)² − (Σ xᵢ)²|^(1/2) + (½ Σ xᵢ² + Σ xᵢ) / n + ½, each xᵢ in [−5, 5] +``` + +Its minimum is 0, at (−1, …, −1), the only one: the second part is Σ (xᵢ + 1)² / (2n), 0 only +there, where the first is 0 too. Here n = 10. genoxide takes it from the CEC 2014 report (Liang, Qu +and Suganthan 2013, function 12), which scales its search space [−100, 100] by 5/100, to +[−5, 5], and gives no other source; it's usually credited to Beyer and Finck too, whose paper +couldn't be read. + +## What makes it hard + +The first term is 0 where ‖x‖² = |Σ xᵢ|, a curved surface through the origin and (−1, …, −1), +and rises as a square root away from it: a groove whose floor curves around to the minimum, with a +gentle slope along it. As on HappyCat, a search falls into the groove at once, then has to follow a +curving direction with small steps across it and large ones along it. + +## Representation + +A `Real` genome of 10 genes, each in [−5, 5]: the point x itself. The fitness is f(x), to +minimize. The function is genoxide's `problems::HgBat`, which brings its bounds and its minimum. + +## Algorithm + +Five algorithms, each from seeds 1 to 10, with a budget of 10,000 evaluations per dimension, +100,000 per run, and a target of 1e-8: + +- CMA-ES (Hansen and Ostermeier, 2001, Evolutionary Computation 9(2): 159-195), which samples a + population of 10 from a normal distribution and adapts its mean, its step size and its covariance + matrix, from a step size of 0.3 of each gene's range and a random start; +- the same with IPOP restarts (Auger and Hansen, 2005, IEEE CEC 2005: 1769-1776): a run that has + converged starts again from a random point with twice the population; +- differential evolution with genoxide's defaults, SHADE (Tanabe and Fukunaga, CEC 2013), with a + population of 100 and its restarts on stagnation; +- particle swarm optimization (Kennedy and Eberhart, 1995), 40 particles with Clerc and Kennedy's + constriction coefficients and a global topology; +- a real-coded genetic algorithm: a population of 100, tournaments of 3, simulated binary crossover + (Deb and Agrawal, 1995) with η = 15 and polynomial mutation with η = 20 at a rate of 1/10 per + gene. + +## Output + +The first line gives the dimension, the seeds and the budget. Then a row per algorithm: how many +of its 10 runs reached the minimum, to within 1e-8, the median of their evaluations (a dash if none +did), and the median of every run's best error, to two significant digits. The function is +evaluated with genoxide's portable math, so the runs are the same on every platform, and in Python, +`run` evaluates it in Rust, so both versions print the same. + +[The project page](https://tachsin.gr/projects/genoxide/examples/hg-bat) plays back another run: +CMA-ES with IPOP restarts on the function in 2 dimensions, so that the population +can be drawn on its contour. Within 20,000 evaluations it ends at an error of 0.010, in the groove: it doesn't reach the +target in 2 dimensions either. + +## Good results + +No algorithm reaches the minimum to within 1e-8. SHADE comes closest, with a median error of 0.13; +PSO ends at 0.20, the genetic algorithm at 0.30, CMA-ES with IPOP restarts at 0.34 and without +restarts at 0.45. They reach the groove and stall in it, as on HappyCat. diff --git a/examples/hg_bat/main.py b/examples/hg_bat/main.py new file mode 100644 index 00000000..0339a21a --- /dev/null +++ b/examples/hg_bat/main.py @@ -0,0 +1,86 @@ +"""HGBat: minimize HGBat, HappyCat's relative with a groove along a cone, in 10 +dimensions. + +Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), +differential evolution (SHADE), particle swarm optimization and a real-coded genetic algorithm from +10 seeds each, and counts the runs that reach the minimum, 0 at (−1, …, −1), to within 1e-8. The +function is genoxide's `problems::HgBat`, which run evaluates in Rust. + +With ``GENOXIDE_TRACE=``, it also writes a trace of a run for the plot on the example's page, +with trace.py. + + python examples/hg_bat/main.py +""" + +import genoxide as gx + +from trace import record_small + +DIMENSIONS = 10 +SEEDS = 10 +BUDGET = 10_000 * DIMENSIONS +# a run stops once its error to the minimum is at most this +ERROR = 1e-8 +ALGORITHMS = ["CMA-ES", "CMA-ES with IPOP", "DE", "PSO", "GA"] + + +def build(name, genome, seed): + """The algorithm called ``name``, on ``genome``, from ``seed``.""" + if name == "CMA-ES": + return gx.Cmaes(genome, objective="minimize", seed=seed) + if name == "CMA-ES with IPOP": + return gx.Cmaes(genome, restarts="ipop", objective="minimize", seed=seed) + if name == "DE": + return gx.De(genome, objective="minimize", seed=seed) + if name == "PSO": + return gx.Pso(genome, population_size=40, objective="minimize", seed=seed) + return gx.Ga( + genome, + population_size=100, + select=gx.Tournament(3), + crossover=gx.SimulatedBinaryCrossover(15.0), + mutation=gx.PolynomialMutation(20.0, rate=1 / DIMENSIONS), + objective="minimize", + seed=seed, + ) + + +def median(values): + """The median of ``values``, None without any.""" + values = sorted(values) + middle = len(values) // 2 + if not values: + return None + return values[middle] if len(values) % 2 else (values[middle - 1] + values[middle]) / 2 + + +def error_text(error): + """An error to two significant digits, as Rust writes it: 9.9e-9.""" + mantissa, exponent = f"{error:.1e}".split("e") + return f"{mantissa}e{int(exponent)}" + + +problem = gx.problems.HgBat(DIMENSIONS) +minimum = problem.optimum.value +print(f"HGBat in {DIMENSIONS} dimensions, {SEEDS} seeds, {BUDGET} evaluations at most per run") +print("algorithm at min evaluations median error") +for name in ALGORITHMS: + # the evaluations of the runs that reach the minimum, and every run's best error + evaluations, errors = [], [] + for seed in range(1, SEEDS + 1): + result = build(name, problem.genome, seed).run( + problem, target=minimum + ERROR, evaluations=BUDGET + ) + if result.stop_reason == "target": + evaluations.append(float(result.evaluations)) + # rounding can put a solution a few ulps below the minimum + errors.append(max(result.best_fitness - minimum, 0.0)) + reached = f"{len(evaluations)}/{SEEDS}" + middle = median(evaluations) + evaluations_text = "-" if middle is None else f"{middle:.0f}" + print(f"{name:<16} {reached:>6} {evaluations_text:>11} {error_text(median(errors)):>12}") +print("evaluations: the median of the runs that reach the minimum") + +# with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate run in +# 2 dimensions: the plot is the function's contour +record_small() diff --git a/examples/hg_bat/main.rs b/examples/hg_bat/main.rs new file mode 100644 index 00000000..d41dbda9 --- /dev/null +++ b/examples/hg_bat/main.rs @@ -0,0 +1,118 @@ +//! HGBat: minimize HGBat, HappyCat's relative with a groove along a cone, in 10 +//! dimensions. +//! +//! Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), +//! differential evolution (SHADE), particle swarm optimization and a real-coded genetic algorithm +//! from 10 seeds each, and counts the runs that reach the minimum, 0 at (−1, …, −1), to within +//! 1e-8. The function is genoxide's `problems::HgBat`. +//! +//! With `GENOXIDE_TRACE=`, it also writes a trace of a run for the plot on the example's +//! page, with `trace.rs`. +//! +//! ```text +//! cargo run --release --example hg_bat +//! ``` + +mod trace; + +use genoxide::prelude::*; +use genoxide::problems::{HgBat, Problem}; + +const DIMENSIONS: usize = 10; +const SEEDS: u64 = 10; +const BUDGET: u64 = 10_000 * DIMENSIONS as u64; +// a run stops once its error to the minimum is at most this +const ERROR: f64 = 1e-8; +const ALGORITHMS: [&str; 5] = ["CMA-ES", "CMA-ES with IPOP", "DE", "PSO", "GA"]; + +fn main() -> Result<()> { + let problem = HgBat::new(DIMENSIONS); + let minimum = problem.optimum().expect("known").value(); + println!( + "HGBat in {DIMENSIONS} dimensions, {SEEDS} seeds, {BUDGET} evaluations at most per run" + ); + println!("algorithm at min evaluations median error"); + for algorithm in ALGORITHMS { + // the evaluations of the runs that reach the minimum, and every run's best error + let mut evaluations = Vec::new(); + let mut errors = Vec::new(); + for seed in 1..=SEEDS { + let outcome = run(algorithm, problem, seed, minimum + ERROR)?; + if outcome.stop_reason() == StopReason::Target { + evaluations.push(outcome.evaluations() as f64); + } + // rounding can put a solution a few ulps below the minimum + let best = outcome.best_fitness().score().expect("valid"); + errors.push((best - minimum).max(0.0)); + } + let reached = format!("{}/{SEEDS}", evaluations.len()); + let evaluations = median(evaluations).map_or("-".to_string(), |e| format!("{e:.0}")); + let error = median(errors).expect("a run"); + println!( + "{algorithm:<16} {reached:>6} {evaluations:>11} {:>12}", + format!("{error:.1e}") + ); + } + println!("evaluations: the median of the runs that reach the minimum"); + + // with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate + // run in 2 dimensions: the plot is the function's contour + trace::record_small()?; + Ok(()) +} + +// a run of `algorithm` from `seed`, until its best is at most `target` or it has used BUDGET +// evaluations +fn run(algorithm: &str, problem: HgBat, seed: u64, target: f64) -> Result> { + let real = problem.representation(); + let stop = Stop::target(target).or(Stop::evaluations(BUDGET)); + match algorithm { + "CMA-ES" | "CMA-ES with IPOP" => { + let restarts = if algorithm == "CMA-ES" { + cmaes::Restarts::Never + } else { + cmaes::Restarts::Ipop + }; + let cmaes = Cmaes::builder(real) + .restarts(restarts) + .minimize() + .seed(seed) + .build()?; + Engine::new(cmaes, problem).stop_when(stop).run() + } + "DE" => { + let de = De::builder(real).minimize().seed(seed).build()?; + Engine::new(de, problem).stop_when(stop).run() + } + "PSO" => { + let pso = Pso::builder(real) + .population_size(40) + .minimize() + .seed(seed) + .build()?; + Engine::new(pso, problem).stop_when(stop).run() + } + _ => { + let ga = Ga::builder(real) + .population_size(100) + .select(Tournament::new(3)?) + .crossover(SimulatedBinaryCrossover::new(15.0)?) + .mutate(PolynomialMutation::per_gene(1.0 / DIMENSIONS as f64, 20.0)?) + .minimize() + .seed(seed) + .build()?; + Engine::new(ga, problem).stop_when(stop).run() + } + } +} + +// the median of `values`, None without any +fn median(mut values: Vec) -> Option { + values.sort_by(f64::total_cmp); + let middle = values.len() / 2; + match values.len() { + 0 => None, + n if n % 2 == 1 => Some(values[middle]), + _ => Some((values[middle - 1] + values[middle]) / 2.0), + } +} diff --git a/examples/hg_bat/output.txt b/examples/hg_bat/output.txt new file mode 100644 index 00000000..89540bac --- /dev/null +++ b/examples/hg_bat/output.txt @@ -0,0 +1,8 @@ +HGBat in 10 dimensions, 10 seeds, 100000 evaluations at most per run +algorithm at min evaluations median error +CMA-ES 0/10 - 4.5e-1 +CMA-ES with IPOP 0/10 - 3.4e-1 +DE 0/10 - 1.3e-1 +PSO 0/10 - 2.0e-1 +GA 0/10 - 3.0e-1 +evaluations: the median of the runs that reach the minimum diff --git a/examples/hg_bat/trace.json b/examples/hg_bat/trace.json new file mode 100644 index 00000000..7ee67688 --- /dev/null +++ b/examples/hg_bat/trace.json @@ -0,0 +1,102 @@ +{"example":"hg_bat","format":1,"log_y":true,"objective":"minimize","optimum":0.0,"plot":"contour","problem":{"bounds":[[-5.0,5.0],[-5.0,5.0]],"function":"hg_bat","minima":[[-1.0,-1.0]]},"x_label":"evaluations","y_label":"error","frames":[ +{"best":9.1227,"evaluations":6,"generation":0,"median":22.3027,"state":{"best":[2.14496,-1.42894],"population":[[-4.02856,-1.2232],[1.09727,-3.0536],[-2.70235,3.76881],[-1.07094,-4.64995],[-3.75609,-3.6306],[2.14496,-1.42894]]}}, +{"best":0.483697,"evaluations":48,"generation":7,"median":2.79206,"state":{"best":[-1.08673,-0.156447],"population":[[-1.64272,0.218136],[-0.989715,0.858634],[-1.57886,-1.15271],[-0.93516,1.19111],[-1.32685,0.767843],[0.35638,0.739813]]}}, +{"best":0.483697,"evaluations":84,"generation":13,"median":0.600453,"state":{"best":[-1.08673,-0.156447],"population":[[-1.0947,-0.95698],[-0.356645,0.144415],[-0.418077,-0.656397],[-1.15358,-0.519075],[-0.527432,-0.287842],[-0.520028,0.14745]]}}, +{"best":0.176304,"evaluations":126,"generation":20,"median":0.875053,"state":{"best":[-0.703982,-1.18121],"population":[[-0.359752,-0.988738],[-0.919003,-0.800793],[-0.703982,-1.18121],[-1.23406,-0.895468],[-0.941348,-1.38236],[-0.748106,-1.25771]]}}, +{"best":0.159686,"evaluations":162,"generation":26,"median":0.609279,"state":{"best":[-0.900474,-1.08794],"population":[[-0.975893,-1.0492],[-0.958538,-0.930931],[-0.900474,-1.08794],[-0.976703,-1.18678],[-0.81365,-1.03152],[-0.895571,-1.15328]]}}, +{"best":0.0711971,"evaluations":204,"generation":33,"median":0.327012,"state":{"best":[-0.868308,-1.10448],"population":[[-0.870537,-1.12791],[-0.774588,-1.19776],[-0.764231,-1.19716],[-0.846287,-1.1059],[-0.825007,-1.14318],[-0.868308,-1.10448]]}}, +{"best":0.0283917,"evaluations":246,"generation":40,"median":0.16801,"state":{"best":[-0.819889,-1.13066],"population":[[-0.855969,-1.10052],[-0.854795,-1.11265],[-0.828082,-1.13016],[-0.835803,-1.11865],[-0.836926,-1.11495],[-0.843958,-1.12429]]}}, +{"best":0.0283917,"evaluations":282,"generation":46,"median":0.0633536,"state":{"best":[-0.819889,-1.13066],"population":[[-0.842675,-1.11811],[-0.838173,-1.12174],[-0.842512,-1.11817],[-0.836787,-1.12212],[-0.840296,-1.11796],[-0.852455,-1.11184]]}}, +{"best":0.0254069,"evaluations":324,"generation":53,"median":0.0381492,"state":{"best":[-0.838029,-1.12103],"population":[[-0.837423,-1.12129],[-0.8389,-1.12084],[-0.840029,-1.11983],[-0.836256,-1.12215],[-0.836355,-1.12168],[-0.839684,-1.12001]]}}, +{"best":0.0161657,"evaluations":366,"generation":60,"median":0.0217144,"state":{"best":[-0.838816,-1.12064],"population":[[-0.834892,-1.1227],[-0.833434,-1.12355],[-0.836138,-1.12216],[-0.833307,-1.12364],[-0.837913,-1.12113],[-0.836701,-1.12183]]}}, +{"best":0.0113222,"evaluations":402,"generation":66,"median":0.0152732,"state":{"best":[-0.836324,-1.122],"population":[[-0.836335,-1.12201],[-0.83659,-1.12186],[-0.836324,-1.122],[-0.835981,-1.12218],[-0.83621,-1.12204],[-0.836632,-1.12184]]}}, +{"best":0.0108334,"evaluations":444,"generation":73,"median":0.0132846,"state":{"best":[-0.836136,-1.1221],"population":[[-0.836039,-1.12215],[-0.836105,-1.12212],[-0.836136,-1.1221],[-0.83629,-1.12203],[-0.8361,-1.12212],[-0.836208,-1.12207]]}}, +{"best":0.0107334,"evaluations":480,"generation":79,"median":0.0122432,"state":{"best":[-0.836211,-1.12206],"population":[[-0.836322,-1.122],[-0.83621,-1.12206],[-0.836183,-1.12208],[-0.836378,-1.12197],[-0.836245,-1.12204],[-0.83604,-1.12216]]}}, +{"best":0.0107334,"evaluations":522,"generation":86,"median":0.0116029,"state":{"best":[-0.836211,-1.12206],"population":[[-0.836486,-1.12191],[-0.836421,-1.12195],[-0.836468,-1.12192],[-0.836542,-1.12188],[-0.836436,-1.12194],[-0.836472,-1.12192]]}}, +{"best":0.0104543,"evaluations":564,"generation":93,"median":0.0109681,"state":{"best":[-0.836412,-1.12195],"population":[[-0.836434,-1.12194],[-0.836403,-1.12196],[-0.836429,-1.12194],[-0.836418,-1.12195],[-0.836428,-1.12195],[-0.836437,-1.12194]]}}, +{"best":0.0104543,"evaluations":600,"generation":99,"median":0.0106761,"state":{"best":[-0.836412,-1.12195],"population":[[-0.836409,-1.12196],[-0.836412,-1.12195],[-0.836411,-1.12195],[-0.836406,-1.12196],[-0.836421,-1.12195],[-0.83641,-1.12196]]}}, +{"best":0.0104321,"evaluations":642,"generation":106,"median":0.0104758,"state":{"best":[-0.836414,-1.12195],"population":[[-0.836419,-1.12195],[-0.836416,-1.12195],[-0.836416,-1.12195],[-0.836418,-1.12195],[-0.836415,-1.12195],[-0.836417,-1.12195]]}}, +{"best":0.0104213,"evaluations":678,"generation":112,"median":0.0104739,"state":{"best":[-0.836418,-1.12195],"population":[[-0.836417,-1.12195],[-0.836418,-1.12195],[-0.836418,-1.12195],[-0.836417,-1.12195],[-0.836418,-1.12195],[-0.836418,-1.12195]]}}, +{"best":0.0104126,"evaluations":720,"generation":119,"median":0.0104255,"state":{"best":[-0.836418,-1.12195],"population":[[-0.836418,-1.12195],[-0.836417,-1.12195],[-0.836417,-1.12195],[-0.836418,-1.12195],[-0.836418,-1.12195],[-0.836418,-1.12195]]}}, +{"best":0.0104103,"evaluations":762,"generation":126,"median":0.0104136,"state":{"best":[-0.836418,-1.12195],"population":[[-0.836418,-1.12195],[-0.836418,-1.12195],[-0.836418,-1.12195],[-0.836418,-1.12195],[-0.836418,-1.12195],[-0.836418,-1.12195]]}}, +{"best":0.0104103,"evaluations":798,"generation":132,"median":0.0104154,"state":{"best":[-0.836418,-1.12195],"population":[[-0.836418,-1.12195],[-0.836418,-1.12195],[-0.836418,-1.12195],[-0.836418,-1.12195],[-0.836418,-1.12195],[-0.836418,-1.12195]]}}, +{"best":0.010408,"evaluations":840,"generation":139,"median":0.0104098,"state":{"best":[-0.836418,-1.12195],"population":[[-0.836418,-1.12195],[-0.836418,-1.12195],[-0.836418,-1.12195],[-0.836418,-1.12195],[-0.836418,-1.12195],[-0.836418,-1.12195]]}}, +{"best":0.0104079,"evaluations":882,"generation":146,"median":0.0104089,"state":{"best":[-0.836418,-1.12195],"population":[[-0.836418,-1.12195],[-0.836418,-1.12195],[-0.836418,-1.12195],[-0.836418,-1.12195],[-0.836418,-1.12195],[-0.836418,-1.12195]]}}, +{"best":0.0104079,"evaluations":918,"generation":152,"median":0.0104087,"state":{"best":[-0.836418,-1.12195],"population":[[-0.836418,-1.12195],[-0.836418,-1.12195],[-0.836418,-1.12195],[-0.836418,-1.12195],[-0.836418,-1.12195],[-0.836418,-1.12195]]}}, +{"best":0.0104079,"evaluations":960,"generation":159,"median":0.0104083,"state":{"best":[-0.836418,-1.12195],"population":[[-0.836418,-1.12195],[-0.836418,-1.12195],[-0.836418,-1.12195],[-0.836418,-1.12195],[-0.836418,-1.12195],[-0.836418,-1.12195]]}}, +{"best":0.0104079,"evaluations":996,"generation":165,"median":0.010408,"state":{"best":[-0.836418,-1.12195],"population":[[-0.836418,-1.12195],[-0.836418,-1.12195],[-0.836418,-1.12195],[-0.836418,-1.12195],[-0.836418,-1.12195],[-0.836418,-1.12195]]}}, +{"best":0.0104078,"evaluations":1038,"generation":172,"median":0.0104079,"state":{"best":[-0.836418,-1.12195],"population":[[-0.836418,-1.12195],[-0.836418,-1.12195],[-0.836418,-1.12195],[-0.836418,-1.12195],[-0.836418,-1.12195],[-0.836418,-1.12195]]}}, +{"best":0.0104078,"evaluations":1080,"generation":179,"median":0.010408,"state":{"best":[-0.836418,-1.12195],"population":[[-0.836418,-1.12195],[-0.836418,-1.12195],[-0.836418,-1.12195],[-0.836418,-1.12195],[-0.836418,-1.12195],[-0.836418,-1.12195]]}}, +{"best":0.0104078,"evaluations":1134,"generation":185,"median":20.4635,"state":{"best":[-0.836418,-1.12195],"population":[[3.57166,1.3867],[-2.92505,2.78437],[-1.75702,3.50189],[-2.82351,3.18107],[4.0417,-2.66346],[2.30823,0.127847],[1.20999,-3.59091],[4.62688,2.135],[-2.8211,-1.4505],[2.61805,1.20942],[-0.123104,-1.7367],[4.92666,-1.73912]]}}, +{"best":0.0104078,"evaluations":1218,"generation":192,"median":1.27756,"state":{"best":[-0.836418,-1.12195],"population":[[0.575685,0.0702354],[-0.0401797,-0.596375],[0.689613,-0.65806],[0.891607,-0.97297],[0.278386,0.515184],[0.549008,-0.260192],[0.402496,-0.591817],[-0.342067,0.0104629],[-1.30958,-0.0291989],[-2.05561,0.586758],[-0.814116,0.405754],[-0.461111,-0.347902]]}}, +{"best":0.0104078,"evaluations":1290,"generation":198,"median":0.672197,"state":{"best":[-0.836418,-1.12195],"population":[[-0.232848,0.252379],[-0.335687,0.39007],[-0.633716,0.275666],[-0.545984,0.113197],[-0.362961,0.116147],[-0.269453,0.245313],[-0.0757308,0.145306],[0.136108,0.171694],[-0.445038,-0.00939075],[-0.305911,0.319768],[-0.370844,0.267304],[-0.282102,-0.0108599]]}}, +{"best":0.0104078,"evaluations":1374,"generation":205,"median":0.514679,"state":{"best":[-0.836418,-1.12195],"population":[[-0.142978,0.123111],[-0.124681,0.0889074],[-0.0763353,0.0188934],[-0.144582,0.106757],[-0.123042,0.0924092],[-0.130101,0.10353],[-0.114767,0.151785],[-0.190492,0.164879],[-0.0580413,0.0520467],[-0.151142,0.0738789],[-0.052959,0.0255179],[-0.0989968,0.085333]]}}, +{"best":0.0104078,"evaluations":1458,"generation":212,"median":0.509748,"state":{"best":[-0.836418,-1.12195],"population":[[0.00456115,0.00168924],[0.0607994,-0.0488791],[0.0331216,-0.041122],[0.00178872,-0.0134098],[-0.0709294,0.0516134],[0.0446922,-0.040472],[-0.0529782,0.00747189],[0.0132183,-0.0171467],[0.0659612,-0.0544974],[0.0446412,-0.0627042],[0.0320633,-0.0165586],[0.10311,-0.0839425]]}}, +{"best":0.0104078,"evaluations":1530,"generation":218,"median":0.501201,"state":{"best":[-0.836418,-1.12195],"population":[[-0.0154711,0.0100222],[0.0100379,-0.00792983],[0.00490991,-0.0105164],[0.00820971,-0.0101872],[0.0201254,-0.0219375],[0.0148017,-0.0133937],[-0.00301846,0.00327816],[0.0221705,-0.0248508],[0.00772687,-0.00729099],[0.0253663,-0.0263831],[0.0204585,-0.0127435],[0.00854645,-0.00880656]]}}, +{"best":0.0104078,"evaluations":1614,"generation":225,"median":0.50032,"state":{"best":[-0.836418,-1.12195],"population":[[0.00469304,-0.00433482],[0.011511,-0.0127937],[0.00955758,-0.00904642],[0.00727324,-0.00726713],[0.0033502,-0.00332733],[0.00779316,-0.0082903],[0.000993575,-0.00210126],[0.00931391,-0.00967743],[0.00766239,-0.00742355],[0.00407502,-0.00388974],[0.00651396,-0.00687406],[0.0141162,-0.0150676]]}}, +{"best":0.0104078,"evaluations":1698,"generation":232,"median":0.500138,"state":{"best":[-0.836418,-1.12195],"population":[[-0.00318965,0.00332997],[-0.00339897,0.00349644],[-0.0142494,0.0142345],[-0.00447886,0.0041882],[-0.00164011,0.00175226],[-0.00602281,0.00578321],[0.0037796,-0.00390412],[-0.0062485,0.00640502],[-0.000895347,0.000723575],[-0.00439495,0.00432018],[0.00353222,-0.0037258],[0.0050899,-0.00517521]]}}, +{"best":0.0104078,"evaluations":1770,"generation":238,"median":0.500025,"state":{"best":[-0.836418,-1.12195],"population":[[-0.000139748,0.00012094],[0.00437397,-0.00446588],[0.00095332,-0.000990593],[0.0012966,-0.00135539],[-0.000702899,0.000597267],[0.0022633,-0.00233163],[0.00241133,-0.00240969],[0.000367542,-0.000455093],[-0.00129305,0.00119772],[0.00175947,-0.0017904],[0.00201503,-0.00205229],[0.00266822,-0.00269887]]}}, +{"best":0.0104078,"evaluations":1854,"generation":245,"median":0.500006,"state":{"best":[-0.836418,-1.12195],"population":[[-0.000488308,0.0004723],[0.000154733,-0.00018021],[-0.00194052,0.00192484],[-0.000379438,0.000378001],[-0.0013558,0.00135156],[-0.00047958,0.000482645],[0.000165362,-0.000166661],[-0.00103377,0.00103325],[-0.00144581,0.00145153],[-0.00260944,0.00259117],[-0.00100863,0.00100985],[-0.00117054,0.00119227]]}}, +{"best":0.0104078,"evaluations":1926,"generation":251,"median":0.500001,"state":{"best":[-0.836418,-1.12195],"population":[[-0.000114355,0.000112125],[0.00031756,-0.000318758],[0.00022595,-0.000224133],[0.000452492,-0.000450878],[9.75561e-05,-9.72188e-05],[-0.000247063,0.00024705],[0.000445262,-0.000446686],[0.000128518,-0.000131207],[-0.000276085,0.000274118],[-0.000251403,0.000252003],[-6.66546e-05,6.58282e-05],[0.000212049,-0.000209829]]}}, +{"best":0.0104078,"evaluations":2010,"generation":258,"median":0.500001,"state":{"best":[-0.836418,-1.12195],"population":[[0.000635121,-0.000637172],[0.00140541,-0.00140742],[0.00105156,-0.00105324],[0.000595656,-0.000596865],[0.000146274,-0.00014681],[0.000152783,-0.000153405],[0.00124117,-0.00124323],[0.000424807,-0.00042547],[0.000835916,-0.000837991],[0.000556777,-0.000558868],[-0.000313085,0.000312926],[0.00120223,-0.00120311]]}}, +{"best":0.0104078,"evaluations":2094,"generation":265,"median":0.5,"state":{"best":[-0.836418,-1.12195],"population":[[0.000419148,-0.000419295],[-1.1402e-05,1.12829e-05],[0.000106759,-0.000106796],[0.000113478,-0.000113593],[9.51399e-05,-9.51529e-05],[-8.02655e-05,8.05171e-05],[-4.55011e-05,4.52056e-05],[-0.000253217,0.000253112],[3.59685e-05,-3.61084e-05],[0.000251338,-0.000251196],[8.4002e-05,-8.4086e-05],[2.01036e-05,-2.02093e-05]]}}, +{"best":0.0104078,"evaluations":2166,"generation":271,"median":0.5,"state":{"best":[-0.836418,-1.12195],"population":[[0.000138044,-0.000138083],[0.000147813,-0.000147882],[0.000234763,-0.000234925],[0.000165492,-0.000165551],[4.24371e-05,-4.24244e-05],[0.000174386,-0.000174494],[9.01266e-05,-9.01196e-05],[0.000136427,-0.000136483],[0.000277961,-0.000278101],[0.000260706,-0.000260812],[0.00023144,-0.000231557],[0.000149386,-0.00014949]]}}, +{"best":0.0104078,"evaluations":2250,"generation":278,"median":0.5,"state":{"best":[-0.836418,-1.12195],"population":[[0.000176256,-0.000176316],[0.000171163,-0.000171219],[0.000197094,-0.000197179],[0.000166703,-0.00016676],[0.000212278,-0.000212363],[0.00020216,-0.000202242],[0.000216687,-0.000216777],[0.000187405,-0.000187473],[0.000152833,-0.000152885],[0.000154514,-0.000154571],[0.000177109,-0.000177171],[0.000216089,-0.000216177]]}}, +{"best":0.0104078,"evaluations":2322,"generation":284,"median":0.5,"state":{"best":[-0.836418,-1.12195],"population":[[0.000229104,-0.000229209],[0.00021195,-0.000212042],[0.000191697,-0.000191771],[0.000206934,-0.000207022],[0.000223655,-0.000223755],[0.000228783,-0.000228885],[0.000200885,-0.000200967],[0.000213425,-0.000213517],[0.00021148,-0.000211571],[0.000194762,-0.00019484],[0.000216101,-0.000216196],[0.000205679,-0.000205763]]}}, +{"best":0.0104078,"evaluations":2406,"generation":291,"median":0.5,"state":{"best":[-0.836418,-1.12195],"population":[[0.000197491,-0.000197569],[0.00019471,-0.000194786],[0.000190836,-0.000190909],[0.00020732,-0.000207407],[0.000204353,-0.000204437],[0.000207273,-0.000207358],[0.000200176,-0.000200257],[0.00020084,-0.000200921],[0.000189677,-0.000189749],[0.000200313,-0.000200394],[0.000210493,-0.000210582],[0.000208958,-0.000209046]]}}, +{"best":0.0104078,"evaluations":2490,"generation":298,"median":0.5,"state":{"best":[-0.836418,-1.12195],"population":[[0.000206308,-0.000206393],[0.000206428,-0.000206513],[0.000205405,-0.000205489],[0.000204505,-0.000204589],[0.000202559,-0.000202641],[0.000207015,-0.000207101],[0.000204646,-0.00020473],[0.000207438,-0.000207524],[0.000205211,-0.000205295],[0.000204333,-0.000204416],[0.00020377,-0.000203853],[0.000203967,-0.000204051]]}}, +{"best":0.0104078,"evaluations":2562,"generation":304,"median":0.5,"state":{"best":[-0.836418,-1.12195],"population":[[0.000209098,-0.000209185],[0.000209166,-0.000209254],[0.000208325,-0.000208411],[0.000208272,-0.000208359],[0.000209491,-0.000209579],[0.000209815,-0.000209903],[0.00020816,-0.000208247],[0.000208352,-0.000208439],[0.000207734,-0.00020782],[0.000209598,-0.000209686],[0.000207805,-0.000207892],[0.00020779,-0.000207876]]}}, +{"best":0.0104078,"evaluations":2646,"generation":311,"median":0.5,"state":{"best":[-0.836418,-1.12195],"population":[[0.000208868,-0.000208955],[0.000208845,-0.000208932],[0.000209739,-0.000209827],[0.000209767,-0.000209855],[0.000209206,-0.000209293],[0.000209446,-0.000209534],[0.000208953,-0.00020904],[0.000208736,-0.000208823],[0.000210555,-0.000210644],[0.000209585,-0.000209673],[0.000209742,-0.00020983],[0.000208909,-0.000208997]]}}, +{"best":0.0104078,"evaluations":2730,"generation":318,"median":0.5,"state":{"best":[-0.836418,-1.12195],"population":[[0.000209377,-0.000209465],[0.00020977,-0.000209858],[0.000209365,-0.000209453],[0.000210049,-0.000210137],[0.000209447,-0.000209535],[0.000209512,-0.0002096],[0.000209832,-0.00020992],[0.000209647,-0.000209735],[0.000209626,-0.000209714],[0.000209612,-0.0002097],[0.00020973,-0.000209818],[0.000209627,-0.000209715]]}}, +{"best":0.0104078,"evaluations":2802,"generation":324,"median":0.5,"state":{"best":[-0.836418,-1.12195],"population":[[0.000210401,-0.000210489],[0.000210106,-0.000210195],[0.000210567,-0.000210656],[0.000210015,-0.000210104],[0.000210201,-0.000210289],[0.000210229,-0.000210317],[0.00021044,-0.000210529],[0.000210211,-0.000210299],[0.000210197,-0.000210286],[0.000210442,-0.000210531],[0.000209705,-0.000209793],[0.000210358,-0.000210446]]}}, +{"best":0.0104078,"evaluations":2886,"generation":331,"median":0.5,"state":{"best":[-0.836418,-1.12195],"population":[[0.000210434,-0.000210523],[0.000210321,-0.000210409],[0.00021035,-0.000210439],[0.000210367,-0.000210456],[0.000210347,-0.000210435],[0.000210327,-0.000210415],[0.000210401,-0.00021049],[0.000210389,-0.000210478],[0.000210347,-0.000210436],[0.000210308,-0.000210396],[0.000210453,-0.000210542],[0.000210325,-0.000210414]]}}, +{"best":0.0104078,"evaluations":2958,"generation":337,"median":0.5,"state":{"best":[-0.836418,-1.12195],"population":[[0.000210364,-0.000210452],[0.000210368,-0.000210456],[0.000210359,-0.000210447],[0.000210365,-0.000210454],[0.000210357,-0.000210446],[0.000210366,-0.000210454],[0.000210365,-0.000210453],[0.000210351,-0.00021044],[0.000210366,-0.000210455],[0.000210357,-0.000210445],[0.000210369,-0.000210458],[0.000210369,-0.000210457]]}}, +{"best":0.0104078,"evaluations":3114,"generation":344,"median":2.76518,"state":{"best":[-0.836418,-1.12195],"population":[[-1.33318,-1.09558],[1.25352,-0.292187],[0.0468936,0.556887],[-0.269868,-1.16704],[-0.734718,-1.53197],[-1.40033,-2.26727],[0.481066,-0.153502],[0.174499,0.543395],[2.42174,2.1925],[0.356219,-0.77597],[0.327919,-0.549114],[-1.70851,0.0130322],[1.11179,1.22614],[-1.49598,1.02095],[1.44996,-1.47484],[-1.94663,-0.938488],[3.08435,1.10723],[1.26463,-2.26571],[-1.18543,1.83741],[0.576996,-0.0163789],[0.258304,0.82588],[-2.16787,-1.31367],[1.15696,-1.92946],[0.803684,-1.15684]]}}, +{"best":0.0104078,"evaluations":3282,"generation":351,"median":0.686358,"state":{"best":[-0.836418,-1.12195],"population":[[-0.374502,-0.0614328],[-0.110203,-0.028739],[-0.212396,-0.0637798],[0.272109,-0.169022],[-0.249624,0.185351],[-0.195612,0.0551587],[-0.166038,0.177888],[0.521062,-0.430015],[-0.605402,-0.113268],[-0.364039,-0.189976],[-0.0706327,-0.256174],[-0.436394,0.398468],[-0.426272,0.368133],[-0.242084,-0.0998964],[-0.420541,0.196697],[0.162003,-0.302777],[-0.543571,-0.0616755],[-0.0389199,-0.32286],[-0.330187,0.0138264],[-0.10475,0.00396817],[-0.183946,-0.389373],[-0.631655,-0.0261221],[-0.803977,0.290458],[-0.907065,0.208973]]}}, +{"best":0.0104078,"evaluations":3426,"generation":357,"median":0.595603,"state":{"best":[-0.836418,-1.12195],"population":[[-0.388336,0.177163],[-0.836233,0.457928],[-0.137258,-0.0483094],[-0.697582,0.31311],[0.204315,-0.0763087],[-0.498021,0.275868],[0.145959,-0.169685],[-0.45989,0.159049],[-0.978234,0.53383],[-0.713162,0.425849],[0.126154,-0.209054],[-0.405903,0.299477],[-0.324166,0.184457],[-0.212426,0.0816275],[-0.0349212,-0.0843556],[0.540673,-0.333093],[-0.0952365,-0.0329585],[-0.37865,0.168366],[-0.0507562,0.0976726],[0.329089,-0.133022],[-0.834088,0.471351],[-0.0285506,0.109948],[-0.362011,0.179943],[-0.275573,0.104577]]}}, +{"best":0.0104078,"evaluations":3594,"generation":364,"median":0.535935,"state":{"best":[-0.836418,-1.12195],"population":[[-0.0111865,-0.0195506],[0.207726,-0.141486],[-0.0834848,0.0279294],[-0.176771,0.0919377],[-0.164015,0.163735],[-0.177573,0.096056],[0.135825,-0.113497],[0.258667,-0.303829],[0.217282,-0.248334],[-0.125558,0.0716926],[-0.141904,0.0807777],[0.0170848,0.000357746],[-0.263548,0.167223],[-0.0944399,0.0457819],[-0.249075,0.195485],[-0.0644545,0.06591],[0.195378,-0.269708],[0.00217917,-0.0262968],[-0.114231,0.115546],[-0.151063,0.084486],[0.1372,-0.12936],[0.10465,-0.0355578],[0.0320229,-0.104462],[-0.307065,0.16558]]}}, +{"best":0.0104078,"evaluations":3762,"generation":371,"median":0.50817,"state":{"best":[-0.836418,-1.12195],"population":[[-0.0364941,0.013016],[0.0349814,-0.0565899],[0.0321165,-0.040846],[0.0575039,-0.0780273],[0.038,-0.0599084],[0.0301257,-0.046249],[0.0630602,-0.0691948],[0.0849443,-0.0783007],[-0.0326147,0.0363411],[-0.0134829,0.0066812],[-0.0269886,0.0182506],[-0.0101285,0.000470946],[0.132287,-0.135098],[0.00359939,-0.0119391],[0.101327,-0.116486],[-0.0728153,0.05976],[0.00335919,-0.00966111],[-0.0129442,-0.00669101],[-0.0923671,0.0828331],[-0.0565026,0.0353369],[0.153235,-0.15199],[-0.0122456,-0.00202283],[0.00872071,-0.00510463],[0.0144183,-0.0295689]]}}, +{"best":0.0104078,"evaluations":3906,"generation":377,"median":0.501048,"state":{"best":[-0.836418,-1.12195],"population":[[-0.00651446,0.00821052],[0.0102059,-0.0130792],[0.00789926,-0.0062378],[-0.00846948,0.00747187],[-0.00664995,0.00388734],[-0.00256409,0.00114269],[-0.00430692,0.0041742],[0.013707,-0.0102399],[-0.0170865,0.0149158],[0.0187899,-0.0210621],[0.00405713,-0.00603764],[0.0252885,-0.0261305],[0.0265336,-0.0251095],[0.0061476,-0.00691232],[0.00453571,-0.009011],[-0.019726,0.0182751],[-0.00088093,0.000592117],[-0.00454122,-0.00104201],[-0.0146986,0.0143355],[-0.00218025,-5.07588e-06],[-0.000178194,-0.000195746],[-0.00312077,0.00173389],[0.00689747,-0.007573],[-0.00242397,0.00393387]]}}, +{"best":0.0104078,"evaluations":4074,"generation":384,"median":0.500069,"state":{"best":[-0.836418,-1.12195],"population":[[0.00191459,-0.00197757],[0.00431092,-0.00434949],[-0.00409371,0.00391453],[0.000994958,-0.000880678],[-0.0025028,0.00247488],[0.00362412,-0.00357869],[-0.00303893,0.00293236],[-0.00184798,0.00176678],[-0.00309236,0.00309501],[-0.00155205,0.00150899],[-0.00432533,0.00469152],[0.00234523,-0.00250768],[-0.000369452,0.000598994],[0.00380712,-0.00406689],[-0.00132657,0.00105251],[-0.00326774,0.00331416],[-5.2806e-05,6.2092e-05],[-0.000289229,0.000118819],[0.000462846,-0.000281687],[0.000912728,-0.000844914],[-0.00425416,0.00407015],[-0.000974409,0.000925297],[-0.0060183,0.00609269],[0.00250786,-0.00255891]]}}, +{"best":0.0104078,"evaluations":4218,"generation":390,"median":0.50001,"state":{"best":[-0.836418,-1.12195],"population":[[-0.000885288,0.000872435],[-0.00148219,0.00147776],[-0.00219761,0.00216794],[0.00105314,-0.00103973],[-0.000863943,0.000838365],[0.000886391,-0.000884188],[-0.00252763,0.00249594],[0.00131385,-0.0013064],[-0.000895729,0.000888813],[-0.00255062,0.00254682],[-0.000595455,0.000601283],[-0.000180127,0.00015912],[0.000247828,-0.000251702],[-0.0015707,0.00155924],[0.000670011,-0.000663856],[-0.00135304,0.00133775],[0.000116388,-0.00011631],[0.00109241,-0.00108571],[-0.000978856,0.000972801],[0.0014805,-0.00150254],[0.000373593,-0.000345453],[0.00130617,-0.00127163],[-0.00102541,0.0010166],[-0.0035828,0.00356366]]}}, +{"best":0.0104078,"evaluations":4386,"generation":397,"median":0.500001,"state":{"best":[-0.836418,-1.12195],"population":[[-0.000843181,0.000841176],[-5.46515e-05,5.2329e-05],[0.000423909,-0.000422828],[0.000773168,-0.000770059],[7.69353e-05,-7.76778e-05],[-0.000720353,0.00071858],[-0.000304614,0.000303215],[0.000421036,-0.000419631],[-0.00059108,0.00058737],[0.000290606,-0.000290502],[0.000143323,-0.00014039],[-0.00126079,0.00125573],[-0.000603957,0.00060197],[0.000289499,-0.000288831],[-0.000400936,0.000398593],[0.000558274,-0.000555655],[-0.000419127,0.000418994],[-4.7159e-05,4.80741e-05],[-0.00117146,0.00116579],[-0.00051009,0.000507938],[-0.000594809,0.000594165],[-0.000280012,0.00027963],[-0.000503222,0.000499904],[0.000275039,-0.000274179]]}}, +{"best":0.0104078,"evaluations":4554,"generation":404,"median":0.5,"state":{"best":[-0.836418,-1.12195],"population":[[-0.00025494,0.000254706],[2.48097e-05,-2.47905e-05],[-5.3337e-05,5.31876e-05],[-6.36961e-05,6.37642e-05],[-0.000187467,0.000186961],[1.77745e-06,-1.74361e-06],[-0.000363372,0.000362906],[-4.47059e-05,4.4646e-05],[0.000266778,-0.000266602],[-0.00031482,0.000314382],[-0.000143009,0.000142709],[-0.000302998,0.000302595],[-0.00015858,0.0001586],[-0.000316503,0.000316365],[-0.000345574,0.000345325],[-0.000338963,0.00033852],[-0.000360738,0.000360526],[9.21225e-05,-9.21498e-05],[-7.59525e-05,7.61254e-05],[-0.000245398,0.000245128],[-0.000203871,0.000203564],[-0.00014243,0.000142585],[-0.000126594,0.000126301],[-0.000177973,0.00017773]]}}, +{"best":0.0104078,"evaluations":4698,"generation":410,"median":0.5,"state":{"best":[-0.836418,-1.12195],"population":[[-6.60532e-05,6.60291e-05],[-8.94937e-05,8.94557e-05],[-0.000106611,0.000106561],[3.02876e-05,-3.02282e-05],[-0.000134301,0.000134223],[-7.30343e-05,7.2973e-05],[-3.28372e-05,3.28364e-05],[-0.000126568,0.000126465],[-5.21115e-05,5.20823e-05],[-2.63658e-05,2.63459e-05],[-3.29835e-05,3.29789e-05],[-0.000107465,0.000107404],[3.02799e-05,-3.02209e-05],[-9.24403e-05,9.24279e-05],[-0.000103947,0.000103881],[-0.00011479,0.00011476],[4.56824e-05,-4.55882e-05],[-0.000180367,0.000180291],[-0.000121279,0.000121233],[-0.000165133,0.000165059],[-0.000139181,0.000139098],[-9.00904e-05,9.00806e-05],[-6.20619e-05,6.20399e-05],[-0.000134889,0.000134853]]}}, +{"best":0.0104078,"evaluations":4866,"generation":417,"median":0.5,"state":{"best":[-0.836418,-1.12195],"population":[[-0.000109613,0.000109585],[-0.000115197,0.000115163],[-0.000137267,0.000137228],[-9.80383e-05,9.80082e-05],[-8.87804e-05,8.87609e-05],[-0.000116505,0.000116474],[-8.98501e-05,8.98291e-05],[-0.000113481,0.000113452],[-9.56883e-05,9.56651e-05],[-0.000126487,0.000126455],[-0.000203498,0.000203435],[-0.000134315,0.000134279],[-6.66962e-05,6.66831e-05],[-0.00011242,0.000112397],[-8.50785e-05,8.50594e-05],[-0.000124791,0.000124757],[-4.95114e-05,4.9511e-05],[-9.25266e-05,9.25083e-05],[-0.000123802,0.000123768],[-0.000119186,0.000119157],[-0.000114922,0.000114894],[-0.000105566,0.000105541],[-7.28156e-05,7.28056e-05],[-7.713e-05,7.71102e-05]]}}, +{"best":0.0104078,"evaluations":5010,"generation":423,"median":0.5,"state":{"best":[-0.836418,-1.12195],"population":[[-0.000128826,0.000128792],[-0.000111204,0.000111179],[-0.000141569,0.00014153],[-0.000108785,0.000108759],[-0.000118304,0.000118276],[-0.00011045,0.000110427],[-0.000124803,0.000124772],[-0.000148735,0.000148691],[-0.000113167,0.000113141],[-0.00011047,0.000110445],[-0.000114598,0.000114572],[-9.74801e-05,9.7461e-05],[-0.000131188,0.000131156],[-0.000128805,0.000128773],[-0.000125265,0.000125234],[-0.000126546,0.000126513],[-0.000114096,0.000114069],[-0.000129808,0.000129774],[-0.000121368,0.000121341],[-9.54221e-05,9.5403e-05],[-0.000126759,0.000126726],[-8.62742e-05,8.62606e-05],[-9.3764e-05,9.3748e-05],[-0.000129351,0.000129319]]}}, +{"best":0.0104078,"evaluations":5178,"generation":430,"median":0.5,"state":{"best":[-0.836418,-1.12195],"population":[[-0.000124234,0.000124203],[-0.000132357,0.000132322],[-0.000125853,0.000125821],[-0.000121572,0.000121542],[-0.000131705,0.000131671],[-0.000130593,0.000130558],[-0.000132756,0.000132721],[-0.000133155,0.000133119],[-0.000129907,0.000129873],[-0.00013663,0.000136593],[-0.000131745,0.00013171],[-0.000123091,0.000123061],[-0.000126894,0.000126861],[-0.000120162,0.000120134],[-0.000124204,0.000124173],[-0.000124406,0.000124375],[-0.000128895,0.000128862],[-0.000131287,0.000131253],[-0.000131472,0.000131437],[-0.000129172,0.000129138],[-0.000129343,0.00012931],[-0.000129783,0.00012975],[-0.000132178,0.000132144],[-0.000133601,0.000133565]]}}, +{"best":0.0104078,"evaluations":5346,"generation":437,"median":0.5,"state":{"best":[-0.836418,-1.12195],"population":[[-0.000131888,0.000131853],[-0.00013186,0.000131826],[-0.00013372,0.000133684],[-0.000131505,0.00013147],[-0.000132363,0.000132328],[-0.000129338,0.000129305],[-0.000134227,0.000134191],[-0.000131657,0.000131622],[-0.000131364,0.00013133],[-0.000133675,0.000133639],[-0.000132654,0.000132619],[-0.000133386,0.00013335],[-0.000133625,0.000133589],[-0.000131333,0.000131298],[-0.000134397,0.000134361],[-0.000132282,0.000132247],[-0.000130701,0.000130667],[-0.00013302,0.000132985],[-0.000131637,0.000131603],[-0.00013398,0.000133945],[-0.000133086,0.00013305],[-0.000133651,0.000133616],[-0.000134351,0.000134315],[-0.000131072,0.000131038]]}}, +{"best":0.0104078,"evaluations":5490,"generation":443,"median":0.5,"state":{"best":[-0.836418,-1.12195],"population":[[-0.000132832,0.000132797],[-0.000133558,0.000133522],[-0.000134359,0.000134322],[-0.000132721,0.000132685],[-0.000133522,0.000133486],[-0.000133191,0.000133156],[-0.000133965,0.000133929],[-0.000133193,0.000133157],[-0.000134363,0.000134327],[-0.000132828,0.000132793],[-0.000132604,0.000132569],[-0.000133657,0.000133621],[-0.00013386,0.000133824],[-0.000133086,0.000133051],[-0.000132706,0.000132671],[-0.000133723,0.000133687],[-0.000133008,0.000132973],[-0.000132954,0.000132919],[-0.000134155,0.000134119],[-0.0001329,0.000132865],[-0.000134199,0.000134163],[-0.000133537,0.000133501],[-0.000133301,0.000133266],[-0.000134155,0.000134119]]}}, +{"best":0.0104078,"evaluations":5658,"generation":450,"median":0.5,"state":{"best":[-0.836418,-1.12195],"population":[[-0.000134182,0.000134146],[-0.000134226,0.00013419],[-0.000133479,0.000133443],[-0.000134151,0.000134115],[-0.000134055,0.000134019],[-0.00013415,0.000134114],[-0.000133782,0.000133746],[-0.000134177,0.000134141],[-0.00013395,0.000133914],[-0.000133978,0.000133942],[-0.000134175,0.000134139],[-0.000133823,0.000133787],[-0.000134224,0.000134188],[-0.000133595,0.000133559],[-0.000134096,0.00013406],[-0.000133621,0.000133585],[-0.000133839,0.000133803],[-0.000133983,0.000133947],[-0.00013433,0.000134293],[-0.000134002,0.000133966],[-0.000133788,0.000133752],[-0.000133565,0.00013353],[-0.000133609,0.000133573],[-0.000134069,0.000134034]]}}, +{"best":0.0104078,"evaluations":5826,"generation":457,"median":0.5,"state":{"best":[-0.836418,-1.12195],"population":[[-0.000134363,0.000134327],[-0.000134586,0.00013455],[-0.000134272,0.000134236],[-0.000134112,0.000134076],[-0.000134109,0.000134073],[-0.00013425,0.000134214],[-0.000134092,0.000134056],[-0.000134233,0.000134197],[-0.000134222,0.000134186],[-0.000134311,0.000134275],[-0.000134269,0.000134233],[-0.000134118,0.000134082],[-0.0001341,0.000134064],[-0.000134364,0.000134327],[-0.000134073,0.000134037],[-0.000134264,0.000134228],[-0.000134283,0.000134247],[-0.000134369,0.000134333],[-0.000134079,0.000134043],[-0.000134321,0.000134285],[-0.000134133,0.000134097],[-0.000134348,0.000134312],[-0.000134145,0.000134109],[-0.000134271,0.000134235]]}}, +{"best":0.0104078,"evaluations":5970,"generation":463,"median":0.5,"state":{"best":[-0.836418,-1.12195],"population":[[-0.000134442,0.000134406],[-0.000134411,0.000134375],[-0.000134436,0.0001344],[-0.000134324,0.000134288],[-0.000134348,0.000134312],[-0.000134495,0.000134458],[-0.000134365,0.000134328],[-0.000134393,0.000134357],[-0.000134443,0.000134407],[-0.000134326,0.000134289],[-0.000134395,0.000134359],[-0.000134347,0.000134311],[-0.000134392,0.000134356],[-0.000134457,0.000134421],[-0.00013435,0.000134314],[-0.000134365,0.000134329],[-0.000134355,0.000134319],[-0.000134429,0.000134393],[-0.00013444,0.000134404],[-0.000134478,0.000134442],[-0.000134409,0.000134373],[-0.000134311,0.000134275],[-0.000134428,0.000134392],[-0.000134374,0.000134337]]}}, +{"best":0.0104078,"evaluations":6234,"generation":470,"median":3.59736,"state":{"best":[-0.836418,-1.12195],"population":[[-2.91758,-2.14313],[0.701878,-1.18405],[1.93463,0.463255],[-1.75902,-0.0053622],[-2.75483,-3.76304],[0.928259,1.89064],[-2.48639,-3.54903],[0.146016,-0.204974],[1.04844,1.90526],[-1.4401,0.169075],[0.603987,0.11051],[-1.92616,0.564853],[-1.15256,0.273568],[1.25791,0.549208],[-3.51522,-1.93835],[-0.308424,-0.258364],[-0.226907,-0.480163],[-3.10736,-4.19271],[-1.35714,-2.2946],[-0.531056,2.05213],[1.82281,0.974071],[0.669628,0.762152],[-1.00772,-0.0826891],[-2.27544,-0.367288],[-1.16187,0.60323],[-0.569073,-2.38249],[2.33388,1.9969],[0.0372848,0.0656617],[-0.229421,-0.433024],[-0.508088,-0.161311],[-1.04853,0.211468],[-1.69905,0.771013],[-0.900782,-0.0926322],[-1.70596,-0.578174],[3.37019,0.769097],[-1.9234,0.738795],[-0.789693,1.88711],[0.624827,0.948771],[-2.15988,-1.34444],[0.419246,-1.48521],[-0.805701,0.357489],[0.988546,1.70027],[-0.119403,0.14251],[-2.41198,1.17728],[-1.30403,0.259142],[0.849983,-2.56379],[2.43014,-0.58153],[-1.48287,-0.0724747]]}}, +{"best":0.0104078,"evaluations":6522,"generation":476,"median":0.92723,"state":{"best":[-0.836418,-1.12195],"population":[[0.674589,0.979519],[-0.471378,-0.871],[-0.535474,-0.605832],[0.0433006,-1.15147],[-0.471463,-0.338533],[-1.25932,-1.23921],[-0.486443,-1.2911],[-0.467465,-0.327009],[-0.575784,-0.444951],[-1.1128,-2.12384],[-0.250088,-0.0859955],[-1.15202,-0.856351],[-1.13174,-0.922893],[-1.36967,-1.54791],[-0.376979,-0.399672],[-1.30047,-0.457597],[0.230518,-0.277368],[0.198012,-0.43422],[-0.663667,-0.848392],[-0.825211,-1.43156],[0.326371,-1.02125],[-1.16075,-1.72198],[-0.944096,-0.63396],[-0.0299051,0.296037],[-0.235807,0.243685],[-0.109432,-0.108864],[0.306151,0.362744],[-0.486356,-0.683375],[0.274321,-0.904642],[-0.455597,-0.331388],[0.081643,-0.00225925],[-0.917858,-0.209587],[-0.497832,-0.572811],[0.182696,0.341357],[-0.129573,-0.816065],[-1.12482,-1.03422],[-0.105379,-0.0303741],[-1.19687,-0.511336],[-0.428491,-0.33297],[0.323161,0.208864],[0.409919,0.631942],[-0.140953,0.0463591],[0.275983,0.155759],[0.460676,-0.0963108],[-1.57505,-2.01327],[-0.404722,-0.181816],[0.130685,-0.162341],[-0.39322,-0.720712]]}}, +{"best":0.0104078,"evaluations":6858,"generation":483,"median":0.882122,"state":{"best":[-0.836418,-1.12195],"population":[[-0.203016,-0.901784],[0.0691519,0.369333],[-0.129804,-0.311803],[-0.0580652,-0.390955],[0.0914547,-0.671726],[-0.244876,-0.676938],[0.22703,-0.891561],[0.177942,-0.883241],[-0.275821,-0.0681203],[0.198984,0.165212],[-0.100017,-0.756288],[-0.09126,-0.552624],[0.338041,-0.435264],[-0.0937941,-1.36006],[-0.244321,-0.91053],[0.424852,-0.226452],[-0.173034,-0.45284],[-0.0899312,-0.971325],[-0.435647,-0.527885],[-0.113673,-1.20526],[-0.227324,-1.02748],[-0.688752,-0.718704],[-0.0799069,-1.08028],[0.194303,-1.43686],[0.368474,-0.567292],[-0.083482,-1.21815],[-0.24596,-0.0671292],[0.0748732,-0.552457],[-0.103304,-1.02494],[-0.376789,-0.505005],[-0.342392,-0.740735],[0.48897,0.0453449],[-0.549044,-0.716647],[0.228623,-0.664834],[-0.173221,-0.888206],[-0.40142,-0.357233],[-0.477203,-0.635458],[0.573163,-0.68386],[0.361213,0.00499303],[-0.233183,-0.998938],[0.57517,-0.214126],[-0.2948,-0.496012],[-0.0123715,-0.741792],[-0.625935,-0.745965],[-0.155173,-0.75835],[0.348218,-0.456889],[0.455763,-0.947023],[-0.74986,-1.78477]]}}, +{"best":0.0104078,"evaluations":7194,"generation":490,"median":0.618696,"state":{"best":[-0.836418,-1.12195],"population":[[0.273114,-0.687587],[0.0677213,-0.925583],[0.131492,-0.379484],[0.249689,-0.619801],[0.31055,-0.629293],[0.136461,-1.08454],[0.16915,-0.89866],[0.0304123,-0.651594],[0.100638,-0.877234],[0.141638,-0.906],[0.0292185,-0.983237],[0.0966956,-0.55997],[0.170509,-0.761195],[0.137321,-0.624616],[0.214689,-0.539487],[0.121542,-0.461291],[0.266434,-0.293612],[0.295902,-0.190116],[0.0990666,-0.770544],[0.16882,-0.50352],[0.133087,-0.761344],[0.203416,-0.698924],[0.155272,-0.385842],[0.237117,-1.07264],[0.322522,-0.573621],[0.222988,-0.365897],[0.0107498,-1.05117],[-0.0184626,-0.409392],[0.0976407,-0.777209],[0.113053,-0.461263],[0.0850412,-0.746635],[0.186011,-0.252236],[0.373157,-0.312914],[-0.0301609,-1.08856],[0.162295,-0.836487],[0.12833,-0.491476],[0.207594,-0.273406],[0.198822,-0.853356],[0.0889591,-0.905271],[0.129696,-0.781758],[0.188394,-0.614114],[0.0761095,-0.998435],[0.203849,-0.503145],[0.141728,-0.745591],[0.0773829,-0.44787],[0.134119,-0.718709],[0.196787,-0.70563],[0.169756,-0.367242]]}}, +{"best":0.0104078,"evaluations":7482,"generation":496,"median":0.482315,"state":{"best":[-0.836418,-1.12195],"population":[[0.153436,-0.737435],[0.127974,-0.761435],[0.130579,-0.800887],[0.14091,-0.748905],[0.18483,-0.619811],[0.102942,-0.873786],[0.146348,-0.852374],[0.0817527,-0.941301],[0.174899,-0.663097],[0.144993,-0.811346],[0.158988,-0.730136],[0.198006,-0.627819],[0.113759,-0.876266],[0.156354,-0.710266],[0.174344,-0.709133],[0.180717,-0.690672],[0.163122,-0.738096],[0.108795,-0.875495],[0.150166,-0.780259],[0.151611,-0.769621],[0.225776,-0.55041],[0.126282,-0.878744],[0.107904,-0.901028],[0.161177,-0.729672],[0.187038,-0.67821],[0.135356,-0.782271],[0.117374,-0.842598],[0.117113,-0.779298],[0.149259,-0.763896],[0.127726,-0.87459],[0.148487,-0.766787],[0.120609,-0.897764],[0.168757,-0.688333],[0.180184,-0.659932],[0.119769,-0.825245],[0.144875,-0.693311],[0.200841,-0.574219],[0.126581,-0.826954],[0.161237,-0.730978],[0.161094,-0.711863],[0.17025,-0.692769],[0.155634,-0.786565],[0.179398,-0.636685],[0.136193,-0.845443],[0.151823,-0.759478],[0.123952,-0.864278],[0.176479,-0.650624],[0.198827,-0.549235]]}}, +{"best":0.0104078,"evaluations":7818,"generation":503,"median":0.350814,"state":{"best":[-0.836418,-1.12195],"population":[[0.124752,-0.831345],[0.123069,-0.83625],[0.138237,-0.80269],[0.11879,-0.844249],[0.126204,-0.829607],[0.12607,-0.827602],[0.123652,-0.833654],[0.137631,-0.805277],[0.130432,-0.818133],[0.124924,-0.832644],[0.126463,-0.827193],[0.1221,-0.835439],[0.124858,-0.829772],[0.12162,-0.837733],[0.121823,-0.836555],[0.130055,-0.820856],[0.120387,-0.839876],[0.132967,-0.813223],[0.124153,-0.832709],[0.137013,-0.807823],[0.119944,-0.841441],[0.120904,-0.838715],[0.128641,-0.823473],[0.129825,-0.822068],[0.130415,-0.82031],[0.126135,-0.828114],[0.12876,-0.825211],[0.129714,-0.820421],[0.117031,-0.846244],[0.134036,-0.812217],[0.129104,-0.822348],[0.129865,-0.821716],[0.122702,-0.836674],[0.128941,-0.821078],[0.136559,-0.808515],[0.125902,-0.828114],[0.122938,-0.834658],[0.142619,-0.795757],[0.131819,-0.817241],[0.130133,-0.818753],[0.123594,-0.83309],[0.117846,-0.845978],[0.131346,-0.816651],[0.130553,-0.81942],[0.13243,-0.815202],[0.124552,-0.831185],[0.135735,-0.809932],[0.11706,-0.845398]]}}, +{"best":0.0104078,"evaluations":8106,"generation":509,"median":0.326853,"state":{"best":[-0.836418,-1.12195],"population":[[0.122665,-0.835125],[0.12107,-0.83814],[0.122036,-0.836226],[0.122573,-0.835212],[0.121348,-0.837542],[0.120753,-0.838663],[0.121441,-0.837314],[0.12124,-0.837759],[0.120676,-0.83876],[0.12359,-0.833354],[0.121596,-0.837091],[0.12149,-0.837219],[0.121392,-0.837422],[0.122208,-0.835893],[0.123017,-0.834433],[0.122327,-0.835733],[0.12216,-0.836103],[0.121254,-0.83765],[0.122223,-0.835826],[0.123307,-0.833821],[0.121437,-0.837306],[0.122681,-0.835105],[0.121562,-0.83714],[0.121021,-0.838283],[0.120204,-0.839635],[0.121969,-0.836374],[0.120635,-0.838872],[0.122069,-0.836248],[0.1219,-0.836562],[0.121506,-0.837229],[0.123363,-0.833756],[0.122881,-0.834717],[0.121159,-0.837866],[0.122914,-0.834618],[0.122735,-0.834924],[0.122173,-0.83603],[0.120415,-0.839312],[0.11991,-0.840228],[0.121702,-0.836795],[0.120872,-0.838462],[0.120438,-0.839215],[0.119859,-0.840272],[0.120947,-0.838226],[0.12266,-0.835079],[0.124237,-0.832152],[0.120344,-0.839392],[0.120138,-0.839799],[0.12165,-0.836951]]}}, +{"best":0.0104078,"evaluations":8442,"generation":516,"median":0.321204,"state":{"best":[-0.836418,-1.12195],"population":[[0.119297,-0.841289],[0.120404,-0.83926],[0.119585,-0.840757],[0.119902,-0.840179],[0.119745,-0.840462],[0.120036,-0.839931],[0.119878,-0.840221],[0.120073,-0.839866],[0.120108,-0.839803],[0.120426,-0.83922],[0.119514,-0.840885],[0.120032,-0.839942],[0.120068,-0.839873],[0.120249,-0.839548],[0.119921,-0.840143],[0.119846,-0.840281],[0.119637,-0.840662],[0.12086,-0.838428],[0.120378,-0.839308],[0.120148,-0.839729],[0.119257,-0.841356],[0.119892,-0.840196],[0.120042,-0.83992],[0.11983,-0.84031],[0.119402,-0.841091],[0.119835,-0.840303],[0.120004,-0.839991],[0.119971,-0.840052],[0.1201,-0.839816],[0.120203,-0.839628],[0.120391,-0.839283],[0.119555,-0.840813],[0.120092,-0.839831],[0.119474,-0.84096],[0.120363,-0.839334],[0.1195,-0.840911],[0.119923,-0.84014],[0.119935,-0.840116],[0.119886,-0.840206],[0.120206,-0.839622],[0.119528,-0.840861],[0.119798,-0.840372],[0.119417,-0.841065],[0.120352,-0.839359],[0.120983,-0.838204],[0.120134,-0.839755],[0.119586,-0.840751],[0.12036,-0.839341]]}}, +{"best":0.0104078,"evaluations":8778,"generation":523,"median":0.320041,"state":{"best":[-0.836418,-1.12195],"population":[[0.119776,-0.840407],[0.119633,-0.840668],[0.119773,-0.840413],[0.119837,-0.840297],[0.119826,-0.840317],[0.119735,-0.840483],[0.119843,-0.840286],[0.119783,-0.840396],[0.11974,-0.840473],[0.119802,-0.840361],[0.119774,-0.840411],[0.119753,-0.84045],[0.119792,-0.840378],[0.119724,-0.840504],[0.119713,-0.840523],[0.119713,-0.840524],[0.11978,-0.840401],[0.119748,-0.84046],[0.119725,-0.840502],[0.1198,-0.840365],[0.119814,-0.840338],[0.119814,-0.840339],[0.11968,-0.840583],[0.119833,-0.840304],[0.119733,-0.840486],[0.119717,-0.840516],[0.119629,-0.840676],[0.119837,-0.840297],[0.119773,-0.840413],[0.119828,-0.840314],[0.119674,-0.840593],[0.11973,-0.840492],[0.119735,-0.840482],[0.119776,-0.840408],[0.119729,-0.840493],[0.119865,-0.840246],[0.119832,-0.840306],[0.119766,-0.840427],[0.119757,-0.840444],[0.119792,-0.840378],[0.119844,-0.840284],[0.119782,-0.840397],[0.119795,-0.840374],[0.119735,-0.840483],[0.119707,-0.840533],[0.119815,-0.840336],[0.119809,-0.840347],[0.119818,-0.840331]]}}, +{"best":0.0104078,"evaluations":9066,"generation":529,"median":0.319863,"state":{"best":[-0.836418,-1.12195],"population":[[0.11973,-0.840491],[0.119729,-0.840493],[0.119732,-0.840488],[0.119749,-0.840457],[0.119724,-0.840503],[0.119717,-0.840516],[0.119729,-0.840494],[0.119749,-0.840458],[0.119711,-0.840526],[0.119733,-0.840486],[0.119735,-0.840484],[0.119761,-0.840436],[0.119729,-0.840493],[0.119709,-0.84053],[0.119718,-0.840514],[0.119726,-0.840499],[0.119709,-0.84053],[0.119732,-0.840487],[0.11975,-0.840456],[0.119721,-0.840509],[0.119715,-0.840519],[0.119707,-0.840533],[0.119745,-0.840465],[0.119717,-0.840515],[0.119708,-0.840533],[0.119705,-0.840537],[0.119717,-0.840515],[0.119728,-0.840496],[0.119717,-0.840515],[0.119695,-0.840556],[0.119732,-0.840489],[0.119692,-0.84056],[0.119716,-0.840517],[0.119737,-0.840479],[0.11974,-0.840474],[0.119736,-0.840482],[0.119734,-0.840484],[0.119708,-0.840531],[0.119733,-0.840487],[0.119719,-0.840513],[0.11975,-0.840456],[0.119733,-0.840486],[0.11973,-0.840492],[0.119687,-0.84057],[0.119727,-0.840498],[0.119737,-0.840479],[0.119757,-0.840442],[0.119716,-0.840517]]}}, +{"best":0.0104078,"evaluations":9402,"generation":536,"median":0.31981,"state":{"best":[-0.836418,-1.12195],"population":[[0.119716,-0.840518],[0.119719,-0.840512],[0.119719,-0.840511],[0.11972,-0.84051],[0.119716,-0.840518],[0.119718,-0.840514],[0.119718,-0.840514],[0.119718,-0.840514],[0.119715,-0.840518],[0.119715,-0.84052],[0.119718,-0.840513],[0.11972,-0.840511],[0.119723,-0.840505],[0.119719,-0.840512],[0.11972,-0.840511],[0.119717,-0.840516],[0.119719,-0.840513],[0.119718,-0.840514],[0.11972,-0.84051],[0.11972,-0.84051],[0.119719,-0.840513],[0.119719,-0.840513],[0.119714,-0.84052],[0.119717,-0.840515],[0.119715,-0.840519],[0.119722,-0.840506],[0.119714,-0.840521],[0.119712,-0.840524],[0.119713,-0.840523],[0.119718,-0.840514],[0.11972,-0.840511],[0.119716,-0.840517],[0.119719,-0.840512],[0.119721,-0.840508],[0.119718,-0.840513],[0.119717,-0.840516],[0.119717,-0.840516],[0.119717,-0.840515],[0.119719,-0.840511],[0.119717,-0.840516],[0.119722,-0.840506],[0.119721,-0.840508],[0.119719,-0.840513],[0.119721,-0.840508],[0.119719,-0.840511],[0.11972,-0.840511],[0.119719,-0.840511],[0.119716,-0.840518]]}}, +{"best":0.0104078,"evaluations":9738,"generation":543,"median":0.319801,"state":{"best":[-0.836418,-1.12195],"population":[[0.119717,-0.840516],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840518],[0.119716,-0.840517],[0.119717,-0.840515],[0.119717,-0.840515],[0.119716,-0.840517],[0.119717,-0.840515],[0.119716,-0.840517],[0.119717,-0.840516],[0.119717,-0.840516],[0.119716,-0.840517],[0.119717,-0.840516],[0.119716,-0.840517],[0.119716,-0.840517],[0.119717,-0.840516],[0.119717,-0.840516],[0.119717,-0.840516],[0.119715,-0.840518],[0.119716,-0.840517],[0.119716,-0.840518],[0.119716,-0.840518],[0.119717,-0.840516],[0.119717,-0.840516],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840517],[0.119717,-0.840516],[0.119716,-0.840517],[0.119716,-0.840517],[0.119717,-0.840515],[0.119717,-0.840515],[0.119717,-0.840516],[0.119717,-0.840516],[0.119716,-0.840517],[0.119716,-0.840517],[0.119718,-0.840514],[0.119718,-0.840513],[0.119716,-0.840516],[0.119717,-0.840516],[0.119716,-0.840517],[0.119717,-0.840516],[0.119717,-0.840516],[0.119716,-0.840517],[0.119718,-0.840513],[0.119716,-0.840517],[0.119716,-0.840517]]}}, +{"best":0.0104078,"evaluations":10026,"generation":549,"median":0.3198,"state":{"best":[-0.836418,-1.12195],"population":[[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840516],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840517],[0.119716,-0.840517],[0.119717,-0.840516]]}}, +{"best":0.0104078,"evaluations":10506,"generation":556,"median":5.52802,"state":{"best":[-0.836418,-1.12195],"population":[[-0.242032,-1.32883],[-1.009,3.29697],[0.875073,-0.258028],[1.00525,4.59061],[0.272774,1.24157],[0.385191,-1.59495],[1.25062,-2.62618],[1.16552,4.57493],[-2.60907,-0.100706],[-0.444282,1.0061],[0.368075,0.351813],[-0.502133,0.276772],[2.13794,-1.75194],[0.220114,-2.24296],[0.104135,-0.791586],[1.26671,-2.13484],[-1.12008,0.78863],[-1.60905,-0.801823],[-2.24353,-2.85186],[1.7632,0.945309],[0.273618,-1.04647],[-1.14556,2.82458],[0.0750523,-0.392387],[-0.218836,0.766077],[1.16246,-0.503826],[-0.884733,1.43424],[0.559259,-0.51906],[-1.61194,-1.64167],[0.033867,-0.212124],[-0.155856,0.323264],[-2.45879,-0.942289],[-0.680787,-2.08913],[0.903351,-3.18028],[-1.20043,-1.23687],[0.582479,-1.59062],[-1.24622,-4.67671],[-0.86554,0.265919],[-0.11036,-1.58676],[0.28216,-3.78786],[-0.716016,-3.75196],[0.220899,1.82545],[-0.941776,0.534787],[-0.549137,-1.72077],[-1.66024,-0.70426],[1.97274,-2.47717],[0.033119,-2.4713],[0.835415,3.14358],[1.08644,-1.0207],[-0.75688,-4.41301],[1.67605,4.97311],[0.273731,-4.84026],[0.875487,-1.63903],[-2.51574,-2.46357],[-0.558103,-1.56659],[-0.303591,-3.97416],[0.663268,-1.04627],[-0.223844,-4.51793],[1.92789,0.914671],[1.96267,4.23505],[0.566439,-2.31339],[-0.711027,-3.26972],[0.0366102,1.84458],[0.627652,-0.581824],[-0.116289,-0.569254],[-0.236904,-4.39148],[0.0212599,0.995097],[1.42067,-1.40117],[1.39691,1.93076],[0.338417,3.38533],[-1.26745,-4.73218],[-1.46884,-3.80658],[1.2528,1.157],[-1.18404,0.0104646],[-1.51138,0.144775],[0.330788,0.613945],[0.99169,0.164789],[0.42365,1.89392],[0.157173,-0.572019],[1.74272,-3.94057],[0.591472,-1.34008],[-2.82569,4.16002],[1.36434,1.47826],[-1.1383,2.33073],[1.27836,-1.63838],[0.694639,-1.50418],[1.63573,-1.0229],[-0.0987259,3.21993],[1.4144,-3.16256],[-0.865545,3.88778],[1.63954,-1.40053],[-0.383505,3.16675],[-0.350557,2.07238],[0.920225,-2.25141],[-1.17944,-2.76224],[-1.73049,-0.360018],[-2.36933,0.0553351]]}}, +{"best":0.0104078,"evaluations":11082,"generation":562,"median":0.821429,"state":{"best":[-0.836418,-1.12195],"population":[[-0.935375,-0.292388],[-0.858584,0.386501],[-1.00625,-0.0375672],[0.618087,-0.351667],[0.0819831,0.313096],[0.252102,-0.524186],[0.255365,0.193805],[-1.09592,0.571789],[-0.090893,0.174813],[-0.488601,-0.241633],[-1.10466,0.723652],[-0.179586,-0.0780529],[0.188356,-0.414987],[-0.221782,0.0259082],[-0.342533,0.0111645],[0.122605,0.134574],[-0.384609,0.217265],[0.255135,0.214338],[-0.349485,0.097486],[-0.658347,-0.431041],[-0.0502199,-0.170118],[-0.150578,0.0943207],[-0.162707,-0.344221],[-0.438107,-0.186547],[0.832141,-0.372142],[0.0729182,-0.41053],[-0.775486,0.38929],[0.793313,0.176346],[-0.351683,0.0867339],[0.669151,-0.273623],[0.532851,-0.0957466],[0.77014,-0.283834],[-0.157703,-0.565579],[-0.314707,-0.906359],[0.578088,-0.360285],[-0.19651,-0.269971],[-0.709448,0.251426],[-0.249807,0.248619],[-0.460482,-0.331981],[-0.88246,-0.319813],[-0.0494622,-0.149977],[-0.0789629,0.543371],[-0.244323,-0.355022],[-0.845862,-0.187648],[-0.883222,0.115278],[-0.722702,-0.0472231],[-0.0575363,-0.633399],[0.0489343,0.296443],[0.376245,-0.404302],[0.142034,-0.272708],[-0.0563855,0.205006],[-0.245146,-0.308171],[-0.0891533,0.0297021],[-0.578312,0.0622365],[0.373888,-0.540555],[-0.459832,0.166896],[-0.715802,-0.00362551],[-0.166513,-0.173079],[0.0401757,-0.0267797],[-0.756716,-0.595435],[-0.569541,-0.274209],[-0.238312,0.161503],[0.230712,-0.0313443],[0.0270561,-0.302579],[-0.388972,-0.0117036],[-0.793662,-0.211477],[-0.124517,-0.74366],[0.606807,-0.417674],[-0.158729,-0.471267],[0.231028,-0.364239],[-0.0975701,-0.455715],[0.457706,-0.0341128],[-0.867507,0.189425],[-0.478737,-0.548815],[0.00821955,-0.182003],[-1.19285,-0.559963],[-0.57583,0.628063],[-0.996707,0.103528],[0.148098,0.0402129],[-0.473579,-0.259954],[0.420061,-0.362594],[-0.264246,-0.0308033],[-0.602071,-0.392716],[0.524634,-0.439996],[0.037523,0.0981948],[0.382032,-0.40037],[0.237104,-0.477001],[-0.692511,0.0762202],[-1.14483,0.137786],[-0.858686,-0.461722],[-0.237291,0.0186494],[-0.193181,-0.864453],[0.381477,-0.316665],[0.229012,0.030273],[0.181075,0.41678],[0.108115,-0.401393]]}}, +{"best":0.0104078,"evaluations":11754,"generation":569,"median":0.576492,"state":{"best":[-0.836418,-1.12195],"population":[[-0.337418,0.137316],[-0.249283,0.063015],[0.0163908,-0.12157],[-0.311088,0.120399],[-0.257916,0.0442012],[-0.503461,0.0845998],[-0.0911536,0.0822878],[0.210816,-0.157063],[-0.174726,0.0104752],[-0.047442,-0.0202074],[-0.00648869,-0.0114366],[-0.221973,0.0500349],[-0.248933,0.0750202],[-0.286674,0.0563619],[0.273739,-0.154391],[-0.036487,-0.0422018],[-0.0604896,-0.0262849],[-0.44664,0.178966],[0.0914362,-0.0109134],[0.0843978,-0.0795267],[-0.582538,0.222219],[0.17472,-0.0781389],[-0.0184389,-0.0853283],[-0.354921,0.0844879],[-0.260988,0.0323678],[-0.24841,0.113095],[-0.0868938,0.150708],[-0.213529,0.0619806],[-0.438999,0.0976735],[0.0637579,-0.0556994],[-0.0663635,-0.0905136],[-0.459714,0.194851],[0.452153,-0.361862],[-0.127067,0.0726475],[-0.423779,0.129543],[-0.13412,0.0535178],[-0.0406382,0.0659652],[-0.555099,0.227062],[-0.220982,0.0951391],[-0.403484,0.129252],[0.298444,-0.18274],[-0.19632,-0.0268194],[-0.201228,0.0580715],[-0.0242259,-0.0452475],[-0.295725,0.195132],[-0.173028,0.0884953],[-0.199998,0.0412825],[0.0034557,-0.057661],[-0.383182,0.146835],[0.00696332,-0.0648339],[-0.204655,0.00944352],[0.10925,-0.0582085],[-0.119565,-0.0284417],[-0.333107,0.19598],[-0.0962747,0.0762528],[0.0184342,0.0357294],[-0.410736,0.162447],[-0.137019,0.031146],[-0.167236,0.0733876],[0.0471494,-0.0486934],[0.0822458,-0.0977822],[0.011272,0.0916659],[-0.181847,0.0404531],[0.293953,-0.23497],[-0.786309,0.353197],[-0.417663,0.240297],[-0.218725,0.0511861],[-0.480397,0.148127],[-0.3318,0.16989],[-0.308426,0.174615],[-0.530644,0.198921],[-0.0172783,-0.0209988],[-0.386833,0.20067],[-0.38204,0.143155],[-0.709599,0.286442],[-0.168679,-0.0468759],[-0.438951,0.0530824],[-0.285233,0.0837779],[-0.33832,0.160962],[-0.0737895,-0.104874],[-0.268693,0.125018],[-0.353835,0.150454],[0.0420846,-0.0377755],[-0.203645,0.0468809],[0.0552024,-0.0550747],[-0.10795,0.162565],[0.0883746,-0.188241],[-0.475666,0.143483],[-0.344525,0.177605],[-0.00125506,0.00389607],[-0.380964,0.181427],[-0.495853,0.22226],[-0.277292,0.103606],[-0.297317,0.0840395],[0.0132457,-0.0389521],[-0.166991,-0.0238707]]}}, +{"best":0.0104078,"evaluations":12426,"generation":576,"median":0.509909,"state":{"best":[-0.836418,-1.12195],"population":[[-0.0383105,0.0272217],[-0.135536,0.0983385],[-0.0895894,0.0654001],[-0.00752373,0.00689215],[-0.105072,0.0782143],[-0.0403336,0.0295843],[-0.0103536,0.0178061],[-0.209815,0.153025],[-0.0193401,0.030182],[-0.0782489,0.0544765],[-0.055914,0.0528119],[-0.0284583,0.00921193],[-0.0738658,0.0549924],[-0.125949,0.0869737],[0.00346487,-0.0128585],[0.0461062,-0.0356841],[-0.122502,0.0788754],[0.121488,-0.0954317],[-0.013385,0.0123648],[-0.0552694,0.0410724],[-0.0487261,0.043342],[-0.0249551,0.0154032],[0.00473491,-0.0102191],[-0.0880279,0.0568259],[-0.100044,0.0776126],[0.0824469,-0.0653601],[0.0158268,0.0074027],[0.0198688,-0.0178238],[-0.0443659,0.0263214],[-0.0594725,0.0475114],[0.049375,-0.0432594],[-0.0198896,-0.00448426],[-0.0997684,0.0710235],[-0.0784104,0.0583589],[-0.141497,0.0804116],[-0.0944548,0.0719641],[-0.013503,0.00178154],[-0.0194195,0.000560962],[-0.201712,0.165405],[-0.0386819,0.0421832],[-0.0747507,0.0558319],[-0.107308,0.0679585],[0.0269922,-0.0129992],[-0.0831766,0.05473],[-0.146596,0.105299],[-0.153261,0.101921],[-0.247114,0.20262],[-0.0762097,0.0667576],[-0.0786679,0.0521326],[-0.00803854,-0.00770772],[-0.0496304,0.016124],[-0.0416596,0.0215951],[-0.0944505,0.0661424],[0.00228051,-0.00699002],[-0.0483239,0.014884],[-0.167022,0.113428],[-0.0905333,0.0655973],[-0.0557508,0.0301656],[-0.0794068,0.0416102],[0.0598656,-0.0450406],[0.0469351,-0.0384834],[-0.0971392,0.0849278],[-0.10773,0.0820795],[-0.106731,0.0640262],[-0.00259344,-0.0043081],[-0.0183508,0.00556238],[-0.1156,0.103078],[-0.0237135,0.011419],[-0.0308344,0.0317065],[-0.086672,0.0674286],[-0.056748,0.0355497],[-0.00661093,0.00362558],[-0.0310572,0.0196268],[-0.0871761,0.0570211],[0.00665512,-0.00418735],[-0.016552,0.000178035],[-0.114296,0.0802311],[-0.131034,0.113528],[-0.158611,0.123424],[-0.0475909,0.0410718],[-0.0967677,0.0602589],[-0.120267,0.0813084],[0.00437882,2.57262e-05],[-0.0723661,0.0674165],[-0.0101697,0.0159458],[-0.083267,0.0750967],[-0.0784697,0.0718412],[-0.0775199,0.0450049],[-0.0177534,0.0158821],[-0.0244958,0.00835623],[-0.0194076,-0.00747586],[-0.111715,0.0829991],[-0.0631852,0.0553964],[-0.0130761,-0.00554052],[-0.0672949,0.0552512],[-0.00985388,0.0114003]]}}, +{"best":0.0104078,"evaluations":13002,"generation":582,"median":0.501071,"state":{"best":[-0.836418,-1.12195],"population":[[0.00570448,-0.00737771],[-0.0175843,0.0155381],[-0.0491988,0.0439022],[-0.0100831,0.0111886],[0.00663361,-0.00628181],[-0.00253063,0.00174205],[-0.01169,0.0108237],[-0.0118197,0.00960936],[-0.0128123,0.0135739],[-0.00178056,0.00119087],[0.0070815,-0.00729525],[-0.0258526,0.0238799],[-0.0225199,0.0202151],[-0.015398,0.0132842],[-0.0317648,0.0281619],[-0.0189574,0.0167136],[-0.00134576,0.00236884],[-0.0371373,0.0354761],[-0.0190946,0.0175564],[-0.0496144,0.0471257],[-0.0102976,0.0085355],[-0.00551568,0.00584291],[0.00126459,-0.0027972],[-0.0062566,0.00685579],[0.000393761,-0.00332412],[-0.0348855,0.0318657],[-0.0237545,0.0204965],[-0.0164192,0.015182],[-0.00981633,0.00895022],[0.0198794,-0.0188493],[-0.0199129,0.0181312],[-0.0106279,0.00903492],[-0.0480587,0.0448585],[-0.00930853,0.00944782],[-0.0321611,0.0274864],[-0.0244928,0.0204744],[-0.0275084,0.0223087],[-0.0137679,0.0136262],[-0.0119522,0.0069509],[-0.0176915,0.0177096],[-0.0213541,0.0226276],[-0.0231543,0.0216302],[-0.00992605,0.0099458],[-0.0176451,0.0155456],[-0.0228865,0.0216215],[-0.012833,0.0145895],[0.0194213,-0.0191025],[-0.0123317,0.00994484],[0.0119814,-0.00883787],[-0.021714,0.0216045],[0.0130542,-0.0117696],[-0.0582734,0.0508368],[-0.0114103,0.00897188],[-0.0327889,0.0319029],[-0.0115326,0.00935388],[-0.0454641,0.0424539],[-0.0259063,0.0219584],[-0.00392468,0.0022246],[-0.0115353,0.00961547],[-0.00118654,0.000136787],[-0.0274317,0.0246953],[-0.0346196,0.0319793],[-0.0207328,0.0169096],[-0.0225947,0.0231435],[-0.0206779,0.0202997],[-0.0309578,0.0290966],[-0.0489345,0.0453191],[-0.00430917,0.00324356],[-0.0303065,0.0285267],[-0.0104758,0.00805715],[-0.0461884,0.0410544],[-0.010441,0.00942772],[0.0147038,-0.0109025],[-0.000928722,0.00179285],[-0.0418412,0.03855],[-0.0330817,0.030372],[-0.0158787,0.0160708],[-0.00501973,0.00387316],[-0.00388143,0.00256598],[-0.0291963,0.0280833],[0.00123081,-0.00185297],[-0.0298022,0.0291422],[-0.0229822,0.0209775],[-0.0363332,0.0348146],[-0.0160299,0.0174607],[-0.0189754,0.0174031],[-0.00664985,0.00707258],[-0.0277536,0.0234718],[-0.0236008,0.0223167],[-0.0180206,0.0152781],[-0.0142221,0.0131063],[-0.0499872,0.0457228],[-0.0155807,0.0132818],[-0.0107698,0.0109164],[-0.0266366,0.0249167],[-0.0186964,0.0181331]]}}, +{"best":0.0104078,"evaluations":13674,"generation":589,"median":0.500108,"state":{"best":[-0.836418,-1.12195],"population":[[-0.00224389,0.00244112],[-0.00596031,0.00592883],[-0.0124735,0.0122921],[-0.0167156,0.0161332],[-0.00741796,0.00709989],[-0.00494255,0.00470194],[-0.00518455,0.00514466],[-0.015381,0.014904],[-0.00914259,0.00905935],[-0.00835995,0.00778554],[-0.014214,0.0139032],[-0.000159993,0.000175272],[-0.00691765,0.00680057],[-0.00544479,0.0054615],[-0.00337997,0.00337406],[-0.0119261,0.01165],[-0.00995387,0.00960146],[-0.00847252,0.00843253],[-0.00718909,0.00689107],[-0.00213897,0.00188197],[-0.00172866,0.00181427],[-0.00174843,0.00145675],[-0.0106122,0.0101974],[0.00104743,-0.00111233],[-0.00622475,0.00583292],[-0.00818521,0.00816101],[-0.00557708,0.00555463],[-0.00413362,0.00401247],[-0.00745378,0.00723192],[-0.00994035,0.0097036],[-0.00576658,0.00557075],[-0.0140781,0.0138955],[-0.0130276,0.0125901],[-0.00523804,0.00509069],[-0.00230219,0.00237303],[-0.00483399,0.00469514],[-0.0082815,0.0079039],[-0.00517859,0.00520911],[-0.00541106,0.0052507],[-0.000698749,0.000695318],[-0.00467494,0.00447111],[-0.0101131,0.0097028],[-0.0031899,0.00295575],[-0.00604405,0.00608329],[-0.0152824,0.0148402],[-0.00206085,0.00181779],[-0.0144741,0.0138895],[0.000226173,-0.000365534],[-0.000746668,0.000733839],[-0.0090724,0.00873377],[-0.0084549,0.00811876],[-0.00536537,0.00510642],[0.000255429,-0.00011962],[-0.015272,0.0148533],[-0.00354119,0.00337882],[-0.0137701,0.0135087],[-0.0103457,0.00984087],[-0.0110924,0.0110602],[-0.00388776,0.00371565],[-0.00732891,0.0071624],[-0.00381513,0.00371217],[-0.0025011,0.00237329],[-0.00630078,0.00602727],[-0.0081337,0.00789194],[-0.00170209,0.00170371],[-0.0077117,0.00739528],[-0.00155149,0.00140131],[-0.00757677,0.00739456],[-0.00433391,0.00417616],[0.00495854,-0.00493886],[-0.0134919,0.0130445],[-0.00159762,0.00152224],[-0.00833887,0.00814127],[0.00312797,-0.00309894],[-0.00970757,0.00964328],[0.00139519,-0.00109708],[-0.00781125,0.0075415],[-0.00917819,0.00878259],[0.00449993,-0.0045344],[-0.00579165,0.00579664],[-0.00748992,0.00740889],[-0.00885845,0.00848732],[-0.0147558,0.0143942],[-0.0109878,0.0107111],[-0.00485921,0.00462545],[-0.0125949,0.0123611],[-0.00672242,0.00651488],[-0.001721,0.00155384],[-0.00830966,0.00790169],[0.00275933,-0.0026417],[-0.0117841,0.0115234],[-0.0112603,0.0107109],[-0.00267939,0.00254608],[-0.00320872,0.00299903],[-0.00510679,0.00491738],[-0.00133153,0.00137093]]}}, +{"best":0.0104078,"evaluations":14250,"generation":595,"median":0.500034,"state":{"best":[-0.836418,-1.12195],"population":[[-0.00554242,0.00547369],[-0.00206125,0.00202346],[0.00212926,-0.00206182],[-0.000467014,0.000439624],[-0.00420229,0.00418019],[-0.000875347,0.000925729],[-0.00532209,0.00523858],[-0.00365601,0.0035709],[-0.00230617,0.00230663],[-0.00357721,0.00353636],[-0.00697615,0.00689829],[0.00257576,-0.00256476],[-0.00419825,0.00412259],[0.0028169,-0.00274702],[0.000423089,-0.000391602],[0.00292707,-0.00289057],[-0.000515147,0.000488642],[0.0043375,-0.00427292],[-0.000176765,0.000193075],[-0.00607972,0.00592683],[-0.00698751,0.00687982],[0.00370585,-0.00367935],[-0.00594529,0.00584317],[-0.00681748,0.0067317],[-0.00678076,0.00671062],[-0.000191062,0.000186871],[-0.00344303,0.00340984],[0.000394264,-0.000404117],[-0.00154981,0.00155829],[-0.00287938,0.00280495],[-0.00187238,0.00182792],[0.00139905,-0.00137195],[0.00369395,-0.00360446],[-0.00396584,0.0039073],[0.00129304,-0.0012467],[0.00364245,-0.00356688],[-0.00143972,0.00145389],[0.00239602,-0.00232413],[0.0005573,-0.000552439],[0.00436066,-0.00431605],[0.000869408,-0.000884794],[0.000541514,-0.000483909],[-0.00123093,0.00127044],[-0.00312678,0.00306594],[-0.00520189,0.00510435],[0.00072989,-0.000734846],[-0.00202798,0.00202996],[0.000761299,-0.000786361],[0.00140528,-0.00137827],[-0.00407704,0.00397497],[-0.0031297,0.00303273],[-0.00048544,0.00047289],[-0.0100932,0.00992293],[-0.00344722,0.00338202],[-0.00249861,0.00246371],[0.00271717,-0.00274531],[0.00381578,-0.00374371],[-0.00217725,0.00218556],[-0.000773977,0.000770971],[0.00313935,-0.00304386],[0.00518562,-0.0050771],[-0.0022499,0.00224954],[8.97609e-05,-5.82971e-05],[0.00133085,-0.00128997],[-0.00062663,0.000644467],[9.16762e-06,-5.91585e-05],[0.00305796,-0.00297534],[-0.00373783,0.00369042],[-0.00241551,0.00237578],[0.00140393,-0.00137168],[0.0021333,-0.00215211],[-0.000592306,0.000618182],[0.00116858,-0.00114353],[0.00240299,-0.00227264],[-0.00679293,0.00669327],[-0.00203145,0.00203946],[-0.00180596,0.00175172],[-0.00291351,0.00289468],[-0.00306327,0.00302418],[-0.00155715,0.00154662],[-0.00499902,0.00490809],[-0.00502252,0.00493977],[-0.00454117,0.00445915],[-0.0042958,0.00426866],[-0.00358791,0.00350777],[-0.00468842,0.00460229],[0.00112497,-0.00106167],[-0.00519852,0.0050348],[0.00178521,-0.00167233],[-0.00020438,0.000202103],[0.00361521,-0.0034928],[-0.00368166,0.00365708],[-0.00561602,0.00549801],[-0.000645535,0.00061983],[-0.00646926,0.00640211],[-0.00188391,0.0018252]]}}, +{"best":0.0104078,"evaluations":14922,"generation":602,"median":0.500005,"state":{"best":[-0.836418,-1.12195],"population":[[-0.00182157,0.00181349],[0.00133016,-0.00132483],[-0.00196515,0.00194481],[-0.00289432,0.00287341],[-0.000427521,0.000430698],[-0.000678239,0.00067505],[-0.00147955,0.00147517],[-0.000508788,0.000497661],[-0.00175572,0.00174088],[-0.00091429,0.000906855],[-0.00261787,0.00259528],[-0.00458141,0.00454789],[-0.00133016,0.00132358],[-0.00103431,0.0010221],[-0.000524077,0.000509245],[0.00216116,-0.00213719],[-0.00157516,0.00156084],[-2.29846e-05,2.08406e-05],[-7.08741e-05,7.54706e-05],[-0.000691763,0.000683925],[0.000296682,-0.00029528],[-0.00136517,0.00135603],[-0.000121499,0.00011731],[0.00138344,-0.00137377],[-0.000809314,0.000798201],[-0.0027233,0.00270766],[0.000364648,-0.00036104],[-0.00251482,0.00250203],[-0.00158629,0.00158115],[-0.00157713,0.00156809],[-0.00149647,0.00148854],[0.000411548,-0.000402364],[-0.00149858,0.00148712],[0.000418846,-0.000410605],[0.00132687,-0.00132032],[-0.00104035,0.00103148],[-0.00109698,0.00109002],[-0.000583653,0.000582231],[-0.00309283,0.0030714],[-0.00157039,0.00155477],[-0.00159134,0.00158396],[-0.000686421,0.000682408],[0.00143436,-0.00141674],[-0.00139539,0.00139246],[-0.00237212,0.00235557],[-0.00119411,0.00117594],[-0.00120552,0.00120577],[-0.000992601,0.000986911],[0.000665783,-0.000665796],[0.000429619,-0.000429441],[-0.00128148,0.00127326],[-0.00138524,0.00138171],[0.000484183,-0.000486539],[-0.0034293,0.00341066],[0.000171861,-0.000166438],[0.000392223,-0.000390384],[-0.000808029,0.000804703],[0.000177712,-0.000176903],[-0.000150432,0.000153545],[-0.000150277,0.000146998],[-0.00438098,0.00435016],[-0.000333526,0.000331357],[-0.000576704,0.000573597],[-0.00268957,0.00266915],[-0.00159108,0.00157276],[0.00208235,-0.00206594],[-0.00154587,0.00153065],[-0.000210064,0.000208244],[-0.0028487,0.00283375],[0.00140567,-0.00139959],[-0.000565934,0.000553462],[0.000109792,-0.000109965],[0.000834556,-0.000826526],[0.000738669,-0.00074121],[0.000832122,-0.000835546],[0.00131676,-0.00130533],[-0.000883572,0.000883995],[-0.00084839,0.000843289],[-0.00117603,0.00117199],[-8.67907e-05,8.1801e-05],[0.000533715,-0.000529609],[-0.00457265,0.00455079],[-0.00185671,0.00184451],[-0.00148759,0.0014795],[9.57137e-05,-9.23649e-05],[0.000204038,-0.000199161],[0.000648554,-0.000647888],[-0.00122733,0.00121456],[-0.000820222,0.00081526],[-0.00307026,0.00304543],[-0.00241802,0.00240289],[-0.00291037,0.00290425],[-0.00134081,0.00133515],[0.00108366,-0.0010745],[0.000580455,-0.000576344],[-0.00221709,0.00220703]]}}, +{"best":0.0104078,"evaluations":15594,"generation":609,"median":0.500001,"state":{"best":[-0.836418,-1.12195],"population":[[0.000186879,-0.000186901],[-0.00109044,0.00108644],[0.00087312,-0.000869129],[-0.0012042,0.00120119],[-0.00100418,0.00100129],[7.55568e-05,-7.58859e-05],[-0.000145356,0.000144523],[7.90699e-05,-8.00749e-05],[-0.00103396,0.00103026],[-0.00154156,0.00153753],[-0.000770321,0.000767731],[-0.00114147,0.00113968],[-0.000172651,0.000171568],[9.81354e-05,-9.66534e-05],[-0.00069145,0.000689561],[-0.000565662,0.000564642],[-2.1823e-05,2.15442e-05],[-0.000595595,0.000592611],[-0.000385919,0.000384815],[-0.000507091,0.000504535],[-0.000472976,0.000471375],[-0.000840657,0.000837825],[-0.000664101,0.00066074],[-0.000526874,0.000524898],[-0.000900497,0.000897449],[-0.00029255,0.000291981],[-0.00143037,0.00142476],[-0.000453533,0.000451402],[-0.000573852,0.000572181],[-0.00113741,0.00113396],[-0.00204739,0.00204028],[-0.000331933,0.000332266],[-0.00174451,0.00173897],[-0.000259764,0.000260195],[0.000420789,-0.000417738],[-0.00241738,0.00240948],[-0.000487151,0.000485729],[0.00140527,-0.00140125],[-0.000835282,0.000833139],[-0.000908837,0.000905424],[-0.000107704,0.000109039],[-0.00118749,0.00118195],[-0.000543604,0.000541243],[-0.000564753,0.000562524],[-0.000118343,0.00011805],[1.99061e-05,-1.98759e-05],[-0.000773561,0.000770805],[-0.00108859,0.00108492],[0.000204109,-0.000202476],[-0.000747857,0.000744325],[-0.000135888,0.000134429],[0.000405976,-0.00040573],[-0.00121811,0.00121305],[-0.000297707,0.000298208],[-0.00120836,0.00120391],[-0.000215229,0.000215035],[9.20531e-05,-9.1343e-05],[-0.00109319,0.00108912],[-0.00098302,0.000979584],[-0.000281681,0.000281264],[0.000137011,-0.000135503],[-0.00131398,0.00131025],[-0.00145596,0.00145174],[-0.000486348,0.000483738],[-0.000631843,0.000629941],[-0.000744799,0.000741218],[-0.000378134,0.000376756],[0.000558279,-0.000556053],[-0.000824302,0.00082196],[-0.0010563,0.00105421],[-0.000635169,0.000633331],[-0.00149882,0.00149434],[-0.00146836,0.00146315],[-0.00235394,0.00234608],[-0.000337061,0.000338158],[0.000125495,-0.000124047],[-0.000520036,0.000518278],[-0.000473321,0.000471301],[-0.000357497,0.00035444],[-0.000624792,0.000622278],[0.000491477,-0.000490018],[-0.000256928,0.00025743],[-0.00111419,0.00111089],[-0.000450941,0.000449848],[-0.00148881,0.00148466],[-0.000684072,0.000682028],[-0.000897907,0.000894216],[-0.000431335,0.000430666],[6.42508e-05,-6.25846e-05],[-0.00123978,0.0012366],[-0.00129088,0.00128624],[-2.73634e-05,2.78323e-05],[-0.000576889,0.000574614],[-0.00142456,0.00141833],[-0.000747496,0.000744908],[-0.000688275,0.000686344]]}}, +{"best":0.0104078,"evaluations":16170,"generation":615,"median":0.5,"state":{"best":[-0.836418,-1.12195],"population":[[6.53884e-05,-6.5125e-05],[-0.00052567,0.000524919],[-0.00121027,0.00120835],[-0.000830989,0.000830076],[-0.000263595,0.000263284],[-0.000689689,0.000688727],[-0.000781916,0.000780419],[-0.000468706,0.000467807],[-0.000232805,0.000232425],[1.52544e-05,-1.55276e-05],[-0.00106349,0.00106179],[-0.000383885,0.000383427],[-0.000416587,0.000415977],[-0.000643334,0.000642166],[-0.000407974,0.000407287],[-0.000925345,0.00092381],[-0.000317595,0.000317131],[-0.000753836,0.000752492],[-0.000521022,0.000519803],[-0.000805048,0.000803579],[-0.000739895,0.00073841],[-0.000332181,0.000331619],[-0.000254468,0.000253518],[-0.000682521,0.000681058],[-0.000310673,0.000309861],[-0.000119557,0.000119103],[-0.000756321,0.000755077],[-0.00064152,0.000640601],[-0.000530704,0.000529895],[-0.000695327,0.000694061],[-0.00062478,0.000624313],[0.000172969,-0.000172637],[-0.000888156,0.000886665],[-0.000907969,0.000906763],[-0.000196552,0.00019665],[-0.000905073,0.000903879],[-0.000286545,0.000286083],[-0.00051685,0.000515954],[0.00018681,-0.000186774],[0.000119604,-0.000119702],[0.000379094,-0.000378529],[-0.00032765,0.000327568],[-0.000201735,0.000201258],[-0.000678879,0.000677623],[0.00022276,-0.000222455],[-0.000216417,0.000216538],[-0.00062715,0.000626061],[-1.98128e-05,1.98889e-05],[-0.00021451,0.000214095],[-0.000234414,0.000233552],[-0.000638437,0.000637639],[-0.000391171,0.000390449],[-0.000636712,0.000635002],[-0.00049009,0.000489183],[-0.00031702,0.000316794],[-0.000211183,0.000210758],[-0.00041998,0.000419495],[-0.000696419,0.000695368],[-0.000853287,0.000851613],[-0.000885839,0.000884507],[-0.000295519,0.000295138],[-7.18816e-05,7.1699e-05],[-0.000819478,0.000818522],[-0.000454267,0.000453651],[-0.00048822,0.000487577],[-0.00059956,0.000598569],[-0.000408682,0.000408103],[-0.000856234,0.000855483],[-0.000408809,0.000407963],[-0.000265281,0.00026532],[-0.00056085,0.000559859],[-0.000756535,0.000755143],[-0.000483495,0.000483078],[-0.000958537,0.000956895],[-0.0001443,0.000144371],[-0.000187184,0.000186768],[-0.000306174,0.000305707],[-0.000662301,0.000661232],[-0.0010018,0.00100045],[-0.000571126,0.000570362],[-0.000866448,0.000864782],[-0.000408584,0.000407713],[-0.000249199,0.000248912],[0.00011146,-0.000110503],[-0.000433691,0.000433],[-0.000433912,0.0004334],[-0.00130707,0.00130489],[-0.000648415,0.000647262],[-0.00013494,0.000134783],[-0.000344242,0.000343409],[-0.000433401,0.000432552],[-0.000510632,0.000509935],[-0.000701323,0.000700093],[-0.000258847,0.00025879],[-0.000284302,0.000284137],[-0.000862472,0.000861074]]}}, +{"best":0.0104078,"evaluations":16842,"generation":622,"median":0.5,"state":{"best":[-0.836418,-1.12195],"population":[[-0.000279446,0.000279235],[-0.000324346,0.000324107],[-0.000333238,0.000332775],[-0.000307397,0.000307086],[1.74365e-05,-1.73358e-05],[-0.000376154,0.000375762],[-0.000607956,0.000607334],[-0.00056219,0.000561527],[-0.000537566,0.000536922],[-0.00024655,0.000246431],[-0.000442184,0.000441784],[-0.000612276,0.000611528],[-0.000276054,0.000275768],[-4.11001e-05,4.11569e-05],[-0.000329828,0.000329477],[-4.9922e-06,5.14638e-06],[-0.000552494,0.000551841],[-0.00031624,0.000315897],[-0.000229341,0.000229134],[-0.000631351,0.000630454],[7.51292e-05,-7.49599e-05],[3.10697e-05,-3.09217e-05],[-0.000319271,0.000318891],[-0.000205037,0.000204706],[-0.000225686,0.0002255],[-0.000416588,0.000416083],[-0.000395954,0.000395541],[-0.000265406,0.000265379],[-0.000649744,0.00064896],[-0.000271275,0.000270994],[-0.000466112,0.000465628],[-0.000496918,0.000496333],[-0.00032322,0.000322969],[-0.000361216,0.000360942],[-0.00073223,0.000731303],[-0.000298323,0.000297956],[-0.000232154,0.000231987],[-0.000584518,0.000583812],[-0.000674657,0.000673849],[-0.00015225,0.000152202],[-0.000322436,0.000322124],[-0.000119435,0.000119411],[-0.000392163,0.000391778],[-4.18729e-05,4.2022e-05],[-0.000351911,0.000351602],[-0.000746004,0.000745195],[1.46655e-05,-1.44313e-05],[-0.000139299,0.000139237],[-0.00053007,0.000529451],[-8.73314e-05,8.73398e-05],[-0.00034868,0.000348353],[-0.000336496,0.0003362],[-0.000459708,0.000459267],[-0.000449106,0.000448559],[-0.000536381,0.00053586],[-0.000638549,0.000637738],[-0.000249447,0.000249363],[-0.000540162,0.000539614],[-0.000504397,0.000503786],[-0.000110381,0.000110361],[-0.000125641,0.000125708],[-0.000532137,0.000531498],[-0.000493938,0.000493392],[-0.000659072,0.000658281],[0.000109868,-0.000109414],[-0.000230847,0.000230711],[-0.000449041,0.000448571],[-0.000320744,0.00032034],[-0.000182519,0.000182474],[-0.000619023,0.000618268],[-0.000469116,0.000468547],[-0.000558272,0.000557694],[-0.00050755,0.000506996],[1.59207e-05,-1.57915e-05],[-0.00054107,0.000540573],[-4.01843e-05,4.02959e-05],[-0.000730504,0.000729578],[-0.000299468,0.000299242],[-0.000381735,0.000381377],[-0.000626875,0.000626204],[-0.000280889,0.000280635],[-0.000647296,0.000646614],[-0.000467897,0.000467281],[-9.22708e-05,9.23119e-05],[-0.000354717,0.000354419],[-0.000405243,0.000404854],[-0.000494845,0.000494207],[2.19157e-05,-2.18767e-05],[-0.000371857,0.000371368],[-0.000502215,0.000501698],[-0.000217177,0.000216917],[-0.000565111,0.000564495],[-0.000364664,0.00036429],[-3.16892e-05,3.16449e-05],[-0.000226671,0.000226501],[-0.000446059,0.000445645]]}}, +{"best":0.0104078,"evaluations":17514,"generation":629,"median":0.5,"state":{"best":[-0.836418,-1.12195],"population":[[-0.000316711,0.000316471],[-0.000524725,0.000524184],[-0.000341303,0.000341017],[-0.000439539,0.000439121],[-0.000502323,0.0005018],[-0.00040654,0.000406204],[-0.000418101,0.00041767],[-0.000458372,0.000457923],[-0.000492937,0.000492436],[-0.000284983,0.000284809],[-0.000464678,0.000464245],[-0.000551335,0.000550756],[-0.000323407,0.000323133],[-0.00036875,0.000368459],[-0.000232883,0.000232804],[-0.000543672,0.000543075],[-0.000434969,0.000434553],[-0.000735122,0.000734265],[-0.000464591,0.00046413],[-0.000204857,0.000204843],[-0.000479149,0.000478626],[-0.000457271,0.000456859],[-0.000306173,0.00030598],[-0.00050751,0.000507025],[-0.000532615,0.000532046],[-0.000505947,0.000505421],[-0.000515586,0.000515051],[-0.000566848,0.000566271],[-0.000321529,0.000321297],[-0.000375301,0.000375013],[-0.000352645,0.000352409],[-0.00051672,0.000516171],[-0.000518199,0.000517675],[-0.000604667,0.000603988],[-0.000530302,0.000529752],[-0.000100326,0.000100416],[-0.00040578,0.000405435],[-0.00042474,0.000424337],[-0.000316906,0.000316689],[-0.000436915,0.000436528],[-0.00061046,0.000609747],[-0.000299075,0.000298852],[-0.000415725,0.00041533],[-0.000476522,0.000476072],[-0.000211715,0.000211621],[-0.000342324,0.00034204],[-0.000457504,0.00045706],[-0.000303368,0.000303141],[-0.000581365,0.000580687],[-0.000640789,0.000640091],[-0.000358165,0.000357849],[-0.000468735,0.000468284],[-0.000501282,0.000500797],[-0.000405212,0.000404844],[-0.000485794,0.000485358],[-0.000323676,0.000323442],[-0.000255631,0.000255473],[-0.0005916,0.00059094],[-0.000517235,0.000516746],[-0.000517573,0.000517063],[-0.000308958,0.000308748],[-0.000322513,0.000322289],[-0.000384116,0.00038381],[-0.000392365,0.000391979],[-0.000511423,0.000510862],[-0.000432026,0.000431608],[-0.00034245,0.000342172],[-0.000313929,0.000313694],[-0.000488981,0.000488478],[-0.000452685,0.000452285],[-0.000470114,0.000469668],[-0.000478734,0.000478266],[-0.000356921,0.000356634],[-0.000357495,0.000357175],[-0.000708551,0.000707729],[-0.000471141,0.000470625],[-0.000515781,0.000515263],[-0.000518596,0.000518062],[-0.000618541,0.000617833],[-0.000290085,0.000289897],[-0.000257165,0.000257057],[-0.00041025,0.000409904],[-0.000600789,0.000600123],[-0.000583093,0.000582481],[-0.000466378,0.000465915],[-0.000492486,0.000491987],[-0.000264143,0.000264025],[-0.000346714,0.000346476],[-0.000224249,0.000224146],[-0.000536131,0.000535586],[-0.000608264,0.000607533],[-0.000350785,0.000350511],[-0.000371532,0.000371192],[-0.00035491,0.000354586],[-0.00037925,0.000378951],[-0.000477216,0.000476715]]}}, +{"best":0.0104078,"evaluations":18090,"generation":635,"median":0.5,"state":{"best":[-0.836418,-1.12195],"population":[[-0.000459849,0.000459426],[-0.000486621,0.000486144],[-0.000511205,0.000510683],[-0.000485658,0.00048519],[-0.000556455,0.000555842],[-0.000569104,0.000568472],[-0.000558715,0.000558112],[-0.000595111,0.000594435],[-0.000499475,0.000498974],[-0.000503322,0.000502809],[-0.000435228,0.000434837],[-0.000536806,0.000536232],[-0.000452146,0.000451731],[-0.000472965,0.000472519],[-0.000536955,0.000536386],[-0.000497417,0.000496924],[-0.000529359,0.000528797],[-0.000523149,0.000522602],[-0.000512003,0.000511484],[-0.000483084,0.000482612],[-0.00054095,0.000540368],[-0.000547106,0.000546517],[-0.000500535,0.000500023],[-0.000520303,0.000519768],[-0.000542653,0.000542075],[-0.000480045,0.000479579],[-0.000548784,0.000548189],[-0.000444739,0.000444338],[-0.000448369,0.000447966],[-0.000458316,0.000457895],[-0.000528725,0.000528172],[-0.000486063,0.000485589],[-0.0004513,0.000450893],[-0.000525753,0.000525198],[-0.00054559,0.000544997],[-0.000523364,0.000522808],[-0.000573742,0.000573106],[-0.000463611,0.000463166],[-0.000533074,0.000532517],[-0.000525473,0.000524925],[-0.000485081,0.000484608],[-0.000482386,0.000481919],[-0.000508992,0.000508477],[-0.000468109,0.000467677],[-0.000427899,0.000427527],[-0.000529475,0.000528918],[-0.000554834,0.000554222],[-0.000574256,0.00057361],[-0.000483414,0.000482943],[-0.000482056,0.000481589],[-0.000479445,0.000478986],[-0.000509383,0.000508857],[-0.000593343,0.000592664],[-0.000477419,0.000476955],[-0.000513232,0.000512708],[-0.000411819,0.00041148],[-0.000506281,0.000505773],[-0.000513569,0.00051304],[-0.000558899,0.000558279],[-0.000426572,0.000426216],[-0.000518134,0.000517592],[-0.00053727,0.000536692],[-0.000487933,0.00048745],[-0.000499949,0.000499451],[-0.000521061,0.000520525],[-0.00048605,0.000485576],[-0.000502996,0.000502491],[-0.000467231,0.000466795],[-0.000522643,0.000522105],[-0.000492184,0.0004917],[-0.000521425,0.000520889],[-0.000449024,0.000448632],[-0.000400443,0.000400121],[-0.000503813,0.000503304],[-0.000519391,0.000518855],[-0.00049371,0.000493228],[-0.000491472,0.000490988],[-0.000565146,0.000564518],[-0.000441207,0.00044082],[-0.000505798,0.000505279],[-0.000475871,0.000475415],[-0.000511844,0.000511317],[-0.000504854,0.000504338],[-0.000524741,0.0005242],[-0.000426205,0.000425842],[-0.000456333,0.000455902],[-0.000513199,0.00051267],[-0.000429378,0.000429009],[-0.000454457,0.000454036],[-0.000519984,0.000519439],[-0.000502516,0.000502001],[-0.000523035,0.000522494],[-0.000487274,0.000486786],[-0.000505256,0.000504744],[-0.000538901,0.000538327],[-0.000455419,0.000455009]]}}, +{"best":0.0104078,"evaluations":18762,"generation":642,"median":0.5,"state":{"best":[-0.836418,-1.12195],"population":[[-0.00051967,0.00051913],[-0.000527962,0.000527405],[-0.000538919,0.000538339],[-0.000536014,0.00053544],[-0.000534216,0.000533645],[-0.000522204,0.000521659],[-0.000532056,0.00053149],[-0.000514284,0.000513755],[-0.000537653,0.000537076],[-0.000544944,0.000544351],[-0.000536181,0.000535606],[-0.000531299,0.000530735],[-0.000522052,0.000521507],[-0.000521985,0.00052144],[-0.000529635,0.000529074],[-0.000530008,0.000529447],[-0.000528348,0.00052779],[-0.000536632,0.000536056],[-0.000538562,0.000537983],[-0.000526727,0.000526172],[-0.000527673,0.000527117],[-0.000523813,0.000523265],[-0.000515349,0.000514818],[-0.000524908,0.000524358],[-0.000529668,0.000529107],[-0.000544026,0.000543436],[-0.000548734,0.000548135],[-0.00052962,0.000529059],[-0.000534057,0.000533487],[-0.000545589,0.000544995],[-0.00053206,0.000531495],[-0.000518026,0.000517489],[-0.000524541,0.000523991],[-0.00052908,0.000528521],[-0.00053251,0.000531944],[-0.000528034,0.000527477],[-0.000501271,0.000500769],[-0.00053851,0.000537932],[-0.000536113,0.000535539],[-0.00053428,0.000533709],[-0.00053899,0.00053841],[-0.000533028,0.000532461],[-0.000527135,0.000526579],[-0.000529684,0.000529123],[-0.000533216,0.000532647],[-0.000517898,0.000517362],[-0.000540048,0.000539466],[-0.000530953,0.000530389],[-0.000550502,0.000549898],[-0.000513918,0.00051339],[-0.000539717,0.000539136],[-0.000524464,0.000523914],[-0.000530356,0.000529793],[-0.000528088,0.00052753],[-0.000527176,0.00052662],[-0.000531301,0.000530737],[-0.000521091,0.000520548],[-0.000529455,0.000528895],[-0.00055576,0.000555145],[-0.000518127,0.00051759],[-0.000544475,0.000543884],[-0.000533668,0.000533099],[-0.000530135,0.000529573],[-0.000524153,0.000523604],[-0.000526685,0.00052613],[-0.000546515,0.00054592],[-0.000525467,0.000524915],[-0.000514571,0.000514042],[-0.000537776,0.000537199],[-0.000523956,0.000523408],[-0.000525206,0.000524655],[-0.000515679,0.000515148],[-0.000533939,0.000533369],[-0.000522801,0.000522255],[-0.000532128,0.000531562],[-0.000524393,0.000523844],[-0.000539656,0.000539075],[-0.000532706,0.000532139],[-0.000534513,0.000533943],[-0.000524284,0.000523734],[-0.000529757,0.000529196],[-0.000537932,0.000537354],[-0.000531103,0.000530539],[-0.000533109,0.000532541],[-0.000539635,0.000539054],[-0.000526631,0.000526077],[-0.000532777,0.000532209],[-0.00052336,0.000522813],[-0.000540702,0.000540118],[-0.000511875,0.000511351],[-0.000538323,0.000537744],[-0.000548587,0.000547987],[-0.000520587,0.000520045],[-0.000532996,0.000532429],[-0.000531208,0.000530644],[-0.000528124,0.000527566]]}}, +{"best":0.0104078,"evaluations":19338,"generation":648,"median":0.5,"state":{"best":[-0.836418,-1.12195],"population":[[-0.000535901,0.000535327],[-0.000536456,0.000535881],[-0.000537789,0.000537212],[-0.000535585,0.000535012],[-0.000535266,0.000534693],[-0.000533226,0.000532658],[-0.000538515,0.000537936],[-0.000536399,0.000535824],[-0.000539524,0.000538942],[-0.000534071,0.000533502],[-0.000532684,0.000532117],[-0.00053499,0.000534418],[-0.000536128,0.000535553],[-0.000534742,0.000534171],[-0.000537617,0.00053704],[-0.000535298,0.000534726],[-0.000536996,0.00053642],[-0.000534321,0.000533751],[-0.000535473,0.0005349],[-0.000531066,0.000530502],[-0.000537092,0.000536516],[-0.000535918,0.000535344],[-0.000533855,0.000533285],[-0.000534347,0.000533776],[-0.000538955,0.000538374],[-0.000540184,0.000539601],[-0.00053708,0.000536504],[-0.000532675,0.000532108],[-0.000536005,0.000535431],[-0.00053814,0.000537561],[-0.000537818,0.00053724],[-0.000541479,0.000540893],[-0.000535094,0.000534522],[-0.000539286,0.000538705],[-0.000533783,0.000533214],[-0.000533782,0.000533213],[-0.000534071,0.000533501],[-0.000530226,0.000529664],[-0.000538897,0.000538317],[-0.000536431,0.000535856],[-0.000534153,0.000533583],[-0.000533125,0.000532557],[-0.00053833,0.000537751],[-0.000531841,0.000531276],[-0.000537125,0.000536548],[-0.000530438,0.000529876],[-0.000529719,0.000529158],[-0.000530923,0.00053036],[-0.000533667,0.000533098],[-0.000533917,0.000533347],[-0.00053987,0.000539288],[-0.000532706,0.000532139],[-0.000536532,0.000535957],[-0.000534559,0.000533988],[-0.000533563,0.000532994],[-0.000536361,0.000535786],[-0.000537463,0.000536886],[-0.000534385,0.000533815],[-0.000538347,0.000537768],[-0.000538548,0.000537968],[-0.000536849,0.000536273],[-0.000536743,0.000536168],[-0.00053637,0.000535795],[-0.000537661,0.000537084],[-0.000536159,0.000535584],[-0.000537417,0.00053684],[-0.000532347,0.000531781],[-0.00053368,0.00053311],[-0.000540296,0.000539713],[-0.000535371,0.000534798],[-0.000536713,0.000536137],[-0.000535287,0.000534714],[-0.000534109,0.00053354],[-0.00053268,0.000532113],[-0.000536001,0.000535427],[-0.000539128,0.000538547],[-0.000534775,0.000534203],[-0.000531128,0.000530565],[-0.00053219,0.000531624],[-0.000535162,0.00053459],[-0.000537422,0.000536845],[-0.000532085,0.000531519],[-0.000533249,0.00053268],[-0.000532311,0.000531745],[-0.000539956,0.000539374],[-0.000533757,0.000533188],[-0.00053353,0.000532961],[-0.000537283,0.000536706],[-0.000536685,0.000536109],[-0.000535175,0.000534603],[-0.000531402,0.000530838],[-0.000539845,0.000539263],[-0.000535705,0.000535132],[-0.000535682,0.000535108],[-0.000541317,0.000540731],[-0.000534348,0.000533777]]}}, +{"best":0.0104078,"evaluations":20010,"generation":655,"median":0.5,"state":{"best":[-0.836418,-1.12195],"population":[[-0.000536768,0.000536192],[-0.000537655,0.000537078],[-0.000537054,0.000536478],[-0.000536632,0.000536056],[-0.000536655,0.000536079],[-0.000537237,0.00053666],[-0.000537129,0.000536553],[-0.000537198,0.000536621],[-0.00053688,0.000536305],[-0.000537014,0.000536437],[-0.000537212,0.000536635],[-0.000537494,0.000536917],[-0.000537332,0.000536755],[-0.00053726,0.000536684],[-0.00053696,0.000536384],[-0.000537453,0.000536876],[-0.000537745,0.000537167],[-0.000537532,0.000536955],[-0.000536865,0.000536289],[-0.000536857,0.000536281],[-0.000537342,0.000536765],[-0.000537266,0.00053669],[-0.000537322,0.000536745],[-0.000537093,0.000536517],[-0.000537439,0.000536862],[-0.000536795,0.000536219],[-0.000536861,0.000536285],[-0.000537012,0.000536436],[-0.00053691,0.000536334],[-0.000536614,0.000536039],[-0.000537229,0.000536653],[-0.000536778,0.000536203],[-0.000536997,0.000536421],[-0.00053702,0.000536444],[-0.000537441,0.000536864],[-0.000537366,0.000536789],[-0.000537046,0.000536469],[-0.000536759,0.000536184],[-0.000537026,0.00053645],[-0.000537161,0.000536584],[-0.000536606,0.00053603],[-0.000536943,0.000536367],[-0.000536979,0.000536403],[-0.00053678,0.000536204],[-0.000537071,0.000536495],[-0.00053781,0.000537232],[-0.000537762,0.000537184],[-0.000536367,0.000535793],[-0.000537245,0.000536668],[-0.000536748,0.000536173],[-0.000537431,0.000536854],[-0.000536635,0.00053606],[-0.000537314,0.000536737],[-0.00053655,0.000535975],[-0.000537031,0.000536455],[-0.000536677,0.000536101],[-0.000536708,0.000536133],[-0.000537106,0.000536529],[-0.000537592,0.000537015],[-0.000536589,0.000536014],[-0.000536602,0.000536027],[-0.000537291,0.000536714],[-0.000537309,0.000536733],[-0.000536783,0.000536208],[-0.000536291,0.000535717],[-0.000537255,0.000536679],[-0.000536776,0.0005362],[-0.000537114,0.000536538],[-0.000537606,0.000537029],[-0.00053711,0.000536533],[-0.000537003,0.000536426],[-0.000536671,0.000536096],[-0.000536759,0.000536183],[-0.000536661,0.000536085],[-0.000537383,0.000536806],[-0.000536746,0.00053617],[-0.000537386,0.00053681],[-0.000537016,0.00053644],[-0.000536876,0.000536301],[-0.000536479,0.000535904],[-0.000536551,0.000535976],[-0.000536986,0.00053641],[-0.000536347,0.000535772],[-0.000536912,0.000536336],[-0.000536701,0.000536125],[-0.00053656,0.000535985],[-0.000537459,0.000536882],[-0.000537376,0.000536799],[-0.000537424,0.000536847],[-0.000536999,0.000536423],[-0.000537196,0.00053662],[-0.000536584,0.000536009],[-0.000536815,0.00053624],[-0.000536985,0.000536409],[-0.000536994,0.000536418],[-0.000537751,0.000537173]]}} +]} diff --git a/examples/hg_bat/trace.py b/examples/hg_bat/trace.py new file mode 100644 index 00000000..7fd1d7c9 --- /dev/null +++ b/examples/hg_bat/trace.py @@ -0,0 +1,189 @@ +"""The trace for the plot on the example's page, written to the file that ``GENOXIDE_TRACE`` +names. The plot draws the population on the function's contour, which needs two dimensions: the +trace is of a separate run of CMA-ES with IPOP restarts in 2 dimensions, with a budget of +20,000 evaluations, in at most 100 frames. The Rust example writes the same file.""" + +import json +import math +import os + +import genoxide as gx + + +def record_small(): + """Runs CMA-ES with IPOP restarts in 2 dimensions and writes its trace, if ``GENOXIDE_TRACE`` is set.""" + path = os.environ.get("GENOXIDE_TRACE") + if not path: + return + problem = gx.problems.HgBat(2) + minimum = problem.optimum.value + budget = 20_000 + cmaes = gx.Cmaes(problem.genome, restarts="ipop", objective="minimize", seed=1) + frames = Frames(100) + + def record(progress): + state = {"population": progress.population.tolist(), "best": progress.best_genome.tolist()} + frames.push(frame(progress, state, minimum)) + + cmaes.run(problem, target=minimum + 1e-8, evaluations=budget, on_generation=record) + low, high = problem.genome.bounds + settings = { + "format": 1, + "example": "hg_bat", + "objective": "minimize", + "x_label": "evaluations", + "y_label": "error", + "log_y": True, + "optimum": 0.0, + "plot": "contour", + "problem": { + "function": "hg_bat", + "bounds": [[float(low), float(high)]] * 2, + "minima": problem.optimum.solutions.tolist(), + }, + } + write(path, settings, frames.to_list()) + + +def frame(progress, state, minimum): + """The frame of a generation: its progress, the errors of its best and of its population's + median to ``minimum`` (rounding can put a solution a few ulps below it), and ``state``.""" + + def error(value): + return None if value is None else max(value - minimum, 0.0) + + return { + "generation": progress.generation, + "evaluations": progress.evaluations, + "best": error(progress.best_fitness), + "median": error(median(progress.scores)), + "state": state, + } + + +def median(scores): + """The median of the valid scores, None without any.""" + scores = sorted(float(score) for score in scores if not math.isnan(score)) + middle = len(scores) // 2 + if not scores: + return None + return scores[middle] if len(scores) % 2 else (scores[middle - 1] + scores[middle]) / 2 + + +# ---- the same in every example's trace ---------------------------------------------------------- + + +class Frames: + """The frames of at most ``most`` generations, from the part of the run where what the page + plots changes: the frames after the last change are left out (a run that reached its target, + or a front that no longer moves), and the rest are spread evenly over the generations up to + it. While the run goes, up to 8 × ``most`` frames are kept: every ``every``-th generation, + with ``every`` doubling whenever there are that many, and the last one.""" + + def __init__(self, most): + self.most, self.every, self.kept, self.last = most, 1, [], None + + def push(self, frame): + if frame["generation"] % self.every: + self.last = frame + return + self.kept.append(frame) + self.last = None + if len(self.kept) == 8 * self.most: + self.every *= 2 + self.kept = [kept for kept in self.kept if kept["generation"] % self.every == 0] + + def to_list(self): + frames = self.kept + ([self.last] if self.last else []) + active = frames[: last_change(frames) + 1] + count, most = len(active), max(self.most, 2) + if count <= most: + return active + return [active[(i * (count - 1) + (most - 1) // 2) // (most - 1)] for i in range(most)] + + +def last_change(frames): + """The index of the frame after which nothing the page plots changes. To 3 significant + digits, as a plot shows them: the best, the median and, for a single objective (a numeric + best), the state; to within a hundredth of their range over the run: a front's + hypervolumes, in the state or in a grid's series.""" + if not frames: + return 0 + last = len(frames) - 1 + number = lambda value: isinstance(value, (int, float)) and not isinstance(value, bool) + single = any(number(frame.get("best")) for frame in frames) + + def measures(frame): + values = [] + state = frame.get("state") + hypervolume = state.get("hypervolume") if isinstance(state, dict) else None + for value in (hypervolume, frame.get("series")): + if number(value): + values.append(float(value)) + elif isinstance(value, dict): + values.extend(float(v) for _, v in sorted(value.items()) if number(v)) + return values + + measured = [measures(frame) for frame in frames] + end = measured[last] + tolerance = [] + for k in range(len(end)): + values = [values[k] for values in measured if k < len(values)] + tolerance.append((max(values) - min(values)) / 100.0) + + def same(frame, final, key, flush=False): + return coarse(frame.get(key), flush) == coarse(final.get(key), flush) + + def settled(i): + frame, final = frames[i], frames[last] + return ( + same(frame, final, "best") + and same(frame, final, "median") + and (not single or same(frame, final, "state", flush=True)) + and len(measured[i]) == len(end) + and all(abs(v - e) <= t for v, e, t in zip(measured[i], end, tolerance)) + ) + + first = last + while first > 0 and settled(first - 1): + first -= 1 + return first + + +def coarse(value, flush=False): + """``value`` with its numbers to 3 significant digits, as precisely as a plot shows them: two + frames whose plotted values agree to that precision look the same. With ``flush``, for the + solutions a plot draws on their ranges, numbers below 1e-6 in size count as 0.""" + if isinstance(value, float): + if flush and abs(value) < 1e-6: + value = 0.0 + return f"{value:.2e}" + if isinstance(value, (list, tuple)): + return "[" + ",".join(coarse(item, flush) for item in value) + "]" + if isinstance(value, dict): + items = sorted(value.items()) + return "{" + ",".join(f"{key}:{coarse(item, flush)}" for key, item in items) + "}" + return json.dumps(value) + + +def write(path, settings, frames): + """Writes the settings and the frames to ``path``, a frame per line.""" + lines = ",\n".join(map(to_json, frames)) + with open(path, "w", encoding="utf-8", newline="\n") as file: + file.write(f'{to_json(settings)[:-1]},"frames":[\n{lines}\n]}}\n') + + +def to_json(value): + """Compact JSON with sorted keys, and numbers rounded to 6 significant digits, as the Rust + example writes it.""" + return json.dumps(rounded(value), sort_keys=True, separators=(",", ":"), ensure_ascii=False) + + +def rounded(value): + if isinstance(value, dict): + return {key: rounded(item) for key, item in value.items()} + if isinstance(value, (list, tuple)): + return [rounded(item) for item in value] + if isinstance(value, float): + return float(f"{value:.5e}") if math.isfinite(value) else None + return value diff --git a/examples/hg_bat/trace.rs b/examples/hg_bat/trace.rs new file mode 100644 index 00000000..755266ef --- /dev/null +++ b/examples/hg_bat/trace.rs @@ -0,0 +1,261 @@ +//! The trace for the plot on the example's page, written to the file that `GENOXIDE_TRACE` names. +//! The plot draws the population on the function's contour, which needs two dimensions: the trace +//! is of a separate run of CMA-ES with IPOP restarts in 2 dimensions, with a budget of +//! 20,000 evaluations, in at most 100 frames. The Python example writes the same +//! file. + +use genoxide::observer::Snapshot; +use genoxide::prelude::*; +use genoxide::problems::{HgBat, Problem}; +use serde_json::{Value, json}; + +// runs CMA-ES with IPOP restarts in 2 dimensions and writes its trace, if GENOXIDE_TRACE is set +pub fn record_small() -> Result<()> { + let Ok(path) = std::env::var("GENOXIDE_TRACE") else { + return Ok(()); + }; + let problem = HgBat::new(2); + let optimum = problem.optimum().expect("known"); + let minimum = optimum.value(); + let budget = 20_000; + let cmaes = Cmaes::builder(problem.representation()) + .restarts(cmaes::Restarts::Ipop) + .minimize() + .seed(1) + .build()?; + let mut frames = Frames::new(100); + Engine::new(cmaes, problem.clone()) + .stop_when(Stop::target(minimum + 1e-8).or(Stop::evaluations(budget))) + .on_generation(|snapshot| { + let population = snapshot.population().iter().map(|x| &x.genome()[..]); + let population: Vec<&[f64]> = population.collect(); + let best = &snapshot.best().genome()[..]; + let state = json!({ "population": population, "best": best }); + frames.push(frame(snapshot, state, minimum)); + }) + .run()?; + let bounds = problem.representation().bounds().to_vec(); + let bounds: Vec<[f64; 2]> = bounds.iter().map(|b| [*b.start(), *b.end()]).collect(); + let minima: Vec<&[f64]> = optimum.solutions().iter().map(|x| &x[..]).collect(); + let settings = json!({ + "format": 1, + "example": "hg_bat", + "objective": "minimize", + "x_label": "evaluations", + "y_label": "error", + "log_y": true, + "optimum": 0.0, + "plot": "contour", + "problem": { + "function": "hg_bat", + "bounds": bounds, + "minima": minima, + }, + }); + write(&path, settings, frames.into_vec()); + Ok(()) +} + +// the frame of a generation: its progress, the errors of its best and of its population's median +// to `minimum` (rounding can put a solution a few ulps below it), and `state` +fn frame(snapshot: &Snapshot<'_, Reals>, state: Value, minimum: f64) -> Value { + let progress = snapshot.progress(); + let error = |value: f64| (value - minimum).max(0.0); + let population = snapshot.population().iter(); + let scores = population.filter_map(|individual| individual.fitness()?.score()); + json!({ + "generation": progress.generation(), + "evaluations": progress.evaluations(), + "best": progress.best().and_then(Fitness::score).map(error), + "median": median(scores.collect()).map(error), + "state": state, + }) +} + +// the median of the scores, None without any +fn median(mut scores: Vec) -> Option { + scores.sort_by(f64::total_cmp); + let middle = scores.len() / 2; + match scores.len() { + 0 => None, + n if n % 2 == 1 => Some(scores[middle]), + _ => Some((scores[middle - 1] + scores[middle]) / 2.0), + } +} + +// ---- the same in every example's trace --------------------------------------------------------- + +// the frames of at most `most` generations, from the part of the run where what the page plots +// changes: the frames after the last change are left out (a run that reached its target, or a +// front that no longer moves), and the rest are spread evenly over the generations up to it. While +// the run goes, up to 8 × `most` frames are kept: every `every`-th generation, with `every` +// doubling whenever there are that many, and the last one. +struct Frames { + most: usize, + every: u64, + kept: Vec<(u64, Value)>, + last: Option<(u64, Value)>, +} + +impl Frames { + fn new(most: usize) -> Self { + let (every, kept, last) = (1, Vec::new(), None); + Self { + most, + every, + kept, + last, + } + } + + fn push(&mut self, frame: Value) { + let generation = frame["generation"].as_u64().expect("a generation"); + if !generation.is_multiple_of(self.every) { + self.last = Some((generation, frame)); + return; + } + self.kept.push((generation, frame)); + self.last = None; + if self.kept.len() == 8 * self.most { + self.every *= 2; + let every = self.every; + self.kept.retain(|(generation, _)| generation % every == 0); + } + } + + fn into_vec(self) -> Vec { + let frames = self.kept.into_iter().chain(self.last); + let frames: Vec = frames.map(|(_, frame)| frame).collect(); + let active = &frames[..=last_change(&frames)]; + let (count, most) = (active.len(), self.most.max(2)); + if count <= most { + return active.to_vec(); + } + let at = |i: usize| active[(i * (count - 1) + (most - 1) / 2) / (most - 1)].clone(); + (0..most).map(at).collect() + } +} + +// the index of the frame after which nothing the page plots changes. To 3 significant digits, as +// a plot shows them: the best, the median and, for a single objective (a numeric best), the state; +// to within a hundredth of their range over the run: a front's hypervolumes, in the state or in a +// grid's series +fn last_change(frames: &[Value]) -> usize { + let Some(last) = frames.len().checked_sub(1) else { + return 0; + }; + let single = frames.iter().any(|frame| frame["best"].is_number()); + let measures = |frame: &Value| -> Vec { + let mut values = Vec::new(); + for value in [&frame["state"]["hypervolume"], &frame["series"]] { + match value { + Value::Number(number) => values.extend(number.as_f64()), + Value::Object(map) => values.extend(map.values().filter_map(Value::as_f64)), + _ => {} + } + } + values + }; + let measured: Vec> = frames.iter().map(measures).collect(); + let end = &measured[last]; + let tolerance: Vec = (0..end.len()) + .map(|k| { + let values = measured.iter().filter_map(|values| values.get(k).copied()); + let (low, high) = values.fold((f64::INFINITY, f64::NEG_INFINITY), |(low, high), v| { + (low.min(v), high.max(v)) + }); + (high - low) / 100.0 + }) + .collect(); + let settled = |i: usize| { + let (frame, final_frame) = (&frames[i], &frames[last]); + let same = + |key: &str, flush: bool| coarse(&frame[key], flush) == coarse(&final_frame[key], flush); + same("best", false) + && same("median", false) + && (!single || same("state", true)) + && measured[i].len() == end.len() + && measured[i] + .iter() + .zip(end) + .zip(&tolerance) + .all(|((value, end), tolerance)| (value - end).abs() <= *tolerance) + }; + let mut first = last; + while first > 0 && settled(first - 1) { + first -= 1; + } + first +} + +// `value` with its numbers to 3 significant digits, as precisely as a plot shows them: two frames +// whose plotted values agree to that precision look the same. With `flush`, for the solutions a +// plot draws on their ranges, numbers below 1e-6 in size count as 0 +fn coarse(value: &Value, flush: bool) -> String { + let join = |items: Vec| items.join(","); + match value { + Value::Number(number) if number.is_f64() => { + let number = number.as_f64().expect("f64"); + let number = if flush && number.abs() < 1e-6 { + 0.0 + } else { + number + }; + format!("{number:.2e}") + } + Value::Array(items) => { + format!( + "[{}]", + join(items.iter().map(|item| coarse(item, flush)).collect()) + ) + } + Value::Object(map) => { + let entry = |(key, item): (&String, &Value)| format!("{key}:{}", coarse(item, flush)); + format!("{{{}}}", join(map.iter().map(entry).collect())) + } + other => other.to_string(), + } +} + +// writes the settings and the frames to `path`, a frame per line +fn write(path: &str, settings: Value, frames: Vec) { + let frames: Vec = frames.iter().map(to_json).collect(); + let settings = to_json(&settings); + let head = &settings[..settings.len() - 1]; + let text = format!("{head},\"frames\":[\n{}\n]}}\n", frames.join(",\n")); + std::fs::write(path, text).expect("the trace is written"); +} + +// compact JSON with sorted keys, and numbers rounded to 6 significant digits and written as +// Python writes them (7542.0, 1e-08): the Python example writes the same file +fn to_json(value: &Value) -> String { + let join = |items: Vec| items.join(","); + match value { + Value::Number(number) if number.is_f64() => python_float(number.as_f64().expect("f64")), + Value::Array(items) => format!("[{}]", join(items.iter().map(to_json).collect())), + Value::Object(map) => { + let entry = + |(key, item): (&String, &Value)| format!("{}:{}", json!(key), to_json(item)); + format!("{{{}}}", join(map.iter().map(entry).collect())) + } + other => other.to_string(), + } +} + +fn python_float(value: f64) -> String { + let rounded: f64 = format!("{value:.5e}").parse().expect("a number"); + let shortest = format!("{rounded:e}"); + let (mantissa, exponent) = shortest.split_once('e').expect("an exponent"); + let exponent: i32 = exponent.parse().expect("an exponent"); + if (-4..16).contains(&exponent) { + let text = rounded.to_string(); + if text.contains('.') { + text + } else { + text + ".0" + } + } else { + let sign = if exponent < 0 { '-' } else { '+' }; + format!("{mantissa}e{sign}{:02}", exponent.abs()) + } +} diff --git a/examples/high_conditioned_elliptic/README.md b/examples/high_conditioned_elliptic/README.md new file mode 100644 index 00000000..e2154009 --- /dev/null +++ b/examples/high_conditioned_elliptic/README.md @@ -0,0 +1,91 @@ +--- +title: High-conditioned elliptic +category: continuous +summary: Minimize an ellipsoid with a condition number of 10⁶ in 30 dimensions, as it is and shifted and rotated as CEC 2005's F3, and compare CMA-ES, sep-CMA-ES, DE, PSO and a GA. +reference: "Suganthan, P. N., Hansen, N., Liang, J. J., Deb, K., Chen, Y.-P., Auger, A. and Tiwari, S. (2005). Problem Definitions and Evaluation Criteria for the CEC 2005 Special Session on Real-Parameter Optimization. Nanyang Technological University and KanGAL report 2005005." +reference_url: "https://github.com/P-N-Suganthan/CEC2005" +optimum: "0 (at the origin)" +languages: [rust, python] +order: 54 +trace_note: "Recorded from another run: CMA-ES in 2 dimensions on the function rotated with seed 1, so that the population can be drawn on the function's contour." +--- + +# High-conditioned elliptic + +## The problem + +The high-conditioned elliptic function is an ellipsoid whose weights grow geometrically from the +first gene to the last: + +```text +f(x) = Σ (10⁶)^((i−1)/(n−1)) xᵢ², i from 1 to n, each xᵢ in [−100, 100] +``` + +Its minimum is 0, at the origin. Here n = 30. It's the function F3 of the CEC 2005 report +(Suganthan et al. 2005), which shifts and rotates it, and gives these bounds; the CEC 2014 and +2017 reports have the same basic function, and BBOB's f2 and f10 (Hansen et al. 2009) the same +ellipsoid with an oscillation that genoxide doesn't apply. + +## What makes it hard + +The weights run from 1 to 10⁶: the ellipsoid's axes from 1 to 1,000 in length, a condition number +of 10⁶. Along the first gene the function is a million times flatter than along the last. A search +with one step size for every direction either crawls along the flat axes or overshoots along the +steep ones: it must learn a scale per direction. + +As it is, those directions are the genes' axes, and a scale per gene is enough. Shifted and +rotated, as in CEC 2005, they're 30 random directions: only a full covariance matrix, with its +465 parameters, can learn them. + +## Representation + +A `Real` genome of 30 genes: the point x itself. The fitness is f(x), to minimize. The function is +genoxide's `problems::HighConditionedElliptic`, which brings its bounds and its minimum, and the shifted and rotated +instance `problems::Rotated::new(problems::Shifted::new(function, 1), 1)`, which keeps them. + +## Algorithm + +Five algorithms, each with a budget of 10,000 evaluations per dimension, 300,000 in all, and a +target of 1e-8, from seed 1: + +- CMA-ES (Hansen and Ostermeier, 2001, Evolutionary Computation 9(2): 159-195), which samples a + population of 14 from a normal distribution and adapts its mean, its step size and its covariance + matrix, from a step size of 0.3 of each gene's range and a random start; +- sep-CMA-ES (Ros and Hansen, 2008, PPSN X: 296-305), the same with a diagonal covariance matrix: a + scale per gene but no correlations; +- differential evolution with genoxide's defaults, SHADE (Tanabe and Fukunaga, CEC 2013), with a + population of 100; +- particle swarm optimization (Kennedy and Eberhart, 1995), 40 particles with Clerc and Kennedy's + constriction coefficients and a global topology; +- a real-coded genetic algorithm: a population of 100, tournaments of 3, simulated binary crossover + (Deb and Agrawal, 1995) with η = 15 and polynomial mutation with η = 20 at a rate of 1/30 per + gene. + +The second table runs the same algorithms on the function shifted and rotated, with genoxide's +`problems::Shifted` and `problems::Rotated` and seed 1: the minimum moves to a random point in the +middle 80% of the box, and an orthogonal matrix, drawn from normal numbers made orthonormal by +Gram-Schmidt as BBOB draws its rotations, turns the function about it. That's how the CEC and BBOB +suites use the function, with their own data; genoxide generates its instances instead. + +## Output + +The first line gives the dimension and the budget. Then two tables, the function as it is and shifted and rotated: a row per algorithm, the +evaluations it had used when its best error first reached each value of the heading, and the best +error it found, to two significant digits. A dash is an error not reached. The function is +evaluated with genoxide's portable math, so the runs are the same on every platform, and in Python, +`run` evaluates it in Rust, so both versions print the same. + +[The project page](https://tachsin.gr/projects/genoxide/examples/high-conditioned-elliptic) plays back another +run: CMA-ES on the function in 2 dimensions, x₁² + 10⁶ x₂², rotated with seed 1, so that the +population can be drawn on its contour. It meets the target after 654 evaluations. + +## Good results + +The minimum is 0. As it is, sep-CMA-ES reaches 1e-8 first, after 9,016 evaluations: a scale per +gene fits the ellipsoid. PSO takes 35,320, CMA-ES 39,242 (most of them, 36,036, to reach an error of +1, while its covariance matrix learns the scales), and SHADE 40,100. The genetic algorithm ends at +0.92. + +Shifted and rotated, as CEC 2005's F3, CMA-ES takes the same 39,550 evaluations: for its full +covariance matrix, a rotation changes nothing. Every other algorithm fails: sep-CMA-ES ends at +5.6·10⁴, SHADE at 2.7·10³, PSO at 1.2·10⁶ and the genetic algorithm at 4.8·10⁶. diff --git a/examples/high_conditioned_elliptic/main.py b/examples/high_conditioned_elliptic/main.py new file mode 100644 index 00000000..dae906dd --- /dev/null +++ b/examples/high_conditioned_elliptic/main.py @@ -0,0 +1,97 @@ +"""High-conditioned elliptic: minimize an ellipsoid whose axes range from 1 to 1000 in length, in 30 +dimensions, as it is and shifted and rotated, as CEC 2005's F3. + +Compares how fast CMA-ES, with a full and with a diagonal covariance matrix (sep-CMA-ES), +differential evolution, particle swarm optimization and a real-coded genetic algorithm close in on +the minimum, 0 at the origin: the evaluations each takes until its error is at most 1, 1e-2, 1e-4, 1e-6 and 1e-8. +The function is genoxide's `problems::HighConditionedElliptic`. Then the same on the function shifted and rotated, with genoxide's `problems::Shifted` +and `problems::Rotated`, as the CEC and BBOB suites transform it. + +With ``GENOXIDE_TRACE=``, it also writes a trace of a run for the plot on the example's page, +with trace.py. + + python examples/high_conditioned_elliptic/main.py +""" + +import genoxide as gx + +from trace import record_small + +DIMENSIONS = 30 +BUDGET = 10_000 * DIMENSIONS +# the errors at which the table gives each run's evaluations +ERRORS = [1e0, 1e-2, 1e-4, 1e-6, 1e-8] +COLUMNS = ["1", "1e-2", "1e-4", "1e-6", "1e-8"] + + +def error_text(error): + """An error to two significant digits, as Rust writes it: 9.9e-9.""" + mantissa, exponent = f"{error:.1e}".split("e") + return f"{mantissa}e{int(exponent)}" + + +class Reached: + """The evaluations after the first generation whose best error was at most each of ERRORS, + for a function whose minimum is ``minimum``.""" + + def __init__(self, minimum): + self.minimum = minimum + self.evaluations = [None] * len(ERRORS) + + def record(self, progress): + if progress.best_fitness is None: + return + error = progress.best_fitness - self.minimum + for i, bound in enumerate(ERRORS): + if self.evaluations[i] is None and error <= bound: + self.evaluations[i] = progress.evaluations + + def print(self, name, result): + """A row of the table: the evaluations, "-" for an error not reached, and the best + error.""" + cells = ["-" if reached is None else str(reached) for reached in self.evaluations] + # rounding can put a solution a few ulps below the minimum + cells.append(error_text(max(result.best_fitness - self.minimum, 0.0))) + print(f"{name:<10}" + "".join(f"{cell:>9}" for cell in cells)) + + +def compare(name, problem): + """The table of the five algorithms on ``problem``, after a line that names it.""" + minimum = problem.optimum.value + print(f"{name}: evaluations until the error is at most") + print(f"{'algorithm':<10}" + "".join(f"{column:>9}" for column in COLUMNS) + f"{'best':>9}") + genome = problem.genome + for label, algorithm in ( + ("CMA-ES", gx.Cmaes(genome, objective="minimize", seed=1)), + ("sep-CMA-ES", gx.Cmaes(genome, covariance="diagonal", objective="minimize", seed=1)), + ("DE", gx.De(genome, objective="minimize", seed=1)), + ("PSO", gx.Pso(genome, population_size=40, objective="minimize", seed=1)), + ( + "GA", + gx.Ga( + genome, + population_size=100, + select=gx.Tournament(3), + crossover=gx.SimulatedBinaryCrossover(15.0), + mutation=gx.PolynomialMutation(20.0, rate=1 / DIMENSIONS), + objective="minimize", + seed=1, + ), + ), + ): + reached = Reached(minimum) + result = algorithm.run( + problem, target=minimum + 1e-8, evaluations=BUDGET, on_generation=reached.record + ) + reached.print(label, result) + + +print(f"High-conditioned elliptic in {DIMENSIONS} dimensions, {BUDGET} evaluations at most") +compare("High-conditioned elliptic", gx.problems.HighConditionedElliptic(DIMENSIONS)) +# CEC 2005's F3, with genoxide's own shift and rotation +rotated = gx.problems.Rotated(gx.problems.Shifted(gx.problems.HighConditionedElliptic(DIMENSIONS), seed=1), seed=1) +compare("Shifted and rotated (seed 1)", rotated) + +# with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate run in +# 2 dimensions: the plot is the function's contour +record_small() diff --git a/examples/high_conditioned_elliptic/main.rs b/examples/high_conditioned_elliptic/main.rs new file mode 100644 index 00000000..76772360 --- /dev/null +++ b/examples/high_conditioned_elliptic/main.rs @@ -0,0 +1,151 @@ +//! High-conditioned elliptic: minimize an ellipsoid whose axes range from 1 to 1000 in length, in 30 +//! dimensions, as it is and shifted and rotated, as CEC 2005's F3. +//! +//! Compares how fast CMA-ES, with a full and with a diagonal covariance matrix (sep-CMA-ES), +//! differential evolution, particle swarm optimization and a real-coded genetic algorithm close in +//! on the minimum, 0 at the origin: the evaluations each takes until its error is at most 1, 1e-2, 1e-4, 1e-6 and 1e-8. +//! The function is genoxide's `problems::HighConditionedElliptic`. Then the same on the function shifted and rotated, with genoxide's `problems::Shifted` +//! and `problems::Rotated`, as the CEC and BBOB suites transform it. +//! +//! With `GENOXIDE_TRACE=`, it also writes a trace of a run for the plot on the example's +//! page, with `trace.rs`. +//! +//! ```text +//! cargo run --release --example high_conditioned_elliptic +//! ``` + +mod trace; + +use genoxide::observer::Snapshot; +use genoxide::prelude::*; +use genoxide::problems::{HighConditionedElliptic, Problem, Rotated, Shifted}; + +const DIMENSIONS: usize = 30; +const BUDGET: u64 = 10_000 * DIMENSIONS as u64; +// the errors at which the table gives each run's evaluations +const ERRORS: [f64; 5] = [1e0, 1e-2, 1e-4, 1e-6, 1e-8]; +const COLUMNS: [&str; 5] = ["1", "1e-2", "1e-4", "1e-6", "1e-8"]; + +fn main() -> Result<()> { + println!("High-conditioned elliptic in {DIMENSIONS} dimensions, {BUDGET} evaluations at most"); + compare("High-conditioned elliptic", &HighConditionedElliptic::new(DIMENSIONS))?; + // CEC 2005's F3, with genoxide's own shift and rotation + let rotated = Rotated::new(Shifted::new(HighConditionedElliptic::new(DIMENSIONS), 1), 1); + compare("Shifted and rotated (seed 1)", &rotated)?; + // with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate + // run in 2 dimensions: the plot is the function's contour + trace::record_small()?; + Ok(()) +} + +// the table of the five algorithms on `problem`, after a line that names it +fn compare

(name: &str, problem: &P) -> Result<()> +where + P: Problem + FitnessFunction + Clone, +{ + let minimum = problem.optimum().expect("known").value(); + let stop = || Stop::target(minimum + 1e-8).or(Stop::evaluations(BUDGET)); + println!("{name}: evaluations until the error is at most"); + print!("{:<10}", "algorithm"); + COLUMNS.iter().for_each(|column| print!("{column:>9}")); + println!("{:>9}", "best"); + + for (name, covariance) in [ + ("CMA-ES", cmaes::Covariance::Full), + ("sep-CMA-ES", cmaes::Covariance::Diagonal), + ] { + let cmaes = Cmaes::builder(problem.representation()) + .covariance(covariance) + .minimize() + .seed(1) + .build()?; + let mut reached = Reached::new(minimum); + let outcome = Engine::new(cmaes, problem.clone()) + .stop_when(stop()) + .on_generation(|snapshot| reached.record(snapshot)) + .run()?; + reached.print(name, &outcome); + } + + let de = De::builder(problem.representation()) + .minimize() + .seed(1) + .build()?; + let mut reached = Reached::new(minimum); + let outcome = Engine::new(de, problem.clone()) + .stop_when(stop()) + .on_generation(|snapshot| reached.record(snapshot)) + .run()?; + reached.print("DE", &outcome); + + let pso = Pso::builder(problem.representation()) + .population_size(40) + .minimize() + .seed(1) + .build()?; + let mut reached = Reached::new(minimum); + let outcome = Engine::new(pso, problem.clone()) + .stop_when(stop()) + .on_generation(|snapshot| reached.record(snapshot)) + .run()?; + reached.print("PSO", &outcome); + + let ga = Ga::builder(problem.representation()) + .population_size(100) + .select(Tournament::new(3)?) + .crossover(SimulatedBinaryCrossover::new(15.0)?) + .mutate(PolynomialMutation::per_gene(1.0 / DIMENSIONS as f64, 20.0)?) + .minimize() + .seed(1) + .build()?; + let mut reached = Reached::new(minimum); + let outcome = Engine::new(ga, problem.clone()) + .stop_when(stop()) + .on_generation(|snapshot| reached.record(snapshot)) + .run()?; + reached.print("GA", &outcome); + Ok(()) +} + +// the evaluations after the first generation whose best error was at most each of ERRORS, for a +// function whose minimum is `minimum` +struct Reached { + minimum: f64, + evaluations: [Option; 5], +} + +impl Reached { + fn new(minimum: f64) -> Self { + let evaluations = [None; 5]; + Self { + minimum, + evaluations, + } + } + + fn record(&mut self, snapshot: &Snapshot<'_, Reals>) { + let progress = snapshot.progress(); + let Some(best) = progress.best().and_then(Fitness::score) else { + return; + }; + let error = best - self.minimum; + for (reached, bound) in self.evaluations.iter_mut().zip(ERRORS) { + if reached.is_none() && error <= bound { + *reached = Some(progress.evaluations()); + } + } + } + + // a row of the table: the evaluations, "-" for an error not reached, and the best error + fn print(&self, name: &str, outcome: &Outcome) { + print!("{name:<10}"); + for reached in self.evaluations { + let reached = reached.map_or("-".to_string(), |evaluations| evaluations.to_string()); + print!("{reached:>9}"); + } + // rounding can put a solution a few ulps below the minimum + let best = outcome.best_fitness().score().expect("valid"); + let error = (best - self.minimum).max(0.0); + println!("{:>9}", format!("{error:.1e}")); + } +} diff --git a/examples/high_conditioned_elliptic/output.txt b/examples/high_conditioned_elliptic/output.txt new file mode 100644 index 00000000..9869191e --- /dev/null +++ b/examples/high_conditioned_elliptic/output.txt @@ -0,0 +1,15 @@ +High-conditioned elliptic in 30 dimensions, 300000 evaluations at most +High-conditioned elliptic: evaluations until the error is at most +algorithm 1 1e-2 1e-4 1e-6 1e-8 best +CMA-ES 36036 36778 37688 38444 39242 9.6e-9 +sep-CMA-ES 6076 6902 7644 8302 9016 8.3e-9 +DE 22300 26900 31600 36000 40100 9.7e-9 +PSO 18920 23240 26760 30520 35320 9.8e-9 +GA 273848 - - - - 9.2e-1 +Shifted and rotated (seed 1): evaluations until the error is at most +algorithm 1 1e-2 1e-4 1e-6 1e-8 best +CMA-ES 34076 37156 37982 38696 39550 9.6e-9 +sep-CMA-ES - - - - - 5.6e4 +DE - - - - - 2.7e3 +PSO - - - - - 1.2e6 +GA - - - - - 4.8e6 diff --git a/examples/high_conditioned_elliptic/trace.json b/examples/high_conditioned_elliptic/trace.json new file mode 100644 index 00000000..1f4bd52d --- /dev/null +++ b/examples/high_conditioned_elliptic/trace.json @@ -0,0 +1,102 @@ +{"example":"high_conditioned_elliptic","format":1,"log_y":true,"objective":"minimize","optimum":0.0,"plot":"contour","problem":{"bounds":[[-100.0,100.0],[-100.0,100.0]],"function":"high_conditioned_elliptic","minima":[[0.0,0.0]],"rotation":{"center":[0.0,0.0],"matrix":[[-0.973552,0.228466],[-0.228466,-0.973552]]}},"x_label":"evaluations","y_label":"error","frames":[ +{"best":324790000.0,"evaluations":6,"generation":0,"median":3344650000.0,"state":{"best":[42.8992,-28.5787],"population":[[-80.5712,-24.4639],[21.9455,-61.072],[-54.0471,75.3763],[-21.4189,-92.999],[-75.1217,-72.6119],[42.8992,-28.5787]]}}, +{"best":102729000.0,"evaluations":12,"generation":1,"median":405169000.0,"state":{"best":[83.6137,-9.21133],"population":[[-47.8678,-10.7098],[83.6137,-9.21133],[54.0489,-44.4305],[3.47724,18.2277],[-81.73,38.5048],[-37.8744,-85.0155]]}}, +{"best":102729000.0,"evaluations":18,"generation":2,"median":4109780000.0,"state":{"best":[83.6137,-9.21133],"population":[[77.6414,45.6579],[93.281,32.0635],[-18.3396,72.0666],[-76.9782,54.619],[12.3031,-99.614],[-57.1569,-64.6161]]}}, +{"best":102729000.0,"evaluations":24,"generation":3,"median":2581690000.0,"state":{"best":[83.6137,-9.21133],"population":[[76.2247,29.5326],[-57.743,-70.2656],[-31.3625,63.9198],[-34.3328,-13.161],[50.2519,98.7305],[-53.1866,30.9413]]}}, +{"best":454006.0,"evaluations":30,"generation":4,"median":3265140000.0,"state":{"best":[-30.1175,6.37636],"population":[[82.1263,90.2453],[-79.1942,77.2839],[17.987,63.2613],[0.0503936,-2.82657],[-56.4258,-45.4466],[-30.1175,6.37636]]}}, +{"best":454006.0,"evaluations":36,"generation":5,"median":505009000.0,"state":{"best":[-30.1175,6.37636],"population":[[-9.0962,-67.4201],[-33.9259,36.6687],[11.433,10.2228],[-69.7266,31.9041],[-27.2162,9.04978],[-8.74004,40.5128]]}}, +{"best":454006.0,"evaluations":48,"generation":7,"median":757789000.0,"state":{"best":[-30.1175,6.37636],"population":[[12.0072,44.8459],[-14.3048,27.5919],[-31.9639,69.1319],[-13.3313,34.9359],[-22.7025,13.3391],[-78.7527,40.5143]]}}, +{"best":454006.0,"evaluations":54,"generation":8,"median":685790000.0,"state":{"best":[-30.1175,6.37636],"population":[[-48.1152,34.5515],[-27.9017,45.162],[-49.9307,34.2769],[-54.6389,-17.2788],[-6.91456,-29.1856],[-20.1104,16.803]]}}, +{"best":454006.0,"evaluations":60,"generation":9,"median":301257000.0,"state":{"best":[-30.1175,6.37636],"population":[[-35.8657,26.0841],[-35.961,4.9245],[-10.3261,34.0262],[-31.9173,25.4778],[-46.2147,30.4707],[-8.26173,-0.131052]]}}, +{"best":454006.0,"evaluations":66,"generation":10,"median":333259000.0,"state":{"best":[-30.1175,6.37636],"population":[[-0.750465,-13.0488],[-26.0218,11.8147],[-58.2912,46.7029],[-42.7814,44.4715],[-10.0519,25.3442],[-49.8409,9.63321]]}}, +{"best":454006.0,"evaluations":72,"generation":11,"median":75111800.0,"state":{"best":[-30.1175,6.37636],"population":[[-43.7373,29.9255],[-20.3599,16.1433],[-38.9415,9.88032],[-35.827,13.8227],[-17.3474,42.9873],[-55.3843,9.09803]]}}, +{"best":454006.0,"evaluations":78,"generation":12,"median":134156000.0,"state":{"best":[-30.1175,6.37636],"population":[[-52.3318,-0.112492],[-34.833,31.5575],[-49.3784,-5.25581],[-62.5566,26.0595],[-23.0041,13.5482],[-49.6119,10.3299]]}}, +{"best":454006.0,"evaluations":84,"generation":13,"median":64802300.0,"state":{"best":[-30.1175,6.37636],"population":[[-41.2545,-1.19067],[-56.2775,36.5122],[-33.8925,8.68077],[-42.9231,26.9021],[-28.8489,9.1947],[-52.2856,7.96444]]}}, +{"best":454006.0,"evaluations":90,"generation":14,"median":17371300.0,"state":{"best":[-30.1175,6.37636],"population":[[-10.8473,4.82932],[-45.806,16.2754],[-7.83214,-1.8242],[-51.984,9.51829],[-50.8261,7.10653],[-20.2936,10.8655]]}}, +{"best":454006.0,"evaluations":96,"generation":15,"median":34467100.0,"state":{"best":[-30.1175,6.37636],"population":[[-22.7323,12.0617],[-31.6892,9.28557],[-9.40079,9.01428],[-29.6002,19.4256],[-32.4895,12.8661],[-31.2741,4.25941]]}}, +{"best":454006.0,"evaluations":102,"generation":16,"median":9742660.0,"state":{"best":[-30.1175,6.37636],"population":[[-48.7693,8.8082],[-44.7548,14.1908],[-23.4826,10.9157],[-36.1309,7.31238],[-25.9035,14.66],[-34.4763,8.84871]]}}, +{"best":185773.0,"evaluations":108,"generation":17,"median":1121350.0,"state":{"best":[-47.6292,11.6171],"population":[[-47.6292,11.6171],[-28.4915,5.50054],[-49.0649,10.5662],[-42.5518,15.8056],[-33.5548,12.5449],[-24.7577,4.83069]]}}, +{"best":173200.0,"evaluations":120,"generation":19,"median":4045440.0,"state":{"best":[-33.7706,8.351],"population":[[-50.5052,15.4549],[-54.4908,14.4159],[-38.6444,7.75931],[-42.1923,12.3261],[-28.061,5.31575],[-33.1468,11.3309]]}}, +{"best":173200.0,"evaluations":126,"generation":20,"median":1632280.0,"state":{"best":[-33.7706,8.351],"population":[[-34.3872,8.98522],[-30.7301,5.53711],[-40.3661,5.70237],[-26.1693,5.56119],[-39.5774,7.67429],[-31.2045,6.52239]]}}, +{"best":173200.0,"evaluations":132,"generation":21,"median":2188350.0,"state":{"best":[-33.7706,8.351],"population":[[-29.5726,7.80609],[-30.4169,5.67195],[-39.3383,7.4272],[-27.2753,4.83022],[-28.9596,5.75529],[-34.828,11.0718]]}}, +{"best":76309.9,"evaluations":138,"generation":22,"median":1717160.0,"state":{"best":[-30.6776,7.48107],"population":[[-33.0201,5.6731],[-17.8906,2.84023],[-38.6122,9.67091],[-30.6776,7.48107],[-34.6749,9.78617],[-27.0237,7.67497]]}}, +{"best":4175.8,"evaluations":144,"generation":23,"median":776972.0,"state":{"best":[-35.1519,8.30422],"population":[[-30.3184,8.09107],[-27.1294,5.0021],[-35.1519,8.30422],[-35.9147,7.61605],[-35.5468,9.16899],[-32.0592,9.33092]]}}, +{"best":4175.8,"evaluations":150,"generation":24,"median":50800.3,"state":{"best":[-35.1519,8.30422],"population":[[-31.098,9.32376],[-34.9867,6.57975],[-42.8053,10.213],[-32.9897,7.66956],[-35.1923,8.03369],[-34.9947,7.98024]]}}, +{"best":4175.8,"evaluations":156,"generation":25,"median":326248.0,"state":{"best":[-35.1519,8.30422],"population":[[-38.5119,9.44969],[-39.8157,9.02238],[-41.6523,10.4923],[-37.345,8.65268],[-37.2325,7.33909],[-36.4111,9.46222]]}}, +{"best":4175.8,"evaluations":162,"generation":26,"median":285345.0,"state":{"best":[-35.1519,8.30422],"population":[[-38.1515,8.38702],[-37.5511,9.64045],[-39.7068,7.99219],[-36.2923,8.73398],[-34.9843,7.68193],[-35.8458,8.29323]]}}, +{"best":3282.76,"evaluations":168,"generation":27,"median":119519.0,"state":{"best":[-31.2543,7.28576],"population":[[-32.1267,7.72549],[-36.206,8.06823],[-31.2543,7.28576],[-35.4518,8.06285],[-39.4931,8.58126],[-36.7597,7.50413]]}}, +{"best":1630.91,"evaluations":174,"generation":28,"median":94191.8,"state":{"best":[-39.1507,9.19138],"population":[[-35.0579,8.42366],[-39.1507,9.19138],[-34.4517,7.91422],[-34.3869,7.63517],[-33.7725,7.50855],[-29.5823,7.33935]]}}, +{"best":1630.91,"evaluations":180,"generation":29,"median":103952.0,"state":{"best":[-39.1507,9.19138],"population":[[-38.2513,8.51099],[-38.6943,9.39392],[-42.005,9.69873],[-35.9,9.13933],[-37.9415,9.1779],[-41.2478,10.0226]]}}, +{"best":1630.91,"evaluations":192,"generation":31,"median":41425.5,"state":{"best":[-39.1507,9.19138],"population":[[-33.1314,8.16241],[-34.9138,8.10928],[-38.519,8.9753],[-37.2701,8.60387],[-34.4603,8.45384],[-39.572,9.53914]]}}, +{"best":1630.91,"evaluations":198,"generation":32,"median":36478.2,"state":{"best":[-39.1507,9.19138],"population":[[-37.9689,8.82066],[-38.0926,8.62016],[-33.3567,7.56034],[-33.0327,7.54383],[-37.8078,8.82932],[-36.2564,8.33223]]}}, +{"best":1630.91,"evaluations":204,"generation":33,"median":24939.7,"state":{"best":[-39.1507,9.19138],"population":[[-38.6462,8.94277],[-39.3892,9.23318],[-37.4371,8.60262],[-36.4526,8.29698],[-37.4759,8.60725],[-35.548,8.41692]]}}, +{"best":1606.92,"evaluations":210,"generation":34,"median":4625.66,"state":{"best":[-38.9498,9.13785],"population":[[-38.9997,9.21462],[-37.2527,8.7208],[-37.6753,8.7905],[-38.9498,9.13785],[-37.398,8.60167],[-39.6189,9.39726]]}}, +{"best":1606.92,"evaluations":216,"generation":35,"median":4262.66,"state":{"best":[-38.9498,9.13785],"population":[[-38.323,9.06581],[-38.5982,9.06573],[-40.453,9.47626],[-39.3031,9.37073],[-37.8598,8.87088],[-38.0584,9.04436]]}}, +{"best":1606.92,"evaluations":222,"generation":36,"median":2142.68,"state":{"best":[-38.9498,9.13785],"population":[[-38.2241,8.93687],[-37.6168,8.76864],[-38.8923,9.11874],[-39.0004,9.16021],[-38.4506,9.03525],[-38.4477,8.97332]]}}, +{"best":1534.04,"evaluations":228,"generation":37,"median":2270.66,"state":{"best":[-38.0564,8.92825],"population":[[-38.6857,9.05975],[-39.0723,9.12509],[-39.1028,9.14489],[-39.2042,9.15391],[-38.0564,8.92825],[-40.1574,9.40635]]}}, +{"best":1534.04,"evaluations":234,"generation":38,"median":2070.34,"state":{"best":[-38.0564,8.92825],"population":[[-38.198,8.94908],[-37.8298,8.90229],[-38.7887,9.02572],[-38.4095,9.03001],[-39.5394,9.24797],[-38.664,9.05096]]}}, +{"best":1524.86,"evaluations":240,"generation":39,"median":1851.89,"state":{"best":[-37.7396,8.86127],"population":[[-37.7396,8.86127],[-38.8101,9.15358],[-38.6312,9.04968],[-37.8157,8.85431],[-38.1326,8.96485],[-38.2041,8.9979]]}}, +{"best":1524.86,"evaluations":246,"generation":40,"median":1914.13,"state":{"best":[-37.7396,8.86127],"population":[[-37.8665,8.86218],[-38.4778,8.97309],[-37.4985,8.82234],[-36.6586,8.62181],[-38.0745,8.91619],[-37.8099,8.88961]]}}, +{"best":1524.86,"evaluations":252,"generation":41,"median":2787.35,"state":{"best":[-37.7396,8.86127],"population":[[-37.7039,8.89022],[-37.5244,8.86147],[-37.3031,8.80135],[-37.6725,8.87027],[-37.4231,8.81321],[-38.2409,8.95438]]}}, +{"best":1469.0,"evaluations":264,"generation":43,"median":1880.54,"state":{"best":[-37.1385,8.71919],"population":[[-38.0672,9.00288],[-37.1385,8.71919],[-37.3568,8.79282],[-37.9456,8.88369],[-37.3238,8.74306],[-37.1297,8.73295]]}}, +{"best":1469.0,"evaluations":270,"generation":44,"median":1608.08,"state":{"best":[-37.1385,8.71919],"population":[[-36.9502,8.68222],[-37.586,8.82797],[-36.9356,8.68301],[-37.5212,8.80504],[-37.2705,8.70533],[-37.1364,8.73254]]}}, +{"best":1452.41,"evaluations":276,"generation":45,"median":1503.57,"state":{"best":[-37.1022,8.70703],"population":[[-37.5328,8.80488],[-37.6335,8.83475],[-37.2077,8.72491],[-37.6207,8.83243],[-37.1022,8.70703],[-37.4802,8.82131]]}}, +{"best":1452.41,"evaluations":282,"generation":46,"median":1540.39,"state":{"best":[-37.1022,8.70703],"population":[[-38.0344,8.92742],[-37.5859,8.81401],[-37.608,8.81089],[-36.5434,8.56346],[-37.3967,8.76551],[-37.4508,8.78443]]}}, +{"best":1443.06,"evaluations":288,"generation":47,"median":1658.09,"state":{"best":[-36.9078,8.65875],"population":[[-37.2144,8.75123],[-37.588,8.81155],[-37.7551,8.8398],[-36.9078,8.65875],[-37.1606,8.72751],[-37.7242,8.83684]]}}, +{"best":1443.06,"evaluations":294,"generation":48,"median":1507.34,"state":{"best":[-36.9078,8.65875],"population":[[-37.4979,8.79354],[-37.1597,8.72669],[-36.6957,8.61883],[-37.1072,8.71907],[-37.4035,8.76412],[-37.0082,8.68742]]}}, +{"best":1394.37,"evaluations":300,"generation":49,"median":1591.51,"state":{"best":[-36.2827,8.51693],"population":[[-36.5866,8.60134],[-37.114,8.72871],[-37.6685,8.84699],[-37.4431,8.79972],[-36.9697,8.67121],[-36.2827,8.51693]]}}, +{"best":1385.76,"evaluations":306,"generation":50,"median":1450.59,"state":{"best":[-36.0498,8.45595],"population":[[-36.3783,8.55352],[-36.5325,8.5761],[-36.7299,8.61142],[-36.9385,8.65749],[-36.3971,8.54092],[-36.0498,8.45595]]}}, +{"best":1338.21,"evaluations":312,"generation":51,"median":1406.85,"state":{"best":[-35.6114,8.35656],"population":[[-36.7392,8.63183],[-35.7806,8.39005],[-35.7014,8.37041],[-36.1704,8.49401],[-35.6114,8.35656],[-35.9007,8.4131]]}}, +{"best":1242.59,"evaluations":318,"generation":52,"median":1399.8,"state":{"best":[-33.927,7.95628],"population":[[-37.0862,8.70157],[-34.6847,8.14298],[-35.4806,8.31079],[-36.2609,8.51135],[-33.927,7.95628],[-34.0917,8.01426]]}}, +{"best":1220.78,"evaluations":324,"generation":53,"median":1463.02,"state":{"best":[-33.8679,7.9512],"population":[[-34.9023,8.19657],[-35.9627,8.45545],[-36.2366,8.52535],[-33.4426,7.84136],[-33.8679,7.9512],[-34.6795,8.16327]]}}, +{"best":1220.78,"evaluations":336,"generation":55,"median":1344.77,"state":{"best":[-33.8679,7.9512],"population":[[-33.2202,7.78404],[-35.2007,8.26072],[-35.6196,8.36339],[-32.9438,7.74504],[-35.3154,8.25383],[-37.8067,8.87629]]}}, +{"best":994.471,"evaluations":342,"generation":56,"median":1292.95,"state":{"best":[-30.5654,7.1698],"population":[[-34.7941,8.1527],[-36.8893,8.6722],[-32.1192,7.5412],[-34.6313,8.11031],[-30.5654,7.1698],[-30.8984,7.23829]]}}, +{"best":994.471,"evaluations":348,"generation":57,"median":1168.34,"state":{"best":[-30.5654,7.1698],"population":[[-29.5138,6.91619],[-32.3709,7.57674],[-30.7753,7.22926],[-31.1988,7.32763],[-30.2762,7.08699],[-31.7307,7.42958]]}}, +{"best":810.754,"evaluations":354,"generation":58,"median":1101.97,"state":{"best":[-26.5332,6.21813],"population":[[-33.1896,7.79627],[-36.0103,8.42133],[-28.9025,6.79318],[-28.5637,6.69719],[-29.7358,6.95972],[-26.5332,6.21813]]}}, +{"best":494.518,"evaluations":360,"generation":59,"median":1003.97,"state":{"best":[-21.6171,5.07418],"population":[[-18.6321,4.39481],[-25.7701,6.0697],[-21.9721,5.16567],[-28.8284,6.73808],[-21.6171,5.07418],[-33.449,7.83656]]}}, +{"best":412.853,"evaluations":366,"generation":60,"median":1575.01,"state":{"best":[-18.875,4.43567],"population":[[-26.8071,6.27445],[-30.9792,7.30903],[-23.6158,5.57051],[-18.875,4.43567],[-14.982,3.47538],[-28.6177,6.76632]]}}, +{"best":412.853,"evaluations":372,"generation":61,"median":2114.48,"state":{"best":[-18.875,4.43567],"population":[[-16.836,3.86825],[-21.9495,5.19891],[-26.4677,6.22014],[-7.2453,1.73323],[-37.4293,8.77564],[-8.89054,2.02302]]}}, +{"best":412.853,"evaluations":378,"generation":62,"median":956.286,"state":{"best":[-18.875,4.43567],"population":[[-15.9831,3.72011],[-18.2438,4.26934],[-5.53963,1.32894],[-27.6988,6.51722],[-24.2944,5.66748],[-16.4605,3.83951]]}}, +{"best":412.853,"evaluations":384,"generation":63,"median":2141.36,"state":{"best":[-18.875,4.43567],"population":[[-13.3171,3.06873],[-17.0957,3.94544],[-31.0256,7.28894],[-22.6848,5.30275],[-19.4908,4.46564],[-12.3073,2.87054]]}}, +{"best":289.945,"evaluations":390,"generation":64,"median":467.342,"state":{"best":[-16.3327,3.82984],"population":[[-16.3327,3.82984],[-10.293,2.42943],[-20.5276,4.81635],[-13.8334,3.20085],[-20.9434,4.86071],[-16.2322,3.79432]]}}, +{"best":243.45,"evaluations":396,"generation":65,"median":426.688,"state":{"best":[-15.1567,3.5558],"population":[[-17.0642,4.00217],[-15.2316,3.54637],[-18.9139,4.43745],[-15.1567,3.5558],[-10.3839,2.45632],[-13.6698,3.24247]]}}, +{"best":125.15,"evaluations":408,"generation":67,"median":184.98,"state":{"best":[-9.17695,2.14739],"population":[[-9.17695,2.14739],[-11.9027,2.79103],[-9.49101,2.23741],[-11.2979,2.62025],[-9.87038,2.32518],[-7.36213,1.76561]]}}, +{"best":83.6406,"evaluations":414,"generation":68,"median":158.572,"state":{"best":[-3.03176,0.720303],"population":[[-8.7062,2.0329],[-8.24079,1.92863],[-3.03176,0.720303],[-10.466,2.4407],[-11.1693,2.61845],[-18.9405,4.42609]]}}, +{"best":83.6406,"evaluations":420,"generation":69,"median":577.807,"state":{"best":[-3.03176,0.720303],"population":[[-12.682,3.00623],[0.333083,-0.0480735],[-1.07823,0.269959],[-2.29365,0.555799],[-15.4371,3.67171],[-11.978,2.80824]]}}, +{"best":3.71191,"evaluations":426,"generation":70,"median":209.344,"state":{"best":[0.349727,-0.0840154],"population":[[-2.0816,0.462706],[-5.20491,1.21908],[0.349727,-0.0840154],[-9.85779,2.29189],[-9.03092,2.10976],[-13.7403,3.2174]]}}, +{"best":3.71191,"evaluations":432,"generation":71,"median":98.8057,"state":{"best":[0.349727,-0.0840154],"population":[[0.532595,-0.14237],[-2.83812,0.665565],[-4.76816,1.12135],[-1.92034,0.463581],[7.48614,-1.77085],[0.965781,-0.220629]]}}, +{"best":3.71191,"evaluations":438,"generation":72,"median":43.503,"state":{"best":[0.349727,-0.0840154],"population":[[-4.01289,0.938938],[6.73922,-1.5718],[3.49407,-0.827212],[1.88449,-0.441006],[-5.80294,1.34021],[3.68696,-0.865866]]}}, +{"best":3.71191,"evaluations":444,"generation":73,"median":122.98,"state":{"best":[0.349727,-0.0840154],"population":[[3.36037,-0.793768],[-4.36358,1.04124],[-4.43593,1.05378],[0.764398,-0.182784],[-3.95252,0.93906],[-9.25485,2.16809]]}}, +{"best":3.71191,"evaluations":450,"generation":74,"median":93.7241,"state":{"best":[0.349727,-0.0840154],"population":[[-8.30855,1.94741],[-7.69506,1.80065],[0.422565,-0.109412],[0.419398,-0.0838425],[-0.0422498,0.0223379],[-5.89423,1.38281]]}}, +{"best":1.78757,"evaluations":456,"generation":75,"median":195.056,"state":{"best":[-0.977383,0.228458],"population":[[0.538685,-0.118149],[-14.1676,3.30076],[-0.977383,0.228458],[-10.7886,2.51997],[-12.9577,3.04241],[-7.21111,1.67943]]}}, +{"best":0.157746,"evaluations":462,"generation":76,"median":90.1969,"state":{"best":[0.385636,-0.0905278],"population":[[8.7442,-2.05738],[3.1585,-0.737218],[2.69133,-0.623308],[-6.16802,1.45982],[-0.637155,0.166063],[0.385636,-0.0905278]]}}, +{"best":0.157746,"evaluations":468,"generation":77,"median":55.1328,"state":{"best":[0.385636,-0.0905278],"population":[[-1.78087,0.425479],[-1.92453,0.450078],[5.89917,-1.37815],[1.78123,-0.423912],[5.6472,-1.32075],[3.16587,-0.750491]]}}, +{"best":0.157746,"evaluations":480,"generation":79,"median":17.1568,"state":{"best":[0.385636,-0.0905278],"population":[[6.99406,-1.6449],[2.57987,-0.601622],[1.12392,-0.259911],[-0.438956,0.103063],[-1.17788,0.276103],[1.90824,-0.443812]]}}, +{"best":0.157746,"evaluations":486,"generation":80,"median":4.86762,"state":{"best":[0.385636,-0.0905278],"population":[[-1.08272,0.256975],[-1.84618,0.433836],[-1.44358,0.338303],[0.26886,-0.0655537],[-0.104002,0.0252762],[2.90158,-0.685076]]}}, +{"best":0.157746,"evaluations":492,"generation":81,"median":4.50421,"state":{"best":[0.385636,-0.0905278],"population":[[-1.02375,0.238799],[-1.40029,0.325704],[-0.540083,0.126232],[1.1183,-0.264892],[-1.60133,0.374142],[0.15577,-0.0345762]]}}, +{"best":0.157746,"evaluations":498,"generation":82,"median":2.44353,"state":{"best":[0.385636,-0.0905278],"population":[[-0.778837,0.182806],[-0.249167,0.0591179],[-0.52117,0.119981],[-1.84079,0.429934],[-1.56649,0.366406],[0.797365,-0.187634]]}}, +{"best":0.0426877,"evaluations":504,"generation":83,"median":2.40346,"state":{"best":[0.096025,-0.0227209],"population":[[-2.05169,0.482334],[-1.51314,0.356598],[-1.44607,0.340018],[0.096025,-0.0227209],[-1.19469,0.281206],[0.469932,-0.109445]]}}, +{"best":0.0116513,"evaluations":510,"generation":84,"median":0.950453,"state":{"best":[-0.0156869,0.00379091],"population":[[0.309608,-0.0733184],[-0.0156869,0.00379091],[-0.281624,0.0641721],[-0.420817,0.0986071],[1.18244,-0.278285],[0.099168,-0.022068]]}}, +{"best":0.0116513,"evaluations":516,"generation":85,"median":0.278648,"state":{"best":[-0.0156869,0.00379091],"population":[[-0.3225,0.0754018],[-0.0290429,0.00595159],[0.468095,-0.111211],[0.111082,-0.0255188],[-0.458576,0.107812],[0.351831,-0.0823964]]}}, +{"best":0.0116513,"evaluations":522,"generation":86,"median":0.26803,"state":{"best":[-0.0156869,0.00379091],"population":[[0.225138,-0.0523745],[0.275646,-0.06515],[0.287318,-0.0676385],[0.677062,-0.158425],[0.15707,-0.0369402],[0.449163,-0.105134]]}}, +{"best":0.0112181,"evaluations":528,"generation":87,"median":0.345735,"state":{"best":[0.00191607,-0.000340874],"population":[[0.664635,-0.156318],[-0.199866,0.0470159],[0.391325,-0.0922033],[0.494579,-0.115677],[0.00191607,-0.000340874],[0.273502,-0.065175]]}}, +{"best":0.0112181,"evaluations":534,"generation":88,"median":0.135018,"state":{"best":[0.00191607,-0.000340874],"population":[[0.0986722,-0.0231976],[-0.296137,0.0693646],[-0.0723455,0.0174602],[-0.278579,0.0657716],[-0.218369,0.0515874],[0.213469,-0.0498799]]}}, +{"best":0.0112181,"evaluations":540,"generation":89,"median":0.0608438,"state":{"best":[0.00191607,-0.000340874],"population":[[0.0323999,-0.00772557],[0.0257387,-0.00635896],[0.168795,-0.039761],[-0.092267,0.0215158],[0.260741,-0.060894],[0.232142,-0.0545971]]}}, +{"best":0.000616427,"evaluations":552,"generation":91,"median":0.01944,"state":{"best":[0.00569352,-0.0013609],"population":[[0.0789939,-0.0184117],[-0.0618304,0.0143917],[0.00569352,-0.0013609],[-0.134227,0.0315944],[-0.0580676,0.0134242],[-0.0765647,0.0180664]]}}, +{"best":0.000616427,"evaluations":558,"generation":92,"median":0.0138682,"state":{"best":[0.00569352,-0.0013609],"population":[[0.00297699,-0.000537502],[-0.0950209,0.0221562],[0.0726714,-0.0171075],[-0.0709711,0.016587],[-0.00714099,0.00171573],[-0.0632831,0.0149716]]}}, +{"best":0.000616427,"evaluations":564,"generation":93,"median":0.00945319,"state":{"best":[0.00569352,-0.0013609],"population":[[-0.0584053,0.013811],[0.0677526,-0.0158943],[0.155423,-0.0363945],[0.0184262,-0.00426104],[-0.00310881,0.000781326],[0.0213824,-0.0048511]]}}, +{"best":5.92968e-05,"evaluations":570,"generation":94,"median":0.00375753,"state":{"best":[-0.00492903,0.00116267],"population":[[0.0895207,-0.0210233],[-0.00492903,0.00116267],[0.0017006,-0.000376513],[0.0397261,-0.00924684],[0.0234952,-0.0054933],[0.0484389,-0.0113018]]}}, +{"best":5.92968e-05,"evaluations":576,"generation":95,"median":0.00347914,"state":{"best":[-0.00492903,0.00116267],"population":[[-0.0313136,0.0073121],[0.0328283,-0.00762473],[0.0319394,-0.00744911],[-0.093974,0.022065],[0.0473042,-0.0111006],[0.0253685,-0.00589533]]}}, +{"best":5.92968e-05,"evaluations":582,"generation":96,"median":0.00162345,"state":{"best":[-0.00492903,0.00116267],"population":[[0.00356163,-0.000876185],[-0.0241075,0.0057142],[0.0323476,-0.00757361],[0.0216642,-0.00507791],[0.0399036,-0.00936734],[-0.0466822,0.0109353]]}}, +{"best":5.92968e-05,"evaluations":588,"generation":97,"median":0.00395445,"state":{"best":[-0.00492903,0.00116267],"population":[[0.103455,-0.0242106],[-0.0282566,0.00669964],[0.0642965,-0.0151345],[0.0163625,-0.00379411],[-0.0133959,0.0031571],[0.0367611,-0.00866211]]}}, +{"best":5.92968e-05,"evaluations":594,"generation":98,"median":0.00308425,"state":{"best":[-0.00492903,0.00116267],"population":[[-0.00176995,0.000474336],[0.0357674,-0.00836451],[0.020507,-0.00480928],[0.0261616,-0.00608269],[0.0494742,-0.0115928],[-0.019516,0.00468581]]}}, +{"best":5.92968e-05,"evaluations":600,"generation":99,"median":0.000959696,"state":{"best":[-0.00492903,0.00116267],"population":[[0.0579353,-0.0134832],[-0.00454455,0.0010739],[0.039487,-0.00927402],[0.0191717,-0.00447962],[0.0131243,-0.00308703],[0.0333251,-0.00782183]]}}, +{"best":5.92968e-05,"evaluations":606,"generation":100,"median":0.000321709,"state":{"best":[-0.00492903,0.00116267],"population":[[-0.0422108,0.00992362],[0.00626512,-0.00146436],[-0.00268045,0.000618031],[0.0112103,-0.00265095],[-0.0170246,0.0040008],[0.00572341,-0.00132615]]}}, +{"best":5.92968e-05,"evaluations":612,"generation":101,"median":0.000268782,"state":{"best":[-0.00492903,0.00116267],"population":[[0.00333081,-0.000767093],[0.00208812,-0.000470614],[-0.00912008,0.00213384],[-0.0174087,0.00408769],[-0.0263679,0.00620954],[0.0126819,-0.00296987]]}}, +{"best":2.30292e-05,"evaluations":624,"generation":103,"median":0.000173305,"state":{"best":[-0.00196711,0.000457154],"population":[[0.0106308,-0.00250159],[-0.00196711,0.000457154],[0.0125609,-0.00295409],[0.000297903,-7.63286e-05],[0.023371,-0.00548573],[-0.012337,0.00290003]]}}, +{"best":1.24989e-05,"evaluations":630,"generation":104,"median":0.000166664,"state":{"best":[-0.0022419,0.000528868],"population":[[-0.00276882,0.000639011],[-0.0022419,0.000528868],[-0.0131215,0.00307863],[-0.0115425,0.00269895],[0.00565509,-0.00133956],[-0.00675428,0.00157456]]}}, +{"best":3.56445e-06,"evaluations":636,"generation":105,"median":2.12812e-05,"state":{"best":[0.00164287,-0.000386405],"population":[[-0.00264568,0.00062009],[-0.00679046,0.00158972],[0.00164287,-0.000386405],[0.00322939,-0.000758792],[-0.00347562,0.000808098],[0.00518513,-0.00121523]]}}, +{"best":1.32895e-07,"evaluations":642,"generation":106,"median":7.78499e-06,"state":{"best":[0.00028015,-6.55136e-05],"population":[[0.000760304,-0.000185128],[0.00028015,-6.55136e-05],[-0.00159455,0.000373408],[0.00559904,-0.00131882],[0.000706445,-0.000169307],[0.00133694,-0.000312899]]}}, +{"best":1.32895e-07,"evaluations":648,"generation":107,"median":2.74805e-05,"state":{"best":[0.00028015,-6.55136e-05],"population":[[-0.000109506,2.38728e-05],[-0.00671815,0.00157401],[-0.00247342,0.000580365],[0.00304034,-0.00071913],[0.00312998,-0.000736733],[0.00700117,-0.00164099]]}}, +{"best":6.86842e-09,"evaluations":654,"generation":108,"median":3.85122e-06,"state":{"best":[-7.05725e-05,1.66027e-05],"population":[[-0.00379332,0.000885857],[0.00110697,-0.000258688],[0.00147141,-0.00034352],[0.00114906,-0.000274016],[-7.05725e-05,1.66027e-05],[-0.000508983,0.00011857]]}} +]} diff --git a/examples/high_conditioned_elliptic/trace.py b/examples/high_conditioned_elliptic/trace.py new file mode 100644 index 00000000..107b044b --- /dev/null +++ b/examples/high_conditioned_elliptic/trace.py @@ -0,0 +1,190 @@ +"""The trace for the plot on the example's page, written to the file that ``GENOXIDE_TRACE`` +names. The plot draws the population on the function's contour, which needs two dimensions: the +trace is of a separate run of CMA-ES in 2 dimensions, rotated with seed 1, with a budget of +20,000 evaluations, in at most 100 frames. The Rust example writes the same file.""" + +import json +import math +import os + +import genoxide as gx + + +def record_small(): + """Runs CMA-ES in 2 dimensions and writes its trace, if ``GENOXIDE_TRACE`` is set.""" + path = os.environ.get("GENOXIDE_TRACE") + if not path: + return + problem = gx.problems.Rotated(gx.problems.HighConditionedElliptic(2), seed=1) + minimum = problem.optimum.value + budget = 20_000 + cmaes = gx.Cmaes(problem.genome, objective="minimize", seed=1) + frames = Frames(100) + + def record(progress): + state = {"population": progress.population.tolist(), "best": progress.best_genome.tolist()} + frames.push(frame(progress, state, minimum)) + + cmaes.run(problem, target=minimum + 1e-8, evaluations=budget, on_generation=record) + low, high = problem.genome.bounds + settings = { + "format": 1, + "example": "high_conditioned_elliptic", + "objective": "minimize", + "x_label": "evaluations", + "y_label": "error", + "log_y": True, + "optimum": 0.0, + "plot": "contour", + "problem": { + "function": "high_conditioned_elliptic", + "bounds": [[float(low), float(high)]] * 2, + "minima": problem.optimum.solutions.tolist(), + "rotation": {"matrix": problem.matrix.tolist(), "center": problem.center.tolist()}, + }, + } + write(path, settings, frames.to_list()) + + +def frame(progress, state, minimum): + """The frame of a generation: its progress, the errors of its best and of its population's + median to ``minimum`` (rounding can put a solution a few ulps below it), and ``state``.""" + + def error(value): + return None if value is None else max(value - minimum, 0.0) + + return { + "generation": progress.generation, + "evaluations": progress.evaluations, + "best": error(progress.best_fitness), + "median": error(median(progress.scores)), + "state": state, + } + + +def median(scores): + """The median of the valid scores, None without any.""" + scores = sorted(float(score) for score in scores if not math.isnan(score)) + middle = len(scores) // 2 + if not scores: + return None + return scores[middle] if len(scores) % 2 else (scores[middle - 1] + scores[middle]) / 2 + + +# ---- the same in every example's trace ---------------------------------------------------------- + + +class Frames: + """The frames of at most ``most`` generations, from the part of the run where what the page + plots changes: the frames after the last change are left out (a run that reached its target, + or a front that no longer moves), and the rest are spread evenly over the generations up to + it. While the run goes, up to 8 × ``most`` frames are kept: every ``every``-th generation, + with ``every`` doubling whenever there are that many, and the last one.""" + + def __init__(self, most): + self.most, self.every, self.kept, self.last = most, 1, [], None + + def push(self, frame): + if frame["generation"] % self.every: + self.last = frame + return + self.kept.append(frame) + self.last = None + if len(self.kept) == 8 * self.most: + self.every *= 2 + self.kept = [kept for kept in self.kept if kept["generation"] % self.every == 0] + + def to_list(self): + frames = self.kept + ([self.last] if self.last else []) + active = frames[: last_change(frames) + 1] + count, most = len(active), max(self.most, 2) + if count <= most: + return active + return [active[(i * (count - 1) + (most - 1) // 2) // (most - 1)] for i in range(most)] + + +def last_change(frames): + """The index of the frame after which nothing the page plots changes. To 3 significant + digits, as a plot shows them: the best, the median and, for a single objective (a numeric + best), the state; to within a hundredth of their range over the run: a front's + hypervolumes, in the state or in a grid's series.""" + if not frames: + return 0 + last = len(frames) - 1 + number = lambda value: isinstance(value, (int, float)) and not isinstance(value, bool) + single = any(number(frame.get("best")) for frame in frames) + + def measures(frame): + values = [] + state = frame.get("state") + hypervolume = state.get("hypervolume") if isinstance(state, dict) else None + for value in (hypervolume, frame.get("series")): + if number(value): + values.append(float(value)) + elif isinstance(value, dict): + values.extend(float(v) for _, v in sorted(value.items()) if number(v)) + return values + + measured = [measures(frame) for frame in frames] + end = measured[last] + tolerance = [] + for k in range(len(end)): + values = [values[k] for values in measured if k < len(values)] + tolerance.append((max(values) - min(values)) / 100.0) + + def same(frame, final, key, flush=False): + return coarse(frame.get(key), flush) == coarse(final.get(key), flush) + + def settled(i): + frame, final = frames[i], frames[last] + return ( + same(frame, final, "best") + and same(frame, final, "median") + and (not single or same(frame, final, "state", flush=True)) + and len(measured[i]) == len(end) + and all(abs(v - e) <= t for v, e, t in zip(measured[i], end, tolerance)) + ) + + first = last + while first > 0 and settled(first - 1): + first -= 1 + return first + + +def coarse(value, flush=False): + """``value`` with its numbers to 3 significant digits, as precisely as a plot shows them: two + frames whose plotted values agree to that precision look the same. With ``flush``, for the + solutions a plot draws on their ranges, numbers below 1e-6 in size count as 0.""" + if isinstance(value, float): + if flush and abs(value) < 1e-6: + value = 0.0 + return f"{value:.2e}" + if isinstance(value, (list, tuple)): + return "[" + ",".join(coarse(item, flush) for item in value) + "]" + if isinstance(value, dict): + items = sorted(value.items()) + return "{" + ",".join(f"{key}:{coarse(item, flush)}" for key, item in items) + "}" + return json.dumps(value) + + +def write(path, settings, frames): + """Writes the settings and the frames to ``path``, a frame per line.""" + lines = ",\n".join(map(to_json, frames)) + with open(path, "w", encoding="utf-8", newline="\n") as file: + file.write(f'{to_json(settings)[:-1]},"frames":[\n{lines}\n]}}\n') + + +def to_json(value): + """Compact JSON with sorted keys, and numbers rounded to 6 significant digits, as the Rust + example writes it.""" + return json.dumps(rounded(value), sort_keys=True, separators=(",", ":"), ensure_ascii=False) + + +def rounded(value): + if isinstance(value, dict): + return {key: rounded(item) for key, item in value.items()} + if isinstance(value, (list, tuple)): + return [rounded(item) for item in value] + if isinstance(value, float): + return float(f"{value:.5e}") if math.isfinite(value) else None + return value diff --git a/examples/high_conditioned_elliptic/trace.rs b/examples/high_conditioned_elliptic/trace.rs new file mode 100644 index 00000000..01e5b268 --- /dev/null +++ b/examples/high_conditioned_elliptic/trace.rs @@ -0,0 +1,264 @@ +//! The trace for the plot on the example's page, written to the file that `GENOXIDE_TRACE` names. +//! The plot draws the population on the function's contour, which needs two dimensions: the trace +//! is of a separate run of CMA-ES in 2 dimensions, rotated with seed 1, with a budget of +//! 20,000 evaluations, in at most 100 frames. The Python example writes the same +//! file. + +use genoxide::observer::Snapshot; +use genoxide::prelude::*; +use genoxide::problems::{HighConditionedElliptic, Problem, Rotated}; +use serde_json::{Value, json}; + +// runs CMA-ES in 2 dimensions and writes its trace, if GENOXIDE_TRACE is set +pub fn record_small() -> Result<()> { + let Ok(path) = std::env::var("GENOXIDE_TRACE") else { + return Ok(()); + }; + let problem = Rotated::new(HighConditionedElliptic::new(2), 1); + let optimum = problem.optimum().expect("known"); + let minimum = optimum.value(); + let budget = 20_000; + let cmaes = Cmaes::builder(problem.representation()) + .minimize() + .seed(1) + .build()?; + let mut frames = Frames::new(100); + Engine::new(cmaes, problem.clone()) + .stop_when(Stop::target(minimum + 1e-8).or(Stop::evaluations(budget))) + .on_generation(|snapshot| { + let population = snapshot.population().iter().map(|x| &x.genome()[..]); + let population: Vec<&[f64]> = population.collect(); + let best = &snapshot.best().genome()[..]; + let state = json!({ "population": population, "best": best }); + frames.push(frame(snapshot, state, minimum)); + }) + .run()?; + let bounds = problem.representation().bounds().to_vec(); + let bounds: Vec<[f64; 2]> = bounds.iter().map(|b| [*b.start(), *b.end()]).collect(); + let minima: Vec<&[f64]> = optimum.solutions().iter().map(|x| &x[..]).collect(); + let settings = json!({ + "format": 1, + "example": "high_conditioned_elliptic", + "objective": "minimize", + "x_label": "evaluations", + "y_label": "error", + "log_y": true, + "optimum": 0.0, + "plot": "contour", + "problem": { + "function": "high_conditioned_elliptic", + "bounds": bounds, + "minima": minima, + "rotation": { + "matrix": problem.matrix().chunks(2).collect::>(), + "center": problem.center(), + }, + }, + }); + write(&path, settings, frames.into_vec()); + Ok(()) +} + +// the frame of a generation: its progress, the errors of its best and of its population's median +// to `minimum` (rounding can put a solution a few ulps below it), and `state` +fn frame(snapshot: &Snapshot<'_, Reals>, state: Value, minimum: f64) -> Value { + let progress = snapshot.progress(); + let error = |value: f64| (value - minimum).max(0.0); + let population = snapshot.population().iter(); + let scores = population.filter_map(|individual| individual.fitness()?.score()); + json!({ + "generation": progress.generation(), + "evaluations": progress.evaluations(), + "best": progress.best().and_then(Fitness::score).map(error), + "median": median(scores.collect()).map(error), + "state": state, + }) +} + +// the median of the scores, None without any +fn median(mut scores: Vec) -> Option { + scores.sort_by(f64::total_cmp); + let middle = scores.len() / 2; + match scores.len() { + 0 => None, + n if n % 2 == 1 => Some(scores[middle]), + _ => Some((scores[middle - 1] + scores[middle]) / 2.0), + } +} + +// ---- the same in every example's trace --------------------------------------------------------- + +// the frames of at most `most` generations, from the part of the run where what the page plots +// changes: the frames after the last change are left out (a run that reached its target, or a +// front that no longer moves), and the rest are spread evenly over the generations up to it. While +// the run goes, up to 8 × `most` frames are kept: every `every`-th generation, with `every` +// doubling whenever there are that many, and the last one. +struct Frames { + most: usize, + every: u64, + kept: Vec<(u64, Value)>, + last: Option<(u64, Value)>, +} + +impl Frames { + fn new(most: usize) -> Self { + let (every, kept, last) = (1, Vec::new(), None); + Self { + most, + every, + kept, + last, + } + } + + fn push(&mut self, frame: Value) { + let generation = frame["generation"].as_u64().expect("a generation"); + if !generation.is_multiple_of(self.every) { + self.last = Some((generation, frame)); + return; + } + self.kept.push((generation, frame)); + self.last = None; + if self.kept.len() == 8 * self.most { + self.every *= 2; + let every = self.every; + self.kept.retain(|(generation, _)| generation % every == 0); + } + } + + fn into_vec(self) -> Vec { + let frames = self.kept.into_iter().chain(self.last); + let frames: Vec = frames.map(|(_, frame)| frame).collect(); + let active = &frames[..=last_change(&frames)]; + let (count, most) = (active.len(), self.most.max(2)); + if count <= most { + return active.to_vec(); + } + let at = |i: usize| active[(i * (count - 1) + (most - 1) / 2) / (most - 1)].clone(); + (0..most).map(at).collect() + } +} + +// the index of the frame after which nothing the page plots changes. To 3 significant digits, as +// a plot shows them: the best, the median and, for a single objective (a numeric best), the state; +// to within a hundredth of their range over the run: a front's hypervolumes, in the state or in a +// grid's series +fn last_change(frames: &[Value]) -> usize { + let Some(last) = frames.len().checked_sub(1) else { + return 0; + }; + let single = frames.iter().any(|frame| frame["best"].is_number()); + let measures = |frame: &Value| -> Vec { + let mut values = Vec::new(); + for value in [&frame["state"]["hypervolume"], &frame["series"]] { + match value { + Value::Number(number) => values.extend(number.as_f64()), + Value::Object(map) => values.extend(map.values().filter_map(Value::as_f64)), + _ => {} + } + } + values + }; + let measured: Vec> = frames.iter().map(measures).collect(); + let end = &measured[last]; + let tolerance: Vec = (0..end.len()) + .map(|k| { + let values = measured.iter().filter_map(|values| values.get(k).copied()); + let (low, high) = values.fold((f64::INFINITY, f64::NEG_INFINITY), |(low, high), v| { + (low.min(v), high.max(v)) + }); + (high - low) / 100.0 + }) + .collect(); + let settled = |i: usize| { + let (frame, final_frame) = (&frames[i], &frames[last]); + let same = + |key: &str, flush: bool| coarse(&frame[key], flush) == coarse(&final_frame[key], flush); + same("best", false) + && same("median", false) + && (!single || same("state", true)) + && measured[i].len() == end.len() + && measured[i] + .iter() + .zip(end) + .zip(&tolerance) + .all(|((value, end), tolerance)| (value - end).abs() <= *tolerance) + }; + let mut first = last; + while first > 0 && settled(first - 1) { + first -= 1; + } + first +} + +// `value` with its numbers to 3 significant digits, as precisely as a plot shows them: two frames +// whose plotted values agree to that precision look the same. With `flush`, for the solutions a +// plot draws on their ranges, numbers below 1e-6 in size count as 0 +fn coarse(value: &Value, flush: bool) -> String { + let join = |items: Vec| items.join(","); + match value { + Value::Number(number) if number.is_f64() => { + let number = number.as_f64().expect("f64"); + let number = if flush && number.abs() < 1e-6 { + 0.0 + } else { + number + }; + format!("{number:.2e}") + } + Value::Array(items) => { + format!( + "[{}]", + join(items.iter().map(|item| coarse(item, flush)).collect()) + ) + } + Value::Object(map) => { + let entry = |(key, item): (&String, &Value)| format!("{key}:{}", coarse(item, flush)); + format!("{{{}}}", join(map.iter().map(entry).collect())) + } + other => other.to_string(), + } +} + +// writes the settings and the frames to `path`, a frame per line +fn write(path: &str, settings: Value, frames: Vec) { + let frames: Vec = frames.iter().map(to_json).collect(); + let settings = to_json(&settings); + let head = &settings[..settings.len() - 1]; + let text = format!("{head},\"frames\":[\n{}\n]}}\n", frames.join(",\n")); + std::fs::write(path, text).expect("the trace is written"); +} + +// compact JSON with sorted keys, and numbers rounded to 6 significant digits and written as +// Python writes them (7542.0, 1e-08): the Python example writes the same file +fn to_json(value: &Value) -> String { + let join = |items: Vec| items.join(","); + match value { + Value::Number(number) if number.is_f64() => python_float(number.as_f64().expect("f64")), + Value::Array(items) => format!("[{}]", join(items.iter().map(to_json).collect())), + Value::Object(map) => { + let entry = + |(key, item): (&String, &Value)| format!("{}:{}", json!(key), to_json(item)); + format!("{{{}}}", join(map.iter().map(entry).collect())) + } + other => other.to_string(), + } +} + +fn python_float(value: f64) -> String { + let rounded: f64 = format!("{value:.5e}").parse().expect("a number"); + let shortest = format!("{rounded:e}"); + let (mantissa, exponent) = shortest.split_once('e').expect("an exponent"); + let exponent: i32 = exponent.parse().expect("an exponent"); + if (-4..16).contains(&exponent) { + let text = rounded.to_string(); + if text.contains('.') { + text + } else { + text + ".0" + } + } else { + let sign = if exponent < 0 { '-' } else { '+' }; + format!("{mantissa}e{sign}{:02}", exponent.abs()) + } +} diff --git a/examples/katsuura/README.md b/examples/katsuura/README.md new file mode 100644 index 00000000..08a5f0f1 --- /dev/null +++ b/examples/katsuura/README.md @@ -0,0 +1,90 @@ +--- +title: Katsuura +category: continuous +summary: Minimize Katsuura's function, rugged everywhere, in 10 dimensions, with CMA-ES without and with restarts, DE, PSO and a GA from 10 seeds each. +reference: "Hansen, N., Finck, S., Ros, R. and Auger, A. (2009). Real-Parameter Black-Box Optimization Benchmarking 2009: Noiseless Functions Definitions. INRIA research report RR-6829." +reference_url: "https://hal.inria.fr/inria-00362633" +optimum: "0 (at the origin, and wherever every gene is a multiple of 1/2)" +languages: [rust, python] +order: 96 +trace_note: "Recorded from another run: CMA-ES with IPOP restarts in 2 dimensions, so that the population can be drawn on the function's contour." +--- + +# Katsuura + +## The problem + +Katsuura's function multiplies, over the genes, terms that measure how far the gene's binary +digits are from whole numbers: + +```text +f(x) = (10 / n²) Πᵢ (1 + i Σⱼ₌₁³² |2ʲxᵢ − round(2ʲxᵢ)| / 2ʲ)^(10 / n^1.2) − 10 / n² +each xᵢ in [−5, 5] +``` + +Its minimum is 0, wherever every gene is a multiple of 1/2: then every 2ʲxᵢ is a whole number, and +every factor is 1. There are 21ⁿ such points in the box, among them the origin. Here n = 10. It's +BBOB's f23 (Hansen et al. 2009), "based on the idea" of Katsuura (1991, The American Mathematical +Monthly 98(5): 411-416, not read), without BBOB's rotation and scaling, and its penalty outside +[−5, 5]; the CEC 2014 report has the same basic function. + +## What makes it hard + +Each factor is a continuous, nowhere-differentiable function of its gene, rugged at every scale +down to 2⁻³², and the product couples the genes. The landscape is highly repetitive, with global +minima on a grid of spacing 1/2 and local minima everywhere between: a search that has found a +good region gains little from its neighborhood. + +The grid of global minima includes the bounds, ±5. A search that pushes genes onto the bounds, as +PSO does when a particle would leave the box and stops at the bound, lands on global minima without searching. +BBOB avoids this by rotating and shifting the function; genoxide's `problems::Shifted` does the +same. + +## Representation + +A `Real` genome of 10 genes, each in [−5, 5]: the point x itself. The fitness is f(x), to +minimize. The function is genoxide's `problems::Katsuura`, which brings its bounds and its +minimum. + +## Algorithm + +Five algorithms, each from seeds 1 to 10, with a budget of 10,000 evaluations per dimension, +100,000 per run, and a target of 1e-8: + +- CMA-ES (Hansen and Ostermeier, 2001, Evolutionary Computation 9(2): 159-195), which samples a + population of 10 from a normal distribution and adapts its mean, its step size and its covariance + matrix, from a step size of 0.3 of each gene's range and a random start; +- the same with IPOP restarts (Auger and Hansen, 2005, IEEE CEC 2005: 1769-1776): a run that has + converged starts again from a random point with twice the population; +- differential evolution with genoxide's defaults, SHADE (Tanabe and Fukunaga, CEC 2013), with a + population of 100 and its restarts on stagnation; +- particle swarm optimization (Kennedy and Eberhart, 1995), 40 particles with Clerc and Kennedy's + constriction coefficients and a global topology; +- a real-coded genetic algorithm: a population of 100, tournaments of 3, simulated binary crossover + (Deb and Agrawal, 1995) with η = 15 and polynomial mutation with η = 20 at a rate of 1/10 per + gene. + +## Output + +The first line gives the dimension, the seeds and the budget. Then a row per algorithm: how many +of its 10 runs reached the minimum, to within 1e-8, the median of their evaluations (a dash if none +did), and the median of every run's best error, to two significant digits. The function is +evaluated with genoxide's portable math, so the runs are the same on every platform, and in Python, +`run` evaluates it in Rust, so both versions print the same. + +[The project page](https://tachsin.gr/projects/genoxide/examples/katsuura) plays back another run: +CMA-ES with IPOP restarts on the function in 2 dimensions, so that the population +can be drawn on its contour. It meets the target after 990 evaluations, at a multiple of 1/2. + +## Good results + +The minimum is 0. PSO reaches it in all 10 runs, after a median of 380 evaluations, but only +through the bounds: its particles head out of the box, stop at ±5 in every gene, and land on a +corner, a global minimum (from seed 1, at (5, 5, −5, 5, −5, 5, −5, 5, 5, −5)). On the function +shifted with genoxide's `problems::Shifted` and seed 1, whose minima are no longer on the bounds, +PSO's runs from seeds 1 and 2 end at 0.021. + +Of the searches that don't use the bounds, CMA-ES with IPOP restarts reaches the minimum once, after +41,990 evaluations, and its median run ends at 1.3e-2. SHADE comes closest without reaching it, +with a median error of 5.8e-6, and the genetic algorithm ends at 3.7e-4. CMA-ES without restarts +ends at 0.10. diff --git a/examples/katsuura/main.py b/examples/katsuura/main.py new file mode 100644 index 00000000..65dfb8a9 --- /dev/null +++ b/examples/katsuura/main.py @@ -0,0 +1,85 @@ +"""Katsuura: minimize Katsuura's function, rugged everywhere, in 10 dimensions. + +Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), +differential evolution (SHADE), particle swarm optimization and a real-coded genetic algorithm from +10 seeds each, and counts the runs that reach the minimum, 0 at the origin, to within 1e-8. The +function is genoxide's `problems::Katsuura`, which run evaluates in Rust. + +With ``GENOXIDE_TRACE=``, it also writes a trace of a run for the plot on the example's page, +with trace.py. + + python examples/katsuura/main.py +""" + +import genoxide as gx + +from trace import record_small + +DIMENSIONS = 10 +SEEDS = 10 +BUDGET = 10_000 * DIMENSIONS +# a run stops once its error to the minimum is at most this +ERROR = 1e-8 +ALGORITHMS = ["CMA-ES", "CMA-ES with IPOP", "DE", "PSO", "GA"] + + +def build(name, genome, seed): + """The algorithm called ``name``, on ``genome``, from ``seed``.""" + if name == "CMA-ES": + return gx.Cmaes(genome, objective="minimize", seed=seed) + if name == "CMA-ES with IPOP": + return gx.Cmaes(genome, restarts="ipop", objective="minimize", seed=seed) + if name == "DE": + return gx.De(genome, objective="minimize", seed=seed) + if name == "PSO": + return gx.Pso(genome, population_size=40, objective="minimize", seed=seed) + return gx.Ga( + genome, + population_size=100, + select=gx.Tournament(3), + crossover=gx.SimulatedBinaryCrossover(15.0), + mutation=gx.PolynomialMutation(20.0, rate=1 / DIMENSIONS), + objective="minimize", + seed=seed, + ) + + +def median(values): + """The median of ``values``, None without any.""" + values = sorted(values) + middle = len(values) // 2 + if not values: + return None + return values[middle] if len(values) % 2 else (values[middle - 1] + values[middle]) / 2 + + +def error_text(error): + """An error to two significant digits, as Rust writes it: 9.9e-9.""" + mantissa, exponent = f"{error:.1e}".split("e") + return f"{mantissa}e{int(exponent)}" + + +problem = gx.problems.Katsuura(DIMENSIONS) +minimum = problem.optimum.value +print(f"Katsuura in {DIMENSIONS} dimensions, {SEEDS} seeds, {BUDGET} evaluations at most per run") +print("algorithm at min evaluations median error") +for name in ALGORITHMS: + # the evaluations of the runs that reach the minimum, and every run's best error + evaluations, errors = [], [] + for seed in range(1, SEEDS + 1): + result = build(name, problem.genome, seed).run( + problem, target=minimum + ERROR, evaluations=BUDGET + ) + if result.stop_reason == "target": + evaluations.append(float(result.evaluations)) + # rounding can put a solution a few ulps below the minimum + errors.append(max(result.best_fitness - minimum, 0.0)) + reached = f"{len(evaluations)}/{SEEDS}" + middle = median(evaluations) + evaluations_text = "-" if middle is None else f"{middle:.0f}" + print(f"{name:<16} {reached:>6} {evaluations_text:>11} {error_text(median(errors)):>12}") +print("evaluations: the median of the runs that reach the minimum") + +# with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate run in +# 2 dimensions: the plot is the function's contour +record_small() diff --git a/examples/katsuura/main.rs b/examples/katsuura/main.rs new file mode 100644 index 00000000..09d7c7f3 --- /dev/null +++ b/examples/katsuura/main.rs @@ -0,0 +1,117 @@ +//! Katsuura: minimize Katsuura's function, rugged everywhere, in 10 dimensions. +//! +//! Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), +//! differential evolution (SHADE), particle swarm optimization and a real-coded genetic algorithm +//! from 10 seeds each, and counts the runs that reach the minimum, 0 at the origin, to within +//! 1e-8. The function is genoxide's `problems::Katsuura`. +//! +//! With `GENOXIDE_TRACE=`, it also writes a trace of a run for the plot on the example's +//! page, with `trace.rs`. +//! +//! ```text +//! cargo run --release --example katsuura +//! ``` + +mod trace; + +use genoxide::prelude::*; +use genoxide::problems::{Katsuura, Problem}; + +const DIMENSIONS: usize = 10; +const SEEDS: u64 = 10; +const BUDGET: u64 = 10_000 * DIMENSIONS as u64; +// a run stops once its error to the minimum is at most this +const ERROR: f64 = 1e-8; +const ALGORITHMS: [&str; 5] = ["CMA-ES", "CMA-ES with IPOP", "DE", "PSO", "GA"]; + +fn main() -> Result<()> { + let problem = Katsuura::new(DIMENSIONS); + let minimum = problem.optimum().expect("known").value(); + println!( + "Katsuura in {DIMENSIONS} dimensions, {SEEDS} seeds, {BUDGET} evaluations at most per run" + ); + println!("algorithm at min evaluations median error"); + for algorithm in ALGORITHMS { + // the evaluations of the runs that reach the minimum, and every run's best error + let mut evaluations = Vec::new(); + let mut errors = Vec::new(); + for seed in 1..=SEEDS { + let outcome = run(algorithm, problem, seed, minimum + ERROR)?; + if outcome.stop_reason() == StopReason::Target { + evaluations.push(outcome.evaluations() as f64); + } + // rounding can put a solution a few ulps below the minimum + let best = outcome.best_fitness().score().expect("valid"); + errors.push((best - minimum).max(0.0)); + } + let reached = format!("{}/{SEEDS}", evaluations.len()); + let evaluations = median(evaluations).map_or("-".to_string(), |e| format!("{e:.0}")); + let error = median(errors).expect("a run"); + println!( + "{algorithm:<16} {reached:>6} {evaluations:>11} {:>12}", + format!("{error:.1e}") + ); + } + println!("evaluations: the median of the runs that reach the minimum"); + + // with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate + // run in 2 dimensions: the plot is the function's contour + trace::record_small()?; + Ok(()) +} + +// a run of `algorithm` from `seed`, until its best is at most `target` or it has used BUDGET +// evaluations +fn run(algorithm: &str, problem: Katsuura, seed: u64, target: f64) -> Result> { + let real = problem.representation(); + let stop = Stop::target(target).or(Stop::evaluations(BUDGET)); + match algorithm { + "CMA-ES" | "CMA-ES with IPOP" => { + let restarts = if algorithm == "CMA-ES" { + cmaes::Restarts::Never + } else { + cmaes::Restarts::Ipop + }; + let cmaes = Cmaes::builder(real) + .restarts(restarts) + .minimize() + .seed(seed) + .build()?; + Engine::new(cmaes, problem).stop_when(stop).run() + } + "DE" => { + let de = De::builder(real).minimize().seed(seed).build()?; + Engine::new(de, problem).stop_when(stop).run() + } + "PSO" => { + let pso = Pso::builder(real) + .population_size(40) + .minimize() + .seed(seed) + .build()?; + Engine::new(pso, problem).stop_when(stop).run() + } + _ => { + let ga = Ga::builder(real) + .population_size(100) + .select(Tournament::new(3)?) + .crossover(SimulatedBinaryCrossover::new(15.0)?) + .mutate(PolynomialMutation::per_gene(1.0 / DIMENSIONS as f64, 20.0)?) + .minimize() + .seed(seed) + .build()?; + Engine::new(ga, problem).stop_when(stop).run() + } + } +} + +// the median of `values`, None without any +fn median(mut values: Vec) -> Option { + values.sort_by(f64::total_cmp); + let middle = values.len() / 2; + match values.len() { + 0 => None, + n if n % 2 == 1 => Some(values[middle]), + _ => Some((values[middle - 1] + values[middle]) / 2.0), + } +} diff --git a/examples/katsuura/output.txt b/examples/katsuura/output.txt new file mode 100644 index 00000000..2fef1214 --- /dev/null +++ b/examples/katsuura/output.txt @@ -0,0 +1,8 @@ +Katsuura in 10 dimensions, 10 seeds, 100000 evaluations at most per run +algorithm at min evaluations median error +CMA-ES 0/10 - 1.0e-1 +CMA-ES with IPOP 1/10 41990 1.3e-2 +DE 0/10 - 5.8e-6 +PSO 10/10 380 0.0e0 +GA 0/10 - 3.7e-4 +evaluations: the median of the runs that reach the minimum diff --git a/examples/katsuura/trace.json b/examples/katsuura/trace.json new file mode 100644 index 00000000..3eae0fae --- /dev/null +++ b/examples/katsuura/trace.json @@ -0,0 +1,102 @@ +{"example":"katsuura","format":1,"log_y":true,"objective":"minimize","optimum":0.0,"plot":"contour","problem":{"bounds":[[-5.0,5.0],[-5.0,5.0]],"function":"katsuura","minima":[[0.0,0.0]]},"x_label":"evaluations","y_label":"error","frames":[ +{"best":25.2461,"evaluations":6,"generation":0,"median":42.5346,"state":{"best":[1.09727,-3.0536],"population":[[-4.02856,-1.2232],[1.09727,-3.0536],[-2.70235,3.76881],[-1.07094,-4.64995],[-3.75609,-3.6306],[2.14496,-1.42894]]}}, +{"best":14.4567,"evaluations":18,"generation":2,"median":41.3938,"state":{"best":[3.44932,-0.961838],"population":[[2.54503,-2.65083],[1.75672,-3.23075],[-3.25815,-0.0421765],[-1.82153,-0.426244],[0.717548,2.12448],[3.44932,-0.961838]]}}, +{"best":14.4567,"evaluations":24,"generation":3,"median":44.9181,"state":{"best":[3.44932,-0.961838],"population":[[-0.371824,-3.53606],[-1.52975,0.275017],[2.17778,-0.385418],[-0.122378,-0.35977],[2.0937,-2.72759],[4.61443,-2.58762]]}}, +{"best":4.56353,"evaluations":36,"generation":5,"median":37.5723,"state":{"best":[1.54091,-0.492906],"population":[[0.31083,-2.26944],[-0.024196,-0.88287],[0.837125,-1.63353],[-0.978424,-1.63786],[2.40337,-1.36449],[0.991867,-2.57186]]}}, +{"best":4.56353,"evaluations":48,"generation":7,"median":32.0215,"state":{"best":[1.54091,-0.492906],"population":[[1.01683,-0.867861],[2.21631,-2.90751],[2.2767,-2.26781],[0.561875,-3.90929],[0.647799,-3.02296],[2.0722,-2.87645]]}}, +{"best":4.56353,"evaluations":54,"generation":8,"median":45.2404,"state":{"best":[1.54091,-0.492906],"population":[[0.473156,-3.12187],[0.191711,-2.78249],[1.48571,-1.81496],[0.268273,-2.73299],[0.132467,-2.06479],[0.259521,-2.78991]]}}, +{"best":4.56353,"evaluations":66,"generation":10,"median":50.1104,"state":{"best":[1.54091,-0.492906],"population":[[1.12933,-2.05843],[1.52608,-2.1141],[0.664836,-1.37324],[0.675496,-2.58599],[1.35241,-1.72152],[2.31314,-0.606431]]}}, +{"best":4.56353,"evaluations":78,"generation":12,"median":33.0138,"state":{"best":[1.54091,-0.492906],"population":[[1.69013,-2.17738],[-0.00623348,-3.2166],[2.73746,-1.89256],[2.127,-2.49538],[1.43682,-1.2807],[2.39956,-2.48396]]}}, +{"best":4.56353,"evaluations":84,"generation":13,"median":54.372,"state":{"best":[1.54091,-0.492906],"population":[[0.678586,-3.02283],[2.55683,-1.58538],[1.81314,-2.81106],[2.86704,-2.82798],[0.163665,-2.59716],[2.62522,-2.16155]]}}, +{"best":4.56353,"evaluations":96,"generation":15,"median":41.2121,"state":{"best":[1.54091,-0.492906],"population":[[1.02199,-2.96441],[1.21358,-3.01752],[2.53591,-1.14983],[1.63802,-1.7479],[1.37758,-2.3028],[2.3763,-1.22924]]}}, +{"best":4.56353,"evaluations":108,"generation":17,"median":40.7397,"state":{"best":[1.54091,-0.492906],"population":[[-0.0584839,-3.77512],[-0.120586,-2.30931],[-0.102238,-3.51525],[-1.07797,-4.34698],[1.04216,-2.65577],[-1.06556,-4.58952]]}}, +{"best":4.56353,"evaluations":114,"generation":18,"median":29.5706,"state":{"best":[1.54091,-0.492906],"population":[[-1.98357,-4.14951],[-0.465577,-3.13905],[1.55929,-2.44903],[2.00784,-2.28416],[1.16006,-2.63352],[0.0212895,-3.20829]]}}, +{"best":4.56353,"evaluations":126,"generation":20,"median":28.7313,"state":{"best":[1.54091,-0.492906],"population":[[-0.865628,-4.01426],[1.75337,-2.6372],[0.411835,-2.86716],[-0.615722,-3.738],[0.388486,-3.48625],[1.00077,-2.74932]]}}, +{"best":4.56353,"evaluations":138,"generation":22,"median":30.4569,"state":{"best":[1.54091,-0.492906],"population":[[-0.78539,-4.00143],[-0.00048693,-4.24974],[1.91405,-2.59802],[-1.07262,-4.58125],[0.0184296,-3.78159],[-0.67969,-4.07081]]}}, +{"best":4.56353,"evaluations":144,"generation":23,"median":50.4144,"state":{"best":[1.54091,-0.492906],"population":[[-0.32818,-3.69707],[-0.217882,-3.71796],[0.600005,-3.58854],[-0.822845,-4.39986],[-0.815806,-4.58594],[-0.992619,-4.36347]]}}, +{"best":4.56353,"evaluations":156,"generation":25,"median":52.6806,"state":{"best":[1.54091,-0.492906],"population":[[-0.583483,-4.07847],[-1.11154,-4.34954],[-1.21413,-4.58467],[-1.64718,-4.67195],[-0.855474,-4.27795],[-0.658575,-4.41667]]}}, +{"best":4.56353,"evaluations":168,"generation":27,"median":35.3918,"state":{"best":[1.54091,-0.492906],"population":[[-0.201409,-3.8895],[0.0221622,-3.67884],[-0.413355,-4.12563],[0.164651,-3.63135],[-0.34064,-4.03542],[-0.796195,-4.45459]]}}, +{"best":4.56353,"evaluations":174,"generation":28,"median":46.5928,"state":{"best":[1.54091,-0.492906],"population":[[-0.411496,-4.29551],[-0.667378,-4.24481],[-0.908872,-4.44509],[-0.59146,-4.26061],[-0.560556,-4.2881],[-0.52315,-4.25934]]}}, +{"best":4.56353,"evaluations":186,"generation":30,"median":50.1302,"state":{"best":[1.54091,-0.492906],"population":[[-1.27071,-4.71423],[-0.940769,-4.70493],[-0.107289,-3.87319],[-0.680319,-4.25648],[-0.566784,-4.34757],[-0.82646,-4.61939]]}}, +{"best":4.56353,"evaluations":192,"generation":31,"median":44.1613,"state":{"best":[1.54091,-0.492906],"population":[[-0.690164,-4.44279],[-0.126624,-3.7889],[-0.208775,-4.01856],[-0.562755,-4.2881],[-0.426349,-4.20903],[-0.25174,-3.89382]]}}, +{"best":4.56353,"evaluations":204,"generation":33,"median":56.8616,"state":{"best":[1.54091,-0.492906],"population":[[0.208965,-3.82885],[-0.148006,-4.08177],[-0.332257,-4.14534],[0.105777,-3.92895],[0.322379,-3.81524],[0.099819,-3.9362]]}}, +{"best":4.56353,"evaluations":216,"generation":35,"median":34.3287,"state":{"best":[1.54091,-0.492906],"population":[[-0.0562992,-3.91618],[0.468557,-3.55812],[0.391788,-3.70258],[-0.441873,-4.28936],[-0.039655,-3.7854],[0.747846,-3.49851]]}}, +{"best":4.56353,"evaluations":222,"generation":36,"median":58.5863,"state":{"best":[1.54091,-0.492906],"population":[[0.660523,-3.36345],[0.841378,-3.45236],[1.26593,-3.2181],[0.377386,-3.71402],[0.290385,-3.74208],[0.647642,-3.49762]]}}, +{"best":4.56353,"evaluations":234,"generation":38,"median":20.4782,"state":{"best":[1.54091,-0.492906],"population":[[0.0315705,-4.03407],[0.829861,-3.4963],[1.03723,-3.25518],[0.495072,-3.88044],[0.637981,-3.54302],[-0.0985255,-4.15668]]}}, +{"best":4.56353,"evaluations":246,"generation":40,"median":26.2092,"state":{"best":[1.54091,-0.492906],"population":[[0.99459,-3.30293],[1.06977,-3.46102],[0.606265,-3.84906],[1.30494,-3.17027],[2.02021,-2.73936],[0.885578,-3.55845]]}}, +{"best":4.56353,"evaluations":252,"generation":41,"median":26.9649,"state":{"best":[1.54091,-0.492906],"population":[[1.20327,-3.27654],[0.736105,-3.54011],[0.826445,-3.45519],[0.965718,-3.38705],[0.768821,-3.54725],[0.913666,-3.45465]]}}, +{"best":4.56353,"evaluations":264,"generation":43,"median":29.6678,"state":{"best":[1.54091,-0.492906],"population":[[0.710236,-3.5524],[0.576677,-3.42724],[1.13348,-3.28762],[0.99386,-3.30774],[0.752892,-3.55861],[1.0636,-3.3752]]}}, +{"best":4.56353,"evaluations":276,"generation":45,"median":22.2224,"state":{"best":[1.54091,-0.492906],"population":[[0.90149,-3.41592],[0.894881,-3.48179],[0.836199,-3.49607],[1.05798,-3.39853],[0.84129,-3.49096],[1.09797,-3.35345]]}}, +{"best":4.56353,"evaluations":282,"generation":46,"median":42.4174,"state":{"best":[1.54091,-0.492906],"population":[[0.815985,-3.44791],[0.495991,-3.69999],[0.701405,-3.60028],[0.707031,-3.62668],[1.1553,-3.33632],[0.789271,-3.55988]]}}, +{"best":4.56353,"evaluations":294,"generation":48,"median":39.0873,"state":{"best":[1.54091,-0.492906],"population":[[0.715742,-3.58964],[0.606727,-3.63213],[0.739783,-3.51056],[0.951524,-3.38724],[0.755446,-3.48432],[0.663312,-3.62719]]}}, +{"best":4.56353,"evaluations":306,"generation":50,"median":30.4625,"state":{"best":[1.54091,-0.492906],"population":[[1.01278,-3.35293],[0.731105,-3.38369],[0.707304,-3.47636],[0.659405,-3.5655],[0.585065,-3.61977],[0.769875,-3.46529]]}}, +{"best":4.20548,"evaluations":312,"generation":51,"median":36.0326,"state":{"best":[0.549484,-3.50427],"population":[[0.969998,-3.3807],[0.549484,-3.50427],[0.884895,-3.4156],[0.911909,-3.40713],[0.736384,-3.43122],[0.92438,-3.36676]]}}, +{"best":4.10097,"evaluations":324,"generation":53,"median":24.237,"state":{"best":[0.57812,-3.50063],"population":[[0.878349,-3.29201],[0.57812,-3.50063],[0.449689,-3.54151],[0.412893,-3.54537],[0.753572,-3.4419],[0.694907,-3.44508]]}}, +{"best":4.10097,"evaluations":336,"generation":55,"median":36.7479,"state":{"best":[0.57812,-3.50063],"population":[[0.632521,-3.35672],[0.843622,-3.37364],[0.561205,-3.45902],[0.499051,-3.47175],[0.847048,-3.28238],[0.589951,-3.56341]]}}, +{"best":4.10097,"evaluations":342,"generation":56,"median":20.2367,"state":{"best":[0.57812,-3.50063],"population":[[0.297943,-3.54142],[0.4459,-3.53036],[0.236749,-3.51634],[0.647499,-3.3865],[0.464695,-3.53773],[0.78507,-3.35353]]}}, +{"best":2.79706,"evaluations":354,"generation":58,"median":8.70085,"state":{"best":[0.540188,-3.49875],"population":[[0.47944,-3.54336],[0.395402,-3.54126],[0.329377,-3.62177],[0.521941,-3.48312],[0.540188,-3.49875],[0.511379,-3.52884]]}}, +{"best":0.992364,"evaluations":366,"generation":60,"median":5.00649,"state":{"best":[0.510932,-3.50074],"population":[[0.450563,-3.54183],[0.494382,-3.52865],[0.454299,-3.52047],[0.510932,-3.50074],[0.549898,-3.4941],[0.58648,-3.49975]]}}, +{"best":0.992364,"evaluations":372,"generation":61,"median":6.32324,"state":{"best":[0.510932,-3.50074],"population":[[0.488198,-3.50415],[0.56943,-3.51241],[0.527899,-3.48823],[0.508688,-3.50919],[0.606512,-3.45896],[0.45326,-3.5387]]}}, +{"best":0.992364,"evaluations":384,"generation":63,"median":7.69522,"state":{"best":[0.510932,-3.50074],"population":[[0.574716,-3.50648],[0.560901,-3.51174],[0.540984,-3.52133],[0.457236,-3.52359],[0.505918,-3.51754],[0.531647,-3.53797]]}}, +{"best":0.992364,"evaluations":396,"generation":65,"median":3.62015,"state":{"best":[0.510932,-3.50074],"population":[[0.52046,-3.5099],[0.50891,-3.51576],[0.519438,-3.52119],[0.500235,-3.51824],[0.51766,-3.51241],[0.538183,-3.49842]]}}, +{"best":0.992364,"evaluations":402,"generation":66,"median":3.35775,"state":{"best":[0.510932,-3.50074],"population":[[0.52718,-3.49637],[0.510831,-3.5125],[0.514869,-3.51097],[0.56856,-3.49733],[0.546892,-3.50977],[0.521147,-3.50482]]}}, +{"best":0.992364,"evaluations":414,"generation":68,"median":3.09441,"state":{"best":[0.510932,-3.50074],"population":[[0.557017,-3.48374],[0.539427,-3.50137],[0.540504,-3.49945],[0.555748,-3.48992],[0.534309,-3.50471],[0.531124,-3.50176]]}}, +{"best":0.986433,"evaluations":426,"generation":70,"median":2.36511,"state":{"best":[0.512609,-3.49965],"population":[[0.49558,-3.50418],[0.535884,-3.50879],[0.525646,-3.50164],[0.542851,-3.50059],[0.511681,-3.50865],[0.513959,-3.50462]]}}, +{"best":0.542698,"evaluations":432,"generation":71,"median":1.87635,"state":{"best":[0.502924,-3.49871],"population":[[0.483067,-3.50962],[0.511719,-3.50876],[0.500257,-3.5035],[0.493867,-3.50285],[0.502924,-3.49871],[0.534399,-3.5064]]}}, +{"best":0.468087,"evaluations":444,"generation":73,"median":1.57841,"state":{"best":[0.49977,-3.50231],"population":[[0.527536,-3.49859],[0.508516,-3.50205],[0.481959,-3.49659],[0.481856,-3.49824],[0.49977,-3.50231],[0.483514,-3.49853]]}}, +{"best":0.468087,"evaluations":456,"generation":75,"median":1.54812,"state":{"best":[0.49977,-3.50231],"population":[[0.48536,-3.50193],[0.514274,-3.49726],[0.485219,-3.50888],[0.511414,-3.49997],[0.491785,-3.50497],[0.487081,-3.50196]]}}, +{"best":0.468087,"evaluations":462,"generation":76,"median":0.836744,"state":{"best":[0.49977,-3.50231],"population":[[0.501959,-3.50279],[0.516777,-3.50108],[0.508832,-3.49953],[0.508091,-3.49854],[0.495729,-3.49875],[0.503297,-3.49695]]}}, +{"best":0.155559,"evaluations":474,"generation":78,"median":0.545067,"state":{"best":[0.501073,-3.50017],"population":[[0.502612,-3.50212],[0.504025,-3.49984],[0.497258,-3.50062],[0.502797,-3.50132],[0.50393,-3.49891],[0.494471,-3.50038]]}}, +{"best":0.106888,"evaluations":486,"generation":80,"median":0.185302,"state":{"best":[0.500145,-3.50037],"population":[[0.501868,-3.49963],[0.499798,-3.49967],[0.498829,-3.50027],[0.49937,-3.5005],[0.501638,-3.50089],[0.501106,-3.5001]]}}, +{"best":0.0706323,"evaluations":492,"generation":81,"median":0.281787,"state":{"best":[0.500281,-3.50013],"population":[[0.504451,-3.50068],[0.499533,-3.50044],[0.498962,-3.50089],[0.500281,-3.50013],[0.50293,-3.50059],[0.498624,-3.50054]]}}, +{"best":0.057765,"evaluations":504,"generation":83,"median":0.18593,"state":{"best":[0.499688,-3.50007],"population":[[0.501871,-3.49993],[0.497325,-3.49992],[0.498146,-3.4997],[0.49826,-3.49995],[0.500647,-3.50015],[0.498645,-3.49989]]}}, +{"best":0.0541842,"evaluations":510,"generation":84,"median":0.105659,"state":{"best":[0.499748,-3.50008],"population":[[0.500651,-3.49996],[0.500154,-3.50028],[0.499748,-3.50008],[0.49944,-3.50062],[0.499253,-3.50015],[0.501226,-3.50031]]}}, +{"best":0.0163469,"evaluations":522,"generation":86,"median":0.0601948,"state":{"best":[0.500012,-3.49995],"population":[[0.500357,-3.49987],[0.500099,-3.49976],[0.500173,-3.50009],[0.500187,-3.5],[0.500703,-3.49977],[0.500012,-3.49995]]}}, +{"best":0.0163469,"evaluations":534,"generation":88,"median":0.047406,"state":{"best":[0.500012,-3.49995],"population":[[0.500074,-3.50015],[0.50014,-3.49999],[0.49975,-3.50002],[0.499971,-3.49985],[0.499767,-3.49987],[0.499827,-3.49989]]}}, +{"best":0.0163469,"evaluations":540,"generation":89,"median":0.0327928,"state":{"best":[0.500012,-3.49995],"population":[[0.500203,-3.49995],[0.499949,-3.50003],[0.499943,-3.50008],[0.500083,-3.50004],[0.499827,-3.50003],[0.500173,-3.49991]]}}, +{"best":0.00813192,"evaluations":552,"generation":91,"median":0.0200035,"state":{"best":[0.500051,-3.5],"population":[[0.500032,-3.50004],[0.500098,-3.49997],[0.499966,-3.50004],[0.500029,-3.50002],[0.499895,-3.49998],[0.49997,-3.50007]]}}, +{"best":0.00496026,"evaluations":564,"generation":93,"median":0.0115522,"state":{"best":[0.499997,-3.49999],"population":[[0.499956,-3.49998],[0.499917,-3.49998],[0.50005,-3.5],[0.500139,-3.49998],[0.499997,-3.49999],[0.499975,-3.49999]]}}, +{"best":0.00235338,"evaluations":570,"generation":94,"median":0.0083132,"state":{"best":[0.499987,-3.5],"population":[[0.500004,-3.49994],[0.500087,-3.50002],[0.49998,-3.50001],[0.499987,-3.5],[0.500031,-3.49998],[0.500012,-3.5]]}}, +{"best":0.00235338,"evaluations":582,"generation":96,"median":0.0130673,"state":{"best":[0.499987,-3.5],"population":[[0.500055,-3.49998],[0.50004,-3.5],[0.500004,-3.49997],[0.500075,-3.49999],[0.500062,-3.49999],[0.500085,-3.49999]]}}, +{"best":0.00226274,"evaluations":594,"generation":98,"median":0.00989574,"state":{"best":[0.500006,-3.5],"population":[[0.500006,-3.5],[0.499988,-3.49998],[0.500044,-3.49999],[0.500021,-3.5],[0.50003,-3.49998],[0.500064,-3.5]]}}, +{"best":0.00164801,"evaluations":600,"generation":99,"median":0.00597765,"state":{"best":[0.499999,-3.5],"population":[[0.499986,-3.49997],[0.50005,-3.49997],[0.499968,-3.5],[0.500025,-3.50001],[0.499999,-3.5],[0.49999,-3.5]]}}, +{"best":0.000989333,"evaluations":612,"generation":101,"median":0.00297622,"state":{"best":[0.499998,-3.5],"population":[[0.500002,-3.5],[0.499999,-3.5],[0.499997,-3.49999],[0.499985,-3.5],[0.499977,-3.5],[0.499967,-3.49999]]}}, +{"best":0.000715685,"evaluations":624,"generation":103,"median":0.00202565,"state":{"best":[0.500003,-3.5],"population":[[0.50001,-3.5],[0.500003,-3.5],[0.499991,-3.5],[0.500005,-3.5],[0.499993,-3.5],[0.500016,-3.5]]}}, +{"best":0.000715685,"evaluations":630,"generation":104,"median":0.00253497,"state":{"best":[0.500003,-3.5],"population":[[0.49999,-3.5],[0.5,-3.5],[0.500001,-3.5],[0.499988,-3.5],[0.499989,-3.5],[0.50001,-3.5]]}}, +{"best":0.000249465,"evaluations":642,"generation":106,"median":0.000803108,"state":{"best":[0.499999,-3.5],"population":[[0.500006,-3.5],[0.500001,-3.5],[0.5,-3.5],[0.499998,-3.5],[0.500006,-3.5],[0.500001,-3.5]]}}, +{"best":0.000238263,"evaluations":654,"generation":108,"median":0.000654772,"state":{"best":[0.5,-3.5],"population":[[0.500003,-3.5],[0.499996,-3.5],[0.500001,-3.5],[0.500001,-3.5],[0.500001,-3.5],[0.5,-3.5]]}}, +{"best":0.000238263,"evaluations":660,"generation":109,"median":0.000319423,"state":{"best":[0.5,-3.5],"population":[[0.5,-3.5],[0.499999,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5]]}}, +{"best":0.000120774,"evaluations":672,"generation":111,"median":0.000484511,"state":{"best":[0.5,-3.5],"population":[[0.5,-3.5],[0.500001,-3.5],[0.500002,-3.5],[0.5,-3.5],[0.499999,-3.5],[0.500002,-3.5]]}}, +{"best":8.37143e-05,"evaluations":684,"generation":113,"median":0.000340923,"state":{"best":[0.5,-3.5],"population":[[0.5,-3.5],[0.500001,-3.5],[0.499999,-3.5],[0.500001,-3.5],[0.499999,-3.5],[0.5,-3.5]]}}, +{"best":8.37143e-05,"evaluations":690,"generation":114,"median":0.000292136,"state":{"best":[0.5,-3.5],"population":[[0.500001,-3.5],[0.5,-3.5],[0.499999,-3.5],[0.499999,-3.5],[0.5,-3.5],[0.499999,-3.5]]}}, +{"best":4.84454e-05,"evaluations":702,"generation":116,"median":0.000197366,"state":{"best":[0.5,-3.5],"population":[[0.5,-3.5],[0.500001,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.499999,-3.5]]}}, +{"best":1.88145e-05,"evaluations":714,"generation":118,"median":8.81111e-05,"state":{"best":[0.5,-3.5],"population":[[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5]]}}, +{"best":1.88145e-05,"evaluations":720,"generation":119,"median":8.70301e-05,"state":{"best":[0.5,-3.5],"population":[[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5]]}}, +{"best":1.88145e-05,"evaluations":732,"generation":121,"median":5.87378e-05,"state":{"best":[0.5,-3.5],"population":[[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5]]}}, +{"best":7.77211e-06,"evaluations":744,"generation":123,"median":3.23712e-05,"state":{"best":[0.5,-3.5],"population":[[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5]]}}, +{"best":7.77211e-06,"evaluations":750,"generation":124,"median":3.10831e-05,"state":{"best":[0.5,-3.5],"population":[[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5]]}}, +{"best":7.77211e-06,"evaluations":762,"generation":126,"median":1.57424e-05,"state":{"best":[0.5,-3.5],"population":[[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5]]}}, +{"best":3.15775e-06,"evaluations":774,"generation":128,"median":1.07347e-05,"state":{"best":[0.5,-3.5],"population":[[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5]]}}, +{"best":3.15775e-06,"evaluations":780,"generation":129,"median":1.21077e-05,"state":{"best":[0.5,-3.5],"population":[[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5]]}}, +{"best":3.15775e-06,"evaluations":792,"generation":131,"median":9.93436e-06,"state":{"best":[0.5,-3.5],"population":[[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5]]}}, +{"best":2.05848e-06,"evaluations":804,"generation":133,"median":5.44005e-06,"state":{"best":[0.5,-3.5],"population":[[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5]]}}, +{"best":1.15352e-06,"evaluations":810,"generation":134,"median":4.20286e-06,"state":{"best":[0.5,-3.5],"population":[[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5]]}}, +{"best":7.39859e-07,"evaluations":822,"generation":136,"median":3.2357e-06,"state":{"best":[0.5,-3.5],"population":[[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5]]}}, +{"best":7.39859e-07,"evaluations":828,"generation":137,"median":2.84837e-06,"state":{"best":[0.5,-3.5],"population":[[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5]]}}, +{"best":7.39859e-07,"evaluations":840,"generation":139,"median":2.00423e-06,"state":{"best":[0.5,-3.5],"population":[[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5]]}}, +{"best":4.90074e-07,"evaluations":852,"generation":141,"median":1.55135e-06,"state":{"best":[0.5,-3.5],"population":[[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5]]}}, +{"best":2.57289e-07,"evaluations":858,"generation":142,"median":1.96831e-06,"state":{"best":[0.5,-3.5],"population":[[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5]]}}, +{"best":2.57289e-07,"evaluations":870,"generation":144,"median":1.23049e-06,"state":{"best":[0.5,-3.5],"population":[[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5]]}}, +{"best":2.57289e-07,"evaluations":882,"generation":146,"median":3.33211e-07,"state":{"best":[0.5,-3.5],"population":[[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5]]}}, +{"best":2.57289e-07,"evaluations":888,"generation":147,"median":4.91661e-07,"state":{"best":[0.5,-3.5],"population":[[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5]]}}, +{"best":5.96758e-08,"evaluations":900,"generation":149,"median":3.31408e-07,"state":{"best":[0.5,-3.5],"population":[[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5]]}}, +{"best":5.96758e-08,"evaluations":912,"generation":151,"median":2.42655e-07,"state":{"best":[0.5,-3.5],"population":[[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5]]}}, +{"best":4.40739e-08,"evaluations":918,"generation":152,"median":2.16395e-07,"state":{"best":[0.5,-3.5],"population":[[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5]]}}, +{"best":4.40739e-08,"evaluations":930,"generation":154,"median":1.48851e-07,"state":{"best":[0.5,-3.5],"population":[[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5]]}}, +{"best":4.40739e-08,"evaluations":942,"generation":156,"median":1.46991e-07,"state":{"best":[0.5,-3.5],"population":[[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5]]}}, +{"best":1.91173e-08,"evaluations":948,"generation":157,"median":1.02183e-07,"state":{"best":[0.5,-3.5],"population":[[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5]]}}, +{"best":1.91173e-08,"evaluations":960,"generation":159,"median":7.30503e-08,"state":{"best":[0.5,-3.5],"population":[[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5]]}}, +{"best":1.91173e-08,"evaluations":972,"generation":161,"median":5.6805e-08,"state":{"best":[0.5,-3.5],"population":[[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5]]}}, +{"best":1.91173e-08,"evaluations":978,"generation":162,"median":3.06654e-08,"state":{"best":[0.5,-3.5],"population":[[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5]]}}, +{"best":6.58615e-09,"evaluations":990,"generation":164,"median":2.7203e-08,"state":{"best":[0.5,-3.5],"population":[[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5],[0.5,-3.5]]}} +]} diff --git a/examples/katsuura/trace.py b/examples/katsuura/trace.py new file mode 100644 index 00000000..ed554e0a --- /dev/null +++ b/examples/katsuura/trace.py @@ -0,0 +1,189 @@ +"""The trace for the plot on the example's page, written to the file that ``GENOXIDE_TRACE`` +names. The plot draws the population on the function's contour, which needs two dimensions: the +trace is of a separate run of CMA-ES with IPOP restarts in 2 dimensions, with a budget of +20,000 evaluations, in at most 100 frames. The Rust example writes the same file.""" + +import json +import math +import os + +import genoxide as gx + + +def record_small(): + """Runs CMA-ES with IPOP restarts in 2 dimensions and writes its trace, if ``GENOXIDE_TRACE`` is set.""" + path = os.environ.get("GENOXIDE_TRACE") + if not path: + return + problem = gx.problems.Katsuura(2) + minimum = problem.optimum.value + budget = 20_000 + cmaes = gx.Cmaes(problem.genome, restarts="ipop", objective="minimize", seed=1) + frames = Frames(100) + + def record(progress): + state = {"population": progress.population.tolist(), "best": progress.best_genome.tolist()} + frames.push(frame(progress, state, minimum)) + + cmaes.run(problem, target=minimum + 1e-8, evaluations=budget, on_generation=record) + low, high = problem.genome.bounds + settings = { + "format": 1, + "example": "katsuura", + "objective": "minimize", + "x_label": "evaluations", + "y_label": "error", + "log_y": True, + "optimum": 0.0, + "plot": "contour", + "problem": { + "function": "katsuura", + "bounds": [[float(low), float(high)]] * 2, + "minima": problem.optimum.solutions.tolist(), + }, + } + write(path, settings, frames.to_list()) + + +def frame(progress, state, minimum): + """The frame of a generation: its progress, the errors of its best and of its population's + median to ``minimum`` (rounding can put a solution a few ulps below it), and ``state``.""" + + def error(value): + return None if value is None else max(value - minimum, 0.0) + + return { + "generation": progress.generation, + "evaluations": progress.evaluations, + "best": error(progress.best_fitness), + "median": error(median(progress.scores)), + "state": state, + } + + +def median(scores): + """The median of the valid scores, None without any.""" + scores = sorted(float(score) for score in scores if not math.isnan(score)) + middle = len(scores) // 2 + if not scores: + return None + return scores[middle] if len(scores) % 2 else (scores[middle - 1] + scores[middle]) / 2 + + +# ---- the same in every example's trace ---------------------------------------------------------- + + +class Frames: + """The frames of at most ``most`` generations, from the part of the run where what the page + plots changes: the frames after the last change are left out (a run that reached its target, + or a front that no longer moves), and the rest are spread evenly over the generations up to + it. While the run goes, up to 8 × ``most`` frames are kept: every ``every``-th generation, + with ``every`` doubling whenever there are that many, and the last one.""" + + def __init__(self, most): + self.most, self.every, self.kept, self.last = most, 1, [], None + + def push(self, frame): + if frame["generation"] % self.every: + self.last = frame + return + self.kept.append(frame) + self.last = None + if len(self.kept) == 8 * self.most: + self.every *= 2 + self.kept = [kept for kept in self.kept if kept["generation"] % self.every == 0] + + def to_list(self): + frames = self.kept + ([self.last] if self.last else []) + active = frames[: last_change(frames) + 1] + count, most = len(active), max(self.most, 2) + if count <= most: + return active + return [active[(i * (count - 1) + (most - 1) // 2) // (most - 1)] for i in range(most)] + + +def last_change(frames): + """The index of the frame after which nothing the page plots changes. To 3 significant + digits, as a plot shows them: the best, the median and, for a single objective (a numeric + best), the state; to within a hundredth of their range over the run: a front's + hypervolumes, in the state or in a grid's series.""" + if not frames: + return 0 + last = len(frames) - 1 + number = lambda value: isinstance(value, (int, float)) and not isinstance(value, bool) + single = any(number(frame.get("best")) for frame in frames) + + def measures(frame): + values = [] + state = frame.get("state") + hypervolume = state.get("hypervolume") if isinstance(state, dict) else None + for value in (hypervolume, frame.get("series")): + if number(value): + values.append(float(value)) + elif isinstance(value, dict): + values.extend(float(v) for _, v in sorted(value.items()) if number(v)) + return values + + measured = [measures(frame) for frame in frames] + end = measured[last] + tolerance = [] + for k in range(len(end)): + values = [values[k] for values in measured if k < len(values)] + tolerance.append((max(values) - min(values)) / 100.0) + + def same(frame, final, key, flush=False): + return coarse(frame.get(key), flush) == coarse(final.get(key), flush) + + def settled(i): + frame, final = frames[i], frames[last] + return ( + same(frame, final, "best") + and same(frame, final, "median") + and (not single or same(frame, final, "state", flush=True)) + and len(measured[i]) == len(end) + and all(abs(v - e) <= t for v, e, t in zip(measured[i], end, tolerance)) + ) + + first = last + while first > 0 and settled(first - 1): + first -= 1 + return first + + +def coarse(value, flush=False): + """``value`` with its numbers to 3 significant digits, as precisely as a plot shows them: two + frames whose plotted values agree to that precision look the same. With ``flush``, for the + solutions a plot draws on their ranges, numbers below 1e-6 in size count as 0.""" + if isinstance(value, float): + if flush and abs(value) < 1e-6: + value = 0.0 + return f"{value:.2e}" + if isinstance(value, (list, tuple)): + return "[" + ",".join(coarse(item, flush) for item in value) + "]" + if isinstance(value, dict): + items = sorted(value.items()) + return "{" + ",".join(f"{key}:{coarse(item, flush)}" for key, item in items) + "}" + return json.dumps(value) + + +def write(path, settings, frames): + """Writes the settings and the frames to ``path``, a frame per line.""" + lines = ",\n".join(map(to_json, frames)) + with open(path, "w", encoding="utf-8", newline="\n") as file: + file.write(f'{to_json(settings)[:-1]},"frames":[\n{lines}\n]}}\n') + + +def to_json(value): + """Compact JSON with sorted keys, and numbers rounded to 6 significant digits, as the Rust + example writes it.""" + return json.dumps(rounded(value), sort_keys=True, separators=(",", ":"), ensure_ascii=False) + + +def rounded(value): + if isinstance(value, dict): + return {key: rounded(item) for key, item in value.items()} + if isinstance(value, (list, tuple)): + return [rounded(item) for item in value] + if isinstance(value, float): + return float(f"{value:.5e}") if math.isfinite(value) else None + return value diff --git a/examples/katsuura/trace.rs b/examples/katsuura/trace.rs new file mode 100644 index 00000000..fd3ef74a --- /dev/null +++ b/examples/katsuura/trace.rs @@ -0,0 +1,261 @@ +//! The trace for the plot on the example's page, written to the file that `GENOXIDE_TRACE` names. +//! The plot draws the population on the function's contour, which needs two dimensions: the trace +//! is of a separate run of CMA-ES with IPOP restarts in 2 dimensions, with a budget of +//! 20,000 evaluations, in at most 100 frames. The Python example writes the same +//! file. + +use genoxide::observer::Snapshot; +use genoxide::prelude::*; +use genoxide::problems::{Katsuura, Problem}; +use serde_json::{Value, json}; + +// runs CMA-ES with IPOP restarts in 2 dimensions and writes its trace, if GENOXIDE_TRACE is set +pub fn record_small() -> Result<()> { + let Ok(path) = std::env::var("GENOXIDE_TRACE") else { + return Ok(()); + }; + let problem = Katsuura::new(2); + let optimum = problem.optimum().expect("known"); + let minimum = optimum.value(); + let budget = 20_000; + let cmaes = Cmaes::builder(problem.representation()) + .restarts(cmaes::Restarts::Ipop) + .minimize() + .seed(1) + .build()?; + let mut frames = Frames::new(100); + Engine::new(cmaes, problem.clone()) + .stop_when(Stop::target(minimum + 1e-8).or(Stop::evaluations(budget))) + .on_generation(|snapshot| { + let population = snapshot.population().iter().map(|x| &x.genome()[..]); + let population: Vec<&[f64]> = population.collect(); + let best = &snapshot.best().genome()[..]; + let state = json!({ "population": population, "best": best }); + frames.push(frame(snapshot, state, minimum)); + }) + .run()?; + let bounds = problem.representation().bounds().to_vec(); + let bounds: Vec<[f64; 2]> = bounds.iter().map(|b| [*b.start(), *b.end()]).collect(); + let minima: Vec<&[f64]> = optimum.solutions().iter().map(|x| &x[..]).collect(); + let settings = json!({ + "format": 1, + "example": "katsuura", + "objective": "minimize", + "x_label": "evaluations", + "y_label": "error", + "log_y": true, + "optimum": 0.0, + "plot": "contour", + "problem": { + "function": "katsuura", + "bounds": bounds, + "minima": minima, + }, + }); + write(&path, settings, frames.into_vec()); + Ok(()) +} + +// the frame of a generation: its progress, the errors of its best and of its population's median +// to `minimum` (rounding can put a solution a few ulps below it), and `state` +fn frame(snapshot: &Snapshot<'_, Reals>, state: Value, minimum: f64) -> Value { + let progress = snapshot.progress(); + let error = |value: f64| (value - minimum).max(0.0); + let population = snapshot.population().iter(); + let scores = population.filter_map(|individual| individual.fitness()?.score()); + json!({ + "generation": progress.generation(), + "evaluations": progress.evaluations(), + "best": progress.best().and_then(Fitness::score).map(error), + "median": median(scores.collect()).map(error), + "state": state, + }) +} + +// the median of the scores, None without any +fn median(mut scores: Vec) -> Option { + scores.sort_by(f64::total_cmp); + let middle = scores.len() / 2; + match scores.len() { + 0 => None, + n if n % 2 == 1 => Some(scores[middle]), + _ => Some((scores[middle - 1] + scores[middle]) / 2.0), + } +} + +// ---- the same in every example's trace --------------------------------------------------------- + +// the frames of at most `most` generations, from the part of the run where what the page plots +// changes: the frames after the last change are left out (a run that reached its target, or a +// front that no longer moves), and the rest are spread evenly over the generations up to it. While +// the run goes, up to 8 × `most` frames are kept: every `every`-th generation, with `every` +// doubling whenever there are that many, and the last one. +struct Frames { + most: usize, + every: u64, + kept: Vec<(u64, Value)>, + last: Option<(u64, Value)>, +} + +impl Frames { + fn new(most: usize) -> Self { + let (every, kept, last) = (1, Vec::new(), None); + Self { + most, + every, + kept, + last, + } + } + + fn push(&mut self, frame: Value) { + let generation = frame["generation"].as_u64().expect("a generation"); + if !generation.is_multiple_of(self.every) { + self.last = Some((generation, frame)); + return; + } + self.kept.push((generation, frame)); + self.last = None; + if self.kept.len() == 8 * self.most { + self.every *= 2; + let every = self.every; + self.kept.retain(|(generation, _)| generation % every == 0); + } + } + + fn into_vec(self) -> Vec { + let frames = self.kept.into_iter().chain(self.last); + let frames: Vec = frames.map(|(_, frame)| frame).collect(); + let active = &frames[..=last_change(&frames)]; + let (count, most) = (active.len(), self.most.max(2)); + if count <= most { + return active.to_vec(); + } + let at = |i: usize| active[(i * (count - 1) + (most - 1) / 2) / (most - 1)].clone(); + (0..most).map(at).collect() + } +} + +// the index of the frame after which nothing the page plots changes. To 3 significant digits, as +// a plot shows them: the best, the median and, for a single objective (a numeric best), the state; +// to within a hundredth of their range over the run: a front's hypervolumes, in the state or in a +// grid's series +fn last_change(frames: &[Value]) -> usize { + let Some(last) = frames.len().checked_sub(1) else { + return 0; + }; + let single = frames.iter().any(|frame| frame["best"].is_number()); + let measures = |frame: &Value| -> Vec { + let mut values = Vec::new(); + for value in [&frame["state"]["hypervolume"], &frame["series"]] { + match value { + Value::Number(number) => values.extend(number.as_f64()), + Value::Object(map) => values.extend(map.values().filter_map(Value::as_f64)), + _ => {} + } + } + values + }; + let measured: Vec> = frames.iter().map(measures).collect(); + let end = &measured[last]; + let tolerance: Vec = (0..end.len()) + .map(|k| { + let values = measured.iter().filter_map(|values| values.get(k).copied()); + let (low, high) = values.fold((f64::INFINITY, f64::NEG_INFINITY), |(low, high), v| { + (low.min(v), high.max(v)) + }); + (high - low) / 100.0 + }) + .collect(); + let settled = |i: usize| { + let (frame, final_frame) = (&frames[i], &frames[last]); + let same = + |key: &str, flush: bool| coarse(&frame[key], flush) == coarse(&final_frame[key], flush); + same("best", false) + && same("median", false) + && (!single || same("state", true)) + && measured[i].len() == end.len() + && measured[i] + .iter() + .zip(end) + .zip(&tolerance) + .all(|((value, end), tolerance)| (value - end).abs() <= *tolerance) + }; + let mut first = last; + while first > 0 && settled(first - 1) { + first -= 1; + } + first +} + +// `value` with its numbers to 3 significant digits, as precisely as a plot shows them: two frames +// whose plotted values agree to that precision look the same. With `flush`, for the solutions a +// plot draws on their ranges, numbers below 1e-6 in size count as 0 +fn coarse(value: &Value, flush: bool) -> String { + let join = |items: Vec| items.join(","); + match value { + Value::Number(number) if number.is_f64() => { + let number = number.as_f64().expect("f64"); + let number = if flush && number.abs() < 1e-6 { + 0.0 + } else { + number + }; + format!("{number:.2e}") + } + Value::Array(items) => { + format!( + "[{}]", + join(items.iter().map(|item| coarse(item, flush)).collect()) + ) + } + Value::Object(map) => { + let entry = |(key, item): (&String, &Value)| format!("{key}:{}", coarse(item, flush)); + format!("{{{}}}", join(map.iter().map(entry).collect())) + } + other => other.to_string(), + } +} + +// writes the settings and the frames to `path`, a frame per line +fn write(path: &str, settings: Value, frames: Vec) { + let frames: Vec = frames.iter().map(to_json).collect(); + let settings = to_json(&settings); + let head = &settings[..settings.len() - 1]; + let text = format!("{head},\"frames\":[\n{}\n]}}\n", frames.join(",\n")); + std::fs::write(path, text).expect("the trace is written"); +} + +// compact JSON with sorted keys, and numbers rounded to 6 significant digits and written as +// Python writes them (7542.0, 1e-08): the Python example writes the same file +fn to_json(value: &Value) -> String { + let join = |items: Vec| items.join(","); + match value { + Value::Number(number) if number.is_f64() => python_float(number.as_f64().expect("f64")), + Value::Array(items) => format!("[{}]", join(items.iter().map(to_json).collect())), + Value::Object(map) => { + let entry = + |(key, item): (&String, &Value)| format!("{}:{}", json!(key), to_json(item)); + format!("{{{}}}", join(map.iter().map(entry).collect())) + } + other => other.to_string(), + } +} + +fn python_float(value: f64) -> String { + let rounded: f64 = format!("{value:.5e}").parse().expect("a number"); + let shortest = format!("{rounded:e}"); + let (mantissa, exponent) = shortest.split_once('e').expect("an exponent"); + let exponent: i32 = exponent.parse().expect("an exponent"); + if (-4..16).contains(&exponent) { + let text = rounded.to_string(); + if text.contains('.') { + text + } else { + text + ".0" + } + } else { + let sign = if exponent < 0 { '-' } else { '+' }; + format!("{mantissa}e{sign}{:02}", exponent.abs()) + } +} diff --git a/examples/non_continuous_rastrigin/README.md b/examples/non_continuous_rastrigin/README.md new file mode 100644 index 00000000..f0a19fa5 --- /dev/null +++ b/examples/non_continuous_rastrigin/README.md @@ -0,0 +1,79 @@ +--- +title: Non-continuous Rastrigin +category: continuous +summary: Minimize Rastrigin's function made flat between half-integers, in 10 dimensions, with CMA-ES without and with restarts, DE, PSO and a GA from 10 seeds each. +reference: "Liang, J. J., Qin, A. K., Suganthan, P. N. and Baskar, S. (2006). Comprehensive learning particle swarm optimizer for global optimization of multimodal functions. IEEE Transactions on Evolutionary Computation 10(3): 281-295." +reference_url: "https://doi.org/10.1109/TEVC.2005.857610" +optimum: "0 (at the origin)" +languages: [rust, python] +order: 94 +trace_note: "Recorded from another run: CMA-ES with IPOP restarts in 2 dimensions, so that the population can be drawn on the function's contour." +--- + +# Non-continuous Rastrigin + +## The problem + +The non-continuous Rastrigin function is Rastrigin's function of genes rounded to half-integers +away from the origin: + +```text +f(x) = Σ (yᵢ² − 10 cos 2πyᵢ + 10), yᵢ = xᵢ if |xᵢ| < 1/2, round(2xᵢ)/2 otherwise +each xᵢ in [−5.12, 5.12] +``` + +Its minimum is 0, at the origin. Here n = 10. It's the function f7 of Liang, Qin, Suganthan and +Baskar (2006), whose table II gives the bounds and the minimum. `round` rounds halves away from 0, +as MATLAB's does, which their experiments used. The CEC 2017 report composes it with BBOB's +transformations, which genoxide doesn't apply. + +## What makes it hard + +Outside [−0.5, 0.5], each gene's term takes only the values of Rastrigin's function at the +half-integers: flat steps, with Rastrigin's local minima at the integers. A search sees plateaus +with no slope to follow, and as many local minima as Rastrigin's function, about 10ⁿ in the box. +Only near the origin, where every gene is within 1/2, is the function smooth. + +## Representation + +A `Real` genome of 10 genes, each in [−5.12, 5.12]: the point x itself. The fitness is f(x), to +minimize. The function is genoxide's `problems::NonContinuousRastrigin`, which brings its bounds and +its minimum. + +## Algorithm + +Five algorithms, each from seeds 1 to 10, with a budget of 10,000 evaluations per dimension, +100,000 per run, and a target of 1e-8: + +- CMA-ES (Hansen and Ostermeier, 2001, Evolutionary Computation 9(2): 159-195), which samples a + population of 10 from a normal distribution and adapts its mean, its step size and its covariance + matrix, from a step size of 0.3 of each gene's range and a random start; +- the same with IPOP restarts (Auger and Hansen, 2005, IEEE CEC 2005: 1769-1776): a run that has + converged starts again from a random point with twice the population; +- differential evolution with genoxide's defaults, SHADE (Tanabe and Fukunaga, CEC 2013), with a + population of 100 and its restarts on stagnation; +- particle swarm optimization (Kennedy and Eberhart, 1995), 40 particles with Clerc and Kennedy's + constriction coefficients and a global topology; +- a real-coded genetic algorithm: a population of 100, tournaments of 3, simulated binary crossover + (Deb and Agrawal, 1995) with η = 15 and polynomial mutation with η = 20 at a rate of 1/10 per + gene. + +## Output + +The first line gives the dimension, the seeds and the budget. Then a row per algorithm: how many +of its 10 runs reached the minimum, to within 1e-8, the median of their evaluations (a dash if none +did), and the median of every run's best error, to two significant digits. The function is +evaluated with genoxide's portable math, so the runs are the same on every platform, and in Python, +`run` evaluates it in Rust, so both versions print the same. + +[The project page](https://tachsin.gr/projects/genoxide/examples/non-continuous-rastrigin) plays back another run: +CMA-ES with IPOP restarts on the function in 2 dimensions, so that the population +can be drawn on its contour. Within 20,000 evaluations it ends at an error of 6.9e-4, near the +minimum but short of the target. + +## Good results + +The minimum is 0. SHADE reaches it in all 10 runs, after a median of 64,650 evaluations. No other +algorithm does within the budget: CMA-ES ends in a local minimum with a median error of 18, and 3.0 +with IPOP restarts; PSO's median run ends at 4.0, four genes one integer away from 0. The genetic +algorithm gets near it, to a median error of 2.4e-5. diff --git a/examples/non_continuous_rastrigin/main.py b/examples/non_continuous_rastrigin/main.py new file mode 100644 index 00000000..161709a9 --- /dev/null +++ b/examples/non_continuous_rastrigin/main.py @@ -0,0 +1,86 @@ +"""Non-continuous Rastrigin: minimize Rastrigin's function made flat between half-integers, in 10 +dimensions. + +Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), +differential evolution (SHADE), particle swarm optimization and a real-coded genetic algorithm from +10 seeds each, and counts the runs that reach the minimum, 0 at the origin, to within 1e-8. The +function is genoxide's `problems::NonContinuousRastrigin`, which run evaluates in Rust. + +With ``GENOXIDE_TRACE=``, it also writes a trace of a run for the plot on the example's page, +with trace.py. + + python examples/non_continuous_rastrigin/main.py +""" + +import genoxide as gx + +from trace import record_small + +DIMENSIONS = 10 +SEEDS = 10 +BUDGET = 10_000 * DIMENSIONS +# a run stops once its error to the minimum is at most this +ERROR = 1e-8 +ALGORITHMS = ["CMA-ES", "CMA-ES with IPOP", "DE", "PSO", "GA"] + + +def build(name, genome, seed): + """The algorithm called ``name``, on ``genome``, from ``seed``.""" + if name == "CMA-ES": + return gx.Cmaes(genome, objective="minimize", seed=seed) + if name == "CMA-ES with IPOP": + return gx.Cmaes(genome, restarts="ipop", objective="minimize", seed=seed) + if name == "DE": + return gx.De(genome, objective="minimize", seed=seed) + if name == "PSO": + return gx.Pso(genome, population_size=40, objective="minimize", seed=seed) + return gx.Ga( + genome, + population_size=100, + select=gx.Tournament(3), + crossover=gx.SimulatedBinaryCrossover(15.0), + mutation=gx.PolynomialMutation(20.0, rate=1 / DIMENSIONS), + objective="minimize", + seed=seed, + ) + + +def median(values): + """The median of ``values``, None without any.""" + values = sorted(values) + middle = len(values) // 2 + if not values: + return None + return values[middle] if len(values) % 2 else (values[middle - 1] + values[middle]) / 2 + + +def error_text(error): + """An error to two significant digits, as Rust writes it: 9.9e-9.""" + mantissa, exponent = f"{error:.1e}".split("e") + return f"{mantissa}e{int(exponent)}" + + +problem = gx.problems.NonContinuousRastrigin(DIMENSIONS) +minimum = problem.optimum.value +print(f"Non-continuous Rastrigin in {DIMENSIONS} dimensions, {SEEDS} seeds, {BUDGET} evaluations at most per run") +print("algorithm at min evaluations median error") +for name in ALGORITHMS: + # the evaluations of the runs that reach the minimum, and every run's best error + evaluations, errors = [], [] + for seed in range(1, SEEDS + 1): + result = build(name, problem.genome, seed).run( + problem, target=minimum + ERROR, evaluations=BUDGET + ) + if result.stop_reason == "target": + evaluations.append(float(result.evaluations)) + # rounding can put a solution a few ulps below the minimum + errors.append(max(result.best_fitness - minimum, 0.0)) + reached = f"{len(evaluations)}/{SEEDS}" + middle = median(evaluations) + evaluations_text = "-" if middle is None else f"{middle:.0f}" + print(f"{name:<16} {reached:>6} {evaluations_text:>11} {error_text(median(errors)):>12}") +print("evaluations: the median of the runs that reach the minimum") + +# with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate run in +# 2 dimensions: the plot is the function's contour +record_small() diff --git a/examples/non_continuous_rastrigin/main.rs b/examples/non_continuous_rastrigin/main.rs new file mode 100644 index 00000000..6801080e --- /dev/null +++ b/examples/non_continuous_rastrigin/main.rs @@ -0,0 +1,118 @@ +//! Non-continuous Rastrigin: minimize Rastrigin's function made flat between half-integers, in 10 +//! dimensions. +//! +//! Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), +//! differential evolution (SHADE), particle swarm optimization and a real-coded genetic algorithm +//! from 10 seeds each, and counts the runs that reach the minimum, 0 at the origin, to within +//! 1e-8. The function is genoxide's `problems::NonContinuousRastrigin`. +//! +//! With `GENOXIDE_TRACE=`, it also writes a trace of a run for the plot on the example's +//! page, with `trace.rs`. +//! +//! ```text +//! cargo run --release --example non_continuous_rastrigin +//! ``` + +mod trace; + +use genoxide::prelude::*; +use genoxide::problems::{NonContinuousRastrigin, Problem}; + +const DIMENSIONS: usize = 10; +const SEEDS: u64 = 10; +const BUDGET: u64 = 10_000 * DIMENSIONS as u64; +// a run stops once its error to the minimum is at most this +const ERROR: f64 = 1e-8; +const ALGORITHMS: [&str; 5] = ["CMA-ES", "CMA-ES with IPOP", "DE", "PSO", "GA"]; + +fn main() -> Result<()> { + let problem = NonContinuousRastrigin::new(DIMENSIONS); + let minimum = problem.optimum().expect("known").value(); + println!( + "Non-continuous Rastrigin in {DIMENSIONS} dimensions, {SEEDS} seeds, {BUDGET} evaluations at most per run" + ); + println!("algorithm at min evaluations median error"); + for algorithm in ALGORITHMS { + // the evaluations of the runs that reach the minimum, and every run's best error + let mut evaluations = Vec::new(); + let mut errors = Vec::new(); + for seed in 1..=SEEDS { + let outcome = run(algorithm, problem, seed, minimum + ERROR)?; + if outcome.stop_reason() == StopReason::Target { + evaluations.push(outcome.evaluations() as f64); + } + // rounding can put a solution a few ulps below the minimum + let best = outcome.best_fitness().score().expect("valid"); + errors.push((best - minimum).max(0.0)); + } + let reached = format!("{}/{SEEDS}", evaluations.len()); + let evaluations = median(evaluations).map_or("-".to_string(), |e| format!("{e:.0}")); + let error = median(errors).expect("a run"); + println!( + "{algorithm:<16} {reached:>6} {evaluations:>11} {:>12}", + format!("{error:.1e}") + ); + } + println!("evaluations: the median of the runs that reach the minimum"); + + // with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate + // run in 2 dimensions: the plot is the function's contour + trace::record_small()?; + Ok(()) +} + +// a run of `algorithm` from `seed`, until its best is at most `target` or it has used BUDGET +// evaluations +fn run(algorithm: &str, problem: NonContinuousRastrigin, seed: u64, target: f64) -> Result> { + let real = problem.representation(); + let stop = Stop::target(target).or(Stop::evaluations(BUDGET)); + match algorithm { + "CMA-ES" | "CMA-ES with IPOP" => { + let restarts = if algorithm == "CMA-ES" { + cmaes::Restarts::Never + } else { + cmaes::Restarts::Ipop + }; + let cmaes = Cmaes::builder(real) + .restarts(restarts) + .minimize() + .seed(seed) + .build()?; + Engine::new(cmaes, problem).stop_when(stop).run() + } + "DE" => { + let de = De::builder(real).minimize().seed(seed).build()?; + Engine::new(de, problem).stop_when(stop).run() + } + "PSO" => { + let pso = Pso::builder(real) + .population_size(40) + .minimize() + .seed(seed) + .build()?; + Engine::new(pso, problem).stop_when(stop).run() + } + _ => { + let ga = Ga::builder(real) + .population_size(100) + .select(Tournament::new(3)?) + .crossover(SimulatedBinaryCrossover::new(15.0)?) + .mutate(PolynomialMutation::per_gene(1.0 / DIMENSIONS as f64, 20.0)?) + .minimize() + .seed(seed) + .build()?; + Engine::new(ga, problem).stop_when(stop).run() + } + } +} + +// the median of `values`, None without any +fn median(mut values: Vec) -> Option { + values.sort_by(f64::total_cmp); + let middle = values.len() / 2; + match values.len() { + 0 => None, + n if n % 2 == 1 => Some(values[middle]), + _ => Some((values[middle - 1] + values[middle]) / 2.0), + } +} diff --git a/examples/non_continuous_rastrigin/output.txt b/examples/non_continuous_rastrigin/output.txt new file mode 100644 index 00000000..237c0b1a --- /dev/null +++ b/examples/non_continuous_rastrigin/output.txt @@ -0,0 +1,8 @@ +Non-continuous Rastrigin in 10 dimensions, 10 seeds, 100000 evaluations at most per run +algorithm at min evaluations median error +CMA-ES 0/10 - 1.8e1 +CMA-ES with IPOP 0/10 - 3.0e0 +DE 10/10 64650 8.3e-9 +PSO 0/10 - 4.0e0 +GA 0/10 - 2.4e-5 +evaluations: the median of the runs that reach the minimum diff --git a/examples/non_continuous_rastrigin/trace.json b/examples/non_continuous_rastrigin/trace.json new file mode 100644 index 00000000..2aa1c251 --- /dev/null +++ b/examples/non_continuous_rastrigin/trace.json @@ -0,0 +1,102 @@ +{"example":"non_continuous_rastrigin","format":1,"log_y":true,"objective":"minimize","optimum":0.0,"plot":"contour","problem":{"bounds":[[-5.12,5.12],[-5.12,5.12]],"function":"non_continuous_rastrigin","minima":[[0.0,0.0]]},"x_label":"evaluations","y_label":"error","frames":[ +{"best":10.0,"evaluations":6,"generation":0,"median":26.125,"state":{"best":[1.12361,-3.12689],"population":[[-4.12525,-1.25255],[1.12361,-3.12689],[-2.76721,3.85927],[-1.09665,-4.76155],[-3.84623,-3.71773],[2.19644,-1.46323]]}}, +{"best":2.0,"evaluations":24,"generation":3,"median":26.125,"state":{"best":[-0.920022,1.02881],"population":[[3.37521,4.40592],[1.67241,-2.35105],[-1.09569,2.66805],[0.895187,0.107115],[-0.920022,1.02881],[-3.9104,2.80421]]}}, +{"best":2.0,"evaluations":48,"generation":7,"median":35.9522,"state":{"best":[-0.920022,1.02881],"population":[[0.446356,4.17053],[-0.141956,3.05816],[-1.02525,4.44077],[-0.181848,3.36809],[-0.249296,2.35258],[-2.09038,2.54546]]}}, +{"best":2.0,"evaluations":66,"generation":10,"median":22.562,"state":{"best":[-0.920022,1.02881],"population":[[-0.367734,2.04695],[-0.308554,4.72818],[0.0856623,4.04036],[0.498342,1.99291],[-1.13621,2.87146],[0.117034,2.48851]]}}, +{"best":2.0,"evaluations":84,"generation":13,"median":18.954,"state":{"best":[-0.920022,1.02881],"population":[[-0.965508,2.06867],[-0.307984,0.927359],[-1.05591,1.70484],[-0.605862,3.28704],[-1.46779,1.06911],[-0.0944709,2.14321]]}}, +{"best":2.0,"evaluations":102,"generation":16,"median":18.2844,"state":{"best":[-0.920022,1.02881],"population":[[-0.902095,0.184946],[-0.624586,1.54502],[-0.817529,-0.319281],[-0.653334,1.18347],[-0.375324,1.28325],[-0.963308,1.20934]]}}, +{"best":2.0,"evaluations":126,"generation":20,"median":22.25,"state":{"best":[-0.920022,1.02881],"population":[[-0.606503,1.9887],[-1.08194,0.6337],[-0.684937,1.25064],[-0.937257,0.809256],[-0.877078,0.485137],[-0.790777,1.2993]]}}, +{"best":2.0,"evaluations":156,"generation":23,"median":33.625,"state":{"best":[-0.920022,1.02881],"population":[[-0.829534,-0.859724],[1.75781,0.656768],[0.109446,-3.10387],[-0.132094,1.13987],[3.09476,4.85259],[-3.27163,-1.37927],[0.344474,3.08386],[-4.70722,-1.75832],[3.79112,5.07643],[-3.35314,1.16445],[-1.57368,4.60899],[-2.46986,2.6422]]}}, +{"best":2.0,"evaluations":192,"generation":26,"median":37.5846,"state":{"best":[-0.920022,1.02881],"population":[[-0.489784,0.365031],[-2.65429,-0.279997],[-1.73756,-0.461341],[-1.2773,3.0166],[-4.01303,1.29385],[-1.52037,0.220691],[-0.774149,-1.87743],[2.71004,-0.199354],[2.74295,0.419654],[-1.56589,0.680272],[0.125519,-0.119592],[-1.74959,-0.490682]]}}, +{"best":1.55347,"evaluations":240,"generation":30,"median":20.3225,"state":{"best":[0.0530625,-0.849806],"population":[[-1.30731,-0.0594121],[-0.213254,-0.936577],[0.674522,-0.240201],[-0.180625,0.0735063],[-0.492816,0.280712],[0.568465,-1.01678],[0.413048,-2.08454],[0.207252,0.149636],[1.2341,0.680218],[0.240584,-1.06335],[-0.0540425,-0.184486],[-0.781202,-0.403905]]}}, +{"best":1.21268,"evaluations":276,"generation":33,"median":18.9796,"state":{"best":[0.032799,-0.868753],"population":[[0.131445,-0.402835],[-0.172288,-0.219996],[0.129131,-0.415183],[-0.182424,-0.345591],[0.204393,-0.815671],[0.610321,-0.405244],[0.239201,-0.245051],[0.177185,-0.0419379],[-0.503198,-0.188642],[0.0764398,-0.161141],[0.16961,-0.307699],[0.0475229,-1.03426]]}}, +{"best":1.18599,"evaluations":312,"generation":36,"median":18.24,"state":{"best":[-0.0306654,-0.894831],"population":[[-0.0822925,-0.648549],[-0.0987004,-0.574198],[-0.0400726,-1.37848],[-0.162739,-0.917765],[-0.0212168,-0.420104],[0.287055,-1.02289],[-0.219512,-1.26012],[0.034169,-0.375126],[0.104305,-1.18584],[-0.327405,-0.846977],[-0.390185,-1.74721],[0.0586938,-1.22828]]}}, +{"best":1.00102,"evaluations":360,"generation":40,"median":5.02995,"state":{"best":[-0.00227007,-0.908661],"population":[[-0.0678541,-1.34],[-0.146643,-1.17885],[0.0508414,-0.609749],[-0.147531,-1.06298],[0.147959,-0.786122],[0.0812149,-0.673021],[0.0997555,-1.24216],[0.00782804,-1.15802],[-0.0408547,-0.940563],[-0.0615931,-0.462946],[0.0602174,-1.3715],[-0.0102518,-0.140092]]}}, +{"best":1.00007,"evaluations":396,"generation":43,"median":1.06557,"state":{"best":[0.000572482,-0.991288],"population":[[0.00284694,-0.841798],[0.0163397,-0.932514],[-0.00179389,-0.951042],[-0.0280782,-1.05723],[-0.0146117,-1.10189],[0.0198695,-0.911614],[0.0137726,-0.918895],[-0.0606871,-0.907037],[-0.0237929,-0.799438],[0.000572482,-0.991288],[-0.027817,-1.01608],[-0.0348025,-0.925533]]}}, +{"best":1.00007,"evaluations":432,"generation":46,"median":1.03042,"state":{"best":[0.000572482,-0.991288],"population":[[0.00191819,-0.841688],[0.00650969,-0.868469],[-0.00195799,-0.952794],[-0.0228381,-0.71271],[-0.00852099,-0.890581],[0.00335603,-0.777093],[-0.0315033,-0.948061],[-0.0188529,-0.740811],[-0.0153054,-0.83736],[0.0118593,-0.551282],[-0.0205093,-0.819245],[-0.00332859,-0.762667]]}}, +{"best":1.00001,"evaluations":468,"generation":49,"median":1.00622,"state":{"best":[-0.000171576,-1.00017],"population":[[0.00566491,-0.870626],[-0.00705382,-1.01816],[0.000242168,-0.796895],[-0.00653377,-0.987045],[-0.00178281,-0.769058],[-0.00524017,-0.989563],[0.00631628,-0.941655],[-0.0024803,-0.847546],[-0.00553678,-1.08167],[0.0107986,-0.977845],[-0.000171576,-1.00017],[-0.0162217,-0.813186]]}}, +{"best":1.0,"evaluations":516,"generation":53,"median":1.00019,"state":{"best":[4.02523e-05,-0.925364],"population":[[-0.00023266,-0.814664],[-0.00178505,-0.780948],[-0.000796804,-0.898031],[0.00105726,-0.881476],[-0.00153723,-0.873373],[-0.000696234,-0.901057],[-0.000814557,-0.817616],[-0.000898619,-0.839929],[-0.00276499,-0.895212],[-0.00031873,-0.8536],[-0.00169862,-0.8812],[-0.00243526,-0.830741]]}}, +{"best":1.0,"evaluations":552,"generation":56,"median":1.00001,"state":{"best":[-1.84133e-05,-0.82406],"population":[[0.000275675,-0.833756],[-2.43568e-05,-0.844811],[0.000641599,-0.86256],[0.000246291,-0.822732],[0.000374663,-0.862147],[-0.000233265,-0.877577],[0.000357688,-0.823104],[-0.000739394,-0.837423],[0.000212695,-0.836503],[-0.000190156,-0.855499],[0.000199197,-0.870975],[0.000522846,-0.873538]]}}, +{"best":1.0,"evaluations":588,"generation":59,"median":1.00002,"state":{"best":[-1.84133e-05,-0.82406],"population":[[0.000339073,-0.886171],[-0.000397435,-0.845617],[-2.50412e-05,-0.87639],[0.000231118,-0.868538],[-0.000171739,-0.85058],[-7.88257e-05,-0.879931],[-0.000425157,-0.866018],[-0.00027024,-0.856444],[-0.00034392,-0.877549],[-0.000551309,-0.860602],[7.27348e-05,-0.899635],[-0.000412656,-0.903782]]}}, +{"best":1.0,"evaluations":636,"generation":63,"median":1.0,"state":{"best":[9.23453e-06,-0.896122],"population":[[0.000212318,-0.888355],[-3.64371e-05,-0.891465],[-8.54333e-05,-0.890335],[9.74439e-05,-0.876245],[-0.000136688,-0.896073],[5.53707e-05,-0.867586],[0.000110983,-0.895009],[0.000187538,-0.892452],[-0.000146234,-0.871056],[7.36336e-05,-0.880039],[6.80286e-05,-0.896606],[0.000109309,-0.881118]]}}, +{"best":1.0,"evaluations":672,"generation":66,"median":1.0,"state":{"best":[-2.45471e-07,-0.891427],"population":[[-0.00012718,-0.883686],[-9.60345e-06,-0.898619],[2.65842e-05,-0.880361],[-0.00010382,-0.904759],[6.20907e-05,-0.902347],[8.9918e-07,-0.881269],[-4.26487e-06,-0.901688],[6.83136e-05,-0.895579],[2.03904e-05,-0.892205],[-5.16249e-05,-0.881546],[1.0908e-05,-0.908887],[-0.00012677,-0.896637]]}}, +{"best":1.0,"evaluations":708,"generation":69,"median":1.0,"state":{"best":[-2.45471e-07,-0.891427],"population":[[-8.7132e-06,-0.90525],[2.29786e-05,-0.897758],[-1.26822e-05,-0.896265],[-3.45836e-05,-0.892578],[-5.42638e-06,-0.900769],[-1.19728e-05,-0.89339],[1.90778e-06,-0.893309],[-1.32075e-05,-0.901856],[-1.82398e-05,-0.8963],[3.67713e-05,-0.896151],[2.54767e-06,-0.890203],[3.10686e-05,-0.896084]]}}, +{"best":1.0,"evaluations":744,"generation":72,"median":1.0,"state":{"best":[1.31192e-07,-0.890625],"population":[[-6.54921e-06,-0.888458],[4.20637e-07,-0.888917],[-6.11682e-06,-0.900439],[-1.57759e-06,-0.893516],[-3.57078e-06,-0.875236],[1.38232e-05,-0.886084],[-9.25428e-06,-0.886978],[-1.70022e-05,-0.889549],[1.06808e-05,-0.892563],[9.12348e-06,-0.8831],[-6.07984e-07,-0.894197],[2.41558e-05,-0.88524]]}}, +{"best":1.0,"evaluations":792,"generation":76,"median":1.0,"state":{"best":[1.31192e-07,-0.890625],"population":[[-5.02956e-06,-0.889678],[-2.41714e-06,-0.88717],[5.27902e-06,-0.892737],[-3.44836e-06,-0.892816],[-1.88519e-06,-0.88983],[-4.95518e-06,-0.892892],[-4.51342e-07,-0.890272],[-2.15116e-06,-0.890596],[-2.52125e-06,-0.891833],[1.80525e-06,-0.889282],[2.8802e-07,-0.89158],[-1.83904e-06,-0.889877]]}}, +{"best":1.0,"evaluations":828,"generation":79,"median":1.0,"state":{"best":[1.96927e-08,-0.88964],"population":[[-6.84684e-07,-0.890821],[-1.36618e-07,-0.888471],[-5.75502e-07,-0.890747],[1.7574e-06,-0.891375],[-9.97552e-07,-0.88989],[-1.53742e-06,-0.890303],[3.67038e-07,-0.889983],[1.29998e-07,-0.890232],[2.30967e-06,-0.89047],[2.15938e-06,-0.889585],[5.80812e-07,-0.890454],[1.00883e-06,-0.888999]]}}, +{"best":1.0,"evaluations":864,"generation":82,"median":1.0,"state":{"best":[1.96927e-08,-0.88964],"population":[[4.79812e-07,-0.889406],[-4.35087e-07,-0.889467],[-3.42766e-07,-0.889022],[3.45933e-07,-0.890364],[-5.78871e-07,-0.889039],[5.88632e-07,-0.890222],[8.58753e-08,-0.889588],[1.70723e-07,-0.889276],[-6.03788e-07,-0.889266],[-2.45039e-07,-0.888403],[-4.44823e-07,-0.889432],[-1.30206e-06,-0.889956]]}}, +{"best":1.0,"evaluations":912,"generation":86,"median":1.0,"state":{"best":[-4.74707e-09,-0.889473],"population":[[2.62514e-07,-0.889533],[-5.30879e-08,-0.890439],[-1.2304e-07,-0.889498],[-4.74707e-09,-0.889473],[2.15367e-07,-0.889672],[4.8869e-09,-0.889121],[4.00132e-08,-0.88996],[-1.97788e-07,-0.890331],[5.62068e-08,-0.88961],[-9.65221e-08,-0.889546],[-3.17717e-08,-0.889803],[2.20073e-07,-0.889984]]}}, +{"best":1.0,"evaluations":948,"generation":89,"median":1.0,"state":{"best":[2.63855e-10,-0.890223],"population":[[4.18354e-07,-0.889497],[-1.54898e-07,-0.889508],[-3.06293e-07,-0.888901],[7.57969e-08,-0.888875],[-2.20184e-07,-0.890744],[-6.20076e-08,-0.888368],[2.7029e-08,-0.88974],[-6.20785e-08,-0.88784],[6.58775e-08,-0.888434],[4.7715e-08,-0.889338],[-2.30504e-07,-0.887365],[2.63855e-10,-0.890223]]}}, +{"best":1.0,"evaluations":984,"generation":92,"median":1.0,"state":{"best":[2.63855e-10,-0.890223],"population":[[2.47892e-09,-0.889001],[1.6499e-08,-0.889346],[-1.08082e-08,-0.888791],[-5.04258e-08,-0.889176],[5.90081e-08,-0.889499],[3.78398e-08,-0.889495],[-4.83779e-09,-0.889035],[4.7036e-08,-0.889474],[2.99281e-08,-0.889454],[-6.58081e-09,-0.889452],[-1.5053e-08,-0.889492],[6.09341e-08,-0.888992]]}}, +{"best":1.0,"evaluations":1020,"generation":95,"median":1.0,"state":{"best":[2.63855e-10,-0.890223],"population":[[-1.19233e-08,-0.889488],[-3.55889e-09,-0.889573],[1.57593e-08,-0.889072],[-2.02904e-08,-0.888447],[1.94934e-08,-0.889004],[-5.8199e-10,-0.888758],[2.70668e-08,-0.889044],[3.02879e-08,-0.88964],[4.81957e-08,-0.889272],[-5.51115e-08,-0.888983],[5.31715e-08,-0.889574],[-2.59133e-08,-0.888513]]}}, +{"best":1.0,"evaluations":1092,"generation":99,"median":32.25,"state":{"best":[2.63855e-10,-0.890223],"population":[[-0.743581,2.18144],[1.99849,-3.4784],[-0.714531,-0.983007],[3.04728,-2.80735],[2.57069,-3.17319],[2.35782,-2.03472],[-3.54126,-0.864324],[2.62566,4.11297],[-0.666136,2.97038],[2.9225,0.902045],[1.29454,-3.48039],[-4.54727,-1.54754],[-1.63649,-4.71636],[3.44928,2.75375],[-3.91259,1.96295],[-0.0453727,-1.85139],[-3.77154,0.260465],[-3.18162,1.38118],[3.33042,-3.75167],[0.252319,0.126509],[2.84877,-2.63197],[0.838296,2.75226],[-3.80103,0.658003],[-3.46609,0.144409]]}}, +{"best":1.0,"evaluations":1164,"generation":102,"median":23.75,"state":{"best":[2.63855e-10,-0.890223],"population":[[-1.84487,-1.76068],[-0.176398,0.17188],[3.69656,-2.97081],[0.113743,2.97195],[0.662636,3.87447],[0.57702,-1.95814],[-2.16028,4.11521],[-0.646414,0.339381],[-1.45782,1.74196],[2.47494,0.750508],[-0.582773,-0.355314],[-1.36375,0.97292],[-1.21373,-1.36841],[0.720203,1.10658],[-0.639964,-0.229262],[1.8199,4.66614],[0.163931,0.618194],[-3.28737,0.150117],[-1.18573,1.47913],[-0.49778,-0.84099],[-1.14158,3.07546],[-0.372303,1.86829],[1.27587,1.37284],[1.75832,-3.76042]]}}, +{"best":1.0,"evaluations":1236,"generation":105,"median":23.88,"state":{"best":[2.63855e-10,-0.890223],"population":[[0.825256,-2.23536],[2.82097,2.54532],[2.2156,-2.0423],[-2.52684,2.82784],[0.884154,-0.79278],[0.517608,0.529689],[0.538301,1.23685],[1.31102,-3.29916],[0.940728,-4.23096],[1.26226,-1.97228],[-1.30005,1.1674],[1.10008,-1.44702],[3.04904,-2.80042],[-0.158141,0.462748],[0.791418,-2.21596],[1.45559,-0.725895],[1.87983,-3.28883],[-2.40633,-2.27209],[-0.98588,-0.270291],[0.743727,2.25282],[0.122665,0.216938],[-0.0141053,-0.508968],[1.46824,-2.68511],[1.19573,2.7284]]}}, +{"best":0.225551,"evaluations":1332,"generation":109,"median":21.1046,"state":{"best":[-0.0331521,-0.00646454],"population":[[-0.373801,0.969413],[0.137858,-0.428115],[0.704298,0.420626],[0.292394,1.31735],[0.0716223,0.010325],[1.04714,-3.67797],[0.0157632,1.62071],[-2.72708,0.902595],[-1.75018,1.92681],[0.956374,-3.16736],[1.21542,-0.659036],[0.0220043,0.608499],[-2.38906,2.63705],[0.614558,0.484959],[0.154455,0.2962],[0.539235,-0.0582512],[2.34322,-3.98489],[2.5992,-0.898841],[-1.12698,-0.46391],[-0.603203,2.95828],[-2.07924,0.99259],[-0.0332269,-0.494441],[-2.19874,0.992889],[0.658059,-0.0338143]]}}, +{"best":0.225551,"evaluations":1404,"generation":112,"median":27.25,"state":{"best":[-0.0331521,-0.00646454],"population":[[-1.07432,1.87344],[-1.26356,-2.37507],[2.49213,-0.757816],[-0.747947,-0.321496],[-0.326587,-1.70217],[-1.03154,-0.140995],[1.88969,-2.17187],[-3.5572,-0.46997],[-2.23019,-1.47822],[0.919673,-0.730165],[0.475136,0.10096],[-0.526082,0.785591],[-4.27331,2.34341],[-2.74471,-1.14058],[-0.50069,-0.803167],[-1.29159,-1.17456],[-0.647419,-1.59344],[0.31558,-1.28072],[-2.96344,-1.51041],[-0.311917,-1.51904],[0.124825,2.03281],[-2.74493,0.667237],[-0.403409,0.753471],[0.647647,-1.47052]]}}, +{"best":0.225551,"evaluations":1476,"generation":115,"median":21.25,"state":{"best":[-0.0331521,-0.00646454],"population":[[1.62545,-0.616787],[0.305976,-0.236514],[0.339294,0.357044],[-0.223858,-1.35295],[-0.773395,0.837591],[0.782501,-0.336948],[0.496227,0.770427],[-1.24485,0.685988],[0.0420556,-1.55168],[1.63632,-1.82669],[0.447751,0.90495],[0.0420841,-0.123695],[-0.658551,0.561321],[1.5575,1.26998],[0.555813,1.07357],[-0.111443,-0.290456],[0.450023,0.669282],[-0.83289,-0.0363343],[-0.439365,-0.937622],[-0.548285,1.34275],[0.309241,-0.980479],[-0.251651,-0.076468],[1.56539,0.816914],[-0.489726,-0.986098]]}}, +{"best":0.225551,"evaluations":1572,"generation":119,"median":24.75,"state":{"best":[-0.0331521,-0.00646454],"population":[[-2.24023,2.05192],[-0.566491,-0.0265014],[-1.72592,2.09257],[-1.11995,0.299326],[-0.591067,0.206576],[-0.839771,0.768594],[-1.51704,1.57431],[-2.21281,2.49327],[-2.20447,1.50471],[-1.08254,1.24865],[-3.02541,1.59891],[0.761994,0.207857],[-3.15469,2.53154],[-2.16726,1.46352],[-2.3627,0.915154],[-1.06965,0.807556],[-0.0402233,-1.0731],[-1.29362,1.22391],[-2.64927,1.85881],[-2.68062,1.25717],[-1.4148,0.820085],[0.159324,1.07],[-1.81196,1.90627],[-1.37787,0.749892]]}}, +{"best":0.225551,"evaluations":1644,"generation":122,"median":23.25,"state":{"best":[-0.0331521,-0.00646454],"population":[[-0.608984,-0.207754],[-1.60725,0.970165],[-0.772519,-0.440852],[-0.501735,-0.813961],[-0.968124,-0.0298833],[-1.45467,0.854341],[0.12224,0.27553],[-2.71166,2.17887],[-1.99305,1.72733],[0.115825,-0.333003],[-0.838662,-0.0120761],[-1.66287,1.53709],[-0.962957,0.599918],[-2.57973,1.53654],[-0.377293,-0.351208],[-1.5416,0.802906],[-2.02247,1.0141],[-1.22876,0.31633],[-1.43259,0.0143905],[-1.46603,0.479021],[-0.933742,-0.159107],[-0.603174,0.275206],[-1.73749,0.776067],[-1.601,0.624658]]}}, +{"best":0.225551,"evaluations":1716,"generation":125,"median":18.388,"state":{"best":[-0.0331521,-0.00646454],"population":[[-0.441691,-0.426873],[-1.0886,-0.0683333],[0.0890127,0.241002],[-2.54662,1.00431],[-1.66307,-0.377411],[-1.772,-0.210377],[-1.09027,-0.362079],[-1.45163,-0.0911499],[-2.00383,1.22037],[-0.894763,-0.688127],[0.210045,-0.439699],[-1.33777,-0.474028],[-0.153195,-0.8715],[-1.38447,-0.379847],[-2.21965,0.493225],[-0.997318,-0.0315549],[-0.961598,-0.0195029],[-0.860706,-0.479502],[-1.11321,-0.381728],[0.312642,-0.15367],[-1.03322,0.27949],[-1.7666,0.753492],[-1.9292,0.686033],[-0.241508,-0.886313]]}}, +{"best":0.225551,"evaluations":1788,"generation":128,"median":21.25,"state":{"best":[-0.0331521,-0.00646454],"population":[[-1.22355,-0.394637],[-0.590634,-0.0259524],[-0.829131,0.559492],[-0.486144,-0.165795],[-1.47271,-0.137046],[-0.898962,0.726606],[-1.00565,0.267964],[-1.39133,0.335682],[-0.882847,0.890686],[-0.799715,0.102007],[-1.62191,0.699879],[-0.552918,0.0303203],[-1.19448,-0.452242],[-1.66095,-0.444255],[-1.13421,-0.465681],[-0.70138,-0.639667],[-1.59018,0.250397],[-0.424471,-0.70183],[-1.01009,-0.0718244],[-0.885435,-0.526929],[-1.1365,0.532092],[0.157547,-0.0296308],[-0.605896,-0.615101],[-1.03691,0.0204744]]}}, +{"best":0.225551,"evaluations":1884,"generation":132,"median":1.99918,"state":{"best":[-0.0331521,-0.00646454],"population":[[-1.04068,-0.0141043],[-1.19136,-0.0130037],[-0.856165,0.0773113],[-0.953306,0.14321],[-1.00997,-0.0997337],[-0.939393,0.056412],[-0.987265,0.0653538],[-1.04818,-0.102314],[-0.737904,-0.0759592],[-1.04532,0.0305865],[-0.824131,-0.0502772],[-0.936428,0.085999],[-1.08696,0.00873084],[-1.10574,0.0913369],[-0.990343,-0.0142391],[-0.926218,-0.130039],[-0.941028,0.134225],[-0.831309,0.041879],[-0.817069,-0.111011],[-0.958712,-0.140735],[-0.906057,-0.054513],[-1.10684,-0.00217285],[-1.01655,-0.0505024],[-0.981901,0.224033]]}}, +{"best":0.225551,"evaluations":1956,"generation":135,"median":1.28112,"state":{"best":[-0.0331521,-0.00646454],"population":[[-1.09637,0.0120587],[-0.868221,-0.021559],[-1.15989,0.0393224],[-1.20412,-0.0417044],[-1.12863,0.0399306],[-0.957778,-0.045613],[-1.01965,-0.00737404],[-1.23085,0.0373361],[-1.13035,-0.00877305],[-1.02362,0.0668998],[-0.966818,0.0929104],[-0.875967,0.0896491],[-1.26145,0.0442518],[-1.12888,0.0360319],[-1.07185,0.0439291],[-1.03748,-0.00809296],[-1.06905,0.0342808],[-1.14514,0.0181611],[-0.98739,0.0124412],[-1.04792,-0.0146065],[-1.15985,0.0381221],[-1.16046,0.0413346],[-0.768923,0.0042683],[-0.930797,0.07535]]}}, +{"best":0.225551,"evaluations":2028,"generation":138,"median":1.00777,"state":{"best":[-0.0331521,-0.00646454],"population":[[-0.951487,0.00839852],[-0.949237,-0.0171386],[-0.854543,-0.00367668],[-0.97127,-0.00705716],[-0.935392,0.00711168],[-0.866754,0.000619403],[-0.924436,0.00544663],[-1.17961,-0.00162031],[-0.980637,0.00517068],[-0.85399,-0.020549],[-0.934025,-0.0143974],[-0.90318,-0.00749261],[-1.14743,0.00532238],[-1.00464,0.00650249],[-0.838066,0.00404029],[-1.0294,0.00365048],[-1.00845,-0.0111015],[-1.02806,-0.0113265],[-0.955568,0.00600189],[-0.817843,0.00541264],[-1.02087,-0.00491257],[-0.806829,0.0138693],[-0.940914,0.019141],[-1.05855,0.00363784]]}}, +{"best":0.225551,"evaluations":2124,"generation":142,"median":1.0002,"state":{"best":[-0.0331521,-0.00646454],"population":[[-0.939956,4.81202e-05],[-0.977068,-0.000260418],[-0.950419,0.000374111],[-0.897457,0.00164082],[-0.886498,0.000693501],[-0.967643,-0.00218385],[-0.934401,-0.000107589],[-0.88848,-0.00159178],[-0.912468,0.00104209],[-1.00515,0.000673169],[-0.949736,-0.00121973],[-0.925637,-0.0010087],[-0.887199,0.00102052],[-0.947414,-0.000570747],[-0.938865,-0.00349654],[-0.902643,-0.000398176],[-0.96577,-0.00234244],[-0.930632,-0.00127446],[-0.939501,0.00208987],[-0.96496,0.00170248],[-0.931971,0.000980091],[-0.889664,-0.00100223],[-0.868029,-0.000346251],[-0.917429,0.00149751]]}}, +{"best":0.225551,"evaluations":2196,"generation":145,"median":1.0,"state":{"best":[-0.0331521,-0.00646454],"population":[[-0.897118,-0.00010716],[-0.900811,9.00842e-06],[-0.952749,0.000425343],[-0.943554,4.0353e-05],[-0.950239,-0.000457209],[-0.933233,7.38675e-05],[-0.984942,0.000220828],[-0.945363,-6.59272e-05],[-0.970317,0.000359607],[-0.929328,0.000170563],[-0.946179,0.000132959],[-0.945464,-5.01214e-05],[-0.981018,-0.000261861],[-0.94882,-0.000332043],[-0.934856,0.00011312],[-0.913716,0.00043662],[-0.913734,0.000312659],[-0.935708,-0.000110714],[-0.95368,-0.000113507],[-0.92337,-0.000225711],[-0.914272,0.000201541],[-0.920208,0.000771301],[-0.957269,-2.23346e-05],[-0.958163,-0.000117558]]}}, +{"best":0.225551,"evaluations":2268,"generation":148,"median":1.0,"state":{"best":[-0.0331521,-0.00646454],"population":[[-0.916893,-9.40794e-05],[-0.916906,-3.83129e-05],[-0.92382,0.000189646],[-0.925301,6.39674e-05],[-0.915369,-1.84526e-05],[-0.9186,0.000101594],[-0.925311,-2.02379e-05],[-0.920772,-0.000142385],[-0.93284,8.75348e-05],[-0.931385,6.82709e-06],[-0.923696,-8.43454e-06],[-0.942291,5.60278e-05],[-0.933753,-7.90019e-05],[-0.902505,-9.04162e-05],[-0.928339,4.27179e-05],[-0.924572,-4.52313e-05],[-0.915971,2.84405e-05],[-0.922465,-5.02228e-06],[-0.930839,-1.71611e-05],[-0.936702,4.2414e-05],[-0.940681,-1.28579e-05],[-0.908008,-3.31345e-05],[-0.91319,8.67658e-05],[-0.913405,6.71039e-06]]}}, +{"best":0.225551,"evaluations":2340,"generation":151,"median":1.0,"state":{"best":[-0.0331521,-0.00646454],"population":[[-0.930044,-2.34242e-05],[-0.930542,-1.80987e-05],[-0.93459,-6.95083e-06],[-0.937228,2.65924e-06],[-0.937639,-1.76403e-05],[-0.892554,4.30189e-06],[-0.89939,-1.15085e-05],[-0.938332,1.1682e-05],[-0.938669,-1.13756e-05],[-0.92396,-4.02636e-06],[-0.915612,2.48586e-07],[-0.916056,-1.40311e-05],[-0.932364,1.30907e-05],[-0.924335,-1.49988e-05],[-0.927428,1.52944e-05],[-0.935004,-4.7334e-06],[-0.930227,1.4718e-05],[-0.941667,3.30281e-05],[-0.936812,1.3095e-05],[-0.890842,2.98603e-05],[-0.915769,1.27857e-05],[-0.926927,-3.1603e-05],[-0.94621,1.33132e-05],[-0.904586,1.4109e-05]]}}, +{"best":0.225551,"evaluations":2436,"generation":155,"median":1.0,"state":{"best":[-0.0331521,-0.00646454],"population":[[-0.910203,1.6736e-06],[-0.914403,4.79868e-06],[-0.880904,-8.58862e-06],[-0.930365,3.79238e-06],[-0.922634,-1.09989e-05],[-0.851291,6.40982e-06],[-0.95103,9.66541e-08],[-0.910375,6.65242e-07],[-0.90506,-3.48958e-06],[-0.920715,7.05857e-06],[-0.924384,3.07589e-06],[-0.889836,3.51849e-06],[-0.902518,-6.19896e-06],[-0.915636,-6.5475e-06],[-0.89392,5.80956e-07],[-0.914115,4.4035e-06],[-0.942162,9.48941e-07],[-0.915459,-7.91016e-06],[-0.893588,6.09013e-06],[-0.925999,-6.33364e-06],[-0.873478,9.11465e-06],[-0.891838,2.03481e-06],[-0.924526,1.29709e-06],[-0.883536,4.71415e-06]]}}, +{"best":0.225551,"evaluations":2508,"generation":158,"median":1.0,"state":{"best":[-0.0331521,-0.00646454],"population":[[-0.911042,-6.29762e-07],[-0.937476,-3.65605e-06],[-0.951163,-8.69505e-07],[-0.890799,2.50548e-06],[-0.904826,-2.68651e-06],[-0.931888,-1.99101e-06],[-0.897646,2.61648e-06],[-0.852196,-1.44301e-06],[-0.873032,1.21611e-06],[-0.923465,-2.78393e-06],[-0.925827,2.7252e-07],[-0.980719,2.11874e-06],[-0.87389,9.28751e-07],[-0.918623,-1.5358e-06],[-0.922989,-5.29983e-07],[-0.937154,-1.45291e-06],[-0.905025,-1.74096e-07],[-0.916622,2.68019e-06],[-0.879035,1.49175e-06],[-0.942139,8.45204e-09],[-0.920593,-1.49056e-08],[-0.901638,3.37266e-06],[-0.894288,5.09604e-07],[-0.911155,4.59339e-07]]}}, +{"best":0.225551,"evaluations":2580,"generation":161,"median":1.0,"state":{"best":[-0.0331521,-0.00646454],"population":[[-0.9432,2.61183e-07],[-0.931617,2.05069e-08],[-0.920668,2.47552e-07],[-0.912634,1.18899e-07],[-0.925315,2.43274e-08],[-0.920526,-2.52255e-07],[-0.915129,3.57714e-07],[-0.924868,7.56361e-08],[-0.910946,6.19638e-07],[-0.908741,-1.60362e-07],[-0.905532,4.25519e-07],[-0.932095,2.86889e-07],[-0.943666,1.77839e-07],[-0.928689,4.21432e-07],[-0.918377,-1.309e-07],[-0.918735,1.69925e-07],[-0.920327,-2.26174e-08],[-0.90489,-4.55982e-07],[-0.926395,-1.75743e-07],[-0.920843,4.09613e-07],[-0.898597,4.67257e-07],[-0.905402,-3.22216e-07],[-0.941279,5.4331e-07],[-0.957394,1.01324e-06]]}}, +{"best":0.225551,"evaluations":2676,"generation":165,"median":1.0,"state":{"best":[-0.0331521,-0.00646454],"population":[[-0.943623,-1.14754e-07],[-0.93242,-4.18866e-08],[-0.923679,-2.48631e-08],[-0.938757,6.48068e-08],[-0.933017,8.84858e-08],[-0.925702,-5.58597e-08],[-0.9347,1.39104e-08],[-0.944905,1.21157e-07],[-0.937807,2.30225e-08],[-0.935436,4.20191e-08],[-0.940583,6.79678e-08],[-0.950104,5.31919e-08],[-0.934119,7.40905e-08],[-0.932342,4.12151e-09],[-0.937699,3.37192e-08],[-0.936162,1.01256e-07],[-0.934719,4.2509e-09],[-0.941398,-5.5266e-08],[-0.929239,-6.3712e-08],[-0.927957,-3.91765e-08],[-0.924725,3.5067e-08],[-0.928173,1.11212e-07],[-0.92299,-8.72377e-08],[-0.940537,-4.34968e-11]]}}, +{"best":0.225551,"evaluations":2748,"generation":168,"median":1.0,"state":{"best":[-0.0331521,-0.00646454],"population":[[-0.944205,-2.26603e-08],[-0.933693,2.94421e-08],[-0.93925,1.83876e-08],[-0.942092,1.35822e-08],[-0.933025,-2.25499e-09],[-0.92546,3.05887e-08],[-0.918071,-1.67427e-08],[-0.926062,8.43989e-09],[-0.934294,-3.83879e-09],[-0.939318,-3.09068e-08],[-0.930671,2.04678e-08],[-0.935345,2.69883e-08],[-0.929579,-8.95271e-09],[-0.935822,-2.98831e-08],[-0.928359,1.41788e-08],[-0.930604,1.16534e-08],[-0.924843,1.22209e-08],[-0.925175,1.48496e-08],[-0.922002,-5.62091e-09],[-0.938443,-1.4866e-08],[-0.933333,-1.58496e-08],[-0.933377,-2.01401e-09],[-0.933263,1.37987e-08],[-0.933739,-7.02896e-09]]}}, +{"best":0.225551,"evaluations":2844,"generation":171,"median":41.1402,"state":{"best":[-0.0331521,-0.00646454],"population":[[-4.24777,3.3343],[-1.7128,3.05385],[-3.91968,2.03755],[-4.64104,1.45128],[1.07155,2.28369],[-4.57894,2.80056],[-4.46584,1.50447],[-4.0971,2.03336],[-4.44868,1.77964],[-3.01148,2.1466],[-4.61465,3.01285],[-5.04903,0.201353],[-4.05667,1.65971],[-3.41404,-4.05295],[-3.97387,0.438772],[0.0963437,3.86954],[-0.765139,0.860652],[0.114042,-4.11137],[-1.37067,0.380396],[1.08122,3.15722],[-3.34157,4.00453],[-4.5568,2.8092],[-0.720188,3.42473],[-2.51705,4.21418],[0.191196,-0.367445],[-4.31435,2.41576],[-3.33907,4.91596],[0.453419,0.724554],[-4.64536,1.93924],[-4.61779,0.542847],[-4.87801,2.2011],[-2.31077,4.21164],[-1.32829,-0.629775],[1.27048,4.17866],[-3.40698,2.20967],[2.44414,1.92849],[-2.44985,5.10312],[-3.77758,0.496787],[-4.0498,3.32679],[-1.44552,3.15055],[1.62105,-2.26566],[-3.73402,1.72364],[-2.78142,1.96451],[-0.405295,4.92856],[-4.35775,3.58538],[-4.67116,3.58451],[-2.28819,2.10859],[-2.15935,3.20897]]}}, +{"best":0.225551,"evaluations":3036,"generation":175,"median":25.625,"state":{"best":[-0.0331521,-0.00646454],"population":[[-0.151484,0.437636],[2.35247,0.947542],[0.0651296,-0.425954],[-0.130251,-0.348252],[-1.61718,1.29132],[0.94237,-1.67184],[1.43091,0.506592],[-1.11729,-0.188093],[-1.88047,0.200924],[-3.26576,0.619534],[0.698512,-0.540662],[1.48414,0.325854],[5.0154,-1.62965],[-0.22747,-0.777383],[0.0684867,-0.591658],[-0.304217,2.51834],[2.95001,-0.493058],[1.20099,2.88766],[-0.573007,-2.70598],[-1.74629,2.2202],[3.89613,-3.22863],[-1.76452,-2.97075],[2.49813,3.00034],[0.940987,-0.580726],[1.91963,0.396698],[-2.38653,2.27425],[-1.36283,-2.60689],[-0.499378,-1.62817],[0.110498,-2.42425],[-0.06415,0.644833],[0.585027,2.26593],[1.34881,0.0599972],[-0.0372348,-0.164152],[-0.628055,2.08674],[-0.245316,-0.672968],[-1.2781,-1.80323],[0.27677,1.29081],[1.31591,-1.91071],[0.672576,1.15503],[0.516487,0.00359392],[0.288671,2.19698],[-1.22605,1.98675],[0.295599,1.41673],[2.07079,-2.85461],[-2.54572,-0.13407],[-0.0900542,0.408493],[0.406948,1.93379],[0.696473,3.94976]]}}, +{"best":0.225551,"evaluations":3180,"generation":178,"median":22.3025,"state":{"best":[-0.0331521,-0.00646454],"population":[[-0.549319,0.104168],[0.193788,-0.0279541],[0.0831027,0.858432],[0.167313,-0.789155],[-0.0917622,-0.608536],[-0.942536,0.614249],[-0.556432,-0.370826],[-0.568332,0.503535],[-0.909221,0.992013],[-1.62907,1.98141],[-0.285052,0.0508427],[0.711241,0.763337],[-0.474522,1.00658],[0.649128,-1.83897],[-1.46903,0.408299],[-0.0721867,1.33417],[-1.1385,0.629646],[0.148554,0.645864],[0.266733,0.62877],[-0.674675,0.662468],[-0.688197,0.402162],[-0.11131,-1.85215],[-1.46743,1.3069],[0.484454,-0.62057],[-1.14939,1.15201],[-0.0450397,0.355439],[-1.36769,-0.0219087],[-0.483042,0.735721],[-0.322762,-0.328848],[-0.446731,0.174654],[-0.610072,-1.09937],[0.232966,-0.716171],[-0.113109,-0.372297],[0.234384,-0.979824],[-1.26669,-0.905264],[-0.68748,1.76122],[-0.836052,1.22614],[-0.941792,0.464737],[0.7735,-0.932809],[0.692212,-0.844016],[-0.554532,0.427314],[0.219236,-0.160996],[-1.00935,-0.163097],[-0.528359,1.33193],[-1.11799,0.626628],[-0.263042,0.271013],[-0.230797,-0.482203],[-1.34038,1.41002]]}}, +{"best":0.225551,"evaluations":3324,"generation":181,"median":21.5716,"state":{"best":[-0.0331521,-0.00646454],"population":[[-0.637168,0.640514],[0.613223,-1.23366],[0.172175,0.940045],[-1.04266,1.37958],[0.253331,0.298924],[-0.406482,-1.75274],[-1.18325,0.367018],[0.763529,-1.16492],[-0.769549,0.903859],[1.02894,-0.886193],[-0.63024,1.03413],[0.178921,0.962771],[-0.577278,1.50145],[-0.893525,1.52294],[0.18711,0.75167],[0.216067,-0.313148],[-0.623657,0.354272],[-0.0447445,-0.596769],[-0.242279,0.563844],[-0.185418,-0.323332],[-0.82397,0.824741],[-0.169704,0.255377],[-0.53369,-0.00136901],[-0.0464121,1.63391],[-0.105007,0.306141],[-0.159197,-0.413598],[0.151176,0.286278],[-0.421722,0.751233],[0.437469,0.483234],[-1.45952,1.91117],[-0.301507,1.42493],[-0.594427,-0.644586],[0.0333256,0.241459],[-1.54407,1.24779],[-0.79883,1.64225],[0.602769,0.592704],[0.569534,-0.111498],[-1.92908,2.0039],[0.521172,-0.909913],[-0.156654,0.0849193],[-0.638813,0.63799],[-1.42626,1.55562],[-1.61491,0.237939],[-1.19956,1.31801],[-0.462569,0.797454],[0.00996606,-1.00616],[-0.658141,-0.888796],[0.553988,0.265508]]}}, +{"best":0.225551,"evaluations":3468,"generation":184,"median":21.607,"state":{"best":[-0.0331521,-0.00646454],"population":[[-0.207089,-0.765604],[-0.97662,0.640245],[0.282667,-1.03069],[0.237934,-0.403059],[0.451009,-0.262192],[0.0221012,-0.0772045],[-0.332581,0.00609113],[1.39739,-1.63175],[0.729581,-1.01498],[0.41181,-1.40183],[-0.709587,-0.231757],[-0.796331,2.1461],[1.23854,-2.53408],[-0.553286,0.256234],[-0.362924,0.710846],[-0.830264,0.276673],[-2.33541,4.12474],[-0.463238,0.471594],[1.19406,-1.60003],[-0.431063,0.966962],[-0.320451,-0.522233],[-1.14254,1.7775],[1.80676,-1.46068],[1.30942,-2.12628],[-0.907754,0.433388],[0.685781,-2.07578],[0.500418,-1.23409],[-0.144362,-0.621754],[-1.24564,1.20231],[-0.0943163,-0.544542],[1.13266,-1.81792],[0.649031,0.566696],[0.263784,0.236843],[-0.320644,-0.00131825],[0.300183,0.234216],[-0.748256,1.14488],[-0.903085,0.697294],[-0.330261,0.969996],[1.50278,-1.5975],[-0.0288828,-0.78441],[1.47324,-0.69151],[0.167434,-0.651019],[-0.837038,0.572159],[-0.531774,1.21186],[-1.25313,0.838335],[-0.275658,1.03196],[-1.5007,1.73808],[0.127386,0.303016]]}}, +{"best":0.225551,"evaluations":3660,"generation":188,"median":21.25,"state":{"best":[-0.0331521,-0.00646454],"population":[[-1.53814,0.131218],[-1.43461,0.654858],[0.465845,-1.03053],[-0.548178,-0.222061],[0.455094,-0.929351],[0.153499,-0.844194],[-0.935781,0.496882],[-1.32242,0.640338],[-0.495071,-0.415552],[-1.59367,-0.678364],[-1.95274,1.08947],[-0.399787,0.0015542],[-0.663236,0.0250782],[-0.691746,-0.0679746],[-0.746062,-0.409274],[0.00820635,0.248215],[0.671555,-0.291481],[-1.95592,0.172027],[0.605037,-0.380492],[-0.197705,0.383157],[-0.740743,1.02603],[-0.063201,-1.04944],[-0.688752,0.0329812],[1.25416,0.119032],[0.377346,-0.38001],[-0.0799957,-0.294767],[1.51272,-0.906174],[-1.21999,-0.211413],[-0.525846,-0.759683],[-0.0457068,-0.0741803],[-0.287666,-0.907041],[-0.511387,-0.802244],[-0.352934,-0.43497],[0.324827,-0.22008],[1.01598,0.237257],[-0.119523,1.1471],[-0.366185,0.435443],[-0.559426,0.457953],[-0.449037,0.258934],[1.05643,-0.673632],[-0.278119,0.202742],[0.303346,-1.02712],[-1.12677,0.649737],[-0.200298,0.309286],[-0.864745,-0.226768],[-1.15852,1.00628],[-1.30311,0.0873178],[1.39743,-0.654632]]}}, +{"best":0.225551,"evaluations":3804,"generation":191,"median":21.25,"state":{"best":[-0.0331521,-0.00646454],"population":[[0.0954379,-0.419259],[-0.972097,0.285232],[-0.393272,-0.0571701],[0.257835,0.442932],[-0.473243,0.171691],[-0.423998,-0.226585],[-0.394527,-0.565089],[-0.325993,-0.423599],[-0.983554,0.402397],[0.0611,1.12413],[-0.577237,-0.0312986],[-0.682543,-0.72762],[-0.675056,-0.35499],[-0.883813,0.428843],[-0.743673,-0.3214],[-1.55621,-0.19762],[-0.535728,0.878887],[-0.0236982,0.207244],[-1.04948,0.993966],[-1.17177,0.628347],[-1.03342,0.084904],[-0.70859,0.656018],[-0.659317,-0.57645],[-0.363859,0.0109712],[-0.102403,-0.731763],[-0.597145,-0.226097],[-0.26151,-0.185296],[0.208042,-0.574854],[-0.853781,0.774802],[-0.235913,-0.576507],[-0.0575215,0.230597],[-0.32613,0.755784],[-0.288867,0.352156],[-0.080105,-0.0309576],[-0.195113,-1.12017],[0.0637612,0.58783],[-1.04312,0.5883],[-0.558391,0.5135],[-1.06873,0.156117],[-0.833123,-0.521164],[-0.475388,0.148956],[-0.874194,1.25758],[0.231206,0.375202],[-0.203482,0.0127772],[-0.731011,1.59575],[0.209141,0.046426],[-0.392809,0.579804],[-0.235201,0.0375966]]}}, +{"best":0.225551,"evaluations":3948,"generation":194,"median":21.25,"state":{"best":[-0.0331521,-0.00646454],"population":[[-0.669592,-0.32776],[-0.877864,-0.28038],[-0.532244,1.40204],[-0.505494,0.46036],[-0.380788,0.203258],[-1.43207,-0.198561],[-0.328743,-0.478234],[-0.661862,-0.26244],[-0.914561,-0.487003],[-0.458334,-0.0251152],[-0.741077,0.624526],[-1.41385,-0.323603],[-1.06142,0.417659],[-0.382002,0.46255],[-0.77811,-0.114041],[-1.1044,0.700434],[-2.21223,-0.0630443],[-0.321582,0.0954179],[0.257466,-0.971461],[-0.828139,-1.05262],[-0.142478,-0.75351],[-0.338782,-0.817346],[-0.231546,-0.71979],[-1.29458,-1.02814],[-0.847563,-0.0760218],[-1.05792,-0.405629],[0.139373,0.716156],[-0.247771,1.22842],[-0.792144,0.583193],[-1.14353,0.548244],[-1.19731,-0.653536],[-0.682878,0.862602],[-0.205407,-1.27331],[-0.613282,0.851475],[-0.950819,-1.13014],[0.228975,0.0478934],[-1.02066,-0.158252],[-1.03773,-0.84801],[-0.355523,-0.334471],[-1.1028,-0.545683],[-1.99863,-0.771808],[-0.0175195,-1.47093],[-0.145736,-0.264818],[-0.861003,-1.23971],[-0.698596,-0.428186],[-1.05557,-0.252089],[-1.11124,-0.419038],[-1.25199,-1.36831]]}}, +{"best":0.225551,"evaluations":4140,"generation":198,"median":21.25,"state":{"best":[-0.0331521,-0.00646454],"population":[[-1.02817,-0.730278],[-1.18029,-0.84266],[-0.735636,1.60691],[-0.884067,-0.275953],[-0.802402,-0.925459],[-0.632517,0.091148],[-1.25851,-0.889966],[-0.86166,0.378664],[-1.20807,-0.382621],[-0.573778,0.0708016],[-1.28953,-0.490431],[-0.894442,-0.581573],[-0.626814,-1.35482],[-0.97013,-1.11755],[-0.984188,0.400499],[-1.08996,-0.311094],[-0.773444,-0.60172],[-1.1803,-0.663902],[-0.801655,-0.325832],[-1.07626,-0.560829],[-1.25134,-0.534575],[-0.882433,-0.656179],[-1.25699,1.07061],[-1.17605,-1.89136],[-1.34349,-1.87019],[-0.869112,-0.533533],[-0.424671,-0.959118],[-0.837714,2.22702],[-0.268601,-0.632506],[-0.841285,-1.12658],[-0.913721,1.4432],[-0.584334,-1.86316],[-0.671018,-1.18028],[-1.12113,-0.858124],[-0.719035,-1.44811],[-1.40556,-1.03292],[-0.872221,0.90435],[-1.18102,-0.813823],[-0.608329,0.254256],[-1.12842,-0.506023],[-0.693558,-0.746157],[-0.664295,-1.49844],[-1.09153,0.127066],[-0.882799,-0.350943],[-0.98551,0.241309],[-0.902375,-1.12006],[-1.47912,-0.190277],[-1.07948,-2.10486]]}}, +{"best":0.225551,"evaluations":4284,"generation":201,"median":10.4416,"state":{"best":[-0.0331521,-0.00646454],"population":[[-1.11935,-0.547149],[-1.23431,-0.507975],[-1.17741,-0.392802],[-0.811112,-0.234914],[-1.08076,-0.216615],[-1.06453,-0.933128],[-1.14841,-1.78183],[-1.00893,-0.379833],[-0.947302,-0.501379],[-1.01004,0.20297],[-1.00314,-1.82867],[-1.01898,-0.834071],[-1.05993,-2.21947],[-0.99752,-0.489282],[-0.71908,0.0596855],[-1.04157,-0.224428],[-1.08664,-0.695197],[-1.01709,-1.39213],[-0.932532,-0.0613443],[-1.06241,0.0452005],[-0.990159,-1.80346],[-1.12167,-0.522126],[-1.14421,-0.546249],[-1.05687,-0.127535],[-1.27227,-0.00321582],[-1.06051,-1.64961],[-0.884905,-0.245452],[-0.907102,-1.10136],[-0.991076,1.00893],[-1.16768,0.168542],[-1.28065,-0.176056],[-1.06214,0.397835],[-0.930036,-0.938984],[-0.993215,-0.145559],[-1.17869,-0.0301801],[-0.877932,0.519075],[-1.11745,0.420108],[-1.19855,-1.60804],[-0.749953,-0.316647],[-0.936577,-0.528653],[-1.13705,0.0843254],[-0.948601,0.176696],[-1.23762,-0.411091],[-1.02362,-1.1713],[-1.10511,-0.8827],[-0.739629,0.257321],[-0.94211,-0.202091],[-0.984598,-1.29846]]}}, +{"best":0.225551,"evaluations":4428,"generation":204,"median":10.259,"state":{"best":[-0.0331521,-0.00646454],"population":[[-0.999981,-0.796729],[-1.06606,-0.78091],[-1.06498,-0.47952],[-1.05657,0.349788],[-0.946193,0.303541],[-1.02664,-0.87306],[-1.09875,-0.77199],[-0.983288,1.50657],[-1.15663,-1.71556],[-1.06863,-0.463401],[-1.18493,-0.212882],[-0.942862,-0.328244],[-1.00888,-0.515554],[-1.03681,0.226955],[-1.12276,-1.25376],[-1.36355,-1.3068],[-1.25383,-1.15927],[-1.00134,-0.0469599],[-1.20727,-1.20822],[-0.94207,-0.261075],[-0.977444,-0.880503],[-1.32499,-0.911249],[-0.964927,-0.128385],[-0.957584,-0.728825],[-1.11565,-0.169113],[-1.04648,-1.29967],[-0.973604,0.241467],[-1.12417,0.169642],[-1.11523,0.190517],[-1.02609,0.0320989],[-0.884697,-0.99745],[-1.07135,-0.233118],[-1.1904,-1.60547],[-1.10881,-0.532099],[-1.14584,-1.72345],[-1.122,-0.919363],[-0.875493,-0.859751],[-0.954624,0.901438],[-1.06276,-0.361492],[-1.03732,0.941716],[-1.03659,-1.3669],[-1.09051,-0.317902],[-0.938782,-0.34994],[-1.00188,0.863805],[-1.07951,0.0391035],[-1.149,-0.616447],[-1.16636,1.00457],[-1.10473,-1.16456]]}}, +{"best":0.225551,"evaluations":4572,"generation":207,"median":5.46072,"state":{"best":[-0.0331521,-0.00646454],"population":[[-1.0309,-0.590353],[-0.946948,-1.1732],[-1.05583,-0.588548],[-0.923305,-0.0136236],[-1.00541,-0.377606],[-1.11106,-1.25664],[-1.06294,-0.620139],[-0.976681,-0.518203],[-1.04088,-1.1021],[-1.04693,-0.115215],[-0.909153,-0.446967],[-1.03114,-0.841528],[-1.06818,-0.704309],[-0.91576,-1.20307],[-1.08971,-1.2291],[-1.17075,-0.108034],[-1.00594,-0.658082],[-1.11608,-1.47778],[-1.042,-0.349093],[-0.998563,-0.949561],[-0.934579,-0.904867],[-0.987998,0.0739806],[-1.02786,-0.917344],[-1.06451,-0.943649],[-1.04822,-0.944569],[-1.121,-0.0438192],[-1.01,-1.48591],[-1.10602,1.65646],[-0.989081,-0.174662],[-1.01351,-0.717331],[-0.970571,-0.498032],[-0.945787,0.388126],[-1.06627,-1.17879],[-0.977172,-0.106631],[-0.985678,-0.909931],[-1.0689,-1.40119],[-1.11026,-0.840873],[-1.06433,0.501178],[-1.09696,0.69508],[-1.08046,-1.23186],[-1.03849,-0.164717],[-0.936713,-1.59932],[-1.02966,-1.91086],[-0.944993,-0.770847],[-0.99936,-0.533635],[-0.919281,-0.832531],[-1.02068,-0.592384],[-0.975751,0.0763874]]}}, +{"best":0.225551,"evaluations":4764,"generation":211,"median":12.5949,"state":{"best":[-0.0331521,-0.00646454],"population":[[-0.899762,-0.0250928],[-0.909935,-0.105295],[-0.893552,-0.923429],[-1.03319,-0.906719],[-0.975857,-0.338705],[-1.03924,0.453683],[-0.947915,-0.0964114],[-0.970867,0.251446],[-1.01676,-0.670095],[-1.07315,-0.672588],[-0.987158,-0.190702],[-0.984921,-0.61799],[-0.948163,-0.0367048],[-0.935943,0.000228188],[-1.05578,-1.00577],[-0.971622,-0.202689],[-1.0507,-2.25615],[-0.905834,-0.376391],[-1.02191,-0.973587],[-0.966861,-0.561717],[-1.02033,-1.34663],[-0.997213,-0.59473],[-0.897646,-0.427527],[-0.937908,-0.357296],[-1.01806,-0.534673],[-0.961135,-0.875746],[-0.886497,0.0195344],[-0.976015,-0.371861],[-0.935894,0.275913],[-0.932707,-0.272487],[-0.939184,0.685997],[-1.00838,-0.441433],[-0.959293,-0.228502],[-0.998455,-0.272649],[-0.974196,-0.442773],[-0.990344,-0.272301],[-0.967178,-0.663102],[-0.860464,-0.664216],[-0.95235,-0.583588],[-1.02177,-0.0969575],[-1.01931,-1.31581],[-1.00484,-0.267994],[-0.952866,-0.329737],[-1.09387,-1.0626],[-1.02421,-0.862075],[-0.951856,-0.282108],[-0.989017,-0.897494],[-0.990031,-0.79951]]}}, +{"best":0.225551,"evaluations":4908,"generation":214,"median":12.2537,"state":{"best":[-0.0331521,-0.00646454],"population":[[-0.976492,-0.369793],[-1.02061,-0.685557],[-0.927228,-0.239237],[-1.05031,-1.1468],[-0.957418,-0.677339],[-0.828598,0.462957],[-0.993444,-0.784753],[-0.955106,-0.30693],[-0.862366,0.394975],[-0.884663,0.305976],[-0.870818,0.0721082],[-0.991939,-0.214243],[-0.941928,-0.272867],[-0.921724,0.151551],[-0.988011,-0.638903],[-0.890476,0.231043],[-1.03227,-0.823666],[-1.05314,-0.772115],[-0.907206,-0.174381],[-1.06798,-1.34172],[-0.870765,0.284214],[-0.89886,-0.0833228],[-0.941289,-0.556294],[-0.878887,0.419515],[-0.920795,-0.161435],[-0.920173,-0.177627],[-1.05727,-1.10982],[-0.836497,0.602448],[-0.975186,-0.345182],[-0.888617,0.0113641],[-0.86772,0.58414],[-0.952375,-0.240297],[-1.08003,-1.21405],[-0.979072,-0.542726],[-0.788825,0.760133],[-0.978773,-0.399042],[-0.966655,-0.264839],[-1.0026,-0.615914],[-0.997341,-0.364207],[-0.999275,-0.789398],[-0.94438,-0.300769],[-0.940413,-0.224585],[-0.871116,0.340196],[-0.926105,0.0307525],[-0.891428,0.130522],[-1.10631,-1.5666],[-0.949661,0.060061],[-0.853037,0.489019]]}}, +{"best":0.225551,"evaluations":5052,"generation":217,"median":13.8303,"state":{"best":[-0.0331521,-0.00646454],"population":[[-0.956962,-0.287044],[-0.969814,-0.641712],[-0.999677,-0.564664],[-0.942915,-0.371723],[-0.924471,-0.406974],[-0.988457,-0.701483],[-1.02074,-0.947719],[-0.933775,-0.13876],[-0.990282,-0.997817],[-1.0514,-0.9511],[-0.952689,-0.414422],[-0.951044,-0.381942],[-0.979823,-0.431136],[-0.840818,0.406623],[-0.899295,-0.0128897],[-0.948093,-0.282102],[-0.922957,-0.328378],[-0.802594,0.422042],[-0.999921,-0.720959],[-0.970987,-0.496541],[-0.914605,-0.172941],[-0.90162,-0.131671],[-0.902741,-0.113649],[-0.879025,0.232012],[-0.926882,-0.30152],[-1.04101,-0.720474],[-0.892424,0.144209],[-0.957418,-0.483434],[-0.970202,-0.562709],[-0.934919,-0.107008],[-0.832489,0.472113],[-0.869213,0.00216557],[-0.888927,0.0309942],[-0.868959,0.0695166],[-0.920388,-0.0684872],[-1.06932,-1.26309],[-1.10053,-1.29071],[-0.8582,0.233077],[-1.0315,-0.863243],[-1.01914,-1.00278],[-0.968677,-0.347781],[-1.05512,-0.910441],[-0.859893,0.304032],[-0.986351,-0.495382],[-0.820495,0.2212],[-0.950552,-0.339994],[-0.959687,-0.274957],[-1.05602,-0.83226]]}}, +{"best":0.225551,"evaluations":5244,"generation":221,"median":5.82848,"state":{"best":[-0.0331521,-0.00646454],"population":[[-0.89227,0.0416056],[-1.03675,-1.17063],[-0.906951,-0.177937],[-0.955432,-0.574928],[-0.983573,-0.668305],[-0.93512,-0.254011],[-0.956627,-0.559002],[-1.06324,-1.07484],[-0.968147,-0.435687],[-1.10117,-1.23879],[-1.0896,-1.32963],[-0.826936,0.305664],[-0.910252,-0.0328776],[-1.00454,-0.656977],[-1.0387,-1.10457],[-1.04344,-0.869034],[-0.819658,0.35218],[-0.879723,0.125568],[-1.1144,-1.57352],[-1.0553,-0.83246],[-0.857103,0.0145106],[-0.902194,0.10253],[-0.941089,-0.250077],[-0.978125,-0.640874],[-0.911221,-0.0480498],[-0.858351,0.393889],[-1.15085,-1.45124],[-1.00891,-0.722454],[-1.01245,-0.741225],[-0.997765,-0.875899],[-1.00362,-0.642554],[-1.04142,-0.984088],[-0.998135,-0.344123],[-0.890036,-0.262637],[-1.07011,-1.07771],[-0.882035,0.136404],[-0.911372,-0.329007],[-1.01243,-0.837833],[-0.993249,-0.806823],[-1.14715,-1.80035],[-1.08803,-1.15048],[-0.740378,0.654458],[-1.06609,-1.12874],[-1.04093,-0.778326],[-0.702893,1.0571],[-0.892378,0.0383167],[-0.954678,-0.637625],[-0.878128,-0.0489032]]}}, +{"best":0.225551,"evaluations":5388,"generation":224,"median":6.85623,"state":{"best":[-0.0331521,-0.00646454],"population":[[-0.991156,-0.698883],[-1.00912,-0.863527],[-0.95377,-0.394723],[-1.04204,-1.09995],[-1.06866,-1.21955],[-1.05114,-0.946613],[-1.02094,-1.02134],[-1.00022,-0.687199],[-0.73817,0.743412],[-0.902144,-0.299246],[-0.8484,-0.0770544],[-0.9066,-0.138694],[-0.912794,-0.395639],[-1.00279,-0.718274],[-0.906721,-0.184804],[-0.915395,-0.258643],[-0.944485,-0.320841],[-0.89528,-0.0610739],[-0.861447,0.195179],[-0.983607,-0.665921],[-0.843135,0.199198],[-0.911016,-0.153918],[-0.99538,-0.87238],[-1.07161,-1.2135],[-0.875459,0.0244635],[-1.04225,-1.11806],[-0.908423,-0.0706161],[-1.04694,-0.874556],[-1.00764,-0.795007],[-0.817502,0.178009],[-0.989861,-0.506143],[-1.03427,-0.947686],[-1.12345,-1.41379],[-0.867052,-0.0353892],[-0.855651,0.200759],[-1.10262,-1.54242],[-0.957299,-0.333045],[-0.922155,-0.0724874],[-1.02033,-0.892935],[-0.927563,-0.377652],[-1.01215,-0.719844],[-0.96005,-0.323253],[-0.995209,-0.755715],[-0.995537,-0.602746],[-0.975684,-0.471233],[-0.88892,-0.20863],[-1.09942,-1.20583],[-0.981587,-0.776958]]}}, +{"best":0.225551,"evaluations":5532,"generation":227,"median":14.6772,"state":{"best":[-0.0331521,-0.00646454],"population":[[-0.984682,-0.623811],[-1.0264,-0.791548],[-1.02746,-0.870544],[-1.04965,-0.94342],[-0.958837,-0.466653],[-0.974983,-0.522674],[-1.05483,-0.991302],[-1.00363,-0.800299],[-0.992598,-0.548884],[-0.924172,-0.341061],[-1.0846,-1.21146],[-0.875607,0.00553355],[-1.01989,-0.773191],[-0.90235,-0.0922513],[-1.00309,-0.593679],[-0.975637,-0.465109],[-0.959057,-0.407913],[-1.10505,-1.3411],[-0.884807,-0.00517397],[-0.945441,-0.286123],[-0.997111,-0.770809],[-1.00139,-0.616621],[-0.981708,-0.508614],[-1.01582,-0.7065],[-1.02364,-0.926149],[-0.933033,-0.26641],[-0.962896,-0.46581],[-0.937337,-0.340481],[-0.999729,-0.744044],[-1.06085,-1.03949],[-1.01625,-0.841801],[-0.852642,0.296129],[-0.891859,-0.140754],[-0.875102,0.0454752],[-0.970447,-0.496484],[-1.04503,-0.942414],[-0.994997,-0.646976],[-0.970281,-0.468551],[-0.993755,-0.751047],[-0.980422,-0.732779],[-0.957587,-0.608899],[-0.99397,-0.552644],[-0.99323,-0.60135],[-0.908324,-0.222695],[-0.884157,0.0588077],[-1.02357,-0.814801],[-0.964995,-0.320846],[-0.950149,-0.42438]]}}, +{"best":0.225551,"evaluations":5724,"generation":231,"median":19.4011,"state":{"best":[-0.0331521,-0.00646454],"population":[[-1.03207,-0.953744],[-0.985385,-0.657392],[-1.05506,-1.03176],[-0.990064,-0.676056],[-0.969614,-0.491988],[-0.907799,-0.133388],[-0.905827,-0.134305],[-0.973024,-0.537098],[-1.06224,-1.09328],[-1.04703,-0.971914],[-1.01351,-0.734991],[-1.04579,-1.00368],[-1.02219,-0.881383],[-0.846129,0.13762],[-1.06788,-1.18883],[-0.926508,-0.294871],[-0.892555,-0.103775],[-0.995309,-0.722626],[-1.08928,-1.22961],[-1.05809,-1.02313],[-1.1376,-1.55136],[-0.932377,-0.355225],[-1.11628,-1.44806],[-0.982387,-0.659397],[-1.08492,-1.18775],[-0.997362,-0.693724],[-1.10438,-1.32166],[-0.91676,-0.234253],[-0.751638,0.695418],[-0.809233,0.469369],[-1.13764,-1.49772],[-1.05011,-0.954504],[-0.984342,-0.605901],[-1.21581,-1.9732],[-1.09895,-1.30838],[-0.947388,-0.365421],[-0.983686,-0.627172],[-1.08818,-1.25666],[-1.10121,-1.27452],[-1.12445,-1.41087],[-0.87779,0.00682227],[-0.996847,-0.609744],[-1.13756,-1.56012],[-0.993677,-0.677208],[-1.0172,-0.858674],[-1.02796,-0.804988],[-1.00605,-0.769696],[-0.982396,-0.545209]]}}, +{"best":0.225551,"evaluations":5916,"generation":234,"median":36.25,"state":{"best":[-0.0331521,-0.00646454],"population":[[-2.32622,-4.91865],[-3.26336,-1.67813],[1.32473,-1.20648],[-3.49383,-4.54344],[-2.80526,-3.26441],[-4.59454,-3.27106],[-1.70272,1.78553],[-3.87438,-5.11373],[-2.83669,-3.61541],[-4.44958,-0.764117],[-2.66407,-0.212823],[-1.40478,0.132861],[-3.57152,-3.40347],[1.8575,-5.04666],[-3.97625,-4.94867],[-0.0277092,-4.16824],[-3.89683,0.151054],[1.02233,-1.95379],[-5.06045,-2.7938],[-4.70936,4.68521],[0.140622,-4.85422],[-0.779649,-3.08535],[-2.34255,-4.00776],[1.37319,-1.17362],[0.17551,-1.40769],[-0.782762,-1.69882],[-4.31798,-3.01402],[-4.9467,0.672639],[2.17529,-4.87082],[-1.27306,-1.7703],[-5.02493,-2.85675],[-0.975038,-4.87085],[0.523458,-4.89772],[-4.19587,-0.888563],[-3.16776,-1.80199],[-3.52382,-2.64827],[-3.3429,-3.01029],[-3.25438,1.45341],[-0.573704,-2.31518],[-4.94836,-2.71694],[-2.57822,-3.21606],[-3.47141,-0.381233],[-4.77291,-3.92384],[1.22271,-3.77652],[-4.4151,0.136712],[-3.3608,-3.71438],[1.7486,-0.828916],[2.11153,-1.12653],[1.29795,-2.66676],[-3.54189,-0.684951],[5.10091,-2.77136],[-5.08719,0.451185],[-0.0664002,-4.6694],[-3.87845,-4.63579],[-4.91134,-1.75592],[-4.06222,-1.12816],[-3.54958,-2.07666],[-0.614201,-4.03954],[1.01195,0.504218],[0.617604,-3.68043],[-2.60665,-3.04961],[-1.02493,-3.93496],[-2.2448,-2.21849],[-2.66421,1.22526],[-4.9838,-4.24655],[-3.28858,-4.00189],[-2.20127,1.78919],[-1.66375,-3.31114],[-1.30233,-3.75591],[-3.46502,0.510203],[-4.78384,-1.81748],[-1.60235,-3.33888],[-1.55394,-1.31661],[-2.71341,-2.54427],[-3.75858,-1.86251],[0.413799,1.56611],[-4.23541,-3.74583],[-3.27854,-1.19347],[-3.80923,-3.78704],[-4.0338,-3.70174],[-4.39609,-3.30216],[-2.88816,-1.12673],[2.02356,-3.24963],[-2.1667,1.56115],[-2.39829,-1.99406],[1.44531,-2.72145],[-0.688397,1.85149],[-2.86575,-4.23605],[-2.63368,-4.92624],[-2.99567,-3.61847],[-2.40467,-4.43304],[-3.4929,0.0787877],[-2.0685,-3.30246],[-3.84738,-0.441166],[-1.75949,-0.92968],[0.352059,-1.86324]]}}, +{"best":0.225551,"evaluations":6204,"generation":237,"median":23.25,"state":{"best":[-0.0331521,-0.00646454],"population":[[0.287891,-1.26105],[-1.18848,-2.34364],[0.615884,1.91806],[0.902086,-0.569267],[0.679292,1.17259],[-2.3712,-2.13225],[-1.09575,-0.205537],[-1.39139,2.01743],[0.525604,0.855439],[-1.90817,1.04538],[0.234746,-2.91279],[2.41492,2.19211],[1.31293,1.25947],[-1.59094,0.833639],[1.84548,-0.664329],[-0.65604,1.9382],[0.334003,2.70514],[0.0765699,-1.70056],[1.1071,0.707062],[1.00921,1.3037],[1.55245,0.537585],[-1.59319,2.5475],[0.519196,0.374222],[-2.75337,-0.063073],[0.285779,-0.0931065],[-2.43215,1.09247],[-1.315,0.867849],[1.26695,1.08158],[-1.3056,2.03454],[0.558436,-1.2179],[0.64701,-3.18816],[1.18428,-0.91279],[0.97759,-4.58581],[1.48966,-1.03115],[0.293278,3.10299],[-0.0468329,0.399944],[-1.06032,1.79161],[-1.60073,-1.33049],[-0.453309,0.99407],[-1.25711,0.760396],[-0.560312,-0.232216],[-0.254163,0.681827],[-1.0236,-0.633606],[-0.979828,1.0498],[0.293234,0.0283627],[0.676928,1.03568],[0.204401,-0.658112],[-0.597629,-1.02951],[-2.13033,-0.438603],[-0.760803,0.789614],[-1.52981,-1.31623],[1.40726,1.16049],[-1.03232,0.164296],[-1.20307,-0.384629],[-1.73531,-1.39992],[-0.0521183,-1.64403],[0.544688,0.764879],[-1.54529,-0.146164],[-1.05577,-0.383119],[-1.25478,-0.292961],[-1.21127,-0.481986],[-0.698727,-0.287478],[0.0471631,-0.641939],[1.36804,1.57057],[-0.215677,3.00298],[-0.888101,2.23594],[-1.63206,-2.96181],[-0.925993,0.762264],[-1.26894,0.852275],[0.473777,1.03423],[1.06473,-1.02906],[0.0697173,-1.86755],[-1.17598,-0.874203],[-0.965764,0.552245],[1.74322,1.48354],[2.49615,-0.0328138],[0.0437072,-1.29513],[0.0360654,3.59147],[1.20154,-0.107494],[2.62534,0.03619],[-0.0336628,-1.32907],[1.28847,2.7143],[-0.260739,0.130099],[-4.48129,-0.876563],[-0.515201,0.304478],[-0.374772,1.1196],[0.087409,-2.41286],[-0.766406,0.832185],[1.91185,1.68796],[0.312073,-0.856901],[1.10321,-2.17178],[-1.12244,-2.09807],[-0.612464,-1.31611],[-0.254037,-1.42631],[-1.88876,1.01721],[-1.2664,-2.44879]]}}, +{"best":0.0733181,"evaluations":6492,"generation":240,"median":21.25,"state":{"best":[-0.0155132,0.0113643],"population":[[-0.431044,1.15551],[-1.50708,0.927282],[0.380885,-0.473135],[-0.336372,-0.301732],[-1.49682,0.619107],[0.354122,0.56992],[-1.1692,-0.680852],[-0.622323,0.825202],[-1.43479,0.0111764],[-0.417725,0.330852],[-1.04516,0.130583],[0.450623,1.65159],[-0.808657,0.131008],[-0.21267,0.685206],[-0.0759253,0.345229],[-1.10591,-0.3584],[-0.0191793,0.899563],[-0.985066,0.584276],[0.0440398,1.17525],[-0.00398324,0.283983],[-0.400855,2.05165],[0.219739,1.3401],[-0.0704009,-0.433655],[-0.113158,0.203391],[0.150152,-0.0574004],[-0.162318,0.395239],[-0.742319,1.38622],[0.736816,-0.110823],[-0.762698,0.29282],[-0.136023,1.28159],[-0.503334,1.5582],[1.67044,-0.951942],[-0.593024,0.772554],[-0.881858,1.17507],[-0.794575,1.02771],[-0.783602,0.067082],[-0.521978,0.897493],[-1.26773,1.32442],[-1.66357,1.68714],[-1.56827,-0.646397],[0.135244,-0.205028],[-0.863234,0.31536],[-0.320186,0.681411],[-0.586766,-0.120588],[-0.178768,0.627997],[0.0540707,0.138858],[0.0763399,-0.780337],[0.229634,-0.30327],[-0.159694,-0.361308],[0.145274,-0.0924918],[0.225461,0.320944],[-1.17122,-1.42879],[-1.36664,1.74754],[-0.128961,-0.22026],[-0.586109,-1.17102],[-0.147226,0.47259],[1.03744,0.166491],[-0.416161,1.52716],[-0.937515,-0.240673],[-1.65806,0.577813],[-0.448069,0.848987],[0.641979,-0.0385876],[-0.454114,-0.356602],[-0.299118,-0.640821],[0.11637,0.0671636],[0.198102,0.0907905],[-0.789179,0.452795],[0.467462,0.787065],[-0.398085,0.188013],[0.800209,0.124977],[0.205383,-0.0782403],[0.282224,-0.484144],[-0.114877,1.06696],[-0.574212,-1.57978],[-0.736233,-0.147815],[0.716129,-1.09362],[-0.907631,1.10673],[-1.13167,0.0647806],[-0.0434364,0.577283],[0.0144142,1.88825],[-0.0511442,-0.717275],[-1.6309,0.891073],[-0.0155132,0.0113643],[-0.508279,-0.221209],[1.02615,-1.47142],[-0.507024,0.627526],[0.443733,-0.0213071],[-1.24086,-0.0808846],[-0.524671,-0.448799],[0.839311,0.060242],[-0.79535,-0.299131],[0.631598,-0.581078],[0.201406,-0.438901],[-0.334509,1.26826],[0.0579361,1.29638],[0.373012,1.46108]]}}, +{"best":0.0733181,"evaluations":6876,"generation":244,"median":20.7229,"state":{"best":[-0.0155132,0.0113643],"population":[[-0.904679,-0.443219],[-0.30039,0.204203],[0.291171,0.952686],[-0.770397,0.440921],[-0.883078,-0.385118],[0.00615647,-0.1385],[-0.58077,-1.18239],[-0.125462,0.943325],[-0.184867,-0.126302],[-0.990782,0.405282],[-0.951948,0.233423],[-0.100174,0.375916],[-0.184356,0.311113],[-0.440308,0.156045],[0.218206,0.433878],[-0.9652,0.344472],[-0.935875,0.38977],[-0.127488,0.234349],[-1.03926,0.4606],[-0.879739,-0.358119],[-0.685023,0.577484],[-0.884822,0.213048],[-0.665463,0.565229],[0.121436,-0.167408],[-0.095909,-0.302249],[0.231324,0.780198],[-0.90505,0.353127],[-0.341534,0.174528],[0.546092,0.637559],[0.0633213,0.603805],[-0.0994853,0.533319],[0.0295519,0.188747],[-0.549259,0.666348],[-0.1413,-0.210566],[-0.548644,0.637784],[0.21662,0.691513],[-0.707896,0.871585],[-0.315244,0.21362],[-0.224211,0.430442],[-0.854194,-0.942918],[0.0376843,0.647782],[-0.591872,0.439489],[-0.922301,0.161269],[-1.07549,0.797233],[-0.491579,0.166916],[-1.18065,0.0183284],[-0.666429,0.329531],[-0.00914791,0.15042],[-0.354769,0.804815],[-0.481978,0.48477],[-0.254055,0.711575],[0.492313,0.449008],[0.0627699,0.739586],[-0.153898,1.7687],[-0.505315,0.61271],[-0.345354,-0.391462],[-0.443238,0.195562],[-0.105379,0.25126],[-0.787448,0.13736],[-0.0818596,0.8346],[-0.244206,0.318356],[0.349541,0.314205],[-0.680343,0.102239],[0.0566092,0.572219],[-0.938561,0.142567],[-0.542061,0.248697],[-0.0554075,0.39287],[0.474118,0.542422],[-0.527658,0.894361],[-0.180357,0.259292],[-0.581479,0.142175],[-0.685196,0.442196],[-0.571005,0.285901],[-0.722582,0.212809],[-0.231606,0.255333],[-0.383927,0.487628],[-0.519574,0.432014],[-0.118454,0.281322],[-0.0588956,0.773147],[-0.118871,0.353269],[-0.850117,-0.259052],[-0.81232,0.658079],[-0.349397,-0.0136124],[0.274159,0.352735],[-0.810055,0.548996],[-0.346047,0.704769],[0.282646,0.993657],[-0.223523,0.420103],[-0.513071,-0.217494],[0.387983,0.862731],[-0.0560959,0.871647],[-0.113726,0.00748117],[-1.40919,0.133137],[-0.764559,0.472028],[-0.342768,0.369648],[-0.873676,-0.0436594]]}}, +{"best":0.0733181,"evaluations":7164,"generation":247,"median":21.25,"state":{"best":[-0.0155132,0.0113643],"population":[[-0.87304,-0.0391494],[-1.07955,-0.164043],[-0.367568,0.30807],[-0.57089,0.194773],[-1.79591,-0.283205],[0.460331,0.124429],[-0.557295,0.438568],[-1.41733,-0.190328],[-0.169118,0.458255],[-0.550682,0.321979],[-0.061684,0.705983],[-0.725956,-0.22381],[0.139058,0.653638],[-0.684613,0.483358],[-1.19076,-0.194647],[-0.890995,-0.116389],[0.339579,0.317854],[0.0596547,0.2992],[-1.25097,0.0405848],[-0.947834,-0.102235],[-0.742995,0.158497],[-0.591458,0.104616],[-1.36785,-0.0429614],[-0.930607,-0.261762],[-1.26739,0.137442],[-0.96223,-0.510992],[-0.44399,0.261496],[-0.423239,0.577301],[0.420779,0.300258],[0.114305,0.393197],[-0.96161,0.0334464],[-0.860862,-0.256625],[0.0539895,0.511446],[-1.4581,-0.166436],[-1.71577,-0.147046],[-0.984642,0.156578],[-1.05581,-0.562084],[-0.682953,0.0661822],[0.0498685,0.406981],[-0.383543,-0.156947],[-1.34224,-0.125058],[-1.62664,-0.265232],[-0.422282,0.287004],[-0.147897,0.105191],[0.224057,0.614784],[-0.338179,0.341997],[-1.28361,-0.389212],[-1.96409,-0.0821772],[-1.20874,-0.0265422],[-0.301726,0.0733737],[-0.286874,-0.0376706],[-0.282744,0.31151],[-0.911091,-0.0555281],[-1.48399,-0.392314],[-0.224422,0.323065],[-0.627769,0.0227745],[0.304407,0.192561],[-2.39088,-0.742971],[-0.307477,0.0259123],[-0.264244,0.274386],[-1.10735,-0.474031],[-0.229435,0.426557],[-0.15836,0.45671],[-1.49743,0.0356657],[-1.07054,-0.414056],[-0.391573,0.0221451],[-2.33152,-0.48187],[-0.767597,-0.203377],[-1.11892,0.161287],[-0.82367,-0.0668493],[-0.356967,0.156132],[-0.853062,0.197124],[-0.283073,0.578091],[-0.824839,-0.43649],[-0.766694,-0.0499244],[-1.50655,-0.416682],[-0.265724,0.156646],[-0.765131,0.191798],[-0.992761,-0.123526],[-1.75932,-0.296146],[-1.16895,-0.405986],[0.45685,0.626502],[-0.889877,-0.234689],[0.24114,0.445162],[-1.10192,0.170612],[-0.286574,0.0255792],[-0.492871,-0.0758966],[-2.03308,-0.655431],[-0.631581,-0.0271461],[-1.06093,0.00779619],[-0.602544,0.464571],[-0.082339,0.0270894],[-1.11534,-0.32911],[-1.67892,-0.477589],[-0.685703,0.13922],[0.301706,0.588947]]}}, +{"best":0.0733181,"evaluations":7452,"generation":250,"median":6.67526,"state":{"best":[-0.0155132,0.0113643],"population":[[-1.2828,0.0808964],[-0.787175,0.0795403],[-1.07312,-0.0529579],[-1.22665,-0.149643],[-1.28825,-0.197879],[-1.6078,-0.194469],[-1.02225,-0.104938],[-0.928506,-0.0975106],[-1.21071,-0.173534],[-1.23755,-0.146026],[-1.86677,-0.130981],[-0.125,0.115686],[-1.58595,-0.0872164],[-1.10449,0.182916],[-0.812864,-0.00350227],[-0.587645,0.0194014],[-0.676599,0.125783],[-1.148,-0.135844],[-1.49515,-0.0382869],[-1.62076,-0.122807],[-1.65874,-0.22404],[-1.3211,0.100809],[-0.740034,0.168114],[-1.04938,0.170026],[-0.782538,-0.133301],[-1.11665,-0.0346823],[-1.38926,0.0321051],[-0.811408,0.0819749],[-0.847221,0.044189],[-1.38368,-0.0943643],[-0.990085,-0.163337],[-1.39888,0.132589],[-1.07229,0.0485219],[-1.32897,0.0597397],[-0.793411,-0.0651276],[-1.4974,-0.0514465],[-0.900469,0.024573],[-1.20984,-0.0121035],[-0.630391,-0.142872],[-0.991391,0.0333075],[-1.38801,0.0108348],[-0.675775,-0.0525644],[-1.19098,0.0449962],[-1.68625,-0.227589],[-1.19249,-0.0167314],[-1.70023,-0.0465929],[-1.49439,0.0406491],[-0.826298,-0.00345406],[-0.91781,0.0427041],[-1.74444,-0.0529466],[-0.450045,-0.123658],[-0.906622,0.0388774],[-1.82137,-0.094152],[-0.968841,0.0890812],[-1.50778,-0.166663],[-0.666216,-0.00209926],[-1.05382,-0.241403],[-1.09895,0.189162],[-1.5385,-0.0633096],[-1.07091,0.0733656],[-1.15167,-0.153569],[-1.48606,-0.0587381],[-1.29336,0.0144648],[-1.3173,-0.0955143],[-0.840033,-0.103149],[-0.0885026,0.0946495],[-1.17282,-0.130664],[-0.891813,-0.106857],[-1.54728,-0.0596601],[-1.41542,-0.01748],[-1.13815,-0.0578841],[-0.709829,0.130273],[-1.21048,-0.0399189],[-0.494585,0.0727842],[-1.22364,-0.0939745],[-0.800631,-0.0904606],[-1.03829,0.095599],[-0.688531,-0.125742],[-0.807058,0.0277929],[-1.52558,-0.114548],[-1.1858,-0.0513738],[-0.753032,-0.0662021],[-1.29215,0.00574852],[-1.12215,-0.0909738],[-1.09406,0.0533978],[-0.841544,-0.0714314],[-1.20814,-0.122489],[-1.77421,-0.07577],[-0.661633,0.0555661],[-0.898082,0.0391062],[-1.27505,-0.0117854],[-0.73427,0.0592015],[-0.305081,-0.0362201],[-1.41549,0.00716547],[-1.58514,-0.0851333],[-0.866181,0.230035]]}}, +{"best":0.0733181,"evaluations":7836,"generation":254,"median":1.0002,"state":{"best":[-0.0155132,0.0113643],"population":[[-1.05241,0.00269098],[-1.048,0.000250076],[-1.08114,-0.000966076],[-1.03243,0.00166492],[-1.0545,-0.00107822],[-0.945564,-0.00187384],[-0.951965,-0.000959876],[-1.01911,-2.96769e-05],[-1.06616,0.000751339],[-0.998868,-0.00209501],[-1.04788,0.000918548],[-1.01062,0.000325779],[-0.9704,0.00014458],[-1.00542,0.00274872],[-0.97624,0.00247665],[-1.03448,-0.000546084],[-0.926072,-0.00149193],[-1.00432,0.00029169],[-0.890243,-0.00182574],[-1.05156,0.000267737],[-1.03403,0.00287899],[-1.11289,0.00249566],[-1.01151,0.00103113],[-1.01145,-0.0016599],[-1.01444,5.93354e-05],[-1.05725,1.92234e-05],[-1.09997,0.00123372],[-0.904369,-0.00122916],[-0.989652,0.000431509],[-1.02083,-0.000148682],[-1.09959,0.001261],[-0.997314,-0.000513947],[-1.01357,-0.00136427],[-0.997426,-0.00119495],[-1.10237,0.00174342],[-0.959751,-0.000903132],[-0.943732,0.00066532],[-1.07768,0.000106334],[-0.95593,-0.0027727],[-1.07771,-0.000469775],[-1.11586,0.00287342],[-1.00137,-0.000272629],[-0.993793,0.000506941],[-0.975633,-0.000598127],[-1.00745,-0.000934284],[-1.06228,0.0010179],[-1.00077,0.000732234],[-1.00383,-0.000543644],[-1.15208,0.000422619],[-1.00547,0.000940175],[-0.992793,0.00116583],[-0.951845,-0.00220104],[-0.966708,-0.00104405],[-1.00942,-0.000231212],[-0.981573,0.00139956],[-1.01975,0.00278099],[-1.11173,0.00155207],[-1.06458,0.00143272],[-1.02042,-0.00216358],[-0.994675,0.000648873],[-0.950823,-0.000305273],[-1.05823,0.000665237],[-0.976662,0.00239399],[-1.02063,0.000428797],[-1.09853,0.00137517],[-1.07077,-6.72087e-05],[-1.06692,0.00163024],[-1.15608,0.000398393],[-0.929534,0.000597485],[-0.909077,-0.000858638],[-0.986474,0.00139284],[-1.00413,-0.0014453],[-1.05488,0.0017235],[-0.939232,-0.000930158],[-0.997192,0.000388192],[-0.971261,0.000243939],[-1.02359,0.00149624],[-1.0914,0.00121128],[-0.926793,-0.000673939],[-1.03651,-0.00220845],[-1.02943,0.000784158],[-1.00321,0.00130215],[-1.1292,-0.00151903],[-1.09262,0.000694629],[-0.909482,-0.00217601],[-1.08967,0.00100781],[-1.05682,0.00219462],[-0.881243,0.000373742],[-1.13632,0.0021011],[-0.972515,0.000195787],[-1.06367,-0.000951445],[-1.02774,-0.00152223],[-1.04571,0.000626736],[-0.950085,-0.0025216],[-1.11864,0.00116892],[-0.937296,-0.00284772]]}}, +{"best":0.0733181,"evaluations":8124,"generation":257,"median":1.0,"state":{"best":[-0.0155132,0.0113643],"population":[[-1.07573,-3.31428e-05],[-0.987314,-2.92683e-05],[-1.00552,4.40281e-05],[-1.06439,6.55282e-05],[-1.00669,0.000155131],[-0.981262,-0.000125987],[-1.03837,8.34949e-05],[-0.988701,0.000100574],[-1.01177,-1.21289e-05],[-1.06536,-9.17914e-05],[-1.08169,-8.75227e-05],[-1.01239,-3.09618e-05],[-1.00368,8.90668e-05],[-0.987484,-3.83987e-05],[-1.07007,-1.58972e-05],[-1.02663,5.77231e-05],[-1.03137,7.13913e-05],[-1.03644,0.000173001],[-1.0244,-1.51029e-05],[-1.04001,0.000193718],[-1.0818,-2.80841e-05],[-1.10512,-7.41342e-05],[-0.96453,0.000123581],[-0.98021,-9.44956e-05],[-1.0063,1.22176e-05],[-0.959156,-2.09112e-06],[-1.01393,-4.39858e-05],[-0.964291,-7.21688e-05],[-0.998582,-1.15448e-05],[-1.04026,0.000148521],[-1.05852,8.56017e-06],[-1.06192,2.51526e-05],[-0.98783,1.00051e-06],[-1.00439,6.96775e-05],[-1.01216,0.00010059],[-1.00694,4.02731e-05],[-1.04341,8.26883e-05],[-1.08051,1.04782e-06],[-1.01013,-1.00045e-05],[-1.04517,6.25737e-05],[-1.0294,-7.48278e-05],[-1.08808,-1.4354e-05],[-0.948664,-2.97059e-05],[-1.04512,-2.81454e-05],[-1.03156,-3.88167e-05],[-0.965178,2.80961e-05],[-1.00086,2.46267e-05],[-1.07598,0.00013587],[-1.03017,-1.05646e-05],[-0.992259,-1.25241e-06],[-1.02641,0.000132871],[-1.04719,-7.78302e-06],[-1.00186,-5.95501e-05],[-0.956984,-3.90096e-05],[-0.991462,-1.81354e-05],[-1.06955,0.000110221],[-1.05269,0.000101321],[-1.04929,6.64674e-05],[-1.10139,5.37027e-06],[-1.00548,0.000137863],[-1.02509,-6.12418e-05],[-1.07034,4.47371e-05],[-1.00771,0.00015075],[-0.977528,-5.90808e-05],[-1.02043,7.03828e-05],[-1.01541,0.000136192],[-1.03089,7.43432e-05],[-1.05295,4.95796e-05],[-1.06741,-6.96414e-05],[-0.896339,-4.95347e-05],[-0.940771,4.39536e-05],[-1.04695,-3.97424e-05],[-1.01076,2.72285e-05],[-0.972509,7.54713e-05],[-0.968474,4.93084e-05],[-0.998256,0.000134402],[-1.057,0.000188745],[-1.02154,8.62858e-05],[-0.982624,-7.15773e-05],[-0.976567,-2.7763e-05],[-1.06244,3.5834e-05],[-1.02979,2.18427e-05],[-1.09953,6.63175e-05],[-1.01107,-2.41486e-05],[-0.993098,-9.34316e-05],[-1.06732,9.51286e-05],[-0.982576,4.28747e-05],[-0.983106,3.20283e-05],[-1.06029,-4.56432e-05],[-1.00244,-8.22095e-05],[-1.01134,-1.52828e-05],[-1.03491,4.34664e-05],[-1.01663,6.81414e-05],[-1.01796,-0.000110581],[-1.05135,3.39073e-06],[-1.06254,1.01691e-05]]}}, +{"best":0.0733181,"evaluations":8412,"generation":260,"median":1.0,"state":{"best":[-0.0155132,0.0113643],"population":[[-1.01228,-1.42177e-05],[-1.06989,-3.1946e-06],[-1.01362,1.47738e-05],[-1.04044,5.31814e-06],[-1.05492,-4.6753e-06],[-1.05616,-1.53992e-05],[-1.05089,4.17917e-06],[-1.03329,-1.71732e-05],[-1.03819,6.91929e-06],[-1.04482,6.01623e-06],[-1.07168,8.91309e-06],[-1.00374,1.04141e-05],[-1.03173,-6.0643e-06],[-1.03734,-1.22412e-06],[-1.05488,1.23903e-06],[-1.028,-1.33058e-06],[-0.988085,1.15915e-05],[-1.02641,4.63497e-06],[-1.02711,-6.08764e-07],[-1.05669,1.06521e-05],[-0.999181,-9.63955e-07],[-1.06772,1.70465e-06],[-1.02346,-5.68865e-06],[-0.954948,-1.5853e-05],[-1.0568,-1.24138e-06],[-1.06144,8.11464e-06],[-1.05357,8.9308e-06],[-1.04523,6.2414e-06],[-1.07367,1.03776e-05],[-1.01489,4.59039e-06],[-1.03566,1.74871e-06],[-1.05619,7.42587e-06],[-1.05853,-1.86663e-06],[-1.03928,7.2129e-06],[-1.07086,5.52279e-06],[-1.03053,3.13909e-06],[-1.0765,3.31727e-06],[-0.995295,-9.44016e-07],[-1.04041,-8.34993e-07],[-1.0626,1.17562e-05],[-1.05343,5.64151e-06],[-1.01727,-1.65841e-05],[-1.02535,-3.23693e-06],[-1.01253,8.23285e-06],[-1.01387,4.63868e-06],[-1.03336,2.1869e-06],[-0.99208,-1.00481e-06],[-0.991082,-2.62421e-06],[-1.02593,-3.50693e-06],[-0.993678,-8.56751e-06],[-1.01734,-7.37786e-06],[-1.02337,2.49138e-06],[-0.991943,-3.86624e-06],[-1.00132,1.55611e-06],[-1.03202,1.64005e-05],[-1.01335,-8.64258e-07],[-1.02574,-6.76931e-06],[-1.02382,-1.25396e-06],[-1.05037,-5.65085e-07],[-1.06213,1.96487e-06],[-1.04054,-1.96689e-06],[-1.05116,8.23721e-06],[-1.0494,-6.64173e-06],[-1.02267,-4.83249e-06],[-1.01444,-8.2355e-06],[-0.992321,1.96861e-06],[-0.98364,-5.86447e-06],[-1.06255,8.36718e-06],[-1.01764,2.16435e-06],[-1.05871,-1.01432e-05],[-1.03626,-3.11442e-07],[-1.05816,1.4881e-05],[-1.03372,5.58916e-07],[-1.0076,1.23357e-05],[-1.03251,1.30374e-05],[-1.00306,-6.71271e-06],[-1.02448,-7.11219e-06],[-1.04193,1.27519e-06],[-1.03892,8.7957e-07],[-1.03182,-1.04621e-06],[-1.00453,-3.7798e-07],[-1.06663,5.89626e-06],[-1.00568,-3.48485e-06],[-1.01539,-4.78694e-06],[-1.02844,6.97761e-06],[-1.01311,5.92126e-06],[-1.02221,-3.03256e-06],[-1.04503,7.87025e-06],[-0.998188,2.29308e-06],[-1.04383,2.38419e-06],[-1.02741,1.01245e-05],[-1.0094,-5.65478e-06],[-1.01188,1.62067e-06],[-1.00767,-9.58012e-06],[-0.968929,-9.52472e-06],[-1.02264,2.19557e-06]]}}, +{"best":0.0733181,"evaluations":8700,"generation":263,"median":1.0,"state":{"best":[-0.0155132,0.0113643],"population":[[-1.04516,-1.23957e-07],[-1.04187,-7.11487e-07],[-1.01869,-1.55636e-07],[-1.02662,-2.50982e-07],[-1.05691,5.68806e-07],[-1.02622,7.05261e-07],[-1.03065,-4.55012e-07],[-1.05113,-2.79161e-07],[-1.05154,-3.7547e-07],[-1.04946,5.95583e-07],[-1.036,-8.64084e-07],[-1.0185,-5.74195e-07],[-1.03163,-3.96605e-07],[-1.04007,-9.72492e-08],[-1.01498,-6.73153e-07],[-1.02086,1.79552e-07],[-1.02882,2.35278e-07],[-1.03722,1.22085e-07],[-1.02177,-4.15978e-07],[-1.04646,3.31202e-07],[-1.03597,-5.91149e-07],[-1.03789,-8.1059e-07],[-1.03906,8.24941e-07],[-0.99957,-8.67585e-07],[-1.01869,6.49976e-08],[-1.05179,1.04459e-06],[-1.04618,-4.30549e-08],[-1.02412,-3.51308e-07],[-1.04451,9.01247e-07],[-1.05699,6.26709e-07],[-1.00638,3.85416e-08],[-1.02498,-3.19016e-07],[-1.05417,6.94747e-07],[-1.05913,3.92838e-07],[-1.01957,-1.10896e-06],[-1.01095,3.85631e-07],[-1.03149,-4.471e-08],[-1.03068,-5.49095e-07],[-1.01897,4.50327e-07],[-1.02551,3.86694e-07],[-1.00635,-4.84737e-08],[-1.02685,4.70419e-07],[-1.01847,5.71573e-07],[-1.03126,-6.45489e-07],[-1.03018,-1.35404e-07],[-1.00492,2.81978e-07],[-1.01807,-1.25902e-06],[-1.02667,1.25226e-07],[-1.04487,-1.75173e-08],[-1.01247,-9.68601e-07],[-1.02727,-1.30121e-07],[-1.01773,-5.67599e-07],[-1.04745,3.65017e-07],[-1.02932,-4.21458e-08],[-1.05811,1.37569e-06],[-1.06702,-7.12241e-07],[-1.04153,-3.17008e-07],[-1.03386,2.80823e-07],[-1.01182,3.98273e-07],[-1.00474,8.02981e-08],[-1.00786,-2.57655e-07],[-1.02076,-5.45464e-07],[-1.04346,3.07344e-07],[-1.02686,1.37617e-07],[-1.03341,3.84535e-07],[-1.03191,-1.28707e-06],[-1.04494,-8.77353e-07],[-1.02606,-8.45754e-07],[-1.03315,6.32643e-07],[-1.01869,-6.40871e-07],[-1.04837,4.60279e-07],[-1.04201,9.03338e-07],[-1.03183,-1.34493e-06],[-1.03638,-3.04454e-07],[-1.0411,1.92934e-07],[-1.05929,-3.53427e-07],[-1.03103,-2.1199e-07],[-1.03019,-6.29035e-07],[-1.01295,6.74034e-07],[-1.04495,5.15028e-07],[-1.03062,-1.08041e-06],[-1.02302,1.15962e-06],[-1.01363,-4.32684e-07],[-1.0431,-1.28414e-07],[-1.04287,-7.4674e-07],[-1.01954,-2.1477e-07],[-1.01257,-1.05754e-06],[-1.05527,2.63052e-07],[-1.03622,8.85358e-07],[-1.02049,-1.69802e-07],[-1.04182,1.3839e-07],[-1.04036,-4.87809e-07],[-1.03773,9.41208e-07],[-1.04172,1.18363e-06],[-1.03438,1.09294e-06],[-1.06234,-1.30786e-07]]}}, +{"best":0.0733181,"evaluations":9084,"generation":267,"median":1.0,"state":{"best":[-0.0155132,0.0113643],"population":[[-1.03019,-8.03392e-09],[-1.03632,-1.01544e-08],[-0.998046,-1.52775e-08],[-1.0334,-2.40645e-08],[-0.996858,1.698e-08],[-1.03526,-1.32723e-08],[-1.03327,9.92307e-09],[-1.0117,1.74331e-08],[-1.04428,-1.64186e-08],[-1.0382,-9.6294e-09],[-1.02838,1.46023e-08],[-1.04114,-1.90347e-09],[-1.03437,-1.63515e-08],[-1.05062,-1.22376e-08],[-1.03429,-1.79437e-08],[-1.04563,-4.59446e-08],[-1.02464,3.98914e-09],[-1.03408,2.82893e-09],[-1.04585,1.04226e-08],[-1.01909,-7.76765e-09],[-1.04847,-2.28554e-08],[-1.05195,-3.42096e-08],[-1.01856,2.12646e-08],[-1.00327,4.49475e-08],[-1.01848,8.11621e-09],[-1.0338,4.87224e-08],[-1.01753,6.5863e-09],[-1.04268,-1.06821e-08],[-1.01,2.52782e-08],[-1.03569,-2.43075e-08],[-1.03424,2.93421e-08],[-1.02282,-3.61716e-08],[-1.02357,4.46795e-08],[-1.01027,-4.32085e-09],[-1.0113,-2.89453e-08],[-1.00786,7.35539e-08],[-1.00743,-9.60676e-09],[-1.08432,-1.56405e-08],[-1.04893,-3.09517e-08],[-1.04228,5.22989e-09],[-1.03124,1.61626e-08],[-1.01724,3.23072e-08],[-1.04591,9.39323e-09],[-1.03996,-7.02263e-09],[-1.04185,1.13215e-08],[-1.05794,-1.45018e-08],[-1.04037,-4.00344e-08],[-1.02988,-3.72156e-09],[-1.03923,-3.77874e-08],[-1.00209,-1.81898e-08],[-1.03582,-1.28294e-08],[-1.02285,2.12754e-08],[-1.0436,-2.10542e-08],[-1.043,1.725e-08],[-1.03685,-1.83099e-08],[-1.05732,1.6371e-08],[-1.01801,4.15332e-09],[-1.02231,-2.10215e-08],[-0.999248,1.41802e-08],[-1.0346,1.75465e-08],[-1.02909,-1.25456e-09],[-1.0179,3.17119e-08],[-1.03507,-1.05009e-08],[-1.00073,1.02267e-08],[-1.01896,1.23501e-08],[-0.983383,3.57121e-08],[-1.03709,-1.87963e-08],[-1.04425,-7.5983e-09],[-1.03331,1.59394e-09],[-1.03945,-2.37896e-08],[-1.0233,-1.43351e-08],[-1.0019,4.84336e-08],[-1.04281,-1.90242e-08],[-1.03403,1.23715e-08],[-1.03173,-4.55812e-08],[-1.03975,-2.87721e-08],[-1.01831,-1.15712e-08],[-1.03592,-1.25866e-08],[-1.02233,1.29701e-08],[-1.05077,1.7761e-08],[-1.06535,3.10442e-08],[-1.00877,1.31613e-08],[-1.04464,1.83475e-08],[-1.03952,-1.34893e-08],[-1.04058,9.82779e-09],[-1.01043,-6.6281e-08],[-1.02388,-2.07582e-09],[-1.00921,-2.39476e-08],[-1.02941,-4.95096e-09],[-1.04668,-3.7712e-09],[-1.04982,-1.4366e-09],[-1.05372,2.61742e-08],[-1.0309,3.83357e-08],[-1.03017,-2.23881e-08],[-1.03682,-3.30726e-08],[-1.05253,-1.23977e-09]]}}, +{"best":0.0733181,"evaluations":9372,"generation":270,"median":1.0,"state":{"best":[-0.0155132,0.0113643],"population":[[-1.03857,-1.70726e-09],[-1.04181,4.36669e-09],[-1.03313,-6.84028e-10],[-1.02051,4.12649e-09],[-1.03916,1.48515e-09],[-1.04766,2.41628e-09],[-1.04545,-1.39746e-09],[-1.04543,6.17636e-09],[-1.03136,-4.66951e-09],[-1.03472,-2.72346e-09],[-1.03342,6.64601e-10],[-1.03071,-2.04856e-09],[-1.02301,-1.88166e-09],[-1.04393,-3.0713e-09],[-1.03408,7.62722e-10],[-1.0457,-3.40363e-10],[-1.0298,6.74586e-09],[-1.03518,-1.42073e-10],[-1.03791,-2.13661e-09],[-1.05735,9.55124e-10],[-1.04123,-1.3518e-09],[-1.05639,-6.26941e-10],[-1.02745,1.74217e-09],[-1.0297,-3.53271e-09],[-1.03874,-9.16463e-10],[-1.04182,-1.16372e-10],[-1.04669,1.38203e-09],[-1.04126,3.47018e-09],[-1.0394,7.59013e-10],[-1.03679,3.08861e-09],[-1.02885,-1.33852e-09],[-1.03921,3.95416e-10],[-1.02845,-2.71842e-10],[-1.03511,1.73316e-10],[-1.04251,-4.83316e-10],[-1.04333,2.25951e-09],[-1.03857,-1.69154e-09],[-1.02734,-3.83919e-09],[-1.03677,1.0858e-09],[-1.04986,-3.26139e-12],[-1.04482,5.65509e-09],[-1.03591,6.07996e-10],[-1.03243,-3.4635e-10],[-1.05297,1.39341e-09],[-1.01819,-1.12008e-10],[-1.03586,1.19913e-09],[-1.0351,-1.25447e-09],[-1.03655,-4.77411e-10],[-1.03214,-1.96889e-09],[-1.04406,-1.72466e-09],[-1.02099,-2.5083e-09],[-1.01806,-2.91179e-09],[-1.01876,-1.68804e-09],[-1.02978,-7.0633e-09],[-1.03448,-2.86087e-09],[-1.0343,-3.41741e-09],[-1.02703,4.86887e-10],[-1.03283,3.1225e-09],[-1.03851,-1.62647e-09],[-1.03679,5.79412e-10],[-1.02857,-3.49743e-09],[-1.04101,1.80528e-09],[-1.02933,-2.15284e-09],[-1.02892,-2.21535e-09],[-1.04325,2.93244e-09],[-1.0501,3.72422e-10],[-1.03151,-4.39351e-09],[-1.03268,1.86392e-09],[-1.02436,-2.71914e-10],[-1.03452,1.10962e-09],[-1.04886,-2.47608e-09],[-1.01794,-1.50457e-09],[-1.04397,7.39793e-10],[-1.03823,-2.2947e-09],[-1.02227,1.11122e-09],[-1.0383,-2.79318e-10],[-1.03174,-1.89244e-09],[-1.0545,-2.94211e-10],[-1.04291,-1.6811e-09],[-1.03294,6.69889e-10],[-1.03844,4.01125e-09],[-1.04051,-3.92171e-09],[-1.02351,-1.06882e-09],[-1.01624,-5.68511e-10],[-1.03123,5.09945e-09],[-1.0291,3.14581e-09],[-1.03281,-1.34419e-09],[-1.02965,-6.6985e-09],[-1.04045,-2.23625e-09],[-1.03319,9.49611e-10],[-1.02751,4.81988e-10],[-1.04143,-1.16164e-09],[-1.02756,-2.47775e-10],[-1.05033,-2.71013e-09],[-1.04157,-8.90473e-10],[-1.03821,-4.26938e-09]]}}, +{"best":0.0733181,"evaluations":9948,"generation":273,"median":26.25,"state":{"best":[-0.0155132,0.0113643],"population":[[-0.628229,2.03447],[-0.661535,1.03823],[-0.674279,-0.244711],[3.96291,-1.94672],[-0.0803651,3.37026],[-1.11537,0.782255],[1.02913,0.904919],[-1.18796,2.40242],[-0.950199,1.46161],[-1.117,0.366214],[0.343994,-1.4824],[1.56778,-0.161689],[0.745736,-2.55281],[-3.75936,1.84845],[-2.61142,1.82246],[-1.20249,3.42031],[3.3323,2.29764],[1.31665,2.91323],[-2.2553,-0.0845152],[2.94199,2.32011],[-0.304994,-2.96069],[0.322105,2.54133],[0.484203,1.04633],[2.67372,1.37156],[-1.99,-0.742454],[0.617804,0.696821],[-1.48718,-0.884095],[1.03039,-1.03281],[-3.08843,2.22839],[0.962976,0.835799],[1.17615,-1.27],[-2.09343,1.85912],[1.30204,-0.679411],[-1.94547,-0.86822],[-0.882713,0.899205],[-0.452229,-1.84695],[-2.02255,1.3583],[-1.52311,2.38646],[-0.0759282,0.169],[-0.35222,0.0213246],[-1.78383,2.18492],[-1.96877,2.53005],[-1.86926,1.71095],[-1.32447,-2.19115],[0.287283,0.626033],[0.105866,0.827021],[-0.312107,4.05659],[0.615824,-0.356134],[-4.34172,2.02491],[-0.747121,1.02769],[-0.231848,2.12594],[1.71583,0.142627],[0.771183,-1.89149],[0.286527,1.27101],[0.21395,1.9041],[2.24253,-1.71671],[-0.758916,1.59666],[-0.947525,0.786437],[-0.377182,1.07159],[-1.37622,4.02232],[1.80006,0.264758],[1.56803,-1.99071],[-0.791772,2.93876],[-0.952347,4.13935],[-0.336453,0.870678],[-1.81858,1.10113],[-0.733314,-0.137182],[0.29045,3.67068],[-0.987117,2.15336],[-0.731141,0.723539],[0.859242,2.52019],[0.585128,-0.327195],[1.11731,0.769228],[-0.335185,0.523276],[-0.100105,0.840407],[-0.777592,-0.543444],[-2.31742,2.41395],[-0.192928,1.73116],[-0.353727,-1.99101],[-0.630499,1.04382],[-1.28928,-1.38985],[-0.0760557,2.80502],[-2.66065,3.46402],[3.03536,-0.759954],[-1.82125,-1.05742],[2.9331,-1.41317],[-0.509398,-0.52015],[-0.905511,-1.50468],[-0.770906,1.54286],[-0.56032,2.4131],[-0.672376,0.937519],[-1.86949,-0.447605],[-3.11801,4.10975],[1.14717,2.46077],[0.093236,-0.790143],[-3.89079,3.13883],[0.219024,-1.80471],[-1.29109,-0.12617],[2.81858,1.5142],[-1.45753,1.71091],[-1.6036,-0.195501],[-0.445028,3.815],[-3.54503,3.23221],[1.55917,0.175842],[-0.600208,2.91229],[2.15925,3.43379],[-1.31038,1.49007],[-0.966868,3.35044],[-1.36388,3.20397],[1.02465,-2.7936],[1.86564,-0.347095],[2.59282,4.12652],[0.611516,0.526783],[-1.7956,1.86578],[-2.68286,4.73991],[-1.61793,-0.0604571],[0.573557,3.38489],[0.39009,-0.533584],[0.636028,1.76955],[-0.205577,1.60456],[0.958561,4.62859],[-1.11256,1.50829],[-1.20459,2.39484],[-1.02099,1.01829],[0.0640736,1.16494],[-2.8557,-1.42565],[-1.61722,-1.0818e-05],[-0.78037,1.6694],[-2.04506,1.90386],[-2.43481,-0.269973],[-0.969575,1.67678],[1.32145,-1.02435],[1.83815,1.7471],[3.76313,-1.30644],[-1.77044,0.731268],[1.17503,2.10703],[-0.857582,3.16448],[-0.997387,-0.815573],[-4.15777,1.44091],[2.73154,-0.623656],[-2.34815,-0.273302],[2.49539,-2.0677],[1.86756,1.16178],[1.57158,3.30282],[0.611108,-1.64862],[-0.727697,1.70743],[2.2183,0.685662],[0.185707,0.0722449],[-1.9001,3.35112],[1.82475,1.36724],[1.66028,2.33558],[-2.21753,-1.6828],[0.0737857,2.69477],[0.0993302,2.36136],[3.09314,0.574508],[-2.32242,0.313832],[2.42169,0.703646],[1.61746,-0.266306],[0.383586,-4.36961],[0.634914,0.860676],[-0.662309,-1.18818],[-2.06578,0.25973],[-0.0867919,1.14764],[3.03847,-3.2259],[2.10265,2.6243],[-2.27817,3.25344],[0.151246,-2.20884],[0.102203,1.03924],[-0.29307,1.37629],[2.92859,-1.29276],[-0.368932,0.514933],[-2.73809,1.88808],[-2.57517,4.1173],[0.164239,0.323101],[0.12414,1.54384],[1.71567,0.882759],[-0.426626,-0.0764533],[0.322472,1.1532],[1.79701,-1.35561],[0.811345,0.835443],[-0.320876,1.91316],[0.912946,-0.388381],[-1.29304,-0.843557],[-0.622375,1.26458],[-3.19484,1.57805],[-3.87936,1.96813],[1.70299,4.74539],[1.6024,0.366739],[3.3217,-3.56061],[-0.801312,0.389417],[-0.600489,-0.999012],[1.35925,0.721008]]}}, +{"best":0.0733181,"evaluations":10716,"generation":277,"median":21.25,"state":{"best":[-0.0155132,0.0113643],"population":[[-1.41073,0.958627],[0.595346,-0.136667],[-0.975502,-0.578124],[-0.919713,-0.0744836],[0.40137,0.136892],[-1.38754,0.167783],[1.1766,0.893012],[0.126889,0.344517],[-1.27484,1.00177],[0.186876,0.0714055],[-0.85224,0.566282],[-1.24825,0.483843],[-0.797708,-0.730168],[0.0608343,1.76601],[-0.779557,-0.257229],[0.206058,0.551168],[0.546489,1.32552],[0.31914,0.0901575],[-0.779813,0.209024],[-0.699924,1.32369],[-0.299007,0.334157],[-0.12758,-0.224346],[1.31283,0.297091],[0.144696,1.18367],[0.352335,0.773631],[0.87567,-0.0676517],[0.183484,-0.613075],[-1.20791,1.04245],[0.514887,-0.0835164],[-1.72806,0.811463],[-0.261038,-0.786944],[0.169912,-0.576282],[0.243397,0.398077],[-0.88959,1.57052],[-1.37471,0.939625],[-2.02587,0.95661],[0.647741,-0.0887887],[-0.149285,0.286201],[-0.598877,0.28617],[-0.0255219,0.143414],[-0.457691,-0.311734],[0.24875,0.253774],[-0.0340731,0.99567],[-0.464595,0.871528],[0.30589,-0.247926],[0.517089,-1.18911],[-0.169821,-0.2222],[-0.386486,0.310966],[-0.310242,0.0234641],[-0.669111,0.6742],[0.147223,0.347026],[-0.960826,-0.110838],[-0.419698,1.04009],[0.523951,0.117695],[-0.795821,1.07788],[-1.15104,-0.996975],[-0.378758,0.284581],[-1.41118,0.0337765],[-0.957257,0.419918],[0.254295,0.272373],[-0.583269,1.12809],[-1.48397,0.308822],[-0.998883,1.33745],[-0.877829,0.729549],[0.36516,0.532743],[-0.342,0.12967],[-0.128205,1.29305],[0.0823341,0.146724],[0.904416,-0.586593],[0.717942,0.236066],[-0.173845,0.713977],[-1.26727,0.638571],[0.15147,-0.499827],[-0.224939,0.30069],[-0.922824,0.0385927],[-1.11075,0.55358],[-0.783764,0.66497],[0.417688,0.66536],[0.793861,1.59226],[-0.273551,-0.149968],[0.0412004,0.806303],[-1.34238,0.582801],[0.0957905,0.540671],[0.476732,0.214159],[-0.262776,0.985495],[0.981714,0.0884267],[0.208493,0.761364],[0.289553,0.782094],[0.67358,-0.481341],[0.253066,-0.0656873],[-0.0731372,0.604267],[-0.416286,-0.131827],[0.761626,0.876851],[0.789734,-0.0806852],[0.0387001,0.0254855],[0.16782,-0.0903279],[1.1646,-0.250199],[0.120415,1.99611],[-0.528332,1.02381],[0.0584556,-0.227855],[-0.125521,0.48731],[0.116139,1.07009],[1.32067,-1.17092],[0.769828,-0.876673],[0.00475883,0.780557],[0.700021,-0.640856],[0.0504068,1.41473],[-0.0593296,0.441472],[-0.00461617,-0.0978126],[-0.220029,0.774333],[-0.0436206,0.17315],[-0.0611183,0.643458],[-0.311882,0.11146],[-0.868982,0.772698],[0.743599,-0.235975],[-0.233946,-0.33064],[0.00892678,0.674597],[-0.327197,-0.587615],[-0.617274,-0.222237],[-0.388381,0.179602],[0.601584,1.5288],[-0.3846,0.930596],[0.655321,-0.985127],[-0.68559,0.967012],[0.169453,1.74353],[-0.266402,0.669291],[-0.605602,-0.513674],[0.269985,1.71438],[0.51532,-0.107269],[-0.423891,-0.791785],[-0.0428197,0.194461],[-1.29604,1.47102],[-0.151182,0.269939],[0.848817,-0.250293],[0.680144,-0.394329],[-0.04186,0.798246],[0.43327,-0.629561],[0.319794,1.67363],[-1.45482,-0.636978],[-0.890955,1.84669],[-1.9443,-0.0242964],[0.316491,0.997543],[-0.0483874,-0.687859],[-0.00368389,0.286862],[-0.286659,0.23368],[-0.728323,1.03164],[-0.579302,0.0486513],[-1.36721,1.19335],[-0.825074,0.851081],[0.721538,-0.241409],[0.181468,-0.0786878],[-0.0095993,-0.48033],[0.435634,0.520882],[0.292376,-0.612672],[-0.120311,-0.582138],[-0.572586,0.766671],[-0.434597,0.843713],[-1.65272,0.19768],[-0.097146,0.875089],[-0.938972,0.0711919],[0.0424274,1.05984],[0.128793,0.890451],[0.0941525,0.0832457],[0.389675,1.91905],[-0.67012,-0.281548],[-0.0630458,1.34194],[0.0236302,1.42148],[0.276714,0.546938],[-0.899403,-0.29219],[-0.0633988,-0.109983],[0.510904,0.915573],[1.41353,0.316261],[-0.0893501,0.617412],[-0.346788,-1.42258],[-0.350645,0.00508594],[-0.327794,1.26594],[0.21519,-0.341945],[0.916997,0.604485],[0.297284,0.048225],[1.27982,-0.127837],[0.518093,0.80975],[1.0315,0.0309395],[-0.414933,-0.422465],[-2.181,0.72104],[-0.572238,0.998584],[-0.679896,1.57369],[0.344232,0.108661],[0.299081,-0.0879262],[0.0570152,0.426295],[-1.11324,0.04717],[-1.1409,0.0579007],[-1.08669,0.0325382]]}}, +{"best":0.00994913,"evaluations":11292,"generation":280,"median":21.25,"state":{"best":[-0.00705373,-0.000633944],"population":[[-0.690181,0.212038],[-0.628377,-0.223553],[0.759504,0.762037],[0.177819,0.381505],[0.79757,0.792307],[-1.08677,-0.161159],[0.11411,0.143322],[-1.11104,-0.193374],[-0.645386,0.91309],[0.321432,0.869323],[0.445659,-0.494616],[-1.16993,0.837346],[-0.234472,-0.433571],[0.208239,-0.260395],[0.595815,-0.00975192],[0.671987,-0.637864],[0.51137,0.838831],[-1.43382,0.0558523],[-0.146995,0.262537],[-0.205252,-0.632338],[0.480946,0.650292],[-0.647332,0.326867],[-0.753068,0.177225],[-0.0727404,0.145332],[0.71894,-0.1937],[-0.30175,0.086954],[0.981894,0.343949],[0.0445518,0.185246],[0.0844753,0.463755],[0.031632,-0.550903],[-0.666192,0.825277],[0.0540911,0.376068],[-0.616663,0.598864],[-0.517783,-0.0576698],[-1.10294,1.08916],[0.513774,0.143563],[-0.794895,0.438727],[-0.00989596,0.653877],[-0.869545,-0.374984],[-0.255153,-0.197839],[0.136633,0.621328],[0.0789286,-0.0506914],[-0.313001,0.69785],[-0.975671,-0.220804],[-1.02013,0.483125],[0.2133,-0.484965],[0.110893,-0.471781],[-1.05116,0.395527],[0.0094649,0.868772],[1.44943,-0.0335777],[-0.12155,-0.189675],[-0.476188,0.347636],[-0.481448,-0.550643],[-1.26022,0.450285],[-0.974009,0.475948],[-0.418666,-0.25678],[0.429213,0.724656],[-1.14419,0.964744],[-1.16693,0.353921],[-0.523399,0.247969],[0.376168,-0.449346],[0.154634,0.16573],[-0.811361,-0.566319],[0.375763,0.21769],[-0.684361,1.13811],[-0.180174,-0.0636487],[-0.276518,0.0321732],[-1.36308,0.155976],[0.717291,0.404154],[-0.289406,-0.0725605],[0.545477,0.397387],[-0.169263,-0.0888769],[-0.0537298,0.202438],[-0.945292,0.317974],[-0.0169565,-0.231869],[0.778295,-0.0169626],[-0.0514538,0.465636],[1.2614,-0.0694528],[-0.666877,-0.536377],[0.0194541,-0.248613],[-0.11819,0.573831],[0.0558064,0.903299],[0.405778,-0.282785],[1.18461,-0.404939],[-0.463412,0.714967],[0.382544,0.834543],[0.0456257,-0.501601],[0.0249609,-0.275834],[-0.312906,-0.00206738],[-0.717245,0.879364],[0.78189,0.348056],[-0.450507,0.104714],[-1.29439,0.675554],[-0.949199,0.857054],[0.260261,-0.0898985],[0.481915,-0.827499],[0.741777,0.418859],[0.248861,0.40134],[-0.447725,-0.182014],[-1.08414,0.0123138],[-0.498359,0.110759],[0.038909,0.766715],[-1.25385,0.516244],[0.322354,0.191607],[-1.31818,1.09884],[-1.56243,0.804172],[-0.359721,-0.393316],[0.468267,0.482359],[-1.08707,1.29758],[-0.853509,0.691407],[-1.05962,0.615224],[-0.461893,0.871422],[0.43254,-0.178026],[-0.704576,-0.528755],[1.16354,0.429835],[-0.999782,1.00951],[-0.293771,0.0934499],[-0.354352,-0.543101],[-0.294991,0.891343],[-0.375241,-0.201555],[-0.681543,0.554769],[-0.517516,0.578416],[0.667564,-0.0132582],[-1.24321,0.712755],[0.206484,-0.36664],[0.0987731,0.0931923],[-0.979159,-0.126185],[-0.54902,0.0399371],[-0.423879,-0.747056],[-0.262575,-0.279766],[0.00563829,0.326985],[-0.300839,0.305552],[0.168293,0.536646],[-0.273717,-0.225734],[-1.01198,0.122936],[-0.0700376,0.0707441],[-1.63193,0.473661],[-0.77851,0.20875],[-1.62752,0.694023],[-0.402545,0.130973],[0.303372,-0.236865],[-0.0824683,-0.243452],[0.369947,-0.155455],[-0.710581,-0.194904],[-0.490466,-0.473888],[0.364884,0.904944],[0.269462,0.480892],[-0.798293,0.197457],[-0.349692,-0.216719],[-1.72431,0.652298],[-0.287613,0.310547],[0.585124,0.380211],[0.0733054,-0.00432411],[0.499079,0.0579174],[-1.11243,0.0558139],[-0.276121,0.416204],[-0.101628,-0.434128],[0.0319365,0.193755],[-0.945246,-0.494207],[0.379871,0.42472],[-0.600241,1.06702],[0.563193,-0.351765],[-0.776868,0.545659],[0.325909,0.282361],[-0.405463,-0.200822],[1.09728,0.847087],[-0.686924,0.536916],[0.126579,0.484188],[-0.559208,0.0394145],[0.620128,0.233981],[0.271593,-0.444871],[-1.34359,0.39128],[0.569218,0.317275],[0.232502,0.473232],[-0.32298,-0.0487244],[-0.349805,1.10498],[-0.930833,0.584979],[-1.21608,0.370712],[-0.161947,-0.56204],[0.211471,-0.475256],[-0.832958,0.341273],[-0.203659,-0.134437],[-0.702407,-0.364288],[-0.811706,0.00774049],[-0.488512,0.0419479],[-0.747671,0.348686],[0.027355,0.430817],[0.0922374,0.0830726],[-1.08058,1.15825],[-0.253681,-0.173578],[-0.659289,0.843795],[-0.836039,0.806522]]}}, +{"best":0.00994913,"evaluations":11868,"generation":283,"median":21.25,"state":{"best":[-0.00705373,-0.000633944],"population":[[-1.00654,0.226096],[0.394046,0.537026],[-0.392375,0.0524875],[0.468946,0.447064],[-0.469017,1.58845],[0.888683,-0.59087],[-1.27038,-0.45772],[-1.05495,0.519602],[0.186465,0.693924],[-1.14907,0.368618],[-1.51998,0.153424],[-0.708831,0.191426],[-0.704749,-0.0879208],[0.330373,0.37945],[-0.125354,-0.402029],[-0.97593,-0.107177],[0.175381,0.184154],[0.378963,-0.903238],[-0.269232,0.188727],[-1.0996,-0.186361],[0.294729,0.75145],[0.629551,-0.036544],[-1.0331,0.156637],[-1.04521,1.65727],[0.896851,-0.420442],[0.107944,1.27408],[-0.705139,0.149986],[0.102912,0.554998],[0.494347,-0.15675],[-0.195172,0.275306],[0.600482,-0.0350051],[-1.27417,0.185054],[-0.41311,-0.610686],[-1.79871,-0.417191],[-1.52368,0.992037],[-0.270698,0.416588],[-1.98231,1.00666],[0.735591,0.813611],[-0.454664,0.121086],[-1.27424,0.258899],[-0.0734895,0.639196],[1.548,-0.0306307],[0.304518,1.18722],[-0.888507,-0.0102066],[-0.145862,-0.37397],[-1.0895,0.097746],[0.0591098,1.54992],[-1.25551,0.37729],[-1.29762,0.326408],[-0.265161,0.0622685],[-0.58161,0.516383],[-0.2023,0.251723],[-1.11947,-0.904509],[0.426477,0.586744],[-0.666154,0.93105],[-1.16771,-0.158411],[-1.2539,-0.0453321],[0.0491736,0.124202],[-0.853291,0.213462],[-0.205408,1.07803],[-1.89851,-0.227805],[-0.931726,0.964539],[-0.0799887,-0.0161104],[-0.0686681,0.19679],[-0.505169,0.695779],[-2.06104,0.0676682],[0.092422,0.326178],[-0.964506,1.30177],[0.0545601,0.0527312],[-0.827382,-0.00880359],[1.44933,0.810293],[-0.842823,-0.861959],[-1.70071,-0.607857],[0.351335,0.635021],[-0.0200433,0.394556],[-0.685161,1.30792],[-0.390447,-0.846992],[-0.824166,0.694298],[-0.593132,0.432952],[-1.10214,0.110808],[-0.100514,-0.714993],[-1.69981,0.499729],[-0.749865,0.613416],[0.567214,0.582272],[-0.0547662,-0.538547],[-1.93119,-0.543831],[-1.06502,0.395131],[-0.622219,0.852808],[-1.27706,-0.276403],[-1.14022,0.0166409],[-0.468929,0.598611],[1.23143,0.924721],[-2.69425,-0.348772],[0.0317594,0.909668],[-1.78421,-0.437804],[-0.930006,0.0295345],[0.313929,-0.470635],[0.422819,0.699643],[1.29862,0.471782],[0.170097,-0.701488],[-0.148833,0.141099],[0.184601,0.130199],[-0.096926,0.748864],[0.830158,-0.11471],[-0.994921,-0.206613],[-0.40047,0.24286],[-0.0507236,0.300229],[0.325625,-0.168879],[-0.741067,0.386163],[-1.47695,0.865012],[-1.30415,-0.267151],[0.771246,0.879573],[-0.525028,0.465051],[-0.0280824,0.778676],[-0.859834,-0.0877949],[-0.421202,0.566726],[-0.473946,0.0127047],[-0.605248,-0.0655567],[-1.5898,-0.101835],[-2.20064,-0.254341],[-0.599892,0.586548],[0.474904,0.607735],[-0.665624,-0.314416],[-0.955437,0.744904],[-0.881931,-0.185465],[-0.308431,0.83027],[0.382006,-0.808704],[0.73372,0.029696],[-0.262503,1.16172],[0.125794,-0.014855],[1.21669,0.722113],[-0.186573,0.289743],[-0.697887,0.313596],[-0.538666,0.726476],[-2.57286,0.622635],[0.322511,0.607943],[0.990386,0.103308],[-0.423625,-0.780502],[0.149705,0.52195],[-0.491124,-0.305951],[-0.735649,0.409356],[-0.392037,0.063433],[-0.197179,-0.0930313],[0.640277,1.04442],[1.24613,0.183927],[-0.144356,0.704319],[-1.0561,-0.25507],[-0.576314,0.793649],[0.360272,-0.572294],[-0.326717,0.0557459],[0.21734,0.314608],[1.7992,0.606681],[-1.09665,0.225305],[0.474684,-0.65048],[0.0733889,-0.432733],[-1.4442,0.218593],[-0.933057,0.339159],[-0.934454,0.909888],[0.654669,-0.107905],[-0.352089,0.45654],[-0.109871,0.870662],[-1.1354,1.41832],[-0.868315,0.191477],[0.530987,0.31488],[0.416025,-0.104506],[-0.971025,-0.448744],[0.719258,0.199449],[0.350915,0.480355],[-1.17371,0.0672662],[-0.471367,-0.544435],[-0.523184,-0.37516],[-0.881461,-0.360896],[1.16037,0.308869],[-0.4032,1.01982],[0.208465,0.824643],[-0.565543,-0.187598],[-1.21322,0.658068],[-0.74199,1.29226],[-0.402402,-0.350272],[-0.150644,0.780103],[0.79474,-0.409649],[-0.00666835,-0.263221],[-1.22297,0.00351021],[-2.70145,-0.000925229],[0.226122,0.695355],[-1.11507,-0.209719],[-0.243393,-0.351598],[-1.56099,0.65964],[-2.98168,0.380384],[0.218074,-0.620477],[-1.37825,1.53627],[-0.461958,0.302392]]}}, +{"best":0.00994913,"evaluations":12444,"generation":286,"median":21.25,"state":{"best":[-0.00705373,-0.000633944],"population":[[0.152312,0.522347],[-0.322601,-0.360001],[-0.716956,-0.172703],[-0.364081,0.845218],[-0.194342,0.162542],[0.209598,0.492101],[0.757089,0.700156],[-0.310644,0.570745],[-0.513813,0.0605544],[-0.552148,0.434818],[-0.883473,-0.213278],[0.131046,1.37794],[-1.15313,0.395355],[-0.298668,0.840678],[-0.788178,1.26553],[-0.315516,0.390592],[-1.0134,-0.270398],[-0.702471,0.0654648],[-0.156228,0.676671],[-0.855574,0.0124387],[-0.35491,0.407788],[-0.425736,0.96753],[-1.55657,-0.762929],[-0.653741,1.1099],[-0.547007,0.0503982],[-0.800111,0.716706],[0.0596036,0.0787746],[-0.620418,0.210702],[-0.821962,-0.357798],[0.252679,0.340686],[0.323066,0.923874],[-0.64008,-0.529907],[0.99402,1.27474],[-0.231701,0.678388],[-0.477989,0.325997],[-0.629829,0.617876],[-0.161902,0.409524],[0.161251,0.474437],[-0.481853,-0.184509],[-0.906148,0.154459],[0.671103,1.06244],[-0.484262,1.4522],[0.172244,0.698825],[-0.208811,0.162552],[-0.602962,0.415395],[0.492603,0.764325],[0.33042,-0.123437],[-0.724195,-0.0676255],[-0.65423,0.181286],[-0.42821,-1.09238],[-0.822071,0.137757],[0.0680856,0.303477],[0.181949,0.0687143],[-2.01422,-0.065961],[-0.732092,0.903135],[-0.632187,0.211426],[-0.536565,-0.41971],[-0.0593791,1.09911],[-0.487961,-0.100594],[-1.06096,-0.385183],[-0.876273,-0.719851],[-2.45297,-0.234194],[-0.920438,0.547173],[-0.475337,-0.0453778],[0.262062,0.148053],[0.14923,-0.365808],[-0.111991,0.08464],[-0.658093,-0.0662292],[0.103233,0.508026],[0.16662,-0.366897],[-1.01565,-0.762884],[-0.695348,0.0417519],[-0.164204,-0.0720489],[-0.168924,-0.438301],[0.401881,1.04224],[0.390806,0.852617],[-1.15129,0.505206],[-0.928774,0.0617117],[-0.433514,-0.538871],[0.0931328,0.443924],[0.0266705,0.278755],[-1.41474,0.542632],[-0.0663171,0.31011],[-0.542302,0.790408],[-0.798815,0.231246],[-0.302516,0.0843791],[-0.0764482,0.591752],[-0.198944,0.359628],[-0.498795,-0.150028],[-0.0344971,0.748232],[0.154222,0.148326],[-0.788499,-0.216133],[-1.50188,0.408306],[-1.41028,-0.139505],[-0.581109,0.575109],[-0.461189,-0.347707],[-0.738643,-0.37211],[-0.122632,0.8221],[-0.990631,0.694985],[-0.375789,0.90827],[-1.06061,0.610591],[-1.03332,0.652094],[-0.289923,-0.258048],[-0.272128,0.659977],[0.0304892,0.177338],[0.408239,-0.212693],[-0.901161,-0.0353334],[-0.775266,0.571407],[0.268663,0.0605935],[-0.715973,0.432974],[-0.251955,0.759139],[-0.247766,-0.286222],[-0.188329,0.442303],[-0.00487541,-0.170285],[-0.114445,1.14741],[-1.23972,0.423777],[-0.7623,0.199081],[-0.214441,0.54097],[-0.700313,-0.663698],[0.275216,1.18409],[-1.31253,0.56053],[-0.620514,-0.433109],[-0.51579,1.01296],[-0.313443,-0.182181],[-0.170046,0.432136],[-1.47055,0.867194],[0.137897,0.55286],[0.0639693,0.162698],[-0.891416,0.4892],[-0.78708,1.22746],[-0.19404,-0.0603413],[-0.24246,0.473922],[-0.965153,0.461348],[0.358656,-0.0397894],[-1.18645,0.18437],[-0.91998,-0.479536],[-0.448398,0.555077],[-0.557113,-0.471639],[-1.11906,-0.160605],[-0.812257,-0.206811],[-0.460767,-0.271442],[-0.0914154,-0.057978],[-1.52858,-0.551848],[0.221993,0.62652],[0.908221,1.55661],[-0.689574,-0.427256],[-0.81208,-0.219746],[-0.486967,0.292332],[-0.0791267,-0.236074],[-0.734814,0.275337],[-0.21689,0.391947],[0.191193,-0.180971],[-0.110029,0.905478],[-0.763543,0.522918],[0.271678,0.387669],[-0.750437,-0.502586],[-1.20938,-0.738358],[-0.833469,0.175123],[-0.814129,0.445984],[0.265734,0.319942],[0.220859,1.00998],[-1.79375,-0.581682],[-0.391418,0.476324],[0.374998,0.527081],[-0.739307,0.0668676],[-0.745103,-0.411517],[0.415858,0.177843],[-0.0730192,0.55915],[-0.865976,0.669343],[0.245903,-0.384559],[-0.207963,0.243033],[0.0107291,-0.294075],[-0.489637,0.111503],[0.616258,0.561432],[-0.386153,0.504246],[-0.97491,0.101385],[-0.493975,0.374681],[0.083964,0.351487],[-0.905789,0.216386],[-0.508237,0.403384],[-0.340488,-0.300564],[-0.0338535,0.377062],[-0.583207,0.28808],[0.0836003,1.02151],[-0.505667,0.228967],[-0.776199,-0.087937],[-0.750229,0.454418],[-0.66563,0.446611],[-0.434114,0.643502],[-1.82177,-0.0591386],[-1.10673,0.253561],[-0.970403,-0.937051]]}}, +{"best":0.00994913,"evaluations":13212,"generation":290,"median":21.25,"state":{"best":[-0.00705373,-0.000633944],"population":[[-0.0100529,-0.0174444],[0.151142,0.335054],[-0.83235,-0.0549872],[0.300046,0.670546],[-0.673445,-0.47512],[-0.165747,0.444461],[0.41166,0.511412],[-0.489789,-0.178938],[0.232971,0.0790984],[-1.57577,0.169142],[-0.0139203,-0.0718695],[-0.608746,0.830363],[0.031375,0.266414],[-0.67681,0.353124],[0.0163361,-0.0317451],[-0.772097,0.00884222],[-0.459157,0.0207666],[-0.0112864,0.348342],[-1.11835,-0.0829471],[-0.360423,0.541753],[-0.440714,-1.11505],[-0.356417,-0.243064],[-0.790155,0.197724],[-0.633457,0.181394],[-1.54342,-0.568431],[-0.745284,-0.296086],[0.33373,0.0846293],[-1.01792,-0.169014],[-0.261039,-0.127232],[-1.29299,0.171738],[-0.248542,-0.503681],[-0.426098,0.384944],[0.300173,-0.0353695],[-0.852301,0.41649],[-1.2821,0.5379],[-0.704796,0.141155],[0.321893,-0.0710831],[-0.565281,0.492204],[-0.573212,-0.775159],[0.38078,0.108584],[-0.783371,-0.479791],[-0.473431,-0.616703],[-0.00526231,-0.0178108],[-0.414552,-1.12988],[-0.849026,0.0824009],[-0.335809,0.551667],[-0.829721,-0.104029],[-0.109372,0.60089],[-0.0350413,0.262808],[-1.25269,-0.412728],[-0.740695,0.479013],[-0.0697003,0.0744083],[-1.95855,0.563395],[-0.675871,0.0850274],[0.325954,0.965227],[0.302342,-0.276161],[-0.0832764,-0.23877],[-0.645067,0.308642],[-0.213164,0.495507],[0.417824,-0.23968],[-0.633151,-0.298664],[0.193146,0.0537049],[-0.476227,0.023049],[-0.715732,-0.156501],[-1.51533,0.51835],[-0.648971,-0.243313],[-0.281101,0.49873],[-0.967938,-0.257898],[-0.82182,0.179776],[-0.000729375,0.418769],[-0.611364,1.16141],[-0.851323,0.123049],[-1.04703,-0.189741],[-0.785429,0.552577],[-0.629622,0.277208],[-0.487677,-0.454571],[0.218484,-0.305245],[-0.159876,-0.0441263],[0.518258,0.0676118],[-1.02067,0.203781],[0.295133,0.209826],[-0.311186,-0.494114],[0.180832,0.475235],[-0.347023,-0.532369],[-0.477925,-0.228114],[-1.29288,0.083784],[-0.265056,-0.257323],[0.0889399,-0.510352],[0.12794,0.505464],[-0.0446419,0.281577],[-0.944582,-0.223517],[-0.331257,0.0154274],[-0.0897353,-0.606617],[-0.8413,1.27955],[0.258652,0.477847],[-0.819824,0.355864],[-1.02149,0.294733],[-0.260455,0.383805],[0.64953,0.80028],[0.0342456,0.492437],[-0.110983,0.402678],[-1.36628,0.140273],[-1.25031,-0.0338691],[-1.15262,0.499747],[0.373903,-0.422025],[-0.709294,-0.16695],[-0.0986963,-0.531581],[-0.196329,0.533039],[-0.226538,0.397826],[0.0829793,0.0350828],[-0.307311,-0.313022],[-0.500571,0.762084],[-0.758093,0.201467],[-0.973069,0.412244],[-0.622746,-0.442515],[-0.527148,0.574852],[-0.601951,-0.193098],[-0.579364,-0.0380869],[-1.14689,-0.198369],[-0.21926,0.713007],[-0.0466843,-0.621923],[-0.140137,0.153129],[-0.351226,0.626065],[0.320627,0.267194],[0.247387,0.743712],[-0.781335,0.157072],[-0.823307,0.937667],[-0.379281,0.568581],[-0.0216629,0.42598],[-0.556086,0.289702],[0.92677,-0.623346],[-1.10744,-0.308654],[-0.963124,-0.0291004],[-0.696343,0.0772858],[0.0398638,-0.144474],[-0.419887,0.53397],[-0.349303,-0.204501],[-0.157355,0.525063],[-0.828913,0.270093],[-0.285713,-0.476755],[0.259031,-0.278124],[0.638052,0.332124],[0.0750469,0.0507168],[-0.570518,0.345355],[-0.179171,0.0107369],[-0.0614161,0.051187],[-0.767719,-0.238155],[-0.913847,0.475521],[0.0192179,0.163887],[0.094697,0.240773],[0.28639,0.557556],[0.337592,-0.0920992],[0.243207,0.405413],[-1.75662,-0.437683],[-0.540136,-0.150709],[-0.895714,-0.346611],[-0.42176,-0.982534],[-0.314095,-0.420455],[-0.23736,-0.531297],[-0.856658,-0.300405],[-0.876714,0.292843],[-0.796823,-0.183131],[-1.75377,-0.00486286],[-0.572745,-0.371564],[-0.710074,0.930385],[-0.357849,0.0703736],[-0.464537,0.83531],[-0.539347,-0.152655],[0.0286107,-0.545043],[-0.0855232,-0.279052],[-0.212469,-0.231365],[0.37163,-0.0102731],[-0.663223,-0.0219916],[-0.176708,-0.052666],[-0.167043,0.057528],[0.24657,0.276662],[-0.744418,0.0416409],[-0.300518,-0.27792],[-0.0163761,0.0679082],[0.0452493,0.104113],[-0.889932,0.887783],[-0.986728,-0.836067],[-0.917968,-0.267771],[-1.22997,-0.601595],[0.0210396,0.298165],[-1.39686,-0.184229],[0.627076,-0.348221],[0.0567873,0.0577082],[0.226356,-0.809443],[-0.347737,0.688991],[-0.189708,-0.633946],[-0.0597949,-0.318362]]}}, +{"best":0.00457669,"evaluations":13788,"generation":293,"median":11.1182,"state":{"best":[0.00189744,0.00441247],"population":[[-0.596557,-0.0754495],[-1.11983,0.079154],[-0.787008,0.0472544],[-0.244094,-0.074475],[-0.930276,0.119083],[-0.409803,-0.0085604],[0.0331682,-0.104019],[-0.547265,-0.116275],[0.425855,-0.00664354],[-0.857905,0.0790209],[-0.806649,-0.146474],[-0.0524069,-0.0551345],[-0.09809,-0.0980693],[-0.266793,-0.035654],[0.0642823,0.0381809],[-0.828212,0.0966237],[0.182078,-0.0623248],[-0.435786,0.0821865],[-0.560141,0.00954272],[-0.349588,-0.0473801],[-0.00588314,-0.117987],[-1.23145,-0.121548],[0.233456,-0.19638],[0.113021,-0.009968],[-0.367259,0.199349],[0.372045,-0.14617],[-0.302274,-0.11138],[-0.903965,-0.00907193],[0.37582,0.0440797],[-0.352127,-0.0980454],[-0.837954,-0.127334],[-0.764077,0.135555],[0.179902,-0.104762],[-0.0644119,-0.0993802],[0.102701,-0.163531],[-0.0274333,0.117861],[-0.332372,0.130968],[-0.357676,0.0573382],[-0.452146,0.0128383],[-0.428236,0.0615491],[-0.122774,-0.108807],[-0.0863658,0.0293953],[-0.692867,0.0314092],[0.318805,0.0135434],[-0.605795,0.101383],[-0.876114,0.114317],[-0.87874,-0.200962],[-1.1836,0.0629912],[-0.273122,-0.0298192],[-0.0138218,0.033616],[-0.359672,0.0499369],[-0.609946,-0.171891],[0.783568,-0.170473],[-0.339221,-0.0287239],[-0.0873935,0.0311975],[0.331352,0.0317027],[-0.622277,0.0913291],[-0.498276,0.000657641],[-0.527632,-0.173214],[-0.00903605,-0.038947],[-0.256712,0.0237743],[-0.457889,-0.183873],[-0.383763,0.053823],[-0.78883,-0.0165206],[-0.0152439,-0.0289188],[-1.3142,0.19567],[-0.67686,0.0173207],[-0.849263,-0.00724614],[-0.258512,0.0386544],[-1.11793,-0.0679479],[-0.0807294,-0.130719],[-0.143791,-0.0520785],[-0.729308,0.0304767],[-0.192117,0.0575735],[-0.427565,0.109104],[-0.16224,0.0719994],[0.0634017,0.0447787],[-0.480265,-0.155791],[-0.8945,-0.070083],[-0.106393,-0.047679],[-0.0858097,-0.0101282],[-0.394246,-0.0232836],[-0.602125,-0.0226171],[0.219429,0.0228871],[-1.23592,0.063881],[-1.0024,0.0648375],[-0.0747441,-0.0357373],[-0.412984,0.0719216],[-0.164737,-0.0749385],[0.148423,-0.0452716],[-0.682921,-0.142449],[-0.524198,-0.0674331],[0.263163,0.134525],[0.012956,0.0515428],[-0.687755,0.0739048],[-1.05328,-0.213049],[-0.212736,0.11094],[-0.466472,0.146642],[-0.642485,-0.0849947],[0.122767,-0.132444],[-0.197022,-0.0170308],[-0.973159,-0.0815214],[-0.26795,-0.0268586],[-0.243872,-0.0999823],[-0.149491,-0.0686195],[-0.935419,0.0913948],[-1.30123,0.0500425],[-1.33928,0.0930551],[0.359792,-0.00194425],[-0.0513439,0.0601168],[-0.29283,-0.0371577],[-0.587219,0.0960232],[-0.405744,-0.19306],[-0.00775803,-0.0851534],[-0.139617,0.123017],[-0.861282,0.111635],[-0.424218,0.0279664],[-0.557042,-0.107285],[0.705596,0.0980457],[-0.105743,-0.0378769],[-1.20272,-0.120843],[-0.19224,0.0427225],[-0.976502,0.0430142],[-0.697688,-0.0222716],[0.305292,-0.062644],[-0.566208,0.237736],[-1.15316,-0.0433454],[-0.233233,-0.0981048],[-0.211098,0.107884],[-0.325568,-0.00319086],[-0.380828,-0.0379222],[0.743098,-0.0320363],[-0.353612,-0.0649182],[-0.344822,0.0169191],[-1.06577,-0.0344828],[-0.0315479,0.012977],[-0.0102129,-0.165172],[0.438392,-0.21339],[-0.834058,-0.030151],[-0.445271,-0.0938723],[-0.627275,-0.0740893],[-1.05366,-0.0751537],[-0.666083,-0.122764],[-0.32984,-0.139681],[0.497766,-0.0137151],[-0.294514,-0.0377293],[0.198188,-0.0869765],[-0.425286,-0.213041],[0.188903,-0.106874],[-0.597007,-0.257999],[0.278168,0.0157673],[0.475095,-0.0479634],[0.255474,0.11364],[-0.920515,-0.0401005],[-0.271508,0.00574792],[-0.156388,-0.0702662],[-0.22746,0.17503],[0.4587,-0.18347],[-0.941511,-0.0740226],[-0.225902,-0.023642],[-0.423926,-0.00764349],[0.254998,-0.195893],[-0.832999,-0.0864067],[0.147962,-0.207935],[-0.18113,0.143292],[-0.720795,-0.112967],[-1.11917,0.117264],[-0.378913,0.0291492],[0.224428,-0.0722889],[-1.05843,-0.17471],[-0.0955907,-0.150742],[-0.589921,0.0240807],[-0.0790545,0.0413021],[-1.04469,-0.0183507],[-0.753605,0.00500283],[-0.0635193,0.109934],[-0.322995,-0.0830744],[-0.691791,0.252891],[-0.137606,0.0418455],[-0.514511,-0.0977623],[-0.711574,0.0388211],[-0.891034,0.0969638],[0.339703,-0.00303552],[0.00189744,0.00441247],[0.431103,0.0738796],[-0.353208,0.211509],[-0.812601,-0.191656],[-1.11244,0.090478],[0.478003,-0.0385404],[-0.326845,0.0603801],[0.176932,-0.234733],[-0.317161,-0.0167361]]}}, +{"best":0.000690479,"evaluations":14364,"generation":296,"median":9.54788,"state":{"best":[-0.0018549,0.000199362],"population":[[-1.0643,0.00324499],[-0.978371,-0.0028256],[-0.939914,0.0415861],[-0.808233,-0.0144641],[-1.00428,-0.00434986],[0.0197574,0.0449056],[-1.08781,-0.0648694],[0.13286,0.0789175],[-0.211328,0.00627398],[0.458896,0.0617362],[-0.830435,0.0352637],[-1.16689,-0.0192233],[-0.287852,-0.0079992],[-1.32433,0.0369823],[-0.505878,-0.0195174],[-0.847848,0.00583192],[0.289628,-0.0112335],[-0.317857,-0.0322196],[-0.048758,0.00905126],[-0.24747,0.0316397],[-1.21482,0.00216646],[-0.385958,-0.00133038],[-0.238836,0.0409535],[-0.368138,-0.0205012],[-0.253755,-0.0090965],[-1.43664,-0.0349725],[-0.680183,0.0241296],[-0.294317,-0.00279633],[-1.1264,0.00974345],[-0.799168,-0.0159846],[-1.3326,0.010001],[0.542715,0.0246703],[-1.42784,0.0212855],[-0.900691,0.0294839],[-1.03909,0.0231177],[-0.43446,0.0128093],[-0.233372,0.0277751],[-0.572281,0.039024],[-0.373263,-0.0261273],[-1.10366,-0.0839735],[-0.680476,0.00357898],[-0.886267,-0.037807],[-0.174248,0.0678744],[0.0743022,-0.0321242],[-0.457286,0.0124624],[-0.739469,-0.0138241],[-0.206563,-0.00332145],[-0.5796,0.00550175],[-0.953395,-0.00669445],[-0.21212,0.0659477],[-0.493519,0.0129114],[-0.997041,0.046666],[-0.345834,0.0105885],[0.176918,0.0310331],[-0.462387,0.000237265],[-0.319117,0.000676685],[0.463457,0.01965],[-1.46934,0.0336261],[-0.505763,0.0151253],[-0.0831782,0.000308531],[-0.484325,0.0221624],[-0.706313,-0.0213009],[-0.13512,0.0431695],[0.0167774,0.0351748],[-0.305297,0.0428185],[-0.834083,0.0128844],[-0.986235,-0.0505569],[0.136495,0.0117702],[0.123803,0.02339],[-0.953111,0.00674581],[-0.981903,0.000263976],[0.0257093,0.0513992],[-0.529725,0.0153707],[-0.0698554,-0.00685906],[-0.11107,0.025754],[-1.16692,-0.0257062],[0.0255712,0.0125723],[0.232246,-0.0198402],[0.0570167,-0.00218932],[-0.0403354,-0.0197022],[-0.802147,-0.0169564],[-0.661062,0.0304659],[-0.401887,0.0442163],[-0.921049,0.0357338],[-0.0437386,0.00308064],[-1.17503,-0.00319257],[-0.09881,0.0172376],[-0.256907,0.0230057],[-1.49707,-0.0181984],[-1.65273,0.0359425],[-0.780566,0.0187367],[-0.846339,-0.0536626],[-0.845809,-0.021947],[-0.589883,0.038413],[0.214666,0.00169922],[-0.804583,-0.0132739],[-0.312346,0.0237402],[-0.410902,-0.0371562],[-0.843387,0.0375684],[-0.253357,-0.00659584],[-1.05799,0.0386808],[-0.189669,0.00916098],[-0.201957,0.0497079],[0.836548,0.0036273],[-0.193837,-0.00770717],[-0.278212,0.0299622],[-0.0359096,0.0495376],[-0.590311,-0.0337001],[-1.96325,-0.0557183],[-0.0908478,0.0256822],[0.4023,0.0056644],[0.254796,0.0114011],[-1.04284,0.0161155],[-0.523256,-0.0189785],[-1.0484,-0.0336633],[-0.515901,0.0257641],[-1.05933,-0.00517561],[-0.71893,0.021726],[-0.831789,-0.0288025],[-0.142659,-0.0232629],[-0.702888,-0.0575354],[-0.505358,-0.0172214],[-0.676689,-0.0147464],[-0.595701,-0.000667005],[-0.693785,0.0286456],[-0.560099,-0.00738828],[0.153375,0.0152416],[0.289335,0.0225088],[0.465076,0.0401316],[0.129689,0.0248104],[-0.451318,-0.00351874],[-0.270202,0.0285897],[-0.152414,-0.0204426],[-0.447271,-0.000139081],[-0.538813,0.0132059],[-1.28282,-0.0276681],[-0.355028,-0.0382307],[0.162366,0.00586081],[0.234094,0.0371865],[-0.249664,-0.000168637],[-1.18105,-0.00910643],[-0.392075,0.0551174],[-0.622623,0.000257298],[-0.996684,0.00508699],[-0.4002,0.0519375],[0.0923365,0.0306936],[-0.431773,0.0275029],[-0.250791,-0.0126504],[-0.761614,0.0398721],[-0.60108,-0.0020707],[-0.926056,0.0832657],[-0.491056,0.0153026],[0.444091,0.0245034],[-0.679906,0.0316127],[-0.317853,-0.00184044],[-0.802006,-0.00316907],[-1.46347,-0.0352462],[-0.287127,0.0278693],[-0.408003,-0.0180002],[-1.23109,-0.00129767],[0.480777,0.051904],[0.193416,0.0266167],[-0.21179,0.00355508],[-1.24069,-0.0184858],[-1.48258,-0.00769306],[-0.338786,0.0332283],[-0.701857,-0.00271705],[0.640648,0.034552],[-0.38736,-0.0709675],[-0.849038,0.0199682],[-0.949294,0.00389464],[-0.630014,0.0099465],[-0.894329,-0.00594754],[-1.10176,-0.0193341],[0.412011,0.0419154],[-0.260132,0.0104884],[-0.082441,0.0394097],[-0.945691,0.0685716],[-0.574043,0.0347656],[-1.32107,-0.0135456],[-0.17295,0.017522],[-1.14372,-0.00498844],[-1.01032,-0.0455948],[-0.238589,0.0185347],[-0.440293,0.0219262],[-0.34563,-0.0416941],[0.176948,-0.00435994],[-0.630185,0.0407522],[-0.731373,0.0112615],[-0.0688764,0.0565313],[-1.35996,0.0302941],[0.265473,0.025745]]}}, +{"best":0.000690479,"evaluations":15132,"generation":300,"median":6.97279,"state":{"best":[-0.0018549,0.000199362],"population":[[-0.640512,0.0165624],[-0.321691,-0.0169788],[0.319018,-0.00898769],[0.0908619,0.0173828],[-0.751642,-0.00544518],[-0.41897,-0.00596563],[-1.09819,0.00773513],[-0.278765,0.0245552],[-0.410938,0.0267872],[0.197762,0.0329626],[-1.1221,-0.00832842],[-0.622596,-0.00464264],[-1.22212,-0.0031812],[-0.692613,-0.00311563],[-1.03113,-0.010391],[0.171843,-0.00478536],[-0.126424,0.000437441],[-0.141392,0.00395275],[0.63646,0.0106909],[-0.195756,0.0225584],[-0.654973,0.00193387],[-0.558236,-0.0152994],[-0.61545,-0.0234098],[-1.21133,-0.0060607],[-1.05961,0.00978459],[-0.992388,-0.0172222],[0.559555,0.0238725],[-0.320411,0.00867715],[-0.867725,0.0170569],[-0.770221,-0.0212267],[-0.469056,-0.0204903],[0.217784,0.0278912],[-0.188427,0.000379824],[-0.716147,0.0118822],[-1.43483,-0.00698184],[-1.02076,0.0136504],[0.0914974,0.01588],[0.499038,0.0165313],[-0.347078,0.0227154],[-0.0680778,0.0206344],[-1.16903,-0.00537693],[-0.0310303,0.0059825],[-0.675607,-0.0137994],[-0.598371,0.0050091],[-0.201532,0.00600116],[0.254015,0.0136601],[-0.0577557,-0.00903631],[-0.799056,0.010172],[-1.46174,-0.00861694],[0.819449,0.0231267],[0.146793,0.00245041],[-0.169376,0.0141193],[-0.0668427,0.00287699],[-0.282422,0.0012589],[-0.888105,0.0112017],[0.10717,-0.0023421],[-0.65285,0.00785551],[0.557067,-0.00282508],[-0.830681,0.0172521],[-0.610963,-0.0104413],[0.360188,0.0159423],[-1.5033,-0.029958],[-0.535469,-0.00541868],[-0.0465425,0.0114114],[-0.956258,0.0151854],[-0.362799,0.0173047],[-0.038081,0.0184155],[-0.712901,-0.0160643],[-0.00901308,-0.00599551],[-0.65289,-0.000458199],[-0.707843,-0.0185706],[-1.53995,-0.00933042],[0.675357,0.0159233],[-0.188834,0.018961],[-0.785515,0.0208107],[0.104518,-0.00449047],[-0.390059,0.0222119],[-0.350117,0.0128062],[-1.01732,0.0100448],[-1.1512,0.00366561],[0.143249,-0.00385377],[-1.01012,0.0263848],[-0.3701,0.00980354],[-0.0869427,0.0125277],[-0.709118,0.0240058],[-0.24759,0.0181142],[0.395238,0.0093103],[-0.148158,0.00830084],[0.848334,0.00920672],[-0.38573,-0.00418395],[-1.2678,-0.0194868],[-1.48258,-0.0225507],[0.0809711,0.0114913],[-0.310362,0.0149468],[-0.875767,0.0352475],[-0.48657,0.0321155],[0.0178073,-0.0132796],[-0.21318,0.0189922],[-1.14408,-0.0189292],[-1.00548,0.0180319],[-0.754979,-0.0151381],[-0.626316,-0.00526891],[-0.550065,-0.00547627],[-0.299843,-0.00460904],[-0.170541,-0.00730316],[-0.904341,0.0144902],[-0.150143,0.019382],[-0.935829,-0.0200728],[-0.0325988,-0.0175198],[-0.141359,-0.0170876],[-0.308801,0.0149799],[-0.623201,-0.0067653],[0.803274,0.00682884],[-0.302661,-0.00546653],[0.50874,0.0106602],[-0.392193,0.0234648],[-0.0488948,0.0106833],[-0.506162,0.0211429],[-1.15801,0.00547286],[0.157783,0.0287907],[-0.762109,0.0153517],[0.103754,0.0157144],[-0.355655,-0.00628143],[-0.366317,0.0309634],[-0.2786,0.00757644],[-0.278428,-0.0106858],[-0.563098,0.00306814],[-0.612329,0.0170648],[-0.83896,-0.00224021],[-0.36542,-0.00651213],[0.586048,0.0168623],[-0.558216,0.00642636],[-0.493685,0.00262728],[-0.77138,-0.00830605],[-0.892756,-0.0287622],[-0.119059,-0.00207137],[-0.924204,0.00727542],[-0.378413,0.0236393],[-0.126795,0.0196968],[-1.22509,-0.000128395],[-0.993458,-0.0199051],[-0.77608,-0.00323771],[0.0174252,0.0238106],[-0.785653,0.019229],[-0.895329,0.0251361],[-0.423519,0.0206677],[0.384796,0.0328115],[0.639183,0.0201226],[-0.237277,0.0346373],[-0.194853,0.0178174],[-0.48864,-0.0164407],[0.171507,0.00774209],[-0.587449,-0.00422401],[-0.780127,0.0155433],[0.199151,0.00912251],[-0.836483,-0.0200328],[1.16052,0.00273081],[0.874757,0.0280564],[-0.398768,0.0229167],[0.827984,0.0166993],[-0.507125,-0.00955551],[-0.39517,0.00210713],[-0.980463,0.0141845],[0.226141,-0.00696154],[-0.962354,-0.0146425],[-0.983693,0.0436942],[-0.151837,0.00671492],[0.680778,0.0214451],[-0.747489,0.00825606],[-0.643568,0.00741388],[0.821955,0.0150843],[-0.30407,-0.00888922],[-0.128398,-0.00241014],[-0.121541,0.0126925],[-1.03639,0.0195152],[-0.516282,0.0182756],[0.375814,0.00764801],[-0.357309,-0.00869415],[-1.00824,-0.00649732],[-0.836807,-0.00594626],[-0.701005,0.0156755],[-0.522439,-0.0178201],[-0.0188439,0.0213715],[0.0951467,0.00651274],[-0.318683,-0.00293711],[-0.667044,0.0199382],[-1.35622,-0.00365726],[0.436586,0.00850571],[0.815083,0.0389314],[-1.47805,0.00263672],[-0.37926,0.0179665],[0.173684,0.000459229]]}}, +{"best":0.000690479,"evaluations":15708,"generation":303,"median":8.94761,"state":{"best":[-0.0018549,0.000199362],"population":[[-0.207335,0.0163869],[-0.869353,0.00512419],[-0.356842,0.00867249],[-1.159,0.00579863],[-0.536913,0.00617878],[-0.701743,-0.00155429],[-0.341848,0.0112942],[0.0408067,0.018797],[-0.966629,0.00817334],[-1.00556,-0.0011927],[-0.0295993,0.0120319],[-0.453835,0.00262727],[-1.10836,-0.00998764],[-0.585778,0.00349376],[-0.540216,0.00704563],[-0.799215,0.0109919],[0.159676,0.00947284],[0.0452274,0.00907673],[-0.381994,0.0181891],[-0.260509,0.00377795],[-0.720507,0.00617582],[-1.42282,0.00836671],[-0.917693,0.00099991],[-1.20095,-0.002463],[-1.21092,-0.00235485],[-0.403875,0.00482479],[-0.954132,0.000853887],[-0.616296,0.00526588],[-0.503516,0.0199232],[-0.560852,-0.0030316],[-0.473539,0.00303315],[-0.00418639,0.0158215],[-0.622009,0.0112152],[-0.393468,0.00429775],[0.443245,0.0144608],[-0.595845,0.000802832],[-0.78512,0.00285749],[-0.224039,0.00839391],[0.0711613,0.0133441],[-0.161646,-0.00109558],[-0.326642,0.00491392],[-0.500267,0.00652654],[-0.638419,0.00807955],[-0.323515,0.0117079],[-0.961502,0.000391015],[-1.55926,-0.000288851],[-1.29248,0.00363946],[-0.191371,0.021195],[-0.472492,0.0181561],[-0.503107,0.0103276],[-0.260487,0.0191963],[-1.03305,-0.00265045],[-0.878757,0.00794739],[-0.840925,0.0116061],[-0.68051,-0.00378614],[0.286034,0.0184258],[-0.616837,0.00403495],[-0.846152,0.000548374],[-0.0321409,0.00776533],[-0.773218,0.00434739],[-0.380622,0.0175728],[0.43139,0.0164011],[0.361855,0.0151444],[-0.816375,0.00578868],[-0.0172146,0.0034233],[0.706845,0.0204645],[0.127047,0.0132597],[-0.444425,0.00529045],[-0.376862,0.00618592],[0.19548,0.0165794],[-0.202636,0.00543109],[0.37367,0.0065323],[-0.686802,-0.000329779],[-0.498449,0.00201112],[-0.0353134,0.00699072],[-0.237223,0.0161303],[0.109324,0.00642792],[0.183053,0.0204272],[-0.00749247,0.00767215],[-0.347186,0.0131318],[-0.525821,-0.000139306],[-0.592122,0.00522927],[-0.718991,0.00472304],[0.125665,0.0170205],[1.07604,0.0141972],[-0.668675,0.00392951],[0.384695,0.0243274],[-0.385414,0.00883086],[-1.19095,0.00447514],[-0.591341,0.00155212],[-0.226431,0.00825211],[-0.406837,-0.00353044],[-0.618123,0.00377268],[0.872235,0.01791],[0.501548,0.00713628],[-0.677203,0.012633],[-0.389446,0.0129406],[-0.461479,-0.00114537],[-0.302704,0.00480108],[-0.171721,0.00896241],[-0.103564,0.000120697],[-1.13666,0.000176248],[-0.219003,0.0252208],[-1.45746,-0.014434],[-1.43368,-0.00649332],[-0.292997,0.00486557],[-1.04751,0.00672147],[-0.0626103,0.0199588],[-0.355172,0.0123002],[-0.538777,0.0169566],[-0.051827,0.00467419],[-0.979146,-0.00433025],[-0.505937,0.00821824],[-1.0697,-0.00189175],[-0.459377,-0.00618743],[-1.10197,0.001671],[-0.166844,0.0125825],[-1.0389,0.0150468],[-0.087503,0.00825807],[-0.157636,0.0028061],[-0.345063,0.0004134],[-0.160745,0.00136782],[-0.982901,0.00515951],[-1.11479,-0.00744906],[0.46097,0.0169709],[-0.417666,0.00706006],[-0.10137,0.0117872],[-0.0425605,0.0103468],[-0.38061,0.000589398],[-1.12467,-0.00821884],[-0.182919,-0.004062],[-0.569196,-0.000333595],[-0.0289234,0.0181386],[-0.559218,0.000234642],[0.288699,0.0144346],[0.404165,0.0116124],[0.394181,0.00989252],[-0.904683,0.000628738],[-0.396776,0.0174399],[-0.416456,0.00460642],[-0.834752,0.0046912],[-0.844119,0.00444795],[-0.396571,0.00321271],[-0.112824,0.0108393],[-0.179122,0.0155081],[0.570898,0.024242],[-0.151554,0.00690615],[-0.473707,0.00544931],[0.0395539,0.00724532],[-0.530162,0.00776137],[-0.342631,-0.00633018],[-0.371989,0.00532965],[-0.377311,0.00247075],[-0.185986,-0.0102526],[-0.0748277,0.0123889],[-0.651256,-0.00552926],[-0.536322,0.00336673],[0.644539,0.00415711],[-0.151512,0.0019258],[-0.878349,0.00193284],[-0.806797,0.00321563],[-0.197141,0.0159484],[-0.437032,0.0131393],[0.301345,-0.00343847],[-0.674639,0.00363392],[0.0833396,0.0186481],[0.0714895,0.00622541],[-0.886128,0.00569706],[-1.28805,-0.00512535],[-0.73273,0.0142035],[0.806884,0.0122667],[-0.0212666,0.00925592],[-1.12637,0.00978015],[-1.49248,0.00650121],[-0.492984,-0.00998391],[-0.205587,0.0175539],[-0.763379,0.000554692],[-0.210566,0.00376322],[1.13511,0.0164732],[-0.942819,0.0108721],[-1.08539,-0.00256221],[-0.463406,0.00606479],[-0.899802,0.00571042],[0.0778772,0.0159961],[-0.937985,-0.00276568],[-0.149201,0.0136356],[-1.14043,-0.00630347],[-0.0684202,0.0162064],[-0.648,0.00267696],[-0.613468,0.0124515],[-0.496675,0.0052508],[-0.838557,-0.00348362]]}}, +{"best":0.000690479,"evaluations":16284,"generation":306,"median":6.9639,"state":{"best":[-0.0018549,0.000199362],"population":[[-0.496019,0.00137878],[-0.205841,0.00890951],[0.450859,0.0247467],[-0.542017,0.00442599],[-0.542611,0.00722736],[-2.13392,-0.0100622],[-0.933291,-0.000651094],[0.00248593,0.00980576],[-0.378667,0.00132035],[-0.541321,0.00195616],[-0.682391,0.00511771],[-1.02974,-0.00132176],[-0.223689,0.0125989],[-0.270017,0.0111638],[-1.32358,-0.00234362],[0.202893,0.016387],[-0.623357,0.00334282],[-0.273281,0.0118789],[-0.997717,0.000158959],[-0.526306,0.00188544],[-0.0610922,0.0113141],[-0.447767,0.0087721],[-0.570422,0.00641371],[-0.920908,0.00595449],[-1.17644,-0.0092752],[-0.362728,0.00338998],[-0.426375,0.0072954],[-0.974154,-0.00522085],[-1.82597,-0.00244434],[0.414625,0.0119984],[-0.268579,0.0109504],[-1.44657,-0.00961398],[-1.73289,-0.00987293],[-1.45319,0.00198644],[-0.148131,0.00921557],[-0.240292,0.00301227],[-1.1738,0.000244024],[-0.0685991,0.00855568],[-1.37111,-0.00439346],[-0.882846,0.00144273],[-0.405469,0.0132358],[-0.564872,0.00907145],[-1.05557,2.92137e-05],[0.369992,0.00905943],[-0.947255,-0.00798854],[-0.559188,4.5938e-06],[-0.818589,0.00701069],[-1.18633,0.000299077],[-0.576418,0.00206714],[-0.18036,0.00219611],[-0.839338,-0.0087746],[-0.599165,0.00491074],[-0.743278,0.00258154],[-0.647967,-0.000565709],[-0.329637,0.0092708],[-0.582933,0.000871018],[-1.14364,0.000253633],[-0.0871782,0.00752437],[-0.142433,0.00691618],[-1.29999,-0.00633313],[-0.705533,0.00156167],[-1.18005,0.000527633],[-0.479125,0.00214605],[0.0526936,0.00929827],[-0.591561,0.0034911],[-0.553941,0.00435721],[-1.11899,-0.00652268],[-1.24798,-0.00330542],[-2.00952,-0.00909435],[-0.857989,-8.18432e-05],[0.103398,0.00822469],[-0.473709,0.0049095],[0.0561196,0.0118269],[1.20704,0.0252476],[0.153617,0.0113825],[-1.00663,-0.000692873],[-0.903459,0.00804916],[0.137688,0.0156516],[-0.200949,0.0103967],[-0.460176,0.00360749],[-1.81029,-0.00590479],[-0.942453,-0.00506572],[-0.869018,0.0060844],[-0.451754,0.00931642],[-0.451501,0.00501164],[-0.719818,0.00228429],[-1.2095,-0.00338833],[-0.966117,-0.00189861],[0.486138,0.00706813],[-0.764541,0.00633474],[-2.24257,-0.0139989],[0.0518851,0.0146628],[0.834408,0.020294],[-1.53169,-0.00365575],[-0.414448,0.00575581],[-0.373976,0.00457762],[-0.39984,0.00526375],[-0.607712,0.00708677],[-0.51752,0.00378149],[-0.823225,0.00842663],[-1.99157,-0.0105491],[-1.67291,-0.00460978],[-1.02849,0.0115184],[-1.04752,-0.00163987],[-0.29069,0.00809276],[-0.998784,-0.0050636],[-1.12904,0.00100232],[0.285937,0.0064568],[-1.01735,0.00146892],[0.472749,0.0191318],[0.139258,0.013447],[-0.667419,-0.00453989],[-0.577439,0.00322549],[-0.132418,0.00990912],[-0.815135,-0.00558919],[-1.57217,-0.0034079],[-0.824361,0.00394034],[-0.271051,0.0092806],[-0.430983,0.00816997],[-0.894643,0.0013006],[-0.132742,0.0112808],[0.142228,0.00932679],[-0.124229,0.00335798],[-0.270237,0.0137788],[-0.243384,0.00651939],[-1.00071,0.00216696],[-1.01406,0.000858574],[-1.63345,-0.00775617],[-0.199089,0.00464652],[-0.194597,0.00813592],[-0.31675,0.00608085],[-0.245542,0.0121211],[-0.293409,0.00850616],[-1.20883,0.00494458],[-0.075553,0.00775334],[-0.835987,0.00263382],[-0.547581,0.000359171],[0.0805958,0.00838226],[-0.563016,0.00927313],[-1.36442,-0.0023009],[-0.739358,0.00748617],[-0.853765,0.00108052],[-0.895653,0.00389218],[-1.64364,-0.00284138],[-0.411016,0.00526089],[-0.949247,0.0013196],[-1.24207,-0.00328957],[-1.2457,0.00200809],[-0.332993,0.000318691],[-1.57684,-0.00070681],[-0.888002,6.55422e-05],[-0.128192,0.00467156],[-1.46744,0.00143216],[-1.88039,-0.0105062],[-0.085329,0.00683907],[-0.194328,0.00867472],[0.0398429,0.0062057],[0.484014,0.0159505],[-0.103663,0.00712908],[-1.052,-0.00304637],[-0.93687,-0.00104984],[-0.562267,0.00701293],[-0.867426,0.000791476],[-1.57679,-0.0096161],[-1.03201,-0.00787997],[-0.5883,6.10866e-05],[-1.57735,-0.00735961],[-1.8879,-0.00957246],[-1.88529,-0.0144328],[-0.410566,0.00361603],[0.0456738,0.0136839],[-0.0502363,0.0108825],[0.0283666,0.00975819],[-0.277962,0.00206155],[-0.534044,0.00547385],[-0.0807301,0.00908948],[-1.61976,-0.0111419],[-0.788224,-0.00272325],[-0.637185,0.000185976],[-0.119361,0.0101636],[-1.35164,-0.00715163],[-0.345907,0.00674851],[-0.652636,-0.00074521],[-1.35567,-0.00887164],[-1.40677,-0.000529769],[-0.42995,0.00569556],[-0.757959,0.00225807],[-0.0207791,0.011386],[-1.0572,0.00130667],[-1.71203,-0.00391594],[0.0472044,0.00710299],[-0.386197,0.0130806]]}}, +{"best":0.000690479,"evaluations":17052,"generation":310,"median":12.283,"state":{"best":[-0.0018549,0.000199362],"population":[[-0.727804,0.00196504],[0.345996,0.0120654],[-1.8573,-0.00792679],[-0.778803,0.00121243],[-0.559406,0.00424181],[-0.40458,0.0041604],[-1.04438,-0.00150489],[-1.30301,-0.00422412],[-0.0373614,0.00941826],[-0.476413,0.00567441],[-0.396856,0.00711049],[0.429665,0.0163161],[-0.855592,0.00207024],[-1.01553,0.000139001],[-0.939763,-0.000795245],[-0.760844,0.00251882],[-0.328309,0.00320821],[-0.514929,0.00286306],[-0.369056,0.00819753],[-1.03195,-0.00205216],[-0.457672,0.00659199],[-0.0304536,0.0101444],[-1.03743,0.00103041],[-0.409756,0.00307791],[-0.23712,0.00738677],[-0.666091,0.00239224],[-1.02728,-0.00197679],[-0.556232,0.00514745],[0.137874,0.0107186],[-1.12192,-0.00298079],[-1.65451,-0.00775373],[-0.21003,0.0102853],[-0.163854,0.00982947],[-0.273901,0.01],[0.0914047,0.00930698],[-0.426521,0.00744887],[-0.713143,0.005539],[-1.1181,-0.00182579],[-0.911643,-9.85679e-06],[-0.571711,0.00352433],[-0.220692,0.00763644],[-1.44546,-0.00394812],[-1.101,-0.00178174],[-0.376528,0.00420185],[-1.60991,-0.00634754],[-0.357033,0.00659587],[-1.63896,-0.00909787],[-0.340823,0.00628976],[-0.656646,0.00240097],[-0.545295,0.00463181],[-0.779857,0.00108476],[-0.860824,0.00111958],[-0.851001,0.00165632],[-0.56857,0.00438828],[-1.12229,-0.00285743],[-0.577508,0.00127945],[-0.505733,0.00252004],[-0.266972,0.00696576],[-1.45284,-0.00699259],[-0.432154,0.00827115],[-0.572684,0.00338081],[-0.238132,0.0087566],[-1.80001,-0.00832402],[-0.822929,0.00236273],[-0.357882,0.00435044],[0.509222,0.0163951],[-0.834963,-0.000516574],[0.296057,0.0130606],[-0.500477,0.00725093],[-0.556955,0.00444697],[-0.491776,0.00669372],[0.00792595,0.00786609],[-0.793132,0.00245967],[0.123105,0.0137355],[-0.818783,-0.000182873],[-0.24294,0.00982108],[-1.07922,-0.00535067],[-0.889126,0.0020801],[-0.687944,0.00297648],[-0.368362,0.00391527],[-0.536751,0.00461456],[-1.28784,-0.00369028],[-0.436716,0.00626522],[-0.826654,0.00237021],[-1.32274,-0.00359262],[-1.16937,-0.00152992],[-0.555174,0.00463565],[-0.964815,0.00178258],[-0.641193,0.0040277],[-0.796426,0.00154663],[-0.545871,0.00580511],[-0.404902,0.00549747],[-1.25857,-0.00327254],[0.0827609,0.0103785],[0.221644,0.0116583],[-1.06619,-0.00321945],[-0.680689,0.00414989],[-1.33406,-0.00226774],[-0.72049,-0.000843447],[-0.8152,0.00212858],[-0.265773,0.00877423],[-1.02008,-0.00309702],[-0.599521,0.00344967],[0.29857,0.0133088],[-1.65068,-0.0106447],[-1.23914,-0.00665693],[0.112538,0.0123782],[-0.00871922,0.00918958],[-0.890323,0.00213299],[-0.471929,0.00518591],[-0.221913,0.00916684],[-0.568026,0.00365511],[-0.252605,0.00460978],[-0.505382,0.00648231],[-1.57225,-0.00663342],[-0.740012,0.00257633],[-0.510077,0.00546373],[-0.636391,0.00363429],[-0.0410405,0.0113827],[-1.2786,-0.00665164],[-0.0100929,0.0116185],[-0.558731,0.00200634],[-1.49641,-0.0079983],[-0.695442,0.00322223],[-0.142063,0.00900516],[-0.48192,0.0033697],[-1.49175,-0.00862843],[-0.652374,0.00403887],[-0.900351,0.00250115],[-0.239589,0.00611139],[-0.639722,0.00305851],[-0.229208,0.00863997],[0.186792,0.0166738],[-0.226122,0.007952],[-0.683438,0.00341021],[-1.32268,-0.00482691],[-0.963667,-0.000464742],[-0.0950004,0.00853665],[-0.131373,0.00987862],[-1.20505,-0.00269195],[-0.65823,0.000349284],[-1.04551,2.54408e-05],[0.230411,0.0130615],[-0.44613,0.00655338],[-1.06102,-0.00172377],[-0.468392,0.00627189],[-0.774999,0.00365042],[-0.610657,0.00110979],[-0.393477,0.00584512],[-0.434442,0.0048369],[-0.942225,0.00195706],[-0.733705,0.00315192],[-0.522867,0.00575306],[-1.20131,-0.00353435],[-0.217206,0.00862194],[-1.16907,-0.00494417],[-1.23373,-0.00476739],[0.202616,0.0147165],[-0.823236,-0.000132955],[-0.325955,0.00500793],[-0.364223,0.00687234],[-0.680544,0.00344958],[-0.682852,0.000363142],[-0.449447,0.00552244],[-0.985668,0.000175401],[-1.08685,-0.00170233],[-0.201315,0.00974066],[-0.235455,0.00812495],[-0.70203,0.00246472],[-0.0479583,0.00882356],[0.0247957,0.0134961],[-0.60201,0.00554402],[-0.664463,0.00691757],[-0.794502,0.00226387],[-0.983206,0.000352651],[-0.317898,0.0074659],[-0.142626,0.00817941],[-0.732817,0.00147375],[-0.198823,0.0129474],[0.214499,0.0133032],[-0.698272,0.00308582],[-1.07627,-0.00182377],[-0.678124,0.00411875],[-0.712361,0.00310591],[0.155329,0.0115704],[-0.0989408,0.00827884],[-0.578136,0.00560755],[-0.00102519,0.0119571],[-0.770978,0.00110636],[-1.45058,-0.00505245],[-1.06263,-8.66184e-05],[0.0291978,0.0115706]]}}, +{"best":0.000690479,"evaluations":17628,"generation":313,"median":10.6867,"state":{"best":[-0.0018549,0.000199362],"population":[[-0.397252,0.00703157],[-1.31513,-0.00363414],[-1.22996,-0.00105327],[-0.66757,0.00243536],[-0.79336,0.00146454],[0.306641,0.0141045],[-0.0911861,0.0106628],[0.498977,0.01293],[-1.0037,0.000820934],[-1.35098,-0.0074601],[-0.110708,0.00857091],[-0.210559,0.00538537],[-0.130451,0.00551332],[-0.247902,0.00851221],[-0.719719,0.000510463],[-1.04173,-0.000389406],[0.104193,0.0124188],[-0.833106,0.00151646],[-1.18257,-0.000688486],[-1.05063,0.000369562],[-0.00123902,0.00952634],[-1.09153,-0.00196909],[-0.273904,0.0075148],[-0.496612,0.00214946],[-0.264623,0.00680935],[-0.161136,0.00552268],[-1.40376,-0.00338703],[-0.387364,0.00514679],[0.162204,0.010647],[-0.845111,0.00271649],[-0.775416,0.00104496],[-0.617953,0.00423256],[-1.28829,-0.0034873],[0.293531,0.0113971],[-1.2219,-0.00195125],[-0.272419,0.00602795],[-0.347711,0.00640572],[-0.54061,0.00441341],[-0.427052,0.0091139],[-0.401649,0.00586411],[-0.77801,-0.000410082],[-0.100139,0.00864289],[0.367764,0.0122527],[-1.12764,-0.000733855],[-0.879462,-0.00194033],[-0.279322,0.00523415],[-0.51223,0.00561409],[-0.371153,0.00699129],[0.184384,0.00925983],[-0.131063,0.00610682],[0.0778315,0.00854891],[-0.639208,0.000791948],[-1.47705,-0.005154],[-0.505298,0.00508371],[-0.0657122,0.00822187],[-0.627405,0.000347295],[-0.31671,0.00916175],[-0.524104,0.00347575],[0.518378,0.012894],[-0.76319,0.00226518],[-0.590178,0.00627577],[-1.39212,-0.00544087],[-0.907064,0.00150714],[-0.419332,0.00436581],[-0.352842,0.00606182],[0.348519,0.0139684],[-0.27984,0.00500259],[-0.853068,0.00106543],[-1.01231,-0.00194271],[-0.382887,0.0045973],[-0.410266,0.00270023],[-0.598492,0.00149797],[0.0734246,0.00996364],[-0.190572,0.0077624],[-0.0676632,0.0097774],[-0.707008,0.00424228],[-1.28839,-0.00101803],[0.102537,0.0139795],[-0.0642672,0.00746855],[-1.23718,-0.00471997],[-0.638463,0.00239936],[0.281561,0.0105932],[0.290649,0.0116664],[-0.484687,0.00336986],[-0.0714725,0.0107131],[0.120544,0.0108079],[-1.04119,0.000786704],[-0.348748,0.00596803],[-0.618607,-0.00107784],[-0.490336,0.00629181],[-1.01561,0.000873704],[-1.34957,-0.00407174],[0.125969,0.0124462],[-1.09297,0.00145875],[-0.168428,0.00859099],[-1.39402,-0.00351778],[0.107956,0.0110232],[-0.778045,0.00202193],[-1.05405,-0.000271484],[-1.09293,-0.000550482],[-1.50257,-0.00451673],[-0.192757,0.0109802],[-1.50977,-0.00473818],[-0.346238,0.00507603],[-0.646592,-0.000331465],[-0.329436,0.00655045],[-0.643522,0.00475526],[-0.992363,-0.00175665],[-0.956601,0.00242897],[0.272049,0.0131723],[-0.467515,0.00380913],[-1.12347,-0.00146017],[-0.00866772,0.00516533],[-0.799857,0.00111282],[-1.50958,-0.00422869],[-0.536036,0.00345282],[0.266598,0.0130144],[-0.133197,0.0078554],[0.0439412,0.00613845],[-1.00378,-0.000723325],[-0.270339,0.00684469],[-0.134556,0.0089507],[-0.476533,0.00417133],[-1.65951,-0.0062247],[-0.880403,0.00385204],[0.661785,0.0147535],[-0.430362,0.00265822],[-0.508254,0.00457837],[-0.95075,0.000835713],[-1.06491,-0.00213715],[-0.7119,0.00234387],[0.0728499,0.00978565],[-0.46599,0.00506915],[-0.0895914,0.0101267],[-2.05179,-0.0100432],[0.285967,0.0124362],[-0.33371,0.00451432],[-1.23109,-0.00283243],[-0.000740129,0.00880356],[-0.65993,0.00335375],[0.243699,0.00933846],[-0.943336,-0.00108077],[-0.803623,0.00279018],[-0.816198,0.00269956],[-1.60168,-0.00698228],[-1.35175,-0.00254313],[-0.867074,0.000195491],[-0.879565,-0.000936134],[0.0418285,0.00773937],[0.145028,0.0139098],[-0.091891,0.00890483],[-0.310696,0.00604441],[-1.11359,0.000713776],[-1.16167,-0.00195351],[-0.343353,0.00681615],[-0.579791,0.00502698],[-0.0569885,0.00871819],[-0.585036,0.00244969],[-0.953995,0.00115455],[0.459564,0.0120647],[-1.28818,-0.00199974],[-0.682288,0.00198469],[0.254402,0.0133602],[-0.887611,-0.000417442],[0.0487678,0.0114262],[-0.490709,0.00295239],[-0.15599,0.00966955],[-0.327951,0.00700354],[-1.92371,-0.0071675],[-0.0126104,0.00907663],[-0.614677,0.00364771],[-0.605942,0.00407998],[-0.804107,-0.000172226],[-0.787596,0.000832035],[-0.97079,0.00327863],[-0.829339,0.0038108],[-0.0883577,0.00938063],[-0.388983,0.00716612],[-0.420807,0.00591352],[-1.11385,-0.00237176],[-0.240564,0.00445991],[-0.488954,0.00590081],[0.728616,0.0199265],[-0.278667,0.00995436],[-0.392585,0.0018584],[-0.62943,0.00395042],[-0.627933,0.00355317],[-0.471328,0.00324588],[-0.988958,0.000915393],[-1.42332,-0.00582414],[0.0830583,0.00883052],[0.779604,0.0176068]]}}, +{"best":0.000690479,"evaluations":18204,"generation":316,"median":10.1131,"state":{"best":[-0.0018549,0.000199362],"population":[[-0.615293,0.00305181],[-0.517241,0.00327503],[-0.796257,0.00362354],[0.585722,0.0139317],[0.163299,0.00753966],[-0.634304,0.00291355],[0.541226,0.0136353],[0.189548,0.00947468],[-0.729427,0.00117555],[-0.484422,0.0027951],[-0.772302,0.0031395],[-0.270647,0.00411991],[-0.522921,0.0043346],[-0.994796,0.000500269],[0.175935,0.012286],[-0.283292,0.0046906],[-0.55694,0.00464601],[-1.16544,-0.00308816],[-1.5005,-0.00405558],[-1.8415,-0.00769255],[0.970628,0.0177078],[-0.960302,0.000370323],[-1.58729,-0.00528733],[-0.851719,0.000676785],[-0.827288,0.00148635],[-0.24443,0.00678456],[-0.672619,0.00366407],[-0.199938,0.00684577],[-0.359552,0.00621879],[-0.984305,-0.000514094],[-1.07471,-0.00026174],[-0.309223,0.00545686],[0.263158,0.01328],[-0.680527,0.00332106],[-0.491401,0.00254458],[0.147827,0.0129021],[-0.366272,0.00475307],[-1.14626,-0.00218983],[-0.621107,-0.000243693],[0.243763,0.0115414],[-0.988736,0.000503167],[-0.889781,-0.000742268],[-1.25755,-0.00439801],[-0.503082,0.00455822],[-0.598336,0.00449351],[-0.00180443,0.0114915],[-0.330731,0.00510858],[-1.66924,-0.00567205],[-1.11226,-0.000397755],[-0.102371,0.00717693],[-0.0819218,0.00799296],[-0.72641,0.00175015],[-0.103205,0.00701356],[-0.290455,0.00491013],[-0.158842,0.00900989],[-0.164141,0.00622083],[-0.679585,0.00284281],[0.0042274,0.0090507],[-0.147481,0.00762755],[-1.18158,-0.000732193],[-0.995546,-0.00218874],[0.0464833,0.00694059],[-0.0748216,0.00733826],[-0.634981,0.0035527],[-0.450107,0.00446611],[0.0844475,0.00861392],[-1.05998,0.000428949],[-0.577175,0.00404529],[-1.0829,-0.000384384],[0.342862,0.0136746],[-0.556167,0.00339267],[-0.145383,0.0079261],[0.148942,0.0099281],[-0.551886,0.00587162],[0.51719,0.0132621],[-1.17051,-0.00168421],[-0.969165,0.00219139],[-0.346261,0.00567128],[-0.715468,0.0016624],[-0.393077,0.0069553],[-0.979071,0.00132764],[-1.03277,0.000414069],[-0.720869,0.000963578],[-0.792498,0.000476964],[-0.105489,0.00845681],[0.0132804,0.00945862],[-0.275597,0.00397337],[-0.440059,0.00344273],[0.163715,0.0101637],[0.108318,0.00912023],[0.0829379,0.0100098],[-0.637204,0.00345042],[-1.4077,-0.00420528],[0.179653,0.0103771],[-1.14627,-0.00179363],[-0.12009,0.00885142],[-0.605867,0.00215833],[-0.932064,0.000163761],[-0.887531,0.000670671],[-0.892405,-0.000510563],[-1.01796,0.00056112],[0.294578,0.0120816],[-0.523449,0.00489091],[0.19433,0.00975584],[-0.0934347,0.00810756],[-0.369911,0.00652714],[0.0964685,0.00921742],[0.313331,0.0115431],[-0.259559,0.00744838],[0.011569,0.00999884],[-0.130245,0.00827735],[-0.210587,0.00699631],[-1.1109,-0.00159928],[-0.285699,0.00733095],[0.155967,0.0112884],[-0.36248,0.00619203],[-0.303205,0.00577232],[-0.166894,0.00568731],[-0.992001,-0.00128765],[-0.4301,0.00541555],[0.0935695,0.00717833],[-0.105923,0.00550369],[0.0804193,0.0099277],[0.176863,0.00995536],[-1.21595,-0.00172767],[-0.263998,0.00804028],[-0.200601,0.00716344],[-0.597601,0.00386003],[0.0656515,0.00926995],[-0.374119,0.00470445],[-0.185089,0.00682225],[-0.61168,0.00356417],[-0.115029,0.00707936],[-0.286011,0.00436036],[-1.22953,-0.0019763],[-0.776201,0.00193021],[-1.62139,-0.00684726],[-0.433862,0.00586067],[0.272701,0.0113348],[-0.927603,0.00134324],[-0.70715,0.00266367],[-1.05489,-0.000932926],[-0.152273,0.00803423],[0.176979,0.00965648],[-0.592462,0.00520889],[-0.571256,0.00217756],[-0.0205488,0.00981442],[0.0802226,0.00989487],[-0.84736,0.00166447],[-1.03592,0.00131797],[-1.00211,-6.02088e-05],[-1.29598,-0.00227626],[-0.33525,0.00386195],[0.329074,0.0116131],[-0.736753,0.00281374],[-0.974045,0.000655559],[-0.339267,0.0049905],[-0.659654,0.00335245],[-0.633727,0.00248631],[-0.442862,0.00276294],[-0.816125,0.00203874],[-0.636779,0.00225762],[-1.24873,-0.00436793],[-0.46554,0.00419013],[-0.0429406,0.00959693],[-0.697909,0.00252182],[0.302597,0.00984133],[0.0580284,0.00946162],[-1.36591,-0.00486609],[0.154605,0.0119161],[0.355814,0.0118594],[-0.541158,0.00607998],[0.557937,0.013799],[-0.538028,0.00639425],[-0.435164,0.00467009],[-0.376811,0.00317636],[-0.390445,0.00734642],[0.461245,0.0124601],[-0.345779,0.00408861],[-0.400154,0.00436532],[-0.339019,0.00586726],[-0.557995,0.00340595],[-0.278246,0.00765578],[-0.256848,0.00745226],[-0.873475,0.00199944],[-0.312023,0.0071408],[-0.814472,0.00201148],[0.30456,0.0075916],[-0.0690829,0.0101148],[-0.371184,0.00449446],[0.627322,0.0146556],[-0.201202,0.00804296]]}}, +{"best":0.000690479,"evaluations":18780,"generation":319,"median":13.8755,"state":{"best":[-0.0018549,0.000199362],"population":[[-0.264893,0.00732135],[-0.519603,0.00390695],[-0.48364,0.00438959],[-0.7558,0.00033026],[0.0731219,0.0100831],[-1.69524,-0.00686713],[-0.712046,0.00213175],[-0.599275,0.00487293],[-1.45024,-0.00397898],[-0.503839,0.0039955],[-0.162027,0.00790852],[-1.23768,-0.00186266],[-0.816063,0.00115631],[-0.0904185,0.00839169],[-0.114036,0.00968537],[0.144306,0.0100441],[-0.306141,0.00642959],[-0.901281,0.000791086],[-0.743491,0.0024089],[-0.645801,0.0027889],[0.00663561,0.00858692],[-0.528505,0.0054288],[0.436863,0.0130427],[-0.832533,0.00171237],[-1.22855,-0.00362071],[-0.752539,-2.78115e-07],[-0.487385,0.00499669],[0.0149157,0.00856504],[0.0185397,0.00994594],[-0.396968,0.00434115],[-0.417248,0.00490841],[-0.327082,0.00611705],[-0.777044,0.00202814],[-0.881912,0.00191001],[-0.239016,0.00658607],[-0.290431,0.00569153],[-0.0807503,0.00790794],[0.379019,0.0127213],[-0.140259,0.00855512],[-0.398795,0.00639473],[-1.17873,-0.000965078],[-1.43449,-0.00167504],[-0.396166,0.00427567],[-0.637208,0.00389032],[-1.26359,-0.00315863],[-0.528744,0.0053347],[0.233607,0.0121422],[-0.120293,0.00777939],[-0.366845,0.0055697],[-0.553185,0.00375696],[-0.310053,0.00645853],[1.14372,0.0186758],[-0.879114,0.00192354],[-0.748903,0.00278534],[-0.649275,0.00211482],[-0.90515,0.00098296],[-0.581314,0.00409172],[-0.26117,0.00658323],[-0.399662,0.00459319],[-0.591481,0.00324358],[0.240529,0.0117376],[-0.962614,0.00100028],[-0.468573,0.00554998],[-1.53047,-0.0066826],[0.456725,0.0141329],[-0.944657,0.0030492],[-0.116116,0.00688621],[-0.436129,0.00393165],[-0.312956,0.00741648],[-0.263422,0.00813164],[-0.487468,0.00431186],[0.0671217,0.00879885],[-0.387202,0.0050239],[-1.81608,-0.00820044],[0.228111,0.0112256],[-1.20308,-0.00324107],[-0.616033,0.00197636],[-0.42413,0.00405404],[-0.0992318,0.00921802],[-0.236742,0.00766441],[-1.31391,-0.00318817],[-0.170604,0.00901135],[0.42128,0.0119525],[-0.839221,0.00325598],[-0.0885323,0.00812784],[-0.156455,0.00871644],[0.361058,0.0127706],[-0.630774,0.00440916],[-0.0257819,0.00955633],[-0.532397,0.00485419],[-0.112281,0.00942781],[-0.941326,-0.0013102],[-0.563806,0.00382291],[-0.662001,0.00392098],[-0.106327,0.00877417],[-0.403628,0.00547557],[-0.847694,0.00240161],[-0.476722,0.00497727],[-0.585677,0.00273684],[-0.940223,0.00131263],[-0.233842,0.00779248],[-0.567637,0.00254815],[-0.0561691,0.00921975],[-0.998131,-0.000865692],[0.567719,0.0145688],[-0.868917,0.000963864],[-1.42643,-0.00415992],[0.0945098,0.00905406],[-0.579569,0.00458687],[-0.482455,0.00492064],[-0.314909,0.00670266],[-0.18019,0.0103245],[-0.463147,0.00473248],[-0.145098,0.00900236],[-1.19359,-0.0010016],[-1.01709,0.000234527],[-0.538865,0.00280123],[-1.08193,0.000269537],[-0.592527,0.00451405],[-0.474459,0.00325592],[-1.12298,-0.00171694],[-0.328877,0.00645733],[-0.00300465,0.00770616],[-0.912123,0.000426816],[0.0354127,0.00829823],[-1.30043,-0.00237683],[0.355451,0.0121854],[-0.679155,0.0033251],[-0.648134,0.00153777],[-0.935176,-0.000611645],[-0.383569,0.00634267],[-0.591423,0.00226049],[0.140136,0.0116352],[-0.684921,0.0023407],[-0.723584,0.00285964],[-0.484489,0.0055464],[-0.0133134,0.00984612],[-1.92116,-0.0099373],[-0.401122,0.00386214],[-0.522675,0.00403877],[-0.509169,0.00205314],[-0.379915,0.00541996],[-0.62676,0.00344267],[-0.496917,0.00528113],[-0.69742,0.00222685],[-1.03438,-0.00173748],[-0.446666,0.00508103],[0.349188,0.0143769],[-0.1818,0.00906273],[0.0236011,0.00885337],[-0.975958,7.39182e-05],[-0.734462,0.00176345],[-0.953006,-6.99775e-05],[-1.39826,-0.00431837],[-0.391468,0.00543143],[-0.859619,0.00124024],[-0.942048,0.00276151],[-0.652102,0.00368691],[-1.11376,-0.00215128],[-0.653584,0.00361937],[-0.703932,0.00243677],[-0.352445,0.00586159],[-0.295247,0.00538783],[-0.510703,0.00409889],[-0.48366,0.0044019],[-0.481643,0.00465344],[-0.497581,0.00440252],[0.202604,0.011156],[-0.210005,0.00824811],[-0.895989,0.00388264],[-0.743552,0.00289447],[-0.916027,-0.0026892],[-0.800878,0.00200543],[-0.330112,0.0051623],[-1.20987,-0.00250629],[-0.880895,0.000636529],[-0.201685,0.00783703],[-0.147906,0.00794792],[0.32784,0.0120105],[0.228554,0.0124753],[-0.338847,0.00619033],[0.192711,0.0117031],[-1.09538,-0.000997932],[0.191466,0.0120913],[-0.474278,0.00441781],[-0.98781,0.00179935],[0.022326,0.00842432],[-0.61319,0.00596083],[-0.268323,0.00705501],[-0.664399,0.00457047],[0.0339087,0.0093168],[-0.43218,0.00734405]]}}, +{"best":0.000690479,"evaluations":19548,"generation":323,"median":9.76126,"state":{"best":[-0.0018549,0.000199362],"population":[[-0.743412,0.00173809],[-0.500026,0.00510471],[-0.826884,0.00120888],[-0.933786,-0.000932527],[-0.692763,0.00304491],[-0.899153,0.00255113],[-1.11343,-0.00266116],[-0.908504,-0.000522266],[-0.667201,0.00262442],[-1.08152,7.03063e-05],[-1.02087,-0.000353256],[-1.09045,-0.000803893],[-1.43295,-0.0043742],[-1.51495,-0.00431757],[-0.879163,0.00111741],[-0.829174,0.00291497],[0.212383,0.0131833],[-0.740041,0.00252865],[-1.20854,-0.00167953],[-0.566788,0.00414338],[-1.24311,-0.000758948],[0.355192,0.0141663],[-1.27887,-0.0017127],[-1.33035,-0.00302634],[-0.823707,0.00192903],[-0.543647,0.00447497],[-0.0659327,0.00962182],[-0.604945,0.00359808],[-0.245119,0.00752051],[-1.31308,-0.00280397],[-0.029635,0.0100659],[0.0900474,0.00987385],[-1.0258,0.000531571],[-0.81033,0.00179346],[-0.871668,0.00073859],[0.0960356,0.0113983],[-0.399989,0.00562037],[-0.376217,0.00572576],[-0.180718,0.0084139],[-0.873693,0.00170881],[-0.603095,0.00310047],[-0.899807,0.000768849],[0.0132986,0.00979519],[-0.740183,0.00254206],[-0.553507,0.00593608],[-0.400279,0.00662788],[0.315853,0.0131719],[-0.690804,0.00326518],[-0.346753,0.00792951],[-0.981617,-0.00173224],[-0.333991,0.00573614],[-0.585092,0.00235606],[-0.182691,0.00862093],[-0.111815,0.0091701],[-0.297412,0.00688306],[-0.814764,0.00338885],[-0.460798,0.00317817],[-0.271255,0.00586056],[-1.16605,-0.00189975],[-0.631116,0.00363621],[-0.211466,0.00663987],[-0.396709,0.00502153],[-0.46851,0.00573685],[-0.568251,0.00490484],[-0.722855,0.00189292],[-0.733059,0.00277338],[-0.859758,0.00131006],[-1.42862,-0.00402993],[-1.47607,-0.00363264],[-0.0246373,0.00970329],[-0.965462,0.000554322],[-1.1029,-0.00121889],[-0.466326,0.00680919],[-0.587363,0.00517421],[-0.967581,0.000360067],[-1.12723,-0.00115604],[-1.1862,-0.00217768],[0.584916,0.0154455],[0.0584902,0.0112135],[-0.586564,0.00440131],[-0.384959,0.00537248],[-0.818745,0.00121291],[-1.05044,-0.00230417],[-0.517024,0.00405086],[-0.547511,0.00369659],[-0.336852,0.00536118],[-0.280358,0.0075116],[-1.16293,-0.00301118],[-1.00786,-0.000179408],[-0.661703,0.00299168],[-0.402006,0.00681091],[-0.0356711,0.0090457],[-0.732301,0.00222337],[-0.778785,0.00211045],[-0.583605,0.00433736],[-0.133305,0.00725137],[0.174085,0.0115486],[-0.200965,0.00921854],[-0.418165,0.00577875],[-0.586361,0.00563995],[-1.07891,0.000167788],[0.0576248,0.00936082],[-1.0254,0.000530873],[0.108494,0.00947899],[-0.855343,0.000815592],[-0.187533,0.0081783],[0.274728,0.0111688],[-0.342044,0.00687352],[-0.312864,0.00788349],[-0.691315,0.00137978],[-1.14472,-0.000560452],[-0.923328,0.000805507],[-0.585515,0.00214836],[-0.984974,-0.000683714],[-0.107267,0.0082708],[-1.10258,-0.0011879],[0.188361,0.0123198],[-0.247098,0.00751651],[-0.478722,0.00561385],[-1.28996,-0.00299509],[-0.558508,0.00600991],[-0.401221,0.00493484],[-0.510447,0.00456385],[-0.281625,0.00444177],[-0.61862,0.0053228],[-1.00417,-0.00145748],[-0.673941,0.00411873],[-0.217025,0.0069592],[-0.749272,0.00261788],[-0.0915253,0.00824984],[-1.43799,-0.00326842],[-0.70359,0.00402366],[-0.0148526,0.00840094],[-0.971062,-0.000267944],[-0.603254,0.00263037],[-0.0148957,0.0100394],[-0.631535,0.00171717],[0.121893,0.00931747],[-0.21213,0.00712299],[-0.376698,0.00508437],[0.00595473,0.00929207],[-0.426918,0.00531001],[-0.117732,0.00847903],[-0.100048,0.008858],[-0.461686,0.0035237],[-0.2502,0.00734714],[-0.758346,0.00187862],[-0.32201,0.00863063],[0.09387,0.010457],[-0.324545,0.00755876],[0.272662,0.0147792],[-0.354431,0.00665143],[-0.259773,0.00723973],[-0.236636,0.00780513],[-0.665869,0.00178411],[-0.653903,0.00376785],[-0.902945,-0.00032545],[0.534239,0.0153462],[-0.892071,-0.000242703],[-0.979305,-0.00113637],[-0.982281,0.000737155],[-0.629981,0.0035525],[-0.445161,0.00367528],[-0.913316,0.000128195],[0.619614,0.0146047],[-0.504506,0.00494247],[-0.0559511,0.00934997],[-0.572027,0.0038054],[-0.220097,0.00651367],[-0.268724,0.00576116],[-0.890337,0.00207172],[-0.919292,0.000292607],[-0.915007,0.000367207],[-1.01839,-0.000212154],[-0.162849,0.00676302],[-1.24646,-0.00301018],[-1.12159,-0.00190246],[-0.692948,0.00309806],[-0.159558,0.00647212],[-1.24082,-0.00361663],[-0.692524,0.00285008],[0.322398,0.0112573],[-0.0559095,0.00774201],[-0.781061,0.00181087],[-0.540556,0.00527899],[-0.195007,0.00784358],[-0.191974,0.0077788],[-1.00255,-0.000574856],[-0.578889,0.00380599],[-0.245061,0.00639297],[-0.479814,0.00521692],[-0.451045,0.00459029]]}}, +{"best":0.000690479,"evaluations":20124,"generation":326,"median":12.7221,"state":{"best":[-0.0018549,0.000199362],"population":[[-0.34768,0.00585415],[0.695967,0.015386],[-0.227296,0.00774933],[0.11793,0.0110857],[0.348117,0.0131372],[-1.11973,-0.000930394],[-0.984699,0.0007439],[-1.0633,3.90285e-06],[-0.368946,0.00516919],[-0.691362,0.00339866],[0.308593,0.0124361],[-0.0692281,0.0083872],[-0.346113,0.00630203],[-0.361057,0.00552992],[-1.59661,-0.00593374],[-0.479356,0.00472434],[-0.295019,0.00674763],[-0.643772,0.00205869],[0.0789609,0.00975875],[-0.280242,0.00688479],[-0.526047,0.00414961],[-0.117672,0.00786803],[-1.19337,-0.00124868],[0.418322,0.0128859],[-0.549052,0.00326537],[-0.682501,0.00242972],[-0.80956,0.00140899],[-0.0533156,0.00847766],[-0.726727,0.00217556],[-0.196715,0.00773531],[0.490708,0.0124704],[-1.06281,-0.000635457],[-0.0466553,0.00956737],[-0.564533,0.00413016],[-0.650397,0.00402054],[0.394791,0.0129112],[-0.0642162,0.00804021],[-0.196676,0.00782516],[-0.991694,-0.000667207],[-0.300965,0.006987],[-1.47289,-0.00486899],[-0.580881,0.00339563],[-0.555473,0.00433089],[-0.653588,0.00306842],[0.199542,0.0104604],[-0.244126,0.00684645],[-0.790217,0.00216534],[-0.549934,0.00450812],[0.166794,0.0113393],[-0.333006,0.00510291],[-0.766047,0.00151324],[0.394287,0.0137816],[0.0195028,0.00841438],[-1.27211,-0.00288213],[-0.646961,0.00383099],[-0.195885,0.00830596],[-0.725832,0.00143662],[-1.09447,-0.00095164],[-1.34021,-0.00348487],[-0.357471,0.00623251],[-1.23936,-0.00259928],[-0.681664,0.00260824],[-0.533377,0.00403415],[-0.695743,0.00257727],[-0.471805,0.00453841],[-0.501599,0.00367246],[-0.00289639,0.0085042],[-0.599216,0.00365907],[-0.341655,0.0062409],[-0.834677,0.00137741],[-0.869047,0.00215659],[-0.689306,0.00339368],[-0.989379,-0.000387596],[0.41189,0.0131601],[-0.0635403,0.00831708],[-0.45725,0.00531876],[-1.25062,-0.00218258],[-0.488547,0.00532247],[-0.338929,0.00565784],[-1.14629,-0.00123031],[-1.03769,0.000367304],[-0.0482639,0.00944559],[-0.958205,0.000310422],[-0.0961884,0.00820682],[-0.44081,0.00507371],[-0.133695,0.00784041],[0.109265,0.0104723],[-1.02573,0.000446249],[-0.806739,0.00164719],[-0.395297,0.00511547],[0.0486999,0.0109202],[0.380247,0.0128866],[-0.487832,0.00487198],[-0.135599,0.0074246],[-0.556825,0.0044163],[-0.401355,0.00570238],[-0.683317,0.0028081],[0.166279,0.0109208],[-0.788586,0.00251096],[-0.631954,0.00265586],[-0.479817,0.00475637],[-0.810005,0.00198116],[-0.565273,0.0037412],[0.0764108,0.0106436],[-0.722581,0.00247979],[-1.66563,-0.00571313],[-0.731126,0.00246013],[0.068218,0.00986733],[-0.068513,0.00834829],[0.401357,0.0132619],[-0.658901,0.00326058],[-0.0647768,0.00891327],[-0.166276,0.00829678],[-0.522686,0.00477258],[-0.0761366,0.00921077],[-0.821746,0.00117783],[-0.690713,0.00333037],[-0.159978,0.00899135],[-0.719067,0.00286219],[0.0110823,0.00896414],[-1.59973,-0.00673102],[-0.515,0.00447498],[-0.419539,0.00585908],[-1.45754,-0.00451274],[0.11338,0.00940141],[-1.27124,-0.00228955],[-1.27548,-0.00230656],[-0.815988,0.00107342],[-0.916891,0.00128288],[-0.156423,0.00714397],[-0.509179,0.00429014],[-0.914976,0.000425788],[-0.670871,0.00282464],[-0.428231,0.00486211],[-1.36302,-0.00278859],[-0.723859,0.00286088],[-0.701567,0.00271187],[-0.266126,0.00725504],[-0.796357,0.00215009],[-0.196884,0.00691689],[-1.41177,-0.00347076],[0.287795,0.0112251],[-0.193985,0.00843315],[-0.285441,0.00654161],[-0.672636,0.0033138],[-1.03542,-0.000624607],[-1.24189,-0.00301179],[-0.928012,-2.88259e-06],[-0.846159,0.00105293],[-0.248827,0.00687684],[-0.0431073,0.0089233],[-1.1467,-0.00240633],[-0.0995582,0.00747688],[-0.257062,0.00675771],[-0.701721,0.00322877],[-0.678394,0.00247747],[-0.357382,0.00619158],[-0.835181,0.00140894],[-0.841524,0.0016574],[-0.405142,0.00578174],[-0.867021,0.00118834],[-0.213163,0.00646085],[-0.196848,0.00733438],[0.21005,0.011659],[-0.608713,0.00470839],[-0.455887,0.00513633],[-0.299761,0.00576981],[0.0910116,0.0109943],[-0.732067,0.00262944],[-0.879372,0.00087513],[-0.735388,0.00228918],[-0.325226,0.00575656],[0.00619307,0.00974821],[0.0500323,0.008913],[0.0608525,0.00997768],[-1.03344,-4.75181e-05],[-0.161709,0.00794831],[-0.958216,0.000689742],[-1.24385,-0.00258475],[0.177629,0.0108726],[0.489799,0.0140431],[-0.662695,0.0022419],[-0.692676,0.00280541],[-0.882412,0.000888095],[-0.289639,0.00644395],[-0.468468,0.00508717],[-0.875244,0.0016445],[-0.896081,6.40278e-05],[-0.502943,0.00424477],[-0.689659,0.00176691],[0.120794,0.0102897],[-0.440343,0.00530309]]}} +]} diff --git a/examples/non_continuous_rastrigin/trace.py b/examples/non_continuous_rastrigin/trace.py new file mode 100644 index 00000000..17a40a16 --- /dev/null +++ b/examples/non_continuous_rastrigin/trace.py @@ -0,0 +1,189 @@ +"""The trace for the plot on the example's page, written to the file that ``GENOXIDE_TRACE`` +names. The plot draws the population on the function's contour, which needs two dimensions: the +trace is of a separate run of CMA-ES with IPOP restarts in 2 dimensions, with a budget of +20,000 evaluations, in at most 100 frames. The Rust example writes the same file.""" + +import json +import math +import os + +import genoxide as gx + + +def record_small(): + """Runs CMA-ES with IPOP restarts in 2 dimensions and writes its trace, if ``GENOXIDE_TRACE`` is set.""" + path = os.environ.get("GENOXIDE_TRACE") + if not path: + return + problem = gx.problems.NonContinuousRastrigin(2) + minimum = problem.optimum.value + budget = 20_000 + cmaes = gx.Cmaes(problem.genome, restarts="ipop", objective="minimize", seed=1) + frames = Frames(100) + + def record(progress): + state = {"population": progress.population.tolist(), "best": progress.best_genome.tolist()} + frames.push(frame(progress, state, minimum)) + + cmaes.run(problem, target=minimum + 1e-8, evaluations=budget, on_generation=record) + low, high = problem.genome.bounds + settings = { + "format": 1, + "example": "non_continuous_rastrigin", + "objective": "minimize", + "x_label": "evaluations", + "y_label": "error", + "log_y": True, + "optimum": 0.0, + "plot": "contour", + "problem": { + "function": "non_continuous_rastrigin", + "bounds": [[float(low), float(high)]] * 2, + "minima": problem.optimum.solutions.tolist(), + }, + } + write(path, settings, frames.to_list()) + + +def frame(progress, state, minimum): + """The frame of a generation: its progress, the errors of its best and of its population's + median to ``minimum`` (rounding can put a solution a few ulps below it), and ``state``.""" + + def error(value): + return None if value is None else max(value - minimum, 0.0) + + return { + "generation": progress.generation, + "evaluations": progress.evaluations, + "best": error(progress.best_fitness), + "median": error(median(progress.scores)), + "state": state, + } + + +def median(scores): + """The median of the valid scores, None without any.""" + scores = sorted(float(score) for score in scores if not math.isnan(score)) + middle = len(scores) // 2 + if not scores: + return None + return scores[middle] if len(scores) % 2 else (scores[middle - 1] + scores[middle]) / 2 + + +# ---- the same in every example's trace ---------------------------------------------------------- + + +class Frames: + """The frames of at most ``most`` generations, from the part of the run where what the page + plots changes: the frames after the last change are left out (a run that reached its target, + or a front that no longer moves), and the rest are spread evenly over the generations up to + it. While the run goes, up to 8 × ``most`` frames are kept: every ``every``-th generation, + with ``every`` doubling whenever there are that many, and the last one.""" + + def __init__(self, most): + self.most, self.every, self.kept, self.last = most, 1, [], None + + def push(self, frame): + if frame["generation"] % self.every: + self.last = frame + return + self.kept.append(frame) + self.last = None + if len(self.kept) == 8 * self.most: + self.every *= 2 + self.kept = [kept for kept in self.kept if kept["generation"] % self.every == 0] + + def to_list(self): + frames = self.kept + ([self.last] if self.last else []) + active = frames[: last_change(frames) + 1] + count, most = len(active), max(self.most, 2) + if count <= most: + return active + return [active[(i * (count - 1) + (most - 1) // 2) // (most - 1)] for i in range(most)] + + +def last_change(frames): + """The index of the frame after which nothing the page plots changes. To 3 significant + digits, as a plot shows them: the best, the median and, for a single objective (a numeric + best), the state; to within a hundredth of their range over the run: a front's + hypervolumes, in the state or in a grid's series.""" + if not frames: + return 0 + last = len(frames) - 1 + number = lambda value: isinstance(value, (int, float)) and not isinstance(value, bool) + single = any(number(frame.get("best")) for frame in frames) + + def measures(frame): + values = [] + state = frame.get("state") + hypervolume = state.get("hypervolume") if isinstance(state, dict) else None + for value in (hypervolume, frame.get("series")): + if number(value): + values.append(float(value)) + elif isinstance(value, dict): + values.extend(float(v) for _, v in sorted(value.items()) if number(v)) + return values + + measured = [measures(frame) for frame in frames] + end = measured[last] + tolerance = [] + for k in range(len(end)): + values = [values[k] for values in measured if k < len(values)] + tolerance.append((max(values) - min(values)) / 100.0) + + def same(frame, final, key, flush=False): + return coarse(frame.get(key), flush) == coarse(final.get(key), flush) + + def settled(i): + frame, final = frames[i], frames[last] + return ( + same(frame, final, "best") + and same(frame, final, "median") + and (not single or same(frame, final, "state", flush=True)) + and len(measured[i]) == len(end) + and all(abs(v - e) <= t for v, e, t in zip(measured[i], end, tolerance)) + ) + + first = last + while first > 0 and settled(first - 1): + first -= 1 + return first + + +def coarse(value, flush=False): + """``value`` with its numbers to 3 significant digits, as precisely as a plot shows them: two + frames whose plotted values agree to that precision look the same. With ``flush``, for the + solutions a plot draws on their ranges, numbers below 1e-6 in size count as 0.""" + if isinstance(value, float): + if flush and abs(value) < 1e-6: + value = 0.0 + return f"{value:.2e}" + if isinstance(value, (list, tuple)): + return "[" + ",".join(coarse(item, flush) for item in value) + "]" + if isinstance(value, dict): + items = sorted(value.items()) + return "{" + ",".join(f"{key}:{coarse(item, flush)}" for key, item in items) + "}" + return json.dumps(value) + + +def write(path, settings, frames): + """Writes the settings and the frames to ``path``, a frame per line.""" + lines = ",\n".join(map(to_json, frames)) + with open(path, "w", encoding="utf-8", newline="\n") as file: + file.write(f'{to_json(settings)[:-1]},"frames":[\n{lines}\n]}}\n') + + +def to_json(value): + """Compact JSON with sorted keys, and numbers rounded to 6 significant digits, as the Rust + example writes it.""" + return json.dumps(rounded(value), sort_keys=True, separators=(",", ":"), ensure_ascii=False) + + +def rounded(value): + if isinstance(value, dict): + return {key: rounded(item) for key, item in value.items()} + if isinstance(value, (list, tuple)): + return [rounded(item) for item in value] + if isinstance(value, float): + return float(f"{value:.5e}") if math.isfinite(value) else None + return value diff --git a/examples/non_continuous_rastrigin/trace.rs b/examples/non_continuous_rastrigin/trace.rs new file mode 100644 index 00000000..28f48292 --- /dev/null +++ b/examples/non_continuous_rastrigin/trace.rs @@ -0,0 +1,261 @@ +//! The trace for the plot on the example's page, written to the file that `GENOXIDE_TRACE` names. +//! The plot draws the population on the function's contour, which needs two dimensions: the trace +//! is of a separate run of CMA-ES with IPOP restarts in 2 dimensions, with a budget of +//! 20,000 evaluations, in at most 100 frames. The Python example writes the same +//! file. + +use genoxide::observer::Snapshot; +use genoxide::prelude::*; +use genoxide::problems::{NonContinuousRastrigin, Problem}; +use serde_json::{Value, json}; + +// runs CMA-ES with IPOP restarts in 2 dimensions and writes its trace, if GENOXIDE_TRACE is set +pub fn record_small() -> Result<()> { + let Ok(path) = std::env::var("GENOXIDE_TRACE") else { + return Ok(()); + }; + let problem = NonContinuousRastrigin::new(2); + let optimum = problem.optimum().expect("known"); + let minimum = optimum.value(); + let budget = 20_000; + let cmaes = Cmaes::builder(problem.representation()) + .restarts(cmaes::Restarts::Ipop) + .minimize() + .seed(1) + .build()?; + let mut frames = Frames::new(100); + Engine::new(cmaes, problem.clone()) + .stop_when(Stop::target(minimum + 1e-8).or(Stop::evaluations(budget))) + .on_generation(|snapshot| { + let population = snapshot.population().iter().map(|x| &x.genome()[..]); + let population: Vec<&[f64]> = population.collect(); + let best = &snapshot.best().genome()[..]; + let state = json!({ "population": population, "best": best }); + frames.push(frame(snapshot, state, minimum)); + }) + .run()?; + let bounds = problem.representation().bounds().to_vec(); + let bounds: Vec<[f64; 2]> = bounds.iter().map(|b| [*b.start(), *b.end()]).collect(); + let minima: Vec<&[f64]> = optimum.solutions().iter().map(|x| &x[..]).collect(); + let settings = json!({ + "format": 1, + "example": "non_continuous_rastrigin", + "objective": "minimize", + "x_label": "evaluations", + "y_label": "error", + "log_y": true, + "optimum": 0.0, + "plot": "contour", + "problem": { + "function": "non_continuous_rastrigin", + "bounds": bounds, + "minima": minima, + }, + }); + write(&path, settings, frames.into_vec()); + Ok(()) +} + +// the frame of a generation: its progress, the errors of its best and of its population's median +// to `minimum` (rounding can put a solution a few ulps below it), and `state` +fn frame(snapshot: &Snapshot<'_, Reals>, state: Value, minimum: f64) -> Value { + let progress = snapshot.progress(); + let error = |value: f64| (value - minimum).max(0.0); + let population = snapshot.population().iter(); + let scores = population.filter_map(|individual| individual.fitness()?.score()); + json!({ + "generation": progress.generation(), + "evaluations": progress.evaluations(), + "best": progress.best().and_then(Fitness::score).map(error), + "median": median(scores.collect()).map(error), + "state": state, + }) +} + +// the median of the scores, None without any +fn median(mut scores: Vec) -> Option { + scores.sort_by(f64::total_cmp); + let middle = scores.len() / 2; + match scores.len() { + 0 => None, + n if n % 2 == 1 => Some(scores[middle]), + _ => Some((scores[middle - 1] + scores[middle]) / 2.0), + } +} + +// ---- the same in every example's trace --------------------------------------------------------- + +// the frames of at most `most` generations, from the part of the run where what the page plots +// changes: the frames after the last change are left out (a run that reached its target, or a +// front that no longer moves), and the rest are spread evenly over the generations up to it. While +// the run goes, up to 8 × `most` frames are kept: every `every`-th generation, with `every` +// doubling whenever there are that many, and the last one. +struct Frames { + most: usize, + every: u64, + kept: Vec<(u64, Value)>, + last: Option<(u64, Value)>, +} + +impl Frames { + fn new(most: usize) -> Self { + let (every, kept, last) = (1, Vec::new(), None); + Self { + most, + every, + kept, + last, + } + } + + fn push(&mut self, frame: Value) { + let generation = frame["generation"].as_u64().expect("a generation"); + if !generation.is_multiple_of(self.every) { + self.last = Some((generation, frame)); + return; + } + self.kept.push((generation, frame)); + self.last = None; + if self.kept.len() == 8 * self.most { + self.every *= 2; + let every = self.every; + self.kept.retain(|(generation, _)| generation % every == 0); + } + } + + fn into_vec(self) -> Vec { + let frames = self.kept.into_iter().chain(self.last); + let frames: Vec = frames.map(|(_, frame)| frame).collect(); + let active = &frames[..=last_change(&frames)]; + let (count, most) = (active.len(), self.most.max(2)); + if count <= most { + return active.to_vec(); + } + let at = |i: usize| active[(i * (count - 1) + (most - 1) / 2) / (most - 1)].clone(); + (0..most).map(at).collect() + } +} + +// the index of the frame after which nothing the page plots changes. To 3 significant digits, as +// a plot shows them: the best, the median and, for a single objective (a numeric best), the state; +// to within a hundredth of their range over the run: a front's hypervolumes, in the state or in a +// grid's series +fn last_change(frames: &[Value]) -> usize { + let Some(last) = frames.len().checked_sub(1) else { + return 0; + }; + let single = frames.iter().any(|frame| frame["best"].is_number()); + let measures = |frame: &Value| -> Vec { + let mut values = Vec::new(); + for value in [&frame["state"]["hypervolume"], &frame["series"]] { + match value { + Value::Number(number) => values.extend(number.as_f64()), + Value::Object(map) => values.extend(map.values().filter_map(Value::as_f64)), + _ => {} + } + } + values + }; + let measured: Vec> = frames.iter().map(measures).collect(); + let end = &measured[last]; + let tolerance: Vec = (0..end.len()) + .map(|k| { + let values = measured.iter().filter_map(|values| values.get(k).copied()); + let (low, high) = values.fold((f64::INFINITY, f64::NEG_INFINITY), |(low, high), v| { + (low.min(v), high.max(v)) + }); + (high - low) / 100.0 + }) + .collect(); + let settled = |i: usize| { + let (frame, final_frame) = (&frames[i], &frames[last]); + let same = + |key: &str, flush: bool| coarse(&frame[key], flush) == coarse(&final_frame[key], flush); + same("best", false) + && same("median", false) + && (!single || same("state", true)) + && measured[i].len() == end.len() + && measured[i] + .iter() + .zip(end) + .zip(&tolerance) + .all(|((value, end), tolerance)| (value - end).abs() <= *tolerance) + }; + let mut first = last; + while first > 0 && settled(first - 1) { + first -= 1; + } + first +} + +// `value` with its numbers to 3 significant digits, as precisely as a plot shows them: two frames +// whose plotted values agree to that precision look the same. With `flush`, for the solutions a +// plot draws on their ranges, numbers below 1e-6 in size count as 0 +fn coarse(value: &Value, flush: bool) -> String { + let join = |items: Vec| items.join(","); + match value { + Value::Number(number) if number.is_f64() => { + let number = number.as_f64().expect("f64"); + let number = if flush && number.abs() < 1e-6 { + 0.0 + } else { + number + }; + format!("{number:.2e}") + } + Value::Array(items) => { + format!( + "[{}]", + join(items.iter().map(|item| coarse(item, flush)).collect()) + ) + } + Value::Object(map) => { + let entry = |(key, item): (&String, &Value)| format!("{key}:{}", coarse(item, flush)); + format!("{{{}}}", join(map.iter().map(entry).collect())) + } + other => other.to_string(), + } +} + +// writes the settings and the frames to `path`, a frame per line +fn write(path: &str, settings: Value, frames: Vec) { + let frames: Vec = frames.iter().map(to_json).collect(); + let settings = to_json(&settings); + let head = &settings[..settings.len() - 1]; + let text = format!("{head},\"frames\":[\n{}\n]}}\n", frames.join(",\n")); + std::fs::write(path, text).expect("the trace is written"); +} + +// compact JSON with sorted keys, and numbers rounded to 6 significant digits and written as +// Python writes them (7542.0, 1e-08): the Python example writes the same file +fn to_json(value: &Value) -> String { + let join = |items: Vec| items.join(","); + match value { + Value::Number(number) if number.is_f64() => python_float(number.as_f64().expect("f64")), + Value::Array(items) => format!("[{}]", join(items.iter().map(to_json).collect())), + Value::Object(map) => { + let entry = + |(key, item): (&String, &Value)| format!("{}:{}", json!(key), to_json(item)); + format!("{{{}}}", join(map.iter().map(entry).collect())) + } + other => other.to_string(), + } +} + +fn python_float(value: f64) -> String { + let rounded: f64 = format!("{value:.5e}").parse().expect("a number"); + let shortest = format!("{rounded:e}"); + let (mantissa, exponent) = shortest.split_once('e').expect("an exponent"); + let exponent: i32 = exponent.parse().expect("an exponent"); + if (-4..16).contains(&exponent) { + let text = rounded.to_string(); + if text.contains('.') { + text + } else { + text + ".0" + } + } else { + let sign = if exponent < 0 { '-' } else { '+' }; + format!("{mantissa}e{sign}{:02}", exponent.abs()) + } +} diff --git a/examples/penalized1/README.md b/examples/penalized1/README.md new file mode 100644 index 00000000..6b876103 --- /dev/null +++ b/examples/penalized1/README.md @@ -0,0 +1,81 @@ +--- +title: Penalized 1 +category: continuous +summary: Minimize Yao, Liu and Lin's first penalized function in 30 dimensions, with CMA-ES without and with restarts, DE, PSO and a GA from 10 seeds each. +reference: "Yao, X., Liu, Y. and Lin, G. (1999). Evolutionary programming made faster. IEEE Transactions on Evolutionary Computation 3(2): 82-102." +reference_url: "https://doi.org/10.1109/4235.771163" +optimum: "0 (at (−1, …, −1))" +languages: [rust, python] +order: 91 +family: Penalized +tab: Penalized 1 +trace_note: "Recorded from another run: CMA-ES with IPOP restarts in 2 dimensions, so that the population can be drawn on the function's contour." +--- + +# Penalized 1 + +## The problem + +Yao, Liu and Lin's first generalized penalized function is Levy's function of yᵢ = 1 + (xᵢ + 1)/4, +with a penalty beyond ±10: + +```text +f(x) = (π/n) {10 sin²(πy₁) + Σᵢ₌₁ⁿ⁻¹ (yᵢ − 1)² [1 + 10 sin²(πyᵢ₊₁)] + (yₙ − 1)²} + + Σ u(xᵢ, 10, 100, 4), each xᵢ in [−50, 50] +u(x, a, k, m) = k (|x| − a)^m if |x| > a, and 0 otherwise +``` + +Its minimum is 0, at (−1, …, −1), where every yᵢ is 1 and every term 0. Here n = 30. It's Yao, Liu +and Lin's (1999) f12, whose table I and appendix give the definition, the bounds and the dimension; +the appendix misprints the minimizer as (1, …, 1), where the value is 13π/2 in 2 dimensions. The +function is usually credited to Levy and Montalvo's tunneling papers (1985), which weren't read. + +## What makes it hard + +The sines put a local minimum near every point where their arguments are whole multiples of π: +a grid of shallow wells over the box, the more of them the more genes. The wells' depth scales with +the squares in front of the sines, so they are shallower the nearer the minimum, and the squares +lead towards it. The penalty u is 0 inside [−10, 10] (Penalized 1) or [−5, 5] (Penalized 2), and rises as a +fourth power outside: a wall that keeps the search away from the bounds of [−50, 50]. + +## Representation + +A `Real` genome of 30 genes, each in [−50, 50]: the point x itself. The fitness is f(x), to +minimize. The function is genoxide's `problems::Penalized1`, which brings its bounds and its minimum. + +## Algorithm + +Five algorithms, each from seeds 1 to 10, with a budget of 10,000 evaluations per dimension, +300,000 per run, and a target of 1e-8: + +- CMA-ES (Hansen and Ostermeier, 2001, Evolutionary Computation 9(2): 159-195), which samples a + population of 14 from a normal distribution and adapts its mean, its step size and its covariance + matrix, from a step size of 0.3 of each gene's range and a random start; +- the same with IPOP restarts (Auger and Hansen, 2005, IEEE CEC 2005: 1769-1776): a run that has + converged starts again from a random point with twice the population; +- differential evolution with genoxide's defaults, SHADE (Tanabe and Fukunaga, CEC 2013), with a + population of 100 and its restarts on stagnation; +- particle swarm optimization (Kennedy and Eberhart, 1995), 40 particles with Clerc and Kennedy's + constriction coefficients and a global topology; +- a real-coded genetic algorithm: a population of 100, tournaments of 3, simulated binary crossover + (Deb and Agrawal, 1995) with η = 15 and polynomial mutation with η = 20 at a rate of 1/30 per + gene. + +## Output + +The first line gives the dimension, the seeds and the budget. Then a row per algorithm: how many +of its 10 runs reached the minimum, to within 1e-8, the median of their evaluations (a dash if none +did), and the median of every run's best error, to two significant digits. The function is +evaluated with genoxide's portable math, so the runs are the same on every platform, and in Python, +`run` evaluates it in Rust, so both versions print the same. + +[The project page](https://tachsin.gr/projects/genoxide/examples/penalized1) plays back another run: +CMA-ES with IPOP restarts on the function in 2 dimensions, so that the population +can be drawn on its contour. It meets the target after 426 evaluations. + +## Good results + +The minimum is 0. CMA-ES with IPOP restarts reaches it in all 10 runs, after a median of 6,391 +evaluations, and without restarts in 9 of 10, after 6,370. SHADE reaches it every time, after +27,600. PSO reaches it 5 times, and its median run ends at 0.052, in a local minimum; the genetic +algorithm never, with a median error of 4.8e-7. diff --git a/examples/penalized1/main.py b/examples/penalized1/main.py new file mode 100644 index 00000000..8d9fb0ae --- /dev/null +++ b/examples/penalized1/main.py @@ -0,0 +1,86 @@ +"""Penalized 1: minimize Yao, Liu and Lin's first penalized function, Levy's function with a +penalty, in 30 dimensions. + +Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), +differential evolution (SHADE), particle swarm optimization and a real-coded genetic algorithm from +10 seeds each, and counts the runs that reach the minimum, 0 at (−1, …, −1), to within 1e-8. The +function is genoxide's `problems::Penalized1`, which run evaluates in Rust. + +With ``GENOXIDE_TRACE=``, it also writes a trace of a run for the plot on the example's page, +with trace.py. + + python examples/penalized1/main.py +""" + +import genoxide as gx + +from trace import record_small + +DIMENSIONS = 30 +SEEDS = 10 +BUDGET = 10_000 * DIMENSIONS +# a run stops once its error to the minimum is at most this +ERROR = 1e-8 +ALGORITHMS = ["CMA-ES", "CMA-ES with IPOP", "DE", "PSO", "GA"] + + +def build(name, genome, seed): + """The algorithm called ``name``, on ``genome``, from ``seed``.""" + if name == "CMA-ES": + return gx.Cmaes(genome, objective="minimize", seed=seed) + if name == "CMA-ES with IPOP": + return gx.Cmaes(genome, restarts="ipop", objective="minimize", seed=seed) + if name == "DE": + return gx.De(genome, objective="minimize", seed=seed) + if name == "PSO": + return gx.Pso(genome, population_size=40, objective="minimize", seed=seed) + return gx.Ga( + genome, + population_size=100, + select=gx.Tournament(3), + crossover=gx.SimulatedBinaryCrossover(15.0), + mutation=gx.PolynomialMutation(20.0, rate=1 / DIMENSIONS), + objective="minimize", + seed=seed, + ) + + +def median(values): + """The median of ``values``, None without any.""" + values = sorted(values) + middle = len(values) // 2 + if not values: + return None + return values[middle] if len(values) % 2 else (values[middle - 1] + values[middle]) / 2 + + +def error_text(error): + """An error to two significant digits, as Rust writes it: 9.9e-9.""" + mantissa, exponent = f"{error:.1e}".split("e") + return f"{mantissa}e{int(exponent)}" + + +problem = gx.problems.Penalized1(DIMENSIONS) +minimum = problem.optimum.value +print(f"Penalized 1 in {DIMENSIONS} dimensions, {SEEDS} seeds, {BUDGET} evaluations at most per run") +print("algorithm at min evaluations median error") +for name in ALGORITHMS: + # the evaluations of the runs that reach the minimum, and every run's best error + evaluations, errors = [], [] + for seed in range(1, SEEDS + 1): + result = build(name, problem.genome, seed).run( + problem, target=minimum + ERROR, evaluations=BUDGET + ) + if result.stop_reason == "target": + evaluations.append(float(result.evaluations)) + # rounding can put a solution a few ulps below the minimum + errors.append(max(result.best_fitness - minimum, 0.0)) + reached = f"{len(evaluations)}/{SEEDS}" + middle = median(evaluations) + evaluations_text = "-" if middle is None else f"{middle:.0f}" + print(f"{name:<16} {reached:>6} {evaluations_text:>11} {error_text(median(errors)):>12}") +print("evaluations: the median of the runs that reach the minimum") + +# with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate run in +# 2 dimensions: the plot is the function's contour +record_small() diff --git a/examples/penalized1/main.rs b/examples/penalized1/main.rs new file mode 100644 index 00000000..917941fc --- /dev/null +++ b/examples/penalized1/main.rs @@ -0,0 +1,118 @@ +//! Penalized 1: minimize Yao, Liu and Lin's first penalized function, Levy's function with a +//! penalty, in 30 dimensions. +//! +//! Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), +//! differential evolution (SHADE), particle swarm optimization and a real-coded genetic algorithm +//! from 10 seeds each, and counts the runs that reach the minimum, 0 at (−1, …, −1), to within +//! 1e-8. The function is genoxide's `problems::Penalized1`. +//! +//! With `GENOXIDE_TRACE=`, it also writes a trace of a run for the plot on the example's +//! page, with `trace.rs`. +//! +//! ```text +//! cargo run --release --example penalized1 +//! ``` + +mod trace; + +use genoxide::prelude::*; +use genoxide::problems::{Penalized1, Problem}; + +const DIMENSIONS: usize = 30; +const SEEDS: u64 = 10; +const BUDGET: u64 = 10_000 * DIMENSIONS as u64; +// a run stops once its error to the minimum is at most this +const ERROR: f64 = 1e-8; +const ALGORITHMS: [&str; 5] = ["CMA-ES", "CMA-ES with IPOP", "DE", "PSO", "GA"]; + +fn main() -> Result<()> { + let problem = Penalized1::new(DIMENSIONS); + let minimum = problem.optimum().expect("known").value(); + println!( + "Penalized 1 in {DIMENSIONS} dimensions, {SEEDS} seeds, {BUDGET} evaluations at most per run" + ); + println!("algorithm at min evaluations median error"); + for algorithm in ALGORITHMS { + // the evaluations of the runs that reach the minimum, and every run's best error + let mut evaluations = Vec::new(); + let mut errors = Vec::new(); + for seed in 1..=SEEDS { + let outcome = run(algorithm, problem, seed, minimum + ERROR)?; + if outcome.stop_reason() == StopReason::Target { + evaluations.push(outcome.evaluations() as f64); + } + // rounding can put a solution a few ulps below the minimum + let best = outcome.best_fitness().score().expect("valid"); + errors.push((best - minimum).max(0.0)); + } + let reached = format!("{}/{SEEDS}", evaluations.len()); + let evaluations = median(evaluations).map_or("-".to_string(), |e| format!("{e:.0}")); + let error = median(errors).expect("a run"); + println!( + "{algorithm:<16} {reached:>6} {evaluations:>11} {:>12}", + format!("{error:.1e}") + ); + } + println!("evaluations: the median of the runs that reach the minimum"); + + // with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate + // run in 2 dimensions: the plot is the function's contour + trace::record_small()?; + Ok(()) +} + +// a run of `algorithm` from `seed`, until its best is at most `target` or it has used BUDGET +// evaluations +fn run(algorithm: &str, problem: Penalized1, seed: u64, target: f64) -> Result> { + let real = problem.representation(); + let stop = Stop::target(target).or(Stop::evaluations(BUDGET)); + match algorithm { + "CMA-ES" | "CMA-ES with IPOP" => { + let restarts = if algorithm == "CMA-ES" { + cmaes::Restarts::Never + } else { + cmaes::Restarts::Ipop + }; + let cmaes = Cmaes::builder(real) + .restarts(restarts) + .minimize() + .seed(seed) + .build()?; + Engine::new(cmaes, problem).stop_when(stop).run() + } + "DE" => { + let de = De::builder(real).minimize().seed(seed).build()?; + Engine::new(de, problem).stop_when(stop).run() + } + "PSO" => { + let pso = Pso::builder(real) + .population_size(40) + .minimize() + .seed(seed) + .build()?; + Engine::new(pso, problem).stop_when(stop).run() + } + _ => { + let ga = Ga::builder(real) + .population_size(100) + .select(Tournament::new(3)?) + .crossover(SimulatedBinaryCrossover::new(15.0)?) + .mutate(PolynomialMutation::per_gene(1.0 / DIMENSIONS as f64, 20.0)?) + .minimize() + .seed(seed) + .build()?; + Engine::new(ga, problem).stop_when(stop).run() + } + } +} + +// the median of `values`, None without any +fn median(mut values: Vec) -> Option { + values.sort_by(f64::total_cmp); + let middle = values.len() / 2; + match values.len() { + 0 => None, + n if n % 2 == 1 => Some(values[middle]), + _ => Some((values[middle - 1] + values[middle]) / 2.0), + } +} diff --git a/examples/penalized1/output.txt b/examples/penalized1/output.txt new file mode 100644 index 00000000..ae9ab8f6 --- /dev/null +++ b/examples/penalized1/output.txt @@ -0,0 +1,8 @@ +Penalized 1 in 30 dimensions, 10 seeds, 300000 evaluations at most per run +algorithm at min evaluations median error +CMA-ES 9/10 6370 9.0e-9 +CMA-ES with IPOP 10/10 6391 9.0e-9 +DE 10/10 27600 9.3e-9 +PSO 5/10 31360 5.2e-2 +GA 0/10 - 4.8e-7 +evaluations: the median of the runs that reach the minimum diff --git a/examples/penalized1/trace.json b/examples/penalized1/trace.json new file mode 100644 index 00000000..25cf9872 --- /dev/null +++ b/examples/penalized1/trace.json @@ -0,0 +1,73 @@ +{"example":"penalized1","format":1,"log_y":true,"objective":"minimize","optimum":0.0,"plot":"contour","problem":{"bounds":[[-50.0,50.0],[-50.0,50.0]],"function":"penalized1","minima":[[-1.0,-1.0]]},"x_label":"evaluations","y_label":"error","frames":[ +{"best":1752840.0,"evaluations":6,"generation":0,"median":75651900.0,"state":{"best":[21.4496,-14.2894],"population":[[-40.2856,-12.232],[10.9727,-30.536],[-27.0235,37.6881],[-10.7094,-46.4995],[-37.5609,-36.306],[21.4496,-14.2894]]}}, +{"best":11383.6,"evaluations":12,"generation":1,"median":13259400.0,"state":{"best":[13.2588,10.8562],"population":[[-14.1222,-4.57542],[40.2274,-22.5578],[13.2588,10.8562],[-32.18,21.6694],[-8.79292,-44.2007],[18.2438,6.87475]]}}, +{"best":11383.6,"evaluations":18,"generation":2,"median":84185500.0,"state":{"best":[13.2588,10.8562],"population":[[22.6799,26.0632],[-36.9782,29.562],[5.45705,-45.916],[-33.3059,-39.0533],[-9.54399,25.1023],[46.4609,9.7435]]}}, +{"best":1.31636,"evaluations":24,"generation":3,"median":16676000.0,"state":{"best":[-1.33471,-2.29626],"population":[[-3.07042,-29.4843],[-11.5028,30.8612],[-1.33471,-2.29626],[-16.1343,14.1325],[-39.5098,43.7074],[-41.7046,31.1616]]}}, +{"best":1.31636,"evaluations":30,"generation":4,"median":88433.5,"state":{"best":[-1.33471,-2.29626],"population":[[7.38608,0.333237],[-2.96874,-25.9061],[-2.1115,-2.43541],[10.6077,-27.1072],[-15.5132,14.7015],[5.39862,14.3407]]}}, +{"best":1.17123,"evaluations":36,"generation":5,"median":263836.0,"state":{"best":[-1.0817,2.35408],"population":[[-16.3533,1.91176],[-1.0817,2.35408],[0.18722,17.7703],[-12.5789,40.2894],[-13.9627,4.09392],[-0.524085,22.8138]]}}, +{"best":1.17123,"evaluations":42,"generation":6,"median":492567.0,"state":{"best":[-1.0817,2.35408],"population":[[-14.805,-18.5007],[-7.25846,23.6295],[-12.4045,15.5385],[10.7305,17.9985],[3.58599,6.81453],[-6.57222,21.5114]]}}, +{"best":1.17123,"evaluations":48,"generation":7,"median":44.0769,"state":{"best":[-1.0817,2.35408],"population":[[7.77431,16.6472],[6.89122,7.28081],[-12.5507,9.87956],[5.81293,7.5586],[0.696931,-5.03581],[6.41275,8.34736]]}}, +{"best":0.818451,"evaluations":54,"generation":8,"median":30204.4,"state":{"best":[-1.23569,0.540886],"population":[[2.00823,24.5491],[-14.2568,14.8754],[-1.23569,0.540886],[7.64612,4.26611],[2.34257,14.9557],[0.257237,-9.48311]]}}, +{"best":0.818451,"evaluations":60,"generation":9,"median":901.377,"state":{"best":[-1.23569,0.540886],"population":[[0.787949,-2.68379],[6.68812,-0.0181386],[-12.9362,0.812135],[0.539424,-12.0426],[0.0571384,2.74452],[0.602138,22.538]]}}, +{"best":0.818451,"evaluations":66,"generation":10,"median":35.3507,"state":{"best":[-1.23569,0.540886],"population":[[6.16802,13.0286],[7.89155,2.58414],[-3.90149,9.12494],[5.34008,5.50985],[6.57162,-2.15879],[1.19874,1.14723]]}}, +{"best":0.818451,"evaluations":72,"generation":11,"median":28.1449,"state":{"best":[-1.23569,0.540886],"population":[[4.42121,2.24716],[13.7909,2.6053],[0.0877036,5.41215],[4.39039,7.71284],[1.54169,-7.68184],[3.51768,9.13157]]}}, +{"best":0.551439,"evaluations":78,"generation":12,"median":15.0167,"state":{"best":[-1.06265,1.27784],"population":[[4.22068,-0.402209],[-2.34873,-1.9678],[1.84571,2.10192],[0.158034,5.55062],[4.0323,-4.28047],[-1.06265,1.27784]]}}, +{"best":0.551439,"evaluations":84,"generation":13,"median":12.9364,"state":{"best":[-1.06265,1.27784],"population":[[-0.890509,-4.09955],[-4.01134,-0.635029],[0.471044,3.17739],[-7.08163,-1.78747],[1.82708,-0.952637],[-7.83965,0.742382]]}}, +{"best":0.551439,"evaluations":90,"generation":14,"median":16.7335,"state":{"best":[-1.06265,1.27784],"population":[[3.51615,-0.132275],[3.41747,0.919312],[-5.64338,-6.30302],[-2.00429,-5.74219],[0.481865,-3.10736],[-5.09741,-6.37769]]}}, +{"best":0.551439,"evaluations":96,"generation":15,"median":17.8231,"state":{"best":[-1.06265,1.27784],"population":[[0.427509,-9.14976],[1.71123,-5.70023],[2.13465,-1.93815],[4.88782,-1.54735],[2.43366,-6.38369],[-3.37809,-7.46935]]}}, +{"best":0.551439,"evaluations":102,"generation":16,"median":18.8729,"state":{"best":[-1.06265,1.27784],"population":[[3.77657,-2.24967],[-0.738278,-9.00176],[2.98909,-3.59049],[5.95078,-4.19748],[-0.125222,-2.36572],[6.69697,-3.07088]]}}, +{"best":0.551439,"evaluations":108,"generation":17,"median":16.6603,"state":{"best":[-1.06265,1.27784],"population":[[0.816211,-12.0293],[-2.10927,-10.7847],[-4.05462,-5.58356],[-4.52131,-4.49613],[-3.52698,-6.34834],[-1.8775,-8.26841]]}}, +{"best":0.551439,"evaluations":114,"generation":18,"median":19.4307,"state":{"best":[-1.06265,1.27784],"population":[[-3.00952,-7.87977],[-0.404033,-3.23869],[2.43291,-6.35763],[-3.02491,-11.9303],[0.00560983,-10.6149],[-2.10365,-3.56766]]}}, +{"best":0.436865,"evaluations":120,"generation":19,"median":8.0075,"state":{"best":[-0.853353,-2.46164],"population":[[-1.25594,-5.98538],[-1.97337,0.0580417],[-4.30547,-5.31643],[-2.14698,-6.10309],[-0.853353,-2.46164],[4.27314,-1.49964]]}}, +{"best":0.436865,"evaluations":126,"generation":20,"median":11.5959,"state":{"best":[-0.853353,-2.46164],"population":[[-3.00003,-3.42628],[0.464513,-3.83019],[-1.80595,-3.71364],[-1.8616,-4.96266],[-0.162714,-3.11635],[1.9622,-3.679]]}}, +{"best":0.361108,"evaluations":132,"generation":21,"median":11.2271,"state":{"best":[-0.975349,-2.90042],"population":[[-0.975349,-2.90042],[-0.964034,-3.36353],[-1.98283,-6.31919],[0.986891,-2.01974],[-2.54554,-0.997887],[0.13209,-5.08033]]}}, +{"best":0.13393,"evaluations":138,"generation":22,"median":2.41069,"state":{"best":[-0.898791,-1.57084],"population":[[-0.960296,-3.46537],[-1.07536,-4.55228],[-1.9119,-3.85625],[-1.68677,-3.48699],[-0.898791,-1.57084],[-0.452361,-3.20949]]}}, +{"best":0.13393,"evaluations":144,"generation":23,"median":9.53699,"state":{"best":[-0.898791,-1.57084],"population":[[0.274932,-1.68473],[-0.687208,-2.84155],[-1.76672,-3.27348],[-3.15891,-3.84402],[0.0656201,-0.929319],[0.062163,-3.42491]]}}, +{"best":0.13393,"evaluations":150,"generation":24,"median":1.09649,"state":{"best":[-0.898791,-1.57084],"population":[[-1.24727,-2.76274],[-0.92956,-2.73407],[-0.951181,-2.72065],[-0.740391,-3.3148],[-0.276655,-2.7229],[-0.416606,-3.73348]]}}, +{"best":0.13393,"evaluations":156,"generation":25,"median":1.70276,"state":{"best":[-0.898791,-1.57084],"population":[[-0.787815,-2.71222],[-0.416037,-1.81508],[-1.19694,-3.39196],[-0.793432,-2.33314],[-1.41753,-3.56623],[-0.310769,-1.72348]]}}, +{"best":0.13393,"evaluations":162,"generation":26,"median":0.68533,"state":{"best":[-0.898791,-1.57084],"population":[[-1.06532,-2.67942],[-0.953646,-2.16371],[-1.00389,-2.45184],[-1.29065,-2.55249],[-0.655513,-2.2325],[-1.29106,-2.3214]]}}, +{"best":0.13393,"evaluations":168,"generation":27,"median":1.58058,"state":{"best":[-0.898791,-1.57084],"population":[[-0.947866,-2.10279],[-0.389663,-1.93348],[-0.501072,-1.45934],[-0.858481,-2.57267],[-0.535221,-2.56409],[-0.750419,-2.23911]]}}, +{"best":0.13393,"evaluations":174,"generation":28,"median":0.703063,"state":{"best":[-0.898791,-1.57084],"population":[[-0.701762,-2.00374],[-0.736017,-2.00343],[-1.08953,-2.46914],[-0.773939,-1.92181],[-0.905038,-2.54646],[-0.612668,-2.2507]]}}, +{"best":0.13393,"evaluations":180,"generation":29,"median":0.575231,"state":{"best":[-0.898791,-1.57084],"population":[[-1.22149,-2.91796],[-1.04206,-2.66204],[-0.886239,-2.77351],[-0.805549,-2.04801],[-1.42283,-2.39278],[-1.18998,-2.66369]]}}, +{"best":0.13393,"evaluations":186,"generation":30,"median":0.393878,"state":{"best":[-0.898791,-1.57084],"population":[[-1.03006,-2.3859],[-0.869396,-2.23852],[-0.773684,-2.52133],[-1.15606,-2.98793],[-1.00395,-2.58832],[-0.865053,-2.64375]]}}, +{"best":0.13393,"evaluations":192,"generation":31,"median":0.272867,"state":{"best":[-0.898791,-1.57084],"population":[[-0.943698,-2.36048],[-1.11233,-2.71805],[-0.92475,-2.67749],[-0.982033,-2.42369],[-0.922787,-2.15223],[-1.13949,-2.14711]]}}, +{"best":0.13393,"evaluations":198,"generation":32,"median":0.192448,"state":{"best":[-0.898791,-1.57084],"population":[[-1.06405,-2.03129],[-0.934377,-2.29082],[-0.958067,-2.10952],[-0.882737,-2.16729],[-0.883763,-2.35915],[-0.920209,-2.06091]]}}, +{"best":0.0542694,"evaluations":204,"generation":33,"median":0.105165,"state":{"best":[-0.986313,-1.73045],"population":[[-0.986313,-1.73045],[-0.958304,-1.86989],[-1.14113,-2.29122],[-0.957658,-2.2293],[-1.04248,-2.00821],[-0.999855,-1.94531]]}}, +{"best":0.0138095,"evaluations":210,"generation":34,"median":0.126642,"state":{"best":[-1.03626,-1.09777],"population":[[-0.929771,-1.77627],[-1.03626,-1.09777],[-0.886916,-2.17926],[-1.00371,-2.2118],[-0.967411,-1.89842],[-0.778126,-1.78624]]}}, +{"best":0.0138095,"evaluations":216,"generation":35,"median":0.136723,"state":{"best":[-1.03626,-1.09777],"population":[[-0.908823,-2.44757],[-1.07779,-1.36206],[-1.07391,-2.21109],[-1.06285,-1.0404],[-1.18107,-0.7791],[-0.931817,-1.2944]]}}, +{"best":0.0138095,"evaluations":222,"generation":36,"median":0.0413639,"state":{"best":[-1.03626,-1.09777],"population":[[-0.932353,-1.24647],[-1.03947,-1.31813],[-1.058,-0.42549],[-1.07813,-0.864674],[-0.999345,-0.430459],[-0.98821,-0.640772]]}}, +{"best":0.0138095,"evaluations":228,"generation":37,"median":0.381588,"state":{"best":[-1.03626,-1.09777],"population":[[-0.943588,-0.0226494],[-1.20381,-0.831644],[-0.704237,-0.507421],[-1.07345,-0.649021],[-1.17237,-1.76923],[-0.91389,1.10451]]}}, +{"best":0.0124215,"evaluations":234,"generation":38,"median":0.219324,"state":{"best":[-1.03081,-1.17815],"population":[[-1.03081,-1.17815],[-0.757062,0.0839775],[-0.9817,-0.186046],[-1.21415,-0.95342],[-0.852266,-2.12334],[-0.942582,-0.244365]]}}, +{"best":0.0124215,"evaluations":240,"generation":39,"median":0.11662,"state":{"best":[-1.03081,-1.17815],"population":[[-1.13516,-0.531632],[-1.04066,-1.38169],[-1.01587,-1.76807],[-1.03798,0.0320957],[-0.90294,0.800555],[-1.10641,-1.17535]]}}, +{"best":0.00405971,"evaluations":246,"generation":40,"median":0.122184,"state":{"best":[-1.00809,-0.813401],"population":[[-1.28057,-1.54603],[-1.00809,-0.813401],[-1.06062,-1.73346],[-0.962131,-2.05819],[-0.98562,-2.27896],[-1.01362,-2.09501]]}}, +{"best":0.00405971,"evaluations":252,"generation":41,"median":0.0517171,"state":{"best":[-1.00809,-0.813401],"population":[[-0.969272,-1.43241],[-0.992976,-1.42512],[-0.913931,-0.819609],[-1.09318,-1.79377],[-0.954762,-0.745633],[-1.12868,-1.23744]]}}, +{"best":0.000238684,"evaluations":258,"generation":42,"median":0.0319039,"state":{"best":[-1.00098,-1.04833],"population":[[-1.01357,-1.5835],[-0.98919,-1.52811],[-0.928755,-1.01214],[-0.925763,-2.26658],[-1.00098,-1.04833],[-0.98353,-1.44412]]}}, +{"best":0.000238684,"evaluations":264,"generation":43,"median":0.0134732,"state":{"best":[-1.00098,-1.04833],"population":[[-0.959449,-0.885292],[-0.99859,-0.855199],[-1.01165,-1.24634],[-1.01157,-1.3215],[-0.968751,-1.36032],[-1.01268,-1.37619]]}}, +{"best":0.000238684,"evaluations":270,"generation":44,"median":0.00320443,"state":{"best":[-1.00098,-1.04833],"population":[[-0.986478,-1.0456],[-1.0029,-0.543402],[-1.00444,-1.20736],[-1.00145,-0.916244],[-0.993833,-1.02888],[-1.02408,-0.809168]]}}, +{"best":0.000238684,"evaluations":276,"generation":45,"median":0.00884571,"state":{"best":[-1.00098,-1.04833],"population":[[-0.988061,-1.02719],[-1.01838,-0.910528],[-0.993942,-1.29622],[-0.937198,-1.13366],[-0.97065,-0.946176],[-0.970171,-0.804149]]}}, +{"best":0.000238684,"evaluations":282,"generation":46,"median":0.00427984,"state":{"best":[-1.00098,-1.04833],"population":[[-1.0285,-0.81619],[-0.988238,-0.894007],[-0.985278,-0.96868],[-1.01052,-1.24906],[-0.992903,-0.928645],[-0.984929,-0.801374]]}}, +{"best":4.44668e-05,"evaluations":288,"generation":47,"median":0.00340865,"state":{"best":[-1.002,-1.00723],"population":[[-1.01994,-0.916362],[-1.00733,-1.04168],[-0.982191,-0.816961],[-0.973986,-0.903296],[-0.985305,-1.03576],[-1.002,-1.00723]]}}, +{"best":4.44668e-05,"evaluations":294,"generation":48,"median":0.00277815,"state":{"best":[-1.002,-1.00723],"population":[[-1.00326,-1.14622],[-0.988496,-0.90706],[-1.0037,-1.04907],[-1.01465,-1.11283],[-1.00122,-1.19035],[-0.982878,-1.10585]]}}, +{"best":4.44668e-05,"evaluations":300,"generation":49,"median":0.00114551,"state":{"best":[-1.002,-1.00723],"population":[[-0.99016,-1.11821],[-0.996634,-0.944725],[-1.01288,-0.962562],[-1.00643,-1.14106],[-1.00076,-1.03223],[-0.994894,-0.947147]]}}, +{"best":2.01048e-05,"evaluations":306,"generation":50,"median":0.000235025,"state":{"best":[-1.00096,-0.989356],"population":[[-0.993569,-0.946594],[-1.00096,-0.989356],[-1.00413,-0.962598],[-0.995933,-1.06515],[-1.00209,-0.974611],[-1.00264,-0.9685]]}}, +{"best":2.01048e-05,"evaluations":312,"generation":51,"median":0.000390893,"state":{"best":[-1.00096,-0.989356],"population":[[-1.00245,-1.01493],[-1.00607,-0.981025],[-1.00257,-0.942392],[-0.993844,-0.985676],[-1.00738,-1.0073],[-1.00111,-0.938589]]}}, +{"best":1.88766e-07,"evaluations":318,"generation":52,"median":8.32967e-05,"state":{"best":[-1.00003,-0.998648],"population":[[-1.00003,-0.998648],[-1.00855,-0.982911],[-1.00875,-1.03124],[-1.00085,-1.00116],[-0.998425,-1.01727],[-0.997888,-1.02659]]}}, +{"best":1.88766e-07,"evaluations":324,"generation":53,"median":0.00012521,"state":{"best":[-1.00003,-0.998648],"population":[[-1.00197,-0.995094],[-1.00128,-1.00942],[-1.00004,-1.0404],[-0.999854,-0.969723],[-0.995984,-0.991049],[-1.00572,-1.05293]]}}, +{"best":1.88766e-07,"evaluations":330,"generation":54,"median":5.35057e-05,"state":{"best":[-1.00003,-0.998648],"population":[[-0.998627,-0.998493],[-0.998829,-0.9973],[-1.00374,-1.03028],[-1.00532,-0.993785],[-1.00241,-1.0068],[-1.00181,-1.01168]]}}, +{"best":1.88766e-07,"evaluations":336,"generation":55,"median":0.000137978,"state":{"best":[-1.00003,-0.998648],"population":[[-1.00361,-1.01987],[-0.999514,-0.96484],[-0.996119,-1.00702],[-0.997753,-0.990433],[-0.995678,-1.02416],[-1.001,-1.01251]]}}, +{"best":1.88766e-07,"evaluations":342,"generation":56,"median":1.56013e-05,"state":{"best":[-1.00003,-0.998648],"population":[[-0.999014,-0.993746],[-1.00282,-1.00647],[-1.00235,-0.998452],[-1.00079,-0.998338],[-0.998919,-0.991917],[-1.00023,-1.00771]]}}, +{"best":1.88766e-07,"evaluations":348,"generation":57,"median":8.35912e-06,"state":{"best":[-1.00003,-0.998648],"population":[[-1.00049,-1.00428],[-1.0007,-0.993437],[-0.999997,-0.993695],[-0.999261,-1.00496],[-0.99771,-0.988037],[-1.00109,-1.00723]]}}, +{"best":1.88766e-07,"evaluations":354,"generation":58,"median":8.65294e-06,"state":{"best":[-1.00003,-0.998648],"population":[[-1.00048,-0.997159],[-1.00005,-0.993142],[-1.00104,-0.996686],[-1.00223,-1.00566],[-1.0006,-1.00474],[-1.00139,-1.00208]]}}, +{"best":1.88766e-07,"evaluations":360,"generation":59,"median":5.88528e-06,"state":{"best":[-1.00003,-0.998648],"population":[[-0.999964,-0.992121],[-1.0015,-0.998754],[-0.999137,-0.994575],[-0.999704,-0.993004],[-0.999448,-1.00114],[-1.00022,-1.0]]}}, +{"best":1.88766e-07,"evaluations":366,"generation":60,"median":3.6327e-06,"state":{"best":[-1.00003,-0.998648],"population":[[-1.00017,-1.00002],[-1.0005,-0.994758],[-0.999365,-1.00472],[-1.0003,-0.991151],[-0.999924,-1.00463],[-0.999587,-1.00033]]}}, +{"best":1.88766e-07,"evaluations":372,"generation":61,"median":8.59624e-06,"state":{"best":[-1.00003,-0.998648],"population":[[-1.00088,-1.00378],[-0.998988,-0.999033],[-1.00078,-0.995214],[-1.00044,-0.995451],[-1.00027,-0.997537],[-1.00125,-1.00245]]}}, +{"best":1.88766e-07,"evaluations":378,"generation":62,"median":1.01115e-05,"state":{"best":[-1.00003,-0.998648],"population":[[-0.99995,-0.996934],[-1.0004,-0.991114],[-1.00089,-0.992505],[-1.00074,-0.992172],[-1.00055,-0.991042],[-0.999403,-0.99857]]}}, +{"best":1.88766e-07,"evaluations":384,"generation":63,"median":1.96551e-06,"state":{"best":[-1.00003,-0.998648],"population":[[-0.999506,-0.995916],[-1.00005,-0.986916],[-1.00012,-0.99645],[-0.999791,-0.998674],[-1.00009,-1.00171],[-0.999519,-0.998274]]}}, +{"best":5.75858e-08,"evaluations":390,"generation":64,"median":8.49651e-07,"state":{"best":[-1.00003,-1.00069],"population":[[-1.00022,-0.997535],[-0.999796,-0.99552],[-1.00003,-1.00069],[-0.999873,-0.999586],[-1.00003,-0.996736],[-0.999749,-0.999448]]}}, +{"best":1.76566e-08,"evaluations":396,"generation":65,"median":9.30743e-07,"state":{"best":[-0.999958,-0.999943],"population":[[-0.999958,-0.999943],[-1.00019,-1.00261],[-0.999996,-1.0037],[-0.999728,-0.99894],[-0.999796,-0.999127],[-1.0007,-0.998917]]}}, +{"best":1.76566e-08,"evaluations":402,"generation":66,"median":1.98224e-07,"state":{"best":[-0.999958,-0.999943],"population":[[-1.00012,-0.997037],[-0.999852,-1.00006],[-1.00006,-1.00047],[-1.00015,-0.999039],[-0.999992,-0.999241],[-1.00012,-1.00066]]}}, +{"best":1.76566e-08,"evaluations":408,"generation":67,"median":8.57725e-07,"state":{"best":[-0.999958,-0.999943],"population":[[-1.00019,-0.997201],[-1.00023,-1.00092],[-1.00034,-1.00372],[-1.0001,-0.999601],[-1.00012,-1.00012],[-1.00032,-1.00187]]}}, +{"best":1.76566e-08,"evaluations":414,"generation":68,"median":3.65173e-07,"state":{"best":[-0.999958,-0.999943],"population":[[-1.0001,-0.998994],[-1.00008,-0.999879],[-0.99981,-0.998318],[-0.999917,-1.00098],[-1.00025,-1.00148],[-1.00022,-1.00071]]}}, +{"best":1.76566e-08,"evaluations":420,"generation":69,"median":2.92917e-07,"state":{"best":[-0.999958,-0.999943],"population":[[-1.00009,-1.00079],[-0.999815,-1.00175],[-0.999893,-0.999631],[-1.00016,-0.998335],[-1.0001,-0.999703],[-1.00021,-0.999675]]}}, +{"best":1.87396e-10,"evaluations":426,"generation":70,"median":5.90683e-08,"state":{"best":[-1.0,-0.999957],"population":[[-1.00002,-0.998792],[-1.00003,-0.99924],[-0.999962,-0.999364],[-1.00007,-0.999249],[-1.00003,-0.999848],[-1.0,-0.999957]]}} +]} diff --git a/examples/penalized1/trace.py b/examples/penalized1/trace.py new file mode 100644 index 00000000..c727bb02 --- /dev/null +++ b/examples/penalized1/trace.py @@ -0,0 +1,189 @@ +"""The trace for the plot on the example's page, written to the file that ``GENOXIDE_TRACE`` +names. The plot draws the population on the function's contour, which needs two dimensions: the +trace is of a separate run of CMA-ES with IPOP restarts in 2 dimensions, with a budget of +20,000 evaluations, in at most 100 frames. The Rust example writes the same file.""" + +import json +import math +import os + +import genoxide as gx + + +def record_small(): + """Runs CMA-ES with IPOP restarts in 2 dimensions and writes its trace, if ``GENOXIDE_TRACE`` is set.""" + path = os.environ.get("GENOXIDE_TRACE") + if not path: + return + problem = gx.problems.Penalized1(2) + minimum = problem.optimum.value + budget = 20_000 + cmaes = gx.Cmaes(problem.genome, restarts="ipop", objective="minimize", seed=1) + frames = Frames(100) + + def record(progress): + state = {"population": progress.population.tolist(), "best": progress.best_genome.tolist()} + frames.push(frame(progress, state, minimum)) + + cmaes.run(problem, target=minimum + 1e-8, evaluations=budget, on_generation=record) + low, high = problem.genome.bounds + settings = { + "format": 1, + "example": "penalized1", + "objective": "minimize", + "x_label": "evaluations", + "y_label": "error", + "log_y": True, + "optimum": 0.0, + "plot": "contour", + "problem": { + "function": "penalized1", + "bounds": [[float(low), float(high)]] * 2, + "minima": problem.optimum.solutions.tolist(), + }, + } + write(path, settings, frames.to_list()) + + +def frame(progress, state, minimum): + """The frame of a generation: its progress, the errors of its best and of its population's + median to ``minimum`` (rounding can put a solution a few ulps below it), and ``state``.""" + + def error(value): + return None if value is None else max(value - minimum, 0.0) + + return { + "generation": progress.generation, + "evaluations": progress.evaluations, + "best": error(progress.best_fitness), + "median": error(median(progress.scores)), + "state": state, + } + + +def median(scores): + """The median of the valid scores, None without any.""" + scores = sorted(float(score) for score in scores if not math.isnan(score)) + middle = len(scores) // 2 + if not scores: + return None + return scores[middle] if len(scores) % 2 else (scores[middle - 1] + scores[middle]) / 2 + + +# ---- the same in every example's trace ---------------------------------------------------------- + + +class Frames: + """The frames of at most ``most`` generations, from the part of the run where what the page + plots changes: the frames after the last change are left out (a run that reached its target, + or a front that no longer moves), and the rest are spread evenly over the generations up to + it. While the run goes, up to 8 × ``most`` frames are kept: every ``every``-th generation, + with ``every`` doubling whenever there are that many, and the last one.""" + + def __init__(self, most): + self.most, self.every, self.kept, self.last = most, 1, [], None + + def push(self, frame): + if frame["generation"] % self.every: + self.last = frame + return + self.kept.append(frame) + self.last = None + if len(self.kept) == 8 * self.most: + self.every *= 2 + self.kept = [kept for kept in self.kept if kept["generation"] % self.every == 0] + + def to_list(self): + frames = self.kept + ([self.last] if self.last else []) + active = frames[: last_change(frames) + 1] + count, most = len(active), max(self.most, 2) + if count <= most: + return active + return [active[(i * (count - 1) + (most - 1) // 2) // (most - 1)] for i in range(most)] + + +def last_change(frames): + """The index of the frame after which nothing the page plots changes. To 3 significant + digits, as a plot shows them: the best, the median and, for a single objective (a numeric + best), the state; to within a hundredth of their range over the run: a front's + hypervolumes, in the state or in a grid's series.""" + if not frames: + return 0 + last = len(frames) - 1 + number = lambda value: isinstance(value, (int, float)) and not isinstance(value, bool) + single = any(number(frame.get("best")) for frame in frames) + + def measures(frame): + values = [] + state = frame.get("state") + hypervolume = state.get("hypervolume") if isinstance(state, dict) else None + for value in (hypervolume, frame.get("series")): + if number(value): + values.append(float(value)) + elif isinstance(value, dict): + values.extend(float(v) for _, v in sorted(value.items()) if number(v)) + return values + + measured = [measures(frame) for frame in frames] + end = measured[last] + tolerance = [] + for k in range(len(end)): + values = [values[k] for values in measured if k < len(values)] + tolerance.append((max(values) - min(values)) / 100.0) + + def same(frame, final, key, flush=False): + return coarse(frame.get(key), flush) == coarse(final.get(key), flush) + + def settled(i): + frame, final = frames[i], frames[last] + return ( + same(frame, final, "best") + and same(frame, final, "median") + and (not single or same(frame, final, "state", flush=True)) + and len(measured[i]) == len(end) + and all(abs(v - e) <= t for v, e, t in zip(measured[i], end, tolerance)) + ) + + first = last + while first > 0 and settled(first - 1): + first -= 1 + return first + + +def coarse(value, flush=False): + """``value`` with its numbers to 3 significant digits, as precisely as a plot shows them: two + frames whose plotted values agree to that precision look the same. With ``flush``, for the + solutions a plot draws on their ranges, numbers below 1e-6 in size count as 0.""" + if isinstance(value, float): + if flush and abs(value) < 1e-6: + value = 0.0 + return f"{value:.2e}" + if isinstance(value, (list, tuple)): + return "[" + ",".join(coarse(item, flush) for item in value) + "]" + if isinstance(value, dict): + items = sorted(value.items()) + return "{" + ",".join(f"{key}:{coarse(item, flush)}" for key, item in items) + "}" + return json.dumps(value) + + +def write(path, settings, frames): + """Writes the settings and the frames to ``path``, a frame per line.""" + lines = ",\n".join(map(to_json, frames)) + with open(path, "w", encoding="utf-8", newline="\n") as file: + file.write(f'{to_json(settings)[:-1]},"frames":[\n{lines}\n]}}\n') + + +def to_json(value): + """Compact JSON with sorted keys, and numbers rounded to 6 significant digits, as the Rust + example writes it.""" + return json.dumps(rounded(value), sort_keys=True, separators=(",", ":"), ensure_ascii=False) + + +def rounded(value): + if isinstance(value, dict): + return {key: rounded(item) for key, item in value.items()} + if isinstance(value, (list, tuple)): + return [rounded(item) for item in value] + if isinstance(value, float): + return float(f"{value:.5e}") if math.isfinite(value) else None + return value diff --git a/examples/penalized1/trace.rs b/examples/penalized1/trace.rs new file mode 100644 index 00000000..49f36764 --- /dev/null +++ b/examples/penalized1/trace.rs @@ -0,0 +1,261 @@ +//! The trace for the plot on the example's page, written to the file that `GENOXIDE_TRACE` names. +//! The plot draws the population on the function's contour, which needs two dimensions: the trace +//! is of a separate run of CMA-ES with IPOP restarts in 2 dimensions, with a budget of +//! 20,000 evaluations, in at most 100 frames. The Python example writes the same +//! file. + +use genoxide::observer::Snapshot; +use genoxide::prelude::*; +use genoxide::problems::{Penalized1, Problem}; +use serde_json::{Value, json}; + +// runs CMA-ES with IPOP restarts in 2 dimensions and writes its trace, if GENOXIDE_TRACE is set +pub fn record_small() -> Result<()> { + let Ok(path) = std::env::var("GENOXIDE_TRACE") else { + return Ok(()); + }; + let problem = Penalized1::new(2); + let optimum = problem.optimum().expect("known"); + let minimum = optimum.value(); + let budget = 20_000; + let cmaes = Cmaes::builder(problem.representation()) + .restarts(cmaes::Restarts::Ipop) + .minimize() + .seed(1) + .build()?; + let mut frames = Frames::new(100); + Engine::new(cmaes, problem.clone()) + .stop_when(Stop::target(minimum + 1e-8).or(Stop::evaluations(budget))) + .on_generation(|snapshot| { + let population = snapshot.population().iter().map(|x| &x.genome()[..]); + let population: Vec<&[f64]> = population.collect(); + let best = &snapshot.best().genome()[..]; + let state = json!({ "population": population, "best": best }); + frames.push(frame(snapshot, state, minimum)); + }) + .run()?; + let bounds = problem.representation().bounds().to_vec(); + let bounds: Vec<[f64; 2]> = bounds.iter().map(|b| [*b.start(), *b.end()]).collect(); + let minima: Vec<&[f64]> = optimum.solutions().iter().map(|x| &x[..]).collect(); + let settings = json!({ + "format": 1, + "example": "penalized1", + "objective": "minimize", + "x_label": "evaluations", + "y_label": "error", + "log_y": true, + "optimum": 0.0, + "plot": "contour", + "problem": { + "function": "penalized1", + "bounds": bounds, + "minima": minima, + }, + }); + write(&path, settings, frames.into_vec()); + Ok(()) +} + +// the frame of a generation: its progress, the errors of its best and of its population's median +// to `minimum` (rounding can put a solution a few ulps below it), and `state` +fn frame(snapshot: &Snapshot<'_, Reals>, state: Value, minimum: f64) -> Value { + let progress = snapshot.progress(); + let error = |value: f64| (value - minimum).max(0.0); + let population = snapshot.population().iter(); + let scores = population.filter_map(|individual| individual.fitness()?.score()); + json!({ + "generation": progress.generation(), + "evaluations": progress.evaluations(), + "best": progress.best().and_then(Fitness::score).map(error), + "median": median(scores.collect()).map(error), + "state": state, + }) +} + +// the median of the scores, None without any +fn median(mut scores: Vec) -> Option { + scores.sort_by(f64::total_cmp); + let middle = scores.len() / 2; + match scores.len() { + 0 => None, + n if n % 2 == 1 => Some(scores[middle]), + _ => Some((scores[middle - 1] + scores[middle]) / 2.0), + } +} + +// ---- the same in every example's trace --------------------------------------------------------- + +// the frames of at most `most` generations, from the part of the run where what the page plots +// changes: the frames after the last change are left out (a run that reached its target, or a +// front that no longer moves), and the rest are spread evenly over the generations up to it. While +// the run goes, up to 8 × `most` frames are kept: every `every`-th generation, with `every` +// doubling whenever there are that many, and the last one. +struct Frames { + most: usize, + every: u64, + kept: Vec<(u64, Value)>, + last: Option<(u64, Value)>, +} + +impl Frames { + fn new(most: usize) -> Self { + let (every, kept, last) = (1, Vec::new(), None); + Self { + most, + every, + kept, + last, + } + } + + fn push(&mut self, frame: Value) { + let generation = frame["generation"].as_u64().expect("a generation"); + if !generation.is_multiple_of(self.every) { + self.last = Some((generation, frame)); + return; + } + self.kept.push((generation, frame)); + self.last = None; + if self.kept.len() == 8 * self.most { + self.every *= 2; + let every = self.every; + self.kept.retain(|(generation, _)| generation % every == 0); + } + } + + fn into_vec(self) -> Vec { + let frames = self.kept.into_iter().chain(self.last); + let frames: Vec = frames.map(|(_, frame)| frame).collect(); + let active = &frames[..=last_change(&frames)]; + let (count, most) = (active.len(), self.most.max(2)); + if count <= most { + return active.to_vec(); + } + let at = |i: usize| active[(i * (count - 1) + (most - 1) / 2) / (most - 1)].clone(); + (0..most).map(at).collect() + } +} + +// the index of the frame after which nothing the page plots changes. To 3 significant digits, as +// a plot shows them: the best, the median and, for a single objective (a numeric best), the state; +// to within a hundredth of their range over the run: a front's hypervolumes, in the state or in a +// grid's series +fn last_change(frames: &[Value]) -> usize { + let Some(last) = frames.len().checked_sub(1) else { + return 0; + }; + let single = frames.iter().any(|frame| frame["best"].is_number()); + let measures = |frame: &Value| -> Vec { + let mut values = Vec::new(); + for value in [&frame["state"]["hypervolume"], &frame["series"]] { + match value { + Value::Number(number) => values.extend(number.as_f64()), + Value::Object(map) => values.extend(map.values().filter_map(Value::as_f64)), + _ => {} + } + } + values + }; + let measured: Vec> = frames.iter().map(measures).collect(); + let end = &measured[last]; + let tolerance: Vec = (0..end.len()) + .map(|k| { + let values = measured.iter().filter_map(|values| values.get(k).copied()); + let (low, high) = values.fold((f64::INFINITY, f64::NEG_INFINITY), |(low, high), v| { + (low.min(v), high.max(v)) + }); + (high - low) / 100.0 + }) + .collect(); + let settled = |i: usize| { + let (frame, final_frame) = (&frames[i], &frames[last]); + let same = + |key: &str, flush: bool| coarse(&frame[key], flush) == coarse(&final_frame[key], flush); + same("best", false) + && same("median", false) + && (!single || same("state", true)) + && measured[i].len() == end.len() + && measured[i] + .iter() + .zip(end) + .zip(&tolerance) + .all(|((value, end), tolerance)| (value - end).abs() <= *tolerance) + }; + let mut first = last; + while first > 0 && settled(first - 1) { + first -= 1; + } + first +} + +// `value` with its numbers to 3 significant digits, as precisely as a plot shows them: two frames +// whose plotted values agree to that precision look the same. With `flush`, for the solutions a +// plot draws on their ranges, numbers below 1e-6 in size count as 0 +fn coarse(value: &Value, flush: bool) -> String { + let join = |items: Vec| items.join(","); + match value { + Value::Number(number) if number.is_f64() => { + let number = number.as_f64().expect("f64"); + let number = if flush && number.abs() < 1e-6 { + 0.0 + } else { + number + }; + format!("{number:.2e}") + } + Value::Array(items) => { + format!( + "[{}]", + join(items.iter().map(|item| coarse(item, flush)).collect()) + ) + } + Value::Object(map) => { + let entry = |(key, item): (&String, &Value)| format!("{key}:{}", coarse(item, flush)); + format!("{{{}}}", join(map.iter().map(entry).collect())) + } + other => other.to_string(), + } +} + +// writes the settings and the frames to `path`, a frame per line +fn write(path: &str, settings: Value, frames: Vec) { + let frames: Vec = frames.iter().map(to_json).collect(); + let settings = to_json(&settings); + let head = &settings[..settings.len() - 1]; + let text = format!("{head},\"frames\":[\n{}\n]}}\n", frames.join(",\n")); + std::fs::write(path, text).expect("the trace is written"); +} + +// compact JSON with sorted keys, and numbers rounded to 6 significant digits and written as +// Python writes them (7542.0, 1e-08): the Python example writes the same file +fn to_json(value: &Value) -> String { + let join = |items: Vec| items.join(","); + match value { + Value::Number(number) if number.is_f64() => python_float(number.as_f64().expect("f64")), + Value::Array(items) => format!("[{}]", join(items.iter().map(to_json).collect())), + Value::Object(map) => { + let entry = + |(key, item): (&String, &Value)| format!("{}:{}", json!(key), to_json(item)); + format!("{{{}}}", join(map.iter().map(entry).collect())) + } + other => other.to_string(), + } +} + +fn python_float(value: f64) -> String { + let rounded: f64 = format!("{value:.5e}").parse().expect("a number"); + let shortest = format!("{rounded:e}"); + let (mantissa, exponent) = shortest.split_once('e').expect("an exponent"); + let exponent: i32 = exponent.parse().expect("an exponent"); + if (-4..16).contains(&exponent) { + let text = rounded.to_string(); + if text.contains('.') { + text + } else { + text + ".0" + } + } else { + let sign = if exponent < 0 { '-' } else { '+' }; + format!("{mantissa}e{sign}{:02}", exponent.abs()) + } +} diff --git a/examples/penalized2/README.md b/examples/penalized2/README.md new file mode 100644 index 00000000..542a3e76 --- /dev/null +++ b/examples/penalized2/README.md @@ -0,0 +1,81 @@ +--- +title: Penalized 2 +category: continuous +summary: Minimize Yao, Liu and Lin's second penalized function in 30 dimensions, with CMA-ES without and with restarts, DE, PSO and a GA from 10 seeds each. +reference: "Yao, X., Liu, Y. and Lin, G. (1999). Evolutionary programming made faster. IEEE Transactions on Evolutionary Computation 3(2): 82-102." +reference_url: "https://doi.org/10.1109/4235.771163" +optimum: "0 (at (1, …, 1))" +languages: [rust, python] +order: 92 +family: Penalized +tab: Penalized 2 +trace_note: "Recorded from another run: CMA-ES with IPOP restarts in 2 dimensions, so that the population can be drawn on the function's contour." +--- + +# Penalized 2 + +## The problem + +Yao, Liu and Lin's second generalized penalized function has sines of three times the genes, and a +penalty beyond ±5: + +```text +f(x) = 0.1 {sin²(3πx₁) + Σᵢ₌₁ⁿ⁻¹ (xᵢ − 1)² [1 + sin²(3πxᵢ₊₁)] + (xₙ − 1)² [1 + sin²(2πxₙ)]} + + Σ u(xᵢ, 5, 100, 4), each xᵢ in [−50, 50] +u(x, a, k, m) = k (|x| − a)^m if |x| > a, and 0 otherwise +``` + +Its minimum is 0, at (1, …, 1), where every term is 0. Here n = 30. It's Yao, Liu and Lin's (1999) +f13, whose appendix gives this definition, the bounds and the dimension; their table I drops the +square of the last term's (xₙ − 1), without which the function would have no minimum there. The +function is usually credited to Levy and Montalvo's tunneling papers (1985), which weren't read. + +## What makes it hard + +The sines put a local minimum near every point where their arguments are whole multiples of π: +a grid of shallow wells over the box, the more of them the more genes. The wells' depth scales with +the squares in front of the sines, so they are shallower the nearer the minimum, and the squares +lead towards it. The penalty u is 0 inside [−10, 10] (Penalized 1) or [−5, 5] (Penalized 2), and rises as a +fourth power outside: a wall that keeps the search away from the bounds of [−50, 50]. + +## Representation + +A `Real` genome of 30 genes, each in [−50, 50]: the point x itself. The fitness is f(x), to +minimize. The function is genoxide's `problems::Penalized2`, which brings its bounds and its minimum. + +## Algorithm + +Five algorithms, each from seeds 1 to 10, with a budget of 10,000 evaluations per dimension, +300,000 per run, and a target of 1e-8: + +- CMA-ES (Hansen and Ostermeier, 2001, Evolutionary Computation 9(2): 159-195), which samples a + population of 14 from a normal distribution and adapts its mean, its step size and its covariance + matrix, from a step size of 0.3 of each gene's range and a random start; +- the same with IPOP restarts (Auger and Hansen, 2005, IEEE CEC 2005: 1769-1776): a run that has + converged starts again from a random point with twice the population; +- differential evolution with genoxide's defaults, SHADE (Tanabe and Fukunaga, CEC 2013), with a + population of 100 and its restarts on stagnation; +- particle swarm optimization (Kennedy and Eberhart, 1995), 40 particles with Clerc and Kennedy's + constriction coefficients and a global topology; +- a real-coded genetic algorithm: a population of 100, tournaments of 3, simulated binary crossover + (Deb and Agrawal, 1995) with η = 15 and polynomial mutation with η = 20 at a rate of 1/30 per + gene. + +## Output + +The first line gives the dimension, the seeds and the budget. Then a row per algorithm: how many +of its 10 runs reached the minimum, to within 1e-8, the median of their evaluations (a dash if none +did), and the median of every run's best error, to two significant digits. The function is +evaluated with genoxide's portable math, so the runs are the same on every platform, and in Python, +`run` evaluates it in Rust, so both versions print the same. + +[The project page](https://tachsin.gr/projects/genoxide/examples/penalized2) plays back another run: +CMA-ES with IPOP restarts on the function in 2 dimensions, so that the population +can be drawn on its contour. It meets the target after 396 evaluations. + +## Good results + +The minimum is 0. CMA-ES with IPOP restarts reaches it in all 10 runs, after a median of 6,776 +evaluations, and without restarts in 9 of 10, after 6,762. SHADE reaches it every time, after +30,250, and PSO 7 times, after 26,840. The genetic algorithm never does: its median run ends at +1.1e-5. diff --git a/examples/penalized2/main.py b/examples/penalized2/main.py new file mode 100644 index 00000000..bcfda828 --- /dev/null +++ b/examples/penalized2/main.py @@ -0,0 +1,85 @@ +"""Penalized 2: minimize Yao, Liu and Lin's second penalized function in 30 dimensions. + +Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), +differential evolution (SHADE), particle swarm optimization and a real-coded genetic algorithm from +10 seeds each, and counts the runs that reach the minimum, 0 at (1, …, 1), to within 1e-8. The +function is genoxide's `problems::Penalized2`, which run evaluates in Rust. + +With ``GENOXIDE_TRACE=``, it also writes a trace of a run for the plot on the example's page, +with trace.py. + + python examples/penalized2/main.py +""" + +import genoxide as gx + +from trace import record_small + +DIMENSIONS = 30 +SEEDS = 10 +BUDGET = 10_000 * DIMENSIONS +# a run stops once its error to the minimum is at most this +ERROR = 1e-8 +ALGORITHMS = ["CMA-ES", "CMA-ES with IPOP", "DE", "PSO", "GA"] + + +def build(name, genome, seed): + """The algorithm called ``name``, on ``genome``, from ``seed``.""" + if name == "CMA-ES": + return gx.Cmaes(genome, objective="minimize", seed=seed) + if name == "CMA-ES with IPOP": + return gx.Cmaes(genome, restarts="ipop", objective="minimize", seed=seed) + if name == "DE": + return gx.De(genome, objective="minimize", seed=seed) + if name == "PSO": + return gx.Pso(genome, population_size=40, objective="minimize", seed=seed) + return gx.Ga( + genome, + population_size=100, + select=gx.Tournament(3), + crossover=gx.SimulatedBinaryCrossover(15.0), + mutation=gx.PolynomialMutation(20.0, rate=1 / DIMENSIONS), + objective="minimize", + seed=seed, + ) + + +def median(values): + """The median of ``values``, None without any.""" + values = sorted(values) + middle = len(values) // 2 + if not values: + return None + return values[middle] if len(values) % 2 else (values[middle - 1] + values[middle]) / 2 + + +def error_text(error): + """An error to two significant digits, as Rust writes it: 9.9e-9.""" + mantissa, exponent = f"{error:.1e}".split("e") + return f"{mantissa}e{int(exponent)}" + + +problem = gx.problems.Penalized2(DIMENSIONS) +minimum = problem.optimum.value +print(f"Penalized 2 in {DIMENSIONS} dimensions, {SEEDS} seeds, {BUDGET} evaluations at most per run") +print("algorithm at min evaluations median error") +for name in ALGORITHMS: + # the evaluations of the runs that reach the minimum, and every run's best error + evaluations, errors = [], [] + for seed in range(1, SEEDS + 1): + result = build(name, problem.genome, seed).run( + problem, target=minimum + ERROR, evaluations=BUDGET + ) + if result.stop_reason == "target": + evaluations.append(float(result.evaluations)) + # rounding can put a solution a few ulps below the minimum + errors.append(max(result.best_fitness - minimum, 0.0)) + reached = f"{len(evaluations)}/{SEEDS}" + middle = median(evaluations) + evaluations_text = "-" if middle is None else f"{middle:.0f}" + print(f"{name:<16} {reached:>6} {evaluations_text:>11} {error_text(median(errors)):>12}") +print("evaluations: the median of the runs that reach the minimum") + +# with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate run in +# 2 dimensions: the plot is the function's contour +record_small() diff --git a/examples/penalized2/main.rs b/examples/penalized2/main.rs new file mode 100644 index 00000000..f92de3a5 --- /dev/null +++ b/examples/penalized2/main.rs @@ -0,0 +1,117 @@ +//! Penalized 2: minimize Yao, Liu and Lin's second penalized function in 30 dimensions. +//! +//! Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), +//! differential evolution (SHADE), particle swarm optimization and a real-coded genetic algorithm +//! from 10 seeds each, and counts the runs that reach the minimum, 0 at (1, …, 1), to within +//! 1e-8. The function is genoxide's `problems::Penalized2`. +//! +//! With `GENOXIDE_TRACE=`, it also writes a trace of a run for the plot on the example's +//! page, with `trace.rs`. +//! +//! ```text +//! cargo run --release --example penalized2 +//! ``` + +mod trace; + +use genoxide::prelude::*; +use genoxide::problems::{Penalized2, Problem}; + +const DIMENSIONS: usize = 30; +const SEEDS: u64 = 10; +const BUDGET: u64 = 10_000 * DIMENSIONS as u64; +// a run stops once its error to the minimum is at most this +const ERROR: f64 = 1e-8; +const ALGORITHMS: [&str; 5] = ["CMA-ES", "CMA-ES with IPOP", "DE", "PSO", "GA"]; + +fn main() -> Result<()> { + let problem = Penalized2::new(DIMENSIONS); + let minimum = problem.optimum().expect("known").value(); + println!( + "Penalized 2 in {DIMENSIONS} dimensions, {SEEDS} seeds, {BUDGET} evaluations at most per run" + ); + println!("algorithm at min evaluations median error"); + for algorithm in ALGORITHMS { + // the evaluations of the runs that reach the minimum, and every run's best error + let mut evaluations = Vec::new(); + let mut errors = Vec::new(); + for seed in 1..=SEEDS { + let outcome = run(algorithm, problem, seed, minimum + ERROR)?; + if outcome.stop_reason() == StopReason::Target { + evaluations.push(outcome.evaluations() as f64); + } + // rounding can put a solution a few ulps below the minimum + let best = outcome.best_fitness().score().expect("valid"); + errors.push((best - minimum).max(0.0)); + } + let reached = format!("{}/{SEEDS}", evaluations.len()); + let evaluations = median(evaluations).map_or("-".to_string(), |e| format!("{e:.0}")); + let error = median(errors).expect("a run"); + println!( + "{algorithm:<16} {reached:>6} {evaluations:>11} {:>12}", + format!("{error:.1e}") + ); + } + println!("evaluations: the median of the runs that reach the minimum"); + + // with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate + // run in 2 dimensions: the plot is the function's contour + trace::record_small()?; + Ok(()) +} + +// a run of `algorithm` from `seed`, until its best is at most `target` or it has used BUDGET +// evaluations +fn run(algorithm: &str, problem: Penalized2, seed: u64, target: f64) -> Result> { + let real = problem.representation(); + let stop = Stop::target(target).or(Stop::evaluations(BUDGET)); + match algorithm { + "CMA-ES" | "CMA-ES with IPOP" => { + let restarts = if algorithm == "CMA-ES" { + cmaes::Restarts::Never + } else { + cmaes::Restarts::Ipop + }; + let cmaes = Cmaes::builder(real) + .restarts(restarts) + .minimize() + .seed(seed) + .build()?; + Engine::new(cmaes, problem).stop_when(stop).run() + } + "DE" => { + let de = De::builder(real).minimize().seed(seed).build()?; + Engine::new(de, problem).stop_when(stop).run() + } + "PSO" => { + let pso = Pso::builder(real) + .population_size(40) + .minimize() + .seed(seed) + .build()?; + Engine::new(pso, problem).stop_when(stop).run() + } + _ => { + let ga = Ga::builder(real) + .population_size(100) + .select(Tournament::new(3)?) + .crossover(SimulatedBinaryCrossover::new(15.0)?) + .mutate(PolynomialMutation::per_gene(1.0 / DIMENSIONS as f64, 20.0)?) + .minimize() + .seed(seed) + .build()?; + Engine::new(ga, problem).stop_when(stop).run() + } + } +} + +// the median of `values`, None without any +fn median(mut values: Vec) -> Option { + values.sort_by(f64::total_cmp); + let middle = values.len() / 2; + match values.len() { + 0 => None, + n if n % 2 == 1 => Some(values[middle]), + _ => Some((values[middle - 1] + values[middle]) / 2.0), + } +} diff --git a/examples/penalized2/output.txt b/examples/penalized2/output.txt new file mode 100644 index 00000000..6c13f9b1 --- /dev/null +++ b/examples/penalized2/output.txt @@ -0,0 +1,8 @@ +Penalized 2 in 30 dimensions, 10 seeds, 300000 evaluations at most per run +algorithm at min evaluations median error +CMA-ES 9/10 6762 9.0e-9 +CMA-ES with IPOP 10/10 6776 8.8e-9 +DE 10/10 30250 9.4e-9 +PSO 7/10 26840 9.8e-9 +GA 0/10 - 1.1e-5 +evaluations: the median of the runs that reach the minimum diff --git a/examples/penalized2/trace.json b/examples/penalized2/trace.json new file mode 100644 index 00000000..90cb0b64 --- /dev/null +++ b/examples/penalized2/trace.json @@ -0,0 +1,68 @@ +{"example":"penalized2","format":1,"log_y":true,"objective":"minimize","optimum":0.0,"plot":"contour","problem":{"bounds":[[-50.0,50.0],[-50.0,50.0]],"function":"penalized2","minima":[[1.0,1.0]]},"x_label":"evaluations","y_label":"error","frames":[ +{"best":8066610.0,"evaluations":6,"generation":0,"median":146497000.0,"state":{"best":[21.4496,-14.2894],"population":[[-40.2856,-12.232],[10.9727,-30.536],[-27.0235,37.6881],[-10.7094,-46.4995],[-37.5609,-36.306],[21.4496,-14.2894]]}}, +{"best":582901.0,"evaluations":12,"generation":1,"median":32687200.0,"state":{"best":[13.2588,10.8562],"population":[[-14.1222,-4.57542],[40.2274,-22.5578],[13.2588,10.8562],[-32.18,21.6694],[-8.79292,-44.2007],[18.2438,6.87475]]}}, +{"best":582901.0,"evaluations":18,"generation":2,"median":169819000.0,"state":{"best":[13.2588,10.8562],"population":[[22.6799,26.0632],[-36.9782,29.562],[5.45705,-45.916],[-33.3059,-39.0533],[-9.54399,25.1023],[46.4609,9.7435]]}}, +{"best":2.69281,"evaluations":24,"generation":3,"median":40423000.0,"state":{"best":[-1.33471,-2.29626],"population":[[-3.07042,-29.4843],[-11.5028,30.8612],[-1.33471,-2.29626],[-16.1343,14.1325],[-39.5098,43.7074],[-41.7046,31.1616]]}}, +{"best":2.69281,"evaluations":30,"generation":4,"median":1434400.0,"state":{"best":[-1.33471,-2.29626],"population":[[7.38608,0.333237],[-2.96874,-25.9061],[-2.1115,-2.43541],[10.6077,-27.1072],[-15.5132,14.7015],[5.39862,14.3407]]}}, +{"best":0.797015,"evaluations":36,"generation":5,"median":2160530.0,"state":{"best":[-1.0817,2.35408],"population":[[-16.3533,1.91176],[-1.0817,2.35408],[0.18722,17.7703],[-12.5789,40.2894],[-13.9627,4.09392],[-0.524085,22.8138]]}}, +{"best":0.797015,"evaluations":42,"generation":6,"median":3604570.0,"state":{"best":[-1.0817,2.35408],"population":[[-14.805,-18.5007],[-7.25846,23.6295],[-12.4045,15.5385],[10.7305,17.9985],[3.58599,6.81453],[-6.57222,21.5114]]}}, +{"best":0.797015,"evaluations":48,"generation":7,"median":8651.69,"state":{"best":[-1.0817,2.35408],"population":[[7.77431,16.6472],[6.89122,7.28081],[-12.5507,9.87956],[5.81293,7.5586],[0.696931,-5.03581],[6.41275,8.34736]]}}, +{"best":0.797015,"evaluations":54,"generation":8,"median":589939.0,"state":{"best":[-1.0817,2.35408],"population":[[-1.46283,21.3656],[-16.1019,9.7741],[-2.82498,-4.50868],[5.2788,0.159142],[-0.471136,11.1536],[-0.711544,-15.0899]]}}, +{"best":0.797015,"evaluations":60,"generation":9,"median":13872.9,"state":{"best":[-1.0817,2.35408],"population":[[3.33591,-0.886614],[8.20805,2.11174],[-8.61759,1.52786],[3.7225,-9.96614],[2.36387,4.31783],[1.56282,23.522]]}}, +{"best":0.797015,"evaluations":66,"generation":10,"median":18423.9,"state":{"best":[-1.0817,2.35408],"population":[[5.78348,13.0824],[9.49144,3.81155],[-2.45092,7.34835],[6.59522,5.97039],[9.28725,-0.843759],[3.77891,1.06841]]}}, +{"best":0.797015,"evaluations":72,"generation":11,"median":7614.33,"state":{"best":[-1.0817,2.35408],"population":[[5.63928,3.38515],[14.0794,5.72795],[1.03845,5.41153],[4.46708,8.48206],[5.10092,-6.50318],[3.37697,9.61971]]}}, +{"best":0.306033,"evaluations":78,"generation":12,"median":154.086,"state":{"best":[0.693614,-0.367378],"population":[[6.31513,3.10348],[0.693614,-0.367378],[3.40424,4.84626],[0.858045,7.71447],[7.25095,-0.738817],[0.953015,3.18178]]}}, +{"best":0.306033,"evaluations":84,"generation":13,"median":2.64027,"state":{"best":[0.693614,-0.367378],"population":[[2.59981,-3.37881],[-1.37388,-0.856099],[1.75423,4.32022],[-3.94471,-2.94091],[4.25113,0.596079],[-5.40539,-0.637668]]}}, +{"best":0.306033,"evaluations":90,"generation":14,"median":1.79694,"state":{"best":[0.693614,-0.367378],"population":[[6.00762,2.99988],[5.7384,3.72373],[-0.171293,-2.42019],[2.62631,-1.58967],[4.12945,0.553085],[0.27721,-2.4067]]}}, +{"best":0.306033,"evaluations":96,"generation":15,"median":5.4419,"state":{"best":[0.693614,-0.367378],"population":[[3.26475,-5.57646],[3.67608,-2.91924],[3.31957,-0.142942],[5.51594,0.482975],[4.39981,-3.32404],[-0.187665,-4.83404]]}}, +{"best":0.306033,"evaluations":102,"generation":16,"median":5.90721,"state":{"best":[0.693614,-0.367378],"population":[[4.42651,-0.0981414],[2.06718,-5.46258],[4.02798,-1.15007],[5.97656,-1.22059],[1.93229,-0.6579],[6.36565,-0.326391]]}}, +{"best":0.182043,"evaluations":108,"generation":17,"median":0.726069,"state":{"best":[0.748334,0.203012],"population":[[3.603,-3.14273],[2.20123,-2.76719],[1.02215,-0.306304],[0.748334,0.203012],[1.30548,-0.647201],[2.16464,-1.4749]]}}, +{"best":0.146976,"evaluations":114,"generation":18,"median":0.709389,"state":{"best":[0.236897,1.07726],"population":[[0.236897,1.07726],[-0.512939,-1.04155],[-2.31819,0.545408],[-0.245454,3.00676],[-1.6116,2.48767],[0.302702,-0.945201]]}}, +{"best":0.146976,"evaluations":120,"generation":19,"median":0.397253,"state":{"best":[0.236897,1.07726],"population":[[0.22564,2.16181],[1.68847,-1.7287],[2.38954,1.58981],[0.807164,2.19452],[0.525252,-0.0675588],[-2.77433,-0.437436]]}}, +{"best":0.106812,"evaluations":126,"generation":20,"median":0.27035,"state":{"best":[1.21681,1.39405],"population":[[2.49787,0.247774],[-0.265439,0.828256],[1.5061,0.548693],[1.21681,1.39405],[0.405123,0.286994],[-1.37341,0.857408]]}}, +{"best":0.00182883,"evaluations":132,"generation":21,"median":0.389869,"state":{"best":[0.994748,0.893264],"population":[[1.14134,0.541389],[0.994748,0.893264],[0.989718,3.03198],[-0.271926,0.0668696],[3.04324,-1.05369],[-0.447866,2.30115]]}}, +{"best":0.00182883,"evaluations":138,"generation":22,"median":0.116992,"state":{"best":[0.994748,0.893264],"population":[[0.819717,0.866916],[0.659172,1.69001],[1.54416,1.04964],[1.43884,0.793158],[1.21904,-0.585081],[0.44431,0.732985]]}}, +{"best":0.00182883,"evaluations":144,"generation":23,"median":0.211227,"state":{"best":[0.994748,0.893264],"population":[[-0.062295,1.04814],[0.457039,1.77575],[1.23466,1.96288],[2.23447,2.21402],[0.277368,0.474693],[-0.28156,2.28757]]}}, +{"best":0.00182883,"evaluations":150,"generation":24,"median":0.19393,"state":{"best":[0.994748,0.893264],"population":[[-0.131628,0.813687],[0.242107,0.826848],[0.212733,0.839802],[0.617899,0.295951],[1.02238,0.810865],[1.11361,-0.0942838]]}}, +{"best":0.00182883,"evaluations":156,"generation":25,"median":0.102215,"state":{"best":[0.994748,0.893264],"population":[[1.07962,0.673078],[1.31697,1.54553],[0.731761,0.0176425],[0.965375,1.04886],[0.490022,-0.145323],[1.42995,1.63165]]}}, +{"best":0.00182883,"evaluations":162,"generation":26,"median":0.10321,"state":{"best":[0.994748,0.893264],"population":[[0.692479,1.1],[0.925997,1.70326],[0.813699,1.35916],[0.371661,1.39549],[1.36324,1.44079],[0.400802,1.69513]]}}, +{"best":0.00182883,"evaluations":168,"generation":27,"median":0.0689817,"state":{"best":[0.994748,0.893264],"population":[[0.915386,1.40923],[1.64945,1.31914],[1.55898,1.90078],[0.978105,0.843289],[1.39334,0.691836],[1.15339,1.15963]]}}, +{"best":0.00182883,"evaluations":174,"generation":28,"median":0.118645,"state":{"best":[0.994748,0.893264],"population":[[1.15719,1.25068],[1.11552,1.21275],[1.14675,0.4658],[0.989441,1.23238],[1.44558,0.612733],[1.5077,1.16271]]}}, +{"best":0.00182883,"evaluations":180,"generation":29,"median":0.113786,"state":{"best":[0.994748,0.893264],"population":[[1.25598,0.616335],[1.21956,1.02545],[1.52882,1.11798],[0.888875,1.78256],[0.466993,0.796862],[1.03573,0.852993]]}}, +{"best":0.00182883,"evaluations":186,"generation":30,"median":0.0286817,"state":{"best":[0.994748,0.893264],"population":[[0.862224,1.07709],[1.00954,1.36417],[1.34395,1.08907],[1.07047,0.266363],[1.03684,0.851248],[1.28587,0.879336]]}}, +{"best":0.00182883,"evaluations":192,"generation":31,"median":0.091157,"state":{"best":[0.994748,0.893264],"population":[[1.17184,1.08064],[1.15373,0.575842],[1.39385,0.739495],[1.15659,0.986019],[1.07314,1.32582],[0.763707,1.19464]]}}, +{"best":0.00182883,"evaluations":198,"generation":32,"median":0.0897244,"state":{"best":[0.994748,0.893264],"population":[[0.873801,1.30104],[1.16973,1.10864],[1.05636,1.27169],[1.18708,1.24874],[1.27064,1.06503],[1.08766,1.33432]]}}, +{"best":0.00182883,"evaluations":204,"generation":33,"median":0.0336271,"state":{"best":[0.994748,0.893264],"population":[[0.993465,1.4873],[1.07418,1.39029],[1.01935,1.00554],[1.20233,1.11573],[1.0292,1.2557],[1.05451,1.3184]]}}, +{"best":0.00182883,"evaluations":210,"generation":34,"median":0.046157,"state":{"best":[0.994748,0.893264],"population":[[1.07063,1.1289],[0.939935,1.39535],[1.13007,0.969307],[1.02766,0.948511],[1.04351,1.0772],[1.20634,1.13486]]}}, +{"best":0.000474526,"evaluations":216,"generation":35,"median":0.0315866,"state":{"best":[0.992727,1.00076],"population":[[1.13438,0.710159],[0.992727,1.00076],[1.02558,0.767717],[0.990249,1.08978],[0.909031,1.15626],[1.07899,1.02588]]}}, +{"best":0.000474526,"evaluations":222,"generation":36,"median":0.00446009,"state":{"best":[0.992727,1.00076],"population":[[1.03801,0.989037],[0.986182,0.979645],[0.989089,1.12065],[0.973764,1.05179],[1.01689,1.11882],[1.01942,1.08548]]}}, +{"best":0.000474526,"evaluations":228,"generation":37,"median":0.0395321,"state":{"best":[0.992727,1.00076],"population":[[1.01965,1.12374],[0.916176,1.02903],[1.1024,1.06158],[0.965761,1.04943],[0.918206,0.914713],[1.04193,1.26025]]}}, +{"best":0.000232278,"evaluations":234,"generation":38,"median":0.0212136,"state":{"best":[1.00222,1.04196],"population":[[1.00222,1.04196],[1.11248,1.17931],[1.0324,1.15432],[0.942905,1.07256],[1.05012,0.92894],[1.04491,1.1466]]}}, +{"best":7.13767e-05,"evaluations":240,"generation":39,"median":0.00618795,"state":{"best":[0.999341,0.974353],"population":[[0.975637,1.11866],[0.996167,1.01912],[0.999341,0.974353],[1.01621,1.18045],[1.07238,1.26462],[0.976671,1.04441]]}}, +{"best":7.13767e-05,"evaluations":246,"generation":40,"median":0.00271943,"state":{"best":[0.999341,0.974353],"population":[[0.907983,0.993805],[1.01742,1.07816],[0.984977,0.959664],[1.01595,0.912766],[1.00422,0.884803],[0.996749,0.910165]]}}, +{"best":7.13767e-05,"evaluations":252,"generation":41,"median":0.0283868,"state":{"best":[0.999341,0.974353],"population":[[1.02419,0.847353],[1.01019,0.850627],[1.07201,0.976106],[0.941413,0.777957],[1.04937,0.995047],[0.933553,0.900979]]}}, +{"best":7.13767e-05,"evaluations":258,"generation":42,"median":0.0153953,"state":{"best":[0.999341,0.974353],"population":[[0.98974,0.71734],[1.00868,0.73973],[1.05785,0.950669],[1.05275,0.435703],[1.0025,0.936837],[1.01349,0.774126]]}}, +{"best":7.13767e-05,"evaluations":264,"generation":43,"median":0.00855553,"state":{"best":[0.999341,0.974353],"population":[[1.04101,1.02895],[1.00533,1.04445],[0.990589,0.85181],[0.99013,0.814751],[1.02912,0.794879],[0.988732,0.787802]]}}, +{"best":4.55853e-05,"evaluations":270,"generation":44,"median":0.00195571,"state":{"best":[1.00203,1.00924],"population":[[1.01356,0.953122],[1.00318,1.17081],[0.997739,0.883101],[1.00203,1.00924],[1.0076,0.960398],[0.984054,1.05573]]}}, +{"best":4.55853e-05,"evaluations":276,"generation":45,"median":0.00424541,"state":{"best":[1.00203,1.00924],"population":[[1.01029,0.978567],[0.986516,1.02825],[1.00388,0.864306],[1.05073,0.933128],[1.02486,1.01291],[1.02612,1.07324]]}}, +{"best":4.55853e-05,"evaluations":282,"generation":46,"median":0.00134052,"state":{"best":[1.00203,1.00924],"population":[[0.978656,1.05446],[1.0088,1.02228],[1.01071,0.991525],[0.990369,0.876146],[1.00511,1.00803],[1.01171,1.06042]]}}, +{"best":4.55853e-05,"evaluations":288,"generation":47,"median":0.00148489,"state":{"best":[1.00203,1.00924],"population":[[0.984468,1.01946],[0.993394,0.968191],[1.01327,1.05997],[1.01906,1.02465],[1.00998,0.97054],[0.99755,0.982258]]}}, +{"best":4.55853e-05,"evaluations":294,"generation":48,"median":0.00103748,"state":{"best":[1.00203,1.00924],"population":[[0.995939,0.924267],[1.0083,1.02381],[0.99607,0.964918],[0.987442,0.938617],[0.997282,0.905737],[1.01162,0.940464]]}}, +{"best":4.11746e-05,"evaluations":300,"generation":49,"median":0.000459508,"state":{"best":[1.00195,1.00846],"population":[[1.00606,0.935355],[1.00195,1.00846],[0.989461,1.00152],[0.99353,0.926308],[0.998376,0.971836],[1.00326,1.00738]]}}, +{"best":1.66983e-05,"evaluations":306,"generation":50,"median":8.94185e-05,"state":{"best":[1.00052,1.01192],"population":[[1.00798,1.03631],[1.00052,1.01192],[0.997983,1.02757],[1.00403,0.967774],[0.999693,1.02051],[0.999278,1.02408]]}}, +{"best":1.66983e-05,"evaluations":312,"generation":51,"median":0.000208133,"state":{"best":[1.00052,1.01192],"population":[[0.998655,0.995853],[0.995608,1.01712],[0.999689,1.04095],[1.00765,1.01357],[0.993893,1.00086],[1.0012,1.04323]]}}, +{"best":5.36394e-07,"evaluations":318,"generation":52,"median":6.42015e-05,"state":{"best":[0.999792,1.00122],"population":[[1.00067,1.00286],[0.992105,1.01367],[0.991224,0.981469],[0.999792,1.00122],[1.00206,0.990393],[1.00249,0.984162]]}}, +{"best":5.36394e-07,"evaluations":324,"generation":53,"median":5.77679e-05,"state":{"best":[0.999792,1.00122],"population":[[0.998461,1.00461],[0.998954,0.995315],[0.999785,0.975227],[1.00092,1.02095],[1.00451,1.00701],[0.993926,0.967322]]}}, +{"best":5.36394e-07,"evaluations":330,"generation":54,"median":3.52714e-05,"state":{"best":[0.999792,1.00122],"population":[[1.00176,1.00234],[1.00158,1.00312],[0.996157,0.981644],[0.995161,1.00564],[0.997855,0.997005],[0.998371,0.993786]]}}, +{"best":5.36394e-07,"evaluations":336,"generation":55,"median":6.9915e-05,"state":{"best":[0.999792,1.00122],"population":[[0.996208,0.987987],[1.00071,1.0206],[1.00317,0.995413],[1.00193,1.00533],[1.00331,0.985201],[0.998674,0.992289]]}}, +{"best":5.36394e-07,"evaluations":342,"generation":56,"median":7.45121e-06,"state":{"best":[0.999792,1.00122],"population":[[1.00068,1.00352],[0.997266,0.995882],[0.997764,1.00075],[0.999106,1.00077],[1.00078,1.00463],[0.999464,0.995046]]}}, +{"best":5.36394e-07,"evaluations":348,"generation":57,"median":4.84513e-06,"state":{"best":[0.999792,1.00122],"population":[[0.999738,0.995758],[0.999696,1.00217],[1.00027,1.002],[1.00075,0.995319],[1.00224,1.00527],[0.9992,0.994033]]}}, +{"best":5.36394e-07,"evaluations":354,"generation":58,"median":4.32672e-06,"state":{"best":[0.999792,1.00122],"population":[[0.999737,1.00186],[1.00018,1.00453],[0.999265,1.0022],[0.99808,0.996228],[0.999495,0.996792],[0.998865,0.998597]]}}, +{"best":7.60885e-08,"evaluations":360,"generation":59,"median":3.9536e-06,"state":{"best":[0.999909,0.999878],"population":[[1.00028,1.00531],[0.998799,1.00078],[1.00096,1.00359],[1.00049,1.00469],[1.00056,0.999066],[0.999909,0.999878]]}}, +{"best":3.99055e-08,"evaluations":366,"generation":60,"median":1.70352e-06,"state":{"best":[0.999934,0.99991],"population":[[0.999934,0.99991],[0.999758,1.00348],[1.00054,0.996715],[0.999991,1.00592],[1.00006,0.996789],[1.00043,0.999691]]}}, +{"best":3.99055e-08,"evaluations":372,"generation":61,"median":5.75358e-06,"state":{"best":[0.999934,0.99991],"population":[[0.999147,0.996697],[1.00093,0.999992],[0.999409,1.00272],[0.999704,1.00255],[0.999818,1.00108],[0.998846,0.997641]]}}, +{"best":3.99055e-08,"evaluations":378,"generation":62,"median":3.69585e-06,"state":{"best":[0.999934,0.99991],"population":[[1.00011,1.0015],[0.999834,1.00561],[0.999371,1.00463],[0.999508,1.00487],[0.999704,1.00566],[1.00057,1.00034]]}}, +{"best":3.99055e-08,"evaluations":384,"generation":63,"median":1.20248e-06,"state":{"best":[0.999934,0.99991],"population":[[1.00053,1.0022],[1.00025,1.00844],[0.999977,1.00184],[1.00022,1.00029],[0.999891,0.998191],[1.00046,1.00057]]}}, +{"best":3.99055e-08,"evaluations":390,"generation":64,"median":6.8097e-07,"state":{"best":[0.999934,0.99991],"population":[[0.999905,1.00244],[1.00021,1.00336],[1.00002,1.001],[1.00014,1.0015],[1.00004,1.0028],[1.00022,1.00156]]}}, +{"best":4.14481e-09,"evaluations":396,"generation":65,"median":3.70652e-07,"state":{"best":[1.0,0.999799],"population":[[1.00005,1.00139],[0.999884,1.00026],[1.0,0.999799],[1.0002,1.00182],[1.00016,1.00174],[0.999581,1.00183]]}} +]} diff --git a/examples/penalized2/trace.py b/examples/penalized2/trace.py new file mode 100644 index 00000000..85edaf1d --- /dev/null +++ b/examples/penalized2/trace.py @@ -0,0 +1,189 @@ +"""The trace for the plot on the example's page, written to the file that ``GENOXIDE_TRACE`` +names. The plot draws the population on the function's contour, which needs two dimensions: the +trace is of a separate run of CMA-ES with IPOP restarts in 2 dimensions, with a budget of +20,000 evaluations, in at most 100 frames. The Rust example writes the same file.""" + +import json +import math +import os + +import genoxide as gx + + +def record_small(): + """Runs CMA-ES with IPOP restarts in 2 dimensions and writes its trace, if ``GENOXIDE_TRACE`` is set.""" + path = os.environ.get("GENOXIDE_TRACE") + if not path: + return + problem = gx.problems.Penalized2(2) + minimum = problem.optimum.value + budget = 20_000 + cmaes = gx.Cmaes(problem.genome, restarts="ipop", objective="minimize", seed=1) + frames = Frames(100) + + def record(progress): + state = {"population": progress.population.tolist(), "best": progress.best_genome.tolist()} + frames.push(frame(progress, state, minimum)) + + cmaes.run(problem, target=minimum + 1e-8, evaluations=budget, on_generation=record) + low, high = problem.genome.bounds + settings = { + "format": 1, + "example": "penalized2", + "objective": "minimize", + "x_label": "evaluations", + "y_label": "error", + "log_y": True, + "optimum": 0.0, + "plot": "contour", + "problem": { + "function": "penalized2", + "bounds": [[float(low), float(high)]] * 2, + "minima": problem.optimum.solutions.tolist(), + }, + } + write(path, settings, frames.to_list()) + + +def frame(progress, state, minimum): + """The frame of a generation: its progress, the errors of its best and of its population's + median to ``minimum`` (rounding can put a solution a few ulps below it), and ``state``.""" + + def error(value): + return None if value is None else max(value - minimum, 0.0) + + return { + "generation": progress.generation, + "evaluations": progress.evaluations, + "best": error(progress.best_fitness), + "median": error(median(progress.scores)), + "state": state, + } + + +def median(scores): + """The median of the valid scores, None without any.""" + scores = sorted(float(score) for score in scores if not math.isnan(score)) + middle = len(scores) // 2 + if not scores: + return None + return scores[middle] if len(scores) % 2 else (scores[middle - 1] + scores[middle]) / 2 + + +# ---- the same in every example's trace ---------------------------------------------------------- + + +class Frames: + """The frames of at most ``most`` generations, from the part of the run where what the page + plots changes: the frames after the last change are left out (a run that reached its target, + or a front that no longer moves), and the rest are spread evenly over the generations up to + it. While the run goes, up to 8 × ``most`` frames are kept: every ``every``-th generation, + with ``every`` doubling whenever there are that many, and the last one.""" + + def __init__(self, most): + self.most, self.every, self.kept, self.last = most, 1, [], None + + def push(self, frame): + if frame["generation"] % self.every: + self.last = frame + return + self.kept.append(frame) + self.last = None + if len(self.kept) == 8 * self.most: + self.every *= 2 + self.kept = [kept for kept in self.kept if kept["generation"] % self.every == 0] + + def to_list(self): + frames = self.kept + ([self.last] if self.last else []) + active = frames[: last_change(frames) + 1] + count, most = len(active), max(self.most, 2) + if count <= most: + return active + return [active[(i * (count - 1) + (most - 1) // 2) // (most - 1)] for i in range(most)] + + +def last_change(frames): + """The index of the frame after which nothing the page plots changes. To 3 significant + digits, as a plot shows them: the best, the median and, for a single objective (a numeric + best), the state; to within a hundredth of their range over the run: a front's + hypervolumes, in the state or in a grid's series.""" + if not frames: + return 0 + last = len(frames) - 1 + number = lambda value: isinstance(value, (int, float)) and not isinstance(value, bool) + single = any(number(frame.get("best")) for frame in frames) + + def measures(frame): + values = [] + state = frame.get("state") + hypervolume = state.get("hypervolume") if isinstance(state, dict) else None + for value in (hypervolume, frame.get("series")): + if number(value): + values.append(float(value)) + elif isinstance(value, dict): + values.extend(float(v) for _, v in sorted(value.items()) if number(v)) + return values + + measured = [measures(frame) for frame in frames] + end = measured[last] + tolerance = [] + for k in range(len(end)): + values = [values[k] for values in measured if k < len(values)] + tolerance.append((max(values) - min(values)) / 100.0) + + def same(frame, final, key, flush=False): + return coarse(frame.get(key), flush) == coarse(final.get(key), flush) + + def settled(i): + frame, final = frames[i], frames[last] + return ( + same(frame, final, "best") + and same(frame, final, "median") + and (not single or same(frame, final, "state", flush=True)) + and len(measured[i]) == len(end) + and all(abs(v - e) <= t for v, e, t in zip(measured[i], end, tolerance)) + ) + + first = last + while first > 0 and settled(first - 1): + first -= 1 + return first + + +def coarse(value, flush=False): + """``value`` with its numbers to 3 significant digits, as precisely as a plot shows them: two + frames whose plotted values agree to that precision look the same. With ``flush``, for the + solutions a plot draws on their ranges, numbers below 1e-6 in size count as 0.""" + if isinstance(value, float): + if flush and abs(value) < 1e-6: + value = 0.0 + return f"{value:.2e}" + if isinstance(value, (list, tuple)): + return "[" + ",".join(coarse(item, flush) for item in value) + "]" + if isinstance(value, dict): + items = sorted(value.items()) + return "{" + ",".join(f"{key}:{coarse(item, flush)}" for key, item in items) + "}" + return json.dumps(value) + + +def write(path, settings, frames): + """Writes the settings and the frames to ``path``, a frame per line.""" + lines = ",\n".join(map(to_json, frames)) + with open(path, "w", encoding="utf-8", newline="\n") as file: + file.write(f'{to_json(settings)[:-1]},"frames":[\n{lines}\n]}}\n') + + +def to_json(value): + """Compact JSON with sorted keys, and numbers rounded to 6 significant digits, as the Rust + example writes it.""" + return json.dumps(rounded(value), sort_keys=True, separators=(",", ":"), ensure_ascii=False) + + +def rounded(value): + if isinstance(value, dict): + return {key: rounded(item) for key, item in value.items()} + if isinstance(value, (list, tuple)): + return [rounded(item) for item in value] + if isinstance(value, float): + return float(f"{value:.5e}") if math.isfinite(value) else None + return value diff --git a/examples/penalized2/trace.rs b/examples/penalized2/trace.rs new file mode 100644 index 00000000..dd3c1eeb --- /dev/null +++ b/examples/penalized2/trace.rs @@ -0,0 +1,261 @@ +//! The trace for the plot on the example's page, written to the file that `GENOXIDE_TRACE` names. +//! The plot draws the population on the function's contour, which needs two dimensions: the trace +//! is of a separate run of CMA-ES with IPOP restarts in 2 dimensions, with a budget of +//! 20,000 evaluations, in at most 100 frames. The Python example writes the same +//! file. + +use genoxide::observer::Snapshot; +use genoxide::prelude::*; +use genoxide::problems::{Penalized2, Problem}; +use serde_json::{Value, json}; + +// runs CMA-ES with IPOP restarts in 2 dimensions and writes its trace, if GENOXIDE_TRACE is set +pub fn record_small() -> Result<()> { + let Ok(path) = std::env::var("GENOXIDE_TRACE") else { + return Ok(()); + }; + let problem = Penalized2::new(2); + let optimum = problem.optimum().expect("known"); + let minimum = optimum.value(); + let budget = 20_000; + let cmaes = Cmaes::builder(problem.representation()) + .restarts(cmaes::Restarts::Ipop) + .minimize() + .seed(1) + .build()?; + let mut frames = Frames::new(100); + Engine::new(cmaes, problem.clone()) + .stop_when(Stop::target(minimum + 1e-8).or(Stop::evaluations(budget))) + .on_generation(|snapshot| { + let population = snapshot.population().iter().map(|x| &x.genome()[..]); + let population: Vec<&[f64]> = population.collect(); + let best = &snapshot.best().genome()[..]; + let state = json!({ "population": population, "best": best }); + frames.push(frame(snapshot, state, minimum)); + }) + .run()?; + let bounds = problem.representation().bounds().to_vec(); + let bounds: Vec<[f64; 2]> = bounds.iter().map(|b| [*b.start(), *b.end()]).collect(); + let minima: Vec<&[f64]> = optimum.solutions().iter().map(|x| &x[..]).collect(); + let settings = json!({ + "format": 1, + "example": "penalized2", + "objective": "minimize", + "x_label": "evaluations", + "y_label": "error", + "log_y": true, + "optimum": 0.0, + "plot": "contour", + "problem": { + "function": "penalized2", + "bounds": bounds, + "minima": minima, + }, + }); + write(&path, settings, frames.into_vec()); + Ok(()) +} + +// the frame of a generation: its progress, the errors of its best and of its population's median +// to `minimum` (rounding can put a solution a few ulps below it), and `state` +fn frame(snapshot: &Snapshot<'_, Reals>, state: Value, minimum: f64) -> Value { + let progress = snapshot.progress(); + let error = |value: f64| (value - minimum).max(0.0); + let population = snapshot.population().iter(); + let scores = population.filter_map(|individual| individual.fitness()?.score()); + json!({ + "generation": progress.generation(), + "evaluations": progress.evaluations(), + "best": progress.best().and_then(Fitness::score).map(error), + "median": median(scores.collect()).map(error), + "state": state, + }) +} + +// the median of the scores, None without any +fn median(mut scores: Vec) -> Option { + scores.sort_by(f64::total_cmp); + let middle = scores.len() / 2; + match scores.len() { + 0 => None, + n if n % 2 == 1 => Some(scores[middle]), + _ => Some((scores[middle - 1] + scores[middle]) / 2.0), + } +} + +// ---- the same in every example's trace --------------------------------------------------------- + +// the frames of at most `most` generations, from the part of the run where what the page plots +// changes: the frames after the last change are left out (a run that reached its target, or a +// front that no longer moves), and the rest are spread evenly over the generations up to it. While +// the run goes, up to 8 × `most` frames are kept: every `every`-th generation, with `every` +// doubling whenever there are that many, and the last one. +struct Frames { + most: usize, + every: u64, + kept: Vec<(u64, Value)>, + last: Option<(u64, Value)>, +} + +impl Frames { + fn new(most: usize) -> Self { + let (every, kept, last) = (1, Vec::new(), None); + Self { + most, + every, + kept, + last, + } + } + + fn push(&mut self, frame: Value) { + let generation = frame["generation"].as_u64().expect("a generation"); + if !generation.is_multiple_of(self.every) { + self.last = Some((generation, frame)); + return; + } + self.kept.push((generation, frame)); + self.last = None; + if self.kept.len() == 8 * self.most { + self.every *= 2; + let every = self.every; + self.kept.retain(|(generation, _)| generation % every == 0); + } + } + + fn into_vec(self) -> Vec { + let frames = self.kept.into_iter().chain(self.last); + let frames: Vec = frames.map(|(_, frame)| frame).collect(); + let active = &frames[..=last_change(&frames)]; + let (count, most) = (active.len(), self.most.max(2)); + if count <= most { + return active.to_vec(); + } + let at = |i: usize| active[(i * (count - 1) + (most - 1) / 2) / (most - 1)].clone(); + (0..most).map(at).collect() + } +} + +// the index of the frame after which nothing the page plots changes. To 3 significant digits, as +// a plot shows them: the best, the median and, for a single objective (a numeric best), the state; +// to within a hundredth of their range over the run: a front's hypervolumes, in the state or in a +// grid's series +fn last_change(frames: &[Value]) -> usize { + let Some(last) = frames.len().checked_sub(1) else { + return 0; + }; + let single = frames.iter().any(|frame| frame["best"].is_number()); + let measures = |frame: &Value| -> Vec { + let mut values = Vec::new(); + for value in [&frame["state"]["hypervolume"], &frame["series"]] { + match value { + Value::Number(number) => values.extend(number.as_f64()), + Value::Object(map) => values.extend(map.values().filter_map(Value::as_f64)), + _ => {} + } + } + values + }; + let measured: Vec> = frames.iter().map(measures).collect(); + let end = &measured[last]; + let tolerance: Vec = (0..end.len()) + .map(|k| { + let values = measured.iter().filter_map(|values| values.get(k).copied()); + let (low, high) = values.fold((f64::INFINITY, f64::NEG_INFINITY), |(low, high), v| { + (low.min(v), high.max(v)) + }); + (high - low) / 100.0 + }) + .collect(); + let settled = |i: usize| { + let (frame, final_frame) = (&frames[i], &frames[last]); + let same = + |key: &str, flush: bool| coarse(&frame[key], flush) == coarse(&final_frame[key], flush); + same("best", false) + && same("median", false) + && (!single || same("state", true)) + && measured[i].len() == end.len() + && measured[i] + .iter() + .zip(end) + .zip(&tolerance) + .all(|((value, end), tolerance)| (value - end).abs() <= *tolerance) + }; + let mut first = last; + while first > 0 && settled(first - 1) { + first -= 1; + } + first +} + +// `value` with its numbers to 3 significant digits, as precisely as a plot shows them: two frames +// whose plotted values agree to that precision look the same. With `flush`, for the solutions a +// plot draws on their ranges, numbers below 1e-6 in size count as 0 +fn coarse(value: &Value, flush: bool) -> String { + let join = |items: Vec| items.join(","); + match value { + Value::Number(number) if number.is_f64() => { + let number = number.as_f64().expect("f64"); + let number = if flush && number.abs() < 1e-6 { + 0.0 + } else { + number + }; + format!("{number:.2e}") + } + Value::Array(items) => { + format!( + "[{}]", + join(items.iter().map(|item| coarse(item, flush)).collect()) + ) + } + Value::Object(map) => { + let entry = |(key, item): (&String, &Value)| format!("{key}:{}", coarse(item, flush)); + format!("{{{}}}", join(map.iter().map(entry).collect())) + } + other => other.to_string(), + } +} + +// writes the settings and the frames to `path`, a frame per line +fn write(path: &str, settings: Value, frames: Vec) { + let frames: Vec = frames.iter().map(to_json).collect(); + let settings = to_json(&settings); + let head = &settings[..settings.len() - 1]; + let text = format!("{head},\"frames\":[\n{}\n]}}\n", frames.join(",\n")); + std::fs::write(path, text).expect("the trace is written"); +} + +// compact JSON with sorted keys, and numbers rounded to 6 significant digits and written as +// Python writes them (7542.0, 1e-08): the Python example writes the same file +fn to_json(value: &Value) -> String { + let join = |items: Vec| items.join(","); + match value { + Value::Number(number) if number.is_f64() => python_float(number.as_f64().expect("f64")), + Value::Array(items) => format!("[{}]", join(items.iter().map(to_json).collect())), + Value::Object(map) => { + let entry = + |(key, item): (&String, &Value)| format!("{}:{}", json!(key), to_json(item)); + format!("{{{}}}", join(map.iter().map(entry).collect())) + } + other => other.to_string(), + } +} + +fn python_float(value: f64) -> String { + let rounded: f64 = format!("{value:.5e}").parse().expect("a number"); + let shortest = format!("{rounded:e}"); + let (mantissa, exponent) = shortest.split_once('e').expect("an exponent"); + let exponent: i32 = exponent.parse().expect("an exponent"); + if (-4..16).contains(&exponent) { + let text = rounded.to_string(); + if text.contains('.') { + text + } else { + text + ".0" + } + } else { + let sign = if exponent < 0 { '-' } else { '+' }; + format!("{mantissa}e{sign}{:02}", exponent.abs()) + } +} diff --git a/examples/quartic/README.md b/examples/quartic/README.md new file mode 100644 index 00000000..04ed5494 --- /dev/null +++ b/examples/quartic/README.md @@ -0,0 +1,90 @@ +--- +title: Quartic +category: continuous +summary: Minimize De Jong's quartic function in 30 dimensions, without noise and with noise drawn from the genome, and compare CMA-ES, sep-CMA-ES, DE, PSO and a GA. +reference: "De Jong, K. A. (1975). An Analysis of the Behavior of a Class of Genetic Adaptive Systems. PhD thesis, University of Michigan." +reference_url: "https://hdl.handle.net/2027.42/4507" +optimum: "0 (at the origin, without noise)" +languages: [rust, python] +order: 52 +trace_note: "Recorded from another run: CMA-ES in 2 dimensions, without noise, so that the population can be drawn on the function's contour." +--- + +# Quartic + +## The problem + +The quartic function is a weighted sum of fourth powers, to minimize; Yao, Liu and Lin add noise: + +```text +f(x) = Σ i xᵢ⁴ + random[0, 1), i from 1 to n, each xᵢ in [−1.28, 1.28] +``` + +Without the noise, its minimum is 0, at the origin. Here n = 30. It's De Jong's (1975) F4, with +Gaussian noise; genoxide takes this form, the uniform noise, the bounds and the dimension from Yao, +Liu and Lin (1999, f7), and is still to check De Jong's thesis (issue #168). + +A fitness function in genoxide is deterministic: a copy of a genome inherits its fitness. So +`problems::Quartic::noisy` draws the noise from a generator seeded with the genome's bits: the same +genome always gets the same noise, and two genomes, however close, independent ones. Its minimum +isn't known, so its `optimum` is none. + +## What makes it hard + +Without noise, the function is unimodal and separable, but flat near the minimum: at 0.01 from 0 in +every gene, it's below 10⁻⁵. A search has to keep shrinking its steps on a slope that vanishes +faster than a parabola's. + +With noise, every value is off by up to 1, far more than the quartic itself near the minimum. A +search that compares two points sees mostly their noise, and the best value it keeps is the one +whose noise happened to be small: the lowest of many draws, not the lowest quartic. + +## Representation + +A `Real` genome of 30 genes, each in [−1.28, 1.28]: the point x itself. The fitness is f(x), to +minimize. The functions are genoxide's `problems::Quartic::new` and `problems::Quartic::noisy`. + +## Algorithm + +Five algorithms, each with a budget of 10,000 evaluations per dimension, 300,000 in all, and a +target of 1e-8, from seed 1: + +- CMA-ES (Hansen and Ostermeier, 2001, Evolutionary Computation 9(2): 159-195), which samples a + population of 14 from a normal distribution and adapts its mean, its step size and its covariance + matrix, from a step size of 0.3 of each gene's range and a random start; +- sep-CMA-ES (Ros and Hansen, 2008, PPSN X: 296-305), the same with a diagonal covariance matrix: a + scale per gene but no correlations; +- differential evolution with genoxide's defaults, SHADE (Tanabe and Fukunaga, CEC 2013), with a + population of 100; +- particle swarm optimization (Kennedy and Eberhart, 1995), 40 particles with Clerc and Kennedy's + constriction coefficients and a global topology; +- a real-coded genetic algorithm: a population of 100, tournaments of 3, simulated binary crossover + (Deb and Agrawal, 1995) with η = 15 and polynomial mutation with η = 20 at a rate of 1/30 per + gene. + +With noise, each algorithm runs to the end of its budget, since no target can be met. + +## Output + +The first line gives the dimension and the budget. Then a table for the function without noise: a row per algorithm, the +evaluations it had used when its best error first reached each value of the heading, and the best +error it found, to two significant digits. A dash is an error not reached. Then, with noise, a row per algorithm: the best value it found, noise included, and the +quartic at that point without noise. The function is +evaluated with genoxide's portable math, so the runs are the same on every platform, and in Python, +`run` evaluates it in Rust, so both versions print the same. + +[The project page](https://tachsin.gr/projects/genoxide/examples/quartic) plays back another +run: CMA-ES on the function in 2 dimensions without noise, x₁⁴ + 2x₂⁴, so that the +population can be drawn on its contour. It meets the target after 108 evaluations. + +## Good results + +Without noise, the minimum is 0. sep-CMA-ES reaches 1e-8 after 2,184 evaluations and CMA-ES after +2,436; PSO takes 12,440, SHADE 13,400 and the genetic algorithm 52,845. + +With noise, PSO's best value is 0.0026, with a quartic of 0.0024 there, and SHADE's 0.0034 (a +quartic of 0.0033); the genetic algorithm ends at 0.011. Their best values are the quartic plus a +noise of about 10⁻⁴, the lowest of hundreds of thousands of draws. CMA-ES and sep-CMA-ES stop at +0.10: their step sizes adapt to differences between samples, which the noise dominates long before +the quartic is small. Yao, Liu and Lin report mean best values of 7.6·10⁻³ for their fast +evolutionary programming and 1.8·10⁻² for the classical one, after 3,000 generations of 100. diff --git a/examples/quartic/main.py b/examples/quartic/main.py new file mode 100644 index 00000000..6cdd05fe --- /dev/null +++ b/examples/quartic/main.py @@ -0,0 +1,125 @@ +"""Quartic: minimize De Jong's quartic function in 30 dimensions, without noise and with +the noise of Yao, Liu and Lin, drawn from the genome. + +Compares how fast CMA-ES, with a full and with a diagonal covariance matrix (sep-CMA-ES), +differential evolution, particle swarm optimization and a real-coded genetic algorithm close in on +the minimum, 0 at the origin: the evaluations each takes until its error is at most 1, 1e-2, 1e-4, 1e-6 and 1e-8. +The function is genoxide's `problems::Quartic`. Then, with noise, each algorithm's best value and the quartic without noise +there. + +With ``GENOXIDE_TRACE=``, it also writes a trace of a run for the plot on the example's page, +with trace.py. + + python examples/quartic/main.py +""" + +import genoxide as gx + +from trace import record_small + +DIMENSIONS = 30 +BUDGET = 10_000 * DIMENSIONS +# the errors at which the table gives each run's evaluations +ERRORS = [1e0, 1e-2, 1e-4, 1e-6, 1e-8] +COLUMNS = ["1", "1e-2", "1e-4", "1e-6", "1e-8"] + + +def error_text(error): + """An error to two significant digits, as Rust writes it: 9.9e-9.""" + mantissa, exponent = f"{error:.1e}".split("e") + return f"{mantissa}e{int(exponent)}" + + +class Reached: + """The evaluations after the first generation whose best error was at most each of ERRORS, + for a function whose minimum is ``minimum``.""" + + def __init__(self, minimum): + self.minimum = minimum + self.evaluations = [None] * len(ERRORS) + + def record(self, progress): + if progress.best_fitness is None: + return + error = progress.best_fitness - self.minimum + for i, bound in enumerate(ERRORS): + if self.evaluations[i] is None and error <= bound: + self.evaluations[i] = progress.evaluations + + def print(self, name, result): + """A row of the table: the evaluations, "-" for an error not reached, and the best + error.""" + cells = ["-" if reached is None else str(reached) for reached in self.evaluations] + # rounding can put a solution a few ulps below the minimum + cells.append(error_text(max(result.best_fitness - self.minimum, 0.0))) + print(f"{name:<10}" + "".join(f"{cell:>9}" for cell in cells)) + + +def compare(name, problem): + """The table of the five algorithms on ``problem``, after a line that names it.""" + minimum = problem.optimum.value + print(f"{name}: evaluations until the error is at most") + print(f"{'algorithm':<10}" + "".join(f"{column:>9}" for column in COLUMNS) + f"{'best':>9}") + genome = problem.genome + for label, algorithm in ( + ("CMA-ES", gx.Cmaes(genome, objective="minimize", seed=1)), + ("sep-CMA-ES", gx.Cmaes(genome, covariance="diagonal", objective="minimize", seed=1)), + ("DE", gx.De(genome, objective="minimize", seed=1)), + ("PSO", gx.Pso(genome, population_size=40, objective="minimize", seed=1)), + ( + "GA", + gx.Ga( + genome, + population_size=100, + select=gx.Tournament(3), + crossover=gx.SimulatedBinaryCrossover(15.0), + mutation=gx.PolynomialMutation(20.0, rate=1 / DIMENSIONS), + objective="minimize", + seed=1, + ), + ), + ): + reached = Reached(minimum) + result = algorithm.run( + problem, target=minimum + 1e-8, evaluations=BUDGET, on_generation=reached.record + ) + reached.print(label, result) + + +def noisy(): + """The quartic with noise: each algorithm's best value, noise included, and the quartic + without noise at that point.""" + problem = gx.problems.Quartic(DIMENSIONS, noisy=True) + quiet = gx.problems.Quartic(DIMENSIONS) + genome = problem.genome + print("With noise in [0, 1): the best value found, and the quartic there without noise") + print(f"{'algorithm':<10}{'best':>12}{'without noise':>16}") + for label, algorithm in ( + ("CMA-ES", gx.Cmaes(genome, objective="minimize", seed=1)), + ("sep-CMA-ES", gx.Cmaes(genome, covariance="diagonal", objective="minimize", seed=1)), + ("DE", gx.De(genome, objective="minimize", seed=1)), + ("PSO", gx.Pso(genome, population_size=40, objective="minimize", seed=1)), + ( + "GA", + gx.Ga( + genome, + population_size=100, + select=gx.Tournament(3), + crossover=gx.SimulatedBinaryCrossover(15.0), + mutation=gx.PolynomialMutation(20.0, rate=1 / DIMENSIONS), + objective="minimize", + seed=1, + ), + ), + ): + result = algorithm.run(problem, evaluations=BUDGET) + without = error_text(quiet(result.best_genome)) + print(f"{label:<10}{result.best_fitness:>12.4f}{without:>16}") + +print(f"Quartic in {DIMENSIONS} dimensions, {BUDGET} evaluations at most") +compare("Quartic without noise", gx.problems.Quartic(DIMENSIONS)) +noisy() + +# with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate run in +# 2 dimensions: the plot is the function's contour +record_small() diff --git a/examples/quartic/main.rs b/examples/quartic/main.rs new file mode 100644 index 00000000..705f859d --- /dev/null +++ b/examples/quartic/main.rs @@ -0,0 +1,194 @@ +//! Quartic: minimize De Jong's quartic function in 30 dimensions, without noise and with +//! the noise of Yao, Liu and Lin, drawn from the genome. +//! +//! Compares how fast CMA-ES, with a full and with a diagonal covariance matrix (sep-CMA-ES), +//! differential evolution, particle swarm optimization and a real-coded genetic algorithm close in +//! on the minimum, 0 at the origin: the evaluations each takes until its error is at most 1, 1e-2, 1e-4, 1e-6 and 1e-8. +//! The function is genoxide's `problems::Quartic`. Then, with noise, each algorithm's best value and the quartic without noise +//! there. +//! +//! With `GENOXIDE_TRACE=`, it also writes a trace of a run for the plot on the example's +//! page, with `trace.rs`. +//! +//! ```text +//! cargo run --release --example quartic +//! ``` + +mod trace; + +use genoxide::observer::Snapshot; +use genoxide::prelude::*; +use genoxide::problems::{Problem, Quartic}; + +const DIMENSIONS: usize = 30; +const BUDGET: u64 = 10_000 * DIMENSIONS as u64; +// the errors at which the table gives each run's evaluations +const ERRORS: [f64; 5] = [1e0, 1e-2, 1e-4, 1e-6, 1e-8]; +const COLUMNS: [&str; 5] = ["1", "1e-2", "1e-4", "1e-6", "1e-8"]; + +fn main() -> Result<()> { + println!("Quartic in {DIMENSIONS} dimensions, {BUDGET} evaluations at most"); + compare("Quartic without noise", &Quartic::new(DIMENSIONS))?; + noisy()?; + // with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate + // run in 2 dimensions: the plot is the function's contour + trace::record_small()?; + Ok(()) +} + +// the table of the five algorithms on `problem`, after a line that names it +fn compare

(name: &str, problem: &P) -> Result<()> +where + P: Problem + FitnessFunction + Clone, +{ + let minimum = problem.optimum().expect("known").value(); + let stop = || Stop::target(minimum + 1e-8).or(Stop::evaluations(BUDGET)); + println!("{name}: evaluations until the error is at most"); + print!("{:<10}", "algorithm"); + COLUMNS.iter().for_each(|column| print!("{column:>9}")); + println!("{:>9}", "best"); + + for (name, covariance) in [ + ("CMA-ES", cmaes::Covariance::Full), + ("sep-CMA-ES", cmaes::Covariance::Diagonal), + ] { + let cmaes = Cmaes::builder(problem.representation()) + .covariance(covariance) + .minimize() + .seed(1) + .build()?; + let mut reached = Reached::new(minimum); + let outcome = Engine::new(cmaes, problem.clone()) + .stop_when(stop()) + .on_generation(|snapshot| reached.record(snapshot)) + .run()?; + reached.print(name, &outcome); + } + + let de = De::builder(problem.representation()) + .minimize() + .seed(1) + .build()?; + let mut reached = Reached::new(minimum); + let outcome = Engine::new(de, problem.clone()) + .stop_when(stop()) + .on_generation(|snapshot| reached.record(snapshot)) + .run()?; + reached.print("DE", &outcome); + + let pso = Pso::builder(problem.representation()) + .population_size(40) + .minimize() + .seed(1) + .build()?; + let mut reached = Reached::new(minimum); + let outcome = Engine::new(pso, problem.clone()) + .stop_when(stop()) + .on_generation(|snapshot| reached.record(snapshot)) + .run()?; + reached.print("PSO", &outcome); + + let ga = Ga::builder(problem.representation()) + .population_size(100) + .select(Tournament::new(3)?) + .crossover(SimulatedBinaryCrossover::new(15.0)?) + .mutate(PolynomialMutation::per_gene(1.0 / DIMENSIONS as f64, 20.0)?) + .minimize() + .seed(1) + .build()?; + let mut reached = Reached::new(minimum); + let outcome = Engine::new(ga, problem.clone()) + .stop_when(stop()) + .on_generation(|snapshot| reached.record(snapshot)) + .run()?; + reached.print("GA", &outcome); + Ok(()) +} + +// the quartic with noise: each algorithm's best value, noise included, and the quartic without +// noise at that point +fn noisy() -> Result<()> { + let noisy = Quartic::noisy(DIMENSIONS); + let quiet = Quartic::new(DIMENSIONS); + let real = noisy.representation(); + let stop = || Stop::evaluations(BUDGET); + println!("With noise in [0, 1): the best value found, and the quartic there without noise"); + println!("{:<10}{:>12}{:>16}", "algorithm", "best", "without noise"); + let row = |name: &str, outcome: Outcome| { + let best = outcome.best_fitness().score().expect("valid"); + let without = quiet.evaluate(outcome.best_genome()); + println!("{name:<10}{best:>12.4}{:>16}", format!("{without:.1e}")); + }; + for (name, covariance) in [ + ("CMA-ES", cmaes::Covariance::Full), + ("sep-CMA-ES", cmaes::Covariance::Diagonal), + ] { + let cmaes = Cmaes::builder(real.clone()) + .covariance(covariance) + .minimize() + .seed(1) + .build()?; + row(name, Engine::new(cmaes, noisy).stop_when(stop()).run()?); + } + let de = De::builder(real.clone()).minimize().seed(1).build()?; + row("DE", Engine::new(de, noisy).stop_when(stop()).run()?); + let pso = Pso::builder(real.clone()) + .population_size(40) + .minimize() + .seed(1) + .build()?; + row("PSO", Engine::new(pso, noisy).stop_when(stop()).run()?); + let ga = Ga::builder(real) + .population_size(100) + .select(Tournament::new(3)?) + .crossover(SimulatedBinaryCrossover::new(15.0)?) + .mutate(PolynomialMutation::per_gene(1.0 / DIMENSIONS as f64, 20.0)?) + .minimize() + .seed(1) + .build()?; + row("GA", Engine::new(ga, noisy).stop_when(stop()).run()?); + Ok(()) +} + +// the evaluations after the first generation whose best error was at most each of ERRORS, for a +// function whose minimum is `minimum` +struct Reached { + minimum: f64, + evaluations: [Option; 5], +} + +impl Reached { + fn new(minimum: f64) -> Self { + let evaluations = [None; 5]; + Self { + minimum, + evaluations, + } + } + + fn record(&mut self, snapshot: &Snapshot<'_, Reals>) { + let progress = snapshot.progress(); + let Some(best) = progress.best().and_then(Fitness::score) else { + return; + }; + let error = best - self.minimum; + for (reached, bound) in self.evaluations.iter_mut().zip(ERRORS) { + if reached.is_none() && error <= bound { + *reached = Some(progress.evaluations()); + } + } + } + + // a row of the table: the evaluations, "-" for an error not reached, and the best error + fn print(&self, name: &str, outcome: &Outcome) { + print!("{name:<10}"); + for reached in self.evaluations { + let reached = reached.map_or("-".to_string(), |evaluations| evaluations.to_string()); + print!("{reached:>9}"); + } + // rounding can put a solution a few ulps below the minimum + let best = outcome.best_fitness().score().expect("valid"); + let error = (best - self.minimum).max(0.0); + println!("{:>9}", format!("{error:.1e}")); + } +} diff --git a/examples/quartic/output.txt b/examples/quartic/output.txt new file mode 100644 index 00000000..b3cc22f1 --- /dev/null +++ b/examples/quartic/output.txt @@ -0,0 +1,15 @@ +Quartic in 30 dimensions, 300000 evaluations at most +Quartic without noise: evaluations until the error is at most +algorithm 1 1e-2 1e-4 1e-6 1e-8 best +CMA-ES 476 980 1498 1974 2436 5.7e-9 +sep-CMA-ES 434 840 1232 1722 2184 4.8e-9 +DE 2400 5200 7600 10900 13400 9.8e-9 +PSO 2000 4520 7320 9760 12440 9.4e-9 +GA 2845 5774 10672 21396 52845 9.5e-9 +With noise in [0, 1): the best value found, and the quartic there without noise +algorithm best without noise +CMA-ES 0.1003 9.8e-2 +sep-CMA-ES 0.0964 9.6e-2 +DE 0.0034 3.3e-3 +PSO 0.0026 2.4e-3 +GA 0.0112 1.0e-2 diff --git a/examples/quartic/trace.json b/examples/quartic/trace.json new file mode 100644 index 00000000..775889a2 --- /dev/null +++ b/examples/quartic/trace.json @@ -0,0 +1,20 @@ +{"example":"quartic","format":1,"log_y":true,"objective":"minimize","optimum":0.0,"plot":"contour","problem":{"bounds":[[-1.28,1.28],[-1.28,1.28]],"function":"quartic","minima":[[0.0,0.0]]},"x_label":"evaluations","y_label":"error","frames":[ +{"best":0.126728,"evaluations":6,"generation":0,"median":1.55629,"state":{"best":[0.54911,-0.365808],"population":[[-1.03131,-0.313138],[0.280902,-0.781721],[-0.691802,0.964816],[-0.274162,-1.19039],[-0.961558,-0.929433],[0.54911,-0.365808]]}}, +{"best":0.0108926,"evaluations":12,"generation":1,"median":0.265182,"state":{"best":[0.314038,0.155412],"population":[[-0.363118,-0.226226],[0.980995,-0.670946],[0.314038,0.155412],[-0.809703,0.422833],[-0.231321,-1.20619],[0.437321,0.0569469]]}}, +{"best":0.0108926,"evaluations":18,"generation":2,"median":1.60342,"state":{"best":[0.314038,0.155412],"population":[[0.540251,0.486207],[-0.890359,0.630113],[-0.720965,1.25574],[0.106808,-1.17567],[-0.821449,-0.975056],[-0.23328,0.497406]]}}, +{"best":0.000879841,"evaluations":24,"generation":3,"median":0.517763,"state":{"best":[-0.0441443,-0.144668],"population":[[0.962565,0.548257],[-0.0929633,-0.771655],[-0.27674,0.632683],[-0.0441443,-0.144668],[0.455158,1.17712],[-0.391518,0.250587]]}}, +{"best":0.000879841,"evaluations":30,"generation":4,"median":0.42099,"state":{"best":[-0.0441443,-0.144668],"population":[[-1.10948,-0.361374],[0.404729,1.17133],[-0.815471,0.146225],[-0.629473,0.31493],[0.0643102,0.653431],[-0.794686,-0.0596352]]}}, +{"best":0.000879841,"evaluations":36,"generation":5,"median":0.0412472,"state":{"best":[-0.0441443,-0.144668],"population":[[-0.131801,0.385934],[-0.365249,-0.210174],[-0.357895,0.321685],[-0.0391536,-0.235204],[-0.688759,0.707762],[-0.187313,0.702949]]}}, +{"best":0.000879841,"evaluations":42,"generation":6,"median":0.0662599,"state":{"best":[-0.0441443,-0.144668],"population":[[-0.561656,-0.298283],[-0.231626,-0.145716],[-0.348467,0.209557],[-0.839054,0.5919],[-0.529812,-0.227332],[-0.411341,0.31526]]}}, +{"best":0.000879841,"evaluations":48,"generation":7,"median":0.185878,"state":{"best":[-0.0441443,-0.144668],"population":[[-0.286628,-0.670542],[-0.51966,0.541163],[-0.56696,0.272524],[-0.0154583,0.563868],[-0.0816162,0.192235],[-0.481409,0.490602]]}}, +{"best":0.000569494,"evaluations":54,"generation":8,"median":0.00584923,"state":{"best":[-0.119675,-0.116179],"population":[[-0.128479,0.449244],[-0.0797947,0.22004],[-0.499709,0.147426],[-0.104039,0.219196],[-0.119675,-0.116179],[-0.0972915,0.242134]]}}, +{"best":1.00771e-05,"evaluations":60,"generation":9,"median":0.0323137,"state":{"best":[-0.0516901,0.0348148],"population":[[-0.316952,0.556737],[-0.617312,0.190079],[-0.226325,-0.122645],[-0.0516901,0.0348148],[-0.244015,0.295392],[-0.124359,-0.388616]]}}, +{"best":1.00771e-05,"evaluations":66,"generation":10,"median":0.00178686,"state":{"best":[-0.0516901,0.0348148],"population":[[-0.0963583,0.00298592],[-0.0218201,0.0992922],[-0.348445,-0.0204041],[-0.0244432,-0.192387],[-0.152333,0.110204],[-0.304114,0.523544]]}}, +{"best":1.00771e-05,"evaluations":72,"generation":11,"median":0.00293736,"state":{"best":[-0.0516901,0.0348148],"population":[[-0.131349,0.409796],[0.0490678,0.173619],[-0.29104,0.178175],[-0.0453251,0.212098],[0.0864233,0.038236],[-0.0730205,0.0484045]]}}, +{"best":1.00771e-05,"evaluations":78,"generation":12,"median":0.00243974,"state":{"best":[-0.0516901,0.0348148],"population":[[0.0188709,0.0797278],[0.22042,0.212832],[-0.118724,0.089989],[-0.0546333,0.197179],[0.0877593,-0.172917],[-0.0927537,0.216094]]}}, +{"best":1.00771e-05,"evaluations":84,"generation":13,"median":0.000192386,"state":{"best":[-0.0516901,0.0348148],"population":[[0.109157,0.0726455],[-0.0418248,-0.084801],[0.000759654,0.0983468],[-0.105527,0.161532],[0.17202,-0.0350308],[-0.0637858,0.0251185]]}}, +{"best":9.55595e-07,"evaluations":90,"generation":14,"median":0.000186914,"state":{"best":[0.031244,-0.00603526],"population":[[-0.00593801,-0.101934],[-0.110017,-0.0488613],[-0.0367395,0.0775397],[-0.172862,-0.101804],[0.031244,-0.00603526],[-0.212782,-0.0499866]]}}, +{"best":9.55595e-07,"evaluations":96,"generation":15,"median":8.94732e-05,"state":{"best":[0.031244,-0.00603526],"population":[[0.0785217,0.109585],[0.0650575,0.126343],[-0.0480854,-0.0829098],[0.0226789,-0.038279],[0.046655,0.0301375],[-0.0357501,-0.0788887]]}}, +{"best":9.55595e-07,"evaluations":102,"generation":16,"median":9.39658e-05,"state":{"best":[0.031244,-0.00603526],"population":[[0.107669,-0.0669699],[0.0788984,-0.0125151],[0.0327913,0.0328984],[0.0688618,0.0763836],[0.0993305,-0.00932712],[0.0268259,-0.103848]]}}, +{"best":4.54221e-09,"evaluations":108,"generation":17,"median":9.95255e-05,"state":{"best":[0.00305892,0.00686983],"population":[[0.0529524,0.0608596],[0.0840289,-0.0868698],[0.0605618,0.0329911],[0.107762,0.0650178],[0.00305892,0.00686983],[0.102483,0.089571]]}} +]} diff --git a/examples/quartic/trace.py b/examples/quartic/trace.py new file mode 100644 index 00000000..7acdbb79 --- /dev/null +++ b/examples/quartic/trace.py @@ -0,0 +1,189 @@ +"""The trace for the plot on the example's page, written to the file that ``GENOXIDE_TRACE`` +names. The plot draws the population on the function's contour, which needs two dimensions: the +trace is of a separate run of CMA-ES in 2 dimensions, with a budget of +20,000 evaluations, in at most 100 frames. The Rust example writes the same file.""" + +import json +import math +import os + +import genoxide as gx + + +def record_small(): + """Runs CMA-ES in 2 dimensions and writes its trace, if ``GENOXIDE_TRACE`` is set.""" + path = os.environ.get("GENOXIDE_TRACE") + if not path: + return + problem = gx.problems.Quartic(2) + minimum = problem.optimum.value + budget = 20_000 + cmaes = gx.Cmaes(problem.genome, objective="minimize", seed=1) + frames = Frames(100) + + def record(progress): + state = {"population": progress.population.tolist(), "best": progress.best_genome.tolist()} + frames.push(frame(progress, state, minimum)) + + cmaes.run(problem, target=minimum + 1e-8, evaluations=budget, on_generation=record) + low, high = problem.genome.bounds + settings = { + "format": 1, + "example": "quartic", + "objective": "minimize", + "x_label": "evaluations", + "y_label": "error", + "log_y": True, + "optimum": 0.0, + "plot": "contour", + "problem": { + "function": "quartic", + "bounds": [[float(low), float(high)]] * 2, + "minima": problem.optimum.solutions.tolist(), + }, + } + write(path, settings, frames.to_list()) + + +def frame(progress, state, minimum): + """The frame of a generation: its progress, the errors of its best and of its population's + median to ``minimum`` (rounding can put a solution a few ulps below it), and ``state``.""" + + def error(value): + return None if value is None else max(value - minimum, 0.0) + + return { + "generation": progress.generation, + "evaluations": progress.evaluations, + "best": error(progress.best_fitness), + "median": error(median(progress.scores)), + "state": state, + } + + +def median(scores): + """The median of the valid scores, None without any.""" + scores = sorted(float(score) for score in scores if not math.isnan(score)) + middle = len(scores) // 2 + if not scores: + return None + return scores[middle] if len(scores) % 2 else (scores[middle - 1] + scores[middle]) / 2 + + +# ---- the same in every example's trace ---------------------------------------------------------- + + +class Frames: + """The frames of at most ``most`` generations, from the part of the run where what the page + plots changes: the frames after the last change are left out (a run that reached its target, + or a front that no longer moves), and the rest are spread evenly over the generations up to + it. While the run goes, up to 8 × ``most`` frames are kept: every ``every``-th generation, + with ``every`` doubling whenever there are that many, and the last one.""" + + def __init__(self, most): + self.most, self.every, self.kept, self.last = most, 1, [], None + + def push(self, frame): + if frame["generation"] % self.every: + self.last = frame + return + self.kept.append(frame) + self.last = None + if len(self.kept) == 8 * self.most: + self.every *= 2 + self.kept = [kept for kept in self.kept if kept["generation"] % self.every == 0] + + def to_list(self): + frames = self.kept + ([self.last] if self.last else []) + active = frames[: last_change(frames) + 1] + count, most = len(active), max(self.most, 2) + if count <= most: + return active + return [active[(i * (count - 1) + (most - 1) // 2) // (most - 1)] for i in range(most)] + + +def last_change(frames): + """The index of the frame after which nothing the page plots changes. To 3 significant + digits, as a plot shows them: the best, the median and, for a single objective (a numeric + best), the state; to within a hundredth of their range over the run: a front's + hypervolumes, in the state or in a grid's series.""" + if not frames: + return 0 + last = len(frames) - 1 + number = lambda value: isinstance(value, (int, float)) and not isinstance(value, bool) + single = any(number(frame.get("best")) for frame in frames) + + def measures(frame): + values = [] + state = frame.get("state") + hypervolume = state.get("hypervolume") if isinstance(state, dict) else None + for value in (hypervolume, frame.get("series")): + if number(value): + values.append(float(value)) + elif isinstance(value, dict): + values.extend(float(v) for _, v in sorted(value.items()) if number(v)) + return values + + measured = [measures(frame) for frame in frames] + end = measured[last] + tolerance = [] + for k in range(len(end)): + values = [values[k] for values in measured if k < len(values)] + tolerance.append((max(values) - min(values)) / 100.0) + + def same(frame, final, key, flush=False): + return coarse(frame.get(key), flush) == coarse(final.get(key), flush) + + def settled(i): + frame, final = frames[i], frames[last] + return ( + same(frame, final, "best") + and same(frame, final, "median") + and (not single or same(frame, final, "state", flush=True)) + and len(measured[i]) == len(end) + and all(abs(v - e) <= t for v, e, t in zip(measured[i], end, tolerance)) + ) + + first = last + while first > 0 and settled(first - 1): + first -= 1 + return first + + +def coarse(value, flush=False): + """``value`` with its numbers to 3 significant digits, as precisely as a plot shows them: two + frames whose plotted values agree to that precision look the same. With ``flush``, for the + solutions a plot draws on their ranges, numbers below 1e-6 in size count as 0.""" + if isinstance(value, float): + if flush and abs(value) < 1e-6: + value = 0.0 + return f"{value:.2e}" + if isinstance(value, (list, tuple)): + return "[" + ",".join(coarse(item, flush) for item in value) + "]" + if isinstance(value, dict): + items = sorted(value.items()) + return "{" + ",".join(f"{key}:{coarse(item, flush)}" for key, item in items) + "}" + return json.dumps(value) + + +def write(path, settings, frames): + """Writes the settings and the frames to ``path``, a frame per line.""" + lines = ",\n".join(map(to_json, frames)) + with open(path, "w", encoding="utf-8", newline="\n") as file: + file.write(f'{to_json(settings)[:-1]},"frames":[\n{lines}\n]}}\n') + + +def to_json(value): + """Compact JSON with sorted keys, and numbers rounded to 6 significant digits, as the Rust + example writes it.""" + return json.dumps(rounded(value), sort_keys=True, separators=(",", ":"), ensure_ascii=False) + + +def rounded(value): + if isinstance(value, dict): + return {key: rounded(item) for key, item in value.items()} + if isinstance(value, (list, tuple)): + return [rounded(item) for item in value] + if isinstance(value, float): + return float(f"{value:.5e}") if math.isfinite(value) else None + return value diff --git a/examples/quartic/trace.rs b/examples/quartic/trace.rs new file mode 100644 index 00000000..b31119cf --- /dev/null +++ b/examples/quartic/trace.rs @@ -0,0 +1,260 @@ +//! The trace for the plot on the example's page, written to the file that `GENOXIDE_TRACE` names. +//! The plot draws the population on the function's contour, which needs two dimensions: the trace +//! is of a separate run of CMA-ES in 2 dimensions, with a budget of +//! 20,000 evaluations, in at most 100 frames. The Python example writes the same +//! file. + +use genoxide::observer::Snapshot; +use genoxide::prelude::*; +use genoxide::problems::{Problem, Quartic}; +use serde_json::{Value, json}; + +// runs CMA-ES in 2 dimensions and writes its trace, if GENOXIDE_TRACE is set +pub fn record_small() -> Result<()> { + let Ok(path) = std::env::var("GENOXIDE_TRACE") else { + return Ok(()); + }; + let problem = Quartic::new(2); + let optimum = problem.optimum().expect("known"); + let minimum = optimum.value(); + let budget = 20_000; + let cmaes = Cmaes::builder(problem.representation()) + .minimize() + .seed(1) + .build()?; + let mut frames = Frames::new(100); + Engine::new(cmaes, problem.clone()) + .stop_when(Stop::target(minimum + 1e-8).or(Stop::evaluations(budget))) + .on_generation(|snapshot| { + let population = snapshot.population().iter().map(|x| &x.genome()[..]); + let population: Vec<&[f64]> = population.collect(); + let best = &snapshot.best().genome()[..]; + let state = json!({ "population": population, "best": best }); + frames.push(frame(snapshot, state, minimum)); + }) + .run()?; + let bounds = problem.representation().bounds().to_vec(); + let bounds: Vec<[f64; 2]> = bounds.iter().map(|b| [*b.start(), *b.end()]).collect(); + let minima: Vec<&[f64]> = optimum.solutions().iter().map(|x| &x[..]).collect(); + let settings = json!({ + "format": 1, + "example": "quartic", + "objective": "minimize", + "x_label": "evaluations", + "y_label": "error", + "log_y": true, + "optimum": 0.0, + "plot": "contour", + "problem": { + "function": "quartic", + "bounds": bounds, + "minima": minima, + }, + }); + write(&path, settings, frames.into_vec()); + Ok(()) +} + +// the frame of a generation: its progress, the errors of its best and of its population's median +// to `minimum` (rounding can put a solution a few ulps below it), and `state` +fn frame(snapshot: &Snapshot<'_, Reals>, state: Value, minimum: f64) -> Value { + let progress = snapshot.progress(); + let error = |value: f64| (value - minimum).max(0.0); + let population = snapshot.population().iter(); + let scores = population.filter_map(|individual| individual.fitness()?.score()); + json!({ + "generation": progress.generation(), + "evaluations": progress.evaluations(), + "best": progress.best().and_then(Fitness::score).map(error), + "median": median(scores.collect()).map(error), + "state": state, + }) +} + +// the median of the scores, None without any +fn median(mut scores: Vec) -> Option { + scores.sort_by(f64::total_cmp); + let middle = scores.len() / 2; + match scores.len() { + 0 => None, + n if n % 2 == 1 => Some(scores[middle]), + _ => Some((scores[middle - 1] + scores[middle]) / 2.0), + } +} + +// ---- the same in every example's trace --------------------------------------------------------- + +// the frames of at most `most` generations, from the part of the run where what the page plots +// changes: the frames after the last change are left out (a run that reached its target, or a +// front that no longer moves), and the rest are spread evenly over the generations up to it. While +// the run goes, up to 8 × `most` frames are kept: every `every`-th generation, with `every` +// doubling whenever there are that many, and the last one. +struct Frames { + most: usize, + every: u64, + kept: Vec<(u64, Value)>, + last: Option<(u64, Value)>, +} + +impl Frames { + fn new(most: usize) -> Self { + let (every, kept, last) = (1, Vec::new(), None); + Self { + most, + every, + kept, + last, + } + } + + fn push(&mut self, frame: Value) { + let generation = frame["generation"].as_u64().expect("a generation"); + if !generation.is_multiple_of(self.every) { + self.last = Some((generation, frame)); + return; + } + self.kept.push((generation, frame)); + self.last = None; + if self.kept.len() == 8 * self.most { + self.every *= 2; + let every = self.every; + self.kept.retain(|(generation, _)| generation % every == 0); + } + } + + fn into_vec(self) -> Vec { + let frames = self.kept.into_iter().chain(self.last); + let frames: Vec = frames.map(|(_, frame)| frame).collect(); + let active = &frames[..=last_change(&frames)]; + let (count, most) = (active.len(), self.most.max(2)); + if count <= most { + return active.to_vec(); + } + let at = |i: usize| active[(i * (count - 1) + (most - 1) / 2) / (most - 1)].clone(); + (0..most).map(at).collect() + } +} + +// the index of the frame after which nothing the page plots changes. To 3 significant digits, as +// a plot shows them: the best, the median and, for a single objective (a numeric best), the state; +// to within a hundredth of their range over the run: a front's hypervolumes, in the state or in a +// grid's series +fn last_change(frames: &[Value]) -> usize { + let Some(last) = frames.len().checked_sub(1) else { + return 0; + }; + let single = frames.iter().any(|frame| frame["best"].is_number()); + let measures = |frame: &Value| -> Vec { + let mut values = Vec::new(); + for value in [&frame["state"]["hypervolume"], &frame["series"]] { + match value { + Value::Number(number) => values.extend(number.as_f64()), + Value::Object(map) => values.extend(map.values().filter_map(Value::as_f64)), + _ => {} + } + } + values + }; + let measured: Vec> = frames.iter().map(measures).collect(); + let end = &measured[last]; + let tolerance: Vec = (0..end.len()) + .map(|k| { + let values = measured.iter().filter_map(|values| values.get(k).copied()); + let (low, high) = values.fold((f64::INFINITY, f64::NEG_INFINITY), |(low, high), v| { + (low.min(v), high.max(v)) + }); + (high - low) / 100.0 + }) + .collect(); + let settled = |i: usize| { + let (frame, final_frame) = (&frames[i], &frames[last]); + let same = + |key: &str, flush: bool| coarse(&frame[key], flush) == coarse(&final_frame[key], flush); + same("best", false) + && same("median", false) + && (!single || same("state", true)) + && measured[i].len() == end.len() + && measured[i] + .iter() + .zip(end) + .zip(&tolerance) + .all(|((value, end), tolerance)| (value - end).abs() <= *tolerance) + }; + let mut first = last; + while first > 0 && settled(first - 1) { + first -= 1; + } + first +} + +// `value` with its numbers to 3 significant digits, as precisely as a plot shows them: two frames +// whose plotted values agree to that precision look the same. With `flush`, for the solutions a +// plot draws on their ranges, numbers below 1e-6 in size count as 0 +fn coarse(value: &Value, flush: bool) -> String { + let join = |items: Vec| items.join(","); + match value { + Value::Number(number) if number.is_f64() => { + let number = number.as_f64().expect("f64"); + let number = if flush && number.abs() < 1e-6 { + 0.0 + } else { + number + }; + format!("{number:.2e}") + } + Value::Array(items) => { + format!( + "[{}]", + join(items.iter().map(|item| coarse(item, flush)).collect()) + ) + } + Value::Object(map) => { + let entry = |(key, item): (&String, &Value)| format!("{key}:{}", coarse(item, flush)); + format!("{{{}}}", join(map.iter().map(entry).collect())) + } + other => other.to_string(), + } +} + +// writes the settings and the frames to `path`, a frame per line +fn write(path: &str, settings: Value, frames: Vec) { + let frames: Vec = frames.iter().map(to_json).collect(); + let settings = to_json(&settings); + let head = &settings[..settings.len() - 1]; + let text = format!("{head},\"frames\":[\n{}\n]}}\n", frames.join(",\n")); + std::fs::write(path, text).expect("the trace is written"); +} + +// compact JSON with sorted keys, and numbers rounded to 6 significant digits and written as +// Python writes them (7542.0, 1e-08): the Python example writes the same file +fn to_json(value: &Value) -> String { + let join = |items: Vec| items.join(","); + match value { + Value::Number(number) if number.is_f64() => python_float(number.as_f64().expect("f64")), + Value::Array(items) => format!("[{}]", join(items.iter().map(to_json).collect())), + Value::Object(map) => { + let entry = + |(key, item): (&String, &Value)| format!("{}:{}", json!(key), to_json(item)); + format!("{{{}}}", join(map.iter().map(entry).collect())) + } + other => other.to_string(), + } +} + +fn python_float(value: f64) -> String { + let rounded: f64 = format!("{value:.5e}").parse().expect("a number"); + let shortest = format!("{rounded:e}"); + let (mantissa, exponent) = shortest.split_once('e').expect("an exponent"); + let exponent: i32 = exponent.parse().expect("an exponent"); + if (-4..16).contains(&exponent) { + let text = rounded.to_string(); + if text.contains('.') { + text + } else { + text + ".0" + } + } else { + let sign = if exponent < 0 { '-' } else { '+' }; + format!("{mantissa}e{sign}{:02}", exponent.abs()) + } +} diff --git a/examples/rotated_hyper_ellipsoid/README.md b/examples/rotated_hyper_ellipsoid/README.md new file mode 100644 index 00000000..1dac5670 --- /dev/null +++ b/examples/rotated_hyper_ellipsoid/README.md @@ -0,0 +1,94 @@ +--- +title: Rotated hyper-ellipsoid +category: continuous +summary: Minimize the "rotated" hyper-ellipsoid in 30 dimensions, which is in fact axis-parallel, and then the same function truly rotated, with CMA-ES and sep-CMA-ES, DE, PSO and a GA. +reference: "Molga, M. and Smutnicki, C. (2005). Test functions for optimization needs." +reference_url: "" +optimum: "0 (at the origin)" +languages: [rust, python] +order: 53 +trace_note: "Recorded from another run: CMA-ES in 2 dimensions on the function rotated with seed 1, so that the population can be drawn on the function's contour." +--- + +# Rotated hyper-ellipsoid + +## The problem + +The rotated hyper-ellipsoid, as Molga and Smutnicki (2005, section 2.3) define it, sums the sums of +squares of the first genes: + +```text +f(x) = Σᵢ Σⱼ≤ᵢ xⱼ², each xᵢ in [−65.536, 65.536] +``` + +Its minimum is 0, at the origin. Here n = 30. Its origin is unknown; genoxide takes it, and its +bounds, from Molga and Smutnicki, and it's still to be checked against an original (issue #168). + +Despite its name, it isn't rotated. Gene j appears in the n − j + 1 sums from i = j on, so + +```text +f(x) = Σⱼ (n − j + 1) xⱼ² +``` + +an ellipsoid along the axes, with weights from 30 down to 1: genoxide's axis-parallel ellipsoid +with its genes reversed. Molga and Smutnicki describe Schwefel's problem 1.2, Σᵢ (Σⱼ≤ᵢ xⱼ)², +whose ellipsoids are rotated, but write this formula, which other collections repeat. + +## What makes it hard + +As written, little: it's a separable quadratic with a condition number of 30, which a search can +solve a gene at a time. + +The example then rotates it, with genoxide's `problems::Rotated` and seed 1: an orthogonal matrix, +drawn from normal numbers made orthonormal by Gram-Schmidt as BBOB draws its rotations, turns the +function about its minimum. The ellipsoid's axes are no longer the genes' axes, and the genes +interact: a scale per gene no longer fits it, nor do steps along the axes. The plan of genoxide's +test problems suggested this page for comparing CMA-ES with a full and with a diagonal covariance +matrix. + +## Representation + +A `Real` genome of 30 genes, each in [−65.536, 65.536]: the point x itself. The fitness is f(x), +to minimize. The function is genoxide's `problems::RotatedHyperEllipsoid`, and its rotation +`problems::Rotated`, which keeps the bounds and the minimum. + +## Algorithm + +Five algorithms, each with a budget of 10,000 evaluations per dimension, 300,000 in all, and a +target of 1e-8, from seed 1: + +- CMA-ES (Hansen and Ostermeier, 2001, Evolutionary Computation 9(2): 159-195), which samples a + population of 14 from a normal distribution and adapts its mean, its step size and its covariance + matrix, from a step size of 0.3 of each gene's range and a random start; +- sep-CMA-ES (Ros and Hansen, 2008, PPSN X: 296-305), the same with a diagonal covariance matrix: a + scale per gene but no correlations; +- differential evolution with genoxide's defaults, SHADE (Tanabe and Fukunaga, CEC 2013), with a + population of 100; +- particle swarm optimization (Kennedy and Eberhart, 1995), 40 particles with Clerc and Kennedy's + constriction coefficients and a global topology; +- a real-coded genetic algorithm: a population of 100, tournaments of 3, simulated binary crossover + (Deb and Agrawal, 1995) with η = 15 and polynomial mutation with η = 20 at a rate of 1/30 per + gene. + +## Output + +The first line gives the dimension and the budget. Then two tables, the function as written and rotated by an orthogonal matrix: a row per algorithm, the +evaluations it had used when its best error first reached each value of the heading, and the best +error it found, to two significant digits. A dash is an error not reached. The function is +evaluated with genoxide's portable math, so the runs are the same on every platform, and in Python, +`run` evaluates it in Rust, so both versions print the same. + +[The project page](https://tachsin.gr/projects/genoxide/examples/rotated-hyper-ellipsoid) plays back another +run: CMA-ES on the function in 2 dimensions, 2x₁² + x₂², rotated with seed 1, so that +the population can be drawn on its contour. It meets the target after 342 evaluations. + +## Good results + +The minimum is 0. As written, sep-CMA-ES reaches 1e-8 first, after 4,886 evaluations, then CMA-ES +(7,140), PSO (27,520) and SHADE (31,900); the genetic algorithm ends at 1.1e-3. + +Rotated, CMA-ES takes about as long, 7,294 evaluations: its full covariance matrix learns the +ellipsoid's axes, whichever they are. sep-CMA-ES takes 2.5 times as long, 12,180, since its +diagonal matrix can only scale the genes; with a condition number of 30, it still gets there. +SHADE and PSO slow down by two and three and a half times (59,000 and 96,600), and the genetic +algorithm, which recombines genes position by position, ends at 4.2. diff --git a/examples/rotated_hyper_ellipsoid/main.py b/examples/rotated_hyper_ellipsoid/main.py new file mode 100644 index 00000000..f174ccef --- /dev/null +++ b/examples/rotated_hyper_ellipsoid/main.py @@ -0,0 +1,97 @@ +"""Rotated hyper-ellipsoid: minimize the "rotated" hyper-ellipsoid in 30 dimensions, which is in fact +axis-parallel, and then the same function truly rotated. + +Compares how fast CMA-ES, with a full and with a diagonal covariance matrix (sep-CMA-ES), +differential evolution, particle swarm optimization and a real-coded genetic algorithm close in on +the minimum, 0 at the origin: the evaluations each takes until its error is at most 1, 1e-2, 1e-4, 1e-6 and 1e-8. +The function is genoxide's `problems::RotatedHyperEllipsoid`. Then the same on the function rotated by an orthogonal matrix, with genoxide's +`problems::Rotated`. + +With ``GENOXIDE_TRACE=``, it also writes a trace of a run for the plot on the example's page, +with trace.py. + + python examples/rotated_hyper_ellipsoid/main.py +""" + +import genoxide as gx + +from trace import record_small + +DIMENSIONS = 30 +BUDGET = 10_000 * DIMENSIONS +# the errors at which the table gives each run's evaluations +ERRORS = [1e0, 1e-2, 1e-4, 1e-6, 1e-8] +COLUMNS = ["1", "1e-2", "1e-4", "1e-6", "1e-8"] + + +def error_text(error): + """An error to two significant digits, as Rust writes it: 9.9e-9.""" + mantissa, exponent = f"{error:.1e}".split("e") + return f"{mantissa}e{int(exponent)}" + + +class Reached: + """The evaluations after the first generation whose best error was at most each of ERRORS, + for a function whose minimum is ``minimum``.""" + + def __init__(self, minimum): + self.minimum = minimum + self.evaluations = [None] * len(ERRORS) + + def record(self, progress): + if progress.best_fitness is None: + return + error = progress.best_fitness - self.minimum + for i, bound in enumerate(ERRORS): + if self.evaluations[i] is None and error <= bound: + self.evaluations[i] = progress.evaluations + + def print(self, name, result): + """A row of the table: the evaluations, "-" for an error not reached, and the best + error.""" + cells = ["-" if reached is None else str(reached) for reached in self.evaluations] + # rounding can put a solution a few ulps below the minimum + cells.append(error_text(max(result.best_fitness - self.minimum, 0.0))) + print(f"{name:<10}" + "".join(f"{cell:>9}" for cell in cells)) + + +def compare(name, problem): + """The table of the five algorithms on ``problem``, after a line that names it.""" + minimum = problem.optimum.value + print(f"{name}: evaluations until the error is at most") + print(f"{'algorithm':<10}" + "".join(f"{column:>9}" for column in COLUMNS) + f"{'best':>9}") + genome = problem.genome + for label, algorithm in ( + ("CMA-ES", gx.Cmaes(genome, objective="minimize", seed=1)), + ("sep-CMA-ES", gx.Cmaes(genome, covariance="diagonal", objective="minimize", seed=1)), + ("DE", gx.De(genome, objective="minimize", seed=1)), + ("PSO", gx.Pso(genome, population_size=40, objective="minimize", seed=1)), + ( + "GA", + gx.Ga( + genome, + population_size=100, + select=gx.Tournament(3), + crossover=gx.SimulatedBinaryCrossover(15.0), + mutation=gx.PolynomialMutation(20.0, rate=1 / DIMENSIONS), + objective="minimize", + seed=1, + ), + ), + ): + reached = Reached(minimum) + result = algorithm.run( + problem, target=minimum + 1e-8, evaluations=BUDGET, on_generation=reached.record + ) + reached.print(label, result) + + +print(f"Rotated hyper-ellipsoid in {DIMENSIONS} dimensions, {BUDGET} evaluations at most") +compare("Rotated hyper-ellipsoid", gx.problems.RotatedHyperEllipsoid(DIMENSIONS)) +# the same function rotated by an orthogonal matrix: now the genes interact +rotated = gx.problems.Rotated(gx.problems.RotatedHyperEllipsoid(DIMENSIONS), seed=1) +compare("Rotated by an orthogonal matrix (seed 1)", rotated) + +# with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate run in +# 2 dimensions: the plot is the function's contour +record_small() diff --git a/examples/rotated_hyper_ellipsoid/main.rs b/examples/rotated_hyper_ellipsoid/main.rs new file mode 100644 index 00000000..f0d06f43 --- /dev/null +++ b/examples/rotated_hyper_ellipsoid/main.rs @@ -0,0 +1,151 @@ +//! Rotated hyper-ellipsoid: minimize the "rotated" hyper-ellipsoid in 30 dimensions, which is in fact +//! axis-parallel, and then the same function truly rotated. +//! +//! Compares how fast CMA-ES, with a full and with a diagonal covariance matrix (sep-CMA-ES), +//! differential evolution, particle swarm optimization and a real-coded genetic algorithm close in +//! on the minimum, 0 at the origin: the evaluations each takes until its error is at most 1, 1e-2, 1e-4, 1e-6 and 1e-8. +//! The function is genoxide's `problems::RotatedHyperEllipsoid`. Then the same on the function rotated by an orthogonal matrix, with genoxide's +//! `problems::Rotated`. +//! +//! With `GENOXIDE_TRACE=`, it also writes a trace of a run for the plot on the example's +//! page, with `trace.rs`. +//! +//! ```text +//! cargo run --release --example rotated_hyper_ellipsoid +//! ``` + +mod trace; + +use genoxide::observer::Snapshot; +use genoxide::prelude::*; +use genoxide::problems::{Problem, Rotated, RotatedHyperEllipsoid}; + +const DIMENSIONS: usize = 30; +const BUDGET: u64 = 10_000 * DIMENSIONS as u64; +// the errors at which the table gives each run's evaluations +const ERRORS: [f64; 5] = [1e0, 1e-2, 1e-4, 1e-6, 1e-8]; +const COLUMNS: [&str; 5] = ["1", "1e-2", "1e-4", "1e-6", "1e-8"]; + +fn main() -> Result<()> { + println!("Rotated hyper-ellipsoid in {DIMENSIONS} dimensions, {BUDGET} evaluations at most"); + compare("Rotated hyper-ellipsoid", &RotatedHyperEllipsoid::new(DIMENSIONS))?; + // the same function rotated by an orthogonal matrix: now the genes interact + let rotated = Rotated::new(RotatedHyperEllipsoid::new(DIMENSIONS), 1); + compare("Rotated by an orthogonal matrix (seed 1)", &rotated)?; + // with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate + // run in 2 dimensions: the plot is the function's contour + trace::record_small()?; + Ok(()) +} + +// the table of the five algorithms on `problem`, after a line that names it +fn compare

(name: &str, problem: &P) -> Result<()> +where + P: Problem + FitnessFunction + Clone, +{ + let minimum = problem.optimum().expect("known").value(); + let stop = || Stop::target(minimum + 1e-8).or(Stop::evaluations(BUDGET)); + println!("{name}: evaluations until the error is at most"); + print!("{:<10}", "algorithm"); + COLUMNS.iter().for_each(|column| print!("{column:>9}")); + println!("{:>9}", "best"); + + for (name, covariance) in [ + ("CMA-ES", cmaes::Covariance::Full), + ("sep-CMA-ES", cmaes::Covariance::Diagonal), + ] { + let cmaes = Cmaes::builder(problem.representation()) + .covariance(covariance) + .minimize() + .seed(1) + .build()?; + let mut reached = Reached::new(minimum); + let outcome = Engine::new(cmaes, problem.clone()) + .stop_when(stop()) + .on_generation(|snapshot| reached.record(snapshot)) + .run()?; + reached.print(name, &outcome); + } + + let de = De::builder(problem.representation()) + .minimize() + .seed(1) + .build()?; + let mut reached = Reached::new(minimum); + let outcome = Engine::new(de, problem.clone()) + .stop_when(stop()) + .on_generation(|snapshot| reached.record(snapshot)) + .run()?; + reached.print("DE", &outcome); + + let pso = Pso::builder(problem.representation()) + .population_size(40) + .minimize() + .seed(1) + .build()?; + let mut reached = Reached::new(minimum); + let outcome = Engine::new(pso, problem.clone()) + .stop_when(stop()) + .on_generation(|snapshot| reached.record(snapshot)) + .run()?; + reached.print("PSO", &outcome); + + let ga = Ga::builder(problem.representation()) + .population_size(100) + .select(Tournament::new(3)?) + .crossover(SimulatedBinaryCrossover::new(15.0)?) + .mutate(PolynomialMutation::per_gene(1.0 / DIMENSIONS as f64, 20.0)?) + .minimize() + .seed(1) + .build()?; + let mut reached = Reached::new(minimum); + let outcome = Engine::new(ga, problem.clone()) + .stop_when(stop()) + .on_generation(|snapshot| reached.record(snapshot)) + .run()?; + reached.print("GA", &outcome); + Ok(()) +} + +// the evaluations after the first generation whose best error was at most each of ERRORS, for a +// function whose minimum is `minimum` +struct Reached { + minimum: f64, + evaluations: [Option; 5], +} + +impl Reached { + fn new(minimum: f64) -> Self { + let evaluations = [None; 5]; + Self { + minimum, + evaluations, + } + } + + fn record(&mut self, snapshot: &Snapshot<'_, Reals>) { + let progress = snapshot.progress(); + let Some(best) = progress.best().and_then(Fitness::score) else { + return; + }; + let error = best - self.minimum; + for (reached, bound) in self.evaluations.iter_mut().zip(ERRORS) { + if reached.is_none() && error <= bound { + *reached = Some(progress.evaluations()); + } + } + } + + // a row of the table: the evaluations, "-" for an error not reached, and the best error + fn print(&self, name: &str, outcome: &Outcome) { + print!("{name:<10}"); + for reached in self.evaluations { + let reached = reached.map_or("-".to_string(), |evaluations| evaluations.to_string()); + print!("{reached:>9}"); + } + // rounding can put a solution a few ulps below the minimum + let best = outcome.best_fitness().score().expect("valid"); + let error = (best - self.minimum).max(0.0); + println!("{:>9}", format!("{error:.1e}")); + } +} diff --git a/examples/rotated_hyper_ellipsoid/output.txt b/examples/rotated_hyper_ellipsoid/output.txt new file mode 100644 index 00000000..5b5f1f7d --- /dev/null +++ b/examples/rotated_hyper_ellipsoid/output.txt @@ -0,0 +1,15 @@ +Rotated hyper-ellipsoid in 30 dimensions, 300000 evaluations at most +Rotated hyper-ellipsoid: evaluations until the error is at most +algorithm 1 1e-2 1e-4 1e-6 1e-8 best +CMA-ES 3262 4410 5362 6160 7140 8.7e-9 +sep-CMA-ES 2142 2772 3556 4354 4886 9.6e-9 +DE 13500 18100 23100 27100 31900 7.9e-9 +PSO 10960 16320 20280 24160 27520 9.4e-9 +GA 44250 138965 - - - 1.1e-3 +Rotated by an orthogonal matrix (seed 1): evaluations until the error is at most +algorithm 1 1e-2 1e-4 1e-6 1e-8 best +CMA-ES 3430 4536 5348 6314 7294 8.8e-9 +sep-CMA-ES 3920 6342 8540 10668 12180 9.5e-9 +DE 18300 30500 41100 50500 59000 9.9e-9 +PSO 25120 42640 57360 79760 96600 1.0e-8 +GA - - - - - 4.2e0 diff --git a/examples/rotated_hyper_ellipsoid/trace.json b/examples/rotated_hyper_ellipsoid/trace.json new file mode 100644 index 00000000..e1213cdd --- /dev/null +++ b/examples/rotated_hyper_ellipsoid/trace.json @@ -0,0 +1,59 @@ +{"example":"rotated_hyper_ellipsoid","format":1,"log_y":true,"objective":"minimize","optimum":0.0,"plot":"contour","problem":{"bounds":[[-65.536,65.536],[-65.536,65.536]],"function":"rotated_hyper_ellipsoid","minima":[[0.0,0.0]],"rotation":{"center":[0.0,0.0],"matrix":[[-0.973552,0.228466],[-0.228466,-0.973552]]}},"x_label":"evaluations","y_label":"error","frames":[ +{"best":2142.92,"evaluations":6,"generation":0,"median":4618.21,"state":{"best":[28.1144,-18.7293],"population":[[-52.8031,-16.0327],[14.3822,-40.0241],[-35.4203,49.3986],[-14.0371,-60.9478],[-49.2318,-47.5869],[28.1144,-18.7293]]}}, +{"best":605.791,"evaluations":12,"generation":1,"median":2395.36,"state":{"best":[-15.533,-15.1106],"population":[[-15.533,-15.1106],[53.2481,-37.8679],[19.1185,4.41859],[-38.3857,18.1031],[-8.78868,-65.2577],[25.4271,-0.620073]]}}, +{"best":605.791,"evaluations":18,"generation":2,"median":5459.03,"state":{"best":[-15.533,-15.1106],"population":[[20.2414,6.96846],[-46.8246,30.3429],[-34.2537,56.6261],[-19.9401,59.6442],[-12.3645,-63.0441],[-55.1079,-43.0299]]}}, +{"best":5.33285,"evaluations":24,"generation":3,"median":1592.51,"state":{"best":[0.382433,-2.11098],"population":[[-4.16461,12.5136],[47.6786,-17.0399],[-0.72608,-55.2891],[0.382433,-2.11098],[4.81526,-32.797],[31.7822,10.8338]]}}, +{"best":5.33285,"evaluations":30,"generation":4,"median":1646.34,"state":{"best":[0.382433,-2.11098],"population":[[1.47692,39.5508],[-9.22869,-7.40615],[-43.2128,-4.15368],[32.2789,35.173],[-26.8496,11.1598],[-17.7354,15.2752]]}}, +{"best":4.03073,"evaluations":36,"generation":5,"median":503.532,"state":{"best":[1.37481,-0.354625],"population":[[-63.3342,34.8714],[2.37969,21.2869],[-35.5165,6.15701],[1.37481,-0.354625],[-12.1973,-18.2674],[-7.8859,-0.218572]]}}, +{"best":4.03073,"evaluations":42,"generation":6,"median":206.996,"state":{"best":[1.37481,-0.354625],"population":[[8.36064,-14.2334],[-7.02501,9.76923],[6.65427,7.21855],[-15.5623,5.31479],[-2.91221,3.41139],[-1.06241,13.0271]]}}, +{"best":4.03073,"evaluations":48,"generation":7,"median":362.619,"state":{"best":[1.37481,-0.354625],"population":[[-7.74317,28.3302],[-10.2553,9.38496],[-0.216727,17.6713],[-11.3575,-10.2399],[1.02747,22.3404],[-5.05076,16.813]]}}, +{"best":0.649963,"evaluations":54,"generation":8,"median":92.511,"state":{"best":[0.348446,-0.557521],"population":[[8.14869,0.758523],[-0.691336,-2.59864],[-0.978326,10.3335],[0.348446,-0.557521],[-4.44229,-6.17034],[-16.4785,4.95379]]}}, +{"best":0.649963,"evaluations":60,"generation":9,"median":118.686,"state":{"best":[0.348446,-0.557521],"population":[[2.39631,-5.7751],[-5.72301,-10.8007],[3.07389,-5.58139],[8.70306,14.2321],[-7.65224,16.404],[-6.38149,-0.413286]]}}, +{"best":0.649963,"evaluations":66,"generation":10,"median":73.9784,"state":{"best":[0.348446,-0.557521],"population":[[-0.303871,-5.45452],[3.87507,-12.9179],[6.29313,3.28158],[1.08089,-4.74896],[-4.48998,-6.3201],[13.7493,-8.25015]]}}, +{"best":0.649963,"evaluations":72,"generation":11,"median":226.754,"state":{"best":[0.348446,-0.557521],"population":[[-0.00303114,1.02053],[0.00261792,-7.94272],[-0.897238,-19.8751],[-4.66463,-16.3954],[-8.4491,-6.81534],[7.40862,-12.4165]]}}, +{"best":0.649963,"evaluations":78,"generation":12,"median":20.888,"state":{"best":[0.348446,-0.557521],"population":[[0.800566,2.13617],[4.64104,-1.40582],[-0.434695,-1.88613],[0.755952,-1.25196],[8.49883,3.61594],[-4.3669,-1.40009]]}}, +{"best":0.649963,"evaluations":84,"generation":13,"median":26.3503,"state":{"best":[0.348446,-0.557521],"population":[[-0.54925,2.52679],[3.47971,-6.9728],[-1.73818,2.92235],[5.05753,-0.437024],[-0.820542,-5.88217],[1.06056,-0.00172984]]}}, +{"best":0.649963,"evaluations":90,"generation":14,"median":16.0801,"state":{"best":[0.348446,-0.557521],"population":[[-1.04092,4.36133],[4.45689,-3.42046],[-1.36493,0.487032],[1.56845,-2.98595],[-2.10938,-0.472535],[1.44676,3.67239]]}}, +{"best":0.649963,"evaluations":96,"generation":15,"median":26.0985,"state":{"best":[0.348446,-0.557521],"population":[[-6.09785,-2.23795],[1.53249,-0.157091],[-7.2116,-0.328321],[2.17494,3.4477],[1.75874,4.12818],[-3.79935,-2.76081]]}}, +{"best":0.0164754,"evaluations":102,"generation":16,"median":4.61215,"state":{"best":[0.000825752,-0.124953],"population":[[0.308649,2.27949],[0.000825752,-0.124953],[2.31288,4.55768],[-1.97156,2.15551],[-0.851154,0.353789],[1.12516,-0.947376]]}}, +{"best":0.0164754,"evaluations":108,"generation":17,"median":9.64262,"state":{"best":[0.000825752,-0.124953],"population":[[-2.14545,-3.34902],[-2.99596,-0.977427],[0.0571291,2.40946],[-0.438512,-1.20685],[-1.09193,2.99738],[-0.626877,-0.426327]]}}, +{"best":0.0164754,"evaluations":114,"generation":18,"median":7.11453,"state":{"best":[0.000825752,-0.124953],"population":[[-2.07788,-1.81276],[0.67299,0.32281],[-1.96254,-2.27232],[-2.58641,-0.0939285],[-1.21109,0.833641],[1.09813,0.843244]]}}, +{"best":0.0164754,"evaluations":120,"generation":19,"median":2.48831,"state":{"best":[0.000825752,-0.124953],"population":[[2.60356,1.70523],[1.75147,1.59738],[0.677175,1.2708],[-0.225769,0.245926],[0.985861,-0.539421],[-0.505903,-1.50422]]}}, +{"best":0.0164754,"evaluations":126,"generation":20,"median":3.15795,"state":{"best":[0.000825752,-0.124953],"population":[[-1.46659,0.178456],[-1.4993,-0.474259],[0.440942,0.155658],[-0.509706,0.575066],[1.4008,0.941112],[0.127227,1.44554]]}}, +{"best":0.0164754,"evaluations":132,"generation":21,"median":0.43431,"state":{"best":[0.000825752,-0.124953],"population":[[-0.255873,0.631001],[0.412302,0.437542],[0.0821927,-0.60187],[0.552138,0.947266],[-0.20918,-0.171982],[0.23935,0.556064]]}}, +{"best":0.0104454,"evaluations":138,"generation":22,"median":0.129483,"state":{"best":[-0.023029,-0.099574],"population":[[-0.307726,0.0802178],[-0.0343395,-0.2349],[-0.407619,-0.806241],[0.127121,-0.0590891],[-0.023029,-0.099574],[-0.827135,-0.00307023]]}}, +{"best":0.0104454,"evaluations":144,"generation":23,"median":0.543537,"state":{"best":[-0.023029,-0.099574],"population":[[0.185814,-0.648545],[0.908949,0.427164],[-0.566974,-0.6181],[-0.0718685,-0.156097],[-0.519051,-0.214497],[-0.0416989,0.23107]]}}, +{"best":0.0104454,"evaluations":150,"generation":24,"median":0.138706,"state":{"best":[-0.023029,-0.099574],"population":[[-0.0720443,0.125451],[0.370778,0.0282816],[-0.147157,-0.222346],[-0.0627327,-0.357205],[-0.266319,-0.156885],[-0.254233,0.129054]]}}, +{"best":0.00786094,"evaluations":156,"generation":25,"median":0.0359756,"state":{"best":[-0.0640088,-0.00519091],"population":[[-0.203845,0.410981],[0.11641,-0.159485],[-0.418029,-0.29474],[-0.00693021,0.0981586],[-0.072573,-0.0128498],[-0.0640088,-0.00519091]]}}, +{"best":0.000832167,"evaluations":162,"generation":26,"median":0.0251618,"state":{"best":[-0.0204387,-0.0103403],"population":[[-0.0550343,-0.09731],[0.0581087,-0.0247842],[-0.0211701,-0.189423],[-0.0204387,-0.0103403],[0.12536,0.157304],[-0.159477,-0.127121]]}}, +{"best":0.000832167,"evaluations":168,"generation":27,"median":0.0119714,"state":{"best":[-0.0204387,-0.0103403],"population":[[0.058001,0.0429801],[-0.14113,-0.152254],[0.190885,0.127169],[-0.0840631,-0.0391805],[-0.00996904,0.0945955],[-0.0478116,0.0185487]]}}, +{"best":0.000468832,"evaluations":174,"generation":28,"median":0.0158465,"state":{"best":[0.0136421,-0.0075745],"population":[[0.0526793,0.144568],[0.0136421,-0.0075745],[0.0959669,0.146004],[0.0153303,0.0254781],[-0.0403984,-0.110068],[0.0665663,-0.0800557]]}}, +{"best":0.000468832,"evaluations":180,"generation":29,"median":0.00570093,"state":{"best":[0.0136421,-0.0075745],"population":[[-0.0532837,-0.0328013],[-0.0960315,-0.10152],[-0.0133083,-0.0540975],[0.0100591,-0.074236],[0.017443,-0.0648243],[0.0087696,0.0545862]]}}, +{"best":0.000468832,"evaluations":186,"generation":30,"median":0.00371444,"state":{"best":[0.0136421,-0.0075745],"population":[[0.0412019,0.0476151],[-0.0129049,-0.026271],[0.0477642,-0.0096839],[-0.0643088,-0.0405125],[-0.0158602,-0.016784],[0.00480949,-0.0490425]]}}, +{"best":0.000468832,"evaluations":192,"generation":31,"median":0.003774,"state":{"best":[0.0136421,-0.0075745],"population":[[0.0440192,0.0183861],[-0.077385,0.0213437],[-0.0551844,-0.0380511],[-0.00530843,0.0245319],[0.0366387,0.0274704],[0.0357725,-0.0282007]]}}, +{"best":0.000468832,"evaluations":198,"generation":32,"median":0.0016828,"state":{"best":[0.0136421,-0.0075745],"population":[[-0.0366092,-0.0160033],[0.00946563,0.0352033],[0.0293044,0.0178906],[0.0278133,0.0327567],[-0.0272022,-0.0189335],[0.0116708,-0.0257738]]}}, +{"best":0.000404968,"evaluations":204,"generation":33,"median":0.00105121,"state":{"best":[0.0110503,0.0151535],"population":[[0.0131988,-0.0084319],[0.0381064,0.030474],[0.00162386,0.0455916],[-0.00675163,0.0369803],[0.00726432,-0.0156179],[0.0110503,0.0151535]]}}, +{"best":0.00035963,"evaluations":210,"generation":34,"median":0.000863269,"state":{"best":[-0.0128799,-0.00921158],"population":[[0.0198061,0.0103692],[0.0159448,-0.0100396],[0.0166563,0.0233409],[0.0161374,0.0382903],[0.0172056,0.0238862],[-0.0128799,-0.00921158]]}}, +{"best":2.82791e-05,"evaluations":216,"generation":35,"median":0.000301402,"state":{"best":[-0.00159706,0.00438136],"population":[[-0.00130548,-0.0213172],[-0.00731738,0.000499614],[-0.00159706,0.00438136],[0.00389316,-0.00916239],[0.00691693,0.0281733],[0.000169455,-0.0304559]]}}, +{"best":1.76833e-05,"evaluations":222,"generation":36,"median":0.000322113,"state":{"best":[-0.0028898,-0.0019224],"population":[[-0.0104747,-0.0116932],[-0.0028898,-0.0019224],[0.0122144,-0.00481373],[-0.0102005,-0.0279324],[-0.0061527,0.00447875],[-0.0158811,-0.0174875]]}}, +{"best":7.76063e-07,"evaluations":228,"generation":37,"median":8.78194e-05,"state":{"best":[-0.000415697,-0.000740098],"population":[[-0.00346125,0.00741464],[-0.00590236,0.0154472],[-0.000415697,-0.000740098],[-0.00125432,-0.00459865],[-0.00648495,-0.00308836],[0.000253563,0.00982837]]}}, +{"best":7.76063e-07,"evaluations":234,"generation":38,"median":3.90379e-05,"state":{"best":[-0.000415697,-0.000740098],"population":[[-0.00109133,0.00116321],[0.00346231,0.00373389],[0.00263669,0.00172332],[0.00448747,0.00362389],[-0.00646932,0.000778388],[0.00832051,-0.00384928]]}}, +{"best":7.76063e-07,"evaluations":240,"generation":39,"median":7.0008e-05,"state":{"best":[-0.000415697,-0.000740098],"population":[[-0.00049073,0.00352012],[-0.00739572,-0.00293489],[0.010421,0.0135673],[-0.00218667,-0.00332139],[0.0112112,0.0019702],[0.0037793,0.00336361]]}}, +{"best":7.76063e-07,"evaluations":246,"generation":40,"median":4.44697e-05,"state":{"best":[-0.000415697,-0.000740098],"population":[[-0.00477411,0.00125306],[-0.00206862,-0.00794936],[0.00207256,0.00212737],[-0.00226847,0.00490003],[-0.0034713,-0.00154896],[-0.0044173,-0.00425899]]}}, +{"best":7.76063e-07,"evaluations":252,"generation":41,"median":3.3622e-05,"state":{"best":[-0.000415697,-0.000740098],"population":[[0.00226841,0.00576807],[0.00694616,0.00824735],[-0.0025904,0.000491945],[-0.00536385,0.0038522],[0.00262429,0.0043234],[-0.00102609,0.000239355]]}}, +{"best":7.76063e-07,"evaluations":258,"generation":42,"median":6.95639e-06,"state":{"best":[-0.000415697,-0.000740098],"population":[[-0.00131812,-0.00202814],[-0.00212104,-0.00254271],[-0.0021336,-0.0016674],[-0.000869241,-0.0012072],[-0.00130643,-0.000874453],[0.00194534,0.000843431]]}}, +{"best":7.76063e-07,"evaluations":264,"generation":43,"median":1.76963e-05,"state":{"best":[-0.000415697,-0.000740098],"population":[[-0.004055,-0.00301997],[0.00145687,-0.000143564],[-0.00317972,-0.000149929],[-0.00312678,-0.00271663],[-0.00234427,-0.00276968],[0.00100894,-0.000684678]]}}, +{"best":4.44415e-07,"evaluations":270,"generation":44,"median":8.51595e-06,"state":{"best":[6.01506e-05,-0.000632136],"population":[[-0.00162884,-0.00737096],[0.00103114,0.000699221],[-1.50506e-05,-0.00179259],[0.0036836,0.000702883],[0.00248134,0.00188907],[6.01506e-05,-0.000632136]]}}, +{"best":4.44415e-07,"evaluations":276,"generation":45,"median":3.03456e-06,"state":{"best":[6.01506e-05,-0.000632136],"population":[[-0.00062844,-0.000736558],[0.000408415,-0.0018178],[-0.000881308,-0.00103531],[0.000749067,-0.0010769],[0.00267434,0.00264707],[-0.000746128,-0.00164866]]}}, +{"best":3.12951e-07,"evaluations":282,"generation":46,"median":1.48931e-06,"state":{"best":[-0.000192722,-0.000520666],"population":[[-0.000192722,-0.000520666],[-0.000473358,-0.00115987],[-0.000290139,0.000414903],[-0.000526929,-0.0011791],[-0.000810809,0.000168138],[-0.00199305,-0.00237656]]}}, +{"best":2.8069e-07,"evaluations":288,"generation":47,"median":1.57737e-06,"state":{"best":[0.000199646,-0.000399116],"population":[[0.000533573,-0.00196814],[0.000509692,-0.000500671],[0.00108707,7.48821e-05],[-0.000408583,0.0019403],[0.000544236,0.000168496],[0.000199646,-0.000399116]]}}, +{"best":2.8069e-07,"evaluations":294,"generation":48,"median":1.60206e-06,"state":{"best":[0.000199646,-0.000399116],"population":[[9.18153e-05,0.00123342],[0.000411751,-0.000543502],[0.00050224,-0.00128397],[0.00162336,0.000836263],[0.000673331,0.00084034],[0.000390724,-0.00104893]]}}, +{"best":2.904e-08,"evaluations":300,"generation":49,"median":3.89707e-07,"state":{"best":[-1.86948e-05,0.000160268],"population":[[-3.70988e-05,-0.000698627],[-1.86948e-05,0.000160268],[0.000678279,0.0006394],[-0.000129994,0.00041222],[0.000415757,-0.000925028],[0.000377397,0.000141287]]}}, +{"best":2.904e-08,"evaluations":306,"generation":50,"median":1.98428e-06,"state":{"best":[-1.86948e-05,0.000160268],"population":[[2.22752e-05,0.000936],[-0.000827146,0.000733536],[-0.00112925,-0.000139149],[-0.00103692,0.000249671],[0.000262329,-0.000168198],[0.000928662,0.000586987]]}}, +{"best":2.904e-08,"evaluations":312,"generation":51,"median":3.95795e-07,"state":{"best":[-1.86948e-05,0.000160268],"population":[[-6.2695e-05,0.000853887],[0.000226725,0.00030594],[0.000397522,-0.00017184],[0.00030707,-0.000373628],[0.00044918,0.00025365],[0.000856063,0.000302784]]}}, +{"best":2.904e-08,"evaluations":318,"generation":52,"median":2.21333e-07,"state":{"best":[-1.86948e-05,0.000160268],"population":[[0.000145484,-0.000354476],[0.000281687,0.000360758],[0.000286534,0.000413292],[0.000113039,-4.56244e-05],[0.00012169,0.000299221],[0.000410134,0.000419589]]}}, +{"best":2.904e-08,"evaluations":324,"generation":53,"median":1.95692e-07,"state":{"best":[-1.86948e-05,0.000160268],"population":[[0.000348157,-0.000216065],[-0.000154473,8.19055e-05],[0.000288208,0.000264313],[0.000147545,-0.000142054],[-0.000145959,0.000346057],[-0.000425302,6.07173e-06]]}}, +{"best":1.82604e-08,"evaluations":330,"generation":54,"median":1.6626e-07,"state":{"best":[9.31837e-05,6.05442e-05],"population":[[-0.00019769,8.12934e-05],[-0.000412653,0.000104728],[-0.000481859,0.000142186],[9.31837e-05,6.05442e-05],[-2.00462e-05,0.00013193],[-0.000247292,0.000293849]]}}, +{"best":1.82604e-08,"evaluations":336,"generation":55,"median":5.82196e-08,"state":{"best":[9.31837e-05,6.05442e-05],"population":[[0.00012708,-8.25631e-05],[-0.000168847,-7.12392e-05],[0.000184631,0.000487164],[-0.000178871,-4.77484e-05],[-0.000156528,-4.96684e-05],[0.000118233,0.000389579]]}}, +{"best":1.08598e-10,"evaluations":342,"generation":56,"median":9.94318e-08,"state":{"best":[-7.27907e-06,1.19875e-06],"population":[[0.00029401,8.48494e-05],[5.4703e-05,5.5892e-06],[-7.27907e-06,1.19875e-06],[0.000158342,0.000279969],[0.000252747,-0.000229704],[-0.000188543,-0.000176702]]}} +]} diff --git a/examples/rotated_hyper_ellipsoid/trace.py b/examples/rotated_hyper_ellipsoid/trace.py new file mode 100644 index 00000000..6493b78a --- /dev/null +++ b/examples/rotated_hyper_ellipsoid/trace.py @@ -0,0 +1,190 @@ +"""The trace for the plot on the example's page, written to the file that ``GENOXIDE_TRACE`` +names. The plot draws the population on the function's contour, which needs two dimensions: the +trace is of a separate run of CMA-ES in 2 dimensions, rotated with seed 1, with a budget of +20,000 evaluations, in at most 100 frames. The Rust example writes the same file.""" + +import json +import math +import os + +import genoxide as gx + + +def record_small(): + """Runs CMA-ES in 2 dimensions and writes its trace, if ``GENOXIDE_TRACE`` is set.""" + path = os.environ.get("GENOXIDE_TRACE") + if not path: + return + problem = gx.problems.Rotated(gx.problems.RotatedHyperEllipsoid(2), seed=1) + minimum = problem.optimum.value + budget = 20_000 + cmaes = gx.Cmaes(problem.genome, objective="minimize", seed=1) + frames = Frames(100) + + def record(progress): + state = {"population": progress.population.tolist(), "best": progress.best_genome.tolist()} + frames.push(frame(progress, state, minimum)) + + cmaes.run(problem, target=minimum + 1e-8, evaluations=budget, on_generation=record) + low, high = problem.genome.bounds + settings = { + "format": 1, + "example": "rotated_hyper_ellipsoid", + "objective": "minimize", + "x_label": "evaluations", + "y_label": "error", + "log_y": True, + "optimum": 0.0, + "plot": "contour", + "problem": { + "function": "rotated_hyper_ellipsoid", + "bounds": [[float(low), float(high)]] * 2, + "minima": problem.optimum.solutions.tolist(), + "rotation": {"matrix": problem.matrix.tolist(), "center": problem.center.tolist()}, + }, + } + write(path, settings, frames.to_list()) + + +def frame(progress, state, minimum): + """The frame of a generation: its progress, the errors of its best and of its population's + median to ``minimum`` (rounding can put a solution a few ulps below it), and ``state``.""" + + def error(value): + return None if value is None else max(value - minimum, 0.0) + + return { + "generation": progress.generation, + "evaluations": progress.evaluations, + "best": error(progress.best_fitness), + "median": error(median(progress.scores)), + "state": state, + } + + +def median(scores): + """The median of the valid scores, None without any.""" + scores = sorted(float(score) for score in scores if not math.isnan(score)) + middle = len(scores) // 2 + if not scores: + return None + return scores[middle] if len(scores) % 2 else (scores[middle - 1] + scores[middle]) / 2 + + +# ---- the same in every example's trace ---------------------------------------------------------- + + +class Frames: + """The frames of at most ``most`` generations, from the part of the run where what the page + plots changes: the frames after the last change are left out (a run that reached its target, + or a front that no longer moves), and the rest are spread evenly over the generations up to + it. While the run goes, up to 8 × ``most`` frames are kept: every ``every``-th generation, + with ``every`` doubling whenever there are that many, and the last one.""" + + def __init__(self, most): + self.most, self.every, self.kept, self.last = most, 1, [], None + + def push(self, frame): + if frame["generation"] % self.every: + self.last = frame + return + self.kept.append(frame) + self.last = None + if len(self.kept) == 8 * self.most: + self.every *= 2 + self.kept = [kept for kept in self.kept if kept["generation"] % self.every == 0] + + def to_list(self): + frames = self.kept + ([self.last] if self.last else []) + active = frames[: last_change(frames) + 1] + count, most = len(active), max(self.most, 2) + if count <= most: + return active + return [active[(i * (count - 1) + (most - 1) // 2) // (most - 1)] for i in range(most)] + + +def last_change(frames): + """The index of the frame after which nothing the page plots changes. To 3 significant + digits, as a plot shows them: the best, the median and, for a single objective (a numeric + best), the state; to within a hundredth of their range over the run: a front's + hypervolumes, in the state or in a grid's series.""" + if not frames: + return 0 + last = len(frames) - 1 + number = lambda value: isinstance(value, (int, float)) and not isinstance(value, bool) + single = any(number(frame.get("best")) for frame in frames) + + def measures(frame): + values = [] + state = frame.get("state") + hypervolume = state.get("hypervolume") if isinstance(state, dict) else None + for value in (hypervolume, frame.get("series")): + if number(value): + values.append(float(value)) + elif isinstance(value, dict): + values.extend(float(v) for _, v in sorted(value.items()) if number(v)) + return values + + measured = [measures(frame) for frame in frames] + end = measured[last] + tolerance = [] + for k in range(len(end)): + values = [values[k] for values in measured if k < len(values)] + tolerance.append((max(values) - min(values)) / 100.0) + + def same(frame, final, key, flush=False): + return coarse(frame.get(key), flush) == coarse(final.get(key), flush) + + def settled(i): + frame, final = frames[i], frames[last] + return ( + same(frame, final, "best") + and same(frame, final, "median") + and (not single or same(frame, final, "state", flush=True)) + and len(measured[i]) == len(end) + and all(abs(v - e) <= t for v, e, t in zip(measured[i], end, tolerance)) + ) + + first = last + while first > 0 and settled(first - 1): + first -= 1 + return first + + +def coarse(value, flush=False): + """``value`` with its numbers to 3 significant digits, as precisely as a plot shows them: two + frames whose plotted values agree to that precision look the same. With ``flush``, for the + solutions a plot draws on their ranges, numbers below 1e-6 in size count as 0.""" + if isinstance(value, float): + if flush and abs(value) < 1e-6: + value = 0.0 + return f"{value:.2e}" + if isinstance(value, (list, tuple)): + return "[" + ",".join(coarse(item, flush) for item in value) + "]" + if isinstance(value, dict): + items = sorted(value.items()) + return "{" + ",".join(f"{key}:{coarse(item, flush)}" for key, item in items) + "}" + return json.dumps(value) + + +def write(path, settings, frames): + """Writes the settings and the frames to ``path``, a frame per line.""" + lines = ",\n".join(map(to_json, frames)) + with open(path, "w", encoding="utf-8", newline="\n") as file: + file.write(f'{to_json(settings)[:-1]},"frames":[\n{lines}\n]}}\n') + + +def to_json(value): + """Compact JSON with sorted keys, and numbers rounded to 6 significant digits, as the Rust + example writes it.""" + return json.dumps(rounded(value), sort_keys=True, separators=(",", ":"), ensure_ascii=False) + + +def rounded(value): + if isinstance(value, dict): + return {key: rounded(item) for key, item in value.items()} + if isinstance(value, (list, tuple)): + return [rounded(item) for item in value] + if isinstance(value, float): + return float(f"{value:.5e}") if math.isfinite(value) else None + return value diff --git a/examples/rotated_hyper_ellipsoid/trace.rs b/examples/rotated_hyper_ellipsoid/trace.rs new file mode 100644 index 00000000..751d075b --- /dev/null +++ b/examples/rotated_hyper_ellipsoid/trace.rs @@ -0,0 +1,264 @@ +//! The trace for the plot on the example's page, written to the file that `GENOXIDE_TRACE` names. +//! The plot draws the population on the function's contour, which needs two dimensions: the trace +//! is of a separate run of CMA-ES in 2 dimensions, rotated with seed 1, with a budget of +//! 20,000 evaluations, in at most 100 frames. The Python example writes the same +//! file. + +use genoxide::observer::Snapshot; +use genoxide::prelude::*; +use genoxide::problems::{Problem, Rotated, RotatedHyperEllipsoid}; +use serde_json::{Value, json}; + +// runs CMA-ES in 2 dimensions and writes its trace, if GENOXIDE_TRACE is set +pub fn record_small() -> Result<()> { + let Ok(path) = std::env::var("GENOXIDE_TRACE") else { + return Ok(()); + }; + let problem = Rotated::new(RotatedHyperEllipsoid::new(2), 1); + let optimum = problem.optimum().expect("known"); + let minimum = optimum.value(); + let budget = 20_000; + let cmaes = Cmaes::builder(problem.representation()) + .minimize() + .seed(1) + .build()?; + let mut frames = Frames::new(100); + Engine::new(cmaes, problem.clone()) + .stop_when(Stop::target(minimum + 1e-8).or(Stop::evaluations(budget))) + .on_generation(|snapshot| { + let population = snapshot.population().iter().map(|x| &x.genome()[..]); + let population: Vec<&[f64]> = population.collect(); + let best = &snapshot.best().genome()[..]; + let state = json!({ "population": population, "best": best }); + frames.push(frame(snapshot, state, minimum)); + }) + .run()?; + let bounds = problem.representation().bounds().to_vec(); + let bounds: Vec<[f64; 2]> = bounds.iter().map(|b| [*b.start(), *b.end()]).collect(); + let minima: Vec<&[f64]> = optimum.solutions().iter().map(|x| &x[..]).collect(); + let settings = json!({ + "format": 1, + "example": "rotated_hyper_ellipsoid", + "objective": "minimize", + "x_label": "evaluations", + "y_label": "error", + "log_y": true, + "optimum": 0.0, + "plot": "contour", + "problem": { + "function": "rotated_hyper_ellipsoid", + "bounds": bounds, + "minima": minima, + "rotation": { + "matrix": problem.matrix().chunks(2).collect::>(), + "center": problem.center(), + }, + }, + }); + write(&path, settings, frames.into_vec()); + Ok(()) +} + +// the frame of a generation: its progress, the errors of its best and of its population's median +// to `minimum` (rounding can put a solution a few ulps below it), and `state` +fn frame(snapshot: &Snapshot<'_, Reals>, state: Value, minimum: f64) -> Value { + let progress = snapshot.progress(); + let error = |value: f64| (value - minimum).max(0.0); + let population = snapshot.population().iter(); + let scores = population.filter_map(|individual| individual.fitness()?.score()); + json!({ + "generation": progress.generation(), + "evaluations": progress.evaluations(), + "best": progress.best().and_then(Fitness::score).map(error), + "median": median(scores.collect()).map(error), + "state": state, + }) +} + +// the median of the scores, None without any +fn median(mut scores: Vec) -> Option { + scores.sort_by(f64::total_cmp); + let middle = scores.len() / 2; + match scores.len() { + 0 => None, + n if n % 2 == 1 => Some(scores[middle]), + _ => Some((scores[middle - 1] + scores[middle]) / 2.0), + } +} + +// ---- the same in every example's trace --------------------------------------------------------- + +// the frames of at most `most` generations, from the part of the run where what the page plots +// changes: the frames after the last change are left out (a run that reached its target, or a +// front that no longer moves), and the rest are spread evenly over the generations up to it. While +// the run goes, up to 8 × `most` frames are kept: every `every`-th generation, with `every` +// doubling whenever there are that many, and the last one. +struct Frames { + most: usize, + every: u64, + kept: Vec<(u64, Value)>, + last: Option<(u64, Value)>, +} + +impl Frames { + fn new(most: usize) -> Self { + let (every, kept, last) = (1, Vec::new(), None); + Self { + most, + every, + kept, + last, + } + } + + fn push(&mut self, frame: Value) { + let generation = frame["generation"].as_u64().expect("a generation"); + if !generation.is_multiple_of(self.every) { + self.last = Some((generation, frame)); + return; + } + self.kept.push((generation, frame)); + self.last = None; + if self.kept.len() == 8 * self.most { + self.every *= 2; + let every = self.every; + self.kept.retain(|(generation, _)| generation % every == 0); + } + } + + fn into_vec(self) -> Vec { + let frames = self.kept.into_iter().chain(self.last); + let frames: Vec = frames.map(|(_, frame)| frame).collect(); + let active = &frames[..=last_change(&frames)]; + let (count, most) = (active.len(), self.most.max(2)); + if count <= most { + return active.to_vec(); + } + let at = |i: usize| active[(i * (count - 1) + (most - 1) / 2) / (most - 1)].clone(); + (0..most).map(at).collect() + } +} + +// the index of the frame after which nothing the page plots changes. To 3 significant digits, as +// a plot shows them: the best, the median and, for a single objective (a numeric best), the state; +// to within a hundredth of their range over the run: a front's hypervolumes, in the state or in a +// grid's series +fn last_change(frames: &[Value]) -> usize { + let Some(last) = frames.len().checked_sub(1) else { + return 0; + }; + let single = frames.iter().any(|frame| frame["best"].is_number()); + let measures = |frame: &Value| -> Vec { + let mut values = Vec::new(); + for value in [&frame["state"]["hypervolume"], &frame["series"]] { + match value { + Value::Number(number) => values.extend(number.as_f64()), + Value::Object(map) => values.extend(map.values().filter_map(Value::as_f64)), + _ => {} + } + } + values + }; + let measured: Vec> = frames.iter().map(measures).collect(); + let end = &measured[last]; + let tolerance: Vec = (0..end.len()) + .map(|k| { + let values = measured.iter().filter_map(|values| values.get(k).copied()); + let (low, high) = values.fold((f64::INFINITY, f64::NEG_INFINITY), |(low, high), v| { + (low.min(v), high.max(v)) + }); + (high - low) / 100.0 + }) + .collect(); + let settled = |i: usize| { + let (frame, final_frame) = (&frames[i], &frames[last]); + let same = + |key: &str, flush: bool| coarse(&frame[key], flush) == coarse(&final_frame[key], flush); + same("best", false) + && same("median", false) + && (!single || same("state", true)) + && measured[i].len() == end.len() + && measured[i] + .iter() + .zip(end) + .zip(&tolerance) + .all(|((value, end), tolerance)| (value - end).abs() <= *tolerance) + }; + let mut first = last; + while first > 0 && settled(first - 1) { + first -= 1; + } + first +} + +// `value` with its numbers to 3 significant digits, as precisely as a plot shows them: two frames +// whose plotted values agree to that precision look the same. With `flush`, for the solutions a +// plot draws on their ranges, numbers below 1e-6 in size count as 0 +fn coarse(value: &Value, flush: bool) -> String { + let join = |items: Vec| items.join(","); + match value { + Value::Number(number) if number.is_f64() => { + let number = number.as_f64().expect("f64"); + let number = if flush && number.abs() < 1e-6 { + 0.0 + } else { + number + }; + format!("{number:.2e}") + } + Value::Array(items) => { + format!( + "[{}]", + join(items.iter().map(|item| coarse(item, flush)).collect()) + ) + } + Value::Object(map) => { + let entry = |(key, item): (&String, &Value)| format!("{key}:{}", coarse(item, flush)); + format!("{{{}}}", join(map.iter().map(entry).collect())) + } + other => other.to_string(), + } +} + +// writes the settings and the frames to `path`, a frame per line +fn write(path: &str, settings: Value, frames: Vec) { + let frames: Vec = frames.iter().map(to_json).collect(); + let settings = to_json(&settings); + let head = &settings[..settings.len() - 1]; + let text = format!("{head},\"frames\":[\n{}\n]}}\n", frames.join(",\n")); + std::fs::write(path, text).expect("the trace is written"); +} + +// compact JSON with sorted keys, and numbers rounded to 6 significant digits and written as +// Python writes them (7542.0, 1e-08): the Python example writes the same file +fn to_json(value: &Value) -> String { + let join = |items: Vec| items.join(","); + match value { + Value::Number(number) if number.is_f64() => python_float(number.as_f64().expect("f64")), + Value::Array(items) => format!("[{}]", join(items.iter().map(to_json).collect())), + Value::Object(map) => { + let entry = + |(key, item): (&String, &Value)| format!("{}:{}", json!(key), to_json(item)); + format!("{{{}}}", join(map.iter().map(entry).collect())) + } + other => other.to_string(), + } +} + +fn python_float(value: f64) -> String { + let rounded: f64 = format!("{value:.5e}").parse().expect("a number"); + let shortest = format!("{rounded:e}"); + let (mantissa, exponent) = shortest.split_once('e').expect("an exponent"); + let exponent: i32 = exponent.parse().expect("an exponent"); + if (-4..16).contains(&exponent) { + let text = rounded.to_string(); + if text.contains('.') { + text + } else { + text + ".0" + } + } else { + let sign = if exponent < 0 { '-' } else { '+' }; + format!("{mantissa}e{sign}{:02}", exponent.abs()) + } +} diff --git a/examples/schaffer_f7/README.md b/examples/schaffer_f7/README.md new file mode 100644 index 00000000..6e5199cb --- /dev/null +++ b/examples/schaffer_f7/README.md @@ -0,0 +1,78 @@ +--- +title: Schaffer F7 +category: continuous +summary: Minimize Schaffer's F7, rings of ripples around the minimum, in 10 dimensions, with CMA-ES without and with restarts, DE, PSO and a GA from 10 seeds each. +reference: "Schaffer, J. D., Caruana, R. A., Eshelman, L. J. and Das, R. (1989). A study of control parameters affecting online performance of genetic algorithms for function optimization. Proceedings of the Third International Conference on Genetic Algorithms, Morgan Kaufmann: 51-60." +reference_url: "" +optimum: "0 (at the origin)" +languages: [rust, python] +order: 90 +trace_note: "Recorded from another run: CMA-ES with IPOP restarts in 2 dimensions, so that the population can be drawn on the function's contour." +--- + +# Schaffer F7 + +## The problem + +Schaffer's F7 measures the distance of each pair of neighboring genes and adds ripples to it: + +```text +f(x) = ((1 / (n − 1)) Σᵢ₌₁ⁿ⁻¹ √sᵢ (1 + sin²(50 sᵢ^(1/5))))², sᵢ = √(xᵢ² + xᵢ₊₁²) +each xᵢ in [−100, 100] +``` + +Its minimum is 0, at the origin. Here n = 10. Schaffer, Caruana, Eshelman and Das (1989) defined +F7 in two dimensions; their paper couldn't be read. This n-dimensional form is BBOB's f17 (Hansen +et al. 2009), without the transformations BBOB applies to it, and the bounds are those of Schaffer's +F6. The CEC 2017 report (Awad et al. 2016, function 19) prints sin for sin², and scales its search +space to [−0.5, 0.5]. The original is still to be checked (issue #168). + +## What makes it hard + +Around the minimum, each pair's term is a cone, √sᵢ, with rings of ripples whose frequency grows +as sᵢ^(1/5): near the origin the rings crowd together, each a local minimum that holds a search +whose steps are smaller than the ring's width. Far from it, the cone dominates and leads inwards. +The terms of neighboring pairs share a gene, so the rings of one pair cut across those of the next. + +## Representation + +A `Real` genome of 10 genes, each in [−100, 100]: the point x itself. The fitness is f(x), to +minimize. The function is genoxide's `problems::SchafferF7`, which brings its bounds and its +minimum. + +## Algorithm + +Five algorithms, each from seeds 1 to 10, with a budget of 10,000 evaluations per dimension, +100,000 per run, and a target of 1e-8: + +- CMA-ES (Hansen and Ostermeier, 2001, Evolutionary Computation 9(2): 159-195), which samples a + population of 10 from a normal distribution and adapts its mean, its step size and its covariance + matrix, from a step size of 0.3 of each gene's range and a random start; +- the same with IPOP restarts (Auger and Hansen, 2005, IEEE CEC 2005: 1769-1776): a run that has + converged starts again from a random point with twice the population; +- differential evolution with genoxide's defaults, SHADE (Tanabe and Fukunaga, CEC 2013), with a + population of 100 and its restarts on stagnation; +- particle swarm optimization (Kennedy and Eberhart, 1995), 40 particles with Clerc and Kennedy's + constriction coefficients and a global topology; +- a real-coded genetic algorithm: a population of 100, tournaments of 3, simulated binary crossover + (Deb and Agrawal, 1995) with η = 15 and polynomial mutation with η = 20 at a rate of 1/10 per + gene. + +## Output + +The first line gives the dimension, the seeds and the budget. Then a row per algorithm: how many +of its 10 runs reached the minimum, to within 1e-8, the median of their evaluations (a dash if none +did), and the median of every run's best error, to two significant digits. The function is +evaluated with genoxide's portable math, so the runs are the same on every platform, and in Python, +`run` evaluates it in Rust, so both versions print the same. + +[The project page](https://tachsin.gr/projects/genoxide/examples/schaffer-f7) plays back another run: +CMA-ES with IPOP restarts on the function in 2 dimensions, so that the population +can be drawn on its contour. It meets the target after 2,070 evaluations. + +## Good results + +The minimum is 0. CMA-ES with IPOP restarts reaches it in all 10 runs, after a median of 24,360 +evaluations, and SHADE in all 10, after 58,450. Without restarts, CMA-ES ends in a ring in every +run, with a median error of 0.10. PSO reaches the minimum once, and its median run ends at 7.7e-5; +the genetic algorithm's at 2.4e-3. diff --git a/examples/schaffer_f7/main.py b/examples/schaffer_f7/main.py new file mode 100644 index 00000000..38b629d5 --- /dev/null +++ b/examples/schaffer_f7/main.py @@ -0,0 +1,86 @@ +"""Schaffer F7: minimize Schaffer's F7, rings of ripples around the minimum, in 10 +dimensions. + +Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), +differential evolution (SHADE), particle swarm optimization and a real-coded genetic algorithm from +10 seeds each, and counts the runs that reach the minimum, 0 at the origin, to within 1e-8. The +function is genoxide's `problems::SchafferF7`, which run evaluates in Rust. + +With ``GENOXIDE_TRACE=``, it also writes a trace of a run for the plot on the example's page, +with trace.py. + + python examples/schaffer_f7/main.py +""" + +import genoxide as gx + +from trace import record_small + +DIMENSIONS = 10 +SEEDS = 10 +BUDGET = 10_000 * DIMENSIONS +# a run stops once its error to the minimum is at most this +ERROR = 1e-8 +ALGORITHMS = ["CMA-ES", "CMA-ES with IPOP", "DE", "PSO", "GA"] + + +def build(name, genome, seed): + """The algorithm called ``name``, on ``genome``, from ``seed``.""" + if name == "CMA-ES": + return gx.Cmaes(genome, objective="minimize", seed=seed) + if name == "CMA-ES with IPOP": + return gx.Cmaes(genome, restarts="ipop", objective="minimize", seed=seed) + if name == "DE": + return gx.De(genome, objective="minimize", seed=seed) + if name == "PSO": + return gx.Pso(genome, population_size=40, objective="minimize", seed=seed) + return gx.Ga( + genome, + population_size=100, + select=gx.Tournament(3), + crossover=gx.SimulatedBinaryCrossover(15.0), + mutation=gx.PolynomialMutation(20.0, rate=1 / DIMENSIONS), + objective="minimize", + seed=seed, + ) + + +def median(values): + """The median of ``values``, None without any.""" + values = sorted(values) + middle = len(values) // 2 + if not values: + return None + return values[middle] if len(values) % 2 else (values[middle - 1] + values[middle]) / 2 + + +def error_text(error): + """An error to two significant digits, as Rust writes it: 9.9e-9.""" + mantissa, exponent = f"{error:.1e}".split("e") + return f"{mantissa}e{int(exponent)}" + + +problem = gx.problems.SchafferF7(DIMENSIONS) +minimum = problem.optimum.value +print(f"Schaffer F7 in {DIMENSIONS} dimensions, {SEEDS} seeds, {BUDGET} evaluations at most per run") +print("algorithm at min evaluations median error") +for name in ALGORITHMS: + # the evaluations of the runs that reach the minimum, and every run's best error + evaluations, errors = [], [] + for seed in range(1, SEEDS + 1): + result = build(name, problem.genome, seed).run( + problem, target=minimum + ERROR, evaluations=BUDGET + ) + if result.stop_reason == "target": + evaluations.append(float(result.evaluations)) + # rounding can put a solution a few ulps below the minimum + errors.append(max(result.best_fitness - minimum, 0.0)) + reached = f"{len(evaluations)}/{SEEDS}" + middle = median(evaluations) + evaluations_text = "-" if middle is None else f"{middle:.0f}" + print(f"{name:<16} {reached:>6} {evaluations_text:>11} {error_text(median(errors)):>12}") +print("evaluations: the median of the runs that reach the minimum") + +# with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate run in +# 2 dimensions: the plot is the function's contour +record_small() diff --git a/examples/schaffer_f7/main.rs b/examples/schaffer_f7/main.rs new file mode 100644 index 00000000..e6cf48da --- /dev/null +++ b/examples/schaffer_f7/main.rs @@ -0,0 +1,118 @@ +//! Schaffer F7: minimize Schaffer's F7, rings of ripples around the minimum, in 10 +//! dimensions. +//! +//! Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), +//! differential evolution (SHADE), particle swarm optimization and a real-coded genetic algorithm +//! from 10 seeds each, and counts the runs that reach the minimum, 0 at the origin, to within +//! 1e-8. The function is genoxide's `problems::SchafferF7`. +//! +//! With `GENOXIDE_TRACE=`, it also writes a trace of a run for the plot on the example's +//! page, with `trace.rs`. +//! +//! ```text +//! cargo run --release --example schaffer_f7 +//! ``` + +mod trace; + +use genoxide::prelude::*; +use genoxide::problems::{SchafferF7, Problem}; + +const DIMENSIONS: usize = 10; +const SEEDS: u64 = 10; +const BUDGET: u64 = 10_000 * DIMENSIONS as u64; +// a run stops once its error to the minimum is at most this +const ERROR: f64 = 1e-8; +const ALGORITHMS: [&str; 5] = ["CMA-ES", "CMA-ES with IPOP", "DE", "PSO", "GA"]; + +fn main() -> Result<()> { + let problem = SchafferF7::new(DIMENSIONS); + let minimum = problem.optimum().expect("known").value(); + println!( + "Schaffer F7 in {DIMENSIONS} dimensions, {SEEDS} seeds, {BUDGET} evaluations at most per run" + ); + println!("algorithm at min evaluations median error"); + for algorithm in ALGORITHMS { + // the evaluations of the runs that reach the minimum, and every run's best error + let mut evaluations = Vec::new(); + let mut errors = Vec::new(); + for seed in 1..=SEEDS { + let outcome = run(algorithm, problem, seed, minimum + ERROR)?; + if outcome.stop_reason() == StopReason::Target { + evaluations.push(outcome.evaluations() as f64); + } + // rounding can put a solution a few ulps below the minimum + let best = outcome.best_fitness().score().expect("valid"); + errors.push((best - minimum).max(0.0)); + } + let reached = format!("{}/{SEEDS}", evaluations.len()); + let evaluations = median(evaluations).map_or("-".to_string(), |e| format!("{e:.0}")); + let error = median(errors).expect("a run"); + println!( + "{algorithm:<16} {reached:>6} {evaluations:>11} {:>12}", + format!("{error:.1e}") + ); + } + println!("evaluations: the median of the runs that reach the minimum"); + + // with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate + // run in 2 dimensions: the plot is the function's contour + trace::record_small()?; + Ok(()) +} + +// a run of `algorithm` from `seed`, until its best is at most `target` or it has used BUDGET +// evaluations +fn run(algorithm: &str, problem: SchafferF7, seed: u64, target: f64) -> Result> { + let real = problem.representation(); + let stop = Stop::target(target).or(Stop::evaluations(BUDGET)); + match algorithm { + "CMA-ES" | "CMA-ES with IPOP" => { + let restarts = if algorithm == "CMA-ES" { + cmaes::Restarts::Never + } else { + cmaes::Restarts::Ipop + }; + let cmaes = Cmaes::builder(real) + .restarts(restarts) + .minimize() + .seed(seed) + .build()?; + Engine::new(cmaes, problem).stop_when(stop).run() + } + "DE" => { + let de = De::builder(real).minimize().seed(seed).build()?; + Engine::new(de, problem).stop_when(stop).run() + } + "PSO" => { + let pso = Pso::builder(real) + .population_size(40) + .minimize() + .seed(seed) + .build()?; + Engine::new(pso, problem).stop_when(stop).run() + } + _ => { + let ga = Ga::builder(real) + .population_size(100) + .select(Tournament::new(3)?) + .crossover(SimulatedBinaryCrossover::new(15.0)?) + .mutate(PolynomialMutation::per_gene(1.0 / DIMENSIONS as f64, 20.0)?) + .minimize() + .seed(seed) + .build()?; + Engine::new(ga, problem).stop_when(stop).run() + } + } +} + +// the median of `values`, None without any +fn median(mut values: Vec) -> Option { + values.sort_by(f64::total_cmp); + let middle = values.len() / 2; + match values.len() { + 0 => None, + n if n % 2 == 1 => Some(values[middle]), + _ => Some((values[middle - 1] + values[middle]) / 2.0), + } +} diff --git a/examples/schaffer_f7/output.txt b/examples/schaffer_f7/output.txt new file mode 100644 index 00000000..03e5df97 --- /dev/null +++ b/examples/schaffer_f7/output.txt @@ -0,0 +1,8 @@ +Schaffer F7 in 10 dimensions, 10 seeds, 100000 evaluations at most per run +algorithm at min evaluations median error +CMA-ES 0/10 - 1.0e-1 +CMA-ES with IPOP 10/10 24360 8.7e-9 +DE 10/10 58450 8.8e-9 +PSO 1/10 25000 7.7e-5 +GA 0/10 - 2.4e-3 +evaluations: the median of the runs that reach the minimum diff --git a/examples/schaffer_f7/trace.json b/examples/schaffer_f7/trace.json new file mode 100644 index 00000000..c27433d6 --- /dev/null +++ b/examples/schaffer_f7/trace.json @@ -0,0 +1,102 @@ +{"example":"schaffer_f7","format":1,"log_y":true,"objective":"minimize","optimum":0.0,"plot":"contour","problem":{"bounds":[[-100.0,100.0],[-100.0,100.0]],"function":"schaffer_f7","minima":[[0.0,0.0]]},"x_label":"evaluations","y_label":"error","frames":[ +{"best":51.7924,"evaluations":6,"generation":0,"median":302.3,"state":{"best":[42.8992,-28.5787],"population":[[-80.5712,-24.4639],[21.9455,-61.072],[-54.0471,75.3763],[-21.4189,-92.999],[-75.1217,-72.6119],[42.8992,-28.5787]]}}, +{"best":39.4277,"evaluations":24,"generation":3,"median":111.572,"state":{"best":[24.5342,12.1416],"population":[[42.5653,14.0326],[-36.4051,-84.7179],[-50.1545,20.349],[-32.7527,-37.8093],[4.6031,61.0816],[-58.7418,-8.23787]]}}, +{"best":22.5741,"evaluations":36,"generation":5,"median":77.68,"state":{"best":[0.467626,-5.65904],"population":[[40.9128,18.9213],[0.467626,-5.65904],[21.9357,26.8369],[23.2059,-24.3523],[13.0607,68.103],[49.3515,41.4398]]}}, +{"best":14.9263,"evaluations":54,"generation":8,"median":54.9666,"state":{"best":[6.5873,-3.46185],"population":[[28.3922,19.7974],[21.1652,4.0494],[-12.1733,20.9603],[19.3967,5.22006],[2.62623,-13.4526],[20.9487,6.2115]]}}, +{"best":9.77406,"evaluations":66,"generation":10,"median":52.5125,"state":{"best":[6.06642,7.29628],"population":[[6.06642,7.29628],[15.6005,10.1281],[-12.8711,16.7885],[2.57578,-8.15619],[6.80928,16.4946],[14.2202,49.1707]]}}, +{"best":5.2124,"evaluations":84,"generation":13,"median":21.9484,"state":{"best":[4.61602,-1.90318],"population":[[16.816,-7.11594],[0.675467,-9.84131],[11.7964,-0.366647],[8.67287,8.63477],[15.3349,-16.8515],[4.61602,-1.90318]]}}, +{"best":5.2124,"evaluations":96,"generation":15,"median":19.9391,"state":{"best":[4.61602,-1.90318],"population":[[10.0241,3.77069],[9.32589,6.46934],[-10.2062,-16.983],[-1.3564,-13.6795],[3.72232,-5.53743],[-8.81024,-16.9024]]}}, +{"best":1.60736,"evaluations":114,"generation":18,"median":6.42794,"state":{"best":[0.0536551,0.423179],"population":[[-0.370547,-7.837],[-2.8682,-5.36742],[-1.86017,1.94823],[-1.71618,3.49529],[-1.73941,0.801917],[-1.07462,-2.17096]]}}, +{"best":1.60736,"evaluations":126,"generation":20,"median":7.5022,"state":{"best":[0.0536551,0.423179],"population":[[-0.820758,-2.76905],[6.80191,-0.594287],[1.16589,1.10556],[-0.620982,-1.70414],[3.30791,-2.50536],[2.50472,-8.57108]]}}, +{"best":1.60736,"evaluations":144,"generation":23,"median":4.62638,"state":{"best":[0.0536551,0.423179],"population":[[1.09414,-1.19726],[-0.796161,-1.08739],[1.17644,0.477682],[1.66288,0.106099],[4.50546,-1.13893],[1.13657,-2.08708]]}}, +{"best":0.568884,"evaluations":156,"generation":25,"median":2.13526,"state":{"best":[0.187082,0.107199],"population":[[0.187082,0.107199],[-0.469364,-0.401002],[-0.399773,-0.376709],[-1.82952,-0.303301],[-1.89579,-1.41339],[-3.22477,-0.521297]]}}, +{"best":0.525852,"evaluations":174,"generation":28,"median":2.06581,"state":{"best":[0.510262,0.124798],"population":[[0.621667,0.00434616],[-0.208788,-0.932025],[0.739051,-1.07018],[-0.276561,0.17244],[-0.895241,-0.312568],[0.0258043,-0.201307]]}}, +{"best":0.467955,"evaluations":186,"generation":30,"median":1.76177,"state":{"best":[0.0749038,0.337192],"population":[[-0.208732,0.623965],[-0.24289,0.208524],[-0.63583,0.0648115],[0.0133224,-0.519048],[0.713947,0.561754],[0.0131653,0.414856]]}}, +{"best":0.170315,"evaluations":204,"generation":33,"median":0.493536,"state":{"best":[0.11383,-0.101117],"population":[[0.0376536,0.271384],[0.135538,-0.0987072],[0.163586,0.0924005],[0.252352,-0.0368223],[0.185056,-0.212751],[0.234831,0.0990676]]}}, +{"best":0.104171,"evaluations":216,"generation":35,"median":0.248756,"state":{"best":[0.0144726,-0.0620715],"population":[[0.120584,-0.100454],[0.327957,-0.14219],[0.0144726,-0.0620715],[0.106487,0.0211958],[0.130768,-0.0550701],[-0.00798857,-0.199889]]}}, +{"best":0.0489929,"evaluations":234,"generation":38,"median":0.160972,"state":{"best":[0.0213588,0.0277411],"population":[[-0.0011716,-0.0596084],[0.131669,0.0194643],[-0.120274,-0.0256406],[0.0656795,-0.000816173],[0.11822,0.0998043],[-0.0189295,-0.158482]]}}, +{"best":0.0489929,"evaluations":246,"generation":40,"median":0.142677,"state":{"best":[0.0213588,0.0277411],"population":[[0.0658304,-0.0226031],[0.0212487,0.0294205],[0.00885793,0.0543173],[0.0261191,-0.0681034],[-0.0291302,-0.130305],[0.0506254,0.0197387]]}}, +{"best":0.0259015,"evaluations":264,"generation":43,"median":0.0883219,"state":{"best":[0.0132897,0.00507016],"population":[[-0.0062071,-0.038084],[0.00898817,-0.03129],[0.0442227,0.0277858],[0.0541775,-0.112049],[-0.00160722,0.0219229],[0.0120594,-0.0217791]]}}, +{"best":0.0106839,"evaluations":276,"generation":45,"median":0.0722583,"state":{"best":[0.000768491,-0.00835021],"population":[[0.0126693,-0.0224539],[-0.00390888,0.0359296],[0.00149678,-0.043282],[0.000768491,-0.00835021],[0.0072831,-0.0211021],[-0.0163466,0.0024352]]}}, +{"best":0.0102743,"evaluations":294,"generation":48,"median":0.0219015,"state":{"best":[0.00662348,6.83175e-05],"population":[[-0.0136036,0.0022326],[-0.00570035,-0.0132986],[0.0116278,0.0145217],[0.0167575,0.00382217],[0.00885354,-0.0125793],[-0.00207128,-0.00903406]]}}, +{"best":0.0102743,"evaluations":306,"generation":50,"median":0.0696209,"state":{"best":[0.00662348,6.83175e-05],"population":[[0.0301078,-0.0285127],[0.0114831,-0.00366662],[-0.0006148,-0.0110667],[0.0183729,-0.0366909],[0.0147505,-0.0183174],[0.01311,-0.00354078]]}}, +{"best":0.00178484,"evaluations":324,"generation":53,"median":0.0170408,"state":{"best":[-0.000449696,-0.000124574],"population":[[0.00463841,-0.00630157],[-0.0119313,-0.0111644],[0.000384965,-0.0255505],[0.00410129,-0.00794259],[0.011847,-0.00997135],[0.0150652,-0.0121043]]}}, +{"best":0.00178484,"evaluations":336,"generation":55,"median":0.0154046,"state":{"best":[-0.000449696,-0.000124574],"population":[[0.00177995,0.00227847],[0.00111658,0.0023445],[0.00264757,-0.0142886],[-0.0102987,-0.00579334],[-0.00191727,-0.00550946],[0.000429195,-0.00610109]]}}, +{"best":0.00178484,"evaluations":354,"generation":58,"median":0.0167463,"state":{"best":[-0.000449696,-0.000124574],"population":[[-0.00199074,-0.00267411],[-0.0025966,0.00467143],[0.000223179,0.00402412],[0.00296642,-0.00396391],[0.00958683,0.00622831],[-0.00449555,-0.00422255]]}}, +{"best":0.00178484,"evaluations":366,"generation":60,"median":0.00561029,"state":{"best":[-0.000449696,-0.000124574],"population":[[-0.000660816,0.0039408],[-0.0067165,0.000230389],[0.00270448,0.00192588],[0.000399834,0.00323259],[0.00158088,-0.0023035],[-0.00152127,-0.00119287]]}}, +{"best":0.00178484,"evaluations":384,"generation":63,"median":0.00844035,"state":{"best":[-0.000449696,-0.000124574],"population":[[0.00110972,-0.000787927],[-0.0001352,-0.00545197],[0.0035842,-0.00675357],[0.00252457,-0.00632244],[0.000670568,-0.00608893],[-0.000957804,0.00222966]]}}, +{"best":0.0012226,"evaluations":396,"generation":65,"median":0.00279448,"state":{"best":[0.000773473,0.000281267],"population":[[0.000533025,-0.00144334],[-0.00217366,-0.000378435],[0.000773473,0.000281267],[-0.000369544,0.000578507],[-0.000652886,-0.000925266],[-0.000991107,0.00102226]]}}, +{"best":0.000279746,"evaluations":414,"generation":68,"median":0.00387109,"state":{"best":[0.000153044,-9.21641e-05],"population":[[0.00034375,-0.00138676],[0.00145843,-0.000496452],[0.00260568,-5.03026e-05],[0.000603104,-0.000476338],[0.000794924,-0.000378442],[0.00205851,-0.000498955]]}}, +{"best":0.000279746,"evaluations":426,"generation":70,"median":0.00444497,"state":{"best":[0.000153044,-9.21641e-05],"population":[[0.000142153,-6.28985e-05],[-0.00193039,0.00129445],[-0.00176692,-0.000147364],[0.000188768,-0.001687],[-7.10434e-05,-0.000701064],[0.00088359,-0.00105763]]}}, +{"best":8.96292e-05,"evaluations":444,"generation":73,"median":0.00194275,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[0.000523393,-0.000197883],[-0.000301655,-0.000445683],[0.000667091,-0.000282104],[0.000169757,-0.000214241],[-0.000320183,0.000397065],[-0.000355148,0.000315894]]}}, +{"best":8.96292e-05,"evaluations":456,"generation":75,"median":0.0012396,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[0.000109868,0.000310754],[6.67424e-05,0.000280435],[-0.000390948,0.000157971],[0.00051008,6.16793e-06],[-0.000564979,-0.000281804],[0.000365712,-0.000122234]]}}, +{"best":8.96292e-05,"evaluations":474,"generation":78,"median":0.000535086,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[2.00629e-05,-0.000280816],[0.000377704,-5.71487e-05],[7.19147e-05,-0.000362645],[0.000334659,-3.1679e-05],[-9.56528e-05,7.2217e-05],[0.000147022,-0.000236165]]}}, +{"best":8.96292e-05,"evaluations":486,"generation":80,"median":0.000331368,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[-0.000126415,-5.4272e-06],[-0.000179845,2.03431e-05],[0.000114206,7.72901e-07],[-2.47759e-05,0.000136885],[-0.000187405,8.4089e-05],[-0.000191829,-8.03034e-08]]}}, +{"best":8.96292e-05,"evaluations":504,"generation":83,"median":0.000696129,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[-0.000369805,3.85567e-05],[-0.00030107,5.93166e-05],[8.04683e-06,-0.00013272],[-0.00037854,0.00023208],[-0.000271519,0.000213084],[-0.000304527,0.00015003]]}}, +{"best":8.96292e-05,"evaluations":522,"generation":86,"median":0.000285714,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[-0.000142669,-5.376e-05],[-0.000231144,-2.06881e-05],[-0.000132267,-0.00010569],[-0.000144339,-4.71059e-05],[-0.000206065,-0.000153859],[-0.000184861,-0.000128655]]}}, +{"best":8.96292e-05,"evaluations":534,"generation":88,"median":0.000301778,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[-0.00018242,-0.000250073],[-0.000125506,-0.000168994],[-0.000284624,3.07073e-07],[-0.000219914,-0.000139639],[-0.000152951,-6.64511e-05],[-0.000109933,-0.00024359]]}}, +{"best":8.96292e-05,"evaluations":552,"generation":91,"median":0.000232799,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[-4.187e-05,-0.000134289],[3.17336e-05,-0.00022155],[-6.9134e-05,-0.000243627],[3.81698e-05,-0.000217584],[-0.000116714,-0.000204798],[-4.87794e-05,-0.000218183]]}}, +{"best":8.96292e-05,"evaluations":564,"generation":93,"median":0.000309906,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[-5.58747e-05,-0.000188862],[4.32642e-05,-0.000184676],[1.19837e-06,-0.000110221],[-5.01333e-05,-7.22302e-05],[9.84401e-05,-0.000240305],[0.000248856,-0.000275445]]}}, +{"best":8.96292e-05,"evaluations":582,"generation":96,"median":0.000238502,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[-0.000104918,-0.000171705],[3.8607e-05,-0.00025007],[2.7427e-05,-0.00021419],[-3.76733e-06,-0.000236254],[-1.73485e-05,-0.00016706],[4.75643e-05,-0.000228789]]}}, +{"best":8.96292e-05,"evaluations":594,"generation":98,"median":0.000256425,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[3.9552e-05,-0.000192567],[-1.41755e-05,-0.00019191],[6.1895e-05,-0.000245486],[5.13588e-05,-0.000189425],[0.00011718,-0.00023284],[8.33456e-05,-0.000240808]]}}, +{"best":8.96292e-05,"evaluations":612,"generation":101,"median":0.000241608,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[9.06665e-05,-0.000236106],[3.8344e-05,-0.000193708],[8.66297e-05,-0.000192644],[7.94475e-05,-0.000187636],[7.74767e-05,-0.000180295],[4.33036e-05,-0.000208292]]}}, +{"best":8.96292e-05,"evaluations":624,"generation":103,"median":0.000238364,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[5.30069e-05,-0.000202663],[0.00010856,-0.000227198],[0.000113936,-0.000210694],[9.56779e-05,-0.000216944],[6.56392e-05,-0.000205723],[0.000100442,-0.000217633]]}}, +{"best":8.96292e-05,"evaluations":642,"generation":106,"median":0.000230116,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[7.82091e-05,-0.000212117],[6.57107e-05,-0.000215289],[8.19194e-05,-0.000210658],[6.72066e-05,-0.000218353],[6.70815e-05,-0.000209209],[6.22369e-05,-0.000209471]]}}, +{"best":8.96292e-05,"evaluations":654,"generation":108,"median":0.000229782,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[6.82461e-05,-0.000217703],[6.86894e-05,-0.000214829],[7.50244e-05,-0.000212545],[5.65656e-05,-0.000213764],[6.89973e-05,-0.000209597],[6.99606e-05,-0.000208919]]}}, +{"best":8.96292e-05,"evaluations":672,"generation":111,"median":0.000229662,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[5.05497e-05,-0.000214144],[6.25813e-05,-0.000216156],[5.90268e-05,-0.000215561],[6.17048e-05,-0.000212743],[6.66856e-05,-0.000214961],[5.81225e-05,-0.000210717]]}}, +{"best":8.96292e-05,"evaluations":684,"generation":113,"median":0.000229544,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[5.45628e-05,-0.000213212],[5.81615e-05,-0.000215002],[5.48667e-05,-0.00020989],[6.16705e-05,-0.000211714],[5.13353e-05,-0.000215481],[6.043e-05,-0.000214909]]}}, +{"best":8.96292e-05,"evaluations":702,"generation":116,"median":0.000229524,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[5.60927e-05,-0.000215135],[5.16735e-05,-0.000213745],[5.30003e-05,-0.000214119],[6.2728e-05,-0.000213965],[5.53714e-05,-0.000213228],[5.2405e-05,-0.00021335]]}}, +{"best":8.96292e-05,"evaluations":714,"generation":118,"median":0.00022949,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[5.37524e-05,-0.00021385],[5.56652e-05,-0.000214001],[5.31493e-05,-0.000213369],[5.36625e-05,-0.000214238],[5.24276e-05,-0.00021446],[5.38512e-05,-0.000213108]]}}, +{"best":8.96292e-05,"evaluations":732,"generation":121,"median":0.000229487,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[5.63842e-05,-0.000214014],[5.32046e-05,-0.000214525],[5.49278e-05,-0.000214011],[5.22817e-05,-0.000213904],[5.35398e-05,-0.000214392],[5.34584e-05,-0.000214224]]}}, +{"best":8.96292e-05,"evaluations":744,"generation":123,"median":0.000229487,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[5.57256e-05,-0.000213743],[5.52844e-05,-0.00021443],[5.53756e-05,-0.00021427],[5.42667e-05,-0.000214327],[5.5438e-05,-0.000213989],[5.50091e-05,-0.00021404]]}}, +{"best":8.96292e-05,"evaluations":762,"generation":126,"median":0.000229487,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[5.67367e-05,-0.000213399],[5.5058e-05,-0.000213779],[5.56992e-05,-0.000213831],[5.64258e-05,-0.000213459],[5.53953e-05,-0.000213872],[5.70253e-05,-0.000213508]]}}, +{"best":8.96292e-05,"evaluations":774,"generation":128,"median":0.000229487,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[5.44336e-05,-0.000214148],[5.60697e-05,-0.000213718],[5.57981e-05,-0.000213813],[5.49253e-05,-0.000214035],[5.55637e-05,-0.00021379],[5.50987e-05,-0.000213933]]}}, +{"best":8.96292e-05,"evaluations":792,"generation":131,"median":0.000229487,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[5.55979e-05,-0.000213827],[5.48881e-05,-0.000213982],[5.56807e-05,-0.000213787],[5.54875e-05,-0.000213892],[5.5731e-05,-0.000213816],[5.55857e-05,-0.000213909]]}}, +{"best":8.96292e-05,"evaluations":804,"generation":133,"median":0.000229487,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[5.57109e-05,-0.000213776],[5.55335e-05,-0.000213859],[5.55846e-05,-0.000213813],[5.56953e-05,-0.000213807],[5.54899e-05,-0.000213833],[5.56815e-05,-0.0002138]]}}, +{"best":8.96292e-05,"evaluations":822,"generation":136,"median":0.000229487,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[5.56568e-05,-0.000213808],[5.55075e-05,-0.000213831],[5.55561e-05,-0.000213843],[5.55256e-05,-0.000213837],[5.55533e-05,-0.000213836],[5.55492e-05,-0.000213812]]}}, +{"best":8.96292e-05,"evaluations":834,"generation":138,"median":0.000229487,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[5.55624e-05,-0.00021382],[5.54829e-05,-0.000213836],[5.55827e-05,-0.00021382],[5.55967e-05,-0.000213814],[5.55384e-05,-0.000213831],[5.5544e-05,-0.000213828]]}}, +{"best":8.96292e-05,"evaluations":852,"generation":141,"median":0.000229487,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[5.55342e-05,-0.000213833],[5.5544e-05,-0.00021383],[5.55437e-05,-0.000213828],[5.55315e-05,-0.000213832],[5.55461e-05,-0.000213827],[5.54862e-05,-0.000213842]]}}, +{"best":8.96292e-05,"evaluations":864,"generation":143,"median":0.000229487,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[5.55082e-05,-0.000213838],[5.55388e-05,-0.000213832],[5.55091e-05,-0.000213839],[5.55351e-05,-0.000213832],[5.5511e-05,-0.000213838],[5.55343e-05,-0.000213832]]}}, +{"best":8.96292e-05,"evaluations":882,"generation":146,"median":0.000229487,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[5.55239e-05,-0.000213835],[5.55283e-05,-0.000213833],[5.55407e-05,-0.00021383],[5.55409e-05,-0.00021383],[5.55329e-05,-0.000213832],[5.55234e-05,-0.000213835]]}}, +{"best":8.96292e-05,"evaluations":894,"generation":148,"median":0.000229487,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[5.55387e-05,-0.00021383],[5.5536e-05,-0.000213832],[5.55459e-05,-0.000213829],[5.55429e-05,-0.00021383],[5.55401e-05,-0.00021383],[5.55429e-05,-0.000213829]]}}, +{"best":8.96292e-05,"evaluations":912,"generation":151,"median":0.000229487,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[5.55562e-05,-0.000213826],[5.55781e-05,-0.00021382],[5.55662e-05,-0.000213823],[5.55514e-05,-0.000213827],[5.55451e-05,-0.00021383],[5.55641e-05,-0.000213823]]}}, +{"best":8.96292e-05,"evaluations":924,"generation":153,"median":0.000229487,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[5.55523e-05,-0.000213828],[5.55596e-05,-0.000213826],[5.55564e-05,-0.000213826],[5.55444e-05,-0.000213829],[5.55615e-05,-0.000213825],[5.5558e-05,-0.000213826]]}}, +{"best":8.96292e-05,"evaluations":954,"generation":156,"median":144.577,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[53.5849,-71.5627],[1.79626,-53.148],[-3.76349,1.98487],[1.00507,59.7277],[-24.065,0.174689],[73.1858,37.0706],[-14.0416,-71.7801],[-53.1383,34.5428],[-12.7229,-73.8668],[25.416,-1.25834],[48.7985,52.7368],[60.4683,-68.115]]}}, +{"best":8.96292e-05,"evaluations":978,"generation":158,"median":85.7299,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[-33.5029,-25.563],[40.8093,-36.4885],[26.0538,-11.3772],[-12.654,-36.9376],[-23.6292,-4.1554],[-1.81561,-56.9377],[34.3233,-19.7249],[-60.2677,10.0825],[-41.7499,9.90457],[-6.11948,-33.6063],[-49.8814,7.7828],[-34.9766,6.09732]]}}, +{"best":8.96292e-05,"evaluations":1014,"generation":161,"median":32.6513,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[-15.419,-8.04261],[-9.26208,0.0729883],[14.9637,-6.36958],[6.06358,8.99657],[0.898375,9.45689],[-4.60401,-9.34425],[20.0405,-18.693],[-5.93277,-12.1588],[6.84985,-14.4553],[-10.2721,-12.7848],[-17.4498,3.42863],[-23.4449,-11.2352]]}}, +{"best":8.96292e-05,"evaluations":1038,"generation":163,"median":33.0011,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[-9.25561,-16.4537],[-1.32837,-17.4083],[-7.39717,4.3215],[10.3103,-28.6965],[0.580487,-5.69059],[-8.29422,-20.3643],[1.97508,-2.35547],[2.94096,-7.99481],[14.6009,-14.6742],[-7.41749,6.18892],[1.0494,7.11764],[11.4821,-10.1698]]}}, +{"best":8.96292e-05,"evaluations":1074,"generation":166,"median":10.5913,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[2.57762,2.15042],[-11.9635,7.47245],[0.74676,1.94699],[-3.93583,-0.356441],[0.432763,4.34302],[1.01397,2.62173],[2.12972,0.674453],[-2.1751,4.01566],[-2.43208,3.96271],[0.0950761,1.39181],[-9.93936,7.83714],[-3.17063,1.93497]]}}, +{"best":8.96292e-05,"evaluations":1110,"generation":169,"median":3.86712,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[-0.58597,-1.73089],[-1.55475,1.42378],[-0.201264,-0.466943],[-3.17238,1.03049],[-2.53035,3.22886],[-1.96646,0.114188],[-2.44944,1.36919],[-0.895032,1.21099],[0.251108,-0.721164],[0.233581,0.412],[-3.06124,1.38687],[-0.80712,-0.798723]]}}, +{"best":8.96292e-05,"evaluations":1134,"generation":171,"median":2.93922,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[0.0965506,-0.323999],[0.307152,0.0929108],[-1.4567,0.25989],[-1.13981,0.482619],[-2.04932,0.442659],[-1.42923,0.366473],[-1.43314,2.34774],[0.435724,-0.949424],[-0.035497,-0.273946],[-1.51429,0.886403],[-1.15565,-1.81361],[-1.87979,0.851045]]}}, +{"best":8.96292e-05,"evaluations":1170,"generation":174,"median":0.994146,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[-0.1146,0.0396052],[-0.251895,0.387325],[-0.285057,-0.00752093],[-0.267371,-0.351989],[0.392064,-0.0284802],[-0.382685,-0.444675],[-0.256038,-0.0578342],[-0.0367632,0.0490341],[-0.320581,0.289453],[0.418844,0.24521],[-0.219686,0.310731],[0.788251,-0.734506]]}}, +{"best":8.96292e-05,"evaluations":1194,"generation":176,"median":0.577747,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[-0.0592684,0.0206277],[-0.0410726,-0.166567],[-0.268784,0.11039],[0.402549,-0.164887],[0.308233,-0.180693],[0.321588,-0.222488],[0.0569644,-0.10793],[-0.255392,0.425816],[-0.0865655,-0.174515],[-0.184178,-0.146193],[0.0563019,0.0492184],[0.124617,-0.463262]]}}, +{"best":8.96292e-05,"evaluations":1230,"generation":179,"median":0.187457,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[-0.10073,-0.0611145],[-0.138957,-0.0472472],[0.0321242,-0.138644],[-0.0556447,-0.087319],[-0.0858338,-0.0454948],[-0.00268376,-0.0448709],[0.0203281,0.0321175],[0.104934,0.0315851],[0.0514237,-0.0457213],[-0.0364079,-0.00265102],[0.0867232,-0.148825],[-0.085691,-0.020672]]}}, +{"best":8.96292e-05,"evaluations":1254,"generation":181,"median":0.147476,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[-0.0540219,0.0315337],[-0.0459607,-0.0110629],[-0.0466869,-0.0812359],[-0.0459728,-0.00754214],[-0.0248487,0.0597498],[-0.000723874,-0.0339651],[-0.0249684,-0.0865171],[-0.0305139,0.0716329],[-0.00231534,-0.0250797],[-0.0546343,-0.0426513],[0.00692269,0.0466833],[-0.0819794,-0.0742015]]}}, +{"best":8.96292e-05,"evaluations":1290,"generation":184,"median":0.0924049,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[-0.0765538,0.0278866],[-0.0143045,0.0328685],[0.0629401,0.0401708],[0.0161096,0.0212402],[0.00110614,0.0130651],[-0.00600814,-0.0432978],[0.0800208,0.0394262],[0.0319737,-0.0182433],[0.0578665,-0.0310552],[-0.0174491,-0.0137272],[0.0127479,-0.0524776],[0.0247402,-0.0923395]]}}, +{"best":8.96292e-05,"evaluations":1314,"generation":186,"median":0.0647655,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[-0.00279959,-0.036624],[-0.0168103,-0.0232031],[0.00523899,0.0232071],[0.0329096,0.0181831],[0.0270435,0.0334002],[0.00314131,-0.0273739],[0.00455057,-0.031701],[-0.0195759,-0.0181631],[0.0180327,0.00581815],[0.044872,-0.00273595],[-0.00406104,-0.0197221],[0.00613,-0.0291587]]}}, +{"best":8.96292e-05,"evaluations":1350,"generation":189,"median":0.035795,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[0.00773479,-0.0208015],[0.00758999,0.0111777],[0.0128474,0.00589401],[0.000474381,0.00261031],[0.0142105,0.0201387],[-0.000992342,-0.00455556],[0.0133915,0.0383466],[0.00735858,-0.00754895],[0.00538554,0.00344212],[-0.00385826,0.00916959],[0.0028725,-0.0277645],[-0.00477063,-0.0601062]]}}, +{"best":8.96292e-05,"evaluations":1374,"generation":191,"median":0.0178576,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[0.0024477,-0.000786603],[0.00316571,-0.00783164],[0.00631263,-0.0046448],[0.00551045,-2.02952e-05],[0.00332558,-0.00573877],[0.00368948,-0.0238652],[0.00467831,0.00171501],[-0.00723024,0.00183586],[-0.00223445,0.00531648],[0.00381998,-0.0214109],[0.00734051,-0.0102316],[0.00371013,-0.00293415]]}}, +{"best":8.96292e-05,"evaluations":1410,"generation":194,"median":0.00880853,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[0.00220404,-0.00628933],[-0.00574152,-0.00130146],[0.00487405,-0.00411785],[0.00688427,0.00263104],[-0.00194393,0.00232499],[0.00324247,-0.00267071],[-0.00816753,0.00349308],[-0.00126042,0.00194166],[0.000814078,0.000535713],[-0.00354685,0.00127565],[0.00205881,-0.00284055],[-0.00241656,0.00341239]]}}, +{"best":8.96292e-05,"evaluations":1434,"generation":196,"median":0.0037521,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[0.000735086,0.00145381],[0.000327108,0.00245643],[-0.00124739,0.00202397],[-0.00279252,-0.000637088],[-0.00150396,0.00251722],[0.00406802,-0.00404043],[-0.00198708,0.000986708],[0.0019624,0.00157518],[0.00116348,0.000296738],[7.37801e-05,0.000108764],[-0.00125034,0.000271425],[0.000362769,0.000284138]]}}, +{"best":8.96292e-05,"evaluations":1470,"generation":199,"median":0.00201167,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[-0.000547626,0.000548116],[-3.65621e-05,0.00052651],[0.0011779,0.000429691],[-0.000300182,-0.000161312],[-0.000247629,0.00230517],[3.23705e-05,0.000114383],[-0.000455299,-0.00046211],[-0.00119214,0.00130709],[0.000416523,-0.00101004],[-0.000924526,-0.000661336],[0.000348541,0.000532474],[0.000789126,0.0010007]]}}, +{"best":8.96292e-05,"evaluations":1494,"generation":201,"median":0.00131057,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[-0.000584657,0.000546352],[-0.000235074,0.000518012],[-0.000262093,0.000220837],[-0.000337189,-0.000139482],[0.000646222,6.9796e-05],[-4.4729e-06,-0.000191923],[0.000427088,0.000462648],[0.000149937,-0.000818315],[0.000274976,0.00047275],[0.000300219,0.000555384],[8.37287e-05,0.000286472],[0.000333685,-0.000724381]]}}, +{"best":8.96292e-05,"evaluations":1530,"generation":204,"median":0.000412711,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[-0.000201511,-0.000106987],[-0.000142486,0.000393696],[-0.000194287,0.000184621],[2.12021e-05,-0.00012623],[-0.000122005,0.000109176],[-9.62988e-05,-0.000221773],[0.000122404,-0.000275771],[-0.000349838,2.17437e-05],[0.000199561,-0.000145906],[-3.50016e-05,-0.000121896],[-4.99194e-05,0.000332091],[0.000127625,-0.000291653]]}}, +{"best":8.96292e-05,"evaluations":1554,"generation":206,"median":0.000406946,"state":{"best":[4.99394e-05,4.49254e-06],"population":[[-0.000357555,5.57347e-06],[-0.00021976,-0.000209265],[-0.000144994,-0.000259481],[-0.000194157,-1.86108e-05],[-9.12083e-05,-2.23953e-05],[9.21504e-05,-0.000311737],[-4.08994e-05,-6.51887e-05],[-0.000210703,-0.000243237],[-0.000186636,-0.00032571],[-4.75761e-05,-9.07524e-05],[-0.000155019,-0.000222424],[-3.98568e-05,-0.000255112]]}}, +{"best":2.90091e-05,"evaluations":1590,"generation":209,"median":0.000354559,"state":{"best":[-1.2651e-05,-2.10241e-05],"population":[[0.000254529,-0.000137602],[-7.74273e-05,-0.000196497],[-0.000194102,-9.16676e-05],[-0.000144071,-7.22942e-05],[-7.73614e-05,-0.000103819],[1.00403e-05,0.000122281],[0.000121038,-5.35402e-05],[-0.000116545,-0.000221089],[-9.47578e-05,-0.000263887],[-1.2651e-05,-2.10241e-05],[-0.000106717,2.30521e-05],[-8.81337e-05,-6.40531e-05]]}}, +{"best":2.90091e-05,"evaluations":1614,"generation":211,"median":0.000365002,"state":{"best":[-1.2651e-05,-2.10241e-05],"population":[[-0.00015246,1.62351e-06],[4.26885e-05,-0.000114081],[-0.000116155,4.19437e-05],[-9.25244e-06,-0.000116192],[3.2768e-05,-8.97575e-05],[-5.04775e-06,-4.42862e-05],[-8.27838e-05,-1.41021e-06],[-0.000165821,5.28269e-05],[-0.000130778,-5.70093e-05],[-3.95735e-05,-7.55593e-06],[-0.00019427,-0.000103599],[0.000131962,4.51747e-06]]}}, +{"best":2.90091e-05,"evaluations":1650,"generation":214,"median":0.000347598,"state":{"best":[-1.2651e-05,-2.10241e-05],"population":[[-2.02444e-05,-6.05747e-05],[-9.88877e-05,5.71339e-05],[-0.00010713,-9.95768e-05],[-0.00014197,-4.94294e-05],[-0.000104802,-8.54311e-05],[7.44797e-05,-5.71398e-06],[3.16698e-05,-3.39163e-05],[8.81429e-05,-2.95844e-05],[-0.000101914,-2.94616e-06],[0.000178254,-1.03638e-05],[-7.51212e-05,3.43358e-05],[5.93617e-05,-6.29624e-05]]}}, +{"best":2.90091e-05,"evaluations":1674,"generation":216,"median":0.000318862,"state":{"best":[-1.2651e-05,-2.10241e-05],"population":[[-3.79821e-05,-8.31671e-06],[0.00010746,-8.45033e-05],[-3.98746e-05,-4.8567e-05],[8.69899e-05,2.92692e-05],[2.63465e-05,-0.000113333],[3.84908e-05,-7.08676e-05],[-9.24796e-05,-2.32093e-05],[2.88619e-05,-2.44568e-05],[-1.03003e-05,-2.03314e-05],[-9.30773e-05,-3.3423e-05],[-6.80132e-05,2.86421e-05],[8.53326e-05,-1.29692e-05]]}}, +{"best":2.90091e-05,"evaluations":1710,"generation":219,"median":3.8382e-05,"state":{"best":[-1.2651e-05,-2.10241e-05],"population":[[1.37983e-06,-6.36198e-05],[2.96639e-05,-4.27676e-05],[-1.94713e-05,-2.35926e-05],[2.43062e-05,-4.58595e-05],[6.15973e-06,-1.42996e-05],[-2.26363e-05,-3.57549e-05],[1.39078e-05,-2.91439e-05],[3.98615e-06,-3.66605e-05],[1.4475e-05,-1.68931e-05],[9.05319e-07,-9.43408e-06],[4.42657e-05,-2.9101e-05],[1.74056e-06,-3.07285e-05]]}}, +{"best":8.86954e-07,"evaluations":1734,"generation":221,"median":3.14444e-05,"state":{"best":[-3.27815e-07,-8.15615e-07],"population":[[1.74804e-05,-1.68522e-05],[-1.22335e-05,-5.28429e-06],[6.04817e-06,-3.92563e-06],[3.76386e-05,-3.12808e-05],[-1.47149e-05,-2.88495e-05],[2.41223e-06,-2.532e-05],[9.56371e-06,-9.90383e-06],[5.98336e-06,-1.21502e-05],[6.9955e-06,-1.97422e-05],[-2.7096e-05,6.31507e-06],[-3.27815e-07,-8.15615e-07],[-1.52263e-05,-1.32367e-05]]}}, +{"best":8.86954e-07,"evaluations":1770,"generation":224,"median":3.66506e-05,"state":{"best":[-3.27815e-07,-8.15615e-07],"population":[[-2.14988e-05,-8.68598e-06],[-8.51453e-06,9.79031e-07],[9.87827e-06,-5.06137e-07],[-3.66366e-06,-9.55406e-06],[-3.57286e-06,-1.02266e-05],[-1.20929e-05,-4.76387e-06],[-9.48432e-06,-2.7364e-06],[-1.03549e-05,-2.5812e-05],[1.98588e-06,-1.36939e-05],[1.29379e-05,-1.06368e-05],[1.23008e-05,-7.38758e-06],[-2.14571e-05,-7.2465e-06]]}}, +{"best":8.86954e-07,"evaluations":1794,"generation":226,"median":3.3347e-05,"state":{"best":[-3.27815e-07,-8.15615e-07],"population":[[-2.55609e-05,-1.63843e-05],[-3.56307e-05,-1.48742e-05],[-4.97834e-06,-6.28246e-06],[-9.39059e-06,1.91555e-07],[8.53516e-06,-1.38305e-05],[-1.44456e-05,-1.10228e-05],[1.13373e-06,-1.39721e-06],[-2.10099e-05,-3.08111e-05],[3.88214e-06,-6.78468e-07],[-2.93028e-05,1.20172e-05],[9.77336e-06,-1.64445e-05],[-1.46895e-05,-6.1409e-06]]}}, +{"best":8.86954e-07,"evaluations":1830,"generation":229,"median":3.32069e-05,"state":{"best":[-3.27815e-07,-8.15615e-07],"population":[[-7.59705e-07,-8.54712e-06],[4.39408e-07,1.15882e-06],[-8.99284e-06,1.75103e-06],[3.12567e-06,1.58372e-06],[-6.22468e-06,-1.00055e-05],[-1.17012e-05,1.89919e-06],[-6.98788e-06,-2.06305e-06],[-1.13434e-05,-6.26224e-06],[-1.35885e-05,3.05385e-06],[-3.05302e-06,-5.82293e-07],[-1.79606e-05,-6.87368e-06],[8.56001e-08,1.93844e-06]]}}, +{"best":6.12573e-07,"evaluations":1854,"generation":231,"median":2.02279e-05,"state":{"best":[2.43193e-07,3.02471e-07],"population":[[4.16466e-06,3.56613e-06],[4.54575e-07,-2.39057e-06],[3.51105e-06,-4.17535e-06],[6.6333e-06,-9.22604e-07],[-1.05037e-05,-7.69032e-06],[-4.0006e-06,-2.93331e-06],[5.48611e-07,-4.74586e-06],[5.3698e-07,2.13919e-06],[6.18238e-06,-6.54555e-06],[5.64389e-06,2.88599e-06],[4.53411e-06,2.6285e-06],[6.72e-06,5.99719e-06]]}}, +{"best":4.76843e-07,"evaluations":1890,"generation":234,"median":7.60979e-06,"state":{"best":[9.5102e-08,-1.59397e-07],"population":[[-4.06153e-06,1.43312e-07],[-1.44494e-06,1.27637e-07],[-8.25957e-07,1.37703e-06],[-3.74576e-06,2.30957e-06],[3.382e-06,4.94891e-07],[9.5102e-08,-1.59397e-07],[-2.75259e-06,-1.46715e-06],[1.44361e-06,-2.72313e-06],[8.57363e-07,3.1158e-06],[-4.03455e-06,-2.43847e-06],[4.16035e-06,2.18949e-07],[2.6558e-07,1.93822e-06]]}}, +{"best":4.43349e-07,"evaluations":1914,"generation":236,"median":9.41679e-07,"state":{"best":[-1.37785e-07,8.01093e-08],"population":[[-9.24373e-08,5.79389e-07],[-1.55506e-06,-8.44386e-07],[-1.8212e-07,1.60231e-07],[-1.81718e-06,1.27411e-07],[-3.55608e-07,-4.73111e-07],[-1.82239e-06,3.49709e-08],[5.40173e-07,4.93797e-07],[-1.53731e-06,1.29474e-06],[-1.08956e-06,1.11279e-06],[4.29524e-07,-4.12794e-07],[-3.0329e-07,3.251e-09],[-1.04622e-06,-3.20275e-07]]}}, +{"best":4.00873e-07,"evaluations":1950,"generation":239,"median":6.83124e-07,"state":{"best":[6.05492e-09,-1.32178e-07],"population":[[-5.38178e-07,5.19962e-07],[-1.04516e-08,-2.74483e-07],[-3.6479e-07,8.79176e-07],[-2.52632e-07,4.63739e-07],[-6.57569e-07,2.55651e-07],[-2.40097e-07,-4.67308e-07],[-5.39236e-08,6.98575e-07],[-4.57183e-07,2.23721e-07],[4.01548e-07,8.80446e-08],[-2.19043e-07,-3.42003e-07],[1.00055e-07,-5.71797e-07],[5.19135e-07,-2.74842e-07]]}}, +{"best":4.00873e-07,"evaluations":1974,"generation":241,"median":7.24763e-07,"state":{"best":[6.05492e-09,-1.32178e-07],"population":[[1.49574e-07,-7.83896e-07],[5.7461e-07,-8.38117e-07],[3.5352e-07,-4.44611e-07],[-3.33816e-07,1.04065e-07],[-4.57767e-07,4.35589e-07],[3.81626e-07,-4.06299e-08],[3.83101e-07,-5.91569e-07],[-9.51577e-07,-2.05855e-07],[6.00682e-07,-2.36721e-07],[5.70321e-08,-2.80768e-07],[-5.09585e-07,-3.77262e-07],[3.93011e-07,-1.44511e-06]]}}, +{"best":1.39451e-07,"evaluations":2010,"generation":244,"median":4.98224e-07,"state":{"best":[-2.82806e-08,2.04923e-08],"population":[[3.07837e-07,-9.82446e-09],[1.94064e-07,-5.82158e-08],[1.75092e-07,-1.21249e-07],[1.48153e-08,5.04272e-08],[1.47853e-07,-8.72857e-08],[1.58529e-07,1.74287e-08],[3.37971e-08,-5.51455e-08],[5.00661e-09,8.06817e-08],[2.21087e-07,-4.75394e-08],[2.29935e-07,-5.9037e-08],[-1.39606e-07,-1.54728e-07],[1.59324e-07,-3.21056e-07]]}}, +{"best":7.42878e-08,"evaluations":2034,"generation":246,"median":2.84106e-07,"state":{"best":[-1.39749e-08,1.28097e-08],"population":[[1.3813e-08,4.64468e-08],[6.84725e-08,-1.76949e-07],[-7.20227e-09,-3.8181e-08],[7.48717e-08,-1.36139e-07],[-1.39749e-08,1.28097e-08],[3.49176e-09,-1.27992e-07],[1.60118e-08,9.0799e-08],[3.96723e-08,5.61922e-08],[5.75101e-08,-5.23124e-08],[-5.42649e-08,6.39485e-08],[6.93567e-08,-4.05033e-08],[-5.18961e-08,2.84217e-13]]}}, +{"best":6.51532e-10,"evaluations":2070,"generation":249,"median":1.22615e-07,"state":{"best":[6.45741e-11,3.46418e-10],"population":[[-1.944e-09,6.07989e-09],[-3.5244e-08,-3.29323e-08],[4.42874e-09,-3.49717e-08],[-2.6976e-08,-1.2546e-08],[6.45741e-11,3.46418e-10],[7.30105e-09,-2.5619e-08],[3.87089e-10,-4.74574e-09],[-6.7838e-08,4.4765e-08],[-1.29434e-08,8.08843e-09],[-1.77878e-08,-6.05269e-08],[-2.81045e-08,-3.23879e-08],[-1.18449e-08,-2.92551e-08]]}} +]} diff --git a/examples/schaffer_f7/trace.py b/examples/schaffer_f7/trace.py new file mode 100644 index 00000000..adc72cac --- /dev/null +++ b/examples/schaffer_f7/trace.py @@ -0,0 +1,189 @@ +"""The trace for the plot on the example's page, written to the file that ``GENOXIDE_TRACE`` +names. The plot draws the population on the function's contour, which needs two dimensions: the +trace is of a separate run of CMA-ES with IPOP restarts in 2 dimensions, with a budget of +20,000 evaluations, in at most 100 frames. The Rust example writes the same file.""" + +import json +import math +import os + +import genoxide as gx + + +def record_small(): + """Runs CMA-ES with IPOP restarts in 2 dimensions and writes its trace, if ``GENOXIDE_TRACE`` is set.""" + path = os.environ.get("GENOXIDE_TRACE") + if not path: + return + problem = gx.problems.SchafferF7(2) + minimum = problem.optimum.value + budget = 20_000 + cmaes = gx.Cmaes(problem.genome, restarts="ipop", objective="minimize", seed=1) + frames = Frames(100) + + def record(progress): + state = {"population": progress.population.tolist(), "best": progress.best_genome.tolist()} + frames.push(frame(progress, state, minimum)) + + cmaes.run(problem, target=minimum + 1e-8, evaluations=budget, on_generation=record) + low, high = problem.genome.bounds + settings = { + "format": 1, + "example": "schaffer_f7", + "objective": "minimize", + "x_label": "evaluations", + "y_label": "error", + "log_y": True, + "optimum": 0.0, + "plot": "contour", + "problem": { + "function": "schaffer_f7", + "bounds": [[float(low), float(high)]] * 2, + "minima": problem.optimum.solutions.tolist(), + }, + } + write(path, settings, frames.to_list()) + + +def frame(progress, state, minimum): + """The frame of a generation: its progress, the errors of its best and of its population's + median to ``minimum`` (rounding can put a solution a few ulps below it), and ``state``.""" + + def error(value): + return None if value is None else max(value - minimum, 0.0) + + return { + "generation": progress.generation, + "evaluations": progress.evaluations, + "best": error(progress.best_fitness), + "median": error(median(progress.scores)), + "state": state, + } + + +def median(scores): + """The median of the valid scores, None without any.""" + scores = sorted(float(score) for score in scores if not math.isnan(score)) + middle = len(scores) // 2 + if not scores: + return None + return scores[middle] if len(scores) % 2 else (scores[middle - 1] + scores[middle]) / 2 + + +# ---- the same in every example's trace ---------------------------------------------------------- + + +class Frames: + """The frames of at most ``most`` generations, from the part of the run where what the page + plots changes: the frames after the last change are left out (a run that reached its target, + or a front that no longer moves), and the rest are spread evenly over the generations up to + it. While the run goes, up to 8 × ``most`` frames are kept: every ``every``-th generation, + with ``every`` doubling whenever there are that many, and the last one.""" + + def __init__(self, most): + self.most, self.every, self.kept, self.last = most, 1, [], None + + def push(self, frame): + if frame["generation"] % self.every: + self.last = frame + return + self.kept.append(frame) + self.last = None + if len(self.kept) == 8 * self.most: + self.every *= 2 + self.kept = [kept for kept in self.kept if kept["generation"] % self.every == 0] + + def to_list(self): + frames = self.kept + ([self.last] if self.last else []) + active = frames[: last_change(frames) + 1] + count, most = len(active), max(self.most, 2) + if count <= most: + return active + return [active[(i * (count - 1) + (most - 1) // 2) // (most - 1)] for i in range(most)] + + +def last_change(frames): + """The index of the frame after which nothing the page plots changes. To 3 significant + digits, as a plot shows them: the best, the median and, for a single objective (a numeric + best), the state; to within a hundredth of their range over the run: a front's + hypervolumes, in the state or in a grid's series.""" + if not frames: + return 0 + last = len(frames) - 1 + number = lambda value: isinstance(value, (int, float)) and not isinstance(value, bool) + single = any(number(frame.get("best")) for frame in frames) + + def measures(frame): + values = [] + state = frame.get("state") + hypervolume = state.get("hypervolume") if isinstance(state, dict) else None + for value in (hypervolume, frame.get("series")): + if number(value): + values.append(float(value)) + elif isinstance(value, dict): + values.extend(float(v) for _, v in sorted(value.items()) if number(v)) + return values + + measured = [measures(frame) for frame in frames] + end = measured[last] + tolerance = [] + for k in range(len(end)): + values = [values[k] for values in measured if k < len(values)] + tolerance.append((max(values) - min(values)) / 100.0) + + def same(frame, final, key, flush=False): + return coarse(frame.get(key), flush) == coarse(final.get(key), flush) + + def settled(i): + frame, final = frames[i], frames[last] + return ( + same(frame, final, "best") + and same(frame, final, "median") + and (not single or same(frame, final, "state", flush=True)) + and len(measured[i]) == len(end) + and all(abs(v - e) <= t for v, e, t in zip(measured[i], end, tolerance)) + ) + + first = last + while first > 0 and settled(first - 1): + first -= 1 + return first + + +def coarse(value, flush=False): + """``value`` with its numbers to 3 significant digits, as precisely as a plot shows them: two + frames whose plotted values agree to that precision look the same. With ``flush``, for the + solutions a plot draws on their ranges, numbers below 1e-6 in size count as 0.""" + if isinstance(value, float): + if flush and abs(value) < 1e-6: + value = 0.0 + return f"{value:.2e}" + if isinstance(value, (list, tuple)): + return "[" + ",".join(coarse(item, flush) for item in value) + "]" + if isinstance(value, dict): + items = sorted(value.items()) + return "{" + ",".join(f"{key}:{coarse(item, flush)}" for key, item in items) + "}" + return json.dumps(value) + + +def write(path, settings, frames): + """Writes the settings and the frames to ``path``, a frame per line.""" + lines = ",\n".join(map(to_json, frames)) + with open(path, "w", encoding="utf-8", newline="\n") as file: + file.write(f'{to_json(settings)[:-1]},"frames":[\n{lines}\n]}}\n') + + +def to_json(value): + """Compact JSON with sorted keys, and numbers rounded to 6 significant digits, as the Rust + example writes it.""" + return json.dumps(rounded(value), sort_keys=True, separators=(",", ":"), ensure_ascii=False) + + +def rounded(value): + if isinstance(value, dict): + return {key: rounded(item) for key, item in value.items()} + if isinstance(value, (list, tuple)): + return [rounded(item) for item in value] + if isinstance(value, float): + return float(f"{value:.5e}") if math.isfinite(value) else None + return value diff --git a/examples/schaffer_f7/trace.rs b/examples/schaffer_f7/trace.rs new file mode 100644 index 00000000..0283321e --- /dev/null +++ b/examples/schaffer_f7/trace.rs @@ -0,0 +1,261 @@ +//! The trace for the plot on the example's page, written to the file that `GENOXIDE_TRACE` names. +//! The plot draws the population on the function's contour, which needs two dimensions: the trace +//! is of a separate run of CMA-ES with IPOP restarts in 2 dimensions, with a budget of +//! 20,000 evaluations, in at most 100 frames. The Python example writes the same +//! file. + +use genoxide::observer::Snapshot; +use genoxide::prelude::*; +use genoxide::problems::{Problem, SchafferF7}; +use serde_json::{Value, json}; + +// runs CMA-ES with IPOP restarts in 2 dimensions and writes its trace, if GENOXIDE_TRACE is set +pub fn record_small() -> Result<()> { + let Ok(path) = std::env::var("GENOXIDE_TRACE") else { + return Ok(()); + }; + let problem = SchafferF7::new(2); + let optimum = problem.optimum().expect("known"); + let minimum = optimum.value(); + let budget = 20_000; + let cmaes = Cmaes::builder(problem.representation()) + .restarts(cmaes::Restarts::Ipop) + .minimize() + .seed(1) + .build()?; + let mut frames = Frames::new(100); + Engine::new(cmaes, problem.clone()) + .stop_when(Stop::target(minimum + 1e-8).or(Stop::evaluations(budget))) + .on_generation(|snapshot| { + let population = snapshot.population().iter().map(|x| &x.genome()[..]); + let population: Vec<&[f64]> = population.collect(); + let best = &snapshot.best().genome()[..]; + let state = json!({ "population": population, "best": best }); + frames.push(frame(snapshot, state, minimum)); + }) + .run()?; + let bounds = problem.representation().bounds().to_vec(); + let bounds: Vec<[f64; 2]> = bounds.iter().map(|b| [*b.start(), *b.end()]).collect(); + let minima: Vec<&[f64]> = optimum.solutions().iter().map(|x| &x[..]).collect(); + let settings = json!({ + "format": 1, + "example": "schaffer_f7", + "objective": "minimize", + "x_label": "evaluations", + "y_label": "error", + "log_y": true, + "optimum": 0.0, + "plot": "contour", + "problem": { + "function": "schaffer_f7", + "bounds": bounds, + "minima": minima, + }, + }); + write(&path, settings, frames.into_vec()); + Ok(()) +} + +// the frame of a generation: its progress, the errors of its best and of its population's median +// to `minimum` (rounding can put a solution a few ulps below it), and `state` +fn frame(snapshot: &Snapshot<'_, Reals>, state: Value, minimum: f64) -> Value { + let progress = snapshot.progress(); + let error = |value: f64| (value - minimum).max(0.0); + let population = snapshot.population().iter(); + let scores = population.filter_map(|individual| individual.fitness()?.score()); + json!({ + "generation": progress.generation(), + "evaluations": progress.evaluations(), + "best": progress.best().and_then(Fitness::score).map(error), + "median": median(scores.collect()).map(error), + "state": state, + }) +} + +// the median of the scores, None without any +fn median(mut scores: Vec) -> Option { + scores.sort_by(f64::total_cmp); + let middle = scores.len() / 2; + match scores.len() { + 0 => None, + n if n % 2 == 1 => Some(scores[middle]), + _ => Some((scores[middle - 1] + scores[middle]) / 2.0), + } +} + +// ---- the same in every example's trace --------------------------------------------------------- + +// the frames of at most `most` generations, from the part of the run where what the page plots +// changes: the frames after the last change are left out (a run that reached its target, or a +// front that no longer moves), and the rest are spread evenly over the generations up to it. While +// the run goes, up to 8 × `most` frames are kept: every `every`-th generation, with `every` +// doubling whenever there are that many, and the last one. +struct Frames { + most: usize, + every: u64, + kept: Vec<(u64, Value)>, + last: Option<(u64, Value)>, +} + +impl Frames { + fn new(most: usize) -> Self { + let (every, kept, last) = (1, Vec::new(), None); + Self { + most, + every, + kept, + last, + } + } + + fn push(&mut self, frame: Value) { + let generation = frame["generation"].as_u64().expect("a generation"); + if !generation.is_multiple_of(self.every) { + self.last = Some((generation, frame)); + return; + } + self.kept.push((generation, frame)); + self.last = None; + if self.kept.len() == 8 * self.most { + self.every *= 2; + let every = self.every; + self.kept.retain(|(generation, _)| generation % every == 0); + } + } + + fn into_vec(self) -> Vec { + let frames = self.kept.into_iter().chain(self.last); + let frames: Vec = frames.map(|(_, frame)| frame).collect(); + let active = &frames[..=last_change(&frames)]; + let (count, most) = (active.len(), self.most.max(2)); + if count <= most { + return active.to_vec(); + } + let at = |i: usize| active[(i * (count - 1) + (most - 1) / 2) / (most - 1)].clone(); + (0..most).map(at).collect() + } +} + +// the index of the frame after which nothing the page plots changes. To 3 significant digits, as +// a plot shows them: the best, the median and, for a single objective (a numeric best), the state; +// to within a hundredth of their range over the run: a front's hypervolumes, in the state or in a +// grid's series +fn last_change(frames: &[Value]) -> usize { + let Some(last) = frames.len().checked_sub(1) else { + return 0; + }; + let single = frames.iter().any(|frame| frame["best"].is_number()); + let measures = |frame: &Value| -> Vec { + let mut values = Vec::new(); + for value in [&frame["state"]["hypervolume"], &frame["series"]] { + match value { + Value::Number(number) => values.extend(number.as_f64()), + Value::Object(map) => values.extend(map.values().filter_map(Value::as_f64)), + _ => {} + } + } + values + }; + let measured: Vec> = frames.iter().map(measures).collect(); + let end = &measured[last]; + let tolerance: Vec = (0..end.len()) + .map(|k| { + let values = measured.iter().filter_map(|values| values.get(k).copied()); + let (low, high) = values.fold((f64::INFINITY, f64::NEG_INFINITY), |(low, high), v| { + (low.min(v), high.max(v)) + }); + (high - low) / 100.0 + }) + .collect(); + let settled = |i: usize| { + let (frame, final_frame) = (&frames[i], &frames[last]); + let same = + |key: &str, flush: bool| coarse(&frame[key], flush) == coarse(&final_frame[key], flush); + same("best", false) + && same("median", false) + && (!single || same("state", true)) + && measured[i].len() == end.len() + && measured[i] + .iter() + .zip(end) + .zip(&tolerance) + .all(|((value, end), tolerance)| (value - end).abs() <= *tolerance) + }; + let mut first = last; + while first > 0 && settled(first - 1) { + first -= 1; + } + first +} + +// `value` with its numbers to 3 significant digits, as precisely as a plot shows them: two frames +// whose plotted values agree to that precision look the same. With `flush`, for the solutions a +// plot draws on their ranges, numbers below 1e-6 in size count as 0 +fn coarse(value: &Value, flush: bool) -> String { + let join = |items: Vec| items.join(","); + match value { + Value::Number(number) if number.is_f64() => { + let number = number.as_f64().expect("f64"); + let number = if flush && number.abs() < 1e-6 { + 0.0 + } else { + number + }; + format!("{number:.2e}") + } + Value::Array(items) => { + format!( + "[{}]", + join(items.iter().map(|item| coarse(item, flush)).collect()) + ) + } + Value::Object(map) => { + let entry = |(key, item): (&String, &Value)| format!("{key}:{}", coarse(item, flush)); + format!("{{{}}}", join(map.iter().map(entry).collect())) + } + other => other.to_string(), + } +} + +// writes the settings and the frames to `path`, a frame per line +fn write(path: &str, settings: Value, frames: Vec) { + let frames: Vec = frames.iter().map(to_json).collect(); + let settings = to_json(&settings); + let head = &settings[..settings.len() - 1]; + let text = format!("{head},\"frames\":[\n{}\n]}}\n", frames.join(",\n")); + std::fs::write(path, text).expect("the trace is written"); +} + +// compact JSON with sorted keys, and numbers rounded to 6 significant digits and written as +// Python writes them (7542.0, 1e-08): the Python example writes the same file +fn to_json(value: &Value) -> String { + let join = |items: Vec| items.join(","); + match value { + Value::Number(number) if number.is_f64() => python_float(number.as_f64().expect("f64")), + Value::Array(items) => format!("[{}]", join(items.iter().map(to_json).collect())), + Value::Object(map) => { + let entry = + |(key, item): (&String, &Value)| format!("{}:{}", json!(key), to_json(item)); + format!("{{{}}}", join(map.iter().map(entry).collect())) + } + other => other.to_string(), + } +} + +fn python_float(value: f64) -> String { + let rounded: f64 = format!("{value:.5e}").parse().expect("a number"); + let shortest = format!("{rounded:e}"); + let (mantissa, exponent) = shortest.split_once('e').expect("an exponent"); + let exponent: i32 = exponent.parse().expect("an exponent"); + if (-4..16).contains(&exponent) { + let text = rounded.to_string(); + if text.contains('.') { + text + } else { + text + ".0" + } + } else { + let sign = if exponent < 0 { '-' } else { '+' }; + format!("{mantissa}e{sign}{:02}", exponent.abs()) + } +} diff --git a/examples/step/README.md b/examples/step/README.md new file mode 100644 index 00000000..683f8869 --- /dev/null +++ b/examples/step/README.md @@ -0,0 +1,78 @@ +--- +title: Step +category: continuous +summary: Minimize a sphere of flat steps in 30 dimensions, whose gradient is 0 almost everywhere, and compare how fast CMA-ES, sep-CMA-ES, DE, PSO and a GA reach the minimum. +reference: "Yao, X., Liu, Y. and Lin, G. (1999). Evolutionary programming made faster. IEEE Transactions on Evolutionary Computation 3(2): 82-102." +reference_url: "https://doi.org/10.1109/4235.771163" +optimum: "0 (on the cube [−0.5, 0.5)ⁿ)" +languages: [rust, python] +order: 51 +trace_note: "Recorded from another run: CMA-ES in 2 dimensions, so that the population can be drawn on the function's contour." +--- + +# Step + +## The problem + +The step function rounds each gene to the nearest integer before squaring it: + +```text +f(x) = Σ ⌊xᵢ + 0.5⌋², each xᵢ in [−100, 100] +``` + +Its minimum is 0, on the whole cube [−0.5, 0.5)ⁿ, where every gene rounds to 0. Here n = 30. It's +Yao, Liu and Lin's (1999) f6, whose table I and appendix give this definition, the bounds, the +dimension and the minimum. De Jong's (1975) F3, which it's often credited to, is another step +function, Σ ⌊xᵢ⌋ on [−5.12, 5.12]⁵, with its minimum at a corner. + +## What makes it hard + +The function is a sphere made of flat terraces: its value is a whole number, and it changes only +where a gene crosses a half-integer. Its gradient is 0 almost everywhere, and a small step changes +nothing: a search sees many points of equal value and has to cross plateaus without a direction. +Yao, Liu and Lin chose it for that: their classical evolutionary programming, whose steps were +small, ended far from the minimum, and Cauchy steps reached it. Near the minimum, the error counts +the genes off by one step: an error of 4 is four genes at ±1. + +## Representation + +A `Real` genome of 30 genes, each in [−100, 100]: the point x itself. The fitness is f(x), to +minimize. The function is genoxide's `problems::Step`, which brings its bounds and its minimum. + +## Algorithm + +Five algorithms, each with a budget of 10,000 evaluations per dimension, 300,000 in all, and the +target 0, from seed 1: + +- CMA-ES (Hansen and Ostermeier, 2001, Evolutionary Computation 9(2): 159-195), which samples a + population of 14 from a normal distribution and adapts its mean, its step size and its covariance + matrix, from a step size of 0.3 of each gene's range and a random start; +- sep-CMA-ES (Ros and Hansen, 2008, PPSN X: 296-305), the same with a diagonal covariance matrix: a + scale per gene but no correlations; +- differential evolution with genoxide's defaults, SHADE (Tanabe and Fukunaga, CEC 2013), with a + population of 100; +- particle swarm optimization (Kennedy and Eberhart, 1995), 40 particles with Clerc and Kennedy's + constriction coefficients and a global topology; +- a real-coded genetic algorithm: a population of 100, tournaments of 3, simulated binary crossover + (Deb and Agrawal, 1995) with η = 15 and polynomial mutation with η = 20 at a rate of 1/30 per + gene. + +## Output + +The first line gives the dimension and the budget. Then a table: a row per algorithm, the +evaluations it had used when its best error first reached each value of the heading, and the best +error it found, to two significant digits. A dash is an error not reached. The errors are whole numbers here, so the columns are 1000, 100, 10, 1 and 0. The function is +evaluated with genoxide's portable math, so the runs are the same on every platform, and in Python, +`run` evaluates it in Rust, so both versions print the same. + +[The project page](https://tachsin.gr/projects/genoxide/examples/step) plays back another +run: CMA-ES on the function in 2 dimensions, so that the population can be drawn on its +contour. It reaches the minimum after 114 evaluations. + +## Good results + +The minimum is 0. sep-CMA-ES reaches it after 1,848 evaluations and CMA-ES after 1,862: from a +step size of 60, a third of the range, the plateaus are small next to their steps, and they shrink +their steps no faster than they close in. SHADE reaches it after 11,600 evaluations and the genetic +algorithm after 25,390. PSO stops at an error of 4, four genes one step from 0: once the swarm has +gathered on a plateau, its particles slow down and see no better point near them. diff --git a/examples/step/main.py b/examples/step/main.py new file mode 100644 index 00000000..66e09271 --- /dev/null +++ b/examples/step/main.py @@ -0,0 +1,93 @@ +"""Step: minimize a sphere of flat steps in 30 dimensions, whose gradient is 0 almost +everywhere. + +Compares how fast CMA-ES, with a full and with a diagonal covariance matrix (sep-CMA-ES), +differential evolution, particle swarm optimization and a real-coded genetic algorithm close in on +the minimum, 0 on the cube [−0.5, 0.5)ⁿ: the evaluations each takes until its error is at most 1000, 100, 10, 1 and 0. +The function is genoxide's `problems::Step`. + +With ``GENOXIDE_TRACE=``, it also writes a trace of a run for the plot on the example's page, +with trace.py. + + python examples/step/main.py +""" + +import genoxide as gx + +from trace import record_small + +DIMENSIONS = 30 +BUDGET = 10_000 * DIMENSIONS +# the errors at which the table gives each run's evaluations +ERRORS = [1e3, 1e2, 1e1, 1e0, 0.0] +COLUMNS = ["1000", "100", "10", "1", "0"] + + +def error_text(error): + """An error to two significant digits, as Rust writes it: 9.9e-9.""" + mantissa, exponent = f"{error:.1e}".split("e") + return f"{mantissa}e{int(exponent)}" + + +class Reached: + """The evaluations after the first generation whose best error was at most each of ERRORS, + for a function whose minimum is ``minimum``.""" + + def __init__(self, minimum): + self.minimum = minimum + self.evaluations = [None] * len(ERRORS) + + def record(self, progress): + if progress.best_fitness is None: + return + error = progress.best_fitness - self.minimum + for i, bound in enumerate(ERRORS): + if self.evaluations[i] is None and error <= bound: + self.evaluations[i] = progress.evaluations + + def print(self, name, result): + """A row of the table: the evaluations, "-" for an error not reached, and the best + error.""" + cells = ["-" if reached is None else str(reached) for reached in self.evaluations] + # rounding can put a solution a few ulps below the minimum + cells.append(error_text(max(result.best_fitness - self.minimum, 0.0))) + print(f"{name:<10}" + "".join(f"{cell:>9}" for cell in cells)) + + +def compare(name, problem): + """The table of the five algorithms on ``problem``, after a line that names it.""" + minimum = problem.optimum.value + print(f"{name}: evaluations until the error is at most") + print(f"{'algorithm':<10}" + "".join(f"{column:>9}" for column in COLUMNS) + f"{'best':>9}") + genome = problem.genome + for label, algorithm in ( + ("CMA-ES", gx.Cmaes(genome, objective="minimize", seed=1)), + ("sep-CMA-ES", gx.Cmaes(genome, covariance="diagonal", objective="minimize", seed=1)), + ("DE", gx.De(genome, objective="minimize", seed=1)), + ("PSO", gx.Pso(genome, population_size=40, objective="minimize", seed=1)), + ( + "GA", + gx.Ga( + genome, + population_size=100, + select=gx.Tournament(3), + crossover=gx.SimulatedBinaryCrossover(15.0), + mutation=gx.PolynomialMutation(20.0, rate=1 / DIMENSIONS), + objective="minimize", + seed=1, + ), + ), + ): + reached = Reached(minimum) + result = algorithm.run( + problem, target=minimum + 1e-8, evaluations=BUDGET, on_generation=reached.record + ) + reached.print(label, result) + + +print(f"Step in {DIMENSIONS} dimensions, {BUDGET} evaluations at most") +compare("Step", gx.problems.Step(DIMENSIONS)) + +# with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate run in +# 2 dimensions: the plot is the function's contour +record_small() diff --git a/examples/step/main.rs b/examples/step/main.rs new file mode 100644 index 00000000..f375d99a --- /dev/null +++ b/examples/step/main.rs @@ -0,0 +1,147 @@ +//! Step: minimize a sphere of flat steps in 30 dimensions, whose gradient is 0 almost +//! everywhere. +//! +//! Compares how fast CMA-ES, with a full and with a diagonal covariance matrix (sep-CMA-ES), +//! differential evolution, particle swarm optimization and a real-coded genetic algorithm close in +//! on the minimum, 0 on the cube [−0.5, 0.5)ⁿ: the evaluations each takes until its error is at most 1000, 100, 10, 1 and 0. +//! The function is genoxide's `problems::Step`. +//! +//! With `GENOXIDE_TRACE=`, it also writes a trace of a run for the plot on the example's +//! page, with `trace.rs`. +//! +//! ```text +//! cargo run --release --example step +//! ``` + +mod trace; + +use genoxide::observer::Snapshot; +use genoxide::prelude::*; +use genoxide::problems::{Problem, Step}; + +const DIMENSIONS: usize = 30; +const BUDGET: u64 = 10_000 * DIMENSIONS as u64; +// the errors at which the table gives each run's evaluations +const ERRORS: [f64; 5] = [1e3, 1e2, 1e1, 1e0, 0.0]; +const COLUMNS: [&str; 5] = ["1000", "100", "10", "1", "0"]; + +fn main() -> Result<()> { + println!("Step in {DIMENSIONS} dimensions, {BUDGET} evaluations at most"); + compare("Step", &Step::new(DIMENSIONS))?; + // with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate + // run in 2 dimensions: the plot is the function's contour + trace::record_small()?; + Ok(()) +} + +// the table of the five algorithms on `problem`, after a line that names it +fn compare

(name: &str, problem: &P) -> Result<()> +where + P: Problem + FitnessFunction + Clone, +{ + let minimum = problem.optimum().expect("known").value(); + let stop = || Stop::target(minimum + 1e-8).or(Stop::evaluations(BUDGET)); + println!("{name}: evaluations until the error is at most"); + print!("{:<10}", "algorithm"); + COLUMNS.iter().for_each(|column| print!("{column:>9}")); + println!("{:>9}", "best"); + + for (name, covariance) in [ + ("CMA-ES", cmaes::Covariance::Full), + ("sep-CMA-ES", cmaes::Covariance::Diagonal), + ] { + let cmaes = Cmaes::builder(problem.representation()) + .covariance(covariance) + .minimize() + .seed(1) + .build()?; + let mut reached = Reached::new(minimum); + let outcome = Engine::new(cmaes, problem.clone()) + .stop_when(stop()) + .on_generation(|snapshot| reached.record(snapshot)) + .run()?; + reached.print(name, &outcome); + } + + let de = De::builder(problem.representation()) + .minimize() + .seed(1) + .build()?; + let mut reached = Reached::new(minimum); + let outcome = Engine::new(de, problem.clone()) + .stop_when(stop()) + .on_generation(|snapshot| reached.record(snapshot)) + .run()?; + reached.print("DE", &outcome); + + let pso = Pso::builder(problem.representation()) + .population_size(40) + .minimize() + .seed(1) + .build()?; + let mut reached = Reached::new(minimum); + let outcome = Engine::new(pso, problem.clone()) + .stop_when(stop()) + .on_generation(|snapshot| reached.record(snapshot)) + .run()?; + reached.print("PSO", &outcome); + + let ga = Ga::builder(problem.representation()) + .population_size(100) + .select(Tournament::new(3)?) + .crossover(SimulatedBinaryCrossover::new(15.0)?) + .mutate(PolynomialMutation::per_gene(1.0 / DIMENSIONS as f64, 20.0)?) + .minimize() + .seed(1) + .build()?; + let mut reached = Reached::new(minimum); + let outcome = Engine::new(ga, problem.clone()) + .stop_when(stop()) + .on_generation(|snapshot| reached.record(snapshot)) + .run()?; + reached.print("GA", &outcome); + Ok(()) +} + +// the evaluations after the first generation whose best error was at most each of ERRORS, for a +// function whose minimum is `minimum` +struct Reached { + minimum: f64, + evaluations: [Option; 5], +} + +impl Reached { + fn new(minimum: f64) -> Self { + let evaluations = [None; 5]; + Self { + minimum, + evaluations, + } + } + + fn record(&mut self, snapshot: &Snapshot<'_, Reals>) { + let progress = snapshot.progress(); + let Some(best) = progress.best().and_then(Fitness::score) else { + return; + }; + let error = best - self.minimum; + for (reached, bound) in self.evaluations.iter_mut().zip(ERRORS) { + if reached.is_none() && error <= bound { + *reached = Some(progress.evaluations()); + } + } + } + + // a row of the table: the evaluations, "-" for an error not reached, and the best error + fn print(&self, name: &str, outcome: &Outcome) { + print!("{name:<10}"); + for reached in self.evaluations { + let reached = reached.map_or("-".to_string(), |evaluations| evaluations.to_string()); + print!("{reached:>9}"); + } + // rounding can put a solution a few ulps below the minimum + let best = outcome.best_fitness().score().expect("valid"); + let error = (best - self.minimum).max(0.0); + println!("{:>9}", format!("{error:.1e}")); + } +} diff --git a/examples/step/output.txt b/examples/step/output.txt new file mode 100644 index 00000000..599a2eca --- /dev/null +++ b/examples/step/output.txt @@ -0,0 +1,8 @@ +Step in 30 dimensions, 300000 evaluations at most +Step: evaluations until the error is at most +algorithm 1000 100 10 1 0 best +CMA-ES 728 1148 1610 1848 1862 0.0e0 +sep-CMA-ES 686 980 1330 1582 1848 0.0e0 +DE 3900 6700 9100 11400 11600 0.0e0 +PSO 3400 5400 7800 - - 4.0e0 +GA 3805 5797 12977 18372 25390 0.0e0 diff --git a/examples/step/trace.json b/examples/step/trace.json new file mode 100644 index 00000000..5a4d38db --- /dev/null +++ b/examples/step/trace.json @@ -0,0 +1,21 @@ +{"example":"step","format":1,"log_y":true,"objective":"minimize","optimum":0.0,"plot":"contour","problem":{"bounds":[[-100.0,100.0],[-100.0,100.0]],"function":"step","minima":[[0.0,0.0]]},"x_label":"evaluations","y_label":"error","frames":[ +{"best":2690.0,"evaluations":6,"generation":0,"median":7839.0,"state":{"best":[42.8992,-28.5787],"population":[[-80.5712,-24.4639],[21.9455,-61.072],[-54.0471,75.3763],[-21.4189,-92.999],[-75.1217,-72.6119],[42.8992,-28.5787]]}}, +{"best":769.0,"evaluations":12,"generation":1,"median":3115.0,"state":{"best":[24.5342,12.1416],"population":[[-28.3686,-17.6739],[76.6402,-52.4176],[24.5342,12.1416],[-63.2581,33.0338],[-18.0719,-94.234],[34.1657,4.44898]]}}, +{"best":769.0,"evaluations":18,"generation":2,"median":7914.5,"state":{"best":[24.5342,12.1416],"population":[[42.2071,37.9849],[-69.5593,49.2276],[-56.3254,98.1044],[8.34435,-91.8491],[-64.1757,-76.1763],[-18.225,38.8598]]}}, +{"best":130.0,"evaluations":24,"generation":3,"median":3267.0,"state":{"best":[-3.44877,-11.3022],"population":[[75.2004,42.8326],[-7.26276,-60.2856],[-21.6203,49.4284],[-3.44877,-11.3022],[35.5592,91.9625],[-30.5874,19.5771]]}}, +{"best":130.0,"evaluations":30,"generation":4,"median":4043.0,"state":{"best":[-3.44877,-11.3022],"population":[[-86.6778,-28.2323],[31.6195,91.5101],[-63.7087,11.4238],[-49.1776,24.6039],[5.02423,51.0493],[-62.0848,-4.659]]}}, +{"best":125.0,"evaluations":36,"generation":5,"median":1445.5,"state":{"best":[-9.64656,-5.49374],"population":[[7.95878,39.4614],[-9.64656,-5.49374],[-9.09202,34.6161],[14.9457,-7.38133],[-34.0439,63.7319],[3.77234,63.3689]]}}, +{"best":50.0,"evaluations":42,"generation":6,"median":951.0,"state":{"best":[-7.23354,0.884067],"population":[[-31.4586,-5.8343],[-7.23354,0.884067],[-11.0386,28.075],[-39.9479,62.0958],[-28.4657,-1.12363],[-14.0826,36.5316]]}}, +{"best":50.0,"evaluations":48,"generation":7,"median":2120.5,"state":{"best":[-7.23354,0.884067],"population":[[-22.1684,-47.3436],[-23.9661,47.139],[-30.5884,27.5381],[12.08,41.9913],[2.8674,14.8853],[-21.8673,42.8084]]}}, +{"best":50.0,"evaluations":54,"generation":8,"median":337.0,"state":{"best":[-7.23354,0.884067],"population":[[6.08922,33.8554],[5.96711,16.5794],[-25.0466,17.9789],[4.2289,16.9013],[-2.13088,-7.00593],[5.06785,18.4468]]}}, +{"best":34.0,"evaluations":60,"generation":9,"median":714.0,"state":{"best":[4.74364,2.87112],"population":[[-6.04519,44.9642],[-33.358,23.135],[-10.2581,-5.7772],[4.74364,2.87112],[-4.93627,24.8393],[-7.14103,-26.6995]]}}, +{"best":2.0,"evaluations":66,"generation":10,"median":159.0,"state":{"best":[1.0409,1.25722],"population":[[1.0409,1.25722],[7.92407,7.06567],[-17.4315,3.69774],[3.09845,-14.1987],[-1.27361,10.0109],[-5.60041,42.7041]]}}, +{"best":2.0,"evaluations":72,"generation":11,"median":290.0,"state":{"best":[1.0409,1.25722],"population":[[2.97845,30.6014],[11.6656,11.5052],[-11.3265,17.1056],[5.84314,15.6267],[12.1659,1.58549],[1.50774,4.76512]]}}, +{"best":2.0,"evaluations":78,"generation":12,"median":235.5,"state":{"best":[1.0409,1.25722],"population":[[8.02926,5.42252],[22.7152,11.062],[-0.534661,8.31735],[5.07301,14.4367],[8.73883,-12.5342],[2.93274,16.3107]]}}, +{"best":2.0,"evaluations":84,"generation":13,"median":130.5,"state":{"best":[1.0409,1.25722],"population":[[10.1107,6.67226],[-1.38926,-1.17381],[3.80306,10.0297],[-1.8483,15.7832],[12.4657,-1.28653],[-1.19639,6.2919]]}}, +{"best":2.0,"evaluations":90,"generation":14,"median":58.5,"state":{"best":[1.0409,1.25722],"population":[[0.246918,-7.05241],[-5.93543,-0.803223],[1.76531,7.61309],[-11.4059,-3.68095],[4.80368,-0.296307],[-13.134,1.17808]]}}, +{"best":2.0,"evaluations":96,"generation":15,"median":76.5,"state":{"best":[1.0409,1.25722],"population":[[8.95956,5.07289],[8.34599,6.69793],[-4.15891,-7.7777],[1.8517,-5.65447],[5.00698,-0.652405],[-3.19007,-7.70963]]}}, +{"best":2.0,"evaluations":102,"generation":16,"median":89.5,"state":{"best":[1.0409,1.25722],"population":[[7.93806,-8.82413],[7.40083,-3.6248],[5.44277,1.42384],[9.04574,3.67311],[8.87962,-4.03309],[1.45092,-9.1123]]}}, +{"best":2.0,"evaluations":108,"generation":17,"median":87.0,"state":{"best":[1.0409,1.25722],"population":[[6.9031,1.84641],[5.22722,-10.2097],[6.70117,-0.481822],[10.591,0.467689],[2.28587,-0.669833],[10.8621,2.47497]]}}, +{"best":0.0,"evaluations":114,"generation":18,"median":7.5,"state":{"best":[-0.16681,-0.00494924],"population":[[6.44651,-4.34376],[3.72718,-4.2705],[0.546028,-0.726942],[-0.16681,-0.00494924],[1.20609,-1.1719],[3.12178,-2.18677]]}} +]} diff --git a/examples/step/trace.py b/examples/step/trace.py new file mode 100644 index 00000000..1ffe2d78 --- /dev/null +++ b/examples/step/trace.py @@ -0,0 +1,189 @@ +"""The trace for the plot on the example's page, written to the file that ``GENOXIDE_TRACE`` +names. The plot draws the population on the function's contour, which needs two dimensions: the +trace is of a separate run of CMA-ES in 2 dimensions, with a budget of +20,000 evaluations, in at most 100 frames. The Rust example writes the same file.""" + +import json +import math +import os + +import genoxide as gx + + +def record_small(): + """Runs CMA-ES in 2 dimensions and writes its trace, if ``GENOXIDE_TRACE`` is set.""" + path = os.environ.get("GENOXIDE_TRACE") + if not path: + return + problem = gx.problems.Step(2) + minimum = problem.optimum.value + budget = 20_000 + cmaes = gx.Cmaes(problem.genome, objective="minimize", seed=1) + frames = Frames(100) + + def record(progress): + state = {"population": progress.population.tolist(), "best": progress.best_genome.tolist()} + frames.push(frame(progress, state, minimum)) + + cmaes.run(problem, target=minimum + 1e-8, evaluations=budget, on_generation=record) + low, high = problem.genome.bounds + settings = { + "format": 1, + "example": "step", + "objective": "minimize", + "x_label": "evaluations", + "y_label": "error", + "log_y": True, + "optimum": 0.0, + "plot": "contour", + "problem": { + "function": "step", + "bounds": [[float(low), float(high)]] * 2, + "minima": problem.optimum.solutions.tolist(), + }, + } + write(path, settings, frames.to_list()) + + +def frame(progress, state, minimum): + """The frame of a generation: its progress, the errors of its best and of its population's + median to ``minimum`` (rounding can put a solution a few ulps below it), and ``state``.""" + + def error(value): + return None if value is None else max(value - minimum, 0.0) + + return { + "generation": progress.generation, + "evaluations": progress.evaluations, + "best": error(progress.best_fitness), + "median": error(median(progress.scores)), + "state": state, + } + + +def median(scores): + """The median of the valid scores, None without any.""" + scores = sorted(float(score) for score in scores if not math.isnan(score)) + middle = len(scores) // 2 + if not scores: + return None + return scores[middle] if len(scores) % 2 else (scores[middle - 1] + scores[middle]) / 2 + + +# ---- the same in every example's trace ---------------------------------------------------------- + + +class Frames: + """The frames of at most ``most`` generations, from the part of the run where what the page + plots changes: the frames after the last change are left out (a run that reached its target, + or a front that no longer moves), and the rest are spread evenly over the generations up to + it. While the run goes, up to 8 × ``most`` frames are kept: every ``every``-th generation, + with ``every`` doubling whenever there are that many, and the last one.""" + + def __init__(self, most): + self.most, self.every, self.kept, self.last = most, 1, [], None + + def push(self, frame): + if frame["generation"] % self.every: + self.last = frame + return + self.kept.append(frame) + self.last = None + if len(self.kept) == 8 * self.most: + self.every *= 2 + self.kept = [kept for kept in self.kept if kept["generation"] % self.every == 0] + + def to_list(self): + frames = self.kept + ([self.last] if self.last else []) + active = frames[: last_change(frames) + 1] + count, most = len(active), max(self.most, 2) + if count <= most: + return active + return [active[(i * (count - 1) + (most - 1) // 2) // (most - 1)] for i in range(most)] + + +def last_change(frames): + """The index of the frame after which nothing the page plots changes. To 3 significant + digits, as a plot shows them: the best, the median and, for a single objective (a numeric + best), the state; to within a hundredth of their range over the run: a front's + hypervolumes, in the state or in a grid's series.""" + if not frames: + return 0 + last = len(frames) - 1 + number = lambda value: isinstance(value, (int, float)) and not isinstance(value, bool) + single = any(number(frame.get("best")) for frame in frames) + + def measures(frame): + values = [] + state = frame.get("state") + hypervolume = state.get("hypervolume") if isinstance(state, dict) else None + for value in (hypervolume, frame.get("series")): + if number(value): + values.append(float(value)) + elif isinstance(value, dict): + values.extend(float(v) for _, v in sorted(value.items()) if number(v)) + return values + + measured = [measures(frame) for frame in frames] + end = measured[last] + tolerance = [] + for k in range(len(end)): + values = [values[k] for values in measured if k < len(values)] + tolerance.append((max(values) - min(values)) / 100.0) + + def same(frame, final, key, flush=False): + return coarse(frame.get(key), flush) == coarse(final.get(key), flush) + + def settled(i): + frame, final = frames[i], frames[last] + return ( + same(frame, final, "best") + and same(frame, final, "median") + and (not single or same(frame, final, "state", flush=True)) + and len(measured[i]) == len(end) + and all(abs(v - e) <= t for v, e, t in zip(measured[i], end, tolerance)) + ) + + first = last + while first > 0 and settled(first - 1): + first -= 1 + return first + + +def coarse(value, flush=False): + """``value`` with its numbers to 3 significant digits, as precisely as a plot shows them: two + frames whose plotted values agree to that precision look the same. With ``flush``, for the + solutions a plot draws on their ranges, numbers below 1e-6 in size count as 0.""" + if isinstance(value, float): + if flush and abs(value) < 1e-6: + value = 0.0 + return f"{value:.2e}" + if isinstance(value, (list, tuple)): + return "[" + ",".join(coarse(item, flush) for item in value) + "]" + if isinstance(value, dict): + items = sorted(value.items()) + return "{" + ",".join(f"{key}:{coarse(item, flush)}" for key, item in items) + "}" + return json.dumps(value) + + +def write(path, settings, frames): + """Writes the settings and the frames to ``path``, a frame per line.""" + lines = ",\n".join(map(to_json, frames)) + with open(path, "w", encoding="utf-8", newline="\n") as file: + file.write(f'{to_json(settings)[:-1]},"frames":[\n{lines}\n]}}\n') + + +def to_json(value): + """Compact JSON with sorted keys, and numbers rounded to 6 significant digits, as the Rust + example writes it.""" + return json.dumps(rounded(value), sort_keys=True, separators=(",", ":"), ensure_ascii=False) + + +def rounded(value): + if isinstance(value, dict): + return {key: rounded(item) for key, item in value.items()} + if isinstance(value, (list, tuple)): + return [rounded(item) for item in value] + if isinstance(value, float): + return float(f"{value:.5e}") if math.isfinite(value) else None + return value diff --git a/examples/step/trace.rs b/examples/step/trace.rs new file mode 100644 index 00000000..290ac863 --- /dev/null +++ b/examples/step/trace.rs @@ -0,0 +1,260 @@ +//! The trace for the plot on the example's page, written to the file that `GENOXIDE_TRACE` names. +//! The plot draws the population on the function's contour, which needs two dimensions: the trace +//! is of a separate run of CMA-ES in 2 dimensions, with a budget of +//! 20,000 evaluations, in at most 100 frames. The Python example writes the same +//! file. + +use genoxide::observer::Snapshot; +use genoxide::prelude::*; +use genoxide::problems::{Problem, Step}; +use serde_json::{Value, json}; + +// runs CMA-ES in 2 dimensions and writes its trace, if GENOXIDE_TRACE is set +pub fn record_small() -> Result<()> { + let Ok(path) = std::env::var("GENOXIDE_TRACE") else { + return Ok(()); + }; + let problem = Step::new(2); + let optimum = problem.optimum().expect("known"); + let minimum = optimum.value(); + let budget = 20_000; + let cmaes = Cmaes::builder(problem.representation()) + .minimize() + .seed(1) + .build()?; + let mut frames = Frames::new(100); + Engine::new(cmaes, problem.clone()) + .stop_when(Stop::target(minimum + 1e-8).or(Stop::evaluations(budget))) + .on_generation(|snapshot| { + let population = snapshot.population().iter().map(|x| &x.genome()[..]); + let population: Vec<&[f64]> = population.collect(); + let best = &snapshot.best().genome()[..]; + let state = json!({ "population": population, "best": best }); + frames.push(frame(snapshot, state, minimum)); + }) + .run()?; + let bounds = problem.representation().bounds().to_vec(); + let bounds: Vec<[f64; 2]> = bounds.iter().map(|b| [*b.start(), *b.end()]).collect(); + let minima: Vec<&[f64]> = optimum.solutions().iter().map(|x| &x[..]).collect(); + let settings = json!({ + "format": 1, + "example": "step", + "objective": "minimize", + "x_label": "evaluations", + "y_label": "error", + "log_y": true, + "optimum": 0.0, + "plot": "contour", + "problem": { + "function": "step", + "bounds": bounds, + "minima": minima, + }, + }); + write(&path, settings, frames.into_vec()); + Ok(()) +} + +// the frame of a generation: its progress, the errors of its best and of its population's median +// to `minimum` (rounding can put a solution a few ulps below it), and `state` +fn frame(snapshot: &Snapshot<'_, Reals>, state: Value, minimum: f64) -> Value { + let progress = snapshot.progress(); + let error = |value: f64| (value - minimum).max(0.0); + let population = snapshot.population().iter(); + let scores = population.filter_map(|individual| individual.fitness()?.score()); + json!({ + "generation": progress.generation(), + "evaluations": progress.evaluations(), + "best": progress.best().and_then(Fitness::score).map(error), + "median": median(scores.collect()).map(error), + "state": state, + }) +} + +// the median of the scores, None without any +fn median(mut scores: Vec) -> Option { + scores.sort_by(f64::total_cmp); + let middle = scores.len() / 2; + match scores.len() { + 0 => None, + n if n % 2 == 1 => Some(scores[middle]), + _ => Some((scores[middle - 1] + scores[middle]) / 2.0), + } +} + +// ---- the same in every example's trace --------------------------------------------------------- + +// the frames of at most `most` generations, from the part of the run where what the page plots +// changes: the frames after the last change are left out (a run that reached its target, or a +// front that no longer moves), and the rest are spread evenly over the generations up to it. While +// the run goes, up to 8 × `most` frames are kept: every `every`-th generation, with `every` +// doubling whenever there are that many, and the last one. +struct Frames { + most: usize, + every: u64, + kept: Vec<(u64, Value)>, + last: Option<(u64, Value)>, +} + +impl Frames { + fn new(most: usize) -> Self { + let (every, kept, last) = (1, Vec::new(), None); + Self { + most, + every, + kept, + last, + } + } + + fn push(&mut self, frame: Value) { + let generation = frame["generation"].as_u64().expect("a generation"); + if !generation.is_multiple_of(self.every) { + self.last = Some((generation, frame)); + return; + } + self.kept.push((generation, frame)); + self.last = None; + if self.kept.len() == 8 * self.most { + self.every *= 2; + let every = self.every; + self.kept.retain(|(generation, _)| generation % every == 0); + } + } + + fn into_vec(self) -> Vec { + let frames = self.kept.into_iter().chain(self.last); + let frames: Vec = frames.map(|(_, frame)| frame).collect(); + let active = &frames[..=last_change(&frames)]; + let (count, most) = (active.len(), self.most.max(2)); + if count <= most { + return active.to_vec(); + } + let at = |i: usize| active[(i * (count - 1) + (most - 1) / 2) / (most - 1)].clone(); + (0..most).map(at).collect() + } +} + +// the index of the frame after which nothing the page plots changes. To 3 significant digits, as +// a plot shows them: the best, the median and, for a single objective (a numeric best), the state; +// to within a hundredth of their range over the run: a front's hypervolumes, in the state or in a +// grid's series +fn last_change(frames: &[Value]) -> usize { + let Some(last) = frames.len().checked_sub(1) else { + return 0; + }; + let single = frames.iter().any(|frame| frame["best"].is_number()); + let measures = |frame: &Value| -> Vec { + let mut values = Vec::new(); + for value in [&frame["state"]["hypervolume"], &frame["series"]] { + match value { + Value::Number(number) => values.extend(number.as_f64()), + Value::Object(map) => values.extend(map.values().filter_map(Value::as_f64)), + _ => {} + } + } + values + }; + let measured: Vec> = frames.iter().map(measures).collect(); + let end = &measured[last]; + let tolerance: Vec = (0..end.len()) + .map(|k| { + let values = measured.iter().filter_map(|values| values.get(k).copied()); + let (low, high) = values.fold((f64::INFINITY, f64::NEG_INFINITY), |(low, high), v| { + (low.min(v), high.max(v)) + }); + (high - low) / 100.0 + }) + .collect(); + let settled = |i: usize| { + let (frame, final_frame) = (&frames[i], &frames[last]); + let same = + |key: &str, flush: bool| coarse(&frame[key], flush) == coarse(&final_frame[key], flush); + same("best", false) + && same("median", false) + && (!single || same("state", true)) + && measured[i].len() == end.len() + && measured[i] + .iter() + .zip(end) + .zip(&tolerance) + .all(|((value, end), tolerance)| (value - end).abs() <= *tolerance) + }; + let mut first = last; + while first > 0 && settled(first - 1) { + first -= 1; + } + first +} + +// `value` with its numbers to 3 significant digits, as precisely as a plot shows them: two frames +// whose plotted values agree to that precision look the same. With `flush`, for the solutions a +// plot draws on their ranges, numbers below 1e-6 in size count as 0 +fn coarse(value: &Value, flush: bool) -> String { + let join = |items: Vec| items.join(","); + match value { + Value::Number(number) if number.is_f64() => { + let number = number.as_f64().expect("f64"); + let number = if flush && number.abs() < 1e-6 { + 0.0 + } else { + number + }; + format!("{number:.2e}") + } + Value::Array(items) => { + format!( + "[{}]", + join(items.iter().map(|item| coarse(item, flush)).collect()) + ) + } + Value::Object(map) => { + let entry = |(key, item): (&String, &Value)| format!("{key}:{}", coarse(item, flush)); + format!("{{{}}}", join(map.iter().map(entry).collect())) + } + other => other.to_string(), + } +} + +// writes the settings and the frames to `path`, a frame per line +fn write(path: &str, settings: Value, frames: Vec) { + let frames: Vec = frames.iter().map(to_json).collect(); + let settings = to_json(&settings); + let head = &settings[..settings.len() - 1]; + let text = format!("{head},\"frames\":[\n{}\n]}}\n", frames.join(",\n")); + std::fs::write(path, text).expect("the trace is written"); +} + +// compact JSON with sorted keys, and numbers rounded to 6 significant digits and written as +// Python writes them (7542.0, 1e-08): the Python example writes the same file +fn to_json(value: &Value) -> String { + let join = |items: Vec| items.join(","); + match value { + Value::Number(number) if number.is_f64() => python_float(number.as_f64().expect("f64")), + Value::Array(items) => format!("[{}]", join(items.iter().map(to_json).collect())), + Value::Object(map) => { + let entry = + |(key, item): (&String, &Value)| format!("{}:{}", json!(key), to_json(item)); + format!("{{{}}}", join(map.iter().map(entry).collect())) + } + other => other.to_string(), + } +} + +fn python_float(value: f64) -> String { + let rounded: f64 = format!("{value:.5e}").parse().expect("a number"); + let shortest = format!("{rounded:e}"); + let (mantissa, exponent) = shortest.split_once('e').expect("an exponent"); + let exponent: i32 = exponent.parse().expect("an exponent"); + if (-4..16).contains(&exponent) { + let text = rounded.to_string(); + if text.contains('.') { + text + } else { + text + ".0" + } + } else { + let sign = if exponent < 0 { '-' } else { '+' }; + format!("{mantissa}e{sign}{:02}", exponent.abs()) + } +} diff --git a/examples/sum_of_different_powers/README.md b/examples/sum_of_different_powers/README.md new file mode 100644 index 00000000..b73d79fb --- /dev/null +++ b/examples/sum_of_different_powers/README.md @@ -0,0 +1,91 @@ +--- +title: Sum of different powers +category: continuous +summary: Minimize the sum of the genes' absolute values to powers from 2 to 31 in 30 dimensions, as it is and shifted and rotated, and compare how fast CMA-ES, sep-CMA-ES, DE, PSO and a GA close in on the minimum. +reference: "Molga, M. and Smutnicki, C. (2005). Test functions for optimization needs." +reference_url: "" +optimum: "0 (at the origin)" +languages: [rust, python] +order: 50 +trace_note: "Recorded from another run: CMA-ES in 2 dimensions, so that the population can be drawn on the function's contour." +--- + +# Sum of different powers + +## The problem + +The sum of different powers raises each gene's absolute value to a power one more than its index, to +minimize: + +```text +f(x) = Σ |xᵢ|^(i+1), i from 1 to n, each xᵢ in [−1, 1] +``` + +Its minimum is 0, at the origin. Here n = 30, so the powers run from 2 to 31. Its origin is +unknown: genoxide takes the definition and the bounds from Molga and Smutnicki (2005, section +2.8), and they're still to be checked against an original (issue #168). An early version of the +CEC 2017 report had it, shifted and rotated, as its function 2. + +## What makes it hard + +It's unimodal and separable, and each term is smallest at 0. But the terms differ widely in how much +they matter. Near the minimum, the first gene's term is a parabola, while the thirtieth's, |x|³¹, +is flat: at x₃₀ = 0.5 it's 5·10⁻¹⁰, and an error of 1e-8 allows x₃₀ up to 0.55. A search reaches +small values long before the later genes are near 0, and the flatter terms give it little to +follow. + +Shifted and rotated, every direction mixes steep and flat terms, and the shapes that the steps +must learn are no longer along the axes. + +## Representation + +A `Real` genome of 30 genes, each in [−1, 1]: the point x itself. The fitness is f(x), to +minimize. The function is genoxide's `problems::SumOfDifferentPowers`, which brings its bounds and +its minimum. + +## Algorithm + +Five algorithms, each with a budget of 10,000 evaluations per dimension, 300,000 in all, and a +target of 1e-8, from seed 1: + +- CMA-ES (Hansen and Ostermeier, 2001, Evolutionary Computation 9(2): 159-195), which samples a + population of 14 from a normal distribution and adapts its mean, its step size and its covariance + matrix, from a step size of 0.3 of each gene's range and a random start; +- sep-CMA-ES (Ros and Hansen, 2008, PPSN X: 296-305), the same with a diagonal covariance matrix: a + scale per gene but no correlations; +- differential evolution with genoxide's defaults, SHADE (Tanabe and Fukunaga, CEC 2013), with a + population of 100; +- particle swarm optimization (Kennedy and Eberhart, 1995), 40 particles with Clerc and Kennedy's + constriction coefficients and a global topology; +- a real-coded genetic algorithm: a population of 100, tournaments of 3, simulated binary crossover + (Deb and Agrawal, 1995) with η = 15 and polynomial mutation with η = 20 at a rate of 1/30 per + gene. + +The second table runs the same algorithms on the function shifted and rotated, with genoxide's +`problems::Shifted` and `problems::Rotated` and seed 1: the minimum moves to a random point in the +middle 80% of the box, and an orthogonal matrix, drawn from normal numbers made orthonormal by +Gram-Schmidt as BBOB draws its rotations, turns the function about it. That's how the CEC and BBOB +suites use the function, with their own data; genoxide generates its instances instead. + +## Output + +The first line gives the dimension and the budget. Then two tables, the function as it is and shifted and rotated: a row per algorithm, the +evaluations it had used when its best error first reached each value of the heading, and the best +error it found, to two significant digits. A dash is an error not reached. The function is +evaluated with genoxide's portable math, so the runs are the same on every platform, and in Python, +`run` evaluates it in Rust, so both versions print the same. + +[The project page](https://tachsin.gr/projects/genoxide/examples/sum-of-different-powers) plays back another +run: CMA-ES on the function in 2 dimensions, |x₁|² + |x₂|³, so that the population can be +drawn on its contour. It meets the target after 204 evaluations. + +## Good results + +The minimum is 0. On the function as it is, sep-CMA-ES reaches 1e-8 first, after 2,464 +evaluations, then PSO (4,880), SHADE (6,500), CMA-ES (13,006) and the genetic algorithm (15,922): +every one gets there. The function is separable, and the methods that work a gene at a time, or +learn one scale per gene, are the fastest. + +Shifted and rotated, CMA-ES takes about as long as before, 12,334 evaluations: its full covariance +matrix learns the rotation. SHADE needs five times as many, 32,200, and PSO 243,400. sep-CMA-ES +reaches 1e-6 after 10,220 evaluations but ends at 1.4e-8, and the genetic algorithm at 5.9e-8. diff --git a/examples/sum_of_different_powers/main.py b/examples/sum_of_different_powers/main.py new file mode 100644 index 00000000..d47a4e0f --- /dev/null +++ b/examples/sum_of_different_powers/main.py @@ -0,0 +1,97 @@ +"""Sum of different powers: minimize the sum of the genes' absolute values to powers from 2 to 31, in 30 +dimensions: the later the gene, the flatter the function near the minimum. + +Compares how fast CMA-ES, with a full and with a diagonal covariance matrix (sep-CMA-ES), +differential evolution, particle swarm optimization and a real-coded genetic algorithm close in on +the minimum, 0 at the origin: the evaluations each takes until its error is at most 1, 1e-2, 1e-4, 1e-6 and 1e-8. +The function is genoxide's `problems::SumOfDifferentPowers`. Then the same on the function shifted and rotated, with genoxide's `problems::Shifted` +and `problems::Rotated`, as the CEC and BBOB suites transform it. + +With ``GENOXIDE_TRACE=``, it also writes a trace of a run for the plot on the example's page, +with trace.py. + + python examples/sum_of_different_powers/main.py +""" + +import genoxide as gx + +from trace import record_small + +DIMENSIONS = 30 +BUDGET = 10_000 * DIMENSIONS +# the errors at which the table gives each run's evaluations +ERRORS = [1e0, 1e-2, 1e-4, 1e-6, 1e-8] +COLUMNS = ["1", "1e-2", "1e-4", "1e-6", "1e-8"] + + +def error_text(error): + """An error to two significant digits, as Rust writes it: 9.9e-9.""" + mantissa, exponent = f"{error:.1e}".split("e") + return f"{mantissa}e{int(exponent)}" + + +class Reached: + """The evaluations after the first generation whose best error was at most each of ERRORS, + for a function whose minimum is ``minimum``.""" + + def __init__(self, minimum): + self.minimum = minimum + self.evaluations = [None] * len(ERRORS) + + def record(self, progress): + if progress.best_fitness is None: + return + error = progress.best_fitness - self.minimum + for i, bound in enumerate(ERRORS): + if self.evaluations[i] is None and error <= bound: + self.evaluations[i] = progress.evaluations + + def print(self, name, result): + """A row of the table: the evaluations, "-" for an error not reached, and the best + error.""" + cells = ["-" if reached is None else str(reached) for reached in self.evaluations] + # rounding can put a solution a few ulps below the minimum + cells.append(error_text(max(result.best_fitness - self.minimum, 0.0))) + print(f"{name:<10}" + "".join(f"{cell:>9}" for cell in cells)) + + +def compare(name, problem): + """The table of the five algorithms on ``problem``, after a line that names it.""" + minimum = problem.optimum.value + print(f"{name}: evaluations until the error is at most") + print(f"{'algorithm':<10}" + "".join(f"{column:>9}" for column in COLUMNS) + f"{'best':>9}") + genome = problem.genome + for label, algorithm in ( + ("CMA-ES", gx.Cmaes(genome, objective="minimize", seed=1)), + ("sep-CMA-ES", gx.Cmaes(genome, covariance="diagonal", objective="minimize", seed=1)), + ("DE", gx.De(genome, objective="minimize", seed=1)), + ("PSO", gx.Pso(genome, population_size=40, objective="minimize", seed=1)), + ( + "GA", + gx.Ga( + genome, + population_size=100, + select=gx.Tournament(3), + crossover=gx.SimulatedBinaryCrossover(15.0), + mutation=gx.PolynomialMutation(20.0, rate=1 / DIMENSIONS), + objective="minimize", + seed=1, + ), + ), + ): + reached = Reached(minimum) + result = algorithm.run( + problem, target=minimum + 1e-8, evaluations=BUDGET, on_generation=reached.record + ) + reached.print(label, result) + + +print(f"Sum of different powers in {DIMENSIONS} dimensions, {BUDGET} evaluations at most") +compare("Sum of different powers", gx.problems.SumOfDifferentPowers(DIMENSIONS)) +# the same function, shifted and rotated: the CEC 2017 report's first version had it so +rotated = gx.problems.Rotated(gx.problems.Shifted(gx.problems.SumOfDifferentPowers(DIMENSIONS), seed=1), seed=1) +compare("Shifted and rotated (seed 1)", rotated) + +# with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate run in +# 2 dimensions: the plot is the function's contour +record_small() diff --git a/examples/sum_of_different_powers/main.rs b/examples/sum_of_different_powers/main.rs new file mode 100644 index 00000000..7d9e09a3 --- /dev/null +++ b/examples/sum_of_different_powers/main.rs @@ -0,0 +1,151 @@ +//! Sum of different powers: minimize the sum of the genes' absolute values to powers from 2 to 31, in 30 +//! dimensions: the later the gene, the flatter the function near the minimum. +//! +//! Compares how fast CMA-ES, with a full and with a diagonal covariance matrix (sep-CMA-ES), +//! differential evolution, particle swarm optimization and a real-coded genetic algorithm close in +//! on the minimum, 0 at the origin: the evaluations each takes until its error is at most 1, 1e-2, 1e-4, 1e-6 and 1e-8. +//! The function is genoxide's `problems::SumOfDifferentPowers`. Then the same on the function shifted and rotated, with genoxide's `problems::Shifted` +//! and `problems::Rotated`, as the CEC and BBOB suites transform it. +//! +//! With `GENOXIDE_TRACE=`, it also writes a trace of a run for the plot on the example's +//! page, with `trace.rs`. +//! +//! ```text +//! cargo run --release --example sum_of_different_powers +//! ``` + +mod trace; + +use genoxide::observer::Snapshot; +use genoxide::prelude::*; +use genoxide::problems::{Problem, Rotated, Shifted, SumOfDifferentPowers}; + +const DIMENSIONS: usize = 30; +const BUDGET: u64 = 10_000 * DIMENSIONS as u64; +// the errors at which the table gives each run's evaluations +const ERRORS: [f64; 5] = [1e0, 1e-2, 1e-4, 1e-6, 1e-8]; +const COLUMNS: [&str; 5] = ["1", "1e-2", "1e-4", "1e-6", "1e-8"]; + +fn main() -> Result<()> { + println!("Sum of different powers in {DIMENSIONS} dimensions, {BUDGET} evaluations at most"); + compare("Sum of different powers", &SumOfDifferentPowers::new(DIMENSIONS))?; + // the same function, shifted and rotated: the CEC 2017 report's first version had it so + let rotated = Rotated::new(Shifted::new(SumOfDifferentPowers::new(DIMENSIONS), 1), 1); + compare("Shifted and rotated (seed 1)", &rotated)?; + // with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate + // run in 2 dimensions: the plot is the function's contour + trace::record_small()?; + Ok(()) +} + +// the table of the five algorithms on `problem`, after a line that names it +fn compare

(name: &str, problem: &P) -> Result<()> +where + P: Problem + FitnessFunction + Clone, +{ + let minimum = problem.optimum().expect("known").value(); + let stop = || Stop::target(minimum + 1e-8).or(Stop::evaluations(BUDGET)); + println!("{name}: evaluations until the error is at most"); + print!("{:<10}", "algorithm"); + COLUMNS.iter().for_each(|column| print!("{column:>9}")); + println!("{:>9}", "best"); + + for (name, covariance) in [ + ("CMA-ES", cmaes::Covariance::Full), + ("sep-CMA-ES", cmaes::Covariance::Diagonal), + ] { + let cmaes = Cmaes::builder(problem.representation()) + .covariance(covariance) + .minimize() + .seed(1) + .build()?; + let mut reached = Reached::new(minimum); + let outcome = Engine::new(cmaes, problem.clone()) + .stop_when(stop()) + .on_generation(|snapshot| reached.record(snapshot)) + .run()?; + reached.print(name, &outcome); + } + + let de = De::builder(problem.representation()) + .minimize() + .seed(1) + .build()?; + let mut reached = Reached::new(minimum); + let outcome = Engine::new(de, problem.clone()) + .stop_when(stop()) + .on_generation(|snapshot| reached.record(snapshot)) + .run()?; + reached.print("DE", &outcome); + + let pso = Pso::builder(problem.representation()) + .population_size(40) + .minimize() + .seed(1) + .build()?; + let mut reached = Reached::new(minimum); + let outcome = Engine::new(pso, problem.clone()) + .stop_when(stop()) + .on_generation(|snapshot| reached.record(snapshot)) + .run()?; + reached.print("PSO", &outcome); + + let ga = Ga::builder(problem.representation()) + .population_size(100) + .select(Tournament::new(3)?) + .crossover(SimulatedBinaryCrossover::new(15.0)?) + .mutate(PolynomialMutation::per_gene(1.0 / DIMENSIONS as f64, 20.0)?) + .minimize() + .seed(1) + .build()?; + let mut reached = Reached::new(minimum); + let outcome = Engine::new(ga, problem.clone()) + .stop_when(stop()) + .on_generation(|snapshot| reached.record(snapshot)) + .run()?; + reached.print("GA", &outcome); + Ok(()) +} + +// the evaluations after the first generation whose best error was at most each of ERRORS, for a +// function whose minimum is `minimum` +struct Reached { + minimum: f64, + evaluations: [Option; 5], +} + +impl Reached { + fn new(minimum: f64) -> Self { + let evaluations = [None; 5]; + Self { + minimum, + evaluations, + } + } + + fn record(&mut self, snapshot: &Snapshot<'_, Reals>) { + let progress = snapshot.progress(); + let Some(best) = progress.best().and_then(Fitness::score) else { + return; + }; + let error = best - self.minimum; + for (reached, bound) in self.evaluations.iter_mut().zip(ERRORS) { + if reached.is_none() && error <= bound { + *reached = Some(progress.evaluations()); + } + } + } + + // a row of the table: the evaluations, "-" for an error not reached, and the best error + fn print(&self, name: &str, outcome: &Outcome) { + print!("{name:<10}"); + for reached in self.evaluations { + let reached = reached.map_or("-".to_string(), |evaluations| evaluations.to_string()); + print!("{reached:>9}"); + } + // rounding can put a solution a few ulps below the minimum + let best = outcome.best_fitness().score().expect("valid"); + let error = (best - self.minimum).max(0.0); + println!("{:>9}", format!("{error:.1e}")); + } +} diff --git a/examples/sum_of_different_powers/output.txt b/examples/sum_of_different_powers/output.txt new file mode 100644 index 00000000..0041d817 --- /dev/null +++ b/examples/sum_of_different_powers/output.txt @@ -0,0 +1,15 @@ +Sum of different powers in 30 dimensions, 300000 evaluations at most +Sum of different powers: evaluations until the error is at most +algorithm 1 1e-2 1e-4 1e-6 1e-8 best +CMA-ES 28 294 1624 5306 13006 9.1e-9 +sep-CMA-ES 28 252 742 1540 2464 9.2e-9 +DE 100 1100 3100 4800 6500 7.4e-10 +PSO 40 760 1680 3120 4880 7.2e-9 +GA 100 1517 3781 6915 15922 8.7e-9 +Shifted and rotated (seed 1): evaluations until the error is at most +algorithm 1 1e-2 1e-4 1e-6 1e-8 best +CMA-ES 168 476 1666 4718 12334 9.0e-9 +sep-CMA-ES 182 322 784 10220 - 1.4e-8 +DE 600 2100 5100 16200 32200 7.5e-9 +PSO 280 920 2560 14280 243400 9.9e-9 +GA 293 1609 3316 27087 - 5.9e-8 diff --git a/examples/sum_of_different_powers/trace.json b/examples/sum_of_different_powers/trace.json new file mode 100644 index 00000000..90bcd774 --- /dev/null +++ b/examples/sum_of_different_powers/trace.json @@ -0,0 +1,36 @@ +{"example":"sum_of_different_powers","format":1,"log_y":true,"objective":"minimize","optimum":0.0,"plot":"contour","problem":{"bounds":[[-1.0,1.0],[-1.0,1.0]],"function":"sum_of_different_powers","minima":[[0.0,0.0]]},"x_label":"evaluations","y_label":"error","frames":[ +{"best":0.207376,"evaluations":6,"generation":0,"median":0.692089,"state":{"best":[0.428992,-0.285787],"population":[[-0.805712,-0.244639],[0.219455,-0.61072],[-0.540471,0.753763],[-0.214189,-0.92999],[-0.751217,-0.726119],[0.428992,-0.285787]]}}, +{"best":0.0619828,"evaluations":12,"generation":1,"median":0.276512,"state":{"best":[0.245342,0.121416],"population":[[-0.283686,-0.176739],[0.766402,-0.524176],[0.245342,0.121416],[-0.632581,0.330338],[-0.180719,-0.94234],[0.341657,0.0444898]]}}, +{"best":0.0619828,"evaluations":18,"generation":2,"median":0.692485,"state":{"best":[0.245342,0.121416],"population":[[0.422071,0.379849],[-0.695593,0.492276],[-0.563254,0.981044],[0.0834435,-0.918491],[-0.641757,-0.761763],[-0.18225,0.388598]]}}, +{"best":0.00263315,"evaluations":24,"generation":3,"median":0.195939,"state":{"best":[-0.0344877,-0.113022],"population":[[0.752004,0.428326],[-0.0726276,-0.602856],[-0.216203,0.494284],[-0.0344877,-0.113022],[0.355592,0.919625],[-0.305874,0.195771]]}}, +{"best":0.00263315,"evaluations":30,"generation":4,"median":0.396462,"state":{"best":[-0.0344877,-0.113022],"population":[[-0.866778,-0.282323],[0.316195,0.915101],[-0.637087,0.114238],[-0.491776,0.246039],[0.0502423,0.510493],[-0.620848,-0.04659]]}}, +{"best":0.00263315,"evaluations":36,"generation":5,"median":0.0587648,"state":{"best":[-0.0344877,-0.113022],"population":[[0.0795878,0.394614],[-0.0964656,-0.0549374],[-0.0909202,0.346161],[0.149457,-0.0738133],[-0.340439,0.637319],[0.0377234,0.633689]]}}, +{"best":0.00263315,"evaluations":42,"generation":6,"median":0.0748083,"state":{"best":[-0.0344877,-0.113022],"population":[[-0.314586,-0.058343],[-0.0723354,0.00884067],[-0.110386,0.28075],[-0.399479,0.620958],[-0.284657,-0.0112363],[-0.140826,0.365316]]}}, +{"best":0.00263315,"evaluations":48,"generation":7,"median":0.124723,"state":{"best":[-0.0344877,-0.113022],"population":[[-0.170403,-0.360115],[-0.187529,0.539922],[-0.250612,0.353205],[0.155845,0.490885],[0.0680864,0.232675],[-0.167535,0.498669]]}}, +{"best":0.00263315,"evaluations":54,"generation":8,"median":0.00571093,"state":{"best":[-0.0344877,-0.113022],"population":[[0.0676747,0.193794],[0.078705,0.0476633],[-0.184634,0.0378336],[0.0637757,0.0491711],[0.0266684,-0.157373],[0.0697937,0.0628216]]}}, +{"best":0.00162122,"evaluations":60,"generation":9,"median":0.0130765,"state":{"best":[-0.0330802,-0.0807699],"population":[[-0.0328657,0.364032],[-0.255129,0.154334],[-0.0330802,-0.0807699],[0.0914026,0.00531622],[-0.00873157,0.189616],[0.00912323,-0.260684]]}}, +{"best":1.76277e-05,"evaluations":66,"generation":10,"median":0.00279493,"state":{"best":[-0.00419448,-0.00324279],"population":[[-0.00419448,-0.00324279],[0.0532042,0.0495764],[-0.168629,0.00275026],[0.022875,-0.128343],[-0.0296679,0.0667384],[-0.0867022,0.331378]]}}, +{"best":1.76277e-05,"evaluations":72,"generation":11,"median":0.00671414,"state":{"best":[-0.00419448,-0.00324279],"population":[[-0.00656263,0.211891],[0.075939,0.0708351],[-0.118036,0.0976161],[0.0253506,0.0984624],[0.0854751,-0.00530027],[-0.00476035,0.0116138]]}}, +{"best":1.76277e-05,"evaluations":78,"generation":12,"median":0.0016578,"state":{"best":[-0.00419448,-0.00324279],"population":[[0.0295003,0.0481934],[0.13514,0.0875913],[-0.0313883,0.0711733],[0.00940729,0.115692],[0.0324993,-0.0853802],[-0.00567695,0.129985]]}}, +{"best":1.76277e-05,"evaluations":84,"generation":13,"median":0.0015167,"state":{"best":[-0.00419448,-0.00324279],"population":[[0.0677865,0.0486677],[-0.0180334,-0.00950569],[0.0216283,0.0755455],[-0.0193999,0.120693],[0.0842202,-0.0128194],[-0.0157196,0.0477475]]}}, +{"best":1.76277e-05,"evaluations":90,"generation":14,"median":0.00149598,"state":{"best":[-0.00419448,-0.00324279],"population":[[-0.00736993,-0.0518911],[-0.0488335,-0.00613535],[0.00487593,0.0561551],[-0.0865929,-0.027552],[0.0246376,-0.00195575],[-0.0977867,0.00815338]]}}, +{"best":1.76277e-05,"evaluations":96,"generation":15,"median":0.00186119,"state":{"best":[-0.00419448,-0.00324279],"population":[[0.0539985,0.0300273],[0.0497936,0.042619],[-0.0422938,-0.0703352],[0.00131994,-0.0535841],[0.0247369,-0.0146039],[-0.0353006,-0.0697641]]}}, +{"best":1.76277e-05,"evaluations":102,"generation":16,"median":0.00166529,"state":{"best":[-0.00419448,-0.00324279],"population":[[0.0336429,-0.106118],[0.032392,-0.0560289],[0.0210403,-0.00638837],[0.0475665,0.0126014],[0.0426288,-0.0609657],[-0.0122795,-0.104342]]}}, +{"best":1.76277e-05,"evaluations":108,"generation":17,"median":0.00137278,"state":{"best":[-0.00419448,-0.00324279],"population":[[0.0314002,-0.00375068],[0.0139553,-0.116096],[0.0288771,-0.0255302],[0.0563626,-0.0192665],[-0.00189312,-0.0242636],[0.0592119,-0.000556011]]}}, +{"best":1.76277e-05,"evaluations":114,"generation":18,"median":0.000238672,"state":{"best":[-0.00419448,-0.00324279],"population":[[0.0264032,-0.0610798],[0.00756404,-0.0596497],[-0.0138631,-0.0250437],[-0.0186772,-0.0179754],[-0.00936574,-0.0294594],[0.00373557,-0.039641]]}}, +{"best":6.54866e-06,"evaluations":120,"generation":19,"median":0.000336263,"state":{"best":[0.00243937,-0.00842566],"population":[[0.00851597,-0.0432859],[0.00243937,-0.00842566],[0.0227513,-0.0108542],[0.0218085,-0.0633733],[0.0281935,-0.0430021],[-0.00248851,-0.0178304]]}}, +{"best":5.8933e-06,"evaluations":126,"generation":20,"median":7.94755e-05,"state":{"best":[-0.00226843,-0.00907556],"population":[[0.00611981,-0.0283405],[-0.0132974,-0.00127039],[-0.00664279,-0.0379394],[0.00326407,-0.0327056],[-0.00226843,-0.00907556],[0.0133676,0.0174577]]}}, +{"best":5.8933e-06,"evaluations":132,"generation":21,"median":4.57839e-05,"state":{"best":[-0.00226843,-0.00907556],"population":[[-0.00890844,-0.0242983],[0.00815724,-0.00989502],[-0.00251543,-0.020212],[0.00154267,-0.0278833],[0.00285677,-0.0087058],[0.0144104,-0.001738]]}}, +{"best":8.04572e-07,"evaluations":138,"generation":22,"median":4.75417e-05,"state":{"best":[0.000484581,-0.00829015],"population":[[0.000484581,-0.00829015],[0.00184275,-0.0105494],[0.00645435,-0.0294336],[0.00527779,0.00412546],[-0.0107605,-0.00524525],[0.0107974,-0.0146099]]}}, +{"best":8.04572e-07,"evaluations":144,"generation":23,"median":1.14993e-05,"state":{"best":[0.000484581,-0.00829015],"population":[[0.00236775,-0.00862194],[0.00594985,-0.016847],[-0.00119027,-0.0165209],[-0.00141674,-0.0127167],[-0.00461637,0.00495988],[0.00408457,-0.00407537]]}}, +{"best":4.34252e-07,"evaluations":150,"generation":24,"median":9.21211e-06,"state":{"best":[-0.000648129,-0.00242049],"population":[[0.00192736,-0.00552193],[0.00103742,-0.0151251],[-0.00200934,-0.0214363],[-0.00590664,-0.0296451],[-0.000648129,-0.00242049],[0.00524127,-0.0152961]]}}, +{"best":5.30481e-08,"evaluations":156,"generation":25,"median":5.63863e-06,"state":{"best":[8.03707e-05,-0.00359827],"population":[[-0.00197145,-0.00487785],[8.03707e-05,-0.00359827],[-9.27343e-05,-0.00355522],[0.0026042,-0.00789829],[0.0044009,-0.00137299],[0.00567088,-0.0103869]]}}, +{"best":2.87218e-08,"evaluations":162,"generation":26,"median":2.04674e-06,"state":{"best":[0.000166812,0.000963927],"population":[[0.000957787,-0.00278349],[0.0014731,0.00768199],[-0.000222697,-0.0112413],[0.000166812,0.000963927],[-0.00124264,-0.0138895],[0.001943,0.00902961]]}}, +{"best":2.87218e-08,"evaluations":168,"generation":27,"median":2.55859e-06,"state":{"best":[0.000166812,0.000963927],"population":[[-0.00124647,-0.00443089],[-0.00178454,0.00291933],[-0.0013807,-0.00111977],[-0.0035282,-0.00402627],[0.000948395,0.00367798],[-0.00419823,-0.00101305]]}}, +{"best":2.87218e-08,"evaluations":174,"generation":28,"median":3.00878e-06,"state":{"best":[0.000166812,0.000963927],"population":[[-5.63447e-05,0.00311074],[0.00310672,0.007562],[0.00142528,0.0121619],[0.00147769,-0.00154661],[0.00349441,6.44444e-05],[0.00146815,0.00256513]]}}, +{"best":2.87218e-08,"evaluations":180,"generation":29,"median":2.33309e-06,"state":{"best":[0.000166812,0.000963927],"population":[[0.00184902,0.00665266],[0.00158199,0.00654667],[-0.000699273,-0.00109857],[0.00120415,0.00756481],[0.000815423,-0.00158451],[0.00279257,0.00348939]]}}, +{"best":2.87218e-08,"evaluations":186,"generation":30,"median":1.13083e-06,"state":{"best":[0.000166812,0.000963927],"population":[[-0.00117504,-0.00662803],[-0.000203778,-0.00314907],[0.000788367,-0.00405052],[0.000953112,0.00468917],[-0.00262693,-0.00098293],[-0.00109779,-0.00355644]]}}, +{"best":1.03046e-08,"evaluations":192,"generation":31,"median":8.65024e-07,"state":{"best":[-2.29584e-05,-0.00213834],"population":[[-0.000261895,0.000278011],[0.000852179,0.00236105],[0.00161054,-0.000908256],[-0.0010113,-0.00727563],[-2.29584e-05,-0.00213834],[0.000986837,-0.00256263]]}}, +{"best":1.03046e-08,"evaluations":198,"generation":32,"median":1.70714e-07,"state":{"best":[-2.29584e-05,-0.00213834],"population":[[0.000293249,-0.000251477],[-0.000416669,-0.00419311],[0.000560488,-0.00344289],[0.000122374,-0.000963591],[0.000295256,0.00190511],[-0.000860942,0.00156718]]}}, +{"best":4.0857e-10,"evaluations":204,"generation":33,"median":1.31289e-07,"state":{"best":[1.56603e-05,0.000546619],"population":[[-0.000590595,0.00104248],[0.000247559,-0.000891951],[1.56603e-05,0.000546619],[0.000447858,0.000176564],[0.000555314,-0.00137977],[0.000187193,0.000989895]]}} +]} diff --git a/examples/sum_of_different_powers/trace.py b/examples/sum_of_different_powers/trace.py new file mode 100644 index 00000000..b31f237e --- /dev/null +++ b/examples/sum_of_different_powers/trace.py @@ -0,0 +1,189 @@ +"""The trace for the plot on the example's page, written to the file that ``GENOXIDE_TRACE`` +names. The plot draws the population on the function's contour, which needs two dimensions: the +trace is of a separate run of CMA-ES in 2 dimensions, with a budget of +20,000 evaluations, in at most 100 frames. The Rust example writes the same file.""" + +import json +import math +import os + +import genoxide as gx + + +def record_small(): + """Runs CMA-ES in 2 dimensions and writes its trace, if ``GENOXIDE_TRACE`` is set.""" + path = os.environ.get("GENOXIDE_TRACE") + if not path: + return + problem = gx.problems.SumOfDifferentPowers(2) + minimum = problem.optimum.value + budget = 20_000 + cmaes = gx.Cmaes(problem.genome, objective="minimize", seed=1) + frames = Frames(100) + + def record(progress): + state = {"population": progress.population.tolist(), "best": progress.best_genome.tolist()} + frames.push(frame(progress, state, minimum)) + + cmaes.run(problem, target=minimum + 1e-8, evaluations=budget, on_generation=record) + low, high = problem.genome.bounds + settings = { + "format": 1, + "example": "sum_of_different_powers", + "objective": "minimize", + "x_label": "evaluations", + "y_label": "error", + "log_y": True, + "optimum": 0.0, + "plot": "contour", + "problem": { + "function": "sum_of_different_powers", + "bounds": [[float(low), float(high)]] * 2, + "minima": problem.optimum.solutions.tolist(), + }, + } + write(path, settings, frames.to_list()) + + +def frame(progress, state, minimum): + """The frame of a generation: its progress, the errors of its best and of its population's + median to ``minimum`` (rounding can put a solution a few ulps below it), and ``state``.""" + + def error(value): + return None if value is None else max(value - minimum, 0.0) + + return { + "generation": progress.generation, + "evaluations": progress.evaluations, + "best": error(progress.best_fitness), + "median": error(median(progress.scores)), + "state": state, + } + + +def median(scores): + """The median of the valid scores, None without any.""" + scores = sorted(float(score) for score in scores if not math.isnan(score)) + middle = len(scores) // 2 + if not scores: + return None + return scores[middle] if len(scores) % 2 else (scores[middle - 1] + scores[middle]) / 2 + + +# ---- the same in every example's trace ---------------------------------------------------------- + + +class Frames: + """The frames of at most ``most`` generations, from the part of the run where what the page + plots changes: the frames after the last change are left out (a run that reached its target, + or a front that no longer moves), and the rest are spread evenly over the generations up to + it. While the run goes, up to 8 × ``most`` frames are kept: every ``every``-th generation, + with ``every`` doubling whenever there are that many, and the last one.""" + + def __init__(self, most): + self.most, self.every, self.kept, self.last = most, 1, [], None + + def push(self, frame): + if frame["generation"] % self.every: + self.last = frame + return + self.kept.append(frame) + self.last = None + if len(self.kept) == 8 * self.most: + self.every *= 2 + self.kept = [kept for kept in self.kept if kept["generation"] % self.every == 0] + + def to_list(self): + frames = self.kept + ([self.last] if self.last else []) + active = frames[: last_change(frames) + 1] + count, most = len(active), max(self.most, 2) + if count <= most: + return active + return [active[(i * (count - 1) + (most - 1) // 2) // (most - 1)] for i in range(most)] + + +def last_change(frames): + """The index of the frame after which nothing the page plots changes. To 3 significant + digits, as a plot shows them: the best, the median and, for a single objective (a numeric + best), the state; to within a hundredth of their range over the run: a front's + hypervolumes, in the state or in a grid's series.""" + if not frames: + return 0 + last = len(frames) - 1 + number = lambda value: isinstance(value, (int, float)) and not isinstance(value, bool) + single = any(number(frame.get("best")) for frame in frames) + + def measures(frame): + values = [] + state = frame.get("state") + hypervolume = state.get("hypervolume") if isinstance(state, dict) else None + for value in (hypervolume, frame.get("series")): + if number(value): + values.append(float(value)) + elif isinstance(value, dict): + values.extend(float(v) for _, v in sorted(value.items()) if number(v)) + return values + + measured = [measures(frame) for frame in frames] + end = measured[last] + tolerance = [] + for k in range(len(end)): + values = [values[k] for values in measured if k < len(values)] + tolerance.append((max(values) - min(values)) / 100.0) + + def same(frame, final, key, flush=False): + return coarse(frame.get(key), flush) == coarse(final.get(key), flush) + + def settled(i): + frame, final = frames[i], frames[last] + return ( + same(frame, final, "best") + and same(frame, final, "median") + and (not single or same(frame, final, "state", flush=True)) + and len(measured[i]) == len(end) + and all(abs(v - e) <= t for v, e, t in zip(measured[i], end, tolerance)) + ) + + first = last + while first > 0 and settled(first - 1): + first -= 1 + return first + + +def coarse(value, flush=False): + """``value`` with its numbers to 3 significant digits, as precisely as a plot shows them: two + frames whose plotted values agree to that precision look the same. With ``flush``, for the + solutions a plot draws on their ranges, numbers below 1e-6 in size count as 0.""" + if isinstance(value, float): + if flush and abs(value) < 1e-6: + value = 0.0 + return f"{value:.2e}" + if isinstance(value, (list, tuple)): + return "[" + ",".join(coarse(item, flush) for item in value) + "]" + if isinstance(value, dict): + items = sorted(value.items()) + return "{" + ",".join(f"{key}:{coarse(item, flush)}" for key, item in items) + "}" + return json.dumps(value) + + +def write(path, settings, frames): + """Writes the settings and the frames to ``path``, a frame per line.""" + lines = ",\n".join(map(to_json, frames)) + with open(path, "w", encoding="utf-8", newline="\n") as file: + file.write(f'{to_json(settings)[:-1]},"frames":[\n{lines}\n]}}\n') + + +def to_json(value): + """Compact JSON with sorted keys, and numbers rounded to 6 significant digits, as the Rust + example writes it.""" + return json.dumps(rounded(value), sort_keys=True, separators=(",", ":"), ensure_ascii=False) + + +def rounded(value): + if isinstance(value, dict): + return {key: rounded(item) for key, item in value.items()} + if isinstance(value, (list, tuple)): + return [rounded(item) for item in value] + if isinstance(value, float): + return float(f"{value:.5e}") if math.isfinite(value) else None + return value diff --git a/examples/sum_of_different_powers/trace.rs b/examples/sum_of_different_powers/trace.rs new file mode 100644 index 00000000..d75f15fa --- /dev/null +++ b/examples/sum_of_different_powers/trace.rs @@ -0,0 +1,260 @@ +//! The trace for the plot on the example's page, written to the file that `GENOXIDE_TRACE` names. +//! The plot draws the population on the function's contour, which needs two dimensions: the trace +//! is of a separate run of CMA-ES in 2 dimensions, with a budget of +//! 20,000 evaluations, in at most 100 frames. The Python example writes the same +//! file. + +use genoxide::observer::Snapshot; +use genoxide::prelude::*; +use genoxide::problems::{Problem, SumOfDifferentPowers}; +use serde_json::{Value, json}; + +// runs CMA-ES in 2 dimensions and writes its trace, if GENOXIDE_TRACE is set +pub fn record_small() -> Result<()> { + let Ok(path) = std::env::var("GENOXIDE_TRACE") else { + return Ok(()); + }; + let problem = SumOfDifferentPowers::new(2); + let optimum = problem.optimum().expect("known"); + let minimum = optimum.value(); + let budget = 20_000; + let cmaes = Cmaes::builder(problem.representation()) + .minimize() + .seed(1) + .build()?; + let mut frames = Frames::new(100); + Engine::new(cmaes, problem.clone()) + .stop_when(Stop::target(minimum + 1e-8).or(Stop::evaluations(budget))) + .on_generation(|snapshot| { + let population = snapshot.population().iter().map(|x| &x.genome()[..]); + let population: Vec<&[f64]> = population.collect(); + let best = &snapshot.best().genome()[..]; + let state = json!({ "population": population, "best": best }); + frames.push(frame(snapshot, state, minimum)); + }) + .run()?; + let bounds = problem.representation().bounds().to_vec(); + let bounds: Vec<[f64; 2]> = bounds.iter().map(|b| [*b.start(), *b.end()]).collect(); + let minima: Vec<&[f64]> = optimum.solutions().iter().map(|x| &x[..]).collect(); + let settings = json!({ + "format": 1, + "example": "sum_of_different_powers", + "objective": "minimize", + "x_label": "evaluations", + "y_label": "error", + "log_y": true, + "optimum": 0.0, + "plot": "contour", + "problem": { + "function": "sum_of_different_powers", + "bounds": bounds, + "minima": minima, + }, + }); + write(&path, settings, frames.into_vec()); + Ok(()) +} + +// the frame of a generation: its progress, the errors of its best and of its population's median +// to `minimum` (rounding can put a solution a few ulps below it), and `state` +fn frame(snapshot: &Snapshot<'_, Reals>, state: Value, minimum: f64) -> Value { + let progress = snapshot.progress(); + let error = |value: f64| (value - minimum).max(0.0); + let population = snapshot.population().iter(); + let scores = population.filter_map(|individual| individual.fitness()?.score()); + json!({ + "generation": progress.generation(), + "evaluations": progress.evaluations(), + "best": progress.best().and_then(Fitness::score).map(error), + "median": median(scores.collect()).map(error), + "state": state, + }) +} + +// the median of the scores, None without any +fn median(mut scores: Vec) -> Option { + scores.sort_by(f64::total_cmp); + let middle = scores.len() / 2; + match scores.len() { + 0 => None, + n if n % 2 == 1 => Some(scores[middle]), + _ => Some((scores[middle - 1] + scores[middle]) / 2.0), + } +} + +// ---- the same in every example's trace --------------------------------------------------------- + +// the frames of at most `most` generations, from the part of the run where what the page plots +// changes: the frames after the last change are left out (a run that reached its target, or a +// front that no longer moves), and the rest are spread evenly over the generations up to it. While +// the run goes, up to 8 × `most` frames are kept: every `every`-th generation, with `every` +// doubling whenever there are that many, and the last one. +struct Frames { + most: usize, + every: u64, + kept: Vec<(u64, Value)>, + last: Option<(u64, Value)>, +} + +impl Frames { + fn new(most: usize) -> Self { + let (every, kept, last) = (1, Vec::new(), None); + Self { + most, + every, + kept, + last, + } + } + + fn push(&mut self, frame: Value) { + let generation = frame["generation"].as_u64().expect("a generation"); + if !generation.is_multiple_of(self.every) { + self.last = Some((generation, frame)); + return; + } + self.kept.push((generation, frame)); + self.last = None; + if self.kept.len() == 8 * self.most { + self.every *= 2; + let every = self.every; + self.kept.retain(|(generation, _)| generation % every == 0); + } + } + + fn into_vec(self) -> Vec { + let frames = self.kept.into_iter().chain(self.last); + let frames: Vec = frames.map(|(_, frame)| frame).collect(); + let active = &frames[..=last_change(&frames)]; + let (count, most) = (active.len(), self.most.max(2)); + if count <= most { + return active.to_vec(); + } + let at = |i: usize| active[(i * (count - 1) + (most - 1) / 2) / (most - 1)].clone(); + (0..most).map(at).collect() + } +} + +// the index of the frame after which nothing the page plots changes. To 3 significant digits, as +// a plot shows them: the best, the median and, for a single objective (a numeric best), the state; +// to within a hundredth of their range over the run: a front's hypervolumes, in the state or in a +// grid's series +fn last_change(frames: &[Value]) -> usize { + let Some(last) = frames.len().checked_sub(1) else { + return 0; + }; + let single = frames.iter().any(|frame| frame["best"].is_number()); + let measures = |frame: &Value| -> Vec { + let mut values = Vec::new(); + for value in [&frame["state"]["hypervolume"], &frame["series"]] { + match value { + Value::Number(number) => values.extend(number.as_f64()), + Value::Object(map) => values.extend(map.values().filter_map(Value::as_f64)), + _ => {} + } + } + values + }; + let measured: Vec> = frames.iter().map(measures).collect(); + let end = &measured[last]; + let tolerance: Vec = (0..end.len()) + .map(|k| { + let values = measured.iter().filter_map(|values| values.get(k).copied()); + let (low, high) = values.fold((f64::INFINITY, f64::NEG_INFINITY), |(low, high), v| { + (low.min(v), high.max(v)) + }); + (high - low) / 100.0 + }) + .collect(); + let settled = |i: usize| { + let (frame, final_frame) = (&frames[i], &frames[last]); + let same = + |key: &str, flush: bool| coarse(&frame[key], flush) == coarse(&final_frame[key], flush); + same("best", false) + && same("median", false) + && (!single || same("state", true)) + && measured[i].len() == end.len() + && measured[i] + .iter() + .zip(end) + .zip(&tolerance) + .all(|((value, end), tolerance)| (value - end).abs() <= *tolerance) + }; + let mut first = last; + while first > 0 && settled(first - 1) { + first -= 1; + } + first +} + +// `value` with its numbers to 3 significant digits, as precisely as a plot shows them: two frames +// whose plotted values agree to that precision look the same. With `flush`, for the solutions a +// plot draws on their ranges, numbers below 1e-6 in size count as 0 +fn coarse(value: &Value, flush: bool) -> String { + let join = |items: Vec| items.join(","); + match value { + Value::Number(number) if number.is_f64() => { + let number = number.as_f64().expect("f64"); + let number = if flush && number.abs() < 1e-6 { + 0.0 + } else { + number + }; + format!("{number:.2e}") + } + Value::Array(items) => { + format!( + "[{}]", + join(items.iter().map(|item| coarse(item, flush)).collect()) + ) + } + Value::Object(map) => { + let entry = |(key, item): (&String, &Value)| format!("{key}:{}", coarse(item, flush)); + format!("{{{}}}", join(map.iter().map(entry).collect())) + } + other => other.to_string(), + } +} + +// writes the settings and the frames to `path`, a frame per line +fn write(path: &str, settings: Value, frames: Vec) { + let frames: Vec = frames.iter().map(to_json).collect(); + let settings = to_json(&settings); + let head = &settings[..settings.len() - 1]; + let text = format!("{head},\"frames\":[\n{}\n]}}\n", frames.join(",\n")); + std::fs::write(path, text).expect("the trace is written"); +} + +// compact JSON with sorted keys, and numbers rounded to 6 significant digits and written as +// Python writes them (7542.0, 1e-08): the Python example writes the same file +fn to_json(value: &Value) -> String { + let join = |items: Vec| items.join(","); + match value { + Value::Number(number) if number.is_f64() => python_float(number.as_f64().expect("f64")), + Value::Array(items) => format!("[{}]", join(items.iter().map(to_json).collect())), + Value::Object(map) => { + let entry = + |(key, item): (&String, &Value)| format!("{}:{}", json!(key), to_json(item)); + format!("{{{}}}", join(map.iter().map(entry).collect())) + } + other => other.to_string(), + } +} + +fn python_float(value: f64) -> String { + let rounded: f64 = format!("{value:.5e}").parse().expect("a number"); + let shortest = format!("{rounded:e}"); + let (mantissa, exponent) = shortest.split_once('e').expect("an exponent"); + let exponent: i32 = exponent.parse().expect("an exponent"); + if (-4..16).contains(&exponent) { + let text = rounded.to_string(); + if text.contains('.') { + text + } else { + text + ".0" + } + } else { + let sign = if exponent < 0 { '-' } else { '+' }; + format!("{mantissa}e{sign}{:02}", exponent.abs()) + } +} diff --git a/examples/weierstrass/README.md b/examples/weierstrass/README.md new file mode 100644 index 00000000..00fdb238 --- /dev/null +++ b/examples/weierstrass/README.md @@ -0,0 +1,78 @@ +--- +title: Weierstrass +category: continuous +summary: Minimize the Weierstrass function, continuous but nowhere smooth, in 10 dimensions, with CMA-ES without and with restarts, DE, PSO and a GA from 10 seeds each. +reference: "Suganthan, P. N., Hansen, N., Liang, J. J., Deb, K., Chen, Y.-P., Auger, A. and Tiwari, S. (2005). Problem Definitions and Evaluation Criteria for the CEC 2005 Special Session on Real-Parameter Optimization. Nanyang Technological University and KanGAL report 2005005." +reference_url: "https://github.com/P-N-Suganthan/CEC2005" +optimum: "0 (at the origin)" +languages: [rust, python] +order: 95 +trace_note: "Recorded from another run: CMA-ES with IPOP restarts in 2 dimensions, so that the population can be drawn on the function's contour." +--- + +# Weierstrass + +## The problem + +The Weierstrass function sums cosines of growing frequency and shrinking amplitude: + +```text +f(x) = Σᵢ Σₖ aᵏ cos(2π bᵏ (xᵢ + 0.5)) − n Σₖ aᵏ cos(π bᵏ), a = 0.5, b = 3, k from 0 to 20 +each xᵢ in [−0.5, 0.5] +``` + +Its minimum is 0, at the origin: each gene's sum is at least −Σ aᵏ, reached where every cosine is +−1, at the integers, and the second term is −n Σ aᵏ, since every bᵏ is odd. Here n = 10. It's the +function F11 of the CEC 2005 report (Suganthan et al. 2005), shifted and rotated there, with its +constants and bounds; Liang et al. (2006) and the CEC 2014 report have the same form, and BBOB's +f16 another one. It's named after Weierstrass's (1872) continuous, nowhere-differentiable function. + +## What makes it hard + +Each gene's sum is a fractal: ripples on ripples, each three times faster and half as high as the +last, down to 3²⁰ ≈ 3.5·10⁹ periods per unit. The function is continuous but differentiable only on +a set of points, and has local minima at every scale. A search that has found the right valley at +one scale still has to find it at every finer one. + +## Representation + +A `Real` genome of 10 genes, each in [−0.5, 0.5]: the point x itself. The fitness is f(x), to +minimize. The function is genoxide's `problems::Weierstrass`, which brings its bounds and its +minimum. + +## Algorithm + +Five algorithms, each from seeds 1 to 10, with a budget of 10,000 evaluations per dimension, +100,000 per run, and a target of 1e-8: + +- CMA-ES (Hansen and Ostermeier, 2001, Evolutionary Computation 9(2): 159-195), which samples a + population of 10 from a normal distribution and adapts its mean, its step size and its covariance + matrix, from a step size of 0.3 of each gene's range and a random start; +- the same with IPOP restarts (Auger and Hansen, 2005, IEEE CEC 2005: 1769-1776): a run that has + converged starts again from a random point with twice the population; +- differential evolution with genoxide's defaults, SHADE (Tanabe and Fukunaga, CEC 2013), with a + population of 100 and its restarts on stagnation; +- particle swarm optimization (Kennedy and Eberhart, 1995), 40 particles with Clerc and Kennedy's + constriction coefficients and a global topology; +- a real-coded genetic algorithm: a population of 100, tournaments of 3, simulated binary crossover + (Deb and Agrawal, 1995) with η = 15 and polynomial mutation with η = 20 at a rate of 1/10 per + gene. + +## Output + +The first line gives the dimension, the seeds and the budget. Then a row per algorithm: how many +of its 10 runs reached the minimum, to within 1e-8, the median of their evaluations (a dash if none +did), and the median of every run's best error, to two significant digits. The function is +evaluated with genoxide's portable math, so the runs are the same on every platform, and in Python, +`run` evaluates it in Rust, so both versions print the same. + +[The project page](https://tachsin.gr/projects/genoxide/examples/weierstrass) plays back another run: +CMA-ES with IPOP restarts on the function in 2 dimensions, so that the population +can be drawn on its contour. It meets the target after 816 evaluations. + +## Good results + +The minimum is 0. CMA-ES with IPOP restarts reaches it in all 10 runs, after a median of 10,195 +evaluations, and SHADE in all 10, after 42,300. PSO reaches it 8 times, after 17,720. CMA-ES without +restarts reaches it once, and its median run ends at 2.6e-3; the genetic algorithm never does, its +median run ending at 1.2e-2. diff --git a/examples/weierstrass/main.py b/examples/weierstrass/main.py new file mode 100644 index 00000000..bc21d151 --- /dev/null +++ b/examples/weierstrass/main.py @@ -0,0 +1,86 @@ +"""Weierstrass: minimize the Weierstrass function, continuous but nowhere smooth, in 10 +dimensions. + +Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), +differential evolution (SHADE), particle swarm optimization and a real-coded genetic algorithm from +10 seeds each, and counts the runs that reach the minimum, 0 at the origin, to within 1e-8. The +function is genoxide's `problems::Weierstrass`, which run evaluates in Rust. + +With ``GENOXIDE_TRACE=``, it also writes a trace of a run for the plot on the example's page, +with trace.py. + + python examples/weierstrass/main.py +""" + +import genoxide as gx + +from trace import record_small + +DIMENSIONS = 10 +SEEDS = 10 +BUDGET = 10_000 * DIMENSIONS +# a run stops once its error to the minimum is at most this +ERROR = 1e-8 +ALGORITHMS = ["CMA-ES", "CMA-ES with IPOP", "DE", "PSO", "GA"] + + +def build(name, genome, seed): + """The algorithm called ``name``, on ``genome``, from ``seed``.""" + if name == "CMA-ES": + return gx.Cmaes(genome, objective="minimize", seed=seed) + if name == "CMA-ES with IPOP": + return gx.Cmaes(genome, restarts="ipop", objective="minimize", seed=seed) + if name == "DE": + return gx.De(genome, objective="minimize", seed=seed) + if name == "PSO": + return gx.Pso(genome, population_size=40, objective="minimize", seed=seed) + return gx.Ga( + genome, + population_size=100, + select=gx.Tournament(3), + crossover=gx.SimulatedBinaryCrossover(15.0), + mutation=gx.PolynomialMutation(20.0, rate=1 / DIMENSIONS), + objective="minimize", + seed=seed, + ) + + +def median(values): + """The median of ``values``, None without any.""" + values = sorted(values) + middle = len(values) // 2 + if not values: + return None + return values[middle] if len(values) % 2 else (values[middle - 1] + values[middle]) / 2 + + +def error_text(error): + """An error to two significant digits, as Rust writes it: 9.9e-9.""" + mantissa, exponent = f"{error:.1e}".split("e") + return f"{mantissa}e{int(exponent)}" + + +problem = gx.problems.Weierstrass(DIMENSIONS) +minimum = problem.optimum.value +print(f"Weierstrass in {DIMENSIONS} dimensions, {SEEDS} seeds, {BUDGET} evaluations at most per run") +print("algorithm at min evaluations median error") +for name in ALGORITHMS: + # the evaluations of the runs that reach the minimum, and every run's best error + evaluations, errors = [], [] + for seed in range(1, SEEDS + 1): + result = build(name, problem.genome, seed).run( + problem, target=minimum + ERROR, evaluations=BUDGET + ) + if result.stop_reason == "target": + evaluations.append(float(result.evaluations)) + # rounding can put a solution a few ulps below the minimum + errors.append(max(result.best_fitness - minimum, 0.0)) + reached = f"{len(evaluations)}/{SEEDS}" + middle = median(evaluations) + evaluations_text = "-" if middle is None else f"{middle:.0f}" + print(f"{name:<16} {reached:>6} {evaluations_text:>11} {error_text(median(errors)):>12}") +print("evaluations: the median of the runs that reach the minimum") + +# with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate run in +# 2 dimensions: the plot is the function's contour +record_small() diff --git a/examples/weierstrass/main.rs b/examples/weierstrass/main.rs new file mode 100644 index 00000000..bcab3e7e --- /dev/null +++ b/examples/weierstrass/main.rs @@ -0,0 +1,118 @@ +//! Weierstrass: minimize the Weierstrass function, continuous but nowhere smooth, in 10 +//! dimensions. +//! +//! Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), +//! differential evolution (SHADE), particle swarm optimization and a real-coded genetic algorithm +//! from 10 seeds each, and counts the runs that reach the minimum, 0 at the origin, to within +//! 1e-8. The function is genoxide's `problems::Weierstrass`. +//! +//! With `GENOXIDE_TRACE=`, it also writes a trace of a run for the plot on the example's +//! page, with `trace.rs`. +//! +//! ```text +//! cargo run --release --example weierstrass +//! ``` + +mod trace; + +use genoxide::prelude::*; +use genoxide::problems::{Weierstrass, Problem}; + +const DIMENSIONS: usize = 10; +const SEEDS: u64 = 10; +const BUDGET: u64 = 10_000 * DIMENSIONS as u64; +// a run stops once its error to the minimum is at most this +const ERROR: f64 = 1e-8; +const ALGORITHMS: [&str; 5] = ["CMA-ES", "CMA-ES with IPOP", "DE", "PSO", "GA"]; + +fn main() -> Result<()> { + let problem = Weierstrass::new(DIMENSIONS); + let minimum = problem.optimum().expect("known").value(); + println!( + "Weierstrass in {DIMENSIONS} dimensions, {SEEDS} seeds, {BUDGET} evaluations at most per run" + ); + println!("algorithm at min evaluations median error"); + for algorithm in ALGORITHMS { + // the evaluations of the runs that reach the minimum, and every run's best error + let mut evaluations = Vec::new(); + let mut errors = Vec::new(); + for seed in 1..=SEEDS { + let outcome = run(algorithm, problem, seed, minimum + ERROR)?; + if outcome.stop_reason() == StopReason::Target { + evaluations.push(outcome.evaluations() as f64); + } + // rounding can put a solution a few ulps below the minimum + let best = outcome.best_fitness().score().expect("valid"); + errors.push((best - minimum).max(0.0)); + } + let reached = format!("{}/{SEEDS}", evaluations.len()); + let evaluations = median(evaluations).map_or("-".to_string(), |e| format!("{e:.0}")); + let error = median(errors).expect("a run"); + println!( + "{algorithm:<16} {reached:>6} {evaluations:>11} {:>12}", + format!("{error:.1e}") + ); + } + println!("evaluations: the median of the runs that reach the minimum"); + + // with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate + // run in 2 dimensions: the plot is the function's contour + trace::record_small()?; + Ok(()) +} + +// a run of `algorithm` from `seed`, until its best is at most `target` or it has used BUDGET +// evaluations +fn run(algorithm: &str, problem: Weierstrass, seed: u64, target: f64) -> Result> { + let real = problem.representation(); + let stop = Stop::target(target).or(Stop::evaluations(BUDGET)); + match algorithm { + "CMA-ES" | "CMA-ES with IPOP" => { + let restarts = if algorithm == "CMA-ES" { + cmaes::Restarts::Never + } else { + cmaes::Restarts::Ipop + }; + let cmaes = Cmaes::builder(real) + .restarts(restarts) + .minimize() + .seed(seed) + .build()?; + Engine::new(cmaes, problem).stop_when(stop).run() + } + "DE" => { + let de = De::builder(real).minimize().seed(seed).build()?; + Engine::new(de, problem).stop_when(stop).run() + } + "PSO" => { + let pso = Pso::builder(real) + .population_size(40) + .minimize() + .seed(seed) + .build()?; + Engine::new(pso, problem).stop_when(stop).run() + } + _ => { + let ga = Ga::builder(real) + .population_size(100) + .select(Tournament::new(3)?) + .crossover(SimulatedBinaryCrossover::new(15.0)?) + .mutate(PolynomialMutation::per_gene(1.0 / DIMENSIONS as f64, 20.0)?) + .minimize() + .seed(seed) + .build()?; + Engine::new(ga, problem).stop_when(stop).run() + } + } +} + +// the median of `values`, None without any +fn median(mut values: Vec) -> Option { + values.sort_by(f64::total_cmp); + let middle = values.len() / 2; + match values.len() { + 0 => None, + n if n % 2 == 1 => Some(values[middle]), + _ => Some((values[middle - 1] + values[middle]) / 2.0), + } +} diff --git a/examples/weierstrass/output.txt b/examples/weierstrass/output.txt new file mode 100644 index 00000000..bb03b61e --- /dev/null +++ b/examples/weierstrass/output.txt @@ -0,0 +1,8 @@ +Weierstrass in 10 dimensions, 10 seeds, 100000 evaluations at most per run +algorithm at min evaluations median error +CMA-ES 1/10 4070 2.6e-3 +CMA-ES with IPOP 10/10 10195 8.3e-9 +DE 10/10 42300 8.8e-9 +PSO 8/10 17720 9.1e-9 +GA 0/10 - 1.2e-2 +evaluations: the median of the runs that reach the minimum diff --git a/examples/weierstrass/trace.json b/examples/weierstrass/trace.json new file mode 100644 index 00000000..ae438fc1 --- /dev/null +++ b/examples/weierstrass/trace.json @@ -0,0 +1,102 @@ +{"example":"weierstrass","format":1,"log_y":true,"objective":"minimize","optimum":0.0,"plot":"contour","problem":{"bounds":[[-0.5,0.5],[-0.5,0.5]],"function":"weierstrass","minima":[[0.0,0.0]]},"x_label":"evaluations","y_label":"error","frames":[ +{"best":2.95623,"evaluations":6,"generation":0,"median":4.32597,"state":{"best":[0.109727,-0.30536],"population":[[-0.402856,-0.12232],[0.109727,-0.30536],[-0.270235,0.376881],[-0.107094,-0.464995],[-0.375609,-0.36306],[0.214496,-0.142894]]}}, +{"best":1.38359,"evaluations":12,"generation":1,"median":3.23402,"state":{"best":[0.0865916,-0.0120203],"population":[[-0.161444,-0.151811],[0.473712,-0.144572],[0.330892,-0.314707],[0.0865916,-0.0120203],[-0.325025,0.0859334],[0.131749,-0.0480871]]}}, +{"best":1.38359,"evaluations":24,"generation":3,"median":3.67292,"state":{"best":[0.0865916,-0.0120203],"population":[[-0.297097,0.291241],[0.246007,0.164017],[-0.114781,-0.359677],[-0.222728,0.162671],[-0.113724,-0.122978],[0.0376806,0.38659]]}}, +{"best":1.38359,"evaluations":30,"generation":4,"median":4.07604,"state":{"best":[0.0865916,-0.0120203],"population":[[-0.278301,0.236252],[-0.140679,-0.261153],[-0.441466,-0.404173],[0.0012466,0.352399],[-0.378386,-0.176175],[-0.321873,-0.0907973]]}}, +{"best":1.33073,"evaluations":36,"generation":5,"median":2.83559,"state":{"best":[0.0010715,-0.0561033],"population":[[-0.0781158,0.455127],[-0.357581,0.0708311],[0.0320167,0.216122],[0.0010715,-0.0561033],[-0.0574898,0.163507],[0.143823,-0.0286259]]}}, +{"best":0.584597,"evaluations":48,"generation":7,"median":3.18353,"state":{"best":[0.0121392,-0.00596864],"population":[[-0.134264,0.02152],[-0.0810946,0.212011],[-0.0295062,-0.28211],[-0.0960274,0.29064],[-0.125205,0.167592],[0.12846,0.281158]]}}, +{"best":0.525582,"evaluations":54,"generation":8,"median":1.48994,"state":{"best":[-0.00932204,0.00499982],"population":[[-0.00932204,0.00499982],[-0.131449,0.145128],[-0.0177611,0.0381442],[-0.013844,-0.0726282],[-0.236635,-0.0719063],[-0.0263982,-0.0710267]]}}, +{"best":0.525582,"evaluations":66,"generation":10,"median":1.68223,"state":{"best":[-0.00932204,0.00499982],"population":[[0.00633629,0.105393],[-0.0329884,-0.102225],[0.027772,0.000203594],[0.0864528,0.019684],[-0.0993547,0.0466978],[0.0163666,-0.0881643]]}}, +{"best":0.525582,"evaluations":72,"generation":11,"median":2.64839,"state":{"best":[-0.00932204,0.00499982],"population":[[0.0316115,0.0701428],[0.0524228,0.230148],[0.0896732,0.18297],[0.121413,0.0539283],[-0.0438251,0.131129],[0.0844547,0.0893782]]}}, +{"best":0.525582,"evaluations":78,"generation":12,"median":2.12168,"state":{"best":[-0.00932204,0.00499982],"population":[[0.109327,0.027593],[0.0585406,0.0753298],[0.0761035,0.0710445],[0.198374,0.0530359],[0.0284931,0.123687],[0.0903753,0.143839]]}}, +{"best":0.407359,"evaluations":90,"generation":14,"median":1.59624,"state":{"best":[0.0121253,0.00165704],"population":[[0.0505178,-0.146991],[-0.00352724,-0.0136204],[0.0068671,-0.114382],[-0.0267719,-0.0291246],[0.079353,0.0351462],[-0.0898672,-0.0421505]]}}, +{"best":0.407359,"evaluations":96,"generation":15,"median":1.83613,"state":{"best":[0.0121253,0.00165704],"population":[[0.0374681,-0.0673178],[-0.130004,0.00646458],[0.0950325,0.0174792],[0.0957376,0.0382859],[-0.0961402,-0.0850978],[-0.0248626,-0.0813999]]}}, +{"best":0.407359,"evaluations":102,"generation":16,"median":1.76369,"state":{"best":[0.0121253,0.00165704],"population":[[0.037474,-0.078336],[-0.0716166,-0.127638],[-0.00348275,-0.167708],[0.0305961,-0.106336],[0.0506222,-0.0373922],[0.100251,-0.0358085]]}}, +{"best":0.407359,"evaluations":114,"generation":18,"median":2.03346,"state":{"best":[0.0121253,0.00165704],"population":[[-0.00258816,-0.0572864],[0.0768711,-0.084819],[0.00201085,-0.155316],[-0.0251432,-0.131173],[-0.0188206,-0.0551776],[-0.0181975,-0.0391434]]}}, +{"best":0.407359,"evaluations":120,"generation":19,"median":1.68312,"state":{"best":[0.0121253,0.00165704],"population":[[-0.0522041,-0.0321854],[-0.0431262,-0.064484],[-0.00643848,-0.0717836],[0.0279988,-0.00484102],[0.060404,-0.036167],[-0.00914825,-0.123483]]}}, +{"best":0.407359,"evaluations":126,"generation":20,"median":1.31727,"state":{"best":[0.0121253,0.00165704],"population":[[0.0543264,-0.0776949],[0.0300415,-0.0107504],[0.00973039,-0.0635019],[-0.00293541,0.00938319],[-0.0276043,-0.0597132],[-0.000971861,-0.0662253]]}}, +{"best":0.333677,"evaluations":138,"generation":22,"median":1.18424,"state":{"best":[-0.00431455,-0.00349551],"population":[[0.00726751,0.0178509],[0.0434666,0.0263811],[-0.00485571,0.0186693],[0.000321995,0.0101328],[0.0125229,-0.0553868],[0.0231992,0.0549727]]}}, +{"best":0.333677,"evaluations":144,"generation":23,"median":0.850807,"state":{"best":[-0.00431455,-0.00349551],"population":[[-0.0448843,0.0469291],[0.0416367,0.00209779],[0.00685787,0.00979667],[0.0197243,-0.0208111],[-0.0138141,-0.0133969],[-0.0130146,-0.00050774]]}}, +{"best":0.248444,"evaluations":156,"generation":25,"median":0.503048,"state":{"best":[0.00169507,0.00265303],"population":[[0.00767322,0.0287825],[0.0255045,-0.00892883],[-0.00554379,0.000723279],[0.00231031,0.00241669],[0.00169507,0.00265303],[0.0101281,-0.0102511]]}}, +{"best":0.248444,"evaluations":162,"generation":26,"median":0.496838,"state":{"best":[0.00169507,0.00265303],"population":[[0.0114024,0.00491344],[0.0126603,-0.00942464],[0.00489404,0.00313471],[0.00848236,0.0200456],[-0.000409758,-0.00997633],[0.00310973,0.00989958]]}}, +{"best":0.248444,"evaluations":168,"generation":27,"median":0.496858,"state":{"best":[0.00169507,0.00265303],"population":[[-0.0033624,-0.018713],[0.00916627,0.0123565],[-0.0040245,-0.00886076],[-0.00431993,0.0030269],[-0.00383477,-0.00358024],[-0.0107625,-0.00665251]]}}, +{"best":0.174675,"evaluations":180,"generation":29,"median":0.373925,"state":{"best":[0.000207003,0.00244687],"population":[[0.00573648,-0.00163033],[0.000207003,0.00244687],[0.000771712,0.00598983],[-5.02768e-05,0.00598447],[-0.00735858,-0.00331245],[-0.00116378,0.00758024]]}}, +{"best":0.0915111,"evaluations":186,"generation":30,"median":0.346632,"state":{"best":[-6.43435e-05,-0.00120321],"population":[[-6.43435e-05,-0.00120321],[0.00567496,0.00291984],[-0.00492053,-0.00471653],[-0.000707611,-0.000310582],[0.00258701,-0.00293242],[0.00514709,0.0108436]]}}, +{"best":0.0915111,"evaluations":192,"generation":31,"median":0.332103,"state":{"best":[-6.43435e-05,-0.00120321],"population":[[-0.00803838,0.000977338],[-0.0037352,-0.00433179],[-0.000820464,0.00404305],[0.00334291,0.0059394],[0.00517269,0.000140506],[-0.00493923,-0.00653855]]}}, +{"best":0.0915111,"evaluations":204,"generation":33,"median":0.33238,"state":{"best":[-6.43435e-05,-0.00120321],"population":[[0.00162636,0.00682174],[-0.00217008,0.00702447],[-0.00260439,0.00610725],[0.000547537,0.00229696],[-0.000228927,0.00485566],[0.00146278,0.00393583]]}}, +{"best":0.0915111,"evaluations":210,"generation":34,"median":0.255028,"state":{"best":[-6.43435e-05,-0.00120321],"population":[[0.00163636,0.00187909],[0.000870915,0.00461163],[0.000452115,0.00582042],[0.000907191,0.00466588],[-0.000999332,0.00143108],[0.00120233,0.00175783]]}}, +{"best":0.0882317,"evaluations":216,"generation":35,"median":0.158407,"state":{"best":[-0.000549582,-0.000189257],"population":[[-0.000858153,0.00216095],[-0.00042899,0.00258618],[0.000419128,0.00156486],[-0.000245279,0.00471018],[0.000613802,-0.000265311],[-0.000549582,-0.000189257]]}}, +{"best":0.051586,"evaluations":228,"generation":37,"median":0.0923278,"state":{"best":[0.000275935,-6.59917e-05],"population":[[-0.000892543,0.00191091],[0.000275935,-6.59917e-05],[0.00029103,-0.000628253],[-0.000397111,-0.000643922],[3.48228e-05,0.001405],[-0.000353666,0.000437]]}}, +{"best":0.051586,"evaluations":234,"generation":38,"median":0.10782,"state":{"best":[0.000275935,-6.59917e-05],"population":[[0.00045995,0.00121987],[0.00042018,0.00089785],[0.000586586,0.00125292],[-0.0006477,0.000333813],[0.00126938,0.000382713],[-0.000111354,0.000483414]]}}, +{"best":0.0317836,"evaluations":246,"generation":40,"median":0.0964279,"state":{"best":[-6.723e-05,-0.000106867],"population":[[-0.000145542,-0.00143299],[0.000149007,0.000318148],[-0.00049441,0.000545494],[-0.000491578,-0.000508002],[-0.000548622,-0.000971164],[1.69687e-05,0.00110608]]}}, +{"best":0.0317836,"evaluations":252,"generation":41,"median":0.0904607,"state":{"best":[-6.723e-05,-0.000106867],"population":[[0.00081952,0.00193504],[-0.000297943,0.000213193],[-0.000770651,0.000623102],[0.000323863,0.00108834],[-7.45338e-05,0.000248376],[0.000179256,-0.000151404]]}}, +{"best":0.0317836,"evaluations":258,"generation":42,"median":0.0822706,"state":{"best":[-6.723e-05,-0.000106867],"population":[[9.83484e-05,-0.000704352],[4.77458e-05,-0.000536818],[0.000221568,-0.000335075],[0.000134142,-0.000310057],[0.000551507,0.000311755],[-0.000315251,-0.000651594]]}}, +{"best":0.0317836,"evaluations":270,"generation":44,"median":0.0749596,"state":{"best":[-6.723e-05,-0.000106867],"population":[[0.000326443,0.000260129],[0.000317605,-0.000384148],[0.000761218,0.000561689],[0.000486571,0.000675577],[0.000254148,-0.000130827],[0.000228354,-0.00028912]]}}, +{"best":0.0317836,"evaluations":276,"generation":45,"median":0.0633728,"state":{"best":[-6.723e-05,-0.000106867],"population":[[0.000379762,-0.000328612],[0.00012182,-0.000310137],[0.000387108,-0.000137167],[0.000458353,0.000848817],[0.000182938,-0.000422158],[0.000321714,0.000131865]]}}, +{"best":0.0221137,"evaluations":282,"generation":46,"median":0.0761212,"state":{"best":[9.3854e-05,-1.11299e-05],"population":[[0.000239601,-0.000213521],[0.000153119,9.62307e-05],[0.000233059,-0.000223442],[9.3854e-05,-1.11299e-05],[0.000102435,-0.000617621],[0.000498329,-0.000446411]]}}, +{"best":0.0221137,"evaluations":294,"generation":48,"median":0.0557396,"state":{"best":[9.3854e-05,-1.11299e-05],"population":[[0.000243556,0.000155585],[0.000330099,0.000350377],[-7.58122e-06,0.000131913],[5.37732e-05,-0.000102581],[0.000308019,0.000268192],[0.000346645,0.000107141]]}}, +{"best":0.0119825,"evaluations":300,"generation":49,"median":0.0328503,"state":{"best":[2.02211e-05,-9.01866e-06],"population":[[5.04834e-05,-0.000140535],[-8.54297e-05,-6.34211e-05],[1.92114e-05,-0.000251738],[0.000188973,0.000324196],[2.02211e-05,-9.01866e-06],[-9.91324e-05,-0.000152994]]}}, +{"best":0.0119825,"evaluations":306,"generation":50,"median":0.0484777,"state":{"best":[2.02211e-05,-9.01866e-06],"population":[[1.75165e-06,-0.00040397],[0.000226154,-0.000279906],[0.000130932,-0.00034731],[7.58189e-05,0.000126376],[-0.000163957,0.000135191],[-0.000110317,-0.000351457]]}}, +{"best":0.0119825,"evaluations":318,"generation":52,"median":0.0295722,"state":{"best":[2.02211e-05,-9.01866e-06],"population":[[4.73422e-05,0.000114971],[4.30375e-05,0.000143164],[2.51764e-05,-0.000142856],[-1.28774e-05,3.51908e-05],[9.45461e-05,0.000183815],[0.000224435,-7.27056e-05]]}}, +{"best":0.0119825,"evaluations":324,"generation":53,"median":0.032532,"state":{"best":[2.02211e-05,-9.01866e-06],"population":[[-0.000125965,-1.65706e-05],[5.4749e-05,0.000231733],[4.34424e-05,-4.11105e-05],[-0.000156988,0.000133295],[-0.000241258,-0.000148574],[1.77239e-05,-4.8002e-05]]}}, +{"best":0.0112602,"evaluations":336,"generation":55,"median":0.0265405,"state":{"best":[-2.18886e-05,-7.04231e-06],"population":[[6.91997e-05,4.73876e-07],[-0.000155706,-0.000199403],[6.49339e-05,-1.60768e-05],[6.07905e-05,-7.68415e-06],[-0.000115437,-0.000165986],[-0.000115056,5.85566e-05]]}}, +{"best":0.0112602,"evaluations":342,"generation":56,"median":0.0233633,"state":{"best":[-2.18886e-05,-7.04231e-06],"population":[[3.00627e-05,-8.94977e-06],[3.49289e-05,-3.90191e-05],[-9.78273e-05,-3.31296e-05],[0.000126322,0.000156645],[0.000123181,-8.0932e-05],[0.000116695,1.67019e-05]]}}, +{"best":0.0112602,"evaluations":348,"generation":57,"median":0.0176473,"state":{"best":[-2.18886e-05,-7.04231e-06],"population":[[6.22724e-05,-0.000139646],[-2.42413e-05,-4.14407e-05],[8.27319e-05,1.91482e-05],[-4.55087e-05,3.19185e-06],[-1.52314e-05,4.06607e-05],[2.59931e-05,1.90607e-05]]}}, +{"best":0.00727074,"evaluations":360,"generation":59,"median":0.019024,"state":{"best":[4.92589e-06,-1.72771e-05],"population":[[-0.000151262,-5.80397e-05],[6.99276e-06,2.58475e-05],[4.92589e-06,-1.72771e-05],[-2.42972e-05,-4.64312e-05],[4.28391e-05,-2.90826e-05],[0.000124299,3.2807e-05]]}}, +{"best":0.00727074,"evaluations":366,"generation":60,"median":0.0167706,"state":{"best":[4.92589e-06,-1.72771e-05],"population":[[2.2853e-05,2.80207e-05],[5.72325e-05,9.29688e-06],[-1.51487e-05,-3.29695e-05],[5.92365e-05,-1.3699e-06],[-5.72107e-05,-1.19307e-05],[-2.84185e-05,-2.5646e-05]]}}, +{"best":0.00176083,"evaluations":372,"generation":61,"median":0.0135596,"state":{"best":[1.84472e-06,-5.89935e-07],"population":[[-3.0217e-05,9.63558e-06],[1.84472e-06,-5.89935e-07],[2.08572e-05,-1.91562e-05],[3.3484e-05,-5.63484e-05],[-1.83739e-05,1.78283e-05],[1.99272e-05,-7.87694e-05]]}}, +{"best":0.00176083,"evaluations":384,"generation":63,"median":0.0149048,"state":{"best":[1.84472e-06,-5.89935e-07],"population":[[-1.28327e-05,-2.32108e-05],[4.06621e-05,-3.09728e-05],[-2.91025e-05,1.20532e-05],[-3.92106e-05,-2.06411e-05],[-1.20833e-05,-3.27665e-05],[-1.97995e-05,-2.88774e-05]]}}, +{"best":0.00176083,"evaluations":390,"generation":64,"median":0.0135068,"state":{"best":[1.84472e-06,-5.89935e-07],"population":[[-1.83159e-05,1.33719e-05],[2.68468e-05,-3.38918e-05],[1.44165e-06,-1.71214e-05],[-1.62145e-05,4.5137e-05],[-2.61318e-05,-2.46757e-05],[-1.30984e-05,-3.88876e-05]]}}, +{"best":0.00176083,"evaluations":396,"generation":65,"median":0.0073534,"state":{"best":[1.84472e-06,-5.89935e-07],"population":[[-1.69577e-05,-3.87356e-05],[4.82274e-06,-1.63175e-05],[-1.47095e-05,6.26432e-06],[5.81267e-07,2.07133e-05],[-6.29154e-06,-1.1823e-05],[-6.53663e-07,-4.31297e-06]]}}, +{"best":0.00176083,"evaluations":408,"generation":67,"median":0.00753692,"state":{"best":[1.84472e-06,-5.89935e-07],"population":[[7.7361e-06,3.07875e-06],[-2.03208e-05,5.16644e-06],[-7.60843e-06,1.74952e-05],[3.5432e-06,-5.3241e-06],[-6.84678e-06,-7.98067e-06],[-1.04166e-05,2.74792e-06]]}}, +{"best":0.00171087,"evaluations":414,"generation":68,"median":0.00494699,"state":{"best":[9.02641e-07,4.5851e-07],"population":[[9.02641e-07,4.5851e-07],[-5.36832e-06,-6.0232e-06],[2.96576e-06,1.58261e-05],[-4.45962e-06,-5.36708e-06],[-1.28261e-05,-2.0729e-05],[2.32128e-06,1.24668e-06]]}}, +{"best":0.00171087,"evaluations":426,"generation":70,"median":0.00521997,"state":{"best":[9.02641e-07,4.5851e-07],"population":[[-4.32641e-06,-6.44975e-06],[-3.0918e-06,-2.9327e-06],[-2.25665e-06,-2.93383e-06],[6.30033e-06,-9.2464e-06],[4.87718e-06,3.42569e-06],[-3.34247e-06,1.1743e-05]]}}, +{"best":0.00171087,"evaluations":432,"generation":71,"median":0.00247208,"state":{"best":[9.02641e-07,4.5851e-07],"population":[[-3.59389e-06,-2.38015e-08],[-7.073e-06,3.95945e-07],[-2.42534e-07,5.41901e-06],[-1.03702e-06,1.81474e-06],[1.84618e-06,5.77732e-07],[-3.03215e-06,1.89465e-06]]}}, +{"best":0.000517931,"evaluations":438,"generation":72,"median":0.0020635,"state":{"best":[2.04868e-07,-8.80207e-08],"population":[[2.04868e-07,-8.80207e-08],[6.58749e-07,-1.00216e-06],[-1.18783e-06,-2.56235e-06],[-2.35877e-06,4.46653e-06],[-1.65591e-06,-6.74694e-07],[8.98002e-07,1.39741e-06]]}}, +{"best":0.000517931,"evaluations":450,"generation":74,"median":0.00161091,"state":{"best":[2.04868e-07,-8.80207e-08],"population":[[-3.75637e-07,-2.56785e-06],[-1.1808e-07,-1.92964e-06],[-6.18497e-07,7.62384e-07],[-1.76719e-07,-1.71208e-06],[2.04173e-06,1.48856e-07],[1.62663e-06,-7.42587e-07]]}}, +{"best":0.000517931,"evaluations":456,"generation":75,"median":0.00275922,"state":{"best":[2.04868e-07,-8.80207e-08],"population":[[1.70916e-06,-5.1907e-07],[2.99756e-09,7.85807e-07],[-1.45782e-06,-3.15451e-06],[-1.21686e-06,-2.84073e-06],[9.84074e-07,-1.16391e-06],[-2.64635e-06,-1.20575e-06]]}}, +{"best":0.000517931,"evaluations":462,"generation":76,"median":0.00231861,"state":{"best":[2.04868e-07,-8.80207e-08],"population":[[3.77978e-06,1.56403e-06],[-4.22842e-07,9.08852e-07],[2.15571e-06,7.89987e-07],[1.3401e-06,-7.70669e-07],[1.65086e-06,1.31542e-06],[-1.7428e-07,2.56948e-06]]}}, +{"best":0.000517931,"evaluations":474,"generation":78,"median":0.0016578,"state":{"best":[2.04868e-07,-8.80207e-08],"population":[[6.51979e-07,-2.87227e-07],[-9.12579e-07,-1.12891e-06],[3.48991e-07,5.25536e-07],[-7.81783e-07,-8.79445e-07],[2.36657e-07,8.31644e-07],[-6.69348e-07,-9.44103e-07]]}}, +{"best":0.000517931,"evaluations":480,"generation":79,"median":0.00153332,"state":{"best":[2.04868e-07,-8.80207e-08],"population":[[9.9924e-07,-2.04292e-07],[5.07368e-07,7.62703e-07],[-2.88674e-07,-9.13032e-07],[1.27744e-06,-6.08331e-07],[3.36755e-07,-4.55576e-07],[-5.24926e-07,1.42395e-06]]}}, +{"best":0.000517931,"evaluations":486,"generation":80,"median":0.0012789,"state":{"best":[2.04868e-07,-8.80207e-08],"population":[[-3.13282e-08,-6.83335e-07],[1.73777e-07,-7.93007e-07],[6.54987e-07,-3.1785e-07],[7.85301e-07,-3.13963e-07],[5.11869e-08,-7.6141e-07],[3.80592e-07,-9.92028e-07]]}}, +{"best":0.000435526,"evaluations":498,"generation":82,"median":0.00119974,"state":{"best":[1.56426e-07,6.34116e-08],"population":[[8.61277e-07,7.59679e-07],[3.59761e-07,2.22373e-07],[2.85937e-07,9.4939e-07],[7.3089e-07,3.96495e-07],[-1.21001e-07,-3.6046e-07],[1.73173e-07,-3.10893e-07]]}}, +{"best":0.000435526,"evaluations":504,"generation":83,"median":0.000953536,"state":{"best":[1.56426e-07,6.34116e-08],"population":[[-2.61537e-07,-5.28669e-07],[2.99777e-07,3.93902e-07],[5.99354e-07,8.53024e-08],[3.88277e-07,-1.44302e-07],[-3.43394e-07,2.34792e-08],[4.76622e-07,-7.10562e-07]]}}, +{"best":0.000435526,"evaluations":516,"generation":85,"median":0.000870148,"state":{"best":[1.56426e-07,6.34116e-08],"population":[[2.30965e-08,2.95116e-07],[5.38484e-07,1.08159e-06],[2.23777e-07,3.02435e-07],[-2.26296e-07,9.74551e-07],[-2.44686e-07,-1.36632e-07],[1.34816e-07,3.61737e-07]]}}, +{"best":0.000258207,"evaluations":522,"generation":86,"median":0.000567224,"state":{"best":[6.15485e-08,2.78176e-08],"population":[[1.95783e-08,5.51593e-07],[-1.08955e-07,8.43204e-07],[-1.86915e-07,-3.61377e-08],[6.15485e-08,2.78176e-08],[-2.33888e-07,1.65169e-07],[-1.79996e-07,-6.1141e-08]]}}, +{"best":0.000258207,"evaluations":528,"generation":87,"median":0.000636561,"state":{"best":[6.15485e-08,2.78176e-08],"population":[[-3.67071e-08,3.12334e-07],[-7.62609e-08,1.79085e-07],[-3.39388e-07,-1.09049e-07],[-3.76135e-08,8.14595e-08],[-2.13606e-07,-5.10418e-08],[-2.16456e-07,2.73745e-07]]}}, +{"best":0.000258207,"evaluations":540,"generation":89,"median":0.000488753,"state":{"best":[6.15485e-08,2.78176e-08],"population":[[1.16209e-07,4.16117e-08],[-5.64201e-08,-2.8197e-07],[4.43495e-08,-2.50057e-07],[2.46172e-08,-2.15139e-07],[-1.49069e-07,-1.11563e-07],[3.22655e-08,4.48581e-08]]}}, +{"best":0.000190409,"evaluations":546,"generation":90,"median":0.000392207,"state":{"best":[8.63489e-09,7.07893e-08],"population":[[8.45205e-08,1.66569e-07],[8.63489e-09,7.07893e-08],[1.36694e-07,6.11714e-08],[-5.0995e-08,-1.82841e-07],[-2.35038e-08,5.42817e-08],[-3.07425e-08,-2.10712e-07]]}}, +{"best":0.000190409,"evaluations":552,"generation":91,"median":0.000282624,"state":{"best":[8.63489e-09,7.07893e-08],"population":[[1.76634e-08,-8.38141e-08],[-4.77036e-08,3.3417e-08],[3.67401e-08,-5.51109e-08],[-4.24928e-08,-2.00663e-08],[9.8772e-09,1.23575e-07],[-4.48199e-08,-3.26914e-08]]}}, +{"best":0.000118664,"evaluations":564,"generation":93,"median":0.000277657,"state":{"best":[-1.90807e-08,-3.94922e-09],"population":[[4.62368e-08,1.02651e-07],[-5.46847e-08,6.58095e-08],[2.60977e-08,5.75784e-08],[-1.90807e-08,-3.94922e-09],[4.58579e-09,-6.2699e-08],[3.03469e-08,-7.5544e-08]]}}, +{"best":0.000118664,"evaluations":570,"generation":94,"median":0.000236224,"state":{"best":[-1.90807e-08,-3.94922e-09],"population":[[-3.62645e-08,-9.39629e-09],[-8.53367e-08,-4.17845e-08],[-1.81368e-08,-4.86578e-08],[-6.73195e-09,-4.46367e-08],[-2.94647e-08,-1.08393e-07],[-5.47581e-08,4.8151e-08]]}}, +{"best":8.93062e-05,"evaluations":576,"generation":95,"median":0.000131443,"state":{"best":[1.26862e-09,-1.33449e-08],"population":[[1.26862e-09,-1.33449e-08],[-4.73525e-09,-2.39474e-08],[-3.43228e-08,-5.53622e-08],[-1.79265e-08,-1.91134e-08],[-3.85093e-08,-4.68397e-08],[1.79094e-08,-7.03723e-09]]}}, +{"best":7.08007e-05,"evaluations":588,"generation":97,"median":0.000184601,"state":{"best":[4.47976e-09,7.21405e-09],"population":[[-4.98904e-09,-5.7812e-08],[-3.25249e-08,-1.19086e-08],[-2.40198e-08,-7.0002e-09],[-3.35386e-08,5.26106e-09],[2.21607e-08,-9.56358e-09],[-6.74751e-08,-1.75672e-08]]}}, +{"best":7.08007e-05,"evaluations":594,"generation":98,"median":0.000184857,"state":{"best":[4.47976e-09,7.21405e-09],"population":[[7.05875e-09,-5.26897e-08],[-2.63268e-08,3.05854e-08],[-1.25916e-08,-3.02774e-08],[5.74595e-09,-1.91296e-08],[-1.38096e-08,1.87021e-08],[-1.70213e-08,-3.60735e-08]]}}, +{"best":5.80968e-05,"evaluations":606,"generation":100,"median":0.000116819,"state":{"best":[3.20291e-09,5.05079e-09],"population":[[3.20291e-09,5.05079e-09],[-2.37492e-08,1.13208e-08],[-8.66374e-09,-3.03932e-09],[-8.74065e-09,1.24488e-08],[-1.94378e-08,8.10863e-09],[1.6275e-08,-8.63895e-09]]}}, +{"best":1.85529e-05,"evaluations":612,"generation":101,"median":8.67277e-05,"state":{"best":[-1.13271e-09,3.08795e-10],"population":[[-1.13271e-09,3.08795e-10],[1.11618e-09,1.32683e-08],[-8.52531e-09,1.97581e-08],[1.23048e-08,1.23293e-09],[1.10671e-09,-8.00882e-09],[3.80386e-09,-1.00196e-08]]}}, +{"best":1.85529e-05,"evaluations":618,"generation":102,"median":7.64805e-05,"state":{"best":[-1.13271e-09,3.08795e-10],"population":[[2.33973e-09,-1.14256e-08],[5.56963e-09,4.08808e-09],[1.08593e-08,-1.02447e-09],[1.76097e-08,-1.24546e-08],[-4.62867e-09,-3.70473e-09],[4.02067e-09,2.44953e-09]]}}, +{"best":1.85529e-05,"evaluations":630,"generation":104,"median":7.33519e-05,"state":{"best":[-1.13271e-09,3.08795e-10],"population":[[-2.95801e-09,4.74898e-09],[-1.12092e-08,1.06679e-09],[-5.00774e-09,4.94959e-09],[-1.42774e-08,-4.79028e-09],[6.62695e-09,3.62682e-09],[-6.25057e-09,7.01049e-09]]}}, +{"best":1.85529e-05,"evaluations":636,"generation":105,"median":7.199e-05,"state":{"best":[-1.13271e-09,3.08795e-10],"population":[[3.04547e-09,7.57857e-10],[8.02895e-09,6.89546e-09],[1.72745e-09,1.16661e-08],[-1.08248e-08,6.70884e-09],[-1.7434e-09,1.02615e-08],[-1.96238e-09,3.75974e-09]]}}, +{"best":1.85529e-05,"evaluations":642,"generation":106,"median":3.63724e-05,"state":{"best":[-1.13271e-09,3.08795e-10],"population":[[-1.59438e-09,3.61564e-09],[4.111e-09,6.74271e-10],[4.94953e-09,-2.26387e-10],[-1.17736e-09,-2.40872e-10],[6.95953e-09,1.07552e-10],[-1.71601e-09,-2.43218e-09]]}}, +{"best":1.06584e-05,"evaluations":654,"generation":108,"median":5.21702e-05,"state":{"best":[6.10691e-10,-1.53204e-10],"population":[[4.15296e-09,3.57291e-09],[2.02602e-09,8.66407e-10],[-4.21702e-09,4.0596e-09],[-2.92304e-09,1.42145e-09],[-4.09296e-09,-2.53091e-09],[2.07204e-09,4.25475e-09]]}}, +{"best":1.06584e-05,"evaluations":660,"generation":109,"median":2.1775e-05,"state":{"best":[6.10691e-10,-1.53204e-10],"population":[[2.531e-10,-1.41158e-09],[2.44635e-10,-2.15552e-09],[-2.50162e-09,3.81082e-09],[8.741e-10,-1.52214e-10],[8.4354e-10,8.21255e-10],[1.16876e-09,3.19652e-09]]}}, +{"best":1.06584e-05,"evaluations":666,"generation":110,"median":2.19253e-05,"state":{"best":[6.10691e-10,-1.53204e-10],"population":[[9.68526e-10,-3.18572e-11],[1.1962e-09,-7.68208e-10],[1.62312e-09,-1.57149e-09],[8.61125e-11,2.44799e-09],[2.31694e-09,1.04075e-09],[-5.85164e-10,8.46085e-10]]}}, +{"best":7.87846e-06,"evaluations":678,"generation":112,"median":2.18353e-05,"state":{"best":[2.98092e-10,2.56418e-10],"population":[[-1.67846e-09,4.74342e-10],[3.47144e-10,-6.12966e-10],[-2.03949e-10,1.62978e-09],[-3.45504e-10,-1.7836e-09],[1.30589e-09,-6.69438e-10],[-4.32139e-10,1.39702e-09]]}}, +{"best":7.87846e-06,"evaluations":684,"generation":113,"median":1.85551e-05,"state":{"best":[2.98092e-10,2.56418e-10],"population":[[5.78007e-10,-1.10865e-09],[9.69984e-10,-2.12857e-10],[3.8864e-10,-9.65971e-11],[-7.28326e-10,6.12151e-10],[1.02903e-09,-1.73128e-09],[-7.52487e-10,-1.15288e-09]]}}, +{"best":3.56601e-06,"evaluations":696,"generation":115,"median":1.44159e-05,"state":{"best":[-1.23268e-11,2.36202e-10],"population":[[3.56173e-10,9.19036e-10],[3.71495e-10,8.25437e-10],[-1.23268e-11,2.36202e-10],[5.87449e-10,5.74159e-10],[4.32874e-10,-4.01753e-10],[2.76018e-10,1.94897e-10]]}}, +{"best":3.56601e-06,"evaluations":702,"generation":116,"median":1.04514e-05,"state":{"best":[-1.23268e-11,2.36202e-10],"population":[[-1.40572e-10,3.64084e-10],[4.48566e-10,1.32938e-10],[-3.97407e-10,7.35545e-10],[5.67795e-10,1.12497e-10],[2.88725e-10,2.82223e-10],[-1.0481e-09,3.78937e-10]]}}, +{"best":3.56601e-06,"evaluations":708,"generation":117,"median":1.0137e-05,"state":{"best":[-1.23268e-11,2.36202e-10],"population":[[3.82538e-10,-5.91172e-12],[7.20454e-10,-5.70533e-12],[3.05941e-10,2.47277e-10],[7.4906e-10,4.60131e-10],[5.67065e-10,4.02432e-10],[3.91948e-10,-2.78418e-10]]}}, +{"best":1.27468e-06,"evaluations":720,"generation":119,"median":6.30973e-06,"state":{"best":[4.84495e-11,-4.81605e-11],"population":[[5.90575e-11,1.76152e-10],[2.6258e-10,-2.68503e-10],[4.84495e-11,-4.81605e-11],[3.46454e-10,2.12714e-10],[-4.15992e-11,3.15257e-10],[3.12788e-10,1.89295e-10]]}}, +{"best":1.27468e-06,"evaluations":726,"generation":120,"median":3.60602e-06,"state":{"best":[4.84495e-11,-4.81605e-11],"population":[[-3.73545e-10,9.81161e-11],[1.12192e-10,-1.9428e-11],[2.60049e-10,3.14486e-10],[-2.23976e-11,-2.15192e-10],[2.02554e-10,-6.82643e-12],[-6.54232e-12,1.91893e-10]]}}, +{"best":9.87174e-07,"evaluations":732,"generation":121,"median":4.8534e-06,"state":{"best":[4.09949e-11,4.32476e-11],"population":[[7.62868e-11,1.48266e-10],[3.70481e-10,2.09727e-10],[2.16681e-10,-7.99364e-11],[-2.11744e-10,-3.53129e-11],[4.09949e-11,4.32476e-11],[-2.69432e-10,3.10949e-10]]}}, +{"best":9.87174e-07,"evaluations":744,"generation":123,"median":6.43394e-06,"state":{"best":[4.09949e-11,4.32476e-11],"population":[[-4.12841e-10,1.43289e-11],[-2.6285e-10,2.31148e-11],[-1.39885e-11,7.66899e-11],[-1.23445e-10,-3.04854e-10],[-1.00004e-10,-2.14669e-10],[-2.99816e-10,-1.3272e-10]]}}, +{"best":4.02839e-07,"evaluations":750,"generation":124,"median":3.88032e-06,"state":{"best":[-3.62681e-11,1.03959e-11],"population":[[-3.62681e-11,1.03959e-11],[-9.80342e-11,1.31227e-11],[-4.84301e-11,2.19753e-10],[-8.36229e-11,9.51306e-11],[-5.33111e-11,-2.23276e-10],[-2.14217e-10,-4.66531e-11]]}}, +{"best":1.62971e-07,"evaluations":756,"generation":125,"median":2.83668e-06,"state":{"best":[5.44198e-12,-2.30922e-11],"population":[[5.44198e-12,-2.30922e-11],[5.77162e-11,1.68914e-11],[-1.3574e-10,4.18144e-11],[-1.19765e-10,-8.74273e-11],[-5.84184e-11,7.10262e-11],[-2.2509e-10,-6.69801e-11]]}}, +{"best":1.62971e-07,"evaluations":768,"generation":127,"median":1.55829e-06,"state":{"best":[5.44198e-12,-2.30922e-11],"population":[[-5.71602e-11,2.12497e-13],[8.42038e-11,-1.66098e-11],[-1.23555e-10,-3.42444e-11],[-6.51209e-11,-7.65993e-12],[-1.62078e-10,8.02641e-11],[6.03462e-11,3.86121e-11]]}}, +{"best":8.98284e-08,"evaluations":774,"generation":128,"median":1.54494e-06,"state":{"best":[-1.09892e-11,-1.3641e-11],"population":[[-8.64384e-11,-2.41281e-11],[5.33489e-11,-3.8928e-11],[-1.96596e-10,-1.76437e-11],[2.62002e-11,-6.41542e-13],[-1.09892e-11,-1.3641e-11],[-1.29783e-10,-1.94486e-11]]}}, +{"best":5.19588e-08,"evaluations":786,"generation":130,"median":6.27717e-07,"state":{"best":[1.19669e-11,5.83622e-12],"population":[[6.05627e-11,1.32728e-11],[-2.09507e-11,2.48207e-11],[6.96314e-11,-1.42291e-11],[3.82825e-11,2.13444e-11],[-1.9744e-11,-1.497e-11],[-4.06161e-11,-2.9632e-11]]}}, +{"best":1.9513e-08,"evaluations":792,"generation":131,"median":1.38177e-07,"state":{"best":[7.98606e-12,-1.63286e-12],"population":[[2.40904e-11,1.14744e-11],[-6.57724e-12,7.3952e-12],[7.98606e-12,-1.63286e-12],[-9.43904e-11,1.16861e-11],[2.05861e-11,7.40463e-12],[-9.16839e-12,-1.96788e-11]]}}, +{"best":1.9513e-08,"evaluations":798,"generation":132,"median":2.69162e-07,"state":{"best":[7.98606e-12,-1.63286e-12],"population":[[3.09852e-11,-8.10657e-12],[1.56207e-11,-2.53322e-11],[-3.912e-11,1.17948e-11],[1.8279e-11,1.30536e-11],[1.01726e-11,-7.33258e-12],[2.81443e-11,1.36893e-11]]}}, +{"best":1.11622e-08,"evaluations":810,"generation":134,"median":4.10126e-08,"state":{"best":[6.03173e-12,1.26277e-12],"population":[[-7.65393e-12,8.85958e-13],[7.57006e-12,-3.95278e-12],[-1.07219e-11,9.57423e-12],[-2.99601e-11,-1.64313e-14],[2.31742e-11,1.88249e-12],[6.83076e-12,1.28597e-12]]}}, +{"best":6.10058e-10,"evaluations":816,"generation":135,"median":2.28144e-08,"state":{"best":[1.0637e-12,9.70446e-13],"population":[[-2.79154e-12,-5.52974e-12],[1.1676e-11,3.00882e-12],[-9.65916e-12,-4.87049e-12],[1.0637e-12,9.70446e-13],[-1.20615e-11,1.15887e-11],[4.13714e-12,-3.98764e-12]]}} +]} diff --git a/examples/weierstrass/trace.py b/examples/weierstrass/trace.py new file mode 100644 index 00000000..7c8650cf --- /dev/null +++ b/examples/weierstrass/trace.py @@ -0,0 +1,189 @@ +"""The trace for the plot on the example's page, written to the file that ``GENOXIDE_TRACE`` +names. The plot draws the population on the function's contour, which needs two dimensions: the +trace is of a separate run of CMA-ES with IPOP restarts in 2 dimensions, with a budget of +20,000 evaluations, in at most 100 frames. The Rust example writes the same file.""" + +import json +import math +import os + +import genoxide as gx + + +def record_small(): + """Runs CMA-ES with IPOP restarts in 2 dimensions and writes its trace, if ``GENOXIDE_TRACE`` is set.""" + path = os.environ.get("GENOXIDE_TRACE") + if not path: + return + problem = gx.problems.Weierstrass(2) + minimum = problem.optimum.value + budget = 20_000 + cmaes = gx.Cmaes(problem.genome, restarts="ipop", objective="minimize", seed=1) + frames = Frames(100) + + def record(progress): + state = {"population": progress.population.tolist(), "best": progress.best_genome.tolist()} + frames.push(frame(progress, state, minimum)) + + cmaes.run(problem, target=minimum + 1e-8, evaluations=budget, on_generation=record) + low, high = problem.genome.bounds + settings = { + "format": 1, + "example": "weierstrass", + "objective": "minimize", + "x_label": "evaluations", + "y_label": "error", + "log_y": True, + "optimum": 0.0, + "plot": "contour", + "problem": { + "function": "weierstrass", + "bounds": [[float(low), float(high)]] * 2, + "minima": problem.optimum.solutions.tolist(), + }, + } + write(path, settings, frames.to_list()) + + +def frame(progress, state, minimum): + """The frame of a generation: its progress, the errors of its best and of its population's + median to ``minimum`` (rounding can put a solution a few ulps below it), and ``state``.""" + + def error(value): + return None if value is None else max(value - minimum, 0.0) + + return { + "generation": progress.generation, + "evaluations": progress.evaluations, + "best": error(progress.best_fitness), + "median": error(median(progress.scores)), + "state": state, + } + + +def median(scores): + """The median of the valid scores, None without any.""" + scores = sorted(float(score) for score in scores if not math.isnan(score)) + middle = len(scores) // 2 + if not scores: + return None + return scores[middle] if len(scores) % 2 else (scores[middle - 1] + scores[middle]) / 2 + + +# ---- the same in every example's trace ---------------------------------------------------------- + + +class Frames: + """The frames of at most ``most`` generations, from the part of the run where what the page + plots changes: the frames after the last change are left out (a run that reached its target, + or a front that no longer moves), and the rest are spread evenly over the generations up to + it. While the run goes, up to 8 × ``most`` frames are kept: every ``every``-th generation, + with ``every`` doubling whenever there are that many, and the last one.""" + + def __init__(self, most): + self.most, self.every, self.kept, self.last = most, 1, [], None + + def push(self, frame): + if frame["generation"] % self.every: + self.last = frame + return + self.kept.append(frame) + self.last = None + if len(self.kept) == 8 * self.most: + self.every *= 2 + self.kept = [kept for kept in self.kept if kept["generation"] % self.every == 0] + + def to_list(self): + frames = self.kept + ([self.last] if self.last else []) + active = frames[: last_change(frames) + 1] + count, most = len(active), max(self.most, 2) + if count <= most: + return active + return [active[(i * (count - 1) + (most - 1) // 2) // (most - 1)] for i in range(most)] + + +def last_change(frames): + """The index of the frame after which nothing the page plots changes. To 3 significant + digits, as a plot shows them: the best, the median and, for a single objective (a numeric + best), the state; to within a hundredth of their range over the run: a front's + hypervolumes, in the state or in a grid's series.""" + if not frames: + return 0 + last = len(frames) - 1 + number = lambda value: isinstance(value, (int, float)) and not isinstance(value, bool) + single = any(number(frame.get("best")) for frame in frames) + + def measures(frame): + values = [] + state = frame.get("state") + hypervolume = state.get("hypervolume") if isinstance(state, dict) else None + for value in (hypervolume, frame.get("series")): + if number(value): + values.append(float(value)) + elif isinstance(value, dict): + values.extend(float(v) for _, v in sorted(value.items()) if number(v)) + return values + + measured = [measures(frame) for frame in frames] + end = measured[last] + tolerance = [] + for k in range(len(end)): + values = [values[k] for values in measured if k < len(values)] + tolerance.append((max(values) - min(values)) / 100.0) + + def same(frame, final, key, flush=False): + return coarse(frame.get(key), flush) == coarse(final.get(key), flush) + + def settled(i): + frame, final = frames[i], frames[last] + return ( + same(frame, final, "best") + and same(frame, final, "median") + and (not single or same(frame, final, "state", flush=True)) + and len(measured[i]) == len(end) + and all(abs(v - e) <= t for v, e, t in zip(measured[i], end, tolerance)) + ) + + first = last + while first > 0 and settled(first - 1): + first -= 1 + return first + + +def coarse(value, flush=False): + """``value`` with its numbers to 3 significant digits, as precisely as a plot shows them: two + frames whose plotted values agree to that precision look the same. With ``flush``, for the + solutions a plot draws on their ranges, numbers below 1e-6 in size count as 0.""" + if isinstance(value, float): + if flush and abs(value) < 1e-6: + value = 0.0 + return f"{value:.2e}" + if isinstance(value, (list, tuple)): + return "[" + ",".join(coarse(item, flush) for item in value) + "]" + if isinstance(value, dict): + items = sorted(value.items()) + return "{" + ",".join(f"{key}:{coarse(item, flush)}" for key, item in items) + "}" + return json.dumps(value) + + +def write(path, settings, frames): + """Writes the settings and the frames to ``path``, a frame per line.""" + lines = ",\n".join(map(to_json, frames)) + with open(path, "w", encoding="utf-8", newline="\n") as file: + file.write(f'{to_json(settings)[:-1]},"frames":[\n{lines}\n]}}\n') + + +def to_json(value): + """Compact JSON with sorted keys, and numbers rounded to 6 significant digits, as the Rust + example writes it.""" + return json.dumps(rounded(value), sort_keys=True, separators=(",", ":"), ensure_ascii=False) + + +def rounded(value): + if isinstance(value, dict): + return {key: rounded(item) for key, item in value.items()} + if isinstance(value, (list, tuple)): + return [rounded(item) for item in value] + if isinstance(value, float): + return float(f"{value:.5e}") if math.isfinite(value) else None + return value diff --git a/examples/weierstrass/trace.rs b/examples/weierstrass/trace.rs new file mode 100644 index 00000000..930751af --- /dev/null +++ b/examples/weierstrass/trace.rs @@ -0,0 +1,261 @@ +//! The trace for the plot on the example's page, written to the file that `GENOXIDE_TRACE` names. +//! The plot draws the population on the function's contour, which needs two dimensions: the trace +//! is of a separate run of CMA-ES with IPOP restarts in 2 dimensions, with a budget of +//! 20,000 evaluations, in at most 100 frames. The Python example writes the same +//! file. + +use genoxide::observer::Snapshot; +use genoxide::prelude::*; +use genoxide::problems::{Problem, Weierstrass}; +use serde_json::{Value, json}; + +// runs CMA-ES with IPOP restarts in 2 dimensions and writes its trace, if GENOXIDE_TRACE is set +pub fn record_small() -> Result<()> { + let Ok(path) = std::env::var("GENOXIDE_TRACE") else { + return Ok(()); + }; + let problem = Weierstrass::new(2); + let optimum = problem.optimum().expect("known"); + let minimum = optimum.value(); + let budget = 20_000; + let cmaes = Cmaes::builder(problem.representation()) + .restarts(cmaes::Restarts::Ipop) + .minimize() + .seed(1) + .build()?; + let mut frames = Frames::new(100); + Engine::new(cmaes, problem.clone()) + .stop_when(Stop::target(minimum + 1e-8).or(Stop::evaluations(budget))) + .on_generation(|snapshot| { + let population = snapshot.population().iter().map(|x| &x.genome()[..]); + let population: Vec<&[f64]> = population.collect(); + let best = &snapshot.best().genome()[..]; + let state = json!({ "population": population, "best": best }); + frames.push(frame(snapshot, state, minimum)); + }) + .run()?; + let bounds = problem.representation().bounds().to_vec(); + let bounds: Vec<[f64; 2]> = bounds.iter().map(|b| [*b.start(), *b.end()]).collect(); + let minima: Vec<&[f64]> = optimum.solutions().iter().map(|x| &x[..]).collect(); + let settings = json!({ + "format": 1, + "example": "weierstrass", + "objective": "minimize", + "x_label": "evaluations", + "y_label": "error", + "log_y": true, + "optimum": 0.0, + "plot": "contour", + "problem": { + "function": "weierstrass", + "bounds": bounds, + "minima": minima, + }, + }); + write(&path, settings, frames.into_vec()); + Ok(()) +} + +// the frame of a generation: its progress, the errors of its best and of its population's median +// to `minimum` (rounding can put a solution a few ulps below it), and `state` +fn frame(snapshot: &Snapshot<'_, Reals>, state: Value, minimum: f64) -> Value { + let progress = snapshot.progress(); + let error = |value: f64| (value - minimum).max(0.0); + let population = snapshot.population().iter(); + let scores = population.filter_map(|individual| individual.fitness()?.score()); + json!({ + "generation": progress.generation(), + "evaluations": progress.evaluations(), + "best": progress.best().and_then(Fitness::score).map(error), + "median": median(scores.collect()).map(error), + "state": state, + }) +} + +// the median of the scores, None without any +fn median(mut scores: Vec) -> Option { + scores.sort_by(f64::total_cmp); + let middle = scores.len() / 2; + match scores.len() { + 0 => None, + n if n % 2 == 1 => Some(scores[middle]), + _ => Some((scores[middle - 1] + scores[middle]) / 2.0), + } +} + +// ---- the same in every example's trace --------------------------------------------------------- + +// the frames of at most `most` generations, from the part of the run where what the page plots +// changes: the frames after the last change are left out (a run that reached its target, or a +// front that no longer moves), and the rest are spread evenly over the generations up to it. While +// the run goes, up to 8 × `most` frames are kept: every `every`-th generation, with `every` +// doubling whenever there are that many, and the last one. +struct Frames { + most: usize, + every: u64, + kept: Vec<(u64, Value)>, + last: Option<(u64, Value)>, +} + +impl Frames { + fn new(most: usize) -> Self { + let (every, kept, last) = (1, Vec::new(), None); + Self { + most, + every, + kept, + last, + } + } + + fn push(&mut self, frame: Value) { + let generation = frame["generation"].as_u64().expect("a generation"); + if !generation.is_multiple_of(self.every) { + self.last = Some((generation, frame)); + return; + } + self.kept.push((generation, frame)); + self.last = None; + if self.kept.len() == 8 * self.most { + self.every *= 2; + let every = self.every; + self.kept.retain(|(generation, _)| generation % every == 0); + } + } + + fn into_vec(self) -> Vec { + let frames = self.kept.into_iter().chain(self.last); + let frames: Vec = frames.map(|(_, frame)| frame).collect(); + let active = &frames[..=last_change(&frames)]; + let (count, most) = (active.len(), self.most.max(2)); + if count <= most { + return active.to_vec(); + } + let at = |i: usize| active[(i * (count - 1) + (most - 1) / 2) / (most - 1)].clone(); + (0..most).map(at).collect() + } +} + +// the index of the frame after which nothing the page plots changes. To 3 significant digits, as +// a plot shows them: the best, the median and, for a single objective (a numeric best), the state; +// to within a hundredth of their range over the run: a front's hypervolumes, in the state or in a +// grid's series +fn last_change(frames: &[Value]) -> usize { + let Some(last) = frames.len().checked_sub(1) else { + return 0; + }; + let single = frames.iter().any(|frame| frame["best"].is_number()); + let measures = |frame: &Value| -> Vec { + let mut values = Vec::new(); + for value in [&frame["state"]["hypervolume"], &frame["series"]] { + match value { + Value::Number(number) => values.extend(number.as_f64()), + Value::Object(map) => values.extend(map.values().filter_map(Value::as_f64)), + _ => {} + } + } + values + }; + let measured: Vec> = frames.iter().map(measures).collect(); + let end = &measured[last]; + let tolerance: Vec = (0..end.len()) + .map(|k| { + let values = measured.iter().filter_map(|values| values.get(k).copied()); + let (low, high) = values.fold((f64::INFINITY, f64::NEG_INFINITY), |(low, high), v| { + (low.min(v), high.max(v)) + }); + (high - low) / 100.0 + }) + .collect(); + let settled = |i: usize| { + let (frame, final_frame) = (&frames[i], &frames[last]); + let same = + |key: &str, flush: bool| coarse(&frame[key], flush) == coarse(&final_frame[key], flush); + same("best", false) + && same("median", false) + && (!single || same("state", true)) + && measured[i].len() == end.len() + && measured[i] + .iter() + .zip(end) + .zip(&tolerance) + .all(|((value, end), tolerance)| (value - end).abs() <= *tolerance) + }; + let mut first = last; + while first > 0 && settled(first - 1) { + first -= 1; + } + first +} + +// `value` with its numbers to 3 significant digits, as precisely as a plot shows them: two frames +// whose plotted values agree to that precision look the same. With `flush`, for the solutions a +// plot draws on their ranges, numbers below 1e-6 in size count as 0 +fn coarse(value: &Value, flush: bool) -> String { + let join = |items: Vec| items.join(","); + match value { + Value::Number(number) if number.is_f64() => { + let number = number.as_f64().expect("f64"); + let number = if flush && number.abs() < 1e-6 { + 0.0 + } else { + number + }; + format!("{number:.2e}") + } + Value::Array(items) => { + format!( + "[{}]", + join(items.iter().map(|item| coarse(item, flush)).collect()) + ) + } + Value::Object(map) => { + let entry = |(key, item): (&String, &Value)| format!("{key}:{}", coarse(item, flush)); + format!("{{{}}}", join(map.iter().map(entry).collect())) + } + other => other.to_string(), + } +} + +// writes the settings and the frames to `path`, a frame per line +fn write(path: &str, settings: Value, frames: Vec) { + let frames: Vec = frames.iter().map(to_json).collect(); + let settings = to_json(&settings); + let head = &settings[..settings.len() - 1]; + let text = format!("{head},\"frames\":[\n{}\n]}}\n", frames.join(",\n")); + std::fs::write(path, text).expect("the trace is written"); +} + +// compact JSON with sorted keys, and numbers rounded to 6 significant digits and written as +// Python writes them (7542.0, 1e-08): the Python example writes the same file +fn to_json(value: &Value) -> String { + let join = |items: Vec| items.join(","); + match value { + Value::Number(number) if number.is_f64() => python_float(number.as_f64().expect("f64")), + Value::Array(items) => format!("[{}]", join(items.iter().map(to_json).collect())), + Value::Object(map) => { + let entry = + |(key, item): (&String, &Value)| format!("{}:{}", json!(key), to_json(item)); + format!("{{{}}}", join(map.iter().map(entry).collect())) + } + other => other.to_string(), + } +} + +fn python_float(value: f64) -> String { + let rounded: f64 = format!("{value:.5e}").parse().expect("a number"); + let shortest = format!("{rounded:e}"); + let (mantissa, exponent) = shortest.split_once('e').expect("an exponent"); + let exponent: i32 = exponent.parse().expect("an exponent"); + if (-4..16).contains(&exponent) { + let text = rounded.to_string(); + if text.contains('.') { + text + } else { + text + ".0" + } + } else { + let sign = if exponent < 0 { '-' } else { '+' }; + format!("{mantissa}e{sign}{:02}", exponent.abs()) + } +} From 367e3b52bf08f5f3e3c42a100c700954af28aed4 Mon Sep 17 00:00:00 2001 From: Someguy Date: Thu, 1 Oct 2026 17:07:04 +0300 Subject: [PATCH 06/16] docs: batch 10b in the plan, the feature list and AGENTS.md --- AGENTS.md | 2 +- docs/features.md | 4 +-- docs/problems-plan.md | 59 ++++++++++++++++++++++++++++++++----------- 3 files changed, 47 insertions(+), 18 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index e92aa438..618cba70 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -134,7 +134,7 @@ Stops: `Stop::target(score)` (at least as good), `generations(n)`, `evaluations( - Maximize is the default; use `.minimize()`, don't negate. - `None`, `Fitness::invalid()` and NaN are invalid: worse than everything. - **Constraints:** return `(score, violation)`, 0 when feasible, adding up `constraint::at_most(value, limit)`, `at_least`, `equal(value, target, tolerance)`. Deb's rules: feasible beats infeasible, then score or violation decides. Select with `Tournament` or `Rank`: roulette and SUS give infeasible solutions no weight. `Penalty::new(weight)?.fitness(objective, score, violation)` is a static penalty instead. -- **Test problems:** `problems::{Sphere, AxisParallelEllipsoid, Schwefel1_2, Rastrigin, Rosenbrock, Ackley, Griewank, Schwefel2_26, Levy, Zakharov, StyblinskiTang, Michalewicz, Schwefel2_21, Schwefel2_22, DixonPrice, Trid, Powell}::new(n)` (`Powell` takes a multiple of 4) and `problems::{Himmelblau, Branin, GoldsteinPrice, SixHumpCamel, Hartmann3, Hartmann6, Shekel5, Shekel7, Shekel10, Easom, Eggholder, SchafferF6, Beale, Booth, Matyas, Bohachevsky1, Bohachevsky2, Bohachevsky3, ThreeHumpCamel, Langermann, ShekelFoxholes, Kowalik}` are fitness functions for `Engine::new(algorithm, problem)`, all minimized. The `problems::Problem` trait gives `representation()` (the bounds), `optimum()` (`value()`, `solutions()`), `reference()`; `problems::all()` lists them as `Box`. Constrained, with fitness `(score, violation)` and `constraints(&x)` (`g <= 0`, then `h = 0`): `problems::cec2006::{G01, …, G24}` (equalities met within `EQUALITY_TOLERANCE` = 1e-4; `with_tolerance(δ)` for the problems with equalities, e.g. `G03::with_tolerance(δ)`), and `problems::engineering::{WeldedBeam, WeldedBeamRagsdell, PressureVessel, TensionCompressionSpring, SpeedReducer, ThreeBarTruss, CantileverBeam, CarSideImpact}`. `PressureVessel` and `SpeedReducer` round their discrete genes when evaluated; `design(&x)` gives the rounded design. `engineering::GearTrain` has an `Integer` genome and isn't in `all()`. `Optimum::is_proven()` is false for a best known value. +- **Test problems:** `problems::{Sphere, AxisParallelEllipsoid, Schwefel1_2, Rastrigin, Rosenbrock, Ackley, Griewank, Schwefel2_26, Levy, Zakharov, StyblinskiTang, Michalewicz, Schwefel2_21, Schwefel2_22, DixonPrice, Trid, Powell, SumOfDifferentPowers, Step, Quartic, Penalized1, Penalized2, HighConditionedElliptic, BentCigar, Discus, DifferentPowers, BucheRastrigin, NonContinuousRastrigin, Weierstrass, Katsuura, HappyCat, HgBat, SchafferF7, RotatedHyperEllipsoid}::new(n)` (`Powell` takes a multiple of 4; `Quartic::noisy(n)` adds noise drawn from the genome) and `problems::{Himmelblau, Branin, GoldsteinPrice, SixHumpCamel, Hartmann3, Hartmann6, Shekel5, Shekel7, Shekel10, Easom, Eggholder, SchafferF6, Beale, Booth, Matyas, Bohachevsky1, Bohachevsky2, Bohachevsky3, ThreeHumpCamel, Langermann, ShekelFoxholes, Kowalik}` are fitness functions for `Engine::new(algorithm, problem)`, all minimized. The `problems::Problem` trait gives `representation()` (the bounds), `optimum()` (`value()`, `solutions()`), `reference()`; `problems::all()` lists them as `Box`. `problems::Shifted::new(problem, seed)` and `problems::Rotated::new(problem, seed)` make CEC/BBOB-style instances of any of them (e.g. CEC 2005's F10: `Rotated::new(Shifted::new(Rastrigin::new(n), seed), seed)`), keeping the optimum's value. Constrained, with fitness `(score, violation)` and `constraints(&x)` (`g <= 0`, then `h = 0`): `problems::cec2006::{G01, …, G24}` (equalities met within `EQUALITY_TOLERANCE` = 1e-4; `with_tolerance(δ)` for the problems with equalities, e.g. `G03::with_tolerance(δ)`), and `problems::engineering::{WeldedBeam, WeldedBeamRagsdell, PressureVessel, TensionCompressionSpring, SpeedReducer, ThreeBarTruss, CantileverBeam, CarSideImpact}`. `PressureVessel` and `SpeedReducer` round their discrete genes when evaluated; `design(&x)` gives the rounded design. `engineering::GearTrain` has an `Integer` genome and isn't in `all()`. `Optimum::is_proven()` is false for a best known value. - **Extras:** return `Evaluated::new(value, info)` (`value` any of the above, `info` any `Send + Sync + 'static` type, e.g. a struct with a penalty's terms) to keep what the fitness function computed. Read it by type: `outcome.best_info::()`, `snapshot.info::(genome)` and `snapshot.best_info::()` in `.on_generation`, `hall_of_fame.info::(genome)`, and in `MultiEngine` `snapshot.info` and `outcome.info(genome)` for the front; `None` for another type. Never used by the search. Kept by genome for the population, the discarded and the best (copies share it); not in checkpoints. - **Gradients:** `Differentiable(|x: &Reals, gradient: &mut [f64]| value)`, for gradient-based methods; see [Gradients](#gradients-supplying-them). - **Constraint values:** `Constrained::new(m, |x: &Reals, g: &mut [f64]| score)` writes the values of m constraints `gᵢ(x) <= 0`; `Constrained::differentiable(m, |x, gradient, g, jacobian| score)` also the gradient and the Jacobian (`jacobian[i * n + j]` = ∂gᵢ/∂xⱼ). Either is `(score, Σ max(0, gᵢ))` for any algorithm, and gives the values one by one to those that use them (`Mma`). The CEC 2006 problems with inequalities only and the engineering problems give their values (`problem.provides().inequalities`), not their gradients. diff --git a/docs/features.md b/docs/features.md index 1107bf02..9a2217c5 100644 --- a/docs/features.md +++ b/docs/features.md @@ -66,8 +66,8 @@ What genoxide has on main; [docs.rs](https://docs.rs/genoxide) documents the lat - **First-order methods** (`FirstOrder`): steps along the gradient without a line search, for smooth problems with up to millions of variables, by a `first_order::Step` rule: gradient descent, Polyak's momentum, Nesterov's accelerated gradient (Sutskever et al.'s form), Adam (Kingma and Ba's Algorithm 1, with its bias correction) and AdamW (Loshchilov and Hutter's decoupled weight decay, Algorithm 2). One gradient per generation, supplied or by finite differences in the same round; points projected onto the bounds; convergence by the projected gradient or the step (`StopReason::Converged`); a learning rate and a schedule multiplier set by `control`, for schedules; an invalid point stepped back from; random restarts; re-evaluation that keeps the velocity and Adam's averages. O(n) memory and work per step, and no allocation after the first step (tested at a million genes); in Python (`gx.FirstOrder`, with `gradient=`) and the `genoxide` program (`type = "first-order"`, with the gradient protocol). - **MMA and GCMMA** (`Mma`): Svanberg's method of moving asymptotes and its globally convergent form, for smooth problems with very many variables (millions) and few inequality constraints, from the gradients of the score and of every constraint: convex separable approximations with moving asymptotes and the notes' default constants, solved through their dual in the constraints' multipliers (O(n·m) per iteration, no n × n matrix, nothing allocated after the first iteration, the sums in fixed chunks, optionally in parallel with the same bits); artificial variables that keep every subproblem feasible; GCMMA's inner iterations for convergence from any start; convergence by the KKT residual or the step (`StopReason::Converged`); a restoration step onto the feasible side of the active constraints at the end; multipliers, asymptotes and the KKT residual to read, re-evaluation and checkpoints. Reproduces the 2002 paper's table 8.1 and the 1987 paper's cantilever beam. - **Continuation** (`Continuation`, the `Continue` trait): a local method run through stages of one problem, a parameter of the fitness function changed between them by a closure (a smoothing, a p-norm's p, a penalty weight), each stage ending when the method has converged or after its budget of generations, and the run only after the last (`StopReason::Converged`). Each stage starts by evaluating the point again on the changed function, with the method's state kept (`Keep::State`: Adam's averages and step count, MMA's asymptotes, a Nelder-Mead simplex, a CMA-ES distribution; L-BFGS-B's pairs optionally) or only the point (`Keep::Point`). Each stage's generations, evaluations, best value and end reported by a callback and after the run; checkpoints that resume in their stage; nothing allocated per step (tested at a million genes); in Python (`gx.Continuation` around `FirstOrder`, `Lbfgsb` or `Mma`, with Python stage callbacks). -- **Test problems** (`problems`): Sphere, the axis-parallel ellipsoid, Schwefel 1.2 and 2.26, Rastrigin, Rosenbrock, Ackley, Griewank, Levy, Zakharov, Styblinski-Tang, Michalewicz, Himmelblau, Branin, Goldstein-Price, the six-hump camel, Hartmann's functions in 3 and 6 dimensions, Shekel's with 5, 7 and 10 wells, Easom, the eggholder, Schaffer's F6, Schwefel 2.21 and 2.22, Dixon-Price, Trid, Powell's singular function, Beale, Booth, Matyas, Bohachevsky's three functions, the three-hump camel, Langermann, Shekel's foxholes and Kowalik, each with its bounds, its analytic gradient (all but the eggholder and Schwefel 2.21 and 2.22, which aren't differentiable), known optimum (or best known, for those found numerically) and reference, in Rust and Python. -- **Constrained test problems:** CEC 2006's g01-g24 (`problems::cec2006`), and the engineering design problems (`problems::engineering`): the welded beam in two forms, the pressure vessel, the tension/compression spring, the speed reducer, the gear train (integer), the three-bar truss, the cantilever beam and the car side impact, each with its optimum or best known solution and references, in Rust and Python. Those with inequalities only give their constraints' values one by one to the algorithms that use them. +- **Test problems** (`problems`): Sphere, the axis-parallel ellipsoid, Schwefel 1.2 and 2.26, Rastrigin, Rosenbrock, Ackley, Griewank, Levy, Zakharov, Styblinski-Tang, Michalewicz, Himmelblau, Branin, Goldstein-Price, the six-hump camel, Hartmann's functions in 3 and 6 dimensions, Shekel's with 5, 7 and 10 wells, Easom, the eggholder, Schaffer's F6, Schwefel 2.21 and 2.22, Dixon-Price, Trid, Powell's singular function, Beale, Booth, Matyas, Bohachevsky's three functions, the three-hump camel, Langermann, Shekel's foxholes, Kowalik, the sum of different powers, the step function, the quartic (with or without noise), Yao, Liu and Lin's two penalized functions, the high-conditioned elliptic, the bent cigar, the discus, BBOB's different powers, Büche-Rastrigin, the non-continuous Rastrigin, Weierstrass, Katsuura, HappyCat, HGBat, Schaffer's F7 and the rotated hyper-ellipsoid, each with its bounds, known optimum (or best known, for those found numerically) and reference, in Rust and Python; and shift and rotation wrappers, generated from a seed, for CEC- and BBOB-style instances of any of them. +- **Constrained test problems:** CEC 2006's g01-g24 (`problems::cec2006`), and the engineering design problems (`problems::engineering`): the welded beam in two forms, the pressure vessel, the tension/compression spring, the speed reducer, the gear train (integer), the three-bar truss, the cantilever beam and the car side impact, each with its optimum or best known solution and references, in Rust and Python. ## Multi-objective diff --git a/docs/problems-plan.md b/docs/problems-plan.md index b3d334d3..df2b412b 100644 --- a/docs/problems-plan.md +++ b/docs/problems-plan.md @@ -63,17 +63,17 @@ docs of each function say where its bounds come from when the original has none. | Schwefel 1.2 (double sum), Σᵢ(Σⱼ≤ᵢ xⱼ)² | Schwefel, H.-P. (1981). *Numerical Optimization of Computer Models.* Wiley. Problem 1.2 | any | Y99 [−100, 100] | 0 at 0 | VO (the German edition of 1977, p. 319, read for #241: any n, unbounded); bounds VS(Y99, CEC05 F2) | | Schwefel 2.21, maxᵢ \|xᵢ\| | Schwefel (1981), problem 2.21 | any | Y99 [−100, 100] | 0 at 0 | VS(Y99 table I, read in batch 10a) | | Schwefel 2.22, Σ\|xᵢ\| + Π\|xᵢ\| | Schwefel (1981), problem 2.22 | any | Y99 [−10, 10] (Jamil-Yang [−100, 100]) | 0 at 0 | VS(Y99 table I, read in batch 10a) | -| Axis-parallel ellipsoid Σ i xᵢ² and rotated hyper-ellipsoid Σᵢ Σⱼ≤ᵢ xⱼ² | U (origin not found) | any | axis-parallel [−5.12, 5.12], rotated [−65.536, 65.536] (Molga and Smutnicki 2005, sections 2.2 and 2.3) | 0 at 0 | U; not the same as Schwefel 1.2 | -| Step (Y99 f6), Σ(⌊xᵢ + 0.5⌋)² | Y99, after De Jong's F3 (Σ⌊xᵢ⌋ on [−5.12, 5.12], n = 5) | any (30) | [−100, 100] | 0 on xᵢ ∈ [−0.5, 0.5) | VS(Y99) for n, bounds, f*; formula U | -| Quartic with noise (De Jong's F4) | De Jong (1975); Y99 f7 | any (30) | [−1.28, 1.28] | 0 at 0 without noise | VS(Y99); the noise (Gaussian in De Jong, uniform [0, 1) in Y99) U | +| Axis-parallel ellipsoid Σ i xᵢ² and rotated hyper-ellipsoid Σᵢ Σⱼ≤ᵢ xⱼ² | U (origin not found) | any | axis-parallel [−5.12, 5.12], rotated [−65.536, 65.536] (Molga and Smutnicki 2005, sections 2.2 and 2.3) | 0 at 0 | rotated: VS(Molga-Smutnicki 2.3, read in batch 10b), whose formula is Σⱼ (n − j + 1) xⱼ², axis-parallel despite the name; not the same as Schwefel 1.2; origin U | +| Step (Y99 f6), Σ(⌊xᵢ + 0.5⌋)² | Y99, after De Jong's F3 (Σ⌊xᵢ⌋ on [−5.12, 5.12], n = 5) | any (30) | [−100, 100] | 0 on xᵢ ∈ [−0.5, 0.5) | VS(Y99 table I and appendix F, read in batch 10b); De Jong's F3 U | +| Quartic with noise (De Jong's F4) | De Jong (1975); Y99 f7 | any (30) | [−1.28, 1.28] | 0 at 0 without noise | VS(Y99 table I and appendix G, read in batch 10b: Σ i xᵢ⁴ + random[0, 1)); De Jong's Gaussian noise U; genoxide draws the noise from the genome's bits (batch 10b) | | Rosenbrock | Rosenbrock, H. H. (1960). An automatic method for finding the greatest or least value of a function. *The Computer Journal* 3(3): 175-184. doi:10.1093/comjnl/3.3.175 (2-D); chained n-D form in De Jong (1975) F2 and Y99 f5 | any | none in the original (start (−1.2, 1)); Y99 [−30, 30] | 0 at (1, …, 1) | citation VO; n-D form VS(Y99, CEC05 F6); f(−1.2, 1) = 24.2 VC | | Zakharov | U (no primary source found) | any | usually [−5, 10] | 0 at 0 | U | | Dixon-Price | Dixon, L. C. W. and Price, R. C. (1989). Truncated Newton method for sparse unconstrained optimization using automatic differentiation. *JOTA* 60(2): 261-275. doi:10.1007/BF00940007 | any | [−10, 10] | 0 at xᵢ = 2^(−(2ⁱ − 2)/2ⁱ), and with xₙ negated (two minima); a stationary point 2/3 at (1/3, 0, …, 0) for n ≥ 3, not a local minimum but a trap (batch 10a) | VS(Jamil-Yang, whose x* drops the minus sign; Laguna-Martí, whose sum starts at i = 1); x* VC; the paper unread | | Trid | U (origin not found) | any | [−n², n²] | −n(n+4)(n−1)/6 at xᵢ = i(n+1−i); n = 6: −50, n = 10: −210 | f* VC (unique: tridiagonal Hessian positive definite); origin U (Hedar's collection, per Jamil-Yang, who misprint −200 for n = 10); formula VS(Laguna-Martí, who misprint xᵢxⱼ) | | Powell singular | Powell, M. J. D. (1962). An iterative method for finding stationary values of a function of several variables. *The Computer Journal* 5(2): 147-151. doi:10.1093/comjnl/5.2.147 | 4 (4k extended) | none (start (3, −1, 0, 1)) | 0 at 0 | formula VS(Steihaug and Suleiman 2013, JOGO 56(3): 845-853, read in batch 10a, restating Powell); blocks of four and [−4, 5] VS(Laguna-Martí, n = 24); f(3, −1, 0, 1) = 215 VC; Jamil-Yang print (x₂ − x₃)⁴ and give the start as x*; the paper unread | -| Sum of different powers Σ\|xᵢ\|^(i+1) | U | any | [−1, 1] | 0 at 0 | U | -| High-conditioned elliptic Σ (10⁶)^((i−1)/(n−1)) zᵢ² | CEC05 F3; BBOB f2, f10 | any | CEC05 [−100, 100]; BBOB [−5, 5] | 0 (+ bias) | VO(CEC05) | -| Bent cigar, Discus, BBOB different powers | BBOB f12, f11, f14 | any | [−5, 5] | f_opt | U | +| Sum of different powers Σ\|xᵢ\|^(i+1) | U | any | [−1, 1] | 0 at 0 | VS(Molga-Smutnicki 2.8, read in batch 10b); origin U | +| High-conditioned elliptic Σ (10⁶)^((i−1)/(n−1)) zᵢ² | CEC05 F3; BBOB f2, f10 | any | CEC05 [−100, 100]; BBOB [−5, 5] | 0 (+ bias) | VO(CEC05, read in batch 10b); CEC 2014/2017 basic function the same; BBOB's adds T_osz | +| Bent cigar, Discus, BBOB different powers | BBOB f12, f11, f14 | any | [−5, 5]; CEC 2014/2017 [−100, 100] | f_opt | VO(BBOB, read in batch 10b); the plain bent cigar and discus are the CEC 2014 and 2017 reports' basic functions (read), on [−100, 100]; genoxide uses those, and BBOB's [−5, 5] for different powers | #### Scalable, multimodal @@ -84,17 +84,17 @@ docs of each function say where its bounds come from when the original has none. | Ackley, −20 exp(−0.2 √(Σxᵢ²/n)) − exp(Σ cos(2πxᵢ)/n) + 20 + e | Ackley, D. H. (1987). *A Connectionist Machine for Genetic Hillclimbing.* Kluwer. doi:10.1007/978-1-4613-1997-9 (2-D); n-D form by Bäck, T. (1996). *Evolutionary Algorithms in Theory and Practice.* Oxford University Press | Y99 [−32, 32] (checked in its table I; [−32.768, 32.768] elsewhere); CEC05 [−32, 32] | 0 at 0 | constants VS(CEC05 F8); bounds VS(Y99); the original's dimension U | | Griewank, 1 + Σxᵢ²/4000 − Π cos(xᵢ/√i) | Griewank, A. O. (1981). Generalized descent for global optimization. *JOTA* 34(1): 11-39. doi:10.1007/BF00933356 | Y99 [−600, 600] | 0 at 0 | citation VO; form VS(Y99, CEC05 F7); the original's d = 200 for n = 2 on [−100, 100] U | | Levy (the w = 1 + (x − 1)/4 form) | usually credited to Levy, A. V. and Montalvo, A. (1985). The tunneling algorithm for the global minimization of functions. *SIAM J. Sci. Stat. Comput.* 6(1): 15-29. doi:10.1137/0906002 | [−10, 10] | 0 at (1, …, 1) | U: at least four "Levy" functions circulate; the w-form's presence in the 1985 paper is unverified | -| Penalized 1 and 2 (Levy-type, with u(x, a, k, m)) | Y99 f12, f13 | [−50, 50] | 0 at (−1, …) and (1, …) | bounds, f* VS(Y99); formula U | +| Penalized 1 and 2 (Levy-type, with u(x, a, k, m)) | Y99 f12, f13 | [−50, 50] | 0 at (−1, …) and (1, …) | VS(Y99 table I and appendix L, read in batch 10b; the appendix misprints f12's minimizer as (1, …, 1), table I drops f13's (xₙ − 1)²'s square); Levy-Montalvo origin U | | Styblinski-Tang, ½ Σ(xᵢ⁴ − 16xᵢ² + 5xᵢ) | Styblinski, M. A. and Tang, T.-S. (1990). Experiments in nonconvex optimization: stochastic approximation with function smoothing and simulated annealing. *Neural Networks* 3(4): 467-483. doi:10.1016/0893-6080(90)90029-K | [−5, 5] | −39.16616570 n at xᵢ = −2.903534 | citation VO; values VC; domain U | | Michalewicz, −Σ sin(xᵢ) sin²ᵐ(i xᵢ²/π), m = 10 | Michalewicz, Z. (1992). *Genetic Algorithms + Data Structures = Evolution Programs.* Springer | [0, π] | n = 2: −1.8013 at (2.20, 1.57); n = 5: −4.687658; n = 10: −9.66015 | U (values and m) | -| Weierstrass (a = 0.5, b = 3, k_max = 20) | CEC05 F11 (Weierstrass 1872 as a function) | [−0.5, 0.5] | 0 (+ bias) | VO(CEC05); BBOB f16 differs | -| Katsuura | BBOB f23; Katsuura, H. (1991). Continuous nowhere-differentiable functions. *Amer. Math. Monthly* 98(5): 411-416 | [−5, 5] | f_opt | BBOB form VO; 1991 details U | -| HappyCat, HGBat | Beyer, H.-G. and Finck, S. (2012). HappyCat: a simple function class where well-known direct search algorithms do fail. PPSN XII, LNCS 7491: 367-376. doi:10.1007/978-3-642-32937-1_37 | — | 0 at (−1, …, −1) | U (α = 1/8 vs CEC 2014's 1/4) | +| Weierstrass (a = 0.5, b = 3, k_max = 20) | CEC05 F11 (Weierstrass 1872 as a function) | [−0.5, 0.5] | 0 (+ bias) | VO(CEC05, read in batch 10b; Liang et al. 2006 and CEC 2014 the same); BBOB f16 differs | +| Katsuura | BBOB f23; Katsuura, H. (1991). Continuous nowhere-differentiable functions. *Amer. Math. Monthly* 98(5): 411-416 | [−5, 5] | 0 wherever every xᵢ is a multiple of 1/2 (21ⁿ points in the box, the bounds among them) | BBOB form VO (batch 10b), CEC 2014 basic function the same (read); the 1991 paper unread | +| HappyCat, HGBat | Beyer, H.-G. and Finck, S. (2012). HappyCat: a simple function class where well-known direct search algorithms do fail. PPSN XII, LNCS 7491: 367-376. doi:10.1007/978-3-642-32937-1_37 | [−5, 5] (CEC 2014's [−100, 100] scaled by 5/100) | 0 at (−1, …, −1), unique (proven, batch 10b) | VS(CEC 2014 functions 11 and 12, read in batch 10b, exponents 1/4 and 1/2 on the absolute values); the paper unread: whether its α = 1/8 is CEC's 1/4 U; HGBat's origin U | | Eggholder | Whitley, D., Rana, S., Dzubera, J. and Mathias, K. (1996). Evaluating evolutionary algorithms. *Artificial Intelligence* 85(1-2): 245-276. doi:10.1016/0004-3702(95)00124-7 | [−512, 512] (Mishra 2006); the original's is [−512, 511] | 2-D: −959.6406627 at (512, 404.2318051) on [−512, 512]; −956.9182316 at (482.35331, 432.87900) on [−512, 511] | **VO** (batch 6: the authors' copy, section 4.2, F101, [−512, 511] with 10 bits, no 2-D minimum); name, [−512, 512] and (512, 404.2319) from Mishra, S. K. (2006), MPRA paper 2718, read, whose sign is lost and whose x₂ is 404.2318 to 4 decimals | -| Schaffer F6 and F7 | Schaffer, J. D., Caruana, R. A., Eshelman, L. J. and Das, R. (1989). A study of control parameters affecting online performance of genetic algorithms for function optimization. Proc. 3rd ICGA: 51-60 | [−100, 100] | 0 at 0 | F6 VS(Whitley et al. 1996, table 1, F9, crediting Schaffer et al.; CEC05 section 2.3.2), batch 6; the original unread; F7 U | -| Büche-Rastrigin; BBOB Rastrigin (f3) | BBOB f4, f3 | [−5, 5] | f_opt | VO (BBOB) | -| Shifted, shifted-rotated Rastrigin | CEC05 F9, F10 (shift vectors and matrices in the report's data files) | [−5, 5] | bias −330 | VO(CEC05) | -| Non-continuous Rastrigin | Liang, J. J., Qin, A. K., Suganthan, P. N. and Baskar, S. (2006). Comprehensive learning particle swarm optimizer. *IEEE TEVC* 10(3): 281-295. doi:10.1109/TEVC.2005.857610 | [−5.12, 5.12] | 0 | U | +| Schaffer F6 and F7 | Schaffer, J. D., Caruana, R. A., Eshelman, L. J. and Das, R. (1989). A study of control parameters affecting online performance of genetic algorithms for function optimization. Proc. 3rd ICGA: 51-60 | [−100, 100] | 0 at 0 | F6 VS(Whitley et al. 1996, table 1, F9, crediting Schaffer et al.; CEC05 section 2.3.2), batch 6; the original unread; F7's n-dimensional form VO(BBOB f17, batch 10b; CEC 2017 function 19 prints sin for sin²), the 2-D original U | +| Büche-Rastrigin; BBOB Rastrigin (f3) | BBOB f4, f3 | [−5, 5] | f_opt | VO (BBOB, read in batch 10b: f4 with xᵒᵖᵗ = 0, fᵒᵖᵗ = 0, T_osz and the penalty kept) | +| Shifted, shifted-rotated Rastrigin | CEC05 F9, F10 (shift vectors and matrices in the report's data files) | [−5, 5] | bias −330 | VO(CEC05, read in batch 10b); `Shifted` and `Rotated` around `Rastrigin`, with genoxide's own shift and matrix (batch 10b) | +| Non-continuous Rastrigin | Liang, J. J., Qin, A. K., Suganthan, P. N. and Baskar, S. (2006). Comprehensive learning particle swarm optimizer. *IEEE TEVC* 10(3): 281-295. doi:10.1109/TEVC.2005.857610 | [−5.12, 5.12] | 0 | VO (f7 and table II, read in batch 10b) | #### Fixed dimension @@ -180,6 +180,35 @@ stall in 10 and 30 dimensions; Beale has a minimum 0.76207 on its bound. The min and Kowalik are recomputed to 40 digits by Newton's method (mpmath) and stored as best known values; the others are proven from their formulas. +**Checked in batch 10b** (the sum of different powers, step, quartic, penalized 1 and 2, the +high-conditioned elliptic, bent cigar, discus, BBOB's different powers, Büche-Rastrigin, +non-continuous Rastrigin, Weierstrass, Katsuura, HappyCat, HGBat, Schaffer F7, the rotated +hyper-ellipsoid, and the `Shifted` and `Rotated` wrappers). Read: the BBOB definitions (Hansen, +Finck, Ros and Auger, RR-6829, version 2 of 2019, with its errata), the CEC 2005 report (May 2005, +the organizers' repository), the CEC 2014 report (Liang, Qu and Suganthan, December 2013) and the +CEC 2017 report (Awad et al., as modified on 15 October 2016), Yao, Liu and Lin (1999, table I and +the appendix), Liang, Qin, Suganthan and Baskar (2006, section IV.A and table II) and Molga and +Smutnicki (2005, sections 2.3 and 2.8). Not reachable: Beyer and Finck (2012), Katsuura (1991), +Schaffer et al. (1989), Levy and Montalvo (1985) and De Jong's thesis for F4's noise. Choices: the +functions are the plain basic functions, z = x, as the CEC 2014 and 2017 reports define them (BBOB's +own compose them with T_osz, T_asy and conditioning matrices, which genoxide doesn't apply), but for +Büche-Rastrigin, which exists only in BBOB's form and keeps T_osz and its penalty; the bounds follow +the source of each plain form (CEC [−100, 100] for the elliptic function, the bent cigar and the +discus; BBOB [−5, 5] for different powers, Büche-Rastrigin and Katsuura; CEC 2014's scaled [−5, 5] +for HappyCat and HGBat; Schaffer F6's [−100, 100] for F7). `Shifted` moves the wrapped optimum's +first solution to a point uniform in the middle 80% of each range (CEC's [−80, 80] in [−100, 100], +BBOB's [−4, 4] in [−5, 5]); `Rotated` draws a matrix of standard normal numbers from the seed, +orthonormalizes its rows by Gram-Schmidt (BBOB's method, applied twice) and turns the function +about that solution (as CEC 2005's `(x − o) M` and BBOB's `R (x − xᵒᵖᵗ)` do), so both keep the +optimum's value; they are generic over any `Problem` on `Real` genomes, take their name and +reference from the wrapped problem, and aren't in the registry. Findings: Molga and Smutnicki's +"rotated" hyper-ellipsoid is axis-parallel, Σⱼ (n − j + 1) xⱼ²; Y99's appendix gives f12's minimizer +as (1, …, 1) (it's (−1, …, −1)) and its table I drops the square of f13's last (xₙ − 1); the CEC 2017 +report prints Schaffer F7 with sin for BBOB's sin²; Katsuura's minima include the bounds ±5, where a +PSO that stops particles at the bounds lands on them; at G06's minimum, shifted, rounding in x − o +leaves an active constraint violated by 6e-14. The minima are proven from the formulas (every term +at least 0), but the noisy quartic's, which isn't known. + **Hand-computed test values (VC):** Rosenbrock (−1.2, 1) = 24.2; Powell (3, −1, 0, 1) = 215; Goldstein-Price (0, −1) = 3 and its three local minima's values from the paper; Beale (3, 0.5) = 0; Branin at its three minima = 5/(4π); Styblinski-Tang −39.1661657 per dimension at −2.903534; @@ -1164,7 +1193,7 @@ page); a comparison belongs on the problems' own pages. | 8 | done | Scaled and inverted DTLZ, and MW | Convex DTLZ2, scaled DTLZ1, scaled DTLZ2, inverted DTLZ1 (4), MW1-MW14 (14) | an example per problem: `convex_dtlz2`, `scaled_dtlz1`, `scaled_dtlz2`, `inverted_dtlz1` (NSGA-III against MOEA/D or other directions) and `mw1` to `mw14` (NSGA-II, NSGA-III and SMS-EMOA, with the paper's settings and settings that reach the fronts); the `mw` comparison of all fourteen is still to come | | 9 | done ([#357](https://github.com/tachsin/genoxide/pull/357); the marine design after it, once its original was read) | Engineering design, several objectives (`multi::problems::engineering`, section 1.5's "Checked in batch 9") | Two-bar truss, welded beam (2 objectives), disc brake, car side impact (3 objectives), speed reducer (2 objectives), four-bar truss, water resource planning, rocket injector, vehicle crashworthiness, conceptual marine design (10) | an example per problem: `two_bar_truss`, `welded_beam_2obj`, `disc_brake`, `speed_reducer_2obj`, `four_bar_truss` (NSGA-II), `car_side_impact_3obj` (NSGA-III, Jain and Deb's settings), `rocket_injector`, `vehicle_crashworthiness`, `marine_design` (SMS-EMOA), `water_resource_planning` (SPEA2) | | 10a | done | Remaining low-dimensional and classic scalable functions (section 1.1's "Checked in batch 10a") | Beale, Booth, Matyas, Bohachevsky 1-3, Three-hump camel, Dixon-Price, Trid, Powell, Langermann, Shekel's foxholes, Kowalik, Schwefel 2.21, Schwefel 2.22 (15) | an example per function: `beale`, `booth`, `matyas`, `bohachevsky1` to `bohachevsky3`, `three_hump_camel`, `langermann`, `shekel_foxholes` and `kowalik` (30 seeds each of CMA-ES with and without IPOP, DE, PSO or a GA), `dixon_price` (CMA-ES with IPOP, DE and PSO in 5 and 10 dimensions), and `schwefel_2_21`, `schwefel_2_22`, `trid` and `powell` (CMA-ES, sep-CMA-ES, DE, PSO and a GA to errors of 1 … 1e-8) | -| 10b | | CEC and BBOB-style functions, and the shift / rotation wrappers | `Shifted

`, `Rotated

`; Sum of different powers, Step, Quartic (deterministic: without noise, or with noise seeded from the genome, since fitness functions must be deterministic), Penalized 1 and 2, High-conditioned elliptic, Bent cigar, Discus, Büche-Rastrigin, Non-continuous Rastrigin, Weierstrass, Katsuura, HappyCat, HGBat, Schaffer F7, Rotated hyper-ellipsoid, BBOB different powers (17; the shifted and rotated Rastrigin of CEC 2005 and BBOB are the wrappers around `Rastrigin`) | an example per function (e.g. CMA-ES with full and diagonal covariance on a rotated ellipsoid's page) | +| 10b | done | CEC and BBOB-style functions, and the shift / rotation wrappers (section 1.1's "Checked in batch 10b") | `Shifted

`, `Rotated

`; Sum of different powers, Step, Quartic (deterministic: without noise, or with noise seeded from the genome, since fitness functions must be deterministic), Penalized 1 and 2, High-conditioned elliptic, Bent cigar, Discus, Büche-Rastrigin, Non-continuous Rastrigin, Weierstrass, Katsuura, HappyCat, HGBat, Schaffer F7, Rotated hyper-ellipsoid, BBOB different powers (17; the shifted and rotated Rastrigin of CEC 2005 and BBOB are the wrappers around `Rastrigin`) | an example per function: `sum_of_different_powers`, `step`, `quartic` (with and without noise), `rotated_hyper_ellipsoid`, `high_conditioned_elliptic`, `bent_cigar`, `discus` and `different_powers` (CMA-ES, sep-CMA-ES, DE, PSO and a GA to errors of 1 … 1e-8, as they are and shifted and rotated, or rotated), and `schaffer_f7`, `penalized1`, `penalized2`, `buche_rastrigin`, `non_continuous_rastrigin`, `weierstrass`, `katsuura`, `happy_cat` and `hg_bat` (10 seeds each of CMA-ES with and without IPOP, DE, PSO and a GA) | | 11 | | Advanced constrained multi-objective suites | DAS-CMOP1-9 (with the 16 difficulty triplets as a parameter), DC-DTLZ (DC1-DC3 on DTLZ1/DTLZ3), DTLZ8, DTLZ9 (≈15) | an example per problem | | 12 | | Binary and combinatorial problems | OneMax, LeadingOnes, deceptive trap, royal road, NK landscapes (seeded), 0/1 knapsack (generated instance classes) (6) | an example per problem; `one_max` and `knapsack` switch to the problems | | 13 (optional) | | Competition suites whose definitions are long | LIR-CMOP1-14, CEC 2009 UF1-UF10 and CF1-CF10, MaF1-MaF15, Deb's 1999 two-objective problems, Van Veldhuizen's constrained problems; the deferred engineering problems (section 1.5) once their originals are read | none; used by the benchmark suite | From 77f76cca43ec87ad9b1491ceeaf99230ed8f813d Mon Sep 17 00:00:00 2001 From: Someguy Date: Thu, 1 Oct 2026 17:18:54 +0300 Subject: [PATCH 07/16] style: batch 10b's examples and tests within 100 columns, formatted MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also notes in Shifted's docs that rounding in x − o can put a shifted solution a few ulps outside a constraint that's active there. --- examples/bent_cigar/README.md | 34 +++++------ examples/bent_cigar/main.py | 15 +++-- examples/buche_rastrigin/README.md | 37 ++++++------ examples/buche_rastrigin/main.py | 16 +++-- examples/buche_rastrigin/trace.py | 3 +- examples/different_powers/README.md | 32 +++++----- examples/different_powers/main.py | 11 ++-- examples/discus/README.md | 22 +++---- examples/discus/main.py | 11 ++-- examples/happy_cat/README.md | 44 +++++++------- examples/happy_cat/main.py | 11 ++-- examples/happy_cat/trace.py | 3 +- examples/hg_bat/README.md | 37 ++++++------ examples/hg_bat/main.py | 14 ++--- examples/hg_bat/trace.py | 3 +- examples/high_conditioned_elliptic/README.md | 49 ++++++++-------- examples/high_conditioned_elliptic/main.py | 11 ++-- examples/high_conditioned_elliptic/main.rs | 5 +- examples/katsuura/README.md | 61 ++++++++++---------- examples/katsuura/main.py | 11 ++-- examples/katsuura/trace.py | 3 +- examples/non_continuous_rastrigin/README.md | 22 +++---- examples/non_continuous_rastrigin/main.py | 16 +++-- examples/non_continuous_rastrigin/main.rs | 7 ++- examples/non_continuous_rastrigin/trace.py | 3 +- examples/penalized1/README.md | 29 +++++----- examples/penalized1/main.py | 16 +++-- examples/penalized1/trace.py | 3 +- examples/penalized2/README.md | 29 +++++----- examples/penalized2/main.py | 16 +++-- examples/penalized2/trace.py | 3 +- examples/quartic/README.md | 21 +++---- examples/quartic/main.py | 10 ++-- examples/rotated_hyper_ellipsoid/README.md | 35 +++++------ examples/rotated_hyper_ellipsoid/main.py | 10 ++-- examples/rotated_hyper_ellipsoid/main.rs | 5 +- examples/schaffer_f7/README.md | 34 +++++------ examples/schaffer_f7/main.py | 19 +++--- examples/schaffer_f7/main.rs | 2 +- examples/schaffer_f7/trace.py | 3 +- examples/step/README.md | 19 +++--- examples/step/main.py | 7 +-- examples/sum_of_different_powers/README.md | 46 +++++++-------- examples/sum_of_different_powers/main.py | 17 +++--- examples/sum_of_different_powers/main.rs | 7 ++- examples/weierstrass/README.md | 24 ++++---- examples/weierstrass/main.py | 19 +++--- examples/weierstrass/main.rs | 2 +- examples/weierstrass/trace.py | 3 +- python/genoxide/problems/__init__.py | 4 +- python/tests/test_problems.py | 26 ++++++--- src/problems/transform.rs | 4 +- 52 files changed, 485 insertions(+), 409 deletions(-) diff --git a/examples/bent_cigar/README.md b/examples/bent_cigar/README.md index ba0bb702..f46cc8dd 100644 --- a/examples/bent_cigar/README.md +++ b/examples/bent_cigar/README.md @@ -22,21 +22,21 @@ f(x) = x₁² + 10⁶ Σᵢ₌₂ⁿ xᵢ², each xᵢ in [−100, 100] Its minimum is 0, at the origin. Here n = 30. It's BBOB's f12 (Hansen et al. 2009), which bends it with an asymmetric transformation and rotates it twice; this plain form and the bounds are the CEC -2014 (Liang, Qu and Suganthan 2013, function 2) and CEC 2017 (Awad et al. 2016, function 1) -reports' basic function, which those suites shift and rotate. +2014 (Liang, Qu and Suganthan 2013, function 2) and CEC 2017 (Awad et al. 2016, function 1) reports' +basic function, which those suites shift and rotate. ## What makes it hard -The function is a ridge: low only near the line along the first axis, a thousand times narrower -than long. A search has to find the ridge, then follow it to the minimum, with steps a thousand -times longer along it than across it, in a single direction. As it is, that direction is a gene's -axis. Shifted and rotated, it's a random one, and the search has to learn it. +The function is a ridge: low only near the line along the first axis, a thousand times narrower than +long. A search has to find the ridge, then follow it to the minimum, with steps a thousand times +longer along it than across it, in a single direction. As it is, that direction is a gene's axis. +Shifted and rotated, it's a random one, and the search has to learn it. ## Representation A `Real` genome of 30 genes: the point x itself. The fitness is f(x), to minimize. The function is -genoxide's `problems::BentCigar`, which brings its bounds and its minimum, and the shifted and rotated -instance `problems::Rotated::new(problems::Shifted::new(function, 1), 1)`, which keeps them. +genoxide's `problems::BentCigar`, which brings its bounds and its minimum, and the shifted and +rotated instance `problems::Rotated::new(problems::Shifted::new(function, 1), 1)`, which keeps them. ## Algorithm @@ -64,21 +64,21 @@ suites use the function, with their own data; genoxide generates its instances i ## Output -The first line gives the dimension and the budget. Then two tables, the function as it is and shifted and rotated: a row per algorithm, the -evaluations it had used when its best error first reached each value of the heading, and the best -error it found, to two significant digits. A dash is an error not reached. The function is -evaluated with genoxide's portable math, so the runs are the same on every platform, and in Python, -`run` evaluates it in Rust, so both versions print the same. +The first line gives the dimension and the budget. Then two tables, the function as it is and +shifted and rotated: a row per algorithm, the evaluations it had used when its best error first +reached each value of the heading, and the best error it found, to two significant digits. A dash is +an error not reached. The function is evaluated with genoxide's portable math, so the runs are the +same on every platform, and in Python, `run` evaluates it in Rust, so both versions print the same. -[The project page](https://tachsin.gr/projects/genoxide/examples/bent-cigar) plays back another -run: CMA-ES on the function in 2 dimensions, x₁² + 10⁶ x₂², not rotated (in 2 dimensions, it's the +[The project page](https://tachsin.gr/projects/genoxide/examples/bent-cigar) plays back another run: +CMA-ES on the function in 2 dimensions, x₁² + 10⁶ x₂², not rotated (in 2 dimensions, it's the high-conditioned elliptic function), so that the population can be drawn on its contour. It meets the target after 756 evaluations. ## Good results -The minimum is 0. As it is, sep-CMA-ES reaches 1e-8 after 8,316 evaluations and CMA-ES after -13,482; SHADE takes 42,800 and PSO 47,600. The genetic algorithm ends at 210. +The minimum is 0. As it is, sep-CMA-ES reaches 1e-8 after 8,316 evaluations and CMA-ES after 13,482; +SHADE takes 42,800 and PSO 47,600. The genetic algorithm ends at 210. Shifted and rotated, CMA-ES takes 13,902 evaluations, about as many: it learns the ridge's direction. SHADE gets there after 171,700, four times as many as before, and the others fail: diff --git a/examples/bent_cigar/main.py b/examples/bent_cigar/main.py index 95d2f738..0886e904 100644 --- a/examples/bent_cigar/main.py +++ b/examples/bent_cigar/main.py @@ -1,11 +1,12 @@ -"""Bent cigar: minimize a narrow ridge, a thousand times longer than wide, in 30 dimensions, -as it is and shifted and rotated, as in the CEC 2014 and 2017 suites. +"""Bent cigar: minimize a narrow ridge, a thousand times longer than wide, in 30 dimensions, as it +is and shifted and rotated, as in the CEC 2014 and 2017 suites. Compares how fast CMA-ES, with a full and with a diagonal covariance matrix (sep-CMA-ES), differential evolution, particle swarm optimization and a real-coded genetic algorithm close in on -the minimum, 0 at the origin: the evaluations each takes until its error is at most 1, 1e-2, 1e-4, 1e-6 and 1e-8. -The function is genoxide's `problems::BentCigar`. Then the same on the function shifted and rotated, with genoxide's `problems::Shifted` -and `problems::Rotated`, as the CEC and BBOB suites transform it. +the minimum, 0 at the origin: the evaluations each takes until its error is at most 1, 1e-2, 1e-4, +1e-6 and 1e-8. The function is genoxide's `problems::BentCigar`. Then the same on the function +shifted and rotated, with genoxide's `problems::Shifted` and `problems::Rotated`, as the CEC and +BBOB suites transform it. With ``GENOXIDE_TRACE=``, it also writes a trace of a run for the plot on the example's page, with trace.py. @@ -89,7 +90,9 @@ def compare(name, problem): print(f"Bent cigar in {DIMENSIONS} dimensions, {BUDGET} evaluations at most") compare("Bent cigar", gx.problems.BentCigar(DIMENSIONS)) # the CEC 2014 and 2017 suites' form, with genoxide's own shift and rotation -rotated = gx.problems.Rotated(gx.problems.Shifted(gx.problems.BentCigar(DIMENSIONS), seed=1), seed=1) +rotated = gx.problems.Rotated( + gx.problems.Shifted(gx.problems.BentCigar(DIMENSIONS), seed=1), seed=1 +) compare("Shifted and rotated (seed 1)", rotated) # with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate run in diff --git a/examples/buche_rastrigin/README.md b/examples/buche_rastrigin/README.md index f4452c46..9a81d58b 100644 --- a/examples/buche_rastrigin/README.md +++ b/examples/buche_rastrigin/README.md @@ -22,11 +22,11 @@ f(x) = 10 (n − Σ cos 2πzᵢ) + Σ zᵢ² + 100 Σ max(0, |xᵢ| − 5)², each xᵢ in [−5, 5] ``` -T_osz is BBOB's oscillation, `sign(x) exp(x̂ + 0.049 (sin c₁x̂ + sin c₂x̂))` with x̂ = ln |x|, -c₁ = 10 and c₂ = 7.9 for positive x, 5.5 and 3.1 otherwise: the identity, with small smooth -wiggles. The scale sᵢ grows from 1 to √10 along the genes, and is ten times larger where xᵢ > 0 -and i is odd. Its minimum is 0, at the origin. Here n = 10. It's BBOB's f4 (Hansen et al. 2009), -with its optimum at the origin and no offset, and BBOB's search domain. +T_osz is BBOB's oscillation, `sign(x) exp(x̂ + 0.049 (sin c₁x̂ + sin c₂x̂))` with x̂ = ln |x|, c₁ = +10 and c₂ = 7.9 for positive x, 5.5 and 3.1 otherwise: the identity, with small smooth wiggles. The +scale sᵢ grows from 1 to √10 along the genes, and is ten times larger where xᵢ > 0 and i is odd. Its +minimum is 0, at the origin. Here n = 10. It's BBOB's f4 (Hansen et al. 2009), with its optimum at +the origin and no offset, and BBOB's search domain. ## What makes it hard @@ -38,14 +38,13 @@ look the same on both sides. ## Representation -A `Real` genome of 10 genes, each in [−5, 5]: the point x itself. The fitness is f(x), to -minimize. The function is genoxide's `problems::BucheRastrigin`, which brings its bounds and its -minimum. +A `Real` genome of 10 genes, each in [−5, 5]: the point x itself. The fitness is f(x), to minimize. +The function is genoxide's `problems::BucheRastrigin`, which brings its bounds and its minimum. ## Algorithm -Five algorithms, each from seeds 1 to 10, with a budget of 10,000 evaluations per dimension, -100,000 per run, and a target of 1e-8: +Five algorithms, each from seeds 1 to 10, with a budget of 10,000 evaluations per dimension, 100,000 +per run, and a target of 1e-8: - CMA-ES (Hansen and Ostermeier, 2001, Evolutionary Computation 9(2): 159-195), which samples a population of 10 from a normal distribution and adapts its mean, its step size and its covariance @@ -62,16 +61,16 @@ Five algorithms, each from seeds 1 to 10, with a budget of 10,000 evaluations pe ## Output -The first line gives the dimension, the seeds and the budget. Then a row per algorithm: how many -of its 10 runs reached the minimum, to within 1e-8, the median of their evaluations (a dash if none -did), and the median of every run's best error, to two significant digits. The function is -evaluated with genoxide's portable math, so the runs are the same on every platform, and in Python, -`run` evaluates it in Rust, so both versions print the same. +The first line gives the dimension, the seeds and the budget. Then a row per algorithm: how many of +its 10 runs reached the minimum, to within 1e-8, the median of their evaluations (a dash if none +did), and the median of every run's best error, to two significant digits. The function is evaluated +with genoxide's portable math, so the runs are the same on every platform, and in Python, `run` +evaluates it in Rust, so both versions print the same. -[The project page](https://tachsin.gr/projects/genoxide/examples/buche-rastrigin) plays back another run: -CMA-ES with IPOP restarts on the function in 2 dimensions, so that the population -can be drawn on its contour. Within 20,000 evaluations it restarts 6 times, up to a population of -384, and ends at an error of 0.36: it doesn't reach the minimum in 2 dimensions either. +[The project page](https://tachsin.gr/projects/genoxide/examples/buche-rastrigin) plays back another +run: CMA-ES with IPOP restarts on the function in 2 dimensions, so that the population can be drawn +on its contour. Within 20,000 evaluations it restarts 6 times, up to a population of 384, and ends +at an error of 0.36: it doesn't reach the minimum in 2 dimensions either. ## Good results diff --git a/examples/buche_rastrigin/main.py b/examples/buche_rastrigin/main.py index 7d9aef84..b1e9dd37 100644 --- a/examples/buche_rastrigin/main.py +++ b/examples/buche_rastrigin/main.py @@ -1,10 +1,10 @@ """Büche-Rastrigin: minimize BBOB's Büche-Rastrigin function, an asymmetric Rastrigin, in 10 dimensions. -Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), -differential evolution (SHADE), particle swarm optimization and a real-coded genetic algorithm from -10 seeds each, and counts the runs that reach the minimum, 0 at the origin, to within 1e-8. The -function is genoxide's `problems::BucheRastrigin`, which run evaluates in Rust. +Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), differential +evolution (SHADE), particle swarm optimization and a real-coded genetic algorithm from 10 seeds +each, and counts the runs that reach the minimum, 0 at the origin, to within 1e-8. The function is +genoxide's `problems::BucheRastrigin`, which run evaluates in Rust. With ``GENOXIDE_TRACE=``, it also writes a trace of a run for the plot on the example's page, with trace.py. @@ -62,7 +62,10 @@ def error_text(error): problem = gx.problems.BucheRastrigin(DIMENSIONS) minimum = problem.optimum.value -print(f"Büche-Rastrigin in {DIMENSIONS} dimensions, {SEEDS} seeds, {BUDGET} evaluations at most per run") +print( + f"Büche-Rastrigin in {DIMENSIONS} dimensions, {SEEDS} seeds, " + f"{BUDGET} evaluations at most per run" +) print("algorithm at min evaluations median error") for name in ALGORITHMS: # the evaluations of the runs that reach the minimum, and every run's best error @@ -78,7 +81,8 @@ def error_text(error): reached = f"{len(evaluations)}/{SEEDS}" middle = median(evaluations) evaluations_text = "-" if middle is None else f"{middle:.0f}" - print(f"{name:<16} {reached:>6} {evaluations_text:>11} {error_text(median(errors)):>12}") + error = error_text(median(errors)) + print(f"{name:<16} {reached:>6} {evaluations_text:>11} {error:>12}") print("evaluations: the median of the runs that reach the minimum") # with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate run in diff --git a/examples/buche_rastrigin/trace.py b/examples/buche_rastrigin/trace.py index bff23fd4..9499503b 100644 --- a/examples/buche_rastrigin/trace.py +++ b/examples/buche_rastrigin/trace.py @@ -11,7 +11,8 @@ def record_small(): - """Runs CMA-ES with IPOP restarts in 2 dimensions and writes its trace, if ``GENOXIDE_TRACE`` is set.""" + """Runs CMA-ES with IPOP restarts in 2 dimensions and writes its trace, if + ``GENOXIDE_TRACE`` is set.""" path = os.environ.get("GENOXIDE_TRACE") if not path: return diff --git a/examples/different_powers/README.md b/examples/different_powers/README.md index 1b6d8e6e..6716e967 100644 --- a/examples/different_powers/README.md +++ b/examples/different_powers/README.md @@ -22,21 +22,21 @@ f(x) = √(Σ |xᵢ|^(2 + 4 (i−1)/(n−1))), i from 1 to n, each xᵢ in [ ``` Its minimum is 0, at the origin. Here n = 30. It's BBOB's f14 (Hansen et al. 2009), which rotates -it, with its search domain. It isn't the sum of different powers of Molga and Smutnicki, with -powers 2 to n + 1 and no square root. +it, with its search domain. It isn't the sum of different powers of Molga and Smutnicki, with powers +2 to n + 1 and no square root. ## What makes it hard Near the minimum, the genes' sensitivities drift apart: an error of 1e-8, under the square root, -needs the first gene within 10⁻⁸ of 0, but allows the last one, with its sixth power, to be -10⁻²·⁷ ≈ 0.002 away. The closer the search gets, the more different the scales it needs, so a -search must keep adapting them. Shifted and rotated, every direction mixes the powers. +needs the first gene within 10⁻⁸ of 0, but allows the last one, with its sixth power, to be 10⁻²·⁷ ≈ +0.002 away. The closer the search gets, the more different the scales it needs, so a search must +keep adapting them. Shifted and rotated, every direction mixes the powers. ## Representation A `Real` genome of 30 genes: the point x itself. The fitness is f(x), to minimize. The function is -genoxide's `problems::DifferentPowers`, which brings its bounds and its minimum, and the shifted and rotated -instance `problems::Rotated::new(problems::Shifted::new(function, 1), 1)`, which keeps them. +genoxide's `problems::DifferentPowers`, which brings its bounds and its minimum, and the shifted and +rotated instance `problems::Rotated::new(problems::Shifted::new(function, 1), 1)`, which keeps them. ## Algorithm @@ -64,14 +64,14 @@ suites use the function, with their own data; genoxide generates its instances i ## Output -The first line gives the dimension and the budget. Then two tables, the function as it is and shifted and rotated: a row per algorithm, the -evaluations it had used when its best error first reached each value of the heading, and the best -error it found, to two significant digits. A dash is an error not reached. The function is -evaluated with genoxide's portable math, so the runs are the same on every platform, and in Python, -`run` evaluates it in Rust, so both versions print the same. +The first line gives the dimension and the budget. Then two tables, the function as it is and +shifted and rotated: a row per algorithm, the evaluations it had used when its best error first +reached each value of the heading, and the best error it found, to two significant digits. A dash is +an error not reached. The function is evaluated with genoxide's portable math, so the runs are the +same on every platform, and in Python, `run` evaluates it in Rust, so both versions print the same. -[The project page](https://tachsin.gr/projects/genoxide/examples/different-powers) plays back another -run: CMA-ES on the function in 2 dimensions, √(x₁² + x₂⁶), rotated with seed 1, so that the +[The project page](https://tachsin.gr/projects/genoxide/examples/different-powers) plays back +another run: CMA-ES on the function in 2 dimensions, √(x₁² + x₂⁶), rotated with seed 1, so that the population can be drawn on its contour. It meets the target after 714 evaluations. ## Good results @@ -80,5 +80,5 @@ The minimum is 0. As it is, sep-CMA-ES reaches 1e-8 first, after 7,420 evaluatio (23,080), SHADE (30,000) and CMA-ES (47,208); the genetic algorithm ends at 1.3e-6. Shifted and rotated, only CMA-ES reaches 1e-8, after 48,734 evaluations, about as many as before. -sep-CMA-ES ends at 3.9e-5, SHADE at 1.1e-5, PSO at 1.6e-4 and the genetic algorithm at 3.1e-3: -their scales per gene, or steps along the axes, no longer fit. +sep-CMA-ES ends at 3.9e-5, SHADE at 1.1e-5, PSO at 1.6e-4 and the genetic algorithm at 3.1e-3: their +scales per gene, or steps along the axes, no longer fit. diff --git a/examples/different_powers/main.py b/examples/different_powers/main.py index bbed857e..af4184c8 100644 --- a/examples/different_powers/main.py +++ b/examples/different_powers/main.py @@ -3,9 +3,10 @@ Compares how fast CMA-ES, with a full and with a diagonal covariance matrix (sep-CMA-ES), differential evolution, particle swarm optimization and a real-coded genetic algorithm close in on -the minimum, 0 at the origin: the evaluations each takes until its error is at most 1, 1e-2, 1e-4, 1e-6 and 1e-8. -The function is genoxide's `problems::DifferentPowers`. Then the same on the function shifted and rotated, with genoxide's `problems::Shifted` -and `problems::Rotated`, as the CEC and BBOB suites transform it. +the minimum, 0 at the origin: the evaluations each takes until its error is at most 1, 1e-2, 1e-4, +1e-6 and 1e-8. The function is genoxide's `problems::DifferentPowers`. Then the same on the function +shifted and rotated, with genoxide's `problems::Shifted` and `problems::Rotated`, as the CEC and +BBOB suites transform it. With ``GENOXIDE_TRACE=``, it also writes a trace of a run for the plot on the example's page, with trace.py. @@ -89,7 +90,9 @@ def compare(name, problem): print(f"Different powers in {DIMENSIONS} dimensions, {BUDGET} evaluations at most") compare("Different powers", gx.problems.DifferentPowers(DIMENSIONS)) # BBOB's f14, with genoxide's own shift and rotation -rotated = gx.problems.Rotated(gx.problems.Shifted(gx.problems.DifferentPowers(DIMENSIONS), seed=1), seed=1) +rotated = gx.problems.Rotated( + gx.problems.Shifted(gx.problems.DifferentPowers(DIMENSIONS), seed=1), seed=1 +) compare("Shifted and rotated (seed 1)", rotated) # with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate run in diff --git a/examples/discus/README.md b/examples/discus/README.md index cb84062b..e9bbda46 100644 --- a/examples/discus/README.md +++ b/examples/discus/README.md @@ -28,9 +28,9 @@ which those suites shift and rotate. ## What makes it hard The level sets are discs: one direction is a thousand times more sensitive than all the others. A -step that suits the 29 flat directions overshoots in the steep one, and a step that suits the -steep one crawls in the others: a search has to give that one direction its own scale. As it is, -the direction is a gene's axis; shifted and rotated, a random one. +step that suits the 29 flat directions overshoots in the steep one, and a step that suits the steep +one crawls in the others: a search has to give that one direction its own scale. As it is, the +direction is a gene's axis; shifted and rotated, a random one. ## Representation @@ -64,15 +64,15 @@ suites use the function, with their own data; genoxide generates its instances i ## Output -The first line gives the dimension and the budget. Then two tables, the function as it is and shifted and rotated: a row per algorithm, the -evaluations it had used when its best error first reached each value of the heading, and the best -error it found, to two significant digits. A dash is an error not reached. The function is -evaluated with genoxide's portable math, so the runs are the same on every platform, and in Python, -`run` evaluates it in Rust, so both versions print the same. +The first line gives the dimension and the budget. Then two tables, the function as it is and +shifted and rotated: a row per algorithm, the evaluations it had used when its best error first +reached each value of the heading, and the best error it found, to two significant digits. A dash is +an error not reached. The function is evaluated with genoxide's portable math, so the runs are the +same on every platform, and in Python, `run` evaluates it in Rust, so both versions print the same. -[The project page](https://tachsin.gr/projects/genoxide/examples/discus) plays back another -run: CMA-ES on the function in 2 dimensions, 10⁶ x₁² + x₂², rotated with seed 1, so that the -population can be drawn on its contour. It meets the target after 684 evaluations. +[The project page](https://tachsin.gr/projects/genoxide/examples/discus) plays back another run: +CMA-ES on the function in 2 dimensions, 10⁶ x₁² + x₂², rotated with seed 1, so that the population +can be drawn on its contour. It meets the target after 684 evaluations. ## Good results diff --git a/examples/discus/main.py b/examples/discus/main.py index 25fe7ea8..9a8748a9 100644 --- a/examples/discus/main.py +++ b/examples/discus/main.py @@ -1,11 +1,12 @@ -"""Discus: minimize a sphere squashed along one axis, a thousand times more sensitive than -the others, in 30 dimensions, as it is and shifted and rotated. +"""Discus: minimize a sphere squashed along one axis, a thousand times more sensitive than the +others, in 30 dimensions, as it is and shifted and rotated. Compares how fast CMA-ES, with a full and with a diagonal covariance matrix (sep-CMA-ES), differential evolution, particle swarm optimization and a real-coded genetic algorithm close in on -the minimum, 0 at the origin: the evaluations each takes until its error is at most 1, 1e-2, 1e-4, 1e-6 and 1e-8. -The function is genoxide's `problems::Discus`. Then the same on the function shifted and rotated, with genoxide's `problems::Shifted` -and `problems::Rotated`, as the CEC and BBOB suites transform it. +the minimum, 0 at the origin: the evaluations each takes until its error is at most 1, 1e-2, 1e-4, +1e-6 and 1e-8. The function is genoxide's `problems::Discus`. Then the same on the function shifted +and rotated, with genoxide's `problems::Shifted` and `problems::Rotated`, as the CEC and BBOB suites +transform it. With ``GENOXIDE_TRACE=``, it also writes a trace of a run for the plot on the example's page, with trace.py. diff --git a/examples/happy_cat/README.md b/examples/happy_cat/README.md index 294e23cd..37a726bc 100644 --- a/examples/happy_cat/README.md +++ b/examples/happy_cat/README.md @@ -20,13 +20,13 @@ HappyCat adds a slope to the distance from a sphere of radius √n: f(x) = |Σ xᵢ² − n|^(1/4) + (½ Σ xᵢ² + Σ xᵢ) / n + ½, each xᵢ in [−5, 5] ``` -Its minimum is 0, at (−1, …, −1), the only one: the second part is Σ (xᵢ + 1)² / (2n), 0 only -there, where the first is 0 too. Here n = 10. It's Beyer and Finck's (2012) function, which -couldn't be read: its parameter α shapes the groove, and its experiments use α = 1/8, which would -be this function's 1/4 if α is the exponent of (Σ xᵢ² − n)², as it's usually written; that couldn't -be confirmed. genoxide takes the definition from the CEC 2014 report (Liang, Qu and Suganthan 2013, -function 11), which cites Beyer and Finck and scales its search space [−100, 100] by 5/100, to -[−5, 5]. The original is still to be checked (issue #168). +Its minimum is 0, at (−1, …, −1), the only one: the second part is Σ (xᵢ + 1)² / (2n), 0 only there, +where the first is 0 too. Here n = 10. It's Beyer and Finck's (2012) function, which couldn't be +read: its parameter α shapes the groove, and its experiments use α = 1/8, which would be this +function's 1/4 if α is the exponent of (Σ xᵢ² − n)², as it's usually written; that couldn't be +confirmed. genoxide takes the definition from the CEC 2014 report (Liang, Qu and Suganthan 2013, +function 11), which cites Beyer and Finck and scales its search space [−100, 100] by 5/100, to [−5, +5]. The original is still to be checked (issue #168). ## What makes it hard @@ -39,13 +39,13 @@ the groove. The shape of its contour in two dimensions gave it its name. ## Representation -A `Real` genome of 10 genes, each in [−5, 5]: the point x itself. The fitness is f(x), to -minimize. The function is genoxide's `problems::HappyCat`, which brings its bounds and its minimum. +A `Real` genome of 10 genes, each in [−5, 5]: the point x itself. The fitness is f(x), to minimize. +The function is genoxide's `problems::HappyCat`, which brings its bounds and its minimum. ## Algorithm -Five algorithms, each from seeds 1 to 10, with a budget of 10,000 evaluations per dimension, -100,000 per run, and a target of 1e-8: +Five algorithms, each from seeds 1 to 10, with a budget of 10,000 evaluations per dimension, 100,000 +per run, and a target of 1e-8: - CMA-ES (Hansen and Ostermeier, 2001, Evolutionary Computation 9(2): 159-195), which samples a population of 10 from a normal distribution and adapts its mean, its step size and its covariance @@ -62,20 +62,20 @@ Five algorithms, each from seeds 1 to 10, with a budget of 10,000 evaluations pe ## Output -The first line gives the dimension, the seeds and the budget. Then a row per algorithm: how many -of its 10 runs reached the minimum, to within 1e-8, the median of their evaluations (a dash if none -did), and the median of every run's best error, to two significant digits. The function is -evaluated with genoxide's portable math, so the runs are the same on every platform, and in Python, -`run` evaluates it in Rust, so both versions print the same. +The first line gives the dimension, the seeds and the budget. Then a row per algorithm: how many of +its 10 runs reached the minimum, to within 1e-8, the median of their evaluations (a dash if none +did), and the median of every run's best error, to two significant digits. The function is evaluated +with genoxide's portable math, so the runs are the same on every platform, and in Python, `run` +evaluates it in Rust, so both versions print the same. [The project page](https://tachsin.gr/projects/genoxide/examples/happy-cat) plays back another run: -CMA-ES with IPOP restarts on the function in 2 dimensions, so that the population -can be drawn on its contour. Within 20,000 evaluations it ends at an error of 1.7e-4, in the groove near the minimum: -it doesn't reach the target in 2 dimensions either. +CMA-ES with IPOP restarts on the function in 2 dimensions, so that the population can be drawn on +its contour. Within 20,000 evaluations it ends at an error of 1.7e-4, in the groove near the +minimum: it doesn't reach the target in 2 dimensions either. ## Good results No algorithm reaches the minimum to within 1e-8: that's the function's point. CMA-ES with IPOP -restarts comes closest, with a median error of 5.4·10⁻³; CMA-ES without restarts ends at -9.4·10⁻², the genetic algorithm at 7.8·10⁻², SHADE at 0.10 and PSO at 0.14. They all reach the -groove, and stall in it, short of the minimum. +restarts comes closest, with a median error of 5.4·10⁻³; CMA-ES without restarts ends at 9.4·10⁻², +the genetic algorithm at 7.8·10⁻², SHADE at 0.10 and PSO at 0.14. They all reach the groove, and +stall in it, short of the minimum. diff --git a/examples/happy_cat/main.py b/examples/happy_cat/main.py index 6e75757f..9985f725 100644 --- a/examples/happy_cat/main.py +++ b/examples/happy_cat/main.py @@ -1,10 +1,10 @@ """HappyCat: minimize HappyCat, a groove that curves around a sphere to the minimum, in 10 dimensions. -Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), -differential evolution (SHADE), particle swarm optimization and a real-coded genetic algorithm from -10 seeds each, and counts the runs that reach the minimum, 0 at (−1, …, −1), to within 1e-8. The -function is genoxide's `problems::HappyCat`, which run evaluates in Rust. +Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), differential +evolution (SHADE), particle swarm optimization and a real-coded genetic algorithm from 10 seeds +each, and counts the runs that reach the minimum, 0 at (−1, …, −1), to within 1e-8. The function is +genoxide's `problems::HappyCat`, which run evaluates in Rust. With ``GENOXIDE_TRACE=``, it also writes a trace of a run for the plot on the example's page, with trace.py. @@ -78,7 +78,8 @@ def error_text(error): reached = f"{len(evaluations)}/{SEEDS}" middle = median(evaluations) evaluations_text = "-" if middle is None else f"{middle:.0f}" - print(f"{name:<16} {reached:>6} {evaluations_text:>11} {error_text(median(errors)):>12}") + error = error_text(median(errors)) + print(f"{name:<16} {reached:>6} {evaluations_text:>11} {error:>12}") print("evaluations: the median of the runs that reach the minimum") # with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate run in diff --git a/examples/happy_cat/trace.py b/examples/happy_cat/trace.py index 44691e1b..7e4a1ed8 100644 --- a/examples/happy_cat/trace.py +++ b/examples/happy_cat/trace.py @@ -11,7 +11,8 @@ def record_small(): - """Runs CMA-ES with IPOP restarts in 2 dimensions and writes its trace, if ``GENOXIDE_TRACE`` is set.""" + """Runs CMA-ES with IPOP restarts in 2 dimensions and writes its trace, if + ``GENOXIDE_TRACE`` is set.""" path = os.environ.get("GENOXIDE_TRACE") if not path: return diff --git a/examples/hg_bat/README.md b/examples/hg_bat/README.md index 62a3c532..0a812a68 100644 --- a/examples/hg_bat/README.md +++ b/examples/hg_bat/README.md @@ -20,28 +20,27 @@ HGBat is HappyCat's relative, with the difference of two squares in the first te f(x) = |(Σ xᵢ²)² − (Σ xᵢ)²|^(1/2) + (½ Σ xᵢ² + Σ xᵢ) / n + ½, each xᵢ in [−5, 5] ``` -Its minimum is 0, at (−1, …, −1), the only one: the second part is Σ (xᵢ + 1)² / (2n), 0 only -there, where the first is 0 too. Here n = 10. genoxide takes it from the CEC 2014 report (Liang, Qu -and Suganthan 2013, function 12), which scales its search space [−100, 100] by 5/100, to -[−5, 5], and gives no other source; it's usually credited to Beyer and Finck too, whose paper -couldn't be read. +Its minimum is 0, at (−1, …, −1), the only one: the second part is Σ (xᵢ + 1)² / (2n), 0 only there, +where the first is 0 too. Here n = 10. genoxide takes it from the CEC 2014 report (Liang, Qu and +Suganthan 2013, function 12), which scales its search space [−100, 100] by 5/100, to [−5, 5], and +gives no other source; it's usually credited to Beyer and Finck too, whose paper couldn't be read. ## What makes it hard -The first term is 0 where ‖x‖² = |Σ xᵢ|, a curved surface through the origin and (−1, …, −1), -and rises as a square root away from it: a groove whose floor curves around to the minimum, with a +The first term is 0 where ‖x‖² = |Σ xᵢ|, a curved surface through the origin and (−1, …, −1), and +rises as a square root away from it: a groove whose floor curves around to the minimum, with a gentle slope along it. As on HappyCat, a search falls into the groove at once, then has to follow a curving direction with small steps across it and large ones along it. ## Representation -A `Real` genome of 10 genes, each in [−5, 5]: the point x itself. The fitness is f(x), to -minimize. The function is genoxide's `problems::HgBat`, which brings its bounds and its minimum. +A `Real` genome of 10 genes, each in [−5, 5]: the point x itself. The fitness is f(x), to minimize. +The function is genoxide's `problems::HgBat`, which brings its bounds and its minimum. ## Algorithm -Five algorithms, each from seeds 1 to 10, with a budget of 10,000 evaluations per dimension, -100,000 per run, and a target of 1e-8: +Five algorithms, each from seeds 1 to 10, with a budget of 10,000 evaluations per dimension, 100,000 +per run, and a target of 1e-8: - CMA-ES (Hansen and Ostermeier, 2001, Evolutionary Computation 9(2): 159-195), which samples a population of 10 from a normal distribution and adapts its mean, its step size and its covariance @@ -58,16 +57,16 @@ Five algorithms, each from seeds 1 to 10, with a budget of 10,000 evaluations pe ## Output -The first line gives the dimension, the seeds and the budget. Then a row per algorithm: how many -of its 10 runs reached the minimum, to within 1e-8, the median of their evaluations (a dash if none -did), and the median of every run's best error, to two significant digits. The function is -evaluated with genoxide's portable math, so the runs are the same on every platform, and in Python, -`run` evaluates it in Rust, so both versions print the same. +The first line gives the dimension, the seeds and the budget. Then a row per algorithm: how many of +its 10 runs reached the minimum, to within 1e-8, the median of their evaluations (a dash if none +did), and the median of every run's best error, to two significant digits. The function is evaluated +with genoxide's portable math, so the runs are the same on every platform, and in Python, `run` +evaluates it in Rust, so both versions print the same. [The project page](https://tachsin.gr/projects/genoxide/examples/hg-bat) plays back another run: -CMA-ES with IPOP restarts on the function in 2 dimensions, so that the population -can be drawn on its contour. Within 20,000 evaluations it ends at an error of 0.010, in the groove: it doesn't reach the -target in 2 dimensions either. +CMA-ES with IPOP restarts on the function in 2 dimensions, so that the population can be drawn on +its contour. Within 20,000 evaluations it ends at an error of 0.010, in the groove: it doesn't reach +the target in 2 dimensions either. ## Good results diff --git a/examples/hg_bat/main.py b/examples/hg_bat/main.py index 0339a21a..576f4972 100644 --- a/examples/hg_bat/main.py +++ b/examples/hg_bat/main.py @@ -1,10 +1,9 @@ -"""HGBat: minimize HGBat, HappyCat's relative with a groove along a cone, in 10 -dimensions. +"""HGBat: minimize HGBat, HappyCat's relative with a groove along a cone, in 10 dimensions. -Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), -differential evolution (SHADE), particle swarm optimization and a real-coded genetic algorithm from -10 seeds each, and counts the runs that reach the minimum, 0 at (−1, …, −1), to within 1e-8. The -function is genoxide's `problems::HgBat`, which run evaluates in Rust. +Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), differential +evolution (SHADE), particle swarm optimization and a real-coded genetic algorithm from 10 seeds +each, and counts the runs that reach the minimum, 0 at (−1, …, −1), to within 1e-8. The function is +genoxide's `problems::HgBat`, which run evaluates in Rust. With ``GENOXIDE_TRACE=``, it also writes a trace of a run for the plot on the example's page, with trace.py. @@ -78,7 +77,8 @@ def error_text(error): reached = f"{len(evaluations)}/{SEEDS}" middle = median(evaluations) evaluations_text = "-" if middle is None else f"{middle:.0f}" - print(f"{name:<16} {reached:>6} {evaluations_text:>11} {error_text(median(errors)):>12}") + error = error_text(median(errors)) + print(f"{name:<16} {reached:>6} {evaluations_text:>11} {error:>12}") print("evaluations: the median of the runs that reach the minimum") # with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate run in diff --git a/examples/hg_bat/trace.py b/examples/hg_bat/trace.py index 7fd1d7c9..f7de2ea3 100644 --- a/examples/hg_bat/trace.py +++ b/examples/hg_bat/trace.py @@ -11,7 +11,8 @@ def record_small(): - """Runs CMA-ES with IPOP restarts in 2 dimensions and writes its trace, if ``GENOXIDE_TRACE`` is set.""" + """Runs CMA-ES with IPOP restarts in 2 dimensions and writes its trace, if + ``GENOXIDE_TRACE`` is set.""" path = os.environ.get("GENOXIDE_TRACE") if not path: return diff --git a/examples/high_conditioned_elliptic/README.md b/examples/high_conditioned_elliptic/README.md index e2154009..a9745842 100644 --- a/examples/high_conditioned_elliptic/README.md +++ b/examples/high_conditioned_elliptic/README.md @@ -21,27 +21,28 @@ first gene to the last: f(x) = Σ (10⁶)^((i−1)/(n−1)) xᵢ², i from 1 to n, each xᵢ in [−100, 100] ``` -Its minimum is 0, at the origin. Here n = 30. It's the function F3 of the CEC 2005 report -(Suganthan et al. 2005), which shifts and rotates it, and gives these bounds; the CEC 2014 and -2017 reports have the same basic function, and BBOB's f2 and f10 (Hansen et al. 2009) the same -ellipsoid with an oscillation that genoxide doesn't apply. +Its minimum is 0, at the origin. Here n = 30. It's the function F3 of the CEC 2005 report (Suganthan +et al. 2005), which shifts and rotates it, and gives these bounds; the CEC 2014 and 2017 reports +have the same basic function, and BBOB's f2 and f10 (Hansen et al. 2009) the same ellipsoid with an +oscillation that genoxide doesn't apply. ## What makes it hard -The weights run from 1 to 10⁶: the ellipsoid's axes from 1 to 1,000 in length, a condition number -of 10⁶. Along the first gene the function is a million times flatter than along the last. A search -with one step size for every direction either crawls along the flat axes or overshoots along the -steep ones: it must learn a scale per direction. +The weights run from 1 to 10⁶: the ellipsoid's axes from 1 to 1,000 in length, a condition number of +10⁶. Along the first gene the function is a million times flatter than along the last. A search with +one step size for every direction either crawls along the flat axes or overshoots along the steep +ones: it must learn a scale per direction. -As it is, those directions are the genes' axes, and a scale per gene is enough. Shifted and -rotated, as in CEC 2005, they're 30 random directions: only a full covariance matrix, with its -465 parameters, can learn them. +As it is, those directions are the genes' axes, and a scale per gene is enough. Shifted and rotated, +as in CEC 2005, they're 30 random directions: only a full covariance matrix, with its 465 +parameters, can learn them. ## Representation A `Real` genome of 30 genes: the point x itself. The fitness is f(x), to minimize. The function is -genoxide's `problems::HighConditionedElliptic`, which brings its bounds and its minimum, and the shifted and rotated -instance `problems::Rotated::new(problems::Shifted::new(function, 1), 1)`, which keeps them. +genoxide's `problems::HighConditionedElliptic`, which brings its bounds and its minimum, and the +shifted and rotated instance `problems::Rotated::new(problems::Shifted::new(function, 1), 1)`, which +keeps them. ## Algorithm @@ -69,21 +70,21 @@ suites use the function, with their own data; genoxide generates its instances i ## Output -The first line gives the dimension and the budget. Then two tables, the function as it is and shifted and rotated: a row per algorithm, the -evaluations it had used when its best error first reached each value of the heading, and the best -error it found, to two significant digits. A dash is an error not reached. The function is -evaluated with genoxide's portable math, so the runs are the same on every platform, and in Python, -`run` evaluates it in Rust, so both versions print the same. +The first line gives the dimension and the budget. Then two tables, the function as it is and +shifted and rotated: a row per algorithm, the evaluations it had used when its best error first +reached each value of the heading, and the best error it found, to two significant digits. A dash is +an error not reached. The function is evaluated with genoxide's portable math, so the runs are the +same on every platform, and in Python, `run` evaluates it in Rust, so both versions print the same. -[The project page](https://tachsin.gr/projects/genoxide/examples/high-conditioned-elliptic) plays back another -run: CMA-ES on the function in 2 dimensions, x₁² + 10⁶ x₂², rotated with seed 1, so that the -population can be drawn on its contour. It meets the target after 654 evaluations. +[The project page](https://tachsin.gr/projects/genoxide/examples/high-conditioned-elliptic) plays +back another run: CMA-ES on the function in 2 dimensions, x₁² + 10⁶ x₂², rotated with seed 1, so +that the population can be drawn on its contour. It meets the target after 654 evaluations. ## Good results -The minimum is 0. As it is, sep-CMA-ES reaches 1e-8 first, after 9,016 evaluations: a scale per -gene fits the ellipsoid. PSO takes 35,320, CMA-ES 39,242 (most of them, 36,036, to reach an error of -1, while its covariance matrix learns the scales), and SHADE 40,100. The genetic algorithm ends at +The minimum is 0. As it is, sep-CMA-ES reaches 1e-8 first, after 9,016 evaluations: a scale per gene +fits the ellipsoid. PSO takes 35,320, CMA-ES 39,242 (most of them, 36,036, to reach an error of 1, +while its covariance matrix learns the scales), and SHADE 40,100. The genetic algorithm ends at 0.92. Shifted and rotated, as CEC 2005's F3, CMA-ES takes the same 39,550 evaluations: for its full diff --git a/examples/high_conditioned_elliptic/main.py b/examples/high_conditioned_elliptic/main.py index dae906dd..0dd276f4 100644 --- a/examples/high_conditioned_elliptic/main.py +++ b/examples/high_conditioned_elliptic/main.py @@ -3,9 +3,10 @@ Compares how fast CMA-ES, with a full and with a diagonal covariance matrix (sep-CMA-ES), differential evolution, particle swarm optimization and a real-coded genetic algorithm close in on -the minimum, 0 at the origin: the evaluations each takes until its error is at most 1, 1e-2, 1e-4, 1e-6 and 1e-8. -The function is genoxide's `problems::HighConditionedElliptic`. Then the same on the function shifted and rotated, with genoxide's `problems::Shifted` -and `problems::Rotated`, as the CEC and BBOB suites transform it. +the minimum, 0 at the origin: the evaluations each takes until its error is at most 1, 1e-2, 1e-4, +1e-6 and 1e-8. The function is genoxide's `problems::HighConditionedElliptic`. Then the same on the +function shifted and rotated, with genoxide's `problems::Shifted` and `problems::Rotated`, as the +CEC and BBOB suites transform it. With ``GENOXIDE_TRACE=``, it also writes a trace of a run for the plot on the example's page, with trace.py. @@ -89,7 +90,9 @@ def compare(name, problem): print(f"High-conditioned elliptic in {DIMENSIONS} dimensions, {BUDGET} evaluations at most") compare("High-conditioned elliptic", gx.problems.HighConditionedElliptic(DIMENSIONS)) # CEC 2005's F3, with genoxide's own shift and rotation -rotated = gx.problems.Rotated(gx.problems.Shifted(gx.problems.HighConditionedElliptic(DIMENSIONS), seed=1), seed=1) +rotated = gx.problems.Rotated( + gx.problems.Shifted(gx.problems.HighConditionedElliptic(DIMENSIONS), seed=1), seed=1 +) compare("Shifted and rotated (seed 1)", rotated) # with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate run in diff --git a/examples/high_conditioned_elliptic/main.rs b/examples/high_conditioned_elliptic/main.rs index 76772360..87ef2516 100644 --- a/examples/high_conditioned_elliptic/main.rs +++ b/examples/high_conditioned_elliptic/main.rs @@ -28,7 +28,10 @@ const COLUMNS: [&str; 5] = ["1", "1e-2", "1e-4", "1e-6", "1e-8"]; fn main() -> Result<()> { println!("High-conditioned elliptic in {DIMENSIONS} dimensions, {BUDGET} evaluations at most"); - compare("High-conditioned elliptic", &HighConditionedElliptic::new(DIMENSIONS))?; + compare( + "High-conditioned elliptic", + &HighConditionedElliptic::new(DIMENSIONS), + )?; // CEC 2005's F3, with genoxide's own shift and rotation let rotated = Rotated::new(Shifted::new(HighConditionedElliptic::new(DIMENSIONS), 1), 1); compare("Shifted and rotated (seed 1)", &rotated)?; diff --git a/examples/katsuura/README.md b/examples/katsuura/README.md index 08a5f0f1..f51573aa 100644 --- a/examples/katsuura/README.md +++ b/examples/katsuura/README.md @@ -14,8 +14,8 @@ trace_note: "Recorded from another run: CMA-ES with IPOP restarts in 2 dimension ## The problem -Katsuura's function multiplies, over the genes, terms that measure how far the gene's binary -digits are from whole numbers: +Katsuura's function multiplies, over the genes, terms that measure how far the gene's binary digits +are from whole numbers: ```text f(x) = (10 / n²) Πᵢ (1 + i Σⱼ₌₁³² |2ʲxᵢ − round(2ʲxᵢ)| / 2ʲ)^(10 / n^1.2) − 10 / n² @@ -25,31 +25,30 @@ each xᵢ in [−5, 5] Its minimum is 0, wherever every gene is a multiple of 1/2: then every 2ʲxᵢ is a whole number, and every factor is 1. There are 21ⁿ such points in the box, among them the origin. Here n = 10. It's BBOB's f23 (Hansen et al. 2009), "based on the idea" of Katsuura (1991, The American Mathematical -Monthly 98(5): 411-416, not read), without BBOB's rotation and scaling, and its penalty outside -[−5, 5]; the CEC 2014 report has the same basic function. +Monthly 98(5): 411-416, not read), without BBOB's rotation and scaling, and its penalty outside [−5, +5]; the CEC 2014 report has the same basic function. ## What makes it hard -Each factor is a continuous, nowhere-differentiable function of its gene, rugged at every scale -down to 2⁻³², and the product couples the genes. The landscape is highly repetitive, with global -minima on a grid of spacing 1/2 and local minima everywhere between: a search that has found a -good region gains little from its neighborhood. +Each factor is a continuous, nowhere-differentiable function of its gene, rugged at every scale down +to 2⁻³², and the product couples the genes. The landscape is highly repetitive, with global minima +on a grid of spacing 1/2 and local minima everywhere between: a search that has found a good region +gains little from its neighborhood. The grid of global minima includes the bounds, ±5. A search that pushes genes onto the bounds, as -PSO does when a particle would leave the box and stops at the bound, lands on global minima without searching. -BBOB avoids this by rotating and shifting the function; genoxide's `problems::Shifted` does the -same. +PSO does when a particle would leave the box and stops at the bound, lands on global minima without +searching. BBOB avoids this by rotating and shifting the function; genoxide's `problems::Shifted` +does the same. ## Representation -A `Real` genome of 10 genes, each in [−5, 5]: the point x itself. The fitness is f(x), to -minimize. The function is genoxide's `problems::Katsuura`, which brings its bounds and its -minimum. +A `Real` genome of 10 genes, each in [−5, 5]: the point x itself. The fitness is f(x), to minimize. +The function is genoxide's `problems::Katsuura`, which brings its bounds and its minimum. ## Algorithm -Five algorithms, each from seeds 1 to 10, with a budget of 10,000 evaluations per dimension, -100,000 per run, and a target of 1e-8: +Five algorithms, each from seeds 1 to 10, with a budget of 10,000 evaluations per dimension, 100,000 +per run, and a target of 1e-8: - CMA-ES (Hansen and Ostermeier, 2001, Evolutionary Computation 9(2): 159-195), which samples a population of 10 from a normal distribution and adapts its mean, its step size and its covariance @@ -66,25 +65,25 @@ Five algorithms, each from seeds 1 to 10, with a budget of 10,000 evaluations pe ## Output -The first line gives the dimension, the seeds and the budget. Then a row per algorithm: how many -of its 10 runs reached the minimum, to within 1e-8, the median of their evaluations (a dash if none -did), and the median of every run's best error, to two significant digits. The function is -evaluated with genoxide's portable math, so the runs are the same on every platform, and in Python, -`run` evaluates it in Rust, so both versions print the same. +The first line gives the dimension, the seeds and the budget. Then a row per algorithm: how many of +its 10 runs reached the minimum, to within 1e-8, the median of their evaluations (a dash if none +did), and the median of every run's best error, to two significant digits. The function is evaluated +with genoxide's portable math, so the runs are the same on every platform, and in Python, `run` +evaluates it in Rust, so both versions print the same. [The project page](https://tachsin.gr/projects/genoxide/examples/katsuura) plays back another run: -CMA-ES with IPOP restarts on the function in 2 dimensions, so that the population -can be drawn on its contour. It meets the target after 990 evaluations, at a multiple of 1/2. +CMA-ES with IPOP restarts on the function in 2 dimensions, so that the population can be drawn on +its contour. It meets the target after 990 evaluations, at a multiple of 1/2. ## Good results -The minimum is 0. PSO reaches it in all 10 runs, after a median of 380 evaluations, but only -through the bounds: its particles head out of the box, stop at ±5 in every gene, and land on a -corner, a global minimum (from seed 1, at (5, 5, −5, 5, −5, 5, −5, 5, 5, −5)). On the function -shifted with genoxide's `problems::Shifted` and seed 1, whose minima are no longer on the bounds, -PSO's runs from seeds 1 and 2 end at 0.021. +The minimum is 0. PSO reaches it in all 10 runs, after a median of 380 evaluations, but only through +the bounds: its particles head out of the box, stop at ±5 in every gene, and land on a corner, a +global minimum (from seed 1, at (5, 5, −5, 5, −5, 5, −5, 5, 5, −5)). On the function shifted with +genoxide's `problems::Shifted` and seed 1, whose minima are no longer on the bounds, PSO's runs from +seeds 1 and 2 end at 0.021. Of the searches that don't use the bounds, CMA-ES with IPOP restarts reaches the minimum once, after -41,990 evaluations, and its median run ends at 1.3e-2. SHADE comes closest without reaching it, -with a median error of 5.8e-6, and the genetic algorithm ends at 3.7e-4. CMA-ES without restarts -ends at 0.10. +41,990 evaluations, and its median run ends at 1.3e-2. SHADE comes closest without reaching it, with +a median error of 5.8e-6, and the genetic algorithm ends at 3.7e-4. CMA-ES without restarts ends at +0.10. diff --git a/examples/katsuura/main.py b/examples/katsuura/main.py index 65dfb8a9..ac07d488 100644 --- a/examples/katsuura/main.py +++ b/examples/katsuura/main.py @@ -1,9 +1,9 @@ """Katsuura: minimize Katsuura's function, rugged everywhere, in 10 dimensions. -Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), -differential evolution (SHADE), particle swarm optimization and a real-coded genetic algorithm from -10 seeds each, and counts the runs that reach the minimum, 0 at the origin, to within 1e-8. The -function is genoxide's `problems::Katsuura`, which run evaluates in Rust. +Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), differential +evolution (SHADE), particle swarm optimization and a real-coded genetic algorithm from 10 seeds +each, and counts the runs that reach the minimum, 0 at the origin, to within 1e-8. The function is +genoxide's `problems::Katsuura`, which run evaluates in Rust. With ``GENOXIDE_TRACE=``, it also writes a trace of a run for the plot on the example's page, with trace.py. @@ -77,7 +77,8 @@ def error_text(error): reached = f"{len(evaluations)}/{SEEDS}" middle = median(evaluations) evaluations_text = "-" if middle is None else f"{middle:.0f}" - print(f"{name:<16} {reached:>6} {evaluations_text:>11} {error_text(median(errors)):>12}") + error = error_text(median(errors)) + print(f"{name:<16} {reached:>6} {evaluations_text:>11} {error:>12}") print("evaluations: the median of the runs that reach the minimum") # with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate run in diff --git a/examples/katsuura/trace.py b/examples/katsuura/trace.py index ed554e0a..e53e1a50 100644 --- a/examples/katsuura/trace.py +++ b/examples/katsuura/trace.py @@ -11,7 +11,8 @@ def record_small(): - """Runs CMA-ES with IPOP restarts in 2 dimensions and writes its trace, if ``GENOXIDE_TRACE`` is set.""" + """Runs CMA-ES with IPOP restarts in 2 dimensions and writes its trace, if + ``GENOXIDE_TRACE`` is set.""" path = os.environ.get("GENOXIDE_TRACE") if not path: return diff --git a/examples/non_continuous_rastrigin/README.md b/examples/non_continuous_rastrigin/README.md index f0a19fa5..d0ddb0ba 100644 --- a/examples/non_continuous_rastrigin/README.md +++ b/examples/non_continuous_rastrigin/README.md @@ -14,8 +14,8 @@ trace_note: "Recorded from another run: CMA-ES with IPOP restarts in 2 dimension ## The problem -The non-continuous Rastrigin function is Rastrigin's function of genes rounded to half-integers -away from the origin: +The non-continuous Rastrigin function is Rastrigin's function of genes rounded to half-integers away +from the origin: ```text f(x) = Σ (yᵢ² − 10 cos 2πyᵢ + 10), yᵢ = xᵢ if |xᵢ| < 1/2, round(2xᵢ)/2 otherwise @@ -42,8 +42,8 @@ its minimum. ## Algorithm -Five algorithms, each from seeds 1 to 10, with a budget of 10,000 evaluations per dimension, -100,000 per run, and a target of 1e-8: +Five algorithms, each from seeds 1 to 10, with a budget of 10,000 evaluations per dimension, 100,000 +per run, and a target of 1e-8: - CMA-ES (Hansen and Ostermeier, 2001, Evolutionary Computation 9(2): 159-195), which samples a population of 10 from a normal distribution and adapts its mean, its step size and its covariance @@ -60,14 +60,14 @@ Five algorithms, each from seeds 1 to 10, with a budget of 10,000 evaluations pe ## Output -The first line gives the dimension, the seeds and the budget. Then a row per algorithm: how many -of its 10 runs reached the minimum, to within 1e-8, the median of their evaluations (a dash if none -did), and the median of every run's best error, to two significant digits. The function is -evaluated with genoxide's portable math, so the runs are the same on every platform, and in Python, -`run` evaluates it in Rust, so both versions print the same. +The first line gives the dimension, the seeds and the budget. Then a row per algorithm: how many of +its 10 runs reached the minimum, to within 1e-8, the median of their evaluations (a dash if none +did), and the median of every run's best error, to two significant digits. The function is evaluated +with genoxide's portable math, so the runs are the same on every platform, and in Python, `run` +evaluates it in Rust, so both versions print the same. -[The project page](https://tachsin.gr/projects/genoxide/examples/non-continuous-rastrigin) plays back another run: -CMA-ES with IPOP restarts on the function in 2 dimensions, so that the population +[The project page](https://tachsin.gr/projects/genoxide/examples/non-continuous-rastrigin) plays +back another run: CMA-ES with IPOP restarts on the function in 2 dimensions, so that the population can be drawn on its contour. Within 20,000 evaluations it ends at an error of 6.9e-4, near the minimum but short of the target. diff --git a/examples/non_continuous_rastrigin/main.py b/examples/non_continuous_rastrigin/main.py index 161709a9..d4e553f7 100644 --- a/examples/non_continuous_rastrigin/main.py +++ b/examples/non_continuous_rastrigin/main.py @@ -1,10 +1,10 @@ """Non-continuous Rastrigin: minimize Rastrigin's function made flat between half-integers, in 10 dimensions. -Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), -differential evolution (SHADE), particle swarm optimization and a real-coded genetic algorithm from -10 seeds each, and counts the runs that reach the minimum, 0 at the origin, to within 1e-8. The -function is genoxide's `problems::NonContinuousRastrigin`, which run evaluates in Rust. +Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), differential +evolution (SHADE), particle swarm optimization and a real-coded genetic algorithm from 10 seeds +each, and counts the runs that reach the minimum, 0 at the origin, to within 1e-8. The function is +genoxide's `problems::NonContinuousRastrigin`, which run evaluates in Rust. With ``GENOXIDE_TRACE=``, it also writes a trace of a run for the plot on the example's page, with trace.py. @@ -62,7 +62,10 @@ def error_text(error): problem = gx.problems.NonContinuousRastrigin(DIMENSIONS) minimum = problem.optimum.value -print(f"Non-continuous Rastrigin in {DIMENSIONS} dimensions, {SEEDS} seeds, {BUDGET} evaluations at most per run") +print( + f"Non-continuous Rastrigin in {DIMENSIONS} dimensions, {SEEDS} seeds, " + f"{BUDGET} evaluations at most per run" +) print("algorithm at min evaluations median error") for name in ALGORITHMS: # the evaluations of the runs that reach the minimum, and every run's best error @@ -78,7 +81,8 @@ def error_text(error): reached = f"{len(evaluations)}/{SEEDS}" middle = median(evaluations) evaluations_text = "-" if middle is None else f"{middle:.0f}" - print(f"{name:<16} {reached:>6} {evaluations_text:>11} {error_text(median(errors)):>12}") + error = error_text(median(errors)) + print(f"{name:<16} {reached:>6} {evaluations_text:>11} {error:>12}") print("evaluations: the median of the runs that reach the minimum") # with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate run in diff --git a/examples/non_continuous_rastrigin/main.rs b/examples/non_continuous_rastrigin/main.rs index 6801080e..36034fc9 100644 --- a/examples/non_continuous_rastrigin/main.rs +++ b/examples/non_continuous_rastrigin/main.rs @@ -63,7 +63,12 @@ fn main() -> Result<()> { // a run of `algorithm` from `seed`, until its best is at most `target` or it has used BUDGET // evaluations -fn run(algorithm: &str, problem: NonContinuousRastrigin, seed: u64, target: f64) -> Result> { +fn run( + algorithm: &str, + problem: NonContinuousRastrigin, + seed: u64, + target: f64, +) -> Result> { let real = problem.representation(); let stop = Stop::target(target).or(Stop::evaluations(BUDGET)); match algorithm { diff --git a/examples/non_continuous_rastrigin/trace.py b/examples/non_continuous_rastrigin/trace.py index 17a40a16..db8c0395 100644 --- a/examples/non_continuous_rastrigin/trace.py +++ b/examples/non_continuous_rastrigin/trace.py @@ -11,7 +11,8 @@ def record_small(): - """Runs CMA-ES with IPOP restarts in 2 dimensions and writes its trace, if ``GENOXIDE_TRACE`` is set.""" + """Runs CMA-ES with IPOP restarts in 2 dimensions and writes its trace, if + ``GENOXIDE_TRACE`` is set.""" path = os.environ.get("GENOXIDE_TRACE") if not path: return diff --git a/examples/penalized1/README.md b/examples/penalized1/README.md index 6b876103..2475bf4c 100644 --- a/examples/penalized1/README.md +++ b/examples/penalized1/README.md @@ -32,21 +32,22 @@ function is usually credited to Levy and Montalvo's tunneling papers (1985), whi ## What makes it hard -The sines put a local minimum near every point where their arguments are whole multiples of π: -a grid of shallow wells over the box, the more of them the more genes. The wells' depth scales with +The sines put a local minimum near every point where their arguments are whole multiples of π: a +grid of shallow wells over the box, the more of them the more genes. The wells' depth scales with the squares in front of the sines, so they are shallower the nearer the minimum, and the squares -lead towards it. The penalty u is 0 inside [−10, 10] (Penalized 1) or [−5, 5] (Penalized 2), and rises as a -fourth power outside: a wall that keeps the search away from the bounds of [−50, 50]. +lead towards it. The penalty u is 0 inside [−10, 10] (Penalized 1) or [−5, 5] (Penalized 2), and +rises as a fourth power outside: a wall that keeps the search away from the bounds of [−50, 50]. ## Representation A `Real` genome of 30 genes, each in [−50, 50]: the point x itself. The fitness is f(x), to -minimize. The function is genoxide's `problems::Penalized1`, which brings its bounds and its minimum. +minimize. The function is genoxide's `problems::Penalized1`, which brings its bounds and its +minimum. ## Algorithm -Five algorithms, each from seeds 1 to 10, with a budget of 10,000 evaluations per dimension, -300,000 per run, and a target of 1e-8: +Five algorithms, each from seeds 1 to 10, with a budget of 10,000 evaluations per dimension, 300,000 +per run, and a target of 1e-8: - CMA-ES (Hansen and Ostermeier, 2001, Evolutionary Computation 9(2): 159-195), which samples a population of 14 from a normal distribution and adapts its mean, its step size and its covariance @@ -63,15 +64,15 @@ Five algorithms, each from seeds 1 to 10, with a budget of 10,000 evaluations pe ## Output -The first line gives the dimension, the seeds and the budget. Then a row per algorithm: how many -of its 10 runs reached the minimum, to within 1e-8, the median of their evaluations (a dash if none -did), and the median of every run's best error, to two significant digits. The function is -evaluated with genoxide's portable math, so the runs are the same on every platform, and in Python, -`run` evaluates it in Rust, so both versions print the same. +The first line gives the dimension, the seeds and the budget. Then a row per algorithm: how many of +its 10 runs reached the minimum, to within 1e-8, the median of their evaluations (a dash if none +did), and the median of every run's best error, to two significant digits. The function is evaluated +with genoxide's portable math, so the runs are the same on every platform, and in Python, `run` +evaluates it in Rust, so both versions print the same. [The project page](https://tachsin.gr/projects/genoxide/examples/penalized1) plays back another run: -CMA-ES with IPOP restarts on the function in 2 dimensions, so that the population -can be drawn on its contour. It meets the target after 426 evaluations. +CMA-ES with IPOP restarts on the function in 2 dimensions, so that the population can be drawn on +its contour. It meets the target after 426 evaluations. ## Good results diff --git a/examples/penalized1/main.py b/examples/penalized1/main.py index 8d9fb0ae..b365d23f 100644 --- a/examples/penalized1/main.py +++ b/examples/penalized1/main.py @@ -1,10 +1,10 @@ """Penalized 1: minimize Yao, Liu and Lin's first penalized function, Levy's function with a penalty, in 30 dimensions. -Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), -differential evolution (SHADE), particle swarm optimization and a real-coded genetic algorithm from -10 seeds each, and counts the runs that reach the minimum, 0 at (−1, …, −1), to within 1e-8. The -function is genoxide's `problems::Penalized1`, which run evaluates in Rust. +Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), differential +evolution (SHADE), particle swarm optimization and a real-coded genetic algorithm from 10 seeds +each, and counts the runs that reach the minimum, 0 at (−1, …, −1), to within 1e-8. The function is +genoxide's `problems::Penalized1`, which run evaluates in Rust. With ``GENOXIDE_TRACE=``, it also writes a trace of a run for the plot on the example's page, with trace.py. @@ -62,7 +62,10 @@ def error_text(error): problem = gx.problems.Penalized1(DIMENSIONS) minimum = problem.optimum.value -print(f"Penalized 1 in {DIMENSIONS} dimensions, {SEEDS} seeds, {BUDGET} evaluations at most per run") +print( + f"Penalized 1 in {DIMENSIONS} dimensions, {SEEDS} seeds, " + f"{BUDGET} evaluations at most per run" +) print("algorithm at min evaluations median error") for name in ALGORITHMS: # the evaluations of the runs that reach the minimum, and every run's best error @@ -78,7 +81,8 @@ def error_text(error): reached = f"{len(evaluations)}/{SEEDS}" middle = median(evaluations) evaluations_text = "-" if middle is None else f"{middle:.0f}" - print(f"{name:<16} {reached:>6} {evaluations_text:>11} {error_text(median(errors)):>12}") + error = error_text(median(errors)) + print(f"{name:<16} {reached:>6} {evaluations_text:>11} {error:>12}") print("evaluations: the median of the runs that reach the minimum") # with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate run in diff --git a/examples/penalized1/trace.py b/examples/penalized1/trace.py index c727bb02..aa152e37 100644 --- a/examples/penalized1/trace.py +++ b/examples/penalized1/trace.py @@ -11,7 +11,8 @@ def record_small(): - """Runs CMA-ES with IPOP restarts in 2 dimensions and writes its trace, if ``GENOXIDE_TRACE`` is set.""" + """Runs CMA-ES with IPOP restarts in 2 dimensions and writes its trace, if + ``GENOXIDE_TRACE`` is set.""" path = os.environ.get("GENOXIDE_TRACE") if not path: return diff --git a/examples/penalized2/README.md b/examples/penalized2/README.md index 542a3e76..97701f4e 100644 --- a/examples/penalized2/README.md +++ b/examples/penalized2/README.md @@ -32,21 +32,22 @@ function is usually credited to Levy and Montalvo's tunneling papers (1985), whi ## What makes it hard -The sines put a local minimum near every point where their arguments are whole multiples of π: -a grid of shallow wells over the box, the more of them the more genes. The wells' depth scales with +The sines put a local minimum near every point where their arguments are whole multiples of π: a +grid of shallow wells over the box, the more of them the more genes. The wells' depth scales with the squares in front of the sines, so they are shallower the nearer the minimum, and the squares -lead towards it. The penalty u is 0 inside [−10, 10] (Penalized 1) or [−5, 5] (Penalized 2), and rises as a -fourth power outside: a wall that keeps the search away from the bounds of [−50, 50]. +lead towards it. The penalty u is 0 inside [−10, 10] (Penalized 1) or [−5, 5] (Penalized 2), and +rises as a fourth power outside: a wall that keeps the search away from the bounds of [−50, 50]. ## Representation A `Real` genome of 30 genes, each in [−50, 50]: the point x itself. The fitness is f(x), to -minimize. The function is genoxide's `problems::Penalized2`, which brings its bounds and its minimum. +minimize. The function is genoxide's `problems::Penalized2`, which brings its bounds and its +minimum. ## Algorithm -Five algorithms, each from seeds 1 to 10, with a budget of 10,000 evaluations per dimension, -300,000 per run, and a target of 1e-8: +Five algorithms, each from seeds 1 to 10, with a budget of 10,000 evaluations per dimension, 300,000 +per run, and a target of 1e-8: - CMA-ES (Hansen and Ostermeier, 2001, Evolutionary Computation 9(2): 159-195), which samples a population of 14 from a normal distribution and adapts its mean, its step size and its covariance @@ -63,15 +64,15 @@ Five algorithms, each from seeds 1 to 10, with a budget of 10,000 evaluations pe ## Output -The first line gives the dimension, the seeds and the budget. Then a row per algorithm: how many -of its 10 runs reached the minimum, to within 1e-8, the median of their evaluations (a dash if none -did), and the median of every run's best error, to two significant digits. The function is -evaluated with genoxide's portable math, so the runs are the same on every platform, and in Python, -`run` evaluates it in Rust, so both versions print the same. +The first line gives the dimension, the seeds and the budget. Then a row per algorithm: how many of +its 10 runs reached the minimum, to within 1e-8, the median of their evaluations (a dash if none +did), and the median of every run's best error, to two significant digits. The function is evaluated +with genoxide's portable math, so the runs are the same on every platform, and in Python, `run` +evaluates it in Rust, so both versions print the same. [The project page](https://tachsin.gr/projects/genoxide/examples/penalized2) plays back another run: -CMA-ES with IPOP restarts on the function in 2 dimensions, so that the population -can be drawn on its contour. It meets the target after 396 evaluations. +CMA-ES with IPOP restarts on the function in 2 dimensions, so that the population can be drawn on +its contour. It meets the target after 396 evaluations. ## Good results diff --git a/examples/penalized2/main.py b/examples/penalized2/main.py index bcfda828..fc3a4317 100644 --- a/examples/penalized2/main.py +++ b/examples/penalized2/main.py @@ -1,9 +1,9 @@ """Penalized 2: minimize Yao, Liu and Lin's second penalized function in 30 dimensions. -Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), -differential evolution (SHADE), particle swarm optimization and a real-coded genetic algorithm from -10 seeds each, and counts the runs that reach the minimum, 0 at (1, …, 1), to within 1e-8. The -function is genoxide's `problems::Penalized2`, which run evaluates in Rust. +Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), differential +evolution (SHADE), particle swarm optimization and a real-coded genetic algorithm from 10 seeds +each, and counts the runs that reach the minimum, 0 at (1, …, 1), to within 1e-8. The function is +genoxide's `problems::Penalized2`, which run evaluates in Rust. With ``GENOXIDE_TRACE=``, it also writes a trace of a run for the plot on the example's page, with trace.py. @@ -61,7 +61,10 @@ def error_text(error): problem = gx.problems.Penalized2(DIMENSIONS) minimum = problem.optimum.value -print(f"Penalized 2 in {DIMENSIONS} dimensions, {SEEDS} seeds, {BUDGET} evaluations at most per run") +print( + f"Penalized 2 in {DIMENSIONS} dimensions, {SEEDS} seeds, " + f"{BUDGET} evaluations at most per run" +) print("algorithm at min evaluations median error") for name in ALGORITHMS: # the evaluations of the runs that reach the minimum, and every run's best error @@ -77,7 +80,8 @@ def error_text(error): reached = f"{len(evaluations)}/{SEEDS}" middle = median(evaluations) evaluations_text = "-" if middle is None else f"{middle:.0f}" - print(f"{name:<16} {reached:>6} {evaluations_text:>11} {error_text(median(errors)):>12}") + error = error_text(median(errors)) + print(f"{name:<16} {reached:>6} {evaluations_text:>11} {error:>12}") print("evaluations: the median of the runs that reach the minimum") # with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate run in diff --git a/examples/penalized2/trace.py b/examples/penalized2/trace.py index 85edaf1d..e6a240f7 100644 --- a/examples/penalized2/trace.py +++ b/examples/penalized2/trace.py @@ -11,7 +11,8 @@ def record_small(): - """Runs CMA-ES with IPOP restarts in 2 dimensions and writes its trace, if ``GENOXIDE_TRACE`` is set.""" + """Runs CMA-ES with IPOP restarts in 2 dimensions and writes its trace, if + ``GENOXIDE_TRACE`` is set.""" path = os.environ.get("GENOXIDE_TRACE") if not path: return diff --git a/examples/quartic/README.md b/examples/quartic/README.md index 04ed5494..c379ed92 100644 --- a/examples/quartic/README.md +++ b/examples/quartic/README.md @@ -66,16 +66,17 @@ With noise, each algorithm runs to the end of its budget, since no target can be ## Output -The first line gives the dimension and the budget. Then a table for the function without noise: a row per algorithm, the -evaluations it had used when its best error first reached each value of the heading, and the best -error it found, to two significant digits. A dash is an error not reached. Then, with noise, a row per algorithm: the best value it found, noise included, and the -quartic at that point without noise. The function is -evaluated with genoxide's portable math, so the runs are the same on every platform, and in Python, -`run` evaluates it in Rust, so both versions print the same. - -[The project page](https://tachsin.gr/projects/genoxide/examples/quartic) plays back another -run: CMA-ES on the function in 2 dimensions without noise, x₁⁴ + 2x₂⁴, so that the -population can be drawn on its contour. It meets the target after 108 evaluations. +The first line gives the dimension and the budget. Then a table for the function without noise: a +row per algorithm, the evaluations it had used when its best error first reached each value of the +heading, and the best error it found, to two significant digits. A dash is an error not reached. +Then, with noise, a row per algorithm: the best value it found, noise included, and the quartic at +that point without noise. The function is evaluated with genoxide's portable math, so the runs are +the same on every platform, and in Python, `run` evaluates it in Rust, so both versions print the +same. + +[The project page](https://tachsin.gr/projects/genoxide/examples/quartic) plays back another run: +CMA-ES on the function in 2 dimensions without noise, x₁⁴ + 2x₂⁴, so that the population can be +drawn on its contour. It meets the target after 108 evaluations. ## Good results diff --git a/examples/quartic/main.py b/examples/quartic/main.py index 6cdd05fe..cc1d52f6 100644 --- a/examples/quartic/main.py +++ b/examples/quartic/main.py @@ -1,11 +1,11 @@ -"""Quartic: minimize De Jong's quartic function in 30 dimensions, without noise and with -the noise of Yao, Liu and Lin, drawn from the genome. +"""Quartic: minimize De Jong's quartic function in 30 dimensions, without noise and with the noise +of Yao, Liu and Lin, drawn from the genome. Compares how fast CMA-ES, with a full and with a diagonal covariance matrix (sep-CMA-ES), differential evolution, particle swarm optimization and a real-coded genetic algorithm close in on -the minimum, 0 at the origin: the evaluations each takes until its error is at most 1, 1e-2, 1e-4, 1e-6 and 1e-8. -The function is genoxide's `problems::Quartic`. Then, with noise, each algorithm's best value and the quartic without noise -there. +the minimum, 0 at the origin: the evaluations each takes until its error is at most 1, 1e-2, 1e-4, +1e-6 and 1e-8. The function is genoxide's `problems::Quartic`. Then, with noise, each algorithm's +best value and the quartic without noise there. With ``GENOXIDE_TRACE=``, it also writes a trace of a run for the plot on the example's page, with trace.py. diff --git a/examples/rotated_hyper_ellipsoid/README.md b/examples/rotated_hyper_ellipsoid/README.md index 1dac5670..55670d39 100644 --- a/examples/rotated_hyper_ellipsoid/README.md +++ b/examples/rotated_hyper_ellipsoid/README.md @@ -30,9 +30,9 @@ Despite its name, it isn't rotated. Gene j appears in the n − j + 1 sums from f(x) = Σⱼ (n − j + 1) xⱼ² ``` -an ellipsoid along the axes, with weights from 30 down to 1: genoxide's axis-parallel ellipsoid -with its genes reversed. Molga and Smutnicki describe Schwefel's problem 1.2, Σᵢ (Σⱼ≤ᵢ xⱼ)², -whose ellipsoids are rotated, but write this formula, which other collections repeat. +an ellipsoid along the axes, with weights from 30 down to 1: genoxide's axis-parallel ellipsoid with +its genes reversed. Molga and Smutnicki describe Schwefel's problem 1.2, Σᵢ (Σⱼ≤ᵢ xⱼ)², whose +ellipsoids are rotated, but write this formula, which other collections repeat. ## What makes it hard @@ -48,8 +48,8 @@ matrix. ## Representation -A `Real` genome of 30 genes, each in [−65.536, 65.536]: the point x itself. The fitness is f(x), -to minimize. The function is genoxide's `problems::RotatedHyperEllipsoid`, and its rotation +A `Real` genome of 30 genes, each in [−65.536, 65.536]: the point x itself. The fitness is f(x), to +minimize. The function is genoxide's `problems::RotatedHyperEllipsoid`, and its rotation `problems::Rotated`, which keeps the bounds and the minimum. ## Algorithm @@ -72,15 +72,16 @@ target of 1e-8, from seed 1: ## Output -The first line gives the dimension and the budget. Then two tables, the function as written and rotated by an orthogonal matrix: a row per algorithm, the -evaluations it had used when its best error first reached each value of the heading, and the best -error it found, to two significant digits. A dash is an error not reached. The function is -evaluated with genoxide's portable math, so the runs are the same on every platform, and in Python, -`run` evaluates it in Rust, so both versions print the same. +The first line gives the dimension and the budget. Then two tables, the function as written and +rotated by an orthogonal matrix: a row per algorithm, the evaluations it had used when its best +error first reached each value of the heading, and the best error it found, to two significant +digits. A dash is an error not reached. The function is evaluated with genoxide's portable math, so +the runs are the same on every platform, and in Python, `run` evaluates it in Rust, so both versions +print the same. -[The project page](https://tachsin.gr/projects/genoxide/examples/rotated-hyper-ellipsoid) plays back another -run: CMA-ES on the function in 2 dimensions, 2x₁² + x₂², rotated with seed 1, so that -the population can be drawn on its contour. It meets the target after 342 evaluations. +[The project page](https://tachsin.gr/projects/genoxide/examples/rotated-hyper-ellipsoid) plays back +another run: CMA-ES on the function in 2 dimensions, 2x₁² + x₂², rotated with seed 1, so that the +population can be drawn on its contour. It meets the target after 342 evaluations. ## Good results @@ -88,7 +89,7 @@ The minimum is 0. As written, sep-CMA-ES reaches 1e-8 first, after 4,886 evaluat (7,140), PSO (27,520) and SHADE (31,900); the genetic algorithm ends at 1.1e-3. Rotated, CMA-ES takes about as long, 7,294 evaluations: its full covariance matrix learns the -ellipsoid's axes, whichever they are. sep-CMA-ES takes 2.5 times as long, 12,180, since its -diagonal matrix can only scale the genes; with a condition number of 30, it still gets there. -SHADE and PSO slow down by two and three and a half times (59,000 and 96,600), and the genetic -algorithm, which recombines genes position by position, ends at 4.2. +ellipsoid's axes, whichever they are. sep-CMA-ES takes 2.5 times as long, 12,180, since its diagonal +matrix can only scale the genes; with a condition number of 30, it still gets there. SHADE and PSO +slow down by two and three and a half times (59,000 and 96,600), and the genetic algorithm, which +recombines genes position by position, ends at 4.2. diff --git a/examples/rotated_hyper_ellipsoid/main.py b/examples/rotated_hyper_ellipsoid/main.py index f174ccef..da72112c 100644 --- a/examples/rotated_hyper_ellipsoid/main.py +++ b/examples/rotated_hyper_ellipsoid/main.py @@ -1,11 +1,11 @@ -"""Rotated hyper-ellipsoid: minimize the "rotated" hyper-ellipsoid in 30 dimensions, which is in fact -axis-parallel, and then the same function truly rotated. +"""Rotated hyper-ellipsoid: minimize the "rotated" hyper-ellipsoid in 30 dimensions, which is in +fact axis-parallel, and then the same function truly rotated. Compares how fast CMA-ES, with a full and with a diagonal covariance matrix (sep-CMA-ES), differential evolution, particle swarm optimization and a real-coded genetic algorithm close in on -the minimum, 0 at the origin: the evaluations each takes until its error is at most 1, 1e-2, 1e-4, 1e-6 and 1e-8. -The function is genoxide's `problems::RotatedHyperEllipsoid`. Then the same on the function rotated by an orthogonal matrix, with genoxide's -`problems::Rotated`. +the minimum, 0 at the origin: the evaluations each takes until its error is at most 1, 1e-2, 1e-4, +1e-6 and 1e-8. The function is genoxide's `problems::RotatedHyperEllipsoid`. Then the same on the +function rotated by an orthogonal matrix, with genoxide's `problems::Rotated`. With ``GENOXIDE_TRACE=``, it also writes a trace of a run for the plot on the example's page, with trace.py. diff --git a/examples/rotated_hyper_ellipsoid/main.rs b/examples/rotated_hyper_ellipsoid/main.rs index f0d06f43..684ea28b 100644 --- a/examples/rotated_hyper_ellipsoid/main.rs +++ b/examples/rotated_hyper_ellipsoid/main.rs @@ -28,7 +28,10 @@ const COLUMNS: [&str; 5] = ["1", "1e-2", "1e-4", "1e-6", "1e-8"]; fn main() -> Result<()> { println!("Rotated hyper-ellipsoid in {DIMENSIONS} dimensions, {BUDGET} evaluations at most"); - compare("Rotated hyper-ellipsoid", &RotatedHyperEllipsoid::new(DIMENSIONS))?; + compare( + "Rotated hyper-ellipsoid", + &RotatedHyperEllipsoid::new(DIMENSIONS), + )?; // the same function rotated by an orthogonal matrix: now the genes interact let rotated = Rotated::new(RotatedHyperEllipsoid::new(DIMENSIONS), 1); compare("Rotated by an orthogonal matrix (seed 1)", &rotated)?; diff --git a/examples/schaffer_f7/README.md b/examples/schaffer_f7/README.md index 6e5199cb..2949075d 100644 --- a/examples/schaffer_f7/README.md +++ b/examples/schaffer_f7/README.md @@ -21,18 +21,18 @@ f(x) = ((1 / (n − 1)) Σᵢ₌₁ⁿ⁻¹ √sᵢ (1 + sin²(50 sᵢ^(1/5)))) each xᵢ in [−100, 100] ``` -Its minimum is 0, at the origin. Here n = 10. Schaffer, Caruana, Eshelman and Das (1989) defined -F7 in two dimensions; their paper couldn't be read. This n-dimensional form is BBOB's f17 (Hansen -et al. 2009), without the transformations BBOB applies to it, and the bounds are those of Schaffer's +Its minimum is 0, at the origin. Here n = 10. Schaffer, Caruana, Eshelman and Das (1989) defined F7 +in two dimensions; their paper couldn't be read. This n-dimensional form is BBOB's f17 (Hansen et +al. 2009), without the transformations BBOB applies to it, and the bounds are those of Schaffer's F6. The CEC 2017 report (Awad et al. 2016, function 19) prints sin for sin², and scales its search space to [−0.5, 0.5]. The original is still to be checked (issue #168). ## What makes it hard -Around the minimum, each pair's term is a cone, √sᵢ, with rings of ripples whose frequency grows -as sᵢ^(1/5): near the origin the rings crowd together, each a local minimum that holds a search -whose steps are smaller than the ring's width. Far from it, the cone dominates and leads inwards. -The terms of neighboring pairs share a gene, so the rings of one pair cut across those of the next. +Around the minimum, each pair's term is a cone, √sᵢ, with rings of ripples whose frequency grows as +sᵢ^(1/5): near the origin the rings crowd together, each a local minimum that holds a search whose +steps are smaller than the ring's width. Far from it, the cone dominates and leads inwards. The +terms of neighboring pairs share a gene, so the rings of one pair cut across those of the next. ## Representation @@ -42,8 +42,8 @@ minimum. ## Algorithm -Five algorithms, each from seeds 1 to 10, with a budget of 10,000 evaluations per dimension, -100,000 per run, and a target of 1e-8: +Five algorithms, each from seeds 1 to 10, with a budget of 10,000 evaluations per dimension, 100,000 +per run, and a target of 1e-8: - CMA-ES (Hansen and Ostermeier, 2001, Evolutionary Computation 9(2): 159-195), which samples a population of 10 from a normal distribution and adapts its mean, its step size and its covariance @@ -60,15 +60,15 @@ Five algorithms, each from seeds 1 to 10, with a budget of 10,000 evaluations pe ## Output -The first line gives the dimension, the seeds and the budget. Then a row per algorithm: how many -of its 10 runs reached the minimum, to within 1e-8, the median of their evaluations (a dash if none -did), and the median of every run's best error, to two significant digits. The function is -evaluated with genoxide's portable math, so the runs are the same on every platform, and in Python, -`run` evaluates it in Rust, so both versions print the same. +The first line gives the dimension, the seeds and the budget. Then a row per algorithm: how many of +its 10 runs reached the minimum, to within 1e-8, the median of their evaluations (a dash if none +did), and the median of every run's best error, to two significant digits. The function is evaluated +with genoxide's portable math, so the runs are the same on every platform, and in Python, `run` +evaluates it in Rust, so both versions print the same. -[The project page](https://tachsin.gr/projects/genoxide/examples/schaffer-f7) plays back another run: -CMA-ES with IPOP restarts on the function in 2 dimensions, so that the population -can be drawn on its contour. It meets the target after 2,070 evaluations. +[The project page](https://tachsin.gr/projects/genoxide/examples/schaffer-f7) plays back another +run: CMA-ES with IPOP restarts on the function in 2 dimensions, so that the population can be drawn +on its contour. It meets the target after 2,070 evaluations. ## Good results diff --git a/examples/schaffer_f7/main.py b/examples/schaffer_f7/main.py index 38b629d5..b5235eed 100644 --- a/examples/schaffer_f7/main.py +++ b/examples/schaffer_f7/main.py @@ -1,10 +1,9 @@ -"""Schaffer F7: minimize Schaffer's F7, rings of ripples around the minimum, in 10 -dimensions. +"""Schaffer F7: minimize Schaffer's F7, rings of ripples around the minimum, in 10 dimensions. -Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), -differential evolution (SHADE), particle swarm optimization and a real-coded genetic algorithm from -10 seeds each, and counts the runs that reach the minimum, 0 at the origin, to within 1e-8. The -function is genoxide's `problems::SchafferF7`, which run evaluates in Rust. +Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), differential +evolution (SHADE), particle swarm optimization and a real-coded genetic algorithm from 10 seeds +each, and counts the runs that reach the minimum, 0 at the origin, to within 1e-8. The function is +genoxide's `problems::SchafferF7`, which run evaluates in Rust. With ``GENOXIDE_TRACE=``, it also writes a trace of a run for the plot on the example's page, with trace.py. @@ -62,7 +61,10 @@ def error_text(error): problem = gx.problems.SchafferF7(DIMENSIONS) minimum = problem.optimum.value -print(f"Schaffer F7 in {DIMENSIONS} dimensions, {SEEDS} seeds, {BUDGET} evaluations at most per run") +print( + f"Schaffer F7 in {DIMENSIONS} dimensions, {SEEDS} seeds, " + f"{BUDGET} evaluations at most per run" +) print("algorithm at min evaluations median error") for name in ALGORITHMS: # the evaluations of the runs that reach the minimum, and every run's best error @@ -78,7 +80,8 @@ def error_text(error): reached = f"{len(evaluations)}/{SEEDS}" middle = median(evaluations) evaluations_text = "-" if middle is None else f"{middle:.0f}" - print(f"{name:<16} {reached:>6} {evaluations_text:>11} {error_text(median(errors)):>12}") + error = error_text(median(errors)) + print(f"{name:<16} {reached:>6} {evaluations_text:>11} {error:>12}") print("evaluations: the median of the runs that reach the minimum") # with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate run in diff --git a/examples/schaffer_f7/main.rs b/examples/schaffer_f7/main.rs index e6cf48da..a849036c 100644 --- a/examples/schaffer_f7/main.rs +++ b/examples/schaffer_f7/main.rs @@ -16,7 +16,7 @@ mod trace; use genoxide::prelude::*; -use genoxide::problems::{SchafferF7, Problem}; +use genoxide::problems::{Problem, SchafferF7}; const DIMENSIONS: usize = 10; const SEEDS: u64 = 10; diff --git a/examples/schaffer_f7/trace.py b/examples/schaffer_f7/trace.py index adc72cac..2c986728 100644 --- a/examples/schaffer_f7/trace.py +++ b/examples/schaffer_f7/trace.py @@ -11,7 +11,8 @@ def record_small(): - """Runs CMA-ES with IPOP restarts in 2 dimensions and writes its trace, if ``GENOXIDE_TRACE`` is set.""" + """Runs CMA-ES with IPOP restarts in 2 dimensions and writes its trace, if + ``GENOXIDE_TRACE`` is set.""" path = os.environ.get("GENOXIDE_TRACE") if not path: return diff --git a/examples/step/README.md b/examples/step/README.md index 683f8869..9e52e5a0 100644 --- a/examples/step/README.md +++ b/examples/step/README.md @@ -61,18 +61,19 @@ target 0, from seed 1: The first line gives the dimension and the budget. Then a table: a row per algorithm, the evaluations it had used when its best error first reached each value of the heading, and the best -error it found, to two significant digits. A dash is an error not reached. The errors are whole numbers here, so the columns are 1000, 100, 10, 1 and 0. The function is -evaluated with genoxide's portable math, so the runs are the same on every platform, and in Python, -`run` evaluates it in Rust, so both versions print the same. +error it found, to two significant digits. A dash is an error not reached. The errors are whole +numbers here, so the columns are 1000, 100, 10, 1 and 0. The function is evaluated with genoxide's +portable math, so the runs are the same on every platform, and in Python, `run` evaluates it in +Rust, so both versions print the same. -[The project page](https://tachsin.gr/projects/genoxide/examples/step) plays back another -run: CMA-ES on the function in 2 dimensions, so that the population can be drawn on its -contour. It reaches the minimum after 114 evaluations. +[The project page](https://tachsin.gr/projects/genoxide/examples/step) plays back another run: +CMA-ES on the function in 2 dimensions, so that the population can be drawn on its contour. It +reaches the minimum after 114 evaluations. ## Good results -The minimum is 0. sep-CMA-ES reaches it after 1,848 evaluations and CMA-ES after 1,862: from a -step size of 60, a third of the range, the plateaus are small next to their steps, and they shrink -their steps no faster than they close in. SHADE reaches it after 11,600 evaluations and the genetic +The minimum is 0. sep-CMA-ES reaches it after 1,848 evaluations and CMA-ES after 1,862: from a step +size of 60, a third of the range, the plateaus are small next to their steps, and they shrink their +steps no faster than they close in. SHADE reaches it after 11,600 evaluations and the genetic algorithm after 25,390. PSO stops at an error of 4, four genes one step from 0: once the swarm has gathered on a plateau, its particles slow down and see no better point near them. diff --git a/examples/step/main.py b/examples/step/main.py index 66e09271..425cc7e7 100644 --- a/examples/step/main.py +++ b/examples/step/main.py @@ -1,10 +1,9 @@ -"""Step: minimize a sphere of flat steps in 30 dimensions, whose gradient is 0 almost -everywhere. +"""Step: minimize a sphere of flat steps in 30 dimensions, whose gradient is 0 almost everywhere. Compares how fast CMA-ES, with a full and with a diagonal covariance matrix (sep-CMA-ES), differential evolution, particle swarm optimization and a real-coded genetic algorithm close in on -the minimum, 0 on the cube [−0.5, 0.5)ⁿ: the evaluations each takes until its error is at most 1000, 100, 10, 1 and 0. -The function is genoxide's `problems::Step`. +the minimum, 0 on the cube [−0.5, 0.5)ⁿ: the evaluations each takes until its error is at most 1000, +100, 10, 1 and 0. The function is genoxide's `problems::Step`. With ``GENOXIDE_TRACE=``, it also writes a trace of a run for the plot on the example's page, with trace.py. diff --git a/examples/sum_of_different_powers/README.md b/examples/sum_of_different_powers/README.md index b73d79fb..0f62a141 100644 --- a/examples/sum_of_different_powers/README.md +++ b/examples/sum_of_different_powers/README.md @@ -21,27 +21,25 @@ minimize: f(x) = Σ |xᵢ|^(i+1), i from 1 to n, each xᵢ in [−1, 1] ``` -Its minimum is 0, at the origin. Here n = 30, so the powers run from 2 to 31. Its origin is -unknown: genoxide takes the definition and the bounds from Molga and Smutnicki (2005, section -2.8), and they're still to be checked against an original (issue #168). An early version of the -CEC 2017 report had it, shifted and rotated, as its function 2. +Its minimum is 0, at the origin. Here n = 30, so the powers run from 2 to 31. Its origin is unknown: +genoxide takes the definition and the bounds from Molga and Smutnicki (2005, section 2.8), and +they're still to be checked against an original (issue #168). ## What makes it hard It's unimodal and separable, and each term is smallest at 0. But the terms differ widely in how much -they matter. Near the minimum, the first gene's term is a parabola, while the thirtieth's, |x|³¹, -is flat: at x₃₀ = 0.5 it's 5·10⁻¹⁰, and an error of 1e-8 allows x₃₀ up to 0.55. A search reaches -small values long before the later genes are near 0, and the flatter terms give it little to -follow. +they matter. Near the minimum, the first gene's term is a parabola, while the thirtieth's, |x|³¹, is +flat: at x₃₀ = 0.5 it's 5·10⁻¹⁰, and an error of 1e-8 allows x₃₀ up to 0.55. A search reaches small +values long before the later genes are near 0, and the flatter terms give it little to follow. -Shifted and rotated, every direction mixes steep and flat terms, and the shapes that the steps -must learn are no longer along the axes. +Shifted and rotated, every direction mixes steep and flat terms, and the shapes that the steps must +learn are no longer along the axes. ## Representation -A `Real` genome of 30 genes, each in [−1, 1]: the point x itself. The fitness is f(x), to -minimize. The function is genoxide's `problems::SumOfDifferentPowers`, which brings its bounds and -its minimum. +A `Real` genome of 30 genes, each in [−1, 1]: the point x itself. The fitness is f(x), to minimize. +The function is genoxide's `problems::SumOfDifferentPowers`, which brings its bounds and its +minimum. ## Algorithm @@ -69,22 +67,22 @@ suites use the function, with their own data; genoxide generates its instances i ## Output -The first line gives the dimension and the budget. Then two tables, the function as it is and shifted and rotated: a row per algorithm, the -evaluations it had used when its best error first reached each value of the heading, and the best -error it found, to two significant digits. A dash is an error not reached. The function is -evaluated with genoxide's portable math, so the runs are the same on every platform, and in Python, -`run` evaluates it in Rust, so both versions print the same. +The first line gives the dimension and the budget. Then two tables, the function as it is and +shifted and rotated: a row per algorithm, the evaluations it had used when its best error first +reached each value of the heading, and the best error it found, to two significant digits. A dash is +an error not reached. The function is evaluated with genoxide's portable math, so the runs are the +same on every platform, and in Python, `run` evaluates it in Rust, so both versions print the same. -[The project page](https://tachsin.gr/projects/genoxide/examples/sum-of-different-powers) plays back another -run: CMA-ES on the function in 2 dimensions, |x₁|² + |x₂|³, so that the population can be +[The project page](https://tachsin.gr/projects/genoxide/examples/sum-of-different-powers) plays back +another run: CMA-ES on the function in 2 dimensions, |x₁|² + |x₂|³, so that the population can be drawn on its contour. It meets the target after 204 evaluations. ## Good results -The minimum is 0. On the function as it is, sep-CMA-ES reaches 1e-8 first, after 2,464 -evaluations, then PSO (4,880), SHADE (6,500), CMA-ES (13,006) and the genetic algorithm (15,922): -every one gets there. The function is separable, and the methods that work a gene at a time, or -learn one scale per gene, are the fastest. +The minimum is 0. On the function as it is, sep-CMA-ES reaches 1e-8 first, after 2,464 evaluations, +then PSO (4,880), SHADE (6,500), CMA-ES (13,006) and the genetic algorithm (15,922): every one gets +there. The function is separable, and the methods that work a gene at a time, or learn one scale per +gene, are the fastest. Shifted and rotated, CMA-ES takes about as long as before, 12,334 evaluations: its full covariance matrix learns the rotation. SHADE needs five times as many, 32,200, and PSO 243,400. sep-CMA-ES diff --git a/examples/sum_of_different_powers/main.py b/examples/sum_of_different_powers/main.py index d47a4e0f..0f4267c2 100644 --- a/examples/sum_of_different_powers/main.py +++ b/examples/sum_of_different_powers/main.py @@ -1,11 +1,12 @@ -"""Sum of different powers: minimize the sum of the genes' absolute values to powers from 2 to 31, in 30 -dimensions: the later the gene, the flatter the function near the minimum. +"""Sum of different powers: minimize the sum of the genes' absolute values to powers from 2 to 31, +in 30 dimensions: the later the gene, the flatter the function near the minimum. Compares how fast CMA-ES, with a full and with a diagonal covariance matrix (sep-CMA-ES), differential evolution, particle swarm optimization and a real-coded genetic algorithm close in on -the minimum, 0 at the origin: the evaluations each takes until its error is at most 1, 1e-2, 1e-4, 1e-6 and 1e-8. -The function is genoxide's `problems::SumOfDifferentPowers`. Then the same on the function shifted and rotated, with genoxide's `problems::Shifted` -and `problems::Rotated`, as the CEC and BBOB suites transform it. +the minimum, 0 at the origin: the evaluations each takes until its error is at most 1, 1e-2, 1e-4, +1e-6 and 1e-8. The function is genoxide's `problems::SumOfDifferentPowers`. Then the same on the +function shifted and rotated, with genoxide's `problems::Shifted` and `problems::Rotated`, as the +CEC and BBOB suites transform it. With ``GENOXIDE_TRACE=``, it also writes a trace of a run for the plot on the example's page, with trace.py. @@ -88,8 +89,10 @@ def compare(name, problem): print(f"Sum of different powers in {DIMENSIONS} dimensions, {BUDGET} evaluations at most") compare("Sum of different powers", gx.problems.SumOfDifferentPowers(DIMENSIONS)) -# the same function, shifted and rotated: the CEC 2017 report's first version had it so -rotated = gx.problems.Rotated(gx.problems.Shifted(gx.problems.SumOfDifferentPowers(DIMENSIONS), seed=1), seed=1) +# the same function, shifted and rotated, as the CEC and BBOB suites transform theirs +rotated = gx.problems.Rotated( + gx.problems.Shifted(gx.problems.SumOfDifferentPowers(DIMENSIONS), seed=1), seed=1 +) compare("Shifted and rotated (seed 1)", rotated) # with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate run in diff --git a/examples/sum_of_different_powers/main.rs b/examples/sum_of_different_powers/main.rs index 7d9e09a3..7ee5c01f 100644 --- a/examples/sum_of_different_powers/main.rs +++ b/examples/sum_of_different_powers/main.rs @@ -28,8 +28,11 @@ const COLUMNS: [&str; 5] = ["1", "1e-2", "1e-4", "1e-6", "1e-8"]; fn main() -> Result<()> { println!("Sum of different powers in {DIMENSIONS} dimensions, {BUDGET} evaluations at most"); - compare("Sum of different powers", &SumOfDifferentPowers::new(DIMENSIONS))?; - // the same function, shifted and rotated: the CEC 2017 report's first version had it so + compare( + "Sum of different powers", + &SumOfDifferentPowers::new(DIMENSIONS), + )?; + // the same function, shifted and rotated, as the CEC and BBOB suites transform theirs let rotated = Rotated::new(Shifted::new(SumOfDifferentPowers::new(DIMENSIONS), 1), 1); compare("Shifted and rotated (seed 1)", &rotated)?; // with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate diff --git a/examples/weierstrass/README.md b/examples/weierstrass/README.md index 00fdb238..9f5df5d7 100644 --- a/examples/weierstrass/README.md +++ b/examples/weierstrass/README.md @@ -24,8 +24,8 @@ each xᵢ in [−0.5, 0.5] Its minimum is 0, at the origin: each gene's sum is at least −Σ aᵏ, reached where every cosine is −1, at the integers, and the second term is −n Σ aᵏ, since every bᵏ is odd. Here n = 10. It's the function F11 of the CEC 2005 report (Suganthan et al. 2005), shifted and rotated there, with its -constants and bounds; Liang et al. (2006) and the CEC 2014 report have the same form, and BBOB's -f16 another one. It's named after Weierstrass's (1872) continuous, nowhere-differentiable function. +constants and bounds; Liang et al. (2006) and the CEC 2014 report have the same form, and BBOB's f16 +another one. It's named after Weierstrass's (1872) continuous, nowhere-differentiable function. ## What makes it hard @@ -42,8 +42,8 @@ minimum. ## Algorithm -Five algorithms, each from seeds 1 to 10, with a budget of 10,000 evaluations per dimension, -100,000 per run, and a target of 1e-8: +Five algorithms, each from seeds 1 to 10, with a budget of 10,000 evaluations per dimension, 100,000 +per run, and a target of 1e-8: - CMA-ES (Hansen and Ostermeier, 2001, Evolutionary Computation 9(2): 159-195), which samples a population of 10 from a normal distribution and adapts its mean, its step size and its covariance @@ -60,15 +60,15 @@ Five algorithms, each from seeds 1 to 10, with a budget of 10,000 evaluations pe ## Output -The first line gives the dimension, the seeds and the budget. Then a row per algorithm: how many -of its 10 runs reached the minimum, to within 1e-8, the median of their evaluations (a dash if none -did), and the median of every run's best error, to two significant digits. The function is -evaluated with genoxide's portable math, so the runs are the same on every platform, and in Python, -`run` evaluates it in Rust, so both versions print the same. +The first line gives the dimension, the seeds and the budget. Then a row per algorithm: how many of +its 10 runs reached the minimum, to within 1e-8, the median of their evaluations (a dash if none +did), and the median of every run's best error, to two significant digits. The function is evaluated +with genoxide's portable math, so the runs are the same on every platform, and in Python, `run` +evaluates it in Rust, so both versions print the same. -[The project page](https://tachsin.gr/projects/genoxide/examples/weierstrass) plays back another run: -CMA-ES with IPOP restarts on the function in 2 dimensions, so that the population -can be drawn on its contour. It meets the target after 816 evaluations. +[The project page](https://tachsin.gr/projects/genoxide/examples/weierstrass) plays back another +run: CMA-ES with IPOP restarts on the function in 2 dimensions, so that the population can be drawn +on its contour. It meets the target after 816 evaluations. ## Good results diff --git a/examples/weierstrass/main.py b/examples/weierstrass/main.py index bc21d151..fa1ede9f 100644 --- a/examples/weierstrass/main.py +++ b/examples/weierstrass/main.py @@ -1,10 +1,9 @@ -"""Weierstrass: minimize the Weierstrass function, continuous but nowhere smooth, in 10 -dimensions. +"""Weierstrass: minimize the Weierstrass function, continuous but nowhere smooth, in 10 dimensions. -Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), -differential evolution (SHADE), particle swarm optimization and a real-coded genetic algorithm from -10 seeds each, and counts the runs that reach the minimum, 0 at the origin, to within 1e-8. The -function is genoxide's `problems::Weierstrass`, which run evaluates in Rust. +Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), differential +evolution (SHADE), particle swarm optimization and a real-coded genetic algorithm from 10 seeds +each, and counts the runs that reach the minimum, 0 at the origin, to within 1e-8. The function is +genoxide's `problems::Weierstrass`, which run evaluates in Rust. With ``GENOXIDE_TRACE=``, it also writes a trace of a run for the plot on the example's page, with trace.py. @@ -62,7 +61,10 @@ def error_text(error): problem = gx.problems.Weierstrass(DIMENSIONS) minimum = problem.optimum.value -print(f"Weierstrass in {DIMENSIONS} dimensions, {SEEDS} seeds, {BUDGET} evaluations at most per run") +print( + f"Weierstrass in {DIMENSIONS} dimensions, {SEEDS} seeds, " + f"{BUDGET} evaluations at most per run" +) print("algorithm at min evaluations median error") for name in ALGORITHMS: # the evaluations of the runs that reach the minimum, and every run's best error @@ -78,7 +80,8 @@ def error_text(error): reached = f"{len(evaluations)}/{SEEDS}" middle = median(evaluations) evaluations_text = "-" if middle is None else f"{middle:.0f}" - print(f"{name:<16} {reached:>6} {evaluations_text:>11} {error_text(median(errors)):>12}") + error = error_text(median(errors)) + print(f"{name:<16} {reached:>6} {evaluations_text:>11} {error:>12}") print("evaluations: the median of the runs that reach the minimum") # with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate run in diff --git a/examples/weierstrass/main.rs b/examples/weierstrass/main.rs index bcab3e7e..0c469692 100644 --- a/examples/weierstrass/main.rs +++ b/examples/weierstrass/main.rs @@ -16,7 +16,7 @@ mod trace; use genoxide::prelude::*; -use genoxide::problems::{Weierstrass, Problem}; +use genoxide::problems::{Problem, Weierstrass}; const DIMENSIONS: usize = 10; const SEEDS: u64 = 10; diff --git a/examples/weierstrass/trace.py b/examples/weierstrass/trace.py index 7c8650cf..3f6ba7ff 100644 --- a/examples/weierstrass/trace.py +++ b/examples/weierstrass/trace.py @@ -11,7 +11,8 @@ def record_small(): - """Runs CMA-ES with IPOP restarts in 2 dimensions and writes its trace, if ``GENOXIDE_TRACE`` is set.""" + """Runs CMA-ES with IPOP restarts in 2 dimensions and writes its trace, if + ``GENOXIDE_TRACE`` is set.""" path = os.environ.get("GENOXIDE_TRACE") if not path: return diff --git a/python/genoxide/problems/__init__.py b/python/genoxide/problems/__init__.py index a38d3b08..4423877e 100644 --- a/python/genoxide/problems/__init__.py +++ b/python/genoxide/problems/__init__.py @@ -1471,7 +1471,9 @@ class RotatedHyperEllipsoid(_Scalable): def _wrapped(name: str, problem: Any) -> dict[str, Any]: """The description of the problem a wrapper wraps.""" if not isinstance(problem, Problem): - raise ValueError(f"{name}.problem is a single-objective problem of genoxide.problems, not {problem!r}") + raise ValueError( + f"{name}.problem is a single-objective problem of genoxide.problems, not {problem!r}" + ) return problem._describe() diff --git a/python/tests/test_problems.py b/python/tests/test_problems.py index 347efb9f..c467820b 100644 --- a/python/tests/test_problems.py +++ b/python/tests/test_problems.py @@ -397,8 +397,10 @@ def test_shifted_and_rotated_problems(): x = np.array([0.5, -1.0, 2.0, 0.0, 1.5]) assert shifted(x) == gx.problems.Rastrigin(5)(x - shifted.shift) # the same seed, the same shift, as in Rust; another, another - assert np.array_equal(gx.problems.Shifted(gx.problems.Sphere(2), 1).shift, [46.23653733062747, 24.878588135984046]) - assert not np.array_equal(gx.problems.Shifted(gx.problems.Rastrigin(5), 2).shift, shifted.shift) + expected = [46.23653733062747, 24.878588135984046] + assert np.array_equal(gx.problems.Shifted(gx.problems.Sphere(2), 1).shift, expected) + other = gx.problems.Shifted(gx.problems.Rastrigin(5), 2) + assert not np.array_equal(other.shift, shifted.shift) # CEC 2005's F10: rotated about the shifted minimum rotated = gx.problems.Rotated(shifted, seed=1) matrix = rotated.matrix @@ -408,7 +410,8 @@ def test_shifted_and_rotated_problems(): assert np.array_equal(rotated.optimum.solutions[0], shifted.shift) y = shifted.shift + matrix @ (x - shifted.shift) assert rotated(x) == pytest.approx(shifted(y), rel=1e-12) - assert np.array_equal(gx.problems.Rotated(gx.problems.Sphere(2), 1).matrix.ravel(), [-0.9735519448992744, 0.22846577551756006, -0.2284657755175601, -0.9735519448992744]) + expected = [-0.9735519448992744, 0.22846577551756006, -0.2284657755175601, -0.9735519448992744] + assert np.array_equal(gx.problems.Rotated(gx.problems.Sphere(2), 1).matrix.ravel(), expected) # constrained problems shift too, with their violation: at G06's minimum, both constraints # are active, and x − o rounds to a point outside one of them by 6e-14 g06 = gx.problems.Shifted(gx.problems.cec2006.G06(), seed=3) @@ -425,10 +428,16 @@ def test_shifted_and_rotated_problems(): @pytest.mark.parametrize( "problem, message", [ - (gx.problems.Shifted(lambda x: 0.0, seed=1), "Shifted.problem is a single-objective problem of genoxide.problems"), + ( + gx.problems.Shifted(lambda x: 0.0, seed=1), + "Shifted.problem is a single-objective problem of genoxide.problems", + ), (gx.problems.Rotated(gx.problems.Sphere(2), seed=-1), "Rotated.seed is at least 0, not -1"), - (gx.problems.Shifted(gx.problems.Zdt1(), seed=1), "Shifted.problem is a single-objective problem"), - (gx.problems.Rotated(gx.problems.engineering.GearTrain(), seed=1), "Rotated wraps a single-objective problem on real genomes"), + (gx.problems.Shifted(gx.problems.Zdt1(), seed=1), "Shifted.problem is a single-objective"), + ( + gx.problems.Rotated(gx.problems.engineering.GearTrain(), seed=1), + "Rotated wraps a single-objective problem on real genomes", + ), (gx.problems.Quartic(3, noisy=1), "Quartic.noisy is True or False, not 1"), ], ) @@ -459,7 +468,10 @@ def test_sizes(): (gx.problems.Powell(6), "Powell.dimensions is a multiple of 4, not 6"), (gx.problems.BentCigar(1), "BentCigar.dimensions is at least 2, not 1"), (gx.problems.SchafferF7(1), "SchafferF7.dimensions is at least 2, not 1"), - (gx.problems.Shifted(gx.problems.Sphere(0), seed=1), "Sphere.dimensions is at least 1, not 0"), + ( + gx.problems.Shifted(gx.problems.Sphere(0), seed=1), + "Sphere.dimensions is at least 1, not 0", + ), (gx.problems.Sphere(2.0), "Sphere.dimensions is a whole number"), (gx.problems.Sphere(2**40), "Sphere.dimensions is at most 16777216, not 1099511627776"), ], diff --git a/src/problems/transform.rs b/src/problems/transform.rs index 478b2851..3ae2600b 100644 --- a/src/problems/transform.rs +++ b/src/problems/transform.rs @@ -61,7 +61,9 @@ fn moved_optimum( /// [`HighConditionedElliptic`](super::HighConditionedElliptic), but not for a function whose /// minimum is only the lowest in its box: shifted, [`Schwefel2_26`](super::Schwefel2_26) brings /// lower values from outside its box into it. The name and the reference are the wrapped -/// problem's, and so is the constraint violation of a constrained problem, at `x − o`. +/// problem's, and so is the constraint violation of a constrained problem, at `x − o`; rounding +/// in `x − o` can put a shifted solution a few ulps outside a constraint that's active there +/// (6·10⁻¹⁴ at [`G06`](super::cec2006::G06)'s minimum with seed 3). /// /// ``` /// use genoxide::genome::Representation; From eb4559c431465a52130c994fb9dcf56dbac3d533 Mon Sep 17 00:00:00 2001 From: Someguy Date: Thu, 1 Oct 2026 17:22:58 +0300 Subject: [PATCH 08/16] fix(examples): no clone of the problems that are Copy in batch 10b's traces --- examples/bent_cigar/trace.rs | 2 +- examples/buche_rastrigin/trace.rs | 2 +- examples/happy_cat/trace.rs | 2 +- examples/hg_bat/trace.rs | 2 +- examples/katsuura/trace.rs | 2 +- examples/non_continuous_rastrigin/trace.rs | 2 +- examples/penalized1/trace.rs | 2 +- examples/penalized2/trace.rs | 2 +- examples/quartic/trace.rs | 2 +- examples/schaffer_f7/trace.rs | 2 +- examples/step/trace.rs | 2 +- examples/sum_of_different_powers/trace.rs | 2 +- examples/weierstrass/trace.rs | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/examples/bent_cigar/trace.rs b/examples/bent_cigar/trace.rs index 398eb590..c321d089 100644 --- a/examples/bent_cigar/trace.rs +++ b/examples/bent_cigar/trace.rs @@ -23,7 +23,7 @@ pub fn record_small() -> Result<()> { .seed(1) .build()?; let mut frames = Frames::new(100); - Engine::new(cmaes, problem.clone()) + Engine::new(cmaes, problem) .stop_when(Stop::target(minimum + 1e-8).or(Stop::evaluations(budget))) .on_generation(|snapshot| { let population = snapshot.population().iter().map(|x| &x.genome()[..]); diff --git a/examples/buche_rastrigin/trace.rs b/examples/buche_rastrigin/trace.rs index 3e04e21c..ca6b81ff 100644 --- a/examples/buche_rastrigin/trace.rs +++ b/examples/buche_rastrigin/trace.rs @@ -24,7 +24,7 @@ pub fn record_small() -> Result<()> { .seed(1) .build()?; let mut frames = Frames::new(100); - Engine::new(cmaes, problem.clone()) + Engine::new(cmaes, problem) .stop_when(Stop::target(minimum + 1e-8).or(Stop::evaluations(budget))) .on_generation(|snapshot| { let population = snapshot.population().iter().map(|x| &x.genome()[..]); diff --git a/examples/happy_cat/trace.rs b/examples/happy_cat/trace.rs index 36c337b8..cd704825 100644 --- a/examples/happy_cat/trace.rs +++ b/examples/happy_cat/trace.rs @@ -24,7 +24,7 @@ pub fn record_small() -> Result<()> { .seed(1) .build()?; let mut frames = Frames::new(100); - Engine::new(cmaes, problem.clone()) + Engine::new(cmaes, problem) .stop_when(Stop::target(minimum + 1e-8).or(Stop::evaluations(budget))) .on_generation(|snapshot| { let population = snapshot.population().iter().map(|x| &x.genome()[..]); diff --git a/examples/hg_bat/trace.rs b/examples/hg_bat/trace.rs index 755266ef..c3267ed4 100644 --- a/examples/hg_bat/trace.rs +++ b/examples/hg_bat/trace.rs @@ -24,7 +24,7 @@ pub fn record_small() -> Result<()> { .seed(1) .build()?; let mut frames = Frames::new(100); - Engine::new(cmaes, problem.clone()) + Engine::new(cmaes, problem) .stop_when(Stop::target(minimum + 1e-8).or(Stop::evaluations(budget))) .on_generation(|snapshot| { let population = snapshot.population().iter().map(|x| &x.genome()[..]); diff --git a/examples/katsuura/trace.rs b/examples/katsuura/trace.rs index fd3ef74a..b0ea38c7 100644 --- a/examples/katsuura/trace.rs +++ b/examples/katsuura/trace.rs @@ -24,7 +24,7 @@ pub fn record_small() -> Result<()> { .seed(1) .build()?; let mut frames = Frames::new(100); - Engine::new(cmaes, problem.clone()) + Engine::new(cmaes, problem) .stop_when(Stop::target(minimum + 1e-8).or(Stop::evaluations(budget))) .on_generation(|snapshot| { let population = snapshot.population().iter().map(|x| &x.genome()[..]); diff --git a/examples/non_continuous_rastrigin/trace.rs b/examples/non_continuous_rastrigin/trace.rs index 28f48292..c6ad6768 100644 --- a/examples/non_continuous_rastrigin/trace.rs +++ b/examples/non_continuous_rastrigin/trace.rs @@ -24,7 +24,7 @@ pub fn record_small() -> Result<()> { .seed(1) .build()?; let mut frames = Frames::new(100); - Engine::new(cmaes, problem.clone()) + Engine::new(cmaes, problem) .stop_when(Stop::target(minimum + 1e-8).or(Stop::evaluations(budget))) .on_generation(|snapshot| { let population = snapshot.population().iter().map(|x| &x.genome()[..]); diff --git a/examples/penalized1/trace.rs b/examples/penalized1/trace.rs index 49f36764..cf487b9f 100644 --- a/examples/penalized1/trace.rs +++ b/examples/penalized1/trace.rs @@ -24,7 +24,7 @@ pub fn record_small() -> Result<()> { .seed(1) .build()?; let mut frames = Frames::new(100); - Engine::new(cmaes, problem.clone()) + Engine::new(cmaes, problem) .stop_when(Stop::target(minimum + 1e-8).or(Stop::evaluations(budget))) .on_generation(|snapshot| { let population = snapshot.population().iter().map(|x| &x.genome()[..]); diff --git a/examples/penalized2/trace.rs b/examples/penalized2/trace.rs index dd3c1eeb..175ce007 100644 --- a/examples/penalized2/trace.rs +++ b/examples/penalized2/trace.rs @@ -24,7 +24,7 @@ pub fn record_small() -> Result<()> { .seed(1) .build()?; let mut frames = Frames::new(100); - Engine::new(cmaes, problem.clone()) + Engine::new(cmaes, problem) .stop_when(Stop::target(minimum + 1e-8).or(Stop::evaluations(budget))) .on_generation(|snapshot| { let population = snapshot.population().iter().map(|x| &x.genome()[..]); diff --git a/examples/quartic/trace.rs b/examples/quartic/trace.rs index b31119cf..990164b7 100644 --- a/examples/quartic/trace.rs +++ b/examples/quartic/trace.rs @@ -23,7 +23,7 @@ pub fn record_small() -> Result<()> { .seed(1) .build()?; let mut frames = Frames::new(100); - Engine::new(cmaes, problem.clone()) + Engine::new(cmaes, problem) .stop_when(Stop::target(minimum + 1e-8).or(Stop::evaluations(budget))) .on_generation(|snapshot| { let population = snapshot.population().iter().map(|x| &x.genome()[..]); diff --git a/examples/schaffer_f7/trace.rs b/examples/schaffer_f7/trace.rs index 0283321e..0282b5fa 100644 --- a/examples/schaffer_f7/trace.rs +++ b/examples/schaffer_f7/trace.rs @@ -24,7 +24,7 @@ pub fn record_small() -> Result<()> { .seed(1) .build()?; let mut frames = Frames::new(100); - Engine::new(cmaes, problem.clone()) + Engine::new(cmaes, problem) .stop_when(Stop::target(minimum + 1e-8).or(Stop::evaluations(budget))) .on_generation(|snapshot| { let population = snapshot.population().iter().map(|x| &x.genome()[..]); diff --git a/examples/step/trace.rs b/examples/step/trace.rs index 290ac863..adc6381e 100644 --- a/examples/step/trace.rs +++ b/examples/step/trace.rs @@ -23,7 +23,7 @@ pub fn record_small() -> Result<()> { .seed(1) .build()?; let mut frames = Frames::new(100); - Engine::new(cmaes, problem.clone()) + Engine::new(cmaes, problem) .stop_when(Stop::target(minimum + 1e-8).or(Stop::evaluations(budget))) .on_generation(|snapshot| { let population = snapshot.population().iter().map(|x| &x.genome()[..]); diff --git a/examples/sum_of_different_powers/trace.rs b/examples/sum_of_different_powers/trace.rs index d75f15fa..2ea489ed 100644 --- a/examples/sum_of_different_powers/trace.rs +++ b/examples/sum_of_different_powers/trace.rs @@ -23,7 +23,7 @@ pub fn record_small() -> Result<()> { .seed(1) .build()?; let mut frames = Frames::new(100); - Engine::new(cmaes, problem.clone()) + Engine::new(cmaes, problem) .stop_when(Stop::target(minimum + 1e-8).or(Stop::evaluations(budget))) .on_generation(|snapshot| { let population = snapshot.population().iter().map(|x| &x.genome()[..]); diff --git a/examples/weierstrass/trace.rs b/examples/weierstrass/trace.rs index 930751af..ff8374a1 100644 --- a/examples/weierstrass/trace.rs +++ b/examples/weierstrass/trace.rs @@ -24,7 +24,7 @@ pub fn record_small() -> Result<()> { .seed(1) .build()?; let mut frames = Frames::new(100); - Engine::new(cmaes, problem.clone()) + Engine::new(cmaes, problem) .stop_when(Stop::target(minimum + 1e-8).or(Stop::evaluations(budget))) .on_generation(|snapshot| { let population = snapshot.population().iter().map(|x| &x.genome()[..]); From 7bcbf537ab72b990a2fb19105ff43578f4bda555 Mon Sep 17 00:00:00 2001 From: Someguy Date: Thu, 1 Oct 2026 21:48:28 +0300 Subject: [PATCH 09/16] docs: the feature list keeps main's gradients and constraint values next to batch 10b's functions --- docs/features.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/features.md b/docs/features.md index 9a2217c5..97696cf2 100644 --- a/docs/features.md +++ b/docs/features.md @@ -66,8 +66,8 @@ What genoxide has on main; [docs.rs](https://docs.rs/genoxide) documents the lat - **First-order methods** (`FirstOrder`): steps along the gradient without a line search, for smooth problems with up to millions of variables, by a `first_order::Step` rule: gradient descent, Polyak's momentum, Nesterov's accelerated gradient (Sutskever et al.'s form), Adam (Kingma and Ba's Algorithm 1, with its bias correction) and AdamW (Loshchilov and Hutter's decoupled weight decay, Algorithm 2). One gradient per generation, supplied or by finite differences in the same round; points projected onto the bounds; convergence by the projected gradient or the step (`StopReason::Converged`); a learning rate and a schedule multiplier set by `control`, for schedules; an invalid point stepped back from; random restarts; re-evaluation that keeps the velocity and Adam's averages. O(n) memory and work per step, and no allocation after the first step (tested at a million genes); in Python (`gx.FirstOrder`, with `gradient=`) and the `genoxide` program (`type = "first-order"`, with the gradient protocol). - **MMA and GCMMA** (`Mma`): Svanberg's method of moving asymptotes and its globally convergent form, for smooth problems with very many variables (millions) and few inequality constraints, from the gradients of the score and of every constraint: convex separable approximations with moving asymptotes and the notes' default constants, solved through their dual in the constraints' multipliers (O(n·m) per iteration, no n × n matrix, nothing allocated after the first iteration, the sums in fixed chunks, optionally in parallel with the same bits); artificial variables that keep every subproblem feasible; GCMMA's inner iterations for convergence from any start; convergence by the KKT residual or the step (`StopReason::Converged`); a restoration step onto the feasible side of the active constraints at the end; multipliers, asymptotes and the KKT residual to read, re-evaluation and checkpoints. Reproduces the 2002 paper's table 8.1 and the 1987 paper's cantilever beam. - **Continuation** (`Continuation`, the `Continue` trait): a local method run through stages of one problem, a parameter of the fitness function changed between them by a closure (a smoothing, a p-norm's p, a penalty weight), each stage ending when the method has converged or after its budget of generations, and the run only after the last (`StopReason::Converged`). Each stage starts by evaluating the point again on the changed function, with the method's state kept (`Keep::State`: Adam's averages and step count, MMA's asymptotes, a Nelder-Mead simplex, a CMA-ES distribution; L-BFGS-B's pairs optionally) or only the point (`Keep::Point`). Each stage's generations, evaluations, best value and end reported by a callback and after the run; checkpoints that resume in their stage; nothing allocated per step (tested at a million genes); in Python (`gx.Continuation` around `FirstOrder`, `Lbfgsb` or `Mma`, with Python stage callbacks). -- **Test problems** (`problems`): Sphere, the axis-parallel ellipsoid, Schwefel 1.2 and 2.26, Rastrigin, Rosenbrock, Ackley, Griewank, Levy, Zakharov, Styblinski-Tang, Michalewicz, Himmelblau, Branin, Goldstein-Price, the six-hump camel, Hartmann's functions in 3 and 6 dimensions, Shekel's with 5, 7 and 10 wells, Easom, the eggholder, Schaffer's F6, Schwefel 2.21 and 2.22, Dixon-Price, Trid, Powell's singular function, Beale, Booth, Matyas, Bohachevsky's three functions, the three-hump camel, Langermann, Shekel's foxholes, Kowalik, the sum of different powers, the step function, the quartic (with or without noise), Yao, Liu and Lin's two penalized functions, the high-conditioned elliptic, the bent cigar, the discus, BBOB's different powers, Büche-Rastrigin, the non-continuous Rastrigin, Weierstrass, Katsuura, HappyCat, HGBat, Schaffer's F7 and the rotated hyper-ellipsoid, each with its bounds, known optimum (or best known, for those found numerically) and reference, in Rust and Python; and shift and rotation wrappers, generated from a seed, for CEC- and BBOB-style instances of any of them. -- **Constrained test problems:** CEC 2006's g01-g24 (`problems::cec2006`), and the engineering design problems (`problems::engineering`): the welded beam in two forms, the pressure vessel, the tension/compression spring, the speed reducer, the gear train (integer), the three-bar truss, the cantilever beam and the car side impact, each with its optimum or best known solution and references, in Rust and Python. +- **Test problems** (`problems`): Sphere, the axis-parallel ellipsoid, Schwefel 1.2 and 2.26, Rastrigin, Rosenbrock, Ackley, Griewank, Levy, Zakharov, Styblinski-Tang, Michalewicz, Himmelblau, Branin, Goldstein-Price, the six-hump camel, Hartmann's functions in 3 and 6 dimensions, Shekel's with 5, 7 and 10 wells, Easom, the eggholder, Schaffer's F6, Schwefel 2.21 and 2.22, Dixon-Price, Trid, Powell's singular function, Beale, Booth, Matyas, Bohachevsky's three functions, the three-hump camel, Langermann, Shekel's foxholes, Kowalik, the sum of different powers, the step function, the quartic (with or without noise), Yao, Liu and Lin's two penalized functions, the high-conditioned elliptic, the bent cigar, the discus, BBOB's different powers, Büche-Rastrigin, the non-continuous Rastrigin, Weierstrass, Katsuura, HappyCat, HGBat, Schaffer's F7 and the rotated hyper-ellipsoid, each with its bounds, known optimum (or best known, for those found numerically) and reference, in Rust and Python, and the analytic gradient of the smooth ones up to Kowalik and Powell (all but the eggholder and Schwefel 2.21 and 2.22, which aren't differentiable; not yet the CEC- and BBOB-style ones); and shift and rotation wrappers, generated from a seed, for CEC- and BBOB-style instances of any of them. +- **Constrained test problems:** CEC 2006's g01-g24 (`problems::cec2006`), and the engineering design problems (`problems::engineering`): the welded beam in two forms, the pressure vessel, the tension/compression spring, the speed reducer, the gear train (integer), the three-bar truss, the cantilever beam and the car side impact, each with its optimum or best known solution and references, in Rust and Python. Those with inequalities only give their constraints' values one by one to the algorithms that use them. ## Multi-objective From 25e00694e98bad06e0df72e5a7a18490f5e582c5 Mon Sep 17 00:00:00 2001 From: tachsin Date: Fri, 2 Oct 2026 15:26:12 +0300 Subject: [PATCH 10/16] =?UTF-8?q?docs(problems):=20Shifted's=20[=E2=88=928?= =?UTF-8?q?0,=2080]=20is=20CEC=202013,=202014=20and=202017's;=20CEC=202005?= =?UTF-8?q?'s=20shifts=20spread=20wider?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/problems/transform.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/problems/transform.rs b/src/problems/transform.rs index 3ae2600b..9c91a3af 100644 --- a/src/problems/transform.rs +++ b/src/problems/transform.rs @@ -52,8 +52,9 @@ fn moved_optimum( /// /// The shift moves the first solution of the wrapped problem's optimum (the center of the box if /// the optimum isn't known) to a point drawn uniformly from the middle 80% of each gene's range: -/// the CEC 2005, 2013, 2014 and 2017 suites draw their shifted optima from [−80, 80]ⁿ in -/// [−100, 100]ⁿ, and BBOB from [−4, 4]ⁿ in [−5, 5]ⁿ. The bounds are the wrapped problem's. +/// the CEC 2013, 2014 and 2017 suites draw their shifted optima from [−80, 80]ⁿ in +/// [−100, 100]ⁿ, and BBOB from [−4, 4]ⁿ in [−5, 5]ⁿ (CEC 2005's data files spread theirs over +/// about 90% of each range). The bounds are the wrapped problem's. /// /// The optimum keeps its value, and its solutions are shifted (those that the shift moves out of /// the box are dropped). That holds when the wrapped problem's minimum is its minimum over all of From b88f8c0022ebeab0bbd569c494268a1d82e42400 Mon Sep 17 00:00:00 2001 From: tachsin Date: Fri, 2 Oct 2026 15:27:02 +0300 Subject: [PATCH 11/16] docs(problems): HGBat's groove lies on two spheres through the origin, not a cone --- examples/hg_bat/README.md | 6 +++--- examples/hg_bat/main.py | 2 +- examples/hg_bat/main.rs | 2 +- python/genoxide/problems/__init__.py | 2 +- src/problems/classic.rs | 3 ++- 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/examples/hg_bat/README.md b/examples/hg_bat/README.md index 0a812a68..2e19546e 100644 --- a/examples/hg_bat/README.md +++ b/examples/hg_bat/README.md @@ -27,9 +27,9 @@ gives no other source; it's usually credited to Beyer and Finck too, whose paper ## What makes it hard -The first term is 0 where ‖x‖² = |Σ xᵢ|, a curved surface through the origin and (−1, …, −1), and -rises as a square root away from it: a groove whose floor curves around to the minimum, with a -gentle slope along it. As on HappyCat, a search falls into the groove at once, then has to follow a +The first term is 0 where ‖x‖² = |Σ xᵢ|, on two spheres through the origin, one of them through +(−1, …, −1), and rises as a square root away from them: a groove whose floor curves around to the +minimum, with a gentle slope along it. As on HappyCat, a search falls into the groove at once, then has to follow a curving direction with small steps across it and large ones along it. ## Representation diff --git a/examples/hg_bat/main.py b/examples/hg_bat/main.py index 576f4972..6c34a3f0 100644 --- a/examples/hg_bat/main.py +++ b/examples/hg_bat/main.py @@ -1,4 +1,4 @@ -"""HGBat: minimize HGBat, HappyCat's relative with a groove along a cone, in 10 dimensions. +"""HGBat: minimize HGBat, HappyCat's relative with a groove along two spheres, in 10 dimensions. Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), differential evolution (SHADE), particle swarm optimization and a real-coded genetic algorithm from 10 seeds diff --git a/examples/hg_bat/main.rs b/examples/hg_bat/main.rs index d41dbda9..c539bbfe 100644 --- a/examples/hg_bat/main.rs +++ b/examples/hg_bat/main.rs @@ -1,4 +1,4 @@ -//! HGBat: minimize HGBat, HappyCat's relative with a groove along a cone, in 10 +//! HGBat: minimize HGBat, HappyCat's relative with a groove along two spheres, in 10 //! dimensions. //! //! Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), diff --git a/python/genoxide/problems/__init__.py b/python/genoxide/problems/__init__.py index 4423877e..b5dc92e4 100644 --- a/python/genoxide/problems/__init__.py +++ b/python/genoxide/problems/__init__.py @@ -1419,7 +1419,7 @@ class HappyCat(_Scalable): @dataclass(frozen=True) class HgBat(_Scalable): """HGBat, ``|(Σ xᵢ²)² − (Σ xᵢ)²|^(1/2) + (½ Σ xᵢ² + Σ xᵢ) / n + ½``: HappyCat's relative, - with a groove along a cone. + with a groove along two spheres through the origin, where ``‖x‖² = |Σ xᵢ|``. Bounds [-5, 5]ⁿ; minimum 0 at (−1, …, −1), the only one. ``dimensions`` is at least 1. diff --git a/src/problems/classic.rs b/src/problems/classic.rs index 53c45a7c..b72af380 100644 --- a/src/problems/classic.rs +++ b/src/problems/classic.rs @@ -3281,7 +3281,8 @@ scalable_problem!( scalable!( /// HGBat, `|(Σ xᵢ²)² − (Σ xᵢ)²|^(1/2) + (½ Σ xᵢ² + Σ xᵢ) / n + ½`: HappyCat's relative, whose - /// first term is 0 on a cone, `‖x‖² = |Σ xᵢ|`, instead of a sphere. + /// first term is 0 where `‖x‖² = |Σ xᵢ|`: on two spheres of radius √n / 2 through the origin, + /// centered at ±(½, …, ½), instead of one. /// /// Bounds [−5, 5]ⁿ; minimum 0 at (−1, …, −1), the only one: the second part is /// `Σ (xᵢ + 1)² / (2n)`, 0 only there, where the first is 0 too. 30 dimensions by default. From 2a8c33cdba3464b26772463adebaf837a77667e4 Mon Sep 17 00:00:00 2001 From: tachsin Date: Fri, 2 Oct 2026 15:28:03 +0300 Subject: [PATCH 12/16] docs(problems): Weierstrass's and Katsuura's finite sums are differentiable, almost everywhere for Katsuura --- examples/katsuura/README.md | 8 ++++---- examples/weierstrass/README.md | 8 ++++---- examples/weierstrass/main.py | 2 +- examples/weierstrass/main.rs | 3 +-- python/genoxide/problems/__init__.py | 5 +++-- src/problems/classic.rs | 8 +++++--- 6 files changed, 18 insertions(+), 16 deletions(-) diff --git a/examples/katsuura/README.md b/examples/katsuura/README.md index f51573aa..e7ca9c46 100644 --- a/examples/katsuura/README.md +++ b/examples/katsuura/README.md @@ -30,10 +30,10 @@ Monthly 98(5): 411-416, not read), without BBOB's rotation and scaling, and its ## What makes it hard -Each factor is a continuous, nowhere-differentiable function of its gene, rugged at every scale down -to 2⁻³², and the product couples the genes. The landscape is highly repetitive, with global minima -on a grid of spacing 1/2 and local minima everywhere between: a search that has found a good region -gains little from its neighborhood. +Each factor is a continuous function of its gene, with kinks at every multiple of 2⁻³³, rugged at +every scale down to 2⁻³², and the product couples the genes. The landscape is highly repetitive, +with global minima on a grid of spacing 1/2 and local minima everywhere between: a search that has +found a good region gains little from its neighborhood. The grid of global minima includes the bounds, ±5. A search that pushes genes onto the bounds, as PSO does when a particle would leave the box and stops at the bound, lands on global minima without diff --git a/examples/weierstrass/README.md b/examples/weierstrass/README.md index 9f5df5d7..96a0c24a 100644 --- a/examples/weierstrass/README.md +++ b/examples/weierstrass/README.md @@ -1,7 +1,7 @@ --- title: Weierstrass category: continuous -summary: Minimize the Weierstrass function, continuous but nowhere smooth, in 10 dimensions, with CMA-ES without and with restarts, DE, PSO and a GA from 10 seeds each. +summary: Minimize the Weierstrass function, rippled at every scale, in 10 dimensions, with CMA-ES without and with restarts, DE, PSO and a GA from 10 seeds each. reference: "Suganthan, P. N., Hansen, N., Liang, J. J., Deb, K., Chen, Y.-P., Auger, A. and Tiwari, S. (2005). Problem Definitions and Evaluation Criteria for the CEC 2005 Special Session on Real-Parameter Optimization. Nanyang Technological University and KanGAL report 2005005." reference_url: "https://github.com/P-N-Suganthan/CEC2005" optimum: "0 (at the origin)" @@ -30,9 +30,9 @@ another one. It's named after Weierstrass's (1872) continuous, nowhere-different ## What makes it hard Each gene's sum is a fractal: ripples on ripples, each three times faster and half as high as the -last, down to 3²⁰ ≈ 3.5·10⁹ periods per unit. The function is continuous but differentiable only on -a set of points, and has local minima at every scale. A search that has found the right valley at -one scale still has to find it at every finer one. +last, down to 3²⁰ ≈ 3.5·10⁹ periods per unit. The sum stops there, so the function is smooth, but +it's steep and has local minima at every scale. A search that has found the right valley at one +scale still has to find it at every finer one. ## Representation diff --git a/examples/weierstrass/main.py b/examples/weierstrass/main.py index fa1ede9f..1651bd5d 100644 --- a/examples/weierstrass/main.py +++ b/examples/weierstrass/main.py @@ -1,4 +1,4 @@ -"""Weierstrass: minimize the Weierstrass function, continuous but nowhere smooth, in 10 dimensions. +"""Weierstrass: minimize the Weierstrass function, rippled at every scale, in 10 dimensions. Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), differential evolution (SHADE), particle swarm optimization and a real-coded genetic algorithm from 10 seeds diff --git a/examples/weierstrass/main.rs b/examples/weierstrass/main.rs index 0c469692..1ab1fa66 100644 --- a/examples/weierstrass/main.rs +++ b/examples/weierstrass/main.rs @@ -1,5 +1,4 @@ -//! Weierstrass: minimize the Weierstrass function, continuous but nowhere smooth, in 10 -//! dimensions. +//! Weierstrass: minimize the Weierstrass function, rippled at every scale, in 10 dimensions. //! //! Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), //! differential evolution (SHADE), particle swarm optimization and a real-coded genetic algorithm diff --git a/python/genoxide/problems/__init__.py b/python/genoxide/problems/__init__.py index b5dc92e4..a66725d3 100644 --- a/python/genoxide/problems/__init__.py +++ b/python/genoxide/problems/__init__.py @@ -1366,7 +1366,8 @@ class NonContinuousRastrigin(_Scalable): @dataclass(frozen=True) class Weierstrass(_Scalable): """The Weierstrass function, ``Σᵢ Σₖ aᵏ cos(2π bᵏ (xᵢ + 0.5)) − n Σₖ aᵏ cos(π bᵏ)`` with - a = 0.5, b = 3 and k from 0 to 20: continuous, differentiable only on a set of points. + a = 0.5, b = 3 and k from 0 to 20: smooth, but rippled at every scale down to 3⁻²⁰ of the + first ripple's period. Bounds [-0.5, 0.5]ⁿ; minimum 0 at the origin. ``dimensions`` is at least 1. @@ -1384,7 +1385,7 @@ class Weierstrass(_Scalable): class Katsuura(_Scalable): """Katsuura's function, ``(10 / n²) Πᵢ (1 + i Σⱼ₌₁³² |2ʲxᵢ − round(2ʲxᵢ)| / 2ʲ)^(10 / n^1.2) − 10 / n²``: rugged - everywhere, continuous but nowhere differentiable. + everywhere, continuous, with kinks at every multiple of 2⁻³³ in each gene. Bounds [-5, 5]ⁿ; minimum 0 at the origin, and wherever every gene is a multiple of 1/2. ``dimensions`` is at least 1. diff --git a/src/problems/classic.rs b/src/problems/classic.rs index b72af380..5340782b 100644 --- a/src/problems/classic.rs +++ b/src/problems/classic.rs @@ -3136,8 +3136,9 @@ fn weierstrass_sum(x: f64) -> f64 { scalable!( /// The Weierstrass function, `Σᵢ Σₖ aᵏ cos(2π bᵏ (xᵢ + 0.5)) − n Σₖ aᵏ cos(π bᵏ)` with - /// a = 0.5, b = 3 and k from 0 to 20: continuous, but differentiable only on a set of - /// points, a fractal of ripples within ripples. + /// a = 0.5, b = 3 and k from 0 to 20: ripples within ripples, down to 3²⁰ times the first + /// one's frequency. The finite sum is smooth, but steep and rippled at every scale; with + /// infinitely many terms, it would be differentiable nowhere. /// /// Bounds [−0.5, 0.5]ⁿ; minimum 0 at the origin (at every integer point without bounds); /// 30 dimensions by default. Each gene's sum is at least −Σ aᵏ, reached where every cosine @@ -3176,7 +3177,8 @@ scalable_problem!( scalable!( /// Katsuura's function, /// `(10 / n²) Πᵢ (1 + i Σⱼ₌₁³² |2ʲxᵢ − round(2ʲxᵢ)| / 2ʲ)^(10 / n^1.2) − 10 / n²` - /// (i from 1): rugged everywhere, continuous but nowhere differentiable, and highly + /// (i from 1): rugged everywhere, continuous, with kinks at every multiple of 2⁻³³ in each + /// gene (with infinitely many terms, it would be differentiable nowhere), and highly /// repetitive. /// /// Bounds [−5, 5]ⁿ; minimum 0 at the origin, and at every point whose genes are multiples From fcd8fa18bad5d3ec4f364cd243d9bb4ad33801ae Mon Sep 17 00:00:00 2001 From: tachsin Date: Fri, 2 Oct 2026 15:29:58 +0300 Subject: [PATCH 13/16] docs: the CEC- and BBOB-style functions and the wrappers don't supply gradients yet --- AGENTS.md | 2 +- src/problems.rs | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index e07a4eb7..2d37d127 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -907,7 +907,7 @@ How fitness functions give gradients to gradient-based methods ([L-BFGS-B](#l-bf - `Differentiable(|x: &Reals, gradient: &mut [f64]| value)` writes the gradient (zeroed, one value per gene) and returns the value; any algorithm takes it as a plain fitness function. `Batch(Differentiable(|xs: &[&Reals], gradients: &mut [f64]| values))`: flat, row-major, a row per genome. - A `FitnessFunction` declares it with `fn provides(&self) -> Provided { Provided::GRADIENT }` and writes it in `fn evaluate_with(&self, x, extras: &mut Extras<'_>)` when `extras.gradient()` is `Some` (`genoxide::engine::{Extras, Provided}`); the value must be `evaluate`'s, to the bit. -- The smooth test problems supply theirs: every classic function in `problems` but `Eggholder`, `Schwefel2_21` and `Schwefel2_22`; `problem.provides().gradient`. +- The smooth test problems supply theirs: every classic function in `problems` but `Eggholder`, `Schwefel2_21` and `Schwefel2_22`, and not yet the CEC- and BBOB-style ones (`SumOfDifferentPowers` to `RotatedHyperEllipsoid`) or the `Shifted` and `Rotated` wrappers; `problem.provides().gradient`. - `gradient::check(&function, &x)?` compares a supplied gradient with central differences: `.largest()` about 1e-10 when right, `.worst_gene()`. - An algorithm's `gradient::Gradients` setting: `Auto` (default: supplied if provided, else forward differences, n evaluations per gradient, up to `gradient::AUTO_LIMIT` = 10⁴ genes), `Supplied` (an error at the start of a run without one), `Forward { step: None }`, `Central { step: None }` (2n per gradient, more accurate). Finite differences count towards `Stop::evaluations`. - A NaN in a gradient follows the `NanPolicy`: invalid fitness, or `Error::NanFitness`. diff --git a/src/problems.rs b/src/problems.rs index efd5f4d8..8180b8f2 100644 --- a/src/problems.rs +++ b/src/problems.rs @@ -89,12 +89,14 @@ //! `Shifted::new(Rastrigin::new(n), seed)` and `Rotated::new(Shifted::new(Rastrigin::new(n), seed), seed)`, //! with genoxide's own shift and matrix rather than the report's data files. //! -//! The classic functions but [`Eggholder`], [`Schwefel2_21`] and [`Schwefel2_22`], which aren't -//! differentiable everywhere, supply their analytic gradient to the algorithms that want one (see -//! [`gradient`](crate::gradient)): [`FitnessFunction::provides`] says so, and -//! [`FitnessFunction::evaluate_with`] computes it, with [`math`](crate::math)'s functions. Ackley's -//! has a cone at the origin, where its gradient is taken as 0, and Schwefel 2.26's second -//! derivative is unbounded at 0. +//! The classic functions of the table up to [`Kowalik`] but [`Eggholder`], [`Schwefel2_21`] and +//! [`Schwefel2_22`], which aren't differentiable everywhere, supply their analytic gradient to the +//! algorithms that want one (see [`gradient`](crate::gradient)): [`FitnessFunction::provides`] +//! says so, and [`FitnessFunction::evaluate_with`] computes it, with [`math`](crate::math)'s +//! functions. Ackley's has a cone at the origin, where its gradient is taken as 0, and Schwefel +//! 2.26's second derivative is unbounded at 0. The functions after [`Kowalik`], from +//! [`SumOfDifferentPowers`] on, and the [`Shifted`] and [`Rotated`] wrappers don't supply one +//! yet: algorithms estimate it by finite differences. //! //! Two submodules hold constrained problems, whose fitness is `(score, violation)`: //! From 1783bba0d3b1d4930c31c337a7e3fdff41bc81f3 Mon Sep 17 00:00:00 2001 From: tachsin Date: Fri, 2 Oct 2026 15:48:37 +0300 Subject: [PATCH 14/16] perf(examples): Weierstrass evaluates in parallel, and CMA-ES without restarts stops once converged MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The same output in 3 s instead of 30: each evaluation's 210 cosines, some of arguments up to 2·10¹⁰, are slow, and CMA-ES sampled on to the end of its budget after converging. --- Cargo.toml | 6 ++++++ examples/weierstrass/README.md | 7 ++++++- examples/weierstrass/main.py | 10 +++++++--- examples/weierstrass/main.rs | 28 ++++++++++++++++++++++------ 4 files changed, 41 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 80b8e60e..8732f584 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -96,6 +96,12 @@ name = "bo_asynchronous" path = "examples/bo_asynchronous/main.rs" required-features = ["parallel"] +# slow evaluations, evaluated in parallel for the same results sooner +[[example]] +name = "weierstrass" +path = "examples/weierstrass/main.rs" +required-features = ["parallel"] + [[bin]] name = "genoxide" required-features = ["cli"] diff --git a/examples/weierstrass/README.md b/examples/weierstrass/README.md index 96a0c24a..ae57e9c2 100644 --- a/examples/weierstrass/README.md +++ b/examples/weierstrass/README.md @@ -47,7 +47,9 @@ per run, and a target of 1e-8: - CMA-ES (Hansen and Ostermeier, 2001, Evolutionary Computation 9(2): 159-195), which samples a population of 10 from a normal distribution and adapts its mean, its step size and its covariance - matrix, from a step size of 0.3 of each gene's range and a random start; + matrix, from a step size of 0.3 of each gene's range and a random start, and stops once it has + converged (`cmaes::Restarts::Stop`): sampling on around its point to the end of the budget + wouldn't change its best; - the same with IPOP restarts (Auger and Hansen, 2005, IEEE CEC 2005: 1769-1776): a run that has converged starts again from a random point with twice the population; - differential evolution with genoxide's defaults, SHADE (Tanabe and Fukunaga, CEC 2013), with a @@ -58,6 +60,9 @@ per run, and a target of 1e-8: (Deb and Agrawal, 1995) with η = 15 and polynomial mutation with η = 20 at a rate of 1/10 per gene. +An evaluation is slow, 21 cosines per gene, some of arguments up to 2·10¹⁰, so each generation's +points are evaluated in parallel, which gives the same results on any number of threads. + ## Output The first line gives the dimension, the seeds and the budget. Then a row per algorithm: how many of diff --git a/examples/weierstrass/main.py b/examples/weierstrass/main.py index 1651bd5d..ceaef924 100644 --- a/examples/weierstrass/main.py +++ b/examples/weierstrass/main.py @@ -3,7 +3,9 @@ Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), differential evolution (SHADE), particle swarm optimization and a real-coded genetic algorithm from 10 seeds each, and counts the runs that reach the minimum, 0 at the origin, to within 1e-8. The function is -genoxide's `problems::Weierstrass`, which run evaluates in Rust. +genoxide's `problems::Weierstrass`, which run evaluates in Rust. Its 21 cosines per gene, some of +arguments up to 2·10¹⁰, make each evaluation slow: the runs evaluate in parallel, with the same +results on any number of threads, and CMA-ES without restarts stops once it has converged. With ``GENOXIDE_TRACE=``, it also writes a trace of a run for the plot on the example's page, with trace.py. @@ -26,7 +28,9 @@ def build(name, genome, seed): """The algorithm called ``name``, on ``genome``, from ``seed``.""" if name == "CMA-ES": - return gx.Cmaes(genome, objective="minimize", seed=seed) + # without restarts, the run ends once it has converged: sampling on around its point + # wouldn't change its best + return gx.Cmaes(genome, restarts="stop", objective="minimize", seed=seed) if name == "CMA-ES with IPOP": return gx.Cmaes(genome, restarts="ipop", objective="minimize", seed=seed) if name == "DE": @@ -71,7 +75,7 @@ def error_text(error): evaluations, errors = [], [] for seed in range(1, SEEDS + 1): result = build(name, problem.genome, seed).run( - problem, target=minimum + ERROR, evaluations=BUDGET + problem, target=minimum + ERROR, evaluations=BUDGET, parallel=True ) if result.stop_reason == "target": evaluations.append(float(result.evaluations)) diff --git a/examples/weierstrass/main.rs b/examples/weierstrass/main.rs index 1ab1fa66..4856fd92 100644 --- a/examples/weierstrass/main.rs +++ b/examples/weierstrass/main.rs @@ -3,7 +3,9 @@ //! Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), //! differential evolution (SHADE), particle swarm optimization and a real-coded genetic algorithm //! from 10 seeds each, and counts the runs that reach the minimum, 0 at the origin, to within -//! 1e-8. The function is genoxide's `problems::Weierstrass`. +//! 1e-8. The function is genoxide's `problems::Weierstrass`. Its 21 cosines per gene, some of +//! arguments up to 2·10¹⁰, make each evaluation slow: the runs evaluate in parallel, with the same +//! results on any number of threads, and CMA-ES without restarts stops once it has converged. //! //! With `GENOXIDE_TRACE=`, it also writes a trace of a run for the plot on the example's //! page, with `trace.rs`. @@ -67,8 +69,10 @@ fn run(algorithm: &str, problem: Weierstrass, seed: u64, target: f64) -> Result< let stop = Stop::target(target).or(Stop::evaluations(BUDGET)); match algorithm { "CMA-ES" | "CMA-ES with IPOP" => { + // without restarts, the run ends once it has converged: sampling on around its point + // wouldn't change its best let restarts = if algorithm == "CMA-ES" { - cmaes::Restarts::Never + cmaes::Restarts::Stop } else { cmaes::Restarts::Ipop }; @@ -77,11 +81,17 @@ fn run(algorithm: &str, problem: Weierstrass, seed: u64, target: f64) -> Result< .minimize() .seed(seed) .build()?; - Engine::new(cmaes, problem).stop_when(stop).run() + Engine::new(cmaes, problem) + .stop_when(stop) + .parallel(true) + .run() } "DE" => { let de = De::builder(real).minimize().seed(seed).build()?; - Engine::new(de, problem).stop_when(stop).run() + Engine::new(de, problem) + .stop_when(stop) + .parallel(true) + .run() } "PSO" => { let pso = Pso::builder(real) @@ -89,7 +99,10 @@ fn run(algorithm: &str, problem: Weierstrass, seed: u64, target: f64) -> Result< .minimize() .seed(seed) .build()?; - Engine::new(pso, problem).stop_when(stop).run() + Engine::new(pso, problem) + .stop_when(stop) + .parallel(true) + .run() } _ => { let ga = Ga::builder(real) @@ -100,7 +113,10 @@ fn run(algorithm: &str, problem: Weierstrass, seed: u64, target: f64) -> Result< .minimize() .seed(seed) .build()?; - Engine::new(ga, problem).stop_when(stop).run() + Engine::new(ga, problem) + .stop_when(stop) + .parallel(true) + .run() } } } From 162058c2ed1affc75ee4d20eb22ac62f29b1a48a Mon Sep 17 00:00:00 2001 From: tachsin Date: Fri, 2 Oct 2026 15:48:44 +0300 Subject: [PATCH 15/16] docs(examples): Katsuura's main method is CMA-ES with IPOP restarts, reaching the minimum from all 10 seeds With 500,000 evaluations per run, it reaches 1e-8 from every seed, after 41,990 to 456,820. CMA-ES without restarts, SHADE, PSO and the GA stay as contrasts with the other pages' 100,000, PSO's corners counted in the output. --- Cargo.toml | 7 ++- examples/katsuura/README.md | 54 +++++++++++++--------- examples/katsuura/main.py | 46 ++++++++++++++----- examples/katsuura/main.rs | 87 +++++++++++++++++++++++++++--------- examples/katsuura/output.txt | 16 ++++--- 5 files changed, 147 insertions(+), 63 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8732f584..f0c56afa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -96,12 +96,17 @@ name = "bo_asynchronous" path = "examples/bo_asynchronous/main.rs" required-features = ["parallel"] -# slow evaluations, evaluated in parallel for the same results sooner +# slow evaluations (Weierstrass), or up to half a million per run (Katsuura), evaluated in parallel [[example]] name = "weierstrass" path = "examples/weierstrass/main.rs" required-features = ["parallel"] +[[example]] +name = "katsuura" +path = "examples/katsuura/main.rs" +required-features = ["parallel"] + [[bin]] name = "genoxide" required-features = ["cli"] diff --git a/examples/katsuura/README.md b/examples/katsuura/README.md index e7ca9c46..e9f76b96 100644 --- a/examples/katsuura/README.md +++ b/examples/katsuura/README.md @@ -1,7 +1,7 @@ --- title: Katsuura category: continuous -summary: Minimize Katsuura's function, rugged everywhere, in 10 dimensions, with CMA-ES without and with restarts, DE, PSO and a GA from 10 seeds each. +summary: Minimize Katsuura's function, rugged everywhere, in 10 dimensions, with CMA-ES with IPOP restarts from 10 seeds, against CMA-ES without restarts, DE, PSO and a GA. reference: "Hansen, N., Finck, S., Ros, R. and Auger, A. (2009). Real-Parameter Black-Box Optimization Benchmarking 2009: Noiseless Functions Definitions. INRIA research report RR-6829." reference_url: "https://hal.inria.fr/inria-00362633" optimum: "0 (at the origin, and wherever every gene is a multiple of 1/2)" @@ -47,14 +47,18 @@ The function is genoxide's `problems::Katsuura`, which brings its bounds and its ## Algorithm -Five algorithms, each from seeds 1 to 10, with a budget of 10,000 evaluations per dimension, 100,000 -per run, and a target of 1e-8: +The main method is CMA-ES (Hansen and Ostermeier, 2001, Evolutionary Computation 9(2): 159-195) +with IPOP restarts (Auger and Hansen, 2005, IEEE CEC 2005: 1769-1776). It samples a population of +10 from a normal distribution and adapts its mean, its step size and its covariance matrix, from a +step size of 0.3 of each gene's range and a random start; a run that has converged starts again from +a random point with twice the population. It runs from seeds 1 to 10, with a budget of 50,000 +evaluations per dimension, 500,000 per run, and a target of 1e-8. -- CMA-ES (Hansen and Ostermeier, 2001, Evolutionary Computation 9(2): 159-195), which samples a - population of 10 from a normal distribution and adapts its mean, its step size and its covariance - matrix, from a step size of 0.3 of each gene's range and a random start; -- the same with IPOP restarts (Auger and Hansen, 2005, IEEE CEC 2005: 1769-1776): a run that has - converged starts again from a random point with twice the population; +Four contrasts run from the same seeds with the budget of the other functions' pages, 10,000 +evaluations per dimension, 100,000 per run: + +- CMA-ES without restarts, which stops once it has converged (`cmaes::Restarts::Stop`): sampling on + around its point to the end of the budget wouldn't change its best; - differential evolution with genoxide's defaults, SHADE (Tanabe and Fukunaga, CEC 2013), with a population of 100 and its restarts on stagnation; - particle swarm optimization (Kennedy and Eberhart, 1995), 40 particles with Clerc and Kennedy's @@ -63,13 +67,17 @@ per run, and a target of 1e-8: (Deb and Agrawal, 1995) with η = 15 and polynomial mutation with η = 20 at a rate of 1/10 per gene. +Each generation's points are evaluated in parallel, which gives the same results on any number of +threads. + ## Output -The first line gives the dimension, the seeds and the budget. Then a row per algorithm: how many of +The first line gives the dimension and the seeds. Then a row per algorithm: its budget, how many of its 10 runs reached the minimum, to within 1e-8, the median of their evaluations (a dash if none -did), and the median of every run's best error, to two significant digits. The function is evaluated -with genoxide's portable math, so the runs are the same on every platform, and in Python, `run` -evaluates it in Rust, so both versions print the same. +did), and the median of every run's best error, to two significant digits. Two lines follow: the +fewest and most evaluations the main method needed, and how many of PSO's runs ended on a corner of +the box. The function is evaluated with genoxide's portable math, so the runs are the same on every +platform, and in Python, `run` evaluates it in Rust, so both versions print the same. [The project page](https://tachsin.gr/projects/genoxide/examples/katsuura) plays back another run: CMA-ES with IPOP restarts on the function in 2 dimensions, so that the population can be drawn on @@ -77,13 +85,15 @@ its contour. It meets the target after 990 evaluations, at a multiple of 1/2. ## Good results -The minimum is 0. PSO reaches it in all 10 runs, after a median of 380 evaluations, but only through -the bounds: its particles head out of the box, stop at ±5 in every gene, and land on a corner, a -global minimum (from seed 1, at (5, 5, −5, 5, −5, 5, −5, 5, 5, −5)). On the function shifted with -genoxide's `problems::Shifted` and seed 1, whose minima are no longer on the bounds, PSO's runs from -seeds 1 and 2 end at 0.021. - -Of the searches that don't use the bounds, CMA-ES with IPOP restarts reaches the minimum once, after -41,990 evaluations, and its median run ends at 1.3e-2. SHADE comes closest without reaching it, with -a median error of 5.8e-6, and the genetic algorithm ends at 3.7e-4. CMA-ES without restarts ends at -0.10. +The minimum is 0. CMA-ES with IPOP restarts reaches it in all 10 runs, after a median of 230,100 +evaluations, from 41,990 (seed 3) to 456,820 (seed 10): each restart is a fresh try with a larger +population, and one of them eventually lands in a minimum's basin and follows it down to 1e-8. With +the other pages' budget of 100,000, it reached it only once, from seed 3. + +The contrasts show why it takes that many. CMA-ES without restarts converges to a local minimum, at +a median error of 0.10. SHADE comes closest of the others, to a median error of 5.8e-6, and the +genetic algorithm ends at 3.7e-4. PSO reaches 0 in all 10 runs, after a median of 380 evaluations, +but only through the bounds: its particles head out of the box, stop at ±5 in every gene, and all 10 +runs end on a corner, a global minimum (from seed 1, at (5, 5, −5, 5, −5, 5, −5, 5, 5, −5)). On the +function shifted with genoxide's `problems::Shifted` and seed 1, whose minima are no longer on the +bounds, PSO's runs from seeds 1 and 2 end at 0.021. diff --git a/examples/katsuura/main.py b/examples/katsuura/main.py index ac07d488..583aa5e6 100644 --- a/examples/katsuura/main.py +++ b/examples/katsuura/main.py @@ -1,9 +1,12 @@ """Katsuura: minimize Katsuura's function, rugged everywhere, in 10 dimensions. -Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), differential -evolution (SHADE), particle swarm optimization and a real-coded genetic algorithm from 10 seeds -each, and counts the runs that reach the minimum, 0 at the origin, to within 1e-8. The function is -genoxide's `problems::Katsuura`, which run evaluates in Rust. +Runs CMA-ES with IPOP restarts (a population that doubles at each restart) from 10 seeds, with a +budget of 500,000 evaluations per run, and counts the runs that reach the minimum, 0 at the origin, +to within 1e-8. Then, as contrasts with the budget of 100,000 evaluations of the other functions' +pages: CMA-ES without restarts, differential evolution (SHADE), particle swarm optimization, which +reaches the minimum only by stopping at the bounds, and a real-coded genetic algorithm. The function +is genoxide's `problems::Katsuura`, which run evaluates in Rust. The runs evaluate in parallel, with +the same results on any number of threads. With ``GENOXIDE_TRACE=``, it also writes a trace of a run for the plot on the example's page, with trace.py. @@ -17,16 +20,25 @@ DIMENSIONS = 10 SEEDS = 10 -BUDGET = 10_000 * DIMENSIONS # a run stops once its error to the minimum is at most this ERROR = 1e-8 -ALGORITHMS = ["CMA-ES", "CMA-ES with IPOP", "DE", "PSO", "GA"] +# the algorithms and their budgets of evaluations per run: the main method's, enough for every +# seed, then the contrasts', the 10,000 per dimension of the other functions' pages +ALGORITHMS = [ + ("CMA-ES with IPOP", 50_000 * DIMENSIONS), + ("CMA-ES", 10_000 * DIMENSIONS), + ("DE", 10_000 * DIMENSIONS), + ("PSO", 10_000 * DIMENSIONS), + ("GA", 10_000 * DIMENSIONS), +] def build(name, genome, seed): """The algorithm called ``name``, on ``genome``, from ``seed``.""" if name == "CMA-ES": - return gx.Cmaes(genome, objective="minimize", seed=seed) + # without restarts, the run ends once it has converged: sampling on around its point + # wouldn't change its best + return gx.Cmaes(genome, restarts="stop", objective="minimize", seed=seed) if name == "CMA-ES with IPOP": return gx.Cmaes(genome, restarts="ipop", objective="minimize", seed=seed) if name == "DE": @@ -61,25 +73,35 @@ def error_text(error): problem = gx.problems.Katsuura(DIMENSIONS) minimum = problem.optimum.value -print(f"Katsuura in {DIMENSIONS} dimensions, {SEEDS} seeds, {BUDGET} evaluations at most per run") -print("algorithm at min evaluations median error") -for name in ALGORITHMS: +print(f"Katsuura in {DIMENSIONS} dimensions, {SEEDS} seeds") +print("algorithm budget at min evaluations median error") +corners = 0 +fewest = most = float("nan") +for name, budget in ALGORITHMS: # the evaluations of the runs that reach the minimum, and every run's best error evaluations, errors = [], [] for seed in range(1, SEEDS + 1): result = build(name, problem.genome, seed).run( - problem, target=minimum + ERROR, evaluations=BUDGET + problem, target=minimum + ERROR, evaluations=budget, parallel=True ) if result.stop_reason == "target": evaluations.append(float(result.evaluations)) # rounding can put a solution a few ulps below the minimum errors.append(max(result.best_fitness - minimum, 0.0)) + # a corner of the box, where every gene is at a bound + if name == "PSO" and all(abs(x) == 5.0 for x in result.best_genome): + corners += 1 reached = f"{len(evaluations)}/{SEEDS}" + if name == "CMA-ES with IPOP": + # the main method's fewest and most evaluations to the minimum + fewest, most = min(evaluations), max(evaluations) middle = median(evaluations) evaluations_text = "-" if middle is None else f"{middle:.0f}" error = error_text(median(errors)) - print(f"{name:<16} {reached:>6} {evaluations_text:>11} {error:>12}") + print(f"{name:<16} {budget:>7} {reached:>6} {evaluations_text:>11} {error:>12}") print("evaluations: the median of the runs that reach the minimum") +print(f"CMA-ES with IPOP: from {fewest:.0f} to {most:.0f} evaluations to the minimum") +print(f"PSO: {corners} of its {SEEDS} runs end on a corner of the box, every gene at a bound") # with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate run in # 2 dimensions: the plot is the function's contour diff --git a/examples/katsuura/main.rs b/examples/katsuura/main.rs index 09d7c7f3..c69b8a1a 100644 --- a/examples/katsuura/main.rs +++ b/examples/katsuura/main.rs @@ -1,9 +1,12 @@ //! Katsuura: minimize Katsuura's function, rugged everywhere, in 10 dimensions. //! -//! Runs CMA-ES without and with IPOP restarts (a population that doubles at each restart), -//! differential evolution (SHADE), particle swarm optimization and a real-coded genetic algorithm -//! from 10 seeds each, and counts the runs that reach the minimum, 0 at the origin, to within -//! 1e-8. The function is genoxide's `problems::Katsuura`. +//! Runs CMA-ES with IPOP restarts (a population that doubles at each restart) from 10 seeds, with +//! a budget of 500,000 evaluations per run, and counts the runs that reach the minimum, 0 at the +//! origin, to within 1e-8. Then, as contrasts with the budget of 100,000 evaluations of the other +//! functions' pages: CMA-ES without restarts, differential evolution (SHADE), particle swarm +//! optimization, which reaches the minimum only by stopping at the bounds, and a real-coded +//! genetic algorithm. The function is genoxide's `problems::Katsuura`. The runs evaluate in +//! parallel, with the same results on any number of threads. //! //! With `GENOXIDE_TRACE=`, it also writes a trace of a run for the plot on the example's //! page, with `trace.rs`. @@ -19,40 +22,62 @@ use genoxide::problems::{Katsuura, Problem}; const DIMENSIONS: usize = 10; const SEEDS: u64 = 10; -const BUDGET: u64 = 10_000 * DIMENSIONS as u64; // a run stops once its error to the minimum is at most this const ERROR: f64 = 1e-8; -const ALGORITHMS: [&str; 5] = ["CMA-ES", "CMA-ES with IPOP", "DE", "PSO", "GA"]; +// the algorithms and their budgets of evaluations per run: the main method's, enough for every +// seed, then the contrasts', the 10,000 per dimension of the other functions' pages +const ALGORITHMS: [(&str, u64); 5] = [ + ("CMA-ES with IPOP", 50_000 * DIMENSIONS as u64), + ("CMA-ES", 10_000 * DIMENSIONS as u64), + ("DE", 10_000 * DIMENSIONS as u64), + ("PSO", 10_000 * DIMENSIONS as u64), + ("GA", 10_000 * DIMENSIONS as u64), +]; fn main() -> Result<()> { let problem = Katsuura::new(DIMENSIONS); let minimum = problem.optimum().expect("known").value(); - println!( - "Katsuura in {DIMENSIONS} dimensions, {SEEDS} seeds, {BUDGET} evaluations at most per run" - ); - println!("algorithm at min evaluations median error"); - for algorithm in ALGORITHMS { + println!("Katsuura in {DIMENSIONS} dimensions, {SEEDS} seeds"); + println!("algorithm budget at min evaluations median error"); + let mut corners = 0; + let mut main_range = (f64::NAN, f64::NAN); + for (algorithm, budget) in ALGORITHMS { // the evaluations of the runs that reach the minimum, and every run's best error let mut evaluations = Vec::new(); let mut errors = Vec::new(); for seed in 1..=SEEDS { - let outcome = run(algorithm, problem, seed, minimum + ERROR)?; + let outcome = run(algorithm, problem, seed, minimum + ERROR, budget)?; if outcome.stop_reason() == StopReason::Target { evaluations.push(outcome.evaluations() as f64); } // rounding can put a solution a few ulps below the minimum let best = outcome.best_fitness().score().expect("valid"); errors.push((best - minimum).max(0.0)); + // a corner of the box, where every gene is at a bound + if algorithm == "PSO" && outcome.best_genome().iter().all(|x| x.abs() == 5.0) { + corners += 1; + } } let reached = format!("{}/{SEEDS}", evaluations.len()); + if algorithm == "CMA-ES with IPOP" { + // the main method's fewest and most evaluations to the minimum + let fewest = evaluations.iter().copied().fold(f64::INFINITY, f64::min); + let most = evaluations.iter().copied().fold(0.0, f64::max); + main_range = (fewest, most); + } let evaluations = median(evaluations).map_or("-".to_string(), |e| format!("{e:.0}")); let error = median(errors).expect("a run"); println!( - "{algorithm:<16} {reached:>6} {evaluations:>11} {:>12}", + "{algorithm:<16} {budget:>7} {reached:>6} {evaluations:>11} {:>12}", format!("{error:.1e}") ); } println!("evaluations: the median of the runs that reach the minimum"); + let (fewest, most) = main_range; + println!("CMA-ES with IPOP: from {fewest:.0} to {most:.0} evaluations to the minimum"); + println!( + "PSO: {corners} of its {SEEDS} runs end on a corner of the box, every gene at a bound" + ); // with GENOXIDE_TRACE=, a trace for the plot on the example's page, of a separate // run in 2 dimensions: the plot is the function's contour @@ -60,15 +85,23 @@ fn main() -> Result<()> { Ok(()) } -// a run of `algorithm` from `seed`, until its best is at most `target` or it has used BUDGET +// a run of `algorithm` from `seed`, until its best is at most `target` or it has used `budget` // evaluations -fn run(algorithm: &str, problem: Katsuura, seed: u64, target: f64) -> Result> { +fn run( + algorithm: &str, + problem: Katsuura, + seed: u64, + target: f64, + budget: u64, +) -> Result> { let real = problem.representation(); - let stop = Stop::target(target).or(Stop::evaluations(BUDGET)); + let stop = Stop::target(target).or(Stop::evaluations(budget)); match algorithm { "CMA-ES" | "CMA-ES with IPOP" => { + // without restarts, the run ends once it has converged: sampling on around its point + // wouldn't change its best let restarts = if algorithm == "CMA-ES" { - cmaes::Restarts::Never + cmaes::Restarts::Stop } else { cmaes::Restarts::Ipop }; @@ -77,11 +110,17 @@ fn run(algorithm: &str, problem: Katsuura, seed: u64, target: f64) -> Result { let de = De::builder(real).minimize().seed(seed).build()?; - Engine::new(de, problem).stop_when(stop).run() + Engine::new(de, problem) + .stop_when(stop) + .parallel(true) + .run() } "PSO" => { let pso = Pso::builder(real) @@ -89,7 +128,10 @@ fn run(algorithm: &str, problem: Katsuura, seed: u64, target: f64) -> Result { let ga = Ga::builder(real) @@ -100,7 +142,10 @@ fn run(algorithm: &str, problem: Katsuura, seed: u64, target: f64) -> Result Date: Fri, 2 Oct 2026 15:48:44 +0300 Subject: [PATCH 16/16] docs(examples): the evidence that HappyCat and HGBat's minima are out of reach Ten times the budget for CMA-ES with IPOP restarts, then Nelder-Mead from its best, from 5 seeds, and the CEC 2014 winner's errors on the same functions. --- examples/happy_cat/README.md | 14 ++++++++++++++ examples/hg_bat/README.md | 17 +++++++++++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/examples/happy_cat/README.md b/examples/happy_cat/README.md index 37a726bc..b8f40f6f 100644 --- a/examples/happy_cat/README.md +++ b/examples/happy_cat/README.md @@ -79,3 +79,17 @@ No algorithm reaches the minimum to within 1e-8: that's the function's point. CM restarts comes closest, with a median error of 5.4·10⁻³; CMA-ES without restarts ends at 9.4·10⁻², the genetic algorithm at 7.8·10⁻², SHADE at 0.10 and PSO at 0.14. They all reach the groove, and stall in it, short of the minimum. + +A larger budget doesn't change that. CMA-ES with IPOP restarts from seeds 1 to 5, with 1,000,000 +evaluations each, ten times the page's budget, ends at errors of 8.0·10⁻⁴ to 2.8·10⁻³ (1.9·10⁻³, +2.8·10⁻³, 8.2·10⁻⁴, 1.2·10⁻³ and 8.0·10⁻⁴). Nelder-Mead started from each of those points, with an +initial step of 0.01 of each range, converges after 2,584 to 2,735 evaluations without improving +any of them. + +That matches the function's reputation, as Beyer and Finck's title says: "a simple function class +where well-known direct search algorithms do fail". The CEC 2014 competition's winner, L-SHADE, +didn't reach the minimum either: on the competition's shifted and rotated HappyCat (its F13) in 10 +dimensions, with 100,000 evaluations, its best of 51 runs ended at an error of 1.6·10⁻² and its +median at 5.3·10⁻² (Tanabe, R. and Fukunaga, A. S. (2014). Improving the search performance of SHADE +using linear population size reduction. 2014 IEEE Congress on Evolutionary Computation: 1658-1665, +table I, [doi:10.1109/CEC.2014.6900380](https://doi.org/10.1109/CEC.2014.6900380)). diff --git a/examples/hg_bat/README.md b/examples/hg_bat/README.md index 2e19546e..33e57b3c 100644 --- a/examples/hg_bat/README.md +++ b/examples/hg_bat/README.md @@ -29,8 +29,8 @@ gives no other source; it's usually credited to Beyer and Finck too, whose paper The first term is 0 where ‖x‖² = |Σ xᵢ|, on two spheres through the origin, one of them through (−1, …, −1), and rises as a square root away from them: a groove whose floor curves around to the -minimum, with a gentle slope along it. As on HappyCat, a search falls into the groove at once, then has to follow a -curving direction with small steps across it and large ones along it. +minimum, with a gentle slope along it. As on HappyCat, a search falls into the groove at once, then +has to follow a curving direction with small steps across it and large ones along it. ## Representation @@ -73,3 +73,16 @@ the target in 2 dimensions either. No algorithm reaches the minimum to within 1e-8. SHADE comes closest, with a median error of 0.13; PSO ends at 0.20, the genetic algorithm at 0.30, CMA-ES with IPOP restarts at 0.34 and without restarts at 0.45. They reach the groove and stall in it, as on HappyCat. + +A larger budget doesn't change that. CMA-ES with IPOP restarts from seeds 1 to 5, with 1,000,000 +evaluations each, ten times the page's budget, ends at errors of 0.11 to 0.33 (0.29, 0.11, 0.33, +0.25 and 0.29). Nelder-Mead started from each of those points, with an initial step of 0.01 of each +range, converges after 1,347 to 2,021 evaluations at 0.10 to 0.25 (0.25, 0.10, 0.20, 0.15 and 0.15): +better, but nowhere near the minimum. + +That matches the function's record. The CEC 2014 competition's winner, L-SHADE, didn't reach the +minimum either: on the competition's shifted and rotated HGBat (its F14) in 10 dimensions, with +100,000 evaluations, its best of 51 runs ended at an error of 4.5·10⁻² and its median at 7.6·10⁻² +(Tanabe, R. and Fukunaga, A. S. (2014). Improving the search performance of SHADE using linear +population size reduction. 2014 IEEE Congress on Evolutionary Computation: 1658-1665, table I, +[doi:10.1109/CEC.2014.6900380](https://doi.org/10.1109/CEC.2014.6900380)).