예제 #1
0
def st_valid_inds_of_same_length(draw, v1, v2):
    len1, len2 = len(v1), len(v2)
    ret = hyst.just(([], []))
    # TODO we should include integer arrays here by chaining `| hynp.integer_array_indices(shape=(LEN_X,))`
    val1 = hynp.basic_indices(shape=(len1,), allow_ellipsis=False)
    if len1 == len2:
        ret = ret | hyst.tuples(hyst.shared(val1, key="st_valid_inds_of_same_length"), hyst.shared(val1, key="st_valid_inds_of_same_length"))
    if len1 > 0 and len2 > 0:
        val2 = hynp.basic_indices(shape=(len2,), allow_ellipsis=False)
        ret = ret | hyst.tuples(val1, val2)
    return draw(ret)
예제 #2
0
def get_vector_index_axis(draw, max_shape: int = 10):
    N = draw(integers(min_value=2, max_value=max_shape))
    index = draw(
        npst.basic_indices(shape=(N, ),
                           min_dims=1,
                           max_dims=1,
                           allow_ellipsis=False))
    axis = draw(integers(min_value=0, max_value=1))
    return (N, *index, axis)
예제 #3
0
def test_basic_indices_can_generate_indices_not_covering_all_dims():
    # These "flat indices" are skippable in the underlying BasicIndexStrategy,
    # so we ensure we're definitely generating them for nps.basic_indices().
    find_any(
        nps.basic_indices(shape=(3, 3, 3)),
        lambda ix: (
            (not isinstance(ix, tuple) and ix != Ellipsis)
            or (isinstance(ix, tuple) and Ellipsis not in ix and len(ix) < 3)
        ),
    )
예제 #4
0
def array_and_basic_indices(
    draw,
    array_min_dims: int = 0,
    array_max_dims: int = 2,
    dtype: np.dtype = None,
):
    arr = draw(
        anyarray(min_dims=array_min_dims, max_dims=array_max_dims, dtype=dtype)
    )
    ind = draw(basic_indices(arr.shape))
    return arr, ind
예제 #5
0
def st_valid_inds_of_different_length(draw, v1, v2):
    len1, len2 = len(v1), len(v2)
    ret = nothing()
    # TODO we should include integer arrays here
    val = hynp.basic_indices(shape=(len1,), allow_ellipsis=False)  # | hynp.integer_array_indices(shape=(len1,))
    if len1 != len2:
        ret = ret | hyst.just((slice(None), slice(None))) \
              | hyst.tuples(hyst.shared(val, key="indfl"), hyst.shared(val, key="indfl"))
    if len1 > 0 and len2 > 0:
        ret = ret | hyst.tuples(val, val).filter(lambda x: len(x[0])!=len(x[1]))
    return draw(ret)
예제 #6
0
def get_chainable_arrays_shapes_and_indices(draw,
                                            base_min_dims: int = 1,
                                            base_max_dims: int = 2,
                                            max_chain: int = 8,
                                            chain_min_dims: int = 1):
    shape_strategy = get_chainable_array_shapes(base_min_dims=base_min_dims,
                                                base_max_dims=base_max_dims,
                                                max_chain=max_chain,
                                                chain_min_dims=chain_min_dims)
    shapes = draw(shape_strategy)
    shape = (shapes[0][0], shapes[-1][-1])
    indices = draw(npst.basic_indices(shape, allow_ellipsis=False, min_dims=2))

    return shapes, indices, shape
