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/predicate/pointwise_stabilizer_predicate.h> 00049 #include <permlib/predicate/stabilizes_point_predicate.h> 00050 00051 #include <permlib/redundant_base_point_insertion_strategy.h> 00052 00053 namespace permlib { 00054 00055 template <class PERM, class TRANS> 00056 struct BSGS; 00057 00058 template <class PERM, class TRANS> 00059 std::ostream &operator<< (std::ostream &out, const BSGS<PERM,TRANS> &bsgs) { 00060 out << "BASE[" << bsgs.B.size() << "]" << std::endl; 00061 BOOST_FOREACH(unsigned long beta, bsgs.B) { 00062 out << static_cast<unsigned int>(beta+1) << ","; 00063 } 00064 out << std::endl; 00065 out << "SGS[" << bsgs.S.size() << "]" << std::endl; 00066 BOOST_FOREACH(const typename PERM::ptr &g, bsgs.S) { 00067 out << *g << ","; 00068 } 00069 out << std::endl; 00070 out << "U" << std::endl; 00071 BOOST_FOREACH(const TRANS &U, bsgs.U) { 00072 for (unsigned int i=0; i<bsgs.n; ++i) 00073 // trigger transversal depth reload 00074 boost::scoped_ptr<PERM> dummy(U.at(i)); 00075 out << U.size() << "{" << U.m_statMaxDepth << "}" << ","; 00076 } 00077 out << " = " << bsgs.order() << std::endl; 00078 BOOST_FOREACH(const TRANS &U, bsgs.U) { 00079 out << U << std::endl; 00080 } 00081 return out; 00082 } 00083 00085 template <class PERM, class TRANS> 00086 struct BSGS : public BSGSCore<PERM,TRANS> { 00087 typedef typename BSGSCore<PERM,TRANS>::PERMlist PERMlist; 00088 00090 explicit BSGS(dom_int n); 00092 00096 BSGS(const BSGS<PERM,TRANS>& bsgs); 00097 00099 00103 BSGS<PERM,TRANS>& operator=(const BSGS<PERM,TRANS>&); 00104 00106 00109 boost::uint64_t order() const; 00110 00112 00117 unsigned int sift(const PERM& g, PERM& siftee, unsigned int j = 0) const; 00119 00125 unsigned int sift(const PERM& g, PERM& siftee, unsigned int j, unsigned int k) const; 00127 bool sifts(const PERM& g) const; 00128 00130 00136 bool chooseBaseElement(const PERM &h, dom_int &beta) const; 00138 00143 unsigned int insertRedundantBasePoint(unsigned int beta, unsigned int minPos = 0); 00145 void stripRedundantBasePoints(int minPos = 0); 00146 00148 00151 void orbit(unsigned int j, const PERMlist &generators); 00153 00156 void orbitUpdate(unsigned int j, const PERMlist &generators, const typename PERM::ptr &g); 00157 00159 00164 int insertGenerator(const typename PERM::ptr& g, bool updateOrbit); 00166 00170 void updateOrbits(int pos); 00171 00173 00176 PERM random(const int i = 0) const; 00177 00179 friend std::ostream &operator<< <> (std::ostream &out, const BSGS<PERM,TRANS> &bsgs); 00180 private: 00182 template <class BaseIterator, class TransversalIterator> 00183 unsigned int sift(const PERM& g, PERM& siftee, BaseIterator begin, BaseIterator end, TransversalIterator beginT, TransversalIterator endT) const; 00184 00186 mutable boost::uint64_t m_order; 00187 00189 static int ms_bsgsId; 00190 00192 void copyTransversals(const BSGS<PERM,TRANS>& bsgs); 00193 }; 00194 00195 // 00196 // ---- IMPLEMENTATION 00197 // 00198 00199 template <class PERM, class TRANS> 00200 int BSGS<PERM,TRANS>::ms_bsgsId = 0; 00201 00202 template <class PERM, class TRANS> 00203 BSGS<PERM,TRANS>::BSGS(dom_int n) 00204 : BSGSCore<PERM,TRANS>(++ms_bsgsId, n, 0), 00205 m_order(1) 00206 {} 00207 00208 template <class PERM, class TRANS> 00209 BSGS<PERM,TRANS>::BSGS(const BSGS<PERM,TRANS>& bsgs) 00210 : BSGSCore<PERM,TRANS>(bsgs.m_id, bsgs.B, bsgs.U, bsgs.n), 00211 m_order(bsgs.m_order) 00212 { 00213 copyTransversals(bsgs); 00214 } 00215 00216 template <class PERM, class TRANS> 00217 BSGS<PERM,TRANS>& BSGS<PERM,TRANS>::operator=(const BSGS<PERM,TRANS>& bsgs) { 00218 if (this == &bsgs) 00219 return *this; 00220 00221 this->B = bsgs.B; 00222 this->n = bsgs.n; 00223 this->m_order = bsgs.m_order; 00224 this->m_id = bsgs.m_id; 00225 00226 copyTransversals(bsgs); 00227 return *this; 00228 } 00229 00230 template <class PERM, class TRANS> 00231 template <class BaseIterator, class TransversalIterator> 00232 unsigned int BSGS<PERM, TRANS>::sift(const PERM& g, PERM& siftee, BaseIterator begin, BaseIterator end, TransversalIterator beginT, TransversalIterator endT) const{ 00233 unsigned int k = 0; 00234 siftee = g; 00235 BaseIterator baseIt; 00236 TransversalIterator transIt; 00237 for (baseIt = begin, transIt = beginT; baseIt != end && transIt != endT; ++baseIt, ++transIt) { 00238 unsigned long b = *baseIt; 00239 const TRANS& U_i = *transIt; 00240 //std::cout << " ~~~ sift " << siftee << " b" << b << std::endl; 00241 boost::scoped_ptr<PERM> u_b(U_i.at(siftee / b)); 00242 if (u_b == 0) 00243 return k; 00244 u_b->invertInplace(); 00245 siftee *= *u_b; 00246 ++k; 00247 } 00248 return k; 00249 } 00250 00251 template <class PERM, class TRANS> 00252 unsigned int BSGS<PERM, TRANS>::sift(const PERM& g, PERM& siftee, unsigned int j) const { 00253 return sift(g, siftee, this->B.begin() + j, this->B.end(), this->U.begin() + j, this->U.end()); 00254 } 00255 00256 template <class PERM, class TRANS> 00257 unsigned int BSGS<PERM, TRANS>::sift(const PERM& g, PERM& siftee, unsigned int j, unsigned int k) const { 00258 return sift(g, siftee, this->B.begin() + j, this->B.begin() + k, this->U.begin() + j, this->U.begin() + k); 00259 } 00260 00261 template <class PERM, class TRANS> 00262 bool BSGS<PERM, TRANS>::sifts(const PERM& g) const { 00263 PERM siftee(this->n); 00264 unsigned int m = sift(g, siftee); 00265 return this->B.size() == m && siftee.isIdentity(); 00266 } 00267 00268 template <class PERM, class TRANS> 00269 bool BSGS<PERM, TRANS>::chooseBaseElement(const PERM &h, dom_int &beta) const { 00270 for (beta = 0; beta < this->n; ++beta) { 00271 if (std::find(this->B.begin(), this->B.end(), beta) != this->B.end()) 00272 continue; 00273 if (h / beta != beta) 00274 return true; 00275 } 00276 return false; 00277 } 00278 00279 template <class PERM, class TRANS> 00280 void BSGS<PERM, TRANS>::orbit(unsigned int j, const PERMlist &generators) { 00281 this->U[j].orbit(this->B[j], generators); 00282 // mark order as tainted 00283 m_order = 0; 00284 } 00285 00286 template <class PERM, class TRANS> 00287 void BSGS<PERM, TRANS>::orbitUpdate(unsigned int j, const PERMlist &generators, const typename PERM::ptr &g) { 00288 this->U[j].orbitUpdate(this->B[j], generators, g); 00289 // mark order as tainted 00290 m_order = 0; 00291 } 00292 00293 template <class PERM, class TRANS> 00294 PERM BSGS<PERM, TRANS>::random(const int i) const { 00295 BOOST_ASSERT( i >= 0 ); 00296 PERM g(this->n); 00297 for (int l = this->U.size()-1; l>=i ; --l) { 00298 //std::cout << l << " : " << U[l] << " : " << U[l].size() << std::endl; 00299 unsigned long beta = *(boost::next(this->U[l].begin(), randomInt(this->U[l].size()))); 00300 boost::scoped_ptr<PERM> u_beta(this->U[l].at(beta)); 00301 g *= *u_beta; 00302 } 00303 return g; 00304 } 00305 00306 template <class PERM, class TRANS> 00307 int BSGS<PERM, TRANS>::insertGenerator(const typename PERM::ptr& g, bool updateOrbit) { 00308 int pos = 0; 00309 for (; static_cast<unsigned int>(pos) < this->B.size(); ++pos) { 00310 if (*g / this->B[pos] != this->B[pos]) 00311 break; 00312 } 00313 00314 if (static_cast<unsigned int>(pos) == this->B.size()) { 00315 dom_int beta; 00316 bool newBaseElement __attribute__((unused)) = chooseBaseElement(*g, beta); 00317 BOOST_ASSERT( newBaseElement ); 00318 this->B.push_back(beta); 00319 this->U.push_back(TRANS(this->n)); 00320 } 00321 00322 const int insertionPosition = pos; 00323 this->S.push_back(g); 00324 00325 if (updateOrbit) { 00326 boost::uint64_t oldOrder = order(); 00327 00328 for (; pos >= 0; --pos) { 00329 PERMlist orbitGenerators; 00330 //std::cout << "INSERT orbit @ " << pos << " : " << g << std::endl; 00331 std::copy_if(this->S.begin(), this->S.end(), std::back_inserter(orbitGenerators), 00332 PointwiseStabilizerPredicate<PERM>(this->B.begin(), this->B.begin() + pos)); 00333 if (orbitGenerators.size() > 0) 00334 orbitUpdate(pos, orbitGenerators, g); 00335 } 00336 00337 if (order() <= oldOrder) { 00338 this->S.pop_back(); 00339 return -1; 00340 } 00341 } 00342 00343 return insertionPosition; 00344 } 00345 00346 template <class PERM, class TRANS> 00347 void BSGS<PERM, TRANS>::updateOrbits(int pos) { 00348 if (pos < 0) 00349 return; 00350 for (; pos >= 0; --pos) { 00351 PERMlist orbitGenerators; 00352 std::copy_if(this->S.begin(), this->S.end(), std::back_inserter(orbitGenerators), 00353 PointwiseStabilizerPredicate<PERM>(this->B.begin(), this->B.begin() + pos)); 00354 if (orbitGenerators.size() > 0) 00355 orbit(pos, orbitGenerators); 00356 } 00357 } 00358 00359 template <class PERM, class TRANS> 00360 boost::uint64_t BSGS<PERM, TRANS>::order() const { 00361 if (m_order == 0) { 00362 m_order = 1; 00363 BOOST_FOREACH(const TRANS &Ui, this->U) { 00364 m_order *= Ui.size(); 00365 } 00366 } 00367 return m_order; 00368 } 00369 00370 00371 template <class PERM, class TRANS> 00372 unsigned int BSGS<PERM, TRANS>::insertRedundantBasePoint(unsigned int beta, unsigned int minPos) { 00373 PERMlist S_i; 00374 TrivialRedundantBasePointInsertionStrategy<PERM,TRANS> is(*this); 00375 int pos = is.findInsertionPoint(beta, S_i); 00376 if (pos < 0) 00377 return -(pos+1); 00378 pos = std::max(static_cast<unsigned int>(pos), minPos); 00379 00380 this->B.insert(this->B.begin() + pos, beta); 00381 this->U.insert(this->U.begin() + pos, TRANS(this->n)); 00382 this->U[pos].orbit(beta, S_i); 00383 return pos; 00384 } 00385 00386 template <class PERM, class TRANS> 00387 void BSGS<PERM, TRANS>::stripRedundantBasePoints(int minPos) { 00388 for (int i = this->B.size()-1; i >= minPos; --i) { 00389 if (this->U[i].size() <= 1) { 00390 if (i == static_cast<int>(this->B.size()-1)) { 00391 this->B.pop_back(); 00392 this->U.pop_back(); 00393 } else { 00394 this->B.erase(this->B.begin() + i); 00395 this->U.erase(this->U.begin() + i); 00396 } 00397 } 00398 } 00399 } 00400 00401 template <class PERM, class TRANS> 00402 void BSGS<PERM,TRANS>::copyTransversals(const BSGS<PERM,TRANS>& bsgs) { 00403 std::map<PERM*,typename PERM::ptr> genMap; 00404 BOOST_FOREACH(const typename PERM::ptr& p, bsgs.S) { 00405 typename PERM::ptr deepcopy(new PERM(*p)); 00406 //std::cout << "found " << p.get() << " = " << *p << std::endl; 00407 genMap.insert(std::make_pair(p.get(), deepcopy)); 00408 this->S.push_back(deepcopy); 00409 } 00410 for (unsigned int i=0; i<this->B.size(); ++i) { 00411 this->U[i] = bsgs.U[i].clone(genMap); 00412 } 00413 } 00414 00415 } 00416 00417 #endif // -- BSGS_H_