permlib  0.2.8
Library for permutation computations
include/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 { struct 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), m_isIdentity(false) {}
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 struct 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& cycleString) {
00175         typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
00176         boost::char_separator<char> sepCycles(",");
00177         tokenizer tokens(cycleString, sepCycles);
00178 
00179         for (dom_int i=0; i<m_perm.size(); ++i)
00180                 m_perm[i] = i;
00181         
00182 #ifdef PERMLIB_DEBUGMODE
00183         boost::dynamic_bitset<> seenIndices(m_perm.size());
00184 #endif
00185         
00186         for (tokenizer::iterator tok_iter = tokens.begin(); tok_iter != tokens.end(); ++tok_iter) {
00187                 std::stringstream ss(*tok_iter);
00188 
00189                 unsigned int first, last, temp;
00190                 ss >> first;
00191                 last = first;
00192 #ifdef PERMLIB_DEBUGMODE
00193                 BOOST_ASSERT( !seenIndices[first-1] );
00194                 seenIndices.set(first-1, 1);
00195 #endif
00196                 
00197                 while (ss >> temp) {
00198 #ifdef PERMLIB_DEBUGMODE
00199                         BOOST_ASSERT( !seenIndices[temp-1] );
00200                         seenIndices.set(temp-1, 1);
00201 #endif
00202                         m_perm[last-1] = temp-1;
00203                         last = temp;
00204                 }
00205                 m_perm[last-1] = first-1;
00206         }
00207 }
00208 
00209 
00210 inline Permutation::Permutation(dom_int n, const std::string & cycleString) 
00211         : m_perm(n), m_isIdentity(false) 
00212 {
00213         initFromCycleString(cycleString);
00214 }
00215 
00216 inline Permutation::Permutation(dom_int n, const char* cycleString) 
00217         : m_perm(n), m_isIdentity(false) 
00218 {
00219         initFromCycleString(std::string(cycleString));
00220 }
00221 
00222 
00223 inline Permutation::Permutation(const perm& p) 
00224         : m_perm(p), m_isIdentity(false) 
00225 { 
00226 #ifdef PERMLIB_DEBUGMODE
00227         // check that m_perm really is a permutation
00228         std::set<dom_int> values;
00229         for (dom_int i=0; i<m_perm.size(); ++i) {
00230                 const dom_int& v = m_perm[i];
00231                 BOOST_ASSERT( v < m_perm.size() );
00232                 values.insert(v);
00233         }
00234         BOOST_ASSERT( values.size() == m_perm.size() );
00235 #endif
00236 }
00237 
00238 inline Permutation Permutation::operator*(const Permutation &p) const {
00239         BOOST_ASSERT(p.m_perm.size() == m_perm.size());
00240 
00241         Permutation res(m_perm.size(), true);
00242         for (dom_int i=0; i<m_perm.size(); ++i) {
00243                 res.m_perm[i] = p.m_perm[m_perm[i]];
00244         }
00245         return res;
00246 }
00247 
00248 inline Permutation& Permutation::operator*=(const Permutation &p) {
00249         BOOST_ASSERT(p.m_perm.size() == m_perm.size());
00250         m_isIdentity = false;
00251         perm tmp(m_perm);
00252         
00253         for (dom_int i=0; i<m_perm.size(); ++i) {
00254                 tmp[i] = p.m_perm[m_perm[i]];
00255         }
00256         m_perm = tmp;
00257         
00258         return *this;
00259 }
00260 
00261 inline Permutation& Permutation::operator^=(const Permutation &p) {
00262         BOOST_ASSERT(p.m_perm.size() == m_perm.size());
00263         m_isIdentity = false;
00264         perm tmp(m_perm);
00265 
00266         for (dom_int i=0; i<m_perm.size(); ++i) {
00267                 m_perm[i] = tmp[p.m_perm[i]];
00268         }
00269         return *this;
00270 }
00271 
00272 inline Permutation Permutation::operator~() const {
00273         Permutation res(m_perm.size(), true);
00274         for (dom_int i=0; i<m_perm.size(); ++i) {
00275                 res.m_perm[m_perm[i]] = i;
00276         }
00277         return res;
00278 }
00279 
00280 inline Permutation& Permutation::invertInplace() {
00281         perm tmp(m_perm);
00282         for (dom_int i=0; i<m_perm.size(); ++i) {
00283                 m_perm[tmp[i]] = i;
00284         }
00285         return *this;
00286 }
00287 
00288 inline dom_int Permutation::operator%(dom_int val) const {
00289         for (dom_int i = 0; i < m_perm.size(); ++i) {
00290                 if (m_perm[i] == val)
00291                         return i;
00292         }
00293         // must not happen, we have a permutation!
00294         BOOST_ASSERT(false);
00295         return -1;
00296 }
00297 
00298 inline bool Permutation::isIdentity() const {
00299         if (m_isIdentity)
00300                 return true;
00301         for (dom_int i=0; i<m_perm.size(); ++i)
00302                 if (at(i) != i)
00303                         return false;
00304         return true;
00305 }
00306 
00307 inline std::list<std::pair<dom_int, unsigned int> > Permutation::cycles(bool includeTrivialCycles) const {
00308         boost::dynamic_bitset<> worked(m_perm.size());
00309         typedef std::pair<dom_int, unsigned int> CyclePair;
00310         std::list<CyclePair> cycleList;
00311         unsigned int cycleLength = 0;
00312         
00313         for (dom_int x=0; x<m_perm.size(); ++x) {
00314                 if (worked[x])
00315                         continue;
00316                 
00317                 dom_int px, startX;
00318                 worked.set(x, 1);
00319                 startX = x;
00320                 px = m_perm[x];
00321                 if (x == px) {
00322                         if (includeTrivialCycles)
00323                                 cycleList.push_back(CyclePair(x, 1));
00324                         continue;
00325                 }
00326                 
00327                 cycleLength = 2;
00328                 
00329                 while (m_perm[px] != startX) {
00330                                 worked.set(px, 1);
00331                                 px = m_perm[px];
00332                                 ++cycleLength;
00333                 }
00334                 worked.set(px, 1);
00335                 cycleList.push_back(CyclePair(startX, cycleLength));
00336         }
00337         
00338         return cycleList;
00339 }
00340 
00341 inline boost::uint64_t Permutation::order() const {
00342         typedef std::pair<dom_int, unsigned int> CyclePair;
00343         std::list<CyclePair> cycleList = this->cycles();
00344         boost::uint64_t ord = 1;
00345         BOOST_FOREACH(const CyclePair& cyc, cycleList) {
00346                 ord = boost::math::lcm(ord, static_cast<boost::uint64_t>(cyc.second));
00347         }
00348         return ord;
00349 }
00350 
00351 template<typename ForwardIterator>
00352 Permutation* Permutation::project(unsigned int n_proj, ForwardIterator begin, ForwardIterator end) const {
00353         std::map<dom_int, dom_int> projectionMap;
00354         dom_int c = 0;
00355         for (ForwardIterator it = begin; it != end; ++it) {
00356                 projectionMap[*it] = c++;
00357         }
00358         
00359         Permutation* proj = new Permutation(n_proj);
00360         bool is_identity = true;
00361         
00362         while (begin != end) {
00363                 dom_int x = *begin++;
00364                 BOOST_ASSERT( projectionMap.find(x) != projectionMap.end() );
00365                 BOOST_ASSERT( projectionMap.find(m_perm[x]) != projectionMap.end() );
00366                 const dom_int proj_x = projectionMap[x];
00367                 const dom_int proj_px = projectionMap[ m_perm[x] ];
00368                 BOOST_ASSERT( proj_x < n_proj );
00369                 BOOST_ASSERT( proj_px < n_proj );
00370                 proj->m_perm[ proj_x ] = proj_px;
00371                 
00372                 if (proj_x != proj_px)
00373                         is_identity = false;
00374         }
00375         
00376         proj->m_isIdentity = is_identity;
00377         
00378         return proj;
00379 }
00380 
00381 inline void Permutation::setTransposition(dom_int pos, dom_int val) {
00382         BOOST_ASSERT(pos < m_perm.size());
00383         BOOST_ASSERT(val < m_perm.size());
00384         
00385         m_perm[pos] = val;
00386         m_perm[val] = pos;
00387 }
00388 
00389 inline std::ostream& operator<<(std::ostream& out, const Permutation& p) {
00390         typedef std::pair<dom_int, unsigned int> CyclePair;
00391         bool output = false;
00392         
00393         std::list<CyclePair> cycleList = p.cycles();
00394         BOOST_FOREACH(const CyclePair& c, cycleList) {
00395                 dom_int px = p / c.first;
00396                 out << "(" << (c.first + 1) << ",";
00397                 while (px != c.first) {
00398                         out << (px+1);
00399                         px = p / px;
00400                         if (px == c.first)
00401                                  out << ")";
00402                         else
00403                                 out << ",";
00404                 }
00405                 output = true;
00406         }
00407         
00408         if (!output)
00409                 out << "()";
00410         
00411         return out;
00412 }
00413 
00414 }
00415 
00416 #endif // -- PERMUTATION_H_
 All Classes Functions Variables Typedefs Enumerations Friends