From 1ff8629304b28d6f3cfd999d2faa88564dcfb86a Mon Sep 17 00:00:00 2001 From: jverzani Date: Sun, 2 Mar 2025 10:55:37 -0500 Subject: [PATCH 1/2] add sign, has_symbol --- src/mathfuns.jl | 1 + src/types.jl | 13 ++++++++++++- test/runtests.jl | 10 ++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/mathfuns.jl b/src/mathfuns.jl index 72e30a9..b39f0f0 100644 --- a/src/mathfuns.jl +++ b/src/mathfuns.jl @@ -55,6 +55,7 @@ for (meth, libnm, modu) in [ (:log,:log,:Base), (:sqrt,:sqrt,:Base), (:exp,:exp,:Base), + (:sign, :sign, :Base), (:eta,:dirichlet_eta,:SpecialFunctions), (:zeta,:zeta,:SpecialFunctions), ] diff --git a/src/types.jl b/src/types.jl index d778a69..f726fe5 100644 --- a/src/types.jl +++ b/src/types.jl @@ -232,6 +232,18 @@ 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 + + +"Does expression contain the symbol" +function has_symbol(ex::Basic, x::Basic) + 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)) +end " Return free symbols in an expression as a `Set`" @@ -305,4 +317,3 @@ function Serialization.deserialize(s::Serialization.AbstractSerializer, ::Type{B throw_if_error(res) return a end - diff --git a/test/runtests.jl b/test/runtests.jl index 9855ce9..743194f 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -185,6 +185,16 @@ A = [x 2; x 1] x,y,z = symbols("x y z") @test length(SymEngine.free_symbols([x*y, y,z])) == 3 +# is/has/free symbol(s) +@vars x y z +@test SymEngine.is_symbol(x) +@test !SymEngine.is_symbol(x(2)) +@test !SymEngine.is_symbol(x^2) +@test SymEngine.has_symbol(x^2, x) +@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]) +@test Set(free_symbols(x*y^z)) != Set([x,y]) ## check that callable symengine expressions can be used as functions for duck-typed functions @vars x From b223c02d335e0a2ea8d4927aa91beece110408c7 Mon Sep 17 00:00:00 2001 From: jverzani Date: Sun, 2 Mar 2025 11:46:59 -0500 Subject: [PATCH 2/2] patch holes in call syntax --- src/subs.jl | 7 ++++--- test/runtests.jl | 8 ++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/subs.jl b/src/subs.jl index ee62ab1..f7f47fb 100644 --- a/src/subs.jl +++ b/src/subs.jl @@ -38,11 +38,12 @@ subs(ex::T, d::Pair...) where {T <: SymbolicType} = subs(ex, [(p.first, p.second ## Allow an expression to be called, as with ex(2). When there is more than one symbol, one can rely on order of `free_symbols` or ## be explicit by passing in pairs : `ex(x=>1, y=>2)` or a dict `ex(Dict(x=>1, y=>2))`. function (ex::Basic)(args...) - xs = free_symbols(ex) - subs(ex, collect(zip(xs, args))...) + xs = free_symbols(ex) + isempty(xs) && return ex + subs(ex, collect(zip(xs, args))...) end (ex::Basic)(x::AbstractDict) = subs(ex, x) -(ex::Basic)(x::Pair...) = subs(ex, x...) +(ex::Basic)(x::Pair, xs::Pair...) = subs(ex, x, xs...) ## Lambdify diff --git a/test/runtests.jl b/test/runtests.jl index 743194f..3a0171f 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -196,6 +196,14 @@ x,y,z = symbols("x y z") @test Set(free_symbols(x*y)) == Set([x,y]) @test Set(free_symbols(x*y^z)) != Set([x,y]) +# call without specifying variables +@vars x y +z = x(2) +@test x(2) == 2 +@test (x*y^2)(1,2) == subs(x*y^2, x=>1, y=>2) == (x*y^2)(x=>1, y=>2) +@test z() == 2 +@test z(1) == 2 + ## check that callable symengine expressions can be used as functions for duck-typed functions @vars x function simple_newton(f, fp, x0)