From fd31083fdf1180c93845f4a898e3fd6658765a37 Mon Sep 17 00:00:00 2001 From: Shashi Gowda Date: Sun, 26 Apr 2020 17:41:59 -0400 Subject: [PATCH] Variable, vars -> Sym, syms --- README.md | 34 ++++++++++++------------- src/SymbolicUtils.jl | 2 +- src/methods.jl | 4 +-- src/rule_dsl.jl | 4 +-- src/simplify.jl | 6 ++--- src/types.jl | 59 ++++++++++++++++++++++---------------------- test/basics.jl | 16 ++++++------ test/fuzz.jl | 6 ++--- test/interface.jl | 8 +++--- test/order.jl | 2 +- test/rewrite.jl | 2 +- test/rulesets.jl | 12 ++++----- 12 files changed, 78 insertions(+), 77 deletions(-) diff --git a/README.md b/README.md index 218ce006f..3e041f202 100644 --- a/README.md +++ b/README.md @@ -4,27 +4,27 @@ SymbolicUtils.jl provides various utilities for symbolic computing. [![Build Status](https://travis-ci.org/JuliaSymbolics/SymbolicUtils.jl.svg?branch=master)](https://travis-ci.com/github/JuliaSymbolics/SymbolicUtils.jl) [![Coverage Status](https://coveralls.io/repos/github/JuliaSymbolics/SymbolicUtils.jl/badge.svg?branch=master)](https://coveralls.io/github/JuliaSymbolics/SymbolicUtils.jl?branch=master) -## Variables and expressions +## Symbols and expressions -Symbolic variables can be created using the `@vars` macro: +Symbols can be created using the `@syms` macro: ```julia julia> using SymbolicUtils -julia> @vars a::Integer b c d x::Real y::Number +julia> @syms a::Integer b c d x::Real y::Number (a, b, c, d, x, y) ``` -This macro also defines the Julia variables of the same name and each is set to the its respective symbolic variable object. +This macro also defines the Julia variables of the same name and each is set to the its respective symbolic object. -The associated type `T` in the `@vars a::T` syntax, called `symtype` of the variable, is the type the value of the variable is supposed to be of. These types may determine the rules of symbolic simplification. +The associated type `T` in the `@syms a::T` syntax, called `symtype` of the symbol, is the type the value of the symbol is supposed to be of. These types may determine the rules of symbolic simplification. -Arithmetic and math functions are defined on variables and return `Term` objects which represent function call expressions. +Arithmetic and math functions are defined on symbols and return `Term` objects which represent function call expressions. -Variables can be defined to behave like functions. Both the input and output types for the function can be specified. Any application to that function will only admit either values of those types or symbolic variables of the same `symtype`. +Symbols can be defined to behave like functions. Both the input and output types for the function can be specified. Any application to that function will only admit either values of those types or symbols of the same `symtype`. ```julia -julia> @vars f(x) g(x::Real, y::Real)::Real +julia> @syms f(x) g(x::Real, y::Real)::Real (f(::Number)::Number, g(::Real, ::Real)::Real) julia> f(c) @@ -67,7 +67,7 @@ _Example:_ Simple rule to turn any `sin` into `cos`: ```julia -julia> @vars a b c +julia> @syms a b c (a, b, c) julia> r = @rule sin(~x) => cos(~x) @@ -153,7 +153,7 @@ is equivalent to `f(x, y, z, u, v, w)` and commutative if the order of arguments SymbolicUtils has a special `@acrule` macro meant for rules on functions which are associate and commutative such as addition and multiplication of real and complex numbers. ```julia -julia> @vars x y +julia> @syms x y (x, y) julia> acr = @acrule((~y)^(~n) * ~y => (~y)^(~n+1)) @@ -169,7 +169,7 @@ Rules are applied to an entire term, they do not see sub-terms ```julia julia> using SymbolicUtils -julia> @vars x y +julia> @syms x y (x, y) julia> r = @rule sin(~x) => cos(~x) @@ -233,7 +233,7 @@ Called only if `istree(x)` is `true`. Part of the API required for `simplify` to work. Other required methods are `operation` and `istree` #### `to_symbolic(x::S)` -Convert your variable type to a `SymbolicUtils.Variable`. Suppose you have +Convert your variable type to a `SymbolicUtils.Sym`. Suppose you have ```julia struct MySymbol s::Symbol @@ -241,7 +241,7 @@ end ``` which could represent any type symbolically, then you would define ```julia -SymbolicUtils.to_symbolic(s::MySymbol) = SymbolicUtils.Variable(s.s) +SymbolicUtils.to_symbolic(s::MySymbol) = SymbolicUtils.Sym(s.s) ``` ### Optional @@ -283,12 +283,12 @@ julia> ex = 1 + (:x - 2) How can we use SymbolicUtils.jl to convert `ex` to `(-)(:x, 1)`? We simply implement `istree`, `operation`, `arguments` and `to_symbolic` and we'll be off to the races: ```julia -using SymbolicUtils: Variable, istree, operation, arguments, to_symbolic +using SymbolicUtils: Sym, istree, operation, arguments, to_symbolic SymbolicUtils.istree(ex::Expr) = ex.head == :call SymbolicUtils.operation(ex::Expr) = ex.args[1] SymbolicUtils.arguments(ex::Expr) = ex.args[2:end] -SymbolicUtils.to_symbolic(s::Symbol) = Variable(s) +SymbolicUtils.to_symbolic(s::Symbol) = Sym(s) julia> simplify(ex) (-1 + x) @@ -298,7 +298,7 @@ Term{Any} f: + (function of type typeof(+)) arguments: Array{Any}((2,)) 1: Int64 -1 - 2: Variable{Any} + 2: Sym{Any} name: Symbol x ``` this thing returns a `Term{Any}`, but it's not hard to convert back to `Expr`: @@ -327,7 +327,7 @@ Term{Real} f: + (function of type typeof(+)) arguments: Array{Any}((2,)) 1: Int64 -1 - 2: Variable{Real} + 2: Sym{Real} name: Symbol x ``` and now all our analysis is able to figure out that the `Term`s are `Number`s. diff --git a/src/SymbolicUtils.jl b/src/SymbolicUtils.jl index f80d5ee92..e3bb86870 100644 --- a/src/SymbolicUtils.jl +++ b/src/SymbolicUtils.jl @@ -28,7 +28,7 @@ else end -export @vars, term, @fun, showraw +export @syms, term, @fun, showraw include("types.jl") diff --git a/src/methods.jl b/src/methods.jl index f59a50cb9..f67edd9d1 100644 --- a/src/methods.jl +++ b/src/methods.jl @@ -8,8 +8,8 @@ for f in diadic T::Type{<:Number}, S::Type{<:Number}) = promote_type(T, S) - for T in [Variable, Term] - for S in [Variable, Term] + for T in [Sym, Term] + for S in [Sym, Term] @eval (::$(typeof(f)))(a::$T, b::$S) = term($f, a, b) end @eval begin diff --git a/src/rule_dsl.jl b/src/rule_dsl.jl index 35797511a..e1221e32f 100644 --- a/src/rule_dsl.jl +++ b/src/rule_dsl.jl @@ -56,7 +56,7 @@ _Example:_ Simple rule to turn any `sin` into `cos`: ```julia -julia> @vars a b c +julia> @syms a b c (a, b, c) julia> r = @rule sin(~x) => cos(~x) @@ -176,7 +176,7 @@ Base.show(io::IO, acr::ACRule) = print(io, "ACRule(", acr.rule, ")") function (acr::ACRule)(term) r = Rule(acr) - if term isa Variable + if term isa Sym r(term) else f = operation(term) diff --git a/src/simplify.jl b/src/simplify.jl index 73192b0b6..6ca647dbc 100644 --- a/src/simplify.jl +++ b/src/simplify.jl @@ -21,7 +21,7 @@ _isone(x::Number) = isone(x) <ₑ(a::Number, b::Symbolic) = true arglength(a) = length(arguments(a)) -function <ₑ(a::Variable, b::Term) +function <ₑ(a::Sym, b::Term) args = arguments(b) if length(args) === 2 n1, n2 = !isnumber(args[1]) , !isnumber(args[2]) @@ -54,7 +54,7 @@ function <ₑ(a::Variable, b::Term) end end -<ₑ(a::Symbolic, b::Variable) = !(b <ₑ a) +<ₑ(a::Symbolic, b::Sym) = !(b <ₑ a) function <ₑ(a::Symbol, b::Symbol) # Enforce the order [+,-,\,/,^,*] @@ -75,7 +75,7 @@ function <ₑ(a::Symbol, b::Symbol) end end -<ₑ(a::Variable, b::Variable) = a.name < b.name +<ₑ(a::Sym, b::Sym) = a.name < b.name <ₑ(a::T, b::S) where {T, S} = T===S ? isless(a, b) : nameof(T) < nameof(S) function <ₑ(a::Term, b::Term) diff --git a/src/types.jl b/src/types.jl index d6298c9f2..2f9dea986 100644 --- a/src/types.jl +++ b/src/types.jl @@ -92,56 +92,57 @@ Base.:(==)(a::Symbolic, b::Symbolic) = a === b || isequal(a,b) #-------------------- #-------------------- -#### Variables +#### Syms #-------------------- """ - Variable{T}(name::Symbol) + Sym{T}(name::Symbol) A named variable of type `T`. Type `T` can be `FnType{X,Y}` which means the variable is a function with the type signature X -> Y where `X` is a tuple type of arguments and `Y` is any type. """ -struct Variable{T} <: Symbolic{T} +struct Sym{T} <: Symbolic{T} name::Symbol end -Variable(x) = Variable{symtype(x)}(x) +const Variable = Sym # old name +Sym(x) = Sym{symtype(x)}(x) -Base.nameof(v::Variable) = v.name +Base.nameof(v::Sym) = v.name -Base.:(==)(a::Variable, b::Variable) = a === b +Base.:(==)(a::Sym, b::Sym) = a === b -Base.:(==)(::Variable, ::Symbolic) = false +Base.:(==)(::Sym, ::Symbolic) = false -Base.:(==)(::Symbolic, ::Variable) = false +Base.:(==)(::Symbolic, ::Sym) = false -Base.isequal(v1::Variable, v2::Variable) = isequal(v1.name, v2.name) +Base.isequal(v1::Sym, v2::Sym) = isequal(v1.name, v2.name) -Base.show(io::IO, v::Variable) = print(io, v.name) +Base.show(io::IO, v::Sym) = print(io, v.name) #--------------------------- #--------------------------- #### Function-like variables #--------------------------- -# Maybe don't even need a new type, can just use Variable{FnType} +# Maybe don't even need a new type, can just use Sym{FnType} struct FnType{X<:Tuple,Y} end -(f::Variable{<:FnType})(args...) = term(f, args...) +(f::Sym{<:FnType})(args...) = term(f, args...) -function (f::Variable)(args...) - error("Variable $f of type $F are not callable. " * - "Use @vars $f(var1, var2,...) to create it as a callable. " * +function (f::Sym)(args...) + error("Sym $f of type $F are not callable. " * + "Use @syms $f(var1, var2,...) to create it as a callable. " * "See ?@fun for more options") end """ -`promote_symtype(f::Variable{FnType{X,Y}}, arg_symtypes...)` +`promote_symtype(f::Sym{FnType{X,Y}}, arg_symtypes...)` The resultant type of applying variable `f` to arugments of symtype `arg_symtypes...`. if the arguments are of the wrong type then this function will error. """ -function promote_symtype(f::Variable{FnType{X,Y}}, args...) where {X, Y} +function promote_symtype(f::Sym{FnType{X,Y}}, args...) where {X, Y} nrequired = fieldcount(X) ngiven = nfields(args) @@ -159,39 +160,39 @@ function promote_symtype(f::Variable{FnType{X,Y}}, args...) where {X, Y} end """ - @vars [::T1] [::T2]... + @syms [::T1] [::T2]... For instance: - @vars foo::Real bar baz(x, y::Real)::Complex + @syms foo::Real bar baz(x, y::Real)::Complex Create one or more variables. `` can be just a symbol in which case it will be the name of the variable, or a function call in which case a function-like -variable which has the same name as the function being called. The Variable type, or -in the case of a function-like Variable, the output type of calling the function +variable which has the same name as the function being called. The Sym type, or +in the case of a function-like Sym, the output type of calling the function can be set using the `::T` syntax. # Examples: -- `@vars foo bar::Real baz::Int` will create +- `@syms foo bar::Real baz::Int` will create variable `foo` of symtype `Number` (the default), `bar` of symtype `Real` and `baz` of symtype `Int` -- `@vars f(x) g(y::Real, x)::Int h(a::Int, f(b))` creates 1-arg `f` 2-arg `g` +- `@syms f(x) g(y::Real, x)::Int h(a::Int, f(b))` creates 1-arg `f` 2-arg `g` and 2 arg `f`. The second argument to `h` must be a one argument function-like variable. So, `h(1, g)` will fail and `h(1, f)` will work. """ -macro vars(xs...) +macro syms(xs...) defs = map(xs) do x n, t = _name_type(x) - :($(esc(n)) = Variable{$(esc(t))}($(Expr(:quote, n)))) + :($(esc(n)) = Sym{$(esc(t))}($(Expr(:quote, n)))) end Expr(:block, defs..., :(tuple($(map(x->esc(_name_type(x).name), xs)...)))) end -function vars_syntax_error() - error("Incorrect @vars syntax. Try `@vars x::Real y::Complex g(a) f(::Real)::Real` for instance.") +function syms_syntax_error() + error("Incorrect @syms syntax. Try `@syms x::Real y::Complex g(a) f(::Real)::Real` for instance.") end function _name_type(x) @@ -212,11 +213,11 @@ function _name_type(x) elseif x isa Expr && x.head === :call return _name_type(:($x::Number)) else - vars_syntax_error() + syms_syntax_error() end end -function Base.show(io::IO, f::Variable{<:FnType{X,Y}}) where {X,Y} +function Base.show(io::IO, f::Sym{<:FnType{X,Y}}) where {X,Y} print(io, f.name) argrepr = join(map(t->"::"*string(t), X.parameters), ", ") print(io, "(", argrepr, ")") diff --git a/test/basics.jl b/test/basics.jl index 039184c15..c63dc7d73 100644 --- a/test/basics.jl +++ b/test/basics.jl @@ -1,21 +1,21 @@ -using SymbolicUtils: Variable, FnType, Term, symtype +using SymbolicUtils: Sym, FnType, Term, symtype using SymbolicUtils using Test -@testset "@vars" begin +@testset "@syms" begin let - @vars a b::Float64 f(::Real) g(p, h(q::Real))::Int + @syms a b::Float64 f(::Real) g(p, h(q::Real))::Int - @test a isa Variable{Number} + @test a isa Sym{Number} @test a.name === :a - @test b isa Variable{Float64} + @test b isa Sym{Float64} @test b.name === :b - @test f isa Variable{FnType{Tuple{Real}, Number}} + @test f isa Sym{FnType{Tuple{Real}, Number}} @test f.name === :f - @test g isa Variable{FnType{Tuple{Number, FnType{Tuple{Real}, Number}}, Int}} + @test g isa Sym{FnType{Tuple{Number, FnType{Tuple{Real}, Number}}, Int}} @test g.name === :g @test f(b) isa Term @@ -30,7 +30,7 @@ using Test end @testset "methods test" begin - @vars w::Complex z::Complex a::Real b::Real x + @syms w::Complex z::Complex a::Real b::Real x @test w + z == Term{Complex}(+, [w, z]) @test z + a == Term{Number}(+, [z, a]) diff --git a/test/fuzz.jl b/test/fuzz.jl index ba9535517..61283969d 100644 --- a/test/fuzz.jl +++ b/test/fuzz.jl @@ -5,8 +5,8 @@ using SymbolicUtils: showraw const leaf_funcs = [()->100*randn(), ()->rand(-100:100), - ()->rand(@vars a b c d e f), - ()->rand(@vars a b c d e f)] + ()->rand(@syms a b c d e f), + ()->rand(@syms a b c d e f)] const fns = vcat(1 .=> SymbolicUtils.monadic, 2 .=> vcat(SymbolicUtils.diadic, fill(+, 5), [-,-], fill(*, 5)), @@ -16,7 +16,7 @@ const fns = vcat(1 .=> SymbolicUtils.monadic, function gen_rand_expr(inputs; leaf_prob=0.92, depth=0, min_depth=1, max_depth=5) if depth > max_depth || (min_depth <= depth && rand() < leaf_prob) leaf = rand(leaf_funcs)() - if leaf isa SymbolicUtils.Variable + if leaf isa SymbolicUtils.Sym push!(inputs, leaf) end return leaf diff --git a/test/interface.jl b/test/interface.jl index c1bcd0b4c..5935c6c46 100644 --- a/test/interface.jl +++ b/test/interface.jl @@ -1,10 +1,10 @@ using SymbolicUtils, Test -using SymbolicUtils: Term, Variable, to_symbolic, istree, operation, arguments, symtype +using SymbolicUtils: Term, Sym, to_symbolic, istree, operation, arguments, symtype SymbolicUtils.istree(ex::Expr) = ex.head == :call SymbolicUtils.operation(ex::Expr) = ex.args[1] SymbolicUtils.arguments(ex::Expr) = ex.args[2:end] -SymbolicUtils.to_symbolic(s::Symbol) = Variable(s) +SymbolicUtils.to_symbolic(s::Symbol) = Sym(s) for f ∈ [:+, :-, :*, :/, :^] @eval begin @@ -16,11 +16,11 @@ end ex = 1 + (:x - 2) -@test to_symbolic(ex) == Term{Any}(+, [1, Term{Any}(-, [Variable{Any}(:x), 2])]) +@test to_symbolic(ex) == Term{Any}(+, [1, Term{Any}(-, [Sym{Any}(:x), 2])]) @test simplify(ex) == to_symbolic(-1 + :x) to_expr(t::Term) = Expr(:call, operation(t), to_expr.(arguments(t))...) -to_expr(s::Variable) = s.name +to_expr(s::Sym) = s.name to_expr(x) = x @test to_expr(simplify(ex)) == Expr(:call, +, -1, :x) diff --git a/test/order.jl b/test/order.jl index f0d5be1b4..97f9a45f8 100644 --- a/test/order.jl +++ b/test/order.jl @@ -2,7 +2,7 @@ using Test using SymbolicUtils: <ₑ SymbolicUtils.show_simplified[] = false -@vars a b c +@syms a b c function istotal(x,y) #either diff --git a/test/rewrite.jl b/test/rewrite.jl index c89a9895b..62baf4636 100644 --- a/test/rewrite.jl +++ b/test/rewrite.jl @@ -1,4 +1,4 @@ -@vars a b c +@syms a b c @testset "Equality" begin @test a == a diff --git a/test/rulesets.jl b/test/rulesets.jl index 10d4d6955..c686eebee 100644 --- a/test/rulesets.jl +++ b/test/rulesets.jl @@ -1,5 +1,5 @@ @testset "Numeric" begin - @vars a::Integer b c d x::Real y::Number + @syms a::Integer b c d x::Real y::Number @test simplify(x - y) == x + -1*y @test simplify(x - sin(y)) == x + -1*sin(y) @test simplify(-sin(x)) == -sin(x) @@ -22,7 +22,7 @@ end @testset "Pythagorean Identities" begin - @vars a::Integer x::Real y::Number + @syms a::Integer x::Real y::Number @test simplify(cos(x)^2 + 1 + sin(x)^2) == 2 @test simplify(cos(y)^2 + 1 + sin(y)^2) == 2 @@ -33,14 +33,14 @@ end end #@testset "2π Identities" begin -# @vars a::Integer x::Real y::Number +# @syms a::Integer x::Real y::Number # # @test simplify(cos(x + 2π + a)) == cos(a + x) # @test simplify(tan(x + 2π * a)) == tan(x) #end @testset "Depth" begin - @vars x + @syms x R = RuleSet([@rule(sin(~x) => cos(~x)), @rule( ~x + 1 => ~x - 1)]) @test R(sin(sin(sin(x + 1)))) == cos(cos(cos(x - 1))) @@ -50,7 +50,7 @@ end @testset "RuleRewriteError" begin pred(x) = error("Fail") - @vars a b + @syms a b rs = RuleSet([@rule ~x + ~y::pred => ~x]) @test_throws SymbolicUtils.RuleRewriteError rs(a+b) @@ -59,7 +59,7 @@ end end @testset "timerwrite" begin - @vars a b c d + @syms a b c d expr1 = foldr((x,y)->rand([*, /])(x,y), rand([a,b,c,d], 100)) SymbolicUtils.@timerewrite simplify(expr1) end