4

我想对有理矩阵进行运算。我使用模块numpyfractions.

这是我的代码:

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 返回浮点数而不是分数?我怎样才能得到一个理性的行列式?

请注意,此矩阵上的其他操作会给出合理的输出(例如m.trace())。

4

2 回答 2

5

NumPy 通过 LAPACK 中的下上分解例程计算矩阵的行列式。该例程只能处理浮点数。

在计算矩阵的行列式之前,linalg.det检查它具有的值的类型,然后通过调用名为 的函数来确定应该运行的内部循环的类型_commonType()。此函数会将循环设置为针对 double 或 complex-double 值运行。

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

这意味着在使用时不可能将Fraction类型保留为返回类型det

其他功能(例如trace()不执行与det对象类型相同的类型检查)可能会持续存在。通过调用对象的方法trace简单地对对角线求和,因此可以将对象保留为返回类型。Fraction__add__Fraction

如果您想将行列式计算为有理数,您可以研究 SymPy。此处记录了矩阵运算,例如计算行列式。

于 2015-03-21T12:36:57.403 回答
1

在我看来,这不是一个容易解决的问题,并且可能是np.linalg对大多数操作都依赖于 lapack 的事实的限制。查看源代码numpy.linalg似乎_commonType在调用任何 lapack 例程之前调用了一个被调用的例程。这会尝试为输入数组中包含的数据找到适当的类型,但如果无法确定类型,则假定类型为double。该数组是在传递给 lapack 例程之前转换为结果类型。这很可能已经完成,因为几乎不可能处理可以传递的每种类型。

我从来没有使用过这个Fraction包,所以我不能给你一个可行的解决方案来回到一个Fraction对象矩阵。我打算建议打电话m.astype(Fraction),但这似乎也没有。

  • 项目清单
于 2015-03-21T12:39:43.923 回答