Search code examples
pythonsympy

How to modify sympy's printing order?


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, 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?

Similar issues have already been raised in Prevent Sympy from rearranging the equation and Avoid sorting args in Python module Sympy.


Solution

  • 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))