PermLib

partition.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 PARTITION_H_
00034 #define PARTITION_H_
00035 
00036 #include <algorithm>
00037 #include <list>
00038 #include <boost/foreach.hpp>
00039 #include <boost/dynamic_bitset.hpp>
00040 
00041 namespace permlib {
00042 namespace partition {
00043         
00044 template<class T>
00045 class BacktrackRefinement;
00046 
00048 class Partition {
00049 public:
00051         explicit Partition(unsigned long n);
00052         
00054 
00061         template<class ForwardIterator>
00062         bool intersect(ForwardIterator begin, ForwardIterator end, unsigned int j);
00064         bool undoIntersection();
00065 
00068         template<class ForwardIterator>
00069         bool intersects(ForwardIterator begin, ForwardIterator end, unsigned int j) const;
00070         
00072         unsigned int fixPointsSize() const;
00074         std::vector<unsigned long>::const_iterator fixPointsBegin() const;
00076         std::vector<unsigned long>::const_iterator fixPointsEnd() const;
00078         unsigned long cells() const;
00080         unsigned long cellSize(unsigned int c) const;
00081         
00082         typedef std::vector<unsigned long>::const_iterator CellIt;
00083         
00084         CellIt cellBegin(unsigned long cell) const { 
00085                 BOOST_ASSERT(cell < cells());
00086                 return partition.begin() + partitionCellBorder[cell];
00087         }
00088         
00089         CellIt cellEnd(unsigned long cell) const { 
00090                 BOOST_ASSERT(cell < cells());
00091                 return partition.begin() + partitionCellBorder[cell] + partitionCellLength[cell];
00092         }
00093 private:
00094         explicit Partition(unsigned long n, bool);
00095         
00096         std::vector<unsigned long> partition;
00097         std::vector<unsigned int> partitionCellBorder;
00098         std::vector<unsigned int> partitionCellLength;
00099         std::vector<unsigned int> partitionCellOf;
00100         
00102         unsigned int cellCounter;
00103         
00106         std::vector<unsigned long> fix;
00108         unsigned int fixCounter;
00109         
00110         friend std::ostream& operator<<(std::ostream& out, const Partition& p);
00111         
00112         template<class T>
00113         friend class BacktrackRefinement;
00114 };
00115 
00116 inline std::ostream& operator<<(std::ostream& out, const Partition& p) {
00117         out << "[";
00118         std::vector<unsigned int>::const_iterator border = p.partitionCellBorder.begin();
00119         std::vector<unsigned int>::const_iterator length = p.partitionCellLength.begin();
00120         for (unsigned int j = 0; j < p.cellCounter; ++j) {
00121                 for (unsigned int i = *border; i < *border + *length; ++i) {
00122                         out << (p.partition[i] + 1) << " ";
00123                 }
00124                 out << "| ";
00125                 ++border;
00126                 ++length;
00127         }       
00128         out << "]|(";
00129         int countFix = p.fixCounter;
00130         BOOST_FOREACH(unsigned long alpha, p.fix) {
00131                 if (--countFix < 0)
00132                         break;
00133                 out << (alpha+1) << ",";
00134         }
00135         out << ")";
00136         return out;
00137 }
00138 
00139 inline Partition::Partition(unsigned long n) 
00140         : partition(n), partitionCellBorder(n), partitionCellLength(n), partitionCellOf(n), cellCounter(1), fix(n), fixCounter(0)
00141 {
00142         for (unsigned int i=0; i<n; ++i) {
00143                 partition[i] = i;
00144                 // partitionCellOf is already zero
00145         }
00146         partitionCellBorder[0] = 0;
00147         partitionCellLength[0] = n;
00148 }
00149 
00150 inline Partition::Partition(unsigned long n, bool) 
00151         : partition(n), partitionCellBorder(n), partitionCellLength(n), partitionCellOf(n), cellCounter(0), fix(n), fixCounter(0)
00152 { }
00153 
00154 inline unsigned long Partition::cells() const {
00155         return cellCounter;
00156 }
00157 
00158 inline unsigned int Partition::fixPointsSize() const {
00159         return fixCounter;
00160 }
00161 inline std::vector<unsigned long>::const_iterator Partition::fixPointsBegin() const {
00162         return fix.begin();
00163 }
00164 inline std::vector<unsigned long>::const_iterator Partition::fixPointsEnd() const {
00165         return fix.begin() + fixCounter;
00166 }
00167 inline unsigned long Partition::cellSize(unsigned int c) const {
00168         return partitionCellLength[c]; 
00169 }
00170 
00171 template<class ForwardIterator>
00172 inline bool Partition::intersects(ForwardIterator begin, ForwardIterator end, unsigned int j) const {
00173         while (begin != end) {
00174                 //std::cout << " B " << *begin << " < " << partitionCellOf[*begin] << " < " << j << std::endl;
00175                 if (partitionCellOf[*begin++] == j)
00176                         return true;
00177         }
00178         return false;
00179 }
00180 
00182 template<class ForwardIterator>
00183 inline bool Partition::intersect(ForwardIterator otherCellBegin, ForwardIterator otherCellEnd, unsigned int j) {
00184         if (!intersects(otherCellBegin, otherCellEnd, j))
00185                 return false;
00186         
00187         //WARNING: not thread-safe
00188         static std::vector<unsigned long> newCell(partition.size());
00189         
00190         ForwardIterator otherCellIt = otherCellBegin;
00191         std::vector<unsigned long>::iterator cellIt;
00192         std::vector<unsigned long>::reverse_iterator newCellIt;
00193         std::vector<unsigned long>::reverse_iterator newCellBeginIt;
00194         std::vector<unsigned long>::iterator newCell2It;
00195         std::vector<unsigned int>::iterator   borderIt;
00196         bool createdNewCell = false;
00197         const unsigned int cellSize = partitionCellLength[j];
00198         if (j >= cellCounter)
00199                 return false;
00200         if (cellSize <= 1)
00201                 return false;
00202         std::vector<unsigned long>::iterator cellBeginIt = partition.begin() + partitionCellBorder[j];
00203         std::vector<unsigned long>::iterator cellEndIt   = partition.begin() + (partitionCellBorder[j] + partitionCellLength[j]);
00204         //print_iterable(cellBeginIt, cellEndIt, 1, " ^ cell");
00205         newCellBeginIt  = newCell.rbegin() + (partition.size() - cellSize);
00206         newCellIt       = newCellBeginIt;
00207         newCell2It      = newCell.begin();
00208         unsigned int newCellCounter = 0;
00209         
00210         for (cellIt = cellBeginIt; cellIt != cellEndIt; ++cellIt) {
00211                 while (otherCellIt != otherCellEnd && *otherCellIt < *cellIt) {
00212                         ++otherCellIt;
00213                 }
00214                 if (otherCellIt != otherCellEnd && *cellIt == *otherCellIt) {
00215                         *newCell2It = *cellIt;
00216                         ++newCell2It;
00217                         if (newCellCounter == 0) {
00218                                 /*std::cout << "copy into new cell ";
00219                                 print_iterable(partition.begin() + borderLo, cellIt, 1);
00220                                 std::cout << std::endl;*/
00221                                 newCellIt = std::copy(cellBeginIt, cellIt, newCellIt);
00222                         }
00223                         ++newCellCounter;
00224                 } else if (newCellCounter) {
00225                         *newCellIt = *cellIt;
00226                         ++newCellIt;
00227                 }
00228         }
00229         
00230         if (newCellCounter > 0 && newCellCounter < cellSize) {
00231                 std::reverse(newCellBeginIt, newCellIt);
00232                 std::copy(newCell.begin(), newCell.begin() + cellSize, cellBeginIt);
00233                 /*std::cout << "new cell[" << cellSize << "] = ";
00234                 print_iterable(newCell.begin(), newCell.begin() + cellSize, 1);
00235                 std::cout << std::endl;*/
00236                 std::vector<unsigned long>::iterator fixIt = fix.begin() + fixCounter;
00237                 
00238                 if (newCellCounter == 1) {
00239                         *fixIt = newCell[0];
00240                         ++fixIt;
00241                         ++fixCounter;
00242                 }
00243                 if (newCellCounter == cellSize - 1) {
00244                         *fixIt = newCell[cellSize - 1];
00245                         ++fixIt;
00246                         ++fixCounter;
00247                 }
00248                 
00249                 /*
00250                 for (unsigned int i = partitionCellBorder[j]; i < partitionCellBorder[j] + partitionCellLength[j]; ++i) {
00251                         std::cout << partition[i]+1 << " ";
00252                 }
00253                 std::cout << std::endl;
00254                 std::cout << "new cell counter " << newCellCounter << std::endl;
00255                 */
00256                 
00257                 partitionCellLength[j] = newCellCounter;
00258                 
00259                 //std::cout << "cellCounter " << cellCounter << std::endl;
00260                 partitionCellBorder[cellCounter] = partitionCellBorder[j] + newCellCounter;
00261                 partitionCellLength[cellCounter] = cellSize - newCellCounter;
00262                 for (unsigned int i = partitionCellBorder[cellCounter]; i < partitionCellBorder[j] + cellSize; ++i) {
00263                         partitionCellOf[partition[i]] = cellCounter;
00264                 }
00265                 ++cellCounter;
00266                 
00267                 createdNewCell = true;
00268         }
00269                 
00270         return createdNewCell;
00271 }
00272 
00273 inline bool Partition::undoIntersection() {
00274         if (partitionCellBorder[cellCounter-1] < 1)
00275                 return false;
00276         --cellCounter;
00277         unsigned int splitFromCellNumber = partitionCellOf[ partition[partitionCellBorder[cellCounter] - 1] ];
00278         
00279         BOOST_ASSERT(partitionCellBorder[splitFromCellNumber] < partitionCellBorder[cellCounter]);
00280         BOOST_ASSERT(partitionCellLength[cellCounter] > 0 );
00281         //std::cout << "split from " << splitFromCellNumber << std::endl;
00282         //std::cout << "merge " << partitionCellBorder[splitFromCellNumber] << " " << partitionCellBorder[cellCounter] << " " << (partitionCellBorder[cellCounter] + partitionCellLength[cellCounter]) << std::endl;
00283         
00284         for (unsigned int i=partitionCellBorder[cellCounter]; i<partitionCellBorder[cellCounter] + partitionCellLength[cellCounter]; ++i) {
00285                 partitionCellOf[partition[i]] = splitFromCellNumber;
00286         }
00287         std::inplace_merge(partition.begin() + partitionCellBorder[splitFromCellNumber],
00288                                            partition.begin() + partitionCellBorder[cellCounter],
00289                                            partition.begin() + (partitionCellBorder[cellCounter] + partitionCellLength[cellCounter]));
00290         
00291         
00292         if (partitionCellLength[cellCounter] == 1) {
00293                 --fixCounter;
00294                 fix[fixCounter] = 0;
00295         }
00296         if (partitionCellLength[splitFromCellNumber] == 1) {
00297                 --fixCounter;
00298                 fix[fixCounter] = 0;
00299         }
00300         
00301         partitionCellLength[splitFromCellNumber] += partitionCellLength[cellCounter];
00302         
00303         partitionCellLength[cellCounter] = 0;
00304         partitionCellBorder[cellCounter] = 0;
00305         
00306         return true;
00307 }
00308 
00309 }
00310 }
00311 
00312 #endif // -- PARTITION_H_