# Optimización de funciones escalares diferenciables con `SymPy`

> - Mediante optimización se obtienen soluciones elegantes tanto en teoría como en ciertas aplicaciones.
> - La teoría de optimización usa elementos comenzando con cálculo elemental y álgebra lineal básica, y luego se extiende con análisis funcional y convexo.
> - Las aplicaciones en optimización involucran ciencia, ingeniería, economía, finanzas e industria.
> - El amplio y creciente uso de la optimización lo hace escencial para estudiantes y profesionales de cualquier rama de la ciencia y la tecnología.

**Referencia:**
- http://www.math.uwaterloo.ca/~hwolkowi//henry/reports/talks.d/t06talks.d/06msribirs.d/optimportance.shtml

Algunas aplicaciones son:

1. Ingeniería
 - Encontrar la composición de equilibrio de una mezcla de diferentes átomos.
 - Planeación de ruta para un robot (o vehículo aéreo no tripulado).
 - Planeación de la mano de obra óptima en una construcción o planta de producción.
2. Distribución óptima de recursos.
 - Distribución de rutas de vuelo.
 - Encontrar una dieta óptima.
 - Planeación de ruta óptima.
3. Optimización financiera
 - Administración de riesgos.
 - Portafolios de inversión.

En esta clase veremos aspectos básicos de optimización. En específico, veremos cómo obtener máximos y mínimos de una función escalar de una variable (como en cálculo diferencial).

___
## 0. Librerías que usaremos

Como ya dijimos en la primer clase `python` es el lenguaje de programación (el cual es de alto nivel). Sin embargo, `python` solo tiene unos pocos comandos primitivos y para hacer más fácil su uso en nuestras actividades de simulación en ingeniería, otras personas ya han escrito ciertas librerías por nosotros.

### 0.1 `NumPy`

`NumPy` (Numerical Python) es la librería fundamental para computación científica (numérica) con `Python`. Contiene, entre otras cosas:
- un objeto tipo arreglo N-dimensional muy poderoso
- funciones sofisticadas
- funciones de álgebra lineal, transformada de Fourier y números aleatorios.

Por lo anterior, `NumPy` es de amplio uso entre la comunidad científica e ingenieril (por su manejo de cantidades vectoriales). De la misma manera, se usa para guardar datos. Para nuestros propósitos, se puede usar libremente.

**Referencia:**
- http://www.numpy.org/

`NumPy` ya viene incluido en la instalación estándar de Anaconda por defecto. Para comenzar a usarlo, solo debemos de importarlo:

```python
# importar la librería numpy
import numpy as np
```

```python
a = np.array([1, 2, 3, 4])
a
```

    array([1, 2, 3, 4])

```python
a ** 2
```

    array([ 1,  4,  9, 16])

### 0.2 `SymPy`

`SymPy` (Symbolic Python) es una librería de `Python` para matemáticas simbólicas. Su objetivo es convertirse en un sistema de álgebra computacional con las mejores características, manteniendo el código lo más simple posible para que sea comprensible.

**Referencia:**
- http://www.sympy.org/en/index.html

`SymPy` ya viene incluido en la instalación estándar de Anaconda por defecto. Para comenzar a usarlo, solo debemos de importarlo:

```python
# importar la librería sympy
import sympy as sym
```

