OR-Tools  9.6
lp_data/permutation.h
Go to the documentation of this file.
1 // Copyright 2010-2022 Google LLC
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 #ifndef OR_TOOLS_LP_DATA_PERMUTATION_H_
15 #define OR_TOOLS_LP_DATA_PERMUTATION_H_
16 
17 #include "absl/random/random.h"
21 
22 namespace operations_research {
23 namespace glop {
24 
25 // Permutation<IndexType> is a template class for storing and using
26 // row- and column- permutations, when instantiated with RowIndex and ColIndex
27 // respectively.
28 //
29 // By a row permutation we mean a permutation that maps the row 'i' of a matrix
30 // (or column vector) to the row 'permutation[i]' and in a similar fashion by a
31 // column permutation we mean a permutation that maps the column 'j' of a matrix
32 // (or row vector) to the column 'permutation[j]'.
33 //
34 // A permutation can be represented as a matrix P, but it gets a bit tricky
35 // here: P.x permutes the rows of x according to the permutation P but x^T.P
36 // permutes the columns of x^T (a row vector) using the INVERSE permutation.
37 // That is, to permute the columns of x^T using P, one has to compute
38 // x^T.P^{-1} but P^{-1} = P^T so the notation is consistent: If P.x permutes x,
39 // then (P.x)^T = x^T.P^T permutes x^T with the same permutation.
40 //
41 // So to be clear, if P and Q are permutation matrices, the matrix P.A.Q^{-1}
42 // is the image of A through the row permutation P and column permutation Q.
43 template <typename IndexType>
44 class Permutation {
45  public:
46  Permutation() : perm_() {}
47 
48  explicit Permutation(IndexType size) : perm_(size.value(), IndexType(0)) {}
49 
50  IndexType size() const { return IndexType(perm_.size()); }
51  bool empty() const { return perm_.empty(); }
52 
53  void clear() { perm_.clear(); }
54 
55  void resize(IndexType size, IndexType value) {
56  perm_.resize(size.value(), value);
57  }
58 
59  void assign(IndexType size, IndexType value) {
60  perm_.assign(size.value(), value);
61  }
62 
63  IndexType& operator[](IndexType i) { return perm_[i]; }
64 
65  const IndexType operator[](IndexType i) const { return perm_[i]; }
66 
67  // Populates the calling object with the inverse permutation of the parameter
68  // inverse.
69  void PopulateFromInverse(const Permutation& inverse);
70 
71  // Populates the calling object with the identity permutation.
73 
74  // Populates the calling object with a random permutation.
76 
77  // Returns true if the calling object contains a permutation, false otherwise.
78  bool Check() const;
79 
80  // Returns the signature of a permutation in O(n), where n is the permutation
81  // size.
82  // The signature of a permutation is the product of the signature of
83  // the cycles defining the permutation.
84  // The signature of an odd cycle is 1, while the signature of an even cycle
85  // is -1. (Remembering hint: the signature of a swap (a 2-cycle) is -1.)
86  int ComputeSignature() const;
87 
88  private:
90 
91  DISALLOW_COPY_AND_ASSIGN(Permutation);
92 };
93 
96 
97 // Applies the permutation perm to the vector b. Overwrites result to store
98 // the result.
99 // TODO(user): Try to restrict this method to using the same integer type in
100 // the permutation and for the vector indices, i.e.
101 // IndexType == ITIVectorType::IndexType. Some client code will need to be
102 // refactored.
103 template <typename IndexType, typename ITIVectorType>
105  const ITIVectorType& b, ITIVectorType* result);
106 
107 // Applies the inverse of perm to the vector b. Overwrites result to store
108 // the result.
109 template <typename IndexType, typename ITIVectorType>
111  const ITIVectorType& b, ITIVectorType* result);
112 
113 // Specialization of ApplyPermutation(): apply a column permutation to a
114 // row-indexed vector v.
115 template <typename RowIndexedVector>
117  const Permutation<ColIndex>& col_perm, RowIndexedVector* v) {
118  RowIndexedVector temp_v = *v;
119  ApplyPermutation(col_perm, temp_v, v);
120 }
121 
122 template <typename RowIndexedVector>
124  const Permutation<ColIndex>& col_perm, RowIndexedVector* v,
125  RowIndexedVector* tmp) {
126  ApplyPermutation(col_perm, *v, tmp);
127  std::swap(*tmp, *v);
128 }
129 
130 // --------------------------------------------------------
131 // Implementation
132 // --------------------------------------------------------
133 
134 template <typename IndexType>
136  const size_t size = inverse.perm_.size();
137  perm_.resize(size);
138  for (IndexType i(0); i < size; ++i) {
139  perm_[inverse[i]] = i;
140  }
141 }
142 
143 template <typename IndexType>
145  const size_t size = perm_.size();
146  perm_.resize(size, IndexType(0));
147  for (IndexType i(0); i < size; ++i) {
148  perm_[i] = i;
149  }
150 }
151 
152 template <typename IndexType>
154  PopulateFromIdentity();
155  std::shuffle(perm_.begin(), perm_.end());
156 }
157 
158 template <typename IndexType>
160  const size_t size = perm_.size();
161  absl::StrongVector<IndexType, bool> visited(size, false);
162  for (IndexType i(0); i < size; ++i) {
163  if (perm_[i] < 0 || perm_[i] >= size) {
164  return false;
165  }
166  visited[perm_[i]] = true;
167  }
168  for (IndexType i(0); i < size; ++i) {
169  if (!visited[i]) {
170  return false;
171  }
172  }
173  return true;
174 }
175 
176 template <typename IndexType>
178  const size_t size = perm_.size();
180  DCHECK(Check());
181  int signature = 1;
182  for (IndexType i(0); i < size; ++i) {
183  if (!visited[i]) {
184  int cycle_size = 0;
185  IndexType j = i;
186  do {
187  j = perm_[j];
188  visited[j] = true;
189  ++cycle_size;
190  } while (j != i);
191  if ((cycle_size & 1) == 0) {
192  signature = -signature;
193  }
194  }
195  }
196  return signature;
197 }
198 
199 template <typename IndexType, typename ITIVectorType>
201  const ITIVectorType& b, ITIVectorType* result) {
202  RETURN_IF_NULL(result);
203  const IndexType size(perm.size());
204  if (size == 0) {
205  // Empty size means identity.
206  *result = b;
207  return;
208  }
209  DCHECK_EQ(size.value(), b.size().value());
210  result->resize(b.size(), /*whatever junk value*/ b.back());
211  for (IndexType i(0); i < size; ++i) {
212  const typename ITIVectorType::IndexType ith_index(i.value());
213  const typename ITIVectorType::IndexType permuted(perm[i].value());
214  (*result)[permuted] = b[ith_index];
215  }
216 }
217 
218 template <typename IndexType, typename ITIVectorType>
220  const ITIVectorType& b, ITIVectorType* result) {
221  RETURN_IF_NULL(result);
222  const IndexType size(perm.size());
223  if (size == 0) {
224  // Empty size means identity.
225  *result = b;
226  return;
227  }
228  DCHECK_EQ(size.value(), b.size().value());
229  result->resize(b.size(), /*whatever junk value*/ b.back());
230  for (IndexType i(0); i < size; ++i) {
231  const typename ITIVectorType::IndexType ith_index(i.value());
232  const typename ITIVectorType::IndexType permuted(perm[i].value());
233  (*result)[ith_index] = b[permuted];
234  }
235 }
236 
237 } // namespace glop
238 } // namespace operations_research
239 
240 #endif // OR_TOOLS_LP_DATA_PERMUTATION_H_
void assign(size_type n, const value_type &val)
void resize(size_type new_size)
size_type size() const
bool empty() const
void resize(IndexType size, IndexType value)
const IndexType operator[](IndexType i) const
void assign(IndexType size, IndexType value)
void PopulateFromInverse(const Permutation &inverse)
int64_t b
int64_t value
void ApplyInversePermutation(const Permutation< IndexType > &perm, const ITIVectorType &b, ITIVectorType *result)
Permutation< ColIndex > ColumnPermutation
void ApplyPermutation(const Permutation< IndexType > &perm, const ITIVectorType &b, ITIVectorType *result)
void ApplyColumnPermutationToRowIndexedVector(const Permutation< ColIndex > &col_perm, RowIndexedVector *v)
Permutation< RowIndex > RowPermutation
void swap(IdMap< K, V > &a, IdMap< K, V > &b)
Definition: id_map.h:269
Collection of objects used to extend the Constraint Solver library.
#define RETURN_IF_NULL(x)
Definition: return_macros.h:20