1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
|
#pragma once
#include <stdexcept>
#include <vector>
/// \ingroup core
///
/// Generic permutation group material. Largely follows the notation of xperm to avoid
/// confusion.
///
/// Example: 1->4, 4->3, 3->1, 5->6, 6->5
///
/// Perm( 3, 2, 4, 1, 6, 5 )
/// Images( 4, 2, 1, 3, 6, 5 )
class PermutationException : std::logic_error {
public:
PermutationException(const std::string& ex) : std::logic_error(ex) {};
};
class Perm {
public:
std::vector<int> perm;
/// Find the permutation that takes [start1, end1> to [start2, end2>.
/// This will be available in 'perm' afterwards.
template<class iterator>
void find(iterator start1, iterator end1, iterator start2, iterator end2);
/// Apply the permutation 'perm' on the given range.
template<class iterator>
void apply(iterator start1, iterator end1);
};
class Images {
public:
std::vector<int> images;
/// Find the permutation that takes [start1, end1> to [start2, end2>.
template<class iterator>
void find(iterator start1, iterator end1, iterator start2, iterator end2);
};
template<class iterator>
void Perm::find(iterator start1, iterator end1, iterator start2, iterator end2)
{
perm.clear();
while(start2!=end2) {
auto it=start1;
int num=0;
while(it!=end1) {
if(*start2==*it) {
perm.push_back(num);
break;
}
++num;
++it;
}
if(it==end1)
throw PermutationException("Sets do not contain the same elements.");
++start2;
}
}
template<class iterator>
void Perm::apply(iterator start, iterator end)
{
typedef typename std::remove_reference<decltype(*start)>::type value_type;
std::vector<value_type> orig;
auto it=start;
while(it!=end) {
orig.push_back(*it);
++it;
}
// std::cerr << orig.size() << ", " << perm.size() << std::endl;
if(orig.size()!=perm.size()) {
std::cerr << "Perm::apply: orig.size()=" << orig.size() << ", "
<< "perm.size()=" << perm.size() << std::endl;
assert(orig.size()==perm.size());
}
for(unsigned int i=0; i<orig.size(); ++i) {
*start=orig[perm[i]];
++start;
}
}
template<class iterator>
void Images::find(iterator start1, iterator end1, iterator start2, iterator end2)
{
images.clear();
while(start1!=end1) {
auto it=start2;
int num=0;
while(it!=end2) {
if(*start1==*it) {
images.push_back(num);
break;
}
++num;
++it;
}
if(it==end2)
throw PermutationException("Sets do not contain the same elements.");
++start1;
}
}
|