Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature Request] SymReal and domain inference #22

Open
Roger-luo opened this issue Sep 25, 2019 · 2 comments
Open

[Feature Request] SymReal and domain inference #22

Roger-luo opened this issue Sep 25, 2019 · 2 comments

Comments

@Roger-luo
Copy link

currently symbols are all defined as subtype of Number, which my cause things not work with builtin complex number. After I played a few ideas with my own toy engine: https://github.com/Roger-luo/Sym.jl

I think a proper solution might be to have different types defined as subtype of Real, Number and even AbstractMatrix. This will make symbolic objects go through most of the functions defined in many packages, so a lot things should "just work".

Moreover, the domain can always be inferred by Julia's own type inference in this way. So to be more specific what I'm suggesting is to separate the engine with higher abstraction of the symbols, e.g Variable, Term, Expression etc.

maybe we could just use Rewrite.jl or Simplify as the engine in the future, and provide this wrapper here, it would look like

struct SymReal <: Real
    term::Term
end

struct SymComplex <: Number # see JuliaLang/julia/issues/33246
    term::Term
end

struct SymMatrix{T <: Union{SymReal, SymComplex}} <: AbstractMatrix{T}
    name::Term
end

and we could just forward the functions calls to Term, e.g

Base.sin(x::SymReal) = SymReal(@term(sin(x.term)))
Base.sin(x::SymComplex) = SymComplex(@term(sin(x.term)))

in this way the Real/Complex domain of result type can be inferred by Julia's own type inference from these primitives (imagine if there is a more complicated user defined function)

XRef: SciML/ModelingToolkit.jl#175

@Roger-luo
Copy link
Author

here is a toy implementation if anyone would like to play with it:

using Simplify, MacroTools

struct SymReal <: Real
    term::Term
end

SymReal(name::Symbol) = SymReal(Variable(name))

function Base.show(io::IO, x::SymReal)
    t = x.term
    ex = MacroTools.postwalk(Simplify._show_term, get(t))
    macro_call = Expr(:macrocall, Symbol("@term"), nothing, ex)
    repr = sprint(show, macro_call)[9:end-1]
    print(io, repr)
end

_term(x) = x
_term(x::SymReal) = x.term

function track(f, xs...)
    xs = map(_term, xs)
    t = track_term(f, xs...)
    return SymReal(t)
end

@generated function track_term(f, xs...)
    quote
        convert(Term, Expr(:call, f, xs...))
    end
end

Base.promote_rule(::Type{SymReal}, ::Type{T}) where {T <: Real} = SymReal
Base.convert(::Type{SymReal}, x::Real) = SymReal(@term(x))
Base.convert(::Type{SymReal}, x::SymReal) = x
Base.:(*)(x::SymReal, y::SymReal) = track(*, x, y)


x = SymReal(:x)
y = SymReal(:y)
ex = 2x * y * 2
normalize(ex.term)

@MasonProtter
Copy link
Owner

Yes, this is a good suggestion. I have some ideas for a next gen interface as I rewrite Symbolics.jl from scratch, but those aren't really ready to make public.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants