1"""Tests for `_util`."""
2
3
4import numpy as np
5import pytest
6from numpy.testing import assert_array_equal
7
8from skimage.morphology import _util
9
10
11@pytest.mark.parametrize("image_shape", [
12    (111,), (33, 44), (22, 55, 11), (6, 5, 4, 3)
13])
14@pytest.mark.parametrize("order", ["C", "F"])
15def test_offsets_to_raveled_neighbors_highest_connectivity(image_shape, order):
16    """
17    Check scenarios where footprint is always of the highest connectivity
18    and all dimensions are > 2.
19    """
20    footprint = np.ones((3,) * len(image_shape), dtype=bool)
21    center = (1,) * len(image_shape)
22    offsets = _util._offsets_to_raveled_neighbors(
23        image_shape, footprint, center, order
24    )
25
26    # Assert only neighbors are present, center was removed
27    assert len(offsets) == footprint.sum() - 1
28    assert 0 not in offsets
29    # Assert uniqueness
30    assert len(set(offsets)) == offsets.size
31    # offsets form pairs of with same value but different signs
32    # if footprint is symmetric around center
33    assert all(-x in offsets for x in offsets)
34
35    # Construct image whose values are the Manhattan distance to its center
36    image_center = tuple(s // 2 for s in image_shape)
37    coords = [
38        np.abs(np.arange(s, dtype=np.intp) - c)
39        for s, c in zip(image_shape, image_center)
40    ]
41    grid = np.meshgrid(*coords, indexing="ij")
42    image = np.sum(grid, axis=0)
43
44    image_raveled = image.ravel(order)
45    image_center_raveled = np.ravel_multi_index(
46        image_center, image_shape, order=order
47    )
48
49    # Sample raveled image around its center
50    samples = []
51    for offset in offsets:
52        index = image_center_raveled + offset
53        samples.append(image_raveled[index])
54
55    # Assert that center with value 0 wasn't selected
56    assert np.min(samples) == 1
57    # Assert that only neighbors where selected
58    # (highest value == connectivity)
59    assert np.max(samples) == len(image_shape)
60    # Assert that nearest neighbors are selected first
61    assert list(sorted(samples)) == samples
62
63
64@pytest.mark.parametrize("image_shape", [
65    (2,), (2, 2), (2, 1, 2), (2, 2, 1, 2), (0, 2, 1, 2)
66])
67@pytest.mark.parametrize("order", ["C", "F"])
68def test_offsets_to_raveled_neighbors_footprint_smaller_image(image_shape,
69                                                              order):
70    """
71    Test if a dimension indicated by `image_shape` is smaller than in
72    `footprint`.
73    """
74    footprint = np.ones((3,) * len(image_shape), dtype=bool)
75    center = (1,) * len(image_shape)
76    offsets = _util._offsets_to_raveled_neighbors(
77        image_shape, footprint, center, order
78    )
79
80    # Assert only neighbors are present, center and duplicates (possible
81    # for this scenario) where removed
82    assert len(offsets) <= footprint.sum() - 1
83    assert 0 not in offsets
84    # Assert uniqueness
85    assert len(set(offsets)) == offsets.size
86    # offsets form pairs of with same value but different signs
87    # if footprint is symmetric around center
88    assert all(-x in offsets for x in offsets)
89
90
91def test_offsets_to_raveled_neighbors_explicit_0():
92    """Check reviewed example."""
93    image_shape = (100, 200, 3)
94    footprint = np.ones((3, 3, 3), dtype=bool)
95    center = (1, 1, 1)
96    offsets = _util._offsets_to_raveled_neighbors(
97        image_shape, footprint, center
98    )
99
100    desired = np.array([
101          3, -600,    1,   -1,  600,   -3,    4,    2,  603,   -2,   -4,
102        -597,  601, -599, -601, -603,  599,  597,  602, -604,  596, -596,
103        -598, -602,  598,  604
104    ])
105    assert_array_equal(offsets, desired)
106
107
108def test_offsets_to_raveled_neighbors_explicit_1():
109    """Check reviewed example where footprint is larger in last dimension."""
110    image_shape = (10, 9, 8, 3)
111    footprint = np.ones((3, 3, 3, 4), dtype=bool)
112    center = (1, 1, 1, 1)
113    offsets = _util._offsets_to_raveled_neighbors(
114        image_shape, footprint, center
115    )
116
117    desired = np.array([
118            216, 24, -24, 3, -216, 1, -1, -3, 215, -27, -25, -23, -21, -2,
119            -192, 192, 2, 4, 21, 23, 25, 27, -4, 217, 213, -219, 219, -217,
120            -213, -215, 240, -240, 193, 239, -237, 241, -239, 218, -220, 22,
121            -241, 243, 189, 26, -243, 191, 20, -218, 195, -193, 220, -191,
122            -212, -189, 214, 28, -195, -214, -28, 212, -22, 237, -20, -26, 236,
123            196, 190, 242, 238, 194, 188, -244, -188, -196, -194, -190, -238,
124            -236, 244, -242, 5, 221, -211, -19, 29, -235, -187, 197, 245
125            ])
126    assert_array_equal(offsets, desired)
127