AI Newsletter Digest improvements: fixed QP soft line break decoding, URL extraction, and content cleaning
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',
|
||||
]
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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)
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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