13

我正在用 Python 制作一个新系统的原型;功能主要是数字。

一个重要的要求是能够使用不同的线性代数后端:从单个用户实现到通用库,例如​​ Numpy。线性代数实现(即后端)必须独立于接口。

我最初的架构尝试如下:

(1) 定义系统接口

>>> v1 = Vector([1,2,3])
>>> v2 = Vector([4,5,6])
>>> print v1 * v2
>>> # prints "Vector([4, 10, 18])"

(2) 实现允许独立于后端使用该接口的代码

# this example uses numpy as the back-end, but I mean
# to do this for a general back-end
import numpy 
def numpy_array(*args): # creates a numpy array from the arguments
    return numpy.array(*args)

class VectorBase(type):
    def __init__(cls, name, bases, attrs):
        engine = attrs.pop("engine", None)
        if not engine:
            raise RuntimeError("you need to specify an engine")
        # this implementation would change depending on `engine`
        def new(cls, *args):
            return numpy_array(*args)   
        setattr(cls, "new", classmethod(new))

class Vector(object):   
    __metaclass__ = VectorBase        
    # I could change this at run time
    # and offer alternative back-ends
    engine = "numpy"  
    @classmethod
    def create(cls, v):
        nv = cls()
        nv._v = v
        return nv    
    def __init__(self, *args):  
        self._v = None
        if args:
            self._v = self.new(*args)
    def __repr__(self):
        l = [item for item in self._v]
        return "Vector(%s)" % repr(l)
    def __mul__(self, other):
        try:
            return Vector.create(self._v * other._v)
        except AttributeError:
            return Vector.create(self._v * other)
    def __rmul__(self, other):
        return self.__mul__(other)

这个简单示例的工作方式如下:Vector该类保留对后端创建的向量实例的引用(numpy.ndarray在示例中);所有算术调用都由接口实现,但它们的评估推迟到后端。

在实践中,接口重载了所有适当的运算符并推迟到后端(示例仅显示__mul__and __rmul__,但您可以遵循每个操作都会执行相同的操作)。

我愿意牺牲一些性能来换取可定制性。即使我的示例有效,但感觉不对——我会用这么多构造函数调用来破坏后端!这需要一个不同的metaclass实现,允许更好的调用延迟。

那么,你会如何建议我实现这个功能呢?我需要强调保持所有系统Vector实例同质且独立于线性代数后端的重要性。

4

3 回答 3

6

You should check out PEP-3141 and the standard lib module ABCMeta.

For a detailed explanation of how to use ABCMeta, the always helpful PyMOTW has a nice write-up.

于 2011-06-02T06:08:42.367 回答
3

Why not simply make a "virtual" class (AbstractVector) which is like Vector in your example, and make different subclasses of it for each implementation?

An engine could be chosen by doing Vector = NumPyVector or something like that.

于 2011-06-01T18:12:51.743 回答
2

仅供参考,您可以轻松配置和构建 NumPy 以使用英特尔的数学内核库或 AMD 的核心数学库,而不是通常的 ATLAS + LAPACK。这就像使用适当设置的、、和变量创建一个site.cfg文件一样简单。(为 MKL 和 ACML 设置这些选项的详细信息很容易在 Google 上搜索到。)将它放在脚本旁边并照常构建。blas_libslapack_libslibrary_dirsinclude_dirssetup.py

例如,要在这些标准线性代数库之间切换,您可以为每个库构建一个不同的 NumPy 实例并使用virtualenvs管理它们。

我知道这不会为您提供使用自己的自定义数学库所需的灵活性,但只是想我会把它扔在那里。虽然我没有研究过,但我想你也可以让 NumPy 构建一个自定义库,而不是构建自己的前端,特别是如果你想保留广泛的功能NumPy/SciPy 大厦。

于 2011-06-11T20:00:03.593 回答