```python
help(sym.init_printing)
```

    Help on function init_printing in module sympy.interactive.printing:

    init_printing(pretty_print=True, order=None, use_unicode=None, use_latex=None, wrap_line=None, num_columns=None, no_global=False, ip=None, euler=False, forecolor=None, backcolor='Transparent', fontsize='10pt', latex_mode='plain', print_builtin=True, str_printer=None, pretty_printer=None, latex_printer=None, scale=1.0, **settings)
        Initializes pretty-printer depending on the environment.

        Parameters
        ==========

        pretty_print : boolean, default=True
            If True, use pretty_print to stringify or the provided pretty
            printer; if False, use sstrrepr to stringify or the provided string
            printer.
        order : string or None, default='lex'
            There are a few different settings for this parameter:
            lex (default), which is lexographic order;
            grlex, which is graded lexographic order;
            grevlex, which is reversed graded lexographic order;
            old, which is used for compatibility reasons and for long expressions;
            None, which sets it to lex.
        use_unicode : boolean or None, default=None
            If True, use unicode characters;
            if False, do not use unicode characters;
            if None, make a guess based on the environment.
        use_latex : string, boolean, or None, default=None
            If True, use default LaTeX rendering in GUI interfaces (png and
            mathjax);
            if False, do not use LaTeX rendering;
            if None, make a guess based on the environment;
            if 'png', enable latex rendering with an external latex compiler,
            falling back to matplotlib if external compilation fails;
            if 'matplotlib', enable LaTeX rendering with matplotlib;
            if 'mathjax', enable LaTeX text generation, for example MathJax
            rendering in IPython notebook or text rendering in LaTeX documents;
            if 'svg', enable LaTeX rendering with an external latex compiler,
            no fallback
        wrap_line : boolean
            If True, lines will wrap at the end; if False, they will not wrap
            but continue as one line. This is only relevant if ``pretty_print`` is
            True.
        num_columns : int or None, default=None
            If int, number of columns before wrapping is set to num_columns; if
            None, number of columns before wrapping is set to terminal width.
            This is only relevant if ``pretty_print`` is True.
        no_global : boolean, default=False
            If True, the settings become system wide;
            if False, use just for this console/session.
        ip : An interactive console
            This can either be an instance of IPython,
            or a class that derives from code.InteractiveConsole.
        euler : boolean, optional, default=False
            Loads the euler package in the LaTeX preamble for handwritten style
            fonts (http://www.ctan.org/pkg/euler).
        forecolor : string or None, optional, default=None
            DVI setting for foreground color. None means that either 'Black',
            'White', or 'Gray' will be selected based on a guess of the IPython
            terminal color setting. See notes.
        backcolor : string, optional, default='Transparent'
            DVI setting for background color. See notes.
        fontsize : string, optional, default='10pt'
            A font size to pass to the LaTeX documentclass function in the
            preamble. Note that the options are limited by the documentclass.
            Consider using scale instead.
        latex_mode : string, optional, default='plain'
            The mode used in the LaTeX printer. Can be one of:
            {'inline'|'plain'|'equation'|'equation*'}.
        print_builtin : boolean, optional, default=True
            If ``True`` then floats and integers will be printed. If ``False`` the
            printer will only print SymPy types.
        str_printer : function, optional, default=None
            A custom string printer function. This should mimic
            sympy.printing.sstrrepr().
        pretty_printer : function, optional, default=None
            A custom pretty printer. This should mimic sympy.printing.pretty().
        latex_printer : function, optional, default=None
            A custom LaTeX printer. This should mimic sympy.printing.latex().
        scale : float, optional, default=1.0
            Scale the LaTeX output when using the ``png`` or ``svg`` backends.
            Useful for high dpi screens.
        settings :
            Any additional settings for the ``latex`` and ``pretty`` commands can
            be used to fine-tune the output.

        Examples
        ========

        >>> from sympy.interactive import init_printing
        >>> from sympy import Symbol, sqrt
        >>> from sympy.abc import x, y
        >>> sqrt(5)
        sqrt(5)
        >>> init_printing(pretty_print=True) # doctest: +SKIP
        >>> sqrt(5) # doctest: +SKIP
          ___
        \/ 5
        >>> theta = Symbol('theta') # doctest: +SKIP
        >>> init_printing(use_unicode=True) # doctest: +SKIP
        >>> theta # doctest: +SKIP
        \u03b8
        >>> init_printing(use_unicode=False) # doctest: +SKIP
        >>> theta # doctest: +SKIP
        theta
        >>> init_printing(order='lex') # doctest: +SKIP
        >>> str(y + x + y**2 + x**2) # doctest: +SKIP
        x**2 + x + y**2 + y
        >>> init_printing(order='grlex') # doctest: +SKIP
        >>> str(y + x + y**2 + x**2) # doctest: +SKIP
        x**2 + x + y**2 + y
        >>> init_printing(order='grevlex') # doctest: +SKIP
        >>> str(y * x**2 + x * y**2) # doctest: +SKIP
        x**2*y + x*y**2
        >>> init_printing(order='old') # doctest: +SKIP
        >>> str(x**2 + y**2 + x + y) # doctest: +SKIP
        x**2 + x + y**2 + y
        >>> init_printing(num_columns=10) # doctest: +SKIP
        >>> x**2 + x + y**2 + y # doctest: +SKIP
        x + y +
        x**2 + y**2

        Notes
        =====

        The foreground and background colors can be selected when using 'png' or
        'svg' LaTeX rendering. Note that before the ``init_printing`` command is
        executed, the LaTeX rendering is handled by the IPython console and not SymPy.

        The colors can be selected among the 68 standard colors known to ``dvips``,
        for a list see [1]_. In addition, the background color can be
        set to  'Transparent' (which is the default value).

        When using the 'Auto' foreground color, the guess is based on the
        ``colors`` variable in the IPython console, see [2]_. Hence, if
        that variable is set correctly in your IPython console, there is a high
        chance that the output will be readable, although manual settings may be
        needed.

        References
        ==========

        .. [1] https://en.wikibooks.org/wiki/LaTeX/Colors#The_68_standard_colors_known_to_dvips

        .. [2] https://ipython.readthedocs.io/en/stable/config/details.html#terminal-colors

        See Also
        ========

        sympy.printing.latex
        sympy.printing.pretty

```python
# imprimir en formato latex
sym.init_printing(use_latex='mathjax')
```

La funcionalidad de imprimir en formato LaTex que nos da `SymPy` mediante el proyecto `mathjax` hace de `SymPy` una herramienta muy atractiva...

Notar que en `SymPy` y en `NumPy` existen funciones con el mismo nombre, pero reciben tipos de datos diferentes...

```python
sym.sin(3.1416)
```

$\displaystyle -7.34641020664359 \cdot 10^{-6}$

```python
np.sin(3.1416)
```

$\displaystyle -7.346410206643587e-06$

```python
vector = np.array([0, 3.1416 / 2, 3.1416, 3 * 3.1416 / 2])
np.sin(vector)
```

    array([ 0.00000000e+00,  1.00000000e+00, -7.34641021e-06, -1.00000000e+00])

```python
sym.sin(vector)
```

```python
help(sym.sin)
```

    Help on class sin in module sympy.functions.elementary.trigonometric:

    class sin(TrigonometricFunction)
     |  sin(arg)
     |
     |  The sine function.
     |
     |  Returns the sine of x (measured in radians).
     |
     |  Notes
     |  =====
     |
     |  This function will evaluate automatically in the
     |  case x/pi is some rational number [4]_.  For example,
     |  if x is a multiple of pi, pi/2, pi/3, pi/4 and pi/6.
     |
     |  Examples
     |  ========
     |
     |  >>> from sympy import sin, pi
     |  >>> from sympy.abc import x
     |  >>> sin(x**2).diff(x)
     |  2*x*cos(x**2)
     |  >>> sin(1).diff(x)
     |  0
     |  >>> sin(pi)
     |  0
     |  >>> sin(pi/2)
     |  1
     |  >>> sin(pi/6)
     |  1/2
     |  >>> sin(pi/12)
     |  -sqrt(2)/4 + sqrt(6)/4
     |
     |
     |  See Also
     |  ========
     |
     |  csc, cos, sec, tan, cot
     |  asin, acsc, acos, asec, atan, acot, atan2
     |
     |  References
     |  ==========
     |
     |  .. [1] https://en.wikipedia.org/wiki/Trigonometric_functions
     |  .. [2] http://dlmf.nist.gov/4.14
     |  .. [3] http://functions.wolfram.com/ElementaryFunctions/Sin
     |  .. [4] http://mathworld.wolfram.com/TrigonometryAngles.html
     |
     |  Method resolution order:
     |      sin
     |      TrigonometricFunction
     |      sympy.core.function.Function
     |      sympy.core.function.Application
     |      sympy.core.expr.Expr
     |      sympy.core.basic.Basic
     |      sympy.core.evalf.EvalfMixin
     |      builtins.object
     |
     |  Methods defined here:
     |
     |  as_real_imag(self, deep=True, **hints)
     |      Performs complex expansion on 'self' and returns a tuple
     |      containing collected both real and imaginary parts. This
     |      method can't be confused with re() and im() functions,
     |      which does not perform complex expansion at evaluation.
     |
     |      However it is possible to expand both re() and im()
     |      functions and get exactly the same results as with
     |      a single call to this function.
     |
     |      >>> from sympy import symbols, I
     |
     |      >>> x, y = symbols('x,y', real=True)
     |
     |      >>> (x + y*I).as_real_imag()
     |      (x, y)
     |
     |      >>> from sympy.abc import z, w
     |
     |      >>> (z + w*I).as_real_imag()
     |      (re(z) - im(w), re(w) + im(z))
     |
     |  fdiff(self, argindex=1)
     |      Returns the first derivative of the function.
     |
     |  period(self, symbol=None)
     |
     |  ----------------------------------------------------------------------
     |  Class methods defined here:
     |
     |  eval(arg) from sympy.core.function.FunctionClass
     |      Returns a canonical form of cls applied to arguments args.
     |
     |      The eval() method is called when the class cls is about to be
     |      instantiated and it should return either some simplified instance
     |      (possible of some other class), or if the class cls should be
     |      unmodified, return None.
     |
     |      Examples of eval() for the function "sign"
     |      ---------------------------------------------
     |
     |      .. code-block:: python
     |
     |          @classmethod
     |          def eval(cls, arg):
     |              if arg is S.NaN:
     |                  return S.NaN
     |              if arg.is_zero: return S.Zero
     |              if arg.is_positive: return S.One
     |              if arg.is_negative: return S.NegativeOne
     |              if isinstance(arg, Mul):
     |                  coeff, terms = arg.as_coeff_Mul(rational=True)
     |                  if coeff is not S.One:
     |                      return cls(coeff) * cls(terms)
     |
     |  ----------------------------------------------------------------------
     |  Static methods defined here:
     |
     |  taylor_term(n, x, *previous_terms)
     |
     |  ----------------------------------------------------------------------
     |  Data descriptors defined here:
     |
     |  __sympy__
     |
     |  ----------------------------------------------------------------------
     |  Data and other attributes defined here:
     |
     |  default_assumptions = {}
     |
     |  ----------------------------------------------------------------------
     |  Data and other attributes inherited from TrigonometricFunction:
     |
     |  unbranched = True
     |
     |  ----------------------------------------------------------------------
     |  Methods inherited from sympy.core.function.Function:
     |
     |  __new__(cls, *args, **options)
     |
     |  as_base_exp(self)
     |      Returns the method as the 2-tuple (base, exponent).
     |
     |  ----------------------------------------------------------------------
     |  Class methods inherited from sympy.core.function.Function:
     |
     |  class_key() from sympy.core.function.FunctionClass
     |      Nice order of classes.
     |
     |  ----------------------------------------------------------------------
     |  Data descriptors inherited from sympy.core.function.Function:
     |
     |  is_commutative
     |      Returns whether the function is commutative.
     |
     |  ----------------------------------------------------------------------
     |  Data descriptors inherited from sympy.core.function.Application:
     |
     |  __dict__
     |      dictionary for instance variables (if defined)
     |
     |  __weakref__
     |      list of weak references to the object (if defined)
     |
     |  func
     |      The top-level function in an expression.
     |
     |      The following should hold for all objects::
     |
     |          >> x == x.func(*x.args)
     |
     |      Examples
     |      ========
     |
     |      >>> from sympy.abc import x
     |      >>> a = 2*x
     |      >>> a.func
     |      <class 'sympy.core.mul.Mul'>
     |      >>> a.args
     |      (2, x)
     |      >>> a.func(*a.args)
     |      2*x
     |      >>> a == a.func(*a.args)
     |      True
     |
     |  ----------------------------------------------------------------------
     |  Data and other attributes inherited from sympy.core.function.Application:
     |
     |  is_Function = True
     |
     |  ----------------------------------------------------------------------
     |  Methods inherited from sympy.core.expr.Expr:
     |
     |  __abs__(self)
     |
     |  __add__(self, other)
     |
     |  __complex__(self)
     |
     |  __div__(self, other)
     |
     |  __divmod__(self, other)
     |
     |  __eq__(self, other)
     |      Return a boolean indicating whether a == b on the basis of
     |      their symbolic trees.
     |
     |      This is the same as a.compare(b) == 0 but faster.
     |
     |      Notes
     |      =====
     |
     |      If a class that overrides __eq__() needs to retain the
     |      implementation of __hash__() from a parent class, the
     |      interpreter must be told this explicitly by setting __hash__ =
     |      <ParentClass>.__hash__. Otherwise the inheritance of __hash__()
     |      will be blocked, just as if __hash__ had been explicitly set to
     |      None.
     |
     |      References
     |      ==========
     |
     |      from http://docs.python.org/dev/reference/datamodel.html#object.__hash__
     |
     |  __float__(self)
     |
     |  __floordiv__(self, other)
     |
     |  __ge__(self, other)
     |      Return self>=value.
     |
     |  __gt__(self, other)
     |      Return self>value.
     |
     |  __hash__(self)
     |      Return hash(self).
     |
     |  __int__(self)
     |
     |  __le__(self, other)
     |      Return self<=value.
     |
     |  __long__ = __int__(self)
     |
     |  __lt__(self, other)
     |      Return self<value.
     |
     |  __mod__(self, other)
     |
     |  __mul__(self, other)
     |
     |  __neg__(self)
     |
     |  __pos__(self)
     |
     |  __pow__(self, other, mod=None)
     |
     |  __radd__(self, other)
     |
     |  __rdiv__(self, other)
     |
     |  __rdivmod__(self, other)
     |
     |  __rfloordiv__(self, other)
     |
     |  __rmod__(self, other)
     |
     |  __rmul__(self, other)
     |
     |  __round__ = round(self, n=None)
     |
     |  __rpow__(self, other)
     |
     |  __rsub__(self, other)
     |
     |  __rtruediv__ = __rdiv__(self, other)
     |
     |  __sub__(self, other)
     |
     |  __truediv__ = __div__(self, other)
     |
     |  __trunc__(self)
     |
     |  adjoint(self)
     |
     |  apart(self, x=None, **args)
     |      See the apart function in sympy.polys
     |
     |  args_cnc(self, cset=False, warn=True, split_1=True)
     |      Return [commutative factors, non-commutative factors] of self.
     |
     |      self is treated as a Mul and the ordering of the factors is maintained.
     |      If ``cset`` is True the commutative factors will be returned in a set.
     |      If there were repeated factors (as may happen with an unevaluated Mul)
     |      then an error will be raised unless it is explicitly suppressed by
     |      setting ``warn`` to False.
     |
     |      Note: -1 is always separated from a Number unless split_1 is False.
     |
     |      >>> from sympy import symbols, oo
     |      >>> A, B = symbols('A B', commutative=0)
     |      >>> x, y = symbols('x y')
     |      >>> (-2*x*y).args_cnc()
     |      [[-1, 2, x, y], []]
     |      >>> (-2.5*x).args_cnc()
     |      [[-1, 2.5, x], []]
     |      >>> (-2*x*A*B*y).args_cnc()
     |      [[-1, 2, x, y], [A, B]]
     |      >>> (-2*x*A*B*y).args_cnc(split_1=False)
     |      [[-2, x, y], [A, B]]
     |      >>> (-2*x*y).args_cnc(cset=True)
     |      [{-1, 2, x, y}, []]
     |
     |      The arg is always treated as a Mul:
     |
     |      >>> (-2 + x + A).args_cnc()
     |      [[], [x - 2 + A]]
     |      >>> (-oo).args_cnc() # -oo is a singleton
     |      [[-1, oo], []]
     |
     |  as_coeff_Add(self, rational=False)
     |      Efficiently extract the coefficient of a summation.
     |
     |  as_coeff_Mul(self, rational=False)
     |      Efficiently extract the coefficient of a product.
     |
     |  as_coeff_add(self, *deps)
     |      Return the tuple (c, args) where self is written as an Add, ``a``.
     |
     |      c should be a Rational added to any terms of the Add that are
     |      independent of deps.
     |
     |      args should be a tuple of all other terms of ``a``; args is empty
     |      if self is a Number or if self is independent of deps (when given).
     |
     |      This should be used when you don't know if self is an Add or not but
     |      you want to treat self as an Add or if you want to process the
     |      individual arguments of the tail of self as an Add.
     |
     |      - if you know self is an Add and want only the head, use self.args[0];
     |      - if you don't want to process the arguments of the tail but need the
     |        tail then use self.as_two_terms() which gives the head and tail.
     |      - if you want to split self into an independent and dependent parts
     |        use ``self.as_independent(*deps)``
     |
     |      >>> from sympy import S
     |      >>> from sympy.abc import x, y
     |      >>> (S(3)).as_coeff_add()
     |      (3, ())
     |      >>> (3 + x).as_coeff_add()
     |      (3, (x,))
     |      >>> (3 + x + y).as_coeff_add(x)
     |      (y + 3, (x,))
     |      >>> (3 + y).as_coeff_add(x)
     |      (y + 3, ())
     |
     |  as_coeff_exponent(self, x)
     |      ``c*x**e -> c,e`` where x can be any symbolic expression.
     |
     |  as_coeff_mul(self, *deps, **kwargs)
     |      Return the tuple (c, args) where self is written as a Mul, ``m``.
     |
     |      c should be a Rational multiplied by any factors of the Mul that are
     |      independent of deps.
     |
     |      args should be a tuple of all other factors of m; args is empty
     |      if self is a Number or if self is independent of deps (when given).
     |
     |      This should be used when you don't know if self is a Mul or not but
     |      you want to treat self as a Mul or if you want to process the
     |      individual arguments of the tail of self as a Mul.
     |
     |      - if you know self is a Mul and want only the head, use self.args[0];
     |      - if you don't want to process the arguments of the tail but need the
     |        tail then use self.as_two_terms() which gives the head and tail;
     |      - if you want to split self into an independent and dependent parts
     |        use ``self.as_independent(*deps)``
     |
     |      >>> from sympy import S
     |      >>> from sympy.abc import x, y
     |      >>> (S(3)).as_coeff_mul()
     |      (3, ())
     |      >>> (3*x*y).as_coeff_mul()
     |      (3, (x, y))
     |      >>> (3*x*y).as_coeff_mul(x)
     |      (3*y, (x,))
     |      >>> (3*y).as_coeff_mul(x)
     |      (3*y, ())
     |
     |  as_coefficient(self, expr)
     |      Extracts symbolic coefficient at the given expression. In
     |      other words, this functions separates 'self' into the product
     |      of 'expr' and 'expr'-free coefficient. If such separation
     |      is not possible it will return None.
     |
     |      Examples
     |      ========
     |
     |      >>> from sympy import E, pi, sin, I, Poly
     |      >>> from sympy.abc import x
     |
     |      >>> E.as_coefficient(E)
     |      1
     |      >>> (2*E).as_coefficient(E)
     |      2
     |      >>> (2*sin(E)*E).as_coefficient(E)
     |
     |      Two terms have E in them so a sum is returned. (If one were
     |      desiring the coefficient of the term exactly matching E then
     |      the constant from the returned expression could be selected.
     |      Or, for greater precision, a method of Poly can be used to
     |      indicate the desired term from which the coefficient is
     |      desired.)
     |
     |      >>> (2*E + x*E).as_coefficient(E)
     |      x + 2
     |      >>> _.args[0]  # just want the exact match
     |      2
     |      >>> p = Poly(2*E + x*E); p
     |      Poly(x*E + 2*E, x, E, domain='ZZ')
     |      >>> p.coeff_monomial(E)
     |      2
     |      >>> p.nth(0, 1)
     |      2
     |
     |      Since the following cannot be written as a product containing
     |      E as a factor, None is returned. (If the coefficient ``2*x`` is
     |      desired then the ``coeff`` method should be used.)
     |
     |      >>> (2*E*x + x).as_coefficient(E)
     |      >>> (2*E*x + x).coeff(E)
     |      2*x
     |
     |      >>> (E*(x + 1) + x).as_coefficient(E)
     |
     |      >>> (2*pi*I).as_coefficient(pi*I)
     |      2
     |      >>> (2*I).as_coefficient(pi*I)
     |
     |      See Also
     |      ========
     |
     |      coeff: return sum of terms have a given factor
     |      as_coeff_Add: separate the additive constant from an expression
     |      as_coeff_Mul: separate the multiplicative constant from an expression
     |      as_independent: separate x-dependent terms/factors from others
     |      sympy.polys.polytools.Poly.coeff_monomial: efficiently find the single coefficient of a monomial in Poly
     |      sympy.polys.polytools.Poly.nth: like coeff_monomial but powers of monomial terms are used
     |
     |  as_coefficients_dict(self)
     |      Return a dictionary mapping terms to their Rational coefficient.
     |      Since the dictionary is a defaultdict, inquiries about terms which
     |      were not present will return a coefficient of 0. If an expression is
     |      not an Add it is considered to have a single term.
     |
     |      Examples
     |      ========
     |
     |      >>> from sympy.abc import a, x
     |      >>> (3*x + a*x + 4).as_coefficients_dict()
     |      {1: 4, x: 3, a*x: 1}
     |      >>> _[a]
     |      0
     |      >>> (3*a*x).as_coefficients_dict()
     |      {a*x: 3}
     |
     |  as_content_primitive(self, radical=False, clear=True)
     |      This method should recursively remove a Rational from all arguments
     |      and return that (content) and the new self (primitive). The content
     |      should always be positive and ``Mul(*foo.as_content_primitive()) == foo``.
     |      The primitive need not be in canonical form and should try to preserve
     |      the underlying structure if possible (i.e. expand_mul should not be
     |      applied to self).
     |
     |      Examples
     |      ========
     |
     |      >>> from sympy import sqrt
     |      >>> from sympy.abc import x, y, z
     |
     |      >>> eq = 2 + 2*x + 2*y*(3 + 3*y)
     |
     |      The as_content_primitive function is recursive and retains structure:
     |
     |      >>> eq.as_content_primitive()
     |      (2, x + 3*y*(y + 1) + 1)
     |
     |      Integer powers will have Rationals extracted from the base:
     |
     |      >>> ((2 + 6*x)**2).as_content_primitive()
     |      (4, (3*x + 1)**2)
     |      >>> ((2 + 6*x)**(2*y)).as_content_primitive()
     |      (1, (2*(3*x + 1))**(2*y))
     |
     |      Terms may end up joining once their as_content_primitives are added:
     |
     |      >>> ((5*(x*(1 + y)) + 2*x*(3 + 3*y))).as_content_primitive()
     |      (11, x*(y + 1))
     |      >>> ((3*(x*(1 + y)) + 2*x*(3 + 3*y))).as_content_primitive()
     |      (9, x*(y + 1))
     |      >>> ((3*(z*(1 + y)) + 2.0*x*(3 + 3*y))).as_content_primitive()
     |      (1, 6.0*x*(y + 1) + 3*z*(y + 1))
     |      >>> ((5*(x*(1 + y)) + 2*x*(3 + 3*y))**2).as_content_primitive()
     |      (121, x**2*(y + 1)**2)
     |      >>> ((x*(1 + y) + 0.4*x*(3 + 3*y))**2).as_content_primitive()
     |      (1, 4.84*x**2*(y + 1)**2)
     |
     |      Radical content can also be factored out of the primitive:
     |
     |      >>> (2*sqrt(2) + 4*sqrt(10)).as_content_primitive(radical=True)
     |      (2, sqrt(2)*(1 + 2*sqrt(5)))
     |
     |      If clear=False (default is True) then content will not be removed
     |      from an Add if it can be distributed to leave one or more
     |      terms with integer coefficients.
     |
     |      >>> (x/2 + y).as_content_primitive()
     |      (1/2, x + 2*y)
     |      >>> (x/2 + y).as_content_primitive(clear=False)
     |      (1, x/2 + y)
     |
     |  as_expr(self, *gens)
     |      Convert a polynomial to a SymPy expression.
     |
     |      Examples
     |      ========
     |
     |      >>> from sympy import sin
     |      >>> from sympy.abc import x, y
     |
     |      >>> f = (x**2 + x*y).as_poly(x, y)
     |      >>> f.as_expr()
     |      x**2 + x*y
     |
     |      >>> sin(x).as_expr()
     |      sin(x)
     |
     |  as_independent(self, *deps, **hint)
     |      A mostly naive separation of a Mul or Add into arguments that are not
     |      are dependent on deps. To obtain as complete a separation of variables
     |      as possible, use a separation method first, e.g.:
     |
     |      * separatevars() to change Mul, Add and Pow (including exp) into Mul
     |      * .expand(mul=True) to change Add or Mul into Add
     |      * .expand(log=True) to change log expr into an Add
     |
     |      The only non-naive thing that is done here is to respect noncommutative
     |      ordering of variables and to always return (0, 0) for `self` of zero
     |      regardless of hints.
     |
     |      For nonzero `self`, the returned tuple (i, d) has the
     |      following interpretation:
     |
     |      * i will has no variable that appears in deps
     |      * d will either have terms that contain variables that are in deps, or
     |        be equal to 0 (when self is an Add) or 1 (when self is a Mul)
     |      * if self is an Add then self = i + d
     |      * if self is a Mul then self = i*d
     |      * otherwise (self, S.One) or (S.One, self) is returned.
     |
     |      To force the expression to be treated as an Add, use the hint as_Add=True
     |
     |      Examples
     |      ========
     |
     |      -- self is an Add
     |
     |      >>> from sympy import sin, cos, exp
     |      >>> from sympy.abc import x, y, z
     |
     |      >>> (x + x*y).as_independent(x)
     |      (0, x*y + x)
     |      >>> (x + x*y).as_independent(y)
     |      (x, x*y)
     |      >>> (2*x*sin(x) + y + x + z).as_independent(x)
     |      (y + z, 2*x*sin(x) + x)
     |      >>> (2*x*sin(x) + y + x + z).as_independent(x, y)
     |      (z, 2*x*sin(x) + x + y)
     |
     |      -- self is a Mul
     |
     |      >>> (x*sin(x)*cos(y)).as_independent(x)
     |      (cos(y), x*sin(x))
     |
     |      non-commutative terms cannot always be separated out when self is a Mul
     |
     |      >>> from sympy import symbols
     |      >>> n1, n2, n3 = symbols('n1 n2 n3', commutative=False)
     |      >>> (n1 + n1*n2).as_independent(n2)
     |      (n1, n1*n2)
     |      >>> (n2*n1 + n1*n2).as_independent(n2)
     |      (0, n1*n2 + n2*n1)
     |      >>> (n1*n2*n3).as_independent(n1)
     |      (1, n1*n2*n3)
     |      >>> (n1*n2*n3).as_independent(n2)
     |      (n1, n2*n3)
     |      >>> ((x-n1)*(x-y)).as_independent(x)
     |      (1, (x - y)*(x - n1))
     |
     |      -- self is anything else:
     |
     |      >>> (sin(x)).as_independent(x)
     |      (1, sin(x))
     |      >>> (sin(x)).as_independent(y)
     |      (sin(x), 1)
     |      >>> exp(x+y).as_independent(x)
     |      (1, exp(x + y))
     |
     |      -- force self to be treated as an Add:
     |
     |      >>> (3*x).as_independent(x, as_Add=True)
     |      (0, 3*x)
     |
     |      -- force self to be treated as a Mul:
     |
     |      >>> (3+x).as_independent(x, as_Add=False)
     |      (1, x + 3)
     |      >>> (-3+x).as_independent(x, as_Add=False)
     |      (1, x - 3)
     |
     |      Note how the below differs from the above in making the
     |      constant on the dep term positive.
     |
     |      >>> (y*(-3+x)).as_independent(x)
     |      (y, x - 3)
     |
     |      -- use .as_independent() for true independence testing instead
     |         of .has(). The former considers only symbols in the free
     |         symbols while the latter considers all symbols
     |
     |      >>> from sympy import Integral
     |      >>> I = Integral(x, (x, 1, 2))
     |      >>> I.has(x)
     |      True
     |      >>> x in I.free_symbols
     |      False
     |      >>> I.as_independent(x) == (I, 1)
     |      True
     |      >>> (I + x).as_independent(x) == (I, x)
     |      True
     |
     |      Note: when trying to get independent terms, a separation method
     |      might need to be used first. In this case, it is important to keep
     |      track of what you send to this routine so you know how to interpret
     |      the returned values
     |
     |      >>> from sympy import separatevars, log
     |      >>> separatevars(exp(x+y)).as_independent(x)
     |      (exp(y), exp(x))
     |      >>> (x + x*y).as_independent(y)
     |      (x, x*y)
     |      >>> separatevars(x + x*y).as_independent(y)
     |      (x, y + 1)
     |      >>> (x*(1 + y)).as_independent(y)
     |      (x, y + 1)
     |      >>> (x*(1 + y)).expand(mul=True).as_independent(y)
     |      (x, x*y)
     |      >>> a, b=symbols('a b', positive=True)
     |      >>> (log(a*b).expand(log=True)).as_independent(b)
     |      (log(a), log(b))
     |
     |      See Also
     |      ========
     |      .separatevars(), .expand(log=True), sympy.core.add.Add.as_two_terms(),
     |      sympy.core.mul.Mul.as_two_terms(), .as_coeff_add(), .as_coeff_mul()
     |
     |  as_leading_term(self, *symbols)
     |      Returns the leading (nonzero) term of the series expansion of self.
     |
     |      The _eval_as_leading_term routines are used to do this, and they must
     |      always return a non-zero value.
     |
     |      Examples
     |      ========
     |
     |      >>> from sympy.abc import x
     |      >>> (1 + x + x**2).as_leading_term(x)
     |      1
     |      >>> (1/x**2 + x + x**2).as_leading_term(x)
     |      x**(-2)
     |
     |  as_numer_denom(self)
     |      expression -> a/b -> a, b
     |
     |      This is just a stub that should be defined by
     |      an object's class methods to get anything else.
     |
     |      See Also
     |      ========
     |      normal: return a/b instead of a, b
     |
     |  as_ordered_factors(self, order=None)
     |      Return list of ordered factors (if Mul) else [self].
     |
     |  as_ordered_terms(self, order=None, data=False)
     |      Transform an expression to an ordered list of terms.
     |
     |      Examples
     |      ========
     |
     |      >>> from sympy import sin, cos
     |      >>> from sympy.abc import x
     |
     |      >>> (sin(x)**2*cos(x) + sin(x)**2 + 1).as_ordered_terms()
     |      [sin(x)**2*cos(x), sin(x)**2, 1]
     |
     |  as_powers_dict(self)
     |      Return self as a dictionary of factors with each factor being
     |      treated as a power. The keys are the bases of the factors and the
     |      values, the corresponding exponents. The resulting dictionary should
     |      be used with caution if the expression is a Mul and contains non-
     |      commutative factors since the order that they appeared will be lost in
     |      the dictionary.
     |
     |      See Also
     |      ========
     |      as_ordered_factors: An alternative for noncommutative applications,
     |                          returning an ordered list of factors.
     |      args_cnc: Similar to as_ordered_factors, but guarantees separation
     |                of commutative and noncommutative factors.
     |
     |  as_terms(self)
     |      Transform an expression to a list of terms.
     |
     |  aseries(self, x=None, n=6, bound=0, hir=False)
     |      Asymptotic Series expansion of self.
     |      This is equivalent to ``self.series(x, oo, n)``.
     |
     |      Parameters
     |      ==========
     |
     |      self : Expression
     |             The expression whose series is to be expanded.
     |
     |      x : Symbol
     |          It is the variable of the expression to be calculated.
     |
     |      n : Value
     |          The number of terms upto which the series is to be expanded.
     |
     |      hir : Boolean
     |            Set this parameter to be True to produce hierarchical series.
     |            It stops the recursion at an early level and may provide nicer
     |            and more useful results.
     |
     |      bound : Value, Integer
     |              Use the ``bound`` parameter to give limit on rewriting
     |              coefficients in its normalised form.
     |
     |      Examples
     |      ========
     |
     |      >>> from sympy import sin, exp
     |      >>> from sympy.abc import x, y
     |
     |      >>> e = sin(1/x + exp(-x)) - sin(1/x)
     |
     |      >>> e.aseries(x)
     |      (1/(24*x**4) - 1/(2*x**2) + 1 + O(x**(-6), (x, oo)))*exp(-x)
     |
     |      >>> e.aseries(x, n=3, hir=True)
     |      -exp(-2*x)*sin(1/x)/2 + exp(-x)*cos(1/x) + O(exp(-3*x), (x, oo))
     |
     |      >>> e = exp(exp(x)/(1 - 1/x))
     |
     |      >>> e.aseries(x)
     |      exp(exp(x)/(1 - 1/x))
     |
     |      >>> e.aseries(x, bound=3)
     |      exp(exp(x)/x**2)*exp(exp(x)/x)*exp(-exp(x) + exp(x)/(1 - 1/x) - exp(x)/x - exp(x)/x**2)*exp(exp(x))
     |
     |      Returns
     |      =======
     |
     |      Expr
     |          Asymptotic series expansion of the expression.
     |
     |      Notes
     |      =====
     |
     |      This algorithm is directly induced from the limit computational algorithm provided by Gruntz.
     |      It majorly uses the mrv and rewrite sub-routines. The overall idea of this algorithm is first
     |      to look for the most rapidly varying subexpression w of a given expression f and then expands f
     |      in a series in w. Then same thing is recursively done on the leading coefficient
     |      till we get constant coefficients.
     |
     |      If the most rapidly varying subexpression of a given expression f is f itself,
     |      the algorithm tries to find a normalised representation of the mrv set and rewrites f
     |      using this normalised representation.
     |
     |      If the expansion contains an order term, it will be either ``O(x ** (-n))`` or ``O(w ** (-n))``
     |      where ``w`` belongs to the most rapidly varying expression of ``self``.
     |
     |      References
     |      ==========
     |
     |      .. [1] A New Algorithm for Computing Asymptotic Series - Dominik Gruntz
     |      .. [2] Gruntz thesis - p90
     |      .. [3] http://en.wikipedia.org/wiki/Asymptotic_expansion
     |
     |      See Also
     |      ========
     |
     |      Expr.aseries: See the docstring of this function for complete details of this wrapper.
     |
     |  cancel(self, *gens, **args)
     |      See the cancel function in sympy.polys
     |
     |  coeff(self, x, n=1, right=False)
     |      Returns the coefficient from the term(s) containing ``x**n``. If ``n``
     |      is zero then all terms independent of ``x`` will be returned.
     |
     |      When ``x`` is noncommutative, the coefficient to the left (default) or
     |      right of ``x`` can be returned. The keyword 'right' is ignored when
     |      ``x`` is commutative.
     |
     |      See Also
     |      ========
     |
     |      as_coefficient: separate the expression into a coefficient and factor
     |      as_coeff_Add: separate the additive constant from an expression
     |      as_coeff_Mul: separate the multiplicative constant from an expression
     |      as_independent: separate x-dependent terms/factors from others
     |      sympy.polys.polytools.Poly.coeff_monomial: efficiently find the single coefficient of a monomial in Poly
     |      sympy.polys.polytools.Poly.nth: like coeff_monomial but powers of monomial terms are used
     |
     |      Examples
     |      ========
     |
     |      >>> from sympy import symbols
     |      >>> from sympy.abc import x, y, z
     |
     |      You can select terms that have an explicit negative in front of them:
     |
     |      >>> (-x + 2*y).coeff(-1)
     |      x
     |      >>> (x - 2*y).coeff(-1)
     |      2*y
     |
     |      You can select terms with no Rational coefficient:
     |
     |      >>> (x + 2*y).coeff(1)
     |      x
     |      >>> (3 + 2*x + 4*x**2).coeff(1)
     |      0
     |
     |      You can select terms independent of x by making n=0; in this case
     |      expr.as_independent(x)[0] is returned (and 0 will be returned instead
     |      of None):
     |
     |      >>> (3 + 2*x + 4*x**2).coeff(x, 0)
     |      3
     |      >>> eq = ((x + 1)**3).expand() + 1
     |      >>> eq
     |      x**3 + 3*x**2 + 3*x + 2
     |      >>> [eq.coeff(x, i) for i in reversed(range(4))]
     |      [1, 3, 3, 2]
     |      >>> eq -= 2
     |      >>> [eq.coeff(x, i) for i in reversed(range(4))]
     |      [1, 3, 3, 0]
     |
     |      You can select terms that have a numerical term in front of them:
     |
     |      >>> (-x - 2*y).coeff(2)
     |      -y
     |      >>> from sympy import sqrt
     |      >>> (x + sqrt(2)*x).coeff(sqrt(2))
     |      x
     |
     |      The matching is exact:
     |
     |      >>> (3 + 2*x + 4*x**2).coeff(x)
     |      2
     |      >>> (3 + 2*x + 4*x**2).coeff(x**2)
     |      4
     |      >>> (3 + 2*x + 4*x**2).coeff(x**3)
     |      0
     |      >>> (z*(x + y)**2).coeff((x + y)**2)
     |      z
     |      >>> (z*(x + y)**2).coeff(x + y)
     |      0
     |
     |      In addition, no factoring is done, so 1 + z*(1 + y) is not obtained
     |      from the following:
     |
     |      >>> (x + z*(x + x*y)).coeff(x)
     |      1
     |
     |      If such factoring is desired, factor_terms can be used first:
     |
     |      >>> from sympy import factor_terms
     |      >>> factor_terms(x + z*(x + x*y)).coeff(x)
     |      z*(y + 1) + 1
     |
     |      >>> n, m, o = symbols('n m o', commutative=False)
     |      >>> n.coeff(n)
     |      1
     |      >>> (3*n).coeff(n)
     |      3
     |      >>> (n*m + m*n*m).coeff(n) # = (1 + m)*n*m
     |      1 + m
     |      >>> (n*m + m*n*m).coeff(n, right=True) # = (1 + m)*n*m
     |      m
     |
     |      If there is more than one possible coefficient 0 is returned:
     |
     |      >>> (n*m + m*n).coeff(n)
     |      0
     |
     |      If there is only one possible coefficient, it is returned:
     |
     |      >>> (n*m + x*m*n).coeff(m*n)
     |      x
     |      >>> (n*m + x*m*n).coeff(m*n, right=1)
     |      1
     |
     |  collect(self, syms, func=None, evaluate=True, exact=False, distribute_order_term=True)
     |      See the collect function in sympy.simplify
     |
     |  combsimp(self)
     |      See the combsimp function in sympy.simplify
     |
     |  compute_leading_term(self, x, logx=None)
     |      as_leading_term is only allowed for results of .series()
     |      This is a wrapper to compute a series first.
     |
     |  conjugate(self)
     |
     |  could_extract_minus_sign(self)
     |      Return True if self is not in a canonical form with respect
     |      to its sign.
     |
     |      For most expressions, e, there will be a difference in e and -e.
     |      When there is, True will be returned for one and False for the
     |      other; False will be returned if there is no difference.
     |
     |      Examples
     |      ========
     |
     |      >>> from sympy.abc import x, y
     |      >>> e = x - y
     |      >>> {i.could_extract_minus_sign() for i in (e, -e)}
     |      {False, True}
     |
     |  count_ops(self, visual=None)
     |      wrapper for count_ops that returns the operation count.
     |
     |  diff(self, *symbols, **assumptions)
     |
     |  equals(self, other, failing_expression=False)
     |      Return True if self == other, False if it doesn't, or None. If
     |      failing_expression is True then the expression which did not simplify
     |      to a 0 will be returned instead of None.
     |
     |      If ``self`` is a Number (or complex number) that is not zero, then
     |      the result is False.
     |
     |      If ``self`` is a number and has not evaluated to zero, evalf will be
     |      used to test whether the expression evaluates to zero. If it does so
     |      and the result has significance (i.e. the precision is either -1, for
     |      a Rational result, or is greater than 1) then the evalf value will be
     |      used to return True or False.
     |
     |  expand(self, deep=True, modulus=None, power_base=True, power_exp=True, mul=True, log=True, multinomial=True, basic=True, **hints)
     |      Expand an expression using hints.
     |
     |      See the docstring of the expand() function in sympy.core.function for
     |      more information.
     |
     |  extract_additively(self, c)
     |      Return self - c if it's possible to subtract c from self and
     |      make all matching coefficients move towards zero, else return None.
     |
     |      Examples
     |      ========
     |
     |      >>> from sympy.abc import x, y
     |      >>> e = 2*x + 3
     |      >>> e.extract_additively(x + 1)
     |      x + 2
     |      >>> e.extract_additively(3*x)
     |      >>> e.extract_additively(4)
     |      >>> (y*(x + 1)).extract_additively(x + 1)
     |      >>> ((x + 1)*(x + 2*y + 1) + 3).extract_additively(x + 1)
     |      (x + 1)*(x + 2*y) + 3
     |
     |      Sometimes auto-expansion will return a less simplified result
     |      than desired; gcd_terms might be used in such cases:
     |
     |      >>> from sympy import gcd_terms
     |      >>> (4*x*(y + 1) + y).extract_additively(x)
     |      4*x*(y + 1) + x*(4*y + 3) - x*(4*y + 4) + y
     |      >>> gcd_terms(_)
     |      x*(4*y + 3) + y
     |
     |      See Also
     |      ========
     |      extract_multiplicatively
     |      coeff
     |      as_coefficient
     |
     |  extract_branch_factor(self, allow_half=False)
     |      Try to write self as ``exp_polar(2*pi*I*n)*z`` in a nice way.
     |      Return (z, n).
     |
     |      >>> from sympy import exp_polar, I, pi
     |      >>> from sympy.abc import x, y
     |      >>> exp_polar(I*pi).extract_branch_factor()
     |      (exp_polar(I*pi), 0)
     |      >>> exp_polar(2*I*pi).extract_branch_factor()
     |      (1, 1)
     |      >>> exp_polar(-pi*I).extract_branch_factor()
     |      (exp_polar(I*pi), -1)
     |      >>> exp_polar(3*pi*I + x).extract_branch_factor()
     |      (exp_polar(x + I*pi), 1)
     |      >>> (y*exp_polar(-5*pi*I)*exp_polar(3*pi*I + 2*pi*x)).extract_branch_factor()
     |      (y*exp_polar(2*pi*x), -1)
     |      >>> exp_polar(-I*pi/2).extract_branch_factor()
     |      (exp_polar(-I*pi/2), 0)
     |
     |      If allow_half is True, also extract exp_polar(I*pi):
     |
     |      >>> exp_polar(I*pi).extract_branch_factor(allow_half=True)
     |      (1, 1/2)
     |      >>> exp_polar(2*I*pi).extract_branch_factor(allow_half=True)
     |      (1, 1)
     |      >>> exp_polar(3*I*pi).extract_branch_factor(allow_half=True)
     |      (1, 3/2)
     |      >>> exp_polar(-I*pi).extract_branch_factor(allow_half=True)
     |      (1, -1/2)
     |
     |  extract_multiplicatively(self, c)
     |      Return None if it's not possible to make self in the form
     |      c * something in a nice way, i.e. preserving the properties
     |      of arguments of self.
     |
     |      Examples
     |      ========
     |
     |      >>> from sympy import symbols, Rational
     |
     |      >>> x, y = symbols('x,y', real=True)
     |
     |      >>> ((x*y)**3).extract_multiplicatively(x**2 * y)
     |      x*y**2
     |
     |      >>> ((x*y)**3).extract_multiplicatively(x**4 * y)
     |
     |      >>> (2*x).extract_multiplicatively(2)
     |      x
     |
     |      >>> (2*x).extract_multiplicatively(3)
     |
     |      >>> (Rational(1, 2)*x).extract_multiplicatively(3)
     |      x/6
     |
     |  factor(self, *gens, **args)
     |      See the factor() function in sympy.polys.polytools
     |
     |  fourier_series(self, limits=None)
     |      Compute fourier sine/cosine series of self.
     |
     |      See the docstring of the :func:`fourier_series` in sympy.series.fourier
     |      for more information.
     |
     |  fps(self, x=None, x0=0, dir=1, hyper=True, order=4, rational=True, full=False)
     |      Compute formal power power series of self.
     |
     |      See the docstring of the :func:`fps` function in sympy.series.formal for
     |      more information.
     |
     |  gammasimp(self)
     |      See the gammasimp function in sympy.simplify
     |
     |  getO(self)
     |      Returns the additive O(..) symbol if there is one, else None.
     |
     |  getn(self)
     |      Returns the order of the expression.
     |
     |      The order is determined either from the O(...) term. If there
     |      is no O(...) term, it returns None.
     |
     |      Examples
     |      ========
     |
     |      >>> from sympy import O
     |      >>> from sympy.abc import x
     |      >>> (1 + x + O(x**2)).getn()
     |      2
     |      >>> (1 + x).getn()
     |
     |  integrate(self, *args, **kwargs)
     |      See the integrate function in sympy.integrals
     |
     |  invert(self, g, *gens, **args)
     |      Return the multiplicative inverse of ``self`` mod ``g``
     |      where ``self`` (and ``g``) may be symbolic expressions).
     |
     |      See Also
     |      ========
     |      sympy.core.numbers.mod_inverse, sympy.polys.polytools.invert
     |
     |  is_algebraic_expr(self, *syms)
     |      This tests whether a given expression is algebraic or not, in the
     |      given symbols, syms. When syms is not given, all free symbols
     |      will be used. The rational function does not have to be in expanded
     |      or in any kind of canonical form.
     |
     |      This function returns False for expressions that are "algebraic
     |      expressions" with symbolic exponents. This is a simple extension to the
     |      is_rational_function, including rational exponentiation.
     |
     |      Examples
     |      ========
     |
     |      >>> from sympy import Symbol, sqrt
     |      >>> x = Symbol('x', real=True)
     |      >>> sqrt(1 + x).is_rational_function()
     |      False
     |      >>> sqrt(1 + x).is_algebraic_expr()
     |      True
     |
     |      This function does not attempt any nontrivial simplifications that may
     |      result in an expression that does not appear to be an algebraic
     |      expression to become one.
     |
     |      >>> from sympy import exp, factor
     |      >>> a = sqrt(exp(x)**2 + 2*exp(x) + 1)/(exp(x) + 1)
     |      >>> a.is_algebraic_expr(x)
     |      False
     |      >>> factor(a).is_algebraic_expr()
     |      True
     |
     |      See Also
     |      ========
     |      is_rational_function()
     |
     |      References
     |      ==========
     |
     |      - https://en.wikipedia.org/wiki/Algebraic_expression
     |
     |  is_constant(self, *wrt, **flags)
     |      Return True if self is constant, False if not, or None if
     |      the constancy could not be determined conclusively.
     |
     |      If an expression has no free symbols then it is a constant. If
     |      there are free symbols it is possible that the expression is a
     |      constant, perhaps (but not necessarily) zero. To test such
     |      expressions, a few strategies are tried:
     |
     |      1) numerical evaluation at two random points. If two such evaluations
     |      give two different values and the values have a precision greater than
     |      1 then self is not constant. If the evaluations agree or could not be
     |      obtained with any precision, no decision is made. The numerical testing
     |      is done only if ``wrt`` is different than the free symbols.
     |
     |      2) differentiation with respect to variables in 'wrt' (or all free
     |      symbols if omitted) to see if the expression is constant or not. This
     |      will not always lead to an expression that is zero even though an
     |      expression is constant (see added test in test_expr.py). If
     |      all derivatives are zero then self is constant with respect to the
     |      given symbols.
     |
     |      3) finding out zeros of denominator expression with free_symbols.
     |      It won't be constant if there are zeros. It gives more negative
     |      answers for expression that are not constant.
     |
     |      If neither evaluation nor differentiation can prove the expression is
     |      constant, None is returned unless two numerical values happened to be
     |      the same and the flag ``failing_number`` is True -- in that case the
     |      numerical value will be returned.
     |
     |      If flag simplify=False is passed, self will not be simplified;
     |      the default is True since self should be simplified before testing.
     |
     |      Examples
     |      ========
     |
     |      >>> from sympy import cos, sin, Sum, S, pi
     |      >>> from sympy.abc import a, n, x, y
     |      >>> x.is_constant()
     |      False
     |      >>> S(2).is_constant()
     |      True
     |      >>> Sum(x, (x, 1, 10)).is_constant()
     |      True
     |      >>> Sum(x, (x, 1, n)).is_constant()
     |      False
     |      >>> Sum(x, (x, 1, n)).is_constant(y)
     |      True
     |      >>> Sum(x, (x, 1, n)).is_constant(n)
     |      False
     |      >>> Sum(x, (x, 1, n)).is_constant(x)
     |      True
     |      >>> eq = a*cos(x)**2 + a*sin(x)**2 - a
     |      >>> eq.is_constant()
     |      True
     |      >>> eq.subs({x: pi, a: 2}) == eq.subs({x: pi, a: 3}) == 0
     |      True
     |
     |      >>> (0**x).is_constant()
     |      False
     |      >>> x.is_constant()
     |      False
     |      >>> (x**x).is_constant()
     |      False
     |      >>> one = cos(x)**2 + sin(x)**2
     |      >>> one.is_constant()
     |      True
     |      >>> ((one - 1)**(x + 1)).is_constant() in (True, False) # could be 0 or 1
     |      True
     |
     |  is_polynomial(self, *syms)
     |      Return True if self is a polynomial in syms and False otherwise.
     |
     |      This checks if self is an exact polynomial in syms.  This function
     |      returns False for expressions that are "polynomials" with symbolic
     |      exponents.  Thus, you should be able to apply polynomial algorithms to
     |      expressions for which this returns True, and Poly(expr, \*syms) should
     |      work if and only if expr.is_polynomial(\*syms) returns True. The
     |      polynomial does not have to be in expanded form.  If no symbols are
     |      given, all free symbols in the expression will be used.
     |
     |      This is not part of the assumptions system.  You cannot do
     |      Symbol('z', polynomial=True).
     |
     |      Examples
     |      ========
     |
     |      >>> from sympy import Symbol
     |      >>> x = Symbol('x')
     |      >>> ((x**2 + 1)**4).is_polynomial(x)
     |      True
     |      >>> ((x**2 + 1)**4).is_polynomial()
     |      True
     |      >>> (2**x + 1).is_polynomial(x)
     |      False
     |
     |
     |      >>> n = Symbol('n', nonnegative=True, integer=True)
     |      >>> (x**n + 1).is_polynomial(x)
     |      False
     |
     |      This function does not attempt any nontrivial simplifications that may
     |      result in an expression that does not appear to be a polynomial to
     |      become one.
     |
     |      >>> from sympy import sqrt, factor, cancel
     |      >>> y = Symbol('y', positive=True)
     |      >>> a = sqrt(y**2 + 2*y + 1)
     |      >>> a.is_polynomial(y)
     |      False
     |      >>> factor(a)
     |      y + 1
     |      >>> factor(a).is_polynomial(y)
     |      True
     |
     |      >>> b = (y**2 + 2*y + 1)/(y + 1)
     |      >>> b.is_polynomial(y)
     |      False
     |      >>> cancel(b)
     |      y + 1
     |      >>> cancel(b).is_polynomial(y)
     |      True
     |
     |      See also .is_rational_function()
     |
     |  is_rational_function(self, *syms)
     |      Test whether function is a ratio of two polynomials in the given
     |      symbols, syms. When syms is not given, all free symbols will be used.
     |      The rational function does not have to be in expanded or in any kind of
     |      canonical form.
     |
     |      This function returns False for expressions that are "rational
     |      functions" with symbolic exponents.  Thus, you should be able to call
     |      .as_numer_denom() and apply polynomial algorithms to the result for
     |      expressions for which this returns True.
     |
     |      This is not part of the assumptions system.  You cannot do
     |      Symbol('z', rational_function=True).
     |
     |      Examples
     |      ========
     |
     |      >>> from sympy import Symbol, sin
     |      >>> from sympy.abc import x, y
     |
     |      >>> (x/y).is_rational_function()
     |      True
     |
     |      >>> (x**2).is_rational_function()
     |      True
     |
     |      >>> (x/sin(y)).is_rational_function(y)
     |      False
     |
     |      >>> n = Symbol('n', integer=True)
     |      >>> (x**n + 1).is_rational_function(x)
     |      False
     |
     |      This function does not attempt any nontrivial simplifications that may
     |      result in an expression that does not appear to be a rational function
     |      to become one.
     |
     |      >>> from sympy import sqrt, factor
     |      >>> y = Symbol('y', positive=True)
     |      >>> a = sqrt(y**2 + 2*y + 1)/y
     |      >>> a.is_rational_function(y)
     |      False
     |      >>> factor(a)
     |      (y + 1)/y
     |      >>> factor(a).is_rational_function(y)
     |      True
     |
     |      See also is_algebraic_expr().
     |
     |  leadterm(self, x)
     |      Returns the leading term a*x**b as a tuple (a, b).
     |
     |      Examples
     |      ========
     |
     |      >>> from sympy.abc import x
     |      >>> (1+x+x**2).leadterm(x)
     |      (1, 0)
     |      >>> (1/x**2+x+x**2).leadterm(x)
     |      (1, -2)
     |
     |  limit(self, x, xlim, dir='+')
     |      Compute limit x->xlim.
     |
     |  lseries(self, x=None, x0=0, dir='+', logx=None)
     |      Wrapper for series yielding an iterator of the terms of the series.
     |
     |      Note: an infinite series will yield an infinite iterator. The following,
     |      for exaxmple, will never terminate. It will just keep printing terms
     |      of the sin(x) series::
     |
     |        for term in sin(x).lseries(x):
     |            print term
     |
     |      The advantage of lseries() over nseries() is that many times you are
     |      just interested in the next term in the series (i.e. the first term for
     |      example), but you don't know how many you should ask for in nseries()
     |      using the "n" parameter.
     |
     |      See also nseries().
     |
     |  normal(self)
     |
     |  nseries(self, x=None, x0=0, n=6, dir='+', logx=None)
     |      Wrapper to _eval_nseries if assumptions allow, else to series.
     |
     |      If x is given, x0 is 0, dir='+', and self has x, then _eval_nseries is
     |      called. This calculates "n" terms in the innermost expressions and
     |      then builds up the final series just by "cross-multiplying" everything
     |      out.
     |
     |      The optional ``logx`` parameter can be used to replace any log(x) in the
     |      returned series with a symbolic value to avoid evaluating log(x) at 0. A
     |      symbol to use in place of log(x) should be provided.
     |
     |      Advantage -- it's fast, because we don't have to determine how many
     |      terms we need to calculate in advance.
     |
     |      Disadvantage -- you may end up with less terms than you may have
     |      expected, but the O(x**n) term appended will always be correct and
     |      so the result, though perhaps shorter, will also be correct.
     |
     |      If any of those assumptions is not met, this is treated like a
     |      wrapper to series which will try harder to return the correct
     |      number of terms.
     |
     |      See also lseries().
     |
     |      Examples
     |      ========
     |
     |      >>> from sympy import sin, log, Symbol
     |      >>> from sympy.abc import x, y
     |      >>> sin(x).nseries(x, 0, 6)
     |      x - x**3/6 + x**5/120 + O(x**6)
     |      >>> log(x+1).nseries(x, 0, 5)
     |      x - x**2/2 + x**3/3 - x**4/4 + O(x**5)
     |
     |      Handling of the ``logx`` parameter --- in the following example the
     |      expansion fails since ``sin`` does not have an asymptotic expansion
     |      at -oo (the limit of log(x) as x approaches 0):
     |
     |      >>> e = sin(log(x))
     |      >>> e.nseries(x, 0, 6)
     |      Traceback (most recent call last):
     |      ...
     |      PoleError: ...
     |      ...
     |      >>> logx = Symbol('logx')
     |      >>> e.nseries(x, 0, 6, logx=logx)
     |      sin(logx)
     |
     |      In the following example, the expansion works but gives only an Order term
     |      unless the ``logx`` parameter is used:
     |
     |      >>> e = x**y
     |      >>> e.nseries(x, 0, 2)
     |      O(log(x)**2)
     |      >>> e.nseries(x, 0, 2, logx=logx)
     |      exp(logx*y)
     |
     |  nsimplify(self, constants=[], tolerance=None, full=False)
     |      See the nsimplify function in sympy.simplify
     |
     |  powsimp(self, *args, **kwargs)
     |      See the powsimp function in sympy.simplify
     |
     |  primitive(self)
     |      Return the positive Rational that can be extracted non-recursively
     |      from every term of self (i.e., self is treated like an Add). This is
     |      like the as_coeff_Mul() method but primitive always extracts a positive
     |      Rational (never a negative or a Float).
     |
     |      Examples
     |      ========
     |
     |      >>> from sympy.abc import x
     |      >>> (3*(x + 1)**2).primitive()
     |      (3, (x + 1)**2)
     |      >>> a = (6*x + 2); a.primitive()
     |      (2, 3*x + 1)
     |      >>> b = (x/2 + 3); b.primitive()
     |      (1/2, x + 6)
     |      >>> (a*b).primitive() == (1, a*b)
     |      True
     |
     |  radsimp(self, **kwargs)
     |      See the radsimp function in sympy.simplify
     |
     |  ratsimp(self)
     |      See the ratsimp function in sympy.simplify
     |
     |  refine(self, assumption=True)
     |      See the refine function in sympy.assumptions
     |
     |  removeO(self)
     |      Removes the additive O(..) symbol if there is one
     |
     |  round(self, n=None)
     |      Return x rounded to the given decimal place.
     |
     |      If a complex number would results, apply round to the real
     |      and imaginary components of the number.
     |
     |      Examples
     |      ========
     |
     |      >>> from sympy import pi, E, I, S, Add, Mul, Number
     |      >>> pi.round()
     |      3
     |      >>> pi.round(2)
     |      3.14
     |      >>> (2*pi + E*I).round()
     |      6 + 3*I
     |
     |      The round method has a chopping effect:
     |
     |      >>> (2*pi + I/10).round()
     |      6
     |      >>> (pi/10 + 2*I).round()
     |      2*I
     |      >>> (pi/10 + E*I).round(2)
     |      0.31 + 2.72*I
     |
     |      Notes
     |      =====
     |
     |      The Python builtin function, round, always returns a
     |      float in Python 2 while the SymPy round method (and
     |      round with a Number argument in Python 3) returns a
     |      Number.
     |
     |      >>> from sympy.core.compatibility import PY3
     |      >>> isinstance(round(S(123), -2), Number if PY3 else float)
     |      True
     |
     |      For a consistent behavior, and Python 3 rounding
     |      rules, import `round` from sympy.core.compatibility.
     |
     |      >>> from sympy.core.compatibility import round
     |      >>> isinstance(round(S(123), -2), Number)
     |      True
     |
     |  separate(self, deep=False, force=False)
     |      See the separate function in sympy.simplify
     |
     |  series(self, x=None, x0=0, n=6, dir='+', logx=None)
     |      Series expansion of "self" around ``x = x0`` yielding either terms of
     |      the series one by one (the lazy series given when n=None), else
     |      all the terms at once when n != None.
     |
     |      Returns the series expansion of "self" around the point ``x = x0``
     |      with respect to ``x`` up to ``O((x - x0)**n, x, x0)`` (default n is 6).
     |
     |      If ``x=None`` and ``self`` is univariate, the univariate symbol will
     |      be supplied, otherwise an error will be raised.
     |
     |      Parameters
     |      ==========
     |
     |      expr : Expression
     |             The expression whose series is to be expanded.
     |
     |      x : Symbol
     |          It is the variable of the expression to be calculated.
     |
     |      x0 : Value
     |           The value around which ``x`` is calculated. Can be any value
     |           from ``-oo`` to ``oo``.
     |
     |      n : Value
     |          The number of terms upto which the series is to be expanded.
     |
     |      dir : String, optional
     |            The series-expansion can be bi-directional. If ``dir="+"``,
     |            then (x->x0+). If ``dir="-", then (x->x0-). For infinite
     |            ``x0`` (``oo`` or ``-oo``), the ``dir`` argument is determined
     |            from the direction of the infinity (i.e., ``dir="-"`` for
     |            ``oo``).
     |
     |      logx : optional
     |             It is used to replace any log(x) in the returned series with a
     |             symbolic value rather than evaluating the actual value.
     |
     |      Examples
     |      ========
     |
     |      >>> from sympy import cos, exp, tan, oo, series
     |      >>> from sympy.abc import x, y
     |      >>> cos(x).series()
     |      1 - x**2/2 + x**4/24 + O(x**6)
     |      >>> cos(x).series(n=4)
     |      1 - x**2/2 + O(x**4)
     |      >>> cos(x).series(x, x0=1, n=2)
     |      cos(1) - (x - 1)*sin(1) + O((x - 1)**2, (x, 1))
     |      >>> e = cos(x + exp(y))
     |      >>> e.series(y, n=2)
     |      cos(x + 1) - y*sin(x + 1) + O(y**2)
     |      >>> e.series(x, n=2)
     |      cos(exp(y)) - x*sin(exp(y)) + O(x**2)
     |
     |      If ``n=None`` then a generator of the series terms will be returned.
     |
     |      >>> term=cos(x).series(n=None)
     |      >>> [next(term) for i in range(2)]
     |      [1, -x**2/2]
     |
     |      For ``dir=+`` (default) the series is calculated from the right and
     |      for ``dir=-`` the series from the left. For smooth functions this
     |      flag will not alter the results.
     |
     |      >>> abs(x).series(dir="+")
     |      x
     |      >>> abs(x).series(dir="-")
     |      -x
     |      >>> f = tan(x)
     |      >>> f.series(x, 2, 6, "+")
     |      tan(2) + (1 + tan(2)**2)*(x - 2) + (x - 2)**2*(tan(2)**3 + tan(2)) +
     |      (x - 2)**3*(1/3 + 4*tan(2)**2/3 + tan(2)**4) + (x - 2)**4*(tan(2)**5 +
     |      5*tan(2)**3/3 + 2*tan(2)/3) + (x - 2)**5*(2/15 + 17*tan(2)**2/15 +
     |      2*tan(2)**4 + tan(2)**6) + O((x - 2)**6, (x, 2))
     |
     |      >>> f.series(x, 2, 3, "-")
     |      tan(2) + (2 - x)*(-tan(2)**2 - 1) + (2 - x)**2*(tan(2)**3 + tan(2))
     |      + O((x - 2)**3, (x, 2))
     |
     |      Returns
     |      =======
     |
     |      Expr : Expression
     |          Series expansion of the expression about x0
     |
     |      Raises
     |      ======
     |
     |      TypeError
     |          If "n" and "x0" are infinity objects
     |
     |      PoleError
     |          If "x0" is an infinity object
     |
     |  simplify(self, **kwargs)
     |      See the simplify function in sympy.simplify
     |
     |  sort_key(self, order=None)
     |
     |  together(self, *args, **kwargs)
     |      See the together function in sympy.polys
     |
     |  transpose(self)
     |
     |  trigsimp(self, **args)
     |      See the trigsimp function in sympy.simplify
     |
     |  ----------------------------------------------------------------------
     |  Data descriptors inherited from sympy.core.expr.Expr:
     |
     |  expr_free_symbols
     |      Like ``free_symbols``, but returns the free symbols only if they are contained in an expression node.
     |
     |      Examples
     |      ========
     |
     |      >>> from sympy.abc import x, y
     |      >>> (x + y).expr_free_symbols
     |      {x, y}
     |
     |      If the expression is contained in a non-expression object, don't return
     |      the free symbols. Compare:
     |
     |      >>> from sympy import Tuple
     |      >>> t = Tuple(x + y)
     |      >>> t.expr_free_symbols
     |      set()
     |      >>> t.free_symbols
     |      {x, y}
     |
     |  is_number
     |      Returns True if ``self`` has no free symbols and no
     |      undefined functions (AppliedUndef, to be precise). It will be
     |      faster than ``if not self.free_symbols``, however, since
     |      ``is_number`` will fail as soon as it hits a free symbol
     |      or undefined function.
     |
     |      Examples
     |      ========
     |
     |      >>> from sympy import log, Integral, cos, sin, pi
     |      >>> from sympy.core.function import Function
     |      >>> from sympy.abc import x
     |      >>> f = Function('f')
     |
     |      >>> x.is_number
     |      False
     |      >>> f(1).is_number
     |      False
     |      >>> (2*x).is_number
     |      False
     |      >>> (2 + Integral(2, x)).is_number
     |      False
     |      >>> (2 + Integral(2, (x, 1, 2))).is_number
     |      True
     |
     |      Not all numbers are Numbers in the SymPy sense:
     |
     |      >>> pi.is_number, pi.is_Number
     |      (True, False)
     |
     |      If something is a number it should evaluate to a number with
     |      real and imaginary parts that are Numbers; the result may not
     |      be comparable, however, since the real and/or imaginary part
     |      of the result may not have precision.
     |
     |      >>> cos(1).is_number and cos(1).is_comparable
     |      True
     |
     |      >>> z = cos(1)**2 + sin(1)**2 - 1
     |      >>> z.is_number
     |      True
     |      >>> z.is_comparable
     |      False
     |
     |      See Also
     |      ========
     |      sympy.core.basic.Basic.is_comparable
     |
     |  ----------------------------------------------------------------------
     |  Data and other attributes inherited from sympy.core.expr.Expr:
     |
     |  is_scalar = True
     |
     |  ----------------------------------------------------------------------
     |  Methods inherited from sympy.core.basic.Basic:
     |
     |  __getnewargs__(self)
     |
     |  __getstate__(self)
     |
     |  __ne__(self, other)
     |      ``a != b``  -> Compare two symbolic trees and see whether they are different
     |
     |      this is the same as:
     |
     |      ``a.compare(b) != 0``
     |
     |      but faster
     |
     |  __reduce_ex__(self, proto)
     |      Pickling support.
     |
     |  __repr__(self)
     |      Method to return the string representation.
     |
     |      Return the expression as a string.
     |
     |  __setstate__(self, state)
     |
     |  __str__(self)
     |      Return str(self).
     |
     |  as_dummy(self)
     |      Return the expression with any objects having structurally
     |      bound symbols replaced with unique, canonical symbols within
     |      the object in which they appear and having only the default
     |      assumption for commutativity being True.
     |
     |      Examples
     |      ========
     |
     |      >>> from sympy import Integral, Symbol
     |      >>> from sympy.abc import x, y
     |      >>> r = Symbol('r', real=True)
     |      >>> Integral(r, (r, x)).as_dummy()
     |      Integral(_0, (_0, x))
     |      >>> _.variables[0].is_real is None
     |      True
     |
     |      Notes
     |      =====
     |
     |      Any object that has structural dummy variables should have
     |      a property, `bound_symbols` that returns a list of structural
     |      dummy symbols of the object itself.
     |
     |      Lambda and Subs have bound symbols, but because of how they
     |      are cached, they already compare the same regardless of their
     |      bound symbols:
     |
     |      >>> from sympy import Lambda
     |      >>> Lambda(x, x + 1) == Lambda(y, y + 1)
     |      True
     |
     |  as_poly(self, *gens, **args)
     |      Converts ``self`` to a polynomial or returns ``None``.
     |
     |      >>> from sympy import sin
     |      >>> from sympy.abc import x, y
     |
     |      >>> print((x**2 + x*y).as_poly())
     |      Poly(x**2 + x*y, x, y, domain='ZZ')
     |
     |      >>> print((x**2 + x*y).as_poly(x, y))
     |      Poly(x**2 + x*y, x, y, domain='ZZ')
     |
     |      >>> print((x**2 + sin(y)).as_poly(x, y))
     |      None
     |
     |  atoms(self, *types)
     |      Returns the atoms that form the current object.
     |
     |      By default, only objects that are truly atomic and can't
     |      be divided into smaller pieces are returned: symbols, numbers,
     |      and number symbols like I and pi. It is possible to request
     |      atoms of any type, however, as demonstrated below.
     |
     |      Examples
     |      ========
     |
     |      >>> from sympy import I, pi, sin
     |      >>> from sympy.abc import x, y
     |      >>> (1 + x + 2*sin(y + I*pi)).atoms()
     |      {1, 2, I, pi, x, y}
     |
     |      If one or more types are given, the results will contain only
     |      those types of atoms.
     |
     |      >>> from sympy import Number, NumberSymbol, Symbol
     |      >>> (1 + x + 2*sin(y + I*pi)).atoms(Symbol)
     |      {x, y}
     |
     |      >>> (1 + x + 2*sin(y + I*pi)).atoms(Number)
     |      {1, 2}
     |
     |      >>> (1 + x + 2*sin(y + I*pi)).atoms(Number, NumberSymbol)
     |      {1, 2, pi}
     |
     |      >>> (1 + x + 2*sin(y + I*pi)).atoms(Number, NumberSymbol, I)
     |      {1, 2, I, pi}
     |
     |      Note that I (imaginary unit) and zoo (complex infinity) are special
     |      types of number symbols and are not part of the NumberSymbol class.
     |
     |      The type can be given implicitly, too:
     |
     |      >>> (1 + x + 2*sin(y + I*pi)).atoms(x) # x is a Symbol
     |      {x, y}
     |
     |      Be careful to check your assumptions when using the implicit option
     |      since ``S(1).is_Integer = True`` but ``type(S(1))`` is ``One``, a special type
     |      of sympy atom, while ``type(S(2))`` is type ``Integer`` and will find all
     |      integers in an expression:
     |
     |      >>> from sympy import S
     |      >>> (1 + x + 2*sin(y + I*pi)).atoms(S(1))
     |      {1}
     |
     |      >>> (1 + x + 2*sin(y + I*pi)).atoms(S(2))
     |      {1, 2}
     |
     |      Finally, arguments to atoms() can select more than atomic atoms: any
     |      sympy type (loaded in core/__init__.py) can be listed as an argument
     |      and those types of "atoms" as found in scanning the arguments of the
     |      expression recursively:
     |
     |      >>> from sympy import Function, Mul
     |      >>> from sympy.core.function import AppliedUndef
     |      >>> f = Function('f')
     |      >>> (1 + f(x) + 2*sin(y + I*pi)).atoms(Function)
     |      {f(x), sin(y + I*pi)}
     |      >>> (1 + f(x) + 2*sin(y + I*pi)).atoms(AppliedUndef)
     |      {f(x)}
     |
     |      >>> (1 + x + 2*sin(y + I*pi)).atoms(Mul)
     |      {I*pi, 2*sin(y + I*pi)}
     |
     |  compare(self, other)
     |      Return -1, 0, 1 if the object is smaller, equal, or greater than other.
     |
     |      Not in the mathematical sense. If the object is of a different type
     |      from the "other" then their classes are ordered according to
     |      the sorted_classes list.
     |
     |      Examples
     |      ========
     |
     |      >>> from sympy.abc import x, y
     |      >>> x.compare(y)
     |      -1
     |      >>> x.compare(x)
     |      0
     |      >>> y.compare(x)
     |      1
     |
     |  copy(self)
     |
     |  count(self, query)
     |      Count the number of matching subexpressions.
     |
     |  doit(self, **hints)
     |      Evaluate objects that are not evaluated by default like limits,
     |      integrals, sums and products. All objects of this kind will be
     |      evaluated recursively, unless some species were excluded via 'hints'
     |      or unless the 'deep' hint was set to 'False'.
     |
     |      >>> from sympy import Integral
     |      >>> from sympy.abc import x
     |
     |      >>> 2*Integral(x, x)
     |      2*Integral(x, x)
     |
     |      >>> (2*Integral(x, x)).doit()
     |      x**2
     |
     |      >>> (2*Integral(x, x)).doit(deep=False)
     |      2*Integral(x, x)
     |
     |  dummy_eq(self, other, symbol=None)
     |      Compare two expressions and handle dummy symbols.
     |
     |      Examples
     |      ========
     |
     |      >>> from sympy import Dummy
     |      >>> from sympy.abc import x, y
     |
     |      >>> u = Dummy('u')
     |
     |      >>> (u**2 + 1).dummy_eq(x**2 + 1)
     |      True
     |      >>> (u**2 + 1) == (x**2 + 1)
     |      False
     |
     |      >>> (u**2 + y).dummy_eq(x**2 + y, x)
     |      True
     |      >>> (u**2 + y).dummy_eq(x**2 + y, y)
     |      False
     |
     |  find(self, query, group=False)
     |      Find all subexpressions matching a query.
     |
     |  has(self, *patterns)
     |      Test whether any subexpression matches any of the patterns.
     |
     |      Examples
     |      ========
     |
     |      >>> from sympy import sin
     |      >>> from sympy.abc import x, y, z
     |      >>> (x**2 + sin(x*y)).has(z)
     |      False
     |      >>> (x**2 + sin(x*y)).has(x, y, z)
     |      True
     |      >>> x.has(x)
     |      True
     |
     |      Note ``has`` is a structural algorithm with no knowledge of
     |      mathematics. Consider the following half-open interval:
     |
     |      >>> from sympy.sets import Interval
     |      >>> i = Interval.Lopen(0, 5); i
     |      Interval.Lopen(0, 5)
     |      >>> i.args
     |      (0, 5, True, False)
     |      >>> i.has(4)  # there is no "4" in the arguments
     |      False
     |      >>> i.has(0)  # there *is* a "0" in the arguments
     |      True
     |
     |      Instead, use ``contains`` to determine whether a number is in the
     |      interval or not:
     |
     |      >>> i.contains(4)
     |      True
     |      >>> i.contains(0)
     |      False
     |
     |
     |      Note that ``expr.has(*patterns)`` is exactly equivalent to
     |      ``any(expr.has(p) for p in patterns)``. In particular, ``False`` is
     |      returned when the list of patterns is empty.
     |
     |      >>> x.has()
     |      False
     |
     |  is_hypergeometric(self, k)
     |
     |  match(self, pattern, old=False)
     |      Pattern matching.
     |
     |      Wild symbols match all.
     |
     |      Return ``None`` when expression (self) does not match
     |      with pattern. Otherwise return a dictionary such that::
     |
     |        pattern.xreplace(self.match(pattern)) == self
     |
     |      Examples
     |      ========
     |
     |      >>> from sympy import Wild
     |      >>> from sympy.abc import x, y
     |      >>> p = Wild("p")
     |      >>> q = Wild("q")
     |      >>> r = Wild("r")
     |      >>> e = (x+y)**(x+y)
     |      >>> e.match(p**p)
     |      {p_: x + y}
     |      >>> e.match(p**q)
     |      {p_: x + y, q_: x + y}
     |      >>> e = (2*x)**2
     |      >>> e.match(p*q**r)
     |      {p_: 4, q_: x, r_: 2}
     |      >>> (p*q**r).xreplace(e.match(p*q**r))
     |      4*x**2
     |
     |      The ``old`` flag will give the old-style pattern matching where
     |      expressions and patterns are essentially solved to give the
     |      match. Both of the following give None unless ``old=True``:
     |
     |      >>> (x - 2).match(p - x, old=True)
     |      {p_: 2*x - 2}
     |      >>> (2/x).match(p*x, old=True)
     |      {p_: 2/x**2}
     |
     |  matches(self, expr, repl_dict={}, old=False)
     |      Helper method for match() that looks for a match between Wild symbols
     |      in self and expressions in expr.
     |
     |      Examples
     |      ========
     |
     |      >>> from sympy import symbols, Wild, Basic
     |      >>> a, b, c = symbols('a b c')
     |      >>> x = Wild('x')
     |      >>> Basic(a + x, x).matches(Basic(a + b, c)) is None
     |      True
     |      >>> Basic(a + x, x).matches(Basic(a + b + c, b + c))
     |      {x_: b + c}
     |
     |  rcall(self, *args)
     |      Apply on the argument recursively through the expression tree.
     |
     |      This method is used to simulate a common abuse of notation for
     |      operators. For instance in SymPy the the following will not work:
     |
     |      ``(x+Lambda(y, 2*y))(z) == x+2*z``,
     |
     |      however you can use
     |
     |      >>> from sympy import Lambda
     |      >>> from sympy.abc import x, y, z
     |      >>> (x + Lambda(y, 2*y)).rcall(z)
     |      x + 2*z
     |
     |  replace(self, query, value, map=False, simultaneous=True, exact=None)
     |      Replace matching subexpressions of ``self`` with ``value``.
     |
     |      If ``map = True`` then also return the mapping {old: new} where ``old``
     |      was a sub-expression found with query and ``new`` is the replacement
     |      value for it. If the expression itself doesn't match the query, then
     |      the returned value will be ``self.xreplace(map)`` otherwise it should
     |      be ``self.subs(ordered(map.items()))``.
     |
     |      Traverses an expression tree and performs replacement of matching
     |      subexpressions from the bottom to the top of the tree. The default
     |      approach is to do the replacement in a simultaneous fashion so
     |      changes made are targeted only once. If this is not desired or causes
     |      problems, ``simultaneous`` can be set to False.
     |
     |      In addition, if an expression containing more than one Wild symbol
     |      is being used to match subexpressions and the ``exact`` flag is None
     |      it will be set to True so the match will only succeed if all non-zero
     |      values are received for each Wild that appears in the match pattern.
     |      Setting this to False accepts a match of 0; while setting it True
     |      accepts all matches that have a 0 in them. See example below for
     |      cautions.
     |
     |      The list of possible combinations of queries and replacement values
     |      is listed below:
     |
     |      Examples
     |      ========
     |
     |      Initial setup
     |
     |      >>> from sympy import log, sin, cos, tan, Wild, Mul, Add
     |      >>> from sympy.abc import x, y
     |      >>> f = log(sin(x)) + tan(sin(x**2))
     |
     |      1.1. type -> type
     |          obj.replace(type, newtype)
     |
     |          When object of type ``type`` is found, replace it with the
     |          result of passing its argument(s) to ``newtype``.
     |
     |          >>> f.replace(sin, cos)
     |          log(cos(x)) + tan(cos(x**2))
     |          >>> sin(x).replace(sin, cos, map=True)
     |          (cos(x), {sin(x): cos(x)})
     |          >>> (x*y).replace(Mul, Add)
     |          x + y
     |
     |      1.2. type -> func
     |          obj.replace(type, func)
     |
     |          When object of type ``type`` is found, apply ``func`` to its
     |          argument(s). ``func`` must be written to handle the number
     |          of arguments of ``type``.
     |
     |          >>> f.replace(sin, lambda arg: sin(2*arg))
     |          log(sin(2*x)) + tan(sin(2*x**2))
     |          >>> (x*y).replace(Mul, lambda *args: sin(2*Mul(*args)))
     |          sin(2*x*y)
     |
     |      2.1. pattern -> expr
     |          obj.replace(pattern(wild), expr(wild))
     |
     |          Replace subexpressions matching ``pattern`` with the expression
     |          written in terms of the Wild symbols in ``pattern``.
     |
     |          >>> a, b = map(Wild, 'ab')
     |          >>> f.replace(sin(a), tan(a))
     |          log(tan(x)) + tan(tan(x**2))
     |          >>> f.replace(sin(a), tan(a/2))
     |          log(tan(x/2)) + tan(tan(x**2/2))
     |          >>> f.replace(sin(a), a)
     |          log(x) + tan(x**2)
     |          >>> (x*y).replace(a*x, a)
     |          y
     |
     |          Matching is exact by default when more than one Wild symbol
     |          is used: matching fails unless the match gives non-zero
     |          values for all Wild symbols:
     |
     |          >>> (2*x + y).replace(a*x + b, b - a)
     |          y - 2
     |          >>> (2*x).replace(a*x + b, b - a)
     |          2*x
     |
     |          When set to False, the results may be non-intuitive:
     |
     |          >>> (2*x).replace(a*x + b, b - a, exact=False)
     |          2/x
     |
     |      2.2. pattern -> func
     |          obj.replace(pattern(wild), lambda wild: expr(wild))
     |
     |          All behavior is the same as in 2.1 but now a function in terms of
     |          pattern variables is used rather than an expression:
     |
     |          >>> f.replace(sin(a), lambda a: sin(2*a))
     |          log(sin(2*x)) + tan(sin(2*x**2))
     |
     |      3.1. func -> func
     |          obj.replace(filter, func)
     |
     |          Replace subexpression ``e`` with ``func(e)`` if ``filter(e)``
     |          is True.
     |
     |          >>> g = 2*sin(x**3)
     |          >>> g.replace(lambda expr: expr.is_Number, lambda expr: expr**2)
     |          4*sin(x**9)
     |
     |      The expression itself is also targeted by the query but is done in
     |      such a fashion that changes are not made twice.
     |
     |          >>> e = x*(x*y + 1)
     |          >>> e.replace(lambda x: x.is_Mul, lambda x: 2*x)
     |          2*x*(2*x*y + 1)
     |
     |      When matching a single symbol, `exact` will default to True, but
     |      this may or may not be the behavior that is desired:
     |
     |      Here, we want `exact=False`:
     |
     |      >>> from sympy import Function
     |      >>> f = Function('f')
     |      >>> e = f(1) + f(0)
     |      >>> q = f(a), lambda a: f(a + 1)
     |      >>> e.replace(*q, exact=False)
     |      f(1) + f(2)
     |      >>> e.replace(*q, exact=True)
     |      f(0) + f(2)
     |
     |      But here, the nature of matching makes selecting
     |      the right setting tricky:
     |
     |      >>> e = x**(1 + y)
     |      >>> (x**(1 + y)).replace(x**(1 + a), lambda a: x**-a, exact=False)
     |      1
     |      >>> (x**(1 + y)).replace(x**(1 + a), lambda a: x**-a, exact=True)
     |      x**(-x - y + 1)
     |      >>> (x**y).replace(x**(1 + a), lambda a: x**-a, exact=False)
     |      1
     |      >>> (x**y).replace(x**(1 + a), lambda a: x**-a, exact=True)
     |      x**(1 - y)
     |
     |      It is probably better to use a different form of the query
     |      that describes the target expression more precisely:
     |
     |      >>> (1 + x**(1 + y)).replace(
     |      ... lambda x: x.is_Pow and x.exp.is_Add and x.exp.args[0] == 1,
     |      ... lambda x: x.base**(1 - (x.exp - 1)))
     |      ...
     |      x**(1 - y) + 1
     |
     |      See Also
     |      ========
     |
     |      subs: substitution of subexpressions as defined by the objects
     |            themselves.
     |      xreplace: exact node replacement in expr tree; also capable of
     |                using matching rules
     |
     |  rewrite(self, *args, **hints)
     |      Rewrite functions in terms of other functions.
     |
     |      Rewrites expression containing applications of functions
     |      of one kind in terms of functions of different kind. For
     |      example you can rewrite trigonometric functions as complex
     |      exponentials or combinatorial functions as gamma function.
     |
     |      As a pattern this function accepts a list of functions to
     |      to rewrite (instances of DefinedFunction class). As rule
     |      you can use string or a destination function instance (in
     |      this case rewrite() will use the str() function).
     |
     |      There is also the possibility to pass hints on how to rewrite
     |      the given expressions. For now there is only one such hint
     |      defined called 'deep'. When 'deep' is set to False it will
     |      forbid functions to rewrite their contents.
     |
     |      Examples
     |      ========
     |
     |      >>> from sympy import sin, exp
     |      >>> from sympy.abc import x
     |
     |      Unspecified pattern:
     |
     |      >>> sin(x).rewrite(exp)
     |      -I*(exp(I*x) - exp(-I*x))/2
     |
     |      Pattern as a single function:
     |
     |      >>> sin(x).rewrite(sin, exp)
     |      -I*(exp(I*x) - exp(-I*x))/2
     |
     |      Pattern as a list of functions:
     |
     |      >>> sin(x).rewrite([sin, ], exp)
     |      -I*(exp(I*x) - exp(-I*x))/2
     |
     |  subs(self, *args, **kwargs)
     |      Substitutes old for new in an expression after sympifying args.
     |
     |      `args` is either:
     |        - two arguments, e.g. foo.subs(old, new)
     |        - one iterable argument, e.g. foo.subs(iterable). The iterable may be
     |           o an iterable container with (old, new) pairs. In this case the
     |             replacements are processed in the order given with successive
     |             patterns possibly affecting replacements already made.
     |           o a dict or set whose key/value items correspond to old/new pairs.
     |             In this case the old/new pairs will be sorted by op count and in
     |             case of a tie, by number of args and the default_sort_key. The
     |             resulting sorted list is then processed as an iterable container
     |             (see previous).
     |
     |      If the keyword ``simultaneous`` is True, the subexpressions will not be
     |      evaluated until all the substitutions have been made.
     |
     |      Examples
     |      ========
     |
     |      >>> from sympy import pi, exp, limit, oo
     |      >>> from sympy.abc import x, y
     |      >>> (1 + x*y).subs(x, pi)
     |      pi*y + 1
     |      >>> (1 + x*y).subs({x:pi, y:2})
     |      1 + 2*pi
     |      >>> (1 + x*y).subs([(x, pi), (y, 2)])
     |      1 + 2*pi
     |      >>> reps = [(y, x**2), (x, 2)]
     |      >>> (x + y).subs(reps)
     |      6
     |      >>> (x + y).subs(reversed(reps))
     |      x**2 + 2
     |
     |      >>> (x**2 + x**4).subs(x**2, y)
     |      y**2 + y
     |
     |      To replace only the x**2 but not the x**4, use xreplace:
     |
     |      >>> (x**2 + x**4).xreplace({x**2: y})
     |      x**4 + y
     |
     |      To delay evaluation until all substitutions have been made,
     |      set the keyword ``simultaneous`` to True:
     |
     |      >>> (x/y).subs([(x, 0), (y, 0)])
     |      0
     |      >>> (x/y).subs([(x, 0), (y, 0)], simultaneous=True)
     |      nan
     |
     |      This has the added feature of not allowing subsequent substitutions
     |      to affect those already made:
     |
     |      >>> ((x + y)/y).subs({x + y: y, y: x + y})
     |      1
     |      >>> ((x + y)/y).subs({x + y: y, y: x + y}, simultaneous=True)
     |      y/(x + y)
     |
     |      In order to obtain a canonical result, unordered iterables are
     |      sorted by count_op length, number of arguments and by the
     |      default_sort_key to break any ties. All other iterables are left
     |      unsorted.
     |
     |      >>> from sympy import sqrt, sin, cos
     |      >>> from sympy.abc import a, b, c, d, e
     |
     |      >>> A = (sqrt(sin(2*x)), a)
     |      >>> B = (sin(2*x), b)
     |      >>> C = (cos(2*x), c)
     |      >>> D = (x, d)
     |      >>> E = (exp(x), e)
     |
     |      >>> expr = sqrt(sin(2*x))*sin(exp(x)*x)*cos(2*x) + sin(2*x)
     |
     |      >>> expr.subs(dict([A, B, C, D, E]))
     |      a*c*sin(d*e) + b
     |
     |      The resulting expression represents a literal replacement of the
     |      old arguments with the new arguments. This may not reflect the
     |      limiting behavior of the expression:
     |
     |      >>> (x**3 - 3*x).subs({x: oo})
     |      nan
     |
     |      >>> limit(x**3 - 3*x, x, oo)
     |      oo
     |
     |      If the substitution will be followed by numerical
     |      evaluation, it is better to pass the substitution to
     |      evalf as
     |
     |      >>> (1/x).evalf(subs={x: 3.0}, n=21)
     |      0.333333333333333333333
     |
     |      rather than
     |
     |      >>> (1/x).subs({x: 3.0}).evalf(21)
     |      0.333333333333333314830
     |
     |      as the former will ensure that the desired level of precision is
     |      obtained.
     |
     |      See Also
     |      ========
     |      replace: replacement capable of doing wildcard-like matching,
     |               parsing of match, and conditional replacements
     |      xreplace: exact node replacement in expr tree; also capable of
     |                using matching rules
     |      sympy.core.evalf.EvalfMixin.evalf: calculates the given formula to a desired level of precision
     |
     |  xreplace lambda rule, **_
     |      # Function needs args so we define a property that returns
     |      # a function that takes args...and then use that function
     |      # to return the right value
     |
     |  ----------------------------------------------------------------------
     |  Class methods inherited from sympy.core.basic.Basic:
     |
     |  fromiter(args, **assumptions) from sympy.core.function.FunctionClass
     |      Create a new object from an iterable.
     |
     |      This is a convenience function that allows one to create objects from
     |      any iterable, without having to convert to a list or tuple first.
     |
     |      Examples
     |      ========
     |
     |      >>> from sympy import Tuple
     |      >>> Tuple.fromiter(i for i in range(5))
     |      (0, 1, 2, 3, 4)
     |
     |  ----------------------------------------------------------------------
     |  Data descriptors inherited from sympy.core.basic.Basic:
     |
     |  args
     |      Returns a tuple of arguments of 'self'.
     |
     |      Examples
     |      ========
     |
     |      >>> from sympy import cot
     |      >>> from sympy.abc import x, y
     |
     |      >>> cot(x).args
     |      (x,)
     |
     |      >>> cot(x).args[0]
     |      x
     |
     |      >>> (x*y).args
     |      (x, y)
     |
     |      >>> (x*y).args[1]
     |      y
     |
     |      Notes
     |      =====
     |
     |      Never use self._args, always use self.args.
     |      Only use _args in __new__ when creating a new function.
     |      Don't override .args() from Basic (so that it's easy to
     |      change the interface in the future if needed).
     |
     |  assumptions0
     |      Return object `type` assumptions.
     |
     |      For example:
     |
     |        Symbol('x', real=True)
     |        Symbol('x', integer=True)
     |
     |      are different objects. In other words, besides Python type (Symbol in
     |      this case), the initial assumptions are also forming their typeinfo.
     |
     |      Examples
     |      ========
     |
     |      >>> from sympy import Symbol
     |      >>> from sympy.abc import x
     |      >>> x.assumptions0
     |      {'commutative': True}
     |      >>> x = Symbol("x", positive=True)
     |      >>> x.assumptions0
     |      {'commutative': True, 'complex': True, 'extended_negative': False,
     |       'extended_nonnegative': True, 'extended_nonpositive': False,
     |       'extended_nonzero': True, 'extended_positive': True, 'extended_real':
     |       True, 'finite': True, 'hermitian': True, 'imaginary': False,
     |       'infinite': False, 'negative': False, 'nonnegative': True,
     |       'nonpositive': False, 'nonzero': True, 'positive': True, 'real':
     |       True, 'zero': False}
     |
     |  canonical_variables
     |      Return a dictionary mapping any variable defined in
     |      ``self.bound_symbols`` to Symbols that do not clash
     |      with any existing symbol in the expression.
     |
     |      Examples
     |      ========
     |
     |      >>> from sympy import Lambda
     |      >>> from sympy.abc import x
     |      >>> Lambda(x, 2*x).canonical_variables
     |      {x: _0}
     |
     |  free_symbols
     |      Return from the atoms of self those which are free symbols.
     |
     |      For most expressions, all symbols are free symbols. For some classes
     |      this is not true. e.g. Integrals use Symbols for the dummy variables
     |      which are bound variables, so Integral has a method to return all
     |      symbols except those. Derivative keeps track of symbols with respect
     |      to which it will perform a derivative; those are
     |      bound variables, too, so it has its own free_symbols method.
     |
     |      Any other method that uses bound variables should implement a
     |      free_symbols method.
     |
     |  is_algebraic
     |
     |  is_antihermitian
     |
     |  is_comparable
     |      Return True if self can be computed to a real number
     |      (or already is a real number) with precision, else False.
     |
     |      Examples
     |      ========
     |
     |      >>> from sympy import exp_polar, pi, I
     |      >>> (I*exp_polar(I*pi/2)).is_comparable
     |      True
     |      >>> (I*exp_polar(I*pi*2)).is_comparable
     |      False
     |
     |      A False result does not mean that `self` cannot be rewritten
     |      into a form that would be comparable. For example, the
     |      difference computed below is zero but without simplification
     |      it does not evaluate to a zero with precision:
     |
     |      >>> e = 2**pi*(1 + 2**pi)
     |      >>> dif = e - e.expand()
     |      >>> dif.is_comparable
     |      False
     |      >>> dif.n(2)._prec
     |      1
     |
     |  is_complex
     |
     |  is_composite
     |
     |  is_even
     |
     |  is_extended_negative
     |
     |  is_extended_nonnegative
     |
     |  is_extended_nonpositive
     |
     |  is_extended_nonzero
     |
     |  is_extended_positive
     |
     |  is_extended_real
     |
     |  is_finite
     |
     |  is_hermitian
     |
     |  is_imaginary
     |
     |  is_infinite
     |
     |  is_integer
     |
     |  is_irrational
     |
     |  is_negative
     |
     |  is_noninteger
     |
     |  is_nonnegative
     |
     |  is_nonpositive
     |
     |  is_nonzero
     |
     |  is_odd
     |
     |  is_polar
     |
     |  is_positive
     |
     |  is_prime
     |
     |  is_rational
     |
     |  is_real
     |
     |  is_transcendental
     |
     |  is_zero
     |
     |  ----------------------------------------------------------------------
     |  Data and other attributes inherited from sympy.core.basic.Basic:
     |
     |  is_Add = False
     |
     |  is_AlgebraicNumber = False
     |
     |  is_Atom = False
     |
     |  is_Boolean = False
     |
     |  is_Derivative = False
     |
     |  is_Dummy = False
     |
     |  is_Equality = False
     |
     |  is_Float = False
     |
     |  is_Indexed = False
     |
     |  is_Integer = False
     |
     |  is_MatAdd = False
     |
     |  is_MatMul = False
     |
     |  is_Matrix = False
     |
     |  is_Mul = False
     |
     |  is_Not = False
     |
     |  is_Number = False
     |
     |  is_NumberSymbol = False
     |
     |  is_Order = False
     |
     |  is_Piecewise = False
     |
     |  is_Point = False
     |
     |  is_Poly = False
     |
     |  is_Pow = False
     |
     |  is_Rational = False
     |
     |  is_Relational = False
     |
     |  is_Symbol = False
     |
     |  is_Vector = False
     |
     |  is_Wild = False
     |
     |  is_symbol = False
     |
     |  ----------------------------------------------------------------------
     |  Methods inherited from sympy.core.evalf.EvalfMixin:
     |
     |  evalf(self, n=15, subs=None, maxn=100, chop=False, strict=False, quad=None, verbose=False)
     |      Evaluate the given formula to an accuracy of n digits.
     |      Optional keyword arguments:
     |
     |          subs=<dict>
     |              Substitute numerical values for symbols, e.g.
     |              subs={x:3, y:1+pi}. The substitutions must be given as a
     |              dictionary.
     |
     |          maxn=<integer>
     |              Allow a maximum temporary working precision of maxn digits
     |              (default=100)
     |
     |          chop=<bool>
     |              Replace tiny real or imaginary parts in subresults
     |              by exact zeros (default=False)
     |
     |          strict=<bool>
     |              Raise PrecisionExhausted if any subresult fails to evaluate
     |              to full accuracy, given the available maxprec
     |              (default=False)
     |
     |          quad=<str>
     |              Choose algorithm for numerical quadrature. By default,
     |              tanh-sinh quadrature is used. For oscillatory
     |              integrals on an infinite interval, try quad='osc'.
     |
     |          verbose=<bool>
     |              Print debug information (default=False)
     |
     |      Notes
     |      =====
     |
     |      When Floats are naively substituted into an expression, precision errors
     |      may adversely affect the result. For example, adding 1e16 (a Float) to 1
     |      will truncate to 1e16; if 1e16 is then subtracted, the result will be 0.
     |      That is exactly what happens in the following:
     |
     |      >>> from sympy.abc import x, y, z
     |      >>> values = {x: 1e16, y: 1, z: 1e16}
     |      >>> (x + y - z).subs(values)
     |      0
     |
     |      Using the subs argument for evalf is the accurate way to evaluate such an
     |      expression:
     |
     |      >>> (x + y - z).evalf(subs=values)
     |      1.00000000000000
     |
     |  n = evalf(self, n=15, subs=None, maxn=100, chop=False, strict=False, quad=None, verbose=False)

