Архитектура для обеспечения различных линейных концов алгебры - PullRequest
13 голосов
/ 20 марта 2011

Я создаю прототип новой системы на 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__ и __rmul__, но вы можете следить, что то же самое будет сделано для каждой операции).

Я хочу потерять некоторую производительность в обмен на настраиваемость.Несмотря на то, что мой пример работает, он не чувствует себя хорошо - я бы испортил бэкэнд так много вызовов конструктора!Это требует другой реализации metaclass, позволяющей улучшить отсрочку вызова.

Итак, как бы вы порекомендовали мне реализовать эту функцию?Мне нужно подчеркнуть важность сохранения всех Vector экземпляров системы однородными и независимыми от конца линейной алгебры.

Ответы [ 3 ]

6 голосов
/ 02 июня 2011

Вы должны проверить PEP-3141 и стандартный модуль lib ABCMeta .

Для подробного объяснения того, как использовать ABCMeta, всегда полезно PyMOTW с хорошим описанием.

3 голосов
/ 01 июня 2011

Почему бы просто не создать "виртуальный" класс (AbstractVector), который похож на Vector в вашем примере, и создать разные его подклассы для каждой реализации?

Двигатель можно выбрать, выполнив Vector = NumPyVector или что-то в этом роде.

2 голосов
/ 12 июня 2011

Только к вашему сведению, вы можете легко настроить и собрать NumPy для использования Math Kernel Library от Intel или Core Math Library от AMD вместо обычного ATLAS + LAPACK. Это так же просто, как создание файла site.cfg с переменными blas_libs, lapack_libs, library_dirs и include_dirs, установленными соответствующим образом. (Подробности настройки этих параметров для MKL и ACML легко доступны для Google.) Поместите его рядом со скриптом setup.py и постройте как обычно.

Чтобы переключаться между этими стандартными библиотеками линейной алгебры, вы можете создать разные экземпляры NumPy для каждого и управлять ими, например, используя virtualenvs .

Я знаю, что это не дает вам гибкости, необходимой вам для использования ваших собственных пользовательских математических библиотек, но я просто подумал, что я добавлю это туда. И хотя я не рассматривал это, я полагаю, что вы также можете заставить NumPy создавать собственные библиотеки с меньшими усилиями, чем при создании собственного интерфейса, особенно если вы хотите сохранить расширенную функциональность. здания NumPy / SciPy.

...