OR-Tools  9.0
theta_tree.cc
Go to the documentation of this file.
1 // Copyright 2010-2021 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 #include "ortools/sat/theta_tree.h"
15 
16 #include <algorithm>
17 #include <cstdint>
18 #include <memory>
19 
20 #include "ortools/base/int_type.h"
21 
22 namespace operations_research {
23 namespace sat {
24 
25 template <typename IntegerType>
27 
28 template <typename IntegerType>
30 ThetaLambdaTree<IntegerType>::ComposeTreeNodes(TreeNode left, TreeNode right) {
31  return {std::max(right.envelope, left.envelope + right.sum_of_energy_min),
32  std::max(right.envelope_opt,
33  right.sum_of_energy_min +
34  std::max(left.envelope_opt,
35  left.envelope + right.max_of_energy_delta)),
36  left.sum_of_energy_min + right.sum_of_energy_min,
37  std::max(right.max_of_energy_delta, left.max_of_energy_delta)};
38 }
39 
40 template <typename IntegerType>
42 #ifndef NDEBUG
43  leaf_nodes_have_delayed_operations_ = false;
44 #endif
45  // Because the algorithm needs to access a node sibling (i.e. node_index ^ 1),
46  // our tree will always have an even number of leaves, just large enough to
47  // fit our number of events. And at least 2 for the empty tree case.
48  num_events_ = num_events;
49  num_leaves_ = std::max(2, num_events + (num_events & 1));
50 
51  const int num_nodes = 2 * num_leaves_;
52  tree_.assign(num_nodes, TreeNode{IntegerTypeMinimumValue<IntegerType>(),
53  IntegerTypeMinimumValue<IntegerType>(),
54  IntegerType{0}, IntegerType{0}});
55 
56  // If num_leaves is not a power or two, the last depth of the tree will not be
57  // full, and the array will look like:
58  // [( num_leafs parents)(leaves at depth d - 1)(leaves at depth d)
59  // The first leaves at depth p will have power_of_two_ as index.
60  for (power_of_two_ = 2; power_of_two_ < num_leaves_; power_of_two_ <<= 1) {
61  }
62 }
63 
64 template <typename IntegerType>
66  DCHECK_LE(0, event);
67  DCHECK_LT(event, num_events_);
68  // Keeping the ordering of events is important, so the first set of events
69  // must be mapped to the set of leaves at depth d, and the second set of
70  // events must be mapped to the set of leaves at depth d-1.
71  const int r = power_of_two_ + event;
72  return r < 2 * num_leaves_ ? r : r - num_leaves_;
73 }
74 
75 template <typename IntegerType>
76 int ThetaLambdaTree<IntegerType>::GetEventFromLeaf(int leaf) const {
77  DCHECK_GE(leaf, num_leaves_);
78  DCHECK_LT(leaf, 2 * num_leaves_);
79  const int r = leaf - power_of_two_;
80  return r >= 0 ? r : r + num_leaves_;
81 }
82 
83 template <typename IntegerType>
85 #ifndef NDEBUG
86  leaf_nodes_have_delayed_operations_ = false;
87 #endif
88  // Only recompute internal nodes.
89  const int last_internal_node = tree_.size() / 2 - 1;
90  for (int node = last_internal_node; node >= 1; --node) {
91  const int right = 2 * node + 1;
92  const int left = 2 * node;
93  tree_[node] = ComposeTreeNodes(tree_[left], tree_[right]);
94  }
95 }
96 
97 template <typename IntegerType>
99  int event, IntegerType initial_envelope, IntegerType energy_min,
100  IntegerType energy_max) {
101 #ifndef NDEBUG
102  leaf_nodes_have_delayed_operations_ = true;
103 #endif
104  DCHECK_LE(0, energy_min);
105  DCHECK_LE(energy_min, energy_max);
106  const int node = GetLeafFromEvent(event);
107  tree_[node] = {initial_envelope + energy_min, initial_envelope + energy_max,
108  energy_min, energy_max - energy_min};
109 }
110 
111 template <typename IntegerType>
113  int event, IntegerType initial_envelope, IntegerType energy_min,
114  IntegerType energy_max) {
115  DCHECK(!leaf_nodes_have_delayed_operations_);
116  DCHECK_LE(0, energy_min);
117  DCHECK_LE(energy_min, energy_max);
118  const int node = GetLeafFromEvent(event);
119  tree_[node] = {initial_envelope + energy_min, initial_envelope + energy_max,
120  energy_min, energy_max - energy_min};
121  RefreshNode(node);
122 }
123 
124 template <typename IntegerType>
126  int event, IntegerType initial_envelope_opt, IntegerType energy_max) {
127  DCHECK(!leaf_nodes_have_delayed_operations_);
128  DCHECK_LE(0, energy_max);
129  const int node = GetLeafFromEvent(event);
130  tree_[node] = {IntegerTypeMinimumValue<IntegerType>(),
131  initial_envelope_opt + energy_max, IntegerType{0}, energy_max};
132  RefreshNode(node);
133 }
134 
135 template <typename IntegerType>
137  int event, IntegerType initial_envelope_opt, IntegerType energy_max) {
138 #ifndef NDEBUG
139  leaf_nodes_have_delayed_operations_ = true;
140 #endif
141  DCHECK_LE(0, energy_max);
142  const int node = GetLeafFromEvent(event);
143  tree_[node] = {IntegerTypeMinimumValue<IntegerType>(),
144  initial_envelope_opt + energy_max, IntegerType{0}, energy_max};
145 }
146 
147 template <typename IntegerType>
149  DCHECK(!leaf_nodes_have_delayed_operations_);
150  const int node = GetLeafFromEvent(event);
151  tree_[node] = {IntegerTypeMinimumValue<IntegerType>(),
152  IntegerTypeMinimumValue<IntegerType>(), IntegerType{0},
153  IntegerType{0}};
154  RefreshNode(node);
155 }
156 
157 template <typename IntegerType>
159 #ifndef NDEBUG
160  leaf_nodes_have_delayed_operations_ = true;
161 #endif
162  const int node = GetLeafFromEvent(event);
163  tree_[node] = {IntegerTypeMinimumValue<IntegerType>(),
164  IntegerTypeMinimumValue<IntegerType>(), IntegerType{0},
165  IntegerType{0}};
166 }
167 
168 template <typename IntegerType>
170  DCHECK(!leaf_nodes_have_delayed_operations_);
171  return tree_[1].envelope;
172 }
173 template <typename IntegerType>
175  DCHECK(!leaf_nodes_have_delayed_operations_);
176  return tree_[1].envelope_opt;
177 }
178 
179 template <typename IntegerType>
181  IntegerType target_envelope) const {
182  DCHECK(!leaf_nodes_have_delayed_operations_);
183  DCHECK_LT(target_envelope, tree_[1].envelope);
184  IntegerType unused;
185  return GetEventFromLeaf(
186  GetMaxLeafWithEnvelopeGreaterThan(1, target_envelope, &unused));
187 }
188 
189 template <typename IntegerType>
191  IntegerType target_envelope, int* critical_event, int* optional_event,
192  IntegerType* available_energy) const {
193  DCHECK(!leaf_nodes_have_delayed_operations_);
194  int critical_leaf;
195  int optional_leaf;
196  GetLeavesWithOptionalEnvelopeGreaterThan(target_envelope, &critical_leaf,
197  &optional_leaf, available_energy);
198  *critical_event = GetEventFromLeaf(critical_leaf);
199  *optional_event = GetEventFromLeaf(optional_leaf);
200 }
201 
202 template <typename IntegerType>
203 IntegerType ThetaLambdaTree<IntegerType>::GetEnvelopeOf(int event) const {
204  DCHECK(!leaf_nodes_have_delayed_operations_);
205  const int leaf = GetLeafFromEvent(event);
206  IntegerType envelope = tree_[leaf].envelope;
207  for (int node = leaf; node > 1; node >>= 1) {
208  const int right = node | 1;
209  if (node != right) envelope += tree_[right].sum_of_energy_min;
210  }
211  return envelope;
212 }
213 
214 template <typename IntegerType>
216  do {
217  const int right = node | 1;
218  const int left = right ^ 1;
219  node >>= 1;
220  tree_[node] = ComposeTreeNodes(tree_[left], tree_[right]);
221  } while (node > 1);
222 }
223 
224 template <typename IntegerType>
225 int ThetaLambdaTree<IntegerType>::GetMaxLeafWithEnvelopeGreaterThan(
226  int node, IntegerType target_envelope, IntegerType* extra) const {
227  DCHECK(!leaf_nodes_have_delayed_operations_);
228  DCHECK_LT(target_envelope, tree_[node].envelope);
229  while (node < num_leaves_) {
230  const int left = node << 1;
231  const int right = left | 1;
232  DCHECK_LT(right, tree_.size());
233 
234  if (target_envelope < tree_[right].envelope) {
235  node = right;
236  } else {
237  target_envelope -= tree_[right].sum_of_energy_min;
238  node = left;
239  }
240  }
241  *extra = tree_[node].envelope - target_envelope;
242  return node;
243 }
244 
245 template <typename IntegerType>
246 int ThetaLambdaTree<IntegerType>::GetLeafWithMaxEnergyDelta(int node) const {
247  DCHECK(!leaf_nodes_have_delayed_operations_);
248  const IntegerType delta_node = tree_[node].max_of_energy_delta;
249  while (node < num_leaves_) {
250  const int left = node << 1;
251  const int right = left | 1;
252  DCHECK_LT(right, tree_.size());
253  if (tree_[right].max_of_energy_delta == delta_node) {
254  node = right;
255  } else {
256  DCHECK_EQ(tree_[left].max_of_energy_delta, delta_node);
257  node = left;
258  }
259  }
260  return node;
261 }
262 
263 template <typename IntegerType>
264 void ThetaLambdaTree<IntegerType>::GetLeavesWithOptionalEnvelopeGreaterThan(
265  IntegerType target_envelope, int* critical_leaf, int* optional_leaf,
266  IntegerType* available_energy) const {
267  DCHECK(!leaf_nodes_have_delayed_operations_);
268  DCHECK_LT(target_envelope, tree_[1].envelope_opt);
269  int node = 1;
270  while (node < num_leaves_) {
271  const int left = node << 1;
272  const int right = left | 1;
273  DCHECK_LT(right, tree_.size());
274 
275  if (target_envelope < tree_[right].envelope_opt) {
276  node = right;
277  } else {
278  const IntegerType opt_energy_right =
279  tree_[right].sum_of_energy_min + tree_[right].max_of_energy_delta;
280  if (target_envelope < tree_[left].envelope + opt_energy_right) {
281  *optional_leaf = GetLeafWithMaxEnergyDelta(right);
282  IntegerType extra;
283  *critical_leaf = GetMaxLeafWithEnvelopeGreaterThan(
284  left, target_envelope - opt_energy_right, &extra);
285  *available_energy = tree_[*optional_leaf].sum_of_energy_min +
286  tree_[*optional_leaf].max_of_energy_delta - extra;
287  return;
288  } else { // < tree_[left].envelope_opt + tree_[right].sum_of_energy_min
289  target_envelope -= tree_[right].sum_of_energy_min;
290  node = left;
291  }
292  }
293  }
294  *critical_leaf = node;
295  *optional_leaf = node;
296  *available_energy = target_envelope - (tree_[node].envelope_opt -
297  tree_[node].sum_of_energy_min -
298  tree_[node].max_of_energy_delta);
299 }
300 
301 template class ThetaLambdaTree<IntegerValue>;
302 template class ThetaLambdaTree<int64_t>;
303 
304 } // namespace sat
305 } // namespace operations_research
int64_t max
Definition: alldiff_cst.cc:140
#define DCHECK_LE(val1, val2)
Definition: base/logging.h:895
#define DCHECK_GE(val1, val2)
Definition: base/logging.h:897
#define DCHECK_LT(val1, val2)
Definition: base/logging.h:896
#define DCHECK(condition)
Definition: base/logging.h:892
#define DCHECK_EQ(val1, val2)
Definition: base/logging.h:893
IntegerType GetEnvelopeOf(int event) const
Definition: theta_tree.cc:203
void GetEventsWithOptionalEnvelopeGreaterThan(IntegerType target_envelope, int *critical_event, int *optional_event, IntegerType *available_energy) const
Definition: theta_tree.cc:190
int GetMaxEventWithEnvelopeGreaterThan(IntegerType target_envelope) const
Definition: theta_tree.cc:180
void AddOrUpdateOptionalEvent(int event, IntegerType initial_envelope_opt, IntegerType energy_max)
Definition: theta_tree.cc:125
void DelayedAddOrUpdateEvent(int event, IntegerType initial_envelope, IntegerType energy_min, IntegerType energy_max)
Definition: theta_tree.cc:98
void DelayedAddOrUpdateOptionalEvent(int event, IntegerType initial_envelope_opt, IntegerType energy_max)
Definition: theta_tree.cc:136
void AddOrUpdateEvent(int event, IntegerType initial_envelope, IntegerType energy_min, IntegerType energy_max)
Definition: theta_tree.cc:112
Collection of objects used to extend the Constraint Solver library.