Algebra generators
Algebra generators, such as creation/annihilation operators \(c^\dagger\)/
\(c\) in fermionic and bosonic algebras, are atomic structural units of
any expression. Within libcommute’s framework, algebra generators are classes
derived from the abstract base libcommute::generator
. Every generator
carries an index sequence (possibly of zero length), and the respective
index types must be passed as template parameters to
libcommute::generator
. The index types must be less-comparable and
form strictly ordered sets so that tuples of the indices (index sequences) are
also less-comparable and form a strictly ordered set.
The few methods that derived classes have to override serve a multitude of purposes.
Assign a numerical ID shared by all generators of a particular algebra (fermions, bosons, spin operators or a user-defined algebra) and unique to that algebra.
Establish a canonical ordering of generators belonging to the same algebra.
Describe commutation/anti-commutation rules that can be used to simplify a product of two generators and to put them into the canonical order.
Describe further simplification rules applicable to products of 3 and more generators (currently, only one simplification of this kind is implemented).
Generators of different algebras always commute. In a canonically ordered product, generators are placed in the non-decreasing order of their algebra IDs.
The following table summarizes information about predefined generators.
Algebra |
Generator type |
Algebra ID |
---|---|---|
Fermions \(c^\dagger_i\)/\(c_i\) |
libcommute::generator_fermion |
libcommute::fermion |
Bosons \(a^\dagger_i\)/\(a_i\) |
libcommute::generator_boson |
libcommute::boson |
Spins \(S_\pm\)/\(S_z\) |
libcommute::generator_spin |
libcommute::spin |
User-defined algebra |
A class derived from |
>= libcommute::min_user_defined_algebra_id |
Integer constants fermion, boson, spin and min_user_defined_algebra_id mentioned in the 3rd column are defined in <libcommute/algebra_ids.hpp>.
-
static constexpr int fermion = -3
-
static constexpr int boson = -2
-
static constexpr int spin = -1
-
static constexpr int min_user_defined_algebra_id = 0
generator
: abstract base class for algebra generators
-
template<typename ...IndexTypes>
class generator Defined in <libcommute/expression/generator.hpp>
The abstract base class for algebra generator types.
IndexTypes
- types of indices carried by this generator.Member type aliases
-
using index_types = std::tuple<IndexTypes...>
Index tuple type.
-
using linear_function_t = linear_function<std::unique_ptr<generator>>
Linear combination of generators. This type is used by various methods dealing with transformations of generator products.
Constructor
Copy/move-constructors, assignments and destructor
-
virtual ~generator()
-
virtual std::unique_ptr<generator> clone() const = 0
Virtual copy-constructor. Makes a copy of this generator managed by a unique pointer.
Algebra ID
-
virtual int algebra_id() const = 0
Get the ID of the algebra this generator belongs to.
Index sequence
-
index_types const &indices() const
Read-only access to the index tuple carried by the generator.
Canonical ordering
-
protected virtual bool equal(generator const &g) const
-
protected virtual bool less(generator const &g) const
-
protected virtual bool greater(generator const &g) const
These methods can be overridden by the derived classes to establish the canonical order of g w.r.t. *this assuming both generators belong to the same algebra. The default implementation compares index tuples of *this and g.
-
friend bool operator==(generator const &g1, generator const &g2)
-
friend bool operator!=(generator const &g1, generator const &g2)
-
friend bool operator<(generator const &g1, generator const &g2)
-
friend bool operator>(generator const &g1, generator const &g2)
Comparison operators for a pair of generators. First, they compare algebra IDs of g1 and g2. If those are equal, g1.equal(g2), g1.less(g2) or g1.greater(g2) is called.
Product simplification/transformation
-
virtual double swap_with(generator const &g2, linear_function_t &f) const = 0
Given a pair of generators \(g_1\) (*this) and \(g_2\) such that \(g_1 > g_2\), swap_with() must signal what transformation \(g_1 g_2 \mapsto c g_2 g_1 + f(g)\) should be applied to the product \(g_1 g_2\) in order to put it into the canonical order. swap_with() returns the constant \(c\) and writes the linear function of generators \(f(g)\) into its second argument. \(c\) is allowed to be zero.
-
virtual bool simplify_prod(generator const &g2, linear_function_t &f) const
Given a pair of generators \(g_1\) (*this) and \(g_2\) such that \(g_1 g_2\) is in the canonical order (\(g_1 \leq g_2\)), optionally apply a simplifying transformation \(g_1 g_2 \mapsto f(g)\). If a simplification is actually possible, simplified_prod() must return true and write the linear function \(f(g)\) into its second argument. Otherwise return false.
The default implementation always returns false.
-
virtual bool reduce_power(int power, linear_function_t &f) const
Given a generator \(g_1\) (*this) and a power \(p > 2\) (power), optionally apply a simplifying transformation \(g_1^p \mapsto f(g)\). If a simplification is actually possible, reduce_power() must return true and write the linear function \(f(g)\) into its second argument. Otherwise return false.
The default implementation always returns false.
Note
Simplifications for \(p = 2\) must be carried out by simplify_prod().
Other methods
-
virtual void conj(linear_function_t &f)
Return the Hermitian conjugate of generator as a linear function of other generators (write the result into f). The default implementation returns the generator itself.
-
protected virtual std::ostream &print(std::ostream &os) const
Virtual stream output function to be overridden by the derived classes.
-
using index_types = std::tuple<IndexTypes...>
-
template<typename T>
struct linear_function Defined in <libcommute/utility.hpp>
A linear function of objects of type T with double coefficients,
\[f(x_1, \ldots, x_n) = c + c_1 x_1 + \ldots + c_n x_n.\]-
double const_term = 0;
Constant term \(c\).
-
linear_function() = default
Construct an identically vanishing function \(f(x_1, \ldots, x_n) = 0\).
-
linear_function(double const_term)
Construct a constant function \(f(x_1, \ldots, x_n) = c\).
-
linear_function(double const_term, Args&&... args)
Construct a linear function from a sequence of arguments \(c, x_1, c_1, x_2, c_2, \ldots, x_n, c_n\).
-
linear_function(double const_term, std::vector<std::pair<T, double>> terms)
Construct a linear function from a constant term and a list of pairs \((x_1, c_1), \ldots, (x_n, c_n)\).
-
void set(double const_term, Args&&... args)
Clear all terms and replace them with a sequence of arguments \(c, x_1, c_1, x_2, c_2, \ldots, x_n, c_n\).
-
bool vanishing() const
Is this linear function identically zero?
-
double const_term = 0;
Fermions
Fermionic algebra is generated by creation and annihilation operators \(c_i^\dagger\)/\(c_i\) with canonical anti-commutation relations
The canonical order is defined according to
where index sequences \(i_k\) satisfy \(i_1 < i_2 < i_3\). In other words,
Creation operators precede annihilation operators;
Creation operator with the smallest index sequence comes first;
Annihilation operator with the smallest index sequence comes last.
-
template<typename ...IndexTypes>
class generator_fermion : public generator<IndexTypes...> Defined in <libcommute/expression/generator_fermion.hpp>
Part of the interface not inherited from / identical to
libcommute::generator
.-
bool dagger() const
Returns true for \(c^\dagger\) and false for \(c\).
-
bool dagger() const
-
template<typename ...IndexTypes>
generator_fermion<IndexTypes...> static_indices::make_fermion(bool dagger, IndexTypes&&... indices) Defined in <libcommute/expression/generator_fermion.hpp>
Make a fermionic creation (dagger = true) or annihilation (dagger = false) operator with given indices.
-
template<typename ...IndexTypes>
generator_fermion<IndexTypes...> dynamic_indices::make_fermion(bool dagger, IndexTypes&&... indices) Defined in <libcommute/expression/generator_fermion.hpp>
Make a fermionic creation (dagger = true) or annihilation (dagger = false) operator with a given dynamic index sequence.
-
template<typename ...IndexTypes>
bool is_fermion(generator<IndexTypes...> const &gen) Defined in <libcommute/expression/generator_fermion.hpp>
Detect if gen points to a generator of the fermionic algebra.
using namespace libcommute::static_indices;
// Make c^\dagger_{1,up}
auto g = make_fermion(true, 1, "up");
// ...
// If 'g' is a fermionic generator, print whether it is a creation
// or annihilation operator.
if(is_fermion(g)) {
auto const& f = dynamic_cast<generator_fermion<int, std::string> const&>(g);
std::cout << (f.dagger() ? "creation" : "annihilation") << '\n';
}
Bosons
Bosonic algebra is generated by creation and annihilation operators \(a_i^\dagger\)/\(a_i\) with canonical commutation relations
The canonical order is defined according to
where index sequences \(i_k\) satisfy \(i_1 < i_2 < i_3\). In other words,
Creation operators precede annihilation operators;
Creation operator with the smallest index sequence comes first;
Annihilation operator with the smallest index sequence comes last.
-
template<typename ...IndexTypes>
class generator_boson : public generator<IndexTypes...> Defined in <libcommute/expression/generator_boson.hpp>
Part of the interface not inherited from / identical to
libcommute::generator
.-
bool dagger() const
Returns true for \(a^\dagger\) and false for \(a\).
-
bool dagger() const
-
template<typename ...IndexTypes>
generator_boson<IndexTypes...> static_indices::make_boson(bool dagger, IndexTypes&&... indices) Defined in <libcommute/expression/generator_boson.hpp>
Make a bosonic creation (dagger = true) or annihilation (dagger = false) operator with given indices.
-
template<typename ...IndexTypes>
generator_fermion<IndexTypes...> dynamic_indices::make_boson(bool dagger, IndexTypes&&... indices) Defined in <libcommute/expression/generator_boson.hpp>
Make a bosonic creation (dagger = true) or annihilation (dagger = false) operator with a given dynamic index sequence.
-
template<typename ...IndexTypes>
bool is_boson(generator<IndexTypes...> const &gen) Defined in <libcommute/expression/generator_boson.hpp>
Detect if gen points to a generator of the bosonic algebra.
using namespace libcommute::static_indices;
// Make a^\dagger_1
auto g = make_boson(true, 1);
// ...
// If 'g' is a bosonic generator, print whether it is a creation or
// annihilation operator.
if(is_boson(g)) {
auto const& b = dynamic_cast<generator_boson<int> const&>(g);
std::cout << (b.dagger() ? "creation" : "annihilation") << '\n';
}
Spins
libcommute supports algebra of spin operators for \(S = 1/2\) as well as for higher integer and half-integer spins. Generators of spin algebras with different \(S\) share the same algebra ID and are distinguished by an extra integer data member multiplicity equal to \(2S+1\). For a fixed \(S\) and a set of indices, the spin algebra is generated by the triplet of operators \(S_+\), \(S_-\) and \(S_z\) subject to the following commutation relations.
Note
Using \(S_\pm\) instead of \(S_x\), \(S_y\) as algebra generators
is beneficial because all coefficients in the commutation relations above are
real. \(S_x\)/\(S_y\) would necessitate the complex scalar types in
all libcommute::expression
objects.
The canonical order is defined according to
In other words,
Operators with lower \(S\) precede operators with higher \(S\).
Among operators with the same \(S\), the operator with the smallest index sequence comes first.
Among operators with the same \(S\) and index sequence, \(S_+\) comes first followed by \(S_-\) and eventually by \(S_z\).
-
enum spin_component : std::uint8_t
Component of spin operator.
-
enumerator plus = 0
\(S_+\).
-
enumerator minus = 1
\(S_-\).
-
enumerator z = 2
\(S_z\).
-
enumerator plus = 0
-
template<typename ...IndexTypes>
class generator_spin : public generator<IndexTypes...> Defined in <libcommute/expression/generator_spin.hpp>
Part of the interface not inherited from / identical to
libcommute::generator
.-
template<typename ...Args>
generator_spin(spin_component c, Args&&... indices) Construct generator \(S_+\), \(S_-\) or \(S_z\) for spin \(S=1/2\) with given indices.
-
template<typename ...Args>
generator_spin(double spin, spin_component c, Args&&... indices) Construct generator \(S_+\), \(S_-\) or \(S_z\) for spin spin with given indices.
-
double spin() const
Read-only access to generator’s spin \(S\).
-
int multiplicity() const
Read-only access to generator’s multiplicity \(2S+1\).
-
libcommute::spin_component component() const
Is this generator \(S_+\), \(S_-\) or \(S_z\)?
-
template<typename ...Args>
-
template<typename ...IndexTypes>
generator_spin<IndexTypes...> static_indices::make_spin(spin_component c, IndexTypes&&... indices) Defined in <libcommute/expression/generator_spin.hpp>
Make generator \(S_+\), \(S_-\) or \(S_z\) for spin \(S=1/2\) with given indices.
-
template<typename ...IndexTypes>
generator_spin<IndexTypes...> static_indices::make_spin(double spin, spin_component c, IndexTypes&&... indices) Defined in <libcommute/expression/generator_spin.hpp>
Make generator \(S_+\), \(S_-\) or \(S_z\) for spin spin with given indices.
-
template<typename ...IndexTypes>
generator_spin<dyn_indices> dynamic_indices::make_spin(spin_component c, IndexTypes&&... indices) Defined in <libcommute/expression/generator_spin.hpp>
Make generator \(S_+\), \(S_-\) or \(S_z\) for spin \(S=1/2\) with a given dynamic index sequence.
-
template<typename ...IndexTypes>
generator_spin<dyn_indices> libcommute::dynamic_indices::make_spin(double spin, libcommute::spin_component c, IndexTypes&&... indices) Defined in <libcommute/expression/generator_spin.hpp>
Make generator \(S_+\), \(S_-\) or \(S_z\) for spin spin with a given dynamic index sequence.
-
template<typename ...IndexTypes>
bool libcommute::is_spin(libcommute::generator<IndexTypes...> const &gen) Defined in <libcommute/expression/generator_spin.hpp>
Detect if gen points to a generator of the spin algebra.
using namespace libcommute::static_indices;
// Make S^{J=1}_{1,+}
auto g = make_spin(1.0, libcommute::plus, 1);
// ...
// If 'g' is a spin algebra generator, print its properties.
if(is_spin(g)) {
auto const& s = dynamic_cast<generator_spin<int> const&>(g);
std::cout << "J = " << s.spin() << '\n';
std::cout << "2J+1 = " << s.multiplicity() << '\n';
switch(s.component()) {
case libcommute::plus:
std::cout << "+\n";
break;
case libcommute::minus:
std::cout << "-\n";
break;
case libcommute::z:
std::cout << "z\n";
break;
}
}