Skip to content

Commit f7c02f0

Browse files
feat: add visitor for recursive accessor functions
Currently only implemented for `equations`
1 parent 8d49c9d commit f7c02f0

File tree

1 file changed

+108
-8
lines changed

1 file changed

+108
-8
lines changed

lib/ModelingToolkitBase/src/systems/abstractsystem.jl

Lines changed: 108 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1261,18 +1261,18 @@ namespace_parameters(sys::AbstractSystem) = parameters(sys, parameters(sys))
12611261
namespace_guesses(sys::AbstractSystem) = namespace_expr(guesses(sys), sys)
12621262

12631263
"""
1264-
$(TYPEDSIGNATURES)
1264+
namespace_equations(sys::AbstractSystem)
12651265
12661266
Return `equations(sys)`, namespaced by the name of `sys`.
12671267
"""
1268-
function namespace_equations(sys::AbstractSystem, ivs = independent_variables(sys))
1269-
eqs = equations(sys)
1268+
function namespace_equations(sys::AbstractSystem, visitor = NoVisitor())
1269+
eqs = equations(sys, visitor)
12701270
isempty(eqs) && return eqs
12711271
if eqs === get_eqs(sys)
12721272
eqs = copy(eqs)
12731273
end
12741274
for i in eachindex(eqs)
1275-
eqs[i] = namespace_equation(eqs[i], sys; ivs)
1275+
eqs[i] = namespace_equation(eqs[i], sys)
12761276
end
12771277
return eqs
12781278
end
@@ -1657,25 +1657,125 @@ end
16571657
flatten(sys::AbstractSystem, args...) = sys
16581658

16591659
"""
1660-
$(TYPEDSIGNATURES)
1660+
$TYPEDEF
1661+
1662+
Abstract supertype for functors that can be passed to recursive functions such as
1663+
[`equations`](@ref) to track additional information.
1664+
"""
1665+
abstract type AbstractRecursivePropertyVisitor end
1666+
1667+
"""
1668+
descend_visitor!(visitor::AbstractRecursivePropertyVisitor, sys::AbstractSystem, f)
1669+
1670+
Descend the `visitor` into system `sys`. Also provide the getter function `f` for the
1671+
property the recursive function handles (e.g. `get_eqs` for `equations`).
1672+
"""
1673+
function descend_visitor! end
1674+
1675+
"""
1676+
ascend_visitor!(visitor::AbstractRecursivePropertyVisitor, sys::AbstractSystem, f)
1677+
1678+
Ascend the `visitor` from system `sys` into the parent, marking that all its subsystems
1679+
have been explored. Also provide the getter function `f` for the property the recursive
1680+
function handles (e.g. `get_eqs` for `equations`).
1681+
"""
1682+
function ascend_visitor! end
1683+
1684+
"""
1685+
$TYPEDEF
1686+
1687+
Dummy visitor
1688+
"""
1689+
struct NoVisitor <: AbstractRecursivePropertyVisitor end
1690+
descend_visitor!(::NoVisitor, ::AbstractSystem, _) = nothing
1691+
ascend_visitor!(::NoVisitor, ::AbstractSystem, _) = nothing
1692+
1693+
"""
1694+
$TYPEDEF
1695+
1696+
Visitor that tracks source information
1697+
"""
1698+
struct SourceInformationVisitor <: AbstractRecursivePropertyVisitor
1699+
"""
1700+
List of names indicating the subsystem containing each value as a path from the root.
1701+
Names are in reverse order (root occurs last).
1702+
"""
1703+
sources::Vector{Vector{Symbol}}
1704+
"""
1705+
A stack of indices indicating the index where source entries belonging to each system
1706+
in the call stack start.
1707+
"""
1708+
start_positions_stack::Vector{Int}
1709+
end
1710+
1711+
SourceInformationVisitor() = SourceInformationVisitor(Vector{Symbol}[], Int[])
1712+
1713+
function descend_visitor!(vis::SourceInformationVisitor, sys::AbstractSystem, f)
1714+
(; sources, start_positions_stack) = vis
1715+
# The sources for equations in this system start from the next valid index
1716+
start = length(sources) + 1
1717+
push!(start_positions_stack, start)
1718+
# Add source information for the current system
1719+
for _ in f(sys)
1720+
push!(sources, Symbol[])
1721+
end
1722+
end
1723+
1724+
function ascend_visitor!(vis::SourceInformationVisitor, sys::AbstractSystem, f)
1725+
(; sources, start_positions_stack) = vis
1726+
# Get the start position for `sys`. We know we've explored all subsystems of `sys`.
1727+
cur_start = pop!(start_positions_stack)
1728+
# Since the search is DFS, all entries in `sources` from `cur_start` till the
1729+
# end are inside `sys`, so add the name to them.
1730+
name = nameof(sys)
1731+
for i in cur_start:lastindex(sources)
1732+
push!(sources[i], name)
1733+
end
1734+
end
1735+
1736+
"""
1737+
equations(sys::AbstractSystem)
16611738
16621739
Get the flattened equations of the system `sys` and its subsystems.
16631740
It may include some abbreviations and aliases of observables.
16641741
It is often the most useful way to inspect the equations of a system.
16651742
16661743
See also [`full_equations`](@ref) and [`ModelingToolkitBase.get_eqs`](@ref).
16671744
"""
1668-
function equations(sys::AbstractSystem)
1745+
function equations(sys::AbstractSystem, visitor::AbstractRecursivePropertyVisitor = NoVisitor())
16691746
eqs = get_eqs(sys)
16701747
systems = get_systems(sys)
1671-
isempty(systems) && return eqs
1748+
descend_visitor!(visitor, sys, get_eqs)
1749+
if isempty(systems)
1750+
ascend_visitor!(visitor, sys, get_eqs)
1751+
return eqs
1752+
end
16721753
eqs = copy(eqs)
16731754
for subsys in systems
1674-
append!(eqs, namespace_equations(subsys))
1755+
append!(eqs, namespace_equations(subsys, visitor))
16751756
end
1757+
ascend_visitor!(visitor, sys, get_eqs)
16761758
return eqs
16771759
end
16781760

1761+
function equations_source(sys::AbstractSystem)
1762+
source = Vector{Symbol}[]
1763+
for _ in eachindex(get_eqs(sys))
1764+
push!(source, Symbol[])
1765+
end
1766+
systems = get_systems(sys)
1767+
isempty(systems) && return source
1768+
1769+
for subsys in systems
1770+
name = nameof(subsys)
1771+
sub_sources = equations_source(subsys)
1772+
for src in sub_sources
1773+
push!(src, name)
1774+
end
1775+
append!(source, name)
1776+
end
1777+
end
1778+
16791779
"""
16801780
equations_toplevel(sys::AbstractSystem)
16811781

0 commit comments

Comments
 (0)