mutable API

Luna-Flow/linear-algebra/mutable 提供面向执行的稠密线性代数:Matrix[T] 将元素存放在一个行主序的 Array[T] 中,并可原地更新;Vector[T] 包装一个 Array[T];RowView、ColView 和 Transpose 是矩阵的实时视图。在存储之上,该包实现了仓库中的数值例程:基于 LU 的行列式、逆矩阵与秩,Cholesky 分解,对称矩阵特征值,幂法,行化简以及简单统计。

源码:src/mutable。算法及其数值性质在 mutable 设计中推导;immut 是面向值的对应包,核心名称相同。

导入

///|
import {
  "Luna-Flow/linear-algebra/mutable",
}

约定

  • 形状与存储。 矩阵有 row() 行、col() 列,二者均非负;0×n0 \times n 与 n×0n \times 0 都合法且互不相同。元素 (i,j)(i, j) 存放在偏移 i⋅col+ji \cdot \mathrm{col} + j 处。
  • 修改。 返回 Unit 的方法(set、swap_rows、*_inplace、视图写入)会原地修改矩阵,它的所有视图和别名都能看到这一修改。其余方法都返回新值,不改变参数;唯一的例外是 reduce_row_elimination,它原地工作并返回其接收者。
  • 别名构造函数。 Matrix::from_array 与 Vector::from_array 直接接管给定数组而不复制。from_2d_array、copy 以及所有到数组的转换都会复制。
  • 边界。 所有公开访问器都分别检查行和列,索引越界时中止;迭代器、视图和转置视图也是如此。
  • 受检与非受检。 存在运行时失败情形的操作返回 Result[_, LinearAlgebraError],并有一个会中止的 unchecked_* 对应版本(unchecked_inverse 则返回 Option)。参见错误设计。
  • 数值例程要求 T : Compare + Field + Num + Tolerance(需要开平方时还要求 Sqrt)。Tolerance 只为 Double 和 Float 实现,因此这些例程面向浮点矩阵。
  • 目标平台。 内核针对 native、js、wasm 和 wasm-gc 分别调优。公开语义在所有目标上相同;若某个内核的求和顺序不同,浮点结果的最后几位可能有差异。

类型

Matrix

Matrix[T] 是可变稠密矩阵。

type Matrix[T] derive(Eq)

该类型是抽象的。它实现了 Eq(形状与元素)、Show、Add、Sub、Neg 和 Mul(矩阵乘积),元素约束与相应方法一致。

Lens

Lens[T] 是 m[r] 返回的行访问器;它支撑 m[r][c] 与 m[r][c] = x。

type Lens[T]

Lens::at, Lens::set

Lens::at(l, c) 读取、Lens::set(l, c, x) 写入该 lens 所指行的第 c 列。

#alias("_[_]")
pub fn[T] Lens::at(Self[T], Int) -> T
#alias("_[_]=_")
pub fn[T] Lens::set(Self[T], Int, T) -> Unit

从 Transpose 获得的 lens 寻址的是转置后的矩阵。列越界时中止。

RowView, ColView

RowView[T] 和 ColView[T] 是一行或一列的实时视图。

pub struct RowView[T] {
  data : Matrix[T]
  row : Int
}
pub struct ColView[T] {
  data : Matrix[T]
  col : Int
}

字段可读。通过视图写入会改变底层矩阵。

Transpose

Transpose[T] 是矩阵的实时转置视图。

pub struct Transpose[T](Matrix[T])

它与被包装的矩阵共享存储。它的方法寻址转置后的矩阵:视图的元素 (i,j)(i, j) 就是矩阵的元素 (j,i)(j, i)。

Vector

Vector[A] 是可变稠密向量,是 Array[A] 的包装类型。

pub struct Vector[A](Array[A])

数组可通过 v.0 读取。它实现了 Eq、Show(|a, b, c|)、Add、Mul(逐元素)、Neg、Debug 以及 quickcheck 的 Arbitrary。

Tolerance

Tolerance 提供数值例程使用的绝对阈值。

pub trait Tolerance {
  fn tolerance() -> Self
}
pub impl Tolerance for Float
pub impl Tolerance for Double

两个实例都返回 10−1110^{-11}。该 trait 不是开放的:其他包不能添加实例。阈值如何以及在何处使用,见 mutable 设计。

Sqrt

Sqrt 是 Luna-Flow/arithmetic.Sqrt 的重新导出,cholesky_decomposition、eigen、is_positive_definite、frobenius_norm 和 std_dev 需要它。

pub using @arithmetic {trait Sqrt}

构造

Matrix::make

Matrix::make(r, c, f) 构造元素为 f(i,j)f(i, j) 的 r×cr \times c 矩阵。

pub fn[A] Matrix::make(Int, Int, (Int, Int) -> A) -> Self[A]

负维度会中止。f 应当是纯函数;对同一元素调用它的次数未作规定。

Matrix::new

Matrix::new(r, c, x) 构造一个以 x 填充的 r×cr \times c 矩阵。

pub fn[T] Matrix::new(Int, Int, T) -> Self[T]

Matrix::from_2d_array

Matrix::from_2d_array(rows) 把嵌套的行复制到新矩阵中。

pub fn[T] Matrix::from_2d_array(Array[Array[T]]) -> Self[T]

[] 得到 0×00 \times 0;行长不一致时中止。

Matrix::from_array

Matrix::from_array(r, c, data) 将 data 直接作为 r×cr \times c 矩阵的行主序存储。

pub fn[T] Matrix::from_array(Int, Int, Array[T]) -> Self[T]

负维度或 data.length() != r * c 会中止。数组不会被复制:之后对 data 的写入会改变矩阵,反之亦然。

identity

identity(n) 构造 n×nn \times n 单位矩阵。它是顶层函数 @mutable.identity(n)。

