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