【问题标题】:Fastest method for comparing ranges of multidimensional lists比较多维列表范围的最快方法
【发布时间】:2016-09-27 11:57:24
【问题描述】:

上下文:我正在尝试在未知环境中编写 A* 搜索。为此,我在 2-D 或 3-D 列表(取决于环境)和另一个 n-D 列表中维护环境表示,该列表表示代理对环境的了解。

当代理移动时,我会根据实际环境检查他们周围的区域。如果有差异,他们的地图会更新,然后我再次运行 A*。

问题:检查这两个列表的范围之间是否存在差异的最快方法是什么?

简单的解决方案:

from itertools import product
from random import randint

width, height = 10, 10
known_environment = [[0 for x in range(width)] for y in range(height)]
actual_environment = [[0 for x in range(width)] for y in range(height)]

# Populate with obstacles
for i in xrange(10):
    x = randint(0, len(actual_environment) - 1)
    y = randint(0, len(actual_environment[x]) - 1)
    actual_environment[x][y] += 1

# Run A* and get a path
path = [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4),
        (5, 5), (6, 6), (7, 7), (8, 8), (9, 9)]  # dummy path

# Traverse path, checking for "new" obstacles
for step in path:
    x, y = step[0], step[1]

    # check area around agent
    for (i, j) in product([-1, 0, 1], [-1, 0, 1]):
        # don't bother checking out-of-bounds
        if not 0 <= x + i < width:
            continue
        if not 0 <= y + j < height:
            continue
        # internal map doesn't match real world, update
        if not known_environment[x + i][ y + j] == actual_environment[x + i][ y + j]:
            known_environment[x + i][ y + j] = actual_environment[x + i][ y + j]
            # Re-run A*

这可行,但感觉效率低下。我想我可以用set(known_environment).intersection(actual_environment) 之类的东西替换循环来检查是否存在差异,如果需要,then 更新;但这可能也可以改进。

想法?

编辑:我已切换到 numpy 切片,并使用 array_equal 而不是集合。

# check area around agent
left = x - sight if x - sight >= 0 else 0
right = x + sight if x + sight < width else width - 1
top = y - sight if y - sight >= 0 else 0
bottom = y + sight if y + sight < height else height - 1

known_section = known_environment[left:right + 1, top:bottom + 1]
actual_section = actual_environment[left:right + 1, top:bottom + 1]
if not np.array_equal(known_section, actual_section):
    known_environment[left:right + 1, top:bottom + 1] = actual_section

【问题讨论】:

  • 您有时间查看stackoverflow.com/questions/6105777/… 吗? ;-)
  • @Dilettant,谢谢,但我还需要不同元素矩阵中的 positions 以便我可以更新“地图”。
  • 为什么要使用两个环境?只需在 A* 搜索中使用和修改全局环境。
  • 我还建议使用[[0] * width] * height 而不是那个冗长的环境初始化语句。
  • @EvilTak,我已经切换到 numpy,它允许更好:known_environment = np.zeros(shape=(width, height), dtype=int)

标签: python algorithm performance search optimization


【解决方案1】:

当您使用我对问题的评论中给出的链接中的解决方案概念时,它应该已经快一点了。

我修改/修改了一些给定的代码并尝试了:

#! /usr/bin/env python
from __future__ import print_function
from itertools import product
from random import randint

width, height = 10, 10
known_env = [[0 for x in range(width)] for y in range(height)]
actual_env = [[0 for x in range(width)] for y in range(height)]

# Populate with obstacles
for i in xrange(10):
    x = randint(0, len(actual_env) - 1)
    y = randint(0, len(actual_env[x]) - 1)
    actual_env[x][y] += 1

# Run A* and get a path
path = [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4),
        (5, 5), (6, 6), (7, 7), (8, 8), (9, 9)]  # dummy path


def effective_slices(i_w, j_h):
    """Note: Depends on globals width and height."""
    w, h = width - 1, height - 1
    i_w_p, j_h_p = max(0, i_w - 1), max(0, j_h - 1)
    i_w_s, j_h_s = min(w, i_w + 1), min(h, j_h + 1)
    return slice(i_w_p, i_w_s), slice(j_h_p, j_h_s)


# Traverse path, checking for "new" obstacles
for step in path:
    x, y = step[0], step[1]
    # check area around agent
    dim_w, dim_h = effective_slices(x, y)
    actual_set = set(map(tuple, actual_env[dim_w][dim_h]))
    known_set = set(map(tuple, known_env[dim_w][dim_h]))
    sym_diff = actual_set.symmetric_difference(known_set)
    if sym_diff:  # internal map doesn't match real world, update
        for (i, j) in product(range(dim_w.start, dim_w.stop + 1), 
                              range(dim_h.start, dim_h.stop + 1)):
            if known_env[i][j] != actual_env[i][j]:
                known_env[i][j] = actual_env[i][j]
                # Re-run A*

(已编辑):在急切更新循环中添加了对上述索引的某种重用。

第二次编辑以适应 w.r.t 的评论。更新的问题(参见下面的评论):

查看修改后的问题,即 sn-p 现在与基于 numpy 的实现相关,我建议进行两项更改,至少使代码对我来说更清晰:

  1. 为避免文字 + 1 混乱,通过引入 rightbottom最高 值来解决不包括 stop 的切片问题
  2. minmax定义截面边界框,使关系清晰。

像这样:

# ... 8< - - 
# check area around agent (note: uses numpy)
sight = 1
left, right_sup = max(0, x - sight), min(x + sight + 1, width)
top, bottom_sup = max(0, y - sight), min(y + sight + 1, height)

known_section = known_environment[left:right_sup, top:bottom_sup]
actual_section = actual_environment[left:right_sup, top:bottom_sup]
if not np.array_equal(known_section, actual_section):
    known_environment[left:right_sup, top:bottom_sup] = actual_section
# - - >8 ... 

...或摆脱结肠炎(对不起):

# ... 8< - - 
h_slice = slice(max(0, x - sight), min(x + sight + 1, width))
v_slice = slice(max(0, y - sight), min(y + sight + 1, height))

known_section = known_environment[h_slice, v_slice]
actual_section = actual_environment[h_slice, v_slice]
if not np.array_equal(known_section, actual_section):
    known_environment[h_slice, v_slice] = actual_section
# - - >8 ... 

应该是简明扼要的阅读,在运行时容易和漂亮的操场。

...但是图像处理(例如使用固定掩码)和交错网格处理算法应该比比皆是,以提供现成的解决方案

【讨论】:

  • 我正在使用 numpy 切片和 array_equal 而不是集合。这样我们就避免了创建集合。我现在拥有的(参见编辑)看起来与您的解决方案相似,但我发现您对 max 的使用比我的 if-thens 更优雅。
  • 在我的民间传说中 ;-) 当重复使用同一个切片时,最好为重复出现的一件事引入一个清晰的标记(而不是解析器/阅读器必须结合的字面意思) ) 其次,您可以询问切片问题,例如a_slice.starta_slice.stop 等,它更加通用,因为您可以通过清晰的函数语法(例如范围)动态创建它...如果这可以更好地优化- 我目前不知道,但我建议这样做(也许试试 dis 模块或......)。这是否充分说明了我个人对差异的看法?
猜你喜欢
  • 2012-04-19
  • 1970-01-01
  • 2016-12-13
  • 2021-12-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-06
  • 1970-01-01
相关资源
最近更新 更多