///|
// =====================================================================
// matrix3.mbt — 矩陣演算法(續):QR、子空間、最小二乘、張量積、指數
// =====================================================================
/// M-30 QR 分解(Gram–Schmidt 於行上):A = QR,Q 行標準正交
pub fn mat_qr(a : Mat) -> (Mat, Mat) {
let m = a.rows
let n = a.cols
let q_cols : Array[Array[Double]] = []
let r = mat_new(n, n)
for j = 0; j < n; j = j + 1 {
let mut v = mat_col(a, j)
for i = 0; i < q_cols.length(); i = i + 1 {
let c = euc_inner(q_cols[i], v)
mat_set(r, i, j, c)
v = euc_add(v, euc_scale(-c, q_cols[i]))
}
let nrm = ip_norm(euc_ip(m), v)
mat_set(r, j, j, nrm)
if nrm > 1.0e-12 {
q_cols.push(euc_scale(1.0 / nrm, v))
} else {
q_cols.push(euc_zero(m))
}
}
let q = mat_new(m, n)
for j = 0; j < n; j = j + 1 {
for i = 0; i < m; i = i + 1 {
mat_set(q, i, j, q_cols[j][i])
}
}
(q, r)
}
/// M-31 列空間基(A 的主元行)
pub fn mat_col_space_basis(a : Mat, eps : Double) -> Array[Array[Double]] {
let pivs = mat_pivot_cols(a, eps)
let out : Array[Array[Double]] = []
for j in pivs {
out.push(mat_col(a, j))
}
out
}
/// M-32 行空間基(RREF 非零列)
pub fn mat_row_space_basis(a : Mat, eps : Double) -> Array[Array[Double]] {
let r = mat_rref(a, eps)
let out : Array[Array[Double]] = []
for i = 0; i < r.rows; i = i + 1 {
let row = mat_row(r, i)
let mut nonzero = false
for x in row {
if x.abs() > eps {
nonzero = true
}
}
if nonzero {
out.push(row)
}
}
out
}
/// M-33 零空間基(自由變量法)
pub fn mat_null_space_basis(a : Mat, eps : Double) -> Array[Array[Double]] {
let r = mat_rref(a, eps)
let m = r.rows
let n = r.cols
let pivs = mat_pivot_cols(a, eps)
let is_piv = Array::make(n, false)
for p in pivs {
is_piv[p] = true
}
let out : Array[Array[Double]] = []
for f = 0; f < n; f = f + 1 {
if !is_piv[f] {
let v = Array::make(n, 0.0)
v[f] = 1.0
for i = 0; i < pivs.length(); i = i + 1 {
v[pivs[i]] = -mat_get(r, i, f)
}
let _ = m
out.push(v)
}
}
out
}
/// M-34 最小二乘解(法方程 AᵀAx = Aᵀb,經 Cholesky 或 LU)
pub fn least_squares(a : Mat, b : Array[Double]) -> Array[Double] {
let at = mat_transpose(a)
let ata = mat_mul(at, a)
let atb = mat_vec(at, b)
match mat_cholesky(ata) {
Some(l) => {
// 前代 Ly = atb
let n = atb.length()
let y = Array::make(n, 0.0)
for i = 0; i < n; i = i + 1 {
let mut s = atb[i]
for j = 0; j < i; j = j + 1 {
s = s - mat_get(l, i, j) * y[j]
}
y[i] = s / mat_get(l, i, i)
}
// 回代 Lᵀx = y
let x = Array::make(n, 0.0)
for i = n - 1; i >= 0; i = i - 1 {
let mut s = y[i]
for j = i + 1; j < n; j = j + 1 {
s = s - mat_get(l, j, i) * x[j]
}
x[i] = s / mat_get(l, i, i)
}
x
}
None => {
let (l, u, perm) = mat_lu(ata)
let _ = l
lu_solve(l, u, perm, atb)
}
}
}
/// M-35 外積 u vᵀ
pub fn outer_product(u : Array[Double], v : Array[Double]) -> Mat {
let out = mat_new(u.length(), v.length())
for i = 0; i < u.length(); i = i + 1 {
for j = 0; j < v.length(); j = j + 1 {
mat_set(out, i, j, u[i] * v[j])
}
}
out
}
/// M-36 Kronecker 積 A⊗B
pub fn mat_kronecker(a : Mat, b : Mat) -> Mat {
let out = mat_new(a.rows * b.rows, a.cols * b.cols)
for i = 0; i < a.rows; i = i + 1 {
for j = 0; j < a.cols; j = j + 1 {
for k = 0; k < b.rows; k = k + 1 {
for l = 0; l < b.cols; l = l + 1 {
mat_set(
out,
i * b.rows + k,
j * b.cols + l,
mat_get(a, i, j) * mat_get(b, k, l),
)
}
}
}
}
out
}
/// M-37 對稱化:sym(A) = (A + Aᵀ)/2(到對稱矩陣空間之正交投影)
pub fn mat_symmetrize(a : Mat) -> Mat {
let at = mat_transpose(a)
mat_scale(0.5, mat_add(a, at))
}
/// M-38 反對稱化:skew(A) = (A − Aᵀ)/2
pub fn mat_skew(a : Mat) -> Mat {
let at = mat_transpose(a)
mat_scale(0.5, mat_sub(a, at))
}
/// M-39 對稱判定
pub fn mat_is_symmetric(a : Mat, eps : Double) -> Bool {
mat_eq_eps(a, mat_transpose(a), eps)
}
/// M-40 矩陣指數 e^A(scaling-and-squaring + Taylor 20 項)
pub fn mat_exp(a : Mat) -> Mat {
// 選 s 使 ‖A/2^s‖∞ ≤ 1/2
let mut nrm = 0.0
for i = 0; i < a.rows; i = i + 1 {
let mut rs = 0.0
for j = 0; j < a.cols; j = j + 1 {
rs = rs + mat_get(a, i, j).abs()
}
if rs > nrm {
nrm = rs
}
}
let mut s = 0
let mut scale = 1.0
while nrm / scale > 0.5 {
scale = scale * 2.0
s = s + 1
}
let b = mat_scale(1.0 / scale, a)
// Taylor: E = I + B + B²/2! + ...
let n = a.rows
let mut e = mat_eye(n)
let mut term = mat_eye(n)
for k = 1; k <= 20; k = k + 1 {
term = mat_scale(1.0 / k.to_double(), mat_mul(term, b))
e = mat_add(e, term)
}
// 平方 s 次
for it_ = 0; it_ < s; it_ = it_ + 1 {
e = mat_mul(e, e)
}
e
}
/// M-41 譜分解重構:由 (特徵值, Q) 重建 A ≈ Q diag(λ) Qᵀ
pub fn spectral_reconstruct(vals : Array[Double], q : Mat) -> Mat {
let n = vals.length()
let d = mat_new(n, n)
for i = 0; i < n; i = i + 1 {
mat_set(d, i, i, vals[i])
}
mat_mul(q, mat_mul(d, mat_transpose(q)))
}
/// M-42 Rayleigh 商 xᵀAx / xᵀx
pub fn rayleigh_quotient(a : Mat, x : Array[Double]) -> Double {
let ax = mat_vec(a, x)
euc_inner(x, ax) / euc_inner(x, x)
}
/// M-43 對角矩陣構造
pub fn mat_diag(d : Array[Double]) -> Mat {
let n = d.length()
let out = mat_new(n, n)
for i = 0; i < n; i = i + 1 {
mat_set(out, i, i, d[i])
}
out
}
/// M-44 取對角線
pub fn mat_diagonal(a : Mat) -> Array[Double] {
let n = if a.rows < a.cols { a.rows } else { a.cols }
let out : Array[Double] = []
for i = 0; i < n; i = i + 1 {
out.push(mat_get(a, i, i))
}
out
}