State vectors
StateVector
concept
Let us say we want to make type SV
a libcommutecompatible state
vector type so that linear operators can act on instances
of SV
. For this we have to make SV
model the StateVector
concept.
In a nutshell, a StateVector
type is a onedimensional array of numbers
(quantum amplitudes) allowing integer indexing and implementing a certain
interface. Elements of the array do not have to be stored contiguously.
Acceptable index values must be at least 64bit wide unsigned integers since
libcommute uses the following type for basis state indexing.

using sv_index_type = std::uint64_t
Defined in <libcommute/loperator/state_vector.hpp>
Type of basis state indices.
The table below shows the interface (a set of free functions and a
metafunction) that needs be implemented for an object sv of type
SV
.
libcommute provides an implementation of the StateVector
concept for
std::vector
(see <libcommute/loperator/state_vector.hpp>).
Function/metafunction 
Description 
Implementation for std::vector<T> 

element_type<SV>::type 
Type of the elements. 
T 
get_element(sv, n) 
Return the nth element of sv. 
sv[n] 
update_add_element(sv, n, value) 
Add a value of some type 
sv[n] += value or sv[n] = sv[n] + value The compoundassignment from type 
set_zeros(sv) 
Fill sv with zeros. 
std::fill(sv.begin(), sv.end(), zero). The zero value is created by make_const(0) as described in “Custom scalar types”. 
zeros_like(sv) 
Return an object of the same type and size as sv but filled with zeros. 
Creates a new object as std::vector<T>(sv.size(), zero). 
foreach(sv, f) 
Apply a functionlike object f to all basis state index/nonzero element pairs (n, a) in sv. 
In a forloop, calls f(n, a) for all nonzero elements a as detected by is_zero() (see “Custom scalar types”). 
Inclusion of <libcommute/loperator/state_vector_eigen3.hpp> makes some
Eigen 3 types (column vectors,
vector blocks,
columnlike matrix blocks and onedimensional Eigen::Map views)
compatible with the StateVector
concept as well.
Sparse state vector
sparse_state_vector
is a state vector that saves memory by storing only
the nonzero elements. It is essentially a wrapper around
std::unordered_map
modelling the StateVector
concept. Here, we show
only the part of its interface not covered by StateVector
.

template<typename ScalarType>
class sparse_state_vector State vector with a sparse storage of elements (quantum amplitudes). ScalarType is the type of the elements.

sparse_state_vector() = delete

sparse_state_vector(sv_index_type size)
Construct a zero (empty) sparse vector with a given size – dimension of the corresponding Hilbert space.

sv_index_type size() const
Size (dimension) of the vector.

ScalarType &operator[](sv_index_type n)
Access the nth element. If it is zero (missing from the storage), then a new valueinitialized element will be inserted and a reference to it will be returned.
Warning
Improper use of this method may result in zero elements being stored in the unordered map. Only the nonzero values should be assigned to the references returned by it.

sv_index_type n_nonzeros() const
Get the number of nonzero (stored) elements.

void prune()
Remove all zero elements (as defined by scalar_traits<ScalarType>::is_zero()) from the unordered map.

template<typename UnaryPredicate>
void prune(UnaryPredicate &&p) Remove unordered map elements (amplitudes) for which predicate p returns
true
.

sparse_state_vector() = delete
Mapped basis view
mapped_basis_view
is another utility type modelling the StateVector
concept. It is a view of a state vector, which translates basis state
index arguments of get_element()
and update_add_element()
according to a predefined map sv_index_type
> sv_index_type
.
The element access functions throw std::out_of_range
if their index
argument is missing from the map.
mapped_basis_view
can be used in situations
where a linear operator acts in a small subspace of
a full Hilbert space, and it is desirable to store vector components only within
that subspace. Such a situation naturally emerges when working with
invariant subspaces of operators.

template<typename StateVector, bool Ref = true>
class mapped_basis_view View of a
StateVector
object that translates basis state indices according to a certain mapping.StateVector
 type of the underlying state vector object. Defining a readonly view (such that prohibits update_add_element() operations) requires using aconst
qualified type here. For example, one can useStateVector = std::vector<double>
for a readwrite view, andStateVector = const std::vector<double>
for a readonly view.Ref
 by default,mapped_basis_view
stores a reference to the underlying state vector. Setting this option tofalse
will result in a copy being created and stored instead. This feature can be useful when the underlying type is already a viewlike object similar toEigen::Map
.
The mapped basis views should always be constructed by means of a special
factory class basis_mapper
and its methods
basis_mapper:: make_view()
/basis_mapper::make_const_view()
.

class basis_mapper
Factory class for
mapped_basis_view
.Constructors

basis_mapper(std::vector<sv_index_type> const &basis_state_indices)
Build a mapping from a list of basis states basis_state_indices to their positions within the list.
std::vector<sv_index_type> basis_indices{3, 5, 6}; basis_mapper mapper(basis_indices); // Views created by 'mapper' will translate basis state indices // according to // 0 > std::out_of_range // 1 > std::out_of_range // 2 > std::out_of_range // 3 > 0 // 4 > std::out_of_range // 5 > 1 // 6 > 2 // 7 > std::out_of_range // ...