```python
# from sympy import *
# from numpy import *
# Esta práctica no es para nada recomendable.
```

Explicar el uso de la sintaxis `from numpy import *` y sus peligros (no recomendable).

### 0.3 `PyPlot` de `matplotlib`

El módulo `PyPlot` de la librería `matplotlib` contiene funciones que nos permite generar una gran cantidad de gráficas rápidamente. Las funciones de este módulo están escritas con el mismo nombre que las funciones para graficar en `Matlab`.

**Referencia:**
- https://matplotlib.org/api/pyplot_summary.html

```python
# importar matplotlib.pyplot
import matplotlib.pyplot as plt
# Lo siguiente es equivalente
# from matplotlib import pyplot as plt
# comando para que las gráficas salgan en la misma ventana
%matplotlib inline
```

Ya que revisamos todas las librerías que usaremos, empecemos con la clase como tal...

___
Basamos todos los resultados en los siguientes teoremas:

## 1. Teorema de Fermat (análisis)

Si una función $f(x)$ alcanza un máximo o mínimo local en $x=c$, y si la derivada $f'(c)$ existe en el punto $c$, entonces $f'(c) = 0$.

### Ejemplo

Sabemos que la función $f(x)=x^2$ tiene un mínimo global en $x=0$, pues

$$f(x)=x^2\geq0,\qquad\text{y}\qquad f(x)=x^2=0 \qquad\text{si y solo si}\qquad x=0.$$

```python
# declarar la variable real x
sym.var('x')
```

$\displaystyle x$

```python
# declarar ahora f=x^2 y mostrar
f = x**2
f
```

$\displaystyle x^{2}$

```python
# derivar f respecto a x y mostrar
df = sym.diff(f, x)
df
```

$\displaystyle 2 x$

```python
help(sym.solve)
```

    Help on function solve in module sympy.solvers.solvers:

    solve(f, *symbols, **flags)
        Algebraically solves equations and systems of equations.

        Currently supported are:
            - polynomial,
            - transcendental
            - piecewise combinations of the above
            - systems of linear and polynomial equations
            - systems containing relational expressions.

        Input is formed as:

        * f
            - a single Expr or Poly that must be zero,
            - an Equality
            - a Relational expression
            - a Boolean
            - iterable of one or more of the above

        * symbols (object(s) to solve for) specified as
            - none given (other non-numeric objects will be used)
            - single symbol
            - denested list of symbols
              e.g. solve(f, x, y)
            - ordered iterable of symbols
              e.g. solve(f, [x, y])

        * flags
            'dict'=True (default is False)
                return list (perhaps empty) of solution mappings
            'set'=True (default is False)
                return list of symbols and set of tuple(s) of solution(s)
            'exclude=[] (default)'
                don't try to solve for any of the free symbols in exclude;
                if expressions are given, the free symbols in them will
                be extracted automatically.
            'check=True (default)'
                If False, don't do any testing of solutions. This can be
                useful if one wants to include solutions that make any
                denominator zero.
            'numerical=True (default)'
                do a fast numerical check if ``f`` has only one symbol.
            'minimal=True (default is False)'
                a very fast, minimal testing.
            'warn=True (default is False)'
                show a warning if checksol() could not conclude.
            'simplify=True (default)'
                simplify all but polynomials of order 3 or greater before
                returning them and (if check is not False) use the
                general simplify function on the solutions and the
                expression obtained when they are substituted into the
                function which should be zero
            'force=True (default is False)'
                make positive all symbols without assumptions regarding sign.
            'rational=True (default)'
                recast Floats as Rational; if this option is not used, the
                system containing floats may fail to solve because of issues
                with polys. If rational=None, Floats will be recast as
                rationals but the answer will be recast as Floats. If the
                flag is False then nothing will be done to the Floats.
            'manual=True (default is False)'
                do not use the polys/matrix method to solve a system of
                equations, solve them one at a time as you might "manually"
            'implicit=True (default is False)'
                allows solve to return a solution for a pattern in terms of
                other functions that contain that pattern; this is only
                needed if the pattern is inside of some invertible function
                like cos, exp, ....
            'particular=True (default is False)'
                instructs solve to try to find a particular solution to a linear
                system with as many zeros as possible; this is very expensive
            'quick=True (default is False)'
                when using particular=True, use a fast heuristic instead to find a
                solution with many zeros (instead of using the very slow method
                guaranteed to find the largest number of zeros possible)
            'cubics=True (default)'
                return explicit solutions when cubic expressions are encountered
            'quartics=True (default)'
                return explicit solutions when quartic expressions are encountered
            'quintics=True (default)'
                return explicit solutions (if possible) when quintic expressions
                are encountered

        Examples
        ========

        The output varies according to the input and can be seen by example::

            >>> from sympy import solve, Poly, Eq, Function, exp
            >>> from sympy.abc import x, y, z, a, b
            >>> f = Function('f')

        * boolean or univariate Relational

            >>> solve(x < 3)
            (-oo < x) & (x < 3)

        * to always get a list of solution mappings, use flag dict=True

            >>> solve(x - 3, dict=True)
            [{x: 3}]
            >>> sol = solve([x - 3, y - 1], dict=True)
            >>> sol
            [{x: 3, y: 1}]
            >>> sol[0][x]
            3
            >>> sol[0][y]
            1

        * to get a list of symbols and set of solution(s) use flag set=True

            >>> solve([x**2 - 3, y - 1], set=True)
            ([x, y], {(-sqrt(3), 1), (sqrt(3), 1)})

        * single expression and single symbol that is in the expression

            >>> solve(x - y, x)
            [y]
            >>> solve(x - 3, x)
            [3]
            >>> solve(Eq(x, 3), x)
            [3]
            >>> solve(Poly(x - 3), x)
            [3]
            >>> solve(x**2 - y**2, x, set=True)
            ([x], {(-y,), (y,)})
            >>> solve(x**4 - 1, x, set=True)
            ([x], {(-1,), (1,), (-I,), (I,)})

        * single expression with no symbol that is in the expression

            >>> solve(3, x)
            []
            >>> solve(x - 3, y)
            []

        * single expression with no symbol given

              In this case, all free symbols will be selected as potential
              symbols to solve for. If the equation is univariate then a list
              of solutions is returned; otherwise -- as is the case when symbols are
              given as an iterable of length > 1 -- a list of mappings will be returned.

                >>> solve(x - 3)
                [3]
                >>> solve(x**2 - y**2)
                [{x: -y}, {x: y}]
                >>> solve(z**2*x**2 - z**2*y**2)
                [{x: -y}, {x: y}, {z: 0}]
                >>> solve(z**2*x - z**2*y**2)
                [{x: y**2}, {z: 0}]

        * when an object other than a Symbol is given as a symbol, it is
          isolated algebraically and an implicit solution may be obtained.
          This is mostly provided as a convenience to save one from replacing
          the object with a Symbol and solving for that Symbol. It will only
          work if the specified object can be replaced with a Symbol using the
          subs method.

              >>> solve(f(x) - x, f(x))
              [x]
              >>> solve(f(x).diff(x) - f(x) - x, f(x).diff(x))
              [x + f(x)]
              >>> solve(f(x).diff(x) - f(x) - x, f(x))
              [-x + Derivative(f(x), x)]
              >>> solve(x + exp(x)**2, exp(x), set=True)
              ([exp(x)], {(-sqrt(-x),), (sqrt(-x),)})

              >>> from sympy import Indexed, IndexedBase, Tuple, sqrt
              >>> A = IndexedBase('A')
              >>> eqs = Tuple(A[1] + A[2] - 3, A[1] - A[2] + 1)
              >>> solve(eqs, eqs.atoms(Indexed))
              {A[1]: 1, A[2]: 2}

            * To solve for a *symbol* implicitly, use 'implicit=True':

                >>> solve(x + exp(x), x)
                [-LambertW(1)]
                >>> solve(x + exp(x), x, implicit=True)
                [-exp(x)]

            * It is possible to solve for anything that can be targeted with
              subs:

                >>> solve(x + 2 + sqrt(3), x + 2)
                [-sqrt(3)]
                >>> solve((x + 2 + sqrt(3), x + 4 + y), y, x + 2)
                {y: -2 + sqrt(3), x + 2: -sqrt(3)}

            * Nothing heroic is done in this implicit solving so you may end up
              with a symbol still in the solution:

                >>> eqs = (x*y + 3*y + sqrt(3), x + 4 + y)
                >>> solve(eqs, y, x + 2)
                {y: -sqrt(3)/(x + 3), x + 2: (-2*x - 6 + sqrt(3))/(x + 3)}
                >>> solve(eqs, y*x, x)
                {x: -y - 4, x*y: -3*y - sqrt(3)}

            * if you attempt to solve for a number remember that the number
              you have obtained does not necessarily mean that the value is
              equivalent to the expression obtained:

                >>> solve(sqrt(2) - 1, 1)
                [sqrt(2)]
                >>> solve(x - y + 1, 1)  # /!\ -1 is targeted, too
                [x/(y - 1)]
                >>> [_.subs(z, -1) for _ in solve((x - y + 1).subs(-1, z), 1)]
                [-x + y]

            * To solve for a function within a derivative, use dsolve.

        * single expression and more than 1 symbol

            * when there is a linear solution

                >>> solve(x - y**2, x, y)
                [(y**2, y)]
                >>> solve(x**2 - y, x, y)
                [(x, x**2)]
                >>> solve(x**2 - y, x, y, dict=True)
                [{y: x**2}]

            * when undetermined coefficients are identified

                * that are linear

                    >>> solve((a + b)*x - b + 2, a, b)
                    {a: -2, b: 2}

                * that are nonlinear

                    >>> solve((a + b)*x - b**2 + 2, a, b, set=True)
                    ([a, b], {(-sqrt(2), sqrt(2)), (sqrt(2), -sqrt(2))})

            * if there is no linear solution then the first successful
              attempt for a nonlinear solution will be returned

                >>> solve(x**2 - y**2, x, y, dict=True)
                [{x: -y}, {x: y}]
                >>> solve(x**2 - y**2/exp(x), x, y, dict=True)
                [{x: 2*LambertW(-y/2)}, {x: 2*LambertW(y/2)}]
                >>> solve(x**2 - y**2/exp(x), y, x)
                [(-x*sqrt(exp(x)), x), (x*sqrt(exp(x)), x)]

        * iterable of one or more of the above

            * involving relationals or bools

                >>> solve([x < 3, x - 2])
                Eq(x, 2)
                >>> solve([x > 3, x - 2])
                False

            * when the system is linear

                * with a solution

                    >>> solve([x - 3], x)
                    {x: 3}
                    >>> solve((x + 5*y - 2, -3*x + 6*y - 15), x, y)
                    {x: -3, y: 1}
                    >>> solve((x + 5*y - 2, -3*x + 6*y - 15), x, y, z)
                    {x: -3, y: 1}
                    >>> solve((x + 5*y - 2, -3*x + 6*y - z), z, x, y)
                    {x: 2 - 5*y, z: 21*y - 6}

                * without a solution

                    >>> solve([x + 3, x - 3])
                    []

            * when the system is not linear

                >>> solve([x**2 + y -2, y**2 - 4], x, y, set=True)
                ([x, y], {(-2, -2), (0, 2), (2, -2)})

            * if no symbols are given, all free symbols will be selected and a list
              of mappings returned

                >>> solve([x - 2, x**2 + y])
                [{x: 2, y: -4}]
                >>> solve([x - 2, x**2 + f(x)], {f(x), x})
                [{x: 2, f(x): -4}]

            * if any equation doesn't depend on the symbol(s) given it will be
              eliminated from the equation set and an answer may be given
              implicitly in terms of variables that were not of interest

                >>> solve([x - y, y - 3], x)
                {x: y}

        Notes
        =====

        solve() with check=True (default) will run through the symbol tags to
        elimate unwanted solutions.  If no assumptions are included all possible
        solutions will be returned.

            >>> from sympy import Symbol, solve
            >>> x = Symbol("x")
            >>> solve(x**2 - 1)
            [-1, 1]

        By using the positive tag only one solution will be returned:

            >>> pos = Symbol("pos", positive=True)
            >>> solve(pos**2 - 1)
            [1]

        Assumptions aren't checked when `solve()` input involves
        relationals or bools.

        When the solutions are checked, those that make any denominator zero
        are automatically excluded. If you do not want to exclude such solutions
        then use the check=False option:

            >>> from sympy import sin, limit
            >>> solve(sin(x)/x)  # 0 is excluded
            [pi]

        If check=False then a solution to the numerator being zero is found: x = 0.
        In this case, this is a spurious solution since sin(x)/x has the well known
        limit (without dicontinuity) of 1 at x = 0:

            >>> solve(sin(x)/x, check=False)
            [0, pi]

        In the following case, however, the limit exists and is equal to the
        value of x = 0 that is excluded when check=True:

            >>> eq = x**2*(1/x - z**2/x)
            >>> solve(eq, x)
            []
            >>> solve(eq, x, check=False)
            [0]
            >>> limit(eq, x, 0, '-')
            0
            >>> limit(eq, x, 0, '+')
            0

        Disabling high-order, explicit solutions
        ----------------------------------------

        When solving polynomial expressions, one might not want explicit solutions
        (which can be quite long). If the expression is univariate, CRootOf
        instances will be returned instead:

            >>> solve(x**3 - x + 1)
            [-1/((-1/2 - sqrt(3)*I/2)*(3*sqrt(69)/2 + 27/2)**(1/3)) - (-1/2 -
            sqrt(3)*I/2)*(3*sqrt(69)/2 + 27/2)**(1/3)/3, -(-1/2 +
            sqrt(3)*I/2)*(3*sqrt(69)/2 + 27/2)**(1/3)/3 - 1/((-1/2 +
            sqrt(3)*I/2)*(3*sqrt(69)/2 + 27/2)**(1/3)), -(3*sqrt(69)/2 +
            27/2)**(1/3)/3 - 1/(3*sqrt(69)/2 + 27/2)**(1/3)]
            >>> solve(x**3 - x + 1, cubics=False)
            [CRootOf(x**3 - x + 1, 0),
             CRootOf(x**3 - x + 1, 1),
             CRootOf(x**3 - x + 1, 2)]

            If the expression is multivariate, no solution might be returned:

            >>> solve(x**3 - x + a, x, cubics=False)
            []

        Sometimes solutions will be obtained even when a flag is False because the
        expression could be factored. In the following example, the equation can
        be factored as the product of a linear and a quadratic factor so explicit
        solutions (which did not require solving a cubic expression) are obtained:

            >>> eq = x**3 + 3*x**2 + x - 1
            >>> solve(eq, cubics=False)
            [-1, -1 + sqrt(2), -sqrt(2) - 1]

        Solving equations involving radicals
        ------------------------------------

        Because of SymPy's use of the principle root (issue #8789), some solutions
        to radical equations will be missed unless check=False:

            >>> from sympy import root
            >>> eq = root(x**3 - 3*x**2, 3) + 1 - x
            >>> solve(eq)
            []
            >>> solve(eq, check=False)
            [1/3]

        In the above example there is only a single solution to the
        equation. Other expressions will yield spurious roots which
        must be checked manually; roots which give a negative argument
        to odd-powered radicals will also need special checking:

            >>> from sympy import real_root, S
            >>> eq = root(x, 3) - root(x, 5) + S(1)/7
            >>> solve(eq)  # this gives 2 solutions but misses a 3rd
            [CRootOf(7*_p**5 - 7*_p**3 + 1, 1)**15,
            CRootOf(7*_p**5 - 7*_p**3 + 1, 2)**15]
            >>> sol = solve(eq, check=False)
            >>> [abs(eq.subs(x,i).n(2)) for i in sol]
            [0.48, 0.e-110, 0.e-110, 0.052, 0.052]

            The first solution is negative so real_root must be used to see
            that it satisfies the expression:

            >>> abs(real_root(eq.subs(x, sol[0])).n(2))
            0.e-110

        If the roots of the equation are not real then more care will be
        necessary to find the roots, especially for higher order equations.
        Consider the following expression:

            >>> expr = root(x, 3) - root(x, 5)

        We will construct a known value for this expression at x = 3 by selecting
        the 1-th root for each radical:

            >>> expr1 = root(x, 3, 1) - root(x, 5, 1)
            >>> v = expr1.subs(x, -3)

        The solve function is unable to find any exact roots to this equation:

            >>> eq = Eq(expr, v); eq1 = Eq(expr1, v)
            >>> solve(eq, check=False), solve(eq1, check=False)
            ([], [])

        The function unrad, however, can be used to get a form of the equation for
        which numerical roots can be found:

            >>> from sympy.solvers.solvers import unrad
            >>> from sympy import nroots
            >>> e, (p, cov) = unrad(eq)
            >>> pvals = nroots(e)
            >>> inversion = solve(cov, x)[0]
            >>> xvals = [inversion.subs(p, i) for i in pvals]

        Although eq or eq1 could have been used to find xvals, the solution can
        only be verified with expr1:

            >>> z = expr - v
            >>> [xi.n(chop=1e-9) for xi in xvals if abs(z.subs(x, xi).n()) < 1e-9]
            []
            >>> z1 = expr1 - v
            >>> [xi.n(chop=1e-9) for xi in xvals if abs(z1.subs(x, xi).n()) < 1e-9]
            [-3.0]

        See Also
        ========

            - rsolve() for solving recurrence relationships
            - dsolve() for solving differential equations

