Python:带有域检查的线性代数包

时间:2016-06-08 09:41:35

标签: python numpy linear-algebra

在执行线性操作之前是否存在使用某种形式的域检查的(可能有效的)线性代数包?

numpy在线性操作之前已执行某种域检查:如果维度不匹配,则会引发ValueError。我想更准确地识别我的域名(例如,通过使用指定空间基础的标记),并在域名不匹配时获得相同的行为。

假设我有两个3维的空间

  • 向量空间A代表水果:尺寸1 =香蕉,2 =苹果,3 =梨。 A的向量是一个食谱

  • 向量空间B代表衣服:尺寸1 =鞋子,2 =裤子,3 =衬衫。 B的向量是衣柜。

以下是我想要的(而不是numpy

import numpy as np
a = np.array([1,2,3], domain='fruits')
b = np.array([3,2,1], domain='clothes')
a + b # I want it to raise a ValueError: can't sum clothes and fruits

1 个答案:

答案 0 :(得分:1)

您可以按subclassing numpy arrays滚动自己的矢量空间。我设法提出了一个简单的子类,基本上是numpy.ndarray加上一个名字。通过限制相同类型名称的数组的加法和减法,我们基本上可以做你想要实现的。这假设你真的想要一个向量空间:在这种情况下,我们只需要在向量元素之间定义加法,而不是乘法(虽然这也很容易以相同的方式实现)。

这是我的班级:

import numpy as np

class named_ndarray(np.ndarray):
    def __new__(cls, name, inparray):
        obj = np.asarray(inparray).view(cls)
        obj._name = name
        return obj

    def __array_finalize__(self, obj):
        if obj is None: return
        self._name = getattr(obj, '_name', None)

    def __add__(self,other):
        if np.isscalar(other) or (type(other)==type(self) and other._name==self._name):
            return named_ndarray(self._name,np.asarray(self) + np.asarray(other))
        else:
            raise TypeError('Named type "{}" can only be added to the same type! (Other is "{}")'.format(self._name,other._name))

    def __radd__(self,other):
        return __add__(self,other)

    def __sub__(self,other):
        if np.isscalar(other) or (type(other)==type(self) and other._name==self._name):
            return named_ndarray(self._name,np.asarray(self) - np.asarray(other))
        else:
            raise TypeError('Only same type can be subtracted from named type "{}"! (Other is "{}")'.format(self._name,other._name))

    def __rsub__(self,other):
        if np.isscalar(other) or (type(other)==type(self) and other._name==self._name):
            return named_ndarray(self._name,np.asarray(self) - np.asarray(other))
        else:
            raise TypeError('Named type "{}" can only be subtracted from the same type! (Other is "{}")'.format(self._name,other._name))

前两种方法是ndarray等同于__init__()。可以通过指定名称并从现有数组或列表初始化来使用此类:

fruitvec1 = named_ndarray('fruits',[1,3,5])
fruitvec2 = named_ndarray('fruits',[2,4,6])
clothesvec = named_ndarray('clothes',[1,1,1])

通过覆盖__add____radd____sub____rsub__方法,我们可以确保只有相同类型的命名数组和标量(整数,浮点数等)。 )可以添加。通过单独进行乘法/除法,这些将对标量的预期工作(并且这样的两个对象不应相互相乘)。如果您想要超越线性空间,则应该类似地定义__mul____rmul____truediv____rtruediv__(后者假定为Python 3或from __future__ import division

以下是这些对象的行为:

>>> fruitvec1*3
named_ndarray([ 3,  9, 15])
>>> 3/fruitvec1
named_ndarray([ 3. ,  1. ,  0.6])
>>> fruitvec1 - 2*fruitvec2
named_ndarray([-3, -5, -7])
>>> fruitvec1 + clothesvec/4
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "foo.py", line 17, in __add__
    raise TypeError('Named type "{}" can only be added to the same type! (Other is "{}")'.format(self._name,other._name))
TypeError: Named type "fruits" can only be added to the same type! (Other is "clothes")