From b618075fe0c539e7c4c17c41057a2f30405d136c Mon Sep 17 00:00:00 2001 From: Andrew Haselgrove Date: Mon, 30 Sep 2019 15:31:55 +1000 Subject: [PATCH 1/5] Fix bug with array allocation for tournament selection --- src/selections.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/selections.jl b/src/selections.jl index 23234a5..0517952 100644 --- a/src/selections.jl +++ b/src/selections.jl @@ -44,7 +44,7 @@ function sus(fitness::Vector{<:Real}, N::Int) P = F/N start = P*rand() pointers = [start+P*i for i = 0:(N-1)] - selected = Array{Int}(undef, N) + selected = Vector{Int}(undef, N) i = c = 1 for P in pointers while sum(fitness[1:i]) < P @@ -65,10 +65,10 @@ function truncation(fitness::Vector{<:Real}, N::Int) end # Tournament selection -function tournament(groupSize :: Int) +function tournament(groupSize::Int) @assert groupSize > 0 "Group size must be positive" function tournamentN(fitness::Vector{<:Real}, N::Int) - selection = fill(0,N) + selection = Vector{Int}(undef, N) nFitness = length(fitness) @@ -99,7 +99,7 @@ end # Utils: selection function pselection(prob::Vector{<:Real}, N::Int) cp = cumsum(prob) - selected = Array{Int}(undef, N) + selected = Vector{Int}(undef, N) for i in 1:N j = 1 r = rand() From a70074c170b38c1974ca0e9bf39ae392ecbd658b Mon Sep 17 00:00:00 2001 From: Andrew Haselgrove Date: Mon, 30 Sep 2019 16:19:21 +1000 Subject: [PATCH 2/5] Refactor vlookup functionality out of pselection and add probability assertion --- src/selections.jl | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/selections.jl b/src/selections.jl index 0517952..973235a 100644 --- a/src/selections.jl +++ b/src/selections.jl @@ -98,16 +98,24 @@ end # Utils: selection function pselection(prob::Vector{<:Real}, N::Int) - cp = cumsum(prob) selected = Vector{Int}(undef, N) + + cp = cumsum(prob) + @assert cp[end] ≈ 1 "Sum of probability vector must equal 1" + for i in 1:N - j = 1 - r = rand() - while cp[j] < r - j += 1 - end - selected[i] = j + selected[i] = vlookup(cp, rand()) end return selected end +# Utils: vlookup +function vlookup(range::Vector{<:Number}, value::Number) + for i in eachindex(range) + if range[i] >= value + return i + end + end + + return -1 +end From aa045ccde8e16e7b5b7859b0fce9807e9b1bb7bd Mon Sep 17 00:00:00 2001 From: Andrew Haselgrove Date: Mon, 30 Sep 2019 16:42:28 +1000 Subject: [PATCH 3/5] Refactor names for clarity --- src/selections.jl | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/selections.jl b/src/selections.jl index 973235a..ee03644 100644 --- a/src/selections.jl +++ b/src/selections.jl @@ -1,4 +1,4 @@ -# GA seclections +# GA selections # ============== # Rank-based fitness assignment @@ -7,12 +7,14 @@ function ranklinear(sp::Float64) @assert 1.0 <= sp <= 2.0 "Selective pressure has to be in range [1.0, 2.0]." function rank(fitness::Vector{<:Real}, N::Int) λ = length(fitness) - idx = sortperm(fitness) - ranks = zeros(λ) + rank = sortperm(fitness) + + prob = Vector{Float64}(undef, λ) for i in 1:λ - ranks[i] = ( 2 - sp + 2*(sp - 1)*(idx[i] - 1) / (λ - 1) ) / λ + prob[i] = ( 2.0- sp + 2.0*(sp - 1.0)*(rank[i] - 1.0) / (λ - 1.0) ) / λ end - return pselection(ranks, N) + + return pselection(prob, N) end return rank end @@ -21,13 +23,10 @@ end function uniformranking(μ::Int) function uniformrank(fitness::Vector{<:Real}, N::Int) λ = length(fitness) - idx = sortperm(fitness, rev=true) - @assert μ < λ "μ should be less then $(λ)" - ranks = similar(fitness, Float64) - for i in 1:μ - ranks[idx[i]] = 1/μ - end - return pselection(ranks, N) + @assert μ < λ "μ should equal $(λ)" + + prob = fill(1/μ, μ) + return pselection(prob, N) end return uniformrank end @@ -40,11 +39,13 @@ end # Stochastic universal sampling (SUS) function sus(fitness::Vector{<:Real}, N::Int) + selected = Vector{Int}(undef, N) + F = sum(fitness) P = F/N + start = P*rand() pointers = [start+P*i for i = 0:(N-1)] - selected = Vector{Int}(undef, N) i = c = 1 for P in pointers while sum(fitness[1:i]) < P @@ -53,6 +54,7 @@ function sus(fitness::Vector{<:Real}, N::Int) selected[c] = i c += 1 end + return selected end From 4a80b36596e8ae640ff7c34d61d57a47493f79b5 Mon Sep 17 00:00:00 2001 From: Andrew Haselgrove Date: Mon, 30 Sep 2019 16:51:21 +1000 Subject: [PATCH 4/5] Simplify uniformranking --- src/Evolutionary.jl | 2 +- src/selections.jl | 19 ++++++++++--------- test/selections.jl | 7 +++---- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Evolutionary.jl b/src/Evolutionary.jl index 691402d..c5f4989 100644 --- a/src/Evolutionary.jl +++ b/src/Evolutionary.jl @@ -12,7 +12,7 @@ using Random discrete, waverage, intermediate, line, pmx, ox1, cx, ox2, pos, # GA selections - ranklinear, uniformranking, roulette, sus, tournament, truncation, + ranklinear, rankuniform, roulette, sus, tournament, truncation, # Optimization methods es, cmaes, ga diff --git a/src/selections.jl b/src/selections.jl index ee03644..298ac85 100644 --- a/src/selections.jl +++ b/src/selections.jl @@ -8,7 +8,7 @@ function ranklinear(sp::Float64) function rank(fitness::Vector{<:Real}, N::Int) λ = length(fitness) rank = sortperm(fitness) - + prob = Vector{Float64}(undef, λ) for i in 1:λ prob[i] = ( 2.0- sp + 2.0*(sp - 1.0)*(rank[i] - 1.0) / (λ - 1.0) ) / λ @@ -20,15 +20,16 @@ function ranklinear(sp::Float64) end # (μ, λ)-uniform ranking selection -function uniformranking(μ::Int) - function uniformrank(fitness::Vector{<:Real}, N::Int) - λ = length(fitness) - @assert μ < λ "μ should equal $(λ)" +function rankuniform(fitness::Vector{<:Real}, N::Int) + μ = N + λ = length(fitness) + @assert μ <= λ "μ must be ≤ λ = $(λ)" + + prob = zeros(λ) + rank = sortperm(fitness, rev=true) + prob[rank[1:μ]] .= 1/μ - prob = fill(1/μ, μ) - return pselection(prob, N) - end - return uniformrank + return pselection(prob, N) end # Roulette wheel (proportionate selection) selection diff --git a/test/selections.jl b/test/selections.jl index 3df7fbb..8e96eef 100644 --- a/test/selections.jl +++ b/test/selections.jl @@ -11,10 +11,9 @@ end @testset "Uniform" begin - s = uniformranking(2) - @test sort(unique(s([1.0,2.0,3.0], 10))) == [2,3] - @test sort(unique(s([5,2,3], 5))) == [1,3] - @test_throws AssertionError s([1.,2.], 2) + @test sort(unique(rankuniform([1.0,2.0,3.0], 2))) == [2,3] + @test sort(unique(rankuniform([1,2,3], 2))) == [2,3] + @test_throws AssertionError rankuniform([1.,2.], 3) end @testset "Roulette" begin From ac4398e620916cee86cfd171f643526bcffcb01f Mon Sep 17 00:00:00 2001 From: Andrew Haselgrove Date: Mon, 30 Sep 2019 17:05:43 +1000 Subject: [PATCH 5/5] Improve coverage of selections --- test/rastrigin.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/rastrigin.jl b/test/rastrigin.jl index 59df6a1..68ec846 100644 --- a/test/rastrigin.jl +++ b/test/rastrigin.jl @@ -38,7 +38,7 @@ test_result(result, fitness, N, 1e-1) # Testing: GA - selections = [roulette, sus, ranklinear(1.5)] + selections = [roulette, sus, ranklinear(1.5), rankuniform, tournament(4)] crossovers = [discrete, intermediate(0.), intermediate(0.25), line(0.2)] mutations = [domainrange(fill(0.5,N)), domainrange(fill(1.0,N))]