Skip to content

Commit

Permalink
Merge pull request #12 from isaacsas/update_to_catalyst13
Browse files Browse the repository at this point in the history
Update to Catalyst 13 and latest Symbolics
  • Loading branch information
kaandocal committed Sep 26, 2023
2 parents 3beaccb + 8b992dc commit 24ac103
Show file tree
Hide file tree
Showing 13 changed files with 90 additions and 84 deletions.
81 changes: 40 additions & 41 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,41 +1,40 @@
name: CI
on:
- push
- pull_request
jobs:
test:
name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
version:
- '1.5'
- '1.6'
- '1.7'
os:
- ubuntu-latest
arch:
- x64
steps:
- uses: actions/checkout@v2
- uses: julia-actions/setup-julia@v1
with:
version: ${{ matrix.version }}
arch: ${{ matrix.arch }}
- uses: actions/cache@v1
env:
cache-name: cache-artifacts
with:
path: ~/.julia/artifacts
key: ${{ runner.os }}-test-${{ env.cache-name }}-${{ hashFiles('**/Project.toml') }}
restore-keys: |
${{ runner.os }}-test-${{ env.cache-name }}-
${{ runner.os }}-test-
${{ runner.os }}-
- uses: julia-actions/julia-buildpkg@v1
- uses: julia-actions/julia-runtest@v1
- uses: julia-actions/julia-processcoverage@v1
- uses: codecov/codecov-action@v1
with:
file: lcov.info
name: CI
on:
- push
- pull_request
jobs:
test:
name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
version:
- '1.6'
- '1.9'
os:
- ubuntu-latest
arch:
- x64
steps:
- uses: actions/checkout@v2
- uses: julia-actions/setup-julia@v1
with:
version: ${{ matrix.version }}
arch: ${{ matrix.arch }}
- uses: actions/cache@v1
env:
cache-name: cache-artifacts
with:
path: ~/.julia/artifacts
key: ${{ runner.os }}-test-${{ env.cache-name }}-${{ hashFiles('**/Project.toml') }}
restore-keys: |
${{ runner.os }}-test-${{ env.cache-name }}-
${{ runner.os }}-test-
${{ runner.os }}-
- uses: julia-actions/julia-buildpkg@v1
- uses: julia-actions/julia-runtest@v1
- uses: julia-actions/julia-processcoverage@v1
- uses: codecov/codecov-action@v1
with:
file: lcov.info
6 changes: 3 additions & 3 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "FiniteStateProjection"
uuid = "069e79ea-d681-44e8-b935-95bdaf9e8f28"
authors = ["kaandocal"]
version = "0.2.1"
version = "0.3.0"

[deps]
Catalyst = "479239e8-5488-4da2-87a7-35f2df7eef83"
Expand All @@ -12,12 +12,12 @@ RuntimeGeneratedFunctions = "7e49a35a-f44a-4d26-94aa-eba1b4ca6b47"
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"

[compat]
Catalyst = "9, 10, 11, 12"
Catalyst = "13"
DiffEqBase = "6"
MacroTools = "^0.5.5"
Reexport = "1"
RuntimeGeneratedFunctions = "0.5"
julia = "1.5"
julia = "1.6"

