Python 库(如 numpy 和 sympy)中的基本列操作

问题描述 投票:0回答:1

我试图通过初等列运算找到宽矩阵的逆矩阵。该方程的形式为

A * B = C
,其中 A 是高矩阵,B 是宽矩阵。我使用 numpy 作为执行操作的库,但我目前面临浮点精度的问题。

我写的代码如下

import numpy as np

A = np.random.normal(size=(3, 2))
B = np.random.normal(size=(2, 3))

result = np.matmul(A, B)

print("A: \n", A)
print("B: \n", B)
print("result: \n", result)

输出是

A: 
 [[-0.75475352  0.57273983]
 [-0.58109354  1.60719081]
 [-0.46268783 -0.94800159]]
B: 
 [[0.50491008 0.83252516 0.0064097 ]
 [1.40104051 0.26863747 0.60867192]]
result: 
 [[ 0.42134905 -0.47449191  0.34377291]
 [ 1.95833945 -0.05202331  0.97452729]
 [-1.56180438 -0.639868   -0.57998764]]

执行操作的代码如下

rows, columns = len(result), len(result[0])
result = np.matmul(A, B)

print("B = ")
print(B)
print()
print("result = ")
print(result)

print("Start...")
for idx in range(columns):
    print(f"{idx} start")
    divisor = result[idx][idx]
    print("Divisor: ", divisor)
    B[:, idx] = B[:, idx] / divisor
    result = np.matmul(A, B)
    print("B = ")
    print(B)
    print()
    print("result = ")
    print(result)

    for jdx in range(columns):
        if idx != jdx:
            subtrahend = result[idx][jdx]
            print("Subtrahend: ", subtrahend)
            B[:, jdx] = B[:, jdx] - (subtrahend * B[:, idx])
            result = np.matmul(A, B)
            print("B = ")
            print(B)
            print()
            print("result = ")
            print(result)
    
    print(f"{idx} complete...\n")
    print("-----------------------------------------------------------------")

print(result)

输出是

B = 
[[0.50491008 0.83252516 0.0064097 ]
 [1.40104051 0.26863747 0.60867192]]

result = 
[[ 0.42134905 -0.47449191  0.34377291]
 [ 1.95833945 -0.05202331  0.97452729]
 [-1.56180438 -0.639868   -0.57998764]]
Start...
0 start
Divisor:  0.4213490465153189
B = 
[[1.19831785 0.83252516 0.0064097 ]
 [3.32513036 0.26863747 0.60867192]]

result = 
[[ 1.         -0.47449191  0.34377291]
 [ 4.64778422 -0.05202331  0.97452729]
 [-3.70667595 -0.639868   -0.57998764]]
Subtrahend:  -0.47449191424025916
B = 
[[1.19831785 1.40111729 0.0064097 ]
 [3.32513036 1.84638494 0.60867192]]

result = 
[[ 1.00000000e+00  9.01785029e-18  3.43772912e-01]
 [ 4.64778422e+00  2.15331272e+00  9.74527289e-01]
 [-3.70667595e+00 -2.39865577e+00 -5.79987642e-01]]
Subtrahend:  0.3437729124266499
B = 
[[ 1.19831785  1.40111729 -0.40553951]
 [ 3.32513036  1.84638494 -0.53441783]]

result = 
[[ 1.00000000e+00  9.01785029e-18 -8.94178216e-17]
 [ 4.64778422e+00  2.15331272e+00 -6.23255029e-01]
 [-3.70667595e+00 -2.39865577e+00  6.94267144e-01]]
0 complete...

-----------------------------------------------------------------
1 start
Divisor:  2.1533127196651907
B = 
[[ 1.19831785  0.65067989 -0.40553951]
 [ 3.32513036  0.85746252 -0.53441783]]

result = 
[[ 1.00000000e+00 -3.50978762e-17 -8.94178216e-17]
 [ 4.64778422e+00  1.00000000e+00 -6.23255029e-01]
 [-3.70667595e+00 -1.11393749e+00  6.94267144e-01]]
Subtrahend:  4.64778422285792
B = 
[[-1.82590189  0.65067989 -0.40553951]
 [-0.66017039  0.85746252 -0.53441783]]

