diff --git a/src/api/types.jl b/src/api/types.jl index 5c82e17..e37ecf7 100644 --- a/src/api/types.jl +++ b/src/api/types.jl @@ -171,7 +171,10 @@ abstract type AbstractStrategy end """Empty evolution strategy""" struct NoStrategy <: AbstractStrategy end -copy(s::NoStrategy) = NoStrategy() +copy(::NoStrategy) = NoStrategy() +Base.getproperty(s::NoStrategy, ::Symbol) = 0.0 +Base.setproperty!(s::NoStrategy, ::Symbol, ::T) where {T<:Real} = 0.0 + """ Isotropic evolution strategy diff --git a/src/es.jl b/src/es.jl index 2616992..65849b0 100644 --- a/src/es.jl +++ b/src/es.jl @@ -4,8 +4,8 @@ Implementation of Evolution Strategy: (μ/ρ(+/,)λ)-ES The constructor takes following keyword arguments: - `initStrategy`: an initial strategy description, (default: empty) -- `recombination`: ES recombination function for population (default: `first`), see [Crossover](@ref) -- `srecombination`: ES recombination function for strategies (default: `first`), see [Crossover](@ref) +- `recombination`: ES recombination function for population (default: [`average`](@ref)), see [Crossover](@ref) +- `srecombination`: ES recombination function for strategies (default: [`average`](@ref)), see [Crossover](@ref) - `mutation`: [Mutation](@ref) function for population (default: [`nop`](@ref)) - `smutation`: [Mutation](@ref) function for strategies (default: [`nop`](@ref)) - `μ`/`mu`: the number of parents @@ -27,8 +27,8 @@ struct ES{T1,T2,T3,T4} <: AbstractOptimizer metrics::ConvergenceMetrics ES(; initStrategy::AbstractStrategy = NoStrategy(), - recombination::T1 = first, - srecombination::T2 = first, + recombination::T1 = average, + srecombination::T2 = average, mutation::T3 = nop, smutation::T4 = nop, μ::Integer = 1, diff --git a/src/mutations.jl b/src/mutations.jl index ec4ae2a..20aefa0 100644 --- a/src/mutations.jl +++ b/src/mutations.jl @@ -5,14 +5,14 @@ # ====================== """ - nop(s::AbstractStrategy) + nop(x, s::AbstractStrategy; kwargs...) -This is a dummy mutation operator that does not change the strategy. +This is a dummy mutation operator of the recombinant `x` that does not change the strategy `s`. """ nop(recombinant::AbstractVector, s::AbstractStrategy; kwargs...) = recombinant """ - gaussian(x, s::IsotropicStrategy) + gaussian(x, s::IsotropicStrategy; rng=Random.default_rng()) Performs Gaussian isotropic mutation of the recombinant `x` given the strategy `s` by adding Gaussian noise as follows: @@ -27,7 +27,7 @@ function gaussian(recombinant::AbstractVector, s::IsotropicStrategy; end """ - gaussian(x, s::AnisotropicStrategy) + gaussian(x, s::AnisotropicStrategy; rng=Random.default_rng()) Performs Gaussian anisotropic mutation of the recombinant `x` given the strategy `s` by adding Gaussian noise as follows: @@ -43,7 +43,7 @@ function gaussian(recombinant::AbstractVector, s::AnisotropicStrategy; end """ - cauchy(x, s::IsotropicStrategy) + cauchy(x, s::IsotropicStrategy; rng=Random.default_rng()) Performs isotropic mutation of the recombinant `x` given the strategy `s` by adding a noise from the Cauchy distribution as follows: @@ -65,7 +65,7 @@ end # =========================== """ - nop(s::AbstractStrategy) + nop(s::AbstractStrategy; kwargs...) This is a dummy operator that does not change strategy. """ @@ -73,7 +73,7 @@ nop(s::AbstractStrategy; kwargs...) = s """ - gaussian(s::IsotropicStrategy) + gaussian(s::IsotropicStrategy; rng=Random.default_rng()) Performs in-place mutation of the isotropic strategy `s` modifying its mutated strategy parameter ``\\sigma`` with Gaussian noise as follows: @@ -87,7 +87,7 @@ end """ - gaussian(s::AnisotropicStrategy) + gaussian(s::AnisotropicStrategy; rng=Random.default_rng()) Performs in-place mutation of the anisotropic strategy `s` modifying its mutated strategy parameter ``\\sigma`` with Gaussian noise as follows: @@ -107,14 +107,14 @@ end # --------------------- """ - genop(recombinant) + genop(recombinant; kwargs...) This is a dummy mutation operator that does not change the `recombinant`. """ genop(recombinant; kwargs...) = recombinant """ - flip(recombinant) + flip(recombinant; rng=Random.default_rng()) Returns an in-place mutated binary `recombinant` with a bit flips at random positions. """ @@ -131,7 +131,7 @@ end Returns an in-place mutated binary `recombinant` with its bits inverted. """ -bitinversion(recombinant::T) where {T <: AbstractVector{Bool}} = map!(!, recombinant, recombinant) +bitinversion(recombinant::T; kwargs...) where {T <: AbstractVector{Bool}} = map!(!, recombinant, recombinant) # Real-valued mutations diff --git a/src/recombinations.jl b/src/recombinations.jl index 8ec65a6..f4f932a 100644 --- a/src/recombinations.jl +++ b/src/recombinations.jl @@ -1,7 +1,7 @@ # Recombinations # ============== """ - average(population) + average(population; kwargs...) Returns an *one* offspring individual of a multi-parent recombination by averaging `population`. """ @@ -15,7 +15,7 @@ function average(population::Vector{T}; kwargs...) where {T <: AbstractVector} end """ - marriage(population) + marriage(population; rng=Radom.default_rng()) Returns an *one* offspring individual of a multi-parent recombination by random copying from `population`. """ @@ -38,7 +38,7 @@ end Returns the average value of the mutation parameter ``\\sigma`` of strategies `ss`. """ -function average(ss::Vector{<:AbstractStrategy}; kwargs...) +function average(ss::Vector{<:AbstractStrategy}) s = copy(first(ss)) l = length(ss) s.σ = mapreduce(s->s.σ/l, +, ss) diff --git a/test/issues.jl b/test/issues.jl new file mode 100644 index 0000000..3bb0ab5 --- /dev/null +++ b/test/issues.jl @@ -0,0 +1,6 @@ +@testset "Issues" begin + # issue #105 + res = Evolutionary.optimize(sum, ones(5), ES(μ = 40, λ = 100)) + @test minimum(res) == 5 + +end \ No newline at end of file diff --git a/test/runtests.jl b/test/runtests.jl index c2da747..9f87363 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -24,7 +24,8 @@ for tests in [ "onemax.jl", "moea.jl", "regression.jl", - "gp.jl" + "gp.jl", + "issues.jl" ] include(tests) end