예제 #7
0
def test_basic_indices_generate_valid_indexers(
    shape, allow_newaxis, allow_ellipsis, data
):
    min_dims = data.draw(
        st.integers(0, 5 if allow_newaxis else len(shape)), label="min_dims"
    )
    max_dims = data.draw(
        st.none() | st.integers(min_dims, 32 if allow_newaxis else len(shape)),
        label="max_dims",
    )
    indexer = data.draw(
        nps.basic_indices(
            shape,
            min_dims=min_dims,
            max_dims=max_dims,
            allow_ellipsis=allow_ellipsis,
            allow_newaxis=allow_newaxis,
        ),
        label="indexer",
    )

    # Check that disallowed things are indeed absent
    if not allow_newaxis:
        if isinstance(indexer, tuple):
            assert 0 <= len(indexer) <= len(shape) + int(allow_ellipsis)
        else:
            assert 1 <= len(shape) + int(allow_ellipsis)
        assert np.newaxis not in shape
    if not allow_ellipsis:
        assert Ellipsis not in shape

    if 0 in shape:
        # If there's a zero in the shape, the array will have no elements.
        array = np.zeros(shape)
        assert array.size == 0
    elif np.prod(shape) <= 10**5:
        # If it's small enough to instantiate, do so with distinct elements.
        array = np.arange(np.prod(shape)).reshape(shape)
    else:
        # We can't cheat on this one, so just try another.
        assume(False)
    view = array[indexer]
    if not np.isscalar(view):
        assert min_dims <= view.ndim <= (32 if max_dims is None else max_dims)
        if view.size:
            assert np.shares_memory(view, array)
예제 #8
0
def get_boardcastable_arrays_shapes_and_indices(draw,
                                                base_min_dims: int = 2,
                                                base_max_dims: int = 3,
                                                broadcast_min_dims: int = 1,
                                                broadcast_max_dims: int = 5):
    shape_strategy = get_boardcastable_arrays_shapes(
        base_min_dims=base_min_dims,
        base_max_dims=base_max_dims,
        broadcast_min_dims=broadcast_min_dims,
        broadcast_max_dims=broadcast_max_dims)

    shapes = draw(shape_strategy)
    # What is final shape?
    ndim = max(len(shape) for shape in shapes)
    padded_shapes = np.array([[1] * (ndim - len(shape)) + list(shape)
                              for shape in shapes])
    shape = tuple(np.max(padded_shapes, axis=0).astype(int))
    # TODO: raise Issue with hypothesis. Numpy types aren't allowed. uncomment next line and it fails
    shape = tuple(int(s) for s in shape)
    indices = draw(npst.basic_indices(shape, allow_ellipsis=False, min_dims=2))
    return shapes, indices, shape
예제 #9
0
def test_basic_indices_can_generate_empty_tuple():
    find_any(nps.basic_indices(shape=(0, 0), allow_ellipsis=True),
             lambda ix: ix == ())


def test_basic_indices_can_generate_long_ellipsis():
    # Runs of slice(None) - such as [0,:,:,:,0] - can be replaced by e.g. [0,...,0]
    find_any(
        nps.basic_indices(shape=(1, 0, 0, 0, 1), allow_ellipsis=True),
        lambda ix: len(ix) == 3 and ix[1] == Ellipsis,
    )


@given(
    nps.basic_indices(shape=(0, 0, 0, 0,
                             0)).filter(lambda idx: Ellipsis in idx))
def test_basic_indices_replaces_whole_axis_slices_with_ellipsis(idx):
    # If ... is in the slice, it replaces all ,:, entries for this shape.
    assert slice(None) not in idx


@given(
    shape=nps.array_shapes(min_dims=0, max_side=4)
    | nps.array_shapes(min_dims=0, min_side=0, max_side=10),
    min_dims=st.integers(0, 5),
    allow_ellipsis=st.booleans(),
    allow_newaxis=st.booleans(),
    data=st.data(),
)
def test_basic_indices_generate_valid_indexers(shape, min_dims, allow_ellipsis,
                                               allow_newaxis, data):