result = 
[[ 1.00000000e+00 -3.50978762e-17 -8.94178216e-17]
 [ 1.50294027e-16  1.00000000e+00 -6.23255029e-01]
 [ 1.47066515e+00 -1.11393749e+00  6.94267144e-01]]
Subtrahend:  -0.6232550291421382
B = 
[[-1.82590189e+00  6.50679892e-01  2.22044605e-16]
 [-6.60170388e-01  8.57462516e-01  1.11022302e-16]]

result = 
[[ 1.00000000e+00 -3.50978762e-17 -1.04002052e-16]
 [ 1.50294027e-16  1.00000000e+00  4.94053401e-17]
 [ 1.47066515e+00 -1.11393749e+00 -2.07986655e-16]]
1 complete...

-----------------------------------------------------------------
2 start
Divisor:  -2.0798665491526003e-16
B = 
[[-1.82590189  0.65067989 -1.06759063]
 [-0.66017039  0.85746252 -0.53379532]]

result = 
[[ 1.00000000e+00 -3.50978762e-17  5.00041949e-01]
 [ 1.50294027e-16  1.00000000e+00 -2.37540914e-01]
 [ 1.47066515e+00 -1.11393749e+00  1.00000000e+00]]
Subtrahend:  1.4706651531204138
B = 
[[-0.25583354  0.65067989 -1.06759063]
 [ 0.12486378  0.85746252 -0.53379532]]

result = 
[[ 2.64605730e-01 -3.50978762e-17  5.00041949e-01]
 [ 3.49343145e-01  1.00000000e+00 -2.37540914e-01]
 [ 1.94932892e-16 -1.11393749e+00  1.00000000e+00]]
Subtrahend:  -1.1139374921272234
B = 
[[-0.25583354 -0.53854934 -1.06759063]
 [ 0.12486378  0.2628479  -0.53379532]]

result = 
[[ 2.64605730e-01  5.57015475e-01  5.00041949e-01]
 [ 3.49343145e-01  7.35394270e-01 -2.37540914e-01]
 [ 1.94932892e-16 -3.06368148e-17  1.00000000e+00]]
2 complete...

-----------------------------------------------------------------
[[ 2.64605730e-01  5.57015475e-01  5.00041949e-01]
 [ 3.49343145e-01  7.35394270e-01 -2.37540914e-01]
 [ 1.94932892e-16 -3.06368148e-17  1.00000000e+00]]

如您所见,结果在第 2 步开始时就偏离了轨道,并且不一致的情况会在以下子步骤中级联。

一些探索让我进入了 sympy 库。我尝试使用 sympy 中的一些内置函数编写上述代码。但结果是相似的。

from sympy import *
import numpy as np

init_printing(use_unicode=True)

A = np.random.normal(size=(3, 2))
B = np.random.normal(size=(2, 3))

result = np.matmul(A, B)

sympy_A = Matrix(A)
sympy_B = Matrix(B)

sympy_result = sympy_A * sympy_B

print("sympy_A = ")
pprint(sympy_A)
print()
print("sympy_B = ")
pprint(sympy_B)
print()
print("sympy_result = ")
pprint(sympy_result)

输出是

sympy_A = 
⎡0.805194469349538   -0.652924642433639⎤
⎢                                      ⎥
⎢-0.958576236163622  -0.434740834956345⎥
⎢                                      ⎥
⎣0.111691146842653   -1.07586944212184 ⎦

sympy_B = 
⎡ 0.29518339586785    -0.921434362266118   1.48986246464666 ⎤
⎢                                                           ⎥
⎣-0.0431486161372306  -0.0913003438306285  -1.53001914838522⎦

sympy_result = 
⎡0.265852832559516    -0.682321608015616     2.198616222001  ⎤
⎢                                                            ⎥
⎢-0.264197323182289   0.922957070561612    -0.762984951694262⎥
⎢                                                            ⎥
⎣0.0793916495852806  -0.00468881067914134   1.81250529492314 ⎦

以下是使用 sympy 内置函数的列操作

columns, rows = sympy_result.shape

