# can sage stop ordering terms? Noob question incoming...

sage: var('A B C x y')
(A, B, C, x, y)
sage: y == (C - Ax) / B
y == -(A
x - C)/B

What I would like/expect to get here is y == (C - Ax)/B. Is there a way to tell Sage to stop ordering terms?

Rationale - the expression ultimately goes to latex() and I'd like to be able to control how the result looks like.

edit retag close merge delete

Sort by » oldest newest most voted

Short answer is "probably not, unless you want to muck about in the internals of Ginac/Pynac, our symbolics engine". Even this one reorders:

sage: B.add(A,hold=True)
A + B


I think that some symbolics programs find a semi-canonical ordering and stick with that... Interestingly,

sage: C - A*x
-A*x + C


so the minus sign comes out only with the fraction. It's conceivable that one could consider this inconsistency a bug, though I am not qualified to assess that.

That said, perhaps one could make a feature request to control this, though I suspect this would be harder than one thinks.

more

If I had to guess, I'd say that Sage tries to guess the order of each term and sorts them accordingly. x^3 will probably come before x^2, etc. sage: y == C.add(-A*x,hold=True)/B
y == (C - A*x)/B


Another example:

sage: a = (-2*x).add(x^2,-x^3, hold=True); a
-2*x + x^2 - x^3


Further operations reorder the expression

sage: -2*a
2*x^3 - 2*x^2 + 4*x


sage: -2.mul(a,hold=True)
AttributeError: 'sage.rings.integer.Integer' object has no attribute
'mul'

sage: Expression(SR,-2).mul(a,hold=True)
-2*(-2*x + x^2 - x^3)

sage: a.mul(-2,hold=True)
-2*(-2*x + x^2 - x^3)


Don't know why kcrisman gets a reordered expression

sage: B.add(A,hold=True)
B + A

more

I just tried Sage Cell Server (aleph.sagemath.org) x.add(x^2,hold=True) reorders to x^2 + x

Yeah, this is probably because Pynac was upgraded a few times ago.

Definitely we want that Sage reorders... We want A+B+A to become 2A + B...

I do not think it would be hard to manage a pretty print that put first the "positive" terms and then the negative ones (knowing that negative are considered as mul(x,-1)).

Here is a simple function that do it on the first level.

def pretty_print(E):
pos = []
neg = []
for elt in E.operands():
if (elt.operator() == operator.mul and elt.operands()[-1] < 0) or (elt.is_numeric() and elt < 0):
neg.append(-elt)
else:
pos.append(elt)
pos_str = ' + '.join(map(repr,pos))
neg_str = ' + '.join(map(repr,neg))
if len(neg) == 0:
print pos_str
elif len(neg) == 1:
print pos_str + ' - ' + neg_str
else:
print ' + '.join(map(str,pos)) + ' - (' + ' + '.join(map(str,neg)) + ')'

else:
print E


Then inside Sage

sage: var('x,y,z,t')
sage: pretty_print(x-y+z)
x + z - y
sage: pretty_print(z-x-y)
z - (x + y)
sage: pretty_print(y-x-3*z+t)
t + y - (x + 3*z)
sage: pretty_print(3*x*y - 2*z*t - 3)
3*x*y - (2*t*z + 3)

more

Eek, tree walkers! Cool stuff. Any way to make this recursive for more complicated ones? :-)

We definitely want B+A+B to become 2A+B, but I'm in a situation that I don't want B+2A to become 2A+B. That pretty much sums it up :) Thanks for the effort on the function! Looks good for simple expressions, though I doubt this approach can be flexible enough for more complex expressions, e.g. fractions, several parenthesis etc.

Sure my code does not work for more complicated expressions (and I do not want to do it). If you are really interested in that feature for more complex expressions either you walk on the tree as kcricsman pointed out (.operator and .operands makes you go one level down). You could also access to ginac which is the library used for symbolic expression.