[extras]
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Finite State Projection [[1]](#1) algorithms for chemical reaction networks bas
- FSP equations are generated as `ODEFunction`/`ODEProblem`s and can be solved with [DifferentialEquations.jl](https://github.com/SciML/DifferentialEquations.jl), with on-the-fly generation of targeted functions for improved performance
- The Chemical Master Equation can be represented as a `SparseMatrixCSC`

More information is available in the [documentation](https://kaandocal.github.io/FiniteStateProjection.jl/dev/). Please feel free to open issues and submit pull requests!
More information is available in the [documentation](https://kaandocal.github.io/FiniteStateProjection.jl/dev/). Please feel free to open issues and submit pull requests!

## Examples
### Birth-Death System
Expand All @@ -20,7 +20,7 @@ using OrdinaryDiffEq
rn = @reaction_network begin
σ, 0 --> A
d, A --> 0
end σ d
end

sys = FSPSystem(rn)

Expand All @@ -30,7 +30,7 @@ ps = [ 10.0, 1.0 ]
# Initial distribution (over 1 species)
# Here we start with 0 copies of A
u0 = zeros(50)
u0[1] = 1.0
u0[1] = 1.0

prob = convert(ODEProblem, sys, u0, (0, 10.0), ps)
sol = solve(prob, Vern7())
Expand All @@ -47,7 +47,7 @@ rn = @reaction_network begin
σ_off, G_on --> 0
ρ, G_on --> G_on + M
d, M --> 0
end σ_on σ_off ρ d
end

sys = FSPSystem(rn)

Expand Down
2 changes: 1 addition & 1 deletion demo/birth_death.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ using PyPlot
rs = @reaction_network begin
r1, 0 --> A
r2, A --> 0
end r1 r2
end

##

Expand Down
6 changes: 3 additions & 3 deletions demo/telegraph.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ rs = @reaction_network begin
r2, G_on --> 0
r3, G_on --> G_on + M
r4, M --> 0
end r1 r2 r3 r4
end

##

Expand All @@ -20,9 +20,9 @@ ps = [ 0.25, 0.15, 15.0, 1.0 ]

# Initial values
# Since G_on + G_off = const. we do not have to model the two
# separately. Use reduced_species(sys) to get the list of
# separately. Use reduced_species(sys) to get the list of
# species we actually have to model:
#
#
# julia> reduced_species(sys)
# 2-element Vector{Int64}:
# 1
Expand Down
3 changes: 3 additions & 0 deletions docs/Project.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
[deps]
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"

[compat]
Documenter = "0.27"
6 changes: 3 additions & 3 deletions docs/src/examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ using OrdinaryDiffEq
rn = @reaction_network begin
σ, 0 --> A
d, A --> 0
end σ d
end

sys = FSPSystem(rn)

Expand All @@ -21,7 +21,7 @@ ps = [ 10.0, 1.0 ]
# Initial distribution (over 1 species)
# Here we start with 0 copies of A
u0 = zeros(50)
u0[1] = 1.0
u0[1] = 1.0

prob = ODEProblem(sys, u0, (0, 10.0), ps)
sol = solve(prob, Vern7())
Expand All @@ -47,7 +47,7 @@ rn = @reaction_network begin
σ_off, G_on --> 0
ρ, G_on --> G_on + M
d, M --> 0
end σ_on σ_off ρ d
end

sys = FSPSystem(rn)

Expand Down
2 changes: 1 addition & 1 deletion docs/src/troubleshoot.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ This point might seem obvious, but errors in the rate functions, or an incorrect
rn = @reaction_network begin
σ * (N - I), I --> 2I
ρ, I --> 0
end σ ρ N
end

sys_fsp = FSPSystem(rn)
```
Expand Down
25 changes: 15 additions & 10 deletions src/fspsystem.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""
Thin wrapper around `Catalyst.ReactionSystem` for use with this package.
"""
Thin wrapper around `Catalyst.ReactionSystem` for use with this package.
Constructor: `FSPSystem(rs::ReactionSystem[, ih=DefaultIndexHandler(); combinatoric_ratelaw::Bool=true])`
"""
Expand All @@ -10,22 +10,27 @@ struct FSPSystem{IHT <: AbstractIndexHandler, RT}
end

function FSPSystem(rs::ReactionSystem, ih=DefaultIndexHandler(); combinatoric_ratelaw::Bool=true)
isempty(Catalyst.get_systems(rs)) ||
error("Supported Catalyst models can not contain subsystems. Please use `rs = Catalyst.flatten(rs::ReactionSystem)` to generate a single system with no subsystems from your Catalyst model.")
any(eq -> !(eq isa Reaction), equations(rs)) &&
error("Catalyst models that include constraint ODEs or algebraic equations are not supported.")

rfs = create_ratefuncs(rs, ih; combinatoric_ratelaw=combinatoric_ratelaw)
FSPSystem(rs, ih, rfs)
end

"""
"""
build_ratefuncs(rs, ih; state_sym::Symbol, combinatoric_ratelaw::Bool)::Vector
Return the rate functions converted to Julia expressions in the state variable
Return the rate functions converted to Julia expressions in the state variable
`state_sym`. Abundances of the species are computed using `getsubstitutions`.
See also: [`getsubstitutions`](@ref), [`build_rhs`](@ref)
"""
function build_ratefuncs(rs::ReactionSystem, ih::AbstractIndexHandler; state_sym::Symbol, combinatoric_ratelaw::Bool=true)
substitutions = getsubstitutions(ih, rs, state_sym=state_sym)
return map(Catalyst.get_eqs(rs)) do reac

return map(Catalyst.reactions(rs)) do reac
jrl = jumpratelaw(reac; combinatoric_ratelaw)
jrl_s = substitute(jrl, substitutions)
toexpr(jrl_s)
Expand All @@ -34,12 +39,12 @@ end

function create_ratefuncs(rs::ReactionSystem, ih::AbstractIndexHandler; combinatoric_ratelaw::Bool=true)
paramsyms = Symbol.(Catalyst.parameters(rs))
return tuple(map(ex -> compile_ratefunc(ex, paramsyms),

return tuple(map(ex -> compile_ratefunc(ex, paramsyms),
build_ratefuncs(rs, ih; state_sym=:idx_in, combinatoric_ratelaw))...)
end
end

function compile_ratefunc(ex_rf, params)
function compile_ratefunc(ex_rf, params)
# Make this nicer in the future
ex = :((idx_in, t, $(params...)) -> $(ex_rf)) |> MacroTools.flatten
@RuntimeGeneratedFunction(ex)
Expand Down
4 changes: 3 additions & 1 deletion src/indexhandlers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -112,5 +112,7 @@ end
Defines the abundance of species ``S_i`` to be `state_sym[i] - offset`.
"""
function getsubstitutions(ih::DefaultIndexHandler, rs::ReactionSystem; state_sym::Symbol)
Dict(symbol => Term{Number}(Base.getindex, (state_sym, i)) - ih.offset for (i, symbol) in enumerate(species(rs)))
nspecs = numspecies(rs)
state_sym_vec = ModelingToolkit.value.(ModelingToolkit.scalarize((@variables ($state_sym)[1:nspecs])[1]))
Dict(symbol => state_sym_vec[i] - ih.offset for (i, symbol) in enumerate(species(rs)))
end
12 changes: 6 additions & 6 deletions src/matrix.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ function create_sparsematrix(sys::FSPSystem, dims::NTuple, ps, t)
J = Int[]
V = Float64[]

predsize = Ntot * (length(Catalyst.get_eqs(sys.rs)) + 1)
predsize = Ntot * (length(Catalyst.equations(sys.rs)) + 1)

sizehint!(I, predsize)
sizehint!(J, predsize)
Expand All @@ -33,7 +33,7 @@ function create_sparsematrix(sys::FSPSystem, dims::NTuple, ps, t)
push!(I, lind[idx_cout])
push!(J, lind[idx_cin])

rate = rf(idx_cin, t, ps...)
rate = rf(idx_cin, t, ps...)
push!(V, rate)
end
end
Expand All @@ -49,7 +49,7 @@ function create_sparsematrix_ss(sys::FSPSystem, dims::NTuple, ps)
J = Int[]
V = Float64[]

predsize = 2 * Ntot * length(Catalyst.get_eqs(sys.rs))
predsize = 2 * Ntot * length(Catalyst.equations(sys.rs))

sizehint!(I, predsize)
sizehint!(J, predsize)
Expand Down Expand Up @@ -79,8 +79,8 @@ end
"""
Base.convert(::Type{SparseMatrixCSC}, sys::FSPSystem, dims::NTuple, ps, t::Real)
Convert the reaction system into a sparse matrix defining the right-hand side of the
Chemical Master Equation. `dims` is a tuple denoting the dimensions of the FSP and
Convert the reaction system into a sparse matrix defining the right-hand side of the
Chemical Master Equation. `dims` is a tuple denoting the dimensions of the FSP and
`ps` is the tuple of parameters. The sparse matrix works on the flattened version
of the state obtained using `vec`.
"""
Expand All @@ -91,7 +91,7 @@ end
"""
Base.convert(::Type{SparseMatrixCSC}, sys::FSPSystem, dims::NTuple, ps, ::SteadyState)
Convert the reaction system into a sparse matrix defining the right-hand side of the
Convert the reaction system into a sparse matrix defining the right-hand side of the
Chemical Master Equation, steady-state version.
"""
function Base.convert(::Type{SparseMatrixCSC}, sys::FSPSystem, dims::NTuple, ps, ::SteadyState)
Expand Down
11 changes: 5 additions & 6 deletions test/birthdeath2D.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,27 @@ using Sundials

marg(vec; dims) = dropdims(sum(vec; dims); dims)

@parameters r1, r2, s1, s2
rs = @reaction_network begin
r1, 0 --> A
r2, A --> 0
s1, 0 --> B
s2, B --> 0
end r1 r2 s1 s2
end

sys = FSPSystem(rs)

prs = exp.(2 .* rand(2))
ps = [ prs[1], prs[1] / exp(4 * rand()),
ps = [ prs[1], prs[1] / exp(4 * rand()),
prs[2], prs[2] / exp(4 * rand()) ]

Nmax = 130
Nmax = 100
u0 = zeros(Nmax+1, Nmax+1)
u0[1] = 1.0

tt = [ 0.25, 1.0, 10.0 ]

prob = convert(ODEProblem, sys, u0, 10.0, ps)
sol = solve(prob, Vern7(), abstol=1e-9, reltol=1e-6, saveat=tt)
sol = solve(prob, Vern7(), abstol=1e-6, saveat=tt)

@test marg(sol.u[1], dims=2) pdf.(Poisson(ps[1] / ps[2] * (1 - exp(-ps[2] * tt[1]))), 0:Nmax) atol=1e-4
@test marg(sol.u[1], dims=1) pdf.(Poisson(ps[3] / ps[4] * (1 - exp(-ps[4] * tt[1]))), 0:Nmax) atol=1e-4
Expand All @@ -45,7 +44,7 @@ A = convert(SparseMatrixCSC, sys, (Nmax+1, Nmax+1), ps, 0)
f = (du,u,t) -> mul!(du, A, u)

probA = ODEProblem(f, u0, 10.0)
solA = solve(prob, Vern7(), abstol=1e-9, reltol=1e-6, saveat=tt)
solA = solve(prob, Vern7(), abstol=1e-6, saveat=tt)

@test sol.u[1] solA.u[1] atol=1e-4
@test sol.u[2] solA.u[2] atol=1e-4
Expand Down

0 comments on commit 24ac103

Please sign in to comment.