use std::rc::Rc;
use pumpkin_core::asserts::pumpkin_assert_moderate;
use pumpkin_core::containers::SparseSet;
use pumpkin_core::propagation::Domains;
use pumpkin_core::propagation::ReadDomains;
use pumpkin_core::variables::IntegerVariable;
use super::CumulativeParameters;
use super::Task;
use super::UpdatedTaskInfo;
#[derive(Debug, Clone)]
pub(crate) struct UpdatableStructures<Var> {
bounds: Vec<(i32, i32)>,
updates: Vec<UpdatedTaskInfo<Var>>,
updated_tasks: SparseSet<Rc<Task<Var>>>,
unfixed_tasks: SparseSet<Rc<Task<Var>>>,
}
impl<Var: IntegerVariable + 'static> UpdatableStructures<Var> {
pub(crate) fn new(parameters: &CumulativeParameters<Var>) -> Self {
let mut updated_tasks = SparseSet::new_with_mapping(parameters.tasks.to_vec(), |element| {
Task::get_id(element) as i32
});
updated_tasks.set_to_empty();
let unfixed_tasks = SparseSet::new_with_mapping(parameters.tasks.to_vec(), |element| {
Task::get_id(element) as i32
});
Self {
bounds: vec![],
updates: vec![],
updated_tasks,
unfixed_tasks,
}
}
pub(crate) fn has_updates(&self) -> bool {
!self.updated_tasks.is_empty()
}
pub(crate) fn pop_next_updated_task(&mut self) -> Option<Rc<Task<Var>>> {
if self.updated_tasks.is_empty() {
return None;
}
let updated_task = Rc::clone(self.updated_tasks.get(0));
self.updated_tasks.remove(&updated_task);
Some(updated_task)
}
pub(crate) fn get_update_for_task(
&mut self,
updated_task: &Rc<Task<Var>>,
) -> UpdatedTaskInfo<Var> {
self.updates[updated_task.id.unpack() as usize].clone()
}
pub(crate) fn reset_update_for_task(&mut self, updated_task: &Rc<Task<Var>>) {
let update = &mut self.updates[updated_task.id.unpack() as usize];
update.old_lower_bound = update.new_lower_bound;
update.old_upper_bound = update.new_upper_bound;
}
pub(crate) fn get_stored_bounds(&self) -> &[(i32, i32)] {
&self.bounds
}
pub(crate) fn get_stored_bounds_mut(&mut self) -> &mut [(i32, i32)] {
&mut self.bounds
}
pub(crate) fn get_stored_lower_bound(&self, task: &Rc<Task<Var>>) -> i32 {
self.bounds[task.id.unpack() as usize].0
}
pub(crate) fn get_stored_upper_bound(&self, task: &Rc<Task<Var>>) -> i32 {
self.bounds[task.id.unpack() as usize].1
}
pub(crate) fn fix_task(&mut self, updated_task: &Rc<Task<Var>>) {
self.unfixed_tasks.remove(updated_task);
}
pub(crate) fn unfix_task(&mut self, updated_task: Rc<Task<Var>>) {
self.unfixed_tasks.insert(updated_task);
}
pub(crate) fn remove_fixed(
&mut self,
context: Domains,
parameters: &CumulativeParameters<Var>,
) {
for task in parameters.tasks.iter() {
if context.is_fixed(&task.start_variable) {
self.unfixed_tasks.remove(task);
} else {
self.unfixed_tasks.insert(Rc::clone(task));
}
}
}
pub(crate) fn reset_all_bounds_and_remove_fixed(
&mut self,
context: Domains,
parameters: &CumulativeParameters<Var>,
) {
for task in parameters.tasks.iter() {
if self.updates.len() <= task.id.unpack() as usize {
pumpkin_assert_moderate!(task.id.unpack() as usize == self.updates.len());
self.updates.push(UpdatedTaskInfo {
task: Rc::clone(task),
old_lower_bound: context.lower_bound(&task.start_variable),
old_upper_bound: context.upper_bound(&task.start_variable),
new_lower_bound: context.lower_bound(&task.start_variable),
new_upper_bound: context.upper_bound(&task.start_variable),
});
} else {
let update = &mut self.updates[task.id.unpack() as usize];
update.new_lower_bound = context.lower_bound(&task.start_variable);
update.new_upper_bound = context.upper_bound(&task.start_variable);
update.old_lower_bound = context.lower_bound(&task.start_variable);
update.old_upper_bound = context.upper_bound(&task.start_variable);
}
if self.bounds.len() <= task.id.unpack() as usize {
pumpkin_assert_moderate!(task.id.unpack() as usize == self.bounds.len());
self.bounds.push((
context.lower_bound(&task.start_variable),
context.upper_bound(&task.start_variable),
));
} else {
self.bounds[task.id.unpack() as usize] = (
context.lower_bound(&task.start_variable),
context.upper_bound(&task.start_variable),
);
}
if context.is_fixed(&task.start_variable) {
self.unfixed_tasks.remove(task);
} else {
self.unfixed_tasks.insert(Rc::clone(task));
}
}
}
pub(crate) fn initialise_bounds_and_remove_fixed(
&mut self,
context: Domains,
parameters: &CumulativeParameters<Var>,
) {
for task in parameters.tasks.iter() {
self.bounds.push((
context.lower_bound(&task.start_variable),
context.upper_bound(&task.start_variable),
));
if context.is_fixed(&task.start_variable) {
self.fix_task(task);
}
}
}
pub(crate) fn get_unfixed_tasks(&self) -> impl Iterator<Item = &Rc<Task<Var>>> {
self.unfixed_tasks.iter()
}
pub(crate) fn get_fixed_tasks(&self) -> impl Iterator<Item = &Rc<Task<Var>>> {
self.unfixed_tasks.out_of_domain()
}
pub(crate) fn number_of_unfixed_tasks(&self) -> usize {
self.unfixed_tasks.len()
}
pub(crate) fn has_no_unfixed_tasks(&self) -> bool {
self.unfixed_tasks.is_empty()
}
pub(crate) fn temporarily_remove_task_from_unfixed(&mut self, task: &Rc<Task<Var>>) {
self.unfixed_tasks.remove_temporarily(task)
}
pub(crate) fn restore_temporarily_removed(&mut self) {
self.unfixed_tasks.restore_temporarily_removed()
}
pub(crate) fn get_unfixed_task_at_index(&self, index: usize) -> Rc<Task<Var>> {
Rc::clone(self.unfixed_tasks.get(index))
}
pub(crate) fn task_has_been_updated(&mut self, task: &Rc<Task<Var>>) {
self.updated_tasks.insert(Rc::clone(task))
}
pub(crate) fn insert_update_for_task(
&mut self,
task: &Rc<Task<Var>>,
updated_task_info: UpdatedTaskInfo<Var>,
) {
let stored_updated_task_info = &mut self.updates[task.id.unpack() as usize];
stored_updated_task_info.new_lower_bound = updated_task_info.new_lower_bound;
stored_updated_task_info.new_upper_bound = updated_task_info.new_upper_bound;
}
pub(crate) fn recreate_from_context(
&self,
context: Domains,
parameters: &CumulativeParameters<Var>,
) -> Self {
let mut other = self.clone();
parameters
.tasks
.iter()
.for_each(|task| other.unfix_task(Rc::clone(task)));
other.reset_all_bounds_and_remove_fixed(context, parameters);
other
}
}