Classes for symbolic functions

To enable their usage as part of symbolic expressions, symbolic function classes are derived from one of the subclasses of Function:

  • BuiltinFunction: the code of these functions is written in Python; many special functions are of this type

  • GinacFunction: the code of these functions is written in C++ and part of the Pynac support library; most elementary functions are of this type

  • SymbolicFunction: symbolic functions defined on the Sage command line are of this type

Sage uses BuiltinFunction and GinacFunction for its symbolic builtin functions. Users can define any other additional SymbolicFunction through the function() factory, see Factory for symbolic functions

Several parameters are supported by the superclass’ __init__() method. Examples follow below.

  • nargs: the number of arguments

  • name: the string that is printed on the CLI; the name of the member functions that are attempted for evaluation of Sage element arguments; also the name of the Pynac function that is associated with a GinacFunction

  • alt_name: the second name of the member functions that are attempted for evaluation of Sage element arguments

  • latex_name: what is printed when latex(f(...)) is called

  • conversions: a dict containing the function’s name in other CAS

  • evalf_params_first: if False, when floating-point evaluating the expression do not evaluate function arguments before calling the _evalf_() member of the function

  • preserved_arg: if nonzero, the index (starting with 1) of the function argument that determines the return type. Note that, e.g, atan2() uses both arguments to determine return type, through a different mechanism

Function classes can define the following Python member functions:

  • _eval_(*args): the only mandatory member function, evaluating the argument and returning the result; if None is returned the expression stays unevaluated

  • _eval_numpy_(*args): evaluation of f(args) with arguments of numpy type

  • _evalf_(*args, **kwds): called when the expression is floating-point evaluated; may receive a parent keyword specifying the expected parent of the result. If not defined an attempt is made to convert the result of _eval_().

  • _conjugate_(*args), _real_part_(*args), _imag_part_(*args): return conjugate, real part, imaginary part of the expression f(args)

  • _derivative_(*args, index): return derivative with respect to the parameter indexed by index (starting with 0) of f(args)

  • _tderivative_(): same as _derivative_() but don’t apply chain rule; only one of the two functions may be defined

  • _power_(*args, expo): return f(args)^expo

  • _series_(*args, **kwds): return the power series at at up to order with respect to var of f(args); these three values are received in kwds. If not defined the series is attempted to be computed by differentiation.

  • print(*args): return what should be printed on the CLI with f(args)

  • print_latex(*args): return what should be output with latex(f(args))

The following examples are intended for Sage developers. Users can define functions interactively through the function() factory, see Factory for symbolic functions.

EXAMPLES:

The simplest example is a function returning nothing, it practically behaves like a symbol. Setting nargs=0 allows any number of arguments:

sage: from sage.symbolic.function import BuiltinFunction
sage: class Test1(BuiltinFunction):
....:     def __init__(self):
....:         BuiltinFunction.__init__(self, 'test', nargs=0)
....:     def _eval_(self, *args):
....:         pass
sage: f = Test1()
sage: f()                                                                           # needs sage.symbolic
test()
sage: f(1,2,3)*f(1,2,3)                                                             # needs sage.symbolic
test(1, 2, 3)^2
>>> from sage.all import *
>>> from sage.symbolic.function import BuiltinFunction
>>> class Test1(BuiltinFunction):
...     def __init__(self):
...         BuiltinFunction.__init__(self, 'test', nargs=Integer(0))
...     def _eval_(self, *args):
...         pass
>>> f = Test1()
>>> f()                                                                           # needs sage.symbolic
test()
>>> f(Integer(1),Integer(2),Integer(3))*f(Integer(1),Integer(2),Integer(3))                                                             # needs sage.symbolic
test(1, 2, 3)^2
from sage.symbolic.function import BuiltinFunction
class Test1(BuiltinFunction):
    def __init__(self):
        BuiltinFunction.__init__(self, 'test', nargs=0)
    def _eval_(self, *args):
        pass
