Python - 生成一个数组,其中元素是可变参数的函数,而无需每次都构建数组

Python - Generate an array where elements are a function of a varying parameter, without building the array each time

提问人:MrTLane 提问时间:8/21/2018 最后编辑:MrTLane 更新时间:8/22/2018 访问量:524

问:

TLDR我怎样才能生成一个数组,其元素依赖于某个任意(浮点数)值 k,而不必在每次更改 k 值时都经历从头开始构建数组的极其耗时的过程。

我想要实现的目标如下所示:

Intended structure of the code

我正在 2D 晶格(N x N numpy 数组)的原子基中生成一个巨大的哈密顿量。填充此阵列需要多次比较原子位点的位置 (xyz),以用于我想要包含的每种不同耦合类型,随着系统规模的增长,这将变得非常耗时。(通常为 N > 16,000 个站点)。

这个数组的元素依赖于其他一些浮点类型变量 k(在程序的物理上下文中,这是一个我想迭代的量子计数数)。我需要多次计算这个数组,范围为 1000 k。

即生成 256,000,000 个元素数组 1000 次......欧元

目前,每次更改为新的 k 值时,我都必须创建数组,这显然是非常低效的。它的基本结构看起来(非常一般)是这样的:

class Device():

    def __init__(self, xyz, energy, ... other input parameters ...):

        self.xyz = xyz           # N x 3 array of positions
        self.energy = energy     # Length N list of energies
        # + A range of other parameters that define the device


     # -------- OTHER OPERATIONS ON THE DEVICE -------- #


     def get_H(self, k):
        """ Get the Hamiltonian for a given k - value """

        # Initialise the N x N array
        h = np.zeros((len(self.xyz), len(self.xyz)))

        # - Fill THE HAMILTONIAN BY COMPARING ALL ATOMIC POSITIONS IN self.xyz - #

        return h

这需要我每次都调用整个施工过程。

我想知道是否有办法生成一次这个数组,k 被保留为一个自由参数,然后可以稍后填充。即返回一个数组,它是 k 的函数。优先级是只需要构造一次数组,因为测试表明这占用了我总运行时间的很大一部分。

下面是一个最小的(非工作)示例,说明我希望通过作用于测试数组来实现的目标。我想使哈密顿量成为一个对象变量,而不是一个每次都必须制作的方法,但对 k 有一定的依赖性(我意识到这在语法上将是灾难性的,但希望这将是一个答案的良好开端)。

class Test_device():

def __init__():

    self.get_H = self.make_H()

def make_H(self):

    h = np.linspace(1,9,9).reshape((3,3)) # Test array

    # The below clearly will not work because k is not defined, but this is
    # where I want to achieve this

    h[1,1] += k # Give some k-dependence to the middle element of the array

    def ham(k, h = h):

        # Somehow set the value of k in h

        return h

    return ham

然后我将通过以下方式访问它

device = Test_device()
device.get_H(k = k_value)

提前致谢!

数组 python-3.x free-variable

评论

0赞 jtlz2 8/21/2018
我喜欢这个问题,可能会有所帮助,但我不清楚你的绊脚石到底是什么 - 是你只想初始化哈密顿数组一次,然后使用任意函数依赖性来动态填充它吗?为什么不能有更新方法?kDevice
0赞 MrTLane 8/21/2018
生成数组并填充数组的过程每次都是相同的(对于给定的格结构),但每次迭代时 k 的值都不同。从本质上讲,我想要一个只是 k 函数的数组作为我的 make_H() 方法的输出
0赞 jtlz2 8/22/2018
函数只是一个python函数吗?k
0赞 jtlz2 8/22/2018
你有没有看过例如 docs.scipy.org/doc/numpy/reference/generated/...
0赞 MrTLane 8/22/2018
是的。但是决定应该在数组中的位置的函数是时间昂贵的部分,我只想做一次,而不是像现在这样每次。k

答:

0赞 eatmeimadanish 8/21/2018 #1

这不是一个工作示例,但是......

class Test_device():

    def __init__(self, h):
        self.k = 0
        self.h = h

    def get_H(self):

        self.h = np.linspace(1,9,9).reshape((3,3)) # Test array

        # The below clearly will not work because k is not defined, but this is
        # where I want to achieve this

        self.h[1,1] += self.k # Give some k-dependence to the middle element of the array

    def ham(self):

        # Somehow set the value of k in h
        return self.h