template<typename HSType, typename LOpScalarType, int... LOpAlgebraIDs>
basis_mapper(loperator<LOpScalarType, LOpAlgebraIDs...> const &O, HSType const &hs) Build a mapping from a set of all basis states contributing to \(\hat O0\rangle\).
Operator O acts in the Hilbert space hs. \(0\rangle\) is the basis state with index 0 (‘vacuum’ state in the case of fermions and bosons). Mapped values are assigned continuously starting from 0 without any specific order.

template<typename HSType, typename LOpScalarType, int... LOpAlgebraIDs>
basis_mapper(std::vector<loperator<LOpScalarType, LOpAlgebraIDs...>> const &O_list, HSType const &hs, unsigned int N) Given a list of operators \(\{\hat O_1, \hat O_2, \hat O_3, \ldots, \hat O_M\}\), build a mapping from all basis states contributing to all states \(\hat O_1^{n_1} \hat O_2^{n_2} \ldots \hat O_M^{n_M} 0\rangle\), where \(n_m \geq 0\) and \(\sum_{m=1}^M n_M = N\).
Operators in O_list act in the Hilbert space hs. \(0\rangle\) is the basis state with index 0 (‘vacuum’ state in the case of fermions and bosons). Mapped values are assigned continuously starting from 0 without any specific order.
This constructor is useful to create a mapping from a fixedparticlenumber subspace of a fermionic/bosonic Hilbert space.
mapped_basis_view
factory functions
template<typename StateVector>
mapped_basis_view<StateVector> make_view(StateVector &&sv) const 
template<typename StateVector>
mapped_basis_view<StateVector const> make_const_view(StateVector &&sv) const Make a read/write or constant view of sv. Constant views will not be accepted by
update_add_element()
. If sv is not an lvalue reference, the resulting view will hold a copy of sv.Warning
To reduce memory footprint,
mapped_basis_view
objects store a reference to the basis index map owned by their parentbasis_mapper
object. For this reason, the views should never outlive the mapper.
Other methods

sv_index_type size() const
Number of elements in the index map.

std::unordered_map<sv_index_type, sv_index_type> const &map() const
Direct access to the underlying index map.

std::unordered_map<sv_index_type, sv_index_type> inverse_map() const
Build and return an inverse index map. Depending on map’s size, building the inverse can be an expensive operation. Calling this method on a noninvertible map is undefined behavior.

basis_mapper(std::vector<sv_index_type> const &basis_state_indices)
Nfermion sector views
There are two more specialized flavours of the basis mapping views called
\(N\)fermion sector views and \(N\)fermion multisector views. They
can come in handy when working with particlenumber preserving models of
fermions. If the model is large, then generating and storing a basis state index
map for mapped_basis_view
may become too expensive.

template<typename StateVector, bool Ref = true>
class n_fermion_sector_view Defined in <libcommute/loperator/n_fermion_sector_view.hpp>
View of a
StateVector
object that translates basis state indices from a full Hilbert space to its subspace (sector) with a fixed total occupation of fermionic degrees of freedom \(N\). The full Hilbert space does not have to be purely fermionic.n_fermion_sector_view
is generally less performant thanmapped_basis_view
in terms of the index translation speed. However, its required storage space scales only as \(O(M \min(N, M  N))\), where \(M\) is the total number of the fermionic degrees of freedom. This scaling law is much milder that the exponential growth of the sector size.StateVector
 type of the underlying state vector object. Defining a readonly view (such that prohibits update_add_element() operations) requires using aconst
qualified type here. For example, one can useStateVector = std::vector<double>
for a readwrite view, andStateVector = const std::vector<double>
for a readonly view.Ref
 by default,n_fermion_sector_view
stores a reference to the underlying state vector. Setting this option tofalse
will result in a copy being created and stored instead. This feature can be useful when the underlying type is already a viewlike object similar toEigen::Map
.
template<typename SV, typename HSType>
n_fermion_sector_view(SV &&sv, HSType const &hs, unsigned int N) Construct a view of the state vector sv, defined in the Nfermion sector of the full Hilbert space hs.

sv_index_type map_index(sv_index_type index) const
Translate a basis state index from the full Hilbert space to the sector.

template<typename SV, typename HSType>

template<typename HSType>
struct sector_descriptor Description of an \(N\)fermion sector defined over a subset of fermionic degrees of freedom.
HSType
 type of the full Hilbert space this sector belongs to.
std::set<typename HSType::index_types> indices
Set of indices corresponding to the relevant fermionic degrees of freedom.

unsigned int N
Total occupation of the sector.

std::set<typename HSType::index_types> indices

