Paddy3118 wrote about partitioning elements in the same way a Venn diagram does. So, if we have sets A, B and C, the partitions are
These partitions can be organised in a table according to whether each of A, B and C is included or excluded:
A | B | C | partition |
---|---|---|---|
1 | 0 | 0 | A-(B∪C) |
0 | 1 | 0 | B-(A∪C) |
1 | 1 | 0 | (A∩B)-C |
0 | 0 | 1 | C-(A∪B) |
1 | 0 | 1 | (A∩C)-B |
0 | 1 | 1 | (B∩C)-A |
1 | 1 | 1 | A∩B∩C |
and the question is how to write a function that will return this sequence of partitions. Paddy3118 writes it like this:
def venndiv(*sets): bins = tuple(set() for n in range(2**len(sets))) for i, si in enumerate(sets): # Over every individual item of each set for item in si: binindex = 0 for j, sj in enumerate(sets): # Test for membership of each set if item in sj: binindex += 2**j # Binary count binning bins[binindex].add(item) return bins[1:] # bins[0] - an item in no set is impossible.
which is perfectly good: the explicit manipulation of index numbers is a little inelegant, perhaps. This post describes a different, pleasingly simple, way to express the venndiv
function.
The first thing to notice is that there is a systematic way to build up the partitions by starting with A∪B∪C and taking intersections and differences with A, B and C. Where there is a 1 in the table, take an intersection with that set, and where there is a 0 subtract that set. You can do these steps in any order. Here is the table again, with systematic expressions included:
A | B | C | partition | systematic |
---|---|---|---|---|
0 | 0 | 0 | ∅ | (((A∪B∪C) – C) – B) – A |
1 | 0 | 0 | A-(B∪C) | (((A∪B∪C) – C) – B) ∩ A |
0 | 1 | 0 | B-(A∪C) | (((A∪B∪C) – C) ∩ B) – A |
1 | 1 | 0 | (A∩B)-C | (((A∪B∪C) – C) ∩ B) ∩ A |
0 | 0 | 1 | C-(A∪B) | (((A∪B∪C) ∩ C) – B) – A |
1 | 0 | 1 | (A∩C)-B | (((A∪B∪C) ∩ C) – B) ∩ A |
0 | 1 | 1 | (B∩C)-A | (((A∪B∪C) ∩ C) ∩ B) – A |
1 | 1 | 1 | A∩B∩C | (((A∪B∪C) ∩ C) ∩ B) ∩ A |
So we can build the partitions starting with the C’s, then the B’s and then the A’s, like this:
The bottom row has all the partitions, in the right order. So our algorithm is: make a recursive call to fetch the second-to-last row, then split each bin into (bin – A) and (bin ∩ A). In Python:
def venndiv(*sets): def vd(x, *xs): bins = vd(*xs) if xs else (set.union(*sets),) return sum(tuple( (bin - x, bin & x) for bin in bins ), ()) return vd(*sets)[1:]
Or maybe it’s clearer as a loop, rather than a recursive function:
def venndiv(*sets): bins = ( set.union(*sets), ) for x in reversed(sets): bins = sum(tuple( (bin - x, bin & x) for bin in bins ), ()) return bins[1:]
Give a try and use Creately which have 3 set Veen diagrams,4 set Venn diagrams etc based on the requirement.
https://creately.com/lp/venn-diagram-maker/