|
| 1 | +using NonlinearSolveBase |
| 2 | +using NonlinearSolveBase: dampen_jacobian!! |
| 3 | +using ArrayInterface |
| 4 | +using LinearAlgebra |
| 5 | +using StaticArrays |
| 6 | +using Test |
| 7 | + |
| 8 | +# `dampen_jacobian!!` has a mutable path (`can_setindex(J_cache)`, damping written in place) and |
| 9 | +# an out-of-place fallback for Jacobians that cannot `setindex!` — `SMatrix`, and GPU sparse |
| 10 | +# matrices, which are mutable only through `nonzeros`. The two must agree: damping is defined by |
| 11 | +# the math, not by how the Jacobian happens to be stored. The scalar-`D` fallback used to read |
| 12 | +# `J .+ D`, which adds `D` to *every* entry rather than only the diagonal, so an `SMatrix` |
| 13 | +# Jacobian was silently damped wrong (a convergence bug, not a wrong root: damping does not move |
| 14 | +# the fixed point). |
| 15 | + |
| 16 | +J = [1.0 2.0; 3.0 4.0] |
| 17 | +Jstatic = SMatrix{2, 2}(J) |
| 18 | + |
| 19 | +@testset "scalar damping touches only the diagonal" begin |
| 20 | + D = 10.0 |
| 21 | + expected = J + D * I # [11 2; 3 14] |
| 22 | + |
| 23 | + @test dampen_jacobian!!(copy(J), J, D) == expected |
| 24 | + @test !ArrayInterface.can_setindex(Jstatic) # ensure we exercise the fallback |
| 25 | + @test Array(dampen_jacobian!!(Jstatic, Jstatic, D)) == expected |
| 26 | + |
| 27 | + # The off-diagonal entries must survive untouched. |
| 28 | + damped = dampen_jacobian!!(Jstatic, Jstatic, D) |
| 29 | + @test damped[1, 2] == J[1, 2] |
| 30 | + @test damped[2, 1] == J[2, 1] |
| 31 | +end |
| 32 | + |
| 33 | +@testset "diagonal damping touches only the diagonal" begin |
| 34 | + D = Diagonal([10.0, 20.0]) |
| 35 | + expected = J + D |
| 36 | + |
| 37 | + @test dampen_jacobian!!(copy(J), J, D) == expected |
| 38 | + @test Array(dampen_jacobian!!(Jstatic, Jstatic, D)) == expected |
| 39 | +end |
| 40 | + |
| 41 | +@testset "matrix damping adds the full matrix" begin |
| 42 | + D = [10.0 100.0; 200.0 20.0] |
| 43 | + expected = J + D |
| 44 | + |
| 45 | + @test dampen_jacobian!!(copy(J), J, D) == expected |
| 46 | + @test Array(dampen_jacobian!!(Jstatic, Jstatic, D)) == expected |
| 47 | +end |
| 48 | + |
| 49 | +@testset "mutable and immutable paths agree" begin |
| 50 | + # The invariant behind all of the above, stated directly. |
| 51 | + for D in (10.0, Diagonal([10.0, 20.0]), [10.0 100.0; 200.0 20.0]) |
| 52 | + @test Array(dampen_jacobian!!(Jstatic, Jstatic, D)) == |
| 53 | + dampen_jacobian!!(copy(J), J, D) |
| 54 | + end |
| 55 | +end |
0 commit comments