123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839 |
- from .accumulationbounds import AccumBounds, AccumulationBounds # noqa: F401
- from .singularities import singularities
- from sympy.core import Pow, S
- from sympy.core.function import diff, expand_mul
- from sympy.core.kind import NumberKind
- from sympy.core.mod import Mod
- from sympy.core.relational import Relational
- from sympy.core.symbol import Symbol, Dummy
- from sympy.core.sympify import _sympify
- from sympy.functions.elementary.complexes import Abs, im, re
- from sympy.functions.elementary.exponential import exp, log
- from sympy.functions.elementary.piecewise import Piecewise
- from sympy.functions.elementary.trigonometric import (
- TrigonometricFunction, sin, cos, csc, sec)
- from sympy.polys.polytools import degree, lcm_list
- from sympy.sets.sets import (Interval, Intersection, FiniteSet, Union,
- Complement)
- from sympy.sets.fancysets import ImageSet
- from sympy.simplify.simplify import simplify
- from sympy.utilities import filldedent
- from sympy.utilities.iterables import iterable
- def continuous_domain(f, symbol, domain):
- """
- Returns the intervals in the given domain for which the function
- is continuous.
- This method is limited by the ability to determine the various
- singularities and discontinuities of the given function.
- Parameters
- ==========
- f : :py:class:`~.Expr`
- The concerned function.
- symbol : :py:class:`~.Symbol`
- The variable for which the intervals are to be determined.
- domain : :py:class:`~.Interval`
- The domain over which the continuity of the symbol has to be checked.
- Examples
- ========
- >>> from sympy import Interval, Symbol, S, tan, log, pi, sqrt
- >>> from sympy.calculus.util import continuous_domain
- >>> x = Symbol('x')
- >>> continuous_domain(1/x, x, S.Reals)
- Union(Interval.open(-oo, 0), Interval.open(0, oo))
- >>> continuous_domain(tan(x), x, Interval(0, pi))
- Union(Interval.Ropen(0, pi/2), Interval.Lopen(pi/2, pi))
- >>> continuous_domain(sqrt(x - 2), x, Interval(-5, 5))
- Interval(2, 5)
- >>> continuous_domain(log(2*x - 1), x, S.Reals)
- Interval.open(1/2, oo)
- Returns
- =======
- :py:class:`~.Interval`
- Union of all intervals where the function is continuous.
- Raises
- ======
- NotImplementedError
- If the method to determine continuity of such a function
- has not yet been developed.
- """
- from sympy.solvers.inequalities import solve_univariate_inequality
- if domain.is_subset(S.Reals):
- constrained_interval = domain
- for atom in f.atoms(Pow):
- den = atom.exp.as_numer_denom()[1]
- if den.is_even and den.is_nonzero:
- constraint = solve_univariate_inequality(atom.base >= 0,
- symbol).as_set()
- constrained_interval = Intersection(constraint,
- constrained_interval)
- for atom in f.atoms(log):
- constraint = solve_univariate_inequality(atom.args[0] > 0,
- symbol).as_set()
- constrained_interval = Intersection(constraint,
- constrained_interval)
- return constrained_interval - singularities(f, symbol, domain)
- def function_range(f, symbol, domain):
- """
- Finds the range of a function in a given domain.
- This method is limited by the ability to determine the singularities and
- determine limits.
- Parameters
- ==========
- f : :py:class:`~.Expr`
- The concerned function.
- symbol : :py:class:`~.Symbol`
- The variable for which the range of function is to be determined.
- domain : :py:class:`~.Interval`
- The domain under which the range of the function has to be found.
- Examples
- ========
- >>> from sympy import Interval, Symbol, S, exp, log, pi, sqrt, sin, tan
- >>> from sympy.calculus.util import function_range
- >>> x = Symbol('x')
- >>> function_range(sin(x), x, Interval(0, 2*pi))
- Interval(-1, 1)
- >>> function_range(tan(x), x, Interval(-pi/2, pi/2))
- Interval(-oo, oo)
- >>> function_range(1/x, x, S.Reals)
- Union(Interval.open(-oo, 0), Interval.open(0, oo))
- >>> function_range(exp(x), x, S.Reals)
- Interval.open(0, oo)
- >>> function_range(log(x), x, S.Reals)
- Interval(-oo, oo)
- >>> function_range(sqrt(x), x, Interval(-5, 9))
- Interval(0, 3)
- Returns
- =======
- :py:class:`~.Interval`
- Union of all ranges for all intervals under domain where function is
- continuous.
- Raises
- ======
- NotImplementedError
- If any of the intervals, in the given domain, for which function
- is continuous are not finite or real,
- OR if the critical points of the function on the domain cannot be found.
- """
- if domain is S.EmptySet:
- return S.EmptySet
- period = periodicity(f, symbol)
- if period == S.Zero:
- # the expression is constant wrt symbol
- return FiniteSet(f.expand())
- from sympy.series.limits import limit
- from sympy.solvers.solveset import solveset
- if period is not None:
- if isinstance(domain, Interval):
- if (domain.inf - domain.sup).is_infinite:
- domain = Interval(0, period)
- elif isinstance(domain, Union):
- for sub_dom in domain.args:
- if isinstance(sub_dom, Interval) and \
- ((sub_dom.inf - sub_dom.sup).is_infinite):
- domain = Interval(0, period)
- intervals = continuous_domain(f, symbol, domain)
- range_int = S.EmptySet
- if isinstance(intervals,(Interval, FiniteSet)):
- interval_iter = (intervals,)
- elif isinstance(intervals, Union):
- interval_iter = intervals.args
- else:
- raise NotImplementedError(filldedent('''
- Unable to find range for the given domain.
- '''))
- for interval in interval_iter:
- if isinstance(interval, FiniteSet):
- for singleton in interval:
- if singleton in domain:
- range_int += FiniteSet(f.subs(symbol, singleton))
- elif isinstance(interval, Interval):
- vals = S.EmptySet
- critical_points = S.EmptySet
- critical_values = S.EmptySet
- bounds = ((interval.left_open, interval.inf, '+'),
- (interval.right_open, interval.sup, '-'))
- for is_open, limit_point, direction in bounds:
- if is_open:
- critical_values += FiniteSet(limit(f, symbol, limit_point, direction))
- vals += critical_values
- else:
- vals += FiniteSet(f.subs(symbol, limit_point))
- solution = solveset(f.diff(symbol), symbol, interval)
- if not iterable(solution):
- raise NotImplementedError(
- 'Unable to find critical points for {}'.format(f))
- if isinstance(solution, ImageSet):
- raise NotImplementedError(
- 'Infinite number of critical points for {}'.format(f))
- critical_points += solution
- for critical_point in critical_points:
- vals += FiniteSet(f.subs(symbol, critical_point))
- left_open, right_open = False, False
- if critical_values is not S.EmptySet:
- if critical_values.inf == vals.inf:
- left_open = True
- if critical_values.sup == vals.sup:
- right_open = True
- range_int += Interval(vals.inf, vals.sup, left_open, right_open)
- else:
- raise NotImplementedError(filldedent('''
- Unable to find range for the given domain.
- '''))
- return range_int
- def not_empty_in(finset_intersection, *syms):
- """
- Finds the domain of the functions in ``finset_intersection`` in which the
- ``finite_set`` is not-empty
- Parameters
- ==========
- finset_intersection : Intersection of FiniteSet
- The unevaluated intersection of FiniteSet containing
- real-valued functions with Union of Sets
- syms : Tuple of symbols
- Symbol for which domain is to be found
- Raises
- ======
- NotImplementedError
- The algorithms to find the non-emptiness of the given FiniteSet are
- not yet implemented.
- ValueError
- The input is not valid.
- RuntimeError
- It is a bug, please report it to the github issue tracker
- (https://github.com/sympy/sympy/issues).
- Examples
- ========
- >>> from sympy import FiniteSet, Interval, not_empty_in, oo
- >>> from sympy.abc import x
- >>> not_empty_in(FiniteSet(x/2).intersect(Interval(0, 1)), x)
- Interval(0, 2)
- >>> not_empty_in(FiniteSet(x, x**2).intersect(Interval(1, 2)), x)
- Union(Interval(1, 2), Interval(-sqrt(2), -1))
- >>> not_empty_in(FiniteSet(x**2/(x + 2)).intersect(Interval(1, oo)), x)
- Union(Interval.Lopen(-2, -1), Interval(2, oo))
- """
- # TODO: handle piecewise defined functions
- # TODO: handle transcendental functions
- # TODO: handle multivariate functions
- if len(syms) == 0:
- raise ValueError("One or more symbols must be given in syms.")
- if finset_intersection is S.EmptySet:
- return S.EmptySet
- if isinstance(finset_intersection, Union):
- elm_in_sets = finset_intersection.args[0]
- return Union(not_empty_in(finset_intersection.args[1], *syms),
- elm_in_sets)
- if isinstance(finset_intersection, FiniteSet):
- finite_set = finset_intersection
- _sets = S.Reals
- else:
- finite_set = finset_intersection.args[1]
- _sets = finset_intersection.args[0]
- if not isinstance(finite_set, FiniteSet):
- raise ValueError('A FiniteSet must be given, not %s: %s' %
- (type(finite_set), finite_set))
- if len(syms) == 1:
- symb = syms[0]
- else:
- raise NotImplementedError('more than one variables %s not handled' %
- (syms,))
- def elm_domain(expr, intrvl):
- """ Finds the domain of an expression in any given interval """
- from sympy.solvers.solveset import solveset
- _start = intrvl.start
- _end = intrvl.end
- _singularities = solveset(expr.as_numer_denom()[1], symb,
- domain=S.Reals)
- if intrvl.right_open:
- if _end is S.Infinity:
- _domain1 = S.Reals
- else:
- _domain1 = solveset(expr < _end, symb, domain=S.Reals)
- else:
- _domain1 = solveset(expr <= _end, symb, domain=S.Reals)
- if intrvl.left_open:
- if _start is S.NegativeInfinity:
- _domain2 = S.Reals
- else:
- _domain2 = solveset(expr > _start, symb, domain=S.Reals)
- else:
- _domain2 = solveset(expr >= _start, symb, domain=S.Reals)
- # domain in the interval
- expr_with_sing = Intersection(_domain1, _domain2)
- expr_domain = Complement(expr_with_sing, _singularities)
- return expr_domain
- if isinstance(_sets, Interval):
- return Union(*[elm_domain(element, _sets) for element in finite_set])
- if isinstance(_sets, Union):
- _domain = S.EmptySet
- for intrvl in _sets.args:
- _domain_element = Union(*[elm_domain(element, intrvl)
- for element in finite_set])
- _domain = Union(_domain, _domain_element)
- return _domain
- def periodicity(f, symbol, check=False):
- """
- Tests the given function for periodicity in the given symbol.
- Parameters
- ==========
- f : :py:class:`~.Expr`.
- The concerned function.
- symbol : :py:class:`~.Symbol`
- The variable for which the period is to be determined.
- check : bool, optional
- The flag to verify whether the value being returned is a period or not.
- Returns
- =======
- period
- The period of the function is returned.
- ``None`` is returned when the function is aperiodic or has a complex period.
- The value of $0$ is returned as the period of a constant function.
- Raises
- ======
- NotImplementedError
- The value of the period computed cannot be verified.
- Notes
- =====
- Currently, we do not support functions with a complex period.
- The period of functions having complex periodic values such
- as ``exp``, ``sinh`` is evaluated to ``None``.
- The value returned might not be the "fundamental" period of the given
- function i.e. it may not be the smallest periodic value of the function.
- The verification of the period through the ``check`` flag is not reliable
- due to internal simplification of the given expression. Hence, it is set
- to ``False`` by default.
- Examples
- ========
- >>> from sympy import periodicity, Symbol, sin, cos, tan, exp
- >>> x = Symbol('x')
- >>> f = sin(x) + sin(2*x) + sin(3*x)
- >>> periodicity(f, x)
- 2*pi
- >>> periodicity(sin(x)*cos(x), x)
- pi
- >>> periodicity(exp(tan(2*x) - 1), x)
- pi/2
- >>> periodicity(sin(4*x)**cos(2*x), x)
- pi
- >>> periodicity(exp(x), x)
- """
- if symbol.kind is not NumberKind:
- raise NotImplementedError("Cannot use symbol of kind %s" % symbol.kind)
- temp = Dummy('x', real=True)
- f = f.subs(symbol, temp)
- symbol = temp
- def _check(orig_f, period):
- '''Return the checked period or raise an error.'''
- new_f = orig_f.subs(symbol, symbol + period)
- if new_f.equals(orig_f):
- return period
- else:
- raise NotImplementedError(filldedent('''
- The period of the given function cannot be verified.
- When `%s` was replaced with `%s + %s` in `%s`, the result
- was `%s` which was not recognized as being the same as
- the original function.
- So either the period was wrong or the two forms were
- not recognized as being equal.
- Set check=False to obtain the value.''' %
- (symbol, symbol, period, orig_f, new_f)))
- orig_f = f
- period = None
- if isinstance(f, Relational):
- f = f.lhs - f.rhs
- f = simplify(f)
- if symbol not in f.free_symbols:
- return S.Zero
- if isinstance(f, TrigonometricFunction):
- try:
- period = f.period(symbol)
- except NotImplementedError:
- pass
- if isinstance(f, Abs):
- arg = f.args[0]
- if isinstance(arg, (sec, csc, cos)):
- # all but tan and cot might have a
- # a period that is half as large
- # so recast as sin
- arg = sin(arg.args[0])
- period = periodicity(arg, symbol)
- if period is not None and isinstance(arg, sin):
- # the argument of Abs was a trigonometric other than
- # cot or tan; test to see if the half-period
- # is valid. Abs(arg) has behaviour equivalent to
- # orig_f, so use that for test:
- orig_f = Abs(arg)
- try:
- return _check(orig_f, period/2)
- except NotImplementedError as err:
- if check:
- raise NotImplementedError(err)
- # else let new orig_f and period be
- # checked below
- if isinstance(f, exp) or (f.is_Pow and f.base == S.Exp1):
- f = Pow(S.Exp1, expand_mul(f.exp))
- if im(f) != 0:
- period_real = periodicity(re(f), symbol)
- period_imag = periodicity(im(f), symbol)
- if period_real is not None and period_imag is not None:
- period = lcim([period_real, period_imag])
- if f.is_Pow and f.base != S.Exp1:
- base, expo = f.args
- base_has_sym = base.has(symbol)
- expo_has_sym = expo.has(symbol)
- if base_has_sym and not expo_has_sym:
- period = periodicity(base, symbol)
- elif expo_has_sym and not base_has_sym:
- period = periodicity(expo, symbol)
- else:
- period = _periodicity(f.args, symbol)
- elif f.is_Mul:
- coeff, g = f.as_independent(symbol, as_Add=False)
- if isinstance(g, TrigonometricFunction) or coeff is not S.One:
- period = periodicity(g, symbol)
- else:
- period = _periodicity(g.args, symbol)
- elif f.is_Add:
- k, g = f.as_independent(symbol)
- if k is not S.Zero:
- return periodicity(g, symbol)
- period = _periodicity(g.args, symbol)
- elif isinstance(f, Mod):
- a, n = f.args
- if a == symbol:
- period = n
- elif isinstance(a, TrigonometricFunction):
- period = periodicity(a, symbol)
- #check if 'f' is linear in 'symbol'
- elif (a.is_polynomial(symbol) and degree(a, symbol) == 1 and
- symbol not in n.free_symbols):
- period = Abs(n / a.diff(symbol))
- elif isinstance(f, Piecewise):
- pass # not handling Piecewise yet as the return type is not favorable
- elif period is None:
- from sympy.solvers.decompogen import compogen, decompogen
- g_s = decompogen(f, symbol)
- num_of_gs = len(g_s)
- if num_of_gs > 1:
- for index, g in enumerate(reversed(g_s)):
- start_index = num_of_gs - 1 - index
- g = compogen(g_s[start_index:], symbol)
- if g not in (orig_f, f): # Fix for issue 12620
- period = periodicity(g, symbol)
- if period is not None:
- break
- if period is not None:
- if check:
- return _check(orig_f, period)
- return period
- return None
- def _periodicity(args, symbol):
- """
- Helper for `periodicity` to find the period of a list of simpler
- functions.
- It uses the `lcim` method to find the least common period of
- all the functions.
- Parameters
- ==========
- args : Tuple of :py:class:`~.Symbol`
- All the symbols present in a function.
- symbol : :py:class:`~.Symbol`
- The symbol over which the function is to be evaluated.
- Returns
- =======
- period
- The least common period of the function for all the symbols
- of the function.
- ``None`` if for at least one of the symbols the function is aperiodic.
- """
- periods = []
- for f in args:
- period = periodicity(f, symbol)
- if period is None:
- return None
- if period is not S.Zero:
- periods.append(period)
- if len(periods) > 1:
- return lcim(periods)
- if periods:
- return periods[0]
- def lcim(numbers):
- """Returns the least common integral multiple of a list of numbers.
- The numbers can be rational or irrational or a mixture of both.
- `None` is returned for incommensurable numbers.
- Parameters
- ==========
- numbers : list
- Numbers (rational and/or irrational) for which lcim is to be found.
- Returns
- =======
- number
- lcim if it exists, otherwise ``None`` for incommensurable numbers.
- Examples
- ========
- >>> from sympy.calculus.util import lcim
- >>> from sympy import S, pi
- >>> lcim([S(1)/2, S(3)/4, S(5)/6])
- 15/2
- >>> lcim([2*pi, 3*pi, pi, pi/2])
- 6*pi
- >>> lcim([S(1), 2*pi])
- """
- result = None
- if all(num.is_irrational for num in numbers):
- factorized_nums = list(map(lambda num: num.factor(), numbers))
- factors_num = list(
- map(lambda num: num.as_coeff_Mul(),
- factorized_nums))
- term = factors_num[0][1]
- if all(factor == term for coeff, factor in factors_num):
- common_term = term
- coeffs = [coeff for coeff, factor in factors_num]
- result = lcm_list(coeffs) * common_term
- elif all(num.is_rational for num in numbers):
- result = lcm_list(numbers)
- else:
- pass
- return result
- def is_convex(f, *syms, domain=S.Reals):
- r"""Determines the convexity of the function passed in the argument.
- Parameters
- ==========
- f : :py:class:`~.Expr`
- The concerned function.
- syms : Tuple of :py:class:`~.Symbol`
- The variables with respect to which the convexity is to be determined.
- domain : :py:class:`~.Interval`, optional
- The domain over which the convexity of the function has to be checked.
- If unspecified, S.Reals will be the default domain.
- Returns
- =======
- bool
- The method returns ``True`` if the function is convex otherwise it
- returns ``False``.
- Raises
- ======
- NotImplementedError
- The check for the convexity of multivariate functions is not implemented yet.
- Notes
- =====
- To determine concavity of a function pass `-f` as the concerned function.
- To determine logarithmic convexity of a function pass `\log(f)` as
- concerned function.
- To determine logartihmic concavity of a function pass `-\log(f)` as
- concerned function.
- Currently, convexity check of multivariate functions is not handled.
- Examples
- ========
- >>> from sympy import is_convex, symbols, exp, oo, Interval
- >>> x = symbols('x')
- >>> is_convex(exp(x), x)
- True
- >>> is_convex(x**3, x, domain = Interval(-1, oo))
- False
- References
- ==========
- .. [1] https://en.wikipedia.org/wiki/Convex_function
- .. [2] http://www.ifp.illinois.edu/~angelia/L3_convfunc.pdf
- .. [3] https://en.wikipedia.org/wiki/Logarithmically_convex_function
- .. [4] https://en.wikipedia.org/wiki/Logarithmically_concave_function
- .. [5] https://en.wikipedia.org/wiki/Concave_function
- """
- if len(syms) > 1:
- raise NotImplementedError(
- "The check for the convexity of multivariate functions is not implemented yet.")
- from sympy.solvers.inequalities import solve_univariate_inequality
- f = _sympify(f)
- var = syms[0]
- condition = f.diff(var, 2) < 0
- if solve_univariate_inequality(condition, var, False, domain):
- return False
- return True
- def stationary_points(f, symbol, domain=S.Reals):
- """
- Returns the stationary points of a function (where derivative of the
- function is 0) in the given domain.
- Parameters
- ==========
- f : :py:class:`~.Expr`
- The concerned function.
- symbol : :py:class:`~.Symbol`
- The variable for which the stationary points are to be determined.
- domain : :py:class:`~.Interval`
- The domain over which the stationary points have to be checked.
- If unspecified, ``S.Reals`` will be the default domain.
- Returns
- =======
- Set
- A set of stationary points for the function. If there are no
- stationary point, an :py:class:`~.EmptySet` is returned.
- Examples
- ========
- >>> from sympy import Interval, Symbol, S, sin, pi, pprint, stationary_points
- >>> x = Symbol('x')
- >>> stationary_points(1/x, x, S.Reals)
- EmptySet
- >>> pprint(stationary_points(sin(x), x), use_unicode=False)
- pi 3*pi
- {2*n*pi + -- | n in Integers} U {2*n*pi + ---- | n in Integers}
- 2 2
- >>> stationary_points(sin(x),x, Interval(0, 4*pi))
- {pi/2, 3*pi/2, 5*pi/2, 7*pi/2}
- """
- from sympy.solvers.solveset import solveset
- if domain is S.EmptySet:
- return S.EmptySet
- domain = continuous_domain(f, symbol, domain)
- set = solveset(diff(f, symbol), symbol, domain)
- return set
- def maximum(f, symbol, domain=S.Reals):
- """
- Returns the maximum value of a function in the given domain.
- Parameters
- ==========
- f : :py:class:`~.Expr`
- The concerned function.
- symbol : :py:class:`~.Symbol`
- The variable for maximum value needs to be determined.
- domain : :py:class:`~.Interval`
- The domain over which the maximum have to be checked.
- If unspecified, then the global maximum is returned.
- Returns
- =======
- number
- Maximum value of the function in given domain.
- Examples
- ========
- >>> from sympy import Interval, Symbol, S, sin, cos, pi, maximum
- >>> x = Symbol('x')
- >>> f = -x**2 + 2*x + 5
- >>> maximum(f, x, S.Reals)
- 6
- >>> maximum(sin(x), x, Interval(-pi, pi/4))
- sqrt(2)/2
- >>> maximum(sin(x)*cos(x), x)
- 1/2
- """
- if isinstance(symbol, Symbol):
- if domain is S.EmptySet:
- raise ValueError("Maximum value not defined for empty domain.")
- return function_range(f, symbol, domain).sup
- else:
- raise ValueError("%s is not a valid symbol." % symbol)
- def minimum(f, symbol, domain=S.Reals):
- """
- Returns the minimum value of a function in the given domain.
- Parameters
- ==========
- f : :py:class:`~.Expr`
- The concerned function.
- symbol : :py:class:`~.Symbol`
- The variable for minimum value needs to be determined.
- domain : :py:class:`~.Interval`
- The domain over which the minimum have to be checked.
- If unspecified, then the global minimum is returned.
- Returns
- =======
- number
- Minimum value of the function in the given domain.
- Examples
- ========
- >>> from sympy import Interval, Symbol, S, sin, cos, minimum
- >>> x = Symbol('x')
- >>> f = x**2 + 2*x + 5
- >>> minimum(f, x, S.Reals)
- 4
- >>> minimum(sin(x), x, Interval(2, 3))
- sin(3)
- >>> minimum(sin(x)*cos(x), x)
- -1/2
- """
- if isinstance(symbol, Symbol):
- if domain is S.EmptySet:
- raise ValueError("Minimum value not defined for empty domain.")
- return function_range(f, symbol, domain).inf
- else:
- raise ValueError("%s is not a valid symbol." % symbol)
|