Example #1
0
    def __init__(self, k: int = None):
        super().__init__(k)

        self._coloring_tip_gid = None  # The gid of the tip of the coloring chain
        self._coloring_chain = set()  # A set of the coloring chain
        self._k_chain = self.KChain(set(), float('inf'))  # The "main" k-chain

        # The various data structures to hold the coloring and ordering of the DAG
        self._blue_past_order = ChainMap()
        self._red_past_order = ChainMap()

        # The antipast is in essence the diffpast between the virtual block and its coloring parent,
        # who is simply the coloring tip of the entire DAG.
        self._blue_antipast_order = dict()
        self._red_antipast_order = dict()
        self._uncolored_unordered_antipast = LazySet()

        # Some unifying data structures to make coloring and ordering easier
        self._past_order = ChainMap(self._blue_past_order,
                                    self._red_past_order)
        self._antipast_order = ChainMap(self._blue_antipast_order,
                                        self._red_antipast_order)
        self._antipast = ChainMap(self._antipast_order,
                                  self._uncolored_unordered_antipast).keys()
        self._coloring_order = ChainMap(self._blue_past_order,
                                        self._blue_antipast_order)

        # The coloring is in essence the virtual block's coloring of the entire DAG
        self._coloring = self._coloring_order.keys()

        # The mapping is in essence the virtual block's ordering of the entire DAG
        self._mapping = ChainMap(self._past_order, self._antipast_order)
Example #2
0
    def _get_antipast(
            self, global_id: Block.GlobalID) -> AbstractSet[Block.GlobalID]:
        """
        :return: the antipast of the block with the given global id.
        """
        if global_id is None:
            return self._mapping.keys()

        if global_id == self._coloring_tip_gid:
            return self._antipast

        positive_sets, negative_sets = [], []
        for cur_chain_gid, is_main_coloring_chain, is_intersection in \
                self._local_tip_to_global_tip_generator(global_id):
            if not is_main_coloring_chain or is_intersection:
                append_to = negative_sets
            else:
                append_to = positive_sets
            append_to.append(self._G.node[cur_chain_gid][
                self._BLUE_DIFF_PAST_ORDER_KEY].keys())
            append_to.append(self._G.node[cur_chain_gid][
                self._RED_DIFF_PAST_ORDER_KEY].keys())

        antipast = LazySet(base_set=self._antipast,
                           positive_sets=positive_sets)
        for negative_set in negative_sets:
            antipast.lazy_difference_update(negative_set)

        # See the remark on antipast usage in _update_past_coloring_according_to
        # antipast.flatten()

        return antipast
Example #3
0
    def _get_past(self,
                  global_id: Block.GlobalID) -> AbstractSet[Block.GlobalID]:
        """
        :return: the past of the block with the given global id.
        """
        if global_id is None:
            return set()

        positive_chain, negative_chain = ChainMap(), ChainMap()
        for cur_chain_gid, is_main_coloring_chain, is_intersection in \
                self._local_tip_to_global_tip_generator(global_id):
            if is_intersection:
                continue
            if not is_main_coloring_chain:
                append_to = positive_chain.maps
            else:
                append_to = negative_chain.maps
            append_to.append(
                self._G.node[cur_chain_gid][self._BLUE_DIFF_PAST_ORDER_KEY])
            append_to.append(
                self._G.node[cur_chain_gid][self._RED_DIFF_PAST_ORDER_KEY])

        return LazySet(base_set=self._past_order.keys(),
                       negative_sets=[negative_chain.keys()],
                       positive_sets=[positive_chain.keys()])
