#python #performance #numpy #numba
#python #Производительность #numpy #numba
Вопрос:
Мне нужна быстрая реализация следующей задачи, предпочтительно в виде функции numba. Я беру два случайных целых числа a
amp; b
из списка с именем integerlist
и рассматриваю их двоичное представление длины l
, например a=10->1010
, b=6->0110
. После этого я выполняю равномерный переход между обоими двоичными представлениями, и целочисленное значение результирующего двоичного числа сохраняется в случайной позиции в integerlist
. Равномерная рекомбинация означает, что каждая запись двоичного представления целого числа c
либо берется из записи двоичного представления a
, либо b
с равной вероятностью, например
a=10->1010
b=6 ->0110
1110 ->c=14
Для этого я придумал следующий код, который не очень быстрый. На данный момент я пытаюсь получить numba-версию этой функции, но пока безуспешно. Не могли бы вы помочь?
def recombination(integerlist, l):
N = len(integerlist)
for x1 in range(N):
a = integerlist[random.randint(0, N-1)]
b = integerlist[random.randint(0, N-1)]
binary_a = list(map(int, numpy.binary_repr(a, width=l)))
binary_b = list(map(int, numpy.binary_repr(b, width=l)))
binary_c = [0]*l
for x2 in range(l):
if random.random() <= 0.5:
binary_c[x2] = binary_a[x2]
else:
binary_c[x2] = binary_b[x2]
c = 0
for bit in binary_c:
c = (c << 1) | bit
integerlist[random.randint(0, N-1)] = c
Редактировать: Если я заменю list(map(int, numpy.binary_repr(a, width=l)))
следующей функцией
@nb.njit
def dec_to_binary_fct(a, l):
bin_temp = []
for i in range(l):
i = l-i-1
k = a >> i
if (k amp; 1):
bin_temp.append(1)
else:
bin_temp.append(0)
return bin_temp
Я могу поместить @nb.njit
перед def recombination(integerlist, l):
, которые уже значительно повышают производительность. Мне все еще любопытно, можно ли увеличить производительность.
Ответ №1:
Вот способ вычисления пересечения, который, я уверен, быстрее:
def xover(a, b):
l = max(a.bit_length(), b.bit_length())
return a^((a^b)amp;random.randint(0, (1<<l)-1))
Объяснение:
- сначала мы используем побитовое исключение or, чтобы найти биты, которые отличаются (для других битов не имеет значения, откуда мы их берем, поэтому мы также можем взять их все из a)
- затем мы используем побитовую и случайную маску для удаления в среднем половины из них
- и, наконец, используйте побитовое исключение или снова, чтобы перевернуть оставшиеся биты в a (мы знаем, что в этих позициях перевернутое a равно b)
Комментарии:
1. Это действительно хорошая идея, но немного незавершенная, поскольку она применима только к
l<32
. По крайней мере,l<64
было бы неплохо.2. @HighwayJohn просто измените случайный диапазон. Верхний предел должен быть степенью двойки (минус единица, если вы решите использовать
random
вместоnp.random
). Если вы выходите за рамки 64, я думаю, чтоrandom
модуль, безусловно, лучший выбор, еслиnp.random
он вообще работает. Если вы используете ровно 64 с numpy, обязательно используйтеuint64
3. Вау, отлично, большое спасибо! Я, вероятно, могу это выяснить, но max (), похоже, не поддерживается в numba. Вы случайно не знаете обходной путь?
4. @HighwayJohn Не совсем, нет. Может быть, и я действительно просто предполагаю, что он примет один аргумент последовательности вместо двух отдельных аргументов?
5. Если вы знаете, что все ваши числа меньше некоторого числа,
X
тогда используйте фиксированноеl
. Поскольку вы вычисляете это только один раз, вы можете использовать для этого дорогостоящие функции, подобныеlog2(X)
.