```python
# resolver f'(x)=0 y mostrar soluciones
soluciones = sym.solve(df, x)
```

```python
soluciones
```

$\displaystyle \left[ 0\right]$

```python
# Encuentra también soluciones complejas
s2 = sym.solve(x**2 + 1, x)
s2[0], s2[1]
```

$\displaystyle \left( - i, \  i\right)$

```python
# Puedo resolver ecuaciones que involucren más de una variable
sym.var('y')
s3 = sym.solve(x**3 + y, x)
s3
```

$\displaystyle \left[ \sqrt[3]{- y}, \  - \frac{\sqrt[3]{- y}}{2} - \frac{\sqrt{3} i \sqrt[3]{- y}}{2}, \  - \frac{\sqrt[3]{- y}}{2} + \frac{\sqrt{3} i \sqrt[3]{- y}}{2}\right]$

Veamos la gráfica...

```python
# convertir f e una función que se pueda evaluar numéricamente (función lambdify de la librería sympy)
f_num = sym.lambdify(x, f, modules='numpy')
```

```python
f
```

$\displaystyle x^{2}$

```python
f_num(np.array([12, 5, 13]))
```

    array([144,  25, 169])

```python
help(np.linspace)
```

    Help on function linspace in module numpy:

    linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None, axis=0)
        Return evenly spaced numbers over a specified interval.

        Returns `num` evenly spaced samples, calculated over the
        interval [`start`, `stop`].

        The endpoint of the interval can optionally be excluded.

        .. versionchanged:: 1.16.0
            Non-scalar `start` and `stop` are now supported.

        Parameters
        ----------
        start : array_like
            The starting value of the sequence.
        stop : array_like
            The end value of the sequence, unless `endpoint` is set to False.
            In that case, the sequence consists of all but the last of ``num + 1``
            evenly spaced samples, so that `stop` is excluded.  Note that the step
            size changes when `endpoint` is False.
        num : int, optional
            Number of samples to generate. Default is 50. Must be non-negative.
        endpoint : bool, optional
            If True, `stop` is the last sample. Otherwise, it is not included.
            Default is True.
        retstep : bool, optional
            If True, return (`samples`, `step`), where `step` is the spacing
            between samples.
        dtype : dtype, optional
            The type of the output array.  If `dtype` is not given, infer the data
            type from the other input arguments.

            .. versionadded:: 1.9.0

        axis : int, optional
            The axis in the result to store the samples.  Relevant only if start
            or stop are array-like.  By default (0), the samples will be along a
            new axis inserted at the beginning. Use -1 to get an axis at the end.

            .. versionadded:: 1.16.0

        Returns
        -------
        samples : ndarray
            There are `num` equally spaced samples in the closed interval
            ``[start, stop]`` or the half-open interval ``[start, stop)``
            (depending on whether `endpoint` is True or False).
        step : float, optional
            Only returned if `retstep` is True

            Size of spacing between samples.

        See Also
        --------
        arange : Similar to `linspace`, but uses a step size (instead of the
                 number of samples).
        geomspace : Similar to `linspace`, but with numbers spaced evenly on a log
                    scale (a geometric progression).
        logspace : Similar to `geomspace`, but with the end points specified as
                   logarithms.

        Examples
        --------
        >>> np.linspace(2.0, 3.0, num=5)
        array([2.  , 2.25, 2.5 , 2.75, 3.  ])
        >>> np.linspace(2.0, 3.0, num=5, endpoint=False)
        array([2. ,  2.2,  2.4,  2.6,  2.8])
        >>> np.linspace(2.0, 3.0, num=5, retstep=True)
        (array([2.  ,  2.25,  2.5 ,  2.75,  3.  ]), 0.25)

        Graphical illustration:

        >>> import matplotlib.pyplot as plt
        >>> N = 8
        >>> y = np.zeros(N)
        >>> x1 = np.linspace(0, 10, N, endpoint=True)
        >>> x2 = np.linspace(0, 10, N, endpoint=False)
        >>> plt.plot(x1, y, 'o')
        [<matplotlib.lines.Line2D object at 0x...>]
        >>> plt.plot(x2, y + 0.5, 'o')
        [<matplotlib.lines.Line2D object at 0x...>]
        >>> plt.ylim([-0.5, 1])
        (-0.5, 1)
        >>> plt.show()

