Some Common Issues with Functions - Tutorial

Skip to content
Back to top
View this page
Edit this page

# Some Common Issues with Functions

Some aspects of defining functions (e.g., for differentiation or plotting) can be confusing. In this section we try to address some of the relevant issues.

Here are several ways to define things which might deserve to be called “functions”:

1. Define a Python function, as described in Functions, Indentation, and Counting. These functions can be plotted, but not differentiated or integrated.

Sage

    sage: def f(z): return z^2
    sage: type(f)
    <... 'function'>
    sage: f(3)
    9
    sage: plot(f, 0, 2)
    Graphics object consisting of 1 graphics primitive

Python

    >>> from sage.all import *
    >>> def f(z): return z**Integer(2)
    >>> type(f)
    <... 'function'>
    >>> f(Integer(3))
    9
    >>> plot(f, Integer(0), Integer(2))
    Graphics object consisting of 1 graphics primitive

In the last line, note the syntax. Using `plot(f(z), 0, 2)` instead will give a `NameError`, because `z` is a dummy variable in the definition of `f` and is not defined outside of that definition. In order to be able to use `f(z)` in the plot command, `z` (or whatever is desired) needs to be defined as a variable. We can use the syntax below, or in the next item in our list.

Sage

    sage: var('z')   # define z to be a variable
    z
    sage: f(z)
    z^2
    sage: plot(f(z), 0, 2)
    Graphics object consisting of 1 graphics primitive

[Python]

    >>> from sage.all import *
    >>> var('z')   # define z to be a variable
    z
    >>> f(z)
    z^2
    >>> plot(f(z), Integer(0), Integer(2))
    Graphics object consisting of 1 graphics primitive

At this point, `f(z)` is a symbolic expression, the next item in our list.

2. Define a “callable symbolic expression”. These can be plotted, differentiated, and integrated.

Sage

    sage: g(x) = x^2
    sage: g        # g sends x to x^2
    x |--> x^2
    sage: g(3)
    9
    sage: Dg = g.derivative(); Dg
    x |--> 2*x
    sage: Dg(3)
    6
    sage: type(g)
    <class 'sage.symbolic.expression.Expression'>
    sage: plot(g, 0, 2)
    Graphics object consisting of 1 graphics primitive

Python

    >>> from sage.all import *
    >>> __tmp__=var("x"); g = symbolic_expression(x**Integer(2)).function(x)
    >>> g        # g sends x to x^2
    x |--> x^2
    >>> g(Integer(3))
    9
    >>> Dg = g.derivative(); Dg
    x |--> 2*x
    >>> Dg(Integer(3))
    6
    >>> type(g)
    <class 'sage.symbolic.expression.Expression'>
    >>> plot(g, Integer(0), Integer(2))
    Graphics object consisting of 1 graphics primitive

Note that while `g` is a callable symbolic expression, `g(x)` is a related, but different sort of object, which can also be plotted, differentated, etc., albeit with some issues: see item 5 below for an illustration.

Sage

    sage: g(x)
    x^2
    sage: type(g(x))
    <class 'sage.symbolic.expression.Expression'>
    sage: g(x).derivative()
    2*x
    sage: plot(g(x), 0, 2)
    Graphics object consisting of 1 graphics primitive

[Python]

    >>> from sage.all import *
    >>> g(x)
    x^2
    >>> type(g(x))
    <class 'sage.symbolic.expression.Expression'>
    >>> g(x).derivative()
    2*x
    >>> plot(g(x), Integer(0), Integer(2))
    Graphics object consisting of 1 graphics primitive

3. Use a pre-defined Sage ‘calculus function’. These can be plotted, and with a little help, differentiated, and integrated.

Sage

    sage: type(sin)
    <class 'sage.functions.trig.Function_sin'>
    sage: plot(sin, 0, 2)
    Graphics object consisting of 1 graphics primitive
    sage: type(sin(x))
    <class 'sage.symbolic.expression.Expression'>
    sage: plot(sin(x), 0, 2)
    Graphics object consisting of 1 graphics primitive

Python

    >>> from sage.all import *
    >>> type(sin)
    <class 'sage.functions.trig.Function_sin'>
    >>> plot(sin, Integer(0), Integer(2))
    Graphics object consisting of 1 graphics primitive
    >>> type(sin(x))
    <class 'sage.symbolic.expression.Expression'>
    >>> plot(sin(x), Integer(0), Integer(2))
    Graphics object consisting of 1 graphics primitive

By itself, `sin` cannot be differentiated, at least not to produce `cos`.

Sage

    sage: f = sin
    sage: f.derivative()
    Traceback (most recent call last):
    ...
    AttributeError: ...

[Python]

    >>> from sage.all import *
    >>> f = sin
    >>> f.derivative()
    Traceback (most recent call last):
    ...
    AttributeError: ...

Using `f = sin(x)` instead of `sin` works, but it is probably even better to use `f(x) = sin(x)` to define a callable symbolic expression.

Sage

    sage: S(x) = sin(x)
    sage: S.derivative()
    x |--> cos(x)

