Skip to content

Commit 344016e

Browse files
Handle FIRK prerelease AD matvec fallbacks
Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
1 parent ce207c2 commit 344016e

5 files changed

Lines changed: 77 additions & 6 deletions

File tree

lib/BoundaryValueDiffEqCore/src/utils.jl

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,26 @@ function __maybe_matmul!(z::AbstractArray, A, b, α = eltype(z)(1), β = eltype(
100100
return mul!(z, A, b, α, β)
101101
end
102102

103+
function __maybe_matmul!(
104+
z::AbstractVector{<:Number}, A::AbstractMatrix{<:Number},
105+
b::AbstractVector{<:Number}, α = eltype(z)(1), β = eltype(z)(0)
106+
)
107+
length(z) == size(A, 1) ||
108+
throw(DimensionMismatch("z has length $(length(z)), but A has $(size(A, 1)) rows"))
109+
length(b) == size(A, 2) ||
110+
throw(DimensionMismatch("b has length $(length(b)), but A has $(size(A, 2)) columns"))
111+
112+
T = promote_type(eltype(z), eltype(A), eltype(b), typeof(α), typeof(β))
113+
for (z_index, row) in zip(eachindex(z), axes(A, 1))
114+
acc = zero(T)
115+
for (b_index, col) in zip(eachindex(b), axes(A, 2))
116+
@inbounds acc += A[row, col] * b[b_index]
117+
end
118+
@inbounds z[z_index] = α * acc + β * z[z_index]
119+
end
120+
return z
121+
end
122+
103123
# NOTE: We can implement it as mul! as above but then we pay the cost of moving
104124
# `w` to the GPU too many times. Instead if we iterate of w and w′ we save
105125
# that cost. Our main cost is anyways going to be due to a large `u0` and

lib/BoundaryValueDiffEqFIRK/src/BoundaryValueDiffEqFIRK.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module BoundaryValueDiffEqFIRK
22

3-
using ADTypes: ADTypes, AutoSparse, AutoForwardDiff
3+
using ADTypes: ADTypes, AutoSparse, AutoForwardDiff, AutoEnzyme, AutoMooncake
44
using ArrayInterface: fast_scalar_indexing
55
using BandedMatrices: BandedMatrix, Ones
66
using BoundaryValueDiffEqCore: BoundaryValueDiffEqCore,

lib/BoundaryValueDiffEqFIRK/src/adaptivity.jl

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -201,17 +201,39 @@ function get_S_coeffs(h, yᵢ, yᵢ₊₁, dyᵢ, dyᵢ₊₁, ymid, dymid)
201201
end
202202

203203
# S forward Interpolation
204+
function __firk_matvec!(y, A, b)
205+
length(y) == size(A, 1) ||
206+
throw(DimensionMismatch("y has length $(length(y)), but A has $(size(A, 1)) rows"))
207+
length(b) == size(A, 2) ||
208+
throw(DimensionMismatch("b has length $(length(b)), but A has $(size(A, 2)) columns"))
209+
210+
T = promote_type(eltype(y), eltype(A), eltype(b))
211+
for (y_index, row) in zip(eachindex(y), axes(A, 1))
212+
acc = zero(T)
213+
for (b_index, col) in zip(eachindex(b), axes(A, 2))
214+
@inbounds acc += A[row, col] * b[b_index]
215+
end
216+
@inbounds y[y_index] = acc
217+
end
218+
return y
219+
end
220+
221+
function __firk_matvec(A, b)
222+
y = similar(b, promote_type(eltype(A), eltype(b)), size(A, 1))
223+
return __firk_matvec!(y, A, b)
224+
end
225+
204226
function S_interpolate!(y::AbstractArray, t, coeffs)
205227
ts = [t^(i - 1) for i in axes(coeffs, 2)]
206-
return y .= coeffs * ts
228+
return __firk_matvec!(y, coeffs, ts)
207229
end
208230

209231
function dS_interpolate!(dy::AbstractArray, t, S_coeffs)
210-
ts = zeros(size(S_coeffs, 2))
232+
ts = zeros(promote_type(eltype(S_coeffs), typeof(t)), size(S_coeffs, 2))
211233
for i in 2:size(S_coeffs, 2)
212234
ts[i] = (i - 1) * t^(i - 2)
213235
end
214-
return dy .= S_coeffs * ts
236+
return __firk_matvec!(dy, S_coeffs, ts)
215237
end
216238

217239
"""
@@ -577,7 +599,7 @@ end
577599
end
578600

579601
function get_q_coeffs(A, ki, h)
580-
coeffs = A * ki
602+
coeffs = __firk_matvec(A, ki)
581603
for i in axes(coeffs, 1)
582604
coeffs[i] = coeffs[i] / (h^(i - 1))
583605
end

lib/BoundaryValueDiffEqFIRK/src/firk.jl

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,34 @@ end
7373

7474
Base.eltype(::FIRKCacheExpand{iip, T}) where {iip, T} = T
7575

76+
# Julia 1.13 prereleases expose Enzyme/Mooncake issues in expanded FIRK collocation AD.
77+
const FIRK_AD_PRERELEASE_FALLBACK =
78+
VERSION >= v"1.13.0-DEV.0" && VERSION < v"1.13.0"
79+
80+
@inline __firk_prerelease_diffmode(ad) = ad
81+
@inline function __firk_prerelease_diffmode(ad::AutoEnzyme)
82+
return FIRK_AD_PRERELEASE_FALLBACK ? AutoForwardDiff() : ad
83+
end
84+
@inline function __firk_prerelease_diffmode(ad::AutoMooncake)
85+
return FIRK_AD_PRERELEASE_FALLBACK ? AutoForwardDiff() : ad
86+
end
87+
@inline function __firk_prerelease_diffmode(ad::AutoSparse)
88+
dense_ad = __firk_prerelease_diffmode(ADTypes.dense_ad(ad))
89+
dense_ad === ADTypes.dense_ad(ad) && return ad
90+
return AutoSparse(
91+
dense_ad;
92+
sparsity_detector = ADTypes.sparsity_detector(ad),
93+
coloring_algorithm = ADTypes.coloring_algorithm(ad)
94+
)
95+
end
96+
97+
function __firk_prerelease_jacobian_algorithm(jac_alg::BVPJacobianAlgorithm)
98+
nonbc_diffmode = __firk_prerelease_diffmode(jac_alg.nonbc_diffmode)
99+
diffmode = __firk_prerelease_diffmode(jac_alg.diffmode)
100+
(nonbc_diffmode === jac_alg.nonbc_diffmode && diffmode === jac_alg.diffmode) && return jac_alg
101+
return BVPJacobianAlgorithm(jac_alg.bc_diffmode, nonbc_diffmode, diffmode)
102+
end
103+
76104
function extend_y(y, N::Int, stage::Int)
77105
y_extended = similar(y.u, (N - 1) * (stage + 1) + 1)
78106
for (i, ctr) in enumerate(2:(stage + 1):((N - 1) * (stage + 1) + 1))
@@ -294,6 +322,7 @@ function init_expanded(
294322
)
295323
verbose_spec = _process_verbose_param(verbose)
296324
@set! alg.jac_alg = concrete_jacobian_algorithm(alg.jac_alg, prob, alg)
325+
@set! alg.jac_alg = __firk_prerelease_jacobian_algorithm(alg.jac_alg)
297326
iip = isinplace(prob)
298327
@assert (iip || isnothing(alg.optimize)) "Out-of-place constraints don't allow optimization solvers "
299328
if adaptive && isa(alg, FIRKNoAdaptivity)

lib/BoundaryValueDiffEqFIRK/src/interpolation.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,7 @@ function (s::EvalSol{C})(tval::Number) where {C <: FIRKCacheExpand}
386386
end
387387

388388
function get_q_coeffs_interp(A, ki, h)
389-
coeffs = A * ki
389+
coeffs = __firk_matvec(A, ki)
390390
for i in axes(coeffs, 1)
391391
coeffs[i] = coeffs[i] / (h^(i - 1))
392392
end

0 commit comments

Comments
 (0)