PermLib
|
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_