OR-Tools  9.0
theta_tree.h
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 #ifndef OR_TOOLS_SAT_THETA_TREE_H_
15 #define OR_TOOLS_SAT_THETA_TREE_H_
16 
17 #include <cstdint>
18 #include <vector>
19 
20 #include "ortools/base/logging.h"
21 #include "ortools/sat/integer.h"
22 
23 namespace operations_research {
24 namespace sat {
25 
26 // The Theta-Lambda tree can be used to implement several scheduling algorithms.
27 //
28 // This template class is instantiated only for IntegerValue and int64_t.
29 //
30 // The tree structure itself is a binary tree coded in a vector, where node 0 is
31 // unused, node 1 is the root, node 2 is the left child of the root, node 3 its
32 // right child, etc.
33 //
34 // The API gives access to rightmost events that realize a given envelope.
35 //
36 // See:
37 // _ (0) Petr Vilim's PhD thesis "Global Constraints in Scheduling".
38 // _ (1) Petr Vilim "Edge Finding Filtering Algorithm for Discrete Cumulative
39 // Resources in O(kn log n)"
40 // _ (2) Petr Vilim "Max energy filtering algorithm for discrete cumulative
41 // resources".
42 // _ (3) Wolf & Schrader "O(n log n) Overload Checking for the Cumulative
43 // Constraint and Its Application".
44 // _ (4) Kameugne & Fotso "A cumulative not-first/not-last filtering algorithm
45 // in O(n^2 log n)".
46 // _ (5) Ouellet & Quimper "Time-table extended-edge-finding for the cumulative
47 // constraint".
48 //
49 // Instead of providing one declination of the theta-tree per possible filtering
50 // algorithm, this generalization intends to provide a data structure that can
51 // fit several algorithms.
52 // This tree is based around the notion of events. It has events at its leaves
53 // that can be present or absent, and present events come with an
54 // initial_envelope, a minimal and a maximal energy.
55 // All nodes maintain values on the set of present events under them:
56 // _ sum_energy_min(node) = sum_{leaf \in leaves(node)} energy_min(leaf)
57 // _ envelope(node) =
58 // max_{leaf \in leaves(node)}
59 // initial_envelope(leaf) +
60 // sum_{leaf' \in leaves(node), leaf' >= leaf} energy_min(leaf').
61 //
62 // Thus, the envelope of a leaf representing an event, when present, is
63 // initial_envelope(event) + sum_energy_min(event).
64 //
65 // We also maintain envelope_opt with is the maximum envelope a node could take
66 // if at most one of the events were at its maximum energy.
67 // _ energy_delta(leaf) = energy_max(leaf) - energy_min(leaf)
68 // _ max_energy_delta(node) = max_{leaf \in leaves(node)} energy_delta(leaf)
69 // _ envelope_opt(node) =
70 // max_{leaf \in leaves(node)}
71 // initial_envelope(leaf) +
72 // sum_{leaf' \in leaves(node), leaf' >= leaf} energy_min(leaf') +
73 // max_{leaf' \in leaves(node), leaf' >= leaf} energy_delta(leaf');
74 //
75 // Most articles using theta-tree variants hack Vilim's original theta tree
76 // for the disjunctive resource constraint by manipulating envelope and
77 // energy:
78 // _ in (0), initial_envelope = start_min, energy = duration
79 // _ in (3), initial_envelope = C * start_min, energy = demand * duration
80 // _ in (5), there are several trees in parallel:
81 // initial_envelope = C * start_min or (C - h) * start_min
82 // energy = demand * duration, h * (Horizon - start_min),
83 // or h * (end_min).
84 // _ in (2), same as (3), but putting the max energy instead of min in lambda.
85 // _ in OscaR's TimeTableOverloadChecker,
86 // initial_envelope = C * start_min -
87 // energy of mandatory profile before start_min,
88 // energy = demand * duration
89 //
90 // There is hope to unify the variants of these algorithms by abstracting the
91 // tasks away to reason only on events.
92 
93 // The minimal value of an envelope, for instance the envelope of the empty set.
94 template <typename IntegerType>
95 constexpr IntegerType IntegerTypeMinimumValue() {
97 }
98 template <>
99 constexpr IntegerValue IntegerTypeMinimumValue() {
100  return kMinIntegerValue;
101 }
102 
103 template <typename IntegerType>
105  public:
106  // Builds a reusable tree. Initialization is done with Reset().
107  ThetaLambdaTree();
108 
109  // Initializes this class for events in [0, num_events) and makes all of them
110  // absent. Instead of allocating and de-allocating trees at every usage, i.e.
111  // at every Propagate() of the scheduling algorithms that uses it, this class
112  // allows to keep the same memory for each call.
113  void Reset(int num_events);
114 
115  // Recomputes the values of internal nodes of the tree from the values in the
116  // leaves. We enable batching modifications to the tree by providing
117  // DelayedXXX() methods that run in O(1), but those methods do not
118  // update internal nodes. This breaks tree invariants, so that GetXXX()
119  // methods will not reflect modifications made to events.
120  // RecomputeTreeForDelayedOperations() restores those invariants in O(n).
121  // Thus, batching operations can be done by first doing calls to DelayedXXX()
122  // methods, then calling RecomputeTreeForDelayedOperations() once.
124 
125  // Makes event present and updates its initial envelope and min/max energies.
126  // The initial_envelope must be >= ThetaLambdaTreeNegativeInfinity().
127  // This updates the tree in O(log n).
128  void AddOrUpdateEvent(int event, IntegerType initial_envelope,
129  IntegerType energy_min, IntegerType energy_max);
130 
131  // Delayed version of AddOrUpdateEvent(),
132  // see RecomputeTreeForDelayedOperations().
133  void DelayedAddOrUpdateEvent(int event, IntegerType initial_envelope,
134  IntegerType energy_min, IntegerType energy_max);
135 
136  // Adds event to the lambda part of the tree only.
137  // This will leave GetEnvelope() unchanged, only GetOptionalEnvelope() can
138  // be affected. This is done by setting envelope to IntegerTypeMinimumValue(),
139  // energy_min to 0, and initial_envelope_opt and energy_max to the parameters.
140  // This updates the tree in O(log n).
141  void AddOrUpdateOptionalEvent(int event, IntegerType initial_envelope_opt,
142  IntegerType energy_max);
143 
144  // Delayed version of AddOrUpdateOptionalEvent(),
145  // see RecomputeTreeForDelayedOperations().
146  void DelayedAddOrUpdateOptionalEvent(int event,
147  IntegerType initial_envelope_opt,
148  IntegerType energy_max);
149 
150  // Makes event absent, compute the new envelope in O(log n).
151  void RemoveEvent(int event);
152 
153  // Delayed version of RemoveEvent(), see RecomputeTreeForDelayedOperations().
154  void DelayedRemoveEvent(int event);
155 
156  // Returns the maximum envelope using all the energy_min in O(1).
157  // If theta is empty, returns ThetaLambdaTreeNegativeInfinity().
158  IntegerType GetEnvelope() const;
159 
160  // Returns the maximum envelope using the energy min of all task but
161  // one and the energy max of the last one in O(1).
162  // If theta and lambda are empty, returns ThetaLambdaTreeNegativeInfinity().
163  IntegerType GetOptionalEnvelope() const;
164 
165  // Computes the maximum event s.t. GetEnvelopeOf(event) > envelope_max.
166  // There must be such an event, i.e. GetEnvelope() > envelope_max.
167  // This finds the maximum event e such that
168  // initial_envelope(e) + sum_{e' >= e} energy_min(e') > target_envelope.
169  // This operation is O(log n).
170  int GetMaxEventWithEnvelopeGreaterThan(IntegerType target_envelope) const;
171 
172  // Returns initial_envelope(event) + sum_{event' >= event} energy_min(event'),
173  // in time O(log n).
174  IntegerType GetEnvelopeOf(int event) const;
175 
176  // Computes a pair of events (critical_event, optional_event) such that
177  // if optional_event was at its maximum energy, the envelope of critical_event
178  // would be greater than target_envelope.
179  //
180  // This assumes that such a pair exists, i.e. GetOptionalEnvelope() should be
181  // greater than target_envelope. More formally, this finds events such that:
182  // initial_envelope(critical_event) +
183  // sum_{event' >= critical_event} energy_min(event') +
184  // max_{optional_event >= critical_event} energy_delta(optional_event)
185  // > target envelope.
186  //
187  // For efficiency reasons, this also fills available_energy with the maximum
188  // energy the optional task can take such that the optional envelope of the
189  // pair would be target_envelope, i.e.
190  // target_envelope - GetEnvelopeOf(event) + energy_min(optional_event).
191  //
192  // This operation is O(log n).
194  IntegerType target_envelope, int* critical_event, int* optional_event,
195  IntegerType* available_energy) const;
196 
197  // Getters.
198  IntegerType EnergyMin(int event) const {
199  return tree_[GetLeafFromEvent(event)].sum_of_energy_min;
200  }
201 
202  private:
203  struct TreeNode {
204  IntegerType envelope;
205  IntegerType envelope_opt;
206  IntegerType sum_of_energy_min;
207  IntegerType max_of_energy_delta;
208  };
209 
210  TreeNode ComposeTreeNodes(TreeNode left, TreeNode right);
211 
212  int GetLeafFromEvent(int event) const;
213  int GetEventFromLeaf(int leaf) const;
214 
215  // Propagates the change of leaf energies and envelopes towards the root.
216  void RefreshNode(int node);
217 
218  // Finds the maximum leaf under node such that
219  // initial_envelope(leaf) + sum_{leaf' >= leaf} energy_min(leaf')
220  // > target_envelope.
221  // Fills extra with the difference.
222  int GetMaxLeafWithEnvelopeGreaterThan(int node, IntegerType target_envelope,
223  IntegerType* extra) const;
224 
225  // Returns the leaf with maximum energy delta under node.
226  int GetLeafWithMaxEnergyDelta(int node) const;
227 
228  // Finds the leaves and energy relevant for
229  // GetEventsWithOptionalEnvelopeGreaterThan().
230  void GetLeavesWithOptionalEnvelopeGreaterThan(
231  IntegerType target_envelope, int* critical_leaf, int* optional_leaf,
232  IntegerType* available_energy) const;
233 
234  // Number of events of the last Reset().
235  int num_events_;
236  int num_leaves_;
237  int power_of_two_;
238 
239  // A bool used in debug mode, to check that sequences of delayed operations
240  // are ended by Reset() or RecomputeTreeForDelayedOperations().
241  bool leaf_nodes_have_delayed_operations_ = false;
242 
243  // Envelopes and energies of nodes.
244  std::vector<TreeNode> tree_;
245 };
246 
247 // Explicit instantiations in theta_Tree.cc.
248 extern template class ThetaLambdaTree<IntegerValue>;
249 extern template class ThetaLambdaTree<int64_t>;
250 
251 } // namespace sat
252 } // namespace operations_research
253 
254 #endif // OR_TOOLS_SAT_THETA_TREE_H_
int64_t min
Definition: alldiff_cst.cc:139
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
IntegerType EnergyMin(int event) const
Definition: theta_tree.h:198
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
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue)
constexpr IntegerType IntegerTypeMinimumValue()
Definition: theta_tree.h:95
Collection of objects used to extend the Constraint Solver library.