Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
theta_tree.cc
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
15
16#include <algorithm>
17#include <cstdint>
18
19#include "absl/log/check.h"
20#include "ortools/sat/integer.h"
21
22namespace operations_research {
23namespace sat {
24
25template <typename IntegerType>
27
28template <typename IntegerType>
29typename ThetaLambdaTree<IntegerType>::TreeNode
30ThetaLambdaTree<IntegerType>::ComposeTreeNodes(const TreeNode& left,
31 const TreeNode& right) {
32 return {std::max(right.envelope, left.envelope + right.sum_of_energy_min),
33 std::max(right.envelope_opt,
34 right.sum_of_energy_min +
35 std::max(left.envelope_opt,
36 left.envelope + right.max_of_energy_delta)),
37 left.sum_of_energy_min + right.sum_of_energy_min,
38 std::max(right.max_of_energy_delta, left.max_of_energy_delta)};
39}
40
41template <typename IntegerType>
43#ifndef NDEBUG
44 leaf_nodes_have_delayed_operations_ = false;
45#endif
46 // Because the algorithm needs to access a node sibling (i.e. node_index ^ 1),
47 // our tree will always have an even number of leaves, just large enough to
48 // fit our number of events. And at least 2 for the empty tree case.
49 num_events_ = num_events;
50 num_leaves_ = std::max(2, num_events + (num_events & 1));
51
52 const int num_nodes = 2 * num_leaves_;
53 tree_.assign(num_nodes, TreeNode{IntegerTypeMinimumValue<IntegerType>(),
55 IntegerType{0}, IntegerType{0}});
56
57 // If num_leaves is not a power or two, the last depth of the tree will not be
58 // full, and the array will look like:
59 // [( num_leafs parents)(leaves at depth d - 1)(leaves at depth d)
60 // The first leaves at depth p will have power_of_two_ as index.
61 for (power_of_two_ = 2; power_of_two_ < num_leaves_; power_of_two_ <<= 1) {
62 }
63}
64
65template <typename IntegerType>
67 DCHECK_LE(0, event);
68 DCHECK_LT(event, num_events_);
69 // Keeping the ordering of events is important, so the first set of events
70 // must be mapped to the set of leaves at depth d, and the second set of
71 // events must be mapped to the set of leaves at depth d-1.
72 const int r = power_of_two_ + event;
73 return r < 2 * num_leaves_ ? r : r - num_leaves_;
74}
75
76template <typename IntegerType>
77int ThetaLambdaTree<IntegerType>::GetEventFromLeaf(int leaf) const {
78 DCHECK_GE(leaf, num_leaves_);
79 DCHECK_LT(leaf, 2 * num_leaves_);
80 const int r = leaf - power_of_two_;
81 return r >= 0 ? r : r + num_leaves_;
82}
83
84template <typename IntegerType>
86#ifndef NDEBUG
87 leaf_nodes_have_delayed_operations_ = false;
88#endif
89 // Only recompute internal nodes.
90 const int last_internal_node = tree_.size() / 2 - 1;
91 for (int node = last_internal_node; node >= 1; --node) {
92 const int right = 2 * node + 1;
93 const int left = 2 * node;
94 tree_[node] = ComposeTreeNodes(tree_[left], tree_[right]);
95 }
96}
97
98template <typename IntegerType>
100 int event, IntegerType initial_envelope, IntegerType energy_min,
101 IntegerType energy_max) {
102#ifndef NDEBUG
103 leaf_nodes_have_delayed_operations_ = true;
104#endif
105 DCHECK_LE(0, energy_min);
106 DCHECK_LE(energy_min, energy_max);
107 const int node = GetLeafFromEvent(event);
108 tree_[node] = {initial_envelope + energy_min, initial_envelope + energy_max,
109 energy_min, energy_max - energy_min};
110}
111
112template <typename IntegerType>
114 int event, IntegerType initial_envelope, IntegerType energy_min,
115 IntegerType energy_max) {
116 DCHECK(!leaf_nodes_have_delayed_operations_);
117 DCHECK_LE(0, energy_min);
118 DCHECK_LE(energy_min, energy_max);
119 const int node = GetLeafFromEvent(event);
120 tree_[node] = {initial_envelope + energy_min, initial_envelope + energy_max,
121 energy_min, energy_max - energy_min};
122 RefreshNode(node);
124
125template <typename IntegerType>
127 int event, IntegerType initial_envelope_opt, IntegerType energy_max) {
128 DCHECK(!leaf_nodes_have_delayed_operations_);
129 DCHECK_LE(0, energy_max);
130 const int node = GetLeafFromEvent(event);
132 initial_envelope_opt + energy_max, IntegerType{0}, energy_max};
133 RefreshNode(node);
134}
135
136template <typename IntegerType>
138 int event, IntegerType initial_envelope_opt, IntegerType energy_max) {
139#ifndef NDEBUG
140 leaf_nodes_have_delayed_operations_ = true;
141#endif
142 DCHECK_LE(0, energy_max);
143 const int node = GetLeafFromEvent(event);
145 initial_envelope_opt + energy_max, IntegerType{0}, energy_max};
147
148template <typename IntegerType>
150 DCHECK(!leaf_nodes_have_delayed_operations_);
151 const int node = GetLeafFromEvent(event);
153 IntegerTypeMinimumValue<IntegerType>(), IntegerType{0},
154 IntegerType{0}};
155 RefreshNode(node);
156}
157
158template <typename IntegerType>
160#ifndef NDEBUG
161 leaf_nodes_have_delayed_operations_ = true;
162#endif
163 const int node = GetLeafFromEvent(event);
165 IntegerTypeMinimumValue<IntegerType>(), IntegerType{0},
166 IntegerType{0}};
167}
168
169template <typename IntegerType>
171 DCHECK(!leaf_nodes_have_delayed_operations_);
172 return tree_[1].envelope;
173}
174template <typename IntegerType>
176 DCHECK(!leaf_nodes_have_delayed_operations_);
177 return tree_[1].envelope_opt;
178}
179
180template <typename IntegerType>
182 IntegerType target_envelope) const {
183 DCHECK(!leaf_nodes_have_delayed_operations_);
184 DCHECK_LT(target_envelope, tree_[1].envelope);
185 IntegerType unused;
186 return GetEventFromLeaf(
187 GetMaxLeafWithEnvelopeGreaterThan(1, target_envelope, &unused));
188}
189
190template <typename IntegerType>
192 IntegerType target_envelope, int* critical_event, int* optional_event,
193 IntegerType* available_energy) const {
194 DCHECK(!leaf_nodes_have_delayed_operations_);
195 int critical_leaf;
196 int optional_leaf;
197 GetLeavesWithOptionalEnvelopeGreaterThan(target_envelope, &critical_leaf,
198 &optional_leaf, available_energy);
199 *critical_event = GetEventFromLeaf(critical_leaf);
200 *optional_event = GetEventFromLeaf(optional_leaf);
201}
202
203template <typename IntegerType>
205 DCHECK(!leaf_nodes_have_delayed_operations_);
206 const int leaf = GetLeafFromEvent(event);
207 IntegerType envelope = tree_[leaf].envelope;
208 for (int node = leaf; node > 1; node >>= 1) {
209 const int right = node | 1;
210 if (node != right) envelope += tree_[right].sum_of_energy_min;
211 }
212 return envelope;
213}
214
215template <typename IntegerType>
217 TreeNode* tree = tree_.data();
218 do {
219 const int right = node | 1;
220 const int left = right ^ 1;
221 node >>= 1;
222 tree[node] = ComposeTreeNodes(tree[left], tree[right]);
223 } while (node > 1);
224}
225
226template <typename IntegerType>
227int ThetaLambdaTree<IntegerType>::GetMaxLeafWithEnvelopeGreaterThan(
228 int node, IntegerType target_envelope, IntegerType* extra) const {
229 DCHECK(!leaf_nodes_have_delayed_operations_);
230 DCHECK_LT(target_envelope, tree_[node].envelope);
231 while (node < num_leaves_) {
232 const int left = node << 1;
233 const int right = left | 1;
234 DCHECK_LT(right, tree_.size());
235
236 if (target_envelope < tree_[right].envelope) {
237 node = right;
238 } else {
239 target_envelope -= tree_[right].sum_of_energy_min;
240 node = left;
241 }
242 }
243 *extra = tree_[node].envelope - target_envelope;
244 return node;
245}
246
247template <typename IntegerType>
248int ThetaLambdaTree<IntegerType>::GetLeafWithMaxEnergyDelta(int node) const {
249 DCHECK(!leaf_nodes_have_delayed_operations_);
250 const IntegerType delta_node = tree_[node].max_of_energy_delta;
251 while (node < num_leaves_) {
252 const int left = node << 1;
253 const int right = left | 1;
254 DCHECK_LT(right, tree_.size());
255 if (tree_[right].max_of_energy_delta == delta_node) {
256 node = right;
257 } else {
258 DCHECK_EQ(tree_[left].max_of_energy_delta, delta_node);
259 node = left;
260 }
261 }
262 return node;
263}
264
265template <typename IntegerType>
266void ThetaLambdaTree<IntegerType>::GetLeavesWithOptionalEnvelopeGreaterThan(
267 IntegerType target_envelope, int* critical_leaf, int* optional_leaf,
268 IntegerType* available_energy) const {
269 DCHECK(!leaf_nodes_have_delayed_operations_);
270 DCHECK_LT(target_envelope, tree_[1].envelope_opt);
271 int node = 1;
272 while (node < num_leaves_) {
273 const int left = node << 1;
274 const int right = left | 1;
275 DCHECK_LT(right, tree_.size());
276
277 if (target_envelope < tree_[right].envelope_opt) {
278 node = right;
279 } else {
280 const IntegerType opt_energy_right =
281 tree_[right].sum_of_energy_min + tree_[right].max_of_energy_delta;
282 if (target_envelope < tree_[left].envelope + opt_energy_right) {
283 *optional_leaf = GetLeafWithMaxEnergyDelta(right);
284 IntegerType extra;
285 *critical_leaf = GetMaxLeafWithEnvelopeGreaterThan(
286 left, target_envelope - opt_energy_right, &extra);
287 *available_energy = tree_[*optional_leaf].sum_of_energy_min +
288 tree_[*optional_leaf].max_of_energy_delta - extra;
289 return;
290 } else { // < tree_[left].envelope_opt + tree_[right].sum_of_energy_min
291 target_envelope -= tree_[right].sum_of_energy_min;
292 node = left;
293 }
294 }
295 }
296 *critical_leaf = node;
297 *optional_leaf = node;
298 *available_energy = target_envelope - (tree_[node].envelope_opt -
299 tree_[node].sum_of_energy_min -
300 tree_[node].max_of_energy_delta);
301}
302
303template class ThetaLambdaTree<IntegerValue>;
304template class ThetaLambdaTree<int64_t>;
305
306} // namespace sat
307} // namespace operations_research
void DelayedRemoveEvent(int event)
Delayed version of RemoveEvent(), see RecomputeTreeForDelayedOperations().
ThetaLambdaTree()
Builds a reusable tree. Initialization is done with Reset().
void DelayedAddOrUpdateOptionalEvent(int event, IntegerType initial_envelope_opt, IntegerType energy_max)
void RemoveEvent(int event)
Makes event absent, compute the new envelope in O(log n).
void AddOrUpdateEvent(int event, IntegerType initial_envelope, IntegerType energy_min, IntegerType energy_max)
void GetEventsWithOptionalEnvelopeGreaterThan(IntegerType target_envelope, int *critical_event, int *optional_event, IntegerType *available_energy) const
int GetMaxEventWithEnvelopeGreaterThan(IntegerType target_envelope) const
IntegerType GetEnvelopeOf(int event) const
void AddOrUpdateOptionalEvent(int event, IntegerType initial_envelope_opt, IntegerType energy_max)
void DelayedAddOrUpdateEvent(int event, IntegerType initial_envelope, IntegerType energy_min, IntegerType energy_max)
Definition theta_tree.cc:99
constexpr IntegerType IntegerTypeMinimumValue()
The minimal value of an envelope, for instance the envelope of the empty set.
Definition theta_tree.h:95
In SWIG mode, we don't want anything besides these top-level includes.