def do_draw(self, data):
        should_draw = cu.many(
            data,
            min_size=self.min_size,
            max_size=self.max_size,
            average_size=self.average_size,
        )
        seen_sets = tuple(set() for _ in self.keys)
        result = []

        remaining = LazySequenceCopy(self.element_strategy.elements)

        while should_draw.more():
            i = len(remaining) - 1
            j = cu.integer_range(data, 0, i)
            if j != i:
                remaining[i], remaining[j] = remaining[j], remaining[i]
            value = remaining.pop()

            if all(
                    key(value) not in seen
                    for (key, seen) in zip(self.keys, seen_sets)):
                for key, seen in zip(self.keys, seen_sets):
                    seen.add(key(value))
                result.append(value)
            else:
                should_draw.reject()
        assert self.max_size >= len(result) >= self.min_size
        return result
Exemple #2
0
    def do_draw(self, data):
        should_draw = cu.many(
            data,
            min_size=self.min_size,
            max_size=self.max_size,
            average_size=self.average_size,
        )
        seen_sets = tuple(set() for _ in self.keys)
        result = []

        remaining = LazySequenceCopy(self.element_strategy.elements)

        while remaining and should_draw.more():
            i = len(remaining) - 1
            j = cu.integer_range(data, 0, i)
            if j != i:
                remaining[i], remaining[j] = remaining[j], remaining[i]
            value = self.element_strategy._transform(remaining.pop())

            if value is not filter_not_satisfied and all(
                    key(value) not in seen
                    for key, seen in zip(self.keys, seen_sets)):
                for key, seen in zip(self.keys, seen_sets):
                    seen.add(key(value))
                if self.tuple_suffixes is not None:
                    value = (value, ) + data.draw(self.tuple_suffixes)
                result.append(value)
            else:
                should_draw.reject()
        assert self.max_size >= len(result) >= self.min_size
        return result
Exemple #3
0
def test_pop():
    x = LazySequenceCopy([2, 3])
    assert x.pop() == 3
    assert x.pop() == 2

    with pytest.raises(IndexError):
        x.pop()
Exemple #4
0
def test_pop_with_mask():
    y = [1, 2, 3]
    x = LazySequenceCopy(y)
    x[-1] = 5
    t = x.pop()
    assert t == 5
    assert list(x) == [1, 2]
    assert y == [1, 2, 3]
Exemple #5
0
def test_assignment():
    y = [1, 2, 3]
    x = LazySequenceCopy(y)
    x[-1] = 5
    assert list(x) == [1, 2, 5]
    x[-1] = 7
    assert list(x) == [1, 2, 7]
Exemple #6
0
def test_out_of_range():
    x = LazySequenceCopy([1, 2, 3])

    with pytest.raises(IndexError):
        x[3]

    with pytest.raises(IndexError):
        x[-4]
Exemple #7
0
def test_pop_without_mask():
    y = [1, 2, 3]
    x = LazySequenceCopy(y)
    x.pop()
    assert list(x) == [1, 2]
    assert y == [1, 2, 3]
Exemple #8
0
def test_can_assign_without_changing_underlying():
    underlying = [1, 2, 3]
    x = LazySequenceCopy(underlying)
    x[1] = 10
    assert x[1] == 10
    assert underlying[1] == 2
Exemple #9
0
def test_pass_through():
    x = LazySequenceCopy([1, 2, 3])
    assert x[0] == 1
    assert x[1] == 2
    assert x[2] == 3
Exemple #10
0
    def add(self, data):
        """Attempts to add ``data`` to the pareto front. Returns True if
        ``data`` is now in the front, including if data is already in the
        collection, and False otherwise"""
        data = data.as_result()
        if data.status < Status.VALID:
            return False

        if not self.front:
            self.front.add(data)
            return True

        if data in self.front:
            return True

        # We add data to the pareto front by adding it unconditionally and then
        # doing a certain amount of randomized "clear down" - testing a random
        # set of elements (currently 10) to see if they are dominated by
        # something else in the collection. If they are, we remove them.
        self.front.add(data)
        assert self.__pending is None
        try:
            self.__pending = data

            # We maintain a set of the current exact pareto front of the
            # values we've sampled so far. When we sample a new element we
            # either add it to this exact pareto front or remove it from the
            # collection entirely.
            front = LazySequenceCopy(self.front)

            # We track which values we are going to remove and remove them all
            # at the end so the shape of the front doesn't change while we're
            # using it.
            to_remove = []

            # We now iteratively sample elements from the approximate pareto
            # front to check whether they should be retained. When the set of
            # dominators gets too large we have sampled at least 10 elements
            # and it gets too expensive to continue, so we consider that enough
            # due diligence.
            i = self.front.index(data)

            # First we attempt to look for values that must be removed by the
            # addition of the data. These are necessarily to the right of it
            # in the list.

            failures = 0
            while i + 1 < len(front) and failures < 10:
                j = self.__random.randrange(i + 1, len(front))
                swap(front, j, len(front) - 1)
                candidate = front.pop()
                dom = dominance(data, candidate)
                assert dom != DominanceRelation.RIGHT_DOMINATES
                if dom == DominanceRelation.LEFT_DOMINATES:
                    to_remove.append(candidate)
                    failures = 0
                else:
                    failures += 1

            # Now we look at the points up to where we put data in to see if
            # it is dominated. While we're here we spend some time looking for
            # anything else that might be dominated too, compacting down parts
            # of the list.

            dominators = [data]

            while i >= 0 and len(dominators) < 10:
                swap(front, i, self.__random.randint(0, i))

                candidate = front[i]

                already_replaced = False
                j = 0
                while j < len(dominators):
                    v = dominators[j]

                    dom = dominance(candidate, v)
                    if dom == DominanceRelation.LEFT_DOMINATES:
                        if not already_replaced:
                            already_replaced = True
                            dominators[j] = candidate
                            j += 1
                        else:
                            dominators[j], dominators[-1] = (
                                dominators[-1],
                                dominators[j],
                            )
                            dominators.pop()
                        to_remove.append(v)
                    elif dom == DominanceRelation.RIGHT_DOMINATES:
                        to_remove.append(candidate)
                        break
                    elif dom == DominanceRelation.EQUAL:
                        break
                    else:
                        j += 1
                else:
                    dominators.append(candidate)
                i -= 1

            for v in to_remove:
                self.__remove(v)
            return data in self.front
        finally:
            self.__pending = None
 def selection_order(depth, n):
     pending = LazySequenceCopy(range(n))
     while pending:
         yield pop_random(random, pending)