Skip to content

Commit

Permalink
Merge pull request #2341 from mrocklin/image-set
Browse files Browse the repository at this point in the history
Replace TransformationSet term with ImageSet
  • Loading branch information
mrocklin committed Aug 9, 2013
2 parents 0ef7411 + 661f093 commit 196fdb3
Show file tree
Hide file tree
Showing 11 changed files with 106 additions and 84 deletions.
6 changes: 3 additions & 3 deletions doc/src/modules/sets.rst
Expand Up @@ -65,8 +65,8 @@ Integers
.. autoclass:: Integers
:members:

TransformationSet
^^^^^^^^^^^^^^^^^
.. autoclass:: TransformationSet
ImageSet
^^^^^^^^
.. autoclass:: ImageSet
:members:

2 changes: 1 addition & 1 deletion sympy/core/__init__.py
Expand Up @@ -23,7 +23,7 @@
expand_trig, expand_complex, expand_multinomial, nfloat, \
expand_power_base, expand_power_exp
from .sets import (Set, Interval, Union, EmptySet, FiniteSet, ProductSet,
Intersection)
Intersection, imageset)
from .evalf import PrecisionExhausted, N
from .containers import Tuple, Dict
from .exprtools import gcd_terms, factor_terms, factor_nc
Expand Down
85 changes: 46 additions & 39 deletions sympy/core/sets.py
Expand Up @@ -228,37 +228,9 @@ def measure(self):
"""
return self._measure

def transform(self, *args):
""" Image of set under transformation ``f``
.. math::
{ f(x) | x \in self }
Examples
========
>>> from sympy import Interval, Symbol
>>> x = Symbol('x')
>>> Interval(0, 2).transform(x, 2*x)
[0, 4]
>>> Interval(0, 2).transform(lambda x: 2*x)
[0, 4]
See Also:
TransformationSet
"""
if len(args) == 2:
from sympy import Lambda
f = Lambda(*args)
else:
f, = args
return self._transform(f)

def _transform(self, f):
from sympy.sets.fancysets import TransformationSet
return TransformationSet(f, self)
def _eval_imageset(self, f):
from sympy.sets.fancysets import ImageSet
return ImageSet(f, self)

@property
def _measure(self):
Expand Down Expand Up @@ -663,9 +635,14 @@ def _contains(self, other):

return expr

def _transform(self, f):
# TODO: manage left_open and right_open better
def _eval_imageset(self, f):
# Cut out 0, perform image, add back in image of 0
if self.contains(0) == True:
return imageset(f, self - FiniteSet(0)) + imageset(f, FiniteSet(0))

from sympy.functions.elementary.miscellaneous import Min, Max
# TODO: manage left_open and right_open better in case of
# non-comparable left/right (e.g. Interval(x, y))
_left, _right = f(self.left), f(self.right)
left, right = Min(_left, _right), Max(_left, _right)
if _right == left: # switch happened
Expand Down Expand Up @@ -896,8 +873,8 @@ def _measure(self):
parity *= -1
return measure

def _transform(self, f):
return Union(arg.transform(f) for arg in self.args)
def _eval_imageset(self, f):
return Union(imageset(f, arg) for arg in self.args)

def as_relational(self, symbol):
"""Rewrite a Union in terms of equalities and logic operators. """
Expand Down Expand Up @@ -997,8 +974,8 @@ def _sup(self):
def _complement(self):
raise NotImplementedError()

def _transform(self, f):
return Intersection(arg.transform(f) for arg in self.args)
def _eval_imageset(self, f):
return Intersection(imageset(f, arg) for arg in self.args)

def _contains(self, other):
from sympy.logic.boolalg import And
Expand Down Expand Up @@ -1127,7 +1104,7 @@ def _union(self, other):
def __iter__(self):
return iter([])

def _transform(self, f):
def _eval_imageset(self, f):
return self

class UniversalSet(with_metaclass(Singleton, Set)):
Expand Down Expand Up @@ -1263,7 +1240,7 @@ def _contains(self, other):
"""
return other in self._elements

def _transform(self, f):
def _eval_imageset(self, f):
return FiniteSet(*map(f, self))

