强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

Julia 教程 / Julia 线性代数完全指南

Julia 线性代数完全指南

线性代数是科学计算的基石。Julia 内置了强大的线性代数支持,底层直接调用 BLAS/LAPACK,性能媲美 C/Fortran。


1. LinearAlgebra 模块

using LinearAlgebra

# 单位矩阵
I(3)          # 3×3 单位矩阵
Matrix{Float64}(I, 3, 3)

# 零矩阵与对角矩阵
zeros(3, 3)
Diagonal([1.0, 2.0, 3.0])

# 随机矩阵
A = rand(4, 4)
函数说明
I(n)n×n 单位矩阵
Diagonal(v)以向量 v 为对角的对角矩阵
Tridiagonal(dl, d, du)三对角矩阵
Symmetric(A)对称矩阵视图
Hermitian(A)Hermite 矩阵视图
UpperTriangular(A)上三角视图
LowerTriangular(A)下三角视图

2. 矩阵乘法与基本运算

A = rand(3, 4)
B = rand(4, 5)

# 矩阵乘法
C = A * B           # 3×5 矩阵

# 逐元素运算
A .+ 1.0            # 每个元素加 1
A .* A              # 逐元素乘
A .^ 2              # 逐元素平方

# 向量内积与外积
x = rand(3)
y = rand(3)
dot(x, y)           # 内积(等价于 x' * y)
x * y'              # 外积,3×3 矩阵

⚠️ 注意: Julia 中 * 运算符对矩阵执行的是线性代数中的矩阵乘法,而非逐元素乘法。逐元素乘法需要使用 .*


3. 转置与共轭转置

A = rand(ComplexF64, 3, 3)

# 转置(不取共轭)
transpose(A)     # Aᵀ

# 共轭转置(Hermite 转置)
adjoint(A)       # Aᴴ = conj(Aᵀ)
A'               # 简写,等价于 adjoint(A)

# 实数矩阵两者等价
B = rand(3, 3)
transpose(B) == adjoint(B)   # true
操作函数符号
转置transpose(A)permutedims(A)
共轭转置adjoint(A)A'
共轭conj(A)

💡 提示: adjointtranspose 返回的是惰性视图,不会立即复制数据。只有在参与运算时才真正计算,这对性能非常重要。


4. 矩阵分解

4.1 LU 分解

A = rand(5, 5)
F = lu(A)

# 获取 L 和 U
F.L     # 下三角
F.U     # 上三角
F.P     # 置换矩阵

# 用 LU 分解解方程
b = rand(5)
x = F \ b     # 等价于 A \ b

4.2 QR 分解

A = rand(5, 3)
F = qr(A)

F.Q     # 正交矩阵
F.R     # 上三角矩阵

# QR 分解常用于最小二乘
b = rand(5)
x = F \ b     # 最小二乘解

4.3 SVD 分解(奇异值分解)

A = rand(5, 3)
F = svd(A)

F.U     # 左奇异向量
F.S     # 奇异值(向量)
F.V     # 右奇异向量
F.Vt    # 右奇异向量的转置

# 低秩近似
k = 2
A_approx = F.U[:, 1:k] * Diagonal(F.S[1:k]) * F.Vt[1:k, :]

4.4 Cholesky 分解

# 适用于正定矩阵
A = rand(3, 3)
A = A * A' + I    # 确保正定
F = cholesky(A)

F.L     # 下三角,A = L * Lᵀ
F.U     # 上三角

4.5 特征值分解

A = rand(5, 5)
A = A + A'    # 对称化

# 特征值与特征向量
F = eigen(A)
F.values     # 特征值
F.vectors    # 特征向量(按列排列)

# 只求部分特征值
eigs = eigen(A, 1:3)   # 前 3 个
分解函数适用场景
LUlu(A)解线性方程组
QRqr(A)最小二乘、正交化
SVDsvd(A)低秩近似、PCA
Choleskycholesky(A)正定矩阵、协方差矩阵
Schurschur(A)特征值计算、稳定性分析
Eigeneigen(A)特征值问题
Hessenberghessenberg(A)特征值的中间步骤

