Unverified Commit 3f0d7bd2 authored by Miroslav Kratochvil's avatar Miroslav Kratochvil Committed by GitHub
Browse files

Merge pull request #69 from LCSB-BioCore/mk-symbolics-completeness

Support MathTime conversion to Symbolics, document the whole thing
parents f61be314 7f1506c8
...@@ -89,7 +89,14 @@ Modules = [SBML] ...@@ -89,7 +89,14 @@ Modules = [SBML]
Pages = ["utils.jl"] Pages = ["utils.jl"]
``` ```
## Internal math manipulation ## Math and `Symbolics.jl` compatibility
```@autodocs
Modules = [SBML]
Pages = ["symbolics.jl"]
```
### Internal math helpers
```@autodocs ```@autodocs
Modules = [SBML] Modules = [SBML]
......
...@@ -16,6 +16,6 @@ include("symbolics.jl") ...@@ -16,6 +16,6 @@ include("symbolics.jl")
sbml = (sym::Symbol) -> dlsym(SBML_jll.libsbml_handle, sym) sbml = (sym::Symbol) -> dlsym(SBML_jll.libsbml_handle, sym)
export SBMLVersion, readSBML, getS, getLBs, getUBs, getOCs export SBMLVersion, readSBML, getS, getLBs, getUBs, getOCs
export convert_level_and_version, libsbml_convert, convert_simplify_math export set_level_and_version, libsbml_convert, convert_simplify_math
end # module end # module
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
const VPtr = Ptr{Cvoid} const VPtr = Ptr{Cvoid}
""" """
function get_string(x::VPtr, fn_sym)::Maybe{String} get_string(x::VPtr, fn_sym)::Maybe{String}
C-call the SBML function `fn_sym` with a single parameter `x`, interpret the C-call the SBML function `fn_sym` with a single parameter `x`, interpret the
result as a string and return it, or throw exception in case the pointer is result as a string and return it, or throw exception in case the pointer is
...@@ -18,9 +18,9 @@ function get_string(x::VPtr, fn_sym)::String ...@@ -18,9 +18,9 @@ function get_string(x::VPtr, fn_sym)::String
end end
""" """
function get_optional_string(x::VPtr, fn_sym)::Maybe{String} get_optional_string(x::VPtr, fn_sym)::Maybe{String}
Like [`get_string`](@Ref), but returns `nothing` instead of throwing an Like [`get_string`](@ref), but returns `nothing` instead of throwing an
exception. exception.
This is used to get notes and annotations and several other things (see This is used to get notes and annotations and several other things (see
...@@ -82,7 +82,7 @@ Read the SBML from a XML file in `fn` and return the contained `SBML.Model`. ...@@ -82,7 +82,7 @@ Read the SBML from a XML file in `fn` and return the contained `SBML.Model`.
The `sbml_conversion` is a function that does an in-place modification of the The `sbml_conversion` is a function that does an in-place modification of the
single parameter, which is the C pointer to the loaded SBML document (C type single parameter, which is the C pointer to the loaded SBML document (C type
`SBMLDocument*`). Several functions for doing that are prepared, including `SBMLDocument*`). Several functions for doing that are prepared, including
[`convert_level_and_version`](@ref), [`libsbml_convert`](@ref), and [`set_level_and_version`](@ref), [`libsbml_convert`](@ref), and
[`convert_simplify_math`](@ref). [`convert_simplify_math`](@ref).
# Example # Example
......
default_symbolics_mapping = Dict( """
default_symbolics_mapping :: Dict{String,Any}
Default mapping of SBML function names to Julia functions, represented as a
dictionary from Strings (SBML names) to anything `eval`uable as Julia&Symbolics
functions, such as symbols and expressions.
The default mapping only contains the basic SBML functions that are
unambiguously represented in Julia; it is supposed to be extended by the user
if more functions need to be supported.
"""
default_symbolics_mapping = Dict{String,Any}(
"+" => :+, "+" => :+,
"-" => :-, "-" => :-,
"*" => :*, "*" => :*,
...@@ -12,15 +23,40 @@ default_symbolics_mapping = Dict( ...@@ -12,15 +23,40 @@ default_symbolics_mapping = Dict(
"ceiling" => :ceil, "ceiling" => :ceil,
"floor" => :floor, "floor" => :floor,
"piecewise" => :(Core.ifelse), "piecewise" => :(Core.ifelse),
#TODO extend this in the future
) )
allowed_sym(x, allowed_funs) = allowed_sym(x, allowed_funs) =
haskey(allowed_funs, x) ? allowed_funs[x] : haskey(allowed_funs, x) ? allowed_funs[x] :
throw(DomainError(x, "Unknown SBML function")) throw(DomainError(x, "Unknown SBML function"))
function Base.convert(::Type{Num}, x::SBML.Math; mapping = default_symbolics_mapping) """
Base.convert(
::Type{Num},
x::SBML.Math;
mapping = default_symbolics_mapping,
convert_time = (x::SBML.MathTime) -> Num(Variable(Symbol(x.id))).val,
)
Convert SBML.[`Math`](@ref) to `Num` type Symbolics package. The conversion of
functions can be customized by supplying a custom mapping to symbols; if
nothing is supplied, [`default_symbolics_mapping`](@ref) that translates basic
functions to their Julia equivalents is assumed.
Translation of [`MathLambda`](@ref) is not supported by Symbolics.
[`MathTime`](@ref) is handled specially, the function from the argument
`convert_time` is called to possibly specify any desired behavior. By default,
it just creates a variable with the same name as the time variable name stored
in SBML.
"""
function Base.convert(
::Type{Num},
x::SBML.Math;
mapping = default_symbolics_mapping,
convert_time = (x::SBML.MathTime) -> Num(Variable(Symbol(x.id))).val,
)
conv(x::SBML.MathApply) = eval(allowed_sym(x.fn, mapping))(conv.(x.args)...) conv(x::SBML.MathApply) = eval(allowed_sym(x.fn, mapping))(conv.(x.args)...)
conv(x::SBML.MathTime) = convert_time(x)
conv(x::SBML.MathIdent) = Num(Variable(Symbol(x.id))).val conv(x::SBML.MathIdent) = Num(Variable(Symbol(x.id))).val
conv(x::SBML.MathVal) = x.val conv(x::SBML.MathVal) = x.val
conv(x::SBML.MathLambda) = throw(DomainError(x, "can't translate lambdas to symbolics")) conv(x::SBML.MathLambda) = throw(DomainError(x, "can't translate lambdas to symbolics"))
......
@testset "Math to Symbolics conversions" begin @testset "Math to Symbolics conversions" begin
@variables A B C D E @variables A B C D Time
test = SBML.MathApply( test = SBML.MathApply(
"*", "*",
...@@ -21,11 +21,11 @@ ...@@ -21,11 +21,11 @@
), ),
], ],
), ),
SBML.MathIdent("E"), SBML.MathTime("Time"),
], ],
) )
@test isequal(convert(Num, test), (A * B - C * D) * E) @test isequal(convert(Num, test), (A * B - C * D) * Time)
test = SBML.MathApply( test = SBML.MathApply(
"piecewise", "piecewise",
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment