dynare/dynare++/tl/cc/permutation.cc

152 lines
3.8 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* Copyright © 2004 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 <http://www.gnu.org/licenses/>.
*/
#include "permutation.hh"
#include "tl_exception.hh"
/* This is easy, we simply apply the map in the fashion s∘m */
void
Permutation::apply(const IntSequence &src, IntSequence &tar) const
{
TL_RAISE_IF(src.size() != permap.size() || tar.size() != permap.size(),
"Wrong sizes of input or output in Permutation::apply");
for (int i = 0; i < permap.size(); i++)
tar[i] = src[permap[i]];
}
void
Permutation::apply(IntSequence &tar) const
{
IntSequence tmp(tar);
apply(tmp, tar);
}
void
Permutation::inverse()
{
IntSequence former(permap);
for (int i = 0; i < size(); i++)
permap[former[i]] = i;
}
/* Here we find a number of trailing indices which are identical with
the permutation. */
int
Permutation::tailIdentity() const
{
int i = permap.size();
while (i > 0 && permap[i-1] == i-1)
i--;
return permap.size() - i;
}
/* This calculates a map which corresponds to sorting in the following
sense: $(sorted s)∘m = s, where s is a given sequence.
We go through s and find an the same item in sorted s. We
construct the permap from the found pair of indices. We have to be
careful, to not assign to two positions in s the same position in
sorted s, so we maintain a bitmap flag, in which we remember
indices from the sorted s already assigned. */
void
Permutation::computeSortingMap(const IntSequence &s)
{
IntSequence srt(s);
srt.sort();
IntSequence flags(s.size(), 0);
for (int i = 0; i < s.size(); i++)
{
int j = 0;
while (j < s.size() && (flags[j] || srt[j] != s[i]))
j++;
TL_RAISE_IF(j == s.size(),
"Internal algorithm error in Permutation::computeSortingMap");
flags[j] = 1;
permap[i] = j;
}
}
PermutationSet::PermutationSet()
{
pers.emplace_back(1);
}
PermutationSet::PermutationSet(const PermutationSet &sp, int n)
: order(n), size(n*sp.size)
{
TL_RAISE_IF(n != sp.order+1,
"Wrong new order in PermutationSet constructor");
for (int i = 0; i < sp.size; i++)
for (int j = 0; j < order; j++)
pers.emplace_back(sp.pers[i], j);
}
std::vector<Permutation>
PermutationSet::getPreserving(const IntSequence &s) const
{
TL_RAISE_IF(s.size() != order,
"Wrong sequence length in PermutationSet::getPreserving");
std::vector<Permutation> res;
IntSequence tmp(s.size());
for (int i = 0; i < size; i++)
{
pers[i].apply(s, tmp);
if (s == tmp)
res.push_back(pers[i]);
}
return res;
}
PermutationBundle::PermutationBundle(int nmax)
{
nmax = std::max(nmax, 1);
generateUpTo(nmax);
}
const PermutationSet &
PermutationBundle::get(int n) const
{
if (n > static_cast<int>(bundle.size()) || n < 1)
{
TL_RAISE("Permutation set not found in PermutationSet::get");
return bundle[0];
}
else
return bundle[n-1];
}
void
PermutationBundle::generateUpTo(int nmax)
{
if (bundle.size() == 0)
bundle.emplace_back();
int curmax = bundle.size();
for (int n = curmax+1; n <= nmax; n++)
bundle.emplace_back(bundle.back(), n);
}