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 #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