Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/299.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python中高效的向量/点类_Python_Performance_Python 3.x_Vector - Fatal编程技术网

Python中高效的向量/点类

Python中高效的向量/点类,python,performance,python-3.x,vector,Python,Performance,Python 3.x,Vector,实现一个既可以在Python2.7+中使用又可以在Python3.x中使用的高效向量/点类(或者更好:是否已经有了)的最佳方法是什么 我发现了,但它们似乎只支持Python3.x。然后是,它使用,但它只是一个3D向量。为具有静态属性(x和y)的向量()使用列表似乎也很奇怪。(有所有这些列表方法。) 目前,我正在使用一个扩展namedtuple的类(如下所示),但它的缺点是无法更改坐标。我认为这可能会成为一个性能问题,当数千个对象移动时,每次都会创建一个新的(向量)元组。(对吗?) 编辑:我做了一

实现一个既可以在Python2.7+中使用又可以在Python3.x中使用的高效向量/点类(或者更好:是否已经有了)的最佳方法是什么

我发现了,但它们似乎只支持Python3.x。然后是,它使用,但它只是一个3D向量。为具有静态属性(x和y)的向量()使用列表似乎也很奇怪。(有所有这些列表方法。)

目前,我正在使用一个扩展namedtuple的类(如下所示),但它的缺点是无法更改坐标。我认为这可能会成为一个性能问题,当数千个对象移动时,每次都会创建一个新的(向量)元组。(对吗?)

编辑:我做了一些测试,似乎使用
numpy.array
numpy.ndarray
作为向量太慢了。(例如,获取一个项目几乎需要两倍的时间,更不用说创建一个数组了。我认为它更适合对大量项目进行计算。)


因此,我正在寻找一个轻量级的向量类,它具有固定数量的字段(在我的例子中,就是
x
y
),可以用于游戏。(如果已经有一个经过良好测试的轮子,我不想再发明它。)

是的,有一个向量类:它在事实上的标准模块中。您可以这样创建向量:

>>> v = numpy.array([1, 10, 123])
>>> 2*v
array([  2,  20, 246])
>>> u = numpy.array([1, 1, 1])
>>> v-u
array([  0,   9, 122])
NumPy非常丰富,可以让您访问快速数组操作:点积(
NumPy.dot()
),norm(
NumPy.linalg.norm()
),等等。

在线性代数方面,NumPy中的向量类可能是
NumPy.matrix
,它是
NumPy.ndarray
的一个子类。它本身并不干净,但它使您的代码更干净,因为代数运算是假定的,而不是元素操作

In [77]: a = np.array([1,2])

In [78]: b = np.array([3,3])

In [79]: a*b
Out[79]: array([3, 6])

In [80]: np.dot(a,b)
Out[80]: 9

In [81]: np.outer(a,b)
Out[81]: 
array([[3, 3],
       [6, 6]])

In [82]: a = np.matrix(a).T

In [83]: b = np.matrix(b)

In [84]: b*a
Out[84]: matrix([[9]])

In [85]: a*b
Out[85]: 
matrix([[3, 3],
        [6, 6]])
如果要创建自己的,请基于以下其中一项,例如:

class v2d(np.ndarray):
    def __abs__(self):
        return np.linalg.norm(self)
    def dist(self,other):
        return np.linalg.norm(self-other)
    def dot(self, other):
        return np.dot(self, other)
    # and so on
在最简单的情况下,只需将
ndarray
作为新类查看即可:

In [63]: a = np.array([1,2]).view(v2d)

In [64]: b = np.array([3,3]).view(v2d)

In [65]: a
Out[65]: v2d([1, 2])

In [66]: abs(b)
Out[66]: 4.2426406871192848

In [67]: a - b
Out[67]: v2d([-2, -1])

In [68]: a*b
Out[68]: v2d([3, 6])

In [69]: a*3
Out[69]: v2d([3, 6]) 

In [70]: a.dist(b)
Out[70]: 2.2360679774997898

In [71]: b.dist(a)
Out[71]: 2.2360679774997898

In [72]: a.dot(b)
Out[72]: 9

这里有更多关于的信息。

