Встроенная функция python для уменьшения матрицы
Имеется ли в python встроенная функция, которая преобразует матрицу в форму эшелона строки (также известную как верхняя треугольная)?
Ответы
Ответ 1
Если вы можете использовать sympy
, Matrix.rref()
может это сделать:
In [8]: sympy.Matrix(np.random.random((4,4))).rref()
Out[8]:
([1, 1.42711055402454e-17, 0, -1.38777878078145e-17]
[0, 1.0, 0, 2.22044604925031e-16]
[0, -2.3388341405089e-16, 1, -2.22044604925031e-16]
[0, 3.65674099486992e-17, 0, 1.0],
[0, 1, 2, 3])
Ответ 2
Да. В scipy.linalg
lu
выполняет декомпозицию LU, которая, по существу, придаст вам форму эшелона.
Есть другие факторизации, такие как qr
, rq
, svd
и другие, если вам интересно.
Документация.
Ответ 3
см. http://mail.scipy.org/pipermail/numpy-discussion/2008-November/038705.html
В принципе: не делайте этого.
Алгоритм rref создает слишком много неточности при реализации на компьютере. Таким образом, вы либо хотите решить проблему по-другому, либо использовать символику, такую как @aix.
Ответ 4
Я согласен с комментарием @Mile к ответу @WinstonEwert Нет причин, по которым компьютер не может выполнить RREF с с заданной точностью.
Реализация RREF не должна быть очень сложной, и Matlab каким-то образом удалось получить эту функцию, так что NumPy должно быть тоже.
Я сделал очень простую и понятную реализацию, которая очень неэффективна. Но для простых матриц это работает довольно хорошо:
def rref(mat,precision=0,GJ=False):
m,n = mat.shape
p,t = precision, 1e-1**precision
A = around(mat.astype(float).copy(),decimals=p )
if GJ:
A = hstack((A,identity(n)))
pcol = -1 #pivot colum
for i in xrange(m):
pcol += 1
if pcol >= n : break
#pivot index
pid = argmax( abs(A[i:,pcol]) )
#Row exchange
A[i,:],A[pid+i,:] = A[pid+i,:].copy(),A[i,:].copy()
#pivot with given precision
while pcol < n and abs(A[i,pcol]) < t:
#pivot index
pid = argmax( abs(A[i:,pcol]) )
#Row exchange
A[i,:],A[pid+i,:] = A[pid+i,:].copy(),A[i,:].copy()
pcol += 1
if pcol >= n : break
pivot = float(A[i,pcol])
for j in xrange(m):
if j == i: continue
mul = float(A[j,pcol])/pivot
A[j,:] = around(A[j,:] - A[i,:]*mul,decimals=p)
A[i,:] /= pivot
A[i,:] = around(A[i,:],decimals=p)
if GJ:
return A[:,:n].copy(),A[:,n:].copy()
else:
return A
Вот несколько простых тестов
print "/*--------------------------------------/"
print "/ Simple TEST /"
print "/--------------------------------------*/"
A = array([[1,2,3],[4,5,6],[-7,8,9]])
print "A:\n",R
R = rref(A,precision=6)
print "R:\n",R
print
print "With GJ "
R,E = rref(A,precision=6,GJ=True)
print "R:\n",R
print "E:\n",E
print "AdotE:\n",around( dot(A,E),decimals=0)
/*--------------------------------------/
/ Simple TEST /
/--------------------------------------*/
A:
[[ 1. 0. 1.]
[-0. 1. 1.]
[ 0. 0. 0.]
[ 0. 0. 0.]]
R:
[[ 1. 0. 0.]
[ 0. 1. 0.]
[ 0. 0. 1.]]
With GJ
R:
[[ 1. 0. 0.]
[ 0. 1. 0.]
[ 0. 0. 1.]]
E:
[[-0.071428 0.142857 -0.071429]
[-1.857142 0.714285 0.142857]
[ 1.595237 -0.523809 -0.071428]]
AdotE:
[[ 1. 0. 0.]
[ 0. 1. 0.]
[-0. 0. 1.]]
print "/*--------------------------------------/"
print "/ Not Invertable TEST /"
print "/--------------------------------------*/"
A = array([
[2,2,4, 4],
[3,1,6, 2],
[5,3,10,6]])
print "A:\n",A
R = rref(A,precision=2)
print "R:\n",R
print
print "A^{T}:\n",A.T
R = rref(A.T,precision=10)
print "R:\n",R
/*--------------------------------------/
/ Not Invertable TEST /
/--------------------------------------*/
A:
[[ 2 2 4 4]
[ 3 1 6 2]
[ 5 3 10 6]]
R:
[[ 1. 0. 2. 0.]
[-0. 1. -0. 2.]
[ 0. 0. 0. 0.]]
A^{T}:
[[ 2 3 5]
[ 2 1 3]
[ 4 6 10]
[ 4 2 6]]
R:
[[ 1. 0. 1.]
[-0. 1. 1.]
[ 0. 0. 0.]
[ 0. 0. 0.]]