Discrete helpers/set part

This class implements set partitions, which are essentially the same as equivalence classes.
The partitioned set (called domain) is usually that of non-negative integers.

from discretehelpers.set_part import SetPart


sp = SetPart()
assert sp == SetPart([])

sp.merge_pair(3, 5)
assert sp == SetPart([[3, 5]])

sp.merge_many([7, 8, 9])
assert sp == SetPart([[3, 5], [7, 8, 9]])
assert sp.blocks_with_singletons(10) == [[0], [1], [2], [3, 5], [4], [6], [7, 8, 9]]

sp.merge_pair(5, 7)
assert sp == SetPart([[3, 5, 7, 8, 9]])
assert sp.blocks_with_singletons(10) == [[0], [1], [2], [3, 5, 7, 8, 9], [4], [6]]

Cayley tables edit

 
Cayley table of the Symmetric group S3

SetPart can be used to model the Cayley table of a group.
It makes sense to use a set of simple IDs for the elements of the group. (Typically that should be integers or pairs of integers.)
Then the domain argument is the Cartesian square of the set of IDs.
The entries of the Cayley table are IDs added as labels to the blocks.
The method add_label_to_element will take care of creating the blocks.

Let id_to_perm be a bidict from IDs to permutations.

from itertools import product

from discretehelpers.set_part import SetPart
from discretehelpers.perm import Perm
from discretehelpers.a import rev_colex_perms


perms_raw = rev_colex_perms(3)
perms = [Perm(list(_)) for _ in perms_raw]
domain = list(product(range(6), repeat=2))  # all pairs (a, b) with a, b in 0...5
cayley = SetPart(blocks=[], domain=domain)
for index_a in range(6):
    perm_a = perms[index_a]
    for index_b in range(6):
        perm_b = perms[index_b]
        perm_ab = perm_a * perm_b
        index_ab = perms.index(perm_ab)
        cayley.add_label_to_element(element=(index_a, index_b), label=index_ab)

What are the products of permutations 3 and 5?

assert cayley.get_label_from_element((3, 5)) == 1
assert cayley.get_label_from_element((5, 3)) == 2

Which (other) products create the permutations 1 and 2?

assert cayley.get_block_from_label(1) == [(0, 1), (1, 0), (2, 3), (3, 5), (4, 2), (5, 4)]
assert cayley.get_block_from_label(2) == [(0, 2), (1, 4), (2, 0), (3, 1), (4, 5), (5, 3)]


join and meet edit

The join and meet methods can be used to combine two partitions into one.
The join   (least upper bound) is the finest partition coarser than both. The meet   (greatest lower bound) is the coarsest partition finer than both.
They use the method _combine, which uses the (rather expensive) metribute pairs.

meet edit

The default partition is the finest, and it can be made coarser. But one can not start with the coarsest, and make it finer. (Although theoretically there would be nothing wrong with that.)
This method is a way to make blocks smaller instead of bigger.