Files
ortools-clone/ortools/sat/theta_tree.cc

306 lines
11 KiB
C++

// Copyright 2010-2021 Google LLC
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "ortools/sat/theta_tree.h"
#include <algorithm>
#include <cstdint>
#include "ortools/base/logging.h"
#include "ortools/sat/integer.h"
namespace operations_research {
namespace sat {
template <typename IntegerType>
ThetaLambdaTree<IntegerType>::ThetaLambdaTree() {}
template <typename IntegerType>
typename ThetaLambdaTree<IntegerType>::TreeNode
ThetaLambdaTree<IntegerType>::ComposeTreeNodes(TreeNode left, TreeNode right) {
return {std::max(right.envelope, left.envelope + right.sum_of_energy_min),
std::max(right.envelope_opt,
right.sum_of_energy_min +
std::max(left.envelope_opt,
left.envelope + right.max_of_energy_delta)),
left.sum_of_energy_min + right.sum_of_energy_min,
std::max(right.max_of_energy_delta, left.max_of_energy_delta)};
}
template <typename IntegerType>
void ThetaLambdaTree<IntegerType>::Reset(int num_events) {
#ifndef NDEBUG
leaf_nodes_have_delayed_operations_ = false;
#endif
// Because the algorithm needs to access a node sibling (i.e. node_index ^ 1),
// our tree will always have an even number of leaves, just large enough to
// fit our number of events. And at least 2 for the empty tree case.
num_events_ = num_events;
num_leaves_ = std::max(2, num_events + (num_events & 1));
const int num_nodes = 2 * num_leaves_;
tree_.assign(num_nodes, TreeNode{IntegerTypeMinimumValue<IntegerType>(),
IntegerTypeMinimumValue<IntegerType>(),
IntegerType{0}, IntegerType{0}});
// If num_leaves is not a power or two, the last depth of the tree will not be
// full, and the array will look like:
// [( num_leafs parents)(leaves at depth d - 1)(leaves at depth d)
// The first leaves at depth p will have power_of_two_ as index.
for (power_of_two_ = 2; power_of_two_ < num_leaves_; power_of_two_ <<= 1) {
}
}
template <typename IntegerType>
int ThetaLambdaTree<IntegerType>::GetLeafFromEvent(int event) const {
DCHECK_LE(0, event);
DCHECK_LT(event, num_events_);
// Keeping the ordering of events is important, so the first set of events
// must be mapped to the set of leaves at depth d, and the second set of
// events must be mapped to the set of leaves at depth d-1.
const int r = power_of_two_ + event;
return r < 2 * num_leaves_ ? r : r - num_leaves_;
}
template <typename IntegerType>
int ThetaLambdaTree<IntegerType>::GetEventFromLeaf(int leaf) const {
DCHECK_GE(leaf, num_leaves_);
DCHECK_LT(leaf, 2 * num_leaves_);
const int r = leaf - power_of_two_;
return r >= 0 ? r : r + num_leaves_;
}
template <typename IntegerType>
void ThetaLambdaTree<IntegerType>::RecomputeTreeForDelayedOperations() {
#ifndef NDEBUG
leaf_nodes_have_delayed_operations_ = false;
#endif
// Only recompute internal nodes.
const int last_internal_node = tree_.size() / 2 - 1;
for (int node = last_internal_node; node >= 1; --node) {
const int right = 2 * node + 1;
const int left = 2 * node;
tree_[node] = ComposeTreeNodes(tree_[left], tree_[right]);
}
}
template <typename IntegerType>
void ThetaLambdaTree<IntegerType>::DelayedAddOrUpdateEvent(
int event, IntegerType initial_envelope, IntegerType energy_min,
IntegerType energy_max) {
#ifndef NDEBUG
leaf_nodes_have_delayed_operations_ = true;
#endif
DCHECK_LE(0, energy_min);
DCHECK_LE(energy_min, energy_max);
const int node = GetLeafFromEvent(event);
tree_[node] = {initial_envelope + energy_min, initial_envelope + energy_max,
energy_min, energy_max - energy_min};
}
template <typename IntegerType>
void ThetaLambdaTree<IntegerType>::AddOrUpdateEvent(
int event, IntegerType initial_envelope, IntegerType energy_min,
IntegerType energy_max) {
DCHECK(!leaf_nodes_have_delayed_operations_);
DCHECK_LE(0, energy_min);
DCHECK_LE(energy_min, energy_max);
const int node = GetLeafFromEvent(event);
tree_[node] = {initial_envelope + energy_min, initial_envelope + energy_max,
energy_min, energy_max - energy_min};
RefreshNode(node);
}
template <typename IntegerType>
void ThetaLambdaTree<IntegerType>::AddOrUpdateOptionalEvent(
int event, IntegerType initial_envelope_opt, IntegerType energy_max) {
DCHECK(!leaf_nodes_have_delayed_operations_);
DCHECK_LE(0, energy_max);
const int node = GetLeafFromEvent(event);
tree_[node] = {IntegerTypeMinimumValue<IntegerType>(),
initial_envelope_opt + energy_max, IntegerType{0}, energy_max};
RefreshNode(node);
}
template <typename IntegerType>
void ThetaLambdaTree<IntegerType>::DelayedAddOrUpdateOptionalEvent(
int event, IntegerType initial_envelope_opt, IntegerType energy_max) {
#ifndef NDEBUG
leaf_nodes_have_delayed_operations_ = true;
#endif
DCHECK_LE(0, energy_max);
const int node = GetLeafFromEvent(event);
tree_[node] = {IntegerTypeMinimumValue<IntegerType>(),
initial_envelope_opt + energy_max, IntegerType{0}, energy_max};
}
template <typename IntegerType>
void ThetaLambdaTree<IntegerType>::RemoveEvent(int event) {
DCHECK(!leaf_nodes_have_delayed_operations_);
const int node = GetLeafFromEvent(event);
tree_[node] = {IntegerTypeMinimumValue<IntegerType>(),
IntegerTypeMinimumValue<IntegerType>(), IntegerType{0},
IntegerType{0}};
RefreshNode(node);
}
template <typename IntegerType>
void ThetaLambdaTree<IntegerType>::DelayedRemoveEvent(int event) {
#ifndef NDEBUG
leaf_nodes_have_delayed_operations_ = true;
#endif
const int node = GetLeafFromEvent(event);
tree_[node] = {IntegerTypeMinimumValue<IntegerType>(),
IntegerTypeMinimumValue<IntegerType>(), IntegerType{0},
IntegerType{0}};
}
template <typename IntegerType>
IntegerType ThetaLambdaTree<IntegerType>::GetEnvelope() const {
DCHECK(!leaf_nodes_have_delayed_operations_);
return tree_[1].envelope;
}
template <typename IntegerType>
IntegerType ThetaLambdaTree<IntegerType>::GetOptionalEnvelope() const {
DCHECK(!leaf_nodes_have_delayed_operations_);
return tree_[1].envelope_opt;
}
template <typename IntegerType>
int ThetaLambdaTree<IntegerType>::GetMaxEventWithEnvelopeGreaterThan(
IntegerType target_envelope) const {
DCHECK(!leaf_nodes_have_delayed_operations_);
DCHECK_LT(target_envelope, tree_[1].envelope);
IntegerType unused;
return GetEventFromLeaf(
GetMaxLeafWithEnvelopeGreaterThan(1, target_envelope, &unused));
}
template <typename IntegerType>
void ThetaLambdaTree<IntegerType>::GetEventsWithOptionalEnvelopeGreaterThan(
IntegerType target_envelope, int* critical_event, int* optional_event,
IntegerType* available_energy) const {
DCHECK(!leaf_nodes_have_delayed_operations_);
int critical_leaf;
int optional_leaf;
GetLeavesWithOptionalEnvelopeGreaterThan(target_envelope, &critical_leaf,
&optional_leaf, available_energy);
*critical_event = GetEventFromLeaf(critical_leaf);
*optional_event = GetEventFromLeaf(optional_leaf);
}
template <typename IntegerType>
IntegerType ThetaLambdaTree<IntegerType>::GetEnvelopeOf(int event) const {
DCHECK(!leaf_nodes_have_delayed_operations_);
const int leaf = GetLeafFromEvent(event);
IntegerType envelope = tree_[leaf].envelope;
for (int node = leaf; node > 1; node >>= 1) {
const int right = node | 1;
if (node != right) envelope += tree_[right].sum_of_energy_min;
}
return envelope;
}
template <typename IntegerType>
void ThetaLambdaTree<IntegerType>::RefreshNode(int node) {
do {
const int right = node | 1;
const int left = right ^ 1;
node >>= 1;
tree_[node] = ComposeTreeNodes(tree_[left], tree_[right]);
} while (node > 1);
}
template <typename IntegerType>
int ThetaLambdaTree<IntegerType>::GetMaxLeafWithEnvelopeGreaterThan(
int node, IntegerType target_envelope, IntegerType* extra) const {
DCHECK(!leaf_nodes_have_delayed_operations_);
DCHECK_LT(target_envelope, tree_[node].envelope);
while (node < num_leaves_) {
const int left = node << 1;
const int right = left | 1;
DCHECK_LT(right, tree_.size());
if (target_envelope < tree_[right].envelope) {
node = right;
} else {
target_envelope -= tree_[right].sum_of_energy_min;
node = left;
}
}
*extra = tree_[node].envelope - target_envelope;
return node;
}
template <typename IntegerType>
int ThetaLambdaTree<IntegerType>::GetLeafWithMaxEnergyDelta(int node) const {
DCHECK(!leaf_nodes_have_delayed_operations_);
const IntegerType delta_node = tree_[node].max_of_energy_delta;
while (node < num_leaves_) {
const int left = node << 1;
const int right = left | 1;
DCHECK_LT(right, tree_.size());
if (tree_[right].max_of_energy_delta == delta_node) {
node = right;
} else {
DCHECK_EQ(tree_[left].max_of_energy_delta, delta_node);
node = left;
}
}
return node;
}
template <typename IntegerType>
void ThetaLambdaTree<IntegerType>::GetLeavesWithOptionalEnvelopeGreaterThan(
IntegerType target_envelope, int* critical_leaf, int* optional_leaf,
IntegerType* available_energy) const {
DCHECK(!leaf_nodes_have_delayed_operations_);
DCHECK_LT(target_envelope, tree_[1].envelope_opt);
int node = 1;
while (node < num_leaves_) {
const int left = node << 1;
const int right = left | 1;
DCHECK_LT(right, tree_.size());
if (target_envelope < tree_[right].envelope_opt) {
node = right;
} else {
const IntegerType opt_energy_right =
tree_[right].sum_of_energy_min + tree_[right].max_of_energy_delta;
if (target_envelope < tree_[left].envelope + opt_energy_right) {
*optional_leaf = GetLeafWithMaxEnergyDelta(right);
IntegerType extra;
*critical_leaf = GetMaxLeafWithEnvelopeGreaterThan(
left, target_envelope - opt_energy_right, &extra);
*available_energy = tree_[*optional_leaf].sum_of_energy_min +
tree_[*optional_leaf].max_of_energy_delta - extra;
return;
} else { // < tree_[left].envelope_opt + tree_[right].sum_of_energy_min
target_envelope -= tree_[right].sum_of_energy_min;
node = left;
}
}
}
*critical_leaf = node;
*optional_leaf = node;
*available_energy = target_envelope - (tree_[node].envelope_opt -
tree_[node].sum_of_energy_min -
tree_[node].max_of_energy_delta);
}
template class ThetaLambdaTree<IntegerValue>;
template class ThetaLambdaTree<int64_t>;
} // namespace sat
} // namespace operations_research