Ticket #6344: trac_6344-symbolic_derivative_print.patch

File trac_6344-symbolic_derivative_print.patch, 24.3 KB (added by burcin, 10 years ago)

change printing of symbolic derivatives

  • sage/calculus/calculus.py

    # HG changeset patch
    # User Burcin Erocal <burcin@erocal.org>
    # Date 1247606728 -7200
    # Node ID b6fb8830206c4aa434128adbf3a2e81a922b20b1
    # Parent  108251386d92cf127cdfab2248d0c0076a2298b0
    Change typesetting of derivatives of symbolic functions to something more sensible. #6344
    
    diff --git a/sage/calculus/calculus.py b/sage/calculus/calculus.py
    a b  
    269269
    270270    sage: f = function('F',x)
    271271    sage: diff(f*SR(1),x)
    272     D[0](F)(x)
     272    D[1](F)(x)
    273273"""
    274274
    275275import weakref
     
    11531153
    11541154        sage: f = function('f', x)
    11551155        sage: g = f.diff(x); g
    1156         D[0](f)(x)
     1156        D[1](f)(x)
    11571157        sage: g.laplace(x, s)
    11581158        s*laplace(f(x), x, s) - f(0)
    11591159
     
    13141314        sage: f = function('cr', a)
    13151315        sage: g = f.diff(a).integral(b)
    13161316        sage: g
    1317         b*D[0](cr)(a)
     1317        b*D[1](cr)(a)
    13181318
    13191319    In Sage 4.0, you need to use :meth:`substitute_function` to
    13201320    replace all occurrences of a function with another::
     
    14101410        sage: a = var('a')
    14111411        sage: f = function('cr', a)
    14121412        sage: g = f.diff(a); g
    1413         D[0](cr)(a)
     1413        D[1](cr)(a)
    14141414    """
    14151415    f = args[0]
    14161416    args = list(args[1:])
  • sage/calculus/tests.py

    diff --git a/sage/calculus/tests.py b/sage/calculus/tests.py
    a b  
    9797    sage: derivative(x^n, x, 3)
    9898    (n - 2)*(n - 1)*n*x^(n - 3)
    9999    sage: derivative( function('f')(x), x)
    100     D[0](f)(x)   
     100    D[1](f)(x)   
    101101    sage: diff( 2*x*f(x^2), x)
    102     4*x^2*D[0](f)(x^2) + 2*f(x^2)
     102    4*x^2*D[1](f)(x^2) + 2*f(x^2)
    103103    sage: integrate( 1/(x^4 - a^4), x)
    104104    1/4*log(-a + x)/a^3 - 1/4*log(a + x)/a^3 - 1/2*arctan(x/a)/a^3
    105105    sage: expand(integrate(log(1-x^2), x))
     
    166166    sage: f = function('f'); f
    167167    f
    168168    sage: diff(f(x), x)
    169     D[0](f)(x)   
     169    D[1](f)(x)   
    170170    sage: diff(f(x,y), x, y)
    171     D[0, 1](f)(x, y)   
     171    D[1, 1](f)(x, y)   
    172172    sage: diff(f(x,y), x, y) - diff(f(x,y), y, x)
    173173    0
    174174    sage: g = function('g')
    175175    sage: var('x y z')
    176176    (x, y, z)
    177177    sage: diff(g(x,y,z), x,z,z)
    178     D[0, 2, 2](g)(x, y, z)   
     178    D[1, 0, 2](g)(x, y, z)   
    179179    sage: integrate(sin(x), x)
    180180    -cos(x)
    181181    sage: integrate(sin(x), x, 0, pi)
     
    211211    sage: function('f, g')
    212212    (f, g)
    213213    sage: diff(f(t)*g(t),t)
    214     D[0](f)(t)*g(t) + f(t)*D[0](g)(t)   
     214    D[1](f)(t)*g(t) + f(t)*D[1](g)(t)   
    215215    sage: diff(f(t)/g(t), t)
    216     D[0](f)(t)/g(t) - f(t)*D[0](g)(t)/g(t)^2
     216    D[1](f)(t)/g(t) - f(t)*D[1](g)(t)/g(t)^2
    217217    sage: diff(f(t) + g(t), t)
    218     D[0](f)(t) + D[0](g)(t)   
     218    D[1](f)(t) + D[1](g)(t)   
    219219    sage: diff(c*f(t), t)
    220     c*D[0](f)(t)   
     220    c*D[1](f)(t)   
    221221"""
  • sage/calculus/var.pyx

    diff --git a/sage/calculus/var.pyx b/sage/calculus/var.pyx
    a b  
    125125        sage: g.diff(y)
    126126        (x, y) |--> 1/2*cos(1/2*y)
    127127        sage: k = g.diff(x); k
    128         (x, y) |--> 2*supersin(x)*D[0](supersin)(x)
     128        (x, y) |--> 2*supersin(x)*D[1](supersin)(x)
    129129
    130130    Custom typesetting of symbolic functions in LaTeX::
    131131
     
    139139        latex expression::
    140140
    141141        sage: mu,nu = var('mu,nu')
    142         sage: def my_latex_print(*args): return "\\psi_{%s}"%(', '.join(map(latex, args)))
     142        sage: def my_latex_print(*args, **kwds): return "\\psi_{%s}"%(', '.join(map(latex, args)))
    143143        sage: psi(mu,nu) = function('psi', mu, nu, print_latex_func=my_latex_print)
    144144        sage: latex(psi(mu,nu))
    145145        \psi_{\mu, \nu}
  • sage/functions/other.py

    diff --git a/sage/functions/other.py b/sage/functions/other.py
    a b  
    167167                                   approx=math.ceil,
    168168                                   conversions=dict(maxima='ceiling'))
    169169                                   
    170     def _print_latex_(self, x):
     170    def _print_latex_(self, x, dparams=None):
    171171        r"""
    172172        EXAMPLES:
     173            sage: latex(ceil(x))
     174            \left \lceil x \right \rceil
     175            sage: latex(ceil(x).derivative(x))
     176            D[1]\left \lceil x \right \rceil
    173177        """
    174         return r"\left \lceil %s \right \rceil"%latex(x)
     178        #FIXME process dparams properly
     179        if dparams is not None:
     180            dstr = 'D[' + str(dparams[0]) + ']'
     181        else:
     182            dstr = ''
     183        return dstr + r"\left \lceil %s \right \rceil"%latex(x)
    175184
    176185    def __call__(self, x, maximum_bits=20000):
    177186        try:
     
    300309        PrimitiveFunction.__init__(self, "floor",
    301310                                   approx=math.floor)
    302311       
    303     def _print_latex_(self, x):
     312    def _print_latex_(self, x, dparams=None):
    304313        r"""
    305314        EXAMPLES:
    306315            sage: latex(floor(x))
    307316            \left \lfloor x \right \rfloor
     317            sage: latex(floor(x).derivative(x))
     318            D[1]\left \lfloor x \right \rfloor
    308319        """
    309         return r"\left \lfloor %s \right \rfloor"%latex(x)
     320        #FIXME process dparams properly
     321        if dparams is not None:
     322            dstr = 'D[' + str(dparams[0]) + ']'
     323        else:
     324            dstr = ''
     325        return dstr + r"\left \lfloor %s \right \rfloor"%latex(x)
    310326
    311327    def __call__(self, x, maximum_bits=20000):
    312328        try:
  • sage/symbolic/expression.pyx

    diff --git a/sage/symbolic/expression.pyx b/sage/symbolic/expression.pyx
    a b  
    21112111            sage: from sage.symbolic.function import function as myfunc
    21122112            sage: foo = myfunc('foo',2)
    21132113            sage: foo(x^2,x^2)._derivative(x)
    2114             2*x*D[0](foo)(x^2, x^2) + 2*x*D[1](foo)(x^2, x^2)
     2114            2*x*D[1, 0](foo)(x^2, x^2) + 2*x*D[0, 1](foo)(x^2, x^2)
    21152115
    21162116            sage: SR(1)._derivative()
    21172117            0
     
    30703070
    30713071            sage: f = function('f')
    30723072            sage: a = f(x).diff(x); a
    3073             D[0](f)(x)
     3073            D[1](f)(x)
    30743074            sage: a.operator()
    3075             D[0](f)
     3075            D[1](f)
    30763076           
    30773077        TESTS:
    30783078            sage: (x <= y).operator()
     
    31283128                from sage.symbolic.pynac import paramset_from_Expression
    31293129                from sage.symbolic.operators import FDerivativeOperator
    31303130                parameter_set = paramset_from_Expression(self)
    3131                 res = FDerivativeOperator(res, parameter_set)
     3131                # since we allow creation of symbolic functions with arbitrary
     3132                # number of arguments, i.e., by specifying 0 as nargs at
     3133                # creation, we have to extract the number of arguments here
     3134                res = FDerivativeOperator(res, parameter_set, self._gobj.nops())
    31323135
    31333136            return res
    31343137
  • sage/symbolic/expression_conversions.py

    diff --git a/sage/symbolic/expression_conversions.py b/sage/symbolic/expression_conversions.py
    a b  
    337337
    338338            sage: from sage.symbolic.expression_conversions import Converter
    339339            sage: a = function('f', x).diff(x); a
    340             D[0](f)(x)
     340            D[1](f)(x)
    341341            sage: Converter().derivative(a, a.operator())
    342342            Traceback (most recent call last):
    343343            ...
     
    459459            sage: from sage.symbolic.expression_conversions import InterfaceInit
    460460            sage: m = InterfaceInit(maxima)
    461461            sage: a = function('f', x).diff(x); a
    462             D[0](f)(x)
     462            D[1](f)(x)
    463463            sage: print m.derivative(a, a.operator())
    464464            diff('f(x), x, 1)
    465465            sage: b = function('f', x).diff(x).diff(x)
     
    15451545            sage: s = SubstituteFunction(foo(x), foo, bar)
    15461546            sage: f = foo(x).diff(x)
    15471547            sage: s.derivative(f, f.operator())
    1548             D[0](bar)(x)
     1548            D[1](bar)(x)
    15491549        """
    15501550        if operator.function() is self.original:
    15511551            return operator.change_function(self.new)(*ex.operands())
  • sage/symbolic/function.pyx

    diff --git a/sage/symbolic/function.pyx b/sage/symbolic/function.pyx
    a b  
    5050        sage: psi = function('psi', 1)(r); psi
    5151        psi(r)
    5252        sage: g = 1/r^2*(2*r*psi.derivative(r,1) + r^2*psi.derivative(r,2)); g
    53         (r^2*D[0, 0](psi)(r) + 2*r*D[0](psi)(r))/r^2
     53        (r^2*D[2](psi)(r) + 2*r*D[1](psi)(r))/r^2
    5454        sage: g.expand()
    55         2*D[0](psi)(r)/r + D[0, 0](psi)(r)
     55        2*D[1](psi)(r)/r + D[2](psi)(r)
    5656        sage: g.coeff(psi.derivative(r,2))
    5757        1
    5858        sage: g.coeff(psi.derivative(r,1))
     
    113113            (y,) {'var': y, 'options': 0, 'at': 0, 'order': 5}
    114114            y^4 + y^3 + y^2 + y + 1
    115115
    116             sage: def my_print(*args): return "my args are: " + ', '.join(map(repr, args))
     116            sage: def my_print(*args, **kwds): return "my args are: " + ', '.join(map(repr, args))
    117117            sage: foo = nfunction('t', 2, print_func=my_print)
    118118            sage: foo(x,y^z)
    119119            my args are: x, y^z
     
    154154            ...
    155155            ValueError: eval_func parameter must be callable
    156156
     157        Print function with wrong signature::
     158
     159            sage: def my_print(*args): return 's'
     160            sage: foo = nfunction('t', 2, print_func=my_print, print_latex_func=my_print)
     161            sage: foo(x,y^z)
     162            Traceback (most recent call last):
     163            ...
     164            TypeError: my_print() got an unexpected keyword argument 'dparams'
     165            sage: latex(foo(x,y^z))
     166            Traceback (most recent call last):
     167            ...
     168            TypeError: my_print() got an unexpected keyword argument 'dparams'
     169
     170        Print function returns None::
     171
     172            sage: def my_print(*args, **kwds): return None
     173            sage: foo = nfunction('t', 2, print_func=my_print, print_latex_func=my_print)
     174            sage: foo(x,y^z)
     175            Traceback (most recent call last):
     176            ...
     177            ValueError: custom print function for symbolic function returned None
     178            sage: latex(foo(x,y^z))
     179            Traceback (most recent call last):
     180            ...
     181            ValueError: custom print function for symbolic function returned None
     182
     183        Print function raises error::
     184
     185            sage: def my_print(*args, **kwds): raise ValueError
     186            sage: foo = nfunction('t', 2, print_func=my_print, print_latex_func=my_print)
     187            sage: foo(x,y^z)
     188            Traceback (most recent call last):
     189            ...
     190            ValueError
     191            sage: latex(foo(x,y^z))
     192            Traceback (most recent call last):
     193            ...
     194            ValueError
     195
    157196        """
    158197        self._name = name
    159198        self._nargs = nargs
  • sage/symbolic/operators.py

    diff --git a/sage/symbolic/operators.py b/sage/symbolic/operators.py
    a b  
    1515                      operator.ge:'>='}
    1616
    1717class FDerivativeOperator(object):
    18     def __init__(self, function, parameter_set):
     18    def __init__(self, function, parameter_set, nargs):
    1919        """
    2020        EXAMPLES::
    2121
    2222            sage: from sage.symbolic.operators import FDerivativeOperator
    2323            sage: f = function('foo')
    24             sage: op = FDerivativeOperator(f, [0,1])
     24            sage: op = FDerivativeOperator(f, [0,1], 2)
    2525            sage: loads(dumps(op))
    26             D[0, 1](foo)
     26            D[1, 1](foo)
    2727        """
    2828        self._f = function
    2929        self._parameter_set = map(int, parameter_set)
     30        self._nargs = nargs
    3031
    3132    def __call__(self, *args):
    3233        """
     
    3536            sage: from sage.symbolic.operators import FDerivativeOperator
    3637            sage: x,y = var('x,y')
    3738            sage: f = function('foo')
    38             sage: op = FDerivativeOperator(f, [0,1])
     39            sage: op = FDerivativeOperator(f, [0,1], 2)
    3940            sage: op(x,y)
    40             D[0, 1](foo)(x, y)
     41            D[1, 1](foo)(x, y)
    4142        """
    4243        if (not all(is_SymbolicVariable(x) for x in args) or
    4344            len(args) != len(set(args))):
     
    5152
    5253            sage: from sage.symbolic.operators import FDerivativeOperator
    5354            sage: f = function('foo')
    54             sage: op = FDerivativeOperator(f, [0,1]); op
    55             D[0, 1](foo)
     55            sage: op = FDerivativeOperator(f, [0,1], 2); op
     56            D[1, 1](foo)
    5657        """
    57         return "D[%s](%s)"%(", ".join(map(repr, self._parameter_set)), self._f)
     58        t = [0]*self._nargs
     59        for i in self._parameter_set:
     60            t[i] += 1
     61        return "D[%s](%s)"%(", ".join(map(repr, t)), self._f)
    5862
    5963    def function(self):
    6064        """
     
    6266
    6367            sage: from sage.symbolic.operators import FDerivativeOperator
    6468            sage: f = function('foo')
    65             sage: op = FDerivativeOperator(f, [0,1])
     69            sage: op = FDerivativeOperator(f, [0,1], 2)
    6670            sage: op.function()
    6771            foo
    6872        """
     
    7680            sage: from sage.symbolic.operators import FDerivativeOperator
    7781            sage: f = function('foo')
    7882            sage: b = function('bar')
    79             sage: op = FDerivativeOperator(f, [0,1])
     83            sage: op = FDerivativeOperator(f, [0,1], 2)
    8084            sage: op.change_function(bar)
    81             D[0, 1](bar)
     85            D[1, 1](bar)
    8286        """
    83         return FDerivativeOperator(new, self._parameter_set)
     87        return FDerivativeOperator(new, self._parameter_set, self._nargs)
    8488
    8589    def parameter_set(self):
    8690        """
     
    8892
    8993            sage: from sage.symbolic.operators import FDerivativeOperator
    9094            sage: f = function('foo')
    91             sage: op = FDerivativeOperator(f, [0,1])
     95            sage: op = FDerivativeOperator(f, [0,1], 2)
    9296            sage: op.parameter_set()
    9397            [0, 1]
    9498        """       
  • sage/symbolic/pynac.pyx

    diff --git a/sage/symbolic/pynac.pyx b/sage/symbolic/pynac.pyx
    a b  
    153153# We declare the functions defined below as extern here, to prevent Cython
    154154# from generating separate declarations for them which confuse g++
    155155cdef extern from *:
    156     stdstring* py_repr(object o, int level) except +   
     156    stdstring* py_repr(object o, int level) except +
    157157    stdstring* py_latex(object o, int level) except +
    158158    stdstring* py_latex_variable(char* var_name) except +
    159159    stdstring* py_print_function(unsigned id, object args) except +
     
    274274    print(ostr.c_str())
    275275    stdstring_delete(ostr)
    276276
    277 def py_print_function_pystring(id, args, fname_paren=False):
     277def dparams_to_str(params):
     278    """
     279    Helper function to typeset parameters for symbolic derivatives.
     280
     281    INPUT:
     282
     283    ``params`` - derivative parameters indicating how many times this
     284                expression is derivated w.r.t. the corresponding argument
     285
     286    EXAMPLES::
     287
     288        sage: from sage.symbolic.pynac import dparams_to_str
     289        sage: dparams_to_str((1,))
     290        "'"
     291        sage: dparams_to_str((2,))
     292        "''"
     293        sage: dparams_to_str((3,))
     294        '^{(3)}'
     295        sage: dparams_to_str((1,0))
     296        '^{(1,0)}'
     297    """
     298    if len(params) == 1:
     299        if params[0] == 1:
     300            return "'"
     301        elif params[0] == 2:
     302            return "''"
     303    return ''.join(['^{(', ','.join(map(str, params)), ')}'])
     304
     305def py_print_function_pystring(id, args, dparams=None):
    278306    """
    279307    Return a string with the representation of the symbolic function specified
    280308    by the given id applied to args.
    281309   
    282     INPUT:
     310    INPUT::
    283311
    284312        id --   serial number of the corresponding symbolic function
    285         params -- Set of parameter numbers with respect to which to take
    286                     the derivative.
    287313        args -- arguments of the function.
     314        dparams -- list of integers indicating how many times the function is
     315            derivated w.r.t. each argument
    288316
    289317    EXAMPLES::
    290318
     
    300328        True
    301329        sage: py_print_function_pystring(i, (x,y))
    302330        'foo(x, y)'
    303         sage: py_print_function_pystring(i, (x,y), True)
    304         '(foo)(x, y)'
    305         sage: def my_print(*args): return "my args are: " + ', '.join(map(repr, args))
     331        sage: py_print_function_pystring(i, (x,y), [0,1])
     332        'D[0, 1](foo)(x, y)'
     333        sage: def my_print(*args, **kwds): return "my args are: " + ', '.join(map(repr, args))
    306334        sage: foo = function('foo', 2, print_func=my_print)
    307335        sage: for i in range(get_ginac_serial(), get_ginac_serial()+50):
    308336        ...     if get_sfunction_from_serial(i) == foo: break
     
    311339        True
    312340        sage: py_print_function_pystring(i, (x,y))
    313341        'my args are: x, y'
     342
     343    Test error message::
     344
     345        sage: def broken_print(*args): return "my args are: " + ', '.join(map(repr, args))
     346        sage: bar = function('bar', 2, print_func=broken_print)
     347        sage: for i in range(get_ginac_serial(), get_ginac_serial()+50):
     348        ...     if get_sfunction_from_serial(i) == bar: break
     349
     350        sage: get_sfunction_from_serial(i) == bar
     351        True
     352        sage: py_print_function_pystring(i, (x,y^z))
     353        Traceback (most recent call last):
     354        ...
     355        TypeError: broken_print() got an unexpected keyword argument 'dparams'
     356
    314357    """
    315358    cdef SFunction func = get_sfunction_from_serial(id)
    316359    # This function is called from two places, from function::print in pynac
     
    322365
    323366    # if function has a custom print function call it
    324367    if func._print_ is not None:
    325         res = func._print_(*args)
     368        res = func._print_(*args, dparams=dparams)
    326369        # make sure the output is a string
    327370        if res is None:
    328             return ""
     371            raise ValueError, "custom print function for symbolic function returned None"
    329372        if not isinstance(res, str):
    330             return str(res)
     373            res = str(res)
    331374        return res
    332375
    333376    # otherwise use default output
    334     if fname_paren:
    335         olist = ['(', func._name, ')']
     377    if dparams:
     378        olist = ['D[',', '.join(map(str, dparams)), '](', func._name, ')' ]
    336379    else:
    337380        olist = [func._name]
    338381    olist.extend(['(', ', '.join(map(repr, args)), ')'])
     
    341384cdef public stdstring* py_print_function(unsigned id, object args) except +:
    342385    return string_from_pystr(py_print_function_pystring(id, args))
    343386
    344 def py_latex_function_pystring(id, args, fname_paren=False):
     387def py_latex_function_pystring(id, args, dparams=None):
    345388    """
    346389    Return a string with the latex representation of the symbolic function
    347390    specified by the given id applied to args.
     
    362405        True
    363406        sage: py_latex_function_pystring(i, (x,y^z))
    364407        '{\\rm foo}\\left(x, y^{z}\\right)'
    365         sage: py_latex_function_pystring(i, (x,y^z), True)
    366          '\\left({\\rm foo}\\right)\\left(x, y^{z}\\right)'
     408        sage: py_latex_function_pystring(i, (x,y^z), [1,1])
     409        '{\\rm foo}^{(1,1)}\\left(x, y^{z}\\right)'
    367410
    368411    Test latex_name::
    369412
     
    378421
    379422    Test custom func::
    380423
    381         sage: def my_print(*args): return "my args are: " + ', '.join(map(repr, args))
     424        sage: def my_print(*args, **kwds): return "my args are: " + ', '.join(map(repr, args))
    382425        sage: foo = function('foo', 2, print_latex_func=my_print)
    383426        sage: for i in range(get_ginac_serial(), get_ginac_serial()+50):
    384427        ...     if get_sfunction_from_serial(i) == foo: break
     
    388431        sage: py_latex_function_pystring(i, (x,y^z))
    389432        'my args are: x, y^z'
    390433
    391        
     434    Test error message::
     435
     436        sage: def broken_print(*args): return "my args are: " + ', '.join(map(repr, args))
     437        sage: bar = function('bar', 2, print_latex_func=broken_print)
     438        sage: for i in range(get_ginac_serial(), get_ginac_serial()+50):
     439        ...     if get_sfunction_from_serial(i) == bar: break
     440
     441        sage: get_sfunction_from_serial(i) == bar
     442        True
     443        sage: py_latex_function_pystring(i, (x,y^z))
     444        Traceback (most recent call last):
     445        ...
     446        TypeError: broken_print() got an unexpected keyword argument 'dparams'
     447
    392448    """
    393449    cdef SFunction func = get_sfunction_from_serial(id)
    394450    # This function is called from two places, from function::print in pynac
     
    400456
    401457    # if function has a custom print function call it
    402458    if func._print_latex_:
    403         res = func._print_latex_(*args)
     459        res = func._print_latex_(*args, dparams=dparams)
    404460        # make sure the output is a string
    405461        if res is None:
    406             return ""
     462            raise ValueError, "custom print function for symbolic function returned None"
    407463        if not isinstance(res, str):
    408             return str(res)
     464            res = str(res)
    409465        return res
    410466
    411467    # otherwise, use the latex name if defined
     
    416472        # latex_variable_name with "is_fname=True" flag
    417473        from sage.misc.latex import latex_variable_name
    418474        name = latex_variable_name(func._name, is_fname=True)
    419     if fname_paren:
    420         olist = [r'\left(', name, r'\right)']
     475    if dparams:
     476        olist = [name, dparams_to_str(dparams)]
    421477    else:
    422478        olist = [name]
    423479    # print the arguments
     
    443499
    444500
    445501    """
    446     ostr = ''.join(['D[', ', '.join([repr(int(x)) for x in params]), ']'])
    447     fstr = py_print_function_pystring(id, args, True)
    448     py_res = ostr + fstr
     502    dparams = [0]*len(args)
     503    for i in params:
     504        dparams[i] += 1
     505    py_res = py_print_function_pystring(id, args, dparams)
    449506    return string_from_pystr(py_res)
    450507
    451508def py_print_fderivative_for_doctests(id, params, args):
     
    465522        sage: get_sfunction_from_serial(i) == foo
    466523        True
    467524        sage: py_print_fderivative(i, (0, 1, 0, 1), (x, y^z))
    468         D[0, 1, 0, 1](foo)(x, y^z)
     525        D[2, 2](foo)(x, y^z)
    469526
    470527    Test custom print function::
    471528
    472         sage: def my_print(*args): return "func_with_args(" + ', '.join(map(repr, args)) +')'
     529        sage: def my_print(*args, **kwds): return "func_with_args(" + ', '.join(map(repr, args)) +')'
     530
    473531        sage: foo = function('foo', 2, print_func=my_print)
    474532        sage: for i in range(get_ginac_serial(), get_ginac_serial()+50):
    475533        ...     if get_sfunction_from_serial(i) == foo: break
     
    477535        sage: get_sfunction_from_serial(i) == foo
    478536        True
    479537        sage: py_print_fderivative(i, (0, 1, 0, 1), (x, y^z))
    480         D[0, 1, 0, 1]func_with_args(x, y^z)
     538        func_with_args(x, y^z)
    481539
    482540    """
    483541    cdef stdstring* ostr = py_print_fderivative(id, params, args)
     542    if ostr is NULL:
     543        raise RuntimeError, "py_latex_fderivative raised an error"
    484544    print(ostr.c_str())
    485545    stdstring_delete(ostr)
    486546
     
    493553    See documentation of py_print_fderivative for more information.
    494554
    495555    """
    496     ostr = ''.join(['D[', ', '.join([repr(int(x)) for x in params]), ']'])
    497     fstr = py_latex_function_pystring(id, args, True)
    498     py_res = ostr + fstr
     556    dparams = [0]*len(args)
     557    for i in params:
     558        dparams[i] += 1
     559    py_res = py_latex_function_pystring(id, args, dparams)
    499560    return string_from_pystr(py_res)
    500561
    501562def py_latex_fderivative_for_doctests(id, params, args):
     
    515576        sage: get_sfunction_from_serial(i) == foo
    516577        True
    517578        sage: py_latex_fderivative(i, (0, 1, 0, 1), (x, y^z))
    518         D[0, 1, 0, 1]\left({\rm foo}\right)\left(x, y^{z}\right)
     579        {\rm foo}^{(2,2)}\left(x, y^{z}\right)
    519580
    520581    Test latex_name::
    521582
     
    526587        sage: get_sfunction_from_serial(i) == foo
    527588        True
    528589        sage: py_latex_fderivative(i, (0, 1, 0, 1), (x, y^z))
    529         D[0, 1, 0, 1]\left(\mathrm{bar}\right)\left(x, y^{z}\right)
     590        \mathrm{bar}^{(2,2)}\left(x, y^{z}\right)
    530591
    531592    Test custom func::
    532593
    533         sage: def my_print(*args): return "func_with_args(" + ', '.join(map(repr, args)) +')'
     594        sage: def my_print(*args, **kwds): return "func_with_args(" + ', '.join(map(repr, args)) +')'
     595
    534596        sage: foo = function('foo', 2, print_latex_func=my_print)
    535597        sage: for i in range(get_ginac_serial(), get_ginac_serial()+50):
    536598        ...     if get_sfunction_from_serial(i) == foo: break
     
    538600        sage: get_sfunction_from_serial(i) == foo
    539601        True
    540602        sage: py_latex_fderivative(i, (0, 1, 0, 1), (x, y^z))
    541         D[0, 1, 0, 1]func_with_args(x, y^z)
     603        func_with_args(x, y^z)
    542604    """
    543605    cdef stdstring* ostr = py_latex_fderivative(id, params, args)
     606    if ostr is NULL:
     607        raise RuntimeError, "py_latex_fderivative raised an error"
    544608    print(ostr.c_str())
    545609    stdstring_delete(ostr)
    546610