Example #4
0
    def _get_coloring_chain(
        self, global_id: Block.GlobalID,
        length: float = float("inf")) -> LazySet:
        """
        :param global_id: the global id of the last block of the chain. Block must be in the DAG.
        :param length: optional, a cutoff for the number of blocks in the chain.
        :return: a LazySet of the global ids of blocks in the coloring chain of the given global id.
        The coloring chain is simply a chain ending with a block, such that for each block, the block before him
        in the chain is his "coloring parent".
        """
        infinite_length = length == float("inf")
        main_chain_intersection_gid = None
        base_set = set()
        positive_fork = set()
        negative_fork = set()
        count = 0

        for cur_gid in self._coloring_chain_generator(global_id):
            if count >= length + 1:
                break

            # Note that for complete coloring chains it is enough to find the first coloring ancestor block
            # that is in the main coloring chain - continuing past this point is pointless
            if cur_gid in self._coloring_chain and infinite_length:
                main_chain_intersection_gid = cur_gid
                break

            positive_fork.add(cur_gid)
            count += 1

        if infinite_length and (main_chain_intersection_gid is not None):
            base_set = self._coloring_chain
            for cur_gid in self._coloring_chain_generator(
                    self._coloring_tip_gid):
                if cur_gid == main_chain_intersection_gid:
                    break
                negative_fork.add(cur_gid)
                count += 1

        return LazySet(base_set, [negative_fork], [positive_fork])
Example #5
0
    def interleaving_test_iterator(base_set, negative_sets, positive_sets,
                                   more_negative_sets, more_positive_sets,
                                   intersection_sets,
                                   symmetric_difference_sets, update,
                                   numeric_operations):
        """
        Iterates on the test by alternatingly adding positive and negative sets
        to the LazySet and yielding the according LazySet and regular set.
        :param update: whether to use methods that update the LazySet in-place or not.
        :param numeric_operations: whether to use numeric-operation-style methods (e.g. |, -, etc') when creating
        the LazySet or not.
        """
        lazy_set = LazySet(base_set=base_set,
                           negative_sets=negative_sets,
                           positive_sets=positive_sets)
        regular_set = base_set.difference(*negative_sets).union(*positive_sets)
        yield lazy_set, regular_set  # "base" test
        yield lazy_set.copy(), regular_set
        yield lazy_set.copy_to_set(), regular_set
        yield lazy_set.copy().flatten(), regular_set
        yield lazy_set.copy().flatten(True), regular_set

        # re-run the test after each successive modification to the sets
        index = 0
        while index <= max(len(more_positive_sets), len(more_negative_sets)):
            if index < len(more_negative_sets):
                regular_set -= more_negative_sets[index]
                if update:
                    if numeric_operations:
                        lazy_set -= more_negative_sets[index]
                    else:
                        lazy_set.difference_update(more_negative_sets[index])
                else:
                    if numeric_operations:
                        lazy_set = lazy_set - more_negative_sets[index]
                    else:
                        lazy_set = lazy_set.difference(
                            more_negative_sets[index])
                yield lazy_set, regular_set
                yield lazy_set.copy(), regular_set
                yield lazy_set.copy_to_set(), regular_set
                yield lazy_set.copy().flatten(), regular_set
                yield lazy_set.copy().flatten(True), regular_set

            if index < len(more_positive_sets):
                regular_set |= more_positive_sets[index]
                if update:
                    if numeric_operations:
                        lazy_set |= more_positive_sets[index]
                    else:
                        lazy_set.update(more_positive_sets[index])
                else:
                    if numeric_operations:
                        lazy_set = lazy_set | more_positive_sets[index]
                    else:
                        lazy_set = lazy_set.union(more_positive_sets[index])
                yield lazy_set, regular_set
                yield lazy_set.copy(), regular_set
                yield lazy_set.copy_to_set(), regular_set
                yield lazy_set.copy().flatten(), regular_set
                yield lazy_set.copy().flatten(True), regular_set

            if index < len(intersection_sets):
                regular_set &= intersection_sets[index]
                if update:
                    if numeric_operations:
                        lazy_set &= intersection_sets[index]
                    else:
                        lazy_set.intersection_update(intersection_sets[index])
                else:
                    if numeric_operations:
                        lazy_set = lazy_set & intersection_sets[index]
                    else:
                        lazy_set = lazy_set.intersection(
                            intersection_sets[index])
                yield lazy_set, regular_set
                yield lazy_set.copy(), regular_set
                yield lazy_set.copy_to_set(), regular_set
                yield lazy_set.copy().flatten(), regular_set
                yield lazy_set.copy().flatten(True), regular_set

            if index < len(symmetric_difference_sets):
                regular_set ^= symmetric_difference_sets[index]
                if update:
                    if numeric_operations:
                        lazy_set ^= symmetric_difference_sets[index]
                    else:
                        lazy_set.symmetric_difference_update(
                            symmetric_difference_sets[index])
                else:
                    if numeric_operations:
                        lazy_set = lazy_set ^ symmetric_difference_sets[index]
                    else:
                        lazy_set = lazy_set.symmetric_difference(
                            symmetric_difference_sets[index])
                yield lazy_set, regular_set
                yield lazy_set.copy(), regular_set
                yield lazy_set.copy_to_set(), regular_set
                yield lazy_set.copy().flatten(), regular_set
                yield lazy_set.copy().flatten(True), regular_set

            index += 1

        # clear the sets and run the tests for the final time
        lazy_set.clear()
        regular_set.clear()
        yield lazy_set, regular_set
        yield lazy_set.copy(), regular_set
        yield lazy_set.copy_to_set(), regular_set
        yield lazy_set.copy().flatten(), regular_set
        yield lazy_set.copy().flatten(True), regular_set
