wildart / Evolutionary.jl

Evolutionary & genetic algorithms for Julia
Other
328 stars 59 forks source link

[GA] InexactError when the target function returns Float and the inputs genes are Integers #83

Closed ndgnuh closed 3 years ago

ndgnuh commented 3 years ago

I met this issue while trying to use GA to solve the travelling salesman problem. The code to reproduce this issue is fairly simple, so I'll just paste it here:


using Evolutionary
using Random

struct TSPTargetFunction{T} <: Function
    weights::Matrix{T}
    function TSPTargetFunction(W::AbstractMatrix)
        new{eltype(W)}(W)
    end
end

function (f::TSPTargetFunction)(x)
    (
        f.weights[last(x), first(x)] +
        sum(f.weights[i, j] for (i, j) in zip(x, Iterators.drop(x, 1)))
    )
end

function solve_tsp(
    W::AbstractMatrix;
    population_size = 100,
    options_kwargs = Dict{Symbol,Any}(),
)
    f = TSPTargetFunction(W)
    options =
        Evolutionary.Options(iterations = 2000, successive_f_tol = 30, options_kwargs...)
    optimizer = GA(;
        populationSize = population_size,
        selection = rouletteinv,
        crossover = OX2, # not really, but not relevant
        mutation = x -> x[x], # not really, but not relevant
        mutationRate = 0.5,
        crossoverRate = 0.5,
        epsilon = population_size ÷ 5,
    )
    n = size(W, 1)
    initial_population = [randperm(n) for _ = 1:population_size]
    Evolutionary.optimize(f, initial_population, optimizer, options)
end

solve_tsp(rand(4, 4)) # Error
wildart commented 3 years ago

Yep, it's a bug. The initialization of the NonDifferentiable should be done better. Currently, the result of the objective function must have the same type as an element of the individual of the population. Otherwise, multiple functions has to be overridden to make it work. That is wrong.

ndgnuh commented 3 years ago

Thanks, this workds for me (and shouldn't break the API)

function initialize_objective(f, x::AbstractArray{T}, S = typeof(f(x))) where T
    NonDifferentiable{S,typeof(x)}(f, zero(S), zeros(T, length(x)), [0,])
end
initialize_objective(f, first(individual))