forked from google/or-tools
-
Notifications
You must be signed in to change notification settings - Fork 9
/
cumulative_energy.h
163 lines (134 loc) · 5.97 KB
/
cumulative_energy.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
// Copyright 2010-2024 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.
#ifndef OR_TOOLS_SAT_CUMULATIVE_ENERGY_H_
#define OR_TOOLS_SAT_CUMULATIVE_ENERGY_H_
#include <cstdint>
#include <functional>
#include <utility>
#include <vector>
#include "absl/types/span.h"
#include "ortools/sat/2d_orthogonal_packing.h"
#include "ortools/sat/integer.h"
#include "ortools/sat/intervals.h"
#include "ortools/sat/model.h"
#include "ortools/sat/synchronization.h"
#include "ortools/sat/theta_tree.h"
#include "ortools/sat/util.h"
namespace operations_research {
namespace sat {
// Enforces the existence of a preemptive schedule where every task is executed
// inside its interval, using energy units of the resource during execution.
//
// Important: This only uses the energies min/max and not the actual demand
// of a task. It can thus be used in some non-conventional situation.
//
// All energy expression are assumed to take a non-negative value;
// if the energy of a task is 0, the task can run anywhere.
// The schedule never uses more than capacity units of energy at a given time.
//
// This is mathematically equivalent to making a model with energy(task)
// different tasks with demand and size 1, but is much more efficient,
// since it uses O(|tasks|) variables instead of O(sum_{task} |energy(task)|).
void AddCumulativeOverloadChecker(AffineExpression capacity,
SchedulingConstraintHelper* helper,
SchedulingDemandHelper* demands,
Model* model);
// Same as above, but applying a Dual Feasible Function (also known as a
// conservative scale) before looking for overload.
void AddCumulativeOverloadCheckerDff(AffineExpression capacity,
SchedulingConstraintHelper* helper,
SchedulingDemandHelper* demands,
Model* model);
// Implementation of AddCumulativeOverloadChecker().
class CumulativeEnergyConstraint : public PropagatorInterface {
public:
CumulativeEnergyConstraint(AffineExpression capacity,
SchedulingConstraintHelper* helper,
SchedulingDemandHelper* demands, Model* model);
bool Propagate() final;
void RegisterWith(GenericLiteralWatcher* watcher);
private:
const AffineExpression capacity_;
IntegerTrail* integer_trail_;
SchedulingConstraintHelper* helper_;
SchedulingDemandHelper* demands_;
ThetaLambdaTree<IntegerValue> theta_tree_;
// Task characteristics.
std::vector<int> task_to_start_event_;
// Start event characteristics, by nondecreasing start time.
std::vector<TaskTime> start_event_task_time_;
std::vector<bool> start_event_is_present_;
};
// Given that the "tasks" are part of a cumulative constraint, this adds a
// constraint that propagate the fact that: var >= max(end of substasks) +
// offset.
//
// TODO(user): I am not sure this is the best way, but it does at least push
// the level zero bound on the large cumulative instances.
class CumulativeIsAfterSubsetConstraint : public PropagatorInterface {
public:
CumulativeIsAfterSubsetConstraint(IntegerVariable var,
AffineExpression capacity,
const std::vector<int>& subtasks,
absl::Span<const IntegerValue> offsets,
SchedulingConstraintHelper* helper,
SchedulingDemandHelper* demands,
Model* model);
bool Propagate() final;
void RegisterWith(GenericLiteralWatcher* watcher);
private:
const IntegerVariable var_to_push_;
const AffineExpression capacity_;
const std::vector<int> subtasks_;
// Computed at construction time, this is const.
std::vector<bool> is_in_subtasks_;
std::vector<IntegerValue> task_offsets_;
// Temporary data used by the algorithm.
MaxBoundedSubsetSum dp_;
std::vector<std::pair<IntegerValue, IntegerValue>> energy_changes_;
IntegerTrail* integer_trail_;
SchedulingConstraintHelper* helper_;
SchedulingDemandHelper* demands_;
};
// Implementation of AddCumulativeOverloadCheckerDff().
class CumulativeDualFeasibleEnergyConstraint : public PropagatorInterface {
public:
CumulativeDualFeasibleEnergyConstraint(AffineExpression capacity,
SchedulingConstraintHelper* helper,
SchedulingDemandHelper* demands,
Model* model);
~CumulativeDualFeasibleEnergyConstraint() override;
bool Propagate() final;
void RegisterWith(GenericLiteralWatcher* watcher);
private:
bool FindAndPropagateConflict(IntegerValue window_start,
IntegerValue window_end);
ModelRandomGenerator* random_;
SharedStatistics* shared_stats_;
OrthogonalPackingInfeasibilityDetector opp_infeasibility_detector_;
const AffineExpression capacity_;
IntegerTrail* integer_trail_;
SchedulingConstraintHelper* helper_;
SchedulingDemandHelper* demands_;
ThetaLambdaTree<IntegerValue> theta_tree_;
// Task characteristics.
std::vector<int> task_to_start_event_;
// Start event characteristics, by nondecreasing start time.
std::vector<TaskTime> start_event_task_time_;
int64_t num_calls_ = 0;
int64_t num_conflicts_ = 0;
int64_t num_no_potential_window_ = 0;
};
} // namespace sat
} // namespace operations_research
#endif // OR_TOOLS_SAT_CUMULATIVE_ENERGY_H_