PermLib

r_base.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 RBASE_H_
00034 #define RBASE_H_
00035 
00036 #include <permlib/predicate/subgroup_predicate.h>
00037 
00038 #include <permlib/search/base_search.h>
00039 
00040 #include <permlib/search/partition/partition.h>
00041 #include <permlib/search/partition/refinement_family.h>
00042 #include <permlib/search/partition/backtrack_refinement.h>
00043 
00044 #include <permlib/change/conjugating_base_change.h>
00045 #include <permlib/change/random_base_transpose.h>
00046 
00047 #include <permlib/sorter/base_sorter.h>
00048 
00049 #include <utility>
00050 
00051 namespace permlib {
00052 namespace partition {
00053 
00055 template<class BSGSIN,class TRANSRET>
00056 class RBase : public BaseSearch<BSGSIN,TRANSRET> {
00057 public:
00058         typedef typename BaseSearch<BSGSIN,TRANSRET>::PERM PERM;
00059         typedef typename BaseSearch<BSGSIN,TRANSRET>::TRANS TRANS;
00060         
00062 
00067         RBase(const BSGSIN& bsgs, unsigned int pruningLevelDCM, bool stopAfterFirstElement = false);
00068         
00069         typedef typename Refinement<PERM>::RefinementPtr RefinementPtr;
00070         typedef typename RefinementFamily<PERM>::PartitionPtr PartitionPtr;
00071         typedef typename std::list<std::pair<PartitionPtr,RefinementPtr> >::const_iterator PartitionIt;
00072         
00074         void search(BSGS<PERM,TRANSRET> &groupK);
00075         
00076         using BaseSearch<BSGSIN,TRANSRET>::searchCosetRepresentative;
00077         virtual typename BaseSearch<BSGSIN,TRANSRET>::PERM::ptr searchCosetRepresentative(BSGS<PERM,TRANSRET> &groupK, BSGS<PERM,TRANSRET> &groupL);
00078 protected:
00080         Partition m_partition;
00081         Partition m_partition2;
00082         
00084 
00089         void construct(SubgroupPredicate<PERM>* pred, RefinementFamily<PERM>* predRefinement);
00090         
00092         virtual unsigned int processNewFixPoints(const Partition& pi, unsigned int level);
00093         
00094         virtual const std::vector<dom_int>& subgroupBase() const;
00095 private:
00097         std::vector<dom_int> m_subgroupBase;
00099         std::list<std::pair<PartitionPtr,RefinementPtr> > partitions;
00100         
00102         unsigned int search(PartitionIt pIt, Partition &pi, const PERM& t, const PERM* t2, unsigned int level, unsigned int backtrackLevel, unsigned int& completed, BSGS<PERM,TRANSRET> &groupK, BSGS<PERM,TRANSRET> &groupL);
00103         
00105         bool updateMappingPermutation(const BSGSIN& bsgs, const Partition& sigma, const Partition& pi2, PERM& t2) const;
00106 };
00107 
00108 template<class BSGSIN,class TRANSRET>
00109 RBase<BSGSIN,TRANSRET>::RBase(const BSGSIN& bsgs, unsigned int pruningLevelDCM, bool stopAfterFirstElement) 
00110         : BaseSearch<BSGSIN,TRANSRET>(bsgs, pruningLevelDCM, stopAfterFirstElement),
00111           m_partition(bsgs.n), m_partition2(bsgs.n)
00112 { }
00113 
00114 template<class BSGSIN,class TRANSRET>
00115 void RBase<BSGSIN,TRANSRET>::construct(SubgroupPredicate<PERM>* pred, RefinementFamily<PERM>* predRefinement) {
00116         this->m_pred.reset(pred);
00117         typedef typename boost::shared_ptr<RefinementFamily<PERM> > RefinementFamilyPtr;
00118         std::list<RefinementFamilyPtr> refinements;
00119         
00120         if (!this->m_bsgs.isSymmetricGroup()) {
00121                 RefinementFamilyPtr gr( new GroupRefinementFamily<PERM,TRANS>(this->m_bsgs) );
00122                 refinements.push_back(gr);
00123         }
00124         
00125         if (predRefinement) {
00126                 RefinementFamilyPtr predR( predRefinement );
00127                 refinements.push_back(predR);
00128         }
00129         
00130         PERMLIB_DEBUG(print_iterable(this->m_bsgs.B.begin(), this->m_bsgs.B.end(), 1, "orig BSGS");)
00131         
00132         Partition pi(m_partition);
00133         while (pi.cells() < this->m_bsgs.n) {
00134                 PERMLIB_DEBUG(std::cout << std::endl << "PI0 = " << pi << std::endl;)
00135                 bool found = false;
00136                 do {
00137                         found = false;
00138                         unsigned int foo = 0;
00139                         BOOST_FOREACH(RefinementFamilyPtr ref, refinements) {
00140                                 const unsigned int oldFixPointsSize = pi.fixPointsSize();
00141                                 std::pair<PartitionPtr,RefinementPtr> newRef = ref->apply(pi);
00142                                 if (newRef.first) {
00143                                         partitions.push_back(newRef);
00144                                         if (oldFixPointsSize < pi.fixPointsSize()) {
00145                                                 processNewFixPoints(pi, partitions.size());
00146                                         }
00147                                         //std::cout << "BSGS " << this->m_bsgs;
00148                                         found = true;
00149                                 }
00150                                 ++foo;
00151                         }
00152                 } while(found);
00153                 
00154                 PERMLIB_DEBUG(std::cout << std::endl << "PI1 = " << pi << std::endl;)
00155                 
00156                 if (pi.cells() < this->m_bsgs.n) {
00157                         unsigned long alpha = -1;
00158                         //print_iterable(pi.fixPointsBegin(), pi.fixPointsEnd(), 1, "  fix0");
00159                         //print_iterable(this->m_bsgs.B.begin(), this->m_bsgs.B.end(), 1, "bsgs0");
00160                         if (pi.fixPointsSize() < this->m_bsgs.B.size())
00161                                 alpha = this->m_bsgs.B[pi.fixPointsSize()];
00162                         PERMLIB_DEBUG(std::cout << "choose alpha = " << alpha << std::endl;)
00163                         RefinementPtr br(new BacktrackRefinement<PERM>(this->m_bsgs.n, alpha));
00164                         BacktrackRefinement<PERM>* ref = dynamic_cast<BacktrackRefinement<PERM> *>(br.get());
00165                         ref->initializeAndApply(pi);
00166                         PartitionPtr newPi(new Partition(pi));
00167                         PERMLIB_DEBUG(std::cout << "BACKTRACK " << (ref->alpha()+1) << " in " << pi << "    -->    " << *newPi << std::endl;)
00168                         partitions.push_back(std::make_pair(newPi, br));
00169                         
00170                         processNewFixPoints(pi, partitions.size());
00171                         
00172                         //std::cout << "BSGS " << this->m_bsgs;
00173                         m_subgroupBase.push_back(ref->alpha());
00174                 }
00175         }
00176         
00177         this->m_order = BaseSorterByReference::createOrder(this->m_bsgs.n, pi.fixPointsBegin(), pi.fixPointsEnd());
00178         this->m_sorter.reset(new BaseSorterByReference(this->m_order));
00179         for (typename std::list<std::pair<PartitionPtr,RefinementPtr> >::iterator pIt = partitions.begin(); pIt != partitions.end(); ++pIt) {
00180                 (*pIt).second->sort(*this->m_sorter, 0);
00181                 PERMLIB_DEBUG(std::cout << "SIGMA = " << *(*pIt).first << std::endl;)
00182         }
00183         
00184         PERMLIB_DEBUG(print_iterable(this->m_order.begin(), this->m_order.end(), 0, "ORDER");)
00185 }
00186 
00187 template<class BSGSIN,class TRANSRET>
00188 unsigned int RBase<BSGSIN,TRANSRET>::processNewFixPoints(const Partition& pi, unsigned int level) {
00189         const unsigned int basePos = this->m_baseChange.change(this->m_bsgs, pi.fixPointsBegin(), pi.fixPointsEnd(), true);
00190         if (this->m_bsgs2)
00191                 this->m_baseChange.change(*this->m_bsgs2, pi.fixPointsBegin(), pi.fixPointsEnd(), true);
00192         //print_iterable(pi.fixPointsBegin(), pi.fixPointsEnd(), 1, "  fix");
00193         PERMLIB_DEBUG(print_iterable(this->m_bsgs.B.begin(), this->m_bsgs.B.end(), 1, "change base");)
00194         return basePos;
00195 }
00196 
00197 template<class BSGSIN,class TRANSRET>
00198 void RBase<BSGSIN,TRANSRET>::search(BSGS<PERM,TRANSRET> &groupK) {
00199         BOOST_ASSERT( this->m_pred != 0 );
00200         
00201         setupEmptySubgroup(groupK);
00202         
00203         unsigned int completed = partitions.size();
00204         BSGS<PERM,TRANSRET> groupL(groupK);
00205         PERM identH(this->m_bsgs.n);
00206         search(partitions.begin(), m_partition2, PERM(this->m_bsgs.n), &identH, 0, 0, completed, groupK, groupL);
00207 }
00208 
00209 template<class BSGSIN,class TRANSRET>
00210 typename BaseSearch<BSGSIN,TRANSRET>::PERM::ptr RBase<BSGSIN,TRANSRET>::searchCosetRepresentative(BSGS<PERM,TRANSRET> &groupK, BSGS<PERM,TRANSRET> &groupL) {
00211         BOOST_ASSERT( this->m_pred != 0 );
00212         
00213         // !!!
00214         //
00215         //  TODO:  check that groupK and groupL have the right base (starting with subgroupBase)
00216         //
00217         // !!!
00218         
00219         unsigned int completed = partitions.size();
00220         //BSGS<PERM,TRANS> groupL(groupK);
00221         PERM identH(this->m_bsgs.n);
00222         search(partitions.begin(), m_partition2, PERM(this->m_bsgs.n), &identH, 0, 0, completed, groupK, groupL);
00223         
00224         return BaseSearch<BSGSIN,TRANSRET>::m_lastElement;
00225 }
00226 
00227 
00228 
00229 template<class BSGSIN,class TRANSRET>
00230 unsigned int RBase<BSGSIN,TRANSRET>::search(PartitionIt pIt, Partition &pi, const PERM& t, const PERM* t2, unsigned int level, unsigned int backtrackLevel, unsigned int& completed, BSGS<PERM,TRANSRET> &groupK, BSGS<PERM,TRANSRET> &groupL) {
00231         ++this->m_statNodesVisited;
00232 
00233         if (pIt == partitions.end() || this->checkLeaf(level)) {
00234                 PERMLIB_DEBUG(std::cout << "LEAF: " << pi << " with t = " << t << std::endl;)
00235                 return processLeaf(t, level, backtrackLevel, completed, groupK, groupL);
00236         }
00237         
00238         const Partition& sigma = *((*pIt).first);
00239         const RefinementPtr& ref = (*pIt).second;
00240         ++pIt;
00241         
00242         unsigned int s = ref->alternatives();
00243         const bool isBacktrack = ref->type() == Backtrack;
00244         const bool isGroup = ref->type() == Group;
00245         const PERM* tForRefinement = &t;
00246         
00247         if (isGroup) {
00248                 GroupRefinement<PERM,TRANS>* gref = static_cast<GroupRefinement<PERM,TRANS>*>(ref.get());
00249                 if (this->m_bsgs2 && gref->bsgs() == *this->m_bsgs2) {
00250                         tForRefinement = t2;
00251                 }
00252         }
00253         
00254         ref->sort(*this->m_sorter, &pi);
00255         typedef typename Refinement<PERM>::RefinementPtrIterator RefIt;
00256         for (RefIt rIt = ref->backtrackBegin(); rIt != ref->backtrackEnd(); ++rIt) {
00257                 if (isBacktrack && s < groupK.U[backtrackLevel].size()) {
00258                         PERMLIB_DEBUG(std::cout << "PRUNE the rest:  s=" << s << " < " << groupK.U[backtrackLevel].size() << std::endl;)
00259                         this->m_statNodesPrunedCosetMinimality += s;
00260                         break;
00261                 }
00262                 
00263                 --s;
00264                 RefinementPtr ref2 = *rIt;
00265                 
00266                 const unsigned int oldFixPointsSize = pi.fixPointsSize();
00267                 PERMLIB_DEBUG(std::cout << "  refinement from " << pi << std::endl;)
00268                 const unsigned int strictRefinement = ref2->apply2(pi, *tForRefinement);
00269                 PERMLIB_DEBUG(std::cout << "  to " << pi << " with " << strictRefinement << std::endl;)
00270                 PERMLIB_DEBUG(for(unsigned int jj=0; jj<level; ++jj) std::cout << " ";)
00271                 PERMLIB_DEBUG(std::cout << "NODE " << sigma << "  ~~~>  " << pi << std::endl;)
00272                 /*
00273                 for (unsigned int q = 0; q < level; ++q) std::cout << " ";
00274                 std::cout << " " << level << ": " << sigma << " <-> " << pi2 << " from " << pi << std::endl;
00275                 for (unsigned int q = 0; q < level; ++q) std::cout << " ";
00276                 std::cout << " t = " << t << std::endl;
00277                 */
00278                 if (!strictRefinement) {
00279                         PERMLIB_DEBUG(std::cout << "no strict refinement " << sigma << " -- " << pi << std::endl;)
00280                         ++this->m_statNodesPrunedChildRestriction;
00281                         continue;
00282                 }
00283                 if (pi.cells() != sigma.cells()) {
00284                         PERMLIB_DEBUG(std::cout << "cell number mismatch " << sigma << " -- " << pi << std::endl;)
00285                         ref2->undo(pi, strictRefinement);
00286                         ++this->m_statNodesPrunedChildRestriction;
00287                         continue;
00288                 }
00289                 if (pi.fixPointsSize() != sigma.fixPointsSize()) {
00290                         PERMLIB_DEBUG(std::cout << "fix point number mismatch " << sigma << " -- " << pi << std::endl;)
00291                         ref2->undo(pi, strictRefinement);
00292                         ++this->m_statNodesPrunedChildRestriction;
00293                         continue;
00294                 }
00295                 PERM tG(t);
00296                 PERM* tH = 0;
00297                 if (pi.fixPointsSize() != oldFixPointsSize) {
00298                         if (!updateMappingPermutation(this->m_bsgs, sigma, pi, tG)) {
00299                                 PERMLIB_DEBUG(std::cout << "no t found " << sigma << " -- " << pi << "; tG = " << tG << std::endl;)
00300                                 ref2->undo(pi, strictRefinement);
00301                                 ++this->m_statNodesPrunedChildRestriction;
00302                                 continue;
00303                         }
00304                         if (this->m_bsgs2) {
00305                                 tH = new PERM(*t2);
00306                                 if (!updateMappingPermutation(*this->m_bsgs2, sigma, pi, *tH)) {
00307                                         PERMLIB_DEBUG(std::cout << "no t found " << sigma << " -- " << pi << "; tH = " << tH << std::endl;)
00308                                         ref2->undo(pi, strictRefinement);
00309                                         ++this->m_statNodesPrunedChildRestriction;
00310                                         continue;
00311                                 }
00312                         }
00313                 }
00314                 if (this->m_pruningLevelDCM && isBacktrack) {
00315                         if (pruneDCM(tG, backtrackLevel, groupK, groupL)) {
00316                                 ++this->m_statNodesPrunedCosetMinimality2;
00317                                 ref2->undo(pi, strictRefinement);
00318                                 continue;
00319                         }
00320                 }
00321                 unsigned int ret = search(pIt, pi, tG, tH ? tH : t2, level+1, isBacktrack ? (backtrackLevel + 1) : backtrackLevel, completed, groupK, groupL);
00322                 delete tH;
00323                 PERMLIB_DEBUG(std::cout << "retract " << strictRefinement << " from " << pi << " to ";)
00324                 ref2->undo(pi, strictRefinement);
00325                 PERMLIB_DEBUG(std::cout <<  pi << std::endl;)
00326                 if (BaseSearch<BSGSIN,TRANSRET>::m_stopAfterFirstElement && ret == 0)
00327                         return 0;
00328                 if (ret < level)
00329                         return ret;
00330         }
00331         
00332         completed = std::min(completed, level);
00333         return level;
00334 }
00335 
00336 template<class BSGSIN,class TRANSRET>
00337 bool RBase<BSGSIN,TRANSRET>::updateMappingPermutation(const BSGSIN& bsgs, const Partition& sigma, const Partition& pi, PERM& t2) const {
00338         typedef std::vector<unsigned long>::const_iterator FixIt;
00339         std::vector<dom_int>::const_iterator bIt;
00340         unsigned long i = 0;
00341         FixIt fixSigmaIt = sigma.fixPointsBegin();
00342         const FixIt fixSigmaEndIt = sigma.fixPointsEnd();
00343         FixIt fixPiIt = pi.fixPointsBegin();
00344         PERMLIB_DEBUG(print_iterable(bsgs.B.begin(), bsgs.B.end(), 1, "B   ");)
00345         PERMLIB_DEBUG(print_iterable(fixSigmaIt, fixSigmaEndIt, 1, "Sigma");)
00346         for (bIt = bsgs.B.begin(); bIt != bsgs.B.end(); ++bIt, ++i) {
00347                 PERMLIB_DEBUG(std::cout << "  base: " << (*bIt)+1 << std::endl;)
00348                 while (fixSigmaIt != fixSigmaEndIt && *fixSigmaIt != *bIt) {
00349                         PERMLIB_DEBUG(std::cout << "  skipping " << (*fixSigmaIt)+1 << " for " << (*bIt)+1 << std::endl;)
00350                         ++fixSigmaIt;
00351                         ++fixPiIt;
00352                 }
00353                 if (fixSigmaIt == fixSigmaEndIt) {
00354                         PERMLIB_DEBUG(std::cout << "  no more fix point found for " << (*bIt)+1 << std::endl;)
00355                         return true;
00356                 }
00357                 const unsigned long alpha = *fixSigmaIt;
00358                 const unsigned long beta = *fixPiIt;
00359                 if (t2 / alpha != beta) {
00360                         boost::scoped_ptr<PERM> u_beta(bsgs.U[i].at(t2 % beta));
00361                         if (u_beta) {
00362                                 //std::cout << "  multiply with " << *u_beta << " for " << alpha+1 << "," << beta+1 << " // base " << bsgs.B[i] + 1<< std::endl;
00363                                 t2 ^= *u_beta;
00364                         } else {
00365                                 //std::cout << "could not find a u_b with " << (t2 % beta) << " at " << i << "--" << bsgs.B[i] << " -- " << &bsgs << std::endl;
00366                                 return false;
00367                         }
00368                 }
00369                 
00370                 ++fixSigmaIt;
00371                 ++fixPiIt;
00372         }
00373         return true;
00374 }
00375 
00376 template<class BSGSIN,class TRANSRET>
00377 const std::vector<dom_int>& RBase<BSGSIN,TRANSRET>::subgroupBase() const {
00378         return m_subgroupBase;
00379 }
00380 
00381 }
00382 }
00383 
00384 #endif // -- RBASE_H_