use std::fmt::Debug;
use pumpkin_core::ConstraintOperationError;
use pumpkin_core::Solver;
use pumpkin_core::asserts::pumpkin_assert_simple;
use pumpkin_core::constraints::Constraint;
use pumpkin_core::proof::ConstraintTag;
use pumpkin_core::variables::IntegerVariable;
use pumpkin_core::variables::Literal;
use pumpkin_propagators::cumulative::ArgTask;
use pumpkin_propagators::cumulative::options::CumulativeOptions;
use pumpkin_propagators::cumulative::options::CumulativePropagationMethod;
use pumpkin_propagators::cumulative::time_table::TimeTableOverIntervalIncrementalPropagator;
use pumpkin_propagators::cumulative::time_table::TimeTableOverIntervalPropagator;
use pumpkin_propagators::cumulative::time_table::TimeTablePerPointIncrementalPropagator;
use pumpkin_propagators::cumulative::time_table::TimeTablePerPointPropagator;
pub fn cumulative<StartTimes, Durations, ResourceRequirements>(
start_times: StartTimes,
durations: Durations,
resource_requirements: ResourceRequirements,
resource_capacity: i32,
constraint_tag: ConstraintTag,
) -> impl Constraint
where
StartTimes: IntoIterator,
StartTimes::Item: IntegerVariable + Debug + 'static,
StartTimes::IntoIter: ExactSizeIterator,
Durations: IntoIterator<Item = i32>,
Durations::IntoIter: ExactSizeIterator,
ResourceRequirements: IntoIterator<Item = i32>,
ResourceRequirements::IntoIter: ExactSizeIterator,
{
cumulative_with_options(
start_times,
durations,
resource_requirements,
resource_capacity,
CumulativeOptions::default(),
constraint_tag,
)
}
pub fn cumulative_with_options<StartTimes, Durations, ResourceRequirements>(
start_times: StartTimes,
durations: Durations,
resource_requirements: ResourceRequirements,
resource_capacity: i32,
options: CumulativeOptions,
constraint_tag: ConstraintTag,
) -> impl Constraint
where
StartTimes: IntoIterator,
StartTimes::Item: IntegerVariable + Debug + 'static,
StartTimes::IntoIter: ExactSizeIterator,
Durations: IntoIterator<Item = i32>,
Durations::IntoIter: ExactSizeIterator,
ResourceRequirements: IntoIterator<Item = i32>,
ResourceRequirements::IntoIter: ExactSizeIterator,
{
let start_times = start_times.into_iter();
let durations = durations.into_iter();
let resource_requirements = resource_requirements.into_iter();
pumpkin_assert_simple!(
start_times.len() == durations.len() && durations.len() == resource_requirements.len(),
"The number of start variables, durations and resource requirements should be the same!"
);
CumulativeConstraint::new(
&start_times
.zip(durations)
.zip(resource_requirements)
.map(|((start_time, duration), resource_requirement)| ArgTask {
start_time,
processing_time: duration,
resource_usage: resource_requirement,
})
.collect::<Vec<_>>(),
resource_capacity,
options,
constraint_tag,
)
}
struct CumulativeConstraint<Var> {
tasks: Vec<ArgTask<Var>>,
resource_capacity: i32,
options: CumulativeOptions,
constraint_tag: ConstraintTag,
}
impl<Var: IntegerVariable + 'static> CumulativeConstraint<Var> {
fn new(
tasks: &[ArgTask<Var>],
resource_capacity: i32,
options: CumulativeOptions,
constraint_tag: ConstraintTag,
) -> Self {
Self {
tasks: tasks.into(),
resource_capacity,
options,
constraint_tag,
}
}
}
impl<Var: IntegerVariable + 'static + Debug> Constraint for CumulativeConstraint<Var> {
fn post(self, solver: &mut Solver) -> Result<(), ConstraintOperationError> {
match self.options.propagation_method {
CumulativePropagationMethod::TimeTablePerPoint => TimeTablePerPointPropagator::new(
&self.tasks,
self.resource_capacity,
self.options.propagator_options,
self.constraint_tag,
)
.post(solver),
CumulativePropagationMethod::TimeTablePerPointIncremental => {
TimeTablePerPointIncrementalPropagator::<Var, false>::new(
&self.tasks,
self.resource_capacity,
self.options.propagator_options,
self.constraint_tag,
)
.post(solver)
}
CumulativePropagationMethod::TimeTablePerPointIncrementalSynchronised => {
TimeTablePerPointIncrementalPropagator::<Var, true>::new(
&self.tasks,
self.resource_capacity,
self.options.propagator_options,
self.constraint_tag,
)
.post(solver)
}
CumulativePropagationMethod::TimeTableOverInterval => {
TimeTableOverIntervalPropagator::new(
&self.tasks,
self.resource_capacity,
self.options.propagator_options,
self.constraint_tag,
)
.post(solver)
}
CumulativePropagationMethod::TimeTableOverIntervalIncremental => {
TimeTableOverIntervalIncrementalPropagator::<Var, false>::new(
&self.tasks,
self.resource_capacity,
self.options.propagator_options,
self.constraint_tag,
)
.post(solver)
}
CumulativePropagationMethod::TimeTableOverIntervalIncrementalSynchronised => {
TimeTableOverIntervalIncrementalPropagator::<Var, true>::new(
&self.tasks,
self.resource_capacity,
self.options.propagator_options,
self.constraint_tag,
)
.post(solver)
}
}
}
fn implied_by(
self,
solver: &mut Solver,
reification_literal: Literal,
) -> Result<(), ConstraintOperationError> {
match self.options.propagation_method {
CumulativePropagationMethod::TimeTablePerPoint => TimeTablePerPointPropagator::new(
&self.tasks,
self.resource_capacity,
self.options.propagator_options,
self.constraint_tag,
)
.implied_by(solver, reification_literal),
CumulativePropagationMethod::TimeTablePerPointIncremental => {
TimeTablePerPointIncrementalPropagator::<Var, false>::new(
&self.tasks,
self.resource_capacity,
self.options.propagator_options,
self.constraint_tag,
)
.implied_by(solver, reification_literal)
}
CumulativePropagationMethod::TimeTablePerPointIncrementalSynchronised => {
TimeTablePerPointIncrementalPropagator::<Var, true>::new(
&self.tasks,
self.resource_capacity,
self.options.propagator_options,
self.constraint_tag,
)
.implied_by(solver, reification_literal)
}
CumulativePropagationMethod::TimeTableOverInterval => {
TimeTableOverIntervalPropagator::new(
&self.tasks,
self.resource_capacity,
self.options.propagator_options,
self.constraint_tag,
)
.implied_by(solver, reification_literal)
}
CumulativePropagationMethod::TimeTableOverIntervalIncremental => {
TimeTableOverIntervalIncrementalPropagator::<Var, false>::new(
&self.tasks,
self.resource_capacity,
self.options.propagator_options,
self.constraint_tag,
)
.implied_by(solver, reification_literal)
}
CumulativePropagationMethod::TimeTableOverIntervalIncrementalSynchronised => {
TimeTableOverIntervalIncrementalPropagator::<Var, true>::new(
&self.tasks,
self.resource_capacity,
self.options.propagator_options,
self.constraint_tag,
)
.implied_by(solver, reification_literal)
}
}
}
}