1.改进平方根法
对称阵的三角分解定理
设
A
A
A为
n
n
n阶对称矩阵,且
A
A
A的所有顺序主子式均不为零,则
A
A
A可唯一分解为
A
=
L
D
L
T
,
A=LDL^T,
A=LDLT,
其中
L
L
L为单位下三角矩阵,
D
D
D为对角矩阵.即
A
=
[
1
l
21
1
⋮
⋮
⋱
l
n
1
l
n
2
…
1
]
[
d
1
d
2
⋱
d
n
]
[
1
l
21
…
l
n
1
1
…
l
n
2
⋱
⋮
1
]
A=\begin{bmatrix} 1&&&\\ l_{21}&1&&\\ \vdots&\vdots&\ddots&\\ l_{n1}&l_{n2}&\ldots&1 \end{bmatrix} \begin{bmatrix} d_1&&&\\ &d_2&&\\ &&\ddots&\\ &&&d_n \end{bmatrix} \begin{bmatrix} 1&l_{21}&\ldots&l_{n1}\\ &1&\ldots&l_{n2}\\ &&\ddots&\vdots\\ &&&1\end{bmatrix}
A=
1l21⋮ln11⋮ln2⋱…1
d1d2⋱dn
1l211……⋱ln1ln2⋮1
由矩阵乘法,并注意
l
j
j
=
1
,
l
j
k
=
0
(
j
<
k
)
,
得
l_{jj}=1,l_{jk}=0(j<k),得
ljj=1,ljk=0(j<k),得
a
i
j
=
∑
k
=
1
n
(
L
D
)
i
k
(
L
T
)
k
j
=
∑
k
=
1
n
l
i
k
d
k
l
j
k
=
∑
k
=
1
j
−
1
l
i
k
d
k
l
j
k
+
l
i
j
d
j
l
j
j
a_{ij}=\sum_{k = 1}^{n}(LD)_{ik}(L^T)_{kj}=\sum_{k = 1}^{n}l_{ik}d_kl_{jk}=\sum_{k = 1}^{j-1}l_{ik}d_kl_{jk}+l_{ij}d_jl_{jj}
aij=k=1∑n(LD)ik(LT)kj=k=1∑nlikdkljk=k=1∑j−1likdkljk+lijdjljj
于是得到计算
L
L
L的元素及
D
D
D的对角元素公式:
对于
i
=
1
,
2
,
…
,
n
.
i=1,2,\ldots,n.
i=1,2,…,n.
(
1
)
l
i
j
=
(
a
i
j
−
∑
k
=
1
j
−
1
l
i
k
d
k
l
j
k
)
/
d
j
,
j
=
1
,
2
,
…
,
i
−
1
(1)l_{ij}=(a_{ij}-\sum\limits_{k = 1}^{j-1}l_{ik}d_kl_{jk})/d_j,j=1,2,\ldots,i-1
(1)lij=(aij−k=1∑j−1likdkljk)/dj,j=1,2,…,i−1
(
2
)
d
i
=
a
i
i
−
∑
k
=
1
i
−
1
l
i
k
2
d
k
.
(
i
)
(2)d_i=a_{ii}-\sum\limits_{k = 1}^{i-1}l_{ik}^2d_k.(i)
(2)di=aii−k=1∑i−1lik2dk.(i)
为了避免重复计算,引进
t
i
j
=
l
i
j
d
j
,
t_{ij}=l_{ij}d_j,
tij=lijdj,由(i)式得到按行计算
L
,
T
L,T
L,T元素的公式:
d
1
=
a
11
.
d_1=a_{11}.
d1=a11.
对于
i
=
2
,
3
,
…
,
n
.
i=2,3,\ldots,n.
i=2,3,…,n.
(
1
)
t
i
j
=
a
i
j
−
∑
k
=
1
j
−
1
t
i
k
l
j
k
,
j
=
1
,
2
,
…
,
i
−
1
;
(1)t_{ij}=a_{ij}-\sum\limits_{k=1}^{j-1}t_{ik}l_{jk},j=1,2,\ldots,i-1;
(1)tij=aij−k=1∑j−1tikljk,j=1,2,…,i−1;
(
2
)
l
i
j
=
t
i
j
/
d
j
,
j
=
1
,
2
,
…
,
i
−
1
;
(2)l_{ij}=t_{ij}/d_j,j=1,2,\ldots,i-1;
(2)lij=tij/dj,j=1,2,…,i−1;
(
3
)
d
i
=
a
i
i
−
∑
k
=
1
i
−
1
t
i
k
l
i
k
.
(3)d_i=a_{ii}-\sum\limits_{k = 1}^{i-1}t_{ik}l_{ik}.
(3)di=aii−k=1∑i−1tiklik.
求解
L
y
=
b
,
D
L
T
x
=
y
Ly=b,DL^Tx=y
Ly=b,DLTx=y计算公式:
(
4
)
{
y
1
=
b
1
;
y
i
=
b
i
−
∑
k
=
1
i
−
1
l
i
k
y
k
,
i
=
2
,
3
,
…
,
n
.
(4)\begin{cases} y_1=b_1;\\ y_i=b_i-\sum\limits_{k = 1}^{i-1}l_{ik}y_k,i=2,3,\ldots,n. \end{cases}
(4)⎩
⎨
⎧y1=b1;yi=bi−k=1∑i−1likyk,i=2,3,…,n.
5
)
{
x
n
=
y
n
/
d
n
;
x
i
=
y
i
/
d
i
−
∑
k
=
i
+
1
n
l
k
i
x
k
,
i
=
n
−
1
,
n
−
2
,
…
,
1.
5)\begin{cases} x_n=y_n/d_n;\\ x_i=y_i/d_i-\sum\limits_{k=i+1}^{n}l_{ki}x_k,i=n-1,n-2,\ldots,1. \end{cases}
5)⎩
⎨
⎧xn=yn/dn;xi=yi/di−k=i+1∑nlkixk,i=n−1,n−2,…,1.
2.Python实现改进平方根
# 自己原创改进平方根
def improved_square_root(symmetric_positive_define_matrix: np.ndarray, right_hand_side_vector: np.ndarray):
rows, columns = symmetric_positive_define_matrix.shape
# judge if it is a square matrix
if rows == columns:
# 判断是否对称
if (symmetric_positive_define_matrix.T == symmetric_positive_define_matrix).all():
for k in range(rows): # 判断各阶顺序主子式是否为0,即判定是否正定
if det(symmetric_positive_define_matrix[:k + 1, :k + 1]) == 0:
raise Exception("error, cannot decompose")
else:
# 初始化单位下三角矩阵L
square_ones_matrix = np.ones((rows, columns))
lower_triangle_matrix = np.tril(square_ones_matrix)
diagonal_matrix = np.diag(np.diag(square_ones_matrix))
t = lower_triangle_matrix @ diagonal_matrix
diagonal_matrix[0, 0] = symmetric_positive_define_matrix[0, 0]
for i in range(1, rows):
for j in range(i):
prod = 0
for k in range(j):
prod += t[i, k] * lower_triangle_matrix[j, k]
t[i, j] = symmetric_positive_define_matrix[i, j] - prod
lower_triangle_matrix[i, j] = t[i, j] / diagonal_matrix[j, j]
prod = 0
for k in range(i):
prod += t[i, k] * lower_triangle_matrix[i, k]
diagonal_matrix[i, i] = symmetric_positive_define_matrix[i, i] - prod
return inv(
lower_triangle_matrix @ diagonal_matrix @ lower_triangle_matrix.T) @ right_hand_side_vector
# 自己写的发现第一个解x0=1.,而不是1.11111111,有精度损失,所以采用矩阵运算
# # Ly=b,此处不指定双精度浮点数据类型,则可能会损失精度,导致结果偏差太大
# y = np.ones_like(right_hand_side_vector, dtype=np.float64)
# for i in range(rows):
# prod = 0
# for k in range(i):
# prod += lower_triangle_matrix[i, k] * y[k, 0]
# y[i, 0] = right_hand_side_vector[i, 0] - prod
# # DL^Tx=y,此处不指定双精度浮点数据类型,则可能会损失精度,导致结果偏差太大
# x = np.ones_like(right_hand_side_vector, dtype=np.float64)
# x[rows - 1, 0] = y[rows - 1, 0] / diagonal_matrix[rows - 1, rows - 1]
# for i in range(rows - 2, 0, -1):
# prod = 0
# for k in range(i + 1, rows):
# prod += lower_triangle_matrix[k, i] * x[k, 0]
# x[i, 0] = y[i, 0] / diagonal_matrix[i, i] - prod
# return x
# for i in range(rows):
# for j in range(i):
# prod = 0
# for k in range(j):
# prod += lower_triangle_matrix[i, k] * diagonal_matrix[k, k] * lower_triangle_matrix[j, k]
# lower_triangle_matrix[i, j] = (symmetric_positive_define_matrix[i, j] - prod) / diagonal_matrix[
# j, j]
# prod = 0
# for k in range(i):
# prod += lower_triangle_matrix[i, k] * diagonal_matrix[k, k] * lower_triangle_matrix[i, k]
# diagonal_matrix[i, i] = symmetric_positive_define_matrix[i, i] - prod
else:
raise Exception("error,the input matrix must be a symmetric-matrix")
else:
raise Exception("ERROR:please pass a square matrix.")
3.用改进平方根解对称正定方程组
[ 2 − 1 1 − 1 − 2 3 1 3 1 ] [ x 1 x 2 x 3 ] = [ 4 5 6 ] . \begin{bmatrix} 2&-1&1\\ -1&-2&3\\ 1&3&1 \end{bmatrix} \begin{bmatrix} x_1\\ x_2\\ x_3 \end{bmatrix}= \begin{bmatrix} 4\\ 5\\ 6 \end{bmatrix}. 2−11−1−23131 x1x2x3 = 456 .
4.测试
if __name__ == '__main__':
# 改进平方根法测试成功,来源详见李庆扬数值分析第5版P177,e.g.10
symmetric_positive_define_matrix1 = np.array([[2, -1, 1], [-1, -2, 3], [1, 3, 1]])
column_vector = np.array([4, 5, 6]).reshape((3, 1))
print(improved_square_root(symmetric_positive_define_matrix1, column_vector))