In case of differential evolution, during mutation, the formula that is used most often is

arr[a] = (arr[b] + M * (arr[c] - arr[d])) % arr.shape[1]

Where
arr is a 2d array consisting of non-negative integers such that all elements in each row are unique,
a represents each row of arr,
M is the mutation constant ranging between 0 and 2 and
b, c and d are 3 unique random numbers.

However, on using this formula, I see that arr[a] has duplicate values based on the values of arr[b], arr[c] and arr[d]. I wish to have only unique numbers in arr[a]. How is it possible using Numpy?

e.g.

arr[a] = [2, 8, 4, 9, 1, 6, 7, 3, 0, 5]
arr[b] = [3, 5, 1, 2, 9, 8, 0, 6, 7, 4]
arr[c] = [2, 3, 8, 4, 5, 1, 0, 6, 9, 7]
arr[d] = [6, 1, 9, 2, 7, 5, 8, 0, 3, 4]

On applying the formula, arr[a] becomes [9, 7, 0, 4, 7, 4, 2, 2, 3, 7]. But I want it to have only unique numbers between 0 and arr.shape[1]. I am open to modifying the mutation function if needed if M, arr[b], arr[c] and arr[d] are all used meaningfully.

3 Answers

1
jdehesa On Best Solutions

This is a rather different approach to the problem, but since you seem to be working with permutations, I am not sure numerical differences are that meaningful. You can however see the problem in terms of permutations, that is, reordering of vectors. Instead of the difference between two vectors, you may consider the permutation that takes you from one vector to the other, and instead of the addition of two vectors, you may consider applying a permutation to a vector. If you want to have an M parameter, maybe that could be the number of times you apply the permutation? (assuming that is a non-negative integer)

Here is the basic idea of how you could implement this:

import numpy as np

# Finds the permutation that takes you from vector a to vector b.
# Returns a vector p such that a[p] = b.
def permutation_diff(a, b):
    p = np.zeros_like(a)
    p[a] = np.arange(len(p), dtype=p.dtype)
    return p[b]

# Applies permutation p to vector a, m times.
def permutation_apply(a, p, m=1):
    out = a.copy()
    for _ in range(m):
        out = out[p]
    return out

# Combination function
def combine(b, c, d, m):
    return permutation_apply(b, permutation_diff(d, c), m)

# Test
b = np.array([3, 5, 1, 2, 9, 8, 0, 6, 7, 4])
c = np.array([2, 3, 8, 4, 5, 1, 0, 6, 9, 7])
d = np.array([6, 1, 9, 2, 7, 5, 8, 0, 3, 4])
m = 1
a = combine(b, c, d, m)
print(a)
# [2 7 0 4 8 5 6 3 1 9]

Since you are working with many vectors arranged in a matrix, you may prefer vectorized versions of the above functions. You can have that with something like this (here I assume M is a fixed parameter for the whole algorithm, not per individual):

import numpy as np

# Finds the permutations that takes you from vectors in a to vectors in b.
def permutation_diff_vec(a, b):
    p = np.zeros_like(a)
    i = np.arange(len(p))[:, np.newaxis]
    p[i, a] = np.arange(p.shape[-1], dtype=p.dtype)
    return p[i, b]

# Applies permutations in p to vectors a, m times.
def permutation_apply_vec(a, p, m=1):
    out = a.copy()
    i = np.arange(len(out))[:, np.newaxis]
    for _ in range(m):
        out = out[i, p]
    return out

# Combination function
def combine_vec(b, c, d, m):
    return permutation_apply_vec(b, permutation_diff_vec(d, c), m)

# Test
np.random.seed(100)
arr = np.array([[2, 8, 4, 9, 1, 6, 7, 3, 0, 5],
                [3, 5, 1, 2, 9, 8, 0, 6, 7, 4],
                [2, 3, 8, 4, 5, 1, 0, 6, 9, 7],
                [6, 1, 9, 2, 7, 5, 8, 0, 3, 4]])
n = len(arr)
b = arr[np.random.choice(n, size=n)]
c = arr[np.random.choice(n, size=n)]
d = arr[np.random.choice(n, size=n)]
m = 1
arr[:] = combine_vec(b, c, d, m)
print(arr)
# [[3 6 0 2 5 1 4 7 8 9]
#  [6 1 9 2 7 5 8 0 3 4]
#  [6 9 2 3 5 0 4 1 8 7]
#  [2 6 5 4 1 9 8 0 7 3]]
1
Community On

Try to do this:

list(set(arr[a])) 
0
Community On

here is a example what could do:

array = np.array([9, 7, 0, 4, 7, 4, 2, 2, 3, 7])
shape = array.shape[0]
array = list(set(array))
for i in range(shape):
    if i not in array:
        array.append(i)
array = np.array(array)

If you want to fill in the index of the numbers are duplicate, the logical is a little diffent. But the idea is that. I hope I helped you.