@property
Expand Down Expand Up @@ -1335,3 +1312,33 @@ def _hashable_content(self):
def _sorted_args(self):
from sympy.utilities import default_sort_key
return sorted(self.args, key=default_sort_key)

def imageset(*args):
""" Image of set under transformation ``f``
.. math::
{ f(x) | x \in self }
Examples
========
>>> from sympy import Interval, Symbol, imageset
>>> x = Symbol('x')
>>> imageset(x, 2*x, Interval(0, 2))
[0, 4]
>>> imageset(lambda x: 2*x, Interval(0, 2))
[0, 4]
See Also:
ImageSet
"""
if len(args) == 3:
from sympy import Lambda
f = Lambda(*args[:2])
else:
f = args[0]
set = args[-1]

return set._eval_imageset(f)
7 changes: 6 additions & 1 deletion sympy/core/tests/test_args.py
Expand Up @@ -467,13 +467,18 @@ def test_sympy__sets__fancysets__Reals():
from sympy.sets.fancysets import Reals
assert _test_args(Reals())


def test_sympy__sets__fancysets__TransformationSet():
from sympy.sets.fancysets import TransformationSet
from sympy import S, Lambda, Symbol
x = Symbol('x')
assert _test_args(TransformationSet(Lambda(x, x**2), S.Naturals))

def test_sympy__sets__fancysets__ImageSet():
from sympy.sets.fancysets import ImageSet
from sympy import S, Lambda, Symbol
x = Symbol('x')
assert _test_args(ImageSet(Lambda(x, x**2), S.Naturals))


def test_sympy__sets__fancysets__Range():
from sympy.sets.fancysets import Range
Expand Down
38 changes: 20 additions & 18 deletions sympy/core/tests/test_sets.py
@@ -1,7 +1,7 @@
from sympy import (
Symbol, Set, Union, Interval, oo, S, sympify, nan,
GreaterThan, LessThan, Max, Min, And, Or, Eq, Ge, Le, Gt, Lt, Float,
FiniteSet, Intersection
FiniteSet, Intersection, imageset
)
from sympy.mpmath import mpi

Expand Down Expand Up @@ -502,32 +502,34 @@ def test_Interval_free_symbols():
x = Symbol('x', real=True)
assert set(Interval(0, x).free_symbols) == set((x,))

def test_transform_interval():
def test_image_interval():
x = Symbol('x', real=True)
assert Interval(-2, 1).transform(x, 2*x) == Interval(-4, 2)
assert Interval(-2, 1, True, False).transform(x, 2*x) == \
assert imageset(x, 2*x, Interval(-2, 1)) == Interval(-4, 2)
assert imageset(x, 2*x, Interval(-2, 1, True, False)) == \
Interval(-4, 2, True, False)
assert Interval(-2, 1, True, False).transform(x, x**2) == \
Interval(1, 4, False, True)
assert Interval(-2, 1).transform(x, x**2) == Interval(1, 4)
assert Interval(-2, 1, True, False).transform(x, x**2) == \
Interval(1, 4, False, True)

def test_transform_FiniteSet():
assert imageset(x, x**2, Interval(-2, 1, True, False)) == \
Interval(0, 4, False, True)
assert imageset(x, x**2, Interval(-2, 1)) == Interval(0, 4)
assert imageset(x, x**2, Interval(-2, 1, True, False)) == \
Interval(0, 4, False, True)
assert imageset(x, x**2, Interval(-2, 1, True, True)) == \
Interval(0, 4, False, True)

def test_image_FiniteSet():
x = Symbol('x', real=True)
assert FiniteSet(1, 2, 3).transform(x, 2*x) == FiniteSet(2, 4, 6)
assert imageset(x, 2*x, FiniteSet(1, 2, 3)) == FiniteSet(2, 4, 6)

def test_transform_Union():
def test_image_Union():
x = Symbol('x', real=True)
assert (Interval(-2, 0) + FiniteSet(1, 2, 3)).transform(x, x**2) == \
assert imageset(x, x**2, Interval(-2, 0) + FiniteSet(1, 2, 3)) == \
(Interval(0, 4) + FiniteSet(9))

