Abstract Type Number does´t recognize Int64 as suitable type

I have to question to the following code:

  1. I get an MethodError message if I run the code below:
    “LoadError: MethodError: no method matching ox1(::Array{Int64,2}, ::Array{Int64,2})”
    But actually I don´t understand why, because Int64 is a subtype of Number. What I´m doing wrong?

  2. Is there a way that randperm returns an array of size Array{Int64,2} instead of reshaping it? Or how can I code my methods that they work on both Array{Number,1} and Array{Number,2} without overloading the method and without performance loss?

using Random
using Crossover

# Order crossover
v1 = reshape(randperm(2000), 2000, 1)
v2 = reshape(randperm(2000), 2000, 1)

@time c1, c2 = Crossover.ox1(v1, v2)

module Crossover

# Order crossover
function ox1(v1::Array{Number,2}, v2::Array{Number,2})
    s = length(v1)
    from, to = rand(1:s, 2)
    # while from == to
    #     from, to = rand(1:s, 2)
    # end
    from, to = from > to ? (to, from)  : (from, to)

    c1 = zeros(Int64, size(v1))
    c2 = zeros(Int64, size(v2))
    # Swap
    c1[from:to] = v2[from:to]
    c2[from:to] = v1[from:to]
    # Fill in from parents
    k = to+1 > s ? 1 : to+1 #child1 index
    j = to+1 > s ? 1 : to+1 #child2 index
    for i in vcat(to+1:s,1:from-1)
        while in(v1[k],c1)
            k = k+1 > s ? 1 : k+1
        end
        c1[i] = v1[k]
        while in(v2[j],c2)
            j = j+1 > s ? 1 : j+1
        end
        c2[i] = v2[j]
    end
    return c1, c2
end

end

Try ox1(v1::Array{<:Number,2}, v2::Array{<:Number,2}). Then the concrete type can match the prescribed argument type.

3 Likes

Are you sure that you even need those type signatures? Now, you are disallowing most types of matrices, only the standard Array{..., 2} matrix type will work. No symmetric or sparse matrices, no transposed matrices, etc. etc.

Maybe you should use AbstractMatrix instead? Or maybe even drop the whole signature?

1 Like

I´m not sure. I´m a beginner in julia. I just know, that the method will only and should only works on permutations. So one dimensional vectors. But I don´t know when a method return arrays as Array{…,2} or Array{…,1}. Furthermore i.e. the permutation array is just one array of multiple arrays, which are gathered in another array (see the code eyample below). This is the reason why choose Number and not Int64. I read the performance of the code should be better if not so many types have to be supported. So Any or AbstractMatrix would be slower than Array{Number,2}?

Example:

parms::Array{Array{Number,2},1}

parms = [FloatArray, IntegerArray, PermutationArray, ...]

The function type signature makes no difference for performance, it just limits what sort of inputs that will be accepted. AbstractMatrix will be exactly as fast as just Matrix, because the compiled codes are identical. You can just drop the signature completely and get precisely the same performance.

This is a bit confusing, your code seems to work on matrices, not vectors.

2 Likes

This is really good to know :slight_smile:

I´m looping over it. Parms is more a list of arrays. I.e. with parms[1] you will get the FloatArray, which for example a vector of random float numbers and with parms[3] you will get the PermutationArray, which contains a permutation of a vector. They are separate parameters, which will be optimized by an evolutionary algorithm

Ah, ok. If you know and require that each element should be a matrix, then perhaps a good function signature would be

function ox1(v1::AbstractMatrix, v2::AbstractMatrix)

I wouldn’t bother with specifying number types, unless you have several different versions of ox1 with different behaviours for different types of numbers.

I see something odd in your code, though:

c1 = zeros(Int64, size(v1))
c2 = zeros(Int64, size(v2))
# Swap
c1[from:to] = v2[from:to]
c2[from:to] = v1[from:to]

This will only work if v1 and v2 contain numbers that can be converted to Int, such as 2.0, 6//2, 3+0im etc. Is this really what you want? It will fail in most cases, apparently.

ox1 is the order crossover 1. It creates with two parent permutations two child permutations, which have genes of their parents. So the method is just suited for permutations, which are in integer.

In that case, I would consider limiting the types of the matrix elements.

If the algorithm makes no sense except for integers it can be nice to make that clear by only defining the function for the right kind of types. It’s not necessary, but it can make it clearer to the user what’s going on. If you allow Number, you sort of signal to the user that the algorithm makes sense for all kinds of numbers.

For example:

function ox1(v1::AbstractMatrix{<:Integer}, v2::AbstractMatrix{<:Integer})

and then

c1 = zero(v1)
c2 = zero(v2)

I recommend Matrix over Array{..., 2} because it’s more readable, but means the same thing.

1 Like

Thanks for your help. I allowed number, because parms is Array{Array{Number, 2}, 1} . I will try your advises, thanks.