Example #1
0
class IntListRules(RuleBasedStateMachine):
    @initialize(ls=st.lists(INTEGERS))
    def starting_lists(self, ls):
        self.model = list(ls)
        self.target = IntList(ls)

    @invariant()
    def lists_are_equivalent(self):
        if hasattr(self, "model"):
            assert isinstance(self.model, list)
            assert isinstance(self.target, IntList)
            assert len(self.model) == len(self.target)
            assert list(self.target) == self.model

    @rule(n=INTEGERS)
    def append(self, n):
        self.model.append(n)
        self.target.append(n)

    @rule(i=valid_index() | valid_slice())
    def delete(self, i):
        del self.model[i]
        del self.target[i]

    @rule(sl=valid_slice())
    def slice(self, sl):
        self.model = self.model[sl]
        self.target = self.target[sl]

    @rule(i=valid_index())
    def agree_on_values(self, i):
        assert self.model[i] == self.target[i]
Example #2
0
def test_int_list_equality():
    ls = [1, 2, 3]
    x = IntList(ls)
    y = IntList(ls)

    assert ls != x
    assert x != ls
    assert not (x == ls)
    assert x == x
    assert x == y
Example #3
0
class ExampleRecord(object):
    """Records the series of ``start_example``, ``stop_example``, and
    ``draw_bits`` calls so that these may be stored in ``Examples`` and
    replayed when we need to know about the structure of individual
    ``Example`` objects.

    Note that there is significant similarity between this class and
    ``DataObserver``, and the plan is to eventually unify them, but
    they currently have slightly different functions and implementations.
    """
    def __init__(self):
        self.labels = [DRAW_BYTES_LABEL]
        self.__index_of_labels = {DRAW_BYTES_LABEL: 0}
        self.trail = IntList()

    def freeze(self):
        self.__index_of_labels = None

    def start_example(self, label):
        try:
            i = self.__index_of_labels[label]
        except KeyError:
            i = self.__index_of_labels.setdefault(label, len(self.labels))
            self.labels.append(label)
        self.trail.append(START_EXAMPLE_RECORD + i)

    def stop_example(self, discard):
        if discard:
            self.trail.append(STOP_EXAMPLE_DISCARD_RECORD)
        else:
            self.trail.append(STOP_EXAMPLE_NO_DISCARD_RECORD)

    def draw_bits(self, n, forced):
        self.trail.append(DRAW_BITS_RECORD)
class ExampleRecord(object):
    """Records the series of ``start_example``, ``stop_example``, and
    ``draw_bits`` calls so that these may be stored in ``Examples`` and
    replayed when we need to know about the structure of individual
    ``Example`` objects.

    Note that there is significant similarity between this class and
    ``DataObserver``, and the plan is to eventually unify them, but
    they currently have slightly different functions and implementations.
    """

    def __init__(self):
        self.labels = [DRAW_BYTES_LABEL]
        self.__index_of_labels = {DRAW_BYTES_LABEL: 0}
        self.trail = IntList()

    def freeze(self):
        self.__index_of_labels = None

    def start_example(self, label):
        try:
            i = self.__index_of_labels[label]
        except KeyError:
            i = self.__index_of_labels.setdefault(label, len(self.labels))
            self.labels.append(label)
        self.trail.append(START_EXAMPLE_RECORD + i)

    def stop_example(self, discard):
        if discard:
            self.trail.append(STOP_EXAMPLE_DISCARD_RECORD)
        else:
            self.trail.append(STOP_EXAMPLE_NO_DISCARD_RECORD)

    def draw_bits(self, n, forced):
        self.trail.append(DRAW_BITS_RECORD)
Example #5
0
 def children(self):
     if self.__children is None:
         self.__children = [IntList() for _ in hrange(len(self))]
         for i, p in enumerate(self.parentage):
             if i > 0:
                 self.__children[p].append(i)
         # Replace empty children lists with a tuple to reduce
         # memory usage.
         for i, c in enumerate(self.__children):
             if not c:
                 self.__children[i] = ()
     return self.__children
Example #6
0
 def begin(self):
     self.result = IntList.of_length(len(self.examples))
