First, we introduce basic definitions on the algebra of composite quantum systems, that is, when the state vector of the system is an element of a Hilbert space which is the direct product of elementary Hilbert spaces (by elementary we mean that it cannot be further decomposed as a direct product of more elementary Hilbert spaces):
(1)
The number of elementary Hilbert spaces (the number of quantum numbers of the system) is referred to throughout as the rank or arity (unary, binary, ternary, quaternary, etc.) of the system.
Via an example we define state-vector slices:
(2)
A state-vector slice is defined by the retained index positions , which define the subsystem, and the “dummy” indices . In situations when slicing occurs in the framework, the set of retained index positions is an information available at compile time, while the set of dummy indices is an information becoming available only at runtime.
Slicing is fully recursive in that a state-vector slice behaves exactly as a state vector, only with a lower rank. It can even be further sliced. It is in particular true that
(3)
Via an example we define canonical operator extensions:
(4)
When the numbers in the angular brackets are permutations of a sequence of ordinals, this is in fact not even an extension, only a permutation of the underlying elementary Hilbert spaces.
Matrix elements of the operator in extended Hilbert spaces can then be calculated by acting with the (possibly permutated) original operator on an appropriate vector slice:
(5)
Due to the abovementioned recursiveness, the state vector of a composite quantum system is most conveniently represented as a complex (dcomp) multi-array. For a definition of the multi-array concept cf. the Boost.MultiArray manual.
By virtue of its adequacy for numerics and its efficiency, we have chosen the Array class from the Blitz++ library to represent state vectors on the lowest level in the framework.
See also
In utils, our collection of general-purpose modules, we rely on the template alias TTD_CArray, while in higher levels of the framework we use the more intuitive name StateVectorLow.
The name of the namespace stands for BlitzArraySliceIterator.
Template argument definitions
Compile-time vector holding the retained index positions like in (4).
Example models: tmptools::Vector and mpl::range_c from Boost.MPL.
mpl::size<V>::value must not be larger than RANK. V must not “contain” negative values, values not smaller than RANK, and duplicate values. These are checked for at compile time, and any violation is signalled by more or less intelligent compiler errors generated with the help of Boost.MPL’s static assertions.
template <int RANK, typename V, bool IS_CONST> (cf. template parameters)
Model of ForwardIterator.
This is equivalent to
TTD_CArray<RANK-mpl::size<V>::value>
when IS_CONST is false and
const TTD_CArray<RANK-mpl::size<V>::value>
when it is true. Iterator can be both const and non-const iterator depending on the last template argument.
This iterator is implemented in terms of a MultiIndexIterator, and hence it can be initialized to be either the beginning or the end of the “sequence”.
This class is at the absolute heart of the framework as it is indispensable to implement
This said, it is never really used directly in the framework, but rather through the maker functions below in standard or Boost.Range algorithms.
Quite generally, by iterating through all the combinations of indeces not belonging to the given subsystem (dummy indeces) and when dereferenced returning the corresponding slice, it can be used to implement the action of operators in extended (and/or permutated) Hilbert spaces.
Semantics
Sticking to the example in (5) above, assume that the function
void actWithA(TTD_CArray<5>&);
implements the action of the operator on a state vector of rank 5. Then the action on the extended Hilbert space can be calculated as
void actOnExtended(TTD_CArray<11>& psi)
{
boost::for_each(blitzplusplus::basi::fullRange(psi,
tmptools::Vector<3,6,1,9,7>()),
actWithA);
}
The value returned by fullRange() is a Boost.Range-compliant range, a full range of slice iterators corresponding to all the possible combinations of dummy indices (), and for_each is the range algorithm from Boost.Range.
For further basic examples of usage cf. C++Utils/testsuite/BlitzArraySliceIterator.cc.
Maker functions
Iterator‘s maker functions intelligently dispatch the constness of the Array:
template <typename A, typename V> for all these functions (cf. template parameters)
Here, the following template aliases are in effect:
template <typename A, typename V> using IterC=Iterator<A::_bz_rank,V,true >;
template <typename A, typename V> using Iter =Iterator<A::_bz_rank,V,false>;
template <typename A, typename V> using RangeC=boost::iterator_range<IterC<A,V> >
template <typename A, typename V> using Range =boost::iterator_range<Iter <A,V> >
the trailing dummy argument V is present for allowing template-parameter deduction
The following two classes are mainly helpers for Iterator, but sometimes are used on their own as well, so they are exposed in the header file:
template <int RANK, typename V> (cf. template parameters)
The returned reference simply equals the function argument.
Transposition corresponds to the “possible permutation” mentioned before Eq. (5), and is necessary in order that be the corresponding state vector slice, since this is how it is expected in applications. Cf. Composite for further explanations.
Semantics
static const int RANK=11;
TTD_CArray<RANK> psi;
typedef tmptools::Vector<3,6,1,9,7> Vec;
Transposer<RANK,Vec>::transpose(psi);
is equivalent to
psi.transposeSelf(0,3,2,6,4,5,1,9,8,7,10);
that is, in place of the indeces specified by the elements of the compile-time vector Vec, the elements of Vec are put, but in the order specified by Vec.
template <int RANK, typename V> (cf. template parameters)
The returned reference simply equals the second function argument.
Here the following local template aliases are in effect:
template <typename V>:
template <typename V> using TTD_ResCArray=TTD_CArray<mpl::size<V>::value>
template <int RANK, typename V>:
template <int RANK, typename V> using TTD_VecIdxTiny=TTD_IdxTiny<RANK-mpl::size<V>::value>
Semantics
static const int RANK=11;
TTD_CArray<RANK> psi;
typedef tmptools::Vector<3,6,1,9,7> Vec;
TTD_ResCArray<VEC> psiRes;
TTD_VecIdxTiny<RANK,VEC> idxTiny;
Indexer<RANK,Vec>::index(psi,psiRes,idxTiny);
is equivalent to
const blitz::Range a(blitz::Range::all());
psiRes.reference(psi(0,a,2,a,4,5,a,a,8,a,10));
As a function of the arity of slices (size of V) cf. C++Utils/testsuite/BlitzArraySliceIterator.cc 5th test case.