chore: 添加虚拟环境到仓库
- 添加 backend_service/venv 虚拟环境 - 包含所有Python依赖包 - 注意:虚拟环境约393MB,包含12655个文件
This commit is contained in:
@@ -0,0 +1,405 @@
|
||||
from __future__ import annotations
|
||||
from typing import Callable
|
||||
|
||||
from sympy.core import S, Add, Expr, Basic, Mul, Pow, Rational
|
||||
from sympy.core.logic import fuzzy_not
|
||||
from sympy.logic.boolalg import Boolean
|
||||
|
||||
from sympy.assumptions import ask, Q # type: ignore
|
||||
|
||||
|
||||
def refine(expr, assumptions=True):
|
||||
"""
|
||||
Simplify an expression using assumptions.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
Unlike :func:`~.simplify` which performs structural simplification
|
||||
without any assumption, this function transforms the expression into
|
||||
the form which is only valid under certain assumptions. Note that
|
||||
``simplify()`` is generally not done in refining process.
|
||||
|
||||
Refining boolean expression involves reducing it to ``S.true`` or
|
||||
``S.false``. Unlike :func:`~.ask`, the expression will not be reduced
|
||||
if the truth value cannot be determined.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import refine, sqrt, Q
|
||||
>>> from sympy.abc import x
|
||||
>>> refine(sqrt(x**2), Q.real(x))
|
||||
Abs(x)
|
||||
>>> refine(sqrt(x**2), Q.positive(x))
|
||||
x
|
||||
|
||||
>>> refine(Q.real(x), Q.positive(x))
|
||||
True
|
||||
>>> refine(Q.positive(x), Q.real(x))
|
||||
Q.positive(x)
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
sympy.simplify.simplify.simplify : Structural simplification without assumptions.
|
||||
sympy.assumptions.ask.ask : Query for boolean expressions using assumptions.
|
||||
"""
|
||||
if not isinstance(expr, Basic):
|
||||
return expr
|
||||
|
||||
if not expr.is_Atom:
|
||||
args = [refine(arg, assumptions) for arg in expr.args]
|
||||
# TODO: this will probably not work with Integral or Polynomial
|
||||
expr = expr.func(*args)
|
||||
if hasattr(expr, '_eval_refine'):
|
||||
ref_expr = expr._eval_refine(assumptions)
|
||||
if ref_expr is not None:
|
||||
return ref_expr
|
||||
name = expr.__class__.__name__
|
||||
handler = handlers_dict.get(name, None)
|
||||
if handler is None:
|
||||
return expr
|
||||
new_expr = handler(expr, assumptions)
|
||||
if (new_expr is None) or (expr == new_expr):
|
||||
return expr
|
||||
if not isinstance(new_expr, Expr):
|
||||
return new_expr
|
||||
return refine(new_expr, assumptions)
|
||||
|
||||
|
||||
def refine_abs(expr, assumptions):
|
||||
"""
|
||||
Handler for the absolute value.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import Q, Abs
|
||||
>>> from sympy.assumptions.refine import refine_abs
|
||||
>>> from sympy.abc import x
|
||||
>>> refine_abs(Abs(x), Q.real(x))
|
||||
>>> refine_abs(Abs(x), Q.positive(x))
|
||||
x
|
||||
>>> refine_abs(Abs(x), Q.negative(x))
|
||||
-x
|
||||
|
||||
"""
|
||||
from sympy.functions.elementary.complexes import Abs
|
||||
arg = expr.args[0]
|
||||
if ask(Q.real(arg), assumptions) and \
|
||||
fuzzy_not(ask(Q.negative(arg), assumptions)):
|
||||
# if it's nonnegative
|
||||
return arg
|
||||
if ask(Q.negative(arg), assumptions):
|
||||
return -arg
|
||||
# arg is Mul
|
||||
if isinstance(arg, Mul):
|
||||
r = [refine(abs(a), assumptions) for a in arg.args]
|
||||
non_abs = []
|
||||
in_abs = []
|
||||
for i in r:
|
||||
if isinstance(i, Abs):
|
||||
in_abs.append(i.args[0])
|
||||
else:
|
||||
non_abs.append(i)
|
||||
return Mul(*non_abs) * Abs(Mul(*in_abs))
|
||||
|
||||
|
||||
def refine_Pow(expr, assumptions):
|
||||
"""
|
||||
Handler for instances of Pow.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import Q
|
||||
>>> from sympy.assumptions.refine import refine_Pow
|
||||
>>> from sympy.abc import x,y,z
|
||||
>>> refine_Pow((-1)**x, Q.real(x))
|
||||
>>> refine_Pow((-1)**x, Q.even(x))
|
||||
1
|
||||
>>> refine_Pow((-1)**x, Q.odd(x))
|
||||
-1
|
||||
|
||||
For powers of -1, even parts of the exponent can be simplified:
|
||||
|
||||
>>> refine_Pow((-1)**(x+y), Q.even(x))
|
||||
(-1)**y
|
||||
>>> refine_Pow((-1)**(x+y+z), Q.odd(x) & Q.odd(z))
|
||||
(-1)**y
|
||||
>>> refine_Pow((-1)**(x+y+2), Q.odd(x))
|
||||
(-1)**(y + 1)
|
||||
>>> refine_Pow((-1)**(x+3), True)
|
||||
(-1)**(x + 1)
|
||||
|
||||
"""
|
||||
from sympy.functions.elementary.complexes import Abs
|
||||
from sympy.functions import sign
|
||||
if isinstance(expr.base, Abs):
|
||||
if ask(Q.real(expr.base.args[0]), assumptions) and \
|
||||
ask(Q.even(expr.exp), assumptions):
|
||||
return expr.base.args[0] ** expr.exp
|
||||
if ask(Q.real(expr.base), assumptions):
|
||||
if expr.base.is_number:
|
||||
if ask(Q.even(expr.exp), assumptions):
|
||||
return abs(expr.base) ** expr.exp
|
||||
if ask(Q.odd(expr.exp), assumptions):
|
||||
return sign(expr.base) * abs(expr.base) ** expr.exp
|
||||
if isinstance(expr.exp, Rational):
|
||||
if isinstance(expr.base, Pow):
|
||||
return abs(expr.base.base) ** (expr.base.exp * expr.exp)
|
||||
|
||||
if expr.base is S.NegativeOne:
|
||||
if expr.exp.is_Add:
|
||||
|
||||
old = expr
|
||||
|
||||
# For powers of (-1) we can remove
|
||||
# - even terms
|
||||
# - pairs of odd terms
|
||||
# - a single odd term + 1
|
||||
# - A numerical constant N can be replaced with mod(N,2)
|
||||
|
||||
coeff, terms = expr.exp.as_coeff_add()
|
||||
terms = set(terms)
|
||||
even_terms = set()
|
||||
odd_terms = set()
|
||||
initial_number_of_terms = len(terms)
|
||||
|
||||
for t in terms:
|
||||
if ask(Q.even(t), assumptions):
|
||||
even_terms.add(t)
|
||||
elif ask(Q.odd(t), assumptions):
|
||||
odd_terms.add(t)
|
||||
|
||||
terms -= even_terms
|
||||
if len(odd_terms) % 2:
|
||||
terms -= odd_terms
|
||||
new_coeff = (coeff + S.One) % 2
|
||||
else:
|
||||
terms -= odd_terms
|
||||
new_coeff = coeff % 2
|
||||
|
||||
if new_coeff != coeff or len(terms) < initial_number_of_terms:
|
||||
terms.add(new_coeff)
|
||||
expr = expr.base**(Add(*terms))
|
||||
|
||||
# Handle (-1)**((-1)**n/2 + m/2)
|
||||
e2 = 2*expr.exp
|
||||
if ask(Q.even(e2), assumptions):
|
||||
if e2.could_extract_minus_sign():
|
||||
e2 *= expr.base
|
||||
if e2.is_Add:
|
||||
i, p = e2.as_two_terms()
|
||||
if p.is_Pow and p.base is S.NegativeOne:
|
||||
if ask(Q.integer(p.exp), assumptions):
|
||||
i = (i + 1)/2
|
||||
if ask(Q.even(i), assumptions):
|
||||
return expr.base**p.exp
|
||||
elif ask(Q.odd(i), assumptions):
|
||||
return expr.base**(p.exp + 1)
|
||||
else:
|
||||
return expr.base**(p.exp + i)
|
||||
|
||||
if old != expr:
|
||||
return expr
|
||||
|
||||
|
||||
def refine_atan2(expr, assumptions):
|
||||
"""
|
||||
Handler for the atan2 function.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import Q, atan2
|
||||
>>> from sympy.assumptions.refine import refine_atan2
|
||||
>>> from sympy.abc import x, y
|
||||
>>> refine_atan2(atan2(y,x), Q.real(y) & Q.positive(x))
|
||||
atan(y/x)
|
||||
>>> refine_atan2(atan2(y,x), Q.negative(y) & Q.negative(x))
|
||||
atan(y/x) - pi
|
||||
>>> refine_atan2(atan2(y,x), Q.positive(y) & Q.negative(x))
|
||||
atan(y/x) + pi
|
||||
>>> refine_atan2(atan2(y,x), Q.zero(y) & Q.negative(x))
|
||||
pi
|
||||
>>> refine_atan2(atan2(y,x), Q.positive(y) & Q.zero(x))
|
||||
pi/2
|
||||
>>> refine_atan2(atan2(y,x), Q.negative(y) & Q.zero(x))
|
||||
-pi/2
|
||||
>>> refine_atan2(atan2(y,x), Q.zero(y) & Q.zero(x))
|
||||
nan
|
||||
"""
|
||||
from sympy.functions.elementary.trigonometric import atan
|
||||
y, x = expr.args
|
||||
if ask(Q.real(y) & Q.positive(x), assumptions):
|
||||
return atan(y / x)
|
||||
elif ask(Q.negative(y) & Q.negative(x), assumptions):
|
||||
return atan(y / x) - S.Pi
|
||||
elif ask(Q.positive(y) & Q.negative(x), assumptions):
|
||||
return atan(y / x) + S.Pi
|
||||
elif ask(Q.zero(y) & Q.negative(x), assumptions):
|
||||
return S.Pi
|
||||
elif ask(Q.positive(y) & Q.zero(x), assumptions):
|
||||
return S.Pi/2
|
||||
elif ask(Q.negative(y) & Q.zero(x), assumptions):
|
||||
return -S.Pi/2
|
||||
elif ask(Q.zero(y) & Q.zero(x), assumptions):
|
||||
return S.NaN
|
||||
else:
|
||||
return expr
|
||||
|
||||
|
||||
def refine_re(expr, assumptions):
|
||||
"""
|
||||
Handler for real part.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.assumptions.refine import refine_re
|
||||
>>> from sympy import Q, re
|
||||
>>> from sympy.abc import x
|
||||
>>> refine_re(re(x), Q.real(x))
|
||||
x
|
||||
>>> refine_re(re(x), Q.imaginary(x))
|
||||
0
|
||||
"""
|
||||
arg = expr.args[0]
|
||||
if ask(Q.real(arg), assumptions):
|
||||
return arg
|
||||
if ask(Q.imaginary(arg), assumptions):
|
||||
return S.Zero
|
||||
return _refine_reim(expr, assumptions)
|
||||
|
||||
|
||||
def refine_im(expr, assumptions):
|
||||
"""
|
||||
Handler for imaginary part.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
>>> from sympy.assumptions.refine import refine_im
|
||||
>>> from sympy import Q, im
|
||||
>>> from sympy.abc import x
|
||||
>>> refine_im(im(x), Q.real(x))
|
||||
0
|
||||
>>> refine_im(im(x), Q.imaginary(x))
|
||||
-I*x
|
||||
"""
|
||||
arg = expr.args[0]
|
||||
if ask(Q.real(arg), assumptions):
|
||||
return S.Zero
|
||||
if ask(Q.imaginary(arg), assumptions):
|
||||
return - S.ImaginaryUnit * arg
|
||||
return _refine_reim(expr, assumptions)
|
||||
|
||||
def refine_arg(expr, assumptions):
|
||||
"""
|
||||
Handler for complex argument
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
>>> from sympy.assumptions.refine import refine_arg
|
||||
>>> from sympy import Q, arg
|
||||
>>> from sympy.abc import x
|
||||
>>> refine_arg(arg(x), Q.positive(x))
|
||||
0
|
||||
>>> refine_arg(arg(x), Q.negative(x))
|
||||
pi
|
||||
"""
|
||||
rg = expr.args[0]
|
||||
if ask(Q.positive(rg), assumptions):
|
||||
return S.Zero
|
||||
if ask(Q.negative(rg), assumptions):
|
||||
return S.Pi
|
||||
return None
|
||||
|
||||
|
||||
def _refine_reim(expr, assumptions):
|
||||
# Helper function for refine_re & refine_im
|
||||
expanded = expr.expand(complex = True)
|
||||
if expanded != expr:
|
||||
refined = refine(expanded, assumptions)
|
||||
if refined != expanded:
|
||||
return refined
|
||||
# Best to leave the expression as is
|
||||
return None
|
||||
|
||||
|
||||
def refine_sign(expr, assumptions):
|
||||
"""
|
||||
Handler for sign.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.assumptions.refine import refine_sign
|
||||
>>> from sympy import Symbol, Q, sign, im
|
||||
>>> x = Symbol('x', real = True)
|
||||
>>> expr = sign(x)
|
||||
>>> refine_sign(expr, Q.positive(x) & Q.nonzero(x))
|
||||
1
|
||||
>>> refine_sign(expr, Q.negative(x) & Q.nonzero(x))
|
||||
-1
|
||||
>>> refine_sign(expr, Q.zero(x))
|
||||
0
|
||||
>>> y = Symbol('y', imaginary = True)
|
||||
>>> expr = sign(y)
|
||||
>>> refine_sign(expr, Q.positive(im(y)))
|
||||
I
|
||||
>>> refine_sign(expr, Q.negative(im(y)))
|
||||
-I
|
||||
"""
|
||||
arg = expr.args[0]
|
||||
if ask(Q.zero(arg), assumptions):
|
||||
return S.Zero
|
||||
if ask(Q.real(arg)):
|
||||
if ask(Q.positive(arg), assumptions):
|
||||
return S.One
|
||||
if ask(Q.negative(arg), assumptions):
|
||||
return S.NegativeOne
|
||||
if ask(Q.imaginary(arg)):
|
||||
arg_re, arg_im = arg.as_real_imag()
|
||||
if ask(Q.positive(arg_im), assumptions):
|
||||
return S.ImaginaryUnit
|
||||
if ask(Q.negative(arg_im), assumptions):
|
||||
return -S.ImaginaryUnit
|
||||
return expr
|
||||
|
||||
|
||||
def refine_matrixelement(expr, assumptions):
|
||||
"""
|
||||
Handler for symmetric part.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.assumptions.refine import refine_matrixelement
|
||||
>>> from sympy import MatrixSymbol, Q
|
||||
>>> X = MatrixSymbol('X', 3, 3)
|
||||
>>> refine_matrixelement(X[0, 1], Q.symmetric(X))
|
||||
X[0, 1]
|
||||
>>> refine_matrixelement(X[1, 0], Q.symmetric(X))
|
||||
X[0, 1]
|
||||
"""
|
||||
from sympy.matrices.expressions.matexpr import MatrixElement
|
||||
matrix, i, j = expr.args
|
||||
if ask(Q.symmetric(matrix), assumptions):
|
||||
if (i - j).could_extract_minus_sign():
|
||||
return expr
|
||||
return MatrixElement(matrix, j, i)
|
||||
|
||||
handlers_dict: dict[str, Callable[[Expr, Boolean], Expr]] = {
|
||||
'Abs': refine_abs,
|
||||
'Pow': refine_Pow,
|
||||
'atan2': refine_atan2,
|
||||
're': refine_re,
|
||||
'im': refine_im,
|
||||
'arg': refine_arg,
|
||||
'sign': refine_sign,
|
||||
'MatrixElement': refine_matrixelement
|
||||
}
|
||||
Reference in New Issue
Block a user