【问题标题】:How to do 1D discrete collision detection as efficiently as possible?如何尽可能高效地进行一维离散碰撞检测?
【发布时间】:2021-01-11 14:11:14
【问题描述】:

我有以下情况。在离散域 0、1、...、L 上有 M 个独立的随机游走者。我们对 N 个相同的域执行此操作。这会产生一个矩阵X,其中X[i, j] 是walker i 在域j 上的位置。为了进行随机步骤,我向矩阵X 添加了一个具有随机+1 和-1 的形状相同的矩阵。然后我处理边缘。这很好用。

但是,我想将此模型扩展为具有不能相互穿过的固体粒子。这在 2 种情况下显示。

  1. 一个粒子在i 位置,第二个在i+1 位置。第一个粒子向右移动,第二个向左移动。
  2. 一个粒子在i 位置,第二个在i+2 位置。第一个粒子向右移动,而第二个粒子向左移动。

如果我独立完成所有步骤,我可以手动检查每个步骤,看看它是否合法。但是,O(M^2N) 的性能很差。是否有更有效的方法来检测哪些矩阵元素对X[i,j], X[k, j] 导致两个粒子相互穿过,最好以矢量化方式?这样,我可以让模拟跳过这些步骤。

【问题讨论】:

  • 案例 1 和 2 的预期行为是什么?您是要采样直到没有碰撞,还是要手动解决?即第一个步行者走了,然后第二个步行者向另一个方向移动?
  • 我觉得最简单的方法就是在那个时间步不更新这两个步行者。
  • 你有进步吗?

标签: python numpy collision-detection random-walk discrete-space


【解决方案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)

【讨论】:

    猜你喜欢
    • 2012-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多