Coverage for /usr/lib/python3/dist-packages/sympy/calculus/singularities.py: 27%
51 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
1"""
2Singularities
3=============
5This module implements algorithms for finding singularities for a function
6and identifying types of functions.
8The differential calculus methods in this module include methods to identify
9the following function types in the given ``Interval``:
10- Increasing
11- Strictly Increasing
12- Decreasing
13- Strictly Decreasing
14- Monotonic
16"""
18from sympy.core.power import Pow
19from sympy.core.singleton import S
20from sympy.core.symbol import Symbol
21from sympy.core.sympify import sympify
22from sympy.functions.elementary.exponential import log
23from sympy.functions.elementary.trigonometric import sec, csc, cot, tan, cos
24from sympy.utilities.misc import filldedent
27def singularities(expression, symbol, domain=None):
28 """
29 Find singularities of a given function.
31 Parameters
32 ==========
34 expression : Expr
35 The target function in which singularities need to be found.
36 symbol : Symbol
37 The symbol over the values of which the singularity in
38 expression in being searched for.
40 Returns
41 =======
43 Set
44 A set of values for ``symbol`` for which ``expression`` has a
45 singularity. An ``EmptySet`` is returned if ``expression`` has no
46 singularities for any given value of ``Symbol``.
48 Raises
49 ======
51 NotImplementedError
52 Methods for determining the singularities of this function have
53 not been developed.
55 Notes
56 =====
58 This function does not find non-isolated singularities
59 nor does it find branch points of the expression.
61 Currently supported functions are:
62 - univariate continuous (real or complex) functions
64 References
65 ==========
67 .. [1] https://en.wikipedia.org/wiki/Mathematical_singularity
69 Examples
70 ========
72 >>> from sympy import singularities, Symbol, log
73 >>> x = Symbol('x', real=True)
74 >>> y = Symbol('y', real=False)
75 >>> singularities(x**2 + x + 1, x)
76 EmptySet
77 >>> singularities(1/(x + 1), x)
78 {-1}
79 >>> singularities(1/(y**2 + 1), y)
80 {-I, I}
81 >>> singularities(1/(y**3 + 1), y)
82 {-1, 1/2 - sqrt(3)*I/2, 1/2 + sqrt(3)*I/2}
83 >>> singularities(log(x), x)
84 {0}
86 """
87 from sympy.solvers.solveset import solveset
89 if domain is None:
90 domain = S.Reals if symbol.is_real else S.Complexes
91 try:
92 sings = S.EmptySet
93 for i in expression.rewrite([sec, csc, cot, tan], cos).atoms(Pow):
94 if i.exp.is_infinite:
95 raise NotImplementedError
96 if i.exp.is_negative:
97 sings += solveset(i.base, symbol, domain)
98 for i in expression.atoms(log):
99 sings += solveset(i.args[0], symbol, domain)
100 return sings
101 except NotImplementedError:
102 raise NotImplementedError(filldedent('''
103 Methods for determining the singularities
104 of this function have not been developed.'''))
107###########################################################################
108# DIFFERENTIAL CALCULUS METHODS #
109###########################################################################
112def monotonicity_helper(expression, predicate, interval=S.Reals, symbol=None):
113 """
114 Helper function for functions checking function monotonicity.
116 Parameters
117 ==========
119 expression : Expr
120 The target function which is being checked
121 predicate : function
122 The property being tested for. The function takes in an integer
123 and returns a boolean. The integer input is the derivative and
124 the boolean result should be true if the property is being held,
125 and false otherwise.
126 interval : Set, optional
127 The range of values in which we are testing, defaults to all reals.
128 symbol : Symbol, optional
129 The symbol present in expression which gets varied over the given range.
131 It returns a boolean indicating whether the interval in which
132 the function's derivative satisfies given predicate is a superset
133 of the given interval.
135 Returns
136 =======
138 Boolean
139 True if ``predicate`` is true for all the derivatives when ``symbol``
140 is varied in ``range``, False otherwise.
142 """
143 from sympy.solvers.solveset import solveset
145 expression = sympify(expression)
146 free = expression.free_symbols
148 if symbol is None:
149 if len(free) > 1:
150 raise NotImplementedError(
151 'The function has not yet been implemented'
152 ' for all multivariate expressions.'
153 )
155 variable = symbol or (free.pop() if free else Symbol('x'))
156 derivative = expression.diff(variable)
157 predicate_interval = solveset(predicate(derivative), variable, S.Reals)
158 return interval.is_subset(predicate_interval)
161def is_increasing(expression, interval=S.Reals, symbol=None):
162 """
163 Return whether the function is increasing in the given interval.
165 Parameters
166 ==========
168 expression : Expr
169 The target function which is being checked.
170 interval : Set, optional
171 The range of values in which we are testing (defaults to set of
172 all real numbers).
173 symbol : Symbol, optional
174 The symbol present in expression which gets varied over the given range.
176 Returns
177 =======
179 Boolean
180 True if ``expression`` is increasing (either strictly increasing or
181 constant) in the given ``interval``, False otherwise.
183 Examples
184 ========
186 >>> from sympy import is_increasing
187 >>> from sympy.abc import x, y
188 >>> from sympy import S, Interval, oo
189 >>> is_increasing(x**3 - 3*x**2 + 4*x, S.Reals)
190 True
191 >>> is_increasing(-x**2, Interval(-oo, 0))
192 True
193 >>> is_increasing(-x**2, Interval(0, oo))
194 False
195 >>> is_increasing(4*x**3 - 6*x**2 - 72*x + 30, Interval(-2, 3))
196 False
197 >>> is_increasing(x**2 + y, Interval(1, 2), x)
198 True
200 """
201 return monotonicity_helper(expression, lambda x: x >= 0, interval, symbol)
204def is_strictly_increasing(expression, interval=S.Reals, symbol=None):
205 """
206 Return whether the function is strictly increasing in the given interval.
208 Parameters
209 ==========
211 expression : Expr
212 The target function which is being checked.
213 interval : Set, optional
214 The range of values in which we are testing (defaults to set of
215 all real numbers).
216 symbol : Symbol, optional
217 The symbol present in expression which gets varied over the given range.
219 Returns
220 =======
222 Boolean
223 True if ``expression`` is strictly increasing in the given ``interval``,
224 False otherwise.
226 Examples
227 ========
229 >>> from sympy import is_strictly_increasing
230 >>> from sympy.abc import x, y
231 >>> from sympy import Interval, oo
232 >>> is_strictly_increasing(4*x**3 - 6*x**2 - 72*x + 30, Interval.Ropen(-oo, -2))
233 True
234 >>> is_strictly_increasing(4*x**3 - 6*x**2 - 72*x + 30, Interval.Lopen(3, oo))
235 True
236 >>> is_strictly_increasing(4*x**3 - 6*x**2 - 72*x + 30, Interval.open(-2, 3))
237 False
238 >>> is_strictly_increasing(-x**2, Interval(0, oo))
239 False
240 >>> is_strictly_increasing(-x**2 + y, Interval(-oo, 0), x)
241 False
243 """
244 return monotonicity_helper(expression, lambda x: x > 0, interval, symbol)
247def is_decreasing(expression, interval=S.Reals, symbol=None):
248 """
249 Return whether the function is decreasing in the given interval.
251 Parameters
252 ==========
254 expression : Expr
255 The target function which is being checked.
256 interval : Set, optional
257 The range of values in which we are testing (defaults to set of
258 all real numbers).
259 symbol : Symbol, optional
260 The symbol present in expression which gets varied over the given range.
262 Returns
263 =======
265 Boolean
266 True if ``expression`` is decreasing (either strictly decreasing or
267 constant) in the given ``interval``, False otherwise.
269 Examples
270 ========
272 >>> from sympy import is_decreasing
273 >>> from sympy.abc import x, y
274 >>> from sympy import S, Interval, oo
275 >>> is_decreasing(1/(x**2 - 3*x), Interval.open(S(3)/2, 3))
276 True
277 >>> is_decreasing(1/(x**2 - 3*x), Interval.open(1.5, 3))
278 True
279 >>> is_decreasing(1/(x**2 - 3*x), Interval.Lopen(3, oo))
280 True
281 >>> is_decreasing(1/(x**2 - 3*x), Interval.Ropen(-oo, S(3)/2))
282 False
283 >>> is_decreasing(1/(x**2 - 3*x), Interval.Ropen(-oo, 1.5))
284 False
285 >>> is_decreasing(-x**2, Interval(-oo, 0))
286 False
287 >>> is_decreasing(-x**2 + y, Interval(-oo, 0), x)
288 False
290 """
291 return monotonicity_helper(expression, lambda x: x <= 0, interval, symbol)
294def is_strictly_decreasing(expression, interval=S.Reals, symbol=None):
295 """
296 Return whether the function is strictly decreasing in the given interval.
298 Parameters
299 ==========
301 expression : Expr
302 The target function which is being checked.
303 interval : Set, optional
304 The range of values in which we are testing (defaults to set of
305 all real numbers).
306 symbol : Symbol, optional
307 The symbol present in expression which gets varied over the given range.
309 Returns
310 =======
312 Boolean
313 True if ``expression`` is strictly decreasing in the given ``interval``,
314 False otherwise.
316 Examples
317 ========
319 >>> from sympy import is_strictly_decreasing
320 >>> from sympy.abc import x, y
321 >>> from sympy import S, Interval, oo
322 >>> is_strictly_decreasing(1/(x**2 - 3*x), Interval.Lopen(3, oo))
323 True
324 >>> is_strictly_decreasing(1/(x**2 - 3*x), Interval.Ropen(-oo, S(3)/2))
325 False
326 >>> is_strictly_decreasing(1/(x**2 - 3*x), Interval.Ropen(-oo, 1.5))
327 False
328 >>> is_strictly_decreasing(-x**2, Interval(-oo, 0))
329 False
330 >>> is_strictly_decreasing(-x**2 + y, Interval(-oo, 0), x)
331 False
333 """
334 return monotonicity_helper(expression, lambda x: x < 0, interval, symbol)
337def is_monotonic(expression, interval=S.Reals, symbol=None):
338 """
339 Return whether the function is monotonic in the given interval.
341 Parameters
342 ==========
344 expression : Expr
345 The target function which is being checked.
346 interval : Set, optional
347 The range of values in which we are testing (defaults to set of
348 all real numbers).
349 symbol : Symbol, optional
350 The symbol present in expression which gets varied over the given range.
352 Returns
353 =======
355 Boolean
356 True if ``expression`` is monotonic in the given ``interval``,
357 False otherwise.
359 Raises
360 ======
362 NotImplementedError
363 Monotonicity check has not been implemented for the queried function.
365 Examples
366 ========
368 >>> from sympy import is_monotonic
369 >>> from sympy.abc import x, y
370 >>> from sympy import S, Interval, oo
371 >>> is_monotonic(1/(x**2 - 3*x), Interval.open(S(3)/2, 3))
372 True
373 >>> is_monotonic(1/(x**2 - 3*x), Interval.open(1.5, 3))
374 True
375 >>> is_monotonic(1/(x**2 - 3*x), Interval.Lopen(3, oo))
376 True
377 >>> is_monotonic(x**3 - 3*x**2 + 4*x, S.Reals)
378 True
379 >>> is_monotonic(-x**2, S.Reals)
380 False
381 >>> is_monotonic(x**2 + y + 1, Interval(1, 2), x)
382 True
384 """
385 from sympy.solvers.solveset import solveset
387 expression = sympify(expression)
389 free = expression.free_symbols
390 if symbol is None and len(free) > 1:
391 raise NotImplementedError(
392 'is_monotonic has not yet been implemented'
393 ' for all multivariate expressions.'
394 )
396 variable = symbol or (free.pop() if free else Symbol('x'))
397 turning_points = solveset(expression.diff(variable), variable, interval)
398 return interval.intersection(turning_points) is S.EmptySet