OR-Tools  9.3
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
15
16#include <algorithm>
17#include <cstdint>
18
20#include "ortools/sat/integer.h"
21
22namespace operations_research {
23namespace sat {
24
25template <typename IntegerType>
27
28template <typename IntegerType>
30ThetaLambdaTree<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
40template <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
64template <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
75template <typename IntegerType>
76int 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
83template <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
97template <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
111template <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}
124template <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);
134
135template <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}
147template <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
157template <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
168template <typename IntegerType>
170 DCHECK(!leaf_nodes_have_delayed_operations_);
171 return tree_[1].envelope;
172}
173template <typename IntegerType>
175 DCHECK(!leaf_nodes_have_delayed_operations_);
176 return tree_[1].envelope_opt;
177}
178
179template <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
189template <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
202template <typename IntegerType>
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
214template <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
224template <typename IntegerType>
225int 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
245template <typename IntegerType>
246int 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
263template <typename IntegerType>
264void 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
301template class ThetaLambdaTree<IntegerValue>;
302template 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:893
#define DCHECK_GE(val1, val2)
Definition: base/logging.h:895
#define DCHECK_LT(val1, val2)
Definition: base/logging.h:894
#define DCHECK(condition)
Definition: base/logging.h:890
#define DCHECK_EQ(val1, val2)
Definition: base/logging.h:891
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.