def test_transform_Intersection():
def test_image_Intersection():
x = Symbol('x', real=True)
y = Symbol('y', real=True)
assert Interval(-2, 0).intersect(Interval(x, y)).transform(x, x**2) == \
assert imageset(x, x**2, Interval(-2, 0).intersect(Interval(x, y))) == \
Interval(0, 4).intersect(Interval(Min(x**2, y**2), Max(x**2, y**2)))

def test_transform_EmptySet():
def test_image_EmptySet():
x = Symbol('x', real=True)
assert S.EmptySet.transform(x, 2*x) == S.EmptySet
assert imageset(x, 2*x, S.EmptySet) == S.EmptySet
2 changes: 1 addition & 1 deletion sympy/printing/latex.py
Expand Up @@ -1362,7 +1362,7 @@ def _print_Integers(self, i):
def _print_Reals(self, i):
return r"\mathbb{R}"

def _print_TransformationSet(self, s):
def _print_ImageSet(self, s):
return r"\left\{%s\; |\; %s \in %s\right\}" % (
self._print(s.lamda.expr),
', '.join([self._print(var) for var in s.lamda.variables]),
Expand Down
2 changes: 1 addition & 1 deletion sympy/printing/pretty/pretty.py
Expand Up @@ -1373,7 +1373,7 @@ def _print_Union(self, u):
return self._print_seq(u.args, None, None, union_delimiter,
parenthesize=lambda set: set.is_ProductSet or set.is_Intersection)

def _print_TransformationSet(self, ts):
def _print_ImageSet(self, ts):
if self._use_unicode:
inn = u("\u220a")
else:
Expand Down
6 changes: 3 additions & 3 deletions sympy/printing/tests/test_latex.py
Expand Up @@ -6,7 +6,7 @@
Lambda, LaplaceTransform, Limit, Matrix, Max, MellinTransform, Min,
Order, Piecewise, Poly, ring, field, ZZ, Product, Range, Rational,
RisingFactorial, RootOf, RootSum, S, Shi, Si, SineTransform, Subs,
Sum, Symbol, TransformationSet, Tuple, Union, Ynm, Znm, arg, asin,
Sum, Symbol, ImageSet, Tuple, Union, Ynm, Znm, arg, asin,
assoc_laguerre, assoc_legendre, binomial, catalan, ceiling,
chebyshevt, chebyshevu, conjugate, cot, coth, diff, dirichlet_eta,
exp, expint, factorial, factorial2, floor, gamma, gegenbauer, hermite,
Expand Down Expand Up @@ -473,9 +473,9 @@ def test_latex_Naturals():
assert latex(S.Integers) == r"\mathbb{Z}"


def test_latex_TransformationSet():
def test_latex_ImageSet():
x = Symbol('x')
assert latex(TransformationSet(Lambda(x, x**2), S.Naturals)) == \
assert latex(ImageSet(Lambda(x, x**2), S.Naturals)) == \
r"\left\{x^{2}\; |\; x \in \mathbb{N}\right\}"


Expand Down
2 changes: 1 addition & 1 deletion sympy/sets/__init__.py
@@ -1 +1 @@
from .fancysets import TransformationSet, Range
from .fancysets import TransformationSet, ImageSet, Range
18 changes: 13 additions & 5 deletions sympy/sets/fancysets.py
Expand Up @@ -7,6 +7,7 @@
from sympy.core.compatibility import iterable, as_int, with_metaclass
from sympy.core.sets import Set, Interval, FiniteSet, Intersection
from sympy.core.singleton import Singleton, S
from sympy.core.decorators import deprecated
from sympy.solvers import solve

oo = S.Infinity
Expand Down Expand Up @@ -128,17 +129,17 @@ def __new__(cls):
return Interval.__new__(cls, -oo, oo)


class TransformationSet(Set):
class ImageSet(Set):
"""
A set that is a transformation of another through some algebraic expression
Image of a set under a mathematical function
Examples
--------
>>> from sympy import Symbol, S, TransformationSet, FiniteSet, Lambda
>>> from sympy import Symbol, S, ImageSet, FiniteSet, Lambda
>>> x = Symbol('x')
>>> N = S.Naturals
>>> squares = TransformationSet(Lambda(x, x**2), N) # {x**2 for x in N}
>>> squares = ImageSet(Lambda(x, x**2), N) # {x**2 for x in N}
>>> 4 in squares
True
>>> 5 in squares
Expand Down Expand Up @@ -195,6 +196,13 @@ def _contains(self, other):
def is_iterable(self):
return self.base_set.is_iterable

class TransformationSet(ImageSet):
@deprecated(useinstead="ImageSet",
deprecated_since_version="0.7.4",
issue=3958,
feature="TransformationSet")
def __init__(self, *args):
pass

class Range(Set):
"""
Expand Down Expand Up @@ -225,7 +233,7 @@ def __new__(cls, *args):
start, stop, step = [S(as_int(w)) for w in (start, stop, step)]
except ValueError:
raise ValueError("Inputs to Range must be Integer Valued\n" +
"Use TransformationSets of Ranges for other cases")
"Use ImageSets of Ranges for other cases")
n = ceiling((stop - start)/step)
if n <= 0:
return S.EmptySet
Expand Down
22 changes: 11 additions & 11 deletions sympy/sets/tests/test_fancysets.py
@@ -1,5 +1,5 @@
from sympy.sets.fancysets import TransformationSet, Range
from sympy.core.sets import FiniteSet, Interval
from sympy.sets.fancysets import ImageSet, Range
from sympy.core.sets import FiniteSet, Interval, imageset
from sympy import (S, Symbol, Lambda, symbols, cos, sin, pi, oo, Basic,
Rational, sqrt)
from sympy.utilities.pytest import XFAIL
Expand Down Expand Up @@ -46,8 +46,8 @@ def test_integers():
assert Z.sup == oo


