Mercurial > repos > public > sbplib_julia
changeset 1019:3031ce7a4999 feature/stencil_set_type
Rename readoperator.jl to stencil_set.jl
author | Vidar Stiernström <vidar.stiernstrom@it.uu.se> |
---|---|
date | Tue, 22 Mar 2022 10:02:47 +0100 |
parents | 5ec49dd2c7c4 |
children | 99d1f5651d0b |
files | src/SbpOperators/SbpOperators.jl src/SbpOperators/readoperator.jl src/SbpOperators/stencil_set.jl test/SbpOperators/readoperator_test.jl test/SbpOperators/stencil_set_test.jl |
diffstat | 5 files changed, 337 insertions(+), 337 deletions(-) [+] |
line wrap: on
line diff
--- a/src/SbpOperators/SbpOperators.jl Tue Mar 22 09:57:28 2022 +0100 +++ b/src/SbpOperators/SbpOperators.jl Tue Mar 22 10:02:47 2022 +0100 @@ -30,7 +30,7 @@ end include("stencil.jl") -include("readoperator.jl") +include("stencil_set.jl") include("volumeops/volume_operator.jl") include("volumeops/constant_interior_scaling_operator.jl") include("volumeops/derivatives/first_derivative.jl")
--- a/src/SbpOperators/readoperator.jl Tue Mar 22 09:57:28 2022 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,164 +0,0 @@ -using TOML - - -""" - StencilSet - -A `StencilSet` contains a set of associated stencils. The stencils -are are stored in a table, and can be accesed by indexing into the `StencilSet`. -""" -struct StencilSet - table -end -Base.getindex(set::StencilSet,I...) = set.table[I...] - - -""" -read_stencil_set(filename; filters) - -Creates a `StencilSet` from a TOML file based on some key-value -filters. If more than one set matches the filters an error is raised. The -table of the `StencilSet` is a parsed TOML intended for functions like -`parse_scalar` and `parse_stencil`. - -The `StencilSet` table is not parsed beyond the inital TOML parse. To get usable -stencils use the `parse_stencil` functions on the fields of the stencil set. - -The reason for this is that since stencil sets are intended to be very -general, and currently do not include any way to specify how to parse a given -section, the exact parsing is left to the user. - -For more information see [Operator file format](@ref) in the documentation. - -See also [`StencilSet`](@ref), [`sbp_operators_path`](@ref), [`get_stencil_set`](@ref), [`parse_stencil`](@ref), [`parse_scalar`](@ref), [`parse_tuple`](@ref). -""" -read_stencil_set(filename; filters...) = StencilSet(get_stencil_set(TOML.parsefile(filename); filters...)) - - -""" - get_stencil_set(parsed_toml; filters...) - -Picks out a stencil set from an already parsed TOML based on some key-value -filters. - -See also [`read_stencil_set`](@ref). -""" -function get_stencil_set(parsed_toml; filters...) - matches = findall(parsed_toml["stencil_set"]) do set - for (key, val) ∈ filters - if set[string(key)] != val - return false - end - end - - return true - end - - if length(matches) != 1 - throw(ArgumentError("filters must pick out a single stencil set")) - end - - i = matches[1] - return parsed_toml["stencil_set"][i] -end - -""" - parse_stencil(parsed_toml) - -Accepts parsed TOML and reads it as a stencil. - -See also [`read_stencil_set`](@ref), [`parse_scalar`](@ref), [`parse_tuple`](@ref). -""" -function parse_stencil(parsed_toml) - check_stencil_toml(parsed_toml) - - if parsed_toml isa Array - weights = parse_rational.(parsed_toml) - return CenteredStencil(weights...) - end - - weights = parse_rational.(parsed_toml["s"]) - return Stencil(weights..., center = parsed_toml["c"]) -end - -""" - parse_stencil(T, parsed_toml) - -Parses the input as a stencil with element type `T`. -""" -parse_stencil(T, parsed_toml) = Stencil{T}(parse_stencil(parsed_toml)) - -function check_stencil_toml(parsed_toml) - if !(parsed_toml isa Dict || parsed_toml isa Vector{String}) - throw(ArgumentError("the TOML for a stencil must be a vector of strings or a table.")) - end - - if parsed_toml isa Vector{String} - return - end - - if !(haskey(parsed_toml, "s") && haskey(parsed_toml, "c")) - throw(ArgumentError("the table form of a stencil must have fields `s` and `c`.")) - end - - if !(parsed_toml["s"] isa Vector{String}) - throw(ArgumentError("a stencil must be specified as a vector of strings.")) - end - - if !(parsed_toml["c"] isa Int) - throw(ArgumentError("the center of a stencil must be specified as an integer.")) - end -end - -""" - parse_scalar(parsed_toml) - -Parse a scalar, represented as a string or a number in the TOML, and return it as a `Rational` - -See also [`read_stencil_set`](@ref), [`parse_stencil`](@ref) [`parse_tuple`](@ref). -""" -function parse_scalar(parsed_toml) - try - return parse_rational(parsed_toml) - catch e - throw(ArgumentError("must be a number or a string representing a number.")) - end -end - -""" - parse_tuple(parsed_toml) - -Parse an array as a tuple of scalars. - -See also [`read_stencil_set`](@ref), [`parse_stencil`](@ref), [`parse_scalar`](@ref). -""" -function parse_tuple(parsed_toml) - if !(parsed_toml isa Array) - throw(ArgumentError("argument must be an array")) - end - return Tuple(parse_scalar.(parsed_toml)) -end - - -""" - parse_rational(parsed_toml) - -Parse a string or a number as a rational. -""" -function parse_rational(parsed_toml) - if parsed_toml isa String - expr = Meta.parse(replace(parsed_toml, "/"=>"//")) - return eval(:(Rational($expr))) - else - return Rational(parsed_toml) - end -end - -""" - sbp_operators_path() - -Calculate the path for the operators folder with included stencil sets. - -See also [`StencilSet`](@ref), [`read_stencil_set`](@ref). -""" -sbp_operators_path() = (@__DIR__) * "/operators/"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/SbpOperators/stencil_set.jl Tue Mar 22 10:02:47 2022 +0100 @@ -0,0 +1,164 @@ +using TOML + + +""" + StencilSet + +A `StencilSet` contains a set of associated stencils. The stencils +are are stored in a table, and can be accesed by indexing into the `StencilSet`. +""" +struct StencilSet + table +end +Base.getindex(set::StencilSet,I...) = set.table[I...] + + +""" +read_stencil_set(filename; filters) + +Creates a `StencilSet` from a TOML file based on some key-value +filters. If more than one set matches the filters an error is raised. The +table of the `StencilSet` is a parsed TOML intended for functions like +`parse_scalar` and `parse_stencil`. + +The `StencilSet` table is not parsed beyond the inital TOML parse. To get usable +stencils use the `parse_stencil` functions on the fields of the stencil set. + +The reason for this is that since stencil sets are intended to be very +general, and currently do not include any way to specify how to parse a given +section, the exact parsing is left to the user. + +For more information see [Operator file format](@ref) in the documentation. + +See also [`StencilSet`](@ref), [`sbp_operators_path`](@ref), [`get_stencil_set`](@ref), [`parse_stencil`](@ref), [`parse_scalar`](@ref), [`parse_tuple`](@ref). +""" +read_stencil_set(filename; filters...) = StencilSet(get_stencil_set(TOML.parsefile(filename); filters...)) + + +""" + get_stencil_set(parsed_toml; filters...) + +Picks out a stencil set from an already parsed TOML based on some key-value +filters. + +See also [`read_stencil_set`](@ref). +""" +function get_stencil_set(parsed_toml; filters...) + matches = findall(parsed_toml["stencil_set"]) do set + for (key, val) ∈ filters + if set[string(key)] != val + return false + end + end + + return true + end + + if length(matches) != 1 + throw(ArgumentError("filters must pick out a single stencil set")) + end + + i = matches[1] + return parsed_toml["stencil_set"][i] +end + +""" + parse_stencil(parsed_toml) + +Accepts parsed TOML and reads it as a stencil. + +See also [`read_stencil_set`](@ref), [`parse_scalar`](@ref), [`parse_tuple`](@ref). +""" +function parse_stencil(parsed_toml) + check_stencil_toml(parsed_toml) + + if parsed_toml isa Array + weights = parse_rational.(parsed_toml) + return CenteredStencil(weights...) + end + + weights = parse_rational.(parsed_toml["s"]) + return Stencil(weights..., center = parsed_toml["c"]) +end + +""" + parse_stencil(T, parsed_toml) + +Parses the input as a stencil with element type `T`. +""" +parse_stencil(T, parsed_toml) = Stencil{T}(parse_stencil(parsed_toml)) + +function check_stencil_toml(parsed_toml) + if !(parsed_toml isa Dict || parsed_toml isa Vector{String}) + throw(ArgumentError("the TOML for a stencil must be a vector of strings or a table.")) + end + + if parsed_toml isa Vector{String} + return + end + + if !(haskey(parsed_toml, "s") && haskey(parsed_toml, "c")) + throw(ArgumentError("the table form of a stencil must have fields `s` and `c`.")) + end + + if !(parsed_toml["s"] isa Vector{String}) + throw(ArgumentError("a stencil must be specified as a vector of strings.")) + end + + if !(parsed_toml["c"] isa Int) + throw(ArgumentError("the center of a stencil must be specified as an integer.")) + end +end + +""" + parse_scalar(parsed_toml) + +Parse a scalar, represented as a string or a number in the TOML, and return it as a `Rational` + +See also [`read_stencil_set`](@ref), [`parse_stencil`](@ref) [`parse_tuple`](@ref). +""" +function parse_scalar(parsed_toml) + try + return parse_rational(parsed_toml) + catch e + throw(ArgumentError("must be a number or a string representing a number.")) + end +end + +""" + parse_tuple(parsed_toml) + +Parse an array as a tuple of scalars. + +See also [`read_stencil_set`](@ref), [`parse_stencil`](@ref), [`parse_scalar`](@ref). +""" +function parse_tuple(parsed_toml) + if !(parsed_toml isa Array) + throw(ArgumentError("argument must be an array")) + end + return Tuple(parse_scalar.(parsed_toml)) +end + + +""" + parse_rational(parsed_toml) + +Parse a string or a number as a rational. +""" +function parse_rational(parsed_toml) + if parsed_toml isa String + expr = Meta.parse(replace(parsed_toml, "/"=>"//")) + return eval(:(Rational($expr))) + else + return Rational(parsed_toml) + end +end + +""" + sbp_operators_path() + +Calculate the path for the operators folder with included stencil sets. + +See also [`StencilSet`](@ref), [`read_stencil_set`](@ref). +""" +sbp_operators_path() = (@__DIR__) * "/operators/"
--- a/test/SbpOperators/readoperator_test.jl Tue Mar 22 09:57:28 2022 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,172 +0,0 @@ -using Test - -using TOML -using Sbplib.SbpOperators - -import Sbplib.SbpOperators.Stencil - -@testset "readoperator" begin - toml_str = """ - [meta] - authors = "Ken Mattson" - description = "Standard operators for equidistant grids" - type = "equidistant" - cite = "A paper a long time ago in a galaxy far far away." - - [[stencil_set]] - - order = 2 - test = 2 - - H.inner = ["1"] - H.closure = ["1/2"] - - D1.inner_stencil = ["-1/2", "0", "1/2"] - D1.closure_stencils = [ - {s = ["-1", "1"], c = 1}, - ] - - D2.inner_stencil = ["1", "-2", "1"] - D2.closure_stencils = [ - {s = ["1", "-2", "1"], c = 1}, - ] - - e.closure = ["1"] - d1.closure = {s = ["-3/2", "2", "-1/2"], c = 1} - - [[stencil_set]] - - order = 4 - test = 1 - H.inner = ["1"] - H.closure = ["17/48", "59/48", "43/48", "49/48"] - - D2.inner_stencil = ["-1/12","4/3","-5/2","4/3","-1/12"] - D2.closure_stencils = [ - {s = [ "2", "-5", "4", "-1", "0", "0"], c = 1}, - {s = [ "1", "-2", "1", "0", "0", "0"], c = 2}, - {s = [ "-4/43", "59/43", "-110/43", "59/43", "-4/43", "0"], c = 3}, - {s = [ "-1/49", "0", "59/49", "-118/49", "64/49", "-4/49"], c = 4}, - ] - - e.closure = ["1"] - d1.closure = {s = ["-11/6", "3", "-3/2", "1/3"], c = 1} - - [[stencil_set]] - order = 4 - test = 2 - - H.closure = ["-1/49", "0", "59/49", "-118/49", "64/49", "-4/49"] - """ - - parsed_toml = TOML.parse(toml_str) - - @testset "get_stencil_set" begin - @test get_stencil_set(parsed_toml; order = 2) isa Dict - @test get_stencil_set(parsed_toml; order = 2) == parsed_toml["stencil_set"][1] - @test get_stencil_set(parsed_toml; test = 1) == parsed_toml["stencil_set"][2] - @test get_stencil_set(parsed_toml; order = 4, test = 2) == parsed_toml["stencil_set"][3] - - @test_throws ArgumentError get_stencil_set(parsed_toml; test = 2) - @test_throws ArgumentError get_stencil_set(parsed_toml; order = 4) - end - - @testset "parse_stencil" begin - toml = """ - s1 = ["-1/12","4/3","-5/2","4/3","-1/12"] - s2 = {s = ["2", "-5", "4", "-1", "0", "0"], c = 1} - s3 = {s = ["1", "-2", "1", "0", "0", "0"], c = 2} - s4 = "not a stencil" - s5 = [-1, 4, 3] - s6 = {k = ["1", "-2", "1", "0", "0", "0"], c = 2} - s7 = {s = [-1, 4, 3], c = 2} - s8 = {s = ["1", "-2", "1", "0", "0", "0"], c = [2,2]} - """ - - @test parse_stencil(TOML.parse(toml)["s1"]) == CenteredStencil(-1//12, 4//3, -5//2, 4//3, -1//12) - @test parse_stencil(TOML.parse(toml)["s2"]) == Stencil(2//1, -5//1, 4//1, -1//1, 0//1, 0//1; center=1) - @test parse_stencil(TOML.parse(toml)["s3"]) == Stencil(1//1, -2//1, 1//1, 0//1, 0//1, 0//1; center=2) - - @test_throws ArgumentError parse_stencil(TOML.parse(toml)["s4"]) - @test_throws ArgumentError parse_stencil(TOML.parse(toml)["s5"]) - @test_throws ArgumentError parse_stencil(TOML.parse(toml)["s6"]) - @test_throws ArgumentError parse_stencil(TOML.parse(toml)["s7"]) - @test_throws ArgumentError parse_stencil(TOML.parse(toml)["s8"]) - - stencil_set = get_stencil_set(parsed_toml; order = 4, test = 1) - - @test parse_stencil.(stencil_set["D2"]["closure_stencils"]) == [ - Stencil( 2//1, -5//1, 4//1, -1//1, 0//1, 0//1; center=1), - Stencil( 1//1, -2//1, 1//1, 0//1, 0//1, 0//1; center=2), - Stencil(-4//43, 59//43, -110//43, 59//43, -4//43, 0//1; center=3), - Stencil(-1//49, 0//1, 59//49, -118//49, 64//49, -4//49; center=4), - ] - - - @test parse_stencil(Float64, TOML.parse(toml)["s1"]) == CenteredStencil(-1/12, 4/3, -5/2, 4/3, -1/12) - @test parse_stencil(Float64, TOML.parse(toml)["s2"]) == Stencil(2/1, -5/1, 4/1, -1/1, 0/1, 0/1; center=1) - @test parse_stencil(Float64, TOML.parse(toml)["s3"]) == Stencil(1/1, -2/1, 1/1, 0/1, 0/1, 0/1; center=2) - end - - @testset "parse_scalar" begin - toml = TOML.parse(""" - a1 = 1 - a2 = 1.5 - a3 = 1.0 - a4 = 10 - a5 = "1/2" - a6 = "1.5" - - e1 = [1,2,3] - e2 = "a string value" - """) - - @test parse_scalar(toml["a1"]) == 1//1 - @test parse_scalar(toml["a2"]) == 3//2 - @test parse_scalar(toml["a3"]) == 1//1 - @test parse_scalar(toml["a4"]) == 10//1 - @test parse_scalar(toml["a5"]) == 1//2 - @test parse_scalar(toml["a6"]) == 3//2 - - @test_throws ArgumentError parse_scalar(toml["e1"]) - @test_throws ArgumentError parse_scalar(toml["e2"]) - end - - @testset "parse_tuple" begin - toml = TOML.parse(""" - t1 = [1,3,4] - t2 = ["1/2","3/4","2/1"] - - e1 = "not a tuple" - e2.a="1" - e3 = 1 - e4 = ["1/2","3/4","not a number"] - """) - - @test parse_tuple(toml["t1"]) == (1//1,3//1,4//1) - @test parse_tuple(toml["t2"]) == (1//2,3//4,2//1) - - @test_throws ArgumentError parse_tuple(toml["e1"]) - @test_throws ArgumentError parse_tuple(toml["e2"]) - @test_throws ArgumentError parse_tuple(toml["e3"]) - @test_throws ArgumentError parse_tuple(toml["e4"]) - end -end - -@testset "parse_rational" begin - @test SbpOperators.parse_rational("1") isa Rational - @test SbpOperators.parse_rational("1") == 1//1 - @test SbpOperators.parse_rational("1/2") isa Rational - @test SbpOperators.parse_rational("1/2") == 1//2 - @test SbpOperators.parse_rational("37/13") isa Rational - @test SbpOperators.parse_rational("37/13") == 37//13 - - @test SbpOperators.parse_rational(0.5) isa Rational - @test SbpOperators.parse_rational(0.5) == 1//2 - - @test SbpOperators.parse_rational("0.5") isa Rational - @test SbpOperators.parse_rational("0.5") == 1//2 - - @test SbpOperators.parse_rational(2) isa Rational - @test SbpOperators.parse_rational(2) == 2//1 -end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/SbpOperators/stencil_set_test.jl Tue Mar 22 10:02:47 2022 +0100 @@ -0,0 +1,172 @@ +using Test + +using TOML +using Sbplib.SbpOperators + +import Sbplib.SbpOperators.Stencil + +@testset "readoperator" begin + toml_str = """ + [meta] + authors = "Ken Mattson" + description = "Standard operators for equidistant grids" + type = "equidistant" + cite = "A paper a long time ago in a galaxy far far away." + + [[stencil_set]] + + order = 2 + test = 2 + + H.inner = ["1"] + H.closure = ["1/2"] + + D1.inner_stencil = ["-1/2", "0", "1/2"] + D1.closure_stencils = [ + {s = ["-1", "1"], c = 1}, + ] + + D2.inner_stencil = ["1", "-2", "1"] + D2.closure_stencils = [ + {s = ["1", "-2", "1"], c = 1}, + ] + + e.closure = ["1"] + d1.closure = {s = ["-3/2", "2", "-1/2"], c = 1} + + [[stencil_set]] + + order = 4 + test = 1 + H.inner = ["1"] + H.closure = ["17/48", "59/48", "43/48", "49/48"] + + D2.inner_stencil = ["-1/12","4/3","-5/2","4/3","-1/12"] + D2.closure_stencils = [ + {s = [ "2", "-5", "4", "-1", "0", "0"], c = 1}, + {s = [ "1", "-2", "1", "0", "0", "0"], c = 2}, + {s = [ "-4/43", "59/43", "-110/43", "59/43", "-4/43", "0"], c = 3}, + {s = [ "-1/49", "0", "59/49", "-118/49", "64/49", "-4/49"], c = 4}, + ] + + e.closure = ["1"] + d1.closure = {s = ["-11/6", "3", "-3/2", "1/3"], c = 1} + + [[stencil_set]] + order = 4 + test = 2 + + H.closure = ["-1/49", "0", "59/49", "-118/49", "64/49", "-4/49"] + """ + + parsed_toml = TOML.parse(toml_str) + + @testset "get_stencil_set" begin + @test get_stencil_set(parsed_toml; order = 2) isa Dict + @test get_stencil_set(parsed_toml; order = 2) == parsed_toml["stencil_set"][1] + @test get_stencil_set(parsed_toml; test = 1) == parsed_toml["stencil_set"][2] + @test get_stencil_set(parsed_toml; order = 4, test = 2) == parsed_toml["stencil_set"][3] + + @test_throws ArgumentError get_stencil_set(parsed_toml; test = 2) + @test_throws ArgumentError get_stencil_set(parsed_toml; order = 4) + end + + @testset "parse_stencil" begin + toml = """ + s1 = ["-1/12","4/3","-5/2","4/3","-1/12"] + s2 = {s = ["2", "-5", "4", "-1", "0", "0"], c = 1} + s3 = {s = ["1", "-2", "1", "0", "0", "0"], c = 2} + s4 = "not a stencil" + s5 = [-1, 4, 3] + s6 = {k = ["1", "-2", "1", "0", "0", "0"], c = 2} + s7 = {s = [-1, 4, 3], c = 2} + s8 = {s = ["1", "-2", "1", "0", "0", "0"], c = [2,2]} + """ + + @test parse_stencil(TOML.parse(toml)["s1"]) == CenteredStencil(-1//12, 4//3, -5//2, 4//3, -1//12) + @test parse_stencil(TOML.parse(toml)["s2"]) == Stencil(2//1, -5//1, 4//1, -1//1, 0//1, 0//1; center=1) + @test parse_stencil(TOML.parse(toml)["s3"]) == Stencil(1//1, -2//1, 1//1, 0//1, 0//1, 0//1; center=2) + + @test_throws ArgumentError parse_stencil(TOML.parse(toml)["s4"]) + @test_throws ArgumentError parse_stencil(TOML.parse(toml)["s5"]) + @test_throws ArgumentError parse_stencil(TOML.parse(toml)["s6"]) + @test_throws ArgumentError parse_stencil(TOML.parse(toml)["s7"]) + @test_throws ArgumentError parse_stencil(TOML.parse(toml)["s8"]) + + stencil_set = get_stencil_set(parsed_toml; order = 4, test = 1) + + @test parse_stencil.(stencil_set["D2"]["closure_stencils"]) == [ + Stencil( 2//1, -5//1, 4//1, -1//1, 0//1, 0//1; center=1), + Stencil( 1//1, -2//1, 1//1, 0//1, 0//1, 0//1; center=2), + Stencil(-4//43, 59//43, -110//43, 59//43, -4//43, 0//1; center=3), + Stencil(-1//49, 0//1, 59//49, -118//49, 64//49, -4//49; center=4), + ] + + + @test parse_stencil(Float64, TOML.parse(toml)["s1"]) == CenteredStencil(-1/12, 4/3, -5/2, 4/3, -1/12) + @test parse_stencil(Float64, TOML.parse(toml)["s2"]) == Stencil(2/1, -5/1, 4/1, -1/1, 0/1, 0/1; center=1) + @test parse_stencil(Float64, TOML.parse(toml)["s3"]) == Stencil(1/1, -2/1, 1/1, 0/1, 0/1, 0/1; center=2) + end + + @testset "parse_scalar" begin + toml = TOML.parse(""" + a1 = 1 + a2 = 1.5 + a3 = 1.0 + a4 = 10 + a5 = "1/2" + a6 = "1.5" + + e1 = [1,2,3] + e2 = "a string value" + """) + + @test parse_scalar(toml["a1"]) == 1//1 + @test parse_scalar(toml["a2"]) == 3//2 + @test parse_scalar(toml["a3"]) == 1//1 + @test parse_scalar(toml["a4"]) == 10//1 + @test parse_scalar(toml["a5"]) == 1//2 + @test parse_scalar(toml["a6"]) == 3//2 + + @test_throws ArgumentError parse_scalar(toml["e1"]) + @test_throws ArgumentError parse_scalar(toml["e2"]) + end + + @testset "parse_tuple" begin + toml = TOML.parse(""" + t1 = [1,3,4] + t2 = ["1/2","3/4","2/1"] + + e1 = "not a tuple" + e2.a="1" + e3 = 1 + e4 = ["1/2","3/4","not a number"] + """) + + @test parse_tuple(toml["t1"]) == (1//1,3//1,4//1) + @test parse_tuple(toml["t2"]) == (1//2,3//4,2//1) + + @test_throws ArgumentError parse_tuple(toml["e1"]) + @test_throws ArgumentError parse_tuple(toml["e2"]) + @test_throws ArgumentError parse_tuple(toml["e3"]) + @test_throws ArgumentError parse_tuple(toml["e4"]) + end +end + +@testset "parse_rational" begin + @test SbpOperators.parse_rational("1") isa Rational + @test SbpOperators.parse_rational("1") == 1//1 + @test SbpOperators.parse_rational("1/2") isa Rational + @test SbpOperators.parse_rational("1/2") == 1//2 + @test SbpOperators.parse_rational("37/13") isa Rational + @test SbpOperators.parse_rational("37/13") == 37//13 + + @test SbpOperators.parse_rational(0.5) isa Rational + @test SbpOperators.parse_rational(0.5) == 1//2 + + @test SbpOperators.parse_rational("0.5") isa Rational + @test SbpOperators.parse_rational("0.5") == 1//2 + + @test SbpOperators.parse_rational(2) isa Rational + @test SbpOperators.parse_rational(2) == 2//1 +end