Skip to content

Commit 3c8c8ed

Browse files
ChrisRackauckas-ClaudeChrisRackauckasCursor Agent
authored
Forward ExtendedJumpArray properties to wrapped state (#57) (#669)
* Forward ExtendedJumpArray properties to wrapped state VariableRateJump affect! functions with ArrayPartition state can use integrator.u.x instead of the integrator.u.u.x workaround (#57). Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com> Co-Authored-By: Cursor Agent <noreply@cursor.com> Agent-Harness: Cursor Agent CLI 2026.09.26-dd393fe Agent-Model: auto Agent-Session: local session, transcript at /home/crackauc/sandbox/goals/issue-backlog/jobs/fix-JumpProcesses.jl-57/log.txt on amdci2.julia.csail.mit.edu * Strengthen ArrayPartition ExtendedJumpArray regression test Complete both ODE derivatives, use deterministic jump increments, assert trajectory results, dedupe propertynames, and document property forwarding. Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com> Co-Authored-By: Cursor Agent <noreply@cursor.com> Agent-Harness: Cursor Agent CLI 2026.09.26-dd393fe Agent-Model: auto Agent-Session: local session, transcript at /home/crackauc/sandbox/goals/issue-backlog/jobs/fix-JumpProcesses.jl-57/log.txt on amdci2.julia.csail.mit.edu --------- Co-authored-by: ChrisRackauckas-Claude <accounts@chrisrackauckas.com> Co-authored-by: Cursor Agent <noreply@cursor.com>
1 parent 26b9c57 commit 3c8c8ed

2 files changed

Lines changed: 51 additions & 0 deletions

File tree

‎src/extended_jump_array.jl‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ sol = solve(jprob, Tsit5())
5656
`integrator.u` an `ExtendedJumpArray`.
5757
- As such, `affect!` functions that wish to modify the state via vector
5858
operations should use `ueja.u.u` to obtain the aliased state object.
59+
- `:u` and `:jump_u` always refer to the `ExtendedJumpArray` fields. Any other
60+
property access (and `propertynames`) is forwarded to the wrapped state
61+
`ueja.u`, so e.g. `ueja.x` works when `ueja.u` is an `ArrayPartition`.
5962
"""
6063
struct ExtendedJumpArray{T3 <: Number, T1, T <: AbstractArray{T3, T1}, T2} <:
6164
AbstractArray{T3, 1}
@@ -65,6 +68,18 @@ struct ExtendedJumpArray{T3 <: Number, T1, T <: AbstractArray{T3, T1}, T2} <:
6568
jump_u::T2
6669
end
6770

71+
@inline function Base.getproperty(A::ExtendedJumpArray, s::Symbol)
72+
s === :u && return getfield(A, :u)
73+
s === :jump_u && return getfield(A, :jump_u)
74+
return getproperty(getfield(A, :u), s)
75+
end
76+
77+
function Base.propertynames(A::ExtendedJumpArray, private::Bool = false)
78+
fnames = fieldnames(typeof(A))
79+
unames = propertynames(getfield(A, :u), private)
80+
return (fnames..., filter(n -> !(n in fnames), unames)...)
81+
end
82+
6883
Base.length(A::ExtendedJumpArray) = length(A.u) + length(A.jump_u)
6984
Base.size(A::ExtendedJumpArray) = (length(A),)
7085
@inline function Base.getindex(A::ExtendedJumpArray, i::Int)

‎test/extended_jump_array.jl‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using Test, JumpProcesses, DiffEqBase, OrdinaryDiffEq, SciMLBase, LinearAlgebra, LinearSolve
22
using FastBroadcast
33
using ForwardDiff
4+
using RecursiveArrayTools
45
using StableRNGs
56

67
rng = StableRNG(123)
@@ -228,3 +229,38 @@ let
228229
@test similar(u) isa ExtendedJumpArray
229230
@test copy(u) isa ExtendedJumpArray
230231
end
232+
233+
@testset "ArrayPartition VariableRateJump property forwarding" begin
234+
eja = ExtendedJumpArray(ArrayPartition([1.0], [2.0]), [0.0])
235+
@test eja.u isa ArrayPartition
236+
@test eja.jump_u == [0.0]
237+
@test eja.x === eja.u.x
238+
@test allunique(propertynames(eja))
239+
@test :u in propertynames(eja)
240+
@test :jump_u in propertynames(eja)
241+
@test :x in propertynames(eja)
242+
243+
for agg in (VR_FRM(), VR_Direct())
244+
jumps = Ref(0)
245+
function f!(du, u, p, t)
246+
du.x[1][1] = -u.x[1][1]
247+
du.x[2][1] = 0.0
248+
nothing
249+
end
250+
function affect!(integrator)
251+
jumps[] += 1
252+
integrator.u.x[2][1] += 1.0
253+
nothing
254+
end
255+
u0 = ArrayPartition([1.0], [1.0])
256+
ode = ODEProblem(f!, u0, (0.0, 1.0))
257+
jump = VariableRateJump((u, p, t) -> 10 * u[1], affect!)
258+
jump_prob = JumpProblem(ode, Direct(), jump; vr_aggregator = agg,
259+
rng = StableRNG(57))
260+
sol = solve(jump_prob, Tsit5(); abstol = 1e-11, reltol = 1e-11)
261+
@test sol.retcode == ReturnCode.Success
262+
@test jumps[] > 0
263+
@test isapprox(sol.u[end].x[1][1], exp(-1); rtol = 1e-9)
264+
@test sol.u[end].x[2][1] ≈ 1 + jumps[]
265+
end
266+
end

0 commit comments

Comments
 (0)