在 Julia 中断言对角化向量时,是什么导致“AssertionError”?

What causes `AssertionError` when asserting a diagonalized vector in Julia?

我一直在做一些 exercises in julia,我目前正在尝试 @assert 一个向量,该向量已经对角化为一个矩阵,与练习笔记本中给出的“解矩阵”相对应。但是,在根据提供的解决方案断言我的代码时,我得到了 AssertionError。我的代码示例:

julia> using LinearAlgebra

julia> A =
[
 140   97   74  168  131
  97  106   89  131   36
  74   89  152  144   71
 168  131  144   54  142
 131   36   71  142   36
]

5×5 Matrix{Int64}:
 140   97   74  168  131
  97  106   89  131   36
  74   89  152  144   71
 168  131  144   54  142
 131   36   71  142   36

julia> A_eigv = eigen(A).values

5-element Vector{Float64}:
 -128.49322764802145
  -55.887784553057
   42.752167279318854
   87.16111477514494
  542.4677301466137

julia> A_diag = Diagonal(A_eigv)

5×5 Diagonal{Float64, Vector{Float64}}:
 -128.493     ⋅        ⋅        ⋅         ⋅ 
     ⋅     -55.8878    ⋅        ⋅         ⋅ 
     ⋅        ⋅      42.7522    ⋅         ⋅ 
     ⋅        ⋅        ⋅      87.1611     ⋅ 
     ⋅        ⋅        ⋅        ⋅      542.468

julia> @assert A_diag ==  [-128.493    0.0      0.0      0.0       0.0;
    0.0    -55.8878   0.0      0.0       0.0;
    0.0      0.0     42.7522   0.0       0.0;
    0.0      0.0      0.0     87.1611    0.0;
    0.0 0.0      0.0      0.0     542.468]

AssertionError: A_diag == [-128.493 0.0 0.0 0.0 0.0; 0.0 -55.8878 0.0 0.0 0.0; 0.0 0.0 42.7522 0.0 0.0; 0.0 0.0 0.0 87.1611 0.0; 0.0 0.0 0.0 0.0 542.468]

Stacktrace:
 [1] top-level scope
   @ In[90]:1
 [2] eval
   @ ./boot.jl:360 [inlined]
 [3] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String)
   @ Base ./loading.jl:1094

我最初的假设是小数位数的差异是错误的原因。因此,我将 == 替换为 (\approx)。但是,如下面的代码示例所示,错误仍然存​​在:

julia> @assert A_diag ≈ #\approx
[-128.493    0.0      0.0      0.0       0.0;
    0.0    -55.8878   0.0      0.0       0.0;
    0.0      0.0     42.7522   0.0       0.0;
    0.0      0.0      0.0     87.1611    0.0;
    0.0 0.0      0.0      0.0     542.468]

AssertionError: A_diag ≈ [-128.493 0.0 0.0 0.0 0.0; 0.0 -55.8878 0.0 0.0 0.0; 0.0 0.0 42.7522 0.0 0.0; 0.0 0.0 0.0 87.1611 0.0; 0.0 0.0 0.0 0.0 542.468]

Stacktrace:
 [1] top-level scope
   @ In[97]:1
 [2] eval
   @ ./boot.jl:360 [inlined]
 [3] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String)
   @ Base ./loading.jl:1094

我已经多次通读我的代码了,我不知所措。我的对角矩阵 (A_diag) 中的值似乎与解矩阵相同。此外,将语句设置为近似等于 (\approx) 会呈现相同的错误,因此我假设我可以算出小数错误。

我的主要问题是:是什么导致了 AssertionError

不,为了测试相等性,这些点被视为 0。

julia> Diagonal(1:2) == [1 0; 0 2]
true

你的问题是你的数组实际上相等; -128.49322764802145-128.493 不同。 (数组的漂亮打印版本截断了浮点数以供显示,但这不是真正的基础值!)。

[编辑:]

使用 (\approx) 在这种情况下也会失败。 isapprox()

的文档中解释了这样做的原因

The binary operator is equivalent to isapprox with the default arguments,

if an atol > 0 is not specified, rtol defaults to the square root of eps of the type of x or y, whichever is bigger (least precise).

本质上,这意味着 将测试近似相等,相对容差 √eps() 大约等于 1.5e-8,或 0.0000015%。这个容忍度太低了,增加容忍度会解决这个问题。例如:

# Option 1: Absolute tolerance. Set to a reasonable max deviation:
julia> isapprox(A_diag, sol_mat, atol = 1e-3)
true

# Option 2: Relative tolerance. Setting rtol = 1e-n, n is the number of significant digits in either matrices will work in most cases.
julia> isapprox(A_diag, sol_mat, rtol = 1e-6)
true

由于解矩阵提供了六位有效数字的值,另一种替代方法是将 A_diag 中的值四舍五入到这个数字 og 数字并测试是否相等。例如:

julia> round.(A_diag, RoundNearestTiesUp, sigdigits=6) == 
[-128.493    0.0      0.0      0.0       0.0;
    0.0    -55.8878   0.0      0.0       0.0;
    0.0      0.0     42.7522   0.0       0.0;
    0.0      0.0      0.0     87.1611    0.0;
    0.0      0.0      0.0      0.0     542.468]
true