Add files using upload-large-folder tool
Browse files- .venv/lib/python3.13/site-packages/sympy/assumptions/handlers/__init__.py +13 -0
- .venv/lib/python3.13/site-packages/sympy/assumptions/handlers/calculus.py +273 -0
- .venv/lib/python3.13/site-packages/sympy/assumptions/handlers/common.py +164 -0
- .venv/lib/python3.13/site-packages/sympy/assumptions/handlers/matrices.py +716 -0
- .venv/lib/python3.13/site-packages/sympy/assumptions/handlers/ntheory.py +279 -0
- .venv/lib/python3.13/site-packages/sympy/assumptions/handlers/order.py +440 -0
- .venv/lib/python3.13/site-packages/sympy/assumptions/handlers/sets.py +816 -0
- .venv/lib/python3.13/site-packages/sympy/assumptions/predicates/__init__.py +5 -0
- .venv/lib/python3.13/site-packages/sympy/assumptions/predicates/calculus.py +82 -0
- .venv/lib/python3.13/site-packages/sympy/assumptions/predicates/common.py +81 -0
- .venv/lib/python3.13/site-packages/sympy/assumptions/predicates/ntheory.py +126 -0
- .venv/lib/python3.13/site-packages/sympy/assumptions/predicates/sets.py +399 -0
- .venv/lib/python3.13/site-packages/sympy/assumptions/relation/__init__.py +13 -0
- .venv/lib/python3.13/site-packages/sympy/assumptions/relation/binrel.py +212 -0
- .venv/lib/python3.13/site-packages/sympy/assumptions/relation/equality.py +302 -0
- .venv/lib/python3.13/site-packages/sympy/assumptions/tests/__init__.py +0 -0
- .venv/lib/python3.13/site-packages/sympy/assumptions/tests/test_assumptions_2.py +35 -0
- .venv/lib/python3.13/site-packages/sympy/assumptions/tests/test_context.py +39 -0
- .venv/lib/python3.13/site-packages/sympy/assumptions/tests/test_matrices.py +283 -0
- .venv/lib/python3.13/site-packages/sympy/assumptions/tests/test_query.py +0 -0
- .venv/lib/python3.13/site-packages/sympy/assumptions/tests/test_refine.py +227 -0
- .venv/lib/python3.13/site-packages/sympy/assumptions/tests/test_rel_queries.py +172 -0
- .venv/lib/python3.13/site-packages/sympy/assumptions/tests/test_satask.py +378 -0
- .venv/lib/python3.13/site-packages/sympy/assumptions/tests/test_sathandlers.py +50 -0
- .venv/lib/python3.13/site-packages/sympy/assumptions/tests/test_wrapper.py +39 -0
- .venv/lib/python3.13/site-packages/sympy/integrals/benchmarks/__init__.py +0 -0
- .venv/lib/python3.13/site-packages/sympy/integrals/benchmarks/bench_integrate.py +21 -0
- .venv/lib/python3.13/site-packages/sympy/integrals/benchmarks/bench_trigintegrate.py +13 -0
- .venv/lib/python3.13/site-packages/sympy/integrals/tests/__init__.py +0 -0
- .venv/lib/python3.13/site-packages/sympy/integrals/tests/test_deltafunctions.py +79 -0
- .venv/lib/python3.13/site-packages/sympy/integrals/tests/test_failing_integrals.py +277 -0
- .venv/lib/python3.13/site-packages/sympy/integrals/tests/test_heurisch.py +417 -0
- .venv/lib/python3.13/site-packages/sympy/integrals/tests/test_integrals.py +2187 -0
- .venv/lib/python3.13/site-packages/sympy/integrals/tests/test_intpoly.py +627 -0
- .venv/lib/python3.13/site-packages/sympy/integrals/tests/test_laplace.py +774 -0
- .venv/lib/python3.13/site-packages/sympy/integrals/tests/test_lineintegrals.py +13 -0
- .venv/lib/python3.13/site-packages/sympy/integrals/tests/test_manual.py +714 -0
- .venv/lib/python3.13/site-packages/sympy/integrals/tests/test_meijerint.py +774 -0
- .venv/lib/python3.13/site-packages/sympy/integrals/tests/test_prde.py +322 -0
- .venv/lib/python3.13/site-packages/sympy/integrals/tests/test_quadrature.py +601 -0
- .venv/lib/python3.13/site-packages/sympy/integrals/tests/test_rationaltools.py +183 -0
- .venv/lib/python3.13/site-packages/sympy/integrals/tests/test_rde.py +202 -0
- .venv/lib/python3.13/site-packages/sympy/integrals/tests/test_risch.py +763 -0
- .venv/lib/python3.13/site-packages/sympy/integrals/tests/test_singularityfunctions.py +22 -0
- .venv/lib/python3.13/site-packages/sympy/integrals/tests/test_transforms.py +637 -0
- .venv/lib/python3.13/site-packages/sympy/integrals/tests/test_trigonometry.py +98 -0
- .venv/lib/python3.13/site-packages/sympy/testing/tests/diagnose_imports.py +216 -0
- .venv/lib/python3.13/site-packages/sympy/testing/tests/test_module_imports.py +42 -0
- .venv/lib/python3.13/site-packages/sympy/testing/tests/test_pytest.py +211 -0
- .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
|