Skip to content

Commit

Permalink
Merge 7bac996 into ddbf2d6
Browse files Browse the repository at this point in the history
  • Loading branch information
ChrisRackauckas committed Jun 23, 2022
2 parents ddbf2d6 + 7bac996 commit d3f9ef1
Show file tree
Hide file tree
Showing 9 changed files with 178 additions and 145 deletions.
1 change: 1 addition & 0 deletions .JuliaFormatter.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
style = "sciml"
42 changes: 42 additions & 0 deletions .github/workflows/FormatCheck.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: format-check

on:
push:
branches:
- 'master'
- 'release-'
tags: '*'
pull_request:

jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
julia-version: [1]
julia-arch: [x86]
os: [ubuntu-latest]
steps:
- uses: julia-actions/setup-julia@latest
with:
version: ${{ matrix.julia-version }}

- uses: actions/checkout@v1
- name: Install JuliaFormatter and format
# This will use the latest version by default but you can set the version like so:
#
# julia -e 'using Pkg; Pkg.add(PackageSpec(name="JuliaFormatter", version="0.13.0"))'
run: |
julia -e 'using Pkg; Pkg.add(PackageSpec(name="JuliaFormatter"))'
julia -e 'using JuliaFormatter; format(".", verbose=true)'
- name: Format check
run: |
julia -e '
out = Cmd(`git diff --name-only`) |> read |> String
if out == ""
exit(0)
else
@error "Some files have not been formatted !!!"
write(stdout, out)
exit(1)
end'
8 changes: 3 additions & 5 deletions docs/make.jl
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
using Documenter, MathML

makedocs(sitename="My Documentation")
makedocs(sitename = "My Documentation")

deploydocs(
repo = "github.com/anandijain/MathML.jl.git",
devbranch = "main",
)
deploydocs(repo = "github.com/anandijain/MathML.jl.git",
devbranch = "main")
243 changes: 116 additions & 127 deletions src/maps.jl
Original file line number Diff line number Diff line change
@@ -1,130 +1,119 @@

