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 ORBIT_LEX_MIN_SEARCH_H_ 00033 #define ORBIT_LEX_MIN_SEARCH_H_ 00034 00035 #include <permlib/predicate/pointwise_stabilizer_predicate.h> 00036 #include <permlib/change/conjugating_base_change.h> 00037 #include <permlib/change/random_base_transpose.h> 00038 #include <permlib/search/dset.h> 00039 00040 #include <vector> 00041 #include <limits> 00042 #include <boost/dynamic_bitset.hpp> 00043 00044 namespace permlib { 00045 00047 00051 template<class BSGSIN> 00052 class OrbitLexMinSearch { 00053 public: 00055 00060 OrbitLexMinSearch(const BSGSIN& bsgs, bool abortSearchIfSmallerFound = false) 00061 : m_bsgs(bsgs), m_cbc(bsgs), m_dsetAction(bsgs.n), m_orb(m_bsgs.n), m_orbVector(m_bsgs.n, 0), 00062 m_orbVectorIndex(0), m_abortSearchIfSmallerFound(abortSearchIfSmallerFound) {} 00063 00065 00070 dset lexMin(const dset& element, const BSGSIN* stabilizer = NULL); 00071 00073 00078 static bool isLexSmaller(const dset& a, const dset& b); 00079 00080 private: 00081 BSGSIN m_bsgs; 00082 const BSGSIN* m_bsgsStabilizer; 00083 typedef typename BSGSIN::PERMtype PERM; 00084 typedef std::vector<boost::shared_ptr<PERM> > PERMvec; 00085 00086 struct Candidate { 00087 dset D; 00088 dset J; 00089 00090 Candidate(dset D_) : D(D_), J(D_.size()) {} 00091 Candidate(dset D_, dset J_) : D(D_), J(J_) {} 00092 00093 void print(const char* prefix) const { 00094 std::cout << prefix << ".J = " << J << " ; " << prefix << ".D = " << D << std::endl; 00095 } 00096 }; 00097 00098 typedef Candidate* CandidatePtr; 00099 00100 ConjugatingBaseChange<PERM, typename BSGSIN::TRANStype, RandomBaseTranspose<PERM, typename BSGSIN::TRANStype> > m_cbc; 00101 DSetAction<PERM> m_dsetAction; 00102 00103 bool lexMin(unsigned int i, unsigned int k, const dset& element, const BSGSIN* stabilizer, const std::list<CandidatePtr>& candidates, std::list<CandidatePtr>& candidatesNext, dset& M_i, std::list<unsigned long>& base, PERMvec& S_i); 00105 unsigned long orbMin(unsigned long element, const PERMvec& generators); 00106 00108 00113 dset* orbRepresentatives(dset element, const std::list<typename PERM::ptr>& generators); 00114 00115 // temporary variables for the orbMin calculation 00116 dset m_orb; 00117 std::vector<unsigned long> m_orbVector; 00118 unsigned int m_orbVectorIndex; 00119 const bool m_abortSearchIfSmallerFound; 00120 }; 00121 00122 00123 template<class BSGSIN> 00124 inline dset OrbitLexMinSearch<BSGSIN>::lexMin(const dset& element, const BSGSIN* stabilizer) { 00125 if (element.count() == element.size()) 00126 return element; 00127 if (element.count() == 0) 00128 return element; 00129 CandidatePtr c0(new Candidate(element)); 00130 00131 std::list<CandidatePtr> candList0, candList1; 00132 std::list<CandidatePtr>* cand0 = &candList0; 00133 std::list<CandidatePtr>* cand1 = &candList1; 00134 00135 cand0->push_back(c0); 00136 dset M_i(element.size()); 00137 std::list<unsigned long> base; 00138 PERMvec S_i; 00139 S_i.reserve(m_bsgs.S.size()); 00140 00141 for (unsigned int i = 0; i < element.count(); ++i) { 00142 if (lexMin(i, element.count(), element, stabilizer, *cand0, *cand1, M_i, base, S_i)) 00143 break; 00144 std::swap(cand0, cand1); 00145 } 00146 std::for_each(candList0.begin(), candList0.end(), delete_object()); 00147 std::for_each(candList1.begin(), candList1.end(), delete_object()); 00148 00149 return M_i; 00150 } 00151 00152 template<class BSGSIN> 00153 inline bool OrbitLexMinSearch<BSGSIN>::lexMin(unsigned int i, unsigned int k, const dset& element, const BSGSIN* stabilizer, const std::list<CandidatePtr>& candidates, std::list<CandidatePtr>& candidatesNext, dset& M_i, std::list<unsigned long>& base, PERMvec& S_i) { 00154 PERMLIB_DEBUG(std::cout << "### START " << i << " with #" << candidates.size() << std::endl;) 00155 00156 // if current stabilizer in the stabilizer chain is trivial we may 00157 // choose the minimal candidate and abort the search 00158 bool allOne = true; 00159 for (unsigned int j = i; j < m_bsgs.B.size(); ++j) { 00160 if (m_bsgs.U[j].size() > 1) { 00161 allOne = false; 00162 break; 00163 } 00164 } 00165 if (allOne) { 00166 M_i = candidates.front()->D; 00167 BOOST_FOREACH(const CandidatePtr& R, candidates) { 00168 if (isLexSmaller(R->D, M_i)) { 00169 M_i = R->D; 00170 } 00171 } 00172 return true; 00173 } 00174 00175 unsigned int m = m_bsgs.n + 1; 00176 S_i.clear(); 00177 PointwiseStabilizerPredicate<PERM> stab_i(m_bsgs.B.begin(), m_bsgs.B.begin() + i); 00178 std::copy_if(m_bsgs.S.begin(), m_bsgs.S.end(), std::back_inserter(S_i), stab_i); 00179 const unsigned long UNDEFINED_ORBIT = std::numeric_limits<unsigned long>::max(); 00180 std::vector<unsigned long> orbitCache(m_bsgs.n, UNDEFINED_ORBIT); 00181 std::list<CandidatePtr> pass; 00182 00183 BOOST_FOREACH(const CandidatePtr& R, candidates) { 00184 unsigned long m_R = m; 00185 if (m_abortSearchIfSmallerFound && isLexSmaller(R->D, element)) { 00186 BOOST_ASSERT(R->D.count() == element.count()); 00187 M_i = R->D; 00188 return true; 00189 } 00190 for (unsigned long j = 0; j < R->D.size(); ++j) { 00191 if (R->J[j] || !R->D[j]) 00192 continue; 00193 00194 unsigned long val = orbitCache[j]; 00195 if (val == UNDEFINED_ORBIT) { 00196 val = orbMin(j, S_i); 00197 orbitCache[j] = val; 00198 } 00199 if (m_R > val) 00200 m_R = val; 00201 } 00202 00203 if (m_R < m) { 00204 m = m_R; 00205 pass.clear(); 00206 pass.push_back(R); 00207 } else if (m_R == m) { 00208 pass.push_back(R); 00209 } 00210 } 00211 00212 PERMLIB_DEBUG(std::cout << " found m = " << m << std::endl;) 00213 M_i.set(m, 1); 00214 if (i == k-1) 00215 return true; 00216 00217 base.push_back(m); 00218 m_cbc.change(m_bsgs, base.begin(), base.end()); 00219 00220 std::for_each(candidatesNext.begin(), candidatesNext.end(), delete_object()); 00221 candidatesNext.clear(); 00222 00223 PERM* UNDEFINED_TRANSVERSAL = reinterpret_cast<PERM*>(1L); 00224 std::vector<PERM*> transversalCache(m_bsgs.n); 00225 BOOST_FOREACH(PERM*& p, transversalCache) { 00226 p = UNDEFINED_TRANSVERSAL; 00227 } 00228 BOOST_FOREACH(const CandidatePtr& R, pass) { 00229 for (unsigned long j = 0; j < R->D.size(); ++j) { 00230 if (!R->D[j]) 00231 continue; 00232 00233 PERM* perm = transversalCache[j]; 00234 if (perm == UNDEFINED_TRANSVERSAL) { 00235 perm = m_bsgs.U[i].at(j); 00236 if (perm) { 00237 perm->invertInplace(); 00238 } 00239 transversalCache[j] = perm; 00240 } 00241 00242 if (!perm) 00243 continue; 00244 00245 CandidatePtr c(new Candidate(R->D, R->J)); 00246 m_dsetAction.apply(*perm, R->D, c->D); 00247 c->J.set(m); 00248 candidatesNext.push_back(c); 00249 } 00250 } 00251 00252 BOOST_FOREACH(PERM* p, transversalCache) { 00253 if (p != UNDEFINED_TRANSVERSAL) 00254 delete p; 00255 } 00256 return false; 00257 } 00258 00259 template<class BSGSIN> 00260 inline unsigned long OrbitLexMinSearch<BSGSIN>::orbMin(unsigned long element, const PERMvec& generators) { 00261 if (element == 0) 00262 return 0; 00263 00264 unsigned long minElement = element; 00265 m_orb.reset(); 00266 m_orb.set(element, 1); 00267 m_orbVectorIndex = 0; 00268 m_orbVector[m_orbVectorIndex++] = element; 00269 00270 for (unsigned int i = 0; i < m_orbVectorIndex; ++i) { 00271 const unsigned long &alpha = m_orbVector[i]; 00272 BOOST_FOREACH(const typename PERM::ptr& p, generators) { 00273 unsigned long alpha_p = *p / alpha; 00274 if (alpha_p == 0) 00275 return 0; 00276 if (!m_orb[alpha_p]) { 00277 m_orbVector[m_orbVectorIndex++] = alpha_p; 00278 m_orb.set(alpha_p); 00279 if (alpha_p < minElement) 00280 minElement = alpha_p; 00281 } 00282 } 00283 } 00284 00285 return minElement; 00286 } 00287 00288 00289 template<class BSGSIN> 00290 inline dset* OrbitLexMinSearch<BSGSIN>::orbRepresentatives(dset element, const std::list<typename PERM::ptr>& generators) { 00291 dset* ret = new dset(element.size()); 00292 00293 for (unsigned int j = 0; j < element.size(); ++j) { 00294 if (!element[j]) 00295 continue; 00296 00297 m_orb.set(); 00298 m_orb.set(j, 0); 00299 m_orbVectorIndex = 0; 00300 m_orbVector[m_orbVectorIndex++] = j; 00301 for (unsigned int i = 0; i < m_orbVectorIndex; ++i) { 00302 const unsigned long &alpha = m_orbVector[i]; 00303 BOOST_FOREACH(const typename PERM::ptr& p, generators) { 00304 unsigned long alpha_p = *p / alpha; 00305 if (m_orb[alpha_p]) { 00306 m_orbVector[m_orbVectorIndex++] = alpha_p; 00307 m_orb.reset(alpha_p); 00308 } 00309 } 00310 } 00311 00312 element &= m_orb; 00313 ret->set(j); 00314 } 00315 00316 return ret; 00317 } 00318 00319 00320 template<class BSGSIN> 00321 inline bool OrbitLexMinSearch<BSGSIN>::isLexSmaller(const dset& a, const dset& b) { 00322 dset::size_type i = a.find_first(), j = b.find_first(); 00323 while (i != dset::npos && j != dset::npos) { 00324 if (i < j) 00325 return true; 00326 if (i > j) 00327 return false; 00328 i = a.find_next(i); 00329 j = b.find_next(j); 00330 } 00331 return false; 00332 } 00333 00334 } // ns permlib 00335 00336 #endif // ORBIT_LEX_MIN_SEARCH_H_