5. 解线性方程组

# 最基本的方式:A \ b
A = rand(5, 5)
b = rand(5)
x = A \ b     # 自动选择最优分解

# 验证
norm(A * x - b)    # 应接近机器精度 ≈ 1e-16

# 多右端项
B = rand(5, 3)
X = A \ B     # 同时解 3 个方程组

# 带特殊结构的矩阵(Julia 自动利用结构)
Symmetric(A) \ b       # 对称矩阵
Hermitian(A) \ b       # Hermite 矩阵
UpperTriangular(A) \ b # 上三角

⚠️ 注意: A \ b 会根据 A 的类型自动选择最优算法。对稀疏矩阵使用稀疏求解器,对带状矩阵使用带状求解器,无需手动指定。


6. 稀疏矩阵(SparseArrays)

using SparseArrays

# 创建稀疏矩阵
# 方法1:从坐标列表创建
I = [1, 2, 3, 3]
J = [2, 1, 3, 1]
V = [1.0, 2.0, 3.0, 4.0]
S = sparse(I, J, V, 3, 3)

# 方法2:从稠密矩阵转换
A = rand(1000, 1000)
A[abs.(A) .< 0.9] .= 0    # 设置大部分元素为 0
S = sparse(A)

# 方法3:使用 spzeros 构建
S = spzeros(100, 100)
S[1, 5] = 1.0
S[50, 50] = 3.14

# 稀疏矩阵操作
nnz(S)             # 非零元素数量
dropzeros(S)       # 去除存储的零元素
sparse(I(100))     # 稀疏单位矩阵

# 稀疏线性方程组
S = sprand(1000, 1000, 0.01) + 10I    # 1% 非零率
b = rand(1000)
x = S \ b    # 使用 UMFPACK 稀疏求解器
操作稠密矩阵稀疏矩阵
存储 (1000×1000, 1% 非零)8 MB≈ 0.1 MB
矩阵-向量乘O(n²)O(nnz)
方程组求解O(n³)远低于 O(n³)

💡 提示: 当矩阵非零元素比例低于约 30% 时,稀疏矩阵在存储和计算上都有优势。


7. BLAS/LAPACK 底层调用

using LinearAlgebra.BLAS

# Julia 默认使用 OpenBLAS 或 MKL
# 查看当前 BLAS 后端
BLAS.get_config()

# 直接调用 BLAS 例程
n = 1000
A = rand(n, n)
B = rand(n, n)
C = zeros(n, n)

# DGEMM: C = α*A*B + β*C
BLAS.gemm!('N', 'N', 1.0, A, B, 0.0, C)

# 设置 BLAS 线程数
BLAS.set_num_threads(4)
# 查看 LAPACK 版本
using LinearAlgebra.LAPACK
# 通常通过 Julia 内部自动调用
# 手动调用 LAPACK 例程(高级用法)
A = rand(5, 5)
b = rand(5)
# 等价于 A \ b,但手动控制
A_copy = copy(A)
LU, ipiv, info = LAPACK.getrf!(A_copy)   # LU 分解
x = LAPACK.getrs!('N', LU, ipiv, copy(b)) # 解方程

⚠️ 注意: 一般情况下不需要直接调用 BLAS/LAPACK,Julia 的高级接口已经自动利用底层库。仅在需要极致性能调优时才考虑直接调用。


8. 矩阵函数

A = rand(4, 4)
A = A + A'    # 对称化

# 矩阵指数
exp(A)         # eᴬ

# 矩阵平方根
sqrt(A)        # A^(1/2)

# 矩阵对数
log(A)         # ln(A)

# 矩阵幂
A^3            # A * A * A

# 条件数
cond(A)        # 条件数,衡量矩阵"病态"程度

# 秩
rank(A)        # 矩阵的秩

# 行列式
det(A)         # 行列式

