pumpkin_constraints/constraints/
cumulative.rs1use std::fmt::Debug;
2
3use pumpkin_core::ConstraintOperationError;
4use pumpkin_core::Solver;
5use pumpkin_core::asserts::pumpkin_assert_simple;
6use pumpkin_core::constraints::Constraint;
7use pumpkin_core::proof::ConstraintTag;
8use pumpkin_core::variables::IntegerVariable;
9use pumpkin_core::variables::Literal;
10use pumpkin_propagators::cumulative::ArgTask;
11use pumpkin_propagators::cumulative::options::CumulativeOptions;
12use pumpkin_propagators::cumulative::options::CumulativePropagationMethod;
13use pumpkin_propagators::cumulative::time_table::TimeTableOverIntervalIncrementalPropagator;
14use pumpkin_propagators::cumulative::time_table::TimeTableOverIntervalPropagator;
15use pumpkin_propagators::cumulative::time_table::TimeTablePerPointIncrementalPropagator;
16use pumpkin_propagators::cumulative::time_table::TimeTablePerPointPropagator;
17
18pub fn cumulative<StartTimes, Durations, ResourceRequirements>(
81 start_times: StartTimes,
82 durations: Durations,
83 resource_requirements: ResourceRequirements,
84 resource_capacity: i32,
85 constraint_tag: ConstraintTag,
86) -> impl Constraint
87where
88 StartTimes: IntoIterator,
89 StartTimes::Item: IntegerVariable + Debug + 'static,
90 StartTimes::IntoIter: ExactSizeIterator,
91 Durations: IntoIterator<Item = i32>,
92 Durations::IntoIter: ExactSizeIterator,
93 ResourceRequirements: IntoIterator<Item = i32>,
94 ResourceRequirements::IntoIter: ExactSizeIterator,
95{
96 cumulative_with_options(
97 start_times,
98 durations,
99 resource_requirements,
100 resource_capacity,
101 CumulativeOptions::default(),
102 constraint_tag,
103 )
104}
105
106pub fn cumulative_with_options<StartTimes, Durations, ResourceRequirements>(
111 start_times: StartTimes,
112 durations: Durations,
113 resource_requirements: ResourceRequirements,
114 resource_capacity: i32,
115 options: CumulativeOptions,
116 constraint_tag: ConstraintTag,
117) -> impl Constraint
118where
119 StartTimes: IntoIterator,
120 StartTimes::Item: IntegerVariable + Debug + 'static,
121 StartTimes::IntoIter: ExactSizeIterator,
122 Durations: IntoIterator<Item = i32>,
123 Durations::IntoIter: ExactSizeIterator,
124 ResourceRequirements: IntoIterator<Item = i32>,
125 ResourceRequirements::IntoIter: ExactSizeIterator,
126{
127 let start_times = start_times.into_iter();
128 let durations = durations.into_iter();
129 let resource_requirements = resource_requirements.into_iter();
130
131 pumpkin_assert_simple!(
132 start_times.len() == durations.len() && durations.len() == resource_requirements.len(),
133 "The number of start variables, durations and resource requirements should be the same!"
134 );
135
136 CumulativeConstraint::new(
137 &start_times
138 .zip(durations)
139 .zip(resource_requirements)
140 .map(|((start_time, duration), resource_requirement)| ArgTask {
141 start_time,
142 processing_time: duration,
143 resource_usage: resource_requirement,
144 })
145 .collect::<Vec<_>>(),
146 resource_capacity,
147 options,
148 constraint_tag,
149 )
150}
151
152struct CumulativeConstraint<Var> {
153 tasks: Vec<ArgTask<Var>>,
154 resource_capacity: i32,
155 options: CumulativeOptions,
156 constraint_tag: ConstraintTag,
157}
158
159impl<Var: IntegerVariable + 'static> CumulativeConstraint<Var> {
160 fn new(
161 tasks: &[ArgTask<Var>],
162 resource_capacity: i32,
163 options: CumulativeOptions,
164 constraint_tag: ConstraintTag,
165 ) -> Self {
166 Self {
167 tasks: tasks.into(),
168 resource_capacity,
169
170 options,
171 constraint_tag,
172 }
173 }
174}
175
176impl<Var: IntegerVariable + 'static + Debug> Constraint for CumulativeConstraint<Var> {
177 fn post(self, solver: &mut Solver) -> Result<(), ConstraintOperationError> {
178 match self.options.propagation_method {
179 CumulativePropagationMethod::TimeTablePerPoint => TimeTablePerPointPropagator::new(
180 &self.tasks,
181 self.resource_capacity,
182 self.options.propagator_options,
183 self.constraint_tag,
184 )
185 .post(solver),
186
187 CumulativePropagationMethod::TimeTablePerPointIncremental => {
188 TimeTablePerPointIncrementalPropagator::<Var, false>::new(
189 &self.tasks,
190 self.resource_capacity,
191 self.options.propagator_options,
192 self.constraint_tag,
193 )
194 .post(solver)
195 }
196 CumulativePropagationMethod::TimeTablePerPointIncrementalSynchronised => {
197 TimeTablePerPointIncrementalPropagator::<Var, true>::new(
198 &self.tasks,
199 self.resource_capacity,
200 self.options.propagator_options,
201 self.constraint_tag,
202 )
203 .post(solver)
204 }
205 CumulativePropagationMethod::TimeTableOverInterval => {
206 TimeTableOverIntervalPropagator::new(
207 &self.tasks,
208 self.resource_capacity,
209 self.options.propagator_options,
210 self.constraint_tag,
211 )
212 .post(solver)
213 }
214 CumulativePropagationMethod::TimeTableOverIntervalIncremental => {
215 TimeTableOverIntervalIncrementalPropagator::<Var, false>::new(
216 &self.tasks,
217 self.resource_capacity,
218 self.options.propagator_options,
219 self.constraint_tag,
220 )
221 .post(solver)
222 }
223 CumulativePropagationMethod::TimeTableOverIntervalIncrementalSynchronised => {
224 TimeTableOverIntervalIncrementalPropagator::<Var, true>::new(
225 &self.tasks,
226 self.resource_capacity,
227 self.options.propagator_options,
228 self.constraint_tag,
229 )
230 .post(solver)
231 }
232 }
233 }
234
235 fn implied_by(
236 self,
237 solver: &mut Solver,
238 reification_literal: Literal,
239 ) -> Result<(), ConstraintOperationError> {
240 match self.options.propagation_method {
241 CumulativePropagationMethod::TimeTablePerPoint => TimeTablePerPointPropagator::new(
242 &self.tasks,
243 self.resource_capacity,
244 self.options.propagator_options,
245 self.constraint_tag,
246 )
247 .implied_by(solver, reification_literal),
248 CumulativePropagationMethod::TimeTablePerPointIncremental => {
249 TimeTablePerPointIncrementalPropagator::<Var, false>::new(
250 &self.tasks,
251 self.resource_capacity,
252 self.options.propagator_options,
253 self.constraint_tag,
254 )
255 .implied_by(solver, reification_literal)
256 }
257 CumulativePropagationMethod::TimeTablePerPointIncrementalSynchronised => {
258 TimeTablePerPointIncrementalPropagator::<Var, true>::new(
259 &self.tasks,
260 self.resource_capacity,
261 self.options.propagator_options,
262 self.constraint_tag,
263 )
264 .implied_by(solver, reification_literal)
265 }
266 CumulativePropagationMethod::TimeTableOverInterval => {
267 TimeTableOverIntervalPropagator::new(
268 &self.tasks,
269 self.resource_capacity,
270 self.options.propagator_options,
271 self.constraint_tag,
272 )
273 .implied_by(solver, reification_literal)
274 }
275 CumulativePropagationMethod::TimeTableOverIntervalIncremental => {
276 TimeTableOverIntervalIncrementalPropagator::<Var, false>::new(
277 &self.tasks,
278 self.resource_capacity,
279 self.options.propagator_options,
280 self.constraint_tag,
281 )
282 .implied_by(solver, reification_literal)
283 }
284 CumulativePropagationMethod::TimeTableOverIntervalIncrementalSynchronised => {
285 TimeTableOverIntervalIncrementalPropagator::<Var, true>::new(
286 &self.tasks,
287 self.resource_capacity,
288 self.options.propagator_options,
289 self.constraint_tag,
290 )
291 .implied_by(solver, reification_literal)
292 }
293 }
294 }
295}