From 28d476729a5a69751b3a4d1e1672483c81d4b90b Mon Sep 17 00:00:00 2001 From: Chris Rackauckas Date: Thu, 23 Jun 2022 14:35:08 -0400 Subject: [PATCH] Format SciML Style --- .JuliaFormatter.toml | 12 ++ .github/workflows/FormatCheck.yml | 42 ++++++ docs/make.jl | 8 +- src/MathML.jl | 2 +- src/maps.jl | 235 ++++++++++++++---------------- src/parse.jl | 23 +-- src/utils.jl | 21 +-- test/parse.jl | 21 ++- test/runtests.jl | 12 +- test/sys.jl | 2 +- test/utils.jl | 2 +- 11 files changed, 210 insertions(+), 170 deletions(-) create mode 100644 .JuliaFormatter.toml create mode 100644 .github/workflows/FormatCheck.yml diff --git a/.JuliaFormatter.toml b/.JuliaFormatter.toml new file mode 100644 index 0000000..724808e --- /dev/null +++ b/.JuliaFormatter.toml @@ -0,0 +1,12 @@ +style = "yas" +indent = 4 +margin = 100 +always_for_in = true +whitespace_ops_in_indices = true +whitespace_typedefs = false +remove_extra_newlines = true +import_to_using = true +pipe_to_function_call = false +short_to_long_function_def = false +always_use_return = true +whitespace_in_kwargs = true \ No newline at end of file diff --git a/.github/workflows/FormatCheck.yml b/.github/workflows/FormatCheck.yml new file mode 100644 index 0000000..2a3517a --- /dev/null +++ b/.github/workflows/FormatCheck.yml @@ -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' diff --git a/docs/make.jl b/docs/make.jl index aae2ae9..747c6d9 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -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", -) \ No newline at end of file +deploydocs(; repo = "github.com/anandijain/MathML.jl.git", + devbranch = "main") diff --git a/src/MathML.jl b/src/MathML.jl index 3d025a4..983a275 100644 --- a/src/MathML.jl +++ b/src/MathML.jl @@ -5,7 +5,7 @@ module MathML using DocStringExtensions using EzXML, Symbolics, Statistics, IfElse, AbstractTrees -import SpecialFunctions +using SpecialFunctions: SpecialFunctions include("utils.jl") include("parse.jl") diff --git a/src/maps.jl b/src/maps.jl index 0c6c03a..58ab431 100644 --- a/src/maps.jl +++ b/src/maps.jl @@ -2,129 +2,112 @@ # 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 - "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, -) + # 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 + "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) diff --git a/src/parse.jl b/src/parse.jl index 8a0b561..bab3690 100644 --- a/src/parse.jl +++ b/src/parse.jl @@ -4,22 +4,22 @@ take a node and parse into Symbolics form """ function parse_node(node) - tagmap[node.name](node) + return tagmap[node.name](node) end function parse_str(str) doc = parsexml(str) - parse_doc(doc) + return parse_doc(doc) end function parse_doc(doc) node = doc.root - parse_node(node) + return parse_node(node) end function parse_file(fn) node = readxml(fn).root - parse_node(node) + return parse_node(node) end """ @@ -73,7 +73,7 @@ parse a node function parse_ci(node) # c = Symbol(Meta.parse(strip(node.content))) c = Symbol(string(strip(node.content))) - (@variables $c)[1] + return (@variables $c)[1] end ########## Parse piecewise ################################################### @@ -96,7 +96,7 @@ 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 """ @@ -107,10 +107,11 @@ parse an 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) + return applymap[elms[1].name](cs) end """ @@ -120,7 +121,7 @@ parse a node """ function parse_bvar(node) es = elements(node) - length(es) == 1 ? (parse_node(es[1]), 1) : Tuple(parse_node.(es)) + return length(es) == 1 ? (parse_node(es[1]), 1) : Tuple(parse_node.(es)) end """ @@ -134,7 +135,7 @@ function parse_diff(a) deg = trunc(Int, deg) # num = Num(Symbolics.Sym{Symbolics.FnType{Tuple{Real},Real}}(Symbol(x))(iv)) D = Differential(iv)^deg - D(x) + return D(x) end """ @@ -157,5 +158,5 @@ function parse_lambda(node) args = first.(parse_bvar.(vars)) num = parse_apply(es[end]) - eval(build_function([num], args...)[1]) + return eval(build_function([num], args...)[1]) end diff --git a/src/utils.jl b/src/utils.jl index 89e3d9c..6f733c2 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -12,12 +12,12 @@ function mathml_to_nums end function mathml_to_nums(fn::AbstractString) doc = readxml(fn) - mathml_to_nums(doc) + return mathml_to_nums(doc) end function mathml_to_nums(xml::EzXML.Document) doc_root = EzXML.root(xml) - mathml_to_nums(doc_root) + return mathml_to_nums(doc_root) end """ @@ -29,16 +29,16 @@ returns all of the MathML nodes. function extract_mathml end function extract_mathml(fn::AbstractString) - extract_mathml(readxml(fn)) + return extract_mathml(readxml(fn)) end function extract_mathml(doc::EzXML.Document) - extract_mathml(EzXML.root(doc)) + return extract_mathml(EzXML.root(doc)) end function extract_mathml(node::EzXML.Node) disambiguate_equality!(node) - findall("//x:math", node, ["x" => mathml_ns]) + return findall("//x:math", node, ["x" => mathml_ns]) end """ @@ -60,7 +60,7 @@ end utility macro for parsing xml strings into node """ macro xml_str(s) - parsexml(s).root + return parsexml(s).root end """ @@ -69,7 +69,7 @@ end utility macro for parsing xml strings into symbolics """ macro MathML_str(s) - MathML.parse_str(s) + return MathML.parse_str(s) end # bindings for viewing call tree @@ -78,17 +78,18 @@ AbstractTrees.printnode(io::IO, node::EzXML.Node) = print(io, getproperty(node, AbstractTrees.nodetype(::EzXML.Node) = EzXML.Node function custom_root(x) - length(x) == 1 ? sqrt(x...) : Base.:^(x[2], x[1]) + return length(x) == 1 ? sqrt(x...) : Base.:^(x[2], x[1]) end "ensure theres only one independent variable, returns false if more than one iv" function check_ivs(node) x = findall("//x:bvar", node, ["x" => MathML.mathml_ns]) - all(y -> y.content == x[1].content, x) + return all(y -> y.content == x[1].content, x) end # conditional and rounding hacks 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]) +heaviside_or(x) = length(x) == 1 ? x[1] : + x[1] + heaviside_or(x[2:end]) - x[1] * heaviside_or(x[2:end]) diff --git a/test/parse.jl b/test/parse.jl index 2603888..cac5c9d 100644 --- a/test/parse.jl +++ b/test/parse.jl @@ -12,10 +12,8 @@ fn = "data/eq.xml" doc = readxml(fn) eqs = MathML.parse_node(doc.root) @variables T I Par_94 Par_90 -true_eqs = [ - T ~ Par_94, - I ~ Par_90, -] +true_eqs = [T ~ Par_94, + I ~ Par_90] @test isequal(eqs, true_eqs) @variables w x y z a b t @@ -30,7 +28,7 @@ str = """52""" @test isequal(MathML.parse_str(str), 500) str = """ 2 3.1415 """ -@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 = """ 12.3 5 """ @test isequal(MathML.parse_str(str), Complex(12.3, 5)) @@ -97,15 +95,14 @@ str = """ """ -@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 = "x" -@test isequal(MathML.parse_str(str), SpecialFunctions.gamma(1+x)) +@test isequal(MathML.parse_str(str), SpecialFunctions.gamma(1 + x)) str = "5" @test MathML.parse_str(str) == 120 @@ -261,7 +258,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 as firstelement problem diff --git a/test/runtests.jl b/test/runtests.jl index 1229137..7007ed7 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,8 +1,14 @@ using MathML, EzXML, Symbolics, SpecialFunctions, IfElse, AbstractTrees, Test @testset "MathML.jl" begin - @testset "parsing" begin include("parse.jl") end - @testset "utils" begin include("utils.jl") end - @testset "print" begin include("print.jl") end + @testset "parsing" begin + include("parse.jl") + end + @testset "utils" begin + include("utils.jl") + end + @testset "print" begin + include("print.jl") + end # @testset "systems" begin include("sys.jl") end end diff --git a/test/sys.jl b/test/sys.jl index 3d82ff9..c08e353 100644 --- a/test/sys.jl +++ b/test/sys.jl @@ -3,4 +3,4 @@ fn = "test/data/lorenz.xml" xml = readxml(fn).root eqs = parse_node(xml) ODESystem(eqs) -@test !isnothing() # TODO \ No newline at end of file +@test !isnothing() # TODO diff --git a/test/utils.jl b/test/utils.jl index 7c12268..aa8e2e4 100644 --- a/test/utils.jl +++ b/test/utils.jl @@ -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 \ No newline at end of file +@test length(maths) == 24