Example #7
0
 def starting_lists(self, ls):
     self.model = list(ls)
     self.target = IntList(ls)
Example #8
0
 def begin(self):
     self.starts = IntList.of_length(len(self.examples))
     self.ends = IntList.of_length(len(self.examples))
Example #9
0
 def begin(self):
     self.nontrivial = IntList.of_length(len(self.examples))
     self.result = set()
Example #10
0
 def __init__(self):
     self.labels = [DRAW_BYTES_LABEL]
     self.__index_of_labels = {DRAW_BYTES_LABEL: 0}
     self.trail = IntList()
Example #11
0
 def __init__(self):
     self.labels = [DRAW_BYTES_LABEL]
     self.__index_of_labels = {DRAW_BYTES_LABEL: 0}
     self.trail = IntList()
Example #12
0
def test_int_list_of_length():
    assert list(IntList.of_length(10)) == [0] * 10
Example #13
0
 def begin(self):
     """Called at the beginning of the run to initialise any
     relevant state."""
     self.result = IntList.of_length(len(self.examples))
Example #14
0
class Blocks(object):
    """A lazily calculated list of blocks for a particular ``ConjectureResult``
    or ``ConjectureData`` object.

    Pretends to be a list containing ``Block`` objects but actually only
    contains their endpoints right up until the point where you want to
    access the actual block, at which point it is constructed.

    This is designed to be as space efficient as possible, so will at
    various points silently transform its representation into one
    that is better suited for the current access pattern.

    In addition, it has a number of convenience methods for accessing
    properties of the block object at index ``i`` that should generally
    be preferred to using the Block objects directly, as it will not
    have to allocate the actual object."""

    __slots__ = ("endpoints", "owner", "__blocks", "__count", "__sparse")

    def __init__(self, owner):
        self.owner = owner
        self.endpoints = IntList()
        self.__blocks = {}
        self.__count = 0
        self.__sparse = True

    def add_endpoint(self, n):
        """Add n to the list of endpoints."""
        assert isinstance(self.owner, ConjectureData)
        self.endpoints.append(n)

    def transfer_ownership(self, new_owner):
        """Used to move ``Blocks`` over to a ``ConjectureResult`` object
        when that is read to be used and we no longer want to keep the
        whole ``ConjectureData`` around."""
        assert isinstance(new_owner, ConjectureResult)
        self.owner = new_owner
        self.__check_completion()

    def start(self, i):
        """Equivalent to self[i].start."""
        i = self._check_index(i)

        if i == 0:
            return 0
        else:
            return self.end(i - 1)

    def end(self, i):
        """Equivalent to self[i].end."""
        return self.endpoints[i]

    def bounds(self, i):
        """Equivalent to self[i].bounds."""
        return (self.start(i), self.end(i))

    def all_bounds(self):
        """Equivalent to [(b.start, b.end) for b in self]."""
        prev = 0
        for e in self.endpoints:
            yield (prev, e)
            prev = e

    @property
    def last_block_length(self):
        return self.end(-1) - self.start(-1)

    def __len__(self):
        return len(self.endpoints)

    def __known_block(self, i):
        try:
            return self.__blocks[i]
        except (KeyError, IndexError):
            return None

    def trivial(self, i):
        """Equivalent to self.blocks[i].trivial."""
        if self.owner is not None:
            return self.start(i) in self.owner.forced_indices or not any(
                self.owner.buffer[self.start(i):self.end(i)])
        else:
            return self[i].trivial

    def _check_index(self, i):
        n = len(self)
        if i < -n or i >= n:
            raise IndexError("Index %d out of range [-%d, %d)" % (i, n, n))
        if i < 0:
            i += n
        return i

    def __getitem__(self, i):
        i = self._check_index(i)
        assert i >= 0
        result = self.__known_block(i)
        if result is not None:
            return result

        # We store the blocks as a sparse dict mapping indices to the
        # actual result, but this isn't the best representation once we
        # stop being sparse and want to use most of the blocks. Switch
        # over to a list at that point.
        if self.__sparse and len(self.__blocks) * 2 >= len(self):
            new_blocks = [None] * len(self)
            for k, v in self.__blocks.items():
                new_blocks[k] = v
            self.__sparse = False
            self.__blocks = new_blocks
            assert self.__blocks[i] is None

        start = self.start(i)
        end = self.end(i)

        # We keep track of the number of blocks that have actually been
        # instantiated so that when every block that could be instantiated
        # has been we know that the list is complete and can throw away
        # some data that we no longer need.
        self.__count += 1

        # Integrity check: We can't have allocated more blocks than we have
        # positions for blocks.
        assert self.__count <= len(self)
        result = Block(
            start=start,
            end=end,
            index=i,
            forced=start in self.owner.forced_indices,
            all_zero=not any(self.owner.buffer[start:end]),
        )
        try:
            self.__blocks[i] = result
        except IndexError:
            assert isinstance(self.__blocks, list)
            assert len(self.__blocks) < len(self)
            self.__blocks.extend([None] * (len(self) - len(self.__blocks)))
            self.__blocks[i] = result

        self.__check_completion()

        return result

    def __check_completion(self):
        """The list of blocks is complete if we have created every ``Block``
        object that we currently good and know that no more will be created.

        If this happens then we don't need to keep the reference to the
        owner around, and delete it so that there is no circular reference.
        The main benefit of this is that the gc doesn't need to run to collect
        this because normal reference counting is enough.
        """
        if self.__count == len(self) and isinstance(self.owner,
                                                    ConjectureResult):
            self.owner = None

    def __iter__(self):
        for i in hrange(len(self)):
            yield self[i]

    def __repr__(self):
        parts = []
        for i in hrange(len(self)):
            b = self.__known_block(i)
            if b is None:
                parts.append("...")
            else:
                parts.append(repr(b))
        return "Block([%s])" % (", ".join(parts), )
