Как сделать 1D дискретное обнаружение столкновений максимально эффективным?
У меня следующая ситуация. В дискретной области 0, 1, ..., L находится M независимых случайных блуждающих людей. Мы делаем это для N одинаковых областей. В результате получается матрица
X
где
X[i, j]
это позиция ходока
i
в домене
j
. Чтобы сделать случайный шаг, я добавляю матрицу одинаковой формы со случайными +1 и -1 к матрице
X
. Затем занимаюсь краями. Это хорошо работает.
Однако я хочу расширить эту модель, чтобы иметь твердые частицы, которые не могут проходить друг через друга. Это показано в 2 случаях.
- Одна частица находится в позиции
i
, второй находится на позицииi+1
. Первая частица движется вправо, а вторая - влево. - Одна частица находится в позиции
i
, второй находится на позицииi+2
. Первая частица движется вправо, а вторая частица движется влево.
Если я выполняю все шаги независимо, я могу проверять каждый шаг вручную, чтобы убедиться, что это законный шаг. Однако это плохо
O(M^2N)
спектакль. Есть ли более эффективный способ определить, какие пары элементов матрицы
X[i,j], X[k, j]
приведет к тому, что две частицы будут проходить друг через друга, желательно векторизованным образом? Таким образом, я могу заставить симуляцию пропустить эти шаги.
1 ответ
Я предполагаю, что для этого вам нужно использовать какую-то форму циклов, но, возможно, это поможет:
import numpy as np
import matplotlib.pyplot as plt
L = 50
N = 30
W = 20
n_steps = 1000
# Initialize all walkers on the left side
wn0 = np.arange(W)[:, np.newaxis].repeat(N, axis=1)
# Set up the plot
fig, ax = plt.subplots()
worlds = np.zeros((N, L))
worlds[np.arange(N)[np.newaxis, :], wn0] = np.arange(W)[:, np.newaxis]
h = ax.imshow(worlds, cmap='gray_r') # cmap='tab20')
ax.set_xlabel('Distance in 1D World')
ax.set_ylabel('Ensemble of Worlds')
for _ in range(n_steps):
r = np.where(np.random.random(wn0.shape) < 0.5, 1, -1)
wn1 = wn0 + r
wn1 = np.clip(wn1, 0, L-1)
# Case 1
rest_mat = np.zeros_like(wn0, dtype=bool)
for i in range(W):
for j in range(i+1, W):
rest_mat[[[i], [j]], np.logical_and(wn0[i] == wn1[j], wn1[i] == wn0[j])] = True
wn1[rest_mat] = wn0[rest_mat]
# Case 2, go from 0->W and than from W->0 to make sure all duplicates are gone
for i in np.hstack((range(W), range(W)[-2::-1])):
temp = (wn1[i] == wn1).sum(axis=0) > 1
wn1[i, temp] = wn0[i, temp]
# for wn1_j in wn1.T: Check if there are collisions
# assert len(np.unique(wn1_j)) == W
wn0 = wn1
worlds = np.zeros((N, L))
worlds[np.arange(N)[np.newaxis, :], wn1] = np.arange(W)[:, np.newaxis]
h.set_data(worlds)
plt.pause(0.1)