OR-Tools  9.6
rev.h
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 
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"
21 #include "ortools/base/logging.h"
23 
24 namespace 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:
31  virtual ~ReversibleInterface() {}
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.
45 template <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.
86 template <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 
132 template <class T>
133 void RevRepository<T>::SetLevel(int level) {
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.
153 template <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;
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 
202 template <class Map>
203 void 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 
224 template <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 
234 template <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).
250 template <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 
274 template <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 
296 template <class Key, class Value>
297 const std::vector<Value>& RevGrowingMultiMap<Key, Value>::Values(
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 
304 template <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_
void resize(size_type new_size)
size_type size() const
void SetLevel(int level) final
Definition: rev.h:275
void Add(Key key, Value value)
Definition: rev.h:305
const std::vector< Value > & Values(Key key) const
Definition: rev.h:297
int Level() const
Definition: rev.h:168
void Set(key_type key, mapped_type value)
Definition: rev.h:235
Map::value_type value_type
Definition: rev.h:158
void SetLevel(int level) final
Definition: rev.h:203
const_iterator begin() const
Definition: rev.h:180
const_iterator find(const key_type &k) const
Definition: rev.h:179
bool empty() const
Definition: rev.h:178
Map::key_type key_type
Definition: rev.h:156
bool contains(key_type key) const
Definition: rev.h:170
const mapped_type & at(key_type key) const
Definition: rev.h:171
const_iterator end() const
Definition: rev.h:181
Map::mapped_type mapped_type
Definition: rev.h:157
void EraseOrDie(key_type key)
Definition: rev.h:225
Map::const_iterator const_iterator
Definition: rev.h:159
int size() const
Definition: rev.h:177
void SetLevel(int level) final
Definition: rev.h:133
void SaveState(T *object)
Definition: rev.h:60
void SaveStateWithStamp(T *object, int64_t *stamp)
Definition: rev.h:70
void SetLevel(int level) final
Definition: rev.h:111
void Grow(int new_size)
Definition: rev.h:102
T & MutableRef(IndexType index)
Definition: rev.h:94
const T & operator[](IndexType index) const
Definition: rev.h:89
virtual void SetLevel(int level)=0
int64_t value
int index
std::function< int64_t(const Model &)> Value(IntegerVariable v)
Definition: integer.h:1795
Collection of objects used to extend the Constraint Solver library.
const int64_t stamp
Definition: search.cc:3165