Example #15
0
def test_int_list_cannot_contain_negative():
    with pytest.raises(ValueError):
        IntList([-1])
Example #16
0
 def begin(self):
     self.starts = IntList.of_length(len(self.examples))
     self.ends = IntList.of_length(len(self.examples))
Example #17
0
 def __init__(self, owner):
     self.owner = owner
     self.endpoints = IntList()
     self.__blocks = {}
     self.__count = 0
     self.__sparse = True
Example #18
0
class Blocks(object):
    """A lazily calculated list of blocks for a particular ``ConjectureResult``
    or ``ConjectureData`` object.

    Pretends to be a list containing ``Block`` objects but actually only
    contains their endpoints right up until the point where you want to
    access the actual block, at which point it is constructed.

    This is designed to be as space efficient as possible, so will at
    various points silently transform its representation into one
    that is better suited for the current access pattern.

    In addition, it has a number of convenience methods for accessing
    properties of the block object at index ``i`` that should generally
    be preferred to using the Block objects directly, as it will not
    have to allocate the actual object."""

    __slots__ = ("endpoints", "owner", "__blocks", "__count", "__sparse")

    def __init__(self, owner):
        self.owner = owner
        self.endpoints = IntList()
        self.__blocks = {}
        self.__count = 0
        self.__sparse = True

    def add_endpoint(self, n):
        """Add n to the list of endpoints."""
        assert isinstance(self.owner, ConjectureData)
        self.endpoints.append(n)

    def transfer_ownership(self, new_owner):
        """Used to move ``Blocks`` over to a ``ConjectureResult`` object
        when that is read to be used and we no longer want to keep the
        whole ``ConjectureData`` around."""
        assert isinstance(new_owner, ConjectureResult)
        self.owner = new_owner
        self.__check_completion()

    def start(self, i):
        """Equivalent to self[i].start."""
        i = self._check_index(i)

        if i == 0:
            return 0
        else:
            return self.end(i - 1)

    def end(self, i):
        """Equivalent to self[i].end."""
        return self.endpoints[i]

    def bounds(self, i):
        """Equivalent to self[i].bounds."""
        return (self.start(i), self.end(i))

    def all_bounds(self):
        """Equivalent to [(b.start, b.end) for b in self]."""
        prev = 0
        for e in self.endpoints:
            yield (prev, e)
            prev = e

    @property
    def last_block_length(self):
        return self.end(-1) - self.start(-1)

    def __len__(self):
        return len(self.endpoints)

    def __known_block(self, i):
        try:
            return self.__blocks[i]
        except (KeyError, IndexError):
            return None

    def trivial(self, i):
        """Equivalent to self.blocks[i].trivial."""
        if self.owner is not None:
            return self.start(i) in self.owner.forced_indices or not any(
                self.owner.buffer[self.start(i) : self.end(i)]
            )
        else:
            return self[i].trivial

    def _check_index(self, i):
        n = len(self)
        if i < -n or i >= n:
            raise IndexError("Index %d out of range [-%d, %d)" % (i, n, n))
        if i < 0:
            i += n
        return i

    def __getitem__(self, i):
        i = self._check_index(i)
        assert i >= 0
        result = self.__known_block(i)
        if result is not None:
            return result

        # We store the blocks as a sparse dict mapping indices to the
        # actual result, but this isn't the best representation once we
        # stop being sparse and want to use most of the blocks. Switch
        # over to a list at that point.
        if self.__sparse and len(self.__blocks) * 2 >= len(self):
            new_blocks = [None] * len(self)
            for k, v in self.__blocks.items():
                new_blocks[k] = v
            self.__sparse = False
            self.__blocks = new_blocks
            assert self.__blocks[i] is None

        start = self.start(i)
        end = self.end(i)

        # We keep track of the number of blocks that have actually been
        # instantiated so that when every block that could be instantiated
        # has been we know that the list is complete and can throw away
        # some data that we no longer need.
        self.__count += 1

        # Integrity check: We can't have allocated more blocks than we have
        # positions for blocks.
        assert self.__count <= len(self)
        result = Block(
            start=start,
            end=end,
            index=i,
            forced=start in self.owner.forced_indices,
            all_zero=not any(self.owner.buffer[start:end]),
        )
        try:
            self.__blocks[i] = result
        except IndexError:
            assert isinstance(self.__blocks, list)
            assert len(self.__blocks) < len(self)
            self.__blocks.extend([None] * (len(self) - len(self.__blocks)))
            self.__blocks[i] = result

        self.__check_completion()

        return result

    def __check_completion(self):
        """The list of blocks is complete if we have created every ``Block``
        object that we currently good and know that no more will be created.

        If this happens then we don't need to keep the reference to the
        owner around, and delete it so that there is no circular reference.
        The main benefit of this is that the gc doesn't need to run to collect
        this because normal reference counting is enough.
        """
        if self.__count == len(self) and isinstance(self.owner, ConjectureResult):
            self.owner = None

    def __iter__(self):
        for i in hrange(len(self)):
            yield self[i]

    def __repr__(self):
        parts = []
        for i in hrange(len(self)):
            b = self.__known_block(i)
            if b is None:
                parts.append("...")
            else:
                parts.append(repr(b))
        return "Block([%s])" % (", ".join(parts),)
Example #19
0
 def begin(self):
     self.result = IntList.of_length(len(self.examples))
Example #20
0
 def begin(self):
     self.nontrivial = IntList.of_length(len(self.examples))
     self.result = set()
Example #21
0
 def __init__(self, owner):
     self.owner = owner
     self.endpoints = IntList()
     self.__blocks = {}
     self.__count = 0
     self.__sparse = True
Example #22
0
 def __init__(self):
     # We store canonical values as a sorted list of integers
     # with each value being treated as equivalent to the largest
     # integer in the list that is below it.
     self.__values = IntList([0])
Example #23
0
def test_int_list_can_contain_arbitrary_size():
    n = 2**65
    assert list(IntList([n])) == [n]
Example #24
0
 def __copy__(self):
     result = IntegerNormalizer()
     result.__values = IntList(self.__values)
     return result
Example #25
0
 def begin(self):
     """Called at the beginning of the run to initialise any
     relevant state."""
     self.result = IntList.of_length(len(self.examples))
def test_extend_by_too_large():
    x = IntList()
    ls = [1, 10 ** 6]
    x.extend(ls)
    assert list(x) == ls