pub fn[T : @luna-generic.Zero + @luna-generic.One] identity(Int) -> Matrix[T]

Matrix::copy

Matrix::copy(m) 返回拥有独立存储的深拷贝。

pub fn[T] Matrix::copy(Self[T]) -> Self[T]
///|
test "mutable construction and aliasing" {
  let data = [1, 2, 3, 4]
  let shared = @mutable.Matrix::from_array(2, 2, data)
  data[0] = 100
  inspect(shared.get(0, 0), content="100")
  let separate = shared.copy()
  shared.set(0, 0, 1)
  inspect(separate.get(0, 0), content="100")
  let id : @mutable.Matrix[Double] = @mutable.identity(2)
  inspect(id, content="|1, 0|\n|0, 1|")
  inspect(
    @mutable.Matrix::make(2, 3, (i, j) => i * 3 + j),
    content="|0, 1, 2|\n|3, 4, 5|",
  )
}

形状与元素访问

Matrix::row, Matrix::col, Matrix::shape

行数、列数以及 (row, col)。

pub fn[T] Matrix::row(Self[T]) -> Int
pub fn[T] Matrix::col(Self[T]) -> Int
pub fn[T] Matrix::shape(Self[T]) -> (Int, Int)

Matrix::is_square

Matrix::is_square(m) 返回 row() == col()。

pub fn[T] Matrix::is_square(Self[T]) -> Bool

Matrix::get, Matrix::set

get(r, c) 读取元素 (r,c)(r, c);set(r, c, x) 原地写入该元素。

pub fn[T] Matrix::get(Self[T], Int, Int) -> T
pub fn[T] Matrix::set(Self[T], Int, Int, T) -> Unit

二者均为 O(1)O(1),索引越界时中止。它们是访问单个元素最快的方式。

Matrix::at

Matrix::at(m, r) 返回第 r 行的 Lens;它支撑 m[r][c] 与 m[r][c] = x。

#alias("_[_]")
pub fn[T] Matrix::at(Self[T], Int) -> Lens[T]

Matrix::row_view, Matrix::col_view

row_view(r) 与 col_view(c) 返回一行或一列的实时视图。

pub fn[T] Matrix::row_view(Self[T], Int) -> RowView[T]
pub fn[T] Matrix::col_view(Self[T], Int) -> ColView[T]

索引在创建视图时检查。

Matrix::to_transpose

Matrix::to_transpose(m) 在 O(1)O(1) 时间内返回与 m 共享存储的实时转置视图。

pub fn[T] Matrix::to_transpose(Self[T]) -> Transpose[T]

Matrix::equal, Matrix::to_string

equal 比较形状和元素(支撑 ==);to_string 把每行渲染为 |a, b| 形式的一行。

pub fn[T : Eq] Matrix::equal(Self[T], Self[T]) -> Bool
pub fn[T : Show] Matrix::to_string(Self[T]) -> String
///|
test "mutable access" {
  let m = @mutable.Matrix::from_2d_array([[1, 2, 3], [4, 5, 6]])
  m[0][2] = 30
  m.set(1, 0, 40)
  inspect(m.get(0, 2), content="30")
  inspect(m[1][0], content="40")
  let r = m.row_view(1)
  r[2] = 60
  inspect(m, content="|1, 2, 30|\n|40, 5, 60|")
  debug_inspect(m.shape(), content="(2, 3)")
}

遍历与原地变换

Matrix::each, Matrix::eachi

each(f) 按行主序对每个元素调用 f;eachi(f) 还会传入扁平的行主序索引。

pub fn[T] Matrix::each(Self[T], (T) -> Unit) -> Unit
pub fn[T] Matrix::eachi(Self[T], (Int, T) -> Unit) -> Unit

Matrix::each_row_col

each_row_col(f) 按行主序对每个元素调用 f(i, j, a_ij)。

pub fn[T] Matrix::each_row_col(Self[T], (Int, Int, T) -> Unit) -> Unit

Matrix::each_row, Matrix::eachi_row, Matrix::each_col, Matrix::eachi_col

访问一行(从左到右)或一列(从上到下);eachi_* 形式会传入元素在该行或该列中的位置。

pub fn[T] Matrix::each_row(Self[T], Int, (T) -> Unit) -> Unit
pub fn[T] Matrix::eachi_row(Self[T], Int, (Int, T) -> Unit) -> Unit
pub fn[T] Matrix::each_col(Self[T], Int, (T) -> Unit) -> Unit
pub fn[T] Matrix::eachi_col(Self[T], Int, (Int, T) -> Unit) -> Unit

Matrix::iter, Matrix::iter_row, Matrix::iter_col

遍历全部元素(行主序)、一行或一列的迭代器。

pub fn[T] Matrix::iter(Self[T]) -> Iter[T]
pub fn[T] Matrix::iter_row(Self[T], Int) -> Iter[T]
pub fn[T] Matrix::iter_col(Self[T], Int) -> Iter[T]

Matrix::map, Matrix::mapi

map(f) 与 mapi(f) 返回对每个元素应用 f 后的新矩阵;mapi 还会收到 (i, j)。

pub fn[T, U] Matrix::map(Self[T], (T) -> U) -> Self[U]
pub fn[T, U] Matrix::mapi(Self[T], (Int, Int, T) -> U) -> Self[U]

Matrix::map_inplace, Matrix::map_row_inplace, Matrix::map_col_inplace

将每个元素、某一行的每个元素或某一列的每个元素原地替换为 f(entry)。

#alias(map_in_place, deprecated)
pub fn[T] Matrix::map_inplace(Self[T], (T) -> T) -> Unit
#alias(map_row_in_place, deprecated)
pub fn[T] Matrix::map_row_inplace(Self[T], Int, (T) -> T) -> Unit
#alias(map_col_in_place, deprecated)
pub fn[T] Matrix::map_col_inplace(Self[T], Int, (T) -> T) -> Unit