print("Start...")
for idx in range(columns):
    print(f"{idx} start")
    divisor = sympy_result[idx, idx]
    print("Divisor: ", divisor)
    k = 1 / divisor
    sympy_B = sympy_B.elementary_col_op(op='n->kn', col=idx, k=k, col1=None, col2=None)
    # sympy_result = sympy_result.elementary_col_op(op='n->kn', col=idx, k=k, col1=None, col2=None)
    sympy_result = sympy_A * sympy_B
    print("sympy_B = ")
    pprint(sympy_B)
    print()
    print("sympy_result = ")
    pprint(sympy_result)
    print()

    for jdx in range(columns):
        if idx != jdx:
            subtrahend = sympy_result[idx, jdx]
            print("Subtrahend: ", subtrahend)
            k = -subtrahend
            sympy_B = sympy_B.elementary_col_op(op='n->n+km', col=jdx, k=k, col1=jdx, col2=idx)
            # sympy_result = sympy_result.elementary_col_op(op='n->n+km', col=jdx, k=k, col1=jdx, col2=idx)
            sympy_result = sympy_A * sympy_B
            print("sympy_B = ")
            pprint(sympy_B)
            print()
            print("sympy_result = ")
            pprint(sympy_result)
            print()
    
    print(f"{idx} complete...\n")
    print("-----------------------------------------------------------------")

输出是

Start...
0 start
Divisor:  0.265852832559516
sympy_B = 
⎡ 1.11032631484853   -0.921434362266118   1.48986246464666 ⎤
⎢                                                          ⎥
⎣-0.162302638350002  -0.0913003438306285  -1.53001914838522⎦

sympy_result = 
⎡       1.0          -0.682321608015616     2.198616222001  ⎤
⎢                                                           ⎥
⎢-0.99377283528903   0.922957070561612    -0.762984951694262⎥
⎢                                                           ⎥
⎣0.298630068451527  -0.00468881067914134   1.81250529492314 ⎦

Subtrahend:  -0.682321608015616
sympy_B = 
⎡ 1.11032631484853   -0.163834725696617  1.48986246464666 ⎤
⎢                                                         ⎥
⎣-0.162302638350002  -0.202042941014779  -1.53001914838522⎦

sympy_result = 
⎡       1.0         2.77555756156289e-17    2.198616222001  ⎤
⎢                                                           ⎥
⎢-0.99377283528903   0.244884391584963    -0.762984951694262⎥
⎢                                                           ⎥
⎣0.298630068451527   0.199072937828518     1.81250529492314 ⎦

Subtrahend:  2.19861622200100
sympy_B = 
⎡ 1.11032631484853   -0.163834725696617  -0.951318982893909⎤
⎢                                                          ⎥
⎣-0.162302638350002  -0.202042941014779  -1.17317793483535 ⎦

sympy_result = 
⎡       1.0         2.77555756156289e-17  -1.11022302462516e-16⎤
⎢                                                              ⎥
⎢-0.99377283528903   0.244884391584963      1.42194012495613   ⎥
⎢                                                              ⎥
⎣0.298630068451527   0.199072937828518      1.15593238204835   ⎦

0 complete...

-----------------------------------------------------------------
1 start
Divisor:  0.244884391584963
sympy_B = 
⎡ 1.11032631484853   -0.669028861481253  -0.951318982893909⎤
⎢                                                          ⎥
⎣-0.162302638350002  -0.825054384671467  -1.17317793483535 ⎦

sympy_result = 
⎡       1.0         1.11022302462516e-16  -1.11022302462516e-16⎤
⎢                                                              ⎥
⎢-0.99377283528903          1.0             1.42194012495613   ⎥
⎢                                                              ⎥
⎣0.298630068451527   0.812926199746991      1.15593238204835   ⎦

Subtrahend:  -0.993772835289030
sympy_B = 
⎡0.445463606284112   -0.669028861481253  -0.951318982893909⎤
⎢                                                          ⎥
⎣-0.982219273472611  -0.825054384671467  -1.17317793483535 ⎦

sympy_result = 
⎡        1.0           1.11022302462516e-16  -1.11022302462516e-16⎤
⎢                                                                 ⎥
⎢5.55111512312578e-17          1.0             1.42194012495613   ⎥
⎢                                                                 ⎥
⎣  1.10649404285483     0.812926199746991      1.15593238204835   ⎦

Subtrahend:  1.42194012495613
sympy_B = 
⎡0.445463606284112   -0.669028861481253  -2.22044604925031e-16⎤
⎢                                                             ⎥
⎣-0.982219273472611  -0.825054384671467  2.22044604925031e-16 ⎦

