sympy/sympy — pull request #1994 by smichr (2013-04-09 21:55:50+00:00)
Title: 3070: remove Neg from cse_opts and use different mechanism

Some objects, like RootOf, don't interact well with the Neg mechanism
that cse uses to keep track of Adds that can have a -1 extracted.

1) wrapping an expression in Neg changes the perceived degree of the
expression for Poly (Poly(x**2) is degree 2 but Poly(Neg(x**2)) is
degree 1. Issue 3070 shows why this leads to an error.

2) if Neg is used like a kern so that y - x -> -Neg()*(x - y) that
still causes problems with RootOf because this creates a new generator:

>>> class Neg(Expr):
... @property
... def is_commutative(self): return True
...

Poly is ok
>>> Poly(Neg()*x)
Poly(x*Neg(), x, Neg(), domain='ZZ')

>>> RootOf(Neg()*x)
Traceback (most recent call last):
sympy.polys.polyerrors.PolynomialError:

So instead of using Neg, an unevaluated Mul is simply used. Instead
of replacing y - x with -1*(x - y) (since that will be hard to find later
because Muls can have a leading -1) a leading (1, -1) is used instead:

>>> Mul._from_args([S.One,S.NegativeOne])
-1
>>> _.args
(1, -1)

Muls should not start with a leading 1 and even if something does
(because someone used an unevaluated Mul) the storage of the -1
will make the replacement correct in terms of mathematical equality,
1*-1*x is eventually replaced with -x.