Program Listing for File basis.hpp

↰ Return to documentation for file (SeQuant/core/basis.hpp)

#ifndef SEQUANT_CORE_BASIS_HPP
#define SEQUANT_CORE_BASIS_HPP

#include <SeQuant/core/attr.hpp>
#include <SeQuant/core/hash.hpp>
#include <SeQuant/core/space.hpp>

#include <compare>
#include <concepts>
#include <cstddef>
#include <cstdint>
#include <optional>
#include <string>
#include <utility>

namespace sequant {


class IndexBasis {
 public:
  using instance_type = std::int32_t;
  using optional_instance = std::optional<instance_type>;

  IndexBasis() noexcept = default;

  IndexBasis(IndexSpace space) noexcept : space_(std::move(space)) {}

  template <basic_string_convertible S, typename... Args>
    requires(sizeof...(Args) > 0 &&
             std::constructible_from<IndexSpace, S, Args...>)
  IndexBasis(S&& type_label, Args&&... args)
      : space_(std::forward<S>(type_label), std::forward<Args>(args)...) {}

  explicit IndexBasis(IndexSpace space,
                      optional_instance basis_instance) noexcept
      : space_(std::move(space)), basis_instance_(basis_instance) {}

  IndexBasis(IndexSpace space, optional_instance basis_instance,
             std::wstring name, std::optional<std::size_t> extent = {},
             IndexBasisMetric metric = IndexBasisMetric::Unit,
             std::optional<Field> field = {});

  const IndexSpace& space() const noexcept { return space_; }

  const optional_instance& basis_instance() const noexcept {
    return basis_instance_;
  }

  bool has_basis_instance() const noexcept {
    return basis_instance_.has_value();
  }

  const std::wstring& name() const noexcept { return name_; }

  bool has_name() const noexcept { return !name_.empty(); }

  const std::wstring& base_key() const noexcept {
    return has_name() ? name_ : space_.base_key();
  }

  optional_instance unnamed_instance() const noexcept {
    return has_name() ? std::nullopt : basis_instance_;
  }

  std::size_t extent() const noexcept {
    return extent_ ? *extent_ : space_.dimension();
  }

  IndexBasisMetric metric() const noexcept { return metric_; }

  Field field() const noexcept { return field_ ? *field_ : space_.field(); }

  const std::optional<std::size_t>& own_extent() const noexcept {
    return extent_;
  }

  const std::optional<Field>& own_field() const noexcept { return field_; }

  std::wstring instance_suffix() const;

  friend bool operator==(const IndexBasis& b1, const IndexBasis& b2) noexcept {
    return b1.space_ == b2.space_ && b1.basis_instance_ == b2.basis_instance_ &&
           b1.name_ == b2.name_;
  }

  friend std::strong_ordering operator<=>(const IndexBasis& b1,
                                          const IndexBasis& b2) noexcept {
    if (auto c = b1.space_ <=> b2.space_; c != 0) return c;
    if (auto c = b1.basis_instance_ <=> b2.basis_instance_; c != 0) return c;
    return b1.name_ <=> b2.name_;
  }

  friend std::size_t hash_value(const IndexBasis& b) {
    std::size_t result = hash_value(b.space_);
    if (b.basis_instance_) hash::combine(result, *b.basis_instance_);
    if (b.has_name()) hash::combine(result, b.name_);
    return result;
  }


  template <std::ranges::contiguous_range View>
    requires(std::same_as<std::remove_cvref_t<std::ranges::range_value_t<View>>,
                          char> ||
             std::same_as<std::remove_cvref_t<std::ranges::range_value_t<View>>,
                          wchar_t>)
  static auto reduce_key(View&& key) {
    return IndexSpace::reduce_key(key);
  }

  template <typename CharT>
  static auto reduce_key(const CharT* key) {
    return IndexSpace::reduce_key(key);
  }

  struct bad_key : IndexSpace::bad_key {
    using IndexSpace::bad_key::bad_key;
  };


 private:
  IndexSpace space_;
  optional_instance basis_instance_;
  std::wstring name_;
  std::optional<std::size_t> extent_;
  IndexBasisMetric metric_ = IndexBasisMetric::Unit;
  std::optional<Field> field_;

  // the registry writes the metadata of its named entries in place
  friend class IndexBasisRegistry;
  void extent(std::size_t n) noexcept { extent_ = n; }
  void metric(IndexBasisMetric m) noexcept { metric_ = m; }
  void field(Field f) noexcept { field_ = f; }
};

bool same_instance(const IndexBasis& b1, const IndexBasis& b2) noexcept;

bool includes(const IndexBasis& basis, const IndexBasis& subbasis);

bool different_instances(const IndexBasis& b1, const IndexBasis& b2);

}  // namespace sequant

#endif  // SEQUANT_CORE_BASIS_HPP