Hi,
On Wed, Apr 1, 2009 at 10:11 PM, Jason Grout
<[email protected]> 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 [email protected]
To unsubscribe from this group, send email to
[email protected]
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 <[email protected]>
# 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