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
+ os = convert(ODESystem, rs)
27
+
28
+ # dependency of each ODE on state variables
29
+ equation_dependencies(os)
30
+
31
+ # dependency of each ODE on parameters
32
+ equation_dependencies(os, variables=parameters(os))
33
+
34
+ # Jumps
35
+ js = convert(JumpSystem, rs)
36
+
37
+ # dependency of each jump rate function on state variables
38
+ equation_dependencies(js)
39
+
40
+ # dependency of each jump rate function on parameters
41
+ equation_dependencies(js, variables=parameters(js))
42
+ ```
43
+ """
3
44
function equation_dependencies (sys:: AbstractSystem ; variables= states (sys))
4
45
eqs = equations (sys)
5
46
deps = Set {Operation} ()
@@ -14,14 +55,67 @@ function equation_dependencies(sys::AbstractSystem; variables=states(sys))
14
55
depeqs_to_vars
15
56
end
16
57
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
+ """
18
85
mutable struct BipartiteGraph{T <: Integer }
86
+ """ Number of edges from source vertices to vertices they depend on."""
19
87
ne:: Int
88
+ """ Forward adjacency list mapping index of source vertices to the vertices they depend on."""
20
89
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."""
21
91
badjlist:: Vector{Vector{T}} # badjlist[dst] = [src1,src2,...]
22
92
end
23
93
24
- # convert equation-variable dependencies to a bipartite graph
94
+ function Base. isequal (bg1:: BipartiteGraph{T} , bg2:: BipartiteGraph{T} ) where {T<: Integer }
95
+ iseq = (bg1. ne == bg2. ne)
96
+ iseq &= (bg1. fadjlist == bg2. fadjlist)
97
+ iseq &= (bg1. badjlist == bg2. badjlist)
98
+ iseq
99
+ end
100
+
101
+ """
102
+ ```julia
103
+ asgraph(eqdeps, vtois)
104
+ ```
105
+
106
+ Convert a collection of equation dependencies, for example as returned by
107
+ `equation_dependencies`, to a `BipartiteGraph`.
108
+
109
+ Notes:
110
+ - `vtois` should provide `Dict` like mapping from variable dependency in `eqdeps`
111
+ to the integer idx of the variable to use in the graph.
112
+
113
+ Example:
114
+ Continuing the example started in [`equation_dependencies`](@ref)
115
+ ```julia
116
+ digr = asgraph(equation_dependencies(os), Dict(s => i for (i,s) in enumerate(states(os))))
117
+ ```
118
+ """
25
119
function asgraph (eqdeps, vtois)
26
120
fadjlist = Vector {Vector{Int}} (undef, length (eqdeps))
27
121
for (i,dep) in enumerate (eqdeps)
@@ -38,20 +132,41 @@ function asgraph(eqdeps, vtois)
38
132
BipartiteGraph (ne, fadjlist, badjlist)
39
133
end
40
134
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
47
135
48
136
# 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)
137
+ """
138
+ ```julia
139
+ asgraph(sys::AbstractSystem; variables=states(sys),
140
+ variablestoids=Dict(convert(Variable, v) => i for (i,v) in enumerate(variables)))
141
+ ```
142
+
143
+ Convert an `AbstractSystem` to a `BipartiteGraph` mapping equations
144
+ to variables they depend on.
145
+
146
+ Notes:
147
+ - Defaults for kwargs creating a mapping from `equations(sys)` to `states(sys)`
148
+ they depend on.
149
+ - `variables` should provide the list of variables to use for generating
150
+ the dependency graph.
151
+ - `variablestoids` should provide `Dict` like mapping from a variable to its
152
+ integer index within `variables`.
153
+
154
+ Example:
155
+ Continuing the example started in [`equation_dependencies`](@ref)
156
+ ```julia
157
+ digr = asgraph(os)
158
+ ```
159
+ """
160
+ function asgraph (sys:: AbstractSystem ; variables= states (sys),
161
+ variablestoids= Dict (convert (Variable, v) => i for (i,v) in enumerate (variables)))
162
+ asgraph (equation_dependencies (sys, variables= variables), variablestoids)
54
163
end
164
+ # function asgraph(sys::AbstractSystem; variables=nothing, variablestoids=nothing)
165
+ # vs = isnothing(variables) ? states(sys) : variables
166
+ # eqdeps = equation_dependencies(sys, variables=vs)
167
+ # vtois = isnothing(variablestoids) ? Dict(convert(Variable, v) => i for (i,v) in enumerate(vs)) : variablestoids
168
+ # asgraph(eqdeps, vtois)
169
+ # end
55
170
56
171
# for each variable determine the equations that modify it
57
172
function variable_dependencies (sys:: AbstractSystem ; variables= states (sys), variablestoids= nothing )
@@ -76,6 +191,12 @@ function variable_dependencies(sys::AbstractSystem; variables=states(sys), varia
76
191
BipartiteGraph (ne, fadjlist, badjlist)
77
192
end
78
193
194
+ """
195
+ - The resulting `SimpleDiGraph` unifies the two sets of vertices (equations
196
+ and then states in the case `eqdeps` comes from `equation_dependencies`), producing
197
+ one ordered set of integer vertices (as `SimpleDiGraph` does not support two distinct
198
+ collections of nodes.
199
+ """
79
200
# convert BipartiteGraph to LightGraph.SimpleDiGraph
80
201
function asdigraph (g:: BipartiteGraph , sys:: AbstractSystem ; variables = states (sys), equationsfirst = true )
81
202
neqs = length (equations (sys))
0 commit comments