Uni20
Asynchronous tensor and runtime library.
Loading...
Searching...
No Matches
two_site_effective_hamiltonian.hpp
Go to the documentation of this file.
1
7#pragma once
8
14
15#include <algorithm>
16#include <array>
17#include <concepts>
18#include <cstddef>
19#include <map>
20#include <memory>
21#include <optional>
22#include <ranges>
23#include <stdexcept>
24#include <type_traits>
25#include <utility>
26#include <vector>
27
29{
30namespace detail
31{
32
33template <class Tensor>
34concept TwoSiteCenterView = BlockTensorView<Tensor> && (block_tensor_domain_t<Tensor>::size() == 3) &&
35 (block_tensor_codomain_t<Tensor>::size() == 1);
36
37template <class Tensor>
38concept TwoSiteOperatorView = ImmediateBlockTensorView<Tensor> && (block_tensor_domain_t<Tensor>::size() == 2) &&
39 (block_tensor_codomain_t<Tensor>::size() == 2);
40
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>>;
47
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);
53
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);
59
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);
65
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>>;
72
73} // namespace detail
74
85template <detail::TwoSiteOperatorView Hamiltonian> class LocalTwoSiteEffectiveHamiltonian {
86 public:
87 using hamiltonian_type = std::remove_cvref_t<Hamiltonian>;
88
91
98 template <MutableImmediateBlockTensorView Output, detail::TwoSiteCenterView Input>
99 requires detail::CompatibleTwoSiteCenters<Output, Input>
100 void operator()(Output& output, Input const& input) const
101 {
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);
108 }
109
111 [[nodiscard]] auto hamiltonian() const noexcept -> hamiltonian_type const& { return hamiltonian_; }
112
113 private:
114 hamiltonian_type hamiltonian_;
115};
116
117template <class Hamiltonian>
119
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>
142 public:
143 using center_type = std::remove_cvref_t<Center>;
144 using left_environment_type = std::remove_cvref_t<LeftEnvironment>;
145 using first_mpo_type = std::remove_cvref_t<FirstMpo>;
146 using second_mpo_type = std::remove_cvref_t<SecondMpo>;
147 using right_environment_type = std::remove_cvref_t<RightEnvironment>;
154
155 private:
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>>);
178
179 public:
189 first_mpo_type first_mpo, second_mpo_type second_mpo,
190 right_environment_type right_environment)
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))
194 {
195 this->validate_operand_spaces(prototype, first_mpo, second_mpo);
196 auto plan = this->make_plan(first_mpo, second_mpo);
197 prepared_rabc_.emplace(
198 prepare_rabc_contract(prototype, std::move(plan), left_environment_, prototype, right_environment_));
199 }
200
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> &&
210 std::same_as<block_tensor_codomain_t<Output>, codomain_type>
211 void operator()(Output& output, Input const& input)
212 {
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>>)
216 {
217 if (std::addressof(output) == std::addressof(input))
218 {
219 throw std::invalid_argument("two-site effective Hamiltonian output must not alias its input");
220 }
221 }
222
223 (*prepared_rabc_)(output, left_environment_, input, right_environment_);
224 }
225
227 [[nodiscard]] auto term_count() const noexcept -> std::size_t { return prepared_rabc_->plan().term_count(); }
228
230 [[nodiscard]] auto plan() const noexcept -> plan_type const& { return prepared_rabc_->plan(); }
231
233 [[nodiscard]] auto prepared_intermediate_count() const noexcept -> std::size_t
234 {
235 return prepared_rabc_->intermediate_count();
236 }
237
238 private:
239 void validate_operand_spaces(center_type const& prototype, first_mpo_type const& first_mpo,
240 second_mpo_type const& second_mpo) const
241 {
242 if (left_environment_.symmetry() != symmetry_ || first_mpo.symmetry() != symmetry_ ||
243 second_mpo.symmetry() != symmetry_ || right_environment_.symmetry() != symmetry_)
244 {
245 throw std::invalid_argument("two-site effective Hamiltonian operands require one symmetry");
246 }
247
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>())
259 {
260 throw std::invalid_argument(
261 "two-site effective Hamiltonian has incompatible center, MPO, or environment spaces");
262 }
263 }
264
265 [[nodiscard]] auto find_center_ordinal(key_type const& key) const -> std::optional<std::size_t>
266 {
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());
270 }
271
272 [[nodiscard]] auto make_plan(first_mpo_type const& first_mpo, second_mpo_type const& second_mpo) const -> plan_type
273 {
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);
277
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)
281 {
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);
284 }
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)
287 {
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);
290 }
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)
293 {
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);
296 }
297
298 std::vector<RabcTerm<scalar_type>> terms;
299 for (std::size_t input = 0; input < stored_keys_.size(); ++input)
300 {
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)
305 {
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)
311 {
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)
317 {
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;
322 scalar_type const coefficient =
323 first_mpo.block_by_ordinal(first)[] * second_mpo.block_by_ordinal(second)[];
324 if (coefficient == scalar_type{}) continue;
325 for (std::size_t const right : right_match->second)
326 {
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);
331 if (!output)
332 {
333 throw std::invalid_argument(
334 "two-site center stored pattern is not closed under its effective Hamiltonian");
335 }
336 terms.push_back({.r_key_index = *output,
337 .a_key_index = left,
338 .b_key_index = input,
339 .c_key_index = right,
340 .coefficient = coefficient});
341 }
342 }
343 }
344 }
345 }
346 using a_key_type = typename plan_type::a_key_type;
347 using c_key_type = typename plan_type::c_key_type;
348 return plan_type(
349 stored_keys_,
350 std::vector<a_key_type>(left_environment_.stored_keys().begin(), left_environment_.stored_keys().end()),
351 stored_keys_,
352 std::vector<c_key_type>(right_environment_.stored_keys().begin(), right_environment_.stored_keys().end()),
353 std::move(terms));
354 }
355
356 template <BlockTensorView Tensor> void require_center(Tensor const& center) const
357 {
358 if (center.symmetry() != symmetry_ || center.domain() != domain_ || center.codomain() != codomain_ ||
359 !std::ranges::equal(center.stored_keys(), stored_keys_))
360 {
361 throw std::invalid_argument("two-site effective Hamiltonian requires its compiled center structure");
362 }
363 }
364
365 Symmetry symmetry_;
366 domain_type domain_;
367 codomain_type codomain_;
368 std::vector<key_type> stored_keys_;
369 left_environment_type left_environment_;
370 right_environment_type right_environment_;
371 using prepared_rabc_type = decltype(prepare_rabc_contract(
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_;
375};
376
377template <class Center, class LeftEnvironment, class FirstMpo, class SecondMpo, class RightEnvironment>
378TwoSiteEffectiveHamiltonian(Center const&, LeftEnvironment, FirstMpo, SecondMpo, RightEnvironment)
379 -> TwoSiteEffectiveHamiltonian<std::remove_cvref_t<Center>, std::remove_cvref_t<LeftEnvironment>,
380 std::remove_cvref_t<FirstMpo>, std::remove_cvref_t<SecondMpo>,
381 std::remove_cvref_t<RightEnvironment>>;
382
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>
399[[nodiscard]] auto make_two_site_effective_hamiltonian(Center const& prototype, LeftEnvironment const& left_environment,
400 FirstMpo const& first_mpo, SecondMpo const& second_mpo,
401 RightEnvironment const& right_environment)
402{
403 return TwoSiteEffectiveHamiltonian(prototype, as_block_tensor_view(left_environment), as_block_tensor_view(first_mpo),
404 as_block_tensor_view(second_mpo), as_block_tensor_view(right_environment));
405}
406
407} // namespace uni20::tensor_network
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 qnum.hpp:403
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