【问题标题】:Python heapq heappush The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()Python heapq heappush 具有多个元素的数组的真值是模棱两可的。使用 a.any() 或 a.all()
【发布时间】:2017-01-23 01:55:06
【问题描述】:

我遇到了heapq 库的错误——尤其是heappush 函数。错误代码(如下)对我没有帮助。

(Pdb) heapq.heappush(priority_queue, (f, depth, child_node_puzzle_state))
*** ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

这是导致问题的 sn-p...

h = compute_heuristic(child_node_puzzle_state, solved_puzzle)
depth = current_node[1] + 1
f = h + depth
heapq.heappush(priority_queue, [f, depth, child_node_puzzle_state])

我应该注意到hdepthintchild_node_puzzle_state 是一个numpy 数组。查看一些调试代码...

(Pdb) child_node_puzzle_state
array([[  5.,   4.,  18.,  15.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,
         99.],
       [ 99.,  10.,   6.,  14.,  12.,  20.,   0.,   0.,   0.,   0.,  99.,
         99.],
       [ 99.,  99.,  11.,  19.,  17.,  16.,   8.,   0.,   0.,  99.,  99.,
         99.],
       [ 99.,  99.,  99.,   2.,   3.,   0.,   0.,   0.,  99.,  99.,  99.,
         99.],
       [ 99.,  99.,  99.,  99.,   1.,  21.,   0.,  99.,  99.,  99.,  99.,
         99.],
       [ 99.,  99.,  99.,  99.,  99.,   9.,  13.,   7.,   0.,   0.,   0.,
          0.]])
(Pdb) child_node_puzzle_state.dtype
dtype('float64')
(Pdb) p h
3
(Pdb) depth
2
(Pdb) f
5
(Pdb) priority_queue
[(5, 2, array([[  9.,  15.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,
         99.],
       [ 99.,  10.,   6.,  14.,   5.,   4.,  18.,   0.,   0.,   0.,  99.,
         99.],
       [ 99.,  99.,  11.,  19.,  17.,  12.,  20.,   8.,   0.,  99.,  99.,
         99.],
       [ 99.,  99.,  99.,  16.,   3.,   0.,   0.,   0.,  99.,  99.,  99.,
         99.],
       [ 99.,  99.,  99.,  99.,   2.,   0.,   0.,  99.,  99.,  99.,  99.,
         99.],
       [ 99.,  99.,  99.,  99.,  99.,   1.,  21.,  13.,   7.,   0.,   0.,


...

(Pdb) len(priority_queue)
9

这是我无法弄清楚的……如果我改变一点点它会起作用——但它在语义上是错误的。这是变化...

h = compute_heuristic(child_node_puzzle_state, solved_puzzle)
depth = current_node[1] + 1
heapq.heappush(priority_queue, (h, depth, child_node_puzzle_state))

你发现区别了吗?而不是计算f = h + depth,我只使用h。它神奇地起作用?

这不可能是大小,因为正如我在调试中展示的那样......

(Pdb) len(priority_queue)
9

这对我来说真的没有意义,所以我将包含更多代码。首先,这是计算h 所需的一切,没有什么奇怪的事情发生,所以我真的怀疑这是问题所在。所有函数都返回整数(尽管它们使用 numpy 数组)...

def tubes_aligned(puzzle_state):

    current_index = 3 #test for index 3
    blue_tube = puzzle_state[3,:]
    len_of_top_tube = len(blue_tube[blue_tube < 99]) - 3
    correct_index = 6 - len_of_top_tube

    found = False
    distance = 3
    for i in range(3):
        if i == correct_index:
            distance = current_index - i
            found = True

    if not found:
        for i in range(5,2,-1):
            if i == correct_index:
                distance = i - current_index

    return distance

def balls_in_top_half(puzzle_state):

    for i in range(6):
        full_tube = puzzle_state[i,:]
        num_balls = full_tube[full_tube < 99]
        num_balls = len(num_balls[num_balls > 0])
        if (6 - i - num_balls) != 0:
            return 1

    return 0

def balls_in_correct_place(puzzle_state, solved_puzzle):
    if is_solved(puzzle_state, solved_puzzle):
        return 0
    else:
        return 1

def compute_heuristic(puzzle_state, solved_puzzle):
    # print "computing heuristic"
    # heuristic (sum all three):
    #     1. how many tubes is the puzzle state from tubes being aligned -- max is 3
    #     2. is there balls in the top portion? 1 -- yes || 0 -- no
    #     3. are there balls in the wrong place in the bottom half? 1 -- yes || 0 -- no
    part_1 = tubes_aligned(puzzle_state)
    part_2 = balls_in_top_half(puzzle_state)
    part_3 = balls_in_correct_place(puzzle_state, solved_puzzle)
    return part_1 + part_2 + part_3

【问题讨论】:

  • 我曾经遇到过这个错误,因为numpy.any()numpy.all() 遮蔽了内置的any()all()。但我明白了,这个错误有很多方法可以出现。如果您发布MVCE,我们也许可以帮助您。
  • @moooeeeep 嗯......为此会做些什么?为什么在我的场景中将h 更改为f 会导致错误?
  • 在需要标量 True/False 的上下文中使用布尔数组(具有 1 个以上元素)时会出现此错误。不管细节如何,heapq 比较本质上都是标量的。因此,将数组放在 heapq 上可能会引发此错误。

标签: python numpy heap


【解决方案1】:

heapq.heappush比较一个数组与堆中的其他数组,如果您推送的元组中的前面元素相等。

这是heappush()的纯Python实现:

def heappush(heap, item):
    """Push item onto heap, maintaining the heap invariant."""
    heap.append(item)
    _siftdown(heap, 0, len(heap)-1)

def _siftdown(heap, startpos, pos):
    newitem = heap[pos]
    # Follow the path to the root, moving parents down until finding a place
    # newitem fits.
    while pos > startpos:
        parentpos = (pos - 1) >> 1
        parent = heap[parentpos]
        if newitem < parent:
            heap[pos] = parent
            pos = parentpos
            continue
        break
    heap[pos] = newitem

实际的实现将在 C 中,这就是为什么您在没有更深入的回溯的情况下得到错误的原因。

注意newitem &lt; parent 的比较;正是 那个比较 引发了异常,因为 numpy array 对象将逐个元素地进行比较,并产生一个具有真假结果的布尔数组。如果您的堆中存在fdepth 相等的状态,则该比较必须比较数组:

>>> import numpy
>>> t1 = (5, 2, numpy.array([9.,  15.]))
>>> t2 = (5, 2, numpy.array([10.,  15.]))
>>> t1 < t2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

对您而言,当您更改元组第一个位置的值时,问题“消失”了,与堆中已有的值相比,前两个值再次唯一。但它实际上并没有解决根本问题。

您可以通过在数组前插入唯一计数(使用itertools.count())来避免此问题:

from itertools import count

# a global
tiebreaker = count()

# each time you push
heapq.heappush(priority_queue, (f, depth, next(tiebreaker), child_node_puzzle_state))

计数器确保元组的前三个元素始终唯一。这也意味着任何后来添加到堆中的与启发式分数 深度上已经存在的状态相匹配的东西都会排在旧的之前。如果你想反转这种关系,你可以使用count(step=-1)

【讨论】:

    猜你喜欢
    • 2019-05-05
    • 2019-10-08
    • 1970-01-01
    • 2021-01-20
    • 2018-03-28
    • 1970-01-01
    • 2021-08-12
    • 2015-09-16
    • 1970-01-01
    相关资源
    最近更新 更多