我想对有理矩阵执行运算。我使用模块numpy
和fractions
。
这是我的代码:
import numpy as np
from fractions import Fraction
m=np.matrix([[Fraction(1, 6), Fraction(8, 7)], [Fraction(1, 2), Fraction(3, 2)]])
print(np.linalg.det(m))
# Gives -0.321428571429
print(m[0,0]*m[1,1] - m[0,1]*m[1,0])
# Gives -9/28
由于用高斯方法计算行列式只需要有理运算,所以有理矩阵的行列式是有理的。
所以我的问题是:为什么numpy返回的是float而不是Fraction?我怎样才能得到一个有理行列式?
注意,这个矩阵上的其他运算给出了有理输出(例如m.trace()
)。
NumPy通过LAPACK中的上下分解例程计算矩阵的行列式。此例程只能处理浮点数字。
在计算矩阵的行列式之前,linalg.det
检查它所具有的值的类型,然后通过调用名为_commonType()
的函数来建立应该运行的内部循环的类型。此函数将循环设置为针对双精度或复杂双精度值运行。
以下是函数linalg.det
中处理检查的Python部分:
def det(a):
a = asarray(a) # convert matrix to NumPy array
_assertNoEmpty2d(a)
_assertRankAtLeast2(a)
_assertNdSquareness(a)
t, result_t = _commonType(a) # input/output types established here
signature = 'D->D' if isComplexType(t) else 'd->d' # signature 'float->float' chosen
return _umath_linalg.det(a, signature=signature).astype(result_t)
在对矩阵的形状进行检查并确定类型后,return
行将数组中的值传递给上下分解的LAPACK实现,并返回浮点值。
试图用我们自己的类型签名绕过这种类型检查会引发一个错误,即没有为对象类型定义这样的循环:
>>> np.linalg._umath_linalg.det(a, signature='O->O') # 'O' is 'object'
TypeError: No loop matching the specified signature was found for ufunc det
这意味着在使用det
时不可能保留Fraction
类型作为返回类型。
诸如trace()
之类的其他函数不进行与det
相同的类型检查,并且对象类型可以持久存在。trace
通过调用Fraction
对象的__add__
方法简单地求对角线的和,因此Fraction
对象可以保留为返回类型。
如果你想把行列式计算成有理数,你可以研究SymPy。矩阵运算,例如计算行列式,在这里被记录下来。
在我看来,这不是一个容易解决的问题,可能是因为np.linalg
的大部分操作都依赖于lapack。从numpy.linalg
的源代码中可以看出,在调用任何lapack例程之前,都会调用一个名为_commonType
的例程。这将尝试为输入数组中包含的数据找到合适的类型,但如果无法确定类型,则假定类型为double
。数组是在传递到lapack例程之前转换为结果类型的数组。这很可能是因为几乎不可能处理每一种可以传递的类型。
我从未使用过Fraction
包,所以我无法为您提供一个可行的解决方案来返回到Fraction
对象的矩阵。我本来打算建议给m.astype(Fraction)
打电话,但似乎也不行。
- 列出项目