PermLib

permutation.h

00001 // ---------------------------------------------------------------------------
00002 //
00003 //  This file is part of PermLib.
00004 //
00005 // Copyright (c) 2009-2011 Thomas Rehn <thomas@carmen76.de>
00006 // All rights reserved.
00007 // 
00008 // Redistribution and use in source and binary forms, with or without
00009 // modification, are permitted provided that the following conditions
00010 // are met:
00011 // 1. Redistributions of source code must retain the above copyright
00012 //    notice, this list of conditions and the following disclaimer.
00013 // 2. Redistributions in binary form must reproduce the above copyright
00014 //    notice, this list of conditions and the following disclaimer in the
00015 //    documentation and/or other materials provided with the distribution.
00016 // 3. The name of the author may not be used to endorse or promote products
00017 //    derived from this software without specific prior written permission.
00018 // 
00019 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00020 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00021 // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00022 // IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00023 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00024 // NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00025 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00026 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00027 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00028 // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029 //
00030 // ---------------------------------------------------------------------------
00031 
00032 
00033 #ifndef PERMUTATION_H_
00034 #define PERMUTATION_H_
00035 
00036 #include <permlib/common.h>
00037 
00038 // for I/O
00039 #include <string>
00040 #include <iostream>
00041 #include <boost/tokenizer.hpp>
00042 #include <sstream>
00043 #include <set>
00044 #include <list>
00045 #include <map>
00046 
00047 #include <boost/shared_ptr.hpp>
00048 #include <boost/dynamic_bitset.hpp>
00049 #include <boost/foreach.hpp>
00050 #include <boost/cstdint.hpp>
00051 #include <boost/math/common_factor_rt.hpp>
00052 
00053 namespace permlib {
00054 
00055 namespace exports { class BSGSSchreierExport; }
00056 
00058 class Permutation {
00059 public:
00061         typedef std::vector<dom_int> perm;
00062         
00064         typedef boost::shared_ptr<Permutation> ptr;
00065         
00067         explicit Permutation(dom_int n);
00069         Permutation(dom_int n, const std::string &cycles);
00071         Permutation(dom_int n, const char* cycles);
00073         explicit Permutation(const perm &p);
00075         Permutation(const Permutation &p) : m_perm(p.m_perm), m_isIdentity(p.m_isIdentity) {};
00077         template<class InputIterator>
00078         Permutation(InputIterator begin, InputIterator end) : m_perm(begin, end) {}
00079 
00081         Permutation operator*(const Permutation &p) const;
00083 
00086         Permutation& operator*=(const Permutation &p);
00088 
00091         Permutation& operator^=(const Permutation &p);
00093         Permutation operator~() const;
00095         Permutation& invertInplace();
00097         bool operator==(const Permutation &p2) const { return m_perm == p2.m_perm; };
00098 
00100         inline dom_int operator/(dom_int val) const { return at(val); }
00102         inline dom_int at(dom_int val) const { return m_perm[val]; }
00103 
00105         dom_int operator%(dom_int val) const;
00106 
00108         friend std::ostream &operator<< (std::ostream &out, const Permutation &p);
00109 
00111 
00114         bool isIdentity() const;
00116         inline void flush() {};
00118         inline dom_int size() const { return m_perm.size(); }
00119         
00121 
00125         std::list<std::pair<dom_int, unsigned int> > cycles(bool includeTrivialCycles = false) const;
00126         
00128 
00131         boost::uint64_t order() const;
00132         
00134 
00141         template<typename ForwardIterator>
00142         Permutation* project(unsigned int n_proj, ForwardIterator begin, ForwardIterator end) const;
00143         
00145         void setTransposition(dom_int pos, dom_int val);
00146 protected:
00148         perm m_perm;
00149 
00151         bool m_isIdentity;
00152 
00154         Permutation(dom_int n, bool) : m_perm(n), m_isIdentity(false) {}
00155         
00157         void initFromCycleString(const std::string& cycles);
00158         
00159         friend class permlib::exports::BSGSSchreierExport;
00160 };
00161 
00162 
00163 //
00164 //     ----       IMPLEMENTATION
00165 //
00166 
00167 inline Permutation::Permutation(dom_int n) 
00168         : m_perm(n), m_isIdentity(true) 
00169 {
00170         for (dom_int i=0; i<n; ++i)
00171                 m_perm[i] = i;
00172 }
00173 
00174 inline void Permutation::initFromCycleString(const std::string& cycles) {
00175         typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
00176         boost::char_separator<char> sepCycles(",");
00177         tokenizer tokens(cycles, sepCycles);
00178 
00179         for (dom_int i=0; i<m_perm.size(); ++i)
00180                 m_perm[i] = i;
00181 
00182         for (tokenizer::iterator tok_iter = tokens.begin(); tok_iter != tokens.end(); ++tok_iter) {
00183                 std::stringstream ss(*tok_iter);
00184 
00185                 unsigned int first, last, temp;
00186                 ss >> first;
00187                 last = first;
00188 
00189                 while (!ss.eof()) {
00190                         ss >> temp;
00191                         m_perm[last-1] = temp-1;
00192                         last = temp;
00193                 }
00194                 m_perm[last-1] = first-1;
00195         }
00196 }
00197 
00198 
00199 inline Permutation::Permutation(dom_int n, const std::string & cycles) 
00200         : m_perm(n), m_isIdentity(false) 
00201 {
00202         initFromCycleString(cycles);
00203 }
00204 
00205 inline Permutation::Permutation(dom_int n, const char* cycles) 
00206         : m_perm(n), m_isIdentity(false) 
00207 {
00208         initFromCycleString(std::string(cycles));
00209 }
00210 
00211 
00212 inline Permutation::Permutation(const perm& p) 
00213         : m_perm(p), m_isIdentity(false) 
00214 { 
00215 #ifdef PERMLIB_DEBUGMODE
00216         // check that m_perm really is a permutation
00217         std::set<dom_int> values;
00218         for (dom_int i=0; i<m_perm.size(); ++i) {
00219                 const dom_int& v = m_perm[i];
00220                 BOOST_ASSERT( v < m_perm.size() );
00221                 values.insert(v);
00222         }
00223         BOOST_ASSERT( values.size() == m_perm.size() );
00224 #endif
00225 }
00226 
00227 inline Permutation Permutation::operator*(const Permutation &p) const {
00228         BOOST_ASSERT(p.m_perm.size() == m_perm.size());
00229 
00230         Permutation res(m_perm.size(), true);
00231         for (dom_int i=0; i<m_perm.size(); ++i) {
00232                 res.m_perm[i] = p.m_perm[m_perm[i]];
00233         }
00234         return res;
00235 }
00236 
00237 inline Permutation& Permutation::operator*=(const Permutation &p) {
00238         BOOST_ASSERT(p.m_perm.size() == m_perm.size());
00239         m_isIdentity = false;
00240         
00241         for (dom_int i=0; i<m_perm.size(); ++i) {
00242                 m_perm[i] = p.m_perm[m_perm[i]];
00243         }
00244         return *this;
00245 }
00246 
00247 inline Permutation& Permutation::operator^=(const Permutation &p) {
00248         BOOST_ASSERT(p.m_perm.size() == m_perm.size());
00249         m_isIdentity = false;
00250         perm tmp(m_perm);
00251 
00252         for (dom_int i=0; i<m_perm.size(); ++i) {
00253                 m_perm[i] = tmp[p.m_perm[i]];
00254         }
00255         return *this;
00256 }
00257 
00258 inline Permutation Permutation::operator~() const {
00259         Permutation res(m_perm.size(), true);
00260         for (dom_int i=0; i<m_perm.size(); ++i) {
00261                 res.m_perm[m_perm[i]] = i;
00262         }
00263         return res;
00264 }
00265 
00266 inline Permutation& Permutation::invertInplace() {
00267         perm tmp(m_perm);
00268         for (dom_int i=0; i<m_perm.size(); ++i) {
00269                 m_perm[tmp[i]] = i;
00270         }
00271         return *this;
00272 }
00273 
00274 inline dom_int Permutation::operator%(dom_int val) const {
00275         for (dom_int i = 0; i < m_perm.size(); ++i) {
00276                 if (m_perm[i] == val)
00277                         return i;
00278         }
00279         // must not happen, we have a permutation!
00280         BOOST_ASSERT(false);
00281         return -1;
00282 }
00283 
00284 inline bool Permutation::isIdentity() const {
00285         if (m_isIdentity)
00286                 return true;
00287         for (dom_int i=0; i<m_perm.size(); ++i)
00288                 if (at(i) != i)
00289                         return false;
00290         return true;
00291 }
00292 
00293 inline std::list<std::pair<dom_int, unsigned int> > Permutation::cycles(bool includeTrivialCycles) const {
00294         boost::dynamic_bitset<> worked(m_perm.size());
00295         typedef std::pair<dom_int, unsigned int> CyclePair;
00296         std::list<CyclePair> cycles;
00297         unsigned int cycleLength = 0;
00298         
00299         for (dom_int x=0; x<m_perm.size(); ++x) {
00300                 if (worked[x])
00301                         continue;
00302                 
00303                 dom_int px, startX;
00304                 worked.set(x, 1);
00305                 startX = x;
00306                 px = m_perm[x];
00307                 if (x == px) {
00308                         if (includeTrivialCycles)
00309                                 cycles.push_back(CyclePair(x, 1));
00310                         continue;
00311                 }
00312                 
00313                 cycleLength = 2;
00314                 
00315                 while (m_perm[px] != startX) {
00316                                 worked.set(px, 1);
00317                                 px = m_perm[px];
00318                                 ++cycleLength;
00319                 }
00320                 worked.set(px, 1);
00321                 cycles.push_back(CyclePair(startX, cycleLength));
00322         }
00323         
00324         return cycles;
00325 }
00326 
00327 inline boost::uint64_t Permutation::order() const {
00328         typedef std::pair<dom_int, unsigned int> CyclePair;
00329         std::list<CyclePair> cycleList = this->cycles();
00330         boost::uint64_t ord = 1;
00331         BOOST_FOREACH(const CyclePair& cyc, cycleList) {
00332                 ord = boost::math::lcm(ord, static_cast<boost::uint64_t>(cyc.second));
00333         }
00334         return ord;
00335 }
00336 
00337 template<typename ForwardIterator>
00338 Permutation* Permutation::project(unsigned int n_proj, ForwardIterator begin, ForwardIterator end) const {
00339         std::map<dom_int, dom_int> projectionMap;
00340         dom_int c = 0;
00341         for (ForwardIterator it = begin; it != end; ++it) {
00342                 projectionMap[*it] = c++;
00343         }
00344         
00345         Permutation* proj = new Permutation(n_proj);
00346         bool isIdentity = true;
00347         
00348         while (begin != end) {
00349                 dom_int x = *begin++;
00350                 BOOST_ASSERT( projectionMap.find(x) != projectionMap.end() );
00351                 BOOST_ASSERT( projectionMap.find(m_perm[x]) != projectionMap.end() );
00352                 const dom_int proj_x = projectionMap[x];
00353                 const dom_int proj_px = projectionMap[ m_perm[x] ];
00354                 BOOST_ASSERT( proj_x < n_proj );
00355                 BOOST_ASSERT( proj_px < n_proj );
00356                 proj->m_perm[ proj_x ] = proj_px;
00357                 
00358                 if (proj_x != proj_px)
00359                         isIdentity = false;
00360         }
00361         
00362         proj->m_isIdentity = isIdentity;
00363         
00364         return proj;
00365 }
00366 
00367 inline void Permutation::setTransposition(dom_int pos, dom_int val) {
00368         BOOST_ASSERT(pos < m_perm.size());
00369         BOOST_ASSERT(val < m_perm.size());
00370         
00371         m_perm[pos] = val;
00372         m_perm[val] = pos;
00373 }
00374 
00375 inline std::ostream& operator<<(std::ostream& out, const Permutation& p) {
00376         typedef std::pair<dom_int, unsigned int> CyclePair;
00377         bool output = false;
00378         
00379         std::list<CyclePair> cycleList = p.cycles();
00380         BOOST_FOREACH(const CyclePair& c, cycleList) {
00381                 dom_int px = p / c.first;
00382                 out << "(" << (c.first + 1) << ",";
00383                 while (px != c.first) {
00384                         out << (px+1);
00385                         px = p / px;
00386                         if (px == c.first)
00387                                  out << ")";
00388                         else
00389                                 out << ",";
00390                 }
00391                 output = true;
00392         }
00393         
00394         if (!output)
00395                 out << "()";
00396         
00397         return out;
00398 }
00399 
00400 }
00401 
00402 #endif // -- PERMUTATION_H_