强制乘法使用 __rmul__() 而不是 Numpy 数组 __mul__() 或绕过广播
Forcing multiplication to use __rmul__() instead of Numpy array __mul__() or bypassing the broadcasting
这个问题与 中的问题很接近,但我的印象是这是一个比数字数据更普遍的问题。这也没有得到回答,我真的不想为此操作使用矩阵乘法 @
。因此,问题。
我有一个接受标量和数值数组乘法的对象。像往常一样,左乘法工作正常,因为它使用了 myobj()
方法,但在右乘法中,NumPy 使用广播规则并给出元素结果 dtype=object
.
这也有无法检查数组大小是否兼容的副作用。
所以问题是
Is there a way to force numpy array to look for the __rmul__()
of the other object instead of broadcasting and performing elementwise __mul__()
?
在我的特殊情况下,对象是 MIMO(多输入、多输出)传递函数矩阵(如果您愿意,也可以是滤波器系数矩阵),因此矩阵乘法在线性加法和乘法方面具有特殊意义系统。因此在每个条目中都有 SISO 系统。
import numpy as np
class myobj():
def __init__(self):
pass
def __mul__(self, other):
if isinstance(other, type(np.array([0.]))):
if other.size == 1:
print('Scalar multiplication')
else:
print('Multiplication of arrays')
def __rmul__(self, other):
if isinstance(other, type(np.array([0.]))):
if other.size == 1:
print('Scalar multiplication')
else:
print('Multiplication of arrays')
A = myobj()
a = np.array([[[1+1j]]]) # some generic scalar
B = np.random.rand(3, 3)
根据这些定义,以下命令显示了不良行为。
In [123]: A*a
Scalar multiplication
In [124]: a*A
Out[124]: array([[[None]]], dtype=object)
In [125]: B*A
Out[125]:
array([[None, None, None],
[None, None, None],
[None, None, None]], dtype=object)
In [126]: A*B
Multiplication of arrays
In [127]: 5 * A
In [128]: A.__rmul__(B) # This is the desired behavior for B*A
Multiplication of arrays
我将尝试演示发生了什么。
In [494]: B=np.random.rand(3,3)
准系统class:
In [497]: class myobj():
...: pass
...:
In [498]: B*myobj()
...
TypeError: unsupported operand type(s) for *: 'float' and 'myobj'
添加一个__mul__
In [500]: class myobj():
...: pass
...: def __mul__(self,other):
...: print('myobj mul')
...: return 12.3
...:
In [501]: B*myobj()
...
TypeError: unsupported operand type(s) for *: 'float' and 'myobj'
In [502]: myobj()*B
myobj mul
Out[502]: 12.3
添加一个rmul
:
In [515]: class myobj():
...: pass
...: def __mul__(self,other):
...: print('myobj mul',other)
...: return 12.3
...: def __rmul__(self,other):
...: print('myobj rmul',other)
...: return 4.32
...:
In [516]: B*myobj()
myobj rmul 0.792751549595306
myobj rmul 0.5668783619454384
myobj rmul 0.2196204913660168
myobj rmul 0.5474970289273348
myobj rmul 0.2079367474424587
myobj rmul 0.5374571198848628
myobj rmul 0.35748803226628456
myobj rmul 0.41306113085906715
myobj rmul 0.499598995529441
Out[516]:
array([[4.32, 4.32, 4.32],
[4.32, 4.32, 4.32],
[4.32, 4.32, 4.32]], dtype=object)
B*myobj()
被赋予 B
,作为 B.__mul__(myobj())
,它继续为 B
.
的每个元素执行 myobj().__rmul__(i)
在 myobj()*B
中转换为 myobj.__mul__(B)
:
In [517]: myobj()*B
myobj mul [[ 0.79275155 0.56687836 0.21962049]
[ 0.54749703 0.20793675 0.53745712]
[ 0.35748803 0.41306113 0.499599 ]]
Out[517]: 12.3
In [518]: myobj().__rmul__(B)
myobj rmul [[ 0.79275155 0.56687836 0.21962049]
[ 0.54749703 0.20793675 0.53745712]
[ 0.35748803 0.41306113 0.499599 ]]
Out[518]: 4.32
您无法在 myobj
中执行任何操作来覆盖 B*myobj()
到 B.__mul__(myobj())
的翻译。如果您需要更好地控制操作,请使用函数或方法。口译员好难斗
默认情况下,NumPy 假设未知对象(不是从 ndarray 继承)是标量,它需要 "vectorize" 对任何 NumPy 数组的每个元素进行乘法运算。
要自己控制操作,您需要设置 __array_priority__
(最向后兼容)或 __array_ufunc__
(仅限 NumPy 1.13+)。例如:
class myworkingobj(myobj):
__array_priority__ = 1000
A = myworkingobj()
B = np.random.rand(3, 3)
B * A # Multiplication of arrays
这个问题与 @
。因此,问题。
我有一个接受标量和数值数组乘法的对象。像往常一样,左乘法工作正常,因为它使用了 myobj()
方法,但在右乘法中,NumPy 使用广播规则并给出元素结果 dtype=object
.
这也有无法检查数组大小是否兼容的副作用。
所以问题是
Is there a way to force numpy array to look for the
__rmul__()
of the other object instead of broadcasting and performing elementwise__mul__()
?
在我的特殊情况下,对象是 MIMO(多输入、多输出)传递函数矩阵(如果您愿意,也可以是滤波器系数矩阵),因此矩阵乘法在线性加法和乘法方面具有特殊意义系统。因此在每个条目中都有 SISO 系统。
import numpy as np
class myobj():
def __init__(self):
pass
def __mul__(self, other):
if isinstance(other, type(np.array([0.]))):
if other.size == 1:
print('Scalar multiplication')
else:
print('Multiplication of arrays')
def __rmul__(self, other):
if isinstance(other, type(np.array([0.]))):
if other.size == 1:
print('Scalar multiplication')
else:
print('Multiplication of arrays')
A = myobj()
a = np.array([[[1+1j]]]) # some generic scalar
B = np.random.rand(3, 3)
根据这些定义,以下命令显示了不良行为。
In [123]: A*a
Scalar multiplication
In [124]: a*A
Out[124]: array([[[None]]], dtype=object)
In [125]: B*A
Out[125]:
array([[None, None, None],
[None, None, None],
[None, None, None]], dtype=object)
In [126]: A*B
Multiplication of arrays
In [127]: 5 * A
In [128]: A.__rmul__(B) # This is the desired behavior for B*A
Multiplication of arrays
我将尝试演示发生了什么。
In [494]: B=np.random.rand(3,3)
准系统class:
In [497]: class myobj():
...: pass
...:
In [498]: B*myobj()
...
TypeError: unsupported operand type(s) for *: 'float' and 'myobj'
添加一个__mul__
In [500]: class myobj():
...: pass
...: def __mul__(self,other):
...: print('myobj mul')
...: return 12.3
...:
In [501]: B*myobj()
...
TypeError: unsupported operand type(s) for *: 'float' and 'myobj'
In [502]: myobj()*B
myobj mul
Out[502]: 12.3
添加一个rmul
:
In [515]: class myobj():
...: pass
...: def __mul__(self,other):
...: print('myobj mul',other)
...: return 12.3
...: def __rmul__(self,other):
...: print('myobj rmul',other)
...: return 4.32
...:
In [516]: B*myobj()
myobj rmul 0.792751549595306
myobj rmul 0.5668783619454384
myobj rmul 0.2196204913660168
myobj rmul 0.5474970289273348
myobj rmul 0.2079367474424587
myobj rmul 0.5374571198848628
myobj rmul 0.35748803226628456
myobj rmul 0.41306113085906715
myobj rmul 0.499598995529441
Out[516]:
array([[4.32, 4.32, 4.32],
[4.32, 4.32, 4.32],
[4.32, 4.32, 4.32]], dtype=object)
B*myobj()
被赋予 B
,作为 B.__mul__(myobj())
,它继续为 B
.
myobj().__rmul__(i)
在 myobj()*B
中转换为 myobj.__mul__(B)
:
In [517]: myobj()*B
myobj mul [[ 0.79275155 0.56687836 0.21962049]
[ 0.54749703 0.20793675 0.53745712]
[ 0.35748803 0.41306113 0.499599 ]]
Out[517]: 12.3
In [518]: myobj().__rmul__(B)
myobj rmul [[ 0.79275155 0.56687836 0.21962049]
[ 0.54749703 0.20793675 0.53745712]
[ 0.35748803 0.41306113 0.499599 ]]
Out[518]: 4.32
您无法在 myobj
中执行任何操作来覆盖 B*myobj()
到 B.__mul__(myobj())
的翻译。如果您需要更好地控制操作,请使用函数或方法。口译员好难斗
默认情况下,NumPy 假设未知对象(不是从 ndarray 继承)是标量,它需要 "vectorize" 对任何 NumPy 数组的每个元素进行乘法运算。
要自己控制操作,您需要设置 __array_priority__
(最向后兼容)或 __array_ufunc__
(仅限 NumPy 1.13+)。例如:
class myworkingobj(myobj):
__array_priority__ = 1000
A = myworkingobj()
B = np.random.rand(3, 3)
B * A # Multiplication of arrays