25namespace uni20::detail
28template <std::size_t Offset,
class Tuple, std::size_t... I>
29auto tuple_slice_impl(Tuple
const& tuple, std::index_sequence<I...>)
31 return std::tuple{std::get<Offset + I>(tuple)...};
34template <std::
size_t Offset, std::
size_t Count,
class Tuple>
auto tuple_slice(Tuple
const& tuple)
36 return tuple_slice_impl<Offset>(tuple, std::make_index_sequence<Count>{});
39template <
class Tuple>
auto domain_from_tuple(Tuple&& tuple)
41 return std::apply([](
auto&&... spaces) {
return Domain{std::forward<decltype(spaces)>(spaces)...}; },
42 std::forward<Tuple>(tuple));
45template <
class Tuple>
auto codomain_from_tuple(Tuple&& tuple)
47 return std::apply([](
auto&&... spaces) {
return Codomain{std::forward<decltype(spaces)>(spaces)...}; },
48 std::forward<Tuple>(tuple));
51template <
class Tensor, std::size_t Axis,
52 bool DomainAxis = Axis<std::remove_cvref_t<Tensor>::domain_type::size()>
struct TensorAxisSpace;
54template <
class Tensor, std::
size_t Axis>
struct TensorAxisSpace<
Tensor, Axis, true>
56 using tensor_type = std::remove_cvref_t<Tensor>;
57 using type =
typename tensor_type::domain_type::template space_type<Axis>;
60template <
class Tensor, std::
size_t Axis>
struct TensorAxisSpace<
Tensor, Axis, false>
62 using tensor_type = std::remove_cvref_t<Tensor>;
63 static constexpr std::size_t codomain_axis = Axis - tensor_type::domain_type::size();
64 using type =
typename tensor_type::codomain_type::template space_type<codomain_axis>;
67template <
class Tensor, std::
size_t Axis>
using tensor_axis_space_t =
typename TensorAxisSpace<Tensor, Axis>::type;
69template <std::
size_t Size>
70consteval auto is_valid_axis_permutation(std::array<std::size_t, Size>
const& permutation) ->
bool
72 std::array<bool, Size> seen{};
73 for (std::size_t
const axis : permutation)
75 if (axis >= Size || seen[axis])
return false;
81template <std::
size_t Size>
consteval auto make_identity_axis_permutation()
83 std::array<std::size_t, Size> permutation{};
84 for (std::size_t axis = 0; axis < Size; ++axis)
85 permutation[axis] = axis;
89template <
class Tensor, std::size_t... Axis>
consteval auto key_axis_flags_impl(std::index_sequence<Axis...>)
91 return std::array<bool,
sizeof...(Axis)>{
92 BlockTensorSpaceTraits<tensor_axis_space_t<Tensor, Axis>>::has_block_coordinate...};
95template <
class Tensor>
consteval auto key_axis_flags()
97 return key_axis_flags_impl<Tensor>(std::make_index_sequence<std::remove_cvref_t<Tensor>::order()>{});
100template <
class Tensor, std::size_t... Axis>
consteval auto dense_axis_flags_impl(std::index_sequence<Axis...>)
102 return std::array<bool,
sizeof...(Axis)>{
103 BlockTensorSpaceTraits<tensor_axis_space_t<Tensor, Axis>>::has_dense_axis...};
106template <
class Tensor>
consteval auto dense_axis_flags()
108 return dense_axis_flags_impl<Tensor>(std::make_index_sequence<std::remove_cvref_t<Tensor>::order()>{});
111template <
class Tensor, auto FactorPermutation,
bool DenseAxes>
consteval auto make_filtered_axis_permutation()
113 using tensor_type = std::remove_cvref_t<Tensor>;
114 constexpr std::size_t order = tensor_type::order();
115 constexpr std::size_t filtered_count =
116 DenseAxes ? tensor_type::dense_block_order() : tensor_type::key_coordinate_count();
117 static_assert(std::tuple_size_v<
decltype(FactorPermutation)> == order);
118 static_assert(is_valid_axis_permutation(FactorPermutation));
120 constexpr auto flags = [] {
121 if constexpr (DenseAxes)
122 return dense_axis_flags<tensor_type>();
124 return key_axis_flags<tensor_type>();
127 std::array<std::size_t, order> source_filtered_axis{};
128 std::size_t source_count = 0;
129 for (std::size_t axis = 0; axis < order; ++axis)
131 if (flags[axis]) source_filtered_axis[axis] = source_count++;
134 std::array<std::size_t, filtered_count> permutation{};
135 std::size_t output = 0;
136 for (std::size_t factor = 0; factor < order; ++factor)
138 std::size_t
const source_factor = FactorPermutation[factor];
139 if (flags[source_factor]) permutation[output++] = source_filtered_axis[source_factor];
141 if (output != filtered_count)
throw "invalid filtered BlockTensor axis permutation";
145template <std::
size_t CoordinateCount>
146auto permute_key(BlockKey<CoordinateCount>
const& source, std::array<std::size_t, CoordinateCount>
const& permutation)
147 -> BlockKey<CoordinateCount>
149 std::array<std::size_t, CoordinateCount> coordinates{};
150 for (std::size_t axis = 0; axis < CoordinateCount; ++axis)
152 coordinates[axis] = source.coordinate(permutation[axis]);
154 return BlockKey<CoordinateCount>{coordinates};
157template <
class Block,
bool Immediate = MdspanLike<std::remove_cvref_t<Block>>>
struct StridedBlock;
159template <
class Block>
struct StridedBlock<Block, true>
161 using source_type = std::remove_cvref_t<Block>;
162 using extents_type = stdex::dextents<
typename source_type::index_type, source_type::rank()>;
163 using type = stdex::mdspan<
typename source_type::element_type, extents_type, stdex::layout_stride,
164 typename source_type::accessor_type>;
167template <
class Block>
struct StridedBlock<Block, false>
169 using source_type = std::remove_cvref_t<Block>;
170 static_assert(MdspecLike<source_type>);
171 using extents_type = stdex::dextents<
typename source_type::index_type, source_type::rank()>;
172 using type = mdspec<
typename source_type::element_type, extents_type, stdex::layout_stride,
173 typename source_type::accessor_type,
typename source_type::data_descriptor_type>;
176template <
class Block>
using strided_block_t =
typename StridedBlock<Block>::type;
178template <MdspecLike Block, std::
size_t DenseBlockOrder>
179 requires(DenseBlockOrder == 0 || StridedMdspecLike<Block>)
180auto permute_block_mdspec(Block block, std::array<std::size_t, DenseBlockOrder>
const& permutation)
181 -> strided_block_t<Block>
183 using result_type = strided_block_t<Block>;
184 using extents_type =
typename result_type::extents_type;
185 using mapping_type =
typename result_type::mapping_type;
186 using index_type =
typename extents_type::index_type;
188 std::array<std::size_t, DenseBlockOrder> extents{};
189 std::array<index_type, DenseBlockOrder>
strides{};
190 if constexpr (DenseBlockOrder > 0)
192 for (std::size_t axis = 0; axis < DenseBlockOrder; ++axis)
194 extents[axis] =
static_cast<std::size_t
>(block.extent(permutation[axis]));
198 auto const result_extents = make_extents<extents_type>(extents);
199 if constexpr (MdspanLike<Block>)
201 return result_type(block.data_handle(), mapping_type(result_extents,
strides), block.accessor());
205 return result_type(std::move(block.data_descriptor()), mapping_type(result_extents,
strides), block.accessor());
209template <TensorView Block, std::
size_t DenseBlockOrder>
210 requires(DenseBlockOrder == tensor_mdspec_t<Block>::rank() && (DenseBlockOrder == 0 || StridedTensorView<Block>))
211auto permute_block(Block block,
std::array<
std::
size_t, DenseBlockOrder> const& permutation)
213 auto mutable_mdspec = permute_block_mdspec(
mdspec_of(block), permutation);
214 auto const_mdspec = permute_block_mdspec(
mdspec_of(std::as_const(block)), permutation);
215 using mutable_mdspec_type =
decltype(mutable_mdspec);
216 using const_mdspec_type =
decltype(const_mdspec);
217 using storage_policy = tensor_storage_policy_t<Block>;
218 return MdspecTensorView<mutable_mdspec_type, const_mdspec_type, storage_policy>{std::move(mutable_mdspec),
219 std::move(const_mdspec)};
222template <TensorView Block>
auto make_read_only_block_view(Block
const& block)
225 using mdspec_type = std::remove_cvref_t<
decltype(const_mdspec)>;
226 using storage_policy = tensor_storage_policy_t<Block>;
227 return MdspecTensorView<mdspec_type, mdspec_type, storage_policy>{const_mdspec, const_mdspec};
232template <auto Permutation, TensorView Block>
auto map_block(Block block)
234 if constexpr (Permutation == make_identity_axis_permutation<std::tuple_size_v<
decltype(Permutation)>>())
237 return permute_block(std::move(block), Permutation);
240template <
class SourceTensor,
class =
void>
class BlockTensorAllocationContextBinding {
242 explicit BlockTensorAllocationContextBinding(SourceTensor&)
noexcept {}
245template <
class SourceTensor>
246class BlockTensorAllocationContextBinding<
247 SourceTensor,
std::void_t<decltype(std::declval<SourceTensor const&>().allocation_context())>> {
249 using context_type = std::remove_reference_t<decltype(std::declval<SourceTensor const&>().allocation_context())>;
251 explicit BlockTensorAllocationContextBinding(SourceTensor& source) noexcept
252 : context_(std::addressof(source.allocation_context()))
255 [[nodiscard]]
auto get() const noexcept -> context_type& {
return *context_; }
258 context_type* context_;
269template <
class SourceTensor,
class DomainType,
class CodomainType, auto KeyPermutation, auto DensePermutation>
270class BlockTensorMappedView {
272 using source_type = SourceTensor;
273 using source_tensor_type = std::remove_cvref_t<SourceTensor>;
274 using borrowed_block_tensor_view_tag = void;
275 using element_type =
typename source_tensor_type::element_type;
276 using value_type =
typename source_tensor_type::value_type;
277 using storage_policy =
typename source_tensor_type::storage_policy;
278 using storage_type =
typename source_tensor_type::storage_type;
279 using backend_selector_type =
typename source_tensor_type::backend_selector_type;
280 using key_type =
typename source_tensor_type::key_type;
281 using domain_type = DomainType;
282 using codomain_type = CodomainType;
283 using source_mutable_access_block_type =
284 decltype(std::declval<SourceTensor&>().block_by_ordinal(std::size_t{}));
285 using mutable_block_type =
decltype(map_block<DensePermutation>(std::declval<source_mutable_access_block_type>()));
286 using const_block_type =
decltype(make_read_only_block_view(std::declval<mutable_block_type const&>()));
287 using allocation_context_binding_type = BlockTensorAllocationContextBinding<SourceTensor>;
289 static constexpr std::size_t static_order = source_tensor_type::order();
290 static constexpr std::size_t static_key_coordinate_count = source_tensor_type::key_coordinate_count();
291 static constexpr std::size_t static_dense_block_order = source_tensor_type::dense_block_order();
294 static constexpr bool source_blocks_writable =
295 !std::is_const_v<typename std::remove_cvref_t<source_mutable_access_block_type>::element_type>;
297 static_assert(IsDomain<domain_type>::value);
298 static_assert(IsCodomain<codomain_type>::value);
299 static_assert(domain_type::size() + codomain_type::size() == static_order);
300 static_assert(BoundaryBlockShape<domain_type>::key_coordinate_count +
301 BoundaryBlockShape<codomain_type>::key_coordinate_count ==
302 static_key_coordinate_count);
303 static_assert(BoundaryBlockShape<domain_type>::dense_block_order +
304 BoundaryBlockShape<codomain_type>::dense_block_order ==
305 static_dense_block_order);
306 static_assert(std::tuple_size_v<
decltype(KeyPermutation)> == static_key_coordinate_count);
307 static_assert(std::tuple_size_v<
decltype(DensePermutation)> == static_dense_block_order);
308 static_assert(is_valid_axis_permutation(KeyPermutation));
309 static_assert(is_valid_axis_permutation(DensePermutation));
316 explicit BlockTensorMappedView(SourceTensor& source, domain_type domain, codomain_type codomain)
317 : symmetry_(source.symmetry()), domain_(
std::move(domain)), codomain_(
std::move(codomain)),
318 allocation_context_(source)
320 this->build_key_index(source);
324 BlockTensorMappedView(BlockTensorMappedView
const&) =
default;
327 BlockTensorMappedView(BlockTensorMappedView&&) =
default;
330 auto operator=(BlockTensorMappedView
const&) -> BlockTensorMappedView& =
delete;
333 auto operator=(BlockTensorMappedView&&) -> BlockTensorMappedView& =
delete;
336 auto symmetry() const -> Symmetry {
return symmetry_; }
339 auto domain() const -> domain_type const& {
return domain_; }
342 auto codomain() const -> codomain_type const& {
return codomain_; }
345 static constexpr auto order() noexcept ->
std::
size_t {
return static_order; }
348 static constexpr auto key_coordinate_count() noexcept ->
std::
size_t {
return static_key_coordinate_count; }
351 static constexpr auto dense_block_order() noexcept ->
std::
size_t {
return static_dense_block_order; }
354 auto stored_block_count() const noexcept ->
std::
size_t {
return keys_.size(); }
357 auto legal_block_count() const ->
std::
size_t
359 std::size_t
count = 0;
360 this->for_each_possible_key([&](key_type
const& key) {
361 if (this->is_legal(key)) ++count;
367 auto has_all_legal_blocks() const ->
bool {
return this->stored_block_count() == this->legal_block_count(); }
370 auto is_legal(key_type
const& key)
const ->
bool
372 return is_legal_block_key(this->symmetry(), domain_, codomain_, key);
376 auto contains(key_type
const& key)
const ->
bool {
return this->ordinal(key).has_value(); }
379 auto find_block(key_type
const& key) -> std::optional<mutable_block_type>
380 requires source_blocks_writable
382 auto const found = this->ordinal(key);
383 if (!found)
return std::nullopt;
384 return blocks_[*found];
388 auto find_block(key_type
const& key)
const -> std::optional<const_block_type>
390 auto const found = this->ordinal(key);
391 if (!found)
return std::nullopt;
392 return make_read_only_block_view(std::as_const(blocks_[*found]));
397 auto block(key_type
const& key) -> mutable_block_type
398 requires source_blocks_writable
400 auto const found = this->find_block(key);
401 if (!found)
throw std::out_of_range(
"mapped BlockTensor block key is not stored");
407 auto block(key_type
const& key)
const -> const_block_type
409 auto const found = this->find_block(key);
410 if (!found)
throw std::out_of_range(
"mapped BlockTensor block key is not stored");
418 auto block_by_ordinal(std::size_t ordinal) -> mutable_block_type
419 requires source_blocks_writable
421 if (ordinal >= keys_.size())
throw std::out_of_range(
"mapped BlockTensor block ordinal is out of range");
422 return blocks_[ordinal];
429 auto block_by_ordinal(std::size_t ordinal)
const -> const_block_type
431 if (ordinal >= keys_.size())
throw std::out_of_range(
"mapped BlockTensor block ordinal is out of range");
432 return make_read_only_block_view(std::as_const(blocks_[ordinal]));
436 auto stored_keys() const noexcept ->
std::
span<key_type const> {
return keys_; }
439 static constexpr auto backend_selector() noexcept -> backend_selector_type
441 return source_tensor_type::backend_selector();
445 decltype(
auto) allocation_context()
const noexcept
446 requires requires(allocation_context_binding_type
const& binding) { binding.get(); }
448 return allocation_context_.get();
455 std::size_t source_ordinal;
458 void build_key_index(SourceTensor& source)
460 std::vector<KeyBinding> bindings;
461 bindings.reserve(source.stored_block_count());
462 for (std::size_t ordinal = 0; ordinal < source.stored_block_count(); ++ordinal)
464 bindings.push_back({permute_key(source.stored_keys()[ordinal], KeyPermutation), ordinal});
466 std::ranges::sort(bindings, {}, &KeyBinding::key);
468 keys_.reserve(bindings.size());
469 blocks_.reserve(bindings.size());
470 for (
auto const& binding : bindings)
472 keys_.push_back(binding.key);
473 auto source_block = source.block_by_ordinal(binding.source_ordinal);
474 blocks_.push_back(map_block<DensePermutation>(std::move(source_block)));
478 template <
class Function>
void for_each_possible_key(Function&& function)
const
480 auto const sizes = boundary_factor_sizes<static_key_coordinate_count>(domain_, codomain_);
481 if (std::ranges::find(sizes, std::size_t{0}) != sizes.end())
return;
483 if constexpr (static_key_coordinate_count == 0)
485 function(key_type{});
489 std::array<std::size_t, static_key_coordinate_count> coordinates{};
492 function(key_type{coordinates});
493 std::size_t axis = static_key_coordinate_count;
497 if (++coordinates[axis] < sizes[axis])
break;
498 coordinates[axis] = 0;
500 if (axis == 0 && coordinates[0] == 0)
return;
505 auto ordinal(key_type
const& key)
const -> std::optional<std::size_t>
507 auto const found = std::ranges::lower_bound(keys_, key);
508 if (found == keys_.end() || *found != key)
return std::nullopt;
509 return static_cast<std::size_t
>(found - keys_.begin());
514 codomain_type codomain_;
515 [[no_unique_address]] allocation_context_binding_type allocation_context_;
516 std::vector<key_type> keys_;
517 std::vector<mutable_block_type> blocks_;
Defines the first bosonic abelian BlockTensor container.
Domain
MKL computation domains accepted by domain-specific thread controls.
Definition backend_mkl.hpp:35
auto strides(S const &s)
Retrieve the strides associated with a strided mdspec-like type.
Definition mdspan/concepts.hpp:558
Mdspan-shaped metadata for storage whose data handle requires acquisition.
typename optional_traits< T >::value_type value_type
Definition data_table.hpp:42
Codomain(Spaces &&...) -> Codomain< std::remove_cvref_t< Spaces >... >
Deduce a codomain's concrete value types.
constexpr decltype(auto) mdspec_of(Tensor &tensor) noexcept(noexcept(tensor.mdspec()))
Return a tensor's immediate or descriptor-backed multidimensional metadata.
Definition tensor/concepts.hpp:50
std::ptrdiff_t index_type
Definition types.hpp:19
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::size_t span
Definition presentation.cpp:2017