Skip to content

Commit dc88b14

Browse files
Merge pull request #384 from isaacsas/depgreaph-docs
dependency graph docs
2 parents 2c62ae2 + db4bb75 commit dc88b14

File tree

3 files changed

+236
-20
lines changed

3 files changed

+236
-20
lines changed

docs/make.jl

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ makedocs(
1919
"systems/NonlinearSystem.md",
2020
"systems/OptimizationSystem.md",
2121
"systems/ReactionSystem.md",
22-
"systems/PDESystem.md"
22+
"systems/PDESystem.md",
23+
"systems/DependencyGraphs.md"
2324
],
2425
"IR.md"
2526
]

docs/src/systems/DependencyGraphs.md

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Dependency Graphs
2+
3+
# Types
4+
```@docs
5+
BipartiteGraph
6+
```
7+
8+
# Utility functions for `BiPartiteGraph`s
9+
```@docs
10+
Base.isequal
11+
```
12+
13+
# Functions for calculating dependency graphs
14+
```@docs
15+
equation_dependencies
16+
asgraph
17+
variable_dependencies
18+
asdigraph
19+
eqeq_dependencies
20+
varvar_dependencies
21+
```

src/systems/dependency_graphs.jl

+213-19
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,46 @@
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+
"""
344
function 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
1556
end
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+
"""
1885
mutable 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,...]
2292
end
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+
"""
25126
function 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)
39140
end
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)
54170
end
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+
"""
57191
function 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)
77211
end
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+
"""
80238
function 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)
97255
end
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+
"""
100276
function 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
112288
end
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+
"""
115309
varvar_dependencies(eqdeps::BipartiteGraph{T}, vardeps::BipartiteGraph{T}) where {T <: Integer} = eqeq_dependencies(vardeps, eqdeps)

0 commit comments

Comments
 (0)