Open MatthewJA opened 9 years ago
I'm not so sure that simplification is the right way to go about this, I just used what I had available. Maybe it should just expand instead? Distribute all power/multiplication terms so the expression tree is always (from top to bottom) "addtion > multiplication > power", then sort all terms so that you have a fully unambiguous canonical form.
I think you're right, expanding makes sense. I'm not entirely sure expanding is going to give a canonical form, though (which seems to be the problem here anyway), so that'll need to be fixed. The simple solution is to call expand until the expression no longer changes, but that's pretty slow.
I started experimenting with writing a canonicalization function on this branch. It still needs work. There is currently an issue with distribution of division, which I find odd, because distribution of powers appears to work OK and division is just multiplication by Pow(base, -1).
My approach, so far, is as follows:
canonical
class method which applies the operation while enforcing canonicalization rules.
canonicalize
instance method, which canonicalizes sub-expressions before canonicalizing the current expression.canonical
is not necessarily a node of that operator's type. An example of this is that Mul.canonical
will return an Add
node if the multiplication is distributed over an Add
operand.Add
> Mul
> Pow
, with special cases for exponentsAdd
and Mul
must have at least two terms (not including identities 0 or 1, respectively)Add
may not contain another Add
(combine terms)Mul
may not contain another Mul
(combine terms)Mul
may not contain Add
(distribute)Pow
may not be another Pow
(combine exponents)Pow
may not be a Mul
(distribute)Pow
may not be an Add
(distribute)Add.canonical
Add
operandsMul.canonical
Constant(0)
Mul.canonical
Mul
operandsAdd
, return resultPow.canonical
Constant(1)
Pow.canonical
Add
, split the terms. Multiply individual powers for each term in the exponent.Add
and exponent is a Constant
n
times, where n
is the integer part of the exponentPow
for the fractional part of the exponentMul
Pow
, multiply exponentsAlso, although I wrote a separate implementation, I think there is some overlap between canonicalize
and simplify
(distribution, collection of like terms, etc.). As I see it, canonicalize
is focused on unambiguous results, while simplify
focuses on producing concise human-readable results. I think this makes simplify
a superset of canonicalize
which performs additional simplification, not necessarily respecting the above constraints.
That looks really good! I'd definitely expect overlap between canonicalize
and simplify
, but possibly more overlap with expand
. One idea that comes to mind is rewriting simplify
and expand
in terms of canonicalize
, which I think makes a great deal more sense than the existing implementations of simplify
and expand
, so I might do that once.
But yeah, looks great so far!
So
@expr.expandAndSimplify
isn't fully simplifying. I'm not really sure why, but one possible (bad?) solution is to just keep simplifying until the expression no longer changes.