diff --git a/src/mathfuns.jl b/src/mathfuns.jl index b39f0f0..8139129 100644 --- a/src/mathfuns.jl +++ b/src/mathfuns.jl @@ -110,6 +110,15 @@ for (meth, libnm) in [(:nextprime,:nextprime) eval(Expr(:export, meth)) end +"Return coefficient of `x^n` term, `x` a symbol" +function coeff(b::Basic, x, n) + c = Basic() + out = ccall((:basic_coeff, libsymengine), Nothing, + (Ref{Basic},Ref{Basic},Ref{Basic},Ref{Basic}), + c,b,Basic(x), Basic(n)) + c +end + function Base.convert(::Type{CVecBasic}, x::Vector{T}) where T vec = CVecBasic() for i in x diff --git a/src/numerics.jl b/src/numerics.jl index 421acbc..c0b80d1 100644 --- a/src/numerics.jl +++ b/src/numerics.jl @@ -212,6 +212,51 @@ isnan(x::Basic) = ( x == NAN ) isinf(x::Basic) = !isnan(x) & !isfinite(x) isless(x::Basic, y::Basic) = isless(N(x), N(y)) +# is_a_functions +# could use metaprogramming here +is_a_Number(x::Basic) = + Bool(convert(Int, ccall((:is_a_Number, libsymengine), + Cuint, (Ref{Basic},), x))) +is_a_Integer(x::Basic) = + Bool(convert(Int, ccall((:is_a_Integer, libsymengine), + Cuint, (Ref{Basic},), x))) +is_a_Rational(x::Basic) = + Bool(convert(Int, ccall((:is_a_Rational, libsymengine), + Cuint, (Ref{Basic},), x))) +is_a_RealDouble(x::Basic) = + Bool(convert(Int, ccall((:is_a_RealDouble, libsymengine), + Cuint, (Ref{Basic},), x))) +is_a_RealMPFR(x::Basic) = + Bool(convert(Int, ccall((:is_a_RealMPFR, libsymengine), + Cuint, (Ref{Basic},), x))) +is_a_Complex(x::Basic) = + Bool(convert(Int, ccall((:is_a_Complex, libsymengine), + Cuint, (Ref{Basic},), x))) +is_a_ComplexDouble(x::Basic) = + Bool(convert(Int, ccall((:is_a_ComplexDouble, libsymengine), + Cuint, (Ref{Basic},), x))) +is_a_ComplexMPC(x::Basic) = + Bool(convert(Int, ccall((:is_a_ComplexMPC, libsymengine), + Cuint, (Ref{Basic},), x))) + +Base.isinteger(x::Basic) = is_a_Integer(x) +function Base.isreal(x::Basic) + is_a_Number(x) || return false + is_a_Integer(x) || is_a_Rational(x) || is_a_RealDouble(x) || is_a_RealMPFR(x) +end + +# may not allocate; seems more idiomatic than default x == zero(x) +function Base.iszero(x::Basic) + is_a_Number(x) || return false + x == zero(x) +end + +function Base.isone(x::Basic) + is_a_Number(x) || return false + x == one(x) +end + + ## These should have support in symengine-wrapper, but currently don't trunc(x::Basic, args...) = Basic(trunc(N(x), args...)) diff --git a/src/types.jl b/src/types.jl index f726fe5..e0cdd1f 100644 --- a/src/types.jl +++ b/src/types.jl @@ -233,13 +233,13 @@ BasicTrigFunction = Union{[SymEngine.BasicType{Val{i}} for i in trig_types]...} ### "Is expression a symbol" -is_symbol(x::Basic) = is_symbol(BasicType(x)) -is_symbol(x::BasicType{Val{:Symbol}}) = true -is_symbol(x::BasicType) = false - +function is_symbol(x::SymbolicType) + res = ccall((:is_a_Symbol, libsymengine), Cuint, (Ref{Basic},), x) + Bool(convert(Int,res)) +end "Does expression contain the symbol" -function has_symbol(ex::Basic, x::Basic) +function has_symbol(ex::SymbolicType, x::SymbolicType) is_symbol(x) || throw(ArgumentError("Not a symbol")) res = ccall((:basic_has_symbol, libsymengine), Cuint, (Ref{Basic},Ref{Basic}), ex, x) Bool(convert(Int, res)) diff --git a/test/runtests.jl b/test/runtests.jl index 3a0171f..7e5aecc 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -80,6 +80,21 @@ println() @test subs(sin(x), x, pi) == 0 @test sind(Basic(30)) == 1 // 2 +## predicates +@vars x +u,v,w = x(2.1), x(1), x(0) +@test isreal(u) +@test !isinteger(u) +@test isinteger(v) +@test isone(v) +@test iszero(w) +@test (@allocated isreal(u)) == 0 +@test (@allocated isinteger(v)) == 0 +@test (@allocated isone(x)) == 0 +@test (@allocated iszero(x)) == 0 +@test (@allocated isone(v)) > 0 # checking v==zero(v) value allocates +@test (@allocated iszero(w)) > 0 + ## calculus x,y = symbols("x y") n = Basic(2) @@ -188,9 +203,12 @@ x,y,z = symbols("x y z") # is/has/free symbol(s) @vars x y z @test SymEngine.is_symbol(x) +@test (@allocated SymEngine.is_symbol(x)) == 0 @test !SymEngine.is_symbol(x(2)) @test !SymEngine.is_symbol(x^2) @test SymEngine.has_symbol(x^2, x) +@test SymEngine.has_symbol(x, x) +@test @allocated(SymEngine.has_symbol(x, x)) == 0 @test SymEngine.has_symbol(sin(sin(sin(x))), x) @test !SymEngine.has_symbol(x^2, y) @test Set(free_symbols(x*y)) == Set([x,y])