# need to check the arities
# units handling??
applymap = Dict{String,Function}(
# eq sometimes needs to be ~ and sometimes needs to be =, not sure what the soln is
"eq" => x -> Symbolics.:~(x...), # arity 2,
"times" => Base.prod, # arity 2, but prod fine
# "prod" => Base.prod,
"divide" => x -> Base.:/(x...),
"power" => x -> Base.:^(x...),
"root" => custom_root,
"plus" => x -> Base.:+(x...),
"minus" => x -> Base.:-(x...),

# comparison functions implemented using the Heaviside function
"lt" => x -> H(x[2] - x[1] - ϵ),
"leq" => x -> H(x[2] - x[1]),
"geq" => x -> H(x[1] - x[2]),
"gt" => x -> H(x[1] - x[2] - ϵ),

# equal nodes are not part of the MathML specification and
# are generated by disambiguate_equality!
"equal" => x -> H(x[1] - x[2]) * H(x[2] - x[1]),
"neq" => x -> 1 - H(x[1] - x[2]) * H(x[2] - x[1]),

# "lt" => x -> Base.foldl(Base.:<, x),
# "leq" => x -> Base.foldl(Base.:≤, x),
# "geq" => x -> Base.foldl(Base.:≥, x),
# "gt" => x -> Base.foldl(Base.:>, x),

# "quotient" => x->Base.:div(x...), # broken, RoundingMode
"factorial" => x -> SpecialFunctions.gamma(1 .+ x[1]),
"max" => x -> Base.max(x...),
"min" => x -> Base.min(x...),
"rem" => x -> Base.:rem(x...),
"gcd" => x -> Base.:gcd(x...),

"and" => x -> Base.:*(x...),
"or" => heaviside_or,
"xor" => x -> x[1]*(one(x[2])-x[2]) + (one(x[1])-x[1])*x[2],
"not" => x -> one(x[1]) - x[1],

# "and" => x -> Base.:&(x...),
# "or" => Base.:|,
# "xor" => Base.:⊻,
# "not" => Base.:!,

"abs" => x -> Base.abs(x...),
"conjugate" => Base.conj,
"arg" => Base.angle,
"real" => Base.real,
"imaginary" => Base.imag,
"lcm" => x -> Base.lcm(x...),

"floor" => x -> x[1] - frac(x[1]),
"ceiling" => x -> x[1] - frac(x[1]) + one(x[1]),
"round" => x -> x[1] + 0.5 - frac(x[1] + 0.5),

# "floor" => x -> Base.floor(x...),
# "ceiling" => x -> Base.ceil(x...),
# "round" => x -> Base.round(x...),

"inverse" => Base.inv,
"compose" => x -> Base.:(x...),
"ident" => Base.identity,
"approx" => x -> Base.:(x...),

"sin" => x -> Base.sin(x...),
"cos" => x -> Base.cos(x...),
"tan" => x -> Base.tan(x...),
"sec" => x -> Base.sec(x...),
"csc" => x -> Base.csc(x...),
"cot" => x -> Base.cot(x...),
"arcsin" => x -> Base.asin(x...),
"arccos" => x -> Base.acos(x...),
"arctan" => x -> Base.atan(x...),
"arcsec" => x -> Base.asec(x...),
"arccsc" => x -> Base.acsc(x...),
"arccot" => x -> Base.acot(x...),
"sinh" => x -> Base.sinh(x...),
"cosh" => x -> Base.cosh(x...),
"tanh" => x -> Base.tanh(x...),
"sech" => x -> Base.sech(x...),
"csch" => x -> Base.csch(x...),
"coth" => x -> Base.coth(x...),
"arcsinh" => x -> Base.asinh(x...),
"arccosh" => x -> Base.acosh(x...),
"arctanh" => x -> Base.atanh(x...),
"arcsech" => x -> Base.asech(x...),
"arccsch" => x -> Base.acsch(x...),
"arccoth" => x -> Base.acoth(x...),

"exp" => x -> Base.exp(x...),
"log" => x -> Base.log10(x...), # todo handle <logbase>
"ln" => x -> Base.log(x...),

"mean" => Statistics.mean,
"sdev" => Statistics.std,
"variance" => Statistics.var,
"median" => Statistics.median,
# "mode" => Statistics.mode, # crazy mode isn't in Base

"vector" => Base.identity,
"diff" => parse_diff,
"cn" => parse_diff,
# "apply" => x -> parse_apply(x) # this wont work because we pass the name which is string
)

