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+ """
344function equation_dependencies (sys:: AbstractSystem ; variables= states (sys))
445 eqs = equations (sys)
546 deps = Set {Operation} ()
@@ -14,14 +55,67 @@ 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+ 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+ """
25119function asgraph (eqdeps, vtois)
26120 fadjlist = Vector {Vector{Int}} (undef, length (eqdeps))
27121 for (i,dep) in enumerate (eqdeps)
@@ -38,20 +132,41 @@ function asgraph(eqdeps, vtois)
38132 BipartiteGraph (ne, fadjlist, badjlist)
39133end
40134
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
47135
48136# 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)
54163end
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
55170
56171# for each variable determine the equations that modify it
57172function variable_dependencies (sys:: AbstractSystem ; variables= states (sys), variablestoids= nothing )
@@ -76,6 +191,12 @@ function variable_dependencies(sys::AbstractSystem; variables=states(sys), varia
76191 BipartiteGraph (ne, fadjlist, badjlist)
77192end
78193
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+ """
79200# convert BipartiteGraph to LightGraph.SimpleDiGraph
80201function asdigraph (g:: BipartiteGraph , sys:: AbstractSystem ; variables = states (sys), equationsfirst = true )
81202 neqs = length (equations (sys))
0 commit comments