///|
// =====================================================================
// ipspace.mbt — 有限維內積空間公理結構與衍生演算法
// 公理(自證於 ipspace_wbtest.mbt):
// 對稱性 ⟨u,v⟩=⟨v,u⟩、雙線性、正定性 ⟨v,v⟩≥0 且 =0 ⟺ v=0
// 衍生:範數、距離、角度、正交性、投影、Gram–Schmidt、Bessel 等
// =====================================================================
/// 內積空間字典 = 向量空間 + 內積
pub struct IPSp[V] {
sp : VecSp[V]
inner : (V, V) -> Double
}
/// 從向量空間字典與內積構造
pub fn[V] ips_make(sp : VecSp[V], inner : (V, V) -> Double) -> IPSp[V] {
{ sp, inner }
}
/// I-1 範數 ‖v‖ = √⟨v,v⟩
pub fn[V] ip_norm(ip : IPSp[V], v : V) -> Double {
let g = (ip.inner)(v, v)
if g < 0.0 {
0.0
} else {
g.sqrt()
}
}
/// I-2 距離 d(u,v) = ‖u−v‖
pub fn[V] ip_dist(ip : IPSp[V], a : V, b : V) -> Double {
let d = vsub(ip.sp, a, b)
ip_norm(ip, d)
}
/// I-3 餘弦角 cos θ = ⟨u,v⟩/(‖u‖‖v‖)(零向量時回 1)
pub fn[V] ip_cos(ip : IPSp[V], a : V, b : V) -> Double {
let na = ip_norm(ip, a)
let nb = ip_norm(ip, b)
if na == 0.0 || nb == 0.0 {
1.0
} else {
let c = (ip.inner)(a, b) / (na * nb)
if c > 1.0 {
1.0
} else if c < -1.0 {
-1.0
} else {
c
}
}
}
/// I-4 角度 θ = arccos(cos θ) ∈ [0, π]
pub fn[V] ip_angle(ip : IPSp[V], a : V, b : V) -> Double {
@math.acos(ip_cos(ip, a, b))
}
/// I-5 正交判定 |⟨u,v⟩| < eps
pub fn[V] ip_is_orthogonal(ip : IPSp[V], a : V, b : V, eps : Double) -> Bool {
(ip.inner)(a, b).abs() < eps
}
/// I-6 單位化 v/‖v‖(零向量回零)
pub fn[V] ip_normalize(ip : IPSp[V], v : V) -> V {
let n = ip_norm(ip, v)
if n == 0.0 {
ip.sp.zero
} else {
(ip.sp.scale)(1.0 / n, v)
}
}
/// I-7 投影係數 ⟨u,v⟩/⟨v,v⟩
pub fn[V] ip_proj_coeff(ip : IPSp[V], u : V, v : V) -> Double {
(ip.inner)(u, v) / (ip.inner)(v, v)
}
/// I-8 正交投影 proj_v(u) = ⟨u,v⟩/⟨v,v⟩ · v
pub fn[V] ip_proj(ip : IPSp[V], u : V, v : V) -> V {
(ip.sp.scale)(ip_proj_coeff(ip, u, v), v)
}
/// I-9 正交分量(拒絕)rej_v(u) = u − proj_v(u)
pub fn[V] ip_rej(ip : IPSp[V], u : V, v : V) -> V {
vsub(ip.sp, u, ip_proj(ip, u, v))
}
/// I-10 Gram–Schmidt 正交化(丟棄線性相關者,容差 eps)
pub fn[V] ip_gram_schmidt(
ip : IPSp[V],
vs : Array[V],
eps : Double,
) -> Array[V] {
let out : Array[V] = []
for v in vs {
let mut w = v
for u in out {
let c = (ip.inner)(w, u) / (ip.inner)(u, u)
w = vsub(ip.sp, w, (ip.sp.scale)(c, u))
}
if ip_norm(ip, w) > eps {
out.push(w)
}
}
out
}
/// I-11 Gram–Schmidt 標準正交化
pub fn[V] ip_orthonormal(ip : IPSp[V], vs : Array[V], eps : Double) -> Array[V] {
let ortho = ip_gram_schmidt(ip, vs, eps)
let out : Array[V] = []
for v in ortho {
out.push(ip_normalize(ip, v))
}
out
}
/// I-12 標準正交基下的座標 ⟨v, eᵢ⟩
pub fn[V] ip_coords(ip : IPSp[V], v : V, onb : Array[V]) -> Array[Double] {
let out : Array[Double] = []
for e in onb {
out.push((ip.inner)(v, e))
}
out
}
/// I-13 由座標重構向量 Σ cᵢeᵢ(Fourier 重構)
pub fn[V] ip_from_coords(
ip : IPSp[V],
cs : Array[Double],
onb : Array[V],
) -> V {
vlinc(ip.sp, cs, onb)
}
/// I-14 子空間正交投影(輸入為子空間之標準正交基)
pub fn[V] ip_proj_subspace(ip : IPSp[V], v : V, onb : Array[V]) -> V {
let cs = ip_coords(ip, v, onb)
ip_from_coords(ip, cs, onb)
}
/// I-15 到子空間之距離 ‖v − proj v‖
pub fn[V] ip_dist_subspace(ip : IPSp[V], v : V, onb : Array[V]) -> Double {
let p = ip_proj_subspace(ip, v, onb)
ip_dist(ip, v, p)
}
/// I-16 鏡射(Householder 型):沿單位法向量 n 反射 v ↦ v − 2⟨v,n⟩n
pub fn[V] ip_reflect(ip : IPSp[V], v : V, n_unit : V) -> V {
let c = 2.0 * (ip.inner)(v, n_unit)
vsub(ip.sp, v, (ip.sp.scale)(c, n_unit))
}
/// I-17 Gram 矩陣 Gᵢⱼ = ⟨vᵢ, vⱼ⟩(傳回扁平方陣,列主序)
pub fn[V] ip_gram_matrix(ip : IPSp[V], vs : Array[V]) -> Array[Double] {
let n = vs.length()
let g = Array::make(n * n, 0.0)
for i = 0; i < n; i = i + 1 {
for j = 0; j < n; j = j + 1 {
g[i * n + j] = (ip.inner)(vs[i], vs[j])
}
}
g
}
/// I-18 平行多面體體積 = √det(Gram)(依賴 matrix.mbt 之 det)
pub fn[V] ip_volume(ip : IPSp[V], vs : Array[V]) -> Double {
let g = ip_gram_matrix(ip, vs)
let d = flat_det(g, vs.length())
if d < 0.0 {
0.0
} else {
d.sqrt()
}
}
/// I-19 Bessel 殘差 ‖v‖² − Σ⟨v,eᵢ⟩²(對標準正交系必 ≥ 0)
pub fn[V] ip_bessel_residual(ip : IPSp[V], v : V, onb : Array[V]) -> Double {
let mut s = (ip.inner)(v, v)
for e in onb {
let c = (ip.inner)(v, e)
s = s - c * c
}
s
}
/// I-20 加權內積尺度變換:⟨,⟩' = c·⟨,⟩
pub fn[V] ips_scale(ip : IPSp[V], c : Double) -> IPSp[V] {
{
sp: ip.sp,
inner: fn(a, b) { c * (ip.inner)(a, b) },
}
}