123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398 |
- """
- Singularities
- =============
- This module implements algorithms for finding singularities for a function
- and identifying types of functions.
- The differential calculus methods in this module include methods to identify
- the following function types in the given ``Interval``:
- - Increasing
- - Strictly Increasing
- - Decreasing
- - Strictly Decreasing
- - Monotonic
- """
- from sympy.core.power import Pow
- from sympy.core.singleton import S
- from sympy.core.symbol import Symbol
- from sympy.core.sympify import sympify
- from sympy.functions.elementary.exponential import log
- from sympy.functions.elementary.trigonometric import sec, csc, cot, tan, cos
- from sympy.utilities.misc import filldedent
- def singularities(expression, symbol, domain=None):
- """
- Find singularities of a given function.
- Parameters
- ==========
- expression : Expr
- The target function in which singularities need to be found.
- symbol : Symbol
- The symbol over the values of which the singularity in
- expression in being searched for.
- Returns
- =======
- Set
- A set of values for ``symbol`` for which ``expression`` has a
- singularity. An ``EmptySet`` is returned if ``expression`` has no
- singularities for any given value of ``Symbol``.
- Raises
- ======
- NotImplementedError
- Methods for determining the singularities of this function have
- not been developed.
- Notes
- =====
- This function does not find non-isolated singularities
- nor does it find branch points of the expression.
- Currently supported functions are:
- - univariate continuous (real or complex) functions
- References
- ==========
- .. [1] https://en.wikipedia.org/wiki/Mathematical_singularity
- Examples
- ========
- >>> from sympy import singularities, Symbol, log
- >>> x = Symbol('x', real=True)
- >>> y = Symbol('y', real=False)
- >>> singularities(x**2 + x + 1, x)
- EmptySet
- >>> singularities(1/(x + 1), x)
- {-1}
- >>> singularities(1/(y**2 + 1), y)
- {-I, I}
- >>> singularities(1/(y**3 + 1), y)
- {-1, 1/2 - sqrt(3)*I/2, 1/2 + sqrt(3)*I/2}
- >>> singularities(log(x), x)
- {0}
- """
- from sympy.solvers.solveset import solveset
- if domain is None:
- domain = S.Reals if symbol.is_real else S.Complexes
- try:
- sings = S.EmptySet
- for i in expression.rewrite([sec, csc, cot, tan], cos).atoms(Pow):
- if i.exp.is_infinite:
- raise NotImplementedError
- if i.exp.is_negative:
- sings += solveset(i.base, symbol, domain)
- for i in expression.atoms(log):
- sings += solveset(i.args[0], symbol, domain)
- return sings
- except NotImplementedError:
- raise NotImplementedError(filldedent('''
- Methods for determining the singularities
- of this function have not been developed.'''))
- ###########################################################################
- # DIFFERENTIAL CALCULUS METHODS #
- ###########################################################################
- def monotonicity_helper(expression, predicate, interval=S.Reals, symbol=None):
- """
- Helper function for functions checking function monotonicity.
- Parameters
- ==========
- expression : Expr
- The target function which is being checked
- predicate : function
- The property being tested for. The function takes in an integer
- and returns a boolean. The integer input is the derivative and
- the boolean result should be true if the property is being held,
- and false otherwise.
- interval : Set, optional
- The range of values in which we are testing, defaults to all reals.
- symbol : Symbol, optional
- The symbol present in expression which gets varied over the given range.
- It returns a boolean indicating whether the interval in which
- the function's derivative satisfies given predicate is a superset
- of the given interval.
- Returns
- =======
- Boolean
- True if ``predicate`` is true for all the derivatives when ``symbol``
- is varied in ``range``, False otherwise.
- """
- from sympy.solvers.solveset import solveset
- expression = sympify(expression)
- free = expression.free_symbols
- if symbol is None:
- if len(free) > 1:
- raise NotImplementedError(
- 'The function has not yet been implemented'
- ' for all multivariate expressions.'
- )
- variable = symbol or (free.pop() if free else Symbol('x'))
- derivative = expression.diff(variable)
- predicate_interval = solveset(predicate(derivative), variable, S.Reals)
- return interval.is_subset(predicate_interval)
- def is_increasing(expression, interval=S.Reals, symbol=None):
- """
- Return whether the function is increasing in the given interval.
- Parameters
- ==========
- expression : Expr
- The target function which is being checked.
- interval : Set, optional
- The range of values in which we are testing (defaults to set of
- all real numbers).
- symbol : Symbol, optional
- The symbol present in expression which gets varied over the given range.
- Returns
- =======
- Boolean
- True if ``expression`` is increasing (either strictly increasing or
- constant) in the given ``interval``, False otherwise.
- Examples
- ========
- >>> from sympy import is_increasing
- >>> from sympy.abc import x, y
- >>> from sympy import S, Interval, oo
- >>> is_increasing(x**3 - 3*x**2 + 4*x, S.Reals)
- True
- >>> is_increasing(-x**2, Interval(-oo, 0))
- True
- >>> is_increasing(-x**2, Interval(0, oo))
- False
- >>> is_increasing(4*x**3 - 6*x**2 - 72*x + 30, Interval(-2, 3))
- False
- >>> is_increasing(x**2 + y, Interval(1, 2), x)
- True
- """
- return monotonicity_helper(expression, lambda x: x >= 0, interval, symbol)
- def is_strictly_increasing(expression, interval=S.Reals, symbol=None):
- """
- Return whether the function is strictly increasing in the given interval.
- Parameters
- ==========
- expression : Expr
- The target function which is being checked.
- interval : Set, optional
- The range of values in which we are testing (defaults to set of
- all real numbers).
- symbol : Symbol, optional
- The symbol present in expression which gets varied over the given range.
- Returns
- =======
- Boolean
- True if ``expression`` is strictly increasing in the given ``interval``,
- False otherwise.
- Examples
- ========
- >>> from sympy import is_strictly_increasing
- >>> from sympy.abc import x, y
- >>> from sympy import Interval, oo
- >>> is_strictly_increasing(4*x**3 - 6*x**2 - 72*x + 30, Interval.Ropen(-oo, -2))
- True
- >>> is_strictly_increasing(4*x**3 - 6*x**2 - 72*x + 30, Interval.Lopen(3, oo))
- True
- >>> is_strictly_increasing(4*x**3 - 6*x**2 - 72*x + 30, Interval.open(-2, 3))
- False
- >>> is_strictly_increasing(-x**2, Interval(0, oo))
- False
- >>> is_strictly_increasing(-x**2 + y, Interval(-oo, 0), x)
- False
- """
- return monotonicity_helper(expression, lambda x: x > 0, interval, symbol)
- def is_decreasing(expression, interval=S.Reals, symbol=None):
- """
- Return whether the function is decreasing in the given interval.
- Parameters
- ==========
- expression : Expr
- The target function which is being checked.
- interval : Set, optional
- The range of values in which we are testing (defaults to set of
- all real numbers).
- symbol : Symbol, optional
- The symbol present in expression which gets varied over the given range.
- Returns
- =======
- Boolean
- True if ``expression`` is decreasing (either strictly decreasing or
- constant) in the given ``interval``, False otherwise.
- Examples
- ========
- >>> from sympy import is_decreasing
- >>> from sympy.abc import x, y
- >>> from sympy import S, Interval, oo
- >>> is_decreasing(1/(x**2 - 3*x), Interval.open(S(3)/2, 3))
- True
- >>> is_decreasing(1/(x**2 - 3*x), Interval.open(1.5, 3))
- True
- >>> is_decreasing(1/(x**2 - 3*x), Interval.Lopen(3, oo))
- True
- >>> is_decreasing(1/(x**2 - 3*x), Interval.Ropen(-oo, S(3)/2))
- False
- >>> is_decreasing(1/(x**2 - 3*x), Interval.Ropen(-oo, 1.5))
- False
- >>> is_decreasing(-x**2, Interval(-oo, 0))
- False
- >>> is_decreasing(-x**2 + y, Interval(-oo, 0), x)
- False
- """
- return monotonicity_helper(expression, lambda x: x <= 0, interval, symbol)
- def is_strictly_decreasing(expression, interval=S.Reals, symbol=None):
- """
- Return whether the function is strictly decreasing in the given interval.
- Parameters
- ==========
- expression : Expr
- The target function which is being checked.
- interval : Set, optional
- The range of values in which we are testing (defaults to set of
- all real numbers).
- symbol : Symbol, optional
- The symbol present in expression which gets varied over the given range.
- Returns
- =======
- Boolean
- True if ``expression`` is strictly decreasing in the given ``interval``,
- False otherwise.
- Examples
- ========
- >>> from sympy import is_strictly_decreasing
- >>> from sympy.abc import x, y
- >>> from sympy import S, Interval, oo
- >>> is_strictly_decreasing(1/(x**2 - 3*x), Interval.Lopen(3, oo))
- True
- >>> is_strictly_decreasing(1/(x**2 - 3*x), Interval.Ropen(-oo, S(3)/2))
- False
- >>> is_strictly_decreasing(1/(x**2 - 3*x), Interval.Ropen(-oo, 1.5))
- False
- >>> is_strictly_decreasing(-x**2, Interval(-oo, 0))
- False
- >>> is_strictly_decreasing(-x**2 + y, Interval(-oo, 0), x)
- False
- """
- return monotonicity_helper(expression, lambda x: x < 0, interval, symbol)
- def is_monotonic(expression, interval=S.Reals, symbol=None):
- """
- Return whether the function is monotonic in the given interval.
- Parameters
- ==========
- expression : Expr
- The target function which is being checked.
- interval : Set, optional
- The range of values in which we are testing (defaults to set of
- all real numbers).
- symbol : Symbol, optional
- The symbol present in expression which gets varied over the given range.
- Returns
- =======
- Boolean
- True if ``expression`` is monotonic in the given ``interval``,
- False otherwise.
- Raises
- ======
- NotImplementedError
- Monotonicity check has not been implemented for the queried function.
- Examples
- ========
- >>> from sympy import is_monotonic
- >>> from sympy.abc import x, y
- >>> from sympy import S, Interval, oo
- >>> is_monotonic(1/(x**2 - 3*x), Interval.open(S(3)/2, 3))
- True
- >>> is_monotonic(1/(x**2 - 3*x), Interval.open(1.5, 3))
- True
- >>> is_monotonic(1/(x**2 - 3*x), Interval.Lopen(3, oo))
- True
- >>> is_monotonic(x**3 - 3*x**2 + 4*x, S.Reals)
- True
- >>> is_monotonic(-x**2, S.Reals)
- False
- >>> is_monotonic(x**2 + y + 1, Interval(1, 2), x)
- True
- """
- from sympy.solvers.solveset import solveset
- expression = sympify(expression)
- free = expression.free_symbols
- if symbol is None and len(free) > 1:
- raise NotImplementedError(
- 'is_monotonic has not yet been implemented'
- ' for all multivariate expressions.'
- )
- variable = symbol or (free.pop() if free else Symbol('x'))
- turning_points = solveset(expression.diff(variable), variable, interval)
- return interval.intersection(turning_points) is S.EmptySet
|