Google OR-Tools v9.9
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
rev.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// Reversible (i.e Backtrackable) classes, used to simplify coding propagators.
15#ifndef OR_TOOLS_UTIL_REV_H_
16#define OR_TOOLS_UTIL_REV_H_
17
18#include <vector>
19
20#include "absl/container/flat_hash_map.h"
23
24namespace operations_research {
25
26// Interface for reversible objects used to maintain them in sync with a tree
27// search organized by decision levels.
29 public:
32
33 // Initially a reversible class starts at level zero. Increasing the level
34 // saves the state of the current old level. Decreasing the level restores the
35 // state to what it was at this level and all higher levels are forgotten.
36 // Everything done at level zero cannot be backtracked over.
37 //
38 // The level is assumed to be non-negative.
39 virtual void SetLevel(int level) = 0;
40};
41
42// A repository that maintains a set of reversible objects of type T.
43// This is meant to be used for small types that are efficient to copy, like
44// all the basic types, std::pair and things like this.
45template <class T>
47 public:
48 RevRepository() : stamp_(0) {}
49
50 // This works in O(level_diff) on level increase.
51 // For level decrease, it is in O(level_diff + num_restored_states).
52 void SetLevel(int level) final;
53 int Level() const { return end_of_level_.size(); }
54
55 // Saves the given object value for the current level. If this is called
56 // multiple time by level, only the value of the first call matter. This is
57 // NOT optimized for many calls by level and should mainly be used just once
58 // for a given level. If a client cannot do that efficiently, it can use the
59 // SaveStateWithStamp() function below.
60 void SaveState(T* object) {
61 if (end_of_level_.empty()) return; // Not useful for level zero.
62 stack_.push_back({object, *object});
63 }
64
65 // Calls SaveState() if the given stamp is not the same as the current one.
66 // This also sets the given stamp to the current one. The current stamp is
67 // maintained by this class and is updated on each level changes. The whole
68 // process make sure that only one SaveValue() par level will ever be called,
69 // so it is efficient to call this before each update to the object T.
70 void SaveStateWithStamp(T* object, int64_t* stamp) {
71 if (*stamp == stamp_) return;
72 *stamp = stamp_;
73 SaveState(object);
74 }
75
76 private:
77 int64_t stamp_;
78 std::vector<int> end_of_level_; // In stack_.
79
80 // TODO(user): If we ever see this in any cpu profile, consider using two
81 // vectors for a better memory packing in case sizeof(T) is not sizeof(T*).
82 std::vector<std::pair<T*, T>> stack_;
83};
84
85// A basic reversible vector implementation.
86template <class IndexType, class T>
88 public:
89 const T& operator[](IndexType index) const { return vector_[index]; }
90
91 // TODO(user): Maybe we could have also used the [] operator, but it is harder
92 // to be 100% sure that the mutable version is only called when we modify
93 // the vector. And I had performance bug because of that.
94 T& MutableRef(IndexType index) {
95 // Save on the stack first.
96 if (!end_of_level_.empty()) stack_.push_back({index, vector_[index]});
97 return vector_[index];
98 }
99
100 int size() const { return vector_.size(); }
101
102 void Grow(int new_size) {
103 CHECK_GE(new_size, vector_.size());
104 vector_.resize(new_size);
105 }
106
107 void GrowByOne() { vector_.resize(vector_.size() + 1); }
108
109 int Level() const { return end_of_level_.size(); }
110
111 void SetLevel(int level) final {
112 DCHECK_GE(level, 0);
113 if (level == Level()) return;
114 if (level < Level()) {
115 const int index = end_of_level_[level];
116 end_of_level_.resize(level); // Shrinks.
117 for (int i = stack_.size() - 1; i >= index; --i) {
118 vector_[stack_[i].first] = stack_[i].second;
119 }
120 stack_.resize(index);
121 } else {
122 end_of_level_.resize(level, stack_.size()); // Grows.
123 }
124 }
125
126 private:
127 std::vector<int> end_of_level_; // In stack_.
128 std::vector<std::pair<IndexType, T>> stack_;
130};
131
132template <class T>
134 DCHECK_GE(level, 0);
135 if (level == Level()) return;
136 ++stamp_;
137 if (level < Level()) {
138 const int index = end_of_level_[level];
139 end_of_level_.resize(level); // Shrinks.
140 for (int i = stack_.size() - 1; i >= index; --i) {
141 *stack_[i].first = stack_[i].second;
142 }
143 stack_.resize(index);
144 } else {
145 end_of_level_.resize(level, stack_.size()); // Grows.
146 }
147}
148
149// Like a normal map but support backtrackable operations.
150//
151// This works on any class "Map" that supports: begin(), end(), find(), erase(),
152// insert(), key_type, value_type, mapped_type and const_iterator.
153template <class Map>
155 public:
156 typedef typename Map::key_type key_type;
157 typedef typename Map::mapped_type mapped_type;
158 typedef typename Map::value_type value_type;
159 typedef typename Map::const_iterator const_iterator;
160
161 // Backtracking support: changes the current "level" (always non-negative).
162 //
163 // Initially the class starts at level zero. Increasing the level works in
164 // O(level diff) and saves the state of the current old level. Decreasing the
165 // level restores the state to what it was at this level and all higher levels
166 // are forgotten. Everything done at level zero cannot be backtracked over.
167 void SetLevel(int level) final;
168 int Level() const { return first_op_index_of_next_level_.size(); }
169
170 bool contains(key_type key) const { return map_.contains(key); }
171 const mapped_type& at(key_type key) const { return map_.at(key); }
172
173 void EraseOrDie(key_type key);
174 void Set(key_type key, mapped_type value); // Adds or overwrites.
175
176 // Wrapper to the underlying const map functions.
177 int size() const { return map_.size(); }
178 bool empty() const { return map_.empty(); }
179 const_iterator find(const key_type& k) const { return map_.find(k); }
180 const_iterator begin() const { return map_.begin(); }
181 const_iterator end() const { return map_.end(); }
182
183 private:
184 Map map_;
185
186 // The operation that needs to be performed to reverse one modification:
187 // - If is_deletion is true, then we need to delete the entry with given key.
188 // - Otherwise we need to add back (or overwrite) the saved entry.
189 struct UndoOperation {
190 bool is_deletion;
191 key_type key;
192 mapped_type value;
193 };
194
195 // TODO(user): We could merge the operations with the same key from the same
196 // level. Investigate and implement if this is worth the effort for our use
197 // case.
198 std::vector<UndoOperation> operations_;
199 std::vector<int> first_op_index_of_next_level_;
200};
201
202template <class Map>
203void RevMap<Map>::SetLevel(int level) {
204 DCHECK_GE(level, 0);
205 if (level < Level()) {
206 const int backtrack_level = first_op_index_of_next_level_[level];
207 first_op_index_of_next_level_.resize(level); // Shrinks.
208 while (operations_.size() > backtrack_level) {
209 const UndoOperation& to_undo = operations_.back();
210 if (to_undo.is_deletion) {
211 map_.erase(to_undo.key);
212 } else {
213 map_.insert({to_undo.key, to_undo.value}).first->second = to_undo.value;
214 }
215 operations_.pop_back();
216 }
217 return;
218 }
219
220 // This is ok even if level == Level().
221 first_op_index_of_next_level_.resize(level, operations_.size()); // Grows.
222}
223
224template <class Map>
226 const auto iter = map_.find(key);
227 if (iter == map_.end()) LOG(FATAL) << "key not present: '" << key << "'.";
228 if (Level() > 0) {
229 operations_.push_back({false, key, iter->second});
230 }
231 map_.erase(iter);
232}
233
234template <class Map>
236 auto insertion_result = map_.insert({key, value});
237 if (Level() > 0) {
238 if (insertion_result.second) {
239 // It is an insertion. Undo = delete.
240 operations_.push_back({true, key});
241 } else {
242 // It is a modification. Undo = change back to old value.
243 operations_.push_back({false, key, insertion_result.first->second});
244 }
245 }
246 insertion_result.first->second = value;
247}
248
249// A basic backtrackable multi map that can only grow (except on backtrack).
250template <class Key, class Value>
252 public:
253 void SetLevel(int level) final;
254
255 // Adds a new value at the given key.
256 void Add(Key key, Value value);
257
258 // Returns the list of values for a given key (can be empty).
259 const std::vector<Value>& Values(Key key) const;
260
261 private:
262 std::vector<Value> empty_values_;
263
264 // TODO(user): use inlined vectors. Another datastructure that may be more
265 // efficient is to use a linked list inside added_keys_ for the values sharing
266 // the same key.
267 absl::flat_hash_map<Key, std::vector<Value>> map_;
268
269 // Backtracking data.
270 std::vector<Key> added_keys_;
271 std::vector<int> first_added_key_of_next_level_;
272};
273
274template <class Key, class Value>
276 DCHECK_GE(level, 0);
277 if (level < first_added_key_of_next_level_.size()) {
278 const int backtrack_level = first_added_key_of_next_level_[level];
279 first_added_key_of_next_level_.resize(level); // Shrinks.
280 while (added_keys_.size() > backtrack_level) {
281 auto it = map_.find(added_keys_.back());
282 if (it->second.size() > 1) {
283 it->second.pop_back();
284 } else {
285 map_.erase(it);
286 }
287 added_keys_.pop_back();
288 }
289 return;
290 }
291
292 // This is ok even if level == Level().
293 first_added_key_of_next_level_.resize(level, added_keys_.size()); // Grows.
294}
295
296template <class Key, class Value>
298 Key key) const {
299 const auto it = map_.find(key);
300 if (it != map_.end()) return it->second;
301 return empty_values_;
302}
303
304template <class Key, class Value>
306 if (!first_added_key_of_next_level_.empty()) {
307 added_keys_.push_back(key);
308 }
309 map_[key].push_back(value);
310}
311
312} // namespace operations_research
313
314#endif // OR_TOOLS_UTIL_REV_H_
STL vector ---------------------------------------------------------------—.
void resize(size_type new_size)
size_type size() const
A basic backtrackable multi map that can only grow (except on backtrack).
Definition rev.h:251
void SetLevel(int level) final
Definition rev.h:275
void Add(Key key, Value value)
Adds a new value at the given key.
Definition rev.h:305
const std::vector< Value > & Values(Key key) const
Returns the list of values for a given key (can be empty).
Definition rev.h:297
void EraseOrDie(key_type key)
Definition rev.h:225
bool empty() const
Definition rev.h:178
Map::const_iterator const_iterator
Definition rev.h:159
bool contains(key_type key) const
Definition rev.h:170
Map::value_type value_type
Definition rev.h:158
const_iterator end() const
Definition rev.h:181
int size() const
Wrapper to the underlying const map functions.
Definition rev.h:177
const mapped_type & at(key_type key) const
Definition rev.h:171
const_iterator begin() const
Definition rev.h:180
const_iterator find(const key_type &k) const
Definition rev.h:179
Map::key_type key_type
Definition rev.h:156
void SetLevel(int level) final
Definition rev.h:203
Map::mapped_type mapped_type
Definition rev.h:157
void Set(key_type key, mapped_type value)
Definition rev.h:235
void SetLevel(int level) final
Definition rev.h:133
void SaveStateWithStamp(T *object, int64_t *stamp)
Definition rev.h:70
void SaveState(T *object)
Definition rev.h:60
A basic reversible vector implementation.
Definition rev.h:87
void Grow(int new_size)
Definition rev.h:102
const T & operator[](IndexType index) const
Definition rev.h:89
T & MutableRef(IndexType index)
Definition rev.h:94
void SetLevel(int level) final
Definition rev.h:111
virtual void SetLevel(int level)=0
int64_t value
int index
In SWIG mode, we don't want anything besides these top-level includes.
int64_t stamp
Definition search.cc:3270