Matrix::swap_rows, Matrix::swap_cols

原地交换两行或两列。

pub fn[T] Matrix::swap_rows(Self[T], Int, Int) -> Unit
pub fn[T] Matrix::swap_cols(Self[T], Int, Int) -> Unit

索引越界时中止;两个索引相等时矩阵保持不变。

///|
test "mutable traversal" {
  let m = @mutable.Matrix::from_2d_array([[1, 2], [3, 4]])
  let mut sum = 0
  m.each(x => sum = sum + x)
  inspect(sum, content="10")
  m.map_col_inplace(1, x => x * 10)
  m.swap_rows(0, 1)
  inspect(m, content="|3, 40|\n|1, 20|")
  debug_inspect(m.iter_col(0).to_array(), content="[3, 1]")
}

转换

Matrix::to_array, Matrix::to_2d_array, Matrix::to_vector

将所有元素复制到扁平的行主序数组、嵌套行或扁平的 Vector 中。

pub fn[T] Matrix::to_array(Self[T]) -> Array[T]
pub fn[T] Matrix::to_2d_array(Self[T]) -> Array[Array[T]]
pub fn[T] Matrix::to_vector(Self[T]) -> Vector[T]

Matrix::row_to_array, Matrix::col_to_array, Matrix::row_to_vector, Matrix::col_to_vector

将一行或一列复制到数组或 Vector 中。

pub fn[T] Matrix::row_to_array(Self[T], Int) -> Array[T]
pub fn[T] Matrix::col_to_array(Self[T], Int) -> Array[T]
pub fn[T] Matrix::row_to_vector(Self[T], Int) -> Vector[T]
pub fn[T] Matrix::col_to_vector(Self[T], Int) -> Vector[T]

Matrix::transpose

Matrix::transpose(m) 返回一个新的、已物化的转置;对比 to_transpose,后者返回视图。

pub fn[T] Matrix::transpose(Self[T]) -> Self[T]

Matrix::horizontal_combine, Matrix::vertical_combine

分块拼接 [A  B][A \; B] 与 [AB]\begin{bmatrix} A \\ B \end{bmatrix};行数(或列数)不同时中止。

pub fn[T] Matrix::horizontal_combine(Self[T], Self[T]) -> Self[T]
pub fn[T] Matrix::vertical_combine(Self[T], Self[T]) -> Self[T]

算术运算

Matrix::add, Matrix::sub, Matrix::neg

逐元素的 A+BA + B、A−BA - B、−A-A;它们支撑相应运算符,形状不同时中止。

pub fn[T : Add] Matrix::add(Self[T], Self[T]) -> Self[T]
pub fn[T : Add + Neg] Matrix::sub(Self[T], Self[T]) -> Self[T]
pub fn[T : Neg] Matrix::neg(Self[T]) -> Self[T]

Matrix::scale, Matrix::add_constant

将每个元素右乘一个标量,或给每个元素加上一个标量。

pub fn[T : Mul] Matrix::scale(Self[T], T) -> Self[T]
pub fn[T : Add] Matrix::add_constant(Self[T], T) -> Self[T]

Matrix::adjoint

Matrix::adjoint(m) 返回共轭转置 A∗A^{*};它要求标量类型实现 Conjugate。

pub fn[T : @luna-generic.Conjugate] Matrix::adjoint(Self[T]) -> Self[T]

Matrix::null

当每个元素都严格等于 Zero::zero() 时,Matrix::null(m) 返回 true。

pub fn[T : Compare + @luna-generic.Zero] Matrix::null(Self[T]) -> Bool

Matrix::mul

Matrix::mul(a, b) 是 a * b 背后的矩阵乘积。

pub fn[T : @luna-generic.AddMonoid + Mul] Matrix::mul(Self[T], Self[T]) -> Self[T]

它检查 cols⁡(A)=rows⁡(B)\operatorname{cols}(A) = \operatorname{rows}(B),不满足时以 Matrix::mul: dimension mismatch 中止,满足时调用 unchecked_matmul。本包没有返回 Result 的 matmul;请先检查形状,或使用 @immut.Matrix::matmul。

Matrix::unchecked_matmul

Matrix::unchecked_matmul(a, b) 返回 ABAB,不验证形状。

pub fn[T : @luna-generic.AddMonoid + Mul] Matrix::unchecked_matmul(Self[T], Self[T]) -> Self[T]

开销:rcnrcn 次乘加。较大的乘积(至少 4×16×164 \times 16 \times 16)会先把 BB 的列连续打包,再做乘法。

Matrix::mul_vec

当 cols⁡(A)=len⁡(x)\operatorname{cols}(A) = \operatorname{len}(x) 时,Matrix::mul_vec(a, x) 返回 Ok(Ax),否则返回 DimensionMismatch。

pub fn[T : @luna-generic.AddMonoid + Mul] Matrix::mul_vec(Self[T], Vector[T]) -> Result[Vector[T], @error.LinearAlgebraError]

Matrix::unchecked_mul_vec

Matrix::unchecked_mul_vec(a, x) 返回 AxAx,长度不匹配时中止。

pub fn[T : @luna-generic.AddMonoid + Mul] Matrix::unchecked_mul_vec(Self[T], Vector[T]) -> Vector[T]

Matrix::pow, Matrix::matrix_power

对方阵 AA 和 k≥0k \ge 0,pow(k) 通过二进制快速幂返回 Ok(A^k)(A0=IA^0 = I)。matrix_power 是同一函数的另一个名字。

pub fn[T : @luna-generic.Semiring] Matrix::pow(Self[T], Int) -> Result[Self[T], @error.LinearAlgebraError]
pub fn[T : @luna-generic.Semiring] Matrix::matrix_power(Self[T], Int) -> Result[Self[T], @error.LinearAlgebraError]

