Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
permutation.h
Go to the documentation of this file.
1// Copyright 2010-2024 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
22namespace operations_research {
23namespace 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.
43template <typename IndexType>
45 public:
46 Permutation() : perm_() {}
47
48 explicit Permutation(IndexType size) : perm_(size.value(), IndexType(0)) {}
49
50 // This type is neither copyable nor movable.
51 Permutation(const Permutation&) = delete;
53
54 IndexType size() const { return IndexType(perm_.size()); }
55 bool empty() const { return perm_.empty(); }
56
57 void clear() { perm_.clear(); }
58
59 void resize(IndexType size, IndexType value) {
60 perm_.resize(size.value(), value);
61 }
62
63 void assign(IndexType size, IndexType value) {
64 perm_.assign(size.value(), value);
65 }
66
67 IndexType& operator[](IndexType i) { return perm_[i]; }
68
69 IndexType operator[](IndexType i) const { return perm_[i]; }
70
71 // Populates the calling object with the inverse permutation of the parameter
72 // inverse.
73 void PopulateFromInverse(const Permutation& inverse);
74
75 // Populates the calling object with the identity permutation.
77
78 // Populates the calling object with a random permutation.
80
81 // Returns true if the calling object contains a permutation, false otherwise.
82 bool Check() const;
83
84 // Returns the signature of a permutation in O(n), where n is the permutation
85 // size.
86 // The signature of a permutation is the product of the signature of
87 // the cycles defining the permutation.
88 // The signature of an odd cycle is 1, while the signature of an even cycle
89 // is -1. (Remembering hint: the signature of a swap (a 2-cycle) is -1.)
90 int ComputeSignature() const;
91
92 private:
94};
95
98
99// Applies the permutation perm to the vector b. Overwrites result to store
100// the result.
101// TODO(user): Try to restrict this method to using the same integer type in
102// the permutation and for the vector indices, i.e.
103// IndexType == ITIVectorType::IndexType. Some client code will need to be
104// refactored.
105template <typename IndexType, typename ITIVectorType>
107 const ITIVectorType& b, ITIVectorType* result);
108
109// Applies the inverse of perm to the vector b. Overwrites result to store
110// the result.
111template <typename IndexType, typename ITIVectorType>
113 const ITIVectorType& b, ITIVectorType* result);
114
115// Specialization of ApplyPermutation(): apply a column permutation to a
116// row-indexed vector v.
117template <typename RowIndexedVector>
119 const Permutation<ColIndex>& col_perm, RowIndexedVector* v) {
120 RowIndexedVector temp_v = *v;
121 ApplyPermutation(col_perm, temp_v, v);
122}
123
124template <typename RowIndexedVector>
126 const Permutation<ColIndex>& col_perm, RowIndexedVector* v,
127 RowIndexedVector* tmp) {
128 ApplyPermutation(col_perm, *v, tmp);
129 std::swap(*tmp, *v);
130}
131
132// --------------------------------------------------------
133// Implementation
134// --------------------------------------------------------
135
136template <typename IndexType>
137void Permutation<IndexType>::PopulateFromInverse(const Permutation& inverse) {
138 const size_t size = inverse.perm_.size();
139 perm_.resize(size);
140 for (IndexType i(0); i < size; ++i) {
141 perm_[inverse[i]] = i;
142 }
143}
144
145template <typename IndexType>
147 const size_t size = perm_.size();
148 perm_.resize(size, IndexType(0));
149 for (IndexType i(0); i < size; ++i) {
150 perm_[i] = i;
151 }
152}
153
154template <typename IndexType>
156 PopulateFromIdentity();
157 std::shuffle(perm_.begin(), perm_.end());
158}
159
160template <typename IndexType>
162 const size_t size = perm_.size();
164 for (IndexType i(0); i < size; ++i) {
165 if (perm_[i] < 0 || perm_[i] >= size) {
166 return false;
167 }
168 visited[perm_[i]] = true;
169 }
170 for (IndexType i(0); i < size; ++i) {
171 if (!visited[i]) {
172 return false;
173 }
174 }
175 return true;
176}
177
178template <typename IndexType>
180 const size_t size = perm_.size();
182 DCHECK(Check());
183 int signature = 1;
184 for (IndexType i(0); i < size; ++i) {
185 if (!visited[i]) {
186 int cycle_size = 0;
187 IndexType j = i;
188 do {
189 j = perm_[j];
190 visited[j] = true;
191 ++cycle_size;
192 } while (j != i);
193 if ((cycle_size & 1) == 0) {
194 signature = -signature;
195 }
196 }
197 }
198 return signature;
199}
200
201template <typename IndexType, typename ITIVectorType>
202void ApplyPermutation(const Permutation<IndexType>& perm,
203 const ITIVectorType& b, ITIVectorType* result) {
205 const IndexType size(perm.size());
206 if (size == 0) {
207 // Empty size means identity.
208 *result = b;
209 return;
210 }
211 DCHECK_EQ(size.value(), b.size().value());
212 result->resize(b.size(), /*whatever junk value*/ b.back());
213 for (IndexType i(0); i < size; ++i) {
214 const typename ITIVectorType::IndexType ith_index(i.value());
215 const typename ITIVectorType::IndexType permuted(perm[i].value());
216 (*result)[permuted] = b[ith_index];
217 }
218}
219
220template <typename IndexType, typename ITIVectorType>
221void ApplyInversePermutation(const Permutation<IndexType>& perm,
222 const ITIVectorType& b, ITIVectorType* result) {
224 const IndexType size(perm.size());
225 if (size == 0) {
226 // Empty size means identity.
227 *result = b;
228 return;
229 }
230 DCHECK_EQ(size.value(), b.size().value());
231 result->resize(b.size(), /*whatever junk value*/ b.back());
232 for (IndexType i(0); i < size; ++i) {
233 const typename ITIVectorType::IndexType ith_index(i.value());
234 const typename ITIVectorType::IndexType permuted(perm[i].value());
235 (*result)[ith_index] = b[permuted];
236 }
237}
238
239} // namespace glop
240} // namespace operations_research
241
242#endif // OR_TOOLS_LP_DATA_PERMUTATION_H_
IntegerValue size
void PopulateFromInverse(const Permutation &inverse)
void PopulateFromIdentity()
Populates the calling object with the identity permutation.
Permutation & operator=(const Permutation &)=delete
IndexType & operator[](IndexType i)
Definition permutation.h:67
IndexType operator[](IndexType i) const
Definition permutation.h:69
void resize(IndexType size, IndexType value)
Definition permutation.h:59
bool Check() const
Returns true if the calling object contains a permutation, false otherwise.
void PopulateRandomly()
Populates the calling object with a random permutation.
void assign(IndexType size, IndexType value)
Definition permutation.h:63
Permutation(const Permutation &)=delete
This type is neither copyable nor movable.
void assign(size_type n, const value_type &val)
void resize(size_type new_size)
int64_t b
Definition table.cc:45
int64_t value
Permutation< ColIndex > ColumnPermutation
Definition permutation.h:97
Permutation< RowIndex > RowPermutation
Definition permutation.h:96
void ApplyPermutation(const Permutation< IndexType > &perm, const ITIVectorType &b, ITIVectorType *result)
void ApplyColumnPermutationToRowIndexedVector(const Permutation< ColIndex > &col_perm, RowIndexedVector *v)
void ApplyInversePermutation(const Permutation< IndexType > &perm, const ITIVectorType &b, ITIVectorType *result)
In SWIG mode, we don't want anything besides these top-level includes.
#define RETURN_IF_NULL(x)