From e641dd281ba8fd8378cc38be924e07e1968e27e0 Mon Sep 17 00:00:00 2001 From: jverzani Date: Wed, 2 Apr 2025 15:55:33 -0400 Subject: [PATCH 1/7] add True, False --- src/mathops.jl | 8 +++++++- src/types.jl | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/mathops.jl b/src/mathops.jl index da9815c..f08de65 100644 --- a/src/mathops.jl +++ b/src/mathops.jl @@ -90,6 +90,9 @@ for op in [:IM, :PI, :E, :EulerGamma, :Catalan, :GoldenRatio, :oo, :zoo, :NAN] eval(Expr(:export, op)) end +True, False = Basic(C_NULL), Basic(C_NULL); +export True, False + macro init_constant(op, libnm) tup = (Base.Symbol("basic_const_$libnm"), libsymengine) alloc_tup = (:basic_new_stack, libsymengine) @@ -112,14 +115,17 @@ function init_constants() @init_constant oo infinity @init_constant zoo complex_infinity @init_constant NAN nan + ccall((:bool_set_true, libsymengine), Nothing, (Ref{Basic},), True) + ccall((:bool_set_false, libsymengine), Nothing, (Ref{Basic},), False) end -## ## Conversions +## Conversions Base.convert(::Type{Basic}, x::Irrational{:π}) = PI Base.convert(::Type{Basic}, x::Irrational{:e}) = E Base.convert(::Type{Basic}, x::Irrational{:γ}) = EulerGamma Base.convert(::Type{Basic}, x::Irrational{:catalan}) = Catalan Base.convert(::Type{Basic}, x::Irrational{:φ}) = (1 + Basic(5)^Basic(1//2))/2 +Base.convert(::Type{Basic}, x::Bool) = x ? True : False Base.convert(::Type{BasicType}, x::Irrational) = BasicType(convert(Basic, x)) ## Logical operators diff --git a/src/types.jl b/src/types.jl index 0d34bb3..7f3b940 100644 --- a/src/types.jl +++ b/src/types.jl @@ -96,6 +96,7 @@ Basic(x::Basic) = x Base.promote_rule(::Type{Basic}, ::Type{S}) where {S<:Number} = Basic Base.promote_rule(::Type{S}, ::Type{Basic}) where {S<:Number} = Basic Base.promote_rule(::Type{S}, ::Type{Basic}) where {S<:AbstractIrrational} = Basic +Base.promote_rule(::Type{Bool}, ::Type{Basic}) = Basic ## Class ID get_type(s::Basic) = ccall((:basic_get_type, libsymengine), UInt, (Ref{Basic},), s) From 19a55098a00d23db941cb863ece923f79d747db1 Mon Sep 17 00:00:00 2001 From: jverzani Date: Thu, 3 Apr 2025 12:31:17 -0400 Subject: [PATCH 2/7] integrate with N --- src/numerics.jl | 8 +++++++- src/subs.jl | 2 +- src/utils.jl | 1 - 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/numerics.jl b/src/numerics.jl index 74ea3a3..efd9355 100644 --- a/src/numerics.jl +++ b/src/numerics.jl @@ -91,6 +91,7 @@ N(::Val{:RealMPFR}, b::Basic) = _convert(BigFloat, b) N(::Val{:Complex}, b::Basic) = complex(N(real(b)), N(imag(b))) N(::Val{:ComplexMPC}, b::Basic) = complex(N(real(b)), N(imag(b))) N(::Val{:ComplexDouble}, b::Basic) = complex(N(real(b)), N(imag(b))) +N(::Val{:BooleanAtom}, b::Basic) = b == True ? 1 : 0 N(::Val{:NaN}, b::Basic) = NaN function N(::Val{:Infty}, b::Basic) @@ -124,7 +125,12 @@ end function N(::Val{<:Any}, b::Basic) is_constant(b) || throw(ArgumentError("Object can have no free symbols")) - out = evalf(b) + + # replace any True/False with 1/0 + m = CMapBasicBasic() + m[True] = Basic(1); m[False] = Basic(0) + + out = evalf(subs(b, m)) imag(out) == Basic(0.0) ? N(real(out)) : N(out) end diff --git a/src/subs.jl b/src/subs.jl index 0d4d39e..90f8291 100644 --- a/src/subs.jl +++ b/src/subs.jl @@ -80,7 +80,7 @@ function _convert(::Type{Expr}, ex::Basic) if fn == :Symbol return nameof(ex) - elseif (fn in number_types) || (fn == :Constant) + elseif (fn in number_types) || (fn == :Constant) || (fn == :BooleanAtom) return N(ex) end diff --git a/src/utils.jl b/src/utils.jl index 1f17287..5aeb8ae 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -33,4 +33,3 @@ function have_component(comp::String) false end end - From ca3de9b896c2f24895fe0fc1ded20cca664ba5de Mon Sep 17 00:00:00 2001 From: jverzani Date: Fri, 4 Apr 2025 16:11:12 -0400 Subject: [PATCH 3/7] Alternative for True/False values --- src/mathops.jl | 5 ++++- src/numerics.jl | 12 ++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/mathops.jl b/src/mathops.jl index ecdbb68..fcd9cf5 100644 --- a/src/mathops.jl +++ b/src/mathops.jl @@ -95,7 +95,7 @@ Base.one(::Type{T}) where {T<:BasicType} = BasicType(Basic(1)) ## Math constants ## no oo! -for op in [:IM, :PI, :E, :EulerGamma, :Catalan, :GoldenRatio, :oo, :zoo, :NAN] +for op in [:IM, :PI, :E, :EulerGamma, :Catalan, :GoldenRatio, :oo, :zoo, :NAN, :ZERO, :ONE, :MINUSONE] @eval begin const $op = Basic(C_NULL) end @@ -127,6 +127,9 @@ function init_constants() @init_constant oo infinity @init_constant zoo complex_infinity @init_constant NAN nan + @init_constant ZERO zero + @init_constant ONE one + @init_constant MINUSONE minus_one ccall((:bool_set_true, libsymengine), Nothing, (Ref{Basic},), True) ccall((:bool_set_false, libsymengine), Nothing, (Ref{Basic},), False) end diff --git a/src/numerics.jl b/src/numerics.jl index efd9355..8068226 100644 --- a/src/numerics.jl +++ b/src/numerics.jl @@ -12,6 +12,11 @@ function evalf(b::Basic, bits::Integer=53, real::Bool=false) if status == 0 return c else + # replace any True/False with 1/0 + m = CMapBasicBasic() + m[True] = ONE; m[False] = ZERO + b′ = subs(b, m) + b′ != b && return evalf(b′, bits, real) throw(ArgumentError("symbolic value cannot be evaluated to a numeric value")) end end @@ -125,12 +130,7 @@ end function N(::Val{<:Any}, b::Basic) is_constant(b) || throw(ArgumentError("Object can have no free symbols")) - - # replace any True/False with 1/0 - m = CMapBasicBasic() - m[True] = Basic(1); m[False] = Basic(0) - - out = evalf(subs(b, m)) + out = evalf(b) imag(out) == Basic(0.0) ? N(real(out)) : N(out) end From 1d379d32f759f34d768cb89e2ae926818472afcc Mon Sep 17 00:00:00 2001 From: jverzani Date: Fri, 4 Apr 2025 16:38:07 -0400 Subject: [PATCH 4/7] Try out global map --- src/SymEngine.jl | 4 ++++ src/numerics.jl | 5 +---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/SymEngine.jl b/src/SymEngine.jl index 8a1ebaa..2986d72 100644 --- a/src/SymEngine.jl +++ b/src/SymEngine.jl @@ -36,6 +36,10 @@ include("dense-matrix.jl") function __init__() init_constants() + + global TrueFalseMap = CMapBasicBasic() + TrueFalseMap[True] = ONE + TrueFalseMap[False] = ZERO end end diff --git a/src/numerics.jl b/src/numerics.jl index 8068226..03c8048 100644 --- a/src/numerics.jl +++ b/src/numerics.jl @@ -12,10 +12,7 @@ function evalf(b::Basic, bits::Integer=53, real::Bool=false) if status == 0 return c else - # replace any True/False with 1/0 - m = CMapBasicBasic() - m[True] = ONE; m[False] = ZERO - b′ = subs(b, m) + b′ = subs(b, TrueFalseMap) # replace any True/False with 1/0 b′ != b && return evalf(b′, bits, real) throw(ArgumentError("symbolic value cannot be evaluated to a numeric value")) end From f489a510d1d9a64e3157925a3860b4bf9c4a213e Mon Sep 17 00:00:00 2001 From: jverzani Date: Fri, 4 Apr 2025 16:40:57 -0400 Subject: [PATCH 5/7] add test --- test/runtests.jl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/runtests.jl b/test/runtests.jl index 2336e45..e3a1b80 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -386,6 +386,13 @@ expr = x^3 + 3*x^2*y + 3*x*y^2 + y^3 + 1 end end +@testset "Symbolic Booleans" begin + @test N(True) == 1 + @test N(False) == 1 + v = Basic(1) + True + @test N(v) == 1 + true +end + @test round(Basic(3.14)) == 3.0 @test round(Basic(3.14); digits=1) == 3.1 From 83f0e8d7adc0d85d68e4a15f43ab2d088075f8a7 Mon Sep 17 00:00:00 2001 From: jverzani Date: Fri, 4 Apr 2025 16:43:57 -0400 Subject: [PATCH 6/7] oops --- test/runtests.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/runtests.jl b/test/runtests.jl index e3a1b80..457679b 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -388,7 +388,7 @@ end @testset "Symbolic Booleans" begin @test N(True) == 1 - @test N(False) == 1 + @test N(False) == 0 v = Basic(1) + True @test N(v) == 1 + true end From 898f53de59671c4204a3c0662526f3e352411669 Mon Sep 17 00:00:00 2001 From: jverzani Date: Sat, 5 Apr 2025 07:33:32 -0400 Subject: [PATCH 7/7] add negative infinity --- src/mathops.jl | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/mathops.jl b/src/mathops.jl index fcd9cf5..9f092b0 100644 --- a/src/mathops.jl +++ b/src/mathops.jl @@ -95,16 +95,14 @@ Base.one(::Type{T}) where {T<:BasicType} = BasicType(Basic(1)) ## Math constants ## no oo! -for op in [:IM, :PI, :E, :EulerGamma, :Catalan, :GoldenRatio, :oo, :zoo, :NAN, :ZERO, :ONE, :MINUSONE] +for op in [:IM, :PI, :E, :EulerGamma, :Catalan, :GoldenRatio, :oo, :zoo, + :NEGINFINITY, :NAN, :ZERO, :ONE, :MINUSONE, :True, :False] @eval begin const $op = Basic(C_NULL) end eval(Expr(:export, op)) end -True, False = Basic(C_NULL), Basic(C_NULL); -export True, False - macro init_constant(op, libnm) tup = (Base.Symbol("basic_const_$libnm"), libsymengine) alloc_tup = (:basic_new_stack, libsymengine) @@ -126,6 +124,7 @@ function init_constants() @init_constant GoldenRatio GoldenRatio @init_constant oo infinity @init_constant zoo complex_infinity + @init_constant NEGINFINITY neginfinity @init_constant NAN nan @init_constant ZERO zero @init_constant ONE one