Example #6
0
    def test_single_element_methods(self):
        """
        Tests the LazySet by adding and then removing single elements to it.
        """
        lazy_set = LazySet()
        regular_set = set()
        TestLazySet.basic_test(lazy_set, regular_set)

        elem1 = 1
        lazy_set.add(elem1)
        regular_set.add(elem1)
        TestLazySet.basic_test(lazy_set, regular_set)

        elem2 = '1'
        lazy_set.add(elem2)
        regular_set.add(elem2)
        TestLazySet.basic_test(lazy_set, regular_set)

        elem3 = None
        lazy_set.add(elem3)
        regular_set.add(elem3)
        TestLazySet.basic_test(lazy_set, regular_set)

        elem4 = float('inf')
        lazy_set.add(elem4)
        regular_set.add(elem4)
        TestLazySet.basic_test(lazy_set, regular_set)

        lazy_set.remove(elem2)
        regular_set.remove(elem2)
        TestLazySet.basic_test(lazy_set, regular_set)

        with pytest.raises(KeyError) as lazy_excinfo:
            lazy_set.remove(elem2)
        with pytest.raises(KeyError) as regular_excinfo:
            regular_set.remove(elem2)
        assert lazy_excinfo.type == regular_excinfo.type
        assert str(lazy_excinfo.value) == str(regular_excinfo.value)
        TestLazySet.basic_test(lazy_set, regular_set)

        lazy_set.discard(elem2)
        regular_set.discard(elem2)
        TestLazySet.basic_test(lazy_set, regular_set)

        lazy_set.discard(elem1)
        regular_set.discard(elem1)
        TestLazySet.basic_test(lazy_set, regular_set)

        lazy_set.add(elem2)
        regular_set.add(elem2)
        TestLazySet.basic_test(lazy_set, regular_set)

        lazy_set.discard(elem2)
        regular_set.discard(elem2)
        TestLazySet.basic_test(lazy_set, regular_set)

        pop_elem = lazy_set.pop()
        regular_set.remove(pop_elem)
        TestLazySet.basic_test(lazy_set, regular_set)

        pop_elem = lazy_set.pop()
        regular_set.remove(pop_elem)
        TestLazySet.basic_test(lazy_set, regular_set)

        with pytest.raises(KeyError) as lazy_excinfo:
            lazy_set.pop()
        with pytest.raises(KeyError) as regular_excinfo:
            regular_set.pop()
        assert lazy_excinfo.type == regular_excinfo.type