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 PRIMITIVITY_TEST_H_ 00034 #define PRIMITIVITY_TEST_H_ 00035 00036 #include <permlib/prime_helper.h> 00037 00038 #include <boost/foreach.hpp> 00039 #include <boost/utility.hpp> 00040 #include <vector> 00041 #include <list> 00042 #include <set> 00043 00044 namespace permlib { 00045 00047 00054 template<typename PERM> 00055 class PrimitivityTest { 00056 public: 00064 template<typename InputIterator> 00065 PrimitivityTest(const unsigned int n, InputIterator genBegin, InputIterator genEnd); 00066 00074 bool blockOfImprimitivity(std::vector<dom_int>* minimalBlock) const; 00075 00083 bool allBlocks(std::list<std::vector<dom_int> >* blocks, bool findOnlyOneBlock = false) const; 00084 00088 bool isPrimitive() const { return blockOfImprimitivity(NULL); } 00089 00090 private: 00091 const unsigned int m_n; 00092 unsigned int m_primeLimit; 00093 const std::list<typename PERM::ptr> m_generators; 00094 00095 bool fillTrivialBlock(std::list<std::vector<dom_int> >* block) const; 00096 00097 static dom_int rep(dom_int kappa, std::vector<dom_int>& p); 00098 00099 bool merge(dom_int kappa, dom_int lambda, std::vector<dom_int>& c, std::vector<dom_int>& p, std::vector<dom_int>& q, unsigned int& l) const; 00100 }; 00101 00102 00103 00104 template<typename PERM> 00105 template<typename InputIterator> 00106 PrimitivityTest<PERM>::PrimitivityTest(const unsigned int n, InputIterator genBegin, InputIterator genEnd) 00107 : m_n(n), m_primeLimit(m_n), m_generators(genBegin, genEnd) 00108 { 00109 for (const unsigned int* p = PrimeHelper::firstPrime(); p != PrimeHelper::lastPrime(); ++p) { 00110 if (m_n % (*p) == 0) { 00111 m_primeLimit = m_n / (*p); 00112 break; 00113 } 00114 } 00115 } 00116 00117 template<typename PERM> 00118 bool PrimitivityTest<PERM>::blockOfImprimitivity(std::vector<dom_int>* minimalBlock) const { 00119 if (minimalBlock) { 00120 std::list<std::vector<dom_int> > blocks; 00121 const bool is_primitive = allBlocks(&blocks, true); 00122 minimalBlock->clear(); 00123 minimalBlock->reserve(blocks.front().size()); 00124 std::copy(blocks.front().begin(), blocks.front().end(), std::back_inserter(*minimalBlock)); 00125 return is_primitive; 00126 } 00127 return allBlocks(0, true); 00128 } 00129 00130 00131 template<typename PERM> 00132 bool PrimitivityTest<PERM>::allBlocks(std::list<std::vector<dom_int> >* blocks, bool findOnlyOneBlock) const { 00133 std::vector<dom_int> alphas(2); 00134 std::set<dom_int> workedAlphas; 00135 alphas[0] = 0; 00136 00137 for (dom_int a = 1; a < m_n; ++a) { 00138 if (workedAlphas.count(a)) 00139 continue; 00140 alphas[1] = a; 00141 00142 const unsigned int k = alphas.size(); 00143 unsigned int l = k - 1; 00144 std::vector<dom_int> p(m_n); 00145 std::vector<dom_int> q(m_n); 00146 std::vector<dom_int> c(m_n); 00147 00148 for (unsigned int i = 0; i < m_n; ++i) { 00149 c[i] = 1; 00150 p[i] = i; 00151 } 00152 00153 for (unsigned int i = 0; i < k - 1; ++i) { 00154 p[alphas[i+1]] = alphas[0]; 00155 q[i] = alphas[i+1]; 00156 } 00157 00158 c[alphas[0]] = k; 00159 for (unsigned int i = 0; i < l; ++i) { 00160 const dom_int gamma = q[i]; 00161 BOOST_FOREACH(const typename PERM::ptr& x, m_generators) { 00162 const dom_int delta = rep(gamma, p); 00163 if (merge(x->at(gamma), x->at(delta), c, p, q, l)) { 00164 goto TRY_NEXT_ALPHA; 00165 } 00166 } 00167 } 00168 00169 for (unsigned int i = 0; i < m_n; ++i) 00170 rep(i, p); 00171 00172 if (c[rep(alphas[0], p)] < m_n) { 00173 if (blocks) { 00174 std::vector<dom_int> block; 00175 block.reserve(c[rep(alphas[0], p)]); 00176 for (unsigned int i = 0; i < m_n; ++i) { 00177 if (p[i] == p[alphas[0]]) { 00178 block.push_back(i); 00179 if (i != alphas[0]) 00180 workedAlphas.insert(i); 00181 } 00182 } 00183 BOOST_ASSERT( block.size() == c[rep(alphas[0], p)] ); 00184 blocks->push_back(block); 00185 } 00186 if (findOnlyOneBlock) 00187 return false; 00188 } 00189 00190 // end of alpha loop 00191 TRY_NEXT_ALPHA: 00192 continue; 00193 } 00194 00195 if (!blocks->empty()) 00196 return false; 00197 return fillTrivialBlock(blocks); 00198 } 00199 00200 template<typename PERM> 00201 bool PrimitivityTest<PERM>::fillTrivialBlock(std::list<std::vector<dom_int> >* blocks) const { 00202 if (blocks) { 00203 std::vector<dom_int> minimalBlock(m_n); 00204 for (unsigned int i = 0; i < m_n; ++i) 00205 minimalBlock[i] = i; 00206 blocks->push_back(minimalBlock); 00207 } 00208 return true; 00209 } 00210 00211 template<typename PERM> 00212 dom_int PrimitivityTest<PERM>::rep(dom_int kappa, std::vector<dom_int>& p) { 00213 dom_int lambda = kappa; 00214 dom_int rho = p[lambda]; 00215 while (rho != lambda) { 00216 lambda = rho; 00217 rho = p[lambda]; 00218 } 00219 00220 dom_int mu = kappa; 00221 rho = p[mu]; 00222 while (rho != lambda) { 00223 p[mu] = lambda; 00224 mu = rho; 00225 rho = p[mu]; 00226 } 00227 00228 return lambda; 00229 } 00230 00231 template<typename PERM> 00232 bool PrimitivityTest<PERM>::merge(dom_int kappa, dom_int lambda, std::vector<dom_int>& c, std::vector<dom_int>& p, std::vector<dom_int>& q, unsigned int& l) const { 00233 dom_int phi = rep(kappa, p); 00234 dom_int psi = rep(lambda, p); 00235 00236 if (phi != psi) { 00237 dom_int mu, nu; 00238 if (c[phi] >= c[psi]) { 00239 mu = phi; 00240 nu = psi; 00241 } else { 00242 mu = psi; 00243 nu = phi; 00244 } 00245 p[nu] = mu; 00246 c[mu] += c[nu]; 00247 if (c[mu] > m_primeLimit) 00248 return true; 00249 00250 q[l] = nu; 00251 ++l; 00252 } 00253 00254 return false; 00255 } 00256 00257 } 00258 00259 #endif