在Spyder中运行时,具有SymPy符号的NumPy数组的哈希值不同

brccelvz  于 2023-04-30  发布在  其他
关注(0)|答案(1)|浏览(122)

当我运行 www.example.com ,我在运行之间得到了不同的b的哈希值,而a的哈希值保持不变。
script.py

from sympy import Symbol
import numpy as np

x = Symbol("x")

a = np.array([  1, x]) 
b = np.array([1.0, x])
print(hash(a.tobytes()))
print(hash(b.tobytes()))

运行此脚本将产生以下输出。

In [1]: runfile(./script.py)
-1258340495102975319
3795610135772286033

In [2]: runfile(./script.py)
-1258340495102975319
7432739601143179777

In [3]: runfile(./script.py)
-1258340495102975319
1451381667883822748

In [4]: runfile(./script.py)
-1258340495102975319
2683979045255549228

In [5]: runfile(./script.py)
-1258340495102975319
-345973347917904018

请有人能对这种奇怪的行为给出一些解释,并可能提出一个解决方案,为浮点情况给予一致的哈希。
我尝试在for循环中模拟相同的行为,但在这种情况下,哈希值是一致的。当代码运行多次时,就会出现差异。
我不希望ab的哈希值相同,因为11.0是不同的数据类型,但我希望两者的哈希值在运行过程中保持一致(就像a一样)。
这个问题并不是散列所特有的,tobytes()方法在每次运行时都会给出不同的结果,但散列给出了更明显的差异表示。
编辑:经过更多的测试,我意识到这个问题不仅仅是SymPy特有的,同样的行为也发生在具有对象数据类型的NumPy数组上。例如,print(hash(np.array([1.0], dtype="O").tobytes()))在不同的运行中给出不同的结果。
EDIT2:给出指针的答案仍然有一些无法解释的行为,因为这种行为只特定于对象数据类型的数组。

In [2]: hash(np.array([1.0]).tobytes())
Out[2]: -1405879698645296540

In [3]: hash(np.array([1.0]).tobytes())
Out[3]: -1405879698645296540

In [4]: hash(np.array([1.0]).tobytes())
Out[4]: -1405879698645296540

In [5]: hash(np.array([1.0]).tobytes())
Out[5]: -1405879698645296540

In [6]: hash(np.array([1.0], dtype="O").tobytes())
Out[6]: 7075328050134915067

In [7]: hash(np.array([1.0], dtype="O").tobytes())
Out[7]: -6443853770133964536

In [8]: hash(np.array([1.0], dtype="O").tobytes())
Out[8]: 889083274033361878

In [9]: hash(np.array([1.0], dtype="O").tobytes())
Out[9]: -6819397306369441685
im9ewurl

im9ewurl1#

第1条:Numpy数组只能保存数值。当你把一个syms,或任何其他非数值的对象放入一个数组中,即使是None,数组的dtype将是object,值将是指针。
第2条:数组的哈希值,或者实际上任何正常对象,都取决于值。这意味着具有相同dtype和数值的两个不同数组应该具有相同的散列。
第3项:与ID不同,ID通常在每次运行中被不同地加盐,散列在运行之间被一致地计算。例如,CPython中int的哈希值就是int的值。float的散列在运行之间也是一致的。
您正在创建一对指针数组。数组中1的值是一个指向解释器创建的内部int对象的指针。x也是指针。似乎发生的情况是,第一个数组的元素在脚本运行之间被分配在相同的位置,而float没有。如果你有int s或float s的数组,使用非指针数据类型,数据将被直接散列,所有的散列都是相同的。
要打印数组中的指针值,可以使用一个技巧绕过保护numpy put。a.view(np.uint64)a.astype(np.uint64)由于这些保护措施而无法工作。

In [1]: a = np.empty(2, object); a[0] = 1; a[1] = None

In [2]: a.dtype.itemsize
Out[2]: 8

In [3]: x = np.ndarray(shape=2, dtype=np.uint64, buffer=a)

In [4]: x
Out[4]: array([11476160, 11272160], dtype=uint64)

通过打印原始数组值(指针),您应该能够确认哪些对象被分配在与前一次运行相同的位置。

相关问题