예제 #10
0
def arbitrary_indices(draw, shape: Tuple[int]):
    """
    Hypothesis search strategy: Generate a valid index
    for an array of a given shape. The index can contain
    any type of valid object used for indexing, including
    integers, slices, Ellipsis's, newaxis's, boolean arrays,
    and integer arrays.

    Parameters
    ----------
    shape : Tuple[int]
        The shape of the array to be indexed into

    Notes
    -----
    `draw` is a parameter reserved by hypothesis, and should not be specified
    by the user.

    When given a shape with a 0-dimensional axis, only a basic index will be returned.

    Returns
    -------
    hypothesis.searchstrategy.SearchStrategy[Tuple[Union[int, slice, Ellipsis, NoneType, numpy.ndarray], ...]]
    """
    def group_continuous_integers(ls):
        """
        Given a list of integers, find and group continuous sequences

        Parameters
        ----------
        ls: List[int]

        Returns
        -------
        List[Tuple[int]]

        Examples
        --------
        >>> group_continuous_integers([1, 3, 4, 5, 7, 8])
        [(1,), (3, 4, 5), (7, 8)]
        """
        return [
            tuple(map(itemgetter(1), g))
            for k, g in groupby(enumerate(ls), lambda x: x[0] - x[1])
        ]

    if not shape or 0 in shape:
        return draw(hnp.basic_indices(shape=shape, allow_newaxis=True))

    shape_inds = list(range(len(shape)))
    index = []  # stores tuples of (axis, indexing object)

    # add integers, slices
    basic_inds = sorted(
        draw(st.lists(st.sampled_from(shape_inds), unique=True)))

    if len(basic_inds) > 0:
        basic_dims = tuple(shape[i] for i in basic_inds)

        # only draw ints and slices
        # will handle possible ellipsis and newaxis objects later
        # as these can make array indices difficult to handle
        basics = draw(hnp.basic_indices(shape=basic_dims,
                                        allow_ellipsis=False))
        if not isinstance(basics, tuple):
            basics = (basics, )

        index += [tup for tup in zip(basic_inds, basics)]

        # will not necessarily index all axes from basic_inds as
        # `basic_indices` can return indices with omitted trailing slices
        # so only remove dimensions directly indexed into
        for i in basic_inds[:len(basics)]:
            shape_inds.pop(shape_inds.index(i))

    if len(shape_inds) > 0:
        # add integer arrays to index
        int_arr_inds = sorted(
            draw(st.lists(st.sampled_from(shape_inds), unique=True)))

        if len(int_arr_inds) > 0:
            int_arr_dims = tuple(shape[i] for i in int_arr_inds)
            int_arrs = draw(hnp.integer_array_indices(shape=int_arr_dims))
            index += [tup for tup in zip(int_arr_inds, int_arrs)]

            for i in int_arr_inds:
                shape_inds.pop(shape_inds.index(i))

    if len(shape_inds) > 0:
        # add boolean arrays to index
        bool_inds = sorted(
            draw(st.lists(st.sampled_from(shape_inds), unique=True)))

        if len(bool_inds) > 0:
            # boolean arrays can be multi-dimensional, so by grouping all
            # adjacent axes to make a single boolean array, this can be tested for
            grouped_bool_inds = group_continuous_integers(bool_inds)
            bool_dims = [
                tuple(shape[i] for i in ind) for ind in grouped_bool_inds
            ]

            # if multiple boolean array indices, the number of trues must be such that
            # the output of ind.nonzero() for each index are broadcast compatible
            # this must also be the same as the trailing dim of each integer array, if any used
            if len(int_arr_inds):
                max_trues = max(i.shape[-1] for i in int_arrs)
            else:
                max_trues = st.integers(min_value=0,
                                        max_value=min(
                                            bool_dims,
                                            key=lambda x: np.prod(x)))

            index += [(
                i[0],
                draw(
                    hnp.arrays(shape=sh, dtype=bool).filter(
                        lambda x: x.sum() in (1, max_trues))),
            ) for i, sh in zip(grouped_bool_inds, bool_dims)]

            for i in bool_inds:
                shape_inds.pop(shape_inds.index(i))

    grouped_shape_inds = group_continuous_integers(sorted(shape_inds))
    if len(grouped_shape_inds) == 1:
        # unused indices form a continuous stretch of dimensions
        # so can replace with an ellipsis

        # to test ellipsis vs omitted slices, randomly
        # add ellipsis when the unused axes are trailing
        if max(shape_inds) + 1 == len(shape):
            if draw(st.booleans()):
                index += [(min(shape_inds), Ellipsis)]
        else:
            index += [(min(shape_inds), Ellipsis)]
    elif len(grouped_shape_inds) == 0 and draw(st.booleans()):
        # all indices filled already
        # can randomly add ellipsis that expands to 0-d tuple
        # this can have counter-intuitive behavior
        # (particularly in conjunction with array indices)
        i = draw(st.integers(min_value=0, max_value=len(index)))
        index.insert(i, (i, Ellipsis))
    else:
        # so that current chosen index's work,
        # fill in remaining any gaps with empty slices
        index += [(i, slice(None)) for i in shape_inds]

    index = sorted(index, key=lambda x: x[0])

    # can now randomly add in newaxis objects
    newaxis_pos = sorted(
        draw(
            st.lists(st.integers(min_value=0, max_value=len(index)),
                     unique=True)),
        reverse=True,
    )
    for i in newaxis_pos:
        index.insert(i, (-1, np.newaxis))

    out_ind = tuple(i[1] for i in index)
    return out_ind
