Skip to content

Commit 5b3c702

Browse files
authored
Merge pull request #117 from isaacsas/better-ismassaction-test
Better ismassaction test and == test for networks
2 parents c843e48 + 86aea75 commit 5b3c702

File tree

3 files changed

+97
-27
lines changed

3 files changed

+97
-27
lines changed

src/DiffEqBiological.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ using Parameters
1212
@reexport using DiffEqBase, DiffEqJump
1313
using Compat
1414

15+
import Base: (==)
16+
1517
const ExprValues = Union{Expr,Symbol,Float64,Int}
1618

1719
include("reaction_network.jl")

src/maketype.jl

Lines changed: 54 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,35 @@ function gentypefun_exprs(name; esc_exprs=true, gen_inplace=true, gen_outofplace
133133
exprs
134134
end
135135

136+
######################## reaction network operators #######################
137+
138+
# note, this is allocating, and could potentially be made more efficient by iterating
139+
# through reaction components directly...
140+
"""
141+
==(rn1::DiffEqBase.AbstractReactionNetwork, rn2::DiffEqBase.AbstractReactionNetwork)
142+
143+
Tests whether the underlying species symbols, parameter symbols and reactions
144+
are the same in the two networks. Ignores order network components were defined,
145+
so the integer id of any individual species/parameters/reactions may be
146+
different between the two networks. *Does not* currently account for different
147+
reaction definitions, so "k, X+Y --> Y + Z" will not be the same as "k, Y+X -->
148+
Y + Z"
149+
"""
150+
function (==)(rn1::DiffEqBase.AbstractReactionNetwork, rn2::DiffEqBase.AbstractReactionNetwork)
151+
issetequal(species(rn1), species(rn2)) || return false
152+
issetequal(params(rn1), params(rn2)) || return false
153+
nr1 = numreactions(rn1)
154+
nr2 = numreactions(rn2)
155+
(nr1 == nr2) || return false
156+
idx1 = 1:nr1
157+
idx2 = 1:nr2
158+
issetequal(substrates.(rn1, idx1), substrates.(rn2, idx2)) || return false
159+
issetequal(products.(rn1, idx1), products.(rn2, idx2)) || return false
160+
issetequal(dependants.(rn1, idx1), dependants.(rn2, idx2)) || return false
161+
issetequal(rateexpr.(rn1, idx1), rateexpr.(rn2, idx2)) || return false
162+
issetequal(ismassaction.(rn1, idx1), ismassaction.(rn2, idx2)) || return false
163+
end
164+
136165
######################## functions to extend a network ####################
137166

138167
"""
@@ -209,88 +238,88 @@ the noise scaling coefficient.
209238
add_scale_noise_param!(rn::DiffEqBase.AbstractReactionNetwork, scale_noise_name::String) = add_scale_noise_param!(rn, Symbol(scale_noise_name))
210239

211240
"""
212-
addreaction!(network, rateexpr::Union{Expr,Symbol,Int,Float64}, rxexpr::Expr)
241+
addreaction!(network, rateex::Union{Expr,Symbol,Int,Float64}, rxexpr::Expr)
213242
214243
Given an AbstractReaction network, add a reaction with the passed in rate and
215244
reaction expressions. i.e. a reaction of the form
216245
```julia
217246
k*X, 2X + Y --> 2W
218247
```
219-
would have `rateexpr=:(k*X)` and `rxexpr=:(2X + Y --> W)`,
248+
would have `rateex=:(k*X)` and `rxexpr=:(2X + Y --> W)`,
220249
```julia
221250
10.5, 0 --> X
222251
```
223-
would have `rateexpr=10.5` and `rxexpr=:(0 --> X)`, and
252+
would have `rateex=10.5` and `rxexpr=:(0 --> X)`, and
224253
```julia
225254
k, X+X --> Z
226255
```
227-
would have `rateexpr=:k` and `rxexpr=:(X+X --> Z)`.
256+
would have `rateex=:k` and `rxexpr=:(X+X --> Z)`.
228257
229258
All normal DSL reaction definition notation should be supported.
230259
"""
231-
function addreaction!(rn::DiffEqBase.AbstractReactionNetwork, rateexpr::ExprValues, rxexpr::Expr)
232-
ex = Expr(:block, :(($rateexpr, $rxexpr)))
260+
function addreaction!(rn::DiffEqBase.AbstractReactionNetwork, rateex::ExprValues, rxexpr::Expr)
261+
ex = Expr(:block, :(($rateex, $rxexpr)))
233262
newrxs = get_reactions(ex)
234263
foreach(rx -> push!(rn.reactions,ReactionStruct(rx, species(rn))), newrxs)
235264
nothing
236265
end
237266

238267
"""
239-
addreaction!(network, rateexpr::Union{Expr,Symbol,Int,Float64}, substrates, products)
268+
addreaction!(network, rateex::Union{Expr,Symbol,Int,Float64}, substrates, products)
240269
241270
Given an AbstractReaction network, add a reaction with the passed in rate,
242-
`rateexpr`, substrate stoichiometry, and product stoichiometry. Stoichiometries
271+
`rateex`, substrate stoichiometry, and product stoichiometry. Stoichiometries
243272
are represented as tuples of `Pair{Symbol,Int}`. i.e. a reaction of the form
244273
```julia
245274
k*X, 2X + Y --> 2W
246275
```
247-
would have `rateexpr=:(k*X)`, `substrates=(:X=>2, :Y=>2)`` and
276+
would have `rateex=:(k*X)`, `substrates=(:X=>2, :Y=>2)`` and
248277
`products=(W=>2,)`,
249278
```julia
250279
10.5, 0 --> X
251280
```
252-
would have `rateexpr=10.5`, `substrates=()` and `products=(:X=>1,)`, and
281+
would have `rateex=10.5`, `substrates=()` and `products=(:X=>1,)`, and
253282
```julia
254283
k, X+X --> Z
255284
```
256-
would have `rateexpr=:k`, `substrates=(:X=>2,)` and `products=(:Z=>2,)`.
285+
would have `rateex=:k`, `substrates=(:X=>2,)` and `products=(:Z=>2,)`.
257286
258287
All normal DSL reaction definition notation should be supported for the
259-
`rateexpr`.
288+
`rateex`.
260289
"""
261-
function addreaction!(rn::DiffEqBase.AbstractReactionNetwork, rateexpr::ExprValues,
290+
function addreaction!(rn::DiffEqBase.AbstractReactionNetwork, rateex::ExprValues,
262291
subs::Tuple{Vararg{Pair{Symbol,Int}}},
263292
prods::Tuple{Vararg{Pair{Symbol,Int}}}) where {T <: Number}
264293

265294
substrates = ReactantStruct[ReactantStruct(p[1],p[2]) for p in subs]
266295
dependents = Symbol[p[1] for p in subs]
267296
products = ReactantStruct[ReactantStruct(p[1],p[2]) for p in prods]
268-
rate_DE = mass_rate_DE(substrates, true, rateexpr)
269-
rate_SSA = mass_rate_SSA(substrates, true, rateexpr)
297+
rate_DE = mass_rate_DE(substrates, true, rateex)
298+
rate_SSA = mass_rate_SSA(substrates, true, rateex)
270299

271-
# resolve dependents from rateexpr
272-
if rateexpr isa Number
300+
# resolve dependents from rateex
301+
if rateex isa Number
273302
ismassaction = true
274-
elseif rateexpr isa Symbol
275-
if haskey(speciesmap(rn), rateexpr)
303+
elseif rateex isa Symbol
304+
if haskey(speciesmap(rn), rateex)
276305
ismassaction = false
277-
if rateexpr dependents
278-
push!(dependents, rateexpr)
306+
if rateex dependents
307+
push!(dependents, rateex)
279308
end
280-
elseif haskey(paramsmap(rn), rateexpr)
309+
elseif haskey(paramsmap(rn), rateex)
281310
ismassaction = true
282311
else
283-
error("rateexpr is a symbol that is neither a species or parameter.")
312+
error("rateex is a symbol that is neither a species or parameter.")
284313
end
285314
else # isa Expr
286315

287316
# mimicing ReactionStruct constructor for now, but this should be optimized...
288317
newdeps = unique!(recursive_content(rate_DE, speciesmap(rn), Vector{Symbol}()))
289-
ismassaction = length(newdeps)==length(intersect!(dependents, newdeps)) ? true : false
318+
ismassaction = issetequal(dependents,newdeps)
290319
dependents = newdeps
291320
end
292321

293-
push!(rn.reactions, ReactionStruct(substrates, products, rateexpr, rate_DE, rate_SSA, dependents, ismassaction))
322+
push!(rn.reactions, ReactionStruct(substrates, products, rateex, rate_DE, rate_SSA, dependents, ismassaction))
294323
nothing
295324
end
296325

src/network_properties.jl

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -313,11 +313,25 @@ end
313313
Given an `AbstractReactionNetwork` and a reaction index, `rxidx`, return a
314314
vector of pairs, mapping ids of species that serve as substrates in the reaction
315315
to the corresponding stoichiometric coefficient as a substrate.
316+
317+
Allocates a new vector to store the pairs.
316318
"""
317319
function substratestoich(rn::DiffEqBase.AbstractReactionNetwork, rxidx)
318320
substratestoich(rn.reactions[rxidx], speciesmap(rn))
319321
end
320322

323+
"""
324+
substratesymstoich(network, rxidx)
325+
326+
Given an `AbstractReactionNetwork` and a reaction index, `rxidx`, return a
327+
`ReactantStruct`, mapping the symbols of species that serve as substrates in the
328+
reaction to the corresponding stoichiometric coefficient as a substrate.
329+
330+
Non-allocating, returns underlying field within the reaction_network.
331+
"""
332+
function substratesymstoich(rn::DiffEqBase.AbstractReactionNetwork, rxidx)
333+
rn.reactions[rxidx].substrates
334+
end
321335

322336
function productstoich(rs::ReactionStruct, specmap)
323337
sort( [specmap[p.reactant] => p.stoichiometry for p in rs.products] )
@@ -329,11 +343,26 @@ end
329343
Given an `AbstractReactionNetwork` and a reaction index, `rxidx`, return a
330344
vector of pairs, mapping ids of species that are products in the reaction to the
331345
corresponding stoichiometric coefficient as a product.
346+
347+
Allocates a new vector to store the pairs.
332348
"""
333349
function productstoich(rn::DiffEqBase.AbstractReactionNetwork, rxidx)
334350
productstoich(rn.reactions[rxidx], speciesmap(rn))
335351
end
336352

353+
"""
354+
productsymstoich(network, rxidx)
355+
356+
Given an `AbstractReactionNetwork` and a reaction index, `rxidx`, return a
357+
`ReactantStruct`, mapping the symbols of species that are products in the
358+
reaction to the corresponding stoichiometric coefficient as a product.
359+
360+
Non-allocating, returns underlying field within the reaction_network.
361+
"""
362+
function productsymstoich(rn::DiffEqBase.AbstractReactionNetwork, rxidx)
363+
rn.reactions[rxidx].products
364+
end
365+
337366
function netstoich(rs::ReactionStruct, specmap)
338367
nsdict = Dict{Int,Int}(specmap[s.reactant] => -s.stoichiometry for s in rs.substrates)
339368

@@ -357,6 +386,8 @@ Given an `AbstractReactionNetwork` and a reaction index, `rxidx`, return a
357386
vector of pairs, mapping ids of species that participate in the reaction to the
358387
net stoichiometric coefficient of the species (i.e. net change in the species
359388
due to the reaction).
389+
390+
Allocates a new vector to store the pairs.
360391
"""
361392
function netstoich(rn::DiffEqBase.AbstractReactionNetwork, rxidx)
362393
netstoich(rn.reactions[rxidx], speciesmap(rn))
@@ -376,6 +407,8 @@ would return true, while reactions with state-dependent rates like
376407
`k*X, X + Y --> Z`
377408
378409
would return false.
410+
411+
Non-allocating, returns underlying field within the reaction_network.
379412
"""
380413
function ismassaction(rn::DiffEqBase.AbstractReactionNetwork, rxidx)
381414
rn.reactions[rxidx].is_pure_mass_action
@@ -391,6 +424,8 @@ vector of symbols of species the *reaction rate law* depends on. i.e. for
391424
`k*W, 2X + 3Y --> 5Z + W`
392425
393426
the returned vector would be `[:W,:X,:Y]`.
427+
428+
Non-allocating, returns underlying field within the reaction_network.
394429
"""
395430
function dependents(rn::DiffEqBase.AbstractReactionNetwork, rxidx)
396431
rn.reactions[rxidx].dependants
@@ -415,9 +450,11 @@ i.e. for
415450
`k*W, X + 3Y --> X + W`
416451
417452
the returned vector would be `[:X,:Y]`.
453+
454+
Allocates a new vector to store the symbols.
418455
"""
419456
function substrates(rn::DiffEqBase.AbstractReactionNetwork, rxidx)
420-
rn.reactions[rxidx].substrates
457+
[sub.reactant for sub in rn.reactions[rxidx].substrates]
421458
end
422459

423460
"""
@@ -430,9 +467,11 @@ i.e. for
430467
`k*W, X + 3Y --> X + W`
431468
432469
the returned vector would be `[:X,:W]`.
470+
471+
Allocates a new vector to store the symbols.
433472
"""
434473
function products(rn::DiffEqBase.AbstractReactionNetwork, rxidx)
435-
rn.reactions[rxidx].products
474+
[prod.reactant for prod in rn.reactions[rxidx].products]
436475
end
437476

438477
######### Network Properties: #########

0 commit comments

Comments
 (0)