diff --git a/src/networkapi.jl b/src/networkapi.jl index c234481e0e..adf1a03b1a 100644 --- a/src/networkapi.jl +++ b/src/networkapi.jl @@ -1302,11 +1302,15 @@ end function hash(rx::Reaction, h::UInt) h = Base.hash(rx.rate, h) - h = Base.hash(rx.substrates, h) - h = Base.hash(rx.products, h) - h = Base.hash(rx.prodstoich, h) - h = Base.hash(rx.substoich, h) - h = Base.hash(rx.netstoich, h) + for s in Iterators.flatten((rx.substrates, rx.products)) + h ⊻= hash(s) + end + for s in Iterators.flatten((rx.substoich, rx.prodstoich)) + h ⊻= hash(s) + end + for s in rx.netstoich + h ⊻= hash(s) + end Base.hash(rx.only_use_rate, h) end diff --git a/src/reactionsystem.jl b/src/reactionsystem.jl index 0b4b37051e..77dd98710b 100644 --- a/src/reactionsystem.jl +++ b/src/reactionsystem.jl @@ -142,6 +142,8 @@ function Reaction(rate, subs, prods, substoich, prodstoich; else subs = value.(subs) end + allunique(subs) || + throw(ArgumentError("Substrates can not be repeated in the list provided to `Reaction`, please modify the stoichiometry for any repeated substrates instead.")) S = eltype(substoich) if isnothing(prods) @@ -152,6 +154,8 @@ function Reaction(rate, subs, prods, substoich, prodstoich; else prods = value.(prods) end + allunique(prods) || + throw(ArgumentError("Products can not be repeated in the list provided to `Reaction`, please modify the stoichiometry for any repeated products instead.")) T = eltype(prodstoich) # try to get a common type for stoichiometry, using Any if have Syms diff --git a/test/reactionsystem.jl b/test/reactionsystem.jl index 1d72f6033c..fe55f39132 100644 --- a/test/reactionsystem.jl +++ b/test/reactionsystem.jl @@ -676,3 +676,27 @@ let @test issetequal(parameters(osys), [k1, k2]) @test length(equations(osys)) == 3 end + +# test errors for repeated substrates or products +let + @variables t + @species A(t) B(t) + @test_throws ArgumentError Reaction(1.0, [A, A, B], [B]) + @test_throws ArgumentError Reaction(1.0, [B], [A, A]) + @test_throws ArgumentError Reaction(1.0, [A, A], [B, B]) +end + +# test order of species and products doesn't matter for equality or hashing +let + @variables t + @species A(t) α(t) + rx = Reaction(1.0, [α, A], [α, A], [2, 3], [4, 5]) + rx2 = Reaction(1.0, [A, α], [A, α], [3, 2], [5, 4]) + @test rx == rx2 + @test hash(rx) == hash(rx2) + + rx = Reaction(1.0, [α, A], [α, A], [2, 3], [4, 5]; netstoich = [α => 2, A => 2]) + rx2 = Reaction(1.0, [A, α], [A, α], [3, 2], [5, 4]; netstoich = [A => 2, α => 2]) + @test rx == rx2 + @test hash(rx) == hash(rx2) +end