Program Listing for File space.hpp¶
↰ Return to documentation for file (SeQuant/core/space.hpp
)
//
// Created by Eduard Valeyev on 3/20/18.
//
#ifndef SEQUANT_SPACE_H
#define SEQUANT_SPACE_H
#include <bitset>
#include <cassert>
#include <cmath>
#include <SeQuant/core/attr.hpp>
#include <SeQuant/core/container.hpp>
#include <SeQuant/core/utility/string.hpp>
#include <SeQuant/core/wstring.hpp>
#include <range/v3/algorithm/any_of.hpp>
namespace sequant {
namespace bitset {
using type = int32_t;
constexpr type reserved = 0x80000000;
constexpr type null = 0x00000000;
} // namespace bitset
using bitset_t = bitset::type;
class QuantumNumbersAttr; // used to constrain TypeAttr ctor
class Index; // friend of TypeAttr
class TypeAttr {
public:
constexpr TypeAttr() noexcept = default;
const static TypeAttr null;
explicit constexpr TypeAttr(bitset_t bitset) noexcept : bitset(bitset) {
assert((this->bitset & bitset::reserved) == bitset::null);
}
template <typename T,
typename = std::enable_if_t<
meta::is_statically_castable_v<std::decay_t<T>, bitset_t> &&
!std::is_same_v<std::decay_t<T>, bool> &&
!std::is_same_v<std::decay_t<T>, QuantumNumbersAttr> &&
!std::is_same_v<std::decay_t<T>, TypeAttr>>>
constexpr TypeAttr(T &&value) noexcept
: TypeAttr(static_cast<bitset_t>(std::forward<T>(value))) {}
constexpr explicit operator int64_t() const {
return static_cast<int64_t>(bitset);
}
constexpr explicit operator bitset_t() const { return bitset; }
constexpr int32_t to_int32() const { return bitset; }
constexpr explicit operator bool() const { return bitset != 0; }
constexpr TypeAttr(const TypeAttr &other) { bitset = other.to_int32(); }
constexpr TypeAttr unIon(TypeAttr other) const {
return TypeAttr(this->to_int32() | other.to_int32());
}
friend constexpr TypeAttr operator|(const TypeAttr a, const TypeAttr b) {
return a.unIon(b);
}
constexpr const TypeAttr xOr(TypeAttr other) const {
return TypeAttr(this->to_int32() ^ other.to_int32());
}
friend constexpr TypeAttr operator^(const TypeAttr a, const TypeAttr b) {
return a.xOr(b);
}
constexpr const TypeAttr intersection(TypeAttr other) const {
return TypeAttr(this->to_int32() & other.to_int32());
}
friend constexpr TypeAttr operator&(const TypeAttr a, const TypeAttr b) {
return a.intersection(b);
}
constexpr TypeAttr operator~() const { return ~this->to_int32(); }
friend constexpr bool operator==(const TypeAttr lhs, const TypeAttr rhs) {
return lhs.to_int32() == rhs.to_int32();
}
friend constexpr bool operator!=(const TypeAttr lhs, const TypeAttr rhs) {
return !(lhs == rhs);
}
constexpr bool includes(TypeAttr other) const {
return intersection(other) == other;
}
friend constexpr bool operator<(TypeAttr a, TypeAttr b) {
return a.to_int32() < b.to_int32();
}
private:
bitset_t bitset = 0;
friend class Index;
const static TypeAttr reserved;
static TypeAttr make_reserved() {
TypeAttr result;
result.bitset = 0x80000000;
return result;
}
}; // struct TypeAttr
inline const TypeAttr TypeAttr::null;
inline const TypeAttr TypeAttr::reserved = TypeAttr::make_reserved();
class QuantumNumbersAttr {
public:
constexpr QuantumNumbersAttr() noexcept = default;
const static QuantumNumbersAttr null;
explicit constexpr QuantumNumbersAttr(bitset_t bitset) noexcept
: bitset(bitset) {
assert((this->bitset & bitset::reserved) == bitset::null);
}
template <typename QN,
typename = std::enable_if_t<
meta::is_statically_castable_v<std::decay_t<QN>, bitset_t> &&
!std::is_same_v<std::decay_t<QN>, bool> &&
!std::is_same_v<std::decay_t<QN>, TypeAttr> &&
!std::is_same_v<std::decay_t<QN>, QuantumNumbersAttr>>>
constexpr QuantumNumbersAttr(QN &&value) noexcept
: bitset(static_cast<bitset_t>(std::forward<QN>(value))) {}
constexpr explicit operator int64_t() const {
return static_cast<int64_t>(bitset);
}
constexpr explicit operator bitset_t() const { return bitset; }
constexpr int32_t to_int32() const { return bitset; }
constexpr explicit operator bool() const { return bitset != 0; }
constexpr QuantumNumbersAttr xOr(QuantumNumbersAttr other) const {
return QuantumNumbersAttr(this->to_int32() ^ other.to_int32());
}
friend constexpr QuantumNumbersAttr operator^(const QuantumNumbersAttr a,
const QuantumNumbersAttr b) {
return a.xOr(b);
}
constexpr QuantumNumbersAttr unIon(QuantumNumbersAttr other) const {
return QuantumNumbersAttr(this->to_int32() | other.to_int32());
}
friend constexpr QuantumNumbersAttr operator|(const QuantumNumbersAttr a,
const QuantumNumbersAttr b) {
return a.unIon(b);
}
constexpr QuantumNumbersAttr intersection(QuantumNumbersAttr other) const {
return QuantumNumbersAttr(this->to_int32() & other.to_int32());
}
friend constexpr QuantumNumbersAttr operator&(const QuantumNumbersAttr a,
const QuantumNumbersAttr b) {
return a.intersection(b);
}
constexpr QuantumNumbersAttr operator~() const { return ~this->to_int32(); }
friend constexpr bool operator==(QuantumNumbersAttr lhs,
QuantumNumbersAttr rhs) {
return lhs.to_int32() == rhs.to_int32();
}
friend constexpr bool operator!=(QuantumNumbersAttr lhs,
QuantumNumbersAttr rhs) {
return !(lhs == rhs);
}
bool includes(QuantumNumbersAttr other) const {
return intersection(other) == other;
}
friend constexpr bool operator<(QuantumNumbersAttr lhs,
QuantumNumbersAttr rhs) {
return lhs.to_int32() < rhs.to_int32();
}
private:
bitset_t bitset = bitset::null;
friend class Index;
const static QuantumNumbersAttr reserved;
static QuantumNumbersAttr make_reserved() {
QuantumNumbersAttr result;
result.bitset = bitset::reserved;
return result;
}
}; // struct QuantumNumbersAttr
inline const QuantumNumbersAttr QuantumNumbersAttr::null;
inline const QuantumNumbersAttr QuantumNumbersAttr::reserved =
QuantumNumbersAttr::make_reserved();
class IndexSpace {
public:
struct Attr : TypeAttr, QuantumNumbersAttr {
Attr(TypeAttr type, QuantumNumbersAttr qns) noexcept
: TypeAttr(type), QuantumNumbersAttr(qns){};
Attr(int32_t type, int32_t qns) noexcept
: TypeAttr(type), QuantumNumbersAttr(qns){};
Attr() = default;
Attr(const Attr &) = default;
Attr(Attr &&) = default;
Attr &operator=(const Attr &) = default;
Attr &operator=(Attr &&) = default;
const static Attr null;
constexpr const TypeAttr &type() const {
return static_cast<const TypeAttr &>(*this);
}
constexpr TypeAttr &type() { return static_cast<TypeAttr &>(*this); }
constexpr const QuantumNumbersAttr &qns() const {
return static_cast<const QuantumNumbersAttr &>(*this);
}
constexpr QuantumNumbersAttr &qns() {
return static_cast<QuantumNumbersAttr &>(*this);
}
constexpr explicit operator int64_t() const {
return (static_cast<int64_t>(this->type()) << 32) +
static_cast<int64_t>(this->qns());
}
explicit operator bool() const {
return static_cast<bool>(this->type()) || static_cast<bool>(this->qns());
}
Attr unIon(Attr other) const {
return {this->type().unIon(other.type()), this->qns().unIon(other.qns())};
}
friend Attr operator|(Attr a, Attr b) { return a.unIon(b); }
Attr intersection(Attr other) const {
return Attr(this->type().intersection(other.type()),
this->qns().intersection(other.qns()));
}
friend Attr operator&(Attr a, Attr b) { return a.intersection(b); }
bool includes(Attr other) const {
return this->type().includes(other.type()) &&
this->qns().includes(other.qns());
}
constexpr bool operator==(Attr other) const {
return this->type() == other.type() && this->qns() == other.qns();
}
constexpr bool operator!=(Attr other) const { return !(*this == other); }
constexpr bool operator<(Attr other) const {
if (this->qns() == other.qns()) {
return this->type() < other.type();
} else {
return this->qns() < other.qns();
}
}
}; // struct Attr
using Type = TypeAttr;
using QuantumNumbers = QuantumNumbersAttr;
struct bad_key : std::invalid_argument {
bad_key() : std::invalid_argument("bad key") {}
template <typename S, typename = meta::EnableIfAllBasicStringConvertible<S>>
bad_key(S &&key)
: std::invalid_argument(std::string("bad key: ") +
sequant::to_string(key)) {}
};
struct KeyCompare {
using is_transparent = void;
bool operator()(const IndexSpace &a, const IndexSpace &b) const {
return a.base_key() < b.base_key();
}
bool operator()(const std::wstring &a, const IndexSpace &b) const {
return a < b.base_key();
}
bool operator()(const std::wstring_view &a, const IndexSpace &b) const {
return a < b.base_key();
}
bool operator()(const IndexSpace &a, const std::wstring &b) const {
return a.base_key() < b;
}
bool operator()(const IndexSpace &a, const std::wstring_view &b) const {
return a.base_key() < b;
}
bool operator()(const std::wstring &a, const std::wstring &b) const {
return a < b;
}
bool operator()(const std::wstring &a, const std::wstring_view &b) const {
return a < b;
}
bool operator()(const std::wstring_view &a, const std::wstring &b) const {
return a < b;
}
};
friend constexpr bool operator==(IndexSpace const &,
IndexSpace const &) noexcept;
friend constexpr bool operator!=(IndexSpace const &,
IndexSpace const &) noexcept;
friend constexpr bool operator<(IndexSpace const &,
IndexSpace const &) noexcept;
constexpr Attr attr() const noexcept { return attr_; }
constexpr Type type() const noexcept { return attr().type(); }
QuantumNumbers qns() const noexcept { return attr().qns(); }
IndexSpace() noexcept {}
const static IndexSpace null;
explicit operator bool() const { return *this != null; }
template <typename S, typename = meta::EnableIfAllBasicStringConvertible<S>>
IndexSpace(S &&type_label, TypeAttr typeattr,
QuantumNumbersAttr qnattr = QuantumNumbersAttr{0},
unsigned long approximate_size = 10)
: attr_(typeattr, qnattr),
base_key_(sequant::to_wstring(std::forward<S>(type_label))),
approximate_size_(approximate_size) {}
IndexSpace(const IndexSpace &other) = default;
IndexSpace(IndexSpace &&other) = default;
IndexSpace &operator=(const IndexSpace &other) = default;
IndexSpace &operator=(IndexSpace &&other) = default;
const std::wstring &base_key() const { return base_key_; }
static std::wstring_view reduce_key(std::wstring_view key) {
const auto underscore_position = key.rfind(L'_');
if (underscore_position != std::wstring::npos) { // key can be reduced
return key.substr(0, underscore_position);
} else {
return key;
}
}
static std::wstring reduce_key(std::string_view key) {
const auto underscore_position = key.rfind(L'_');
if (underscore_position != std::string::npos) { // key can be reduced
return sequant::to_wstring(key.substr(0, underscore_position));
} else {
return sequant::to_wstring(key);
}
}
std::size_t approximate_size() const { return approximate_size_; }
void approximate_size(size_t n) { approximate_size_ = n; }
private:
Attr attr_;
std::wstring base_key_;
std::size_t approximate_size_;
static std::wstring to_wstring(std::wstring_view key) {
return std::wstring(key.begin(), key.end());
}
}; // class IndexSpace
inline const IndexSpace IndexSpace::null;
inline const IndexSpace::Attr IndexSpace::Attr::null;
inline bool includes(IndexSpace::Type type1, IndexSpace::Type type2) {
return type1.includes(type2);
}
inline bool includes(IndexSpace::QuantumNumbers qns1,
IndexSpace::QuantumNumbers qns2) {
return qns1.includes(qns2);
}
inline bool includes(const IndexSpace &space1, const IndexSpace &space2) {
return space1.attr().includes(space2.attr());
}
[[nodiscard]] inline constexpr bool operator<(
const IndexSpace &space1, const IndexSpace &space2) noexcept {
return space1.attr() < space2.attr();
}
[[nodiscard]] inline constexpr bool operator==(
IndexSpace const &space1, IndexSpace const &space2) noexcept {
return space1.type() == space2.type() && space1.qns() == space2.qns() &&
space1.base_key() == space2.base_key();
}
[[nodiscard]] inline constexpr bool operator!=(
IndexSpace const &space1, IndexSpace const &space2) noexcept {
return !(space1 == space2);
}
} // namespace sequant
#endif // SEQUANT_SPACE_H