(args)
Simplify an intersection using known rules

        We first start with global rules like
        'if any empty sets return empty set' and 'distribute any unions'

        Then we iterate through all pairs and ask the constituent sets if they
        can simplify themselves with any other constituent
Simplify an intersection using known rules
Simplify an intersection using known rules
def reduce(args):
        """
        Simplify an intersection using known rules

        We first start with global rules like
        'if any empty sets return empty set' and 'distribute any unions'

        Then we iterate through all pairs and ask the constituent sets if they
        can simplify themselves with any other constituent
        """

        # ===== Global Rules =====
        # If any EmptySets return EmptySet
        if any(s.is_EmptySet for s in args):
            return S.EmptySet

        # If any FiniteSets see which elements of that finite set occur within
        # all other sets in the intersection
        for s in args:
            if s.is_FiniteSet:
                return s.__class__(x for x in s
                        if all(x in other for other in args))

        # If any of the sets are unions, return a Union of Intersections
        for s in args:
            if s.is_Union:
                other_sets = set(args) - set((s,))
                other = Intersection(other_sets)
                return Union(Intersection(arg, other) for arg in s.args)

        # At this stage we are guaranteed not to have any
        # EmptySets, FiniteSets, or Unions in the intersection

        # ===== Pair-wise Rules =====
        # Here we depend on rules built into the constituent sets
        args = set(args)
        new_args = True
        while(new_args):
            for s in args:
                new_args = False
                for t in args - set((s,)):
                    new_set = s._intersect(t)
                    # This returns None if s does not know how to intersect
                    # with t. Returns the newly intersected set otherwise
                    if new_set is not None:
                        new_args = (args - set((s, t))).union(set((new_set, )))
                        break
                if new_args:
                    args = new_args
                    break

        if len(args) == 1:
            return args.pop()
        else:
            return Intersection(args, evaluate=False)
def reduce ( args ) : # ===== Global Rules ===== # If any EmptySets return EmptySet if any ( s . is_EmptySet for s in args ) : return S . EmptySet # If any FiniteSets see which elements of that finite set occur within # all other sets in the intersection for s in args : if s . is_FiniteSet : return s . __class__ ( x for x in s if all ( x in other for other in args ) ) # If any of the sets are unions, return a Union of Intersections for s in args : if s . is_Union : other_sets = set ( args ) - set ( ( s , ) ) other = Intersection ( other_sets ) return Union ( Intersection ( arg , other ) for arg in s . args ) # At this stage we are guaranteed not to have any # EmptySets, FiniteSets, or Unions in the intersection # ===== Pair-wise Rules ===== # Here we depend on rules built into the constituent sets args = set ( args ) new_args = True while ( new_args ) : for s in args : new_args = False for t in args - set ( ( s , ) ) : new_set = s . _intersect ( t ) # This returns None if s does not know how to intersect # with t. Returns the newly intersected set otherwise if new_set is not None : new_args = ( args - set ( ( s , t ) ) ) . union ( set ( ( new_set , ) ) ) break if new_args : args = new_args break if len ( args ) == 1 : return args . pop ( ) else : return Intersection ( args , evaluate = False )