PermLib

type_recognition.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 #ifndef TYPE_RECOGNITION_H_
00033 #define TYPE_RECOGNITION_H_
00034 
00035 #include <permlib/prime_helper.h>
00036 #include <permlib/transversal/schreier_tree_transversal.h>
00037 #include <permlib/generator/bsgs_generator.h>
00038 #include <permlib/construct/schreier_sims_construction.h>
00039 #include <permlib/transversal/orbit_set.h>
00040 #include <permlib/test/giant_test.h>
00041 #include <permlib/test/group_type.h>
00042 #include <permlib/test/primitivity_sgs_test.h>
00043 
00044 #include <iostream>
00045 
00046 
00047 namespace permlib {
00048 
00050 
00054 template<class PERM, class TRANSVERSAL = SchreierTreeTransversal<PERM> >
00055 class TypeRecognition {
00056 public:
00058         typedef boost::shared_ptr<BSGS<PERM, TRANSVERSAL> > PermutationGroupPtr;
00059         
00065         template<class InputIterator>
00066         TypeRecognition(unsigned int n, InputIterator genBegin, InputIterator genEnd);
00067         
00071         TypeRecognition(const PermutationGroupPtr& bsgs);
00072         
00074         GroupType* analyze() { return analyze(true); }
00076         PermutationGroupPtr bsgs() const { return m_bsgs; }
00077 private:
00078         const unsigned int m_n;
00079         std::list<typename PERM::ptr> m_generators;
00080         const PermutationGroupPtr m_externalBSGS;
00081         PermutationGroupPtr m_bsgs;
00082         
00086         GroupType* analyze(bool allowRecursiveCalls);
00087         
00089 
00092         GroupType* checkOrbitActions();
00093         
00095         static const unsigned int m_bsgsComputationDegreeLimit = 50;
00096 };
00097 
00098 template<class PERM, class TRANSVERSAL>
00099 template<class InputIterator>
00100 TypeRecognition<PERM,TRANSVERSAL>::TypeRecognition(unsigned int n, InputIterator genBegin, InputIterator genEnd) 
00101         : m_n(n), m_generators(genBegin, genEnd)
00102 { }
00103 
00104 template<class PERM, class TRANSVERSAL>
00105 TypeRecognition<PERM,TRANSVERSAL>::TypeRecognition(const PermutationGroupPtr& bsgs) 
00106         : m_n(bsgs->n), m_generators(bsgs->S.begin(), bsgs->S.end()), m_externalBSGS(bsgs), m_bsgs(m_externalBSGS)
00107 { }
00108 
00109 
00110 template<class PERM, class TRANSVERSAL>
00111 GroupType* TypeRecognition<PERM,TRANSVERSAL>::analyze(bool allowRecursiveCalls) {
00112         if (m_n < m_bsgsComputationDegreeLimit && ! m_bsgs) {
00113                 SchreierSimsConstruction<PERM,TRANSVERSAL> ssc(m_n);
00114                 m_bsgs = PermutationGroupPtr(new BSGS<PERM, TRANSVERSAL>(ssc.construct(m_generators.begin(), m_generators.end())));
00115         }
00116         
00117         if (m_bsgs) {
00118                 const unsigned int groupIntOrder = m_bsgs->template order<unsigned int>();
00119                 
00120                 if (groupIntOrder == 1)
00121                         return new TrivialGroupType(m_n);
00122                 
00123                 //
00124                 // check for cyclic groups
00125                 //
00126                 if (PrimeHelper::isPrimeNumber(groupIntOrder, false)) {
00127                         BOOST_ASSERT( m_n % groupIntOrder == 0 );
00128                         return new CyclicGroupType(groupIntOrder, m_n);
00129                 }
00130                 
00131                 if (groupIntOrder == 4) {
00132                         // distinguish between C_4 and the Klein four group
00133                         BSGSGenerator<TRANSVERSAL> bsgsGen(m_bsgs->U);
00134                         while (bsgsGen.hasNext()) {
00135                                 PERM el = bsgsGen.next();
00136                                 if (el.order() == 4)
00137                                         return new CyclicGroupType(4, m_n);
00138                         }
00139                         return new DirectProductGroupType(new CyclicGroupType(2,2), new CyclicGroupType(2,2), m_n);
00140                 }
00141                 
00142                 //
00143                 // check for symmetric groups, natural action
00144                 //
00145                 unsigned int symmetricGroupCandidateDegree = 0;
00146                 
00147                 std::vector<unsigned int> transversalSizes(m_bsgs->U.size());
00148                 for (unsigned int i = 0; i < m_bsgs->U.size(); ++i) {
00149                         transversalSizes[i] = m_bsgs->U[i].size();
00150                 }
00151                 std::sort(transversalSizes.begin(), transversalSizes.end());
00152                 
00153                 // test whether group order is a factorial of some natural number
00154                 
00155                 unsigned int expectedFactor = 2;
00156                 for (std::vector<unsigned int>::const_iterator it = transversalSizes.begin(); it != transversalSizes.end(); ++it) {
00157                         if (*it == 1)
00158                                 continue;
00159                         if (*it == expectedFactor)
00160                                 ++expectedFactor;
00161                         else {
00162                                 expectedFactor = 0;
00163                                 break;
00164                         }
00165                 }
00166                 
00167                 if (expectedFactor > 0)
00168                         symmetricGroupCandidateDegree = expectedFactor - 1;
00169                 
00170                 if (symmetricGroupCandidateDegree == m_n)
00171                         return new SymmetricGroupType(symmetricGroupCandidateDegree, m_n);
00172                 
00173                 // check for wreath products of symmetric groups if group is transitive
00174                 if (m_bsgs->U[0].size() == m_n) {
00175                         std::list<typename PERM::ptr> S1;
00176                         PointwiseStabilizerPredicate<PERM> stabPred(m_bsgs->B[0]);
00177                         BOOST_FOREACH(const typename PERM::ptr& p, m_bsgs->S) {
00178                                 if (stabPred(p))
00179                                         S1.push_back(p);
00180                         }
00181                         PrimitivitySGSTest<TRANSVERSAL> primitivityTest(m_bsgs->S.begin(), m_bsgs->S.end(), m_bsgs->B[0], S1.begin(), S1.end(), m_bsgs->U[0]);
00182                         std::vector<dom_int> minimalBlock;
00183                         if ( ! primitivityTest.blockOfImprimitivity(&minimalBlock) ) {
00184                                 // TODO: avoid integer overflow in order computation
00185                                 unsigned int degreeG = minimalBlock.size();
00186                                 unsigned int degreeH = m_n / degreeG;
00187                                 if (m_n % degreeG == 0) {
00188                                         boost::uint64_t wreathSize = 1;
00189                                         // group order must equal   factorial(deg G)^(deg H) * factorial(deg H)
00190                                         for (unsigned int i = 1; i <= degreeH; ++i) {
00191                                                 for (unsigned int j = 2; j <= degreeG; ++j) {
00192                                                         wreathSize *= j;
00193                                                 }
00194                                                 wreathSize *= i;
00195                                         }
00196                                         if (wreathSize == m_bsgs->order())
00197                                                 return new WreathSymmetricGroupType(degreeG, degreeH, m_n);
00198                                 }
00199                         }
00200                 }
00201                 
00202                 
00203                 if (allowRecursiveCalls) {
00204                         // check for multiple linked copies of S_k
00205                         // TODO: check for inner direct products of S_k \times S_l
00206                         GroupType* t = checkOrbitActions();
00207                         if (t) {
00208                                 return t;
00209                         }
00210                 }
00211         } // end if m_bsgs
00212         else // else if ! m_bsgs
00213         {
00214                 const double eps = 1e-3;
00215                 GiantTest<PERM> giantTest;
00216                 GiantTestBase::GiantGroupType giant = giantTest.determineGiantType(eps, 
00217                         m_n, m_generators.begin(), m_generators.end());
00218                 if (giant == GiantTestBase::Symmetric)
00219                         return new SymmetricGroupType(m_n, m_n);
00220                 else if (giant == GiantTestBase::Alternating)
00221                         return new AlternatingGroupType(m_n, m_n);
00222                 
00223                 if (allowRecursiveCalls) {
00224                         GroupType* t = checkOrbitActions();
00225                         if (t)
00226                                 return t;
00227                 }
00228         }
00229         
00230         if (m_bsgs)
00231                 return new AnonymousGroupType<>(m_n, m_bsgs->order());
00232         return new AnonymousGroupType<>(m_n);
00233 }
00234 
00235 template<class PERM, class TRANSVERSAL>
00236 GroupType* TypeRecognition<PERM,TRANSVERSAL>::checkOrbitActions() {
00237         if (m_generators.empty())
00238                 return NULL;
00239         
00240         typedef typename PERM::ptr PERMptr;
00241         boost::dynamic_bitset<> worked(m_n);
00242         GroupType* candidateType = 0;
00243         
00244         for (unsigned int i = 0; i < m_n; ++i) {
00245                 if (worked[i])
00246                         continue;
00247                 worked.set(i, true);
00248                 OrbitSet<PERM, dom_int> orbit;
00249                 orbit.orbit(i, m_generators, typename Transversal<PERM>::TrivialAction());
00250                 for (typename OrbitSet<PERM, dom_int>::const_iterator it = orbit.begin(); it != orbit.end(); ++it) {
00251                         worked.set(i, true);
00252                 }
00253                 
00254                 // restrict group to this orbit
00255                 std::list<PERMptr> orbitGenerators;
00256                 BOOST_FOREACH(const PERMptr& p, m_generators) {
00257                         orbitGenerators.push_back(PERMptr(p->project(orbit.size(), orbit.begin(), orbit.end())));
00258                 }
00259                 TypeRecognition<PERM, TRANSVERSAL> orbitTypeRecognition(orbit.size(), orbitGenerators.begin(), orbitGenerators.end());
00260                 GroupType* orbitType = orbitTypeRecognition.analyze(false);
00261                 if ( ! candidateType )
00262                         candidateType = orbitType;
00263                 else {
00264                         const bool isEqualType = candidateType->equals(orbitType);
00265                         delete orbitType;
00266                         if ( ! isEqualType ) 
00267                                 return NULL;
00268                 }
00269         }
00270         if (candidateType)
00271                 candidateType->setNonNaturalAction(m_n);
00272         return candidateType;
00273 }
00274 
00275 
00276 }
00277 
00278 #endif