你可以做这样的事情:

device = Test_Device(10)
device.get_H()
device.h = 12
device.get_H()
h = device.ham()

您可以随时更改 h 或 k,只需更改类中的值即可,例如 。k也一样。device.h = 14

评论

0赞 MrTLane 8/21/2018
这里的问题是 get_H() 每次仍然必须经历生成数组的过程。在实践中,我写成 h[1,1] += k 的行大约有 200 行代码,跨越 4 个不同的方法,每个方法都用于唯一的耦合类型。鉴于 h 是一个数组,我也不确定为什么要用 int 值初始化它。你是想通过Test_device k吗?
1赞 MrTLane 8/21/2018
作为附加评论,我不想让 k 成为类的属性,因为它不是一个物理量,因此不属于这里。(我是一名物理学家,所以从编码的角度来看,这种事情可能比它应该更困扰我XD)
0赞 eatmeimadanish 8/23/2018
老实说,我无法理解您的初始代码示例。我只是给你一个关于如何在执行过程中修改值的想法。
0赞 jtlz2 8/22/2018 #2

仔细想想,我认为这不是你想要的。而是尝试:np.fromfunction()

import numpy as np

class Test_device(object):

    def __init__(self, h_shape):
        self.h_shape = h_shape

        # Create array once
        self.h = np.linspace(1, h_shape[0] ** 2, h_shape[1] ** 2).reshape(self.h_shape)

    def get_H(self, k, locn=(1, 1)):
        self.h[locn] += k  # Give some k-dependence to the middle element of the array

        # Somehow set the value of k in h
        pass

在下文中,初始化设备一次(给定 的预期形状)。然后选择一个(和一个位置,如果你愿意)。然后调用 的方法。 从不归因于 ,但如果您愿意,可以归因于 (如 Eatmeinadanish 所述)。hklocnget_Hdevicekdeviceself.k=k

然后,您可以随时访问。device.h

h_shape = (3, 3)
device = Test_device(h_shape)
k = 1.3
locn = (1, 1)
device.get_H(k, locn=locn)
print device.h

我不确定这最终对你有多大帮助,无论它是否是你真正想要的,请注意,它并没有真正增加 eatmeinadanish 的答案。

评论

0赞 MrTLane 8/22/2018
感谢您对我的问题进行思考。在您的解决方案中,我认为我仍然需要计算每种情况下的去向,因为我在任何时候都没有保存。事实上,为我包含的每个耦合保存一个数组会占用大量内存,因此可能根本不是一个可行的选择。我需要的是类似于 Mathematica 的东西,您可以在表达式中保留未计算的变量,但这在 python 中很可能是不可能的。klocnlocn
0赞 jtlz2 8/22/2018
没问题 - 对不起,没有更多的帮助。你可以在python中使用TensorFlow声明式编程来做到这一点(参见例如 stackoverflow.com/questions/35677724/...),但我确实想知道它最终是否会为你节省任何计算资源——因为你无法真正摆脱数字运算。是每个元素都受到影响,还是可以以某种方式截断(这就是为什么我想知道相干长度)以便您只触及其中的几个值?hk
0赞 MrTLane 8/22/2018
矩阵有些稀疏,所以那里可能会有加速,但是在堆栈溢出上查看这里对 scipy 稀疏模块的讨论表明,您可能需要一个比我实际拥有的更稀疏的矩阵(~1-2% 的值是非零的,不像我的更像 20%)。是的,大量非零元素直接取决于 k,因为电子在原子位点之间跳跃时会拾取相位因子等。e^{i k.x}
0赞 MrTLane 8/22/2018
我不确定接受任何一个答案是否是一个好主意,因为我不想误导任何来这里寻找答案或想尝试自己回答问题的人,但我非常感谢你思考并提出这么多好主意。特别是因为我只是在中医;)
0赞 jtlz2 8/22/2018
完全没有问题 - 祝你好运 - 保持打开状态,直到你对答案感到满意 - 或者 - 如果你突然解决了它,这似乎经常发生在思考它之后,发布并接受你自己的答案 Q. 祝你好运!:)