wildart / Evolutionary.jl

Evolutionary & genetic algorithms for Julia
Other
324 stars 60 forks source link

no method matching NLSolversBase.NonDifferentiable #69

Open aadimator opened 3 years ago

aadimator commented 3 years ago

I've been trying to run GA on my custom structure, Organism, but it's giving the following error:

result = Evolutionary.optimize(
        fitness,
        () -> init_organism("msa_data/temp.tfa"),
        GA(
            populationSize = 50,
        ))

Error

MethodError: no method matching NLSolversBase.NonDifferentiable(::typeof(Main.workspace3.fitness), ::Main.workspace3.Organism)

Closest candidates are:

NLSolversBase.NonDifferentiable(::Any, ::Any, !Matched::AbstractArray) at C:\Users\aadim\.julia\packages\NLSolversBase\QPnui\src\objective_types\nondifferentiable.jl:21

NLSolversBase.NonDifferentiable(::Any, ::TF, !Matched::TX, !Matched::Array{Int64,1}) where {TF, TX} at C:\Users\aadim\.julia\packages\NLSolversBase\QPnui\src\objective_types\nondifferentiable.jl:3

NLSolversBase.NonDifferentiable(::Any, ::Any, !Matched::AbstractArray, !Matched::Union{Real, AbstractArray}) at C:\Users\aadim\.julia\packages\NLSolversBase\QPnui\src\objective_types\nondifferentiable.jl:21

...

optimize(::Function, ::Evolutionary.NoConstraints, ::Function, ::Evolutionary.GA, ::Evolutionary.Options{Nothing})@optimize.jl:30
optimize@optimize.jl:13[inlined]
top-level scope@Local: 1

The init_organism function initializes an object of type Organism and returns it, while the fitness function takes an Organism as input and returns a Number as fitness value. I haven't defined the crossover and mutation functions for now, as I only want to see if the GA is being initialized well.

function fitness(organism::Organism)
    sum = 0
    if !ismissing(organism.alignment)
        alignments = collect(values(organism.alignment))
        for i=(1:length(alignments)-1), j=(i+1:length(alignments))
            a = alignments[i]
            b = alignments[j]
            sum += pairwise_score(
                a, b, 
                matrix=organism.scoring_matrix.matrix, 
                gop=organism.gop, gep=organism.gep)
        end
    end
    sum
end

After a thorough search, I'm unable to figure out the way to solve this problem/error. If anyone could give me some helpful pointers to solve this error message, I'd be grateful. Thanks

wildart commented 3 years ago

You need to provide overriding for the NonDifferentiable with the type of your individual, i.e. Organism. Basically, it's a wrapper type that keeps fitness function with its parameter & result in one place. Look how it is done for the BitVector: https://github.com/wildart/Evolutionary.jl/blob/30d677fcfc19d517f2a974a00bafda34656c468c/src/api/types.jl#L113-L120

aadimator commented 3 years ago

Thank you for replying. I've thought (and searched) about it long and hard, but I'm unable to figure out how I'm supposed to approach this, because of the lack of documentation for the JuliaNSolvers and mostly because of my inexperience. I'm quite new to the Julia environment and still trying to figure things out, although I'm hopeful and excited to learn about it more.

wildart commented 3 years ago

I added an example of supervised learning problem by GA optimization of multi-layer perceptrons, see the notebook in examples/MLP.ipynb

It shows how to fill some missing functionality, when the individuals are custom types (not arrays). For starters, you need to create a NonDifferentiable constructor, and make sure that copy/copyto! functions are working on your individual object. Then, write genetic operations which support your object type. In my example, I reused existing operations by writing wrappers, which accept MLP object.