Use a while
loop and .pop()
values to process from the set:
def CyclotomicCosets(q, n):
N = q ^ n - 1
ZN = set(range(N))
Cosets = []
while ZN:
i = ZN.pop()
tmp = {i * (q ^ j) % N for j in range(n)}
Cosets.append(list(tmp))
ZN -= tmp
return Cosets
Note that I replaced your inner for
loop with a set comprehension to make it a little faster and more compact. These were introduced in Python 2.7 and Python 3, in earlier versions of python you can use a generator expression instead:
tmp = set(i * (q ^ j) % N for j in range(n))
Your original mistake was to replace ZN
rather than update it:
ZN=ZN.difference(tmp)
This did not alter the original set you were using in the for
loop. Rather, you are creating a new set and point the ZN
reference to that.
However, you cannot modify a set
while iterating over it, so even an in-place difference would not have worked; you would have to use ZN -= tmp
or ZN.difference_update(tmp)
but that would lead to exceptions instead:
>>> ZN = set(range(3))
>>> for i in ZN:
... ZN -= set([2])
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
RuntimeError: Set changed size during iteration
The corrected code gives:
>>> CyclotomicCosets(3, 5)
[[0], [0, 1, 2, 3], [0, 1, 4, 5], [0, 4, 5, 6]]
Alternatively, loop over range(N)
instead, and keep a set of values you've already processed:
def CyclotomicCosets(q, n):
N = q ^ n - 1
Cosets = []
seen = set()
for i in range(N):
if i in seen: continue
tmp = {i * (q ^ j) % N for j in range(n)}
Cosets.append(list(tmp))
seen |= tmp
return Cosets