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

125 lines
3.1 KiB
C++

// Copyright (C) 2004-2011, Ondra Kamenik
#include "symmetry.hh"
#include "permutation.hh"
#include "tl_exception.hh"
#include <iostream>
/* This constructs an implied symmetry from a more general symmetry and
equivalence class. For example, let the general symmetry be $y^3u^2$ and the
equivalence class is $\{0,4\}$ picking up first and fifth variable, we
calculate symmetry corresponding to the picked variables. These are $yu$.
Thus the constructed sequence must be $(1,1)$, meaning that we picked one
$y$ and one $u$. */
Symmetry::Symmetry(const Symmetry &sy, const OrdSequence &cl)
: IntSequence(sy.num())
{
const std::vector<int> &se = cl.getData();
TL_RAISE_IF(sy.dimen() <= se[se.size()-1],
"Sequence is not reachable by symmetry in IntSequence()");
for (int i = 0; i < size(); i++)
operator[](i) = 0;
for (int i : se)
operator[](sy.findClass(i))++;
}
/* Find a class of the symmetry containing a given index. */
int
Symmetry::findClass(int i) const
{
int j = 0;
int sum = 0;
do
{
sum += operator[](j);
j++;
}
while (j < size() && sum <= i);
return j-1;
}
/* The symmetry is full if it allows for any permutation of indices. It
means, that there is at most one non-zero index. */
bool
Symmetry::isFull() const
{
int count = 0;
for (int i = 0; i < num(); i++)
if (operator[](i) != 0)
count++;
return count <= 1;
}
/* Construct a symiterator of given dimension, starting from the given
symmetry. */
symiterator::symiterator(int dim_arg, Symmetry run_arg)
: dim{dim_arg}, run(std::move(run_arg))
{
}
/* Here we move to the next symmetry. We do so only, if we are not at
the end. If length is 2, we increase lower index and decrease upper
index, otherwise we increase the subordinal symmetry. If we got to the
end, we recreate the subordinal symmetry set and set the subordinal
iterator to the beginning. */
symiterator &
symiterator::operator++()
{
if (run[0] == dim)
run[0]++; // Jump to the past-the-end iterator
else if (run.size() == 2)
{
run[0]++;
run[1]--;
}
else
{
symiterator subit{dim-run[0], Symmetry(run, run.size()-1)};
++subit;
if (run[1] == dim-run[0]+1)
{
run[0]++;
run[1] = 0;
/* subit is equal to the past-the-end iterator, so the range
2..(size()-1) is already set to 0 */
run[run.size()-1] = dim-run[0];
}
}
return *this;
}
InducedSymmetries::InducedSymmetries(const Equivalence &e, const Symmetry &s)
{
for (const auto & i : e)
emplace_back(s, i);
}
// |InducedSymmetries| permuted constructor code
InducedSymmetries::InducedSymmetries(const Equivalence &e, const Permutation &p,
const Symmetry &s)
{
for (int i = 0; i < e.numClasses(); i++)
{
auto it = e.find(p.getMap()[i]);
emplace_back(s, *it);
}
}
/* Debug print. */
void
InducedSymmetries::print() const
{
std::cout << "Induced symmetries: " << size() << std::endl;
for (unsigned int i = 0; i < size(); i++)
operator[](i).print();
}