错误:NonSquareMatrix(先检查),然后是 NegativeExponent。

Matrix::unchecked_pow, Matrix::unchecked_matrix_power

pow 与 matrix_power 的中止形式。

pub fn[T : @luna-generic.Semiring] Matrix::unchecked_pow(Self[T], Int) -> Self[T]
pub fn[T : @luna-generic.Semiring] Matrix::unchecked_matrix_power(Self[T], Int) -> Self[T]

Matrix::trace, Matrix::unchecked_trace

对方阵,trace() 返回 Ok(Σ a_ii),否则返回 NonSquareMatrix;unchecked_trace 则改为中止。

pub fn[T : @luna-generic.AddMonoid] Matrix::trace(Self[T]) -> Result[T, @error.LinearAlgebraError]
pub fn[T : @luna-generic.AddMonoid] Matrix::unchecked_trace(Self[T]) -> T
///|
test "mutable arithmetic" {
  let a = @mutable.Matrix::from_2d_array([[1.0, 2.0], [3.0, 4.0]])
  let x = @mutable.Vector::from_array([1.0, 1.0])
  inspect(a.mul_vec(x).unwrap(), content="|3, 7|")
  inspect(a * a, content="|7, 10|\n|15, 22|")
  inspect(a.pow(0).unwrap(), content="|1, 0|\n|0, 1|")
  inspect(a.trace().unwrap(), content="5")
  inspect(
    a.mul_vec(@mutable.Vector::from_array([1.0])) is Err(_),
    content="true",
  )
}

线性方程组与分解

本节所有例程都面向 Float 与 Double 矩阵。诸如“该主元为零”之类的判断,是将绝对值与 Tolerance::tolerance()(10−1110^{-11})比较;算法、开销与误差界见设计页面。

Matrix::determinant

对于方阵,Matrix::determinant(a) 返回 Ok(det A);否则返回 NonSquareMatrix。

pub fn[T : Compare + @luna-generic.Field + @luna-generic.Num + Tolerance] Matrix::determinant(Self[T]) -> Result[T, @error.LinearAlgebraError]

当 n≤4n \le 4 时:使用闭式余子式公式。当 n≥5n \ge 5 时:若矩阵在容差内为三角矩阵,则取对角线乘积;否则做部分选主元的 LU 分解,对 ss 次行交换有 det⁡A=(−1)s∏iuii\det A = (-1)^{s} \prod_i u_{ii}。若某个主元低于容差,结果严格为零。0×00 \times 0 矩阵的 det⁡\det 为 11。

Matrix::unchecked_determinant

determinant 的中止形式。

pub fn[T : Compare + @luna-generic.Field + @luna-generic.Num + Tolerance] Matrix::unchecked_determinant(Self[T]) -> T

Matrix::inverse

Matrix::inverse(a) 返回 Ok(A^{-1});对非方阵返回 NonSquareMatrix;当某个主元低于容差时返回 SingularMatrix。

pub fn[T : Compare + @luna-generic.Field + @luna-generic.Num + Tolerance] Matrix::inverse(Self[T]) -> Result[Self[T], @error.LinearAlgebraError]

单位矩阵、对角矩阵和置换矩阵会被识别并直接求逆(P−1=PTP^{-1} = P^{\mathsf T});其他矩阵则基于部分选主元的 LU 分解逐列求解。开销 ≈83n3\approx \tfrac{8}{3} n^3 flops。0×00 \times 0 矩阵的逆矩阵是 0×00 \times 0 矩阵。

Matrix::unchecked_inverse

Matrix::unchecked_inverse(a) 返回 Some(A^{-1}),对奇异矩阵返回 None,对非方阵则中止。

pub fn[T : Compare + @luna-generic.Field + @luna-generic.Num + Tolerance] Matrix::unchecked_inverse(Self[T]) -> Self[T]?

Matrix::is_invertible, Matrix::unchecked_is_invertible

当 LU 分解没有发现低于容差的主元时,is_invertible() 返回 Ok(true),否则返回 Ok(false);对非方阵返回 NonSquareMatrix;unchecked_is_invertible 则改为中止。

pub fn[T : Compare + @luna-generic.Field + @luna-generic.Num + Tolerance] Matrix::is_invertible(Self[T]) -> Result[Bool, @error.LinearAlgebraError]
pub fn[T : Compare + @luna-generic.Field + @luna-generic.Num + Tolerance] Matrix::unchecked_is_invertible(Self[T]) -> Bool

Matrix::rank

Matrix::rank(a) 返回在 a 的副本上做部分选主元高斯消元所找到的主元个数。

pub fn[T : Compare + @luna-generic.Field + @luna-generic.Num + Tolerance] Matrix::rank(Self[T]) -> Int

若某列剩余元素中的最大值低于容差,该列不贡献主元。适用于任意形状;a 保持不变。开销 O(min⁡(r,c) rc)O(\min(r, c)\, r c)。

Matrix::reduce_row_elimination

Matrix::reduce_row_elimination(a) 通过部分选主元的 Gauss–Jordan 消元把 a 原地变换为简化行阶梯形,并返回 a 本身。

pub fn[T : Compare + @luna-generic.Field + @luna-generic.Num + Tolerance] Matrix::reduce_row_elimination(Self[T]) -> Self[T]

主元被精确置为一,主元列的其他元素被精确置为零,过程中绝对值不超过容差的元素会被置零。如需保留原矩阵,请先复制。

Matrix::cholesky_decomposition

Matrix::cholesky_decomposition(a) 返回 Some(L),其中 LL 为下三角矩阵、对角线为正且 LLT=AL L^{\mathsf T} = A;否则返回 None。

