Generated on: Thu Mar 29 07:46:58 PDT 2012 for custom file set | ||
|
||
00001 // Copyright 2010-2012 Google 00002 // Licensed under the Apache License, Version 2.0 (the "License"); 00003 // you may not use this file except in compliance with the License. 00004 // You may obtain a copy of the License at 00005 // 00006 // http://www.apache.org/licenses/LICENSE-2.0 00007 // 00008 // Unless required by applicable law or agreed to in writing, software 00009 // distributed under the License is distributed on an "AS IS" BASIS, 00010 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00011 // See the License for the specific language governing permissions and 00012 // limitations under the License. 00013 // 00014 // Classes for permuting indexable, ordered containers of data without 00015 // depending on that data to be accessible in any particular way. The 00016 // client needs to give us two things: 00017 // 1. a permutation to apply to some container(s) of data, and 00018 // 2. a description of how to move data around in the container(s). 00019 // 00020 // The permutation (1) comes to us in the form of an array argument to 00021 // PermutationApplier::Apply(), along with index values that tell us 00022 // where in that array the permutation of interest lies. Typically 00023 // those index values will span the entire array that describes the 00024 // permutation. 00025 // 00026 // Applying a permutation involves decomposing the permutation into 00027 // disjoint cycles and walking each element of the underlying data one 00028 // step around the unique cycle in which it participates. The 00029 // decomposition into disjoint cycles is done implicitly on the fly as 00030 // the code in PermutationApplier::Apply() advances through the array 00031 // describing the permutation. As an important piece of bookkeeping to 00032 // support the decomposition into cycles, the elements of the 00033 // permutation array typically get modified somehow to indicate which 00034 // ones have already been used. 00035 // 00036 // At first glance, it would seem that if the containers are 00037 // indexable, we don't need anything more complicated than just the 00038 // permutation and the container of data we want to permute; it would 00039 // seem we can just use the container's operator[] to retrieve and 00040 // assign elements within the container. Unfortunately it's not so 00041 // simple because the containers of interest can be indexable without 00042 // providing any consistent way of accessing their contents that 00043 // applies to all the containers of interest. For instance, if we 00044 // could insist that every indexable container must define an lvalue 00045 // operator[]() we could simply use that for the assignments we need 00046 // to do while walking around cycles of the permutation. But we cannot 00047 // insist on any such thing. To see why, consider the PackedArray 00048 // class template in util/packed_array.h 00049 // where operator[] is supplied for rvalues, but because each logical 00050 // array element is packed across potentially multiple instances of 00051 // the underlying data type that the C++ language knows about, there 00052 // is no way to have a C++ reference to an element of a 00053 // PackedArray. There are other such examples besides PackedArray, 00054 // too. This is the main reason we need a codified description (2) of 00055 // how to move data around in the indexable container. That 00056 // description comes to us via the PermutationApplier constructor's 00057 // argument which is a PermutationCycleHandler instance. Such an 00058 // object has three important methods defined: SetTempFromIndex(), 00059 // SetIndexFromIndex(), and SetIndexFromTemp(). Those methods embody 00060 // all we need to know about how to move data in the indexable 00061 // container(s) underlying the PermutationCycleHandler. 00062 // 00063 // Another reason we need the description (2) of how to move elements 00064 // around in the container(s) is that it is often important to permute 00065 // side-by-side containers of elements according to the same 00066 // permutation. This situation, too, is covered by defining a 00067 // PermutationCycleHandler that knows about multiple underlying 00068 // indexable containers. 00069 // 00070 // The above-mentioned PermutationCycleHandler methods embody 00071 // knowledge of how to assign elements. It happens that 00072 // PermutationCycleHandler is also a convenient place to embody the 00073 // knowledge of how to keep track of which permutation elements have 00074 // been consumed by the process of walking data around cycles. We 00075 // depend on the PermutationCycleHandler instance we're given to 00076 // define SetSeen() and Unseen() methods for that purpose. 00077 // 00078 // For the common case in which elements can be accessed using 00079 // operator[](), we provide the class template 00080 // ArrayIndexCycleHandler. 00081 00082 #ifndef OR_TOOLS_UTIL_PERMUTATION_H_ 00083 #define OR_TOOLS_UTIL_PERMUTATION_H_ 00084 00085 #include "base/logging.h" 00086 #include "base/macros.h" 00087 00088 namespace operations_research { 00089 00090 // Abstract base class template defining the interface needed by 00091 // PermutationApplier to handle a single cycle of a permutation. 00092 template <typename IndexType> class PermutationCycleHandler { 00093 public: 00094 // Sets the internal temporary storage from the given index in the 00095 // underlying container(s). 00096 virtual void SetTempFromIndex(IndexType source) = 0; 00097 00098 // Moves a data element one step along its cycle. 00099 virtual void SetIndexFromIndex(IndexType source, 00100 IndexType destination) const = 0; 00101 00102 // Sets a data element from the temporary. 00103 virtual void SetIndexFromTemp(IndexType destination) const = 0; 00104 00105 // Marks an element of the permutation as handled by 00106 // PermutationHandler::Apply(), meaning that we have read the 00107 // corresponding value from the data to be permuted, and put that 00108 // value somewhere (either in the temp or in its ultimate 00109 // destination in the data. 00110 // 00111 // This method must be overridden in implementations where it is 00112 // called. If an implementation doesn't call it, no need to 00113 // override. 00114 virtual void SetSeen(IndexType* unused_permutation_element) const { 00115 LOG(FATAL) << "Base implementation of SetSeen() must not be called."; 00116 } 00117 00118 // Returns true iff the given element of the permutation is unseen, 00119 // meaning that it has not yet been handled by 00120 // PermutationApplier::Apply(). 00121 // 00122 // This method must be overridden in implementations where it is 00123 // called. If an implementation doesn't call it, no need to 00124 // override. 00125 virtual bool Unseen(IndexType unused_permutation_element) const { 00126 LOG(FATAL) << "Base implementation of Unseen() must not be called."; 00127 return false; 00128 } 00129 00130 virtual ~PermutationCycleHandler() { } 00131 00132 protected: 00133 PermutationCycleHandler() { } 00134 00135 private: 00136 DISALLOW_COPY_AND_ASSIGN(PermutationCycleHandler); 00137 }; 00138 00139 // A generic cycle handler class for the common case in which the 00140 // object to be permuted is indexable with T& operator[](int), and the 00141 // permutation is represented by a mutable array of nonnegative 00142 // int-typed index values. To mark a permutation element as seen, we 00143 // replace it by its ones-complement value. 00144 template <typename DataType, typename IndexType> class ArrayIndexCycleHandler 00145 : public PermutationCycleHandler<IndexType> { 00146 public: 00147 explicit ArrayIndexCycleHandler(DataType* data) : data_(data) { } 00148 00149 virtual void SetTempFromIndex(IndexType source) { 00150 temp_ = data_[source]; 00151 } 00152 virtual void SetIndexFromIndex(IndexType source, 00153 IndexType destination) const { 00154 data_[destination] = data_[source]; 00155 } 00156 virtual void SetIndexFromTemp(IndexType destination) const { 00157 data_[destination] = temp_; 00158 } 00159 virtual void SetSeen(IndexType *permutation_element) const { 00160 *permutation_element = -*permutation_element - 1; 00161 } 00162 virtual bool Unseen(IndexType permutation_element) const { 00163 return permutation_element >= 0; 00164 } 00165 00166 private: 00167 // Pointer to the base of the array of data to be permuted. 00168 DataType* data_; 00169 00170 // Temporary storage for the one extra element we need. 00171 DataType temp_; 00172 00173 DISALLOW_COPY_AND_ASSIGN(ArrayIndexCycleHandler); 00174 }; 00175 00176 // Note that this template is not implemented in an especially 00177 // performance-sensitive way. In particular, it makes multiple virtual 00178 // method calls for each element of the permutation. 00179 template <typename IndexType> class PermutationApplier { 00180 public: 00181 explicit PermutationApplier( 00182 PermutationCycleHandler<IndexType>* cycle_handler) 00183 : cycle_handler_(cycle_handler) { } 00184 00185 void Apply(IndexType permutation[], 00186 int permutation_start, 00187 int permutation_end) { 00188 for (IndexType current = permutation_start; 00189 current < permutation_end; 00190 ++current) { 00191 IndexType next = permutation[current]; 00192 // cycle_start is only for debugging. 00193 const IndexType cycle_start = current; 00194 if (cycle_handler_->Unseen(next)) { 00195 cycle_handler_->SetSeen(&permutation[current]); 00196 DCHECK(!cycle_handler_->Unseen(permutation[current])); 00197 cycle_handler_->SetTempFromIndex(current); 00198 while (cycle_handler_->Unseen(permutation[next])) { 00199 cycle_handler_->SetIndexFromIndex(next, current); 00200 current = next; 00201 next = permutation[next]; 00202 cycle_handler_->SetSeen(&permutation[current]); 00203 DCHECK(!cycle_handler_->Unseen(permutation[current])); 00204 } 00205 cycle_handler_->SetIndexFromTemp(current); 00206 // Set current back to the start of this cycle. 00207 current = next; 00208 } 00209 DCHECK_EQ(cycle_start, current); 00210 } 00211 } 00212 00213 private: 00214 PermutationCycleHandler<IndexType>* cycle_handler_; 00215 00216 DISALLOW_COPY_AND_ASSIGN(PermutationApplier); 00217 }; 00218 } 00219 #endif // OR_TOOLS_UTIL_PERMUTATION_H_