33template <
class Tensor>
34concept TwoSiteCenterView = BlockTensorView<Tensor> && (block_tensor_domain_t<Tensor>::size() == 3) &&
35 (block_tensor_codomain_t<Tensor>::size() == 1);
37template <
class Tensor>
38concept TwoSiteOperatorView = ImmediateBlockTensorView<Tensor> && (block_tensor_domain_t<Tensor>::size() == 2) &&
39 (block_tensor_codomain_t<Tensor>::size() == 2);
41template <
class Output,
class Input>
42concept CompatibleTwoSiteCenters = TwoSiteCenterView<Output> && TwoSiteCenterView<Input> &&
43 std::same_as<block_tensor_value_t<Output>, block_tensor_value_t<Input>> &&
44 std::same_as<block_tensor_key_t<Output>, block_tensor_key_t<Input>> &&
45 std::same_as<block_tensor_domain_t<Output>, block_tensor_domain_t<Input>> &&
46 std::same_as<block_tensor_codomain_t<Output>, block_tensor_codomain_t<Input>>;
48template <
class Tensor>
49concept MpoEffectiveCenter =
50 BlockTensorView<Tensor> && (block_tensor_domain_t<Tensor>::size() == 3) &&
51 (block_tensor_codomain_t<Tensor>::size() == 1) && (block_tensor_type_t<Tensor>::key_coordinate_count() == 4) &&
52 (block_tensor_type_t<Tensor>::dense_block_order() == 2);
54template <
class Tensor>
55concept MpoEffectiveEnvironment =
56 BlockTensorView<Tensor> && (block_tensor_domain_t<Tensor>::size() == 2) &&
57 (block_tensor_codomain_t<Tensor>::size() == 1) && (block_tensor_type_t<Tensor>::key_coordinate_count() == 3) &&
58 (block_tensor_type_t<Tensor>::dense_block_order() == 2);
60template <
class Tensor>
61concept MpoEffectiveSite =
62 ImmediateBlockTensorView<Tensor> && (block_tensor_domain_t<Tensor>::size() == 2) &&
63 (block_tensor_codomain_t<Tensor>::size() == 2) && (block_tensor_type_t<Tensor>::key_coordinate_count() == 4) &&
64 (block_tensor_type_t<Tensor>::dense_block_order() == 0);
66template <
class Center,
class LeftEnvironment,
class FirstMpo,
class SecondMpo,
class RightEnvironment>
67concept CompatibleMpoEffectiveScalars =
68 std::same_as<block_tensor_value_t<Center>, block_tensor_value_t<LeftEnvironment>> &&
69 std::same_as<block_tensor_value_t<Center>, block_tensor_value_t<FirstMpo>> &&
70 std::same_as<block_tensor_value_t<Center>, block_tensor_value_t<SecondMpo>> &&
71 std::same_as<block_tensor_value_t<Center>, block_tensor_value_t<RightEnvironment>>;
98 template <MutableImmediateBlockTensorView Output, detail::TwoSiteCenterView Input>
99 requires detail::CompatibleTwoSiteCenters<Output, Input>
102 auto operator_input = permute<0, 1, 3, 2>(repartition<MorphismSide::Domain, BoundaryEnd::Right>(
103 repartition<MorphismSide::Domain, BoundaryEnd::Right>(input)));
104 auto applied = contract_adjacent<2>(operator_input, hamiltonian_);
105 auto canonical_output = repartition<MorphismSide::Codomain, BoundaryEnd::Right>(
106 repartition<MorphismSide::Codomain, BoundaryEnd::Right>(permute<0, 1, 3, 2>(applied)));
107 copy(output, canonical_output);
117template <
class Hamiltonian>
137template <detail::MpoEffectiveCenter Center, detail::MpoEffectiveEnvironment LeftEnvironment,
138 detail::MpoEffectiveSite FirstMpo, detail::MpoEffectiveSite SecondMpo,
139 detail::MpoEffectiveEnvironment RightEnvironment>
140 requires detail::CompatibleMpoEffectiveScalars<Center, LeftEnvironment, FirstMpo, SecondMpo, RightEnvironment>
156 static_assert(std::same_as<typename left_environment_type::codomain_type::template space_type<0>,
157 typename domain_type::template space_type<0>>);
158 static_assert(std::same_as<typename left_environment_type::domain_type::template space_type<0>,
159 typename domain_type::template space_type<0>>);
160 static_assert(std::same_as<typename left_environment_type::domain_type::template space_type<1>,
161 typename first_mpo_type::domain_type::template space_type<0>>);
162 static_assert(std::same_as<typename first_mpo_type::domain_type::template space_type<1>,
163 typename domain_type::template space_type<1>>);
164 static_assert(std::same_as<typename first_mpo_type::codomain_type::template space_type<1>,
165 typename domain_type::template space_type<1>>);
166 static_assert(std::same_as<typename first_mpo_type::codomain_type::template space_type<0>,
167 typename second_mpo_type::domain_type::template space_type<0>>);
168 static_assert(std::same_as<typename second_mpo_type::domain_type::template space_type<1>,
169 typename domain_type::template space_type<2>>);
170 static_assert(std::same_as<typename second_mpo_type::codomain_type::template space_type<1>,
171 typename domain_type::template space_type<2>>);
172 static_assert(std::same_as<typename second_mpo_type::codomain_type::template space_type<0>,
173 typename right_environment_type::domain_type::template space_type<1>>);
174 static_assert(std::same_as<typename right_environment_type::domain_type::template space_type<0>,
175 typename codomain_type::template space_type<0>>);
176 static_assert(std::same_as<typename right_environment_type::codomain_type::template space_type<0>,
177 typename codomain_type::template space_type<0>>);
191 : symmetry_(prototype.symmetry()), domain_(prototype.domain()), codomain_(prototype.codomain()),
192 stored_keys_(prototype.stored_keys().
begin(), prototype.stored_keys().end()),
193 left_environment_(
std::move(left_environment)), right_environment_(
std::move(right_environment))
195 this->validate_operand_spaces(prototype, first_mpo, second_mpo);
196 auto plan = this->make_plan(first_mpo, second_mpo);
197 prepared_rabc_.emplace(
205 template <MutableBlockTensorView Output, detail::MpoEffectiveCenter Input>
206 requires detail::CompatibleTwoSiteCenters<Output, Input> &&
207 std::same_as<block_tensor_value_t<Output>,
scalar_type> &&
208 std::same_as<block_tensor_key_t<Output>,
key_type> &&
209 std::same_as<block_tensor_domain_t<Output>,
domain_type> &&
213 this->require_center(output);
214 this->require_center(input);
215 if constexpr (std::same_as<std::remove_cvref_t<Output>, std::remove_cvref_t<Input>>)
217 if (std::addressof(output) == std::addressof(input))
219 throw std::invalid_argument(
"two-site effective Hamiltonian output must not alias its input");
223 (*prepared_rabc_)(output, left_environment_, input, right_environment_);
227 [[nodiscard]]
auto term_count() const noexcept ->
std::
size_t {
return prepared_rabc_->plan().term_count(); }
230 [[nodiscard]]
auto plan() const noexcept ->
plan_type const& {
return prepared_rabc_->plan(); }
235 return prepared_rabc_->intermediate_count();
242 if (left_environment_.symmetry() != symmetry_ || first_mpo.symmetry() != symmetry_ ||
243 second_mpo.symmetry() != symmetry_ || right_environment_.symmetry() != symmetry_)
245 throw std::invalid_argument(
"two-site effective Hamiltonian operands require one symmetry");
248 if (left_environment_.codomain().template space<0>() != prototype.domain().template space<0>() ||
249 left_environment_.domain().template space<0>() != prototype.domain().template space<0>() ||
250 left_environment_.domain().template space<1>() != first_mpo.domain().template space<0>() ||
251 first_mpo.domain().template space<1>() != prototype.domain().template space<1>() ||
252 first_mpo.codomain().template space<1>() != prototype.domain().template space<1>() ||
253 first_mpo.codomain().template space<0>() != second_mpo.domain().template space<0>() ||
254 second_mpo.domain().template space<1>() != prototype.domain().template space<2>() ||
255 second_mpo.codomain().template space<1>() != prototype.domain().template space<2>() ||
256 second_mpo.codomain().template space<0>() != right_environment_.domain().template space<1>() ||
257 right_environment_.domain().template space<0>() != prototype.codomain().template space<0>() ||
258 right_environment_.codomain().template space<0>() != prototype.codomain().template space<0>())
260 throw std::invalid_argument(
261 "two-site effective Hamiltonian has incompatible center, MPO, or environment spaces");
265 [[nodiscard]]
auto find_center_ordinal(
key_type const& key)
const -> std::optional<std::size_t>
267 auto const found = std::ranges::lower_bound(stored_keys_, key);
268 if (found == stored_keys_.end() || *found != key)
return std::nullopt;
269 return static_cast<std::size_t
>(found - stored_keys_.begin());
274 std::map<std::size_t, std::vector<std::size_t>> left_by_input_bond;
275 for (std::size_t ordinal = 0; ordinal < left_environment_.stored_block_count(); ++ordinal)
276 left_by_input_bond[left_environment_.stored_keys()[ordinal].coordinate(2)].push_back(ordinal);
278 using coordinate_pair = std::array<std::size_t, 2>;
279 std::map<coordinate_pair, std::vector<std::size_t>> first_by_left_auxiliary_and_input;
280 for (std::size_t ordinal = 0; ordinal < first_mpo.stored_block_count(); ++ordinal)
282 auto const& key = first_mpo.stored_keys()[ordinal];
283 first_by_left_auxiliary_and_input[{key.coordinate(0), key.coordinate(1)}].push_back(ordinal);
285 std::map<coordinate_pair, std::vector<std::size_t>> second_by_left_auxiliary_and_input;
286 for (std::size_t ordinal = 0; ordinal < second_mpo.stored_block_count(); ++ordinal)
288 auto const& key = second_mpo.stored_keys()[ordinal];
289 second_by_left_auxiliary_and_input[{key.coordinate(0), key.coordinate(1)}].push_back(ordinal);
291 std::map<coordinate_pair, std::vector<std::size_t>> right_by_auxiliary_and_input_bond;
292 for (std::size_t ordinal = 0; ordinal < right_environment_.stored_block_count(); ++ordinal)
294 auto const& key = right_environment_.stored_keys()[ordinal];
295 right_by_auxiliary_and_input_bond[{key.coordinate(1), key.coordinate(2)}].push_back(ordinal);
298 std::vector<RabcTerm<scalar_type>> terms;
299 for (std::size_t input = 0; input < stored_keys_.size(); ++input)
301 auto const& input_key = stored_keys_[input];
302 auto const left_match = left_by_input_bond.find(input_key.coordinate(0));
303 if (left_match == left_by_input_bond.end())
continue;
304 for (std::size_t
const left : left_match->second)
306 auto const& left_key = left_environment_.stored_keys()[
left];
307 auto const first_match =
308 first_by_left_auxiliary_and_input.find({left_key.coordinate(1), input_key.coordinate(1)});
309 if (first_match == first_by_left_auxiliary_and_input.end())
continue;
310 for (std::size_t
const first : first_match->second)
312 auto const& first_key = first_mpo.stored_keys()[first];
313 auto const second_match =
314 second_by_left_auxiliary_and_input.find({first_key.coordinate(2), input_key.coordinate(2)});
315 if (second_match == second_by_left_auxiliary_and_input.end())
continue;
316 for (std::size_t
const second : second_match->second)
318 auto const& second_key = second_mpo.stored_keys()[second];
319 auto const right_match =
320 right_by_auxiliary_and_input_bond.find({second_key.coordinate(2), input_key.coordinate(3)});
321 if (right_match == right_by_auxiliary_and_input_bond.end())
continue;
323 first_mpo.block_by_ordinal(first)[] * second_mpo.block_by_ordinal(second)[];
325 for (std::size_t
const right : right_match->second)
327 auto const& right_key = right_environment_.stored_keys()[
right];
328 key_type const output_key{{left_key.coordinate(0), first_key.coordinate(3), second_key.coordinate(3),
329 right_key.coordinate(0)}};
330 auto const output = this->find_center_ordinal(output_key);
333 throw std::invalid_argument(
334 "two-site center stored pattern is not closed under its effective Hamiltonian");
336 terms.push_back({.r_key_index = *output,
338 .b_key_index = input,
339 .c_key_index =
right,
340 .coefficient = coefficient});
350 std::vector<a_key_type>(left_environment_.stored_keys().begin(), left_environment_.stored_keys().end()),
352 std::vector<c_key_type>(right_environment_.stored_keys().begin(), right_environment_.stored_keys().end()),
356 template <BlockTensorView Tensor>
void require_center(Tensor
const& center)
const
358 if (
center.symmetry() != symmetry_ ||
center.domain() != domain_ ||
center.codomain() != codomain_ ||
359 !std::ranges::equal(
center.stored_keys(), stored_keys_))
361 throw std::invalid_argument(
"two-site effective Hamiltonian requires its compiled center structure");
368 std::vector<key_type> stored_keys_;
372 std::declval<center_type const&>(), std::declval<plan_type>(), std::declval<left_environment_type const&>(),
373 std::declval<center_type const&>(), std::declval<right_environment_type const&>()));
374 std::optional<prepared_rabc_type> prepared_rabc_;
377template <
class Center,
class LeftEnvironment,
class FirstMpo,
class SecondMpo,
class RightEnvironment>
380 std::remove_cvref_t<FirstMpo>, std::remove_cvref_t<SecondMpo>,
381 std::remove_cvref_t<RightEnvironment>>;
395template <detail::MpoEffectiveCenter Center, detail::MpoEffectiveEnvironment LeftEnvironment,
396 detail::MpoEffectiveSite FirstMpo, detail::MpoEffectiveSite SecondMpo,
397 detail::MpoEffectiveEnvironment RightEnvironment>
398 requires detail::CompatibleMpoEffectiveScalars<Center, LeftEnvironment, FirstMpo, SecondMpo, RightEnvironment>
400 FirstMpo
const& first_mpo, SecondMpo
const& second_mpo,
401 RightEnvironment
const& right_environment)
Defines local pairwise BlockTensor contraction.
Defines structure-preserving linear operations on BlockTensor values.
Defines zero-copy bosonic BlockTensor factor permutations.
Defines zero-copy bosonic edge repartition views.
Apply a local two-site operator to a fixed BlockTensor center.
Definition two_site_effective_hamiltonian.hpp:85
LocalTwoSiteEffectiveHamiltonian(hamiltonian_type hamiltonian)
Retain an immutable local two-site Hamiltonian object.
Definition two_site_effective_hamiltonian.hpp:90
void operator()(Output &output, Input const &input) const
Overwrite a fixed center with the Hamiltonian application.
Definition two_site_effective_hamiltonian.hpp:100
auto hamiltonian() const noexcept -> hamiltonian_type const &
Return the retained local Hamiltonian.
Definition two_site_effective_hamiltonian.hpp:111
std::remove_cvref_t< Hamiltonian > hamiltonian_type
Definition two_site_effective_hamiltonian.hpp:87
Immutable sparse coefficient tensor for an R/A/B/C contraction.
Definition rabc_contraction_plan.hpp:68
CKey c_key_type
Definition rabc_contraction_plan.hpp:74
AKey a_key_type
Definition rabc_contraction_plan.hpp:72
Matrix-free two-site Hamiltonian compiled from environments and MPO sites.
Definition two_site_effective_hamiltonian.hpp:141
void operator()(Output &output, Input const &input)
Overwrite a compatible fixed center with one planned Hamiltonian apply.
Definition two_site_effective_hamiltonian.hpp:211
std::remove_cvref_t< LeftEnvironment > left_environment_type
Definition two_site_effective_hamiltonian.hpp:144
block_tensor_domain_t< center_type > domain_type
Definition two_site_effective_hamiltonian.hpp:149
auto plan() const noexcept -> plan_type const &
Return the immutable sparse coefficient plan used by the prepared backend.
Definition two_site_effective_hamiltonian.hpp:230
block_tensor_value_t< center_type > scalar_type
Definition two_site_effective_hamiltonian.hpp:148
RabcContractionPlan< scalar_type, key_type, block_tensor_key_t< left_environment_type >, key_type, block_tensor_key_t< right_environment_type > > plan_type
Definition two_site_effective_hamiltonian.hpp:153
std::remove_cvref_t< SecondMpo > second_mpo_type
Definition two_site_effective_hamiltonian.hpp:146
block_tensor_key_t< center_type > key_type
Definition two_site_effective_hamiltonian.hpp:151
auto term_count() const noexcept -> std::size_t
Return the number of compiled logical R/A/B/C contributions.
Definition two_site_effective_hamiltonian.hpp:227
std::remove_cvref_t< RightEnvironment > right_environment_type
Definition two_site_effective_hamiltonian.hpp:147
auto prepared_intermediate_count() const noexcept -> std::size_t
Return the number of retained right-first intermediate blocks.
Definition two_site_effective_hamiltonian.hpp:233
block_tensor_codomain_t< center_type > codomain_type
Definition two_site_effective_hamiltonian.hpp:150
std::remove_cvref_t< Center > center_type
Definition two_site_effective_hamiltonian.hpp:143
TwoSiteEffectiveHamiltonian(center_type const &prototype, left_environment_type left_environment, first_mpo_type first_mpo, second_mpo_type second_mpo, right_environment_type right_environment)
Compile one fixed-center sparse effective-Hamiltonian plan.
Definition two_site_effective_hamiltonian.hpp:188
std::remove_cvref_t< FirstMpo > first_mpo_type
Definition two_site_effective_hamiltonian.hpp:145
Definition right_first_rabc.hpp:34
auto prepare_rabc_contract(linalg::backend_list< RightFirstRabcBackend< IntermediateStorage, ContractionSelector > > selector, Output const &output, Plan plan, A const &a, B const &b, C const &c)
Prepare the single right-first backend selected for fixed R/A/B/C operands.
Definition rabc_contraction.hpp:89
auto make_two_site_effective_hamiltonian(Center const &prototype, LeftEnvironment const &left_environment, FirstMpo const &first_mpo, SecondMpo const &second_mpo, RightEnvironment const &right_environment)
Compile a two-site effective Hamiltonian borrowing environment payloads.
Definition two_site_effective_hamiltonian.hpp:399
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
typename block_tensor_type_t< Tensor >::key_type block_tensor_key_t
Logical block-key type exposed by a BlockTensor-level object.
Definition block_tensor_concepts.hpp:28
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
auto as_block_tensor_view(Tensor &tensor)
Materialize a borrowed identity view over an existing BlockTensor view.
Definition block_tensor_permute.hpp:186
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
Dispatchable sparse R/A/B/C block contraction.
Trait to extract the scalar type from a type T.
Definition scalar_traits.hpp:93