pub fn[T : Compare + @luna-generic.Field + @luna-generic.Num + @arithmetic.Sqrt + Tolerance] Matrix::cholesky_decomposition(Self[T]) -> Self[T]?

None 表示 a 不是方阵、在容差内不对称,或者某个对角主元 ajj−∑k<jljk2a_{jj} - \sum_{k<j} l_{jk}^2 不超过容差(矩阵不是正定的,或接近奇异)。开销 ≈n3/3\approx n^3/3 flops。

Matrix::is_positive_definite

Matrix::is_positive_definite(a) 返回 cholesky_decomposition 是否成功。

pub fn[T : Compare + @luna-generic.Field + @luna-generic.Num + @arithmetic.Sqrt + Tolerance] Matrix::is_positive_definite(Self[T]) -> Bool

Matrix::is_symmetric

当 a 是方阵且对所有 i<ji < j 有 ∣aij−aji∣≤tol|a_{ij} - a_{ji}| \le \mathrm{tol} 时,Matrix::is_symmetric(a) 返回 true。

pub fn[T : Compare + @luna-generic.Num + Tolerance] Matrix::is_symmetric(Self[T]) -> Bool
///|
test "solving and factorizing" {
  let a = @mutable.Matrix::from_2d_array([[4.0, 2.0], [2.0, 3.0]])
  inspect(a.determinant().unwrap(), content="8")
  inspect(a.inverse().unwrap(), content="|0.375, -0.25|\n|-0.25, 0.5|")
  let l = a.cholesky_decomposition().unwrap()
  inspect(l, content="|2, 0|\n|1, 1.4142135623730951|")
  inspect(a.is_positive_definite(), content="true")
  let r = @mutable.Matrix::from_2d_array([
    [1.0, 2.0, 3.0],
    [2.0, 4.0, 6.0],
    [7.0, 8.0, 9.0],
  ])
  inspect(r.rank(), content="2")
  inspect(r.is_invertible().unwrap(), content="false")
}

特征值

Matrix::eigen

Matrix::eigen(a) 以 (values, vectors) 的形式返回实对称矩阵的特征值与特征向量,其中 vectors 的第 kk 列是对应 values[k] 的特征向量。

pub fn[T : Compare + @luna-generic.Field + @luna-generic.Num + @arithmetic.Sqrt + Tolerance] Matrix::eigen(Self[T]) -> (Vector[T], Self[T])
  • 若 a 不是方阵、在容差内不对称,或某个特征值在 60 次迭代内未收敛,则中止。
  • 对 2×22 \times 2 输入,特征值由特征多项式给出:λ1,2=m±m2−det⁡A\lambda_{1,2} = m \pm \sqrt{m^2 - \det A},其中 m=12tr⁡Am = \tfrac12 \operatorname{tr} A,并按 λ1≥λ2\lambda_1 \ge \lambda_2 排序;特征向量列未归一化。
  • 对其他规模,矩阵先通过 Householder 反射约化为三对角形式,再用带 Wilkinson 位移的隐式 QL 算法对角化。特征向量列在舍入误差范围内是标准正交的。特征值不排序。
  • 开销 O(n3)O(n^3)。

Matrix::power_method

Matrix::power_method(a, max_iterations) 通过幂迭代逼近主特征对 (λ,x)(\lambda, x),一旦 ∥Ax−λx∥∞≤tol\lVert A x - \lambda x \rVert_\infty \le \mathrm{tol} 即返回 Some((λ, x))。

pub fn[T : Compare + @luna-generic.Field + @luna-generic.Num + Tolerance] Matrix::power_method(Self[T], Int) -> (T, Vector[T])?
  • xx 被缩放使得 ∥x∥∞=1\lVert x \rVert_\infty = 1;λ\lambda 是 Rayleigh 商 xTAx/xTxx^{\mathsf T} A x / x^{\mathsf T} x。
  • 若迭代在 max_iterations 步内未通过残差检验,或迭代向量在数值上变为零(例如对幂零矩阵),则返回 None。两个模相等、符号相反的主特征值(例如 ±1\pm 1)会阻碍收敛。
  • 对非方阵或空矩阵中止。
  • 每次迭代的开销为一次矩阵-向量乘积,即 O(n2)O(n^2)。
///|
test "eigenvalues" {
  let a = @mutable.Matrix::from_2d_array([[2.0, 1.0], [1.0, 2.0]])
  let (values, vectors) = a.eigen()
  inspect(values, content="|3, 1|")
  inspect(vectors, content="|1, 1|\n|1, -1|")
  let b = @mutable.Matrix::from_2d_array([[2.0, 1.0], [1.0, 3.0]])
  let (lambda, x) = b.power_method(200).unwrap()
  inspect((lambda - 3.618033988749895).abs() < 1.0e-9, content="true")
  inspect(x[1], content="1")
  let flip = @mutable.Matrix::from_2d_array([[1.0, 0.0], [0.0, -1.0]])
  inspect(flip.power_method(100) is None, content="true")
}

统计量与范数

统计函数把矩阵视为其 N=rcN = rc 个元素组成的扁平列表。

Matrix::mean, Matrix::unchecked_mean

mean() 返回 Ok(\bar a),其中 aˉ=1N∑aij\bar a = \tfrac1N \sum a_{ij};当 N=0N = 0 时返回 EmptyMatrix;unchecked_mean 则改为中止。

pub fn[T : @luna-generic.Field] Matrix::mean(Self[T]) -> Result[T, @error.LinearAlgebraError]
pub fn[T : @luna-generic.Field] Matrix::unchecked_mean(Self[T]) -> T

Matrix::variance, Matrix::unchecked_variance

variance() 返回总体方差 1N∑(aij−aˉ)2\tfrac1N \sum (a_{ij} - \bar a)^2(两遍算法),或返回 EmptyMatrix。

