chore: 添加虚拟环境到仓库
- 添加 backend_service/venv 虚拟环境 - 包含所有Python依赖包 - 注意:虚拟环境约393MB,包含12655个文件
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
"""ASCII-ART 2D pretty-printer"""
|
||||
|
||||
from .pretty import (pretty, pretty_print, pprint, pprint_use_unicode,
|
||||
pprint_try_use_unicode, pager_print)
|
||||
|
||||
# if unicode output is available -- let's use it
|
||||
pprint_try_use_unicode()
|
||||
|
||||
__all__ = [
|
||||
'pretty', 'pretty_print', 'pprint', 'pprint_use_unicode',
|
||||
'pprint_try_use_unicode', 'pager_print',
|
||||
]
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,731 @@
|
||||
"""Symbolic primitives + unicode/ASCII abstraction for pretty.py"""
|
||||
|
||||
import sys
|
||||
import warnings
|
||||
from string import ascii_lowercase, ascii_uppercase
|
||||
import unicodedata
|
||||
|
||||
unicode_warnings = ''
|
||||
|
||||
def U(name):
|
||||
"""
|
||||
Get a unicode character by name or, None if not found.
|
||||
|
||||
This exists because older versions of Python use older unicode databases.
|
||||
"""
|
||||
try:
|
||||
return unicodedata.lookup(name)
|
||||
except KeyError:
|
||||
global unicode_warnings
|
||||
unicode_warnings += 'No \'%s\' in unicodedata\n' % name
|
||||
return None
|
||||
|
||||
from sympy.printing.conventions import split_super_sub
|
||||
from sympy.core.alphabets import greeks
|
||||
from sympy.utilities.exceptions import sympy_deprecation_warning
|
||||
|
||||
# prefix conventions when constructing tables
|
||||
# L - LATIN i
|
||||
# G - GREEK beta
|
||||
# D - DIGIT 0
|
||||
# S - SYMBOL +
|
||||
|
||||
|
||||
__all__ = ['greek_unicode', 'sub', 'sup', 'xsym', 'vobj', 'hobj', 'pretty_symbol',
|
||||
'annotated', 'center_pad', 'center']
|
||||
|
||||
|
||||
_use_unicode = False
|
||||
|
||||
|
||||
def pretty_use_unicode(flag=None):
|
||||
"""Set whether pretty-printer should use unicode by default"""
|
||||
global _use_unicode, unicode_warnings
|
||||
if flag is None:
|
||||
return _use_unicode
|
||||
|
||||
if flag and unicode_warnings:
|
||||
# print warnings (if any) on first unicode usage
|
||||
warnings.warn(unicode_warnings)
|
||||
unicode_warnings = ''
|
||||
|
||||
use_unicode_prev = _use_unicode
|
||||
_use_unicode = flag
|
||||
return use_unicode_prev
|
||||
|
||||
|
||||
def pretty_try_use_unicode():
|
||||
"""See if unicode output is available and leverage it if possible"""
|
||||
|
||||
encoding = getattr(sys.stdout, 'encoding', None)
|
||||
|
||||
# this happens when e.g. stdout is redirected through a pipe, or is
|
||||
# e.g. a cStringIO.StringO
|
||||
if encoding is None:
|
||||
return # sys.stdout has no encoding
|
||||
|
||||
symbols = []
|
||||
|
||||
# see if we can represent greek alphabet
|
||||
symbols += greek_unicode.values()
|
||||
|
||||
# and atoms
|
||||
symbols += atoms_table.values()
|
||||
|
||||
for s in symbols:
|
||||
if s is None:
|
||||
return # common symbols not present!
|
||||
|
||||
try:
|
||||
s.encode(encoding)
|
||||
except UnicodeEncodeError:
|
||||
return
|
||||
|
||||
# all the characters were present and encodable
|
||||
pretty_use_unicode(True)
|
||||
|
||||
|
||||
def xstr(*args):
|
||||
sympy_deprecation_warning(
|
||||
"""
|
||||
The sympy.printing.pretty.pretty_symbology.xstr() function is
|
||||
deprecated. Use str() instead.
|
||||
""",
|
||||
deprecated_since_version="1.7",
|
||||
active_deprecations_target="deprecated-pretty-printing-functions"
|
||||
)
|
||||
return str(*args)
|
||||
|
||||
# GREEK
|
||||
g = lambda l: U('GREEK SMALL LETTER %s' % l.upper())
|
||||
G = lambda l: U('GREEK CAPITAL LETTER %s' % l.upper())
|
||||
|
||||
greek_letters = list(greeks) # make a copy
|
||||
# deal with Unicode's funny spelling of lambda
|
||||
greek_letters[greek_letters.index('lambda')] = 'lamda'
|
||||
|
||||
# {} greek letter -> (g,G)
|
||||
greek_unicode = {L: g(L) for L in greek_letters}
|
||||
greek_unicode.update((L[0].upper() + L[1:], G(L)) for L in greek_letters)
|
||||
|
||||
# aliases
|
||||
greek_unicode['lambda'] = greek_unicode['lamda']
|
||||
greek_unicode['Lambda'] = greek_unicode['Lamda']
|
||||
greek_unicode['varsigma'] = '\N{GREEK SMALL LETTER FINAL SIGMA}'
|
||||
|
||||
# BOLD
|
||||
b = lambda l: U('MATHEMATICAL BOLD SMALL %s' % l.upper())
|
||||
B = lambda l: U('MATHEMATICAL BOLD CAPITAL %s' % l.upper())
|
||||
|
||||
bold_unicode = {l: b(l) for l in ascii_lowercase}
|
||||
bold_unicode.update((L, B(L)) for L in ascii_uppercase)
|
||||
|
||||
# GREEK BOLD
|
||||
gb = lambda l: U('MATHEMATICAL BOLD SMALL %s' % l.upper())
|
||||
GB = lambda l: U('MATHEMATICAL BOLD CAPITAL %s' % l.upper())
|
||||
|
||||
greek_bold_letters = list(greeks) # make a copy, not strictly required here
|
||||
# deal with Unicode's funny spelling of lambda
|
||||
greek_bold_letters[greek_bold_letters.index('lambda')] = 'lamda'
|
||||
|
||||
# {} greek letter -> (g,G)
|
||||
greek_bold_unicode = {L: g(L) for L in greek_bold_letters}
|
||||
greek_bold_unicode.update((L[0].upper() + L[1:], G(L)) for L in greek_bold_letters)
|
||||
greek_bold_unicode['lambda'] = greek_unicode['lamda']
|
||||
greek_bold_unicode['Lambda'] = greek_unicode['Lamda']
|
||||
greek_bold_unicode['varsigma'] = '\N{MATHEMATICAL BOLD SMALL FINAL SIGMA}'
|
||||
|
||||
digit_2txt = {
|
||||
'0': 'ZERO',
|
||||
'1': 'ONE',
|
||||
'2': 'TWO',
|
||||
'3': 'THREE',
|
||||
'4': 'FOUR',
|
||||
'5': 'FIVE',
|
||||
'6': 'SIX',
|
||||
'7': 'SEVEN',
|
||||
'8': 'EIGHT',
|
||||
'9': 'NINE',
|
||||
}
|
||||
|
||||
symb_2txt = {
|
||||
'+': 'PLUS SIGN',
|
||||
'-': 'MINUS',
|
||||
'=': 'EQUALS SIGN',
|
||||
'(': 'LEFT PARENTHESIS',
|
||||
')': 'RIGHT PARENTHESIS',
|
||||
'[': 'LEFT SQUARE BRACKET',
|
||||
']': 'RIGHT SQUARE BRACKET',
|
||||
'{': 'LEFT CURLY BRACKET',
|
||||
'}': 'RIGHT CURLY BRACKET',
|
||||
|
||||
# non-std
|
||||
'{}': 'CURLY BRACKET',
|
||||
'sum': 'SUMMATION',
|
||||
'int': 'INTEGRAL',
|
||||
}
|
||||
|
||||
# SUBSCRIPT & SUPERSCRIPT
|
||||
LSUB = lambda letter: U('LATIN SUBSCRIPT SMALL LETTER %s' % letter.upper())
|
||||
GSUB = lambda letter: U('GREEK SUBSCRIPT SMALL LETTER %s' % letter.upper())
|
||||
DSUB = lambda digit: U('SUBSCRIPT %s' % digit_2txt[digit])
|
||||
SSUB = lambda symb: U('SUBSCRIPT %s' % symb_2txt[symb])
|
||||
|
||||
LSUP = lambda letter: U('SUPERSCRIPT LATIN SMALL LETTER %s' % letter.upper())
|
||||
DSUP = lambda digit: U('SUPERSCRIPT %s' % digit_2txt[digit])
|
||||
SSUP = lambda symb: U('SUPERSCRIPT %s' % symb_2txt[symb])
|
||||
|
||||
sub = {} # symb -> subscript symbol
|
||||
sup = {} # symb -> superscript symbol
|
||||
|
||||
# latin subscripts
|
||||
for l in 'aeioruvxhklmnpst':
|
||||
sub[l] = LSUB(l)
|
||||
|
||||
for l in 'in':
|
||||
sup[l] = LSUP(l)
|
||||
|
||||
for gl in ['beta', 'gamma', 'rho', 'phi', 'chi']:
|
||||
sub[gl] = GSUB(gl)
|
||||
|
||||
for d in [str(i) for i in range(10)]:
|
||||
sub[d] = DSUB(d)
|
||||
sup[d] = DSUP(d)
|
||||
|
||||
for s in '+-=()':
|
||||
sub[s] = SSUB(s)
|
||||
sup[s] = SSUP(s)
|
||||
|
||||
# Variable modifiers
|
||||
# TODO: Make brackets adjust to height of contents
|
||||
modifier_dict = {
|
||||
# Accents
|
||||
'mathring': lambda s: center_accent(s, '\N{COMBINING RING ABOVE}'),
|
||||
'ddddot': lambda s: center_accent(s, '\N{COMBINING FOUR DOTS ABOVE}'),
|
||||
'dddot': lambda s: center_accent(s, '\N{COMBINING THREE DOTS ABOVE}'),
|
||||
'ddot': lambda s: center_accent(s, '\N{COMBINING DIAERESIS}'),
|
||||
'dot': lambda s: center_accent(s, '\N{COMBINING DOT ABOVE}'),
|
||||
'check': lambda s: center_accent(s, '\N{COMBINING CARON}'),
|
||||
'breve': lambda s: center_accent(s, '\N{COMBINING BREVE}'),
|
||||
'acute': lambda s: center_accent(s, '\N{COMBINING ACUTE ACCENT}'),
|
||||
'grave': lambda s: center_accent(s, '\N{COMBINING GRAVE ACCENT}'),
|
||||
'tilde': lambda s: center_accent(s, '\N{COMBINING TILDE}'),
|
||||
'hat': lambda s: center_accent(s, '\N{COMBINING CIRCUMFLEX ACCENT}'),
|
||||
'bar': lambda s: center_accent(s, '\N{COMBINING OVERLINE}'),
|
||||
'vec': lambda s: center_accent(s, '\N{COMBINING RIGHT ARROW ABOVE}'),
|
||||
'prime': lambda s: s+'\N{PRIME}',
|
||||
'prm': lambda s: s+'\N{PRIME}',
|
||||
# # Faces -- these are here for some compatibility with latex printing
|
||||
# 'bold': lambda s: s,
|
||||
# 'bm': lambda s: s,
|
||||
# 'cal': lambda s: s,
|
||||
# 'scr': lambda s: s,
|
||||
# 'frak': lambda s: s,
|
||||
# Brackets
|
||||
'norm': lambda s: '\N{DOUBLE VERTICAL LINE}'+s+'\N{DOUBLE VERTICAL LINE}',
|
||||
'avg': lambda s: '\N{MATHEMATICAL LEFT ANGLE BRACKET}'+s+'\N{MATHEMATICAL RIGHT ANGLE BRACKET}',
|
||||
'abs': lambda s: '\N{VERTICAL LINE}'+s+'\N{VERTICAL LINE}',
|
||||
'mag': lambda s: '\N{VERTICAL LINE}'+s+'\N{VERTICAL LINE}',
|
||||
}
|
||||
|
||||
# VERTICAL OBJECTS
|
||||
HUP = lambda symb: U('%s UPPER HOOK' % symb_2txt[symb])
|
||||
CUP = lambda symb: U('%s UPPER CORNER' % symb_2txt[symb])
|
||||
MID = lambda symb: U('%s MIDDLE PIECE' % symb_2txt[symb])
|
||||
EXT = lambda symb: U('%s EXTENSION' % symb_2txt[symb])
|
||||
HLO = lambda symb: U('%s LOWER HOOK' % symb_2txt[symb])
|
||||
CLO = lambda symb: U('%s LOWER CORNER' % symb_2txt[symb])
|
||||
TOP = lambda symb: U('%s TOP' % symb_2txt[symb])
|
||||
BOT = lambda symb: U('%s BOTTOM' % symb_2txt[symb])
|
||||
|
||||
# {} '(' -> (extension, start, end, middle) 1-character
|
||||
_xobj_unicode = {
|
||||
|
||||
# vertical symbols
|
||||
# (( ext, top, bot, mid ), c1)
|
||||
'(': (( EXT('('), HUP('('), HLO('(') ), '('),
|
||||
')': (( EXT(')'), HUP(')'), HLO(')') ), ')'),
|
||||
'[': (( EXT('['), CUP('['), CLO('[') ), '['),
|
||||
']': (( EXT(']'), CUP(']'), CLO(']') ), ']'),
|
||||
'{': (( EXT('{}'), HUP('{'), HLO('{'), MID('{') ), '{'),
|
||||
'}': (( EXT('{}'), HUP('}'), HLO('}'), MID('}') ), '}'),
|
||||
'|': U('BOX DRAWINGS LIGHT VERTICAL'),
|
||||
'Tee': U('BOX DRAWINGS LIGHT UP AND HORIZONTAL'),
|
||||
'UpTack': U('BOX DRAWINGS LIGHT DOWN AND HORIZONTAL'),
|
||||
'corner_up_centre'
|
||||
'(_ext': U('LEFT PARENTHESIS EXTENSION'),
|
||||
')_ext': U('RIGHT PARENTHESIS EXTENSION'),
|
||||
'(_lower_hook': U('LEFT PARENTHESIS LOWER HOOK'),
|
||||
')_lower_hook': U('RIGHT PARENTHESIS LOWER HOOK'),
|
||||
'(_upper_hook': U('LEFT PARENTHESIS UPPER HOOK'),
|
||||
')_upper_hook': U('RIGHT PARENTHESIS UPPER HOOK'),
|
||||
'<': ((U('BOX DRAWINGS LIGHT VERTICAL'),
|
||||
U('BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT'),
|
||||
U('BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT')), '<'),
|
||||
|
||||
'>': ((U('BOX DRAWINGS LIGHT VERTICAL'),
|
||||
U('BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT'),
|
||||
U('BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT')), '>'),
|
||||
|
||||
'lfloor': (( EXT('['), EXT('['), CLO('[') ), U('LEFT FLOOR')),
|
||||
'rfloor': (( EXT(']'), EXT(']'), CLO(']') ), U('RIGHT FLOOR')),
|
||||
'lceil': (( EXT('['), CUP('['), EXT('[') ), U('LEFT CEILING')),
|
||||
'rceil': (( EXT(']'), CUP(']'), EXT(']') ), U('RIGHT CEILING')),
|
||||
|
||||
'int': (( EXT('int'), U('TOP HALF INTEGRAL'), U('BOTTOM HALF INTEGRAL') ), U('INTEGRAL')),
|
||||
'sum': (( U('BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT'), '_', U('OVERLINE'), U('BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT')), U('N-ARY SUMMATION')),
|
||||
|
||||
# horizontal objects
|
||||
#'-': '-',
|
||||
'-': U('BOX DRAWINGS LIGHT HORIZONTAL'),
|
||||
'_': U('LOW LINE'),
|
||||
# We used to use this, but LOW LINE looks better for roots, as it's a
|
||||
# little lower (i.e., it lines up with the / perfectly. But perhaps this
|
||||
# one would still be wanted for some cases?
|
||||
# '_': U('HORIZONTAL SCAN LINE-9'),
|
||||
|
||||
# diagonal objects '\' & '/' ?
|
||||
'/': U('BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT'),
|
||||
'\\': U('BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT'),
|
||||
}
|
||||
|
||||
_xobj_ascii = {
|
||||
# vertical symbols
|
||||
# (( ext, top, bot, mid ), c1)
|
||||
'(': (( '|', '/', '\\' ), '('),
|
||||
')': (( '|', '\\', '/' ), ')'),
|
||||
|
||||
# XXX this looks ugly
|
||||
# '[': (( '|', '-', '-' ), '['),
|
||||
# ']': (( '|', '-', '-' ), ']'),
|
||||
# XXX not so ugly :(
|
||||
'[': (( '[', '[', '[' ), '['),
|
||||
']': (( ']', ']', ']' ), ']'),
|
||||
|
||||
'{': (( '|', '/', '\\', '<' ), '{'),
|
||||
'}': (( '|', '\\', '/', '>' ), '}'),
|
||||
'|': '|',
|
||||
|
||||
'<': (( '|', '/', '\\' ), '<'),
|
||||
'>': (( '|', '\\', '/' ), '>'),
|
||||
|
||||
'int': ( ' | ', ' /', '/ ' ),
|
||||
|
||||
# horizontal objects
|
||||
'-': '-',
|
||||
'_': '_',
|
||||
|
||||
# diagonal objects '\' & '/' ?
|
||||
'/': '/',
|
||||
'\\': '\\',
|
||||
}
|
||||
|
||||
|
||||
def xobj(symb, length):
|
||||
"""Construct spatial object of given length.
|
||||
|
||||
return: [] of equal-length strings
|
||||
"""
|
||||
|
||||
if length <= 0:
|
||||
raise ValueError("Length should be greater than 0")
|
||||
|
||||
# TODO robustify when no unicodedat available
|
||||
if _use_unicode:
|
||||
_xobj = _xobj_unicode
|
||||
else:
|
||||
_xobj = _xobj_ascii
|
||||
|
||||
vinfo = _xobj[symb]
|
||||
|
||||
c1 = top = bot = mid = None
|
||||
|
||||
if not isinstance(vinfo, tuple): # 1 entry
|
||||
ext = vinfo
|
||||
else:
|
||||
if isinstance(vinfo[0], tuple): # (vlong), c1
|
||||
vlong = vinfo[0]
|
||||
c1 = vinfo[1]
|
||||
else: # (vlong), c1
|
||||
vlong = vinfo
|
||||
|
||||
ext = vlong[0]
|
||||
|
||||
try:
|
||||
top = vlong[1]
|
||||
bot = vlong[2]
|
||||
mid = vlong[3]
|
||||
except IndexError:
|
||||
pass
|
||||
|
||||
if c1 is None:
|
||||
c1 = ext
|
||||
if top is None:
|
||||
top = ext
|
||||
if bot is None:
|
||||
bot = ext
|
||||
if mid is not None:
|
||||
if (length % 2) == 0:
|
||||
# even height, but we have to print it somehow anyway...
|
||||
# XXX is it ok?
|
||||
length += 1
|
||||
|
||||
else:
|
||||
mid = ext
|
||||
|
||||
if length == 1:
|
||||
return c1
|
||||
|
||||
res = []
|
||||
next = (length - 2)//2
|
||||
nmid = (length - 2) - next*2
|
||||
|
||||
res += [top]
|
||||
res += [ext]*next
|
||||
res += [mid]*nmid
|
||||
res += [ext]*next
|
||||
res += [bot]
|
||||
|
||||
return res
|
||||
|
||||
|
||||
def vobj(symb, height):
|
||||
"""Construct vertical object of a given height
|
||||
|
||||
see: xobj
|
||||
"""
|
||||
return '\n'.join( xobj(symb, height) )
|
||||
|
||||
|
||||
def hobj(symb, width):
|
||||
"""Construct horizontal object of a given width
|
||||
|
||||
see: xobj
|
||||
"""
|
||||
return ''.join( xobj(symb, width) )
|
||||
|
||||
# RADICAL
|
||||
# n -> symbol
|
||||
root = {
|
||||
2: U('SQUARE ROOT'), # U('RADICAL SYMBOL BOTTOM')
|
||||
3: U('CUBE ROOT'),
|
||||
4: U('FOURTH ROOT'),
|
||||
}
|
||||
|
||||
|
||||
# RATIONAL
|
||||
VF = lambda txt: U('VULGAR FRACTION %s' % txt)
|
||||
|
||||
# (p,q) -> symbol
|
||||
frac = {
|
||||
(1, 2): VF('ONE HALF'),
|
||||
(1, 3): VF('ONE THIRD'),
|
||||
(2, 3): VF('TWO THIRDS'),
|
||||
(1, 4): VF('ONE QUARTER'),
|
||||
(3, 4): VF('THREE QUARTERS'),
|
||||
(1, 5): VF('ONE FIFTH'),
|
||||
(2, 5): VF('TWO FIFTHS'),
|
||||
(3, 5): VF('THREE FIFTHS'),
|
||||
(4, 5): VF('FOUR FIFTHS'),
|
||||
(1, 6): VF('ONE SIXTH'),
|
||||
(5, 6): VF('FIVE SIXTHS'),
|
||||
(1, 8): VF('ONE EIGHTH'),
|
||||
(3, 8): VF('THREE EIGHTHS'),
|
||||
(5, 8): VF('FIVE EIGHTHS'),
|
||||
(7, 8): VF('SEVEN EIGHTHS'),
|
||||
}
|
||||
|
||||
|
||||
# atom symbols
|
||||
_xsym = {
|
||||
'==': ('=', '='),
|
||||
'<': ('<', '<'),
|
||||
'>': ('>', '>'),
|
||||
'<=': ('<=', U('LESS-THAN OR EQUAL TO')),
|
||||
'>=': ('>=', U('GREATER-THAN OR EQUAL TO')),
|
||||
'!=': ('!=', U('NOT EQUAL TO')),
|
||||
':=': (':=', ':='),
|
||||
'+=': ('+=', '+='),
|
||||
'-=': ('-=', '-='),
|
||||
'*=': ('*=', '*='),
|
||||
'/=': ('/=', '/='),
|
||||
'%=': ('%=', '%='),
|
||||
'*': ('*', U('DOT OPERATOR')),
|
||||
'-->': ('-->', U('EM DASH') + U('EM DASH') +
|
||||
U('BLACK RIGHT-POINTING TRIANGLE') if U('EM DASH')
|
||||
and U('BLACK RIGHT-POINTING TRIANGLE') else None),
|
||||
'==>': ('==>', U('BOX DRAWINGS DOUBLE HORIZONTAL') +
|
||||
U('BOX DRAWINGS DOUBLE HORIZONTAL') +
|
||||
U('BLACK RIGHT-POINTING TRIANGLE') if
|
||||
U('BOX DRAWINGS DOUBLE HORIZONTAL') and
|
||||
U('BOX DRAWINGS DOUBLE HORIZONTAL') and
|
||||
U('BLACK RIGHT-POINTING TRIANGLE') else None),
|
||||
'.': ('*', U('RING OPERATOR')),
|
||||
}
|
||||
|
||||
|
||||
def xsym(sym):
|
||||
"""get symbology for a 'character'"""
|
||||
op = _xsym[sym]
|
||||
|
||||
if _use_unicode:
|
||||
return op[1]
|
||||
else:
|
||||
return op[0]
|
||||
|
||||
|
||||
# SYMBOLS
|
||||
|
||||
atoms_table = {
|
||||
# class how-to-display
|
||||
'Exp1': U('SCRIPT SMALL E'),
|
||||
'Pi': U('GREEK SMALL LETTER PI'),
|
||||
'Infinity': U('INFINITY'),
|
||||
'NegativeInfinity': U('INFINITY') and ('-' + U('INFINITY')), # XXX what to do here
|
||||
#'ImaginaryUnit': U('GREEK SMALL LETTER IOTA'),
|
||||
#'ImaginaryUnit': U('MATHEMATICAL ITALIC SMALL I'),
|
||||
'ImaginaryUnit': U('DOUBLE-STRUCK ITALIC SMALL I'),
|
||||
'EmptySet': U('EMPTY SET'),
|
||||
'Naturals': U('DOUBLE-STRUCK CAPITAL N'),
|
||||
'Naturals0': (U('DOUBLE-STRUCK CAPITAL N') and
|
||||
(U('DOUBLE-STRUCK CAPITAL N') +
|
||||
U('SUBSCRIPT ZERO'))),
|
||||
'Integers': U('DOUBLE-STRUCK CAPITAL Z'),
|
||||
'Rationals': U('DOUBLE-STRUCK CAPITAL Q'),
|
||||
'Reals': U('DOUBLE-STRUCK CAPITAL R'),
|
||||
'Complexes': U('DOUBLE-STRUCK CAPITAL C'),
|
||||
'Universe': U('MATHEMATICAL DOUBLE-STRUCK CAPITAL U'),
|
||||
'IdentityMatrix': U('MATHEMATICAL DOUBLE-STRUCK CAPITAL I'),
|
||||
'ZeroMatrix': U('MATHEMATICAL DOUBLE-STRUCK DIGIT ZERO'),
|
||||
'OneMatrix': U('MATHEMATICAL DOUBLE-STRUCK DIGIT ONE'),
|
||||
'Differential': U('DOUBLE-STRUCK ITALIC SMALL D'),
|
||||
'Union': U('UNION'),
|
||||
'ElementOf': U('ELEMENT OF'),
|
||||
'SmallElementOf': U('SMALL ELEMENT OF'),
|
||||
'SymmetricDifference': U('INCREMENT'),
|
||||
'Intersection': U('INTERSECTION'),
|
||||
'Ring': U('RING OPERATOR'),
|
||||
'Multiplication': U('MULTIPLICATION SIGN'),
|
||||
'TensorProduct': U('N-ARY CIRCLED TIMES OPERATOR'),
|
||||
'Dots': U('HORIZONTAL ELLIPSIS'),
|
||||
'Modifier Letter Low Ring':U('Modifier Letter Low Ring'),
|
||||
'EmptySequence': 'EmptySequence',
|
||||
'SuperscriptPlus': U('SUPERSCRIPT PLUS SIGN'),
|
||||
'SuperscriptMinus': U('SUPERSCRIPT MINUS'),
|
||||
'Dagger': U('DAGGER'),
|
||||
'Degree': U('DEGREE SIGN'),
|
||||
#Logic Symbols
|
||||
'And': U('LOGICAL AND'),
|
||||
'Or': U('LOGICAL OR'),
|
||||
'Not': U('NOT SIGN'),
|
||||
'Nor': U('NOR'),
|
||||
'Nand': U('NAND'),
|
||||
'Xor': U('XOR'),
|
||||
'Equiv': U('LEFT RIGHT DOUBLE ARROW'),
|
||||
'NotEquiv': U('LEFT RIGHT DOUBLE ARROW WITH STROKE'),
|
||||
'Implies': U('LEFT RIGHT DOUBLE ARROW'),
|
||||
'NotImplies': U('LEFT RIGHT DOUBLE ARROW WITH STROKE'),
|
||||
'Arrow': U('RIGHTWARDS ARROW'),
|
||||
'ArrowFromBar': U('RIGHTWARDS ARROW FROM BAR'),
|
||||
'NotArrow': U('RIGHTWARDS ARROW WITH STROKE'),
|
||||
'Tautology': U('BOX DRAWINGS LIGHT UP AND HORIZONTAL'),
|
||||
'Contradiction': U('BOX DRAWINGS LIGHT DOWN AND HORIZONTAL')
|
||||
}
|
||||
|
||||
|
||||
def pretty_atom(atom_name, default=None, printer=None):
|
||||
"""return pretty representation of an atom"""
|
||||
if _use_unicode:
|
||||
if printer is not None and atom_name == 'ImaginaryUnit' and printer._settings['imaginary_unit'] == 'j':
|
||||
return U('DOUBLE-STRUCK ITALIC SMALL J')
|
||||
else:
|
||||
return atoms_table[atom_name]
|
||||
else:
|
||||
if default is not None:
|
||||
return default
|
||||
|
||||
raise KeyError('only unicode') # send it default printer
|
||||
|
||||
|
||||
def pretty_symbol(symb_name, bold_name=False):
|
||||
"""return pretty representation of a symbol"""
|
||||
# let's split symb_name into symbol + index
|
||||
# UC: beta1
|
||||
# UC: f_beta
|
||||
|
||||
if not _use_unicode:
|
||||
return symb_name
|
||||
|
||||
name, sups, subs = split_super_sub(symb_name)
|
||||
|
||||
def translate(s, bold_name) :
|
||||
if bold_name:
|
||||
gG = greek_bold_unicode.get(s)
|
||||
else:
|
||||
gG = greek_unicode.get(s)
|
||||
if gG is not None:
|
||||
return gG
|
||||
for key in sorted(modifier_dict.keys(), key=lambda k:len(k), reverse=True) :
|
||||
if s.lower().endswith(key) and len(s)>len(key):
|
||||
return modifier_dict[key](translate(s[:-len(key)], bold_name))
|
||||
if bold_name:
|
||||
return ''.join([bold_unicode[c] for c in s])
|
||||
return s
|
||||
|
||||
name = translate(name, bold_name)
|
||||
|
||||
# Let's prettify sups/subs. If it fails at one of them, pretty sups/subs are
|
||||
# not used at all.
|
||||
def pretty_list(l, mapping):
|
||||
result = []
|
||||
for s in l:
|
||||
pretty = mapping.get(s)
|
||||
if pretty is None:
|
||||
try: # match by separate characters
|
||||
pretty = ''.join([mapping[c] for c in s])
|
||||
except (TypeError, KeyError):
|
||||
return None
|
||||
result.append(pretty)
|
||||
return result
|
||||
|
||||
pretty_sups = pretty_list(sups, sup)
|
||||
if pretty_sups is not None:
|
||||
pretty_subs = pretty_list(subs, sub)
|
||||
else:
|
||||
pretty_subs = None
|
||||
|
||||
# glue the results into one string
|
||||
if pretty_subs is None: # nice formatting of sups/subs did not work
|
||||
if subs:
|
||||
name += '_'+'_'.join([translate(s, bold_name) for s in subs])
|
||||
if sups:
|
||||
name += '__'+'__'.join([translate(s, bold_name) for s in sups])
|
||||
return name
|
||||
else:
|
||||
sups_result = ' '.join(pretty_sups)
|
||||
subs_result = ' '.join(pretty_subs)
|
||||
|
||||
return ''.join([name, sups_result, subs_result])
|
||||
|
||||
|
||||
def annotated(letter):
|
||||
"""
|
||||
Return a stylised drawing of the letter ``letter``, together with
|
||||
information on how to put annotations (super- and subscripts to the
|
||||
left and to the right) on it.
|
||||
|
||||
See pretty.py functions _print_meijerg, _print_hyper on how to use this
|
||||
information.
|
||||
"""
|
||||
ucode_pics = {
|
||||
'F': (2, 0, 2, 0, '\N{BOX DRAWINGS LIGHT DOWN AND RIGHT}\N{BOX DRAWINGS LIGHT HORIZONTAL}\n'
|
||||
'\N{BOX DRAWINGS LIGHT VERTICAL AND RIGHT}\N{BOX DRAWINGS LIGHT HORIZONTAL}\n'
|
||||
'\N{BOX DRAWINGS LIGHT UP}'),
|
||||
'G': (3, 0, 3, 1, '\N{BOX DRAWINGS LIGHT ARC DOWN AND RIGHT}\N{BOX DRAWINGS LIGHT HORIZONTAL}\N{BOX DRAWINGS LIGHT ARC DOWN AND LEFT}\n'
|
||||
'\N{BOX DRAWINGS LIGHT VERTICAL}\N{BOX DRAWINGS LIGHT RIGHT}\N{BOX DRAWINGS LIGHT DOWN AND LEFT}\n'
|
||||
'\N{BOX DRAWINGS LIGHT ARC UP AND RIGHT}\N{BOX DRAWINGS LIGHT HORIZONTAL}\N{BOX DRAWINGS LIGHT ARC UP AND LEFT}')
|
||||
}
|
||||
ascii_pics = {
|
||||
'F': (3, 0, 3, 0, ' _\n|_\n|\n'),
|
||||
'G': (3, 0, 3, 1, ' __\n/__\n\\_|')
|
||||
}
|
||||
|
||||
if _use_unicode:
|
||||
return ucode_pics[letter]
|
||||
else:
|
||||
return ascii_pics[letter]
|
||||
|
||||
_remove_combining = dict.fromkeys(list(range(ord('\N{COMBINING GRAVE ACCENT}'), ord('\N{COMBINING LATIN SMALL LETTER X}')))
|
||||
+ list(range(ord('\N{COMBINING LEFT HARPOON ABOVE}'), ord('\N{COMBINING ASTERISK ABOVE}'))))
|
||||
|
||||
def is_combining(sym):
|
||||
"""Check whether symbol is a unicode modifier. """
|
||||
|
||||
return ord(sym) in _remove_combining
|
||||
|
||||
|
||||
def center_accent(string, accent):
|
||||
"""
|
||||
Returns a string with accent inserted on the middle character. Useful to
|
||||
put combining accents on symbol names, including multi-character names.
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
string : string
|
||||
The string to place the accent in.
|
||||
accent : string
|
||||
The combining accent to insert
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Combining_character
|
||||
.. [2] https://en.wikipedia.org/wiki/Combining_Diacritical_Marks
|
||||
|
||||
"""
|
||||
|
||||
# Accent is placed on the previous character, although it may not always look
|
||||
# like that depending on console
|
||||
midpoint = len(string) // 2 + 1
|
||||
firstpart = string[:midpoint]
|
||||
secondpart = string[midpoint:]
|
||||
return firstpart + accent + secondpart
|
||||
|
||||
|
||||
def line_width(line):
|
||||
"""Unicode combining symbols (modifiers) are not ever displayed as
|
||||
separate symbols and thus should not be counted
|
||||
"""
|
||||
return len(line.translate(_remove_combining))
|
||||
|
||||
|
||||
def is_subscriptable_in_unicode(subscript):
|
||||
"""
|
||||
Checks whether a string is subscriptable in unicode or not.
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
subscript: the string which needs to be checked
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.printing.pretty.pretty_symbology import is_subscriptable_in_unicode
|
||||
>>> is_subscriptable_in_unicode('abc')
|
||||
False
|
||||
>>> is_subscriptable_in_unicode('123')
|
||||
True
|
||||
|
||||
"""
|
||||
return all(character in sub for character in subscript)
|
||||
|
||||
|
||||
def center_pad(wstring, wtarget, fillchar=' '):
|
||||
"""
|
||||
Return the padding strings necessary to center a string of
|
||||
wstring characters wide in a wtarget wide space.
|
||||
|
||||
The line_width wstring should always be less or equal to wtarget
|
||||
or else a ValueError will be raised.
|
||||
"""
|
||||
if wstring > wtarget:
|
||||
raise ValueError('not enough space for string')
|
||||
wdelta = wtarget - wstring
|
||||
|
||||
wleft = wdelta // 2 # favor left '1 '
|
||||
wright = wdelta - wleft
|
||||
|
||||
left = fillchar * wleft
|
||||
right = fillchar * wright
|
||||
|
||||
return left, right
|
||||
|
||||
|
||||
def center(string, width, fillchar=' '):
|
||||
"""Return a centered string of length determined by `line_width`
|
||||
that uses `fillchar` for padding.
|
||||
"""
|
||||
left, right = center_pad(line_width(string), width, fillchar)
|
||||
return ''.join([left, string, right])
|
||||
@@ -0,0 +1,537 @@
|
||||
"""Prettyprinter by Jurjen Bos.
|
||||
(I hate spammers: mail me at pietjepuk314 at the reverse of ku.oc.oohay).
|
||||
All objects have a method that create a "stringPict",
|
||||
that can be used in the str method for pretty printing.
|
||||
|
||||
Updates by Jason Gedge (email <my last name> at cs mun ca)
|
||||
- terminal_string() method
|
||||
- minor fixes and changes (mostly to prettyForm)
|
||||
|
||||
TODO:
|
||||
- Allow left/center/right alignment options for above/below and
|
||||
top/center/bottom alignment options for left/right
|
||||
"""
|
||||
|
||||
import shutil
|
||||
|
||||
from .pretty_symbology import hobj, vobj, xsym, xobj, pretty_use_unicode, line_width, center
|
||||
from sympy.utilities.exceptions import sympy_deprecation_warning
|
||||
|
||||
_GLOBAL_WRAP_LINE = None
|
||||
|
||||
class stringPict:
|
||||
"""An ASCII picture.
|
||||
The pictures are represented as a list of equal length strings.
|
||||
"""
|
||||
#special value for stringPict.below
|
||||
LINE = 'line'
|
||||
|
||||
def __init__(self, s, baseline=0):
|
||||
"""Initialize from string.
|
||||
Multiline strings are centered.
|
||||
"""
|
||||
self.s = s
|
||||
#picture is a string that just can be printed
|
||||
self.picture = stringPict.equalLengths(s.splitlines())
|
||||
#baseline is the line number of the "base line"
|
||||
self.baseline = baseline
|
||||
self.binding = None
|
||||
|
||||
@staticmethod
|
||||
def equalLengths(lines):
|
||||
# empty lines
|
||||
if not lines:
|
||||
return ['']
|
||||
|
||||
width = max(line_width(line) for line in lines)
|
||||
return [center(line, width) for line in lines]
|
||||
|
||||
def height(self):
|
||||
"""The height of the picture in characters."""
|
||||
return len(self.picture)
|
||||
|
||||
def width(self):
|
||||
"""The width of the picture in characters."""
|
||||
return line_width(self.picture[0])
|
||||
|
||||
@staticmethod
|
||||
def next(*args):
|
||||
"""Put a string of stringPicts next to each other.
|
||||
Returns string, baseline arguments for stringPict.
|
||||
"""
|
||||
#convert everything to stringPicts
|
||||
objects = []
|
||||
for arg in args:
|
||||
if isinstance(arg, str):
|
||||
arg = stringPict(arg)
|
||||
objects.append(arg)
|
||||
|
||||
#make a list of pictures, with equal height and baseline
|
||||
newBaseline = max(obj.baseline for obj in objects)
|
||||
newHeightBelowBaseline = max(
|
||||
obj.height() - obj.baseline
|
||||
for obj in objects)
|
||||
newHeight = newBaseline + newHeightBelowBaseline
|
||||
|
||||
pictures = []
|
||||
for obj in objects:
|
||||
oneEmptyLine = [' '*obj.width()]
|
||||
basePadding = newBaseline - obj.baseline
|
||||
totalPadding = newHeight - obj.height()
|
||||
pictures.append(
|
||||
oneEmptyLine * basePadding +
|
||||
obj.picture +
|
||||
oneEmptyLine * (totalPadding - basePadding))
|
||||
|
||||
result = [''.join(lines) for lines in zip(*pictures)]
|
||||
return '\n'.join(result), newBaseline
|
||||
|
||||
def right(self, *args):
|
||||
r"""Put pictures next to this one.
|
||||
Returns string, baseline arguments for stringPict.
|
||||
(Multiline) strings are allowed, and are given a baseline of 0.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.printing.pretty.stringpict import stringPict
|
||||
>>> print(stringPict("10").right(" + ",stringPict("1\r-\r2",1))[0])
|
||||
1
|
||||
10 + -
|
||||
2
|
||||
|
||||
"""
|
||||
return stringPict.next(self, *args)
|
||||
|
||||
def left(self, *args):
|
||||
"""Put pictures (left to right) at left.
|
||||
Returns string, baseline arguments for stringPict.
|
||||
"""
|
||||
return stringPict.next(*(args + (self,)))
|
||||
|
||||
@staticmethod
|
||||
def stack(*args):
|
||||
"""Put pictures on top of each other,
|
||||
from top to bottom.
|
||||
Returns string, baseline arguments for stringPict.
|
||||
The baseline is the baseline of the second picture.
|
||||
Everything is centered.
|
||||
Baseline is the baseline of the second picture.
|
||||
Strings are allowed.
|
||||
The special value stringPict.LINE is a row of '-' extended to the width.
|
||||
"""
|
||||
#convert everything to stringPicts; keep LINE
|
||||
objects = []
|
||||
for arg in args:
|
||||
if arg is not stringPict.LINE and isinstance(arg, str):
|
||||
arg = stringPict(arg)
|
||||
objects.append(arg)
|
||||
|
||||
#compute new width
|
||||
newWidth = max(
|
||||
obj.width()
|
||||
for obj in objects
|
||||
if obj is not stringPict.LINE)
|
||||
|
||||
lineObj = stringPict(hobj('-', newWidth))
|
||||
|
||||
#replace LINE with proper lines
|
||||
for i, obj in enumerate(objects):
|
||||
if obj is stringPict.LINE:
|
||||
objects[i] = lineObj
|
||||
|
||||
#stack the pictures, and center the result
|
||||
newPicture = [center(line, newWidth) for obj in objects for line in obj.picture]
|
||||
newBaseline = objects[0].height() + objects[1].baseline
|
||||
return '\n'.join(newPicture), newBaseline
|
||||
|
||||
def below(self, *args):
|
||||
"""Put pictures under this picture.
|
||||
Returns string, baseline arguments for stringPict.
|
||||
Baseline is baseline of top picture
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.printing.pretty.stringpict import stringPict
|
||||
>>> print(stringPict("x+3").below(
|
||||
... stringPict.LINE, '3')[0]) #doctest: +NORMALIZE_WHITESPACE
|
||||
x+3
|
||||
---
|
||||
3
|
||||
|
||||
"""
|
||||
s, baseline = stringPict.stack(self, *args)
|
||||
return s, self.baseline
|
||||
|
||||
def above(self, *args):
|
||||
"""Put pictures above this picture.
|
||||
Returns string, baseline arguments for stringPict.
|
||||
Baseline is baseline of bottom picture.
|
||||
"""
|
||||
string, baseline = stringPict.stack(*(args + (self,)))
|
||||
baseline = len(string.splitlines()) - self.height() + self.baseline
|
||||
return string, baseline
|
||||
|
||||
def parens(self, left='(', right=')', ifascii_nougly=False):
|
||||
"""Put parentheses around self.
|
||||
Returns string, baseline arguments for stringPict.
|
||||
|
||||
left or right can be None or empty string which means 'no paren from
|
||||
that side'
|
||||
"""
|
||||
h = self.height()
|
||||
b = self.baseline
|
||||
|
||||
# XXX this is a hack -- ascii parens are ugly!
|
||||
if ifascii_nougly and not pretty_use_unicode():
|
||||
h = 1
|
||||
b = 0
|
||||
|
||||
res = self
|
||||
|
||||
if left:
|
||||
lparen = stringPict(vobj(left, h), baseline=b)
|
||||
res = stringPict(*lparen.right(self))
|
||||
if right:
|
||||
rparen = stringPict(vobj(right, h), baseline=b)
|
||||
res = stringPict(*res.right(rparen))
|
||||
|
||||
return ('\n'.join(res.picture), res.baseline)
|
||||
|
||||
def leftslash(self):
|
||||
"""Precede object by a slash of the proper size.
|
||||
"""
|
||||
# XXX not used anywhere ?
|
||||
height = max(
|
||||
self.baseline,
|
||||
self.height() - 1 - self.baseline)*2 + 1
|
||||
slash = '\n'.join(
|
||||
' '*(height - i - 1) + xobj('/', 1) + ' '*i
|
||||
for i in range(height)
|
||||
)
|
||||
return self.left(stringPict(slash, height//2))
|
||||
|
||||
def root(self, n=None):
|
||||
"""Produce a nice root symbol.
|
||||
Produces ugly results for big n inserts.
|
||||
"""
|
||||
# XXX not used anywhere
|
||||
# XXX duplicate of root drawing in pretty.py
|
||||
#put line over expression
|
||||
result = self.above('_'*self.width())
|
||||
#construct right half of root symbol
|
||||
height = self.height()
|
||||
slash = '\n'.join(
|
||||
' ' * (height - i - 1) + '/' + ' ' * i
|
||||
for i in range(height)
|
||||
)
|
||||
slash = stringPict(slash, height - 1)
|
||||
#left half of root symbol
|
||||
if height > 2:
|
||||
downline = stringPict('\\ \n \\', 1)
|
||||
else:
|
||||
downline = stringPict('\\')
|
||||
#put n on top, as low as possible
|
||||
if n is not None and n.width() > downline.width():
|
||||
downline = downline.left(' '*(n.width() - downline.width()))
|
||||
downline = downline.above(n)
|
||||
#build root symbol
|
||||
root = downline.right(slash)
|
||||
#glue it on at the proper height
|
||||
#normally, the root symbel is as high as self
|
||||
#which is one less than result
|
||||
#this moves the root symbol one down
|
||||
#if the root became higher, the baseline has to grow too
|
||||
root.baseline = result.baseline - result.height() + root.height()
|
||||
return result.left(root)
|
||||
|
||||
def render(self, * args, **kwargs):
|
||||
"""Return the string form of self.
|
||||
|
||||
Unless the argument line_break is set to False, it will
|
||||
break the expression in a form that can be printed
|
||||
on the terminal without being broken up.
|
||||
"""
|
||||
if _GLOBAL_WRAP_LINE is not None:
|
||||
kwargs["wrap_line"] = _GLOBAL_WRAP_LINE
|
||||
|
||||
if kwargs["wrap_line"] is False:
|
||||
return "\n".join(self.picture)
|
||||
|
||||
if kwargs["num_columns"] is not None:
|
||||
# Read the argument num_columns if it is not None
|
||||
ncols = kwargs["num_columns"]
|
||||
else:
|
||||
# Attempt to get a terminal width
|
||||
ncols = self.terminal_width()
|
||||
|
||||
if ncols <= 0:
|
||||
ncols = 80
|
||||
|
||||
# If smaller than the terminal width, no need to correct
|
||||
if self.width() <= ncols:
|
||||
return type(self.picture[0])(self)
|
||||
|
||||
"""
|
||||
Break long-lines in a visually pleasing format.
|
||||
without overflow indicators | with overflow indicators
|
||||
| 2 2 3 | | 2 2 3 ↪|
|
||||
|6*x *y + 4*x*y + | |6*x *y + 4*x*y + ↪|
|
||||
| | | |
|
||||
| 3 4 4 | |↪ 3 4 4 |
|
||||
|4*y*x + x + y | |↪ 4*y*x + x + y |
|
||||
|a*c*e + a*c*f + a*d | |a*c*e + a*c*f + a*d ↪|
|
||||
|*e + a*d*f + b*c*e | | |
|
||||
|+ b*c*f + b*d*e + b | |↪ *e + a*d*f + b*c* ↪|
|
||||
|*d*f | | |
|
||||
| | |↪ e + b*c*f + b*d*e ↪|
|
||||
| | | |
|
||||
| | |↪ + b*d*f |
|
||||
"""
|
||||
|
||||
overflow_first = ""
|
||||
if kwargs["use_unicode"] or pretty_use_unicode():
|
||||
overflow_start = "\N{RIGHTWARDS ARROW WITH HOOK} "
|
||||
overflow_end = " \N{RIGHTWARDS ARROW WITH HOOK}"
|
||||
else:
|
||||
overflow_start = "> "
|
||||
overflow_end = " >"
|
||||
|
||||
def chunks(line):
|
||||
"""Yields consecutive chunks of line_width ncols"""
|
||||
prefix = overflow_first
|
||||
width, start = line_width(prefix + overflow_end), 0
|
||||
for i, x in enumerate(line):
|
||||
wx = line_width(x)
|
||||
# Only flush the screen when the current character overflows.
|
||||
# This way, combining marks can be appended even when width == ncols.
|
||||
if width + wx > ncols:
|
||||
yield prefix + line[start:i] + overflow_end
|
||||
prefix = overflow_start
|
||||
width, start = line_width(prefix + overflow_end), i
|
||||
width += wx
|
||||
yield prefix + line[start:]
|
||||
|
||||
# Concurrently assemble chunks of all lines into individual screens
|
||||
pictures = zip(*map(chunks, self.picture))
|
||||
|
||||
# Join lines of each screen into sub-pictures
|
||||
pictures = ["\n".join(picture) for picture in pictures]
|
||||
|
||||
# Add spacers between sub-pictures
|
||||
return "\n\n".join(pictures)
|
||||
|
||||
def terminal_width(self):
|
||||
"""Return the terminal width if possible, otherwise return 0.
|
||||
"""
|
||||
size = shutil.get_terminal_size(fallback=(0, 0))
|
||||
return size.columns
|
||||
|
||||
def __eq__(self, o):
|
||||
if isinstance(o, str):
|
||||
return '\n'.join(self.picture) == o
|
||||
elif isinstance(o, stringPict):
|
||||
return o.picture == self.picture
|
||||
return False
|
||||
|
||||
def __hash__(self):
|
||||
return super().__hash__()
|
||||
|
||||
def __str__(self):
|
||||
return '\n'.join(self.picture)
|
||||
|
||||
def __repr__(self):
|
||||
return "stringPict(%r,%d)" % ('\n'.join(self.picture), self.baseline)
|
||||
|
||||
def __getitem__(self, index):
|
||||
return self.picture[index]
|
||||
|
||||
def __len__(self):
|
||||
return len(self.s)
|
||||
|
||||
|
||||
class prettyForm(stringPict):
|
||||
"""
|
||||
Extension of the stringPict class that knows about basic math applications,
|
||||
optimizing double minus signs.
|
||||
|
||||
"Binding" is interpreted as follows::
|
||||
|
||||
ATOM this is an atom: never needs to be parenthesized
|
||||
FUNC this is a function application: parenthesize if added (?)
|
||||
DIV this is a division: make wider division if divided
|
||||
POW this is a power: only parenthesize if exponent
|
||||
MUL this is a multiplication: parenthesize if powered
|
||||
ADD this is an addition: parenthesize if multiplied or powered
|
||||
NEG this is a negative number: optimize if added, parenthesize if
|
||||
multiplied or powered
|
||||
OPEN this is an open object: parenthesize if added, multiplied, or
|
||||
powered (example: Piecewise)
|
||||
"""
|
||||
ATOM, FUNC, DIV, POW, MUL, ADD, NEG, OPEN = range(8)
|
||||
|
||||
def __init__(self, s, baseline=0, binding=0, unicode=None):
|
||||
"""Initialize from stringPict and binding power."""
|
||||
stringPict.__init__(self, s, baseline)
|
||||
self.binding = binding
|
||||
if unicode is not None:
|
||||
sympy_deprecation_warning(
|
||||
"""
|
||||
The unicode argument to prettyForm is deprecated. Only the s
|
||||
argument (the first positional argument) should be passed.
|
||||
""",
|
||||
deprecated_since_version="1.7",
|
||||
active_deprecations_target="deprecated-pretty-printing-functions")
|
||||
self._unicode = unicode or s
|
||||
|
||||
@property
|
||||
def unicode(self):
|
||||
sympy_deprecation_warning(
|
||||
"""
|
||||
The prettyForm.unicode attribute is deprecated. Use the
|
||||
prettyForm.s attribute instead.
|
||||
""",
|
||||
deprecated_since_version="1.7",
|
||||
active_deprecations_target="deprecated-pretty-printing-functions")
|
||||
return self._unicode
|
||||
|
||||
# Note: code to handle subtraction is in _print_Add
|
||||
|
||||
def __add__(self, *others):
|
||||
"""Make a pretty addition.
|
||||
Addition of negative numbers is simplified.
|
||||
"""
|
||||
arg = self
|
||||
if arg.binding > prettyForm.NEG:
|
||||
arg = stringPict(*arg.parens())
|
||||
result = [arg]
|
||||
for arg in others:
|
||||
#add parentheses for weak binders
|
||||
if arg.binding > prettyForm.NEG:
|
||||
arg = stringPict(*arg.parens())
|
||||
#use existing minus sign if available
|
||||
if arg.binding != prettyForm.NEG:
|
||||
result.append(' + ')
|
||||
result.append(arg)
|
||||
return prettyForm(binding=prettyForm.ADD, *stringPict.next(*result))
|
||||
|
||||
def __truediv__(self, den, slashed=False):
|
||||
"""Make a pretty division; stacked or slashed.
|
||||
"""
|
||||
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())
|
||||
|
||||
if num.binding==prettyForm.NEG:
|
||||
num = num.right(" ")[0]
|
||||
|
||||
return prettyForm(binding=prettyForm.DIV, *stringPict.stack(
|
||||
num,
|
||||
stringPict.LINE,
|
||||
den))
|
||||
|
||||
def __mul__(self, *others):
|
||||
"""Make a pretty multiplication.
|
||||
Parentheses are needed around +, - and neg.
|
||||
"""
|
||||
quantity = {
|
||||
'degree': "\N{DEGREE SIGN}"
|
||||
}
|
||||
|
||||
if len(others) == 0:
|
||||
return self # We aren't actually multiplying... So nothing to do here.
|
||||
|
||||
# add parens on args that need them
|
||||
arg = self
|
||||
if arg.binding > prettyForm.MUL and arg.binding != prettyForm.NEG:
|
||||
arg = stringPict(*arg.parens())
|
||||
result = [arg]
|
||||
for arg in others:
|
||||
if arg.picture[0] not in quantity.values():
|
||||
result.append(xsym('*'))
|
||||
#add parentheses for weak binders
|
||||
if arg.binding > prettyForm.MUL and arg.binding != prettyForm.NEG:
|
||||
arg = stringPict(*arg.parens())
|
||||
result.append(arg)
|
||||
|
||||
len_res = len(result)
|
||||
for i in range(len_res):
|
||||
if i < len_res - 1 and result[i] == '-1' and result[i + 1] == xsym('*'):
|
||||
# substitute -1 by -, like in -1*x -> -x
|
||||
result.pop(i)
|
||||
result.pop(i)
|
||||
result.insert(i, '-')
|
||||
if result[0][0] == '-':
|
||||
# if there is a - sign in front of all
|
||||
# This test was failing to catch a prettyForm.__mul__(prettyForm("-1", 0, 6)) being negative
|
||||
bin = prettyForm.NEG
|
||||
if result[0] == '-':
|
||||
right = result[1]
|
||||
if right.picture[right.baseline][0] == '-':
|
||||
result[0] = '- '
|
||||
else:
|
||||
bin = prettyForm.MUL
|
||||
return prettyForm(binding=bin, *stringPict.next(*result))
|
||||
|
||||
def __repr__(self):
|
||||
return "prettyForm(%r,%d,%d)" % (
|
||||
'\n'.join(self.picture),
|
||||
self.baseline,
|
||||
self.binding)
|
||||
|
||||
def __pow__(self, b):
|
||||
"""Make a pretty power.
|
||||
"""
|
||||
a = self
|
||||
use_inline_func_form = False
|
||||
if b.binding == prettyForm.POW:
|
||||
b = stringPict(*b.parens())
|
||||
if a.binding > prettyForm.FUNC:
|
||||
a = stringPict(*a.parens())
|
||||
elif a.binding == prettyForm.FUNC:
|
||||
# heuristic for when to use inline power
|
||||
if b.height() > 1:
|
||||
a = stringPict(*a.parens())
|
||||
else:
|
||||
use_inline_func_form = True
|
||||
|
||||
if use_inline_func_form:
|
||||
# 2
|
||||
# sin + + (x)
|
||||
b.baseline = a.prettyFunc.baseline + b.height()
|
||||
func = stringPict(*a.prettyFunc.right(b))
|
||||
return prettyForm(*func.right(a.prettyArgs))
|
||||
else:
|
||||
# 2 <-- top
|
||||
# (x+y) <-- bot
|
||||
top = stringPict(*b.left(' '*a.width()))
|
||||
bot = stringPict(*a.right(' '*b.width()))
|
||||
|
||||
return prettyForm(binding=prettyForm.POW, *bot.above(top))
|
||||
|
||||
simpleFunctions = ["sin", "cos", "tan"]
|
||||
|
||||
@staticmethod
|
||||
def apply(function, *args):
|
||||
"""Functions of one or more variables.
|
||||
"""
|
||||
if function in prettyForm.simpleFunctions:
|
||||
#simple function: use only space if possible
|
||||
assert len(
|
||||
args) == 1, "Simple function %s must have 1 argument" % function
|
||||
arg = args[0].__pretty__()
|
||||
if arg.binding <= prettyForm.DIV:
|
||||
#optimization: no parentheses necessary
|
||||
return prettyForm(binding=prettyForm.FUNC, *arg.left(function + ' '))
|
||||
argumentList = []
|
||||
for arg in args:
|
||||
argumentList.append(',')
|
||||
argumentList.append(arg.__pretty__())
|
||||
argumentList = stringPict(*stringPict.next(*argumentList[1:]))
|
||||
argumentList = stringPict(*argumentList.parens())
|
||||
return prettyForm(binding=prettyForm.ATOM, *argumentList.left(function))
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user