Skip to content

Commit 99f3a7f

Browse files
authored
Add files via upload
1 parent 35fe098 commit 99f3a7f

File tree

7 files changed

+9869
-317
lines changed

7 files changed

+9869
-317
lines changed

SetCalcPy/Set.py

+320
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,320 @@
1+
from .powerSet.powerSetCalc import calcPSetOf
2+
3+
4+
class Set:
5+
def __init__(self, *elements, universe=[]):
6+
"""
7+
Constructs a set object/converts lists to Sets
8+
:param elements: A list of elements in the set (repeating elements will be removed)
9+
:param universe: Universe of discourse (Set that should be used when calculating the complement)
10+
"""
11+
# Iteration variable for tracking iterations
12+
self.current = 0
13+
14+
# If the user mistakenly enters a single list to contain all elements then that list is converted into an
15+
# elements list
16+
if len(elements) == 1 and (type(elements[0]) == list or type(elements[0]) == tuple):
17+
elements = elements[0]
18+
19+
if type(universe) != list and not isinstance(universe, Set):
20+
print("Error! Universal sets must be specified as a list or Set!")
21+
raise TypeError
22+
elif isinstance(universe, Set):
23+
universe = universe.__list__()
24+
25+
self.elements = elements
26+
# elements = self.duplicateRemoval()
27+
elements = self.elements
28+
# universe of discourse
29+
self.universe = universe
30+
# Converts each iterable element in the set into a set object
31+
self.elements = tuple(self.toSet(elements))
32+
self.isProduct = False
33+
34+
def __len__(self):
35+
return len(self.elements)
36+
37+
def __iter__(self):
38+
# This is strictly used for the beginning of iteration
39+
return self
40+
41+
def __getitem__(self, index):
42+
# Used for brackets element accessing
43+
return self.elements[index]
44+
45+
def __next__(self):
46+
# Accesses the next element during iteration
47+
if self.current < len(self):
48+
c = self.current
49+
self.current += 1
50+
return self.elements[c]
51+
else:
52+
self.current = 0
53+
raise StopIteration
54+
55+
def __str__(self):
56+
return str(self.__list__()).replace("[", '{').replace(']','}')
57+
58+
def __list__(self):
59+
"""
60+
Converts the current instance of the set object into a standard list (along with each of its set elements)
61+
:return: A list of the elements the set
62+
"""
63+
64+
return_list = [0 for i in range(len(self.elements))]
65+
66+
for i in range(len(self.elements)):
67+
# Checks if the current element is iterable
68+
isIter = Set.isIterable(self.elements[i])
69+
70+
if isIter and type(self.elements[i]) != tuple and not isinstance(self.elements[i], Set):
71+
# List/dictionaries and other iterable objects are converted to lists using the standard constructor
72+
return_list[i] = list(self.elements[i])
73+
elif isIter and type(self.elements[i]) != tuple:
74+
# Converts set objects to lists
75+
return_list[i] = self.elements[i].__list__()
76+
else:
77+
# If an element is not mutable than it can be added to the return list as is
78+
return_list[i] = self.elements[i]
79+
return return_list
80+
81+
def __set__(self):
82+
return set(self.__list__())
83+
84+
def __eq__(self, other):
85+
return self.equal(other)
86+
87+
def __abs__(self):
88+
return len(self)
89+
90+
def __add__(self, other):
91+
return self.union(other)
92+
93+
def __sub__(self, other):
94+
return self.setMinus(other)
95+
96+
def __and__(self, other):
97+
return self.intersection(other)
98+
99+
def __mul__(self, other):
100+
return self.cartesianProduct(other)
101+
102+
@staticmethod
103+
def tryConvert(obj):
104+
"""
105+
Tries to convert the input object into a set object.
106+
:param obj: Object to be converted into a set
107+
:return: Unchanged obj if it is already a set object; otherwise, the object is attempted to be converted into a
108+
set if possible, if this can't be done, a value error is thrown
109+
"""
110+
if not isinstance(obj, Set):
111+
if Set.isIterable(obj) and type(obj) != tuple:
112+
obj = Set(obj)
113+
else:
114+
print("Please input a set object")
115+
raise TypeError
116+
return obj
117+
118+
def union(self, setb):
119+
"""
120+
Takes the union of two sets
121+
:param setb: Set object to be unionized with self
122+
:return: The set of all elements in either the calling set or setb
123+
"""
124+
setb = Set.tryConvert(setb)
125+
126+
result = []
127+
128+
for x in self:
129+
if x not in result:
130+
result.append(x)
131+
for x in setb:
132+
if x not in result:
133+
result.append(x)
134+
135+
return Set(result)
136+
137+
def setMinus(self, setb):
138+
"""
139+
Calculates the disjoint of self - setb
140+
:param setb: The return set should be disjoint with
141+
:return: A set containing all elements of the calling that are not in setb
142+
"""
143+
setb = Set.tryConvert(setb)
144+
result = []
145+
146+
for x in self:
147+
if x not in setb:
148+
result.append(x)
149+
return Set(result)
150+
151+
def complement(self):
152+
"""
153+
Calculates the complement of the calling set with its declared universe
154+
:return: All elements in the calling set, but not in the universal set
155+
"""
156+
return self.setMinus(Set(self.universe))
157+
158+
159+
@staticmethod
160+
def isIterable(obj):
161+
"""
162+
Checks if the object passed is ierable
163+
:param obj: Any object
164+
:return: True if the object is iterable and false if not
165+
"""
166+
try:
167+
getattr(obj, '__iter__')
168+
except AttributeError:
169+
return False
170+
return True
171+
172+
def intersection(self, setb):
173+
"""
174+
Calculates the intersection of two sets
175+
:param setb: set to be intersected with the calling set
176+
:return: All elements in the calling set and in setb
177+
"""
178+
setb = Set.tryConvert(setb)
179+
result = []
180+
181+
for x in self:
182+
if x in setb:
183+
result.append(x)
184+
185+
return Set(result)
186+
187+
def toSet(self, elements):
188+
'''
189+
A helper function used to convert a list of elements to a set; however the constructor should be called for this
190+
purpose not this method
191+
:param elements: A list of elements
192+
:return: A list of elements where all mutable elements have been converted to set objects
193+
'''
194+
195+
return_list = [0 for i in range(len(elements))]
196+
197+
for i in range(len(elements)):
198+
199+
# Checks to see if the current element is iterable
200+
isIter = Set.isIterable(elements[i])
201+
202+
if isIter and type(elements[i]) != tuple and not isinstance(elements[i], Set):
203+
# Converts the current element to a set object
204+
return_list[i] = Set(elements[i], universe=self.universe)
205+
else:
206+
# If the current object is a base type, then it does not need to be converted and is kept as is
207+
return_list[i] = elements[i]
208+
return return_list
209+
210+
def duplicateRemoval(self):
211+
'''
212+
Removes duplicate elements from the given set object (this is not intended to be called from outside the class
213+
:return: A list of non-repeating elements
214+
'''
215+
clean = []
216+
for element in self.elements:
217+
if element not in clean:
218+
clean.append(element)
219+
return clean
220+
221+
@staticmethod
222+
def inCheck(element, set):
223+
"""
224+
Checks if an element is in set (this was used for purposes of preventing infinite recursion using the
225+
__contains__ operator
226+
:param element: Any object to be inspected for membership of set
227+
:param set: The Set that element should be checked for membership against
228+
:return:
229+
"""
230+
for x in set:
231+
if x == element:
232+
return True
233+
return False
234+
235+
def powerSet(self):
236+
'''
237+
Calculates the powerset of a set
238+
:return: A set containing all subsets of the calling set
239+
'''
240+
241+
_self = self.__list__()
242+
# This relies on the compiled python extension imported
243+
powerSet = calcPSetOf(_self)
244+
return Set(powerSet)
245+
246+
def subsetof(self, setb):
247+
"""
248+
Checks if the current set is a subset of the input set
249+
:param setb: comparison set
250+
:return: Is this set a subset of setb
251+
"""
252+
setb = Set.tryConvert(setb)
253+
for y in self.elements:
254+
found = False
255+
for x in setb.elements:
256+
found = x == y
257+
if found:
258+
break
259+
if not found:
260+
return False
261+
return True
262+
263+
def equal(self, setb):
264+
"""
265+
Checks if the calling set is equal to setb (that it is a subset of setb and setb is a subset of it)
266+
:param setb: It's checked if the calling set is a subset of this set
267+
:return: True if the calling set is a subset of this set and false if not
268+
"""
269+
270+
if isinstance(setb, Set):
271+
if self.subsetof(setb) and setb.subsetof(self):
272+
return True
273+
return False
274+
275+
def setDisplayMode(self):
276+
"""
277+
Displays each element of the current set by hitting enter each time. This is a good way to display a very long
278+
set especially when copying
279+
:return: Nothing
280+
"""
281+
282+
for x in self:
283+
print(x, end="\n")
284+
input()
285+
286+
def cartesianProduct(self, *setb):
287+
"""
288+
Calculates the cartesian product of the calling set and the variable number of sets input.
289+
Input 2 sets for a normal product =
290+
Input 3 sets for a triple product
291+
etc.
292+
:param setb: Multiple sets separated by commas
293+
:return: A set of ordered pairs. When doing a normal product (A*B), each element is of the form (a,b),
294+
where a is in the calling set (A) and b is in B
295+
"""
296+
return Set(self.aCartesianProduct(setb))
297+
298+
def aCartesianProduct(self, *setb):
299+
"""
300+
The helper function to calculate various cartesian products
301+
:param setb: A list of sets to be used in the cartesian product
302+
:return: A list of ordered pairs representing the cartesian product of self with all the sets in setb
303+
"""
304+
305+
result = []
306+
if type(setb[0]) == list or type(setb[0]) == tuple and len(setb) == 1:
307+
setb = setb[0]
308+
309+
if len(setb) == 1:
310+
for x in self:
311+
for y in setb[0]:
312+
result.append((x,y))
313+
else:
314+
otherComb = setb[0].cartesianProduct(setb[1:])
315+
for i in range(len(self)):
316+
for y in otherComb:
317+
_y = list(y)
318+
_y.insert(0, self[i])
319+
result.append(tuple(_y))
320+
return result

0 commit comments

Comments
 (0)