def test_TransformationSet():
squares = TransformationSet(Lambda(x, x**2), S.Naturals)
def test_ImageSet():
squares = ImageSet(Lambda(x, x**2), S.Naturals)
assert 4 in squares
assert 5 not in squares
assert FiniteSet(range(10)).intersect(squares) == FiniteSet(1, 4, 9)
Expand All @@ -58,15 +58,15 @@ def test_TransformationSet():
a, b, c, d = next(si), next(si), next(si), next(si)
assert (a, b, c, d) == (1, 4, 9, 16)

harmonics = TransformationSet(Lambda(x, 1/x), S.Naturals)
harmonics = ImageSet(Lambda(x, 1/x), S.Naturals)
assert Rational(1, 5) in harmonics
assert .25 in harmonics
assert .3 not in harmonics

assert harmonics.is_iterable

def test_transform_is_TransformationSet():
assert isinstance(Range(5).transform(x, sqrt(sin(x))), TransformationSet)
def test_image_is_ImageSet():
assert isinstance(imageset(x, sqrt(sin(x)), Range(5)), ImageSet)


@XFAIL
Expand All @@ -76,7 +76,7 @@ def test_halfcircle():
# I believe the code within fancysets is correct
r, th = symbols('r, theta', real=True)
L = Lambda((r, th), (r*cos(th), r*sin(th)))
halfcircle = TransformationSet(L, Interval(0, 1)*Interval(0, pi))
halfcircle = ImageSet(L, Interval(0, 1)*Interval(0, pi))

assert (1, 0) in halfcircle
assert (0, -1) not in halfcircle
Expand All @@ -85,9 +85,9 @@ def test_halfcircle():
assert not halfcircle.is_iterable


def test_transformation_iterator_not_injetive():
def test_ImageSet_iterator_not_injetive():
L = Lambda(x, x - x % 2) # produces 0, 2, 2, 4, 4, 6, 6, ...
evens = TransformationSet(L, S.Naturals)
evens = ImageSet(L, S.Naturals)
i = iter(evens)
# No repeats here
assert (next(i), next(i), next(i), next(i)) == (0, 2, 4, 6)
Expand Down Expand Up @@ -138,7 +138,7 @@ def test_range_interval_intersection():


def test_fun():
assert (FiniteSet(TransformationSet(Lambda(x, sin(pi*x/4)),
assert (FiniteSet(ImageSet(Lambda(x, sin(pi*x/4)),
Range(-10, 11))) == FiniteSet(-1, -sqrt(2)/2, 0, sqrt(2)/2, 1))


Expand Down

0 comments on commit 196fdb3

Please sign in to comment.