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