36template <
class Tensor, std::
size_t Index>
37using environment_domain_space_t =
typename block_tensor_domain_t<Tensor>::template space_type<Index>;
39template <
class Tensor, std::
size_t Index>
40using environment_codomain_space_t =
typename block_tensor_codomain_t<Tensor>::template space_type<Index>;
43concept EnvironmentBondSpace =
44 BlockTensorSpace<Space> && BlockTensorSpaceTraits<std::remove_cvref_t<Space>>::has_block_coordinate &&
45 BlockTensorSpaceTraits<std::remove_cvref_t<Space>>::has_dense_axis;
48concept EnvironmentDiscreteSpace =
49 BlockTensorSpace<Space> && BlockTensorSpaceTraits<std::remove_cvref_t<Space>>::has_block_coordinate &&
50 !BlockTensorSpaceTraits<std::remove_cvref_t<Space>>::has_dense_axis;
52template <
class Tensor>
53concept ImmediateHostBlockTensorView =
54 ImmediateBlockTensorView<Tensor> &&
55 HostAccessibleMdspan<immediate_tensor_mdspan_t<block_tensor_const_block_t<Tensor>>>;
57template <
class Storage,
class Value>
58using environment_storage_block_t =
typename Storage::template storage_t<Value, 3, 2>::mutable_block_type;
60template <
class Storage,
class Value>
61concept EnvironmentStorageFor =
62 SparseBlockStorage<Storage> && !DiagonalBlockStorage<Storage> && LocalBlockStorageFor<Storage, Value, 3, 2> &&
63 !AsyncLocalBlockStorageFor<Storage, Value, 3, 2>;
65template <
class Result>
66auto make_identity_environment_keys(BlockSpace
const& bond,
67 std::size_t auxiliary_index) -> std::vector<typename Result::key_type>
69 std::vector<typename Result::key_type> keys;
70 keys.reserve(bond.size());
71 for (std::size_t sector = 0; sector < bond.size(); ++sector)
72 keys.push_back(
typename Result::key_type{{sector, auxiliary_index, sector}});
76template <
class Result>
void initialize_identity_environment(Result& result)
78 using value_type =
typename Result::value_type;
79 for (std::size_t ordinal = 0; ordinal < result.stored_block_count(); ++ordinal)
81 auto block = result.block_by_ordinal(ordinal);
82 ColumnMajorTensor<value_type, 2> identity(
uninitialized, block.extent(0), block.extent(1));
83 auto identity_span = identity.mdspan();
84 for (
index_type column = 0; column < identity.extent(1); ++column)
93template <
class Tensor>
94concept EnvironmentMatrixView =
95 BlockTensorView<Tensor> && (block_tensor_domain_t<Tensor>::size() == 2) &&
96 (block_tensor_codomain_t<Tensor>::size() == 1) && (block_tensor_type_t<Tensor>::key_coordinate_count() == 3) &&
97 (block_tensor_type_t<Tensor>::dense_block_order() == 2) &&
98 EnvironmentBondSpace<environment_domain_space_t<Tensor, 0>> &&
99 EnvironmentDiscreteSpace<environment_domain_space_t<Tensor, 1>> &&
100 EnvironmentBondSpace<environment_codomain_space_t<Tensor, 0>>;
102template <
class Tensor>
103concept EnvironmentMpoView =
104 ImmediateHostBlockTensorView<Tensor> && (block_tensor_domain_t<Tensor>::size() == 2) &&
105 (block_tensor_codomain_t<Tensor>::size() == 2) && (block_tensor_type_t<Tensor>::key_coordinate_count() == 4) &&
106 (block_tensor_type_t<Tensor>::dense_block_order() == 0) &&
107 EnvironmentDiscreteSpace<environment_domain_space_t<Tensor, 0>> &&
108 EnvironmentDiscreteSpace<environment_domain_space_t<Tensor, 1>> &&
109 EnvironmentDiscreteSpace<environment_codomain_space_t<Tensor, 0>> &&
110 EnvironmentDiscreteSpace<environment_codomain_space_t<Tensor, 1>>;
112template <
class Environment,
class BraSite,
class Mpo,
class KetSite>
113concept CompatibleEnvironmentUpdateScalars =
114 std::same_as<block_tensor_value_t<Environment>, block_tensor_value_t<BraSite>> &&
115 std::same_as<block_tensor_value_t<Environment>, block_tensor_value_t<Mpo>> &&
116 std::same_as<block_tensor_value_t<Environment>, block_tensor_value_t<KetSite>>;
118template <
class Environment,
class BraSite,
class Mpo,
class KetSite>
119concept CompatibleLeftEnvironmentUpdateSpaces =
120 std::same_as<environment_domain_space_t<Environment, 0>, environment_domain_space_t<BraSite, 0>> &&
121 std::same_as<environment_domain_space_t<Environment, 1>, environment_domain_space_t<Mpo, 0>> &&
122 std::same_as<environment_codomain_space_t<Environment, 0>, environment_domain_space_t<KetSite, 0>> &&
123 std::same_as<environment_domain_space_t<BraSite, 1>, environment_codomain_space_t<Mpo, 1>> &&
124 std::same_as<environment_domain_space_t<KetSite, 1>, environment_domain_space_t<Mpo, 1>>;
126template <
class Environment,
class BraSite,
class Mpo,
class KetSite>
127concept CompatibleRightEnvironmentUpdateSpaces =
128 std::same_as<environment_domain_space_t<Environment, 0>, environment_codomain_space_t<BraSite, 0>> &&
129 std::same_as<environment_domain_space_t<Environment, 1>, environment_codomain_space_t<Mpo, 0>> &&
130 std::same_as<environment_codomain_space_t<Environment, 0>, environment_codomain_space_t<KetSite, 0>> &&
131 std::same_as<environment_domain_space_t<BraSite, 1>, environment_codomain_space_t<Mpo, 1>> &&
132 std::same_as<environment_domain_space_t<KetSite, 1>, environment_domain_space_t<Mpo, 1>>;
134enum class EnvironmentUpdateDirection
140struct EnvironmentUpdateTerm
142 BlockKey<3> output_key;
143 std::size_t output_ordinal = 0;
144 std::size_t environment_ordinal;
145 std::size_t bra_site_ordinal;
146 std::size_t mpo_ordinal;
147 std::size_t ket_site_ordinal;
150struct EnvironmentUpdatePlan
152 std::vector<BlockKey<3>> output_keys;
153 std::vector<EnvironmentUpdateTerm> terms;
154 std::vector<std::size_t> group_offsets;
157template <EnvironmentUpdateDirection Direction, EnvironmentMatrixView Environment, EnvironmentMatrixView BraSite,
158 EnvironmentMpoView Mpo, EnvironmentMatrixView KetSite>
159auto make_environment_update_plan(Environment
const&
environment, BraSite
const& bra_site, Mpo
const& mpo,
160 KetSite
const& ket_site) -> EnvironmentUpdatePlan
162 EnvironmentUpdatePlan result;
163 for (std::size_t environment_ordinal = 0; environment_ordinal <
environment.stored_block_count();
164 ++environment_ordinal)
166 auto const& environment_key =
environment.stored_keys()[environment_ordinal];
167 for (std::size_t mpo_ordinal = 0; mpo_ordinal < mpo.stored_block_count(); ++mpo_ordinal)
169 auto const& mpo_key = mpo.stored_keys()[mpo_ordinal];
170 constexpr std::size_t mpo_auxiliary = Direction == EnvironmentUpdateDirection::left ? 0 : 2;
171 if (environment_key.coordinate(1) != mpo_key.coordinate(mpo_auxiliary))
continue;
173 for (std::size_t bra_ordinal = 0; bra_ordinal < bra_site.stored_block_count(); ++bra_ordinal)
175 auto const& bra_key = bra_site.stored_keys()[bra_ordinal];
176 constexpr std::size_t site_bond = Direction == EnvironmentUpdateDirection::left ? 0 : 2;
177 if (environment_key.coordinate(0) != bra_key.coordinate(site_bond) ||
178 mpo_key.coordinate(3) != bra_key.coordinate(1))
181 for (std::size_t ket_ordinal = 0; ket_ordinal < ket_site.stored_block_count(); ++ket_ordinal)
183 auto const& ket_key = ket_site.stored_keys()[ket_ordinal];
184 if (environment_key.coordinate(2) != ket_key.coordinate(site_bond) ||
185 mpo_key.coordinate(1) != ket_key.coordinate(1))
188 BlockKey<3>
const output_key =
189 Direction == EnvironmentUpdateDirection::left
190 ? BlockKey<3>{{bra_key.coordinate(2), mpo_key.coordinate(2), ket_key.coordinate(2)}}
191 : BlockKey<3>{{bra_key.coordinate(0), mpo_key.coordinate(0), ket_key.coordinate(0)}};
192 result.terms.push_back({.output_key = output_key,
193 .environment_ordinal = environment_ordinal,
194 .bra_site_ordinal = bra_ordinal,
195 .mpo_ordinal = mpo_ordinal,
196 .ket_site_ordinal = ket_ordinal});
202 std::ranges::stable_sort(result.terms, {}, &EnvironmentUpdateTerm::output_key);
203 for (
auto& term : result.terms)
205 if (result.output_keys.empty() || result.output_keys.back() != term.output_key)
206 result.output_keys.push_back(term.output_key);
207 term.output_ordinal = result.output_keys.size() - 1;
209 result.group_offsets.assign(result.output_keys.size() + 1, 0);
210 for (
auto const& term : result.terms)
211 ++result.group_offsets[term.output_ordinal + 1];
212 std::partial_sum(result.group_offsets.begin(), result.group_offsets.end(), result.group_offsets.begin());
216template <
class Function>
void execute_environment_groups(SerialBlockExecution, std::size_t size, Function&& function)
218 for (std::size_t index = 0; index <
size; ++index)
222template <
class Function>
223void execute_environment_groups(SchedulerBatchBlockExecution, std::size_t size, Function&& function)
228template <
class LeafStorage,
class Scalar, TensorView OutputBlock>
229[[nodiscard]]
auto make_environment_intermediate(OutputBlock
const& output_block, std::size_t rows, std::size_t columns)
231 using intermediate_type = Tensor<Scalar, 2, LeafStorage, ColumnMajor>;
232 auto descriptor =
mdspec_of(output_block);
233 if constexpr (
requires {
234 descriptor.data_descriptor().buffer().resources();
235 intermediate_type(descriptor.data_descriptor().buffer().resources(), rows, columns);
238 return intermediate_type(descriptor.data_descriptor().buffer().resources(), rows, columns);
242 return intermediate_type(rows, columns);
246template <EnvironmentUpdateDirection Direction, MutableBlockTensorView Output, EnvironmentMatrixView Environment,
247 EnvironmentMatrixView BraSite, EnvironmentMpoView Mpo, EnvironmentMatrixView KetSite>
248void execute_environment_update(Output& output, EnvironmentUpdatePlan
const& plan, Environment
const&
environment,
249 BraSite
const& bra_site, Mpo
const& mpo, KetSite
const& ket_site)
251 using scalar_type = block_tensor_value_t<Output>;
252 using leaf_storage_policy =
typename block_tensor_type_t<Output>::storage_policy::leaf_storage_policy;
254 execute_environment_groups(
255 typename std::remove_cvref_t<Output>::storage_policy::block_execution_policy{}, output.stored_block_count(),
256 [&](std::size_t output_ordinal) {
257 auto output_block = output.block_by_ordinal(output_ordinal);
258 std::size_t
const first = plan.group_offsets[output_ordinal];
259 std::size_t
const last = plan.group_offsets[output_ordinal + 1];
260 for (std::size_t index = first; index < last; ++index)
262 auto const& term = plan.terms[index];
263 auto const environment_block =
environment.block_by_ordinal(term.environment_ordinal);
264 auto const bra_block = bra_site.block_by_ordinal(term.bra_site_ordinal);
265 auto const mpo_block = mpo.block_by_ordinal(term.mpo_ordinal);
266 auto const ket_block = ket_site.block_by_ordinal(term.ket_site_ordinal);
268 scalar_type
const coefficient = mpo_block[];
269 scalar_type
const beta = index == first ? scalar_type{} : scalar_type{1};
271 if constexpr (Direction == EnvironmentUpdateDirection::left)
273 constexpr std::array<std::pair<std::size_t, std::size_t>, 1> first_axes{std::pair{1U, 0U}};
274 constexpr std::array<std::pair<std::size_t, std::size_t>, 1> second_axes{std::pair{0U, 0U}};
275 auto intermediate = make_environment_intermediate<leaf_storage_policy, scalar_type>(
276 output_block,
static_cast<std::size_t
>(environment_block.extent(0)),
277 static_cast<std::size_t
>(ket_block.extent(1)));
278 linalg::contract(intermediate, scalar_type{1}, environment_block, ket_block, first_axes, scalar_type{});
283 constexpr std::array<std::pair<std::size_t, std::size_t>, 1> first_axes{std::pair{1U, 0U}};
284 constexpr std::array<std::pair<std::size_t, std::size_t>, 1> second_axes{std::pair{1U, 1U}};
285 auto intermediate = make_environment_intermediate<leaf_storage_policy, scalar_type>(
286 output_block,
static_cast<std::size_t
>(bra_block.extent(0)),
287 static_cast<std::size_t
>(environment_block.extent(1)));
288 linalg::contract(intermediate, scalar_type{1}, conjugated_bra, environment_block, first_axes,
296template <EnvironmentUpdateDirection Direction, EnvironmentMatrixView Environment, EnvironmentMatrixView BraSite,
297 EnvironmentMpoView Mpo, EnvironmentMatrixView KetSite>
298void validate_environment_update(Environment
const&
environment, BraSite
const& bra_site, Mpo
const& mpo,
299 KetSite
const& ket_site)
303 throw std::invalid_argument(
"MPO environment update operands require one symmetry");
305 bool compatible =
false;
306 if constexpr (Direction == EnvironmentUpdateDirection::left)
308 compatible =
environment.domain().template space<0>() == bra_site.domain().template space<0>() &&
309 environment.domain().template space<1>() == mpo.domain().template space<0>() &&
310 environment.codomain().template space<0>() == ket_site.domain().template space<0>() &&
311 bra_site.domain().template space<1>() == mpo.codomain().template space<1>() &&
312 ket_site.domain().template space<1>() == mpo.domain().template space<1>();
316 compatible =
environment.domain().template space<0>() == bra_site.codomain().template space<0>() &&
317 environment.domain().template space<1>() == mpo.codomain().template space<0>() &&
318 environment.codomain().template space<0>() == ket_site.codomain().template space<0>() &&
319 bra_site.domain().template space<1>() == mpo.codomain().template space<1>() &&
320 ket_site.domain().template space<1>() == mpo.domain().template space<1>();
323 throw std::invalid_argument(
"MPO environment update has incompatible environment, site, or MPO spaces");
338template <
typename Value, SparseBlockStorage Storage = SeparateSparseBlockStorage<>>
339 requires Scalar<Value> && detail::EnvironmentStorageFor<Storage, Value>
341 std::size_t auxiliary_index)
344 if (bond.symmetry() != auxiliary.symmetry())
345 throw std::invalid_argument(
"identity MPO environment spaces require one symmetry");
346 if (auxiliary_index >= auxiliary.size())
347 throw std::invalid_argument(
"identity MPO environment auxiliary index is out of range");
349 throw std::invalid_argument(
"identity MPO environment requires an identity-charge auxiliary state");
352 auto keys = detail::make_identity_environment_keys<result_type>(bond, auxiliary_index);
354 detail::initialize_identity_environment(result);
367template <
typename Value, SparseBlockStorage Storage = SeparateSparseBlockStorage<>,
class Context>
368 requires Scalar<Value> && detail::EnvironmentStorageFor<Storage, Value> &&
371 std::vector<typename MpoEnvironment<Value, BlockSpace, LocalSpace, BlockSpace, Storage>::key_type>
374 MpoEnvironment<Value, BlockSpace, LocalSpace, BlockSpace, Storage>(
375 uninitialized, bond.symmetry(),
Domain{bond, auxiliary},
Codomain{bond}, std::move(keys), context);
381 if (bond.symmetry() != auxiliary.symmetry())
382 throw std::invalid_argument(
"identity MPO environment spaces require one symmetry");
383 if (auxiliary_index >= auxiliary.size())
384 throw std::invalid_argument(
"identity MPO environment auxiliary index is out of range");
386 throw std::invalid_argument(
"identity MPO environment requires an identity-charge auxiliary state");
389 auto keys = detail::make_identity_environment_keys<result_type>(bond, auxiliary_index);
391 detail::initialize_identity_environment(result);
403template <SparseBlockStorage OutputStorage = SeparateSparseBlockStorage<>, detail::EnvironmentMatrixView Environment,
404 detail::EnvironmentMatrixView BraSite, detail::EnvironmentMpoView Mpo, detail::EnvironmentMatrixView KetSite>
405 requires detail::CompatibleEnvironmentUpdateScalars<Environment, BraSite, Mpo, KetSite> &&
406 detail::CompatibleLeftEnvironmentUpdateSpaces<Environment, BraSite, Mpo, KetSite> &&
407 detail::EnvironmentStorageFor<OutputStorage, block_tensor_value_t<Environment>>
409 KetSite
const& ket_site)
417 detail::validate_environment_update<detail::EnvironmentUpdateDirection::left>(
environment, bra_site, mpo, ket_site);
418 auto plan = detail::make_environment_update_plan<detail::EnvironmentUpdateDirection::left>(
environment, bra_site, mpo,
421 auto domain =
Domain{bra_site.codomain().template space<0>(), mpo.codomain().template space<0>()};
422 auto codomain =
Codomain{ket_site.codomain().template space<0>()};
423 if constexpr (
requires {
424 result_type(
environment.symmetry(), domain, codomain, plan.output_keys,
427 return result_type(
environment.symmetry(), std::move(domain), std::move(codomain), std::move(plan.output_keys),
430 return result_type(
environment.symmetry(), std::move(domain), std::move(codomain), std::move(plan.output_keys));
432 detail::execute_environment_update<detail::EnvironmentUpdateDirection::left>(result, plan,
environment, bra_site, mpo,
441template <SparseBlockStorage OutputStorage = SeparateSparseBlockStorage<>, detail::EnvironmentMatrixView Environment,
442 detail::EnvironmentMatrixView Site, detail::EnvironmentMpoView Mpo>
445 return extend_left_environment<OutputStorage>(
environment, site, mpo, site);
456template <SparseBlockStorage OutputStorage = SeparateSparseBlockStorage<>, detail::EnvironmentMatrixView Environment,
457 detail::EnvironmentMatrixView BraSite, detail::EnvironmentMpoView Mpo, detail::EnvironmentMatrixView KetSite>
458 requires detail::CompatibleEnvironmentUpdateScalars<Environment, BraSite, Mpo, KetSite> &&
459 detail::CompatibleRightEnvironmentUpdateSpaces<Environment, BraSite, Mpo, KetSite> &&
460 detail::EnvironmentStorageFor<OutputStorage, block_tensor_value_t<Environment>>
462 KetSite
const& ket_site)
470 detail::validate_environment_update<detail::EnvironmentUpdateDirection::right>(
environment, bra_site, mpo, ket_site);
471 auto plan = detail::make_environment_update_plan<detail::EnvironmentUpdateDirection::right>(
environment, bra_site,
474 auto domain =
Domain{bra_site.domain().template space<0>(), mpo.domain().template space<0>()};
475 auto codomain =
Codomain{ket_site.domain().template space<0>()};
476 if constexpr (
requires {
477 result_type(
environment.symmetry(), domain, codomain, plan.output_keys,
480 return result_type(
environment.symmetry(), std::move(domain), std::move(codomain), std::move(plan.output_keys),
483 return result_type(
environment.symmetry(), std::move(domain), std::move(codomain), std::move(plan.output_keys));
485 detail::execute_environment_update<detail::EnvironmentUpdateDirection::right>(result, plan,
environment, bra_site,
494template <SparseBlockStorage OutputStorage = SeparateSparseBlockStorage<>, detail::EnvironmentMatrixView Environment,
495 detail::EnvironmentMatrixView Site, detail::EnvironmentMpoView Mpo>
498 return extend_right_environment<OutputStorage>(
environment, site, mpo, site);
Concepts and associated types for BlockTensor-level views.
Classifies tensor spaces for block-key and dense-block storage.
Immutable coalesced tensor space represented as unique symmetry blocks.
Definition block_space.hpp:38
Fixed-order tensor whose blocks obey a bosonic abelian selection rule.
Definition block_tensor.hpp:161
Ordered codomain spaces of a tensor morphism.
Definition morphism_boundary.hpp:78
Ordered domain spaces of a tensor morphism.
Definition morphism_boundary.hpp:24
Ordered local-state space whose quantum numbers may repeat.
Definition local_space.hpp:28
Concept for numeric scalar types (integer, real, or complex).
Definition scalar_concepts.hpp:81
Read-only lazy conjugation views for tensor-level objects.
Coroutine scheduler for AsyncTask.
Named backend-neutral function objects for elementwise transforms.
uni20::complex< T > conj(detail::standard_complex< T > x)
Returns the complex conjugate for complex-valued scalars.
Definition math.hpp:70
Fixed-output pairwise Tensor contraction front end.
std::pair< int, int > size(std::FILE *stream)
Return the terminal size associated with a C stream.
Definition terminal.cpp:504
void execute_batch(std::size_t size, Function &&function)
Execute a synchronous lightweight batch on the global scheduler.
Definition debug_scheduler.hpp:245
void contract(BackendSelector selector, async::Async< OutputTensor > &output, Alpha &&alpha, async::Async< LhsTensor > const &lhs, async::Async< RhsTensor > const &rhs, ContractionAxes< LhsRank, RhsRank, ContractedRank > axes, Beta &&beta)
Schedule a fixed-output pairwise contraction through an explicit selector.
Definition linalg/async/contract.hpp:84
typename optional_traits< T >::value_type value_type
Definition data_table.hpp:42
Definition right_first_rabc.hpp:34
auto extend_right_environment(Environment const &environment, BraSite const &bra_site, Mpo const &mpo, KetSite const &ket_site)
Extend a right MPO environment across distinct bra and ket MPS sites.
Definition environment.hpp:461
auto extend_left_environment(Environment const &environment, BraSite const &bra_site, Mpo const &mpo, KetSite const &ket_site)
Extend a left MPO environment across distinct bra and ket MPS sites.
Definition environment.hpp:408
auto make_identity_mpo_environment(BlockSpace const &bond, LocalSpace const &auxiliary, std::size_t auxiliary_index) -> MpoEnvironment< Value, BlockSpace, LocalSpace, BlockSpace, Storage >
Construct an identity MPO environment at one scalar auxiliary state.
Definition environment.hpp:340
constexpr uninitialized_t uninitialized
Explicit allocation tag for overwrite outputs and scratch space.
Definition common/initialization.hpp:22
typename block_tensor_type_t< Tensor >::domain_type block_tensor_domain_t
Ordered domain type exposed by a BlockTensor-level object.
Definition block_tensor_concepts.hpp:31
typename block_tensor_type_t< Tensor >::value_type block_tensor_value_t
Scalar value type exposed by a BlockTensor-level object.
Definition block_tensor_concepts.hpp:25
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
void copy(BackendSelector selector, async::Async< OutputTensor > &output, async::Async< InputTensor > const &input)
Schedule a Tensor copy through an explicit backend selector.
Definition linalg/async/copy.hpp:174
std::ptrdiff_t index_type
Definition types.hpp:19
mpreal beta(mpreal const &a, mpreal const &x)
Real Beta function; positive rational/integer pairs retain exact values.
Definition mpreal_special.hpp:164
typename block_tensor_type_t< Tensor >::codomain_type block_tensor_codomain_t
Ordered codomain type exposed by a BlockTensor-level object.
Definition block_tensor_concepts.hpp:34
auto is_identity(QNum const &q) -> bool
Return whether a quantum number is the identity irrep.
Definition qnum.hpp:250
Defines canonical BlockTensor types for matrix-product networks.
Trait to extract the scalar type from a type T.
Definition scalar_traits.hpp:93
General-purpose owning tensors with runtime extents.