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 BSGS_H_ 00034 #define BSGS_H_ 00035 00036 #include <map> 00037 #include <list> 00038 #include <vector> 00039 00040 #include <boost/cstdint.hpp> 00041 #include <boost/foreach.hpp> 00042 #include <boost/scoped_ptr.hpp> 00043 #include <boost/shared_ptr.hpp> 00044 #include <boost/utility.hpp> 00045 00046 #include <permlib/bsgs_core.h> 00047 00048 #include <permlib/transversal/orbit_set.h> 00049 #include <permlib/transversal/transversal.h> 00050 #include <permlib/predicate/pointwise_stabilizer_predicate.h> 00051 #include <permlib/predicate/stabilizes_point_predicate.h> 00052 00053 #include <permlib/redundant_base_point_insertion_strategy.h> 00054 00055 namespace permlib { 00056 00057 template <class PERM, class TRANS> 00058 struct BSGS; 00059 00060 template <class PERM, class TRANS> 00061 std::ostream &operator<< (std::ostream &out, const BSGS<PERM,TRANS> &bsgs) { 00062 out << "BASE[" << bsgs.B.size() << "]" << std::endl; 00063 BOOST_FOREACH(unsigned long beta, bsgs.B) { 00064 out << static_cast<unsigned int>(beta+1) << ","; 00065 } 00066 out << std::endl; 00067 out << "SGS[" << bsgs.S.size() << "]" << std::endl; 00068 BOOST_FOREACH(const typename PERM::ptr &g, bsgs.S) { 00069 out << *g << ","; 00070 } 00071 out << std::endl; 00072 out << "U" << std::endl; 00073 BOOST_FOREACH(const TRANS &U, bsgs.U) { 00074 for (unsigned int i=0; i<bsgs.n; ++i) 00075 // trigger transversal depth reload 00076 boost::scoped_ptr<PERM> dummy(U.at(i)); 00077 out << U.size() << "{" << U.m_statMaxDepth << "}" << ","; 00078 } 00079 out << " = " << bsgs.order() << std::endl; 00080 BOOST_FOREACH(const TRANS &U, bsgs.U) { 00081 out << U << std::endl; 00082 } 00083 return out; 00084 } 00085 00087 template <class PERM, class TRANS> 00088 struct BSGS : public BSGSCore<PERM,TRANS> { 00089 typedef typename BSGSCore<PERM,TRANS>::PERMlist PERMlist; 00090 00092 explicit BSGS(dom_int n); 00094 00098 BSGS(const BSGS<PERM,TRANS>& bsgs); 00099 00101 00105 BSGS<PERM,TRANS>& operator=(const BSGS<PERM,TRANS>&); 00106 00108 00111 template<typename Integer> 00112 Integer order() const; 00113 00115 00118 boost::uint64_t order() const; 00119 00121 00126 unsigned int sift(const PERM& g, PERM& siftee, unsigned int j = 0) const; 00128 00134 unsigned int sift(const PERM& g, PERM& siftee, unsigned int j, unsigned int k) const; 00136 bool sifts(const PERM& g) const; 00137 00139 00145 bool chooseBaseElement(const PERM &h, dom_int &beta) const; 00147 00152 unsigned int insertRedundantBasePoint(unsigned int beta, unsigned int minPos = 0); 00154 void stripRedundantBasePoints(int minPos = 0); 00155 00157 00164 void stripRedundantStrongGenerators(); 00165 00167 00170 void orbit(unsigned int j, const PERMlist &generators); 00172 00175 void orbitUpdate(unsigned int j, const PERMlist &generators, const typename PERM::ptr &g); 00176 00178 00183 int insertGenerator(const typename PERM::ptr& g, bool updateOrbit); 00185 00189 void updateOrbits(int pos); 00190 00192 00195 PERM random(const int i = 0) const; 00196 00198 00202 void conjugate(const PERM& g); 00203 00205 friend std::ostream &operator<< <> (std::ostream &out, const BSGS<PERM,TRANS> &bsgs); 00206 private: 00208 template <class BaseIterator, class TransversalIterator> 00209 unsigned int sift(const PERM& g, PERM& siftee, BaseIterator begin, BaseIterator end, TransversalIterator beginT, TransversalIterator endT) const; 00210 00212 static int ms_bsgsId; 00213 00215 void copyTransversals(const BSGS<PERM,TRANS>& bsgs); 00216 }; 00217 00218 // 00219 // ---- IMPLEMENTATION 00220 // 00221 00222 template <class PERM, class TRANS> 00223 int BSGS<PERM,TRANS>::ms_bsgsId = 0; 00224 00225 template <class PERM, class TRANS> 00226 BSGS<PERM,TRANS>::BSGS(dom_int n_) 00227 : BSGSCore<PERM,TRANS>(++ms_bsgsId, n_, 0) 00228 {} 00229 00230 template <class PERM, class TRANS> 00231 BSGS<PERM,TRANS>::BSGS(const BSGS<PERM,TRANS>& bsgs) 00232 : BSGSCore<PERM,TRANS>(bsgs.m_id, bsgs.B, bsgs.U, bsgs.n) 00233 { 00234 copyTransversals(bsgs); 00235 } 00236 00237 template <class PERM, class TRANS> 00238 BSGS<PERM,TRANS>& BSGS<PERM,TRANS>::operator=(const BSGS<PERM,TRANS>& bsgs) { 00239 if (this == &bsgs) 00240 return *this; 00241 00242 this->B = bsgs.B; 00243 this->n = bsgs.n; 00244 this->m_id = bsgs.m_id; 00245 00246 copyTransversals(bsgs); 00247 return *this; 00248 } 00249 00250 template <class PERM, class TRANS> 00251 template <class BaseIterator, class TransversalIterator> 00252 unsigned int BSGS<PERM, TRANS>::sift(const PERM& g, PERM& siftee, BaseIterator begin, BaseIterator end, TransversalIterator beginT, TransversalIterator endT) const{ 00253 unsigned int k = 0; 00254 siftee = g; 00255 BaseIterator baseIt; 00256 TransversalIterator transIt; 00257 for (baseIt = begin, transIt = beginT; baseIt != end && transIt != endT; ++baseIt, ++transIt) { 00258 unsigned long b = *baseIt; 00259 const TRANS& U_i = *transIt; 00260 //std::cout << " ~~~ sift " << siftee << " b" << b << std::endl; 00261 boost::scoped_ptr<PERM> u_b(U_i.at(siftee / b)); 00262 if (u_b == 0) 00263 return k; 00264 u_b->invertInplace(); 00265 siftee *= *u_b; 00266 ++k; 00267 } 00268 return k; 00269 } 00270 00271 template <class PERM, class TRANS> 00272 unsigned int BSGS<PERM, TRANS>::sift(const PERM& g, PERM& siftee, unsigned int j) const { 00273 return sift(g, siftee, this->B.begin() + j, this->B.end(), this->U.begin() + j, this->U.end()); 00274 } 00275 00276 template <class PERM, class TRANS> 00277 unsigned int BSGS<PERM, TRANS>::sift(const PERM& g, PERM& siftee, unsigned int j, unsigned int k) const { 00278 return sift(g, siftee, this->B.begin() + j, this->B.begin() + k, this->U.begin() + j, this->U.begin() + k); 00279 } 00280 00281 template <class PERM, class TRANS> 00282 bool BSGS<PERM, TRANS>::sifts(const PERM& g) const { 00283 PERM siftee(this->n); 00284 unsigned int m = sift(g, siftee); 00285 return this->B.size() == m && siftee.isIdentity(); 00286 } 00287 00288 template <class PERM, class TRANS> 00289 bool BSGS<PERM, TRANS>::chooseBaseElement(const PERM &h, dom_int &beta) const { 00290 for (beta = 0; beta < this->n; ++beta) { 00291 if (std::find(this->B.begin(), this->B.end(), beta) != this->B.end()) 00292 continue; 00293 if (h / beta != beta) 00294 return true; 00295 } 00296 return false; 00297 } 00298 00299 template <class PERM, class TRANS> 00300 void BSGS<PERM, TRANS>::orbit(unsigned int j, const PERMlist &generators) { 00301 this->U[j].orbit(this->B[j], generators); 00302 } 00303 00304 template <class PERM, class TRANS> 00305 void BSGS<PERM, TRANS>::orbitUpdate(unsigned int j, const PERMlist &generators, const typename PERM::ptr &g) { 00306 this->U[j].orbitUpdate(this->B[j], generators, g); 00307 } 00308 00309 template <class PERM, class TRANS> 00310 PERM BSGS<PERM, TRANS>::random(const int i) const { 00311 BOOST_ASSERT( i >= 0 ); 00312 PERM g(this->n); 00313 for (int l = this->U.size()-1; l>=i ; --l) { 00314 //std::cout << l << " : " << U[l] << " : " << U[l].size() << std::endl; 00315 unsigned long beta = *(boost::next(this->U[l].begin(), randomInt(this->U[l].size()))); 00316 boost::scoped_ptr<PERM> u_beta(this->U[l].at(beta)); 00317 g *= *u_beta; 00318 } 00319 return g; 00320 } 00321 00322 template <class PERM, class TRANS> 00323 void BSGS<PERM, TRANS>::conjugate(const PERM& g) { 00324 PERM gInv(g); 00325 gInv.invertInplace(); 00326 00327 // 00328 // to conjugate a BSGS, all three components (B,S,U) have to be adjusted 00329 // 00330 00331 // STEP 1: conjugate generating set S 00332 BOOST_FOREACH(typename PERM::ptr& p, this->S) { 00333 *p ^= gInv; 00334 *p *= g; 00335 } 00336 00337 std::vector<dom_int> oldB(this->B); 00338 for (unsigned int i = 0; i < this->U.size(); ++i) { 00339 // STEP 2: adapt base B 00340 this->B[i] = g / oldB[i]; 00341 // STEP 3: conjugate transversal U 00342 this->U[i].permute(g, gInv); 00343 } 00344 } 00345 00346 template <class PERM, class TRANS> 00347 int BSGS<PERM, TRANS>::insertGenerator(const typename PERM::ptr& g, bool updateOrbit) { 00348 int pos = 0; 00349 for (; static_cast<unsigned int>(pos) < this->B.size(); ++pos) { 00350 if (*g / this->B[pos] != this->B[pos]) 00351 break; 00352 } 00353 00354 if (static_cast<unsigned int>(pos) == this->B.size()) { 00355 dom_int beta; 00356 bool newBaseElement __attribute__((unused)) = chooseBaseElement(*g, beta); 00357 BOOST_ASSERT( newBaseElement ); 00358 this->B.push_back(beta); 00359 this->U.push_back(TRANS(this->n)); 00360 } 00361 00362 const int insertionPosition = pos; 00363 this->S.push_back(g); 00364 00365 if (updateOrbit) { 00366 bool groupOrderChanged = false; 00367 for (; pos >= 0; --pos) { 00368 PERMlist orbitGenerators; 00369 const unsigned int oldTransversalSize = this->U[pos].size(); 00370 //std::cout << "INSERT orbit @ " << pos << " : " << g << std::endl; 00371 std::copy_if(this->S.begin(), this->S.end(), std::back_inserter(orbitGenerators), 00372 PointwiseStabilizerPredicate<PERM>(this->B.begin(), this->B.begin() + pos)); 00373 if (orbitGenerators.size() > 0) { 00374 orbitUpdate(pos, orbitGenerators, g); 00375 00376 // group order can only increase by adding generators 00377 if (this->U[pos].size() > oldTransversalSize) 00378 groupOrderChanged = true; 00379 } 00380 } 00381 00382 if (!groupOrderChanged) { 00383 this->S.pop_back(); 00384 return -1; 00385 } 00386 } 00387 00388 return insertionPosition; 00389 } 00390 00391 template <class PERM, class TRANS> 00392 void BSGS<PERM, TRANS>::updateOrbits(int pos) { 00393 if (pos < 0) 00394 return; 00395 for (; pos >= 0; --pos) { 00396 PERMlist orbitGenerators; 00397 std::copy_if(this->S.begin(), this->S.end(), std::back_inserter(orbitGenerators), 00398 PointwiseStabilizerPredicate<PERM>(this->B.begin(), this->B.begin() + pos)); 00399 if (orbitGenerators.size() > 0) 00400 orbit(pos, orbitGenerators); 00401 } 00402 } 00403 00404 template <class PERM, class TRANS> 00405 template <typename Integer> 00406 Integer BSGS<PERM, TRANS>::order() const { 00407 Integer orderValue(1); 00408 BOOST_FOREACH(const TRANS &Ui, this->U) { 00409 orderValue *= Ui.size(); 00410 } 00411 return orderValue; 00412 } 00413 00414 template <class PERM, class TRANS> 00415 boost::uint64_t BSGS<PERM, TRANS>::order() const { 00416 return order<boost::uint64_t>(); 00417 } 00418 00419 00420 template <class PERM, class TRANS> 00421 unsigned int BSGS<PERM, TRANS>::insertRedundantBasePoint(unsigned int beta, unsigned int minPos) { 00422 PERMlist S_i; 00423 TrivialRedundantBasePointInsertionStrategy<PERM,TRANS> is(*this); 00424 int pos = is.findInsertionPoint(beta, S_i); 00425 if (pos < 0) 00426 return -(pos+1); 00427 pos = std::max(static_cast<unsigned int>(pos), minPos); 00428 00429 this->B.insert(this->B.begin() + pos, beta); 00430 this->U.insert(this->U.begin() + pos, TRANS(this->n)); 00431 this->U[pos].orbit(beta, S_i); 00432 return pos; 00433 } 00434 00435 template <class PERM, class TRANS> 00436 void BSGS<PERM, TRANS>::stripRedundantBasePoints(int minPos) { 00437 for (int i = this->B.size()-1; i >= minPos; --i) { 00438 if (this->U[i].size() <= 1) { 00439 if (i == static_cast<int>(this->B.size()-1)) { 00440 this->B.pop_back(); 00441 this->U.pop_back(); 00442 } else { 00443 this->B.erase(this->B.begin() + i); 00444 this->U.erase(this->U.begin() + i); 00445 } 00446 } 00447 } 00448 } 00449 00450 00452 00456 template <class PERM> 00457 class StrongGeneratingSetSorter : public std::binary_function<typename PERM::ptr, typename PERM::ptr, bool> { 00458 public: 00463 template<class InputIterator> 00464 StrongGeneratingSetSorter(InputIterator baseBegin, InputIterator baseEnd) : m_base(baseBegin, baseEnd) { } 00465 00467 bool operator()(const typename PERM::ptr& p1, const typename PERM::ptr& p2) const { 00468 BOOST_FOREACH(const dom_int b, m_base) { 00469 if ( p1->at(b) == b && p2->at(b) != b ) 00470 return true; 00471 if ( p1->at(b) != b ) 00472 return false; 00473 } 00474 return false; 00475 } 00476 private: 00477 std::vector<dom_int> m_base; 00478 }; 00479 00480 template <class PERM, class TRANS> 00481 void BSGS<PERM, TRANS>::stripRedundantStrongGenerators() { 00482 PERMlist sortedSGS(this->S); 00483 sortedSGS.sort(StrongGeneratingSetSorter<PERM>(this->B.begin(), this->B.end())); 00484 00485 PERMlist filteredSGS; 00486 OrbitSet<PERM, dom_int>* oldOrbit = new OrbitSet<PERM, dom_int>(); 00487 dom_int oldBaseElement = static_cast<dom_int>(-1); 00488 BOOST_FOREACH(const typename PERM::ptr& gen, sortedSGS) { 00489 if (gen->isIdentity()) 00490 continue; 00491 filteredSGS.push_back(gen); 00492 00493 // Compute to which base element this strong generator belongs. 00494 // That is, gen stabilizes all base points up to baseElement. 00495 // No generator can stabilize all base elements because we excluded 00496 // identity permutations before. 00497 dom_int baseElement = this->B.front(); 00498 BOOST_FOREACH(const dom_int b, this->B) { 00499 baseElement = b; 00500 if (*gen / b != b) 00501 break; 00502 } 00503 PERMLIB_DEBUG(std::cout << "gen " << *gen << " @ " << baseElement << std::endl;) 00504 00505 OrbitSet<PERM, dom_int>* newOrbit = new OrbitSet<PERM, dom_int>(); 00506 newOrbit->orbit(baseElement, filteredSGS, typename Transversal<PERM>::TrivialAction()); 00507 if (oldBaseElement == baseElement && newOrbit->size() == oldOrbit->size()) { 00508 delete newOrbit; 00509 PERMLIB_DEBUG(std::cout << " removed\n";) 00510 filteredSGS.pop_back(); 00511 } else { 00512 delete oldOrbit; 00513 oldOrbit = newOrbit; 00514 } 00515 oldBaseElement = baseElement; 00516 } 00517 delete oldOrbit; 00518 00519 this->S = filteredSGS; 00520 } 00521 00522 template <class PERM, class TRANS> 00523 void BSGS<PERM,TRANS>::copyTransversals(const BSGS<PERM,TRANS>& bsgs) { 00524 std::map<PERM*,typename PERM::ptr> genMap; 00525 BOOST_FOREACH(const typename PERM::ptr& p, bsgs.S) { 00526 typename PERM::ptr deepcopy(new PERM(*p)); 00527 //std::cout << "found " << p.get() << " = " << *p << std::endl; 00528 genMap.insert(std::make_pair(p.get(), deepcopy)); 00529 this->S.push_back(deepcopy); 00530 } 00531 00532 BOOST_ASSERT(this->B.size() == bsgs.B.size()); 00533 BOOST_ASSERT(bsgs.B.size() == bsgs.U.size()); 00534 this->U.clear(); 00535 this->U.resize(bsgs.U.size(), TRANS(bsgs.n)); 00536 BOOST_ASSERT(this->U.size() == bsgs.U.size()); 00537 00538 for (unsigned int i=0; i<this->U.size(); ++i) { 00539 this->U[i] = bsgs.U[i].clone(genMap); 00540 } 00541 } 00542 00543 } 00544 00545 #endif // -- BSGS_H_