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 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_