Search code examples
pythonsetquantifiers

How do I impose a condition that must be satisfied by *any two* members of a set?


I want to use python to define one set in terms of another, as follows: For some set N that consists of sets, define C as the set such that an element n of N is in C just in case any two elements of n both satisfy some specific condition.

Here is the particular problem I need to solve. Consider the power set N of the set of ordered pairs of elements in x={1,2,3,4,5,6}, and the following subsets of N:

i = {{1,1},{2,2},{3,4},{4,3},{5,6},{6,5}}

j = {{3,3},{4,4},{1,2},{2,1},{5,6},{6,5}}

k = {{5,5},{6,6},{1,2},{2,1},{3,4},{4,3}}

Using python, I want to define a special class of subsets of N: the subsets of N such that any two of their members are both either in i, j, or k.

More explicitly, I want to define the set terms: C = {n in N| for all a, b in n, either a and b are both in i or a and b are both in j or a and b are both in k}.

I'm attaching what I tried to do in Python. But this doesn't give me the right result: the set C I'm defining here is not such that any two of its members are both either in i, j, or k.

Any leads would be much appreciated!

import itertools

def powerset(iterable):

    s = list(iterable)
    return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))

x = [1,2,3,4,5,6]


ordered_pairs = [[j,k] for j in x for k in x if k>=j]

powers = list(powerset(ordered_pairs))

i = [[1,1],[2,2],[3,4],[4,3],[5,6],[6,5]]
j = [[3,3],[4,4],[1,2],[2,1],[5,6],[6,5]]
k = [[5,5],[6,6],[1,2],[2,1],[3,4],[4,3]]

M = [i,j,k]

C = []

for n in powers:
    for a in n: 
        for b in n:
            for m in M:
                if a in m:
                    if b in m:
                        if a != b:
                            C.append(n)
                        if len(n) == 1:
                            C.append(n)


Solution

  • First of all, note that the ordered pairs you list are sets, not pairs. Use tuples, since they're hashable, and you'll be able to easily generate the power set using itertools. With that done, you have an easier time identifying the qualifying subsets.

    The code below implements that much of the process. You can accumulate the hits at the HIT line of code. Even better, you can collapse the loop into a nested comprehension using any to iterate over the three zone sets.

    test_list = [
        set(((1,1),(2,2))),                     # trivial hit on i
        set(),                                  # trivial miss
        set(((1, 1), (4, 4), (6, 6))),          # one element in each target set
        set(((3, 3), (6, 2), (4, 4), (2, 2))),  # two elements in j
    ]
    
    i = set(((1,1),(2,2),(3,4),(4,3),(5,6),(6,5)))
    j = set(((3,3),(4,4),(1,2),(2,1),(5,6),(6,5)))
    k = set(((5,5),(6,6),(1,2),(2,1),(3,4),(4,3)))
    
    zone = [i, j, k]
    
    for candidate in test_list:
        for target in zone:
            overlap = candidate.intersection(target)    
            if len(overlap) >= 2:
                print("HIT", candidate, target)
                break
        else:
            print("MISS", candidate)
    

    Output:

    HIT {(1, 1), (2, 2)} {(5, 6), (4, 3), (2, 2), (3, 4), (1, 1), (6, 5)}
    MISS set()
    MISS {(4, 4), (1, 1), (6, 6)}
    HIT {(6, 2), (3, 3), (4, 4), (2, 2)} {(1, 2), (3, 3), (5, 6), (4, 4), (2, 1), (6, 5)}