|
permlib
0.2.8
Library for permutation computations
|
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_
1.7.6.1