Hi, On Wed, Apr 1, 2009 at 10:11 PM, Jason Grout <jason-s...@creativetrax.com> wrote: > >> Should I submit patches for each of these functions >> separately? > > I think one patch covering all of the functions would be fine. It's one > logical issue.
... So here goes the patch to enhance the typesetting capability of symbolic functions within sage. It includes several doc-tests for each functions. Main features are: (1) Symbolics functions with name in Greek letters (with possible suffixes), are typeset nicely in LaTeX. Ex: psi(x) => \psi(x) (2) Functions such as "diff", "integrate", "limit", "conjugate", "laplace", "inverse_lapse" are now typeset within Sage itself. Ex: psi(x).conjugate() => {\psi}^*(x) (3) Default (fall-back) typesetting for unknown functions (as in Maxima). Ex: myfn(x) => {\it myfn}(x) (4) Allows users to define their own/custom LaTeX expression for any symbolic functions via a new method "set_latex()" for the class SymbolicFunctionEvaluation. Ex: var('t'); hubble(t) = function('hubble',t) hubble(t).set_latex('\\mathcal{H}') #To reset custom LaTeX expression hubble(t).set_latex() (5) If the arguments of a symbolic function are all symbolic variables then typesetting will avoid using \left(, \right). Ex: Phi(x,y) => \Phi(x, y) (if x,y are symbolic vars) Note: You need to apply a small patch http://trac.sagemath.org/sage_trac/ticket/5678 before you apply the attached patch. This patch is created using sage-3.4. I will be happy to hear any issues that you may find in it, before I open a ticket for this enhancement. Cheers, Golam --~--~---------~--~----~------------~-------~--~----~ To post to this group, send email to sage-devel@googlegroups.com To unsubscribe from this group, send email to sage-devel-unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/sage-devel URLs: http://www.sagemath.org -~----------~----~----~----~------~----~------~--~---
# HG changeset patch # User Golam Mortuza Hossain <gmhoss...@gmail.com> # Date 1239118264 10800 # Node ID e190effda0d16b5b703ee277674984613411b0ab # Parent 17fe77f21e21c79cb989aaab2e2fe128d16beaa1 Enhances typsetting of Symbolic functions within Sage diff -r 17fe77f21e21 -r e190effda0d1 sage/calculus/calculus.py --- a/sage/calculus/calculus.py Thu Mar 26 15:00:42 2009 -0300 +++ b/sage/calculus/calculus.py Tue Apr 07 12:31:04 2009 -0300 @@ -297,7 +297,7 @@ from sage.structure.parent_base import ParentWithBase import operator -from sage.misc.latex import latex, latex_variable_name +from sage.misc.latex import latex, latex_variable_name, latex_symbolic_function from sage.misc.misc import uniq as unique from sage.structure.sage_object import SageObject @@ -9724,38 +9724,91 @@ def _latex_(self): r""" - Return a latex version of the function - - EXAMPLES:: - - sage: var("t,u") - (t, u) - sage: y=function('y',u) - sage: z=function('z',t,u) - sage: latex(y) - y\left(u\right) - sage: latex(diff(y,u)) - {{{\it \partial}}\over{{\it \partial}\,u}}\,y\left(u\right) - sage: latex(diff(y,u,3)) - {{{\it \partial}^3}\over{{\it \partial}\,u^3}}\,y\left(u\right) - sage: latex(diff(z,u)) - {{{\it \partial}}\over{{\it \partial}\,u}}\,z\left(t , u\right) - sage: latex(diff(z,u,t,u,t)) - {{{\it \partial}^4}\over{{\it \partial}\,t^2\,{\it \partial}\,u^2}} \,z\left(t , u\right) - sage: latex(integrate(y,u)) - \int {y\left(u\right)}{\;du} + Return a LaTeX expression of the function. + + EXAMPLES:: + + sage: var('x,y,a,b,t,s') + (x, y, a, b, t, s) + sage: psi(x) = function('psi',x) + sage: latex(psi(x)) + \psi(x) + sage: latex(psi(x).conjugate()) + {\psi}^*(x) + sage: latex(limit(psi(x),x=a)) + \lim_{x \to a}\, \psi(x) + + sage: f(t) = function('f',t) + sage: latex(laplace(f(t),t,s)) + \mathcal{L}\left(f(t), t, s\right) + + sage: F(s) = function('F',s) + sage: latex(inverse_laplace(F(s),s,t)) + \mathcal{L}^{-1}\left(F(s), s, t\right) + + sage: f(x) = function('f',x) + sage: latex(integrate(f(x),x)) + \int f(x)\,{d x} + sage: latex(integrate(f(x),x,a,b)) + \int_{a}^{b} f(x)\,{d x} + + sage: var('x,y') + (x, y) + sage: f(x) = function('f',x) + sage: latex(diff(f(x),x)) + \frac{d f(x)}{d x} + sage: f(x,y) = function('f',x,y) + sage: latex(diff(f(x,y),x)) + \frac{\partial}{\partial x}f(x, y) + + sage: myfunc(x) = function('myfunc',x) + sage: latex(myfunc(x)) + {\it myfunc}(x) sage: latex(derivative(ceil(x), x)) - {{{\it \partial}}\over{{\it \partial}\,x}}\,\left \lceil x \right \rceil - - """ - try: - return latex(self._maxima_()) - except: - return "{\\rm %s}(%s)"%(self._f._name, ', '.join([x._latex_() for - x in self._args])) - - + \frac{d \left \lceil x \right \rceil}{d x} + + """ + return latex_symbolic_function(self) + + def set_latex(self, expr=None): + r""" + Set custom LaTeX expression for the given symbolic function. + + INPUTS: + + - ``expr`` -- a valid LaTeX expression to be used for the + function. + + Calling it without an arugment will reset any previously set + custom LaTeX expression. See EXAMPLES section for explicit use. + + EXAMPLES:: + + sage: var('x') + x + sage: riemann(x) = function('riemann',x) + sage: latex(riemann(x)) + {\it riemann}(x) + sage: riemann(x).set_latex('\\mathcal{R}') + sage: latex(riemann(x)) + \mathcal{R}(x) + sage: riemann(x).set_latex() + sage: latex(riemann(x)) + {\it riemann}(x) + + AUTHORS: + + - Golam Mortuza Hossain (2009-04-05) + """ + from sage.misc.latex import user_defined_latex_dict as ldict + key = self._f._name + # Some sanity checks + if expr is not None and expr != "" and not expr.isspace(): + ldict[key] = expr + elif key in ldict: + del ldict[key] + return None def _maxima_init_(self): r""" diff -r 17fe77f21e21 -r e190effda0d1 sage/misc/latex.py --- a/sage/misc/latex.py Thu Mar 26 15:00:42 2009 -0300 +++ b/sage/misc/latex.py Tue Apr 07 12:31:04 2009 -0300 @@ -756,6 +756,416 @@ 'omega', 'Omega'] +def latex_symbolic_function(self): + r""" + Typeset a given symbolic function in LaTeX. + + EXAMPLES:: + + sage: import sage.misc.latex as latex_module + sage: latex_sym_fn = latex_module.latex_symbolic_function + sage: var('x,a,b,t,s') + (x, a, b, t, s) + sage: psi(x) = function('psi',x) + sage: latex_sym_fn(psi(x)) + '\\psi(x)' + sage: latex_sym_fn(psi(x).conjugate()) + '{\\psi}^*(x)' + sage: latex_sym_fn(limit(psi(x),x=a)) + '\\lim_{x \\to a}\\, \\psi(x)' + + sage: f(t) = function('f',t) + sage: latex_sym_fn(laplace(f(t),t,s)) + '\\mathcal{L}\\left(f(t), t, s\\right)' + + sage: F(s) = function('F',s) + sage: latex_sym_fn(inverse_laplace(F(s),s,t)) + '\\mathcal{L}^{-1}\\left(F(s), s, t\\right)' + + sage: f(x) = function('f',x) + sage: latex_sym_fn(integrate(f(x),x)) + '\\int f(x)\\,{d x}' + sage: latex_sym_fn(integrate(f(x),x,a,b)) + '\\int_{a}^{b} f(x)\\,{d x}' + + sage: var('x,y') + (x, y) + sage: f(x) = function('f',x) + sage: latex_sym_fn(diff(f(x),x)) + '\\frac{d f(x)}{d x}' + sage: f(x,y) = function('f',x,y) + sage: latex_sym_fn(diff(f(x,y),x)) + '\\frac{\\partial}{\\partial x}f(x, y)' + + sage: myfunc(x) = function('myfunc',x) + sage: latex_sym_fn(myfunc(x)) + '{\\it myfunc}(x)' + + AUTHORS: + + - Golam Mortuza Hossain (2009-04-05) + """ + # Get the name of symbolic function + fname = self._f._name + # Special handling of fname where specific processing is needed + if fname == "conjugate": + return _conjugate_latex_(self) + elif fname == "limit": + return _limit_latex_(self) + elif fname == "laplace": + return _laplace_latex_(self) + elif fname == "ilt": + return _inverse_laplace_latex_(self) + elif fname == "integrate": + return _integrate_latex_(self) + elif fname == "diff": + return _derivative_latex_(self) + # Check whether fname has custom LaTeX string or is a Greek letter + name = latex_function_name(fname) + if name is not False: + return "%s%s"%(name, _args_latex_(self)) + # Use default typesetting scheme + return _symbolic_function_default_latex_(self) + +def _symbolic_function_default_latex_(self): + r""" + Return LaTeX expression of a symbolic function using default scheme. + + EXAMPLES:: + + sage: import sage.misc.latex as latex_module + sage: _sym_def_latex_ = latex_module._symbolic_function_default_latex_ + sage: var('x') + x + sage: myfunc(x) = function('myfunc',x) + sage: _sym_def_latex_(myfunc(x)) + '{\\it myfunc}(x)' + sage: my_func(x) = function('my_func',x) + sage: _sym_def_latex_(my_func(x)) + '{\\it my\\_func}(x)' + + AUTHORS: + + - Golam Mortuza Hossain (2009-04-05) + """ + # Get the name of the symbolic function + fname = self._f._name + fname = fname.replace("_", "\\_") + # Default typesetting scheme (similar to Maxima scheme) + return "{\\it %s}%s"%(fname, _args_latex_(self)) + +def _args_latex_(self): + r""" + Return LaTeX expression for the arguments of a symbolic function. + + EXAMPLES:: + + sage: import sage.misc.latex as latex_module + sage: _args_latex_ = latex_module._args_latex_ + sage: var('x') + x + sage: f(x) = function('f',x) + sage: _args_latex_(f(x)) + '(x)' + sage: g(x) = function('g',x) + sage: _args_latex_(f(g(x))) + '\\left(g(x)\\right)' + + AUTHORS: + + - Golam Mortuza Hossain (2009-04-06) + """ + from sage.calculus.calculus import SymbolicVariable + # If all arguments are SymbolicVariables then the function should be + # typeset as f(x) rather than f\left(x\right) + use_left_right = False + for x in self._args: + if not isinstance(x, SymbolicVariable): + use_left_right = True + break + if use_left_right is True: + return "\\left(%s\\right)"%(', '.join([latex(x) for x in self._args])) + else: + return "(%s)"%(', '.join([latex(x) for x in self._args])) + +def _derivative_latex_(self): + r""" + Return LaTeX expression for derivatives of a symbolic function. + + EXAMPLES:: + + sage: import sage.misc.latex as latex_module + sage: _derivative_latex_ = latex_module._derivative_latex_ + sage: var('x,y') + (x, y) + sage: f(x) = function('f',x) + sage: _derivative_latex_(diff(f(x),x)) + '\\frac{d f(x)}{d x}' + sage: _derivative_latex_(diff(f(x),x,2)) + '\\frac{d^{2} f(x)}{d {x}^{2}}' + + sage: f(x,y) = function('f',x,y) + sage: _derivative_latex_(diff(f(x,y),x)) + '\\frac{\\partial}{\\partial x}f(x, y)' + sage: _derivative_latex_(diff(f(x,y),x,3)) + '\\frac{\\partial^{3}}{\\partial {x}^{3}}f(x, y)' + sage: _derivative_latex_(diff(f(x,y),x,y)) + '\\frac{\\partial^{2}}{\\partial y\\partial x}f(x, y)' + + AUTHORS: + + - Golam Mortuza Hossain (2009-04-05) + """ + n = len(self._args) + # We dont do any processing for n < 2 + if n < 2: + return _symbolic_function_default_latex_(self) + # Read the function + f = self._args[0] + # Check whether it should be partial derivative + # Logic taken from: http://trac.sagemath.org/sage_trac/ticket/4202 + if len(f.variables()) == 1: + d_latex = "d" + else: + d_latex = "\\partial" + + # Read the variables + diffstr = ""; total = 0 + for i in range(1,n-1,2): + x = self._args[i] # variable + j = self._args[i+1] # no of times diff acts on f w.r.t. variable x + total = total + j # total no of times diff acts + if j == 1: + diffstr = "%s %s"%(d_latex, latex(x)) + diffstr + else: + diffstr = "%s {%s}^{%s}"%(d_latex, latex(x), latex(j)) + diffstr + # Return final expression + if total == 1: + if d_latex == "d": + return "\\frac{%s %s}{%s}"%(d_latex, latex(f), diffstr) + else: + return "\\frac{%s}{%s}%s"%(d_latex, diffstr, latex(f)) + if d_latex == "d": + return "\\frac{%s^{%d} %s}{%s}"%(d_latex, total, latex(f), diffstr) + else: + return "\\frac{%s^{%d}}{%s}%s"%(d_latex, total, diffstr, latex(f)) + +def _integrate_latex_(self): + r""" + Return LaTeX expression for integration of a symbolic function. + + EXAMPLES:: + + sage: import sage.misc.latex as latex_module + sage: _integrate_latex_ = latex_module._integrate_latex_ + sage: var('x,a,b') + (x, a, b) + sage: f(x) = function('f',x) + sage: _integrate_latex_(integrate(f(x),x)) + '\\int f(x)\\,{d x}' + sage: _integrate_latex_(integrate(f(x),x,a,b)) + '\\int_{a}^{b} f(x)\\,{d x}' + + AUTHORS: + + - Golam Mortuza Hossain (2009-04-05) + """ + n = len(self._args) + # We dont process if number of arguments is neither 2 nor 4 + if n != 2 and n != 4: + # Return default typesetting + return _symbolic_function_default_latex_(self) + f = self._args[0] + x = self._args[1] + # Check whether its a definite integral + if n == 4: + a = self._args[2] + b = self._args[3] + return "\\int_{%s}^{%s} %s\\,{d %s}"%(latex(a), latex(b), latex(f), latex(x)) + # Typeset as indefinite integral + return "\\int %s\\,{d %s}"%(latex(f), latex(x)) + +def _inverse_laplace_latex_(self): + r""" + Return LaTeX expression for inverse Laplace transform of a symbolic function. + + EXAMPLES:: + + sage: import sage.misc.latex as latex_module + sage: _inverse_laplace_latex_ = latex_module._inverse_laplace_latex_ + sage: var('s,t') + (s, t) + sage: F(s) = function('F',s) + sage: _inverse_laplace_latex_(inverse_laplace(F(s),s,t)) + '\\mathcal{L}^{-1}\\left(F(s), s, t\\right)' + + AUTHORS: + + - Golam Mortuza Hossain (2009-04-05) + """ + return "\\mathcal{L}^{-1}\\left(%s\\right)"%(', '.join([latex(x) for x in self._args])) + +def _laplace_latex_(self): + r""" + Return LaTeX expression for Laplace transform of a symbolic function. + + EXAMPLES:: + + sage: import sage.misc.latex as latex_module + sage: _laplace_latex_ = latex_module._laplace_latex_ + sage: var('s,t') + (s, t) + sage: f(t) = function('f',t) + sage: _laplace_latex_(laplace(f(t),t,s)) + '\\mathcal{L}\\left(f(t), t, s\\right)' + + AUTHORS: + + - Golam Mortuza Hossain (2009-04-05) + """ + return "\\mathcal{L}\\left(%s\\right)"%(', '.join([latex(x) for x in self._args])) + +def _limit_latex_(self): + r""" + Return latex expression for limit of a symbolic function. + + EXAMPLES:: + + sage: import sage.misc.latex as latex_module + sage: _limit_latex_ = latex_module._limit_latex_ + sage: var('x,a') + (x, a) + sage: psi(x) = function('psi',x) + sage: _limit_latex_(limit(psi(x),x=a)) + '\\lim_{x \\to a}\\, \\psi(x)' + + AUTHORS: + + - Golam Mortuza Hossain (2009-04-05) + """ + # We process only if there are precisely three arguments + if len(self._args) == 3: + # Read f,x,a from arguments + f = self._args[0] + x = self._args[1] + a = self._args[2] + return "\\lim_{%s \\to %s}\\, %s"%(latex(x), latex(a), latex(f)) + # Return default typesetting + return _symbolic_function_default_latex_(self) + +def _conjugate_latex_(self): + r""" + Return LaTeX expression for conjugate of a symbolic function. + + EXAMPLES:: + + sage: import sage.misc.latex as latex_module + sage: _conjugate_latex_ = latex_module._conjugate_latex_ + sage: var('x') + x + sage: psi(x) = function('psi',x) + sage: _conjugate_latex_(psi(x).conjugate()) + '{\\psi}^*(x)' + + AUTHORS: + + - Golam Mortuza Hossain (2009-04-05) + """ + # We process only if there is only one argument + if len(self._args) == 1: + chld = self._args[0] + name = latex_function_name(chld._f._name) + if name is not False: + # conjugate(psi(x)) => psi^*(x) + return "{%s}^*%s"%(name, _args_latex_(chld)) + # Return default typesetting + return _symbolic_function_default_latex_(self) + +user_defined_latex_dict = {} + +def latex_function_name(x): + r""" + Return common function names such as alpha, beta1, psi_00, R_mn, + etc. as latex symbols, else return False. + + EXAMPLES:: + + sage: import sage.misc.latex as latex_module + sage: latex_function_name = latex_module.latex_function_name + sage: latex_function_name('psi') + '\\psi' + sage: latex_function_name('psi0') + '\\psi_{0}' + sage: latex_function_name('f1') + 'f_{1}' + sage: latex_function_name('psi_mu') + '\\psi_{\\mu}' + sage: latex_function_name('psi_11') + '\\psi_{11}' + sage: latex_function_name('R_ab') + 'R_{ab}' + sage: latex_function_name('R_nu') + 'R_{\\nu}' + sage: latex_function_name('myfunc') + False + sage: latex_function_name('psi_') + False + sage: latex_function_name('abc_xyz_psi') + False + sage: latex_function_name('abc_beta') + False + + NOTES: + + This function is based largely on latex_variable_name function. + + AUTHORS: + + - Golam Mortuza Hossain (2009-04-05) + """ + # If user has defined latex string then use it first + if x in user_defined_latex_dict: + return user_defined_latex_dict[x] + # For known names return them after preprending with "\\" + if x in common_varnames: + return "\\" + x + # Look for underscrore. If found then use its postion to + # find the suffix + underscore = x.find("_") + if underscore == -1: + import re + # * The "\d|[.,]" means "decimal digit" or period or comma + # * The "+" means "1 or more" + # * The "$" means "at the end of the line" + m = re.search('(\d|[.,])+$',x) + if m is None: + prefix = x + suffix = None + else: + prefix = x[:m.start()] + suffix = x[m.start():] + else: + prefix = x[:underscore] + suffix = x[underscore+1:] + if len(suffix)== 0: + return False + # If suffix contains underscores then don't process + if suffix and suffix.find("_") != -1: + return False + # If prefix is not a common name or a more-than-one letters word + # then don't process + if prefix not in common_varnames and len(prefix) != 1: + return False + # Check if prefix or suffix is a common name + if prefix in common_varnames: + prefix = "\\" + prefix + if suffix and len(suffix) > 0: + if suffix in common_varnames: + suffix = "\\" + suffix + return '%s_{%s}'%(prefix, suffix) + else: + return '%s'%(prefix) + def latex_varify(a): if a in common_varnames: return "\\" + a