symbolics.jl 3.63 KB
Newer Older
paulflang's avatar
paulflang committed
1

2
3
4
5
6
7
8
9
10
11
12
"""
    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.
"""
13
const default_symbolics_mapping = Dict{String,Any}(
14
    "*" => :*,
paulflang's avatar
paulflang committed
15
16
17
    "+" => :+,
    "-" => :-,
    "/" => :/,
anand jain's avatar
anand jain committed
18
19
20
21
22
23
24
25
26
27
28
29
30
    "abs" => :abs,
    "arccos" => :acos,
    "arccosh" => :acosh,
    "arccot" => :acot,
    "arccoth" => :acoth,
    "arccsc" => :acsc,
    "arccsch" => :acsch,
    "arcsec" => :asec,
    "arcsech" => :asech,
    "arcsin" => :asin,
    "arcsinh" => :asinh,
    "arctan" => :atan,
    "arctanh" => :atanh,
31
    "ceiling" => :ceil,
anand jain's avatar
anand jain committed
32
33
34
35
36
37
38
    "cos" => :cos,
    "cosh" => :cosh,
    "cot" => :cot,
    "coth" => :coth,
    "csc" => :csc,
    "csch" => :csch,
    "eq" => :isequal,
39
    "exp" => :exp,
anand jain's avatar
anand jain committed
40
    "factorial" => :factorial,
41
42
43
44
45
46
47
    "floor" => :floor,
    "geq" => :>=,
    "gt" => :>,
    "leq" => :<=,
    "ln" => :log,
    "log" => :sbmlLog,
    "lt" => :<,
48
    "piecewise" => :(sbmlPiecewise),
49
50
    "power" => :^,
    "root" => :sbmlRoot,
anand jain's avatar
anand jain committed
51
    "sech" => :sech,
52
    "sec" => :sec,
anand jain's avatar
anand jain committed
53
    "sinh" => :sinh,
54
55
    "sin" => :sin,
    "tanh" => :tanh,
anand jain's avatar
anand jain committed
56
    "tan" => :tan,
paulflang's avatar
paulflang committed
57
58
)

59
60
61
62
63
64
65
66
67
68
69
function sbmlPiecewise(args...)
    if length(args) == 1
        args[1]
    elseif length(args) >= 3
        Core.ifelse(args[2], args[1], sbmlPiecewise(args[3:end]...))
    else
        throw(AssertionError("malformed piecewise SBML function"))
    end
end


70
sbmlLog(x) = log(x, 10)
71
sbmlLog(base, x) = log(base, x)
72
73
74
75

sbmlRoot(x) = sqrt(x)
sbmlRoot(power, x) = x^(1 / power)

76
77
78
allowed_sym(x, allowed_funs) =
    haskey(allowed_funs, x) ? allowed_funs[x] :
    throw(DomainError(x, "Unknown SBML function"))
paulflang's avatar
paulflang committed
79

80
81
82
83
84
85
86
87
88
"""
    const default_symbolics_constants::Dict{String, Any}

A dictionary of default constants filled in place of SBML Math constants in the
symbolics conversion.
"""
const default_symbolics_constants =
    Dict{String,Any}("true" => true, "false" => false, "pi" => pi, "e" => exp(1))

89
90
91
92
93
94
"""
    Base.convert(
        ::Type{Num},
        x::SBML.Math;
        mapping = default_symbolics_mapping,
        convert_time = (x::SBML.MathTime) -> Num(Variable(Symbol(x.id))).val,
95
        convert_const = (x::SBML.MathConst) -> Num(default_symbolics_constants[x.id]),
96
97
    )

Miroslav Kratochvil's avatar
a typo.    
Miroslav Kratochvil committed
98
99
Convert SBML.[`Math`](@ref) to `Num` type from Symbolics package. The
conversion of functions can be customized by supplying a custom mapping; if
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
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,
115
    convert_const = (x::SBML.MathConst) -> Num(default_symbolics_constants[x.id]),
116
)
117
    conv(x::SBML.MathApply) = eval(allowed_sym(x.fn, mapping))(conv.(x.args)...)
118
    conv(x::SBML.MathTime) = convert_time(x)
119
    conv(x::SBML.MathConst) = convert_const(x)
120
    conv(x::SBML.MathIdent) = Num(Variable(Symbol(x.id))).val
121
    conv(x::SBML.MathVal) = Num(x.val)
122
    conv(x::SBML.MathLambda) = throw(DomainError(x, "can't translate lambdas to symbolics"))
paulflang's avatar
paulflang committed
123
124
    conv(x)
end