Google OR-Tools v9.12
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-2025 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 <cstddef>
18
19#include "absl/log/check.h"
20#include "absl/random/random.h"
24
25namespace operations_research {
26namespace glop {
27
28// Permutation<IndexType> is a template class for storing and using
29// row- and column- permutations, when instantiated with RowIndex and ColIndex
30// respectively.
31//
32// By a row permutation we mean a permutation that maps the row 'i' of a matrix
33// (or column vector) to the row 'permutation[i]' and in a similar fashion by a
34// column permutation we mean a permutation that maps the column 'j' of a matrix
35// (or row vector) to the column 'permutation[j]'.
36//
37// A permutation can be represented as a matrix P, but it gets a bit tricky
38// here: P.x permutes the rows of x according to the permutation P but x^T.P
39// permutes the columns of x^T (a row vector) using the INVERSE permutation.
40// That is, to permute the columns of x^T using P, one has to compute
41// x^T.P^{-1} but P^{-1} = P^T so the notation is consistent: If P.x permutes x,
42// then (P.x)^T = x^T.P^T permutes x^T with the same permutation.
43//
44// So to be clear, if P and Q are permutation matrices, the matrix P.A.Q^{-1}
45// is the image of A through the row permutation P and column permutation Q.
46template <typename IndexType>
48 public:
49 Permutation() : perm_() {}
50
51 explicit Permutation(IndexType size) : perm_(size, IndexType(0)) {}
52
53 // This type is neither copyable nor movable.
54 Permutation(const Permutation&) = delete;
56
57 IndexType size() const { return perm_.size(); }
58 bool empty() const { return perm_.empty(); }
59
60 void clear() { perm_.clear(); }
61
62 void resize(IndexType size, IndexType value) {
63 perm_.resize(size.value(), value);
64 }
65
66 void assign(IndexType size, IndexType value) { perm_.assign(size, value); }
67
68 IndexType& operator[](IndexType i) { return perm_[i]; }
69
70 IndexType operator[](IndexType i) const { return perm_[i]; }
71
72 // Populates the calling object with the inverse permutation of the parameter
73 // inverse.
74 void PopulateFromInverse(const Permutation& inverse);
75
76 // Populates the calling object with the identity permutation.
78
79 // Populates the calling object with a random permutation.
81
82 // Returns true if the calling object contains a permutation, false otherwise.
83 bool Check() const;
84
85 // Returns the signature of a permutation in O(n), where n is the permutation
86 // size.
87 // The signature of a permutation is the product of the signature of
88 // the cycles defining the permutation.
89 // The signature of an odd cycle is 1, while the signature of an even cycle
90 // is -1. (Remembering hint: the signature of a swap (a 2-cycle) is -1.)
91 int ComputeSignature() const;
92
93 // For hot-loops it might be slighlty faster to cache the pointer and avoid
94 // bound checking on each [] access.
95 const IndexType* data() const { return perm_.data(); }
96
98 return perm_.view();
99 }
100
101 private:
103};
104
107
108// Applies the permutation perm to the vector b. Overwrites result to store
109// the result.
110// TODO(user): Try to restrict this method to using the same integer type in
111// the permutation and for the vector indices, i.e.
112// IndexType == ITIVectorType::IndexType. Some client code will need to be
113// refactored.
114template <typename IndexType, typename ITIVectorType>
116 const ITIVectorType& b, ITIVectorType* result);
117
118// Applies the inverse of perm to the vector b. Overwrites result to store
119// the result.
120template <typename IndexType, typename ITIVectorType>
122 const ITIVectorType& b, ITIVectorType* result);
123
124// Specialization of ApplyPermutation(): apply a column permutation to a
125// row-indexed vector v.
126template <typename RowIndexedVector>
128 StrictITISpan<ColIndex, const ColIndex> col_perm, RowIndexedVector* v,
129 RowIndexedVector* tmp) {
130 // Empty size means identity.
131 const int size = col_perm.size().value();
132 if (size == 0) return;
133
134 // Permute into tmp and swap.
135 DCHECK_EQ(size, v->size());
136
137 tmp->resize(RowIndex(size));
138 const auto* from = v->data();
139 auto* to = tmp->data();
140 for (int i = 0; i < size; ++i) {
141 to[col_perm[ColIndex(i)].value()] = from[i];
142 }
143 std::swap(*tmp, *v);
144}
145
146// --------------------------------------------------------
147// Implementation
148// --------------------------------------------------------
149
150template <typename IndexType>
151void Permutation<IndexType>::PopulateFromInverse(const Permutation& inverse) {
152 const IndexType size = inverse.perm_.size();
153 perm_.resize(size);
154 for (IndexType i(0); i < size; ++i) {
155 perm_[inverse[i]] = i;
156 }
157}
158
159template <typename IndexType>
161 const IndexType size = perm_.size();
162 perm_.resize(size, IndexType(0));
163 for (IndexType i(0); i < size; ++i) {
164 perm_[i] = i;
165 }
166}
167
168template <typename IndexType>
170 PopulateFromIdentity();
171 std::shuffle(perm_.begin(), perm_.end(), absl::BitGen());
172}
173
174template <typename IndexType>
176 const size_t size = perm_.size().value();
178 for (IndexType i(0); i < size; ++i) {
179 if (perm_[i] < 0 || perm_[i] >= size) {
180 return false;
181 }
182 visited[perm_[i]] = true;
183 }
184 for (IndexType i(0); i < size; ++i) {
185 if (!visited[i]) {
186 return false;
187 }
188 }
189 return true;
190}
191
192template <typename IndexType>
194 const size_t size = perm_.size().value();
196 DCHECK(Check());
197 int signature = 1;
198 for (IndexType i(0); i < size; ++i) {
199 if (!visited[i]) {
200 int cycle_size = 0;
201 IndexType j = i;
202 do {
203 j = perm_[j];
204 visited[j] = true;
205 ++cycle_size;
206 } while (j != i);
207 if ((cycle_size & 1) == 0) {
208 signature = -signature;
209 }
210 }
211 }
212 return signature;
213}
214
215template <typename IndexType, typename ITIVectorType>
217 const ITIVectorType& b, ITIVectorType* result) {
219 const IndexType size(perm.size());
220 if (size == 0) {
221 // Empty size means identity.
222 *result = b;
223 return;
224 }
225 DCHECK_EQ(size.value(), b.size().value());
226 result->resize(b.size(), /*whatever junk value*/ b.back());
227 for (IndexType i(0); i < size; ++i) {
228 const typename ITIVectorType::IndexType ith_index(i.value());
229 const typename ITIVectorType::IndexType permuted(perm[i].value());
230 (*result)[permuted] = b[ith_index];
231 }
232}
233
234template <typename IndexType, typename ITIVectorType>
236 const ITIVectorType& b, ITIVectorType* result) {
238 const IndexType size(perm.size());
239 if (size == 0) {
240 // Empty size means identity.
241 *result = b;
242 return;
243 }
244 DCHECK_EQ(size.value(), b.size().value());
245 result->resize(b.size(), /*whatever junk value*/ b.back());
246 for (IndexType i(0); i < size; ++i) {
247 const typename ITIVectorType::IndexType ith_index(i.value());
248 const typename ITIVectorType::IndexType permuted(perm[i].value());
249 (*result)[ith_index] = b[permuted];
250 }
251}
252
253} // namespace glop
254} // namespace operations_research
255
256#endif // OR_TOOLS_LP_DATA_PERMUTATION_H_
StrictITISpan< IndexType, const IndexType > const_view() const
Definition permutation.h:97
void PopulateFromInverse(const Permutation &inverse)
const IndexType * data() const
Definition permutation.h:95
void PopulateFromIdentity()
Populates the calling object with the identity permutation.
Permutation & operator=(const Permutation &)=delete
IndexType & operator[](IndexType i)
Definition permutation.h:68
IndexType operator[](IndexType i) const
Definition permutation.h:70
void resize(IndexType size, IndexType value)
Definition permutation.h:62
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:66
Permutation(const Permutation &)=delete
This type is neither copyable nor movable.
Permutation< ColIndex > ColumnPermutation
Permutation< RowIndex > RowPermutation
void ApplyPermutation(const Permutation< IndexType > &perm, const ITIVectorType &b, ITIVectorType *result)
void ApplyColumnPermutationToRowIndexedVector(StrictITISpan< ColIndex, const ColIndex > col_perm, RowIndexedVector *v, RowIndexedVector *tmp)
void ApplyInversePermutation(const Permutation< IndexType > &perm, const ITIVectorType &b, ITIVectorType *result)
In SWIG mode, we don't want anything besides these top-level includes.
trees with all degrees equal to
#define RETURN_IF_NULL(x)