From f2657a162d54839e023999858d44a673d440ae4e Mon Sep 17 00:00:00 2001 From: Sam Isaacson Date: Fri, 16 Aug 2024 11:28:17 -0400 Subject: [PATCH 1/8] metadata as dispatch from SymbolicUtils --- Project.toml | 2 + src/Catalyst.jl | 1 + src/reaction.jl | 36 +++++++++++++--- test/dsl/dsl_advanced_model_construction.jl | 28 ++++++------ test/reactionsystem_core/reaction.jl | 48 +++++++++++---------- 5 files changed, 72 insertions(+), 43 deletions(-) diff --git a/Project.toml b/Project.toml index 5d9e1ae58d..66cddb75ea 100644 --- a/Project.toml +++ b/Project.toml @@ -23,6 +23,7 @@ RuntimeGeneratedFunctions = "7e49a35a-f44a-4d26-94aa-eba1b4ca6b47" SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" Setfield = "efcf1570-3423-57d1-acb7-fd33fddbac46" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" +SymbolicUtils = "d1185830-fcd6-423d-90d6-eec64667417b" Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7" Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d" @@ -65,6 +66,7 @@ SciMLBase = "2.46" Setfield = "1" StructuralIdentifiability = "0.5.8" Symbolics = "5.30.1" +SymbolicUtils = "2.1.2" Unitful = "1.12.4" julia = "1.10" diff --git a/src/Catalyst.jl b/src/Catalyst.jl index 242323a0e2..2c5c6003a2 100644 --- a/src/Catalyst.jl +++ b/src/Catalyst.jl @@ -45,6 +45,7 @@ import DataStructures: OrderedDict, OrderedSet import Parameters: @with_kw_noshow import Symbolics: occursin, wrap import Symbolics.RewriteHelpers: hasnode, replacenode +import SymbolicUtils: getmetadata, hasmetadata, setmetadata # globals for the modulate function default_time_deriv() diff --git a/src/reaction.jl b/src/reaction.jl index 8f85d77343..f4208f06dd 100644 --- a/src/reaction.jl +++ b/src/reaction.jl @@ -461,9 +461,10 @@ function getmetadata_dict(reaction::Reaction) end """ -hasmetadata(reaction::Reaction, md_key::Symbol) + SymbolicUtils.hasmetadata(reaction::Reaction, md_key::Symbol) -Checks if a `Reaction` have a certain metadata field. If it does, returns `true` (else returns `false`). +Checks if a `Reaction` have a certain metadata field. If it does, returns `true` (else +returns `false`). Arguments: - `reaction`: The reaction for which we wish to check if a specific metadata field exist. @@ -475,14 +476,15 @@ reaction = @reaction k, 0 --> X, [description="Production reaction"] hasmetadata(reaction, :description) ``` """ -function hasmetadata(reaction::Reaction, md_key::Symbol) +function SymbolicUtils.hasmetadata(reaction::Reaction, md_key::Symbol) return any(isequal(md_key, entry[1]) for entry in getmetadata_dict(reaction)) end """ -getmetadata(reaction::Reaction, md_key::Symbol) + SymbolicUtils.getmetadata(reaction::Reaction, md_key::Symbol) -Retrieves a certain metadata value from a `Reaction`. If the metadata does not exist, throws an error. +Retrieves a certain metadata value from a `Reaction`. If the metadata does not exist, throws +an error. Arguments: - `reaction`: The reaction for which we wish to retrieve a specific metadata value. @@ -494,7 +496,7 @@ reaction = @reaction k, 0 --> X, [description="Production reaction"] getmetadata(reaction, :description) ``` """ -function getmetadata(reaction::Reaction, md_key::Symbol) +function SymbolicUtils.getmetadata(reaction::Reaction, md_key::Symbol) metadata = getmetadata_dict(reaction) idx = findfirst(isequal(md_key, entry[1]) for entry in metadata) (idx === nothing) && @@ -502,7 +504,27 @@ function getmetadata(reaction::Reaction, md_key::Symbol) return metadata[idx][2] end -### Implemented Reaction Metadata ### +""" + SymbolicUtils.setmetadata(rx::Reaction, key::Symbol, val) + +Sets the metadata with key `key` to the value `val`, overwriting if already present or +adding if not present. + +Arguments: +- `rx`: The reaction to add the metadata too. +- `key`: `Symbol` representing the metadata's key (i.e. name). +- `val`: value for the metadata. +""" +function SymbolicUtils.setmetadata(rx::Reaction, key::Symbol, val) + mdvec = getmetadata_dict(rx) + idx = findfirst(isequal(key, first(md)) for md in mdvec) + if idx === nothing + push!(mdvec, key => val) + else + mdvec[idx] = key => val + end + nothing +end # Noise scaling. """ diff --git a/test/dsl/dsl_advanced_model_construction.jl b/test/dsl/dsl_advanced_model_construction.jl index 5638c9173c..b988adcb95 100644 --- a/test/dsl/dsl_advanced_model_construction.jl +++ b/test/dsl/dsl_advanced_model_construction.jl @@ -184,20 +184,20 @@ let # Checks DSL reactions are correct. rxs = reactions(rs) @test isequal([r1, r2, r3], rxs) - @test isequal(Catalyst.getmetadata_dict(r1), Catalyst.getmetadata_dict(rxs[1])) - @test isequal(Catalyst.getmetadata_dict(r2), Catalyst.getmetadata_dict(rxs[2])) - @test isequal(Catalyst.getmetadata_dict(r3), Catalyst.getmetadata_dict(rxs[3])) + @test isequal(getmetadata_dict(r1), getmetadata_dict(rxs[1])) + @test isequal(getmetadata_dict(r2), getmetadata_dict(rxs[2])) + @test isequal(getmetadata_dict(r3), getmetadata_dict(rxs[3])) # Checks that accessor functions works on the DSL. - @test Catalyst.hasmetadata(rxs[1], :noise_scaling) - @test !Catalyst.hasmetadata(rxs[1], :md_1) - @test !Catalyst.hasmetadata(rxs[2], :noise_scaling) - @test Catalyst.hasmetadata(rxs[2], :md_1) - @test !Catalyst.hasmetadata(rxs[3], :noise_scaling) - @test !Catalyst.hasmetadata(rxs[3], :md_1) + @test getmetadata(rxs[1], :noise_scaling) + @test !getmetadata(rxs[1], :md_1) + @test !getmetadata(rxs[2], :noise_scaling) + @test getmetadata(rxs[2], :md_1) + @test !getmetadata(rxs[3], :noise_scaling) + @test !getmetadata(rxs[3], :md_1) - @test isequal(Catalyst.getmetadata(rxs[1], :noise_scaling), η) - @test isequal(Catalyst.getmetadata(rxs[2], :md_1), 1.0) + @test isequal(getmetadata(rxs[1], :noise_scaling), η) + @test isequal(getmetadata(rxs[2], :md_1), 1.0) # Test that metadata works for @reaction macro. rx1 = @reaction k, 2X --> X2, [noise_scaling=$η] @@ -205,9 +205,9 @@ let rx3 = @reaction k, 2X --> X2 @test isequal([rx1, rx2, rx3], rxs) - @test isequal(Catalyst.getmetadata_dict(rx1), Catalyst.getmetadata_dict(rxs[1])) - @test isequal(Catalyst.getmetadata_dict(rx2), Catalyst.getmetadata_dict(rxs[2])) - @test isequal(Catalyst.getmetadata_dict(rx3), Catalyst.getmetadata_dict(rxs[3])) + @test isequal(getmetadata_dict(rx1), getmetadata_dict(rxs[1])) + @test isequal(getmetadata_dict(rx2), getmetadata_dict(rxs[2])) + @test isequal(getmetadata_dict(rx3), getmetadata_dict(rxs[3])) end # Checks that repeated metadata throws errors. diff --git a/test/reactionsystem_core/reaction.jl b/test/reactionsystem_core/reaction.jl index 36d5d946d0..ac5bfc58c6 100644 --- a/test/reactionsystem_core/reaction.jl +++ b/test/reactionsystem_core/reaction.jl @@ -132,11 +132,15 @@ let metadata = [:noise_scaling => 0.0] r = Reaction(k, [X], [X2], [2], [1]; metadata=metadata) - @test Catalyst.getmetadata_dict(r) == [:noise_scaling => 0.0] - @test Catalyst.hasmetadata(r, :noise_scaling) - @test !Catalyst.hasmetadata(r, :nonexisting_metadata) - @test Catalyst.getmetadata(r, :noise_scaling) == 0.0 - @test_throws Exception Catalyst.getmetadata(r, :misc) + @test getmetadata_dict(r) == [:noise_scaling => 0.0] + @test getmetadata(r, :noise_scaling) + @test !getmetadata(r, :nonexisting_metadata) + @test getmetadata(r, :noise_scaling) == 0.0 + @test_throws Exception getmetadata(r, :misc) + setmetadata(r, :test_metadata, 1234) + @test getmetadata(r, :test_metadata) == 1234 + setmetadata(r, :test_metadata, 1111) + @test getmetadata(r, :test_metadata) == 1111 metadata_repeated = [:noise_scaling => 0.0, :noise_scaling => 1.0, :metadata_entry => "unused"] @test_throws Exception Reaction(k, [X], [X2], [2], [1]; metadata=metadata_repeated) @@ -152,8 +156,8 @@ let r2 = Reaction(k, [X], [X2], [2], [1]; metadata=metadata) @test isequal(r1, r2) - @test Catalyst.getmetadata_dict(r1) == Pair{Symbol,Any}[] - @test !Catalyst.hasmetadata(r1, :md) + @test getmetadata_dict(r1) == Pair{Symbol,Any}[] + @test !getmetadata(r1, :md) end # Tests creation. @@ -172,21 +176,21 @@ let push!(metadata, :md_6 => (0.1, 2.0)) r = Reaction(k, [X], [X2], [2], [1]; metadata=metadata) - @test Catalyst.getmetadata_dict(r) isa Vector{Pair{Symbol,Any}} - @test Catalyst.hasmetadata(r, :md_1) - @test Catalyst.hasmetadata(r, :md_2) - @test Catalyst.hasmetadata(r, :md_3) - @test Catalyst.hasmetadata(r, :md_4) - @test Catalyst.hasmetadata(r, :md_5) - @test Catalyst.hasmetadata(r, :md_6) - @test !Catalyst.hasmetadata(r, :md_8) - - @test isequal(Catalyst.getmetadata(r, :md_1), 1.0) - @test isequal(Catalyst.getmetadata(r, :md_2), false) - @test isequal(Catalyst.getmetadata(r, :md_3), "Hello world") - @test isequal(Catalyst.getmetadata(r, :md_4), :sym) - @test isequal(Catalyst.getmetadata(r, :md_5), X + X2^k -1) - @test isequal(Catalyst.getmetadata(r, :md_6), (0.1, 2.0)) + @test getmetadata_dict(r) isa Vector{Pair{Symbol,Any}} + @test getmetadata(r, :md_1) + @test getmetadata(r, :md_2) + @test getmetadata(r, :md_3) + @test getmetadata(r, :md_4) + @test getmetadata(r, :md_5) + @test getmetadata(r, :md_6) + @test !getmetadata(r, :md_8) + + @test isequal(getmetadata(r, :md_1), 1.0) + @test isequal(getmetadata(r, :md_2), false) + @test isequal(getmetadata(r, :md_3), "Hello world") + @test isequal(getmetadata(r, :md_4), :sym) + @test isequal(getmetadata(r, :md_5), X + X2^k -1) + @test isequal(getmetadata(r, :md_6), (0.1, 2.0)) end # Tests the noise scaling metadata. From 23eab99779dbc371b4f7ee1e77f1a454c2b4f892 Mon Sep 17 00:00:00 2001 From: Sam Isaacson Date: Fri, 16 Aug 2024 11:31:58 -0400 Subject: [PATCH 2/8] update comment --- src/reaction.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/reaction.jl b/src/reaction.jl index f4208f06dd..e6202a73ac 100644 --- a/src/reaction.jl +++ b/src/reaction.jl @@ -526,6 +526,8 @@ function SymbolicUtils.setmetadata(rx::Reaction, key::Symbol, val) nothing end +### Catalyst Defined Reaction Metadata ### + # Noise scaling. """ hasnoisescaling(reaction::Reaction) From c501104f77f08a88c986689a4827c1018c448a30 Mon Sep 17 00:00:00 2001 From: Sam Isaacson Date: Fri, 16 Aug 2024 11:34:52 -0400 Subject: [PATCH 3/8] fix --- test/dsl/dsl_advanced_model_construction.jl | 12 ++++++------ test/reactionsystem_core/reaction.jl | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/test/dsl/dsl_advanced_model_construction.jl b/test/dsl/dsl_advanced_model_construction.jl index b988adcb95..e8e73b51fe 100644 --- a/test/dsl/dsl_advanced_model_construction.jl +++ b/test/dsl/dsl_advanced_model_construction.jl @@ -184,9 +184,9 @@ let # Checks DSL reactions are correct. rxs = reactions(rs) @test isequal([r1, r2, r3], rxs) - @test isequal(getmetadata_dict(r1), getmetadata_dict(rxs[1])) - @test isequal(getmetadata_dict(r2), getmetadata_dict(rxs[2])) - @test isequal(getmetadata_dict(r3), getmetadata_dict(rxs[3])) + @test isequal(Catalyst.getmetadata_dict(r1), Catalyst.getmetadata_dict(rxs[1])) + @test isequal(Catalyst.getmetadata_dict(r2), Catalyst.getmetadata_dict(rxs[2])) + @test isequal(Catalyst.getmetadata_dict(r3), Catalyst.getmetadata_dict(rxs[3])) # Checks that accessor functions works on the DSL. @test getmetadata(rxs[1], :noise_scaling) @@ -205,9 +205,9 @@ let rx3 = @reaction k, 2X --> X2 @test isequal([rx1, rx2, rx3], rxs) - @test isequal(getmetadata_dict(rx1), getmetadata_dict(rxs[1])) - @test isequal(getmetadata_dict(rx2), getmetadata_dict(rxs[2])) - @test isequal(getmetadata_dict(rx3), getmetadata_dict(rxs[3])) + @test isequal(Catalyst.getmetadata_dict(rx1), Catalyst.getmetadata_dict(rxs[1])) + @test isequal(Catalyst.getmetadata_dict(rx2), Catalyst.getmetadata_dict(rxs[2])) + @test isequal(Catalyst.getmetadata_dict(rx3), Catalyst.getmetadata_dict(rxs[3])) end # Checks that repeated metadata throws errors. diff --git a/test/reactionsystem_core/reaction.jl b/test/reactionsystem_core/reaction.jl index ac5bfc58c6..171be69a05 100644 --- a/test/reactionsystem_core/reaction.jl +++ b/test/reactionsystem_core/reaction.jl @@ -132,7 +132,7 @@ let metadata = [:noise_scaling => 0.0] r = Reaction(k, [X], [X2], [2], [1]; metadata=metadata) - @test getmetadata_dict(r) == [:noise_scaling => 0.0] + @test Catalyst.getmetadata_dict(r) == [:noise_scaling => 0.0] @test getmetadata(r, :noise_scaling) @test !getmetadata(r, :nonexisting_metadata) @test getmetadata(r, :noise_scaling) == 0.0 @@ -156,7 +156,7 @@ let r2 = Reaction(k, [X], [X2], [2], [1]; metadata=metadata) @test isequal(r1, r2) - @test getmetadata_dict(r1) == Pair{Symbol,Any}[] + @test Catalyst.getmetadata_dict(r1) == Pair{Symbol,Any}[] @test !getmetadata(r1, :md) end @@ -176,7 +176,7 @@ let push!(metadata, :md_6 => (0.1, 2.0)) r = Reaction(k, [X], [X2], [2], [1]; metadata=metadata) - @test getmetadata_dict(r) isa Vector{Pair{Symbol,Any}} + @test Catalyst.getmetadata_dict(r) isa Vector{Pair{Symbol,Any}} @test getmetadata(r, :md_1) @test getmetadata(r, :md_2) @test getmetadata(r, :md_3) From ccd296e035c36964228ea8792e62094e0737d4d6 Mon Sep 17 00:00:00 2001 From: Sam Isaacson Date: Fri, 16 Aug 2024 11:38:19 -0400 Subject: [PATCH 4/8] fix --- test/dsl/dsl_advanced_model_construction.jl | 12 ++++++------ test/reactionsystem_core/reaction.jl | 20 ++++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/test/dsl/dsl_advanced_model_construction.jl b/test/dsl/dsl_advanced_model_construction.jl index e8e73b51fe..c4e46bb521 100644 --- a/test/dsl/dsl_advanced_model_construction.jl +++ b/test/dsl/dsl_advanced_model_construction.jl @@ -189,12 +189,12 @@ let @test isequal(Catalyst.getmetadata_dict(r3), Catalyst.getmetadata_dict(rxs[3])) # Checks that accessor functions works on the DSL. - @test getmetadata(rxs[1], :noise_scaling) - @test !getmetadata(rxs[1], :md_1) - @test !getmetadata(rxs[2], :noise_scaling) - @test getmetadata(rxs[2], :md_1) - @test !getmetadata(rxs[3], :noise_scaling) - @test !getmetadata(rxs[3], :md_1) + @test hasmetadata(rxs[1], :noise_scaling) + @test !hasmetadata(rxs[1], :md_1) + @test !hasmetadata(rxs[2], :noise_scaling) + @test hasmetadata(rxs[2], :md_1) + @test !hasmetadata(rxs[3], :noise_scaling) + @test !hasmetadata(rxs[3], :md_1) @test isequal(getmetadata(rxs[1], :noise_scaling), η) @test isequal(getmetadata(rxs[2], :md_1), 1.0) diff --git a/test/reactionsystem_core/reaction.jl b/test/reactionsystem_core/reaction.jl index 171be69a05..3d3b5396f7 100644 --- a/test/reactionsystem_core/reaction.jl +++ b/test/reactionsystem_core/reaction.jl @@ -133,8 +133,8 @@ let r = Reaction(k, [X], [X2], [2], [1]; metadata=metadata) @test Catalyst.getmetadata_dict(r) == [:noise_scaling => 0.0] - @test getmetadata(r, :noise_scaling) - @test !getmetadata(r, :nonexisting_metadata) + @test hasmetadata(r, :noise_scaling) + @test !hasmetadata(r, :nonexisting_metadata) @test getmetadata(r, :noise_scaling) == 0.0 @test_throws Exception getmetadata(r, :misc) setmetadata(r, :test_metadata, 1234) @@ -157,7 +157,7 @@ let @test isequal(r1, r2) @test Catalyst.getmetadata_dict(r1) == Pair{Symbol,Any}[] - @test !getmetadata(r1, :md) + @test !hasmetadata(r1, :md) end # Tests creation. @@ -177,13 +177,13 @@ let r = Reaction(k, [X], [X2], [2], [1]; metadata=metadata) @test Catalyst.getmetadata_dict(r) isa Vector{Pair{Symbol,Any}} - @test getmetadata(r, :md_1) - @test getmetadata(r, :md_2) - @test getmetadata(r, :md_3) - @test getmetadata(r, :md_4) - @test getmetadata(r, :md_5) - @test getmetadata(r, :md_6) - @test !getmetadata(r, :md_8) + @test hasmetadata(r, :md_1) + @test hasmetadata(r, :md_2) + @test hasmetadata(r, :md_3) + @test hasmetadata(r, :md_4) + @test hasmetadata(r, :md_5) + @test hasmetadata(r, :md_6) + @test !hasmetadata(r, :md_8) @test isequal(getmetadata(r, :md_1), 1.0) @test isequal(getmetadata(r, :md_2), false) From 204ce6a08a0f29d4f84f6f7f0916986d760390ce Mon Sep 17 00:00:00 2001 From: Sam Isaacson Date: Fri, 16 Aug 2024 12:21:07 -0400 Subject: [PATCH 5/8] try latest Symbolics and SymbolicUtils --- Project.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Project.toml b/Project.toml index 66cddb75ea..995ce2f3ea 100644 --- a/Project.toml +++ b/Project.toml @@ -65,8 +65,8 @@ RuntimeGeneratedFunctions = "0.5.12" SciMLBase = "2.46" Setfield = "1" StructuralIdentifiability = "0.5.8" -Symbolics = "5.30.1" -SymbolicUtils = "2.1.2" +Symbolics = "5.30.1, 6" +SymbolicUtils = "2.1.2, 3.1.2" Unitful = "1.12.4" julia = "1.10" From 6a881596e815f33075e35a7664b595ea5ead98ef Mon Sep 17 00:00:00 2001 From: Sam Isaacson Date: Fri, 16 Aug 2024 12:21:53 -0400 Subject: [PATCH 6/8] doc project too --- docs/Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Project.toml b/docs/Project.toml index 3adf7702cd..b67138775e 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -73,4 +73,4 @@ StaticArrays = "1.9" SteadyStateDiffEq = "2.2" StochasticDiffEq = "6.65" StructuralIdentifiability = "0.5.8" -Symbolics = "5.30.1" +Symbolics = "6" From 168a6abe66459fc6be592830f0ff7f2f4f7afdb3 Mon Sep 17 00:00:00 2001 From: Sam Isaacson Date: Fri, 16 Aug 2024 12:35:08 -0400 Subject: [PATCH 7/8] don't update Symbolics and SymbolicUtils --- docs/Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Project.toml b/docs/Project.toml index b67138775e..3adf7702cd 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -73,4 +73,4 @@ StaticArrays = "1.9" SteadyStateDiffEq = "2.2" StochasticDiffEq = "6.65" StructuralIdentifiability = "0.5.8" -Symbolics = "6" +Symbolics = "5.30.1" From c2304834931b172722f356845c904bfa3b9fa9ed Mon Sep 17 00:00:00 2001 From: Sam Isaacson Date: Fri, 16 Aug 2024 12:35:31 -0400 Subject: [PATCH 8/8] don't update Symbolics and SymbolicUtils --- Project.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Project.toml b/Project.toml index 995ce2f3ea..66cddb75ea 100644 --- a/Project.toml +++ b/Project.toml @@ -65,8 +65,8 @@ RuntimeGeneratedFunctions = "0.5.12" SciMLBase = "2.46" Setfield = "1" StructuralIdentifiability = "0.5.8" -Symbolics = "5.30.1, 6" -SymbolicUtils = "2.1.2, 3.1.2" +Symbolics = "5.30.1" +SymbolicUtils = "2.1.2" Unitful = "1.12.4" julia = "1.10"