-
Notifications
You must be signed in to change notification settings - Fork 123
Description
(paraphrased and excerpted from a discussion on discourse)
Over the domain x::AbstractFloat, the rule that rewrites x - x to zero(x) is wrong, since the domain includes NaNs and Infs. However:
julia> y = SymbolicUtils.Sym{AbstractFloat}(:y)
y
julia> y - y
0Over the "real numbers" (or any field), the rule is correct, and that is where that rule is coming from.
It strikes me as un-Julian design to have that rule defined on Sym{Real} (or Sym{Number}), and then have a specialization that turns it off for AbstractFloat. Specializing behavior is essential in the Julia ecosystem for generic programming, but specializations are not, for lack of a better word, done "willy nilly". They are supposed to be consistent with a generic definition, but perhaps more efficient or producing a more compact (symbolic!) representation. For example:
julia> typeof(1:4)
UnitRange{Int64}
julia> typeof(1:4) <: AbstractArray
true
julia> (1:4) .+ 5
6:9
julia> collect(1:4) .+ 5
4-element Vector{Int64}:
6
7
8
9
julia> collect((1:4) .+ 5) == collect(1:4) .+ 5 # consistency
trueIf broadcasted addition on UnitRange{Int64} were defined in such a way that the “# consistency” property did not hold, that would be bad for generic programming!
Does that badness apply in this CAS setting? What consistency should exist across rules that are defined on types that have a subtype relationship among them? I am not sure. That’s what the question is.
My instinct is that this CAS should introduce a new type, e.g. Symbolics.Real, not Base.Real (though perhaps Symbolics.Real <: Base.Real). Defining that simplification rule on Base.Real seems wrong since I can give you an x::Base.Real for which the rule is wrong. But I should not be able to give you an y::Symbolics.Real for which the rule is wrong.
It's already not the case that Sym{Real}<:Real. What is the benefit of re-using this abstract type?