chore: 添加虚拟环境到仓库
- 添加 backend_service/venv 虚拟环境 - 包含所有Python依赖包 - 注意:虚拟环境约393MB,包含12655个文件
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
from .sets import (Set, Interval, Union, FiniteSet, ProductSet,
|
||||
Intersection, imageset, Complement, SymmetricDifference,
|
||||
DisjointUnion)
|
||||
|
||||
from .fancysets import ImageSet, Range, ComplexRegion
|
||||
from .contains import Contains
|
||||
from .conditionset import ConditionSet
|
||||
from .ordinals import Ordinal, OmegaPower, ord0
|
||||
from .powerset import PowerSet
|
||||
from ..core.singleton import S
|
||||
from .handlers.comparison import _eval_is_eq # noqa:F401
|
||||
Complexes = S.Complexes
|
||||
EmptySet = S.EmptySet
|
||||
Integers = S.Integers
|
||||
Naturals = S.Naturals
|
||||
Naturals0 = S.Naturals0
|
||||
Rationals = S.Rationals
|
||||
Reals = S.Reals
|
||||
UniversalSet = S.UniversalSet
|
||||
|
||||
__all__ = [
|
||||
'Set', 'Interval', 'Union', 'EmptySet', 'FiniteSet', 'ProductSet',
|
||||
'Intersection', 'imageset', 'Complement', 'SymmetricDifference', 'DisjointUnion',
|
||||
|
||||
'ImageSet', 'Range', 'ComplexRegion', 'Reals',
|
||||
|
||||
'Contains',
|
||||
|
||||
'ConditionSet',
|
||||
|
||||
'Ordinal', 'OmegaPower', 'ord0',
|
||||
|
||||
'PowerSet',
|
||||
|
||||
'Reals', 'Naturals', 'Naturals0', 'UniversalSet', 'Integers', 'Rationals',
|
||||
]
|
||||
@@ -0,0 +1,246 @@
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.basic import Basic
|
||||
from sympy.core.containers import Tuple
|
||||
from sympy.core.function import Lambda, BadSignatureError
|
||||
from sympy.core.logic import fuzzy_bool
|
||||
from sympy.core.relational import Eq
|
||||
from sympy.core.symbol import Dummy
|
||||
from sympy.core.sympify import _sympify
|
||||
from sympy.logic.boolalg import And, as_Boolean
|
||||
from sympy.utilities.iterables import sift, flatten, has_dups
|
||||
from sympy.utilities.exceptions import sympy_deprecation_warning
|
||||
from .contains import Contains
|
||||
from .sets import Set, Union, FiniteSet, SetKind
|
||||
|
||||
|
||||
adummy = Dummy('conditionset')
|
||||
|
||||
|
||||
class ConditionSet(Set):
|
||||
r"""
|
||||
Set of elements which satisfies a given condition.
|
||||
|
||||
.. math:: \{x \mid \textrm{condition}(x) = \texttt{True}, x \in S\}
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import Symbol, S, ConditionSet, pi, Eq, sin, Interval
|
||||
>>> from sympy.abc import x, y, z
|
||||
|
||||
>>> sin_sols = ConditionSet(x, Eq(sin(x), 0), Interval(0, 2*pi))
|
||||
>>> 2*pi in sin_sols
|
||||
True
|
||||
>>> pi/2 in sin_sols
|
||||
False
|
||||
>>> 3*pi in sin_sols
|
||||
False
|
||||
>>> 5 in ConditionSet(x, x**2 > 4, S.Reals)
|
||||
True
|
||||
|
||||
If the value is not in the base set, the result is false:
|
||||
|
||||
>>> 5 in ConditionSet(x, x**2 > 4, Interval(2, 4))
|
||||
False
|
||||
|
||||
Notes
|
||||
=====
|
||||
|
||||
Symbols with assumptions should be avoided or else the
|
||||
condition may evaluate without consideration of the set:
|
||||
|
||||
>>> n = Symbol('n', negative=True)
|
||||
>>> cond = (n > 0); cond
|
||||
False
|
||||
>>> ConditionSet(n, cond, S.Integers)
|
||||
EmptySet
|
||||
|
||||
Only free symbols can be changed by using `subs`:
|
||||
|
||||
>>> c = ConditionSet(x, x < 1, {x, z})
|
||||
>>> c.subs(x, y)
|
||||
ConditionSet(x, x < 1, {y, z})
|
||||
|
||||
To check if ``pi`` is in ``c`` use:
|
||||
|
||||
>>> pi in c
|
||||
False
|
||||
|
||||
If no base set is specified, the universal set is implied:
|
||||
|
||||
>>> ConditionSet(x, x < 1).base_set
|
||||
UniversalSet
|
||||
|
||||
Only symbols or symbol-like expressions can be used:
|
||||
|
||||
>>> ConditionSet(x + 1, x + 1 < 1, S.Integers)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: non-symbol dummy not recognized in condition
|
||||
|
||||
When the base set is a ConditionSet, the symbols will be
|
||||
unified if possible with preference for the outermost symbols:
|
||||
|
||||
>>> ConditionSet(x, x < y, ConditionSet(z, z + y < 2, S.Integers))
|
||||
ConditionSet(x, (x < y) & (x + y < 2), Integers)
|
||||
|
||||
"""
|
||||
def __new__(cls, sym, condition, base_set=S.UniversalSet):
|
||||
sym = _sympify(sym)
|
||||
flat = flatten([sym])
|
||||
if has_dups(flat):
|
||||
raise BadSignatureError("Duplicate symbols detected")
|
||||
base_set = _sympify(base_set)
|
||||
if not isinstance(base_set, Set):
|
||||
raise TypeError(
|
||||
'base set should be a Set object, not %s' % base_set)
|
||||
condition = _sympify(condition)
|
||||
|
||||
if isinstance(condition, FiniteSet):
|
||||
condition_orig = condition
|
||||
temp = (Eq(lhs, 0) for lhs in condition)
|
||||
condition = And(*temp)
|
||||
sympy_deprecation_warning(
|
||||
f"""
|
||||
Using a set for the condition in ConditionSet is deprecated. Use a boolean
|
||||
instead.
|
||||
|
||||
In this case, replace
|
||||
|
||||
{condition_orig}
|
||||
|
||||
with
|
||||
|
||||
{condition}
|
||||
""",
|
||||
deprecated_since_version='1.5',
|
||||
active_deprecations_target="deprecated-conditionset-set",
|
||||
)
|
||||
|
||||
condition = as_Boolean(condition)
|
||||
|
||||
if condition is S.true:
|
||||
return base_set
|
||||
|
||||
if condition is S.false:
|
||||
return S.EmptySet
|
||||
|
||||
if base_set is S.EmptySet:
|
||||
return S.EmptySet
|
||||
|
||||
# no simple answers, so now check syms
|
||||
for i in flat:
|
||||
if not getattr(i, '_diff_wrt', False):
|
||||
raise ValueError('`%s` is not symbol-like' % i)
|
||||
|
||||
if base_set.contains(sym) is S.false:
|
||||
raise TypeError('sym `%s` is not in base_set `%s`' % (sym, base_set))
|
||||
|
||||
know = None
|
||||
if isinstance(base_set, FiniteSet):
|
||||
sifted = sift(
|
||||
base_set, lambda _: fuzzy_bool(condition.subs(sym, _)))
|
||||
if sifted[None]:
|
||||
know = FiniteSet(*sifted[True])
|
||||
base_set = FiniteSet(*sifted[None])
|
||||
else:
|
||||
return FiniteSet(*sifted[True])
|
||||
|
||||
if isinstance(base_set, cls):
|
||||
s, c, b = base_set.args
|
||||
def sig(s):
|
||||
return cls(s, Eq(adummy, 0)).as_dummy().sym
|
||||
sa, sb = map(sig, (sym, s))
|
||||
if sa != sb:
|
||||
raise BadSignatureError('sym does not match sym of base set')
|
||||
reps = dict(zip(flatten([sym]), flatten([s])))
|
||||
if s == sym:
|
||||
condition = And(condition, c)
|
||||
base_set = b
|
||||
elif not c.free_symbols & sym.free_symbols:
|
||||
reps = {v: k for k, v in reps.items()}
|
||||
condition = And(condition, c.xreplace(reps))
|
||||
base_set = b
|
||||
elif not condition.free_symbols & s.free_symbols:
|
||||
sym = sym.xreplace(reps)
|
||||
condition = And(condition.xreplace(reps), c)
|
||||
base_set = b
|
||||
|
||||
# flatten ConditionSet(Contains(ConditionSet())) expressions
|
||||
if isinstance(condition, Contains) and (sym == condition.args[0]):
|
||||
if isinstance(condition.args[1], Set):
|
||||
return condition.args[1].intersect(base_set)
|
||||
|
||||
rv = Basic.__new__(cls, sym, condition, base_set)
|
||||
return rv if know is None else Union(know, rv)
|
||||
|
||||
sym = property(lambda self: self.args[0])
|
||||
condition = property(lambda self: self.args[1])
|
||||
base_set = property(lambda self: self.args[2])
|
||||
|
||||
@property
|
||||
def free_symbols(self):
|
||||
cond_syms = self.condition.free_symbols - self.sym.free_symbols
|
||||
return cond_syms | self.base_set.free_symbols
|
||||
|
||||
@property
|
||||
def bound_symbols(self):
|
||||
return flatten([self.sym])
|
||||
|
||||
def _contains(self, other):
|
||||
def ok_sig(a, b):
|
||||
tuples = [isinstance(i, Tuple) for i in (a, b)]
|
||||
c = tuples.count(True)
|
||||
if c == 1:
|
||||
return False
|
||||
if c == 0:
|
||||
return True
|
||||
return len(a) == len(b) and all(
|
||||
ok_sig(i, j) for i, j in zip(a, b))
|
||||
if not ok_sig(self.sym, other):
|
||||
return S.false
|
||||
|
||||
# try doing base_cond first and return
|
||||
# False immediately if it is False
|
||||
base_cond = Contains(other, self.base_set)
|
||||
if base_cond is S.false:
|
||||
return S.false
|
||||
|
||||
# Substitute other into condition. This could raise e.g. for
|
||||
# ConditionSet(x, 1/x >= 0, Reals).contains(0)
|
||||
lamda = Lambda((self.sym,), self.condition)
|
||||
try:
|
||||
lambda_cond = lamda(other)
|
||||
except TypeError:
|
||||
return None
|
||||
else:
|
||||
return And(base_cond, lambda_cond)
|
||||
|
||||
def as_relational(self, other):
|
||||
f = Lambda(self.sym, self.condition)
|
||||
if isinstance(self.sym, Tuple):
|
||||
f = f(*other)
|
||||
else:
|
||||
f = f(other)
|
||||
return And(f, self.base_set.contains(other))
|
||||
|
||||
def _eval_subs(self, old, new):
|
||||
sym, cond, base = self.args
|
||||
dsym = sym.subs(old, adummy)
|
||||
insym = dsym.has(adummy)
|
||||
# prioritize changing a symbol in the base
|
||||
newbase = base.subs(old, new)
|
||||
if newbase != base:
|
||||
if not insym:
|
||||
cond = cond.subs(old, new)
|
||||
return self.func(sym, cond, newbase)
|
||||
if insym:
|
||||
pass # no change of bound symbols via subs
|
||||
elif getattr(new, '_diff_wrt', False):
|
||||
cond = cond.subs(old, new)
|
||||
else:
|
||||
pass # let error about the symbol raise from __new__
|
||||
return self.func(sym, cond, base)
|
||||
|
||||
def _kind(self):
|
||||
return SetKind(self.sym.kind)
|
||||
@@ -0,0 +1,63 @@
|
||||
from sympy.core import S
|
||||
from sympy.core.sympify import sympify
|
||||
from sympy.core.relational import Eq, Ne
|
||||
from sympy.core.parameters import global_parameters
|
||||
from sympy.logic.boolalg import Boolean
|
||||
from sympy.utilities.misc import func_name
|
||||
from .sets import Set
|
||||
|
||||
|
||||
class Contains(Boolean):
|
||||
"""
|
||||
Asserts that x is an element of the set S.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import Symbol, Integer, S, Contains
|
||||
>>> Contains(Integer(2), S.Integers)
|
||||
True
|
||||
>>> Contains(Integer(-2), S.Naturals)
|
||||
False
|
||||
>>> i = Symbol('i', integer=True)
|
||||
>>> Contains(i, S.Naturals)
|
||||
Contains(i, Naturals)
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Element_%28mathematics%29
|
||||
"""
|
||||
def __new__(cls, x, s, evaluate=None):
|
||||
x = sympify(x)
|
||||
s = sympify(s)
|
||||
|
||||
if evaluate is None:
|
||||
evaluate = global_parameters.evaluate
|
||||
|
||||
if not isinstance(s, Set):
|
||||
raise TypeError('expecting Set, not %s' % func_name(s))
|
||||
|
||||
if evaluate:
|
||||
# _contains can return symbolic booleans that would be returned by
|
||||
# s.contains(x) but here for Contains(x, s) we only evaluate to
|
||||
# true, false or return the unevaluated Contains.
|
||||
result = s._contains(x)
|
||||
|
||||
if isinstance(result, Boolean):
|
||||
if result in (S.true, S.false):
|
||||
return result
|
||||
elif result is not None:
|
||||
raise TypeError("_contains() should return Boolean or None")
|
||||
|
||||
return super().__new__(cls, x, s)
|
||||
|
||||
@property
|
||||
def binary_symbols(self):
|
||||
return set().union(*[i.binary_symbols
|
||||
for i in self.args[1].args
|
||||
if i.is_Boolean or i.is_Symbol or
|
||||
isinstance(i, (Eq, Ne))])
|
||||
|
||||
def as_set(self):
|
||||
return self.args[1]
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,79 @@
|
||||
from sympy.core.numbers import oo, Infinity, NegativeInfinity
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core import Basic, Expr
|
||||
from sympy.multipledispatch import Dispatcher
|
||||
from sympy.sets import Interval, FiniteSet
|
||||
|
||||
|
||||
|
||||
# XXX: The functions in this module are clearly not tested and are broken in a
|
||||
# number of ways.
|
||||
|
||||
_set_add = Dispatcher('_set_add')
|
||||
_set_sub = Dispatcher('_set_sub')
|
||||
|
||||
|
||||
@_set_add.register(Basic, Basic)
|
||||
def _(x, y):
|
||||
return None
|
||||
|
||||
|
||||
@_set_add.register(Expr, Expr)
|
||||
def _(x, y):
|
||||
return x+y
|
||||
|
||||
|
||||
@_set_add.register(Interval, Interval)
|
||||
def _(x, y):
|
||||
"""
|
||||
Additions in interval arithmetic
|
||||
https://en.wikipedia.org/wiki/Interval_arithmetic
|
||||
"""
|
||||
return Interval(x.start + y.start, x.end + y.end,
|
||||
x.left_open or y.left_open, x.right_open or y.right_open)
|
||||
|
||||
|
||||
@_set_add.register(Interval, Infinity)
|
||||
def _(x, y):
|
||||
if x.start is S.NegativeInfinity:
|
||||
return Interval(-oo, oo)
|
||||
return FiniteSet({S.Infinity})
|
||||
|
||||
@_set_add.register(Interval, NegativeInfinity)
|
||||
def _(x, y):
|
||||
if x.end is S.Infinity:
|
||||
return Interval(-oo, oo)
|
||||
return FiniteSet({S.NegativeInfinity})
|
||||
|
||||
|
||||
@_set_sub.register(Basic, Basic)
|
||||
def _(x, y):
|
||||
return None
|
||||
|
||||
|
||||
@_set_sub.register(Expr, Expr)
|
||||
def _(x, y):
|
||||
return x-y
|
||||
|
||||
|
||||
@_set_sub.register(Interval, Interval)
|
||||
def _(x, y):
|
||||
"""
|
||||
Subtractions in interval arithmetic
|
||||
https://en.wikipedia.org/wiki/Interval_arithmetic
|
||||
"""
|
||||
return Interval(x.start - y.end, x.end - y.start,
|
||||
x.left_open or y.right_open, x.right_open or y.left_open)
|
||||
|
||||
|
||||
@_set_sub.register(Interval, Infinity)
|
||||
def _(x, y):
|
||||
if x.start is S.NegativeInfinity:
|
||||
return Interval(-oo, oo)
|
||||
return FiniteSet(-oo)
|
||||
|
||||
@_set_sub.register(Interval, NegativeInfinity)
|
||||
def _(x, y):
|
||||
if x.start is S.NegativeInfinity:
|
||||
return Interval(-oo, oo)
|
||||
return FiniteSet(-oo)
|
||||
@@ -0,0 +1,53 @@
|
||||
from sympy.core.relational import Eq, is_eq
|
||||
from sympy.core.basic import Basic
|
||||
from sympy.core.logic import fuzzy_and, fuzzy_bool
|
||||
from sympy.logic.boolalg import And
|
||||
from sympy.multipledispatch import dispatch
|
||||
from sympy.sets.sets import tfn, ProductSet, Interval, FiniteSet, Set
|
||||
|
||||
|
||||
@dispatch(Interval, FiniteSet) # type:ignore
|
||||
def _eval_is_eq(lhs, rhs): # noqa: F811
|
||||
return False
|
||||
|
||||
|
||||
@dispatch(FiniteSet, Interval) # type:ignore
|
||||
def _eval_is_eq(lhs, rhs): # noqa: F811
|
||||
return False
|
||||
|
||||
|
||||
@dispatch(Interval, Interval) # type:ignore
|
||||
def _eval_is_eq(lhs, rhs): # noqa: F811
|
||||
return And(Eq(lhs.left, rhs.left),
|
||||
Eq(lhs.right, rhs.right),
|
||||
lhs.left_open == rhs.left_open,
|
||||
lhs.right_open == rhs.right_open)
|
||||
|
||||
@dispatch(FiniteSet, FiniteSet) # type:ignore
|
||||
def _eval_is_eq(lhs, rhs): # noqa: F811
|
||||
def all_in_both():
|
||||
s_set = set(lhs.args)
|
||||
o_set = set(rhs.args)
|
||||
yield fuzzy_and(lhs._contains(e) for e in o_set - s_set)
|
||||
yield fuzzy_and(rhs._contains(e) for e in s_set - o_set)
|
||||
|
||||
return tfn[fuzzy_and(all_in_both())]
|
||||
|
||||
|
||||
@dispatch(ProductSet, ProductSet) # type:ignore
|
||||
def _eval_is_eq(lhs, rhs): # noqa: F811
|
||||
if len(lhs.sets) != len(rhs.sets):
|
||||
return False
|
||||
|
||||
eqs = (is_eq(x, y) for x, y in zip(lhs.sets, rhs.sets))
|
||||
return tfn[fuzzy_and(map(fuzzy_bool, eqs))]
|
||||
|
||||
|
||||
@dispatch(Set, Basic) # type:ignore
|
||||
def _eval_is_eq(lhs, rhs): # noqa: F811
|
||||
return False
|
||||
|
||||
|
||||
@dispatch(Set, Set) # type:ignore
|
||||
def _eval_is_eq(lhs, rhs): # noqa: F811
|
||||
return tfn[fuzzy_and(a.is_subset(b) for a, b in [(lhs, rhs), (rhs, lhs)])]
|
||||
@@ -0,0 +1,262 @@
|
||||
from sympy.core.singleton import S
|
||||
from sympy.sets.sets import Set
|
||||
from sympy.calculus.singularities import singularities
|
||||
from sympy.core import Expr, Add
|
||||
from sympy.core.function import Lambda, FunctionClass, diff, expand_mul
|
||||
from sympy.core.numbers import Float, oo
|
||||
from sympy.core.symbol import Dummy, symbols, Wild
|
||||
from sympy.functions.elementary.exponential import exp, log
|
||||
from sympy.functions.elementary.miscellaneous import Min, Max
|
||||
from sympy.logic.boolalg import true
|
||||
from sympy.multipledispatch import Dispatcher
|
||||
from sympy.sets import (imageset, Interval, FiniteSet, Union, ImageSet,
|
||||
Intersection, Range, Complement)
|
||||
from sympy.sets.sets import EmptySet, is_function_invertible_in_set
|
||||
from sympy.sets.fancysets import Integers, Naturals, Reals
|
||||
from sympy.functions.elementary.exponential import match_real_imag
|
||||
|
||||
|
||||
_x, _y = symbols("x y")
|
||||
|
||||
FunctionUnion = (FunctionClass, Lambda)
|
||||
|
||||
_set_function = Dispatcher('_set_function')
|
||||
|
||||
|
||||
@_set_function.register(FunctionClass, Set)
|
||||
def _(f, x):
|
||||
return None
|
||||
|
||||
@_set_function.register(FunctionUnion, FiniteSet)
|
||||
def _(f, x):
|
||||
return FiniteSet(*map(f, x))
|
||||
|
||||
@_set_function.register(Lambda, Interval)
|
||||
def _(f, x):
|
||||
from sympy.solvers.solveset import solveset
|
||||
from sympy.series import limit
|
||||
# TODO: handle functions with infinitely many solutions (eg, sin, tan)
|
||||
# TODO: handle multivariate functions
|
||||
|
||||
expr = f.expr
|
||||
if len(expr.free_symbols) > 1 or len(f.variables) != 1:
|
||||
return
|
||||
var = f.variables[0]
|
||||
if not var.is_real:
|
||||
if expr.subs(var, Dummy(real=True)).is_real is False:
|
||||
return
|
||||
|
||||
if expr.is_Piecewise:
|
||||
result = S.EmptySet
|
||||
domain_set = x
|
||||
for (p_expr, p_cond) in expr.args:
|
||||
if p_cond is true:
|
||||
intrvl = domain_set
|
||||
else:
|
||||
intrvl = p_cond.as_set()
|
||||
intrvl = Intersection(domain_set, intrvl)
|
||||
|
||||
if p_expr.is_Number:
|
||||
image = FiniteSet(p_expr)
|
||||
else:
|
||||
image = imageset(Lambda(var, p_expr), intrvl)
|
||||
result = Union(result, image)
|
||||
|
||||
# remove the part which has been `imaged`
|
||||
domain_set = Complement(domain_set, intrvl)
|
||||
if domain_set is S.EmptySet:
|
||||
break
|
||||
return result
|
||||
|
||||
if not x.start.is_comparable or not x.end.is_comparable:
|
||||
return
|
||||
|
||||
try:
|
||||
from sympy.polys.polyutils import _nsort
|
||||
sing = list(singularities(expr, var, x))
|
||||
if len(sing) > 1:
|
||||
sing = _nsort(sing)
|
||||
except NotImplementedError:
|
||||
return
|
||||
|
||||
if x.left_open:
|
||||
_start = limit(expr, var, x.start, dir="+")
|
||||
elif x.start not in sing:
|
||||
_start = f(x.start)
|
||||
if x.right_open:
|
||||
_end = limit(expr, var, x.end, dir="-")
|
||||
elif x.end not in sing:
|
||||
_end = f(x.end)
|
||||
|
||||
if len(sing) == 0:
|
||||
soln_expr = solveset(diff(expr, var), var)
|
||||
if not (isinstance(soln_expr, FiniteSet)
|
||||
or soln_expr is S.EmptySet):
|
||||
return
|
||||
solns = list(soln_expr)
|
||||
|
||||
extr = [_start, _end] + [f(i) for i in solns
|
||||
if i.is_real and i in x]
|
||||
start, end = Min(*extr), Max(*extr)
|
||||
|
||||
left_open, right_open = False, False
|
||||
if _start <= _end:
|
||||
# the minimum or maximum value can occur simultaneously
|
||||
# on both the edge of the interval and in some interior
|
||||
# point
|
||||
if start == _start and start not in solns:
|
||||
left_open = x.left_open
|
||||
if end == _end and end not in solns:
|
||||
right_open = x.right_open
|
||||
else:
|
||||
if start == _end and start not in solns:
|
||||
left_open = x.right_open
|
||||
if end == _start and end not in solns:
|
||||
right_open = x.left_open
|
||||
|
||||
return Interval(start, end, left_open, right_open)
|
||||
else:
|
||||
return imageset(f, Interval(x.start, sing[0],
|
||||
x.left_open, True)) + \
|
||||
Union(*[imageset(f, Interval(sing[i], sing[i + 1], True, True))
|
||||
for i in range(0, len(sing) - 1)]) + \
|
||||
imageset(f, Interval(sing[-1], x.end, True, x.right_open))
|
||||
|
||||
@_set_function.register(FunctionClass, Interval)
|
||||
def _(f, x):
|
||||
if f == exp:
|
||||
return Interval(exp(x.start), exp(x.end), x.left_open, x.right_open)
|
||||
elif f == log:
|
||||
return Interval(log(x.start), log(x.end), x.left_open, x.right_open)
|
||||
return ImageSet(Lambda(_x, f(_x)), x)
|
||||
|
||||
@_set_function.register(FunctionUnion, Union)
|
||||
def _(f, x):
|
||||
return Union(*(imageset(f, arg) for arg in x.args))
|
||||
|
||||
@_set_function.register(FunctionUnion, Intersection)
|
||||
def _(f, x):
|
||||
# If the function is invertible, intersect the maps of the sets.
|
||||
if is_function_invertible_in_set(f, x):
|
||||
return Intersection(*(imageset(f, arg) for arg in x.args))
|
||||
else:
|
||||
return ImageSet(Lambda(_x, f(_x)), x)
|
||||
|
||||
@_set_function.register(FunctionUnion, EmptySet)
|
||||
def _(f, x):
|
||||
return x
|
||||
|
||||
@_set_function.register(FunctionUnion, Set)
|
||||
def _(f, x):
|
||||
return ImageSet(Lambda(_x, f(_x)), x)
|
||||
|
||||
@_set_function.register(FunctionUnion, Range)
|
||||
def _(f, self):
|
||||
if not self:
|
||||
return S.EmptySet
|
||||
if not isinstance(f.expr, Expr):
|
||||
return
|
||||
if self.size == 1:
|
||||
return FiniteSet(f(self[0]))
|
||||
if f is S.IdentityFunction:
|
||||
return self
|
||||
|
||||
x = f.variables[0]
|
||||
expr = f.expr
|
||||
# handle f that is linear in f's variable
|
||||
if x not in expr.free_symbols or x in expr.diff(x).free_symbols:
|
||||
return
|
||||
if self.start.is_finite:
|
||||
F = f(self.step*x + self.start) # for i in range(len(self))
|
||||
else:
|
||||
F = f(-self.step*x + self[-1])
|
||||
F = expand_mul(F)
|
||||
if F != expr:
|
||||
return imageset(x, F, Range(self.size))
|
||||
|
||||
@_set_function.register(FunctionUnion, Integers)
|
||||
def _(f, self):
|
||||
expr = f.expr
|
||||
if not isinstance(expr, Expr):
|
||||
return
|
||||
|
||||
n = f.variables[0]
|
||||
if expr == abs(n):
|
||||
return S.Naturals0
|
||||
|
||||
# f(x) + c and f(-x) + c cover the same integers
|
||||
# so choose the form that has the fewest negatives
|
||||
c = f(0)
|
||||
fx = f(n) - c
|
||||
f_x = f(-n) - c
|
||||
neg_count = lambda e: sum(_.could_extract_minus_sign()
|
||||
for _ in Add.make_args(e))
|
||||
if neg_count(f_x) < neg_count(fx):
|
||||
expr = f_x + c
|
||||
|
||||
a = Wild('a', exclude=[n])
|
||||
b = Wild('b', exclude=[n])
|
||||
match = expr.match(a*n + b)
|
||||
if match and match[a] and (
|
||||
not match[a].atoms(Float) and
|
||||
not match[b].atoms(Float)):
|
||||
# canonical shift
|
||||
a, b = match[a], match[b]
|
||||
if a in [1, -1]:
|
||||
# drop integer addends in b
|
||||
nonint = []
|
||||
for bi in Add.make_args(b):
|
||||
if not bi.is_integer:
|
||||
nonint.append(bi)
|
||||
b = Add(*nonint)
|
||||
if b.is_number and a.is_real:
|
||||
# avoid Mod for complex numbers, #11391
|
||||
br, bi = match_real_imag(b)
|
||||
if br and br.is_comparable and a.is_comparable:
|
||||
br %= a
|
||||
b = br + S.ImaginaryUnit*bi
|
||||
elif b.is_number and a.is_imaginary:
|
||||
br, bi = match_real_imag(b)
|
||||
ai = a/S.ImaginaryUnit
|
||||
if bi and bi.is_comparable and ai.is_comparable:
|
||||
bi %= ai
|
||||
b = br + S.ImaginaryUnit*bi
|
||||
expr = a*n + b
|
||||
|
||||
if expr != f.expr:
|
||||
return ImageSet(Lambda(n, expr), S.Integers)
|
||||
|
||||
|
||||
@_set_function.register(FunctionUnion, Naturals)
|
||||
def _(f, self):
|
||||
expr = f.expr
|
||||
if not isinstance(expr, Expr):
|
||||
return
|
||||
|
||||
x = f.variables[0]
|
||||
if not expr.free_symbols - {x}:
|
||||
if expr == abs(x):
|
||||
if self is S.Naturals:
|
||||
return self
|
||||
return S.Naturals0
|
||||
step = expr.coeff(x)
|
||||
c = expr.subs(x, 0)
|
||||
if c.is_Integer and step.is_Integer and expr == step*x + c:
|
||||
if self is S.Naturals:
|
||||
c += step
|
||||
if step > 0:
|
||||
if step == 1:
|
||||
if c == 0:
|
||||
return S.Naturals0
|
||||
elif c == 1:
|
||||
return S.Naturals
|
||||
return Range(c, oo, step)
|
||||
return Range(c, -oo, step)
|
||||
|
||||
|
||||
@_set_function.register(FunctionUnion, Reals)
|
||||
def _(f, self):
|
||||
expr = f.expr
|
||||
if not isinstance(expr, Expr):
|
||||
return
|
||||
return _set_function(f, Interval(-oo, oo))
|
||||
@@ -0,0 +1,533 @@
|
||||
from sympy.core.basic import _aresame
|
||||
from sympy.core.function import Lambda, expand_complex
|
||||
from sympy.core.mul import Mul
|
||||
from sympy.core.numbers import ilcm, Float
|
||||
from sympy.core.relational import Eq
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import (Dummy, symbols)
|
||||
from sympy.core.sorting import ordered
|
||||
from sympy.functions.elementary.complexes import sign
|
||||
from sympy.functions.elementary.integers import floor, ceiling
|
||||
from sympy.sets.fancysets import ComplexRegion
|
||||
from sympy.sets.sets import (FiniteSet, Intersection, Interval, Set, Union)
|
||||
from sympy.multipledispatch import Dispatcher
|
||||
from sympy.sets.conditionset import ConditionSet
|
||||
from sympy.sets.fancysets import (Integers, Naturals, Reals, Range,
|
||||
ImageSet, Rationals)
|
||||
from sympy.sets.sets import EmptySet, UniversalSet, imageset, ProductSet
|
||||
from sympy.simplify.radsimp import numer
|
||||
|
||||
|
||||
intersection_sets = Dispatcher('intersection_sets')
|
||||
|
||||
|
||||
@intersection_sets.register(ConditionSet, ConditionSet)
|
||||
def _(a, b):
|
||||
return None
|
||||
|
||||
@intersection_sets.register(ConditionSet, Set)
|
||||
def _(a, b):
|
||||
return ConditionSet(a.sym, a.condition, Intersection(a.base_set, b))
|
||||
|
||||
@intersection_sets.register(Naturals, Integers)
|
||||
def _(a, b):
|
||||
return a
|
||||
|
||||
@intersection_sets.register(Naturals, Naturals)
|
||||
def _(a, b):
|
||||
return a if a is S.Naturals else b
|
||||
|
||||
@intersection_sets.register(Interval, Naturals)
|
||||
def _(a, b):
|
||||
return intersection_sets(b, a)
|
||||
|
||||
@intersection_sets.register(ComplexRegion, Set)
|
||||
def _(self, other):
|
||||
if other.is_ComplexRegion:
|
||||
# self in rectangular form
|
||||
if (not self.polar) and (not other.polar):
|
||||
return ComplexRegion(Intersection(self.sets, other.sets))
|
||||
|
||||
# self in polar form
|
||||
elif self.polar and other.polar:
|
||||
r1, theta1 = self.a_interval, self.b_interval
|
||||
r2, theta2 = other.a_interval, other.b_interval
|
||||
new_r_interval = Intersection(r1, r2)
|
||||
new_theta_interval = Intersection(theta1, theta2)
|
||||
|
||||
# 0 and 2*Pi means the same
|
||||
if ((2*S.Pi in theta1 and S.Zero in theta2) or
|
||||
(2*S.Pi in theta2 and S.Zero in theta1)):
|
||||
new_theta_interval = Union(new_theta_interval,
|
||||
FiniteSet(0))
|
||||
return ComplexRegion(new_r_interval*new_theta_interval,
|
||||
polar=True)
|
||||
|
||||
|
||||
if other.is_subset(S.Reals):
|
||||
new_interval = []
|
||||
x = symbols("x", cls=Dummy, real=True)
|
||||
|
||||
# self in rectangular form
|
||||
if not self.polar:
|
||||
for element in self.psets:
|
||||
if S.Zero in element.args[1]:
|
||||
new_interval.append(element.args[0])
|
||||
new_interval = Union(*new_interval)
|
||||
return Intersection(new_interval, other)
|
||||
|
||||
# self in polar form
|
||||
elif self.polar:
|
||||
for element in self.psets:
|
||||
if S.Zero in element.args[1]:
|
||||
new_interval.append(element.args[0])
|
||||
if S.Pi in element.args[1]:
|
||||
new_interval.append(ImageSet(Lambda(x, -x), element.args[0]))
|
||||
if S.Zero in element.args[0]:
|
||||
new_interval.append(FiniteSet(0))
|
||||
new_interval = Union(*new_interval)
|
||||
return Intersection(new_interval, other)
|
||||
|
||||
@intersection_sets.register(Integers, Reals)
|
||||
def _(a, b):
|
||||
return a
|
||||
|
||||
@intersection_sets.register(Range, Interval)
|
||||
def _(a, b):
|
||||
# Check that there are no symbolic arguments
|
||||
if not all(i.is_number for i in a.args + b.args[:2]):
|
||||
return
|
||||
|
||||
# In case of null Range, return an EmptySet.
|
||||
if a.size == 0:
|
||||
return S.EmptySet
|
||||
|
||||
# trim down to self's size, and represent
|
||||
# as a Range with step 1.
|
||||
start = ceiling(max(b.inf, a.inf))
|
||||
if start not in b:
|
||||
start += 1
|
||||
end = floor(min(b.sup, a.sup))
|
||||
if end not in b:
|
||||
end -= 1
|
||||
return intersection_sets(a, Range(start, end + 1))
|
||||
|
||||
@intersection_sets.register(Range, Naturals)
|
||||
def _(a, b):
|
||||
return intersection_sets(a, Interval(b.inf, S.Infinity))
|
||||
|
||||
@intersection_sets.register(Range, Range)
|
||||
def _(a, b):
|
||||
# Check that there are no symbolic range arguments
|
||||
if not all(all(v.is_number for v in r.args) for r in [a, b]):
|
||||
return None
|
||||
|
||||
# non-overlap quick exits
|
||||
if not b:
|
||||
return S.EmptySet
|
||||
if not a:
|
||||
return S.EmptySet
|
||||
if b.sup < a.inf:
|
||||
return S.EmptySet
|
||||
if b.inf > a.sup:
|
||||
return S.EmptySet
|
||||
|
||||
# work with finite end at the start
|
||||
r1 = a
|
||||
if r1.start.is_infinite:
|
||||
r1 = r1.reversed
|
||||
r2 = b
|
||||
if r2.start.is_infinite:
|
||||
r2 = r2.reversed
|
||||
|
||||
# If both ends are infinite then it means that one Range is just the set
|
||||
# of all integers (the step must be 1).
|
||||
if r1.start.is_infinite:
|
||||
return b
|
||||
if r2.start.is_infinite:
|
||||
return a
|
||||
|
||||
from sympy.solvers.diophantine.diophantine import diop_linear
|
||||
|
||||
# this equation represents the values of the Range;
|
||||
# it's a linear equation
|
||||
eq = lambda r, i: r.start + i*r.step
|
||||
|
||||
# we want to know when the two equations might
|
||||
# have integer solutions so we use the diophantine
|
||||
# solver
|
||||
va, vb = diop_linear(eq(r1, Dummy('a')) - eq(r2, Dummy('b')))
|
||||
|
||||
# check for no solution
|
||||
no_solution = va is None and vb is None
|
||||
if no_solution:
|
||||
return S.EmptySet
|
||||
|
||||
# there is a solution
|
||||
# -------------------
|
||||
|
||||
# find the coincident point, c
|
||||
a0 = va.as_coeff_Add()[0]
|
||||
c = eq(r1, a0)
|
||||
|
||||
# find the first point, if possible, in each range
|
||||
# since c may not be that point
|
||||
def _first_finite_point(r1, c):
|
||||
if c == r1.start:
|
||||
return c
|
||||
# st is the signed step we need to take to
|
||||
# get from c to r1.start
|
||||
st = sign(r1.start - c)*step
|
||||
# use Range to calculate the first point:
|
||||
# we want to get as close as possible to
|
||||
# r1.start; the Range will not be null since
|
||||
# it will at least contain c
|
||||
s1 = Range(c, r1.start + st, st)[-1]
|
||||
if s1 == r1.start:
|
||||
pass
|
||||
else:
|
||||
# if we didn't hit r1.start then, if the
|
||||
# sign of st didn't match the sign of r1.step
|
||||
# we are off by one and s1 is not in r1
|
||||
if sign(r1.step) != sign(st):
|
||||
s1 -= st
|
||||
if s1 not in r1:
|
||||
return
|
||||
return s1
|
||||
|
||||
# calculate the step size of the new Range
|
||||
step = abs(ilcm(r1.step, r2.step))
|
||||
s1 = _first_finite_point(r1, c)
|
||||
if s1 is None:
|
||||
return S.EmptySet
|
||||
s2 = _first_finite_point(r2, c)
|
||||
if s2 is None:
|
||||
return S.EmptySet
|
||||
|
||||
# replace the corresponding start or stop in
|
||||
# the original Ranges with these points; the
|
||||
# result must have at least one point since
|
||||
# we know that s1 and s2 are in the Ranges
|
||||
def _updated_range(r, first):
|
||||
st = sign(r.step)*step
|
||||
if r.start.is_finite:
|
||||
rv = Range(first, r.stop, st)
|
||||
else:
|
||||
rv = Range(r.start, first + st, st)
|
||||
return rv
|
||||
r1 = _updated_range(a, s1)
|
||||
r2 = _updated_range(b, s2)
|
||||
|
||||
# work with them both in the increasing direction
|
||||
if sign(r1.step) < 0:
|
||||
r1 = r1.reversed
|
||||
if sign(r2.step) < 0:
|
||||
r2 = r2.reversed
|
||||
|
||||
# return clipped Range with positive step; it
|
||||
# can't be empty at this point
|
||||
start = max(r1.start, r2.start)
|
||||
stop = min(r1.stop, r2.stop)
|
||||
return Range(start, stop, step)
|
||||
|
||||
|
||||
@intersection_sets.register(Range, Integers)
|
||||
def _(a, b):
|
||||
return a
|
||||
|
||||
|
||||
@intersection_sets.register(Range, Rationals)
|
||||
def _(a, b):
|
||||
return a
|
||||
|
||||
|
||||
@intersection_sets.register(ImageSet, Set)
|
||||
def _(self, other):
|
||||
from sympy.solvers.diophantine import diophantine
|
||||
|
||||
# Only handle the straight-forward univariate case
|
||||
if (len(self.lamda.variables) > 1
|
||||
or self.lamda.signature != self.lamda.variables):
|
||||
return None
|
||||
base_set = self.base_sets[0]
|
||||
|
||||
# Intersection between ImageSets with Integers as base set
|
||||
# For {f(n) : n in Integers} & {g(m) : m in Integers} we solve the
|
||||
# diophantine equations f(n)=g(m).
|
||||
# If the solutions for n are {h(t) : t in Integers} then we return
|
||||
# {f(h(t)) : t in integers}.
|
||||
# If the solutions for n are {n_1, n_2, ..., n_k} then we return
|
||||
# {f(n_i) : 1 <= i <= k}.
|
||||
if base_set is S.Integers:
|
||||
gm = None
|
||||
if isinstance(other, ImageSet) and other.base_sets == (S.Integers,):
|
||||
gm = other.lamda.expr
|
||||
var = other.lamda.variables[0]
|
||||
# Symbol of second ImageSet lambda must be distinct from first
|
||||
m = Dummy('m')
|
||||
gm = gm.subs(var, m)
|
||||
elif other is S.Integers:
|
||||
m = gm = Dummy('m')
|
||||
if gm is not None:
|
||||
fn = self.lamda.expr
|
||||
n = self.lamda.variables[0]
|
||||
try:
|
||||
solns = list(diophantine(fn - gm, syms=(n, m), permute=True))
|
||||
except (TypeError, NotImplementedError):
|
||||
# TypeError if equation not polynomial with rational coeff.
|
||||
# NotImplementedError if correct format but no solver.
|
||||
return
|
||||
# 3 cases are possible for solns:
|
||||
# - empty set,
|
||||
# - one or more parametric (infinite) solutions,
|
||||
# - a finite number of (non-parametric) solution couples.
|
||||
# Among those, there is one type of solution set that is
|
||||
# not helpful here: multiple parametric solutions.
|
||||
if len(solns) == 0:
|
||||
return S.EmptySet
|
||||
elif any(s.free_symbols for tupl in solns for s in tupl):
|
||||
if len(solns) == 1:
|
||||
soln, solm = solns[0]
|
||||
(t,) = soln.free_symbols
|
||||
expr = fn.subs(n, soln.subs(t, n)).expand()
|
||||
return imageset(Lambda(n, expr), S.Integers)
|
||||
else:
|
||||
return
|
||||
else:
|
||||
return FiniteSet(*(fn.subs(n, s[0]) for s in solns))
|
||||
|
||||
if other == S.Reals:
|
||||
from sympy.solvers.solvers import denoms, solve_linear
|
||||
|
||||
def _solution_union(exprs, sym):
|
||||
# return a union of linear solutions to i in expr;
|
||||
# if i cannot be solved, use a ConditionSet for solution
|
||||
sols = []
|
||||
for i in exprs:
|
||||
x, xis = solve_linear(i, 0, [sym])
|
||||
if x == sym:
|
||||
sols.append(FiniteSet(xis))
|
||||
else:
|
||||
sols.append(ConditionSet(sym, Eq(i, 0)))
|
||||
return Union(*sols)
|
||||
|
||||
f = self.lamda.expr
|
||||
n = self.lamda.variables[0]
|
||||
|
||||
n_ = Dummy(n.name, real=True)
|
||||
f_ = f.subs(n, n_)
|
||||
|
||||
re, im = f_.as_real_imag()
|
||||
im = expand_complex(im)
|
||||
|
||||
re = re.subs(n_, n)
|
||||
im = im.subs(n_, n)
|
||||
ifree = im.free_symbols
|
||||
lam = Lambda(n, re)
|
||||
if im.is_zero:
|
||||
# allow re-evaluation
|
||||
# of self in this case to make
|
||||
# the result canonical
|
||||
pass
|
||||
elif im.is_zero is False:
|
||||
return S.EmptySet
|
||||
elif ifree != {n}:
|
||||
return None
|
||||
else:
|
||||
# univarite imaginary part in same variable;
|
||||
# use numer instead of as_numer_denom to keep
|
||||
# this as fast as possible while still handling
|
||||
# simple cases
|
||||
base_set &= _solution_union(
|
||||
Mul.make_args(numer(im)), n)
|
||||
# exclude values that make denominators 0
|
||||
base_set -= _solution_union(denoms(f), n)
|
||||
return imageset(lam, base_set)
|
||||
|
||||
elif isinstance(other, Interval):
|
||||
from sympy.solvers.solveset import (invert_real, invert_complex,
|
||||
solveset)
|
||||
|
||||
f = self.lamda.expr
|
||||
n = self.lamda.variables[0]
|
||||
new_inf, new_sup = None, None
|
||||
new_lopen, new_ropen = other.left_open, other.right_open
|
||||
|
||||
if f.is_real:
|
||||
inverter = invert_real
|
||||
else:
|
||||
inverter = invert_complex
|
||||
|
||||
g1, h1 = inverter(f, other.inf, n)
|
||||
g2, h2 = inverter(f, other.sup, n)
|
||||
|
||||
if all(isinstance(i, FiniteSet) for i in (h1, h2)):
|
||||
if g1 == n:
|
||||
if len(h1) == 1:
|
||||
new_inf = h1.args[0]
|
||||
if g2 == n:
|
||||
if len(h2) == 1:
|
||||
new_sup = h2.args[0]
|
||||
# TODO: Design a technique to handle multiple-inverse
|
||||
# functions
|
||||
|
||||
# Any of the new boundary values cannot be determined
|
||||
if any(i is None for i in (new_sup, new_inf)):
|
||||
return
|
||||
|
||||
|
||||
range_set = S.EmptySet
|
||||
|
||||
if all(i.is_real for i in (new_sup, new_inf)):
|
||||
# this assumes continuity of underlying function
|
||||
# however fixes the case when it is decreasing
|
||||
if new_inf > new_sup:
|
||||
new_inf, new_sup = new_sup, new_inf
|
||||
new_interval = Interval(new_inf, new_sup, new_lopen, new_ropen)
|
||||
range_set = base_set.intersect(new_interval)
|
||||
else:
|
||||
if other.is_subset(S.Reals):
|
||||
solutions = solveset(f, n, S.Reals)
|
||||
if not isinstance(range_set, (ImageSet, ConditionSet)):
|
||||
range_set = solutions.intersect(other)
|
||||
else:
|
||||
return
|
||||
|
||||
if range_set is S.EmptySet:
|
||||
return S.EmptySet
|
||||
elif isinstance(range_set, Range) and range_set.size is not S.Infinity:
|
||||
range_set = FiniteSet(*list(range_set))
|
||||
|
||||
if range_set is not None:
|
||||
return imageset(Lambda(n, f), range_set)
|
||||
return
|
||||
else:
|
||||
return
|
||||
|
||||
|
||||
@intersection_sets.register(ProductSet, ProductSet)
|
||||
def _(a, b):
|
||||
if len(b.args) != len(a.args):
|
||||
return S.EmptySet
|
||||
return ProductSet(*(i.intersect(j) for i, j in zip(a.sets, b.sets)))
|
||||
|
||||
|
||||
@intersection_sets.register(Interval, Interval)
|
||||
def _(a, b):
|
||||
# handle (-oo, oo)
|
||||
infty = S.NegativeInfinity, S.Infinity
|
||||
if a == Interval(*infty):
|
||||
l, r = a.left, a.right
|
||||
if l.is_real or l in infty or r.is_real or r in infty:
|
||||
return b
|
||||
|
||||
# We can't intersect [0,3] with [x,6] -- we don't know if x>0 or x<0
|
||||
if not a._is_comparable(b):
|
||||
return None
|
||||
|
||||
empty = False
|
||||
|
||||
if a.start <= b.end and b.start <= a.end:
|
||||
# Get topology right.
|
||||
if a.start < b.start:
|
||||
start = b.start
|
||||
left_open = b.left_open
|
||||
elif a.start > b.start:
|
||||
start = a.start
|
||||
left_open = a.left_open
|
||||
else:
|
||||
start = a.start
|
||||
if not _aresame(a.start, b.start):
|
||||
# For example Integer(2) != Float(2)
|
||||
# Prefer the Float boundary because Floats should be
|
||||
# contagious in calculations.
|
||||
if b.start.has(Float) and not a.start.has(Float):
|
||||
start = b.start
|
||||
elif a.start.has(Float) and not b.start.has(Float):
|
||||
start = a.start
|
||||
else:
|
||||
#this is to ensure that if Eq(a.start, b.start) but
|
||||
#type(a.start) != type(b.start) the order of a and b
|
||||
#does not matter for the result
|
||||
start = list(ordered([a,b]))[0].start
|
||||
left_open = a.left_open or b.left_open
|
||||
|
||||
if a.end < b.end:
|
||||
end = a.end
|
||||
right_open = a.right_open
|
||||
elif a.end > b.end:
|
||||
end = b.end
|
||||
right_open = b.right_open
|
||||
else:
|
||||
# see above for logic with start
|
||||
end = a.end
|
||||
if not _aresame(a.end, b.end):
|
||||
if b.end.has(Float) and not a.end.has(Float):
|
||||
end = b.end
|
||||
elif a.end.has(Float) and not b.end.has(Float):
|
||||
end = a.end
|
||||
else:
|
||||
end = list(ordered([a,b]))[0].end
|
||||
right_open = a.right_open or b.right_open
|
||||
|
||||
if end - start == 0 and (left_open or right_open):
|
||||
empty = True
|
||||
else:
|
||||
empty = True
|
||||
|
||||
if empty:
|
||||
return S.EmptySet
|
||||
|
||||
return Interval(start, end, left_open, right_open)
|
||||
|
||||
@intersection_sets.register(EmptySet, Set)
|
||||
def _(a, b):
|
||||
return S.EmptySet
|
||||
|
||||
@intersection_sets.register(UniversalSet, Set)
|
||||
def _(a, b):
|
||||
return b
|
||||
|
||||
@intersection_sets.register(FiniteSet, FiniteSet)
|
||||
def _(a, b):
|
||||
return FiniteSet(*(a._elements & b._elements))
|
||||
|
||||
@intersection_sets.register(FiniteSet, Set)
|
||||
def _(a, b):
|
||||
try:
|
||||
return FiniteSet(*[el for el in a if el in b])
|
||||
except TypeError:
|
||||
return None # could not evaluate `el in b` due to symbolic ranges.
|
||||
|
||||
@intersection_sets.register(Set, Set)
|
||||
def _(a, b):
|
||||
return None
|
||||
|
||||
@intersection_sets.register(Integers, Rationals)
|
||||
def _(a, b):
|
||||
return a
|
||||
|
||||
@intersection_sets.register(Naturals, Rationals)
|
||||
def _(a, b):
|
||||
return a
|
||||
|
||||
@intersection_sets.register(Rationals, Reals)
|
||||
def _(a, b):
|
||||
return a
|
||||
|
||||
def _intlike_interval(a, b):
|
||||
try:
|
||||
if b._inf is S.NegativeInfinity and b._sup is S.Infinity:
|
||||
return a
|
||||
s = Range(max(a.inf, ceiling(b.left)), floor(b.right) + 1)
|
||||
return intersection_sets(s, b) # take out endpoints if open interval
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
@intersection_sets.register(Integers, Interval)
|
||||
def _(a, b):
|
||||
return _intlike_interval(a, b)
|
||||
|
||||
@intersection_sets.register(Naturals, Interval)
|
||||
def _(a, b):
|
||||
return _intlike_interval(a, b)
|
||||
@@ -0,0 +1,144 @@
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import Symbol
|
||||
from sympy.core.logic import fuzzy_and, fuzzy_bool, fuzzy_not, fuzzy_or
|
||||
from sympy.core.relational import Eq
|
||||
from sympy.sets.sets import FiniteSet, Interval, Set, Union, ProductSet
|
||||
from sympy.sets.fancysets import Complexes, Reals, Range, Rationals
|
||||
from sympy.multipledispatch import Dispatcher
|
||||
|
||||
|
||||
_inf_sets = [S.Naturals, S.Naturals0, S.Integers, S.Rationals, S.Reals, S.Complexes]
|
||||
|
||||
|
||||
is_subset_sets = Dispatcher('is_subset_sets')
|
||||
|
||||
|
||||
@is_subset_sets.register(Set, Set)
|
||||
def _(a, b):
|
||||
return None
|
||||
|
||||
@is_subset_sets.register(Interval, Interval)
|
||||
def _(a, b):
|
||||
# This is correct but can be made more comprehensive...
|
||||
if fuzzy_bool(a.start < b.start):
|
||||
return False
|
||||
if fuzzy_bool(a.end > b.end):
|
||||
return False
|
||||
if (b.left_open and not a.left_open and fuzzy_bool(Eq(a.start, b.start))):
|
||||
return False
|
||||
if (b.right_open and not a.right_open and fuzzy_bool(Eq(a.end, b.end))):
|
||||
return False
|
||||
|
||||
@is_subset_sets.register(Interval, FiniteSet)
|
||||
def _(a_interval, b_fs):
|
||||
# An Interval can only be a subset of a finite set if it is finite
|
||||
# which can only happen if it has zero measure.
|
||||
if fuzzy_not(a_interval.measure.is_zero):
|
||||
return False
|
||||
|
||||
@is_subset_sets.register(Interval, Union)
|
||||
def _(a_interval, b_u):
|
||||
if all(isinstance(s, (Interval, FiniteSet)) for s in b_u.args):
|
||||
intervals = [s for s in b_u.args if isinstance(s, Interval)]
|
||||
if all(fuzzy_bool(a_interval.start < s.start) for s in intervals):
|
||||
return False
|
||||
if all(fuzzy_bool(a_interval.end > s.end) for s in intervals):
|
||||
return False
|
||||
if a_interval.measure.is_nonzero:
|
||||
no_overlap = lambda s1, s2: fuzzy_or([
|
||||
fuzzy_bool(s1.end <= s2.start),
|
||||
fuzzy_bool(s1.start >= s2.end),
|
||||
])
|
||||
if all(no_overlap(s, a_interval) for s in intervals):
|
||||
return False
|
||||
|
||||
@is_subset_sets.register(Range, Range)
|
||||
def _(a, b):
|
||||
if a.step == b.step == 1:
|
||||
return fuzzy_and([fuzzy_bool(a.start >= b.start),
|
||||
fuzzy_bool(a.stop <= b.stop)])
|
||||
|
||||
@is_subset_sets.register(Range, Interval)
|
||||
def _(a_range, b_interval):
|
||||
if a_range.step.is_positive:
|
||||
if b_interval.left_open and a_range.inf.is_finite:
|
||||
cond_left = a_range.inf > b_interval.left
|
||||
else:
|
||||
cond_left = a_range.inf >= b_interval.left
|
||||
if b_interval.right_open and a_range.sup.is_finite:
|
||||
cond_right = a_range.sup < b_interval.right
|
||||
else:
|
||||
cond_right = a_range.sup <= b_interval.right
|
||||
return fuzzy_and([cond_left, cond_right])
|
||||
|
||||
@is_subset_sets.register(Range, FiniteSet)
|
||||
def _(a_range, b_finiteset):
|
||||
try:
|
||||
a_size = a_range.size
|
||||
except ValueError:
|
||||
# symbolic Range of unknown size
|
||||
return None
|
||||
if a_size > len(b_finiteset):
|
||||
return False
|
||||
elif any(arg.has(Symbol) for arg in a_range.args):
|
||||
return fuzzy_and(b_finiteset.contains(x) for x in a_range)
|
||||
else:
|
||||
# Checking A \ B == EmptySet is more efficient than repeated naive
|
||||
# membership checks on an arbitrary FiniteSet.
|
||||
a_set = set(a_range)
|
||||
b_remaining = len(b_finiteset)
|
||||
# Symbolic expressions and numbers of unknown type (integer or not) are
|
||||
# all counted as "candidates", i.e. *potentially* matching some a in
|
||||
# a_range.
|
||||
cnt_candidate = 0
|
||||
for b in b_finiteset:
|
||||
if b.is_Integer:
|
||||
a_set.discard(b)
|
||||
elif fuzzy_not(b.is_integer):
|
||||
pass
|
||||
else:
|
||||
cnt_candidate += 1
|
||||
b_remaining -= 1
|
||||
if len(a_set) > b_remaining + cnt_candidate:
|
||||
return False
|
||||
if len(a_set) == 0:
|
||||
return True
|
||||
return None
|
||||
|
||||
@is_subset_sets.register(Interval, Range)
|
||||
def _(a_interval, b_range):
|
||||
if a_interval.measure.is_extended_nonzero:
|
||||
return False
|
||||
|
||||
@is_subset_sets.register(Interval, Rationals)
|
||||
def _(a_interval, b_rationals):
|
||||
if a_interval.measure.is_extended_nonzero:
|
||||
return False
|
||||
|
||||
@is_subset_sets.register(Range, Complexes)
|
||||
def _(a, b):
|
||||
return True
|
||||
|
||||
@is_subset_sets.register(Complexes, Interval)
|
||||
def _(a, b):
|
||||
return False
|
||||
|
||||
@is_subset_sets.register(Complexes, Range)
|
||||
def _(a, b):
|
||||
return False
|
||||
|
||||
@is_subset_sets.register(Complexes, Rationals)
|
||||
def _(a, b):
|
||||
return False
|
||||
|
||||
@is_subset_sets.register(Rationals, Reals)
|
||||
def _(a, b):
|
||||
return True
|
||||
|
||||
@is_subset_sets.register(Rationals, Range)
|
||||
def _(a, b):
|
||||
return False
|
||||
|
||||
@is_subset_sets.register(ProductSet, FiniteSet)
|
||||
def _(a_ps, b_fs):
|
||||
return fuzzy_and(b_fs.contains(x) for x in a_ps)
|
||||
@@ -0,0 +1,79 @@
|
||||
from sympy.core import Basic, Expr
|
||||
from sympy.core.numbers import oo
|
||||
from sympy.core.symbol import symbols
|
||||
from sympy.multipledispatch import Dispatcher
|
||||
from sympy.sets.setexpr import set_mul
|
||||
from sympy.sets.sets import Interval, Set
|
||||
|
||||
|
||||
_x, _y = symbols("x y")
|
||||
|
||||
|
||||
_set_mul = Dispatcher('_set_mul')
|
||||
_set_div = Dispatcher('_set_div')
|
||||
|
||||
|
||||
@_set_mul.register(Basic, Basic)
|
||||
def _(x, y):
|
||||
return None
|
||||
|
||||
@_set_mul.register(Set, Set)
|
||||
def _(x, y):
|
||||
return None
|
||||
|
||||
@_set_mul.register(Expr, Expr)
|
||||
def _(x, y):
|
||||
return x*y
|
||||
|
||||
@_set_mul.register(Interval, Interval)
|
||||
def _(x, y):
|
||||
"""
|
||||
Multiplications in interval arithmetic
|
||||
https://en.wikipedia.org/wiki/Interval_arithmetic
|
||||
"""
|
||||
# TODO: some intervals containing 0 and oo will fail as 0*oo returns nan.
|
||||
comvals = (
|
||||
(x.start * y.start, bool(x.left_open or y.left_open)),
|
||||
(x.start * y.end, bool(x.left_open or y.right_open)),
|
||||
(x.end * y.start, bool(x.right_open or y.left_open)),
|
||||
(x.end * y.end, bool(x.right_open or y.right_open)),
|
||||
)
|
||||
# TODO: handle symbolic intervals
|
||||
minval, minopen = min(comvals)
|
||||
maxval, maxopen = max(comvals)
|
||||
return Interval(
|
||||
minval,
|
||||
maxval,
|
||||
minopen,
|
||||
maxopen
|
||||
)
|
||||
|
||||
@_set_div.register(Basic, Basic)
|
||||
def _(x, y):
|
||||
return None
|
||||
|
||||
@_set_div.register(Expr, Expr)
|
||||
def _(x, y):
|
||||
return x/y
|
||||
|
||||
@_set_div.register(Set, Set)
|
||||
def _(x, y):
|
||||
return None
|
||||
|
||||
@_set_div.register(Interval, Interval)
|
||||
def _(x, y):
|
||||
"""
|
||||
Divisions in interval arithmetic
|
||||
https://en.wikipedia.org/wiki/Interval_arithmetic
|
||||
"""
|
||||
if (y.start*y.end).is_negative:
|
||||
return Interval(-oo, oo)
|
||||
if y.start == 0:
|
||||
s2 = oo
|
||||
else:
|
||||
s2 = 1/y.start
|
||||
if y.end == 0:
|
||||
s1 = -oo
|
||||
else:
|
||||
s1 = 1/y.end
|
||||
return set_mul(x, Interval(s1, s2, y.right_open, y.left_open))
|
||||
@@ -0,0 +1,107 @@
|
||||
from sympy.core import Basic, Expr
|
||||
from sympy.core.function import Lambda
|
||||
from sympy.core.numbers import oo, Infinity, NegativeInfinity, Zero, Integer
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import symbols
|
||||
from sympy.functions.elementary.miscellaneous import (Max, Min)
|
||||
from sympy.sets.fancysets import ImageSet
|
||||
from sympy.sets.setexpr import set_div
|
||||
from sympy.sets.sets import Set, Interval, FiniteSet, Union
|
||||
from sympy.multipledispatch import Dispatcher
|
||||
|
||||
|
||||
_x, _y = symbols("x y")
|
||||
|
||||
|
||||
_set_pow = Dispatcher('_set_pow')
|
||||
|
||||
|
||||
@_set_pow.register(Basic, Basic)
|
||||
def _(x, y):
|
||||
return None
|
||||
|
||||
@_set_pow.register(Set, Set)
|
||||
def _(x, y):
|
||||
return ImageSet(Lambda((_x, _y), (_x ** _y)), x, y)
|
||||
|
||||
@_set_pow.register(Expr, Expr)
|
||||
def _(x, y):
|
||||
return x**y
|
||||
|
||||
@_set_pow.register(Interval, Zero)
|
||||
def _(x, z):
|
||||
return FiniteSet(S.One)
|
||||
|
||||
@_set_pow.register(Interval, Integer)
|
||||
def _(x, exponent):
|
||||
"""
|
||||
Powers in interval arithmetic
|
||||
https://en.wikipedia.org/wiki/Interval_arithmetic
|
||||
"""
|
||||
s1 = x.start**exponent
|
||||
s2 = x.end**exponent
|
||||
if ((s2 > s1) if exponent > 0 else (x.end > -x.start)) == True:
|
||||
left_open = x.left_open
|
||||
right_open = x.right_open
|
||||
# TODO: handle unevaluated condition.
|
||||
sleft = s2
|
||||
else:
|
||||
# TODO: `s2 > s1` could be unevaluated.
|
||||
left_open = x.right_open
|
||||
right_open = x.left_open
|
||||
sleft = s1
|
||||
|
||||
if x.start.is_positive:
|
||||
return Interval(
|
||||
Min(s1, s2),
|
||||
Max(s1, s2), left_open, right_open)
|
||||
elif x.end.is_negative:
|
||||
return Interval(
|
||||
Min(s1, s2),
|
||||
Max(s1, s2), left_open, right_open)
|
||||
|
||||
# Case where x.start < 0 and x.end > 0:
|
||||
if exponent.is_odd:
|
||||
if exponent.is_negative:
|
||||
if x.start.is_zero:
|
||||
return Interval(s2, oo, x.right_open)
|
||||
if x.end.is_zero:
|
||||
return Interval(-oo, s1, True, x.left_open)
|
||||
return Union(Interval(-oo, s1, True, x.left_open), Interval(s2, oo, x.right_open))
|
||||
else:
|
||||
return Interval(s1, s2, x.left_open, x.right_open)
|
||||
elif exponent.is_even:
|
||||
if exponent.is_negative:
|
||||
if x.start.is_zero:
|
||||
return Interval(s2, oo, x.right_open)
|
||||
if x.end.is_zero:
|
||||
return Interval(s1, oo, x.left_open)
|
||||
return Interval(0, oo)
|
||||
else:
|
||||
return Interval(S.Zero, sleft, S.Zero not in x, left_open)
|
||||
|
||||
@_set_pow.register(Interval, Infinity)
|
||||
def _(b, e):
|
||||
# TODO: add logic for open intervals?
|
||||
if b.start.is_nonnegative:
|
||||
if b.end < 1:
|
||||
return FiniteSet(S.Zero)
|
||||
if b.start > 1:
|
||||
return FiniteSet(S.Infinity)
|
||||
return Interval(0, oo)
|
||||
elif b.end.is_negative:
|
||||
if b.start > -1:
|
||||
return FiniteSet(S.Zero)
|
||||
if b.end < -1:
|
||||
return FiniteSet(-oo, oo)
|
||||
return Interval(-oo, oo)
|
||||
else:
|
||||
if b.start > -1:
|
||||
if b.end < 1:
|
||||
return FiniteSet(S.Zero)
|
||||
return Interval(0, oo)
|
||||
return Interval(-oo, oo)
|
||||
|
||||
@_set_pow.register(Interval, NegativeInfinity)
|
||||
def _(b, e):
|
||||
return _set_pow(set_div(S.One, b), oo)
|
||||
@@ -0,0 +1,147 @@
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.sympify import sympify
|
||||
from sympy.functions.elementary.miscellaneous import Min, Max
|
||||
from sympy.sets.sets import (EmptySet, FiniteSet, Intersection,
|
||||
Interval, ProductSet, Set, Union, UniversalSet)
|
||||
from sympy.sets.fancysets import (ComplexRegion, Naturals, Naturals0,
|
||||
Integers, Rationals, Reals)
|
||||
from sympy.multipledispatch import Dispatcher
|
||||
|
||||
|
||||
union_sets = Dispatcher('union_sets')
|
||||
|
||||
|
||||
@union_sets.register(Naturals0, Naturals)
|
||||
def _(a, b):
|
||||
return a
|
||||
|
||||
@union_sets.register(Rationals, Naturals)
|
||||
def _(a, b):
|
||||
return a
|
||||
|
||||
@union_sets.register(Rationals, Naturals0)
|
||||
def _(a, b):
|
||||
return a
|
||||
|
||||
@union_sets.register(Reals, Naturals)
|
||||
def _(a, b):
|
||||
return a
|
||||
|
||||
@union_sets.register(Reals, Naturals0)
|
||||
def _(a, b):
|
||||
return a
|
||||
|
||||
@union_sets.register(Reals, Rationals)
|
||||
def _(a, b):
|
||||
return a
|
||||
|
||||
@union_sets.register(Integers, Set)
|
||||
def _(a, b):
|
||||
intersect = Intersection(a, b)
|
||||
if intersect == a:
|
||||
return b
|
||||
elif intersect == b:
|
||||
return a
|
||||
|
||||
@union_sets.register(ComplexRegion, Set)
|
||||
def _(a, b):
|
||||
if b.is_subset(S.Reals):
|
||||
# treat a subset of reals as a complex region
|
||||
b = ComplexRegion.from_real(b)
|
||||
|
||||
if b.is_ComplexRegion:
|
||||
# a in rectangular form
|
||||
if (not a.polar) and (not b.polar):
|
||||
return ComplexRegion(Union(a.sets, b.sets))
|
||||
# a in polar form
|
||||
elif a.polar and b.polar:
|
||||
return ComplexRegion(Union(a.sets, b.sets), polar=True)
|
||||
return None
|
||||
|
||||
@union_sets.register(EmptySet, Set)
|
||||
def _(a, b):
|
||||
return b
|
||||
|
||||
|
||||
@union_sets.register(UniversalSet, Set)
|
||||
def _(a, b):
|
||||
return a
|
||||
|
||||
@union_sets.register(ProductSet, ProductSet)
|
||||
def _(a, b):
|
||||
if b.is_subset(a):
|
||||
return a
|
||||
if len(b.sets) != len(a.sets):
|
||||
return None
|
||||
if len(a.sets) == 2:
|
||||
a1, a2 = a.sets
|
||||
b1, b2 = b.sets
|
||||
if a1 == b1:
|
||||
return a1 * Union(a2, b2)
|
||||
if a2 == b2:
|
||||
return Union(a1, b1) * a2
|
||||
return None
|
||||
|
||||
@union_sets.register(ProductSet, Set)
|
||||
def _(a, b):
|
||||
if b.is_subset(a):
|
||||
return a
|
||||
return None
|
||||
|
||||
@union_sets.register(Interval, Interval)
|
||||
def _(a, b):
|
||||
if a._is_comparable(b):
|
||||
# Non-overlapping intervals
|
||||
end = Min(a.end, b.end)
|
||||
start = Max(a.start, b.start)
|
||||
if (end < start or
|
||||
(end == start and (end not in a and end not in b))):
|
||||
return None
|
||||
else:
|
||||
start = Min(a.start, b.start)
|
||||
end = Max(a.end, b.end)
|
||||
|
||||
left_open = ((a.start != start or a.left_open) and
|
||||
(b.start != start or b.left_open))
|
||||
right_open = ((a.end != end or a.right_open) and
|
||||
(b.end != end or b.right_open))
|
||||
return Interval(start, end, left_open, right_open)
|
||||
|
||||
@union_sets.register(Interval, UniversalSet)
|
||||
def _(a, b):
|
||||
return S.UniversalSet
|
||||
|
||||
@union_sets.register(Interval, Set)
|
||||
def _(a, b):
|
||||
# If I have open end points and these endpoints are contained in b
|
||||
# But only in case, when endpoints are finite. Because
|
||||
# interval does not contain oo or -oo.
|
||||
open_left_in_b_and_finite = (a.left_open and
|
||||
sympify(b.contains(a.start)) is S.true and
|
||||
a.start.is_finite)
|
||||
open_right_in_b_and_finite = (a.right_open and
|
||||
sympify(b.contains(a.end)) is S.true and
|
||||
a.end.is_finite)
|
||||
if open_left_in_b_and_finite or open_right_in_b_and_finite:
|
||||
# Fill in my end points and return
|
||||
open_left = a.left_open and a.start not in b
|
||||
open_right = a.right_open and a.end not in b
|
||||
new_a = Interval(a.start, a.end, open_left, open_right)
|
||||
return {new_a, b}
|
||||
return None
|
||||
|
||||
@union_sets.register(FiniteSet, FiniteSet)
|
||||
def _(a, b):
|
||||
return FiniteSet(*(a._elements | b._elements))
|
||||
|
||||
@union_sets.register(FiniteSet, Set)
|
||||
def _(a, b):
|
||||
# If `b` set contains one of my elements, remove it from `a`
|
||||
if any(b.contains(x) == True for x in a):
|
||||
return {
|
||||
FiniteSet(*[x for x in a if b.contains(x) != True]), b}
|
||||
return None
|
||||
|
||||
@union_sets.register(Set, Set)
|
||||
def _(a, b):
|
||||
return None
|
||||
@@ -0,0 +1,282 @@
|
||||
from sympy.core import Basic, Integer
|
||||
import operator
|
||||
|
||||
|
||||
class OmegaPower(Basic):
|
||||
"""
|
||||
Represents ordinal exponential and multiplication terms one of the
|
||||
building blocks of the :class:`Ordinal` class.
|
||||
In ``OmegaPower(a, b)``, ``a`` represents exponent and ``b`` represents multiplicity.
|
||||
"""
|
||||
def __new__(cls, a, b):
|
||||
if isinstance(b, int):
|
||||
b = Integer(b)
|
||||
if not isinstance(b, Integer) or b <= 0:
|
||||
raise TypeError("multiplicity must be a positive integer")
|
||||
|
||||
if not isinstance(a, Ordinal):
|
||||
a = Ordinal.convert(a)
|
||||
|
||||
return Basic.__new__(cls, a, b)
|
||||
|
||||
@property
|
||||
def exp(self):
|
||||
return self.args[0]
|
||||
|
||||
@property
|
||||
def mult(self):
|
||||
return self.args[1]
|
||||
|
||||
def _compare_term(self, other, op):
|
||||
if self.exp == other.exp:
|
||||
return op(self.mult, other.mult)
|
||||
else:
|
||||
return op(self.exp, other.exp)
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(other, OmegaPower):
|
||||
try:
|
||||
other = OmegaPower(0, other)
|
||||
except TypeError:
|
||||
return NotImplemented
|
||||
return self.args == other.args
|
||||
|
||||
def __hash__(self):
|
||||
return Basic.__hash__(self)
|
||||
|
||||
def __lt__(self, other):
|
||||
if not isinstance(other, OmegaPower):
|
||||
try:
|
||||
other = OmegaPower(0, other)
|
||||
except TypeError:
|
||||
return NotImplemented
|
||||
return self._compare_term(other, operator.lt)
|
||||
|
||||
|
||||
class Ordinal(Basic):
|
||||
"""
|
||||
Represents ordinals in Cantor normal form.
|
||||
|
||||
Internally, this class is just a list of instances of OmegaPower.
|
||||
|
||||
Examples
|
||||
========
|
||||
>>> from sympy import Ordinal, OmegaPower
|
||||
>>> from sympy.sets.ordinals import omega
|
||||
>>> w = omega
|
||||
>>> w.is_limit_ordinal
|
||||
True
|
||||
>>> Ordinal(OmegaPower(w + 1, 1), OmegaPower(3, 2))
|
||||
w**(w + 1) + w**3*2
|
||||
>>> 3 + w
|
||||
w
|
||||
>>> (w + 1) * w
|
||||
w**2
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Ordinal_arithmetic
|
||||
"""
|
||||
def __new__(cls, *terms):
|
||||
obj = super().__new__(cls, *terms)
|
||||
powers = [i.exp for i in obj.args]
|
||||
if not all(powers[i] >= powers[i+1] for i in range(len(powers) - 1)):
|
||||
raise ValueError("powers must be in decreasing order")
|
||||
return obj
|
||||
|
||||
@property
|
||||
def terms(self):
|
||||
return self.args
|
||||
|
||||
@property
|
||||
def leading_term(self):
|
||||
if self == ord0:
|
||||
raise ValueError("ordinal zero has no leading term")
|
||||
return self.terms[0]
|
||||
|
||||
@property
|
||||
def trailing_term(self):
|
||||
if self == ord0:
|
||||
raise ValueError("ordinal zero has no trailing term")
|
||||
return self.terms[-1]
|
||||
|
||||
@property
|
||||
def is_successor_ordinal(self):
|
||||
try:
|
||||
return self.trailing_term.exp == ord0
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
@property
|
||||
def is_limit_ordinal(self):
|
||||
try:
|
||||
return not self.trailing_term.exp == ord0
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
@property
|
||||
def degree(self):
|
||||
return self.leading_term.exp
|
||||
|
||||
@classmethod
|
||||
def convert(cls, integer_value):
|
||||
if integer_value == 0:
|
||||
return ord0
|
||||
return Ordinal(OmegaPower(0, integer_value))
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(other, Ordinal):
|
||||
try:
|
||||
other = Ordinal.convert(other)
|
||||
except TypeError:
|
||||
return NotImplemented
|
||||
return self.terms == other.terms
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self.args)
|
||||
|
||||
def __lt__(self, other):
|
||||
if not isinstance(other, Ordinal):
|
||||
try:
|
||||
other = Ordinal.convert(other)
|
||||
except TypeError:
|
||||
return NotImplemented
|
||||
for term_self, term_other in zip(self.terms, other.terms):
|
||||
if term_self != term_other:
|
||||
return term_self < term_other
|
||||
return len(self.terms) < len(other.terms)
|
||||
|
||||
def __le__(self, other):
|
||||
return (self == other or self < other)
|
||||
|
||||
def __gt__(self, other):
|
||||
return not self <= other
|
||||
|
||||
def __ge__(self, other):
|
||||
return not self < other
|
||||
|
||||
def __str__(self):
|
||||
net_str = ""
|
||||
plus_count = 0
|
||||
if self == ord0:
|
||||
return 'ord0'
|
||||
for i in self.terms:
|
||||
if plus_count:
|
||||
net_str += " + "
|
||||
|
||||
if i.exp == ord0:
|
||||
net_str += str(i.mult)
|
||||
elif i.exp == 1:
|
||||
net_str += 'w'
|
||||
elif len(i.exp.terms) > 1 or i.exp.is_limit_ordinal:
|
||||
net_str += 'w**(%s)'%i.exp
|
||||
else:
|
||||
net_str += 'w**%s'%i.exp
|
||||
|
||||
if not i.mult == 1 and not i.exp == ord0:
|
||||
net_str += '*%s'%i.mult
|
||||
|
||||
plus_count += 1
|
||||
return(net_str)
|
||||
|
||||
__repr__ = __str__
|
||||
|
||||
def __add__(self, other):
|
||||
if not isinstance(other, Ordinal):
|
||||
try:
|
||||
other = Ordinal.convert(other)
|
||||
except TypeError:
|
||||
return NotImplemented
|
||||
if other == ord0:
|
||||
return self
|
||||
a_terms = list(self.terms)
|
||||
b_terms = list(other.terms)
|
||||
r = len(a_terms) - 1
|
||||
b_exp = other.degree
|
||||
while r >= 0 and a_terms[r].exp < b_exp:
|
||||
r -= 1
|
||||
if r < 0:
|
||||
terms = b_terms
|
||||
elif a_terms[r].exp == b_exp:
|
||||
sum_term = OmegaPower(b_exp, a_terms[r].mult + other.leading_term.mult)
|
||||
terms = a_terms[:r] + [sum_term] + b_terms[1:]
|
||||
else:
|
||||
terms = a_terms[:r+1] + b_terms
|
||||
return Ordinal(*terms)
|
||||
|
||||
def __radd__(self, other):
|
||||
if not isinstance(other, Ordinal):
|
||||
try:
|
||||
other = Ordinal.convert(other)
|
||||
except TypeError:
|
||||
return NotImplemented
|
||||
return other + self
|
||||
|
||||
def __mul__(self, other):
|
||||
if not isinstance(other, Ordinal):
|
||||
try:
|
||||
other = Ordinal.convert(other)
|
||||
except TypeError:
|
||||
return NotImplemented
|
||||
if ord0 in (self, other):
|
||||
return ord0
|
||||
a_exp = self.degree
|
||||
a_mult = self.leading_term.mult
|
||||
summation = []
|
||||
if other.is_limit_ordinal:
|
||||
for arg in other.terms:
|
||||
summation.append(OmegaPower(a_exp + arg.exp, arg.mult))
|
||||
|
||||
else:
|
||||
for arg in other.terms[:-1]:
|
||||
summation.append(OmegaPower(a_exp + arg.exp, arg.mult))
|
||||
b_mult = other.trailing_term.mult
|
||||
summation.append(OmegaPower(a_exp, a_mult*b_mult))
|
||||
summation += list(self.terms[1:])
|
||||
return Ordinal(*summation)
|
||||
|
||||
def __rmul__(self, other):
|
||||
if not isinstance(other, Ordinal):
|
||||
try:
|
||||
other = Ordinal.convert(other)
|
||||
except TypeError:
|
||||
return NotImplemented
|
||||
return other * self
|
||||
|
||||
def __pow__(self, other):
|
||||
if not self == omega:
|
||||
return NotImplemented
|
||||
return Ordinal(OmegaPower(other, 1))
|
||||
|
||||
|
||||
class OrdinalZero(Ordinal):
|
||||
"""The ordinal zero.
|
||||
|
||||
OrdinalZero can be imported as ``ord0``.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class OrdinalOmega(Ordinal):
|
||||
"""The ordinal omega which forms the base of all ordinals in cantor normal form.
|
||||
|
||||
OrdinalOmega can be imported as ``omega``.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.sets.ordinals import omega
|
||||
>>> omega + omega
|
||||
w*2
|
||||
"""
|
||||
def __new__(cls):
|
||||
return Ordinal.__new__(cls)
|
||||
|
||||
@property
|
||||
def terms(self):
|
||||
return (OmegaPower(1, 1),)
|
||||
|
||||
|
||||
ord0 = OrdinalZero()
|
||||
omega = OrdinalOmega()
|
||||
@@ -0,0 +1,119 @@
|
||||
from sympy.core.decorators import _sympifyit
|
||||
from sympy.core.parameters import global_parameters
|
||||
from sympy.core.logic import fuzzy_bool
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.sympify import _sympify
|
||||
|
||||
from .sets import Set, FiniteSet, SetKind
|
||||
|
||||
|
||||
class PowerSet(Set):
|
||||
r"""A symbolic object representing a power set.
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
arg : Set
|
||||
The set to take power of.
|
||||
|
||||
evaluate : bool
|
||||
The flag to control evaluation.
|
||||
|
||||
If the evaluation is disabled for finite sets, it can take
|
||||
advantage of using subset test as a membership test.
|
||||
|
||||
Notes
|
||||
=====
|
||||
|
||||
Power set `\mathcal{P}(S)` is defined as a set containing all the
|
||||
subsets of `S`.
|
||||
|
||||
If the set `S` is a finite set, its power set would have
|
||||
`2^{\left| S \right|}` elements, where `\left| S \right|` denotes
|
||||
the cardinality of `S`.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import PowerSet, S, FiniteSet
|
||||
|
||||
A power set of a finite set:
|
||||
|
||||
>>> PowerSet(FiniteSet(1, 2, 3))
|
||||
PowerSet({1, 2, 3})
|
||||
|
||||
A power set of an empty set:
|
||||
|
||||
>>> PowerSet(S.EmptySet)
|
||||
PowerSet(EmptySet)
|
||||
>>> PowerSet(PowerSet(S.EmptySet))
|
||||
PowerSet(PowerSet(EmptySet))
|
||||
|
||||
A power set of an infinite set:
|
||||
|
||||
>>> PowerSet(S.Reals)
|
||||
PowerSet(Reals)
|
||||
|
||||
Evaluating the power set of a finite set to its explicit form:
|
||||
|
||||
>>> PowerSet(FiniteSet(1, 2, 3)).rewrite(FiniteSet)
|
||||
FiniteSet(EmptySet, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3})
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Power_set
|
||||
|
||||
.. [2] https://en.wikipedia.org/wiki/Axiom_of_power_set
|
||||
"""
|
||||
def __new__(cls, arg, evaluate=None):
|
||||
if evaluate is None:
|
||||
evaluate=global_parameters.evaluate
|
||||
|
||||
arg = _sympify(arg)
|
||||
|
||||
if not isinstance(arg, Set):
|
||||
raise ValueError('{} must be a set.'.format(arg))
|
||||
|
||||
return super().__new__(cls, arg)
|
||||
|
||||
@property
|
||||
def arg(self):
|
||||
return self.args[0]
|
||||
|
||||
def _eval_rewrite_as_FiniteSet(self, *args, **kwargs):
|
||||
arg = self.arg
|
||||
if arg.is_FiniteSet:
|
||||
return arg.powerset()
|
||||
return None
|
||||
|
||||
@_sympifyit('other', NotImplemented)
|
||||
def _contains(self, other):
|
||||
if not isinstance(other, Set):
|
||||
return None
|
||||
|
||||
return fuzzy_bool(self.arg.is_superset(other))
|
||||
|
||||
def _eval_is_subset(self, other):
|
||||
if isinstance(other, PowerSet):
|
||||
return self.arg.is_subset(other.arg)
|
||||
|
||||
def __len__(self):
|
||||
return 2 ** len(self.arg)
|
||||
|
||||
def __iter__(self):
|
||||
found = [S.EmptySet]
|
||||
yield S.EmptySet
|
||||
|
||||
for x in self.arg:
|
||||
temp = []
|
||||
x = FiniteSet(x)
|
||||
for y in found:
|
||||
new = x + y
|
||||
yield new
|
||||
temp.append(new)
|
||||
found.extend(temp)
|
||||
|
||||
@property
|
||||
def kind(self):
|
||||
return SetKind(self.arg.kind)
|
||||
@@ -0,0 +1,97 @@
|
||||
from sympy.core import Expr
|
||||
from sympy.core.decorators import call_highest_priority, _sympifyit
|
||||
from .fancysets import ImageSet
|
||||
from .sets import set_add, set_sub, set_mul, set_div, set_pow, set_function
|
||||
|
||||
|
||||
class SetExpr(Expr):
|
||||
"""An expression that can take on values of a set.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import Interval, FiniteSet
|
||||
>>> from sympy.sets.setexpr import SetExpr
|
||||
|
||||
>>> a = SetExpr(Interval(0, 5))
|
||||
>>> b = SetExpr(FiniteSet(1, 10))
|
||||
>>> (a + b).set
|
||||
Union(Interval(1, 6), Interval(10, 15))
|
||||
>>> (2*a + b).set
|
||||
Interval(1, 20)
|
||||
"""
|
||||
_op_priority = 11.0
|
||||
|
||||
def __new__(cls, setarg):
|
||||
return Expr.__new__(cls, setarg)
|
||||
|
||||
set = property(lambda self: self.args[0])
|
||||
|
||||
def _latex(self, printer):
|
||||
return r"SetExpr\left({}\right)".format(printer._print(self.set))
|
||||
|
||||
@_sympifyit('other', NotImplemented)
|
||||
@call_highest_priority('__radd__')
|
||||
def __add__(self, other):
|
||||
return _setexpr_apply_operation(set_add, self, other)
|
||||
|
||||
@_sympifyit('other', NotImplemented)
|
||||
@call_highest_priority('__add__')
|
||||
def __radd__(self, other):
|
||||
return _setexpr_apply_operation(set_add, other, self)
|
||||
|
||||
@_sympifyit('other', NotImplemented)
|
||||
@call_highest_priority('__rmul__')
|
||||
def __mul__(self, other):
|
||||
return _setexpr_apply_operation(set_mul, self, other)
|
||||
|
||||
@_sympifyit('other', NotImplemented)
|
||||
@call_highest_priority('__mul__')
|
||||
def __rmul__(self, other):
|
||||
return _setexpr_apply_operation(set_mul, other, self)
|
||||
|
||||
@_sympifyit('other', NotImplemented)
|
||||
@call_highest_priority('__rsub__')
|
||||
def __sub__(self, other):
|
||||
return _setexpr_apply_operation(set_sub, self, other)
|
||||
|
||||
@_sympifyit('other', NotImplemented)
|
||||
@call_highest_priority('__sub__')
|
||||
def __rsub__(self, other):
|
||||
return _setexpr_apply_operation(set_sub, other, self)
|
||||
|
||||
@_sympifyit('other', NotImplemented)
|
||||
@call_highest_priority('__rpow__')
|
||||
def __pow__(self, other):
|
||||
return _setexpr_apply_operation(set_pow, self, other)
|
||||
|
||||
@_sympifyit('other', NotImplemented)
|
||||
@call_highest_priority('__pow__')
|
||||
def __rpow__(self, other):
|
||||
return _setexpr_apply_operation(set_pow, other, self)
|
||||
|
||||
@_sympifyit('other', NotImplemented)
|
||||
@call_highest_priority('__rtruediv__')
|
||||
def __truediv__(self, other):
|
||||
return _setexpr_apply_operation(set_div, self, other)
|
||||
|
||||
@_sympifyit('other', NotImplemented)
|
||||
@call_highest_priority('__truediv__')
|
||||
def __rtruediv__(self, other):
|
||||
return _setexpr_apply_operation(set_div, other, self)
|
||||
|
||||
def _eval_func(self, func):
|
||||
# TODO: this could be implemented straight into `imageset`:
|
||||
res = set_function(func, self.set)
|
||||
if res is None:
|
||||
return SetExpr(ImageSet(func, self.set))
|
||||
return SetExpr(res)
|
||||
|
||||
|
||||
def _setexpr_apply_operation(op, x, y):
|
||||
if isinstance(x, SetExpr):
|
||||
x = x.set
|
||||
if isinstance(y, SetExpr):
|
||||
y = y.set
|
||||
out = op(x, y)
|
||||
return SetExpr(out)
|
||||
2804
backend_service/venv/lib/python3.13/site-packages/sympy/sets/sets.py
Normal file
2804
backend_service/venv/lib/python3.13/site-packages/sympy/sets/sets.py
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,294 @@
|
||||
from sympy.core.expr import unchanged
|
||||
from sympy.sets import (ConditionSet, Intersection, FiniteSet,
|
||||
EmptySet, Union, Contains, ImageSet)
|
||||
from sympy.sets.sets import SetKind
|
||||
from sympy.core.function import (Function, Lambda)
|
||||
from sympy.core.mod import Mod
|
||||
from sympy.core.kind import NumberKind
|
||||
from sympy.core.numbers import (oo, pi)
|
||||
from sympy.core.relational import (Eq, Ne)
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import (Symbol, symbols)
|
||||
from sympy.functions.elementary.complexes import Abs
|
||||
from sympy.functions.elementary.trigonometric import (asin, sin)
|
||||
from sympy.logic.boolalg import And
|
||||
from sympy.matrices.dense import Matrix
|
||||
from sympy.matrices.expressions.matexpr import MatrixSymbol
|
||||
from sympy.sets.sets import Interval
|
||||
from sympy.testing.pytest import raises, warns_deprecated_sympy
|
||||
|
||||
|
||||
w = Symbol('w')
|
||||
x = Symbol('x')
|
||||
y = Symbol('y')
|
||||
z = Symbol('z')
|
||||
f = Function('f')
|
||||
|
||||
|
||||
def test_CondSet():
|
||||
sin_sols_principal = ConditionSet(x, Eq(sin(x), 0),
|
||||
Interval(0, 2*pi, False, True))
|
||||
assert pi in sin_sols_principal
|
||||
assert pi/2 not in sin_sols_principal
|
||||
assert 3*pi not in sin_sols_principal
|
||||
assert oo not in sin_sols_principal
|
||||
assert 5 in ConditionSet(x, x**2 > 4, S.Reals)
|
||||
assert 1 not in ConditionSet(x, x**2 > 4, S.Reals)
|
||||
# in this case, 0 is not part of the base set so
|
||||
# it can't be in any subset selected by the condition
|
||||
assert 0 not in ConditionSet(x, y > 5, Interval(1, 7))
|
||||
# since 'in' requires a true/false, the following raises
|
||||
# an error because the given value provides no information
|
||||
# for the condition to evaluate (since the condition does
|
||||
# not depend on the dummy symbol): the result is `y > 5`.
|
||||
# In this case, ConditionSet is just acting like
|
||||
# Piecewise((Interval(1, 7), y > 5), (S.EmptySet, True)).
|
||||
raises(TypeError, lambda: 6 in ConditionSet(x, y > 5,
|
||||
Interval(1, 7)))
|
||||
|
||||
X = MatrixSymbol('X', 2, 2)
|
||||
matrix_set = ConditionSet(X, Eq(X*Matrix([[1, 1], [1, 1]]), X))
|
||||
Y = Matrix([[0, 0], [0, 0]])
|
||||
assert matrix_set.contains(Y).doit() is S.true
|
||||
Z = Matrix([[1, 2], [3, 4]])
|
||||
assert matrix_set.contains(Z).doit() is S.false
|
||||
|
||||
assert isinstance(ConditionSet(x, x < 1, {x, y}).base_set,
|
||||
FiniteSet)
|
||||
raises(TypeError, lambda: ConditionSet(x, x + 1, {x, y}))
|
||||
raises(TypeError, lambda: ConditionSet(x, x, 1))
|
||||
|
||||
I = S.Integers
|
||||
U = S.UniversalSet
|
||||
C = ConditionSet
|
||||
assert C(x, False, I) is S.EmptySet
|
||||
assert C(x, True, I) is I
|
||||
assert C(x, x < 1, C(x, x < 2, I)
|
||||
) == C(x, (x < 1) & (x < 2), I)
|
||||
assert C(y, y < 1, C(x, y < 2, I)
|
||||
) == C(x, (x < 1) & (y < 2), I), C(y, y < 1, C(x, y < 2, I))
|
||||
assert C(y, y < 1, C(x, x < 2, I)
|
||||
) == C(y, (y < 1) & (y < 2), I)
|
||||
assert C(y, y < 1, C(x, y < x, I)
|
||||
) == C(x, (x < 1) & (y < x), I)
|
||||
assert unchanged(C, y, x < 1, C(x, y < x, I))
|
||||
assert ConditionSet(x, x < 1).base_set is U
|
||||
# arg checking is not done at instantiation but this
|
||||
# will raise an error when containment is tested
|
||||
assert ConditionSet((x,), x < 1).base_set is U
|
||||
|
||||
c = ConditionSet((x, y), x < y, I**2)
|
||||
assert (1, 2) in c
|
||||
assert (1, pi) not in c
|
||||
|
||||
raises(TypeError, lambda: C(x, x > 1, C((x, y), x > 1, I**2)))
|
||||
# signature mismatch since only 3 args are accepted
|
||||
raises(TypeError, lambda: C((x, y), x + y < 2, U, U))
|
||||
|
||||
|
||||
def test_CondSet_intersect():
|
||||
input_conditionset = ConditionSet(x, x**2 > 4, Interval(1, 4, False,
|
||||
False))
|
||||
other_domain = Interval(0, 3, False, False)
|
||||
output_conditionset = ConditionSet(x, x**2 > 4, Interval(
|
||||
1, 3, False, False))
|
||||
assert Intersection(input_conditionset, other_domain
|
||||
) == output_conditionset
|
||||
|
||||
|
||||
def test_issue_9849():
|
||||
assert ConditionSet(x, Eq(x, x), S.Naturals
|
||||
) is S.Naturals
|
||||
assert ConditionSet(x, Eq(Abs(sin(x)), -1), S.Naturals
|
||||
) == S.EmptySet
|
||||
|
||||
|
||||
def test_simplified_FiniteSet_in_CondSet():
|
||||
assert ConditionSet(x, And(x < 1, x > -3), FiniteSet(0, 1, 2)
|
||||
) == FiniteSet(0)
|
||||
assert ConditionSet(x, x < 0, FiniteSet(0, 1, 2)) == EmptySet
|
||||
assert ConditionSet(x, And(x < -3), EmptySet) == EmptySet
|
||||
y = Symbol('y')
|
||||
assert (ConditionSet(x, And(x > 0), FiniteSet(-1, 0, 1, y)) ==
|
||||
Union(FiniteSet(1), ConditionSet(x, And(x > 0), FiniteSet(y))))
|
||||
assert (ConditionSet(x, Eq(Mod(x, 3), 1), FiniteSet(1, 4, 2, y)) ==
|
||||
Union(FiniteSet(1, 4), ConditionSet(x, Eq(Mod(x, 3), 1),
|
||||
FiniteSet(y))))
|
||||
|
||||
|
||||
def test_free_symbols():
|
||||
assert ConditionSet(x, Eq(y, 0), FiniteSet(z)
|
||||
).free_symbols == {y, z}
|
||||
assert ConditionSet(x, Eq(x, 0), FiniteSet(z)
|
||||
).free_symbols == {z}
|
||||
assert ConditionSet(x, Eq(x, 0), FiniteSet(x, z)
|
||||
).free_symbols == {x, z}
|
||||
assert ConditionSet(x, Eq(x, 0), ImageSet(Lambda(y, y**2),
|
||||
S.Integers)).free_symbols == set()
|
||||
|
||||
|
||||
def test_bound_symbols():
|
||||
assert ConditionSet(x, Eq(y, 0), FiniteSet(z)
|
||||
).bound_symbols == [x]
|
||||
assert ConditionSet(x, Eq(x, 0), FiniteSet(x, y)
|
||||
).bound_symbols == [x]
|
||||
assert ConditionSet(x, x < 10, ImageSet(Lambda(y, y**2), S.Integers)
|
||||
).bound_symbols == [x]
|
||||
assert ConditionSet(x, x < 10, ConditionSet(y, y > 1, S.Integers)
|
||||
).bound_symbols == [x]
|
||||
|
||||
|
||||
def test_as_dummy():
|
||||
_0, _1 = symbols('_0 _1')
|
||||
assert ConditionSet(x, x < 1, Interval(y, oo)
|
||||
).as_dummy() == ConditionSet(_0, _0 < 1, Interval(y, oo))
|
||||
assert ConditionSet(x, x < 1, Interval(x, oo)
|
||||
).as_dummy() == ConditionSet(_0, _0 < 1, Interval(x, oo))
|
||||
assert ConditionSet(x, x < 1, ImageSet(Lambda(y, y**2), S.Integers)
|
||||
).as_dummy() == ConditionSet(
|
||||
_0, _0 < 1, ImageSet(Lambda(_0, _0**2), S.Integers))
|
||||
e = ConditionSet((x, y), x <= y, S.Reals**2)
|
||||
assert e.bound_symbols == [x, y]
|
||||
assert e.as_dummy() == ConditionSet((_0, _1), _0 <= _1, S.Reals**2)
|
||||
assert e.as_dummy() == ConditionSet((y, x), y <= x, S.Reals**2
|
||||
).as_dummy()
|
||||
|
||||
|
||||
def test_subs_CondSet():
|
||||
s = FiniteSet(z, y)
|
||||
c = ConditionSet(x, x < 2, s)
|
||||
assert c.subs(x, y) == c
|
||||
assert c.subs(z, y) == ConditionSet(x, x < 2, FiniteSet(y))
|
||||
assert c.xreplace({x: y}) == ConditionSet(y, y < 2, s)
|
||||
|
||||
assert ConditionSet(x, x < y, s
|
||||
).subs(y, w) == ConditionSet(x, x < w, s.subs(y, w))
|
||||
# if the user uses assumptions that cause the condition
|
||||
# to evaluate, that can't be helped from SymPy's end
|
||||
n = Symbol('n', negative=True)
|
||||
assert ConditionSet(n, 0 < n, S.Integers) is S.EmptySet
|
||||
p = Symbol('p', positive=True)
|
||||
assert ConditionSet(n, n < y, S.Integers
|
||||
).subs(n, x) == ConditionSet(n, n < y, S.Integers)
|
||||
raises(ValueError, lambda: ConditionSet(
|
||||
x + 1, x < 1, S.Integers))
|
||||
assert ConditionSet(
|
||||
p, n < x, Interval(-5, 5)).subs(x, p) == Interval(-5, 5), ConditionSet(
|
||||
p, n < x, Interval(-5, 5)).subs(x, p)
|
||||
assert ConditionSet(
|
||||
n, n < x, Interval(-oo, 0)).subs(x, p
|
||||
) == Interval(-oo, 0)
|
||||
|
||||
assert ConditionSet(f(x), f(x) < 1, {w, z}
|
||||
).subs(f(x), y) == ConditionSet(f(x), f(x) < 1, {w, z})
|
||||
|
||||
# issue 17341
|
||||
k = Symbol('k')
|
||||
img1 = ImageSet(Lambda(k, 2*k*pi + asin(y)), S.Integers)
|
||||
img2 = ImageSet(Lambda(k, 2*k*pi + asin(S.One/3)), S.Integers)
|
||||
assert ConditionSet(x, Contains(
|
||||
y, Interval(-1,1)), img1).subs(y, S.One/3).dummy_eq(img2)
|
||||
|
||||
assert (0, 1) in ConditionSet((x, y), x + y < 3, S.Integers**2)
|
||||
|
||||
raises(TypeError, lambda: ConditionSet(n, n < -10, Interval(0, 10)))
|
||||
|
||||
|
||||
def test_subs_CondSet_tebr():
|
||||
with warns_deprecated_sympy():
|
||||
assert ConditionSet((x, y), {x + 1, x + y}, S.Reals**2) == \
|
||||
ConditionSet((x, y), Eq(x + 1, 0) & Eq(x + y, 0), S.Reals**2)
|
||||
|
||||
|
||||
def test_dummy_eq():
|
||||
C = ConditionSet
|
||||
I = S.Integers
|
||||
c = C(x, x < 1, I)
|
||||
assert c.dummy_eq(C(y, y < 1, I))
|
||||
assert c.dummy_eq(1) == False
|
||||
assert c.dummy_eq(C(x, x < 1, S.Reals)) == False
|
||||
|
||||
c1 = ConditionSet((x, y), Eq(x + 1, 0) & Eq(x + y, 0), S.Reals**2)
|
||||
c2 = ConditionSet((x, y), Eq(x + 1, 0) & Eq(x + y, 0), S.Reals**2)
|
||||
c3 = ConditionSet((x, y), Eq(x + 1, 0) & Eq(x + y, 0), S.Complexes**2)
|
||||
assert c1.dummy_eq(c2)
|
||||
assert c1.dummy_eq(c3) is False
|
||||
assert c.dummy_eq(c1) is False
|
||||
assert c1.dummy_eq(c) is False
|
||||
|
||||
# issue 19496
|
||||
m = Symbol('m')
|
||||
n = Symbol('n')
|
||||
a = Symbol('a')
|
||||
d1 = ImageSet(Lambda(m, m*pi), S.Integers)
|
||||
d2 = ImageSet(Lambda(n, n*pi), S.Integers)
|
||||
c1 = ConditionSet(x, Ne(a, 0), d1)
|
||||
c2 = ConditionSet(x, Ne(a, 0), d2)
|
||||
assert c1.dummy_eq(c2)
|
||||
|
||||
|
||||
def test_contains():
|
||||
assert 6 in ConditionSet(x, x > 5, Interval(1, 7))
|
||||
assert (8 in ConditionSet(x, y > 5, Interval(1, 7))) is False
|
||||
# `in` should give True or False; in this case there is not
|
||||
# enough information for that result
|
||||
raises(TypeError,
|
||||
lambda: 6 in ConditionSet(x, y > 5, Interval(1, 7)))
|
||||
# here, there is enough information but the comparison is
|
||||
# not defined
|
||||
raises(TypeError, lambda: 0 in ConditionSet(x, 1/x >= 0, S.Reals))
|
||||
assert ConditionSet(x, y > 5, Interval(1, 7)
|
||||
).contains(6) == (y > 5)
|
||||
assert ConditionSet(x, y > 5, Interval(1, 7)
|
||||
).contains(8) is S.false
|
||||
assert ConditionSet(x, y > 5, Interval(1, 7)
|
||||
).contains(w) == And(Contains(w, Interval(1, 7)), y > 5)
|
||||
# This returns an unevaluated Contains object
|
||||
# because 1/0 should not be defined for 1 and 0 in the context of
|
||||
# reals.
|
||||
assert ConditionSet(x, 1/x >= 0, S.Reals).contains(0) == \
|
||||
Contains(0, ConditionSet(x, 1/x >= 0, S.Reals), evaluate=False)
|
||||
c = ConditionSet((x, y), x + y > 1, S.Integers**2)
|
||||
assert not c.contains(1)
|
||||
assert c.contains((2, 1))
|
||||
assert not c.contains((0, 1))
|
||||
c = ConditionSet((w, (x, y)), w + x + y > 1, S.Integers*S.Integers**2)
|
||||
assert not c.contains(1)
|
||||
assert not c.contains((1, 2))
|
||||
assert not c.contains(((1, 2), 3))
|
||||
assert not c.contains(((1, 2), (3, 4)))
|
||||
assert c.contains((1, (3, 4)))
|
||||
|
||||
|
||||
def test_as_relational():
|
||||
assert ConditionSet((x, y), x > 1, S.Integers**2).as_relational((x, y)
|
||||
) == (x > 1) & Contains(x, S.Integers) & Contains(y, S.Integers)
|
||||
assert ConditionSet(x, x > 1, S.Integers).as_relational(x
|
||||
) == Contains(x, S.Integers) & (x > 1)
|
||||
|
||||
|
||||
def test_flatten():
|
||||
"""Tests whether there is basic denesting functionality"""
|
||||
inner = ConditionSet(x, sin(x) + x > 0)
|
||||
outer = ConditionSet(x, Contains(x, inner), S.Reals)
|
||||
assert outer == ConditionSet(x, sin(x) + x > 0, S.Reals)
|
||||
|
||||
inner = ConditionSet(y, sin(y) + y > 0)
|
||||
outer = ConditionSet(x, Contains(y, inner), S.Reals)
|
||||
assert outer != ConditionSet(x, sin(x) + x > 0, S.Reals)
|
||||
|
||||
inner = ConditionSet(x, sin(x) + x > 0).intersect(Interval(-1, 1))
|
||||
outer = ConditionSet(x, Contains(x, inner), S.Reals)
|
||||
assert outer == ConditionSet(x, sin(x) + x > 0, Interval(-1, 1))
|
||||
|
||||
|
||||
def test_duplicate():
|
||||
from sympy.core.function import BadSignatureError
|
||||
# test coverage for line 95 in conditionset.py, check for duplicates in symbols
|
||||
dup = symbols('a,a')
|
||||
raises(BadSignatureError, lambda: ConditionSet(dup, x < 0))
|
||||
|
||||
|
||||
def test_SetKind_ConditionSet():
|
||||
assert ConditionSet(x, Eq(sin(x), 0), Interval(0, 2*pi)).kind is SetKind(NumberKind)
|
||||
assert ConditionSet(x, x < 0).kind is SetKind(NumberKind)
|
||||
@@ -0,0 +1,52 @@
|
||||
from sympy.core.expr import unchanged
|
||||
from sympy.core.numbers import oo
|
||||
from sympy.core.relational import Eq
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import Symbol
|
||||
from sympy.sets.contains import Contains
|
||||
from sympy.sets.sets import (FiniteSet, Interval)
|
||||
from sympy.testing.pytest import raises
|
||||
|
||||
|
||||
def test_contains_basic():
|
||||
raises(TypeError, lambda: Contains(S.Integers, 1))
|
||||
assert Contains(2, S.Integers) is S.true
|
||||
assert Contains(-2, S.Naturals) is S.false
|
||||
|
||||
i = Symbol('i', integer=True)
|
||||
assert Contains(i, S.Naturals) == Contains(i, S.Naturals, evaluate=False)
|
||||
|
||||
|
||||
def test_issue_6194():
|
||||
x = Symbol('x')
|
||||
assert unchanged(Contains, x, Interval(0, 1))
|
||||
assert Interval(0, 1).contains(x) == (S.Zero <= x) & (x <= 1)
|
||||
assert Contains(x, FiniteSet(0)) != S.false
|
||||
assert Contains(x, Interval(1, 1)) != S.false
|
||||
assert Contains(x, S.Integers) != S.false
|
||||
|
||||
|
||||
def test_issue_10326():
|
||||
assert Contains(oo, Interval(-oo, oo)) == False
|
||||
assert Contains(-oo, Interval(-oo, oo)) == False
|
||||
|
||||
|
||||
def test_binary_symbols():
|
||||
x = Symbol('x')
|
||||
y = Symbol('y')
|
||||
z = Symbol('z')
|
||||
assert Contains(x, FiniteSet(y, Eq(z, True))
|
||||
).binary_symbols == {y, z}
|
||||
|
||||
|
||||
def test_as_set():
|
||||
x = Symbol('x')
|
||||
y = Symbol('y')
|
||||
assert Contains(x, FiniteSet(y)).as_set() == FiniteSet(y)
|
||||
assert Contains(x, S.Integers).as_set() == S.Integers
|
||||
assert Contains(x, S.Reals).as_set() == S.Reals
|
||||
|
||||
|
||||
def test_type_error():
|
||||
# Pass in a parameter not of type "set"
|
||||
raises(TypeError, lambda: Contains(2, None))
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,67 @@
|
||||
from sympy.sets.ordinals import Ordinal, OmegaPower, ord0, omega
|
||||
from sympy.testing.pytest import raises
|
||||
|
||||
def test_string_ordinals():
|
||||
assert str(omega) == 'w'
|
||||
assert str(Ordinal(OmegaPower(5, 3), OmegaPower(3, 2))) == 'w**5*3 + w**3*2'
|
||||
assert str(Ordinal(OmegaPower(5, 3), OmegaPower(0, 5))) == 'w**5*3 + 5'
|
||||
assert str(Ordinal(OmegaPower(1, 3), OmegaPower(0, 5))) == 'w*3 + 5'
|
||||
assert str(Ordinal(OmegaPower(omega + 1, 1), OmegaPower(3, 2))) == 'w**(w + 1) + w**3*2'
|
||||
|
||||
def test_addition_with_integers():
|
||||
assert 3 + Ordinal(OmegaPower(5, 3)) == Ordinal(OmegaPower(5, 3))
|
||||
assert Ordinal(OmegaPower(5, 3))+3 == Ordinal(OmegaPower(5, 3), OmegaPower(0, 3))
|
||||
assert Ordinal(OmegaPower(5, 3), OmegaPower(0, 2))+3 == \
|
||||
Ordinal(OmegaPower(5, 3), OmegaPower(0, 5))
|
||||
|
||||
|
||||
def test_addition_with_ordinals():
|
||||
assert Ordinal(OmegaPower(5, 3), OmegaPower(3, 2)) + Ordinal(OmegaPower(3, 3)) == \
|
||||
Ordinal(OmegaPower(5, 3), OmegaPower(3, 5))
|
||||
assert Ordinal(OmegaPower(5, 3), OmegaPower(3, 2)) + Ordinal(OmegaPower(4, 2)) == \
|
||||
Ordinal(OmegaPower(5, 3), OmegaPower(4, 2))
|
||||
assert Ordinal(OmegaPower(omega, 2), OmegaPower(3, 2)) + Ordinal(OmegaPower(4, 2)) == \
|
||||
Ordinal(OmegaPower(omega, 2), OmegaPower(4, 2))
|
||||
|
||||
def test_comparison():
|
||||
assert Ordinal(OmegaPower(5, 3)) > Ordinal(OmegaPower(4, 3), OmegaPower(2, 1))
|
||||
assert Ordinal(OmegaPower(5, 3), OmegaPower(3, 2)) < Ordinal(OmegaPower(5, 4))
|
||||
assert Ordinal(OmegaPower(5, 4)) < Ordinal(OmegaPower(5, 5), OmegaPower(4, 1))
|
||||
|
||||
assert Ordinal(OmegaPower(5, 3), OmegaPower(3, 2)) == \
|
||||
Ordinal(OmegaPower(5, 3), OmegaPower(3, 2))
|
||||
assert not Ordinal(OmegaPower(5, 3), OmegaPower(3, 2)) == Ordinal(OmegaPower(5, 3))
|
||||
assert Ordinal(OmegaPower(omega, 3)) > Ordinal(OmegaPower(5, 3))
|
||||
|
||||
def test_multiplication_with_integers():
|
||||
w = omega
|
||||
assert 3*w == w
|
||||
assert w*9 == Ordinal(OmegaPower(1, 9))
|
||||
|
||||
def test_multiplication():
|
||||
w = omega
|
||||
assert w*(w + 1) == w*w + w
|
||||
assert (w + 1)*(w + 1) == w*w + w + 1
|
||||
assert w*1 == w
|
||||
assert 1*w == w
|
||||
assert w*ord0 == ord0
|
||||
assert ord0*w == ord0
|
||||
assert w**w == w * w**w
|
||||
assert (w**w)*w*w == w**(w + 2)
|
||||
|
||||
def test_exponentiation():
|
||||
w = omega
|
||||
assert w**2 == w*w
|
||||
assert w**3 == w*w*w
|
||||
assert w**(w + 1) == Ordinal(OmegaPower(omega + 1, 1))
|
||||
assert (w**w)*(w**w) == w**(w*2)
|
||||
|
||||
def test_comapre_not_instance():
|
||||
w = OmegaPower(omega + 1, 1)
|
||||
assert(not (w == None))
|
||||
assert(not (w < 5))
|
||||
raises(TypeError, lambda: w < 6.66)
|
||||
|
||||
def test_is_successort():
|
||||
w = Ordinal(OmegaPower(5, 1))
|
||||
assert not w.is_successor_ordinal
|
||||
@@ -0,0 +1,141 @@
|
||||
from sympy.core.expr import unchanged
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import Symbol
|
||||
from sympy.sets.contains import Contains
|
||||
from sympy.sets.fancysets import Interval
|
||||
from sympy.sets.powerset import PowerSet
|
||||
from sympy.sets.sets import FiniteSet
|
||||
from sympy.testing.pytest import raises, XFAIL
|
||||
|
||||
|
||||
def test_powerset_creation():
|
||||
assert unchanged(PowerSet, FiniteSet(1, 2))
|
||||
assert unchanged(PowerSet, S.EmptySet)
|
||||
raises(ValueError, lambda: PowerSet(123))
|
||||
assert unchanged(PowerSet, S.Reals)
|
||||
assert unchanged(PowerSet, S.Integers)
|
||||
|
||||
|
||||
def test_powerset_rewrite_FiniteSet():
|
||||
assert PowerSet(FiniteSet(1, 2)).rewrite(FiniteSet) == \
|
||||
FiniteSet(S.EmptySet, FiniteSet(1), FiniteSet(2), FiniteSet(1, 2))
|
||||
assert PowerSet(S.EmptySet).rewrite(FiniteSet) == FiniteSet(S.EmptySet)
|
||||
assert PowerSet(S.Naturals).rewrite(FiniteSet) == PowerSet(S.Naturals)
|
||||
|
||||
|
||||
def test_finiteset_rewrite_powerset():
|
||||
assert FiniteSet(S.EmptySet).rewrite(PowerSet) == PowerSet(S.EmptySet)
|
||||
assert FiniteSet(
|
||||
S.EmptySet, FiniteSet(1),
|
||||
FiniteSet(2), FiniteSet(1, 2)).rewrite(PowerSet) == \
|
||||
PowerSet(FiniteSet(1, 2))
|
||||
assert FiniteSet(1, 2, 3).rewrite(PowerSet) == FiniteSet(1, 2, 3)
|
||||
|
||||
|
||||
def test_powerset__contains__():
|
||||
subset_series = [
|
||||
S.EmptySet,
|
||||
FiniteSet(1, 2),
|
||||
S.Naturals,
|
||||
S.Naturals0,
|
||||
S.Integers,
|
||||
S.Rationals,
|
||||
S.Reals,
|
||||
S.Complexes]
|
||||
|
||||
l = len(subset_series)
|
||||
for i in range(l):
|
||||
for j in range(l):
|
||||
if i <= j:
|
||||
assert subset_series[i] in \
|
||||
PowerSet(subset_series[j], evaluate=False)
|
||||
else:
|
||||
assert subset_series[i] not in \
|
||||
PowerSet(subset_series[j], evaluate=False)
|
||||
|
||||
|
||||
@XFAIL
|
||||
def test_failing_powerset__contains__():
|
||||
# XXX These are failing when evaluate=True,
|
||||
# but using unevaluated PowerSet works fine.
|
||||
assert FiniteSet(1, 2) not in PowerSet(S.EmptySet).rewrite(FiniteSet)
|
||||
assert S.Naturals not in PowerSet(S.EmptySet).rewrite(FiniteSet)
|
||||
assert S.Naturals not in PowerSet(FiniteSet(1, 2)).rewrite(FiniteSet)
|
||||
assert S.Naturals0 not in PowerSet(S.EmptySet).rewrite(FiniteSet)
|
||||
assert S.Naturals0 not in PowerSet(FiniteSet(1, 2)).rewrite(FiniteSet)
|
||||
assert S.Integers not in PowerSet(S.EmptySet).rewrite(FiniteSet)
|
||||
assert S.Integers not in PowerSet(FiniteSet(1, 2)).rewrite(FiniteSet)
|
||||
assert S.Rationals not in PowerSet(S.EmptySet).rewrite(FiniteSet)
|
||||
assert S.Rationals not in PowerSet(FiniteSet(1, 2)).rewrite(FiniteSet)
|
||||
assert S.Reals not in PowerSet(S.EmptySet).rewrite(FiniteSet)
|
||||
assert S.Reals not in PowerSet(FiniteSet(1, 2)).rewrite(FiniteSet)
|
||||
assert S.Complexes not in PowerSet(S.EmptySet).rewrite(FiniteSet)
|
||||
assert S.Complexes not in PowerSet(FiniteSet(1, 2)).rewrite(FiniteSet)
|
||||
|
||||
|
||||
def test_powerset__len__():
|
||||
A = PowerSet(S.EmptySet, evaluate=False)
|
||||
assert len(A) == 1
|
||||
A = PowerSet(A, evaluate=False)
|
||||
assert len(A) == 2
|
||||
A = PowerSet(A, evaluate=False)
|
||||
assert len(A) == 4
|
||||
A = PowerSet(A, evaluate=False)
|
||||
assert len(A) == 16
|
||||
|
||||
|
||||
def test_powerset__iter__():
|
||||
a = PowerSet(FiniteSet(1, 2)).__iter__()
|
||||
assert next(a) == S.EmptySet
|
||||
assert next(a) == FiniteSet(1)
|
||||
assert next(a) == FiniteSet(2)
|
||||
assert next(a) == FiniteSet(1, 2)
|
||||
|
||||
a = PowerSet(S.Naturals).__iter__()
|
||||
assert next(a) == S.EmptySet
|
||||
assert next(a) == FiniteSet(1)
|
||||
assert next(a) == FiniteSet(2)
|
||||
assert next(a) == FiniteSet(1, 2)
|
||||
assert next(a) == FiniteSet(3)
|
||||
assert next(a) == FiniteSet(1, 3)
|
||||
assert next(a) == FiniteSet(2, 3)
|
||||
assert next(a) == FiniteSet(1, 2, 3)
|
||||
|
||||
|
||||
def test_powerset_contains():
|
||||
A = PowerSet(FiniteSet(1), evaluate=False)
|
||||
assert A.contains(2) == Contains(2, A)
|
||||
|
||||
x = Symbol('x')
|
||||
|
||||
A = PowerSet(FiniteSet(x), evaluate=False)
|
||||
assert A.contains(FiniteSet(1)) == Contains(FiniteSet(1), A)
|
||||
|
||||
|
||||
def test_powerset_method():
|
||||
# EmptySet
|
||||
A = FiniteSet()
|
||||
pset = A.powerset()
|
||||
assert len(pset) == 1
|
||||
assert pset == FiniteSet(S.EmptySet)
|
||||
|
||||
# FiniteSets
|
||||
A = FiniteSet(1, 2)
|
||||
pset = A.powerset()
|
||||
assert len(pset) == 2**len(A)
|
||||
assert pset == FiniteSet(FiniteSet(), FiniteSet(1),
|
||||
FiniteSet(2), A)
|
||||
# Not finite sets
|
||||
A = Interval(0, 1)
|
||||
assert A.powerset() == PowerSet(A)
|
||||
|
||||
def test_is_subset():
|
||||
# covers line 101-102
|
||||
# initialize powerset(1), which is a subset of powerset(1,2)
|
||||
subset = PowerSet(FiniteSet(1))
|
||||
pset = PowerSet(FiniteSet(1, 2))
|
||||
bad_set = PowerSet(FiniteSet(2, 3))
|
||||
# assert "subset" is subset of pset == True
|
||||
assert subset.is_subset(pset)
|
||||
# assert "bad_set" is subset of pset == False
|
||||
assert not pset.is_subset(bad_set)
|
||||
@@ -0,0 +1,317 @@
|
||||
from sympy.sets.setexpr import SetExpr
|
||||
from sympy.sets import Interval, FiniteSet, Intersection, ImageSet, Union
|
||||
|
||||
from sympy.core.expr import Expr
|
||||
from sympy.core.function import Lambda
|
||||
from sympy.core.numbers import (I, Rational, oo)
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import (Dummy, Symbol, symbols)
|
||||
from sympy.functions.elementary.exponential import (exp, log)
|
||||
from sympy.functions.elementary.miscellaneous import (Max, Min, sqrt)
|
||||
from sympy.functions.elementary.trigonometric import cos
|
||||
from sympy.sets.sets import Set
|
||||
|
||||
|
||||
a, x = symbols("a, x")
|
||||
_d = Dummy("d")
|
||||
|
||||
|
||||
def test_setexpr():
|
||||
se = SetExpr(Interval(0, 1))
|
||||
assert isinstance(se.set, Set)
|
||||
assert isinstance(se, Expr)
|
||||
|
||||
|
||||
def test_scalar_funcs():
|
||||
assert SetExpr(Interval(0, 1)).set == Interval(0, 1)
|
||||
a, b = Symbol('a', real=True), Symbol('b', real=True)
|
||||
a, b = 1, 2
|
||||
# TODO: add support for more functions in the future:
|
||||
for f in [exp, log]:
|
||||
input_se = f(SetExpr(Interval(a, b)))
|
||||
output = input_se.set
|
||||
expected = Interval(Min(f(a), f(b)), Max(f(a), f(b)))
|
||||
assert output == expected
|
||||
|
||||
|
||||
def test_Add_Mul():
|
||||
assert (SetExpr(Interval(0, 1)) + 1).set == Interval(1, 2)
|
||||
assert (SetExpr(Interval(0, 1))*2).set == Interval(0, 2)
|
||||
|
||||
|
||||
def test_Pow():
|
||||
assert (SetExpr(Interval(0, 2))**2).set == Interval(0, 4)
|
||||
|
||||
|
||||
def test_compound():
|
||||
assert (exp(SetExpr(Interval(0, 1))*2 + 1)).set == \
|
||||
Interval(exp(1), exp(3))
|
||||
|
||||
|
||||
def test_Interval_Interval():
|
||||
assert (SetExpr(Interval(1, 2)) + SetExpr(Interval(10, 20))).set == \
|
||||
Interval(11, 22)
|
||||
assert (SetExpr(Interval(1, 2))*SetExpr(Interval(10, 20))).set == \
|
||||
Interval(10, 40)
|
||||
|
||||
|
||||
def test_FiniteSet_FiniteSet():
|
||||
assert (SetExpr(FiniteSet(1, 2, 3)) + SetExpr(FiniteSet(1, 2))).set == \
|
||||
FiniteSet(2, 3, 4, 5)
|
||||
assert (SetExpr(FiniteSet(1, 2, 3))*SetExpr(FiniteSet(1, 2))).set == \
|
||||
FiniteSet(1, 2, 3, 4, 6)
|
||||
|
||||
|
||||
def test_Interval_FiniteSet():
|
||||
assert (SetExpr(FiniteSet(1, 2)) + SetExpr(Interval(0, 10))).set == \
|
||||
Interval(1, 12)
|
||||
|
||||
|
||||
def test_Many_Sets():
|
||||
assert (SetExpr(Interval(0, 1)) +
|
||||
SetExpr(Interval(2, 3)) +
|
||||
SetExpr(FiniteSet(10, 11, 12))).set == Interval(12, 16)
|
||||
|
||||
|
||||
def test_same_setexprs_are_not_identical():
|
||||
a = SetExpr(FiniteSet(0, 1))
|
||||
b = SetExpr(FiniteSet(0, 1))
|
||||
assert (a + b).set == FiniteSet(0, 1, 2)
|
||||
|
||||
# Cannot detect the set being the same:
|
||||
# assert (a + a).set == FiniteSet(0, 2)
|
||||
|
||||
|
||||
def test_Interval_arithmetic():
|
||||
i12cc = SetExpr(Interval(1, 2))
|
||||
i12lo = SetExpr(Interval.Lopen(1, 2))
|
||||
i12ro = SetExpr(Interval.Ropen(1, 2))
|
||||
i12o = SetExpr(Interval.open(1, 2))
|
||||
|
||||
n23cc = SetExpr(Interval(-2, 3))
|
||||
n23lo = SetExpr(Interval.Lopen(-2, 3))
|
||||
n23ro = SetExpr(Interval.Ropen(-2, 3))
|
||||
n23o = SetExpr(Interval.open(-2, 3))
|
||||
|
||||
n3n2cc = SetExpr(Interval(-3, -2))
|
||||
|
||||
assert i12cc + i12cc == SetExpr(Interval(2, 4))
|
||||
assert i12cc - i12cc == SetExpr(Interval(-1, 1))
|
||||
assert i12cc*i12cc == SetExpr(Interval(1, 4))
|
||||
assert i12cc/i12cc == SetExpr(Interval(S.Half, 2))
|
||||
assert i12cc**2 == SetExpr(Interval(1, 4))
|
||||
assert i12cc**3 == SetExpr(Interval(1, 8))
|
||||
|
||||
assert i12lo + i12ro == SetExpr(Interval.open(2, 4))
|
||||
assert i12lo - i12ro == SetExpr(Interval.Lopen(-1, 1))
|
||||
assert i12lo*i12ro == SetExpr(Interval.open(1, 4))
|
||||
assert i12lo/i12ro == SetExpr(Interval.Lopen(S.Half, 2))
|
||||
assert i12lo + i12lo == SetExpr(Interval.Lopen(2, 4))
|
||||
assert i12lo - i12lo == SetExpr(Interval.open(-1, 1))
|
||||
assert i12lo*i12lo == SetExpr(Interval.Lopen(1, 4))
|
||||
assert i12lo/i12lo == SetExpr(Interval.open(S.Half, 2))
|
||||
assert i12lo + i12cc == SetExpr(Interval.Lopen(2, 4))
|
||||
assert i12lo - i12cc == SetExpr(Interval.Lopen(-1, 1))
|
||||
assert i12lo*i12cc == SetExpr(Interval.Lopen(1, 4))
|
||||
assert i12lo/i12cc == SetExpr(Interval.Lopen(S.Half, 2))
|
||||
assert i12lo + i12o == SetExpr(Interval.open(2, 4))
|
||||
assert i12lo - i12o == SetExpr(Interval.open(-1, 1))
|
||||
assert i12lo*i12o == SetExpr(Interval.open(1, 4))
|
||||
assert i12lo/i12o == SetExpr(Interval.open(S.Half, 2))
|
||||
assert i12lo**2 == SetExpr(Interval.Lopen(1, 4))
|
||||
assert i12lo**3 == SetExpr(Interval.Lopen(1, 8))
|
||||
|
||||
assert i12ro + i12ro == SetExpr(Interval.Ropen(2, 4))
|
||||
assert i12ro - i12ro == SetExpr(Interval.open(-1, 1))
|
||||
assert i12ro*i12ro == SetExpr(Interval.Ropen(1, 4))
|
||||
assert i12ro/i12ro == SetExpr(Interval.open(S.Half, 2))
|
||||
assert i12ro + i12cc == SetExpr(Interval.Ropen(2, 4))
|
||||
assert i12ro - i12cc == SetExpr(Interval.Ropen(-1, 1))
|
||||
assert i12ro*i12cc == SetExpr(Interval.Ropen(1, 4))
|
||||
assert i12ro/i12cc == SetExpr(Interval.Ropen(S.Half, 2))
|
||||
assert i12ro + i12o == SetExpr(Interval.open(2, 4))
|
||||
assert i12ro - i12o == SetExpr(Interval.open(-1, 1))
|
||||
assert i12ro*i12o == SetExpr(Interval.open(1, 4))
|
||||
assert i12ro/i12o == SetExpr(Interval.open(S.Half, 2))
|
||||
assert i12ro**2 == SetExpr(Interval.Ropen(1, 4))
|
||||
assert i12ro**3 == SetExpr(Interval.Ropen(1, 8))
|
||||
|
||||
assert i12o + i12lo == SetExpr(Interval.open(2, 4))
|
||||
assert i12o - i12lo == SetExpr(Interval.open(-1, 1))
|
||||
assert i12o*i12lo == SetExpr(Interval.open(1, 4))
|
||||
assert i12o/i12lo == SetExpr(Interval.open(S.Half, 2))
|
||||
assert i12o + i12ro == SetExpr(Interval.open(2, 4))
|
||||
assert i12o - i12ro == SetExpr(Interval.open(-1, 1))
|
||||
assert i12o*i12ro == SetExpr(Interval.open(1, 4))
|
||||
assert i12o/i12ro == SetExpr(Interval.open(S.Half, 2))
|
||||
assert i12o + i12cc == SetExpr(Interval.open(2, 4))
|
||||
assert i12o - i12cc == SetExpr(Interval.open(-1, 1))
|
||||
assert i12o*i12cc == SetExpr(Interval.open(1, 4))
|
||||
assert i12o/i12cc == SetExpr(Interval.open(S.Half, 2))
|
||||
assert i12o**2 == SetExpr(Interval.open(1, 4))
|
||||
assert i12o**3 == SetExpr(Interval.open(1, 8))
|
||||
|
||||
assert n23cc + n23cc == SetExpr(Interval(-4, 6))
|
||||
assert n23cc - n23cc == SetExpr(Interval(-5, 5))
|
||||
assert n23cc*n23cc == SetExpr(Interval(-6, 9))
|
||||
assert n23cc/n23cc == SetExpr(Interval.open(-oo, oo))
|
||||
assert n23cc + n23ro == SetExpr(Interval.Ropen(-4, 6))
|
||||
assert n23cc - n23ro == SetExpr(Interval.Lopen(-5, 5))
|
||||
assert n23cc*n23ro == SetExpr(Interval.Ropen(-6, 9))
|
||||
assert n23cc/n23ro == SetExpr(Interval.Lopen(-oo, oo))
|
||||
assert n23cc + n23lo == SetExpr(Interval.Lopen(-4, 6))
|
||||
assert n23cc - n23lo == SetExpr(Interval.Ropen(-5, 5))
|
||||
assert n23cc*n23lo == SetExpr(Interval(-6, 9))
|
||||
assert n23cc/n23lo == SetExpr(Interval.open(-oo, oo))
|
||||
assert n23cc + n23o == SetExpr(Interval.open(-4, 6))
|
||||
assert n23cc - n23o == SetExpr(Interval.open(-5, 5))
|
||||
assert n23cc*n23o == SetExpr(Interval.open(-6, 9))
|
||||
assert n23cc/n23o == SetExpr(Interval.open(-oo, oo))
|
||||
assert n23cc**2 == SetExpr(Interval(0, 9))
|
||||
assert n23cc**3 == SetExpr(Interval(-8, 27))
|
||||
|
||||
n32cc = SetExpr(Interval(-3, 2))
|
||||
n32lo = SetExpr(Interval.Lopen(-3, 2))
|
||||
n32ro = SetExpr(Interval.Ropen(-3, 2))
|
||||
assert n32cc*n32lo == SetExpr(Interval.Ropen(-6, 9))
|
||||
assert n32cc*n32cc == SetExpr(Interval(-6, 9))
|
||||
assert n32lo*n32cc == SetExpr(Interval.Ropen(-6, 9))
|
||||
assert n32cc*n32ro == SetExpr(Interval(-6, 9))
|
||||
assert n32lo*n32ro == SetExpr(Interval.Ropen(-6, 9))
|
||||
assert n32cc/n32lo == SetExpr(Interval.Ropen(-oo, oo))
|
||||
assert i12cc/n32lo == SetExpr(Interval.Ropen(-oo, oo))
|
||||
|
||||
assert n3n2cc**2 == SetExpr(Interval(4, 9))
|
||||
assert n3n2cc**3 == SetExpr(Interval(-27, -8))
|
||||
|
||||
assert n23cc + i12cc == SetExpr(Interval(-1, 5))
|
||||
assert n23cc - i12cc == SetExpr(Interval(-4, 2))
|
||||
assert n23cc*i12cc == SetExpr(Interval(-4, 6))
|
||||
assert n23cc/i12cc == SetExpr(Interval(-2, 3))
|
||||
|
||||
|
||||
def test_SetExpr_Intersection():
|
||||
x, y, z, w = symbols("x y z w")
|
||||
set1 = Interval(x, y)
|
||||
set2 = Interval(w, z)
|
||||
inter = Intersection(set1, set2)
|
||||
se = SetExpr(inter)
|
||||
assert exp(se).set == Intersection(
|
||||
ImageSet(Lambda(x, exp(x)), set1),
|
||||
ImageSet(Lambda(x, exp(x)), set2))
|
||||
assert cos(se).set == ImageSet(Lambda(x, cos(x)), inter)
|
||||
|
||||
|
||||
def test_SetExpr_Interval_div():
|
||||
# TODO: some expressions cannot be calculated due to bugs (currently
|
||||
# commented):
|
||||
assert SetExpr(Interval(-3, -2))/SetExpr(Interval(-2, 1)) == SetExpr(Interval(-oo, oo))
|
||||
assert SetExpr(Interval(2, 3))/SetExpr(Interval(-2, 2)) == SetExpr(Interval(-oo, oo))
|
||||
|
||||
assert SetExpr(Interval(-3, -2))/SetExpr(Interval(0, 4)) == SetExpr(Interval(-oo, Rational(-1, 2)))
|
||||
assert SetExpr(Interval(2, 4))/SetExpr(Interval(-3, 0)) == SetExpr(Interval(-oo, Rational(-2, 3)))
|
||||
assert SetExpr(Interval(2, 4))/SetExpr(Interval(0, 3)) == SetExpr(Interval(Rational(2, 3), oo))
|
||||
|
||||
# assert SetExpr(Interval(0, 1))/SetExpr(Interval(0, 1)) == SetExpr(Interval(0, oo))
|
||||
# assert SetExpr(Interval(-1, 0))/SetExpr(Interval(0, 1)) == SetExpr(Interval(-oo, 0))
|
||||
assert SetExpr(Interval(-1, 2))/SetExpr(Interval(-2, 2)) == SetExpr(Interval(-oo, oo))
|
||||
|
||||
assert 1/SetExpr(Interval(-1, 2)) == SetExpr(Union(Interval(-oo, -1), Interval(S.Half, oo)))
|
||||
|
||||
assert 1/SetExpr(Interval(0, 2)) == SetExpr(Interval(S.Half, oo))
|
||||
assert (-1)/SetExpr(Interval(0, 2)) == SetExpr(Interval(-oo, Rational(-1, 2)))
|
||||
assert 1/SetExpr(Interval(-oo, 0)) == SetExpr(Interval.open(-oo, 0))
|
||||
assert 1/SetExpr(Interval(-1, 0)) == SetExpr(Interval(-oo, -1))
|
||||
# assert (-2)/SetExpr(Interval(-oo, 0)) == SetExpr(Interval(0, oo))
|
||||
# assert 1/SetExpr(Interval(-oo, -1)) == SetExpr(Interval(-1, 0))
|
||||
|
||||
# assert SetExpr(Interval(1, 2))/a == Mul(SetExpr(Interval(1, 2)), 1/a, evaluate=False)
|
||||
|
||||
# assert SetExpr(Interval(1, 2))/0 == SetExpr(Interval(1, 2))*zoo
|
||||
# assert SetExpr(Interval(1, oo))/oo == SetExpr(Interval(0, oo))
|
||||
# assert SetExpr(Interval(1, oo))/(-oo) == SetExpr(Interval(-oo, 0))
|
||||
# assert SetExpr(Interval(-oo, -1))/oo == SetExpr(Interval(-oo, 0))
|
||||
# assert SetExpr(Interval(-oo, -1))/(-oo) == SetExpr(Interval(0, oo))
|
||||
# assert SetExpr(Interval(-oo, oo))/oo == SetExpr(Interval(-oo, oo))
|
||||
# assert SetExpr(Interval(-oo, oo))/(-oo) == SetExpr(Interval(-oo, oo))
|
||||
# assert SetExpr(Interval(-1, oo))/oo == SetExpr(Interval(0, oo))
|
||||
# assert SetExpr(Interval(-1, oo))/(-oo) == SetExpr(Interval(-oo, 0))
|
||||
# assert SetExpr(Interval(-oo, 1))/oo == SetExpr(Interval(-oo, 0))
|
||||
# assert SetExpr(Interval(-oo, 1))/(-oo) == SetExpr(Interval(0, oo))
|
||||
|
||||
|
||||
def test_SetExpr_Interval_pow():
|
||||
assert SetExpr(Interval(0, 2))**2 == SetExpr(Interval(0, 4))
|
||||
assert SetExpr(Interval(-1, 1))**2 == SetExpr(Interval(0, 1))
|
||||
assert SetExpr(Interval(1, 2))**2 == SetExpr(Interval(1, 4))
|
||||
assert SetExpr(Interval(-1, 2))**3 == SetExpr(Interval(-1, 8))
|
||||
assert SetExpr(Interval(-1, 1))**0 == SetExpr(FiniteSet(1))
|
||||
|
||||
|
||||
assert SetExpr(Interval(1, 2))**Rational(5, 2) == SetExpr(Interval(1, 4*sqrt(2)))
|
||||
#assert SetExpr(Interval(-1, 2))**Rational(1, 3) == SetExpr(Interval(-1, 2**Rational(1, 3)))
|
||||
#assert SetExpr(Interval(0, 2))**S.Half == SetExpr(Interval(0, sqrt(2)))
|
||||
|
||||
#assert SetExpr(Interval(-4, 2))**Rational(2, 3) == SetExpr(Interval(0, 2*2**Rational(1, 3)))
|
||||
|
||||
#assert SetExpr(Interval(-1, 5))**S.Half == SetExpr(Interval(0, sqrt(5)))
|
||||
#assert SetExpr(Interval(-oo, 2))**S.Half == SetExpr(Interval(0, sqrt(2)))
|
||||
#assert SetExpr(Interval(-2, 3))**(Rational(-1, 4)) == SetExpr(Interval(0, oo))
|
||||
|
||||
assert SetExpr(Interval(1, 5))**(-2) == SetExpr(Interval(Rational(1, 25), 1))
|
||||
assert SetExpr(Interval(-1, 3))**(-2) == SetExpr(Interval(0, oo))
|
||||
|
||||
assert SetExpr(Interval(0, 2))**(-2) == SetExpr(Interval(Rational(1, 4), oo))
|
||||
assert SetExpr(Interval(-1, 2))**(-3) == SetExpr(Union(Interval(-oo, -1), Interval(Rational(1, 8), oo)))
|
||||
assert SetExpr(Interval(-3, -2))**(-3) == SetExpr(Interval(Rational(-1, 8), Rational(-1, 27)))
|
||||
assert SetExpr(Interval(-3, -2))**(-2) == SetExpr(Interval(Rational(1, 9), Rational(1, 4)))
|
||||
#assert SetExpr(Interval(0, oo))**S.Half == SetExpr(Interval(0, oo))
|
||||
#assert SetExpr(Interval(-oo, -1))**Rational(1, 3) == SetExpr(Interval(-oo, -1))
|
||||
#assert SetExpr(Interval(-2, 3))**(Rational(-1, 3)) == SetExpr(Interval(-oo, oo))
|
||||
|
||||
assert SetExpr(Interval(-oo, 0))**(-2) == SetExpr(Interval.open(0, oo))
|
||||
assert SetExpr(Interval(-2, 0))**(-2) == SetExpr(Interval(Rational(1, 4), oo))
|
||||
|
||||
assert SetExpr(Interval(Rational(1, 3), S.Half))**oo == SetExpr(FiniteSet(0))
|
||||
assert SetExpr(Interval(0, S.Half))**oo == SetExpr(FiniteSet(0))
|
||||
assert SetExpr(Interval(S.Half, 1))**oo == SetExpr(Interval(0, oo))
|
||||
assert SetExpr(Interval(0, 1))**oo == SetExpr(Interval(0, oo))
|
||||
assert SetExpr(Interval(2, 3))**oo == SetExpr(FiniteSet(oo))
|
||||
assert SetExpr(Interval(1, 2))**oo == SetExpr(Interval(0, oo))
|
||||
assert SetExpr(Interval(S.Half, 3))**oo == SetExpr(Interval(0, oo))
|
||||
assert SetExpr(Interval(Rational(-1, 3), Rational(-1, 4)))**oo == SetExpr(FiniteSet(0))
|
||||
assert SetExpr(Interval(-1, Rational(-1, 2)))**oo == SetExpr(Interval(-oo, oo))
|
||||
assert SetExpr(Interval(-3, -2))**oo == SetExpr(FiniteSet(-oo, oo))
|
||||
assert SetExpr(Interval(-2, -1))**oo == SetExpr(Interval(-oo, oo))
|
||||
assert SetExpr(Interval(-2, Rational(-1, 2)))**oo == SetExpr(Interval(-oo, oo))
|
||||
assert SetExpr(Interval(Rational(-1, 2), S.Half))**oo == SetExpr(FiniteSet(0))
|
||||
assert SetExpr(Interval(Rational(-1, 2), 1))**oo == SetExpr(Interval(0, oo))
|
||||
assert SetExpr(Interval(Rational(-2, 3), 2))**oo == SetExpr(Interval(0, oo))
|
||||
assert SetExpr(Interval(-1, 1))**oo == SetExpr(Interval(-oo, oo))
|
||||
assert SetExpr(Interval(-1, S.Half))**oo == SetExpr(Interval(-oo, oo))
|
||||
assert SetExpr(Interval(-1, 2))**oo == SetExpr(Interval(-oo, oo))
|
||||
assert SetExpr(Interval(-2, S.Half))**oo == SetExpr(Interval(-oo, oo))
|
||||
|
||||
assert (SetExpr(Interval(1, 2))**x).dummy_eq(SetExpr(ImageSet(Lambda(_d, _d**x), Interval(1, 2))))
|
||||
|
||||
assert SetExpr(Interval(2, 3))**(-oo) == SetExpr(FiniteSet(0))
|
||||
assert SetExpr(Interval(0, 2))**(-oo) == SetExpr(Interval(0, oo))
|
||||
assert (SetExpr(Interval(-1, 2))**(-oo)).dummy_eq(SetExpr(ImageSet(Lambda(_d, _d**(-oo)), Interval(-1, 2))))
|
||||
|
||||
|
||||
def test_SetExpr_Integers():
|
||||
assert SetExpr(S.Integers) + 1 == SetExpr(S.Integers)
|
||||
assert (SetExpr(S.Integers) + I).dummy_eq(
|
||||
SetExpr(ImageSet(Lambda(_d, _d + I), S.Integers)))
|
||||
assert SetExpr(S.Integers)*(-1) == SetExpr(S.Integers)
|
||||
assert (SetExpr(S.Integers)*2).dummy_eq(
|
||||
SetExpr(ImageSet(Lambda(_d, 2*_d), S.Integers)))
|
||||
assert (SetExpr(S.Integers)*I).dummy_eq(
|
||||
SetExpr(ImageSet(Lambda(_d, I*_d), S.Integers)))
|
||||
# issue #18050:
|
||||
assert SetExpr(S.Integers)._eval_func(Lambda(x, I*x + 1)).dummy_eq(
|
||||
SetExpr(ImageSet(Lambda(_d, I*_d + 1), S.Integers)))
|
||||
# needs improvement:
|
||||
assert (SetExpr(S.Integers)*I + 1).dummy_eq(
|
||||
SetExpr(ImageSet(Lambda(x, x + 1),
|
||||
ImageSet(Lambda(_d, _d*I), S.Integers))))
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user