chore: 添加虚拟环境到仓库
- 添加 backend_service/venv 虚拟环境 - 包含所有Python依赖包 - 注意:虚拟环境约393MB,包含12655个文件
This commit is contained in:
@@ -0,0 +1,485 @@
|
||||
"""A module which implements predicates and assumption context."""
|
||||
|
||||
from contextlib import contextmanager
|
||||
import inspect
|
||||
from sympy.core.symbol import Str
|
||||
from sympy.core.sympify import _sympify
|
||||
from sympy.logic.boolalg import Boolean, false, true
|
||||
from sympy.multipledispatch.dispatcher import Dispatcher, str_signature
|
||||
from sympy.utilities.exceptions import sympy_deprecation_warning
|
||||
from sympy.utilities.iterables import is_sequence
|
||||
from sympy.utilities.source import get_class
|
||||
|
||||
|
||||
class AssumptionsContext(set):
|
||||
"""
|
||||
Set containing default assumptions which are applied to the ``ask()``
|
||||
function.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
This is used to represent global assumptions, but you can also use this
|
||||
class to create your own local assumptions contexts. It is basically a thin
|
||||
wrapper to Python's set, so see its documentation for advanced usage.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
The default assumption context is ``global_assumptions``, which is initially empty:
|
||||
|
||||
>>> from sympy import ask, Q
|
||||
>>> from sympy.assumptions import global_assumptions
|
||||
>>> global_assumptions
|
||||
AssumptionsContext()
|
||||
|
||||
You can add default assumptions:
|
||||
|
||||
>>> from sympy.abc import x
|
||||
>>> global_assumptions.add(Q.real(x))
|
||||
>>> global_assumptions
|
||||
AssumptionsContext({Q.real(x)})
|
||||
>>> ask(Q.real(x))
|
||||
True
|
||||
|
||||
And remove them:
|
||||
|
||||
>>> global_assumptions.remove(Q.real(x))
|
||||
>>> print(ask(Q.real(x)))
|
||||
None
|
||||
|
||||
The ``clear()`` method removes every assumption:
|
||||
|
||||
>>> global_assumptions.add(Q.positive(x))
|
||||
>>> global_assumptions
|
||||
AssumptionsContext({Q.positive(x)})
|
||||
>>> global_assumptions.clear()
|
||||
>>> global_assumptions
|
||||
AssumptionsContext()
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
assuming
|
||||
|
||||
"""
|
||||
|
||||
def add(self, *assumptions):
|
||||
"""Add assumptions."""
|
||||
for a in assumptions:
|
||||
super().add(a)
|
||||
|
||||
def _sympystr(self, printer):
|
||||
if not self:
|
||||
return "%s()" % self.__class__.__name__
|
||||
return "{}({})".format(self.__class__.__name__, printer._print_set(self))
|
||||
|
||||
global_assumptions = AssumptionsContext()
|
||||
|
||||
|
||||
class AppliedPredicate(Boolean):
|
||||
"""
|
||||
The class of expressions resulting from applying ``Predicate`` to
|
||||
the arguments. ``AppliedPredicate`` merely wraps its argument and
|
||||
remain unevaluated. To evaluate it, use the ``ask()`` function.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import Q, ask
|
||||
>>> Q.integer(1)
|
||||
Q.integer(1)
|
||||
|
||||
The ``function`` attribute returns the predicate, and the ``arguments``
|
||||
attribute returns the tuple of arguments.
|
||||
|
||||
>>> type(Q.integer(1))
|
||||
<class 'sympy.assumptions.assume.AppliedPredicate'>
|
||||
>>> Q.integer(1).function
|
||||
Q.integer
|
||||
>>> Q.integer(1).arguments
|
||||
(1,)
|
||||
|
||||
Applied predicates can be evaluated to a boolean value with ``ask``:
|
||||
|
||||
>>> ask(Q.integer(1))
|
||||
True
|
||||
|
||||
"""
|
||||
__slots__ = ()
|
||||
|
||||
def __new__(cls, predicate, *args):
|
||||
if not isinstance(predicate, Predicate):
|
||||
raise TypeError("%s is not a Predicate." % predicate)
|
||||
args = map(_sympify, args)
|
||||
return super().__new__(cls, predicate, *args)
|
||||
|
||||
@property
|
||||
def arg(self):
|
||||
"""
|
||||
Return the expression used by this assumption.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import Q, Symbol
|
||||
>>> x = Symbol('x')
|
||||
>>> a = Q.integer(x + 1)
|
||||
>>> a.arg
|
||||
x + 1
|
||||
|
||||
"""
|
||||
# Will be deprecated
|
||||
args = self._args
|
||||
if len(args) == 2:
|
||||
# backwards compatibility
|
||||
return args[1]
|
||||
raise TypeError("'arg' property is allowed only for unary predicates.")
|
||||
|
||||
@property
|
||||
def function(self):
|
||||
"""
|
||||
Return the predicate.
|
||||
"""
|
||||
# Will be changed to self.args[0] after args overriding is removed
|
||||
return self._args[0]
|
||||
|
||||
@property
|
||||
def arguments(self):
|
||||
"""
|
||||
Return the arguments which are applied to the predicate.
|
||||
"""
|
||||
# Will be changed to self.args[1:] after args overriding is removed
|
||||
return self._args[1:]
|
||||
|
||||
def _eval_ask(self, assumptions):
|
||||
return self.function.eval(self.arguments, assumptions)
|
||||
|
||||
@property
|
||||
def binary_symbols(self):
|
||||
from .ask import Q
|
||||
if self.function == Q.is_true:
|
||||
i = self.arguments[0]
|
||||
if i.is_Boolean or i.is_Symbol:
|
||||
return i.binary_symbols
|
||||
if self.function in (Q.eq, Q.ne):
|
||||
if true in self.arguments or false in self.arguments:
|
||||
if self.arguments[0].is_Symbol:
|
||||
return {self.arguments[0]}
|
||||
elif self.arguments[1].is_Symbol:
|
||||
return {self.arguments[1]}
|
||||
return set()
|
||||
|
||||
|
||||
class PredicateMeta(type):
|
||||
def __new__(cls, clsname, bases, dct):
|
||||
# If handler is not defined, assign empty dispatcher.
|
||||
if "handler" not in dct:
|
||||
name = f"Ask{clsname.capitalize()}Handler"
|
||||
handler = Dispatcher(name, doc="Handler for key %s" % name)
|
||||
dct["handler"] = handler
|
||||
|
||||
dct["_orig_doc"] = dct.get("__doc__", "")
|
||||
|
||||
return super().__new__(cls, clsname, bases, dct)
|
||||
|
||||
@property
|
||||
def __doc__(cls):
|
||||
handler = cls.handler
|
||||
doc = cls._orig_doc
|
||||
if cls is not Predicate and handler is not None:
|
||||
doc += "Handler\n"
|
||||
doc += " =======\n\n"
|
||||
|
||||
# Append the handler's doc without breaking sphinx documentation.
|
||||
docs = [" Multiply dispatched method: %s" % handler.name]
|
||||
if handler.doc:
|
||||
for line in handler.doc.splitlines():
|
||||
if not line:
|
||||
continue
|
||||
docs.append(" %s" % line)
|
||||
other = []
|
||||
for sig in handler.ordering[::-1]:
|
||||
func = handler.funcs[sig]
|
||||
if func.__doc__:
|
||||
s = ' Inputs: <%s>' % str_signature(sig)
|
||||
lines = []
|
||||
for line in func.__doc__.splitlines():
|
||||
lines.append(" %s" % line)
|
||||
s += "\n".join(lines)
|
||||
docs.append(s)
|
||||
else:
|
||||
other.append(str_signature(sig))
|
||||
if other:
|
||||
othersig = " Other signatures:"
|
||||
for line in other:
|
||||
othersig += "\n * %s" % line
|
||||
docs.append(othersig)
|
||||
|
||||
doc += '\n\n'.join(docs)
|
||||
|
||||
return doc
|
||||
|
||||
|
||||
class Predicate(Boolean, metaclass=PredicateMeta):
|
||||
"""
|
||||
Base class for mathematical predicates. It also serves as a
|
||||
constructor for undefined predicate objects.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
Predicate is a function that returns a boolean value [1].
|
||||
|
||||
Predicate function is object, and it is instance of predicate class.
|
||||
When a predicate is applied to arguments, ``AppliedPredicate``
|
||||
instance is returned. This merely wraps the argument and remain
|
||||
unevaluated. To obtain the truth value of applied predicate, use the
|
||||
function ``ask``.
|
||||
|
||||
Evaluation of predicate is done by multiple dispatching. You can
|
||||
register new handler to the predicate to support new types.
|
||||
|
||||
Every predicate in SymPy can be accessed via the property of ``Q``.
|
||||
For example, ``Q.even`` returns the predicate which checks if the
|
||||
argument is even number.
|
||||
|
||||
To define a predicate which can be evaluated, you must subclass this
|
||||
class, make an instance of it, and register it to ``Q``. After then,
|
||||
dispatch the handler by argument types.
|
||||
|
||||
If you directly construct predicate using this class, you will get
|
||||
``UndefinedPredicate`` which cannot be dispatched. This is useful
|
||||
when you are building boolean expressions which do not need to be
|
||||
evaluated.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
Applying and evaluating to boolean value:
|
||||
|
||||
>>> from sympy import Q, ask
|
||||
>>> ask(Q.prime(7))
|
||||
True
|
||||
|
||||
You can define a new predicate by subclassing and dispatching. Here,
|
||||
we define a predicate for sexy primes [2] as an example.
|
||||
|
||||
>>> from sympy import Predicate, Integer
|
||||
>>> class SexyPrimePredicate(Predicate):
|
||||
... name = "sexyprime"
|
||||
>>> Q.sexyprime = SexyPrimePredicate()
|
||||
>>> @Q.sexyprime.register(Integer, Integer)
|
||||
... def _(int1, int2, assumptions):
|
||||
... args = sorted([int1, int2])
|
||||
... if not all(ask(Q.prime(a), assumptions) for a in args):
|
||||
... return False
|
||||
... return args[1] - args[0] == 6
|
||||
>>> ask(Q.sexyprime(5, 11))
|
||||
True
|
||||
|
||||
Direct constructing returns ``UndefinedPredicate``, which can be
|
||||
applied but cannot be dispatched.
|
||||
|
||||
>>> from sympy import Predicate, Integer
|
||||
>>> Q.P = Predicate("P")
|
||||
>>> type(Q.P)
|
||||
<class 'sympy.assumptions.assume.UndefinedPredicate'>
|
||||
>>> Q.P(1)
|
||||
Q.P(1)
|
||||
>>> Q.P.register(Integer)(lambda expr, assump: True)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
TypeError: <class 'sympy.assumptions.assume.UndefinedPredicate'> cannot be dispatched.
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Predicate_%28mathematical_logic%29
|
||||
.. [2] https://en.wikipedia.org/wiki/Sexy_prime
|
||||
|
||||
"""
|
||||
|
||||
is_Atom = True
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
if cls is Predicate:
|
||||
return UndefinedPredicate(*args, **kwargs)
|
||||
obj = super().__new__(cls, *args)
|
||||
return obj
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
# May be overridden
|
||||
return type(self).__name__
|
||||
|
||||
@classmethod
|
||||
def register(cls, *types, **kwargs):
|
||||
"""
|
||||
Register the signature to the handler.
|
||||
"""
|
||||
if cls.handler is None:
|
||||
raise TypeError("%s cannot be dispatched." % type(cls))
|
||||
return cls.handler.register(*types, **kwargs)
|
||||
|
||||
@classmethod
|
||||
def register_many(cls, *types, **kwargs):
|
||||
"""
|
||||
Register multiple signatures to same handler.
|
||||
"""
|
||||
def _(func):
|
||||
for t in types:
|
||||
if not is_sequence(t):
|
||||
t = (t,) # for convenience, allow passing `type` to mean `(type,)`
|
||||
cls.register(*t, **kwargs)(func)
|
||||
return _
|
||||
|
||||
def __call__(self, *args):
|
||||
return AppliedPredicate(self, *args)
|
||||
|
||||
def eval(self, args, assumptions=True):
|
||||
"""
|
||||
Evaluate ``self(*args)`` under the given assumptions.
|
||||
|
||||
This uses only direct resolution methods, not logical inference.
|
||||
"""
|
||||
result = None
|
||||
try:
|
||||
result = self.handler(*args, assumptions=assumptions)
|
||||
except NotImplementedError:
|
||||
pass
|
||||
return result
|
||||
|
||||
def _eval_refine(self, assumptions):
|
||||
# When Predicate is no longer Boolean, delete this method
|
||||
return self
|
||||
|
||||
|
||||
class UndefinedPredicate(Predicate):
|
||||
"""
|
||||
Predicate without handler.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
This predicate is generated by using ``Predicate`` directly for
|
||||
construction. It does not have a handler, and evaluating this with
|
||||
arguments is done by SAT solver.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import Predicate, Q
|
||||
>>> Q.P = Predicate('P')
|
||||
>>> Q.P.func
|
||||
<class 'sympy.assumptions.assume.UndefinedPredicate'>
|
||||
>>> Q.P.name
|
||||
Str('P')
|
||||
|
||||
"""
|
||||
|
||||
handler = None
|
||||
|
||||
def __new__(cls, name, handlers=None):
|
||||
# "handlers" parameter supports old design
|
||||
if not isinstance(name, Str):
|
||||
name = Str(name)
|
||||
obj = super(Boolean, cls).__new__(cls, name)
|
||||
obj.handlers = handlers or []
|
||||
return obj
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self.args[0]
|
||||
|
||||
def _hashable_content(self):
|
||||
return (self.name,)
|
||||
|
||||
def __getnewargs__(self):
|
||||
return (self.name,)
|
||||
|
||||
def __call__(self, expr):
|
||||
return AppliedPredicate(self, expr)
|
||||
|
||||
def add_handler(self, handler):
|
||||
sympy_deprecation_warning(
|
||||
"""
|
||||
The AskHandler system is deprecated. Predicate.add_handler()
|
||||
should be replaced with the multipledispatch handler of Predicate.
|
||||
""",
|
||||
deprecated_since_version="1.8",
|
||||
active_deprecations_target='deprecated-askhandler',
|
||||
)
|
||||
self.handlers.append(handler)
|
||||
|
||||
def remove_handler(self, handler):
|
||||
sympy_deprecation_warning(
|
||||
"""
|
||||
The AskHandler system is deprecated. Predicate.remove_handler()
|
||||
should be replaced with the multipledispatch handler of Predicate.
|
||||
""",
|
||||
deprecated_since_version="1.8",
|
||||
active_deprecations_target='deprecated-askhandler',
|
||||
)
|
||||
self.handlers.remove(handler)
|
||||
|
||||
def eval(self, args, assumptions=True):
|
||||
# Support for deprecated design
|
||||
# When old design is removed, this will always return None
|
||||
sympy_deprecation_warning(
|
||||
"""
|
||||
The AskHandler system is deprecated. Evaluating UndefinedPredicate
|
||||
objects should be replaced with the multipledispatch handler of
|
||||
Predicate.
|
||||
""",
|
||||
deprecated_since_version="1.8",
|
||||
active_deprecations_target='deprecated-askhandler',
|
||||
stacklevel=5,
|
||||
)
|
||||
expr, = args
|
||||
res, _res = None, None
|
||||
mro = inspect.getmro(type(expr))
|
||||
for handler in self.handlers:
|
||||
cls = get_class(handler)
|
||||
for subclass in mro:
|
||||
eval_ = getattr(cls, subclass.__name__, None)
|
||||
if eval_ is None:
|
||||
continue
|
||||
res = eval_(expr, assumptions)
|
||||
# Do not stop if value returned is None
|
||||
# Try to check for higher classes
|
||||
if res is None:
|
||||
continue
|
||||
if _res is None:
|
||||
_res = res
|
||||
else:
|
||||
# only check consistency if both resolutors have concluded
|
||||
if _res != res:
|
||||
raise ValueError('incompatible resolutors')
|
||||
break
|
||||
return res
|
||||
|
||||
|
||||
@contextmanager
|
||||
def assuming(*assumptions):
|
||||
"""
|
||||
Context manager for assumptions.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import assuming, Q, ask
|
||||
>>> from sympy.abc import x, y
|
||||
>>> print(ask(Q.integer(x + y)))
|
||||
None
|
||||
>>> with assuming(Q.integer(x), Q.integer(y)):
|
||||
... print(ask(Q.integer(x + y)))
|
||||
True
|
||||
"""
|
||||
old_global_assumptions = global_assumptions.copy()
|
||||
global_assumptions.update(assumptions)
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
global_assumptions.clear()
|
||||
global_assumptions.update(old_global_assumptions)
|
||||
Reference in New Issue
Block a user