pub fn[T : @luna-generic.Field] Matrix::variance(Self[T]) -> Result[T, @error.LinearAlgebraError]
pub fn[T : @luna-generic.Field] Matrix::unchecked_variance(Self[T]) -> T

Matrix::std_dev, Matrix::unchecked_std_dev

std_dev() 返回总体方差的平方根,或返回 EmptyMatrix。

pub fn[T : @luna-generic.Field + @arithmetic.Sqrt] Matrix::std_dev(Self[T]) -> Result[T, @error.LinearAlgebraError]
pub fn[T : @luna-generic.Field + @arithmetic.Sqrt] Matrix::unchecked_std_dev(Self[T]) -> T

Matrix::max_element, Matrix::min_element

按 Compare 取最大或最小元素,或返回 EmptyMatrix。

pub fn[T : Compare] Matrix::max_element(Self[T]) -> Result[T, @error.LinearAlgebraError]
pub fn[T : Compare] Matrix::min_element(Self[T]) -> Result[T, @error.LinearAlgebraError]

若含有 NaN 元素,结果取决于它们的位置;请先将其过滤。

Matrix::unchecked_max_element, Matrix::unchecked_min_element

max_element 与 min_element 的中止形式。

pub fn[T : Compare] Matrix::unchecked_max_element(Self[T]) -> T
pub fn[T : Compare] Matrix::unchecked_min_element(Self[T]) -> T

Matrix::frobenius_norm

Matrix::frobenius_norm(a) 返回 ∥A∥F=∑aij2\lVert A \rVert_F = \sqrt{\sum a_{ij}^2}。

pub fn[T : @luna-generic.AddMonoid + Mul + @arithmetic.Sqrt] Matrix::frobenius_norm(Self[T]) -> T

平方和不做缩放,因此对 Double 而言,大于约 1015410^{154} 的元素会溢出。空矩阵的范数为 00。

///|
test "statistics" {
  let m = @mutable.Matrix::from_2d_array([[1.0, 2.0], [3.0, 4.0]])
  inspect(m.mean().unwrap(), content="2.5")
  inspect(m.variance().unwrap(), content="1.25")
  inspect(m.max_element().unwrap(), content="4")
  inspect(
    @mutable.Matrix::from_2d_array([[3.0, 4.0]]).frobenius_norm(),
    content="5",
  )
}

视图

RowView::get, RowView::set, ColView::get, ColView::set

读取或写入所视行或列的第 i 个位置;它们支撑 view[i] 与 view[i] = x。

#alias("_[_]")
pub fn[T] RowView::get(Self[T], Int) -> T
#alias("_[_]=_")
pub fn[T] RowView::set(Self[T], Int, T) -> Unit
#alias("_[_]")
pub fn[T] ColView::get(Self[T], Int) -> T
#alias("_[_]=_")
pub fn[T] ColView::set(Self[T], Int, T) -> Unit

RowView::length, ColView::length

矩阵的列数(行视图)或行数(列视图)。

pub fn[T] RowView::length(Self[T]) -> Int
pub fn[T] ColView::length(Self[T]) -> Int

RowView::each, RowView::eachi, RowView::iter, ColView::each, ColView::eachi, ColView::iter

按顺序遍历视图中的元素。

pub fn[T] RowView::each(Self[T], (T) -> Unit) -> Unit
pub fn[T] RowView::eachi(Self[T], (Int, T) -> Unit) -> Unit
pub fn[T] RowView::iter(Self[T]) -> Iter[T]
pub fn[T] ColView::each(Self[T], (T) -> Unit) -> Unit
pub fn[T] ColView::eachi(Self[T], (Int, T) -> Unit) -> Unit
pub fn[T] ColView::iter(Self[T]) -> Iter[T]

RowView::map_inplace, ColView::map_inplace

在底层矩阵中把视图中的每个元素替换为 f(entry)。

pub fn[T] RowView::map_inplace(Self[T], (T) -> T) -> Unit
pub fn[T] ColView::map_inplace(Self[T], (T) -> T) -> Unit

RowView::to_array, RowView::to_vector, ColView::to_array, ColView::to_vector

把视图中的元素复制出来。

pub fn[T] RowView::to_array(Self[T]) -> Array[T]
pub fn[T] RowView::to_vector(Self[T]) -> Vector[T]
pub fn[T] ColView::to_array(Self[T]) -> Array[T]
pub fn[T] ColView::to_vector(Self[T]) -> Vector[T]

RowView::to_string, ColView::to_string

把视图中的元素渲染为 |a, b, c|。

pub fn[T : Show] RowView::to_string(Self[T]) -> String
pub fn[T : Show] ColView::to_string(Self[T]) -> String

转置视图

除非文档说明返回新值,Transpose 的每个方法都寻址转置后的矩阵,并作用于共享存储。

Transpose::row, Transpose::col

视图的形状:row() 是被包装矩阵的列数,col() 是其行数。

pub fn[T] Transpose::row(Self[T]) -> Int
pub fn[T] Transpose::col(Self[T]) -> Int

Transpose::get, Transpose::set, Transpose::at

get(i, j) 与 set(i, j, x) 访问视图的元素 (i,j)(i, j),即矩阵的元素 (j,i)(j, i);at 支撑 t[i][j] 与 t[i][j] = x。

pub fn[T] Transpose::get(Self[T], Int, Int) -> T
pub fn[T] Transpose::set(Self[T], Int, Int, T) -> Unit
#alias("_[_]")
pub fn[T] Transpose::at(Self[T], Int) -> Lens[T]

Transpose::transpose

Transpose::transpose(t) 返回被包装的矩阵本身,而不是副本。

pub fn[T] Transpose::transpose(Self[T]) -> Matrix[T]

Transpose::materialize

