diff --git a/pumpkin-crates/propagators/src/propagators/cumulative/time_table/over_interval_incremental_propagator/time_table_over_interval_incremental.rs b/pumpkin-crates/propagators/src/propagators/cumulative/time_table/over_interval_incremental_propagator/time_table_over_interval_incremental.rs index be07bbb5d..718e9ac0f 100644 --- a/pumpkin-crates/propagators/src/propagators/cumulative/time_table/over_interval_incremental_propagator/time_table_over_interval_incremental.rs +++ b/pumpkin-crates/propagators/src/propagators/cumulative/time_table/over_interval_incremental_propagator/time_table_over_interval_incremental.rs @@ -461,13 +461,7 @@ impl Propagator // // However, this could mean that we potentially enqueue even though the time-table is empty // after backtracking but has not been recalculated yet. - let result = should_enqueue( - &self.parameters, - &self.updatable_structures, - &updated_task, - context.domains(), - self.time_table.is_empty(), - ); + let result = should_enqueue(&self.updatable_structures, &updated_task, context.domains()); // If there is a task which now has a mandatory part then we store it and process it when // the `propagate` method is called diff --git a/pumpkin-crates/propagators/src/propagators/cumulative/time_table/per_point_incremental_propagator/time_table_per_point_incremental.rs b/pumpkin-crates/propagators/src/propagators/cumulative/time_table/per_point_incremental_propagator/time_table_per_point_incremental.rs index 34d9e8e3b..b2882d358 100644 --- a/pumpkin-crates/propagators/src/propagators/cumulative/time_table/per_point_incremental_propagator/time_table_per_point_incremental.rs +++ b/pumpkin-crates/propagators/src/propagators/cumulative/time_table/per_point_incremental_propagator/time_table_per_point_incremental.rs @@ -488,13 +488,7 @@ impl Propagator // // However, this could mean that we potentially enqueue even though the time-table is empty // after backtracking but has not been recalculated yet. - let result = should_enqueue( - &self.parameters, - &self.updatable_structures, - &updated_task, - context.domains(), - self.time_table.is_empty(), - ); + let result = should_enqueue(&self.updatable_structures, &updated_task, context.domains()); // If there is a task which now has a mandatory part then we store it and process it when // the `propagate` method is called diff --git a/pumpkin-crates/propagators/src/propagators/cumulative/time_table/time_table_over_interval.rs b/pumpkin-crates/propagators/src/propagators/cumulative/time_table/time_table_over_interval.rs index 00b841972..827e24656 100644 --- a/pumpkin-crates/propagators/src/propagators/cumulative/time_table/time_table_over_interval.rs +++ b/pumpkin-crates/propagators/src/propagators/cumulative/time_table/time_table_over_interval.rs @@ -67,8 +67,6 @@ pub(crate) struct Event { /// Computer Science and Software Engineering, 2011. #[derive(Debug, Clone)] pub struct TimeTableOverIntervalPropagator { - /// Stores whether the time-table is empty - is_time_table_empty: bool, /// Stores the input parameters to the cumulative constraint parameters: CumulativeParameters, /// Stores structures which change during the search; used to store the bounds @@ -97,7 +95,6 @@ impl TimeTableOverIntervalPropagator { let updatable_structures = UpdatableStructures::new(¶meters); TimeTableOverIntervalPropagator { - is_time_table_empty: true, parameters, updatable_structures, constraint_tag, @@ -159,7 +156,6 @@ impl Propagator for TimeTableOverIntervalPropaga &self.parameters, self.inference_code.as_ref().unwrap(), )?; - self.is_time_table_empty = time_table.is_empty(); // No error has been found -> Check for updates (i.e. go over all profiles and all tasks and // check whether an update can take place) propagate_based_on_timetable( @@ -183,18 +179,8 @@ impl Propagator for TimeTableOverIntervalPropaga event: OpaqueDomainEvent, ) -> EnqueueDecision { let updated_task = Rc::clone(&self.parameters.tasks[local_id.unpack() as usize]); - // Note that it could be the case that `is_time_table_empty` is inaccurate here since it - // wasn't updated in `synchronise`; however, `synchronise` will only remove profiles - // meaning that `is_time_table_empty` will always return `false` when it is not - // empty and it might return `false` even when the time-table is not empty *but* it - // will never return `true` when the time-table is not empty. - let result = should_enqueue( - &self.parameters, - &self.updatable_structures, - &updated_task, - context.domains(), - self.is_time_table_empty, - ); + + let result = should_enqueue(&self.updatable_structures, &updated_task, context.domains()); update_bounds_task( context.domains(), diff --git a/pumpkin-crates/propagators/src/propagators/cumulative/time_table/time_table_per_point.rs b/pumpkin-crates/propagators/src/propagators/cumulative/time_table/time_table_per_point.rs index cabed34c0..dba245989 100644 --- a/pumpkin-crates/propagators/src/propagators/cumulative/time_table/time_table_per_point.rs +++ b/pumpkin-crates/propagators/src/propagators/cumulative/time_table/time_table_per_point.rs @@ -56,8 +56,6 @@ use crate::propagators::cumulative::time_table::propagation_handler::create_conf /// Computer Science and Software Engineering, 2011. #[derive(Debug, Clone)] pub struct TimeTablePerPointPropagator { - /// Stores whether the time-table is empty - is_time_table_empty: bool, /// Stores the input parameters to the cumulative constraint parameters: CumulativeParameters, /// Stores structures which change during the search; used to store the bounds @@ -89,7 +87,6 @@ impl TimeTablePerPointPropagator { let updatable_structures = UpdatableStructures::new(¶meters); TimeTablePerPointPropagator { - is_time_table_empty: true, parameters, updatable_structures, constraint_tag, @@ -149,7 +146,6 @@ impl Propagator for TimeTablePerPointPropagator< self.inference_code.as_ref().unwrap(), &self.parameters, )?; - self.is_time_table_empty = time_table.is_empty(); // No error has been found -> Check for updates (i.e. go over all profiles and all tasks and // check whether an update can take place) propagate_based_on_timetable( @@ -173,18 +169,8 @@ impl Propagator for TimeTablePerPointPropagator< event: OpaqueDomainEvent, ) -> EnqueueDecision { let updated_task = Rc::clone(&self.parameters.tasks[local_id.unpack() as usize]); - // Note that it could be the case that `is_time_table_empty` is inaccurate here since it - // wasn't updated in `synchronise`; however, `synchronise` will only remove profiles - // meaning that `is_time_table_empty` will always return `false` when it is not - // empty and it might return `false` even when the time-table is not empty *but* it - // will never return `true` when the time-table is not empty. - let result = should_enqueue( - &self.parameters, - &self.updatable_structures, - &updated_task, - context.domains(), - self.is_time_table_empty, - ); + + let result = should_enqueue(&self.updatable_structures, &updated_task, context.domains()); // Note that the non-incremental proapgator does not make use of `result.updated` since it // propagates from scratch anyways diff --git a/pumpkin-crates/propagators/src/propagators/cumulative/time_table/time_table_util.rs b/pumpkin-crates/propagators/src/propagators/cumulative/time_table/time_table_util.rs index 3328db381..0971530ef 100644 --- a/pumpkin-crates/propagators/src/propagators/cumulative/time_table/time_table_util.rs +++ b/pumpkin-crates/propagators/src/propagators/cumulative/time_table/time_table_util.rs @@ -40,11 +40,9 @@ pub(crate) struct ShouldEnqueueResult { /// such task exists). This method should be called in the /// [`ConstraintProgrammingPropagator::notify`] method. pub(crate) fn should_enqueue( - parameters: &CumulativeParameters, updatable_structures: &UpdatableStructures, updated_task: &Rc>, mut context: Domains, - empty_time_table: bool, ) -> ShouldEnqueueResult { pumpkin_assert_extreme!( context.lower_bound(&updated_task.start_variable) @@ -79,28 +77,8 @@ pub(crate) fn should_enqueue( }); } - result.decision = if parameters.options.allow_holes_in_domain { - // If there are updates then propagations might occur due to new mandatory parts being - // added. However, if there are no updates then because we allow holes in the domain, no - // updates can occur so we can skip propagation! - if updatable_structures.has_updates() || result.update.is_some() { - EnqueueDecision::Enqueue - } else { - EnqueueDecision::Skip - } - } else { - // If the time-table is empty and we have not received any updates (e.g. no mandatory parts - // have been introduced since the last propagation) then we can determine that no - // propagation will take place. It is not sufficient to check whether there have - // been no updates since it could be the case that a task which has been updated can - // now propagate due to an existing profile (this is due to the fact that we only - // propagate bounds and (currently) do not create holes in the domain!). - if !empty_time_table || updatable_structures.has_updates() || result.update.is_some() { - EnqueueDecision::Enqueue - } else { - EnqueueDecision::Skip - } - }; + result.decision = EnqueueDecision::Enqueue; + result } @@ -201,7 +179,7 @@ fn debug_check_whether_profiles_are_maximal_and_sorted<'a, Var: IntegerVariable pub(crate) fn propagate_based_on_timetable<'a, Var: IntegerVariable + 'static>( context: &mut PropagationContext, inference_code: &InferenceCode, - time_table: impl Iterator> + Clone, + time_table: impl ExactSizeIterator> + Clone, parameters: &CumulativeParameters, updatable_structures: &mut UpdatableStructures, ) -> PropagationStatusCP { @@ -223,6 +201,11 @@ pub(crate) fn propagate_based_on_timetable<'a, Var: IntegerVariable + 'static>( "All of the fixed tasks should be fixed at this point" ); + if time_table.len() == 0 { + // No propagation can take place since the time-table is empty + return Ok(()); + } + if parameters.options.generate_sequence { propagate_sequence_of_profiles( context, diff --git a/pumpkin-crates/propagators/src/propagators/cumulative/utils/structs/updatable_structures.rs b/pumpkin-crates/propagators/src/propagators/cumulative/utils/structs/updatable_structures.rs index 314271ba4..26afaefc0 100644 --- a/pumpkin-crates/propagators/src/propagators/cumulative/utils/structs/updatable_structures.rs +++ b/pumpkin-crates/propagators/src/propagators/cumulative/utils/structs/updatable_structures.rs @@ -46,11 +46,6 @@ impl UpdatableStructures { } } - /// Returns whether there are any updates stored which have not been processed - pub(crate) fn has_updates(&self) -> bool { - !self.updated_tasks.is_empty() - } - /// Returns the next updated task and removes it from the updated list pub(crate) fn pop_next_updated_task(&mut self) -> Option>> { if self.updated_tasks.is_empty() {