예제 #11
0
def test_basic_indices_can_generate_long_ellipsis():
    # Runs of slice(None) - such as [0,:,:,:,0] - can be replaced by e.g. [0,...,0]
    find_any(
        nps.basic_indices(shape=(1, 0, 0, 0, 1), allow_ellipsis=True),
        lambda ix: len(ix) == 3 and ix[1] == Ellipsis,
    )
예제 #12
0
def test_basic_indices_can_generate_non_tuples():
    find_any(
        nps.basic_indices(shape=(0, 0), allow_ellipsis=True),
        lambda ix: not isinstance(ix, tuple),
    )
예제 #13
0
def test_basic_indices_can_generate_empty_tuple():
    find_any(nps.basic_indices(shape=(0, 0), allow_ellipsis=True), lambda ix: ix == ())
예제 #14
0
def test_basic_indices_options(condition):
    indexers = nps.array_shapes(min_dims=0, max_dims=32).flatmap(
        lambda shape: nps.basic_indices(shape, allow_newaxis=True)
    )
    find_any(indexers, condition)
예제 #15
0
        nps.basic_indices(shape=(0, 0), allow_ellipsis=True),
        lambda ix: not isinstance(ix, tuple),
    )


def test_basic_indices_can_generate_long_ellipsis():
    # Runs of slice(None) - such as [0,:,:,:,0] - can be replaced by e.g. [0,...,0]
    find_any(
        nps.basic_indices(shape=(1, 0, 0, 0, 1), allow_ellipsis=True),
        lambda ix: len(ix) == 3 and ix[1] == Ellipsis,
    )


@given(
    nps.basic_indices(shape=(0, 0, 0, 0, 0)).filter(
        lambda idx: isinstance(idx, tuple) and Ellipsis in idx
    )
)
def test_basic_indices_replaces_whole_axis_slices_with_ellipsis(idx):
    # `slice(None)` (aka `:`) is the only valid index for an axis of size
    # zero, so if all dimensions are 0 then a `...` will replace all the
    # slices because we generate `...` for entire contiguous runs of `:`
    assert slice(None) not in idx


def test_basic_indices_can_generate_indices_not_covering_all_dims():
    # These "flat indices" are skippable in the underlying BasicIndexStrategy,
    # so we ensure we're definitely generating them for nps.basic_indices().
    find_any(
        nps.basic_indices(shape=(3, 3, 3)),
        lambda ix: (
예제 #16
0
def test_test_basic_indices_kwonly_emulation():
    with pytest.raises(InvalidArgument):
        nps.basic_indices((), 0, 1).validate()
    with pytest.raises(InvalidArgument):
        nps.basic_indices((), __reserved=None).validate()
예제 #17
0
def test_basic_indices_bad_min_dims_warns():
    with pytest.warns(HypothesisDeprecationWarning):
        with pytest.raises(InvalidArgument):
            nps.basic_indices((3, 3, 3), min_dims=4).example()
예제 #18
0
def test_basic_indices_default_max_dims_does_not_warn():
    with catch_warnings(record=True) as record:
        nps.basic_indices((3, 3, 3)).example()
        nps.basic_indices((3, 3, 3), allow_newaxis=True).example()
        assert len(record) == 0
예제 #19
0
def test_basic_indices_bad_max_dims_warns():
    with pytest.warns(HypothesisDeprecationWarning):
        nps.basic_indices((3, 3, 3), max_dims=4).example()