# 迹
tr(A)          # 主对角线元素之和
函数说明数学含义
exp(A)矩阵指数e^A = Σ Aⁿ/n!
log(A)矩阵对数exp 的逆运算
sqrt(A)矩阵平方根B² = A
sin(A)矩阵正弦泰勒展开
det(A)行列式体积缩放因子
tr(A)对角线和
rank(A)线性无关行列数
cond(A)条件数‖A‖·‖A⁻¹‖

9. 性能注意事项

# ❌ 避免:循环中按列访问(Julia 是列主序)
A = rand(1000, 1000)
function sum_rows_bad(A)
    s = 0.0
    for i in 1:size(A, 1)
        for j in 1:size(A, 2)
            s += A[i, j]    # 按行遍历,缓存不友好
        end
    end
    return s
end

# ✅ 推荐:按列遍历
function sum_cols_good(A)
    s = 0.0
    for j in 1:size(A, 2)
        for i in 1:size(A, 1)
            s += A[i, j]    # 按列遍历,缓存友好
        end
    end
    return s
end

# ✅ 最佳:使用内置函数
sum(A)
# 预分配输出避免重复分配
function mul_add_bad!(A, B, n)
    for _ in 1:n
        C = A * B      # 每次都分配新矩阵
        # 使用 C...
    end
end

function mul_add_good!(C, A, B, n)
    for _ in 1:n
        mul!(C, A, B)   # 写入预分配的 C,零分配
        # 使用 C...
    end
end

💡 提示: 使用 @btime(来自 BenchmarkTools.jl)来精确测量性能:

using BenchmarkTools
@btime $A * $b
@btime mul!($C, $A, $b)

10. 实际应用

10.1 最小二乘拟合

# 用线性回归拟合 y = ax + b
using LinearAlgebra

# 生成数据
x_data = collect(1.0:10.0)
y_data = 2.5 .* x_data .+ 1.3 .+ randn(10) .* 0.5

# 构建设计矩阵 [x, 1]
X = hcat(x_data, ones(10))

# 最小二乘解:β = (XᵀX)⁻¹ Xᵀy = X \ y
β = X \ y_data
println("斜率: $(β[1]), 截距: $(β[2])")

# 预测
y_pred = X * β
residuals = y_data - y_pred
mse = sum(residuals .^ 2) / length(y_data)

10.2 主成分分析(PCA)

using LinearAlgebra

# 数据矩阵(每行一个样本)
X = rand(100, 5)    # 100 个样本,5 个特征

# 中心化
X_centered = X .- mean(X, dims=1)

# 协方差矩阵
C = X_centered' * X_centered / (size(X, 1) - 1)

# 特征值分解
F = eigen(Symmetric(C))
# 按特征值从大到小排序
idx = sortperm(F.values, rev=true)
eigenvalues = F.values[idx]
eigenvectors = F.vectors[:, idx]

# 前 2 个主成分
k = 2
W = eigenvectors[:, 1:k]
X_pca = X_centered * W

# 方差解释比
explained_ratio = eigenvalues ./ sum(eigenvalues)
println("前 $k 个主成分解释了 $(sum(explained_ratio[1:k])*100)% 的方差")

10.3 协方差矩阵与多元正态

using LinearAlgebra

# 协方差矩阵必须是对称正定的
Σ = [4.0 2.0 0.5;
     2.0 3.0 1.0;
     0.5 1.0 2.0]

# 验证正定
isposdef(Σ)    # true

# Cholesky 分解用于生成多元正态样本
L = cholesky(Σ).L
samples = L * randn(3, 1000)    # 1000 个样本

11. 常见陷阱与排错

错误原因解决方案
SingularException矩阵不可逆检查矩阵是否奇异,使用伪逆 pinv
PosDefExceptionCholesky 要求正定确保矩阵对称正定,加小扰动 A + 1e-10I
内存溢出稠密矩阵太大使用 sparse 稀疏存储
结果不精确病态矩阵检查 cond(A),考虑正则化
# 病态矩阵示例
A = [1.0 1.0; 1.0 1.0000001]
cond(A)    # 非常大的条件数
b = [2.0, 2.0000001]
x = A \ b  # 结果可能不准确

# 使用伪逆
x_pinv = pinv(A) * b

扩展阅读