Factory for symbolic functions¶
- sage.symbolic.function_factory.function(s, **kwds)[source]¶
Create a formal symbolic function with the name s.
INPUT:
nargs=0
– number of arguments the function accepts, defaults to variable number of arguments, or 0latex_name
– name used when printing in latex modeconversions
– dictionary specifying names of this function in other systems, this is used by the interfaces internally during conversioneval_func
– method used for automatic evaluationevalf_func
– method used for numeric evaluationevalf_params_first
– boolean to indicate if parameters should be evaluated numerically before calling the custom evalf functionconjugate_func
– method used for complex conjugationreal_part_func
– method used when taking real partsimag_part_func
– method used when taking imaginary partsderivative_func
– method to be used for (partial) derivation This method should take a keyword argument deriv_param specifying the index of the argument to differentiate w.r.ttderivative_func
– method to be used for derivativespower_func
– method used when taking powers This method should take a keyword argument power_param specifying the exponentseries_func
– method used for series expansion This method should expect keyword arguments -order
– order for the expansion to be computed -var
– variable to expand w.r.t. -at
– expand at this valueprint_func
– method for custom printingprint_latex_func
– method for custom printing in latex mode
Note that custom methods must be instance methods, i.e., expect the instance of the symbolic function as the first argument.
EXAMPLES:
sage: from sage.symbolic.function_factory import function sage: var('a, b') (a, b) sage: cr = function('cr') sage: f = cr(a) sage: g = f.diff(a).integral(b); g b*diff(cr(a), a) sage: foo = function("foo", nargs=2) sage: x,y,z = var("x y z") sage: foo(x, y) + foo(y, z)^2 foo(y, z)^2 + foo(x, y)
>>> from sage.all import * >>> from sage.symbolic.function_factory import function >>> var('a, b') (a, b) >>> cr = function('cr') >>> f = cr(a) >>> g = f.diff(a).integral(b); g b*diff(cr(a), a) >>> foo = function("foo", nargs=Integer(2)) >>> x,y,z = var("x y z") >>> foo(x, y) + foo(y, z)**Integer(2) foo(y, z)^2 + foo(x, y)
from sage.symbolic.function_factory import function var('a, b') cr = function('cr') f = cr(a) g = f.diff(a).integral(b); g foo = function("foo", nargs=2) x,y,z = var("x y z") foo(x, y) + foo(y, z)^2
You need to use
substitute_function()
to replace all occurrences of a function with another:sage: g.substitute_function(cr, cos) -b*sin(a) sage: g.substitute_function(cr, (sin(x) + cos(x)).function(x)) b*(cos(a) - sin(a))
>>> from sage.all import * >>> g.substitute_function(cr, cos) -b*sin(a) >>> g.substitute_function(cr, (sin(x) + cos(x)).function(x)) b*(cos(a) - sin(a))
g.substitute_function(cr, cos) g.substitute_function(cr, (sin(x) + cos(x)).function(x))
Basic arithmetic with unevaluated functions is no longer supported:
sage: x = var('x') sage: f = function('f') sage: 2*f Traceback (most recent call last): ... TypeError: unsupported operand parent(s) for *: 'Integer Ring' and '<class 'sage.symbolic.function_factory...NewSymbolicFunction'>'
>>> from sage.all import * >>> x = var('x') >>> f = function('f') >>> Integer(2)*f Traceback (most recent call last): ... TypeError: unsupported operand parent(s) for *: 'Integer Ring' and '<class 'sage.symbolic.function_factory...NewSymbolicFunction'>'
x = var('x') f = function('f') 2*f
You now need to evaluate the function in order to do the arithmetic:
sage: 2*f(x) 2*f(x)
>>> from sage.all import * >>> Integer(2)*f(x) 2*f(x)
2*f(x)
We create a formal function of one variable, write down an expression that involves first and second derivatives, and extract off coefficients.
sage: r, kappa = var('r,kappa') sage: psi = function('psi', nargs=1)(r); psi psi(r) sage: g = 1/r^2*(2*r*psi.derivative(r,1) + r^2*psi.derivative(r,2)); g (r^2*diff(psi(r), r, r) + 2*r*diff(psi(r), r))/r^2 sage: g.expand() 2*diff(psi(r), r)/r + diff(psi(r), r, r) sage: g.coefficient(psi.derivative(r,2)) 1 sage: g.coefficient(psi.derivative(r,1)) 2/r
>>> from sage.all import * >>> r, kappa = var('r,kappa') >>> psi = function('psi', nargs=Integer(1))(r); psi psi(r) >>> g = Integer(1)/r**Integer(2)*(Integer(2)*r*psi.derivative(r,Integer(1)) + r**Integer(2)*psi.derivative(r,Integer(2))); g (r^2*diff(psi(r), r, r) + 2*r*diff(psi(r), r))/r^2 >>> g.expand() 2*diff(psi(r), r)/r + diff(psi(r), r, r) >>> g.coefficient(psi.derivative(r,Integer(2))) 1 >>> g.coefficient(psi.derivative(r,Integer(1))) 2/r
r, kappa = var('r,kappa') psi = function('psi', nargs=1)(r); psi g = 1/r^2*(2*r*psi.derivative(r,1) + r^2*psi.derivative(r,2)); g g.expand() g.coefficient(psi.derivative(r,2)) g.coefficient(psi.derivative(r,1))
Defining custom methods for automatic or numeric evaluation, derivation, conjugation, etc. is supported:
sage: def ev(self, x): return 2*x sage: foo = function("foo", nargs=1, eval_func=ev) sage: foo(x) 2*x sage: foo = function("foo", nargs=1, eval_func=lambda self, x: 5) sage: foo(x) 5 sage: def ef(self, x): pass sage: bar = function("bar", nargs=1, eval_func=ef) sage: bar(x) bar(x) sage: def evalf_f(self, x, parent=None, algorithm=None): return 6 sage: foo = function("foo", nargs=1, evalf_func=evalf_f) sage: foo(x) foo(x) sage: foo(x).n() 6 sage: foo = function("foo", nargs=1, conjugate_func=ev) sage: foo(x).conjugate() 2*x sage: def deriv(self, *args, **kwds): ....: print("{} {}".format(args, kwds)) ....: return args[kwds['diff_param']]^2 sage: foo = function("foo", nargs=2, derivative_func=deriv) sage: foo(x,y).derivative(y) (x, y) {'diff_param': 1} y^2 sage: def pow(self, x, power_param=None): ....: print("{} {}".format(x, power_param)) ....: return x*power_param sage: foo = function("foo", nargs=1, power_func=pow) sage: foo(y)^(x+y) y x + y (x + y)*y sage: def expand(self, *args, **kwds): ....: print("{} {}".format(args, sorted(kwds.items()))) ....: return sum(args[0]^i for i in range(kwds['order'])) sage: foo = function("foo", nargs=1, series_func=expand) sage: foo(y).series(y, 5) (y,) [('at', 0), ('options', 0), ('order', 5), ('var', y)] y^4 + y^3 + y^2 + y + 1 sage: def my_print(self, *args): return "my args are: " + ', '.join(map(repr, args)) sage: foo = function('t', nargs=2, print_func=my_print) sage: foo(x,y^z) my args are: x, y^z sage: latex(foo(x,y^z)) t\left(x, y^{z}\right) sage: foo = function('t', nargs=2, print_latex_func=my_print) sage: foo(x,y^z) t(x, y^z) sage: latex(foo(x,y^z)) my args are: x, y^z sage: foo = function('t', nargs=2, latex_name='foo') sage: latex(foo(x,y^z)) foo\left(x, y^{z}\right)
>>> from sage.all import * >>> def ev(self, x): return Integer(2)*x >>> foo = function("foo", nargs=Integer(1), eval_func=ev) >>> foo(x) 2*x >>> foo = function("foo", nargs=Integer(1), eval_func=lambda self, x: Integer(5)) >>> foo(x) 5 >>> def ef(self, x): pass >>> bar = function("bar", nargs=Integer(1), eval_func=ef) >>> bar(x) bar(x) >>> def evalf_f(self, x, parent=None, algorithm=None): return Integer(6) >>> foo = function("foo", nargs=Integer(1), evalf_func=evalf_f) >>> foo(x) foo(x) >>> foo(x).n() 6 >>> foo = function("foo", nargs=Integer(1), conjugate_func=ev) >>> foo(x).conjugate() 2*x >>> def deriv(self, *args, **kwds): ... print("{} {}".format(args, kwds)) ... return args[kwds['diff_param']]**Integer(2) >>> foo = function("foo", nargs=Integer(2), derivative_func=deriv) >>> foo(x,y).derivative(y) (x, y) {'diff_param': 1} y^2 >>> def pow(self, x, power_param=None): ... print("{} {}".format(x, power_param)) ... return x*power_param >>> foo = function("foo", nargs=Integer(1), power_func=pow) >>> foo(y)**(x+y) y x + y (x + y)*y >>> def expand(self, *args, **kwds): ... print("{} {}".format(args, sorted(kwds.items()))) ... return sum(args[Integer(0)]**i for i in range(kwds['order'])) >>> foo = function("foo", nargs=Integer(1), series_func=expand) >>> foo(y).series(y, Integer(5)) (y,) [('at', 0), ('options', 0), ('order', 5), ('var', y)] y^4 + y^3 + y^2 + y + 1 >>> def my_print(self, *args): return "my args are: " + ', '.join(map(repr, args)) >>> foo = function('t', nargs=Integer(2), print_func=my_print) >>> foo(x,y**z) my args are: x, y^z >>> latex(foo(x,y**z)) t\left(x, y^{z}\right) >>> foo = function('t', nargs=Integer(2), print_latex_func=my_print) >>> foo(x,y**z) t(x, y^z) >>> latex(foo(x,y**z)) my args are: x, y^z >>> foo = function('t', nargs=Integer(2), latex_name='foo') >>> latex(foo(x,y**z)) foo\left(x, y^{z}\right)
def ev(self, x): return 2*x foo = function("foo", nargs=1, eval_func=ev) foo(x) foo = function("foo", nargs=1, eval_func=lambda self, x: 5) foo(x) def ef(self, x): pass bar = function("bar", nargs=1, eval_func=ef) bar(x) def evalf_f(self, x, parent=None, algorithm=None): return 6 foo = function("foo", nargs=1, evalf_func=evalf_f) foo(x) foo(x).n() foo = function("foo", nargs=1, conjugate_func=ev) foo(x).conjugate() def deriv(self, *args, **kwds): print("{} {}".format(args, kwds)) return args[kwds['diff_param']]^2 foo = function("foo", nargs=2, derivative_func=deriv) foo(x,y).derivative(y) def pow(self, x, power_param=None): print("{} {}".format(x, power_param)) return x*power_param foo = function("foo", nargs=1, power_func=pow) foo(y)^(x+y) def expand(self, *args, **kwds): print("{} {}".format(args, sorted(kwds.items()))) return sum(args[0]^i for i in range(kwds['order'])) foo = function("foo", nargs=1, series_func=expand) foo(y).series(y, 5) def my_print(self, *args): return "my args are: " + ', '.join(map(repr, args)) foo = function('t', nargs=2, print_func=my_print) foo(x,y^z) latex(foo(x,y^z)) foo = function('t', nargs=2, print_latex_func=my_print) foo(x,y^z) latex(foo(x,y^z)) foo = function('t', nargs=2, latex_name='foo') latex(foo(x,y^z))
Chain rule:
sage: def print_args(self, *args, **kwds): print("args: {}".format(args)); print("kwds: {}".format(kwds)); return args[0] sage: foo = function('t', nargs=2, tderivative_func=print_args) sage: foo(x,x).derivative(x) args: (x, x) kwds: {'diff_param': x} x sage: foo = function('t', nargs=2, derivative_func=print_args) sage: foo(x,x).derivative(x) args: (x, x) kwds: {'diff_param': 0} args: (x, x) kwds: {'diff_param': 1} 2*x
>>> from sage.all import * >>> def print_args(self, *args, **kwds): print("args: {}".format(args)); print("kwds: {}".format(kwds)); return args[Integer(0)] >>> foo = function('t', nargs=Integer(2), tderivative_func=print_args) >>> foo(x,x).derivative(x) args: (x, x) kwds: {'diff_param': x} x >>> foo = function('t', nargs=Integer(2), derivative_func=print_args) >>> foo(x,x).derivative(x) args: (x, x) kwds: {'diff_param': 0} args: (x, x) kwds: {'diff_param': 1} 2*x
def print_args(self, *args, **kwds): print("args: {}".format(args)); print("kwds: {}".format(kwds)); return args[0] foo = function('t', nargs=2, tderivative_func=print_args) foo(x,x).derivative(x) foo = function('t', nargs=2, derivative_func=print_args) foo(x,x).derivative(x)
- sage.symbolic.function_factory.function_factory(name, nargs=0, latex_name=None, conversions=None, evalf_params_first=True, eval_func=None, evalf_func=None, conjugate_func=None, real_part_func=None, imag_part_func=None, derivative_func=None, tderivative_func=None, power_func=None, series_func=None, print_func=None, print_latex_func=None)[source]¶
Create a formal symbolic function. For an explanation of the arguments see the documentation for the method
function()
.EXAMPLES:
sage: from sage.symbolic.function_factory import function_factory sage: f = function_factory('f', 2, '\\foo', {'mathematica':'Foo'}) sage: f(2,4) f(2, 4) sage: latex(f(1,2)) \foo\left(1, 2\right) sage: f._mathematica_init_() 'Foo' sage: def evalf_f(self, x, parent=None, algorithm=None): return x*.5r sage: g = function_factory('g',1,evalf_func=evalf_f) sage: g(2) g(2) sage: g(2).n() 1.00000000000000
>>> from sage.all import * >>> from sage.symbolic.function_factory import function_factory >>> f = function_factory('f', Integer(2), '\\foo', {'mathematica':'Foo'}) >>> f(Integer(2),Integer(4)) f(2, 4) >>> latex(f(Integer(1),Integer(2))) \foo\left(1, 2\right) >>> f._mathematica_init_() 'Foo' >>> def evalf_f(self, x, parent=None, algorithm=None): return x*.5 >>> g = function_factory('g',Integer(1),evalf_func=evalf_f) >>> g(Integer(2)) g(2) >>> g(Integer(2)).n() 1.00000000000000
from sage.symbolic.function_factory import function_factory f = function_factory('f', 2, '\\foo', {'mathematica':'Foo'}) f(2,4) latex(f(1,2)) f._mathematica_init_() def evalf_f(self, x, parent=None, algorithm=None): return x*.5r g = function_factory('g',1,evalf_func=evalf_f) g(2) g(2).n()
- sage.symbolic.function_factory.unpickle_function(name, nargs, latex_name, conversions, evalf_params_first, pickled_funcs)[source]¶
This is returned by the
__reduce__
method of symbolic functions to be called during unpickling to recreate the given function.It calls
function_factory()
with the supplied arguments.EXAMPLES:
sage: from sage.symbolic.function_factory import unpickle_function sage: nf = unpickle_function('f', 2, '\\foo', {'mathematica':'Foo'}, True, []) sage: nf f sage: nf(1,2) f(1, 2) sage: latex(nf(x,x)) \foo\left(x, x\right) sage: nf._mathematica_init_() 'Foo' sage: from sage.symbolic.function import pickle_wrapper sage: def evalf_f(self, x, parent=None, algorithm=None): return 2r*x + 5r sage: def conjugate_f(self, x): return x/2r sage: nf = unpickle_function('g', 1, None, None, True, [None, pickle_wrapper(evalf_f), pickle_wrapper(conjugate_f)] + [None]*8) sage: nf g sage: nf(2) g(2) sage: nf(2).n() 9.00000000000000 sage: nf(2).conjugate() 1
>>> from sage.all import * >>> from sage.symbolic.function_factory import unpickle_function >>> nf = unpickle_function('f', Integer(2), '\\foo', {'mathematica':'Foo'}, True, []) >>> nf f >>> nf(Integer(1),Integer(2)) f(1, 2) >>> latex(nf(x,x)) \foo\left(x, x\right) >>> nf._mathematica_init_() 'Foo' >>> from sage.symbolic.function import pickle_wrapper >>> def evalf_f(self, x, parent=None, algorithm=None): return 2*x + 5 >>> def conjugate_f(self, x): return x/2 >>> nf = unpickle_function('g', Integer(1), None, None, True, [None, pickle_wrapper(evalf_f), pickle_wrapper(conjugate_f)] + [None]*Integer(8)) >>> nf g >>> nf(Integer(2)) g(2) >>> nf(Integer(2)).n() 9.00000000000000 >>> nf(Integer(2)).conjugate() 1
from sage.symbolic.function_factory import unpickle_function nf = unpickle_function('f', 2, '\\foo', {'mathematica':'Foo'}, True, []) nf nf(1,2) latex(nf(x,x)) nf._mathematica_init_() from sage.symbolic.function import pickle_wrapper def evalf_f(self, x, parent=None, algorithm=None): return 2r*x + 5r def conjugate_f(self, x): return x/2r nf = unpickle_function('g', 1, None, None, True, [None, pickle_wrapper(evalf_f), pickle_wrapper(conjugate_f)] + [None]*8) nf nf(2) nf(2).n() nf(2).conjugate()