```python
# Coordenadas x (abscisas)
x_num = np.linspace(-5, 5)
```

```python
# graficar
# Crear ventana de graficos y damos medidas de la ventana
plt.figure(figsize=(6, 4))
# Sirve para hacer el grafico y determinar sus caracteristicas
plt.plot(x_num,             # Puntos en x
         f_num(x_num),      # Puntos en y
         'k',               # Color: negro
         lw=2,              # Grosor de línea (LineWidth: lw)
         label='$f(x)=x^2$' # Etiqueta de la gráfica
        )
# Punto de mínimo
plt.plot(soluciones,                     # Coordenada en x
         f_num(np.array(soluciones)),    # Coordenada en y
         'ro',                           # Punto rojo
         ms=10,                          # Tamaño del punto (MarkerSize: ms)
         label='Minimo global: $(0, 0)$' # Etiqueta de la gráfica
        )
# Nombre del eje x de la grafica
plt.xlabel("$x$")  # Los signos $$ son para escribir ecuaciones
# Nombre del eje y
plt.ylabel("$y$")
# Sirve para poner las etiquetas de las graficas
plt.legend(loc='best')
# Sirve para poner la cuadricula
plt.grid()
```

Ver diferencias entre f y f_num

```python
# intentar evaluar f y f_num
f(12)
```