我也需要一个快速的解决方案,所以我只是将numpy的数组包装到我自己的数组中。您会注意到一些设计决策可以根据自己的需要进行更改(如默认值)。 如果您想使用它:


谢谢您知道一个干净的包装器类,它使用numpy表示二维向量吗?(numpy.array充满了向量不需要的其他方法)有一个子类
np.ndarray
称为
np.matrix
。它并不干净,但是如果你有两个
matrix
e,
A*B
提供了这两个元素的矩阵积(比如,
np.dot(A,B)
如果它们是双向量):我想如果你这么担心性能,你使用的语言是错误的(别误会,python很棒,但CPython很慢;如果你不依赖第三方软件包,你可以尝试PyPy)。即使你依赖(一些)第三方软件包,你也可以尝试PyPy。特别是,纯python软件包应该可以工作,一些非纯python软件包已经被移植,或者正在被移植(至少部分).我检查过了,但比你建议的要慢,因为协调访问。它也更一般……我从未见过Python的2D或3D优化向量实现:我想自己实现它是最好的选择。您甚至可以在Python包索引上发布结果。:)你考虑过使用复数吗?它们给你v1+v2,v1-v2,实x*v,v/x,abs(v)和abs(pt1-pt2)。单位向量的乘法是旋转,而a*pt+b是任何仿射变换。如果从复合体中导入exp和log,则会得到角度旋转、向量的反正切或差,以及极轴和矩形之间的转换。因为很难说.real和.imag而不是.x和.y,所以我编写了complex的子类来重命名属性。这使得我的积分更大,我肯定比原始的复杂度要慢。
In [63]: a = np.array([1,2]).view(v2d)

In [64]: b = np.array([3,3]).view(v2d)

In [65]: a
Out[65]: v2d([1, 2])

In [66]: abs(b)
Out[66]: 4.2426406871192848

In [67]: a - b
Out[67]: v2d([-2, -1])

In [68]: a*b
Out[68]: v2d([3, 6])

In [69]: a*3
Out[69]: v2d([3, 6]) 

In [70]: a.dist(b)
Out[70]: 2.2360679774997898

In [71]: b.dist(a)
Out[71]: 2.2360679774997898

In [72]: a.dot(b)
Out[72]: 9
import numpy as np


class Point(np.ndarray):
    """
    n-dimensional point used for locations.
    inherits +, -, * (as dot-product)
    > p1 = Point([1, 2])
    > p2 = Point([4, 5])
    > p1 + p2
    Point([5, 7])
    See ``test()`` for more usage.
    """
    def __new__(cls, input_array=(0, 0)):
        """
        :param cls:
        :param input_array: Defaults to 2d origin
        """
        obj = np.asarray(input_array).view(cls)
        return obj

    @property
    def x(self):
        return self[0]

    @property
    def y(self):
        return self[1]

    @property
    def z(self):
        """
        :return: 3rd dimension element. 0 if not defined
        """
        try:
            return self[2]
        except IndexError:
            return 0

    def __eq__(self, other):
        return np.array_equal(self, other)

    def __ne__(self, other):
        return not np.array_equal(self, other)

    def __iter__(self):
        for x in np.nditer(self):
            yield x.item()


    def dist(self, other):
        """
        Both points must have the same dimensions
        :return: Euclidean distance
        """
        return np.linalg.norm(self - other)


def test():
    v1 = Point([1, 2, 3])
    v2 = Point([4, 5, 7])
    v3 = Point([4, ])
    sum12 = Point([5, 7, 10])
    dot12 = Point([4, 10, 21])

    # Access
    assert v2.x == 4
    assert v2.y == 5
    assert v2.z == 7
    assert v3.z == 0
    assert Point().x == 0
    assert v2[0] == 4
    assert v1[-1] == 3  # Not needed but inherited
    assert [x for x in v2] == [4, 5, 7], "Iteration should return all elements"

    # Operations
    assert v1 + v2 == sum12
    assert v1 * v2 == dot12
    assert v1.dist(v2) ** 2 == 34
    assert v1 != v2
    assert v2.size == 3, "v2 should be a 3d point"

    print "pass"


if __name__ == "__main__":
    test()