Google OR-Tools v9.12
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
sparse_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_ALGORITHMS_SPARSE_PERMUTATION_H_
15#define OR_TOOLS_ALGORITHMS_SPARSE_PERMUTATION_H_
16
17#include <string>
18#include <vector>
19
20#include "absl/types/span.h"
22
23namespace operations_research {
24
25// A compact representation for permutations of {0..N-1} that displaces few
26// elements: it needs only O(K) memory for a permutation that displaces
27// K elements.
29 public:
30 explicit SparsePermutation(int size) : size_(size) {} // Identity.
31
32 // TODO(user): complete the reader API.
33 int Size() const { return size_; }
34 int NumCycles() const { return cycle_ends_.size(); }
35
36 // Returns the "support" of this permutation; that is, the set of elements
37 // displaced by it.
38 const std::vector<int>& Support() const { return cycles_; }
39
40 // The permutation has NumCycles() cycles numbered 0 .. NumCycles()-1.
41 // To iterate over cycle #i of the permutation, do this:
42 // for (const int e : permutation.Cycle(i)) { ...
43 struct Iterator;
44 Iterator Cycle(int i) const;
45
46 // This is useful for iterating over the pair {element, image}
47 // of a permutation:
48 //
49 // for (int c = 0; c < perm.NumCycles(); ++c) {
50 // int element = LastElementInCycle(c);
51 // for (int image : perm.Cycle(c)) {
52 // // The pair is (element, image).
53 // ...
54 // element = image;
55 // }
56 // }
57 //
58 // TODO(user): Provide a full iterator for this? Note that we have more
59 // information with the loop above. Not sure it is needed though.
60 int LastElementInCycle(int i) const;
61
62 // Returns the image of the given element or `element` itself if it is stable
63 // under the permutation.
64 int Image(int element) const;
65 int InverseImage(int element) const;
66
67 // To add a cycle to the permutation, repeatedly call AddToCurrentCycle()
68 // with the cycle's orbit, then call CloseCurrentCycle();
69 // This shouldn't be called on trivial cycles (of length 1).
70 void AddToCurrentCycle(int x);
71 void CloseCurrentCycle();
72
73 // Removes the cycles with given indices from the permutation. This
74 // works in O(K) for a permutation displacing K elements.
75 void RemoveCycles(absl::Span<const int> cycle_indices);
76
77 // Output all non-identity cycles of the permutation, sorted
78 // lexicographically (each cycle is described starting by its smallest
79 // element; and all cycles are sorted lexicographically against each other).
80 // This isn't efficient; use for debugging only.
81 // Example: "(1 4 3) (5 9) (6 8 7)".
82 std::string DebugString() const;
83
84 template <typename Collection>
85 void ApplyToDenseCollection(Collection& span) const;
86
87 private:
88 const int size_;
89 std::vector<int> cycles_;
90 std::vector<int> cycle_ends_;
91};
92
94 DCHECK_GE(x, 0);
95 DCHECK_LT(x, size_);
96 cycles_.push_back(x);
97}
98
100 if (cycle_ends_.empty()) {
101 DCHECK_GE(cycles_.size(), 2);
102 } else {
103 DCHECK_GE(cycles_.size(), cycle_ends_.back() + 2);
104 }
105 cycle_ends_.push_back(cycles_.size());
106}
107
109 // These typedefs allow this iterator to be used within testing::ElementsAre.
110 typedef int value_type;
111 typedef std::vector<int>::const_iterator const_iterator;
112
113 Iterator() = default;
114 Iterator(const std::vector<int>::const_iterator& b,
115 const std::vector<int>::const_iterator& e)
116 : begin_(b), end_(e) {}
117
118 std::vector<int>::const_iterator begin() const { return begin_; }
119 std::vector<int>::const_iterator end() const { return end_; }
120 const std::vector<int>::const_iterator begin_;
121 const std::vector<int>::const_iterator end_;
122
123 int size() const { return end_ - begin_; }
124};
125
127 DCHECK_GE(i, 0);
128 DCHECK_LT(i, NumCycles());
129 return Iterator(cycles_.begin() + (i == 0 ? 0 : cycle_ends_[i - 1]),
130 cycles_.begin() + cycle_ends_[i]);
131}
132
134 DCHECK_GE(i, 0);
135 DCHECK_LT(i, cycle_ends_.size());
136 DCHECK_GT(cycle_ends_[i], i == 0 ? 0 : cycle_ends_[i - 1]);
137 return cycles_[cycle_ends_[i] - 1];
138}
139
140template <typename Collection>
141void SparsePermutation::ApplyToDenseCollection(Collection& span) const {
142 using T = typename Collection::value_type;
143 for (int c = 0; c < NumCycles(); ++c) {
144 const int last_element_idx = LastElementInCycle(c);
145 int element = last_element_idx;
146 T last_element = span[element];
147 for (int image : Cycle(c)) {
148 if (image == last_element_idx) {
149 span[element] = last_element;
150 } else {
151 span[element] = span[image];
152 }
153 element = image;
154 }
155 }
156}
157
158} // namespace operations_research
159
160#endif // OR_TOOLS_ALGORITHMS_SPARSE_PERMUTATION_H_
void ApplyToDenseCollection(Collection &span) const
void RemoveCycles(absl::Span< const int > cycle_indices)
const std::vector< int > & Support() const
In SWIG mode, we don't want anything besides these top-level includes.
std::vector< int >::const_iterator end() const
std::vector< int >::const_iterator const_iterator
const std::vector< int >::const_iterator end_
int value_type
These typedefs allow this iterator to be used within testing::ElementsAre.
const std::vector< int >::const_iterator begin_
std::vector< int >::const_iterator begin() const
Iterator(const std::vector< int >::const_iterator &b, const std::vector< int >::const_iterator &e)