```python
f_num(12)
```

$\displaystyle 144$

```python
f
```

$\displaystyle x^{2}$

**Otra manera de hacer lo anterior**

Concepto de función...

```python
# Concepto de función
# def nombre_de_la_funcion(argumento[s]):
#     --> Operación 1
#     --> Operación 2
#     --> ...
#     --> Operación N
#     return [lo que vaya a devolver]
def h(x):
    return x**2
```

```python
type(x)
```

    sympy.core.symbol.Symbol

```python
h(x)
```

$\displaystyle x^{2}$

```python
h(np.array([12, 13, 5]))
```

    array([144, 169,  25])

```python
h(12)
```

$\displaystyle 144$

```python
dh = sym.diff(h(x), x)
dh
```

$\displaystyle 2 x$

```python
soluciones = sym.solve(dh, x)
soluciones
```

$\displaystyle \left[ 0\right]$

```python
# graficar
# Crear ventana de graficos y damos medidas de la ventana
plt.figure(figsize=(7, 5))
# Sirve para hacer el grafico y determinar sus caracteristicas
plt.plot(x_num, h(x_num), label='$h(x)=x^2$')
# Punto de mínimo
plt.plot(soluciones, h(np.array(soluciones)), 'ro', ms=10, label='Minimo global: $(0, 0)$')
# Nombre del eje x de la grafica
plt.xlabel('$x$')
# Nombre del eje y
plt.ylabel('$y$')
# Sirve para poner las etiquetas de las graficas
plt.legend(loc='best')
# Sirve para poner la cuadricula
plt.grid()
```