tagmap = Dict{String,Function}(
"cn" => parse_cn,
"ci" => parse_ci,

"degree" => x -> parse_node(x.firstelement), # won't work for all cases
"bvar" => parse_bvar, # won't work for all cases

"piecewise" => parse_piecewise,

"apply" => parse_apply,
"math" => x -> map(parse_node, elements(x)),
"vector" => x -> map(parse_node, elements(x)),
"lambda" => parse_lambda,

# MathML defined constants
"pi" => x -> π,
"exponentiale" => x -> ℯ,
"notanumber" => x -> NaN,
"infinity" => x -> Inf,
"true" => x -> true,
"false" => x -> false,
)
applymap = Dict{String, Function}(
# eq sometimes needs to be ~ and sometimes needs to be =, not sure what the soln is
"eq" => x -> Symbolics.:~(x...), # arity 2,
"times" => Base.prod, # arity 2, but prod fine
# "prod" => Base.prod,
"divide" => x -> Base.:/(x...),
"power" => x -> Base.:^(x...),
"root" => custom_root,
"plus" => x -> Base.:+(x...),
"minus" => x -> Base.:-(x...),

# comparison functions implemented using the Heaviside function
"lt" => x -> H(x[2] - x[1] - ϵ),
"leq" => x -> H(x[2] - x[1]),
"geq" => x -> H(x[1] - x[2]),
"gt" => x -> H(x[1] - x[2] - ϵ),

# equal nodes are not part of the MathML specification and
# are generated by disambiguate_equality!
"equal" => x -> H(x[1] - x[2]) * H(x[2] - x[1]),
"neq" => x -> 1 - H(x[1] - x[2]) * H(x[2] - x[1]),

# "lt" => x -> Base.foldl(Base.:<, x),
# "leq" => x -> Base.foldl(Base.:≤, x),
# "geq" => x -> Base.foldl(Base.:≥, x),
# "gt" => x -> Base.foldl(Base.:>, x),

# "quotient" => x->Base.:div(x...), # broken, RoundingMode
"factorial" => x -> SpecialFunctions.gamma(1 .+ x[1]),
"max" => x -> Base.max(x...),
"min" => x -> Base.min(x...),
"rem" => x -> Base.:rem(x...),
"gcd" => x -> Base.:gcd(x...),
"and" => x -> Base.:*(x...),
"or" => heaviside_or,
"xor" => x -> x[1] * (one(x[2]) - x[2]) +
(one(x[1]) - x[1]) * x[2],
"not" => x -> one(x[1]) - x[1],

# "and" => x -> Base.:&(x...),
# "or" => Base.:|,
# "xor" => Base.:⊻,
# "not" => Base.:!,

"abs" => x -> Base.abs(x...),
"conjugate" => Base.conj,
"arg" => Base.angle,
"real" => Base.real,
"imaginary" => Base.imag,
"lcm" => x -> Base.lcm(x...),
"floor" => x -> x[1] - frac(x[1]),
"ceiling" => x -> x[1] - frac(x[1]) + one(x[1]),
"round" => x -> x[1] + 0.5 - frac(x[1] + 0.5),

# "floor" => x -> Base.floor(x...),
# "ceiling" => x -> Base.ceil(x...),
# "round" => x -> Base.round(x...),

"inverse" => Base.inv,
"compose" => x -> Base.:(x...),
"ident" => Base.identity,
"approx" => x -> Base.:(x...),
"sin" => x -> Base.sin(x...),
"cos" => x -> Base.cos(x...),
"tan" => x -> Base.tan(x...),
"sec" => x -> Base.sec(x...),
"csc" => x -> Base.csc(x...),
"cot" => x -> Base.cot(x...),
"arcsin" => x -> Base.asin(x...),
"arccos" => x -> Base.acos(x...),
"arctan" => x -> Base.atan(x...),
"arcsec" => x -> Base.asec(x...),
"arccsc" => x -> Base.acsc(x...),
"arccot" => x -> Base.acot(x...),
"sinh" => x -> Base.sinh(x...),
"cosh" => x -> Base.cosh(x...),
"tanh" => x -> Base.tanh(x...),
"sech" => x -> Base.sech(x...),
"csch" => x -> Base.csch(x...),
"coth" => x -> Base.coth(x...),
"arcsinh" => x -> Base.asinh(x...),
"arccosh" => x -> Base.acosh(x...),
"arctanh" => x -> Base.atanh(x...),
"arcsech" => x -> Base.asech(x...),
"arccsch" => x -> Base.acsch(x...),
"arccoth" => x -> Base.acoth(x...),
"exp" => x -> Base.exp(x...),
"log" => x -> Base.log10(x...), # todo handle <logbase>
"ln" => x -> Base.log(x...), "mean" => Statistics.mean,
"sdev" => Statistics.std,
"variance" => Statistics.var,
"median" => Statistics.median,
# "mode" => Statistics.mode, # crazy mode isn't in Base

"vector" => Base.identity,
"diff" => parse_diff,
"cn" => parse_diff
# "apply" => x -> parse_apply(x) # this wont work because we pass the name which is string
)

tagmap = Dict{String, Function}("cn" => parse_cn,
"ci" => parse_ci,
"degree" => x -> parse_node(x.firstelement), # won't work for all cases
"bvar" => parse_bvar, # won't work for all cases
"piecewise" => parse_piecewise, "apply" => parse_apply,
"math" => x -> map(parse_node, elements(x)),
"vector" => x -> map(parse_node, elements(x)),
"lambda" => parse_lambda,

# MathML defined constants
"pi" => x -> π,
"exponentiale" => x -> ℯ,
"notanumber" => x -> NaN,
"infinity" => x -> Inf,
"true" => x -> true,
"false" => x -> false)
6 changes: 4 additions & 2 deletions src/parse.jl
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ function process_pieces(pieces, otherwise)
node = pieces[1]
c = parse_node.(elements(node))
return IfElse.ifelse(c[2] > 0.5, c[1],
length(pieces)==1 ? otherwise : process_pieces(pieces[2:end], otherwise))
length(pieces) == 1 ? otherwise :
process_pieces(pieces[2:end], otherwise))
end

