PermLib

bsgs.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 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_