143 lines
3.8 KiB
C++
143 lines
3.8 KiB
C++
|
/*
|
|||
|
* Copyright © 2004-2011 Ondra Kamenik
|
|||
|
* Copyright © 2019 Dynare Team
|
|||
|
*
|
|||
|
* This file is part of Dynare.
|
|||
|
*
|
|||
|
* Dynare is free software: you can redistribute it and/or modify
|
|||
|
* it under the terms of the GNU General Public License as published by
|
|||
|
* the Free Software Foundation, either version 3 of the License, or
|
|||
|
* (at your option) any later version.
|
|||
|
*
|
|||
|
* Dynare is distributed in the hope that it will be useful,
|
|||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|||
|
* GNU General Public License for more details.
|
|||
|
*
|
|||
|
* You should have received a copy of the GNU General Public License
|
|||
|
* along with Dynare. If not, see <https://www.gnu.org/licenses/>.
|
|||
|
*/
|
|||
|
|
|||
|
#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³u² 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();
|
|||
|
}
|