Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Wip] Refactor "src/dsl.jl" file #985

Open
wants to merge 40 commits into
base: master
Choose a base branch
from

Conversation

TorkelE
Copy link
Member

@TorkelE TorkelE commented Jul 13, 2024

Also does the "src/expression_utils.jl" file, as that primarily support the dsl file (the other relevant file is the chemistry one).

Primarily four types of changes:

  • Added comment to code which did not have (primarily older code).
  • Rewrite some old code (a lot of stuff in the dsl file is stuff I wrote over 6 years ago, which simply can be rewritten better now).
  • Do some organisations for where the options are handled in the main function. Been meaning to do this pretty much since I introduced them, and now when we have all *for the foreseeable future) it seemed like a good time to do it. Now it should also be easier to see where to add new options in the future.
  • Rewrite so that the @reaction_network and @network_component macros reuse minimal amount of code (where as previously it the second was basically ctrl+copied versions of the first.
  • Add a bunch of error checks to handle things which previously went through but shouldn't.

I also add some tests of all the various ways to create models via the DSL, mostly stuff that was not tested before.

src/Catalyst.jl Outdated Show resolved Hide resolved
@TorkelE TorkelE changed the title Refactor "srcd/sl.jl" file [wip] Refactor "srcd/sl.jl" file Jul 13, 2024
@TorkelE TorkelE force-pushed the src___refactoring___dsl_file branch from 3f92a31 to b6ba044 Compare July 13, 2024 23:09
src/dsl.jl Show resolved Hide resolved
src/dsl.jl Outdated Show resolved Hide resolved
src/dsl.jl Show resolved Hide resolved
src/dsl.jl Show resolved Hide resolved
src/dsl.jl Show resolved Hide resolved
src/dsl.jl Outdated
variables = vcat(variables_declared, vars_extracted)

# handle independent variables
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Part of the organisations so that options are handled together (in two sets, some before and some after the reactions are considered, depending on whichever is possible for which option)

src/dsl.jl Show resolved Hide resolved
src/dsl.jl Outdated Show resolved Hide resolved
src/dsl.jl Show resolved Hide resolved
symvec = gensym()
ex = quote
$symvec = $ex
expr = quote
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in some places we used ex and some expr, here I just made it uniform

isequivalent(rs_empty_1, rs_empty)
rs_empty_2 == rs_empty
rs_empty_3 == rs_empty
end
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WHen I remade how the macor inputs are handled at the top level (nothing, name, reactions, name + reactions) I wanted to add some tests that all of this works for all cases and both macros.

function escape_equation!(eqexpr::Expr, diffsyms)
eqexpr.args[2] = recursive_escape_functions!(eqexpr.args[2], diffsyms)
eqexpr.args[3] = recursive_escape_functions!(eqexpr.args[3], diffsyms)
eqexpr
end
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved escape_equation! up here since it is just a helper function to the function above and not involved in other stuff. Calls recursive_escape_functions! on the lhs as well.

rn = @reaction_network begin
@equations D(A) ~ f(A, t)
@equations D(A) + g(A) ~ f(A, t)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated because we now hanldes functions on both sides.

diffs_inferred = Union{Symbol, Expr}[]
if add_default_diff && !any(diff_dec.args[1] == :D for diff_dec in diffsexpr.args)
diffs_inferred = [:D]
push!(diffsexpr.args, :(D = Differential($(tiv))))
end
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now, if we use a default differential, diffsexpr is updated directly in read_equations_options!. Made more sense as I wanted to handle the @differnetials option at the beginning (since this explicitly declares symbols). Previously this option was handled after @equations.

src/dsl.jl Outdated
spsexpr, spsvar = scalarize_macro(spsexpr_init, "specs")
vsexpr, vsvar = scalarize_macro(vsexpr_init, "vars")
cmpsexpr, cmpsvar = scalarize_macro(cmpexpr_init, "comps")
rxsexprs = get_rxexprs(reactions, equations, union(diffs_declared, diffs_inferred))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

trying to harmonise notation a bit across everything. exprs is the expression that generates the actually code, var is the generated variable we store stuff in. init on things that should not be evaluated. sps are species, vs variables, us unknowns, ps parameters, cmps compounds. Syms are lists of symbols (e.g. the symbols corresponding to observables). Not insisting we use this across the board, just explaining how I have changed things.

if rateex isa Symbol
if !(rateex in forbidden_symbols_skip) && !(rateex in excluded_syms)
push!(push_symbols, rateex)
function add_syms_from_expr!(push_symbols::AbstractSet, expr::ExprValues, excluded_syms)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rateex -> expr as this is not necessarily only the rate anymore.

end
return compound_expr, compound_species
return cmpexpr_init, cmps_declared
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shortened compound to cmp in line with other shortenings, and to avoid having to break certain lines into two lines in some places.

src/dsl.jl Show resolved Hide resolved
@TorkelE TorkelE changed the title [Wip] Refactor "srcd/sl.jl" file [Wip] Refactor "src/dsl.jl" file Jan 18, 2025
allunique(syms) ||
error("Reaction network independent variables, parameters, species, and variables must all have distinct names, but a duplicate has been detected. ")
nothing
end
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now only used in one place, there implemented directly.

(length(expr.args) > 3) &&
error("An option input ($expr) is misformatted. Potentially, it has multiple inputs on a single lines, and these should be split across multiple lines using a `begin ... end` block.")
return expr.args[3]
end
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Helper function for handling error checks across multiple options.

sexprs = get_sexpr([species], Dict{Symbol, Expr}())
pexprs = get_pexpr(parameters, Dict{Symbol, Expr}())
sexprs = get_usexpr([species], Dict{Symbol, Expr}())
pexprs = get_psexpr(parameters, Dict{Symbol, Expr}())
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uses new names in the DSL file

# Tests error when disallowed name is used for variable.
let
@test_throws Exception @eval @reaction_network begin
@variables π(t)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new test

probODE = ODEProblem(rn, args...; kwargs...) # Using multiple dispatch the reaction network can be used as input to create ODE, SDE and Jump problems.
probSDE = SDEProblem(rn, args...; kwargs...)
probJump = JumpProblem(prob,aggregator::Direct,rn)
"""
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The first documentation of @reactio_network, but now not even a docstring and just a weird remnant. remove.

probJump = JumpProblem(prob,aggregator::Direct,rn)
"""

### Constant Declarations ###
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not removed, now just line 1 and git got confused.

(sum(length, [reaction_lines, option_lines]) != length(ex.args)) &&
error("@reaction_network input contain $(length(ex.args) - sum(length.([reaction_lines,option_lines]))) malformed lines.")
any(!in(option_keys), keys(options)) &&
error("The following unsupported options were used: $(filter(opt_in->!in(opt_in,option_keys), keys(options)))")
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Step one, read the macro input and check that it is correctly formatted.

if !allunique(syms_declared)
nonunique_syms = [s for s in syms_declared if count(x -> x == s, syms_declared) > 1]
error("The following symbols $(unique(nonunique_syms)) have explicitly been declared as multiple types of components (e.g. occur in at least two of the `@species`, `@parameters`, `@variables`, `@ivs`, `@compounds`, `@differentials`). This is not allowed.")
end
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Step 2, read all options that explicitly declares symbols as stuff.

union(syms_declared, sps_inferred), tiv; requiredec)
ps_inferred = setdiff(ps_pre_inferred, vs_inferred, diffs_inferred)
syms_inferred = union(sps_inferred, ps_inferred, vs_inferred, diffs_inferred)
all_syms = union(syms_declared, syms_inferred)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Step 3, read the reactions, as well as the options from which we infer symbols.

continuous_events_expr = read_events_option(options, :continuous_events)
discrete_events_expr = read_events_option(options, :discrete_events)
default_reaction_metadata = read_default_noise_scaling_option(options)
combinatoric_ratelaws = read_combinatoric_ratelaws_option(options)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Step 4, read the other options.

spsexpr, spsvar = scalarize_macro(spsexpr_init, "specs")
vsexpr, vsvar = scalarize_macro(vsexpr_init, "vars")
cmpsexpr, cmpsvar = scalarize_macro(cmpexpr_init, "comps")
rxsexprs = get_rxexprs(reactions, equations, all_syms)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Step 5, creates the various expressions to put in the macro.

end
union!(excluded_syms, species)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

union! replaces foreach(s -> push!(excluded_syms, s), species)

@test_throws Exception @eval @reaction_network begin
@combinatoric_ratelaws false false
d, 3X --> 0
end
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checks that new error checks work (don't think the one above actually errored either, but it should)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants