Simplify.jl
Simplify.jl copied to clipboard
Distributivity not assumed
Hi, I was just playing around and realized, that distributivity is semingly not assumed (by standard). How can I switch it on? For Example in
julia> @term((x+y)*(x+y) - x^2)
@term((x + y) * (x + y) - x ^ 2)
I would actually expect something like
@term(y ^ 2 + 2 * x * y)
TL;DR: Distributivity is hard, and applying it well in practice is somewhat unclear. It's a difficult problem to tackle, but a medium-term #TODO
.
Dealing with distributivity is a tough philosophical question, even before you get to the code. :slightly_smiling_face: It's hard to agree whether factored or expanded form is simpler, from a generic standpoint.
- It's easier to visually parse the information given by
8x^3 + 12x^2 + 6x + 1
by factoring to(2x + 1)^3
. (It could be argued that the expanded form is easier to mentally differentiate, though?) - It's easier to visually parse the information given by
(x-1) * (x+1) * (x^2 + 1)
by expanding tox^4 - 1
.
In this case, "simplicity" isn't immediately clear, at least without examining each expression on a case-by-case basis (or by both factoring and expanding and using some metric to determine which one is better).
However, let's say we decide that one form is simpler:
- If expanded form is simpler, we can simply register a couple more rules, namely
x * (a + b) => x*a + x*b
and(a + b) * x => a*x + b*x
. The existing rules should take care of cleaning up the remaining expression. - If factored form is simpler, things become a bit trickier. We could try adding the inverse of the previous rules, but that only works when constants haven't been "squashed" already. (For example, if the expanded form of
(x+1) * (x+2)
is derived to bex^2 + x*2 + 1x + 1*2
, we have no issues. But once the result is simplified tox^2 + 3x + 2
, reversing the process becomes challenging.)
One of the best known ways for dealing with polynomial factoring problems is the use of a Gröbner Basis, which would ideally have logic contained in a separate package but be able to operate on an existing Term
object (or an optimized data translation). Then, the user could explicitly call factor
or expand
on their expressions, or we could attempt to automatically determine a simpler form. This type of capability is planned and is significantly influencing the upcoming specializations/strategy API.
From my perspective, you showed more how simplifying a term could be a subjective matter. If one cares about normalization only, that should not be important as long as there is a strict normalization rule, right? I want to use this mostly for comparison of terms so, e.g. the expanded form would be okai as long as I can make sure two differently written but equal terms normalize to the same.
The subjectivity is only the reason why we don't (currently) include any mention of the distributive law in the standard rule set. If the expanded form is okay, though, I think adding the left- and right-distributive rules I mentioned should solve the problem. If factored form is preferred, though, some more complex logic is required (likely in the form of a custom FactorRule <: Rule
).