f = Test1()
f()                                                                           # needs sage.symbolic
f(1,2,3)*f(1,2,3)                                                             # needs sage.symbolic

In the following the sin function of CBF(0) is called because with floating point arguments the CBF element’s my_sin() member function is attempted, and after that sin() which succeeds:

sage: class Test2(BuiltinFunction):
....:     def __init__(self):
....:         BuiltinFunction.__init__(self, 'my_sin', alt_name='sin',
....:                                  latex_name=r'\SIN', nargs=1)
....:     def _eval_(self, x):
....:         return 5
....:     def _evalf_(self, x, **kwds):
....:         return 3.5
sage: f = Test2()
sage: f(0)
5
sage: f(0, hold=True)                                                               # needs sage.symbolic
my_sin(0)
sage: f(0, hold=True).n()                                                           # needs sage.rings.real_mpfr
3.50000000000000
sage: f(CBF(0))                                                                     # needs sage.libs.flint
0

sage: latex(f(0, hold=True))                                                        # needs sage.symbolic
\SIN\left(0\right)
sage: f(1,2)
Traceback (most recent call last):
...
TypeError: Symbolic function my_sin takes exactly 1 arguments (2 given)
>>> from sage.all import *
>>> class Test2(BuiltinFunction):
...     def __init__(self):
...         BuiltinFunction.__init__(self, 'my_sin', alt_name='sin',
...                                  latex_name=r'\SIN', nargs=Integer(1))
...     def _eval_(self, x):
...         return Integer(5)
...     def _evalf_(self, x, **kwds):
...         return RealNumber('3.5')
>>> f = Test2()
>>> f(Integer(0))
5
>>> f(Integer(0), hold=True)                                                               # needs sage.symbolic
my_sin(0)
>>> f(Integer(0), hold=True).n()                                                           # needs sage.rings.real_mpfr
3.50000000000000
>>> f(CBF(Integer(0)))                                                                     # needs sage.libs.flint
0

>>> latex(f(Integer(0), hold=True))                                                        # needs sage.symbolic
\SIN\left(0\right)
>>> f(Integer(1),Integer(2))
Traceback (most recent call last):
...
TypeError: Symbolic function my_sin takes exactly 1 arguments (2 given)
class Test2(BuiltinFunction):
    def __init__(self):
        BuiltinFunction.__init__(self, 'my_sin', alt_name='sin',
                                 latex_name=r'\SIN', nargs=1)
    def _eval_(self, x):
        return 5
    def _evalf_(self, x, **kwds):
        return 3.5
f = Test2()
f(0)
f(0, hold=True)                                                               # needs sage.symbolic
f(0, hold=True).n()                                                           # needs sage.rings.real_mpfr
f(CBF(0))                                                                     # needs sage.libs.flint
latex(f(0, hold=True))                                                        # needs sage.symbolic
f(1,2)
class sage.symbolic.function.BuiltinFunction[source]

Bases: Function

This is the base class for symbolic functions defined in Sage.

If a function is provided by the Sage library, we don’t need to pickle the custom methods, since we can just initialize the same library function again. This allows us to use Cython for custom methods.

We assume that each subclass of this class will define one symbolic function. Make sure you use subclasses and not just call the initializer of this class.

class sage.symbolic.function.Function[source]

Bases: SageObject

Base class for symbolic functions defined through Pynac in Sage.

This is an abstract base class, with generic code for the interfaces and a __call__() method. Subclasses should implement the _is_registered() and _register_function() methods.

This class is not intended for direct use, instead use one of the subclasses BuiltinFunction or SymbolicFunction.

default_variable()[source]

Return a default variable.

EXAMPLES:

sage: sin.default_variable()                                                # needs sage.symbolic
x
>>> from sage.all import *
>>> sin.default_variable()                                                # needs sage.symbolic
x
sin.default_variable()                                                # needs sage.symbolic
name()[source]