El converso del teorema anterior no es cierto.

### Actividad
Considere $g(x)=x^3$.
- Usando `sympy`, muestre que $g'(0)=0$.
- Sin embargo, descartar que $x=0$ es un extremo de $g(x)$ viendo su **gráfica**.

```python
# Declarar la variable simbolica x

```

```python
# Definimos funcion g(x)

```

```python
# Derivamos g(x)

```

```python
# Puntos criticos

```

```python
# graficar
# Crear ventana de graficos y damos medidas de la ventana

# Sirve para hacer el grafico y determinar sus caracteristicas

# Nombre del eje x de la grafica

# Nombre del eje y

# Sirve para poner las etiquetas de las graficas

# Sirve para poner la cuadricula

```

## 2. Criterio de la segunda derivada

Sea $f(x)$ una función tal que $f’(c)=0$ y cuya segunda derivada existe en un intervalo abierto que contiene a $c$.
- Si $f’’(c)>0$, entonces $f(c)$ es un mínimo relativo.
- Si $f’’(c)<0$, entonces $f(c)$ es un máximo relativo.
- Si $f’’(c)=0$, entonces el criterio no decide.

### Ejemplo

Mostrar, usando `sympy`, que la función $f(x)=x^2$ tiene un mínimo relativo en $x=0$.

Ya vimos que $f'(0)=0$. Notemos que:

```python
help(df.subs)
```

    Help on method subs in module sympy.core.basic:

    subs(*args, **kwargs) method of sympy.core.mul.Mul instance
        Substitutes old for new in an expression after sympifying args.

        `args` is either:
          - two arguments, e.g. foo.subs(old, new)
          - one iterable argument, e.g. foo.subs(iterable). The iterable may be
             o an iterable container with (old, new) pairs. In this case the
               replacements are processed in the order given with successive
               patterns possibly affecting replacements already made.
             o a dict or set whose key/value items correspond to old/new pairs.
               In this case the old/new pairs will be sorted by op count and in
               case of a tie, by number of args and the default_sort_key. The
               resulting sorted list is then processed as an iterable container
               (see previous).

        If the keyword ``simultaneous`` is True, the subexpressions will not be
        evaluated until all the substitutions have been made.

        Examples
        ========

        >>> from sympy import pi, exp, limit, oo
        >>> from sympy.abc import x, y
        >>> (1 + x*y).subs(x, pi)
        pi*y + 1
        >>> (1 + x*y).subs({x:pi, y:2})
        1 + 2*pi
        >>> (1 + x*y).subs([(x, pi), (y, 2)])
        1 + 2*pi
        >>> reps = [(y, x**2), (x, 2)]
        >>> (x + y).subs(reps)
        6
        >>> (x + y).subs(reversed(reps))
        x**2 + 2

        >>> (x**2 + x**4).subs(x**2, y)
        y**2 + y

        To replace only the x**2 but not the x**4, use xreplace:

        >>> (x**2 + x**4).xreplace({x**2: y})
        x**4 + y

        To delay evaluation until all substitutions have been made,
        set the keyword ``simultaneous`` to True:

        >>> (x/y).subs([(x, 0), (y, 0)])
        0
        >>> (x/y).subs([(x, 0), (y, 0)], simultaneous=True)
        nan

        This has the added feature of not allowing subsequent substitutions
        to affect those already made:

        >>> ((x + y)/y).subs({x + y: y, y: x + y})
        1
        >>> ((x + y)/y).subs({x + y: y, y: x + y}, simultaneous=True)
        y/(x + y)

        In order to obtain a canonical result, unordered iterables are
        sorted by count_op length, number of arguments and by the
        default_sort_key to break any ties. All other iterables are left
        unsorted.

        >>> from sympy import sqrt, sin, cos
        >>> from sympy.abc import a, b, c, d, e

        >>> A = (sqrt(sin(2*x)), a)
        >>> B = (sin(2*x), b)
        >>> C = (cos(2*x), c)
        >>> D = (x, d)
        >>> E = (exp(x), e)

        >>> expr = sqrt(sin(2*x))*sin(exp(x)*x)*cos(2*x) + sin(2*x)

        >>> expr.subs(dict([A, B, C, D, E]))
        a*c*sin(d*e) + b

        The resulting expression represents a literal replacement of the
        old arguments with the new arguments. This may not reflect the
        limiting behavior of the expression:

        >>> (x**3 - 3*x).subs({x: oo})
        nan

        >>> limit(x**3 - 3*x, x, oo)
        oo

        If the substitution will be followed by numerical
        evaluation, it is better to pass the substitution to
        evalf as

        >>> (1/x).evalf(subs={x: 3.0}, n=21)
        0.333333333333333333333

        rather than

        >>> (1/x).subs({x: 3.0}).evalf(21)
        0.333333333333333314830

        as the former will ensure that the desired level of precision is
        obtained.

        See Also
        ========
        replace: replacement capable of doing wildcard-like matching,
                 parsing of match, and conditional replacements
        xreplace: exact node replacement in expr tree; also capable of
                  using matching rules
        sympy.core.evalf.EvalfMixin.evalf: calculates the given formula to a desired level of precision

```python
df
```

$\displaystyle 2 x$

```python
x
```

$\displaystyle x$

```python
df.subs({x: 0})
```

$\displaystyle 0$

```python
# Sacamos la segunda derivada
d2f = sym.diff(df, x)
# Formas equivalentes
# d2f = sym.diff(f, x, x)
# d2f = sym.diff(f, x, 2)
```

```python
d2f
```

$\displaystyle 2$

Por tanto, por el criterio de la segunda derivada, $f(0)=0$ es un mínimo relativo (en efecto, el mínimo global).

### Ejemplo
¿Qué pasa con $g(x)=x^3$ al intentar utilizar el criterio de la segunda derivada? (usar `sympy`).

```python
# Definimos la función g(x)=x^3
def g(x):
    return x**3
```

```python
# Sacamos la derivada de la función g respecto a x g'(x)=3x^2
dg = sym.diff(g(x), x)
dg
```

$\displaystyle 3 x^{2}$

```python
# Observamos que g'(0)=0 (es un punto crítico)
dg.subs({x: 0})
```

$\displaystyle 0$

```python
# Obtenemos la segunda derivada de la función g respecto a x g''(x)=6x
d2g = sym.diff(g(x), x, 2)
d2g
```

$\displaystyle 6 x$

```python
# Evaluamos g''(0)
d2g.subs({x: 0})
```

$\displaystyle 0$

Como $g''(0)=0$ entonces el criterio de la segunda derivada no concluye.

### Actividad

¿Qué pasa con $h(x)=x^4$ al intentar utilizar el criterio de la segunda derivada?.

```python

```

```python

```

```python

```

```python

```

```python

```

## 3. Método para determinar extremos absolutos de una función continua y=f(x) en [a,b]

- Determinar todos los valores críticos $c_1, c_2, c_3, \dots, c_n$ en $(a,b)$.
- Evaluar $f$ en todos los valores críticos y en los extremos $x=a$ y $x=b$.
- El más grande y el más pequeño de los valores de la lista $f(a), f(b), f(c_1), f(c_2), \dots, f(c_n)$ son el máximo absoluto y el mínimo absoluto, respectivamente, de f en el intervalo [a,b].

### Ejemplo

Determinar los extremos absolutos de $f(x)=x^2-6x$ en $\left[0,5\right]$.

Obtenemos los puntos críticos de $f$ en $\left[0,5\right]$:

```python
# Definimos f
def f(x):
    return x**2 - 6 * x
```

```python
# Derivamos f
df = sym.diff(f(x), x)
df
```

$\displaystyle 2 x - 6$

```python
# Resolver la ecuación f'(x)=0 para encontrar puntos críticos
p_criticos = sym.solve(df, x)
p_criticos
```

$\displaystyle \left[ 3\right]$

Evaluamos $f$ en los extremos y en los puntos críticos:

```python
f(0), f(5), f(p_criticos[0])
```

$\displaystyle \left( 0, \  -5, \  -9\right)$

Concluimos que el máximo absoluto de $f$ en $\left[0,5\right]$ es $0$ y se alcanza en $x=0$, y que el mínimo absoluto es $-9$ y se alcanza en $x=3$.

```python
# graficar
# Crear ventana de graficos y damos medidas de la ventana
plt.figure(figsize=(6, 4))
# Sirve para hacer el grafico y determinar sus caracteristicas
x_num = np.linspace(0, 5)
plt.plot(x_num, f(x_num), 'k', lw=2, label='$f(x)=x^2-6x$')
plt.plot(p_criticos[0], f(p_criticos[0]),
         'ro',
         ms=10,
         label=f'Mínimo absoluto: $({p_criticos[0]}, {f(p_criticos[0])})$')
plt.plot(0, f(0),
         'go',
         ms=10,
         label=f'Máximo absoluto: $({0}, {f(0)})$')
# Nombre del eje x de la grafica
plt.xlabel('$x$')
# Nombre del eje y
plt.ylabel('$y$')
# Sirve para poner las etiquetas de las graficas
plt.legend(loc='best')
# Sirve para poner la cuadricula
plt.grid()
```

### Actividad
Determinar los valores extremos absolutos de $h(x)=x^3-3x$ en $\left[-2.2,1.8\right]$, usando `sympy`. Mostrar en una gráfica.

```python

```

```python

```

```python

```

```python

```

```python

```

```python

```

```python

```

### En varias variables...

El procedimiento es análogo.

Si una función $f:\mathbb{R}^n\to\mathbb{R}$ alcanza un máximo o mínimo local en $\boldsymbol{x}=\boldsymbol{c}\in\mathbb{R}^n$, y $f$ es diferenciable en el punto $\boldsymbol{x}=\boldsymbol{c}$, entonces $\left.\frac{\partial f}{\partial \boldsymbol{x}}\right|_{\boldsymbol{x}=\boldsymbol{c}}=\boldsymbol{0}$ (todas las derivadas parciales en el punto $\boldsymbol{x}=\boldsymbol{c}$ son cero).

**Criterio de la segunda derivada:** para ver si es máximo o mínimo, se toma la segunda derivada (matriz jacobiana) y se verifica definición negativa o positiva, respectivamente.

Si se restringe a cierta región, hay ciertas técnicas. La más general, pero también la más compleja es la de **multiplicadores de Lagrange**.

**Ejemplo:** hacer a mano a la vez para corroborar...

```python
sym.var('x y')
x, y
```

$\displaystyle \left( x, \  y\right)$

```python
def f(x, y):
    return x**2 + y**2
```

```python
dfx = sym.diff(f(x,y), x)
dfy = sym.diff(f(x,y), y)
dfx, dfy
```

$\displaystyle \left( 2 x, \  2 y\right)$

```python
xy_c = sym.solve([dfx, dfy], [x, y])
xy_c
```

$\displaystyle \left\{ x : 0, \  y : 0\right\}$

```python
x_c, y_c = xy_c[x], xy_c[y]
x_c, y_c
```

$\displaystyle \left( 0, \  0\right)$

```python
d2fx = sym.diff(f(x,y), x, 2)
d2fy = sym.diff(f(x,y), y, 2)
dfxy = sym.diff(f(x,y), x, y)

Jf = sym.Matrix([[d2fx, dfxy], [dfxy, d2fy]])
Jf.eigenvals()
```

$\displaystyle \left\{ 2 : 2\right\}$

```python
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
```

```python
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

x = np.linspace(-2, 2, 100)
y = x
X, Y = np.meshgrid(x, y)

ax.plot_surface(X, Y, f(X, Y))
ax.plot([x_c], [y_c], [f(x_c,y_c)], '*r')
```

# Anuncios parroquiales

## 1. [Curso gratis sugerido](https://www.kaggle.com/learn/python)

## 2. La próxima clase hay quiz (clases 1 y 2 - lo que hemos visto).

<footer id="attribution" style="float:right; color:#808080; background:#fff;">
Created with Jupyter by Esteban Jiménez Rodríguez.
</footer>