pub(crate) mod big_step;
pub(crate) mod naive;
pub(crate) mod pointwise;
use std::fmt::Display;
use std::rc::Rc;
use big_step::create_big_step_predicate_propagating_task_lower_bound_propagation;
use big_step::create_big_step_predicate_propagating_task_upper_bound_propagation;
use naive::create_naive_predicate_propagating_task_lower_bound_propagation;
use naive::create_naive_predicate_propagating_task_upper_bound_propagation;
use pointwise::create_pointwise_predicate_propagating_task_lower_bound_propagation;
use pointwise::create_pointwise_predicate_propagating_task_upper_bound_propagation;
use pumpkin_core::predicates::Predicate;
use pumpkin_core::propagation::Domains;
use pumpkin_core::variables::IntegerVariable;
use crate::cumulative::ResourceProfile;
use crate::cumulative::Task;
#[derive(Debug, Clone, Copy, Default)]
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
pub enum CumulativeExplanationType {
Naive,
BigStep,
#[default]
Pointwise,
}
impl Display for CumulativeExplanationType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
CumulativeExplanationType::Naive => write!(f, "naive"),
CumulativeExplanationType::BigStep => write!(f, "big-step"),
CumulativeExplanationType::Pointwise => write!(f, "pointwise"),
}
}
}
pub(crate) fn get_minimal_profile<Var: IntegerVariable + 'static, ConversionFunction>(
profile: &ResourceProfile<Var>,
convert_to_predicate: ConversionFunction,
capacity: i32,
propagating_task_usage: Option<i32>,
) -> impl Iterator<Item = Predicate>
where
ConversionFunction: Fn(&Task<Var>) -> [Predicate; 2],
{
let mut minimal_height = profile.height + propagating_task_usage.unwrap_or_default();
profile
.profile_tasks
.iter()
.filter_map(move |task| {
if minimal_height - task.resource_usage > capacity {
minimal_height -= task.resource_usage;
None
} else {
Some(convert_to_predicate(task))
}
})
.flatten()
}
pub(crate) fn create_predicate_propagating_task_lower_bound_propagation<
Var: IntegerVariable + 'static,
>(
explanation_type: CumulativeExplanationType,
context: Domains,
task: &Rc<Task<Var>>,
profile: &ResourceProfile<Var>,
time_point: Option<i32>,
) -> Predicate {
match explanation_type {
CumulativeExplanationType::Naive => {
create_naive_predicate_propagating_task_lower_bound_propagation(context, task)
}
CumulativeExplanationType::BigStep => {
create_big_step_predicate_propagating_task_lower_bound_propagation(task, profile)
}
CumulativeExplanationType::Pointwise => {
create_pointwise_predicate_propagating_task_lower_bound_propagation(task, time_point)
}
}
}
pub(crate) fn add_propagating_task_predicate_lower_bound<Var: IntegerVariable + 'static>(
explanation: impl Iterator<Item = Predicate>,
explanation_type: CumulativeExplanationType,
context: Domains,
task: &Rc<Task<Var>>,
profile: &ResourceProfile<Var>,
time_point: Option<i32>,
) -> impl Iterator<Item = Predicate> {
explanation.chain(std::iter::once(
create_predicate_propagating_task_lower_bound_propagation(
explanation_type,
context,
task,
profile,
time_point,
),
))
}
pub(crate) fn create_predicate_propagating_task_upper_bound_propagation<
Var: IntegerVariable + 'static,
>(
explanation_type: CumulativeExplanationType,
context: Domains,
task: &Rc<Task<Var>>,
profile: &ResourceProfile<Var>,
time_point: Option<i32>,
) -> Predicate {
match explanation_type {
CumulativeExplanationType::Naive => {
create_naive_predicate_propagating_task_upper_bound_propagation(context, task)
}
CumulativeExplanationType::BigStep => {
create_big_step_predicate_propagating_task_upper_bound_propagation(
task, profile, context,
)
}
CumulativeExplanationType::Pointwise => {
create_pointwise_predicate_propagating_task_upper_bound_propagation(task, time_point)
}
}
}
pub(crate) fn add_propagating_task_predicate_upper_bound<Var: IntegerVariable + 'static>(
explanation: impl Iterator<Item = Predicate>,
explanation_type: CumulativeExplanationType,
context: Domains,
task: &Rc<Task<Var>>,
profile: &ResourceProfile<Var>,
time_point: Option<i32>,
) -> impl Iterator<Item = Predicate> {
explanation.chain(std::iter::once(
create_predicate_propagating_task_upper_bound_propagation(
explanation_type,
context,
task,
profile,
time_point,
),
))
}
#[cfg(test)]
mod tests {
use std::rc::Rc;
use pumpkin_core::predicates::Predicate;
use pumpkin_core::propagation::LocalId;
use pumpkin_core::state::State;
use crate::cumulative::ResourceProfile;
use crate::cumulative::Task;
use crate::cumulative::time_table::explanations::get_minimal_profile;
#[test]
fn test_minimal_conflict_returned() {
let mut state = State::default();
let profile = ResourceProfile {
start: 5,
end: 10,
profile_tasks: vec![
Rc::new(Task {
start_variable: state.new_interval_variable(5, 5, None),
processing_time: 6,
resource_usage: 5,
id: LocalId::from(0),
}),
Rc::new(Task {
start_variable: state.new_interval_variable(5, 5, None),
processing_time: 6,
resource_usage: 1,
id: LocalId::from(1),
}),
Rc::new(Task {
start_variable: state.new_interval_variable(5, 5, None),
processing_time: 6,
resource_usage: 2,
id: LocalId::from(2),
}),
Rc::new(Task {
start_variable: state.new_interval_variable(5, 5, None),
processing_time: 6,
resource_usage: 4,
id: LocalId::from(3),
}),
],
height: 12,
};
let minimal_profile = get_minimal_profile(
&profile,
|_| [Predicate::trivially_true(), Predicate::trivially_true()],
9,
Some(1),
);
assert_eq!(minimal_profile.count() / 2, 2);
}
#[test]
fn test_does_not_remove_both() {
let mut state = State::default();
let profile = ResourceProfile {
start: 5,
end: 10,
profile_tasks: vec![
Rc::new(Task {
start_variable: state.new_interval_variable(5, 5, None),
processing_time: 6,
resource_usage: 1,
id: LocalId::from(1),
}),
Rc::new(Task {
start_variable: state.new_interval_variable(5, 5, None),
processing_time: 6,
resource_usage: 1,
id: LocalId::from(2),
}),
Rc::new(Task {
start_variable: state.new_interval_variable(5, 5, None),
processing_time: 6,
resource_usage: 4,
id: LocalId::from(3),
}),
],
height: 6,
};
let minimal_profile = get_minimal_profile(
&profile,
|_| [Predicate::trivially_true(), Predicate::trivially_true()],
4,
None,
);
assert_eq!(minimal_profile.count() / 2, 2);
}
}