Python

    >>> from sage.all import *
    >>> __tmp__=var("x"); S = symbolic_expression(sin(x)).function(x)
    >>> S.derivative()
    x |--> cos(x)

Here are some common problems, with explanations:

4. Accidental evaluation.

Sage

    sage: def h(x):
    ....:     if x<2:
    ....:         return 0
    ....:     else:
    ....:         return x-2

[Python]

    >>> from sage.all import *
    >>> def h(x):
    ...     if x<Integer(2):
    ...         return Integer(0)
    ...     else:
    ...         return x-Integer(2)

The issue: `plot(h(x), 0, 4)` plots the line \(y=x-2\), not the multi-line function defined by `h`. The reason? In the command `plot(h(x), 0, 4)`, first `h(x)` is evaluated: this means plugging the symbolic variable `x` into the function `h`. So, the inequality `x < 2` evaluates to `False` first, and hence `h(x)` evaluates to `x - 2`. This can be seen with

Sage

    sage: bool(x < 2)
    False
    sage: h(x)
    x - 2

Python

    >>> from sage.all import *
    >>> bool(x < Integer(2))
    False
    >>> h(x)
    x - 2

Note that here there are two different `x`: the Python variable used to define the function `h` (which is local to its definition) and the symbolic variable `x` which is available on startup in Sage.

The solution: don’t use `plot(h(x), 0, 4)`; instead, use

Sage

    sage: plot(h, 0, 4)
    Graphics object consisting of 1 graphics primitive

[Python]

    >>> from sage.all import *
    >>> plot(h, Integer(0), Integer(4))
    Graphics object consisting of 1 graphics primitive

5. Accidentally producing a constant instead of a function.

Sage

    sage: f = x
    sage: g = f.derivative()
    sage: g
    1

Python

    >>> from sage.all import *
    >>> f = x
    >>> g = f.derivative()
    >>> g
    1

The problem: `g(3)`, for example, returns an error, saying “ValueError: the number of arguments must be less than or equal to 0.”

Sage

    sage: type(f)
    <class 'sage.symbolic.expression.Expression'>
    sage: type(g)
    <class 'sage.symbolic.expression.Expression'>

[Python]

    >>> from sage.all import *
    >>> type(f)
    <class 'sage.symbolic.expression.Expression'>
    >>> type(g)
    <class 'sage.symbolic.expression.Expression'>

`g` is not a function, it’s a constant, so it has no variables associated to it, and you can’t plug anything into it.

The solution: there are several options.

- Define `f` initially to be a symbolic expression.

Sage

    sage: f(x) = x        # instead of 'f = x'
    sage: g = f.derivative()
    sage: g
    x |--> 1
    sage: g(3)
    1
    sage: type(g)
    <class 'sage.symbolic.expression.Expression'>

Python

    >>> from sage.all import *
    >>> __tmp__=var("x"); f = symbolic_expression(x        ).function(x)# instead of 'f = x'
    >>> g = f.derivative()
    >>> g
    x |--> 1
    >>> g(Integer(3))
    1
    >>> type(g)
    <class 'sage.symbolic.expression.Expression'>

- Or with `f` as defined originally, define `g` to be a symbolic expression.

Sage

    sage: f = x
    sage: g(x) = f.derivative()  # instead of 'g = f.derivative()'
    sage: g
    x |--> 1
    sage: g(3)
    1
    sage: type(g)
    <class 'sage.symbolic.expression.Expression'>

[Python]

    >>> from sage.all import *
    >>> f = x
    >>> __tmp__=var("x"); g = symbolic_expression(f.derivative()  ).function(x)# instead of 'g = f.derivative()'
    >>> g
    x |--> 1
    >>> g(Integer(3))
    1
    >>> type(g)
    <class 'sage.symbolic.expression.Expression'>

- Or with `f` and `g` as defined originally, specify the variable for which you are substituting.

Sage

    sage: f = x
    sage: g = f.derivative()
    sage: g
    1
    sage: g(x=3)    # instead of 'g(3)'
    1

Python

    >>> from sage.all import *
    >>> f = x
    >>> g = f.derivative()
    >>> g
    1
    >>> g(x=Integer(3))    # instead of 'g(3)'
    1

Finally, here’s one more way to tell the difference between the derivatives of `f = x` and `f(x) = x`

Sage

    sage: f(x) = x
    sage: g = f.derivative()
    sage: g.variables()  # the variables present in g
    ()
    sage: g.arguments()  # the arguments which can be plugged into g
    (x,)
    sage: f = x
    sage: h = f.derivative()
    sage: h.variables()
    ()
    sage: h.arguments()
    ()

[Python]

    >>> from sage.all import *
    >>> __tmp__=var("x"); f = symbolic_expression(x).function(x)
    >>> g = f.derivative()
    >>> g.variables()  # the variables present in g
    ()
    >>> g.arguments()  # the arguments which can be plugged into g
    (x,)
    >>> f = x
    >>> h = f.derivative()
    >>> h.variables()
    ()
    >>> h.arguments()
    ()

As this example has been trying to illustrate, `h` accepts no arguments, and this is why `h(3)` returns an error.