MTerryJack commited on
Commit
0a564b5
·
verified ·
1 Parent(s): b396fc1

Add files using upload-large-folder tool

Browse files
Files changed (50) hide show
  1. .venv/lib/python3.13/site-packages/sympy/assumptions/handlers/__init__.py +13 -0
  2. .venv/lib/python3.13/site-packages/sympy/assumptions/handlers/calculus.py +273 -0
  3. .venv/lib/python3.13/site-packages/sympy/assumptions/handlers/common.py +164 -0
  4. .venv/lib/python3.13/site-packages/sympy/assumptions/handlers/matrices.py +716 -0
  5. .venv/lib/python3.13/site-packages/sympy/assumptions/handlers/ntheory.py +279 -0
  6. .venv/lib/python3.13/site-packages/sympy/assumptions/handlers/order.py +440 -0
  7. .venv/lib/python3.13/site-packages/sympy/assumptions/handlers/sets.py +816 -0
  8. .venv/lib/python3.13/site-packages/sympy/assumptions/predicates/__init__.py +5 -0
  9. .venv/lib/python3.13/site-packages/sympy/assumptions/predicates/calculus.py +82 -0
  10. .venv/lib/python3.13/site-packages/sympy/assumptions/predicates/common.py +81 -0
  11. .venv/lib/python3.13/site-packages/sympy/assumptions/predicates/ntheory.py +126 -0
  12. .venv/lib/python3.13/site-packages/sympy/assumptions/predicates/sets.py +399 -0
  13. .venv/lib/python3.13/site-packages/sympy/assumptions/relation/__init__.py +13 -0
  14. .venv/lib/python3.13/site-packages/sympy/assumptions/relation/binrel.py +212 -0
  15. .venv/lib/python3.13/site-packages/sympy/assumptions/relation/equality.py +302 -0
  16. .venv/lib/python3.13/site-packages/sympy/assumptions/tests/__init__.py +0 -0
  17. .venv/lib/python3.13/site-packages/sympy/assumptions/tests/test_assumptions_2.py +35 -0
  18. .venv/lib/python3.13/site-packages/sympy/assumptions/tests/test_context.py +39 -0
  19. .venv/lib/python3.13/site-packages/sympy/assumptions/tests/test_matrices.py +283 -0
  20. .venv/lib/python3.13/site-packages/sympy/assumptions/tests/test_query.py +0 -0
  21. .venv/lib/python3.13/site-packages/sympy/assumptions/tests/test_refine.py +227 -0
  22. .venv/lib/python3.13/site-packages/sympy/assumptions/tests/test_rel_queries.py +172 -0
  23. .venv/lib/python3.13/site-packages/sympy/assumptions/tests/test_satask.py +378 -0
  24. .venv/lib/python3.13/site-packages/sympy/assumptions/tests/test_sathandlers.py +50 -0
  25. .venv/lib/python3.13/site-packages/sympy/assumptions/tests/test_wrapper.py +39 -0
  26. .venv/lib/python3.13/site-packages/sympy/integrals/benchmarks/__init__.py +0 -0
  27. .venv/lib/python3.13/site-packages/sympy/integrals/benchmarks/bench_integrate.py +21 -0
  28. .venv/lib/python3.13/site-packages/sympy/integrals/benchmarks/bench_trigintegrate.py +13 -0
  29. .venv/lib/python3.13/site-packages/sympy/integrals/tests/__init__.py +0 -0
  30. .venv/lib/python3.13/site-packages/sympy/integrals/tests/test_deltafunctions.py +79 -0
  31. .venv/lib/python3.13/site-packages/sympy/integrals/tests/test_failing_integrals.py +277 -0
  32. .venv/lib/python3.13/site-packages/sympy/integrals/tests/test_heurisch.py +417 -0
  33. .venv/lib/python3.13/site-packages/sympy/integrals/tests/test_integrals.py +2187 -0
  34. .venv/lib/python3.13/site-packages/sympy/integrals/tests/test_intpoly.py +627 -0
  35. .venv/lib/python3.13/site-packages/sympy/integrals/tests/test_laplace.py +774 -0
  36. .venv/lib/python3.13/site-packages/sympy/integrals/tests/test_lineintegrals.py +13 -0
  37. .venv/lib/python3.13/site-packages/sympy/integrals/tests/test_manual.py +714 -0
  38. .venv/lib/python3.13/site-packages/sympy/integrals/tests/test_meijerint.py +774 -0
  39. .venv/lib/python3.13/site-packages/sympy/integrals/tests/test_prde.py +322 -0
  40. .venv/lib/python3.13/site-packages/sympy/integrals/tests/test_quadrature.py +601 -0
  41. .venv/lib/python3.13/site-packages/sympy/integrals/tests/test_rationaltools.py +183 -0
  42. .venv/lib/python3.13/site-packages/sympy/integrals/tests/test_rde.py +202 -0
  43. .venv/lib/python3.13/site-packages/sympy/integrals/tests/test_risch.py +763 -0
  44. .venv/lib/python3.13/site-packages/sympy/integrals/tests/test_singularityfunctions.py +22 -0
  45. .venv/lib/python3.13/site-packages/sympy/integrals/tests/test_transforms.py +637 -0
  46. .venv/lib/python3.13/site-packages/sympy/integrals/tests/test_trigonometry.py +98 -0
  47. .venv/lib/python3.13/site-packages/sympy/testing/tests/diagnose_imports.py +216 -0
  48. .venv/lib/python3.13/site-packages/sympy/testing/tests/test_module_imports.py +42 -0
  49. .venv/lib/python3.13/site-packages/sympy/testing/tests/test_pytest.py +211 -0
  50. .venv/lib/python3.13/site-packages/sympy/testing/tests/test_runtests_pytest.py +171 -0
.venv/lib/python3.13/site-packages/sympy/assumptions/handlers/__init__.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Multipledispatch handlers for ``Predicate`` are implemented here.
3
+ Handlers in this module are not directly imported to other modules in
4
+ order to avoid circular import problem.
5
+ """
6
+
7
+ from .common import (AskHandler, CommonHandler,
8
+ test_closed_group)
9
+
10
+ __all__ = [
11
+ 'AskHandler', 'CommonHandler',
12
+ 'test_closed_group'
13
+ ]
.venv/lib/python3.13/site-packages/sympy/assumptions/handlers/calculus.py ADDED
@@ -0,0 +1,273 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ This module contains query handlers responsible for calculus queries:
3
+ infinitesimal, finite, etc.
4
+ """
5
+
6
+ from sympy.assumptions import Q, ask
7
+ from sympy.core import Expr, Add, Mul, Pow, Symbol
8
+ from sympy.core.numbers import (NegativeInfinity, GoldenRatio,
9
+ Infinity, Exp1, ComplexInfinity, ImaginaryUnit, NaN, Number, Pi, E,
10
+ TribonacciConstant)
11
+ from sympy.functions import cos, exp, log, sign, sin
12
+ from sympy.logic.boolalg import conjuncts
13
+
14
+ from ..predicates.calculus import (FinitePredicate, InfinitePredicate,
15
+ PositiveInfinitePredicate, NegativeInfinitePredicate)
16
+
17
+
18
+ # FinitePredicate
19
+
20
+
21
+ @FinitePredicate.register(Symbol)
22
+ def _(expr, assumptions):
23
+ """
24
+ Handles Symbol.
25
+ """
26
+ if expr.is_finite is not None:
27
+ return expr.is_finite
28
+ if Q.finite(expr) in conjuncts(assumptions):
29
+ return True
30
+ return None
31
+
32
+ @FinitePredicate.register(Add)
33
+ def _(expr, assumptions):
34
+ """
35
+ Return True if expr is bounded, False if not and None if unknown.
36
+
37
+ Truth Table:
38
+
39
+ +-------+-----+-----------+-----------+
40
+ | | | | |
41
+ | | B | U | ? |
42
+ | | | | |
43
+ +-------+-----+---+---+---+---+---+---+
44
+ | | | | | | | | |
45
+ | | |'+'|'-'|'x'|'+'|'-'|'x'|
46
+ | | | | | | | | |
47
+ +-------+-----+---+---+---+---+---+---+
48
+ | | | | |
49
+ | B | B | U | ? |
50
+ | | | | |
51
+ +---+---+-----+---+---+---+---+---+---+
52
+ | | | | | | | | | |
53
+ | |'+'| | U | ? | ? | U | ? | ? |
54
+ | | | | | | | | | |
55
+ | +---+-----+---+---+---+---+---+---+
56
+ | | | | | | | | | |
57
+ | U |'-'| | ? | U | ? | ? | U | ? |
58
+ | | | | | | | | | |
59
+ | +---+-----+---+---+---+---+---+---+
60
+ | | | | | |
61
+ | |'x'| | ? | ? |
62
+ | | | | | |
63
+ +---+---+-----+---+---+---+---+---+---+
64
+ | | | | |
65
+ | ? | | | ? |
66
+ | | | | |
67
+ +-------+-----+-----------+---+---+---+
68
+
69
+ * 'B' = Bounded
70
+
71
+ * 'U' = Unbounded
72
+
73
+ * '?' = unknown boundedness
74
+
75
+ * '+' = positive sign
76
+
77
+ * '-' = negative sign
78
+
79
+ * 'x' = sign unknown
80
+
81
+ * All Bounded -> True
82
+
83
+ * 1 Unbounded and the rest Bounded -> False
84
+
85
+ * >1 Unbounded, all with same known sign -> False
86
+
87
+ * Any Unknown and unknown sign -> None
88
+
89
+ * Else -> None
90
+
91
+ When the signs are not the same you can have an undefined
92
+ result as in oo - oo, hence 'bounded' is also undefined.
93
+ """
94
+ sign = -1 # sign of unknown or infinite
95
+ result = True
96
+ for arg in expr.args:
97
+ _bounded = ask(Q.finite(arg), assumptions)
98
+ if _bounded:
99
+ continue
100
+ s = ask(Q.extended_positive(arg), assumptions)
101
+ # if there has been more than one sign or if the sign of this arg
102
+ # is None and Bounded is None or there was already
103
+ # an unknown sign, return None
104
+ if sign != -1 and s != sign or \
105
+ s is None and None in (_bounded, sign):
106
+ return None
107
+ else:
108
+ sign = s
109
+ # once False, do not change
110
+ if result is not False:
111
+ result = _bounded
112
+ return result
113
+
114
+ @FinitePredicate.register(Mul)
115
+ def _(expr, assumptions):
116
+ """
117
+ Return True if expr is bounded, False if not and None if unknown.
118
+
119
+ Truth Table:
120
+
121
+ +---+---+---+--------+
122
+ | | | | |
123
+ | | B | U | ? |
124
+ | | | | |
125
+ +---+---+---+---+----+
126
+ | | | | | |
127
+ | | | | s | /s |
128
+ | | | | | |
129
+ +---+---+---+---+----+
130
+ | | | | |
131
+ | B | B | U | ? |
132
+ | | | | |
133
+ +---+---+---+---+----+
134
+ | | | | | |
135
+ | U | | U | U | ? |
136
+ | | | | | |
137
+ +---+---+---+---+----+
138
+ | | | | |
139
+ | ? | | | ? |
140
+ | | | | |
141
+ +---+---+---+---+----+
142
+
143
+ * B = Bounded
144
+
145
+ * U = Unbounded
146
+
147
+ * ? = unknown boundedness
148
+
149
+ * s = signed (hence nonzero)
150
+
151
+ * /s = not signed
152
+ """
153
+ result = True
154
+ possible_zero = False
155
+ for arg in expr.args:
156
+ _bounded = ask(Q.finite(arg), assumptions)
157
+ if _bounded:
158
+ if ask(Q.zero(arg), assumptions) is not False:
159
+ if result is False:
160
+ return None
161
+ possible_zero = True
162
+ elif _bounded is None:
163
+ if result is None:
164
+ return None
165
+ if ask(Q.extended_nonzero(arg), assumptions) is None:
166
+ return None
167
+ if result is not False:
168
+ result = None
169
+ else:
170
+ if possible_zero:
171
+ return None
172
+ result = False
173
+ return result
174
+
175
+ @FinitePredicate.register(Pow)
176
+ def _(expr, assumptions):
177
+ """
178
+ * Unbounded ** NonZero -> Unbounded
179
+
180
+ * Bounded ** Bounded -> Bounded
181
+
182
+ * Abs()<=1 ** Positive -> Bounded
183
+
184
+ * Abs()>=1 ** Negative -> Bounded
185
+
186
+ * Otherwise unknown
187
+ """
188
+ if expr.base == E:
189
+ return ask(Q.finite(expr.exp), assumptions)
190
+
191
+ base_bounded = ask(Q.finite(expr.base), assumptions)
192
+ exp_bounded = ask(Q.finite(expr.exp), assumptions)
193
+ if base_bounded is None and exp_bounded is None: # Common Case
194
+ return None
195
+ if base_bounded is False and ask(Q.extended_nonzero(expr.exp), assumptions):
196
+ return False
197
+ if base_bounded and exp_bounded:
198
+ is_base_zero = ask(Q.zero(expr.base),assumptions)
199
+ is_exp_negative = ask(Q.negative(expr.exp),assumptions)
200
+ if is_base_zero is True and is_exp_negative is True:
201
+ return False
202
+ if is_base_zero is not False and is_exp_negative is not False:
203
+ return None
204
+ return True
205
+ if (abs(expr.base) <= 1) == True and ask(Q.extended_positive(expr.exp), assumptions):
206
+ return True
207
+ if (abs(expr.base) >= 1) == True and ask(Q.extended_negative(expr.exp), assumptions):
208
+ return True
209
+ if (abs(expr.base) >= 1) == True and exp_bounded is False:
210
+ return False
211
+ return None
212
+
213
+ @FinitePredicate.register(exp)
214
+ def _(expr, assumptions):
215
+ return ask(Q.finite(expr.exp), assumptions)
216
+
217
+ @FinitePredicate.register(log)
218
+ def _(expr, assumptions):
219
+ # After complex -> finite fact is registered to new assumption system,
220
+ # querying Q.infinite may be removed.
221
+ if ask(Q.infinite(expr.args[0]), assumptions):
222
+ return False
223
+ return ask(~Q.zero(expr.args[0]), assumptions)
224
+
225
+ @FinitePredicate.register_many(cos, sin, Number, Pi, Exp1, GoldenRatio,
226
+ TribonacciConstant, ImaginaryUnit, sign)
227
+ def _(expr, assumptions):
228
+ return True
229
+
230
+ @FinitePredicate.register_many(ComplexInfinity, Infinity, NegativeInfinity)
231
+ def _(expr, assumptions):
232
+ return False
233
+
234
+ @FinitePredicate.register(NaN)
235
+ def _(expr, assumptions):
236
+ return None
237
+
238
+
239
+ # InfinitePredicate
240
+
241
+
242
+ @InfinitePredicate.register(Expr)
243
+ def _(expr, assumptions):
244
+ is_finite = Q.finite(expr)._eval_ask(assumptions)
245
+ if is_finite is None:
246
+ return None
247
+ return not is_finite
248
+
249
+
250
+ # PositiveInfinitePredicate
251
+
252
+
253
+ @PositiveInfinitePredicate.register(Infinity)
254
+ def _(expr, assumptions):
255
+ return True
256
+
257
+
258
+ @PositiveInfinitePredicate.register_many(NegativeInfinity, ComplexInfinity)
259
+ def _(expr, assumptions):
260
+ return False
261
+
262
+
263
+ # NegativeInfinitePredicate
264
+
265
+
266
+ @NegativeInfinitePredicate.register(NegativeInfinity)
267
+ def _(expr, assumptions):
268
+ return True
269
+
270
+
271
+ @NegativeInfinitePredicate.register_many(Infinity, ComplexInfinity)
272
+ def _(expr, assumptions):
273
+ return False
.venv/lib/python3.13/site-packages/sympy/assumptions/handlers/common.py ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ This module defines base class for handlers and some core handlers:
3
+ ``Q.commutative`` and ``Q.is_true``.
4
+ """
5
+
6
+ from sympy.assumptions import Q, ask, AppliedPredicate
7
+ from sympy.core import Basic, Symbol
8
+ from sympy.core.logic import _fuzzy_group, fuzzy_and, fuzzy_or
9
+ from sympy.core.numbers import NaN, Number
10
+ from sympy.logic.boolalg import (And, BooleanTrue, BooleanFalse, conjuncts,
11
+ Equivalent, Implies, Not, Or)
12
+ from sympy.utilities.exceptions import sympy_deprecation_warning
13
+
14
+ from ..predicates.common import CommutativePredicate, IsTruePredicate
15
+
16
+
17
+ class AskHandler:
18
+ """Base class that all Ask Handlers must inherit."""
19
+ def __new__(cls, *args, **kwargs):
20
+ sympy_deprecation_warning(
21
+ """
22
+ The AskHandler system is deprecated. The AskHandler class should
23
+ be replaced with the multipledispatch handler of Predicate
24
+ """,
25
+ deprecated_since_version="1.8",
26
+ active_deprecations_target='deprecated-askhandler',
27
+ )
28
+ return super().__new__(cls, *args, **kwargs)
29
+
30
+
31
+ class CommonHandler(AskHandler):
32
+ # Deprecated
33
+ """Defines some useful methods common to most Handlers. """
34
+
35
+ @staticmethod
36
+ def AlwaysTrue(expr, assumptions):
37
+ return True
38
+
39
+ @staticmethod
40
+ def AlwaysFalse(expr, assumptions):
41
+ return False
42
+
43
+ @staticmethod
44
+ def AlwaysNone(expr, assumptions):
45
+ return None
46
+
47
+ NaN = AlwaysFalse
48
+
49
+
50
+ # CommutativePredicate
51
+
52
+ @CommutativePredicate.register(Symbol)
53
+ def _(expr, assumptions):
54
+ """Objects are expected to be commutative unless otherwise stated"""
55
+ assumps = conjuncts(assumptions)
56
+ if expr.is_commutative is not None:
57
+ return expr.is_commutative and not ~Q.commutative(expr) in assumps
58
+ if Q.commutative(expr) in assumps:
59
+ return True
60
+ elif ~Q.commutative(expr) in assumps:
61
+ return False
62
+ return True
63
+
64
+ @CommutativePredicate.register(Basic)
65
+ def _(expr, assumptions):
66
+ for arg in expr.args:
67
+ if not ask(Q.commutative(arg), assumptions):
68
+ return False
69
+ return True
70
+
71
+ @CommutativePredicate.register(Number)
72
+ def _(expr, assumptions):
73
+ return True
74
+
75
+ @CommutativePredicate.register(NaN)
76
+ def _(expr, assumptions):
77
+ return True
78
+
79
+
80
+ # IsTruePredicate
81
+
82
+ @IsTruePredicate.register(bool)
83
+ def _(expr, assumptions):
84
+ return expr
85
+
86
+ @IsTruePredicate.register(BooleanTrue)
87
+ def _(expr, assumptions):
88
+ return True
89
+
90
+ @IsTruePredicate.register(BooleanFalse)
91
+ def _(expr, assumptions):
92
+ return False
93
+
94
+ @IsTruePredicate.register(AppliedPredicate)
95
+ def _(expr, assumptions):
96
+ return ask(expr, assumptions)
97
+
98
+ @IsTruePredicate.register(Not)
99
+ def _(expr, assumptions):
100
+ arg = expr.args[0]
101
+ if arg.is_Symbol:
102
+ # symbol used as abstract boolean object
103
+ return None
104
+ value = ask(arg, assumptions=assumptions)
105
+ if value in (True, False):
106
+ return not value
107
+ else:
108
+ return None
109
+
110
+ @IsTruePredicate.register(Or)
111
+ def _(expr, assumptions):
112
+ result = False
113
+ for arg in expr.args:
114
+ p = ask(arg, assumptions=assumptions)
115
+ if p is True:
116
+ return True
117
+ if p is None:
118
+ result = None
119
+ return result
120
+
121
+ @IsTruePredicate.register(And)
122
+ def _(expr, assumptions):
123
+ result = True
124
+ for arg in expr.args:
125
+ p = ask(arg, assumptions=assumptions)
126
+ if p is False:
127
+ return False
128
+ if p is None:
129
+ result = None
130
+ return result
131
+
132
+ @IsTruePredicate.register(Implies)
133
+ def _(expr, assumptions):
134
+ p, q = expr.args
135
+ return ask(~p | q, assumptions=assumptions)
136
+
137
+ @IsTruePredicate.register(Equivalent)
138
+ def _(expr, assumptions):
139
+ p, q = expr.args
140
+ pt = ask(p, assumptions=assumptions)
141
+ if pt is None:
142
+ return None
143
+ qt = ask(q, assumptions=assumptions)
144
+ if qt is None:
145
+ return None
146
+ return pt == qt
147
+
148
+
149
+ #### Helper methods
150
+ def test_closed_group(expr, assumptions, key):
151
+ """
152
+ Test for membership in a group with respect
153
+ to the current operation.
154
+ """
155
+ return _fuzzy_group(
156
+ (ask(key(a), assumptions) for a in expr.args), quick_exit=True)
157
+
158
+ def ask_all(*queries, assumptions):
159
+ return fuzzy_and(
160
+ (ask(query, assumptions) for query in queries))
161
+
162
+ def ask_any(*queries, assumptions):
163
+ return fuzzy_or(
164
+ (ask(query, assumptions) for query in queries))
.venv/lib/python3.13/site-packages/sympy/assumptions/handlers/matrices.py ADDED
@@ -0,0 +1,716 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ This module contains query handlers responsible for Matrices queries:
3
+ Square, Symmetric, Invertible etc.
4
+ """
5
+
6
+ from sympy.logic.boolalg import conjuncts
7
+ from sympy.assumptions import Q, ask
8
+ from sympy.assumptions.handlers import test_closed_group
9
+ from sympy.matrices import MatrixBase
10
+ from sympy.matrices.expressions import (BlockMatrix, BlockDiagMatrix, Determinant,
11
+ DiagMatrix, DiagonalMatrix, HadamardProduct, Identity, Inverse, MatAdd, MatMul,
12
+ MatPow, MatrixExpr, MatrixSlice, MatrixSymbol, OneMatrix, Trace, Transpose,
13
+ ZeroMatrix)
14
+ from sympy.matrices.expressions.blockmatrix import reblock_2x2
15
+ from sympy.matrices.expressions.factorizations import Factorization
16
+ from sympy.matrices.expressions.fourier import DFT
17
+ from sympy.core.logic import fuzzy_and
18
+ from sympy.utilities.iterables import sift
19
+ from sympy.core import Basic
20
+
21
+ from ..predicates.matrices import (SquarePredicate, SymmetricPredicate,
22
+ InvertiblePredicate, OrthogonalPredicate, UnitaryPredicate,
23
+ FullRankPredicate, PositiveDefinitePredicate, UpperTriangularPredicate,
24
+ LowerTriangularPredicate, DiagonalPredicate, IntegerElementsPredicate,
25
+ RealElementsPredicate, ComplexElementsPredicate)
26
+
27
+
28
+ def _Factorization(predicate, expr, assumptions):
29
+ if predicate in expr.predicates:
30
+ return True
31
+
32
+
33
+ # SquarePredicate
34
+
35
+ @SquarePredicate.register(MatrixExpr)
36
+ def _(expr, assumptions):
37
+ return expr.shape[0] == expr.shape[1]
38
+
39
+
40
+ # SymmetricPredicate
41
+
42
+ @SymmetricPredicate.register(MatMul)
43
+ def _(expr, assumptions):
44
+ factor, mmul = expr.as_coeff_mmul()
45
+ if all(ask(Q.symmetric(arg), assumptions) for arg in mmul.args):
46
+ return True
47
+ # TODO: implement sathandlers system for the matrices.
48
+ # Now it duplicates the general fact: Implies(Q.diagonal, Q.symmetric).
49
+ if ask(Q.diagonal(expr), assumptions):
50
+ return True
51
+ if len(mmul.args) >= 2 and mmul.args[0] == mmul.args[-1].T:
52
+ if len(mmul.args) == 2:
53
+ return True
54
+ return ask(Q.symmetric(MatMul(*mmul.args[1:-1])), assumptions)
55
+
56
+ @SymmetricPredicate.register(MatPow)
57
+ def _(expr, assumptions):
58
+ # only for integer powers
59
+ base, exp = expr.args
60
+ int_exp = ask(Q.integer(exp), assumptions)
61
+ if not int_exp:
62
+ return None
63
+ non_negative = ask(~Q.negative(exp), assumptions)
64
+ if (non_negative or non_negative == False
65
+ and ask(Q.invertible(base), assumptions)):
66
+ return ask(Q.symmetric(base), assumptions)
67
+ return None
68
+
69
+ @SymmetricPredicate.register(MatAdd)
70
+ def _(expr, assumptions):
71
+ return all(ask(Q.symmetric(arg), assumptions) for arg in expr.args)
72
+
73
+ @SymmetricPredicate.register(MatrixSymbol)
74
+ def _(expr, assumptions):
75
+ if not expr.is_square:
76
+ return False
77
+ # TODO: implement sathandlers system for the matrices.
78
+ # Now it duplicates the general fact: Implies(Q.diagonal, Q.symmetric).
79
+ if ask(Q.diagonal(expr), assumptions):
80
+ return True
81
+ if Q.symmetric(expr) in conjuncts(assumptions):
82
+ return True
83
+
84
+ @SymmetricPredicate.register_many(OneMatrix, ZeroMatrix)
85
+ def _(expr, assumptions):
86
+ return ask(Q.square(expr), assumptions)
87
+
88
+ @SymmetricPredicate.register_many(Inverse, Transpose)
89
+ def _(expr, assumptions):
90
+ return ask(Q.symmetric(expr.arg), assumptions)
91
+
92
+ @SymmetricPredicate.register(MatrixSlice)
93
+ def _(expr, assumptions):
94
+ # TODO: implement sathandlers system for the matrices.
95
+ # Now it duplicates the general fact: Implies(Q.diagonal, Q.symmetric).
96
+ if ask(Q.diagonal(expr), assumptions):
97
+ return True
98
+ if not expr.on_diag:
99
+ return None
100
+ else:
101
+ return ask(Q.symmetric(expr.parent), assumptions)
102
+
103
+ @SymmetricPredicate.register(Identity)
104
+ def _(expr, assumptions):
105
+ return True
106
+
107
+
108
+ # InvertiblePredicate
109
+
110
+ @InvertiblePredicate.register(MatMul)
111
+ def _(expr, assumptions):
112
+ factor, mmul = expr.as_coeff_mmul()
113
+ if all(ask(Q.invertible(arg), assumptions) for arg in mmul.args):
114
+ return True
115
+ if any(ask(Q.invertible(arg), assumptions) is False
116
+ for arg in mmul.args):
117
+ return False
118
+
119
+ @InvertiblePredicate.register(MatPow)
120
+ def _(expr, assumptions):
121
+ # only for integer powers
122
+ base, exp = expr.args
123
+ int_exp = ask(Q.integer(exp), assumptions)
124
+ if not int_exp:
125
+ return None
126
+ if exp.is_negative == False:
127
+ return ask(Q.invertible(base), assumptions)
128
+ return None
129
+
130
+ @InvertiblePredicate.register(MatAdd)
131
+ def _(expr, assumptions):
132
+ return None
133
+
134
+ @InvertiblePredicate.register(MatrixSymbol)
135
+ def _(expr, assumptions):
136
+ if not expr.is_square:
137
+ return False
138
+ if Q.invertible(expr) in conjuncts(assumptions):
139
+ return True
140
+
141
+ @InvertiblePredicate.register_many(Identity, Inverse)
142
+ def _(expr, assumptions):
143
+ return True
144
+
145
+ @InvertiblePredicate.register(ZeroMatrix)
146
+ def _(expr, assumptions):
147
+ return False
148
+
149
+ @InvertiblePredicate.register(OneMatrix)
150
+ def _(expr, assumptions):
151
+ return expr.shape[0] == 1 and expr.shape[1] == 1
152
+
153
+ @InvertiblePredicate.register(Transpose)
154
+ def _(expr, assumptions):
155
+ return ask(Q.invertible(expr.arg), assumptions)
156
+
157
+ @InvertiblePredicate.register(MatrixSlice)
158
+ def _(expr, assumptions):
159
+ if not expr.on_diag:
160
+ return None
161
+ else:
162
+ return ask(Q.invertible(expr.parent), assumptions)
163
+
164
+ @InvertiblePredicate.register(MatrixBase)
165
+ def _(expr, assumptions):
166
+ if not expr.is_square:
167
+ return False
168
+ return expr.rank() == expr.rows
169
+
170
+ @InvertiblePredicate.register(MatrixExpr)
171
+ def _(expr, assumptions):
172
+ if not expr.is_square:
173
+ return False
174
+ return None
175
+
176
+ @InvertiblePredicate.register(BlockMatrix)
177
+ def _(expr, assumptions):
178
+ if not expr.is_square:
179
+ return False
180
+ if expr.blockshape == (1, 1):
181
+ return ask(Q.invertible(expr.blocks[0, 0]), assumptions)
182
+ expr = reblock_2x2(expr)
183
+ if expr.blockshape == (2, 2):
184
+ [[A, B], [C, D]] = expr.blocks.tolist()
185
+ if ask(Q.invertible(A), assumptions) == True:
186
+ invertible = ask(Q.invertible(D - C * A.I * B), assumptions)
187
+ if invertible is not None:
188
+ return invertible
189
+ if ask(Q.invertible(B), assumptions) == True:
190
+ invertible = ask(Q.invertible(C - D * B.I * A), assumptions)
191
+ if invertible is not None:
192
+ return invertible
193
+ if ask(Q.invertible(C), assumptions) == True:
194
+ invertible = ask(Q.invertible(B - A * C.I * D), assumptions)
195
+ if invertible is not None:
196
+ return invertible
197
+ if ask(Q.invertible(D), assumptions) == True:
198
+ invertible = ask(Q.invertible(A - B * D.I * C), assumptions)
199
+ if invertible is not None:
200
+ return invertible
201
+ return None
202
+
203
+ @InvertiblePredicate.register(BlockDiagMatrix)
204
+ def _(expr, assumptions):
205
+ if expr.rowblocksizes != expr.colblocksizes:
206
+ return None
207
+ return fuzzy_and([ask(Q.invertible(a), assumptions) for a in expr.diag])
208
+
209
+
210
+ # OrthogonalPredicate
211
+
212
+ @OrthogonalPredicate.register(MatMul)
213
+ def _(expr, assumptions):
214
+ factor, mmul = expr.as_coeff_mmul()
215
+ if (all(ask(Q.orthogonal(arg), assumptions) for arg in mmul.args) and
216
+ factor == 1):
217
+ return True
218
+ if any(ask(Q.invertible(arg), assumptions) is False
219
+ for arg in mmul.args):
220
+ return False
221
+
222
+ @OrthogonalPredicate.register(MatPow)
223
+ def _(expr, assumptions):
224
+ # only for integer powers
225
+ base, exp = expr.args
226
+ int_exp = ask(Q.integer(exp), assumptions)
227
+ if int_exp:
228
+ return ask(Q.orthogonal(base), assumptions)
229
+ return None
230
+
231
+ @OrthogonalPredicate.register(MatAdd)
232
+ def _(expr, assumptions):
233
+ if (len(expr.args) == 1 and
234
+ ask(Q.orthogonal(expr.args[0]), assumptions)):
235
+ return True
236
+
237
+ @OrthogonalPredicate.register(MatrixSymbol)
238
+ def _(expr, assumptions):
239
+ if (not expr.is_square or
240
+ ask(Q.invertible(expr), assumptions) is False):
241
+ return False
242
+ if Q.orthogonal(expr) in conjuncts(assumptions):
243
+ return True
244
+
245
+ @OrthogonalPredicate.register(Identity)
246
+ def _(expr, assumptions):
247
+ return True
248
+
249
+ @OrthogonalPredicate.register(ZeroMatrix)
250
+ def _(expr, assumptions):
251
+ return False
252
+
253
+ @OrthogonalPredicate.register_many(Inverse, Transpose)
254
+ def _(expr, assumptions):
255
+ return ask(Q.orthogonal(expr.arg), assumptions)
256
+
257
+ @OrthogonalPredicate.register(MatrixSlice)
258
+ def _(expr, assumptions):
259
+ if not expr.on_diag:
260
+ return None
261
+ else:
262
+ return ask(Q.orthogonal(expr.parent), assumptions)
263
+
264
+ @OrthogonalPredicate.register(Factorization)
265
+ def _(expr, assumptions):
266
+ return _Factorization(Q.orthogonal, expr, assumptions)
267
+
268
+
269
+ # UnitaryPredicate
270
+
271
+ @UnitaryPredicate.register(MatMul)
272
+ def _(expr, assumptions):
273
+ factor, mmul = expr.as_coeff_mmul()
274
+ if (all(ask(Q.unitary(arg), assumptions) for arg in mmul.args) and
275
+ abs(factor) == 1):
276
+ return True
277
+ if any(ask(Q.invertible(arg), assumptions) is False
278
+ for arg in mmul.args):
279
+ return False
280
+
281
+ @UnitaryPredicate.register(MatPow)
282
+ def _(expr, assumptions):
283
+ # only for integer powers
284
+ base, exp = expr.args
285
+ int_exp = ask(Q.integer(exp), assumptions)
286
+ if int_exp:
287
+ return ask(Q.unitary(base), assumptions)
288
+ return None
289
+
290
+ @UnitaryPredicate.register(MatrixSymbol)
291
+ def _(expr, assumptions):
292
+ if (not expr.is_square or
293
+ ask(Q.invertible(expr), assumptions) is False):
294
+ return False
295
+ if Q.unitary(expr) in conjuncts(assumptions):
296
+ return True
297
+
298
+ @UnitaryPredicate.register_many(Inverse, Transpose)
299
+ def _(expr, assumptions):
300
+ return ask(Q.unitary(expr.arg), assumptions)
301
+
302
+ @UnitaryPredicate.register(MatrixSlice)
303
+ def _(expr, assumptions):
304
+ if not expr.on_diag:
305
+ return None
306
+ else:
307
+ return ask(Q.unitary(expr.parent), assumptions)
308
+
309
+ @UnitaryPredicate.register_many(DFT, Identity)
310
+ def _(expr, assumptions):
311
+ return True
312
+
313
+ @UnitaryPredicate.register(ZeroMatrix)
314
+ def _(expr, assumptions):
315
+ return False
316
+
317
+ @UnitaryPredicate.register(Factorization)
318
+ def _(expr, assumptions):
319
+ return _Factorization(Q.unitary, expr, assumptions)
320
+
321
+
322
+ # FullRankPredicate
323
+
324
+ @FullRankPredicate.register(MatMul)
325
+ def _(expr, assumptions):
326
+ if all(ask(Q.fullrank(arg), assumptions) for arg in expr.args):
327
+ return True
328
+
329
+ @FullRankPredicate.register(MatPow)
330
+ def _(expr, assumptions):
331
+ # only for integer powers
332
+ base, exp = expr.args
333
+ int_exp = ask(Q.integer(exp), assumptions)
334
+ if int_exp and ask(~Q.negative(exp), assumptions):
335
+ return ask(Q.fullrank(base), assumptions)
336
+ return None
337
+
338
+ @FullRankPredicate.register(Identity)
339
+ def _(expr, assumptions):
340
+ return True
341
+
342
+ @FullRankPredicate.register(ZeroMatrix)
343
+ def _(expr, assumptions):
344
+ return False
345
+
346
+ @FullRankPredicate.register(OneMatrix)
347
+ def _(expr, assumptions):
348
+ return expr.shape[0] == 1 and expr.shape[1] == 1
349
+
350
+ @FullRankPredicate.register_many(Inverse, Transpose)
351
+ def _(expr, assumptions):
352
+ return ask(Q.fullrank(expr.arg), assumptions)
353
+
354
+ @FullRankPredicate.register(MatrixSlice)
355
+ def _(expr, assumptions):
356
+ if ask(Q.orthogonal(expr.parent), assumptions):
357
+ return True
358
+
359
+
360
+ # PositiveDefinitePredicate
361
+
362
+ @PositiveDefinitePredicate.register(MatMul)
363
+ def _(expr, assumptions):
364
+ factor, mmul = expr.as_coeff_mmul()
365
+ if (all(ask(Q.positive_definite(arg), assumptions)
366
+ for arg in mmul.args) and factor > 0):
367
+ return True
368
+ if (len(mmul.args) >= 2
369
+ and mmul.args[0] == mmul.args[-1].T
370
+ and ask(Q.fullrank(mmul.args[0]), assumptions)):
371
+ return ask(Q.positive_definite(
372
+ MatMul(*mmul.args[1:-1])), assumptions)
373
+
374
+ @PositiveDefinitePredicate.register(MatPow)
375
+ def _(expr, assumptions):
376
+ # a power of a positive definite matrix is positive definite
377
+ if ask(Q.positive_definite(expr.args[0]), assumptions):
378
+ return True
379
+
380
+ @PositiveDefinitePredicate.register(MatAdd)
381
+ def _(expr, assumptions):
382
+ if all(ask(Q.positive_definite(arg), assumptions)
383
+ for arg in expr.args):
384
+ return True
385
+
386
+ @PositiveDefinitePredicate.register(MatrixSymbol)
387
+ def _(expr, assumptions):
388
+ if not expr.is_square:
389
+ return False
390
+ if Q.positive_definite(expr) in conjuncts(assumptions):
391
+ return True
392
+
393
+ @PositiveDefinitePredicate.register(Identity)
394
+ def _(expr, assumptions):
395
+ return True
396
+
397
+ @PositiveDefinitePredicate.register(ZeroMatrix)
398
+ def _(expr, assumptions):
399
+ return False
400
+
401
+ @PositiveDefinitePredicate.register(OneMatrix)
402
+ def _(expr, assumptions):
403
+ return expr.shape[0] == 1 and expr.shape[1] == 1
404
+
405
+ @PositiveDefinitePredicate.register_many(Inverse, Transpose)
406
+ def _(expr, assumptions):
407
+ return ask(Q.positive_definite(expr.arg), assumptions)
408
+
409
+ @PositiveDefinitePredicate.register(MatrixSlice)
410
+ def _(expr, assumptions):
411
+ if not expr.on_diag:
412
+ return None
413
+ else:
414
+ return ask(Q.positive_definite(expr.parent), assumptions)
415
+
416
+
417
+ # UpperTriangularPredicate
418
+
419
+ @UpperTriangularPredicate.register(MatMul)
420
+ def _(expr, assumptions):
421
+ factor, matrices = expr.as_coeff_matrices()
422
+ if all(ask(Q.upper_triangular(m), assumptions) for m in matrices):
423
+ return True
424
+
425
+ @UpperTriangularPredicate.register(MatAdd)
426
+ def _(expr, assumptions):
427
+ if all(ask(Q.upper_triangular(arg), assumptions) for arg in expr.args):
428
+ return True
429
+
430
+ @UpperTriangularPredicate.register(MatPow)
431
+ def _(expr, assumptions):
432
+ # only for integer powers
433
+ base, exp = expr.args
434
+ int_exp = ask(Q.integer(exp), assumptions)
435
+ if not int_exp:
436
+ return None
437
+ non_negative = ask(~Q.negative(exp), assumptions)
438
+ if (non_negative or non_negative == False
439
+ and ask(Q.invertible(base), assumptions)):
440
+ return ask(Q.upper_triangular(base), assumptions)
441
+ return None
442
+
443
+ @UpperTriangularPredicate.register(MatrixSymbol)
444
+ def _(expr, assumptions):
445
+ if Q.upper_triangular(expr) in conjuncts(assumptions):
446
+ return True
447
+
448
+ @UpperTriangularPredicate.register_many(Identity, ZeroMatrix)
449
+ def _(expr, assumptions):
450
+ return True
451
+
452
+ @UpperTriangularPredicate.register(OneMatrix)
453
+ def _(expr, assumptions):
454
+ return expr.shape[0] == 1 and expr.shape[1] == 1
455
+
456
+ @UpperTriangularPredicate.register(Transpose)
457
+ def _(expr, assumptions):
458
+ return ask(Q.lower_triangular(expr.arg), assumptions)
459
+
460
+ @UpperTriangularPredicate.register(Inverse)
461
+ def _(expr, assumptions):
462
+ return ask(Q.upper_triangular(expr.arg), assumptions)
463
+
464
+ @UpperTriangularPredicate.register(MatrixSlice)
465
+ def _(expr, assumptions):
466
+ if not expr.on_diag:
467
+ return None
468
+ else:
469
+ return ask(Q.upper_triangular(expr.parent), assumptions)
470
+
471
+ @UpperTriangularPredicate.register(Factorization)
472
+ def _(expr, assumptions):
473
+ return _Factorization(Q.upper_triangular, expr, assumptions)
474
+
475
+ # LowerTriangularPredicate
476
+
477
+ @LowerTriangularPredicate.register(MatMul)
478
+ def _(expr, assumptions):
479
+ factor, matrices = expr.as_coeff_matrices()
480
+ if all(ask(Q.lower_triangular(m), assumptions) for m in matrices):
481
+ return True
482
+
483
+ @LowerTriangularPredicate.register(MatAdd)
484
+ def _(expr, assumptions):
485
+ if all(ask(Q.lower_triangular(arg), assumptions) for arg in expr.args):
486
+ return True
487
+
488
+ @LowerTriangularPredicate.register(MatPow)
489
+ def _(expr, assumptions):
490
+ # only for integer powers
491
+ base, exp = expr.args
492
+ int_exp = ask(Q.integer(exp), assumptions)
493
+ if not int_exp:
494
+ return None
495
+ non_negative = ask(~Q.negative(exp), assumptions)
496
+ if (non_negative or non_negative == False
497
+ and ask(Q.invertible(base), assumptions)):
498
+ return ask(Q.lower_triangular(base), assumptions)
499
+ return None
500
+
501
+ @LowerTriangularPredicate.register(MatrixSymbol)
502
+ def _(expr, assumptions):
503
+ if Q.lower_triangular(expr) in conjuncts(assumptions):
504
+ return True
505
+
506
+ @LowerTriangularPredicate.register_many(Identity, ZeroMatrix)
507
+ def _(expr, assumptions):
508
+ return True
509
+
510
+ @LowerTriangularPredicate.register(OneMatrix)
511
+ def _(expr, assumptions):
512
+ return expr.shape[0] == 1 and expr.shape[1] == 1
513
+
514
+ @LowerTriangularPredicate.register(Transpose)
515
+ def _(expr, assumptions):
516
+ return ask(Q.upper_triangular(expr.arg), assumptions)
517
+
518
+ @LowerTriangularPredicate.register(Inverse)
519
+ def _(expr, assumptions):
520
+ return ask(Q.lower_triangular(expr.arg), assumptions)
521
+
522
+ @LowerTriangularPredicate.register(MatrixSlice)
523
+ def _(expr, assumptions):
524
+ if not expr.on_diag:
525
+ return None
526
+ else:
527
+ return ask(Q.lower_triangular(expr.parent), assumptions)
528
+
529
+ @LowerTriangularPredicate.register(Factorization)
530
+ def _(expr, assumptions):
531
+ return _Factorization(Q.lower_triangular, expr, assumptions)
532
+
533
+
534
+ # DiagonalPredicate
535
+
536
+ def _is_empty_or_1x1(expr):
537
+ return expr.shape in ((0, 0), (1, 1))
538
+
539
+ @DiagonalPredicate.register(MatMul)
540
+ def _(expr, assumptions):
541
+ if _is_empty_or_1x1(expr):
542
+ return True
543
+ factor, matrices = expr.as_coeff_matrices()
544
+ if all(ask(Q.diagonal(m), assumptions) for m in matrices):
545
+ return True
546
+
547
+ @DiagonalPredicate.register(MatPow)
548
+ def _(expr, assumptions):
549
+ # only for integer powers
550
+ base, exp = expr.args
551
+ int_exp = ask(Q.integer(exp), assumptions)
552
+ if not int_exp:
553
+ return None
554
+ non_negative = ask(~Q.negative(exp), assumptions)
555
+ if (non_negative or non_negative == False
556
+ and ask(Q.invertible(base), assumptions)):
557
+ return ask(Q.diagonal(base), assumptions)
558
+ return None
559
+
560
+ @DiagonalPredicate.register(MatAdd)
561
+ def _(expr, assumptions):
562
+ if all(ask(Q.diagonal(arg), assumptions) for arg in expr.args):
563
+ return True
564
+
565
+ @DiagonalPredicate.register(MatrixSymbol)
566
+ def _(expr, assumptions):
567
+ if _is_empty_or_1x1(expr):
568
+ return True
569
+ if Q.diagonal(expr) in conjuncts(assumptions):
570
+ return True
571
+
572
+ @DiagonalPredicate.register(OneMatrix)
573
+ def _(expr, assumptions):
574
+ return expr.shape[0] == 1 and expr.shape[1] == 1
575
+
576
+ @DiagonalPredicate.register_many(Inverse, Transpose)
577
+ def _(expr, assumptions):
578
+ return ask(Q.diagonal(expr.arg), assumptions)
579
+
580
+ @DiagonalPredicate.register(MatrixSlice)
581
+ def _(expr, assumptions):
582
+ if _is_empty_or_1x1(expr):
583
+ return True
584
+ if not expr.on_diag:
585
+ return None
586
+ else:
587
+ return ask(Q.diagonal(expr.parent), assumptions)
588
+
589
+ @DiagonalPredicate.register_many(DiagonalMatrix, DiagMatrix, Identity, ZeroMatrix)
590
+ def _(expr, assumptions):
591
+ return True
592
+
593
+ @DiagonalPredicate.register(Factorization)
594
+ def _(expr, assumptions):
595
+ return _Factorization(Q.diagonal, expr, assumptions)
596
+
597
+
598
+ # IntegerElementsPredicate
599
+
600
+ def BM_elements(predicate, expr, assumptions):
601
+ """ Block Matrix elements. """
602
+ return all(ask(predicate(b), assumptions) for b in expr.blocks)
603
+
604
+ def MS_elements(predicate, expr, assumptions):
605
+ """ Matrix Slice elements. """
606
+ return ask(predicate(expr.parent), assumptions)
607
+
608
+ def MatMul_elements(matrix_predicate, scalar_predicate, expr, assumptions):
609
+ d = sift(expr.args, lambda x: isinstance(x, MatrixExpr))
610
+ factors, matrices = d[False], d[True]
611
+ return fuzzy_and([
612
+ test_closed_group(Basic(*factors), assumptions, scalar_predicate),
613
+ test_closed_group(Basic(*matrices), assumptions, matrix_predicate)])
614
+
615
+
616
+ @IntegerElementsPredicate.register_many(Determinant, HadamardProduct, MatAdd,
617
+ Trace, Transpose)
618
+ def _(expr, assumptions):
619
+ return test_closed_group(expr, assumptions, Q.integer_elements)
620
+
621
+ @IntegerElementsPredicate.register(MatPow)
622
+ def _(expr, assumptions):
623
+ # only for integer powers
624
+ base, exp = expr.args
625
+ int_exp = ask(Q.integer(exp), assumptions)
626
+ if not int_exp:
627
+ return None
628
+ if exp.is_negative == False:
629
+ return ask(Q.integer_elements(base), assumptions)
630
+ return None
631
+
632
+ @IntegerElementsPredicate.register_many(Identity, OneMatrix, ZeroMatrix)
633
+ def _(expr, assumptions):
634
+ return True
635
+
636
+ @IntegerElementsPredicate.register(MatMul)
637
+ def _(expr, assumptions):
638
+ return MatMul_elements(Q.integer_elements, Q.integer, expr, assumptions)
639
+
640
+ @IntegerElementsPredicate.register(MatrixSlice)
641
+ def _(expr, assumptions):
642
+ return MS_elements(Q.integer_elements, expr, assumptions)
643
+
644
+ @IntegerElementsPredicate.register(BlockMatrix)
645
+ def _(expr, assumptions):
646
+ return BM_elements(Q.integer_elements, expr, assumptions)
647
+
648
+
649
+ # RealElementsPredicate
650
+
651
+ @RealElementsPredicate.register_many(Determinant, Factorization, HadamardProduct,
652
+ MatAdd, Trace, Transpose)
653
+ def _(expr, assumptions):
654
+ return test_closed_group(expr, assumptions, Q.real_elements)
655
+
656
+ @RealElementsPredicate.register(MatPow)
657
+ def _(expr, assumptions):
658
+ # only for integer powers
659
+ base, exp = expr.args
660
+ int_exp = ask(Q.integer(exp), assumptions)
661
+ if not int_exp:
662
+ return None
663
+ non_negative = ask(~Q.negative(exp), assumptions)
664
+ if (non_negative or non_negative == False
665
+ and ask(Q.invertible(base), assumptions)):
666
+ return ask(Q.real_elements(base), assumptions)
667
+ return None
668
+
669
+ @RealElementsPredicate.register(MatMul)
670
+ def _(expr, assumptions):
671
+ return MatMul_elements(Q.real_elements, Q.real, expr, assumptions)
672
+
673
+ @RealElementsPredicate.register(MatrixSlice)
674
+ def _(expr, assumptions):
675
+ return MS_elements(Q.real_elements, expr, assumptions)
676
+
677
+ @RealElementsPredicate.register(BlockMatrix)
678
+ def _(expr, assumptions):
679
+ return BM_elements(Q.real_elements, expr, assumptions)
680
+
681
+
682
+ # ComplexElementsPredicate
683
+
684
+ @ComplexElementsPredicate.register_many(Determinant, Factorization, HadamardProduct,
685
+ Inverse, MatAdd, Trace, Transpose)
686
+ def _(expr, assumptions):
687
+ return test_closed_group(expr, assumptions, Q.complex_elements)
688
+
689
+ @ComplexElementsPredicate.register(MatPow)
690
+ def _(expr, assumptions):
691
+ # only for integer powers
692
+ base, exp = expr.args
693
+ int_exp = ask(Q.integer(exp), assumptions)
694
+ if not int_exp:
695
+ return None
696
+ non_negative = ask(~Q.negative(exp), assumptions)
697
+ if (non_negative or non_negative == False
698
+ and ask(Q.invertible(base), assumptions)):
699
+ return ask(Q.complex_elements(base), assumptions)
700
+ return None
701
+
702
+ @ComplexElementsPredicate.register(MatMul)
703
+ def _(expr, assumptions):
704
+ return MatMul_elements(Q.complex_elements, Q.complex, expr, assumptions)
705
+
706
+ @ComplexElementsPredicate.register(MatrixSlice)
707
+ def _(expr, assumptions):
708
+ return MS_elements(Q.complex_elements, expr, assumptions)
709
+
710
+ @ComplexElementsPredicate.register(BlockMatrix)
711
+ def _(expr, assumptions):
712
+ return BM_elements(Q.complex_elements, expr, assumptions)
713
+
714
+ @ComplexElementsPredicate.register(DFT)
715
+ def _(expr, assumptions):
716
+ return True
.venv/lib/python3.13/site-packages/sympy/assumptions/handlers/ntheory.py ADDED
@@ -0,0 +1,279 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Handlers for keys related to number theory: prime, even, odd, etc.
3
+ """
4
+
5
+ from sympy.assumptions import Q, ask
6
+ from sympy.core import Add, Basic, Expr, Float, Mul, Pow, S
7
+ from sympy.core.numbers import (ImaginaryUnit, Infinity, Integer, NaN,
8
+ NegativeInfinity, NumberSymbol, Rational, int_valued)
9
+ from sympy.functions import Abs, im, re
10
+ from sympy.ntheory import isprime
11
+
12
+ from sympy.multipledispatch import MDNotImplementedError
13
+
14
+ from ..predicates.ntheory import (PrimePredicate, CompositePredicate,
15
+ EvenPredicate, OddPredicate)
16
+
17
+
18
+ # PrimePredicate
19
+
20
+ def _PrimePredicate_number(expr, assumptions):
21
+ # helper method
22
+ exact = not expr.atoms(Float)
23
+ try:
24
+ i = int(expr.round())
25
+ if (expr - i).equals(0) is False:
26
+ raise TypeError
27
+ except TypeError:
28
+ return False
29
+ if exact:
30
+ return isprime(i)
31
+ # when not exact, we won't give a True or False
32
+ # since the number represents an approximate value
33
+
34
+ @PrimePredicate.register(Expr)
35
+ def _(expr, assumptions):
36
+ ret = expr.is_prime
37
+ if ret is None:
38
+ raise MDNotImplementedError
39
+ return ret
40
+
41
+ @PrimePredicate.register(Basic)
42
+ def _(expr, assumptions):
43
+ if expr.is_number:
44
+ return _PrimePredicate_number(expr, assumptions)
45
+
46
+ @PrimePredicate.register(Mul)
47
+ def _(expr, assumptions):
48
+ if expr.is_number:
49
+ return _PrimePredicate_number(expr, assumptions)
50
+ for arg in expr.args:
51
+ if not ask(Q.integer(arg), assumptions):
52
+ return None
53
+ for arg in expr.args:
54
+ if arg.is_number and arg.is_composite:
55
+ return False
56
+
57
+ @PrimePredicate.register(Pow)
58
+ def _(expr, assumptions):
59
+ """
60
+ Integer**Integer -> !Prime
61
+ """
62
+ if expr.is_number:
63
+ return _PrimePredicate_number(expr, assumptions)
64
+ if ask(Q.integer(expr.exp), assumptions) and \
65
+ ask(Q.integer(expr.base), assumptions):
66
+ prime_base = ask(Q.prime(expr.base), assumptions)
67
+ if prime_base is False:
68
+ return False
69
+ is_exp_one = ask(Q.eq(expr.exp, 1), assumptions)
70
+ if is_exp_one is False:
71
+ return False
72
+ if prime_base is True and is_exp_one is True:
73
+ return True
74
+
75
+ @PrimePredicate.register(Integer)
76
+ def _(expr, assumptions):
77
+ return isprime(expr)
78
+
79
+ @PrimePredicate.register_many(Rational, Infinity, NegativeInfinity, ImaginaryUnit)
80
+ def _(expr, assumptions):
81
+ return False
82
+
83
+ @PrimePredicate.register(Float)
84
+ def _(expr, assumptions):
85
+ return _PrimePredicate_number(expr, assumptions)
86
+
87
+ @PrimePredicate.register(NumberSymbol)
88
+ def _(expr, assumptions):
89
+ return _PrimePredicate_number(expr, assumptions)
90
+
91
+ @PrimePredicate.register(NaN)
92
+ def _(expr, assumptions):
93
+ return None
94
+
95
+
96
+ # CompositePredicate
97
+
98
+ @CompositePredicate.register(Expr)
99
+ def _(expr, assumptions):
100
+ ret = expr.is_composite
101
+ if ret is None:
102
+ raise MDNotImplementedError
103
+ return ret
104
+
105
+ @CompositePredicate.register(Basic)
106
+ def _(expr, assumptions):
107
+ _positive = ask(Q.positive(expr), assumptions)
108
+ if _positive:
109
+ _integer = ask(Q.integer(expr), assumptions)
110
+ if _integer:
111
+ _prime = ask(Q.prime(expr), assumptions)
112
+ if _prime is None:
113
+ return
114
+ # Positive integer which is not prime is not
115
+ # necessarily composite
116
+ _is_one = ask(Q.eq(expr, 1), assumptions)
117
+ if _is_one:
118
+ return False
119
+ if _is_one is None:
120
+ return None
121
+ return not _prime
122
+ else:
123
+ return _integer
124
+ else:
125
+ return _positive
126
+
127
+
128
+ # EvenPredicate
129
+
130
+ def _EvenPredicate_number(expr, assumptions):
131
+ # helper method
132
+ if isinstance(expr, (float, Float)):
133
+ if int_valued(expr):
134
+ return None
135
+ return False
136
+ try:
137
+ i = int(expr.round())
138
+ except TypeError:
139
+ return False
140
+ if not (expr - i).equals(0):
141
+ return False
142
+ return i % 2 == 0
143
+
144
+ @EvenPredicate.register(Expr)
145
+ def _(expr, assumptions):
146
+ ret = expr.is_even
147
+ if ret is None:
148
+ raise MDNotImplementedError
149
+ return ret
150
+
151
+ @EvenPredicate.register(Basic)
152
+ def _(expr, assumptions):
153
+ if expr.is_number:
154
+ return _EvenPredicate_number(expr, assumptions)
155
+
156
+ @EvenPredicate.register(Mul)
157
+ def _(expr, assumptions):
158
+ """
159
+ Even * Integer -> Even
160
+ Even * Odd -> Even
161
+ Integer * Odd -> ?
162
+ Odd * Odd -> Odd
163
+ Even * Even -> Even
164
+ Integer * Integer -> Even if Integer + Integer = Odd
165
+ otherwise -> ?
166
+ """
167
+ if expr.is_number:
168
+ return _EvenPredicate_number(expr, assumptions)
169
+ even, odd, irrational, acc = False, 0, False, 1
170
+ for arg in expr.args:
171
+ # check for all integers and at least one even
172
+ if ask(Q.integer(arg), assumptions):
173
+ if ask(Q.even(arg), assumptions):
174
+ even = True
175
+ elif ask(Q.odd(arg), assumptions):
176
+ odd += 1
177
+ elif not even and acc != 1:
178
+ if ask(Q.odd(acc + arg), assumptions):
179
+ even = True
180
+ elif ask(Q.irrational(arg), assumptions):
181
+ # one irrational makes the result False
182
+ # two makes it undefined
183
+ if irrational:
184
+ break
185
+ irrational = True
186
+ else:
187
+ break
188
+ acc = arg
189
+ else:
190
+ if irrational:
191
+ return False
192
+ if even:
193
+ return True
194
+ if odd == len(expr.args):
195
+ return False
196
+
197
+ @EvenPredicate.register(Add)
198
+ def _(expr, assumptions):
199
+ """
200
+ Even + Odd -> Odd
201
+ Even + Even -> Even
202
+ Odd + Odd -> Even
203
+
204
+ """
205
+ if expr.is_number:
206
+ return _EvenPredicate_number(expr, assumptions)
207
+ _result = True
208
+ for arg in expr.args:
209
+ if ask(Q.even(arg), assumptions):
210
+ pass
211
+ elif ask(Q.odd(arg), assumptions):
212
+ _result = not _result
213
+ else:
214
+ break
215
+ else:
216
+ return _result
217
+
218
+ @EvenPredicate.register(Pow)
219
+ def _(expr, assumptions):
220
+ if expr.is_number:
221
+ return _EvenPredicate_number(expr, assumptions)
222
+ if ask(Q.integer(expr.exp), assumptions):
223
+ if ask(Q.positive(expr.exp), assumptions):
224
+ return ask(Q.even(expr.base), assumptions)
225
+ elif ask(~Q.negative(expr.exp) & Q.odd(expr.base), assumptions):
226
+ return False
227
+ elif expr.base is S.NegativeOne:
228
+ return False
229
+
230
+ @EvenPredicate.register(Integer)
231
+ def _(expr, assumptions):
232
+ return not bool(expr.p & 1)
233
+
234
+ @EvenPredicate.register_many(Rational, Infinity, NegativeInfinity, ImaginaryUnit)
235
+ def _(expr, assumptions):
236
+ return False
237
+
238
+ @EvenPredicate.register(NumberSymbol)
239
+ def _(expr, assumptions):
240
+ return _EvenPredicate_number(expr, assumptions)
241
+
242
+ @EvenPredicate.register(Abs)
243
+ def _(expr, assumptions):
244
+ if ask(Q.real(expr.args[0]), assumptions):
245
+ return ask(Q.even(expr.args[0]), assumptions)
246
+
247
+ @EvenPredicate.register(re)
248
+ def _(expr, assumptions):
249
+ if ask(Q.real(expr.args[0]), assumptions):
250
+ return ask(Q.even(expr.args[0]), assumptions)
251
+
252
+ @EvenPredicate.register(im)
253
+ def _(expr, assumptions):
254
+ if ask(Q.real(expr.args[0]), assumptions):
255
+ return True
256
+
257
+ @EvenPredicate.register(NaN)
258
+ def _(expr, assumptions):
259
+ return None
260
+
261
+
262
+ # OddPredicate
263
+
264
+ @OddPredicate.register(Expr)
265
+ def _(expr, assumptions):
266
+ ret = expr.is_odd
267
+ if ret is None:
268
+ raise MDNotImplementedError
269
+ return ret
270
+
271
+ @OddPredicate.register(Basic)
272
+ def _(expr, assumptions):
273
+ _integer = ask(Q.integer(expr), assumptions)
274
+ if _integer:
275
+ _even = ask(Q.even(expr), assumptions)
276
+ if _even is None:
277
+ return None
278
+ return not _even
279
+ return _integer
.venv/lib/python3.13/site-packages/sympy/assumptions/handlers/order.py ADDED
@@ -0,0 +1,440 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Handlers related to order relations: positive, negative, etc.
3
+ """
4
+
5
+ from sympy.assumptions import Q, ask
6
+ from sympy.core import Add, Basic, Expr, Mul, Pow, S
7
+ from sympy.core.logic import fuzzy_not, fuzzy_and, fuzzy_or
8
+ from sympy.core.numbers import E, ImaginaryUnit, NaN, I, pi
9
+ from sympy.functions import Abs, acos, acot, asin, atan, exp, factorial, log
10
+ from sympy.matrices import Determinant, Trace
11
+ from sympy.matrices.expressions.matexpr import MatrixElement
12
+
13
+ from sympy.multipledispatch import MDNotImplementedError
14
+
15
+ from ..predicates.order import (NegativePredicate, NonNegativePredicate,
16
+ NonZeroPredicate, ZeroPredicate, NonPositivePredicate, PositivePredicate,
17
+ ExtendedNegativePredicate, ExtendedNonNegativePredicate,
18
+ ExtendedNonPositivePredicate, ExtendedNonZeroPredicate,
19
+ ExtendedPositivePredicate,)
20
+
21
+
22
+ # NegativePredicate
23
+
24
+ def _NegativePredicate_number(expr, assumptions):
25
+ r, i = expr.as_real_imag()
26
+
27
+ if r == S.NaN or i == S.NaN:
28
+ return None
29
+
30
+ # If the imaginary part can symbolically be shown to be zero then
31
+ # we just evaluate the real part; otherwise we evaluate the imaginary
32
+ # part to see if it actually evaluates to zero and if it does then
33
+ # we make the comparison between the real part and zero.
34
+ if not i:
35
+ r = r.evalf(2)
36
+ if r._prec != 1:
37
+ return r < 0
38
+ else:
39
+ i = i.evalf(2)
40
+ if i._prec != 1:
41
+ if i != 0:
42
+ return False
43
+ r = r.evalf(2)
44
+ if r._prec != 1:
45
+ return r < 0
46
+
47
+ @NegativePredicate.register(Basic)
48
+ def _(expr, assumptions):
49
+ if expr.is_number:
50
+ return _NegativePredicate_number(expr, assumptions)
51
+
52
+ @NegativePredicate.register(Expr)
53
+ def _(expr, assumptions):
54
+ ret = expr.is_negative
55
+ if ret is None:
56
+ raise MDNotImplementedError
57
+ return ret
58
+
59
+ @NegativePredicate.register(Add)
60
+ def _(expr, assumptions):
61
+ """
62
+ Positive + Positive -> Positive,
63
+ Negative + Negative -> Negative
64
+ """
65
+ if expr.is_number:
66
+ return _NegativePredicate_number(expr, assumptions)
67
+
68
+ r = ask(Q.real(expr), assumptions)
69
+ if r is not True:
70
+ return r
71
+
72
+ nonpos = 0
73
+ for arg in expr.args:
74
+ if ask(Q.negative(arg), assumptions) is not True:
75
+ if ask(Q.positive(arg), assumptions) is False:
76
+ nonpos += 1
77
+ else:
78
+ break
79
+ else:
80
+ if nonpos < len(expr.args):
81
+ return True
82
+
83
+ @NegativePredicate.register(Mul)
84
+ def _(expr, assumptions):
85
+ if expr.is_number:
86
+ return _NegativePredicate_number(expr, assumptions)
87
+ result = None
88
+ for arg in expr.args:
89
+ if result is None:
90
+ result = False
91
+ if ask(Q.negative(arg), assumptions):
92
+ result = not result
93
+ elif ask(Q.positive(arg), assumptions):
94
+ pass
95
+ else:
96
+ return
97
+ return result
98
+
99
+ @NegativePredicate.register(Pow)
100
+ def _(expr, assumptions):
101
+ """
102
+ Real ** Even -> NonNegative
103
+ Real ** Odd -> same_as_base
104
+ NonNegative ** Positive -> NonNegative
105
+ """
106
+ if expr.base == E:
107
+ # Exponential is always positive:
108
+ if ask(Q.real(expr.exp), assumptions):
109
+ return False
110
+ return
111
+
112
+ if expr.is_number:
113
+ return _NegativePredicate_number(expr, assumptions)
114
+ if ask(Q.real(expr.base), assumptions):
115
+ if ask(Q.positive(expr.base), assumptions):
116
+ if ask(Q.real(expr.exp), assumptions):
117
+ return False
118
+ if ask(Q.even(expr.exp), assumptions):
119
+ return False
120
+ if ask(Q.odd(expr.exp), assumptions):
121
+ return ask(Q.negative(expr.base), assumptions)
122
+
123
+ @NegativePredicate.register_many(Abs, ImaginaryUnit)
124
+ def _(expr, assumptions):
125
+ return False
126
+
127
+ @NegativePredicate.register(exp)
128
+ def _(expr, assumptions):
129
+ if ask(Q.real(expr.exp), assumptions):
130
+ return False
131
+ raise MDNotImplementedError
132
+
133
+
134
+ # NonNegativePredicate
135
+
136
+ @NonNegativePredicate.register(Basic)
137
+ def _(expr, assumptions):
138
+ if expr.is_number:
139
+ notnegative = fuzzy_not(_NegativePredicate_number(expr, assumptions))
140
+ if notnegative:
141
+ return ask(Q.real(expr), assumptions)
142
+ else:
143
+ return notnegative
144
+
145
+ @NonNegativePredicate.register(Expr)
146
+ def _(expr, assumptions):
147
+ ret = expr.is_nonnegative
148
+ if ret is None:
149
+ raise MDNotImplementedError
150
+ return ret
151
+
152
+
153
+ # NonZeroPredicate
154
+
155
+ @NonZeroPredicate.register(Expr)
156
+ def _(expr, assumptions):
157
+ ret = expr.is_nonzero
158
+ if ret is None:
159
+ raise MDNotImplementedError
160
+ return ret
161
+
162
+ @NonZeroPredicate.register(Basic)
163
+ def _(expr, assumptions):
164
+ if ask(Q.real(expr)) is False:
165
+ return False
166
+ if expr.is_number:
167
+ # if there are no symbols just evalf
168
+ i = expr.evalf(2)
169
+ def nonz(i):
170
+ if i._prec != 1:
171
+ return i != 0
172
+ return fuzzy_or(nonz(i) for i in i.as_real_imag())
173
+
174
+ @NonZeroPredicate.register(Add)
175
+ def _(expr, assumptions):
176
+ if all(ask(Q.positive(x), assumptions) for x in expr.args) \
177
+ or all(ask(Q.negative(x), assumptions) for x in expr.args):
178
+ return True
179
+
180
+ @NonZeroPredicate.register(Mul)
181
+ def _(expr, assumptions):
182
+ for arg in expr.args:
183
+ result = ask(Q.nonzero(arg), assumptions)
184
+ if result:
185
+ continue
186
+ return result
187
+ return True
188
+
189
+ @NonZeroPredicate.register(Pow)
190
+ def _(expr, assumptions):
191
+ return ask(Q.nonzero(expr.base), assumptions)
192
+
193
+ @NonZeroPredicate.register(Abs)
194
+ def _(expr, assumptions):
195
+ return ask(Q.nonzero(expr.args[0]), assumptions)
196
+
197
+ @NonZeroPredicate.register(NaN)
198
+ def _(expr, assumptions):
199
+ return None
200
+
201
+
202
+ # ZeroPredicate
203
+
204
+ @ZeroPredicate.register(Expr)
205
+ def _(expr, assumptions):
206
+ ret = expr.is_zero
207
+ if ret is None:
208
+ raise MDNotImplementedError
209
+ return ret
210
+
211
+ @ZeroPredicate.register(Basic)
212
+ def _(expr, assumptions):
213
+ return fuzzy_and([fuzzy_not(ask(Q.nonzero(expr), assumptions)),
214
+ ask(Q.real(expr), assumptions)])
215
+
216
+ @ZeroPredicate.register(Mul)
217
+ def _(expr, assumptions):
218
+ # TODO: This should be deducible from the nonzero handler
219
+ return fuzzy_or(ask(Q.zero(arg), assumptions) for arg in expr.args)
220
+
221
+
222
+ # NonPositivePredicate
223
+
224
+ @NonPositivePredicate.register(Expr)
225
+ def _(expr, assumptions):
226
+ ret = expr.is_nonpositive
227
+ if ret is None:
228
+ raise MDNotImplementedError
229
+ return ret
230
+
231
+ @NonPositivePredicate.register(Basic)
232
+ def _(expr, assumptions):
233
+ if expr.is_number:
234
+ notpositive = fuzzy_not(_PositivePredicate_number(expr, assumptions))
235
+ if notpositive:
236
+ return ask(Q.real(expr), assumptions)
237
+ else:
238
+ return notpositive
239
+
240
+
241
+ # PositivePredicate
242
+
243
+ def _PositivePredicate_number(expr, assumptions):
244
+ r, i = expr.as_real_imag()
245
+ # If the imaginary part can symbolically be shown to be zero then
246
+ # we just evaluate the real part; otherwise we evaluate the imaginary
247
+ # part to see if it actually evaluates to zero and if it does then
248
+ # we make the comparison between the real part and zero.
249
+ if not i:
250
+ r = r.evalf(2)
251
+ if r._prec != 1:
252
+ return r > 0
253
+ else:
254
+ i = i.evalf(2)
255
+ if i._prec != 1:
256
+ if i != 0:
257
+ return False
258
+ r = r.evalf(2)
259
+ if r._prec != 1:
260
+ return r > 0
261
+
262
+ @PositivePredicate.register(Expr)
263
+ def _(expr, assumptions):
264
+ ret = expr.is_positive
265
+ if ret is None:
266
+ raise MDNotImplementedError
267
+ return ret
268
+
269
+ @PositivePredicate.register(Basic)
270
+ def _(expr, assumptions):
271
+ if expr.is_number:
272
+ return _PositivePredicate_number(expr, assumptions)
273
+
274
+ @PositivePredicate.register(Mul)
275
+ def _(expr, assumptions):
276
+ if expr.is_number:
277
+ return _PositivePredicate_number(expr, assumptions)
278
+ result = True
279
+ for arg in expr.args:
280
+ if ask(Q.positive(arg), assumptions):
281
+ continue
282
+ elif ask(Q.negative(arg), assumptions):
283
+ result = result ^ True
284
+ else:
285
+ return
286
+ return result
287
+
288
+ @PositivePredicate.register(Add)
289
+ def _(expr, assumptions):
290
+ if expr.is_number:
291
+ return _PositivePredicate_number(expr, assumptions)
292
+
293
+ r = ask(Q.real(expr), assumptions)
294
+ if r is not True:
295
+ return r
296
+
297
+ nonneg = 0
298
+ for arg in expr.args:
299
+ if ask(Q.positive(arg), assumptions) is not True:
300
+ if ask(Q.negative(arg), assumptions) is False:
301
+ nonneg += 1
302
+ else:
303
+ break
304
+ else:
305
+ if nonneg < len(expr.args):
306
+ return True
307
+
308
+ @PositivePredicate.register(Pow)
309
+ def _(expr, assumptions):
310
+ if expr.base == E:
311
+ if ask(Q.real(expr.exp), assumptions):
312
+ return True
313
+ if ask(Q.imaginary(expr.exp), assumptions):
314
+ return ask(Q.even(expr.exp/(I*pi)), assumptions)
315
+ return
316
+
317
+ if expr.is_number:
318
+ return _PositivePredicate_number(expr, assumptions)
319
+ if ask(Q.positive(expr.base), assumptions):
320
+ if ask(Q.real(expr.exp), assumptions):
321
+ return True
322
+ if ask(Q.negative(expr.base), assumptions):
323
+ if ask(Q.even(expr.exp), assumptions):
324
+ return True
325
+ if ask(Q.odd(expr.exp), assumptions):
326
+ return False
327
+
328
+ @PositivePredicate.register(exp)
329
+ def _(expr, assumptions):
330
+ if ask(Q.real(expr.exp), assumptions):
331
+ return True
332
+ if ask(Q.imaginary(expr.exp), assumptions):
333
+ return ask(Q.even(expr.exp/(I*pi)), assumptions)
334
+
335
+ @PositivePredicate.register(log)
336
+ def _(expr, assumptions):
337
+ r = ask(Q.real(expr.args[0]), assumptions)
338
+ if r is not True:
339
+ return r
340
+ if ask(Q.positive(expr.args[0] - 1), assumptions):
341
+ return True
342
+ if ask(Q.negative(expr.args[0] - 1), assumptions):
343
+ return False
344
+
345
+ @PositivePredicate.register(factorial)
346
+ def _(expr, assumptions):
347
+ x = expr.args[0]
348
+ if ask(Q.integer(x) & Q.positive(x), assumptions):
349
+ return True
350
+
351
+ @PositivePredicate.register(ImaginaryUnit)
352
+ def _(expr, assumptions):
353
+ return False
354
+
355
+ @PositivePredicate.register(Abs)
356
+ def _(expr, assumptions):
357
+ return ask(Q.nonzero(expr), assumptions)
358
+
359
+ @PositivePredicate.register(Trace)
360
+ def _(expr, assumptions):
361
+ if ask(Q.positive_definite(expr.arg), assumptions):
362
+ return True
363
+
364
+ @PositivePredicate.register(Determinant)
365
+ def _(expr, assumptions):
366
+ if ask(Q.positive_definite(expr.arg), assumptions):
367
+ return True
368
+
369
+ @PositivePredicate.register(MatrixElement)
370
+ def _(expr, assumptions):
371
+ if (expr.i == expr.j
372
+ and ask(Q.positive_definite(expr.parent), assumptions)):
373
+ return True
374
+
375
+ @PositivePredicate.register(atan)
376
+ def _(expr, assumptions):
377
+ return ask(Q.positive(expr.args[0]), assumptions)
378
+
379
+ @PositivePredicate.register(asin)
380
+ def _(expr, assumptions):
381
+ x = expr.args[0]
382
+ if ask(Q.positive(x) & Q.nonpositive(x - 1), assumptions):
383
+ return True
384
+ if ask(Q.negative(x) & Q.nonnegative(x + 1), assumptions):
385
+ return False
386
+
387
+ @PositivePredicate.register(acos)
388
+ def _(expr, assumptions):
389
+ x = expr.args[0]
390
+ if ask(Q.nonpositive(x - 1) & Q.nonnegative(x + 1), assumptions):
391
+ return True
392
+
393
+ @PositivePredicate.register(acot)
394
+ def _(expr, assumptions):
395
+ return ask(Q.real(expr.args[0]), assumptions)
396
+
397
+ @PositivePredicate.register(NaN)
398
+ def _(expr, assumptions):
399
+ return None
400
+
401
+
402
+ # ExtendedNegativePredicate
403
+
404
+ @ExtendedNegativePredicate.register(object)
405
+ def _(expr, assumptions):
406
+ return ask(Q.negative(expr) | Q.negative_infinite(expr), assumptions)
407
+
408
+
409
+ # ExtendedPositivePredicate
410
+
411
+ @ExtendedPositivePredicate.register(object)
412
+ def _(expr, assumptions):
413
+ return ask(Q.positive(expr) | Q.positive_infinite(expr), assumptions)
414
+
415
+
416
+ # ExtendedNonZeroPredicate
417
+
418
+ @ExtendedNonZeroPredicate.register(object)
419
+ def _(expr, assumptions):
420
+ return ask(
421
+ Q.negative_infinite(expr) | Q.negative(expr) | Q.positive(expr) | Q.positive_infinite(expr),
422
+ assumptions)
423
+
424
+
425
+ # ExtendedNonPositivePredicate
426
+
427
+ @ExtendedNonPositivePredicate.register(object)
428
+ def _(expr, assumptions):
429
+ return ask(
430
+ Q.negative_infinite(expr) | Q.negative(expr) | Q.zero(expr),
431
+ assumptions)
432
+
433
+
434
+ # ExtendedNonNegativePredicate
435
+
436
+ @ExtendedNonNegativePredicate.register(object)
437
+ def _(expr, assumptions):
438
+ return ask(
439
+ Q.zero(expr) | Q.positive(expr) | Q.positive_infinite(expr),
440
+ assumptions)
.venv/lib/python3.13/site-packages/sympy/assumptions/handlers/sets.py ADDED
@@ -0,0 +1,816 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Handlers for predicates related to set membership: integer, rational, etc.
3
+ """
4
+
5
+ from sympy.assumptions import Q, ask
6
+ from sympy.core import Add, Basic, Expr, Mul, Pow, S
7
+ from sympy.core.numbers import (AlgebraicNumber, ComplexInfinity, Exp1, Float,
8
+ GoldenRatio, ImaginaryUnit, Infinity, Integer, NaN, NegativeInfinity,
9
+ Number, NumberSymbol, Pi, pi, Rational, TribonacciConstant, E)
10
+ from sympy.core.logic import fuzzy_bool
11
+ from sympy.functions import (Abs, acos, acot, asin, atan, cos, cot, exp, im,
12
+ log, re, sin, tan)
13
+ from sympy.core.numbers import I
14
+ from sympy.core.relational import Eq
15
+ from sympy.functions.elementary.complexes import conjugate
16
+ from sympy.matrices import Determinant, MatrixBase, Trace
17
+ from sympy.matrices.expressions.matexpr import MatrixElement
18
+
19
+ from sympy.multipledispatch import MDNotImplementedError
20
+
21
+ from .common import test_closed_group, ask_all, ask_any
22
+ from ..predicates.sets import (IntegerPredicate, RationalPredicate,
23
+ IrrationalPredicate, RealPredicate, ExtendedRealPredicate,
24
+ HermitianPredicate, ComplexPredicate, ImaginaryPredicate,
25
+ AntihermitianPredicate, AlgebraicPredicate)
26
+
27
+
28
+ # IntegerPredicate
29
+
30
+ def _IntegerPredicate_number(expr, assumptions):
31
+ # helper function
32
+ try:
33
+ i = int(expr.round())
34
+ if not (expr - i).equals(0):
35
+ raise TypeError
36
+ return True
37
+ except TypeError:
38
+ return False
39
+
40
+ @IntegerPredicate.register_many(int, Integer) # type:ignore
41
+ def _(expr, assumptions):
42
+ return True
43
+
44
+ @IntegerPredicate.register_many(Exp1, GoldenRatio, ImaginaryUnit, Infinity,
45
+ NegativeInfinity, Pi, Rational, TribonacciConstant)
46
+ def _(expr, assumptions):
47
+ return False
48
+
49
+ @IntegerPredicate.register(Expr)
50
+ def _(expr, assumptions):
51
+ ret = expr.is_integer
52
+ if ret is None:
53
+ raise MDNotImplementedError
54
+ return ret
55
+
56
+ @IntegerPredicate.register(Add)
57
+ def _(expr, assumptions):
58
+ """
59
+ * Integer + Integer -> Integer
60
+ * Integer + !Integer -> !Integer
61
+ * !Integer + !Integer -> ?
62
+ """
63
+ if expr.is_number:
64
+ return _IntegerPredicate_number(expr, assumptions)
65
+ return test_closed_group(expr, assumptions, Q.integer)
66
+
67
+ @IntegerPredicate.register(Pow)
68
+ def _(expr,assumptions):
69
+ if expr.is_number:
70
+ return _IntegerPredicate_number(expr, assumptions)
71
+ if ask_all(~Q.zero(expr.base), Q.finite(expr.base), Q.zero(expr.exp), assumptions=assumptions):
72
+ return True
73
+ if ask_all(Q.integer(expr.base), Q.integer(expr.exp), assumptions=assumptions):
74
+ if ask_any(Q.positive(expr.exp), Q.nonnegative(expr.exp) & ~Q.zero(expr.base), Q.zero(expr.base-1), Q.zero(expr.base+1), assumptions=assumptions):
75
+ return True
76
+
77
+ @IntegerPredicate.register(Mul)
78
+ def _(expr, assumptions):
79
+ """
80
+ * Integer*Integer -> Integer
81
+ * Integer*Irrational -> !Integer
82
+ * Odd/Even -> !Integer
83
+ * Integer*Rational -> ?
84
+ """
85
+ if expr.is_number:
86
+ return _IntegerPredicate_number(expr, assumptions)
87
+ _output = True
88
+ for arg in expr.args:
89
+ if not ask(Q.integer(arg), assumptions):
90
+ if arg.is_Rational:
91
+ if arg.q == 2:
92
+ return ask(Q.even(2*expr), assumptions)
93
+ if ~(arg.q & 1):
94
+ return None
95
+ elif ask(Q.irrational(arg), assumptions):
96
+ if _output:
97
+ _output = False
98
+ else:
99
+ return
100
+ else:
101
+ return
102
+
103
+ return _output
104
+
105
+ @IntegerPredicate.register(Abs)
106
+ def _(expr, assumptions):
107
+ if ask(Q.integer(expr.args[0]), assumptions):
108
+ return True
109
+
110
+ @IntegerPredicate.register_many(Determinant, MatrixElement, Trace)
111
+ def _(expr, assumptions):
112
+ return ask(Q.integer_elements(expr.args[0]), assumptions)
113
+
114
+
115
+ # RationalPredicate
116
+
117
+ @RationalPredicate.register(Rational)
118
+ def _(expr, assumptions):
119
+ return True
120
+
121
+ @RationalPredicate.register(Float)
122
+ def _(expr, assumptions):
123
+ return None
124
+
125
+ @RationalPredicate.register_many(Exp1, GoldenRatio, ImaginaryUnit, Infinity,
126
+ NegativeInfinity, Pi, TribonacciConstant)
127
+ def _(expr, assumptions):
128
+ return False
129
+
130
+ @RationalPredicate.register(Expr)
131
+ def _(expr, assumptions):
132
+ ret = expr.is_rational
133
+ if ret is None:
134
+ raise MDNotImplementedError
135
+ return ret
136
+
137
+ @RationalPredicate.register_many(Add, Mul)
138
+ def _(expr, assumptions):
139
+ """
140
+ * Rational + Rational -> Rational
141
+ * Rational + !Rational -> !Rational
142
+ * !Rational + !Rational -> ?
143
+ """
144
+ if expr.is_number:
145
+ if expr.as_real_imag()[1]:
146
+ return False
147
+ return test_closed_group(expr, assumptions, Q.rational)
148
+
149
+ @RationalPredicate.register(Pow)
150
+ def _(expr, assumptions):
151
+ """
152
+ * Rational ** Integer -> Rational
153
+ * Irrational ** Rational -> Irrational
154
+ * Rational ** Irrational -> ?
155
+ """
156
+ if expr.base == E:
157
+ x = expr.exp
158
+ if ask(Q.rational(x), assumptions):
159
+ return ask(Q.zero(x), assumptions)
160
+ return
161
+
162
+ is_exp_integer = ask(Q.integer(expr.exp), assumptions)
163
+ if is_exp_integer:
164
+ is_base_rational = ask(Q.rational(expr.base),assumptions)
165
+ if is_base_rational:
166
+ is_base_zero = ask(Q.zero(expr.base),assumptions)
167
+ if is_base_zero is False:
168
+ return True
169
+ if is_base_zero and ask(Q.positive(expr.exp)):
170
+ return True
171
+ if ask(Q.algebraic(expr.base),assumptions) is False:
172
+ return ask(Q.zero(expr.exp), assumptions)
173
+ if ask(Q.irrational(expr.base),assumptions) and ask(Q.eq(expr.exp,-1)):
174
+ return False
175
+ return
176
+ elif ask(Q.rational(expr.exp), assumptions):
177
+ if ask(Q.prime(expr.base), assumptions) and is_exp_integer is False:
178
+ return False
179
+ if ask(Q.zero(expr.base)) and ask(Q.positive(expr.exp)):
180
+ return True
181
+ if ask(Q.eq(expr.base,1)):
182
+ return True
183
+
184
+ @RationalPredicate.register_many(asin, atan, cos, sin, tan)
185
+ def _(expr, assumptions):
186
+ x = expr.args[0]
187
+ if ask(Q.rational(x), assumptions):
188
+ return ask(~Q.nonzero(x), assumptions)
189
+
190
+ @RationalPredicate.register(exp)
191
+ def _(expr, assumptions):
192
+ x = expr.exp
193
+ if ask(Q.rational(x), assumptions):
194
+ return ask(~Q.nonzero(x), assumptions)
195
+
196
+ @RationalPredicate.register_many(acot, cot)
197
+ def _(expr, assumptions):
198
+ x = expr.args[0]
199
+ if ask(Q.rational(x), assumptions):
200
+ return False
201
+
202
+ @RationalPredicate.register_many(acos, log)
203
+ def _(expr, assumptions):
204
+ x = expr.args[0]
205
+ if ask(Q.rational(x), assumptions):
206
+ return ask(~Q.nonzero(x - 1), assumptions)
207
+
208
+
209
+ # IrrationalPredicate
210
+
211
+ @IrrationalPredicate.register(Expr)
212
+ def _(expr, assumptions):
213
+ ret = expr.is_irrational
214
+ if ret is None:
215
+ raise MDNotImplementedError
216
+ return ret
217
+
218
+ @IrrationalPredicate.register(Basic)
219
+ def _(expr, assumptions):
220
+ _real = ask(Q.real(expr), assumptions)
221
+ if _real:
222
+ _rational = ask(Q.rational(expr), assumptions)
223
+ if _rational is None:
224
+ return None
225
+ return not _rational
226
+ else:
227
+ return _real
228
+
229
+
230
+ # RealPredicate
231
+
232
+ def _RealPredicate_number(expr, assumptions):
233
+ # let as_real_imag() work first since the expression may
234
+ # be simpler to evaluate
235
+ i = expr.as_real_imag()[1].evalf(2)
236
+ if i._prec != 1:
237
+ return not i
238
+ # allow None to be returned if we couldn't show for sure
239
+ # that i was 0
240
+
241
+ @RealPredicate.register_many(Abs, Exp1, Float, GoldenRatio, im, Pi, Rational,
242
+ re, TribonacciConstant)
243
+ def _(expr, assumptions):
244
+ return True
245
+
246
+ @RealPredicate.register_many(ImaginaryUnit, Infinity, NegativeInfinity)
247
+ def _(expr, assumptions):
248
+ return False
249
+
250
+ @RealPredicate.register(Expr)
251
+ def _(expr, assumptions):
252
+ ret = expr.is_real
253
+ if ret is None:
254
+ raise MDNotImplementedError
255
+ return ret
256
+
257
+ @RealPredicate.register(Add)
258
+ def _(expr, assumptions):
259
+ """
260
+ * Real + Real -> Real
261
+ * Real + (Complex & !Real) -> !Real
262
+ """
263
+ if expr.is_number:
264
+ return _RealPredicate_number(expr, assumptions)
265
+ return test_closed_group(expr, assumptions, Q.real)
266
+
267
+ @RealPredicate.register(Mul)
268
+ def _(expr, assumptions):
269
+ """
270
+ * Real*Real -> Real
271
+ * Real*Imaginary -> !Real
272
+ * Imaginary*Imaginary -> Real
273
+ """
274
+ if expr.is_number:
275
+ return _RealPredicate_number(expr, assumptions)
276
+ result = True
277
+ for arg in expr.args:
278
+ if ask(Q.real(arg), assumptions):
279
+ pass
280
+ elif ask(Q.imaginary(arg), assumptions):
281
+ result = result ^ True
282
+ else:
283
+ break
284
+ else:
285
+ return result
286
+
287
+ @RealPredicate.register(Pow)
288
+ def _(expr, assumptions):
289
+ """
290
+ * Real**Integer -> Real
291
+ * Positive**Real -> Real
292
+ * Negative**Real -> ?
293
+ * Real**(Integer/Even) -> Real if base is nonnegative
294
+ * Real**(Integer/Odd) -> Real
295
+ * Imaginary**(Integer/Even) -> Real
296
+ * Imaginary**(Integer/Odd) -> not Real
297
+ * Imaginary**Real -> ? since Real could be 0 (giving real)
298
+ or 1 (giving imaginary)
299
+ * b**Imaginary -> Real if log(b) is imaginary and b != 0
300
+ and exponent != integer multiple of
301
+ I*pi/log(b)
302
+ * Real**Real -> ? e.g. sqrt(-1) is imaginary and
303
+ sqrt(2) is not
304
+ """
305
+ if expr.is_number:
306
+ return _RealPredicate_number(expr, assumptions)
307
+
308
+ if expr.base == E:
309
+ return ask(
310
+ Q.integer(expr.exp/I/pi) | Q.real(expr.exp), assumptions
311
+ )
312
+
313
+ if expr.base.func == exp or (expr.base.is_Pow and expr.base.base == E):
314
+ if ask(Q.imaginary(expr.base.exp), assumptions):
315
+ if ask(Q.imaginary(expr.exp), assumptions):
316
+ return True
317
+ # If the i = (exp's arg)/(I*pi) is an integer or half-integer
318
+ # multiple of I*pi then 2*i will be an integer. In addition,
319
+ # exp(i*I*pi) = (-1)**i so the overall realness of the expr
320
+ # can be determined by replacing exp(i*I*pi) with (-1)**i.
321
+ i = expr.base.exp/I/pi
322
+ if ask(Q.integer(2*i), assumptions):
323
+ return ask(Q.real((S.NegativeOne**i)**expr.exp), assumptions)
324
+ return
325
+
326
+ if ask(Q.imaginary(expr.base), assumptions):
327
+ if ask(Q.integer(expr.exp), assumptions):
328
+ odd = ask(Q.odd(expr.exp), assumptions)
329
+ if odd is not None:
330
+ return not odd
331
+ return
332
+
333
+ if ask(Q.imaginary(expr.exp), assumptions):
334
+ imlog = ask(Q.imaginary(log(expr.base)), assumptions)
335
+ if imlog is not None:
336
+ # I**i -> real, log(I) is imag;
337
+ # (2*I)**i -> complex, log(2*I) is not imag
338
+ return imlog
339
+
340
+ if ask(Q.real(expr.base), assumptions):
341
+ if ask(Q.real(expr.exp), assumptions):
342
+ if ask(Q.zero(expr.base), assumptions) is not False:
343
+ if ask(Q.positive(expr.exp), assumptions):
344
+ return True
345
+ return
346
+ if expr.exp.is_Rational and \
347
+ ask(Q.even(expr.exp.q), assumptions):
348
+ return ask(Q.positive(expr.base), assumptions)
349
+ elif ask(Q.integer(expr.exp), assumptions):
350
+ return True
351
+ elif ask(Q.positive(expr.base), assumptions):
352
+ return True
353
+
354
+ @RealPredicate.register_many(cos, sin)
355
+ def _(expr, assumptions):
356
+ if ask(Q.real(expr.args[0]), assumptions):
357
+ return True
358
+
359
+ @RealPredicate.register(exp)
360
+ def _(expr, assumptions):
361
+ return ask(
362
+ Q.integer(expr.exp/I/pi) | Q.real(expr.exp), assumptions
363
+ )
364
+
365
+ @RealPredicate.register(log)
366
+ def _(expr, assumptions):
367
+ return ask(Q.positive(expr.args[0]), assumptions)
368
+
369
+ @RealPredicate.register_many(Determinant, MatrixElement, Trace)
370
+ def _(expr, assumptions):
371
+ return ask(Q.real_elements(expr.args[0]), assumptions)
372
+
373
+
374
+ # ExtendedRealPredicate
375
+
376
+ @ExtendedRealPredicate.register(object)
377
+ def _(expr, assumptions):
378
+ return ask(Q.negative_infinite(expr)
379
+ | Q.negative(expr)
380
+ | Q.zero(expr)
381
+ | Q.positive(expr)
382
+ | Q.positive_infinite(expr),
383
+ assumptions)
384
+
385
+ @ExtendedRealPredicate.register_many(Infinity, NegativeInfinity)
386
+ def _(expr, assumptions):
387
+ return True
388
+
389
+ @ExtendedRealPredicate.register_many(Add, Mul, Pow) # type:ignore
390
+ def _(expr, assumptions):
391
+ return test_closed_group(expr, assumptions, Q.extended_real)
392
+
393
+
394
+ # HermitianPredicate
395
+
396
+ @HermitianPredicate.register(object) # type:ignore
397
+ def _(expr, assumptions):
398
+ if isinstance(expr, MatrixBase):
399
+ return None
400
+ return ask(Q.real(expr), assumptions)
401
+
402
+ @HermitianPredicate.register(Add) # type:ignore
403
+ def _(expr, assumptions):
404
+ """
405
+ * Hermitian + Hermitian -> Hermitian
406
+ * Hermitian + !Hermitian -> !Hermitian
407
+ """
408
+ if expr.is_number:
409
+ raise MDNotImplementedError
410
+ return test_closed_group(expr, assumptions, Q.hermitian)
411
+
412
+ @HermitianPredicate.register(Mul) # type:ignore
413
+ def _(expr, assumptions):
414
+ """
415
+ As long as there is at most only one noncommutative term:
416
+
417
+ * Hermitian*Hermitian -> Hermitian
418
+ * Hermitian*Antihermitian -> !Hermitian
419
+ * Antihermitian*Antihermitian -> Hermitian
420
+ """
421
+ if expr.is_number:
422
+ raise MDNotImplementedError
423
+ nccount = 0
424
+ result = True
425
+ for arg in expr.args:
426
+ if ask(Q.antihermitian(arg), assumptions):
427
+ result = result ^ True
428
+ elif not ask(Q.hermitian(arg), assumptions):
429
+ break
430
+ if ask(~Q.commutative(arg), assumptions):
431
+ nccount += 1
432
+ if nccount > 1:
433
+ break
434
+ else:
435
+ return result
436
+
437
+ @HermitianPredicate.register(Pow) # type:ignore
438
+ def _(expr, assumptions):
439
+ """
440
+ * Hermitian**Integer -> Hermitian
441
+ """
442
+ if expr.is_number:
443
+ raise MDNotImplementedError
444
+ if expr.base == E:
445
+ if ask(Q.hermitian(expr.exp), assumptions):
446
+ return True
447
+ raise MDNotImplementedError
448
+ if ask(Q.hermitian(expr.base), assumptions):
449
+ if ask(Q.integer(expr.exp), assumptions):
450
+ return True
451
+ raise MDNotImplementedError
452
+
453
+ @HermitianPredicate.register_many(cos, sin) # type:ignore
454
+ def _(expr, assumptions):
455
+ if ask(Q.hermitian(expr.args[0]), assumptions):
456
+ return True
457
+ raise MDNotImplementedError
458
+
459
+ @HermitianPredicate.register(exp) # type:ignore
460
+ def _(expr, assumptions):
461
+ if ask(Q.hermitian(expr.exp), assumptions):
462
+ return True
463
+ raise MDNotImplementedError
464
+
465
+ @HermitianPredicate.register(MatrixBase) # type:ignore
466
+ def _(mat, assumptions):
467
+ rows, cols = mat.shape
468
+ ret_val = True
469
+ for i in range(rows):
470
+ for j in range(i, cols):
471
+ cond = fuzzy_bool(Eq(mat[i, j], conjugate(mat[j, i])))
472
+ if cond is None:
473
+ ret_val = None
474
+ if cond == False:
475
+ return False
476
+ if ret_val is None:
477
+ raise MDNotImplementedError
478
+ return ret_val
479
+
480
+
481
+ # ComplexPredicate
482
+
483
+ @ComplexPredicate.register_many(Abs, cos, exp, im, ImaginaryUnit, log, Number, # type:ignore
484
+ NumberSymbol, re, sin)
485
+ def _(expr, assumptions):
486
+ return True
487
+
488
+ @ComplexPredicate.register_many(Infinity, NegativeInfinity) # type:ignore
489
+ def _(expr, assumptions):
490
+ return False
491
+
492
+ @ComplexPredicate.register(Expr) # type:ignore
493
+ def _(expr, assumptions):
494
+ ret = expr.is_complex
495
+ if ret is None:
496
+ raise MDNotImplementedError
497
+ return ret
498
+
499
+ @ComplexPredicate.register_many(Add, Mul) # type:ignore
500
+ def _(expr, assumptions):
501
+ return test_closed_group(expr, assumptions, Q.complex)
502
+
503
+ @ComplexPredicate.register(Pow) # type:ignore
504
+ def _(expr, assumptions):
505
+ if expr.base == E:
506
+ return True
507
+ return test_closed_group(expr, assumptions, Q.complex)
508
+
509
+ @ComplexPredicate.register_many(Determinant, MatrixElement, Trace) # type:ignore
510
+ def _(expr, assumptions):
511
+ return ask(Q.complex_elements(expr.args[0]), assumptions)
512
+
513
+ @ComplexPredicate.register(NaN) # type:ignore
514
+ def _(expr, assumptions):
515
+ return None
516
+
517
+
518
+ # ImaginaryPredicate
519
+
520
+ def _Imaginary_number(expr, assumptions):
521
+ # let as_real_imag() work first since the expression may
522
+ # be simpler to evaluate
523
+ r = expr.as_real_imag()[0].evalf(2)
524
+ if r._prec != 1:
525
+ return not r
526
+ # allow None to be returned if we couldn't show for sure
527
+ # that r was 0
528
+
529
+ @ImaginaryPredicate.register(ImaginaryUnit) # type:ignore
530
+ def _(expr, assumptions):
531
+ return True
532
+
533
+ @ImaginaryPredicate.register(Expr) # type:ignore
534
+ def _(expr, assumptions):
535
+ ret = expr.is_imaginary
536
+ if ret is None:
537
+ raise MDNotImplementedError
538
+ return ret
539
+
540
+ @ImaginaryPredicate.register(Add) # type:ignore
541
+ def _(expr, assumptions):
542
+ """
543
+ * Imaginary + Imaginary -> Imaginary
544
+ * Imaginary + Complex -> ?
545
+ * Imaginary + Real -> !Imaginary
546
+ """
547
+ if expr.is_number:
548
+ return _Imaginary_number(expr, assumptions)
549
+
550
+ reals = 0
551
+ for arg in expr.args:
552
+ if ask(Q.imaginary(arg), assumptions):
553
+ pass
554
+ elif ask(Q.real(arg), assumptions):
555
+ reals += 1
556
+ else:
557
+ break
558
+ else:
559
+ if reals == 0:
560
+ return True
561
+ if reals in (1, len(expr.args)):
562
+ # two reals could sum 0 thus giving an imaginary
563
+ return False
564
+
565
+ @ImaginaryPredicate.register(Mul) # type:ignore
566
+ def _(expr, assumptions):
567
+ """
568
+ * Real*Imaginary -> Imaginary
569
+ * Imaginary*Imaginary -> Real
570
+ """
571
+ if expr.is_number:
572
+ return _Imaginary_number(expr, assumptions)
573
+ result = False
574
+ reals = 0
575
+ for arg in expr.args:
576
+ if ask(Q.imaginary(arg), assumptions):
577
+ result = result ^ True
578
+ elif not ask(Q.real(arg), assumptions):
579
+ break
580
+ else:
581
+ if reals == len(expr.args):
582
+ return False
583
+ return result
584
+
585
+ @ImaginaryPredicate.register(Pow) # type:ignore
586
+ def _(expr, assumptions):
587
+ """
588
+ * Imaginary**Odd -> Imaginary
589
+ * Imaginary**Even -> Real
590
+ * b**Imaginary -> !Imaginary if exponent is an integer
591
+ multiple of I*pi/log(b)
592
+ * Imaginary**Real -> ?
593
+ * Positive**Real -> Real
594
+ * Negative**Integer -> Real
595
+ * Negative**(Integer/2) -> Imaginary
596
+ * Negative**Real -> not Imaginary if exponent is not Rational
597
+ """
598
+ if expr.is_number:
599
+ return _Imaginary_number(expr, assumptions)
600
+
601
+ if expr.base == E:
602
+ a = expr.exp/I/pi
603
+ return ask(Q.integer(2*a) & ~Q.integer(a), assumptions)
604
+
605
+ if expr.base.func == exp or (expr.base.is_Pow and expr.base.base == E):
606
+ if ask(Q.imaginary(expr.base.exp), assumptions):
607
+ if ask(Q.imaginary(expr.exp), assumptions):
608
+ return False
609
+ i = expr.base.exp/I/pi
610
+ if ask(Q.integer(2*i), assumptions):
611
+ return ask(Q.imaginary((S.NegativeOne**i)**expr.exp), assumptions)
612
+
613
+ if ask(Q.imaginary(expr.base), assumptions):
614
+ if ask(Q.integer(expr.exp), assumptions):
615
+ odd = ask(Q.odd(expr.exp), assumptions)
616
+ if odd is not None:
617
+ return odd
618
+ return
619
+
620
+ if ask(Q.imaginary(expr.exp), assumptions):
621
+ imlog = ask(Q.imaginary(log(expr.base)), assumptions)
622
+ if imlog is not None:
623
+ # I**i -> real; (2*I)**i -> complex ==> not imaginary
624
+ return False
625
+
626
+ if ask(Q.real(expr.base) & Q.real(expr.exp), assumptions):
627
+ if ask(Q.positive(expr.base), assumptions):
628
+ return False
629
+ else:
630
+ rat = ask(Q.rational(expr.exp), assumptions)
631
+ if not rat:
632
+ return rat
633
+ if ask(Q.integer(expr.exp), assumptions):
634
+ return False
635
+ else:
636
+ half = ask(Q.integer(2*expr.exp), assumptions)
637
+ if half:
638
+ return ask(Q.negative(expr.base), assumptions)
639
+ return half
640
+
641
+ @ImaginaryPredicate.register(log) # type:ignore
642
+ def _(expr, assumptions):
643
+ if ask(Q.real(expr.args[0]), assumptions):
644
+ if ask(Q.positive(expr.args[0]), assumptions):
645
+ return False
646
+ return
647
+ # XXX it should be enough to do
648
+ # return ask(Q.nonpositive(expr.args[0]), assumptions)
649
+ # but ask(Q.nonpositive(exp(x)), Q.imaginary(x)) -> None;
650
+ # it should return True since exp(x) will be either 0 or complex
651
+ if expr.args[0].func == exp or (expr.args[0].is_Pow and expr.args[0].base == E):
652
+ if expr.args[0].exp in [I, -I]:
653
+ return True
654
+ im = ask(Q.imaginary(expr.args[0]), assumptions)
655
+ if im is False:
656
+ return False
657
+
658
+ @ImaginaryPredicate.register(exp) # type:ignore
659
+ def _(expr, assumptions):
660
+ a = expr.exp/I/pi
661
+ return ask(Q.integer(2*a) & ~Q.integer(a), assumptions)
662
+
663
+ @ImaginaryPredicate.register_many(Number, NumberSymbol) # type:ignore
664
+ def _(expr, assumptions):
665
+ return not (expr.as_real_imag()[1] == 0)
666
+
667
+ @ImaginaryPredicate.register(NaN) # type:ignore
668
+ def _(expr, assumptions):
669
+ return None
670
+
671
+
672
+ # AntihermitianPredicate
673
+
674
+ @AntihermitianPredicate.register(object) # type:ignore
675
+ def _(expr, assumptions):
676
+ if isinstance(expr, MatrixBase):
677
+ return None
678
+ if ask(Q.zero(expr), assumptions):
679
+ return True
680
+ return ask(Q.imaginary(expr), assumptions)
681
+
682
+ @AntihermitianPredicate.register(Add) # type:ignore
683
+ def _(expr, assumptions):
684
+ """
685
+ * Antihermitian + Antihermitian -> Antihermitian
686
+ * Antihermitian + !Antihermitian -> !Antihermitian
687
+ """
688
+ if expr.is_number:
689
+ raise MDNotImplementedError
690
+ return test_closed_group(expr, assumptions, Q.antihermitian)
691
+
692
+ @AntihermitianPredicate.register(Mul) # type:ignore
693
+ def _(expr, assumptions):
694
+ """
695
+ As long as there is at most only one noncommutative term:
696
+
697
+ * Hermitian*Hermitian -> !Antihermitian
698
+ * Hermitian*Antihermitian -> Antihermitian
699
+ * Antihermitian*Antihermitian -> !Antihermitian
700
+ """
701
+ if expr.is_number:
702
+ raise MDNotImplementedError
703
+ nccount = 0
704
+ result = False
705
+ for arg in expr.args:
706
+ if ask(Q.antihermitian(arg), assumptions):
707
+ result = result ^ True
708
+ elif not ask(Q.hermitian(arg), assumptions):
709
+ break
710
+ if ask(~Q.commutative(arg), assumptions):
711
+ nccount += 1
712
+ if nccount > 1:
713
+ break
714
+ else:
715
+ return result
716
+
717
+ @AntihermitianPredicate.register(Pow) # type:ignore
718
+ def _(expr, assumptions):
719
+ """
720
+ * Hermitian**Integer -> !Antihermitian
721
+ * Antihermitian**Even -> !Antihermitian
722
+ * Antihermitian**Odd -> Antihermitian
723
+ """
724
+ if expr.is_number:
725
+ raise MDNotImplementedError
726
+ if ask(Q.hermitian(expr.base), assumptions):
727
+ if ask(Q.integer(expr.exp), assumptions):
728
+ return False
729
+ elif ask(Q.antihermitian(expr.base), assumptions):
730
+ if ask(Q.even(expr.exp), assumptions):
731
+ return False
732
+ elif ask(Q.odd(expr.exp), assumptions):
733
+ return True
734
+ raise MDNotImplementedError
735
+
736
+ @AntihermitianPredicate.register(MatrixBase) # type:ignore
737
+ def _(mat, assumptions):
738
+ rows, cols = mat.shape
739
+ ret_val = True
740
+ for i in range(rows):
741
+ for j in range(i, cols):
742
+ cond = fuzzy_bool(Eq(mat[i, j], -conjugate(mat[j, i])))
743
+ if cond is None:
744
+ ret_val = None
745
+ if cond == False:
746
+ return False
747
+ if ret_val is None:
748
+ raise MDNotImplementedError
749
+ return ret_val
750
+
751
+
752
+ # AlgebraicPredicate
753
+
754
+ @AlgebraicPredicate.register_many(AlgebraicNumber, Float, GoldenRatio, # type:ignore
755
+ ImaginaryUnit, TribonacciConstant)
756
+ def _(expr, assumptions):
757
+ return True
758
+
759
+ @AlgebraicPredicate.register_many(ComplexInfinity, Exp1, Infinity, # type:ignore
760
+ NegativeInfinity, Pi)
761
+ def _(expr, assumptions):
762
+ return False
763
+
764
+ @AlgebraicPredicate.register_many(Add, Mul) # type:ignore
765
+ def _(expr, assumptions):
766
+ return test_closed_group(expr, assumptions, Q.algebraic)
767
+
768
+ @AlgebraicPredicate.register(Pow) # type:ignore
769
+ def _(expr, assumptions):
770
+ if expr.base == E:
771
+ if ask(Q.algebraic(expr.exp), assumptions):
772
+ return ask(~Q.nonzero(expr.exp), assumptions)
773
+ return
774
+ if expr.base == pi:
775
+ if ask(Q.integer(expr.exp), assumptions) and ask(Q.positive(expr.exp), assumptions):
776
+ return False
777
+ return
778
+ exp_rational = ask(Q.rational(expr.exp), assumptions)
779
+ base_algebraic = ask(Q.algebraic(expr.base), assumptions)
780
+ exp_algebraic = ask(Q.algebraic(expr.exp),assumptions)
781
+ if base_algebraic and exp_algebraic:
782
+ if exp_rational:
783
+ return True
784
+ # Check based on the Gelfond-Schneider theorem:
785
+ # If the base is algebraic and not equal to 0 or 1, and the exponent
786
+ # is irrational,then the result is transcendental.
787
+ if ask(Q.ne(expr.base,0) & Q.ne(expr.base,1)) and exp_rational is False:
788
+ return False
789
+
790
+ @AlgebraicPredicate.register(Rational) # type:ignore
791
+ def _(expr, assumptions):
792
+ return expr.q != 0
793
+
794
+ @AlgebraicPredicate.register_many(asin, atan, cos, sin, tan) # type:ignore
795
+ def _(expr, assumptions):
796
+ x = expr.args[0]
797
+ if ask(Q.algebraic(x), assumptions):
798
+ return ask(~Q.nonzero(x), assumptions)
799
+
800
+ @AlgebraicPredicate.register(exp) # type:ignore
801
+ def _(expr, assumptions):
802
+ x = expr.exp
803
+ if ask(Q.algebraic(x), assumptions):
804
+ return ask(~Q.nonzero(x), assumptions)
805
+
806
+ @AlgebraicPredicate.register_many(acot, cot) # type:ignore
807
+ def _(expr, assumptions):
808
+ x = expr.args[0]
809
+ if ask(Q.algebraic(x), assumptions):
810
+ return False
811
+
812
+ @AlgebraicPredicate.register_many(acos, log) # type:ignore
813
+ def _(expr, assumptions):
814
+ x = expr.args[0]
815
+ if ask(Q.algebraic(x), assumptions):
816
+ return ask(~Q.nonzero(x - 1), assumptions)
.venv/lib/python3.13/site-packages/sympy/assumptions/predicates/__init__.py ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ """
2
+ Module to implement predicate classes.
3
+
4
+ Class of every predicate registered to ``Q`` is defined here.
5
+ """
.venv/lib/python3.13/site-packages/sympy/assumptions/predicates/calculus.py ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.assumptions import Predicate
2
+ from sympy.multipledispatch import Dispatcher
3
+
4
+ class FinitePredicate(Predicate):
5
+ """
6
+ Finite number predicate.
7
+
8
+ Explanation
9
+ ===========
10
+
11
+ ``Q.finite(x)`` is true if ``x`` is a number but neither an infinity
12
+ nor a ``NaN``. In other words, ``ask(Q.finite(x))`` is true for all
13
+ numerical ``x`` having a bounded absolute value.
14
+
15
+ Examples
16
+ ========
17
+
18
+ >>> from sympy import Q, ask, S, oo, I, zoo
19
+ >>> from sympy.abc import x
20
+ >>> ask(Q.finite(oo))
21
+ False
22
+ >>> ask(Q.finite(-oo))
23
+ False
24
+ >>> ask(Q.finite(zoo))
25
+ False
26
+ >>> ask(Q.finite(1))
27
+ True
28
+ >>> ask(Q.finite(2 + 3*I))
29
+ True
30
+ >>> ask(Q.finite(x), Q.positive(x))
31
+ True
32
+ >>> print(ask(Q.finite(S.NaN)))
33
+ None
34
+
35
+ References
36
+ ==========
37
+
38
+ .. [1] https://en.wikipedia.org/wiki/Finite
39
+
40
+ """
41
+ name = 'finite'
42
+ handler = Dispatcher(
43
+ "FiniteHandler",
44
+ doc=("Handler for Q.finite. Test that an expression is bounded respect"
45
+ " to all its variables.")
46
+ )
47
+
48
+
49
+ class InfinitePredicate(Predicate):
50
+ """
51
+ Infinite number predicate.
52
+
53
+ ``Q.infinite(x)`` is true iff the absolute value of ``x`` is
54
+ infinity.
55
+
56
+ """
57
+ # TODO: Add examples
58
+ name = 'infinite'
59
+ handler = Dispatcher(
60
+ "InfiniteHandler",
61
+ doc="""Handler for Q.infinite key."""
62
+ )
63
+
64
+
65
+ class PositiveInfinitePredicate(Predicate):
66
+ """
67
+ Positive infinity predicate.
68
+
69
+ ``Q.positive_infinite(x)`` is true iff ``x`` is positive infinity ``oo``.
70
+ """
71
+ name = 'positive_infinite'
72
+ handler = Dispatcher("PositiveInfiniteHandler")
73
+
74
+
75
+ class NegativeInfinitePredicate(Predicate):
76
+ """
77
+ Negative infinity predicate.
78
+
79
+ ``Q.negative_infinite(x)`` is true iff ``x`` is negative infinity ``-oo``.
80
+ """
81
+ name = 'negative_infinite'
82
+ handler = Dispatcher("NegativeInfiniteHandler")
.venv/lib/python3.13/site-packages/sympy/assumptions/predicates/common.py ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.assumptions import Predicate, AppliedPredicate, Q
2
+ from sympy.core.relational import Eq, Ne, Gt, Lt, Ge, Le
3
+ from sympy.multipledispatch import Dispatcher
4
+
5
+
6
+ class CommutativePredicate(Predicate):
7
+ """
8
+ Commutative predicate.
9
+
10
+ Explanation
11
+ ===========
12
+
13
+ ``ask(Q.commutative(x))`` is true iff ``x`` commutes with any other
14
+ object with respect to multiplication operation.
15
+
16
+ """
17
+ # TODO: Add examples
18
+ name = 'commutative'
19
+ handler = Dispatcher("CommutativeHandler", doc="Handler for key 'commutative'.")
20
+
21
+
22
+ binrelpreds = {Eq: Q.eq, Ne: Q.ne, Gt: Q.gt, Lt: Q.lt, Ge: Q.ge, Le: Q.le}
23
+
24
+ class IsTruePredicate(Predicate):
25
+ """
26
+ Generic predicate.
27
+
28
+ Explanation
29
+ ===========
30
+
31
+ ``ask(Q.is_true(x))`` is true iff ``x`` is true. This only makes
32
+ sense if ``x`` is a boolean object.
33
+
34
+ Examples
35
+ ========
36
+
37
+ >>> from sympy import ask, Q
38
+ >>> from sympy.abc import x, y
39
+ >>> ask(Q.is_true(True))
40
+ True
41
+
42
+ Wrapping another applied predicate just returns the applied predicate.
43
+
44
+ >>> Q.is_true(Q.even(x))
45
+ Q.even(x)
46
+
47
+ Wrapping binary relation classes in SymPy core returns applied binary
48
+ relational predicates.
49
+
50
+ >>> from sympy import Eq, Gt
51
+ >>> Q.is_true(Eq(x, y))
52
+ Q.eq(x, y)
53
+ >>> Q.is_true(Gt(x, y))
54
+ Q.gt(x, y)
55
+
56
+ Notes
57
+ =====
58
+
59
+ This class is designed to wrap the boolean objects so that they can
60
+ behave as if they are applied predicates. Consequently, wrapping another
61
+ applied predicate is unnecessary and thus it just returns the argument.
62
+ Also, binary relation classes in SymPy core have binary predicates to
63
+ represent themselves and thus wrapping them with ``Q.is_true`` converts them
64
+ to these applied predicates.
65
+
66
+ """
67
+ name = 'is_true'
68
+ handler = Dispatcher(
69
+ "IsTrueHandler",
70
+ doc="Wrapper allowing to query the truth value of a boolean expression."
71
+ )
72
+
73
+ def __call__(self, arg):
74
+ # No need to wrap another predicate
75
+ if isinstance(arg, AppliedPredicate):
76
+ return arg
77
+ # Convert relational predicates instead of wrapping them
78
+ if getattr(arg, "is_Relational", False):
79
+ pred = binrelpreds[type(arg)]
80
+ return pred(*arg.args)
81
+ return super().__call__(arg)
.venv/lib/python3.13/site-packages/sympy/assumptions/predicates/ntheory.py ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.assumptions import Predicate
2
+ from sympy.multipledispatch import Dispatcher
3
+
4
+
5
+ class PrimePredicate(Predicate):
6
+ """
7
+ Prime number predicate.
8
+
9
+ Explanation
10
+ ===========
11
+
12
+ ``ask(Q.prime(x))`` is true iff ``x`` is a natural number greater
13
+ than 1 that has no positive divisors other than ``1`` and the
14
+ number itself.
15
+
16
+ Examples
17
+ ========
18
+
19
+ >>> from sympy import Q, ask
20
+ >>> ask(Q.prime(0))
21
+ False
22
+ >>> ask(Q.prime(1))
23
+ False
24
+ >>> ask(Q.prime(2))
25
+ True
26
+ >>> ask(Q.prime(20))
27
+ False
28
+ >>> ask(Q.prime(-3))
29
+ False
30
+
31
+ """
32
+ name = 'prime'
33
+ handler = Dispatcher(
34
+ "PrimeHandler",
35
+ doc=("Handler for key 'prime'. Test that an expression represents a prime"
36
+ " number. When the expression is an exact number, the result (when True)"
37
+ " is subject to the limitations of isprime() which is used to return the "
38
+ "result.")
39
+ )
40
+
41
+
42
+ class CompositePredicate(Predicate):
43
+ """
44
+ Composite number predicate.
45
+
46
+ Explanation
47
+ ===========
48
+
49
+ ``ask(Q.composite(x))`` is true iff ``x`` is a positive integer and has
50
+ at least one positive divisor other than ``1`` and the number itself.
51
+
52
+ Examples
53
+ ========
54
+
55
+ >>> from sympy import Q, ask
56
+ >>> ask(Q.composite(0))
57
+ False
58
+ >>> ask(Q.composite(1))
59
+ False
60
+ >>> ask(Q.composite(2))
61
+ False
62
+ >>> ask(Q.composite(20))
63
+ True
64
+
65
+ """
66
+ name = 'composite'
67
+ handler = Dispatcher("CompositeHandler", doc="Handler for key 'composite'.")
68
+
69
+
70
+ class EvenPredicate(Predicate):
71
+ """
72
+ Even number predicate.
73
+
74
+ Explanation
75
+ ===========
76
+
77
+ ``ask(Q.even(x))`` is true iff ``x`` belongs to the set of even
78
+ integers.
79
+
80
+ Examples
81
+ ========
82
+
83
+ >>> from sympy import Q, ask, pi
84
+ >>> ask(Q.even(0))
85
+ True
86
+ >>> ask(Q.even(2))
87
+ True
88
+ >>> ask(Q.even(3))
89
+ False
90
+ >>> ask(Q.even(pi))
91
+ False
92
+
93
+ """
94
+ name = 'even'
95
+ handler = Dispatcher("EvenHandler", doc="Handler for key 'even'.")
96
+
97
+
98
+ class OddPredicate(Predicate):
99
+ """
100
+ Odd number predicate.
101
+
102
+ Explanation
103
+ ===========
104
+
105
+ ``ask(Q.odd(x))`` is true iff ``x`` belongs to the set of odd numbers.
106
+
107
+ Examples
108
+ ========
109
+
110
+ >>> from sympy import Q, ask, pi
111
+ >>> ask(Q.odd(0))
112
+ False
113
+ >>> ask(Q.odd(2))
114
+ False
115
+ >>> ask(Q.odd(3))
116
+ True
117
+ >>> ask(Q.odd(pi))
118
+ False
119
+
120
+ """
121
+ name = 'odd'
122
+ handler = Dispatcher(
123
+ "OddHandler",
124
+ doc=("Handler for key 'odd'. Test that an expression represents an odd"
125
+ " number.")
126
+ )
.venv/lib/python3.13/site-packages/sympy/assumptions/predicates/sets.py ADDED
@@ -0,0 +1,399 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.assumptions import Predicate
2
+ from sympy.multipledispatch import Dispatcher
3
+
4
+
5
+ class IntegerPredicate(Predicate):
6
+ """
7
+ Integer predicate.
8
+
9
+ Explanation
10
+ ===========
11
+
12
+ ``Q.integer(x)`` is true iff ``x`` belongs to the set of integer
13
+ numbers.
14
+
15
+ Examples
16
+ ========
17
+
18
+ >>> from sympy import Q, ask, S
19
+ >>> ask(Q.integer(5))
20
+ True
21
+ >>> ask(Q.integer(S(1)/2))
22
+ False
23
+
24
+ References
25
+ ==========
26
+
27
+ .. [1] https://en.wikipedia.org/wiki/Integer
28
+
29
+ """
30
+ name = 'integer'
31
+ handler = Dispatcher(
32
+ "IntegerHandler",
33
+ doc=("Handler for Q.integer.\n\n"
34
+ "Test that an expression belongs to the field of integer numbers.")
35
+ )
36
+
37
+
38
+ class NonIntegerPredicate(Predicate):
39
+ """
40
+ Non-integer extended real predicate.
41
+ """
42
+ name = 'noninteger'
43
+ handler = Dispatcher(
44
+ "NonIntegerHandler",
45
+ doc=("Handler for Q.noninteger.\n\n"
46
+ "Test that an expression is a non-integer extended real number.")
47
+ )
48
+
49
+
50
+ class RationalPredicate(Predicate):
51
+ """
52
+ Rational number predicate.
53
+
54
+ Explanation
55
+ ===========
56
+
57
+ ``Q.rational(x)`` is true iff ``x`` belongs to the set of
58
+ rational numbers.
59
+
60
+ Examples
61
+ ========
62
+
63
+ >>> from sympy import ask, Q, pi, S
64
+ >>> ask(Q.rational(0))
65
+ True
66
+ >>> ask(Q.rational(S(1)/2))
67
+ True
68
+ >>> ask(Q.rational(pi))
69
+ False
70
+
71
+ References
72
+ ==========
73
+
74
+ .. [1] https://en.wikipedia.org/wiki/Rational_number
75
+
76
+ """
77
+ name = 'rational'
78
+ handler = Dispatcher(
79
+ "RationalHandler",
80
+ doc=("Handler for Q.rational.\n\n"
81
+ "Test that an expression belongs to the field of rational numbers.")
82
+ )
83
+
84
+
85
+ class IrrationalPredicate(Predicate):
86
+ """
87
+ Irrational number predicate.
88
+
89
+ Explanation
90
+ ===========
91
+
92
+ ``Q.irrational(x)`` is true iff ``x`` is any real number that
93
+ cannot be expressed as a ratio of integers.
94
+
95
+ Examples
96
+ ========
97
+
98
+ >>> from sympy import ask, Q, pi, S, I
99
+ >>> ask(Q.irrational(0))
100
+ False
101
+ >>> ask(Q.irrational(S(1)/2))
102
+ False
103
+ >>> ask(Q.irrational(pi))
104
+ True
105
+ >>> ask(Q.irrational(I))
106
+ False
107
+
108
+ References
109
+ ==========
110
+
111
+ .. [1] https://en.wikipedia.org/wiki/Irrational_number
112
+
113
+ """
114
+ name = 'irrational'
115
+ handler = Dispatcher(
116
+ "IrrationalHandler",
117
+ doc=("Handler for Q.irrational.\n\n"
118
+ "Test that an expression is irrational numbers.")
119
+ )
120
+
121
+
122
+ class RealPredicate(Predicate):
123
+ r"""
124
+ Real number predicate.
125
+
126
+ Explanation
127
+ ===========
128
+
129
+ ``Q.real(x)`` is true iff ``x`` is a real number, i.e., it is in the
130
+ interval `(-\infty, \infty)`. Note that, in particular the
131
+ infinities are not real. Use ``Q.extended_real`` if you want to
132
+ consider those as well.
133
+
134
+ A few important facts about reals:
135
+
136
+ - Every real number is positive, negative, or zero. Furthermore,
137
+ because these sets are pairwise disjoint, each real number is
138
+ exactly one of those three.
139
+
140
+ - Every real number is also complex.
141
+
142
+ - Every real number is finite.
143
+
144
+ - Every real number is either rational or irrational.
145
+
146
+ - Every real number is either algebraic or transcendental.
147
+
148
+ - The facts ``Q.negative``, ``Q.zero``, ``Q.positive``,
149
+ ``Q.nonnegative``, ``Q.nonpositive``, ``Q.nonzero``,
150
+ ``Q.integer``, ``Q.rational``, and ``Q.irrational`` all imply
151
+ ``Q.real``, as do all facts that imply those facts.
152
+
153
+ - The facts ``Q.algebraic``, and ``Q.transcendental`` do not imply
154
+ ``Q.real``; they imply ``Q.complex``. An algebraic or
155
+ transcendental number may or may not be real.
156
+
157
+ - The "non" facts (i.e., ``Q.nonnegative``, ``Q.nonzero``,
158
+ ``Q.nonpositive`` and ``Q.noninteger``) are not equivalent to
159
+ not the fact, but rather, not the fact *and* ``Q.real``.
160
+ For example, ``Q.nonnegative`` means ``~Q.negative & Q.real``.
161
+ So for example, ``I`` is not nonnegative, nonzero, or
162
+ nonpositive.
163
+
164
+ Examples
165
+ ========
166
+
167
+ >>> from sympy import Q, ask, symbols
168
+ >>> x = symbols('x')
169
+ >>> ask(Q.real(x), Q.positive(x))
170
+ True
171
+ >>> ask(Q.real(0))
172
+ True
173
+
174
+ References
175
+ ==========
176
+
177
+ .. [1] https://en.wikipedia.org/wiki/Real_number
178
+
179
+ """
180
+ name = 'real'
181
+ handler = Dispatcher(
182
+ "RealHandler",
183
+ doc=("Handler for Q.real.\n\n"
184
+ "Test that an expression belongs to the field of real numbers.")
185
+ )
186
+
187
+
188
+ class ExtendedRealPredicate(Predicate):
189
+ r"""
190
+ Extended real predicate.
191
+
192
+ Explanation
193
+ ===========
194
+
195
+ ``Q.extended_real(x)`` is true iff ``x`` is a real number or
196
+ `\{-\infty, \infty\}`.
197
+
198
+ See documentation of ``Q.real`` for more information about related
199
+ facts.
200
+
201
+ Examples
202
+ ========
203
+
204
+ >>> from sympy import ask, Q, oo, I
205
+ >>> ask(Q.extended_real(1))
206
+ True
207
+ >>> ask(Q.extended_real(I))
208
+ False
209
+ >>> ask(Q.extended_real(oo))
210
+ True
211
+
212
+ """
213
+ name = 'extended_real'
214
+ handler = Dispatcher(
215
+ "ExtendedRealHandler",
216
+ doc=("Handler for Q.extended_real.\n\n"
217
+ "Test that an expression belongs to the field of extended real\n"
218
+ "numbers, that is real numbers union {Infinity, -Infinity}.")
219
+ )
220
+
221
+
222
+ class HermitianPredicate(Predicate):
223
+ """
224
+ Hermitian predicate.
225
+
226
+ Explanation
227
+ ===========
228
+
229
+ ``ask(Q.hermitian(x))`` is true iff ``x`` belongs to the set of
230
+ Hermitian operators.
231
+
232
+ References
233
+ ==========
234
+
235
+ .. [1] https://mathworld.wolfram.com/HermitianOperator.html
236
+
237
+ """
238
+ # TODO: Add examples
239
+ name = 'hermitian'
240
+ handler = Dispatcher(
241
+ "HermitianHandler",
242
+ doc=("Handler for Q.hermitian.\n\n"
243
+ "Test that an expression belongs to the field of Hermitian operators.")
244
+ )
245
+
246
+
247
+ class ComplexPredicate(Predicate):
248
+ """
249
+ Complex number predicate.
250
+
251
+ Explanation
252
+ ===========
253
+
254
+ ``Q.complex(x)`` is true iff ``x`` belongs to the set of complex
255
+ numbers. Note that every complex number is finite.
256
+
257
+ Examples
258
+ ========
259
+
260
+ >>> from sympy import Q, Symbol, ask, I, oo
261
+ >>> x = Symbol('x')
262
+ >>> ask(Q.complex(0))
263
+ True
264
+ >>> ask(Q.complex(2 + 3*I))
265
+ True
266
+ >>> ask(Q.complex(oo))
267
+ False
268
+
269
+ References
270
+ ==========
271
+
272
+ .. [1] https://en.wikipedia.org/wiki/Complex_number
273
+
274
+ """
275
+ name = 'complex'
276
+ handler = Dispatcher(
277
+ "ComplexHandler",
278
+ doc=("Handler for Q.complex.\n\n"
279
+ "Test that an expression belongs to the field of complex numbers.")
280
+ )
281
+
282
+
283
+ class ImaginaryPredicate(Predicate):
284
+ """
285
+ Imaginary number predicate.
286
+
287
+ Explanation
288
+ ===========
289
+
290
+ ``Q.imaginary(x)`` is true iff ``x`` can be written as a real
291
+ number multiplied by the imaginary unit ``I``. Please note that ``0``
292
+ is not considered to be an imaginary number.
293
+
294
+ Examples
295
+ ========
296
+
297
+ >>> from sympy import Q, ask, I
298
+ >>> ask(Q.imaginary(3*I))
299
+ True
300
+ >>> ask(Q.imaginary(2 + 3*I))
301
+ False
302
+ >>> ask(Q.imaginary(0))
303
+ False
304
+
305
+ References
306
+ ==========
307
+
308
+ .. [1] https://en.wikipedia.org/wiki/Imaginary_number
309
+
310
+ """
311
+ name = 'imaginary'
312
+ handler = Dispatcher(
313
+ "ImaginaryHandler",
314
+ doc=("Handler for Q.imaginary.\n\n"
315
+ "Test that an expression belongs to the field of imaginary numbers,\n"
316
+ "that is, numbers in the form x*I, where x is real.")
317
+ )
318
+
319
+
320
+ class AntihermitianPredicate(Predicate):
321
+ """
322
+ Antihermitian predicate.
323
+
324
+ Explanation
325
+ ===========
326
+
327
+ ``Q.antihermitian(x)`` is true iff ``x`` belongs to the field of
328
+ antihermitian operators, i.e., operators in the form ``x*I``, where
329
+ ``x`` is Hermitian.
330
+
331
+ References
332
+ ==========
333
+
334
+ .. [1] https://mathworld.wolfram.com/HermitianOperator.html
335
+
336
+ """
337
+ # TODO: Add examples
338
+ name = 'antihermitian'
339
+ handler = Dispatcher(
340
+ "AntiHermitianHandler",
341
+ doc=("Handler for Q.antihermitian.\n\n"
342
+ "Test that an expression belongs to the field of anti-Hermitian\n"
343
+ "operators, that is, operators in the form x*I, where x is Hermitian.")
344
+ )
345
+
346
+
347
+ class AlgebraicPredicate(Predicate):
348
+ r"""
349
+ Algebraic number predicate.
350
+
351
+ Explanation
352
+ ===========
353
+
354
+ ``Q.algebraic(x)`` is true iff ``x`` belongs to the set of
355
+ algebraic numbers. ``x`` is algebraic if there is some polynomial
356
+ in ``p(x)\in \mathbb\{Q\}[x]`` such that ``p(x) = 0``.
357
+
358
+ Examples
359
+ ========
360
+
361
+ >>> from sympy import ask, Q, sqrt, I, pi
362
+ >>> ask(Q.algebraic(sqrt(2)))
363
+ True
364
+ >>> ask(Q.algebraic(I))
365
+ True
366
+ >>> ask(Q.algebraic(pi))
367
+ False
368
+
369
+ References
370
+ ==========
371
+
372
+ .. [1] https://en.wikipedia.org/wiki/Algebraic_number
373
+
374
+ """
375
+ name = 'algebraic'
376
+ AlgebraicHandler = Dispatcher(
377
+ "AlgebraicHandler",
378
+ doc="""Handler for Q.algebraic key."""
379
+ )
380
+
381
+
382
+ class TranscendentalPredicate(Predicate):
383
+ """
384
+ Transcedental number predicate.
385
+
386
+ Explanation
387
+ ===========
388
+
389
+ ``Q.transcendental(x)`` is true iff ``x`` belongs to the set of
390
+ transcendental numbers. A transcendental number is a real
391
+ or complex number that is not algebraic.
392
+
393
+ """
394
+ # TODO: Add examples
395
+ name = 'transcendental'
396
+ handler = Dispatcher(
397
+ "Transcendental",
398
+ doc="""Handler for Q.transcendental key."""
399
+ )
.venv/lib/python3.13/site-packages/sympy/assumptions/relation/__init__.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ A module to implement finitary relations [1] as predicate.
3
+
4
+ References
5
+ ==========
6
+
7
+ .. [1] https://en.wikipedia.org/wiki/Finitary_relation
8
+
9
+ """
10
+
11
+ __all__ = ['BinaryRelation', 'AppliedBinaryRelation']
12
+
13
+ from .binrel import BinaryRelation, AppliedBinaryRelation
.venv/lib/python3.13/site-packages/sympy/assumptions/relation/binrel.py ADDED
@@ -0,0 +1,212 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ General binary relations.
3
+ """
4
+ from typing import Optional
5
+
6
+ from sympy.core.singleton import S
7
+ from sympy.assumptions import AppliedPredicate, ask, Predicate, Q # type: ignore
8
+ from sympy.core.kind import BooleanKind
9
+ from sympy.core.relational import Eq, Ne, Gt, Lt, Ge, Le
10
+ from sympy.logic.boolalg import conjuncts, Not
11
+
12
+ __all__ = ["BinaryRelation", "AppliedBinaryRelation"]
13
+
14
+
15
+ class BinaryRelation(Predicate):
16
+ """
17
+ Base class for all binary relational predicates.
18
+
19
+ Explanation
20
+ ===========
21
+
22
+ Binary relation takes two arguments and returns ``AppliedBinaryRelation``
23
+ instance. To evaluate it to boolean value, use :obj:`~.ask()` or
24
+ :obj:`~.refine()` function.
25
+
26
+ You can add support for new types by registering the handler to dispatcher.
27
+ See :obj:`~.Predicate()` for more information about predicate dispatching.
28
+
29
+ Examples
30
+ ========
31
+
32
+ Applying and evaluating to boolean value:
33
+
34
+ >>> from sympy import Q, ask, sin, cos
35
+ >>> from sympy.abc import x
36
+ >>> Q.eq(sin(x)**2+cos(x)**2, 1)
37
+ Q.eq(sin(x)**2 + cos(x)**2, 1)
38
+ >>> ask(_)
39
+ True
40
+
41
+ You can define a new binary relation by subclassing and dispatching.
42
+ Here, we define a relation $R$ such that $x R y$ returns true if
43
+ $x = y + 1$.
44
+
45
+ >>> from sympy import ask, Number, Q
46
+ >>> from sympy.assumptions import BinaryRelation
47
+ >>> class MyRel(BinaryRelation):
48
+ ... name = "R"
49
+ ... is_reflexive = False
50
+ >>> Q.R = MyRel()
51
+ >>> @Q.R.register(Number, Number)
52
+ ... def _(n1, n2, assumptions):
53
+ ... return ask(Q.zero(n1 - n2 - 1), assumptions)
54
+ >>> Q.R(2, 1)
55
+ Q.R(2, 1)
56
+
57
+ Now, we can use ``ask()`` to evaluate it to boolean value.
58
+
59
+ >>> ask(Q.R(2, 1))
60
+ True
61
+ >>> ask(Q.R(1, 2))
62
+ False
63
+
64
+ ``Q.R`` returns ``False`` with minimum cost if two arguments have same
65
+ structure because it is antireflexive relation [1] by
66
+ ``is_reflexive = False``.
67
+
68
+ >>> ask(Q.R(x, x))
69
+ False
70
+
71
+ References
72
+ ==========
73
+
74
+ .. [1] https://en.wikipedia.org/wiki/Reflexive_relation
75
+ """
76
+
77
+ is_reflexive: Optional[bool] = None
78
+ is_symmetric: Optional[bool] = None
79
+
80
+ def __call__(self, *args):
81
+ if not len(args) == 2:
82
+ raise ValueError("Binary relation takes two arguments, but got %s." % len(args))
83
+ return AppliedBinaryRelation(self, *args)
84
+
85
+ @property
86
+ def reversed(self):
87
+ if self.is_symmetric:
88
+ return self
89
+ return None
90
+
91
+ @property
92
+ def negated(self):
93
+ return None
94
+
95
+ def _compare_reflexive(self, lhs, rhs):
96
+ # quick exit for structurally same arguments
97
+ # do not check != here because it cannot catch the
98
+ # equivalent arguments with different structures.
99
+
100
+ # reflexivity does not hold to NaN
101
+ if lhs is S.NaN or rhs is S.NaN:
102
+ return None
103
+
104
+ reflexive = self.is_reflexive
105
+ if reflexive is None:
106
+ pass
107
+ elif reflexive and (lhs == rhs):
108
+ return True
109
+ elif not reflexive and (lhs == rhs):
110
+ return False
111
+ return None
112
+
113
+ def eval(self, args, assumptions=True):
114
+ # quick exit for structurally same arguments
115
+ ret = self._compare_reflexive(*args)
116
+ if ret is not None:
117
+ return ret
118
+
119
+ # don't perform simplify on args here. (done by AppliedBinaryRelation._eval_ask)
120
+ # evaluate by multipledispatch
121
+ lhs, rhs = args
122
+ ret = self.handler(lhs, rhs, assumptions=assumptions)
123
+ if ret is not None:
124
+ return ret
125
+
126
+ # check reversed order if the relation is reflexive
127
+ if self.is_reflexive:
128
+ types = (type(lhs), type(rhs))
129
+ if self.handler.dispatch(*types) is not self.handler.dispatch(*reversed(types)):
130
+ ret = self.handler(rhs, lhs, assumptions=assumptions)
131
+
132
+ return ret
133
+
134
+
135
+ class AppliedBinaryRelation(AppliedPredicate):
136
+ """
137
+ The class of expressions resulting from applying ``BinaryRelation``
138
+ to the arguments.
139
+
140
+ """
141
+
142
+ @property
143
+ def lhs(self):
144
+ """The left-hand side of the relation."""
145
+ return self.arguments[0]
146
+
147
+ @property
148
+ def rhs(self):
149
+ """The right-hand side of the relation."""
150
+ return self.arguments[1]
151
+
152
+ @property
153
+ def reversed(self):
154
+ """
155
+ Try to return the relationship with sides reversed.
156
+ """
157
+ revfunc = self.function.reversed
158
+ if revfunc is None:
159
+ return self
160
+ return revfunc(self.rhs, self.lhs)
161
+
162
+ @property
163
+ def reversedsign(self):
164
+ """
165
+ Try to return the relationship with signs reversed.
166
+ """
167
+ revfunc = self.function.reversed
168
+ if revfunc is None:
169
+ return self
170
+ if not any(side.kind is BooleanKind for side in self.arguments):
171
+ return revfunc(-self.lhs, -self.rhs)
172
+ return self
173
+
174
+ @property
175
+ def negated(self):
176
+ neg_rel = self.function.negated
177
+ if neg_rel is None:
178
+ return Not(self, evaluate=False)
179
+ return neg_rel(*self.arguments)
180
+
181
+ def _eval_ask(self, assumptions):
182
+ conj_assumps = set()
183
+ binrelpreds = {Eq: Q.eq, Ne: Q.ne, Gt: Q.gt, Lt: Q.lt, Ge: Q.ge, Le: Q.le}
184
+ for a in conjuncts(assumptions):
185
+ if a.func in binrelpreds:
186
+ conj_assumps.add(binrelpreds[type(a)](*a.args))
187
+ else:
188
+ conj_assumps.add(a)
189
+
190
+ # After CNF in assumptions module is modified to take polyadic
191
+ # predicate, this will be removed
192
+ if any(rel in conj_assumps for rel in (self, self.reversed)):
193
+ return True
194
+ neg_rels = (self.negated, self.reversed.negated, Not(self, evaluate=False),
195
+ Not(self.reversed, evaluate=False))
196
+ if any(rel in conj_assumps for rel in neg_rels):
197
+ return False
198
+
199
+ # evaluation using multipledispatching
200
+ ret = self.function.eval(self.arguments, assumptions)
201
+ if ret is not None:
202
+ return ret
203
+
204
+ # simplify the args and try again
205
+ args = tuple(a.simplify() for a in self.arguments)
206
+ return self.function.eval(args, assumptions)
207
+
208
+ def __bool__(self):
209
+ ret = ask(self)
210
+ if ret is None:
211
+ raise TypeError("Cannot determine truth value of %s" % self)
212
+ return ret
.venv/lib/python3.13/site-packages/sympy/assumptions/relation/equality.py ADDED
@@ -0,0 +1,302 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Module for mathematical equality [1] and inequalities [2].
3
+
4
+ The purpose of this module is to provide the instances which represent the
5
+ binary predicates in order to combine the relationals into logical inference
6
+ system. Objects such as ``Q.eq``, ``Q.lt`` should remain internal to
7
+ assumptions module, and user must use the classes such as :obj:`~.Eq()`,
8
+ :obj:`~.Lt()` instead to construct the relational expressions.
9
+
10
+ References
11
+ ==========
12
+
13
+ .. [1] https://en.wikipedia.org/wiki/Equality_(mathematics)
14
+ .. [2] https://en.wikipedia.org/wiki/Inequality_(mathematics)
15
+ """
16
+ from sympy.assumptions import Q
17
+ from sympy.core.relational import is_eq, is_neq, is_gt, is_ge, is_lt, is_le
18
+
19
+ from .binrel import BinaryRelation
20
+
21
+ __all__ = ['EqualityPredicate', 'UnequalityPredicate', 'StrictGreaterThanPredicate',
22
+ 'GreaterThanPredicate', 'StrictLessThanPredicate', 'LessThanPredicate']
23
+
24
+
25
+ class EqualityPredicate(BinaryRelation):
26
+ """
27
+ Binary predicate for $=$.
28
+
29
+ The purpose of this class is to provide the instance which represent
30
+ the equality predicate in order to allow the logical inference.
31
+ This class must remain internal to assumptions module and user must
32
+ use :obj:`~.Eq()` instead to construct the equality expression.
33
+
34
+ Evaluating this predicate to ``True`` or ``False`` is done by
35
+ :func:`~.core.relational.is_eq`
36
+
37
+ Examples
38
+ ========
39
+
40
+ >>> from sympy import ask, Q
41
+ >>> Q.eq(0, 0)
42
+ Q.eq(0, 0)
43
+ >>> ask(_)
44
+ True
45
+
46
+ See Also
47
+ ========
48
+
49
+ sympy.core.relational.Eq
50
+
51
+ """
52
+ is_reflexive = True
53
+ is_symmetric = True
54
+
55
+ name = 'eq'
56
+ handler = None # Do not allow dispatching by this predicate
57
+
58
+ @property
59
+ def negated(self):
60
+ return Q.ne
61
+
62
+ def eval(self, args, assumptions=True):
63
+ if assumptions == True:
64
+ # default assumptions for is_eq is None
65
+ assumptions = None
66
+ return is_eq(*args, assumptions)
67
+
68
+
69
+ class UnequalityPredicate(BinaryRelation):
70
+ r"""
71
+ Binary predicate for $\neq$.
72
+
73
+ The purpose of this class is to provide the instance which represent
74
+ the inequation predicate in order to allow the logical inference.
75
+ This class must remain internal to assumptions module and user must
76
+ use :obj:`~.Ne()` instead to construct the inequation expression.
77
+
78
+ Evaluating this predicate to ``True`` or ``False`` is done by
79
+ :func:`~.core.relational.is_neq`
80
+
81
+ Examples
82
+ ========
83
+
84
+ >>> from sympy import ask, Q
85
+ >>> Q.ne(0, 0)
86
+ Q.ne(0, 0)
87
+ >>> ask(_)
88
+ False
89
+
90
+ See Also
91
+ ========
92
+
93
+ sympy.core.relational.Ne
94
+
95
+ """
96
+ is_reflexive = False
97
+ is_symmetric = True
98
+
99
+ name = 'ne'
100
+ handler = None
101
+
102
+ @property
103
+ def negated(self):
104
+ return Q.eq
105
+
106
+ def eval(self, args, assumptions=True):
107
+ if assumptions == True:
108
+ # default assumptions for is_neq is None
109
+ assumptions = None
110
+ return is_neq(*args, assumptions)
111
+
112
+
113
+ class StrictGreaterThanPredicate(BinaryRelation):
114
+ """
115
+ Binary predicate for $>$.
116
+
117
+ The purpose of this class is to provide the instance which represent
118
+ the ">" predicate in order to allow the logical inference.
119
+ This class must remain internal to assumptions module and user must
120
+ use :obj:`~.Gt()` instead to construct the equality expression.
121
+
122
+ Evaluating this predicate to ``True`` or ``False`` is done by
123
+ :func:`~.core.relational.is_gt`
124
+
125
+ Examples
126
+ ========
127
+
128
+ >>> from sympy import ask, Q
129
+ >>> Q.gt(0, 0)
130
+ Q.gt(0, 0)
131
+ >>> ask(_)
132
+ False
133
+
134
+ See Also
135
+ ========
136
+
137
+ sympy.core.relational.Gt
138
+
139
+ """
140
+ is_reflexive = False
141
+ is_symmetric = False
142
+
143
+ name = 'gt'
144
+ handler = None
145
+
146
+ @property
147
+ def reversed(self):
148
+ return Q.lt
149
+
150
+ @property
151
+ def negated(self):
152
+ return Q.le
153
+
154
+ def eval(self, args, assumptions=True):
155
+ if assumptions == True:
156
+ # default assumptions for is_gt is None
157
+ assumptions = None
158
+ return is_gt(*args, assumptions)
159
+
160
+
161
+ class GreaterThanPredicate(BinaryRelation):
162
+ """
163
+ Binary predicate for $>=$.
164
+
165
+ The purpose of this class is to provide the instance which represent
166
+ the ">=" predicate in order to allow the logical inference.
167
+ This class must remain internal to assumptions module and user must
168
+ use :obj:`~.Ge()` instead to construct the equality expression.
169
+
170
+ Evaluating this predicate to ``True`` or ``False`` is done by
171
+ :func:`~.core.relational.is_ge`
172
+
173
+ Examples
174
+ ========
175
+
176
+ >>> from sympy import ask, Q
177
+ >>> Q.ge(0, 0)
178
+ Q.ge(0, 0)
179
+ >>> ask(_)
180
+ True
181
+
182
+ See Also
183
+ ========
184
+
185
+ sympy.core.relational.Ge
186
+
187
+ """
188
+ is_reflexive = True
189
+ is_symmetric = False
190
+
191
+ name = 'ge'
192
+ handler = None
193
+
194
+ @property
195
+ def reversed(self):
196
+ return Q.le
197
+
198
+ @property
199
+ def negated(self):
200
+ return Q.lt
201
+
202
+ def eval(self, args, assumptions=True):
203
+ if assumptions == True:
204
+ # default assumptions for is_ge is None
205
+ assumptions = None
206
+ return is_ge(*args, assumptions)
207
+
208
+
209
+ class StrictLessThanPredicate(BinaryRelation):
210
+ """
211
+ Binary predicate for $<$.
212
+
213
+ The purpose of this class is to provide the instance which represent
214
+ the "<" predicate in order to allow the logical inference.
215
+ This class must remain internal to assumptions module and user must
216
+ use :obj:`~.Lt()` instead to construct the equality expression.
217
+
218
+ Evaluating this predicate to ``True`` or ``False`` is done by
219
+ :func:`~.core.relational.is_lt`
220
+
221
+ Examples
222
+ ========
223
+
224
+ >>> from sympy import ask, Q
225
+ >>> Q.lt(0, 0)
226
+ Q.lt(0, 0)
227
+ >>> ask(_)
228
+ False
229
+
230
+ See Also
231
+ ========
232
+
233
+ sympy.core.relational.Lt
234
+
235
+ """
236
+ is_reflexive = False
237
+ is_symmetric = False
238
+
239
+ name = 'lt'
240
+ handler = None
241
+
242
+ @property
243
+ def reversed(self):
244
+ return Q.gt
245
+
246
+ @property
247
+ def negated(self):
248
+ return Q.ge
249
+
250
+ def eval(self, args, assumptions=True):
251
+ if assumptions == True:
252
+ # default assumptions for is_lt is None
253
+ assumptions = None
254
+ return is_lt(*args, assumptions)
255
+
256
+
257
+ class LessThanPredicate(BinaryRelation):
258
+ """
259
+ Binary predicate for $<=$.
260
+
261
+ The purpose of this class is to provide the instance which represent
262
+ the "<=" predicate in order to allow the logical inference.
263
+ This class must remain internal to assumptions module and user must
264
+ use :obj:`~.Le()` instead to construct the equality expression.
265
+
266
+ Evaluating this predicate to ``True`` or ``False`` is done by
267
+ :func:`~.core.relational.is_le`
268
+
269
+ Examples
270
+ ========
271
+
272
+ >>> from sympy import ask, Q
273
+ >>> Q.le(0, 0)
274
+ Q.le(0, 0)
275
+ >>> ask(_)
276
+ True
277
+
278
+ See Also
279
+ ========
280
+
281
+ sympy.core.relational.Le
282
+
283
+ """
284
+ is_reflexive = True
285
+ is_symmetric = False
286
+
287
+ name = 'le'
288
+ handler = None
289
+
290
+ @property
291
+ def reversed(self):
292
+ return Q.ge
293
+
294
+ @property
295
+ def negated(self):
296
+ return Q.gt
297
+
298
+ def eval(self, args, assumptions=True):
299
+ if assumptions == True:
300
+ # default assumptions for is_le is None
301
+ assumptions = None
302
+ return is_le(*args, assumptions)
.venv/lib/python3.13/site-packages/sympy/assumptions/tests/__init__.py ADDED
File without changes
.venv/lib/python3.13/site-packages/sympy/assumptions/tests/test_assumptions_2.py ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ rename this to test_assumptions.py when the old assumptions system is deleted
3
+ """
4
+ from sympy.abc import x, y
5
+ from sympy.assumptions.assume import global_assumptions
6
+ from sympy.assumptions.ask import Q
7
+ from sympy.printing import pretty
8
+
9
+
10
+ def test_equal():
11
+ """Test for equality"""
12
+ assert Q.positive(x) == Q.positive(x)
13
+ assert Q.positive(x) != ~Q.positive(x)
14
+ assert ~Q.positive(x) == ~Q.positive(x)
15
+
16
+
17
+ def test_pretty():
18
+ assert pretty(Q.positive(x)) == "Q.positive(x)"
19
+ assert pretty(
20
+ {Q.positive, Q.integer}) == "{Q.integer, Q.positive}"
21
+
22
+
23
+ def test_global():
24
+ """Test for global assumptions"""
25
+ global_assumptions.add(x > 0)
26
+ assert (x > 0) in global_assumptions
27
+ global_assumptions.remove(x > 0)
28
+ assert not (x > 0) in global_assumptions
29
+ # same with multiple of assumptions
30
+ global_assumptions.add(x > 0, y > 0)
31
+ assert (x > 0) in global_assumptions
32
+ assert (y > 0) in global_assumptions
33
+ global_assumptions.clear()
34
+ assert not (x > 0) in global_assumptions
35
+ assert not (y > 0) in global_assumptions
.venv/lib/python3.13/site-packages/sympy/assumptions/tests/test_context.py ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.assumptions import ask, Q
2
+ from sympy.assumptions.assume import assuming, global_assumptions
3
+ from sympy.abc import x, y
4
+
5
+ def test_assuming():
6
+ with assuming(Q.integer(x)):
7
+ assert ask(Q.integer(x))
8
+ assert not ask(Q.integer(x))
9
+
10
+ def test_assuming_nested():
11
+ assert not ask(Q.integer(x))
12
+ assert not ask(Q.integer(y))
13
+ with assuming(Q.integer(x)):
14
+ assert ask(Q.integer(x))
15
+ assert not ask(Q.integer(y))
16
+ with assuming(Q.integer(y)):
17
+ assert ask(Q.integer(x))
18
+ assert ask(Q.integer(y))
19
+ assert ask(Q.integer(x))
20
+ assert not ask(Q.integer(y))
21
+ assert not ask(Q.integer(x))
22
+ assert not ask(Q.integer(y))
23
+
24
+ def test_finally():
25
+ try:
26
+ with assuming(Q.integer(x)):
27
+ 1/0
28
+ except ZeroDivisionError:
29
+ pass
30
+ assert not ask(Q.integer(x))
31
+
32
+ def test_remove_safe():
33
+ global_assumptions.add(Q.integer(x))
34
+ with assuming():
35
+ assert ask(Q.integer(x))
36
+ global_assumptions.remove(Q.integer(x))
37
+ assert not ask(Q.integer(x))
38
+ assert ask(Q.integer(x))
39
+ global_assumptions.clear() # for the benefit of other tests
.venv/lib/python3.13/site-packages/sympy/assumptions/tests/test_matrices.py ADDED
@@ -0,0 +1,283 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.assumptions.ask import (Q, ask)
2
+ from sympy.core.symbol import Symbol
3
+ from sympy.matrices.expressions.diagonal import (DiagMatrix, DiagonalMatrix)
4
+ from sympy.matrices.dense import Matrix
5
+ from sympy.matrices.expressions import (MatrixSymbol, Identity, ZeroMatrix,
6
+ OneMatrix, Trace, MatrixSlice, Determinant, BlockMatrix, BlockDiagMatrix)
7
+ from sympy.matrices.expressions.factorizations import LofLU
8
+ from sympy.testing.pytest import XFAIL
9
+
10
+ X = MatrixSymbol('X', 2, 2)
11
+ Y = MatrixSymbol('Y', 2, 3)
12
+ Z = MatrixSymbol('Z', 2, 2)
13
+ A1x1 = MatrixSymbol('A1x1', 1, 1)
14
+ B1x1 = MatrixSymbol('B1x1', 1, 1)
15
+ C0x0 = MatrixSymbol('C0x0', 0, 0)
16
+ V1 = MatrixSymbol('V1', 2, 1)
17
+ V2 = MatrixSymbol('V2', 2, 1)
18
+
19
+ def test_square():
20
+ assert ask(Q.square(X))
21
+ assert not ask(Q.square(Y))
22
+ assert ask(Q.square(Y*Y.T))
23
+
24
+ def test_invertible():
25
+ assert ask(Q.invertible(X), Q.invertible(X))
26
+ assert ask(Q.invertible(Y)) is False
27
+ assert ask(Q.invertible(X*Y), Q.invertible(X)) is False
28
+ assert ask(Q.invertible(X*Z), Q.invertible(X)) is None
29
+ assert ask(Q.invertible(X*Z), Q.invertible(X) & Q.invertible(Z)) is True
30
+ assert ask(Q.invertible(X.T)) is None
31
+ assert ask(Q.invertible(X.T), Q.invertible(X)) is True
32
+ assert ask(Q.invertible(X.I)) is True
33
+ assert ask(Q.invertible(Identity(3))) is True
34
+ assert ask(Q.invertible(ZeroMatrix(3, 3))) is False
35
+ assert ask(Q.invertible(OneMatrix(1, 1))) is True
36
+ assert ask(Q.invertible(OneMatrix(3, 3))) is False
37
+ assert ask(Q.invertible(X), Q.fullrank(X) & Q.square(X))
38
+
39
+ def test_singular():
40
+ assert ask(Q.singular(X)) is None
41
+ assert ask(Q.singular(X), Q.invertible(X)) is False
42
+ assert ask(Q.singular(X), ~Q.invertible(X)) is True
43
+
44
+ @XFAIL
45
+ def test_invertible_fullrank():
46
+ assert ask(Q.invertible(X), Q.fullrank(X)) is True
47
+
48
+
49
+ def test_invertible_BlockMatrix():
50
+ assert ask(Q.invertible(BlockMatrix([Identity(3)]))) == True
51
+ assert ask(Q.invertible(BlockMatrix([ZeroMatrix(3, 3)]))) == False
52
+
53
+ X = Matrix([[1, 2, 3], [3, 5, 4]])
54
+ Y = Matrix([[4, 2, 7], [2, 3, 5]])
55
+ # non-invertible A block
56
+ assert ask(Q.invertible(BlockMatrix([
57
+ [Matrix.ones(3, 3), Y.T],
58
+ [X, Matrix.eye(2)],
59
+ ]))) == True
60
+ # non-invertible B block
61
+ assert ask(Q.invertible(BlockMatrix([
62
+ [Y.T, Matrix.ones(3, 3)],
63
+ [Matrix.eye(2), X],
64
+ ]))) == True
65
+ # non-invertible C block
66
+ assert ask(Q.invertible(BlockMatrix([
67
+ [X, Matrix.eye(2)],
68
+ [Matrix.ones(3, 3), Y.T],
69
+ ]))) == True
70
+ # non-invertible D block
71
+ assert ask(Q.invertible(BlockMatrix([
72
+ [Matrix.eye(2), X],
73
+ [Y.T, Matrix.ones(3, 3)],
74
+ ]))) == True
75
+
76
+
77
+ def test_invertible_BlockDiagMatrix():
78
+ assert ask(Q.invertible(BlockDiagMatrix(Identity(3), Identity(5)))) == True
79
+ assert ask(Q.invertible(BlockDiagMatrix(ZeroMatrix(3, 3), Identity(5)))) == False
80
+ assert ask(Q.invertible(BlockDiagMatrix(Identity(3), OneMatrix(5, 5)))) == False
81
+
82
+
83
+ def test_symmetric():
84
+ assert ask(Q.symmetric(X), Q.symmetric(X))
85
+ assert ask(Q.symmetric(X*Z), Q.symmetric(X)) is None
86
+ assert ask(Q.symmetric(X*Z), Q.symmetric(X) & Q.symmetric(Z)) is True
87
+ assert ask(Q.symmetric(X + Z), Q.symmetric(X) & Q.symmetric(Z)) is True
88
+ assert ask(Q.symmetric(Y)) is False
89
+ assert ask(Q.symmetric(Y*Y.T)) is True
90
+ assert ask(Q.symmetric(Y.T*X*Y)) is None
91
+ assert ask(Q.symmetric(Y.T*X*Y), Q.symmetric(X)) is True
92
+ assert ask(Q.symmetric(X**10), Q.symmetric(X)) is True
93
+ assert ask(Q.symmetric(A1x1)) is True
94
+ assert ask(Q.symmetric(A1x1 + B1x1)) is True
95
+ assert ask(Q.symmetric(A1x1 * B1x1)) is True
96
+ assert ask(Q.symmetric(V1.T*V1)) is True
97
+ assert ask(Q.symmetric(V1.T*(V1 + V2))) is True
98
+ assert ask(Q.symmetric(V1.T*(V1 + V2) + A1x1)) is True
99
+ assert ask(Q.symmetric(MatrixSlice(Y, (0, 1), (1, 2)))) is True
100
+ assert ask(Q.symmetric(Identity(3))) is True
101
+ assert ask(Q.symmetric(ZeroMatrix(3, 3))) is True
102
+ assert ask(Q.symmetric(OneMatrix(3, 3))) is True
103
+
104
+ def _test_orthogonal_unitary(predicate):
105
+ assert ask(predicate(X), predicate(X))
106
+ assert ask(predicate(X.T), predicate(X)) is True
107
+ assert ask(predicate(X.I), predicate(X)) is True
108
+ assert ask(predicate(X**2), predicate(X))
109
+ assert ask(predicate(Y)) is False
110
+ assert ask(predicate(X)) is None
111
+ assert ask(predicate(X), ~Q.invertible(X)) is False
112
+ assert ask(predicate(X*Z*X), predicate(X) & predicate(Z)) is True
113
+ assert ask(predicate(Identity(3))) is True
114
+ assert ask(predicate(ZeroMatrix(3, 3))) is False
115
+ assert ask(Q.invertible(X), predicate(X))
116
+ assert not ask(predicate(X + Z), predicate(X) & predicate(Z))
117
+
118
+ def test_orthogonal():
119
+ _test_orthogonal_unitary(Q.orthogonal)
120
+
121
+ def test_unitary():
122
+ _test_orthogonal_unitary(Q.unitary)
123
+ assert ask(Q.unitary(X), Q.orthogonal(X))
124
+
125
+ def test_fullrank():
126
+ assert ask(Q.fullrank(X), Q.fullrank(X))
127
+ assert ask(Q.fullrank(X**2), Q.fullrank(X))
128
+ assert ask(Q.fullrank(X.T), Q.fullrank(X)) is True
129
+ assert ask(Q.fullrank(X)) is None
130
+ assert ask(Q.fullrank(Y)) is None
131
+ assert ask(Q.fullrank(X*Z), Q.fullrank(X) & Q.fullrank(Z)) is True
132
+ assert ask(Q.fullrank(Identity(3))) is True
133
+ assert ask(Q.fullrank(ZeroMatrix(3, 3))) is False
134
+ assert ask(Q.fullrank(OneMatrix(1, 1))) is True
135
+ assert ask(Q.fullrank(OneMatrix(3, 3))) is False
136
+ assert ask(Q.invertible(X), ~Q.fullrank(X)) == False
137
+
138
+
139
+ def test_positive_definite():
140
+ assert ask(Q.positive_definite(X), Q.positive_definite(X))
141
+ assert ask(Q.positive_definite(X.T), Q.positive_definite(X)) is True
142
+ assert ask(Q.positive_definite(X.I), Q.positive_definite(X)) is True
143
+ assert ask(Q.positive_definite(Y)) is False
144
+ assert ask(Q.positive_definite(X)) is None
145
+ assert ask(Q.positive_definite(X**3), Q.positive_definite(X))
146
+ assert ask(Q.positive_definite(X*Z*X),
147
+ Q.positive_definite(X) & Q.positive_definite(Z)) is True
148
+ assert ask(Q.positive_definite(X), Q.orthogonal(X))
149
+ assert ask(Q.positive_definite(Y.T*X*Y),
150
+ Q.positive_definite(X) & Q.fullrank(Y)) is True
151
+ assert not ask(Q.positive_definite(Y.T*X*Y), Q.positive_definite(X))
152
+ assert ask(Q.positive_definite(Identity(3))) is True
153
+ assert ask(Q.positive_definite(ZeroMatrix(3, 3))) is False
154
+ assert ask(Q.positive_definite(OneMatrix(1, 1))) is True
155
+ assert ask(Q.positive_definite(OneMatrix(3, 3))) is False
156
+ assert ask(Q.positive_definite(X + Z), Q.positive_definite(X) &
157
+ Q.positive_definite(Z)) is True
158
+ assert not ask(Q.positive_definite(-X), Q.positive_definite(X))
159
+ assert ask(Q.positive(X[1, 1]), Q.positive_definite(X))
160
+
161
+ def test_triangular():
162
+ assert ask(Q.upper_triangular(X + Z.T + Identity(2)), Q.upper_triangular(X) &
163
+ Q.lower_triangular(Z)) is True
164
+ assert ask(Q.upper_triangular(X*Z.T), Q.upper_triangular(X) &
165
+ Q.lower_triangular(Z)) is True
166
+ assert ask(Q.lower_triangular(Identity(3))) is True
167
+ assert ask(Q.lower_triangular(ZeroMatrix(3, 3))) is True
168
+ assert ask(Q.upper_triangular(ZeroMatrix(3, 3))) is True
169
+ assert ask(Q.lower_triangular(OneMatrix(1, 1))) is True
170
+ assert ask(Q.upper_triangular(OneMatrix(1, 1))) is True
171
+ assert ask(Q.lower_triangular(OneMatrix(3, 3))) is False
172
+ assert ask(Q.upper_triangular(OneMatrix(3, 3))) is False
173
+ assert ask(Q.triangular(X), Q.unit_triangular(X))
174
+ assert ask(Q.upper_triangular(X**3), Q.upper_triangular(X))
175
+ assert ask(Q.lower_triangular(X**3), Q.lower_triangular(X))
176
+
177
+
178
+ def test_diagonal():
179
+ assert ask(Q.diagonal(X + Z.T + Identity(2)), Q.diagonal(X) &
180
+ Q.diagonal(Z)) is True
181
+ assert ask(Q.diagonal(ZeroMatrix(3, 3)))
182
+ assert ask(Q.diagonal(OneMatrix(1, 1))) is True
183
+ assert ask(Q.diagonal(OneMatrix(3, 3))) is False
184
+ assert ask(Q.lower_triangular(X) & Q.upper_triangular(X), Q.diagonal(X))
185
+ assert ask(Q.diagonal(X), Q.lower_triangular(X) & Q.upper_triangular(X))
186
+ assert ask(Q.symmetric(X), Q.diagonal(X))
187
+ assert ask(Q.triangular(X), Q.diagonal(X))
188
+ assert ask(Q.diagonal(C0x0))
189
+ assert ask(Q.diagonal(A1x1))
190
+ assert ask(Q.diagonal(A1x1 + B1x1))
191
+ assert ask(Q.diagonal(A1x1*B1x1))
192
+ assert ask(Q.diagonal(V1.T*V2))
193
+ assert ask(Q.diagonal(V1.T*(X + Z)*V1))
194
+ assert ask(Q.diagonal(MatrixSlice(Y, (0, 1), (1, 2)))) is True
195
+ assert ask(Q.diagonal(V1.T*(V1 + V2))) is True
196
+ assert ask(Q.diagonal(X**3), Q.diagonal(X))
197
+ assert ask(Q.diagonal(Identity(3)))
198
+ assert ask(Q.diagonal(DiagMatrix(V1)))
199
+ assert ask(Q.diagonal(DiagonalMatrix(X)))
200
+
201
+
202
+ def test_non_atoms():
203
+ assert ask(Q.real(Trace(X)), Q.positive(Trace(X)))
204
+
205
+ @XFAIL
206
+ def test_non_trivial_implies():
207
+ X = MatrixSymbol('X', 3, 3)
208
+ Y = MatrixSymbol('Y', 3, 3)
209
+ assert ask(Q.lower_triangular(X+Y), Q.lower_triangular(X) &
210
+ Q.lower_triangular(Y)) is True
211
+ assert ask(Q.triangular(X), Q.lower_triangular(X)) is True
212
+ assert ask(Q.triangular(X+Y), Q.lower_triangular(X) &
213
+ Q.lower_triangular(Y)) is True
214
+
215
+ def test_MatrixSlice():
216
+ X = MatrixSymbol('X', 4, 4)
217
+ B = MatrixSlice(X, (1, 3), (1, 3))
218
+ C = MatrixSlice(X, (0, 3), (1, 3))
219
+ assert ask(Q.symmetric(B), Q.symmetric(X))
220
+ assert ask(Q.invertible(B), Q.invertible(X))
221
+ assert ask(Q.diagonal(B), Q.diagonal(X))
222
+ assert ask(Q.orthogonal(B), Q.orthogonal(X))
223
+ assert ask(Q.upper_triangular(B), Q.upper_triangular(X))
224
+
225
+ assert not ask(Q.symmetric(C), Q.symmetric(X))
226
+ assert not ask(Q.invertible(C), Q.invertible(X))
227
+ assert not ask(Q.diagonal(C), Q.diagonal(X))
228
+ assert not ask(Q.orthogonal(C), Q.orthogonal(X))
229
+ assert not ask(Q.upper_triangular(C), Q.upper_triangular(X))
230
+
231
+ def test_det_trace_positive():
232
+ X = MatrixSymbol('X', 4, 4)
233
+ assert ask(Q.positive(Trace(X)), Q.positive_definite(X))
234
+ assert ask(Q.positive(Determinant(X)), Q.positive_definite(X))
235
+
236
+ def test_field_assumptions():
237
+ X = MatrixSymbol('X', 4, 4)
238
+ Y = MatrixSymbol('Y', 4, 4)
239
+ assert ask(Q.real_elements(X), Q.real_elements(X))
240
+ assert not ask(Q.integer_elements(X), Q.real_elements(X))
241
+ assert ask(Q.complex_elements(X), Q.real_elements(X))
242
+ assert ask(Q.complex_elements(X**2), Q.real_elements(X))
243
+ assert ask(Q.real_elements(X**2), Q.integer_elements(X))
244
+ assert ask(Q.real_elements(X+Y), Q.real_elements(X)) is None
245
+ assert ask(Q.real_elements(X+Y), Q.real_elements(X) & Q.real_elements(Y))
246
+ from sympy.matrices.expressions.hadamard import HadamardProduct
247
+ assert ask(Q.real_elements(HadamardProduct(X, Y)),
248
+ Q.real_elements(X) & Q.real_elements(Y))
249
+ assert ask(Q.complex_elements(X+Y), Q.real_elements(X) & Q.complex_elements(Y))
250
+
251
+ assert ask(Q.real_elements(X.T), Q.real_elements(X))
252
+ assert ask(Q.real_elements(X.I), Q.real_elements(X) & Q.invertible(X))
253
+ assert ask(Q.real_elements(Trace(X)), Q.real_elements(X))
254
+ assert ask(Q.integer_elements(Determinant(X)), Q.integer_elements(X))
255
+ assert not ask(Q.integer_elements(X.I), Q.integer_elements(X))
256
+ alpha = Symbol('alpha')
257
+ assert ask(Q.real_elements(alpha*X), Q.real_elements(X) & Q.real(alpha))
258
+ assert ask(Q.real_elements(LofLU(X)), Q.real_elements(X))
259
+ e = Symbol('e', integer=True, negative=True)
260
+ assert ask(Q.real_elements(X**e), Q.real_elements(X) & Q.invertible(X))
261
+ assert ask(Q.real_elements(X**e), Q.real_elements(X)) is None
262
+
263
+ def test_matrix_element_sets():
264
+ X = MatrixSymbol('X', 4, 4)
265
+ assert ask(Q.real(X[1, 2]), Q.real_elements(X))
266
+ assert ask(Q.integer(X[1, 2]), Q.integer_elements(X))
267
+ assert ask(Q.complex(X[1, 2]), Q.complex_elements(X))
268
+ assert ask(Q.integer_elements(Identity(3)))
269
+ assert ask(Q.integer_elements(ZeroMatrix(3, 3)))
270
+ assert ask(Q.integer_elements(OneMatrix(3, 3)))
271
+ from sympy.matrices.expressions.fourier import DFT
272
+ assert ask(Q.complex_elements(DFT(3)))
273
+
274
+
275
+ def test_matrix_element_sets_slices_blocks():
276
+ X = MatrixSymbol('X', 4, 4)
277
+ assert ask(Q.integer_elements(X[:, 3]), Q.integer_elements(X))
278
+ assert ask(Q.integer_elements(BlockMatrix([[X], [X]])),
279
+ Q.integer_elements(X))
280
+
281
+ def test_matrix_element_sets_determinant_trace():
282
+ assert ask(Q.integer(Determinant(X)), Q.integer_elements(X))
283
+ assert ask(Q.integer(Trace(X)), Q.integer_elements(X))
.venv/lib/python3.13/site-packages/sympy/assumptions/tests/test_query.py ADDED
The diff for this file is too large to render. See raw diff
 
.venv/lib/python3.13/site-packages/sympy/assumptions/tests/test_refine.py ADDED
@@ -0,0 +1,227 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.assumptions.ask import Q
2
+ from sympy.assumptions.refine import refine
3
+ from sympy.core.expr import Expr
4
+ from sympy.core.numbers import (I, Rational, nan, pi)
5
+ from sympy.core.singleton import S
6
+ from sympy.core.symbol import Symbol
7
+ from sympy.functions.elementary.complexes import (Abs, arg, im, re, sign)
8
+ from sympy.functions.elementary.exponential import exp
9
+ from sympy.functions.elementary.miscellaneous import sqrt
10
+ from sympy.functions.elementary.trigonometric import (atan, atan2)
11
+ from sympy.abc import w, x, y, z
12
+ from sympy.core.relational import Eq, Ne
13
+ from sympy.functions.elementary.piecewise import Piecewise
14
+ from sympy.matrices.expressions.matexpr import MatrixSymbol
15
+
16
+
17
+ def test_Abs():
18
+ assert refine(Abs(x), Q.positive(x)) == x
19
+ assert refine(1 + Abs(x), Q.positive(x)) == 1 + x
20
+ assert refine(Abs(x), Q.negative(x)) == -x
21
+ assert refine(1 + Abs(x), Q.negative(x)) == 1 - x
22
+
23
+ assert refine(Abs(x**2)) != x**2
24
+ assert refine(Abs(x**2), Q.real(x)) == x**2
25
+
26
+
27
+ def test_pow1():
28
+ assert refine((-1)**x, Q.even(x)) == 1
29
+ assert refine((-1)**x, Q.odd(x)) == -1
30
+ assert refine((-2)**x, Q.even(x)) == 2**x
31
+
32
+ # nested powers
33
+ assert refine(sqrt(x**2)) != Abs(x)
34
+ assert refine(sqrt(x**2), Q.complex(x)) != Abs(x)
35
+ assert refine(sqrt(x**2), Q.real(x)) == Abs(x)
36
+ assert refine(sqrt(x**2), Q.positive(x)) == x
37
+ assert refine((x**3)**Rational(1, 3)) != x
38
+
39
+ assert refine((x**3)**Rational(1, 3), Q.real(x)) != x
40
+ assert refine((x**3)**Rational(1, 3), Q.positive(x)) == x
41
+
42
+ assert refine(sqrt(1/x), Q.real(x)) != 1/sqrt(x)
43
+ assert refine(sqrt(1/x), Q.positive(x)) == 1/sqrt(x)
44
+
45
+ # powers of (-1)
46
+ assert refine((-1)**(x + y), Q.even(x)) == (-1)**y
47
+ assert refine((-1)**(x + y + z), Q.odd(x) & Q.odd(z)) == (-1)**y
48
+ assert refine((-1)**(x + y + 1), Q.odd(x)) == (-1)**y
49
+ assert refine((-1)**(x + y + 2), Q.odd(x)) == (-1)**(y + 1)
50
+ assert refine((-1)**(x + 3)) == (-1)**(x + 1)
51
+
52
+ # continuation
53
+ assert refine((-1)**((-1)**x/2 - S.Half), Q.integer(x)) == (-1)**x
54
+ assert refine((-1)**((-1)**x/2 + S.Half), Q.integer(x)) == (-1)**(x + 1)
55
+ assert refine((-1)**((-1)**x/2 + 5*S.Half), Q.integer(x)) == (-1)**(x + 1)
56
+
57
+
58
+ def test_pow2():
59
+ assert refine((-1)**((-1)**x/2 - 7*S.Half), Q.integer(x)) == (-1)**(x + 1)
60
+ assert refine((-1)**((-1)**x/2 - 9*S.Half), Q.integer(x)) == (-1)**x
61
+
62
+ # powers of Abs
63
+ assert refine(Abs(x)**2, Q.real(x)) == x**2
64
+ assert refine(Abs(x)**3, Q.real(x)) == Abs(x)**3
65
+ assert refine(Abs(x)**2) == Abs(x)**2
66
+
67
+
68
+ def test_exp():
69
+ x = Symbol('x', integer=True)
70
+ assert refine(exp(pi*I*2*x)) == 1
71
+ assert refine(exp(pi*I*2*(x + S.Half))) == -1
72
+ assert refine(exp(pi*I*2*(x + Rational(1, 4)))) == I
73
+ assert refine(exp(pi*I*2*(x + Rational(3, 4)))) == -I
74
+
75
+
76
+ def test_Piecewise():
77
+ assert refine(Piecewise((1, x < 0), (3, True)), (x < 0)) == 1
78
+ assert refine(Piecewise((1, x < 0), (3, True)), ~(x < 0)) == 3
79
+ assert refine(Piecewise((1, x < 0), (3, True)), (y < 0)) == \
80
+ Piecewise((1, x < 0), (3, True))
81
+ assert refine(Piecewise((1, x > 0), (3, True)), (x > 0)) == 1
82
+ assert refine(Piecewise((1, x > 0), (3, True)), ~(x > 0)) == 3
83
+ assert refine(Piecewise((1, x > 0), (3, True)), (y > 0)) == \
84
+ Piecewise((1, x > 0), (3, True))
85
+ assert refine(Piecewise((1, x <= 0), (3, True)), (x <= 0)) == 1
86
+ assert refine(Piecewise((1, x <= 0), (3, True)), ~(x <= 0)) == 3
87
+ assert refine(Piecewise((1, x <= 0), (3, True)), (y <= 0)) == \
88
+ Piecewise((1, x <= 0), (3, True))
89
+ assert refine(Piecewise((1, x >= 0), (3, True)), (x >= 0)) == 1
90
+ assert refine(Piecewise((1, x >= 0), (3, True)), ~(x >= 0)) == 3
91
+ assert refine(Piecewise((1, x >= 0), (3, True)), (y >= 0)) == \
92
+ Piecewise((1, x >= 0), (3, True))
93
+ assert refine(Piecewise((1, Eq(x, 0)), (3, True)), (Eq(x, 0)))\
94
+ == 1
95
+ assert refine(Piecewise((1, Eq(x, 0)), (3, True)), (Eq(0, x)))\
96
+ == 1
97
+ assert refine(Piecewise((1, Eq(x, 0)), (3, True)), ~(Eq(x, 0)))\
98
+ == 3
99
+ assert refine(Piecewise((1, Eq(x, 0)), (3, True)), ~(Eq(0, x)))\
100
+ == 3
101
+ assert refine(Piecewise((1, Eq(x, 0)), (3, True)), (Eq(y, 0)))\
102
+ == Piecewise((1, Eq(x, 0)), (3, True))
103
+ assert refine(Piecewise((1, Ne(x, 0)), (3, True)), (Ne(x, 0)))\
104
+ == 1
105
+ assert refine(Piecewise((1, Ne(x, 0)), (3, True)), ~(Ne(x, 0)))\
106
+ == 3
107
+ assert refine(Piecewise((1, Ne(x, 0)), (3, True)), (Ne(y, 0)))\
108
+ == Piecewise((1, Ne(x, 0)), (3, True))
109
+
110
+
111
+ def test_atan2():
112
+ assert refine(atan2(y, x), Q.real(y) & Q.positive(x)) == atan(y/x)
113
+ assert refine(atan2(y, x), Q.negative(y) & Q.positive(x)) == atan(y/x)
114
+ assert refine(atan2(y, x), Q.negative(y) & Q.negative(x)) == atan(y/x) - pi
115
+ assert refine(atan2(y, x), Q.positive(y) & Q.negative(x)) == atan(y/x) + pi
116
+ assert refine(atan2(y, x), Q.zero(y) & Q.negative(x)) == pi
117
+ assert refine(atan2(y, x), Q.positive(y) & Q.zero(x)) == pi/2
118
+ assert refine(atan2(y, x), Q.negative(y) & Q.zero(x)) == -pi/2
119
+ assert refine(atan2(y, x), Q.zero(y) & Q.zero(x)) is nan
120
+
121
+
122
+ def test_re():
123
+ assert refine(re(x), Q.real(x)) == x
124
+ assert refine(re(x), Q.imaginary(x)) is S.Zero
125
+ assert refine(re(x+y), Q.real(x) & Q.real(y)) == x + y
126
+ assert refine(re(x+y), Q.real(x) & Q.imaginary(y)) == x
127
+ assert refine(re(x*y), Q.real(x) & Q.real(y)) == x * y
128
+ assert refine(re(x*y), Q.real(x) & Q.imaginary(y)) == 0
129
+ assert refine(re(x*y*z), Q.real(x) & Q.real(y) & Q.real(z)) == x * y * z
130
+
131
+
132
+ def test_im():
133
+ assert refine(im(x), Q.imaginary(x)) == -I*x
134
+ assert refine(im(x), Q.real(x)) is S.Zero
135
+ assert refine(im(x+y), Q.imaginary(x) & Q.imaginary(y)) == -I*x - I*y
136
+ assert refine(im(x+y), Q.real(x) & Q.imaginary(y)) == -I*y
137
+ assert refine(im(x*y), Q.imaginary(x) & Q.real(y)) == -I*x*y
138
+ assert refine(im(x*y), Q.imaginary(x) & Q.imaginary(y)) == 0
139
+ assert refine(im(1/x), Q.imaginary(x)) == -I/x
140
+ assert refine(im(x*y*z), Q.imaginary(x) & Q.imaginary(y)
141
+ & Q.imaginary(z)) == -I*x*y*z
142
+
143
+
144
+ def test_complex():
145
+ assert refine(re(1/(x + I*y)), Q.real(x) & Q.real(y)) == \
146
+ x/(x**2 + y**2)
147
+ assert refine(im(1/(x + I*y)), Q.real(x) & Q.real(y)) == \
148
+ -y/(x**2 + y**2)
149
+ assert refine(re((w + I*x) * (y + I*z)), Q.real(w) & Q.real(x) & Q.real(y)
150
+ & Q.real(z)) == w*y - x*z
151
+ assert refine(im((w + I*x) * (y + I*z)), Q.real(w) & Q.real(x) & Q.real(y)
152
+ & Q.real(z)) == w*z + x*y
153
+
154
+
155
+ def test_sign():
156
+ x = Symbol('x', real = True)
157
+ assert refine(sign(x), Q.positive(x)) == 1
158
+ assert refine(sign(x), Q.negative(x)) == -1
159
+ assert refine(sign(x), Q.zero(x)) == 0
160
+ assert refine(sign(x), True) == sign(x)
161
+ assert refine(sign(Abs(x)), Q.nonzero(x)) == 1
162
+
163
+ x = Symbol('x', imaginary=True)
164
+ assert refine(sign(x), Q.positive(im(x))) == S.ImaginaryUnit
165
+ assert refine(sign(x), Q.negative(im(x))) == -S.ImaginaryUnit
166
+ assert refine(sign(x), True) == sign(x)
167
+
168
+ x = Symbol('x', complex=True)
169
+ assert refine(sign(x), Q.zero(x)) == 0
170
+
171
+ def test_arg():
172
+ x = Symbol('x', complex = True)
173
+ assert refine(arg(x), Q.positive(x)) == 0
174
+ assert refine(arg(x), Q.negative(x)) == pi
175
+
176
+ def test_func_args():
177
+ class MyClass(Expr):
178
+ # A class with nontrivial .func
179
+
180
+ def __init__(self, *args):
181
+ self.my_member = ""
182
+
183
+ @property
184
+ def func(self):
185
+ def my_func(*args):
186
+ obj = MyClass(*args)
187
+ obj.my_member = self.my_member
188
+ return obj
189
+ return my_func
190
+
191
+ x = MyClass()
192
+ x.my_member = "A very important value"
193
+ assert x.my_member == refine(x).my_member
194
+
195
+ def test_issue_refine_9384():
196
+ assert refine(Piecewise((1, x < 0), (0, True)), Q.positive(x)) == 0
197
+ assert refine(Piecewise((1, x < 0), (0, True)), Q.negative(x)) == 1
198
+ assert refine(Piecewise((1, x > 0), (0, True)), Q.positive(x)) == 1
199
+ assert refine(Piecewise((1, x > 0), (0, True)), Q.negative(x)) == 0
200
+
201
+
202
+ def test_eval_refine():
203
+ class MockExpr(Expr):
204
+ def _eval_refine(self, assumptions):
205
+ return True
206
+
207
+ mock_obj = MockExpr()
208
+ assert refine(mock_obj)
209
+
210
+ def test_refine_issue_12724():
211
+ expr1 = refine(Abs(x * y), Q.positive(x))
212
+ expr2 = refine(Abs(x * y * z), Q.positive(x))
213
+ assert expr1 == x * Abs(y)
214
+ assert expr2 == x * Abs(y * z)
215
+ y1 = Symbol('y1', real = True)
216
+ expr3 = refine(Abs(x * y1**2 * z), Q.positive(x))
217
+ assert expr3 == x * y1**2 * Abs(z)
218
+
219
+
220
+ def test_matrixelement():
221
+ x = MatrixSymbol('x', 3, 3)
222
+ i = Symbol('i', positive = True)
223
+ j = Symbol('j', positive = True)
224
+ assert refine(x[0, 1], Q.symmetric(x)) == x[0, 1]
225
+ assert refine(x[1, 0], Q.symmetric(x)) == x[0, 1]
226
+ assert refine(x[i, j], Q.symmetric(x)) == x[j, i]
227
+ assert refine(x[j, i], Q.symmetric(x)) == x[j, i]
.venv/lib/python3.13/site-packages/sympy/assumptions/tests/test_rel_queries.py ADDED
@@ -0,0 +1,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.assumptions.lra_satask import lra_satask
2
+ from sympy.logic.algorithms.lra_theory import UnhandledInput
3
+ from sympy.assumptions.ask import Q, ask
4
+
5
+ from sympy.core import symbols, Symbol
6
+ from sympy.matrices.expressions.matexpr import MatrixSymbol
7
+ from sympy.core.numbers import I
8
+
9
+ from sympy.testing.pytest import raises, XFAIL
10
+ x, y, z = symbols("x y z", real=True)
11
+
12
+ def test_lra_satask():
13
+ im = Symbol('im', imaginary=True)
14
+
15
+ # test preprocessing of unequalities is working correctly
16
+ assert lra_satask(Q.eq(x, 1), ~Q.ne(x, 0)) is False
17
+ assert lra_satask(Q.eq(x, 0), ~Q.ne(x, 0)) is True
18
+ assert lra_satask(~Q.ne(x, 0), Q.eq(x, 0)) is True
19
+ assert lra_satask(~Q.eq(x, 0), Q.eq(x, 0)) is False
20
+ assert lra_satask(Q.ne(x, 0), Q.eq(x, 0)) is False
21
+
22
+ # basic tests
23
+ assert lra_satask(Q.ne(x, x)) is False
24
+ assert lra_satask(Q.eq(x, x)) is True
25
+ assert lra_satask(Q.gt(x, 0), Q.gt(x, 1)) is True
26
+
27
+ # check that True/False are handled
28
+ assert lra_satask(Q.gt(x, 0), True) is None
29
+ assert raises(ValueError, lambda: lra_satask(Q.gt(x, 0), False))
30
+
31
+ # check imaginary numbers are correctly handled
32
+ # (im * I).is_real returns True so this is an edge case
33
+ raises(UnhandledInput, lambda: lra_satask(Q.gt(im * I, 0), Q.gt(im * I, 0)))
34
+
35
+ # check matrix inputs
36
+ X = MatrixSymbol("X", 2, 2)
37
+ raises(UnhandledInput, lambda: lra_satask(Q.lt(X, 2) & Q.gt(X, 3)))
38
+
39
+
40
+ def test_old_assumptions():
41
+ # test unhandled old assumptions
42
+ w = symbols("w")
43
+ raises(UnhandledInput, lambda: lra_satask(Q.lt(w, 2) & Q.gt(w, 3)))
44
+ w = symbols("w", rational=False, real=True)
45
+ raises(UnhandledInput, lambda: lra_satask(Q.lt(w, 2) & Q.gt(w, 3)))
46
+ w = symbols("w", odd=True, real=True)
47
+ raises(UnhandledInput, lambda: lra_satask(Q.lt(w, 2) & Q.gt(w, 3)))
48
+ w = symbols("w", even=True, real=True)
49
+ raises(UnhandledInput, lambda: lra_satask(Q.lt(w, 2) & Q.gt(w, 3)))
50
+ w = symbols("w", prime=True, real=True)
51
+ raises(UnhandledInput, lambda: lra_satask(Q.lt(w, 2) & Q.gt(w, 3)))
52
+ w = symbols("w", composite=True, real=True)
53
+ raises(UnhandledInput, lambda: lra_satask(Q.lt(w, 2) & Q.gt(w, 3)))
54
+ w = symbols("w", integer=True, real=True)
55
+ raises(UnhandledInput, lambda: lra_satask(Q.lt(w, 2) & Q.gt(w, 3)))
56
+ w = symbols("w", integer=False, real=True)
57
+ raises(UnhandledInput, lambda: lra_satask(Q.lt(w, 2) & Q.gt(w, 3)))
58
+
59
+ # test handled
60
+ w = symbols("w", positive=True, real=True)
61
+ assert lra_satask(Q.le(w, 0)) is False
62
+ assert lra_satask(Q.gt(w, 0)) is True
63
+ w = symbols("w", negative=True, real=True)
64
+ assert lra_satask(Q.lt(w, 0)) is True
65
+ assert lra_satask(Q.ge(w, 0)) is False
66
+ w = symbols("w", zero=True, real=True)
67
+ assert lra_satask(Q.eq(w, 0)) is True
68
+ assert lra_satask(Q.ne(w, 0)) is False
69
+ w = symbols("w", nonzero=True, real=True)
70
+ assert lra_satask(Q.ne(w, 0)) is True
71
+ assert lra_satask(Q.eq(w, 1)) is None
72
+ w = symbols("w", nonpositive=True, real=True)
73
+ assert lra_satask(Q.le(w, 0)) is True
74
+ assert lra_satask(Q.gt(w, 0)) is False
75
+ w = symbols("w", nonnegative=True, real=True)
76
+ assert lra_satask(Q.ge(w, 0)) is True
77
+ assert lra_satask(Q.lt(w, 0)) is False
78
+
79
+
80
+ def test_rel_queries():
81
+ assert ask(Q.lt(x, 2) & Q.gt(x, 3)) is False
82
+ assert ask(Q.positive(x - z), (x > y) & (y > z)) is True
83
+ assert ask(x + y > 2, (x < 0) & (y <0)) is False
84
+ assert ask(x > z, (x > y) & (y > z)) is True
85
+
86
+
87
+ def test_unhandled_queries():
88
+ X = MatrixSymbol("X", 2, 2)
89
+ assert ask(Q.lt(X, 2) & Q.gt(X, 3)) is None
90
+
91
+
92
+ def test_all_pred():
93
+ # test usable pred
94
+ assert lra_satask(Q.extended_positive(x), (x > 2)) is True
95
+ assert lra_satask(Q.positive_infinite(x)) is False
96
+ assert lra_satask(Q.negative_infinite(x)) is False
97
+
98
+ # test disallowed pred
99
+ raises(UnhandledInput, lambda: lra_satask((x > 0), (x > 2) & Q.prime(x)))
100
+ raises(UnhandledInput, lambda: lra_satask((x > 0), (x > 2) & Q.composite(x)))
101
+ raises(UnhandledInput, lambda: lra_satask((x > 0), (x > 2) & Q.odd(x)))
102
+ raises(UnhandledInput, lambda: lra_satask((x > 0), (x > 2) & Q.even(x)))
103
+ raises(UnhandledInput, lambda: lra_satask((x > 0), (x > 2) & Q.integer(x)))
104
+
105
+
106
+ def test_number_line_properties():
107
+ # From:
108
+ # https://en.wikipedia.org/wiki/Inequality_(mathematics)#Properties_on_the_number_line
109
+
110
+ a, b, c = symbols("a b c", real=True)
111
+
112
+ # Transitivity
113
+ # If a <= b and b <= c, then a <= c.
114
+ assert ask(a <= c, (a <= b) & (b <= c)) is True
115
+ # If a <= b and b < c, then a < c.
116
+ assert ask(a < c, (a <= b) & (b < c)) is True
117
+ # If a < b and b <= c, then a < c.
118
+ assert ask(a < c, (a < b) & (b <= c)) is True
119
+
120
+ # Addition and subtraction
121
+ # If a <= b, then a + c <= b + c and a - c <= b - c.
122
+ assert ask(a + c <= b + c, a <= b) is True
123
+ assert ask(a - c <= b - c, a <= b) is True
124
+
125
+
126
+ @XFAIL
127
+ def test_failing_number_line_properties():
128
+ # From:
129
+ # https://en.wikipedia.org/wiki/Inequality_(mathematics)#Properties_on_the_number_line
130
+
131
+ a, b, c = symbols("a b c", real=True)
132
+
133
+ # Multiplication and division
134
+ # If a <= b and c > 0, then ac <= bc and a/c <= b/c. (True for non-zero c)
135
+ assert ask(a*c <= b*c, (a <= b) & (c > 0) & ~ Q.zero(c)) is True
136
+ assert ask(a/c <= b/c, (a <= b) & (c > 0) & ~ Q.zero(c)) is True
137
+ # If a <= b and c < 0, then ac >= bc and a/c >= b/c. (True for non-zero c)
138
+ assert ask(a*c >= b*c, (a <= b) & (c < 0) & ~ Q.zero(c)) is True
139
+ assert ask(a/c >= b/c, (a <= b) & (c < 0) & ~ Q.zero(c)) is True
140
+
141
+ # Additive inverse
142
+ # If a <= b, then -a >= -b.
143
+ assert ask(-a >= -b, a <= b) is True
144
+
145
+ # Multiplicative inverse
146
+ # For a, b that are both negative or both positive:
147
+ # If a <= b, then 1/a >= 1/b .
148
+ assert ask(1/a >= 1/b, (a <= b) & Q.positive(x) & Q.positive(b)) is True
149
+ assert ask(1/a >= 1/b, (a <= b) & Q.negative(x) & Q.negative(b)) is True
150
+
151
+
152
+ def test_equality():
153
+ # test symmetry and reflexivity
154
+ assert ask(Q.eq(x, x)) is True
155
+ assert ask(Q.eq(y, x), Q.eq(x, y)) is True
156
+ assert ask(Q.eq(y, x), ~Q.eq(z, z) | Q.eq(x, y)) is True
157
+
158
+ # test transitivity
159
+ assert ask(Q.eq(x,z), Q.eq(x,y) & Q.eq(y,z)) is True
160
+
161
+
162
+ @XFAIL
163
+ def test_equality_failing():
164
+ # Note that implementing the substitution property of equality
165
+ # most likely requires a redesign of the new assumptions.
166
+ # See issue #25485 for why this is the case and general ideas
167
+ # about how things could be redesigned.
168
+
169
+ # test substitution property
170
+ assert ask(Q.prime(x), Q.eq(x, y) & Q.prime(y)) is True
171
+ assert ask(Q.real(x), Q.eq(x, y) & Q.real(y)) is True
172
+ assert ask(Q.imaginary(x), Q.eq(x, y) & Q.imaginary(y)) is True
.venv/lib/python3.13/site-packages/sympy/assumptions/tests/test_satask.py ADDED
@@ -0,0 +1,378 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.assumptions.ask import Q
2
+ from sympy.assumptions.assume import assuming
3
+ from sympy.core.numbers import (I, pi)
4
+ from sympy.core.relational import (Eq, Gt)
5
+ from sympy.core.singleton import S
6
+ from sympy.core.symbol import symbols
7
+ from sympy.functions.elementary.complexes import Abs
8
+ from sympy.logic.boolalg import Implies
9
+ from sympy.matrices.expressions.matexpr import MatrixSymbol
10
+ from sympy.assumptions.cnf import CNF, Literal
11
+ from sympy.assumptions.satask import (satask, extract_predargs,
12
+ get_relevant_clsfacts)
13
+
14
+ from sympy.testing.pytest import raises, XFAIL
15
+
16
+
17
+ x, y, z = symbols('x y z')
18
+
19
+
20
+ def test_satask():
21
+ # No relevant facts
22
+ assert satask(Q.real(x), Q.real(x)) is True
23
+ assert satask(Q.real(x), ~Q.real(x)) is False
24
+ assert satask(Q.real(x)) is None
25
+
26
+ assert satask(Q.real(x), Q.positive(x)) is True
27
+ assert satask(Q.positive(x), Q.real(x)) is None
28
+ assert satask(Q.real(x), ~Q.positive(x)) is None
29
+ assert satask(Q.positive(x), ~Q.real(x)) is False
30
+
31
+ raises(ValueError, lambda: satask(Q.real(x), Q.real(x) & ~Q.real(x)))
32
+
33
+ with assuming(Q.positive(x)):
34
+ assert satask(Q.real(x)) is True
35
+ assert satask(~Q.positive(x)) is False
36
+ raises(ValueError, lambda: satask(Q.real(x), ~Q.positive(x)))
37
+
38
+ assert satask(Q.zero(x), Q.nonzero(x)) is False
39
+ assert satask(Q.positive(x), Q.zero(x)) is False
40
+ assert satask(Q.real(x), Q.zero(x)) is True
41
+ assert satask(Q.zero(x), Q.zero(x*y)) is None
42
+ assert satask(Q.zero(x*y), Q.zero(x))
43
+
44
+
45
+ def test_zero():
46
+ """
47
+ Everything in this test doesn't work with the ask handlers, and most
48
+ things would be very difficult or impossible to make work under that
49
+ model.
50
+
51
+ """
52
+ assert satask(Q.zero(x) | Q.zero(y), Q.zero(x*y)) is True
53
+ assert satask(Q.zero(x*y), Q.zero(x) | Q.zero(y)) is True
54
+
55
+ assert satask(Implies(Q.zero(x), Q.zero(x*y))) is True
56
+
57
+ # This one in particular requires computing the fixed-point of the
58
+ # relevant facts, because going from Q.nonzero(x*y) -> ~Q.zero(x*y) and
59
+ # Q.zero(x*y) -> Equivalent(Q.zero(x*y), Q.zero(x) | Q.zero(y)) takes two
60
+ # steps.
61
+ assert satask(Q.zero(x) | Q.zero(y), Q.nonzero(x*y)) is False
62
+
63
+ assert satask(Q.zero(x), Q.zero(x**2)) is True
64
+
65
+
66
+ def test_zero_positive():
67
+ assert satask(Q.zero(x + y), Q.positive(x) & Q.positive(y)) is False
68
+ assert satask(Q.positive(x) & Q.positive(y), Q.zero(x + y)) is False
69
+ assert satask(Q.nonzero(x + y), Q.positive(x) & Q.positive(y)) is True
70
+ assert satask(Q.positive(x) & Q.positive(y), Q.nonzero(x + y)) is None
71
+
72
+ # This one requires several levels of forward chaining
73
+ assert satask(Q.zero(x*(x + y)), Q.positive(x) & Q.positive(y)) is False
74
+
75
+ assert satask(Q.positive(pi*x*y + 1), Q.positive(x) & Q.positive(y)) is True
76
+ assert satask(Q.positive(pi*x*y - 5), Q.positive(x) & Q.positive(y)) is None
77
+
78
+
79
+ def test_zero_pow():
80
+ assert satask(Q.zero(x**y), Q.zero(x) & Q.positive(y)) is True
81
+ assert satask(Q.zero(x**y), Q.nonzero(x) & Q.zero(y)) is False
82
+
83
+ assert satask(Q.zero(x), Q.zero(x**y)) is True
84
+
85
+ assert satask(Q.zero(x**y), Q.zero(x)) is None
86
+
87
+
88
+ @XFAIL
89
+ # Requires correct Q.square calculation first
90
+ def test_invertible():
91
+ A = MatrixSymbol('A', 5, 5)
92
+ B = MatrixSymbol('B', 5, 5)
93
+ assert satask(Q.invertible(A*B), Q.invertible(A) & Q.invertible(B)) is True
94
+ assert satask(Q.invertible(A), Q.invertible(A*B)) is True
95
+ assert satask(Q.invertible(A) & Q.invertible(B), Q.invertible(A*B)) is True
96
+
97
+
98
+ def test_prime():
99
+ assert satask(Q.prime(5)) is True
100
+ assert satask(Q.prime(6)) is False
101
+ assert satask(Q.prime(-5)) is False
102
+
103
+ assert satask(Q.prime(x*y), Q.integer(x) & Q.integer(y)) is None
104
+ assert satask(Q.prime(x*y), Q.prime(x) & Q.prime(y)) is False
105
+
106
+
107
+ def test_old_assump():
108
+ assert satask(Q.positive(1)) is True
109
+ assert satask(Q.positive(-1)) is False
110
+ assert satask(Q.positive(0)) is False
111
+ assert satask(Q.positive(I)) is False
112
+ assert satask(Q.positive(pi)) is True
113
+
114
+ assert satask(Q.negative(1)) is False
115
+ assert satask(Q.negative(-1)) is True
116
+ assert satask(Q.negative(0)) is False
117
+ assert satask(Q.negative(I)) is False
118
+ assert satask(Q.negative(pi)) is False
119
+
120
+ assert satask(Q.zero(1)) is False
121
+ assert satask(Q.zero(-1)) is False
122
+ assert satask(Q.zero(0)) is True
123
+ assert satask(Q.zero(I)) is False
124
+ assert satask(Q.zero(pi)) is False
125
+
126
+ assert satask(Q.nonzero(1)) is True
127
+ assert satask(Q.nonzero(-1)) is True
128
+ assert satask(Q.nonzero(0)) is False
129
+ assert satask(Q.nonzero(I)) is False
130
+ assert satask(Q.nonzero(pi)) is True
131
+
132
+ assert satask(Q.nonpositive(1)) is False
133
+ assert satask(Q.nonpositive(-1)) is True
134
+ assert satask(Q.nonpositive(0)) is True
135
+ assert satask(Q.nonpositive(I)) is False
136
+ assert satask(Q.nonpositive(pi)) is False
137
+
138
+ assert satask(Q.nonnegative(1)) is True
139
+ assert satask(Q.nonnegative(-1)) is False
140
+ assert satask(Q.nonnegative(0)) is True
141
+ assert satask(Q.nonnegative(I)) is False
142
+ assert satask(Q.nonnegative(pi)) is True
143
+
144
+
145
+ def test_rational_irrational():
146
+ assert satask(Q.irrational(2)) is False
147
+ assert satask(Q.rational(2)) is True
148
+ assert satask(Q.irrational(pi)) is True
149
+ assert satask(Q.rational(pi)) is False
150
+ assert satask(Q.irrational(I)) is False
151
+ assert satask(Q.rational(I)) is False
152
+
153
+ assert satask(Q.irrational(x*y*z), Q.irrational(x) & Q.irrational(y) &
154
+ Q.rational(z)) is None
155
+ assert satask(Q.irrational(x*y*z), Q.irrational(x) & Q.rational(y) &
156
+ Q.rational(z)) is True
157
+ assert satask(Q.irrational(pi*x*y), Q.rational(x) & Q.rational(y)) is True
158
+
159
+ assert satask(Q.irrational(x + y + z), Q.irrational(x) & Q.irrational(y) &
160
+ Q.rational(z)) is None
161
+ assert satask(Q.irrational(x + y + z), Q.irrational(x) & Q.rational(y) &
162
+ Q.rational(z)) is True
163
+ assert satask(Q.irrational(pi + x + y), Q.rational(x) & Q.rational(y)) is True
164
+
165
+ assert satask(Q.irrational(x*y*z), Q.rational(x) & Q.rational(y) &
166
+ Q.rational(z)) is False
167
+ assert satask(Q.rational(x*y*z), Q.rational(x) & Q.rational(y) &
168
+ Q.rational(z)) is True
169
+
170
+ assert satask(Q.irrational(x + y + z), Q.rational(x) & Q.rational(y) &
171
+ Q.rational(z)) is False
172
+ assert satask(Q.rational(x + y + z), Q.rational(x) & Q.rational(y) &
173
+ Q.rational(z)) is True
174
+
175
+
176
+ def test_even_satask():
177
+ assert satask(Q.even(2)) is True
178
+ assert satask(Q.even(3)) is False
179
+
180
+ assert satask(Q.even(x*y), Q.even(x) & Q.odd(y)) is True
181
+ assert satask(Q.even(x*y), Q.even(x) & Q.integer(y)) is True
182
+ assert satask(Q.even(x*y), Q.even(x) & Q.even(y)) is True
183
+ assert satask(Q.even(x*y), Q.odd(x) & Q.odd(y)) is False
184
+ assert satask(Q.even(x*y), Q.even(x)) is None
185
+ assert satask(Q.even(x*y), Q.odd(x) & Q.integer(y)) is None
186
+ assert satask(Q.even(x*y), Q.odd(x) & Q.odd(y)) is False
187
+
188
+ assert satask(Q.even(abs(x)), Q.even(x)) is True
189
+ assert satask(Q.even(abs(x)), Q.odd(x)) is False
190
+ assert satask(Q.even(x), Q.even(abs(x))) is None # x could be complex
191
+
192
+
193
+ def test_odd_satask():
194
+ assert satask(Q.odd(2)) is False
195
+ assert satask(Q.odd(3)) is True
196
+
197
+ assert satask(Q.odd(x*y), Q.even(x) & Q.odd(y)) is False
198
+ assert satask(Q.odd(x*y), Q.even(x) & Q.integer(y)) is False
199
+ assert satask(Q.odd(x*y), Q.even(x) & Q.even(y)) is False
200
+ assert satask(Q.odd(x*y), Q.odd(x) & Q.odd(y)) is True
201
+ assert satask(Q.odd(x*y), Q.even(x)) is None
202
+ assert satask(Q.odd(x*y), Q.odd(x) & Q.integer(y)) is None
203
+ assert satask(Q.odd(x*y), Q.odd(x) & Q.odd(y)) is True
204
+
205
+ assert satask(Q.odd(abs(x)), Q.even(x)) is False
206
+ assert satask(Q.odd(abs(x)), Q.odd(x)) is True
207
+ assert satask(Q.odd(x), Q.odd(abs(x))) is None # x could be complex
208
+
209
+
210
+ def test_integer():
211
+ assert satask(Q.integer(1)) is True
212
+ assert satask(Q.integer(S.Half)) is False
213
+
214
+ assert satask(Q.integer(x + y), Q.integer(x) & Q.integer(y)) is True
215
+ assert satask(Q.integer(x + y), Q.integer(x)) is None
216
+
217
+ assert satask(Q.integer(x + y), Q.integer(x) & ~Q.integer(y)) is False
218
+ assert satask(Q.integer(x + y + z), Q.integer(x) & Q.integer(y) &
219
+ ~Q.integer(z)) is False
220
+ assert satask(Q.integer(x + y + z), Q.integer(x) & ~Q.integer(y) &
221
+ ~Q.integer(z)) is None
222
+ assert satask(Q.integer(x + y + z), Q.integer(x) & ~Q.integer(y)) is None
223
+ assert satask(Q.integer(x + y), Q.integer(x) & Q.irrational(y)) is False
224
+
225
+ assert satask(Q.integer(x*y), Q.integer(x) & Q.integer(y)) is True
226
+ assert satask(Q.integer(x*y), Q.integer(x)) is None
227
+
228
+ assert satask(Q.integer(x*y), Q.integer(x) & ~Q.integer(y)) is None
229
+ assert satask(Q.integer(x*y), Q.integer(x) & ~Q.rational(y)) is False
230
+ assert satask(Q.integer(x*y*z), Q.integer(x) & Q.integer(y) &
231
+ ~Q.rational(z)) is False
232
+ assert satask(Q.integer(x*y*z), Q.integer(x) & ~Q.rational(y) &
233
+ ~Q.rational(z)) is None
234
+ assert satask(Q.integer(x*y*z), Q.integer(x) & ~Q.rational(y)) is None
235
+ assert satask(Q.integer(x*y), Q.integer(x) & Q.irrational(y)) is False
236
+
237
+
238
+ def test_abs():
239
+ assert satask(Q.nonnegative(abs(x))) is True
240
+ assert satask(Q.positive(abs(x)), ~Q.zero(x)) is True
241
+ assert satask(Q.zero(x), ~Q.zero(abs(x))) is False
242
+ assert satask(Q.zero(x), Q.zero(abs(x))) is True
243
+ assert satask(Q.nonzero(x), ~Q.zero(abs(x))) is None # x could be complex
244
+ assert satask(Q.zero(abs(x)), Q.zero(x)) is True
245
+
246
+
247
+ def test_imaginary():
248
+ assert satask(Q.imaginary(2*I)) is True
249
+ assert satask(Q.imaginary(x*y), Q.imaginary(x)) is None
250
+ assert satask(Q.imaginary(x*y), Q.imaginary(x) & Q.real(y)) is True
251
+ assert satask(Q.imaginary(x), Q.real(x)) is False
252
+ assert satask(Q.imaginary(1)) is False
253
+ assert satask(Q.imaginary(x*y), Q.real(x) & Q.real(y)) is False
254
+ assert satask(Q.imaginary(x + y), Q.real(x) & Q.real(y)) is False
255
+
256
+
257
+ def test_real():
258
+ assert satask(Q.real(x*y), Q.real(x) & Q.real(y)) is True
259
+ assert satask(Q.real(x + y), Q.real(x) & Q.real(y)) is True
260
+ assert satask(Q.real(x*y*z), Q.real(x) & Q.real(y) & Q.real(z)) is True
261
+ assert satask(Q.real(x*y*z), Q.real(x) & Q.real(y)) is None
262
+ assert satask(Q.real(x*y*z), Q.real(x) & Q.real(y) & Q.imaginary(z)) is False
263
+ assert satask(Q.real(x + y + z), Q.real(x) & Q.real(y) & Q.real(z)) is True
264
+ assert satask(Q.real(x + y + z), Q.real(x) & Q.real(y)) is None
265
+
266
+
267
+ def test_pos_neg():
268
+ assert satask(~Q.positive(x), Q.negative(x)) is True
269
+ assert satask(~Q.negative(x), Q.positive(x)) is True
270
+ assert satask(Q.positive(x + y), Q.positive(x) & Q.positive(y)) is True
271
+ assert satask(Q.negative(x + y), Q.negative(x) & Q.negative(y)) is True
272
+ assert satask(Q.positive(x + y), Q.negative(x) & Q.negative(y)) is False
273
+ assert satask(Q.negative(x + y), Q.positive(x) & Q.positive(y)) is False
274
+
275
+
276
+ def test_pow_pos_neg():
277
+ assert satask(Q.nonnegative(x**2), Q.positive(x)) is True
278
+ assert satask(Q.nonpositive(x**2), Q.positive(x)) is False
279
+ assert satask(Q.positive(x**2), Q.positive(x)) is True
280
+ assert satask(Q.negative(x**2), Q.positive(x)) is False
281
+ assert satask(Q.real(x**2), Q.positive(x)) is True
282
+
283
+ assert satask(Q.nonnegative(x**2), Q.negative(x)) is True
284
+ assert satask(Q.nonpositive(x**2), Q.negative(x)) is False
285
+ assert satask(Q.positive(x**2), Q.negative(x)) is True
286
+ assert satask(Q.negative(x**2), Q.negative(x)) is False
287
+ assert satask(Q.real(x**2), Q.negative(x)) is True
288
+
289
+ assert satask(Q.nonnegative(x**2), Q.nonnegative(x)) is True
290
+ assert satask(Q.nonpositive(x**2), Q.nonnegative(x)) is None
291
+ assert satask(Q.positive(x**2), Q.nonnegative(x)) is None
292
+ assert satask(Q.negative(x**2), Q.nonnegative(x)) is False
293
+ assert satask(Q.real(x**2), Q.nonnegative(x)) is True
294
+
295
+ assert satask(Q.nonnegative(x**2), Q.nonpositive(x)) is True
296
+ assert satask(Q.nonpositive(x**2), Q.nonpositive(x)) is None
297
+ assert satask(Q.positive(x**2), Q.nonpositive(x)) is None
298
+ assert satask(Q.negative(x**2), Q.nonpositive(x)) is False
299
+ assert satask(Q.real(x**2), Q.nonpositive(x)) is True
300
+
301
+ assert satask(Q.nonnegative(x**3), Q.positive(x)) is True
302
+ assert satask(Q.nonpositive(x**3), Q.positive(x)) is False
303
+ assert satask(Q.positive(x**3), Q.positive(x)) is True
304
+ assert satask(Q.negative(x**3), Q.positive(x)) is False
305
+ assert satask(Q.real(x**3), Q.positive(x)) is True
306
+
307
+ assert satask(Q.nonnegative(x**3), Q.negative(x)) is False
308
+ assert satask(Q.nonpositive(x**3), Q.negative(x)) is True
309
+ assert satask(Q.positive(x**3), Q.negative(x)) is False
310
+ assert satask(Q.negative(x**3), Q.negative(x)) is True
311
+ assert satask(Q.real(x**3), Q.negative(x)) is True
312
+
313
+ assert satask(Q.nonnegative(x**3), Q.nonnegative(x)) is True
314
+ assert satask(Q.nonpositive(x**3), Q.nonnegative(x)) is None
315
+ assert satask(Q.positive(x**3), Q.nonnegative(x)) is None
316
+ assert satask(Q.negative(x**3), Q.nonnegative(x)) is False
317
+ assert satask(Q.real(x**3), Q.nonnegative(x)) is True
318
+
319
+ assert satask(Q.nonnegative(x**3), Q.nonpositive(x)) is None
320
+ assert satask(Q.nonpositive(x**3), Q.nonpositive(x)) is True
321
+ assert satask(Q.positive(x**3), Q.nonpositive(x)) is False
322
+ assert satask(Q.negative(x**3), Q.nonpositive(x)) is None
323
+ assert satask(Q.real(x**3), Q.nonpositive(x)) is True
324
+
325
+ # If x is zero, x**negative is not real.
326
+ assert satask(Q.nonnegative(x**-2), Q.nonpositive(x)) is None
327
+ assert satask(Q.nonpositive(x**-2), Q.nonpositive(x)) is None
328
+ assert satask(Q.positive(x**-2), Q.nonpositive(x)) is None
329
+ assert satask(Q.negative(x**-2), Q.nonpositive(x)) is None
330
+ assert satask(Q.real(x**-2), Q.nonpositive(x)) is None
331
+
332
+ # We could deduce things for negative powers if x is nonzero, but it
333
+ # isn't implemented yet.
334
+
335
+
336
+ def test_prime_composite():
337
+ assert satask(Q.prime(x), Q.composite(x)) is False
338
+ assert satask(Q.composite(x), Q.prime(x)) is False
339
+ assert satask(Q.composite(x), ~Q.prime(x)) is None
340
+ assert satask(Q.prime(x), ~Q.composite(x)) is None
341
+ # since 1 is neither prime nor composite the following should hold
342
+ assert satask(Q.prime(x), Q.integer(x) & Q.positive(x) & ~Q.composite(x)) is None
343
+ assert satask(Q.prime(2)) is True
344
+ assert satask(Q.prime(4)) is False
345
+ assert satask(Q.prime(1)) is False
346
+ assert satask(Q.composite(1)) is False
347
+
348
+
349
+ def test_extract_predargs():
350
+ props = CNF.from_prop(Q.zero(Abs(x*y)) & Q.zero(x*y))
351
+ assump = CNF.from_prop(Q.zero(x))
352
+ context = CNF.from_prop(Q.zero(y))
353
+ assert extract_predargs(props) == {Abs(x*y), x*y}
354
+ assert extract_predargs(props, assump) == {Abs(x*y), x*y, x}
355
+ assert extract_predargs(props, assump, context) == {Abs(x*y), x*y, x, y}
356
+
357
+ props = CNF.from_prop(Eq(x, y))
358
+ assump = CNF.from_prop(Gt(y, z))
359
+ assert extract_predargs(props, assump) == {x, y, z}
360
+
361
+
362
+ def test_get_relevant_clsfacts():
363
+ exprs = {Abs(x*y)}
364
+ exprs, facts = get_relevant_clsfacts(exprs)
365
+ assert exprs == {x*y}
366
+ assert facts.clauses == \
367
+ {frozenset({Literal(Q.odd(Abs(x*y)), False), Literal(Q.odd(x*y), True)}),
368
+ frozenset({Literal(Q.zero(Abs(x*y)), False), Literal(Q.zero(x*y), True)}),
369
+ frozenset({Literal(Q.even(Abs(x*y)), False), Literal(Q.even(x*y), True)}),
370
+ frozenset({Literal(Q.zero(Abs(x*y)), True), Literal(Q.zero(x*y), False)}),
371
+ frozenset({Literal(Q.even(Abs(x*y)), False),
372
+ Literal(Q.odd(Abs(x*y)), False),
373
+ Literal(Q.odd(x*y), True)}),
374
+ frozenset({Literal(Q.even(Abs(x*y)), False),
375
+ Literal(Q.even(x*y), True),
376
+ Literal(Q.odd(Abs(x*y)), False)}),
377
+ frozenset({Literal(Q.positive(Abs(x*y)), False),
378
+ Literal(Q.zero(Abs(x*y)), False)})}
.venv/lib/python3.13/site-packages/sympy/assumptions/tests/test_sathandlers.py ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.assumptions.ask import Q
2
+ from sympy.core.basic import Basic
3
+ from sympy.core.expr import Expr
4
+ from sympy.core.mul import Mul
5
+ from sympy.core.symbol import symbols
6
+ from sympy.logic.boolalg import (And, Or)
7
+
8
+ from sympy.assumptions.sathandlers import (ClassFactRegistry, allargs,
9
+ anyarg, exactlyonearg,)
10
+
11
+ x, y, z = symbols('x y z')
12
+
13
+
14
+ def test_class_handler_registry():
15
+ my_handler_registry = ClassFactRegistry()
16
+
17
+ # The predicate doesn't matter here, so just pass
18
+ @my_handler_registry.register(Mul)
19
+ def fact1(expr):
20
+ pass
21
+ @my_handler_registry.multiregister(Expr)
22
+ def fact2(expr):
23
+ pass
24
+
25
+ assert my_handler_registry[Basic] == (frozenset(), frozenset())
26
+ assert my_handler_registry[Expr] == (frozenset(), frozenset({fact2}))
27
+ assert my_handler_registry[Mul] == (frozenset({fact1}), frozenset({fact2}))
28
+
29
+
30
+ def test_allargs():
31
+ assert allargs(x, Q.zero(x), x*y) == And(Q.zero(x), Q.zero(y))
32
+ assert allargs(x, Q.positive(x) | Q.negative(x), x*y) == And(Q.positive(x) | Q.negative(x), Q.positive(y) | Q.negative(y))
33
+
34
+
35
+ def test_anyarg():
36
+ assert anyarg(x, Q.zero(x), x*y) == Or(Q.zero(x), Q.zero(y))
37
+ assert anyarg(x, Q.positive(x) & Q.negative(x), x*y) == \
38
+ Or(Q.positive(x) & Q.negative(x), Q.positive(y) & Q.negative(y))
39
+
40
+
41
+ def test_exactlyonearg():
42
+ assert exactlyonearg(x, Q.zero(x), x*y) == \
43
+ Or(Q.zero(x) & ~Q.zero(y), Q.zero(y) & ~Q.zero(x))
44
+ assert exactlyonearg(x, Q.zero(x), x*y*z) == \
45
+ Or(Q.zero(x) & ~Q.zero(y) & ~Q.zero(z), Q.zero(y)
46
+ & ~Q.zero(x) & ~Q.zero(z), Q.zero(z) & ~Q.zero(x) & ~Q.zero(y))
47
+ assert exactlyonearg(x, Q.positive(x) | Q.negative(x), x*y) == \
48
+ Or((Q.positive(x) | Q.negative(x)) &
49
+ ~(Q.positive(y) | Q.negative(y)), (Q.positive(y) | Q.negative(y)) &
50
+ ~(Q.positive(x) | Q.negative(x)))
.venv/lib/python3.13/site-packages/sympy/assumptions/tests/test_wrapper.py ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.assumptions.ask import Q
2
+ from sympy.assumptions.wrapper import (AssumptionsWrapper, is_infinite,
3
+ is_extended_real)
4
+ from sympy.core.symbol import Symbol
5
+ from sympy.core.assumptions import _assume_defined
6
+
7
+
8
+ def test_all_predicates():
9
+ for fact in _assume_defined:
10
+ method_name = f'_eval_is_{fact}'
11
+ assert hasattr(AssumptionsWrapper, method_name)
12
+
13
+
14
+ def test_AssumptionsWrapper():
15
+ x = Symbol('x', positive=True)
16
+ y = Symbol('y')
17
+ assert AssumptionsWrapper(x).is_positive
18
+ assert AssumptionsWrapper(y).is_positive is None
19
+ assert AssumptionsWrapper(y, Q.positive(y)).is_positive
20
+
21
+
22
+ def test_is_infinite():
23
+ x = Symbol('x', infinite=True)
24
+ y = Symbol('y', infinite=False)
25
+ z = Symbol('z')
26
+ assert is_infinite(x)
27
+ assert not is_infinite(y)
28
+ assert is_infinite(z) is None
29
+ assert is_infinite(z, Q.infinite(z))
30
+
31
+
32
+ def test_is_extended_real():
33
+ x = Symbol('x', extended_real=True)
34
+ y = Symbol('y', extended_real=False)
35
+ z = Symbol('z')
36
+ assert is_extended_real(x)
37
+ assert not is_extended_real(y)
38
+ assert is_extended_real(z) is None
39
+ assert is_extended_real(z, Q.extended_real(z))
.venv/lib/python3.13/site-packages/sympy/integrals/benchmarks/__init__.py ADDED
File without changes
.venv/lib/python3.13/site-packages/sympy/integrals/benchmarks/bench_integrate.py ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core.symbol import Symbol
2
+ from sympy.functions.elementary.trigonometric import sin
3
+ from sympy.integrals.integrals import integrate
4
+
5
+ x = Symbol('x')
6
+
7
+
8
+ def bench_integrate_sin():
9
+ integrate(sin(x), x)
10
+
11
+
12
+ def bench_integrate_x1sin():
13
+ integrate(x**1*sin(x), x)
14
+
15
+
16
+ def bench_integrate_x2sin():
17
+ integrate(x**2*sin(x), x)
18
+
19
+
20
+ def bench_integrate_x3sin():
21
+ integrate(x**3*sin(x), x)
.venv/lib/python3.13/site-packages/sympy/integrals/benchmarks/bench_trigintegrate.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core.symbol import Symbol
2
+ from sympy.functions.elementary.trigonometric import sin
3
+ from sympy.integrals.trigonometry import trigintegrate
4
+
5
+ x = Symbol('x')
6
+
7
+
8
+ def timeit_trigintegrate_sin3x():
9
+ trigintegrate(sin(x)**3, x)
10
+
11
+
12
+ def timeit_trigintegrate_x2():
13
+ trigintegrate(x**2, x) # -> None
.venv/lib/python3.13/site-packages/sympy/integrals/tests/__init__.py ADDED
File without changes
.venv/lib/python3.13/site-packages/sympy/integrals/tests/test_deltafunctions.py ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core.function import Function
2
+ from sympy.core.numbers import (Rational, pi)
3
+ from sympy.core.singleton import S
4
+ from sympy.core.symbol import symbols
5
+ from sympy.functions.elementary.trigonometric import (cos, sin)
6
+ from sympy.functions.special.delta_functions import (DiracDelta, Heaviside)
7
+ from sympy.integrals.deltafunctions import change_mul, deltaintegrate
8
+
9
+ f = Function("f")
10
+ x_1, x_2, x, y, z = symbols("x_1 x_2 x y z")
11
+
12
+
13
+ def test_change_mul():
14
+ assert change_mul(x, x) == (None, None)
15
+ assert change_mul(x*y, x) == (None, None)
16
+ assert change_mul(x*y*DiracDelta(x), x) == (DiracDelta(x), x*y)
17
+ assert change_mul(x*y*DiracDelta(x)*DiracDelta(y), x) == \
18
+ (DiracDelta(x), x*y*DiracDelta(y))
19
+ assert change_mul(DiracDelta(x)**2, x) == \
20
+ (DiracDelta(x), DiracDelta(x))
21
+ assert change_mul(y*DiracDelta(x)**2, x) == \
22
+ (DiracDelta(x), y*DiracDelta(x))
23
+
24
+
25
+ def test_deltaintegrate():
26
+ assert deltaintegrate(x, x) is None
27
+ assert deltaintegrate(x + DiracDelta(x), x) is None
28
+ assert deltaintegrate(DiracDelta(x, 0), x) == Heaviside(x)
29
+ for n in range(10):
30
+ assert deltaintegrate(DiracDelta(x, n + 1), x) == DiracDelta(x, n)
31
+ assert deltaintegrate(DiracDelta(x), x) == Heaviside(x)
32
+ assert deltaintegrate(DiracDelta(-x), x) == Heaviside(x)
33
+ assert deltaintegrate(DiracDelta(x - y), x) == Heaviside(x - y)
34
+ assert deltaintegrate(DiracDelta(y - x), x) == Heaviside(x - y)
35
+
36
+ assert deltaintegrate(x*DiracDelta(x), x) == 0
37
+ assert deltaintegrate((x - y)*DiracDelta(x - y), x) == 0
38
+
39
+ assert deltaintegrate(DiracDelta(x)**2, x) == DiracDelta(0)*Heaviside(x)
40
+ assert deltaintegrate(y*DiracDelta(x)**2, x) == \
41
+ y*DiracDelta(0)*Heaviside(x)
42
+ assert deltaintegrate(DiracDelta(x, 1), x) == DiracDelta(x, 0)
43
+ assert deltaintegrate(y*DiracDelta(x, 1), x) == y*DiracDelta(x, 0)
44
+ assert deltaintegrate(DiracDelta(x, 1)**2, x) == -DiracDelta(0, 2)*Heaviside(x)
45
+ assert deltaintegrate(y*DiracDelta(x, 1)**2, x) == -y*DiracDelta(0, 2)*Heaviside(x)
46
+
47
+
48
+ assert deltaintegrate(DiracDelta(x) * f(x), x) == f(0) * Heaviside(x)
49
+ assert deltaintegrate(DiracDelta(-x) * f(x), x) == f(0) * Heaviside(x)
50
+ assert deltaintegrate(DiracDelta(x - 1) * f(x), x) == f(1) * Heaviside(x - 1)
51
+ assert deltaintegrate(DiracDelta(1 - x) * f(x), x) == f(1) * Heaviside(x - 1)
52
+ assert deltaintegrate(DiracDelta(x**2 + x - 2), x) == \
53
+ Heaviside(x - 1)/3 + Heaviside(x + 2)/3
54
+
55
+ p = cos(x)*(DiracDelta(x) + DiracDelta(x**2 - 1))*sin(x)*(x - pi)
56
+ assert deltaintegrate(p, x) - (-pi*(cos(1)*Heaviside(-1 + x)*sin(1)/2 - \
57
+ cos(1)*Heaviside(1 + x)*sin(1)/2) + \
58
+ cos(1)*Heaviside(1 + x)*sin(1)/2 + \
59
+ cos(1)*Heaviside(-1 + x)*sin(1)/2) == 0
60
+
61
+ p = x_2*DiracDelta(x - x_2)*DiracDelta(x_2 - x_1)
62
+ assert deltaintegrate(p, x_2) == x*DiracDelta(x - x_1)*Heaviside(x_2 - x)
63
+
64
+ p = x*y**2*z*DiracDelta(y - x)*DiracDelta(y - z)*DiracDelta(x - z)
65
+ assert deltaintegrate(p, y) == x**3*z*DiracDelta(x - z)**2*Heaviside(y - x)
66
+ assert deltaintegrate((x + 1)*DiracDelta(2*x), x) == S.Half * Heaviside(x)
67
+ assert deltaintegrate((x + 1)*DiracDelta(x*Rational(2, 3) + Rational(4, 9)), x) == \
68
+ S.Half * Heaviside(x + Rational(2, 3))
69
+
70
+ a, b, c = symbols('a b c', commutative=False)
71
+ assert deltaintegrate(DiracDelta(x - y)*f(x - b)*f(x - a), x) == \
72
+ f(y - b)*f(y - a)*Heaviside(x - y)
73
+
74
+ p = f(x - a)*DiracDelta(x - y)*f(x - c)*f(x - b)
75
+ assert deltaintegrate(p, x) == f(y - a)*f(y - c)*f(y - b)*Heaviside(x - y)
76
+
77
+ p = DiracDelta(x - z)*f(x - b)*f(x - a)*DiracDelta(x - y)
78
+ assert deltaintegrate(p, x) == DiracDelta(y - z)*f(y - b)*f(y - a) * \
79
+ Heaviside(x - y)
.venv/lib/python3.13/site-packages/sympy/integrals/tests/test_failing_integrals.py ADDED
@@ -0,0 +1,277 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # A collection of failing integrals from the issues.
2
+
3
+ from sympy.core.numbers import (I, Rational, oo, pi)
4
+ from sympy.core.singleton import S
5
+ from sympy.core.symbol import symbols
6
+ from sympy.functions.elementary.complexes import sign
7
+ from sympy.functions.elementary.exponential import (exp, log)
8
+ from sympy.functions.elementary.hyperbolic import (sech, sinh)
9
+ from sympy.functions.elementary.miscellaneous import sqrt
10
+ from sympy.functions.elementary.piecewise import Piecewise
11
+ from sympy.functions.elementary.trigonometric import (acos, atan, cos, sin, tan)
12
+ from sympy.functions.special.delta_functions import DiracDelta
13
+ from sympy.functions.special.gamma_functions import gamma
14
+ from sympy.integrals.integrals import (Integral, integrate)
15
+ from sympy.simplify.fu import fu
16
+
17
+
18
+ from sympy.testing.pytest import XFAIL, slow, tooslow
19
+
20
+ from sympy.abc import x, k, c, y, b, h, a, m, z, n, t
21
+
22
+
23
+ @tooslow
24
+ @XFAIL
25
+ def test_issue_3880():
26
+ # integrate_hyperexponential(Poly(t*2*(1 - t0**2)*t0*(x**3 + x**2), t), Poly((1 + t0**2)**2*2*(x**2 + x + 1), t), [Poly(1, x), Poly(1 + t0**2, t0), Poly(t, t)], [x, t0, t], [exp, tan])
27
+ assert not integrate(exp(x)*cos(2*x)*sin(2*x) * (x**3 + x**2)/(2*(x**2 + x + 1)), x).has(Integral)
28
+
29
+
30
+ def test_issue_4212_real():
31
+ xr = symbols('xr', real=True)
32
+ negabsx = Piecewise((-xr, xr < 0), (xr, True))
33
+ assert integrate(sign(xr), xr) == negabsx
34
+
35
+
36
+ @XFAIL
37
+ def test_issue_4212():
38
+ # XXX: Maybe this should be expected to fail without real assumptions on x.
39
+ # As a complex function sign(x) is not analytic and so there is no complex
40
+ # function whose complex derivative is sign(x). With real assumptions this
41
+ # works (see test_issue_4212_real above).
42
+ assert not integrate(sign(x), x).has(Integral)
43
+
44
+
45
+ def test_issue_4511():
46
+ # This works, but gives a slightly over-complicated answer.
47
+ f = integrate(cos(x)**2 / (1 - sin(x)), x)
48
+ assert fu(f) == x - cos(x) - 1
49
+ assert f == ((x*tan(x/2)**2 + x - 2)/(tan(x/2)**2 + 1)).expand()
50
+
51
+
52
+ def test_integrate_DiracDelta_no_meijerg():
53
+ assert integrate(integrate(integrate(
54
+ DiracDelta(x - y - z), (z, 0, oo)), (y, 0, 1), meijerg=False), (x, 0, 1)) == S.Half
55
+
56
+
57
+ @XFAIL
58
+ def test_integrate_DiracDelta_fails():
59
+ # issue 6427
60
+ # works without meijerg. See test_integrate_DiracDelta_no_meijerg above.
61
+ assert integrate(integrate(integrate(
62
+ DiracDelta(x - y - z), (z, 0, oo)), (y, 0, 1)), (x, 0, 1)) == S.Half
63
+
64
+
65
+ @XFAIL
66
+ @slow
67
+ def test_issue_4525():
68
+ # Warning: takes a long time
69
+ assert not integrate((x**m * (1 - x)**n * (a + b*x + c*x**2))/(1 + x**2), (x, 0, 1)).has(Integral)
70
+
71
+
72
+ @XFAIL
73
+ @tooslow
74
+ def test_issue_4540():
75
+ # Note, this integral is probably nonelementary
76
+ assert not integrate(
77
+ (sin(1/x) - x*exp(x)) /
78
+ ((-sin(1/x) + x*exp(x))*x + x*sin(1/x)), x).has(Integral)
79
+
80
+
81
+ @XFAIL
82
+ @slow
83
+ def test_issue_4891():
84
+ # Requires the hypergeometric function.
85
+ assert not integrate(cos(x)**y, x).has(Integral)
86
+
87
+
88
+ @XFAIL
89
+ @slow
90
+ def test_issue_1796a():
91
+ assert not integrate(exp(2*b*x)*exp(-a*x**2), x).has(Integral)
92
+
93
+
94
+ @XFAIL
95
+ def test_issue_4895b():
96
+ assert not integrate(exp(2*b*x)*exp(-a*x**2), (x, -oo, 0)).has(Integral)
97
+
98
+
99
+ @XFAIL
100
+ def test_issue_4895c():
101
+ assert not integrate(exp(2*b*x)*exp(-a*x**2), (x, -oo, oo)).has(Integral)
102
+
103
+
104
+ @XFAIL
105
+ def test_issue_4895d():
106
+ assert not integrate(exp(2*b*x)*exp(-a*x**2), (x, 0, oo)).has(Integral)
107
+
108
+
109
+ @XFAIL
110
+ @slow
111
+ def test_issue_4941():
112
+ assert not integrate(sqrt(1 + sinh(x/20)**2), (x, -25, 25)).has(Integral)
113
+
114
+
115
+ @XFAIL
116
+ def test_issue_4992():
117
+ # Nonelementary integral. Requires hypergeometric/Meijer-G handling.
118
+ assert not integrate(log(x) * x**(k - 1) * exp(-x) / gamma(k), (x, 0, oo)).has(Integral)
119
+
120
+
121
+ @XFAIL
122
+ def test_issue_16396a():
123
+ i = integrate(1/(1+sqrt(tan(x))), (x, pi/3, pi/6))
124
+ assert not i.has(Integral)
125
+
126
+
127
+ @XFAIL
128
+ def test_issue_16396b():
129
+ i = integrate(x*sin(x)/(1+cos(x)**2), (x, 0, pi))
130
+ assert not i.has(Integral)
131
+
132
+
133
+ @XFAIL
134
+ def test_issue_16046():
135
+ assert integrate(exp(exp(I*x)), [x, 0, 2*pi]) == 2*pi
136
+
137
+
138
+ @XFAIL
139
+ def test_issue_15925a():
140
+ assert not integrate(sqrt((1+sin(x))**2+(cos(x))**2), (x, -pi/2, pi/2)).has(Integral)
141
+
142
+
143
+ def test_issue_15925b():
144
+ f = sqrt((-12*cos(x)**2*sin(x))**2+(12*cos(x)*sin(x)**2)**2)
145
+ assert integrate(f, (x, 0, pi/6)) == Rational(3, 2)
146
+
147
+
148
+ @XFAIL
149
+ def test_issue_15925b_manual():
150
+ assert not integrate(sqrt((-12*cos(x)**2*sin(x))**2+(12*cos(x)*sin(x)**2)**2),
151
+ (x, 0, pi/6), manual=True).has(Integral)
152
+
153
+
154
+ @XFAIL
155
+ @tooslow
156
+ def test_issue_15227():
157
+ i = integrate(log(1-x)*log((1+x)**2)/x, (x, 0, 1))
158
+ assert not i.has(Integral)
159
+ # assert i == -5*zeta(3)/4
160
+
161
+
162
+ @XFAIL
163
+ @slow
164
+ def test_issue_14716():
165
+ i = integrate(log(x + 5)*cos(pi*x),(x, S.Half, 1))
166
+ assert not i.has(Integral)
167
+ # Mathematica can not solve it either, but
168
+ # integrate(log(x + 5)*cos(pi*x),(x, S.Half, 1)).transform(x, y - 5).doit()
169
+ # works
170
+ # assert i == -log(Rational(11, 2))/pi - Si(pi*Rational(11, 2))/pi + Si(6*pi)/pi
171
+
172
+
173
+ @XFAIL
174
+ def test_issue_14709a():
175
+ i = integrate(x*acos(1 - 2*x/h), (x, 0, h))
176
+ assert not i.has(Integral)
177
+ # assert i == 5*h**2*pi/16
178
+
179
+
180
+ @slow
181
+ @XFAIL
182
+ def test_issue_14398():
183
+ assert not integrate(exp(x**2)*cos(x), x).has(Integral)
184
+
185
+
186
+ @XFAIL
187
+ def test_issue_14074():
188
+ i = integrate(log(sin(x)), (x, 0, pi/2))
189
+ assert not i.has(Integral)
190
+ # assert i == -pi*log(2)/2
191
+
192
+
193
+ @XFAIL
194
+ @slow
195
+ def test_issue_14078b():
196
+ i = integrate((atan(4*x)-atan(2*x))/x, (x, 0, oo))
197
+ assert not i.has(Integral)
198
+ # assert i == pi*log(2)/2
199
+
200
+
201
+ @XFAIL
202
+ def test_issue_13792():
203
+ i = integrate(log(1/x) / (1 - x), (x, 0, 1))
204
+ assert not i.has(Integral)
205
+ # assert i in [polylog(2, -exp_polar(I*pi)), pi**2/6]
206
+
207
+
208
+ @XFAIL
209
+ def test_issue_11845a():
210
+ assert not integrate(exp(y - x**3), (x, 0, 1)).has(Integral)
211
+
212
+
213
+ @XFAIL
214
+ def test_issue_11845b():
215
+ assert not integrate(exp(-y - x**3), (x, 0, 1)).has(Integral)
216
+
217
+
218
+ @XFAIL
219
+ def test_issue_11813():
220
+ assert not integrate((a - x)**Rational(-1, 2)*x, (x, 0, a)).has(Integral)
221
+
222
+
223
+ @XFAIL
224
+ def test_issue_11254c():
225
+ assert not integrate(sech(x)**2, (x, 0, 1)).has(Integral)
226
+
227
+
228
+ @XFAIL
229
+ def test_issue_10584():
230
+ assert not integrate(sqrt(x**2 + 1/x**2), x).has(Integral)
231
+
232
+
233
+ @XFAIL
234
+ def test_issue_9101():
235
+ assert not integrate(log(x + sqrt(x**2 + y**2 + z**2)), z).has(Integral)
236
+
237
+
238
+ @XFAIL
239
+ def test_issue_7147():
240
+ assert not integrate(x/sqrt(a*x**2 + b*x + c)**3, x).has(Integral)
241
+
242
+
243
+ @XFAIL
244
+ def test_issue_7109():
245
+ assert not integrate(sqrt(a**2/(a**2 - x**2)), x).has(Integral)
246
+
247
+
248
+ @XFAIL
249
+ def test_integrate_Piecewise_rational_over_reals():
250
+ f = Piecewise(
251
+ (0, t - 478.515625*pi < 0),
252
+ (13.2075145209219*pi/(0.000871222*t + 0.995)**2, t - 478.515625*pi >= 0))
253
+
254
+ assert abs((integrate(f, (t, 0, oo)) - 15235.9375*pi).evalf()) <= 1e-7
255
+
256
+
257
+ @XFAIL
258
+ def test_issue_4311_slow():
259
+ # Not slow when bypassing heurish
260
+ assert not integrate(x*abs(9-x**2), x).has(Integral)
261
+
262
+ @XFAIL
263
+ def test_issue_20370():
264
+ a = symbols('a', positive=True)
265
+ assert integrate((1 + a * cos(x))**-1, (x, 0, 2 * pi)) == (2 * pi / sqrt(1 - a**2))
266
+
267
+
268
+ @XFAIL
269
+ def test_polylog():
270
+ # log(1/x)*log(x+1)-polylog(2, -x)
271
+ assert not integrate(log(1/x)/(x + 1), x).has(Integral)
272
+
273
+
274
+ @XFAIL
275
+ def test_polylog_manual():
276
+ # Make sure _parts_rule does not go into an infinite loop here
277
+ assert not integrate(log(1/x)/(x + 1), x, manual=True).has(Integral)
.venv/lib/python3.13/site-packages/sympy/integrals/tests/test_heurisch.py ADDED
@@ -0,0 +1,417 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.concrete.summations import Sum
2
+ from sympy.core.add import Add
3
+ from sympy.core.function import (Derivative, Function, diff)
4
+ from sympy.core.numbers import (I, Rational, pi)
5
+ from sympy.core.relational import Eq, Ne
6
+ from sympy.core.symbol import (Symbol, symbols)
7
+ from sympy.functions.elementary.exponential import (LambertW, exp, log)
8
+ from sympy.functions.elementary.hyperbolic import (asinh, cosh, sinh, tanh)
9
+ from sympy.functions.elementary.miscellaneous import sqrt
10
+ from sympy.functions.elementary.piecewise import Piecewise
11
+ from sympy.functions.elementary.trigonometric import (acos, asin, atan, cos, sin, tan)
12
+ from sympy.functions.special.bessel import (besselj, besselk, bessely, jn)
13
+ from sympy.functions.special.error_functions import erf
14
+ from sympy.integrals.integrals import Integral
15
+ from sympy.logic.boolalg import And
16
+ from sympy.matrices import Matrix
17
+ from sympy.simplify.ratsimp import ratsimp
18
+ from sympy.simplify.simplify import simplify
19
+ from sympy.integrals.heurisch import components, heurisch, heurisch_wrapper
20
+ from sympy.testing.pytest import XFAIL, slow
21
+ from sympy.integrals.integrals import integrate
22
+ from sympy import S
23
+
24
+ x, y, z, nu = symbols('x,y,z,nu')
25
+ f = Function('f')
26
+
27
+
28
+ def test_components():
29
+ assert components(x*y, x) == {x}
30
+ assert components(1/(x + y), x) == {x}
31
+ assert components(sin(x), x) == {sin(x), x}
32
+ assert components(sin(x)*sqrt(log(x)), x) == \
33
+ {log(x), sin(x), sqrt(log(x)), x}
34
+ assert components(x*sin(exp(x)*y), x) == \
35
+ {sin(y*exp(x)), x, exp(x)}
36
+ assert components(x**Rational(17, 54)/sqrt(sin(x)), x) == \
37
+ {sin(x), x**Rational(1, 54), sqrt(sin(x)), x}
38
+
39
+ assert components(f(x), x) == \
40
+ {x, f(x)}
41
+ assert components(Derivative(f(x), x), x) == \
42
+ {x, f(x), Derivative(f(x), x)}
43
+ assert components(f(x)*diff(f(x), x), x) == \
44
+ {x, f(x), Derivative(f(x), x), Derivative(f(x), x)}
45
+
46
+
47
+ def test_issue_10680():
48
+ assert isinstance(integrate(x**log(x**log(x**log(x))),x), Integral)
49
+
50
+
51
+ def test_issue_21166():
52
+ assert integrate(sin(x/sqrt(abs(x))), (x, -1, 1)) == 0
53
+
54
+
55
+ def test_heurisch_polynomials():
56
+ assert heurisch(1, x) == x
57
+ assert heurisch(x, x) == x**2/2
58
+ assert heurisch(x**17, x) == x**18/18
59
+ # For coverage
60
+ assert heurisch_wrapper(y, x) == y*x
61
+
62
+
63
+ def test_heurisch_fractions():
64
+ assert heurisch(1/x, x) == log(x)
65
+ assert heurisch(1/(2 + x), x) == log(x + 2)
66
+ assert heurisch(1/(x + sin(y)), x) == log(x + sin(y))
67
+
68
+ # Up to a constant, where C = pi*I*Rational(5, 12), Mathematica gives identical
69
+ # result in the first case. The difference is because SymPy changes
70
+ # signs of expressions without any care.
71
+ # XXX ^ ^ ^ is this still correct?
72
+ assert heurisch(5*x**5/(
73
+ 2*x**6 - 5), x) in [5*log(2*x**6 - 5) / 12, 5*log(-2*x**6 + 5) / 12]
74
+ assert heurisch(5*x**5/(2*x**6 + 5), x) == 5*log(2*x**6 + 5) / 12
75
+
76
+ assert heurisch(1/x**2, x) == -1/x
77
+ assert heurisch(-1/x**5, x) == 1/(4*x**4)
78
+
79
+
80
+ def test_heurisch_log():
81
+ assert heurisch(log(x), x) == x*log(x) - x
82
+ assert heurisch(log(3*x), x) == -x + x*log(3) + x*log(x)
83
+ assert heurisch(log(x**2), x) in [x*log(x**2) - 2*x, 2*x*log(x) - 2*x]
84
+
85
+
86
+ def test_heurisch_exp():
87
+ assert heurisch(exp(x), x) == exp(x)
88
+ assert heurisch(exp(-x), x) == -exp(-x)
89
+ assert heurisch(exp(17*x), x) == exp(17*x) / 17
90
+ assert heurisch(x*exp(x), x) == x*exp(x) - exp(x)
91
+ assert heurisch(x*exp(x**2), x) == exp(x**2) / 2
92
+
93
+ assert heurisch(exp(-x**2), x) is None
94
+
95
+ assert heurisch(2**x, x) == 2**x/log(2)
96
+ assert heurisch(x*2**x, x) == x*2**x/log(2) - 2**x*log(2)**(-2)
97
+
98
+ assert heurisch(Integral(x**z*y, (y, 1, 2), (z, 2, 3)).function, x) == (x*x**z*y)/(z+1)
99
+ assert heurisch(Sum(x**z, (z, 1, 2)).function, z) == x**z/log(x)
100
+
101
+ # https://github.com/sympy/sympy/issues/23707
102
+ anti = -exp(z)/(sqrt(x - y)*exp(z*sqrt(x - y)) - exp(z*sqrt(x - y)))
103
+ assert heurisch(exp(z)*exp(-z*sqrt(x - y)), z) == anti
104
+
105
+
106
+ def test_heurisch_trigonometric():
107
+ assert heurisch(sin(x), x) == -cos(x)
108
+ assert heurisch(pi*sin(x) + 1, x) == x - pi*cos(x)
109
+
110
+ assert heurisch(cos(x), x) == sin(x)
111
+ assert heurisch(tan(x), x) in [
112
+ log(1 + tan(x)**2)/2,
113
+ log(tan(x) + I) + I*x,
114
+ log(tan(x) - I) - I*x,
115
+ ]
116
+
117
+ assert heurisch(sin(x)*sin(y), x) == -cos(x)*sin(y)
118
+ assert heurisch(sin(x)*sin(y), y) == -cos(y)*sin(x)
119
+
120
+ # gives sin(x) in answer when run via setup.py and cos(x) when run via py.test
121
+ assert heurisch(sin(x)*cos(x), x) in [sin(x)**2 / 2, -cos(x)**2 / 2]
122
+ assert heurisch(cos(x)/sin(x), x) == log(sin(x))
123
+
124
+ assert heurisch(x*sin(7*x), x) == sin(7*x) / 49 - x*cos(7*x) / 7
125
+ assert heurisch(1/pi/4 * x**2*cos(x), x) == 1/pi/4*(x**2*sin(x) -
126
+ 2*sin(x) + 2*x*cos(x))
127
+
128
+ assert heurisch(acos(x/4) * asin(x/4), x) == 2*x - (sqrt(16 - x**2))*asin(x/4) \
129
+ + (sqrt(16 - x**2))*acos(x/4) + x*asin(x/4)*acos(x/4)
130
+
131
+ assert heurisch(sin(x)/(cos(x)**2+1), x) == -atan(cos(x)) #fixes issue 13723
132
+ assert heurisch(1/(cos(x)+2), x) == 2*sqrt(3)*atan(sqrt(3)*tan(x/2)/3)/3
133
+ assert heurisch(2*sin(x)*cos(x)/(sin(x)**4 + 1), x) == atan(sqrt(2)*sin(x)
134
+ - 1) - atan(sqrt(2)*sin(x) + 1)
135
+
136
+ assert heurisch(1/cosh(x), x) == 2*atan(tanh(x/2))
137
+
138
+
139
+ def test_heurisch_hyperbolic():
140
+ assert heurisch(sinh(x), x) == cosh(x)
141
+ assert heurisch(cosh(x), x) == sinh(x)
142
+
143
+ assert heurisch(x*sinh(x), x) == x*cosh(x) - sinh(x)
144
+ assert heurisch(x*cosh(x), x) == x*sinh(x) - cosh(x)
145
+
146
+ assert heurisch(
147
+ x*asinh(x/2), x) == x**2*asinh(x/2)/2 + asinh(x/2) - x*sqrt(4 + x**2)/4
148
+
149
+
150
+ def test_heurisch_mixed():
151
+ assert heurisch(sin(x)*exp(x), x) == exp(x)*sin(x)/2 - exp(x)*cos(x)/2
152
+ assert heurisch(sin(x/sqrt(-x)), x) == 2*x*cos(x/sqrt(-x))/sqrt(-x) - 2*sin(x/sqrt(-x))
153
+
154
+
155
+ def test_heurisch_radicals():
156
+ assert heurisch(1/sqrt(x), x) == 2*sqrt(x)
157
+ assert heurisch(1/sqrt(x)**3, x) == -2/sqrt(x)
158
+ assert heurisch(sqrt(x)**3, x) == 2*sqrt(x)**5/5
159
+
160
+ assert heurisch(sin(x)*sqrt(cos(x)), x) == -2*sqrt(cos(x))**3/3
161
+ y = Symbol('y')
162
+ assert heurisch(sin(y*sqrt(x)), x) == 2/y**2*sin(y*sqrt(x)) - \
163
+ 2*sqrt(x)*cos(y*sqrt(x))/y
164
+ assert heurisch_wrapper(sin(y*sqrt(x)), x) == Piecewise(
165
+ (-2*sqrt(x)*cos(sqrt(x)*y)/y + 2*sin(sqrt(x)*y)/y**2, Ne(y, 0)),
166
+ (0, True))
167
+ y = Symbol('y', positive=True)
168
+ assert heurisch_wrapper(sin(y*sqrt(x)), x) == 2/y**2*sin(y*sqrt(x)) - \
169
+ 2*sqrt(x)*cos(y*sqrt(x))/y
170
+
171
+
172
+ def test_heurisch_special():
173
+ assert heurisch(erf(x), x) == x*erf(x) + exp(-x**2)/sqrt(pi)
174
+ assert heurisch(exp(-x**2)*erf(x), x) == sqrt(pi)*erf(x)**2 / 4
175
+
176
+
177
+ def test_heurisch_symbolic_coeffs():
178
+ assert heurisch(1/(x + y), x) == log(x + y)
179
+ assert heurisch(1/(x + sqrt(2)), x) == log(x + sqrt(2))
180
+ assert simplify(diff(heurisch(log(x + y + z), y), y)) == log(x + y + z)
181
+
182
+
183
+ def test_heurisch_symbolic_coeffs_1130():
184
+ y = Symbol('y')
185
+ assert heurisch_wrapper(1/(x**2 + y), x) == Piecewise(
186
+ (log(x - sqrt(-y))/(2*sqrt(-y)) - log(x + sqrt(-y))/(2*sqrt(-y)),
187
+ Ne(y, 0)), (-1/x, True))
188
+ y = Symbol('y', positive=True)
189
+ assert heurisch_wrapper(1/(x**2 + y), x) == (atan(x/sqrt(y))/sqrt(y))
190
+
191
+
192
+ def test_heurisch_hacking():
193
+ assert heurisch(sqrt(1 + 7*x**2), x, hints=[]) == \
194
+ x*sqrt(1 + 7*x**2)/2 + sqrt(7)*asinh(sqrt(7)*x)/14
195
+ assert heurisch(sqrt(1 - 7*x**2), x, hints=[]) == \
196
+ x*sqrt(1 - 7*x**2)/2 + sqrt(7)*asin(sqrt(7)*x)/14
197
+
198
+ assert heurisch(1/sqrt(1 + 7*x**2), x, hints=[]) == \
199
+ sqrt(7)*asinh(sqrt(7)*x)/7
200
+ assert heurisch(1/sqrt(1 - 7*x**2), x, hints=[]) == \
201
+ sqrt(7)*asin(sqrt(7)*x)/7
202
+
203
+ assert heurisch(exp(-7*x**2), x, hints=[]) == \
204
+ sqrt(7*pi)*erf(sqrt(7)*x)/14
205
+
206
+ assert heurisch(1/sqrt(9 - 4*x**2), x, hints=[]) == \
207
+ asin(x*Rational(2, 3))/2
208
+
209
+ assert heurisch(1/sqrt(9 + 4*x**2), x, hints=[]) == \
210
+ asinh(x*Rational(2, 3))/2
211
+
212
+ assert heurisch(1/sqrt(3*x**2-4), x, hints=[]) == \
213
+ sqrt(3)*log(3*x + sqrt(3)*sqrt(3*x**2 - 4))/3
214
+
215
+
216
+ def test_heurisch_function():
217
+ assert heurisch(f(x), x) is None
218
+
219
+ @XFAIL
220
+ def test_heurisch_function_derivative():
221
+ # TODO: it looks like this used to work just by coincindence and
222
+ # thanks to sloppy implementation. Investigate why this used to
223
+ # work at all and if support for this can be restored.
224
+
225
+ df = diff(f(x), x)
226
+
227
+ assert heurisch(f(x)*df, x) == f(x)**2/2
228
+ assert heurisch(f(x)**2*df, x) == f(x)**3/3
229
+ assert heurisch(df/f(x), x) == log(f(x))
230
+
231
+
232
+ def test_heurisch_wrapper():
233
+ f = 1/(y + x)
234
+ assert heurisch_wrapper(f, x) == log(x + y)
235
+ f = 1/(y - x)
236
+ assert heurisch_wrapper(f, x) == -log(x - y)
237
+ f = 1/((y - x)*(y + x))
238
+ assert heurisch_wrapper(f, x) == Piecewise(
239
+ (-log(x - y)/(2*y) + log(x + y)/(2*y), Ne(y, 0)), (1/x, True))
240
+ # issue 6926
241
+ f = sqrt(x**2/((y - x)*(y + x)))
242
+ assert heurisch_wrapper(f, x) == x*sqrt(-x**2/(x**2 - y**2)) \
243
+ - y**2*sqrt(-x**2/(x**2 - y**2))/x
244
+
245
+
246
+ def test_issue_3609():
247
+ assert heurisch(1/(x * (1 + log(x)**2)), x) == atan(log(x))
248
+
249
+ ### These are examples from the Poor Man's Integrator
250
+ ### http://www-sop.inria.fr/cafe/Manuel.Bronstein/pmint/examples/
251
+
252
+
253
+ def test_pmint_rat():
254
+ # TODO: heurisch() is off by a constant: -3/4. Possibly different permutation
255
+ # would give the optimal result?
256
+
257
+ def drop_const(expr, x):
258
+ if expr.is_Add:
259
+ return Add(*[ arg for arg in expr.args if arg.has(x) ])
260
+ else:
261
+ return expr
262
+
263
+ f = (x**7 - 24*x**4 - 4*x**2 + 8*x - 8)/(x**8 + 6*x**6 + 12*x**4 + 8*x**2)
264
+ g = (4 + 8*x**2 + 6*x + 3*x**3)/(x**5 + 4*x**3 + 4*x) + log(x)
265
+
266
+ assert drop_const(ratsimp(heurisch(f, x)), x) == g
267
+
268
+
269
+ def test_pmint_trig():
270
+ f = (x - tan(x)) / tan(x)**2 + tan(x)
271
+ g = -x**2/2 - x/tan(x) + log(tan(x)**2 + 1)/2
272
+
273
+ assert heurisch(f, x) == g
274
+
275
+
276
+ def test_pmint_logexp():
277
+ f = (1 + x + x*exp(x))*(x + log(x) + exp(x) - 1)/(x + log(x) + exp(x))**2/x
278
+ g = log(x + exp(x) + log(x)) + 1/(x + exp(x) + log(x))
279
+
280
+ assert ratsimp(heurisch(f, x)) == g
281
+
282
+
283
+ def test_pmint_erf():
284
+ f = exp(-x**2)*erf(x)/(erf(x)**3 - erf(x)**2 - erf(x) + 1)
285
+ g = sqrt(pi)*log(erf(x) - 1)/8 - sqrt(pi)*log(erf(x) + 1)/8 - sqrt(pi)/(4*erf(x) - 4)
286
+
287
+ assert ratsimp(heurisch(f, x)) == g
288
+
289
+
290
+ def test_pmint_LambertW():
291
+ f = LambertW(x)
292
+ g = x*LambertW(x) - x + x/LambertW(x)
293
+
294
+ assert heurisch(f, x) == g
295
+
296
+
297
+ def test_pmint_besselj():
298
+ f = besselj(nu + 1, x)/besselj(nu, x)
299
+ g = nu*log(x) - log(besselj(nu, x))
300
+
301
+ assert heurisch(f, x) == g
302
+
303
+ f = (nu*besselj(nu, x) - x*besselj(nu + 1, x))/x
304
+ g = besselj(nu, x)
305
+
306
+ assert heurisch(f, x) == g
307
+
308
+ f = jn(nu + 1, x)/jn(nu, x)
309
+ g = nu*log(x) - log(jn(nu, x))
310
+
311
+ assert heurisch(f, x) == g
312
+
313
+
314
+ @slow
315
+ def test_pmint_bessel_products():
316
+ f = x*besselj(nu, x)*bessely(nu, 2*x)
317
+ g = -2*x*besselj(nu, x)*bessely(nu - 1, 2*x)/3 + x*besselj(nu - 1, x)*bessely(nu, 2*x)/3
318
+
319
+ assert heurisch(f, x) == g
320
+
321
+ f = x*besselj(nu, x)*besselk(nu, 2*x)
322
+ g = -2*x*besselj(nu, x)*besselk(nu - 1, 2*x)/5 - x*besselj(nu - 1, x)*besselk(nu, 2*x)/5
323
+
324
+ assert heurisch(f, x) == g
325
+
326
+
327
+ def test_pmint_WrightOmega():
328
+ def omega(x):
329
+ return LambertW(exp(x))
330
+
331
+ f = (1 + omega(x) * (2 + cos(omega(x)) * (x + omega(x))))/(1 + omega(x))/(x + omega(x))
332
+ g = log(x + LambertW(exp(x))) + sin(LambertW(exp(x)))
333
+
334
+ assert heurisch(f, x) == g
335
+
336
+
337
+ def test_RR():
338
+ # Make sure the algorithm does the right thing if the ring is RR. See
339
+ # issue 8685.
340
+ assert heurisch(sqrt(1 + 0.25*x**2), x, hints=[]) == \
341
+ 0.5*x*sqrt(0.25*x**2 + 1) + 1.0*asinh(0.5*x)
342
+
343
+ # TODO: convert the rest of PMINT tests:
344
+ # Airy functions
345
+ # f = (x - AiryAi(x)*AiryAi(1, x)) / (x**2 - AiryAi(x)**2)
346
+ # g = Rational(1,2)*ln(x + AiryAi(x)) + Rational(1,2)*ln(x - AiryAi(x))
347
+ # f = x**2 * AiryAi(x)
348
+ # g = -AiryAi(x) + AiryAi(1, x)*x
349
+ # Whittaker functions
350
+ # f = WhittakerW(mu + 1, nu, x) / (WhittakerW(mu, nu, x) * x)
351
+ # g = x/2 - mu*ln(x) - ln(WhittakerW(mu, nu, x))
352
+
353
+
354
+ def test_issue_22527():
355
+ t, R = symbols(r't R')
356
+ z = Function('z')(t)
357
+ def f(x):
358
+ return x/sqrt(R**2 - x**2)
359
+ Uz = integrate(f(z), z)
360
+ Ut = integrate(f(t), t)
361
+ assert Ut == Uz.subs(z, t)
362
+
363
+
364
+ def test_heurisch_complex_erf_issue_26338():
365
+ r = symbols('r', real=True)
366
+ a = sqrt(pi)*erf((1 + I)/2)/2
367
+ assert integrate(exp(-I*r**2/2), (r, 0, 1)) == a - I*a
368
+
369
+ a = exp(-x**2/(2*(2 - I)**2))
370
+ assert heurisch(a, x, hints=[]) is None # None, not a wrong soln
371
+ a = exp(-r**2/(2*(2 - I)**2))
372
+ assert heurisch(a, r, hints=[]) is None
373
+ a = sqrt(pi)*erf((1 + I)/2)/2
374
+ assert integrate(exp(-I*x**2/2), (x, 0, 1)) == a - I*a
375
+
376
+
377
+ def test_issue_15498():
378
+ Z0 = Function('Z0')
379
+ k01, k10, t, s= symbols('k01 k10 t s', real=True, positive=True)
380
+ m = Matrix([[exp(-k10*t)]])
381
+ _83 = Rational(83, 100) # 0.83 works, too
382
+ [a, b, c, d, e, f, g] = [100, 0.5, _83, 50, 0.6, 2, 120]
383
+ AIF_btf = a*(d*e*(1 - exp(-(t - b)/e)) + f*g*(1 - exp(-(t - b)/g)))
384
+ AIF_atf = a*(d*e*exp(-(t - b)/e)*(exp((c - b)/e) - 1
385
+ ) + f*g*exp(-(t - b)/g)*(exp((c - b)/g) - 1))
386
+ AIF_sym = Piecewise((0, t < b), (AIF_btf, And(b <= t, t < c)), (AIF_atf, c <= t))
387
+ aif_eq = Eq(Z0(t), AIF_sym)
388
+ f_vec = Matrix([[k01*Z0(t)]])
389
+ integrand = m*m.subs(t, s)**-1*f_vec.subs(aif_eq.lhs, aif_eq.rhs).subs(t, s)
390
+ solution = integrate(integrand[0], (s, 0, t))
391
+ assert solution is not None # does not hang and takes less than 10 s
392
+
393
+
394
+ @slow
395
+ def test_heurisch_issue_26930():
396
+ integrand = x**Rational(4, 3)*log(x)
397
+ anti = 3*x**(S(7)/3)*log(x)/7 - 9*x**(S(7)/3)/49
398
+ assert heurisch(integrand, x) == anti
399
+ assert integrate(integrand, x) == anti
400
+ assert integrate(integrand, (x, 0, 1)) == -S(9)/49
401
+
402
+
403
+ def test_heurisch_issue_26922():
404
+
405
+ a, b, x = symbols("a, b, x", real=True, positive=True)
406
+ C = symbols("C", real=True)
407
+ i1 = -C*x*exp(-a*x**2 - sqrt(b)*x)
408
+ i2 = C*x*exp(-a*x**2 + sqrt(b)*x)
409
+ i = Integral(i1, x) + Integral(i2, x)
410
+ res = (
411
+ -C*exp(-a*x**2)*exp(sqrt(b)*x)/(2*a)
412
+ + C*exp(-a*x**2)*exp(-sqrt(b)*x)/(2*a)
413
+ + sqrt(pi)*C*sqrt(b)*exp(b/(4*a))*erf(sqrt(a)*x - sqrt(b)/(2*sqrt(a)))/(4*a**(S(3)/2))
414
+ + sqrt(pi)*C*sqrt(b)*exp(b/(4*a))*erf(sqrt(a)*x + sqrt(b)/(2*sqrt(a)))/(4*a**(S(3)/2))
415
+ )
416
+
417
+ assert i.doit(heurisch=False).expand() == res
.venv/lib/python3.13/site-packages/sympy/integrals/tests/test_integrals.py ADDED
@@ -0,0 +1,2187 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+ from sympy.concrete.summations import (Sum, summation)
3
+ from sympy.core.add import Add
4
+ from sympy.core.containers import Tuple
5
+ from sympy.core.expr import Expr
6
+ from sympy.core.function import (Derivative, Function, Lambda, diff)
7
+ from sympy.core import EulerGamma
8
+ from sympy.core.numbers import (E, I, Rational, nan, oo, pi, zoo, all_close)
9
+ from sympy.core.relational import (Eq, Ne)
10
+ from sympy.core.singleton import S
11
+ from sympy.core.symbol import (Symbol, symbols)
12
+ from sympy.core.sympify import sympify
13
+ from sympy.functions.elementary.complexes import (Abs, im, polar_lift, re, sign)
14
+ from sympy.functions.elementary.exponential import (LambertW, exp, exp_polar, log)
15
+ from sympy.functions.elementary.hyperbolic import (acosh, asinh, cosh, coth, csch, sinh, tanh, sech)
16
+ from sympy.functions.elementary.miscellaneous import (Max, Min, sqrt)
17
+ from sympy.functions.elementary.piecewise import Piecewise
18
+ from sympy.functions.elementary.trigonometric import (acos, asin, atan, cos, sin, sinc, tan, sec)
19
+ from sympy.functions.special.delta_functions import DiracDelta, Heaviside
20
+ from sympy.functions.special.error_functions import (Ci, Ei, Si, erf, erfc, erfi, fresnelc, li)
21
+ from sympy.functions.special.gamma_functions import (gamma, polygamma)
22
+ from sympy.functions.special.hyper import (hyper, meijerg)
23
+ from sympy.functions.special.singularity_functions import SingularityFunction
24
+ from sympy.functions.special.zeta_functions import lerchphi
25
+ from sympy.integrals.integrals import integrate
26
+ from sympy.logic.boolalg import And
27
+ from sympy.matrices.dense import Matrix
28
+ from sympy.polys.polytools import (Poly, factor)
29
+ from sympy.printing.str import sstr
30
+ from sympy.series.order import O
31
+ from sympy.sets.sets import Interval
32
+ from sympy.simplify.gammasimp import gammasimp
33
+ from sympy.simplify.simplify import simplify
34
+ from sympy.simplify.trigsimp import trigsimp
35
+ from sympy.tensor.indexed import (Idx, IndexedBase)
36
+ from sympy.core.expr import unchanged
37
+ from sympy.functions.elementary.integers import floor
38
+ from sympy.integrals.integrals import Integral
39
+ from sympy.integrals.risch import NonElementaryIntegral
40
+ from sympy.physics import units
41
+ from sympy.testing.pytest import raises, slow, warns_deprecated_sympy, warns
42
+ from sympy.utilities.exceptions import SymPyDeprecationWarning
43
+ from sympy.core.random import verify_numerically
44
+
45
+
46
+ x, y, z, a, b, c, d, e, s, t, x_1, x_2 = symbols('x y z a b c d e s t x_1 x_2')
47
+ n = Symbol('n', integer=True)
48
+ f = Function('f')
49
+
50
+
51
+ def NS(e, n=15, **options):
52
+ return sstr(sympify(e).evalf(n, **options), full_prec=True)
53
+
54
+
55
+ def test_poly_deprecated():
56
+ p = Poly(2*x, x)
57
+ assert p.integrate(x) == Poly(x**2, x, domain='QQ')
58
+ # The stacklevel is based on Integral(Poly)
59
+ with warns(SymPyDeprecationWarning, test_stacklevel=False):
60
+ integrate(p, x)
61
+ with warns(SymPyDeprecationWarning, test_stacklevel=False):
62
+ Integral(p, (x,))
63
+
64
+
65
+ @slow
66
+ def test_principal_value():
67
+ g = 1 / x
68
+ assert Integral(g, (x, -oo, oo)).principal_value() == 0
69
+ assert Integral(g, (y, -oo, oo)).principal_value() == oo * sign(1 / x)
70
+ raises(ValueError, lambda: Integral(g, (x)).principal_value())
71
+ raises(ValueError, lambda: Integral(g).principal_value())
72
+
73
+ l = 1 / ((x ** 3) - 1)
74
+ assert Integral(l, (x, -oo, oo)).principal_value().together() == -sqrt(3)*pi/3
75
+ raises(ValueError, lambda: Integral(l, (x, -oo, 1)).principal_value())
76
+
77
+ d = 1 / (x ** 2 - 1)
78
+ assert Integral(d, (x, -oo, oo)).principal_value() == 0
79
+ assert Integral(d, (x, -2, 2)).principal_value() == -log(3)
80
+
81
+ v = x / (x ** 2 - 1)
82
+ assert Integral(v, (x, -oo, oo)).principal_value() == 0
83
+ assert Integral(v, (x, -2, 2)).principal_value() == 0
84
+
85
+ s = x ** 2 / (x ** 2 - 1)
86
+ assert Integral(s, (x, -oo, oo)).principal_value() is oo
87
+ assert Integral(s, (x, -2, 2)).principal_value() == -log(3) + 4
88
+
89
+ f = 1 / ((x ** 2 - 1) * (1 + x ** 2))
90
+ assert Integral(f, (x, -oo, oo)).principal_value() == -pi / 2
91
+ assert Integral(f, (x, -2, 2)).principal_value() == -atan(2) - log(3) / 2
92
+
93
+
94
+ def diff_test(i):
95
+ """Return the set of symbols, s, which were used in testing that
96
+ i.diff(s) agrees with i.doit().diff(s). If there is an error then
97
+ the assertion will fail, causing the test to fail."""
98
+ syms = i.free_symbols
99
+ for s in syms:
100
+ assert (i.diff(s).doit() - i.doit().diff(s)).expand() == 0
101
+ return syms
102
+
103
+
104
+ def test_improper_integral():
105
+ assert integrate(log(x), (x, 0, 1)) == -1
106
+ assert integrate(x**(-2), (x, 1, oo)) == 1
107
+ assert integrate(1/(1 + exp(x)), (x, 0, oo)) == log(2)
108
+
109
+
110
+ def test_constructor():
111
+ # this is shared by Sum, so testing Integral's constructor
112
+ # is equivalent to testing Sum's
113
+ s1 = Integral(n, n)
114
+ assert s1.limits == (Tuple(n),)
115
+ s2 = Integral(n, (n,))
116
+ assert s2.limits == (Tuple(n),)
117
+ s3 = Integral(Sum(x, (x, 1, y)))
118
+ assert s3.limits == (Tuple(y),)
119
+ s4 = Integral(n, Tuple(n,))
120
+ assert s4.limits == (Tuple(n),)
121
+
122
+ s5 = Integral(n, (n, Interval(1, 2)))
123
+ assert s5.limits == (Tuple(n, 1, 2),)
124
+
125
+ # Testing constructor with inequalities:
126
+ s6 = Integral(n, n > 10)
127
+ assert s6.limits == (Tuple(n, 10, oo),)
128
+ s7 = Integral(n, (n > 2) & (n < 5))
129
+ assert s7.limits == (Tuple(n, 2, 5),)
130
+
131
+
132
+ def test_basics():
133
+
134
+ assert Integral(0, x) != 0
135
+ assert Integral(x, (x, 1, 1)) != 0
136
+ assert Integral(oo, x) != oo
137
+ assert Integral(S.NaN, x) is S.NaN
138
+
139
+ assert diff(Integral(y, y), x) == 0
140
+ assert diff(Integral(x, (x, 0, 1)), x) == 0
141
+ assert diff(Integral(x, x), x) == x
142
+ assert diff(Integral(t, (t, 0, x)), x) == x
143
+
144
+ e = (t + 1)**2
145
+ assert diff(integrate(e, (t, 0, x)), x) == \
146
+ diff(Integral(e, (t, 0, x)), x).doit().expand() == \
147
+ ((1 + x)**2).expand()
148
+ assert diff(integrate(e, (t, 0, x)), t) == \
149
+ diff(Integral(e, (t, 0, x)), t) == 0
150
+ assert diff(integrate(e, (t, 0, x)), a) == \
151
+ diff(Integral(e, (t, 0, x)), a) == 0
152
+ assert diff(integrate(e, t), a) == diff(Integral(e, t), a) == 0
153
+
154
+ assert integrate(e, (t, a, x)).diff(x) == \
155
+ Integral(e, (t, a, x)).diff(x).doit().expand()
156
+ assert Integral(e, (t, a, x)).diff(x).doit() == ((1 + x)**2)
157
+ assert integrate(e, (t, x, a)).diff(x).doit() == (-(1 + x)**2).expand()
158
+
159
+ assert integrate(t**2, (t, x, 2*x)).diff(x) == 7*x**2
160
+
161
+ assert Integral(x, x).atoms() == {x}
162
+ assert Integral(f(x), (x, 0, 1)).atoms() == {S.Zero, S.One, x}
163
+
164
+ assert diff_test(Integral(x, (x, 3*y))) == {y}
165
+ assert diff_test(Integral(x, (a, 3*y))) == {x, y}
166
+
167
+ assert integrate(x, (x, oo, oo)) == 0 #issue 8171
168
+ assert integrate(x, (x, -oo, -oo)) == 0
169
+
170
+ # sum integral of terms
171
+ assert integrate(y + x + exp(x), x) == x*y + x**2/2 + exp(x)
172
+
173
+ assert Integral(x).is_commutative
174
+ n = Symbol('n', commutative=False)
175
+ assert Integral(n + x, x).is_commutative is False
176
+
177
+
178
+ def test_diff_wrt():
179
+ class Test(Expr):
180
+ _diff_wrt = True
181
+ is_commutative = True
182
+
183
+ t = Test()
184
+ assert integrate(t + 1, t) == t**2/2 + t
185
+ assert integrate(t + 1, (t, 0, 1)) == Rational(3, 2)
186
+
187
+ raises(ValueError, lambda: integrate(x + 1, x + 1))
188
+ raises(ValueError, lambda: integrate(x + 1, (x + 1, 0, 1)))
189
+
190
+
191
+ def test_basics_multiple():
192
+ assert diff_test(Integral(x, (x, 3*x, 5*y), (y, x, 2*x))) == {x}
193
+ assert diff_test(Integral(x, (x, 5*y), (y, x, 2*x))) == {x}
194
+ assert diff_test(Integral(x, (x, 5*y), (y, y, 2*x))) == {x, y}
195
+ assert diff_test(Integral(y, y, x)) == {x, y}
196
+ assert diff_test(Integral(y*x, x, y)) == {x, y}
197
+ assert diff_test(Integral(x + y, y, (y, 1, x))) == {x}
198
+ assert diff_test(Integral(x + y, (x, x, y), (y, y, x))) == {x, y}
199
+
200
+
201
+ def test_conjugate_transpose():
202
+ A, B = symbols("A B", commutative=False)
203
+
204
+ x = Symbol("x", complex=True)
205
+ p = Integral(A*B, (x,))
206
+ assert p.adjoint().doit() == p.doit().adjoint()
207
+ assert p.conjugate().doit() == p.doit().conjugate()
208
+ assert p.transpose().doit() == p.doit().transpose()
209
+
210
+ x = Symbol("x", real=True)
211
+ p = Integral(A*B, (x,))
212
+ assert p.adjoint().doit() == p.doit().adjoint()
213
+ assert p.conjugate().doit() == p.doit().conjugate()
214
+ assert p.transpose().doit() == p.doit().transpose()
215
+
216
+
217
+ def test_integration():
218
+ assert integrate(0, (t, 0, x)) == 0
219
+ assert integrate(3, (t, 0, x)) == 3*x
220
+ assert integrate(t, (t, 0, x)) == x**2/2
221
+ assert integrate(3*t, (t, 0, x)) == 3*x**2/2
222
+ assert integrate(3*t**2, (t, 0, x)) == x**3
223
+ assert integrate(1/t, (t, 1, x)) == log(x)
224
+ assert integrate(-1/t**2, (t, 1, x)) == 1/x - 1
225
+ assert integrate(t**2 + 5*t - 8, (t, 0, x)) == x**3/3 + 5*x**2/2 - 8*x
226
+ assert integrate(x**2, x) == x**3/3
227
+ assert integrate((3*t*x)**5, x) == (3*t)**5 * x**6 / 6
228
+
229
+ b = Symbol("b")
230
+ c = Symbol("c")
231
+ assert integrate(a*t, (t, 0, x)) == a*x**2/2
232
+ assert integrate(a*t**4, (t, 0, x)) == a*x**5/5
233
+ assert integrate(a*t**2 + b*t + c, (t, 0, x)) == a*x**3/3 + b*x**2/2 + c*x
234
+
235
+
236
+ def test_multiple_integration():
237
+ assert integrate((x**2)*(y**2), (x, 0, 1), (y, -1, 2)) == Rational(1)
238
+ assert integrate((y**2)*(x**2), x, y) == Rational(1, 9)*(x**3)*(y**3)
239
+ assert integrate(1/(x + 3)/(1 + x)**3, x) == \
240
+ log(3 + x)*Rational(-1, 8) + log(1 + x)*Rational(1, 8) + x/(4 + 8*x + 4*x**2)
241
+ assert integrate(sin(x*y)*y, (x, 0, 1), (y, 0, 1)) == -sin(1) + 1
242
+
243
+
244
+ def test_issue_3532():
245
+ assert integrate(exp(-x), (x, 0, oo)) == 1
246
+
247
+
248
+ def test_issue_3560():
249
+ assert integrate(sqrt(x)**3, x) == 2*sqrt(x)**5/5
250
+ assert integrate(sqrt(x), x) == 2*sqrt(x)**3/3
251
+ assert integrate(1/sqrt(x)**3, x) == -2/sqrt(x)
252
+
253
+
254
+ def test_issue_18038():
255
+ raises(AttributeError, lambda: integrate((x, x)))
256
+
257
+
258
+ def test_integrate_poly():
259
+ p = Poly(x + x**2*y + y**3, x, y)
260
+
261
+ # The stacklevel is based on Integral(Poly)
262
+ with warns_deprecated_sympy():
263
+ qx = Integral(p, x)
264
+ with warns(SymPyDeprecationWarning, test_stacklevel=False):
265
+ qx = integrate(p, x)
266
+ with warns(SymPyDeprecationWarning, test_stacklevel=False):
267
+ qy = integrate(p, y)
268
+
269
+ assert isinstance(qx, Poly) is True
270
+ assert isinstance(qy, Poly) is True
271
+
272
+ assert qx.gens == (x, y)
273
+ assert qy.gens == (x, y)
274
+
275
+ assert qx.as_expr() == x**2/2 + x**3*y/3 + x*y**3
276
+ assert qy.as_expr() == x*y + x**2*y**2/2 + y**4/4
277
+
278
+
279
+ def test_integrate_poly_definite():
280
+ p = Poly(x + x**2*y + y**3, x, y)
281
+
282
+ with warns_deprecated_sympy():
283
+ Qx = Integral(p, (x, 0, 1))
284
+ with warns(SymPyDeprecationWarning, test_stacklevel=False):
285
+ Qx = integrate(p, (x, 0, 1))
286
+ with warns(SymPyDeprecationWarning, test_stacklevel=False):
287
+ Qy = integrate(p, (y, 0, pi))
288
+
289
+ assert isinstance(Qx, Poly) is True
290
+ assert isinstance(Qy, Poly) is True
291
+
292
+ assert Qx.gens == (y,)
293
+ assert Qy.gens == (x,)
294
+
295
+ assert Qx.as_expr() == S.Half + y/3 + y**3
296
+ assert Qy.as_expr() == pi**4/4 + pi*x + pi**2*x**2/2
297
+
298
+
299
+ def test_integrate_omit_var():
300
+ y = Symbol('y')
301
+
302
+ assert integrate(x) == x**2/2
303
+
304
+ raises(ValueError, lambda: integrate(2))
305
+ raises(ValueError, lambda: integrate(x*y))
306
+
307
+
308
+ def test_integrate_poly_accurately():
309
+ y = Symbol('y')
310
+ assert integrate(x*sin(y), x) == x**2*sin(y)/2
311
+
312
+ # when passed to risch_norman, this will be a CPU hog, so this really
313
+ # checks, that integrated function is recognized as polynomial
314
+ assert integrate(x**1000*sin(y), x) == x**1001*sin(y)/1001
315
+
316
+
317
+ def test_issue_3635():
318
+ y = Symbol('y')
319
+ assert integrate(x**2, y) == x**2*y
320
+ assert integrate(x**2, (y, -1, 1)) == 2*x**2
321
+
322
+ # works in SymPy and py.test but hangs in `setup.py test`
323
+
324
+
325
+ def test_integrate_linearterm_pow():
326
+ # check integrate((a*x+b)^c, x) -- issue 3499
327
+ y = Symbol('y', positive=True)
328
+ # TODO: Remove conds='none' below, let the assumption take care of it.
329
+ assert integrate(x**y, x, conds='none') == x**(y + 1)/(y + 1)
330
+ assert integrate((exp(y)*x + 1/y)**(1 + sin(y)), x, conds='none') == \
331
+ exp(-y)*(exp(y)*x + 1/y)**(2 + sin(y)) / (2 + sin(y))
332
+
333
+
334
+ def test_issue_3618():
335
+ assert integrate(pi*sqrt(x), x) == 2*pi*sqrt(x)**3/3
336
+ assert integrate(pi*sqrt(x) + E*sqrt(x)**3, x) == \
337
+ 2*pi*sqrt(x)**3/3 + 2*E *sqrt(x)**5/5
338
+
339
+
340
+ def test_issue_3623():
341
+ assert integrate(cos((n + 1)*x), x) == Piecewise(
342
+ (sin(x*(n + 1))/(n + 1), Ne(n + 1, 0)), (x, True))
343
+ assert integrate(cos((n - 1)*x), x) == Piecewise(
344
+ (sin(x*(n - 1))/(n - 1), Ne(n - 1, 0)), (x, True))
345
+ assert integrate(cos((n + 1)*x) + cos((n - 1)*x), x) == \
346
+ Piecewise((sin(x*(n - 1))/(n - 1), Ne(n - 1, 0)), (x, True)) + \
347
+ Piecewise((sin(x*(n + 1))/(n + 1), Ne(n + 1, 0)), (x, True))
348
+
349
+
350
+ def test_issue_3664():
351
+ n = Symbol('n', integer=True, nonzero=True)
352
+ assert integrate(-1./2 * x * sin(n * pi * x/2), [x, -2, 0]) == \
353
+ 2.0*cos(pi*n)/(pi*n)
354
+ assert integrate(x * sin(n * pi * x/2) * Rational(-1, 2), [x, -2, 0]) == \
355
+ 2*cos(pi*n)/(pi*n)
356
+
357
+
358
+ def test_issue_3679():
359
+ # definite integration of rational functions gives wrong answers
360
+ assert NS(Integral(1/(x**2 - 8*x + 17), (x, 2, 4))) == '1.10714871779409'
361
+
362
+
363
+ def test_issue_3686(): # remove this when fresnel integrals are implemented
364
+ from sympy.core.function import expand_func
365
+ from sympy.functions.special.error_functions import fresnels
366
+ assert expand_func(integrate(sin(x**2), x)) == \
367
+ sqrt(2)*sqrt(pi)*fresnels(sqrt(2)*x/sqrt(pi))/2
368
+
369
+
370
+ def test_integrate_units():
371
+ m = units.m
372
+ s = units.s
373
+ assert integrate(x * m/s, (x, 1*s, 5*s)) == 12*m*s
374
+
375
+
376
+ def test_transcendental_functions():
377
+ assert integrate(LambertW(2*x), x) == \
378
+ -x + x*LambertW(2*x) + x/LambertW(2*x)
379
+
380
+
381
+ def test_log_polylog():
382
+ assert integrate(log(1 - x)/x, (x, 0, 1)) == -pi**2/6
383
+ assert integrate(log(x)*(1 - x)**(-1), (x, 0, 1)) == -pi**2/6
384
+
385
+
386
+ def test_issue_3740():
387
+ f = 4*log(x) - 2*log(x)**2
388
+ fid = diff(integrate(f, x), x)
389
+ assert abs(f.subs(x, 42).evalf() - fid.subs(x, 42).evalf()) < 1e-10
390
+
391
+
392
+ def test_issue_3788():
393
+ assert integrate(1/(1 + x**2), x) == atan(x)
394
+
395
+
396
+ def test_issue_3952():
397
+ f = sin(x)
398
+ assert integrate(f, x) == -cos(x)
399
+ raises(ValueError, lambda: integrate(f, 2*x))
400
+
401
+
402
+ def test_issue_4516():
403
+ assert integrate(2**x - 2*x, x) == 2**x/log(2) - x**2
404
+
405
+
406
+ def test_issue_7450():
407
+ ans = integrate(exp(-(1 + I)*x), (x, 0, oo))
408
+ assert re(ans) == S.Half and im(ans) == Rational(-1, 2)
409
+
410
+
411
+ def test_issue_8623():
412
+ assert integrate((1 + cos(2*x)) / (3 - 2*cos(2*x)), (x, 0, pi)) == -pi/2 + sqrt(5)*pi/2
413
+ assert integrate((1 + cos(2*x))/(3 - 2*cos(2*x))) == -x/2 + sqrt(5)*(atan(sqrt(5)*tan(x)) + \
414
+ pi*floor((x - pi/2)/pi))/2
415
+
416
+
417
+ def test_issue_9569():
418
+ assert integrate(1 / (2 - cos(x)), (x, 0, pi)) == pi/sqrt(3)
419
+ assert integrate(1/(2 - cos(x))) == 2*sqrt(3)*(atan(sqrt(3)*tan(x/2)) + pi*floor((x/2 - pi/2)/pi))/3
420
+
421
+
422
+ def test_issue_13733():
423
+ s = Symbol('s', positive=True)
424
+ pz = exp(-(z - y)**2/(2*s*s))/sqrt(2*pi*s*s)
425
+ pzgx = integrate(pz, (z, x, oo))
426
+ assert integrate(pzgx, (x, 0, oo)) == sqrt(2)*s*exp(-y**2/(2*s**2))/(2*sqrt(pi)) + \
427
+ y*erf(sqrt(2)*y/(2*s))/2 + y/2
428
+
429
+
430
+ def test_issue_13749():
431
+ assert integrate(1 / (2 + cos(x)), (x, 0, pi)) == pi/sqrt(3)
432
+ assert integrate(1/(2 + cos(x))) == 2*sqrt(3)*(atan(sqrt(3)*tan(x/2)/3) + pi*floor((x/2 - pi/2)/pi))/3
433
+
434
+
435
+ def test_issue_18133():
436
+ assert integrate(exp(x)/(1 + x)**2, x) == NonElementaryIntegral(exp(x)/(x + 1)**2, x)
437
+
438
+
439
+ def test_issue_21741():
440
+ a = 4e6
441
+ b = 2.5e-7
442
+ r = Piecewise((b*I*exp(-a*I*pi*t*y)*exp(-a*I*pi*x*z)/(pi*x), Ne(x, 0)),
443
+ (z*exp(-a*I*pi*t*y), True))
444
+ fun = E**((-2*I*pi*(z*x+t*y))/(500*10**(-9)))
445
+ assert all_close(integrate(fun, z), r)
446
+
447
+
448
+ def test_matrices():
449
+ M = Matrix(2, 2, lambda i, j: (i + j + 1)*sin((i + j + 1)*x))
450
+
451
+ assert integrate(M, x) == Matrix([
452
+ [-cos(x), -cos(2*x)],
453
+ [-cos(2*x), -cos(3*x)],
454
+ ])
455
+
456
+
457
+ def test_integrate_functions():
458
+ # issue 4111
459
+ assert integrate(f(x), x) == Integral(f(x), x)
460
+ assert integrate(f(x), (x, 0, 1)) == Integral(f(x), (x, 0, 1))
461
+ assert integrate(f(x)*diff(f(x), x), x) == f(x)**2/2
462
+ assert integrate(diff(f(x), x) / f(x), x) == log(f(x))
463
+
464
+
465
+ def test_integrate_derivatives():
466
+ assert integrate(Derivative(f(x), x), x) == f(x)
467
+ assert integrate(Derivative(f(y), y), x) == x*Derivative(f(y), y)
468
+ assert integrate(Derivative(f(x), x)**2, x) == \
469
+ Integral(Derivative(f(x), x)**2, x)
470
+
471
+
472
+ def test_transform():
473
+ a = Integral(x**2 + 1, (x, -1, 2))
474
+ fx = x
475
+ fy = 3*y + 1
476
+ assert a.doit() == a.transform(fx, fy).doit()
477
+ assert a.transform(fx, fy).transform(fy, fx) == a
478
+ fx = 3*x + 1
479
+ fy = y
480
+ assert a.transform(fx, fy).transform(fy, fx) == a
481
+ a = Integral(sin(1/x), (x, 0, 1))
482
+ assert a.transform(x, 1/y) == Integral(sin(y)/y**2, (y, 1, oo))
483
+ assert a.transform(x, 1/y).transform(y, 1/x) == a
484
+ a = Integral(exp(-x**2), (x, -oo, oo))
485
+ assert a.transform(x, 2*y) == Integral(2*exp(-4*y**2), (y, -oo, oo))
486
+ # < 3 arg limit handled properly
487
+ assert Integral(x, x).transform(x, a*y).doit() == \
488
+ Integral(y*a**2, y).doit()
489
+ _3 = S(3)
490
+ assert Integral(x, (x, 0, -_3)).transform(x, 1/y).doit() == \
491
+ Integral(-1/x**3, (x, -oo, -1/_3)).doit()
492
+ assert Integral(x, (x, 0, _3)).transform(x, 1/y) == \
493
+ Integral(y**(-3), (y, 1/_3, oo))
494
+ # issue 8400
495
+ i = Integral(x + y, (x, 1, 2), (y, 1, 2))
496
+ assert i.transform(x, (x + 2*y, x)).doit() == \
497
+ i.transform(x, (x + 2*z, x)).doit() == 3
498
+
499
+ i = Integral(x, (x, a, b))
500
+ assert i.transform(x, 2*s) == Integral(4*s, (s, a/2, b/2))
501
+ raises(ValueError, lambda: i.transform(x, 1))
502
+ raises(ValueError, lambda: i.transform(x, s*t))
503
+ raises(ValueError, lambda: i.transform(x, -s))
504
+ raises(ValueError, lambda: i.transform(x, (s, t)))
505
+ raises(ValueError, lambda: i.transform(2*x, 2*s))
506
+
507
+ i = Integral(x**2, (x, 1, 2))
508
+ raises(ValueError, lambda: i.transform(x**2, s))
509
+
510
+ am = Symbol('a', negative=True)
511
+ bp = Symbol('b', positive=True)
512
+ i = Integral(x, (x, bp, am))
513
+ i.transform(x, 2*s)
514
+ assert i.transform(x, 2*s) == Integral(-4*s, (s, am/2, bp/2))
515
+
516
+ i = Integral(x, (x, a))
517
+ assert i.transform(x, 2*s) == Integral(4*s, (s, a/2))
518
+
519
+
520
+ def test_issue_4052():
521
+ f = S.Half*asin(x) + x*sqrt(1 - x**2)/2
522
+
523
+ assert integrate(cos(asin(x)), x) == f
524
+ assert integrate(sin(acos(x)), x) == f
525
+
526
+
527
+ @slow
528
+ def test_evalf_integrals():
529
+ assert NS(Integral(x, (x, 2, 5)), 15) == '10.5000000000000'
530
+ gauss = Integral(exp(-x**2), (x, -oo, oo))
531
+ assert NS(gauss, 15) == '1.77245385090552'
532
+ assert NS(gauss**2 - pi + E*Rational(
533
+ 1, 10**20), 15) in ('2.71828182845904e-20', '2.71828182845905e-20')
534
+ # A monster of an integral from http://mathworld.wolfram.com/DefiniteIntegral.html
535
+ t = Symbol('t')
536
+ a = 8*sqrt(3)/(1 + 3*t**2)
537
+ b = 16*sqrt(2)*(3*t + 1)*sqrt(4*t**2 + t + 1)**3
538
+ c = (3*t**2 + 1)*(11*t**2 + 2*t + 3)**2
539
+ d = sqrt(2)*(249*t**2 + 54*t + 65)/(11*t**2 + 2*t + 3)**2
540
+ f = a - b/c - d
541
+ assert NS(Integral(f, (t, 0, 1)), 50) == \
542
+ NS((3*sqrt(2) - 49*pi + 162*atan(sqrt(2)))/12, 50)
543
+ # http://mathworld.wolfram.com/VardisIntegral.html
544
+ assert NS(Integral(log(log(1/x))/(1 + x + x**2), (x, 0, 1)), 15) == \
545
+ NS('pi/sqrt(3) * log(2*pi**(5/6) / gamma(1/6))', 15)
546
+ # http://mathworld.wolfram.com/AhmedsIntegral.html
547
+ assert NS(Integral(atan(sqrt(x**2 + 2))/(sqrt(x**2 + 2)*(x**2 + 1)), (x,
548
+ 0, 1)), 15) == NS(5*pi**2/96, 15)
549
+ # http://mathworld.wolfram.com/AbelsIntegral.html
550
+ assert NS(Integral(x/((exp(pi*x) - exp(
551
+ -pi*x))*(x**2 + 1)), (x, 0, oo)), 15) == NS('log(2)/2-1/4', 15)
552
+ # Complex part trimming
553
+ # http://mathworld.wolfram.com/VardisIntegral.html
554
+ assert NS(Integral(log(log(sin(x)/cos(x))), (x, pi/4, pi/2)), 15, chop=True) == \
555
+ NS('pi/4*log(4*pi**3/gamma(1/4)**4)', 15)
556
+ #
557
+ # Endpoints causing trouble (rounding error in integration points -> complex log)
558
+ assert NS(
559
+ 2 + Integral(log(2*cos(x/2)), (x, -pi, pi)), 17, chop=True) == NS(2, 17)
560
+ assert NS(
561
+ 2 + Integral(log(2*cos(x/2)), (x, -pi, pi)), 20, chop=True) == NS(2, 20)
562
+ assert NS(
563
+ 2 + Integral(log(2*cos(x/2)), (x, -pi, pi)), 22, chop=True) == NS(2, 22)
564
+ # Needs zero handling
565
+ assert NS(pi - 4*Integral(
566
+ 'sqrt(1-x**2)', (x, 0, 1)), 15, maxn=30, chop=True) in ('0.0', '0')
567
+ # Oscillatory quadrature
568
+ a = Integral(sin(x)/x**2, (x, 1, oo)).evalf(maxn=15)
569
+ assert 0.49 < a < 0.51
570
+ assert NS(
571
+ Integral(sin(x)/x**2, (x, 1, oo)), quad='osc') == '0.504067061906928'
572
+ assert NS(Integral(
573
+ cos(pi*x + 1)/x, (x, -oo, -1)), quad='osc') == '0.276374705640365'
574
+ # indefinite integrals aren't evaluated
575
+ assert NS(Integral(x, x)) == 'Integral(x, x)'
576
+ assert NS(Integral(x, (x, y))) == 'Integral(x, (x, y))'
577
+
578
+
579
+ def test_evalf_issue_939():
580
+ # https://github.com/sympy/sympy/issues/4038
581
+
582
+ # The output form of an integral may differ by a step function between
583
+ # revisions, making this test a bit useless. This can't be said about
584
+ # other two tests. For now, all values of this evaluation are used here,
585
+ # but in future this should be reconsidered.
586
+ assert NS(integrate(1/(x**5 + 1), x).subs(x, 4), chop=True) in \
587
+ ['-0.000976138910649103', '0.965906660135753', '1.93278945918216']
588
+
589
+ assert NS(Integral(1/(x**5 + 1), (x, 2, 4))) == '0.0144361088886740'
590
+ assert NS(
591
+ integrate(1/(x**5 + 1), (x, 2, 4)), chop=True) == '0.0144361088886740'
592
+
593
+
594
+ def test_double_previously_failing_integrals():
595
+ # Double integrals not implemented <- Sure it is!
596
+ res = integrate(sqrt(x) + x*y, (x, 1, 2), (y, -1, 1))
597
+ # Old numerical test
598
+ assert NS(res, 15) == '2.43790283299492'
599
+ # Symbolic test
600
+ assert res == Rational(-4, 3) + 8*sqrt(2)/3
601
+ # double integral + zero detection
602
+ assert integrate(sin(x + x*y), (x, -1, 1), (y, -1, 1)) is S.Zero
603
+
604
+
605
+ def test_integrate_SingularityFunction():
606
+ in_1 = SingularityFunction(x, a, 3) + SingularityFunction(x, 5, -1)
607
+ out_1 = SingularityFunction(x, a, 4)/4 + SingularityFunction(x, 5, 0)
608
+ assert integrate(in_1, x) == out_1
609
+
610
+ in_2 = 10*SingularityFunction(x, 4, 0) - 5*SingularityFunction(x, -6, -2)
611
+ out_2 = 10*SingularityFunction(x, 4, 1) - 5*SingularityFunction(x, -6, -1)
612
+ assert integrate(in_2, x) == out_2
613
+
614
+ in_3 = 2*x**2*y -10*SingularityFunction(x, -4, 7) - 2*SingularityFunction(y, 10, -2)
615
+ out_3_1 = 2*x**3*y/3 - 2*x*SingularityFunction(y, 10, -2) - 5*SingularityFunction(x, -4, 8)/4
616
+ out_3_2 = x**2*y**2 - 10*y*SingularityFunction(x, -4, 7) - 2*SingularityFunction(y, 10, -1)
617
+ assert integrate(in_3, x) == out_3_1
618
+ assert integrate(in_3, y) == out_3_2
619
+
620
+ assert unchanged(Integral, in_3, (x,))
621
+ assert Integral(in_3, x) == Integral(in_3, (x,))
622
+ assert Integral(in_3, x).doit() == out_3_1
623
+
624
+ in_4 = 10*SingularityFunction(x, -4, 7) - 2*SingularityFunction(x, 10, -2)
625
+ out_4 = 5*SingularityFunction(x, -4, 8)/4 - 2*SingularityFunction(x, 10, -1)
626
+ assert integrate(in_4, (x, -oo, x)) == out_4
627
+
628
+ assert integrate(SingularityFunction(x, 5, -1), x) == SingularityFunction(x, 5, 0)
629
+ assert integrate(SingularityFunction(x, 0, -1), (x, -oo, oo)) == 1
630
+ assert integrate(5*SingularityFunction(x, 5, -1), (x, -oo, oo)) == 5
631
+ assert integrate(SingularityFunction(x, 5, -1) * f(x), (x, -oo, oo)) == f(5)
632
+
633
+
634
+ def test_integrate_DiracDelta():
635
+ # This is here to check that deltaintegrate is being called, but also
636
+ # to test definite integrals. More tests are in test_deltafunctions.py
637
+ assert integrate(DiracDelta(x) * f(x), (x, -oo, oo)) == f(0)
638
+ assert integrate(DiracDelta(x)**2, (x, -oo, oo)) == DiracDelta(0)
639
+ # issue 4522
640
+ assert integrate(integrate((4 - 4*x + x*y - 4*y) * \
641
+ DiracDelta(x)*DiracDelta(y - 1), (x, 0, 1)), (y, 0, 1)) == 0
642
+ # issue 5729
643
+ p = exp(-(x**2 + y**2))/pi
644
+ assert integrate(p*DiracDelta(x - 10*y), (x, -oo, oo), (y, -oo, oo)) == \
645
+ integrate(p*DiracDelta(x - 10*y), (y, -oo, oo), (x, -oo, oo)) == \
646
+ integrate(p*DiracDelta(10*x - y), (x, -oo, oo), (y, -oo, oo)) == \
647
+ integrate(p*DiracDelta(10*x - y), (y, -oo, oo), (x, -oo, oo)) == \
648
+ 1/sqrt(101*pi)
649
+
650
+
651
+ def test_integrate_returns_piecewise():
652
+ assert integrate(x**y, x) == Piecewise(
653
+ (x**(y + 1)/(y + 1), Ne(y, -1)), (log(x), True))
654
+ assert integrate(x**y, y) == Piecewise(
655
+ (x**y/log(x), Ne(log(x), 0)), (y, True))
656
+ assert integrate(exp(n*x), x) == Piecewise(
657
+ (exp(n*x)/n, Ne(n, 0)), (x, True))
658
+ assert integrate(x*exp(n*x), x) == Piecewise(
659
+ ((n*x - 1)*exp(n*x)/n**2, Ne(n**2, 0)), (x**2/2, True))
660
+ assert integrate(x**(n*y), x) == Piecewise(
661
+ (x**(n*y + 1)/(n*y + 1), Ne(n*y, -1)), (log(x), True))
662
+ assert integrate(x**(n*y), y) == Piecewise(
663
+ (x**(n*y)/(n*log(x)), Ne(n*log(x), 0)), (y, True))
664
+ assert integrate(cos(n*x), x) == Piecewise(
665
+ (sin(n*x)/n, Ne(n, 0)), (x, True))
666
+ assert integrate(cos(n*x)**2, x) == Piecewise(
667
+ ((n*x/2 + sin(n*x)*cos(n*x)/2)/n, Ne(n, 0)), (x, True))
668
+ assert integrate(x*cos(n*x), x) == Piecewise(
669
+ (x*sin(n*x)/n + cos(n*x)/n**2, Ne(n, 0)), (x**2/2, True))
670
+ assert integrate(sin(n*x), x) == Piecewise(
671
+ (-cos(n*x)/n, Ne(n, 0)), (0, True))
672
+ assert integrate(sin(n*x)**2, x) == Piecewise(
673
+ ((n*x/2 - sin(n*x)*cos(n*x)/2)/n, Ne(n, 0)), (0, True))
674
+ assert integrate(x*sin(n*x), x) == Piecewise(
675
+ (-x*cos(n*x)/n + sin(n*x)/n**2, Ne(n, 0)), (0, True))
676
+ assert integrate(exp(x*y), (x, 0, z)) == Piecewise(
677
+ (exp(y*z)/y - 1/y, (y > -oo) & (y < oo) & Ne(y, 0)), (z, True))
678
+ # https://github.com/sympy/sympy/issues/23707
679
+ assert integrate(exp(t)*exp(-t*sqrt(x - y)), t) == Piecewise(
680
+ (-exp(t)/(sqrt(x - y)*exp(t*sqrt(x - y)) - exp(t*sqrt(x - y))),
681
+ Ne(x, y + 1)), (t, True))
682
+
683
+
684
+ def test_integrate_max_min():
685
+ x = symbols('x', real=True)
686
+ assert integrate(Min(x, 2), (x, 0, 3)) == 4
687
+ assert integrate(Max(x**2, x**3), (x, 0, 2)) == Rational(49, 12)
688
+ assert integrate(Min(exp(x), exp(-x))**2, x) == Piecewise( \
689
+ (exp(2*x)/2, x <= 0), (1 - exp(-2*x)/2, True))
690
+ # issue 7907
691
+ c = symbols('c', extended_real=True)
692
+ int1 = integrate(Max(c, x)*exp(-x**2), (x, -oo, oo))
693
+ int2 = integrate(c*exp(-x**2), (x, -oo, c))
694
+ int3 = integrate(x*exp(-x**2), (x, c, oo))
695
+ assert int1 == int2 + int3 == sqrt(pi)*c*erf(c)/2 + \
696
+ sqrt(pi)*c/2 + exp(-c**2)/2
697
+
698
+
699
+ def test_integrate_Abs_sign():
700
+ assert integrate(Abs(x), (x, -2, 1)) == Rational(5, 2)
701
+ assert integrate(Abs(x), (x, 0, 1)) == S.Half
702
+ assert integrate(Abs(x + 1), (x, 0, 1)) == Rational(3, 2)
703
+ assert integrate(Abs(x**2 - 1), (x, -2, 2)) == 4
704
+ assert integrate(Abs(x**2 - 3*x), (x, -15, 15)) == 2259
705
+ assert integrate(sign(x), (x, -1, 2)) == 1
706
+ assert integrate(sign(x)*sin(x), (x, -pi, pi)) == 4
707
+ assert integrate(sign(x - 2) * x**2, (x, 0, 3)) == Rational(11, 3)
708
+
709
+ t, s = symbols('t s', real=True)
710
+ assert integrate(Abs(t), t) == Piecewise(
711
+ (-t**2/2, t <= 0), (t**2/2, True))
712
+ assert integrate(Abs(2*t - 6), t) == Piecewise(
713
+ (-t**2 + 6*t, t <= 3), (t**2 - 6*t + 18, True))
714
+ assert (integrate(abs(t - s**2), (t, 0, 2)) ==
715
+ 2*s**2*Min(2, s**2) - 2*s**2 - Min(2, s**2)**2 + 2)
716
+ assert integrate(exp(-Abs(t)), t) == Piecewise(
717
+ (exp(t), t <= 0), (2 - exp(-t), True))
718
+ assert integrate(sign(2*t - 6), t) == Piecewise(
719
+ (-t, t < 3), (t - 6, True))
720
+ assert integrate(2*t*sign(t**2 - 1), t) == Piecewise(
721
+ (t**2, t < -1), (-t**2 + 2, t < 1), (t**2, True))
722
+ assert integrate(sign(t), (t, s + 1)) == Piecewise(
723
+ (s + 1, s + 1 > 0), (-s - 1, s + 1 < 0), (0, True))
724
+
725
+
726
+ def test_subs1():
727
+ e = Integral(exp(x - y), x)
728
+ assert e.subs(y, 3) == Integral(exp(x - 3), x)
729
+ e = Integral(exp(x - y), (x, 0, 1))
730
+ assert e.subs(y, 3) == Integral(exp(x - 3), (x, 0, 1))
731
+ f = Lambda(x, exp(-x**2))
732
+ conv = Integral(f(x - y)*f(y), (y, -oo, oo))
733
+ assert conv.subs({x: 0}) == Integral(exp(-2*y**2), (y, -oo, oo))
734
+
735
+
736
+ def test_subs2():
737
+ e = Integral(exp(x - y), x, t)
738
+ assert e.subs(y, 3) == Integral(exp(x - 3), x, t)
739
+ e = Integral(exp(x - y), (x, 0, 1), (t, 0, 1))
740
+ assert e.subs(y, 3) == Integral(exp(x - 3), (x, 0, 1), (t, 0, 1))
741
+ f = Lambda(x, exp(-x**2))
742
+ conv = Integral(f(x - y)*f(y), (y, -oo, oo), (t, 0, 1))
743
+ assert conv.subs({x: 0}) == Integral(exp(-2*y**2), (y, -oo, oo), (t, 0, 1))
744
+
745
+
746
+ def test_subs3():
747
+ e = Integral(exp(x - y), (x, 0, y), (t, y, 1))
748
+ assert e.subs(y, 3) == Integral(exp(x - 3), (x, 0, 3), (t, 3, 1))
749
+ f = Lambda(x, exp(-x**2))
750
+ conv = Integral(f(x - y)*f(y), (y, -oo, oo), (t, x, 1))
751
+ assert conv.subs({x: 0}) == Integral(exp(-2*y**2), (y, -oo, oo), (t, 0, 1))
752
+
753
+
754
+ def test_subs4():
755
+ e = Integral(exp(x), (x, 0, y), (t, y, 1))
756
+ assert e.subs(y, 3) == Integral(exp(x), (x, 0, 3), (t, 3, 1))
757
+ f = Lambda(x, exp(-x**2))
758
+ conv = Integral(f(y)*f(y), (y, -oo, oo), (t, x, 1))
759
+ assert conv.subs({x: 0}) == Integral(exp(-2*y**2), (y, -oo, oo), (t, 0, 1))
760
+
761
+
762
+ def test_subs5():
763
+ e = Integral(exp(-x**2), (x, -oo, oo))
764
+ assert e.subs(x, 5) == e
765
+ e = Integral(exp(-x**2 + y), x)
766
+ assert e.subs(y, 5) == Integral(exp(-x**2 + 5), x)
767
+ e = Integral(exp(-x**2 + y), (x, x))
768
+ assert e.subs(x, 5) == Integral(exp(y - x**2), (x, 5))
769
+ assert e.subs(y, 5) == Integral(exp(-x**2 + 5), x)
770
+ e = Integral(exp(-x**2 + y), (y, -oo, oo), (x, -oo, oo))
771
+ assert e.subs(x, 5) == e
772
+ assert e.subs(y, 5) == e
773
+ # Test evaluation of antiderivatives
774
+ e = Integral(exp(-x**2), (x, x))
775
+ assert e.subs(x, 5) == Integral(exp(-x**2), (x, 5))
776
+ e = Integral(exp(x), x)
777
+ assert (e.subs(x,1) - e.subs(x,0) - Integral(exp(x), (x, 0, 1))
778
+ ).doit().is_zero
779
+
780
+
781
+ def test_subs6():
782
+ a, b = symbols('a b')
783
+ e = Integral(x*y, (x, f(x), f(y)))
784
+ assert e.subs(x, 1) == Integral(x*y, (x, f(1), f(y)))
785
+ assert e.subs(y, 1) == Integral(x, (x, f(x), f(1)))
786
+ e = Integral(x*y, (x, f(x), f(y)), (y, f(x), f(y)))
787
+ assert e.subs(x, 1) == Integral(x*y, (x, f(1), f(y)), (y, f(1), f(y)))
788
+ assert e.subs(y, 1) == Integral(x*y, (x, f(x), f(y)), (y, f(x), f(1)))
789
+ e = Integral(x*y, (x, f(x), f(a)), (y, f(x), f(a)))
790
+ assert e.subs(a, 1) == Integral(x*y, (x, f(x), f(1)), (y, f(x), f(1)))
791
+
792
+
793
+ def test_subs7():
794
+ e = Integral(x, (x, 1, y), (y, 1, 2))
795
+ assert e.subs({x: 1, y: 2}) == e
796
+ e = Integral(sin(x) + sin(y), (x, sin(x), sin(y)),
797
+ (y, 1, 2))
798
+ assert e.subs(sin(y), 1) == e
799
+ assert e.subs(sin(x), 1) == Integral(sin(x) + sin(y), (x, 1, sin(y)),
800
+ (y, 1, 2))
801
+
802
+ def test_expand():
803
+ e = Integral(f(x)+f(x**2), (x, 1, y))
804
+ assert e.expand() == Integral(f(x), (x, 1, y)) + Integral(f(x**2), (x, 1, y))
805
+ e = Integral(f(x)+f(x**2), (x, 1, oo))
806
+ assert e.expand() == e
807
+ assert e.expand(force=True) == Integral(f(x), (x, 1, oo)) + \
808
+ Integral(f(x**2), (x, 1, oo))
809
+
810
+
811
+ def test_integration_variable():
812
+ raises(ValueError, lambda: Integral(exp(-x**2), 3))
813
+ raises(ValueError, lambda: Integral(exp(-x**2), (3, -oo, oo)))
814
+
815
+
816
+ def test_expand_integral():
817
+ assert Integral(cos(x**2)*(sin(x**2) + 1), (x, 0, 1)).expand() == \
818
+ Integral(cos(x**2)*sin(x**2), (x, 0, 1)) + \
819
+ Integral(cos(x**2), (x, 0, 1))
820
+ assert Integral(cos(x**2)*(sin(x**2) + 1), x).expand() == \
821
+ Integral(cos(x**2)*sin(x**2), x) + \
822
+ Integral(cos(x**2), x)
823
+
824
+
825
+ def test_as_sum_midpoint1():
826
+ e = Integral(sqrt(x**3 + 1), (x, 2, 10))
827
+ assert e.as_sum(1, method="midpoint") == 8*sqrt(217)
828
+ assert e.as_sum(2, method="midpoint") == 4*sqrt(65) + 12*sqrt(57)
829
+ assert e.as_sum(3, method="midpoint") == 8*sqrt(217)/3 + \
830
+ 8*sqrt(3081)/27 + 8*sqrt(52809)/27
831
+ assert e.as_sum(4, method="midpoint") == 2*sqrt(730) + \
832
+ 4*sqrt(7) + 4*sqrt(86) + 6*sqrt(14)
833
+ assert abs(e.as_sum(4, method="midpoint").n() - e.n()) < 0.5
834
+
835
+ e = Integral(sqrt(x**3 + y**3), (x, 2, 10), (y, 0, 10))
836
+ raises(NotImplementedError, lambda: e.as_sum(4))
837
+
838
+
839
+ def test_as_sum_midpoint2():
840
+ e = Integral((x + y)**2, (x, 0, 1))
841
+ n = Symbol('n', positive=True, integer=True)
842
+ assert e.as_sum(1, method="midpoint").expand() == Rational(1, 4) + y + y**2
843
+ assert e.as_sum(2, method="midpoint").expand() == Rational(5, 16) + y + y**2
844
+ assert e.as_sum(3, method="midpoint").expand() == Rational(35, 108) + y + y**2
845
+ assert e.as_sum(4, method="midpoint").expand() == Rational(21, 64) + y + y**2
846
+ assert e.as_sum(n, method="midpoint").expand() == \
847
+ y**2 + y + Rational(1, 3) - 1/(12*n**2)
848
+
849
+
850
+ def test_as_sum_left():
851
+ e = Integral((x + y)**2, (x, 0, 1))
852
+ assert e.as_sum(1, method="left").expand() == y**2
853
+ assert e.as_sum(2, method="left").expand() == Rational(1, 8) + y/2 + y**2
854
+ assert e.as_sum(3, method="left").expand() == Rational(5, 27) + y*Rational(2, 3) + y**2
855
+ assert e.as_sum(4, method="left").expand() == Rational(7, 32) + y*Rational(3, 4) + y**2
856
+ assert e.as_sum(n, method="left").expand() == \
857
+ y**2 + y + Rational(1, 3) - y/n - 1/(2*n) + 1/(6*n**2)
858
+ assert e.as_sum(10, method="left", evaluate=False).has(Sum)
859
+
860
+
861
+ def test_as_sum_right():
862
+ e = Integral((x + y)**2, (x, 0, 1))
863
+ assert e.as_sum(1, method="right").expand() == 1 + 2*y + y**2
864
+ assert e.as_sum(2, method="right").expand() == Rational(5, 8) + y*Rational(3, 2) + y**2
865
+ assert e.as_sum(3, method="right").expand() == Rational(14, 27) + y*Rational(4, 3) + y**2
866
+ assert e.as_sum(4, method="right").expand() == Rational(15, 32) + y*Rational(5, 4) + y**2
867
+ assert e.as_sum(n, method="right").expand() == \
868
+ y**2 + y + Rational(1, 3) + y/n + 1/(2*n) + 1/(6*n**2)
869
+
870
+
871
+ def test_as_sum_trapezoid():
872
+ e = Integral((x + y)**2, (x, 0, 1))
873
+ assert e.as_sum(1, method="trapezoid").expand() == y**2 + y + S.Half
874
+ assert e.as_sum(2, method="trapezoid").expand() == y**2 + y + Rational(3, 8)
875
+ assert e.as_sum(3, method="trapezoid").expand() == y**2 + y + Rational(19, 54)
876
+ assert e.as_sum(4, method="trapezoid").expand() == y**2 + y + Rational(11, 32)
877
+ assert e.as_sum(n, method="trapezoid").expand() == \
878
+ y**2 + y + Rational(1, 3) + 1/(6*n**2)
879
+ assert Integral(sign(x), (x, 0, 1)).as_sum(1, 'trapezoid') == S.Half
880
+
881
+
882
+ def test_as_sum_raises():
883
+ e = Integral((x + y)**2, (x, 0, 1))
884
+ raises(ValueError, lambda: e.as_sum(-1))
885
+ raises(ValueError, lambda: e.as_sum(0))
886
+ raises(ValueError, lambda: Integral(x).as_sum(3))
887
+ raises(ValueError, lambda: e.as_sum(oo))
888
+ raises(ValueError, lambda: e.as_sum(3, method='xxxx2'))
889
+
890
+
891
+ def test_nested_doit():
892
+ e = Integral(Integral(x, x), x)
893
+ f = Integral(x, x, x)
894
+ assert e.doit() == f.doit()
895
+
896
+
897
+ def test_issue_4665():
898
+ # Allow only upper or lower limit evaluation
899
+ e = Integral(x**2, (x, None, 1))
900
+ f = Integral(x**2, (x, 1, None))
901
+ assert e.doit() == Rational(1, 3)
902
+ assert f.doit() == Rational(-1, 3)
903
+ assert Integral(x*y, (x, None, y)).subs(y, t) == Integral(x*t, (x, None, t))
904
+ assert Integral(x*y, (x, y, None)).subs(y, t) == Integral(x*t, (x, t, None))
905
+ assert integrate(x**2, (x, None, 1)) == Rational(1, 3)
906
+ assert integrate(x**2, (x, 1, None)) == Rational(-1, 3)
907
+ assert integrate("x**2", ("x", "1", None)) == Rational(-1, 3)
908
+
909
+
910
+ def test_integral_reconstruct():
911
+ e = Integral(x**2, (x, -1, 1))
912
+ assert e == Integral(*e.args)
913
+
914
+
915
+ def test_doit_integrals():
916
+ e = Integral(Integral(2*x), (x, 0, 1))
917
+ assert e.doit() == Rational(1, 3)
918
+ assert e.doit(deep=False) == Rational(1, 3)
919
+ f = Function('f')
920
+ # doesn't matter if the integral can't be performed
921
+ assert Integral(f(x), (x, 1, 1)).doit() == 0
922
+ # doesn't matter if the limits can't be evaluated
923
+ assert Integral(0, (x, 1, Integral(f(x), x))).doit() == 0
924
+ assert Integral(x, (a, 0)).doit() == 0
925
+ limits = ((a, 1, exp(x)), (x, 0))
926
+ assert Integral(a, *limits).doit() == Rational(1, 4)
927
+ assert Integral(a, *list(reversed(limits))).doit() == 0
928
+
929
+
930
+ def test_issue_4884():
931
+ assert integrate(sqrt(x)*(1 + x)) == \
932
+ Piecewise(
933
+ (2*sqrt(x)*(x + 1)**2/5 - 2*sqrt(x)*(x + 1)/15 - 4*sqrt(x)/15,
934
+ Abs(x + 1) > 1),
935
+ (2*I*sqrt(-x)*(x + 1)**2/5 - 2*I*sqrt(-x)*(x + 1)/15 -
936
+ 4*I*sqrt(-x)/15, True))
937
+ assert integrate(x**x*(1 + log(x))) == x**x
938
+
939
+ def test_issue_18153():
940
+ assert integrate(x**n*log(x),x) == \
941
+ Piecewise(
942
+ (n*x*x**n*log(x)/(n**2 + 2*n + 1) +
943
+ x*x**n*log(x)/(n**2 + 2*n + 1) - x*x**n/(n**2 + 2*n + 1)
944
+ , Ne(n, -1)), (log(x)**2/2, True)
945
+ )
946
+
947
+
948
+ def test_is_number():
949
+ from sympy.abc import x, y, z
950
+ assert Integral(x).is_number is False
951
+ assert Integral(1, x).is_number is False
952
+ assert Integral(1, (x, 1)).is_number is True
953
+ assert Integral(1, (x, 1, 2)).is_number is True
954
+ assert Integral(1, (x, 1, y)).is_number is False
955
+ assert Integral(1, (x, y)).is_number is False
956
+ assert Integral(x, y).is_number is False
957
+ assert Integral(x, (y, 1, x)).is_number is False
958
+ assert Integral(x, (y, 1, 2)).is_number is False
959
+ assert Integral(x, (x, 1, 2)).is_number is True
960
+ # `foo.is_number` should always be equivalent to `not foo.free_symbols`
961
+ # in each of these cases, there are pseudo-free symbols
962
+ i = Integral(x, (y, 1, 1))
963
+ assert i.is_number is False and i.n() == 0
964
+ i = Integral(x, (y, z, z))
965
+ assert i.is_number is False and i.n() == 0
966
+ i = Integral(1, (y, z, z + 2))
967
+ assert i.is_number is False and i.n() == 2.0
968
+
969
+ assert Integral(x*y, (x, 1, 2), (y, 1, 3)).is_number is True
970
+ assert Integral(x*y, (x, 1, 2), (y, 1, z)).is_number is False
971
+ assert Integral(x, (x, 1)).is_number is True
972
+ assert Integral(x, (x, 1, Integral(y, (y, 1, 2)))).is_number is True
973
+ assert Integral(Sum(z, (z, 1, 2)), (x, 1, 2)).is_number is True
974
+ # it is possible to get a false negative if the integrand is
975
+ # actually an unsimplified zero, but this is true of is_number in general.
976
+ assert Integral(sin(x)**2 + cos(x)**2 - 1, x).is_number is False
977
+ assert Integral(f(x), (x, 0, 1)).is_number is True
978
+
979
+
980
+ def test_free_symbols():
981
+ from sympy.abc import x, y, z
982
+ assert Integral(0, x).free_symbols == {x}
983
+ assert Integral(x).free_symbols == {x}
984
+ assert Integral(x, (x, None, y)).free_symbols == {y}
985
+ assert Integral(x, (x, y, None)).free_symbols == {y}
986
+ assert Integral(x, (x, 1, y)).free_symbols == {y}
987
+ assert Integral(x, (x, y, 1)).free_symbols == {y}
988
+ assert Integral(x, (x, x, y)).free_symbols == {x, y}
989
+ assert Integral(x, x, y).free_symbols == {x, y}
990
+ assert Integral(x, (x, 1, 2)).free_symbols == set()
991
+ assert Integral(x, (y, 1, 2)).free_symbols == {x}
992
+ # pseudo-free in this case
993
+ assert Integral(x, (y, z, z)).free_symbols == {x, z}
994
+ assert Integral(x, (y, 1, 2), (y, None, None)
995
+ ).free_symbols == {x, y}
996
+ assert Integral(x, (y, 1, 2), (x, 1, y)
997
+ ).free_symbols == {y}
998
+ assert Integral(2, (y, 1, 2), (y, 1, x), (x, 1, 2)
999
+ ).free_symbols == set()
1000
+ assert Integral(2, (y, x, 2), (y, 1, x), (x, 1, 2)
1001
+ ).free_symbols == set()
1002
+ assert Integral(2, (x, 1, 2), (y, x, 2), (y, 1, 2)
1003
+ ).free_symbols == {x}
1004
+ assert Integral(f(x), (f(x), 1, y)).free_symbols == {y}
1005
+ assert Integral(f(x), (f(x), 1, x)).free_symbols == {x}
1006
+
1007
+
1008
+ def test_is_zero():
1009
+ from sympy.abc import x, m
1010
+ assert Integral(0, (x, 1, x)).is_zero
1011
+ assert Integral(1, (x, 1, 1)).is_zero
1012
+ assert Integral(1, (x, 1, 2), (y, 2)).is_zero is False
1013
+ assert Integral(x, (m, 0)).is_zero
1014
+ assert Integral(x + m, (m, 0)).is_zero is None
1015
+ i = Integral(m, (m, 1, exp(x)), (x, 0))
1016
+ assert i.is_zero is None
1017
+ assert Integral(m, (x, 0), (m, 1, exp(x))).is_zero is True
1018
+
1019
+ assert Integral(x, (x, oo, oo)).is_zero # issue 8171
1020
+ assert Integral(x, (x, -oo, -oo)).is_zero
1021
+
1022
+ # this is zero but is beyond the scope of what is_zero
1023
+ # should be doing
1024
+ assert Integral(sin(x), (x, 0, 2*pi)).is_zero is None
1025
+
1026
+
1027
+ def test_series():
1028
+ from sympy.abc import x
1029
+ i = Integral(cos(x), (x, x))
1030
+ e = i.lseries(x)
1031
+ assert i.nseries(x, n=8).removeO() == Add(*[next(e) for j in range(4)])
1032
+
1033
+
1034
+ def test_trig_nonelementary_integrals():
1035
+ x = Symbol('x')
1036
+ assert integrate((1 + sin(x))/x, x) == log(x) + Si(x)
1037
+ # next one comes out as log(x) + log(x**2)/2 + Ci(x)
1038
+ # so not hardcoding this log ugliness
1039
+ assert integrate((cos(x) + 2)/x, x).has(Ci)
1040
+
1041
+
1042
+ def test_issue_4403():
1043
+ x = Symbol('x')
1044
+ y = Symbol('y')
1045
+ z = Symbol('z', positive=True)
1046
+ assert integrate(sqrt(x**2 + z**2), x) == \
1047
+ z**2*asinh(x/z)/2 + x*sqrt(x**2 + z**2)/2
1048
+ assert integrate(sqrt(x**2 - z**2), x) == \
1049
+ x*sqrt(x**2 - z**2)/2 - z**2*log(x + sqrt(x**2 - z**2))/2
1050
+
1051
+ x = Symbol('x', real=True)
1052
+ y = Symbol('y', positive=True)
1053
+ assert integrate(1/(x**2 + y**2)**S('3/2'), x) == \
1054
+ x/(y**2*sqrt(x**2 + y**2))
1055
+ # If y is real and nonzero, we get x*Abs(y)/(y**3*sqrt(x**2 + y**2)),
1056
+ # which results from sqrt(1 + x**2/y**2) = sqrt(x**2 + y**2)/|y|.
1057
+
1058
+
1059
+ def test_issue_4403_2():
1060
+ assert integrate(sqrt(-x**2 - 4), x) == \
1061
+ -2*atan(x/sqrt(-4 - x**2)) + x*sqrt(-4 - x**2)/2
1062
+
1063
+
1064
+ def test_issue_4100():
1065
+ R = Symbol('R', positive=True)
1066
+ assert integrate(sqrt(R**2 - x**2), (x, 0, R)) == pi*R**2/4
1067
+
1068
+
1069
+ def test_issue_5167():
1070
+ from sympy.abc import w, x, y, z
1071
+ f = Function('f')
1072
+ assert Integral(Integral(f(x), x), x) == Integral(f(x), x, x)
1073
+ assert Integral(f(x)).args == (f(x), Tuple(x))
1074
+ assert Integral(Integral(f(x))).args == (f(x), Tuple(x), Tuple(x))
1075
+ assert Integral(Integral(f(x)), y).args == (f(x), Tuple(x), Tuple(y))
1076
+ assert Integral(Integral(f(x), z), y).args == (f(x), Tuple(z), Tuple(y))
1077
+ assert Integral(Integral(Integral(f(x), x), y), z).args == \
1078
+ (f(x), Tuple(x), Tuple(y), Tuple(z))
1079
+ assert integrate(Integral(f(x), x), x) == Integral(f(x), x, x)
1080
+ assert integrate(Integral(f(x), y), x) == y*Integral(f(x), x)
1081
+ assert integrate(Integral(f(x), x), y) in [Integral(y*f(x), x), y*Integral(f(x), x)]
1082
+ assert integrate(Integral(2, x), x) == x**2
1083
+ assert integrate(Integral(2, x), y) == 2*x*y
1084
+ # don't re-order given limits
1085
+ assert Integral(1, x, y).args != Integral(1, y, x).args
1086
+ # do as many as possible
1087
+ assert Integral(f(x), y, x, y, x).doit() == y**2*Integral(f(x), x, x)/2
1088
+ assert Integral(f(x), (x, 1, 2), (w, 1, x), (z, 1, y)).doit() == \
1089
+ y*(x - 1)*Integral(f(x), (x, 1, 2)) - (x - 1)*Integral(f(x), (x, 1, 2))
1090
+
1091
+
1092
+ def test_issue_4890():
1093
+ z = Symbol('z', positive=True)
1094
+ assert integrate(exp(-log(x)**2), x) == \
1095
+ sqrt(pi)*exp(Rational(1, 4))*erf(log(x) - S.Half)/2
1096
+ assert integrate(exp(log(x)**2), x) == \
1097
+ sqrt(pi)*exp(Rational(-1, 4))*erfi(log(x)+S.Half)/2
1098
+ assert integrate(exp(-z*log(x)**2), x) == \
1099
+ sqrt(pi)*exp(1/(4*z))*erf(sqrt(z)*log(x) - 1/(2*sqrt(z)))/(2*sqrt(z))
1100
+
1101
+
1102
+ def test_issue_4551():
1103
+ assert not integrate(1/(x*sqrt(1 - x**2)), x).has(Integral)
1104
+
1105
+
1106
+ def test_issue_4376():
1107
+ n = Symbol('n', integer=True, positive=True)
1108
+ assert simplify(integrate(n*(x**(1/n) - 1), (x, 0, S.Half)) -
1109
+ (n**2 - 2**(1/n)*n**2 - n*2**(1/n))/(2**(1 + 1/n) + n*2**(1 + 1/n))) == 0
1110
+
1111
+
1112
+ def test_issue_4517():
1113
+ assert integrate((sqrt(x) - x**3)/x**Rational(1, 3), x) == \
1114
+ 6*x**Rational(7, 6)/7 - 3*x**Rational(11, 3)/11
1115
+
1116
+
1117
+ def test_issue_4527():
1118
+ k, m = symbols('k m', integer=True)
1119
+ assert integrate(sin(k*x)*sin(m*x), (x, 0, pi)).simplify() == \
1120
+ Piecewise((0, Eq(k, 0) | Eq(m, 0)),
1121
+ (-pi/2, Eq(k, -m) | (Eq(k, 0) & Eq(m, 0))),
1122
+ (pi/2, Eq(k, m) | (Eq(k, 0) & Eq(m, 0))),
1123
+ (0, True))
1124
+ # Should be possible to further simplify to:
1125
+ # Piecewise(
1126
+ # (0, Eq(k, 0) | Eq(m, 0)),
1127
+ # (-pi/2, Eq(k, -m)),
1128
+ # (pi/2, Eq(k, m)),
1129
+ # (0, True))
1130
+ assert integrate(sin(k*x)*sin(m*x), (x,)) == Piecewise(
1131
+ (0, And(Eq(k, 0), Eq(m, 0))),
1132
+ (-x*sin(m*x)**2/2 - x*cos(m*x)**2/2 + sin(m*x)*cos(m*x)/(2*m), Eq(k, -m)),
1133
+ (x*sin(m*x)**2/2 + x*cos(m*x)**2/2 - sin(m*x)*cos(m*x)/(2*m), Eq(k, m)),
1134
+ (m*sin(k*x)*cos(m*x)/(k**2 - m**2) -
1135
+ k*sin(m*x)*cos(k*x)/(k**2 - m**2), True))
1136
+
1137
+
1138
+ def test_issue_4199():
1139
+ ypos = Symbol('y', positive=True)
1140
+ # TODO: Remove conds='none' below, let the assumption take care of it.
1141
+ assert integrate(exp(-I*2*pi*ypos*x)*x, (x, -oo, oo), conds='none') == \
1142
+ Integral(exp(-I*2*pi*ypos*x)*x, (x, -oo, oo))
1143
+
1144
+
1145
+ def test_issue_3940():
1146
+ a, b, c, d = symbols('a:d', positive=True)
1147
+ assert integrate(exp(-x**2 + I*c*x), x) == \
1148
+ -sqrt(pi)*exp(-c**2/4)*erf(I*c/2 - x)/2
1149
+ assert integrate(exp(a*x**2 + b*x + c), x).equals(
1150
+ sqrt(pi)*exp(c - b**2/(4*a))*erfi((2*a*x + b)/(2*sqrt(a)))/(2*sqrt(a)))
1151
+
1152
+ from sympy.core.function import expand_mul
1153
+ from sympy.abc import k
1154
+ assert expand_mul(integrate(exp(-x**2)*exp(I*k*x), (x, -oo, oo))) == \
1155
+ sqrt(pi)*exp(-k**2/4)
1156
+ a, d = symbols('a d', positive=True)
1157
+ assert expand_mul(integrate(exp(-a*x**2 + 2*d*x), (x, -oo, oo))) == \
1158
+ sqrt(pi)*exp(d**2/a)/sqrt(a)
1159
+
1160
+
1161
+ def test_issue_5413():
1162
+ # Note that this is not the same as testing ratint() because integrate()
1163
+ # pulls out the coefficient.
1164
+ assert integrate(-a/(a**2 + x**2), x) == I*log(-I*a + x)/2 - I*log(I*a + x)/2
1165
+
1166
+
1167
+ def test_issue_4892a():
1168
+ A, z = symbols('A z')
1169
+ c = Symbol('c', nonzero=True)
1170
+ P1 = -A*exp(-z)
1171
+ P2 = -A/(c*t)*(sin(x)**2 + cos(y)**2)
1172
+
1173
+ h1 = -sin(x)**2 - cos(y)**2
1174
+ h2 = -sin(x)**2 + sin(y)**2 - 1
1175
+
1176
+ # there is still some non-deterministic behavior in integrate
1177
+ # or trigsimp which permits one of the following
1178
+ assert integrate(c*(P2 - P1), t) in [
1179
+ c*(-A*(-h1)*log(c*t)/c + A*t*exp(-z)),
1180
+ c*(-A*(-h2)*log(c*t)/c + A*t*exp(-z)),
1181
+ c*( A* h1 *log(c*t)/c + A*t*exp(-z)),
1182
+ c*( A* h2 *log(c*t)/c + A*t*exp(-z)),
1183
+ (A*c*t - A*(-h1)*log(t)*exp(z))*exp(-z),
1184
+ (A*c*t - A*(-h2)*log(t)*exp(z))*exp(-z),
1185
+ ]
1186
+
1187
+
1188
+ def test_issue_4892b():
1189
+ # Issues relating to issue 4596 are making the actual result of this hard
1190
+ # to test. The answer should be something like
1191
+ #
1192
+ # (-sin(y) + sqrt(-72 + 48*cos(y) - 8*cos(y)**2)/2)*log(x + sqrt(-72 +
1193
+ # 48*cos(y) - 8*cos(y)**2)/(2*(3 - cos(y)))) + (-sin(y) - sqrt(-72 +
1194
+ # 48*cos(y) - 8*cos(y)**2)/2)*log(x - sqrt(-72 + 48*cos(y) -
1195
+ # 8*cos(y)**2)/(2*(3 - cos(y)))) + x**2*sin(y)/2 + 2*x*cos(y)
1196
+
1197
+ expr = (sin(y)*x**3 + 2*cos(y)*x**2 + 12)/(x**2 + 2)
1198
+ assert trigsimp(factor(integrate(expr, x).diff(x) - expr)) == 0
1199
+
1200
+
1201
+ def test_issue_5178():
1202
+ assert integrate(sin(x)*f(y, z), (x, 0, pi), (y, 0, pi), (z, 0, pi)) == \
1203
+ 2*Integral(f(y, z), (y, 0, pi), (z, 0, pi))
1204
+
1205
+
1206
+ def test_integrate_series():
1207
+ f = sin(x).series(x, 0, 10)
1208
+ g = x**2/2 - x**4/24 + x**6/720 - x**8/40320 + x**10/3628800 + O(x**11)
1209
+
1210
+ assert integrate(f, x) == g
1211
+ assert diff(integrate(f, x), x) == f
1212
+
1213
+ assert integrate(O(x**5), x) == O(x**6)
1214
+
1215
+
1216
+ def test_atom_bug():
1217
+ from sympy.integrals.heurisch import heurisch
1218
+ assert heurisch(meijerg([], [], [1], [], x), x) is None
1219
+
1220
+
1221
+ def test_limit_bug():
1222
+ z = Symbol('z', zero=False)
1223
+ assert integrate(sin(x*y*z), (x, 0, pi), (y, 0, pi)).together() == \
1224
+ (log(z) - Ci(pi**2*z) + EulerGamma + 2*log(pi))/z
1225
+
1226
+
1227
+ def test_issue_4703():
1228
+ g = Function('g')
1229
+ assert integrate(exp(x)*g(x), x).has(Integral)
1230
+
1231
+
1232
+ def test_issue_1888():
1233
+ f = Function('f')
1234
+ assert integrate(f(x).diff(x)**2, x).has(Integral)
1235
+
1236
+ # The following tests work using meijerint.
1237
+
1238
+
1239
+ def test_issue_3558():
1240
+ assert integrate(cos(x*y), (x, -pi/2, pi/2), (y, 0, pi)) == 2*Si(pi**2/2)
1241
+
1242
+
1243
+ def test_issue_4422():
1244
+ assert integrate(1/sqrt(16 + 4*x**2), x) == asinh(x/2) / 2
1245
+
1246
+
1247
+ def test_issue_4493():
1248
+ assert simplify(integrate(x*sqrt(1 + 2*x), x)) == \
1249
+ sqrt(2*x + 1)*(6*x**2 + x - 1)/15
1250
+
1251
+
1252
+ def test_issue_4737():
1253
+ assert integrate(sin(x)/x, (x, -oo, oo)) == pi
1254
+ assert integrate(sin(x)/x, (x, 0, oo)) == pi/2
1255
+ assert integrate(sin(x)/x, x) == Si(x)
1256
+
1257
+
1258
+ def test_issue_4992():
1259
+ # Note: psi in _check_antecedents becomes NaN.
1260
+ from sympy.core.function import expand_func
1261
+ a = Symbol('a', positive=True)
1262
+ assert simplify(expand_func(integrate(exp(-x)*log(x)*x**a, (x, 0, oo)))) == \
1263
+ (a*polygamma(0, a) + 1)*gamma(a)
1264
+
1265
+
1266
+ def test_issue_4487():
1267
+ from sympy.functions.special.gamma_functions import lowergamma
1268
+ assert simplify(integrate(exp(-x)*x**y, x)) == lowergamma(y + 1, x)
1269
+
1270
+
1271
+ def test_issue_4215():
1272
+ x = Symbol("x")
1273
+ assert integrate(1/(x**2), (x, -1, 1)) is oo
1274
+
1275
+
1276
+ def test_issue_4400():
1277
+ n = Symbol('n', integer=True, positive=True)
1278
+ assert integrate((x**n)*log(x), x) == \
1279
+ n*x*x**n*log(x)/(n**2 + 2*n + 1) + x*x**n*log(x)/(n**2 + 2*n + 1) - \
1280
+ x*x**n/(n**2 + 2*n + 1)
1281
+
1282
+
1283
+ def test_issue_6253():
1284
+ # Note: this used to raise NotImplementedError
1285
+ # Note: psi in _check_antecedents becomes NaN.
1286
+ assert integrate((sqrt(1 - x) + sqrt(1 + x))**2/x, x, meijerg=True) == \
1287
+ Integral((sqrt(-x + 1) + sqrt(x + 1))**2/x, x)
1288
+
1289
+
1290
+ def test_issue_4153():
1291
+ assert integrate(1/(1 + x + y + z), (x, 0, 1), (y, 0, 1), (z, 0, 1)) in [
1292
+ -12*log(3) - 3*log(6)/2 + 3*log(8)/2 + 5*log(2) + 7*log(4),
1293
+ 6*log(2) + 8*log(4) - 27*log(3)/2, 22*log(2) - 27*log(3)/2,
1294
+ -12*log(3) - 3*log(6)/2 + 47*log(2)/2]
1295
+
1296
+
1297
+ def test_issue_4326():
1298
+ R, b, h = symbols('R b h')
1299
+ # It doesn't matter if we can do the integral. Just make sure the result
1300
+ # doesn't contain nan. This is really a test against _eval_interval.
1301
+ e = integrate(((h*(x - R + b))/b)*sqrt(R**2 - x**2), (x, R - b, R))
1302
+ assert not e.has(nan)
1303
+ # See that it evaluates
1304
+ assert not e.has(Integral)
1305
+
1306
+
1307
+ def test_powers():
1308
+ assert integrate(2**x + 3**x, x) == 2**x/log(2) + 3**x/log(3)
1309
+
1310
+
1311
+ def test_manual_option():
1312
+ raises(ValueError, lambda: integrate(1/x, x, manual=True, meijerg=True))
1313
+ # an example of a function that manual integration cannot handle
1314
+ assert integrate(log(1+x)/x, (x, 0, 1), manual=True).has(Integral)
1315
+
1316
+
1317
+ def test_meijerg_option():
1318
+ raises(ValueError, lambda: integrate(1/x, x, meijerg=True, risch=True))
1319
+ # an example of a function that meijerg integration cannot handle
1320
+ assert integrate(tan(x), x, meijerg=True) == Integral(tan(x), x)
1321
+
1322
+
1323
+ def test_risch_option():
1324
+ # risch=True only allowed on indefinite integrals
1325
+ raises(ValueError, lambda: integrate(1/log(x), (x, 0, oo), risch=True))
1326
+ assert integrate(exp(-x**2), x, risch=True) == NonElementaryIntegral(exp(-x**2), x)
1327
+ assert integrate(log(1/x)*y, x, y, risch=True) == y**2*(x*log(1/x)/2 + x/2)
1328
+ assert integrate(erf(x), x, risch=True) == Integral(erf(x), x)
1329
+ # TODO: How to test risch=False?
1330
+
1331
+
1332
+ @slow
1333
+ def test_heurisch_option():
1334
+ raises(ValueError, lambda: integrate(1/x, x, risch=True, heurisch=True))
1335
+ # an integral that heurisch can handle
1336
+ assert integrate(exp(x**2), x, heurisch=True) == sqrt(pi)*erfi(x)/2
1337
+ # an integral that heurisch currently cannot handle
1338
+ assert integrate(exp(x)/x, x, heurisch=True) == Integral(exp(x)/x, x)
1339
+ # an integral where heurisch currently hangs, issue 15471
1340
+ assert integrate(log(x)*cos(log(x))/x**Rational(3, 4), x, heurisch=False) == (
1341
+ -128*x**Rational(1, 4)*sin(log(x))/289 + 240*x**Rational(1, 4)*cos(log(x))/289 +
1342
+ (16*x**Rational(1, 4)*sin(log(x))/17 + 4*x**Rational(1, 4)*cos(log(x))/17)*log(x))
1343
+
1344
+
1345
+ def test_issue_6828():
1346
+ f = 1/(1.08*x**2 - 4.3)
1347
+ g = integrate(f, x).diff(x)
1348
+ assert verify_numerically(f, g, tol=1e-12)
1349
+
1350
+
1351
+ def test_issue_4803():
1352
+ x_max = Symbol("x_max")
1353
+ assert integrate(y/pi*exp(-(x_max - x)/cos(a)), x) == \
1354
+ y*exp((x - x_max)/cos(a))*cos(a)/pi
1355
+
1356
+
1357
+ def test_issue_4234():
1358
+ assert integrate(1/sqrt(1 + tan(x)**2)) == tan(x)/sqrt(1 + tan(x)**2)
1359
+
1360
+
1361
+ def test_issue_4492():
1362
+ assert simplify(integrate(x**2 * sqrt(5 - x**2), x)).factor(
1363
+ deep=True) == Piecewise(
1364
+ (I*(2*x**5 - 15*x**3 + 25*x - 25*sqrt(x**2 - 5)*acosh(sqrt(5)*x/5)) /
1365
+ (8*sqrt(x**2 - 5)), (x > sqrt(5)) | (x < -sqrt(5))),
1366
+ ((2*x**5 - 15*x**3 + 25*x - 25*sqrt(5 - x**2)*asin(sqrt(5)*x/5)) /
1367
+ (-8*sqrt(-x**2 + 5)), True))
1368
+
1369
+
1370
+ def test_issue_2708():
1371
+ # This test needs to use an integration function that can
1372
+ # not be evaluated in closed form. Update as needed.
1373
+ f = 1/(a + z + log(z))
1374
+ integral_f = NonElementaryIntegral(f, (z, 2, 3))
1375
+ assert Integral(f, (z, 2, 3)).doit() == integral_f
1376
+ assert integrate(f + exp(z), (z, 2, 3)) == integral_f - exp(2) + exp(3)
1377
+ assert integrate(2*f + exp(z), (z, 2, 3)) == \
1378
+ 2*integral_f - exp(2) + exp(3)
1379
+ assert integrate(exp(1.2*n*s*z*(-t + z)/t), (z, 0, x)) == \
1380
+ NonElementaryIntegral(exp(-1.2*n*s*z)*exp(1.2*n*s*z**2/t),
1381
+ (z, 0, x))
1382
+
1383
+
1384
+ def test_issue_2884():
1385
+ f = (4.000002016020*x + 4.000002016020*y + 4.000006024032)*exp(10.0*x)
1386
+ e = integrate(f, (x, 0.1, 0.2))
1387
+ assert str(e) == '1.86831064982608*y + 2.16387491480008'
1388
+
1389
+
1390
+ def test_issue_8368i():
1391
+ from sympy.functions.elementary.complexes import arg, Abs
1392
+ assert integrate(exp(-s*x)*cosh(x), (x, 0, oo)) == \
1393
+ Piecewise(
1394
+ ( pi*Piecewise(
1395
+ ( -s/(pi*(-s**2 + 1)),
1396
+ Abs(s**2) < 1),
1397
+ ( 1/(pi*s*(1 - 1/s**2)),
1398
+ Abs(s**(-2)) < 1),
1399
+ ( meijerg(
1400
+ ((S.Half,), (0, 0)),
1401
+ ((0, S.Half), (0,)),
1402
+ polar_lift(s)**2),
1403
+ True)
1404
+ ),
1405
+ s**2 > 1
1406
+ ),
1407
+ (
1408
+ Integral(exp(-s*x)*cosh(x), (x, 0, oo)),
1409
+ True))
1410
+ assert integrate(exp(-s*x)*sinh(x), (x, 0, oo)) == \
1411
+ Piecewise(
1412
+ ( -1/(s + 1)/2 - 1/(-s + 1)/2,
1413
+ And(
1414
+ Abs(s) > 1,
1415
+ Abs(arg(s)) < pi/2,
1416
+ Abs(arg(s)) <= pi/2
1417
+ )),
1418
+ ( Integral(exp(-s*x)*sinh(x), (x, 0, oo)),
1419
+ True))
1420
+
1421
+
1422
+ def test_issue_8901():
1423
+ assert integrate(sinh(1.0*x)) == 1.0*cosh(1.0*x)
1424
+ assert integrate(tanh(1.0*x)) == 1.0*x - 1.0*log(tanh(1.0*x) + 1)
1425
+ assert integrate(tanh(x)) == x - log(tanh(x) + 1)
1426
+
1427
+
1428
+ @slow
1429
+ def test_issue_8945():
1430
+ assert integrate(sin(x)**3/x, (x, 0, 1)) == -Si(3)/4 + 3*Si(1)/4
1431
+ assert integrate(sin(x)**3/x, (x, 0, oo)) == pi/4
1432
+ assert integrate(cos(x)**2/x**2, x) == -Si(2*x) - cos(2*x)/(2*x) - 1/(2*x)
1433
+
1434
+
1435
+ @slow
1436
+ def test_issue_7130():
1437
+ i, L, a, b = symbols('i L a b')
1438
+ integrand = (cos(pi*i*x/L)**2 / (a + b*x)).rewrite(exp)
1439
+ assert x not in integrate(integrand, (x, 0, L)).free_symbols
1440
+
1441
+
1442
+ def test_issue_10567():
1443
+ a, b, c, t = symbols('a b c t')
1444
+ vt = Matrix([a*t, b, c])
1445
+ assert integrate(vt, t) == Integral(vt, t).doit()
1446
+ assert integrate(vt, t) == Matrix([[a*t**2/2], [b*t], [c*t]])
1447
+
1448
+
1449
+ def test_issue_11742():
1450
+ assert integrate(sqrt(-x**2 + 8*x + 48), (x, 4, 12)) == 16*pi
1451
+
1452
+
1453
+ def test_issue_11856():
1454
+ t = symbols('t')
1455
+ assert integrate(sinc(pi*t), t) == Si(pi*t)/pi
1456
+
1457
+
1458
+ @slow
1459
+ def test_issue_11876():
1460
+ assert integrate(sqrt(log(1/x)), (x, 0, 1)) == sqrt(pi)/2
1461
+
1462
+
1463
+ def test_issue_4950():
1464
+ assert integrate((-60*exp(x) - 19.2*exp(4*x))*exp(4*x), x) ==\
1465
+ -2.4*exp(8*x) - 12.0*exp(5*x)
1466
+
1467
+
1468
+ def test_issue_4968():
1469
+ assert integrate(sin(log(x**2))) == x*sin(log(x**2))/5 - 2*x*cos(log(x**2))/5
1470
+
1471
+
1472
+ def test_singularities():
1473
+ assert integrate(1/x**2, (x, -oo, oo)) is oo
1474
+ assert integrate(1/x**2, (x, -1, 1)) is oo
1475
+ assert integrate(1/(x - 1)**2, (x, -2, 2)) is oo
1476
+
1477
+ assert integrate(1/x**2, (x, 1, -1)) is -oo
1478
+ assert integrate(1/(x - 1)**2, (x, 2, -2)) is -oo
1479
+
1480
+
1481
+ def test_issue_12645():
1482
+ x, y = symbols('x y', real=True)
1483
+ assert (integrate(sin(x*x*x + y*y),
1484
+ (x, -sqrt(pi - y*y), sqrt(pi - y*y)),
1485
+ (y, -sqrt(pi), sqrt(pi)))
1486
+ == Integral(sin(x**3 + y**2),
1487
+ (x, -sqrt(-y**2 + pi), sqrt(-y**2 + pi)),
1488
+ (y, -sqrt(pi), sqrt(pi))))
1489
+
1490
+
1491
+ def test_issue_12677():
1492
+ assert integrate(sin(x) / (cos(x)**3), (x, 0, pi/6)) == Rational(1, 6)
1493
+
1494
+
1495
+ def test_issue_14078():
1496
+ assert integrate((cos(3*x)-cos(x))/x, (x, 0, oo)) == -log(3)
1497
+
1498
+
1499
+ def test_issue_14064():
1500
+ assert integrate(1/cosh(x), (x, 0, oo)) == pi/2
1501
+
1502
+
1503
+ def test_issue_14027():
1504
+ assert integrate(1/(1 + exp(x - S.Half)/(1 + exp(x))), x) == \
1505
+ x - exp(S.Half)*log(exp(x) + exp(S.Half)/(1 + exp(S.Half)))/(exp(S.Half) + E)
1506
+
1507
+
1508
+ def test_issue_8170():
1509
+ assert integrate(tan(x), (x, 0, pi/2)) is S.Infinity
1510
+
1511
+
1512
+ def test_issue_8440_14040():
1513
+ assert integrate(1/x, (x, -1, 1)) is S.NaN
1514
+ assert integrate(1/(x + 1), (x, -2, 3)) is S.NaN
1515
+
1516
+
1517
+ def test_issue_14096():
1518
+ assert integrate(1/(x + y)**2, (x, 0, 1)) == -1/(y + 1) + 1/y
1519
+ assert integrate(1/(1 + x + y + z)**2, (x, 0, 1), (y, 0, 1), (z, 0, 1)) == \
1520
+ -4*log(4) - 6*log(2) + 9*log(3)
1521
+
1522
+
1523
+ def test_issue_14144():
1524
+ assert Abs(integrate(1/sqrt(1 - x**3), (x, 0, 1)).n() - 1.402182) < 1e-6
1525
+ assert Abs(integrate(sqrt(1 - x**3), (x, 0, 1)).n() - 0.841309) < 1e-6
1526
+
1527
+
1528
+ def test_issue_14375():
1529
+ # This raised a TypeError. The antiderivative has exp_polar, which
1530
+ # may be possible to unpolarify, so the exact output is not asserted here.
1531
+ assert integrate(exp(I*x)*log(x), x).has(Ei)
1532
+
1533
+
1534
+ def test_issue_14437():
1535
+ f = Function('f')(x, y, z)
1536
+ assert integrate(f, (x, 0, 1), (y, 0, 2), (z, 0, 3)) == \
1537
+ Integral(f, (x, 0, 1), (y, 0, 2), (z, 0, 3))
1538
+
1539
+
1540
+ def test_issue_14470():
1541
+ assert integrate(1/sqrt(exp(x) + 1), x) == log(sqrt(exp(x) + 1) - 1) - log(sqrt(exp(x) + 1) + 1)
1542
+
1543
+
1544
+ def test_issue_14877():
1545
+ f = exp(1 - exp(x**2)*x + 2*x**2)*(2*x**3 + x)/(1 - exp(x**2)*x)**2
1546
+ assert integrate(f, x) == \
1547
+ -exp(2*x**2 - x*exp(x**2) + 1)/(x*exp(3*x**2) - exp(2*x**2))
1548
+
1549
+
1550
+ def test_issue_14782():
1551
+ f = sqrt(-x**2 + 1)*(-x**2 + x)
1552
+ assert integrate(f, [x, -1, 1]) == - pi / 8
1553
+
1554
+
1555
+ @slow
1556
+ def test_issue_14782_slow():
1557
+ f = sqrt(-x**2 + 1)*(-x**2 + x)
1558
+ assert integrate(f, [x, 0, 1]) == S.One / 3 - pi / 16
1559
+
1560
+
1561
+ def test_issue_12081():
1562
+ f = x**(Rational(-3, 2))*exp(-x)
1563
+ assert integrate(f, [x, 0, oo]) is oo
1564
+
1565
+
1566
+ def test_issue_15285():
1567
+ y = 1/x - 1
1568
+ f = 4*y*exp(-2*y)/x**2
1569
+ assert integrate(f, [x, 0, 1]) == 1
1570
+
1571
+
1572
+ def test_issue_15432():
1573
+ assert integrate(x**n * exp(-x) * log(x), (x, 0, oo)).gammasimp() == Piecewise(
1574
+ (gamma(n + 1)*polygamma(0, n) + gamma(n + 1)/n, re(n) + 1 > 0),
1575
+ (Integral(x**n*exp(-x)*log(x), (x, 0, oo)), True))
1576
+
1577
+
1578
+ def test_issue_15124():
1579
+ omega = IndexedBase('omega')
1580
+ m, p = symbols('m p', cls=Idx)
1581
+ assert integrate(exp(x*I*(omega[m] + omega[p])), x, conds='none') == \
1582
+ -I*exp(I*x*omega[m])*exp(I*x*omega[p])/(omega[m] + omega[p])
1583
+
1584
+
1585
+ def test_issue_15218():
1586
+ with warns_deprecated_sympy():
1587
+ Integral(Eq(x, y))
1588
+ with warns_deprecated_sympy():
1589
+ assert Integral(Eq(x, y), x) == Eq(Integral(x, x), Integral(y, x))
1590
+ with warns_deprecated_sympy():
1591
+ assert Integral(Eq(x, y), x).doit() == Eq(x**2/2, x*y)
1592
+ with warns(SymPyDeprecationWarning, test_stacklevel=False):
1593
+ # The warning is made in the ExprWithLimits superclass. The stacklevel
1594
+ # is correct for integrate(Eq) but not Eq.integrate
1595
+ assert Eq(x, y).integrate(x) == Eq(x**2/2, x*y)
1596
+
1597
+ # These are not deprecated because they are definite integrals
1598
+ assert integrate(Eq(x, y), (x, 0, 1)) == Eq(S.Half, y)
1599
+ assert Eq(x, y).integrate((x, 0, 1)) == Eq(S.Half, y)
1600
+
1601
+
1602
+ def test_issue_15292():
1603
+ res = integrate(exp(-x**2*cos(2*t)) * cos(x**2*sin(2*t)), (x, 0, oo))
1604
+ assert isinstance(res, Piecewise)
1605
+ assert gammasimp((res - sqrt(pi)/2 * cos(t)).subs(t, pi/6)) == 0
1606
+
1607
+
1608
+ def test_issue_4514():
1609
+ assert integrate(sin(2*x)/sin(x), x) == 2*sin(x)
1610
+
1611
+
1612
+ def test_issue_15457():
1613
+ x, a, b = symbols('x a b', real=True)
1614
+ definite = integrate(exp(Abs(x-2)), (x, a, b))
1615
+ indefinite = integrate(exp(Abs(x-2)), x)
1616
+ assert definite.subs({a: 1, b: 3}) == -2 + 2*E
1617
+ assert indefinite.subs(x, 3) - indefinite.subs(x, 1) == -2 + 2*E
1618
+ assert definite.subs({a: -3, b: -1}) == -exp(3) + exp(5)
1619
+ assert indefinite.subs(x, -1) - indefinite.subs(x, -3) == -exp(3) + exp(5)
1620
+
1621
+
1622
+ def test_issue_15431():
1623
+ assert integrate(x*exp(x)*log(x), x) == \
1624
+ (x*exp(x) - exp(x))*log(x) - exp(x) + Ei(x)
1625
+
1626
+
1627
+ def test_issue_15640_log_substitutions():
1628
+ f = x/log(x)
1629
+ F = Ei(2*log(x))
1630
+ assert integrate(f, x) == F and F.diff(x) == f
1631
+ f = x**3/log(x)**2
1632
+ F = -x**4/log(x) + 4*Ei(4*log(x))
1633
+ assert integrate(f, x) == F and F.diff(x) == f
1634
+ f = sqrt(log(x))/x**2
1635
+ F = -sqrt(pi)*erfc(sqrt(log(x)))/2 - sqrt(log(x))/x
1636
+ assert integrate(f, x) == F and F.diff(x) == f
1637
+
1638
+
1639
+ def test_issue_15509():
1640
+ from sympy.vector import CoordSys3D
1641
+ N = CoordSys3D('N')
1642
+ x = N.x
1643
+ assert integrate(cos(a*x + b), (x, x_1, x_2), heurisch=True) == Piecewise(
1644
+ (-sin(a*x_1 + b)/a + sin(a*x_2 + b)/a, (a > -oo) & (a < oo) & Ne(a, 0)), \
1645
+ (-x_1*cos(b) + x_2*cos(b), True))
1646
+
1647
+
1648
+ def test_issue_4311_fast():
1649
+ x = symbols('x', real=True)
1650
+ assert integrate(x*abs(9-x**2), x) == Piecewise(
1651
+ (x**4/4 - 9*x**2/2, x <= -3),
1652
+ (-x**4/4 + 9*x**2/2 - Rational(81, 2), x <= 3),
1653
+ (x**4/4 - 9*x**2/2, True))
1654
+
1655
+
1656
+ def test_integrate_with_complex_constants():
1657
+ K = Symbol('K', positive=True)
1658
+ x = Symbol('x', real=True)
1659
+ m = Symbol('m', real=True)
1660
+ t = Symbol('t', real=True)
1661
+ assert integrate(exp(-I*K*x**2+m*x), x) == sqrt(pi)*exp(-I*m**2
1662
+ /(4*K))*erfi((-2*I*K*x + m)/(2*sqrt(K)*sqrt(-I)))/(2*sqrt(K)*sqrt(-I))
1663
+ assert integrate(1/(1 + I*x**2), x) == (-I*(sqrt(-I)*log(x - I*sqrt(-I))/2
1664
+ - sqrt(-I)*log(x + I*sqrt(-I))/2))
1665
+ assert integrate(exp(-I*x**2), x) == sqrt(pi)*erf(sqrt(I)*x)/(2*sqrt(I))
1666
+
1667
+ assert integrate((1/(exp(I*t)-2)), t) == -t/2 - I*log(exp(I*t) - 2)/2
1668
+ assert integrate((1/(exp(I*t)-2)), (t, 0, 2*pi)) == -pi
1669
+
1670
+
1671
+ def test_issue_14241():
1672
+ x = Symbol('x')
1673
+ n = Symbol('n', positive=True, integer=True)
1674
+ assert integrate(n * x ** (n - 1) / (x + 1), x) == \
1675
+ n**2*x**n*lerchphi(x*exp_polar(I*pi), 1, n)*gamma(n)/gamma(n + 1)
1676
+
1677
+
1678
+ def test_issue_13112():
1679
+ assert integrate(sin(t)**2 / (5 - 4*cos(t)), [t, 0, 2*pi]) == pi / 4
1680
+
1681
+
1682
+ def test_issue_14709b():
1683
+ h = Symbol('h', positive=True)
1684
+ i = integrate(x*acos(1 - 2*x/h), (x, 0, h))
1685
+ assert i == 5*h**2*pi/16
1686
+
1687
+
1688
+ def test_issue_8614():
1689
+ x = Symbol('x')
1690
+ t = Symbol('t')
1691
+ assert integrate(exp(t)/t, (t, -oo, x)) == Ei(x)
1692
+ assert integrate((exp(-x) - exp(-2*x))/x, (x, 0, oo)) == log(2)
1693
+
1694
+
1695
+ @slow
1696
+ def test_issue_15494():
1697
+ s = symbols('s', positive=True)
1698
+
1699
+ integrand = (exp(s/2) - 2*exp(1.6*s) + exp(s))*exp(s)
1700
+ solution = integrate(integrand, s)
1701
+ assert solution != S.NaN
1702
+ # Not sure how to test this properly as it is a symbolic expression with floats
1703
+ # assert str(solution) == '0.666666666666667*exp(1.5*s) + 0.5*exp(2.0*s) - 0.769230769230769*exp(2.6*s)'
1704
+ # Maybe
1705
+ assert abs(solution.subs(s, 1) - (-3.67440080236188)) <= 1e-8
1706
+
1707
+ integrand = (exp(s/2) - 2*exp(S(8)/5*s) + exp(s))*exp(s)
1708
+ assert integrate(integrand, s) == -10*exp(13*s/5)/13 + 2*exp(3*s/2)/3 + exp(2*s)/2
1709
+
1710
+
1711
+ def test_li_integral():
1712
+ y = Symbol('y')
1713
+ assert Integral(li(y*x**2), x).doit() == Piecewise((x*li(x**2*y) - \
1714
+ x*Ei(3*log(x**2*y)/2)/sqrt(x**2*y),
1715
+ Ne(y, 0)), (0, True))
1716
+
1717
+
1718
+ def test_issue_17473():
1719
+ x = Symbol('x')
1720
+ n = Symbol('n')
1721
+ h = S.Half
1722
+ ans = x**(n + 1)*gamma(h + h/n)*hyper((h + h/n,),
1723
+ (3*h, 3*h + h/n), -x**(2*n)/4)/(2*n*gamma(3*h + h/n))
1724
+ got = integrate(sin(x**n), x)
1725
+ assert got == ans
1726
+ _x = Symbol('x', zero=False)
1727
+ reps = {x: _x}
1728
+ assert integrate(sin(_x**n), _x) == ans.xreplace(reps).expand()
1729
+
1730
+
1731
+ def test_issue_17671():
1732
+ assert integrate(log(log(x)) / x**2, [x, 1, oo]) == -EulerGamma
1733
+ assert integrate(log(log(x)) / x**3, [x, 1, oo]) == -log(2)/2 - EulerGamma/2
1734
+ assert integrate(log(log(x)) / x**10, [x, 1, oo]) == -log(9)/9 - EulerGamma/9
1735
+
1736
+
1737
+ def test_issue_2975():
1738
+ w = Symbol('w')
1739
+ C = Symbol('C')
1740
+ y = Symbol('y')
1741
+ assert integrate(1/(y**2+C)**(S(3)/2), (y, -w/2, w/2)) == w/(C**(S(3)/2)*sqrt(1 + w**2/(4*C)))
1742
+
1743
+
1744
+ def test_issue_7827():
1745
+ x, n, M = symbols('x n M')
1746
+ N = Symbol('N', integer=True)
1747
+ assert integrate(summation(x*n, (n, 1, N)), x) == x**2*(N**2/4 + N/4)
1748
+ assert integrate(summation(x*sin(n), (n,1,N)), x) == \
1749
+ Sum(x**2*sin(n)/2, (n, 1, N))
1750
+ assert integrate(summation(sin(n*x), (n,1,N)), x) == \
1751
+ Sum(Piecewise((-cos(n*x)/n, Ne(n, 0)), (0, True)), (n, 1, N))
1752
+ assert integrate(integrate(summation(sin(n*x), (n,1,N)), x), x) == \
1753
+ Piecewise((Sum(Piecewise((-sin(n*x)/n**2, Ne(n, 0)), (-x/n, True)),
1754
+ (n, 1, N)), (n > -oo) & (n < oo) & Ne(n, 0)), (0, True))
1755
+ assert integrate(Sum(x, (n, 1, M)), x) == M*x**2/2
1756
+ raises(ValueError, lambda: integrate(Sum(x, (x, y, n)), y))
1757
+ raises(ValueError, lambda: integrate(Sum(x, (x, 1, n)), n))
1758
+ raises(ValueError, lambda: integrate(Sum(x, (x, 1, y)), x))
1759
+
1760
+
1761
+ def test_issue_4231():
1762
+ f = (1 + 2*x + sqrt(x + log(x))*(1 + 3*x) + x**2)/(x*(x + sqrt(x + log(x)))*sqrt(x + log(x)))
1763
+ assert integrate(f, x) == 2*sqrt(x + log(x)) + 2*log(x + sqrt(x + log(x)))
1764
+
1765
+
1766
+ def test_issue_17841():
1767
+ f = diff(1/(x**2+x+I), x)
1768
+ assert integrate(f, x) == 1/(x**2 + x + I)
1769
+
1770
+
1771
+ def test_issue_21034():
1772
+ x = Symbol('x', real=True, nonzero=True)
1773
+ f1 = x*(-x**4/asin(5)**4 - x*sinh(x + log(asin(5))) + 5)
1774
+ f2 = (x + cosh(cos(4)))/(x*(x + 1/(12*x)))
1775
+
1776
+ assert integrate(f1, x) == \
1777
+ -x**6/(6*asin(5)**4) - x**2*cosh(x + log(asin(5))) + 5*x**2/2 + 2*x*sinh(x + log(asin(5))) - 2*cosh(x + log(asin(5)))
1778
+
1779
+ assert integrate(f2, x) == \
1780
+ log(x**2 + S(1)/12)/2 + 2*sqrt(3)*cosh(cos(4))*atan(2*sqrt(3)*x)
1781
+
1782
+
1783
+ def test_issue_4187():
1784
+ assert integrate(log(x)*exp(-x), x) == Ei(-x) - exp(-x)*log(x)
1785
+ assert integrate(log(x)*exp(-x), (x, 0, oo)) == -EulerGamma
1786
+
1787
+
1788
+ def test_issue_5547():
1789
+ L = Symbol('L')
1790
+ z = Symbol('z')
1791
+ r0 = Symbol('r0')
1792
+ R0 = Symbol('R0')
1793
+
1794
+ assert integrate(r0**2*cos(z)**2, (z, -L/2, L/2)) == -r0**2*(-L/4 -
1795
+ sin(L/2)*cos(L/2)/2) + r0**2*(L/4 + sin(L/2)*cos(L/2)/2)
1796
+
1797
+ assert integrate(r0**2*cos(R0*z)**2, (z, -L/2, L/2)) == Piecewise(
1798
+ (-r0**2*(-L*R0/4 - sin(L*R0/2)*cos(L*R0/2)/2)/R0 +
1799
+ r0**2*(L*R0/4 + sin(L*R0/2)*cos(L*R0/2)/2)/R0, (R0 > -oo) & (R0 < oo) & Ne(R0, 0)),
1800
+ (L*r0**2, True))
1801
+
1802
+ w = 2*pi*z/L
1803
+
1804
+ sol = sqrt(2)*sqrt(L)*r0**2*fresnelc(sqrt(2)*sqrt(L))*gamma(S.One/4)/(16*gamma(S(5)/4)) + L*r0**2/2
1805
+
1806
+ assert integrate(r0**2*cos(w*z)**2, (z, -L/2, L/2)) == sol
1807
+
1808
+
1809
+ def test_issue_15810():
1810
+ assert integrate(1/(2**(2*x/3) + 1), (x, 0, oo)) == Rational(3, 2)
1811
+
1812
+
1813
+ def test_issue_21024():
1814
+ x = Symbol('x', real=True, nonzero=True)
1815
+ f = log(x)*log(4*x) + log(3*x + exp(2))
1816
+ F = x*log(x)**2 + x*log(3*x + exp(2)) + x*(1 - 2*log(2)) + \
1817
+ (-2*x + 2*x*log(2))*log(x) + exp(2)*log(3*x + exp(2))/3
1818
+ assert F == integrate(f, x)
1819
+
1820
+ f = (x + exp(3))/x**2
1821
+ F = log(x) - exp(3)/x
1822
+ assert F == integrate(f, x)
1823
+
1824
+ f = (x**2 + exp(5))/x
1825
+ F = x**2/2 + exp(5)*log(x)
1826
+ assert F == integrate(f, x)
1827
+
1828
+ f = x/(2*x + tanh(1))
1829
+ F = x/2 - log(2*x + tanh(1))*tanh(1)/4
1830
+ assert F == integrate(f, x)
1831
+
1832
+ f = x - sinh(4)/x
1833
+ F = x**2/2 - log(x)*sinh(4)
1834
+ assert F == integrate(f, x)
1835
+
1836
+ f = log(x + exp(5)/x)
1837
+ F = x*log(x + exp(5)/x) - x + 2*exp(Rational(5, 2))*atan(x*exp(Rational(-5, 2)))
1838
+ assert F == integrate(f, x)
1839
+
1840
+ f = x**5/(x + E)
1841
+ F = x**5/5 - E*x**4/4 + x**3*exp(2)/3 - x**2*exp(3)/2 + x*exp(4) - exp(5)*log(x + E)
1842
+ assert F == integrate(f, x)
1843
+
1844
+ f = 4*x/(x + sinh(5))
1845
+ F = 4*x - 4*log(x + sinh(5))*sinh(5)
1846
+ assert F == integrate(f, x)
1847
+
1848
+ f = x**2/(2*x + sinh(2))
1849
+ F = x**2/4 - x*sinh(2)/4 + log(2*x + sinh(2))*sinh(2)**2/8
1850
+ assert F == integrate(f, x)
1851
+
1852
+ f = -x**2/(x + E)
1853
+ F = -x**2/2 + E*x - exp(2)*log(x + E)
1854
+ assert F == integrate(f, x)
1855
+
1856
+ f = (2*x + 3)*exp(5)/x
1857
+ F = 2*x*exp(5) + 3*exp(5)*log(x)
1858
+ assert F == integrate(f, x)
1859
+
1860
+ f = x + 2 + cosh(3)/x
1861
+ F = x**2/2 + 2*x + log(x)*cosh(3)
1862
+ assert F == integrate(f, x)
1863
+
1864
+ f = x - tanh(1)/x**3
1865
+ F = x**2/2 + tanh(1)/(2*x**2)
1866
+ assert F == integrate(f, x)
1867
+
1868
+ f = (3*x - exp(6))/x
1869
+ F = 3*x - exp(6)*log(x)
1870
+ assert F == integrate(f, x)
1871
+
1872
+ f = x**4/(x + exp(5))**2 + x
1873
+ F = x**3/3 + x**2*(Rational(1, 2) - exp(5)) + 3*x*exp(10) - 4*exp(15)*log(x + exp(5)) - exp(20)/(x + exp(5))
1874
+ assert F == integrate(f, x)
1875
+
1876
+ f = x*(x + exp(10)/x**2) + x
1877
+ F = x**3/3 + x**2/2 + exp(10)*log(x)
1878
+ assert F == integrate(f, x)
1879
+
1880
+ f = x + x/(5*x + sinh(3))
1881
+ F = x**2/2 + x/5 - log(5*x + sinh(3))*sinh(3)/25
1882
+ assert F == integrate(f, x)
1883
+
1884
+ f = (x + exp(3))/(2*x**2 + 2*x)
1885
+ F = exp(3)*log(x)/2 - exp(3)*log(x + 1)/2 + log(x + 1)/2
1886
+ assert F == integrate(f, x).expand()
1887
+
1888
+ f = log(x + 4*sinh(4))
1889
+ F = x*log(x + 4*sinh(4)) - x + 4*log(x + 4*sinh(4))*sinh(4)
1890
+ assert F == integrate(f, x)
1891
+
1892
+ f = -x + 20*(exp(-5) - atan(4)/x)**3*sin(4)/x
1893
+ F = (-x**2*exp(15)/2 + 20*log(x)*sin(4) - (-180*x**2*exp(5)*sin(4)*atan(4) + 90*x*exp(10)*sin(4)*atan(4)**2 - \
1894
+ 20*exp(15)*sin(4)*atan(4)**3)/(3*x**3))*exp(-15)
1895
+ assert F == integrate(f, x)
1896
+
1897
+ f = 2*x**2*exp(-4) + 6/x
1898
+ F_true = (2*x**3/3 + 6*exp(4)*log(x))*exp(-4)
1899
+ assert F_true == integrate(f, x)
1900
+
1901
+
1902
+ def test_issue_21721():
1903
+ a = Symbol('a')
1904
+ assert integrate(1/(pi*(1+(x-a)**2)),(x,-oo,oo)).expand() == \
1905
+ -Heaviside(im(a) - 1, 0) + Heaviside(im(a) + 1, 0)
1906
+
1907
+
1908
+ def test_issue_21831():
1909
+ theta = symbols('theta')
1910
+ assert integrate(cos(3*theta)/(5-4*cos(theta)), (theta, 0, 2*pi)) == pi/12
1911
+ integrand = cos(2*theta)/(5 - 4*cos(theta))
1912
+ assert integrate(integrand, (theta, 0, 2*pi)) == pi/6
1913
+
1914
+
1915
+ @slow
1916
+ def test_issue_22033_integral():
1917
+ assert integrate((x**2 - Rational(1, 4))**2 * sqrt(1 - x**2), (x, -1, 1)) == pi/32
1918
+
1919
+
1920
+ @slow
1921
+ def test_issue_21671():
1922
+ assert integrate(1,(z,x**2+y**2,2-x**2-y**2),(y,-sqrt(1-x**2),sqrt(1-x**2)),(x,-1,1)) == pi
1923
+ assert integrate(-4*(1 - x**2)**(S(3)/2)/3 + 2*sqrt(1 - x**2)*(2 - 2*x**2), (x, -1, 1)) == pi
1924
+
1925
+
1926
+ def test_issue_18527():
1927
+ # The manual integrator can not currently solve this. Assert that it does
1928
+ # not give an incorrect result involving Abs when x has real assumptions.
1929
+ xr = symbols('xr', real=True)
1930
+ expr = (cos(x)/(4+(sin(x))**2))
1931
+ res_real = integrate(expr.subs(x, xr), xr, manual=True).subs(xr, x)
1932
+ assert integrate(expr, x, manual=True) == res_real == Integral(expr, x)
1933
+
1934
+
1935
+ def test_issue_23718():
1936
+ f = 1/(b*cos(x) + a*sin(x))
1937
+ Fpos = (-log(-a/b + tan(x/2) - sqrt(a**2 + b**2)/b)/sqrt(a**2 + b**2)
1938
+ +log(-a/b + tan(x/2) + sqrt(a**2 + b**2)/b)/sqrt(a**2 + b**2))
1939
+ F = Piecewise(
1940
+ # XXX: The zoo case here is for a=b=0 so it should just be zoo or maybe
1941
+ # it doesn't really need to be included at all given that the original
1942
+ # integrand is really undefined in that case anyway.
1943
+ (zoo*(-log(tan(x/2) - 1) + log(tan(x/2) + 1)), Eq(a, 0) & Eq(b, 0)),
1944
+ (log(tan(x/2))/a, Eq(b, 0)),
1945
+ (-I/(-I*b*sin(x) + b*cos(x)), Eq(a, -I*b)),
1946
+ (I/(I*b*sin(x) + b*cos(x)), Eq(a, I*b)),
1947
+ (Fpos, True),
1948
+ )
1949
+ assert integrate(f, x) == F
1950
+
1951
+ ap, bp = symbols('a, b', positive=True)
1952
+ rep = {a: ap, b: bp}
1953
+ assert integrate(f.subs(rep), x) == Fpos.subs(rep)
1954
+
1955
+
1956
+ def test_issue_23566():
1957
+ i = integrate(1/sqrt(x**2-1), (x, -2, -1))
1958
+ assert i == -log(2 - sqrt(3))
1959
+ assert math.isclose(i.n(), 1.31695789692482)
1960
+
1961
+
1962
+ def test_pr_23583():
1963
+ # This result from meijerg is wrong. Check whether new result is correct when this test fail.
1964
+ assert integrate(1/sqrt((x - I)**2-1)) == Piecewise((acosh(x - I), Abs((x - I)**2) > 1), (-I*asin(x - I), True))
1965
+
1966
+
1967
+ def test_issue_7264():
1968
+ assert integrate(exp(x)*sqrt(1 + exp(2*x))) == sqrt(exp(2*x) + 1)*exp(x)/2 + asinh(exp(x))/2
1969
+
1970
+
1971
+ def test_issue_11254a():
1972
+ assert integrate(sech(x), (x, 0, 1)) == 2*atan(tanh(S.Half))
1973
+
1974
+
1975
+ def test_issue_11254b():
1976
+ assert integrate(csch(x), x) == log(tanh(x/2))
1977
+ assert integrate(csch(x), (x, 0, 1)) == oo
1978
+
1979
+
1980
+ def test_issue_11254d():
1981
+ # (sech(x)**2).rewrite(sinh)
1982
+ assert integrate(-1/sinh(x + I*pi/2, evaluate=False)**2, x) == -2/(exp(2*x) + 1)
1983
+ assert integrate(cosh(x)**(-2), x) == 2*tanh(x/2)/(tanh(x/2)**2 + 1)
1984
+
1985
+
1986
+ def test_issue_22863():
1987
+ i = integrate((3*x**3-x**2+2*x-4)/sqrt(x**2-3*x+2), (x, 0, 1))
1988
+ assert i == -101*sqrt(2)/8 - 135*log(3 - 2*sqrt(2))/16
1989
+ assert math.isclose(i.n(), -2.98126694400554)
1990
+
1991
+
1992
+ def test_issue_9723():
1993
+ assert integrate(sqrt(x + sqrt(x))) == \
1994
+ 2*sqrt(sqrt(x) + x)*(sqrt(x)/12 + x/3 - S(1)/8) + log(2*sqrt(x) + 2*sqrt(sqrt(x) + x) + 1)/8
1995
+ assert integrate(sqrt(2*x+3+sqrt(4*x+5))**3) == \
1996
+ sqrt(2*x + sqrt(4*x + 5) + 3) * \
1997
+ (9*x/10 + 11*(4*x + 5)**(S(3)/2)/40 + sqrt(4*x + 5)/40 + (4*x + 5)**2/10 + S(11)/10)/2
1998
+
1999
+
2000
+ def test_issue_23704():
2001
+ # XXX: This is testing that an exception is not raised in risch Ideally
2002
+ # manualintegrate (manual=True) would be able to compute this but
2003
+ # manualintegrate is very slow for this example so we don't test that here.
2004
+ assert (integrate(log(x)/x**2/(c*x**2+b*x+a),x, risch=True)
2005
+ == NonElementaryIntegral(log(x)/(a*x**2 + b*x**3 + c*x**4), x))
2006
+
2007
+
2008
+ def test_exp_substitution():
2009
+ assert integrate(1/sqrt(1-exp(2*x))) == log(sqrt(1 - exp(2*x)) - 1)/2 - log(sqrt(1 - exp(2*x)) + 1)/2
2010
+
2011
+
2012
+ def test_hyperbolic():
2013
+ assert integrate(coth(x)) == x - log(tanh(x) + 1) + log(tanh(x))
2014
+ assert integrate(sech(x)) == 2*atan(tanh(x/2))
2015
+ assert integrate(csch(x)) == log(tanh(x/2))
2016
+
2017
+
2018
+ def test_nested_pow():
2019
+ assert integrate(sqrt(x**2)) == x*sqrt(x**2)/2
2020
+ assert integrate(sqrt(x**(S(5)/3))) == 6*x*sqrt(x**(S(5)/3))/11
2021
+ assert integrate(1/sqrt(x**2)) == x*log(x)/sqrt(x**2)
2022
+ assert integrate(x*sqrt(x**(-4))) == x**2*sqrt(x**-4)*log(x)
2023
+
2024
+
2025
+ def test_sqrt_quadratic():
2026
+ assert integrate(1/sqrt(3*x**2+4*x+5)) == sqrt(3)*asinh(3*sqrt(11)*(x + S(2)/3)/11)/3
2027
+ assert integrate(1/sqrt(-3*x**2+4*x+5)) == sqrt(3)*asin(3*sqrt(19)*(x - S(2)/3)/19)/3
2028
+ assert integrate(1/sqrt(3*x**2+4*x-5)) == sqrt(3)*log(6*x + 2*sqrt(3)*sqrt(3*x**2 + 4*x - 5) + 4)/3
2029
+ assert integrate(1/sqrt(4*x**2-4*x+1)) == (x - S.Half)*log(x - S.Half)/(2*sqrt((x - S.Half)**2))
2030
+ assert integrate(1/sqrt(a+b*x+c*x**2), x) == \
2031
+ Piecewise((log(b + 2*sqrt(c)*sqrt(a + b*x + c*x**2) + 2*c*x)/sqrt(c), Ne(c, 0) & Ne(a - b**2/(4*c), 0)),
2032
+ ((b/(2*c) + x)*log(b/(2*c) + x)/sqrt(c*(b/(2*c) + x)**2), Ne(c, 0)),
2033
+ (2*sqrt(a + b*x)/b, Ne(b, 0)), (x/sqrt(a), True))
2034
+
2035
+ assert integrate((7*x+6)/sqrt(3*x**2+4*x+5)) == \
2036
+ 7*sqrt(3*x**2 + 4*x + 5)/3 + 4*sqrt(3)*asinh(3*sqrt(11)*(x + S(2)/3)/11)/9
2037
+ assert integrate((7*x+6)/sqrt(-3*x**2+4*x+5)) == \
2038
+ -7*sqrt(-3*x**2 + 4*x + 5)/3 + 32*sqrt(3)*asin(3*sqrt(19)*(x - S(2)/3)/19)/9
2039
+ assert integrate((7*x+6)/sqrt(3*x**2+4*x-5)) == \
2040
+ 7*sqrt(3*x**2 + 4*x - 5)/3 + 4*sqrt(3)*log(6*x + 2*sqrt(3)*sqrt(3*x**2 + 4*x - 5) + 4)/9
2041
+ assert integrate((d+e*x)/sqrt(a+b*x+c*x**2), x) == \
2042
+ Piecewise(((-b*e/(2*c) + d) *
2043
+ Piecewise((log(b + 2*sqrt(c)*sqrt(a + b*x + c*x**2) + 2*c*x)/sqrt(c), Ne(a - b**2/(4*c), 0)),
2044
+ ((b/(2*c) + x)*log(b/(2*c) + x)/sqrt(c*(b/(2*c) + x)**2), True)) +
2045
+ e*sqrt(a + b*x + c*x**2)/c, Ne(c, 0)),
2046
+ ((2*d*sqrt(a + b*x) + 2*e*(-a*sqrt(a + b*x) + (a + b*x)**(S(3)/2)/3)/b)/b, Ne(b, 0)),
2047
+ ((d*x + e*x**2/2)/sqrt(a), True))
2048
+
2049
+ assert integrate((3*x**3-x**2+2*x-4)/sqrt(x**2-3*x+2)) == \
2050
+ sqrt(x**2 - 3*x + 2)*(x**2 + 13*x/4 + S(101)/8) + 135*log(2*x + 2*sqrt(x**2 - 3*x + 2) - 3)/16
2051
+
2052
+ assert integrate(sqrt(53225*x**2-66732*x+23013)) == \
2053
+ (x/2 - S(16683)/53225)*sqrt(53225*x**2 - 66732*x + 23013) + \
2054
+ 111576969*sqrt(2129)*asinh(53225*x/10563 - S(11122)/3521)/1133160250
2055
+ assert integrate(sqrt(a+b*x+c*x**2), x) == \
2056
+ Piecewise(((a/2 - b**2/(8*c)) *
2057
+ Piecewise((log(b + 2*sqrt(c)*sqrt(a + b*x + c*x**2) + 2*c*x)/sqrt(c), Ne(a - b**2/(4*c), 0)),
2058
+ ((b/(2*c) + x)*log(b/(2*c) + x)/sqrt(c*(b/(2*c) + x)**2), True)) +
2059
+ (b/(4*c) + x/2)*sqrt(a + b*x + c*x**2), Ne(c, 0)),
2060
+ (2*(a + b*x)**(S(3)/2)/(3*b), Ne(b, 0)),
2061
+ (sqrt(a)*x, True))
2062
+
2063
+ assert integrate(x*sqrt(x**2+2*x+4)) == \
2064
+ (x**2/3 + x/6 + S(5)/6)*sqrt(x**2 + 2*x + 4) - 3*asinh(sqrt(3)*(x + 1)/3)/2
2065
+
2066
+
2067
+ def test_mul_pow_derivative():
2068
+ assert integrate(x*sec(x)*tan(x)) == x*sec(x) - log(tan(x) + sec(x))
2069
+ assert integrate(x*sec(x)**2, x) == x*tan(x) + log(cos(x))
2070
+ assert integrate(x**3*Derivative(f(x), (x, 4))) == \
2071
+ x**3*Derivative(f(x), (x, 3)) - 3*x**2*Derivative(f(x), (x, 2)) + 6*x*Derivative(f(x), x) - 6*f(x)
2072
+
2073
+
2074
+ def test_issue_20782():
2075
+ fun1 = Piecewise((0, x < 0.0), (1, True))
2076
+ fun2 = -Piecewise((0, x < 1.0), (1, True))
2077
+ fun_sum = fun1 + fun2
2078
+ L = (x, -float('Inf'), 1)
2079
+
2080
+ assert integrate(fun1, L) == 1
2081
+ assert integrate(fun2, L) == 0
2082
+ assert integrate(-fun1, L) == -1
2083
+ assert integrate(-fun2, L) == 0
2084
+ assert integrate(fun_sum, L) == 1.
2085
+ assert integrate(-fun_sum, L) == -1.
2086
+
2087
+
2088
+ def test_issue_20781():
2089
+ P = lambda a: Piecewise((0, x < a), (1, x >= a))
2090
+ f = lambda a: P(int(a)) + P(float(a))
2091
+ L = (x, -float('Inf'), x)
2092
+ f1 = integrate(f(1), L)
2093
+ assert f1 == 2*x - Min(1.0, x) - Min(x, Max(1.0, 1, evaluate=False))
2094
+ # XXX is_zero is True for S(0) and Float(0) and this is baked into
2095
+ # the code more deeply than the issue of Float(0) != S(0)
2096
+ assert integrate(f(0), (x, -float('Inf'), x)
2097
+ ) == 2*x - 2*Min(0, x)
2098
+
2099
+
2100
+ @slow
2101
+ def test_issue_19427():
2102
+ # <https://github.com/sympy/sympy/issues/19427>
2103
+ x = Symbol("x")
2104
+
2105
+ # Have always been okay:
2106
+ assert integrate((x ** 4) * sqrt(1 - x ** 2), (x, -1, 1)) == pi / 16
2107
+ assert integrate((-2 * x ** 2) * sqrt(1 - x ** 2), (x, -1, 1)) == -pi / 4
2108
+ assert integrate((1) * sqrt(1 - x ** 2), (x, -1, 1)) == pi / 2
2109
+
2110
+ # Sum of the above, used to incorrectly return 0 for a while:
2111
+ assert integrate((x ** 4 - 2 * x ** 2 + 1) * sqrt(1 - x ** 2), (x, -1, 1)) == 5 * pi / 16
2112
+
2113
+
2114
+ def test_issue_23942():
2115
+ I1 = Integral(1/sqrt(a*(1 + x)**3 + (1 + x)**2), (x, 0, z))
2116
+ assert I1.series(a, 1, n=1) == Integral(1/sqrt(x**3 + 4*x**2 + 5*x + 2), (x, 0, z)) + O(a - 1, (a, 1))
2117
+ I2 = Integral(1/sqrt(a*(4 - x)**4 + (5 + x)**2), (x, 0, z))
2118
+ assert I2.series(a, 2, n=1) == Integral(1/sqrt(2*x**4 - 32*x**3 + 193*x**2 - 502*x + 537), (x, 0, z)) + O(a - 2, (a, 2))
2119
+
2120
+
2121
+ def test_issue_25886():
2122
+ # https://github.com/sympy/sympy/issues/25886
2123
+ f = (1-x)*exp(0.937098661j*x)
2124
+ F_exp = (1.0*(-1.0671234968289*I*y
2125
+ + 1.13875255748434
2126
+ + 1.0671234968289*I)*exp(0.937098661*I*y)
2127
+ - 1.13875255748434*exp(0.937098661*I))
2128
+ F = integrate(f, (x, y, 1.0))
2129
+ assert F.is_same(F_exp, math.isclose)
2130
+
2131
+
2132
+ def test_old_issues():
2133
+ # https://github.com/sympy/sympy/issues/5212
2134
+ I1 = integrate(cos(log(x**2))/x)
2135
+ assert I1 == sin(log(x**2))/2
2136
+ # https://github.com/sympy/sympy/issues/5462
2137
+ I2 = integrate(1/(x**2+y**2)**(Rational(3,2)),x)
2138
+ assert I2 == x/(y**3*sqrt(x**2/y**2 + 1))
2139
+ # https://github.com/sympy/sympy/issues/6278
2140
+ I3 = integrate(1/(cos(x)+2),(x,0,2*pi))
2141
+ assert I3 == 2*sqrt(3)*pi/3
2142
+
2143
+
2144
+ def test_integral_issue_26566():
2145
+ # Define the symbols
2146
+ x = symbols('x', real=True)
2147
+ a = symbols('a', real=True, positive=True)
2148
+
2149
+ # Define the integral expression
2150
+ integral_expr = sin(a * (x + pi))**2
2151
+ symbolic_result = integrate(integral_expr, (x, -pi, -pi/2))
2152
+
2153
+ # Known correct result
2154
+ correct_result = pi / 4
2155
+
2156
+ # Substitute a specific value for 'a' to evaluate both results
2157
+ a_value = 1
2158
+ numeric_symbolic_result = symbolic_result.subs(a, a_value).evalf()
2159
+ numeric_correct_result = correct_result.evalf()
2160
+
2161
+ # Assert that the symbolic result matches the correct value
2162
+ assert simplify(numeric_symbolic_result - numeric_correct_result) == 0
2163
+
2164
+
2165
+ def test_definite_integral_with_floats_issue_27231():
2166
+ # Define the symbol and the integral expression
2167
+ x = symbols('x', real=True)
2168
+ integral_expr = sqrt(1 - 0.5625 * (x + 0.333333333333333) ** 2)
2169
+
2170
+ # Perform the definite integral with the known limits
2171
+ result_symbolic = integrate(integral_expr, (x, -1, 1))
2172
+ result_numeric = result_symbolic.evalf()
2173
+
2174
+ # Expected result with higher precision
2175
+ expected_result = sqrt(3) / 6 + 4 * pi / 9
2176
+
2177
+ # Verify that the result is approximately equal within a larger tolerance
2178
+ assert abs(result_numeric - expected_result.evalf()) < 1e-8
2179
+
2180
+
2181
+ def test_issue_27374():
2182
+ #https://github.com/sympy/sympy/issues/27374
2183
+ r = sqrt(x**2 + z**2)
2184
+ u = erf(a*r/sqrt(2))/r
2185
+ Ec = diff(u, z, z).subs([(x, sqrt(b*b-z*z))])
2186
+ expected_result = -2*sqrt(2)*b*a**3*exp(-b**2*a**2/2)/(3*sqrt(pi))
2187
+ assert simplify(integrate(Ec, (z, -b, b))) == expected_result
.venv/lib/python3.13/site-packages/sympy/integrals/tests/test_intpoly.py ADDED
@@ -0,0 +1,627 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.functions.elementary.complexes import Abs
2
+ from sympy.functions.elementary.miscellaneous import sqrt
3
+
4
+ from sympy.core import S, Rational
5
+
6
+ from sympy.integrals.intpoly import (decompose, best_origin, distance_to_side,
7
+ polytope_integrate, point_sort,
8
+ hyperplane_parameters, main_integrate3d,
9
+ main_integrate, polygon_integrate,
10
+ lineseg_integrate, integration_reduction,
11
+ integration_reduction_dynamic, is_vertex)
12
+
13
+ from sympy.geometry.line import Segment2D
14
+ from sympy.geometry.polygon import Polygon
15
+ from sympy.geometry.point import Point, Point2D
16
+ from sympy.abc import x, y, z
17
+
18
+ from sympy.testing.pytest import slow
19
+
20
+
21
+ def test_decompose():
22
+ assert decompose(x) == {1: x}
23
+ assert decompose(x**2) == {2: x**2}
24
+ assert decompose(x*y) == {2: x*y}
25
+ assert decompose(x + y) == {1: x + y}
26
+ assert decompose(x**2 + y) == {1: y, 2: x**2}
27
+ assert decompose(8*x**2 + 4*y + 7) == {0: 7, 1: 4*y, 2: 8*x**2}
28
+ assert decompose(x**2 + 3*y*x) == {2: x**2 + 3*x*y}
29
+ assert decompose(9*x**2 + y + 4*x + x**3 + y**2*x + 3) ==\
30
+ {0: 3, 1: 4*x + y, 2: 9*x**2, 3: x**3 + x*y**2}
31
+
32
+ assert decompose(x, True) == {x}
33
+ assert decompose(x ** 2, True) == {x**2}
34
+ assert decompose(x * y, True) == {x * y}
35
+ assert decompose(x + y, True) == {x, y}
36
+ assert decompose(x ** 2 + y, True) == {y, x ** 2}
37
+ assert decompose(8 * x ** 2 + 4 * y + 7, True) == {7, 4*y, 8*x**2}
38
+ assert decompose(x ** 2 + 3 * y * x, True) == {x ** 2, 3 * x * y}
39
+ assert decompose(9 * x ** 2 + y + 4 * x + x ** 3 + y ** 2 * x + 3, True) == \
40
+ {3, y, 4*x, 9*x**2, x*y**2, x**3}
41
+
42
+
43
+ def test_best_origin():
44
+ expr1 = y ** 2 * x ** 5 + y ** 5 * x ** 7 + 7 * x + x ** 12 + y ** 7 * x
45
+
46
+ l1 = Segment2D(Point(0, 3), Point(1, 1))
47
+ l2 = Segment2D(Point(S(3) / 2, 0), Point(S(3) / 2, 3))
48
+ l3 = Segment2D(Point(0, S(3) / 2), Point(3, S(3) / 2))
49
+ l4 = Segment2D(Point(0, 2), Point(2, 0))
50
+ l5 = Segment2D(Point(0, 2), Point(1, 1))
51
+ l6 = Segment2D(Point(2, 0), Point(1, 1))
52
+
53
+ assert best_origin((2, 1), 3, l1, expr1) == (0, 3)
54
+ # XXX: Should these return exact Rational output? Maybe best_origin should
55
+ # sympify its arguments...
56
+ assert best_origin((2, 0), 3, l2, x ** 7) == (1.5, 0)
57
+ assert best_origin((0, 2), 3, l3, x ** 7) == (0, 1.5)
58
+ assert best_origin((1, 1), 2, l4, x ** 7 * y ** 3) == (0, 2)
59
+ assert best_origin((1, 1), 2, l4, x ** 3 * y ** 7) == (2, 0)
60
+ assert best_origin((1, 1), 2, l5, x ** 2 * y ** 9) == (0, 2)
61
+ assert best_origin((1, 1), 2, l6, x ** 9 * y ** 2) == (2, 0)
62
+
63
+
64
+ @slow
65
+ def test_polytope_integrate():
66
+ # Convex 2-Polytopes
67
+ # Vertex representation
68
+ assert polytope_integrate(Polygon(Point(0, 0), Point(0, 2),
69
+ Point(4, 0)), 1) == 4
70
+ assert polytope_integrate(Polygon(Point(0, 0), Point(0, 1),
71
+ Point(1, 1), Point(1, 0)), x * y) ==\
72
+ Rational(1, 4)
73
+ assert polytope_integrate(Polygon(Point(0, 3), Point(5, 3), Point(1, 1)),
74
+ 6*x**2 - 40*y) == Rational(-935, 3)
75
+
76
+ assert polytope_integrate(Polygon(Point(0, 0), Point(0, sqrt(3)),
77
+ Point(sqrt(3), sqrt(3)),
78
+ Point(sqrt(3), 0)), 1) == 3
79
+
80
+ hexagon = Polygon(Point(0, 0), Point(-sqrt(3) / 2, S.Half),
81
+ Point(-sqrt(3) / 2, S(3) / 2), Point(0, 2),
82
+ Point(sqrt(3) / 2, S(3) / 2), Point(sqrt(3) / 2, S.Half))
83
+
84
+ assert polytope_integrate(hexagon, 1) == S(3*sqrt(3)) / 2
85
+
86
+ # Hyperplane representation
87
+ assert polytope_integrate([((-1, 0), 0), ((1, 2), 4),
88
+ ((0, -1), 0)], 1) == 4
89
+ assert polytope_integrate([((-1, 0), 0), ((0, 1), 1),
90
+ ((1, 0), 1), ((0, -1), 0)], x * y) == Rational(1, 4)
91
+ assert polytope_integrate([((0, 1), 3), ((1, -2), -1),
92
+ ((-2, -1), -3)], 6*x**2 - 40*y) == Rational(-935, 3)
93
+ assert polytope_integrate([((-1, 0), 0), ((0, sqrt(3)), 3),
94
+ ((sqrt(3), 0), 3), ((0, -1), 0)], 1) == 3
95
+
96
+ hexagon = [((Rational(-1, 2), -sqrt(3) / 2), 0),
97
+ ((-1, 0), sqrt(3) / 2),
98
+ ((Rational(-1, 2), sqrt(3) / 2), sqrt(3)),
99
+ ((S.Half, sqrt(3) / 2), sqrt(3)),
100
+ ((1, 0), sqrt(3) / 2),
101
+ ((S.Half, -sqrt(3) / 2), 0)]
102
+ assert polytope_integrate(hexagon, 1) == S(3*sqrt(3)) / 2
103
+
104
+ # Non-convex polytopes
105
+ # Vertex representation
106
+ assert polytope_integrate(Polygon(Point(-1, -1), Point(-1, 1),
107
+ Point(1, 1), Point(0, 0),
108
+ Point(1, -1)), 1) == 3
109
+ assert polytope_integrate(Polygon(Point(-1, -1), Point(-1, 1),
110
+ Point(0, 0), Point(1, 1),
111
+ Point(1, -1), Point(0, 0)), 1) == 2
112
+ # Hyperplane representation
113
+ assert polytope_integrate([((-1, 0), 1), ((0, 1), 1), ((1, -1), 0),
114
+ ((1, 1), 0), ((0, -1), 1)], 1) == 3
115
+ assert polytope_integrate([((-1, 0), 1), ((1, 1), 0), ((-1, 1), 0),
116
+ ((1, 0), 1), ((-1, -1), 0),
117
+ ((1, -1), 0)], 1) == 2
118
+
119
+ # Tests for 2D polytopes mentioned in Chin et al(Page 10):
120
+ # http://dilbert.engr.ucdavis.edu/~suku/quadrature/cls-integration.pdf
121
+ fig1 = Polygon(Point(1.220, -0.827), Point(-1.490, -4.503),
122
+ Point(-3.766, -1.622), Point(-4.240, -0.091),
123
+ Point(-3.160, 4), Point(-0.981, 4.447),
124
+ Point(0.132, 4.027))
125
+ assert polytope_integrate(fig1, x**2 + x*y + y**2) ==\
126
+ S(2031627344735367)/(8*10**12)
127
+
128
+ fig2 = Polygon(Point(4.561, 2.317), Point(1.491, -1.315),
129
+ Point(-3.310, -3.164), Point(-4.845, -3.110),
130
+ Point(-4.569, 1.867))
131
+ assert polytope_integrate(fig2, x**2 + x*y + y**2) ==\
132
+ S(517091313866043)/(16*10**11)
133
+
134
+ fig3 = Polygon(Point(-2.740, -1.888), Point(-3.292, 4.233),
135
+ Point(-2.723, -0.697), Point(-0.643, -3.151))
136
+ assert polytope_integrate(fig3, x**2 + x*y + y**2) ==\
137
+ S(147449361647041)/(8*10**12)
138
+
139
+ fig4 = Polygon(Point(0.211, -4.622), Point(-2.684, 3.851),
140
+ Point(0.468, 4.879), Point(4.630, -1.325),
141
+ Point(-0.411, -1.044))
142
+ assert polytope_integrate(fig4, x**2 + x*y + y**2) ==\
143
+ S(180742845225803)/(10**12)
144
+
145
+ # Tests for many polynomials with maximum degree given(2D case).
146
+ tri = Polygon(Point(0, 3), Point(5, 3), Point(1, 1))
147
+ polys = []
148
+ expr1 = x**9*y + x**7*y**3 + 2*x**2*y**8
149
+ expr2 = x**6*y**4 + x**5*y**5 + 2*y**10
150
+ expr3 = x**10 + x**9*y + x**8*y**2 + x**5*y**5
151
+ polys.extend((expr1, expr2, expr3))
152
+ result_dict = polytope_integrate(tri, polys, max_degree=10)
153
+ assert result_dict[expr1] == Rational(615780107, 594)
154
+ assert result_dict[expr2] == Rational(13062161, 27)
155
+ assert result_dict[expr3] == Rational(1946257153, 924)
156
+
157
+ tri = Polygon(Point(0, 3), Point(5, 3), Point(1, 1))
158
+ expr1 = x**7*y**1 + 2*x**2*y**6
159
+ expr2 = x**6*y**4 + x**5*y**5 + 2*y**10
160
+ expr3 = x**10 + x**9*y + x**8*y**2 + x**5*y**5
161
+ polys.extend((expr1, expr2, expr3))
162
+ assert polytope_integrate(tri, polys, max_degree=9) == \
163
+ {x**7*y + 2*x**2*y**6: Rational(489262, 9)}
164
+
165
+ # Tests when all integral of all monomials up to a max_degree is to be
166
+ # calculated.
167
+ assert polytope_integrate(Polygon(Point(0, 0), Point(0, 1),
168
+ Point(1, 1), Point(1, 0)),
169
+ max_degree=4) == {0: 0, 1: 1, x: S.Half,
170
+ x ** 2 * y ** 2: S.One / 9,
171
+ x ** 4: S.One / 5,
172
+ y ** 4: S.One / 5,
173
+ y: S.Half,
174
+ x * y ** 2: S.One / 6,
175
+ y ** 2: S.One / 3,
176
+ x ** 3: S.One / 4,
177
+ x ** 2 * y: S.One / 6,
178
+ x ** 3 * y: S.One / 8,
179
+ x * y: S.One / 4,
180
+ y ** 3: S.One / 4,
181
+ x ** 2: S.One / 3,
182
+ x * y ** 3: S.One / 8}
183
+
184
+ # Tests for 3D polytopes
185
+ cube1 = [[(0, 0, 0), (0, 6, 6), (6, 6, 6), (3, 6, 0),
186
+ (0, 6, 0), (6, 0, 6), (3, 0, 0), (0, 0, 6)],
187
+ [1, 2, 3, 4], [3, 2, 5, 6], [1, 7, 5, 2], [0, 6, 5, 7],
188
+ [1, 4, 0, 7], [0, 4, 3, 6]]
189
+ assert polytope_integrate(cube1, 1) == S(162)
190
+
191
+ # 3D Test cases in Chin et al(2015)
192
+ cube2 = [[(0, 0, 0), (0, 0, 5), (0, 5, 0), (0, 5, 5), (5, 0, 0),
193
+ (5, 0, 5), (5, 5, 0), (5, 5, 5)],
194
+ [3, 7, 6, 2], [1, 5, 7, 3], [5, 4, 6, 7], [0, 4, 5, 1],
195
+ [2, 0, 1, 3], [2, 6, 4, 0]]
196
+
197
+ cube3 = [[(0, 0, 0), (5, 0, 0), (5, 4, 0), (3, 2, 0), (3, 5, 0),
198
+ (0, 5, 0), (0, 0, 5), (5, 0, 5), (5, 4, 5), (3, 2, 5),
199
+ (3, 5, 5), (0, 5, 5)],
200
+ [6, 11, 5, 0], [1, 7, 6, 0], [5, 4, 3, 2, 1, 0], [11, 10, 4, 5],
201
+ [10, 9, 3, 4], [9, 8, 2, 3], [8, 7, 1, 2], [7, 8, 9, 10, 11, 6]]
202
+
203
+ cube4 = [[(0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1),
204
+ (S.One / 4, S.One / 4, S.One / 4)],
205
+ [0, 2, 1], [1, 3, 0], [4, 2, 3], [4, 3, 1],
206
+ [0, 1, 2], [2, 4, 1], [0, 3, 2]]
207
+
208
+ assert polytope_integrate(cube2, x ** 2 + y ** 2 + x * y + z ** 2) ==\
209
+ Rational(15625, 4)
210
+ assert polytope_integrate(cube3, x ** 2 + y ** 2 + x * y + z ** 2) ==\
211
+ S(33835) / 12
212
+ assert polytope_integrate(cube4, x ** 2 + y ** 2 + x * y + z ** 2) ==\
213
+ S(37) / 960
214
+
215
+ # Test cases from Mathematica's PolyhedronData library
216
+ octahedron = [[(S.NegativeOne / sqrt(2), 0, 0), (0, S.One / sqrt(2), 0),
217
+ (0, 0, S.NegativeOne / sqrt(2)), (0, 0, S.One / sqrt(2)),
218
+ (0, S.NegativeOne / sqrt(2), 0), (S.One / sqrt(2), 0, 0)],
219
+ [3, 4, 5], [3, 5, 1], [3, 1, 0], [3, 0, 4], [4, 0, 2],
220
+ [4, 2, 5], [2, 0, 1], [5, 2, 1]]
221
+
222
+ assert polytope_integrate(octahedron, 1) == sqrt(2) / 3
223
+
224
+ great_stellated_dodecahedron =\
225
+ [[(-0.32491969623290634095, 0, 0.42532540417601993887),
226
+ (0.32491969623290634095, 0, -0.42532540417601993887),
227
+ (-0.52573111211913359231, 0, 0.10040570794311363956),
228
+ (0.52573111211913359231, 0, -0.10040570794311363956),
229
+ (-0.10040570794311363956, -0.3090169943749474241, 0.42532540417601993887),
230
+ (-0.10040570794311363956, 0.30901699437494742410, 0.42532540417601993887),
231
+ (0.10040570794311363956, -0.3090169943749474241, -0.42532540417601993887),
232
+ (0.10040570794311363956, 0.30901699437494742410, -0.42532540417601993887),
233
+ (-0.16245984811645317047, -0.5, 0.10040570794311363956),
234
+ (-0.16245984811645317047, 0.5, 0.10040570794311363956),
235
+ (0.16245984811645317047, -0.5, -0.10040570794311363956),
236
+ (0.16245984811645317047, 0.5, -0.10040570794311363956),
237
+ (-0.42532540417601993887, -0.3090169943749474241, -0.10040570794311363956),
238
+ (-0.42532540417601993887, 0.30901699437494742410, -0.10040570794311363956),
239
+ (-0.26286555605956679615, 0.1909830056250525759, -0.42532540417601993887),
240
+ (-0.26286555605956679615, -0.1909830056250525759, -0.42532540417601993887),
241
+ (0.26286555605956679615, 0.1909830056250525759, 0.42532540417601993887),
242
+ (0.26286555605956679615, -0.1909830056250525759, 0.42532540417601993887),
243
+ (0.42532540417601993887, -0.3090169943749474241, 0.10040570794311363956),
244
+ (0.42532540417601993887, 0.30901699437494742410, 0.10040570794311363956)],
245
+ [12, 3, 0, 6, 16], [17, 7, 0, 3, 13],
246
+ [9, 6, 0, 7, 8], [18, 2, 1, 4, 14],
247
+ [15, 5, 1, 2, 19], [11, 4, 1, 5, 10],
248
+ [8, 19, 2, 18, 9], [10, 13, 3, 12, 11],
249
+ [16, 14, 4, 11, 12], [13, 10, 5, 15, 17],
250
+ [14, 16, 6, 9, 18], [19, 8, 7, 17, 15]]
251
+ # Actual volume is : 0.163118960624632
252
+ assert Abs(polytope_integrate(great_stellated_dodecahedron, 1) -\
253
+ 0.163118960624632) < 1e-12
254
+
255
+ expr = x **2 + y ** 2 + z ** 2
256
+ octahedron_five_compound = [[(0, -0.7071067811865475244, 0),
257
+ (0, 0.70710678118654752440, 0),
258
+ (0.1148764602736805918,
259
+ -0.35355339059327376220, -0.60150095500754567366),
260
+ (0.1148764602736805918, 0.35355339059327376220,
261
+ -0.60150095500754567366),
262
+ (0.18587401723009224507,
263
+ -0.57206140281768429760, 0.37174803446018449013),
264
+ (0.18587401723009224507, 0.57206140281768429760,
265
+ 0.37174803446018449013),
266
+ (0.30075047750377283683, -0.21850801222441053540,
267
+ 0.60150095500754567366),
268
+ (0.30075047750377283683, 0.21850801222441053540,
269
+ 0.60150095500754567366),
270
+ (0.48662449473386508189, -0.35355339059327376220,
271
+ -0.37174803446018449013),
272
+ (0.48662449473386508189, 0.35355339059327376220,
273
+ -0.37174803446018449013),
274
+ (-0.60150095500754567366, 0, -0.37174803446018449013),
275
+ (-0.30075047750377283683, -0.21850801222441053540,
276
+ -0.60150095500754567366),
277
+ (-0.30075047750377283683, 0.21850801222441053540,
278
+ -0.60150095500754567366),
279
+ (0.60150095500754567366, 0, 0.37174803446018449013),
280
+ (0.4156269377774534286, -0.57206140281768429760, 0),
281
+ (0.4156269377774534286, 0.57206140281768429760, 0),
282
+ (0.37174803446018449013, 0, -0.60150095500754567366),
283
+ (-0.4156269377774534286, -0.57206140281768429760, 0),
284
+ (-0.4156269377774534286, 0.57206140281768429760, 0),
285
+ (-0.67249851196395732696, -0.21850801222441053540, 0),
286
+ (-0.67249851196395732696, 0.21850801222441053540, 0),
287
+ (0.67249851196395732696, -0.21850801222441053540, 0),
288
+ (0.67249851196395732696, 0.21850801222441053540, 0),
289
+ (-0.37174803446018449013, 0, 0.60150095500754567366),
290
+ (-0.48662449473386508189, -0.35355339059327376220,
291
+ 0.37174803446018449013),
292
+ (-0.48662449473386508189, 0.35355339059327376220,
293
+ 0.37174803446018449013),
294
+ (-0.18587401723009224507, -0.57206140281768429760,
295
+ -0.37174803446018449013),
296
+ (-0.18587401723009224507, 0.57206140281768429760,
297
+ -0.37174803446018449013),
298
+ (-0.11487646027368059176, -0.35355339059327376220,
299
+ 0.60150095500754567366),
300
+ (-0.11487646027368059176, 0.35355339059327376220,
301
+ 0.60150095500754567366)],
302
+ [0, 10, 16], [23, 10, 0], [16, 13, 0],
303
+ [0, 13, 23], [16, 10, 1], [1, 10, 23],
304
+ [1, 13, 16], [23, 13, 1], [2, 4, 19],
305
+ [22, 4, 2], [2, 19, 27], [27, 22, 2],
306
+ [20, 5, 3], [3, 5, 21], [26, 20, 3],
307
+ [3, 21, 26], [29, 19, 4], [4, 22, 29],
308
+ [5, 20, 28], [28, 21, 5], [6, 8, 15],
309
+ [17, 8, 6], [6, 15, 25], [25, 17, 6],
310
+ [14, 9, 7], [7, 9, 18], [24, 14, 7],
311
+ [7, 18, 24], [8, 12, 15], [17, 12, 8],
312
+ [14, 11, 9], [9, 11, 18], [11, 14, 24],
313
+ [24, 18, 11], [25, 15, 12], [12, 17, 25],
314
+ [29, 27, 19], [20, 26, 28], [28, 26, 21],
315
+ [22, 27, 29]]
316
+ assert Abs(polytope_integrate(octahedron_five_compound, expr)) - 0.353553\
317
+ < 1e-6
318
+
319
+ cube_five_compound = [[(-0.1624598481164531631, -0.5, -0.6881909602355867691),
320
+ (-0.1624598481164531631, 0.5, -0.6881909602355867691),
321
+ (0.1624598481164531631, -0.5, 0.68819096023558676910),
322
+ (0.1624598481164531631, 0.5, 0.68819096023558676910),
323
+ (-0.52573111211913359231, 0, -0.6881909602355867691),
324
+ (0.52573111211913359231, 0, 0.68819096023558676910),
325
+ (-0.26286555605956679615, -0.8090169943749474241,
326
+ -0.1624598481164531631),
327
+ (-0.26286555605956679615, 0.8090169943749474241,
328
+ -0.1624598481164531631),
329
+ (0.26286555605956680301, -0.8090169943749474241,
330
+ 0.1624598481164531631),
331
+ (0.26286555605956680301, 0.8090169943749474241,
332
+ 0.1624598481164531631),
333
+ (-0.42532540417601993887, -0.3090169943749474241,
334
+ 0.68819096023558676910),
335
+ (-0.42532540417601993887, 0.30901699437494742410,
336
+ 0.68819096023558676910),
337
+ (0.42532540417601996609, -0.3090169943749474241,
338
+ -0.6881909602355867691),
339
+ (0.42532540417601996609, 0.30901699437494742410,
340
+ -0.6881909602355867691),
341
+ (-0.6881909602355867691, -0.5, 0.1624598481164531631),
342
+ (-0.6881909602355867691, 0.5, 0.1624598481164531631),
343
+ (0.68819096023558676910, -0.5, -0.1624598481164531631),
344
+ (0.68819096023558676910, 0.5, -0.1624598481164531631),
345
+ (-0.85065080835203998877, 0, -0.1624598481164531631),
346
+ (0.85065080835203993218, 0, 0.1624598481164531631)],
347
+ [18, 10, 3, 7], [13, 19, 8, 0], [18, 0, 8, 10],
348
+ [3, 19, 13, 7], [18, 7, 13, 0], [8, 19, 3, 10],
349
+ [6, 2, 11, 18], [1, 9, 19, 12], [11, 9, 1, 18],
350
+ [6, 12, 19, 2], [1, 12, 6, 18], [11, 2, 19, 9],
351
+ [4, 14, 11, 7], [17, 5, 8, 12], [4, 12, 8, 14],
352
+ [11, 5, 17, 7], [4, 7, 17, 12], [8, 5, 11, 14],
353
+ [6, 10, 15, 4], [13, 9, 5, 16], [15, 9, 13, 4],
354
+ [6, 16, 5, 10], [13, 16, 6, 4], [15, 10, 5, 9],
355
+ [14, 15, 1, 0], [16, 17, 3, 2], [14, 2, 3, 15],
356
+ [1, 17, 16, 0], [14, 0, 16, 2], [3, 17, 1, 15]]
357
+ assert Abs(polytope_integrate(cube_five_compound, expr) - 1.25) < 1e-12
358
+
359
+ echidnahedron = [[(0, 0, -2.4898982848827801995),
360
+ (0, 0, 2.4898982848827802734),
361
+ (0, -4.2360679774997896964, -2.4898982848827801995),
362
+ (0, -4.2360679774997896964, 2.4898982848827802734),
363
+ (0, 4.2360679774997896964, -2.4898982848827801995),
364
+ (0, 4.2360679774997896964, 2.4898982848827802734),
365
+ (-4.0287400534704067567, -1.3090169943749474241, -2.4898982848827801995),
366
+ (-4.0287400534704067567, -1.3090169943749474241, 2.4898982848827802734),
367
+ (-4.0287400534704067567, 1.3090169943749474241, -2.4898982848827801995),
368
+ (-4.0287400534704067567, 1.3090169943749474241, 2.4898982848827802734),
369
+ (4.0287400534704069747, -1.3090169943749474241, -2.4898982848827801995),
370
+ (4.0287400534704069747, -1.3090169943749474241, 2.4898982848827802734),
371
+ (4.0287400534704069747, 1.3090169943749474241, -2.4898982848827801995),
372
+ (4.0287400534704069747, 1.3090169943749474241, 2.4898982848827802734),
373
+ (-2.4898982848827801995, -3.4270509831248422723, -2.4898982848827801995),
374
+ (-2.4898982848827801995, -3.4270509831248422723, 2.4898982848827802734),
375
+ (-2.4898982848827801995, 3.4270509831248422723, -2.4898982848827801995),
376
+ (-2.4898982848827801995, 3.4270509831248422723, 2.4898982848827802734),
377
+ (2.4898982848827802734, -3.4270509831248422723, -2.4898982848827801995),
378
+ (2.4898982848827802734, -3.4270509831248422723, 2.4898982848827802734),
379
+ (2.4898982848827802734, 3.4270509831248422723, -2.4898982848827801995),
380
+ (2.4898982848827802734, 3.4270509831248422723, 2.4898982848827802734),
381
+ (-4.7169310137059934362, -0.8090169943749474241, -1.1135163644116066184),
382
+ (-4.7169310137059934362, 0.8090169943749474241, -1.1135163644116066184),
383
+ (4.7169310137059937438, -0.8090169943749474241, 1.11351636441160673519),
384
+ (4.7169310137059937438, 0.8090169943749474241, 1.11351636441160673519),
385
+ (-4.2916056095299737777, -2.1180339887498948482, 1.11351636441160673519),
386
+ (-4.2916056095299737777, 2.1180339887498948482, 1.11351636441160673519),
387
+ (4.2916056095299737777, -2.1180339887498948482, -1.1135163644116066184),
388
+ (4.2916056095299737777, 2.1180339887498948482, -1.1135163644116066184),
389
+ (-3.6034146492943870399, 0, -3.3405490932348205213),
390
+ (3.6034146492943870399, 0, 3.3405490932348202056),
391
+ (-3.3405490932348205213, -3.4270509831248422723, 1.11351636441160673519),
392
+ (-3.3405490932348205213, 3.4270509831248422723, 1.11351636441160673519),
393
+ (3.3405490932348202056, -3.4270509831248422723, -1.1135163644116066184),
394
+ (3.3405490932348202056, 3.4270509831248422723, -1.1135163644116066184),
395
+ (-2.9152236890588002395, -2.1180339887498948482, 3.3405490932348202056),
396
+ (-2.9152236890588002395, 2.1180339887498948482, 3.3405490932348202056),
397
+ (2.9152236890588002395, -2.1180339887498948482, -3.3405490932348205213),
398
+ (2.9152236890588002395, 2.1180339887498948482, -3.3405490932348205213),
399
+ (-2.2270327288232132368, 0, -1.1135163644116066184),
400
+ (-2.2270327288232132368, -4.2360679774997896964, -1.1135163644116066184),
401
+ (-2.2270327288232132368, 4.2360679774997896964, -1.1135163644116066184),
402
+ (2.2270327288232134704, 0, 1.11351636441160673519),
403
+ (2.2270327288232134704, -4.2360679774997896964, 1.11351636441160673519),
404
+ (2.2270327288232134704, 4.2360679774997896964, 1.11351636441160673519),
405
+ (-1.8017073246471935200, -1.3090169943749474241, 1.11351636441160673519),
406
+ (-1.8017073246471935200, 1.3090169943749474241, 1.11351636441160673519),
407
+ (1.8017073246471935043, -1.3090169943749474241, -1.1135163644116066184),
408
+ (1.8017073246471935043, 1.3090169943749474241, -1.1135163644116066184),
409
+ (-1.3763819204711735382, 0, -4.7169310137059934362),
410
+ (-1.3763819204711735382, 0, 0.26286555605956679615),
411
+ (1.37638192047117353821, 0, 4.7169310137059937438),
412
+ (1.37638192047117353821, 0, -0.26286555605956679615),
413
+ (-1.1135163644116066184, -3.4270509831248422723, -3.3405490932348205213),
414
+ (-1.1135163644116066184, -0.8090169943749474241, 4.7169310137059937438),
415
+ (-1.1135163644116066184, -0.8090169943749474241, -0.26286555605956679615),
416
+ (-1.1135163644116066184, 0.8090169943749474241, 4.7169310137059937438),
417
+ (-1.1135163644116066184, 0.8090169943749474241, -0.26286555605956679615),
418
+ (-1.1135163644116066184, 3.4270509831248422723, -3.3405490932348205213),
419
+ (1.11351636441160673519, -3.4270509831248422723, 3.3405490932348202056),
420
+ (1.11351636441160673519, -0.8090169943749474241, -4.7169310137059934362),
421
+ (1.11351636441160673519, -0.8090169943749474241, 0.26286555605956679615),
422
+ (1.11351636441160673519, 0.8090169943749474241, -4.7169310137059934362),
423
+ (1.11351636441160673519, 0.8090169943749474241, 0.26286555605956679615),
424
+ (1.11351636441160673519, 3.4270509831248422723, 3.3405490932348202056),
425
+ (-0.85065080835203998877, 0, 1.11351636441160673519),
426
+ (0.85065080835203993218, 0, -1.1135163644116066184),
427
+ (-0.6881909602355867691, -0.5, -1.1135163644116066184),
428
+ (-0.6881909602355867691, 0.5, -1.1135163644116066184),
429
+ (-0.6881909602355867691, -4.7360679774997896964, -1.1135163644116066184),
430
+ (-0.6881909602355867691, -2.1180339887498948482, -1.1135163644116066184),
431
+ (-0.6881909602355867691, 2.1180339887498948482, -1.1135163644116066184),
432
+ (-0.6881909602355867691, 4.7360679774997896964, -1.1135163644116066184),
433
+ (0.68819096023558676910, -0.5, 1.11351636441160673519),
434
+ (0.68819096023558676910, 0.5, 1.11351636441160673519),
435
+ (0.68819096023558676910, -4.7360679774997896964, 1.11351636441160673519),
436
+ (0.68819096023558676910, -2.1180339887498948482, 1.11351636441160673519),
437
+ (0.68819096023558676910, 2.1180339887498948482, 1.11351636441160673519),
438
+ (0.68819096023558676910, 4.7360679774997896964, 1.11351636441160673519),
439
+ (-0.42532540417601993887, -1.3090169943749474241, -4.7169310137059934362),
440
+ (-0.42532540417601993887, -1.3090169943749474241, 0.26286555605956679615),
441
+ (-0.42532540417601993887, 1.3090169943749474241, -4.7169310137059934362),
442
+ (-0.42532540417601993887, 1.3090169943749474241, 0.26286555605956679615),
443
+ (-0.26286555605956679615, -0.8090169943749474241, 1.11351636441160673519),
444
+ (-0.26286555605956679615, 0.8090169943749474241, 1.11351636441160673519),
445
+ (0.26286555605956679615, -0.8090169943749474241, -1.1135163644116066184),
446
+ (0.26286555605956679615, 0.8090169943749474241, -1.1135163644116066184),
447
+ (0.42532540417601996609, -1.3090169943749474241, 4.7169310137059937438),
448
+ (0.42532540417601996609, -1.3090169943749474241, -0.26286555605956679615),
449
+ (0.42532540417601996609, 1.3090169943749474241, 4.7169310137059937438),
450
+ (0.42532540417601996609, 1.3090169943749474241, -0.26286555605956679615)],
451
+ [9, 66, 47], [44, 62, 77], [20, 91, 49], [33, 47, 83],
452
+ [3, 77, 84], [12, 49, 53], [36, 84, 66], [28, 53, 62],
453
+ [73, 83, 91], [15, 84, 46], [25, 64, 43], [16, 58, 72],
454
+ [26, 46, 51], [11, 43, 74], [4, 72, 91], [60, 74, 84],
455
+ [35, 91, 64], [23, 51, 58], [19, 74, 77], [79, 83, 78],
456
+ [6, 56, 40], [76, 77, 81], [21, 78, 75], [8, 40, 58],
457
+ [31, 75, 74], [42, 58, 83], [41, 81, 56], [13, 75, 43],
458
+ [27, 51, 47], [2, 89, 71], [24, 43, 62], [17, 47, 85],
459
+ [14, 71, 56], [65, 85, 75], [22, 56, 51], [34, 62, 89],
460
+ [5, 85, 78], [32, 81, 46], [10, 53, 48], [45, 78, 64],
461
+ [7, 46, 66], [18, 48, 89], [37, 66, 85], [70, 89, 81],
462
+ [29, 64, 53], [88, 74, 1], [38, 67, 48], [42, 83, 72],
463
+ [57, 1, 85], [34, 48, 62], [59, 72, 87], [19, 62, 74],
464
+ [63, 87, 67], [17, 85, 83], [52, 75, 1], [39, 87, 49],
465
+ [22, 51, 40], [55, 1, 66], [29, 49, 64], [30, 40, 69],
466
+ [13, 64, 75], [82, 69, 87], [7, 66, 51], [90, 85, 1],
467
+ [59, 69, 72], [70, 81, 71], [88, 1, 84], [73, 72, 83],
468
+ [54, 71, 68], [5, 83, 85], [50, 68, 69], [3, 84, 81],
469
+ [57, 66, 1], [30, 68, 40], [28, 62, 48], [52, 1, 74],
470
+ [23, 40, 51], [38, 48, 86], [9, 51, 66], [80, 86, 68],
471
+ [11, 74, 62], [55, 84, 1], [54, 86, 71], [35, 64, 49],
472
+ [90, 1, 75], [41, 71, 81], [39, 49, 67], [15, 81, 84],
473
+ [61, 67, 86], [21, 75, 64], [24, 53, 43], [50, 69, 0],
474
+ [37, 85, 47], [31, 43, 75], [61, 0, 67], [27, 47, 58],
475
+ [10, 67, 53], [8, 58, 69], [90, 75, 85], [45, 91, 78],
476
+ [80, 68, 0], [36, 66, 46], [65, 78, 85], [63, 0, 87],
477
+ [32, 46, 56], [20, 87, 91], [14, 56, 68], [57, 85, 66],
478
+ [33, 58, 47], [61, 86, 0], [60, 84, 77], [37, 47, 66],
479
+ [82, 0, 69], [44, 77, 89], [16, 69, 58], [18, 89, 86],
480
+ [55, 66, 84], [26, 56, 46], [63, 67, 0], [31, 74, 43],
481
+ [36, 46, 84], [50, 0, 68], [25, 43, 53], [6, 68, 56],
482
+ [12, 53, 67], [88, 84, 74], [76, 89, 77], [82, 87, 0],
483
+ [65, 75, 78], [60, 77, 74], [80, 0, 86], [79, 78, 91],
484
+ [2, 86, 89], [4, 91, 87], [52, 74, 75], [21, 64, 78],
485
+ [18, 86, 48], [23, 58, 40], [5, 78, 83], [28, 48, 53],
486
+ [6, 40, 68], [25, 53, 64], [54, 68, 86], [33, 83, 58],
487
+ [17, 83, 47], [12, 67, 49], [41, 56, 71], [9, 47, 51],
488
+ [35, 49, 91], [2, 71, 86], [79, 91, 83], [38, 86, 67],
489
+ [26, 51, 56], [7, 51, 46], [4, 87, 72], [34, 89, 48],
490
+ [15, 46, 81], [42, 72, 58], [10, 48, 67], [27, 58, 51],
491
+ [39, 67, 87], [76, 81, 89], [3, 81, 77], [8, 69, 40],
492
+ [29, 53, 49], [19, 77, 62], [22, 40, 56], [20, 49, 87],
493
+ [32, 56, 81], [59, 87, 69], [24, 62, 53], [11, 62, 43],
494
+ [14, 68, 71], [73, 91, 72], [13, 43, 64], [70, 71, 89],
495
+ [16, 72, 69], [44, 89, 62], [30, 69, 68], [45, 64, 91]]
496
+ # Actual volume is : 51.405764746872634
497
+ assert Abs(polytope_integrate(echidnahedron, 1) - 51.4057647468726) < 1e-12
498
+ assert Abs(polytope_integrate(echidnahedron, expr) - 253.569603474519) <\
499
+ 1e-12
500
+
501
+ # Tests for many polynomials with maximum degree given(2D case).
502
+ assert polytope_integrate(cube2, [x**2, y*z], max_degree=2) == \
503
+ {y * z: 3125 / S(4), x ** 2: 3125 / S(3)}
504
+
505
+ assert polytope_integrate(cube2, max_degree=2) == \
506
+ {1: 125, x: 625 / S(2), x * z: 3125 / S(4), y: 625 / S(2),
507
+ y * z: 3125 / S(4), z ** 2: 3125 / S(3), y ** 2: 3125 / S(3),
508
+ z: 625 / S(2), x * y: 3125 / S(4), x ** 2: 3125 / S(3)}
509
+
510
+ def test_point_sort():
511
+ assert point_sort([Point(0, 0), Point(1, 0), Point(1, 1)]) == \
512
+ [Point2D(1, 1), Point2D(1, 0), Point2D(0, 0)]
513
+
514
+ fig6 = Polygon((0, 0), (1, 0), (1, 1))
515
+ assert polytope_integrate(fig6, x*y) == Rational(-1, 8)
516
+ assert polytope_integrate(fig6, x*y, clockwise = True) == Rational(1, 8)
517
+
518
+
519
+ def test_polytopes_intersecting_sides():
520
+ fig5 = Polygon(Point(-4.165, -0.832), Point(-3.668, 1.568),
521
+ Point(-3.266, 1.279), Point(-1.090, -2.080),
522
+ Point(3.313, -0.683), Point(3.033, -4.845),
523
+ Point(-4.395, 4.840), Point(-1.007, -3.328))
524
+ assert polytope_integrate(fig5, x**2 + x*y + y**2) ==\
525
+ S(1633405224899363)/(24*10**12)
526
+
527
+ fig6 = Polygon(Point(-3.018, -4.473), Point(-0.103, 2.378),
528
+ Point(-1.605, -2.308), Point(4.516, -0.771),
529
+ Point(4.203, 0.478))
530
+ assert polytope_integrate(fig6, x**2 + x*y + y**2) ==\
531
+ S(88161333955921)/(3*10**12)
532
+
533
+
534
+ def test_max_degree():
535
+ polygon = Polygon((0, 0), (0, 1), (1, 1), (1, 0))
536
+ polys = [1, x, y, x*y, x**2*y, x*y**2]
537
+ assert polytope_integrate(polygon, polys, max_degree=3) == \
538
+ {1: 1, x: S.Half, y: S.Half, x*y: Rational(1, 4), x**2*y: Rational(1, 6), x*y**2: Rational(1, 6)}
539
+ assert polytope_integrate(polygon, polys, max_degree=2) == \
540
+ {1: 1, x: S.Half, y: S.Half, x*y: Rational(1, 4)}
541
+ assert polytope_integrate(polygon, polys, max_degree=1) == \
542
+ {1: 1, x: S.Half, y: S.Half}
543
+
544
+
545
+ def test_main_integrate3d():
546
+ cube = [[(0, 0, 0), (0, 0, 5), (0, 5, 0), (0, 5, 5), (5, 0, 0),\
547
+ (5, 0, 5), (5, 5, 0), (5, 5, 5)],\
548
+ [2, 6, 7, 3], [3, 7, 5, 1], [7, 6, 4, 5], [1, 5, 4, 0],\
549
+ [3, 1, 0, 2], [0, 4, 6, 2]]
550
+ vertices = cube[0]
551
+ faces = cube[1:]
552
+ hp_params = hyperplane_parameters(faces, vertices)
553
+ assert main_integrate3d(1, faces, vertices, hp_params) == -125
554
+ assert main_integrate3d(1, faces, vertices, hp_params, max_degree=1) == \
555
+ {1: -125, y: Rational(-625, 2), z: Rational(-625, 2), x: Rational(-625, 2)}
556
+
557
+
558
+ def test_main_integrate():
559
+ triangle = Polygon((0, 3), (5, 3), (1, 1))
560
+ facets = triangle.sides
561
+ hp_params = hyperplane_parameters(triangle)
562
+ assert main_integrate(x**2 + y**2, facets, hp_params) == Rational(325, 6)
563
+ assert main_integrate(x**2 + y**2, facets, hp_params, max_degree=1) == \
564
+ {0: 0, 1: 5, y: Rational(35, 3), x: 10}
565
+
566
+
567
+ def test_polygon_integrate():
568
+ cube = [[(0, 0, 0), (0, 0, 5), (0, 5, 0), (0, 5, 5), (5, 0, 0),\
569
+ (5, 0, 5), (5, 5, 0), (5, 5, 5)],\
570
+ [2, 6, 7, 3], [3, 7, 5, 1], [7, 6, 4, 5], [1, 5, 4, 0],\
571
+ [3, 1, 0, 2], [0, 4, 6, 2]]
572
+ facet = cube[1]
573
+ facets = cube[1:]
574
+ vertices = cube[0]
575
+ assert polygon_integrate(facet, [(0, 1, 0), 5], 0, facets, vertices, 1, 0) == -25
576
+
577
+
578
+ def test_distance_to_side():
579
+ point = (0, 0, 0)
580
+ assert distance_to_side(point, [(0, 0, 1), (0, 1, 0)], (1, 0, 0)) == -sqrt(2)/2
581
+
582
+
583
+ def test_lineseg_integrate():
584
+ polygon = [(0, 5, 0), (5, 5, 0), (5, 5, 5), (0, 5, 5)]
585
+ line_seg = [(0, 5, 0), (5, 5, 0)]
586
+ assert lineseg_integrate(polygon, 0, line_seg, 1, 0) == 5
587
+ assert lineseg_integrate(polygon, 0, line_seg, 0, 0) == 0
588
+
589
+
590
+ def test_integration_reduction():
591
+ triangle = Polygon(Point(0, 3), Point(5, 3), Point(1, 1))
592
+ facets = triangle.sides
593
+ a, b = hyperplane_parameters(triangle)[0]
594
+ assert integration_reduction(facets, 0, a, b, 1, (x, y), 0) == 5
595
+ assert integration_reduction(facets, 0, a, b, 0, (x, y), 0) == 0
596
+
597
+
598
+ def test_integration_reduction_dynamic():
599
+ triangle = Polygon(Point(0, 3), Point(5, 3), Point(1, 1))
600
+ facets = triangle.sides
601
+ a, b = hyperplane_parameters(triangle)[0]
602
+ x0 = facets[0].points[0]
603
+ monomial_values = [[0, 0, 0, 0], [1, 0, 0, 5],\
604
+ [y, 0, 1, 15], [x, 1, 0, None]]
605
+
606
+ assert integration_reduction_dynamic(facets, 0, a, b, x, 1, (x, y), 1,\
607
+ 0, 1, x0, monomial_values, 3) == Rational(25, 2)
608
+ assert integration_reduction_dynamic(facets, 0, a, b, 0, 1, (x, y), 1,\
609
+ 0, 1, x0, monomial_values, 3) == 0
610
+
611
+
612
+ def test_is_vertex():
613
+ assert is_vertex(2) is False
614
+ assert is_vertex((2, 3)) is True
615
+ assert is_vertex(Point(2, 3)) is True
616
+ assert is_vertex((2, 3, 4)) is True
617
+ assert is_vertex((2, 3, 4, 5)) is False
618
+
619
+
620
+ def test_issue_19234():
621
+ polygon = Polygon(Point(0, 0), Point(0, 1), Point(1, 1), Point(1, 0))
622
+ polys = [ 1, x, y, x*y, x**2*y, x*y**2]
623
+ assert polytope_integrate(polygon, polys) == \
624
+ {1: 1, x: S.Half, y: S.Half, x*y: Rational(1, 4), x**2*y: Rational(1, 6), x*y**2: Rational(1, 6)}
625
+ polys = [ 1, x, y, x*y, 3 + x**2*y, x + x*y**2]
626
+ assert polytope_integrate(polygon, polys) == \
627
+ {1: 1, x: S.Half, y: S.Half, x*y: Rational(1, 4), x**2*y + 3: Rational(19, 6), x*y**2 + x: Rational(2, 3)}
.venv/lib/python3.13/site-packages/sympy/integrals/tests/test_laplace.py ADDED
@@ -0,0 +1,774 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.integrals.laplace import (
2
+ laplace_transform, inverse_laplace_transform,
3
+ LaplaceTransform, InverseLaplaceTransform,
4
+ _laplace_deep_collect, laplace_correspondence,
5
+ laplace_initial_conds)
6
+ from sympy.core.function import Function, expand_mul
7
+ from sympy.core import EulerGamma, Subs, Derivative, diff
8
+ from sympy.core.exprtools import factor_terms
9
+ from sympy.core.numbers import I, oo, pi
10
+ from sympy.core.relational import Eq
11
+ from sympy.core.singleton import S
12
+ from sympy.core.symbol import Symbol, symbols
13
+ from sympy.simplify.simplify import simplify
14
+ from sympy.functions.elementary.complexes import Abs, re
15
+ from sympy.functions.elementary.exponential import exp, log, exp_polar
16
+ from sympy.functions.elementary.hyperbolic import cosh, sinh, coth, asinh
17
+ from sympy.functions.elementary.miscellaneous import sqrt
18
+ from sympy.functions.elementary.piecewise import Piecewise
19
+ from sympy.functions.elementary.trigonometric import atan, cos, sin
20
+ from sympy.logic.boolalg import And
21
+ from sympy.functions.special.gamma_functions import (
22
+ lowergamma, gamma, uppergamma)
23
+ from sympy.functions.special.delta_functions import DiracDelta, Heaviside
24
+ from sympy.functions.special.singularity_functions import SingularityFunction
25
+ from sympy.functions.special.zeta_functions import lerchphi
26
+ from sympy.functions.special.error_functions import (
27
+ fresnelc, fresnels, erf, erfc, Ei, Ci, expint, E1)
28
+ from sympy.functions.special.bessel import besseli, besselj, besselk, bessely
29
+ from sympy.testing.pytest import slow, warns_deprecated_sympy
30
+ from sympy.matrices import Matrix, eye
31
+ from sympy.abc import s
32
+
33
+
34
+ @slow
35
+ def test_laplace_transform():
36
+ LT = laplace_transform
37
+ ILT = inverse_laplace_transform
38
+ a, b, c = symbols('a, b, c', positive=True)
39
+ np = symbols('np', integer=True, positive=True)
40
+ t, w, x = symbols('t, w, x')
41
+ f = Function('f')
42
+ F = Function('F')
43
+ g = Function('g')
44
+ y = Function('y')
45
+ Y = Function('Y')
46
+
47
+ # Test helper functions
48
+ assert (
49
+ _laplace_deep_collect(exp((t+a)*(t+b)) +
50
+ besselj(2, exp((t+a)*(t+b)-t**2)), t) ==
51
+ exp(a*b + t**2 + t*(a + b)) + besselj(2, exp(a*b + t*(a + b))))
52
+ L = laplace_transform(diff(y(t), t, 3), t, s, noconds=True)
53
+ L = laplace_correspondence(L, {y: Y})
54
+ L = laplace_initial_conds(L, t, {y: [2, 4, 8, 16, 32]})
55
+ assert L == s**3*Y(s) - 2*s**2 - 4*s - 8
56
+ # Test whether `noconds=True` in `doit`:
57
+ assert (2*LaplaceTransform(exp(t), t, s) - 1).doit() == -1 + 2/(s - 1)
58
+ assert (LT(a*t+t**2+t**(S(5)/2), t, s) ==
59
+ (a/s**2 + 2/s**3 + 15*sqrt(pi)/(8*s**(S(7)/2)), 0, True))
60
+ assert LT(b/(t+a), t, s) == (-b*exp(-a*s)*Ei(-a*s), 0, True)
61
+ assert (LT(1/sqrt(t+a), t, s) ==
62
+ (sqrt(pi)*sqrt(1/s)*exp(a*s)*erfc(sqrt(a)*sqrt(s)), 0, True))
63
+ assert (LT(sqrt(t)/(t+a), t, s) ==
64
+ (-pi*sqrt(a)*exp(a*s)*erfc(sqrt(a)*sqrt(s)) + sqrt(pi)*sqrt(1/s),
65
+ 0, True))
66
+ assert (LT((t+a)**(-S(3)/2), t, s) ==
67
+ (-2*sqrt(pi)*sqrt(s)*exp(a*s)*erfc(sqrt(a)*sqrt(s)) + 2/sqrt(a),
68
+ 0, True))
69
+ assert (LT(t**(S(1)/2)*(t+a)**(-1), t, s) ==
70
+ (-pi*sqrt(a)*exp(a*s)*erfc(sqrt(a)*sqrt(s)) + sqrt(pi)*sqrt(1/s),
71
+ 0, True))
72
+ assert (LT(1/(a*sqrt(t) + t**(3/2)), t, s) ==
73
+ (pi*sqrt(a)*exp(a*s)*erfc(sqrt(a)*sqrt(s)), 0, True))
74
+ assert (LT((t+a)**b, t, s) ==
75
+ (s**(-b - 1)*exp(-a*s)*uppergamma(b + 1, a*s), 0, True))
76
+ assert LT(t**5/(t+a), t, s) == (120*a**5*uppergamma(-5, a*s), 0, True)
77
+ assert LT(exp(t), t, s) == (1/(s - 1), 1, True)
78
+ assert LT(exp(2*t), t, s) == (1/(s - 2), 2, True)
79
+ assert LT(exp(a*t), t, s) == (1/(s - a), a, True)
80
+ assert LT(exp(a*(t-b)), t, s) == (exp(-a*b)/(-a + s), a, True)
81
+ assert LT(t*exp(-a*(t)), t, s) == ((a + s)**(-2), -a, True)
82
+ assert LT(t*exp(-a*(t-b)), t, s) == (exp(a*b)/(a + s)**2, -a, True)
83
+ assert LT(b*t*exp(-a*t), t, s) == (b/(a + s)**2, -a, True)
84
+ assert LT(exp(-a*exp(-t)), t, s) == (lowergamma(s, a)/a**s, 0, True)
85
+ assert LT(exp(-a*exp(t)), t, s) == (a**s*uppergamma(-s, a), 0, True)
86
+ assert (LT(t**(S(7)/4)*exp(-8*t)/gamma(S(11)/4), t, s) ==
87
+ ((s + 8)**(-S(11)/4), -8, True))
88
+ assert (LT(t**(S(3)/2)*exp(-8*t), t, s) ==
89
+ (3*sqrt(pi)/(4*(s + 8)**(S(5)/2)), -8, True))
90
+ assert LT(t**a*exp(-a*t), t, s) == ((a+s)**(-a-1)*gamma(a+1), -a, True)
91
+ assert (LT(b*exp(-a*t**2), t, s) ==
92
+ (sqrt(pi)*b*exp(s**2/(4*a))*erfc(s/(2*sqrt(a)))/(2*sqrt(a)),
93
+ 0, True))
94
+ assert (LT(exp(-2*t**2), t, s) ==
95
+ (sqrt(2)*sqrt(pi)*exp(s**2/8)*erfc(sqrt(2)*s/4)/4, 0, True))
96
+ assert (LT(b*exp(2*t**2), t, s) ==
97
+ (b*LaplaceTransform(exp(2*t**2), t, s), -oo, True))
98
+ assert (LT(t*exp(-a*t**2), t, s) ==
99
+ (1/(2*a) - s*erfc(s/(2*sqrt(a)))/(4*sqrt(pi)*a**(S(3)/2)),
100
+ 0, True))
101
+ assert (LT(exp(-a/t), t, s) ==
102
+ (2*sqrt(a)*sqrt(1/s)*besselk(1, 2*sqrt(a)*sqrt(s)), 0, True))
103
+ assert LT(sqrt(t)*exp(-a/t), t, s, simplify=True) == (
104
+ sqrt(pi)*(sqrt(a)*sqrt(s) + 1/S(2))*sqrt(s**(-3)) *
105
+ exp(-2*sqrt(a)*sqrt(s)), 0, True)
106
+ assert (LT(exp(-a/t)/sqrt(t), t, s) ==
107
+ (sqrt(pi)*sqrt(1/s)*exp(-2*sqrt(a)*sqrt(s)), 0, True))
108
+ assert (LT(exp(-a/t)/(t*sqrt(t)), t, s) ==
109
+ (sqrt(pi)*sqrt(1/a)*exp(-2*sqrt(a)*sqrt(s)), 0, True))
110
+ # TODO: rules with sqrt(a*t) and sqrt(a/t) have stopped working after
111
+ # changes to as_base_exp
112
+ # assert (
113
+ # LT(exp(-2*sqrt(a*t)), t, s) ==
114
+ # (1/s - sqrt(pi)*sqrt(a) * exp(a/s)*erfc(sqrt(a)*sqrt(1/s)) /
115
+ # s**(S(3)/2), 0, True))
116
+ # assert LT(exp(-2*sqrt(a*t))/sqrt(t), t, s) == (
117
+ # exp(a/s)*erfc(sqrt(a) * sqrt(1/s))*(sqrt(pi)*sqrt(1/s)), 0, True)
118
+ assert (LT(t**4*exp(-2/t), t, s) ==
119
+ (8*sqrt(2)*(1/s)**(S(5)/2)*besselk(5, 2*sqrt(2)*sqrt(s)),
120
+ 0, True))
121
+ assert LT(sinh(a*t), t, s) == (a/(-a**2 + s**2), a, True)
122
+ assert (LT(b*sinh(a*t)**2, t, s) ==
123
+ (2*a**2*b/(-4*a**2*s + s**3), 2*a, True))
124
+ assert (LT(b*sinh(a*t)**2, t, s, simplify=True) ==
125
+ (2*a**2*b/(s*(-4*a**2 + s**2)), 2*a, True))
126
+ # The following line confirms that issue #21202 is solved
127
+ assert LT(cosh(2*t), t, s) == (s/(-4 + s**2), 2, True)
128
+ assert LT(cosh(a*t), t, s) == (s/(-a**2 + s**2), a, True)
129
+ assert (LT(cosh(a*t)**2, t, s, simplify=True) ==
130
+ ((2*a**2 - s**2)/(s*(4*a**2 - s**2)), 2*a, True))
131
+ assert (LT(sinh(x+3), x, s, simplify=True) ==
132
+ ((s*sinh(3) + cosh(3))/(s**2 - 1), 1, True))
133
+ L, _, _ = LT(42*sin(w*t+x)**2, t, s)
134
+ assert (
135
+ L -
136
+ 21*(s**2 + s*(-s*cos(2*x) + 2*w*sin(2*x)) +
137
+ 4*w**2)/(s*(s**2 + 4*w**2))).simplify() == 0
138
+ # The following line replaces the old test test_issue_7173()
139
+ assert LT(sinh(a*t)*cosh(a*t), t, s, simplify=True) == (a/(-4*a**2 + s**2),
140
+ 2*a, True)
141
+ assert LT(sinh(a*t)/t, t, s) == (log((a + s)/(-a + s))/2, a, True)
142
+ assert (LT(t**(-S(3)/2)*sinh(a*t), t, s) ==
143
+ (-sqrt(pi)*(sqrt(-a + s) - sqrt(a + s)), a, True))
144
+ # assert (LT(sinh(2*sqrt(a*t)), t, s) ==
145
+ # (sqrt(pi)*sqrt(a)*exp(a/s)/s**(S(3)/2), 0, True))
146
+ # assert (LT(sqrt(t)*sinh(2*sqrt(a*t)), t, s, simplify=True) ==
147
+ # ((-sqrt(a)*s**(S(5)/2) + sqrt(pi)*s**2*(2*a + s)*exp(a/s) *
148
+ # erf(sqrt(a)*sqrt(1/s))/2)/s**(S(9)/2), 0, True))
149
+ # assert (LT(sinh(2*sqrt(a*t))/sqrt(t), t, s) ==
150
+ # (sqrt(pi)*exp(a/s)*erf(sqrt(a)*sqrt(1/s))/sqrt(s), 0, True))
151
+ # assert (LT(sinh(sqrt(a*t))**2/sqrt(t), t, s) ==
152
+ # (sqrt(pi)*(exp(a/s) - 1)/(2*sqrt(s)), 0, True))
153
+ assert (LT(t**(S(3)/7)*cosh(a*t), t, s) ==
154
+ (((a + s)**(-S(10)/7) + (-a+s)**(-S(10)/7))*gamma(S(10)/7)/2,
155
+ a, True))
156
+ # assert (LT(cosh(2*sqrt(a*t)), t, s) ==
157
+ # (sqrt(pi)*sqrt(a)*exp(a/s)*erf(sqrt(a)*sqrt(1/s))/s**(S(3)/2) +
158
+ # 1/s, 0, True))
159
+ # assert (LT(sqrt(t)*cosh(2*sqrt(a*t)), t, s) ==
160
+ # (sqrt(pi)*(a + s/2)*exp(a/s)/s**(S(5)/2), 0, True))
161
+ # assert (LT(cosh(2*sqrt(a*t))/sqrt(t), t, s) ==
162
+ # (sqrt(pi)*exp(a/s)/sqrt(s), 0, True))
163
+ # assert (LT(cosh(sqrt(a*t))**2/sqrt(t), t, s) ==
164
+ # (sqrt(pi)*(exp(a/s) + 1)/(2*sqrt(s)), 0, True))
165
+ assert LT(log(t), t, s, simplify=True) == (
166
+ (-log(s) - EulerGamma)/s, 0, True)
167
+ assert (LT(-log(t/a), t, s, simplify=True) ==
168
+ ((log(a) + log(s) + EulerGamma)/s, 0, True))
169
+ assert LT(log(1+a*t), t, s) == (-exp(s/a)*Ei(-s/a)/s, 0, True)
170
+ assert (LT(log(t+a), t, s, simplify=True) ==
171
+ ((s*log(a) - exp(s/a)*Ei(-s/a))/s**2, 0, True))
172
+ assert (LT(log(t)/sqrt(t), t, s, simplify=True) ==
173
+ (sqrt(pi)*(-log(s) - log(4) - EulerGamma)/sqrt(s), 0, True))
174
+ assert (LT(t**(S(5)/2)*log(t), t, s, simplify=True) ==
175
+ (sqrt(pi)*(-15*log(s) - log(1073741824) - 15*EulerGamma + 46) /
176
+ (8*s**(S(7)/2)), 0, True))
177
+ assert (LT(t**3*log(t), t, s, noconds=True, simplify=True) -
178
+ 6*(-log(s) - S.EulerGamma + S(11)/6)/s**4).simplify() == S.Zero
179
+ assert (LT(log(t)**2, t, s, simplify=True) ==
180
+ (((log(s) + EulerGamma)**2 + pi**2/6)/s, 0, True))
181
+ assert (LT(exp(-a*t)*log(t), t, s, simplify=True) ==
182
+ ((-log(a + s) - EulerGamma)/(a + s), -a, True))
183
+ assert LT(sin(a*t), t, s) == (a/(a**2 + s**2), 0, True)
184
+ assert (LT(Abs(sin(a*t)), t, s) ==
185
+ (a*coth(pi*s/(2*a))/(a**2 + s**2), 0, True))
186
+ assert LT(sin(a*t)/t, t, s) == (atan(a/s), 0, True)
187
+ assert LT(sin(a*t)**2/t, t, s) == (log(4*a**2/s**2 + 1)/4, 0, True)
188
+ assert (LT(sin(a*t)**2/t**2, t, s) ==
189
+ (a*atan(2*a/s) - s*log(4*a**2/s**2 + 1)/4, 0, True))
190
+ # assert (LT(sin(2*sqrt(a*t)), t, s) ==
191
+ # (sqrt(pi)*sqrt(a)*exp(-a/s)/s**(S(3)/2), 0, True))
192
+ # assert LT(sin(2*sqrt(a*t))/t, t, s) == (pi*erf(sqrt(a)*sqrt(1/s)), 0, True)
193
+ assert LT(cos(a*t), t, s) == (s/(a**2 + s**2), 0, True)
194
+ assert (LT(cos(a*t)**2, t, s) ==
195
+ ((2*a**2 + s**2)/(s*(4*a**2 + s**2)), 0, True))
196
+ # assert (LT(sqrt(t)*cos(2*sqrt(a*t)), t, s, simplify=True) ==
197
+ # (sqrt(pi)*(-a + s/2)*exp(-a/s)/s**(S(5)/2), 0, True))
198
+ # assert (LT(cos(2*sqrt(a*t))/sqrt(t), t, s) ==
199
+ # (sqrt(pi)*sqrt(1/s)*exp(-a/s), 0, True))
200
+ assert (LT(sin(a*t)*sin(b*t), t, s) ==
201
+ (2*a*b*s/((s**2 + (a - b)**2)*(s**2 + (a + b)**2)), 0, True))
202
+ assert (LT(cos(a*t)*sin(b*t), t, s) ==
203
+ (b*(-a**2 + b**2 + s**2)/((s**2 + (a - b)**2)*(s**2 + (a + b)**2)),
204
+ 0, True))
205
+ assert (LT(cos(a*t)*cos(b*t), t, s) ==
206
+ (s*(a**2 + b**2 + s**2)/((s**2 + (a - b)**2)*(s**2 + (a + b)**2)),
207
+ 0, True))
208
+ assert (LT(-a*t*cos(a*t) + sin(a*t), t, s, simplify=True) ==
209
+ (2*a**3/(a**4 + 2*a**2*s**2 + s**4), 0, True))
210
+ assert LT(c*exp(-b*t)*sin(a*t), t, s) == (a *
211
+ c/(a**2 + (b + s)**2), -b, True)
212
+ assert LT(c*exp(-b*t)*cos(a*t), t, s) == (c*(b + s)/(a**2 + (b + s)**2),
213
+ -b, True)
214
+ L, plane, cond = LT(cos(x + 3), x, s, simplify=True)
215
+ assert plane == 0
216
+ assert L - (s*cos(3) - sin(3))/(s**2 + 1) == 0
217
+ # Error functions (laplace7.pdf)
218
+ assert LT(erf(a*t), t, s) == (exp(s**2/(4*a**2))*erfc(s/(2*a))/s, 0, True)
219
+ # assert LT(erf(sqrt(a*t)), t, s) == (sqrt(a)/(s*sqrt(a + s)), 0, True)
220
+ # assert (LT(exp(a*t)*erf(sqrt(a*t)), t, s, simplify=True) ==
221
+ # (-sqrt(a)/(sqrt(s)*(a - s)), a, True))
222
+ # assert (LT(erf(sqrt(a/t)/2), t, s, simplify=True) ==
223
+ # (1/s - exp(-sqrt(a)*sqrt(s))/s, 0, True))
224
+ # assert (LT(erfc(sqrt(a*t)), t, s, simplify=True) ==
225
+ # (-sqrt(a)/(s*sqrt(a + s)) + 1/s, -a, True))
226
+ # assert (LT(exp(a*t)*erfc(sqrt(a*t)), t, s) ==
227
+ # (1/(sqrt(a)*sqrt(s) + s), 0, True))
228
+ # assert LT(erfc(sqrt(a/t)/2), t, s) == (exp(-sqrt(a)*sqrt(s))/s, 0, True)
229
+ # Bessel functions (laplace8.pdf)
230
+ assert LT(besselj(0, a*t), t, s) == (1/sqrt(a**2 + s**2), 0, True)
231
+ assert (LT(besselj(1, a*t), t, s, simplify=True) ==
232
+ (a/(a**2 + s**2 + s*sqrt(a**2 + s**2)), 0, True))
233
+ assert (LT(besselj(2, a*t), t, s, simplify=True) ==
234
+ (a**2/(sqrt(a**2 + s**2)*(s + sqrt(a**2 + s**2))**2), 0, True))
235
+ assert (LT(t*besselj(0, a*t), t, s) ==
236
+ (s/(a**2 + s**2)**(S(3)/2), 0, True))
237
+ assert (LT(t*besselj(1, a*t), t, s) ==
238
+ (a/(a**2 + s**2)**(S(3)/2), 0, True))
239
+ assert (LT(t**2*besselj(2, a*t), t, s) ==
240
+ (3*a**2/(a**2 + s**2)**(S(5)/2), 0, True))
241
+ # assert LT(besselj(0, 2*sqrt(a*t)), t, s) == (exp(-a/s)/s, 0, True)
242
+ # assert (LT(t**(S(3)/2)*besselj(3, 2*sqrt(a*t)), t, s) ==
243
+ # (a**(S(3)/2)*exp(-a/s)/s**4, 0, True))
244
+ assert (LT(besselj(0, a*sqrt(t**2+b*t)), t, s, simplify=True) ==
245
+ (exp(b*(s - sqrt(a**2 + s**2)))/sqrt(a**2 + s**2), 0, True))
246
+ assert LT(besseli(0, a*t), t, s) == (1/sqrt(-a**2 + s**2), a, True)
247
+ assert (LT(besseli(1, a*t), t, s, simplify=True) ==
248
+ (a/(-a**2 + s**2 + s*sqrt(-a**2 + s**2)), a, True))
249
+ assert (LT(besseli(2, a*t), t, s, simplify=True) ==
250
+ (a**2/(sqrt(-a**2 + s**2)*(s + sqrt(-a**2 + s**2))**2), a, True))
251
+ assert LT(t*besseli(0, a*t), t, s) == (s/(-a**2 + s**2)**(S(3)/2), a, True)
252
+ assert LT(t*besseli(1, a*t), t, s) == (a/(-a**2 + s**2)**(S(3)/2), a, True)
253
+ assert (LT(t**2*besseli(2, a*t), t, s) ==
254
+ (3*a**2/(-a**2 + s**2)**(S(5)/2), a, True))
255
+ # assert (LT(t**(S(3)/2)*besseli(3, 2*sqrt(a*t)), t, s) ==
256
+ # (a**(S(3)/2)*exp(a/s)/s**4, 0, True))
257
+ assert (LT(bessely(0, a*t), t, s) ==
258
+ (-2*asinh(s/a)/(pi*sqrt(a**2 + s**2)), 0, True))
259
+ assert (LT(besselk(0, a*t), t, s) ==
260
+ (log((s + sqrt(-a**2 + s**2))/a)/sqrt(-a**2 + s**2), -a, True))
261
+ assert (LT(sin(a*t)**4, t, s, simplify=True) ==
262
+ (24*a**4/(s*(64*a**4 + 20*a**2*s**2 + s**4)), 0, True))
263
+ # Test general rules and unevaluated forms
264
+ # These all also test whether issue #7219 is solved.
265
+ assert LT(Heaviside(t-1)*cos(t-1), t, s) == (s*exp(-s)/(s**2 + 1), 0, True)
266
+ assert LT(a*f(t), t, w) == (a*LaplaceTransform(f(t), t, w), -oo, True)
267
+ assert (LT(a*Heaviside(t+1)*f(t+1), t, s) ==
268
+ (a*LaplaceTransform(f(t + 1), t, s), -oo, True))
269
+ assert (LT(a*Heaviside(t-1)*f(t-1), t, s) ==
270
+ (a*LaplaceTransform(f(t), t, s)*exp(-s), -oo, True))
271
+ assert (LT(b*f(t/a), t, s) ==
272
+ (a*b*LaplaceTransform(f(t), t, a*s), -oo, True))
273
+ assert LT(exp(-f(x)*t), t, s) == (1/(s + f(x)), -re(f(x)), True)
274
+ assert (LT(exp(-a*t)*f(t), t, s) ==
275
+ (LaplaceTransform(f(t), t, a + s), -oo, True))
276
+ # assert (LT(exp(-a*t)*erfc(sqrt(b/t)/2), t, s) ==
277
+ # (exp(-sqrt(b)*sqrt(a + s))/(a + s), -a, True))
278
+ assert (LT(sinh(a*t)*f(t), t, s) ==
279
+ (LaplaceTransform(f(t), t, -a + s)/2 -
280
+ LaplaceTransform(f(t), t, a + s)/2, -oo, True))
281
+ assert (LT(sinh(a*t)*t, t, s, simplify=True) ==
282
+ (2*a*s/(a**4 - 2*a**2*s**2 + s**4), a, True))
283
+ assert (LT(cosh(a*t)*f(t), t, s) ==
284
+ (LaplaceTransform(f(t), t, -a + s)/2 +
285
+ LaplaceTransform(f(t), t, a + s)/2, -oo, True))
286
+ assert (LT(cosh(a*t)*t, t, s, simplify=True) ==
287
+ (1/(2*(a + s)**2) + 1/(2*(a - s)**2), a, True))
288
+ assert (LT(sin(a*t)*f(t), t, s, simplify=True) ==
289
+ (I*(-LaplaceTransform(f(t), t, -I*a + s) +
290
+ LaplaceTransform(f(t), t, I*a + s))/2, -oo, True))
291
+ assert (LT(sin(f(t)), t, s) ==
292
+ (LaplaceTransform(sin(f(t)), t, s), -oo, True))
293
+ assert (LT(sin(a*t)*t, t, s, simplify=True) ==
294
+ (2*a*s/(a**4 + 2*a**2*s**2 + s**4), 0, True))
295
+ assert (LT(cos(a*t)*f(t), t, s) ==
296
+ (LaplaceTransform(f(t), t, -I*a + s)/2 +
297
+ LaplaceTransform(f(t), t, I*a + s)/2, -oo, True))
298
+ assert (LT(cos(a*t)*t, t, s, simplify=True) ==
299
+ ((-a**2 + s**2)/(a**4 + 2*a**2*s**2 + s**4), 0, True))
300
+ L, plane, _ = LT(sin(a*t+b)**2*f(t), t, s)
301
+ assert plane == -oo
302
+ assert (
303
+ -L + (
304
+ LaplaceTransform(f(t), t, s)/2 -
305
+ LaplaceTransform(f(t), t, -2*I*a + s)*exp(2*I*b)/4 -
306
+ LaplaceTransform(f(t), t, 2*I*a + s)*exp(-2*I*b)/4)) == 0
307
+ L = LT(sin(a*t+b)**2*f(t), t, s, noconds=True)
308
+ assert (
309
+ laplace_correspondence(L, {f: F}) ==
310
+ F(s)/2 - F(-2*I*a + s)*exp(2*I*b)/4 -
311
+ F(2*I*a + s)*exp(-2*I*b)/4)
312
+ L, plane, _ = LT(sin(a*t)**3*cosh(b*t), t, s)
313
+ assert plane == b
314
+ assert (
315
+ -L - 3*a/(8*(9*a**2 + b**2 + 2*b*s + s**2)) -
316
+ 3*a/(8*(9*a**2 + b**2 - 2*b*s + s**2)) +
317
+ 3*a/(8*(a**2 + b**2 + 2*b*s + s**2)) +
318
+ 3*a/(8*(a**2 + b**2 - 2*b*s + s**2))).simplify() == 0
319
+ assert (LT(t**2*exp(-t**2), t, s) ==
320
+ (sqrt(pi)*s**2*exp(s**2/4)*erfc(s/2)/8 - s/4 +
321
+ sqrt(pi)*exp(s**2/4)*erfc(s/2)/4, 0, True))
322
+ assert (LT((a*t**2 + b*t + c)*f(t), t, s) ==
323
+ (a*Derivative(LaplaceTransform(f(t), t, s), (s, 2)) -
324
+ b*Derivative(LaplaceTransform(f(t), t, s), s) +
325
+ c*LaplaceTransform(f(t), t, s), -oo, True))
326
+ assert (LT(t**np*g(t), t, s) ==
327
+ ((-1)**np*Derivative(LaplaceTransform(g(t), t, s), (s, np)),
328
+ -oo, True))
329
+ # The following tests check whether _piecewise_to_heaviside works:
330
+ x1 = Piecewise((0, t <= 0), (1, t <= 1), (0, True))
331
+ X1 = LT(x1, t, s)[0]
332
+ assert X1 == 1/s - exp(-s)/s
333
+ y1 = ILT(X1, s, t)
334
+ assert y1 == Heaviside(t) - Heaviside(t - 1)
335
+ x1 = Piecewise((0, t <= 0), (t, t <= 1), (2-t, t <= 2), (0, True))
336
+ X1 = LT(x1, t, s)[0].simplify()
337
+ assert X1 == (exp(2*s) - 2*exp(s) + 1)*exp(-2*s)/s**2
338
+ y1 = ILT(X1, s, t)
339
+ assert (
340
+ -y1 + t*Heaviside(t) + (t - 2)*Heaviside(t - 2) -
341
+ 2*(t - 1)*Heaviside(t - 1)).simplify() == 0
342
+ x1 = Piecewise((exp(t), t <= 0), (1, t <= 1), (exp(-(t)), True))
343
+ X1 = LT(x1, t, s)[0]
344
+ assert X1 == exp(-1)*exp(-s)/(s + 1) + 1/s - exp(-s)/s
345
+ y1 = ILT(X1, s, t)
346
+ assert y1 == (
347
+ exp(-1)*exp(1 - t)*Heaviside(t - 1) + Heaviside(t) - Heaviside(t - 1))
348
+ x1 = Piecewise((0, x <= 0), (1, x <= 1), (0, True))
349
+ X1 = LT(x1, t, s)[0]
350
+ assert X1 == Piecewise((0, x <= 0), (1, x <= 1), (0, True))/s
351
+ x1 = [
352
+ a*Piecewise((1, And(t > 1, t <= 3)), (2, True)),
353
+ a*Piecewise((1, And(t >= 1, t <= 3)), (2, True)),
354
+ a*Piecewise((1, And(t >= 1, t < 3)), (2, True)),
355
+ a*Piecewise((1, And(t > 1, t < 3)), (2, True))]
356
+ for x2 in x1:
357
+ assert LT(x2, t, s)[0].expand() == 2*a/s - a*exp(-s)/s + a*exp(-3*s)/s
358
+ assert (
359
+ LT(Piecewise((1, Eq(t, 1)), (2, True)), t, s)[0] ==
360
+ LaplaceTransform(Piecewise((1, Eq(t, 1)), (2, True)), t, s))
361
+ # The following lines test whether _laplace_transform successfully
362
+ # removes Heaviside(1) before processing espressions. It fails if
363
+ # Heaviside(t) remains because then meijerg functions will appear.
364
+ X1 = 1/sqrt(a*s**2-b)
365
+ x1 = ILT(X1, s, t)
366
+ Y1 = LT(x1, t, s)[0]
367
+ Z1 = (Y1**2/X1**2).simplify()
368
+ assert Z1 == 1
369
+ # The following two lines test whether issues #5813 and #7176 are solved.
370
+ assert (LT(diff(f(t), (t, 1)), t, s, noconds=True) ==
371
+ s*LaplaceTransform(f(t), t, s) - f(0))
372
+ assert (LT(diff(f(t), (t, 3)), t, s, noconds=True) ==
373
+ s**3*LaplaceTransform(f(t), t, s) - s**2*f(0) -
374
+ s*Subs(Derivative(f(t), t), t, 0) -
375
+ Subs(Derivative(f(t), (t, 2)), t, 0))
376
+ # Issue #7219
377
+ assert (LT(diff(f(x, t, w), t, 2), t, s) ==
378
+ (s**2*LaplaceTransform(f(x, t, w), t, s) - s*f(x, 0, w) -
379
+ Subs(Derivative(f(x, t, w), t), t, 0), -oo, True))
380
+ # Issue #23307
381
+ assert (LT(10*diff(f(t), (t, 1)), t, s, noconds=True) ==
382
+ 10*s*LaplaceTransform(f(t), t, s) - 10*f(0))
383
+ assert (LT(a*f(b*t)+g(c*t), t, s, noconds=True) ==
384
+ a*LaplaceTransform(f(t), t, s/b)/b +
385
+ LaplaceTransform(g(t), t, s/c)/c)
386
+ assert inverse_laplace_transform(
387
+ f(w), w, t, plane=0) == InverseLaplaceTransform(f(w), w, t, 0)
388
+ assert (LT(f(t)*g(t), t, s, noconds=True) ==
389
+ LaplaceTransform(f(t)*g(t), t, s))
390
+ # Issue #24294
391
+ assert (LT(b*f(a*t), t, s, noconds=True) ==
392
+ b*LaplaceTransform(f(t), t, s/a)/a)
393
+ assert LT(3*exp(t)*Heaviside(t), t, s) == (3/(s - 1), 1, True)
394
+ assert (LT(2*sin(t)*Heaviside(t), t, s, simplify=True) ==
395
+ (2/(s**2 + 1), 0, True))
396
+ # Issue #25293
397
+ assert (
398
+ LT((1/(t-1))*sin(4*pi*(t-1))*DiracDelta(t-1) *
399
+ (Heaviside(t-1/4) - Heaviside(t-2)), t, s)[0] == 4*pi*exp(-s))
400
+ # additional basic tests from wikipedia
401
+ assert (LT((t - a)**b*exp(-c*(t - a))*Heaviside(t - a), t, s) ==
402
+ ((c + s)**(-b - 1)*exp(-a*s)*gamma(b + 1), -c, True))
403
+ assert (
404
+ LT((exp(2*t)-1)*exp(-b-t)*Heaviside(t)/2, t, s, noconds=True,
405
+ simplify=True) ==
406
+ exp(-b)/(s**2 - 1))
407
+ # DiracDelta function: standard cases
408
+ assert LT(DiracDelta(t), t, s) == (1, -oo, True)
409
+ assert LT(DiracDelta(a*t), t, s) == (1/a, -oo, True)
410
+ assert LT(DiracDelta(t/42), t, s) == (42, -oo, True)
411
+ assert LT(DiracDelta(t+42), t, s) == (0, -oo, True)
412
+ assert (LT(DiracDelta(t)+DiracDelta(t-42), t, s) ==
413
+ (1 + exp(-42*s), -oo, True))
414
+ assert (LT(DiracDelta(t)-a*exp(-a*t), t, s, simplify=True) ==
415
+ (s/(a + s), -a, True))
416
+ assert (
417
+ LT(exp(-t)*(DiracDelta(t)+DiracDelta(t-42)), t, s, simplify=True) ==
418
+ (exp(-42*s - 42) + 1, -oo, True))
419
+ assert LT(f(t)*DiracDelta(t-42), t, s) == (f(42)*exp(-42*s), -oo, True)
420
+ assert LT(f(t)*DiracDelta(b*t-a), t, s) == (f(a/b)*exp(-a*s/b)/b,
421
+ -oo, True)
422
+ assert LT(f(t)*DiracDelta(b*t+a), t, s) == (0, -oo, True)
423
+ # SingularityFunction
424
+ assert LT(SingularityFunction(t, a, -1), t, s)[0] == exp(-a*s)
425
+ assert LT(SingularityFunction(t, a, 1), t, s)[0] == exp(-a*s)/s**2
426
+ assert LT(SingularityFunction(t, a, x), t, s)[0] == (
427
+ LaplaceTransform(SingularityFunction(t, a, x), t, s))
428
+ # Collection of cases that cannot be fully evaluated and/or would catch
429
+ # some common implementation errors
430
+ assert (LT(DiracDelta(t**2), t, s, noconds=True) ==
431
+ LaplaceTransform(DiracDelta(t**2), t, s))
432
+ assert LT(DiracDelta(t**2 - 1), t, s) == (exp(-s)/2, -oo, True)
433
+ assert LT(DiracDelta(t*(1 - t)), t, s) == (1 - exp(-s), -oo, True)
434
+ assert (LT((DiracDelta(t) + 1)*(DiracDelta(t - 1) + 1), t, s) ==
435
+ (LaplaceTransform(DiracDelta(t)*DiracDelta(t - 1), t, s) +
436
+ 1 + exp(-s) + 1/s, 0, True))
437
+ assert LT(DiracDelta(2*t-2*exp(a)), t, s) == (exp(-s*exp(a))/2, -oo, True)
438
+ assert LT(DiracDelta(-2*t+2*exp(a)), t, s) == (exp(-s*exp(a))/2, -oo, True)
439
+ # Heaviside tests
440
+ assert LT(Heaviside(t), t, s) == (1/s, 0, True)
441
+ assert LT(Heaviside(t - a), t, s) == (exp(-a*s)/s, 0, True)
442
+ assert LT(Heaviside(t-1), t, s) == (exp(-s)/s, 0, True)
443
+ assert LT(Heaviside(2*t-4), t, s) == (exp(-2*s)/s, 0, True)
444
+ assert LT(Heaviside(2*t+4), t, s) == (1/s, 0, True)
445
+ assert (LT(Heaviside(-2*t+4), t, s, simplify=True) ==
446
+ (1/s - exp(-2*s)/s, 0, True))
447
+ assert (LT(g(t)*Heaviside(t - w), t, s) ==
448
+ (LaplaceTransform(g(t)*Heaviside(t - w), t, s), -oo, True))
449
+ assert (
450
+ LT(Heaviside(t-a)*g(t), t, s) ==
451
+ (LaplaceTransform(g(a + t), t, s)*exp(-a*s), -oo, True))
452
+ assert (
453
+ LT(Heaviside(t+a)*g(t), t, s) ==
454
+ (LaplaceTransform(g(t), t, s), -oo, True))
455
+ assert (
456
+ LT(Heaviside(-t+a)*g(t), t, s) ==
457
+ (LaplaceTransform(g(t), t, s) -
458
+ LaplaceTransform(g(a + t), t, s)*exp(-a*s), -oo, True))
459
+ assert (
460
+ LT(Heaviside(-t-a)*g(t), t, s) == (0, 0, True))
461
+ # Fresnel functions
462
+ assert (laplace_transform(fresnels(t), t, s, simplify=True) ==
463
+ ((-sin(s**2/(2*pi))*fresnels(s/pi) +
464
+ sqrt(2)*sin(s**2/(2*pi) + pi/4)/2 -
465
+ cos(s**2/(2*pi))*fresnelc(s/pi))/s, 0, True))
466
+ assert (laplace_transform(fresnelc(t), t, s, simplify=True) ==
467
+ ((sin(s**2/(2*pi))*fresnelc(s/pi) -
468
+ cos(s**2/(2*pi))*fresnels(s/pi) +
469
+ sqrt(2)*cos(s**2/(2*pi) + pi/4)/2)/s, 0, True))
470
+ # Matrix tests
471
+ Mt = Matrix([[exp(t), t*exp(-t)], [t*exp(-t), exp(t)]])
472
+ Ms = Matrix([[1/(s - 1), (s + 1)**(-2)],
473
+ [(s + 1)**(-2), 1/(s - 1)]])
474
+ # The default behaviour for Laplace transform of a Matrix returns a Matrix
475
+ # of Tuples and is deprecated:
476
+ with warns_deprecated_sympy():
477
+ Ms_conds = Matrix(
478
+ [[(1/(s - 1), 1, True), ((s + 1)**(-2), -1, True)],
479
+ [((s + 1)**(-2), -1, True), (1/(s - 1), 1, True)]])
480
+ with warns_deprecated_sympy():
481
+ assert LT(Mt, t, s) == Ms_conds
482
+ # The new behavior is to return a tuple of a Matrix and the convergence
483
+ # conditions for the matrix as a whole:
484
+ assert LT(Mt, t, s, legacy_matrix=False) == (Ms, 1, True)
485
+ # With noconds=True the transformed matrix is returned without conditions
486
+ # either way:
487
+ assert LT(Mt, t, s, noconds=True) == Ms
488
+ assert LT(Mt, t, s, legacy_matrix=False, noconds=True) == Ms
489
+
490
+
491
+ @slow
492
+ def test_inverse_laplace_transform():
493
+ s = symbols('s')
494
+ k, n, t = symbols('k, n, t', real=True)
495
+ a, b, c, d = symbols('a, b, c, d', positive=True)
496
+ f = Function('f')
497
+ F = Function('F')
498
+
499
+ def ILT(g):
500
+ return inverse_laplace_transform(g, s, t)
501
+
502
+ def ILTS(g):
503
+ return inverse_laplace_transform(g, s, t, simplify=True)
504
+
505
+ def ILTF(g):
506
+ return laplace_correspondence(
507
+ inverse_laplace_transform(g, s, t), {f: F})
508
+
509
+ # Tests for the rules in Bateman54.
510
+
511
+ # Section 4.1: Some of the Laplace transform rules can also be used well
512
+ # in the inverse transform.
513
+ assert ILTF(exp(-a*s)*F(s)) == f(-a + t)
514
+ assert ILTF(k*F(s-a)) == k*f(t)*exp(-a*t)
515
+ assert ILTF(diff(F(s), s, 3)) == -t**3*f(t)
516
+ assert ILTF(diff(F(s), s, 4)) == t**4*f(t)
517
+
518
+ # Section 5.1: Most rules are impractical for a computer algebra system.
519
+
520
+ # Section 5.2: Rational functions
521
+ assert ILT(2) == 2*DiracDelta(t)
522
+ assert ILT(1/s) == Heaviside(t)
523
+ assert ILT(1/s**2) == t*Heaviside(t)
524
+ assert ILT(1/s**5) == t**4*Heaviside(t)/24
525
+ assert ILT(1/s**n) == t**(n - 1)*Heaviside(t)/gamma(n)
526
+ assert ILT(a/(a + s)) == a*exp(-a*t)*Heaviside(t)
527
+ assert ILT(s/(a + s)) == -a*exp(-a*t)*Heaviside(t) + DiracDelta(t)
528
+ assert (ILT(b*s/(s+a)**2) ==
529
+ b*(-a*t*exp(-a*t)*Heaviside(t) + exp(-a*t)*Heaviside(t)))
530
+ assert (ILTS(c/((s+a)*(s+b))) ==
531
+ c*(exp(a*t) - exp(b*t))*exp(-t*(a + b))*Heaviside(t)/(a - b))
532
+ assert (ILTS(c*s/((s+a)*(s+b))) ==
533
+ c*(a*exp(b*t) - b*exp(a*t))*exp(-t*(a + b))*Heaviside(t)/(a - b))
534
+ assert ILTS(s/(a + s)**3) == t*(-a*t + 2)*exp(-a*t)*Heaviside(t)/2
535
+ assert ILTS(1/(s*(a + s)**3)) == (
536
+ -a**2*t**2 - 2*a*t + 2*exp(a*t) - 2)*exp(-a*t)*Heaviside(t)/(2*a**3)
537
+ assert ILT(1/(s*(a + s)**n)) == (
538
+ Heaviside(t)*lowergamma(n, a*t)/(a**n*gamma(n)))
539
+ assert ILT((s-a)**(-b)) == t**(b - 1)*exp(a*t)*Heaviside(t)/gamma(b)
540
+ assert ILT((a + s)**(-2)) == t*exp(-a*t)*Heaviside(t)
541
+ assert ILT((a + s)**(-5)) == t**4*exp(-a*t)*Heaviside(t)/24
542
+ assert ILT(s**2/(s**2 + 1)) == -sin(t)*Heaviside(t) + DiracDelta(t)
543
+ assert ILT(1 - 1/(s**2 + 1)) == -sin(t)*Heaviside(t) + DiracDelta(t)
544
+ assert ILT(a/(a**2 + s**2)) == sin(a*t)*Heaviside(t)
545
+ assert ILT(s/(s**2 + a**2)) == cos(a*t)*Heaviside(t)
546
+ assert ILT(b/(b**2 + (a + s)**2)) == exp(-a*t)*sin(b*t)*Heaviside(t)
547
+ assert (ILT(b*s/(b**2 + (a + s)**2)) ==
548
+ b*(-a*exp(-a*t)*sin(b*t)/b + exp(-a*t)*cos(b*t))*Heaviside(t))
549
+ assert ILT(1/(s**2*(s**2 + 1))) == t*Heaviside(t) - sin(t)*Heaviside(t)
550
+ assert (ILTS(c*s/(d**2*(s+a)**2+b**2)) ==
551
+ c*(-a*d*sin(b*t/d) + b*cos(b*t/d))*exp(-a*t)*Heaviside(t)/(b*d**2))
552
+ assert ILTS((b*s**2 + d)/(a**2 + s**2)**2) == (
553
+ 2*a**2*b*sin(a*t) + (a**2*b - d)*(a*t*cos(a*t) -
554
+ sin(a*t)))*Heaviside(t)/(2*a**3)
555
+ assert ILTS(b/(s**2-a**2)) == b*sinh(a*t)*Heaviside(t)/a
556
+ assert (ILT(b/(s**2-a**2)) ==
557
+ b*(exp(a*t)*Heaviside(t)/(2*a) - exp(-a*t)*Heaviside(t)/(2*a)))
558
+ assert ILTS(b*s/(s**2-a**2)) == b*cosh(a*t)*Heaviside(t)
559
+ assert (ILT(b/(s*(s+a))) ==
560
+ b*(Heaviside(t)/a - exp(-a*t)*Heaviside(t)/a))
561
+ # Issue #24424
562
+ assert (ILTS((s + 8)/((s + 2)*(s**2 + 2*s + 10))) ==
563
+ ((8*sin(3*t) - 9*cos(3*t))*exp(t) + 9)*exp(-2*t)*Heaviside(t)/15)
564
+ # Issue #8514; this is not important anymore, since this function
565
+ # is not solved by integration anymore
566
+ assert (ILT(1/(a*s**2+b*s+c)) ==
567
+ 2*exp(-b*t/(2*a))*sin(t*sqrt(4*a*c - b**2)/(2*a)) *
568
+ Heaviside(t)/sqrt(4*a*c - b**2))
569
+
570
+ # Section 5.3: Irrational algebraic functions
571
+ assert ( # (1)
572
+ ILT(1/sqrt(s)/(b*s-a)) ==
573
+ exp(a*t/b)*Heaviside(t)*erf(sqrt(a)*sqrt(t)/sqrt(b))/(sqrt(a)*sqrt(b)))
574
+ assert ( # (2)
575
+ ILT(1/sqrt(k*s)/(c*s-a)/s) ==
576
+ (-2*c*sqrt(t)/(sqrt(pi)*a) +
577
+ c**(S(3)/2)*exp(a*t/c)*erf(sqrt(a)*sqrt(t)/sqrt(c))/a**(S(3)/2)) *
578
+ Heaviside(t)/(c*sqrt(k)))
579
+ assert ( # (4)
580
+ ILT(1/(sqrt(c*s)+a)) == (-a*exp(a**2*t/c)*erfc(a*sqrt(t)/sqrt(c))/c +
581
+ 1/(sqrt(pi)*sqrt(c)*sqrt(t)))*Heaviside(t))
582
+ assert ( # (5)
583
+ ILT(a/s/(b*sqrt(s)+a)) ==
584
+ (-exp(a**2*t/b**2)*erfc(a*sqrt(t)/b) + 1)*Heaviside(t))
585
+ assert ( # (6)
586
+ ILT((a-b)*sqrt(s)/(sqrt(s)+sqrt(a))/(s-b)) ==
587
+ (sqrt(a)*sqrt(b)*exp(b*t)*erfc(sqrt(b)*sqrt(t)) +
588
+ a*exp(a*t)*erfc(sqrt(a)*sqrt(t)) - b*exp(b*t))*Heaviside(t))
589
+ assert ( # (7)
590
+ ILT(1/sqrt(s)/(sqrt(b*s)+a)) ==
591
+ exp(a**2*t/b)*Heaviside(t)*erfc(a*sqrt(t)/sqrt(b))/sqrt(b))
592
+ assert ( # (8)
593
+ ILT(a**2/(sqrt(s)+a)/s**(S(3)/2)) ==
594
+ (2*a*sqrt(t)/sqrt(pi) + exp(a**2*t)*erfc(a*sqrt(t)) - 1) *
595
+ Heaviside(t))
596
+ assert ( # (9)
597
+ ILT((a-b)*sqrt(b)/(s-b)/sqrt(s)/(sqrt(s)+sqrt(a))) ==
598
+ (sqrt(a)*exp(b*t)*erf(sqrt(b)*sqrt(t)) +
599
+ sqrt(b)*exp(a*t)*erfc(sqrt(a)*sqrt(t)) -
600
+ sqrt(b)*exp(b*t))*Heaviside(t))
601
+ assert ( # (10)
602
+ ILT(1/(sqrt(s)+sqrt(a))**2) ==
603
+ (-2*sqrt(a)*sqrt(t)/sqrt(pi) +
604
+ (-2*a*t + 1)*(erf(sqrt(a)*sqrt(t)) -
605
+ 1)*exp(a*t) + 1)*Heaviside(t))
606
+ assert ( # (11)
607
+ ILT(1/(sqrt(s)+sqrt(a))**2/s) ==
608
+ ((2*t - 1/a)*exp(a*t)*erfc(sqrt(a)*sqrt(t)) + 1/a -
609
+ 2*sqrt(t)/(sqrt(pi)*sqrt(a)))*Heaviside(t))
610
+ assert ( # (12)
611
+ ILT(1/(sqrt(s)+a)**2/sqrt(s)) ==
612
+ (-2*a*t*exp(a**2*t)*erfc(a*sqrt(t)) +
613
+ 2*sqrt(t)/sqrt(pi))*Heaviside(t))
614
+ assert ( # (13)
615
+ ILT(1/(sqrt(s)+a)**3) ==
616
+ (-a*t*(2*a**2*t + 3)*exp(a**2*t)*erfc(a*sqrt(t)) +
617
+ 2*sqrt(t)*(a**2*t + 1)/sqrt(pi))*Heaviside(t))
618
+ x = (
619
+ - ILT(sqrt(s)/(sqrt(s)+a)**3) +
620
+ 2*(sqrt(pi)*a**2*t*(-2*sqrt(pi)*erfc(a*sqrt(t)) +
621
+ 2*exp(-a**2*t)/(a*sqrt(t))) *
622
+ (-a**4*t**2 - 5*a**2*t/2 - S.Half) * exp(a**2*t)/2 +
623
+ sqrt(pi)*a*sqrt(t)*(a**2*t + 1)/2) *
624
+ Heaviside(t)/(pi*a**2*t)).simplify()
625
+ assert ( # (14)
626
+ x == 0)
627
+ x = (
628
+ - ILT(1/sqrt(s)/(sqrt(s)+a)**3) +
629
+ Heaviside(t)*(sqrt(t)*((2*a**2*t + 1) *
630
+ (sqrt(pi)*a*sqrt(t)*exp(a**2*t) *
631
+ erfc(a*sqrt(t)) - 1) + 1) /
632
+ (sqrt(pi)*a))).simplify()
633
+ assert ( # (15)
634
+ x == 0)
635
+ assert ( # (16)
636
+ factor_terms(ILT(3/(sqrt(s)+a)**4)) ==
637
+ 3*(-2*a**3*t**(S(5)/2)*(2*a**2*t + 5)/(3*sqrt(pi)) +
638
+ t*(4*a**4*t**2 + 12*a**2*t + 3)*exp(a**2*t) *
639
+ erfc(a*sqrt(t))/3)*Heaviside(t))
640
+ assert ( # (17)
641
+ ILT((sqrt(s)-a)/(s*(sqrt(s)+a))) ==
642
+ (2*exp(a**2*t)*erfc(a*sqrt(t))-1)*Heaviside(t))
643
+ assert ( # (18)
644
+ ILT((sqrt(s)-a)**2/(s*(sqrt(s)+a)**2)) == (
645
+ 1 + 8*a**2*t*exp(a**2*t)*erfc(a*sqrt(t)) -
646
+ 8/sqrt(pi)*a*sqrt(t))*Heaviside(t))
647
+ assert ( # (19)
648
+ ILT((sqrt(s)-a)**3/(s*(sqrt(s)+a)**3)) == Heaviside(t)*(
649
+ 2*(8*a**4*t**2+8*a**2*t+1)*exp(a**2*t) *
650
+ erfc(a*sqrt(t))-8/sqrt(pi)*a*sqrt(t)*(2*a**2*t+1)-1))
651
+ assert ( # (22)
652
+ ILT(sqrt(s+a)/(s+b)) == Heaviside(t)*(
653
+ exp(-a*t)/sqrt(t)/sqrt(pi) +
654
+ sqrt(a-b)*exp(-b*t)*erf(sqrt(a-b)*sqrt(t))))
655
+ assert ( # (23)
656
+ ILT(1/sqrt(s+b)/(s+a)) == Heaviside(t)*(
657
+ 1/sqrt(b-a)*exp(-a*t)*erf(sqrt(b-a)*sqrt(t))))
658
+ assert ( # (35)
659
+ ILT(1/sqrt(s**2+a**2)) == Heaviside(t)*(
660
+ besselj(0, a*t)))
661
+ assert ( # (44)
662
+ ILT(1/sqrt(s**2-a**2)) == Heaviside(t)*(
663
+ besseli(0, a*t)))
664
+
665
+ # Miscellaneous tests
666
+ # Can _inverse_laplace_time_shift deal with positive exponents?
667
+ assert (
668
+ - ILT((s**2*exp(2*s) + 4*exp(s) - 4)*exp(-2*s)/(s*(s**2 + 1))) +
669
+ cos(t)*Heaviside(t) + 4*cos(t - 2)*Heaviside(t - 2) -
670
+ 4*cos(t - 1)*Heaviside(t - 1) - 4*Heaviside(t - 2) +
671
+ 4*Heaviside(t - 1)).simplify() == 0
672
+
673
+
674
+ @slow
675
+ def test_inverse_laplace_transform_old():
676
+ from sympy.functions.special.delta_functions import DiracDelta
677
+ ILT = inverse_laplace_transform
678
+ a, b, c, d = symbols('a b c d', positive=True)
679
+ n, r = symbols('n, r', real=True)
680
+ t, z = symbols('t z')
681
+ f = Function('f')
682
+ F = Function('F')
683
+
684
+ def simp_hyp(expr):
685
+ return factor_terms(expand_mul(expr)).rewrite(sin)
686
+
687
+ L = ILT(F(s), s, t)
688
+ assert laplace_correspondence(L, {f: F}) == f(t)
689
+ assert ILT(exp(-a*s)/s, s, t) == Heaviside(-a + t)
690
+ assert ILT(exp(-a*s)/(b + s), s, t) == exp(-b*(-a + t))*Heaviside(-a + t)
691
+ assert (ILT((b + s)/(a**2 + (b + s)**2), s, t) ==
692
+ exp(-b*t)*cos(a*t)*Heaviside(t))
693
+ assert (ILT(exp(-a*s)/s**b, s, t) ==
694
+ (-a + t)**(b - 1)*Heaviside(-a + t)/gamma(b))
695
+ assert (ILT(exp(-a*s)/sqrt(s**2 + 1), s, t) ==
696
+ Heaviside(-a + t)*besselj(0, a - t))
697
+ assert ILT(1/(s*sqrt(s + 1)), s, t) == Heaviside(t)*erf(sqrt(t))
698
+ # TODO sinh/cosh shifted come out a mess. also delayed trig is a mess
699
+ # TODO should this simplify further?
700
+ assert (ILT(exp(-a*s)/s**b, s, t) ==
701
+ (t - a)**(b - 1)*Heaviside(t - a)/gamma(b))
702
+ assert (ILT(exp(-a*s)/sqrt(1 + s**2), s, t) ==
703
+ Heaviside(t - a)*besselj(0, a - t)) # note: besselj(0, x) is even
704
+ # XXX ILT turns these branch factor into trig functions ...
705
+ assert (
706
+ simplify(ILT(a**b*(s + sqrt(s**2 - a**2))**(-b)/sqrt(s**2 - a**2),
707
+ s, t).rewrite(exp)) ==
708
+ Heaviside(t)*besseli(b, a*t))
709
+ assert (
710
+ ILT(a**b*(s + sqrt(s**2 + a**2))**(-b)/sqrt(s**2 + a**2),
711
+ s, t, simplify=True).rewrite(exp) ==
712
+ Heaviside(t)*besselj(b, a*t))
713
+ assert ILT(1/(s*sqrt(s + 1)), s, t) == Heaviside(t)*erf(sqrt(t))
714
+ # TODO can we make erf(t) work?
715
+ assert (ILT((s * eye(2) - Matrix([[1, 0], [0, 2]])).inv(), s, t) ==
716
+ Matrix([[exp(t)*Heaviside(t), 0], [0, exp(2*t)*Heaviside(t)]]))
717
+ # Test time_diff rule
718
+ assert (ILT(s**42*f(s), s, t) ==
719
+ Derivative(InverseLaplaceTransform(f(s), s, t, None), (t, 42)))
720
+ assert ILT(cos(s), s, t) == InverseLaplaceTransform(cos(s), s, t, None)
721
+ # Rules for testing different DiracDelta cases
722
+ assert (
723
+ ILT(1 + 2*s + 3*s**2 + 5*s**3, s, t) == DiracDelta(t) +
724
+ 2*DiracDelta(t, 1) + 3*DiracDelta(t, 2) + 5*DiracDelta(t, 3))
725
+ assert (ILT(2*exp(3*s) - 5*exp(-7*s), s, t) ==
726
+ 2*InverseLaplaceTransform(exp(3*s), s, t, None) -
727
+ 5*DiracDelta(t - 7))
728
+ a = cos(sin(7)/2)
729
+ assert ILT(a*exp(-3*s), s, t) == a*DiracDelta(t - 3)
730
+ assert ILT(exp(2*s), s, t) == InverseLaplaceTransform(exp(2*s), s, t, None)
731
+ r = Symbol('r', real=True)
732
+ assert ILT(exp(r*s), s, t) == InverseLaplaceTransform(exp(r*s), s, t, None)
733
+ # Rules for testing whether Heaviside(t) is treated properly in diff rule
734
+ assert ILT(s**2/(a**2 + s**2), s, t) == (
735
+ -a*sin(a*t)*Heaviside(t) + DiracDelta(t))
736
+ assert ILT(s**2*(f(s) + 1/(a**2 + s**2)), s, t) == (
737
+ -a*sin(a*t)*Heaviside(t) + DiracDelta(t) +
738
+ Derivative(InverseLaplaceTransform(f(s), s, t, None), (t, 2)))
739
+ # Rules from the previous test_inverse_laplace_transform_delta_cond():
740
+ assert (ILT(exp(r*s), s, t, noconds=False) ==
741
+ (InverseLaplaceTransform(exp(r*s), s, t, None), True))
742
+ # inversion does not exist: verify it doesn't evaluate to DiracDelta
743
+ for z in (Symbol('z', extended_real=False),
744
+ Symbol('z', imaginary=True, zero=False)):
745
+ f = ILT(exp(z*s), s, t, noconds=False)
746
+ f = f[0] if isinstance(f, tuple) else f
747
+ assert f.func != DiracDelta
748
+
749
+
750
+ @slow
751
+ def test_expint():
752
+ x = Symbol('x')
753
+ a = Symbol('a')
754
+ u = Symbol('u', polar=True)
755
+
756
+ # TODO LT of Si, Shi, Chi is a mess ...
757
+ assert laplace_transform(Ci(x), x, s) == (-log(1 + s**2)/2/s, 0, True)
758
+ assert (laplace_transform(expint(a, x), x, s, simplify=True) ==
759
+ (lerchphi(s*exp_polar(I*pi), 1, a), 0, re(a) > S.Zero))
760
+ assert (laplace_transform(expint(1, x), x, s, simplify=True) ==
761
+ (log(s + 1)/s, 0, True))
762
+ assert (laplace_transform(expint(2, x), x, s, simplify=True) ==
763
+ ((s - log(s + 1))/s**2, 0, True))
764
+ assert (inverse_laplace_transform(-log(1 + s**2)/2/s, s, u).expand() ==
765
+ Heaviside(u)*Ci(u))
766
+ assert (
767
+ inverse_laplace_transform(log(s + 1)/s, s, x,
768
+ simplify=True).rewrite(expint) ==
769
+ Heaviside(x)*E1(x))
770
+ assert (
771
+ inverse_laplace_transform(
772
+ (s - log(s + 1))/s**2, s, x,
773
+ simplify=True).rewrite(expint).expand() ==
774
+ (expint(2, x)*Heaviside(x)).rewrite(Ei).rewrite(expint).expand())
.venv/lib/python3.13/site-packages/sympy/integrals/tests/test_lineintegrals.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core.numbers import E
2
+ from sympy.core.symbol import symbols
3
+ from sympy.functions.elementary.exponential import log
4
+ from sympy.functions.elementary.miscellaneous import sqrt
5
+ from sympy.geometry.curve import Curve
6
+ from sympy.integrals.integrals import line_integrate
7
+
8
+ s, t, x, y, z = symbols('s,t,x,y,z')
9
+
10
+
11
+ def test_lineintegral():
12
+ c = Curve([E**t + 1, E**t - 1], (t, 0, log(2)))
13
+ assert line_integrate(x + y, c, [x, y]) == 3*sqrt(2)
.venv/lib/python3.13/site-packages/sympy/integrals/tests/test_manual.py ADDED
@@ -0,0 +1,714 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core.expr import Expr
2
+ from sympy.core.mul import Mul
3
+ from sympy.core.function import (Derivative, Function, diff, expand)
4
+ from sympy.core.numbers import (I, Rational, pi)
5
+ from sympy.core.relational import Ne
6
+ from sympy.core.singleton import S
7
+ from sympy.core.symbol import (Dummy, Symbol, symbols)
8
+ from sympy.functions.elementary.exponential import (exp, log)
9
+ from sympy.functions.elementary.hyperbolic import (asinh, csch, cosh, coth, sech, sinh, tanh)
10
+ from sympy.functions.elementary.miscellaneous import sqrt
11
+ from sympy.functions.elementary.piecewise import Piecewise, piecewise_fold
12
+ from sympy.functions.elementary.trigonometric import (acos, acot, acsc, asec, asin, atan, cos, cot, csc, sec, sin, tan)
13
+ from sympy.functions.special.delta_functions import Heaviside, DiracDelta
14
+ from sympy.functions.special.elliptic_integrals import (elliptic_e, elliptic_f)
15
+ from sympy.functions.special.error_functions import (Chi, Ci, Ei, Shi, Si, erf, erfi, fresnelc, fresnels, li)
16
+ from sympy.functions.special.gamma_functions import uppergamma
17
+ from sympy.functions.special.polynomials import (assoc_laguerre, chebyshevt, chebyshevu, gegenbauer, hermite, jacobi, laguerre, legendre)
18
+ from sympy.functions.special.zeta_functions import polylog
19
+ from sympy.integrals.integrals import (Integral, integrate)
20
+ from sympy.logic.boolalg import And
21
+ from sympy.integrals.manualintegrate import (manualintegrate, find_substitutions,
22
+ _parts_rule, integral_steps, manual_subs)
23
+ from sympy.testing.pytest import raises, slow
24
+
25
+ x, y, z, u, n, a, b, c, d, e = symbols('x y z u n a b c d e')
26
+ f = Function('f')
27
+
28
+
29
+ def assert_is_integral_of(f: Expr, F: Expr):
30
+ assert manualintegrate(f, x) == F
31
+ assert F.diff(x).equals(f)
32
+
33
+
34
+ def test_find_substitutions():
35
+ assert find_substitutions((cot(x)**2 + 1)**2*csc(x)**2*cot(x)**2, x, u) == \
36
+ [(cot(x), 1, -u**6 - 2*u**4 - u**2)]
37
+ assert find_substitutions((sec(x)**2 + tan(x) * sec(x)) / (sec(x) + tan(x)),
38
+ x, u) == [(sec(x) + tan(x), 1, 1/u)]
39
+ assert (-x**2, Rational(-1, 2), exp(u)) in find_substitutions(x * exp(-x**2), x, u)
40
+ assert not find_substitutions(Derivative(f(x), x)**2, x, u)
41
+
42
+
43
+ def test_manualintegrate_polynomials():
44
+ assert manualintegrate(y, x) == x*y
45
+ assert manualintegrate(exp(2), x) == x * exp(2)
46
+ assert manualintegrate(x**2, x) == x**3 / 3
47
+ assert manualintegrate(3 * x**2 + 4 * x**3, x) == x**3 + x**4
48
+
49
+ assert manualintegrate((x + 2)**3, x) == (x + 2)**4 / 4
50
+ assert manualintegrate((3*x + 4)**2, x) == (3*x + 4)**3 / 9
51
+
52
+ assert manualintegrate((u + 2)**3, u) == (u + 2)**4 / 4
53
+ assert manualintegrate((3*u + 4)**2, u) == (3*u + 4)**3 / 9
54
+
55
+
56
+ def test_manualintegrate_exponentials():
57
+ assert manualintegrate(exp(2*x), x) == exp(2*x) / 2
58
+ assert manualintegrate(2**x, x) == (2 ** x) / log(2)
59
+ assert_is_integral_of(1/sqrt(1-exp(2*x)),
60
+ log(sqrt(1 - exp(2*x)) - 1)/2 - log(sqrt(1 - exp(2*x)) + 1)/2)
61
+
62
+ assert manualintegrate(1 / x, x) == log(x)
63
+ assert manualintegrate(1 / (2*x + 3), x) == log(2*x + 3) / 2
64
+ assert manualintegrate(log(x)**2 / x, x) == log(x)**3 / 3
65
+
66
+ assert_is_integral_of(x**x*(log(x)+1), x**x)
67
+
68
+
69
+ def test_manualintegrate_parts():
70
+ assert manualintegrate(exp(x) * sin(x), x) == \
71
+ (exp(x) * sin(x)) / 2 - (exp(x) * cos(x)) / 2
72
+ assert manualintegrate(2*x*cos(x), x) == 2*x*sin(x) + 2*cos(x)
73
+ assert manualintegrate(x * log(x), x) == x**2*log(x)/2 - x**2/4
74
+ assert manualintegrate(log(x), x) == x * log(x) - x
75
+ assert manualintegrate((3*x**2 + 5) * exp(x), x) == \
76
+ 3*x**2*exp(x) - 6*x*exp(x) + 11*exp(x)
77
+ assert manualintegrate(atan(x), x) == x*atan(x) - log(x**2 + 1)/2
78
+
79
+ # Make sure _parts_rule doesn't pick u = constant but can pick dv =
80
+ # constant if necessary, e.g. for integrate(atan(x))
81
+ assert _parts_rule(cos(x), x) == None
82
+ assert _parts_rule(exp(x), x) == None
83
+ assert _parts_rule(x**2, x) == None
84
+ result = _parts_rule(atan(x), x)
85
+ assert result[0] == atan(x) and result[1] == 1
86
+
87
+
88
+ def test_manualintegrate_trigonometry():
89
+ assert manualintegrate(sin(x), x) == -cos(x)
90
+ assert manualintegrate(tan(x), x) == -log(cos(x))
91
+
92
+ assert manualintegrate(sec(x), x) == log(sec(x) + tan(x))
93
+ assert manualintegrate(csc(x), x) == -log(csc(x) + cot(x))
94
+
95
+ assert manualintegrate(sin(x) * cos(x), x) in [sin(x) ** 2 / 2, -cos(x)**2 / 2]
96
+ assert manualintegrate(-sec(x) * tan(x), x) == -sec(x)
97
+ assert manualintegrate(csc(x) * cot(x), x) == -csc(x)
98
+ assert manualintegrate(sec(x)**2, x) == tan(x)
99
+ assert manualintegrate(csc(x)**2, x) == -cot(x)
100
+
101
+ assert manualintegrate(x * sec(x**2), x) == log(tan(x**2) + sec(x**2))/2
102
+ assert manualintegrate(cos(x)*csc(sin(x)), x) == -log(cot(sin(x)) + csc(sin(x)))
103
+ assert manualintegrate(cos(3*x)*sec(x), x) == -x + sin(2*x)
104
+ assert manualintegrate(sin(3*x)*sec(x), x) == \
105
+ -3*log(cos(x)) + 2*log(cos(x)**2) - 2*cos(x)**2
106
+
107
+ assert_is_integral_of(sinh(2*x), cosh(2*x)/2)
108
+ assert_is_integral_of(x*cosh(x**2), sinh(x**2)/2)
109
+ assert_is_integral_of(tanh(x), log(cosh(x)))
110
+ assert_is_integral_of(coth(x), log(sinh(x)))
111
+ f, F = sech(x), 2*atan(tanh(x/2))
112
+ assert manualintegrate(f, x) == F
113
+ assert (F.diff(x) - f).rewrite(exp).simplify() == 0 # todo: equals returns None
114
+ f, F = csch(x), log(tanh(x/2))
115
+ assert manualintegrate(f, x) == F
116
+ assert (F.diff(x) - f).rewrite(exp).simplify() == 0
117
+
118
+
119
+ @slow
120
+ def test_manualintegrate_trigpowers():
121
+ assert manualintegrate(sin(x)**2 * cos(x), x) == sin(x)**3 / 3
122
+ assert manualintegrate(sin(x)**2 * cos(x) **2, x) == \
123
+ x / 8 - sin(4*x) / 32
124
+ assert manualintegrate(sin(x) * cos(x)**3, x) == -cos(x)**4 / 4
125
+ assert manualintegrate(sin(x)**3 * cos(x)**2, x) == \
126
+ cos(x)**5 / 5 - cos(x)**3 / 3
127
+
128
+ assert manualintegrate(tan(x)**3 * sec(x), x) == sec(x)**3/3 - sec(x)
129
+ assert manualintegrate(tan(x) * sec(x) **2, x) == sec(x)**2/2
130
+
131
+ assert manualintegrate(cot(x)**5 * csc(x), x) == \
132
+ -csc(x)**5/5 + 2*csc(x)**3/3 - csc(x)
133
+ assert manualintegrate(cot(x)**2 * csc(x)**6, x) == \
134
+ -cot(x)**7/7 - 2*cot(x)**5/5 - cot(x)**3/3
135
+
136
+
137
+ @slow
138
+ def test_manualintegrate_inversetrig():
139
+ # atan
140
+ assert manualintegrate(exp(x) / (1 + exp(2*x)), x) == atan(exp(x))
141
+ assert manualintegrate(1 / (4 + 9 * x**2), x) == atan(3 * x/2) / 6
142
+ assert manualintegrate(1 / (16 + 16 * x**2), x) == atan(x) / 16
143
+ assert manualintegrate(1 / (4 + x**2), x) == atan(x / 2) / 2
144
+ assert manualintegrate(1 / (1 + 4 * x**2), x) == atan(2*x) / 2
145
+ ra = Symbol('a', real=True)
146
+ rb = Symbol('b', real=True)
147
+ assert manualintegrate(1/(ra + rb*x**2), x) == \
148
+ Piecewise((atan(x/sqrt(ra/rb))/(rb*sqrt(ra/rb)), ra/rb > 0),
149
+ ((log(x - sqrt(-ra/rb)) - log(x + sqrt(-ra/rb)))/(2*sqrt(rb)*sqrt(-ra)), True))
150
+ assert manualintegrate(1/(4 + rb*x**2), x) == \
151
+ Piecewise((atan(x/(2*sqrt(1/rb)))/(2*rb*sqrt(1/rb)), 1/rb > 0),
152
+ (-I*(log(x - 2*sqrt(-1/rb)) - log(x + 2*sqrt(-1/rb)))/(4*sqrt(rb)), True))
153
+ assert manualintegrate(1/(ra + 4*x**2), x) == \
154
+ Piecewise((atan(2*x/sqrt(ra))/(2*sqrt(ra)), ra > 0),
155
+ ((log(x - sqrt(-ra)/2) - log(x + sqrt(-ra)/2))/(4*sqrt(-ra)), True))
156
+ assert manualintegrate(1/(4 + 4*x**2), x) == atan(x) / 4
157
+
158
+ assert manualintegrate(1/(a + b*x**2), x) == Piecewise((atan(x/sqrt(a/b))/(b*sqrt(a/b)), Ne(a, 0)),
159
+ (-1/(b*x), True))
160
+
161
+ # asin
162
+ assert manualintegrate(1/sqrt(1-x**2), x) == asin(x)
163
+ assert manualintegrate(1/sqrt(4-4*x**2), x) == asin(x)/2
164
+ assert manualintegrate(3/sqrt(1-9*x**2), x) == asin(3*x)
165
+ assert manualintegrate(1/sqrt(4-9*x**2), x) == asin(x*Rational(3, 2))/3
166
+
167
+ # asinh
168
+ assert manualintegrate(1/sqrt(x**2 + 1), x) == \
169
+ asinh(x)
170
+ assert manualintegrate(1/sqrt(x**2 + 4), x) == \
171
+ asinh(x/2)
172
+ assert manualintegrate(1/sqrt(4*x**2 + 4), x) == \
173
+ asinh(x)/2
174
+ assert manualintegrate(1/sqrt(4*x**2 + 1), x) == \
175
+ asinh(2*x)/2
176
+ assert manualintegrate(1/sqrt(ra*x**2 + 1), x) == \
177
+ Piecewise((asin(x*sqrt(-ra))/sqrt(-ra), ra < 0), (asinh(sqrt(ra)*x)/sqrt(ra), ra > 0), (x, True))
178
+ assert manualintegrate(1/sqrt(ra + x**2), x) == \
179
+ Piecewise((asinh(x*sqrt(1/ra)), ra > 0), (log(2*x + 2*sqrt(ra + x**2)), True))
180
+
181
+ # log
182
+ assert manualintegrate(1/sqrt(x**2 - 1), x) == log(2*x + 2*sqrt(x**2 - 1))
183
+ assert manualintegrate(1/sqrt(x**2 - 4), x) == log(2*x + 2*sqrt(x**2 - 4))
184
+ assert manualintegrate(1/sqrt(4*x**2 - 4), x) == log(8*x + 4*sqrt(4*x**2 - 4))/2
185
+ assert manualintegrate(1/sqrt(9*x**2 - 1), x) == log(18*x + 6*sqrt(9*x**2 - 1))/3
186
+ assert manualintegrate(1/sqrt(ra*x**2 - 4), x) == \
187
+ Piecewise((log(2*sqrt(ra)*sqrt(ra*x**2 - 4) + 2*ra*x)/sqrt(ra), Ne(ra, 0)), (-I*x/2, True))
188
+ assert manualintegrate(1/sqrt(-ra + 4*x**2), x) == \
189
+ Piecewise((asinh(2*x*sqrt(-1/ra))/2, ra < 0), (log(8*x + 4*sqrt(-ra + 4*x**2))/2, True))
190
+
191
+ # From https://www.wikiwand.com/en/List_of_integrals_of_inverse_trigonometric_functions
192
+ # asin
193
+ assert manualintegrate(asin(x), x) == x*asin(x) + sqrt(1 - x**2)
194
+ assert manualintegrate(asin(a*x), x) == Piecewise(((a*x*asin(a*x) + sqrt(-a**2*x**2 + 1))/a, Ne(a, 0)), (0, True))
195
+ assert manualintegrate(x*asin(a*x), x) == \
196
+ -a*Piecewise((-x*sqrt(-a**2*x**2 + 1)/(2*a**2) +
197
+ log(-2*a**2*x + 2*sqrt(-a**2)*sqrt(-a**2*x**2 + 1))/(2*a**2*sqrt(-a**2)), Ne(a**2, 0)),
198
+ (x**3/3, True))/2 + x**2*asin(a*x)/2
199
+ # acos
200
+ assert manualintegrate(acos(x), x) == x*acos(x) - sqrt(1 - x**2)
201
+ assert manualintegrate(acos(a*x), x) == Piecewise(((a*x*acos(a*x) - sqrt(-a**2*x**2 + 1))/a, Ne(a, 0)), (pi*x/2, True))
202
+ assert manualintegrate(x*acos(a*x), x) == \
203
+ a*Piecewise((-x*sqrt(-a**2*x**2 + 1)/(2*a**2) +
204
+ log(-2*a**2*x + 2*sqrt(-a**2)*sqrt(-a**2*x**2 + 1))/(2*a**2*sqrt(-a**2)), Ne(a**2, 0)),
205
+ (x**3/3, True))/2 + x**2*acos(a*x)/2
206
+ # atan
207
+ assert manualintegrate(atan(x), x) == x*atan(x) - log(x**2 + 1)/2
208
+ assert manualintegrate(atan(a*x), x) == Piecewise(((a*x*atan(a*x) - log(a**2*x**2 + 1)/2)/a, Ne(a, 0)), (0, True))
209
+ assert manualintegrate(x*atan(a*x), x) == -a*(x/a**2 - atan(x/sqrt(a**(-2)))/(a**4*sqrt(a**(-2))))/2 + x**2*atan(a*x)/2
210
+ # acsc
211
+ assert manualintegrate(acsc(x), x) == x*acsc(x) + Integral(1/(x*sqrt(1 - 1/x**2)), x)
212
+ assert manualintegrate(acsc(a*x), x) == x*acsc(a*x) + Integral(1/(x*sqrt(1 - 1/(a**2*x**2))), x)/a
213
+ assert manualintegrate(x*acsc(a*x), x) == x**2*acsc(a*x)/2 + Integral(1/sqrt(1 - 1/(a**2*x**2)), x)/(2*a)
214
+ # asec
215
+ assert manualintegrate(asec(x), x) == x*asec(x) - Integral(1/(x*sqrt(1 - 1/x**2)), x)
216
+ assert manualintegrate(asec(a*x), x) == x*asec(a*x) - Integral(1/(x*sqrt(1 - 1/(a**2*x**2))), x)/a
217
+ assert manualintegrate(x*asec(a*x), x) == x**2*asec(a*x)/2 - Integral(1/sqrt(1 - 1/(a**2*x**2)), x)/(2*a)
218
+ # acot
219
+ assert manualintegrate(acot(x), x) == x*acot(x) + log(x**2 + 1)/2
220
+ assert manualintegrate(acot(a*x), x) == Piecewise(((a*x*acot(a*x) + log(a**2*x**2 + 1)/2)/a, Ne(a, 0)), (pi*x/2, True))
221
+ assert manualintegrate(x*acot(a*x), x) == a*(x/a**2 - atan(x/sqrt(a**(-2)))/(a**4*sqrt(a**(-2))))/2 + x**2*acot(a*x)/2
222
+
223
+ # piecewise
224
+ assert manualintegrate(1/sqrt(ra-rb*x**2), x) == \
225
+ Piecewise((asin(x*sqrt(rb/ra))/sqrt(rb), And(-rb < 0, ra > 0)),
226
+ (asinh(x*sqrt(-rb/ra))/sqrt(-rb), And(-rb > 0, ra > 0)),
227
+ (log(-2*rb*x + 2*sqrt(-rb)*sqrt(ra - rb*x**2))/sqrt(-rb), Ne(rb, 0)),
228
+ (x/sqrt(ra), True))
229
+ assert manualintegrate(1/sqrt(ra + rb*x**2), x) == \
230
+ Piecewise((asin(x*sqrt(-rb/ra))/sqrt(-rb), And(ra > 0, rb < 0)),
231
+ (asinh(x*sqrt(rb/ra))/sqrt(rb), And(ra > 0, rb > 0)),
232
+ (log(2*sqrt(rb)*sqrt(ra + rb*x**2) + 2*rb*x)/sqrt(rb), Ne(rb, 0)),
233
+ (x/sqrt(ra), True))
234
+
235
+
236
+ def test_manualintegrate_trig_substitution():
237
+ assert manualintegrate(sqrt(16*x**2 - 9)/x, x) == \
238
+ Piecewise((sqrt(16*x**2 - 9) - 3*acos(3/(4*x)),
239
+ And(x < Rational(3, 4), x > Rational(-3, 4))))
240
+ assert manualintegrate(1/(x**4 * sqrt(25-x**2)), x) == \
241
+ Piecewise((-sqrt(-x**2/25 + 1)/(125*x) -
242
+ (-x**2/25 + 1)**(3*S.Half)/(15*x**3), And(x < 5, x > -5)))
243
+ assert manualintegrate(x**7/(49*x**2 + 1)**(3 * S.Half), x) == \
244
+ ((49*x**2 + 1)**(5*S.Half)/28824005 -
245
+ (49*x**2 + 1)**(3*S.Half)/5764801 +
246
+ 3*sqrt(49*x**2 + 1)/5764801 + 1/(5764801*sqrt(49*x**2 + 1)))
247
+
248
+ def test_manualintegrate_trivial_substitution():
249
+ assert manualintegrate((exp(x) - exp(-x))/x, x) == -Ei(-x) + Ei(x)
250
+ f = Function('f')
251
+ assert manualintegrate((f(x) - f(-x))/x, x) == \
252
+ -Integral(f(-x)/x, x) + Integral(f(x)/x, x)
253
+
254
+
255
+ def test_manualintegrate_rational():
256
+ assert manualintegrate(1/(4 - x**2), x) == -log(x - 2)/4 + log(x + 2)/4
257
+ assert manualintegrate(1/(-1 + x**2), x) == log(x - 1)/2 - log(x + 1)/2
258
+
259
+
260
+ def test_manualintegrate_special():
261
+ f, F = 4*exp(-x**2/3), 2*sqrt(3)*sqrt(pi)*erf(sqrt(3)*x/3)
262
+ assert_is_integral_of(f, F)
263
+ f, F = 3*exp(4*x**2), 3*sqrt(pi)*erfi(2*x)/4
264
+ assert_is_integral_of(f, F)
265
+ f, F = x**Rational(1, 3)*exp(-x/8), -16*uppergamma(Rational(4, 3), x/8)
266
+ assert_is_integral_of(f, F)
267
+ f, F = exp(2*x)/x, Ei(2*x)
268
+ assert_is_integral_of(f, F)
269
+ f, F = exp(1 + 2*x - x**2), sqrt(pi)*exp(2)*erf(x - 1)/2
270
+ assert_is_integral_of(f, F)
271
+ f = sin(x**2 + 4*x + 1)
272
+ F = (sqrt(2)*sqrt(pi)*(-sin(3)*fresnelc(sqrt(2)*(2*x + 4)/(2*sqrt(pi))) +
273
+ cos(3)*fresnels(sqrt(2)*(2*x + 4)/(2*sqrt(pi))))/2)
274
+ assert_is_integral_of(f, F)
275
+ f, F = cos(4*x**2), sqrt(2)*sqrt(pi)*fresnelc(2*sqrt(2)*x/sqrt(pi))/4
276
+ assert_is_integral_of(f, F)
277
+ f, F = sin(3*x + 2)/x, sin(2)*Ci(3*x) + cos(2)*Si(3*x)
278
+ assert_is_integral_of(f, F)
279
+ f, F = sinh(3*x - 2)/x, -sinh(2)*Chi(3*x) + cosh(2)*Shi(3*x)
280
+ assert_is_integral_of(f, F)
281
+ f, F = 5*cos(2*x - 3)/x, 5*cos(3)*Ci(2*x) + 5*sin(3)*Si(2*x)
282
+ assert_is_integral_of(f, F)
283
+ f, F = cosh(x/2)/x, Chi(x/2)
284
+ assert_is_integral_of(f, F)
285
+ f, F = cos(x**2)/x, Ci(x**2)/2
286
+ assert_is_integral_of(f, F)
287
+ f, F = 1/log(2*x + 1), li(2*x + 1)/2
288
+ assert_is_integral_of(f, F)
289
+ f, F = polylog(2, 5*x)/x, polylog(3, 5*x)
290
+ assert_is_integral_of(f, F)
291
+ f, F = 5/sqrt(3 - 2*sin(x)**2), 5*sqrt(3)*elliptic_f(x, Rational(2, 3))/3
292
+ assert_is_integral_of(f, F)
293
+ f, F = sqrt(4 + 9*sin(x)**2), 2*elliptic_e(x, Rational(-9, 4))
294
+ assert_is_integral_of(f, F)
295
+
296
+
297
+ def test_manualintegrate_derivative():
298
+ assert manualintegrate(pi * Derivative(x**2 + 2*x + 3), x) == \
299
+ pi * (x**2 + 2*x + 3)
300
+ assert manualintegrate(Derivative(x**2 + 2*x + 3, y), x) == \
301
+ Integral(Derivative(x**2 + 2*x + 3, y))
302
+ assert manualintegrate(Derivative(sin(x), x, x, x, y), x) == \
303
+ Derivative(sin(x), x, x, y)
304
+
305
+
306
+ def test_manualintegrate_Heaviside():
307
+ assert_is_integral_of(DiracDelta(3*x+2), Heaviside(3*x+2)/3)
308
+ assert_is_integral_of(DiracDelta(3*x, 0), Heaviside(3*x)/3)
309
+ assert manualintegrate(DiracDelta(a+b*x, 1), x) == \
310
+ Piecewise((DiracDelta(a + b*x)/b, Ne(b, 0)), (x*DiracDelta(a, 1), True))
311
+ assert_is_integral_of(DiracDelta(x/3-1, 2), 3*DiracDelta(x/3-1, 1))
312
+ assert manualintegrate(Heaviside(x), x) == x*Heaviside(x)
313
+ assert manualintegrate(x*Heaviside(2), x) == x**2/2
314
+ assert manualintegrate(x*Heaviside(-2), x) == 0
315
+ assert manualintegrate(x*Heaviside( x), x) == x**2*Heaviside( x)/2
316
+ assert manualintegrate(x*Heaviside(-x), x) == x**2*Heaviside(-x)/2
317
+ assert manualintegrate(Heaviside(2*x + 4), x) == (x+2)*Heaviside(2*x + 4)
318
+ assert manualintegrate(x*Heaviside(x), x) == x**2*Heaviside(x)/2
319
+ assert manualintegrate(Heaviside(x + 1)*Heaviside(1 - x)*x**2, x) == \
320
+ ((x**3/3 + Rational(1, 3))*Heaviside(x + 1) - Rational(2, 3))*Heaviside(-x + 1)
321
+
322
+ y = Symbol('y')
323
+ assert manualintegrate(sin(7 + x)*Heaviside(3*x - 7), x) == \
324
+ (- cos(x + 7) + cos(Rational(28, 3)))*Heaviside(3*x - S(7))
325
+
326
+ assert manualintegrate(sin(y + x)*Heaviside(3*x - y), x) == \
327
+ (cos(y*Rational(4, 3)) - cos(x + y))*Heaviside(3*x - y)
328
+
329
+
330
+ def test_manualintegrate_orthogonal_poly():
331
+ n = symbols('n')
332
+ a, b = 7, Rational(5, 3)
333
+ polys = [jacobi(n, a, b, x), gegenbauer(n, a, x), chebyshevt(n, x),
334
+ chebyshevu(n, x), legendre(n, x), hermite(n, x), laguerre(n, x),
335
+ assoc_laguerre(n, a, x)]
336
+ for p in polys:
337
+ integral = manualintegrate(p, x)
338
+ for deg in [-2, -1, 0, 1, 3, 5, 8]:
339
+ # some accept negative "degree", some do not
340
+ try:
341
+ p_subbed = p.subs(n, deg)
342
+ except ValueError:
343
+ continue
344
+ assert (integral.subs(n, deg).diff(x) - p_subbed).expand() == 0
345
+
346
+ # can also integrate simple expressions with these polynomials
347
+ q = x*p.subs(x, 2*x + 1)
348
+ integral = manualintegrate(q, x)
349
+ for deg in [2, 4, 7]:
350
+ assert (integral.subs(n, deg).diff(x) - q.subs(n, deg)).expand() == 0
351
+
352
+ # cannot integrate with respect to any other parameter
353
+ t = symbols('t')
354
+ for i in range(len(p.args) - 1):
355
+ new_args = list(p.args)
356
+ new_args[i] = t
357
+ assert isinstance(manualintegrate(p.func(*new_args), t), Integral)
358
+
359
+
360
+ @slow
361
+ def test_issue_6799():
362
+ r, x, phi = map(Symbol, 'r x phi'.split())
363
+ n = Symbol('n', integer=True, positive=True)
364
+
365
+ integrand = (cos(n*(x-phi))*cos(n*x))
366
+ limits = (x, -pi, pi)
367
+ assert manualintegrate(integrand, x) == \
368
+ ((n*x/2 + sin(2*n*x)/4)*cos(n*phi) - sin(n*phi)*cos(n*x)**2/2)/n
369
+ assert r * integrate(integrand, limits).trigsimp() / pi == r * cos(n * phi)
370
+ assert not integrate(integrand, limits).has(Dummy)
371
+
372
+
373
+ def test_issue_12251():
374
+ assert manualintegrate(x**y, x) == Piecewise(
375
+ (x**(y + 1)/(y + 1), Ne(y, -1)), (log(x), True))
376
+
377
+
378
+ def test_issue_3796():
379
+ assert manualintegrate(diff(exp(x + x**2)), x) == exp(x + x**2)
380
+ assert integrate(x * exp(x**4), x, risch=False) == -I*sqrt(pi)*erf(I*x**2)/4
381
+
382
+
383
+ def test_manual_true():
384
+ assert integrate(exp(x) * sin(x), x, manual=True) == \
385
+ (exp(x) * sin(x)) / 2 - (exp(x) * cos(x)) / 2
386
+ assert integrate(sin(x) * cos(x), x, manual=True) in \
387
+ [sin(x) ** 2 / 2, -cos(x)**2 / 2]
388
+
389
+
390
+ def test_issue_6746():
391
+ y = Symbol('y')
392
+ n = Symbol('n')
393
+ assert manualintegrate(y**x, x) == Piecewise(
394
+ (y**x/log(y), Ne(log(y), 0)), (x, True))
395
+ assert manualintegrate(y**(n*x), x) == Piecewise(
396
+ (Piecewise(
397
+ (y**(n*x)/log(y), Ne(log(y), 0)),
398
+ (n*x, True)
399
+ )/n, Ne(n, 0)),
400
+ (x, True))
401
+ assert manualintegrate(exp(n*x), x) == Piecewise(
402
+ (exp(n*x)/n, Ne(n, 0)), (x, True))
403
+
404
+ y = Symbol('y', positive=True)
405
+ assert manualintegrate((y + 1)**x, x) == (y + 1)**x/log(y + 1)
406
+ y = Symbol('y', zero=True)
407
+ assert manualintegrate((y + 1)**x, x) == x
408
+ y = Symbol('y')
409
+ n = Symbol('n', nonzero=True)
410
+ assert manualintegrate(y**(n*x), x) == Piecewise(
411
+ (y**(n*x)/log(y), Ne(log(y), 0)), (n*x, True))/n
412
+ y = Symbol('y', positive=True)
413
+ assert manualintegrate((y + 1)**(n*x), x) == \
414
+ (y + 1)**(n*x)/(n*log(y + 1))
415
+ a = Symbol('a', negative=True)
416
+ b = Symbol('b')
417
+ assert manualintegrate(1/(a + b*x**2), x) == atan(x/sqrt(a/b))/(b*sqrt(a/b))
418
+ b = Symbol('b', negative=True)
419
+ assert manualintegrate(1/(a + b*x**2), x) == \
420
+ atan(x/(sqrt(-a)*sqrt(-1/b)))/(b*sqrt(-a)*sqrt(-1/b))
421
+ assert manualintegrate(1/((x**a + y**b + 4)*sqrt(a*x**2 + 1)), x) == \
422
+ y**(-b)*Integral(x**(-a)/(y**(-b)*sqrt(a*x**2 + 1) +
423
+ x**(-a)*sqrt(a*x**2 + 1) + 4*x**(-a)*y**(-b)*sqrt(a*x**2 + 1)), x)
424
+ assert manualintegrate(1/((x**2 + 4)*sqrt(4*x**2 + 1)), x) == \
425
+ Integral(1/((x**2 + 4)*sqrt(4*x**2 + 1)), x)
426
+ assert manualintegrate(1/(x - a**x + x*b**2), x) == \
427
+ Integral(1/(-a**x + b**2*x + x), x)
428
+
429
+
430
+ @slow
431
+ def test_issue_2850():
432
+ assert manualintegrate(asin(x)*log(x), x) == -x*asin(x) - sqrt(-x**2 + 1) \
433
+ + (x*asin(x) + sqrt(-x**2 + 1))*log(x) - Integral(sqrt(-x**2 + 1)/x, x)
434
+ assert manualintegrate(acos(x)*log(x), x) == -x*acos(x) + sqrt(-x**2 + 1) + \
435
+ (x*acos(x) - sqrt(-x**2 + 1))*log(x) + Integral(sqrt(-x**2 + 1)/x, x)
436
+ assert manualintegrate(atan(x)*log(x), x) == -x*atan(x) + (x*atan(x) - \
437
+ log(x**2 + 1)/2)*log(x) + log(x**2 + 1)/2 + Integral(log(x**2 + 1)/x, x)/2
438
+
439
+
440
+ def test_issue_9462():
441
+ assert manualintegrate(sin(2*x)*exp(x), x) == exp(x)*sin(2*x)/5 - 2*exp(x)*cos(2*x)/5
442
+ assert not integral_steps(sin(2*x)*exp(x), x).contains_dont_know()
443
+ assert manualintegrate((x - 3) / (x**2 - 2*x + 2)**2, x) == \
444
+ Integral(x/(x**4 - 4*x**3 + 8*x**2 - 8*x + 4), x) \
445
+ - 3*Integral(1/(x**4 - 4*x**3 + 8*x**2 - 8*x + 4), x)
446
+
447
+
448
+ def test_cyclic_parts():
449
+ f = cos(x)*exp(x/4)
450
+ F = 16*exp(x/4)*sin(x)/17 + 4*exp(x/4)*cos(x)/17
451
+ assert manualintegrate(f, x) == F and F.diff(x) == f
452
+ f = x*cos(x)*exp(x/4)
453
+ F = (x*(16*exp(x/4)*sin(x)/17 + 4*exp(x/4)*cos(x)/17) -
454
+ 128*exp(x/4)*sin(x)/289 + 240*exp(x/4)*cos(x)/289)
455
+ assert manualintegrate(f, x) == F and F.diff(x) == f
456
+
457
+
458
+ @slow
459
+ def test_issue_10847_slow():
460
+ assert manualintegrate((4*x**4 + 4*x**3 + 16*x**2 + 12*x + 8)
461
+ / (x**6 + 2*x**5 + 3*x**4 + 4*x**3 + 3*x**2 + 2*x + 1), x) == \
462
+ 2*x/(x**2 + 1) + 3*atan(x) - 1/(x**2 + 1) - 3/(x + 1)
463
+
464
+
465
+ @slow
466
+ def test_issue_10847():
467
+
468
+ assert manualintegrate(x**2 / (x**2 - c), x) == \
469
+ c*Piecewise((atan(x/sqrt(-c))/sqrt(-c), Ne(c, 0)), (-1/x, True)) + x
470
+
471
+ rc = Symbol('c', real=True)
472
+ assert manualintegrate(x**2 / (x**2 - rc), x) == \
473
+ rc*Piecewise((atan(x/sqrt(-rc))/sqrt(-rc), rc < 0),
474
+ ((log(-sqrt(rc) + x) - log(sqrt(rc) + x))/(2*sqrt(rc)), True)) + x
475
+
476
+ assert manualintegrate(sqrt(x - y) * log(z / x), x) == \
477
+ 4*y**2*Piecewise((atan(sqrt(x - y)/sqrt(y))/sqrt(y), Ne(y, 0)),
478
+ (-1/sqrt(x - y), True))/3 - 4*y*sqrt(x - y)/3 + \
479
+ 2*(x - y)**Rational(3, 2)*log(z/x)/3 + 4*(x - y)**Rational(3, 2)/9
480
+ ry = Symbol('y', real=True)
481
+ rz = Symbol('z', real=True)
482
+ assert manualintegrate(sqrt(x - ry) * log(rz / x), x) == \
483
+ 4*ry**2*Piecewise((atan(sqrt(x - ry)/sqrt(ry))/sqrt(ry), ry > 0),
484
+ ((log(-sqrt(-ry) + sqrt(x - ry)) - log(sqrt(-ry) + sqrt(x - ry)))/(2*sqrt(-ry)), True))/3 \
485
+ - 4*ry*sqrt(x - ry)/3 + 2*(x - ry)**Rational(3, 2)*log(rz/x)/3 \
486
+ + 4*(x - ry)**Rational(3, 2)/9
487
+
488
+ assert manualintegrate(sqrt(x) * log(x), x) == 2*x**Rational(3, 2)*log(x)/3 - 4*x**Rational(3, 2)/9
489
+
490
+ result = manualintegrate(sqrt(a*x + b) / x, x)
491
+ assert result == Piecewise((-2*b*Piecewise(
492
+ (-atan(sqrt(a*x + b)/sqrt(-b))/sqrt(-b), Ne(b, 0)),
493
+ (1/sqrt(a*x + b), True)) + 2*sqrt(a*x + b), Ne(a, 0)),
494
+ (sqrt(b)*log(x), True))
495
+ assert piecewise_fold(result) == Piecewise(
496
+ (2*b*atan(sqrt(a*x + b)/sqrt(-b))/sqrt(-b) + 2*sqrt(a*x + b), Ne(a, 0) & Ne(b, 0)),
497
+ (-2*b/sqrt(a*x + b) + 2*sqrt(a*x + b), Ne(a, 0)),
498
+ (sqrt(b)*log(x), True))
499
+
500
+ ra = Symbol('a', real=True)
501
+ rb = Symbol('b', real=True)
502
+ assert manualintegrate(sqrt(ra*x + rb) / x, x) == \
503
+ Piecewise(
504
+ (-2*rb*Piecewise(
505
+ (-atan(sqrt(ra*x + rb)/sqrt(-rb))/sqrt(-rb), rb < 0),
506
+ (-I*(log(-sqrt(rb) + sqrt(ra*x + rb)) - log(sqrt(rb) + sqrt(ra*x + rb)))/(2*sqrt(-rb)), True)) +
507
+ 2*sqrt(ra*x + rb), Ne(ra, 0)),
508
+ (sqrt(rb)*log(x), True))
509
+
510
+ assert expand(manualintegrate(sqrt(ra*x + rb) / (x + rc), x)) == \
511
+ Piecewise((-2*ra*rc*Piecewise((atan(sqrt(ra*x + rb)/sqrt(ra*rc - rb))/sqrt(ra*rc - rb), ra*rc - rb > 0),
512
+ (log(-sqrt(-ra*rc + rb) + sqrt(ra*x + rb))/(2*sqrt(-ra*rc + rb)) -
513
+ log(sqrt(-ra*rc + rb) + sqrt(ra*x + rb))/(2*sqrt(-ra*rc + rb)), True)) +
514
+ 2*rb*Piecewise((atan(sqrt(ra*x + rb)/sqrt(ra*rc - rb))/sqrt(ra*rc - rb), ra*rc - rb > 0),
515
+ (log(-sqrt(-ra*rc + rb) + sqrt(ra*x + rb))/(2*sqrt(-ra*rc + rb)) -
516
+ log(sqrt(-ra*rc + rb) + sqrt(ra*x + rb))/(2*sqrt(-ra*rc + rb)), True)) +
517
+ 2*sqrt(ra*x + rb), Ne(ra, 0)), (sqrt(rb)*log(rc + x), True))
518
+
519
+ assert manualintegrate(sqrt(2*x + 3) / (x + 1), x) == 2*sqrt(2*x + 3) - log(sqrt(2*x + 3) + 1) + log(sqrt(2*x + 3) - 1)
520
+ assert manualintegrate(sqrt(2*x + 3) / 2 * x, x) == (2*x + 3)**Rational(5, 2)/20 - (2*x + 3)**Rational(3, 2)/4
521
+ assert manualintegrate(x**Rational(3,2) * log(x), x) == 2*x**Rational(5,2)*log(x)/5 - 4*x**Rational(5,2)/25
522
+ assert manualintegrate(x**(-3) * log(x), x) == -log(x)/(2*x**2) - 1/(4*x**2)
523
+ assert manualintegrate(log(y)/(y**2*(1 - 1/y)), y) == \
524
+ log(y)*log(-1 + 1/y) - Integral(log(-1 + 1/y)/y, y)
525
+
526
+
527
+ def test_issue_12899():
528
+ assert manualintegrate(f(x,y).diff(x),y) == Integral(Derivative(f(x,y),x),y)
529
+ assert manualintegrate(f(x,y).diff(y).diff(x),y) == Derivative(f(x,y),x)
530
+
531
+
532
+ def test_constant_independent_of_symbol():
533
+ assert manualintegrate(Integral(y, (x, 1, 2)), x) == \
534
+ x*Integral(y, (x, 1, 2))
535
+
536
+
537
+ def test_issue_12641():
538
+ assert manualintegrate(sin(2*x), x) == -cos(2*x)/2
539
+ assert manualintegrate(cos(x)*sin(2*x), x) == -2*cos(x)**3/3
540
+ assert manualintegrate((sin(2*x)*cos(x))/(1 + cos(x)), x) == \
541
+ -2*log(cos(x) + 1) - cos(x)**2 + 2*cos(x)
542
+
543
+
544
+ @slow
545
+ def test_issue_13297():
546
+ assert manualintegrate(sin(x) * cos(x)**5, x) == -cos(x)**6 / 6
547
+
548
+
549
+ def test_issue_14470():
550
+ assert_is_integral_of(1/(x*sqrt(x + 1)), log(sqrt(x + 1) - 1) - log(sqrt(x + 1) + 1))
551
+
552
+
553
+ @slow
554
+ def test_issue_9858():
555
+ assert manualintegrate(exp(x)*cos(exp(x)), x) == sin(exp(x))
556
+ assert manualintegrate(exp(2*x)*cos(exp(x)), x) == \
557
+ exp(x)*sin(exp(x)) + cos(exp(x))
558
+ res = manualintegrate(exp(10*x)*sin(exp(x)), x)
559
+ assert not res.has(Integral)
560
+ assert res.diff(x) == exp(10*x)*sin(exp(x))
561
+ # an example with many similar integrations by parts
562
+ assert manualintegrate(sum(x*exp(k*x) for k in range(1, 8)), x) == (
563
+ x*exp(7*x)/7 + x*exp(6*x)/6 + x*exp(5*x)/5 + x*exp(4*x)/4 +
564
+ x*exp(3*x)/3 + x*exp(2*x)/2 + x*exp(x) - exp(7*x)/49 -exp(6*x)/36 -
565
+ exp(5*x)/25 - exp(4*x)/16 - exp(3*x)/9 - exp(2*x)/4 - exp(x))
566
+
567
+
568
+ def test_issue_8520():
569
+ assert manualintegrate(x/(x**4 + 1), x) == atan(x**2)/2
570
+ assert manualintegrate(x**2/(x**6 + 25), x) == atan(x**3/5)/15
571
+ f = x/(9*x**4 + 4)**2
572
+ assert manualintegrate(f, x).diff(x).factor() == f
573
+
574
+
575
+ def test_manual_subs():
576
+ x, y = symbols('x y')
577
+ expr = log(x) + exp(x)
578
+ # if log(x) is y, then exp(y) is x
579
+ assert manual_subs(expr, log(x), y) == y + exp(exp(y))
580
+ # if exp(x) is y, then log(y) need not be x
581
+ assert manual_subs(expr, exp(x), y) == log(x) + y
582
+
583
+ raises(ValueError, lambda: manual_subs(expr, x))
584
+ raises(ValueError, lambda: manual_subs(expr, exp(x), x, y))
585
+
586
+
587
+ @slow
588
+ def test_issue_15471():
589
+ f = log(x)*cos(log(x))/x**Rational(3, 4)
590
+ F = -128*x**Rational(1, 4)*sin(log(x))/289 + 240*x**Rational(1, 4)*cos(log(x))/289 + (16*x**Rational(1, 4)*sin(log(x))/17 + 4*x**Rational(1, 4)*cos(log(x))/17)*log(x)
591
+ assert_is_integral_of(f, F)
592
+
593
+
594
+ def test_quadratic_denom():
595
+ f = (5*x + 2)/(3*x**2 - 2*x + 8)
596
+ assert manualintegrate(f, x) == 5*log(3*x**2 - 2*x + 8)/6 + 11*sqrt(23)*atan(3*sqrt(23)*(x - Rational(1, 3))/23)/69
597
+ g = 3/(2*x**2 + 3*x + 1)
598
+ assert manualintegrate(g, x) == 3*log(4*x + 2) - 3*log(4*x + 4)
599
+
600
+ def test_issue_22757():
601
+ assert manualintegrate(sin(x), y) == y * sin(x)
602
+
603
+
604
+ def test_issue_23348():
605
+ steps = integral_steps(tan(x), x)
606
+ constant_times_step = steps.substep.substep
607
+ assert constant_times_step.integrand == constant_times_step.constant * constant_times_step.other
608
+
609
+
610
+ def test_issue_23566():
611
+ i = Integral(1/sqrt(x**2 - 1), (x, -2, -1)).doit(manual=True)
612
+ assert i == -log(4 - 2*sqrt(3)) + log(2)
613
+ assert str(i.n()) == '1.31695789692482'
614
+
615
+
616
+ def test_issue_25093():
617
+ ap = Symbol('ap', positive=True)
618
+ an = Symbol('an', negative=True)
619
+ assert manualintegrate(exp(a*x**2 + b), x) == sqrt(pi)*exp(b)*erfi(sqrt(a)*x)/(2*sqrt(a))
620
+ assert manualintegrate(exp(ap*x**2 + b), x) == sqrt(pi)*exp(b)*erfi(sqrt(ap)*x)/(2*sqrt(ap))
621
+ assert manualintegrate(exp(an*x**2 + b), x) == -sqrt(pi)*exp(b)*erf(an*x/sqrt(-an))/(2*sqrt(-an))
622
+ assert manualintegrate(sin(a*x**2 + b), x) == (
623
+ sqrt(2)*sqrt(pi)*(sin(b)*fresnelc(sqrt(2)*sqrt(a)*x/sqrt(pi))
624
+ + cos(b)*fresnels(sqrt(2)*sqrt(a)*x/sqrt(pi)))/(2*sqrt(a)))
625
+ assert manualintegrate(cos(a*x**2 + b), x) == (
626
+ sqrt(2)*sqrt(pi)*(-sin(b)*fresnels(sqrt(2)*sqrt(a)*x/sqrt(pi))
627
+ + cos(b)*fresnelc(sqrt(2)*sqrt(a)*x/sqrt(pi)))/(2*sqrt(a)))
628
+
629
+
630
+ def test_nested_pow():
631
+ assert_is_integral_of(sqrt(x**2), x*sqrt(x**2)/2)
632
+ assert_is_integral_of(sqrt(x**(S(5)/3)), 6*x*sqrt(x**(S(5)/3))/11)
633
+ assert_is_integral_of(1/sqrt(x**2), x*log(x)/sqrt(x**2))
634
+ assert_is_integral_of(x*sqrt(x**(-4)), x**2*sqrt(x**-4)*log(x))
635
+ f = (c*(a+b*x)**d)**e
636
+ F1 = (c*(a + b*x)**d)**e*(a/b + x)/(d*e + 1)
637
+ F2 = (c*(a + b*x)**d)**e*(a/b + x)*log(a/b + x)
638
+ assert manualintegrate(f, x) == \
639
+ Piecewise((Piecewise((F1, Ne(d*e, -1)), (F2, True)), Ne(b, 0)), (x*(a**d*c)**e, True))
640
+ assert F1.diff(x).equals(f)
641
+ assert F2.diff(x).subs(d*e, -1).equals(f)
642
+
643
+
644
+ def test_manualintegrate_sqrt_linear():
645
+ assert_is_integral_of((5*x**3+4)/sqrt(2+3*x),
646
+ 10*(3*x + 2)**(S(7)/2)/567 - 4*(3*x + 2)**(S(5)/2)/27 +
647
+ 40*(3*x + 2)**(S(3)/2)/81 + 136*sqrt(3*x + 2)/81)
648
+ assert manualintegrate(x/sqrt(a+b*x)**3, x) == \
649
+ Piecewise((Mul(2, b**-2, a/sqrt(a + b*x) + sqrt(a + b*x)), Ne(b, 0)), (x**2/(2*a**(S(3)/2)), True))
650
+ assert_is_integral_of((sqrt(3*x+3)+1)/((2*x+2)**(1/S(3))+1),
651
+ 3*sqrt(6)*(2*x + 2)**(S(7)/6)/14 - 3*sqrt(6)*(2*x + 2)**(S(5)/6)/10 -
652
+ 3*sqrt(6)*(2*x + 2)**(S.One/6)/2 + 3*(2*x + 2)**(S(2)/3)/4 - 3*(2*x + 2)**(S.One/3)/2 +
653
+ sqrt(6)*sqrt(2*x + 2)/2 + 3*log((2*x + 2)**(S.One/3) + 1)/2 +
654
+ 3*sqrt(6)*atan((2*x + 2)**(S.One/6))/2)
655
+ assert_is_integral_of(sqrt(x+sqrt(x)),
656
+ 2*sqrt(sqrt(x) + x)*(sqrt(x)/12 + x/3 - S(1)/8) + log(2*sqrt(x) + 2*sqrt(sqrt(x) + x) + 1)/8)
657
+ assert_is_integral_of(sqrt(2*x+3+sqrt(4*x+5))**3,
658
+ sqrt(2*x + sqrt(4*x + 5) + 3) *
659
+ (9*x/10 + 11*(4*x + 5)**(S(3)/2)/40 + sqrt(4*x + 5)/40 + (4*x + 5)**2/10 + S(11)/10)/2)
660
+
661
+
662
+ def test_manualintegrate_sqrt_quadratic():
663
+ assert_is_integral_of(1/sqrt((x - I)**2-1), log(2*x + 2*sqrt(x**2 - 2*I*x - 2) - 2*I))
664
+ assert_is_integral_of(1/sqrt(3*x**2+4*x+5), sqrt(3)*asinh(3*sqrt(11)*(x + S(2)/3)/11)/3)
665
+ assert_is_integral_of(1/sqrt(-3*x**2+4*x+5), sqrt(3)*asin(3*sqrt(19)*(x - S(2)/3)/19)/3)
666
+ assert_is_integral_of(1/sqrt(3*x**2+4*x-5), sqrt(3)*log(6*x + 2*sqrt(3)*sqrt(3*x**2 + 4*x - 5) + 4)/3)
667
+ assert_is_integral_of(1/sqrt(4*x**2-4*x+1), (x - S.Half)*log(x - S.Half)/(2*sqrt((x - S.Half)**2)))
668
+ assert manualintegrate(1/sqrt(a+b*x+c*x**2), x) == \
669
+ Piecewise((log(b + 2*sqrt(c)*sqrt(a + b*x + c*x**2) + 2*c*x)/sqrt(c), Ne(c, 0) & Ne(a - b**2/(4*c), 0)),
670
+ ((b/(2*c) + x)*log(b/(2*c) + x)/sqrt(c*(b/(2*c) + x)**2), Ne(c, 0)),
671
+ (2*sqrt(a + b*x)/b, Ne(b, 0)), (x/sqrt(a), True))
672
+
673
+ assert_is_integral_of((7*x+6)/sqrt(3*x**2+4*x+5),
674
+ 7*sqrt(3*x**2 + 4*x + 5)/3 + 4*sqrt(3)*asinh(3*sqrt(11)*(x + S(2)/3)/11)/9)
675
+ assert_is_integral_of((7*x+6)/sqrt(-3*x**2+4*x+5),
676
+ -7*sqrt(-3*x**2 + 4*x + 5)/3 + 32*sqrt(3)*asin(3*sqrt(19)*(x - S(2)/3)/19)/9)
677
+ assert_is_integral_of((7*x+6)/sqrt(3*x**2+4*x-5),
678
+ 7*sqrt(3*x**2 + 4*x - 5)/3 + 4*sqrt(3)*log(6*x + 2*sqrt(3)*sqrt(3*x**2 + 4*x - 5) + 4)/9)
679
+ assert manualintegrate((d+e*x)/sqrt(a+b*x+c*x**2), x) == \
680
+ Piecewise(((-b*e/(2*c) + d) *
681
+ Piecewise((log(b + 2*sqrt(c)*sqrt(a + b*x + c*x**2) + 2*c*x)/sqrt(c), Ne(a - b**2/(4*c), 0)),
682
+ ((b/(2*c) + x)*log(b/(2*c) + x)/sqrt(c*(b/(2*c) + x)**2), True)) +
683
+ e*sqrt(a + b*x + c*x**2)/c, Ne(c, 0)),
684
+ ((2*d*sqrt(a + b*x) + 2*e*(-a*sqrt(a + b*x) + (a + b*x)**(S(3)/2)/3)/b)/b, Ne(b, 0)),
685
+ ((d*x + e*x**2/2)/sqrt(a), True))
686
+
687
+ assert manualintegrate((3*x**3-x**2+2*x-4)/sqrt(x**2-3*x+2), x) == \
688
+ sqrt(x**2 - 3*x + 2)*(x**2 + 13*x/4 + S(101)/8) + 135*log(2*x + 2*sqrt(x**2 - 3*x + 2) - 3)/16
689
+
690
+ assert_is_integral_of(sqrt(53225*x**2-66732*x+23013),
691
+ (x/2 - S(16683)/53225)*sqrt(53225*x**2 - 66732*x + 23013) +
692
+ 111576969*sqrt(2129)*asinh(53225*x/10563 - S(11122)/3521)/1133160250)
693
+ assert manualintegrate(sqrt(a+c*x**2), x) == \
694
+ Piecewise((a*Piecewise((log(2*sqrt(c)*sqrt(a + c*x**2) + 2*c*x)/sqrt(c), Ne(a, 0)),
695
+ (x*log(x)/sqrt(c*x**2), True))/2 + x*sqrt(a + c*x**2)/2, Ne(c, 0)),
696
+ (sqrt(a)*x, True))
697
+ assert manualintegrate(sqrt(a+b*x+c*x**2), x) == \
698
+ Piecewise(((a/2 - b**2/(8*c)) *
699
+ Piecewise((log(b + 2*sqrt(c)*sqrt(a + b*x + c*x**2) + 2*c*x)/sqrt(c), Ne(a - b**2/(4*c), 0)),
700
+ ((b/(2*c) + x)*log(b/(2*c) + x)/sqrt(c*(b/(2*c) + x)**2), True)) +
701
+ (b/(4*c) + x/2)*sqrt(a + b*x + c*x**2), Ne(c, 0)),
702
+ (2*(a + b*x)**(S(3)/2)/(3*b), Ne(b, 0)),
703
+ (sqrt(a)*x, True))
704
+
705
+ assert_is_integral_of(x*sqrt(x**2+2*x+4),
706
+ (x**2/3 + x/6 + S(5)/6)*sqrt(x**2 + 2*x + 4) - 3*asinh(sqrt(3)*(x + 1)/3)/2)
707
+
708
+
709
+ def test_mul_pow_derivative():
710
+ assert_is_integral_of(x*sec(x)*tan(x), x*sec(x) - log(tan(x) + sec(x)))
711
+ assert_is_integral_of(x*sec(x)**2, x*tan(x) + log(cos(x)))
712
+ assert_is_integral_of(x**3*Derivative(f(x), (x, 4)),
713
+ x**3*Derivative(f(x), (x, 3)) - 3*x**2*Derivative(f(x), (x, 2)) +
714
+ 6*x*Derivative(f(x), x) - 6*f(x))
.venv/lib/python3.13/site-packages/sympy/integrals/tests/test_meijerint.py ADDED
@@ -0,0 +1,774 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core.function import expand_func
2
+ from sympy.core.numbers import (I, Rational, oo, pi)
3
+ from sympy.core.singleton import S
4
+ from sympy.core.sorting import default_sort_key
5
+ from sympy.functions.elementary.complexes import Abs, arg, re, unpolarify
6
+ from sympy.functions.elementary.exponential import (exp, exp_polar, log)
7
+ from sympy.functions.elementary.hyperbolic import cosh, acosh, sinh
8
+ from sympy.functions.elementary.miscellaneous import sqrt
9
+ from sympy.functions.elementary.piecewise import Piecewise, piecewise_fold
10
+ from sympy.functions.elementary.trigonometric import (cos, sin, sinc, asin)
11
+ from sympy.functions.special.error_functions import (erf, erfc)
12
+ from sympy.functions.special.gamma_functions import (gamma, polygamma)
13
+ from sympy.functions.special.hyper import (hyper, meijerg)
14
+ from sympy.integrals.integrals import (Integral, integrate)
15
+ from sympy.simplify.hyperexpand import hyperexpand
16
+ from sympy.simplify.simplify import simplify
17
+ from sympy.integrals.meijerint import (_rewrite_single, _rewrite1,
18
+ meijerint_indefinite, _inflate_g, _create_lookup_table,
19
+ meijerint_definite, meijerint_inversion)
20
+ from sympy.testing.pytest import slow
21
+ from sympy.core.random import (verify_numerically,
22
+ random_complex_number as randcplx)
23
+ from sympy.abc import x, y, a, b, c, d, s, t, z
24
+
25
+
26
+ def test_rewrite_single():
27
+ def t(expr, c, m):
28
+ e = _rewrite_single(meijerg([a], [b], [c], [d], expr), x)
29
+ assert e is not None
30
+ assert isinstance(e[0][0][2], meijerg)
31
+ assert e[0][0][2].argument.as_coeff_mul(x) == (c, (m,))
32
+
33
+ def tn(expr):
34
+ assert _rewrite_single(meijerg([a], [b], [c], [d], expr), x) is None
35
+
36
+ t(x, 1, x)
37
+ t(x**2, 1, x**2)
38
+ t(x**2 + y*x**2, y + 1, x**2)
39
+ tn(x**2 + x)
40
+ tn(x**y)
41
+
42
+ def u(expr, x):
43
+ from sympy.core.add import Add
44
+ r = _rewrite_single(expr, x)
45
+ e = Add(*[res[0]*res[2] for res in r[0]]).replace(
46
+ exp_polar, exp) # XXX Hack?
47
+ assert verify_numerically(e, expr, x)
48
+
49
+ u(exp(-x)*sin(x), x)
50
+
51
+ # The following has stopped working because hyperexpand changed slightly.
52
+ # It is probably not worth fixing
53
+ #u(exp(-x)*sin(x)*cos(x), x)
54
+
55
+ # This one cannot be done numerically, since it comes out as a g-function
56
+ # of argument 4*pi
57
+ # NOTE This also tests a bug in inverse mellin transform (which used to
58
+ # turn exp(4*pi*I*t) into a factor of exp(4*pi*I)**t instead of
59
+ # exp_polar).
60
+ #u(exp(x)*sin(x), x)
61
+ assert _rewrite_single(exp(x)*sin(x), x) == \
62
+ ([(-sqrt(2)/(2*sqrt(pi)), 0,
63
+ meijerg(((Rational(-1, 2), 0, Rational(1, 4), S.Half, Rational(3, 4)), (1,)),
64
+ ((), (Rational(-1, 2), 0)), 64*exp_polar(-4*I*pi)/x**4))], True)
65
+
66
+
67
+ def test_rewrite1():
68
+ assert _rewrite1(x**3*meijerg([a], [b], [c], [d], x**2 + y*x**2)*5, x) == \
69
+ (5, x**3, [(1, 0, meijerg([a], [b], [c], [d], x**2*(y + 1)))], True)
70
+
71
+
72
+ def test_meijerint_indefinite_numerically():
73
+ def t(fac, arg):
74
+ g = meijerg([a], [b], [c], [d], arg)*fac
75
+ subs = {a: randcplx()/10, b: randcplx()/10 + I,
76
+ c: randcplx(), d: randcplx()}
77
+ integral = meijerint_indefinite(g, x)
78
+ assert integral is not None
79
+ assert verify_numerically(g.subs(subs), integral.diff(x).subs(subs), x)
80
+ t(1, x)
81
+ t(2, x)
82
+ t(1, 2*x)
83
+ t(1, x**2)
84
+ t(5, x**S('3/2'))
85
+ t(x**3, x)
86
+ t(3*x**S('3/2'), 4*x**S('7/3'))
87
+
88
+
89
+ def test_meijerint_definite():
90
+ v, b = meijerint_definite(x, x, 0, 0)
91
+ assert v.is_zero and b is True
92
+ v, b = meijerint_definite(x, x, oo, oo)
93
+ assert v.is_zero and b is True
94
+
95
+
96
+ def test_inflate():
97
+ subs = {a: randcplx()/10, b: randcplx()/10 + I, c: randcplx(),
98
+ d: randcplx(), y: randcplx()/10}
99
+
100
+ def t(a, b, arg, n):
101
+ from sympy.core.mul import Mul
102
+ m1 = meijerg(a, b, arg)
103
+ m2 = Mul(*_inflate_g(m1, n))
104
+ # NOTE: (the random number)**9 must still be on the principal sheet.
105
+ # Thus make b&d small to create random numbers of small imaginary part.
106
+ return verify_numerically(m1.subs(subs), m2.subs(subs), x, b=0.1, d=-0.1)
107
+ assert t([[a], [b]], [[c], [d]], x, 3)
108
+ assert t([[a, y], [b]], [[c], [d]], x, 3)
109
+ assert t([[a], [b]], [[c, y], [d]], 2*x**3, 3)
110
+
111
+
112
+ def test_recursive():
113
+ from sympy.core.symbol import symbols
114
+ a, b, c = symbols('a b c', positive=True)
115
+ r = exp(-(x - a)**2)*exp(-(x - b)**2)
116
+ e = integrate(r, (x, 0, oo), meijerg=True)
117
+ assert simplify(e.expand()) == (
118
+ sqrt(2)*sqrt(pi)*(
119
+ (erf(sqrt(2)*(a + b)/2) + 1)*exp(-a**2/2 + a*b - b**2/2))/4)
120
+ e = integrate(exp(-(x - a)**2)*exp(-(x - b)**2)*exp(c*x), (x, 0, oo), meijerg=True)
121
+ assert simplify(e) == (
122
+ sqrt(2)*sqrt(pi)*(erf(sqrt(2)*(2*a + 2*b + c)/4) + 1)*exp(-a**2 - b**2
123
+ + (2*a + 2*b + c)**2/8)/4)
124
+ assert simplify(integrate(exp(-(x - a - b - c)**2), (x, 0, oo), meijerg=True)) == \
125
+ sqrt(pi)/2*(1 + erf(a + b + c))
126
+ assert simplify(integrate(exp(-(x + a + b + c)**2), (x, 0, oo), meijerg=True)) == \
127
+ sqrt(pi)/2*(1 - erf(a + b + c))
128
+
129
+
130
+ @slow
131
+ def test_meijerint():
132
+ from sympy.core.function import expand
133
+ from sympy.core.symbol import symbols
134
+ s, t, mu = symbols('s t mu', real=True)
135
+ assert integrate(meijerg([], [], [0], [], s*t)
136
+ *meijerg([], [], [mu/2], [-mu/2], t**2/4),
137
+ (t, 0, oo)).is_Piecewise
138
+ s = symbols('s', positive=True)
139
+ assert integrate(x**s*meijerg([[], []], [[0], []], x), (x, 0, oo)) == \
140
+ gamma(s + 1)
141
+ assert integrate(x**s*meijerg([[], []], [[0], []], x), (x, 0, oo),
142
+ meijerg=True) == gamma(s + 1)
143
+ assert isinstance(integrate(x**s*meijerg([[], []], [[0], []], x),
144
+ (x, 0, oo), meijerg=False),
145
+ Integral)
146
+
147
+ assert meijerint_indefinite(exp(x), x) == exp(x)
148
+
149
+ # TODO what simplifications should be done automatically?
150
+ # This tests "extra case" for antecedents_1.
151
+ a, b = symbols('a b', positive=True)
152
+ assert simplify(meijerint_definite(x**a, x, 0, b)[0]) == \
153
+ b**(a + 1)/(a + 1)
154
+
155
+ # This tests various conditions and expansions:
156
+ assert meijerint_definite((x + 1)**3*exp(-x), x, 0, oo) == (16, True)
157
+
158
+ # Again, how about simplifications?
159
+ sigma, mu = symbols('sigma mu', positive=True)
160
+ i, c = meijerint_definite(exp(-((x - mu)/(2*sigma))**2), x, 0, oo)
161
+ assert simplify(i) == sqrt(pi)*sigma*(2 - erfc(mu/(2*sigma)))
162
+ assert c == True
163
+
164
+ i, _ = meijerint_definite(exp(-mu*x)*exp(sigma*x), x, 0, oo)
165
+ # TODO it would be nice to test the condition
166
+ assert simplify(i) == 1/(mu - sigma)
167
+
168
+ # Test substitutions to change limits
169
+ assert meijerint_definite(exp(x), x, -oo, 2) == (exp(2), True)
170
+ # Note: causes a NaN in _check_antecedents
171
+ assert expand(meijerint_definite(exp(x), x, 0, I)[0]) == exp(I) - 1
172
+ assert expand(meijerint_definite(exp(-x), x, 0, x)[0]) == \
173
+ 1 - exp(-exp(I*arg(x))*abs(x))
174
+
175
+ # Test -oo to oo
176
+ assert meijerint_definite(exp(-x**2), x, -oo, oo) == (sqrt(pi), True)
177
+ assert meijerint_definite(exp(-abs(x)), x, -oo, oo) == (2, True)
178
+ assert meijerint_definite(exp(-(2*x - 3)**2), x, -oo, oo) == \
179
+ (sqrt(pi)/2, True)
180
+ assert meijerint_definite(exp(-abs(2*x - 3)), x, -oo, oo) == (1, True)
181
+ assert meijerint_definite(exp(-((x - mu)/sigma)**2/2)/sqrt(2*pi*sigma**2),
182
+ x, -oo, oo) == (1, True)
183
+ assert meijerint_definite(sinc(x)**2, x, -oo, oo) == (pi, True)
184
+
185
+ # Test one of the extra conditions for 2 g-functinos
186
+ assert meijerint_definite(exp(-x)*sin(x), x, 0, oo) == (S.Half, True)
187
+
188
+ # Test a bug
189
+ def res(n):
190
+ return (1/(1 + x**2)).diff(x, n).subs(x, 1)*(-1)**n
191
+ for n in range(6):
192
+ assert integrate(exp(-x)*sin(x)*x**n, (x, 0, oo), meijerg=True) == \
193
+ res(n)
194
+
195
+ # This used to test trigexpand... now it is done by linear substitution
196
+ assert simplify(integrate(exp(-x)*sin(x + a), (x, 0, oo), meijerg=True)
197
+ ) == sqrt(2)*sin(a + pi/4)/2
198
+
199
+ # Test the condition 14 from prudnikov.
200
+ # (This is besselj*besselj in disguise, to stop the product from being
201
+ # recognised in the tables.)
202
+ a, b, s = symbols('a b s')
203
+ assert meijerint_definite(meijerg([], [], [a/2], [-a/2], x/4)
204
+ *meijerg([], [], [b/2], [-b/2], x/4)*x**(s - 1), x, 0, oo
205
+ ) == (
206
+ (4*2**(2*s - 2)*gamma(-2*s + 1)*gamma(a/2 + b/2 + s)
207
+ /(gamma(-a/2 + b/2 - s + 1)*gamma(a/2 - b/2 - s + 1)
208
+ *gamma(a/2 + b/2 - s + 1)),
209
+ (re(s) < 1) & (re(s) < S(1)/2) & (re(a)/2 + re(b)/2 + re(s) > 0)))
210
+
211
+ # test a bug
212
+ assert integrate(sin(x**a)*sin(x**b), (x, 0, oo), meijerg=True) == \
213
+ Integral(sin(x**a)*sin(x**b), (x, 0, oo))
214
+
215
+ # test better hyperexpand
216
+ assert integrate(exp(-x**2)*log(x), (x, 0, oo), meijerg=True) == \
217
+ (sqrt(pi)*polygamma(0, S.Half)/4).expand()
218
+
219
+ # Test hyperexpand bug.
220
+ from sympy.functions.special.gamma_functions import lowergamma
221
+ n = symbols('n', integer=True)
222
+ assert simplify(integrate(exp(-x)*x**n, x, meijerg=True)) == \
223
+ lowergamma(n + 1, x)
224
+
225
+ # Test a bug with argument 1/x
226
+ alpha = symbols('alpha', positive=True)
227
+ assert meijerint_definite((2 - x)**alpha*sin(alpha/x), x, 0, 2) == \
228
+ (sqrt(pi)*alpha*gamma(alpha + 1)*meijerg(((), (alpha/2 + S.Half,
229
+ alpha/2 + 1)), ((0, 0, S.Half), (Rational(-1, 2),)), alpha**2/16)/4, True)
230
+
231
+ # test a bug related to 3016
232
+ a, s = symbols('a s', positive=True)
233
+ assert simplify(integrate(x**s*exp(-a*x**2), (x, -oo, oo))) == \
234
+ a**(-s/2 - S.Half)*((-1)**s + 1)*gamma(s/2 + S.Half)/2
235
+
236
+
237
+ def test_bessel():
238
+ from sympy.functions.special.bessel import (besseli, besselj)
239
+ assert simplify(integrate(besselj(a, z)*besselj(b, z)/z, (z, 0, oo),
240
+ meijerg=True, conds='none')) == \
241
+ 2*sin(pi*(a/2 - b/2))/(pi*(a - b)*(a + b))
242
+ assert simplify(integrate(besselj(a, z)*besselj(a, z)/z, (z, 0, oo),
243
+ meijerg=True, conds='none')) == 1/(2*a)
244
+
245
+ # TODO more orthogonality integrals
246
+
247
+ assert simplify(integrate(sin(z*x)*(x**2 - 1)**(-(y + S.Half)),
248
+ (x, 1, oo), meijerg=True, conds='none')
249
+ *2/((z/2)**y*sqrt(pi)*gamma(S.Half - y))) == \
250
+ besselj(y, z)
251
+
252
+ # Werner Rosenheinrich
253
+ # SOME INDEFINITE INTEGRALS OF BESSEL FUNCTIONS
254
+
255
+ assert integrate(x*besselj(0, x), x, meijerg=True) == x*besselj(1, x)
256
+ assert integrate(x*besseli(0, x), x, meijerg=True) == x*besseli(1, x)
257
+ # TODO can do higher powers, but come out as high order ... should they be
258
+ # reduced to order 0, 1?
259
+ assert integrate(besselj(1, x), x, meijerg=True) == -besselj(0, x)
260
+ assert integrate(besselj(1, x)**2/x, x, meijerg=True) == \
261
+ -(besselj(0, x)**2 + besselj(1, x)**2)/2
262
+ # TODO more besseli when tables are extended or recursive mellin works
263
+ assert integrate(besselj(0, x)**2/x**2, x, meijerg=True) == \
264
+ -2*x*besselj(0, x)**2 - 2*x*besselj(1, x)**2 \
265
+ + 2*besselj(0, x)*besselj(1, x) - besselj(0, x)**2/x
266
+ assert integrate(besselj(0, x)*besselj(1, x), x, meijerg=True) == \
267
+ -besselj(0, x)**2/2
268
+ assert integrate(x**2*besselj(0, x)*besselj(1, x), x, meijerg=True) == \
269
+ x**2*besselj(1, x)**2/2
270
+ assert integrate(besselj(0, x)*besselj(1, x)/x, x, meijerg=True) == \
271
+ (x*besselj(0, x)**2 + x*besselj(1, x)**2 -
272
+ besselj(0, x)*besselj(1, x))
273
+ # TODO how does besselj(0, a*x)*besselj(0, b*x) work?
274
+ # TODO how does besselj(0, x)**2*besselj(1, x)**2 work?
275
+ # TODO sin(x)*besselj(0, x) etc come out a mess
276
+ # TODO can x*log(x)*besselj(0, x) be done?
277
+ # TODO how does besselj(1, x)*besselj(0, x+a) work?
278
+ # TODO more indefinite integrals when struve functions etc are implemented
279
+
280
+ # test a substitution
281
+ assert integrate(besselj(1, x**2)*x, x, meijerg=True) == \
282
+ -besselj(0, x**2)/2
283
+
284
+
285
+ def test_inversion():
286
+ from sympy.functions.special.bessel import besselj
287
+ from sympy.functions.special.delta_functions import Heaviside
288
+
289
+ def inv(f):
290
+ return piecewise_fold(meijerint_inversion(f, s, t))
291
+ assert inv(1/(s**2 + 1)) == sin(t)*Heaviside(t)
292
+ assert inv(s/(s**2 + 1)) == cos(t)*Heaviside(t)
293
+ assert inv(exp(-s)/s) == Heaviside(t - 1)
294
+ assert inv(1/sqrt(1 + s**2)) == besselj(0, t)*Heaviside(t)
295
+
296
+ # Test some antcedents checking.
297
+ assert meijerint_inversion(sqrt(s)/sqrt(1 + s**2), s, t) is None
298
+ assert inv(exp(s**2)) is None
299
+ assert meijerint_inversion(exp(-s**2), s, t) is None
300
+
301
+
302
+ def test_inversion_conditional_output():
303
+ from sympy.core.symbol import Symbol
304
+ from sympy.integrals.transforms import InverseLaplaceTransform
305
+
306
+ a = Symbol('a', positive=True)
307
+ F = sqrt(pi/a)*exp(-2*sqrt(a)*sqrt(s))
308
+ f = meijerint_inversion(F, s, t)
309
+ assert not f.is_Piecewise
310
+
311
+ b = Symbol('b', real=True)
312
+ F = F.subs(a, b)
313
+ f2 = meijerint_inversion(F, s, t)
314
+ assert f2.is_Piecewise
315
+ # first piece is same as f
316
+ assert f2.args[0][0] == f.subs(a, b)
317
+ # last piece is an unevaluated transform
318
+ assert f2.args[-1][1]
319
+ ILT = InverseLaplaceTransform(F, s, t, None)
320
+ assert f2.args[-1][0] == ILT or f2.args[-1][0] == ILT.as_integral
321
+
322
+
323
+ def test_inversion_exp_real_nonreal_shift():
324
+ from sympy.core.symbol import Symbol
325
+ from sympy.functions.special.delta_functions import DiracDelta
326
+ r = Symbol('r', real=True)
327
+ c = Symbol('c', extended_real=False)
328
+ a = 1 + 2*I
329
+ z = Symbol('z')
330
+ assert not meijerint_inversion(exp(r*s), s, t).is_Piecewise
331
+ assert meijerint_inversion(exp(a*s), s, t) is None
332
+ assert meijerint_inversion(exp(c*s), s, t) is None
333
+ f = meijerint_inversion(exp(z*s), s, t)
334
+ assert f.is_Piecewise
335
+ assert isinstance(f.args[0][0], DiracDelta)
336
+
337
+
338
+ @slow
339
+ def test_lookup_table():
340
+ from sympy.core.random import uniform, randrange
341
+ from sympy.core.add import Add
342
+ from sympy.integrals.meijerint import z as z_dummy
343
+ table = {}
344
+ _create_lookup_table(table)
345
+ for l in table.values():
346
+ for formula, terms, cond, hint in sorted(l, key=default_sort_key):
347
+ subs = {}
348
+ for ai in list(formula.free_symbols) + [z_dummy]:
349
+ if hasattr(ai, 'properties') and ai.properties:
350
+ # these Wilds match positive integers
351
+ subs[ai] = randrange(1, 10)
352
+ else:
353
+ subs[ai] = uniform(1.5, 2.0)
354
+ if not isinstance(terms, list):
355
+ terms = terms(subs)
356
+
357
+ # First test that hyperexpand can do this.
358
+ expanded = [hyperexpand(g) for (_, g) in terms]
359
+ assert all(x.is_Piecewise or not x.has(meijerg) for x in expanded)
360
+
361
+ # Now test that the meijer g-function is indeed as advertised.
362
+ expanded = Add(*[f*x for (f, x) in terms])
363
+ a, b = formula.n(subs=subs), expanded.n(subs=subs)
364
+ r = min(abs(a), abs(b))
365
+ if r < 1:
366
+ assert abs(a - b).n() <= 1e-10
367
+ else:
368
+ assert (abs(a - b)/r).n() <= 1e-10
369
+
370
+
371
+ def test_branch_bug():
372
+ from sympy.functions.special.gamma_functions import lowergamma
373
+ from sympy.simplify.powsimp import powdenest
374
+ # TODO gammasimp cannot prove that the factor is unity
375
+ assert powdenest(integrate(erf(x**3), x, meijerg=True).diff(x),
376
+ polar=True) == 2*erf(x**3)*gamma(Rational(2, 3))/3/gamma(Rational(5, 3))
377
+ assert integrate(erf(x**3), x, meijerg=True) == \
378
+ 2*x*erf(x**3)*gamma(Rational(2, 3))/(3*gamma(Rational(5, 3))) \
379
+ - 2*gamma(Rational(2, 3))*lowergamma(Rational(2, 3), x**6)/(3*sqrt(pi)*gamma(Rational(5, 3)))
380
+
381
+
382
+ def test_linear_subs():
383
+ from sympy.functions.special.bessel import besselj
384
+ assert integrate(sin(x - 1), x, meijerg=True) == -cos(1 - x)
385
+ assert integrate(besselj(1, x - 1), x, meijerg=True) == -besselj(0, 1 - x)
386
+
387
+
388
+ @slow
389
+ def test_probability():
390
+ # various integrals from probability theory
391
+ from sympy.core.function import expand_mul
392
+ from sympy.core.symbol import (Symbol, symbols)
393
+ from sympy.simplify.gammasimp import gammasimp
394
+ from sympy.simplify.powsimp import powsimp
395
+ mu1, mu2 = symbols('mu1 mu2', nonzero=True)
396
+ sigma1, sigma2 = symbols('sigma1 sigma2', positive=True)
397
+ rate = Symbol('lambda', positive=True)
398
+
399
+ def normal(x, mu, sigma):
400
+ return 1/sqrt(2*pi*sigma**2)*exp(-(x - mu)**2/2/sigma**2)
401
+
402
+ def exponential(x, rate):
403
+ return rate*exp(-rate*x)
404
+
405
+ assert integrate(normal(x, mu1, sigma1), (x, -oo, oo), meijerg=True) == 1
406
+ assert integrate(x*normal(x, mu1, sigma1), (x, -oo, oo), meijerg=True) == \
407
+ mu1
408
+ assert integrate(x**2*normal(x, mu1, sigma1), (x, -oo, oo), meijerg=True) \
409
+ == mu1**2 + sigma1**2
410
+ assert integrate(x**3*normal(x, mu1, sigma1), (x, -oo, oo), meijerg=True) \
411
+ == mu1**3 + 3*mu1*sigma1**2
412
+ assert integrate(normal(x, mu1, sigma1)*normal(y, mu2, sigma2),
413
+ (x, -oo, oo), (y, -oo, oo), meijerg=True) == 1
414
+ assert integrate(x*normal(x, mu1, sigma1)*normal(y, mu2, sigma2),
415
+ (x, -oo, oo), (y, -oo, oo), meijerg=True) == mu1
416
+ assert integrate(y*normal(x, mu1, sigma1)*normal(y, mu2, sigma2),
417
+ (x, -oo, oo), (y, -oo, oo), meijerg=True) == mu2
418
+ assert integrate(x*y*normal(x, mu1, sigma1)*normal(y, mu2, sigma2),
419
+ (x, -oo, oo), (y, -oo, oo), meijerg=True) == mu1*mu2
420
+ assert integrate((x + y + 1)*normal(x, mu1, sigma1)*normal(y, mu2, sigma2),
421
+ (x, -oo, oo), (y, -oo, oo), meijerg=True) == 1 + mu1 + mu2
422
+ assert integrate((x + y - 1)*normal(x, mu1, sigma1)*normal(y, mu2, sigma2),
423
+ (x, -oo, oo), (y, -oo, oo), meijerg=True) == \
424
+ -1 + mu1 + mu2
425
+
426
+ i = integrate(x**2*normal(x, mu1, sigma1)*normal(y, mu2, sigma2),
427
+ (x, -oo, oo), (y, -oo, oo), meijerg=True)
428
+ assert not i.has(Abs)
429
+ assert simplify(i) == mu1**2 + sigma1**2
430
+ assert integrate(y**2*normal(x, mu1, sigma1)*normal(y, mu2, sigma2),
431
+ (x, -oo, oo), (y, -oo, oo), meijerg=True) == \
432
+ sigma2**2 + mu2**2
433
+
434
+ assert integrate(exponential(x, rate), (x, 0, oo), meijerg=True) == 1
435
+ assert integrate(x*exponential(x, rate), (x, 0, oo), meijerg=True) == \
436
+ 1/rate
437
+ assert integrate(x**2*exponential(x, rate), (x, 0, oo), meijerg=True) == \
438
+ 2/rate**2
439
+
440
+ def E(expr):
441
+ res1 = integrate(expr*exponential(x, rate)*normal(y, mu1, sigma1),
442
+ (x, 0, oo), (y, -oo, oo), meijerg=True)
443
+ res2 = integrate(expr*exponential(x, rate)*normal(y, mu1, sigma1),
444
+ (y, -oo, oo), (x, 0, oo), meijerg=True)
445
+ assert expand_mul(res1) == expand_mul(res2)
446
+ return res1
447
+
448
+ assert E(1) == 1
449
+ assert E(x*y) == mu1/rate
450
+ assert E(x*y**2) == mu1**2/rate + sigma1**2/rate
451
+ ans = sigma1**2 + 1/rate**2
452
+ assert simplify(E((x + y + 1)**2) - E(x + y + 1)**2) == ans
453
+ assert simplify(E((x + y - 1)**2) - E(x + y - 1)**2) == ans
454
+ assert simplify(E((x + y)**2) - E(x + y)**2) == ans
455
+
456
+ # Beta' distribution
457
+ alpha, beta = symbols('alpha beta', positive=True)
458
+ betadist = x**(alpha - 1)*(1 + x)**(-alpha - beta)*gamma(alpha + beta) \
459
+ /gamma(alpha)/gamma(beta)
460
+ assert integrate(betadist, (x, 0, oo), meijerg=True) == 1
461
+ i = integrate(x*betadist, (x, 0, oo), meijerg=True, conds='separate')
462
+ assert (gammasimp(i[0]), i[1]) == (alpha/(beta - 1), 1 < beta)
463
+ j = integrate(x**2*betadist, (x, 0, oo), meijerg=True, conds='separate')
464
+ assert j[1] == (beta > 2)
465
+ assert gammasimp(j[0] - i[0]**2) == (alpha + beta - 1)*alpha \
466
+ /(beta - 2)/(beta - 1)**2
467
+
468
+ # Beta distribution
469
+ # NOTE: this is evaluated using antiderivatives. It also tests that
470
+ # meijerint_indefinite returns the simplest possible answer.
471
+ a, b = symbols('a b', positive=True)
472
+ betadist = x**(a - 1)*(-x + 1)**(b - 1)*gamma(a + b)/(gamma(a)*gamma(b))
473
+ assert simplify(integrate(betadist, (x, 0, 1), meijerg=True)) == 1
474
+ assert simplify(integrate(x*betadist, (x, 0, 1), meijerg=True)) == \
475
+ a/(a + b)
476
+ assert simplify(integrate(x**2*betadist, (x, 0, 1), meijerg=True)) == \
477
+ a*(a + 1)/(a + b)/(a + b + 1)
478
+ assert simplify(integrate(x**y*betadist, (x, 0, 1), meijerg=True)) == \
479
+ gamma(a + b)*gamma(a + y)/gamma(a)/gamma(a + b + y)
480
+
481
+ # Chi distribution
482
+ k = Symbol('k', integer=True, positive=True)
483
+ chi = 2**(1 - k/2)*x**(k - 1)*exp(-x**2/2)/gamma(k/2)
484
+ assert powsimp(integrate(chi, (x, 0, oo), meijerg=True)) == 1
485
+ assert simplify(integrate(x*chi, (x, 0, oo), meijerg=True)) == \
486
+ sqrt(2)*gamma((k + 1)/2)/gamma(k/2)
487
+ assert simplify(integrate(x**2*chi, (x, 0, oo), meijerg=True)) == k
488
+
489
+ # Chi^2 distribution
490
+ chisquared = 2**(-k/2)/gamma(k/2)*x**(k/2 - 1)*exp(-x/2)
491
+ assert powsimp(integrate(chisquared, (x, 0, oo), meijerg=True)) == 1
492
+ assert simplify(integrate(x*chisquared, (x, 0, oo), meijerg=True)) == k
493
+ assert simplify(integrate(x**2*chisquared, (x, 0, oo), meijerg=True)) == \
494
+ k*(k + 2)
495
+ assert gammasimp(integrate(((x - k)/sqrt(2*k))**3*chisquared, (x, 0, oo),
496
+ meijerg=True)) == 2*sqrt(2)/sqrt(k)
497
+
498
+ # Dagum distribution
499
+ a, b, p = symbols('a b p', positive=True)
500
+ # XXX (x/b)**a does not work
501
+ dagum = a*p/x*(x/b)**(a*p)/(1 + x**a/b**a)**(p + 1)
502
+ assert simplify(integrate(dagum, (x, 0, oo), meijerg=True)) == 1
503
+ # XXX conditions are a mess
504
+ arg = x*dagum
505
+ assert simplify(integrate(arg, (x, 0, oo), meijerg=True, conds='none')
506
+ ) == a*b*gamma(1 - 1/a)*gamma(p + 1 + 1/a)/(
507
+ (a*p + 1)*gamma(p))
508
+ assert simplify(integrate(x*arg, (x, 0, oo), meijerg=True, conds='none')
509
+ ) == a*b**2*gamma(1 - 2/a)*gamma(p + 1 + 2/a)/(
510
+ (a*p + 2)*gamma(p))
511
+
512
+ # F-distribution
513
+ d1, d2 = symbols('d1 d2', positive=True)
514
+ f = sqrt(((d1*x)**d1 * d2**d2)/(d1*x + d2)**(d1 + d2))/x \
515
+ /gamma(d1/2)/gamma(d2/2)*gamma((d1 + d2)/2)
516
+ assert simplify(integrate(f, (x, 0, oo), meijerg=True)) == 1
517
+ # TODO conditions are a mess
518
+ assert simplify(integrate(x*f, (x, 0, oo), meijerg=True, conds='none')
519
+ ) == d2/(d2 - 2)
520
+ assert simplify(integrate(x**2*f, (x, 0, oo), meijerg=True, conds='none')
521
+ ) == d2**2*(d1 + 2)/d1/(d2 - 4)/(d2 - 2)
522
+
523
+ # TODO gamma, rayleigh
524
+
525
+ # inverse gaussian
526
+ lamda, mu = symbols('lamda mu', positive=True)
527
+ dist = sqrt(lamda/2/pi)*x**(Rational(-3, 2))*exp(-lamda*(x - mu)**2/x/2/mu**2)
528
+ mysimp = lambda expr: simplify(expr.rewrite(exp))
529
+ assert mysimp(integrate(dist, (x, 0, oo))) == 1
530
+ assert mysimp(integrate(x*dist, (x, 0, oo))) == mu
531
+ assert mysimp(integrate((x - mu)**2*dist, (x, 0, oo))) == mu**3/lamda
532
+ assert mysimp(integrate((x - mu)**3*dist, (x, 0, oo))) == 3*mu**5/lamda**2
533
+
534
+ # Levi
535
+ c = Symbol('c', positive=True)
536
+ assert integrate(sqrt(c/2/pi)*exp(-c/2/(x - mu))/(x - mu)**S('3/2'),
537
+ (x, mu, oo)) == 1
538
+ # higher moments oo
539
+
540
+ # log-logistic
541
+ alpha, beta = symbols('alpha beta', positive=True)
542
+ distn = (beta/alpha)*x**(beta - 1)/alpha**(beta - 1)/ \
543
+ (1 + x**beta/alpha**beta)**2
544
+ # FIXME: If alpha, beta are not declared as finite the line below hangs
545
+ # after the changes in:
546
+ # https://github.com/sympy/sympy/pull/16603
547
+ assert simplify(integrate(distn, (x, 0, oo))) == 1
548
+ # NOTE the conditions are a mess, but correctly state beta > 1
549
+ assert simplify(integrate(x*distn, (x, 0, oo), conds='none')) == \
550
+ pi*alpha/beta/sin(pi/beta)
551
+ # (similar comment for conditions applies)
552
+ assert simplify(integrate(x**y*distn, (x, 0, oo), conds='none')) == \
553
+ pi*alpha**y*y/beta/sin(pi*y/beta)
554
+
555
+ # weibull
556
+ k = Symbol('k', positive=True)
557
+ n = Symbol('n', positive=True)
558
+ distn = k/lamda*(x/lamda)**(k - 1)*exp(-(x/lamda)**k)
559
+ assert simplify(integrate(distn, (x, 0, oo))) == 1
560
+ assert simplify(integrate(x**n*distn, (x, 0, oo))) == \
561
+ lamda**n*gamma(1 + n/k)
562
+
563
+ # rice distribution
564
+ from sympy.functions.special.bessel import besseli
565
+ nu, sigma = symbols('nu sigma', positive=True)
566
+ rice = x/sigma**2*exp(-(x**2 + nu**2)/2/sigma**2)*besseli(0, x*nu/sigma**2)
567
+ assert integrate(rice, (x, 0, oo), meijerg=True) == 1
568
+ # can someone verify higher moments?
569
+
570
+ # Laplace distribution
571
+ mu = Symbol('mu', real=True)
572
+ b = Symbol('b', positive=True)
573
+ laplace = exp(-abs(x - mu)/b)/2/b
574
+ assert integrate(laplace, (x, -oo, oo), meijerg=True) == 1
575
+ assert integrate(x*laplace, (x, -oo, oo), meijerg=True) == mu
576
+ assert integrate(x**2*laplace, (x, -oo, oo), meijerg=True) == \
577
+ 2*b**2 + mu**2
578
+
579
+ # TODO are there other distributions supported on (-oo, oo) that we can do?
580
+
581
+ # misc tests
582
+ k = Symbol('k', positive=True)
583
+ assert gammasimp(expand_mul(integrate(log(x)*x**(k - 1)*exp(-x)/gamma(k),
584
+ (x, 0, oo)))) == polygamma(0, k)
585
+
586
+
587
+ @slow
588
+ def test_expint():
589
+ """ Test various exponential integrals. """
590
+ from sympy.core.symbol import Symbol
591
+ from sympy.functions.elementary.hyperbolic import sinh
592
+ from sympy.functions.special.error_functions import (Chi, Ci, Ei, Shi, Si, expint)
593
+ assert simplify(unpolarify(integrate(exp(-z*x)/x**y, (x, 1, oo),
594
+ meijerg=True, conds='none'
595
+ ).rewrite(expint).expand(func=True))) == expint(y, z)
596
+
597
+ assert integrate(exp(-z*x)/x, (x, 1, oo), meijerg=True,
598
+ conds='none').rewrite(expint).expand() == \
599
+ expint(1, z)
600
+ assert integrate(exp(-z*x)/x**2, (x, 1, oo), meijerg=True,
601
+ conds='none').rewrite(expint).expand() == \
602
+ expint(2, z).rewrite(Ei).rewrite(expint)
603
+ assert integrate(exp(-z*x)/x**3, (x, 1, oo), meijerg=True,
604
+ conds='none').rewrite(expint).expand() == \
605
+ expint(3, z).rewrite(Ei).rewrite(expint).expand()
606
+
607
+ t = Symbol('t', positive=True)
608
+ assert integrate(-cos(x)/x, (x, t, oo), meijerg=True).expand() == Ci(t)
609
+ assert integrate(-sin(x)/x, (x, t, oo), meijerg=True).expand() == \
610
+ Si(t) - pi/2
611
+ assert integrate(sin(x)/x, (x, 0, z), meijerg=True) == Si(z)
612
+ assert integrate(sinh(x)/x, (x, 0, z), meijerg=True) == Shi(z)
613
+ assert integrate(exp(-x)/x, x, meijerg=True).expand().rewrite(expint) == \
614
+ I*pi - expint(1, x)
615
+ assert integrate(exp(-x)/x**2, x, meijerg=True).rewrite(expint).expand() \
616
+ == expint(1, x) - exp(-x)/x - I*pi
617
+
618
+ u = Symbol('u', polar=True)
619
+ assert integrate(cos(u)/u, u, meijerg=True).expand().as_independent(u)[1] \
620
+ == Ci(u)
621
+ assert integrate(cosh(u)/u, u, meijerg=True).expand().as_independent(u)[1] \
622
+ == Chi(u)
623
+
624
+ assert integrate(expint(1, x), x, meijerg=True
625
+ ).rewrite(expint).expand() == x*expint(1, x) - exp(-x)
626
+ assert integrate(expint(2, x), x, meijerg=True
627
+ ).rewrite(expint).expand() == \
628
+ -x**2*expint(1, x)/2 + x*exp(-x)/2 - exp(-x)/2
629
+ assert simplify(unpolarify(integrate(expint(y, x), x,
630
+ meijerg=True).rewrite(expint).expand(func=True))) == \
631
+ -expint(y + 1, x)
632
+
633
+ assert integrate(Si(x), x, meijerg=True) == x*Si(x) + cos(x)
634
+ assert integrate(Ci(u), u, meijerg=True).expand() == u*Ci(u) - sin(u)
635
+ assert integrate(Shi(x), x, meijerg=True) == x*Shi(x) - cosh(x)
636
+ assert integrate(Chi(u), u, meijerg=True).expand() == u*Chi(u) - sinh(u)
637
+
638
+ assert integrate(Si(x)*exp(-x), (x, 0, oo), meijerg=True) == pi/4
639
+ assert integrate(expint(1, x)*sin(x), (x, 0, oo), meijerg=True) == log(2)/2
640
+
641
+
642
+ def test_messy():
643
+ from sympy.functions.elementary.hyperbolic import (acosh, acoth)
644
+ from sympy.functions.elementary.trigonometric import (asin, atan)
645
+ from sympy.functions.special.bessel import besselj
646
+ from sympy.functions.special.error_functions import (Chi, E1, Shi, Si)
647
+ from sympy.integrals.transforms import (fourier_transform, laplace_transform)
648
+ assert (laplace_transform(Si(x), x, s, simplify=True) ==
649
+ ((-atan(s) + pi/2)/s, 0, True))
650
+
651
+ assert laplace_transform(Shi(x), x, s, simplify=True) == (
652
+ acoth(s)/s, -oo, s**2 > 1)
653
+
654
+ # where should the logs be simplified?
655
+ assert laplace_transform(Chi(x), x, s, simplify=True) == (
656
+ (log(s**(-2)) - log(1 - 1/s**2))/(2*s), -oo, s**2 > 1)
657
+
658
+ # TODO maybe simplify the inequalities? when the simplification
659
+ # allows for generators instead of symbols this will work
660
+ assert laplace_transform(besselj(a, x), x, s)[1:] == \
661
+ (0, (re(a) > -2) & (re(a) > -1))
662
+
663
+ # NOTE s < 0 can be done, but argument reduction is not good enough yet
664
+ ans = fourier_transform(besselj(1, x)/x, x, s, noconds=False)
665
+ assert (ans[0].factor(deep=True).expand(), ans[1]) == \
666
+ (Piecewise((0, (s > 1/(2*pi)) | (s < -1/(2*pi))),
667
+ (2*sqrt(-4*pi**2*s**2 + 1), True)), s > 0)
668
+ # TODO FT(besselj(0,x)) - conditions are messy (but for acceptable reasons)
669
+ # - folding could be better
670
+
671
+ assert integrate(E1(x)*besselj(0, x), (x, 0, oo), meijerg=True) == \
672
+ log(1 + sqrt(2))
673
+ assert integrate(E1(x)*besselj(1, x), (x, 0, oo), meijerg=True) == \
674
+ log(S.Half + sqrt(2)/2)
675
+
676
+ assert integrate(1/x/sqrt(1 - x**2), x, meijerg=True) == \
677
+ Piecewise((-acosh(1/x), abs(x**(-2)) > 1), (I*asin(1/x), True))
678
+
679
+
680
+ def test_issue_6122():
681
+ assert integrate(exp(-I*x**2), (x, -oo, oo), meijerg=True) == \
682
+ -I*sqrt(pi)*exp(I*pi/4)
683
+
684
+
685
+ def test_issue_6252():
686
+ expr = 1/x/(a + b*x)**Rational(1, 3)
687
+ anti = integrate(expr, x, meijerg=True)
688
+ assert not anti.has(hyper)
689
+ # XXX the expression is a mess, but actually upon differentiation and
690
+ # putting in numerical values seems to work...
691
+
692
+
693
+ def test_issue_6348():
694
+ assert integrate(exp(I*x)/(1 + x**2), (x, -oo, oo)).simplify().rewrite(exp) \
695
+ == pi*exp(-1)
696
+
697
+
698
+ def test_fresnel():
699
+ from sympy.functions.special.error_functions import (fresnelc, fresnels)
700
+
701
+ assert expand_func(integrate(sin(pi*x**2/2), x)) == fresnels(x)
702
+ assert expand_func(integrate(cos(pi*x**2/2), x)) == fresnelc(x)
703
+
704
+
705
+ def test_issue_6860():
706
+ assert meijerint_indefinite(x**x**x, x) is None
707
+
708
+
709
+ def test_issue_7337():
710
+ f = meijerint_indefinite(x*sqrt(2*x + 3), x).together()
711
+ assert f == sqrt(2*x + 3)*(2*x**2 + x - 3)/5
712
+ assert f._eval_interval(x, S.NegativeOne, S.One) == Rational(2, 5)
713
+
714
+
715
+ def test_issue_8368():
716
+ assert meijerint_indefinite(cosh(x)*exp(-x*t), x) == (
717
+ (-t - 1)*exp(x) + (-t + 1)*exp(-x))*exp(-t*x)/2/(t**2 - 1)
718
+
719
+
720
+ def test_issue_10211():
721
+ from sympy.abc import h, w
722
+ assert integrate((1/sqrt((y-x)**2 + h**2)**3), (x,0,w), (y,0,w)) == \
723
+ 2*sqrt(1 + w**2/h**2)/h - 2/h
724
+
725
+
726
+ def test_issue_11806():
727
+ from sympy.core.symbol import symbols
728
+ y, L = symbols('y L', positive=True)
729
+ assert integrate(1/sqrt(x**2 + y**2)**3, (x, -L, L)) == \
730
+ 2*L/(y**2*sqrt(L**2 + y**2))
731
+
732
+ def test_issue_10681():
733
+ from sympy.polys.domains.realfield import RR
734
+ from sympy.abc import R, r
735
+ f = integrate(r**2*(R**2-r**2)**0.5, r, meijerg=True)
736
+ g = (1.0/3)*R**1.0*r**3*hyper((-0.5, Rational(3, 2)), (Rational(5, 2),),
737
+ r**2*exp_polar(2*I*pi)/R**2)
738
+ assert RR.almosteq((f/g).n(), 1.0, 1e-12)
739
+
740
+ def test_issue_13536():
741
+ from sympy.core.symbol import Symbol
742
+ a = Symbol('a', positive=True)
743
+ assert integrate(1/x**2, (x, oo, a)) == -1/a
744
+
745
+
746
+ def test_issue_6462():
747
+ from sympy.core.symbol import Symbol
748
+ x = Symbol('x')
749
+ n = Symbol('n')
750
+ # Not the actual issue, still wrong answer for n = 1, but that there is no
751
+ # exception
752
+ assert integrate(cos(x**n)/x**n, x, meijerg=True).subs(n, 2).equals(
753
+ integrate(cos(x**2)/x**2, x, meijerg=True))
754
+
755
+
756
+ def test_indefinite_1_bug():
757
+ assert integrate((b + t)**(-a), t, meijerg=True) == -b*(1 + t/b)**(1 - a)/(a*b**a - b**a)
758
+
759
+
760
+ def test_pr_23583():
761
+ # This result is wrong. Check whether new result is correct when this test fail.
762
+ assert integrate(1/sqrt((x - I)**2-1), meijerg=True) == \
763
+ Piecewise((acosh(x - I), Abs((x - I)**2) > 1), (-I*asin(x - I), True))
764
+
765
+
766
+ # 25786
767
+ def test_integrate_function_of_square_over_negatives():
768
+ assert integrate(exp(-x**2), (x,-5,0), meijerg=True) == sqrt(pi)/2 * erf(5)
769
+
770
+
771
+ def test_issue_25949():
772
+ from sympy.core.symbol import symbols
773
+ y = symbols("y", nonzero=True)
774
+ assert integrate(cosh(y*(x + 1)), (x, -1, -0.25), meijerg=True) == sinh(0.75*y)/y
.venv/lib/python3.13/site-packages/sympy/integrals/tests/test_prde.py ADDED
@@ -0,0 +1,322 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Most of these tests come from the examples in Bronstein's book."""
2
+ from sympy.integrals.risch import DifferentialExtension, derivation
3
+ from sympy.integrals.prde import (prde_normal_denom, prde_special_denom,
4
+ prde_linear_constraints, constant_system, prde_spde, prde_no_cancel_b_large,
5
+ prde_no_cancel_b_small, limited_integrate_reduce, limited_integrate,
6
+ is_deriv_k, is_log_deriv_k_t_radical, parametric_log_deriv_heu,
7
+ is_log_deriv_k_t_radical_in_field, param_poly_rischDE, param_rischDE,
8
+ prde_cancel_liouvillian)
9
+
10
+ from sympy.polys.polymatrix import PolyMatrix as Matrix
11
+
12
+ from sympy.core.numbers import Rational
13
+ from sympy.core.singleton import S
14
+ from sympy.core.symbol import symbols
15
+ from sympy.polys.domains.rationalfield import QQ
16
+ from sympy.polys.polytools import Poly
17
+ from sympy.abc import x, t, n
18
+
19
+ t0, t1, t2, t3, k = symbols('t:4 k')
20
+
21
+
22
+ def test_prde_normal_denom():
23
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1 + t**2, t)]})
24
+ fa = Poly(1, t)
25
+ fd = Poly(x, t)
26
+ G = [(Poly(t, t), Poly(1 + t**2, t)), (Poly(1, t), Poly(x + x*t**2, t))]
27
+ assert prde_normal_denom(fa, fd, G, DE) == \
28
+ (Poly(x, t, domain='ZZ(x)'), (Poly(1, t, domain='ZZ(x)'), Poly(1, t,
29
+ domain='ZZ(x)')), [(Poly(x*t, t, domain='ZZ(x)'),
30
+ Poly(t**2 + 1, t, domain='ZZ(x)')), (Poly(1, t, domain='ZZ(x)'),
31
+ Poly(t**2 + 1, t, domain='ZZ(x)'))], Poly(1, t, domain='ZZ(x)'))
32
+ G = [(Poly(t, t), Poly(t**2 + 2*t + 1, t)), (Poly(x*t, t),
33
+ Poly(t**2 + 2*t + 1, t)), (Poly(x*t**2, t), Poly(t**2 + 2*t + 1, t))]
34
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]})
35
+ assert prde_normal_denom(Poly(x, t), Poly(1, t), G, DE) == \
36
+ (Poly(t + 1, t), (Poly((-1 + x)*t + x, t), Poly(1, t, domain='ZZ[x]')), [(Poly(t, t),
37
+ Poly(1, t)), (Poly(x*t, t), Poly(1, t, domain='ZZ[x]')), (Poly(x*t**2, t),
38
+ Poly(1, t, domain='ZZ[x]'))], Poly(t + 1, t))
39
+
40
+
41
+ def test_prde_special_denom():
42
+ a = Poly(t + 1, t)
43
+ ba = Poly(t**2, t)
44
+ bd = Poly(1, t)
45
+ G = [(Poly(t, t), Poly(1, t)), (Poly(t**2, t), Poly(1, t)), (Poly(t**3, t), Poly(1, t))]
46
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]})
47
+ assert prde_special_denom(a, ba, bd, G, DE) == \
48
+ (Poly(t + 1, t), Poly(t**2, t), [(Poly(t, t), Poly(1, t)),
49
+ (Poly(t**2, t), Poly(1, t)), (Poly(t**3, t), Poly(1, t))], Poly(1, t))
50
+ G = [(Poly(t, t), Poly(1, t)), (Poly(1, t), Poly(t, t))]
51
+ assert prde_special_denom(Poly(1, t), Poly(t**2, t), Poly(1, t), G, DE) == \
52
+ (Poly(1, t), Poly(t**2 - 1, t), [(Poly(t**2, t), Poly(1, t)),
53
+ (Poly(1, t), Poly(1, t))], Poly(t, t))
54
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(-2*x*t0, t0)]})
55
+ DE.decrement_level()
56
+ G = [(Poly(t, t), Poly(t**2, t)), (Poly(2*t, t), Poly(t, t))]
57
+ assert prde_special_denom(Poly(5*x*t + 1, t), Poly(t**2 + 2*x**3*t, t), Poly(t**3 + 2, t), G, DE) == \
58
+ (Poly(5*x*t + 1, t), Poly(0, t, domain='ZZ[x]'), [(Poly(t, t), Poly(t**2, t)),
59
+ (Poly(2*t, t), Poly(t, t))], Poly(1, x))
60
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly((t**2 + 1)*2*x, t)]})
61
+ G = [(Poly(t + x, t), Poly(t*x, t)), (Poly(2*t, t), Poly(x**2, x))]
62
+ assert prde_special_denom(Poly(5*x*t + 1, t), Poly(t**2 + 2*x**3*t, t), Poly(t**3, t), G, DE) == \
63
+ (Poly(5*x*t + 1, t), Poly(0, t, domain='ZZ[x]'), [(Poly(t + x, t), Poly(x*t, t)),
64
+ (Poly(2*t, t, x), Poly(x**2, t, x))], Poly(1, t))
65
+ assert prde_special_denom(Poly(t + 1, t), Poly(t**2, t), Poly(t**3, t), G, DE) == \
66
+ (Poly(t + 1, t), Poly(0, t, domain='ZZ[x]'), [(Poly(t + x, t), Poly(x*t, t)), (Poly(2*t, t, x),
67
+ Poly(x**2, t, x))], Poly(1, t))
68
+
69
+
70
+ def test_prde_linear_constraints():
71
+ DE = DifferentialExtension(extension={'D': [Poly(1, x)]})
72
+ G = [(Poly(2*x**3 + 3*x + 1, x), Poly(x**2 - 1, x)), (Poly(1, x), Poly(x - 1, x)),
73
+ (Poly(1, x), Poly(x + 1, x))]
74
+ assert prde_linear_constraints(Poly(1, x), Poly(0, x), G, DE) == \
75
+ ((Poly(2*x, x, domain='QQ'), Poly(0, x, domain='QQ'), Poly(0, x, domain='QQ')),
76
+ Matrix([[1, 1, -1], [5, 1, 1]], x))
77
+ G = [(Poly(t, t), Poly(1, t)), (Poly(t**2, t), Poly(1, t)), (Poly(t**3, t), Poly(1, t))]
78
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]})
79
+ assert prde_linear_constraints(Poly(t + 1, t), Poly(t**2, t), G, DE) == \
80
+ ((Poly(t, t, domain='QQ'), Poly(t**2, t, domain='QQ'), Poly(t**3, t, domain='QQ')),
81
+ Matrix(0, 3, [], t))
82
+ G = [(Poly(2*x, t), Poly(t, t)), (Poly(-x, t), Poly(t, t))]
83
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]})
84
+ assert prde_linear_constraints(Poly(1, t), Poly(0, t), G, DE) == \
85
+ ((Poly(0, t, domain='QQ[x]'), Poly(0, t, domain='QQ[x]')), Matrix([[2*x, -x]], t))
86
+
87
+
88
+ def test_constant_system():
89
+ A = Matrix([[-(x + 3)/(x - 1), (x + 1)/(x - 1), 1],
90
+ [-x - 3, x + 1, x - 1],
91
+ [2*(x + 3)/(x - 1), 0, 0]], t)
92
+ u = Matrix([[(x + 1)/(x - 1)], [x + 1], [0]], t)
93
+ DE = DifferentialExtension(extension={'D': [Poly(1, x)]})
94
+ R = QQ.frac_field(x)[t]
95
+ assert constant_system(A, u, DE) == \
96
+ (Matrix([[1, 0, 0],
97
+ [0, 1, 0],
98
+ [0, 0, 0],
99
+ [0, 0, 1]], ring=R), Matrix([0, 1, 0, 0], ring=R))
100
+
101
+
102
+ def test_prde_spde():
103
+ D = [Poly(x, t), Poly(-x*t, t)]
104
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]})
105
+ # TODO: when bound_degree() can handle this, test degree bound from that too
106
+ assert prde_spde(Poly(t, t), Poly(-1/x, t), D, n, DE) == \
107
+ (Poly(t, t), Poly(0, t, domain='ZZ(x)'),
108
+ [Poly(2*x, t, domain='ZZ(x)'), Poly(-x, t, domain='ZZ(x)')],
109
+ [Poly(-x**2, t, domain='ZZ(x)'), Poly(0, t, domain='ZZ(x)')], n - 1)
110
+
111
+
112
+ def test_prde_no_cancel():
113
+ # b large
114
+ DE = DifferentialExtension(extension={'D': [Poly(1, x)]})
115
+ assert prde_no_cancel_b_large(Poly(1, x), [Poly(x**2, x), Poly(1, x)], 2, DE) == \
116
+ ([Poly(x**2 - 2*x + 2, x), Poly(1, x)], Matrix([[1, 0, -1, 0],
117
+ [0, 1, 0, -1]], x))
118
+ assert prde_no_cancel_b_large(Poly(1, x), [Poly(x**3, x), Poly(1, x)], 3, DE) == \
119
+ ([Poly(x**3 - 3*x**2 + 6*x - 6, x), Poly(1, x)], Matrix([[1, 0, -1, 0],
120
+ [0, 1, 0, -1]], x))
121
+ assert prde_no_cancel_b_large(Poly(x, x), [Poly(x**2, x), Poly(1, x)], 1, DE) == \
122
+ ([Poly(x, x, domain='ZZ'), Poly(0, x, domain='ZZ')], Matrix([[1, -1, 0, 0],
123
+ [1, 0, -1, 0],
124
+ [0, 1, 0, -1]], x))
125
+ # b small
126
+ # XXX: Is there a better example of a monomial with D.degree() > 2?
127
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**3 + 1, t)]})
128
+
129
+ # My original q was t**4 + t + 1, but this solution implies q == t**4
130
+ # (c1 = 4), with some of the ci for the original q equal to 0.
131
+ G = [Poly(t**6, t), Poly(x*t**5, t), Poly(t**3, t), Poly(x*t**2, t), Poly(1 + x, t)]
132
+ R = QQ.frac_field(x)[t]
133
+ assert prde_no_cancel_b_small(Poly(x*t, t), G, 4, DE) == \
134
+ ([Poly(t**4/4 - x/12*t**3 + x**2/24*t**2 + (Rational(-11, 12) - x**3/24)*t + x/24, t),
135
+ Poly(x/3*t**3 - x**2/6*t**2 + (Rational(-1, 3) + x**3/6)*t - x/6, t), Poly(t, t),
136
+ Poly(0, t), Poly(0, t)], Matrix([[1, 0, -1, 0, 0, 0, 0, 0, 0, 0],
137
+ [0, 1, Rational(-1, 4), 0, 0, 0, 0, 0, 0, 0],
138
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
139
+ [0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
140
+ [0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
141
+ [1, 0, 0, 0, 0, -1, 0, 0, 0, 0],
142
+ [0, 1, 0, 0, 0, 0, -1, 0, 0, 0],
143
+ [0, 0, 1, 0, 0, 0, 0, -1, 0, 0],
144
+ [0, 0, 0, 1, 0, 0, 0, 0, -1, 0],
145
+ [0, 0, 0, 0, 1, 0, 0, 0, 0, -1]], ring=R))
146
+
147
+ # TODO: Add test for deg(b) <= 0 with b small
148
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1 + t**2, t)]})
149
+ b = Poly(-1/x**2, t, field=True) # deg(b) == 0
150
+ q = [Poly(x**i*t**j, t, field=True) for i in range(2) for j in range(3)]
151
+ h, A = prde_no_cancel_b_small(b, q, 3, DE)
152
+ V = A.nullspace()
153
+ R = QQ.frac_field(x)[t]
154
+ assert len(V) == 1
155
+ assert V[0] == Matrix([Rational(-1, 2), 0, 0, 1, 0, 0]*3, ring=R)
156
+ assert (Matrix([h])*V[0][6:, :])[0] == Poly(x**2/2, t, domain='QQ(x)')
157
+ assert (Matrix([q])*V[0][:6, :])[0] == Poly(x - S.Half, t, domain='QQ(x)')
158
+
159
+
160
+ def test_prde_cancel_liouvillian():
161
+ ### 1. case == 'primitive'
162
+ # used when integrating f = log(x) - log(x - 1)
163
+ # Not taken from 'the' book
164
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]})
165
+ p0 = Poly(0, t, field=True)
166
+ p1 = Poly((x - 1)*t, t, domain='ZZ(x)')
167
+ p2 = Poly(x - 1, t, domain='ZZ(x)')
168
+ p3 = Poly(-x**2 + x, t, domain='ZZ(x)')
169
+ h, A = prde_cancel_liouvillian(Poly(-1/(x - 1), t), [Poly(-x + 1, t), Poly(1, t)], 1, DE)
170
+ V = A.nullspace()
171
+ assert h == [p0, p0, p1, p0, p0, p0, p0, p0, p0, p0, p2, p3, p0, p0, p0, p0]
172
+ assert A.rank() == 16
173
+ assert (Matrix([h])*V[0][:16, :]) == Matrix([[Poly(0, t, domain='QQ(x)')]])
174
+
175
+ ### 2. case == 'exp'
176
+ # used when integrating log(x/exp(x) + 1)
177
+ # Not taken from book
178
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(-t, t)]})
179
+ assert prde_cancel_liouvillian(Poly(0, t, domain='QQ[x]'), [Poly(1, t, domain='QQ(x)')], 0, DE) == \
180
+ ([Poly(1, t, domain='QQ'), Poly(x, t, domain='ZZ(x)')], Matrix([[-1, 0, 1]], DE.t))
181
+
182
+
183
+ def test_param_poly_rischDE():
184
+ DE = DifferentialExtension(extension={'D': [Poly(1, x)]})
185
+ a = Poly(x**2 - x, x, field=True)
186
+ b = Poly(1, x, field=True)
187
+ q = [Poly(x, x, field=True), Poly(x**2, x, field=True)]
188
+ h, A = param_poly_rischDE(a, b, q, 3, DE)
189
+
190
+ assert A.nullspace() == [Matrix([0, 1, 1, 1], DE.t)] # c1, c2, d1, d2
191
+ # Solution of a*Dp + b*p = c1*q1 + c2*q2 = q2 = x**2
192
+ # is d1*h1 + d2*h2 = h1 + h2 = x.
193
+ assert h[0] + h[1] == Poly(x, x, domain='QQ')
194
+ # a*Dp + b*p = q1 = x has no solution.
195
+
196
+ a = Poly(x**2 - x, x, field=True)
197
+ b = Poly(x**2 - 5*x + 3, x, field=True)
198
+ q = [Poly(1, x, field=True), Poly(x, x, field=True),
199
+ Poly(x**2, x, field=True)]
200
+ h, A = param_poly_rischDE(a, b, q, 3, DE)
201
+
202
+ assert A.nullspace() == [Matrix([3, -5, 1, -5, 1, 1], DE.t)]
203
+ p = -Poly(5, DE.t)*h[0] + h[1] + h[2] # Poly(1, x)
204
+ assert a*derivation(p, DE) + b*p == Poly(x**2 - 5*x + 3, x, domain='QQ')
205
+
206
+
207
+ def test_param_rischDE():
208
+ DE = DifferentialExtension(extension={'D': [Poly(1, x)]})
209
+ p1, px = Poly(1, x, field=True), Poly(x, x, field=True)
210
+ G = [(p1, px), (p1, p1), (px, p1)] # [1/x, 1, x]
211
+ h, A = param_rischDE(-p1, Poly(x**2, x, field=True), G, DE)
212
+ assert len(h) == 3
213
+ p = [hi[0].as_expr()/hi[1].as_expr() for hi in h]
214
+ V = A.nullspace()
215
+ assert len(V) == 2
216
+ assert V[0] == Matrix([-1, 1, 0, -1, 1, 0], DE.t)
217
+ y = -p[0] + p[1] + 0*p[2] # x
218
+ assert y.diff(x) - y/x**2 == 1 - 1/x # Dy + f*y == -G0 + G1 + 0*G2
219
+
220
+ # the below test computation takes place while computing the integral
221
+ # of 'f = log(log(x + exp(x)))'
222
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]})
223
+ G = [(Poly(t + x, t, domain='ZZ(x)'), Poly(1, t, domain='QQ')), (Poly(0, t, domain='QQ'), Poly(1, t, domain='QQ'))]
224
+ h, A = param_rischDE(Poly(-t - 1, t, field=True), Poly(t + x, t, field=True), G, DE)
225
+ assert len(h) == 5
226
+ p = [hi[0].as_expr()/hi[1].as_expr() for hi in h]
227
+ V = A.nullspace()
228
+ assert len(V) == 3
229
+ assert V[0] == Matrix([0, 0, 0, 0, 1, 0, 0], DE.t)
230
+ y = 0*p[0] + 0*p[1] + 1*p[2] + 0*p[3] + 0*p[4]
231
+ assert y.diff(t) - y/(t + x) == 0 # Dy + f*y = 0*G0 + 0*G1
232
+
233
+
234
+ def test_limited_integrate_reduce():
235
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]})
236
+ assert limited_integrate_reduce(Poly(x, t), Poly(t**2, t), [(Poly(x, t),
237
+ Poly(t, t))], DE) == \
238
+ (Poly(t, t), Poly(-1/x, t), Poly(t, t), 1, (Poly(x, t), Poly(1, t, domain='ZZ[x]')),
239
+ [(Poly(-x*t, t), Poly(1, t, domain='ZZ[x]'))])
240
+
241
+
242
+ def test_limited_integrate():
243
+ DE = DifferentialExtension(extension={'D': [Poly(1, x)]})
244
+ G = [(Poly(x, x), Poly(x + 1, x))]
245
+ assert limited_integrate(Poly(-(1 + x + 5*x**2 - 3*x**3), x),
246
+ Poly(1 - x - x**2 + x**3, x), G, DE) == \
247
+ ((Poly(x**2 - x + 2, x), Poly(x - 1, x, domain='QQ')), [2])
248
+ G = [(Poly(1, x), Poly(x, x))]
249
+ assert limited_integrate(Poly(5*x**2, x), Poly(3, x), G, DE) == \
250
+ ((Poly(5*x**3/9, x), Poly(1, x, domain='QQ')), [0])
251
+
252
+
253
+ def test_is_log_deriv_k_t_radical():
254
+ DE = DifferentialExtension(extension={'D': [Poly(1, x)], 'exts': [None],
255
+ 'extargs': [None]})
256
+ assert is_log_deriv_k_t_radical(Poly(2*x, x), Poly(1, x), DE) is None
257
+
258
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(2*t1, t1), Poly(1/x, t2)],
259
+ 'exts': [None, 'exp', 'log'], 'extargs': [None, 2*x, x]})
260
+ assert is_log_deriv_k_t_radical(Poly(x + t2/2, t2), Poly(1, t2), DE) == \
261
+ ([(t1, 1), (x, 1)], t1*x, 2, 0)
262
+ # TODO: Add more tests
263
+
264
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t0, t0), Poly(1/x, t)],
265
+ 'exts': [None, 'exp', 'log'], 'extargs': [None, x, x]})
266
+ assert is_log_deriv_k_t_radical(Poly(x + t/2 + 3, t), Poly(1, t), DE) == \
267
+ ([(t0, 2), (x, 1)], x*t0**2, 2, 3)
268
+
269
+
270
+ def test_is_deriv_k():
271
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t1), Poly(1/(x + 1), t2)],
272
+ 'exts': [None, 'log', 'log'], 'extargs': [None, x, x + 1]})
273
+ assert is_deriv_k(Poly(2*x**2 + 2*x, t2), Poly(1, t2), DE) == \
274
+ ([(t1, 1), (t2, 1)], t1 + t2, 2)
275
+
276
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t1), Poly(t2, t2)],
277
+ 'exts': [None, 'log', 'exp'], 'extargs': [None, x, x]})
278
+ assert is_deriv_k(Poly(x**2*t2**3, t2), Poly(1, t2), DE) == \
279
+ ([(x, 3), (t1, 2)], 2*t1 + 3*x, 1)
280
+ # TODO: Add more tests, including ones with exponentials
281
+
282
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(2/x, t1)],
283
+ 'exts': [None, 'log'], 'extargs': [None, x**2]})
284
+ assert is_deriv_k(Poly(x, t1), Poly(1, t1), DE) == \
285
+ ([(t1, S.Half)], t1/2, 1)
286
+
287
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(2/(1 + x), t0)],
288
+ 'exts': [None, 'log'], 'extargs': [None, x**2 + 2*x + 1]})
289
+ assert is_deriv_k(Poly(1 + x, t0), Poly(1, t0), DE) == \
290
+ ([(t0, S.Half)], t0/2, 1)
291
+
292
+ # Issue 10798
293
+ # DE = DifferentialExtension(log(1/x), x)
294
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(-1/x, t)],
295
+ 'exts': [None, 'log'], 'extargs': [None, 1/x]})
296
+ assert is_deriv_k(Poly(1, t), Poly(x, t), DE) == ([(t, 1)], t, 1)
297
+
298
+
299
+ def test_is_log_deriv_k_t_radical_in_field():
300
+ # NOTE: any potential constant factor in the second element of the result
301
+ # doesn't matter, because it cancels in Da/a.
302
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]})
303
+ assert is_log_deriv_k_t_radical_in_field(Poly(5*t + 1, t), Poly(2*t*x, t), DE) == \
304
+ (2, t*x**5)
305
+ assert is_log_deriv_k_t_radical_in_field(Poly(2 + 3*t, t), Poly(5*x*t, t), DE) == \
306
+ (5, x**3*t**2)
307
+
308
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(-t/x**2, t)]})
309
+ assert is_log_deriv_k_t_radical_in_field(Poly(-(1 + 2*t), t),
310
+ Poly(2*x**2 + 2*x**2*t, t), DE) == \
311
+ (2, t + t**2)
312
+ assert is_log_deriv_k_t_radical_in_field(Poly(-1, t), Poly(x**2, t), DE) == \
313
+ (1, t)
314
+ assert is_log_deriv_k_t_radical_in_field(Poly(1, t), Poly(2*x**2, t), DE) == \
315
+ (2, 1/t)
316
+
317
+
318
+ def test_parametric_log_deriv():
319
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]})
320
+ assert parametric_log_deriv_heu(Poly(5*t**2 + t - 6, t), Poly(2*x*t**2, t),
321
+ Poly(-1, t), Poly(x*t**2, t), DE) == \
322
+ (2, 6, t*x**5)
.venv/lib/python3.13/site-packages/sympy/integrals/tests/test_quadrature.py ADDED
@@ -0,0 +1,601 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core import S, Rational
2
+ from sympy.integrals.quadrature import (gauss_legendre, gauss_laguerre,
3
+ gauss_hermite, gauss_gen_laguerre,
4
+ gauss_chebyshev_t, gauss_chebyshev_u,
5
+ gauss_jacobi, gauss_lobatto)
6
+
7
+
8
+ def test_legendre():
9
+ x, w = gauss_legendre(1, 17)
10
+ assert [str(r) for r in x] == ['0']
11
+ assert [str(r) for r in w] == ['2.0000000000000000']
12
+
13
+ x, w = gauss_legendre(2, 17)
14
+ assert [str(r) for r in x] == [
15
+ '-0.57735026918962576',
16
+ '0.57735026918962576']
17
+ assert [str(r) for r in w] == [
18
+ '1.0000000000000000',
19
+ '1.0000000000000000']
20
+
21
+ x, w = gauss_legendre(3, 17)
22
+ assert [str(r) for r in x] == [
23
+ '-0.77459666924148338',
24
+ '0',
25
+ '0.77459666924148338']
26
+ assert [str(r) for r in w] == [
27
+ '0.55555555555555556',
28
+ '0.88888888888888889',
29
+ '0.55555555555555556']
30
+
31
+ x, w = gauss_legendre(4, 17)
32
+ assert [str(r) for r in x] == [
33
+ '-0.86113631159405258',
34
+ '-0.33998104358485626',
35
+ '0.33998104358485626',
36
+ '0.86113631159405258']
37
+ assert [str(r) for r in w] == [
38
+ '0.34785484513745386',
39
+ '0.65214515486254614',
40
+ '0.65214515486254614',
41
+ '0.34785484513745386']
42
+
43
+
44
+ def test_legendre_precise():
45
+ x, w = gauss_legendre(3, 40)
46
+ assert [str(r) for r in x] == [
47
+ '-0.7745966692414833770358530799564799221666',
48
+ '0',
49
+ '0.7745966692414833770358530799564799221666']
50
+ assert [str(r) for r in w] == [
51
+ '0.5555555555555555555555555555555555555556',
52
+ '0.8888888888888888888888888888888888888889',
53
+ '0.5555555555555555555555555555555555555556']
54
+
55
+
56
+ def test_laguerre():
57
+ x, w = gauss_laguerre(1, 17)
58
+ assert [str(r) for r in x] == ['1.0000000000000000']
59
+ assert [str(r) for r in w] == ['1.0000000000000000']
60
+
61
+ x, w = gauss_laguerre(2, 17)
62
+ assert [str(r) for r in x] == [
63
+ '0.58578643762690495',
64
+ '3.4142135623730950']
65
+ assert [str(r) for r in w] == [
66
+ '0.85355339059327376',
67
+ '0.14644660940672624']
68
+
69
+ x, w = gauss_laguerre(3, 17)
70
+ assert [str(r) for r in x] == [
71
+ '0.41577455678347908',
72
+ '2.2942803602790417',
73
+ '6.2899450829374792',
74
+ ]
75
+ assert [str(r) for r in w] == [
76
+ '0.71109300992917302',
77
+ '0.27851773356924085',
78
+ '0.010389256501586136',
79
+ ]
80
+
81
+ x, w = gauss_laguerre(4, 17)
82
+ assert [str(r) for r in x] == [
83
+ '0.32254768961939231',
84
+ '1.7457611011583466',
85
+ '4.5366202969211280',
86
+ '9.3950709123011331']
87
+ assert [str(r) for r in w] == [
88
+ '0.60315410434163360',
89
+ '0.35741869243779969',
90
+ '0.038887908515005384',
91
+ '0.00053929470556132745']
92
+
93
+ x, w = gauss_laguerre(5, 17)
94
+ assert [str(r) for r in x] == [
95
+ '0.26356031971814091',
96
+ '1.4134030591065168',
97
+ '3.5964257710407221',
98
+ '7.0858100058588376',
99
+ '12.640800844275783']
100
+ assert [str(r) for r in w] == [
101
+ '0.52175561058280865',
102
+ '0.39866681108317593',
103
+ '0.075942449681707595',
104
+ '0.0036117586799220485',
105
+ '2.3369972385776228e-5']
106
+
107
+
108
+ def test_laguerre_precise():
109
+ x, w = gauss_laguerre(3, 40)
110
+ assert [str(r) for r in x] == [
111
+ '0.4157745567834790833115338731282744735466',
112
+ '2.294280360279041719822050361359593868960',
113
+ '6.289945082937479196866415765512131657493']
114
+ assert [str(r) for r in w] == [
115
+ '0.7110930099291730154495901911425944313094',
116
+ '0.2785177335692408488014448884567264810349',
117
+ '0.01038925650158613574896492040067908765572']
118
+
119
+
120
+ def test_hermite():
121
+ x, w = gauss_hermite(1, 17)
122
+ assert [str(r) for r in x] == ['0']
123
+ assert [str(r) for r in w] == ['1.7724538509055160']
124
+
125
+ x, w = gauss_hermite(2, 17)
126
+ assert [str(r) for r in x] == [
127
+ '-0.70710678118654752',
128
+ '0.70710678118654752']
129
+ assert [str(r) for r in w] == [
130
+ '0.88622692545275801',
131
+ '0.88622692545275801']
132
+
133
+ x, w = gauss_hermite(3, 17)
134
+ assert [str(r) for r in x] == [
135
+ '-1.2247448713915890',
136
+ '0',
137
+ '1.2247448713915890']
138
+ assert [str(r) for r in w] == [
139
+ '0.29540897515091934',
140
+ '1.1816359006036774',
141
+ '0.29540897515091934']
142
+
143
+ x, w = gauss_hermite(4, 17)
144
+ assert [str(r) for r in x] == [
145
+ '-1.6506801238857846',
146
+ '-0.52464762327529032',
147
+ '0.52464762327529032',
148
+ '1.6506801238857846']
149
+ assert [str(r) for r in w] == [
150
+ '0.081312835447245177',
151
+ '0.80491409000551284',
152
+ '0.80491409000551284',
153
+ '0.081312835447245177']
154
+
155
+ x, w = gauss_hermite(5, 17)
156
+ assert [str(r) for r in x] == [
157
+ '-2.0201828704560856',
158
+ '-0.95857246461381851',
159
+ '0',
160
+ '0.95857246461381851',
161
+ '2.0201828704560856']
162
+ assert [str(r) for r in w] == [
163
+ '0.019953242059045913',
164
+ '0.39361932315224116',
165
+ '0.94530872048294188',
166
+ '0.39361932315224116',
167
+ '0.019953242059045913']
168
+
169
+
170
+ def test_hermite_precise():
171
+ x, w = gauss_hermite(3, 40)
172
+ assert [str(r) for r in x] == [
173
+ '-1.224744871391589049098642037352945695983',
174
+ '0',
175
+ '1.224744871391589049098642037352945695983']
176
+ assert [str(r) for r in w] == [
177
+ '0.2954089751509193378830279138901908637996',
178
+ '1.181635900603677351532111655560763455198',
179
+ '0.2954089751509193378830279138901908637996']
180
+
181
+
182
+ def test_gen_laguerre():
183
+ x, w = gauss_gen_laguerre(1, Rational(-1, 2), 17)
184
+ assert [str(r) for r in x] == ['0.50000000000000000']
185
+ assert [str(r) for r in w] == ['1.7724538509055160']
186
+
187
+ x, w = gauss_gen_laguerre(2, Rational(-1, 2), 17)
188
+ assert [str(r) for r in x] == [
189
+ '0.27525512860841095',
190
+ '2.7247448713915890']
191
+ assert [str(r) for r in w] == [
192
+ '1.6098281800110257',
193
+ '0.16262567089449035']
194
+
195
+ x, w = gauss_gen_laguerre(3, Rational(-1, 2), 17)
196
+ assert [str(r) for r in x] == [
197
+ '0.19016350919348813',
198
+ '1.7844927485432516',
199
+ '5.5253437422632603']
200
+ assert [str(r) for r in w] == [
201
+ '1.4492591904487850',
202
+ '0.31413464064571329',
203
+ '0.0090600198110176913']
204
+
205
+ x, w = gauss_gen_laguerre(4, Rational(-1, 2), 17)
206
+ assert [str(r) for r in x] == [
207
+ '0.14530352150331709',
208
+ '1.3390972881263614',
209
+ '3.9269635013582872',
210
+ '8.5886356890120343']
211
+ assert [str(r) for r in w] == [
212
+ '1.3222940251164826',
213
+ '0.41560465162978376',
214
+ '0.034155966014826951',
215
+ '0.00039920814442273524']
216
+
217
+ x, w = gauss_gen_laguerre(5, Rational(-1, 2), 17)
218
+ assert [str(r) for r in x] == [
219
+ '0.11758132021177814',
220
+ '1.0745620124369040',
221
+ '3.0859374437175500',
222
+ '6.4147297336620305',
223
+ '11.807189489971737']
224
+ assert [str(r) for r in w] == [
225
+ '1.2217252674706516',
226
+ '0.48027722216462937',
227
+ '0.067748788910962126',
228
+ '0.0026872914935624654',
229
+ '1.5280865710465241e-5']
230
+
231
+ x, w = gauss_gen_laguerre(1, 2, 17)
232
+ assert [str(r) for r in x] == ['3.0000000000000000']
233
+ assert [str(r) for r in w] == ['2.0000000000000000']
234
+
235
+ x, w = gauss_gen_laguerre(2, 2, 17)
236
+ assert [str(r) for r in x] == [
237
+ '2.0000000000000000',
238
+ '6.0000000000000000']
239
+ assert [str(r) for r in w] == [
240
+ '1.5000000000000000',
241
+ '0.50000000000000000']
242
+
243
+ x, w = gauss_gen_laguerre(3, 2, 17)
244
+ assert [str(r) for r in x] == [
245
+ '1.5173870806774125',
246
+ '4.3115831337195203',
247
+ '9.1710297856030672']
248
+ assert [str(r) for r in w] == [
249
+ '1.0374949614904253',
250
+ '0.90575000470306537',
251
+ '0.056755033806509347']
252
+
253
+ x, w = gauss_gen_laguerre(4, 2, 17)
254
+ assert [str(r) for r in x] == [
255
+ '1.2267632635003021',
256
+ '3.4125073586969460',
257
+ '6.9026926058516134',
258
+ '12.458036771951139']
259
+ assert [str(r) for r in w] == [
260
+ '0.72552499769865438',
261
+ '1.0634242919791946',
262
+ '0.20669613102835355',
263
+ '0.0043545792937974889']
264
+
265
+ x, w = gauss_gen_laguerre(5, 2, 17)
266
+ assert [str(r) for r in x] == [
267
+ '1.0311091440933816',
268
+ '2.8372128239538217',
269
+ '5.6202942725987079',
270
+ '9.6829098376640271',
271
+ '15.828473921690062']
272
+ assert [str(r) for r in w] == [
273
+ '0.52091739683509184',
274
+ '1.0667059331592211',
275
+ '0.38354972366693113',
276
+ '0.028564233532974658',
277
+ '0.00026271280578124935']
278
+
279
+
280
+ def test_gen_laguerre_precise():
281
+ x, w = gauss_gen_laguerre(3, Rational(-1, 2), 40)
282
+ assert [str(r) for r in x] == [
283
+ '0.1901635091934881328718554276203028970878',
284
+ '1.784492748543251591186722461957367638500',
285
+ '5.525343742263260275941422110422329464413']
286
+ assert [str(r) for r in w] == [
287
+ '1.449259190448785048183829411195134343108',
288
+ '0.3141346406457132878326231270167565378246',
289
+ '0.009060019811017691281714945129254301865020']
290
+
291
+ x, w = gauss_gen_laguerre(3, 2, 40)
292
+ assert [str(r) for r in x] == [
293
+ '1.517387080677412495020323111016672547482',
294
+ '4.311583133719520302881184669723530562299',
295
+ '9.171029785603067202098492219259796890218']
296
+ assert [str(r) for r in w] == [
297
+ '1.037494961490425285817554606541269153041',
298
+ '0.9057500047030653669269785048806009945254',
299
+ '0.05675503380650934725546688857812985243312']
300
+
301
+
302
+ def test_chebyshev_t():
303
+ x, w = gauss_chebyshev_t(1, 17)
304
+ assert [str(r) for r in x] == ['0']
305
+ assert [str(r) for r in w] == ['3.1415926535897932']
306
+
307
+ x, w = gauss_chebyshev_t(2, 17)
308
+ assert [str(r) for r in x] == [
309
+ '0.70710678118654752',
310
+ '-0.70710678118654752']
311
+ assert [str(r) for r in w] == [
312
+ '1.5707963267948966',
313
+ '1.5707963267948966']
314
+
315
+ x, w = gauss_chebyshev_t(3, 17)
316
+ assert [str(r) for r in x] == [
317
+ '0.86602540378443865',
318
+ '0',
319
+ '-0.86602540378443865']
320
+ assert [str(r) for r in w] == [
321
+ '1.0471975511965977',
322
+ '1.0471975511965977',
323
+ '1.0471975511965977']
324
+
325
+ x, w = gauss_chebyshev_t(4, 17)
326
+ assert [str(r) for r in x] == [
327
+ '0.92387953251128676',
328
+ '0.38268343236508977',
329
+ '-0.38268343236508977',
330
+ '-0.92387953251128676']
331
+ assert [str(r) for r in w] == [
332
+ '0.78539816339744831',
333
+ '0.78539816339744831',
334
+ '0.78539816339744831',
335
+ '0.78539816339744831']
336
+
337
+ x, w = gauss_chebyshev_t(5, 17)
338
+ assert [str(r) for r in x] == [
339
+ '0.95105651629515357',
340
+ '0.58778525229247313',
341
+ '0',
342
+ '-0.58778525229247313',
343
+ '-0.95105651629515357']
344
+ assert [str(r) for r in w] == [
345
+ '0.62831853071795865',
346
+ '0.62831853071795865',
347
+ '0.62831853071795865',
348
+ '0.62831853071795865',
349
+ '0.62831853071795865']
350
+
351
+
352
+ def test_chebyshev_t_precise():
353
+ x, w = gauss_chebyshev_t(3, 40)
354
+ assert [str(r) for r in x] == [
355
+ '0.8660254037844386467637231707529361834714',
356
+ '0',
357
+ '-0.8660254037844386467637231707529361834714']
358
+ assert [str(r) for r in w] == [
359
+ '1.047197551196597746154214461093167628066',
360
+ '1.047197551196597746154214461093167628066',
361
+ '1.047197551196597746154214461093167628066']
362
+
363
+
364
+ def test_chebyshev_u():
365
+ x, w = gauss_chebyshev_u(1, 17)
366
+ assert [str(r) for r in x] == ['0']
367
+ assert [str(r) for r in w] == ['1.5707963267948966']
368
+
369
+ x, w = gauss_chebyshev_u(2, 17)
370
+ assert [str(r) for r in x] == [
371
+ '0.50000000000000000',
372
+ '-0.50000000000000000']
373
+ assert [str(r) for r in w] == [
374
+ '0.78539816339744831',
375
+ '0.78539816339744831']
376
+
377
+ x, w = gauss_chebyshev_u(3, 17)
378
+ assert [str(r) for r in x] == [
379
+ '0.70710678118654752',
380
+ '0',
381
+ '-0.70710678118654752']
382
+ assert [str(r) for r in w] == [
383
+ '0.39269908169872415',
384
+ '0.78539816339744831',
385
+ '0.39269908169872415']
386
+
387
+ x, w = gauss_chebyshev_u(4, 17)
388
+ assert [str(r) for r in x] == [
389
+ '0.80901699437494742',
390
+ '0.30901699437494742',
391
+ '-0.30901699437494742',
392
+ '-0.80901699437494742']
393
+ assert [str(r) for r in w] == [
394
+ '0.21707871342270599',
395
+ '0.56831944997474231',
396
+ '0.56831944997474231',
397
+ '0.21707871342270599']
398
+
399
+ x, w = gauss_chebyshev_u(5, 17)
400
+ assert [str(r) for r in x] == [
401
+ '0.86602540378443865',
402
+ '0.50000000000000000',
403
+ '0',
404
+ '-0.50000000000000000',
405
+ '-0.86602540378443865']
406
+ assert [str(r) for r in w] == [
407
+ '0.13089969389957472',
408
+ '0.39269908169872415',
409
+ '0.52359877559829887',
410
+ '0.39269908169872415',
411
+ '0.13089969389957472']
412
+
413
+
414
+ def test_chebyshev_u_precise():
415
+ x, w = gauss_chebyshev_u(3, 40)
416
+ assert [str(r) for r in x] == [
417
+ '0.7071067811865475244008443621048490392848',
418
+ '0',
419
+ '-0.7071067811865475244008443621048490392848']
420
+ assert [str(r) for r in w] == [
421
+ '0.3926990816987241548078304229099378605246',
422
+ '0.7853981633974483096156608458198757210493',
423
+ '0.3926990816987241548078304229099378605246']
424
+
425
+
426
+ def test_jacobi():
427
+ x, w = gauss_jacobi(1, Rational(-1, 2), S.Half, 17)
428
+ assert [str(r) for r in x] == ['0.50000000000000000']
429
+ assert [str(r) for r in w] == ['3.1415926535897932']
430
+
431
+ x, w = gauss_jacobi(2, Rational(-1, 2), S.Half, 17)
432
+ assert [str(r) for r in x] == [
433
+ '-0.30901699437494742',
434
+ '0.80901699437494742']
435
+ assert [str(r) for r in w] == [
436
+ '0.86831485369082398',
437
+ '2.2732777998989693']
438
+
439
+ x, w = gauss_jacobi(3, Rational(-1, 2), S.Half, 17)
440
+ assert [str(r) for r in x] == [
441
+ '-0.62348980185873353',
442
+ '0.22252093395631440',
443
+ '0.90096886790241913']
444
+ assert [str(r) for r in w] == [
445
+ '0.33795476356635433',
446
+ '1.0973322242791115',
447
+ '1.7063056657443274']
448
+
449
+ x, w = gauss_jacobi(4, Rational(-1, 2), S.Half, 17)
450
+ assert [str(r) for r in x] == [
451
+ '-0.76604444311897804',
452
+ '-0.17364817766693035',
453
+ '0.50000000000000000',
454
+ '0.93969262078590838']
455
+ assert [str(r) for r in w] == [
456
+ '0.16333179083642836',
457
+ '0.57690240318269103',
458
+ '1.0471975511965977',
459
+ '1.3541609083740761']
460
+
461
+ x, w = gauss_jacobi(5, Rational(-1, 2), S.Half, 17)
462
+ assert [str(r) for r in x] == [
463
+ '-0.84125353283118117',
464
+ '-0.41541501300188643',
465
+ '0.14231483827328514',
466
+ '0.65486073394528506',
467
+ '0.95949297361449739']
468
+ assert [str(r) for r in w] == [
469
+ '0.090675770007435372',
470
+ '0.33391416373675607',
471
+ '0.65248870981926643',
472
+ '0.94525424081394926',
473
+ '1.1192597692123861']
474
+
475
+ x, w = gauss_jacobi(1, 2, 3, 17)
476
+ assert [str(r) for r in x] == ['0.14285714285714286']
477
+ assert [str(r) for r in w] == ['1.0666666666666667']
478
+
479
+ x, w = gauss_jacobi(2, 2, 3, 17)
480
+ assert [str(r) for r in x] == [
481
+ '-0.24025307335204215',
482
+ '0.46247529557426437']
483
+ assert [str(r) for r in w] == [
484
+ '0.48514624517838660',
485
+ '0.58152042148828007']
486
+
487
+ x, w = gauss_jacobi(3, 2, 3, 17)
488
+ assert [str(r) for r in x] == [
489
+ '-0.46115870378089762',
490
+ '0.10438533038323902',
491
+ '0.62950064612493132']
492
+ assert [str(r) for r in w] == [
493
+ '0.17937613502213266',
494
+ '0.61595640991147154',
495
+ '0.27133412173306246']
496
+
497
+ x, w = gauss_jacobi(4, 2, 3, 17)
498
+ assert [str(r) for r in x] == [
499
+ '-0.59903470850824782',
500
+ '-0.14761105199952565',
501
+ '0.32554377081188859',
502
+ '0.72879429738819258']
503
+ assert [str(r) for r in w] == [
504
+ '0.067809641836772187',
505
+ '0.38956404952032481',
506
+ '0.47995970868024150',
507
+ '0.12933326662932816']
508
+
509
+ x, w = gauss_jacobi(5, 2, 3, 17)
510
+ assert [str(r) for r in x] == [
511
+ '-0.69045775012676106',
512
+ '-0.32651993134900065',
513
+ '0.082337849552034905',
514
+ '0.47517887061283164',
515
+ '0.79279429464422850']
516
+ assert [str(r) for r in w] == [
517
+ '0.027410178066337099',
518
+ '0.21291786060364828',
519
+ '0.43908437944395081',
520
+ '0.32220656547221822',
521
+ '0.065047683080512268']
522
+
523
+
524
+ def test_jacobi_precise():
525
+ x, w = gauss_jacobi(3, Rational(-1, 2), S.Half, 40)
526
+ assert [str(r) for r in x] == [
527
+ '-0.6234898018587335305250048840042398106323',
528
+ '0.2225209339563144042889025644967947594664',
529
+ '0.9009688679024191262361023195074450511659']
530
+ assert [str(r) for r in w] == [
531
+ '0.3379547635663543330553835737094171534907',
532
+ '1.097332224279111467485302294320899710461',
533
+ '1.706305665744327437921957515249186020246']
534
+
535
+ x, w = gauss_jacobi(3, 2, 3, 40)
536
+ assert [str(r) for r in x] == [
537
+ '-0.4611587037808976179121958105554375981274',
538
+ '0.1043853303832390210914918407615869143233',
539
+ '0.6295006461249313240934312425211234110769']
540
+ assert [str(r) for r in w] == [
541
+ '0.1793761350221326596137764371503859752628',
542
+ '0.6159564099114715430909548532229749439714',
543
+ '0.2713341217330624639619353762933057474325']
544
+
545
+
546
+ def test_lobatto():
547
+ x, w = gauss_lobatto(2, 17)
548
+ assert [str(r) for r in x] == [
549
+ '-1',
550
+ '1']
551
+ assert [str(r) for r in w] == [
552
+ '1.0000000000000000',
553
+ '1.0000000000000000']
554
+
555
+ x, w = gauss_lobatto(3, 17)
556
+ assert [str(r) for r in x] == [
557
+ '-1',
558
+ '0',
559
+ '1']
560
+ assert [str(r) for r in w] == [
561
+ '0.33333333333333333',
562
+ '1.3333333333333333',
563
+ '0.33333333333333333']
564
+
565
+ x, w = gauss_lobatto(4, 17)
566
+ assert [str(r) for r in x] == [
567
+ '-1',
568
+ '-0.44721359549995794',
569
+ '0.44721359549995794',
570
+ '1']
571
+ assert [str(r) for r in w] == [
572
+ '0.16666666666666667',
573
+ '0.83333333333333333',
574
+ '0.83333333333333333',
575
+ '0.16666666666666667']
576
+
577
+ x, w = gauss_lobatto(5, 17)
578
+ assert [str(r) for r in x] == [
579
+ '-1',
580
+ '-0.65465367070797714',
581
+ '0',
582
+ '0.65465367070797714',
583
+ '1']
584
+ assert [str(r) for r in w] == [
585
+ '0.10000000000000000',
586
+ '0.54444444444444444',
587
+ '0.71111111111111111',
588
+ '0.54444444444444444',
589
+ '0.10000000000000000']
590
+
591
+
592
+ def test_lobatto_precise():
593
+ x, w = gauss_lobatto(3, 40)
594
+ assert [str(r) for r in x] == [
595
+ '-1',
596
+ '0',
597
+ '1']
598
+ assert [str(r) for r in w] == [
599
+ '0.3333333333333333333333333333333333333333',
600
+ '1.333333333333333333333333333333333333333',
601
+ '0.3333333333333333333333333333333333333333']
.venv/lib/python3.13/site-packages/sympy/integrals/tests/test_rationaltools.py ADDED
@@ -0,0 +1,183 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core.numbers import (I, Rational)
2
+ from sympy.core.singleton import S
3
+ from sympy.core.symbol import (Dummy, symbols)
4
+ from sympy.functions.elementary.exponential import log
5
+ from sympy.functions.elementary.miscellaneous import sqrt
6
+ from sympy.functions.elementary.trigonometric import atan
7
+ from sympy.integrals.integrals import integrate
8
+ from sympy.polys.polytools import Poly
9
+ from sympy.simplify.simplify import simplify
10
+
11
+ from sympy.integrals.rationaltools import ratint, ratint_logpart, log_to_atan
12
+
13
+ from sympy.abc import a, b, x, t
14
+
15
+ half = S.Half
16
+
17
+
18
+ def test_ratint():
19
+ assert ratint(S.Zero, x) == 0
20
+ assert ratint(S(7), x) == 7*x
21
+
22
+ assert ratint(x, x) == x**2/2
23
+ assert ratint(2*x, x) == x**2
24
+ assert ratint(-2*x, x) == -x**2
25
+
26
+ assert ratint(8*x**7 + 2*x + 1, x) == x**8 + x**2 + x
27
+
28
+ f = S.One
29
+ g = x + 1
30
+
31
+ assert ratint(f / g, x) == log(x + 1)
32
+ assert ratint((f, g), x) == log(x + 1)
33
+
34
+ f = x**3 - x
35
+ g = x - 1
36
+
37
+ assert ratint(f/g, x) == x**3/3 + x**2/2
38
+
39
+ f = x
40
+ g = (x - a)*(x + a)
41
+
42
+ assert ratint(f/g, x) == log(x**2 - a**2)/2
43
+
44
+ f = S.One
45
+ g = x**2 + 1
46
+
47
+ assert ratint(f/g, x, real=None) == atan(x)
48
+ assert ratint(f/g, x, real=True) == atan(x)
49
+
50
+ assert ratint(f/g, x, real=False) == I*log(x + I)/2 - I*log(x - I)/2
51
+
52
+ f = S(36)
53
+ g = x**5 - 2*x**4 - 2*x**3 + 4*x**2 + x - 2
54
+
55
+ assert ratint(f/g, x) == \
56
+ -4*log(x + 1) + 4*log(x - 2) + (12*x + 6)/(x**2 - 1)
57
+
58
+ f = x**4 - 3*x**2 + 6
59
+ g = x**6 - 5*x**4 + 5*x**2 + 4
60
+
61
+ assert ratint(f/g, x) == \
62
+ atan(x) + atan(x**3) + atan(x/2 - Rational(3, 2)*x**3 + S.Half*x**5)
63
+
64
+ f = x**7 - 24*x**4 - 4*x**2 + 8*x - 8
65
+ g = x**8 + 6*x**6 + 12*x**4 + 8*x**2
66
+
67
+ assert ratint(f/g, x) == \
68
+ (4 + 6*x + 8*x**2 + 3*x**3)/(4*x + 4*x**3 + x**5) + log(x)
69
+
70
+ assert ratint((x**3*f)/(x*g), x) == \
71
+ -(12 - 16*x + 6*x**2 - 14*x**3)/(4 + 4*x**2 + x**4) - \
72
+ 5*sqrt(2)*atan(x*sqrt(2)/2) + S.Half*x**2 - 3*log(2 + x**2)
73
+
74
+ f = x**5 - x**4 + 4*x**3 + x**2 - x + 5
75
+ g = x**4 - 2*x**3 + 5*x**2 - 4*x + 4
76
+
77
+ assert ratint(f/g, x) == \
78
+ x + S.Half*x**2 + S.Half*log(2 - x + x**2) + (9 - 4*x)/(7*x**2 - 7*x + 14) + \
79
+ 13*sqrt(7)*atan(Rational(-1, 7)*sqrt(7) + 2*x*sqrt(7)/7)/49
80
+
81
+ assert ratint(1/(x**2 + x + 1), x) == \
82
+ 2*sqrt(3)*atan(sqrt(3)/3 + 2*x*sqrt(3)/3)/3
83
+
84
+ assert ratint(1/(x**3 + 1), x) == \
85
+ -log(1 - x + x**2)/6 + log(1 + x)/3 + sqrt(3)*atan(-sqrt(3)
86
+ /3 + 2*x*sqrt(3)/3)/3
87
+
88
+ assert ratint(1/(x**2 + x + 1), x, real=False) == \
89
+ -I*3**half*log(half + x - half*I*3**half)/3 + \
90
+ I*3**half*log(half + x + half*I*3**half)/3
91
+
92
+ assert ratint(1/(x**3 + 1), x, real=False) == log(1 + x)/3 + \
93
+ (Rational(-1, 6) + I*3**half/6)*log(-half + x + I*3**half/2) + \
94
+ (Rational(-1, 6) - I*3**half/6)*log(-half + x - I*3**half/2)
95
+
96
+ # issue 4991
97
+ assert ratint(1/(x*(a + b*x)**3), x) == \
98
+ (3*a + 2*b*x)/(2*a**4 + 4*a**3*b*x + 2*a**2*b**2*x**2) + (
99
+ log(x) - log(a/b + x))/a**3
100
+
101
+ assert ratint(x/(1 - x**2), x) == -log(x**2 - 1)/2
102
+ assert ratint(-x/(1 - x**2), x) == log(x**2 - 1)/2
103
+
104
+ assert ratint((x/4 - 4/(1 - x)).diff(x), x) == x/4 + 4/(x - 1)
105
+
106
+ ans = atan(x)
107
+ assert ratint(1/(x**2 + 1), x, symbol=x) == ans
108
+ assert ratint(1/(x**2 + 1), x, symbol='x') == ans
109
+ assert ratint(1/(x**2 + 1), x, symbol=a) == ans
110
+ # this asserts that as_dummy must return a unique symbol
111
+ # even if the symbol is already a Dummy
112
+ d = Dummy()
113
+ assert ratint(1/(d**2 + 1), d, symbol=d) == atan(d)
114
+
115
+
116
+ def test_ratint_logpart():
117
+ assert ratint_logpart(x, x**2 - 9, x, t) == \
118
+ [(Poly(x**2 - 9, x), Poly(-2*t + 1, t))]
119
+ assert ratint_logpart(x**2, x**3 - 5, x, t) == \
120
+ [(Poly(x**3 - 5, x), Poly(-3*t + 1, t))]
121
+
122
+
123
+ def test_issue_5414():
124
+ assert ratint(1/(x**2 + 16), x) == atan(x/4)/4
125
+
126
+
127
+ def test_issue_5249():
128
+ assert ratint(
129
+ 1/(x**2 + a**2), x) == (-I*log(-I*a + x)/2 + I*log(I*a + x)/2)/a
130
+
131
+
132
+ def test_issue_5817():
133
+ a, b, c = symbols('a,b,c', positive=True)
134
+
135
+ assert simplify(ratint(a/(b*c*x**2 + a**2 + b*a), x)) == \
136
+ sqrt(a)*atan(sqrt(
137
+ b)*sqrt(c)*x/(sqrt(a)*sqrt(a + b)))/(sqrt(b)*sqrt(c)*sqrt(a + b))
138
+
139
+
140
+ def test_issue_5981():
141
+ u = symbols('u')
142
+ assert integrate(1/(u**2 + 1)) == atan(u)
143
+
144
+ def test_issue_10488():
145
+ a,b,c,x = symbols('a b c x', positive=True)
146
+ assert integrate(x/(a*x+b),x) == x/a - b*log(a*x + b)/a**2
147
+
148
+
149
+ def test_issues_8246_12050_13501_14080():
150
+ a = symbols('a', nonzero=True)
151
+ assert integrate(a/(x**2 + a**2), x) == atan(x/a)
152
+ assert integrate(1/(x**2 + a**2), x) == atan(x/a)/a
153
+ assert integrate(1/(1 + a**2*x**2), x) == atan(a*x)/a
154
+
155
+
156
+ def test_issue_6308():
157
+ k, a0 = symbols('k a0', real=True)
158
+ assert integrate((x**2 + 1 - k**2)/(x**2 + 1 + a0**2), x) == \
159
+ x - (a0**2 + k**2)*atan(x/sqrt(a0**2 + 1))/sqrt(a0**2 + 1)
160
+
161
+
162
+ def test_issue_5907():
163
+ a = symbols('a', nonzero=True)
164
+ assert integrate(1/(x**2 + a**2)**2, x) == \
165
+ x/(2*a**4 + 2*a**2*x**2) + atan(x/a)/(2*a**3)
166
+
167
+
168
+ def test_log_to_atan():
169
+ f, g = (Poly(x + S.Half, x, domain='QQ'), Poly(sqrt(3)/2, x, domain='EX'))
170
+ fg_ans = 2*atan(2*sqrt(3)*x/3 + sqrt(3)/3)
171
+ assert log_to_atan(f, g) == fg_ans
172
+ assert log_to_atan(g, f) == -fg_ans
173
+
174
+
175
+ def test_issue_25896():
176
+ # for both tests, C = 0 in log_to_real
177
+ # but this only has a log result
178
+ e = (2*x + 1)/(x**2 + x + 1) + 1/x
179
+ assert ratint(e, x) == log(x**3 + x**2 + x)
180
+ # while this has more
181
+ assert ratint((4*x + 7)/(x**2 + 4*x + 6) + 2/x, x) == (
182
+ 2*log(x) + 2*log(x**2 + 4*x + 6) - sqrt(2)*atan(
183
+ sqrt(2)*x/2 + sqrt(2))/2)
.venv/lib/python3.13/site-packages/sympy/integrals/tests/test_rde.py ADDED
@@ -0,0 +1,202 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Most of these tests come from the examples in Bronstein's book."""
2
+ from sympy.core.numbers import (I, Rational, oo)
3
+ from sympy.core.symbol import symbols
4
+ from sympy.polys.polytools import Poly
5
+ from sympy.integrals.risch import (DifferentialExtension,
6
+ NonElementaryIntegralException)
7
+ from sympy.integrals.rde import (order_at, order_at_oo, weak_normalizer,
8
+ normal_denom, special_denom, bound_degree, spde, solve_poly_rde,
9
+ no_cancel_equal, cancel_primitive, cancel_exp, rischDE)
10
+
11
+ from sympy.testing.pytest import raises
12
+ from sympy.abc import x, t, z, n
13
+
14
+ t0, t1, t2, k = symbols('t:3 k')
15
+
16
+
17
+ def test_order_at():
18
+ a = Poly(t**4, t)
19
+ b = Poly((t**2 + 1)**3*t, t)
20
+ c = Poly((t**2 + 1)**6*t, t)
21
+ d = Poly((t**2 + 1)**10*t**10, t)
22
+ e = Poly((t**2 + 1)**100*t**37, t)
23
+ p1 = Poly(t, t)
24
+ p2 = Poly(1 + t**2, t)
25
+ assert order_at(a, p1, t) == 4
26
+ assert order_at(b, p1, t) == 1
27
+ assert order_at(c, p1, t) == 1
28
+ assert order_at(d, p1, t) == 10
29
+ assert order_at(e, p1, t) == 37
30
+ assert order_at(a, p2, t) == 0
31
+ assert order_at(b, p2, t) == 3
32
+ assert order_at(c, p2, t) == 6
33
+ assert order_at(d, p1, t) == 10
34
+ assert order_at(e, p2, t) == 100
35
+ assert order_at(Poly(0, t), Poly(t, t), t) is oo
36
+ assert order_at_oo(Poly(t**2 - 1, t), Poly(t + 1), t) == \
37
+ order_at_oo(Poly(t - 1, t), Poly(1, t), t) == -1
38
+ assert order_at_oo(Poly(0, t), Poly(1, t), t) is oo
39
+
40
+ def test_weak_normalizer():
41
+ a = Poly((1 + x)*t**5 + 4*t**4 + (-1 - 3*x)*t**3 - 4*t**2 + (-2 + 2*x)*t, t)
42
+ d = Poly(t**4 - 3*t**2 + 2, t)
43
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]})
44
+ r = weak_normalizer(a, d, DE, z)
45
+ assert r == (Poly(t**5 - t**4 - 4*t**3 + 4*t**2 + 4*t - 4, t, domain='ZZ[x]'),
46
+ (Poly((1 + x)*t**2 + x*t, t, domain='ZZ[x]'),
47
+ Poly(t + 1, t, domain='ZZ[x]')))
48
+ assert weak_normalizer(r[1][0], r[1][1], DE) == (Poly(1, t), r[1])
49
+ r = weak_normalizer(Poly(1 + t**2), Poly(t**2 - 1, t), DE, z)
50
+ assert r == (Poly(t**4 - 2*t**2 + 1, t), (Poly(-3*t**2 + 1, t), Poly(t**2 - 1, t)))
51
+ assert weak_normalizer(r[1][0], r[1][1], DE, z) == (Poly(1, t), r[1])
52
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1 + t**2)]})
53
+ r = weak_normalizer(Poly(1 + t**2), Poly(t, t), DE, z)
54
+ assert r == (Poly(t, t), (Poly(0, t), Poly(1, t)))
55
+ assert weak_normalizer(r[1][0], r[1][1], DE, z) == (Poly(1, t), r[1])
56
+
57
+
58
+ def test_normal_denom():
59
+ DE = DifferentialExtension(extension={'D': [Poly(1, x)]})
60
+ raises(NonElementaryIntegralException, lambda: normal_denom(Poly(1, x), Poly(1, x),
61
+ Poly(1, x), Poly(x, x), DE))
62
+ fa, fd = Poly(t**2 + 1, t), Poly(1, t)
63
+ ga, gd = Poly(1, t), Poly(t**2, t)
64
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]})
65
+ assert normal_denom(fa, fd, ga, gd, DE) == \
66
+ (Poly(t, t), (Poly(t**3 - t**2 + t - 1, t), Poly(1, t)), (Poly(1, t),
67
+ Poly(1, t)), Poly(t, t))
68
+
69
+
70
+ def test_special_denom():
71
+ # TODO: add more tests here
72
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]})
73
+ assert special_denom(Poly(1, t), Poly(t**2, t), Poly(1, t), Poly(t**2 - 1, t),
74
+ Poly(t, t), DE) == \
75
+ (Poly(1, t), Poly(t**2 - 1, t), Poly(t**2 - 1, t), Poly(t, t))
76
+ # assert special_denom(Poly(1, t), Poly(2*x, t), Poly((1 + 2*x)*t, t), DE) == 1
77
+
78
+ # issue 3940
79
+ # Note, this isn't a very good test, because the denominator is just 1,
80
+ # but at least it tests the exp cancellation case
81
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(-2*x*t0, t0),
82
+ Poly(I*k*t1, t1)]})
83
+ DE.decrement_level()
84
+ assert special_denom(Poly(1, t0), Poly(I*k, t0), Poly(1, t0), Poly(t0, t0),
85
+ Poly(1, t0), DE) == \
86
+ (Poly(1, t0, domain='ZZ'), Poly(I*k, t0, domain='ZZ_I[k,x]'),
87
+ Poly(t0, t0, domain='ZZ'), Poly(1, t0, domain='ZZ'))
88
+
89
+
90
+ assert special_denom(Poly(1, t), Poly(t**2, t), Poly(1, t), Poly(t**2 - 1, t),
91
+ Poly(t, t), DE, case='tan') == \
92
+ (Poly(1, t, t0, domain='ZZ'), Poly(t**2, t0, t, domain='ZZ[x]'),
93
+ Poly(t, t, t0, domain='ZZ'), Poly(1, t0, domain='ZZ'))
94
+
95
+ raises(ValueError, lambda: special_denom(Poly(1, t), Poly(t**2, t), Poly(1, t), Poly(t**2 - 1, t),
96
+ Poly(t, t), DE, case='unrecognized_case'))
97
+
98
+
99
+ def test_bound_degree_fail():
100
+ # Primitive
101
+ DE = DifferentialExtension(extension={'D': [Poly(1, x),
102
+ Poly(t0/x**2, t0), Poly(1/x, t)]})
103
+ assert bound_degree(Poly(t**2, t), Poly(-(1/x**2*t**2 + 1/x), t),
104
+ Poly((2*x - 1)*t**4 + (t0 + x)/x*t**3 - (t0 + 4*x**2)/2*x*t**2 + x*t,
105
+ t), DE) == 3
106
+
107
+
108
+ def test_bound_degree():
109
+ # Base
110
+ DE = DifferentialExtension(extension={'D': [Poly(1, x)]})
111
+ assert bound_degree(Poly(1, x), Poly(-2*x, x), Poly(1, x), DE) == 0
112
+
113
+ # Primitive (see above test_bound_degree_fail)
114
+ # TODO: Add test for when the degree bound becomes larger after limited_integrate
115
+ # TODO: Add test for db == da - 1 case
116
+
117
+ # Exp
118
+ # TODO: Add tests
119
+ # TODO: Add test for when the degree becomes larger after parametric_log_deriv()
120
+
121
+ # Nonlinear
122
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]})
123
+ assert bound_degree(Poly(t, t), Poly((t - 1)*(t**2 + 1), t), Poly(1, t), DE) == 0
124
+
125
+
126
+ def test_spde():
127
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]})
128
+ raises(NonElementaryIntegralException, lambda: spde(Poly(t, t), Poly((t - 1)*(t**2 + 1), t), Poly(1, t), 0, DE))
129
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]})
130
+ assert spde(Poly(t**2 + x*t*2 + x**2, t), Poly(t**2/x**2 + (2/x - 1)*t, t),
131
+ Poly(t**2/x**2 + (2/x - 1)*t, t), 0, DE) == \
132
+ (Poly(0, t), Poly(0, t), 0, Poly(0, t), Poly(1, t, domain='ZZ(x)'))
133
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t0/x**2, t0), Poly(1/x, t)]})
134
+ assert spde(Poly(t**2, t), Poly(-t**2/x**2 - 1/x, t),
135
+ Poly((2*x - 1)*t**4 + (t0 + x)/x*t**3 - (t0 + 4*x**2)/(2*x)*t**2 + x*t, t), 3, DE) == \
136
+ (Poly(0, t), Poly(0, t), 0, Poly(0, t),
137
+ Poly(t0*t**2/2 + x**2*t**2 - x**2*t, t, domain='ZZ(x,t0)'))
138
+ DE = DifferentialExtension(extension={'D': [Poly(1, x)]})
139
+ assert spde(Poly(x**2 + x + 1, x), Poly(-2*x - 1, x), Poly(x**5/2 +
140
+ 3*x**4/4 + x**3 - x**2 + 1, x), 4, DE) == \
141
+ (Poly(0, x, domain='QQ'), Poly(x/2 - Rational(1, 4), x), 2, Poly(x**2 + x + 1, x), Poly(x*Rational(5, 4), x))
142
+ assert spde(Poly(x**2 + x + 1, x), Poly(-2*x - 1, x), Poly(x**5/2 +
143
+ 3*x**4/4 + x**3 - x**2 + 1, x), n, DE) == \
144
+ (Poly(0, x, domain='QQ'), Poly(x/2 - Rational(1, 4), x), -2 + n, Poly(x**2 + x + 1, x), Poly(x*Rational(5, 4), x))
145
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1, t)]})
146
+ raises(NonElementaryIntegralException, lambda: spde(Poly((t - 1)*(t**2 + 1)**2, t), Poly((t - 1)*(t**2 + 1), t), Poly(1, t), 0, DE))
147
+ DE = DifferentialExtension(extension={'D': [Poly(1, x)]})
148
+ assert spde(Poly(x**2 - x, x), Poly(1, x), Poly(9*x**4 - 10*x**3 + 2*x**2, x), 4, DE) == \
149
+ (Poly(0, x, domain='ZZ'), Poly(0, x), 0, Poly(0, x), Poly(3*x**3 - 2*x**2, x, domain='QQ'))
150
+ assert spde(Poly(x**2 - x, x), Poly(x**2 - 5*x + 3, x), Poly(x**7 - x**6 - 2*x**4 + 3*x**3 - x**2, x), 5, DE) == \
151
+ (Poly(1, x, domain='QQ'), Poly(x + 1, x, domain='QQ'), 1, Poly(x**4 - x**3, x), Poly(x**3 - x**2, x, domain='QQ'))
152
+
153
+ def test_solve_poly_rde_no_cancel():
154
+ # deg(b) large
155
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1 + t**2, t)]})
156
+ assert solve_poly_rde(Poly(t**2 + 1, t), Poly(t**3 + (x + 1)*t**2 + t + x + 2, t),
157
+ oo, DE) == Poly(t + x, t)
158
+ # deg(b) small
159
+ DE = DifferentialExtension(extension={'D': [Poly(1, x)]})
160
+ assert solve_poly_rde(Poly(0, x), Poly(x/2 - Rational(1, 4), x), oo, DE) == \
161
+ Poly(x**2/4 - x/4, x)
162
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]})
163
+ assert solve_poly_rde(Poly(2, t), Poly(t**2 + 2*t + 3, t), 1, DE) == \
164
+ Poly(t + 1, t, x)
165
+ # deg(b) == deg(D) - 1
166
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]})
167
+ assert no_cancel_equal(Poly(1 - t, t),
168
+ Poly(t**3 + t**2 - 2*x*t - 2*x, t), oo, DE) == \
169
+ (Poly(t**2, t), 1, Poly((-2 - 2*x)*t - 2*x, t))
170
+
171
+
172
+ def test_solve_poly_rde_cancel():
173
+ # exp
174
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]})
175
+ assert cancel_exp(Poly(2*x, t), Poly(2*x, t), 0, DE) == \
176
+ Poly(1, t)
177
+ assert cancel_exp(Poly(2*x, t), Poly((1 + 2*x)*t, t), 1, DE) == \
178
+ Poly(t, t)
179
+ # TODO: Add more exp tests, including tests that require is_deriv_in_field()
180
+
181
+ # primitive
182
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]})
183
+
184
+ # If the DecrementLevel context manager is working correctly, this shouldn't
185
+ # cause any problems with the further tests.
186
+ raises(NonElementaryIntegralException, lambda: cancel_primitive(Poly(1, t), Poly(t, t), oo, DE))
187
+
188
+ assert cancel_primitive(Poly(1, t), Poly(t + 1/x, t), 2, DE) == \
189
+ Poly(t, t)
190
+ assert cancel_primitive(Poly(4*x, t), Poly(4*x*t**2 + 2*t/x, t), 3, DE) == \
191
+ Poly(t**2, t)
192
+
193
+ # TODO: Add more primitive tests, including tests that require is_deriv_in_field()
194
+
195
+
196
+ def test_rischDE():
197
+ # TODO: Add more tests for rischDE, including ones from the text
198
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]})
199
+ DE.decrement_level()
200
+ assert rischDE(Poly(-2*x, x), Poly(1, x), Poly(1 - 2*x - 2*x**2, x),
201
+ Poly(1, x), DE) == \
202
+ (Poly(x + 1, x), Poly(1, x))
.venv/lib/python3.13/site-packages/sympy/integrals/tests/test_risch.py ADDED
@@ -0,0 +1,763 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Most of these tests come from the examples in Bronstein's book."""
2
+ from sympy.core.function import (Function, Lambda, diff, expand_log)
3
+ from sympy.core.numbers import (I, Rational, pi)
4
+ from sympy.core.relational import Ne
5
+ from sympy.core.singleton import S
6
+ from sympy.core.symbol import (Symbol, symbols)
7
+ from sympy.functions.elementary.exponential import (exp, log)
8
+ from sympy.functions.elementary.miscellaneous import sqrt
9
+ from sympy.functions.elementary.piecewise import Piecewise
10
+ from sympy.functions.elementary.trigonometric import (atan, sin, tan)
11
+ from sympy.polys.polytools import (Poly, cancel, factor)
12
+ from sympy.integrals.risch import (gcdex_diophantine, frac_in, as_poly_1t,
13
+ derivation, splitfactor, splitfactor_sqf, canonical_representation,
14
+ hermite_reduce, polynomial_reduce, residue_reduce, residue_reduce_to_basic,
15
+ integrate_primitive, integrate_hyperexponential_polynomial,
16
+ integrate_hyperexponential, integrate_hypertangent_polynomial,
17
+ integrate_nonlinear_no_specials, integer_powers, DifferentialExtension,
18
+ risch_integrate, DecrementLevel, NonElementaryIntegral, recognize_log_derivative,
19
+ recognize_derivative, laurent_series)
20
+ from sympy.testing.pytest import raises
21
+
22
+ from sympy.abc import x, t, nu, z, a, y
23
+ t0, t1, t2 = symbols('t:3')
24
+ i = Symbol('i')
25
+
26
+ def test_gcdex_diophantine():
27
+ assert gcdex_diophantine(Poly(x**4 - 2*x**3 - 6*x**2 + 12*x + 15),
28
+ Poly(x**3 + x**2 - 4*x - 4), Poly(x**2 - 1)) == \
29
+ (Poly((-x**2 + 4*x - 3)/5), Poly((x**3 - 7*x**2 + 16*x - 10)/5))
30
+ assert gcdex_diophantine(Poly(x**3 + 6*x + 7), Poly(x**2 + 3*x + 2), Poly(x + 1)) == \
31
+ (Poly(1/13, x, domain='QQ'), Poly(-1/13*x + 3/13, x, domain='QQ'))
32
+
33
+
34
+ def test_frac_in():
35
+ assert frac_in(Poly((x + 1)/x*t, t), x) == \
36
+ (Poly(t*x + t, x), Poly(x, x))
37
+ assert frac_in((x + 1)/x*t, x) == \
38
+ (Poly(t*x + t, x), Poly(x, x))
39
+ assert frac_in((Poly((x + 1)/x*t, t), Poly(t + 1, t)), x) == \
40
+ (Poly(t*x + t, x), Poly((1 + t)*x, x))
41
+ raises(ValueError, lambda: frac_in((x + 1)/log(x)*t, x))
42
+ assert frac_in(Poly((2 + 2*x + x*(1 + x))/(1 + x)**2, t), x, cancel=True) == \
43
+ (Poly(x + 2, x), Poly(x + 1, x))
44
+
45
+
46
+ def test_as_poly_1t():
47
+ assert as_poly_1t(2/t + t, t, z) in [
48
+ Poly(t + 2*z, t, z), Poly(t + 2*z, z, t)]
49
+ assert as_poly_1t(2/t + 3/t**2, t, z) in [
50
+ Poly(2*z + 3*z**2, t, z), Poly(2*z + 3*z**2, z, t)]
51
+ assert as_poly_1t(2/((exp(2) + 1)*t), t, z) in [
52
+ Poly(2/(exp(2) + 1)*z, t, z), Poly(2/(exp(2) + 1)*z, z, t)]
53
+ assert as_poly_1t(2/((exp(2) + 1)*t) + t, t, z) in [
54
+ Poly(t + 2/(exp(2) + 1)*z, t, z), Poly(t + 2/(exp(2) + 1)*z, z, t)]
55
+ assert as_poly_1t(S.Zero, t, z) == Poly(0, t, z)
56
+
57
+
58
+ def test_derivation():
59
+ p = Poly(4*x**4*t**5 + (-4*x**3 - 4*x**4)*t**4 + (-3*x**2 + 2*x**3)*t**3 +
60
+ (2*x + 7*x**2 + 2*x**3)*t**2 + (1 - 4*x - 4*x**2)*t - 1 + 2*x, t)
61
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(-t**2 - 3/(2*x)*t + 1/(2*x), t)]})
62
+ assert derivation(p, DE) == Poly(-20*x**4*t**6 + (2*x**3 + 16*x**4)*t**5 +
63
+ (21*x**2 + 12*x**3)*t**4 + (x*Rational(7, 2) - 25*x**2 - 12*x**3)*t**3 +
64
+ (-5 - x*Rational(15, 2) + 7*x**2)*t**2 - (3 - 8*x - 10*x**2 - 4*x**3)/(2*x)*t +
65
+ (1 - 4*x**2)/(2*x), t)
66
+ assert derivation(Poly(1, t), DE) == Poly(0, t)
67
+ assert derivation(Poly(t, t), DE) == DE.d
68
+ assert derivation(Poly(t**2 + 1/x*t + (1 - 2*x)/(4*x**2), t), DE) == \
69
+ Poly(-2*t**3 - 4/x*t**2 - (5 - 2*x)/(2*x**2)*t - (1 - 2*x)/(2*x**3), t, domain='ZZ(x)')
70
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t1), Poly(t, t)]})
71
+ assert derivation(Poly(x*t*t1, t), DE) == Poly(t*t1 + x*t*t1 + t, t)
72
+ assert derivation(Poly(x*t*t1, t), DE, coefficientD=True) == \
73
+ Poly((1 + t1)*t, t)
74
+ DE = DifferentialExtension(extension={'D': [Poly(1, x)]})
75
+ assert derivation(Poly(x, x), DE) == Poly(1, x)
76
+ # Test basic option
77
+ assert derivation((x + 1)/(x - 1), DE, basic=True) == -2/(1 - 2*x + x**2)
78
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]})
79
+ assert derivation((t + 1)/(t - 1), DE, basic=True) == -2*t/(1 - 2*t + t**2)
80
+ assert derivation(t + 1, DE, basic=True) == t
81
+
82
+
83
+ def test_splitfactor():
84
+ p = Poly(4*x**4*t**5 + (-4*x**3 - 4*x**4)*t**4 + (-3*x**2 + 2*x**3)*t**3 +
85
+ (2*x + 7*x**2 + 2*x**3)*t**2 + (1 - 4*x - 4*x**2)*t - 1 + 2*x, t, field=True)
86
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(-t**2 - 3/(2*x)*t + 1/(2*x), t)]})
87
+ assert splitfactor(p, DE) == (Poly(4*x**4*t**3 + (-8*x**3 - 4*x**4)*t**2 +
88
+ (4*x**2 + 8*x**3)*t - 4*x**2, t, domain='ZZ(x)'),
89
+ Poly(t**2 + 1/x*t + (1 - 2*x)/(4*x**2), t, domain='ZZ(x)'))
90
+ assert splitfactor(Poly(x, t), DE) == (Poly(x, t), Poly(1, t))
91
+ r = Poly(-4*x**4*z**2 + 4*x**6*z**2 - z*x**3 - 4*x**5*z**3 + 4*x**3*z**3 + x**4 + z*x**5 - x**6, t)
92
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]})
93
+ assert splitfactor(r, DE, coefficientD=True) == \
94
+ (Poly(x*z - x**2 - z*x**3 + x**4, t), Poly(-x**2 + 4*x**2*z**2, t))
95
+ assert splitfactor_sqf(r, DE, coefficientD=True) == \
96
+ (((Poly(x*z - x**2 - z*x**3 + x**4, t), 1),), ((Poly(-x**2 + 4*x**2*z**2, t), 1),))
97
+ assert splitfactor(Poly(0, t), DE) == (Poly(0, t), Poly(1, t))
98
+ assert splitfactor_sqf(Poly(0, t), DE) == (((Poly(0, t), 1),), ())
99
+
100
+
101
+ def test_canonical_representation():
102
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1 + t**2, t)]})
103
+ assert canonical_representation(Poly(x - t, t), Poly(t**2, t), DE) == \
104
+ (Poly(0, t, domain='ZZ[x]'), (Poly(0, t, domain='QQ[x]'),
105
+ Poly(1, t, domain='ZZ')), (Poly(-t + x, t, domain='QQ[x]'),
106
+ Poly(t**2, t)))
107
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]})
108
+ assert canonical_representation(Poly(t**5 + t**3 + x**2*t + 1, t),
109
+ Poly((t**2 + 1)**3, t), DE) == \
110
+ (Poly(0, t, domain='ZZ[x]'), (Poly(t**5 + t**3 + x**2*t + 1, t, domain='QQ[x]'),
111
+ Poly(t**6 + 3*t**4 + 3*t**2 + 1, t, domain='QQ')),
112
+ (Poly(0, t, domain='QQ[x]'), Poly(1, t, domain='QQ')))
113
+
114
+
115
+ def test_hermite_reduce():
116
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]})
117
+
118
+ assert hermite_reduce(Poly(x - t, t), Poly(t**2, t), DE) == \
119
+ ((Poly(-x, t, domain='QQ[x]'), Poly(t, t, domain='QQ[x]')),
120
+ (Poly(0, t, domain='QQ[x]'), Poly(1, t, domain='QQ[x]')),
121
+ (Poly(-x, t, domain='QQ[x]'), Poly(1, t, domain='QQ[x]')))
122
+
123
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(-t**2 - t/x - (1 - nu**2/x**2), t)]})
124
+
125
+ assert hermite_reduce(
126
+ Poly(x**2*t**5 + x*t**4 - nu**2*t**3 - x*(x**2 + 1)*t**2 - (x**2 - nu**2)*t - x**5/4, t),
127
+ Poly(x**2*t**4 + x**2*(x**2 + 2)*t**2 + x**2 + x**4 + x**6/4, t), DE) == \
128
+ ((Poly(-x**2 - 4, t, domain='ZZ(x,nu)'), Poly(4*t**2 + 2*x**2 + 4, t, domain='ZZ(x,nu)')),
129
+ (Poly((-2*nu**2 - x**4)*t - (2*x**3 + 2*x), t, domain='ZZ(x,nu)'),
130
+ Poly(2*x**2*t**2 + x**4 + 2*x**2, t, domain='ZZ(x,nu)')),
131
+ (Poly(x*t + 1, t, domain='ZZ(x,nu)'), Poly(x, t, domain='ZZ(x,nu)')))
132
+
133
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]})
134
+
135
+ a = Poly((-2 + 3*x)*t**3 + (-1 + x)*t**2 + (-4*x + 2*x**2)*t + x**2, t)
136
+ d = Poly(x*t**6 - 4*x**2*t**5 + 6*x**3*t**4 - 4*x**4*t**3 + x**5*t**2, t)
137
+
138
+ assert hermite_reduce(a, d, DE) == \
139
+ ((Poly(3*t**2 + t + 3*x, t, domain='ZZ(x)'),
140
+ Poly(3*t**4 - 9*x*t**3 + 9*x**2*t**2 - 3*x**3*t, t, domain='ZZ(x)')),
141
+ (Poly(0, t, domain='ZZ(x)'), Poly(1, t, domain='ZZ(x)')),
142
+ (Poly(0, t, domain='ZZ(x)'), Poly(1, t, domain='ZZ(x)')))
143
+
144
+ assert hermite_reduce(
145
+ Poly(-t**2 + 2*t + 2, t, domain='ZZ(x)'),
146
+ Poly(-x*t**2 + 2*x*t - x, t, domain='ZZ(x)'), DE) == \
147
+ ((Poly(3, t, domain='ZZ(x)'), Poly(t - 1, t, domain='ZZ(x)')),
148
+ (Poly(0, t, domain='ZZ(x)'), Poly(1, t, domain='ZZ(x)')),
149
+ (Poly(1, t, domain='ZZ(x)'), Poly(x, t, domain='ZZ(x)')))
150
+
151
+ assert hermite_reduce(
152
+ Poly(-x**2*t**6 + (-1 - 2*x**3 + x**4)*t**3 + (-3 - 3*x**4)*t**2 -
153
+ 2*x*t - x - 3*x**2, t, domain='ZZ(x)'),
154
+ Poly(x**4*t**6 - 2*x**2*t**3 + 1, t, domain='ZZ(x)'), DE) == \
155
+ ((Poly(x**3*t + x**4 + 1, t, domain='ZZ(x)'), Poly(x**3*t**3 - x, t, domain='ZZ(x)')),
156
+ (Poly(0, t, domain='ZZ(x)'), Poly(1, t, domain='ZZ(x)')),
157
+ (Poly(-1, t, domain='ZZ(x)'), Poly(x**2, t, domain='ZZ(x)')))
158
+
159
+ assert hermite_reduce(
160
+ Poly((-2 + 3*x)*t**3 + (-1 + x)*t**2 + (-4*x + 2*x**2)*t + x**2, t),
161
+ Poly(x*t**6 - 4*x**2*t**5 + 6*x**3*t**4 - 4*x**4*t**3 + x**5*t**2, t), DE) == \
162
+ ((Poly(3*t**2 + t + 3*x, t, domain='ZZ(x)'),
163
+ Poly(3*t**4 - 9*x*t**3 + 9*x**2*t**2 - 3*x**3*t, t, domain='ZZ(x)')),
164
+ (Poly(0, t, domain='ZZ(x)'), Poly(1, t, domain='ZZ(x)')),
165
+ (Poly(0, t, domain='ZZ(x)'), Poly(1, t, domain='ZZ(x)')))
166
+
167
+
168
+ def test_polynomial_reduce():
169
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1 + t**2, t)]})
170
+ assert polynomial_reduce(Poly(1 + x*t + t**2, t), DE) == \
171
+ (Poly(t, t), Poly(x*t, t))
172
+ assert polynomial_reduce(Poly(0, t), DE) == \
173
+ (Poly(0, t), Poly(0, t))
174
+
175
+
176
+ def test_laurent_series():
177
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1, t)]})
178
+ a = Poly(36, t)
179
+ d = Poly((t - 2)*(t**2 - 1)**2, t)
180
+ F = Poly(t**2 - 1, t)
181
+ n = 2
182
+ assert laurent_series(a, d, F, n, DE) == \
183
+ (Poly(-3*t**3 + 3*t**2 - 6*t - 8, t), Poly(t**5 + t**4 - 2*t**3 - 2*t**2 + t + 1, t),
184
+ [Poly(-3*t**3 - 6*t**2, t, domain='QQ'), Poly(2*t**6 + 6*t**5 - 8*t**3, t, domain='QQ')])
185
+
186
+
187
+ def test_recognize_derivative():
188
+ DE = DifferentialExtension(extension={'D': [Poly(1, t)]})
189
+ a = Poly(36, t)
190
+ d = Poly((t - 2)*(t**2 - 1)**2, t)
191
+ assert recognize_derivative(a, d, DE) == False
192
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]})
193
+ a = Poly(2, t)
194
+ d = Poly(t**2 - 1, t)
195
+ assert recognize_derivative(a, d, DE) == False
196
+ assert recognize_derivative(Poly(x*t, t), Poly(1, t), DE) == True
197
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]})
198
+ assert recognize_derivative(Poly(t, t), Poly(1, t), DE) == True
199
+
200
+
201
+ def test_recognize_log_derivative():
202
+
203
+ a = Poly(2*x**2 + 4*x*t - 2*t - x**2*t, t)
204
+ d = Poly((2*x + t)*(t + x**2), t)
205
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]})
206
+ assert recognize_log_derivative(a, d, DE, z) == True
207
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]})
208
+ assert recognize_log_derivative(Poly(t + 1, t), Poly(t + x, t), DE) == True
209
+ assert recognize_log_derivative(Poly(2, t), Poly(t**2 - 1, t), DE) == True
210
+ DE = DifferentialExtension(extension={'D': [Poly(1, x)]})
211
+ assert recognize_log_derivative(Poly(1, x), Poly(x**2 - 2, x), DE) == False
212
+ assert recognize_log_derivative(Poly(1, x), Poly(x**2 + x, x), DE) == True
213
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]})
214
+ assert recognize_log_derivative(Poly(1, t), Poly(t**2 - 2, t), DE) == False
215
+ assert recognize_log_derivative(Poly(1, t), Poly(t**2 + t, t), DE) == False
216
+
217
+
218
+ def test_residue_reduce():
219
+ a = Poly(2*t**2 - t - x**2, t)
220
+ d = Poly(t**3 - x**2*t, t)
221
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)], 'Tfuncs': [log]})
222
+ assert residue_reduce(a, d, DE, z, invert=False) == \
223
+ ([(Poly(z**2 - Rational(1, 4), z, domain='ZZ(x)'),
224
+ Poly((1 + 3*x*z - 6*z**2 - 2*x**2 + 4*x**2*z**2)*t - x*z + x**2 +
225
+ 2*x**2*z**2 - 2*z*x**3, t, domain='ZZ(z, x)'))], False)
226
+ assert residue_reduce(a, d, DE, z, invert=True) == \
227
+ ([(Poly(z**2 - Rational(1, 4), z, domain='ZZ(x)'), Poly(t + 2*x*z, t))], False)
228
+ assert residue_reduce(Poly(-2/x, t), Poly(t**2 - 1, t,), DE, z, invert=False) == \
229
+ ([(Poly(z**2 - 1, z, domain='QQ'), Poly(-2*z*t/x - 2/x, t, domain='ZZ(z,x)'))], True)
230
+ ans = residue_reduce(Poly(-2/x, t), Poly(t**2 - 1, t), DE, z, invert=True)
231
+ assert ans == ([(Poly(z**2 - 1, z, domain='QQ'), Poly(t + z, t))], True)
232
+ assert residue_reduce_to_basic(ans[0], DE, z) == -log(-1 + log(x)) + log(1 + log(x))
233
+
234
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(-t**2 - t/x - (1 - nu**2/x**2), t)]})
235
+ # TODO: Skip or make faster
236
+ assert residue_reduce(Poly((-2*nu**2 - x**4)/(2*x**2)*t - (1 + x**2)/x, t),
237
+ Poly(t**2 + 1 + x**2/2, t), DE, z) == \
238
+ ([(Poly(z + S.Half, z, domain='QQ'), Poly(t**2 + 1 + x**2/2, t,
239
+ domain='ZZ(x,nu)'))], True)
240
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1 + t**2, t)]})
241
+ assert residue_reduce(Poly(-2*x*t + 1 - x**2, t),
242
+ Poly(t**2 + 2*x*t + 1 + x**2, t), DE, z) == \
243
+ ([(Poly(z**2 + Rational(1, 4), z), Poly(t + x + 2*z, t))], True)
244
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]})
245
+ assert residue_reduce(Poly(t, t), Poly(t + sqrt(2), t), DE, z) == \
246
+ ([(Poly(z - 1, z, domain='QQ'), Poly(t + sqrt(2), t))], True)
247
+
248
+
249
+ def test_integrate_hyperexponential():
250
+ # TODO: Add tests for integrate_hyperexponential() from the book
251
+ a = Poly((1 + 2*t1 + t1**2 + 2*t1**3)*t**2 + (1 + t1**2)*t + 1 + t1**2, t)
252
+ d = Poly(1, t)
253
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1 + t1**2, t1),
254
+ Poly(t*(1 + t1**2), t)], 'Tfuncs': [tan, Lambda(i, exp(tan(i)))]})
255
+ assert integrate_hyperexponential(a, d, DE) == \
256
+ (exp(2*tan(x))*tan(x) + exp(tan(x)), 1 + t1**2, True)
257
+ a = Poly((t1**3 + (x + 1)*t1**2 + t1 + x + 2)*t, t)
258
+ assert integrate_hyperexponential(a, d, DE) == \
259
+ ((x + tan(x))*exp(tan(x)), 0, True)
260
+
261
+ a = Poly(t, t)
262
+ d = Poly(1, t)
263
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(2*x*t, t)],
264
+ 'Tfuncs': [Lambda(i, exp(x**2))]})
265
+
266
+ assert integrate_hyperexponential(a, d, DE) == \
267
+ (0, NonElementaryIntegral(exp(x**2), x), False)
268
+
269
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)], 'Tfuncs': [exp]})
270
+ assert integrate_hyperexponential(a, d, DE) == (exp(x), 0, True)
271
+
272
+ a = Poly(25*t**6 - 10*t**5 + 7*t**4 - 8*t**3 + 13*t**2 + 2*t - 1, t)
273
+ d = Poly(25*t**6 + 35*t**4 + 11*t**2 + 1, t)
274
+ assert integrate_hyperexponential(a, d, DE) == \
275
+ (-(11 - 10*exp(x))/(5 + 25*exp(2*x)) + log(1 + exp(2*x)), -1, True)
276
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t0, t0), Poly(t0*t, t)],
277
+ 'Tfuncs': [exp, Lambda(i, exp(exp(i)))]})
278
+ assert integrate_hyperexponential(Poly(2*t0*t**2, t), Poly(1, t), DE) == (exp(2*exp(x)), 0, True)
279
+
280
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t0, t0), Poly(-t0*t, t)],
281
+ 'Tfuncs': [exp, Lambda(i, exp(-exp(i)))]})
282
+ assert integrate_hyperexponential(Poly(-27*exp(9) - 162*t0*exp(9) +
283
+ 27*x*t0*exp(9), t), Poly((36*exp(18) + x**2*exp(18) - 12*x*exp(18))*t, t), DE) == \
284
+ (27*exp(exp(x))/(-6*exp(9) + x*exp(9)), 0, True)
285
+
286
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)], 'Tfuncs': [exp]})
287
+ assert integrate_hyperexponential(Poly(x**2/2*t, t), Poly(1, t), DE) == \
288
+ ((2 - 2*x + x**2)*exp(x)/2, 0, True)
289
+ assert integrate_hyperexponential(Poly(1 + t, t), Poly(t, t), DE) == \
290
+ (-exp(-x), 1, True) # x - exp(-x)
291
+ assert integrate_hyperexponential(Poly(x, t), Poly(t + 1, t), DE) == \
292
+ (0, NonElementaryIntegral(x/(1 + exp(x)), x), False)
293
+
294
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t0), Poly(2*x*t1, t1)],
295
+ 'Tfuncs': [log, Lambda(i, exp(i**2))]})
296
+
297
+ elem, nonelem, b = integrate_hyperexponential(Poly((8*x**7 - 12*x**5 + 6*x**3 - x)*t1**4 +
298
+ (8*t0*x**7 - 8*t0*x**6 - 4*t0*x**5 + 2*t0*x**3 + 2*t0*x**2 - t0*x +
299
+ 24*x**8 - 36*x**6 - 4*x**5 + 22*x**4 + 4*x**3 - 7*x**2 - x + 1)*t1**3
300
+ + (8*t0*x**8 - 4*t0*x**6 - 16*t0*x**5 - 2*t0*x**4 + 12*t0*x**3 +
301
+ t0*x**2 - 2*t0*x + 24*x**9 - 36*x**7 - 8*x**6 + 22*x**5 + 12*x**4 -
302
+ 7*x**3 - 6*x**2 + x + 1)*t1**2 + (8*t0*x**8 - 8*t0*x**6 - 16*t0*x**5 +
303
+ 6*t0*x**4 + 10*t0*x**3 - 2*t0*x**2 - t0*x + 8*x**10 - 12*x**8 - 4*x**7
304
+ + 2*x**6 + 12*x**5 + 3*x**4 - 9*x**3 - x**2 + 2*x)*t1 + 8*t0*x**7 -
305
+ 12*t0*x**6 - 4*t0*x**5 + 8*t0*x**4 - t0*x**2 - 4*x**7 + 4*x**6 +
306
+ 4*x**5 - 4*x**4 - x**3 + x**2, t1), Poly((8*x**7 - 12*x**5 + 6*x**3 -
307
+ x)*t1**4 + (24*x**8 + 8*x**7 - 36*x**6 - 12*x**5 + 18*x**4 + 6*x**3 -
308
+ 3*x**2 - x)*t1**3 + (24*x**9 + 24*x**8 - 36*x**7 - 36*x**6 + 18*x**5 +
309
+ 18*x**4 - 3*x**3 - 3*x**2)*t1**2 + (8*x**10 + 24*x**9 - 12*x**8 -
310
+ 36*x**7 + 6*x**6 + 18*x**5 - x**4 - 3*x**3)*t1 + 8*x**10 - 12*x**8 +
311
+ 6*x**6 - x**4, t1), DE)
312
+
313
+ assert factor(elem) == -((x - 1)*log(x)/((x + exp(x**2))*(2*x**2 - 1)))
314
+ assert (nonelem, b) == (NonElementaryIntegral(exp(x**2)/(exp(x**2) + 1), x), False)
315
+
316
+ def test_integrate_hyperexponential_polynomial():
317
+ # Without proper cancellation within integrate_hyperexponential_polynomial(),
318
+ # this will take a long time to complete, and will return a complicated
319
+ # expression
320
+ p = Poly((-28*x**11*t0 - 6*x**8*t0 + 6*x**9*t0 - 15*x**8*t0**2 +
321
+ 15*x**7*t0**2 + 84*x**10*t0**2 - 140*x**9*t0**3 - 20*x**6*t0**3 +
322
+ 20*x**7*t0**3 - 15*x**6*t0**4 + 15*x**5*t0**4 + 140*x**8*t0**4 -
323
+ 84*x**7*t0**5 - 6*x**4*t0**5 + 6*x**5*t0**5 + x**3*t0**6 - x**4*t0**6 +
324
+ 28*x**6*t0**6 - 4*x**5*t0**7 + x**9 - x**10 + 4*x**12)/(-8*x**11*t0 +
325
+ 28*x**10*t0**2 - 56*x**9*t0**3 + 70*x**8*t0**4 - 56*x**7*t0**5 +
326
+ 28*x**6*t0**6 - 8*x**5*t0**7 + x**4*t0**8 + x**12)*t1**2 +
327
+ (-28*x**11*t0 - 12*x**8*t0 + 12*x**9*t0 - 30*x**8*t0**2 +
328
+ 30*x**7*t0**2 + 84*x**10*t0**2 - 140*x**9*t0**3 - 40*x**6*t0**3 +
329
+ 40*x**7*t0**3 - 30*x**6*t0**4 + 30*x**5*t0**4 + 140*x**8*t0**4 -
330
+ 84*x**7*t0**5 - 12*x**4*t0**5 + 12*x**5*t0**5 - 2*x**4*t0**6 +
331
+ 2*x**3*t0**6 + 28*x**6*t0**6 - 4*x**5*t0**7 + 2*x**9 - 2*x**10 +
332
+ 4*x**12)/(-8*x**11*t0 + 28*x**10*t0**2 - 56*x**9*t0**3 +
333
+ 70*x**8*t0**4 - 56*x**7*t0**5 + 28*x**6*t0**6 - 8*x**5*t0**7 +
334
+ x**4*t0**8 + x**12)*t1 + (-2*x**2*t0 + 2*x**3*t0 + x*t0**2 -
335
+ x**2*t0**2 + x**3 - x**4)/(-4*x**5*t0 + 6*x**4*t0**2 - 4*x**3*t0**3 +
336
+ x**2*t0**4 + x**6), t1, z, expand=False)
337
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t0), Poly(2*x*t1, t1)]})
338
+ assert integrate_hyperexponential_polynomial(p, DE, z) == (
339
+ Poly((x - t0)*t1**2 + (-2*t0 + 2*x)*t1, t1), Poly(-2*x*t0 + x**2 +
340
+ t0**2, t1), True)
341
+
342
+ DE = DifferentialExtension(extension={'D':[Poly(1, x), Poly(t0, t0)]})
343
+ assert integrate_hyperexponential_polynomial(Poly(0, t0), DE, z) == (
344
+ Poly(0, t0), Poly(1, t0), True)
345
+
346
+
347
+ def test_integrate_hyperexponential_returns_piecewise():
348
+ a, b = symbols('a b')
349
+ DE = DifferentialExtension(a**x, x)
350
+ assert integrate_hyperexponential(DE.fa, DE.fd, DE) == (Piecewise(
351
+ (exp(x*log(a))/log(a), Ne(log(a), 0)), (x, True)), 0, True)
352
+ DE = DifferentialExtension(a**(b*x), x)
353
+ assert integrate_hyperexponential(DE.fa, DE.fd, DE) == (Piecewise(
354
+ (exp(b*x*log(a))/(b*log(a)), Ne(b*log(a), 0)), (x, True)), 0, True)
355
+ DE = DifferentialExtension(exp(a*x), x)
356
+ assert integrate_hyperexponential(DE.fa, DE.fd, DE) == (Piecewise(
357
+ (exp(a*x)/a, Ne(a, 0)), (x, True)), 0, True)
358
+ DE = DifferentialExtension(x*exp(a*x), x)
359
+ assert integrate_hyperexponential(DE.fa, DE.fd, DE) == (Piecewise(
360
+ ((a*x - 1)*exp(a*x)/a**2, Ne(a**2, 0)), (x**2/2, True)), 0, True)
361
+ DE = DifferentialExtension(x**2*exp(a*x), x)
362
+ assert integrate_hyperexponential(DE.fa, DE.fd, DE) == (Piecewise(
363
+ ((x**2*a**2 - 2*a*x + 2)*exp(a*x)/a**3, Ne(a**3, 0)),
364
+ (x**3/3, True)), 0, True)
365
+ DE = DifferentialExtension(x**y + z, y)
366
+ assert integrate_hyperexponential(DE.fa, DE.fd, DE) == (Piecewise(
367
+ (exp(log(x)*y)/log(x), Ne(log(x), 0)), (y, True)), z, True)
368
+ DE = DifferentialExtension(x**y + z + x**(2*y), y)
369
+ assert integrate_hyperexponential(DE.fa, DE.fd, DE) == (Piecewise(
370
+ ((exp(2*log(x)*y)*log(x) +
371
+ 2*exp(log(x)*y)*log(x))/(2*log(x)**2), Ne(2*log(x)**2, 0)),
372
+ (2*y, True),
373
+ ), z, True)
374
+ # TODO: Add a test where two different parts of the extension use a
375
+ # Piecewise, like y**x + z**x.
376
+
377
+
378
+ def test_issue_13947():
379
+ a, t, s = symbols('a t s')
380
+ assert risch_integrate(2**(-pi)/(2**t + 1), t) == \
381
+ 2**(-pi)*t - 2**(-pi)*log(2**t + 1)/log(2)
382
+ assert risch_integrate(a**(t - s)/(a**t + 1), t) == \
383
+ exp(-s*log(a))*log(a**t + 1)/log(a)
384
+
385
+
386
+ def test_integrate_primitive():
387
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)],
388
+ 'Tfuncs': [log]})
389
+ assert integrate_primitive(Poly(t, t), Poly(1, t), DE) == (x*log(x), -1, True)
390
+ assert integrate_primitive(Poly(x, t), Poly(t, t), DE) == (0, NonElementaryIntegral(x/log(x), x), False)
391
+
392
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t1), Poly(1/(x + 1), t2)],
393
+ 'Tfuncs': [log, Lambda(i, log(i + 1))]})
394
+ assert integrate_primitive(Poly(t1, t2), Poly(t2, t2), DE) == \
395
+ (0, NonElementaryIntegral(log(x)/log(1 + x), x), False)
396
+
397
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t1), Poly(1/(x*t1), t2)],
398
+ 'Tfuncs': [log, Lambda(i, log(log(i)))]})
399
+ assert integrate_primitive(Poly(t2, t2), Poly(t1, t2), DE) == \
400
+ (0, NonElementaryIntegral(log(log(x))/log(x), x), False)
401
+
402
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t0)],
403
+ 'Tfuncs': [log]})
404
+ assert integrate_primitive(Poly(x**2*t0**3 + (3*x**2 + x)*t0**2 + (3*x**2
405
+ + 2*x)*t0 + x**2 + x, t0), Poly(x**2*t0**4 + 4*x**2*t0**3 + 6*x**2*t0**2 +
406
+ 4*x**2*t0 + x**2, t0), DE) == \
407
+ (-1/(log(x) + 1), NonElementaryIntegral(1/(log(x) + 1), x), False)
408
+
409
+ def test_integrate_hypertangent_polynomial():
410
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]})
411
+ assert integrate_hypertangent_polynomial(Poly(t**2 + x*t + 1, t), DE) == \
412
+ (Poly(t, t), Poly(x/2, t))
413
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(a*(t**2 + 1), t)]})
414
+ assert integrate_hypertangent_polynomial(Poly(t**5, t), DE) == \
415
+ (Poly(1/(4*a)*t**4 - 1/(2*a)*t**2, t), Poly(1/(2*a), t))
416
+
417
+
418
+ def test_integrate_nonlinear_no_specials():
419
+ a, d, = Poly(x**2*t**5 + x*t**4 - nu**2*t**3 - x*(x**2 + 1)*t**2 - (x**2 -
420
+ nu**2)*t - x**5/4, t), Poly(x**2*t**4 + x**2*(x**2 + 2)*t**2 + x**2 + x**4 + x**6/4, t)
421
+ # f(x) == phi_nu(x), the logarithmic derivative of J_v, the Bessel function,
422
+ # which has no specials (see Chapter 5, note 4 of Bronstein's book).
423
+ f = Function('phi_nu')
424
+ DE = DifferentialExtension(extension={'D': [Poly(1, x),
425
+ Poly(-t**2 - t/x - (1 - nu**2/x**2), t)], 'Tfuncs': [f]})
426
+ assert integrate_nonlinear_no_specials(a, d, DE) == \
427
+ (-log(1 + f(x)**2 + x**2/2)/2 + (- 4 - x**2)/(4 + 2*x**2 + 4*f(x)**2), True)
428
+ assert integrate_nonlinear_no_specials(Poly(t, t), Poly(1, t), DE) == \
429
+ (0, False)
430
+
431
+
432
+ def test_integer_powers():
433
+ assert integer_powers([x, x/2, x**2 + 1, x*Rational(2, 3)]) == [
434
+ (x/6, [(x, 6), (x/2, 3), (x*Rational(2, 3), 4)]),
435
+ (1 + x**2, [(1 + x**2, 1)])]
436
+
437
+
438
+ def test_DifferentialExtension_exp():
439
+ assert DifferentialExtension(exp(x) + exp(x**2), x)._important_attrs == \
440
+ (Poly(t1 + t0, t1), Poly(1, t1), [Poly(1, x,), Poly(t0, t0),
441
+ Poly(2*x*t1, t1)], [x, t0, t1], [Lambda(i, exp(i)),
442
+ Lambda(i, exp(i**2))], [], [None, 'exp', 'exp'], [None, x, x**2])
443
+ assert DifferentialExtension(exp(x) + exp(2*x), x)._important_attrs == \
444
+ (Poly(t0**2 + t0, t0), Poly(1, t0), [Poly(1, x), Poly(t0, t0)], [x, t0],
445
+ [Lambda(i, exp(i))], [], [None, 'exp'], [None, x])
446
+ assert DifferentialExtension(exp(x) + exp(x/2), x)._important_attrs == \
447
+ (Poly(t0**2 + t0, t0), Poly(1, t0), [Poly(1, x), Poly(t0/2, t0)],
448
+ [x, t0], [Lambda(i, exp(i/2))], [], [None, 'exp'], [None, x/2])
449
+ assert DifferentialExtension(exp(x) + exp(x**2) + exp(x + x**2), x)._important_attrs == \
450
+ (Poly((1 + t0)*t1 + t0, t1), Poly(1, t1), [Poly(1, x), Poly(t0, t0),
451
+ Poly(2*x*t1, t1)], [x, t0, t1], [Lambda(i, exp(i)),
452
+ Lambda(i, exp(i**2))], [], [None, 'exp', 'exp'], [None, x, x**2])
453
+ assert DifferentialExtension(exp(x) + exp(x**2) + exp(x + x**2 + 1), x)._important_attrs == \
454
+ (Poly((1 + S.Exp1*t0)*t1 + t0, t1), Poly(1, t1), [Poly(1, x),
455
+ Poly(t0, t0), Poly(2*x*t1, t1)], [x, t0, t1], [Lambda(i, exp(i)),
456
+ Lambda(i, exp(i**2))], [], [None, 'exp', 'exp'], [None, x, x**2])
457
+ assert DifferentialExtension(exp(x) + exp(x**2) + exp(x/2 + x**2), x)._important_attrs == \
458
+ (Poly((t0 + 1)*t1 + t0**2, t1), Poly(1, t1), [Poly(1, x),
459
+ Poly(t0/2, t0), Poly(2*x*t1, t1)], [x, t0, t1],
460
+ [Lambda(i, exp(i/2)), Lambda(i, exp(i**2))],
461
+ [(exp(x/2), sqrt(exp(x)))], [None, 'exp', 'exp'], [None, x/2, x**2])
462
+ assert DifferentialExtension(exp(x) + exp(x**2) + exp(x/2 + x**2 + 3), x)._important_attrs == \
463
+ (Poly((t0*exp(3) + 1)*t1 + t0**2, t1), Poly(1, t1), [Poly(1, x),
464
+ Poly(t0/2, t0), Poly(2*x*t1, t1)], [x, t0, t1], [Lambda(i, exp(i/2)),
465
+ Lambda(i, exp(i**2))], [(exp(x/2), sqrt(exp(x)))], [None, 'exp', 'exp'],
466
+ [None, x/2, x**2])
467
+ assert DifferentialExtension(sqrt(exp(x)), x)._important_attrs == \
468
+ (Poly(t0, t0), Poly(1, t0), [Poly(1, x), Poly(t0/2, t0)], [x, t0],
469
+ [Lambda(i, exp(i/2))], [(exp(x/2), sqrt(exp(x)))], [None, 'exp'], [None, x/2])
470
+
471
+ assert DifferentialExtension(exp(x/2), x)._important_attrs == \
472
+ (Poly(t0, t0), Poly(1, t0), [Poly(1, x), Poly(t0/2, t0)], [x, t0],
473
+ [Lambda(i, exp(i/2))], [], [None, 'exp'], [None, x/2])
474
+
475
+
476
+ def test_DifferentialExtension_log():
477
+ assert DifferentialExtension(log(x)*log(x + 1)*log(2*x**2 + 2*x), x)._important_attrs == \
478
+ (Poly(t0*t1**2 + (t0*log(2) + t0**2)*t1, t1), Poly(1, t1),
479
+ [Poly(1, x), Poly(1/x, t0),
480
+ Poly(1/(x + 1), t1, expand=False)], [x, t0, t1],
481
+ [Lambda(i, log(i)), Lambda(i, log(i + 1))], [], [None, 'log', 'log'],
482
+ [None, x, x + 1])
483
+ assert DifferentialExtension(x**x*log(x), x)._important_attrs == \
484
+ (Poly(t0*t1, t1), Poly(1, t1), [Poly(1, x), Poly(1/x, t0),
485
+ Poly((1 + t0)*t1, t1)], [x, t0, t1], [Lambda(i, log(i)),
486
+ Lambda(i, exp(t0*i))], [(exp(x*log(x)), x**x)], [None, 'log', 'exp'],
487
+ [None, x, t0*x])
488
+
489
+
490
+ def test_DifferentialExtension_symlog():
491
+ # See comment on test_risch_integrate below
492
+ assert DifferentialExtension(log(x**x), x)._important_attrs == \
493
+ (Poly(t0*x, t1), Poly(1, t1), [Poly(1, x), Poly(1/x, t0), Poly((t0 +
494
+ 1)*t1, t1)], [x, t0, t1], [Lambda(i, log(i)), Lambda(i, exp(i*t0))],
495
+ [(exp(x*log(x)), x**x)], [None, 'log', 'exp'], [None, x, t0*x])
496
+ assert DifferentialExtension(log(x**y), x)._important_attrs == \
497
+ (Poly(y*t0, t0), Poly(1, t0), [Poly(1, x), Poly(1/x, t0)], [x, t0],
498
+ [Lambda(i, log(i))], [(y*log(x), log(x**y))], [None, 'log'],
499
+ [None, x])
500
+ assert DifferentialExtension(log(sqrt(x)), x)._important_attrs == \
501
+ (Poly(t0, t0), Poly(2, t0), [Poly(1, x), Poly(1/x, t0)], [x, t0],
502
+ [Lambda(i, log(i))], [(log(x)/2, log(sqrt(x)))], [None, 'log'],
503
+ [None, x])
504
+
505
+
506
+ def test_DifferentialExtension_handle_first():
507
+ assert DifferentialExtension(exp(x)*log(x), x, handle_first='log')._important_attrs == \
508
+ (Poly(t0*t1, t1), Poly(1, t1), [Poly(1, x), Poly(1/x, t0),
509
+ Poly(t1, t1)], [x, t0, t1], [Lambda(i, log(i)), Lambda(i, exp(i))],
510
+ [], [None, 'log', 'exp'], [None, x, x])
511
+ assert DifferentialExtension(exp(x)*log(x), x, handle_first='exp')._important_attrs == \
512
+ (Poly(t0*t1, t1), Poly(1, t1), [Poly(1, x), Poly(t0, t0),
513
+ Poly(1/x, t1)], [x, t0, t1], [Lambda(i, exp(i)), Lambda(i, log(i))],
514
+ [], [None, 'exp', 'log'], [None, x, x])
515
+
516
+ # This one must have the log first, regardless of what we set it to
517
+ # (because the log is inside of the exponential: x**x == exp(x*log(x)))
518
+ assert DifferentialExtension(-x**x*log(x)**2 + x**x - x**x/x, x,
519
+ handle_first='exp')._important_attrs == \
520
+ DifferentialExtension(-x**x*log(x)**2 + x**x - x**x/x, x,
521
+ handle_first='log')._important_attrs == \
522
+ (Poly((-1 + x - x*t0**2)*t1, t1), Poly(x, t1),
523
+ [Poly(1, x), Poly(1/x, t0), Poly((1 + t0)*t1, t1)], [x, t0, t1],
524
+ [Lambda(i, log(i)), Lambda(i, exp(t0*i))], [(exp(x*log(x)), x**x)],
525
+ [None, 'log', 'exp'], [None, x, t0*x])
526
+
527
+
528
+ def test_DifferentialExtension_all_attrs():
529
+ # Test 'unimportant' attributes
530
+ DE = DifferentialExtension(exp(x)*log(x), x, handle_first='exp')
531
+ assert DE.f == exp(x)*log(x)
532
+ assert DE.newf == t0*t1
533
+ assert DE.x == x
534
+ assert DE.cases == ['base', 'exp', 'primitive']
535
+ assert DE.case == 'primitive'
536
+
537
+ assert DE.level == -1
538
+ assert DE.t == t1 == DE.T[DE.level]
539
+ assert DE.d == Poly(1/x, t1) == DE.D[DE.level]
540
+ raises(ValueError, lambda: DE.increment_level())
541
+ DE.decrement_level()
542
+ assert DE.level == -2
543
+ assert DE.t == t0 == DE.T[DE.level]
544
+ assert DE.d == Poly(t0, t0) == DE.D[DE.level]
545
+ assert DE.case == 'exp'
546
+ DE.decrement_level()
547
+ assert DE.level == -3
548
+ assert DE.t == x == DE.T[DE.level] == DE.x
549
+ assert DE.d == Poly(1, x) == DE.D[DE.level]
550
+ assert DE.case == 'base'
551
+ raises(ValueError, lambda: DE.decrement_level())
552
+ DE.increment_level()
553
+ DE.increment_level()
554
+ assert DE.level == -1
555
+ assert DE.t == t1 == DE.T[DE.level]
556
+ assert DE.d == Poly(1/x, t1) == DE.D[DE.level]
557
+ assert DE.case == 'primitive'
558
+
559
+ # Test methods
560
+ assert DE.indices('log') == [2]
561
+ assert DE.indices('exp') == [1]
562
+
563
+
564
+ def test_DifferentialExtension_extension_flag():
565
+ raises(ValueError, lambda: DifferentialExtension(extension={'T': [x, t]}))
566
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]})
567
+ assert DE._important_attrs == (None, None, [Poly(1, x), Poly(t, t)], [x, t],
568
+ None, None, None, None)
569
+ assert DE.d == Poly(t, t)
570
+ assert DE.t == t
571
+ assert DE.level == -1
572
+ assert DE.cases == ['base', 'exp']
573
+ assert DE.x == x
574
+ assert DE.case == 'exp'
575
+
576
+ DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)],
577
+ 'exts': [None, 'exp'], 'extargs': [None, x]})
578
+ assert DE._important_attrs == (None, None, [Poly(1, x), Poly(t, t)], [x, t],
579
+ None, None, [None, 'exp'], [None, x])
580
+ raises(ValueError, lambda: DifferentialExtension())
581
+
582
+
583
+ def test_DifferentialExtension_misc():
584
+ # Odd ends
585
+ assert DifferentialExtension(sin(y)*exp(x), x)._important_attrs == \
586
+ (Poly(sin(y)*t0, t0, domain='ZZ[sin(y)]'), Poly(1, t0, domain='ZZ'),
587
+ [Poly(1, x, domain='ZZ'), Poly(t0, t0, domain='ZZ')], [x, t0],
588
+ [Lambda(i, exp(i))], [], [None, 'exp'], [None, x])
589
+ raises(NotImplementedError, lambda: DifferentialExtension(sin(x), x))
590
+ assert DifferentialExtension(10**x, x)._important_attrs == \
591
+ (Poly(t0, t0), Poly(1, t0), [Poly(1, x), Poly(log(10)*t0, t0)], [x, t0],
592
+ [Lambda(i, exp(i*log(10)))], [(exp(x*log(10)), 10**x)], [None, 'exp'],
593
+ [None, x*log(10)])
594
+ assert DifferentialExtension(log(x) + log(x**2), x)._important_attrs in [
595
+ (Poly(3*t0, t0), Poly(2, t0), [Poly(1, x), Poly(2/x, t0)], [x, t0],
596
+ [Lambda(i, log(i**2))], [], [None, ], [], [1], [x**2]),
597
+ (Poly(3*t0, t0), Poly(1, t0), [Poly(1, x), Poly(1/x, t0)], [x, t0],
598
+ [Lambda(i, log(i))], [], [None, 'log'], [None, x])]
599
+ assert DifferentialExtension(S.Zero, x)._important_attrs == \
600
+ (Poly(0, x), Poly(1, x), [Poly(1, x)], [x], [], [], [None], [None])
601
+ assert DifferentialExtension(tan(atan(x).rewrite(log)), x)._important_attrs == \
602
+ (Poly(x, x), Poly(1, x), [Poly(1, x)], [x], [], [], [None], [None])
603
+
604
+
605
+ def test_DifferentialExtension_Rothstein():
606
+ # Rothstein's integral
607
+ f = (2581284541*exp(x) + 1757211400)/(39916800*exp(3*x) +
608
+ 119750400*exp(x)**2 + 119750400*exp(x) + 39916800)*exp(1/(exp(x) + 1) - 10*x)
609
+ assert DifferentialExtension(f, x)._important_attrs == \
610
+ (Poly((1757211400 + 2581284541*t0)*t1, t1), Poly(39916800 +
611
+ 119750400*t0 + 119750400*t0**2 + 39916800*t0**3, t1),
612
+ [Poly(1, x), Poly(t0, t0), Poly(-(10 + 21*t0 + 10*t0**2)/(1 + 2*t0 +
613
+ t0**2)*t1, t1, domain='ZZ(t0)')], [x, t0, t1],
614
+ [Lambda(i, exp(i)), Lambda(i, exp(1/(t0 + 1) - 10*i))], [],
615
+ [None, 'exp', 'exp'], [None, x, 1/(t0 + 1) - 10*x])
616
+
617
+
618
+ class _TestingException(Exception):
619
+ """Dummy Exception class for testing."""
620
+ pass
621
+
622
+
623
+ def test_DecrementLevel():
624
+ DE = DifferentialExtension(x*log(exp(x) + 1), x)
625
+ assert DE.level == -1
626
+ assert DE.t == t1
627
+ assert DE.d == Poly(t0/(t0 + 1), t1)
628
+ assert DE.case == 'primitive'
629
+
630
+ with DecrementLevel(DE):
631
+ assert DE.level == -2
632
+ assert DE.t == t0
633
+ assert DE.d == Poly(t0, t0)
634
+ assert DE.case == 'exp'
635
+
636
+ with DecrementLevel(DE):
637
+ assert DE.level == -3
638
+ assert DE.t == x
639
+ assert DE.d == Poly(1, x)
640
+ assert DE.case == 'base'
641
+
642
+ assert DE.level == -2
643
+ assert DE.t == t0
644
+ assert DE.d == Poly(t0, t0)
645
+ assert DE.case == 'exp'
646
+
647
+ assert DE.level == -1
648
+ assert DE.t == t1
649
+ assert DE.d == Poly(t0/(t0 + 1), t1)
650
+ assert DE.case == 'primitive'
651
+
652
+ # Test that __exit__ is called after an exception correctly
653
+ try:
654
+ with DecrementLevel(DE):
655
+ raise _TestingException
656
+ except _TestingException:
657
+ pass
658
+ else:
659
+ raise AssertionError("Did not raise.")
660
+
661
+ assert DE.level == -1
662
+ assert DE.t == t1
663
+ assert DE.d == Poly(t0/(t0 + 1), t1)
664
+ assert DE.case == 'primitive'
665
+
666
+
667
+ def test_risch_integrate():
668
+ assert risch_integrate(t0*exp(x), x) == t0*exp(x)
669
+ assert risch_integrate(sin(x), x, rewrite_complex=True) == -exp(I*x)/2 - exp(-I*x)/2
670
+
671
+ # From my GSoC writeup
672
+ assert risch_integrate((1 + 2*x**2 + x**4 + 2*x**3*exp(2*x**2))/
673
+ (x**4*exp(x**2) + 2*x**2*exp(x**2) + exp(x**2)), x) == \
674
+ NonElementaryIntegral(exp(-x**2), x) + exp(x**2)/(1 + x**2)
675
+
676
+
677
+ assert risch_integrate(0, x) == 0
678
+
679
+ # also tests prde_cancel()
680
+ e1 = log(x/exp(x) + 1)
681
+ ans1 = risch_integrate(e1, x)
682
+ assert ans1 == (x*log(x*exp(-x) + 1) + NonElementaryIntegral((x**2 - x)/(x + exp(x)), x))
683
+ assert cancel(diff(ans1, x) - e1) == 0
684
+
685
+ # also tests issue #10798
686
+ e2 = (log(-1/y)/2 - log(1/y)/2)/y - (log(1 - 1/y)/2 - log(1 + 1/y)/2)/y
687
+ ans2 = risch_integrate(e2, y)
688
+ assert ans2 == log(1/y)*log(1 - 1/y)/2 - log(1/y)*log(1 + 1/y)/2 + \
689
+ NonElementaryIntegral((I*pi*y**2 - 2*y*log(1/y) - I*pi)/(2*y**3 - 2*y), y)
690
+ assert expand_log(cancel(diff(ans2, y) - e2), force=True) == 0
691
+
692
+ # These are tested here in addition to in test_DifferentialExtension above
693
+ # (symlogs) to test that backsubs works correctly. The integrals should be
694
+ # written in terms of the original logarithms in the integrands.
695
+
696
+ # XXX: Unfortunately, making backsubs work on this one is a little
697
+ # trickier, because x**x is converted to exp(x*log(x)), and so log(x**x)
698
+ # is converted to x*log(x). (x**2*log(x)).subs(x*log(x), log(x**x)) is
699
+ # smart enough, the issue is that these splits happen at different places
700
+ # in the algorithm. Maybe a heuristic is in order
701
+ assert risch_integrate(log(x**x), x) == x**2*log(x)/2 - x**2/4
702
+
703
+ assert risch_integrate(log(x**y), x) == x*log(x**y) - x*y
704
+ assert risch_integrate(log(sqrt(x)), x) == x*log(sqrt(x)) - x/2
705
+
706
+
707
+ def test_risch_integrate_float():
708
+ assert risch_integrate((-60*exp(x) - 19.2*exp(4*x))*exp(4*x), x) == -2.4*exp(8*x) - 12.0*exp(5*x)
709
+
710
+
711
+ def test_NonElementaryIntegral():
712
+ assert isinstance(risch_integrate(exp(x**2), x), NonElementaryIntegral)
713
+ assert isinstance(risch_integrate(x**x*log(x), x), NonElementaryIntegral)
714
+ # Make sure methods of Integral still give back a NonElementaryIntegral
715
+ assert isinstance(NonElementaryIntegral(x**x*t0, x).subs(t0, log(x)), NonElementaryIntegral)
716
+
717
+
718
+ def test_xtothex():
719
+ a = risch_integrate(x**x, x)
720
+ assert a == NonElementaryIntegral(x**x, x)
721
+ assert isinstance(a, NonElementaryIntegral)
722
+
723
+
724
+ def test_DifferentialExtension_equality():
725
+ DE1 = DE2 = DifferentialExtension(log(x), x)
726
+ assert DE1 == DE2
727
+
728
+
729
+ def test_DifferentialExtension_printing():
730
+ DE = DifferentialExtension(exp(2*x**2) + log(exp(x**2) + 1), x)
731
+ assert repr(DE) == ("DifferentialExtension(dict([('f', exp(2*x**2) + log(exp(x**2) + 1)), "
732
+ "('x', x), ('T', [x, t0, t1]), ('D', [Poly(1, x, domain='ZZ'), Poly(2*x*t0, t0, domain='ZZ[x]'), "
733
+ "Poly(2*t0*x/(t0 + 1), t1, domain='ZZ(x,t0)')]), ('fa', Poly(t1 + t0**2, t1, domain='ZZ[t0]')), "
734
+ "('fd', Poly(1, t1, domain='ZZ')), ('Tfuncs', [Lambda(i, exp(i**2)), Lambda(i, log(t0 + 1))]), "
735
+ "('backsubs', []), ('exts', [None, 'exp', 'log']), ('extargs', [None, x**2, t0 + 1]), "
736
+ "('cases', ['base', 'exp', 'primitive']), ('case', 'primitive'), ('t', t1), "
737
+ "('d', Poly(2*t0*x/(t0 + 1), t1, domain='ZZ(x,t0)')), ('newf', t0**2 + t1), ('level', -1), "
738
+ "('dummy', False)]))")
739
+
740
+ assert str(DE) == ("DifferentialExtension({fa=Poly(t1 + t0**2, t1, domain='ZZ[t0]'), "
741
+ "fd=Poly(1, t1, domain='ZZ'), D=[Poly(1, x, domain='ZZ'), Poly(2*x*t0, t0, domain='ZZ[x]'), "
742
+ "Poly(2*t0*x/(t0 + 1), t1, domain='ZZ(x,t0)')]})")
743
+
744
+
745
+ def test_issue_23948():
746
+ f = (
747
+ ( (-2*x**5 + 28*x**4 - 144*x**3 + 324*x**2 - 270*x)*log(x)**2
748
+ +(-4*x**6 + 56*x**5 - 288*x**4 + 648*x**3 - 540*x**2)*log(x)
749
+ +(2*x**5 - 28*x**4 + 144*x**3 - 324*x**2 + 270*x)*exp(x)
750
+ +(2*x**5 - 28*x**4 + 144*x**3 - 324*x**2 + 270*x)*log(5)
751
+ -2*x**7 + 26*x**6 - 116*x**5 + 180*x**4 + 54*x**3 - 270*x**2
752
+ )*log(-log(x)**2 - 2*x*log(x) + exp(x) + log(5) - x**2 - x)**2
753
+ +( (4*x**5 - 44*x**4 + 168*x**3 - 216*x**2 - 108*x + 324)*log(x)
754
+ +(-2*x**5 + 24*x**4 - 108*x**3 + 216*x**2 - 162*x)*exp(x)
755
+ +4*x**6 - 42*x**5 + 144*x**4 - 108*x**3 - 324*x**2 + 486*x
756
+ )*log(-log(x)**2 - 2*x*log(x) + exp(x) + log(5) - x**2 - x)
757
+ )/(x*exp(x)**2*log(x)**2 + 2*x**2*exp(x)**2*log(x) - x*exp(x)**3
758
+ +(-x*log(5) + x**3 + x**2)*exp(x)**2)
759
+
760
+ F = ((x**4 - 12*x**3 + 54*x**2 - 108*x + 81)*exp(-2*x)
761
+ *log(-x**2 - 2*x*log(x) - x + exp(x) - log(x)**2 + log(5))**2)
762
+
763
+ assert risch_integrate(f, x) == F
.venv/lib/python3.13/site-packages/sympy/integrals/tests/test_singularityfunctions.py ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.integrals.singularityfunctions import singularityintegrate
2
+ from sympy.core.function import Function
3
+ from sympy.core.symbol import symbols
4
+ from sympy.functions.special.singularity_functions import SingularityFunction
5
+
6
+ x, a, n, y = symbols('x a n y')
7
+ f = Function('f')
8
+
9
+
10
+ def test_singularityintegrate():
11
+ assert singularityintegrate(x, x) is None
12
+ assert singularityintegrate(x + SingularityFunction(x, 9, 1), x) is None
13
+
14
+ assert 4*singularityintegrate(SingularityFunction(x, a, 3), x) == 4*SingularityFunction(x, a, 4)/4
15
+ assert singularityintegrate(5*SingularityFunction(x, 5, -2), x) == 5*SingularityFunction(x, 5, -1)
16
+ assert singularityintegrate(6*SingularityFunction(x, 5, -1), x) == 6*SingularityFunction(x, 5, 0)
17
+ assert singularityintegrate(x*SingularityFunction(x, 0, -1), x) == 0
18
+ assert singularityintegrate((x - 5)*SingularityFunction(x, 5, -1), x) == 0
19
+ assert singularityintegrate(SingularityFunction(x, 0, -1) * f(x), x) == f(0) * SingularityFunction(x, 0, 0)
20
+ assert singularityintegrate(SingularityFunction(x, 1, -1) * f(x), x) == f(1) * SingularityFunction(x, 1, 0)
21
+ assert singularityintegrate(y*SingularityFunction(x, 0, -1)**2, x) == \
22
+ y*SingularityFunction(0, 0, -1)*SingularityFunction(x, 0, 0)
.venv/lib/python3.13/site-packages/sympy/integrals/tests/test_transforms.py ADDED
@@ -0,0 +1,637 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.integrals.transforms import (
2
+ mellin_transform, inverse_mellin_transform,
3
+ fourier_transform, inverse_fourier_transform,
4
+ sine_transform, inverse_sine_transform,
5
+ cosine_transform, inverse_cosine_transform,
6
+ hankel_transform, inverse_hankel_transform,
7
+ FourierTransform, SineTransform, CosineTransform, InverseFourierTransform,
8
+ InverseSineTransform, InverseCosineTransform, IntegralTransformError)
9
+ from sympy.integrals.laplace import (
10
+ laplace_transform, inverse_laplace_transform)
11
+ from sympy.core.function import Function, expand_mul
12
+ from sympy.core import EulerGamma
13
+ from sympy.core.numbers import I, Rational, oo, pi
14
+ from sympy.core.singleton import S
15
+ from sympy.core.symbol import Symbol, symbols
16
+ from sympy.functions.combinatorial.factorials import factorial
17
+ from sympy.functions.elementary.complexes import re, unpolarify
18
+ from sympy.functions.elementary.exponential import exp, exp_polar, log
19
+ from sympy.functions.elementary.miscellaneous import sqrt
20
+ from sympy.functions.elementary.trigonometric import atan, cos, sin, tan
21
+ from sympy.functions.special.bessel import besseli, besselj, besselk, bessely
22
+ from sympy.functions.special.delta_functions import Heaviside
23
+ from sympy.functions.special.error_functions import erf, expint
24
+ from sympy.functions.special.gamma_functions import gamma
25
+ from sympy.functions.special.hyper import meijerg
26
+ from sympy.simplify.gammasimp import gammasimp
27
+ from sympy.simplify.hyperexpand import hyperexpand
28
+ from sympy.simplify.trigsimp import trigsimp
29
+ from sympy.testing.pytest import XFAIL, slow, skip, raises
30
+ from sympy.abc import x, s, a, b, c, d
31
+
32
+
33
+ nu, beta, rho = symbols('nu beta rho')
34
+
35
+
36
+ def test_undefined_function():
37
+ from sympy.integrals.transforms import MellinTransform
38
+ f = Function('f')
39
+ assert mellin_transform(f(x), x, s) == MellinTransform(f(x), x, s)
40
+ assert mellin_transform(f(x) + exp(-x), x, s) == \
41
+ (MellinTransform(f(x), x, s) + gamma(s + 1)/s, (0, oo), True)
42
+
43
+
44
+ def test_free_symbols():
45
+ f = Function('f')
46
+ assert mellin_transform(f(x), x, s).free_symbols == {s}
47
+ assert mellin_transform(f(x)*a, x, s).free_symbols == {s, a}
48
+
49
+
50
+ def test_as_integral():
51
+ from sympy.integrals.integrals import Integral
52
+ f = Function('f')
53
+ assert mellin_transform(f(x), x, s).rewrite('Integral') == \
54
+ Integral(x**(s - 1)*f(x), (x, 0, oo))
55
+ assert fourier_transform(f(x), x, s).rewrite('Integral') == \
56
+ Integral(f(x)*exp(-2*I*pi*s*x), (x, -oo, oo))
57
+ assert laplace_transform(f(x), x, s, noconds=True).rewrite('Integral') == \
58
+ Integral(f(x)*exp(-s*x), (x, 0, oo))
59
+ assert str(2*pi*I*inverse_mellin_transform(f(s), s, x, (a, b)).rewrite('Integral')) \
60
+ == "Integral(f(s)/x**s, (s, _c - oo*I, _c + oo*I))"
61
+ assert str(2*pi*I*inverse_laplace_transform(f(s), s, x).rewrite('Integral')) == \
62
+ "Integral(f(s)*exp(s*x), (s, _c - oo*I, _c + oo*I))"
63
+ assert inverse_fourier_transform(f(s), s, x).rewrite('Integral') == \
64
+ Integral(f(s)*exp(2*I*pi*s*x), (s, -oo, oo))
65
+
66
+ # NOTE this is stuck in risch because meijerint cannot handle it
67
+
68
+
69
+ @slow
70
+ @XFAIL
71
+ def test_mellin_transform_fail():
72
+ skip("Risch takes forever.")
73
+
74
+ MT = mellin_transform
75
+
76
+ bpos = symbols('b', positive=True)
77
+ # bneg = symbols('b', negative=True)
78
+
79
+ expr = (sqrt(x + b**2) + b)**a/sqrt(x + b**2)
80
+ # TODO does not work with bneg, argument wrong. Needs changes to matching.
81
+ assert MT(expr.subs(b, -bpos), x, s) == \
82
+ ((-1)**(a + 1)*2**(a + 2*s)*bpos**(a + 2*s - 1)*gamma(a + s)
83
+ *gamma(1 - a - 2*s)/gamma(1 - s),
84
+ (-re(a), -re(a)/2 + S.Half), True)
85
+
86
+ expr = (sqrt(x + b**2) + b)**a
87
+ assert MT(expr.subs(b, -bpos), x, s) == \
88
+ (
89
+ 2**(a + 2*s)*a*bpos**(a + 2*s)*gamma(-a - 2*
90
+ s)*gamma(a + s)/gamma(-s + 1),
91
+ (-re(a), -re(a)/2), True)
92
+
93
+ # Test exponent 1:
94
+ assert MT(expr.subs({b: -bpos, a: 1}), x, s) == \
95
+ (-bpos**(2*s + 1)*gamma(s)*gamma(-s - S.Half)/(2*sqrt(pi)),
96
+ (-1, Rational(-1, 2)), True)
97
+
98
+
99
+ def test_mellin_transform():
100
+ from sympy.functions.elementary.miscellaneous import (Max, Min)
101
+ MT = mellin_transform
102
+
103
+ bpos = symbols('b', positive=True)
104
+
105
+ # 8.4.2
106
+ assert MT(x**nu*Heaviside(x - 1), x, s) == \
107
+ (-1/(nu + s), (-oo, -re(nu)), True)
108
+ assert MT(x**nu*Heaviside(1 - x), x, s) == \
109
+ (1/(nu + s), (-re(nu), oo), True)
110
+
111
+ assert MT((1 - x)**(beta - 1)*Heaviside(1 - x), x, s) == \
112
+ (gamma(beta)*gamma(s)/gamma(beta + s), (0, oo), re(beta) > 0)
113
+ assert MT((x - 1)**(beta - 1)*Heaviside(x - 1), x, s) == \
114
+ (gamma(beta)*gamma(1 - beta - s)/gamma(1 - s),
115
+ (-oo, 1 - re(beta)), re(beta) > 0)
116
+
117
+ assert MT((1 + x)**(-rho), x, s) == \
118
+ (gamma(s)*gamma(rho - s)/gamma(rho), (0, re(rho)), True)
119
+
120
+ assert MT(abs(1 - x)**(-rho), x, s) == (
121
+ 2*sin(pi*rho/2)*gamma(1 - rho)*
122
+ cos(pi*(s - rho/2))*gamma(s)*gamma(rho-s)/pi,
123
+ (0, re(rho)), re(rho) < 1)
124
+ mt = MT((1 - x)**(beta - 1)*Heaviside(1 - x)
125
+ + a*(x - 1)**(beta - 1)*Heaviside(x - 1), x, s)
126
+ assert mt[1], mt[2] == ((0, -re(beta) + 1), re(beta) > 0)
127
+
128
+ assert MT((x**a - b**a)/(x - b), x, s)[0] == \
129
+ pi*b**(a + s - 1)*sin(pi*a)/(sin(pi*s)*sin(pi*(a + s)))
130
+ assert MT((x**a - bpos**a)/(x - bpos), x, s) == \
131
+ (pi*bpos**(a + s - 1)*sin(pi*a)/(sin(pi*s)*sin(pi*(a + s))),
132
+ (Max(0, -re(a)), Min(1, 1 - re(a))), True)
133
+
134
+ expr = (sqrt(x + b**2) + b)**a
135
+ assert MT(expr.subs(b, bpos), x, s) == \
136
+ (-a*(2*bpos)**(a + 2*s)*gamma(s)*gamma(-a - 2*s)/gamma(-a - s + 1),
137
+ (0, -re(a)/2), True)
138
+
139
+ expr = (sqrt(x + b**2) + b)**a/sqrt(x + b**2)
140
+ assert MT(expr.subs(b, bpos), x, s) == \
141
+ (2**(a + 2*s)*bpos**(a + 2*s - 1)*gamma(s)
142
+ *gamma(1 - a - 2*s)/gamma(1 - a - s),
143
+ (0, -re(a)/2 + S.Half), True)
144
+
145
+ # 8.4.2
146
+ assert MT(exp(-x), x, s) == (gamma(s), (0, oo), True)
147
+ assert MT(exp(-1/x), x, s) == (gamma(-s), (-oo, 0), True)
148
+
149
+ # 8.4.5
150
+ assert MT(log(x)**4*Heaviside(1 - x), x, s) == (24/s**5, (0, oo), True)
151
+ assert MT(log(x)**3*Heaviside(x - 1), x, s) == (6/s**4, (-oo, 0), True)
152
+ assert MT(log(x + 1), x, s) == (pi/(s*sin(pi*s)), (-1, 0), True)
153
+ assert MT(log(1/x + 1), x, s) == (pi/(s*sin(pi*s)), (0, 1), True)
154
+ assert MT(log(abs(1 - x)), x, s) == (pi/(s*tan(pi*s)), (-1, 0), True)
155
+ assert MT(log(abs(1 - 1/x)), x, s) == (pi/(s*tan(pi*s)), (0, 1), True)
156
+
157
+ # 8.4.14
158
+ assert MT(erf(sqrt(x)), x, s) == \
159
+ (-gamma(s + S.Half)/(sqrt(pi)*s), (Rational(-1, 2), 0), True)
160
+
161
+
162
+ def test_mellin_transform2():
163
+ MT = mellin_transform
164
+ # TODO we cannot currently do these (needs summation of 3F2(-1))
165
+ # this also implies that they cannot be written as a single g-function
166
+ # (although this is possible)
167
+ mt = MT(log(x)/(x + 1), x, s)
168
+ assert mt[1:] == ((0, 1), True)
169
+ assert not hyperexpand(mt[0], allow_hyper=True).has(meijerg)
170
+ mt = MT(log(x)**2/(x + 1), x, s)
171
+ assert mt[1:] == ((0, 1), True)
172
+ assert not hyperexpand(mt[0], allow_hyper=True).has(meijerg)
173
+ mt = MT(log(x)/(x + 1)**2, x, s)
174
+ assert mt[1:] == ((0, 2), True)
175
+ assert not hyperexpand(mt[0], allow_hyper=True).has(meijerg)
176
+
177
+
178
+ @slow
179
+ def test_mellin_transform_bessel():
180
+ from sympy.functions.elementary.miscellaneous import Max
181
+ MT = mellin_transform
182
+
183
+ # 8.4.19
184
+ assert MT(besselj(a, 2*sqrt(x)), x, s) == \
185
+ (gamma(a/2 + s)/gamma(a/2 - s + 1), (-re(a)/2, Rational(3, 4)), True)
186
+ assert MT(sin(sqrt(x))*besselj(a, sqrt(x)), x, s) == \
187
+ (2**a*gamma(-2*s + S.Half)*gamma(a/2 + s + S.Half)/(
188
+ gamma(-a/2 - s + 1)*gamma(a - 2*s + 1)), (
189
+ -re(a)/2 - S.Half, Rational(1, 4)), True)
190
+ assert MT(cos(sqrt(x))*besselj(a, sqrt(x)), x, s) == \
191
+ (2**a*gamma(a/2 + s)*gamma(-2*s + S.Half)/(
192
+ gamma(-a/2 - s + S.Half)*gamma(a - 2*s + 1)), (
193
+ -re(a)/2, Rational(1, 4)), True)
194
+ assert MT(besselj(a, sqrt(x))**2, x, s) == \
195
+ (gamma(a + s)*gamma(S.Half - s)
196
+ / (sqrt(pi)*gamma(1 - s)*gamma(1 + a - s)),
197
+ (-re(a), S.Half), True)
198
+ assert MT(besselj(a, sqrt(x))*besselj(-a, sqrt(x)), x, s) == \
199
+ (gamma(s)*gamma(S.Half - s)
200
+ / (sqrt(pi)*gamma(1 - a - s)*gamma(1 + a - s)),
201
+ (0, S.Half), True)
202
+ # NOTE: prudnikov gives the strip below as (1/2 - re(a), 1). As far as
203
+ # I can see this is wrong (since besselj(z) ~ 1/sqrt(z) for z large)
204
+ assert MT(besselj(a - 1, sqrt(x))*besselj(a, sqrt(x)), x, s) == \
205
+ (gamma(1 - s)*gamma(a + s - S.Half)
206
+ / (sqrt(pi)*gamma(Rational(3, 2) - s)*gamma(a - s + S.Half)),
207
+ (S.Half - re(a), S.Half), True)
208
+ assert MT(besselj(a, sqrt(x))*besselj(b, sqrt(x)), x, s) == \
209
+ (4**s*gamma(1 - 2*s)*gamma((a + b)/2 + s)
210
+ / (gamma(1 - s + (b - a)/2)*gamma(1 - s + (a - b)/2)
211
+ *gamma( 1 - s + (a + b)/2)),
212
+ (-(re(a) + re(b))/2, S.Half), True)
213
+ assert MT(besselj(a, sqrt(x))**2 + besselj(-a, sqrt(x))**2, x, s)[1:] == \
214
+ ((Max(re(a), -re(a)), S.Half), True)
215
+
216
+ # Section 8.4.20
217
+ assert MT(bessely(a, 2*sqrt(x)), x, s) == \
218
+ (-cos(pi*(a/2 - s))*gamma(s - a/2)*gamma(s + a/2)/pi,
219
+ (Max(-re(a)/2, re(a)/2), Rational(3, 4)), True)
220
+ assert MT(sin(sqrt(x))*bessely(a, sqrt(x)), x, s) == \
221
+ (-4**s*sin(pi*(a/2 - s))*gamma(S.Half - 2*s)
222
+ * gamma((1 - a)/2 + s)*gamma((1 + a)/2 + s)
223
+ / (sqrt(pi)*gamma(1 - s - a/2)*gamma(1 - s + a/2)),
224
+ (Max(-(re(a) + 1)/2, (re(a) - 1)/2), Rational(1, 4)), True)
225
+ assert MT(cos(sqrt(x))*bessely(a, sqrt(x)), x, s) == \
226
+ (-4**s*cos(pi*(a/2 - s))*gamma(s - a/2)*gamma(s + a/2)*gamma(S.Half - 2*s)
227
+ / (sqrt(pi)*gamma(S.Half - s - a/2)*gamma(S.Half - s + a/2)),
228
+ (Max(-re(a)/2, re(a)/2), Rational(1, 4)), True)
229
+ assert MT(besselj(a, sqrt(x))*bessely(a, sqrt(x)), x, s) == \
230
+ (-cos(pi*s)*gamma(s)*gamma(a + s)*gamma(S.Half - s)
231
+ / (pi**S('3/2')*gamma(1 + a - s)),
232
+ (Max(-re(a), 0), S.Half), True)
233
+ assert MT(besselj(a, sqrt(x))*bessely(b, sqrt(x)), x, s) == \
234
+ (-4**s*cos(pi*(a/2 - b/2 + s))*gamma(1 - 2*s)
235
+ * gamma(a/2 - b/2 + s)*gamma(a/2 + b/2 + s)
236
+ / (pi*gamma(a/2 - b/2 - s + 1)*gamma(a/2 + b/2 - s + 1)),
237
+ (Max((-re(a) + re(b))/2, (-re(a) - re(b))/2), S.Half), True)
238
+ # NOTE bessely(a, sqrt(x))**2 and bessely(a, sqrt(x))*bessely(b, sqrt(x))
239
+ # are a mess (no matter what way you look at it ...)
240
+ assert MT(bessely(a, sqrt(x))**2, x, s)[1:] == \
241
+ ((Max(-re(a), 0, re(a)), S.Half), True)
242
+
243
+ # Section 8.4.22
244
+ # TODO we can't do any of these (delicate cancellation)
245
+
246
+ # Section 8.4.23
247
+ assert MT(besselk(a, 2*sqrt(x)), x, s) == \
248
+ (gamma(
249
+ s - a/2)*gamma(s + a/2)/2, (Max(-re(a)/2, re(a)/2), oo), True)
250
+ assert MT(besselj(a, 2*sqrt(2*sqrt(x)))*besselk(
251
+ a, 2*sqrt(2*sqrt(x))), x, s) == (4**(-s)*gamma(2*s)*
252
+ gamma(a/2 + s)/(2*gamma(a/2 - s + 1)), (Max(0, -re(a)/2), oo), True)
253
+ # TODO bessely(a, x)*besselk(a, x) is a mess
254
+ assert MT(besseli(a, sqrt(x))*besselk(a, sqrt(x)), x, s) == \
255
+ (gamma(s)*gamma(
256
+ a + s)*gamma(-s + S.Half)/(2*sqrt(pi)*gamma(a - s + 1)),
257
+ (Max(-re(a), 0), S.Half), True)
258
+ assert MT(besseli(b, sqrt(x))*besselk(a, sqrt(x)), x, s) == \
259
+ (2**(2*s - 1)*gamma(-2*s + 1)*gamma(-a/2 + b/2 + s)* \
260
+ gamma(a/2 + b/2 + s)/(gamma(-a/2 + b/2 - s + 1)* \
261
+ gamma(a/2 + b/2 - s + 1)), (Max(-re(a)/2 - re(b)/2, \
262
+ re(a)/2 - re(b)/2), S.Half), True)
263
+
264
+ # TODO products of besselk are a mess
265
+
266
+ mt = MT(exp(-x/2)*besselk(a, x/2), x, s)
267
+ mt0 = gammasimp(trigsimp(gammasimp(mt[0].expand(func=True))))
268
+ assert mt0 == 2*pi**Rational(3, 2)*cos(pi*s)*gamma(S.Half - s)/(
269
+ (cos(2*pi*a) - cos(2*pi*s))*gamma(-a - s + 1)*gamma(a - s + 1))
270
+ assert mt[1:] == ((Max(-re(a), re(a)), oo), True)
271
+ # TODO exp(x/2)*besselk(a, x/2) [etc] cannot currently be done
272
+ # TODO various strange products of special orders
273
+
274
+
275
+ @slow
276
+ def test_expint():
277
+ from sympy.functions.elementary.miscellaneous import Max
278
+ from sympy.functions.special.error_functions import Ci, E1, Si
279
+ from sympy.simplify.simplify import simplify
280
+
281
+ aneg = Symbol('a', negative=True)
282
+ u = Symbol('u', polar=True)
283
+
284
+ assert mellin_transform(E1(x), x, s) == (gamma(s)/s, (0, oo), True)
285
+ assert inverse_mellin_transform(gamma(s)/s, s, x,
286
+ (0, oo)).rewrite(expint).expand() == E1(x)
287
+ assert mellin_transform(expint(a, x), x, s) == \
288
+ (gamma(s)/(a + s - 1), (Max(1 - re(a), 0), oo), True)
289
+ # XXX IMT has hickups with complicated strips ...
290
+ assert simplify(unpolarify(
291
+ inverse_mellin_transform(gamma(s)/(aneg + s - 1), s, x,
292
+ (1 - aneg, oo)).rewrite(expint).expand(func=True))) == \
293
+ expint(aneg, x)
294
+
295
+ assert mellin_transform(Si(x), x, s) == \
296
+ (-2**s*sqrt(pi)*gamma(s/2 + S.Half)/(
297
+ 2*s*gamma(-s/2 + 1)), (-1, 0), True)
298
+ assert inverse_mellin_transform(-2**s*sqrt(pi)*gamma((s + 1)/2)
299
+ /(2*s*gamma(-s/2 + 1)), s, x, (-1, 0)) \
300
+ == Si(x)
301
+
302
+ assert mellin_transform(Ci(sqrt(x)), x, s) == \
303
+ (-2**(2*s - 1)*sqrt(pi)*gamma(s)/(s*gamma(-s + S.Half)), (0, 1), True)
304
+ assert inverse_mellin_transform(
305
+ -4**s*sqrt(pi)*gamma(s)/(2*s*gamma(-s + S.Half)),
306
+ s, u, (0, 1)).expand() == Ci(sqrt(u))
307
+
308
+
309
+ @slow
310
+ def test_inverse_mellin_transform():
311
+ from sympy.core.function import expand
312
+ from sympy.functions.elementary.miscellaneous import (Max, Min)
313
+ from sympy.functions.elementary.trigonometric import cot
314
+ from sympy.simplify.powsimp import powsimp
315
+ from sympy.simplify.simplify import simplify
316
+ IMT = inverse_mellin_transform
317
+
318
+ assert IMT(gamma(s), s, x, (0, oo)) == exp(-x)
319
+ assert IMT(gamma(-s), s, x, (-oo, 0)) == exp(-1/x)
320
+ assert simplify(IMT(s/(2*s**2 - 2), s, x, (2, oo))) == \
321
+ (x**2 + 1)*Heaviside(1 - x)/(4*x)
322
+
323
+ # test passing "None"
324
+ assert IMT(1/(s**2 - 1), s, x, (-1, None)) == \
325
+ -x*Heaviside(-x + 1)/2 - Heaviside(x - 1)/(2*x)
326
+ assert IMT(1/(s**2 - 1), s, x, (None, 1)) == \
327
+ -x*Heaviside(-x + 1)/2 - Heaviside(x - 1)/(2*x)
328
+
329
+ # test expansion of sums
330
+ assert IMT(gamma(s) + gamma(s - 1), s, x, (1, oo)) == (x + 1)*exp(-x)/x
331
+
332
+ # test factorisation of polys
333
+ r = symbols('r', real=True)
334
+ assert IMT(1/(s**2 + 1), s, exp(-x), (None, oo)
335
+ ).subs(x, r).rewrite(sin).simplify() \
336
+ == sin(r)*Heaviside(1 - exp(-r))
337
+
338
+ # test multiplicative substitution
339
+ _a, _b = symbols('a b', positive=True)
340
+ assert IMT(_b**(-s/_a)*factorial(s/_a)/s, s, x, (0, oo)) == exp(-_b*x**_a)
341
+ assert IMT(factorial(_a/_b + s/_b)/(_a + s), s, x, (-_a, oo)) == x**_a*exp(-x**_b)
342
+
343
+ def simp_pows(expr):
344
+ return simplify(powsimp(expand_mul(expr, deep=False), force=True)).replace(exp_polar, exp)
345
+
346
+ # Now test the inverses of all direct transforms tested above
347
+
348
+ # Section 8.4.2
349
+ nu = symbols('nu', real=True)
350
+ assert IMT(-1/(nu + s), s, x, (-oo, None)) == x**nu*Heaviside(x - 1)
351
+ assert IMT(1/(nu + s), s, x, (None, oo)) == x**nu*Heaviside(1 - x)
352
+ assert simp_pows(IMT(gamma(beta)*gamma(s)/gamma(s + beta), s, x, (0, oo))) \
353
+ == (1 - x)**(beta - 1)*Heaviside(1 - x)
354
+ assert simp_pows(IMT(gamma(beta)*gamma(1 - beta - s)/gamma(1 - s),
355
+ s, x, (-oo, None))) \
356
+ == (x - 1)**(beta - 1)*Heaviside(x - 1)
357
+ assert simp_pows(IMT(gamma(s)*gamma(rho - s)/gamma(rho), s, x, (0, None))) \
358
+ == (1/(x + 1))**rho
359
+ expr = IMT(d**c*d**(s - 1)*sin(pi*c)
360
+ *gamma(s)*gamma(s + c)*gamma(1 - s)*gamma(1 - s - c)/pi,
361
+ s, x, (Max(-re(c), 0), Min(1 - re(c), 1)))
362
+ assert powsimp(expand_mul(expr, deep=False)).replace(exp_polar, exp).simplify() \
363
+ == (-d**c + x**c)/(-d + x)
364
+
365
+ assert simplify(IMT(1/sqrt(pi)*(-c/2)*gamma(s)*gamma((1 - c)/2 - s)
366
+ *gamma(-c/2 - s)/gamma(1 - c - s),
367
+ s, x, (0, -re(c)/2))) == \
368
+ (1 + sqrt(x + 1))**c
369
+ assert simplify(IMT(2**(a + 2*s)*b**(a + 2*s - 1)*gamma(s)*gamma(1 - a - 2*s)
370
+ /gamma(1 - a - s), s, x, (0, (-re(a) + 1)/2))) == \
371
+ b**(a - 1)*(b**2*(sqrt(1 + x/b**2) + 1)**a + x*(sqrt(1 + x/b**2) + 1
372
+ )**(a - 1))/(b**2 + x)
373
+ assert simplify(IMT(-2**(c + 2*s)*c*b**(c + 2*s)*gamma(s)*gamma(-c - 2*s)
374
+ / gamma(-c - s + 1), s, x, (0, -re(c)/2))) == \
375
+ b**c*(sqrt(1 + x/b**2) + 1)**c
376
+
377
+ # Section 8.4.5
378
+ assert IMT(24/s**5, s, x, (0, oo)) == log(x)**4*Heaviside(1 - x)
379
+ assert expand(IMT(6/s**4, s, x, (-oo, 0)), force=True) == \
380
+ log(x)**3*Heaviside(x - 1)
381
+ assert IMT(pi/(s*sin(pi*s)), s, x, (-1, 0)) == log(x + 1)
382
+ assert IMT(pi/(s*sin(pi*s/2)), s, x, (-2, 0)) == log(x**2 + 1)
383
+ assert IMT(pi/(s*sin(2*pi*s)), s, x, (Rational(-1, 2), 0)) == log(sqrt(x) + 1)
384
+ assert IMT(pi/(s*sin(pi*s)), s, x, (0, 1)) == log(1 + 1/x)
385
+
386
+ # TODO
387
+ def mysimp(expr):
388
+ from sympy.core.function import expand
389
+ from sympy.simplify.powsimp import powsimp
390
+ from sympy.simplify.simplify import logcombine
391
+ return expand(
392
+ powsimp(logcombine(expr, force=True), force=True, deep=True),
393
+ force=True).replace(exp_polar, exp)
394
+
395
+ assert mysimp(mysimp(IMT(pi/(s*tan(pi*s)), s, x, (-1, 0)))) in [
396
+ log(1 - x)*Heaviside(1 - x) + log(x - 1)*Heaviside(x - 1),
397
+ log(x)*Heaviside(x - 1) + log(1 - 1/x)*Heaviside(x - 1) + log(-x +
398
+ 1)*Heaviside(-x + 1)]
399
+ # test passing cot
400
+ assert mysimp(IMT(pi*cot(pi*s)/s, s, x, (0, 1))) in [
401
+ log(1/x - 1)*Heaviside(1 - x) + log(1 - 1/x)*Heaviside(x - 1),
402
+ -log(x)*Heaviside(-x + 1) + log(1 - 1/x)*Heaviside(x - 1) + log(-x +
403
+ 1)*Heaviside(-x + 1), ]
404
+
405
+ # 8.4.14
406
+ assert IMT(-gamma(s + S.Half)/(sqrt(pi)*s), s, x, (Rational(-1, 2), 0)) == \
407
+ erf(sqrt(x))
408
+
409
+ # 8.4.19
410
+ assert simplify(IMT(gamma(a/2 + s)/gamma(a/2 - s + 1), s, x, (-re(a)/2, Rational(3, 4)))) \
411
+ == besselj(a, 2*sqrt(x))
412
+ assert simplify(IMT(2**a*gamma(S.Half - 2*s)*gamma(s + (a + 1)/2)
413
+ / (gamma(1 - s - a/2)*gamma(1 - 2*s + a)),
414
+ s, x, (-(re(a) + 1)/2, Rational(1, 4)))) == \
415
+ sin(sqrt(x))*besselj(a, sqrt(x))
416
+ assert simplify(IMT(2**a*gamma(a/2 + s)*gamma(S.Half - 2*s)
417
+ / (gamma(S.Half - s - a/2)*gamma(1 - 2*s + a)),
418
+ s, x, (-re(a)/2, Rational(1, 4)))) == \
419
+ cos(sqrt(x))*besselj(a, sqrt(x))
420
+ # TODO this comes out as an amazing mess, but simplifies nicely
421
+ assert simplify(IMT(gamma(a + s)*gamma(S.Half - s)
422
+ / (sqrt(pi)*gamma(1 - s)*gamma(1 + a - s)),
423
+ s, x, (-re(a), S.Half))) == \
424
+ besselj(a, sqrt(x))**2
425
+ assert simplify(IMT(gamma(s)*gamma(S.Half - s)
426
+ / (sqrt(pi)*gamma(1 - s - a)*gamma(1 + a - s)),
427
+ s, x, (0, S.Half))) == \
428
+ besselj(-a, sqrt(x))*besselj(a, sqrt(x))
429
+ assert simplify(IMT(4**s*gamma(-2*s + 1)*gamma(a/2 + b/2 + s)
430
+ / (gamma(-a/2 + b/2 - s + 1)*gamma(a/2 - b/2 - s + 1)
431
+ *gamma(a/2 + b/2 - s + 1)),
432
+ s, x, (-(re(a) + re(b))/2, S.Half))) == \
433
+ besselj(a, sqrt(x))*besselj(b, sqrt(x))
434
+
435
+ # Section 8.4.20
436
+ # TODO this can be further simplified!
437
+ assert simplify(IMT(-2**(2*s)*cos(pi*a/2 - pi*b/2 + pi*s)*gamma(-2*s + 1) *
438
+ gamma(a/2 - b/2 + s)*gamma(a/2 + b/2 + s) /
439
+ (pi*gamma(a/2 - b/2 - s + 1)*gamma(a/2 + b/2 - s + 1)),
440
+ s, x,
441
+ (Max(-re(a)/2 - re(b)/2, -re(a)/2 + re(b)/2), S.Half))) == \
442
+ besselj(a, sqrt(x))*-(besselj(-b, sqrt(x)) -
443
+ besselj(b, sqrt(x))*cos(pi*b))/sin(pi*b)
444
+ # TODO more
445
+
446
+ # for coverage
447
+
448
+ assert IMT(pi/cos(pi*s), s, x, (0, S.Half)) == sqrt(x)/(x + 1)
449
+
450
+
451
+ def test_fourier_transform():
452
+ from sympy.core.function import (expand, expand_complex, expand_trig)
453
+ from sympy.polys.polytools import factor
454
+ from sympy.simplify.simplify import simplify
455
+ FT = fourier_transform
456
+ IFT = inverse_fourier_transform
457
+
458
+ def simp(x):
459
+ return simplify(expand_trig(expand_complex(expand(x))))
460
+
461
+ def sinc(x):
462
+ return sin(pi*x)/(pi*x)
463
+ k = symbols('k', real=True)
464
+ f = Function("f")
465
+
466
+ # TODO for this to work with real a, need to expand abs(a*x) to abs(a)*abs(x)
467
+ a = symbols('a', positive=True)
468
+ b = symbols('b', positive=True)
469
+
470
+ posk = symbols('posk', positive=True)
471
+
472
+ # Test unevaluated form
473
+ assert fourier_transform(f(x), x, k) == FourierTransform(f(x), x, k)
474
+ assert inverse_fourier_transform(
475
+ f(k), k, x) == InverseFourierTransform(f(k), k, x)
476
+
477
+ # basic examples from wikipedia
478
+ assert simp(FT(Heaviside(1 - abs(2*a*x)), x, k)) == sinc(k/a)/a
479
+ # TODO IFT is a *mess*
480
+ assert simp(FT(Heaviside(1 - abs(a*x))*(1 - abs(a*x)), x, k)) == sinc(k/a)**2/a
481
+ # TODO IFT
482
+
483
+ assert factor(FT(exp(-a*x)*Heaviside(x), x, k), extension=I) == \
484
+ 1/(a + 2*pi*I*k)
485
+ # NOTE: the ift comes out in pieces
486
+ assert IFT(1/(a + 2*pi*I*x), x, posk,
487
+ noconds=False) == (exp(-a*posk), True)
488
+ assert IFT(1/(a + 2*pi*I*x), x, -posk,
489
+ noconds=False) == (0, True)
490
+ assert IFT(1/(a + 2*pi*I*x), x, symbols('k', negative=True),
491
+ noconds=False) == (0, True)
492
+ # TODO IFT without factoring comes out as meijer g
493
+
494
+ assert factor(FT(x*exp(-a*x)*Heaviside(x), x, k), extension=I) == \
495
+ 1/(a + 2*pi*I*k)**2
496
+ assert FT(exp(-a*x)*sin(b*x)*Heaviside(x), x, k) == \
497
+ b/(b**2 + (a + 2*I*pi*k)**2)
498
+
499
+ assert FT(exp(-a*x**2), x, k) == sqrt(pi)*exp(-pi**2*k**2/a)/sqrt(a)
500
+ assert IFT(sqrt(pi/a)*exp(-(pi*k)**2/a), k, x) == exp(-a*x**2)
501
+ assert FT(exp(-a*abs(x)), x, k) == 2*a/(a**2 + 4*pi**2*k**2)
502
+ # TODO IFT (comes out as meijer G)
503
+
504
+ # TODO besselj(n, x), n an integer > 0 actually can be done...
505
+
506
+ # TODO are there other common transforms (no distributions!)?
507
+
508
+
509
+ def test_sine_transform():
510
+ t = symbols("t")
511
+ w = symbols("w")
512
+ a = symbols("a")
513
+ f = Function("f")
514
+
515
+ # Test unevaluated form
516
+ assert sine_transform(f(t), t, w) == SineTransform(f(t), t, w)
517
+ assert inverse_sine_transform(
518
+ f(w), w, t) == InverseSineTransform(f(w), w, t)
519
+
520
+ assert sine_transform(1/sqrt(t), t, w) == 1/sqrt(w)
521
+ assert inverse_sine_transform(1/sqrt(w), w, t) == 1/sqrt(t)
522
+
523
+ assert sine_transform((1/sqrt(t))**3, t, w) == 2*sqrt(w)
524
+
525
+ assert sine_transform(t**(-a), t, w) == 2**(
526
+ -a + S.Half)*w**(a - 1)*gamma(-a/2 + 1)/gamma((a + 1)/2)
527
+ assert inverse_sine_transform(2**(-a + S(
528
+ 1)/2)*w**(a - 1)*gamma(-a/2 + 1)/gamma(a/2 + S.Half), w, t) == t**(-a)
529
+
530
+ assert sine_transform(
531
+ exp(-a*t), t, w) == sqrt(2)*w/(sqrt(pi)*(a**2 + w**2))
532
+ assert inverse_sine_transform(
533
+ sqrt(2)*w/(sqrt(pi)*(a**2 + w**2)), w, t) == exp(-a*t)
534
+
535
+ assert sine_transform(
536
+ log(t)/t, t, w) == sqrt(2)*sqrt(pi)*-(log(w**2) + 2*EulerGamma)/4
537
+
538
+ assert sine_transform(
539
+ t*exp(-a*t**2), t, w) == sqrt(2)*w*exp(-w**2/(4*a))/(4*a**Rational(3, 2))
540
+ assert inverse_sine_transform(
541
+ sqrt(2)*w*exp(-w**2/(4*a))/(4*a**Rational(3, 2)), w, t) == t*exp(-a*t**2)
542
+
543
+
544
+ def test_cosine_transform():
545
+ from sympy.functions.special.error_functions import (Ci, Si)
546
+
547
+ t = symbols("t")
548
+ w = symbols("w")
549
+ a = symbols("a")
550
+ f = Function("f")
551
+
552
+ # Test unevaluated form
553
+ assert cosine_transform(f(t), t, w) == CosineTransform(f(t), t, w)
554
+ assert inverse_cosine_transform(
555
+ f(w), w, t) == InverseCosineTransform(f(w), w, t)
556
+
557
+ assert cosine_transform(1/sqrt(t), t, w) == 1/sqrt(w)
558
+ assert inverse_cosine_transform(1/sqrt(w), w, t) == 1/sqrt(t)
559
+
560
+ assert cosine_transform(1/(
561
+ a**2 + t**2), t, w) == sqrt(2)*sqrt(pi)*exp(-a*w)/(2*a)
562
+
563
+ assert cosine_transform(t**(
564
+ -a), t, w) == 2**(-a + S.Half)*w**(a - 1)*gamma((-a + 1)/2)/gamma(a/2)
565
+ assert inverse_cosine_transform(2**(-a + S(
566
+ 1)/2)*w**(a - 1)*gamma(-a/2 + S.Half)/gamma(a/2), w, t) == t**(-a)
567
+
568
+ assert cosine_transform(
569
+ exp(-a*t), t, w) == sqrt(2)*a/(sqrt(pi)*(a**2 + w**2))
570
+ assert inverse_cosine_transform(
571
+ sqrt(2)*a/(sqrt(pi)*(a**2 + w**2)), w, t) == exp(-a*t)
572
+
573
+ assert cosine_transform(exp(-a*sqrt(t))*cos(a*sqrt(
574
+ t)), t, w) == a*exp(-a**2/(2*w))/(2*w**Rational(3, 2))
575
+
576
+ assert cosine_transform(1/(a + t), t, w) == sqrt(2)*(
577
+ (-2*Si(a*w) + pi)*sin(a*w)/2 - cos(a*w)*Ci(a*w))/sqrt(pi)
578
+ assert inverse_cosine_transform(sqrt(2)*meijerg(((S.Half, 0), ()), (
579
+ (S.Half, 0, 0), (S.Half,)), a**2*w**2/4)/(2*pi), w, t) == 1/(a + t)
580
+
581
+ assert cosine_transform(1/sqrt(a**2 + t**2), t, w) == sqrt(2)*meijerg(
582
+ ((S.Half,), ()), ((0, 0), (S.Half,)), a**2*w**2/4)/(2*sqrt(pi))
583
+ assert inverse_cosine_transform(sqrt(2)*meijerg(((S.Half,), ()), ((0, 0), (S.Half,)), a**2*w**2/4)/(2*sqrt(pi)), w, t) == 1/(t*sqrt(a**2/t**2 + 1))
584
+
585
+
586
+ def test_hankel_transform():
587
+ r = Symbol("r")
588
+ k = Symbol("k")
589
+ nu = Symbol("nu")
590
+ m = Symbol("m")
591
+ a = symbols("a")
592
+
593
+ assert hankel_transform(1/r, r, k, 0) == 1/k
594
+ assert inverse_hankel_transform(1/k, k, r, 0) == 1/r
595
+
596
+ assert hankel_transform(
597
+ 1/r**m, r, k, 0) == 2**(-m + 1)*k**(m - 2)*gamma(-m/2 + 1)/gamma(m/2)
598
+ assert inverse_hankel_transform(
599
+ 2**(-m + 1)*k**(m - 2)*gamma(-m/2 + 1)/gamma(m/2), k, r, 0) == r**(-m)
600
+
601
+ assert hankel_transform(1/r**m, r, k, nu) == (
602
+ 2*2**(-m)*k**(m - 2)*gamma(-m/2 + nu/2 + 1)/gamma(m/2 + nu/2))
603
+ assert inverse_hankel_transform(2**(-m + 1)*k**(
604
+ m - 2)*gamma(-m/2 + nu/2 + 1)/gamma(m/2 + nu/2), k, r, nu) == r**(-m)
605
+
606
+ assert hankel_transform(r**nu*exp(-a*r), r, k, nu) == \
607
+ 2**(nu + 1)*a*k**(-nu - 3)*(a**2/k**2 + 1)**(-nu - S(
608
+ 3)/2)*gamma(nu + Rational(3, 2))/sqrt(pi)
609
+ assert inverse_hankel_transform(
610
+ 2**(nu + 1)*a*k**(-nu - 3)*(a**2/k**2 + 1)**(-nu - Rational(3, 2))*gamma(
611
+ nu + Rational(3, 2))/sqrt(pi), k, r, nu) == r**nu*exp(-a*r)
612
+
613
+
614
+ def test_issue_7181():
615
+ assert mellin_transform(1/(1 - x), x, s) != None
616
+
617
+
618
+ def test_issue_8882():
619
+ # This is the original test.
620
+ # from sympy import diff, Integral, integrate
621
+ # r = Symbol('r')
622
+ # psi = 1/r*sin(r)*exp(-(a0*r))
623
+ # h = -1/2*diff(psi, r, r) - 1/r*psi
624
+ # f = 4*pi*psi*h*r**2
625
+ # assert integrate(f, (r, -oo, 3), meijerg=True).has(Integral) == True
626
+
627
+ # To save time, only the critical part is included.
628
+ F = -a**(-s + 1)*(4 + 1/a**2)**(-s/2)*sqrt(1/a**2)*exp(-s*I*pi)* \
629
+ sin(s*atan(sqrt(1/a**2)/2))*gamma(s)
630
+ raises(IntegralTransformError, lambda:
631
+ inverse_mellin_transform(F, s, x, (-1, oo),
632
+ **{'as_meijerg': True, 'needeval': True}))
633
+
634
+
635
+ def test_issue_12591():
636
+ x, y = symbols("x y", real=True)
637
+ assert fourier_transform(exp(x), x, y) == FourierTransform(exp(x), x, y)
.venv/lib/python3.13/site-packages/sympy/integrals/tests/test_trigonometry.py ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core import Ne, Rational, Symbol
2
+ from sympy.functions import sin, cos, tan, csc, sec, cot, log, Piecewise
3
+ from sympy.integrals.trigonometry import trigintegrate
4
+
5
+ x = Symbol('x')
6
+
7
+
8
+ def test_trigintegrate_odd():
9
+ assert trigintegrate(Rational(1), x) == x
10
+ assert trigintegrate(x, x) is None
11
+ assert trigintegrate(x**2, x) is None
12
+
13
+ assert trigintegrate(sin(x), x) == -cos(x)
14
+ assert trigintegrate(cos(x), x) == sin(x)
15
+
16
+ assert trigintegrate(sin(3*x), x) == -cos(3*x)/3
17
+ assert trigintegrate(cos(3*x), x) == sin(3*x)/3
18
+
19
+ y = Symbol('y')
20
+ assert trigintegrate(sin(y*x), x) == Piecewise(
21
+ (-cos(y*x)/y, Ne(y, 0)), (0, True))
22
+ assert trigintegrate(cos(y*x), x) == Piecewise(
23
+ (sin(y*x)/y, Ne(y, 0)), (x, True))
24
+ assert trigintegrate(sin(y*x)**2, x) == Piecewise(
25
+ ((x*y/2 - sin(x*y)*cos(x*y)/2)/y, Ne(y, 0)), (0, True))
26
+ assert trigintegrate(sin(y*x)*cos(y*x), x) == Piecewise(
27
+ (sin(x*y)**2/(2*y), Ne(y, 0)), (0, True))
28
+ assert trigintegrate(cos(y*x)**2, x) == Piecewise(
29
+ ((x*y/2 + sin(x*y)*cos(x*y)/2)/y, Ne(y, 0)), (x, True))
30
+
31
+ y = Symbol('y', positive=True)
32
+ # TODO: remove conds='none' below. For this to work we would have to rule
33
+ # out (e.g. by trying solve) the condition y = 0, incompatible with
34
+ # y.is_positive being True.
35
+ assert trigintegrate(sin(y*x), x, conds='none') == -cos(y*x)/y
36
+ assert trigintegrate(cos(y*x), x, conds='none') == sin(y*x)/y
37
+
38
+ assert trigintegrate(sin(x)*cos(x), x) == sin(x)**2/2
39
+ assert trigintegrate(sin(x)*cos(x)**2, x) == -cos(x)**3/3
40
+ assert trigintegrate(sin(x)**2*cos(x), x) == sin(x)**3/3
41
+
42
+ # check if it selects right function to substitute,
43
+ # so the result is kept simple
44
+ assert trigintegrate(sin(x)**7 * cos(x), x) == sin(x)**8/8
45
+ assert trigintegrate(sin(x) * cos(x)**7, x) == -cos(x)**8/8
46
+
47
+ assert trigintegrate(sin(x)**7 * cos(x)**3, x) == \
48
+ -sin(x)**10/10 + sin(x)**8/8
49
+ assert trigintegrate(sin(x)**3 * cos(x)**7, x) == \
50
+ cos(x)**10/10 - cos(x)**8/8
51
+
52
+ # both n, m are odd and -ve, and not necessarily equal
53
+ assert trigintegrate(sin(x)**-1*cos(x)**-1, x) == \
54
+ -log(sin(x)**2 - 1)/2 + log(sin(x))
55
+
56
+
57
+ def test_trigintegrate_even():
58
+ assert trigintegrate(sin(x)**2, x) == x/2 - cos(x)*sin(x)/2
59
+ assert trigintegrate(cos(x)**2, x) == x/2 + cos(x)*sin(x)/2
60
+
61
+ assert trigintegrate(sin(3*x)**2, x) == x/2 - cos(3*x)*sin(3*x)/6
62
+ assert trigintegrate(cos(3*x)**2, x) == x/2 + cos(3*x)*sin(3*x)/6
63
+ assert trigintegrate(sin(x)**2 * cos(x)**2, x) == \
64
+ x/8 - sin(2*x)*cos(2*x)/16
65
+
66
+ assert trigintegrate(sin(x)**4 * cos(x)**2, x) == \
67
+ x/16 - sin(x) *cos(x)/16 - sin(x)**3*cos(x)/24 + \
68
+ sin(x)**5*cos(x)/6
69
+
70
+ assert trigintegrate(sin(x)**2 * cos(x)**4, x) == \
71
+ x/16 + cos(x) *sin(x)/16 + cos(x)**3*sin(x)/24 - \
72
+ cos(x)**5*sin(x)/6
73
+
74
+ assert trigintegrate(sin(x)**(-4), x) == -2*cos(x)/(3*sin(x)) \
75
+ - cos(x)/(3*sin(x)**3)
76
+
77
+ assert trigintegrate(cos(x)**(-6), x) == sin(x)/(5*cos(x)**5) \
78
+ + 4*sin(x)/(15*cos(x)**3) + 8*sin(x)/(15*cos(x))
79
+
80
+
81
+ def test_trigintegrate_mixed():
82
+ assert trigintegrate(sin(x)*sec(x), x) == -log(cos(x))
83
+ assert trigintegrate(sin(x)*csc(x), x) == x
84
+ assert trigintegrate(sin(x)*cot(x), x) == sin(x)
85
+
86
+ assert trigintegrate(cos(x)*sec(x), x) == x
87
+ assert trigintegrate(cos(x)*csc(x), x) == log(sin(x))
88
+ assert trigintegrate(cos(x)*tan(x), x) == -cos(x)
89
+ assert trigintegrate(cos(x)*cot(x), x) == log(cos(x) - 1)/2 \
90
+ - log(cos(x) + 1)/2 + cos(x)
91
+ assert trigintegrate(cot(x)*cos(x)**2, x) == log(sin(x)) - sin(x)**2/2
92
+
93
+
94
+ def test_trigintegrate_symbolic():
95
+ n = Symbol('n', integer=True)
96
+ assert trigintegrate(cos(x)**n, x) is None
97
+ assert trigintegrate(sin(x)**n, x) is None
98
+ assert trigintegrate(cot(x)**n, x) is None
.venv/lib/python3.13/site-packages/sympy/testing/tests/diagnose_imports.py ADDED
@@ -0,0 +1,216 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python
2
+
3
+ """
4
+ Import diagnostics. Run bin/diagnose_imports.py --help for details.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ if __name__ == "__main__":
10
+
11
+ import sys
12
+ import inspect
13
+ import builtins
14
+
15
+ import optparse
16
+
17
+ from os.path import abspath, dirname, join, normpath
18
+ this_file = abspath(__file__)
19
+ sympy_dir = join(dirname(this_file), '..', '..', '..')
20
+ sympy_dir = normpath(sympy_dir)
21
+ sys.path.insert(0, sympy_dir)
22
+
23
+ option_parser = optparse.OptionParser(
24
+ usage=
25
+ "Usage: %prog option [options]\n"
26
+ "\n"
27
+ "Import analysis for imports between SymPy modules.")
28
+ option_group = optparse.OptionGroup(
29
+ option_parser,
30
+ 'Analysis options',
31
+ 'Options that define what to do. Exactly one of these must be given.')
32
+ option_group.add_option(
33
+ '--problems',
34
+ help=
35
+ 'Print all import problems, that is: '
36
+ 'If an import pulls in a package instead of a module '
37
+ '(e.g. sympy.core instead of sympy.core.add); ' # see ##PACKAGE##
38
+ 'if it imports a symbol that is already present; ' # see ##DUPLICATE##
39
+ 'if it imports a symbol '
40
+ 'from somewhere other than the defining module.', # see ##ORIGIN##
41
+ action='count')
42
+ option_group.add_option(
43
+ '--origins',
44
+ help=
45
+ 'For each imported symbol in each module, '
46
+ 'print the module that defined it. '
47
+ '(This is useful for import refactoring.)',
48
+ action='count')
49
+ option_parser.add_option_group(option_group)
50
+ option_group = optparse.OptionGroup(
51
+ option_parser,
52
+ 'Sort options',
53
+ 'These options define the sort order for output lines. '
54
+ 'At most one of these options is allowed. '
55
+ 'Unsorted output will reflect the order in which imports happened.')
56
+ option_group.add_option(
57
+ '--by-importer',
58
+ help='Sort output lines by name of importing module.',
59
+ action='count')
60
+ option_group.add_option(
61
+ '--by-origin',
62
+ help='Sort output lines by name of imported module.',
63
+ action='count')
64
+ option_parser.add_option_group(option_group)
65
+ (options, args) = option_parser.parse_args()
66
+ if args:
67
+ option_parser.error(
68
+ 'Unexpected arguments %s (try %s --help)' % (args, sys.argv[0]))
69
+ if options.problems > 1:
70
+ option_parser.error('--problems must not be given more than once.')
71
+ if options.origins > 1:
72
+ option_parser.error('--origins must not be given more than once.')
73
+ if options.by_importer > 1:
74
+ option_parser.error('--by-importer must not be given more than once.')
75
+ if options.by_origin > 1:
76
+ option_parser.error('--by-origin must not be given more than once.')
77
+ options.problems = options.problems == 1
78
+ options.origins = options.origins == 1
79
+ options.by_importer = options.by_importer == 1
80
+ options.by_origin = options.by_origin == 1
81
+ if not options.problems and not options.origins:
82
+ option_parser.error(
83
+ 'At least one of --problems and --origins is required')
84
+ if options.problems and options.origins:
85
+ option_parser.error(
86
+ 'At most one of --problems and --origins is allowed')
87
+ if options.by_importer and options.by_origin:
88
+ option_parser.error(
89
+ 'At most one of --by-importer and --by-origin is allowed')
90
+ options.by_process = not options.by_importer and not options.by_origin
91
+
92
+ builtin_import = builtins.__import__
93
+
94
+ class Definition:
95
+ """Information about a symbol's definition."""
96
+ def __init__(self, name, value, definer):
97
+ self.name = name
98
+ self.value = value
99
+ self.definer = definer
100
+ def __hash__(self):
101
+ return hash(self.name)
102
+ def __eq__(self, other):
103
+ return self.name == other.name and self.value == other.value
104
+ def __ne__(self, other):
105
+ return not (self == other)
106
+ def __repr__(self):
107
+ return 'Definition(%s, ..., %s)' % (
108
+ repr(self.name), repr(self.definer))
109
+
110
+ # Maps each function/variable to name of module to define it
111
+ symbol_definers: dict[Definition, str] = {}
112
+
113
+ def in_module(a, b):
114
+ """Is a the same module as or a submodule of b?"""
115
+ return a == b or a != None and b != None and a.startswith(b + '.')
116
+
117
+ def relevant(module):
118
+ """Is module relevant for import checking?
119
+
120
+ Only imports between relevant modules will be checked."""
121
+ return in_module(module, 'sympy')
122
+
123
+ sorted_messages = []
124
+
125
+ def msg(msg, *args):
126
+ if options.by_process:
127
+ print(msg % args)
128
+ else:
129
+ sorted_messages.append(msg % args)
130
+
131
+ def tracking_import(module, globals=globals(), locals=[], fromlist=None, level=-1):
132
+ """__import__ wrapper - does not change imports at all, but tracks them.
133
+
134
+ Default order is implemented by doing output directly.
135
+ All other orders are implemented by collecting output information into
136
+ a sorted list that will be emitted after all imports are processed.
137
+
138
+ Indirect imports can only occur after the requested symbol has been
139
+ imported directly (because the indirect import would not have a module
140
+ to pick the symbol up from).
141
+ So this code detects indirect imports by checking whether the symbol in
142
+ question was already imported.
143
+
144
+ Keeps the semantics of __import__ unchanged."""
145
+ caller_frame = inspect.getframeinfo(sys._getframe(1))
146
+ importer_filename = caller_frame.filename
147
+ importer_module = globals['__name__']
148
+ if importer_filename == caller_frame.filename:
149
+ importer_reference = '%s line %s' % (
150
+ importer_filename, str(caller_frame.lineno))
151
+ else:
152
+ importer_reference = importer_filename
153
+ result = builtin_import(module, globals, locals, fromlist, level)
154
+ importee_module = result.__name__
155
+ # We're only interested if importer and importee are in SymPy
156
+ if relevant(importer_module) and relevant(importee_module):
157
+ for symbol in result.__dict__.iterkeys():
158
+ definition = Definition(
159
+ symbol, result.__dict__[symbol], importer_module)
160
+ if definition not in symbol_definers:
161
+ symbol_definers[definition] = importee_module
162
+ if hasattr(result, '__path__'):
163
+ ##PACKAGE##
164
+ # The existence of __path__ is documented in the tutorial on modules.
165
+ # Python 3.3 documents this in http://docs.python.org/3.3/reference/import.html
166
+ if options.by_origin:
167
+ msg('Error: %s (a package) is imported by %s',
168
+ module, importer_reference)
169
+ else:
170
+ msg('Error: %s contains package import %s',
171
+ importer_reference, module)
172
+ if fromlist != None:
173
+ symbol_list = fromlist
174
+ if '*' in symbol_list:
175
+ if (importer_filename.endswith(("__init__.py", "__init__.pyc", "__init__.pyo"))):
176
+ # We do not check starred imports inside __init__
177
+ # That's the normal "please copy over its imports to my namespace"
178
+ symbol_list = []
179
+ else:
180
+ symbol_list = result.__dict__.iterkeys()
181
+ for symbol in symbol_list:
182
+ if symbol not in result.__dict__:
183
+ if options.by_origin:
184
+ msg('Error: %s.%s is not defined (yet), but %s tries to import it',
185
+ importee_module, symbol, importer_reference)
186
+ else:
187
+ msg('Error: %s tries to import %s.%s, which did not define it (yet)',
188
+ importer_reference, importee_module, symbol)
189
+ else:
190
+ definition = Definition(
191
+ symbol, result.__dict__[symbol], importer_module)
192
+ symbol_definer = symbol_definers[definition]
193
+ if symbol_definer == importee_module:
194
+ ##DUPLICATE##
195
+ if options.by_origin:
196
+ msg('Error: %s.%s is imported again into %s',
197
+ importee_module, symbol, importer_reference)
198
+ else:
199
+ msg('Error: %s imports %s.%s again',
200
+ importer_reference, importee_module, symbol)
201
+ else:
202
+ ##ORIGIN##
203
+ if options.by_origin:
204
+ msg('Error: %s.%s is imported by %s, which should import %s.%s instead',
205
+ importee_module, symbol, importer_reference, symbol_definer, symbol)
206
+ else:
207
+ msg('Error: %s imports %s.%s but should import %s.%s instead',
208
+ importer_reference, importee_module, symbol, symbol_definer, symbol)
209
+ return result
210
+
211
+ builtins.__import__ = tracking_import
212
+ __import__('sympy')
213
+
214
+ sorted_messages.sort()
215
+ for message in sorted_messages:
216
+ print(message)
.venv/lib/python3.13/site-packages/sympy/testing/tests/test_module_imports.py ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Checks that SymPy does not contain indirect imports.
3
+
4
+ An indirect import is importing a symbol from a module that itself imported the
5
+ symbol from elsewhere. Such a constellation makes it harder to diagnose
6
+ inter-module dependencies and import order problems, and is therefore strongly
7
+ discouraged.
8
+
9
+ (Indirect imports from end-user code is fine and in fact a best practice.)
10
+
11
+ Implementation note: Forcing Python into actually unloading already-imported
12
+ submodules is a tricky and partly undocumented process. To avoid these issues,
13
+ the actual diagnostic code is in bin/diagnose_imports, which is run as a
14
+ separate, pristine Python process.
15
+ """
16
+
17
+ import subprocess
18
+ import sys
19
+ from os.path import abspath, dirname, join, normpath
20
+ import inspect
21
+
22
+ from sympy.testing.pytest import XFAIL
23
+
24
+ @XFAIL
25
+ def test_module_imports_are_direct():
26
+ my_filename = abspath(inspect.getfile(inspect.currentframe()))
27
+ my_dirname = dirname(my_filename)
28
+ diagnose_imports_filename = join(my_dirname, 'diagnose_imports.py')
29
+ diagnose_imports_filename = normpath(diagnose_imports_filename)
30
+
31
+ process = subprocess.Popen(
32
+ [
33
+ sys.executable,
34
+ normpath(diagnose_imports_filename),
35
+ '--problems',
36
+ '--by-importer'
37
+ ],
38
+ stdout=subprocess.PIPE,
39
+ stderr=subprocess.STDOUT,
40
+ bufsize=-1)
41
+ output, _ = process.communicate()
42
+ assert output == '', "There are import problems:\n" + output.decode()
.venv/lib/python3.13/site-packages/sympy/testing/tests/test_pytest.py ADDED
@@ -0,0 +1,211 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import warnings
2
+
3
+ from sympy.testing.pytest import (raises, warns, ignore_warnings,
4
+ warns_deprecated_sympy, Failed)
5
+ from sympy.utilities.exceptions import sympy_deprecation_warning
6
+
7
+
8
+
9
+ # Test callables
10
+
11
+
12
+ def test_expected_exception_is_silent_callable():
13
+ def f():
14
+ raise ValueError()
15
+ raises(ValueError, f)
16
+
17
+
18
+ # Under pytest raises will raise Failed rather than AssertionError
19
+ def test_lack_of_exception_triggers_AssertionError_callable():
20
+ try:
21
+ raises(Exception, lambda: 1 + 1)
22
+ assert False
23
+ except Failed as e:
24
+ assert "DID NOT RAISE" in str(e)
25
+
26
+
27
+ def test_unexpected_exception_is_passed_through_callable():
28
+ def f():
29
+ raise ValueError("some error message")
30
+ try:
31
+ raises(TypeError, f)
32
+ assert False
33
+ except ValueError as e:
34
+ assert str(e) == "some error message"
35
+
36
+ # Test with statement
37
+
38
+ def test_expected_exception_is_silent_with():
39
+ with raises(ValueError):
40
+ raise ValueError()
41
+
42
+
43
+ def test_lack_of_exception_triggers_AssertionError_with():
44
+ try:
45
+ with raises(Exception):
46
+ 1 + 1
47
+ assert False
48
+ except Failed as e:
49
+ assert "DID NOT RAISE" in str(e)
50
+
51
+
52
+ def test_unexpected_exception_is_passed_through_with():
53
+ try:
54
+ with raises(TypeError):
55
+ raise ValueError("some error message")
56
+ assert False
57
+ except ValueError as e:
58
+ assert str(e) == "some error message"
59
+
60
+ # Now we can use raises() instead of try/catch
61
+ # to test that a specific exception class is raised
62
+
63
+
64
+ def test_second_argument_should_be_callable_or_string():
65
+ raises(TypeError, lambda: raises("irrelevant", 42))
66
+
67
+
68
+ def test_warns_catches_warning():
69
+ with warnings.catch_warnings(record=True) as w:
70
+ with warns(UserWarning):
71
+ warnings.warn('this is the warning message')
72
+ assert len(w) == 0
73
+
74
+
75
+ def test_warns_raises_without_warning():
76
+ with raises(Failed):
77
+ with warns(UserWarning):
78
+ pass
79
+
80
+
81
+ def test_warns_hides_other_warnings():
82
+ with raises(RuntimeWarning):
83
+ with warns(UserWarning):
84
+ warnings.warn('this is the warning message', UserWarning)
85
+ warnings.warn('this is the other message', RuntimeWarning)
86
+
87
+
88
+ def test_warns_continues_after_warning():
89
+ with warnings.catch_warnings(record=True) as w:
90
+ finished = False
91
+ with warns(UserWarning):
92
+ warnings.warn('this is the warning message')
93
+ finished = True
94
+ assert finished
95
+ assert len(w) == 0
96
+
97
+
98
+ def test_warns_many_warnings():
99
+ with warns(UserWarning):
100
+ warnings.warn('this is the warning message', UserWarning)
101
+ warnings.warn('this is the other warning message', UserWarning)
102
+
103
+
104
+ def test_warns_match_matching():
105
+ with warnings.catch_warnings(record=True) as w:
106
+ with warns(UserWarning, match='this is the warning message'):
107
+ warnings.warn('this is the warning message', UserWarning)
108
+ assert len(w) == 0
109
+
110
+
111
+ def test_warns_match_non_matching():
112
+ with warnings.catch_warnings(record=True) as w:
113
+ with raises(Failed):
114
+ with warns(UserWarning, match='this is the warning message'):
115
+ warnings.warn('this is not the expected warning message', UserWarning)
116
+ assert len(w) == 0
117
+
118
+ def _warn_sympy_deprecation(stacklevel=3):
119
+ sympy_deprecation_warning(
120
+ "feature",
121
+ active_deprecations_target="active-deprecations",
122
+ deprecated_since_version="0.0.0",
123
+ stacklevel=stacklevel,
124
+ )
125
+
126
+ def test_warns_deprecated_sympy_catches_warning():
127
+ with warnings.catch_warnings(record=True) as w:
128
+ with warns_deprecated_sympy():
129
+ _warn_sympy_deprecation()
130
+ assert len(w) == 0
131
+
132
+
133
+ def test_warns_deprecated_sympy_raises_without_warning():
134
+ with raises(Failed):
135
+ with warns_deprecated_sympy():
136
+ pass
137
+
138
+ def test_warns_deprecated_sympy_wrong_stacklevel():
139
+ with raises(Failed):
140
+ with warns_deprecated_sympy():
141
+ _warn_sympy_deprecation(stacklevel=1)
142
+
143
+ def test_warns_deprecated_sympy_doesnt_hide_other_warnings():
144
+ # Unlike pytest's deprecated_call, we should not hide other warnings.
145
+ with raises(RuntimeWarning):
146
+ with warns_deprecated_sympy():
147
+ _warn_sympy_deprecation()
148
+ warnings.warn('this is the other message', RuntimeWarning)
149
+
150
+
151
+ def test_warns_deprecated_sympy_continues_after_warning():
152
+ with warnings.catch_warnings(record=True) as w:
153
+ finished = False
154
+ with warns_deprecated_sympy():
155
+ _warn_sympy_deprecation()
156
+ finished = True
157
+ assert finished
158
+ assert len(w) == 0
159
+
160
+ def test_ignore_ignores_warning():
161
+ with warnings.catch_warnings(record=True) as w:
162
+ with ignore_warnings(UserWarning):
163
+ warnings.warn('this is the warning message')
164
+ assert len(w) == 0
165
+
166
+
167
+ def test_ignore_does_not_raise_without_warning():
168
+ with warnings.catch_warnings(record=True) as w:
169
+ with ignore_warnings(UserWarning):
170
+ pass
171
+ assert len(w) == 0
172
+
173
+
174
+ def test_ignore_allows_other_warnings():
175
+ with warnings.catch_warnings(record=True) as w:
176
+ # This is needed when pytest is run as -Werror
177
+ # the setting is reverted at the end of the catch_Warnings block.
178
+ warnings.simplefilter("always")
179
+ with ignore_warnings(UserWarning):
180
+ warnings.warn('this is the warning message', UserWarning)
181
+ warnings.warn('this is the other message', RuntimeWarning)
182
+ assert len(w) == 1
183
+ assert isinstance(w[0].message, RuntimeWarning)
184
+ assert str(w[0].message) == 'this is the other message'
185
+
186
+
187
+ def test_ignore_continues_after_warning():
188
+ with warnings.catch_warnings(record=True) as w:
189
+ finished = False
190
+ with ignore_warnings(UserWarning):
191
+ warnings.warn('this is the warning message')
192
+ finished = True
193
+ assert finished
194
+ assert len(w) == 0
195
+
196
+
197
+ def test_ignore_many_warnings():
198
+ with warnings.catch_warnings(record=True) as w:
199
+ # This is needed when pytest is run as -Werror
200
+ # the setting is reverted at the end of the catch_Warnings block.
201
+ warnings.simplefilter("always")
202
+ with ignore_warnings(UserWarning):
203
+ warnings.warn('this is the warning message', UserWarning)
204
+ warnings.warn('this is the other message', RuntimeWarning)
205
+ warnings.warn('this is the warning message', UserWarning)
206
+ warnings.warn('this is the other message', RuntimeWarning)
207
+ warnings.warn('this is the other message', RuntimeWarning)
208
+ assert len(w) == 3
209
+ for wi in w:
210
+ assert isinstance(wi.message, RuntimeWarning)
211
+ assert str(wi.message) == 'this is the other message'
.venv/lib/python3.13/site-packages/sympy/testing/tests/test_runtests_pytest.py ADDED
@@ -0,0 +1,171 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pathlib
2
+ from typing import List
3
+
4
+ import pytest
5
+
6
+ from sympy.testing.runtests_pytest import (
7
+ make_absolute_path,
8
+ sympy_dir,
9
+ update_args_with_paths,
10
+ )
11
+
12
+
13
+ class TestMakeAbsolutePath:
14
+
15
+ @staticmethod
16
+ @pytest.mark.parametrize(
17
+ 'partial_path', ['sympy', 'sympy/core', 'sympy/nonexistant_directory'],
18
+ )
19
+ def test_valid_partial_path(partial_path: str):
20
+ """Paths that start with `sympy` are valid."""
21
+ _ = make_absolute_path(partial_path)
22
+
23
+ @staticmethod
24
+ @pytest.mark.parametrize(
25
+ 'partial_path', ['not_sympy', 'also/not/sympy'],
26
+ )
27
+ def test_invalid_partial_path_raises_value_error(partial_path: str):
28
+ """A `ValueError` is raises on paths that don't start with `sympy`."""
29
+ with pytest.raises(ValueError):
30
+ _ = make_absolute_path(partial_path)
31
+
32
+
33
+ class TestUpdateArgsWithPaths:
34
+
35
+ @staticmethod
36
+ def test_no_paths():
37
+ """If no paths are passed, only `sympy` and `doc/src` are appended.
38
+
39
+ `sympy` and `doc/src` are the `testpaths` stated in `pytest.ini`. They
40
+ need to be manually added as if any path-related arguments are passed
41
+ to `pytest.main` then the settings in `pytest.ini` may be ignored.
42
+
43
+ """
44
+ paths = []
45
+ args = update_args_with_paths(paths=paths, keywords=None, args=[])
46
+ expected = [
47
+ str(pathlib.Path(sympy_dir(), 'sympy')),
48
+ str(pathlib.Path(sympy_dir(), 'doc/src')),
49
+ ]
50
+ assert args == expected
51
+
52
+ @staticmethod
53
+ @pytest.mark.parametrize(
54
+ 'path',
55
+ ['sympy/core/tests/test_basic.py', '_basic']
56
+ )
57
+ def test_one_file(path: str):
58
+ """Single files/paths, full or partial, are matched correctly."""
59
+ args = update_args_with_paths(paths=[path], keywords=None, args=[])
60
+ expected = [
61
+ str(pathlib.Path(sympy_dir(), 'sympy/core/tests/test_basic.py')),
62
+ ]
63
+ assert args == expected
64
+
65
+ @staticmethod
66
+ def test_partial_path_from_root():
67
+ """Partial paths from the root directly are matched correctly."""
68
+ args = update_args_with_paths(paths=['sympy/functions'], keywords=None, args=[])
69
+ expected = [str(pathlib.Path(sympy_dir(), 'sympy/functions'))]
70
+ assert args == expected
71
+
72
+ @staticmethod
73
+ def test_multiple_paths_from_root():
74
+ """Multiple paths, partial or full, are matched correctly."""
75
+ paths = ['sympy/core/tests/test_basic.py', 'sympy/functions']
76
+ args = update_args_with_paths(paths=paths, keywords=None, args=[])
77
+ expected = [
78
+ str(pathlib.Path(sympy_dir(), 'sympy/core/tests/test_basic.py')),
79
+ str(pathlib.Path(sympy_dir(), 'sympy/functions')),
80
+ ]
81
+ assert args == expected
82
+
83
+ @staticmethod
84
+ @pytest.mark.parametrize(
85
+ 'paths, expected_paths',
86
+ [
87
+ (
88
+ ['/core', '/util'],
89
+ [
90
+ 'doc/src/modules/utilities',
91
+ 'doc/src/reference/public/utilities',
92
+ 'sympy/core',
93
+ 'sympy/logic/utilities',
94
+ 'sympy/utilities',
95
+ ]
96
+ ),
97
+ ]
98
+ )
99
+ def test_multiple_paths_from_non_root(paths: List[str], expected_paths: List[str]):
100
+ """Multiple partial paths are matched correctly."""
101
+ args = update_args_with_paths(paths=paths, keywords=None, args=[])
102
+ assert len(args) == len(expected_paths)
103
+ for arg, expected in zip(sorted(args), expected_paths):
104
+ assert expected in arg
105
+
106
+ @staticmethod
107
+ @pytest.mark.parametrize(
108
+ 'paths',
109
+ [
110
+
111
+ [],
112
+ ['sympy/physics'],
113
+ ['sympy/physics/mechanics'],
114
+ ['sympy/physics/mechanics/tests'],
115
+ ['sympy/physics/mechanics/tests/test_kane3.py'],
116
+ ]
117
+ )
118
+ def test_string_as_keyword(paths: List[str]):
119
+ """String keywords are matched correctly."""
120
+ keywords = ('bicycle', )
121
+ args = update_args_with_paths(paths=paths, keywords=keywords, args=[])
122
+ expected_args = ['sympy/physics/mechanics/tests/test_kane3.py::test_bicycle']
123
+ assert len(args) == len(expected_args)
124
+ for arg, expected in zip(sorted(args), expected_args):
125
+ assert expected in arg
126
+
127
+ @staticmethod
128
+ @pytest.mark.parametrize(
129
+ 'paths',
130
+ [
131
+
132
+ [],
133
+ ['sympy/core'],
134
+ ['sympy/core/tests'],
135
+ ['sympy/core/tests/test_sympify.py'],
136
+ ]
137
+ )
138
+ def test_integer_as_keyword(paths: List[str]):
139
+ """Integer keywords are matched correctly."""
140
+ keywords = ('3538', )
141
+ args = update_args_with_paths(paths=paths, keywords=keywords, args=[])
142
+ expected_args = ['sympy/core/tests/test_sympify.py::test_issue_3538']
143
+ assert len(args) == len(expected_args)
144
+ for arg, expected in zip(sorted(args), expected_args):
145
+ assert expected in arg
146
+
147
+ @staticmethod
148
+ def test_multiple_keywords():
149
+ """Multiple keywords are matched correctly."""
150
+ keywords = ('bicycle', '3538')
151
+ args = update_args_with_paths(paths=[], keywords=keywords, args=[])
152
+ expected_args = [
153
+ 'sympy/core/tests/test_sympify.py::test_issue_3538',
154
+ 'sympy/physics/mechanics/tests/test_kane3.py::test_bicycle',
155
+ ]
156
+ assert len(args) == len(expected_args)
157
+ for arg, expected in zip(sorted(args), expected_args):
158
+ assert expected in arg
159
+
160
+ @staticmethod
161
+ def test_keyword_match_in_multiple_files():
162
+ """Keywords are matched across multiple files."""
163
+ keywords = ('1130', )
164
+ args = update_args_with_paths(paths=[], keywords=keywords, args=[])
165
+ expected_args = [
166
+ 'sympy/integrals/tests/test_heurisch.py::test_heurisch_symbolic_coeffs_1130',
167
+ 'sympy/utilities/tests/test_lambdify.py::test_python_div_zero_issue_11306',
168
+ ]
169
+ assert len(args) == len(expected_args)
170
+ for arg, expected in zip(sorted(args), expected_args):
171
+ assert expected in arg