Skip to content

Commit fcd819a

Browse files
committed
use Vector{Pair{Symbol,R}} as metadata in Reactions
1 parent 80e34ae commit fcd819a

File tree

6 files changed

+49
-32
lines changed

6 files changed

+49
-32
lines changed

docs/src/api/catalyst_api.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ substoichmat
178178
prodstoichmat
179179
netstoichmat
180180
reactionrates
181-
get_metadata_dict
181+
get_metadata_vec
182182
has_metadata
183183
get_metadata
184184
```

src/Catalyst.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ export mm, mmr, hill, hillr, hillar
8080
include("networkapi.jl")
8181
export species, nonspecies, reactionparams, reactions, speciesmap, paramsmap
8282
export numspecies, numreactions, numreactionparams, setdefaults!, symmap_to_varmap
83-
export get_metadata_dict, has_metadata, get_metadata
83+
export get_metadata_vec, has_metadata, get_metadata
8484
export make_empty_network, addspecies!, addparam!, addreaction!, reactionparamsmap
8585
export dependants, dependents, substoichmat, prodstoichmat, netstoichmat
8686
export conservationlaws, conservedquantities, conservedequations, conservationlaw_constants

src/reaction_network.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -567,7 +567,7 @@ function get_rxexprs(rxstruct)
567567
prod_stoich_init = deepcopy(prod_init)
568568
reaction_func = :(Reaction($(recursive_expand_functions!(rxstruct.rate)), $subs_init,
569569
$prod_init, $subs_stoich_init, $prod_stoich_init,
570-
metadata = Dict($(rxstruct.metadata)),))
570+
metadata = $(rxstruct.metadata),))
571571
for sub in rxstruct.substrates
572572
push!(reaction_func.args[3].args, sub.reactant)
573573
push!(reaction_func.args[5].args, sub.stoichiometry)

src/reactionsystem.jl

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ struct Reaction{R, S, T}
120120
Contain additional data, such whenever the reaction have a specific noise-scaling expression for
121121
the chemical Langevin equation.
122122
"""
123-
metadata::Dict{Symbol, R}
123+
metadata::Vector{Pair{Symbol, R}}
124124
end
125125

126126
"""
@@ -131,9 +131,8 @@ Test if a species is valid as a reactant (i.e. a species variable or a constant
131131
isvalidreactant(s) = MT.isparameter(s) ? isconstant(s) : (isspecies(s) && !isconstant(s))
132132

133133
function Reaction(rate, subs, prods, substoich, prodstoich;
134-
netstoich = nothing, metadata = Dict{Symbol,Any}(),
135-
only_use_rate = (haskey(metadata, :only_use_rate) && Bool(metadata[:only_use_rate])),
136-
kwargs...)
134+
netstoich = nothing, metadata = Pair{Symbol, Any}[],
135+
only_use_rate = metadata_only_use_rate_check(metadata), kwargs...)
137136
(isnothing(prods) && isnothing(subs)) &&
138137
throw(ArgumentError("A reaction requires a non-nothing substrate or product vector."))
139138
(isnothing(prodstoich) && isnothing(substoich)) &&
@@ -187,11 +186,25 @@ function Reaction(rate, subs, prods, substoich, prodstoich;
187186
convert.(stoich_type, netstoich) : netstoich
188187
end
189188

190-
haskey(metadata, :only_use_rate) && delete!(metadata, :only_use_rate)
189+
# Check that all metadata entries are unique.
190+
if length(unique(entry[1] for entry in metadata)) < length(metadata)
191+
error("Repeated entries for the same metadata encountered in the following metadata set: $([entry[1] for entry in metadata]).")
192+
end
193+
194+
# Deletes potential `:only_use_rate => ` entries from the metadata.
195+
if any(:only_use_rate == entry[1] for entry in metadata)
196+
findfirst(:only_use_rate == entry[1] for entry in metadata)
197+
end
191198

192199
Reaction(value(rate), subs, prods, substoich′, prodstoich′, ns, only_use_rate, metadata)
193200
end
194201

202+
# Checks if a metadata input has an entry :only_use_rate => true
203+
function metadata_only_use_rate_check(metadata)
204+
any(:only_use_rate == entry[1] for entry in metadata) || (return false)
205+
return metadata[findfirst(:only_use_rate == entry[1] for entry in metadata)]
206+
end
207+
195208
# three argument constructor assumes stoichiometric coefs are one and integers
196209
function Reaction(rate, subs, prods; kwargs...)
197210
sstoich = isnothing(subs) ? nothing : ones(Int, length(subs))
@@ -841,7 +854,7 @@ end
841854
######################## Other accessors ##############################
842855

843856
"""
844-
get_metadata_dict(reaction::Reaction)
857+
get_metadata_vec(reaction::Reaction)
845858
846859
Retrives the `ImmutableDict` containing all of the metadata associated with a specific reaction.
847860
@@ -851,10 +864,10 @@ Arguments:
851864
Example:
852865
```julia
853866
reaction = @reaction k, 0 --> X, [noise_scaling=0.0]
854-
get_metadata_dict(reaction)
867+
get_metadata_vec(reaction)
855868
```
856869
"""
857-
function get_metadata_dict(reaction::Reaction)
870+
function get_metadata_vec(reaction::Reaction)
858871
return reaction.metadata
859872
end
860873

@@ -874,7 +887,7 @@ has_metadata(reaction, :noise_scaling)
874887
```
875888
"""
876889
function has_metadata(reaction::Reaction, md_key::Symbol)
877-
return haskey(get_metadata_dict(reaction), md_key)
890+
return any(isequal(md_key, entry[1]) for entry in get_metadata_vec(reaction))
878891
end
879892

880893
"""
@@ -894,9 +907,9 @@ get_metadata(reaction, :noise_scaling)
894907
"""
895908
function get_metadata(reaction::Reaction, md_key::Symbol)
896909
if !has_metadata(reaction, md_key)
897-
error("The reaction does not have a metadata field $md_key. It does have the following metadata fields: $(keys(get_metadata_dict(reaction))).")
910+
error("The reaction does not have a metadata field $md_key. It does have the following metadata fields: $(keys(get_metadata_vec(reaction))).")
898911
end
899-
return get_metadata_dict(reaction)[md_key]
912+
return get_metadata_vec(reaction)[findfirst(isequal(md_key, entry[1]) for entry in get_metadata_vec(reaction))][2]
900913
end
901914

902915
######################## Conversion to ODEs/SDEs/jump, etc ##############################

test/dsl/dsl_basics.jl

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -143,14 +143,14 @@ let
143143
@parameters k η
144144
@species X(t) X2(t)
145145

146-
metadata1 = Dict(:noise_scaling => η)
146+
metadata1 = [:noise_scaling => η]
147147
r1 = Reaction(k, [X], [X2], [2], [1]; metadata=metadata1)
148148

149-
metadata2 = Dict(:md_1 => 1.0, :md_2 => false, :md_3 => "Hello world", :md_4 => :sym,
150-
:md_5 => X + X2^k -1, :md_6 => (0.1, 2.0))
149+
metadata2 = [:md_1 => 1.0, :md_2 => false, :md_3 => "Hello world", :md_4 => :sym,
150+
:md_5 => X + X2^k -1, :md_6 => (0.1, 2.0)]
151151
r2 = Reaction(k, [X], [X2], [2], [1]; metadata=metadata2)
152152

153-
metadata3 = Dict{Symbol,Any}()
153+
metadata3 = Pair{Symbol,Any}[]
154154
r3 = Reaction(k, [X], [X2], [2], [1]; metadata=metadata3)
155155

156156
# Creates reactions using DSL.
@@ -164,9 +164,9 @@ let
164164
# Checks DSL reactions are correct.
165165
rxs = reactions(rs)
166166
@test isequal([r1, r2, r3], rxs)
167-
@test isequal(get_metadata_dict(r1), get_metadata_dict(rxs[1]))
168-
@test isequal(get_metadata_dict(r2), get_metadata_dict(rxs[2]))
169-
@test isequal(get_metadata_dict(r3), get_metadata_dict(rxs[3]))
167+
@test isequal(get_metadata_vec(r1), get_metadata_vec(rxs[1]))
168+
@test isequal(get_metadata_vec(r2), get_metadata_vec(rxs[2]))
169+
@test isequal(get_metadata_vec(r3), get_metadata_vec(rxs[3]))
170170

171171
# Checks that accessor functions works on the DSL.
172172
@test has_metadata(rxs[1], :noise_scaling)
@@ -185,9 +185,9 @@ let
185185
rx3 = @reaction k, 2X --> X2
186186

187187
@test isequal([rx1, rx2, rx3], rxs)
188-
@test isequal(get_metadata_dict(rx1), get_metadata_dict(rxs[1]))
189-
@test isequal(get_metadata_dict(rx2), get_metadata_dict(rxs[2]))
190-
@test isequal(get_metadata_dict(rx3), get_metadata_dict(rxs[3]))
188+
@test isequal(get_metadata_vec(rx1), get_metadata_vec(rxs[1]))
189+
@test isequal(get_metadata_vec(rx2), get_metadata_vec(rxs[2]))
190+
@test isequal(get_metadata_vec(rx3), get_metadata_vec(rxs[3]))
191191
end
192192

193193
# Checks that repeated metadata throws errors.

test/reactionsystem_structure/reactions.jl

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,22 @@ using Catalyst, Test
77

88
# Tests creation.
99
# Tests basic accessor functions.
10+
# Tests that repeated metadata entries are not permitted.
1011
let
1112
@variables t
1213
@parameters k
1314
@species X(t) X2(t)
1415

15-
metadata = Dict(:noise_scaling => 0.0)
16+
metadata = [:noise_scaling => 0.0]
1617
r = Reaction(k, [X], [X2], [2], [1]; metadata=metadata)
1718

18-
@test get_metadata_dict(r) == Dict(:noise_scaling => 0.0)
19+
@test get_metadata_vec(r) == [:noise_scaling => 0.0]
1920
@test has_metadata(r, :noise_scaling)
2021
@test !has_metadata(r, :nonexisting_metadata)
2122
@test get_metadata(r, :noise_scaling) == 0.0
23+
24+
metadata_repeated = [:noise_scaling => 0.0, :noise_scaling => 1.0, :metadata_entry => "unused"]
25+
@test_throws Exception Reaction(k, [X], [X2], [2], [1]; metadata=metadata_repeated)
2226
end
2327

2428
# Tests accessors for system without metadata.
@@ -27,12 +31,12 @@ let
2731
@parameters k
2832
@species X(t) X2(t)
2933

30-
metadata = Dict{Symbol,Any}()
34+
metadata = Pair{Symbol,Any}[]
3135
r1 = Reaction(k, [X], [X2], [2], [1])
3236
r2 = Reaction(k, [X], [X2], [2], [1]; metadata=metadata)
3337

3438
@test isequal(r1, r2)
35-
@test get_metadata_dict(r1) == Dict()
39+
@test get_metadata_vec(r1) == Pair{Symbol,Any}[]
3640
@test !has_metadata(r1, :md)
3741
end
3842

@@ -44,12 +48,12 @@ let
4448
@parameters k
4549
@species X(t) X2(t)
4650

47-
metadata = Dict(:md_1 => 1.0, :md_2 => false, :md_3 => "Hello world", :md_4 => :sym,
48-
:md_5 => X + X2^k -1, :md_6 => (0.1, 2.0))
51+
metadata = [:md_1 => 1.0, :md_2 => false, :md_3 => "Hello world", :md_4 => :sym,
52+
:md_5 => X + X2^k -1, :md_6 => (0.1, 2.0)]
4953
r = Reaction(k, [X], [X2], [2], [1]; metadata=metadata)
5054

51-
@test isequal(get_metadata_dict(r), Dict(:md_1 => 1.0, :md_2 => false, :md_3 => "Hello world",
52-
:md_4 => :sym, :md_5 => X + X2^k -1, :md_6 => (0.1, 2.0)))
55+
@test isequal(get_metadata_vec(r), [:md_1 => 1.0, :md_2 => false, :md_3 => "Hello world",
56+
:md_4 => :sym, :md_5 => X + X2^k -1, :md_6 => (0.1, 2.0)])
5357
@test has_metadata(r, :md_1)
5458
@test has_metadata(r, :md_2)
5559
@test has_metadata(r, :md_3)

0 commit comments

Comments
 (0)