Skip to content

Commit a02f28e

Browse files
committed
arena: preserve rank>0 zero-volume ranges; fix stale view comment
ArenaToTBuilder::emplace, given a zero-volume range, used to leave the cell default/null. For an owning (non-view) inner that drops the range metadata -- arena_outer_init keeps a rank>0 zero-volume range as an empty-but-ranked tensor and only collapses a rank-0 range to null. Since make_nested_tile now routes through the builder, mirror that handling so a TA::Tensor inner with e.g. Range{0} stays an empty rank-1 tensor. Arena view inners (which cannot carry a standalone range) still go null. Adds a regression test. Also drops a stale type_traits.h comment that listed TensorInterface as an is_tensor_view specialization -- it is deliberately not a view.
1 parent 176df8a commit a02f28e

3 files changed

Lines changed: 33 additions & 7 deletions

File tree

src/TiledArray/tensor/arena_kernels.h

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -188,14 +188,23 @@ class ArenaToTBuilder {
188188

189189
/// Size and bind the inner cell at outer cell ordinal `ord` to
190190
/// `inner_range`, returning a reference to the bound cell for the caller to
191-
/// fill. A zero-volume range leaves the cell null. Outer element indices
192-
/// translate via `outer_range().ordinal(idx)`.
191+
/// fill. A zero-volume range yields an empty cell: an owning inner keeps a
192+
/// rank>0 range (a rank-0 range stays null), a view inner stays null.
193+
/// Outer element indices translate via `outer_range().ordinal(idx)`.
193194
inner_t& emplace(std::size_t ord, inner_range_t inner_range) {
194195
TA_ASSERT(ord < n_cells_);
195196
inner_t& cell = data_[ord];
196-
const std::size_t vol = inner_range.volume();
197-
if (vol == 0) return cell; // stays null
198197
constexpr bool arena = is_arena_tensor_v<inner_t>;
198+
const std::size_t vol = inner_range.volume();
199+
if (vol == 0) {
200+
// Mirror arena_outer_init: an owning (non-view) inner preserves a
201+
// rank>0 zero-volume range as an empty-but-ranked tensor; a rank-0
202+
// range -- and any arena view inner -- leaves the cell default/null.
203+
if constexpr (!arena) {
204+
if (inner_range.rank() != 0) cell = inner_t(std::move(inner_range));
205+
}
206+
return cell;
207+
}
199208
std::size_t stride;
200209
std::size_t bytes;
201210
if constexpr (arena) {

src/TiledArray/tensor/type_traits.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,9 +120,11 @@ inline constexpr const bool is_nested_tensor_v = is_nested_tensor<Ts...>::value;
120120
} // namespace detail
121121

122122
/// Forward decl for the tensor-view predicate. Specializations live in
123-
/// `tensor/arena_tensor.h` (`ArenaTensor`, `detail::TensorInterface`) and
124-
/// `external/btas.h` (`btas::TensorView`). Declared here so the operator-body
125-
/// predicates below can consult it without including arena_tensor.h.
123+
/// `tensor/arena_tensor.h` (`ArenaTensor`) and `external/btas.h`
124+
/// (`btas::TensorView`). Declared here so the operator-body predicates below
125+
/// can consult it without including arena_tensor.h. Note `TensorInterface` /
126+
/// `TensorMap` is deliberately *not* a view here -- it has value-returning
127+
/// member arithmetic (see arena_tensor.h).
126128
template <typename T>
127129
struct is_tensor_view : std::false_type {};
128130
template <typename T>

tests/arena_kernels.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,21 @@ BOOST_AUTO_TEST_CASE(builder_single_cell_uses_one_exact_page) {
199199
BOOST_CHECK_EQUAL(built.data()->at_ordinal(i), double(i));
200200
}
201201

202+
BOOST_AUTO_TEST_CASE(builder_zero_volume_nonscalar_range_keeps_rank) {
203+
// an owning inner given a zero-volume but rank>0 range keeps that range
204+
// (mirrors arena_outer_init): the rank-1 range is preserved rather than
205+
// collapsed to a rank-0 null cell
206+
TA::detail::ArenaToTBuilder<outer_t> b(TA::Range{2l});
207+
inner_t& c0 = b.emplace(0, TA::Range{0l}); // rank 1, extent 0, volume 0
208+
inner_t& c1 = b.emplace(1, TA::Range{3l});
209+
BOOST_CHECK_EQUAL(c0.range().rank(), 1u);
210+
BOOST_CHECK_EQUAL(c0.range().volume(), 0u);
211+
BOOST_CHECK(!c1.empty());
212+
outer_t built = std::move(b).finish();
213+
BOOST_CHECK_EQUAL(built.data()[0].range().rank(), 1u);
214+
BOOST_CHECK_EQUAL(built.data()[1].range().volume(), 3u);
215+
}
216+
202217
BOOST_AUTO_TEST_CASE(compact_coalesces_a_multipage_tile) {
203218
const std::size_t N = 16;
204219
TA::detail::ArenaToTBuilder<outer_t> b(TA::Range{static_cast<long>(N)}, 1,

0 commit comments

Comments
 (0)