1- # variables equations depend on as a vector of vectors of variables
2- # each system type should define extract_variables! for a single equation
1+ """
2+ ```julia
3+ equation_dependencies(sys::AbstractSystem; variables=states(sys))
4+ ```
5+
6+ Given an `AbstractSystem` calculate for each equation the variables it depends on.
7+
8+ Notes:
9+ - Variables that are not in `variables` are filtered out.
10+ - `get_variables!` is used to determine the variables within a given equation.
11+ - returns a `Vector{Vector{Variable}}()` mapping the index of an equation to the `variables` it depends on.
12+
13+ Example:
14+ ```julia
15+ using ModelingToolkit
16+ @parameters β γ κ η t
17+ @variables S(t) I(t) R(t)
18+
19+ # use a reaction system to easily generate ODE and jump systems
20+ rxs = [Reaction(β, [S,I], [I], [1,1], [2]),
21+ Reaction(γ, [I], [R]),
22+ Reaction(κ+η, [R], [S])]
23+ rs = ReactionSystem(rxs, t, [S,I,R], [β,γ,κ,η])
24+
25+ # ODEs:
26+ odesys = convert(ODESystem, rs)
27+
28+ # dependency of each ODE on state variables
29+ equation_dependencies(odesys)
30+
31+ # dependency of each ODE on parameters
32+ equation_dependencies(odesys, variables=parameters(odesys))
33+
34+ # Jumps
35+ jumpsys = convert(JumpSystem, rs)
36+
37+ # dependency of each jump rate function on state variables
38+ equation_dependencies(jumpsys)
39+
40+ # dependency of each jump rate function on parameters
41+ equation_dependencies(jumpsys, variables=parameters(jumpsys))
42+ ```
43+ """
344function equation_dependencies (sys:: AbstractSystem ; variables= states (sys))
445 eqs = equations (sys)
546 deps = Set {Operation} ()
@@ -14,14 +55,74 @@ function equation_dependencies(sys::AbstractSystem; variables=states(sys))
1455 depeqs_to_vars
1556end
1657
17- # modeled on LightGraphs SimpleGraph
58+ """
59+ $(TYPEDEF)
60+
61+ A bipartite graph representation between two, possibly distinct, sets of vertices
62+ (source and dependencies). Maps source vertices, labelled `1:N₁`, to vertices
63+ on which they depend (labelled `1:N₂`).
64+
65+ # Fields
66+ $(FIELDS)
67+
68+ # Example
69+ ```julia
70+ using ModelingToolkit
71+
72+ ne = 4
73+ srcverts = 1:4
74+ depverts = 1:2
75+
76+ # six source vertices
77+ fadjlist = [[1],[1],[2],[2],[1],[1,2]]
78+
79+ # two vertices they depend on
80+ badjlist = [[1,2,5,6],[3,4,6]]
81+
82+ bg = BipartiteGraph(7, fadjlist, badjlist)
83+ ```
84+ """
1885mutable struct BipartiteGraph{T <: Integer }
86+ """ Number of edges from source vertices to vertices they depend on."""
1987 ne:: Int
88+ """ Forward adjacency list mapping index of source vertices to the vertices they depend on."""
2089 fadjlist:: Vector{Vector{T}} # fadjlist[src] = [dest1,dest2,...]
90+ """ Backwrad adjacency list mapping index of vertices that are dependencies to the source vertices that depend on them."""
2191 badjlist:: Vector{Vector{T}} # badjlist[dst] = [src1,src2,...]
2292end
2393
24- # convert equation-variable dependencies to a bipartite graph
94+ """
95+ ```julia
96+ Base.isequal(bg1::BipartiteGraph{T}, bg2::BipartiteGraph{T}) where {T<:Integer}
97+ ```
98+
99+ Test whether two [`BipartiteGraph`](@ref)s are equal.
100+ """
101+ function Base. isequal (bg1:: BipartiteGraph{T} , bg2:: BipartiteGraph{T} ) where {T<: Integer }
102+ iseq = (bg1. ne == bg2. ne)
103+ iseq &= (bg1. fadjlist == bg2. fadjlist)
104+ iseq &= (bg1. badjlist == bg2. badjlist)
105+ iseq
106+ end
107+
108+ """
109+ ```julia
110+ asgraph(eqdeps, vtois)
111+ ```
112+
113+ Convert a collection of equation dependencies, for example as returned by
114+ `equation_dependencies`, to a [`BipartiteGraph`](@ref).
115+
116+ Notes:
117+ - `vtois` should provide `Dict` like mapping from variable dependency in `eqdeps`
118+ to the integer idx of the variable to use in the graph.
119+
120+ Example:
121+ Continuing the example started in [`equation_dependencies`](@ref)
122+ ```julia
123+ digr = asgraph(equation_dependencies(odesys), Dict(s => i for (i,s) in enumerate(states(odesys))))
124+ ```
125+ """
25126function asgraph (eqdeps, vtois)
26127 fadjlist = Vector {Vector{Int}} (undef, length (eqdeps))
27128 for (i,dep) in enumerate (eqdeps)
@@ -38,22 +139,55 @@ function asgraph(eqdeps, vtois)
38139 BipartiteGraph (ne, fadjlist, badjlist)
39140end
40141
41- function Base. isequal (bg1:: BipartiteGraph{T} , bg2:: BipartiteGraph{T} ) where {T<: Integer }
42- iseq = (bg1. ne == bg2. ne)
43- iseq &= (bg1. fadjlist == bg2. fadjlist)
44- iseq &= (bg1. badjlist == bg2. badjlist)
45- iseq
46- end
47142
48143# could be made to directly generate graph and save memory
49- function asgraph (sys:: AbstractSystem ; variables= nothing , variablestoids= nothing )
50- vs = isnothing (variables) ? states (sys) : variables
51- eqdeps = equation_dependencies (sys, variables= vs)
52- vtois = isnothing (variablestoids) ? Dict (convert (Variable, v) => i for (i,v) in enumerate (vs)) : variablestoids
53- asgraph (eqdeps, vtois)
144+ """
145+ ```julia
146+ asgraph(sys::AbstractSystem; variables=states(sys),
147+ variablestoids=Dict(convert(Variable, v) => i for (i,v) in enumerate(variables)))
148+ ```
149+
150+ Convert an `AbstractSystem` to a [`BipartiteGraph`](@ref) mapping equations
151+ to variables they depend on.
152+
153+ Notes:
154+ - Defaults for kwargs creating a mapping from `equations(sys)` to `states(sys)`
155+ they depend on.
156+ - `variables` should provide the list of variables to use for generating
157+ the dependency graph.
158+ - `variablestoids` should provide `Dict` like mapping from a `Variable` to its
159+ `Int` index within `variables`.
160+
161+ Example:
162+ Continuing the example started in [`equation_dependencies`](@ref)
163+ ```julia
164+ digr = asgraph(odesys)
165+ ```
166+ """
167+ function asgraph (sys:: AbstractSystem ; variables= states (sys),
168+ variablestoids= Dict (convert (Variable, v) => i for (i,v) in enumerate (variables)))
169+ asgraph (equation_dependencies (sys, variables= variables), variablestoids)
54170end
55171
56- # for each variable determine the equations that modify it
172+ """
173+ ```julia
174+ variable_dependencies(sys::AbstractSystem; variables=states(sys), variablestoids=nothing)
175+ ```
176+
177+ For each variable determine the equations that modify it and return as a [`BipartiteGraph`](@ref).
178+
179+ Notes:
180+ - Dependencies are returned as a [`BipartiteGraph`](@ref) mapping variable
181+ indices to the indices of equations that map to them.
182+ - `variables` denotes the list of variables to determine dependencies for.
183+ - `variablestoids` denotes a `Dict` mapping `Variable`s to `Int`s.
184+
185+ Example:
186+ Continuing the example of [`equation_dependencies`](@ref)
187+ ```julia
188+ variable_dependencies(odesys)
189+ ```
190+ """
57191function variable_dependencies (sys:: AbstractSystem ; variables= states (sys), variablestoids= nothing )
58192 eqs = equations (sys)
59193 vtois = isnothing (variablestoids) ? Dict (convert (Variable, v) => i for (i,v) in enumerate (variables)) : variablestoids
@@ -76,7 +210,31 @@ function variable_dependencies(sys::AbstractSystem; variables=states(sys), varia
76210 BipartiteGraph (ne, fadjlist, badjlist)
77211end
78212
79- # convert BipartiteGraph to LightGraph.SimpleDiGraph
213+ """
214+ ```julia
215+ asdigraph(g::BipartiteGraph, sys::AbstractSystem; variables = states(sys), equationsfirst = true)
216+ ```
217+
218+ Convert a [`BipartiteGraph`](@ref) to a `LightGraph.SimpleDiGraph`.
219+
220+ Notes:
221+ - The resulting `SimpleDiGraph` unifies the two sets of vertices (equations
222+ and then states in the case it comes from [`asgraph`](@ref)), producing one
223+ ordered set of integer vertices (`SimpleDiGraph` does not support two distinct
224+ collections of vertices so they must be merged).
225+ - `variables` gives the variables that `g` is associated with (usually the
226+ `states` of a system).
227+ - `equationsfirst` (default is `true`) gives whether the [`BipartiteGraph`](@ref)
228+ gives a mapping from equations to variables they depend on (`true`), as calculated
229+ by [`asgraph`](@ref), or whether it gives a mapping from variables to the equations
230+ that modify them, as calculated by [`variable_dependencies`](@ref).
231+
232+ Example:
233+ Continuing the example in [`asgraph`](@ref)
234+ ```julia
235+ dg = asdigraph(digr)
236+ ```
237+ """
80238function asdigraph (g:: BipartiteGraph , sys:: AbstractSystem ; variables = states (sys), equationsfirst = true )
81239 neqs = length (equations (sys))
82240 nvars = length (variables)
@@ -96,7 +254,25 @@ function asdigraph(g::BipartiteGraph, sys::AbstractSystem; variables = states(sy
96254 SimpleDiGraph (g. ne, fadjlist, badjlist)
97255end
98256
99- # maps the i'th eq to equations that depend on it
257+ """
258+ ```julia
259+ eqeq_dependencies(eqdeps::BipartiteGraph{T}, vardeps::BipartiteGraph{T}) where {T <: Integer}
260+ ```
261+
262+ Calculate a `LightGraph.SimpleDiGraph` that maps each equation to equations they depend on.
263+
264+ Notes:
265+ - The `fadjlist` of the `SimpleDiGraph` maps from an equation to the equations that
266+ modify variables it depends on.
267+ - The `badjlist` of the `SimpleDiGraph` maps from an equation to equations that
268+ depend on variables it modifies.
269+
270+ Example:
271+ Continuing the example of `equation_dependencies`
272+ ```julia
273+ eqeqdep = eqeq_dependencies(asgraph(odesys), variable_dependencies(odesys))
274+ ```
275+ """
100276function eqeq_dependencies (eqdeps:: BipartiteGraph{T} , vardeps:: BipartiteGraph{T} ) where {T <: Integer }
101277 g = SimpleDiGraph {T} (length (eqdeps. fadjlist))
102278
@@ -111,5 +287,23 @@ function eqeq_dependencies(eqdeps::BipartiteGraph{T}, vardeps::BipartiteGraph{T}
111287 g
112288end
113289
114- # maps the i'th variable to variables that depend on it
290+ """
291+ ```julia
292+ varvar_dependencies(eqdeps::BipartiteGraph{T}, vardeps::BipartiteGraph{T}) where {T <: Integer} = eqeq_dependencies(vardeps, eqdeps)
293+ ```
294+
295+ Calculate a `LightGraph.SimpleDiGraph` that maps each variable to variables they depend on.
296+
297+ Notes:
298+ - The `fadjlist` of the `SimpleDiGraph` maps from a variable to the variables that
299+ depend on it.
300+ - The `badjlist` of the `SimpleDiGraph` maps from a variable to variables on which
301+ it depends.
302+
303+ Example:
304+ Continuing the example of `equation_dependencies`
305+ ```julia
306+ varvardep = varvar_dependencies(asgraph(odesys), variable_dependencies(odesys))
307+ ```
308+ """
115309varvar_dependencies (eqdeps:: BipartiteGraph{T} , vardeps:: BipartiteGraph{T} ) where {T <: Integer } = eqeq_dependencies (vardeps, eqdeps)
0 commit comments