PermLib

schreier_tree_transversal.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 SCHREIERTRANSVERSAL_H_
00034 #define SCHREIERTRANSVERSAL_H_
00035 
00036 #include <permlib/transversal/transversal.h>
00037 
00038 namespace permlib {
00039 
00041 template <class PERM>
00042 class SchreierTreeTransversal : public Transversal<PERM> {
00043 public:
00045         SchreierTreeTransversal(unsigned int n);
00046 
00047     virtual bool trivialByDefinition(const PERM& x, unsigned long to) const;
00048     virtual PERM* at(unsigned long val) const;
00049         
00050         virtual void updateGenerators(const std::map<PERM*,typename PERM::ptr>& generatorChange);
00051         
00053 
00057         SchreierTreeTransversal<PERM> clone(const std::map<PERM*,typename PERM::ptr>& generatorChange) const;
00058         
00060     mutable unsigned int m_statMaxDepth;
00061 protected:
00062     virtual void registerMove(unsigned long from, unsigned long to, const typename PERM::ptr &p);
00063 };
00064 
00065 //
00066 //     ----       IMPLEMENTATION
00067 //
00068 
00069 template <class PERM>
00070 SchreierTreeTransversal<PERM>::SchreierTreeTransversal(unsigned int n) 
00071         : Transversal<PERM>(n), m_statMaxDepth(0) 
00072 { }
00073 
00074 template <class PERM>
00075 bool SchreierTreeTransversal<PERM>::trivialByDefinition(const PERM& x, unsigned long to) const {
00076         return *Transversal<PERM>::m_transversal[to] == x; 
00077 }
00078 
00079 template <class PERM>
00080 void SchreierTreeTransversal<PERM>::registerMove(unsigned long from, unsigned long to, const typename PERM::ptr &p) {
00081         Transversal<PERM>::registerMove(from, to, p);
00082         Transversal<PERM>::m_transversal[to] = p;
00083 }
00084 
00085 
00086 template <class PERM>
00087 PERM* SchreierTreeTransversal<PERM>::at(unsigned long val) const {
00088         const std::vector<boost::shared_ptr<PERM> > &transversal = Transversal<PERM>::m_transversal;
00089 
00090         if (transversal[val] == 0) {
00091                 return 0;
00092         }
00093 
00094         unsigned int depth = 1;
00095         PERM *res = new PERM(*transversal[val]);
00096         const PERM* inv = 0;
00097         //std::cout << "Schreier " << *res << std::endl;
00098         unsigned long pred = *res % val;
00099         //TODO: reserve space for PermutationWord-res beforehand (we know how long the m_word vector will be)
00100         while (pred != val) {
00101                 inv = transversal[pred].get();
00102                 //std::cout << "Schreier2 " << inv << " / " << val << " , " << pred << std::endl;
00103                 *res ^= *inv;
00104                 val = pred;
00105                 pred = *inv % pred;
00106                 ++depth;
00107         }
00108         m_statMaxDepth = std::max(m_statMaxDepth, depth);
00109         //std::cout << "Schreier3 " << *res << std::endl;
00110         return res;
00111 }
00112 
00113 template <class PERM>
00114 void SchreierTreeTransversal<PERM>::updateGenerators(const std::map<PERM*,typename PERM::ptr>& generatorChange) {
00115         unsigned int missedCount = 0;
00116         BOOST_FOREACH(typename PERM::ptr& p, this->m_transversal) {
00117                 if (!p)
00118                         continue;
00119                 //std::cout << "require " << p.get() << std::endl;
00120                 typename std::map<PERM*,typename PERM::ptr>::const_iterator pIt = generatorChange.find(p.get());
00121                 //BOOST_ASSERT( pIt != generatorChange.end() );
00122                 if (pIt != generatorChange.end()) {
00123                         p = (*pIt).second;
00124                 } else {
00125                         ++missedCount;
00126                         //std::cout << "missed " << p.get() << " = " << *p << std::endl;
00127                 }
00128         }
00129         // we always miss the identity -- and not anything else
00130         BOOST_ASSERT( missedCount == 1 );
00131 }
00132 
00133 template <class PERM>
00134 SchreierTreeTransversal<PERM> SchreierTreeTransversal<PERM>::clone(const std::map<PERM*,typename PERM::ptr>& generatorChange) const {
00135         SchreierTreeTransversal<PERM> ret(*this);
00136         ret.updateGenerators(generatorChange);
00137         return ret;
00138 }
00139 
00140 }
00141 
00142 #endif // -- SCHREIERTRANSVERSAL_H_