Transpose::materialize(t) 把视图复制到一个具有转置形状的新矩阵中。

pub fn[T] Transpose::materialize(Self[T]) -> Matrix[T]

Transpose::copy

Transpose::copy(t) 返回被包装矩阵深拷贝的视图。

pub fn[T] Transpose::copy(Self[T]) -> Self[T]

遍历:Transpose::each、Transpose::eachi、Transpose::each_row_col、Transpose::each_row、Transpose::eachi_row、Transpose::each_col、Transpose::eachi_col

遍历视图。

pub fn[T] Transpose::each(Self[T], (T) -> Unit) -> Unit
pub fn[T] Transpose::eachi(Self[T], (Int, T) -> Unit) -> Unit
pub fn[T] Transpose::each_row_col(Self[T], (Int, Int, T) -> Unit) -> Unit
pub fn[T] Transpose::each_row(Self[T], Int, (T) -> Unit) -> Unit
pub fn[T] Transpose::eachi_row(Self[T], Int, (Int, T) -> Unit) -> Unit
pub fn[T] Transpose::each_col(Self[T], Int, (T) -> Unit) -> Unit
pub fn[T] Transpose::eachi_col(Self[T], Int, (Int, T) -> Unit) -> Unit

each、eachi 和 each_row_col 按被包装矩阵的存储顺序访问元素,对视图而言这是列主序;eachi 传入的是视图的行主序索引,each_row_col 传入视图坐标。行和列形式按顺序访问视图的一行或一列。

Transpose::row_to_array, Transpose::col_to_array, Transpose::row_to_vector, Transpose::col_to_vector

复制视图的一行或一列。

pub fn[T] Transpose::row_to_array(Self[T], Int) -> Array[T]
pub fn[T] Transpose::col_to_array(Self[T], Int) -> Array[T]
pub fn[T] Transpose::row_to_vector(Self[T], Int) -> Vector[T]
pub fn[T] Transpose::col_to_vector(Self[T], Int) -> Vector[T]

Transpose::map, Transpose::map_inplace, Transpose::map_row_inplace, Transpose::map_col_inplace

map 返回一个新矩阵的新视图;*_inplace 形式修改共享存储。

pub fn[T] Transpose::map(Self[T], (T) -> T) -> Self[T]
#alias(map_in_place, deprecated)
pub fn[T] Transpose::map_inplace(Self[T], (T) -> T) -> Unit
#alias(map_row_in_place, deprecated)
pub fn[T] Transpose::map_row_inplace(Self[T], Int, (T) -> T) -> Unit
#alias(map_col_in_place, deprecated)
pub fn[T] Transpose::map_col_inplace(Self[T], Int, (T) -> T) -> Unit

Transpose::swap_rows, Transpose::swap_cols

原地交换视图的两行或两列(即被包装矩阵的两列或两行)。

pub fn[T] Transpose::swap_rows(Self[T], Int, Int) -> Unit
pub fn[T] Transpose::swap_cols(Self[T], Int, Int) -> Unit

Transpose::horizontal_combine, Transpose::vertical_combine

视图的分块拼接,返回一个新矩阵的视图。

pub fn[T] Transpose::horizontal_combine(Self[T], Self[T]) -> Self[T]
pub fn[T] Transpose::vertical_combine(Self[T], Self[T]) -> Self[T]

Transpose::add, Transpose::sub, Transpose::neg, Transpose::scale, Transpose::add_constant

逐元素算术,返回一个新矩阵的视图。

pub fn[T : Add] Transpose::add(Self[T], Self[T]) -> Self[T]
pub fn[T : Add + Neg] Transpose::sub(Self[T], Self[T]) -> Self[T]
pub fn[T : Neg] Transpose::neg(Self[T]) -> Self[T]
pub fn[T : Mul] Transpose::scale(Self[T], T) -> Self[T]
pub fn[T : Add] Transpose::add_constant(Self[T], T) -> Self[T]

Transpose::mul

Transpose::mul(s, t) 返回两个视图的乘积,按 ATBT=(BA)TA^{\mathsf T} B^{\mathsf T} = (BA)^{\mathsf T} 计算,无需移动数据。

pub fn[T : @luna-generic.AddMonoid + Mul] Transpose::mul(Self[T], Self[T]) -> Self[T]

Transpose::equal, Transpose::to_string

equal 比较被包装的矩阵;to_string 逐行渲染视图。

pub fn[T : Eq] Transpose::equal(Self[T], Self[T]) -> Bool
pub fn[T : Show] Transpose::to_string(Self[T]) -> String
///|
test "transpose view" {
  let m = @mutable.Matrix::from_2d_array([[1, 2, 3], [4, 5, 6]])
  let t = m.to_transpose()
  inspect(t, content="|1, 4|\n|2, 5|\n|3, 6|")
  t[2][0] = 30
  inspect(m.get(0, 2), content="30")
  let s = @mutable.Matrix::from_2d_array([[1, 0], [0, 1], [1, 1]]).to_transpose()
  let product = t * s
  debug_inspect((product.row(), product.col()), content="(3, 3)")
  inspect(t.materialize().row(), content="3")
  let order = []
  t.each(x => order.push(x))
  debug_inspect(order, content="[1, 2, 30, 4, 5, 6]")
}

向量

Vector::from_array

Vector::from_array(xs) 直接将 xs 作为向量的存储,不做复制。

pub fn[A] Vector::from_array(Array[A]) -> Self[A]

Vector::make, Vector::makei

某个值的 nn 份拷贝,或 (f(0),…,f(n−1))(f(0), \dots, f(n-1))。

pub fn[A] Vector::make(Int, A) -> Self[A]
pub fn[A] Vector::makei(Int, (Int) -> A) -> Self[A]

Vector::length, Vector::copy, Vector::iter

长度、深拷贝与迭代器。