"""
Expand All @@ -107,7 +108,8 @@ parse an <apply> node into Symbolics form
how to deal w apply within apply, need to ensure we've hit bottom
"""
function parse_apply(node)
node.name != "apply" && error("calling parse_apply requires the name of the element to be `apply`")
node.name != "apply" &&
error("calling parse_apply requires the name of the element to be `apply`")
elms = elements(node)
cs = parse_node.(elms[2:end])
applymap[elms[1].name](cs)
Expand Down
4 changes: 3 additions & 1 deletion src/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,6 @@ end
H(x) = IfElse.ifelse(x >= 0, one(x), zero(x))
const ϵ = eps(Float64)
frac(x) = 0.5 - atan(cot* x)) / π
heaviside_or(x) = length(x) == 1 ? x[1] : x[1] + heaviside_or(x[2:end]) - x[1] * heaviside_or(x[2:end])
function heaviside_or(x)
length(x) == 1 ? x[1] : x[1] + heaviside_or(x[2:end]) - x[1] * heaviside_or(x[2:end])
end
15 changes: 7 additions & 8 deletions test/parse.jl
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ str = """<cn type="e-notation">5<sep/>2</cn>"""
@test isequal(MathML.parse_str(str), 500)

str = """<cn type="complex-polar"> 2 <sep/> 3.1415 </cn>"""
@test isapprox(MathML.parse_str(str), Complex(-2, 0), atol=1e-3)
@test isapprox(MathML.parse_str(str), Complex(-2, 0), atol = 1e-3)

str = """<cn type="complex-cartesian"> 12.3 <sep/> 5 </cn>"""
@test isequal(MathML.parse_str(str), Complex(12.3, 5))
Expand Down Expand Up @@ -97,15 +97,14 @@ str = """
</otherwise>
</piecewise>
"""
@test isequal(MathML.parse_str(str),
IfElse.ifelse(
IfElse.ifelse(1. - t >= 0, 1, 0) > 0.5,
x * (y + a * z) * ((1.0 - (b * z))^-1),
x * y))
@test isequal(MathML.parse_str(str),
IfElse.ifelse(IfElse.ifelse(1.0 - t >= 0, 1, 0) > 0.5,
x * (y + a * z) * ((1.0 - (b * z))^-1),
x * y))

# factorial
str = "<apply><factorial/><ci>x</ci></apply>"
@test isequal(MathML.parse_str(str), SpecialFunctions.gamma(1+x))
@test isequal(MathML.parse_str(str), SpecialFunctions.gamma(1 + x))

str = "<apply><factorial/><cn>5</cn></apply>"
@test MathML.parse_str(str) == 120
Expand Down Expand Up @@ -261,7 +260,7 @@ str = """
f = parse_str(str)
xml = parsexml(str).root
g = parse_lambda(xml)
@test g(3,5) == f(3,5) == [243]
@test g(3, 5) == f(3, 5) == [243]
@test isequal(f(x, y), [x^y])

# parse_apply with <ci> as firstelement problem
Expand Down
2 changes: 1 addition & 1 deletion test/sys.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ fn = "test/data/lorenz.xml"
xml = readxml(fn).root
eqs = parse_node(xml)
ODESystem(eqs)
@test !isnothing() # TODO
@test !isnothing() # TODO
2 changes: 1 addition & 1 deletion test/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ fn = "data/vinnakota_kemp_kushmeric_2006_exp45.cellml"
doc = readxml(fn)
docroot = doc.root
maths = extract_mathml(fn)
@test length(maths) == 24
@test length(maths) == 24

0 comments on commit d3f9ef1

Please sign in to comment.