SymbolicUtils.jl
SymbolicUtils.jl copied to clipboard
RFC: Wrapper type interface
It maybe worth considering making a macro which generates an interface to wrap a symbolic expression to be a subtype of a certain outside type.
@symbolic_wrap Num <: Real
would generate:
struct Num <: Real
value
end
wrapper_type(::Type{<:Real}) = Num
iswrapper(::Type{Num}) = true # also, there would be iswrapped(x) = iswrapper(typeof(x))
unwrap(x::Num) = x.value
The benefits are:
-
@variables
macro in Symbolics.jl can usewrapper_type
to wrap objects it creates in the right wrapper. - We could also have a
@wrapped
macro which unwraps the arguments and wraps the results appropriately. For example
@symbolic_wrap Num <: Real
@symbolic_wrap IntLike <: Integer
@wrapped function foo(x::Integer, y::Real, z)
<expr> # expr can do istree etc!
end
Would generate the equivalent of
function _foo(x, y, z)
res = <expr>
end
foo(x::Symbolic{<:Integer}, y::Symbolic{<:Real}, z) = _foo(x, y, z)
foo(x::IntLike, y::SymUnion{Real}, z) = wrap(_foo(unwrap(x), unwrap(y), z))
foo(x::SymUnion{Integer}, y::Num, z) = wrap(_foo(unwrap(x), unwrap(y), z))
# where
# const SymUnion{T} = Union{T, Symbolic{<:T}}
# wrap(x) = wrapper_type(typeof(x))(x)
So only code that is aware of the symbolic nature of itself will use @wrapped
, non-symbolic code will try to do things as usual.
I'm opening this in SymbolicUtils rather than Symbolics because we can just define @wrapped
numeric methods here rather than have a @number_methods
type.
This was prompted by attempts to create symbolic ranges to use with symbolic arrays.
@MasonProtter @YingboMa what are your thoughts?
It's not clear what methods to overload. For instance, for real numbers, we will have conj(x) = x
etc, and for <:Number
, we may or may not assume a * b = b * a
.
Yes, but the proposal is to just create conveniences for writing methods. You still have to define them on a case by case basis for every type you want to symbolically support.
I think this is going to ultimately be necessary if we want to do this without fancy compiler tools. One thing I'll note though is that an external using generating
SymbolicUtils.wrapper_type(::Type{<:Real}) = Num
would be piracy, so if multiple users created their own <:Real
types, there'd be trouble.
Yes and we can allow some authorized piracy and document it. Important Base types could be made available here or in Symbolics.
On Mar 16, 2021, at 2:40 AM, Mason Protter @.***> wrote:
I think this is going to ultimately be necessary if we want to do this without fancy compiler tools. One thing I'll note though is that an external using generating
SymbolicUtils.wrapper_type(::Type{<:Real}) = Num would be piracy, so if multiple users created their own <:Real types, there'd be trouble.
— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or unsubscribe.
Note to also support @symbolic_wrap Arr{T,N} <: AbstractArray{T, N}