Files
sjy01-image-proc/vendor/github.com/nuknal/goNum/MatrixEigenClassicalJacobi.go
2024-10-24 15:46:01 +08:00

189 lines
5.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// MatrixEigenClassicalJacobi
/*
------------------------------------------------------
作者 : Black Ghost
日期 : 2018-11-30
版本 : 0.0.0
------------------------------------------------------
求解n阶对称矩阵A的全部特征值及其特征向量经典雅可比法
理论:
参考 李信真, 车刚明, 欧阳洁, 等. 计算方法. 西北工业大学
出版社, 2000, pp 84-89.
------------------------------------------------------
输入 :
A 系数矩阵
tol 最大容许误差
n 最大迭代步数
输出 :
Bbar 主特征值矩阵n阶对角矩阵
Rbar 主特征值所对应的特征向量n维矩阵第i列即对应于
第i个特征值的特征向量
(err) 解出标志false-未解出或达到步数上限;
true-全部解出
------------------------------------------------------
*/
package goNum
import (
"math"
)
//判断矩阵是否对称
func isSymMatrix_MatrixEigenClassicalJacobi(A Matrix) bool {
//是否方阵
if A.Columns != A.Rows {
return false
}
//是否对称
for i := 0; i < A.Rows; i++ {
for j := 0; j < A.Columns; j++ {
if j != i {
if A.GetFromMatrix(i, j) != A.GetFromMatrix(j, i) {
return false
}
}
}
}
return true
}
//取最大非对角元素
func maxElementElse_MatrixEigenClassicalJacobi(A Matrix) (int, int) {
var p, q int
var max float64
for i := 0; i < A.Rows-1; i++ {
for j := i + 1; j < A.Rows; j++ {
c := A.GetFromMatrix(i, j)
if math.Abs(max) < math.Abs(c) {
max = c
p = i
q = j
}
}
}
return p, q
}
//计算cos(theta)及sin(theta)
func cosSinTheta_MatrixEigenClassicalJacobi(A Matrix, p, q int) (float64, float64) {
apq := A.GetFromMatrix(p, q)
app := A.GetFromMatrix(p, p)
aqq := A.GetFromMatrix(q, q)
//情况1app-aqq=0
if app == aqq {
c := math.Sqrt(2.0) / 2.0
switch {
case apq < 0:
return c, -1.0 * c
case apq > 0:
return c, c
default:
panic("MatrixEigenClassicalJacobi/cosSinTheta: A(p, q) = 0")
}
}
//其他情况
c := (app - aqq) / (2.0 * apq)
d := 2.0 * apq / (app - aqq)
//如果|apq| << |app - aqq|用d
if 1000.0*math.Abs(apq) < math.Abs(app-aqq) {
tant := d / (1.0 + math.Sqrt(1.0+d*d))
cost := 1.0 / math.Sqrt(1.0+tant*tant)
sint := tant * cost
return cost, sint
}
// 用c
switch {
case c > 0:
tant := 1.0 / (c + math.Sqrt(1.0+c*c))
cost := 1.0 / math.Sqrt(1.0+tant*tant)
sint := tant * cost
return cost, sint
case c < 0:
tant := -1.0 / (math.Abs(c) + math.Sqrt(1.0+c*c))
cost := 1.0 / math.Sqrt(1.0+tant*tant)
sint := tant * cost
return cost, sint
default:
panic("MatrixEigenClassicalJacobi/cosSinTheta: A(p, q) = 0, c = 0")
}
return 0.0, 0.0
}
//非主对角元素平方之和
func sum2Else_MatrixEigenClassicalJacobi(A Matrix) float64 {
var sum2 float64
for i := 0; i < A.Rows-1; i++ {
for j := i + 1; j < A.Columns; j++ {
if i != j {
sum2 += A.GetFromMatrix(i, j) * A.GetFromMatrix(i, j)
}
}
}
return 2.0 * sum2
}
// MatrixEigenClassicalJacobi 求解n阶对称矩阵A的全部特征值及其特征向量经典雅可比法
func MatrixEigenClassicalJacobi(A Matrix, tol float64, n int) (Matrix, Matrix, bool) {
/*
求解n阶对称矩阵A的全部特征值及其特征向量经典雅可比法
输入 :
A 系数矩阵
tol 最大容许误差
n 最大迭代步数
输出 :
Bbar 主特征值矩阵n阶对角矩阵
Rbar 主特征值所对应的特征向量n维矩阵第i列即对应于
第i个特征值的特征向量
(err) 解出标志false-未解出或达到步数上限;
true-全部解出
*/
//判断A是否对称矩阵
if !isSymMatrix_MatrixEigenClassicalJacobi(A) {
return ZeroMatrix(A.Rows, A.Columns), ZeroMatrix(A.Rows, A.Columns), false
}
//第一步
//Rbar最终为特征向量矩阵
Rbar := IdentityE(A.Rows)
//复制A矩阵为BB为迭代过程中逐渐改变的矩阵最终将成为特征值矩阵
B := ZeroMatrix(A.Rows, A.Columns)
Bbar := ZeroMatrix(A.Rows, A.Columns)
for i := 0; i < len(A.Data); i++ {
B.Data[i] = A.Data[i]
}
//迭代步
for i := 0; i < n; i++ {
//第二步,最大元素所在行列号
p, q := maxElementElse_MatrixEigenClassicalJacobi(B)
//第三步计算cos(theta)及sin(theta)
cost, sint := cosSinTheta_MatrixEigenClassicalJacobi(B, p, q)
//第四步计算R及Rbar迭代B矩阵
//R为迭代矩阵
R := IdentityE(A.Rows)
R.SetMatrix(p, p, cost)
R.SetMatrix(p, q, sint)
R.SetMatrix(q, p, -1.0*sint)
R.SetMatrix(q, q, cost)
Bbar = DotPruduct(DotPruduct(R, B), R.Transpose()) //A1 = RARt
//Rbar = Rbar*Rt
Rbar = DotPruduct(Rbar, R.Transpose())
//第五步,判断误差
if sum2Else_MatrixEigenClassicalJacobi(Bbar) <= tol {
return Bbar, Rbar, true
}
//A = A1
for i := 0; i < len(Bbar.Data); i++ {
B.Data[i] = Bbar.Data[i]
}
}
return ZeroMatrix(A.Rows, A.Columns), ZeroMatrix(A.Rows, A.Columns), false
}