dynare/dynare++/tl/cc/symmetry.hh

184 lines
5.2 KiB
C++

// Copyright 2004, Ondra Kamenik
// Symmetry.
/* Symmetry is an abstraction for a term of the form $y^3u^2$. It manages
only indices, not the variable names. So if one uses this
abstraction, he must keep in mind that $y$ is the first, and $u$ is
the second.
In fact, the symmetry is a special case of equivalence, but its
implementation is much simpler. We do not need an abstraction for the
term $yyuyu$ but due to Green theorem we can have term $y^3u^2$. That
is why the equivalence is too general for our purposes.
One of a main purposes of the tensor library is to calculate something like:
$$\left[B_{y^2u^3}\right]_{\alpha_1\alpha_2\beta_1\beta_2\beta_3}
=\left[g_{y^l}\right]_{\gamma_1\ldots\gamma_l}
\left(\sum_{c\in M_{l,5}}
\prod_{m=1}^l\left[g_{c_m}\right]^{\gamma_m}_{c_m(\alpha,\beta)}\right)$$
If, for instance, $l=3$, and $c=\{\{0,4\},\{1,2\},\{3\}\}$, then we
have to calculate
$$\left[g_{y^3}\right]_{\gamma_1\gamma_2\gamma_3}
\left[g_{yu}\right]^{\gamma_1}_{\alpha_1\beta_3}
\left[g_{yu}\right]^{\gamma_2}_{\alpha_2\beta_1}
\left[g_u\right]^{\gamma_3}_{\beta_2}
$$
We must be able to calculate a symmetry induced by symmetry $y^2u^3$
and by an equivalence class from equivalence $c$. For equivalence
class $\{0,4\}$ the induced symmetry is $yu$, since we pick first and
fifth variable from $y^2u^3$. For a given outer symmetry, the class
|InducedSymmetries| does this for all classes of a given equivalence.
We need also to cycle through all possible symmetries yielding the
given dimension. For this purpose we define classes |SymmetrySet| and
|symiterator|.
The symmetry is implemented as |IntSequence|, in fact, it inherits
from it. */
#ifndef SYMMETRY_H
#define SYMMETRY_H
#include "equivalence.hh"
#include "int_sequence.hh"
#include <list>
#include <vector>
#include <initializer_list>
#include <utility>
#include <memory>
/* Clear. The method |isFull| returns true if and only if the symmetry
allows for any permutation of indices.
WARNING: Symmetry(n) and Symmetry{n} are not the same. The former
initializes a symmetry of n elements, while the latter is a full symmetry of
order n. This is similar to the behaviour of std::vector. */
class Symmetry : public IntSequence
{
public:
// Constructor allocating a given length of (zero-initialized) data
explicit Symmetry(int len)
: IntSequence(len, 0)
{
}
/* Constructor using an initializer list, that gives the contents of the
Symmetry. Used for symmetries of the form $y^n$, $y^n u^m$, $y^nu^m\sigma^k$ */
Symmetry(std::initializer_list<int> init)
: IntSequence(std::move(init))
{
}
// Constructor of implied symmetry for a symmetry and an equivalence class
Symmetry(const Symmetry &s, const OrdSequence &cl);
/* Subsymmetry, which takes the given length of symmetry from the end (shares
data pointer) */
Symmetry(Symmetry &s, int len)
: IntSequence(s, s.size()-len, s.size())
{
}
int
num() const
{
return size();
}
int
dimen() const
{
return sum();
}
int findClass(int i) const;
bool isFull() const;
};
/* This is an iterator that iterates over all symmetries of given length and
dimension (see the SymmetrySet class for details).
The beginning iterator is (0, …, 0, dim).
Increasing it gives (0, … , 1, dim-1)
The just-before-end iterator is (dim, 0, …, 0)
The past-the-end iterator is (dim+1, 0, …, 0)
The constructor creates the iterator which starts from the given symmetry
symmetry (beginning). */
class symiterator
{
const int dim;
Symmetry run;
public:
symiterator(int dim_arg, Symmetry run_arg);
~symiterator() = default;
symiterator &operator++();
const Symmetry &
operator*() const
{
return run;
}
bool
operator=(const symiterator &it)
{
return dim == it.dim && run == it.run;
}
bool
operator!=(const symiterator &it)
{
return !operator=(it);
}
};
/* The class |SymmetrySet| defines a set of symmetries of the given length
having given dimension (i.e. it represents all the lists of integers of
length "len" and of sum equal to "dim"). It does not store all the
symmetries, it is just a convenience class for iteration.
The typical usage of the abstractions for |SymmetrySet| and
|symiterator| is as follows:
for (auto &si : SymmetrySet(6, 4))
It goes through all symmetries of lenght 4 having dimension 6. One can use
"si" as the symmetry in the body. */
class SymmetrySet
{
public:
const int len;
const int dim;
SymmetrySet(int dim_arg, int len_arg)
: len(len_arg), dim(dim_arg)
{
}
symiterator
begin() const
{
Symmetry run(len);
run[len-1] = dim;
return { dim, run };
}
symiterator
end() const
{
Symmetry run(len);
run[0] = dim+1;
return { dim, run };
}
};
/* This simple abstraction just constructs a vector of induced
symmetries from the given equivalence and outer symmetry. A
permutation might optionally permute the classes of the equivalence. */
class InducedSymmetries : public std::vector<Symmetry>
{
public:
InducedSymmetries(const Equivalence &e, const Symmetry &s);
InducedSymmetries(const Equivalence &e, const Permutation &p, const Symmetry &s);
void print() const;
};
#endif