Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Not aligned Sympy's nice pritting of division

Tags:

python

sympy

I'm trying to nice print some divisions with Sympy but I noticed it didn't display aligned.

import sympy
sympy.init_printing(use_unicode=True)

sympy.pprint(sympy.Mul(-1, sympy.Pow(-5, -1, evaluate=False), evaluate=False))
# Output:
# -1 
# ───
#  -5  # Note that "-5" is displayed slightly more on the right than "-1".

Reason/fix for this?

EDIT: I did a lot of reverse-engineering using inspect.getsource and inspect.getsourcefile but it didn't really help out in the end.

Pretty Printing in Sympy seems to be relying on the Prettyprinter by Jurjen Bos.

import sympy

from sympy.printing.pretty.stringpict import *

sympy.init_printing(use_unicode=True)

prettyForm("-1")/prettyForm("-5")
# Displays:
# -1
# --
# -5

So it does display aligned, but I can't get it to use unicode.

The PrettyPrinter is called from the file sympy/printing/pretty/pretty.py in the method PrettyPrinter._print_Mul which simply return prettyForm.__mul__(*a)/prettyForm.__mul__(*b) with, I thought, a and b simply being ['-1'] and ['-5'] but it wouldn't work.

like image 888
jeromej Avatar asked May 12 '15 17:05

jeromej


2 Answers

Negative denominators are not standard and badly handled. If you really need them, you can modify the string outpout given by the pretty function :

import sympy
sympy.init_printing(use_unicode=True)
def ppprint(expr):
    p=sympy.pretty(expr)
    s=p.split('\n')
    if len(s)==3 and int(s[2])<0:
        s[0]=" "+s[0]
        s[1]=s[1][0]+s[1]
        p2="\n".join(s)
        print(p2) 
    else: print(p)

This extend the bar and the numerator of one unit for negative denominators. No warranty of robustness on big expressions.

>>>> ppprint(sympy.Mul(sympy.Pow(-5, -1,evaluate=False),-1,evaluate=False))
 -1 
────
 -5
like image 36
B. M. Avatar answered Sep 20 '22 19:09

B. M.


Found out where the weird part is coming from:

stringpict.py line 417:

        if num.binding==prettyForm.NEG:
            num = num.right(" ")[0]

This is being done ONLY for the numerator. It adds a space after the numerator if the numerator is negative… Weird!

I'm not sure if there can be a fixed other than directly editing the file. I'm going to report this on Github.

Thanks all for your help and suggestion.

PS: In the end, I used pdb to help me debug and figure out what was actually going out!

EDIT: Hotfix if you can't / don't want to edit the code source:

import sympy
sympy.init_printing(use_unicode=True)

from sympy.printing.pretty.stringpict import prettyForm, stringPict

def newDiv(self, den, slashed=False):
    if slashed:
        raise NotImplementedError("Can't do slashed fraction yet")
    num = self
    if num.binding == prettyForm.DIV:
        num = stringPict(*num.parens())
    if den.binding == prettyForm.DIV:
        den = stringPict(*den.parens())

    return prettyForm(binding=prettyForm.DIV, *stringPict.stack(
        num,
        stringPict.LINE,
        den))

prettyForm.__div__ = newDiv

sympy.pprint(sympy.Mul(-1, sympy.Pow(-5, -1, evaluate=False), evaluate=False))

# Displays properly:
# -1
# ──
# -5

I just copied the function from the code source and removed the incriminated line.

Possible improvement could be to functools.wraps the new function with the original one.

like image 183
jeromej Avatar answered Sep 20 '22 19:09

jeromej