我定义了一个函数
def enumerateSpin(n):
s = []
for a in range(0,3**n):
ternary_rep = np.base_repr(a,3)
k = len(ternary_rep)
r = (n-k)*'0'+ternary_rep
if sum(map(int,r)) == n:
s.append(r)
return s
我看的是数字0<;=a<;3^N并询问三元表示法中的数字总和是否达到某个值。我首先将数字转换成三元表示的字符串。我之所以填充零,是因为我想存储一个固定长度表示的列表,以便以后用于进一步计算(即两个元素之间的逐位比较)
现在np.base_repr
和sum(map(int,#))
分别在我的计算机上占用大约5个us,这意味着迭代大约需要10个us,我正在寻找一种方法,在这种方法中,您可以完成我所做的事情,但速度要快10倍
(编辑:关于在左侧填充零的注释)
(Edit2:事后看来,最终表示形式最好是整数的元组,而不是字符串)
(编辑3:对于那些想知道的人来说,代码的目的是枚举具有相同总S_z值的自旋-1链的状态。)
您可以使用^{} 生成数字,然后转换为字符串表示形式:
这给了我大约7倍的加速:
在Python 3.9.0(IPython 7.20.0)(Linux)上测试
上面的过程使用
it.product
也生成了我们通过推理知道它们不符合条件的数字(这是所有数字的一半的情况,因为数字的总和必须等于数字的数目)。对于n
位,我们可以计算最终总计为n
的2
、1
和0
位的各种计数。然后我们可以生成这些数字的所有distinct permutations,从而只生成相关数字:特别是对于大量的
n
,这提供了额外的、显著的加速:请注意,上述解决方案
new
和new2
具有O(1)内存缩放(将new
更改为yield
而不是append
)通常,要获取特定基数中的数字,我们可以执行以下操作:
使用
num = 14, base = 3
运行此命令时,我们会得到:这意味着三元中的14是112。
我们可以将其提取到方法
digits(num, base)
中,并且仅在实际需要将数字转换为字符串时使用np.base_repr(a,3)
:为
enumerateSpin(4)
输出:通过将所有计算委托给numpy以利用矢量化处理,可以实现10倍的改进:
其工作原理(例如eSpin(3)):
nums
是一个包含最多3**n的所有数字的数组base3
将其转换为附加维度中的基3位数:matches
标识base3数字之和与n
匹配的列digits
将匹配的列转换为由base3数字组成的以10为基数的数字最后,匹配的(base10)数字被格式化为前导零
性能:
元组版本:
[EDIT]一种更快的方法(比enumerateSpin快40到80倍)
使用动态编程和记忆可以提供更好的性能:
相关问题 更多 >
编程相关推荐