diff --git a/AGENTS.md b/AGENTS.md index 7c11f674..2d37d127 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -136,7 +136,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. @@ -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/Cargo.toml b/Cargo.toml index 80b8e60e..f0c56afa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -96,6 +96,17 @@ name = "bo_asynchronous" path = "examples/bo_asynchronous/main.rs" required-features = ["parallel"] +# 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/docs/features.md b/docs/features.md index 5b95a299..777ccae6 100644 --- a/docs/features.md +++ b/docs/features.md @@ -73,7 +73,7 @@ What genoxide has on main; [docs.rs](https://docs.rs/genoxide) documents the lat - **Constraints:** the values of `Constrained` fitness functions and of the constrained test problems, a Gaussian process per constraint, and the acquisition weighed by the probability of feasibility (Gardner et al. 2014); before a feasible point, that probability alone. - **Integer genomes:** the genes rounded inside the kernel (Garrido-Merchán and Hernández-Lobato 2020), the acquisition maximized on the lattice by a hill climb (every point of a small lattice at once), the run finished once the lattice is evaluated. - **Gaussian processes** (`model::gp`, unstable for one release): regression with a constant mean, an ARD Matérn 5/2 or squared exponential kernel, no noise by default (the model interpolates a deterministic function) or learned noise, inputs scaled to the unit cube and outputs standardized; hyperparameters by maximum marginal likelihood (Rasmussen and Williams, eq. 2.30 and 5.9) with genoxide's L-BFGS-B from fixed and seeded random starts; the posterior mean and variance with their gradients; Cholesky factorizations with a growing jitter. In Python as `gx.model.gp`. -- **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. +- **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 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 | diff --git a/examples/README.md b/examples/README.md index d5f1509b..8bd7dee5 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/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/bent_cigar/README.md b/examples/bent_cigar/README.md new file mode 100644 index 00000000..f46cc8dd --- /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..0886e904 --- /dev/null +++ b/examples/bent_cigar/main.py @@ -0,0 +1,100 @@ +"""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..c321d089 --- /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) + .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/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/buche_rastrigin/README.md b/examples/buche_rastrigin/README.md new file mode 100644 index 00000000..9a81d58b --- /dev/null +++ b/examples/buche_rastrigin/README.md @@ -0,0 +1,82 @@ +--- +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..b1e9dd37 --- /dev/null +++ b/examples/buche_rastrigin/main.py @@ -0,0 +1,90 @@ +"""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, " + 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 + 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}" + 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 +# 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..9499503b --- /dev/null +++ b/examples/buche_rastrigin/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 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..ca6b81ff --- /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) + .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/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/different_powers/README.md b/examples/different_powers/README.md new file mode 100644 index 00000000..6716e967 --- /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..af4184c8 --- /dev/null +++ b/examples/different_powers/main.py @@ -0,0 +1,100 @@ +"""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..e9bbda46 --- /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..9a8748a9 --- /dev/null +++ b/examples/discus/main.py @@ -0,0 +1,98 @@ +"""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/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/happy_cat/README.md b/examples/happy_cat/README.md new file mode 100644 index 00000000..b8f40f6f --- /dev/null +++ b/examples/happy_cat/README.md @@ -0,0 +1,95 @@ +--- +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. + +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/happy_cat/main.py b/examples/happy_cat/main.py new file mode 100644 index 00000000..9985f725 --- /dev/null +++ b/examples/happy_cat/main.py @@ -0,0 +1,87 @@ +"""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}" + 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 +# 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..7e4a1ed8 --- /dev/null +++ b/examples/happy_cat/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 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..cd704825 --- /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) + .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/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/hg_bat/README.md b/examples/hg_bat/README.md new file mode 100644 index 00000000..33e57b3c --- /dev/null +++ b/examples/hg_bat/README.md @@ -0,0 +1,88 @@ +--- +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ᵢ|, 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 + +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. + +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)). diff --git a/examples/hg_bat/main.py b/examples/hg_bat/main.py new file mode 100644 index 00000000..6c34a3f0 --- /dev/null +++ b/examples/hg_bat/main.py @@ -0,0 +1,86 @@ +"""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 +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}" + 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 +# 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..c539bbfe --- /dev/null +++ b/examples/hg_bat/main.rs @@ -0,0 +1,118 @@ +//! 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 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..f7de2ea3 --- /dev/null +++ b/examples/hg_bat/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 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..c3267ed4 --- /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) + .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..a9745842 --- /dev/null +++ b/examples/high_conditioned_elliptic/README.md @@ -0,0 +1,92 @@ +--- +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..0dd276f4 --- /dev/null +++ b/examples/high_conditioned_elliptic/main.py @@ -0,0 +1,100 @@ +"""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..87ef2516 --- /dev/null +++ b/examples/high_conditioned_elliptic/main.rs @@ -0,0 +1,154 @@ +//! 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/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/katsuura/README.md b/examples/katsuura/README.md new file mode 100644 index 00000000..e9f76b96 --- /dev/null +++ b/examples/katsuura/README.md @@ -0,0 +1,99 @@ +--- +title: Katsuura +category: continuous +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)" +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 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 +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 + +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. + +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 + 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. + +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 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. 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 +its contour. It meets the target after 990 evaluations, at a multiple of 1/2. + +## Good results + +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 new file mode 100644 index 00000000..583aa5e6 --- /dev/null +++ b/examples/katsuura/main.py @@ -0,0 +1,108 @@ +"""Katsuura: minimize Katsuura's function, rugged everywhere, in 10 dimensions. + +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. + + python examples/katsuura/main.py +""" + +import genoxide as gx + +from trace import record_small + +DIMENSIONS = 10 +SEEDS = 10 +# a run stops once its error to the minimum is at most this +ERROR = 1e-8 +# 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": + # 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": + 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") +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, 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} {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 +record_small() diff --git a/examples/katsuura/main.rs b/examples/katsuura/main.rs new file mode 100644 index 00000000..c69b8a1a --- /dev/null +++ b/examples/katsuura/main.rs @@ -0,0 +1,162 @@ +//! Katsuura: minimize Katsuura's function, rugged everywhere, in 10 dimensions. +//! +//! 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`. +//! +//! ```text +//! cargo run --release --example katsuura +//! ``` + +mod trace; + +use genoxide::prelude::*; +use genoxide::problems::{Katsuura, Problem}; + +const DIMENSIONS: usize = 10; +const SEEDS: u64 = 10; +// a run stops once its error to the minimum is at most this +const ERROR: f64 = 1e-8; +// 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"); + 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, 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} {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 + 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, + budget: u64, +) -> Result> { + let real = problem.representation(); + 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::Stop + } else { + cmaes::Restarts::Ipop + }; + let cmaes = Cmaes::builder(real) + .restarts(restarts) + .minimize() + .seed(seed) + .build()?; + 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) + .parallel(true) + .run() + } + "PSO" => { + let pso = Pso::builder(real) + .population_size(40) + .minimize() + .seed(seed) + .build()?; + Engine::new(pso, problem) + .stop_when(stop) + .parallel(true) + .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) + .parallel(true) + .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..aa97ad5a --- /dev/null +++ b/examples/katsuura/output.txt @@ -0,0 +1,10 @@ +Katsuura in 10 dimensions, 10 seeds +algorithm budget at min evaluations median error +CMA-ES with IPOP 500000 10/10 230100 8.5e-9 +CMA-ES 100000 0/10 - 1.0e-1 +DE 100000 0/10 - 5.8e-6 +PSO 100000 10/10 380 0.0e0 +GA 100000 0/10 - 3.7e-4 +evaluations: the median of the runs that reach the minimum +CMA-ES with IPOP: from 41990 to 456820 evaluations to the minimum +PSO: 10 of its 10 runs end on a corner of the box, every gene at a bound 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..e53e1a50 --- /dev/null +++ b/examples/katsuura/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 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..b0ea38c7 --- /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) + .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/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/non_continuous_rastrigin/README.md b/examples/non_continuous_rastrigin/README.md new file mode 100644 index 00000000..d0ddb0ba --- /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..d4e553f7 --- /dev/null +++ b/examples/non_continuous_rastrigin/main.py @@ -0,0 +1,90 @@ +"""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, " + 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 + 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}" + 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 +# 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..36034fc9 --- /dev/null +++ b/examples/non_continuous_rastrigin/main.rs @@ -0,0 +1,123 @@ +//! 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..db8c0395 --- /dev/null +++ b/examples/non_continuous_rastrigin/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 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..c6ad6768 --- /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) + .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/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/penalized1/README.md b/examples/penalized1/README.md new file mode 100644 index 00000000..2475bf4c --- /dev/null +++ b/examples/penalized1/README.md @@ -0,0 +1,82 @@ +--- +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..b365d23f --- /dev/null +++ b/examples/penalized1/main.py @@ -0,0 +1,90 @@ +"""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, " + 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 + 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}" + 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 +# 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..aa152e37 --- /dev/null +++ b/examples/penalized1/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 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..cf487b9f --- /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) + .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..97701f4e --- /dev/null +++ b/examples/penalized2/README.md @@ -0,0 +1,82 @@ +--- +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..fc3a4317 --- /dev/null +++ b/examples/penalized2/main.py @@ -0,0 +1,89 @@ +"""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, " + 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 + 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}" + 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 +# 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..e6a240f7 --- /dev/null +++ b/examples/penalized2/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 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..175ce007 --- /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) + .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/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/quartic/README.md b/examples/quartic/README.md new file mode 100644 index 00000000..c379ed92 --- /dev/null +++ b/examples/quartic/README.md @@ -0,0 +1,91 @@ +--- +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..cc1d52f6 --- /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..990164b7 --- /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) + .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/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/rotated_hyper_ellipsoid/README.md b/examples/rotated_hyper_ellipsoid/README.md new file mode 100644 index 00000000..55670d39 --- /dev/null +++ b/examples/rotated_hyper_ellipsoid/README.md @@ -0,0 +1,95 @@ +--- +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..da72112c --- /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..684ea28b --- /dev/null +++ b/examples/rotated_hyper_ellipsoid/main.rs @@ -0,0 +1,154 @@ +//! 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/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/schaffer_f7/README.md b/examples/schaffer_f7/README.md new file mode 100644 index 00000000..2949075d --- /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..b5235eed --- /dev/null +++ b/examples/schaffer_f7/main.py @@ -0,0 +1,89 @@ +"""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, " + 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 + 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}" + 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 +# 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..a849036c --- /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::{Problem, SchafferF7}; + +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..2c986728 --- /dev/null +++ b/examples/schaffer_f7/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 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..0282b5fa --- /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) + .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/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/step/README.md b/examples/step/README.md new file mode 100644 index 00000000..9e52e5a0 --- /dev/null +++ b/examples/step/README.md @@ -0,0 +1,79 @@ +--- +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..425cc7e7 --- /dev/null +++ b/examples/step/main.py @@ -0,0 +1,92 @@ +"""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..adc6381e --- /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) + .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/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/sum_of_different_powers/README.md b/examples/sum_of_different_powers/README.md new file mode 100644 index 00000000..0f62a141 --- /dev/null +++ b/examples/sum_of_different_powers/README.md @@ -0,0 +1,89 @@ +--- +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). + +## 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..0f4267c2 --- /dev/null +++ b/examples/sum_of_different_powers/main.py @@ -0,0 +1,100 @@ +"""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, 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 +# 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..7ee5c01f --- /dev/null +++ b/examples/sum_of_different_powers/main.rs @@ -0,0 +1,154 @@ +//! 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, 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 + // 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..2ea489ed --- /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) + .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/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/weierstrass/README.md b/examples/weierstrass/README.md new file mode 100644 index 00000000..ae57e9c2 --- /dev/null +++ b/examples/weierstrass/README.md @@ -0,0 +1,83 @@ +--- +title: Weierstrass +category: continuous +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)" +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 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 + +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, 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 + 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. + +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 +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..ceaef924 --- /dev/null +++ b/examples/weierstrass/main.py @@ -0,0 +1,93 @@ +"""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 +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. 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. + + 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": + # 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": + 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, " + 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 + evaluations, errors = [], [] + for seed in range(1, SEEDS + 1): + result = build(name, problem.genome, seed).run( + 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)) + reached = f"{len(evaluations)}/{SEEDS}" + 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("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..4856fd92 --- /dev/null +++ b/examples/weierstrass/main.rs @@ -0,0 +1,133 @@ +//! 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 each, and counts the runs that reach the minimum, 0 at the origin, to within +//! 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`. +//! +//! ```text +//! cargo run --release --example weierstrass +//! ``` + +mod trace; + +use genoxide::prelude::*; +use genoxide::problems::{Problem, Weierstrass}; + +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" => { + // 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::Stop + } else { + cmaes::Restarts::Ipop + }; + let cmaes = Cmaes::builder(real) + .restarts(restarts) + .minimize() + .seed(seed) + .build()?; + 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) + .parallel(true) + .run() + } + "PSO" => { + let pso = Pso::builder(real) + .population_size(40) + .minimize() + .seed(seed) + .build()?; + Engine::new(pso, problem) + .stop_when(stop) + .parallel(true) + .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) + .parallel(true) + .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..3f6ba7ff --- /dev/null +++ b/examples/weierstrass/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 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..ff8374a1 --- /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) + .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()) + } +} 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 --- diff --git a/python/genoxide/problems/__init__.py b/python/genoxide/problems/__init__.py index fe64ce77..a66725d3 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,384 @@ 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: 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. + + 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, 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. + + 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 two spheres through the origin, where ``‖x‖² = |Σ xᵢ|``. + + 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..c467820b 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,104 @@ 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 + 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 + 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) + 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) + 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"), + ( + 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 +466,12 @@ 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"), ], 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": diff --git a/src/problems.rs b/src/problems.rs index 39f54ae5..8180b8f2 100644 --- a/src/problems.rs +++ b/src/problems.rs @@ -64,13 +64,39 @@ //! | [`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 | //! -//! 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. +//! 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 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)`: //! @@ -112,6 +138,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 +167,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 +178,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 +528,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 +589,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..5340782b 100644 --- a/src/problems/classic.rs +++ b/src/problems/classic.rs @@ -2481,6 +2481,933 @@ 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: 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 + /// 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, 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 + /// 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 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. + /// + /// 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 +4257,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..9c91a3af --- /dev/null +++ b/src/problems/transform.rs @@ -0,0 +1,510 @@ +//! 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 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 +/// ℝⁿ, 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`; 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; +/// 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)); + } +}