diff --git a/sympy/printing/latex.py b/sympy/printing/latex.py index 2d644c9fdfde..528a7faf7f22 100644 --- a/sympy/printing/latex.py +++ b/sympy/printing/latex.py @@ -61,10 +61,36 @@ other_symbols = set(['aleph', 'beth', 'daleth', 'gimel', 'ell', 'eth', 'hbar', 'hslash', 'mho', 'wp', ]) -# Make sure to keep this list sorted by decreasing length so that, -# e.g., "ddot" is not confused for "d" followed by "dot" -modifier_keys = ['mathring', 'check', 'breve', 'acute', 'grave', 'tilde', 'prime', 'ddot', - 'bold', 'norm', 'avg', 'hat', 'dot', 'bar', 'vec', 'abs', 'mag', 'prm', 'bm'] +# Variable name modifiers +modifier_dict = { + # Accents + 'mathring': lambda s: r'\mathring{'+s+r'}', + 'ddddot': lambda s: r'\ddddot{'+s+r'}', + 'dddot': lambda s: r'\dddot{'+s+r'}', + 'ddot': lambda s: r'\ddot{'+s+r'}', + 'dot': lambda s: r'\dot{'+s+r'}', + 'check': lambda s: r'\check{'+s+r'}', + 'breve': lambda s: r'\breve{'+s+r'}', + 'acute': lambda s: r'\acute{'+s+r'}', + 'grave': lambda s: r'\grave{'+s+r'}', + 'tilde': lambda s: r'\tilde{'+s+r'}', + 'hat': lambda s: r'\hat{'+s+r'}', + 'bar': lambda s: r'\bar{'+s+r'}', + 'vec': lambda s: r'\vec{'+s+r'}', + 'prime': lambda s: "{"+s+"}'", + 'prm': lambda s: "{"+s+"}'", + # Faces + 'bold': lambda s: r'\boldsymbol{'+s+r'}', + 'bm': lambda s: r'\boldsymbol{'+s+r'}', + 'cal': lambda s: r'\mathcal{'+s+r'}', + 'scr': lambda s: r'\mathscr{'+s+r'}', + 'frak': lambda s: r'\mathfrak{'+s+r'}', + # Brackets + 'norm': lambda s: r'\left\lVert{'+s+r'}\right\rVert', + 'avg': lambda s: r'\left\langle{'+s+r'}\right\rangle', + 'abs': lambda s: r'\left\lvert{'+s+r'}\right\rvert', + 'mag': lambda s: r'\left\lvert{'+s+r'}\right\rvert', +} greek_letters_set = frozenset(greeks) @@ -1648,21 +1674,9 @@ def translate(s): return "\\" + s else: # Process modifiers, if any, and recurse - for key in modifier_keys: + for key in sorted(modifier_dict.keys(), key=lambda k:len(k), reverse=True): if s.lower().endswith(key) and len(s)>len(key): - if(key in ['prime', 'prm']): - # MathJax can fail on primes without braces - return "{" + translate(s[:-len(key)]) + "}'" - if(key in ['abs', 'mag']): - return "\\left\\lvert{" + translate(s[:-len(key)]) + "}\\right\\rvert" - if(key=='norm'): - return "\\left\\lVert{" + translate(s[:-len(key)]) + "}\\right\\rVert" - if(key=='avg'): - return "\\left\\langle{" + translate(s[:-len(key)]) + "}\\right\\rangle" - if(key in ['bm', 'bold']): - # MathJax doesn't know \bm - return "\\boldsymbol{" + translate(s[:-len(key)]) + "}" - return "\\" + key + "{" + translate(s[:-len(key)]) + "}" + return modifier_dict[key](translate(s[:-len(key)])) return s def latex(expr, **settings): diff --git a/sympy/printing/pretty/pretty_symbology.py b/sympy/printing/pretty/pretty_symbology.py index cc26bc54899e..c69191f10589 100644 --- a/sympy/printing/pretty/pretty_symbology.py +++ b/sympy/printing/pretty/pretty_symbology.py @@ -181,6 +181,38 @@ def xstr(*args): sub[s] = SSUB(s) sup[s] = SSUP(s) +# Variable modifiers +# TODO: Is it worth trying to handle faces with, e.g., 'MATHEMATICAL BOLD CAPITAL A'? +# TODO: Make brackets adjust to height of contents +modifier_dict = { + # Accents + 'mathring': lambda s: s+u'\u030A', + # 'ddddot': lambda s: s, + # 'dddot': lambda s: s, + 'ddot': lambda s: s+u'\u0308', + 'dot': lambda s: s+u'\u0307', + 'check': lambda s: s+u'\u030C', + 'breve': lambda s: s+u'\u0306', + 'acute': lambda s: s+u'\u0301', + 'grave': lambda s: s+u'\u0300', + 'tilde': lambda s: s+u'\u0303', + 'hat': lambda s: s+u'\u0302', + 'bar': lambda s: s+u'\u0305', + 'vec': lambda s: s+u'\u20D7', + 'prime': lambda s: s+u'\u030D', + 'prm': lambda s: s+u'\u030D', + # Faces + # 'bold': lambda s:, + # 'bm': lambda s:, + # 'cal': lambda s:, + # 'scr': lambda s:, + # 'frak': lambda s:, + # Brackets + 'norm': lambda s: u'\u2016'+s+u'\u2016', + 'avg': lambda s: u'\u27E8'+s+u'\u27E9', + 'abs': lambda s: u'\u007C'+s+u'\u007C', + 'mag': lambda s: u'\u007C'+s+u'\u007C', +} # VERTICAL OBJECTS HUP = lambda symb: U('%s UPPER HOOK' % symb_2txt[symb]) @@ -452,10 +484,16 @@ def pretty_symbol(symb_name): name, sups, subs = split_super_sub(symb_name) - # let's prettify name - gG = greek_unicode.get(name) - if gG is not None: - name = gG + def translate(s) : + 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)])) + return s + + name = translate(name) # Let's prettify sups/subs. If it fails at one of them, pretty sups/subs are # not used at all. @@ -479,7 +517,7 @@ def pretty_list(l, mapping): # glue the results into one string if pretty_subs is None: # nice formatting of sups/subs did not work - return symb_name + return name + '_'+'_'.join([translate(s) for s in subs]) + '__'+'__'.join([translate(s) for s in sups]) else: sups_result = ' '.join(pretty_sups) subs_result = ' '.join(pretty_subs) diff --git a/sympy/printing/pretty/tests/test_pretty.py b/sympy/printing/pretty/tests/test_pretty.py index 036eeaa6579e..1aae077d45cf 100644 --- a/sympy/printing/pretty/tests/test_pretty.py +++ b/sympy/printing/pretty/tests/test_pretty.py @@ -271,6 +271,28 @@ def test_upretty_subs_missingin_24(): assert upretty( Symbol('F_v') ) == u('Fᵥ') assert upretty( Symbol('F_x') ) == u('Fₓ') +def test_upretty_modifiers(): + # Accents + assert upretty( Symbol('Fmathring') ) == u('F̊') + assert upretty( Symbol('Fddot') ) == u('F̈') + assert upretty( Symbol('Fdot') ) == u('Ḟ') + assert upretty( Symbol('Fcheck') ) == u('F̌') + assert upretty( Symbol('Fbreve') ) == u('F̆') + assert upretty( Symbol('Facute') ) == u('F́') + assert upretty( Symbol('Fgrave') ) == u('F̀') + assert upretty( Symbol('Ftilde') ) == u('F̃') + assert upretty( Symbol('Fhat') ) == u('F̂') + assert upretty( Symbol('Fbar') ) == u('F̅') + assert upretty( Symbol('Fvec') ) == u('F⃗') + assert upretty( Symbol('Fprime') ) == u('F̍') + assert upretty( Symbol('Fprm') ) == u('F̍') + # No faces are implemented... + # Brackets + assert upretty( Symbol('Fnorm') ) == u('‖F‖') + assert upretty( Symbol('Favg') ) == u('⟨F⟩') + assert upretty( Symbol('Fabs') ) == u('|F|') + assert upretty( Symbol('Fmag') ) == u('|F|') + def test_pretty_basic(): assert pretty( -Rational(1)/2 ) == '-1/2' diff --git a/sympy/printing/tests/test_latex.py b/sympy/printing/tests/test_latex.py index 39fd31eacbff..ee592f9f7d14 100644 --- a/sympy/printing/tests/test_latex.py +++ b/sympy/printing/tests/test_latex.py @@ -1065,6 +1065,8 @@ def test_modifiers(): assert latex(symbols("xGrave")) == r"\grave{x}" assert latex(symbols("xTilde")) == r"\tilde{x}" assert latex(symbols("xPrime")) == r"{x}'" + assert latex(symbols("xddDDot")) == r"\ddddot{x}" + assert latex(symbols("xDdDot")) == r"\dddot{x}" assert latex(symbols("xDDot")) == r"\ddot{x}" assert latex(symbols("xBold")) == r"\boldsymbol{x}" assert latex(symbols("xnOrM")) == r"\left\lVert{x}\right\rVert" @@ -1097,6 +1099,7 @@ def test_modifiers(): assert latex(symbols("Mag")) == r"Mag" assert latex(symbols("PrM")) == r"PrM" assert latex(symbols("BM")) == r"BM" + assert latex(symbols("hbar")) == r"\hbar" # Check a few combinations assert latex(symbols("xvecdot")) == r"\dot{\vec{x}}" assert latex(symbols("xDotVec")) == r"\vec{\dot{x}}"