sympy_result = 
⎡        1.0           1.11022302462516e-16  -3.23767482109533e-16⎤
⎢                                                                 ⎥
⎢5.55111512312578e-17          1.0           1.16314824706815e-16 ⎥
⎢                                                                 ⎥
⎣  1.10649404285483     0.812926199746991    -2.63691421801158e-16⎦

1 complete...

-----------------------------------------------------------------
2 start
Divisor:  -2.63691421801158e-16
sympy_B = 
⎡0.445463606284112   -0.669028861481253  0.84206229921453 ⎤
⎢                                                         ⎥
⎣-0.982219273472611  -0.825054384671467  -0.84206229921453⎦

sympy_result = 
⎡        1.0           1.11022302462516e-16   1.22782713179679 ⎤
⎢                                                              ⎥
⎢5.55111512312578e-17          1.0           -0.441102042350565⎥
⎢                                                              ⎥
⎣  1.10649404285483     0.812926199746991           1.0        ⎦

Subtrahend:  1.10649404285483
sympy_B = 
⎡-0.486273311509407   -0.669028861481253  0.84206229921453 ⎤
⎢                                                          ⎥
⎣-0.0504823556790918  -0.825054384671467  -0.84206229921453⎦

sympy_result = 
⎡ -0.358583406988681   1.11022302462516e-16   1.22782713179679 ⎤
⎢                                                              ⎥
⎢   0.488076782152             1.0           -0.441102042350565⎥
⎢                                                              ⎥
⎣1.31838984174237e-16   0.812926199746991           1.0        ⎦

Subtrahend:  0.812926199746991
sympy_B = 
⎡-0.486273311509407   -1.35356336633193   0.84206229921453 ⎤
⎢                                                          ⎥
⎣-0.0504823556790918  -0.140519879820786  -0.84206229921453⎦

sympy_result = 
⎡ -0.358583406988681    -0.998132844197812    1.22782713179679 ⎤
⎢                                                              ⎥
⎢   0.488076782152       1.35858340698868    -0.441102042350565⎥
⎢                                                              ⎥
⎣1.31838984174237e-16  8.32667268468867e-17         1.0        ⎦

2 complete...

-----------------------------------------------------------------

我知道不能像我那样使用 sympy 库。

任何有效使用 sympy 库的方法,例如矩阵的符号创建以及对这些符号矩阵执行列运算,然后替换实际值,也将非常有帮助。

重要的是,我不想使用 numpy 库已经提供的内置逆或伪逆方法,因为我打算出于研究目的修改列操作。

python numpy sympy linear-algebra matrix-inverse
1个回答
0
投票

您可以通过设置精度然后通过fractions.Fraction 将所有数字转换为有理数来解决浮点错误。

但是,我认为不可能反转 2x3 矩阵。

从数学上讲,您有 3 个 A 行向量 A_0、A_1、A_2 和 3 个 B 列向量 B_0、B_1、B_2。实际上,您希望 A_i 和 B_j 的内积成为克罗内克增量。例如,这意味着 A_0 必须垂直于 B_1 和 B_2。但这对于 2-D 空间中的 3 个向量是无法完成的。

我可能是错的,所以如果你仍然想尝试一下,这里是代码。我已经确认它适用于方阵。

import numpy as np
from fractions import Fraction

precision = 2

wide_shape = (4, 4)
rows = wide_shape[-1]

A = np.random.normal(size=wide_shape[::-1])
B = np.random.normal(size=wide_shape)

A = np.array([[Fraction(int(a*10**precision), 10**precision) for a in row] for row in A])
B = np.array([[Fraction(int(b*10**precision), 10**precision) for b in row] for row in B])

result = np.matmul(A, B)

for i in range(rows):
    divisor = result[i, i]

    result[i] /= divisor
    A[i] /= divisor
    
    for j in range(i+1, rows):
        multiplier = result[j,i]
        
        result[j] -= multiplier * result[i]
        A[j] -= multiplier * A[i]

for i in range(rows-1, -1, -1):
    for j in range(i-1, -1, -1):
        multiplier = result[j, i]
        
        result[j] -= multiplier*result[i]
        A[j] -= multiplier*A[i]
    
© www.soinside.com 2019 - 2024. All rights reserved.