diff --git a/src/cdp.jl b/src/cdp.jl index 2441875..be5c1f8 100644 --- a/src/cdp.jl +++ b/src/cdp.jl @@ -603,12 +603,13 @@ function policy_iteration_operator!(cdp::ContinuousDP, C::Vector{Float64}, end -# Sup distance between two arrays, without allocating a temporary +# Sup distance between two arrays, without allocating a temporary. +# NaN entries propagate to the result (as with `maximum(abs, x - y)`), so +# that a diverged iteration is never mistaken for a converged one. function _max_abs_diff(x, y) err = abs(zero(promote_type(eltype(x), eltype(y)))) @inbounds for i in eachindex(x, y) - d = abs(x[i] - y[i]) - d > err && (err = d) + err = max(err, abs(x[i] - y[i])) end return err end diff --git a/test/test_workspace.jl b/test/test_workspace.jl index 5fd7fdc..63dffeb 100644 --- a/test/test_workspace.jl +++ b/test/test_workspace.jl @@ -1,4 +1,22 @@ -using ContinuousDPs: CDPWorkspace, bellman_operator!, policy_iteration_operator! +using ContinuousDPs: CDPWorkspace, bellman_operator!, policy_iteration_operator!, + _max_abs_diff, operator_iteration! + +@testset "_max_abs_diff" begin + @test _max_abs_diff([1.0, 2.0], [1.5, 0.5]) == 1.5 + @test _max_abs_diff([0.0], [0.0]) == 0.0 + # NaN must propagate: a diverged iteration (Inf - Inf = NaN) must not be + # reported as converged + @test isnan(_max_abs_diff([NaN], [NaN])) + @test isnan(_max_abs_diff([1.0, NaN, 2.0], [1.0, NaN, 0.0])) + @test isnan(_max_abs_diff([Inf], [Inf])) + + # End-to-end: an operator that diverges to non-finite values must not be + # declared converged + diverge!(C) = (C .= NaN; C) + converged, num_iter = + operator_iteration!(diverge!, [0.0, 0.0], 1e-8, 10, verbose=0) + @test !converged +end @testset "CDPWorkspace" begin beta = 0.95