Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
dynamic_permutation.cc
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
15
16#include <algorithm>
17#include <memory>
18#include <string>
19#include <vector>
20
21#include "absl/types/span.h"
23
24namespace operations_research {
25
27 : image_(n, -1), ancestor_(n, -1), tmp_mask_(n, false) {
28 for (int i = 0; i < Size(); ++i) image_[i] = ancestor_[i] = i;
29}
30
31void DynamicPermutation::AddMappings(absl::Span<const int> src,
32 absl::Span<const int> dst) {
33 DCHECK_EQ(src.size(), dst.size());
34 mapping_src_size_stack_.push_back(mapping_src_stack_.size());
35 mapping_src_stack_.reserve(mapping_src_stack_.size() + src.size());
36 for (int i = 0; i < src.size(); ++i) {
37 const int s = src[i];
38 const int d = dst[i];
39 DCHECK_EQ(s, ImageOf(s)); // No prior image of s.
40 DCHECK_EQ(d, ancestor_[d]); // No prior ancestor of d.
41
42 ancestor_[d] = RootOf(s);
43 image_[s] = d;
44
45 if (image_[d] == d) loose_ends_.insert(d);
46 loose_ends_.erase(s); // Also takes care of the corner case s == d.
47
48 // Remember the sources for the undo stack.
49 mapping_src_stack_.push_back(s);
50 }
51}
52
54 std::vector<int>* undone_mapping_src) {
55 DCHECK(undone_mapping_src != nullptr);
56 undone_mapping_src->clear();
57 if (mapping_src_size_stack_.empty()) return; // Nothing to undo.
58 const int num_mappings_before = mapping_src_size_stack_.back();
59 mapping_src_size_stack_.pop_back();
60 const int num_mappings_now = mapping_src_stack_.size();
61 DCHECK_GE(num_mappings_now, num_mappings_before);
62 // Dump the undone mappings.
63 undone_mapping_src->reserve(num_mappings_now - num_mappings_before);
64 undone_mapping_src->insert(undone_mapping_src->begin(),
65 mapping_src_stack_.begin() + num_mappings_before,
66 mapping_src_stack_.end());
67 // Note(user): the mappings should be undone in reverse order, because the
68 // code that keeps "tails" up to date depends on it.
69 for (int i = num_mappings_now - 1; i >= num_mappings_before; --i) {
70 const int s = mapping_src_stack_[i];
71 const int d = ImageOf(s);
72
73 if (ancestor_[s] != s) loose_ends_.insert(s);
74 loose_ends_.erase(d);
75
76 ancestor_[d] = d;
77 image_[s] = s;
78 }
79 mapping_src_stack_.resize(num_mappings_before); // Shrink.
80}
81
83 for (const int i : mapping_src_stack_) {
84 const int dst = image_[i];
85 ancestor_[dst] = dst;
86 image_[i] = i;
87 }
88 mapping_src_stack_.clear();
89 mapping_src_size_stack_.clear();
90 loose_ends_.clear();
91}
92
93std::unique_ptr<SparsePermutation> DynamicPermutation::CreateSparsePermutation()
94 const {
95 std::unique_ptr<SparsePermutation> sparse_perm(new SparsePermutation(Size()));
96 int num_identity_singletons = 0;
97 for (const int x : mapping_src_stack_) {
98 if (tmp_mask_[x]) continue;
99 // Deal with the special case of a trivial x->x cycle, which we do *not*
100 // want to add to the sparse permutation.
101 if (ImageOf(x) == x) {
102 DCHECK_EQ(x, RootOf(x));
103 ++num_identity_singletons;
104 continue;
105 }
106 const int root = RootOf(x);
107 int next = root;
108 while (true) {
109 sparse_perm->AddToCurrentCycle(next);
110 tmp_mask_[next] = true;
111 DCHECK_NE(next, ImageOf(next));
112 next = ImageOf(next);
113 if (next == root) break;
114 }
115 sparse_perm->CloseCurrentCycle();
116 }
117 for (const int x : mapping_src_stack_) tmp_mask_[x] = false;
118 DCHECK_EQ(mapping_src_stack_.size(),
119 sparse_perm->Support().size() + num_identity_singletons);
120 return sparse_perm;
121}
122
124 // That's wasteful, but we don't care, DebugString() may be slow.
125 return CreateSparsePermutation()->DebugString();
126}
127
128} // namespace operations_research
int RootOf(int i) const
Forced-inline for the speed.
int ImageOf(int i) const
Forced-inline for the speed.
void UndoLastMappings(std::vector< int > *undone_mapping_src)
DynamicPermutation(int n)
Upon construction, every element i in [0..n-1] maps to itself.
void AddMappings(absl::Span< const int > src, absl::Span< const int > dst)
std::unique_ptr< SparsePermutation > CreateSparsePermutation() const
Block * next
In SWIG mode, we don't want anything besides these top-level includes.
const Variable x
Definition qp_tests.cc:127