Skip to content

Commit 01aea08

Browse files
committed
New post/page
1 parent fb2ca08 commit 01aea08

11 files changed

Lines changed: 1523 additions & 64 deletions

File tree

‎Makefile‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ help:
2626

2727
test:
2828
$(PELICAN) $(INPUTDIR) -o $(OUTPUTDIR) -s $(CONFFILE) $(PELICANOPTS)
29-
cd $(OUTPUTDIR); python -m SimpleHTTPServer
29+
cd $(OUTPUTDIR); python -m SimpleHTTPServer || python3 -m http.server
3030

3131
clean:
3232
[ ! -d $(OUTPUTDIR) ] || rm -rf $(OUTPUTDIR)

‎content/sets-sympy-python.rst‎

Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,280 @@
1+
Set operations with Python ``set`` compared to SymPy's FiniteSet
2+
================================================================
3+
:date: 2015-09-05 23:00
4+
:category: articles
5+
:slug: Sets-in-SymPy-and-built-in-Python-sets
6+
:summary: Sets in SymPy and built-in Python sets
7+
8+
9+
`Chapter 5` (`About <{filename}pages/about.rst>`__) of the book discusses working with mathematical sets in
10+
Python. While writing the chapter, I had a choice of whether to
11+
use Python 3's built-in `set
12+
<https://docs.python.org/3.3/library/stdtypes.html?highlight=union#set-types-set-frozenset>`__ data
13+
structure or use SymPy's (0.7.6 +) ``FiniteSet`` class. I decided to go ahead
14+
with the latter. My choice is briefly explained towards the end of
15+
this post, but hopefully it will be clear before that.
16+
17+
Next, I describe how you can use Python 3's built-in set data
18+
structure to create sets and perform set operations such as finding
19+
the union, intersection or cartesian product of sets. For comparison,
20+
I also show how you can do the same using SymPy's ``FiniteSet`` class.
21+
22+
23+
Creating a set
24+
~~~~~~~~~~~~~~
25+
26+
We can create a set consisting of the elements `{1, 2, 3}` in Python 3
27+
as follows:
28+
29+
.. code-block:: python
30+
31+
>>> s1 = {1, 2, 3}
32+
>>> s1
33+
{1, 2, 3}
34+
35+
To create a set when the elements are already in a list (for
36+
example), we would use the following syntax:
37+
38+
.. code-block:: python
39+
40+
>>> items = [1, 2, 3]
41+
>>> s2 = set(items)
42+
>>> s2
43+
{1, 2, 3}
44+
45+
The comparative operations using SymPy's ``FiniteSet`` class are:
46+
47+
.. code-block:: python
48+
49+
>>> from sympy import FiniteSet
50+
>>> s1 = FiniteSet(1, 2, 3)
51+
>>> s1
52+
{1, 2, 3}
53+
54+
>>> items = [1, 2, 3]
55+
>>> s2 = FiniteSet(*items)
56+
>>> s2
57+
{1, 2, 3}
58+
59+
To create an `empty set <https://en.wikipedia.org/wiki/Empty_set>`__,
60+
in Python 3 you would use create an empty ``set`` object:
61+
62+
.. code-block:: python
63+
64+
>>> e = set()
65+
>>> e
66+
set()
67+
68+
In SymPy, an empty set is represented by an ``EmptySet`` object. Thus,
69+
you can either create an empty set by directly creating an
70+
``EmptySet`` object or by creating a ``FiniteSet`` object without
71+
specifying any set members, like so:
72+
73+
.. code-block:: python
74+
75+
>>> from sympy import EmptySet
76+
>>> e = EmptySet()
77+
>>> e
78+
EmptySet()
79+
>>> e = FiniteSet()
80+
>>> e
81+
EmptySet()
82+
83+
84+
Cardinality and Membership
85+
~~~~~~~~~~~~~~~~~~~~~~~~~~
86+
87+
The ``len()`` function returns the number of set members for sets
88+
created using either of the above approaches.
89+
90+
Similarly, to check if an item ``x`` is present in a set, ``s``
91+
created using any of the above approaches, we can use the statement,
92+
``x in s``.
93+
94+
Union and intersection
95+
~~~~~~~~~~~~~~~~~~~~~~
96+
97+
The ``union()`` method can be used in both cases to find the union of
98+
two or more sets:
99+
100+
.. code-block:: python
101+
102+
>>> s1 = set([1, 2, 3])
103+
>>> s2 = set([2, 3, 4])
104+
>>> s3 = set([2, 3, 4, 5])
105+
>>> s1.union(s2).union(s3)
106+
{1, 2, 3, 4, 5}
107+
108+
Similary in the case of SymPy:
109+
110+
.. code-block:: python
111+
112+
>>> from sympy import FiniteSet
113+
>>> s1 = FiniteSet(1, 2, 3)
114+
>>> s2 = FiniteSet(2, 3, 4)
115+
>>> s3 = FiniteSet(2, 3, 4, 5)
116+
>>> s1.union(s2).union(s3)
117+
{1, 2, 3, 4, 5}
118+
119+
120+
The ``intersection()`` method can be used to find the intersection of
121+
two or more sets created using either of the above approaches. Continuing
122+
with the above three sets:
123+
124+
.. code-block:: python
125+
126+
>>> s1 = set([1, 2, 3])
127+
>>> s2 = set([2, 3, 4])
128+
>>> s3 = set([2, 3, 4, 5])
129+
>>> s1.intersection(s2).intersection(s3)
130+
{2, 3}
131+
132+
Similary, in SymPy:
133+
134+
.. code-block:: python
135+
136+
>>> s1.intersection(s2).intersection(s3)
137+
{2, 3}
138+
139+
140+
Cartesian product
141+
~~~~~~~~~~~~~~~~~
142+
143+
To find the cartesian product of sets created via the built-in ``set``
144+
data structure, we have to use the ``product()`` function in the
145+
`itertools
146+
<https://docs.python.org/3/library/itertools.html#itertools.product>`__
147+
module:
148+
149+
.. code-block:: python
150+
151+
>>> s1 = {1, 2, 3}
152+
>>> s2 = {4, 5, 6}
153+
>>> import itertools
154+
>>> itertools.product(s1, s2)
155+
<itertools.product object at 0x10418c990>
156+
157+
However considering that the `cartesian product` of two sets `should
158+
<http://mathinsight.org/definition/cartesian_product>`__ be another set,
159+
the ``product()`` function doesn't really then return the
160+
cartesian product itself, but (an iterator to) the elements in it. Hence, if we
161+
try to apply the result returned by the function directly to a method or
162+
function which is expected to be applicable to a set, it will fail. For
163+
example, ``itertools.product(s1, s2).union(s3)`` will result in an error, but
164+
``set(itertools.product(s1, s2)).union(s3)`` will work.
165+
166+
Using SymPy's ``FiniteSet``, you can use the ``*``
167+
(multiplication or product) operator to find the cartesian product
168+
and the result is a set itself. Thus, it is closer to what
169+
a cartesian product is mathematically. An example follows:
170+
171+
.. code-block:: python
172+
173+
>>> s1 = FiniteSet(1, 2, 3)
174+
>>> s2 = FiniteSet(4, 5, 6)
175+
>>> >>> s3 = FiniteSet(7, 8, 9)
176+
>>> (s1*s2).union(s3)
177+
{7, 8, 9} U {1, 2, 3} x {4, 5, 6}
178+
179+
**Cartesian product of a set with itself**
180+
181+
182+
To find the cartesian product of a set with itself, i.e. `s1*s1` for
183+
example, we pass in a keyword argument, ``repeat`` while calling the
184+
``itertools.product()`` function. The value of ``repeat`` is the
185+
`power` we want to raise the set to. Thus, ``itertools.product(s1,
186+
repeat=2)`` will calculate the cartesian product, `s1*s1`:
187+
188+
.. code-block:: python
189+
190+
>>> s1 = {1, 2, 3}
191+
>>> set(itertools.product(s1, repeat=2))
192+
{(1, 2), (3, 2), (1, 3), (3, 3), (3, 1), (2, 1), (2, 3), (2, 2), (1, 1)}
193+
194+
195+
In SymPy, the ``**`` operator can be used for finding the cartesian
196+
product of a set with itself:
197+
198+
.. code-block:: python
199+
200+
>>> s1 = FiniteSet(1, 2, 3)
201+
>>> s1**2
202+
{1, 2, 3} x {1, 2, 3}
203+
204+
205+
Subset/super set/proper subset checking
206+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
207+
208+
The ``issubset()`` and ``issuperset()`` methods are available for sets
209+
created via either approaches to check if a set is a subset and super
210+
set of another, respectively. Thus, ``s1.issubset(s2)`` will check if
211+
`s1` is a subset of `s2`.
212+
213+
**Checking for proper subset and superset**
214+
215+
To check if a set, `s1` is a `proper subset
216+
<http://mathworld.wolfram.com/ProperSubset.html>`__ of another set,
217+
`s2` when using built-in set, we can do the following:
218+
219+
.. code-block:: python
220+
221+
>>> s1 = {1, 2, 3}
222+
>>> s2 = {1, 2, 3, 4}
223+
>>> s1.issubset(s2) and s1 != s2
224+
True
225+
226+
We can do something similar for `proper superset
227+
<http://mathinsight.org/definition/proper_superset>`__.
228+
229+
In SymPy, we have ``is_proper_subset()`` and ``is_proper_superset()``
230+
methods which can be used to check if a set is a proper subset or
231+
superset of another, respectively. Thus, the above would be written as
232+
``s1.is_proper_subset(s2)``.
233+
234+
235+
Calculating the powerset
236+
~~~~~~~~~~~~~~~~~~~~~~~~
237+
238+
For sets created via built-in ``set`` data structure, there is no
239+
direct method available to create the `power set
240+
<https://www.mathsisfun.com/sets/power-set.html>`__. However, you can use the
241+
``powerset`` recipe described in the `itertools documentation
242+
<https://docs.python.org/3/library/itertools.html#recipes>`__.
243+
244+
On the other hand, in SymPy, there is a ``powerset()`` method
245+
available which returns the power set:
246+
247+
.. code-block:: python
248+
249+
>>> s1 = FiniteSet(1, 2, 3)
250+
>>> s1.powerset()
251+
{EmptySet(), {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}}
252+
253+
You can see that the ``powerset()`` method returns the power `set` and not the
254+
elements in it.
255+
256+
Choice of SymPy's ``FiniteSet`` over ``set``
257+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
258+
259+
From the above comparison, we can see that SymPy's ``FiniteSet``
260+
provides us with nice features such as being able to use the ``*``
261+
operator to find the cartesian product, ``**`` operator to calculate
262+
the cartesian product with itself and ``powerset()`` method for calculating the
263+
power set. These are not present when using the built-in ``set`` data
264+
structure. This was certainly a big driving factor in my choice,
265+
since SymPy was also being used in other chapters of the book.
266+
267+
However, a *key* reason for my choice was that I wanted to show how we
268+
can create sets which did not allow addition or removal once created -
269+
like mathematical sets. This need was fulfilled by SymPy's
270+
``FiniteSet`` since it used Python's ``frozenset`` data structure and
271+
not the ``set`` data sturcture.
272+
273+
The alternative to that would have
274+
been to use ``frozenset`` directly, but I just did not like the idea
275+
of it and I would have also missed out on the nice features
276+
``FiniteSet`` would provide (eventually). I should note here that once
277+
I had made the decision to go with ``FiniteSet``, I `contributed
278+
<https://github.com/amitsaha/sympy/commits?author=amitsaha>`__ patches
279+
to SymPy to make the methods of ``FiniteSet`` more compatible with Python's built in set
280+
and also implement minor features I discussed above.

‎output/archives.html‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ <h1><a href="./">Doing Math with Python </a></h1>
2828
<h1>Archives for Doing Math with Python</h1>
2929

3030
<dl>
31+
<dt>Sat 05 September 2015</dt>
32+
<dd><a href="./Sets-in-SymPy-and-built-in-Python-sets.html">Set operations with Python <tt class="docutils literal">set</tt> compared to SymPy's FiniteSet</a></dd>
3133
<dt>Wed 02 September 2015</dt>
3234
<dd><a href="./available-now.html">Doing Math with Python Available now!</a></dd>
3335
<dt>Sat 15 August 2015</dt>

0 commit comments

Comments
 (0)