4

I am using sympy to write algebraic expressions and perform basic calculations with them. Sympy does not keep track of the order of the variables which can be a problem when it comes to printing expressions (the issue has already been raised here and here, so this is not a duplicate). e.g.

>>> from sympy import *
>>> var("p,a")
>>> l=p-1-a;
>>> print(l);
-a+p-1

However, sympy seems to print the variables in the alphabetical order. Is there a way to change the alphebetical order Python refers to and thus trick sympy into printing the variables in the desired order? Any other solution is welcome!

Nre
  • 271
  • 2
  • 12
  • Will the Printing page in SymPy's documentation help? http://docs.sympy.org/latest/tutorial/printing.html – BoboDarph Aug 10 '17 at 14:05
  • I have not seen anything relevant there. It seems to be a known issue, I don't think anything "conventional" will help. – Nre Aug 10 '17 at 14:08
  • 1
    Possible duplicate of [Prevent Sympy from rearranging the equation](https://stackoverflow.com/questions/14624511/prevent-sympy-from-rearranging-the-equation) – Alexander McFarlane Aug 10 '17 at 14:30
  • 2
    @AlexanderMcFarlane: OP is well aware of the 4 year old questions (linked them) and probably hopes the situaiton has changed since. Issues were reported to sympy before, unfortunately the links are broken. I do not consider this a duplicate. – laolux Aug 10 '17 at 15:01
  • @Hannebambel Thank you for the clarification. – Nre Aug 10 '17 at 15:08

2 Answers2

1

Some new documentation on creating custom printers is in the pipe. Maybe that will help? I would create a custom printer which -- let's say we create a custom Add printer -- sorts the args based on some property like degree or sign of a term's coefficient, and then prints the resulting Add.

smichr
  • 16,948
  • 2
  • 27
  • 34
  • Thank you! I'll have a look if I manage to do something with that and will post it if it works. – Nre Aug 15 '17 at 11:01
  • Done! I would be happy to get any feedback on the way I implemented your idea. Thanks again – Nre Aug 21 '17 at 10:36
  • My initial feeling is that you are doing more than you need to. I would suggest that your print method take two args: the expression and a function that will sort args. That method would then get the args, sort them, and pass them as an unevaluated expression to the normal printer. Note: in your current code you use is_integer when I think you mean is_Integer and similar for is_symbol – smichr Aug 22 '17 at 13:01
  • Thank you. I will try to adjust the code as you suggest when I have time and update my answer. – Nre Aug 23 '17 at 13:09
1

Thanks to smichr's answer, I wrote a custom printer which does what I want. I am not a good programmer, so if you have any suggestions to make on my code, I would be happy to implement them.

from sympy import *
import math
import copy
import collections
import itertools
init_printing(use_unicode=True)
var("p,a,b,c,d,e,f");
ddict=collections.OrderedDict([(p, 1),(a, 2), (b, 3), (c, 4),(d, 5),(e, 6),(f, 7),])
from sympy import Basic, Function, Symbol
from sympy.printing.printer import Printer
from sympy.printing.latex import print_latex
from sympy.core.basic import Basic
class MyPrinter(Printer):
    printmethod = '_myprinter'
    def _print_Add(self,expr):
        expr_args=expr.args
        def new_place(el):
            if el in ddict:
                return ddict[el]
            else:
                return len(ddict)+1
        def get_place(el):
            if el.is_integer:
                return new_place(el)
            elif el.is_symbol:
                return new_place(el)
            elif len(el.args)>0:
                if el.args[len(el.args)-1].is_symbol:
                    return new_place(el.args[len(el.args)-1])
                else:
                    return 0
            else:
                return 0
        def write_coeff(el):
            if el.is_integer:
                if el>0:
                    return "+%s" %el
                else:
                    return "%s" %el
            elif el.is_symbol:
                return "+%s" %el
            elif len(el.args)>0:
                if el.args[len(el.args)-1].is_symbol:
                    if el.args[0].is_rational:
                        if el.args[0]>0:
                            return "+%s" %latex(el)
                        else:
                            return "%s" %latex(el)
                    else:
                        return "%s" %latex(el)
                else:
                    return "%s" %latex(el)
            else:
                return "%s" %el
        list_place=[get_place(a) for a in expr.args]
        expr_args=zip(*sorted(zip(list_place,expr_args)))[1]
        to_print=[write_coeff(a) for a in expr_args]
        to_print[0]=str(latex(expr_args[0]))
        return "".join(a for a in to_print)
def my_printer(expr):
    return (MyPrinter().doprint(expr))
de=-a+p+3+c-b
print(my_printer(de))
Nre
  • 271
  • 2
  • 12