pub fn[A] Vector::length(Self[A]) -> Int
pub fn[A] Vector::copy(Self[A]) -> Self[A]
pub fn[T] Vector::iter(Self[T]) -> Iter[T]

Vector::at, Vector::set

原地读取或写入第 i 个元素;它们支撑 v[i] 与 v[i] = x。索引越界时中止。

#alias("_[_]")
pub fn[A] Vector::at(Self[A], Int) -> A
#alias("_[_]=_")
pub fn[A] Vector::set(Self[A], Int, A) -> Unit

Vector::map, Vector::zip_with, Vector::map_inplace

map 与 zip_with 返回新向量(zip_with 在长度不同时中止);map_inplace 改写每个元素。

pub fn[A, B] Vector::map(Self[A], (A) -> B) -> Self[B]
pub fn[A, U, V] Vector::zip_with(Self[A], Self[U], (A, U) -> V) -> Self[V]
#alias(map_in_place, deprecated)
pub fn[A] Vector::map_inplace(Self[A], (A) -> A) -> Unit

Vector::add, Vector::mul, Vector::neg, Vector::add_constant

逐元素的 u+vu + v、Hadamard 积 u⊙vu \odot v、−u-u 以及 u+au + a。长度不同时中止。没有 Sub;请写作 u + -v。

pub fn[T : Add] Vector::add(Self[T], Self[T]) -> Self[T]
pub fn[T : Mul] Vector::mul(Self[T], Self[T]) -> Self[T]
pub fn[T : Neg] Vector::neg(Self[T]) -> Self[T]
pub fn[T : Add] Vector::add_constant(Self[T], T) -> Self[T]

Vector::left_scale, Vector::right_scale, Vector::left_scale_inplace, Vector::right_scale_inplace

(avi)(a v_i) 与 (via)(v_i a),可得到新向量,也可原地进行。

pub fn[A : Mul] Vector::left_scale(Self[A], A) -> Self[A]
pub fn[A : Mul] Vector::right_scale(Self[A], A) -> Self[A]
#alias(left_scale_in_place, deprecated)
pub fn[A : Mul] Vector::left_scale_inplace(Self[A], A) -> Unit
#alias(right_scale_in_place, deprecated)
pub fn[A : Mul] Vector::right_scale_inplace(Self[A], A) -> Unit

Vector::dot

Vector::dot(u, v) 返回 ∑iuivi\sum_i u_i v_i,从左到右求和;长度不同时中止。

pub fn[T : @luna-generic.AddMonoid + Mul] Vector::dot(Self[T], Self[T]) -> T

Vector::lerp

Vector::lerp(u, v, t) 返回 (1−t)u+tv(1 - t) u + t v。

pub fn[T : @luna-generic.MulMonoid + Add + Neg] Vector::lerp(Self[T], Self[T], T) -> Self[T]

Vector::lin_comb

Vector::lin_comb(weights, vectors) 一遍计算出 ∑kwkvk\sum_k w_k v_k。

pub fn[T : Mul + Add + @luna-generic.Zero] Vector::lin_comb(Array[T], Array[Self[T]]) -> Self[T]

输入为空、权重与向量个数不同,或向量长度不同时中止。

lin_comb

lin_comb(a, u, b, v) 返回 au+bva u + b v;它是顶层函数。

pub fn[T : Add + Mul] lin_comb(T, Vector[T], T, Vector[T]) -> Vector[T]

Vector::to_row_matrix, Vector::to_col_matrix, Vector::scaled_matrix, Vector::tensor_product

把向量作为 1×n1 \times n 或 n×1n \times 1 矩阵(复制)、对角矩阵 diag⁡(v)\operatorname{diag}(v),以及外积 uvTu v^{\mathsf T}。

pub fn[T] Vector::to_row_matrix(Self[T]) -> Matrix[T]
pub fn[T] Vector::to_col_matrix(Self[T]) -> Matrix[T]
pub fn[T : @luna-generic.Zero] Vector::scaled_matrix(Self[T]) -> Matrix[T]
pub fn[T : Mul] Vector::tensor_product(Self[T], Self[T]) -> Matrix[T]

Vector::equal, Vector::to_string

equal 比较元素(支撑 ==);to_string 渲染为 |a, b, c|。

pub fn[T : Eq] Vector::equal(Self[T], Self[T]) -> Bool
pub fn[T : Show] Vector::to_string(Self[T]) -> String
///|
test "mutable vectors" {
  let v = @mutable.Vector::from_array([1, 2, 3])
  v[0] = 10
  v.left_scale_inplace(2)
  inspect(v, content="|20, 4, 6|")
  inspect(v.dot(@mutable.Vector::make(3, 1)), content="30")
  let w = @mutable.Vector::lin_comb([1, 2], [
    v,
    @mutable.Vector::makei(3, i => i),
  ])
  inspect(w, content="|20, 6, 10|")
  inspect(@mutable.lin_comb(1, v, -1, w), content="|0, -2, -4|")
}

已弃用

项替代方案
Matrix::map_in_place、map_row_in_place、map_col_in_place(别名)map_inplace, map_row_inplace, map_col_inplace
Transpose::map_in_place、map_row_in_place、map_col_in_place(别名)*_inplace 系列名称
Vector::map_in_place、left_scale_in_place、right_scale_in_place(别名)map_inplace, left_scale_inplace, right_scale_inplace
Matrix、Transpose、Vector 上的 not_equal 方法形式(隐藏)!=
Matrix、Transpose、RowView、ColView、Vector 上的 output 方法形式(隐藏)字符串插值或 Show::output(x, logger)
Vector::to_repr(隐藏)Repr(v) 或 @debug.Debug::to_repr(v)
Vector::arbitrary(隐藏)@quickcheck.Arbitrary::arbitrary