2017-02-14 3 views
1

Может кто-нибудь объяснить, почему следующий код приводит к ValueError?Добавление массива numpy в очередь кучи

import heapq 
import numpy as np 

a = np.ones((2, 2), dtype=int) 

states = [] 
heapq.heappush(states, (0, a)) 
heapq.heappush(states, (0, a.copy())) 

Сообщение об ошибке:

Traceback (most recent call last): 
    File "x.py", line 8, in <module> 
    heapq.heappush(states, (0, a.copy())) 
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all() 

Запуск без добавив a.copy() в кучу работает отлично, второй/последующий один почему-то проблема. Я понимаю, что существует неизвестный аспект истины с массивом [True, False, True] и что невозможно определить ни одного True или False, но зачем это делать heapq? Особенно только во втором случае?

+1

heapq необходимо сравнить элементы кучи. Кучевые элементы являются кортежами, а первые записи кортежей равны, поэтому он сравнивает второй элемент. Сравнение вторых элементов не приводит к чему-то, что можно интерпретировать как логическое. – user2357112

+0

Обратите внимание, что 'heapq.heappush (heap, (x, y))' не означает "push вещь' y' с приоритетом 'x'; это означает «push thing» (x, y) '. У нас нет отдельных приоритетов и элементов; у нас просто есть элементы. – user2357112

ответ

2

TL; DR: Поскольку массивы numpy не могут быть переведены в логическое, если они содержат более одного элемента.


Некоторые сведения о кучах:

Кучи «порядок» их содержимое (поэтому детали должны реализовать < но это деталь реализации).

Вы, однако, вставляете элементы в heap, создавая tuple s для элементов, где первые элементы являются некоторым значением, а второе - массивом.

Сравнение кортежей сначала проверяет, совпадают ли первые элементы, и если они проверяют, совпадают ли эти два элемента и так далее, пока они не станут равными, тогда он будет проверять, меньше ли это (когда операция была <) или больше (для >). Однако кортежи реализованы в C, а проверка == немного отличается от таковой в Python. Он использует PyObject_RichCompareBool. Особенно «примечание» важно здесь

Если o1 и o2 являются тот же объект, PyObject_RichCompareBool() всегда возвращает 1 для Py_EQ и 0 для Py_NE.

Теперь давайте перейдем к Numpy массивов:

Вы не можете преобразовать numpy.array к bool, если она содержит более одного элемента:

>>> arr = np.array([1,2,3]) 
>>> bool(arr) 
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all() 

if проверка неявно преобразует условие a boolean:

>>> if arr: pass 
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all() 

Даже после сравнения numpy-arra YS они все еще Numpy массивы:

>>> arr > arr 
array([False, False], dtype=bool) 
>>> arr == arr 
array([ True, True], dtype=bool) 

Таким образом, они не могут быть оценены с ==:

>>> if arr == arr: pass 
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all() 

Таким образом, вы не можете преобразовать Numpy-массивы с более чем одного элемента в булево! Однако теперь идет интересная часть: heapq -модуль использует PyObject_RichCompareBool(), поэтому он может проверить, равны ли два массива, но , если и только если одинаковы!

Вот почему он работает с такой же массив передается в несколько раз, но он терпит неудачу, когда вы копируете его:

>>> arr is arr 
True 
>>> arr is arr.copy() 
False 
+0

«Кучи стабильны и« упорядочивают »их содержимое ... что означает, что предметы, сравнивающие одинаковые, будут в том же порядке, в каком они были изначально» - о чем вы говорите? heapq не гарантирует этого вообще, и он не выполняет описанную вами вещь кортежа value-position. Если вы хотите этого поведения, вы должны сделать это сами. – user2357112

+0

@ user2357112 Спасибо за комментарий, я исправил ответ. – MSeifert

Смежные вопросы