Program Listing for File spin.hpp

Return to documentation for file (SeQuant/domain/mbpt/spin.hpp)

//
// Created by Eduard Valeyev on 2019-02-27.
//

#ifndef SEQUANT_DOMAIN_MBPT_SPIN_HPP
#define SEQUANT_DOMAIN_MBPT_SPIN_HPP

#include <SeQuant/domain/mbpt/fwd.hpp>

#include <SeQuant/domain/mbpt/space_qns.hpp>

#include <SeQuant/core/container.hpp>
#include <SeQuant/core/expr.hpp>
#include <SeQuant/core/index.hpp>
#include <SeQuant/core/utility/macros.hpp>

#include <cstddef>
#include <initializer_list>
#include <string>
#include <vector>

namespace sequant::mbpt {

// Spin is a scoped enum, hence not implicitly convertible to
// QuantumNumbersAttr::bitset_t
static_assert(!std::is_convertible_v<sequant::mbpt::Spin, bitset_t>);
// QuantumNumbersAttr::bitset_t cannot be constructed from Spin
static_assert(!std::is_constructible_v<bitset_t, sequant::mbpt::Spin>);
// but Spin can be cast to QuantumNumbersAttr::bitset_t
static_assert(meta::is_statically_castable_v<sequant::mbpt::Spin, bitset_t>);
// Spin cannot be cast to nonsense ...
static_assert(
    !meta::is_statically_castable_v<sequant::mbpt::Spin, std::string>);

inline Spin operator~(Spin s) {
  return static_cast<Spin>(~(static_cast<bitset_t>(s)));
}
inline Spin operator|(Spin s1, Spin s2) {
  return static_cast<Spin>(static_cast<bitset_t>(s1) |
                           static_cast<bitset_t>(s2));
}
inline Spin operator&(Spin s1, Spin s2) {
  return static_cast<Spin>(static_cast<bitset_t>(s1) &
                           static_cast<bitset_t>(s2));
}

inline Spin to_spin(const QuantumNumbersAttr& t) {
  SEQUANT_ASSERT((t.to_int32() & mask_v<Spin>) != 0);
  return static_cast<Spin>(t.to_int32() & mask_v<Spin>);
}

inline QuantumNumbersAttr spinannotation_remove(const QuantumNumbersAttr& t) {
  static_assert((~(~mask_v<Spin> & ~bitset::reserved) & ~bitset::reserved) ==
                    mask_v<Spin>,
                "Spin bitmask uses reserved bits");
  return t.intersection(QuantumNumbersAttr(~mask_v<Spin> & ~bitset::reserved));
}

template <typename WS, typename = std::enable_if_t<
                           meta::is_wstring_or_view_v<std::decay_t<WS>>>>
std::wstring spinannotation_remove(WS&& label) {
  auto view = to_basic_string_view(label);
  SEQUANT_ASSERT(!ranges::contains(view, L'_'));
  const auto has_annotation = view.back() == L'↑' || view.back() == L'↓';
  return std::wstring{view.data(),
                      view.data() + view.size() - (has_annotation ? 1 : 0)};
}

template <typename WS, typename = std::enable_if_t<
                           meta::is_wstring_or_view_v<std::decay_t<WS>>>>
std::wstring spinannotation_add(WS&& label, Spin s) {
  [[maybe_unused]] auto view = to_basic_string_view(label);
  SEQUANT_ASSERT(!ranges::contains(view, L'_'));
  SEQUANT_ASSERT(view.back() != L'↑' && view.back() != L'↓');
  switch (s) {
    case Spin::any:
      return to_wstring(std::forward<WS>(label));
    case Spin::alpha:
      return to_wstring(std::forward<WS>(label)) + L'↑';
    case Spin::beta:
      return to_wstring(std::forward<WS>(label)) + L'↓';
    case Spin::null:
      SEQUANT_ABORT("Invalid spin quantum number");
  }

  SEQUANT_UNREACHABLE;
}

template <typename WS, typename = std::enable_if_t<
                           meta::is_wstring_or_view_v<std::decay_t<WS>>>>
std::wstring spinannotation_replacе(WS&& label, Spin s) {
  auto label_sf = spinannotation_remove(std::forward<WS>(label));
  return spinannotation_add(label_sf, s);
}

// make alpha-spin idx
[[nodiscard]] Index make_spinalpha(const Index& idx);

// make beta-spin idx
[[nodiscard]] Index make_spinbeta(const Index& idx);

// make null-spin idx
[[nodiscard]] Index make_spinfree(const Index& idx);

ExprPtr swap_bra_ket(const ExprPtr& expr);

ExprPtr append_spin(const ExprPtr& expr,
                    const container::map<Index, Index>& index_replacements);

ExprPtr remove_spin(const ExprPtr& expr);

bool ms_conserving_columns(const AbstractTensor& tensor);

bool ms_uniform_tensor(const AbstractTensor& tensor);

bool can_expand(const AbstractTensor& tensor);

ExprPtr expand_antisymm(const Tensor& tensor, bool skip_spinsymm = false);

ExprPtr expand_antisymm(const ExprPtr& expr, bool skip_spinsymm = false);

container::svector<container::map<Index, Index>> A_maps(const Tensor& A);

ExprPtr expand_A_op(const ProductPtr& product);

ExprPtr symmetrize_expr(const ProductPtr& product);

ExprPtr symmetrize_expr(const ExprPtr& expr);

ExprPtr expand_A_op(const ExprPtr& expr);

container::svector<container::map<Index, Index>> P_maps(const Tensor& P);

ExprPtr expand_P_op(const ProductPtr& product);

ExprPtr expand_P_op(const ExprPtr& expr);

container::svector<container::map<Index, Index>> S_replacement_maps(
    const Tensor& S);

ExprPtr S_maps(const ExprPtr& expr);


ExprPtr WK_biorthogonalization_filter(
    ExprPtr expr,
    const container::svector<container::svector<Index>>& ext_idxs);

// clang-format off
// clang-format on
ExprPtr closed_shell_spintrace(
    const ExprPtr& expr,
    const container::svector<container::svector<Index>>& ext_index_groups = {},
    bool full_expansion = false);

container::svector<ResultExpr> closed_shell_spintrace(
    const ResultExpr& expr, bool full_expansion = false);

// clang-format off
enum class BiorthogonalizationMethod {
  V1,
  V2
};
// clang-format on

struct ClosedShellCCSpintraceOptions {
  BiorthogonalizationMethod method = BiorthogonalizationMethod::V2;
  bool naive_spintrace = false;
};

// clang-format off
// clang-format on
ExprPtr closed_shell_CC_spintrace(ExprPtr const& expr,
                                  ClosedShellCCSpintraceOptions options = {});

ExprPtr closed_shell_CC_spintrace_v1(
    ExprPtr const& expr,
    ClosedShellCCSpintraceOptions options = {
        .method = BiorthogonalizationMethod::V1, .naive_spintrace = false});

ExprPtr closed_shell_CC_spintrace_v2(
    ExprPtr const& expr,
    ClosedShellCCSpintraceOptions options = {
        .method = BiorthogonalizationMethod::V2, .naive_spintrace = false});

container::set<Index, Index::LabelCompare> index_list(const ExprPtr& expr);

Tensor swap_spin(const Tensor& t);

ExprPtr swap_spin(const ExprPtr& expr);

ExprPtr merge_tensors(const Tensor& O1, const Tensor& O2);

std::vector<ExprPtr> open_shell_A_op(const Tensor& A);

std::vector<ExprPtr> open_shell_P_op_vector(const Tensor& A);

// clang-format off
// clang-format on
std::vector<ExprPtr> open_shell_spintrace(
    const ExprPtr& expr,
    const container::svector<container::svector<Index>>& ext_index_groups,
    std::optional<int> target_spin_case = std::nullopt);

// clang-format off
// clang-format on
std::vector<ExprPtr> open_shell_CC_spintrace(const ExprPtr& expr);

ExprPtr spintrace(
    const ExprPtr& expr,
    const container::svector<container::svector<Index>>& ext_index_groups = {},
    bool spinfree_index_spaces = true);

container::svector<ResultExpr> spintrace(const ResultExpr& expr,
                                         bool spinfree_index_spaces = true);

ExprPtr factorize_S(const ExprPtr& expression,
                    std::initializer_list<IndexList> ext_index_groups,
                    bool fast_method = true);

}  // namespace sequant::mbpt

#endif  // SEQUANT_DOMAIN_MBPT_SPIN_HPP