From 2c2480937ee6cdc8e49e94695c11d6889a25f029 Mon Sep 17 00:00:00 2001 From: Sam Isaacson Date: Sun, 3 Nov 2024 14:29:20 -0500 Subject: [PATCH 1/5] cleanup JumpSystem constructor to match ODESystem better --- src/systems/jumps/jumpsystem.jl | 81 +++++++++++++++++++++++---------- 1 file changed, 57 insertions(+), 24 deletions(-) diff --git a/src/systems/jumps/jumpsystem.jl b/src/systems/jumps/jumpsystem.jl index 6409609a10..6a74c6018b 100644 --- a/src/systems/jumps/jumpsystem.jl +++ b/src/systems/jumps/jumpsystem.jl @@ -96,6 +96,11 @@ struct JumpSystem{U <: ArrayPartition} <: AbstractTimeDependentSystem """ discrete_events::Vector{SymbolicDiscreteCallback} """ + A `Vector{SymbolicContinuousCallback}` that model events. + The integrator will use root finding to guarantee that it steps at each zero crossing. + """ + continuous_events::Vector{SymbolicContinuousCallback} + """ Topologically sorted parameter dependency equations, where all symbols are parameters and the LHS is a single parameter. """ @@ -160,13 +165,31 @@ function JumpSystem(eqs, iv, unknowns, ps; metadata = nothing, gui_metadata = nothing, kwargs...) + + # variable processing, similar to ODESystem name === nothing && throw(ArgumentError("The `name` keyword must be provided. Please consider using the `@named` macro")) - eqs = scalarize.(eqs) - sysnames = nameof.(systems) - if length(unique(sysnames)) != length(sysnames) - throw(ArgumentError("System names must be unique.")) + iv′ = value(iv) + us′ = value.(unknowns) + ps′ = value.(ps) + parameter_dependencies, ps = process_parameter_dependencies(parameter_dependencies, ps′) + if !(isempty(default_u0) && isempty(default_p)) + Base.depwarn( + "`default_u0` and `default_p` are deprecated. Use `defaults` instead.", + :JumpSystem, force = true) end + defaults = todict(defaults) + var_to_name = Dict() + process_variables!(var_to_name, defaults, us′) + process_variables!(var_to_name, defaults, ps′) + process_variables!(var_to_name, defaults, [eq.lhs for eq in parameter_dependencies]) + process_variables!(var_to_name, defaults, [eq.rhs for eq in parameter_dependencies]) + defaults = Dict{Any, Any}(value(k) => value(v) for (k, v) in pairs(defaults) + if value(v) !== nothing) + isempty(observed) || collect_var_to_name!(var_to_name, (eq.lhs for eq in observed)) + + # equation processing + eqs = scalarize.(eqs) ap = ArrayPartition(MassActionJump[], ConstantRateJump[], VariableRateJump[]) for eq in eqs if eq isa MassActionJump @@ -179,30 +202,42 @@ function JumpSystem(eqs, iv, unknowns, ps; error("JumpSystem equations must contain MassActionJumps, ConstantRateJumps, or VariableRateJumps.") end end - if !(isempty(default_u0) && isempty(default_p)) - Base.depwarn( - "`default_u0` and `default_p` are deprecated. Use `defaults` instead.", - :JumpSystem, force = true) + + sysnames = nameof.(systems) + if length(unique(sysnames)) != length(sysnames) + throw(ArgumentError("System names must be unique.")) end - defaults = todict(defaults) - defaults = Dict(value(k) => value(v) - for (k, v) in pairs(defaults) if value(v) !== nothing) - unknowns, ps = value.(unknowns), value.(ps) - var_to_name = Dict() - process_variables!(var_to_name, defaults, unknowns) - process_variables!(var_to_name, defaults, ps) - isempty(observed) || collect_var_to_name!(var_to_name, (eq.lhs for eq in observed)) (continuous_events === nothing) || error("JumpSystems currently only support discrete events.") disc_callbacks = SymbolicDiscreteCallbacks(discrete_events) - parameter_dependencies, ps = process_parameter_dependencies(parameter_dependencies, ps) + JumpSystem{typeof(ap)}(Threads.atomic_add!(SYSTEM_COUNT, UInt(1)), - ap, value(iv), unknowns, ps, var_to_name, observed, name, description, systems, + ap, iv′, us′, ps′, var_to_name, observed, name, description, systems, defaults, connector_type, disc_callbacks, parameter_dependencies, metadata, gui_metadata, checks = checks) end +##### MTK dispatches for JumpSystems ##### +function collect_vars!(unknowns, parameters, j::MassActionJump, iv; depth = 0, + op = Differential) + for field in (j.scaled_rates, j.reactant_stoch, j.net_stoch) + collect_vars!(unknowns, parameters, field, iv; depth, op) + end + return nothing +end + +function collect_vars!(unknowns, parameters, j::Union{ConstantRateJump,VariableRateJump}, + iv; depth = 0, op = Differential) + collect_vars!(unknowns, parameters, j.condition, iv; depth, op) + for eq in j.affect + (eq isa Equation) && collect_vars!(unknowns, parameters, eq, iv; depth, op) + end + return nothing +end + +########################################## + has_massactionjumps(js::JumpSystem) = !isempty(equations(js).x[1]) has_constantratejumps(js::JumpSystem) = !isempty(equations(js).x[2]) has_variableratejumps(js::JumpSystem) = !isempty(equations(js).x[3]) @@ -240,9 +275,8 @@ function assemble_vrj( outputvars = (value(affect.lhs) for affect in vrj.affect!) outputidxs = [unknowntoid[var] for var in outputvars] - affect = eval_or_rgf( - generate_affect_function(js, vrj.affect!, - outputidxs); eval_expression, eval_module) + affect = eval_or_rgf(generate_affect_function(js, vrj.affect!, outputidxs); + eval_expression, eval_module) VariableRateJump(rate, affect) end @@ -269,9 +303,8 @@ function assemble_crj( outputvars = (value(affect.lhs) for affect in crj.affect!) outputidxs = [unknowntoid[var] for var in outputvars] - affect = eval_or_rgf( - generate_affect_function(js, crj.affect!, - outputidxs); eval_expression, eval_module) + affect = eval_or_rgf(generate_affect_function(js, crj.affect!, outputidxs); + eval_expression, eval_module) ConstantRateJump(rate, affect) end From 413d258c5e90f146657b588e898a8d342f430b9e Mon Sep 17 00:00:00 2001 From: Sam Isaacson Date: Mon, 4 Nov 2024 10:01:44 -0500 Subject: [PATCH 2/5] get tests workings --- src/systems/jumps/jumpsystem.jl | 32 ++++++++++++++--------------- test/jumpsystem.jl | 36 +++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 16 deletions(-) diff --git a/src/systems/jumps/jumpsystem.jl b/src/systems/jumps/jumpsystem.jl index 6a74c6018b..d59a2df5ce 100644 --- a/src/systems/jumps/jumpsystem.jl +++ b/src/systems/jumps/jumpsystem.jl @@ -96,11 +96,6 @@ struct JumpSystem{U <: ArrayPartition} <: AbstractTimeDependentSystem """ discrete_events::Vector{SymbolicDiscreteCallback} """ - A `Vector{SymbolicContinuousCallback}` that model events. - The integrator will use root finding to guarantee that it steps at each zero crossing. - """ - continuous_events::Vector{SymbolicContinuousCallback} - """ Topologically sorted parameter dependency equations, where all symbols are parameters and the LHS is a single parameter. """ @@ -172,13 +167,14 @@ function JumpSystem(eqs, iv, unknowns, ps; iv′ = value(iv) us′ = value.(unknowns) ps′ = value.(ps) - parameter_dependencies, ps = process_parameter_dependencies(parameter_dependencies, ps′) + parameter_dependencies, ps′ = process_parameter_dependencies( + parameter_dependencies, ps′) if !(isempty(default_u0) && isempty(default_p)) Base.depwarn( "`default_u0` and `default_p` are deprecated. Use `defaults` instead.", :JumpSystem, force = true) end - defaults = todict(defaults) + defaults = Dict{Any,Any}(todict(defaults)) var_to_name = Dict() process_variables!(var_to_name, defaults, us′) process_variables!(var_to_name, defaults, ps′) @@ -188,7 +184,14 @@ function JumpSystem(eqs, iv, unknowns, ps; if value(v) !== nothing) isempty(observed) || collect_var_to_name!(var_to_name, (eq.lhs for eq in observed)) + sysnames = nameof.(systems) + if length(unique(sysnames)) != length(sysnames) + throw(ArgumentError("System names must be unique.")) + end + # equation processing + # this and the treatment of continuous events are the only part + # unique to JumpSystems eqs = scalarize.(eqs) ap = ArrayPartition(MassActionJump[], ConstantRateJump[], VariableRateJump[]) for eq in eqs @@ -203,11 +206,6 @@ function JumpSystem(eqs, iv, unknowns, ps; end end - sysnames = nameof.(systems) - if length(unique(sysnames)) != length(sysnames) - throw(ArgumentError("System names must be unique.")) - end - (continuous_events === nothing) || error("JumpSystems currently only support discrete events.") disc_callbacks = SymbolicDiscreteCallbacks(discrete_events) @@ -220,17 +218,19 @@ end ##### MTK dispatches for JumpSystems ##### function collect_vars!(unknowns, parameters, j::MassActionJump, iv; depth = 0, - op = Differential) + op = Differential) for field in (j.scaled_rates, j.reactant_stoch, j.net_stoch) - collect_vars!(unknowns, parameters, field, iv; depth, op) + for el in field + collect_vars!(unknowns, parameters, el, iv; depth, op) + end end return nothing end function collect_vars!(unknowns, parameters, j::Union{ConstantRateJump,VariableRateJump}, iv; depth = 0, op = Differential) - collect_vars!(unknowns, parameters, j.condition, iv; depth, op) - for eq in j.affect + collect_vars!(unknowns, parameters, j.rate, iv; depth, op) + for eq in j.affect! (eq isa Equation) && collect_vars!(unknowns, parameters, eq, iv; depth, op) end return nothing diff --git a/test/jumpsystem.jl b/test/jumpsystem.jl index 24b9abbc8a..16181d1938 100644 --- a/test/jumpsystem.jl +++ b/test/jumpsystem.jl @@ -340,3 +340,39 @@ let @test all(abs.(cmean .- cmean2) .<= 0.05 .* cmean) end + + +# collect_vars! tests for jumps +let + @variables x1(t) x2(t) x3(t) x4(t) x5(t) + @parameters p1 p2 p3 p4 p5 + j1 = ConstantRateJump(p1, [x1 ~ x1 + 1]) + j2 = MassActionJump(p2, [x2 => 1], [x3 => -1]) + j3 = VariableRateJump(p3, [x3 ~ x3 + 1, x4 ~ x4 + 1]) + j4 = MassActionJump(p4*p5, [x1 => 1, x5 => 1], [x1 => -1, x5 => -1, x2 => 1]) + us = Set() + ps = Set() + iv = t + + MT.collect_vars!(us, ps, j1, iv) + @test issetequal(us, [x1]) + @test issetequal(ps, [p1]) + + empty!(us) + empty!(ps) + MT.collect_vars!(us, ps, j2, iv) + @test issetequal(us, [x2, x3]) + @test issetequal(ps, [p2]) + + empty!(us) + empty!(ps) + MT.collect_vars!(us, ps, j3, iv) + @test issetequal(us, [x3, x4]) + @test issetequal(ps, [p3]) + + empty!(us) + empty!(ps) + MT.collect_vars!(us, ps, j4, iv) + @test issetequal(us, [x1, x5, x2]) + @test issetequal(ps, [p4, p5]) +end From 4daf8846d9b9555b3db071bde36c708d4ec2ce30 Mon Sep 17 00:00:00 2001 From: Sam Isaacson Date: Mon, 4 Nov 2024 10:10:08 -0500 Subject: [PATCH 3/5] tweak collect_vars --- src/systems/jumps/jumpsystem.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/systems/jumps/jumpsystem.jl b/src/systems/jumps/jumpsystem.jl index d59a2df5ce..f444a2480e 100644 --- a/src/systems/jumps/jumpsystem.jl +++ b/src/systems/jumps/jumpsystem.jl @@ -219,7 +219,8 @@ end ##### MTK dispatches for JumpSystems ##### function collect_vars!(unknowns, parameters, j::MassActionJump, iv; depth = 0, op = Differential) - for field in (j.scaled_rates, j.reactant_stoch, j.net_stoch) + collect_vars!(unknowns, parameters, j.scaled_rates, iv; depth, op) + for field in (j.reactant_stoch, j.net_stoch) for el in field collect_vars!(unknowns, parameters, el, iv; depth, op) end From 75f4ec6121b1c99eab4fef12a084b1df6c3067a0 Mon Sep 17 00:00:00 2001 From: Sam Isaacson Date: Mon, 4 Nov 2024 11:38:26 -0500 Subject: [PATCH 4/5] update collecting vars with scoping --- src/systems/abstractsystem.jl | 17 ++++++------ src/systems/jumps/jumpsystem.jl | 2 ++ test/jumpsystem.jl | 46 +++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 9 deletions(-) diff --git a/src/systems/abstractsystem.jl b/src/systems/abstractsystem.jl index c53c900d27..829310927f 100644 --- a/src/systems/abstractsystem.jl +++ b/src/systems/abstractsystem.jl @@ -923,15 +923,14 @@ One property to note is that if a system is complete, the system will no longer namespace its subsystems or variables, i.e. `isequal(complete(sys).v.i, v.i)`. """ function complete(sys::AbstractSystem; split = true, flatten = true) - if !(sys isa JumpSystem) - newunknowns = OrderedSet() - newparams = OrderedSet() - iv = has_iv(sys) ? get_iv(sys) : nothing - collect_scoped_vars!(newunknowns, newparams, sys, iv; depth = -1) - # don't update unknowns to not disturb `structural_simplify` order - # `GlobalScope`d unknowns will be picked up and added there - @set! sys.ps = unique!(vcat(get_ps(sys), collect(newparams))) - end + newunknowns = OrderedSet() + newparams = OrderedSet() + iv = has_iv(sys) ? get_iv(sys) : nothing + collect_scoped_vars!(newunknowns, newparams, sys, iv; depth = -1) + # don't update unknowns to not disturb `structural_simplify` order + # `GlobalScope`d unknowns will be picked up and added there + @set! sys.ps = unique!(vcat(get_ps(sys), collect(newparams))) + if flatten eqs = equations(sys) if eqs isa AbstractArray && eltype(eqs) <: Equation diff --git a/src/systems/jumps/jumpsystem.jl b/src/systems/jumps/jumpsystem.jl index f444a2480e..2fb92db62f 100644 --- a/src/systems/jumps/jumpsystem.jl +++ b/src/systems/jumps/jumpsystem.jl @@ -217,6 +217,7 @@ function JumpSystem(eqs, iv, unknowns, ps; end ##### MTK dispatches for JumpSystems ##### +eqtype_supports_collect_vars(j::MassActionJump) = true function collect_vars!(unknowns, parameters, j::MassActionJump, iv; depth = 0, op = Differential) collect_vars!(unknowns, parameters, j.scaled_rates, iv; depth, op) @@ -228,6 +229,7 @@ function collect_vars!(unknowns, parameters, j::MassActionJump, iv; depth = 0, return nothing end +eqtype_supports_collect_vars(j::Union{ConstantRateJump,VariableRateJump}) = true function collect_vars!(unknowns, parameters, j::Union{ConstantRateJump,VariableRateJump}, iv; depth = 0, op = Differential) collect_vars!(unknowns, parameters, j.rate, iv; depth, op) diff --git a/test/jumpsystem.jl b/test/jumpsystem.jl index 16181d1938..693cd39ddd 100644 --- a/test/jumpsystem.jl +++ b/test/jumpsystem.jl @@ -376,3 +376,49 @@ let @test issetequal(us, [x1, x5, x2]) @test issetequal(ps, [p4, p5]) end + +# scoping tests +let + @variables x1(t) x2(t) x3(t) x4(t) x5(t) + x2 = ParentScope(x2) + x3 = ParentScope(ParentScope(x3)) + x4 = DelayParentScope(x4, 2) + x5 = GlobalScope(x5) + @parameters p1 p2 p3 p4 p5 + p2 = ParentScope(p2) + p3 = ParentScope(ParentScope(p3)) + p4 = DelayParentScope(p4, 2) + p5 = GlobalScope(p5) + + j1 = ConstantRateJump(p1, [x1 ~ x1 + 1]) + j2 = MassActionJump(p2, [x2 => 1], [x3 => -1]) + j3 = VariableRateJump(p3, [x3 ~ x3 + 1, x4 ~ x4 + 1]) + j4 = MassActionJump(p4*p5, [x1 => 1, x5 => 1], [x1 => -1, x5 => -1, x2 => 1]) + @named js = JumpSystem([j1, j2, j3, j4], t, [x1, x2, x3, x4, x5], [p1, p2, p3, p4, p5]) + + us = Set(); ps = Set() + iv = t + MT.collect_scoped_vars!(us, ps, js, iv) + @test issetequal(us, [x2]) + @test issetequal(ps, [p2]) + + empty!.((us,ps)) + MT.collect_scoped_vars!(us, ps, js, iv; depth = 0) + @test issetequal(us, [x1]) + @test issetequal(ps, [p1]) + + empty!.((us,ps)) + MT.collect_scoped_vars!(us, ps, js, iv; depth = 1) + @test issetequal(us, [x2]) + @test issetequal(ps, [p2]) + + empty!.((us,ps)) + MT.collect_scoped_vars!(us, ps, js, iv; depth = 2) + @test issetequal(us, [x3, x4]) + @test issetequal(ps, [p3, p4]) + + empty!.((us,ps)) + MT.collect_scoped_vars!(us, ps, js, iv; depth = -1) + @test issetequal(us, [x5]) + @test issetequal(ps, [p5]) +end From e6ebcb9b5ca21e796670d731ff6f4913ce21a1ac Mon Sep 17 00:00:00 2001 From: Sam Isaacson Date: Mon, 4 Nov 2024 13:09:34 -0500 Subject: [PATCH 5/5] format --- src/systems/abstractsystem.jl | 2 +- src/systems/jumps/jumpsystem.jl | 19 ++++++++++--------- test/jumpsystem.jl | 20 ++++++++++---------- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/systems/abstractsystem.jl b/src/systems/abstractsystem.jl index 829310927f..e565bb27e1 100644 --- a/src/systems/abstractsystem.jl +++ b/src/systems/abstractsystem.jl @@ -930,7 +930,7 @@ function complete(sys::AbstractSystem; split = true, flatten = true) # don't update unknowns to not disturb `structural_simplify` order # `GlobalScope`d unknowns will be picked up and added there @set! sys.ps = unique!(vcat(get_ps(sys), collect(newparams))) - + if flatten eqs = equations(sys) if eqs isa AbstractArray && eltype(eqs) <: Equation diff --git a/src/systems/jumps/jumpsystem.jl b/src/systems/jumps/jumpsystem.jl index 2fb92db62f..9fa073b4b0 100644 --- a/src/systems/jumps/jumpsystem.jl +++ b/src/systems/jumps/jumpsystem.jl @@ -174,14 +174,15 @@ function JumpSystem(eqs, iv, unknowns, ps; "`default_u0` and `default_p` are deprecated. Use `defaults` instead.", :JumpSystem, force = true) end - defaults = Dict{Any,Any}(todict(defaults)) + defaults = Dict{Any, Any}(todict(defaults)) var_to_name = Dict() process_variables!(var_to_name, defaults, us′) process_variables!(var_to_name, defaults, ps′) process_variables!(var_to_name, defaults, [eq.lhs for eq in parameter_dependencies]) process_variables!(var_to_name, defaults, [eq.rhs for eq in parameter_dependencies]) - defaults = Dict{Any, Any}(value(k) => value(v) for (k, v) in pairs(defaults) - if value(v) !== nothing) + #! format: off + defaults = Dict{Any, Any}(value(k) => value(v) for (k, v) in pairs(defaults) if value(v) !== nothing) + #! format: on isempty(observed) || collect_var_to_name!(var_to_name, (eq.lhs for eq in observed)) sysnames = nameof.(systems) @@ -218,8 +219,8 @@ end ##### MTK dispatches for JumpSystems ##### eqtype_supports_collect_vars(j::MassActionJump) = true -function collect_vars!(unknowns, parameters, j::MassActionJump, iv; depth = 0, - op = Differential) +function collect_vars!(unknowns, parameters, j::MassActionJump, iv; depth = 0, + op = Differential) collect_vars!(unknowns, parameters, j.scaled_rates, iv; depth, op) for field in (j.reactant_stoch, j.net_stoch) for el in field @@ -229,8 +230,8 @@ function collect_vars!(unknowns, parameters, j::MassActionJump, iv; depth = 0, return nothing end -eqtype_supports_collect_vars(j::Union{ConstantRateJump,VariableRateJump}) = true -function collect_vars!(unknowns, parameters, j::Union{ConstantRateJump,VariableRateJump}, +eqtype_supports_collect_vars(j::Union{ConstantRateJump, VariableRateJump}) = true +function collect_vars!(unknowns, parameters, j::Union{ConstantRateJump, VariableRateJump}, iv; depth = 0, op = Differential) collect_vars!(unknowns, parameters, j.rate, iv; depth, op) for eq in j.affect! @@ -278,7 +279,7 @@ function assemble_vrj( outputvars = (value(affect.lhs) for affect in vrj.affect!) outputidxs = [unknowntoid[var] for var in outputvars] - affect = eval_or_rgf(generate_affect_function(js, vrj.affect!, outputidxs); + affect = eval_or_rgf(generate_affect_function(js, vrj.affect!, outputidxs); eval_expression, eval_module) VariableRateJump(rate, affect) end @@ -306,7 +307,7 @@ function assemble_crj( outputvars = (value(affect.lhs) for affect in crj.affect!) outputidxs = [unknowntoid[var] for var in outputvars] - affect = eval_or_rgf(generate_affect_function(js, crj.affect!, outputidxs); + affect = eval_or_rgf(generate_affect_function(js, crj.affect!, outputidxs); eval_expression, eval_module) ConstantRateJump(rate, affect) end diff --git a/test/jumpsystem.jl b/test/jumpsystem.jl index 693cd39ddd..30cb636226 100644 --- a/test/jumpsystem.jl +++ b/test/jumpsystem.jl @@ -341,15 +341,14 @@ let @test all(abs.(cmean .- cmean2) .<= 0.05 .* cmean) end - # collect_vars! tests for jumps -let +let @variables x1(t) x2(t) x3(t) x4(t) x5(t) @parameters p1 p2 p3 p4 p5 j1 = ConstantRateJump(p1, [x1 ~ x1 + 1]) j2 = MassActionJump(p2, [x2 => 1], [x3 => -1]) j3 = VariableRateJump(p3, [x3 ~ x3 + 1, x4 ~ x4 + 1]) - j4 = MassActionJump(p4*p5, [x1 => 1, x5 => 1], [x1 => -1, x5 => -1, x2 => 1]) + j4 = MassActionJump(p4 * p5, [x1 => 1, x5 => 1], [x1 => -1, x5 => -1, x2 => 1]) us = Set() ps = Set() iv = t @@ -389,35 +388,36 @@ let p3 = ParentScope(ParentScope(p3)) p4 = DelayParentScope(p4, 2) p5 = GlobalScope(p5) - + j1 = ConstantRateJump(p1, [x1 ~ x1 + 1]) j2 = MassActionJump(p2, [x2 => 1], [x3 => -1]) j3 = VariableRateJump(p3, [x3 ~ x3 + 1, x4 ~ x4 + 1]) - j4 = MassActionJump(p4*p5, [x1 => 1, x5 => 1], [x1 => -1, x5 => -1, x2 => 1]) + j4 = MassActionJump(p4 * p5, [x1 => 1, x5 => 1], [x1 => -1, x5 => -1, x2 => 1]) @named js = JumpSystem([j1, j2, j3, j4], t, [x1, x2, x3, x4, x5], [p1, p2, p3, p4, p5]) - us = Set(); ps = Set() + us = Set() + ps = Set() iv = t MT.collect_scoped_vars!(us, ps, js, iv) @test issetequal(us, [x2]) @test issetequal(ps, [p2]) - empty!.((us,ps)) + empty!.((us, ps)) MT.collect_scoped_vars!(us, ps, js, iv; depth = 0) @test issetequal(us, [x1]) @test issetequal(ps, [p1]) - empty!.((us,ps)) + empty!.((us, ps)) MT.collect_scoped_vars!(us, ps, js, iv; depth = 1) @test issetequal(us, [x2]) @test issetequal(ps, [p2]) - empty!.((us,ps)) + empty!.((us, ps)) MT.collect_scoped_vars!(us, ps, js, iv; depth = 2) @test issetequal(us, [x3, x4]) @test issetequal(ps, [p3, p4]) - empty!.((us,ps)) + empty!.((us, ps)) MT.collect_scoped_vars!(us, ps, js, iv; depth = -1) @test issetequal(us, [x5]) @test issetequal(ps, [p5])