Return the name of this function.

EXAMPLES:

sage: foo = function("foo", nargs=2)                                        # needs sage.symbolic
sage: foo.name()                                                            # needs sage.symbolic
'foo'
>>> from sage.all import *
>>> foo = function("foo", nargs=Integer(2))                                        # needs sage.symbolic
>>> foo.name()                                                            # needs sage.symbolic
'foo'
foo = function("foo", nargs=2)                                        # needs sage.symbolic
foo.name()                                                            # needs sage.symbolic
number_of_arguments()[source]

Return the number of arguments that this function takes.

EXAMPLES:

sage: # needs sage.symbolic
sage: foo = function("foo", nargs=2)
sage: foo.number_of_arguments()
2
sage: foo(x, x)
foo(x, x)
sage: foo(x)
Traceback (most recent call last):
...
TypeError: Symbolic function foo takes exactly 2 arguments (1 given)
>>> from sage.all import *
>>> # needs sage.symbolic
>>> foo = function("foo", nargs=Integer(2))
>>> foo.number_of_arguments()
2
>>> foo(x, x)
foo(x, x)
>>> foo(x)
Traceback (most recent call last):
...
TypeError: Symbolic function foo takes exactly 2 arguments (1 given)
# needs sage.symbolic
foo = function("foo", nargs=2)
foo.number_of_arguments()
foo(x, x)
foo(x)
variables()[source]

Return the variables (of which there are none) present in this function.

EXAMPLES:

sage: sin.variables()
()
>>> from sage.all import *
>>> sin.variables()
()
sin.variables()
class sage.symbolic.function.GinacFunction[source]

Bases: BuiltinFunction

This class provides a wrapper around symbolic functions already defined in Pynac/GiNaC.

GiNaC provides custom methods for these functions defined at the C++ level. It is still possible to define new custom functionality or override those already defined.

There is also no need to register these functions.

class sage.symbolic.function.SymbolicFunction[source]

Bases: Function

This is the basis for user defined symbolic functions. We try to pickle or hash the custom methods, so subclasses must be defined in Python not Cython.

sage.symbolic.function.pickle_wrapper(f)[source]

Return a pickled version of the function f.

If f is None, just return None.

This is a wrapper around pickle_function().

EXAMPLES:

sage: from sage.symbolic.function import pickle_wrapper
sage: def f(x): return x*x
sage: isinstance(pickle_wrapper(f), bytes)
True
sage: pickle_wrapper(None) is None
True
>>> from sage.all import *
>>> from sage.symbolic.function import pickle_wrapper
>>> def f(x): return x*x
>>> isinstance(pickle_wrapper(f), bytes)
True
>>> pickle_wrapper(None) is None
True
from sage.symbolic.function import pickle_wrapper
def f(x): return x*x
isinstance(pickle_wrapper(f), bytes)
pickle_wrapper(None) is None
sage.symbolic.function.unpickle_wrapper(p)[source]

Return a unpickled version of the function defined by p.

If p is None, just return None.

This is a wrapper around unpickle_function().

EXAMPLES:

sage: from sage.symbolic.function import pickle_wrapper, unpickle_wrapper
sage: def f(x): return x*x
sage: s = pickle_wrapper(f)
sage: g = unpickle_wrapper(s)
sage: g(2)
4
sage: unpickle_wrapper(None) is None
True
>>> from sage.all import *
>>> from sage.symbolic.function import pickle_wrapper, unpickle_wrapper
>>> def f(x): return x*x
>>> s = pickle_wrapper(f)
>>> g = unpickle_wrapper(s)
>>> g(Integer(2))
4
>>> unpickle_wrapper(None) is None
True
from sage.symbolic.function import pickle_wrapper, unpickle_wrapper
def f(x): return x*x
s = pickle_wrapper(f)
g = unpickle_wrapper(s)
g(2)
unpickle_wrapper(None) is None