45template <
class Storage>
47 typename Storage::leaf_storage_policy;
48 typename Storage::backend_selector_type;
49 typename Storage::block_execution_policy;
50 { Storage::stores_all_legal_blocks } -> std::convertible_to<bool>;
51 { Storage::is_distributed } -> std::convertible_to<bool>;
52 { Storage::backend_selector() } -> std::same_as<typename Storage::backend_selector_type>;
57template <
class Storage>
62template <
class Storage>
70template <
class Storage>
72 { Storage::stores_diagonal_blocks } -> std::convertible_to<bool>;
73} && Storage::stores_diagonal_blocks;
80template <
class Storage,
typename T, std::
size_t KeyCoordinateCount, std::
size_t DenseBlockOrder>
83 requires(
typename Storage::template storage_t<T, KeyCoordinateCount, DenseBlockOrder>& storage,
84 typename Storage::template storage_t<T, KeyCoordinateCount, DenseBlockOrder>
const& const_storage,
85 std::array<std::size_t, DenseBlockOrder>
const& extents) {
86 typename Storage::template storage_t<T, KeyCoordinateCount, DenseBlockOrder>::mutable_block_type;
87 typename Storage::template storage_t<T, KeyCoordinateCount, DenseBlockOrder>::const_block_type;
88 { const_storage.size() } -> std::same_as<std::size_t>;
89 { const_storage.keys() } -> std::same_as<std::span<BlockKey<KeyCoordinateCount>
const>>;
91 storage.block(std::size_t{}, extents)
93 -> std::same_as<typename Storage::template storage_t<T, KeyCoordinateCount, DenseBlockOrder>::mutable_block_type>;
95 const_storage.block(std::size_t{}, extents)
96 } -> std::same_as<typename Storage::template storage_t<T, KeyCoordinateCount, DenseBlockOrder>::const_block_type>;
99 typename Storage::template storage_t<T, KeyCoordinateCount, DenseBlockOrder>::mutable_block_type,
104 typename Storage::template storage_t<T, KeyCoordinateCount, DenseBlockOrder>::mutable_block_type>,
106 std::same_as<
typename tensor_mdspec_t<
typename Storage::template storage_t<
107 T, KeyCoordinateCount, DenseBlockOrder>::const_block_type>::element_type,
117template <
class Storage,
typename T, std::
size_t KeyCoordinateCount, std::
size_t DenseBlockOrder>
126template <
class Storage,
typename T, std::
size_t KeyCoordinateCount, std::
size_t DenseBlockOrder>
130 typename Storage::template storage_t<T, KeyCoordinateCount, DenseBlockOrder>::mutable_block_type,
133 typename Storage::template storage_t<T, KeyCoordinateCount, DenseBlockOrder>::const_block_type,
141template <
class Storage,
typename T, std::
size_t KeyCoordinateCount, std::
size_t DenseBlockOrder>
144 requires(
typename Storage::template storage_t<T, KeyCoordinateCount, DenseBlockOrder>& storage,
145 typename Storage::template storage_t<T, KeyCoordinateCount, DenseBlockOrder>
const& const_storage) {
146 typename Storage::template storage_t<T, KeyCoordinateCount, DenseBlockOrder>::block_value_type;
147 typename Storage::template storage_t<T, KeyCoordinateCount, DenseBlockOrder>::async_block_type;
149 storage.async_block(std::size_t{})
151 -> std::same_as<typename Storage::template storage_t<T, KeyCoordinateCount, DenseBlockOrder>::async_block_type&>;
153 const_storage.async_block(std::size_t{})
155 typename Storage::template storage_t<T, KeyCoordinateCount, DenseBlockOrder>::async_block_type
const&>;
158 typename Storage::template storage_t<T, KeyCoordinateCount, DenseBlockOrder>::async_block_type,
161 typename Storage::template storage_t<T, KeyCoordinateCount, DenseBlockOrder>::block_value_type,
167template <
class Storage,
typename T, std::
size_t KeyCoordinateCount, std::
size_t DenseBlockOrder>
174template <std::
size_t KeyCoordinateCount, std::
size_t DenseBlockOrder>
struct BlockSpec
176 BlockKey<KeyCoordinateCount> key;
177 std::array<std::size_t, DenseBlockOrder> extents;
180template <
class Tensor, std::size_t Order, std::size_t... I>
181auto make_block_tensor(std::array<std::size_t, Order>
const& extents,
StorageInitialization initialization,
182 std::index_sequence<I...>) ->
Tensor
189template <
class Tensor, std::
size_t Order>
192 return make_block_tensor<Tensor>(extents, initialization, std::make_index_sequence<Order>{});
195template <
class Extents, std::size_t Order, std::size_t... I>
196auto make_extents(std::array<std::size_t, Order>
const& extents, std::index_sequence<I...>) -> Extents
198 return Extents(
static_cast<typename Extents::index_type
>(extents[I])...);
201template <
class Extents, std::
size_t Order>
auto make_extents(std::array<std::size_t, Order>
const& extents) -> Extents
203 return make_extents<Extents>(extents, std::make_index_sequence<Order>{});
206inline auto checked_block_size(std::span<std::size_t const> extents) -> std::size_t
208 std::size_t size = 1;
209 for (std::size_t
const extent : extents)
211 if (extent != 0 && size > std::numeric_limits<std::size_t>::max() / extent)
213 throw std::length_error(
"BlockTensor block size overflows size_t");
220template <std::
size_t Rank>
221constexpr auto diagonal_extent(std::array<std::size_t, Rank>
const& extents)
noexcept -> std::size_t
223 if constexpr (Rank == 0)
229 return *std::ranges::min_element(extents);
233template <
class Storage,
class T>
234auto make_storage(std::size_t size,
StorageInitialization initialization) ->
typename Storage::template storage_t<T>
236 using storage_type =
typename Storage::template storage_t<T>;
237 if constexpr (
requires { Storage::template make_storage<T>(size, initialization); })
239 return Storage::template make_storage<T>(size, initialization);
246 if constexpr (std::default_initializable<storage_type> &&
requires(storage_type&
value) {
value.resize(size); })
254 return storage_type(size);
257 initialize_host_elements(storage.data(), size, initialization);
262template <
class Storage,
class T>
263auto make_storage_like(
typename Storage::template storage_t<T>
const& prototype, std::size_t size,
266 if constexpr (
requires {
268 Storage::template make_storage_like<T>(prototype, size, initialization)
269 } -> std::same_as<typename Storage::template storage_t<T>>;
272 return Storage::template make_storage_like<T>(prototype, size, initialization);
276 return make_storage<Storage, T>(size, initialization);
280template <
class Storage,
class T,
class =
void>
struct PackedStorageType
282 using type =
typename Storage::template storage_t<T>;
285template <
class Storage,
class T>
286struct PackedStorageType<Storage, T,
std::void_t<typename Storage::template packed_storage_t<T>>>
288 using type =
typename Storage::template packed_storage_t<T>;
291template <
class Storage,
class T>
using packed_storage_t =
typename PackedStorageType<Storage, T>::type;
293template <
class Storage,
class T>
294auto make_packed_storage(std::size_t size, std::span<std::size_t const> offsets,
297 if constexpr (
requires {
299 Storage::template make_packed_storage<T>(size, offsets, initialization)
300 } -> std::same_as<packed_storage_t<Storage, T>>;
303 return Storage::template make_packed_storage<T>(size, offsets, initialization);
307 return make_storage<Storage, T>(size, initialization);
311template <
class Storage,
class T>
312auto make_packed_storage_like(packed_storage_t<Storage, T>
const& prototype, std::size_t size,
313 std::span<std::size_t const> offsets,
316 if constexpr (
requires {
318 Storage::template make_packed_storage_like<T>(prototype, size, offsets, initialization)
319 } -> std::same_as<packed_storage_t<Storage, T>>;
322 return Storage::template make_packed_storage_like<T>(prototype, size, offsets, initialization);
326 return make_storage_like<Storage, T>(prototype, size, initialization);
330template <
class Storage,
class Buffer>
331decltype(
auto) make_packed_data_descriptor(Buffer& buffer, std::size_t ordinal, std::size_t offset)
333 if constexpr (
requires { Storage::make_packed_data_descriptor(buffer, ordinal); })
334 return Storage::make_packed_data_descriptor(buffer, ordinal);
336 return Storage::make_data_descriptor(buffer).offset_by(offset);
339template <
class Storage,
class T,
class Buffer>
340void initialize_packed_padding(Buffer& buffer, std::span<std::size_t const> offsets,
341 std::span<std::size_t const> block_ends)
343 if constexpr (
requires { Storage::initialize_packed_padding(buffer, offsets, block_ends); })
345 Storage::initialize_packed_padding(buffer, offsets, block_ends);
350 requires { Storage::make_handle(buffer); },
351 "aligned packed storage must provide immediate access or initialize_packed_padding");
352 auto* data = Storage::make_handle(buffer);
353 for (std::size_t ordinal = 0; ordinal < block_ends.size(); ++ordinal)
354 std::fill(data + block_ends[ordinal], data + offsets[ordinal + 1], zero_value<T>());
358template <
typename T, std::
size_t KeyCoordinateCount, std::
size_t DenseBlockOrder,
class LeafStorage>
359class SeparateSparseBlockStorageData {
361 using key_type = BlockKey<KeyCoordinateCount>;
362 using block_type = ColumnMajorTensor<T, DenseBlockOrder, LeafStorage>;
365 using mutable_block_type = MdspecTensorView<mutable_mdspan_type, const_mdspan_type, LeafStorage>;
366 using const_block_type = MdspecTensorView<const_mdspan_type, const_mdspan_type, LeafStorage>;
369 "separate sparse block storage currently requires immediate leaf access");
371 explicit SeparateSparseBlockStorageData(std::vector<BlockSpec<KeyCoordinateCount, DenseBlockOrder>>
const& specs,
374 keys_.reserve(specs.size());
375 blocks_.reserve(specs.size());
376 for (
auto const& spec : specs)
378 keys_.push_back(spec.key);
379 blocks_.push_back(make_block_tensor<block_type>(spec.extents, initialization));
383 auto size()
const noexcept -> std::size_t {
return keys_.size(); }
384 auto keys()
const noexcept -> std::span<key_type const> {
return keys_; }
386 auto block(std::size_t ordinal, std::array<std::size_t, DenseBlockOrder>
const&) -> mutable_block_type
388 return mutable_block_type{blocks_[ordinal].mdspan(), std::as_const(blocks_[ordinal]).mdspan()};
391 auto block(std::size_t ordinal, std::array<std::size_t, DenseBlockOrder>
const&)
const -> const_block_type
393 auto span = blocks_[ordinal].mdspan();
394 return const_block_type{
span,
span};
398 std::vector<key_type> keys_;
399 std::vector<block_type> blocks_;
402template <
class LeafStorage,
typename T>
403concept ImmediatePackedLeafStorage =
404 std::default_initializable<tensor_accessor_factory_t<LeafStorage>> &&
405 requires(
typename LeafStorage::template storage_t<T>& buffer,
406 typename LeafStorage::template storage_t<T>
const& const_buffer,
407 tensor_accessor_factory_t<LeafStorage>
const& accessor_factory) {
409 LeafStorage::make_handle(buffer)
411 -> std::convertible_to<typename tensor_accessor_factory_t<LeafStorage>::template accessor_t<T>::data_handle_type>;
413 LeafStorage::make_handle(const_buffer)
414 } -> std::convertible_to<
415 typename tensor_accessor_factory_t<LeafStorage>::template accessor_t<T const>::data_handle_type>;
417 accessor_factory.template make_accessor<T>(buffer)
418 } -> std::same_as<typename tensor_accessor_factory_t<LeafStorage>::template accessor_t<T>>;
420 accessor_factory.template make_accessor<T const>(const_buffer)
421 } -> std::same_as<typename tensor_accessor_factory_t<LeafStorage>::template accessor_t<T const>>;
424template <
typename T, std::size_t DenseBlockOrder,
class LeafStorage,
425 bool Immediate = ImmediatePackedLeafStorage<LeafStorage, T>>
426struct PackedBlockViewTraits;
428template <
typename T, std::
size_t DenseBlockOrder,
class LeafStorage>
429struct PackedBlockViewTraits<T, DenseBlockOrder, LeafStorage, true>
431 using buffer_type = packed_storage_t<LeafStorage, T>;
432 using extents_type = stdex::dextents<index_type, DenseBlockOrder>;
433 using mapping_type =
typename ColumnMajor::template mapping<extents_type>;
434 using accessor_factory_type = tensor_accessor_factory_t<LeafStorage>;
435 using accessor_type =
typename accessor_factory_type::template accessor_t<T>;
436 using const_accessor_type =
typename accessor_factory_type::template accessor_t<T const>;
437 using mutable_mdspec_type = stdex::mdspan<T, extents_type, ColumnMajor, accessor_type>;
438 using const_mdspec_type = stdex::mdspan<T const, extents_type, ColumnMajor, const_accessor_type>;
439 using mutable_block_type = MdspecTensorView<mutable_mdspec_type, const_mdspec_type, LeafStorage>;
440 using const_block_type = MdspecTensorView<const_mdspec_type, const_mdspec_type, LeafStorage>;
442 static auto mutable_block(buffer_type& buffer, std::size_t offset,
443 extents_type
const& extents) -> mutable_block_type
445 accessor_factory_type accessor_factory;
446 auto accessor = accessor_factory.template make_accessor<T>(buffer);
447 auto const_accessor = accessor_factory.template make_accessor<T const>(std::as_const(buffer));
448 auto mutable_handle = accessor.offset(LeafStorage::make_handle(buffer), offset);
449 auto const_handle =
const_accessor.offset(LeafStorage::make_handle(std::as_const(buffer)), offset);
450 return mutable_block_type{mutable_mdspec_type{mutable_handle, mapping_type(extents), accessor},
451 const_mdspec_type{const_handle, mapping_type(extents),
const_accessor}};
454 static auto const_block(buffer_type
const& buffer, std::size_t offset,
455 extents_type
const& extents) -> const_block_type
457 accessor_factory_type accessor_factory;
458 auto accessor = accessor_factory.template make_accessor<T const>(buffer);
459 auto handle = accessor.offset(LeafStorage::make_handle(buffer), offset);
460 auto span = const_mdspec_type{
handle, mapping_type(extents), accessor};
461 return const_block_type{
span,
span};
465template <
typename T, std::
size_t DenseBlockOrder,
class LeafStorage>
466struct PackedBlockViewTraits<T, DenseBlockOrder, LeafStorage, false>
468 using buffer_type = packed_storage_t<LeafStorage, T>;
469 using extents_type = stdex::dextents<index_type, DenseBlockOrder>;
470 using mapping_type =
typename ColumnMajor::template mapping<extents_type>;
471 using accessor_factory_type = tensor_accessor_factory_t<LeafStorage>;
472 using accessor_type = tensor_device_accessor_t<accessor_factory_type, T>;
473 using const_accessor_type = tensor_device_accessor_t<accessor_factory_type, T const>;
474 using descriptor_type =
475 decltype(make_packed_data_descriptor<LeafStorage>(std::declval<buffer_type&>(), std::size_t{}, std::size_t{}));
476 using const_descriptor_type =
decltype(make_packed_data_descriptor<LeafStorage>(std::declval<buffer_type const&>(),
477 std::size_t{}, std::size_t{}));
478 using mutable_mdspec_type = mdspec<T, extents_type, ColumnMajor, accessor_type, descriptor_type>;
479 using const_mdspec_type = mdspec<T const, extents_type, ColumnMajor, const_accessor_type, const_descriptor_type>;
480 using mutable_block_type = MdspecTensorView<mutable_mdspec_type, const_mdspec_type, LeafStorage>;
481 using const_block_type = MdspecTensorView<const_mdspec_type, const_mdspec_type, LeafStorage>;
483 static_assert(std::default_initializable<accessor_factory_type>,
484 "packed descriptor-backed storage requires a default-constructible accessor factory");
485 template <
class ElementType>
487 device_accessor(buffer_type
const& buffer) -> tensor_device_accessor_t<accessor_factory_type, ElementType>
489 accessor_factory_type accessor_factory;
490 if constexpr (
requires { accessor_factory.template make_device_accessor<ElementType>(buffer); })
491 return accessor_factory.template make_device_accessor<ElementType>(buffer);
493 return accessor_factory.template make_accessor<ElementType>(buffer);
496 static auto mutable_block(buffer_type& buffer, std::size_t offset, extents_type
const& extents,
497 std::size_t ordinal) -> mutable_block_type
499 auto descriptor = make_packed_data_descriptor<LeafStorage>(buffer, ordinal, offset);
500 auto const_descriptor = make_packed_data_descriptor<LeafStorage>(std::as_const(buffer), ordinal, offset);
501 return mutable_block_type{
502 mutable_mdspec_type{std::move(descriptor), mapping_type(extents), device_accessor<T>(buffer)},
503 const_mdspec_type{std::move(const_descriptor), mapping_type(extents), device_accessor<T const>(buffer)}};
506 static auto const_block(buffer_type
const& buffer, std::size_t offset, extents_type
const& extents,
507 std::size_t ordinal) -> const_block_type
509 auto descriptor = make_packed_data_descriptor<LeafStorage>(buffer, ordinal, offset);
510 auto span = const_mdspec_type{std::move(descriptor), mapping_type(extents), device_accessor<T const>(buffer)};
511 return const_block_type{
span,
span};
515template <
typename T, std::size_t KeyCoordinateCount, std::size_t DenseBlockOrder,
class LeafStorage,
516 std::size_t BlockAlignment>
517class PackedBlockStorageData {
519 using key_type = BlockKey<KeyCoordinateCount>;
520 using buffer_type = packed_storage_t<LeafStorage, T>;
521 using view_traits = PackedBlockViewTraits<T, DenseBlockOrder, LeafStorage>;
522 using extents_type =
typename view_traits::extents_type;
523 using mutable_block_type =
typename view_traits::mutable_block_type;
524 using const_block_type =
typename view_traits::const_block_type;
526 static_assert(BlockAlignment > 0,
"packed block alignment must be positive");
529 if constexpr (BlockAlignment == 1)
531 else if constexpr (
requires { LeafStorage::allocation_alignment; })
532 return LeafStorage::allocation_alignment % BlockAlignment == 0;
536 "nontrivial packed block alignment must divide the leaf allocation alignment");
537 explicit PackedBlockStorageData(std::vector<BlockSpec<KeyCoordinateCount, DenseBlockOrder>>
const& specs,
539 : PackedBlockStorageData(make_layout(specs), initialization)
543 template <
class Context>
544 requires requires(Context& context, std::size_t size, std::span<std::size_t const> offsets,
547 LeafStorage::template make_packed_storage<T>(context, size, offsets, initialization)
548 } -> std::same_as<buffer_type>;
550 explicit PackedBlockStorageData(std::vector<BlockSpec<KeyCoordinateCount, DenseBlockOrder>>
const& specs,
553 : PackedBlockStorageData(make_layout(specs), context, initialization)
556 auto size()
const noexcept -> std::size_t {
return keys_.size(); }
557 auto keys()
const noexcept -> std::span<key_type const> {
return keys_; }
559 auto block(std::size_t ordinal, std::array<std::size_t, DenseBlockOrder>
const& extents) -> mutable_block_type
561 if constexpr (ImmediatePackedLeafStorage<LeafStorage, T>)
562 return view_traits::mutable_block(buffer_, offsets_[ordinal], make_extents<extents_type>(extents));
564 return view_traits::mutable_block(buffer_, offsets_[ordinal], make_extents<extents_type>(extents), ordinal);
567 auto block(std::size_t ordinal, std::array<std::size_t, DenseBlockOrder>
const& extents)
const -> const_block_type
569 if constexpr (ImmediatePackedLeafStorage<LeafStorage, T>)
570 return view_traits::const_block(buffer_, offsets_[ordinal], make_extents<extents_type>(extents));
572 return view_traits::const_block(buffer_, offsets_[ordinal], make_extents<extents_type>(extents), ordinal);
575 auto buffer()
noexcept -> buffer_type& {
return buffer_; }
576 auto buffer()
const noexcept -> buffer_type
const& {
return buffer_; }
577 auto offsets()
const noexcept -> std::span<std::size_t const> {
return offsets_; }
580 decltype(
auto) allocation_context()
const noexcept
581 requires requires(buffer_type
const& buffer) { LeafStorage::allocation_context(buffer); }
583 return LeafStorage::allocation_context(buffer_);
589 auto block_ends()
const noexcept -> std::span<std::size_t const> {
return block_ends_; }
592 [[nodiscard]]
bool has_padding()
const noexcept
594 for (std::size_t ordinal = 0; ordinal < block_ends_.size(); ++ordinal)
595 if (block_ends_[ordinal] != offsets_[ordinal + 1])
return true;
605 return PackedBlockStorageData(Layout{.keys = keys_, .offsets = offsets_, .block_ends = block_ends_}, buffer_,
612 std::vector<key_type> keys;
613 std::vector<std::size_t> offsets;
614 std::vector<std::size_t> block_ends;
617 static constexpr std::size_t alignment_elements = BlockAlignment / std::gcd(BlockAlignment,
sizeof(T));
619 static auto align_offset(std::size_t offset) -> std::size_t
621 std::size_t
const remainder = offset % alignment_elements;
623 std::size_t
const padding = alignment_elements -
remainder;
624 if (offset > std::numeric_limits<std::size_t>::max() - padding)
625 throw std::length_error(
"packed BlockTensor alignment overflows size_t");
626 return offset + padding;
629 static auto make_layout(std::vector<BlockSpec<KeyCoordinateCount, DenseBlockOrder>>
const& specs) -> Layout
632 layout.keys.reserve(specs.size());
633 layout.offsets.reserve(specs.size() + 1);
634 layout.block_ends.reserve(specs.size());
636 std::size_t end_offset = 0;
638 for (
auto const& spec : specs)
640 std::size_t
const block_offset = align_offset(end_offset);
641 layout.keys.push_back(spec.key);
642 layout.offsets.push_back(block_offset);
643 std::size_t
const block_size = checked_block_size(spec.extents);
644 if (block_offset > std::numeric_limits<std::size_t>::max() - block_size)
646 throw std::length_error(
"packed BlockTensor size overflows size_t");
648 end_offset = block_offset + block_size;
649 layout.block_ends.push_back(end_offset);
651 layout.offsets.push_back(end_offset);
656 : keys_(std::move(layout.keys)), offsets_(std::move(layout.offsets)), block_ends_(std::move(layout.block_ends)),
657 buffer_(make_packed_storage<LeafStorage, T>(offsets_.back(), offsets_, initialization))
659 if constexpr (BlockAlignment > 1)
662 initialize_packed_padding<LeafStorage, T>(buffer_, offsets_, block_ends_);
666 PackedBlockStorageData(Layout layout, buffer_type
const& prototype,
StorageInitialization initialization)
667 : keys_(std::move(layout.keys)), offsets_(std::move(layout.offsets)), block_ends_(std::move(layout.block_ends)),
668 buffer_(make_packed_storage_like<LeafStorage, T>(prototype, offsets_.back(), offsets_, initialization))
670 if constexpr (BlockAlignment > 1)
673 initialize_packed_padding<LeafStorage, T>(buffer_, offsets_, block_ends_);
677 template <
class Context>
678 requires requires(Context& context, std::size_t size, std::span<std::size_t const> offsets,
681 LeafStorage::template make_packed_storage<T>(context, size, offsets, initialization)
682 } -> std::same_as<buffer_type>;
685 : keys_(std::move(layout.keys)), offsets_(std::move(layout.offsets)), block_ends_(std::move(layout.block_ends)),
686 buffer_(LeafStorage::template make_packed_storage<T>(context, offsets_.back(), offsets_, initialization))
688 if constexpr (BlockAlignment > 1)
691 initialize_packed_padding<LeafStorage, T>(buffer_, offsets_, block_ends_);
695 std::vector<key_type> keys_;
696 std::vector<std::size_t> offsets_;
697 std::vector<std::size_t> block_ends_;
701template <
typename T, std::
size_t KeyCoordinateCount, std::
size_t DenseBlockOrder,
class LeafStorage>
702class PackedDiagonalBlockStorageData {
704 using key_type = BlockKey<KeyCoordinateCount>;
705 using buffer_type =
typename LeafStorage::template storage_t<T>;
706 using extents_type = stdex::dextents<index_type, DenseBlockOrder>;
707 using mapping_type =
typename GeneratedLayout::template mapping<extents_type>;
708 using accessor_type = diagonal_accessor<T, extents_type>;
709 using const_accessor_type = diagonal_accessor<T const, extents_type>;
710 using mutable_mdspan_type = stdex::mdspan<T, extents_type, GeneratedLayout, accessor_type>;
711 using const_mdspan_type = stdex::mdspan<T const, extents_type, GeneratedLayout, const_accessor_type>;
712 using component_extents_type = stdex::dextents<index_type, 1>;
713 using component_mapping_type = stdex::layout_stride::mapping<component_extents_type>;
714 using mutable_components_type = stdex::mdspan<T, component_extents_type, stdex::layout_stride>;
715 using const_components_type = stdex::mdspan<T const, component_extents_type, stdex::layout_stride>;
716 using mutable_block_type = MdspecTensorView<mutable_mdspan_type, const_mdspan_type, LeafStorage>;
717 using const_block_type = MdspecTensorView<const_mdspan_type, const_mdspan_type, LeafStorage>;
724 static_assert(std::same_as<detail::tensor_accessor_factory_t<LeafStorage>, DefaultAccessorFactory>,
725 "packed diagonal block storage currently requires default-accessor leaf storage");
727 requires(buffer_type& buffer, buffer_type
const& const_buffer) {
728 { LeafStorage::make_handle(buffer) } -> std::same_as<T*>;
729 { LeafStorage::make_handle(const_buffer) } -> std::same_as<T const*>;
730 },
"packed diagonal block storage currently requires immediate contiguous host leaf storage");
732 explicit PackedDiagonalBlockStorageData(std::vector<BlockSpec<KeyCoordinateCount, DenseBlockOrder>>
const& specs,
734 : PackedDiagonalBlockStorageData(make_layout(specs), initialization)
737 auto size()
const noexcept -> std::size_t {
return keys_.size(); }
738 auto keys()
const noexcept -> std::span<key_type const> {
return keys_; }
740 auto block(std::size_t ordinal, std::array<std::size_t, DenseBlockOrder>
const& extents) -> mutable_block_type
742 auto const block_extents = make_extents<extents_type>(extents);
743 auto* mutable_data = LeafStorage::make_handle(buffer_);
744 auto const* const_data = LeafStorage::make_handle(std::as_const(buffer_));
745 if (offsets_[ordinal] != 0)
747 mutable_data += offsets_[ordinal];
748 const_data += offsets_[ordinal];
750 auto const component_extents =
751 component_extents_type{
static_cast<index_type>(offsets_[ordinal + 1] - offsets_[ordinal])};
752 auto const component_mapping =
753 component_mapping_type{component_extents, std::array<index_type, 1>{
index_type{1}}};
754 auto mutable_components = mutable_components_type{mutable_data, component_mapping};
755 auto read_components = const_components_type{const_data, component_mapping};
760 auto block(std::size_t ordinal, std::array<std::size_t, DenseBlockOrder>
const& extents)
const -> const_block_type
762 auto const block_extents = make_extents<extents_type>(extents);
763 auto const* data = LeafStorage::make_handle(buffer_);
764 if (offsets_[ordinal] != 0) data += offsets_[ordinal];
765 auto const component_extents =
766 component_extents_type{
static_cast<index_type>(offsets_[ordinal + 1] - offsets_[ordinal])};
767 auto const component_mapping =
768 component_mapping_type{component_extents, std::array<index_type, 1>{
index_type{1}}};
769 auto components = const_components_type{data, component_mapping};
771 return const_block_type{
span,
span};
775 auto diagonal_values(std::size_t ordinal) -> std::span<T>
777 auto* data = LeafStorage::make_handle(buffer_);
778 if (offsets_[ordinal] != 0) data += offsets_[ordinal];
779 return {data, offsets_[ordinal + 1] - offsets_[ordinal]};
783 auto diagonal_values(std::size_t ordinal)
const -> std::span<T const>
785 auto const* data = LeafStorage::make_handle(buffer_);
786 if (offsets_[ordinal] != 0) data += offsets_[ordinal];
787 return {data, offsets_[ordinal + 1] - offsets_[ordinal]};
790 auto buffer()
noexcept -> buffer_type& {
return buffer_; }
791 auto buffer()
const noexcept -> buffer_type
const& {
return buffer_; }
792 auto offsets()
const noexcept -> std::span<std::size_t const> {
return offsets_; }
797 std::vector<key_type> keys;
798 std::vector<std::size_t> offsets;
801 static auto make_layout(std::vector<BlockSpec<KeyCoordinateCount, DenseBlockOrder>>
const& specs) -> Layout
804 layout.keys.reserve(specs.size());
805 layout.offsets.reserve(specs.size() + 1);
806 layout.offsets.push_back(0);
807 for (
auto const& spec : specs)
809 layout.keys.push_back(spec.key);
810 std::size_t
const block_size = diagonal_extent(spec.extents);
811 if (layout.offsets.back() > std::numeric_limits<std::size_t>::max() - block_size)
813 throw std::length_error(
"packed diagonal BlockTensor size overflows size_t");
815 layout.offsets.push_back(layout.offsets.back() + block_size);
821 : keys_(std::move(layout.keys)), offsets_(std::move(layout.offsets)),
822 buffer_(make_storage<LeafStorage, T>(offsets_.back(), initialization))
825 std::vector<key_type> keys_;
826 std::vector<std::size_t> offsets_;
834template <
class AsyncBlock>
class AsyncBlockDataDescriptor {
836 using async_block_type = AsyncBlock;
838 explicit AsyncBlockDataDescriptor(async_block_type& block) noexcept : block_(&block) {}
841 auto async_block()
const noexcept -> async_block_type& {
return *block_; }
844 async_block_type* block_;
847template <
typename T, std::
size_t KeyCoordinateCount, std::
size_t DenseBlockOrder,
class LeafStorage>
848class AsyncSeparateSparseBlockStorageData {
850 using key_type = BlockKey<KeyCoordinateCount>;
851 using block_value_type = ColumnMajorTensor<T, DenseBlockOrder, LeafStorage>;
853 using extents_type = stdex::dextents<index_type, DenseBlockOrder>;
854 using mapping_type =
typename ColumnMajor::template mapping<extents_type>;
855 using accessor_type = stdex::default_accessor<T>;
856 using const_accessor_type = stdex::default_accessor<T const>;
857 using mutable_descriptor_type = AsyncBlockDataDescriptor<async_block_type>;
858 using const_descriptor_type = AsyncBlockDataDescriptor<async_block_type const>;
859 using mutable_mdspec_type = mdspec<T, extents_type, ColumnMajor, accessor_type, mutable_descriptor_type>;
860 using const_mdspec_type = mdspec<T const, extents_type, ColumnMajor, const_accessor_type, const_descriptor_type>;
861 using mutable_block_type = MdspecTensorView<mutable_mdspec_type, const_mdspec_type, LeafStorage>;
862 using const_block_type = MdspecTensorView<const_mdspec_type, const_mdspec_type, LeafStorage>;
865 "async separate sparse block storage currently requires immediate leaf access");
866 static_assert(std::same_as<detail::tensor_accessor_factory_t<LeafStorage>, DefaultAccessorFactory>,
867 "async separate sparse block storage currently requires default-accessor leaf storage");
869 explicit AsyncSeparateSparseBlockStorageData(
870 std::vector<BlockSpec<KeyCoordinateCount, DenseBlockOrder>>
const& specs,
873 keys_.reserve(specs.size());
874 blocks_.reserve(specs.size());
875 for (
auto const& spec : specs)
877 keys_.push_back(spec.key);
878 blocks_.emplace_back(make_block_tensor<block_value_type>(spec.extents, initialization));
882 auto size()
const noexcept -> std::size_t {
return keys_.size(); }
883 auto keys()
const noexcept -> std::span<key_type const> {
return keys_; }
885 auto block(std::size_t ordinal, std::array<std::size_t, DenseBlockOrder>
const& extents) -> mutable_block_type
887 auto mapping = mapping_type(make_extents<extents_type>(extents));
888 return mutable_block_type{
889 mutable_mdspec_type{mutable_descriptor_type{blocks_[ordinal]}, mapping, accessor_type{}},
890 const_mdspec_type{const_descriptor_type{std::as_const(blocks_[ordinal])}, mapping, const_accessor_type{}}};
893 auto block(std::size_t ordinal, std::array<std::size_t, DenseBlockOrder>
const& extents)
const -> const_block_type
895 auto span = const_mdspec_type{const_descriptor_type{blocks_[ordinal]},
896 mapping_type(make_extents<extents_type>(extents)), const_accessor_type{}};
897 return const_block_type{
span,
span};
900 auto async_block(std::size_t ordinal)
noexcept -> async_block_type& {
return blocks_[ordinal]; }
901 auto async_block(std::size_t ordinal)
const noexcept -> async_block_type
const& {
return blocks_[ordinal]; }
904 std::vector<key_type> keys_;
905 std::vector<async_block_type> blocks_;
920 template <
typename T, std::
size_t KeyCoordinateCount, std::
size_t DenseBlockOrder>
922 detail::SeparateSparseBlockStorageData<T, KeyCoordinateCount, DenseBlockOrder, leaf_storage_policy>;
926 return leaf_storage_policy::backend_selector();
943 template <
typename T, std::
size_t KeyCoordinateCount, std::
size_t DenseBlockOrder>
945 detail::SeparateSparseBlockStorageData<T, KeyCoordinateCount, DenseBlockOrder, leaf_storage_policy>;
949 return leaf_storage_policy::backend_selector();
966 template <
typename T, std::
size_t KeyCoordinateCount, std::
size_t DenseBlockOrder>
968 detail::PackedBlockStorageData<T, KeyCoordinateCount, DenseBlockOrder, leaf_storage_policy, BlockAlignment>;
972 return leaf_storage_policy::backend_selector();
992 template <
typename T, std::
size_t KeyCoordinateCount, std::
size_t DenseBlockOrder>
994 detail::PackedBlockStorageData<T, KeyCoordinateCount, DenseBlockOrder, leaf_storage_policy, BlockAlignment>;
998 return leaf_storage_policy::backend_selector();
1017 template <
typename T, std::
size_t KeyCoordinateCount, std::
size_t DenseBlockOrder>
1019 detail::PackedBlockStorageData<T, KeyCoordinateCount, DenseBlockOrder, leaf_storage_policy, BlockAlignment>;
1023 return leaf_storage_policy::backend_selector();
1042 template <
typename T, std::
size_t KeyCoordinateCount, std::
size_t DenseBlockOrder>
1044 detail::PackedBlockStorageData<T, KeyCoordinateCount, DenseBlockOrder, leaf_storage_policy, BlockAlignment>;
1048 return leaf_storage_policy::backend_selector();
1066 template <
typename T, std::
size_t KeyCoordinateCount, std::
size_t DenseBlockOrder>
1068 detail::PackedDiagonalBlockStorageData<T, KeyCoordinateCount, DenseBlockOrder, leaf_storage_policy>;
1072 return leaf_storage_policy::backend_selector();
1089 template <
typename T, std::
size_t KeyCoordinateCount, std::
size_t DenseBlockOrder>
1091 detail::AsyncSeparateSparseBlockStorageData<T, KeyCoordinateCount, DenseBlockOrder, leaf_storage_policy>;
1095 return leaf_storage_policy::backend_selector();
1099static_assert(SparseBlockStorage<SeparateSparseBlockStorage<>>);
1100static_assert(SparseBlockStorage<ParallelSeparateSparseBlockStorage<>>);
1101static_assert(SparseBlockStorage<PackedSparseBlockStorage<>>);
1102static_assert(SparseBlockStorage<ParallelPackedSparseBlockStorage<>>);
1103static_assert(CompleteBlockStorage<PackedCompleteBlockStorage<>>);
1104static_assert(CompleteBlockStorage<ParallelPackedCompleteBlockStorage<>>);
1105static_assert(SparseBlockStorage<PackedDiagonalBlockStorage<>>);
1106static_assert(DiagonalBlockStorage<PackedDiagonalBlockStorage<>>);
1107static_assert(SparseBlockStorage<AsyncSeparateSparseBlockStorage<>>);
1108static_assert(BlockTensorStorageFor<SeparateSparseBlockStorage<>, double, 2, 2>);
1109static_assert(BlockTensorStorageFor<SeparateSparseBlockStorage<>, double, 4, 0>);
1110static_assert(BlockTensorStorageFor<ParallelSeparateSparseBlockStorage<>, double, 2, 2>);
1111static_assert(BlockTensorStorageFor<PackedSparseBlockStorage<>, double, 2, 2>);
1112static_assert(BlockTensorStorageFor<ParallelPackedSparseBlockStorage<>, double, 2, 2>);
1113static_assert(BlockTensorStorageFor<PackedCompleteBlockStorage<>, double, 2, 2>);
1114static_assert(BlockTensorStorageFor<ParallelPackedCompleteBlockStorage<>, double, 2, 2>);
1115static_assert(BlockTensorStorageFor<PackedSparseBlockStorage<>, double, 4, 0>);
1116static_assert(BlockTensorStorageFor<PackedDiagonalBlockStorage<>, double, 2, 2>);
1117static_assert(BlockTensorStorageFor<PackedDiagonalBlockStorage<>, double, 0, 3>);
1118static_assert(LocalBlockStorageFor<PackedCompleteBlockStorage<>, double, 4, 0>);
1119static_assert(LocalBlockStorageFor<AsyncSeparateSparseBlockStorage<>, double, 4, 0>);
1120static_assert(ImmediateLocalBlockStorageFor<SeparateSparseBlockStorage<>, double, 2, 2>);
1121static_assert(ImmediateLocalBlockStorageFor<ParallelSeparateSparseBlockStorage<>, double, 2, 2>);
1122static_assert(ImmediateLocalBlockStorageFor<PackedSparseBlockStorage<>, double, 4, 0>);
1123static_assert(ImmediateLocalBlockStorageFor<ParallelPackedSparseBlockStorage<>, double, 4, 0>);
1124static_assert(ImmediateLocalBlockStorageFor<PackedCompleteBlockStorage<>, double, 4, 0>);
1125static_assert(ImmediateLocalBlockStorageFor<ParallelPackedCompleteBlockStorage<>, double, 4, 0>);
1126static_assert(ImmediateLocalBlockStorageFor<PackedDiagonalBlockStorage<>, double, 2, 2>);
1127static_assert(AsyncLocalBlockStorageFor<AsyncSeparateSparseBlockStorage<>, double, 2, 2>);
1128static_assert(AsyncLocalBlockStorageFor<AsyncSeparateSparseBlockStorage<>, double, 4, 0>);
The Async<T> container: coroutineāsafe asynchronous read/write.
Defines fixed-order logical block coordinates.
static constexpr bool immediately_writable
Whether mutable storage provides a writable data handle without acquisition.
Definition basic_tensor.hpp:141
static constexpr bool immediately_readable
Whether const storage provides a readable data handle without acquisition.
Definition basic_tensor.hpp:136
stdex::mdspan< element_type, extents_type, layout_policy, accessor_type > mdspan_type
Definition basic_tensor.hpp:130
stdex::mdspan< element_type const, extents_type, layout_policy, const_accessor_type > const_mdspan_type
Definition basic_tensor.hpp:131
Async<T> is a container for coroutine-safe asynchronous read/write.
Definition async/async.hpp:93
Local BlockTensor storage with one independently scheduled async value per block.
Definition block_tensor_storage.hpp:142
Storage policy instantiated for one block scalar and tensor order.
Definition block_tensor_storage.hpp:81
Storage policy for a BlockTensor container.
Definition block_tensor_storage.hpp:46
BlockTensor storage which contains every symmetry-legal block.
Definition block_tensor_storage.hpp:63
BlockTensor storage whose stored numerical blocks are generalized diagonals.
Definition block_tensor_storage.hpp:71
Full logical mdspec with a rank-one view of its generalized diagonal components.
Definition mdspan/concepts.hpp:465
Distributed BlockTensor storage refinement.
Definition block_tensor_storage.hpp:168
BlockTensor storage whose blocks reside within one local process.
Definition block_tensor_storage.hpp:118
Writable generalized-diagonal mdspec with writable rank-one components.
Definition mdspan/concepts.hpp:477
MutableTensorView with a specified static rank.
Definition tensor/concepts.hpp:166
TensorView whose readable mdspec has a specified static rank.
Definition tensor/concepts.hpp:149
BlockTensor storage whose stored key set may omit legal blocks.
Definition block_tensor_storage.hpp:58
cuda::ResourceLease< HandleSlot > handle
Definition cublas/execution.cpp:33
locale_t value
Definition data_table.cpp:49
Accessor support for compressed generalized diagonal tensors.
Synthetic mdspan layout for values generated from logical indices.
constexpr stdex::default_accessor< T const > const_accessor(stdex::default_accessor< T > const &accessor_policy)
Wrap a default_accessor<T> into a const_default_accessor<T>.
Definition mdspan/concepts.hpp:160
Mdspan-shaped metadata for storage whose data handle requires acquisition.
Concrete tensor-level views over owned mdspan or mdspec metadata.
Definition async/async.hpp:26
constexpr uninitialized_t uninitialized
Explicit allocation tag for overwrite outputs and scratch space.
Definition common/initialization.hpp:22
std::remove_cv_t< typename tensor_mdspec_t< T >::element_type > tensor_element_t
Scalar value type exposed by a tensor-level object.
Definition tensor/concepts.hpp:126
std::ptrdiff_t index_type
Definition types.hpp:19
mpreal remainder(mpreal const &a, mpreal const &b)
Nearest-even-quotient remainder; exact operands retain exact rational results.
Definition mpreal_functions.hpp:534
Tensor(InputTensor const &) -> Tensor< tensor_element_t< InputTensor >, tensor_mdspec_t< InputTensor >::rank(), HostStorage, detail::materialized_layout_t< void, tensor_mdspec_t< InputTensor > >, DefaultAccessorFactory >
Deduce a runtime-extents host tensor that materializes a tensor view.
std::remove_cvref_t< detail::normalized_const_mdspec_t< T > > tensor_mdspec_t
Normalized readable MdspecLike type exposed by a tensor-level object.
Definition tensor/concepts.hpp:123
constexpr auto make_diagonal_mdspan(Extents logical_extents, Components const &components)
Present rank-one strided components as a full generalized-diagonal mdspan.
Definition diagonal_accessor.hpp:295
StorageInitialization
Numerical initialization requested from a storage implementation.
Definition common/initialization.hpp:26
std::size_t span
Definition presentation.cpp:2017
Sparse storage with one independently scheduled dense Tensor per block.
Definition block_tensor_storage.hpp:1082
typename leaf_storage_policy::backend_selector_type backend_selector_type
Definition block_tensor_storage.hpp:1084
detail::AsyncSeparateSparseBlockStorageData< T, KeyCoordinateCount, DenseBlockOrder, leaf_storage_policy > storage_t
Definition block_tensor_storage.hpp:1091
static constexpr bool is_distributed
Definition block_tensor_storage.hpp:1087
LeafStorage leaf_storage_policy
Definition block_tensor_storage.hpp:1083
static constexpr auto backend_selector() noexcept -> backend_selector_type
Definition block_tensor_storage.hpp:1093
static constexpr bool stores_all_legal_blocks
Definition block_tensor_storage.hpp:1086
Complete storage packing every symmetry-legal dense block into one leaf buffer.
Definition block_tensor_storage.hpp:1010
typename leaf_storage_policy::backend_selector_type backend_selector_type
Definition block_tensor_storage.hpp:1012
LeafStorage leaf_storage_policy
Definition block_tensor_storage.hpp:1011
static constexpr bool stores_all_legal_blocks
Definition block_tensor_storage.hpp:1014
static constexpr auto backend_selector() noexcept -> backend_selector_type
Definition block_tensor_storage.hpp:1021
static constexpr bool is_distributed
Definition block_tensor_storage.hpp:1015
detail::PackedBlockStorageData< T, KeyCoordinateCount, DenseBlockOrder, leaf_storage_policy, BlockAlignment > storage_t
Definition block_tensor_storage.hpp:1019
Sparse BlockTensor storage packing each generalized diagonal block into one leaf buffer.
Definition block_tensor_storage.hpp:1058
LeafStorage leaf_storage_policy
Definition block_tensor_storage.hpp:1059
static constexpr bool stores_diagonal_blocks
Definition block_tensor_storage.hpp:1063
static constexpr bool stores_all_legal_blocks
Definition block_tensor_storage.hpp:1062
typename leaf_storage_policy::backend_selector_type backend_selector_type
Definition block_tensor_storage.hpp:1060
static constexpr auto backend_selector() noexcept -> backend_selector_type
Definition block_tensor_storage.hpp:1070
detail::PackedDiagonalBlockStorageData< T, KeyCoordinateCount, DenseBlockOrder, leaf_storage_policy > storage_t
Definition block_tensor_storage.hpp:1068
static constexpr bool is_distributed
Definition block_tensor_storage.hpp:1064
Sparse storage packing every stored dense block into one leaf buffer.
Definition block_tensor_storage.hpp:959
typename leaf_storage_policy::backend_selector_type backend_selector_type
Definition block_tensor_storage.hpp:961
static constexpr bool stores_all_legal_blocks
Definition block_tensor_storage.hpp:963
static constexpr bool is_distributed
Definition block_tensor_storage.hpp:964
detail::PackedBlockStorageData< T, KeyCoordinateCount, DenseBlockOrder, leaf_storage_policy, BlockAlignment > storage_t
Definition block_tensor_storage.hpp:968
LeafStorage leaf_storage_policy
Definition block_tensor_storage.hpp:960
static constexpr auto backend_selector() noexcept -> backend_selector_type
Definition block_tensor_storage.hpp:970
Complete packed storage whose disjoint blocks may be processed in a scheduler batch.
Definition block_tensor_storage.hpp:1035
typename leaf_storage_policy::backend_selector_type backend_selector_type
Definition block_tensor_storage.hpp:1037
detail::PackedBlockStorageData< T, KeyCoordinateCount, DenseBlockOrder, leaf_storage_policy, BlockAlignment > storage_t
Definition block_tensor_storage.hpp:1044
static constexpr bool is_distributed
Definition block_tensor_storage.hpp:1040
static constexpr bool stores_all_legal_blocks
Definition block_tensor_storage.hpp:1039
LeafStorage leaf_storage_policy
Definition block_tensor_storage.hpp:1036
static constexpr auto backend_selector() noexcept -> backend_selector_type
Definition block_tensor_storage.hpp:1046
Packed sparse storage whose disjoint dense blocks may be processed in a scheduler batch.
Definition block_tensor_storage.hpp:985
static constexpr auto backend_selector() noexcept -> backend_selector_type
Definition block_tensor_storage.hpp:996
static constexpr bool is_distributed
Definition block_tensor_storage.hpp:990
detail::PackedBlockStorageData< T, KeyCoordinateCount, DenseBlockOrder, leaf_storage_policy, BlockAlignment > storage_t
Definition block_tensor_storage.hpp:994
static constexpr bool stores_all_legal_blocks
Definition block_tensor_storage.hpp:989
typename leaf_storage_policy::backend_selector_type backend_selector_type
Definition block_tensor_storage.hpp:987
LeafStorage leaf_storage_policy
Definition block_tensor_storage.hpp:986
Sparse storage whose separate dense blocks may be processed in a scheduler batch.
Definition block_tensor_storage.hpp:936
detail::SeparateSparseBlockStorageData< T, KeyCoordinateCount, DenseBlockOrder, leaf_storage_policy > storage_t
Definition block_tensor_storage.hpp:945
LeafStorage leaf_storage_policy
Definition block_tensor_storage.hpp:937
static constexpr bool stores_all_legal_blocks
Definition block_tensor_storage.hpp:940
static constexpr bool is_distributed
Definition block_tensor_storage.hpp:941
static constexpr auto backend_selector() noexcept -> backend_selector_type
Definition block_tensor_storage.hpp:947
typename leaf_storage_policy::backend_selector_type backend_selector_type
Definition block_tensor_storage.hpp:938
Execute independent block-level work through the active scheduler's synchronous batch interface.
Definition block_tensor_storage.hpp:41
Sparse storage with one independently owning dense Tensor per stored block.
Definition block_tensor_storage.hpp:913
static constexpr bool is_distributed
Definition block_tensor_storage.hpp:918
LeafStorage leaf_storage_policy
Definition block_tensor_storage.hpp:914
static constexpr bool stores_all_legal_blocks
Definition block_tensor_storage.hpp:917
detail::SeparateSparseBlockStorageData< T, KeyCoordinateCount, DenseBlockOrder, leaf_storage_policy > storage_t
Definition block_tensor_storage.hpp:922
typename leaf_storage_policy::backend_selector_type backend_selector_type
Definition block_tensor_storage.hpp:915
static constexpr auto backend_selector() noexcept -> backend_selector_type
Definition block_tensor_storage.hpp:924
Execute block-level work serially on the calling thread.
Definition block_tensor_storage.hpp:37
General-purpose owning tensors with runtime extents.