@@ -120,6 +120,30 @@ def _cmp_layout_from_dense_vs_from_np(layout: StridedLayout, np_ref: np.ndarray,
120120 assert layout_from_np .strides_in_bytes == layout .strides_in_bytes
121121
122122
123+ def _check_envelope (layout : StridedLayout , layout_spec : LayoutSpec ):
124+ orignal_vol = math .prod (layout_spec .shape )
125+ min_offset , max_offset = layout .offset_bounds
126+ if layout .volume == 0 :
127+ assert min_offset == 0
128+ assert max_offset == - 1
129+ else :
130+ assert min_offset >= 0
131+ assert min_offset <= max_offset
132+ assert max_offset <= orignal_vol - 1
133+ if layout .is_dense :
134+ assert min_offset == 0
135+ assert max_offset == math .prod (layout .shape ) - 1
136+ else :
137+ shape , strides = layout .shape , layout .strides
138+ ref_min_offset = ref_max_offset = layout .slice_offset
139+ ref_min_offset += sum (strides [i ] * (shape [i ] - 1 ) for i in range (layout .ndim ) if strides [i ] < 0 )
140+ ref_max_offset += sum (strides [i ] * (shape [i ] - 1 ) for i in range (layout .ndim ) if strides [i ] > 0 )
141+ assert min_offset == ref_min_offset
142+ assert max_offset == ref_max_offset
143+ assert 0 <= layout .required_size_in_bytes () <= orignal_vol * layout_spec .itemsize
144+ assert layout .required_size_in_bytes () == (max_offset + 1 ) * layout .itemsize
145+
146+
123147def _cmp_slice_offset (
124148 layout_0 : StridedLayout ,
125149 layout_1 : StridedLayout ,
@@ -149,6 +173,7 @@ def test_dense_with_permutation_as_stride_order(layout_spec):
149173 layout , np_ref = _setup_layout_and_np_ref (layout_spec )
150174 _cmp_layout_and_array (layout , np_ref , False )
151175 _cmp_layout_from_dense_vs_from_np (layout , np_ref , False )
176+ _check_envelope (layout , layout_spec )
152177 assert layout .stride_order == layout_spec .stride_order
153178
154179
@@ -182,6 +207,7 @@ def test_permuted(layout_spec):
182207 layout , np_ref = _transform (layout , np_ref , layout_spec )
183208 _cmp_layout_and_array (layout , np_ref , layout_spec .has_no_strides_transformed ())
184209 _cmp_layout_from_dense_vs_from_np (layout , np_ref , layout_spec .has_no_strides_transformed ())
210+ _check_envelope (layout , layout_spec )
185211 unit_dims_count = sum (dim == 1 for dim in np_ref .shape )
186212 if unit_dims_count <= 1 :
187213 # stride order with multiple unit dimensions is not unique
@@ -277,6 +303,7 @@ def test_slice(layout_spec, error_msg):
277303 _cmp_layout_and_array (sliced , sliced_ref , False )
278304 _cmp_layout_from_dense_vs_from_np (sliced , sliced_ref , False )
279305 _cmp_slice_offset (layout , sliced , np_ref , sliced_ref )
306+ _check_envelope (sliced , layout_spec )
280307 layout = sliced
281308 np_ref = sliced_ref
282309 else :
@@ -406,6 +433,7 @@ def test_reshape(layout_spec, new_shape, error_msg):
406433 reshaped_ref = np_ref .reshape (new_shape , copy = False )
407434 _cmp_layout_and_array (reshaped , reshaped_ref , False )
408435 _cmp_layout_from_dense_vs_from_np (reshaped , reshaped_ref , False )
436+ _check_envelope (reshaped , layout_spec )
409437 else :
410438 # sanity check that numpy is not able to reshape without
411439 # a copy as well
@@ -473,6 +501,7 @@ def test_flatten(
473501 layout , np_ref = _transform (layout , np_ref , layout_spec )
474502 _cmp_layout_and_array (layout , np_ref , layout_spec .has_no_strides_transformed ())
475503 _cmp_layout_from_dense_vs_from_np (layout , np_ref , layout_spec .has_no_strides_transformed ())
504+ _check_envelope (layout , layout_spec )
476505
477506 mask = flatten_mask2str (layout .flattened_axis_mask (), layout .ndim )
478507 assert mask == expected_axis_mask
@@ -583,6 +612,8 @@ def test_flatten_together(
583612
584613 flattened_0 = layout_0 .flattened (mask = mask )
585614 flattened_1 = layout_1 .flattened (mask = mask )
615+ _check_envelope (flattened_0 , layout_spec_0 )
616+ _check_envelope (flattened_1 , layout_spec_1 )
586617
587618 for flattened , expected_layout in zip ([flattened_0 , flattened_1 ], [expected_layout_0 , expected_layout_1 ]):
588619 assert flattened == expected_layout
@@ -640,6 +671,7 @@ def test_squeezed(layout_spec):
640671 assert squeezed .shape == (0 ,)
641672 assert squeezed .strides == (0 ,)
642673 assert squeezed .slice_offset == layout .slice_offset
674+ _check_envelope (squeezed , layout_spec )
643675
644676
645677@pytest .mark .parametrize (
@@ -681,6 +713,7 @@ def test_unsqueezed_layout(layout_spec, axes):
681713 has_no_strides = layout_spec .has_no_strides_transformed () and len (axes ) == 0
682714 _cmp_layout_and_array (unsqueezed , unsqueezed_ref , has_no_strides )
683715 _cmp_layout_from_dense_vs_from_np (unsqueezed , unsqueezed_ref , has_no_strides )
716+ _check_envelope (unsqueezed , layout_spec )
684717
685718
686719@pytest .mark .parametrize (
@@ -748,11 +781,13 @@ def test_packed_unpacked(
748781 has_no_strides = layout_spec .has_no_strides_transformed () and layout .itemsize == new_itemsize
749782 _cmp_layout_and_array (packed , packed_ref , has_no_strides )
750783 _cmp_layout_from_dense_vs_from_np (packed , packed_ref , has_no_strides )
784+ _check_envelope (packed , layout_spec )
751785 vec_size = new_itemsize // layout .itemsize
752786 assert packed .slice_offset * vec_size == layout .slice_offset
753787 unpacked = packed .repacked (layout .itemsize , axis = axis )
754788 _cmp_layout_and_array (unpacked , np_ref , has_no_strides )
755789 _cmp_layout_from_dense_vs_from_np (unpacked , np_ref , has_no_strides )
790+ _check_envelope (unpacked , layout_spec )
756791
757792
758793@pytest .mark .parametrize (
@@ -801,6 +836,7 @@ def test_broadcast_layout(
801836 broadcasted_ref = np .broadcast_to (np_ref , new_shape )
802837 _cmp_layout_and_array (broadcasted , broadcasted_ref , False )
803838 _cmp_layout_from_dense_vs_from_np (broadcasted , broadcasted_ref , False )
839+ _check_envelope (broadcasted , layout_spec )
804840 assert layout .is_unique
805841 ndim_diff = len (broadcasted_ref .shape ) - len (np_ref .shape )
806842 expect_unique = all (broadcasted_ref .shape [i ] == 1 for i in range (ndim_diff ))
@@ -875,3 +911,7 @@ def test_to_dense(layout_spec, new_stride_order):
875911 dense_ref = np_ref .transpose (new_stride_order ).copy (order = "C" ).transpose (inv_permutation (new_stride_order ))
876912 _cmp_layout_and_array (dense , dense_ref , False )
877913 _cmp_layout_from_dense_vs_from_np (dense , dense_ref , False )
914+
915+ assert dense .is_dense
916+ assert dense .required_size_in_bytes () == np_ref .size * layout .itemsize
917+ assert dense .offset_bounds == (0 , np_ref .size - 1 )
0 commit comments