template<typename StateVector, bool Ref = true>
class n_fermion_multisector_view Defined in <libcommute/loperator/n_fermion_sector_view.hpp>
View of a
StateVector
object that translates basis state indices from a full Hilbert space to an \(N\)fermion multisector. A multisector is a set of all basis states, which have \(N_1\) particles within a subset of fermionic modes \(\{S_1\}\), \(N_2\) particles within another subset \(\{S_2\}\) and so on. There can be any number of individual pairs \((\{S_i\}, N_i)\) (sectors contributing to the multisector) as long as all subsets \(\{S_i\}\) are disjoint. The full Hilbert space does not have to be purely fermionic.n_fermion_multisector_view
is generally less performant thanmapped_basis_view
in terms of the index translation speed. However, its required storage space scales only as \(O(\sum_i M_i \min(N_i, M_i  N_i))\), where \(M_i = \{S_i\}\). This scaling law is much milder that the exponential growth of the multisector size.It is advised to use
n_fermion_sector_view
instead, if there is only one contributing sector that also spans all fermionic degrees of freedom.StateVector
 type of the underlying state vector object. Defining a readonly view (such that prohibits update_add_element() operations) requires using aconst
qualified type here. For example, one can useStateVector = std::vector<double>
for a readwrite view, andStateVector = const std::vector<double>
for a readonly view.Ref
 by default,n_fermion_multisector_view
stores a reference to the underlying state vector. Setting this option tofalse
will result in a copy being created and stored instead. This feature can be useful when the underlying type is already a viewlike object similar toEigen::Map
.
template<typename SV, typename HSType>
n_fermion_multisector_view(SV &&sv, HSType const &hs, std::vector<sector_descriptor<HSType>> const §ors) Construct a view of the state vector sv, defined in the \(N\)fermion multisector of the full Hilbert space hs. The multisector is defined via a list of contributing sectors (list of \((\{S_i\}, N_i)\) pairs).

sv_index_type map_index(sv_index_type index) const
Translate a basis state index from the full Hilbert space to the multisector.

template<typename SV, typename HSType>
Besides n_fermion_sector_view
and n_fermion_multisector_view
,
<libcommute/loperator/n_fermion_sector_view.hpp> defines a few supplemental
utility functions that help working with (multi)sectors.

template<typename StateVector, typename HSType>
auto make_nfs_view(StateVector &&sv, HSType const &hs, unsigned int N) 
template<typename StateVector, typename HSType>
auto make_const_nfs_view(StateVector &&sv, HSType const &hs, unsigned int N) Make and return a read/write or constant Nfermion sector view of sv within the full Hilbert space hs. If sv is not an lvalue reference, the resulting view will hold a copy of sv.

template<typename StateVector, typename HSType>
auto make_nfms_view(StateVector &&sv, HSType const &hs, std::vector<sector_descriptor<HSType>> const §ors) 
template<typename StateVector, typename HSType>
auto make_const_nfms_view(StateVector &&sv, HSType const &hs, std::vector<sector_descriptor<HSType>> const §ors) Make and return a read/write or constant \(N\)fermion multisector view of sv within the full Hilbert space hs. The multisector is defined via a list of contributing sectors (list of \((\{S_i\}, N_i)\) pairs). If sv is not an lvalue reference, the resulting view will hold a copy of sv.

template<typename HSType>
sv_index_type n_fermion_sector_size(HSType const &hs, unsigned int N) Size of the Nfermion sector within the full Hilbert space hs.

template<typename HSType>
sv_index_type n_fermion_multisector_size(HSType const &hs, std::vector<sector_descriptor<HSType>> const §ors) Size of the \(N\)fermion multisector within the full Hilbert space hs. The multisector is defined via a list of contributing sectors (list of \((\{S_i\}, N_i)\) pairs).

template<typename HSType>
std::vector<sv_index_type> n_fermion_sector_basis_states(HSType const &hs, unsigned int N) Build and return a list of basis state indices forming the Nfermion sector within the full Hilbert space hs. The order of the indices in the list is consistent with the results of
n_fermion_sector_view::map_index()
.auto basis_states = n_fermion_sector_basis_states(hs, N); auto view = n_fermion_sector_view(st, hs, N); for(sv_index_type n = 0; n < basis_states.size(); ++n) { view.map_index(basis_states[n]) == n; // true for all n }

template<typename HSType>
std::vector<sv_index_type> n_fermion_multisector_basis_states(HSType const &hs, std::vector<sector_descriptor<HSType>> const §ors) Build and return a list of basis state indices forming an \(N\)fermion multisector within the full Hilbert space hs. The multisector is defined via a list of contributing sectors (list of \((\{S_i\}, N_i)\) pairs). The order of the indices in the list is consistent with the results of
n_fermion_multisector_view::map_index()
.auto basis_states = n_fermion_multisector_basis_states(hs, sectors); auto view = n_fermion_multisector_view(st, hs, sectors); for(sv_index_type n = 0; n < basis_states.size(); ++n) { view.map_index(basis_states[n]) == n; // true for all n }