From a5360610f6636a0012c1e949c846728ba27f0044 Mon Sep 17 00:00:00 2001 From: Maarten Flippo Date: Fri, 12 Dec 2025 14:35:55 +0100 Subject: [PATCH 01/29] refactor(pumpkin-core): Make propagator module public --- pumpkin-crates/core/src/api/mod.rs | 4 +- pumpkin-crates/core/src/api/solver.rs | 6 +- pumpkin-crates/core/src/basic_types/mod.rs | 2 +- .../predicate_id_generators/mod.rs | 2 +- .../predicate_id_generator.rs | 3 +- .../core/src/basic_types/solution.rs | 32 +++--- .../src/basic_types/stored_conflict_info.rs | 4 +- .../alternating/strategies/until_solution.rs | 8 +- .../branching/branchers/autonomous_search.rs | 1 + .../core/src/branching/selection_context.rs | 4 +- pumpkin-crates/core/src/constraints/mod.rs | 2 +- .../conflict_analysis_context.rs | 4 +- .../minimisers/recursive_minimiser.rs | 5 +- .../resolvers/resolution_resolver.rs | 2 +- .../engine/constraint_satisfaction_solver.rs | 4 +- pumpkin-crates/core/src/engine/cp/mod.rs | 5 +- .../src/engine/cp/propagation/contexts/mod.rs | 4 - .../core/src/engine/cp/propagator_queue.rs | 2 +- pumpkin-crates/core/src/engine/cp/reason.rs | 6 +- .../core/src/engine/cp/test_helper.rs | 16 +-- .../core/src/engine/cp/test_solver.rs | 12 +-- .../core/src/engine/debug_helper.rs | 10 +- pumpkin-crates/core/src/engine/mod.rs | 2 - .../domain_event_watch_list.rs | 2 +- .../domain_events.rs | 13 ++- .../domain_event_notification/event_sink.rs | 4 +- .../domain_event_notification/mod.rs | 2 +- .../core/src/engine/notifications/mod.rs | 18 ++-- pumpkin-crates/core/src/engine/state.rs | 28 ++--- pumpkin-crates/core/src/lib.rs | 3 +- pumpkin-crates/core/src/proof/finalizer.rs | 2 +- .../cp => }/propagation/constructor.rs | 27 ++--- .../contexts/explanation_context.rs | 20 ++-- .../core/src/propagation/contexts/mod.rs | 5 + .../contexts/propagation_context.rs | 102 +++++++++++++----- .../{engine/cp => }/propagation/local_id.rs | 6 +- .../src/{engine/cp => }/propagation/mod.rs | 53 +++++---- .../{engine/cp => }/propagation/propagator.rs | 44 ++++---- .../cp => }/propagation/propagator_id.rs | 0 .../cp => }/propagation/propagator_var_id.rs | 4 +- .../src/{engine/cp => }/propagation/store.rs | 0 .../propagators/arithmetic/absolute_value.rs | 14 +-- .../arithmetic/binary/binary_equals.rs | 24 ++--- .../arithmetic/binary/binary_not_equals.rs | 18 ++-- .../arithmetic/integer_division.rs | 14 +-- .../arithmetic/integer_multiplication.rs | 14 +-- .../arithmetic/linear_less_or_equal.rs | 24 ++--- .../arithmetic/linear_not_equal.rs | 20 ++-- .../src/propagators/arithmetic/maximum.rs | 14 +-- .../time_table/explanations/big_step.rs | 4 +- .../cumulative/time_table/explanations/mod.rs | 2 +- .../time_table/explanations/naive.rs | 4 +- .../time_table/explanations/pointwise.rs | 9 +- .../debug.rs | 2 +- .../synchronisation.rs | 4 +- .../time_table_over_interval_incremental.rs | 18 ++-- .../synchronisation.rs | 4 +- .../time_table_per_point_incremental.rs | 20 ++-- .../time_table/propagation_handler.rs | 20 ++-- .../time_table/time_table_over_interval.rs | 20 ++-- .../time_table/time_table_per_point.rs | 20 ++-- .../cumulative/time_table/time_table_util.rs | 16 +-- .../cumulative/utils/structs/task.rs | 2 +- .../utils/structs/updatable_structures.rs | 4 +- .../src/propagators/cumulative/utils/util.rs | 10 +- .../disjunctive/disjunctive_propagator.rs | 14 +-- .../disjunctive/disjunctive_task.rs | 2 +- .../disjunctive/theta_lambda_tree.rs | 10 +- .../src/propagators/disjunctive/theta_tree.rs | 6 +- .../core/src/propagators/element.rs | 16 +-- pumpkin-crates/core/src/propagators/mod.rs | 4 +- .../propagators/nogoods/nogood_propagator.rs | 18 ++-- .../src/propagators/reified_propagator.rs | 22 ++-- .../core/src/statistics/statistic_logger.rs | 2 +- 74 files changed, 454 insertions(+), 414 deletions(-) delete mode 100644 pumpkin-crates/core/src/engine/cp/propagation/contexts/mod.rs rename pumpkin-crates/core/src/{engine/cp => }/propagation/constructor.rs (93%) rename pumpkin-crates/core/src/{engine/cp => }/propagation/contexts/explanation_context.rs (89%) create mode 100644 pumpkin-crates/core/src/propagation/contexts/mod.rs rename pumpkin-crates/core/src/{engine/cp => }/propagation/contexts/propagation_context.rs (83%) rename pumpkin-crates/core/src/{engine/cp => }/propagation/local_id.rs (84%) rename pumpkin-crates/core/src/{engine/cp => }/propagation/mod.rs (70%) rename pumpkin-crates/core/src/{engine/cp => }/propagation/propagator.rs (80%) rename pumpkin-crates/core/src/{engine/cp => }/propagation/propagator_id.rs (100%) rename pumpkin-crates/core/src/{engine/cp => }/propagation/propagator_var_id.rs (71%) rename pumpkin-crates/core/src/{engine/cp => }/propagation/store.rs (100%) diff --git a/pumpkin-crates/core/src/api/mod.rs b/pumpkin-crates/core/src/api/mod.rs index eee7cf34c..9973e073b 100644 --- a/pumpkin-crates/core/src/api/mod.rs +++ b/pumpkin-crates/core/src/api/mod.rs @@ -128,8 +128,8 @@ pub mod state { pub use crate::engine::EmptyDomain; pub use crate::engine::EmptyDomainConflict; pub use crate::engine::State; - pub use crate::engine::propagation::CurrentNogood; - pub use crate::engine::propagation::PropagatorId; + pub use crate::propagation::CurrentNogood; + pub use crate::propagation::PropagatorId; } pub use crate::basic_types::Function; diff --git a/pumpkin-crates/core/src/api/solver.rs b/pumpkin-crates/core/src/api/solver.rs index f05cb13a6..9278963f9 100644 --- a/pumpkin-crates/core/src/api/solver.rs +++ b/pumpkin-crates/core/src/api/solver.rs @@ -19,8 +19,6 @@ use crate::constraints::ConstraintPoster; use crate::containers::HashSet; use crate::engine::ConstraintSatisfactionSolver; use crate::engine::predicates::predicate::Predicate; -use crate::engine::propagation::constructor::PropagatorConstructor; -pub use crate::engine::propagation::store::PropagatorHandle; use crate::engine::termination::TerminationCondition; use crate::engine::variables::DomainId; use crate::engine::variables::IntegerVariable; @@ -35,6 +33,8 @@ use crate::options::SolverOptions; #[cfg(doc)] use crate::predicates; use crate::proof::ConstraintTag; +use crate::propagation::PropagatorConstructor; +pub use crate::propagation::store::PropagatorHandle; use crate::results::solution_iterator::SolutionIterator; use crate::results::unsatisfiable::UnsatisfiableUnderAssumptions; use crate::statistics::StatisticLogger; @@ -495,7 +495,7 @@ impl Solver { /// If the solver is already in a conflicting state, i.e. a previous call to this method /// already returned `false`, calling this again will not alter the solver in any way, and /// `false` will be returned again. - pub(crate) fn add_propagator( + pub fn add_propagator( &mut self, constructor: Constructor, ) -> Result, ConstraintOperationError> diff --git a/pumpkin-crates/core/src/basic_types/mod.rs b/pumpkin-crates/core/src/basic_types/mod.rs index 2cfe340ea..7635e9519 100644 --- a/pumpkin-crates/core/src/basic_types/mod.rs +++ b/pumpkin-crates/core/src/basic_types/mod.rs @@ -16,7 +16,7 @@ pub use constraint_operation_error::ConstraintOperationError; pub(crate) use csp_solver_execution_flag::CSPSolverExecutionFlag; pub use function::Function; pub(crate) use predicate_id_generators::DeletablePredicateIdGenerator; -pub(crate) use predicate_id_generators::PredicateId; +pub use predicate_id_generators::PredicateId; pub(crate) use predicate_id_generators::PredicateIdGenerator; pub use propagation_status_cp::*; pub use propositional_conjunction::PropositionalConjunction; diff --git a/pumpkin-crates/core/src/basic_types/predicate_id_generators/mod.rs b/pumpkin-crates/core/src/basic_types/predicate_id_generators/mod.rs index 674469ad6..535ce4d21 100644 --- a/pumpkin-crates/core/src/basic_types/predicate_id_generators/mod.rs +++ b/pumpkin-crates/core/src/basic_types/predicate_id_generators/mod.rs @@ -2,5 +2,5 @@ mod deletable_predicate_id_generator; mod predicate_id_generator; pub(crate) use deletable_predicate_id_generator::DeletablePredicateIdGenerator; -pub(crate) use predicate_id_generator::PredicateId; +pub use predicate_id_generator::PredicateId; pub(crate) use predicate_id_generator::PredicateIdGenerator; diff --git a/pumpkin-crates/core/src/basic_types/predicate_id_generators/predicate_id_generator.rs b/pumpkin-crates/core/src/basic_types/predicate_id_generators/predicate_id_generator.rs index cb4fd3b75..303452d95 100644 --- a/pumpkin-crates/core/src/basic_types/predicate_id_generators/predicate_id_generator.rs +++ b/pumpkin-crates/core/src/basic_types/predicate_id_generators/predicate_id_generator.rs @@ -104,8 +104,9 @@ impl Iterator for PredicateIdIterator { } } +/// An ID for a predicate which has its truth-value tracked by the solver. #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd)] -pub(crate) struct PredicateId { +pub struct PredicateId { pub(crate) id: u32, } diff --git a/pumpkin-crates/core/src/basic_types/solution.rs b/pumpkin-crates/core/src/basic_types/solution.rs index f6242b2f1..ded8bf5d3 100644 --- a/pumpkin-crates/core/src/basic_types/solution.rs +++ b/pumpkin-crates/core/src/basic_types/solution.rs @@ -1,13 +1,21 @@ use crate::engine::Assignments; -use crate::engine::propagation::contexts::HasAssignments; use crate::engine::variables::DomainGeneratorIterator; use crate::engine::variables::DomainId; use crate::engine::variables::Literal; -use crate::predicates::Predicate; +use crate::propagation::HasAssignments; use crate::variables::IntegerVariable; /// A trait which specifies the common behaviours of [`Solution`] and [`SolutionReference`]. -pub trait ProblemSolution: HasAssignments { +pub trait ProblemSolution { + /// Returns the number of defined [`DomainId`]s. + fn num_domains(&self) -> usize; + + fn get_integer_value(&self, var: Var) -> i32; + + fn get_literal_value(&self, literal: Literal) -> bool; +} + +impl ProblemSolution for T { /// Returns the number of defined [`DomainId`]s. fn num_domains(&self) -> usize { self.assignments().num_domains() as usize @@ -33,7 +41,7 @@ pub struct SolutionReference<'a> { } impl<'a> SolutionReference<'a> { - pub fn new(assignments: &'a Assignments) -> SolutionReference<'a> { + pub(crate) fn new(assignments: &'a Assignments) -> SolutionReference<'a> { SolutionReference { assignments } } @@ -43,19 +51,15 @@ impl<'a> SolutionReference<'a> { } } -impl ProblemSolution for SolutionReference<'_> {} - /// A solution which takes ownership of its inner structures. +/// +/// Implements [`ProblemSolution`]. #[derive(Clone, Debug, Default)] pub struct Solution { assignments: Assignments, } impl Solution { - pub fn new(assignments: Assignments) -> Self { - Self { assignments } - } - pub fn get_domains(&self) -> DomainGeneratorIterator { self.assignments.get_domains() // todo: Should we skip the first element as it could be the always true domain id? @@ -70,14 +74,14 @@ impl Solution { pub fn contains_domain_id(&self, domain_id: DomainId) -> bool { domain_id.id() < self.assignments.num_domains() } +} - pub fn is_predicate_satisfied(&self, predicate: Predicate) -> bool { - self.assignments.is_predicate_satisfied(predicate) +impl From for Solution { + fn from(value: Assignments) -> Self { + Self { assignments: value } } } -impl ProblemSolution for Solution {} - impl From> for Solution { fn from(value: SolutionReference) -> Self { Self { diff --git a/pumpkin-crates/core/src/basic_types/stored_conflict_info.rs b/pumpkin-crates/core/src/basic_types/stored_conflict_info.rs index 4d38eeea5..c3fc3899e 100644 --- a/pumpkin-crates/core/src/basic_types/stored_conflict_info.rs +++ b/pumpkin-crates/core/src/basic_types/stored_conflict_info.rs @@ -3,10 +3,10 @@ use crate::ConstraintOperationError; #[cfg(doc)] use crate::engine::ConstraintSatisfactionSolver; use crate::engine::EmptyDomainConflict; -#[cfg(doc)] -use crate::engine::propagation::Propagator; use crate::engine::state::Conflict; use crate::predicates::Predicate; +#[cfg(doc)] +use crate::propagation::Propagator; /// a conflict info which can be stored in the solver. /// two (related) conflicts can happen: diff --git a/pumpkin-crates/core/src/branching/branchers/alternating/strategies/until_solution.rs b/pumpkin-crates/core/src/branching/branchers/alternating/strategies/until_solution.rs index c24d94b46..8abcbf904 100644 --- a/pumpkin-crates/core/src/branching/branchers/alternating/strategies/until_solution.rs +++ b/pumpkin-crates/core/src/branching/branchers/alternating/strategies/until_solution.rs @@ -143,7 +143,7 @@ mod tests { )); assert!(!brancher.is_using_default_brancher()); - brancher.on_solution(Solution::new(assignments.clone()).as_reference()); + brancher.on_solution(Solution::from(assignments.clone()).as_reference()); let _ = brancher.next_decision(&mut SelectionContext::new( &assignments, &mut TestRandom::default(), @@ -164,7 +164,7 @@ mod tests { )); assert!(brancher.is_using_default_brancher()); - brancher.on_solution(Solution::new(assignments.clone()).as_reference()); + brancher.on_solution(Solution::from(assignments.clone()).as_reference()); let _ = brancher.next_decision(&mut SelectionContext::new( &assignments, &mut TestRandom::default(), @@ -198,7 +198,7 @@ mod tests { )); assert!(!brancher.is_using_default_brancher()); - brancher.on_solution(Solution::new(assignments.clone()).as_reference()); + brancher.on_solution(Solution::from(assignments.clone()).as_reference()); let _ = brancher.next_decision(&mut SelectionContext::new( &assignments, &mut TestRandom::default(), @@ -219,7 +219,7 @@ mod tests { )); assert!(brancher.is_using_default_brancher()); - brancher.on_solution(Solution::new(assignments.clone()).as_reference()); + brancher.on_solution(Solution::from(assignments.clone()).as_reference()); let _ = brancher.next_decision(&mut SelectionContext::new( &assignments, &mut TestRandom::default(), diff --git a/pumpkin-crates/core/src/branching/branchers/autonomous_search.rs b/pumpkin-crates/core/src/branching/branchers/autonomous_search.rs index cb7628570..c92ece2f0 100644 --- a/pumpkin-crates/core/src/branching/branchers/autonomous_search.rs +++ b/pumpkin-crates/core/src/branching/branchers/autonomous_search.rs @@ -15,6 +15,7 @@ use crate::containers::StorageKey; use crate::create_statistics_struct; use crate::engine::Assignments; use crate::engine::predicates::predicate::Predicate; +use crate::propagation::ReadDomains; use crate::results::Solution; use crate::statistics::Statistic; use crate::statistics::StatisticLogger; diff --git a/pumpkin-crates/core/src/branching/selection_context.rs b/pumpkin-crates/core/src/branching/selection_context.rs index b37941d95..0433e8889 100644 --- a/pumpkin-crates/core/src/branching/selection_context.rs +++ b/pumpkin-crates/core/src/branching/selection_context.rs @@ -7,12 +7,12 @@ use crate::engine::Assignments; #[cfg(test)] use crate::engine::notifications::NotificationEngine; use crate::engine::predicates::predicate::Predicate; -#[cfg(doc)] -use crate::engine::propagation::PropagationContext; use crate::engine::variables::DomainGeneratorIterator; #[cfg(doc)] use crate::engine::variables::DomainId; use crate::engine::variables::IntegerVariable; +#[cfg(doc)] +use crate::propagation::PropagationContext; /// The context provided to the [`Brancher`], /// it allows the retrieval of domain values of variables and access to methods from a [`Random`] diff --git a/pumpkin-crates/core/src/constraints/mod.rs b/pumpkin-crates/core/src/constraints/mod.rs index fe320abd3..a0b0f53b0 100644 --- a/pumpkin-crates/core/src/constraints/mod.rs +++ b/pumpkin-crates/core/src/constraints/mod.rs @@ -49,7 +49,7 @@ pub use table::*; use crate::ConstraintOperationError; use crate::Solver; -use crate::engine::propagation::constructor::PropagatorConstructor; +use crate::propagation::PropagatorConstructor; use crate::propagators::ReifiedPropagatorArgs; use crate::variables::Literal; diff --git a/pumpkin-crates/core/src/engine/conflict_analysis/conflict_analysis_context.rs b/pumpkin-crates/core/src/engine/conflict_analysis/conflict_analysis_context.rs index 23d89d81c..a1ca33369 100644 --- a/pumpkin-crates/core/src/engine/conflict_analysis/conflict_analysis_context.rs +++ b/pumpkin-crates/core/src/engine/conflict_analysis/conflict_analysis_context.rs @@ -12,8 +12,6 @@ use crate::engine::State; use crate::engine::constraint_satisfaction_solver::CSPSolverState; use crate::engine::predicates::predicate::Predicate; use crate::engine::predicates::predicate::PredicateType; -use crate::engine::propagation::CurrentNogood; -use crate::engine::propagation::ExplanationContext; use crate::engine::solver_statistics::SolverStatistics; use crate::predicate; use crate::predicates::PropositionalConjunction; @@ -21,6 +19,8 @@ use crate::proof::InferenceCode; use crate::proof::ProofLog; use crate::proof::RootExplanationContext; use crate::proof::explain_root_assignment; +use crate::propagation::CurrentNogood; +use crate::propagation::ExplanationContext; use crate::propagators::nogoods::NogoodPropagator; use crate::pumpkin_assert_eq_simple; use crate::pumpkin_assert_simple; diff --git a/pumpkin-crates/core/src/engine/conflict_analysis/minimisers/recursive_minimiser.rs b/pumpkin-crates/core/src/engine/conflict_analysis/minimisers/recursive_minimiser.rs index 5bc023861..87f8b932a 100644 --- a/pumpkin-crates/core/src/engine/conflict_analysis/minimisers/recursive_minimiser.rs +++ b/pumpkin-crates/core/src/engine/conflict_analysis/minimisers/recursive_minimiser.rs @@ -3,12 +3,11 @@ use crate::basic_types::moving_averages::MovingAverage; use crate::containers::HashMap; use crate::containers::HashSet; use crate::engine::Assignments; -use crate::engine::conflict_analysis::NogoodMinimiser; -use crate::engine::propagation::ReadDomains; -use crate::engine::propagation::contexts::HasAssignments; +use crate::engine::conflict_analysis::ConflictAnalysisContext; use crate::predicates::Predicate; use crate::proof::RootExplanationContext; use crate::proof::explain_root_assignment; +use crate::propagation::CurrentNogood; use crate::pumpkin_assert_eq_moderate; use crate::pumpkin_assert_moderate; use crate::pumpkin_assert_simple; diff --git a/pumpkin-crates/core/src/engine/conflict_analysis/resolvers/resolution_resolver.rs b/pumpkin-crates/core/src/engine/conflict_analysis/resolvers/resolution_resolver.rs index d29031a71..2173bf98a 100644 --- a/pumpkin-crates/core/src/engine/conflict_analysis/resolvers/resolution_resolver.rs +++ b/pumpkin-crates/core/src/engine/conflict_analysis/resolvers/resolution_resolver.rs @@ -14,11 +14,11 @@ use crate::engine::conflict_analysis::Mode; use crate::engine::conflict_analysis::NogoodMinimiser; use crate::engine::conflict_analysis::RecursiveMinimiser; use crate::engine::constraint_satisfaction_solver::NogoodLabel; -use crate::engine::propagation::CurrentNogood; use crate::predicates::Predicate; use crate::proof::InferenceCode; use crate::proof::RootExplanationContext; use crate::proof::explain_root_assignment; +use crate::propagation::CurrentNogood; use crate::propagators::nogoods::NogoodPropagator; use crate::pumpkin_assert_advanced; use crate::pumpkin_assert_moderate; diff --git a/pumpkin-crates/core/src/engine/constraint_satisfaction_solver.rs b/pumpkin-crates/core/src/engine/constraint_satisfaction_solver.rs index 1f2a0fe08..1e2d95603 100644 --- a/pumpkin-crates/core/src/engine/constraint_satisfaction_solver.rs +++ b/pumpkin-crates/core/src/engine/constraint_satisfaction_solver.rs @@ -17,7 +17,6 @@ use super::conflict_analysis::AnalysisMode; use super::conflict_analysis::ConflictAnalysisContext; use super::conflict_analysis::NoLearningResolver; use super::conflict_analysis::SemanticMinimiser; -use super::propagation::constructor::PropagatorConstructor; use super::solver_statistics::SolverStatistics; use super::termination::TerminationCondition; use super::variables::IntegerVariable; @@ -41,7 +40,6 @@ use crate::engine::RestartStrategy; use crate::engine::State; use crate::engine::conflict_analysis::ConflictResolver as Resolver; use crate::engine::predicates::predicate::Predicate; -use crate::engine::propagation::store::PropagatorHandle; use crate::options::LearningOptions; use crate::proof::ConstraintTag; use crate::proof::FinalizingContext; @@ -50,6 +48,8 @@ use crate::proof::ProofLog; use crate::proof::RootExplanationContext; use crate::proof::explain_root_assignment; use crate::proof::finalize_proof; +use crate::propagation::PropagatorConstructor; +use crate::propagation::store::PropagatorHandle; use crate::propagators::nogoods::NogoodPropagator; use crate::propagators::nogoods::NogoodPropagatorConstructor; use crate::pumpkin_assert_eq_simple; diff --git a/pumpkin-crates/core/src/engine/cp/mod.rs b/pumpkin-crates/core/src/engine/cp/mod.rs index e6dda5f9a..b081a100e 100644 --- a/pumpkin-crates/core/src/engine/cp/mod.rs +++ b/pumpkin-crates/core/src/engine/cp/mod.rs @@ -1,5 +1,4 @@ mod assignments; -pub(crate) mod propagation; mod propagator_queue; pub(crate) mod reason; pub(crate) mod test_solver; @@ -20,11 +19,11 @@ mod tests { use crate::engine::TrailedValues; use crate::engine::cp::assignments; use crate::engine::notifications::NotificationEngine; - use crate::engine::propagation::PropagationContextMut; - use crate::engine::propagation::PropagatorId; use crate::engine::reason::ReasonStore; use crate::predicate; use crate::proof::InferenceCode; + use crate::propagation::PropagationContextMut; + use crate::propagation::PropagatorId; #[test] fn test_no_update_reason_store_if_no_update_lower_bound() { diff --git a/pumpkin-crates/core/src/engine/cp/propagation/contexts/mod.rs b/pumpkin-crates/core/src/engine/cp/propagation/contexts/mod.rs deleted file mode 100644 index 1c4a1eb5e..000000000 --- a/pumpkin-crates/core/src/engine/cp/propagation/contexts/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub(crate) mod explanation_context; -pub(crate) mod propagation_context; - -pub(crate) use propagation_context::*; diff --git a/pumpkin-crates/core/src/engine/cp/propagator_queue.rs b/pumpkin-crates/core/src/engine/cp/propagator_queue.rs index 0625348c5..2693f5211 100644 --- a/pumpkin-crates/core/src/engine/cp/propagator_queue.rs +++ b/pumpkin-crates/core/src/engine/cp/propagator_queue.rs @@ -3,7 +3,7 @@ use std::collections::BinaryHeap; use std::collections::VecDeque; use crate::containers::KeyedVec; -use crate::engine::cp::propagation::PropagatorId; +use crate::propagation::PropagatorId; use crate::pumpkin_assert_moderate; #[derive(Debug, Clone)] diff --git a/pumpkin-crates/core/src/engine/cp/reason.rs b/pumpkin-crates/core/src/engine/cp/reason.rs index 05203a7e6..83075526e 100644 --- a/pumpkin-crates/core/src/engine/cp/reason.rs +++ b/pumpkin-crates/core/src/engine/cp/reason.rs @@ -1,13 +1,13 @@ use std::fmt::Debug; -use super::propagation::ExplanationContext; -use super::propagation::PropagatorId; -use super::propagation::store::PropagatorStore; use crate::basic_types::PropositionalConjunction; use crate::basic_types::Trail; #[cfg(doc)] use crate::containers::KeyedVec; use crate::predicates::Predicate; +use crate::propagation::ExplanationContext; +use crate::propagation::PropagatorId; +use crate::propagation::store::PropagatorStore; use crate::pumpkin_assert_simple; /// The reason store holds a reason for each change made by a CP propagator on a trail. diff --git a/pumpkin-crates/core/src/engine/cp/test_helper.rs b/pumpkin-crates/core/src/engine/cp/test_helper.rs index 79e0df707..989480d46 100644 --- a/pumpkin-crates/core/src/engine/cp/test_helper.rs +++ b/pumpkin-crates/core/src/engine/cp/test_helper.rs @@ -4,19 +4,19 @@ use std::fmt::Debug; use std::fmt::Formatter; -use super::propagation::EnqueueDecision; +use crate::propagation::EnqueueDecision; use super::WatchListPropositional; use crate::basic_types::Inconsistency; use crate::basic_types::PropagationStatusCP; use crate::basic_types::PropositionalConjunction; use crate::engine::opaque_domain_event::OpaqueDomainEvent; use crate::engine::predicates::integer_predicate::IntegerPredicate; -use crate::engine::propagation::LocalId; -use crate::engine::propagation::PropagationContext; -use crate::engine::propagation::PropagationContextMut; -use crate::engine::propagation::Propagator; -use crate::engine::propagation::PropagatorId; -use crate::engine::propagation::PropagatorInitialisationContext; +use crate::propagation::LocalId; +use crate::propagation::PropagationContext; +use crate::propagation::PropagationContextMut; +use crate::propagation::Propagator; +use crate::propagation::PropagatorId; +use crate::propagation::PropagatorInitialisationContext; use crate::engine::reason::ReasonStore; use crate::engine::variables::DomainId; use crate::engine::variables::IntegerVariable; @@ -24,7 +24,7 @@ use crate::engine::variables::Literal; use crate::engine::variables::PropositionalVariable; use crate::engine::AssignmentsInteger; use crate::engine::AssignmentsPropositional; -use crate::engine::DomainEvents; +use crate::propagation::DomainEvents; use crate::engine::EmptyDomain; use crate::engine::WatchListCP; diff --git a/pumpkin-crates/core/src/engine/cp/test_solver.rs b/pumpkin-crates/core/src/engine/cp/test_solver.rs index 4184f721a..c04110b4f 100644 --- a/pumpkin-crates/core/src/engine/cp/test_solver.rs +++ b/pumpkin-crates/core/src/engine/cp/test_solver.rs @@ -5,16 +5,10 @@ use std::fmt::Debug; use std::num::NonZero; use super::PropagatorQueue; -use super::propagation::EnqueueDecision; -use super::propagation::ExplanationContext; -use super::propagation::constructor::PropagatorConstructor; use crate::containers::KeyGenerator; use crate::engine::EmptyDomain; use crate::engine::State; use crate::engine::predicates::predicate::Predicate; -use crate::engine::propagation::PropagationContext; -use crate::engine::propagation::PropagationContextMut; -use crate::engine::propagation::PropagatorId; use crate::engine::variables::DomainId; use crate::engine::variables::IntegerVariable; use crate::engine::variables::Literal; @@ -23,6 +17,12 @@ use crate::predicate; use crate::predicates::PropositionalConjunction; use crate::proof::ConstraintTag; use crate::proof::InferenceCode; +use crate::propagation::EnqueueDecision; +use crate::propagation::ExplanationContext; +use crate::propagation::PropagationContext; +use crate::propagation::PropagationContextMut; +use crate::propagation::PropagatorConstructor; +use crate::propagation::PropagatorId; use crate::propagators::nogoods::NogoodPropagator; use crate::propagators::nogoods::NogoodPropagatorConstructor; use crate::state::Conflict; diff --git a/pumpkin-crates/core/src/engine/debug_helper.rs b/pumpkin-crates/core/src/engine/debug_helper.rs index fa81125fc..c8883f88b 100644 --- a/pumpkin-crates/core/src/engine/debug_helper.rs +++ b/pumpkin-crates/core/src/engine/debug_helper.rs @@ -7,14 +7,14 @@ use log::debug; use super::TrailedValues; use super::notifications::NotificationEngine; use super::predicates::predicate::Predicate; -use super::propagation::ExplanationContext; -use super::propagation::store::PropagatorStore; use super::reason::ReasonStore; use crate::basic_types::PropositionalConjunction; use crate::engine::cp::Assignments; -use crate::engine::propagation::PropagationContextMut; -use crate::engine::propagation::Propagator; -use crate::engine::propagation::PropagatorId; +use crate::propagation::ExplanationContext; +use crate::propagation::PropagationContextMut; +use crate::propagation::Propagator; +use crate::propagation::PropagatorId; +use crate::propagation::store::PropagatorStore; use crate::propagators::nogoods::NogoodPropagator; use crate::state::Conflict; diff --git a/pumpkin-crates/core/src/engine/mod.rs b/pumpkin-crates/core/src/engine/mod.rs index 684c3570d..5760b910e 100644 --- a/pumpkin-crates/core/src/engine/mod.rs +++ b/pumpkin-crates/core/src/engine/mod.rs @@ -27,5 +27,3 @@ pub(crate) use restart_strategy::RestartStrategy; pub(crate) use solver_statistics::SolverStatistics; pub use state::*; pub(crate) use variable_names::VariableNames; - -pub(crate) use crate::engine::notifications::DomainEvents; diff --git a/pumpkin-crates/core/src/engine/notifications/domain_event_notification/domain_event_watch_list.rs b/pumpkin-crates/core/src/engine/notifications/domain_event_notification/domain_event_watch_list.rs index a71b6fc44..4b0e69e5f 100644 --- a/pumpkin-crates/core/src/engine/notifications/domain_event_notification/domain_event_watch_list.rs +++ b/pumpkin-crates/core/src/engine/notifications/domain_event_notification/domain_event_watch_list.rs @@ -5,8 +5,8 @@ use enumset::EnumSetType; use crate::containers::KeyedVec; use crate::engine::notifications::NotificationEngine; -use crate::engine::propagation::PropagatorVarId; use crate::engine::variables::DomainId; +use crate::propagation::PropagatorVarId; #[derive(Default, Debug, Clone)] pub(crate) struct WatchListDomainEvents { diff --git a/pumpkin-crates/core/src/engine/notifications/domain_event_notification/domain_events.rs b/pumpkin-crates/core/src/engine/notifications/domain_event_notification/domain_events.rs index da8d9ed35..d2ef230cf 100644 --- a/pumpkin-crates/core/src/engine/notifications/domain_event_notification/domain_events.rs +++ b/pumpkin-crates/core/src/engine/notifications/domain_event_notification/domain_events.rs @@ -4,33 +4,32 @@ use enumset::enum_set; use super::DomainEvent; #[derive(Debug, Copy, Clone)] -pub(crate) struct DomainEvents { +pub struct DomainEvents { int_events: Option>, } impl DomainEvents { /// DomainEvents with both lower and upper bound tightening (but not other value removal). - pub(crate) const BOUNDS: DomainEvents = DomainEvents::create_with_int_events(enum_set!( + pub const BOUNDS: DomainEvents = DomainEvents::create_with_int_events(enum_set!( DomainEvent::LowerBound | DomainEvent::UpperBound )); // this is all options right now, but won't be once we add variables of other types /// DomainEvents with lower and upper bound tightening, assigning to a single value, and /// single value removal. - pub(crate) const ANY_INT: DomainEvents = DomainEvents::create_with_int_events(enum_set!( + pub const ANY_INT: DomainEvents = DomainEvents::create_with_int_events(enum_set!( DomainEvent::Assign | DomainEvent::LowerBound | DomainEvent::UpperBound | DomainEvent::Removal )); /// DomainEvents with only lower bound tightening. - pub(crate) const LOWER_BOUND: DomainEvents = + pub const LOWER_BOUND: DomainEvents = DomainEvents::create_with_int_events(enum_set!(DomainEvent::LowerBound)); /// DomainEvents with only upper bound tightening. - #[allow(unused, reason = "will be part of public API at some point")] - pub(crate) const UPPER_BOUND: DomainEvents = + pub const UPPER_BOUND: DomainEvents = DomainEvents::create_with_int_events(enum_set!(DomainEvent::UpperBound)); /// DomainEvents with only assigning to a single value. - pub(crate) const ASSIGN: DomainEvents = + pub const ASSIGN: DomainEvents = DomainEvents::create_with_int_events(enum_set!(DomainEvent::Assign)); } diff --git a/pumpkin-crates/core/src/engine/notifications/domain_event_notification/event_sink.rs b/pumpkin-crates/core/src/engine/notifications/domain_event_notification/event_sink.rs index 3dee6bd2d..f1a618c1f 100644 --- a/pumpkin-crates/core/src/engine/notifications/domain_event_notification/event_sink.rs +++ b/pumpkin-crates/core/src/engine/notifications/domain_event_notification/event_sink.rs @@ -2,10 +2,10 @@ use enumset::EnumSet; use super::DomainEvent; use crate::containers::KeyedVec; -#[cfg(doc)] -use crate::engine::DomainEvents; use crate::engine::variables::DomainId; #[cfg(doc)] +use crate::propagation::DomainEvents; +#[cfg(doc)] use crate::propagators; use crate::pumpkin_assert_advanced; diff --git a/pumpkin-crates/core/src/engine/notifications/domain_event_notification/mod.rs b/pumpkin-crates/core/src/engine/notifications/domain_event_notification/mod.rs index a56c38c14..ddf607046 100644 --- a/pumpkin-crates/core/src/engine/notifications/domain_event_notification/mod.rs +++ b/pumpkin-crates/core/src/engine/notifications/domain_event_notification/mod.rs @@ -2,7 +2,7 @@ mod domain_event_watch_list; pub(crate) mod domain_events; mod event_sink; pub(crate) mod opaque_domain_event; -pub(crate) use domain_event_watch_list::DomainEvent; +pub use domain_event_watch_list::DomainEvent; pub(crate) use domain_event_watch_list::WatchListDomainEvents; pub(crate) use domain_event_watch_list::Watchers; pub(crate) use event_sink::*; diff --git a/pumpkin-crates/core/src/engine/notifications/mod.rs b/pumpkin-crates/core/src/engine/notifications/mod.rs index bd3521d0e..eaa7467de 100644 --- a/pumpkin-crates/core/src/engine/notifications/mod.rs +++ b/pumpkin-crates/core/src/engine/notifications/mod.rs @@ -1,29 +1,29 @@ mod domain_event_notification; mod predicate_notification; -pub(crate) use domain_event_notification::DomainEvent; +pub use domain_event_notification::DomainEvent; pub(crate) use domain_event_notification::EventSink; pub(crate) use domain_event_notification::WatchListDomainEvents; pub(crate) use domain_event_notification::Watchers; -pub(crate) use domain_event_notification::domain_events::DomainEvents; +pub use domain_event_notification::domain_events::DomainEvents; pub(crate) use domain_event_notification::opaque_domain_event::OpaqueDomainEvent; use enumset::EnumSet; pub(crate) use predicate_notification::PredicateIdAssignments; pub(crate) use predicate_notification::PredicateNotifier; -use super::propagation::PropagationContext; -use super::propagation::PropagatorVarId; use crate::basic_types::PredicateId; use crate::containers::KeyedVec; use crate::engine::Assignments; use crate::engine::PropagatorQueue; use crate::engine::TrailedValues; -use crate::engine::propagation::EnqueueDecision; -use crate::engine::propagation::LocalId; -use crate::engine::propagation::PropagatorId; -use crate::engine::propagation::contexts::PropagationContextWithTrailedValues; -use crate::engine::propagation::store::PropagatorStore; use crate::predicates::Predicate; +use crate::propagation::EnqueueDecision; +use crate::propagation::LocalId; +use crate::propagation::PropagationContext; +use crate::propagation::PropagationContextWithTrailedValues; +use crate::propagation::PropagatorId; +use crate::propagation::PropagatorVarId; +use crate::propagation::store::PropagatorStore; use crate::pumpkin_assert_extreme; use crate::pumpkin_assert_simple; use crate::variables::DomainId; diff --git a/pumpkin-crates/core/src/engine/state.rs b/pumpkin-crates/core/src/engine/state.rs index ca478c73b..7dc7cde0d 100644 --- a/pumpkin-crates/core/src/engine/state.rs +++ b/pumpkin-crates/core/src/engine/state.rs @@ -11,15 +11,6 @@ use crate::engine::PropagatorQueue; use crate::engine::TrailedValues; use crate::engine::VariableNames; use crate::engine::notifications::NotificationEngine; -use crate::engine::propagation::CurrentNogood; -use crate::engine::propagation::ExplanationContext; -use crate::engine::propagation::PropagationContext; -use crate::engine::propagation::PropagationContextMut; -use crate::engine::propagation::Propagator; -use crate::engine::propagation::PropagatorId; -use crate::engine::propagation::constructor::PropagatorConstructor; -use crate::engine::propagation::constructor::PropagatorConstructorContext; -use crate::engine::propagation::store::PropagatorStore; use crate::engine::reason::ReasonRef; use crate::engine::reason::ReasonStore; use crate::predicate; @@ -30,6 +21,15 @@ use crate::proof::InferenceCode; use crate::proof::InferenceLabel; #[cfg(doc)] use crate::proof::ProofLog; +use crate::propagation::CurrentNogood; +use crate::propagation::ExplanationContext; +use crate::propagation::PropagationContext; +use crate::propagation::PropagationContextMut; +use crate::propagation::Propagator; +use crate::propagation::PropagatorConstructor; +use crate::propagation::PropagatorConstructorContext; +use crate::propagation::PropagatorId; +use crate::propagation::store::PropagatorStore; use crate::pumpkin_assert_advanced; use crate::pumpkin_assert_eq_simple; use crate::pumpkin_assert_extreme; @@ -345,8 +345,6 @@ impl State { /// While the propagator is added to the queue for propagation, this function does _not_ /// trigger a round of propagation. An explicit call to [`State::propagate_to_fixed_point`] is /// necessary to run the new propagator for the first time. - #[allow(private_bounds, reason = "Propagator will be part of public API")] - #[allow(private_interfaces, reason = "Constructor will be part of public API")] pub fn add_propagator( &mut self, constructor: Constructor, @@ -385,19 +383,11 @@ impl State { /// Get a reference to the propagator identified by the given handle. /// /// For an exclusive reference, use [`State::get_propagator_mut`]. - #[allow( - private_bounds, - reason = "Propagator will be part of public interface in the future" - )] pub fn get_propagator(&self, handle: PropagatorHandle

) -> Option<&P> { self.propagators.get_propagator(handle) } /// Get an exclusive reference to the propagator identified by the given handle. - #[allow( - private_bounds, - reason = "Propagator will be part of public interface in the future" - )] pub fn get_propagator_mut( &mut self, handle: PropagatorHandle

, diff --git a/pumpkin-crates/core/src/lib.rs b/pumpkin-crates/core/src/lib.rs index 1e0107a3d..af2544699 100644 --- a/pumpkin-crates/core/src/lib.rs +++ b/pumpkin-crates/core/src/lib.rs @@ -4,7 +4,6 @@ pub(crate) mod basic_types; pub mod containers; pub(crate) mod engine; pub(crate) mod math; -pub(crate) mod propagators; pub(crate) mod pumpkin_asserts; #[cfg(doc)] @@ -16,6 +15,8 @@ pub mod branching; pub mod constraints; pub mod optimisation; pub mod proof; +pub mod propagation; +pub mod propagators; pub mod statistics; pub use convert_case; diff --git a/pumpkin-crates/core/src/proof/finalizer.rs b/pumpkin-crates/core/src/proof/finalizer.rs index 7115c90f8..432ce530d 100644 --- a/pumpkin-crates/core/src/proof/finalizer.rs +++ b/pumpkin-crates/core/src/proof/finalizer.rs @@ -7,9 +7,9 @@ use super::ProofLog; use crate::containers::HashMap; use crate::engine::State; use crate::engine::conflict_analysis::ConflictAnalysisContext; -use crate::engine::propagation::CurrentNogood; use crate::predicates::Predicate; use crate::predicates::PropositionalConjunction; +use crate::propagation::CurrentNogood; pub(crate) struct FinalizingContext<'a> { pub(crate) conflict: PropositionalConjunction, diff --git a/pumpkin-crates/core/src/engine/cp/propagation/constructor.rs b/pumpkin-crates/core/src/propagation/constructor.rs similarity index 93% rename from pumpkin-crates/core/src/engine/cp/propagation/constructor.rs rename to pumpkin-crates/core/src/propagation/constructor.rs index ba25d0714..62f89d301 100644 --- a/pumpkin-crates/core/src/engine/cp/propagation/constructor.rs +++ b/pumpkin-crates/core/src/propagation/constructor.rs @@ -6,16 +6,22 @@ use super::PropagationContext; use super::Propagator; use super::PropagatorId; use super::PropagatorVarId; +#[cfg(doc)] +use crate::Solver; use crate::basic_types::PredicateId; use crate::engine::Assignments; -use crate::engine::DomainEvents; use crate::engine::State; use crate::engine::TrailedValues; use crate::engine::notifications::Watchers; +#[cfg(doc)] +use crate::engine::variables::AffineView; +#[cfg(doc)] +use crate::engine::variables::DomainId; use crate::predicates::Predicate; use crate::proof::ConstraintTag; use crate::proof::InferenceCode; use crate::proof::InferenceLabel; +use crate::propagation::DomainEvents; use crate::variables::IntegerVariable; /// A propagator constructor creates a fully initialized instance of a [`Propagator`]. @@ -23,7 +29,7 @@ use crate::variables::IntegerVariable; /// The constructor is responsible for indicating on which events the propagator should be /// enqueued. Additionally, the propagator can be initialized with values that come from the state /// of the solver. -pub(crate) trait PropagatorConstructor { +pub trait PropagatorConstructor { /// The propagator that is produced by this constructor. type PropagatorImpl: Propagator + Clone; @@ -37,7 +43,7 @@ pub(crate) trait PropagatorConstructor { /// Propagators use the [`PropagatorConstructorContext`] to register to domain changes /// of variables and to retrieve the current bounds of variables. #[derive(Debug)] -pub(crate) struct PropagatorConstructorContext<'a> { +pub struct PropagatorConstructorContext<'a> { state: &'a mut State, pub(crate) propagator_id: PropagatorId, @@ -59,7 +65,8 @@ impl PropagatorConstructorContext<'_> { } } - pub(crate) fn as_readonly(&self) -> PropagationContext<'_> { + /// Get domain information. + pub fn as_readonly(&self) -> PropagationContext<'_> { PropagationContext { assignments: &self.state.assignments, } @@ -73,10 +80,7 @@ impl PropagatorConstructorContext<'_> { /// /// Each variable *must* have a unique [`LocalId`]. Most often this would be its index of the /// variable in the internal array of variables. - /// - /// Note that the [`LocalId`] is used to differentiate between [`DomainId`]s and - /// [`AffineView`]s. - pub(crate) fn register( + pub fn register( &mut self, var: impl IntegerVariable, domain_events: DomainEvents, @@ -95,8 +99,7 @@ impl PropagatorConstructorContext<'_> { /// Register the propagator to be enqueued when the given [`Predicate`] becomes true. /// Returns the [`PredicateId`] used by the solver to track the predicate. - #[allow(unused, reason = "will become public API")] - pub(crate) fn register_predicate(&mut self, predicate: Predicate) -> PredicateId { + pub fn register_predicate(&mut self, predicate: Predicate) -> PredicateId { self.state.notification_engine.watch_predicate( predicate, self.propagator_id, @@ -207,8 +210,8 @@ impl DerefMut for RefOrOwned<'_, T> { mod private { use super::*; - use crate::engine::propagation::contexts::HasAssignments; - use crate::engine::propagation::contexts::HasTrailedValues; + use crate::propagation::HasAssignments; + use crate::propagation::HasTrailedValues; impl HasAssignments for PropagatorConstructorContext<'_> { fn assignments(&self) -> &Assignments { diff --git a/pumpkin-crates/core/src/engine/cp/propagation/contexts/explanation_context.rs b/pumpkin-crates/core/src/propagation/contexts/explanation_context.rs similarity index 89% rename from pumpkin-crates/core/src/engine/cp/propagation/contexts/explanation_context.rs rename to pumpkin-crates/core/src/propagation/contexts/explanation_context.rs index 030483f6b..1e3c8266b 100644 --- a/pumpkin-crates/core/src/engine/cp/propagation/contexts/explanation_context.rs +++ b/pumpkin-crates/core/src/propagation/contexts/explanation_context.rs @@ -7,11 +7,14 @@ use crate::containers::KeyValueHeap; use crate::engine::Assignments; use crate::engine::notifications::NotificationEngine; use crate::predicates::Predicate; +#[cfg(doc)] +use crate::propagation::Propagator; /// The context that is available when lazily explaining propagations. /// -/// See [`pumpkin_solver::engine::propagation::Propagator`] for more information. -pub(crate) struct ExplanationContext<'a> { +/// See [`Propagator`] for more information. +#[derive(Debug)] +pub struct ExplanationContext<'a> { assignments: &'a Assignments, pub(crate) notification_engine: &'a mut NotificationEngine, current_nogood: CurrentNogood<'a>, @@ -46,10 +49,6 @@ impl<'a> ExplanationContext<'a> { } } - pub(crate) fn get_predicate(&mut self, predicate_id: PredicateId) -> Predicate { - self.notification_engine.get_predicate(predicate_id) - } - pub(crate) fn without_working_nogood( assignments: &'a Assignments, trail_position: usize, @@ -63,13 +62,16 @@ impl<'a> ExplanationContext<'a> { } } + pub fn get_predicate(&mut self, predicate_id: PredicateId) -> Predicate { + self.notification_engine.get_predicate(predicate_id) + } + /// Get the current working nogood. /// /// The working nogood does not necessarily contain the predicate that is being explained. /// However, the explanation will be used to either resolve with the working nogood or minimize /// it some other way. - #[allow(unused, reason = "it will be part of the public API at some point")] - pub(crate) fn working_nogood(&self) -> impl Iterator + '_ { + pub fn working_nogood(&self) -> impl Iterator + '_ { self.current_nogood.iter() } @@ -77,7 +79,7 @@ impl<'a> ExplanationContext<'a> { /// /// For example, if the context is created for explaining a predicate `[x >= v]` at trail /// position i, then this method will return `i - 1` - pub(crate) fn get_trail_position(&self) -> usize { + pub fn get_trail_position(&self) -> usize { self.trail_position - 1 } } diff --git a/pumpkin-crates/core/src/propagation/contexts/mod.rs b/pumpkin-crates/core/src/propagation/contexts/mod.rs new file mode 100644 index 000000000..5e365abd0 --- /dev/null +++ b/pumpkin-crates/core/src/propagation/contexts/mod.rs @@ -0,0 +1,5 @@ +mod explanation_context; +mod propagation_context; + +pub use explanation_context::*; +pub use propagation_context::*; diff --git a/pumpkin-crates/core/src/engine/cp/propagation/contexts/propagation_context.rs b/pumpkin-crates/core/src/propagation/contexts/propagation_context.rs similarity index 83% rename from pumpkin-crates/core/src/engine/cp/propagation/contexts/propagation_context.rs rename to pumpkin-crates/core/src/propagation/contexts/propagation_context.rs index e9835e8b1..9a16fe103 100644 --- a/pumpkin-crates/core/src/engine/cp/propagation/contexts/propagation_context.rs +++ b/pumpkin-crates/core/src/propagation/contexts/propagation_context.rs @@ -7,18 +7,19 @@ use crate::engine::TrailedValues; use crate::engine::notifications::NotificationEngine; use crate::engine::notifications::PredicateIdAssignments; use crate::engine::predicates::predicate::Predicate; -#[cfg(doc)] -use crate::engine::propagation::Propagator; -use crate::engine::propagation::PropagatorId; use crate::engine::reason::Reason; use crate::engine::reason::ReasonStore; use crate::engine::reason::StoredReason; use crate::engine::variables::IntegerVariable; use crate::engine::variables::Literal; use crate::proof::InferenceCode; +#[cfg(doc)] +use crate::propagation::Propagator; +use crate::propagation::PropagatorId; use crate::pumpkin_assert_simple; -pub(crate) struct PropagationContextWithTrailedValues<'a> { +#[derive(Debug)] +pub struct PropagationContextWithTrailedValues<'a> { pub(crate) trailed_values: &'a mut TrailedValues, pub(crate) assignments: &'a Assignments, pub(crate) predicate_id_assignments: &'a PredicateIdAssignments, @@ -53,8 +54,8 @@ impl<'a> PropagationContextWithTrailedValues<'a> { /// Note that the [`PropagationContext`] is the only point of communication beween /// the propagations and the solver during propagation. #[derive(Clone, Copy, Debug)] -pub(crate) struct PropagationContext<'a> { - pub assignments: &'a Assignments, +pub struct PropagationContext<'a> { + pub(crate) assignments: &'a Assignments, } impl<'a> PropagationContext<'a> { @@ -64,7 +65,7 @@ impl<'a> PropagationContext<'a> { } #[derive(Debug)] -pub(crate) struct PropagationContextMut<'a> { +pub struct PropagationContextMut<'a> { pub(crate) trailed_values: &'a mut TrailedValues, pub(crate) assignments: &'a mut Assignments, pub(crate) reason_store: &'a mut ReasonStore, @@ -91,19 +92,11 @@ impl<'a> PropagationContextMut<'a> { } } - pub(crate) fn get_predicate(&mut self, predicate_id: PredicateId) -> Predicate { - self.notification_engine.get_predicate(predicate_id) - } - - pub(crate) fn get_id(&mut self, predicate: Predicate) -> PredicateId { - self.notification_engine.get_id(predicate) - } - /// Register the propagator to be enqueued when the provided [`Predicate`] becomes true. /// /// Returns the [`PredicateId`] assigned to the provided predicate, which will be provided - /// to [`Propagator::notify_predicate_satisfied`]. - pub(crate) fn register_predicate(&mut self, predicate: Predicate) -> PredicateId { + /// to [`Propagator::notify_predicate_id_satisfied`]. + pub fn register_predicate(&mut self, predicate: Predicate) -> PredicateId { self.notification_engine.watch_predicate( predicate, self.propagator_id, @@ -112,6 +105,18 @@ impl<'a> PropagationContextMut<'a> { ) } + /// Get the [`Predicate`] for a given [`PredicateId`]. + pub fn get_predicate(&mut self, predicate_id: PredicateId) -> Predicate { + self.notification_engine.get_predicate(predicate_id) + } + + /// Get a [`PredicateId`] for the given [`Predicate`]. + /// + /// If no ID exists, one will be created. + pub fn get_id(&mut self, predicate: Predicate) -> PredicateId { + self.notification_engine.get_id(predicate) + } + /// Apply a reification literal to all the explanations that are passed to the context. pub(crate) fn with_reification(&mut self, reification_literal: Literal) { pumpkin_assert_simple!( @@ -130,7 +135,8 @@ impl<'a> PropagationContextMut<'a> { } } - pub(crate) fn as_readonly(&self) -> PropagationContext<'_> { + /// Get the current domain information. + pub fn as_readonly(&self) -> PropagationContext<'_> { PropagationContext { assignments: self.assignments, } @@ -162,7 +168,7 @@ impl<'a> PropagationContextMut<'a> { /// A trait which defines common methods for retrieving the [`Assignments`] and /// [`AssignmentsPropositional`] from the structure which implements this trait. -pub trait HasAssignments { +pub(crate) trait HasAssignments { /// Returns the stored [`Assignments`]. fn assignments(&self) -> &Assignments; } @@ -235,7 +241,59 @@ pub(crate) trait ManipulateTrailedValues: HasTrailedValues { impl ManipulateTrailedValues for T {} -pub(crate) trait ReadDomains: HasAssignments { +pub trait ReadDomains { + fn is_predicate_satisfied(&self, predicate: Predicate) -> bool; + + fn is_predicate_falsified(&self, predicate: Predicate) -> bool; + + fn is_literal_true(&self, literal: &Literal) -> bool; + + fn is_literal_false(&self, literal: &Literal) -> bool; + + fn is_literal_fixed(&self, literal: &Literal) -> bool; + + /// Returns the holes which were created on the current decision level. + fn get_holes_at_current_checkpoint( + &self, + var: &Var, + ) -> impl Iterator; + + /// Returns all of the holes (currently) in the domain of `var` (including ones which were + /// created at previous decision levels). + fn get_holes(&self, var: &Var) -> impl Iterator; + + /// Returns `true` if the domain of the given variable is singleton. + fn is_fixed(&self, var: &Var) -> bool; + + fn lower_bound(&self, var: &Var) -> i32; + + fn lower_bound_at_trail_position( + &self, + var: &Var, + trail_position: usize, + ) -> i32; + + fn upper_bound(&self, var: &Var) -> i32; + + fn upper_bound_at_trail_position( + &self, + var: &Var, + trail_position: usize, + ) -> i32; + + fn contains(&self, var: &Var, value: i32) -> bool; + + fn contains_at_trail_position( + &self, + var: &Var, + value: i32, + trail_position: usize, + ) -> bool; + + fn iterate_domain(&self, var: &Var) -> impl Iterator; +} + +impl ReadDomains for T { fn is_predicate_satisfied(&self, predicate: Predicate) -> bool { self.assignments() .evaluate_predicate(predicate) @@ -297,7 +355,6 @@ pub(crate) trait ReadDomains: HasAssignments { var.lower_bound(self.assignments()) } - #[allow(unused, reason = "Will be part of the API")] fn lower_bound_at_trail_position( &self, var: &Var, @@ -310,7 +367,6 @@ pub(crate) trait ReadDomains: HasAssignments { var.upper_bound(self.assignments()) } - #[allow(unused, reason = "Will be part of the API")] fn upper_bound_at_trail_position( &self, var: &Var, @@ -337,8 +393,6 @@ pub(crate) trait ReadDomains: HasAssignments { } } -impl ReadDomains for T {} - impl PropagationContextMut<'_> { pub(crate) fn evaluate_predicate(&self, predicate: Predicate) -> Option { self.assignments.evaluate_predicate(predicate) diff --git a/pumpkin-crates/core/src/engine/cp/propagation/local_id.rs b/pumpkin-crates/core/src/propagation/local_id.rs similarity index 84% rename from pumpkin-crates/core/src/engine/cp/propagation/local_id.rs rename to pumpkin-crates/core/src/propagation/local_id.rs index f343474fb..b3a3334df 100644 --- a/pumpkin-crates/core/src/engine/cp/propagation/local_id.rs +++ b/pumpkin-crates/core/src/propagation/local_id.rs @@ -3,14 +3,14 @@ use crate::containers::StorageKey; /// A local id uniquely identifies a variable within a specific propagator. A local id can be /// thought of as the index of the variable in the propagator. #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub(crate) struct LocalId(u32); +pub struct LocalId(u32); impl LocalId { - pub(crate) const fn from(value: u32) -> Self { + pub const fn from(value: u32) -> Self { LocalId(value) } - pub(crate) fn unpack(self) -> u32 { + pub fn unpack(self) -> u32 { self.0 } } diff --git a/pumpkin-crates/core/src/engine/cp/propagation/mod.rs b/pumpkin-crates/core/src/propagation/mod.rs similarity index 70% rename from pumpkin-crates/core/src/engine/cp/propagation/mod.rs rename to pumpkin-crates/core/src/propagation/mod.rs index 84470c3ea..2fa4eb3c9 100644 --- a/pumpkin-crates/core/src/engine/cp/propagation/mod.rs +++ b/pumpkin-crates/core/src/propagation/mod.rs @@ -25,7 +25,7 @@ //! # Practical //! //! Each concrete propagator is associated with one trait: [`Propagator`]. The main function to -//! implement for this trait is [`Proagator::propagate`], which performs the domain reduction. +//! implement for this trait is [`Propagator::propagate`], which performs the domain reduction. //! //! A propagator is created by a [`PropagatorConstructor`]. The constructor is responsible for //! registering to domain events, and setting up the state of the propagator. The constructor is @@ -44,26 +44,21 @@ //! 1. Implement a propagator struct that implements the [`Propagator`] trait. For now only //! implement the required functions, i.e., [`Propagator::debug_propagate_from_scratch`] and //! [`Propagator::name`]. -//! 2. Implement the [`Propagator::initialise_at_root`] function which detects root-level -//! inconsistencies and is also responsible for registering the variables and corresponding -//! [`DomainEvents`] with the solver, so that the solver can notify the propagator once an event -//! happens that relates to one of the variables of the propagator. //! 2. Create an implementation of the [`PropagatorConstructor`] trait, to register for domain //! events and set up the propagator state. //! 3. Following the procedure above gives an initial version of the propagator that is likely not -//! efficient, but has an important role for testing. Now is a good time to write tests which use -//! the [`TestSolver`]. **We strongly discourage skipping this step**. -//! * For example, see the tests in [`crate::propagators::arithmetic::absolute_value`]. -//! 4. Implement [`Propagator::notify`]. Depending on the concrete propagator, this may only make -//! sense when done together with the next step. -//! 5. Implement the remaining functions, i.e., [`Propagator::propagate`], -//! [`Propagator::synchronise`], and [`Propagator::initialise_at_root`]. These are all -//! interdependent. +//! efficient, but has an important role for testing. Now is a good time to write tests using the +//! [`State`] API. **We strongly discourage skipping this step**. +//! 4. Implement [`Propagator::notify`] and/or [`Propagator::notify_predicate_id_satisfied`] for +//! more control on when the propagator is enqueued. Depending on the concrete propagator, this +//! may only make sense when done together with the next step. +//! 5. Implement the remaining hooks, i.e., [`Propagator::propagate`], and +//! [`Propagator::synchronise`] to exploit incrementality. These are all interdependent. //! 6. Decide on the priortiy of the propagator, i.e., implement [`Propagator::priority`]. //! 7. Make sure to write new tests and run all tests throughout the process. //! 8. The propagator implementation is now done! //! -//! The propagator is added to the solver through [`ConstraintSatisfactionSolver::add_propagator`]. +//! The propagator is added to the solver through [`Solver::add_propagator`]. //! //! # Bibliography //! @@ -74,29 +69,27 @@ //! International Workshop on Constraint Solving and Constraint Logic Programming, 2005, pp. //! 118–132. -pub(crate) mod constructor; -pub(crate) mod contexts; -pub(crate) mod local_id; -pub(crate) mod propagator; +mod constructor; +mod contexts; +mod local_id; +mod propagator; + pub(crate) mod propagator_id; pub(crate) mod propagator_var_id; pub(crate) mod store; -pub use contexts::explanation_context::CurrentNogood; -pub(crate) use contexts::explanation_context::ExplanationContext; -pub(crate) use contexts::propagation_context::PropagationContext; -pub(crate) use contexts::propagation_context::PropagationContextMut; -pub(crate) use contexts::propagation_context::ReadDomains; -pub(crate) use local_id::LocalId; -pub(crate) use propagator::EnqueueDecision; -pub(crate) use propagator::Propagator; +pub use constructor::*; +pub use contexts::*; +pub use local_id::*; +pub use propagator::*; pub use propagator_id::PropagatorId; pub(crate) use propagator_var_id::PropagatorVarId; #[cfg(doc)] -use crate::engine::ConstraintSatisfactionSolver; -#[cfg(doc)] -use crate::engine::DomainEvents; +use crate::Solver; +pub use crate::basic_types::PredicateId; +pub use crate::engine::notifications::DomainEvent; +pub use crate::engine::notifications::DomainEvents; #[cfg(doc)] use crate::engine::test_solver::TestSolver; #[cfg(doc)] @@ -105,3 +98,5 @@ use crate::engine::variables::IntegerVariable; use crate::propagators; #[cfg(doc)] use crate::propagators::linear_less_or_equal::LinearLessOrEqualPropagator; +#[cfg(doc)] +use crate::state::State; diff --git a/pumpkin-crates/core/src/engine/cp/propagation/propagator.rs b/pumpkin-crates/core/src/propagation/propagator.rs similarity index 80% rename from pumpkin-crates/core/src/engine/cp/propagation/propagator.rs rename to pumpkin-crates/core/src/propagation/propagator.rs index 4dc13d8d8..7aec68b80 100644 --- a/pumpkin-crates/core/src/engine/cp/propagation/propagator.rs +++ b/pumpkin-crates/core/src/propagation/propagator.rs @@ -15,9 +15,11 @@ use crate::create_statistics_struct; #[cfg(doc)] use crate::engine::ConstraintSatisfactionSolver; use crate::engine::notifications::OpaqueDomainEvent; -use crate::engine::propagation::local_id::LocalId; use crate::predicates::Predicate; #[cfg(doc)] +use crate::propagation::ReadDomains; +use crate::propagation::local_id::LocalId; +#[cfg(doc)] use crate::pumpkin_asserts::PUMPKIN_ASSERT_ADVANCED; #[cfg(doc)] use crate::pumpkin_asserts::PUMPKIN_ASSERT_EXTREME; @@ -32,16 +34,16 @@ impl_downcast!(Propagator); // To allow the State object to be cloneable, we need to allow `Box` to be cloned. clone_trait_object!(Propagator); -/// All propagators implement the [`Propagator`] trait, which defines the main propagator logic with -/// regards to propagation, detecting conflicts, and providing explanations. +/// A propagator removes values from domains which will never be in any solution, or raises +/// explicit conflicts. /// /// The only required functions are [`Propagator::name`], -/// [`Propagator::initialise_at_root`], and [`Propagator::debug_propagate_from_scratch`]; all other +/// and [`Propagator::debug_propagate_from_scratch`]; all other /// functions have default implementations. For initial development, the required functions are /// enough, but a more mature implementation considers all functions in most cases. /// -/// See the [`crate::engine::cp::propagation`] documentation for more details. -pub(crate) trait Propagator: Downcast + DynClone { +/// See the [`crate::propagation`] documentation for more details. +pub trait Propagator: Downcast + DynClone { /// Return the name of the propagator, this is a convenience method that is used for printing. fn name(&self) -> &str; @@ -49,17 +51,15 @@ pub(crate) trait Propagator: Downcast + DynClone { /// /// This method propagates without relying on internal data structures, hence the immutable /// &self parameter. It is usually best to implement this propagation method in the simplest - /// but correct way. When the assert level is set to [`PUMPKIN_ASSERT_ADVANCED`] or - /// [`PUMPKIN_ASSERT_EXTREME`] (see [`crate::pumpkin_asserts`]) this method will be called - /// to double check the reasons for failures and propagations that have been reported by - /// this propagator. + /// but correct way. When this crate is compiled with the `debug-checks` feature, this method + /// will be called to double check the reasons for failures and propagations that have been + /// reported by this propagator. /// /// Propagators are not required to propagate until a fixed point. It will be called again by /// the solver until no further propagations happen. fn debug_propagate_from_scratch(&self, context: PropagationContextMut) -> PropagationStatusCP; - /// Propagate method that will be called during search (e.g. in - /// [`ConstraintSatisfactionSolver::solve`]). + /// Performs stateful propagation. /// /// This method extends the current partial /// assignments with inferred domain changes found by the @@ -87,12 +87,8 @@ pub(crate) trait Propagator: Downcast + DynClone { /// should only be used for computationally cheap logic. Expensive computation should be /// performed in the [`Propagator::propagate()`] method. /// - /// By default the propagator is always enqueued for every event. Not all propagators will - /// benefit from implementing this, so it is not required to do so. - /// - /// Note that the variables and events to which the propagator is subscribed to are determined - /// upon propagator initialisation via [`Propagator::initialise_at_root`] by calling - /// [`PropagatorInitialisationContext::register()`]. + /// By default the propagator is always enqueued for every event it is subscribed to. Not all + /// propagators will benefit from implementing this, so it is not required to do so. fn notify( &mut self, _context: PropagationContextWithTrailedValues, @@ -111,10 +107,6 @@ pub(crate) trait Propagator: Downcast + DynClone { /// /// By default the propagator does nothing when this method is called. Not all propagators will /// benefit from implementing this, so it is not required to do so. - /// - /// Note that the variables and events to which the propagator is subscribed to are determined - /// upon propagator initialisation via [`Propagator::initialise_at_root`] by calling - /// [`PropagatorInitialisationContext::register()`]. fn notify_backtrack( &mut self, _context: PropagationContext, @@ -130,7 +122,7 @@ pub(crate) trait Propagator: Downcast + DynClone { EnqueueDecision::Enqueue } - /// Called each time the [`ConstraintSatisfactionSolver`] backtracks, the propagator can then + /// Called after backtracking, allowing the propagator to /// update its internal data structures given the new variable domains. /// /// By default this function does nothing. @@ -163,13 +155,13 @@ pub(crate) trait Propagator: Downcast + DynClone { /// Hook which is called when a propagated [`Predicate`] should be explained using a lazy /// reason. /// - /// The code which was attached to the propagation through [`Reason::DynamicLazy`] is given, as + /// The code which was attached to the propagation is given, as /// well as a context object which defines what can be inspected from the solver to build the /// explanation. /// /// *Note:* The context which is provided contains the _current_ state (i.e. the state when the /// explanation is generated); the bounds at the time of the propagation can be retrieved using - /// methods such as [`ExplanationContext::get_lower_bound_at_trail_position`] in combination + /// methods such as [`ReadDomains::lower_bound_at_trail_position`] in combination /// with [`ExplanationContext::get_trail_position`]. fn lazy_explanation(&mut self, _code: u64, _context: ExplanationContext) -> &[Predicate] { panic!( @@ -188,7 +180,7 @@ pub(crate) trait Propagator: Downcast + DynClone { /// Indicator of what to do when a propagator is notified. #[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub(crate) enum EnqueueDecision { +pub enum EnqueueDecision { /// The propagator should be enqueued. Enqueue, /// The propagator should not be enqueued. diff --git a/pumpkin-crates/core/src/engine/cp/propagation/propagator_id.rs b/pumpkin-crates/core/src/propagation/propagator_id.rs similarity index 100% rename from pumpkin-crates/core/src/engine/cp/propagation/propagator_id.rs rename to pumpkin-crates/core/src/propagation/propagator_id.rs diff --git a/pumpkin-crates/core/src/engine/cp/propagation/propagator_var_id.rs b/pumpkin-crates/core/src/propagation/propagator_var_id.rs similarity index 71% rename from pumpkin-crates/core/src/engine/cp/propagation/propagator_var_id.rs rename to pumpkin-crates/core/src/propagation/propagator_var_id.rs index d7dae9573..7d40d16e1 100644 --- a/pumpkin-crates/core/src/engine/cp/propagation/propagator_var_id.rs +++ b/pumpkin-crates/core/src/propagation/propagator_var_id.rs @@ -1,5 +1,5 @@ -use crate::engine::propagation::LocalId; -use crate::engine::propagation::PropagatorId; +use crate::propagation::LocalId; +use crate::propagation::PropagatorId; /// A handle to a variable registered to a propagator. #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] diff --git a/pumpkin-crates/core/src/engine/cp/propagation/store.rs b/pumpkin-crates/core/src/propagation/store.rs similarity index 100% rename from pumpkin-crates/core/src/engine/cp/propagation/store.rs rename to pumpkin-crates/core/src/propagation/store.rs diff --git a/pumpkin-crates/core/src/propagators/arithmetic/absolute_value.rs b/pumpkin-crates/core/src/propagators/arithmetic/absolute_value.rs index f4af6856f..4e499a449 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/absolute_value.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/absolute_value.rs @@ -1,17 +1,17 @@ use crate::basic_types::PropagationStatusCP; use crate::conjunction; use crate::declare_inference_label; -use crate::engine::DomainEvents; -use crate::engine::cp::propagation::ReadDomains; -use crate::engine::propagation::LocalId; -use crate::engine::propagation::PropagationContextMut; -use crate::engine::propagation::Propagator; -use crate::engine::propagation::constructor::PropagatorConstructor; -use crate::engine::propagation::constructor::PropagatorConstructorContext; use crate::engine::variables::IntegerVariable; use crate::predicate; use crate::proof::ConstraintTag; use crate::proof::InferenceCode; +use crate::propagation::DomainEvents; +use crate::propagation::LocalId; +use crate::propagation::PropagationContextMut; +use crate::propagation::Propagator; +use crate::propagation::PropagatorConstructor; +use crate::propagation::PropagatorConstructorContext; +use crate::propagation::ReadDomains; declare_inference_label!(AbsoluteValue); diff --git a/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_equals.rs b/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_equals.rs index eb977d8d2..7e9d73f69 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_equals.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_equals.rs @@ -9,20 +9,9 @@ use crate::basic_types::PropagatorConflict; use crate::conjunction; use crate::containers::HashSet; use crate::declare_inference_label; -use crate::engine::DomainEvents; use crate::engine::EmptyDomainConflict; -use crate::engine::cp::propagation::ReadDomains; use crate::engine::notifications::DomainEvent; use crate::engine::notifications::OpaqueDomainEvent; -use crate::engine::propagation::EnqueueDecision; -use crate::engine::propagation::ExplanationContext; -use crate::engine::propagation::LocalId; -use crate::engine::propagation::PropagationContext; -use crate::engine::propagation::PropagationContextMut; -use crate::engine::propagation::Propagator; -use crate::engine::propagation::constructor::PropagatorConstructor; -use crate::engine::propagation::constructor::PropagatorConstructorContext; -use crate::engine::propagation::contexts::PropagationContextWithTrailedValues; use crate::engine::variables::IntegerVariable; use crate::predicate; use crate::predicates::Predicate; @@ -30,6 +19,17 @@ use crate::predicates::PredicateConstructor; use crate::predicates::PredicateType; use crate::proof::ConstraintTag; use crate::proof::InferenceCode; +use crate::propagation::DomainEvents; +use crate::propagation::EnqueueDecision; +use crate::propagation::ExplanationContext; +use crate::propagation::LocalId; +use crate::propagation::PropagationContext; +use crate::propagation::PropagationContextMut; +use crate::propagation::PropagationContextWithTrailedValues; +use crate::propagation::Propagator; +use crate::propagation::PropagatorConstructor; +use crate::propagation::PropagatorConstructorContext; +use crate::propagation::ReadDomains; use crate::pumpkin_assert_advanced; declare_inference_label!(BinaryEquals); @@ -390,8 +390,8 @@ struct BinaryEqualsPropagation { #[cfg(test)] mod tests { - use crate::engine::propagation::EnqueueDecision; use crate::engine::test_solver::TestSolver; + use crate::propagation::EnqueueDecision; use crate::propagators::binary::BinaryEqualsPropagatorArgs; #[test] diff --git a/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_not_equals.rs b/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_not_equals.rs index ed28c28b8..06e5f7408 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_not_equals.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_not_equals.rs @@ -2,18 +2,18 @@ use crate::basic_types::PropagationStatusCP; use crate::basic_types::PropagatorConflict; use crate::conjunction; use crate::declare_inference_label; -use crate::engine::DomainEvents; -use crate::engine::cp::propagation::ReadDomains; -use crate::engine::propagation::LocalId; -use crate::engine::propagation::PropagationContextMut; -use crate::engine::propagation::Propagator; -use crate::engine::propagation::constructor::PropagatorConstructor; -use crate::engine::propagation::constructor::PropagatorConstructorContext; -use crate::engine::propagation::contexts::PropagationContextWithTrailedValues; use crate::engine::variables::IntegerVariable; use crate::predicate; use crate::proof::ConstraintTag; use crate::proof::InferenceCode; +use crate::propagation::DomainEvents; +use crate::propagation::LocalId; +use crate::propagation::PropagationContextMut; +use crate::propagation::PropagationContextWithTrailedValues; +use crate::propagation::Propagator; +use crate::propagation::PropagatorConstructor; +use crate::propagation::PropagatorConstructorContext; +use crate::propagation::ReadDomains; declare_inference_label!(BinaryNotEquals); @@ -175,8 +175,8 @@ where #[cfg(test)] mod tests { - use crate::engine::propagation::EnqueueDecision; use crate::engine::test_solver::TestSolver; + use crate::propagation::EnqueueDecision; use crate::propagators::binary::BinaryNotEqualsPropagatorArgs; #[test] diff --git a/pumpkin-crates/core/src/propagators/arithmetic/integer_division.rs b/pumpkin-crates/core/src/propagators/arithmetic/integer_division.rs index 33563381a..1d7ba23ff 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/integer_division.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/integer_division.rs @@ -1,17 +1,17 @@ use crate::basic_types::PropagationStatusCP; use crate::conjunction; use crate::declare_inference_label; -use crate::engine::DomainEvents; -use crate::engine::propagation::LocalId; -use crate::engine::propagation::PropagationContextMut; -use crate::engine::propagation::Propagator; -use crate::engine::propagation::ReadDomains; -use crate::engine::propagation::constructor::PropagatorConstructor; -use crate::engine::propagation::constructor::PropagatorConstructorContext; use crate::engine::variables::IntegerVariable; use crate::predicate; use crate::proof::ConstraintTag; use crate::proof::InferenceCode; +use crate::propagation::DomainEvents; +use crate::propagation::LocalId; +use crate::propagation::PropagationContextMut; +use crate::propagation::Propagator; +use crate::propagation::PropagatorConstructor; +use crate::propagation::PropagatorConstructorContext; +use crate::propagation::ReadDomains; use crate::pumpkin_assert_simple; /// The [`PropagatorConstructor`] for the [`DivisionPropagator`]. diff --git a/pumpkin-crates/core/src/propagators/arithmetic/integer_multiplication.rs b/pumpkin-crates/core/src/propagators/arithmetic/integer_multiplication.rs index 199d8812f..b544e7137 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/integer_multiplication.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/integer_multiplication.rs @@ -2,17 +2,17 @@ use crate::basic_types::PropagationStatusCP; use crate::basic_types::PropagatorConflict; use crate::conjunction; use crate::declare_inference_label; -use crate::engine::DomainEvents; -use crate::engine::cp::propagation::ReadDomains; -use crate::engine::propagation::LocalId; -use crate::engine::propagation::PropagationContextMut; -use crate::engine::propagation::Propagator; -use crate::engine::propagation::constructor::PropagatorConstructor; -use crate::engine::propagation::constructor::PropagatorConstructorContext; use crate::engine::variables::IntegerVariable; use crate::predicate; use crate::proof::ConstraintTag; use crate::proof::InferenceCode; +use crate::propagation::DomainEvents; +use crate::propagation::LocalId; +use crate::propagation::PropagationContextMut; +use crate::propagation::Propagator; +use crate::propagation::PropagatorConstructor; +use crate::propagation::PropagatorConstructorContext; +use crate::propagation::ReadDomains; use crate::pumpkin_assert_simple; declare_inference_label!(IntegerMultiplication); diff --git a/pumpkin-crates/core/src/propagators/arithmetic/linear_less_or_equal.rs b/pumpkin-crates/core/src/propagators/arithmetic/linear_less_or_equal.rs index 3ae22f673..263a38f7a 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/linear_less_or_equal.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/linear_less_or_equal.rs @@ -2,25 +2,25 @@ use crate::basic_types::PropagationStatusCP; use crate::basic_types::PropagatorConflict; use crate::basic_types::PropositionalConjunction; use crate::declare_inference_label; -use crate::engine::DomainEvents; use crate::engine::TrailedInteger; -use crate::engine::cp::propagation::ReadDomains; use crate::engine::notifications::OpaqueDomainEvent; -use crate::engine::propagation::EnqueueDecision; -use crate::engine::propagation::ExplanationContext; -use crate::engine::propagation::LocalId; -use crate::engine::propagation::PropagationContext; -use crate::engine::propagation::PropagationContextMut; -use crate::engine::propagation::Propagator; -use crate::engine::propagation::constructor::PropagatorConstructor; -use crate::engine::propagation::constructor::PropagatorConstructorContext; -use crate::engine::propagation::contexts::ManipulateTrailedValues; -use crate::engine::propagation::contexts::PropagationContextWithTrailedValues; use crate::engine::variables::IntegerVariable; use crate::predicate; use crate::predicates::Predicate; use crate::proof::ConstraintTag; use crate::proof::InferenceCode; +use crate::propagation::DomainEvents; +use crate::propagation::EnqueueDecision; +use crate::propagation::ExplanationContext; +use crate::propagation::LocalId; +use crate::propagation::ManipulateTrailedValues; +use crate::propagation::PropagationContext; +use crate::propagation::PropagationContextMut; +use crate::propagation::PropagationContextWithTrailedValues; +use crate::propagation::Propagator; +use crate::propagation::PropagatorConstructor; +use crate::propagation::PropagatorConstructorContext; +use crate::propagation::ReadDomains; use crate::pumpkin_assert_simple; declare_inference_label!(LinearBounds); diff --git a/pumpkin-crates/core/src/propagators/arithmetic/linear_not_equal.rs b/pumpkin-crates/core/src/propagators/arithmetic/linear_not_equal.rs index a63908f3c..da8301907 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/linear_not_equal.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/linear_not_equal.rs @@ -6,22 +6,22 @@ use crate::basic_types::PropagationStatusCP; use crate::basic_types::PropagatorConflict; use crate::basic_types::PropositionalConjunction; use crate::declare_inference_label; -use crate::engine::DomainEvents; -use crate::engine::cp::propagation::ReadDomains; use crate::engine::notifications::DomainEvent; use crate::engine::notifications::OpaqueDomainEvent; -use crate::engine::propagation::EnqueueDecision; -use crate::engine::propagation::LocalId; -use crate::engine::propagation::PropagationContext; -use crate::engine::propagation::PropagationContextMut; -use crate::engine::propagation::Propagator; -use crate::engine::propagation::constructor::PropagatorConstructor; -use crate::engine::propagation::constructor::PropagatorConstructorContext; -use crate::engine::propagation::contexts::PropagationContextWithTrailedValues; use crate::engine::variables::IntegerVariable; use crate::predicate; use crate::proof::ConstraintTag; use crate::proof::InferenceCode; +use crate::propagation::DomainEvents; +use crate::propagation::EnqueueDecision; +use crate::propagation::LocalId; +use crate::propagation::PropagationContext; +use crate::propagation::PropagationContextMut; +use crate::propagation::PropagationContextWithTrailedValues; +use crate::propagation::Propagator; +use crate::propagation::PropagatorConstructor; +use crate::propagation::PropagatorConstructorContext; +use crate::propagation::ReadDomains; use crate::pumpkin_assert_extreme; use crate::pumpkin_assert_moderate; use crate::pumpkin_assert_simple; diff --git a/pumpkin-crates/core/src/propagators/arithmetic/maximum.rs b/pumpkin-crates/core/src/propagators/arithmetic/maximum.rs index 13c65efed..219cc3783 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/maximum.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/maximum.rs @@ -2,17 +2,17 @@ use crate::basic_types::PropagationStatusCP; use crate::basic_types::PropositionalConjunction; use crate::conjunction; use crate::declare_inference_label; -use crate::engine::DomainEvents; -use crate::engine::cp::propagation::ReadDomains; -use crate::engine::propagation::LocalId; -use crate::engine::propagation::PropagationContextMut; -use crate::engine::propagation::Propagator; -use crate::engine::propagation::constructor::PropagatorConstructor; -use crate::engine::propagation::constructor::PropagatorConstructorContext; use crate::engine::variables::IntegerVariable; use crate::predicate; use crate::proof::ConstraintTag; use crate::proof::InferenceCode; +use crate::propagation::DomainEvents; +use crate::propagation::LocalId; +use crate::propagation::PropagationContextMut; +use crate::propagation::Propagator; +use crate::propagation::PropagatorConstructor; +use crate::propagation::PropagatorConstructorContext; +use crate::propagation::ReadDomains; #[derive(Clone, Debug)] pub(crate) struct MaximumArgs { diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/explanations/big_step.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/explanations/big_step.rs index 33b04df36..ae5b42f7e 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/explanations/big_step.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/explanations/big_step.rs @@ -1,11 +1,11 @@ use std::cmp::max; use std::rc::Rc; -use crate::engine::propagation::PropagationContext; -use crate::engine::propagation::ReadDomains; use crate::predicate; use crate::predicates::Predicate; use crate::predicates::PropositionalConjunction; +use crate::propagation::PropagationContext; +use crate::propagation::ReadDomains; use crate::propagators::ResourceProfile; use crate::propagators::Task; use crate::variables::IntegerVariable; diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/explanations/mod.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/explanations/mod.rs index 902beb439..32c3d6cb7 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/explanations/mod.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/explanations/mod.rs @@ -11,9 +11,9 @@ 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 crate::engine::propagation::PropagationContext; use crate::predicates::Predicate; use crate::predicates::PropositionalConjunction; +use crate::propagation::PropagationContext; use crate::propagators::ResourceProfile; use crate::propagators::Task; use crate::variables::IntegerVariable; diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/explanations/naive.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/explanations/naive.rs index 4c1f1270b..58e3b93b0 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/explanations/naive.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/explanations/naive.rs @@ -1,10 +1,10 @@ use std::rc::Rc; -use crate::engine::propagation::PropagationContext; -use crate::engine::propagation::ReadDomains; use crate::predicate; use crate::predicates::Predicate; use crate::predicates::PropositionalConjunction; +use crate::propagation::PropagationContext; +use crate::propagation::ReadDomains; use crate::propagators::ResourceProfile; use crate::propagators::Task; use crate::variables::IntegerVariable; diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/explanations/pointwise.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/explanations/pointwise.rs index 0b728c1bd..da2425e96 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/explanations/pointwise.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/explanations/pointwise.rs @@ -2,13 +2,12 @@ use std::rc::Rc; use crate::constraint_arguments::CumulativeExplanationType; use crate::engine::EmptyDomainConflict; -use crate::engine::propagation::PropagationContextMut; -use crate::engine::propagation::ReadDomains; -use crate::engine::propagation::contexts::propagation_context::HasAssignments; use crate::predicate; use crate::predicates::Predicate; use crate::predicates::PropositionalConjunction; use crate::proof::InferenceCode; +use crate::propagation::PropagationContextMut; +use crate::propagation::ReadDomains; use crate::propagators::ResourceProfile; use crate::propagators::Task; use crate::propagators::cumulative::time_table::explanations::add_propagating_task_predicate_lower_bound; @@ -72,7 +71,7 @@ pub(crate) fn propagate_lower_bounds_with_pointwise_explanations( mod tests { use crate::conjunction; use crate::engine::predicates::predicate::Predicate; - use crate::engine::propagation::EnqueueDecision; use crate::engine::test_solver::TestSolver; use crate::predicate; + use crate::propagation::EnqueueDecision; use crate::propagators::ArgTask; use crate::propagators::CumulativeExplanationType; use crate::propagators::CumulativePropagatorOptions; diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/synchronisation.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/synchronisation.rs index 048ef6533..61058bc8d 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/synchronisation.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/synchronisation.rs @@ -1,8 +1,8 @@ use std::rc::Rc; use crate::basic_types::PropagationStatusCP; -use crate::engine::propagation::PropagationContext; use crate::proof::InferenceCode; +use crate::propagation::PropagationContext; use crate::propagators::CumulativeParameters; use crate::propagators::PerPointTimeTableType; use crate::propagators::ResourceProfile; @@ -165,8 +165,8 @@ mod tests { use std::rc::Rc; use super::find_synchronised_conflict; - use crate::engine::propagation::LocalId; use crate::engine::test_solver::TestSolver; + use crate::propagation::LocalId; use crate::propagators::CumulativeParameters; use crate::propagators::CumulativePropagatorOptions; use crate::propagators::PerPointTimeTableType; diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/time_table_per_point_incremental.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/time_table_per_point_incremental.rs index a98ae5839..eccd8eb47 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/time_table_per_point_incremental.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/time_table_per_point_incremental.rs @@ -8,17 +8,17 @@ use crate::basic_types::PropagatorConflict; use crate::conjunction; use crate::engine::notifications::DomainEvent; use crate::engine::notifications::OpaqueDomainEvent; -use crate::engine::propagation::EnqueueDecision; -use crate::engine::propagation::LocalId; -use crate::engine::propagation::PropagationContext; -use crate::engine::propagation::PropagationContextMut; -use crate::engine::propagation::Propagator; -use crate::engine::propagation::constructor::PropagatorConstructor; -use crate::engine::propagation::constructor::PropagatorConstructorContext; -use crate::engine::propagation::contexts::PropagationContextWithTrailedValues; use crate::engine::variables::IntegerVariable; use crate::proof::ConstraintTag; use crate::proof::InferenceCode; +use crate::propagation::EnqueueDecision; +use crate::propagation::LocalId; +use crate::propagation::PropagationContext; +use crate::propagation::PropagationContextMut; +use crate::propagation::PropagationContextWithTrailedValues; +use crate::propagation::Propagator; +use crate::propagation::PropagatorConstructor; +use crate::propagation::PropagatorConstructorContext; use crate::propagators::ArgTask; use crate::propagators::CumulativeParameters; use crate::propagators::CumulativePropagatorOptions; @@ -553,8 +553,8 @@ impl Propagator /// Contains functions related to debugging mod debug { - use crate::engine::propagation::PropagationContext; use crate::proof::InferenceCode; + use crate::propagation::PropagationContext; use crate::propagators::CumulativeParameters; use crate::propagators::PerPointTimeTableType; use crate::propagators::create_time_table_per_point_from_scratch; @@ -623,10 +623,10 @@ mod debug { mod tests { use crate::conjunction; use crate::engine::predicates::predicate::Predicate; - use crate::engine::propagation::EnqueueDecision; use crate::engine::test_solver::TestSolver; use crate::predicate; use crate::predicates::PredicateConstructor; + use crate::propagation::EnqueueDecision; use crate::propagators::ArgTask; use crate::propagators::CumulativeExplanationType; use crate::propagators::CumulativePropagatorOptions; diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/propagation_handler.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/propagation_handler.rs index f378c2c29..31249fa6b 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/propagation_handler.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/propagation_handler.rs @@ -16,14 +16,14 @@ use super::explanations::pointwise::create_pointwise_conflict_explanation; use super::explanations::pointwise::create_pointwise_propagation_explanation; use crate::basic_types::PropagatorConflict; use crate::engine::EmptyDomainConflict; -use crate::engine::propagation::PropagationContext; -use crate::engine::propagation::PropagationContextMut; -use crate::engine::propagation::ReadDomains; -use crate::engine::propagation::contexts::HasAssignments; use crate::predicate; use crate::predicates::Predicate; use crate::predicates::PropositionalConjunction; use crate::proof::InferenceCode; +use crate::propagation::HasAssignments; +use crate::propagation::PropagationContext; +use crate::propagation::PropagationContextMut; +use crate::propagation::ReadDomains; use crate::propagators::ResourceProfile; use crate::propagators::Task; use crate::propagators::cumulative::time_table::explanations::pointwise; @@ -486,17 +486,17 @@ pub(crate) mod test_propagation_handler { use crate::engine::Assignments; use crate::engine::TrailedValues; use crate::engine::notifications::NotificationEngine; - use crate::engine::propagation::ExplanationContext; - use crate::engine::propagation::LocalId; - use crate::engine::propagation::PropagationContext; - use crate::engine::propagation::PropagationContextMut; - use crate::engine::propagation::PropagatorId; - use crate::engine::propagation::store::PropagatorStore; use crate::engine::reason::ReasonStore; use crate::predicate; use crate::predicates::Predicate; use crate::predicates::PropositionalConjunction; use crate::proof::InferenceCode; + use crate::propagation::ExplanationContext; + use crate::propagation::LocalId; + use crate::propagation::PropagationContext; + use crate::propagation::PropagationContextMut; + use crate::propagation::PropagatorId; + use crate::propagation::store::PropagatorStore; use crate::propagators::ResourceProfile; use crate::propagators::Task; use crate::variables::DomainId; diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_over_interval.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_over_interval.rs index 7be88a250..8e4499959 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_over_interval.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_over_interval.rs @@ -8,18 +8,18 @@ use crate::basic_types::PropagatorConflict; use crate::conjunction; use crate::engine::notifications::DomainEvent; use crate::engine::notifications::OpaqueDomainEvent; -use crate::engine::propagation::EnqueueDecision; -use crate::engine::propagation::LocalId; -use crate::engine::propagation::PropagationContext; -use crate::engine::propagation::PropagationContextMut; -use crate::engine::propagation::Propagator; -use crate::engine::propagation::ReadDomains; -use crate::engine::propagation::constructor::PropagatorConstructor; -use crate::engine::propagation::constructor::PropagatorConstructorContext; -use crate::engine::propagation::contexts::PropagationContextWithTrailedValues; use crate::engine::variables::IntegerVariable; use crate::proof::ConstraintTag; use crate::proof::InferenceCode; +use crate::propagation::EnqueueDecision; +use crate::propagation::LocalId; +use crate::propagation::PropagationContext; +use crate::propagation::PropagationContextMut; +use crate::propagation::PropagationContextWithTrailedValues; +use crate::propagation::Propagator; +use crate::propagation::PropagatorConstructor; +use crate::propagation::PropagatorConstructorContext; +use crate::propagation::ReadDomains; use crate::propagators::ArgTask; use crate::propagators::CumulativeParameters; use crate::propagators::CumulativePropagatorOptions; @@ -476,9 +476,9 @@ pub(crate) fn debug_propagate_from_scratch_time_table_interval { diff --git a/pumpkin-crates/core/src/propagators/disjunctive/theta_lambda_tree.rs b/pumpkin-crates/core/src/propagators/disjunctive/theta_lambda_tree.rs index 7e9fd87fa..69a83ccfc 100644 --- a/pumpkin-crates/core/src/propagators/disjunctive/theta_lambda_tree.rs +++ b/pumpkin-crates/core/src/propagators/disjunctive/theta_lambda_tree.rs @@ -3,9 +3,9 @@ use std::cmp::max; use super::disjunctive_task::DisjunctiveTask; use crate::containers::KeyedVec; use crate::containers::StorageKey; -use crate::engine::propagation::LocalId; -use crate::engine::propagation::PropagationContext; -use crate::engine::propagation::ReadDomains; +use crate::propagation::LocalId; +use crate::propagation::PropagationContext; +use crate::propagation::ReadDomains; use crate::pumpkin_assert_moderate; use crate::pumpkin_assert_simple; use crate::variables::IntegerVariable; @@ -379,9 +379,9 @@ impl ThetaLambdaTree { #[cfg(test)] mod tests { - use crate::engine::propagation::LocalId; - use crate::engine::propagation::PropagationContext; use crate::engine::test_solver::TestSolver; + use crate::propagation::LocalId; + use crate::propagation::PropagationContext; use crate::propagators::disjunctive::theta_lambda_tree::Node; use crate::propagators::disjunctive::theta_lambda_tree::ThetaLambdaTree; use crate::propagators::disjunctive_task::DisjunctiveTask; diff --git a/pumpkin-crates/core/src/propagators/disjunctive/theta_tree.rs b/pumpkin-crates/core/src/propagators/disjunctive/theta_tree.rs index 6fc0da72d..3b2fcc94c 100644 --- a/pumpkin-crates/core/src/propagators/disjunctive/theta_tree.rs +++ b/pumpkin-crates/core/src/propagators/disjunctive/theta_tree.rs @@ -3,9 +3,9 @@ use std::cmp::max; use super::disjunctive_task::DisjunctiveTask; use crate::containers::KeyedVec; use crate::containers::StorageKey; -use crate::engine::propagation::LocalId; -use crate::engine::propagation::PropagationContext; -use crate::engine::propagation::ReadDomains; +use crate::propagation::LocalId; +use crate::propagation::PropagationContext; +use crate::propagation::ReadDomains; use crate::pumpkin_assert_simple; use crate::variables::IntegerVariable; diff --git a/pumpkin-crates/core/src/propagators/element.rs b/pumpkin-crates/core/src/propagators/element.rs index f2c02c8fe..71d6e46eb 100644 --- a/pumpkin-crates/core/src/propagators/element.rs +++ b/pumpkin-crates/core/src/propagators/element.rs @@ -5,20 +5,20 @@ use bitfield_struct::bitfield; use crate::basic_types::PropagationStatusCP; use crate::conjunction; use crate::declare_inference_label; -use crate::engine::DomainEvents; -use crate::engine::propagation::ExplanationContext; -use crate::engine::propagation::LocalId; -use crate::engine::propagation::PropagationContextMut; -use crate::engine::propagation::Propagator; -use crate::engine::propagation::ReadDomains; -use crate::engine::propagation::constructor::PropagatorConstructor; -use crate::engine::propagation::constructor::PropagatorConstructorContext; use crate::engine::reason::Reason; use crate::engine::variables::IntegerVariable; use crate::predicate; use crate::predicates::Predicate; use crate::proof::ConstraintTag; use crate::proof::InferenceCode; +use crate::propagation::DomainEvents; +use crate::propagation::ExplanationContext; +use crate::propagation::LocalId; +use crate::propagation::PropagationContextMut; +use crate::propagation::Propagator; +use crate::propagation::PropagatorConstructor; +use crate::propagation::PropagatorConstructorContext; +use crate::propagation::ReadDomains; #[derive(Clone, Debug)] pub(crate) struct ElementArgs { diff --git a/pumpkin-crates/core/src/propagators/mod.rs b/pumpkin-crates/core/src/propagators/mod.rs index 7c8c73093..c87277c4d 100644 --- a/pumpkin-crates/core/src/propagators/mod.rs +++ b/pumpkin-crates/core/src/propagators/mod.rs @@ -1,6 +1,8 @@ //! Contains propagator implementations that are used in Pumpkin. //! -//! See the [`crate::engine::cp::propagation`] for info on propagators. +//! See the [`propagation`] for info on propagators. +#[cfg(doc)] +use crate::propagation; pub(crate) mod arithmetic; mod cumulative; diff --git a/pumpkin-crates/core/src/propagators/nogoods/nogood_propagator.rs b/pumpkin-crates/core/src/propagators/nogoods/nogood_propagator.rs index 47f79a310..589542685 100644 --- a/pumpkin-crates/core/src/propagators/nogoods/nogood_propagator.rs +++ b/pumpkin-crates/core/src/propagators/nogoods/nogood_propagator.rs @@ -18,19 +18,19 @@ use crate::engine::Lbd; use crate::engine::SolverStatistics; use crate::engine::notifications::NotificationEngine; use crate::engine::predicates::predicate::Predicate; -use crate::engine::propagation::EnqueueDecision; -use crate::engine::propagation::ExplanationContext; -use crate::engine::propagation::PropagationContext; -use crate::engine::propagation::PropagationContextMut; -use crate::engine::propagation::Propagator; -use crate::engine::propagation::ReadDomains; -use crate::engine::propagation::constructor::PropagatorConstructor; -use crate::engine::propagation::constructor::PropagatorConstructorContext; -use crate::engine::propagation::contexts::HasAssignments; use crate::engine::reason::Reason; use crate::engine::reason::ReasonStore; use crate::predicate; use crate::proof::InferenceCode; +use crate::propagation::EnqueueDecision; +use crate::propagation::ExplanationContext; +use crate::propagation::HasAssignments; +use crate::propagation::PropagationContext; +use crate::propagation::PropagationContextMut; +use crate::propagation::Propagator; +use crate::propagation::PropagatorConstructor; +use crate::propagation::PropagatorConstructorContext; +use crate::propagation::ReadDomains; use crate::propagators::nogoods::arena_allocator::ArenaAllocator; use crate::propagators::nogoods::arena_allocator::NogoodIndex; use crate::pumpkin_assert_advanced; diff --git a/pumpkin-crates/core/src/propagators/reified_propagator.rs b/pumpkin-crates/core/src/propagators/reified_propagator.rs index 4bb1684c2..c79381c4d 100644 --- a/pumpkin-crates/core/src/propagators/reified_propagator.rs +++ b/pumpkin-crates/core/src/propagators/reified_propagator.rs @@ -1,17 +1,17 @@ use crate::basic_types::PropagationStatusCP; -use crate::engine::DomainEvents; use crate::engine::notifications::OpaqueDomainEvent; -use crate::engine::propagation::EnqueueDecision; -use crate::engine::propagation::ExplanationContext; -use crate::engine::propagation::LocalId; -use crate::engine::propagation::PropagationContext; -use crate::engine::propagation::PropagationContextMut; -use crate::engine::propagation::Propagator; -use crate::engine::propagation::ReadDomains; -use crate::engine::propagation::constructor::PropagatorConstructor; -use crate::engine::propagation::constructor::PropagatorConstructorContext; -use crate::engine::propagation::contexts::PropagationContextWithTrailedValues; use crate::predicates::Predicate; +use crate::propagation::DomainEvents; +use crate::propagation::EnqueueDecision; +use crate::propagation::ExplanationContext; +use crate::propagation::LocalId; +use crate::propagation::PropagationContext; +use crate::propagation::PropagationContextMut; +use crate::propagation::PropagationContextWithTrailedValues; +use crate::propagation::Propagator; +use crate::propagation::PropagatorConstructor; +use crate::propagation::PropagatorConstructorContext; +use crate::propagation::ReadDomains; use crate::pumpkin_assert_simple; use crate::state::Conflict; use crate::variables::Literal; diff --git a/pumpkin-crates/core/src/statistics/statistic_logger.rs b/pumpkin-crates/core/src/statistics/statistic_logger.rs index c651dd4b2..26907ff3b 100644 --- a/pumpkin-crates/core/src/statistics/statistic_logger.rs +++ b/pumpkin-crates/core/src/statistics/statistic_logger.rs @@ -4,7 +4,7 @@ use itertools::Itertools; use super::statistic_logging::log_statistic; #[cfg(doc)] -use crate::engine::propagation::Propagator; +use crate::propagation::Propagator; /// Responsible for logging the statistics with the provided prefix; currently used when logging /// the statistics of propagators. From c376a3f16f1e7925d6d4f67667e1953b5bf4a3ca Mon Sep 17 00:00:00 2001 From: Maarten Flippo Date: Fri, 12 Dec 2025 14:39:38 +0100 Subject: [PATCH 02/29] Move PropagationContext to other module --- .../contexts/propagation_context.rs | 20 +------------------ .../core/src/propagation/domains.rs | 20 +++++++++++++++++++ pumpkin-crates/core/src/propagation/mod.rs | 2 ++ 3 files changed, 23 insertions(+), 19 deletions(-) create mode 100644 pumpkin-crates/core/src/propagation/domains.rs diff --git a/pumpkin-crates/core/src/propagation/contexts/propagation_context.rs b/pumpkin-crates/core/src/propagation/contexts/propagation_context.rs index 9a16fe103..23926c8a3 100644 --- a/pumpkin-crates/core/src/propagation/contexts/propagation_context.rs +++ b/pumpkin-crates/core/src/propagation/contexts/propagation_context.rs @@ -13,6 +13,7 @@ use crate::engine::reason::StoredReason; use crate::engine::variables::IntegerVariable; use crate::engine::variables::Literal; use crate::proof::InferenceCode; +use crate::propagation::PropagationContext; #[cfg(doc)] use crate::propagation::Propagator; use crate::propagation::PropagatorId; @@ -45,25 +46,6 @@ impl<'a> PropagationContextWithTrailedValues<'a> { } } -/// [`PropagationContext`] is passed to propagators during propagation. -/// It may be queried to retrieve information about the current variable domains such as the -/// lower-bound of a particular variable, or used to apply changes to the domain of a variable -/// e.g. set `[x >= 5]`. -/// -/// -/// Note that the [`PropagationContext`] is the only point of communication beween -/// the propagations and the solver during propagation. -#[derive(Clone, Copy, Debug)] -pub struct PropagationContext<'a> { - pub(crate) assignments: &'a Assignments, -} - -impl<'a> PropagationContext<'a> { - pub(crate) fn new(assignments: &'a Assignments) -> Self { - PropagationContext { assignments } - } -} - #[derive(Debug)] pub struct PropagationContextMut<'a> { pub(crate) trailed_values: &'a mut TrailedValues, diff --git a/pumpkin-crates/core/src/propagation/domains.rs b/pumpkin-crates/core/src/propagation/domains.rs new file mode 100644 index 000000000..8d7795f2b --- /dev/null +++ b/pumpkin-crates/core/src/propagation/domains.rs @@ -0,0 +1,20 @@ +use crate::engine::Assignments; + +/// [`PropagationContext`] is passed to propagators during propagation. +/// It may be queried to retrieve information about the current variable domains such as the +/// lower-bound of a particular variable, or used to apply changes to the domain of a variable +/// e.g. set `[x >= 5]`. +/// +/// +/// Note that the [`PropagationContext`] is the only point of communication beween +/// the propagations and the solver during propagation. +#[derive(Clone, Copy, Debug)] +pub struct PropagationContext<'a> { + pub(crate) assignments: &'a Assignments, +} + +impl<'a> PropagationContext<'a> { + pub(crate) fn new(assignments: &'a Assignments) -> Self { + PropagationContext { assignments } + } +} diff --git a/pumpkin-crates/core/src/propagation/mod.rs b/pumpkin-crates/core/src/propagation/mod.rs index 2fa4eb3c9..d451c5e7d 100644 --- a/pumpkin-crates/core/src/propagation/mod.rs +++ b/pumpkin-crates/core/src/propagation/mod.rs @@ -71,6 +71,7 @@ mod constructor; mod contexts; +mod domains; mod local_id; mod propagator; @@ -80,6 +81,7 @@ pub(crate) mod store; pub use constructor::*; pub use contexts::*; +pub use domains::*; pub use local_id::*; pub use propagator::*; pub use propagator_id::PropagatorId; From 14329e724f005e51eac2272b6c5b051e04faeea8 Mon Sep 17 00:00:00 2001 From: Maarten Flippo Date: Fri, 12 Dec 2025 15:06:18 +0100 Subject: [PATCH 03/29] Rename PropagationContext to Domains --- .../core/src/branching/selection_context.rs | 2 +- .../core/src/engine/cp/test_solver.rs | 6 ++-- .../core/src/engine/notifications/mod.rs | 4 +-- pumpkin-crates/core/src/engine/state.rs | 4 +-- .../core/src/propagation/constructor.rs | 6 ++-- .../contexts/propagation_context.rs | 16 ++++------ .../core/src/propagation/domains.rs | 25 +++++++++------- .../core/src/propagation/propagator.rs | 6 ++-- .../arithmetic/binary/binary_equals.rs | 4 +-- .../arithmetic/linear_less_or_equal.rs | 4 +-- .../arithmetic/linear_not_equal.rs | 15 ++++------ .../time_table/explanations/big_step.rs | 4 +-- .../cumulative/time_table/explanations/mod.rs | 10 +++---- .../time_table/explanations/naive.rs | 8 ++--- .../debug.rs | 4 +-- .../synchronisation.rs | 10 +++---- .../time_table_over_interval_incremental.rs | 13 +++----- .../synchronisation.rs | 6 ++-- .../time_table_per_point_incremental.rs | 17 ++++------- .../time_table/propagation_handler.rs | 8 ++--- .../time_table/time_table_over_interval.rs | 4 +-- .../time_table/time_table_per_point.rs | 4 +-- .../cumulative/time_table/time_table_util.rs | 30 +++++++++---------- .../utils/structs/updatable_structures.rs | 10 +++---- .../src/propagators/cumulative/utils/util.rs | 6 ++-- .../disjunctive/theta_lambda_tree.rs | 23 +++++--------- .../src/propagators/disjunctive/theta_tree.rs | 6 ++-- .../propagators/nogoods/nogood_propagator.rs | 4 +-- .../src/propagators/reified_propagator.rs | 11 ++----- 29 files changed, 120 insertions(+), 150 deletions(-) diff --git a/pumpkin-crates/core/src/branching/selection_context.rs b/pumpkin-crates/core/src/branching/selection_context.rs index 0433e8889..26c4fd86a 100644 --- a/pumpkin-crates/core/src/branching/selection_context.rs +++ b/pumpkin-crates/core/src/branching/selection_context.rs @@ -12,7 +12,7 @@ use crate::engine::variables::DomainGeneratorIterator; use crate::engine::variables::DomainId; use crate::engine::variables::IntegerVariable; #[cfg(doc)] -use crate::propagation::PropagationContext; +use crate::propagation::Domains; /// The context provided to the [`Brancher`], /// it allows the retrieval of domain values of variables and access to methods from a [`Random`] diff --git a/pumpkin-crates/core/src/engine/cp/test_solver.rs b/pumpkin-crates/core/src/engine/cp/test_solver.rs index c04110b4f..6ee13a167 100644 --- a/pumpkin-crates/core/src/engine/cp/test_solver.rs +++ b/pumpkin-crates/core/src/engine/cp/test_solver.rs @@ -17,9 +17,9 @@ use crate::predicate; use crate::predicates::PropositionalConjunction; use crate::proof::ConstraintTag; use crate::proof::InferenceCode; +use crate::propagation::Domains; use crate::propagation::EnqueueDecision; use crate::propagation::ExplanationContext; -use crate::propagation::PropagationContext; use crate::propagation::PropagationContextMut; use crate::propagation::PropagatorConstructor; use crate::propagation::PropagatorId; @@ -338,8 +338,6 @@ impl TestSolver { self.state .propagators .iter_propagators_mut() - .for_each(|propagator| { - propagator.synchronise(PropagationContext::new(&self.state.assignments)) - }) + .for_each(|propagator| propagator.synchronise(Domains::new(&self.state.assignments))) } } diff --git a/pumpkin-crates/core/src/engine/notifications/mod.rs b/pumpkin-crates/core/src/engine/notifications/mod.rs index eaa7467de..6ccefcb87 100644 --- a/pumpkin-crates/core/src/engine/notifications/mod.rs +++ b/pumpkin-crates/core/src/engine/notifications/mod.rs @@ -17,9 +17,9 @@ use crate::engine::Assignments; use crate::engine::PropagatorQueue; use crate::engine::TrailedValues; use crate::predicates::Predicate; +use crate::propagation::Domains; use crate::propagation::EnqueueDecision; use crate::propagation::LocalId; -use crate::propagation::PropagationContext; use crate::propagation::PropagationContextWithTrailedValues; use crate::propagation::PropagatorId; use crate::propagation::PropagatorVarId; @@ -327,7 +327,7 @@ impl NotificationEngine { .get_backtrack_affected_propagators(event, domain) { let propagator = &mut propagators[propagator_var.propagator]; - let context = PropagationContext::new(assignments); + let context = Domains::new(assignments); propagator.notify_backtrack(context, propagator_var.variable, event.into()) } diff --git a/pumpkin-crates/core/src/engine/state.rs b/pumpkin-crates/core/src/engine/state.rs index 7dc7cde0d..5984e4e17 100644 --- a/pumpkin-crates/core/src/engine/state.rs +++ b/pumpkin-crates/core/src/engine/state.rs @@ -22,8 +22,8 @@ use crate::proof::InferenceLabel; #[cfg(doc)] use crate::proof::ProofLog; use crate::propagation::CurrentNogood; +use crate::propagation::Domains; use crate::propagation::ExplanationContext; -use crate::propagation::PropagationContext; use crate::propagation::PropagationContextMut; use crate::propagation::Propagator; use crate::propagation::PropagatorConstructor; @@ -505,7 +505,7 @@ impl State { // + allow incremental synchronisation // + only call the subset of propagators that were notified since last backtrack for propagator in self.propagators.iter_propagators_mut() { - let context = PropagationContext::new(&self.assignments); + let context = Domains::new(&self.assignments); propagator.synchronise(context); } diff --git a/pumpkin-crates/core/src/propagation/constructor.rs b/pumpkin-crates/core/src/propagation/constructor.rs index 62f89d301..28a80b6f4 100644 --- a/pumpkin-crates/core/src/propagation/constructor.rs +++ b/pumpkin-crates/core/src/propagation/constructor.rs @@ -1,8 +1,8 @@ use std::ops::Deref; use std::ops::DerefMut; +use super::Domains; use super::LocalId; -use super::PropagationContext; use super::Propagator; use super::PropagatorId; use super::PropagatorVarId; @@ -66,8 +66,8 @@ impl PropagatorConstructorContext<'_> { } /// Get domain information. - pub fn as_readonly(&self) -> PropagationContext<'_> { - PropagationContext { + pub fn as_readonly(&self) -> Domains<'_> { + Domains { assignments: &self.state.assignments, } } diff --git a/pumpkin-crates/core/src/propagation/contexts/propagation_context.rs b/pumpkin-crates/core/src/propagation/contexts/propagation_context.rs index 23926c8a3..a6d4fb59d 100644 --- a/pumpkin-crates/core/src/propagation/contexts/propagation_context.rs +++ b/pumpkin-crates/core/src/propagation/contexts/propagation_context.rs @@ -13,7 +13,7 @@ use crate::engine::reason::StoredReason; use crate::engine::variables::IntegerVariable; use crate::engine::variables::Literal; use crate::proof::InferenceCode; -use crate::propagation::PropagationContext; +use crate::propagation::Domains; #[cfg(doc)] use crate::propagation::Propagator; use crate::propagation::PropagatorId; @@ -39,8 +39,8 @@ impl<'a> PropagationContextWithTrailedValues<'a> { } } - pub(crate) fn as_readonly(&self) -> PropagationContext<'_> { - PropagationContext { + pub(crate) fn as_readonly(&self) -> Domains<'_> { + Domains { assignments: self.assignments, } } @@ -118,8 +118,8 @@ impl<'a> PropagationContextMut<'a> { } /// Get the current domain information. - pub fn as_readonly(&self) -> PropagationContext<'_> { - PropagationContext { + pub fn as_readonly(&self) -> Domains<'_> { + Domains { assignments: self.assignments, } } @@ -183,12 +183,6 @@ mod private { } } - impl HasAssignments for PropagationContext<'_> { - fn assignments(&self) -> &Assignments { - self.assignments - } - } - impl HasAssignments for PropagationContextMut<'_> { fn assignments(&self) -> &Assignments { self.assignments diff --git a/pumpkin-crates/core/src/propagation/domains.rs b/pumpkin-crates/core/src/propagation/domains.rs index 8d7795f2b..f4546f8f4 100644 --- a/pumpkin-crates/core/src/propagation/domains.rs +++ b/pumpkin-crates/core/src/propagation/domains.rs @@ -1,20 +1,25 @@ use crate::engine::Assignments; +use crate::propagation::HasAssignments; +#[cfg(doc)] +use crate::propagation::ReadDomains; -/// [`PropagationContext`] is passed to propagators during propagation. -/// It may be queried to retrieve information about the current variable domains such as the -/// lower-bound of a particular variable, or used to apply changes to the domain of a variable -/// e.g. set `[x >= 5]`. +/// Provides access to domain information to propagators. /// -/// -/// Note that the [`PropagationContext`] is the only point of communication beween -/// the propagations and the solver during propagation. +/// Implements [`ReadDomains`] to expose information about the current variable domains such as the +/// lower-bound of a particular variable. #[derive(Clone, Copy, Debug)] -pub struct PropagationContext<'a> { +pub struct Domains<'a> { pub(crate) assignments: &'a Assignments, } -impl<'a> PropagationContext<'a> { +impl<'a> Domains<'a> { pub(crate) fn new(assignments: &'a Assignments) -> Self { - PropagationContext { assignments } + Domains { assignments } + } +} + +impl HasAssignments for Domains<'_> { + fn assignments(&self) -> &Assignments { + self.assignments } } diff --git a/pumpkin-crates/core/src/propagation/propagator.rs b/pumpkin-crates/core/src/propagation/propagator.rs index 7aec68b80..c5433f726 100644 --- a/pumpkin-crates/core/src/propagation/propagator.rs +++ b/pumpkin-crates/core/src/propagation/propagator.rs @@ -3,8 +3,8 @@ use downcast_rs::impl_downcast; use dyn_clone::DynClone; use dyn_clone::clone_trait_object; +use super::Domains; use super::ExplanationContext; -use super::PropagationContext; use super::PropagationContextMut; use super::contexts::PropagationContextWithTrailedValues; use crate::basic_types::PredicateId; @@ -109,7 +109,7 @@ pub trait Propagator: Downcast + DynClone { /// benefit from implementing this, so it is not required to do so. fn notify_backtrack( &mut self, - _context: PropagationContext, + _context: Domains, _local_id: LocalId, _event: OpaqueDomainEvent, ) { @@ -126,7 +126,7 @@ pub trait Propagator: Downcast + DynClone { /// update its internal data structures given the new variable domains. /// /// By default this function does nothing. - fn synchronise(&mut self, _context: PropagationContext) {} + fn synchronise(&mut self, _context: Domains) {} /// Returns the priority of the propagator represented as an integer. Lower values mean higher /// priority and the priority determines the order in which propagators will be asked to diff --git a/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_equals.rs b/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_equals.rs index 7e9d73f69..b364f112e 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_equals.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_equals.rs @@ -20,10 +20,10 @@ use crate::predicates::PredicateType; use crate::proof::ConstraintTag; use crate::proof::InferenceCode; use crate::propagation::DomainEvents; +use crate::propagation::Domains; use crate::propagation::EnqueueDecision; use crate::propagation::ExplanationContext; use crate::propagation::LocalId; -use crate::propagation::PropagationContext; use crate::propagation::PropagationContextMut; use crate::propagation::PropagationContextWithTrailedValues; use crate::propagation::Propagator; @@ -212,7 +212,7 @@ where EnqueueDecision::Enqueue } - fn synchronise(&mut self, _context: PropagationContext) { + fn synchronise(&mut self, _context: Domains) { // Recall that we need to ensure that the stored removed values could now be inaccurate self.has_backtracked = true; } diff --git a/pumpkin-crates/core/src/propagators/arithmetic/linear_less_or_equal.rs b/pumpkin-crates/core/src/propagators/arithmetic/linear_less_or_equal.rs index 263a38f7a..8e17697d5 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/linear_less_or_equal.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/linear_less_or_equal.rs @@ -10,11 +10,11 @@ use crate::predicates::Predicate; use crate::proof::ConstraintTag; use crate::proof::InferenceCode; use crate::propagation::DomainEvents; +use crate::propagation::Domains; use crate::propagation::EnqueueDecision; use crate::propagation::ExplanationContext; use crate::propagation::LocalId; use crate::propagation::ManipulateTrailedValues; -use crate::propagation::PropagationContext; use crate::propagation::PropagationContextMut; use crate::propagation::PropagationContextWithTrailedValues; use crate::propagation::Propagator; @@ -92,7 +92,7 @@ impl LinearLessOrEqualPropagator where Var: IntegerVariable, { - fn create_conflict(&self, context: PropagationContext) -> PropagatorConflict { + fn create_conflict(&self, context: Domains) -> PropagatorConflict { PropagatorConflict { conjunction: self .x diff --git a/pumpkin-crates/core/src/propagators/arithmetic/linear_not_equal.rs b/pumpkin-crates/core/src/propagators/arithmetic/linear_not_equal.rs index da8301907..f2d310d8f 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/linear_not_equal.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/linear_not_equal.rs @@ -13,9 +13,9 @@ use crate::predicate; use crate::proof::ConstraintTag; use crate::proof::InferenceCode; use crate::propagation::DomainEvents; +use crate::propagation::Domains; use crate::propagation::EnqueueDecision; use crate::propagation::LocalId; -use crate::propagation::PropagationContext; use crate::propagation::PropagationContextMut; use crate::propagation::PropagationContextWithTrailedValues; use crate::propagation::Propagator; @@ -145,12 +145,7 @@ where } } - fn notify_backtrack( - &mut self, - _context: PropagationContext, - local_id: LocalId, - event: OpaqueDomainEvent, - ) { + fn notify_backtrack(&mut self, _context: Domains, local_id: LocalId, event: OpaqueDomainEvent) { if matches!( self.terms[local_id.unpack() as usize].unpack_event(event), DomainEvent::Assign @@ -304,7 +299,7 @@ impl LinearNotEqualPropagator { /// Note that this method always sets the `unfixed_variable_has_been_updated` to true; this /// might be too lenient as it could be the case that synchronisation does not lead to the /// re-adding of the removed value. - fn recalculate_fixed_variables(&mut self, context: PropagationContext) { + fn recalculate_fixed_variables(&mut self, context: Domains) { self.unfixed_variable_has_been_updated = false; (self.fixed_lhs, self.number_of_fixed_terms) = self.terms @@ -322,7 +317,7 @@ impl LinearNotEqualPropagator { } /// Determines whether a conflict has occurred and calculate the reason for the conflict - fn check_for_conflict(&self, context: PropagationContext) -> Result<(), PropagatorConflict> { + fn check_for_conflict(&self, context: Domains) -> Result<(), PropagatorConflict> { pumpkin_assert_simple!(!self.should_recalculate_lhs); if self.number_of_fixed_terms == self.terms.len() && self.fixed_lhs == self.rhs { let conjunction = self @@ -342,7 +337,7 @@ impl LinearNotEqualPropagator { /// Checks whether the number of fixed terms is equal to the number of fixed terms in the /// provided [`PropagationContext`] and whether the value of the fixed lhs is the same as in the /// provided [`PropagationContext`]. - fn is_propagator_state_consistent(&self, context: PropagationContext) -> bool { + fn is_propagator_state_consistent(&self, context: Domains) -> bool { let expected_number_of_fixed_terms = self .terms .iter() diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/explanations/big_step.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/explanations/big_step.rs index ae5b42f7e..45b150cd0 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/explanations/big_step.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/explanations/big_step.rs @@ -4,7 +4,7 @@ use std::rc::Rc; use crate::predicate; use crate::predicates::Predicate; use crate::predicates::PropositionalConjunction; -use crate::propagation::PropagationContext; +use crate::propagation::Domains; use crate::propagation::ReadDomains; use crate::propagators::ResourceProfile; use crate::propagators::Task; @@ -62,7 +62,7 @@ where pub(crate) fn create_big_step_predicate_propagating_task_upper_bound_propagation( task: &Rc>, profile: &ResourceProfile, - context: PropagationContext, + context: Domains, ) -> Predicate where Var: IntegerVariable + 'static, diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/explanations/mod.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/explanations/mod.rs index 32c3d6cb7..cc96aae27 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/explanations/mod.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/explanations/mod.rs @@ -13,7 +13,7 @@ use pointwise::create_pointwise_predicate_propagating_task_upper_bound_propagati use crate::predicates::Predicate; use crate::predicates::PropositionalConjunction; -use crate::propagation::PropagationContext; +use crate::propagation::Domains; use crate::propagators::ResourceProfile; use crate::propagators::Task; use crate::variables::IntegerVariable; @@ -73,7 +73,7 @@ pub(crate) fn create_predicate_propagating_task_lower_bound_propagation< Var: IntegerVariable + 'static, >( explanation_type: CumulativeExplanationType, - context: PropagationContext, + context: Domains, task: &Rc>, profile: &ResourceProfile, time_point: Option, @@ -95,7 +95,7 @@ pub(crate) fn create_predicate_propagating_task_lower_bound_propagation< pub(crate) fn add_propagating_task_predicate_lower_bound( mut explanation: PropositionalConjunction, explanation_type: CumulativeExplanationType, - context: PropagationContext, + context: Domains, task: &Rc>, profile: &ResourceProfile, time_point: Option, @@ -115,7 +115,7 @@ pub(crate) fn create_predicate_propagating_task_upper_bound_propagation< Var: IntegerVariable + 'static, >( explanation_type: CumulativeExplanationType, - context: PropagationContext, + context: Domains, task: &Rc>, profile: &ResourceProfile, time_point: Option, @@ -139,7 +139,7 @@ pub(crate) fn create_predicate_propagating_task_upper_bound_propagation< pub(crate) fn add_propagating_task_predicate_upper_bound( mut explanation: PropositionalConjunction, explanation_type: CumulativeExplanationType, - context: PropagationContext, + context: Domains, task: &Rc>, profile: &ResourceProfile, time_point: Option, diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/explanations/naive.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/explanations/naive.rs index 58e3b93b0..a0cc5fa5e 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/explanations/naive.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/explanations/naive.rs @@ -3,7 +3,7 @@ use std::rc::Rc; use crate::predicate; use crate::predicates::Predicate; use crate::predicates::PropositionalConjunction; -use crate::propagation::PropagationContext; +use crate::propagation::Domains; use crate::propagation::ReadDomains; use crate::propagators::ResourceProfile; use crate::propagators::Task; @@ -13,7 +13,7 @@ use crate::variables::IntegerVariable; /// [`CumulativeExplanationType::Naive`]) pub(crate) fn create_naive_propagation_explanation( profile: &ResourceProfile, - context: PropagationContext, + context: Domains, ) -> PropositionalConjunction { profile .profile_tasks @@ -61,7 +61,7 @@ where } pub(crate) fn create_naive_predicate_propagating_task_lower_bound_propagation( - context: PropagationContext, + context: Domains, task: &Rc>, ) -> Predicate where @@ -71,7 +71,7 @@ where } pub(crate) fn create_naive_predicate_propagating_task_upper_bound_propagation( - context: PropagationContext, + context: Domains, task: &Rc>, ) -> Predicate where diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/debug.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/debug.rs index 6c165fccb..83ca04e55 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/debug.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/debug.rs @@ -3,7 +3,7 @@ use std::ops::Range; use crate::containers::HashSet; use crate::proof::InferenceCode; -use crate::propagation::PropagationContext; +use crate::propagation::Domains; use crate::propagators::CumulativeParameters; use crate::propagators::OverIntervalTimeTableType; use crate::propagators::ResourceProfile; @@ -25,7 +25,7 @@ pub(crate) fn time_tables_are_the_same_interval< Var: IntegerVariable + 'static, const SYNCHRONISE: bool, >( - context: PropagationContext, + context: Domains, inference_code: InferenceCode, time_table: &OverIntervalTimeTableType, parameters: &CumulativeParameters, diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/synchronisation.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/synchronisation.rs index aaa294fca..019af1581 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/synchronisation.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/synchronisation.rs @@ -4,7 +4,7 @@ use super::debug::are_mergeable; use super::debug::merge_profiles; use crate::basic_types::PropagationStatusCP; use crate::proof::InferenceCode; -use crate::propagation::PropagationContext; +use crate::propagation::Domains; use crate::propagation::ReadDomains; use crate::propagators::CumulativeParameters; use crate::propagators::OverIntervalTimeTableType; @@ -57,7 +57,7 @@ pub(crate) fn check_synchronisation_conflict_explanation_over_interval< Var: IntegerVariable + 'static, >( synchronised_conflict_explanation: &PropagationStatusCP, - context: PropagationContext, + context: Domains, parameters: &CumulativeParameters, inference_code: InferenceCode, ) -> bool { @@ -81,7 +81,7 @@ pub(crate) fn check_synchronisation_conflict_explanation_over_interval< /// been reported by [`TimeTableOverIntervalPropagator`] by finding the tasks which should be /// included in the profile and sorting them in the same order. pub(crate) fn create_synchronised_conflict_explanation( - context: PropagationContext, + context: Domains, inference_code: InferenceCode, conflicting_profile: &mut ResourceProfile, parameters: &CumulativeParameters, @@ -127,7 +127,7 @@ pub(crate) fn create_synchronised_conflict_explanation( time_table: &mut OverIntervalTimeTableType, - context: PropagationContext, + context: Domains, ) { if !time_table.is_empty() { // If the time-table is not empty then we merge all the profiles in the range @@ -145,7 +145,7 @@ pub(crate) fn synchronise_time_table( /// non-decreasing order of ID fn sort_profile_based_on_upper_bound_and_id( profile: &mut ResourceProfile, - context: PropagationContext, + context: Domains, ) { profile.profile_tasks.sort_by(|a, b| { // First match on the upper-bound of the variable diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/time_table_over_interval_incremental.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/time_table_over_interval_incremental.rs index b3597baeb..5858bc9af 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/time_table_over_interval_incremental.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/time_table_over_interval_incremental.rs @@ -14,7 +14,7 @@ use crate::propagation::PropagationContextWithTrailedValues; use crate::propagation::PropagatorConstructor; use crate::propagation::EnqueueDecision; use crate::propagation::LocalId; -use crate::propagation::PropagationContext; +use crate::propagation::Domains; use crate::propagation::PropagationContextMut; use crate::propagation::Propagator; use crate::engine::variables::IntegerVariable; @@ -155,7 +155,7 @@ impl /// that all of the adjustments are applied even if a conflict is found. fn add_to_time_table( &mut self, - context: PropagationContext, + context: Domains, mandatory_part_adjustments: &MandatoryPartAdjustments, task: &Rc>, ) -> PropagationStatusCP { @@ -459,12 +459,7 @@ impl Propagator result.decision } - fn notify_backtrack( - &mut self, - context: PropagationContext, - local_id: LocalId, - event: OpaqueDomainEvent, - ) { + fn notify_backtrack(&mut self, context: Domains, local_id: LocalId, event: OpaqueDomainEvent) { pumpkin_assert_simple!(self.parameters.options.incremental_backtracking); let updated_task = Rc::clone(&self.parameters.tasks[local_id.unpack() as usize]); @@ -486,7 +481,7 @@ impl Propagator } } - fn synchronise(&mut self, context: PropagationContext) { + fn synchronise(&mut self, context: Domains) { // We now recalculate the time-table from scratch if necessary and reset all of the bounds // *if* incremental backtracking is disabled if !self.parameters.options.incremental_backtracking { diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/synchronisation.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/synchronisation.rs index 61058bc8d..c5a0fec47 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/synchronisation.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/synchronisation.rs @@ -2,7 +2,7 @@ use std::rc::Rc; use crate::basic_types::PropagationStatusCP; use crate::proof::InferenceCode; -use crate::propagation::PropagationContext; +use crate::propagation::Domains; use crate::propagators::CumulativeParameters; use crate::propagators::PerPointTimeTableType; use crate::propagators::ResourceProfile; @@ -20,7 +20,7 @@ pub(crate) fn check_synchronisation_conflict_explanation_per_point< Var: IntegerVariable + 'static, >( synchronised_conflict_explanation: &PropagationStatusCP, - context: PropagationContext, + context: Domains, inference_code: InferenceCode, parameters: &CumulativeParameters, ) -> bool { @@ -110,7 +110,7 @@ fn get_minimum_set_of_tasks_which_overflow_capacity<'a, Var: IntegerVariable + ' /// reported by [`TimeTablePerPointPropagator`] by finding the tasks which should be included in the /// profile and sorting them in the same order. pub(crate) fn create_synchronised_conflict_explanation( - context: PropagationContext, + context: Domains, inference_code: InferenceCode, conflicting_profile: &mut ResourceProfile, parameters: &CumulativeParameters, diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/time_table_per_point_incremental.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/time_table_per_point_incremental.rs index eccd8eb47..174cd7340 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/time_table_per_point_incremental.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/time_table_per_point_incremental.rs @@ -11,9 +11,9 @@ use crate::engine::notifications::OpaqueDomainEvent; use crate::engine::variables::IntegerVariable; use crate::proof::ConstraintTag; use crate::proof::InferenceCode; +use crate::propagation::Domains; use crate::propagation::EnqueueDecision; use crate::propagation::LocalId; -use crate::propagation::PropagationContext; use crate::propagation::PropagationContextMut; use crate::propagation::PropagationContextWithTrailedValues; use crate::propagation::Propagator; @@ -144,7 +144,7 @@ impl /// that all of the adjustments are applied even if a conflict is found. fn add_to_time_table( &mut self, - context: PropagationContext, + context: Domains, mandatory_part_adjustments: &MandatoryPartAdjustments, task: &Rc>, ) -> PropagationStatusCP { @@ -486,12 +486,7 @@ impl Propagator result.decision } - fn notify_backtrack( - &mut self, - context: PropagationContext, - local_id: LocalId, - event: OpaqueDomainEvent, - ) { + fn notify_backtrack(&mut self, context: Domains, local_id: LocalId, event: OpaqueDomainEvent) { let updated_task = Rc::clone(&self.parameters.tasks[local_id.unpack() as usize]); backtrack_update(context, &mut self.updatable_structures, &updated_task); @@ -511,7 +506,7 @@ impl Propagator } } - fn synchronise(&mut self, context: PropagationContext) { + fn synchronise(&mut self, context: Domains) { // We now recalculate the time-table from scratch if necessary and reset all of the bounds // *if* incremental backtracking is disabled if !self.parameters.options.incremental_backtracking { @@ -554,7 +549,7 @@ impl Propagator mod debug { use crate::proof::InferenceCode; - use crate::propagation::PropagationContext; + use crate::propagation::Domains; use crate::propagators::CumulativeParameters; use crate::propagators::PerPointTimeTableType; use crate::propagators::create_time_table_per_point_from_scratch; @@ -573,7 +568,7 @@ mod debug { Var: IntegerVariable + 'static, const SYNCHRONISE: bool, >( - context: PropagationContext, + context: Domains, inference_code: InferenceCode, time_table: &PerPointTimeTableType, parameters: &CumulativeParameters, diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/propagation_handler.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/propagation_handler.rs index 31249fa6b..601a01c0a 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/propagation_handler.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/propagation_handler.rs @@ -20,8 +20,8 @@ use crate::predicate; use crate::predicates::Predicate; use crate::predicates::PropositionalConjunction; use crate::proof::InferenceCode; +use crate::propagation::Domains; use crate::propagation::HasAssignments; -use crate::propagation::PropagationContext; use crate::propagation::PropagationContextMut; use crate::propagation::ReadDomains; use crate::propagators::ResourceProfile; @@ -46,7 +46,7 @@ pub(crate) struct CumulativePropagationHandler { fn check_explanation( explained_predicate: Predicate, explanation: &PropositionalConjunction, - context: PropagationContext, + context: Domains, ) -> bool { let all_predicates_hold = explanation .iter() @@ -491,9 +491,9 @@ pub(crate) mod test_propagation_handler { use crate::predicates::Predicate; use crate::predicates::PropositionalConjunction; use crate::proof::InferenceCode; + use crate::propagation::Domains; use crate::propagation::ExplanationContext; use crate::propagation::LocalId; - use crate::propagation::PropagationContext; use crate::propagation::PropagationContextMut; use crate::propagation::PropagatorId; use crate::propagation::store::PropagatorStore; @@ -548,7 +548,7 @@ pub(crate) mod test_propagation_handler { }; let reason = create_conflict_explanation( - PropagationContext::new(&self.assignments), + Domains::new(&self.assignments), self.propagation_handler.inference_code, &profile, self.propagation_handler.explanation_type, diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_over_interval.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_over_interval.rs index 8e4499959..b4e1dde55 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_over_interval.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_over_interval.rs @@ -11,9 +11,9 @@ use crate::engine::notifications::OpaqueDomainEvent; use crate::engine::variables::IntegerVariable; use crate::proof::ConstraintTag; use crate::proof::InferenceCode; +use crate::propagation::Domains; use crate::propagation::EnqueueDecision; use crate::propagation::LocalId; -use crate::propagation::PropagationContext; use crate::propagation::PropagationContextMut; use crate::propagation::PropagationContextWithTrailedValues; use crate::propagation::Propagator; @@ -142,7 +142,7 @@ impl Propagator for TimeTableOverIntervalPropaga ) } - fn synchronise(&mut self, context: PropagationContext) { + fn synchronise(&mut self, context: Domains) { self.updatable_structures .reset_all_bounds_and_remove_fixed(context, &self.parameters); } diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_per_point.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_per_point.rs index e9fa5bb9a..b69814b7d 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_per_point.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_per_point.rs @@ -16,9 +16,9 @@ use crate::engine::notifications::OpaqueDomainEvent; use crate::engine::variables::IntegerVariable; use crate::proof::ConstraintTag; use crate::proof::InferenceCode; +use crate::propagation::Domains; use crate::propagation::EnqueueDecision; use crate::propagation::LocalId; -use crate::propagation::PropagationContext; use crate::propagation::PropagationContextMut; use crate::propagation::PropagationContextWithTrailedValues; use crate::propagation::Propagator; @@ -133,7 +133,7 @@ impl Propagator for TimeTablePerPointPropagator< ) } - fn synchronise(&mut self, context: PropagationContext) { + fn synchronise(&mut self, context: Domains) { self.updatable_structures .reset_all_bounds_and_remove_fixed(context, &self.parameters) } diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_util.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_util.rs index 34a084e6c..39abdcfe6 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_util.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_util.rs @@ -8,8 +8,8 @@ use std::rc::Rc; use crate::basic_types::PropagationStatusCP; use crate::engine::variables::IntegerVariable; use crate::proof::InferenceCode; +use crate::propagation::Domains; use crate::propagation::EnqueueDecision; -use crate::propagation::PropagationContext; use crate::propagation::PropagationContextMut; #[cfg(doc)] use crate::propagation::Propagator; @@ -44,7 +44,7 @@ pub(crate) fn should_enqueue( parameters: &CumulativeParameters, updatable_structures: &UpdatableStructures, updated_task: &Rc>, - context: PropagationContext, + context: Domains, empty_time_table: bool, ) -> ShouldEnqueueResult { pumpkin_assert_extreme!( @@ -106,7 +106,7 @@ pub(crate) fn should_enqueue( } pub(crate) fn has_mandatory_part( - context: PropagationContext, + context: Domains, task: &Rc>, ) -> bool { context.upper_bound(&task.start_variable) @@ -116,7 +116,7 @@ pub(crate) fn has_mandatory_part( /// Checks whether a specific task (indicated by id) has a mandatory part which overlaps with the /// interval [start, end] pub(crate) fn has_mandatory_part_in_interval( - context: PropagationContext, + context: Domains, task: &Rc>, start: i32, end: i32, @@ -133,7 +133,7 @@ pub(crate) fn has_mandatory_part_in_interval( /// Checks whether the lower and upper bound of a task overlap with the provided interval pub(crate) fn task_has_overlap_with_interval( - context: PropagationContext, + context: Domains, task: &Rc>, start: i32, end: i32, @@ -585,7 +585,7 @@ fn sweep_backward<'a, Var: IntegerVariable + 'static>( fn find_profiles_which_propagate_lower_bound<'a, Var: IntegerVariable + 'static>( profile_index: usize, time_table: &[&'a ResourceProfile], - context: PropagationContext, + context: Domains, task: &Rc>, capacity: i32, profile_buffer: &mut Vec<&'a ResourceProfile>, @@ -618,7 +618,7 @@ fn find_profiles_which_propagate_lower_bound<'a, Var: IntegerVariable + 'static> fn find_profiles_which_propagate_upper_bound<'a, Var: IntegerVariable + 'static>( profile_index: usize, time_table: &[&'a ResourceProfile], - context: PropagationContext, + context: Domains, task: &Rc>, capacity: i32, profile_buffer: &mut Vec<&'a ResourceProfile>, @@ -663,7 +663,7 @@ fn find_profiles_which_propagate_upper_bound<'a, Var: IntegerVariable + 'static> /// Note: It is assumed that task.resource_usage + height > capacity (i.e. the task has the /// potential to overflow the capacity in combination with the profile) fn lower_bound_can_be_propagated_by_profile( - context: PropagationContext, + context: Domains, task: &Rc>, profile: &ResourceProfile, capacity: i32, @@ -680,7 +680,7 @@ fn lower_bound_can_be_propagated_by_profile( /// * ub(s) <= end, i.e. the latest start time is before the end of the [`ResourceProfile`] /// Note: It is assumed that the task is known to overflow the [`ResourceProfile`] fn upper_bound_can_be_propagated_by_profile( - context: PropagationContext, + context: Domains, task: &Rc>, profile: &ResourceProfile, capacity: i32, @@ -698,7 +698,7 @@ fn upper_bound_can_be_propagated_by_profile( /// If the first condition is true, the second false and the third true then this method returns /// true (otherwise it returns false) fn can_be_updated_by_profile( - context: PropagationContext, + context: Domains, task: &Rc>, profile: &ResourceProfile, capacity: i32, @@ -714,7 +714,7 @@ fn can_be_updated_by_profile( /// If the first condition is true, and the second false then this method returns /// true (otherwise it returns false) fn overflows_capacity_and_is_not_part_of_profile( - context: PropagationContext, + context: Domains, task: &Rc>, profile: &ResourceProfile, capacity: i32, @@ -735,7 +735,7 @@ pub(crate) fn insert_update( } pub(crate) fn backtrack_update( - context: PropagationContext, + context: Domains, updatable_structures: &mut UpdatableStructures, updated_task: &Rc>, ) { @@ -782,8 +782,8 @@ mod tests { use super::find_profiles_which_propagate_lower_bound; use crate::engine::Assignments; + use crate::propagation::Domains; use crate::propagation::LocalId; - use crate::propagation::PropagationContext; use crate::propagators::ResourceProfile; use crate::propagators::Task; use crate::propagators::cumulative::time_table::time_table_util::find_profiles_which_propagate_upper_bound; @@ -825,7 +825,7 @@ mod tests { find_profiles_which_propagate_lower_bound( 0, &time_table, - PropagationContext::new(&assignments), + Domains::new(&assignments), &Rc::new(Task { start_variable: x, processing_time: 6, @@ -875,7 +875,7 @@ mod tests { find_profiles_which_propagate_upper_bound( 1, &time_table, - PropagationContext::new(&assignments), + Domains::new(&assignments), &Rc::new(Task { start_variable: x, processing_time: 6, diff --git a/pumpkin-crates/core/src/propagators/cumulative/utils/structs/updatable_structures.rs b/pumpkin-crates/core/src/propagators/cumulative/utils/structs/updatable_structures.rs index ef271da18..404501128 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/utils/structs/updatable_structures.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/utils/structs/updatable_structures.rs @@ -4,7 +4,7 @@ use super::CumulativeParameters; use super::Task; use super::UpdatedTaskInfo; use crate::containers::SparseSet; -use crate::propagation::PropagationContext; +use crate::propagation::Domains; use crate::propagation::ReadDomains; use crate::pumpkin_assert_moderate; use crate::variables::IntegerVariable; @@ -107,7 +107,7 @@ impl UpdatableStructures { /// Removes the fixed tasks from the internal structure(s). pub(crate) fn remove_fixed( &mut self, - context: PropagationContext, + context: Domains, parameters: &CumulativeParameters, ) { for task in parameters.tasks.iter() { @@ -124,7 +124,7 @@ impl UpdatableStructures { /// tasks from the internal structure(s). pub(crate) fn reset_all_bounds_and_remove_fixed( &mut self, - context: PropagationContext, + context: Domains, parameters: &CumulativeParameters, ) { for task in parameters.tasks.iter() { @@ -174,7 +174,7 @@ impl UpdatableStructures { // Initialises all stored bounds to their current values and removes any tasks which are fixed pub(crate) fn initialise_bounds_and_remove_fixed( &mut self, - context: PropagationContext, + context: Domains, parameters: &CumulativeParameters, ) { for task in parameters.tasks.iter() { @@ -244,7 +244,7 @@ impl UpdatableStructures { /// Used for creating the dynamic structures from the provided context pub(crate) fn recreate_from_context( &self, - context: PropagationContext, + context: Domains, parameters: &CumulativeParameters, ) -> Self { let mut other = self.clone(); diff --git a/pumpkin-crates/core/src/propagators/cumulative/utils/util.rs b/pumpkin-crates/core/src/propagators/cumulative/utils/util.rs index 7c9c44cc6..27b03691c 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/utils/util.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/utils/util.rs @@ -8,8 +8,8 @@ use enumset::enum_set; use crate::engine::notifications::DomainEvent; use crate::engine::variables::IntegerVariable; use crate::propagation::DomainEvents; +use crate::propagation::Domains; use crate::propagation::LocalId; -use crate::propagation::PropagationContext; use crate::propagation::PropagatorConstructorContext; use crate::propagation::ReadDomains; use crate::propagators::ArgTask; @@ -76,7 +76,7 @@ pub(crate) fn register_tasks( /// Updates the bounds of the provided [`Task`] to those stored in /// `context`. pub(crate) fn update_bounds_task( - context: PropagationContext, + context: Domains, bounds: &mut [(i32, i32)], task: &Rc>, ) { @@ -88,7 +88,7 @@ pub(crate) fn update_bounds_task( /// Determines whether the stored bounds are equal when propagation occurs pub(crate) fn check_bounds_equal_at_propagation( - context: PropagationContext, + context: Domains, tasks: &[Rc>], bounds: &[(i32, i32)], ) -> bool { diff --git a/pumpkin-crates/core/src/propagators/disjunctive/theta_lambda_tree.rs b/pumpkin-crates/core/src/propagators/disjunctive/theta_lambda_tree.rs index 69a83ccfc..422282874 100644 --- a/pumpkin-crates/core/src/propagators/disjunctive/theta_lambda_tree.rs +++ b/pumpkin-crates/core/src/propagators/disjunctive/theta_lambda_tree.rs @@ -3,8 +3,8 @@ use std::cmp::max; use super::disjunctive_task::DisjunctiveTask; use crate::containers::KeyedVec; use crate::containers::StorageKey; +use crate::propagation::Domains; use crate::propagation::LocalId; -use crate::propagation::PropagationContext; use crate::propagation::ReadDomains; use crate::pumpkin_assert_moderate; use crate::pumpkin_assert_simple; @@ -112,7 +112,7 @@ impl ThetaLambdaTree { /// Update the theta-lambda tree based on the provided `context`. /// /// It resets theta and lambda to be the empty set. - pub(super) fn update(&mut self, context: PropagationContext) { + pub(super) fn update(&mut self, context: Domains) { // First we sort the tasks by lower-bound/earliest start time. self.sorted_tasks .sort_by_key(|task| context.lower_bound(&task.start_time)); @@ -228,7 +228,7 @@ impl ThetaLambdaTree { pub(super) fn add_to_lambda( &mut self, task: &DisjunctiveTask, - context: PropagationContext, + context: Domains, ) { // We need to find the leaf node index; note that there are |nodes| / 2 leaves let position = self.nodes.len() / 2 + self.mapping[task.id]; @@ -249,11 +249,7 @@ impl ThetaLambdaTree { } /// Add the provided task to Theta - pub(super) fn add_to_theta( - &mut self, - task: &DisjunctiveTask, - context: PropagationContext, - ) { + pub(super) fn add_to_theta(&mut self, task: &DisjunctiveTask, context: Domains) { // We need to find the leaf node index; note that there are |nodes| / 2 leaves let position = self.nodes.len() / 2 + self.mapping[task.id]; let ect = context.lower_bound(&task.start_time) + task.processing_time; @@ -380,8 +376,8 @@ impl ThetaLambdaTree { #[cfg(test)] mod tests { use crate::engine::test_solver::TestSolver; + use crate::propagation::Domains; use crate::propagation::LocalId; - use crate::propagation::PropagationContext; use crate::propagators::disjunctive::theta_lambda_tree::Node; use crate::propagators::disjunctive::theta_lambda_tree::ThetaLambdaTree; use crate::propagators::disjunctive_task::DisjunctiveTask; @@ -418,17 +414,14 @@ mod tests { let mut tree = ThetaLambdaTree::new(&tasks); - tree.update(PropagationContext { + tree.update(Domains { assignments: &solver.state.assignments, }); for task in tasks.iter() { - tree.add_to_theta(task, PropagationContext::new(&solver.state.assignments)); + tree.add_to_theta(task, Domains::new(&solver.state.assignments)); } tree.remove_from_theta(&tasks[2]); - tree.add_to_lambda( - &tasks[2], - PropagationContext::new(&solver.state.assignments), - ); + tree.add_to_lambda(&tasks[2], Domains::new(&solver.state.assignments)); assert_eq!( tree.nodes[6], diff --git a/pumpkin-crates/core/src/propagators/disjunctive/theta_tree.rs b/pumpkin-crates/core/src/propagators/disjunctive/theta_tree.rs index 3b2fcc94c..77c895117 100644 --- a/pumpkin-crates/core/src/propagators/disjunctive/theta_tree.rs +++ b/pumpkin-crates/core/src/propagators/disjunctive/theta_tree.rs @@ -3,8 +3,8 @@ use std::cmp::max; use super::disjunctive_task::DisjunctiveTask; use crate::containers::KeyedVec; use crate::containers::StorageKey; +use crate::propagation::Domains; use crate::propagation::LocalId; -use crate::propagation::PropagationContext; use crate::propagation::ReadDomains; use crate::pumpkin_assert_simple; use crate::variables::IntegerVariable; @@ -57,7 +57,7 @@ pub(super) struct ThetaTree { impl ThetaTree { pub(super) fn new( tasks: &[DisjunctiveTask], - context: PropagationContext, + context: Domains, ) -> Self { // First we sort the tasks by lower-bound let mut sorted_tasks = tasks.to_vec(); @@ -97,7 +97,7 @@ impl ThetaTree { pub(super) fn add( &mut self, task: &DisjunctiveTask, - context: PropagationContext, + context: Domains, ) { // We need to find the leaf node index; note that there are |nodes| / 2 leaves let position = self.nodes.len() / 2 + self.mapping[task.id]; diff --git a/pumpkin-crates/core/src/propagators/nogoods/nogood_propagator.rs b/pumpkin-crates/core/src/propagators/nogoods/nogood_propagator.rs index 589542685..ffe8112a3 100644 --- a/pumpkin-crates/core/src/propagators/nogoods/nogood_propagator.rs +++ b/pumpkin-crates/core/src/propagators/nogoods/nogood_propagator.rs @@ -22,10 +22,10 @@ use crate::engine::reason::Reason; use crate::engine::reason::ReasonStore; use crate::predicate; use crate::proof::InferenceCode; +use crate::propagation::Domains; use crate::propagation::EnqueueDecision; use crate::propagation::ExplanationContext; use crate::propagation::HasAssignments; -use crate::propagation::PropagationContext; use crate::propagation::PropagationContextMut; use crate::propagation::Propagator; use crate::propagation::PropagatorConstructor; @@ -329,7 +329,7 @@ impl Propagator for NogoodPropagator { Ok(()) } - fn synchronise(&mut self, _context: PropagationContext) { + fn synchronise(&mut self, _context: Domains) { self.updated_predicate_ids.clear() } diff --git a/pumpkin-crates/core/src/propagators/reified_propagator.rs b/pumpkin-crates/core/src/propagators/reified_propagator.rs index c79381c4d..5ff4d182d 100644 --- a/pumpkin-crates/core/src/propagators/reified_propagator.rs +++ b/pumpkin-crates/core/src/propagators/reified_propagator.rs @@ -2,10 +2,10 @@ use crate::basic_types::PropagationStatusCP; use crate::engine::notifications::OpaqueDomainEvent; use crate::predicates::Predicate; use crate::propagation::DomainEvents; +use crate::propagation::Domains; use crate::propagation::EnqueueDecision; use crate::propagation::ExplanationContext; use crate::propagation::LocalId; -use crate::propagation::PropagationContext; use crate::propagation::PropagationContextMut; use crate::propagation::PropagationContextWithTrailedValues; use crate::propagation::Propagator; @@ -102,12 +102,7 @@ impl Propagator for ReifiedPropagator Propagator for ReifiedPropagator Date: Fri, 12 Dec 2025 15:09:14 +0100 Subject: [PATCH 04/29] Update docs --- .../core/src/propagation/contexts/propagation_context.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pumpkin-crates/core/src/propagation/contexts/propagation_context.rs b/pumpkin-crates/core/src/propagation/contexts/propagation_context.rs index a6d4fb59d..53734b518 100644 --- a/pumpkin-crates/core/src/propagation/contexts/propagation_context.rs +++ b/pumpkin-crates/core/src/propagation/contexts/propagation_context.rs @@ -148,10 +148,8 @@ impl<'a> PropagationContextMut<'a> { } } -/// A trait which defines common methods for retrieving the [`Assignments`] and -/// [`AssignmentsPropositional`] from the structure which implements this trait. +/// A helper-trait for implementing [`ReadDomains`], which exposes the assignment. pub(crate) trait HasAssignments { - /// Returns the stored [`Assignments`]. fn assignments(&self) -> &Assignments; } From 915b78da5593741fddc6587266fd7e3bd47031f3 Mon Sep 17 00:00:00 2001 From: Maarten Flippo Date: Fri, 12 Dec 2025 15:10:58 +0100 Subject: [PATCH 05/29] Rename `as_context` to `domains` --- .../contexts/propagation_context.rs | 4 +-- .../arithmetic/linear_less_or_equal.rs | 6 ++--- .../arithmetic/linear_not_equal.rs | 6 ++--- .../time_table/explanations/pointwise.rs | 4 +-- .../time_table_over_interval_incremental.rs | 24 ++++++++--------- .../time_table_per_point_incremental.rs | 22 +++++++-------- .../time_table/propagation_handler.rs | 26 +++++++++--------- .../time_table/time_table_over_interval.rs | 10 +++---- .../time_table/time_table_per_point.rs | 15 +++++------ .../cumulative/time_table/time_table_util.rs | 27 +++++++------------ .../disjunctive/disjunctive_propagator.rs | 6 ++--- 11 files changed, 69 insertions(+), 81 deletions(-) diff --git a/pumpkin-crates/core/src/propagation/contexts/propagation_context.rs b/pumpkin-crates/core/src/propagation/contexts/propagation_context.rs index 53734b518..8004e8f95 100644 --- a/pumpkin-crates/core/src/propagation/contexts/propagation_context.rs +++ b/pumpkin-crates/core/src/propagation/contexts/propagation_context.rs @@ -39,7 +39,7 @@ impl<'a> PropagationContextWithTrailedValues<'a> { } } - pub(crate) fn as_readonly(&self) -> Domains<'_> { + pub(crate) fn domains(&self) -> Domains<'_> { Domains { assignments: self.assignments, } @@ -118,7 +118,7 @@ impl<'a> PropagationContextMut<'a> { } /// Get the current domain information. - pub fn as_readonly(&self) -> Domains<'_> { + pub fn domains(&self) -> Domains<'_> { Domains { assignments: self.assignments, } diff --git a/pumpkin-crates/core/src/propagators/arithmetic/linear_less_or_equal.rs b/pumpkin-crates/core/src/propagators/arithmetic/linear_less_or_equal.rs index 8e17697d5..7fc3694c0 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/linear_less_or_equal.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/linear_less_or_equal.rs @@ -113,7 +113,7 @@ where context: PropagationContextWithTrailedValues, ) -> Option { if (self.c as i64) < context.value(self.lower_bound_left_hand_side) { - Some(self.create_conflict(context.as_readonly())) + Some(self.create_conflict(context.domains())) } else { None } @@ -186,7 +186,7 @@ where // This means that the lower-bounds of the current variables will always be // higher than the right-hand side (with a maximum value of i32). We thus // return a conflict - return Err(self.create_conflict(context.as_readonly()).into()); + return Err(self.create_conflict(context.domains()).into()); } Err(_) => { // We cannot fit the `lower_bound_left_hand_side` into an i32 due to an @@ -229,7 +229,7 @@ where // This means that the lower-bounds of the current variables will always be // higher than the right-hand side (with a maximum value of i32). We thus // return a conflict - return Err(self.create_conflict(context.as_readonly()).into()); + return Err(self.create_conflict(context.domains()).into()); } Err(_) => { // We cannot fit the `lower_bound_left_hand_side` into an i32 due to an diff --git a/pumpkin-crates/core/src/propagators/arithmetic/linear_not_equal.rs b/pumpkin-crates/core/src/propagators/arithmetic/linear_not_equal.rs index f2d310d8f..963bf1c74 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/linear_not_equal.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/linear_not_equal.rs @@ -177,10 +177,10 @@ where // If the left-hand side is out of date then we simply recalculate from scratch; we only do // this when we can propagate or check for a conflict if self.should_recalculate_lhs && self.number_of_fixed_terms >= self.terms.len() - 1 { - self.recalculate_fixed_variables(context.as_readonly()); + self.recalculate_fixed_variables(context.domains()); self.should_recalculate_lhs = false; } - pumpkin_assert_extreme!(self.is_propagator_state_consistent(context.as_readonly())); + pumpkin_assert_extreme!(self.is_propagator_state_consistent(context.domains())); // If there is only 1 unfixed variable, then we can propagate if self.number_of_fixed_terms == self.terms.len() - 1 { @@ -217,7 +217,7 @@ where } else if self.number_of_fixed_terms == self.terms.len() { pumpkin_assert_simple!(!self.should_recalculate_lhs); // Otherwise we check for a conflict - self.check_for_conflict(context.as_readonly())?; + self.check_for_conflict(context.domains())?; } Ok(()) diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/explanations/pointwise.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/explanations/pointwise.rs index da2425e96..dc1d29f7f 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/explanations/pointwise.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/explanations/pointwise.rs @@ -63,7 +63,7 @@ pub(crate) fn propagate_lower_bounds_with_pointwise_explanations if self.is_time_table_outdated { // We create the time-table from scratch (and return an error if it overflows) self.time_table = create_time_table_over_interval_from_scratch( - context.as_readonly(), + context.domains(), &self.parameters, self.inference_code.unwrap(), )?; @@ -249,7 +249,7 @@ impl // And we clear all of the updates since they have now necessarily been processed self.updatable_structures - .reset_all_bounds_and_remove_fixed(context.as_readonly(), &self.parameters); + .reset_all_bounds_and_remove_fixed(context.domains(), &self.parameters); return Ok(()); } @@ -275,7 +275,7 @@ impl // Note that the inconsistency returned here does not necessarily hold since other // updates could remove from the profile let result = self.add_to_time_table( - context.as_readonly(), + context.domains(), &mandatory_part_adjustments, &updated_task, ); @@ -301,7 +301,7 @@ impl if let Some(mut conflicting_profile) = conflicting_profile { let synchronised_conflict_explanation = create_synchronised_conflict_explanation( - context.as_readonly(), + context.domains(), self.inference_code.unwrap(), &mut conflicting_profile, &self.parameters, @@ -309,7 +309,7 @@ impl pumpkin_assert_extreme!( check_synchronisation_conflict_explanation_over_interval( &synchronised_conflict_explanation, - context.as_readonly(), + context.domains(), &self.parameters, self.inference_code.unwrap(), ), @@ -331,7 +331,7 @@ impl if let Some(conflicting_profile) = conflicting_profile { pumpkin_assert_extreme!( create_time_table_over_interval_from_scratch( - context.as_readonly(), + context.domains(), &self.parameters, self.inference_code.unwrap(), ) @@ -342,7 +342,7 @@ impl self.found_previous_conflict = true; return Err(create_conflict_explanation( - context.as_readonly(), + context.domains(), self.inference_code.unwrap(), conflicting_profile, self.parameters.options.explanation_type, @@ -358,7 +358,7 @@ impl // We have not found a conflict; we need to ensure that the time-tables are the same by // ensuring that the profiles are maximal and the profile tasks are sorted in the same // order - synchronise_time_table(&mut self.time_table, context.as_readonly()) + synchronise_time_table(&mut self.time_table, context.domains()) } // We check whether there are no non-conflicting profiles in the time-table if we do not @@ -378,7 +378,7 @@ impl Propagator fn propagate(&mut self, mut context: PropagationContextMut) -> PropagationStatusCP { pumpkin_assert_advanced!( check_bounds_equal_at_propagation( - context.as_readonly(), + context.domains(), &self.parameters.tasks, self.updatable_structures.get_stored_bounds(), ), @@ -396,7 +396,7 @@ impl Propagator pumpkin_assert_extreme!( debug::time_tables_are_the_same_interval::( - context.as_readonly(), + context.domains(), self.inference_code.unwrap(), &self.time_table, &self.parameters, @@ -435,7 +435,7 @@ impl Propagator &self.parameters, &self.updatable_structures, &updated_task, - context.as_readonly(), + context.domains(), self.time_table.is_empty(), ); @@ -444,7 +444,7 @@ impl Propagator insert_update(&updated_task, &mut self.updatable_structures, result.update); update_bounds_task( - context.as_readonly(), + context.domains(), self.updatable_structures.get_stored_bounds_mut(), &updated_task, ); diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/time_table_per_point_incremental.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/time_table_per_point_incremental.rs index 174cd7340..8b7063373 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/time_table_per_point_incremental.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/time_table_per_point_incremental.rs @@ -257,7 +257,7 @@ impl if self.is_time_table_outdated { // We create the time-table from scratch (and return an error if it overflows) self.time_table = create_time_table_per_point_from_scratch( - context.as_readonly(), + context.domains(), self.inference_code.unwrap(), &self.parameters, )?; @@ -267,7 +267,7 @@ impl // And we clear all of the updates since they have now necessarily been processed self.updatable_structures - .reset_all_bounds_and_remove_fixed(context.as_readonly(), &self.parameters); + .reset_all_bounds_and_remove_fixed(context.domains(), &self.parameters); return Ok(()); } @@ -293,7 +293,7 @@ impl // Note that the inconsistency returned here does not necessarily hold since other // updates could remove from the profile let result = self.add_to_time_table( - context.as_readonly(), + context.domains(), &mandatory_part_adjustments, &updated_task, ); @@ -325,7 +325,7 @@ impl .expect("Expected to find a conflicting profile"); let synchronised_conflict_explanation = create_synchronised_conflict_explanation( - context.as_readonly(), + context.domains(), self.inference_code.unwrap(), conflicting_profile, &self.parameters, @@ -334,7 +334,7 @@ impl pumpkin_assert_extreme!( check_synchronisation_conflict_explanation_per_point( &synchronised_conflict_explanation, - context.as_readonly(), + context.domains(), self.inference_code.unwrap(), &self.parameters, ), @@ -360,7 +360,7 @@ impl if let Some(conflicting_profile) = conflicting_profile { pumpkin_assert_extreme!( create_time_table_per_point_from_scratch( - context.as_readonly(), + context.domains(), self.inference_code.unwrap(), &self.parameters ) @@ -371,7 +371,7 @@ impl self.found_previous_conflict = true; return Err(create_conflict_explanation( - context.as_readonly(), + context.domains(), self.inference_code.unwrap(), conflicting_profile, self.parameters.options.explanation_type, @@ -407,7 +407,7 @@ impl Propagator fn propagate(&mut self, mut context: PropagationContextMut) -> PropagationStatusCP { pumpkin_assert_advanced!( check_bounds_equal_at_propagation( - context.as_readonly(), + context.domains(), &self.parameters.tasks, self.updatable_structures.get_stored_bounds(), ), @@ -425,7 +425,7 @@ impl Propagator self.update_time_table(&mut context)?; pumpkin_assert_extreme!(debug::time_tables_are_the_same_point::( - context.as_readonly(), + context.domains(), self.inference_code.unwrap(), &self.time_table, &self.parameters @@ -462,7 +462,7 @@ impl Propagator &self.parameters, &self.updatable_structures, &updated_task, - context.as_readonly(), + context.domains(), self.time_table.is_empty(), ); @@ -471,7 +471,7 @@ impl Propagator insert_update(&updated_task, &mut self.updatable_structures, result.update); update_bounds_task( - context.as_readonly(), + context.domains(), self.updatable_structures.get_stored_bounds_mut(), &updated_task, ); diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/propagation_handler.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/propagation_handler.rs index 601a01c0a..685af540d 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/propagation_handler.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/propagation_handler.rs @@ -101,7 +101,7 @@ impl CumulativePropagationHandler { for profile in profiles { let explanation = match self.explanation_type { CumulativeExplanationType::Naive => { - create_naive_propagation_explanation(profile, context.as_readonly()) + create_naive_propagation_explanation(profile, context.domains()) } CumulativeExplanationType::BigStep => { create_big_step_propagation_explanation(profile) @@ -120,7 +120,7 @@ impl CumulativePropagationHandler { let full_explanation = add_propagating_task_predicate_lower_bound( full_explanation, self.explanation_type, - context.as_readonly(), + context.domains(), propagating_task, profiles[0], None, @@ -132,7 +132,7 @@ impl CumulativePropagationHandler { pumpkin_assert_extreme!(check_explanation( predicate, &full_explanation, - context.as_readonly() + context.domains() )); context.post(predicate, full_explanation, self.inference_code) } @@ -167,7 +167,7 @@ impl CumulativePropagationHandler { for profile in profiles { let explanation = match self.explanation_type { CumulativeExplanationType::Naive => { - create_naive_propagation_explanation(profile, context.as_readonly()) + create_naive_propagation_explanation(profile, context.domains()) } CumulativeExplanationType::BigStep => { create_big_step_propagation_explanation(profile) @@ -186,7 +186,7 @@ impl CumulativePropagationHandler { let full_explanation = add_propagating_task_predicate_upper_bound( full_explanation, self.explanation_type, - context.as_readonly(), + context.domains(), propagating_task, profiles[profiles.len() - 1], None, @@ -198,7 +198,7 @@ impl CumulativePropagationHandler { pumpkin_assert_extreme!(check_explanation( predicate, &full_explanation, - context.as_readonly() + context.domains() )); context.post(predicate, full_explanation, self.inference_code) } @@ -237,7 +237,7 @@ impl CumulativePropagationHandler { let lower_bound_predicate_propagating_task = create_predicate_propagating_task_lower_bound_propagation( self.explanation_type, - context.as_readonly(), + context.domains(), propagating_task, profile, None, @@ -246,7 +246,7 @@ impl CumulativePropagationHandler { pumpkin_assert_extreme!(check_explanation( predicate, &explanation, - context.as_readonly() + context.domains() )); let mut reason = (*explanation).clone(); @@ -289,7 +289,7 @@ impl CumulativePropagationHandler { let upper_bound_predicate_propagating_task = create_predicate_propagating_task_upper_bound_propagation( self.explanation_type, - context.as_readonly(), + context.domains(), propagating_task, profile, None, @@ -301,7 +301,7 @@ impl CumulativePropagationHandler { pumpkin_assert_extreme!(check_explanation( predicate, &explanation, - context.as_readonly() + context.domains() )); let mut reason = (*explanation).clone(); @@ -370,7 +370,7 @@ impl CumulativePropagationHandler { pumpkin_assert_extreme!(check_explanation( predicate, &explanation, - context.as_readonly() + context.domains() )); context.post(predicate, (*explanation).clone(), self.inference_code)?; } @@ -403,7 +403,7 @@ impl CumulativePropagationHandler { pumpkin_assert_extreme!(check_explanation( predicate, &explanation, - context.as_readonly() + context.domains() )); context.post(predicate, explanation, self.inference_code)?; } @@ -432,7 +432,7 @@ impl CumulativePropagationHandler { Rc::new( match self.explanation_type { CumulativeExplanationType::Naive => { - create_naive_propagation_explanation(profile, context.as_readonly()) + create_naive_propagation_explanation(profile, context.domains()) }, CumulativeExplanationType::BigStep => { create_big_step_propagation_explanation(profile) diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_over_interval.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_over_interval.rs index b4e1dde55..6a0aff53e 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_over_interval.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_over_interval.rs @@ -126,7 +126,7 @@ impl Propagator for TimeTableOverIntervalPropaga } let time_table = create_time_table_over_interval_from_scratch( - context.as_readonly(), + context.domains(), &self.parameters, self.inference_code.unwrap(), )?; @@ -163,12 +163,12 @@ impl Propagator for TimeTableOverIntervalPropaga &self.parameters, &self.updatable_structures, &updated_task, - context.as_readonly(), + context.domains(), self.is_time_table_empty, ); update_bounds_task( - context.as_readonly(), + context.domains(), self.updatable_structures.get_stored_bounds_mut(), &updated_task, ); @@ -458,7 +458,7 @@ pub(crate) fn debug_propagate_from_scratch_time_table_interval Propagator for TimeTablePerPointPropagator< } let time_table = create_time_table_per_point_from_scratch( - context.as_readonly(), + context.domains(), self.inference_code.unwrap(), &self.parameters, )?; @@ -154,14 +154,14 @@ impl Propagator for TimeTablePerPointPropagator< &self.parameters, &self.updatable_structures, &updated_task, - context.as_readonly(), + context.domains(), self.is_time_table_empty, ); // Note that the non-incremental proapgator does not make use of `result.updated` since it // propagates from scratch anyways update_bounds_task( - context.as_readonly(), + context.domains(), self.updatable_structures.get_stored_bounds_mut(), &updated_task, ); @@ -261,18 +261,15 @@ pub(crate) fn debug_propagate_from_scratch_time_table_point PropagationStatusCP { // We first create a time-table per point and return an error if there was // an overflow of the resource capacity while building the time-table - let time_table = create_time_table_per_point_from_scratch( - context.as_readonly(), - inference_code, - parameters, - )?; + let time_table = + create_time_table_per_point_from_scratch(context.domains(), inference_code, parameters)?; // Then we check whether propagation can take place propagate_based_on_timetable( context, inference_code, time_table.values(), parameters, - &mut updatable_structures.recreate_from_context(context.as_readonly(), parameters), + &mut updatable_structures.recreate_from_context(context.domains(), parameters), ) } diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_util.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_util.rs index 39abdcfe6..a986bcedd 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_util.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_util.rs @@ -307,7 +307,7 @@ fn propagate_single_profiles<'a, Var: IntegerVariable + 'static>( // We get the updates which are possible (i.e. a lower-bound update, an upper-bound // update or a hole in the domain) if lower_bound_can_be_propagated_by_profile( - context.as_readonly(), + context.domains(), &task, profile, parameters.capacity, @@ -320,7 +320,7 @@ fn propagate_single_profiles<'a, Var: IntegerVariable + 'static>( } } if upper_bound_can_be_propagated_by_profile( - context.as_readonly(), + context.domains(), &task, profile, parameters.capacity, @@ -333,12 +333,7 @@ fn propagate_single_profiles<'a, Var: IntegerVariable + 'static>( } } if parameters.options.allow_holes_in_domain - && can_be_updated_by_profile( - context.as_readonly(), - &task, - profile, - parameters.capacity, - ) + && can_be_updated_by_profile(context.domains(), &task, profile, parameters.capacity) { let result = propagation_handler.propagate_holes_in_domain(context, profile, &task); @@ -424,12 +419,8 @@ fn propagate_sequence_of_profiles<'a, Var: IntegerVariable + 'static>( }); for profile in &time_table[lower_bound_index..upper_bound_index] { // Check whether this profile can cause an update - if can_be_updated_by_profile( - context.as_readonly(), - task, - profile, - parameters.capacity, - ) { + if can_be_updated_by_profile(context.domains(), task, profile, parameters.capacity) + { // If we allow the propagation of holes in the domain then we simply let the // propagation handler handle it propagation_handler.propagate_holes_in_domain(context, profile, task)?; @@ -471,7 +462,7 @@ fn sweep_forward<'a, Var: IntegerVariable + 'static>( // We check whether a lower-bound propagation can be performed using this profile if lower_bound_can_be_propagated_by_profile( - context.as_readonly(), + context.domains(), task, profile, parameters.capacity, @@ -481,7 +472,7 @@ fn sweep_forward<'a, Var: IntegerVariable + 'static>( find_profiles_which_propagate_lower_bound( profile_index, time_table, - context.as_readonly(), + context.domains(), task, parameters.capacity, profile_buffer, @@ -539,7 +530,7 @@ fn sweep_backward<'a, Var: IntegerVariable + 'static>( // We check whether an upper-bound propagation can be performed using this profile if upper_bound_can_be_propagated_by_profile( - context.as_readonly(), + context.domains(), task, profile, parameters.capacity, @@ -549,7 +540,7 @@ fn sweep_backward<'a, Var: IntegerVariable + 'static>( find_profiles_which_propagate_upper_bound( profile_index, time_table, - context.as_readonly(), + context.domains(), task, parameters.capacity, profile_buffer, diff --git a/pumpkin-crates/core/src/propagators/disjunctive/disjunctive_propagator.rs b/pumpkin-crates/core/src/propagators/disjunctive/disjunctive_propagator.rs index 5ceb82904..02396e392 100644 --- a/pumpkin-crates/core/src/propagators/disjunctive/disjunctive_propagator.rs +++ b/pumpkin-crates/core/src/propagators/disjunctive/disjunctive_propagator.rs @@ -148,9 +148,9 @@ fn edge_finding( ) -> PropagationStatusCP { // First we create our Theta-Lambda tree and add all of the tasks to Theta (Lambda is empty at // this point) - theta_lambda_tree.update(context.as_readonly()); + theta_lambda_tree.update(context.domains()); for task in tasks.iter() { - theta_lambda_tree.add_to_theta(task, context.as_readonly()); + theta_lambda_tree.add_to_theta(task, context.domains()); } // Then sort in non-increasing order of latest completion time (LCT) @@ -181,7 +181,7 @@ fn edge_finding( theta_lambda_tree.remove_from_theta(j); // And then add it to Lambda (i.e. we are checking whether we can find a task i in Lambda // such that the element in Theta would cause an overflow) - theta_lambda_tree.add_to_lambda(j, context.as_readonly()); + theta_lambda_tree.add_to_lambda(j, context.domains()); // Then we go to the next task which represents the latest completion time of the set Theta index += 1; From c5cf24e9762f5c91725b3d8067749eb9a95dbab6 Mon Sep 17 00:00:00 2001 From: Maarten Flippo Date: Fri, 12 Dec 2025 15:18:23 +0100 Subject: [PATCH 06/29] Make Reason public and move HasAssignments to Domains --- pumpkin-crates/core/src/engine/cp/reason.rs | 2 +- .../contexts/explanation_context.rs | 2 +- .../contexts/propagation_context.rs | 171 +----------------- .../core/src/propagation/domains.rs | 161 ++++++++++++++++- 4 files changed, 168 insertions(+), 168 deletions(-) diff --git a/pumpkin-crates/core/src/engine/cp/reason.rs b/pumpkin-crates/core/src/engine/cp/reason.rs index 83075526e..fb1e8525c 100644 --- a/pumpkin-crates/core/src/engine/cp/reason.rs +++ b/pumpkin-crates/core/src/engine/cp/reason.rs @@ -88,7 +88,7 @@ pub(crate) struct ReasonRef(pub(crate) u32); /// A reason for CP propagator to make a change #[derive(Debug)] -pub(crate) enum Reason { +pub enum Reason { /// An eager reason contains the propositional conjunction with the reason, without the /// propagated predicate. Eager(PropositionalConjunction), diff --git a/pumpkin-crates/core/src/propagation/contexts/explanation_context.rs b/pumpkin-crates/core/src/propagation/contexts/explanation_context.rs index 1e3c8266b..6e1ec860e 100644 --- a/pumpkin-crates/core/src/propagation/contexts/explanation_context.rs +++ b/pumpkin-crates/core/src/propagation/contexts/explanation_context.rs @@ -1,12 +1,12 @@ use std::sync::LazyLock; -use super::HasAssignments; use crate::basic_types::PredicateId; use crate::basic_types::PredicateIdGenerator; use crate::containers::KeyValueHeap; use crate::engine::Assignments; use crate::engine::notifications::NotificationEngine; use crate::predicates::Predicate; +use crate::propagation::HasAssignments; #[cfg(doc)] use crate::propagation::Propagator; diff --git a/pumpkin-crates/core/src/propagation/contexts/propagation_context.rs b/pumpkin-crates/core/src/propagation/contexts/propagation_context.rs index 8004e8f95..2d11f265f 100644 --- a/pumpkin-crates/core/src/propagation/contexts/propagation_context.rs +++ b/pumpkin-crates/core/src/propagation/contexts/propagation_context.rs @@ -10,13 +10,14 @@ use crate::engine::predicates::predicate::Predicate; use crate::engine::reason::Reason; use crate::engine::reason::ReasonStore; use crate::engine::reason::StoredReason; -use crate::engine::variables::IntegerVariable; use crate::engine::variables::Literal; use crate::proof::InferenceCode; use crate::propagation::Domains; #[cfg(doc)] use crate::propagation::Propagator; use crate::propagation::PropagatorId; +#[cfg(doc)] +use crate::propagation::ReadDomains; use crate::pumpkin_assert_simple; #[derive(Debug)] @@ -46,6 +47,10 @@ impl<'a> PropagationContextWithTrailedValues<'a> { } } +/// Provides information about the state of the solver to a propagator. +/// +/// Domains can be read through the implementation of [`ReadDomains`], and changes to the state can +/// be made via [`PropagationContextMut::post`]. #[derive(Debug)] pub struct PropagationContextMut<'a> { pub(crate) trailed_values: &'a mut TrailedValues, @@ -148,11 +153,6 @@ impl<'a> PropagationContextMut<'a> { } } -/// A helper-trait for implementing [`ReadDomains`], which exposes the assignment. -pub(crate) trait HasAssignments { - fn assignments(&self) -> &Assignments; -} - pub(crate) trait HasTrailedValues { fn trailed_values(&self) -> &TrailedValues; fn trailed_values_mut(&mut self) -> &mut TrailedValues; @@ -160,6 +160,7 @@ pub(crate) trait HasTrailedValues { mod private { use super::*; + use crate::propagation::HasAssignments; impl HasTrailedValues for PropagationContextWithTrailedValues<'_> { fn trailed_values(&self) -> &TrailedValues { @@ -215,170 +216,14 @@ pub(crate) trait ManipulateTrailedValues: HasTrailedValues { impl ManipulateTrailedValues for T {} -pub trait ReadDomains { - fn is_predicate_satisfied(&self, predicate: Predicate) -> bool; - - fn is_predicate_falsified(&self, predicate: Predicate) -> bool; - - fn is_literal_true(&self, literal: &Literal) -> bool; - - fn is_literal_false(&self, literal: &Literal) -> bool; - - fn is_literal_fixed(&self, literal: &Literal) -> bool; - - /// Returns the holes which were created on the current decision level. - fn get_holes_at_current_checkpoint( - &self, - var: &Var, - ) -> impl Iterator; - - /// Returns all of the holes (currently) in the domain of `var` (including ones which were - /// created at previous decision levels). - fn get_holes(&self, var: &Var) -> impl Iterator; - - /// Returns `true` if the domain of the given variable is singleton. - fn is_fixed(&self, var: &Var) -> bool; - - fn lower_bound(&self, var: &Var) -> i32; - - fn lower_bound_at_trail_position( - &self, - var: &Var, - trail_position: usize, - ) -> i32; - - fn upper_bound(&self, var: &Var) -> i32; - - fn upper_bound_at_trail_position( - &self, - var: &Var, - trail_position: usize, - ) -> i32; - - fn contains(&self, var: &Var, value: i32) -> bool; - - fn contains_at_trail_position( - &self, - var: &Var, - value: i32, - trail_position: usize, - ) -> bool; - - fn iterate_domain(&self, var: &Var) -> impl Iterator; -} - -impl ReadDomains for T { - fn is_predicate_satisfied(&self, predicate: Predicate) -> bool { - self.assignments() - .evaluate_predicate(predicate) - .is_some_and(|truth_value| truth_value) - } - - fn is_predicate_falsified(&self, predicate: Predicate) -> bool { - self.assignments() - .evaluate_predicate(predicate) - .is_some_and(|truth_value| !truth_value) - } - - fn is_decision_predicate(&self, predicate: &Predicate) -> bool { - self.assignments().is_decision_predicate(predicate) - } - - fn get_checkpoint_for_predicate(&self, predicate: &Predicate) -> Option { - self.assignments().get_checkpoint_for_predicate(predicate) - } - - fn is_literal_true(&self, literal: &Literal) -> bool { - literal - .get_integer_variable() - .lower_bound(self.assignments()) - == 1 - } - - fn is_literal_false(&self, literal: &Literal) -> bool { - literal - .get_integer_variable() - .upper_bound(self.assignments()) - == 0 - } - - fn is_literal_fixed(&self, literal: &Literal) -> bool { - self.is_fixed(literal) - } - - /// Returns the holes which were created on the current decision level. - fn get_holes_at_current_checkpoint( - &self, - var: &Var, - ) -> impl Iterator { - var.get_holes_at_current_checkpoint(self.assignments()) - } - - /// Returns all of the holes (currently) in the domain of `var` (including ones which were - /// created at previous decision levels). - fn get_holes(&self, var: &Var) -> impl Iterator { - var.get_holes(self.assignments()) - } - - /// Returns `true` if the domain of the given variable is singleton. - fn is_fixed(&self, var: &Var) -> bool { - self.lower_bound(var) == self.upper_bound(var) - } - - fn lower_bound(&self, var: &Var) -> i32 { - var.lower_bound(self.assignments()) - } - - fn lower_bound_at_trail_position( - &self, - var: &Var, - trail_position: usize, - ) -> i32 { - var.lower_bound_at_trail_position(self.assignments(), trail_position) - } - - fn upper_bound(&self, var: &Var) -> i32 { - var.upper_bound(self.assignments()) - } - - fn upper_bound_at_trail_position( - &self, - var: &Var, - trail_position: usize, - ) -> i32 { - var.upper_bound_at_trail_position(self.assignments(), trail_position) - } - - fn contains(&self, var: &Var, value: i32) -> bool { - var.contains(self.assignments(), value) - } - - fn contains_at_trail_position( - &self, - var: &Var, - value: i32, - trail_position: usize, - ) -> bool { - var.contains_at_trail_position(self.assignments(), value, trail_position) - } - - fn iterate_domain(&self, var: &Var) -> impl Iterator { - var.iterate_domain(self.assignments()) - } -} - impl PropagationContextMut<'_> { - pub(crate) fn evaluate_predicate(&self, predicate: Predicate) -> Option { - self.assignments.evaluate_predicate(predicate) - } - /// Assign the truth-value of the given [`Predicate`] to `true` in the current partial /// assignment. /// /// If the truth-value is already `true`, then this is a no-op. Alternatively, if the /// truth-value is `false`, then a conflict is triggered and the [`EmptyDomain`] error is /// returned. At that point, no-more propagation should happen. - pub(crate) fn post( + pub fn post( &mut self, predicate: Predicate, reason: impl Into, diff --git a/pumpkin-crates/core/src/propagation/domains.rs b/pumpkin-crates/core/src/propagation/domains.rs index f4546f8f4..1822594df 100644 --- a/pumpkin-crates/core/src/propagation/domains.rs +++ b/pumpkin-crates/core/src/propagation/domains.rs @@ -1,7 +1,7 @@ use crate::engine::Assignments; -use crate::propagation::HasAssignments; -#[cfg(doc)] -use crate::propagation::ReadDomains; +use crate::predicates::Predicate; +use crate::variables::IntegerVariable; +use crate::variables::Literal; /// Provides access to domain information to propagators. /// @@ -18,8 +18,163 @@ impl<'a> Domains<'a> { } } +/// A helper-trait for implementing [`ReadDomains`], which exposes the assignment. +pub(crate) trait HasAssignments { + fn assignments(&self) -> &Assignments; +} + impl HasAssignments for Domains<'_> { fn assignments(&self) -> &Assignments { self.assignments } } + +pub trait ReadDomains { + fn evaluate_predicate(&self, predicate: Predicate) -> Option; + + fn is_predicate_satisfied(&self, predicate: Predicate) -> bool; + + fn is_predicate_falsified(&self, predicate: Predicate) -> bool; + + fn is_literal_true(&self, literal: &Literal) -> bool; + + fn is_literal_false(&self, literal: &Literal) -> bool; + + fn is_literal_fixed(&self, literal: &Literal) -> bool; + + /// Returns the holes which were created on the current decision level. + fn get_holes_at_current_checkpoint( + &self, + var: &Var, + ) -> impl Iterator; + + /// Returns all of the holes (currently) in the domain of `var` (including ones which were + /// created at previous decision levels). + fn get_holes(&self, var: &Var) -> impl Iterator; + + /// Returns `true` if the domain of the given variable is singleton. + fn is_fixed(&self, var: &Var) -> bool; + + fn lower_bound(&self, var: &Var) -> i32; + + fn lower_bound_at_trail_position( + &self, + var: &Var, + trail_position: usize, + ) -> i32; + + fn upper_bound(&self, var: &Var) -> i32; + + fn upper_bound_at_trail_position( + &self, + var: &Var, + trail_position: usize, + ) -> i32; + + fn contains(&self, var: &Var, value: i32) -> bool; + + fn contains_at_trail_position( + &self, + var: &Var, + value: i32, + trail_position: usize, + ) -> bool; + + fn iterate_domain(&self, var: &Var) -> impl Iterator; +} + +impl ReadDomains for T { + fn evaluate_predicate(&self, predicate: Predicate) -> Option { + self.assignments().evaluate_predicate(predicate) + } + + fn is_predicate_satisfied(&self, predicate: Predicate) -> bool { + self.assignments() + .evaluate_predicate(predicate) + .is_some_and(|truth_value| truth_value) + } + + fn is_predicate_falsified(&self, predicate: Predicate) -> bool { + self.assignments() + .evaluate_predicate(predicate) + .is_some_and(|truth_value| !truth_value) + } + + fn is_literal_true(&self, literal: &Literal) -> bool { + literal + .get_integer_variable() + .lower_bound(self.assignments()) + == 1 + } + + fn is_literal_false(&self, literal: &Literal) -> bool { + literal + .get_integer_variable() + .upper_bound(self.assignments()) + == 0 + } + + fn is_literal_fixed(&self, literal: &Literal) -> bool { + self.is_fixed(literal) + } + + /// Returns the holes which were created on the current decision level. + fn get_holes_at_current_checkpoint( + &self, + var: &Var, + ) -> impl Iterator { + var.get_holes_at_current_checkpoint(self.assignments()) + } + + /// Returns all of the holes (currently) in the domain of `var` (including ones which were + /// created at previous decision levels). + fn get_holes(&self, var: &Var) -> impl Iterator { + var.get_holes(self.assignments()) + } + + /// Returns `true` if the domain of the given variable is singleton. + fn is_fixed(&self, var: &Var) -> bool { + self.lower_bound(var) == self.upper_bound(var) + } + + fn lower_bound(&self, var: &Var) -> i32 { + var.lower_bound(self.assignments()) + } + + fn lower_bound_at_trail_position( + &self, + var: &Var, + trail_position: usize, + ) -> i32 { + var.lower_bound_at_trail_position(self.assignments(), trail_position) + } + + fn upper_bound(&self, var: &Var) -> i32 { + var.upper_bound(self.assignments()) + } + + fn upper_bound_at_trail_position( + &self, + var: &Var, + trail_position: usize, + ) -> i32 { + var.upper_bound_at_trail_position(self.assignments(), trail_position) + } + + fn contains(&self, var: &Var, value: i32) -> bool { + var.contains(self.assignments(), value) + } + + fn contains_at_trail_position( + &self, + var: &Var, + value: i32, + trail_position: usize, + ) -> bool { + var.contains_at_trail_position(self.assignments(), value, trail_position) + } + + fn iterate_domain(&self, var: &Var) -> impl Iterator { + var.iterate_domain(self.assignments()) + } +} From 4a1aa1221e56a8c0c17f31772df81a399983bef1 Mon Sep 17 00:00:00 2001 From: Maarten Flippo Date: Fri, 12 Dec 2025 15:24:12 +0100 Subject: [PATCH 07/29] Always use evaluate_predicate on ReadDomains --- .../branching/branchers/autonomous_search.rs | 2 +- .../core/src/propagation/domains.rs | 42 ++----------------- .../arithmetic/binary/binary_equals.rs | 14 ++++--- .../propagators/nogoods/nogood_propagator.rs | 16 ++++--- .../src/propagators/reified_propagator.rs | 10 ++--- 5 files changed, 27 insertions(+), 57 deletions(-) diff --git a/pumpkin-crates/core/src/branching/branchers/autonomous_search.rs b/pumpkin-crates/core/src/branching/branchers/autonomous_search.rs index c92ece2f0..7db972e70 100644 --- a/pumpkin-crates/core/src/branching/branchers/autonomous_search.rs +++ b/pumpkin-crates/core/src/branching/branchers/autonomous_search.rs @@ -240,7 +240,7 @@ impl AutonomousSearch { return predicate; } // Match the truth value according to the best solution. - if solution.is_predicate_satisfied(predicate) { + if solution.evaluate_predicate(predicate) == Some(true) { predicate } else { !predicate diff --git a/pumpkin-crates/core/src/propagation/domains.rs b/pumpkin-crates/core/src/propagation/domains.rs index 1822594df..20a866ee7 100644 --- a/pumpkin-crates/core/src/propagation/domains.rs +++ b/pumpkin-crates/core/src/propagation/domains.rs @@ -32,15 +32,9 @@ impl HasAssignments for Domains<'_> { pub trait ReadDomains { fn evaluate_predicate(&self, predicate: Predicate) -> Option; - fn is_predicate_satisfied(&self, predicate: Predicate) -> bool; - - fn is_predicate_falsified(&self, predicate: Predicate) -> bool; - - fn is_literal_true(&self, literal: &Literal) -> bool; - - fn is_literal_false(&self, literal: &Literal) -> bool; - - fn is_literal_fixed(&self, literal: &Literal) -> bool; + fn evaluate_literal(&self, literal: Literal) -> Option { + self.evaluate_predicate(literal.get_true_predicate()) + } /// Returns the holes which were created on the current decision level. fn get_holes_at_current_checkpoint( @@ -88,36 +82,6 @@ impl ReadDomains for T { self.assignments().evaluate_predicate(predicate) } - fn is_predicate_satisfied(&self, predicate: Predicate) -> bool { - self.assignments() - .evaluate_predicate(predicate) - .is_some_and(|truth_value| truth_value) - } - - fn is_predicate_falsified(&self, predicate: Predicate) -> bool { - self.assignments() - .evaluate_predicate(predicate) - .is_some_and(|truth_value| !truth_value) - } - - fn is_literal_true(&self, literal: &Literal) -> bool { - literal - .get_integer_variable() - .lower_bound(self.assignments()) - == 1 - } - - fn is_literal_false(&self, literal: &Literal) -> bool { - literal - .get_integer_variable() - .upper_bound(self.assignments()) - == 0 - } - - fn is_literal_fixed(&self, literal: &Literal) -> bool { - self.is_fixed(literal) - } - /// Returns the holes which were created on the current decision level. fn get_holes_at_current_checkpoint( &self, diff --git a/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_equals.rs b/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_equals.rs index b364f112e..5fe14fc01 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_equals.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_equals.rs @@ -252,17 +252,19 @@ where // re-evaluate the values which have been removed if self.has_backtracked { self.has_backtracked = false; - self.a_removed_values - .retain(|element| context.is_predicate_satisfied(predicate!(self.a != *element))); - self.b_removed_values - .retain(|element| context.is_predicate_satisfied(predicate!(self.b != *element))); + self.a_removed_values.retain(|element| { + context.evaluate_predicate(predicate!(self.a != *element)) == Some(true) + }); + self.b_removed_values.retain(|element| { + context.evaluate_predicate(predicate!(self.b != *element)) == Some(true) + }); } // Then we remove all of the values which have been removed from `a` from `b` let mut a_removed_values = std::mem::take(&mut self.a_removed_values); for removed_value_a in a_removed_values.drain() { pumpkin_assert_advanced!( - context.is_predicate_satisfied(predicate!(self.a != removed_value_a)) + context.evaluate_predicate(predicate!(self.a != removed_value_a)) == Some(true) ); self.post( &mut context, @@ -277,7 +279,7 @@ where let mut b_removed_values = std::mem::take(&mut self.b_removed_values); for removed_value_b in b_removed_values.drain() { pumpkin_assert_advanced!( - context.is_predicate_satisfied(predicate!(self.b != removed_value_b)) + context.evaluate_predicate(predicate!(self.b != removed_value_b)) == Some(true) ); self.post( &mut context, diff --git a/pumpkin-crates/core/src/propagators/nogoods/nogood_propagator.rs b/pumpkin-crates/core/src/propagators/nogoods/nogood_propagator.rs index ffe8112a3..f36c89586 100644 --- a/pumpkin-crates/core/src/propagators/nogoods/nogood_propagator.rs +++ b/pumpkin-crates/core/src/propagators/nogoods/nogood_propagator.rs @@ -229,7 +229,7 @@ impl Propagator for NogoodPropagator { pumpkin_assert_moderate!( { let predicate = context.get_predicate(predicate_id); - context.is_predicate_satisfied(predicate) + context.evaluate_predicate(predicate) == Some(true) }, "The predicate {} with id {predicate_id:?} should be satisfied but was not", context.get_predicate(predicate_id), @@ -301,7 +301,7 @@ impl Propagator for NogoodPropagator { // At this point, nonwatched predicates and nogood[1] are falsified. pumpkin_assert_advanced!(nogood_predicates.iter().skip(1).all(|p| { let predicate = context.get_predicate(*p); - context.is_predicate_satisfied(predicate) + context.evaluate_predicate(predicate) == Some(true) })); // There are two scenarios: @@ -1122,13 +1122,17 @@ impl NogoodPropagator { // We assume that duplicate predicates have been removed // Check if the nogood cannot be violated, i.e., it has a falsified predicate. - if nogood.is_empty() || nogood.iter().any(|p| context.is_predicate_falsified(*p)) { + if nogood.is_empty() + || nogood + .iter() + .any(|p| context.evaluate_predicate(*p) == Some(false)) + { *nogood = vec![Predicate::trivially_false()]; return; } // Remove predicates that are satisfied at the root level. - nogood.retain(|p| !context.is_predicate_satisfied(*p)); + nogood.retain(|p| context.evaluate_predicate(*p) != Some(true)); // If the nogood is violating at the root, the previous retain would leave an empty nogood. // Return a violating nogood. @@ -1162,7 +1166,7 @@ impl NogoodPropagator { // First we get the number of falsified predicates let has_falsified_predicate = nogood.iter().any(|predicate| { let predicate = context.get_predicate(*predicate); - context.is_predicate_falsified(predicate) + context.evaluate_predicate(predicate) == Some(false) }); // If at least one predicate is false, then the nogood can be skipped @@ -1174,7 +1178,7 @@ impl NogoodPropagator { .iter() .filter(|predicate| { let predicate = context.get_predicate(**predicate); - context.is_predicate_satisfied(predicate) + context.evaluate_predicate(predicate) == Some(true) }) .count(); diff --git a/pumpkin-crates/core/src/propagators/reified_propagator.rs b/pumpkin-crates/core/src/propagators/reified_propagator.rs index 5ff4d182d..7da037520 100644 --- a/pumpkin-crates/core/src/propagators/reified_propagator.rs +++ b/pumpkin-crates/core/src/propagators/reified_propagator.rs @@ -121,7 +121,7 @@ impl Propagator for ReifiedPropagator PropagationStatusCP { self.propagate_reification(&mut context)?; - if context.is_literal_true(&self.reification_literal) { + if context.evaluate_literal(self.reification_literal) == Some(true) { context.with_reification(self.reification_literal); let result = self.propagator.propagate(context); @@ -142,7 +142,7 @@ impl Propagator for ReifiedPropagator PropagationStatusCP { self.propagate_reification(&mut context)?; - if context.is_literal_true(&self.reification_literal) { + if context.evaluate_literal(self.reification_literal) == Some(true) { context.with_reification(self.reification_literal); let result = self.propagator.debug_propagate_from_scratch(context); @@ -177,7 +177,7 @@ impl ReifiedPropagator { where Prop: Propagator, { - if context.is_literal_fixed(&self.reification_literal) { + if context.evaluate_literal(self.reification_literal) == Some(true) { return Ok(()); } @@ -205,13 +205,13 @@ impl ReifiedPropagator { return EnqueueDecision::Skip; } - if context.is_literal_true(&self.reification_literal) { + if context.evaluate_literal(self.reification_literal) == Some(true) { // If the propagator would have enqueued and the literal is true then the reified // propagator is also enqueued return EnqueueDecision::Enqueue; } - if !context.is_literal_false(&self.reification_literal) + if context.evaluate_literal(self.reification_literal) != Some(false) && self.propagator.detect_inconsistency(context).is_some() { // Or the literal is not false already and there the propagator has found an From 7d9f254bb029af52bf4dfb85ab39935324fa2ccc Mon Sep 17 00:00:00 2001 From: Maarten Flippo Date: Fri, 12 Dec 2025 15:32:06 +0100 Subject: [PATCH 08/29] Rename PropagationContextWithTrailedValues to NotificationContext --- pumpkin-crates/core/src/engine/cp/mod.rs | 8 +-- .../core/src/engine/cp/test_solver.rs | 6 +- .../core/src/engine/debug_helper.rs | 10 ++-- .../core/src/engine/notifications/mod.rs | 9 +-- pumpkin-crates/core/src/engine/state.rs | 8 +-- .../contexts/propagation_context.rs | 33 ++++++----- .../core/src/propagation/propagator.rs | 15 ++--- .../propagators/arithmetic/absolute_value.rs | 7 +-- .../arithmetic/binary/binary_equals.rs | 20 +++---- .../arithmetic/binary/binary_not_equals.rs | 16 ++--- .../arithmetic/integer_division.rs | 12 ++-- .../arithmetic/integer_multiplication.rs | 8 +-- .../arithmetic/linear_less_or_equal.rs | 18 ++---- .../arithmetic/linear_not_equal.rs | 13 ++-- .../src/propagators/arithmetic/maximum.rs | 7 +-- .../time_table/explanations/pointwise.rs | 6 +- .../time_table_over_interval_incremental.rs | 15 ++--- .../time_table_per_point_incremental.rs | 15 ++--- .../time_table/propagation_handler.rs | 24 ++++---- .../time_table/time_table_over_interval.rs | 15 ++--- .../time_table/time_table_per_point.rs | 15 ++--- .../cumulative/time_table/time_table_util.rs | 12 ++-- .../disjunctive/disjunctive_propagator.rs | 15 ++--- .../core/src/propagators/element.rs | 15 ++--- .../propagators/nogoods/nogood_propagator.rs | 18 +++--- .../src/propagators/reified_propagator.rs | 59 ++++++++----------- 26 files changed, 171 insertions(+), 228 deletions(-) diff --git a/pumpkin-crates/core/src/engine/cp/mod.rs b/pumpkin-crates/core/src/engine/cp/mod.rs index b081a100e..2e02c8c24 100644 --- a/pumpkin-crates/core/src/engine/cp/mod.rs +++ b/pumpkin-crates/core/src/engine/cp/mod.rs @@ -22,7 +22,7 @@ mod tests { use crate::engine::reason::ReasonStore; use crate::predicate; use crate::proof::InferenceCode; - use crate::propagation::PropagationContextMut; + use crate::propagation::PropagationContext; use crate::propagation::PropagatorId; #[test] @@ -35,7 +35,7 @@ mod tests { assert_eq!(reason_store.len(), 0); { let mut notification_engine = NotificationEngine::default(); - let mut context = PropagationContextMut::new( + let mut context = PropagationContext::new( &mut trailed_values, &mut assignments, &mut reason_store, @@ -64,7 +64,7 @@ mod tests { assert_eq!(reason_store.len(), 0); { let mut notification_engine = NotificationEngine::default(); - let mut context = PropagationContextMut::new( + let mut context = PropagationContext::new( &mut trailed_values, &mut assignments, &mut reason_store, @@ -93,7 +93,7 @@ mod tests { assert_eq!(reason_store.len(), 0); { let mut notification_engine = NotificationEngine::default(); - let mut context = PropagationContextMut::new( + let mut context = PropagationContext::new( &mut trailed_values, &mut assignments, &mut reason_store, diff --git a/pumpkin-crates/core/src/engine/cp/test_solver.rs b/pumpkin-crates/core/src/engine/cp/test_solver.rs index 6ee13a167..076b66ae2 100644 --- a/pumpkin-crates/core/src/engine/cp/test_solver.rs +++ b/pumpkin-crates/core/src/engine/cp/test_solver.rs @@ -20,7 +20,7 @@ use crate::proof::InferenceCode; use crate::propagation::Domains; use crate::propagation::EnqueueDecision; use crate::propagation::ExplanationContext; -use crate::propagation::PropagationContextMut; +use crate::propagation::PropagationContext; use crate::propagation::PropagatorConstructor; use crate::propagation::PropagatorId; use crate::propagators::nogoods::NogoodPropagator; @@ -212,7 +212,7 @@ impl TestSolver { } pub(crate) fn propagate(&mut self, propagator: PropagatorId) -> Result<(), Conflict> { - let context = PropagationContextMut::new( + let context = PropagationContext::new( &mut self.state.trailed_values, &mut self.state.assignments, &mut self.state.reason_store, @@ -231,7 +231,7 @@ impl TestSolver { loop { { // Specify the life-times to be able to retrieve the trail entries - let context = PropagationContextMut::new( + let context = PropagationContext::new( &mut self.state.trailed_values, &mut self.state.assignments, &mut self.state.reason_store, diff --git a/pumpkin-crates/core/src/engine/debug_helper.rs b/pumpkin-crates/core/src/engine/debug_helper.rs index c8883f88b..75b173624 100644 --- a/pumpkin-crates/core/src/engine/debug_helper.rs +++ b/pumpkin-crates/core/src/engine/debug_helper.rs @@ -11,7 +11,7 @@ use super::reason::ReasonStore; use crate::basic_types::PropositionalConjunction; use crate::engine::cp::Assignments; use crate::propagation::ExplanationContext; -use crate::propagation::PropagationContextMut; +use crate::propagation::PropagationContext; use crate::propagation::Propagator; use crate::propagation::PropagatorId; use crate::propagation::store::PropagatorStore; @@ -77,7 +77,7 @@ impl DebugHelper { let num_entries_on_trail_before_propagation = assignments_clone.num_trail_entries(); let mut reason_store = Default::default(); - let context = PropagationContextMut::new( + let context = PropagationContext::new( &mut trailed_values_clone, &mut assignments_clone, &mut reason_store, @@ -255,7 +255,7 @@ impl DebugHelper { if adding_predicates_was_successful { // Now propagate using the debug propagation method. let mut reason_store = Default::default(); - let context = PropagationContextMut::new( + let context = PropagationContext::new( &mut trailed_values_clone, &mut assignments_clone, &mut reason_store, @@ -370,7 +370,7 @@ impl DebugHelper { loop { let num_predicates_before = assignments_clone.num_trail_entries(); - let context = PropagationContextMut::new( + let context = PropagationContext::new( &mut trailed_values_clone, &mut assignments_clone, &mut reason_store, @@ -437,7 +437,7 @@ impl DebugHelper { if adding_predicates_was_successful { // now propagate using the debug propagation method let mut reason_store = Default::default(); - let context = PropagationContextMut::new( + let context = PropagationContext::new( &mut trailed_values_clone, &mut assignments_clone, &mut reason_store, diff --git a/pumpkin-crates/core/src/engine/notifications/mod.rs b/pumpkin-crates/core/src/engine/notifications/mod.rs index 6ccefcb87..e69a83bb6 100644 --- a/pumpkin-crates/core/src/engine/notifications/mod.rs +++ b/pumpkin-crates/core/src/engine/notifications/mod.rs @@ -20,7 +20,7 @@ use crate::predicates::Predicate; use crate::propagation::Domains; use crate::propagation::EnqueueDecision; use crate::propagation::LocalId; -use crate::propagation::PropagationContextWithTrailedValues; +use crate::propagation::NotificationContext; use crate::propagation::PropagatorId; use crate::propagation::PropagatorVarId; use crate::propagation::store::PropagatorStore; @@ -369,11 +369,8 @@ impl NotificationEngine { assignments: &mut Assignments, trailed_values: &mut TrailedValues, ) { - let context = PropagationContextWithTrailedValues::new( - trailed_values, - assignments, - predicate_id_assignments, - ); + let context = + NotificationContext::new(trailed_values, assignments, predicate_id_assignments); let enqueue_decision = propagators[propagator_id].notify(context, local_id, event.into()); diff --git a/pumpkin-crates/core/src/engine/state.rs b/pumpkin-crates/core/src/engine/state.rs index 5984e4e17..d576d2e3b 100644 --- a/pumpkin-crates/core/src/engine/state.rs +++ b/pumpkin-crates/core/src/engine/state.rs @@ -24,7 +24,7 @@ use crate::proof::ProofLog; use crate::propagation::CurrentNogood; use crate::propagation::Domains; use crate::propagation::ExplanationContext; -use crate::propagation::PropagationContextMut; +use crate::propagation::PropagationContext; use crate::propagation::Propagator; use crate::propagation::PropagatorConstructor; use crate::propagation::PropagatorConstructorContext; @@ -400,10 +400,10 @@ impl State { pub(crate) fn get_propagator_mut_with_context( &mut self, handle: PropagatorHandle

, - ) -> (Option<&mut P>, PropagationContextMut<'_>) { + ) -> (Option<&mut P>, PropagationContext<'_>) { ( self.propagators.get_propagator_mut(handle), - PropagationContextMut::new( + PropagationContext::new( &mut self.trailed_values, &mut self.assignments, &mut self.reason_store, @@ -545,7 +545,7 @@ impl State { let propagation_status = { let propagator = &mut self.propagators[propagator_id]; - let context = PropagationContextMut::new( + let context = PropagationContext::new( &mut self.trailed_values, &mut self.assignments, &mut self.reason_store, diff --git a/pumpkin-crates/core/src/propagation/contexts/propagation_context.rs b/pumpkin-crates/core/src/propagation/contexts/propagation_context.rs index 2d11f265f..b71d223d6 100644 --- a/pumpkin-crates/core/src/propagation/contexts/propagation_context.rs +++ b/pumpkin-crates/core/src/propagation/contexts/propagation_context.rs @@ -20,14 +20,18 @@ use crate::propagation::PropagatorId; use crate::propagation::ReadDomains; use crate::pumpkin_assert_simple; +/// Provided to the propagator when it is notified of a domain event. +/// +/// The difference with [`PropagationContext`] is that it is not possible to perform a propagation +/// in the notify callback. #[derive(Debug)] -pub struct PropagationContextWithTrailedValues<'a> { +pub struct NotificationContext<'a> { pub(crate) trailed_values: &'a mut TrailedValues, pub(crate) assignments: &'a Assignments, pub(crate) predicate_id_assignments: &'a PredicateIdAssignments, } -impl<'a> PropagationContextWithTrailedValues<'a> { +impl<'a> NotificationContext<'a> { pub(crate) fn new( trailed_values: &'a mut TrailedValues, assignments: &'a Assignments, @@ -40,7 +44,8 @@ impl<'a> PropagationContextWithTrailedValues<'a> { } } - pub(crate) fn domains(&self) -> Domains<'_> { + /// Get the current domains. + pub fn domains(&self) -> Domains<'_> { Domains { assignments: self.assignments, } @@ -50,9 +55,9 @@ impl<'a> PropagationContextWithTrailedValues<'a> { /// Provides information about the state of the solver to a propagator. /// /// Domains can be read through the implementation of [`ReadDomains`], and changes to the state can -/// be made via [`PropagationContextMut::post`]. +/// be made via [`Self::post`]. #[derive(Debug)] -pub struct PropagationContextMut<'a> { +pub struct PropagationContext<'a> { pub(crate) trailed_values: &'a mut TrailedValues, pub(crate) assignments: &'a mut Assignments, pub(crate) reason_store: &'a mut ReasonStore, @@ -61,7 +66,7 @@ pub struct PropagationContextMut<'a> { reification_literal: Option, } -impl<'a> PropagationContextMut<'a> { +impl<'a> PropagationContext<'a> { pub(crate) fn new( trailed_values: &'a mut TrailedValues, assignments: &'a mut Assignments, @@ -69,7 +74,7 @@ impl<'a> PropagationContextMut<'a> { notification_engine: &'a mut NotificationEngine, propagator_id: PropagatorId, ) -> Self { - PropagationContextMut { + PropagationContext { trailed_values, assignments, reason_store, @@ -114,8 +119,8 @@ impl<'a> PropagationContextMut<'a> { self.reification_literal = Some(reification_literal); } - pub(crate) fn as_trailed_readonly(&mut self) -> PropagationContextWithTrailedValues<'_> { - PropagationContextWithTrailedValues { + pub(crate) fn as_trailed_readonly(&mut self) -> NotificationContext<'_> { + NotificationContext { trailed_values: self.trailed_values, assignments: self.assignments, predicate_id_assignments: self.notification_engine.predicate_id_assignments(), @@ -162,7 +167,7 @@ mod private { use super::*; use crate::propagation::HasAssignments; - impl HasTrailedValues for PropagationContextWithTrailedValues<'_> { + impl HasTrailedValues for NotificationContext<'_> { fn trailed_values(&self) -> &TrailedValues { self.trailed_values } @@ -172,7 +177,7 @@ mod private { } } - impl HasTrailedValues for PropagationContextMut<'_> { + impl HasTrailedValues for PropagationContext<'_> { fn trailed_values(&self) -> &TrailedValues { self.trailed_values } @@ -182,13 +187,13 @@ mod private { } } - impl HasAssignments for PropagationContextMut<'_> { + impl HasAssignments for PropagationContext<'_> { fn assignments(&self) -> &Assignments { self.assignments } } - impl HasAssignments for PropagationContextWithTrailedValues<'_> { + impl HasAssignments for NotificationContext<'_> { fn assignments(&self) -> &Assignments { self.assignments } @@ -216,7 +221,7 @@ pub(crate) trait ManipulateTrailedValues: HasTrailedValues { impl ManipulateTrailedValues for T {} -impl PropagationContextMut<'_> { +impl PropagationContext<'_> { /// Assign the truth-value of the given [`Predicate`] to `true` in the current partial /// assignment. /// diff --git a/pumpkin-crates/core/src/propagation/propagator.rs b/pumpkin-crates/core/src/propagation/propagator.rs index c5433f726..fdc7929a6 100644 --- a/pumpkin-crates/core/src/propagation/propagator.rs +++ b/pumpkin-crates/core/src/propagation/propagator.rs @@ -5,8 +5,8 @@ use dyn_clone::clone_trait_object; use super::Domains; use super::ExplanationContext; -use super::PropagationContextMut; -use super::contexts::PropagationContextWithTrailedValues; +use super::PropagationContext; +use super::contexts::NotificationContext; use crate::basic_types::PredicateId; use crate::basic_types::PropagationStatusCP; use crate::basic_types::PropagatorConflict; @@ -57,7 +57,7 @@ pub trait Propagator: Downcast + DynClone { /// /// Propagators are not required to propagate until a fixed point. It will be called again by /// the solver until no further propagations happen. - fn debug_propagate_from_scratch(&self, context: PropagationContextMut) -> PropagationStatusCP; + fn debug_propagate_from_scratch(&self, context: PropagationContext) -> PropagationStatusCP; /// Performs stateful propagation. /// @@ -76,7 +76,7 @@ pub trait Propagator: Downcast + DynClone { /// again by the solver until no further propagations happen. /// /// By default, this function calls [`Propagator::debug_propagate_from_scratch`]. - fn propagate(&mut self, context: PropagationContextMut) -> PropagationStatusCP { + fn propagate(&mut self, context: PropagationContext) -> PropagationStatusCP { self.debug_propagate_from_scratch(context) } @@ -91,7 +91,7 @@ pub trait Propagator: Downcast + DynClone { /// propagators will benefit from implementing this, so it is not required to do so. fn notify( &mut self, - _context: PropagationContextWithTrailedValues, + _context: NotificationContext, _local_id: LocalId, _event: OpaqueDomainEvent, ) -> EnqueueDecision { @@ -145,10 +145,7 @@ pub trait Propagator: Downcast + DynClone { /// reification literal based on the detected inconsistency. Yet, an implementation is not /// needed for correctness, as [`Propagator::propagate`] should still check for /// inconsistency as well. - fn detect_inconsistency( - &self, - _context: PropagationContextWithTrailedValues, - ) -> Option { + fn detect_inconsistency(&self, _context: NotificationContext) -> Option { None } diff --git a/pumpkin-crates/core/src/propagators/arithmetic/absolute_value.rs b/pumpkin-crates/core/src/propagators/arithmetic/absolute_value.rs index 4e499a449..99a25ece5 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/absolute_value.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/absolute_value.rs @@ -7,7 +7,7 @@ use crate::proof::ConstraintTag; use crate::proof::InferenceCode; use crate::propagation::DomainEvents; use crate::propagation::LocalId; -use crate::propagation::PropagationContextMut; +use crate::propagation::PropagationContext; use crate::propagation::Propagator; use crate::propagation::PropagatorConstructor; use crate::propagation::PropagatorConstructorContext; @@ -73,10 +73,7 @@ where "IntAbs" } - fn debug_propagate_from_scratch( - &self, - mut context: PropagationContextMut, - ) -> PropagationStatusCP { + fn debug_propagate_from_scratch(&self, mut context: PropagationContext) -> PropagationStatusCP { // The bound of absolute may be tightened further during propagation, but it is at least // zero at the root. context.post( diff --git a/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_equals.rs b/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_equals.rs index 5fe14fc01..22d7a7312 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_equals.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_equals.rs @@ -24,8 +24,8 @@ use crate::propagation::Domains; use crate::propagation::EnqueueDecision; use crate::propagation::ExplanationContext; use crate::propagation::LocalId; -use crate::propagation::PropagationContextMut; -use crate::propagation::PropagationContextWithTrailedValues; +use crate::propagation::NotificationContext; +use crate::propagation::PropagationContext; use crate::propagation::Propagator; use crate::propagation::PropagatorConstructor; use crate::propagation::PropagatorConstructorContext; @@ -116,7 +116,7 @@ where { fn post( &self, - context: &mut PropagationContextMut, + context: &mut PropagationContext, variable: Variable, predicate_type: PredicateType, value: i32, @@ -152,10 +152,7 @@ where AVar: IntegerVariable + 'static, BVar: IntegerVariable + 'static, { - fn detect_inconsistency( - &self, - context: PropagationContextWithTrailedValues, - ) -> Option { + fn detect_inconsistency(&self, context: NotificationContext) -> Option { let a_lb = context.lower_bound(&self.a); let a_ub = context.upper_bound(&self.a); @@ -185,7 +182,7 @@ where fn notify( &mut self, - context: PropagationContextWithTrailedValues, + context: NotificationContext, local_id: LocalId, event: OpaqueDomainEvent, ) -> EnqueueDecision { @@ -225,7 +222,7 @@ where "BinaryEq" } - fn propagate(&mut self, mut context: PropagationContextMut) -> PropagationStatusCP { + fn propagate(&mut self, mut context: PropagationContext) -> PropagationStatusCP { if self.first_propagation_loop { // If it is the first propagation loop then we do full propagation self.first_propagation_loop = false; @@ -316,10 +313,7 @@ where slice::from_ref(&self.reason) } - fn debug_propagate_from_scratch( - &self, - mut context: PropagationContextMut, - ) -> PropagationStatusCP { + fn debug_propagate_from_scratch(&self, mut context: PropagationContext) -> PropagationStatusCP { let a_lb = context.lower_bound(&self.a); let a_ub = context.upper_bound(&self.a); diff --git a/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_not_equals.rs b/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_not_equals.rs index 06e5f7408..624696157 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_not_equals.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_not_equals.rs @@ -8,8 +8,8 @@ use crate::proof::ConstraintTag; use crate::proof::InferenceCode; use crate::propagation::DomainEvents; use crate::propagation::LocalId; -use crate::propagation::PropagationContextMut; -use crate::propagation::PropagationContextWithTrailedValues; +use crate::propagation::NotificationContext; +use crate::propagation::PropagationContext; use crate::propagation::Propagator; use crate::propagation::PropagatorConstructor; use crate::propagation::PropagatorConstructorContext; @@ -66,10 +66,7 @@ where AVar: IntegerVariable + 'static, BVar: IntegerVariable + 'static, { - fn detect_inconsistency( - &self, - context: PropagationContextWithTrailedValues, - ) -> Option { + fn detect_inconsistency(&self, context: NotificationContext) -> Option { // We first check whether they are both fixed if context.is_fixed(&self.a) && context.is_fixed(&self.b) { let lb_a = context.lower_bound(&self.a); @@ -98,7 +95,7 @@ where "BinaryNotEq" } - fn propagate(&mut self, mut context: PropagationContextMut) -> PropagationStatusCP { + fn propagate(&mut self, mut context: PropagationContext) -> PropagationStatusCP { if let Some(conflict) = self.detect_inconsistency(context.as_trailed_readonly()) { return Err(conflict.into()); } @@ -135,10 +132,7 @@ where Ok(()) } - fn debug_propagate_from_scratch( - &self, - mut context: PropagationContextMut, - ) -> PropagationStatusCP { + fn debug_propagate_from_scratch(&self, mut context: PropagationContext) -> PropagationStatusCP { if let Some(conflict) = self.detect_inconsistency(context.as_trailed_readonly()) { return Err(conflict.into()); } diff --git a/pumpkin-crates/core/src/propagators/arithmetic/integer_division.rs b/pumpkin-crates/core/src/propagators/arithmetic/integer_division.rs index 1d7ba23ff..085c14e5d 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/integer_division.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/integer_division.rs @@ -7,7 +7,7 @@ use crate::proof::ConstraintTag; use crate::proof::InferenceCode; use crate::propagation::DomainEvents; use crate::propagation::LocalId; -use crate::propagation::PropagationContextMut; +use crate::propagation::PropagationContext; use crate::propagation::Propagator; use crate::propagation::PropagatorConstructor; use crate::propagation::PropagatorConstructorContext; @@ -93,7 +93,7 @@ where "Division" } - fn debug_propagate_from_scratch(&self, context: PropagationContextMut) -> PropagationStatusCP { + fn debug_propagate_from_scratch(&self, context: PropagationContext) -> PropagationStatusCP { perform_propagation( context, &self.numerator, @@ -105,7 +105,7 @@ where } fn perform_propagation( - mut context: PropagationContextMut, + mut context: PropagationContext, numerator: &VA, denominator: &VB, rhs: &VC, @@ -189,7 +189,7 @@ fn perform_propagation( - context: &mut PropagationContextMut, + context: &mut PropagationContext, numerator: &VA, denominator: &VB, rhs: &VC, @@ -279,7 +279,7 @@ fn propagate_positive_domains( - context: &mut PropagationContextMut, + context: &mut PropagationContext, numerator: &VA, denominator: &VB, rhs: &VC, @@ -325,7 +325,7 @@ fn propagate_upper_bounds( - context: &mut PropagationContextMut, + context: &mut PropagationContext, numerator: &VA, denominator: &VB, rhs: &VC, diff --git a/pumpkin-crates/core/src/propagators/arithmetic/integer_multiplication.rs b/pumpkin-crates/core/src/propagators/arithmetic/integer_multiplication.rs index b544e7137..63122b0a8 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/integer_multiplication.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/integer_multiplication.rs @@ -8,7 +8,7 @@ use crate::proof::ConstraintTag; use crate::proof::InferenceCode; use crate::propagation::DomainEvents; use crate::propagation::LocalId; -use crate::propagation::PropagationContextMut; +use crate::propagation::PropagationContext; use crate::propagation::Propagator; use crate::propagation::PropagatorConstructor; use crate::propagation::PropagatorConstructorContext; @@ -85,13 +85,13 @@ where "IntTimes" } - fn debug_propagate_from_scratch(&self, context: PropagationContextMut) -> PropagationStatusCP { + fn debug_propagate_from_scratch(&self, context: PropagationContext) -> PropagationStatusCP { perform_propagation(context, &self.a, &self.b, &self.c, self.inference_code) } } fn perform_propagation( - mut context: PropagationContextMut, + mut context: PropagationContext, a: &VA, b: &VB, c: &VC, @@ -214,7 +214,7 @@ fn perform_propagation( - context: &mut PropagationContextMut, + context: &mut PropagationContext, a: &VA, b: &VB, c: &VC, diff --git a/pumpkin-crates/core/src/propagators/arithmetic/linear_less_or_equal.rs b/pumpkin-crates/core/src/propagators/arithmetic/linear_less_or_equal.rs index 7fc3694c0..9bd6405ba 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/linear_less_or_equal.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/linear_less_or_equal.rs @@ -15,8 +15,8 @@ use crate::propagation::EnqueueDecision; use crate::propagation::ExplanationContext; use crate::propagation::LocalId; use crate::propagation::ManipulateTrailedValues; -use crate::propagation::PropagationContextMut; -use crate::propagation::PropagationContextWithTrailedValues; +use crate::propagation::NotificationContext; +use crate::propagation::PropagationContext; use crate::propagation::Propagator; use crate::propagation::PropagatorConstructor; use crate::propagation::PropagatorConstructorContext; @@ -108,10 +108,7 @@ impl Propagator for LinearLessOrEqualPropagator where Var: IntegerVariable, { - fn detect_inconsistency( - &self, - context: PropagationContextWithTrailedValues, - ) -> Option { + fn detect_inconsistency(&self, context: NotificationContext) -> Option { if (self.c as i64) < context.value(self.lower_bound_left_hand_side) { Some(self.create_conflict(context.domains())) } else { @@ -121,7 +118,7 @@ where fn notify( &mut self, - mut context: PropagationContextWithTrailedValues, + mut context: NotificationContext, local_id: LocalId, _event: OpaqueDomainEvent, ) -> EnqueueDecision { @@ -170,7 +167,7 @@ where &self.reason_buffer } - fn propagate(&mut self, mut context: PropagationContextMut) -> PropagationStatusCP { + fn propagate(&mut self, mut context: PropagationContext) -> PropagationStatusCP { if let Some(conflict) = self.detect_inconsistency(context.as_trailed_readonly()) { return Err(conflict.into()); } @@ -208,10 +205,7 @@ where Ok(()) } - fn debug_propagate_from_scratch( - &self, - mut context: PropagationContextMut, - ) -> PropagationStatusCP { + fn debug_propagate_from_scratch(&self, mut context: PropagationContext) -> PropagationStatusCP { let lower_bound_left_hand_side = self .x .iter() diff --git a/pumpkin-crates/core/src/propagators/arithmetic/linear_not_equal.rs b/pumpkin-crates/core/src/propagators/arithmetic/linear_not_equal.rs index 963bf1c74..66eafc61d 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/linear_not_equal.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/linear_not_equal.rs @@ -16,8 +16,8 @@ use crate::propagation::DomainEvents; use crate::propagation::Domains; use crate::propagation::EnqueueDecision; use crate::propagation::LocalId; -use crate::propagation::PropagationContextMut; -use crate::propagation::PropagationContextWithTrailedValues; +use crate::propagation::NotificationContext; +use crate::propagation::PropagationContext; use crate::propagation::Propagator; use crate::propagation::PropagatorConstructor; use crate::propagation::PropagatorConstructorContext; @@ -118,7 +118,7 @@ where fn notify( &mut self, - context: PropagationContextWithTrailedValues, + context: NotificationContext, local_id: LocalId, _event: OpaqueDomainEvent, ) -> EnqueueDecision { @@ -173,7 +173,7 @@ where } } - fn propagate(&mut self, mut context: PropagationContextMut) -> PropagationStatusCP { + fn propagate(&mut self, mut context: PropagationContext) -> PropagationStatusCP { // If the left-hand side is out of date then we simply recalculate from scratch; we only do // this when we can propagate or check for a conflict if self.should_recalculate_lhs && self.number_of_fixed_terms >= self.terms.len() - 1 { @@ -223,10 +223,7 @@ where Ok(()) } - fn debug_propagate_from_scratch( - &self, - mut context: PropagationContextMut, - ) -> PropagationStatusCP { + fn debug_propagate_from_scratch(&self, mut context: PropagationContext) -> PropagationStatusCP { let num_fixed = self .terms .iter() diff --git a/pumpkin-crates/core/src/propagators/arithmetic/maximum.rs b/pumpkin-crates/core/src/propagators/arithmetic/maximum.rs index 219cc3783..c1457e67d 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/maximum.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/maximum.rs @@ -8,7 +8,7 @@ use crate::proof::ConstraintTag; use crate::proof::InferenceCode; use crate::propagation::DomainEvents; use crate::propagation::LocalId; -use crate::propagation::PropagationContextMut; +use crate::propagation::PropagationContext; use crate::propagation::Propagator; use crate::propagation::PropagatorConstructor; use crate::propagation::PropagatorConstructorContext; @@ -77,10 +77,7 @@ impl Prop "Maximum" } - fn debug_propagate_from_scratch( - &self, - mut context: PropagationContextMut, - ) -> PropagationStatusCP { + fn debug_propagate_from_scratch(&self, mut context: PropagationContext) -> PropagationStatusCP { // This is the constraint that is being propagated: // max(a_0, a_1, ..., a_{n-1}) = rhs diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/explanations/pointwise.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/explanations/pointwise.rs index dc1d29f7f..e6cf85914 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/explanations/pointwise.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/explanations/pointwise.rs @@ -6,7 +6,7 @@ use crate::predicate; use crate::predicates::Predicate; use crate::predicates::PropositionalConjunction; use crate::proof::InferenceCode; -use crate::propagation::PropagationContextMut; +use crate::propagation::PropagationContext; use crate::propagation::ReadDomains; use crate::propagators::ResourceProfile; use crate::propagators::Task; @@ -17,7 +17,7 @@ use crate::pumpkin_assert_simple; use crate::variables::IntegerVariable; pub(crate) fn propagate_lower_bounds_with_pointwise_explanations( - context: &mut PropagationContextMut, + context: &mut PropagationContext, profiles: &[&ResourceProfile], propagating_task: &Rc>, inference_code: InferenceCode, @@ -126,7 +126,7 @@ pub(crate) fn propagate_lower_bounds_with_pointwise_explanations( - context: &mut PropagationContextMut, + context: &mut PropagationContext, profiles: &[&ResourceProfile], propagating_task: &Rc>, inference_code: InferenceCode, diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/time_table_over_interval_incremental.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/time_table_over_interval_incremental.rs index 6cd6fdf2a..dd91444b9 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/time_table_over_interval_incremental.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/time_table_over_interval_incremental.rs @@ -10,12 +10,12 @@ use crate::conjunction; use crate::engine::notifications::OpaqueDomainEvent; use crate::engine::notifications::DomainEvent; use crate::propagation::PropagatorConstructorContext; -use crate::propagation::PropagationContextWithTrailedValues; +use crate::propagation::NotificationContext; use crate::propagation::PropagatorConstructor; use crate::propagation::EnqueueDecision; use crate::propagation::LocalId; use crate::propagation::Domains; -use crate::propagation::PropagationContextMut; +use crate::propagation::PropagationContext; use crate::propagation::Propagator; use crate::engine::variables::IntegerVariable; use crate::proof::ConstraintTag; @@ -235,7 +235,7 @@ impl /// [`TimeTableOverIntervalIncrementalPropagator::is_time_table_outdated`] is true. /// /// An error is returned if an overflow of the resource occurs while updating the time-table. - fn update_time_table(&mut self, context: &mut PropagationContextMut) -> PropagationStatusCP { + fn update_time_table(&mut self, context: &mut PropagationContext) -> PropagationStatusCP { if self.is_time_table_outdated { // We create the time-table from scratch (and return an error if it overflows) self.time_table = create_time_table_over_interval_from_scratch( @@ -375,7 +375,7 @@ impl impl Propagator for TimeTableOverIntervalIncrementalPropagator { - fn propagate(&mut self, mut context: PropagationContextMut) -> PropagationStatusCP { + fn propagate(&mut self, mut context: PropagationContext) -> PropagationStatusCP { pumpkin_assert_advanced!( check_bounds_equal_at_propagation( context.domains(), @@ -419,7 +419,7 @@ impl Propagator fn notify( &mut self, - context: PropagationContextWithTrailedValues, + context: NotificationContext, local_id: LocalId, event: OpaqueDomainEvent, ) -> EnqueueDecision { @@ -506,10 +506,7 @@ impl Propagator "CumulativeTimeTableOverIntervalIncremental" } - fn debug_propagate_from_scratch( - &self, - mut context: PropagationContextMut, - ) -> PropagationStatusCP { + fn debug_propagate_from_scratch(&self, mut context: PropagationContext) -> PropagationStatusCP { // Use the same debug propagator from `TimeTableOverInterval` debug_propagate_from_scratch_time_table_interval( &mut context, diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/time_table_per_point_incremental.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/time_table_per_point_incremental.rs index 8b7063373..19e6c7a2a 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/time_table_per_point_incremental.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/time_table_per_point_incremental.rs @@ -14,8 +14,8 @@ use crate::proof::InferenceCode; use crate::propagation::Domains; use crate::propagation::EnqueueDecision; use crate::propagation::LocalId; -use crate::propagation::PropagationContextMut; -use crate::propagation::PropagationContextWithTrailedValues; +use crate::propagation::NotificationContext; +use crate::propagation::PropagationContext; use crate::propagation::Propagator; use crate::propagation::PropagatorConstructor; use crate::propagation::PropagatorConstructorContext; @@ -253,7 +253,7 @@ impl /// [`DynamicStructures::updated`]. /// /// An error is returned if an overflow of the resource occurs while updating the time-table. - fn update_time_table(&mut self, context: &mut PropagationContextMut) -> PropagationStatusCP { + fn update_time_table(&mut self, context: &mut PropagationContext) -> PropagationStatusCP { if self.is_time_table_outdated { // We create the time-table from scratch (and return an error if it overflows) self.time_table = create_time_table_per_point_from_scratch( @@ -404,7 +404,7 @@ impl impl Propagator for TimeTablePerPointIncrementalPropagator { - fn propagate(&mut self, mut context: PropagationContextMut) -> PropagationStatusCP { + fn propagate(&mut self, mut context: PropagationContext) -> PropagationStatusCP { pumpkin_assert_advanced!( check_bounds_equal_at_propagation( context.domains(), @@ -446,7 +446,7 @@ impl Propagator fn notify( &mut self, - context: PropagationContextWithTrailedValues, + context: NotificationContext, local_id: LocalId, event: OpaqueDomainEvent, ) -> EnqueueDecision { @@ -531,10 +531,7 @@ impl Propagator "CumulativeTimeTablePerPointIncremental" } - fn debug_propagate_from_scratch( - &self, - mut context: PropagationContextMut, - ) -> PropagationStatusCP { + fn debug_propagate_from_scratch(&self, mut context: PropagationContext) -> PropagationStatusCP { // Use the same debug propagator from `TimeTablePerPoint` debug_propagate_from_scratch_time_table_point( &mut context, diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/propagation_handler.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/propagation_handler.rs index 685af540d..e097add28 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/propagation_handler.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/propagation_handler.rs @@ -22,7 +22,7 @@ use crate::predicates::PropositionalConjunction; use crate::proof::InferenceCode; use crate::propagation::Domains; use crate::propagation::HasAssignments; -use crate::propagation::PropagationContextMut; +use crate::propagation::PropagationContext; use crate::propagation::ReadDomains; use crate::propagators::ResourceProfile; use crate::propagators::Task; @@ -86,7 +86,7 @@ impl CumulativePropagationHandler { /// `profiles` anymore. pub(crate) fn propagate_chain_of_lower_bounds_with_explanations( &mut self, - context: &mut PropagationContextMut, + context: &mut PropagationContext, profiles: &[&ResourceProfile], propagating_task: &Rc>, ) -> Result<(), EmptyDomainConflict> @@ -151,7 +151,7 @@ impl CumulativePropagationHandler { /// `profiles` anymore. pub(crate) fn propagate_chain_of_upper_bounds_with_explanations( &mut self, - context: &mut PropagationContextMut, + context: &mut PropagationContext, profiles: &[&ResourceProfile], propagating_task: &Rc>, ) -> Result<(), EmptyDomainConflict> @@ -216,7 +216,7 @@ impl CumulativePropagationHandler { /// Propagates the lower-bound of the `propagating_task` to not conflict with `profile` anymore. pub(crate) fn propagate_lower_bound_with_explanations( &mut self, - context: &mut PropagationContextMut, + context: &mut PropagationContext, profile: &ResourceProfile, propagating_task: &Rc>, ) -> Result<(), EmptyDomainConflict> @@ -267,7 +267,7 @@ impl CumulativePropagationHandler { /// Propagates the upper-bound of the `propagating_task` to not conflict with `profile` anymore. pub(crate) fn propagate_upper_bound_with_explanations( &mut self, - context: &mut PropagationContextMut, + context: &mut PropagationContext, profile: &ResourceProfile, propagating_task: &Rc>, ) -> Result<(), EmptyDomainConflict> @@ -323,7 +323,7 @@ impl CumulativePropagationHandler { /// bounds of `propagating_task`. pub(crate) fn propagate_holes_in_domain( &mut self, - context: &mut PropagationContextMut, + context: &mut PropagationContext, profile: &ResourceProfile, propagating_task: &Rc>, ) -> Result<(), EmptyDomainConflict> @@ -422,7 +422,7 @@ impl CumulativePropagationHandler { /// Either we get the stored stored profile explanation or we initialize it. fn get_stored_profile_explanation_or_init( &mut self, - context: &mut PropagationContextMut, + context: &mut PropagationContext, profile: &ResourceProfile, ) -> Rc where @@ -494,7 +494,7 @@ pub(crate) mod test_propagation_handler { use crate::propagation::Domains; use crate::propagation::ExplanationContext; use crate::propagation::LocalId; - use crate::propagation::PropagationContextMut; + use crate::propagation::PropagationContext; use crate::propagation::PropagatorId; use crate::propagation::store::PropagatorStore; use crate::propagators::ResourceProfile; @@ -589,7 +589,7 @@ pub(crate) mod test_propagation_handler { let result = self .propagation_handler .propagate_lower_bound_with_explanations( - &mut PropagationContextMut::new( + &mut PropagationContext::new( &mut self.trailed_values, &mut self.assignments, &mut self.reason_store, @@ -653,7 +653,7 @@ pub(crate) mod test_propagation_handler { let result = self .propagation_handler .propagate_chain_of_lower_bounds_with_explanations( - &mut PropagationContextMut::new( + &mut PropagationContext::new( &mut self.trailed_values, &mut self.assignments, &mut self.reason_store, @@ -703,7 +703,7 @@ pub(crate) mod test_propagation_handler { let result = self .propagation_handler .propagate_upper_bound_with_explanations( - &mut PropagationContextMut::new( + &mut PropagationContext::new( &mut self.trailed_values, &mut self.assignments, &mut self.reason_store, @@ -767,7 +767,7 @@ pub(crate) mod test_propagation_handler { let result = self .propagation_handler .propagate_chain_of_upper_bounds_with_explanations( - &mut PropagationContextMut::new( + &mut PropagationContext::new( &mut self.trailed_values, &mut self.assignments, &mut self.reason_store, diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_over_interval.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_over_interval.rs index 6a0aff53e..0aa87bb86 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_over_interval.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_over_interval.rs @@ -14,8 +14,8 @@ use crate::proof::InferenceCode; use crate::propagation::Domains; use crate::propagation::EnqueueDecision; use crate::propagation::LocalId; -use crate::propagation::PropagationContextMut; -use crate::propagation::PropagationContextWithTrailedValues; +use crate::propagation::NotificationContext; +use crate::propagation::PropagationContext; use crate::propagation::Propagator; use crate::propagation::PropagatorConstructor; use crate::propagation::PropagatorConstructorContext; @@ -117,7 +117,7 @@ impl PropagatorConstructor } impl Propagator for TimeTableOverIntervalPropagator { - fn propagate(&mut self, mut context: PropagationContextMut) -> PropagationStatusCP { + fn propagate(&mut self, mut context: PropagationContext) -> PropagationStatusCP { if self.parameters.is_infeasible { return Err(Conflict::Propagator(PropagatorConflict { conjunction: conjunction!(), @@ -149,7 +149,7 @@ impl Propagator for TimeTableOverIntervalPropaga fn notify( &mut self, - context: PropagationContextWithTrailedValues, + context: NotificationContext, local_id: LocalId, event: OpaqueDomainEvent, ) -> EnqueueDecision { @@ -191,10 +191,7 @@ impl Propagator for TimeTableOverIntervalPropaga "CumulativeTimeTableOverInterval" } - fn debug_propagate_from_scratch( - &self, - mut context: PropagationContextMut, - ) -> PropagationStatusCP { + fn debug_propagate_from_scratch(&self, mut context: PropagationContext) -> PropagationStatusCP { debug_propagate_from_scratch_time_table_interval( &mut context, &self.parameters, @@ -450,7 +447,7 @@ fn check_starting_new_profile_invariants( } pub(crate) fn debug_propagate_from_scratch_time_table_interval( - context: &mut PropagationContextMut, + context: &mut PropagationContext, parameters: &CumulativeParameters, updatable_structures: &UpdatableStructures, inference_code: InferenceCode, diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_per_point.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_per_point.rs index 497ddacf7..a1e67215c 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_per_point.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_per_point.rs @@ -19,8 +19,8 @@ use crate::proof::InferenceCode; use crate::propagation::Domains; use crate::propagation::EnqueueDecision; use crate::propagation::LocalId; -use crate::propagation::PropagationContextMut; -use crate::propagation::PropagationContextWithTrailedValues; +use crate::propagation::NotificationContext; +use crate::propagation::PropagationContext; use crate::propagation::Propagator; use crate::propagation::PropagatorConstructor; use crate::propagation::PropagatorConstructorContext; @@ -108,7 +108,7 @@ impl PropagatorConstructor for TimeTablePerPoint } impl Propagator for TimeTablePerPointPropagator { - fn propagate(&mut self, mut context: PropagationContextMut) -> PropagationStatusCP { + fn propagate(&mut self, mut context: PropagationContext) -> PropagationStatusCP { if self.parameters.is_infeasible { return Err(Conflict::Propagator(PropagatorConflict { conjunction: conjunction!(), @@ -140,7 +140,7 @@ impl Propagator for TimeTablePerPointPropagator< fn notify( &mut self, - context: PropagationContextWithTrailedValues, + context: NotificationContext, local_id: LocalId, event: OpaqueDomainEvent, ) -> EnqueueDecision { @@ -184,10 +184,7 @@ impl Propagator for TimeTablePerPointPropagator< "CumulativeTimeTablePerPoint" } - fn debug_propagate_from_scratch( - &self, - mut context: PropagationContextMut, - ) -> PropagationStatusCP { + fn debug_propagate_from_scratch(&self, mut context: PropagationContext) -> PropagationStatusCP { debug_propagate_from_scratch_time_table_point( &mut context, self.inference_code.unwrap(), @@ -254,7 +251,7 @@ pub(crate) fn create_time_table_per_point_from_scratch< } pub(crate) fn debug_propagate_from_scratch_time_table_point( - context: &mut PropagationContextMut, + context: &mut PropagationContext, inference_code: InferenceCode, parameters: &CumulativeParameters, updatable_structures: &UpdatableStructures, diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_util.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_util.rs index a986bcedd..3da6bd22d 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_util.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_util.rs @@ -10,7 +10,7 @@ use crate::engine::variables::IntegerVariable; use crate::proof::InferenceCode; use crate::propagation::Domains; use crate::propagation::EnqueueDecision; -use crate::propagation::PropagationContextMut; +use crate::propagation::PropagationContext; #[cfg(doc)] use crate::propagation::Propagator; use crate::propagation::ReadDomains; @@ -200,7 +200,7 @@ fn debug_check_whether_profiles_are_maximal_and_sorted<'a, Var: IntegerVariable /// [`ResourceProfile`] is maximal (i.e. the [`ResourceProfile::start`] and [`ResourceProfile::end`] /// cannot be increased or decreased, respectively). pub(crate) fn propagate_based_on_timetable<'a, Var: IntegerVariable + 'static>( - context: &mut PropagationContextMut, + context: &mut PropagationContext, inference_code: InferenceCode, time_table: impl Iterator> + Clone, parameters: &CumulativeParameters, @@ -255,7 +255,7 @@ pub(crate) fn propagate_based_on_timetable<'a, Var: IntegerVariable + 'static>( /// This type of propagation is likely to be less beneficial for the explanation /// [`CumulativeExplanationType::Pointwise`]. fn propagate_single_profiles<'a, Var: IntegerVariable + 'static>( - context: &mut PropagationContextMut, + context: &mut PropagationContext, inference_code: InferenceCode, time_table: impl Iterator> + Clone, updatable_structures: &mut UpdatableStructures, @@ -358,7 +358,7 @@ fn propagate_single_profiles<'a, Var: IntegerVariable + 'static>( /// Especially in the case of [`CumulativeExplanationType::Pointwise`] this is likely to be /// beneficial. fn propagate_sequence_of_profiles<'a, Var: IntegerVariable + 'static>( - context: &mut PropagationContextMut, + context: &mut PropagationContext, inference_code: InferenceCode, time_table: impl Iterator> + Clone, updatable_structures: &mut UpdatableStructures, @@ -437,7 +437,7 @@ fn propagate_sequence_of_profiles<'a, Var: IntegerVariable + 'static>( fn sweep_forward<'a, Var: IntegerVariable + 'static>( task: &Rc>, propagation_handler: &mut CumulativePropagationHandler, - context: &mut PropagationContextMut, + context: &mut PropagationContext, time_table: &[&'a ResourceProfile], parameters: &CumulativeParameters, profile_buffer: &mut Vec<&'a ResourceProfile>, @@ -501,7 +501,7 @@ fn sweep_forward<'a, Var: IntegerVariable + 'static>( fn sweep_backward<'a, Var: IntegerVariable + 'static>( task: &Rc>, propagation_handler: &mut CumulativePropagationHandler, - context: &mut PropagationContextMut, + context: &mut PropagationContext, time_table: &[&'a ResourceProfile], parameters: &CumulativeParameters, profile_buffer: &mut Vec<&'a ResourceProfile>, diff --git a/pumpkin-crates/core/src/propagators/disjunctive/disjunctive_propagator.rs b/pumpkin-crates/core/src/propagators/disjunctive/disjunctive_propagator.rs index 02396e392..52cf0716f 100644 --- a/pumpkin-crates/core/src/propagators/disjunctive/disjunctive_propagator.rs +++ b/pumpkin-crates/core/src/propagators/disjunctive/disjunctive_propagator.rs @@ -13,7 +13,7 @@ use crate::proof::ConstraintTag; use crate::proof::InferenceCode; use crate::propagation::DomainEvents; use crate::propagation::LocalId; -use crate::propagation::PropagationContextMut; +use crate::propagation::PropagationContext; use crate::propagation::Propagator; use crate::propagation::PropagatorConstructor; use crate::propagation::PropagatorConstructorContext; @@ -111,7 +111,7 @@ impl Propagator for DisjunctivePropagator { "DisjunctiveStrict" } - fn propagate(&mut self, mut context: PropagationContextMut) -> PropagationStatusCP { + fn propagate(&mut self, mut context: PropagationContext) -> PropagationStatusCP { edge_finding( &mut self.theta_lambda_tree, &mut context, @@ -121,10 +121,7 @@ impl Propagator for DisjunctivePropagator { ) } - fn debug_propagate_from_scratch( - &self, - mut context: PropagationContextMut, - ) -> PropagationStatusCP { + fn debug_propagate_from_scratch(&self, mut context: PropagationContext) -> PropagationStatusCP { let mut sorted_tasks = self.sorted_tasks.clone(); let mut theta_lambda_tree = self.theta_lambda_tree.clone(); edge_finding( @@ -141,7 +138,7 @@ impl Propagator for DisjunctivePropagator { /// this implementation is based). fn edge_finding( theta_lambda_tree: &mut ThetaLambdaTree, - context: &mut PropagationContextMut, + context: &mut PropagationContext, tasks: &[DisjunctiveTask], sorted_tasks: &mut [DisjunctiveTask], inference_code: InferenceCode, @@ -242,7 +239,7 @@ fn edge_finding( /// Edge-Finding Propagator’. fn create_conflict_explanation( theta_lambda_tree: &mut ThetaLambdaTree, - context: &PropagationContextMut, + context: &PropagationContext, lct: i32, ) -> PropositionalConjunction { // We get the set of tasks currently in theta @@ -307,7 +304,7 @@ fn create_propagation_explanation<'a, Var: IntegerVariable>( original_tasks: &'a [DisjunctiveTask], propagated_task_id: LocalId, theta_lambda_tree: &mut ThetaLambdaTree, - context: &'a PropagationContextMut, + context: &'a PropagationContext, new_bound: i32, lct_j: i32, ) -> PropositionalConjunction { diff --git a/pumpkin-crates/core/src/propagators/element.rs b/pumpkin-crates/core/src/propagators/element.rs index 71d6e46eb..c34b5473d 100644 --- a/pumpkin-crates/core/src/propagators/element.rs +++ b/pumpkin-crates/core/src/propagators/element.rs @@ -14,7 +14,7 @@ use crate::proof::InferenceCode; use crate::propagation::DomainEvents; use crate::propagation::ExplanationContext; use crate::propagation::LocalId; -use crate::propagation::PropagationContextMut; +use crate::propagation::PropagationContext; use crate::propagation::Propagator; use crate::propagation::PropagatorConstructor; use crate::propagation::PropagatorConstructorContext; @@ -103,10 +103,7 @@ where "Element" } - fn debug_propagate_from_scratch( - &self, - mut context: PropagationContextMut, - ) -> PropagationStatusCP { + fn debug_propagate_from_scratch(&self, mut context: PropagationContext) -> PropagationStatusCP { self.propagate_index_bounds_within_array(&mut context)?; self.propagate_rhs_bounds_based_on_array(&mut context)?; @@ -154,7 +151,7 @@ where /// Propagate the bounds of `self.index` to be in the range `[0, self.array.len())`. fn propagate_index_bounds_within_array( &self, - context: &mut PropagationContextMut<'_>, + context: &mut PropagationContext<'_>, ) -> PropagationStatusCP { context.post( predicate![self.index >= 0], @@ -173,7 +170,7 @@ where /// bound (res. maximum upper bound) of the elements. fn propagate_rhs_bounds_based_on_array( &self, - context: &mut PropagationContextMut<'_>, + context: &mut PropagationContext<'_>, ) -> PropagationStatusCP { let (rhs_lb, rhs_ub) = self .array @@ -215,7 +212,7 @@ where /// right-hand side, remove it from index. fn propagate_index_based_on_domain_intersection_with_rhs( &self, - context: &mut PropagationContextMut<'_>, + context: &mut PropagationContext<'_>, ) -> PropagationStatusCP { let rhs_lb = context.lower_bound(&self.rhs); let rhs_ub = context.upper_bound(&self.rhs); @@ -248,7 +245,7 @@ where /// tightened to the bounds of lhs, through a previous propagation rule. fn propagate_equality( &self, - context: &mut PropagationContextMut<'_>, + context: &mut PropagationContext<'_>, index: i32, ) -> PropagationStatusCP { let rhs_lb = context.lower_bound(&self.rhs); diff --git a/pumpkin-crates/core/src/propagators/nogoods/nogood_propagator.rs b/pumpkin-crates/core/src/propagators/nogoods/nogood_propagator.rs index f36c89586..ab7636a3d 100644 --- a/pumpkin-crates/core/src/propagators/nogoods/nogood_propagator.rs +++ b/pumpkin-crates/core/src/propagators/nogoods/nogood_propagator.rs @@ -26,7 +26,7 @@ use crate::propagation::Domains; use crate::propagation::EnqueueDecision; use crate::propagation::ExplanationContext; use crate::propagation::HasAssignments; -use crate::propagation::PropagationContextMut; +use crate::propagation::PropagationContext; use crate::propagation::Propagator; use crate::propagation::PropagatorConstructor; use crate::propagation::PropagatorConstructorContext; @@ -208,7 +208,7 @@ impl Propagator for NogoodPropagator { EnqueueDecision::Enqueue } - fn propagate(&mut self, mut context: PropagationContextMut) -> Result<(), Conflict> { + fn propagate(&mut self, mut context: PropagationContext) -> Result<(), Conflict> { pumpkin_assert_advanced!(self.debug_is_properly_watched()); // First we perform nogood management to ensure that the database does not grow excessively @@ -335,7 +335,7 @@ impl Propagator for NogoodPropagator { fn debug_propagate_from_scratch( &self, - mut context: PropagationContextMut, + mut context: PropagationContext, ) -> Result<(), Conflict> { // Very inefficient version! @@ -428,7 +428,7 @@ impl NogoodPropagator { &mut self, nogood: Vec, inference_code: InferenceCode, - context: &mut PropagationContextMut, + context: &mut PropagationContext, statistics: &mut SolverStatistics, ) { // We treat unit nogoods in a special way by adding it as a permanent nogood at the @@ -516,7 +516,7 @@ impl NogoodPropagator { &mut self, nogood: Vec, inference_code: InferenceCode, - context: &mut PropagationContextMut, + context: &mut PropagationContext, ) -> PropagationStatusCP { self.add_permanent_nogood(nogood, inference_code, context) } @@ -526,7 +526,7 @@ impl NogoodPropagator { &mut self, mut nogood: Vec, inference_code: InferenceCode, - context: &mut PropagationContextMut, + context: &mut PropagationContext, ) -> PropagationStatusCP { pumpkin_assert_simple!( context.get_checkpoint() == 0, @@ -664,7 +664,7 @@ impl NogoodPropagator { impl NogoodPropagator { /// Adds a watcher to the predicate. fn add_watcher( - context: &mut PropagationContextMut, + context: &mut PropagationContext, predicate: PredicateId, watcher: Watcher, watch_lists: &mut KeyedVec>, @@ -1110,7 +1110,7 @@ impl NogoodPropagator { /// 3. Detecting predicates falsified at the root. In that case, the nogood is preprocessed /// to the empty nogood. /// 4. Conflicting predicates? - fn preprocess_nogood(nogood: &mut Vec, context: &mut PropagationContextMut) { + fn preprocess_nogood(nogood: &mut Vec, context: &mut PropagationContext) { pumpkin_assert_simple!(context.get_checkpoint() == 0); // The code below is broken down into several parts @@ -1149,7 +1149,7 @@ impl NogoodPropagator { fn debug_propagate_nogood_from_scratch( &self, nogood_id: NogoodId, - context: &mut PropagationContextMut, + context: &mut PropagationContext, ) -> Result<(), Conflict> { // This is an inefficient implementation for testing purposes let nogood = &self.nogood_predicates[nogood_id]; diff --git a/pumpkin-crates/core/src/propagators/reified_propagator.rs b/pumpkin-crates/core/src/propagators/reified_propagator.rs index 7da037520..3bb6963ba 100644 --- a/pumpkin-crates/core/src/propagators/reified_propagator.rs +++ b/pumpkin-crates/core/src/propagators/reified_propagator.rs @@ -6,8 +6,8 @@ use crate::propagation::Domains; use crate::propagation::EnqueueDecision; use crate::propagation::ExplanationContext; use crate::propagation::LocalId; -use crate::propagation::PropagationContextMut; -use crate::propagation::PropagationContextWithTrailedValues; +use crate::propagation::NotificationContext; +use crate::propagation::PropagationContext; use crate::propagation::Propagator; use crate::propagation::PropagatorConstructor; use crate::propagation::PropagatorConstructorContext; @@ -81,13 +81,13 @@ pub(crate) struct ReifiedPropagator { impl Propagator for ReifiedPropagator { fn notify( &mut self, - context: PropagationContextWithTrailedValues, + context: NotificationContext, local_id: LocalId, event: OpaqueDomainEvent, ) -> EnqueueDecision { if local_id < self.reification_literal_id { let decision = self.propagator.notify( - PropagationContextWithTrailedValues::new( + NotificationContext::new( context.trailed_values, context.assignments, context.predicate_id_assignments, @@ -118,7 +118,7 @@ impl Propagator for ReifiedPropagator PropagationStatusCP { + fn propagate(&mut self, mut context: PropagationContext) -> PropagationStatusCP { self.propagate_reification(&mut context)?; if context.evaluate_literal(self.reification_literal) == Some(true) { @@ -136,10 +136,7 @@ impl Propagator for ReifiedPropagator PropagationStatusCP { + fn debug_propagate_from_scratch(&self, mut context: PropagationContext) -> PropagationStatusCP { self.propagate_reification(&mut context)?; if context.evaluate_literal(self.reification_literal) == Some(true) { @@ -173,7 +170,7 @@ impl ReifiedPropagator { status } - fn propagate_reification(&self, context: &mut PropagationContextMut<'_>) -> PropagationStatusCP + fn propagate_reification(&self, context: &mut PropagationContext<'_>) -> PropagationStatusCP where Prop: Propagator, { @@ -197,7 +194,7 @@ impl ReifiedPropagator { fn filter_enqueue_decision( &mut self, - context: PropagationContextWithTrailedValues<'_>, + context: NotificationContext<'_>, decision: EnqueueDecision, ) -> EnqueueDecision { if decision == EnqueueDecision::Skip { @@ -252,14 +249,14 @@ mod tests { let _ = solver .new_propagator(ReifiedPropagatorArgs { propagator: GenericPropagator::new( - move |_: PropagationContextMut| { + move |_: PropagationContext| { Err(PropagatorConflict { conjunction: t1.clone(), inference_code, } .into()) }, - move |_: PropagationContextWithTrailedValues| { + move |_: NotificationContext| { Some(PropagatorConflict { conjunction: t2.clone(), inference_code, @@ -286,7 +283,7 @@ mod tests { let propagator = solver .new_propagator(ReifiedPropagatorArgs { propagator: GenericPropagator::new( - move |mut ctx: PropagationContextMut| { + move |mut ctx: PropagationContext| { ctx.post( predicate![var >= 3], conjunction!(), @@ -294,7 +291,7 @@ mod tests { )?; Ok(()) }, - |_: PropagationContextWithTrailedValues| None, + |_: NotificationContext| None, ), reification_literal, }) @@ -326,14 +323,14 @@ mod tests { let inconsistency = solver .new_propagator(ReifiedPropagatorArgs { propagator: GenericPropagator::new( - move |_: PropagationContextMut| { + move |_: PropagationContext| { Err(PropagatorConflict { conjunction: conjunction!([var >= 1]), inference_code, } .into()) }, - |_: PropagationContextWithTrailedValues| None, + |_: NotificationContext| None, ), reification_literal, }) @@ -366,8 +363,8 @@ mod tests { let propagator = solver .new_propagator(ReifiedPropagatorArgs { propagator: GenericPropagator::new( - |_: PropagationContextMut| Ok(()), - move |context: PropagationContextWithTrailedValues| { + |_: PropagationContext| Ok(()), + move |context: NotificationContext| { if context.is_fixed(&var) { Some(PropagatorConflict { conjunction: conjunction!([var == 5]), @@ -397,9 +394,8 @@ mod tests { impl PropagatorConstructor for GenericPropagator where - Propagation: Fn(PropagationContextMut) -> PropagationStatusCP + 'static + Clone, - ConsistencyCheck: - Fn(PropagationContextWithTrailedValues) -> Option + 'static + Clone, + Propagation: Fn(PropagationContext) -> PropagationStatusCP + 'static + Clone, + ConsistencyCheck: Fn(NotificationContext) -> Option + 'static + Clone, { type PropagatorImpl = Self; @@ -418,33 +414,26 @@ mod tests { impl Propagator for GenericPropagator where - Propagation: Fn(PropagationContextMut) -> PropagationStatusCP + 'static + Clone, - ConsistencyCheck: - Fn(PropagationContextWithTrailedValues) -> Option + 'static + Clone, + Propagation: Fn(PropagationContext) -> PropagationStatusCP + 'static + Clone, + ConsistencyCheck: Fn(NotificationContext) -> Option + 'static + Clone, { fn name(&self) -> &str { "Generic Propagator" } - fn debug_propagate_from_scratch( - &self, - context: PropagationContextMut, - ) -> PropagationStatusCP { + fn debug_propagate_from_scratch(&self, context: PropagationContext) -> PropagationStatusCP { (self.propagation)(context) } - fn detect_inconsistency( - &self, - context: PropagationContextWithTrailedValues, - ) -> Option { + fn detect_inconsistency(&self, context: NotificationContext) -> Option { (self.consistency_check)(context) } } impl GenericPropagator where - Propagation: Fn(PropagationContextMut) -> PropagationStatusCP, - ConsistencyCheck: Fn(PropagationContextWithTrailedValues) -> Option, + Propagation: Fn(PropagationContext) -> PropagationStatusCP, + ConsistencyCheck: Fn(NotificationContext) -> Option, { pub(crate) fn new(propagation: Propagation, consistency_check: ConsistencyCheck) -> Self { GenericPropagator { From 58ea7d2001a9c434d8ade33bcb0291a5ff62c49a Mon Sep 17 00:00:00 2001 From: Maarten Flippo Date: Fri, 12 Dec 2025 15:50:48 +0100 Subject: [PATCH 09/29] Rename PropagationContextWithTrailedValues to NotificationContext --- pumpkin-crates/core/src/engine/cp/mod.rs | 2 +- .../core/src/engine/cp/test_solver.rs | 7 ++++- .../core/src/engine/cp/trailed/mod.rs | 2 +- .../src/engine/cp/trailed/trailed_integer.rs | 2 +- .../core/src/engine/notifications/mod.rs | 7 ++--- pumpkin-crates/core/src/engine/state.rs | 10 ++++--- .../core/src/propagation/constructor.rs | 4 +-- .../contexts/propagation_context.rs | 16 ++--------- .../core/src/propagation/domains.rs | 15 ++++++++-- pumpkin-crates/core/src/propagation/mod.rs | 5 ++++ .../core/src/propagation/propagator.rs | 4 +-- .../arithmetic/binary/binary_equals.rs | 12 ++++---- .../arithmetic/binary/binary_not_equals.rs | 14 +++++----- .../arithmetic/linear_less_or_equal.rs | 8 +++--- .../time_table/propagation_handler.rs | 2 +- .../cumulative/time_table/time_table_util.rs | 7 +++-- .../disjunctive/theta_lambda_tree.rs | 17 +++++++---- .../src/propagators/reified_propagator.rs | 28 +++++++++---------- 18 files changed, 89 insertions(+), 73 deletions(-) diff --git a/pumpkin-crates/core/src/engine/cp/mod.rs b/pumpkin-crates/core/src/engine/cp/mod.rs index 2e02c8c24..e987703a0 100644 --- a/pumpkin-crates/core/src/engine/cp/mod.rs +++ b/pumpkin-crates/core/src/engine/cp/mod.rs @@ -8,7 +8,7 @@ pub(crate) use assignments::Assignments; pub(crate) use assignments::ConstraintProgrammingTrailEntry; pub use assignments::EmptyDomain; pub(crate) use propagator_queue::PropagatorQueue; -pub(crate) use trailed::*; +pub use trailed::*; #[cfg(test)] mod tests { diff --git a/pumpkin-crates/core/src/engine/cp/test_solver.rs b/pumpkin-crates/core/src/engine/cp/test_solver.rs index 076b66ae2..f9bd4b44e 100644 --- a/pumpkin-crates/core/src/engine/cp/test_solver.rs +++ b/pumpkin-crates/core/src/engine/cp/test_solver.rs @@ -338,6 +338,11 @@ impl TestSolver { self.state .propagators .iter_propagators_mut() - .for_each(|propagator| propagator.synchronise(Domains::new(&self.state.assignments))) + .for_each(|propagator| { + propagator.synchronise(Domains::new( + &self.state.assignments, + &self.state.trailed_values, + )) + }) } } diff --git a/pumpkin-crates/core/src/engine/cp/trailed/mod.rs b/pumpkin-crates/core/src/engine/cp/trailed/mod.rs index 6b322b555..3ce409b29 100644 --- a/pumpkin-crates/core/src/engine/cp/trailed/mod.rs +++ b/pumpkin-crates/core/src/engine/cp/trailed/mod.rs @@ -2,5 +2,5 @@ mod trailed_change; mod trailed_integer; mod trailed_values; pub(crate) use trailed_change::TrailedChange; -pub(crate) use trailed_integer::TrailedInteger; +pub use trailed_integer::TrailedInteger; pub(crate) use trailed_values::TrailedValues; diff --git a/pumpkin-crates/core/src/engine/cp/trailed/trailed_integer.rs b/pumpkin-crates/core/src/engine/cp/trailed/trailed_integer.rs index 3ceeef972..17736f089 100644 --- a/pumpkin-crates/core/src/engine/cp/trailed/trailed_integer.rs +++ b/pumpkin-crates/core/src/engine/cp/trailed/trailed_integer.rs @@ -1,7 +1,7 @@ use crate::containers::StorageKey; #[derive(Debug, Clone, Copy)] -pub(crate) struct TrailedInteger { +pub struct TrailedInteger { id: u32, } diff --git a/pumpkin-crates/core/src/engine/notifications/mod.rs b/pumpkin-crates/core/src/engine/notifications/mod.rs index e69a83bb6..02056376d 100644 --- a/pumpkin-crates/core/src/engine/notifications/mod.rs +++ b/pumpkin-crates/core/src/engine/notifications/mod.rs @@ -309,6 +309,7 @@ impl NotificationEngine { pub(crate) fn process_backtrack_events( &mut self, assignments: &mut Assignments, + trailed_values: &TrailedValues, propagators: &mut PropagatorStore, ) -> bool { // If there are no variables being watched then there is no reason to perform these @@ -327,7 +328,7 @@ impl NotificationEngine { .get_backtrack_affected_propagators(event, domain) { let propagator = &mut propagators[propagator_var.propagator]; - let context = Domains::new(assignments); + let context = Domains::new(assignments, trailed_values); propagator.notify_backtrack(context, propagator_var.variable, event.into()) } @@ -514,10 +515,6 @@ impl NotificationEngine { result } - pub(crate) fn predicate_id_assignments(&self) -> &PredicateIdAssignments { - &self.predicate_notifier.predicate_id_assignments - } - pub(crate) fn synchronise( &mut self, backtrack_level: usize, diff --git a/pumpkin-crates/core/src/engine/state.rs b/pumpkin-crates/core/src/engine/state.rs index d576d2e3b..1845aa015 100644 --- a/pumpkin-crates/core/src/engine/state.rs +++ b/pumpkin-crates/core/src/engine/state.rs @@ -505,13 +505,15 @@ impl State { // + allow incremental synchronisation // + only call the subset of propagators that were notified since last backtrack for propagator in self.propagators.iter_propagators_mut() { - let context = Domains::new(&self.assignments); + let context = Domains::new(&self.assignments, &self.trailed_values); propagator.synchronise(context); } - let _ = self - .notification_engine - .process_backtrack_events(&mut self.assignments, &mut self.propagators); + let _ = self.notification_engine.process_backtrack_events( + &mut self.assignments, + &self.trailed_values, + &mut self.propagators, + ); self.notification_engine.clear_event_drain(); self.notification_engine diff --git a/pumpkin-crates/core/src/propagation/constructor.rs b/pumpkin-crates/core/src/propagation/constructor.rs index 28a80b6f4..bd10b2864 100644 --- a/pumpkin-crates/core/src/propagation/constructor.rs +++ b/pumpkin-crates/core/src/propagation/constructor.rs @@ -67,9 +67,7 @@ impl PropagatorConstructorContext<'_> { /// Get domain information. pub fn as_readonly(&self) -> Domains<'_> { - Domains { - assignments: &self.state.assignments, - } + Domains::new(&self.state.assignments, &self.state.trailed_values) } /// Subscribes the propagator to the given [`DomainEvents`]. diff --git a/pumpkin-crates/core/src/propagation/contexts/propagation_context.rs b/pumpkin-crates/core/src/propagation/contexts/propagation_context.rs index b71d223d6..708977c07 100644 --- a/pumpkin-crates/core/src/propagation/contexts/propagation_context.rs +++ b/pumpkin-crates/core/src/propagation/contexts/propagation_context.rs @@ -46,9 +46,7 @@ impl<'a> NotificationContext<'a> { /// Get the current domains. pub fn domains(&self) -> Domains<'_> { - Domains { - assignments: self.assignments, - } + Domains::new(self.assignments, self.trailed_values) } } @@ -119,19 +117,9 @@ impl<'a> PropagationContext<'a> { self.reification_literal = Some(reification_literal); } - pub(crate) fn as_trailed_readonly(&mut self) -> NotificationContext<'_> { - NotificationContext { - trailed_values: self.trailed_values, - assignments: self.assignments, - predicate_id_assignments: self.notification_engine.predicate_id_assignments(), - } - } - /// Get the current domain information. pub fn domains(&self) -> Domains<'_> { - Domains { - assignments: self.assignments, - } + Domains::new(self.assignments, self.trailed_values) } pub(crate) fn get_checkpoint(&self) -> usize { diff --git a/pumpkin-crates/core/src/propagation/domains.rs b/pumpkin-crates/core/src/propagation/domains.rs index 20a866ee7..a8bf757b8 100644 --- a/pumpkin-crates/core/src/propagation/domains.rs +++ b/pumpkin-crates/core/src/propagation/domains.rs @@ -1,4 +1,6 @@ use crate::engine::Assignments; +use crate::engine::TrailedInteger; +use crate::engine::TrailedValues; use crate::predicates::Predicate; use crate::variables::IntegerVariable; use crate::variables::Literal; @@ -10,11 +12,20 @@ use crate::variables::Literal; #[derive(Clone, Copy, Debug)] pub struct Domains<'a> { pub(crate) assignments: &'a Assignments, + trailed_values: &'a TrailedValues, } impl<'a> Domains<'a> { - pub(crate) fn new(assignments: &'a Assignments) -> Self { - Domains { assignments } + pub(crate) fn new(assignments: &'a Assignments, trailed_values: &'a TrailedValues) -> Self { + Domains { + assignments, + trailed_values, + } + } + + /// Read the value of a [`TrailedInteger`]. + pub fn value(&self, trailed_integer: TrailedInteger) -> i64 { + self.trailed_values.read(trailed_integer) } } diff --git a/pumpkin-crates/core/src/propagation/mod.rs b/pumpkin-crates/core/src/propagation/mod.rs index d451c5e7d..468fc4a81 100644 --- a/pumpkin-crates/core/src/propagation/mod.rs +++ b/pumpkin-crates/core/src/propagation/mod.rs @@ -79,6 +79,10 @@ pub(crate) mod propagator_id; pub(crate) mod propagator_var_id; pub(crate) mod store; +// BEGIN: Re-exports of types not in this module according to the file tree. +// These will probably be be moved at some point, but for now they are simply re-exported here to +// make the propagator API public. +// END pub use constructor::*; pub use contexts::*; pub use domains::*; @@ -90,6 +94,7 @@ pub(crate) use propagator_var_id::PropagatorVarId; #[cfg(doc)] use crate::Solver; pub use crate::basic_types::PredicateId; +pub use crate::engine::cp::TrailedInteger; pub use crate::engine::notifications::DomainEvent; pub use crate::engine::notifications::DomainEvents; #[cfg(doc)] diff --git a/pumpkin-crates/core/src/propagation/propagator.rs b/pumpkin-crates/core/src/propagation/propagator.rs index fdc7929a6..4c3e086b8 100644 --- a/pumpkin-crates/core/src/propagation/propagator.rs +++ b/pumpkin-crates/core/src/propagation/propagator.rs @@ -126,7 +126,7 @@ pub trait Propagator: Downcast + DynClone { /// update its internal data structures given the new variable domains. /// /// By default this function does nothing. - fn synchronise(&mut self, _context: Domains) {} + fn synchronise(&mut self, _domains: Domains) {} /// Returns the priority of the propagator represented as an integer. Lower values mean higher /// priority and the priority determines the order in which propagators will be asked to @@ -145,7 +145,7 @@ pub trait Propagator: Downcast + DynClone { /// reification literal based on the detected inconsistency. Yet, an implementation is not /// needed for correctness, as [`Propagator::propagate`] should still check for /// inconsistency as well. - fn detect_inconsistency(&self, _context: NotificationContext) -> Option { + fn detect_inconsistency(&self, _domains: Domains) -> Option { None } diff --git a/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_equals.rs b/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_equals.rs index 22d7a7312..b491139b6 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_equals.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_equals.rs @@ -152,12 +152,12 @@ where AVar: IntegerVariable + 'static, BVar: IntegerVariable + 'static, { - fn detect_inconsistency(&self, context: NotificationContext) -> Option { - let a_lb = context.lower_bound(&self.a); - let a_ub = context.upper_bound(&self.a); + fn detect_inconsistency(&self, domains: Domains) -> Option { + let a_lb = domains.lower_bound(&self.a); + let a_ub = domains.upper_bound(&self.a); - let b_lb = context.lower_bound(&self.b); - let b_ub = context.upper_bound(&self.b); + let b_lb = domains.lower_bound(&self.b); + let b_ub = domains.upper_bound(&self.b); if a_ub < b_lb { // If `a` is fully before `b` then we report a conflict @@ -229,7 +229,7 @@ where return self.debug_propagate_from_scratch(context); } - if let Some(conflict) = self.detect_inconsistency(context.as_trailed_readonly()) { + if let Some(conflict) = self.detect_inconsistency(context.domains()) { return Err(conflict.into()); } diff --git a/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_not_equals.rs b/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_not_equals.rs index 624696157..dd90e8812 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_not_equals.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_not_equals.rs @@ -7,8 +7,8 @@ use crate::predicate; use crate::proof::ConstraintTag; use crate::proof::InferenceCode; use crate::propagation::DomainEvents; +use crate::propagation::Domains; use crate::propagation::LocalId; -use crate::propagation::NotificationContext; use crate::propagation::PropagationContext; use crate::propagation::Propagator; use crate::propagation::PropagatorConstructor; @@ -66,11 +66,11 @@ where AVar: IntegerVariable + 'static, BVar: IntegerVariable + 'static, { - fn detect_inconsistency(&self, context: NotificationContext) -> Option { + fn detect_inconsistency(&self, domains: Domains) -> Option { // We first check whether they are both fixed - if context.is_fixed(&self.a) && context.is_fixed(&self.b) { - let lb_a = context.lower_bound(&self.a); - let lb_b = context.lower_bound(&self.b); + if domains.is_fixed(&self.a) && domains.is_fixed(&self.b) { + let lb_a = domains.lower_bound(&self.a); + let lb_b = domains.lower_bound(&self.b); // If they are, then we check whether they are assigned to the same value if lb_a == lb_b { @@ -96,7 +96,7 @@ where } fn propagate(&mut self, mut context: PropagationContext) -> PropagationStatusCP { - if let Some(conflict) = self.detect_inconsistency(context.as_trailed_readonly()) { + if let Some(conflict) = self.detect_inconsistency(context.domains()) { return Err(conflict.into()); } @@ -133,7 +133,7 @@ where } fn debug_propagate_from_scratch(&self, mut context: PropagationContext) -> PropagationStatusCP { - if let Some(conflict) = self.detect_inconsistency(context.as_trailed_readonly()) { + if let Some(conflict) = self.detect_inconsistency(context.domains()) { return Err(conflict.into()); } diff --git a/pumpkin-crates/core/src/propagators/arithmetic/linear_less_or_equal.rs b/pumpkin-crates/core/src/propagators/arithmetic/linear_less_or_equal.rs index 9bd6405ba..4fbc7eed3 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/linear_less_or_equal.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/linear_less_or_equal.rs @@ -108,9 +108,9 @@ impl Propagator for LinearLessOrEqualPropagator where Var: IntegerVariable, { - fn detect_inconsistency(&self, context: NotificationContext) -> Option { - if (self.c as i64) < context.value(self.lower_bound_left_hand_side) { - Some(self.create_conflict(context.domains())) + fn detect_inconsistency(&self, domains: Domains) -> Option { + if (self.c as i64) < domains.value(self.lower_bound_left_hand_side) { + Some(self.create_conflict(domains)) } else { None } @@ -168,7 +168,7 @@ where } fn propagate(&mut self, mut context: PropagationContext) -> PropagationStatusCP { - if let Some(conflict) = self.detect_inconsistency(context.as_trailed_readonly()) { + if let Some(conflict) = self.detect_inconsistency(context.domains()) { return Err(conflict.into()); } diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/propagation_handler.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/propagation_handler.rs index e097add28..428f5734e 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/propagation_handler.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/propagation_handler.rs @@ -548,7 +548,7 @@ pub(crate) mod test_propagation_handler { }; let reason = create_conflict_explanation( - Domains::new(&self.assignments), + Domains::new(&self.assignments, &self.trailed_values), self.propagation_handler.inference_code, &profile, self.propagation_handler.explanation_type, diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_util.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_util.rs index 3da6bd22d..13ed34423 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_util.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_util.rs @@ -773,6 +773,7 @@ mod tests { use super::find_profiles_which_propagate_lower_bound; use crate::engine::Assignments; + use crate::engine::TrailedValues; use crate::propagation::Domains; use crate::propagation::LocalId; use crate::propagators::ResourceProfile; @@ -782,6 +783,7 @@ mod tests { #[test] fn test_finding_last_index_lower_bound() { let mut assignments = Assignments::default(); + let trailed_values = TrailedValues::default(); let x = assignments.grow(0, 10); let y = assignments.grow(5, 5); @@ -816,7 +818,7 @@ mod tests { find_profiles_which_propagate_lower_bound( 0, &time_table, - Domains::new(&assignments), + Domains::new(&assignments, &trailed_values), &Rc::new(Task { start_variable: x, processing_time: 6, @@ -832,6 +834,7 @@ mod tests { #[test] fn test_finding_last_index_upper_bound() { let mut assignments = Assignments::default(); + let trailed_values = TrailedValues::default(); let x = assignments.grow(7, 7); let y = assignments.grow(5, 5); @@ -866,7 +869,7 @@ mod tests { find_profiles_which_propagate_upper_bound( 1, &time_table, - Domains::new(&assignments), + Domains::new(&assignments, &trailed_values), &Rc::new(Task { start_variable: x, processing_time: 6, diff --git a/pumpkin-crates/core/src/propagators/disjunctive/theta_lambda_tree.rs b/pumpkin-crates/core/src/propagators/disjunctive/theta_lambda_tree.rs index 422282874..84dea11f5 100644 --- a/pumpkin-crates/core/src/propagators/disjunctive/theta_lambda_tree.rs +++ b/pumpkin-crates/core/src/propagators/disjunctive/theta_lambda_tree.rs @@ -414,14 +414,21 @@ mod tests { let mut tree = ThetaLambdaTree::new(&tasks); - tree.update(Domains { - assignments: &solver.state.assignments, - }); + tree.update(Domains::new( + &solver.state.assignments, + &solver.state.trailed_values, + )); for task in tasks.iter() { - tree.add_to_theta(task, Domains::new(&solver.state.assignments)); + tree.add_to_theta( + task, + Domains::new(&solver.state.assignments, &solver.state.trailed_values), + ); } tree.remove_from_theta(&tasks[2]); - tree.add_to_lambda(&tasks[2], Domains::new(&solver.state.assignments)); + tree.add_to_lambda( + &tasks[2], + Domains::new(&solver.state.assignments, &solver.state.trailed_values), + ); assert_eq!( tree.nodes[6], diff --git a/pumpkin-crates/core/src/propagators/reified_propagator.rs b/pumpkin-crates/core/src/propagators/reified_propagator.rs index 3bb6963ba..b1d4f70ad 100644 --- a/pumpkin-crates/core/src/propagators/reified_propagator.rs +++ b/pumpkin-crates/core/src/propagators/reified_propagator.rs @@ -178,10 +178,7 @@ impl ReifiedPropagator { return Ok(()); } - if let Some(conflict) = self - .propagator - .detect_inconsistency(context.as_trailed_readonly()) - { + if let Some(conflict) = self.propagator.detect_inconsistency(context.domains()) { context.post( self.reification_literal.get_false_predicate(), conflict.conjunction, @@ -209,7 +206,10 @@ impl ReifiedPropagator { } if context.evaluate_literal(self.reification_literal) != Some(false) - && self.propagator.detect_inconsistency(context).is_some() + && self + .propagator + .detect_inconsistency(context.domains()) + .is_some() { // Or the literal is not false already and there the propagator has found an // inconsistency (i.e. we should and can propagate the reification variable) @@ -256,7 +256,7 @@ mod tests { } .into()) }, - move |_: NotificationContext| { + move |_: Domains| { Some(PropagatorConflict { conjunction: t2.clone(), inference_code, @@ -291,7 +291,7 @@ mod tests { )?; Ok(()) }, - |_: NotificationContext| None, + |_: Domains| None, ), reification_literal, }) @@ -330,7 +330,7 @@ mod tests { } .into()) }, - |_: NotificationContext| None, + |_: Domains| None, ), reification_literal, }) @@ -364,7 +364,7 @@ mod tests { .new_propagator(ReifiedPropagatorArgs { propagator: GenericPropagator::new( |_: PropagationContext| Ok(()), - move |context: NotificationContext| { + move |context: Domains| { if context.is_fixed(&var) { Some(PropagatorConflict { conjunction: conjunction!([var == 5]), @@ -395,7 +395,7 @@ mod tests { for GenericPropagator where Propagation: Fn(PropagationContext) -> PropagationStatusCP + 'static + Clone, - ConsistencyCheck: Fn(NotificationContext) -> Option + 'static + Clone, + ConsistencyCheck: Fn(Domains) -> Option + 'static + Clone, { type PropagatorImpl = Self; @@ -415,7 +415,7 @@ mod tests { impl Propagator for GenericPropagator where Propagation: Fn(PropagationContext) -> PropagationStatusCP + 'static + Clone, - ConsistencyCheck: Fn(NotificationContext) -> Option + 'static + Clone, + ConsistencyCheck: Fn(Domains) -> Option + 'static + Clone, { fn name(&self) -> &str { "Generic Propagator" @@ -425,15 +425,15 @@ mod tests { (self.propagation)(context) } - fn detect_inconsistency(&self, context: NotificationContext) -> Option { - (self.consistency_check)(context) + fn detect_inconsistency(&self, domains: Domains) -> Option { + (self.consistency_check)(domains) } } impl GenericPropagator where Propagation: Fn(PropagationContext) -> PropagationStatusCP, - ConsistencyCheck: Fn(NotificationContext) -> Option, + ConsistencyCheck: Fn(Domains) -> Option, { pub(crate) fn new(propagation: Propagation, consistency_check: ConsistencyCheck) -> Self { GenericPropagator { From 17181820b325db9b821d7c5e46bdb7fec0bffeac Mon Sep 17 00:00:00 2001 From: Maarten Flippo Date: Fri, 12 Dec 2025 15:52:01 +0100 Subject: [PATCH 10/29] Rename as_readonly to domains again --- pumpkin-crates/core/src/propagation/constructor.rs | 2 +- .../core/src/propagators/arithmetic/linear_not_equal.rs | 2 +- .../time_table_over_interval_incremental.rs | 2 +- .../time_table_per_point_incremental.rs | 2 +- .../cumulative/time_table/time_table_over_interval.rs | 2 +- .../propagators/cumulative/time_table/time_table_per_point.rs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pumpkin-crates/core/src/propagation/constructor.rs b/pumpkin-crates/core/src/propagation/constructor.rs index bd10b2864..22e499853 100644 --- a/pumpkin-crates/core/src/propagation/constructor.rs +++ b/pumpkin-crates/core/src/propagation/constructor.rs @@ -66,7 +66,7 @@ impl PropagatorConstructorContext<'_> { } /// Get domain information. - pub fn as_readonly(&self) -> Domains<'_> { + pub fn domains(&self) -> Domains<'_> { Domains::new(&self.state.assignments, &self.state.trailed_values) } diff --git a/pumpkin-crates/core/src/propagators/arithmetic/linear_not_equal.rs b/pumpkin-crates/core/src/propagators/arithmetic/linear_not_equal.rs index 66eafc61d..8d0605719 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/linear_not_equal.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/linear_not_equal.rs @@ -73,7 +73,7 @@ where inference_code: context.create_inference_code(constraint_tag, LinearNotEquals), }; - propagator.recalculate_fixed_variables(context.as_readonly()); + propagator.recalculate_fixed_variables(context.domains()); propagator } diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/time_table_over_interval_incremental.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/time_table_over_interval_incremental.rs index dd91444b9..a2b6271c9 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/time_table_over_interval_incremental.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/time_table_over_interval_incremental.rs @@ -117,7 +117,7 @@ impl PropagatorConstruc // First we store the bounds in the parameters self.updatable_structures - .reset_all_bounds_and_remove_fixed(context.as_readonly(), &self.parameters); + .reset_all_bounds_and_remove_fixed(context.domains(), &self.parameters); self.is_time_table_outdated = true; diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/time_table_per_point_incremental.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/time_table_per_point_incremental.rs index 19e6c7a2a..c0cef63d8 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/time_table_per_point_incremental.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/time_table_per_point_incremental.rs @@ -106,7 +106,7 @@ impl Propagator fn create(mut self, mut context: PropagatorConstructorContext) -> Self::PropagatorImpl { register_tasks(&self.parameters.tasks, context.reborrow(), true); self.updatable_structures - .reset_all_bounds_and_remove_fixed(context.as_readonly(), &self.parameters); + .reset_all_bounds_and_remove_fixed(context.domains(), &self.parameters); // Then we do normal propagation self.is_time_table_outdated = true; diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_over_interval.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_over_interval.rs index 0aa87bb86..3db7c6731 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_over_interval.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_over_interval.rs @@ -107,7 +107,7 @@ impl PropagatorConstructor fn create(mut self, mut context: PropagatorConstructorContext) -> Self::PropagatorImpl { self.updatable_structures - .initialise_bounds_and_remove_fixed(context.as_readonly(), &self.parameters); + .initialise_bounds_and_remove_fixed(context.domains(), &self.parameters); register_tasks(&self.parameters.tasks, context.reborrow(), false); self.inference_code = Some(context.create_inference_code(self.constraint_tag, TimeTable)); diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_per_point.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_per_point.rs index a1e67215c..ed0ca4dfa 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_per_point.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_per_point.rs @@ -98,7 +98,7 @@ impl PropagatorConstructor for TimeTablePerPoint fn create(mut self, mut context: PropagatorConstructorContext) -> Self::PropagatorImpl { self.updatable_structures - .initialise_bounds_and_remove_fixed(context.as_readonly(), &self.parameters); + .initialise_bounds_and_remove_fixed(context.domains(), &self.parameters); register_tasks(&self.parameters.tasks, context.reborrow(), false); self.inference_code = Some(context.create_inference_code(self.constraint_tag, TimeTable)); From bd0c2ff7c0443efa4be88368319daad9582cb63e Mon Sep 17 00:00:00 2001 From: Maarten Flippo Date: Fri, 12 Dec 2025 16:03:28 +0100 Subject: [PATCH 11/29] Update docs for OpaqueDomainEvent --- .../opaque_domain_event.rs | 7 +++++-- .../core/src/engine/notifications/mod.rs | 2 +- pumpkin-crates/core/src/propagation/mod.rs | 19 +++++++++++-------- .../core/src/propagation/propagator.rs | 6 ++++-- 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/pumpkin-crates/core/src/engine/notifications/domain_event_notification/opaque_domain_event.rs b/pumpkin-crates/core/src/engine/notifications/domain_event_notification/opaque_domain_event.rs index f83bb5fe3..1b44f3539 100644 --- a/pumpkin-crates/core/src/engine/notifications/domain_event_notification/opaque_domain_event.rs +++ b/pumpkin-crates/core/src/engine/notifications/domain_event_notification/opaque_domain_event.rs @@ -1,7 +1,10 @@ use super::DomainEvent; +#[cfg(doc)] +use crate::engine::variables::IntegerVariable; -/// A wrapper for a domain event, which forces the propagator implementation to map the event -/// through the variable view. +/// A [`DomainEvent`] that happened in the solver. +/// +/// Obtain the event from the perspective of a variable through [`IntegerVariable::unpack_event`]. #[derive(Clone, Debug, Copy)] pub struct OpaqueDomainEvent(DomainEvent); diff --git a/pumpkin-crates/core/src/engine/notifications/mod.rs b/pumpkin-crates/core/src/engine/notifications/mod.rs index 02056376d..968d105f2 100644 --- a/pumpkin-crates/core/src/engine/notifications/mod.rs +++ b/pumpkin-crates/core/src/engine/notifications/mod.rs @@ -6,7 +6,7 @@ pub(crate) use domain_event_notification::EventSink; pub(crate) use domain_event_notification::WatchListDomainEvents; pub(crate) use domain_event_notification::Watchers; pub use domain_event_notification::domain_events::DomainEvents; -pub(crate) use domain_event_notification::opaque_domain_event::OpaqueDomainEvent; +pub use domain_event_notification::opaque_domain_event::OpaqueDomainEvent; use enumset::EnumSet; pub(crate) use predicate_notification::PredicateIdAssignments; pub(crate) use predicate_notification::PredicateNotifier; diff --git a/pumpkin-crates/core/src/propagation/mod.rs b/pumpkin-crates/core/src/propagation/mod.rs index 468fc4a81..d85ce9445 100644 --- a/pumpkin-crates/core/src/propagation/mod.rs +++ b/pumpkin-crates/core/src/propagation/mod.rs @@ -79,10 +79,16 @@ pub(crate) mod propagator_id; pub(crate) mod propagator_var_id; pub(crate) mod store; -// BEGIN: Re-exports of types not in this module according to the file tree. -// These will probably be be moved at some point, but for now they are simply re-exported here to -// make the propagator API public. -// END +mod reexports { + // Re-exports of types not in this module according to the file tree. + // These will probably be be moved at some point, but for now they are simply re-exported here + // to make the propagator API public. + pub use crate::basic_types::PredicateId; + pub use crate::engine::cp::TrailedInteger; + pub use crate::engine::notifications::DomainEvent; + pub use crate::engine::notifications::DomainEvents; + pub use crate::engine::notifications::OpaqueDomainEvent; +} pub use constructor::*; pub use contexts::*; pub use domains::*; @@ -90,13 +96,10 @@ pub use local_id::*; pub use propagator::*; pub use propagator_id::PropagatorId; pub(crate) use propagator_var_id::PropagatorVarId; +pub use reexports::*; #[cfg(doc)] use crate::Solver; -pub use crate::basic_types::PredicateId; -pub use crate::engine::cp::TrailedInteger; -pub use crate::engine::notifications::DomainEvent; -pub use crate::engine::notifications::DomainEvents; #[cfg(doc)] use crate::engine::test_solver::TestSolver; #[cfg(doc)] diff --git a/pumpkin-crates/core/src/propagation/propagator.rs b/pumpkin-crates/core/src/propagation/propagator.rs index 4c3e086b8..1a45a9277 100644 --- a/pumpkin-crates/core/src/propagation/propagator.rs +++ b/pumpkin-crates/core/src/propagation/propagator.rs @@ -44,7 +44,9 @@ clone_trait_object!(Propagator); /// /// See the [`crate::propagation`] documentation for more details. pub trait Propagator: Downcast + DynClone { - /// Return the name of the propagator, this is a convenience method that is used for printing. + /// Return the name of the propagator. + /// + /// This is a convenience method that is used for printing. fn name(&self) -> &str; /// A propagation method that is used to help debugging. @@ -64,7 +66,7 @@ pub trait Propagator: Downcast + DynClone { /// This method extends the current partial /// assignments with inferred domain changes found by the /// [`Propagator`]. In case no conflict has been detected it should return - /// [`Result::Ok`], otherwise it should return a [`Result::Err`] with an [`Conflict`] which + /// [`Result::Ok`], otherwise it should return a [`Result::Err`] with a [`Conflict`] which /// contains the reason for the failure; either because a propagation caused an /// an empty domain ([`Conflict::EmptyDomain`]) or because the logic of the propagator /// found the current state to be inconsistent ([`Conflict::Propagator`]). From 31340478060727d56e84405015cdd9348c60aebb Mon Sep 17 00:00:00 2001 From: Maarten Flippo Date: Fri, 12 Dec 2025 16:34:00 +0100 Subject: [PATCH 12/29] Docs for trailed integer --- pumpkin-crates/core/src/engine/cp/trailed/trailed_integer.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pumpkin-crates/core/src/engine/cp/trailed/trailed_integer.rs b/pumpkin-crates/core/src/engine/cp/trailed/trailed_integer.rs index 17736f089..23eb66b2e 100644 --- a/pumpkin-crates/core/src/engine/cp/trailed/trailed_integer.rs +++ b/pumpkin-crates/core/src/engine/cp/trailed/trailed_integer.rs @@ -1,5 +1,7 @@ use crate::containers::StorageKey; +/// An integer whose value is trailed by the solver. Backtracking automatically restores the +/// integer to previous values. #[derive(Debug, Clone, Copy)] pub struct TrailedInteger { id: u32, From 525fd3710add495ec991f3988309561870df56cd Mon Sep 17 00:00:00 2001 From: Maarten Flippo Date: Fri, 12 Dec 2025 16:35:07 +0100 Subject: [PATCH 13/29] Docs for CurrentNogood --- .../core/src/propagation/contexts/explanation_context.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pumpkin-crates/core/src/propagation/contexts/explanation_context.rs b/pumpkin-crates/core/src/propagation/contexts/explanation_context.rs index 6e1ec860e..fea9e0c19 100644 --- a/pumpkin-crates/core/src/propagation/contexts/explanation_context.rs +++ b/pumpkin-crates/core/src/propagation/contexts/explanation_context.rs @@ -97,6 +97,9 @@ static EMPTY_PREDICATE_IDS: LazyLock = static EMPTY_PREDICATES: [Predicate; 0] = []; +/// The current nogood that is being analyzed. +/// +/// Can be used by propagators to guide how they explain their propagations. #[derive(Debug)] pub struct CurrentNogood<'a> { heap: &'a KeyValueHeap, From 59303f8f718b833562169f9f51346276b8579599 Mon Sep 17 00:00:00 2001 From: Maarten Flippo Date: Fri, 12 Dec 2025 16:36:26 +0100 Subject: [PATCH 14/29] Docs for DomainEvents --- .../domain_events.rs | 27 +++++++++---------- .../core/src/propagation/constructor.rs | 4 +-- .../arithmetic/linear_not_equal.rs | 4 +-- .../src/propagators/cumulative/utils/util.rs | 4 +-- 4 files changed, 17 insertions(+), 22 deletions(-) diff --git a/pumpkin-crates/core/src/engine/notifications/domain_event_notification/domain_events.rs b/pumpkin-crates/core/src/engine/notifications/domain_event_notification/domain_events.rs index d2ef230cf..2b428f7bc 100644 --- a/pumpkin-crates/core/src/engine/notifications/domain_event_notification/domain_events.rs +++ b/pumpkin-crates/core/src/engine/notifications/domain_event_notification/domain_events.rs @@ -3,45 +3,42 @@ use enumset::enum_set; use super::DomainEvent; +/// A set of [`DomainEvent`]s. #[derive(Debug, Copy, Clone)] pub struct DomainEvents { - int_events: Option>, + events: Option>, } impl DomainEvents { /// DomainEvents with both lower and upper bound tightening (but not other value removal). - pub const BOUNDS: DomainEvents = DomainEvents::create_with_int_events(enum_set!( - DomainEvent::LowerBound | DomainEvent::UpperBound - )); + pub const BOUNDS: DomainEvents = + DomainEvents::new(enum_set!(DomainEvent::LowerBound | DomainEvent::UpperBound)); // this is all options right now, but won't be once we add variables of other types /// DomainEvents with lower and upper bound tightening, assigning to a single value, and /// single value removal. - pub const ANY_INT: DomainEvents = DomainEvents::create_with_int_events(enum_set!( + pub const ANY_INT: DomainEvents = DomainEvents::new(enum_set!( DomainEvent::Assign | DomainEvent::LowerBound | DomainEvent::UpperBound | DomainEvent::Removal )); /// DomainEvents with only lower bound tightening. - pub const LOWER_BOUND: DomainEvents = - DomainEvents::create_with_int_events(enum_set!(DomainEvent::LowerBound)); + pub const LOWER_BOUND: DomainEvents = DomainEvents::new(enum_set!(DomainEvent::LowerBound)); /// DomainEvents with only upper bound tightening. - pub const UPPER_BOUND: DomainEvents = - DomainEvents::create_with_int_events(enum_set!(DomainEvent::UpperBound)); + pub const UPPER_BOUND: DomainEvents = DomainEvents::new(enum_set!(DomainEvent::UpperBound)); /// DomainEvents with only assigning to a single value. - pub const ASSIGN: DomainEvents = - DomainEvents::create_with_int_events(enum_set!(DomainEvent::Assign)); + pub const ASSIGN: DomainEvents = DomainEvents::new(enum_set!(DomainEvent::Assign)); } impl DomainEvents { - pub(crate) const fn create_with_int_events(int_events: EnumSet) -> DomainEvents { + pub(crate) const fn new(int_events: EnumSet) -> DomainEvents { DomainEvents { - int_events: Some(int_events), + events: Some(int_events), } } - pub(crate) fn get_int_events(&self) -> EnumSet { - self.int_events + pub(crate) fn events(&self) -> EnumSet { + self.events .expect("Tried to retrieve int_events when it was not initialized") } } diff --git a/pumpkin-crates/core/src/propagation/constructor.rs b/pumpkin-crates/core/src/propagation/constructor.rs index 22e499853..9cd25bf8e 100644 --- a/pumpkin-crates/core/src/propagation/constructor.rs +++ b/pumpkin-crates/core/src/propagation/constructor.rs @@ -92,7 +92,7 @@ impl PropagatorConstructorContext<'_> { self.update_next_local_id(local_id); let mut watchers = Watchers::new(propagator_var, &mut self.state.notification_engine); - var.watch_all(&mut watchers, domain_events.get_int_events()); + var.watch_all(&mut watchers, domain_events.events()); } /// Register the propagator to be enqueued when the given [`Predicate`] becomes true. @@ -133,7 +133,7 @@ impl PropagatorConstructorContext<'_> { self.update_next_local_id(local_id); let mut watchers = Watchers::new(propagator_var, &mut self.state.notification_engine); - var.watch_all_backtrack(&mut watchers, domain_events.get_int_events()); + var.watch_all_backtrack(&mut watchers, domain_events.events()); } /// Create a new [`InferenceCode`]. These codes are required to identify specific propagations diff --git a/pumpkin-crates/core/src/propagators/arithmetic/linear_not_equal.rs b/pumpkin-crates/core/src/propagators/arithmetic/linear_not_equal.rs index 8d0605719..d2a6f0764 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/linear_not_equal.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/linear_not_equal.rs @@ -56,9 +56,7 @@ where context.register(x_i.clone(), DomainEvents::ASSIGN, LocalId::from(i as u32)); context.register_for_backtrack_events( x_i.clone(), - DomainEvents::create_with_int_events(enum_set!( - DomainEvent::Assign | DomainEvent::Removal - )), + DomainEvents::new(enum_set!(DomainEvent::Assign | DomainEvent::Removal)), LocalId::from(i as u32), ); } diff --git a/pumpkin-crates/core/src/propagators/cumulative/utils/util.rs b/pumpkin-crates/core/src/propagators/cumulative/utils/util.rs index 27b03691c..a15a6f0b8 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/utils/util.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/utils/util.rs @@ -56,7 +56,7 @@ pub(crate) fn register_tasks( tasks.iter().for_each(|task| { context.register( task.start_variable.clone(), - DomainEvents::create_with_int_events(enum_set!( + DomainEvents::new(enum_set!( DomainEvent::LowerBound | DomainEvent::UpperBound | DomainEvent::Assign )), task.id, @@ -64,7 +64,7 @@ pub(crate) fn register_tasks( if register_backtrack { context.register_for_backtrack_events( task.start_variable.clone(), - DomainEvents::create_with_int_events(enum_set!( + DomainEvents::new(enum_set!( DomainEvent::LowerBound | DomainEvent::UpperBound | DomainEvent::Assign )), task.id, From 828334fef8b5b526877429fbda55a293e096360e Mon Sep 17 00:00:00 2001 From: Imko Marijnissen Date: Mon, 15 Dec 2025 09:38:30 +0100 Subject: [PATCH 15/29] fix: add imports + moving minimisation context + adding methods to ReadDomains --- .../conflict_analysis/minimisers/minimiser.rs | 2 +- .../engine/conflict_analysis/minimisers/mod.rs | 2 -- .../minimisers/recursive_minimiser.rs | 13 +++++++------ .../minimisers/semantic_minimiser.rs | 6 +++--- .../resolvers/resolution_resolver.rs | 2 +- .../contexts}/minimisation_context.rs | 6 +++--- .../core/src/propagation/contexts/mod.rs | 2 ++ pumpkin-crates/core/src/propagation/domains.rs | 16 ++++++++++++++++ 8 files changed, 33 insertions(+), 16 deletions(-) rename pumpkin-crates/core/src/{engine/conflict_analysis/minimisers => propagation/contexts}/minimisation_context.rs (94%) diff --git a/pumpkin-crates/core/src/engine/conflict_analysis/minimisers/minimiser.rs b/pumpkin-crates/core/src/engine/conflict_analysis/minimisers/minimiser.rs index 5752c6bd9..1d732a47a 100644 --- a/pumpkin-crates/core/src/engine/conflict_analysis/minimisers/minimiser.rs +++ b/pumpkin-crates/core/src/engine/conflict_analysis/minimisers/minimiser.rs @@ -1,5 +1,5 @@ -use crate::engine::conflict_analysis::MinimisationContext; use crate::predicates::Predicate; +use crate::propagation::MinimisationContext; /// A trait for the behaviour of nogood minimisation approaches. pub(crate) trait NogoodMinimiser: Default { diff --git a/pumpkin-crates/core/src/engine/conflict_analysis/minimisers/mod.rs b/pumpkin-crates/core/src/engine/conflict_analysis/minimisers/mod.rs index b6ad2798f..ec147caf7 100644 --- a/pumpkin-crates/core/src/engine/conflict_analysis/minimisers/mod.rs +++ b/pumpkin-crates/core/src/engine/conflict_analysis/minimisers/mod.rs @@ -1,9 +1,7 @@ -mod minimisation_context; mod minimiser; mod recursive_minimiser; mod semantic_minimiser; -pub(crate) use minimisation_context::*; pub(crate) use minimiser::*; pub(crate) use recursive_minimiser::*; pub(crate) use semantic_minimiser::*; diff --git a/pumpkin-crates/core/src/engine/conflict_analysis/minimisers/recursive_minimiser.rs b/pumpkin-crates/core/src/engine/conflict_analysis/minimisers/recursive_minimiser.rs index 87f8b932a..9f517895d 100644 --- a/pumpkin-crates/core/src/engine/conflict_analysis/minimisers/recursive_minimiser.rs +++ b/pumpkin-crates/core/src/engine/conflict_analysis/minimisers/recursive_minimiser.rs @@ -1,17 +1,18 @@ -use super::MinimisationContext; use crate::basic_types::moving_averages::MovingAverage; use crate::containers::HashMap; use crate::containers::HashSet; use crate::engine::Assignments; -use crate::engine::conflict_analysis::ConflictAnalysisContext; +use crate::engine::conflict_analysis::NogoodMinimiser; use crate::predicates::Predicate; use crate::proof::RootExplanationContext; use crate::proof::explain_root_assignment; use crate::propagation::CurrentNogood; +use crate::propagation::HasAssignments; +use crate::propagation::MinimisationContext; +use crate::propagation::ReadDomains; use crate::pumpkin_assert_eq_moderate; use crate::pumpkin_assert_moderate; use crate::pumpkin_assert_simple; -use crate::state::CurrentNogood; #[derive(Debug, Clone, Default)] pub(crate) struct RecursiveMinimiser { @@ -99,7 +100,7 @@ impl RecursiveMinimiser { // If the predicate is a decision predicate, it cannot be a predicate from the original // learned nogood since those are labelled as part of initialisation. // Therefore the decision literal is labelled as poison and then return. - if context.is_decision_predicate(&input_predicate) { + if context.is_decision_predicate(input_predicate) { self.assign_predicate_label(input_predicate, Label::Poison); self.current_depth -= 1; return; @@ -109,7 +110,7 @@ impl RecursiveMinimiser { // (levels from the original learned clause) cannot be removed. if !self.is_decision_level_allowed( context - .get_checkpoint_for_predicate(&input_predicate) + .get_checkpoint_for_predicate(input_predicate) .unwrap(), ) { self.assign_predicate_label(input_predicate, Label::Poison); @@ -129,7 +130,7 @@ impl RecursiveMinimiser { for antecedent_predicate in reason.iter().copied() { // Root assignments can be safely ignored. if context - .get_checkpoint_for_predicate(&antecedent_predicate) + .get_checkpoint_for_predicate(antecedent_predicate) .unwrap() == 0 { diff --git a/pumpkin-crates/core/src/engine/conflict_analysis/minimisers/semantic_minimiser.rs b/pumpkin-crates/core/src/engine/conflict_analysis/minimisers/semantic_minimiser.rs index 225c59544..ff81bed2a 100644 --- a/pumpkin-crates/core/src/engine/conflict_analysis/minimisers/semantic_minimiser.rs +++ b/pumpkin-crates/core/src/engine/conflict_analysis/minimisers/semantic_minimiser.rs @@ -1,14 +1,14 @@ use std::cmp; -use super::MinimisationContext; use crate::containers::HashSet; use crate::containers::KeyedVec; use crate::containers::SparseSet; use crate::engine::conflict_analysis::NogoodMinimiser; use crate::engine::predicates::predicate::PredicateType; -use crate::engine::propagation::contexts::HasAssignments; use crate::predicate; use crate::predicates::Predicate; +use crate::propagation::HasAssignments; +use crate::propagation::MinimisationContext; use crate::variables::DomainId; #[derive(Clone, Debug)] @@ -263,7 +263,6 @@ mod tests { use crate::conjunction; use crate::containers::HashMap; use crate::engine::SolverStatistics; - use crate::engine::conflict_analysis::MinimisationContext; use crate::engine::conflict_analysis::Mode; use crate::engine::conflict_analysis::NogoodMinimiser; use crate::engine::conflict_analysis::SemanticMinimiser; @@ -271,6 +270,7 @@ mod tests { use crate::predicates::Predicate; use crate::predicates::PropositionalConjunction; use crate::proof::ProofLog; + use crate::propagation::MinimisationContext; use crate::state::State; #[test] diff --git a/pumpkin-crates/core/src/engine/conflict_analysis/resolvers/resolution_resolver.rs b/pumpkin-crates/core/src/engine/conflict_analysis/resolvers/resolution_resolver.rs index 2173bf98a..a4bb61eb2 100644 --- a/pumpkin-crates/core/src/engine/conflict_analysis/resolvers/resolution_resolver.rs +++ b/pumpkin-crates/core/src/engine/conflict_analysis/resolvers/resolution_resolver.rs @@ -9,7 +9,6 @@ use crate::containers::KeyValueHeap; use crate::containers::StorageKey; use crate::engine::Lbd; use crate::engine::conflict_analysis::ConflictAnalysisContext; -use crate::engine::conflict_analysis::MinimisationContext; use crate::engine::conflict_analysis::Mode; use crate::engine::conflict_analysis::NogoodMinimiser; use crate::engine::conflict_analysis::RecursiveMinimiser; @@ -19,6 +18,7 @@ use crate::proof::InferenceCode; use crate::proof::RootExplanationContext; use crate::proof::explain_root_assignment; use crate::propagation::CurrentNogood; +use crate::propagation::MinimisationContext; use crate::propagators::nogoods::NogoodPropagator; use crate::pumpkin_assert_advanced; use crate::pumpkin_assert_moderate; diff --git a/pumpkin-crates/core/src/engine/conflict_analysis/minimisers/minimisation_context.rs b/pumpkin-crates/core/src/propagation/contexts/minimisation_context.rs similarity index 94% rename from pumpkin-crates/core/src/engine/conflict_analysis/minimisers/minimisation_context.rs rename to pumpkin-crates/core/src/propagation/contexts/minimisation_context.rs index fb6e8439e..ce46427eb 100644 --- a/pumpkin-crates/core/src/engine/conflict_analysis/minimisers/minimisation_context.rs +++ b/pumpkin-crates/core/src/propagation/contexts/minimisation_context.rs @@ -2,12 +2,12 @@ use crate::containers::HashMap; use crate::engine::Assignments; use crate::engine::SolverStatistics; use crate::engine::conflict_analysis::ConflictAnalysisContext; -#[cfg(doc)] -use crate::engine::propagation::ReadDomains; -use crate::engine::propagation::contexts::HasAssignments; use crate::predicates::Predicate; use crate::proof::InferenceCode; use crate::proof::ProofLog; +use crate::propagation::HasAssignments; +#[cfg(doc)] +use crate::propagation::ReadDomains; use crate::state::CurrentNogood; use crate::state::State; diff --git a/pumpkin-crates/core/src/propagation/contexts/mod.rs b/pumpkin-crates/core/src/propagation/contexts/mod.rs index 5e365abd0..8a2c497a3 100644 --- a/pumpkin-crates/core/src/propagation/contexts/mod.rs +++ b/pumpkin-crates/core/src/propagation/contexts/mod.rs @@ -1,5 +1,7 @@ mod explanation_context; +mod minimisation_context; mod propagation_context; pub use explanation_context::*; +pub(crate) use minimisation_context::*; pub use propagation_context::*; diff --git a/pumpkin-crates/core/src/propagation/domains.rs b/pumpkin-crates/core/src/propagation/domains.rs index a8bf757b8..d1a7edc3f 100644 --- a/pumpkin-crates/core/src/propagation/domains.rs +++ b/pumpkin-crates/core/src/propagation/domains.rs @@ -86,6 +86,10 @@ pub trait ReadDomains { ) -> bool; fn iterate_domain(&self, var: &Var) -> impl Iterator; + + fn is_decision_predicate(&self, predicate: Predicate) -> bool; + + fn get_checkpoint_for_predicate(&self, predicate: Predicate) -> Option; } impl ReadDomains for T { @@ -152,4 +156,16 @@ impl ReadDomains for T { fn iterate_domain(&self, var: &Var) -> impl Iterator { var.iterate_domain(self.assignments()) } + + /// Returns whether the provided [`Predicate`] was posted as a decision (i.e., it was posted as + /// a [`Predicate`] without a reason). + fn is_decision_predicate(&self, predicate: Predicate) -> bool { + self.assignments().is_decision_predicate(&predicate) + } + + /// If the provided [`Predicate`] is true, then this method returns the checkpoint at which it + /// first become true; otherwise, it returns [`None`]. + fn get_checkpoint_for_predicate(&self, predicate: Predicate) -> Option { + self.assignments().get_checkpoint_for_predicate(&predicate) + } } From 2939c4d01a28045b5a3ccef468aa264609f62e18 Mon Sep 17 00:00:00 2001 From: Imko Marijnissen Date: Mon, 15 Dec 2025 10:10:55 +0100 Subject: [PATCH 16/29] docs: adding documentation to constraint options + updating propagation documentation --- pumpkin-crates/core/src/propagation/mod.rs | 45 +++++++++---------- .../src/propagators/cumulative/options.rs | 4 ++ .../disjunctive/disjunctive_task.rs | 5 +++ 3 files changed, 31 insertions(+), 23 deletions(-) diff --git a/pumpkin-crates/core/src/propagation/mod.rs b/pumpkin-crates/core/src/propagation/mod.rs index d85ce9445..d7d6eca74 100644 --- a/pumpkin-crates/core/src/propagation/mod.rs +++ b/pumpkin-crates/core/src/propagation/mod.rs @@ -3,19 +3,21 @@ //! # Background //! //! A propagator takes as input a set of variables (xi ∈ X) and for each -//! variable a corresponding domain (Di ∈ D); it can then be seen as a -//! function which maps `D ↦ D'` such that D'i ⊆ Di for all -//! variables (i.e. the domain of a variable either remains the same after applying the propagator -//! or it becomes a subset of the domain before applying the propagator). -//! -//! An example of a propagator can be the simple not equal (`!=`) propagator, suppose that -//! we have two variables `x ∈ {0}` and `y ∈ {0, 1}` and the constraint `x != y`. The not equal +//! variable a corresponding domain (Di ∈ D); it then removes values from +//! the domains of variables which are impossible under its reasoning. +//! Thus, it can be seen as a function which maps `D ↦ D'` such that +//! D'i ⊆ Di for all variables (i.e. the domain of a variable +//! either remains the same after applying the propagator or it becomes a subset of the domain +//! before applying the propagator). +//! +//! An example of a simple propagator is that of the binary not equals (`!=`) constraint: suppose +//! that we have two variables `x ∈ {0}` and `y ∈ {0, 1}` and the constraint `x != y`. The not equal //! propagator will then take as input the variables `x` and `y` and their respective domains -//! D = {Dx = {0}, Dy = {0, 1} and produce a new domain D' -//! = {D'x = {0}, D'y = {1}} for which we can see that D_x = -//! D'x and D'y ⊆ Dy. +//! D = {Dx = {0}, Dy = {0, 1}} and produce a new domain +//! D' = {D'x = {0}, D'y = {1}} for which we can see that +//! Dx = D'x and D'y ⊆ Dy. //! -//! A propagator is said to be at fix-point if Dx = D'x meaning +//! A propagator is said to be at fixed-point if Dx = D'x meaning //! that no further propagations can take place when applying the propagator. A propagator is said //! to be "idempotent" if a single call to it will result in it being at fix-point. //! @@ -28,12 +30,12 @@ //! implement for this trait is [`Propagator::propagate`], which performs the domain reduction. //! //! A propagator is created by a [`PropagatorConstructor`]. The constructor is responsible for -//! registering to domain events, and setting up the state of the propagator. The constructor is -//! provided a [`PropagatorConstructorContext`], which has all the available functions allowing the -//! propagator to hook into the solver state. +//! registering to [`DomainEvents`] (using [`PropagatorConstructorContext::register`]), and setting +//! up the state of the propagator. The constructor is provided a [`PropagatorConstructorContext`], +//! which has all the available functions allowing the propagator to hook into the solver state. //! //! We do not require propagators to be idempotent (see the previous section for a -//! definition) and it can be assumed that if a propagator is not at fix-point after propagating +//! definition) and it can be assumed that if a propagator is not at fix-point after propagating, //! that it will be called again by the solver until no further propagations happen. //! //! See the [`propagators`] folder for concrete propagator implementations. @@ -49,11 +51,12 @@ //! 3. Following the procedure above gives an initial version of the propagator that is likely not //! efficient, but has an important role for testing. Now is a good time to write tests using the //! [`State`] API. **We strongly discourage skipping this step**. -//! 4. Implement [`Propagator::notify`] and/or [`Propagator::notify_predicate_id_satisfied`] for -//! more control on when the propagator is enqueued. Depending on the concrete propagator, this -//! may only make sense when done together with the next step. +//! 4. Implement [`Propagator::notify`] and/or [`Propagator::notify_predicate_id_satisfied`] to +//! control when the propagator is enqueued. Depending on the concrete propagator, this may only +//! make sense when done together with the next step. //! 5. Implement the remaining hooks, i.e., [`Propagator::propagate`], and -//! [`Propagator::synchronise`] to exploit incrementality. These are all interdependent. +//! [`Propagator::synchronise`] to exploit incrementality. These functions are all +//! interdependent. //! 6. Decide on the priortiy of the propagator, i.e., implement [`Propagator::priority`]. //! 7. Make sure to write new tests and run all tests throughout the process. //! 8. The propagator implementation is now done! @@ -64,10 +67,6 @@ //! //! \[1\] C. Schulte and P. J. Stuckey, ‘Efficient constraint propagation engines’, ACM Transactions //! on Programming Languages and Systems (TOPLAS), vol. 31, no. 1, pp. 1–43, 2008. -//! -//! \[2\] C. Schulte and G. Tack, ‘Views and iterators for generic constraint implementations’, in -//! International Workshop on Constraint Solving and Constraint Logic Programming, 2005, pp. -//! 118–132. mod constructor; mod contexts; diff --git a/pumpkin-crates/core/src/propagators/cumulative/options.rs b/pumpkin-crates/core/src/propagators/cumulative/options.rs index 82c6a572c..1b7d4f2bc 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/options.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/options.rs @@ -1,4 +1,6 @@ use super::CumulativeExplanationType; +#[cfg(doc)] +use crate::constraints; #[derive(Debug, Default, Clone, Copy)] pub(crate) struct CumulativePropagatorOptions { @@ -15,6 +17,7 @@ pub(crate) struct CumulativePropagatorOptions { pub(crate) incremental_backtracking: bool, } +/// The options provided to the [`constraints::cumulative`] constraints. #[derive(Debug, Copy, Clone, Default)] pub struct CumulativeOptions { /// The propagation method which is used for the cumulative constraints; currently all of them @@ -45,6 +48,7 @@ impl CumulativeOptions { } } +/// The approach used for propagating the [`constraints::cumulative`] constraint. #[derive(Debug, Default, Clone, Copy)] #[cfg_attr(feature = "clap", derive(clap::ValueEnum))] pub enum CumulativePropagationMethod { diff --git a/pumpkin-crates/core/src/propagators/disjunctive/disjunctive_task.rs b/pumpkin-crates/core/src/propagators/disjunctive/disjunctive_task.rs index 7b066625c..658d70c4e 100644 --- a/pumpkin-crates/core/src/propagators/disjunctive/disjunctive_task.rs +++ b/pumpkin-crates/core/src/propagators/disjunctive/disjunctive_task.rs @@ -1,7 +1,12 @@ use std::fmt::Debug; +#[cfg(doc)] +use crate::constraints; use crate::propagation::LocalId; +/// Defines the input of the [`constraints::disjunctive_strict`] constraint. +/// +/// Each task has a variable starting time and a constant processing time. #[derive(Debug, Clone)] pub struct ArgDisjunctiveTask { pub start_time: Var, From 0fc1f976347bf9cb57f0b2d3a55743fa18bb3387 Mon Sep 17 00:00:00 2001 From: Imko Marijnissen Date: Mon, 15 Dec 2025 10:37:59 +0100 Subject: [PATCH 17/29] chore: rename debug_propagate_from_scratch --- pumpkin-crates/core/src/engine/debug_helper.rs | 9 ++++----- pumpkin-crates/core/src/propagation/mod.rs | 2 +- pumpkin-crates/core/src/propagation/propagator.rs | 11 ++++++----- .../core/src/propagators/arithmetic/absolute_value.rs | 2 +- .../propagators/arithmetic/binary/binary_equals.rs | 4 ++-- .../arithmetic/binary/binary_not_equals.rs | 2 +- .../src/propagators/arithmetic/integer_division.rs | 2 +- .../propagators/arithmetic/integer_multiplication.rs | 2 +- .../propagators/arithmetic/linear_less_or_equal.rs | 2 +- .../src/propagators/arithmetic/linear_not_equal.rs | 2 +- .../core/src/propagators/arithmetic/maximum.rs | 2 +- .../time_table_over_interval_incremental.rs | 6 +++--- .../time_table_per_point_incremental.rs | 6 +++--- .../cumulative/time_table/time_table_over_interval.rs | 6 +++--- .../cumulative/time_table/time_table_per_point.rs | 6 +++--- .../propagators/disjunctive/disjunctive_propagator.rs | 2 +- pumpkin-crates/core/src/propagators/element.rs | 2 +- .../core/src/propagators/nogoods/nogood_propagator.rs | 5 +---- .../core/src/propagators/reified_propagator.rs | 6 +++--- 19 files changed, 38 insertions(+), 41 deletions(-) diff --git a/pumpkin-crates/core/src/engine/debug_helper.rs b/pumpkin-crates/core/src/engine/debug_helper.rs index 75b173624..d3eae77ec 100644 --- a/pumpkin-crates/core/src/engine/debug_helper.rs +++ b/pumpkin-crates/core/src/engine/debug_helper.rs @@ -84,7 +84,7 @@ impl DebugHelper { &mut notification_engine_clone, PropagatorId(propagator_id as u32), ); - let propagation_status_cp = propagator.debug_propagate_from_scratch(context); + let propagation_status_cp = propagator.propagate_from_scratch(context); if let Err(ref failure_reason) = propagation_status_cp { panic!( @@ -262,7 +262,7 @@ impl DebugHelper { &mut notification_engine_clone, propagator_id, ); - let debug_propagation_status_cp = propagator.debug_propagate_from_scratch(context); + let debug_propagation_status_cp = propagator.propagate_from_scratch(context); // Note that it could be the case that the propagation leads to conflict, in this // case it should be the result of a propagation (i.e. an EmptyDomain) @@ -377,8 +377,7 @@ impl DebugHelper { &mut notification_engine_clone, propagator_id, ); - let debug_propagation_status_cp = - propagator.debug_propagate_from_scratch(context); + let debug_propagation_status_cp = propagator.propagate_from_scratch(context); // We break if an error was found or if there were no more propagations (i.e. // fixpoint was reached) @@ -444,7 +443,7 @@ impl DebugHelper { &mut notification_engine_clone, propagator_id, ); - let debug_propagation_status_cp = propagator.debug_propagate_from_scratch(context); + let debug_propagation_status_cp = propagator.propagate_from_scratch(context); assert!( debug_propagation_status_cp.is_err(), "Debug propagation could not reproduce the conflict reported diff --git a/pumpkin-crates/core/src/propagation/mod.rs b/pumpkin-crates/core/src/propagation/mod.rs index d7d6eca74..68b3d6113 100644 --- a/pumpkin-crates/core/src/propagation/mod.rs +++ b/pumpkin-crates/core/src/propagation/mod.rs @@ -44,7 +44,7 @@ //! //! We recommend the following workflow: //! 1. Implement a propagator struct that implements the [`Propagator`] trait. For now only -//! implement the required functions, i.e., [`Propagator::debug_propagate_from_scratch`] and +//! implement the required functions, i.e., [`Propagator::propagate_from_scratch`] and //! [`Propagator::name`]. //! 2. Create an implementation of the [`PropagatorConstructor`] trait, to register for domain //! events and set up the propagator state. diff --git a/pumpkin-crates/core/src/propagation/propagator.rs b/pumpkin-crates/core/src/propagation/propagator.rs index 1a45a9277..6981d7b5d 100644 --- a/pumpkin-crates/core/src/propagation/propagator.rs +++ b/pumpkin-crates/core/src/propagation/propagator.rs @@ -38,7 +38,7 @@ clone_trait_object!(Propagator); /// explicit conflicts. /// /// The only required functions are [`Propagator::name`], -/// and [`Propagator::debug_propagate_from_scratch`]; all other +/// and [`Propagator::propagate_from_scratch`]; all other /// functions have default implementations. For initial development, the required functions are /// enough, but a more mature implementation considers all functions in most cases. /// @@ -49,7 +49,8 @@ pub trait Propagator: Downcast + DynClone { /// This is a convenience method that is used for printing. fn name(&self) -> &str; - /// A propagation method that is used to help debugging. + /// A propagation method that propagates from scratch (i.e., without relying on updating + /// internal data structures). /// /// This method propagates without relying on internal data structures, hence the immutable /// &self parameter. It is usually best to implement this propagation method in the simplest @@ -59,7 +60,7 @@ pub trait Propagator: Downcast + DynClone { /// /// Propagators are not required to propagate until a fixed point. It will be called again by /// the solver until no further propagations happen. - fn debug_propagate_from_scratch(&self, context: PropagationContext) -> PropagationStatusCP; + fn propagate_from_scratch(&self, context: PropagationContext) -> PropagationStatusCP; /// Performs stateful propagation. /// @@ -77,9 +78,9 @@ pub trait Propagator: Downcast + DynClone { /// Propagators are not required to propagate until a fixed point. It will be called /// again by the solver until no further propagations happen. /// - /// By default, this function calls [`Propagator::debug_propagate_from_scratch`]. + /// By default, this function calls [`Propagator::propagate_from_scratch`]. fn propagate(&mut self, context: PropagationContext) -> PropagationStatusCP { - self.debug_propagate_from_scratch(context) + self.propagate_from_scratch(context) } /// Called when an event happens to one of the variables the propagator is subscribed to. It diff --git a/pumpkin-crates/core/src/propagators/arithmetic/absolute_value.rs b/pumpkin-crates/core/src/propagators/arithmetic/absolute_value.rs index 99a25ece5..4e379431b 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/absolute_value.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/absolute_value.rs @@ -73,7 +73,7 @@ where "IntAbs" } - fn debug_propagate_from_scratch(&self, mut context: PropagationContext) -> PropagationStatusCP { + fn propagate_from_scratch(&self, mut context: PropagationContext) -> PropagationStatusCP { // The bound of absolute may be tightened further during propagation, but it is at least // zero at the root. context.post( diff --git a/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_equals.rs b/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_equals.rs index b491139b6..643cee333 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_equals.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_equals.rs @@ -226,7 +226,7 @@ where if self.first_propagation_loop { // If it is the first propagation loop then we do full propagation self.first_propagation_loop = false; - return self.debug_propagate_from_scratch(context); + return self.propagate_from_scratch(context); } if let Some(conflict) = self.detect_inconsistency(context.domains()) { @@ -313,7 +313,7 @@ where slice::from_ref(&self.reason) } - fn debug_propagate_from_scratch(&self, mut context: PropagationContext) -> PropagationStatusCP { + fn propagate_from_scratch(&self, mut context: PropagationContext) -> PropagationStatusCP { let a_lb = context.lower_bound(&self.a); let a_ub = context.upper_bound(&self.a); diff --git a/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_not_equals.rs b/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_not_equals.rs index dd90e8812..c57294b77 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_not_equals.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_not_equals.rs @@ -132,7 +132,7 @@ where Ok(()) } - fn debug_propagate_from_scratch(&self, mut context: PropagationContext) -> PropagationStatusCP { + fn propagate_from_scratch(&self, mut context: PropagationContext) -> PropagationStatusCP { if let Some(conflict) = self.detect_inconsistency(context.domains()) { return Err(conflict.into()); } diff --git a/pumpkin-crates/core/src/propagators/arithmetic/integer_division.rs b/pumpkin-crates/core/src/propagators/arithmetic/integer_division.rs index 085c14e5d..7c674e7a6 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/integer_division.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/integer_division.rs @@ -93,7 +93,7 @@ where "Division" } - fn debug_propagate_from_scratch(&self, context: PropagationContext) -> PropagationStatusCP { + fn propagate_from_scratch(&self, context: PropagationContext) -> PropagationStatusCP { perform_propagation( context, &self.numerator, diff --git a/pumpkin-crates/core/src/propagators/arithmetic/integer_multiplication.rs b/pumpkin-crates/core/src/propagators/arithmetic/integer_multiplication.rs index 63122b0a8..215fb53c3 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/integer_multiplication.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/integer_multiplication.rs @@ -85,7 +85,7 @@ where "IntTimes" } - fn debug_propagate_from_scratch(&self, context: PropagationContext) -> PropagationStatusCP { + fn propagate_from_scratch(&self, context: PropagationContext) -> PropagationStatusCP { perform_propagation(context, &self.a, &self.b, &self.c, self.inference_code) } } diff --git a/pumpkin-crates/core/src/propagators/arithmetic/linear_less_or_equal.rs b/pumpkin-crates/core/src/propagators/arithmetic/linear_less_or_equal.rs index 4fbc7eed3..ceb03bb34 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/linear_less_or_equal.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/linear_less_or_equal.rs @@ -205,7 +205,7 @@ where Ok(()) } - fn debug_propagate_from_scratch(&self, mut context: PropagationContext) -> PropagationStatusCP { + fn propagate_from_scratch(&self, mut context: PropagationContext) -> PropagationStatusCP { let lower_bound_left_hand_side = self .x .iter() diff --git a/pumpkin-crates/core/src/propagators/arithmetic/linear_not_equal.rs b/pumpkin-crates/core/src/propagators/arithmetic/linear_not_equal.rs index d2a6f0764..1a4d15682 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/linear_not_equal.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/linear_not_equal.rs @@ -221,7 +221,7 @@ where Ok(()) } - fn debug_propagate_from_scratch(&self, mut context: PropagationContext) -> PropagationStatusCP { + fn propagate_from_scratch(&self, mut context: PropagationContext) -> PropagationStatusCP { let num_fixed = self .terms .iter() diff --git a/pumpkin-crates/core/src/propagators/arithmetic/maximum.rs b/pumpkin-crates/core/src/propagators/arithmetic/maximum.rs index c1457e67d..72fb54396 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/maximum.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/maximum.rs @@ -77,7 +77,7 @@ impl Prop "Maximum" } - fn debug_propagate_from_scratch(&self, mut context: PropagationContext) -> PropagationStatusCP { + fn propagate_from_scratch(&self, mut context: PropagationContext) -> PropagationStatusCP { // This is the constraint that is being propagated: // max(a_0, a_1, ..., a_{n-1}) = rhs diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/time_table_over_interval_incremental.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/time_table_over_interval_incremental.rs index a2b6271c9..b15477ee4 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/time_table_over_interval_incremental.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/time_table_over_interval_incremental.rs @@ -33,7 +33,7 @@ use crate::propagators::cumulative::time_table::time_table_util::insert_update; use crate::propagators::cumulative::time_table::time_table_util::propagate_based_on_timetable; use crate::propagators::cumulative::time_table::time_table_util::should_enqueue; use crate::propagators::cumulative::time_table::TimeTable; -use crate::propagators::debug_propagate_from_scratch_time_table_interval; +use crate::propagators::propagate_from_scratch_time_table_interval; use crate::propagators::util::check_bounds_equal_at_propagation; use crate::propagators::util::create_tasks; use crate::propagators::util::register_tasks; @@ -506,9 +506,9 @@ impl Propagator "CumulativeTimeTableOverIntervalIncremental" } - fn debug_propagate_from_scratch(&self, mut context: PropagationContext) -> PropagationStatusCP { + fn propagate_from_scratch(&self, mut context: PropagationContext) -> PropagationStatusCP { // Use the same debug propagator from `TimeTableOverInterval` - debug_propagate_from_scratch_time_table_interval( + propagate_from_scratch_time_table_interval( &mut context, &self.parameters, &self.updatable_structures, diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/time_table_per_point_incremental.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/time_table_per_point_incremental.rs index c0cef63d8..adbf6567c 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/time_table_per_point_incremental.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/time_table_per_point_incremental.rs @@ -40,7 +40,7 @@ use crate::propagators::cumulative::time_table::time_table_util::backtrack_updat use crate::propagators::cumulative::time_table::time_table_util::insert_update; use crate::propagators::cumulative::time_table::time_table_util::propagate_based_on_timetable; use crate::propagators::cumulative::time_table::time_table_util::should_enqueue; -use crate::propagators::debug_propagate_from_scratch_time_table_point; +use crate::propagators::propagate_from_scratch_time_table_point; use crate::propagators::util::check_bounds_equal_at_propagation; use crate::propagators::util::create_tasks; use crate::propagators::util::register_tasks; @@ -531,9 +531,9 @@ impl Propagator "CumulativeTimeTablePerPointIncremental" } - fn debug_propagate_from_scratch(&self, mut context: PropagationContext) -> PropagationStatusCP { + fn propagate_from_scratch(&self, mut context: PropagationContext) -> PropagationStatusCP { // Use the same debug propagator from `TimeTablePerPoint` - debug_propagate_from_scratch_time_table_point( + propagate_from_scratch_time_table_point( &mut context, self.inference_code.unwrap(), &self.parameters, diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_over_interval.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_over_interval.rs index 3db7c6731..f71e51c5e 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_over_interval.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_over_interval.rs @@ -191,8 +191,8 @@ impl Propagator for TimeTableOverIntervalPropaga "CumulativeTimeTableOverInterval" } - fn debug_propagate_from_scratch(&self, mut context: PropagationContext) -> PropagationStatusCP { - debug_propagate_from_scratch_time_table_interval( + fn propagate_from_scratch(&self, mut context: PropagationContext) -> PropagationStatusCP { + propagate_from_scratch_time_table_interval( &mut context, &self.parameters, &self.updatable_structures, @@ -446,7 +446,7 @@ fn check_starting_new_profile_invariants( && current_profile_tasks.is_empty() } -pub(crate) fn debug_propagate_from_scratch_time_table_interval( +pub(crate) fn propagate_from_scratch_time_table_interval( context: &mut PropagationContext, parameters: &CumulativeParameters, updatable_structures: &UpdatableStructures, diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_per_point.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_per_point.rs index ed0ca4dfa..fb3507c9e 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_per_point.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_per_point.rs @@ -184,8 +184,8 @@ impl Propagator for TimeTablePerPointPropagator< "CumulativeTimeTablePerPoint" } - fn debug_propagate_from_scratch(&self, mut context: PropagationContext) -> PropagationStatusCP { - debug_propagate_from_scratch_time_table_point( + fn propagate_from_scratch(&self, mut context: PropagationContext) -> PropagationStatusCP { + propagate_from_scratch_time_table_point( &mut context, self.inference_code.unwrap(), &self.parameters, @@ -250,7 +250,7 @@ pub(crate) fn create_time_table_per_point_from_scratch< Ok(time_table) } -pub(crate) fn debug_propagate_from_scratch_time_table_point( +pub(crate) fn propagate_from_scratch_time_table_point( context: &mut PropagationContext, inference_code: InferenceCode, parameters: &CumulativeParameters, diff --git a/pumpkin-crates/core/src/propagators/disjunctive/disjunctive_propagator.rs b/pumpkin-crates/core/src/propagators/disjunctive/disjunctive_propagator.rs index 52cf0716f..567a9d9aa 100644 --- a/pumpkin-crates/core/src/propagators/disjunctive/disjunctive_propagator.rs +++ b/pumpkin-crates/core/src/propagators/disjunctive/disjunctive_propagator.rs @@ -121,7 +121,7 @@ impl Propagator for DisjunctivePropagator { ) } - fn debug_propagate_from_scratch(&self, mut context: PropagationContext) -> PropagationStatusCP { + fn propagate_from_scratch(&self, mut context: PropagationContext) -> PropagationStatusCP { let mut sorted_tasks = self.sorted_tasks.clone(); let mut theta_lambda_tree = self.theta_lambda_tree.clone(); edge_finding( diff --git a/pumpkin-crates/core/src/propagators/element.rs b/pumpkin-crates/core/src/propagators/element.rs index c34b5473d..ae1fe43b7 100644 --- a/pumpkin-crates/core/src/propagators/element.rs +++ b/pumpkin-crates/core/src/propagators/element.rs @@ -103,7 +103,7 @@ where "Element" } - fn debug_propagate_from_scratch(&self, mut context: PropagationContext) -> PropagationStatusCP { + fn propagate_from_scratch(&self, mut context: PropagationContext) -> PropagationStatusCP { self.propagate_index_bounds_within_array(&mut context)?; self.propagate_rhs_bounds_based_on_array(&mut context)?; diff --git a/pumpkin-crates/core/src/propagators/nogoods/nogood_propagator.rs b/pumpkin-crates/core/src/propagators/nogoods/nogood_propagator.rs index ab7636a3d..24622e681 100644 --- a/pumpkin-crates/core/src/propagators/nogoods/nogood_propagator.rs +++ b/pumpkin-crates/core/src/propagators/nogoods/nogood_propagator.rs @@ -333,10 +333,7 @@ impl Propagator for NogoodPropagator { self.updated_predicate_ids.clear() } - fn debug_propagate_from_scratch( - &self, - mut context: PropagationContext, - ) -> Result<(), Conflict> { + fn propagate_from_scratch(&self, mut context: PropagationContext) -> Result<(), Conflict> { // Very inefficient version! // The algorithm goes through every nogood explicitly diff --git a/pumpkin-crates/core/src/propagators/reified_propagator.rs b/pumpkin-crates/core/src/propagators/reified_propagator.rs index b1d4f70ad..5f0b76618 100644 --- a/pumpkin-crates/core/src/propagators/reified_propagator.rs +++ b/pumpkin-crates/core/src/propagators/reified_propagator.rs @@ -136,13 +136,13 @@ impl Propagator for ReifiedPropagator PropagationStatusCP { + fn propagate_from_scratch(&self, mut context: PropagationContext) -> PropagationStatusCP { self.propagate_reification(&mut context)?; if context.evaluate_literal(self.reification_literal) == Some(true) { context.with_reification(self.reification_literal); - let result = self.propagator.debug_propagate_from_scratch(context); + let result = self.propagator.propagate_from_scratch(context); self.map_propagation_status(result)?; } @@ -421,7 +421,7 @@ mod tests { "Generic Propagator" } - fn debug_propagate_from_scratch(&self, context: PropagationContext) -> PropagationStatusCP { + fn propagate_from_scratch(&self, context: PropagationContext) -> PropagationStatusCP { (self.propagation)(context) } From cfcfb06c7021be9af17ef9f44bc364d149f31c3c Mon Sep 17 00:00:00 2001 From: Imko Marijnissen Date: Mon, 15 Dec 2025 11:03:19 +0100 Subject: [PATCH 18/29] docs: updating propagator docs --- .../core/src/propagation/constructor.rs | 2 +- .../core/src/propagation/propagator.rs | 71 +++++++++++++------ .../arithmetic/linear_not_equal.rs | 2 +- .../src/propagators/cumulative/utils/util.rs | 2 +- 4 files changed, 53 insertions(+), 24 deletions(-) diff --git a/pumpkin-crates/core/src/propagation/constructor.rs b/pumpkin-crates/core/src/propagation/constructor.rs index 9cd25bf8e..93a9b09fa 100644 --- a/pumpkin-crates/core/src/propagation/constructor.rs +++ b/pumpkin-crates/core/src/propagation/constructor.rs @@ -119,7 +119,7 @@ impl PropagatorConstructorContext<'_> { /// /// Note that the [`LocalId`] is used to differentiate between [`DomainId`]s and /// [`AffineView`]s. - pub(crate) fn register_for_backtrack_events( + pub fn register_backtrack( &mut self, var: Var, domain_events: DomainEvents, diff --git a/pumpkin-crates/core/src/propagation/propagator.rs b/pumpkin-crates/core/src/propagation/propagator.rs index 6981d7b5d..ca2470f58 100644 --- a/pumpkin-crates/core/src/propagation/propagator.rs +++ b/pumpkin-crates/core/src/propagation/propagator.rs @@ -17,6 +17,12 @@ use crate::engine::ConstraintSatisfactionSolver; use crate::engine::notifications::OpaqueDomainEvent; use crate::predicates::Predicate; #[cfg(doc)] +use crate::propagation::DomainEvent; +#[cfg(doc)] +use crate::propagation::PropagatorConstructor; +#[cfg(doc)] +use crate::propagation::PropagatorConstructorContext; +#[cfg(doc)] use crate::propagation::ReadDomains; use crate::propagation::local_id::LocalId; #[cfg(doc)] @@ -49,11 +55,21 @@ pub trait Propagator: Downcast + DynClone { /// This is a convenience method that is used for printing. fn name(&self) -> &str; - /// A propagation method that propagates from scratch (i.e., without relying on updating - /// internal data structures). + /// Performs propagation from scratch (i.e., without relying on updating + /// internal data structures, as opposed to [`Propagator::propagate`]). + /// + /// The main aims of this method are to remove values from the domains of variables (using + /// [`PropagationContext::post`]) which cannot be part of any solution given the current + /// domains and to detect conflicts. /// - /// This method propagates without relying on internal data structures, hence the immutable - /// &self parameter. It is usually best to implement this propagation method in the simplest + /// In case no conflict has been detected this function should + /// return [`Result::Ok`], otherwise it should return a [`Result::Err`] with a [`Conflict`] + /// which contains the reason for the failure; either because a propagation caused an + /// an empty domain ([`Conflict::EmptyDomain`] as a result of [`PropagationContext::post`]) or + /// because the logic of the propagator found the current state to be inconsistent + /// ([`Conflict::Propagator`] ). + /// + /// It is usually best to implement this propagation method in the simplest /// but correct way. When this crate is compiled with the `debug-checks` feature, this method /// will be called to double check the reasons for failures and propagations that have been /// reported by this propagator. @@ -62,18 +78,19 @@ pub trait Propagator: Downcast + DynClone { /// the solver until no further propagations happen. fn propagate_from_scratch(&self, context: PropagationContext) -> PropagationStatusCP; - /// Performs stateful propagation. + /// Performs propagation with state (i.e., with being able to mutate internal data structures, + /// as opposed to [`Propagator::propagate_from_scratch`]). /// - /// This method extends the current partial - /// assignments with inferred domain changes found by the - /// [`Propagator`]. In case no conflict has been detected it should return - /// [`Result::Ok`], otherwise it should return a [`Result::Err`] with a [`Conflict`] which - /// contains the reason for the failure; either because a propagation caused an - /// an empty domain ([`Conflict::EmptyDomain`]) or because the logic of the propagator - /// found the current state to be inconsistent ([`Conflict::Propagator`]). + /// The main aims of this method are to remove values from the domains of variables (using + /// [`PropagationContext::post`]) which cannot be part of any solution given the current + /// domains and to detect conflicts. /// - /// Note that the failure (explanation) is given as a conjunction of predicates that lead to the - /// failure + /// In case no conflict has been detected this function should + /// return [`Result::Ok`], otherwise it should return a [`Result::Err`] with a [`Conflict`] + /// which contains the reason for the failure; either because a propagation caused an + /// an empty domain ([`Conflict::EmptyDomain`] as a result of [`PropagationContext::post`]) or + /// because the logic of the propagator found the current state to be inconsistent + /// ([`Conflict::Propagator`] ). /// /// Propagators are not required to propagate until a fixed point. It will be called /// again by the solver until no further propagations happen. @@ -83,12 +100,13 @@ pub trait Propagator: Downcast + DynClone { self.propagate_from_scratch(context) } - /// Called when an event happens to one of the variables the propagator is subscribed to. It - /// indicates whether the provided event should cause the propagator to be enqueued. + /// Returns whether the propagator should be enqueued for propagation when a [`DomainEvent`] + /// happens to one of the variables the propagator is subscribed to (as registered during + /// creation with [`PropagatorConstructor`] using [`PropagatorConstructorContext::register`]). /// /// This can be used to incrementally maintain data structures or perform propagations, and /// should only be used for computationally cheap logic. Expensive computation should be - /// performed in the [`Propagator::propagate()`] method. + /// performed in the [`Propagator::propagate`] method. /// /// By default the propagator is always enqueued for every event it is subscribed to. Not all /// propagators will benefit from implementing this, so it is not required to do so. @@ -101,13 +119,19 @@ pub trait Propagator: Downcast + DynClone { EnqueueDecision::Enqueue } - /// Called when an event happens to one of the variables the propagator is subscribed to. This - /// method is called during backtrack when the domain of a variable has been undone. + /// This function is called when the effect of a [`DomainEvent`] is undone during backtracking + /// of one of the variables the propagator is subscribed to (as registered during creation with + /// [`PropagatorConstructor`] using [`PropagatorConstructorContext::register_backtrack`]). /// /// This can be used to incrementally maintain data structures or perform propagations, and /// should only be used for computationally cheap logic. Expensive computation should be /// performed in the [`Propagator::propagate`] method. /// + /// *Note*: This method is only called for [`DomainEvent`]s for which [`Propagator::notify`] + /// was called. This means that if the propagator itself made a change, but was not notified of + /// it (e.g., due to a conflict being detected), then this method will also not be called for + /// that [`DomainEvent`]. + /// /// By default the propagator does nothing when this method is called. Not all propagators will /// benefit from implementing this, so it is not required to do so. fn notify_backtrack( @@ -118,7 +142,10 @@ pub trait Propagator: Downcast + DynClone { ) { } - /// Called when a [`PredicateId`] has been satisfied. + /// Returns whether the propagator should be enqueued for propagation when a [`Predicate`] (with + /// corresponding [`PredicateId`]) which the propagator is subscribed to (as registered during + /// creation with [`PropagatorConstructor`] using + /// [`PropagatorConstructorContext::register_predicate`]). /// /// By default, the propagator will be enqueued. fn notify_predicate_id_satisfied(&mut self, _predicate_id: PredicateId) -> EnqueueDecision { @@ -142,7 +169,8 @@ pub trait Propagator: Downcast + DynClone { 3 } - /// A check whether this propagator can detect an inconsistency. + /// A function which returns [`Some`] with a [`PropagatorConflict`] when this propagator can + /// detect an inconsistency (and [`None`] otherwise). /// /// By implementing this function, if the propagator is reified, it can propagate the /// reification literal based on the detected inconsistency. Yet, an implementation is not @@ -172,6 +200,7 @@ pub trait Propagator: Downcast + DynClone { ) ); } + /// Logs statistics of the propagator using the provided [`StatisticLogger`]. /// /// It is recommended to create a struct through the [`create_statistics_struct!`] macro! diff --git a/pumpkin-crates/core/src/propagators/arithmetic/linear_not_equal.rs b/pumpkin-crates/core/src/propagators/arithmetic/linear_not_equal.rs index 1a4d15682..c2ffc8cab 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/linear_not_equal.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/linear_not_equal.rs @@ -54,7 +54,7 @@ where for (i, x_i) in terms.iter().enumerate() { context.register(x_i.clone(), DomainEvents::ASSIGN, LocalId::from(i as u32)); - context.register_for_backtrack_events( + context.register_backtrack( x_i.clone(), DomainEvents::new(enum_set!(DomainEvent::Assign | DomainEvent::Removal)), LocalId::from(i as u32), diff --git a/pumpkin-crates/core/src/propagators/cumulative/utils/util.rs b/pumpkin-crates/core/src/propagators/cumulative/utils/util.rs index a15a6f0b8..b02e200c1 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/utils/util.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/utils/util.rs @@ -62,7 +62,7 @@ pub(crate) fn register_tasks( task.id, ); if register_backtrack { - context.register_for_backtrack_events( + context.register_backtrack( task.start_variable.clone(), DomainEvents::new(enum_set!( DomainEvent::LowerBound | DomainEvent::UpperBound | DomainEvent::Assign From ddba1c6b39616b56a0573af40ddb4a177b89506b Mon Sep 17 00:00:00 2001 From: Imko Marijnissen Date: Mon, 15 Dec 2025 11:05:20 +0100 Subject: [PATCH 19/29] chore: move back minimisation context --- .../conflict_analysis/minimisers}/minimisation_context.rs | 0 .../core/src/engine/conflict_analysis/minimisers/minimiser.rs | 2 +- .../core/src/engine/conflict_analysis/minimisers/mod.rs | 2 ++ .../conflict_analysis/minimisers/recursive_minimiser.rs | 2 +- .../engine/conflict_analysis/minimisers/semantic_minimiser.rs | 4 ++-- .../engine/conflict_analysis/resolvers/resolution_resolver.rs | 2 +- pumpkin-crates/core/src/propagation/contexts/mod.rs | 2 -- 7 files changed, 7 insertions(+), 7 deletions(-) rename pumpkin-crates/core/src/{propagation/contexts => engine/conflict_analysis/minimisers}/minimisation_context.rs (100%) diff --git a/pumpkin-crates/core/src/propagation/contexts/minimisation_context.rs b/pumpkin-crates/core/src/engine/conflict_analysis/minimisers/minimisation_context.rs similarity index 100% rename from pumpkin-crates/core/src/propagation/contexts/minimisation_context.rs rename to pumpkin-crates/core/src/engine/conflict_analysis/minimisers/minimisation_context.rs diff --git a/pumpkin-crates/core/src/engine/conflict_analysis/minimisers/minimiser.rs b/pumpkin-crates/core/src/engine/conflict_analysis/minimisers/minimiser.rs index 1d732a47a..5752c6bd9 100644 --- a/pumpkin-crates/core/src/engine/conflict_analysis/minimisers/minimiser.rs +++ b/pumpkin-crates/core/src/engine/conflict_analysis/minimisers/minimiser.rs @@ -1,5 +1,5 @@ +use crate::engine::conflict_analysis::MinimisationContext; use crate::predicates::Predicate; -use crate::propagation::MinimisationContext; /// A trait for the behaviour of nogood minimisation approaches. pub(crate) trait NogoodMinimiser: Default { diff --git a/pumpkin-crates/core/src/engine/conflict_analysis/minimisers/mod.rs b/pumpkin-crates/core/src/engine/conflict_analysis/minimisers/mod.rs index ec147caf7..b6ad2798f 100644 --- a/pumpkin-crates/core/src/engine/conflict_analysis/minimisers/mod.rs +++ b/pumpkin-crates/core/src/engine/conflict_analysis/minimisers/mod.rs @@ -1,7 +1,9 @@ +mod minimisation_context; mod minimiser; mod recursive_minimiser; mod semantic_minimiser; +pub(crate) use minimisation_context::*; pub(crate) use minimiser::*; pub(crate) use recursive_minimiser::*; pub(crate) use semantic_minimiser::*; diff --git a/pumpkin-crates/core/src/engine/conflict_analysis/minimisers/recursive_minimiser.rs b/pumpkin-crates/core/src/engine/conflict_analysis/minimisers/recursive_minimiser.rs index 9f517895d..2056ac647 100644 --- a/pumpkin-crates/core/src/engine/conflict_analysis/minimisers/recursive_minimiser.rs +++ b/pumpkin-crates/core/src/engine/conflict_analysis/minimisers/recursive_minimiser.rs @@ -2,13 +2,13 @@ use crate::basic_types::moving_averages::MovingAverage; use crate::containers::HashMap; use crate::containers::HashSet; use crate::engine::Assignments; +use crate::engine::conflict_analysis::MinimisationContext; use crate::engine::conflict_analysis::NogoodMinimiser; use crate::predicates::Predicate; use crate::proof::RootExplanationContext; use crate::proof::explain_root_assignment; use crate::propagation::CurrentNogood; use crate::propagation::HasAssignments; -use crate::propagation::MinimisationContext; use crate::propagation::ReadDomains; use crate::pumpkin_assert_eq_moderate; use crate::pumpkin_assert_moderate; diff --git a/pumpkin-crates/core/src/engine/conflict_analysis/minimisers/semantic_minimiser.rs b/pumpkin-crates/core/src/engine/conflict_analysis/minimisers/semantic_minimiser.rs index ff81bed2a..22288e285 100644 --- a/pumpkin-crates/core/src/engine/conflict_analysis/minimisers/semantic_minimiser.rs +++ b/pumpkin-crates/core/src/engine/conflict_analysis/minimisers/semantic_minimiser.rs @@ -3,12 +3,12 @@ use std::cmp; use crate::containers::HashSet; use crate::containers::KeyedVec; use crate::containers::SparseSet; +use crate::engine::conflict_analysis::MinimisationContext; use crate::engine::conflict_analysis::NogoodMinimiser; use crate::engine::predicates::predicate::PredicateType; use crate::predicate; use crate::predicates::Predicate; use crate::propagation::HasAssignments; -use crate::propagation::MinimisationContext; use crate::variables::DomainId; #[derive(Clone, Debug)] @@ -263,6 +263,7 @@ mod tests { use crate::conjunction; use crate::containers::HashMap; use crate::engine::SolverStatistics; + use crate::engine::conflict_analysis::MinimisationContext; use crate::engine::conflict_analysis::Mode; use crate::engine::conflict_analysis::NogoodMinimiser; use crate::engine::conflict_analysis::SemanticMinimiser; @@ -270,7 +271,6 @@ mod tests { use crate::predicates::Predicate; use crate::predicates::PropositionalConjunction; use crate::proof::ProofLog; - use crate::propagation::MinimisationContext; use crate::state::State; #[test] diff --git a/pumpkin-crates/core/src/engine/conflict_analysis/resolvers/resolution_resolver.rs b/pumpkin-crates/core/src/engine/conflict_analysis/resolvers/resolution_resolver.rs index a4bb61eb2..2173bf98a 100644 --- a/pumpkin-crates/core/src/engine/conflict_analysis/resolvers/resolution_resolver.rs +++ b/pumpkin-crates/core/src/engine/conflict_analysis/resolvers/resolution_resolver.rs @@ -9,6 +9,7 @@ use crate::containers::KeyValueHeap; use crate::containers::StorageKey; use crate::engine::Lbd; use crate::engine::conflict_analysis::ConflictAnalysisContext; +use crate::engine::conflict_analysis::MinimisationContext; use crate::engine::conflict_analysis::Mode; use crate::engine::conflict_analysis::NogoodMinimiser; use crate::engine::conflict_analysis::RecursiveMinimiser; @@ -18,7 +19,6 @@ use crate::proof::InferenceCode; use crate::proof::RootExplanationContext; use crate::proof::explain_root_assignment; use crate::propagation::CurrentNogood; -use crate::propagation::MinimisationContext; use crate::propagators::nogoods::NogoodPropagator; use crate::pumpkin_assert_advanced; use crate::pumpkin_assert_moderate; diff --git a/pumpkin-crates/core/src/propagation/contexts/mod.rs b/pumpkin-crates/core/src/propagation/contexts/mod.rs index 8a2c497a3..5e365abd0 100644 --- a/pumpkin-crates/core/src/propagation/contexts/mod.rs +++ b/pumpkin-crates/core/src/propagation/contexts/mod.rs @@ -1,7 +1,5 @@ mod explanation_context; -mod minimisation_context; mod propagation_context; pub use explanation_context::*; -pub(crate) use minimisation_context::*; pub use propagation_context::*; From cdc9c596bb72dc5f353e6badd7dd5a440da283e0 Mon Sep 17 00:00:00 2001 From: Imko Marijnissen Date: Mon, 15 Dec 2025 11:23:53 +0100 Subject: [PATCH 20/29] refactor: changing priority to enum --- .../core/src/engine/cp/propagator_queue.rs | 28 ++++++++++++- pumpkin-crates/core/src/engine/state.rs | 2 +- .../core/src/propagation/propagator.rs | 40 ++++++++++++++----- .../propagators/arithmetic/absolute_value.rs | 5 ++- .../arithmetic/binary/binary_equals.rs | 5 ++- .../arithmetic/binary/binary_not_equals.rs | 5 ++- .../arithmetic/integer_division.rs | 5 ++- .../arithmetic/integer_multiplication.rs | 5 ++- .../arithmetic/linear_less_or_equal.rs | 5 ++- .../arithmetic/linear_not_equal.rs | 5 ++- .../src/propagators/arithmetic/maximum.rs | 5 ++- .../time_table_over_interval_incremental.rs | 5 ++- .../time_table_per_point_incremental.rs | 5 ++- .../time_table/time_table_over_interval.rs | 5 ++- .../time_table/time_table_per_point.rs | 5 ++- .../core/src/propagators/element.rs | 5 ++- .../propagators/nogoods/nogood_propagator.rs | 5 ++- .../src/propagators/reified_propagator.rs | 3 +- 18 files changed, 102 insertions(+), 41 deletions(-) diff --git a/pumpkin-crates/core/src/engine/cp/propagator_queue.rs b/pumpkin-crates/core/src/engine/cp/propagator_queue.rs index 2693f5211..6d877fd27 100644 --- a/pumpkin-crates/core/src/engine/cp/propagator_queue.rs +++ b/pumpkin-crates/core/src/engine/cp/propagator_queue.rs @@ -3,6 +3,7 @@ use std::collections::BinaryHeap; use std::collections::VecDeque; use crate::containers::KeyedVec; +use crate::propagation::Priority; use crate::propagation::PropagatorId; use crate::pumpkin_assert_moderate; @@ -34,7 +35,7 @@ impl PropagatorQueue { self.num_enqueued == 0 } - pub(crate) fn enqueue_propagator(&mut self, propagator_id: PropagatorId, priority: u32) { + pub(crate) fn enqueue_propagator(&mut self, propagator_id: PropagatorId, priority: Priority) { pumpkin_assert_moderate!((priority as usize) < self.queues.len()); if !self.is_propagator_enqueued(propagator_id) { @@ -43,7 +44,7 @@ impl PropagatorQueue { self.num_enqueued += 1; if self.queues[priority as usize].is_empty() { - self.present_priorities.push(Reverse(priority)); + self.present_priorities.push(Reverse(priority as u32)); } self.queues[priority as usize].push_back(propagator_id); } @@ -94,3 +95,26 @@ impl PropagatorQueue { .unwrap_or_default() } } + +#[cfg(test)] +mod tests { + use crate::engine::PropagatorQueue; + use crate::propagation::Priority; + use crate::state::PropagatorId; + + #[test] + fn test_ordering() { + let mut queue = PropagatorQueue::default(); + + queue.enqueue_propagator(PropagatorId(1), Priority::HighPriority); + queue.enqueue_propagator(PropagatorId(0), Priority::MediumPriority); + queue.enqueue_propagator(PropagatorId(3), Priority::VeryLowPriority); + queue.enqueue_propagator(PropagatorId(4), Priority::LowPriority); + + assert_eq!(PropagatorId(1), queue.pop().unwrap()); + assert_eq!(PropagatorId(0), queue.pop().unwrap()); + assert_eq!(PropagatorId(4), queue.pop().unwrap()); + assert_eq!(PropagatorId(3), queue.pop().unwrap()); + assert_eq!(None, queue.pop()); + } +} diff --git a/pumpkin-crates/core/src/engine/state.rs b/pumpkin-crates/core/src/engine/state.rs index 1845aa015..1e45b9ef8 100644 --- a/pumpkin-crates/core/src/engine/state.rs +++ b/pumpkin-crates/core/src/engine/state.rs @@ -360,7 +360,7 @@ impl State { let propagator = constructor.create(constructor_context); pumpkin_assert_simple!( - propagator.priority() <= 3, + propagator.priority() as u8 <= 3, "The propagator priority exceeds 3. Currently we only support values up to 3, but this can easily be changed if there is a good reason." diff --git a/pumpkin-crates/core/src/propagation/propagator.rs b/pumpkin-crates/core/src/propagation/propagator.rs index ca2470f58..16bcdf64f 100644 --- a/pumpkin-crates/core/src/propagation/propagator.rs +++ b/pumpkin-crates/core/src/propagation/propagator.rs @@ -158,15 +158,16 @@ pub trait Propagator: Downcast + DynClone { /// By default this function does nothing. fn synchronise(&mut self, _domains: Domains) {} - /// Returns the priority of the propagator represented as an integer. Lower values mean higher - /// priority and the priority determines the order in which propagators will be asked to - /// propagate. It is custom for simpler propagators to have lower priority values. - /// - /// By default the priority is set to 3. It is expected that propagator implementations would - /// set this value to some appropriate value. - fn priority(&self) -> u32 { - // setting an arbitrary priority by default - 3 + /// Returns the [`Priority`] of the propagator, used for determining the order in which + /// propagators are called. + /// + /// The intuition is that propagators with low computational complexity should be assigned a + /// high priority (i.e., should be propagated before computationally expensive propagators). + /// + /// By default the priority is set to [`Priority::VeryLowPriority`]. It is expected that + /// propagator implementations would set this value to some appropriate value. + fn priority(&self) -> Priority { + Priority::VeryLowPriority } /// A function which returns [`Some`] with a [`PropagatorConflict`] when this propagator can @@ -215,3 +216,24 @@ pub enum EnqueueDecision { /// The propagator should not be enqueued. Skip, } + +/// The priority of a propagator, used for determining the order in which propagators will be +/// called. +/// +/// The intuition is that propagators with low computational complexity should be assigned a high +/// priority (i.e., should be propagated before computationally expensive propagators). +#[derive(Default, Debug, Clone, Copy, Hash, PartialEq, Eq)] +#[repr(u8)] +pub enum Priority { + HighPriority = 0, + MediumPriority = 1, + LowPriority = 2, + #[default] + VeryLowPriority = 3, +} + +impl PartialOrd for Priority { + fn partial_cmp(&self, other: &Self) -> Option { + ((*self) as u8).partial_cmp(&((*other) as u8)) + } +} diff --git a/pumpkin-crates/core/src/propagators/arithmetic/absolute_value.rs b/pumpkin-crates/core/src/propagators/arithmetic/absolute_value.rs index 4e379431b..2a75e5219 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/absolute_value.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/absolute_value.rs @@ -7,6 +7,7 @@ use crate::proof::ConstraintTag; use crate::proof::InferenceCode; use crate::propagation::DomainEvents; use crate::propagation::LocalId; +use crate::propagation::Priority; use crate::propagation::PropagationContext; use crate::propagation::Propagator; use crate::propagation::PropagatorConstructor; @@ -65,8 +66,8 @@ where VA: IntegerVariable + 'static, VB: IntegerVariable + 'static, { - fn priority(&self) -> u32 { - 0 + fn priority(&self) -> Priority { + Priority::HighPriority } fn name(&self) -> &str { diff --git a/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_equals.rs b/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_equals.rs index 643cee333..3857179a5 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_equals.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_equals.rs @@ -25,6 +25,7 @@ use crate::propagation::EnqueueDecision; use crate::propagation::ExplanationContext; use crate::propagation::LocalId; use crate::propagation::NotificationContext; +use crate::propagation::Priority; use crate::propagation::PropagationContext; use crate::propagation::Propagator; use crate::propagation::PropagatorConstructor; @@ -214,8 +215,8 @@ where self.has_backtracked = true; } - fn priority(&self) -> u32 { - 0 + fn priority(&self) -> Priority { + Priority::HighPriority } fn name(&self) -> &str { diff --git a/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_not_equals.rs b/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_not_equals.rs index c57294b77..3d9a42486 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_not_equals.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_not_equals.rs @@ -9,6 +9,7 @@ use crate::proof::InferenceCode; use crate::propagation::DomainEvents; use crate::propagation::Domains; use crate::propagation::LocalId; +use crate::propagation::Priority; use crate::propagation::PropagationContext; use crate::propagation::Propagator; use crate::propagation::PropagatorConstructor; @@ -87,8 +88,8 @@ where } } - fn priority(&self) -> u32 { - 0 + fn priority(&self) -> Priority { + Priority::HighPriority } fn name(&self) -> &str { diff --git a/pumpkin-crates/core/src/propagators/arithmetic/integer_division.rs b/pumpkin-crates/core/src/propagators/arithmetic/integer_division.rs index 7c674e7a6..5bb583621 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/integer_division.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/integer_division.rs @@ -7,6 +7,7 @@ use crate::proof::ConstraintTag; use crate::proof::InferenceCode; use crate::propagation::DomainEvents; use crate::propagation::LocalId; +use crate::propagation::Priority; use crate::propagation::PropagationContext; use crate::propagation::Propagator; use crate::propagation::PropagatorConstructor; @@ -85,8 +86,8 @@ where VB: IntegerVariable, VC: IntegerVariable, { - fn priority(&self) -> u32 { - 0 + fn priority(&self) -> Priority { + Priority::HighPriority } fn name(&self) -> &str { diff --git a/pumpkin-crates/core/src/propagators/arithmetic/integer_multiplication.rs b/pumpkin-crates/core/src/propagators/arithmetic/integer_multiplication.rs index 215fb53c3..391a7d996 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/integer_multiplication.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/integer_multiplication.rs @@ -8,6 +8,7 @@ use crate::proof::ConstraintTag; use crate::proof::InferenceCode; use crate::propagation::DomainEvents; use crate::propagation::LocalId; +use crate::propagation::Priority; use crate::propagation::PropagationContext; use crate::propagation::Propagator; use crate::propagation::PropagatorConstructor; @@ -77,8 +78,8 @@ where VB: IntegerVariable, VC: IntegerVariable, { - fn priority(&self) -> u32 { - 0 + fn priority(&self) -> Priority { + Priority::HighPriority } fn name(&self) -> &str { diff --git a/pumpkin-crates/core/src/propagators/arithmetic/linear_less_or_equal.rs b/pumpkin-crates/core/src/propagators/arithmetic/linear_less_or_equal.rs index ceb03bb34..5d2509855 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/linear_less_or_equal.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/linear_less_or_equal.rs @@ -16,6 +16,7 @@ use crate::propagation::ExplanationContext; use crate::propagation::LocalId; use crate::propagation::ManipulateTrailedValues; use crate::propagation::NotificationContext; +use crate::propagation::Priority; use crate::propagation::PropagationContext; use crate::propagation::Propagator; use crate::propagation::PropagatorConstructor; @@ -139,8 +140,8 @@ where EnqueueDecision::Enqueue } - fn priority(&self) -> u32 { - 0 + fn priority(&self) -> Priority { + Priority::HighPriority } fn name(&self) -> &str { diff --git a/pumpkin-crates/core/src/propagators/arithmetic/linear_not_equal.rs b/pumpkin-crates/core/src/propagators/arithmetic/linear_not_equal.rs index c2ffc8cab..aa5196846 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/linear_not_equal.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/linear_not_equal.rs @@ -17,6 +17,7 @@ use crate::propagation::Domains; use crate::propagation::EnqueueDecision; use crate::propagation::LocalId; use crate::propagation::NotificationContext; +use crate::propagation::Priority; use crate::propagation::PropagationContext; use crate::propagation::Propagator; use crate::propagation::PropagatorConstructor; @@ -106,8 +107,8 @@ impl Propagator for LinearNotEqualPropagator where Var: IntegerVariable + 'static, { - fn priority(&self) -> u32 { - 0 + fn priority(&self) -> Priority { + Priority::HighPriority } fn name(&self) -> &str { diff --git a/pumpkin-crates/core/src/propagators/arithmetic/maximum.rs b/pumpkin-crates/core/src/propagators/arithmetic/maximum.rs index 72fb54396..c44368893 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/maximum.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/maximum.rs @@ -8,6 +8,7 @@ use crate::proof::ConstraintTag; use crate::proof::InferenceCode; use crate::propagation::DomainEvents; use crate::propagation::LocalId; +use crate::propagation::Priority; use crate::propagation::PropagationContext; use crate::propagation::Propagator; use crate::propagation::PropagatorConstructor; @@ -69,8 +70,8 @@ pub(crate) struct MaximumPropagator { impl Propagator for MaximumPropagator { - fn priority(&self) -> u32 { - 0 + fn priority(&self) -> Priority { + Priority::HighPriority } fn name(&self) -> &str { diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/time_table_over_interval_incremental.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/time_table_over_interval_incremental.rs index b15477ee4..e51247662 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/time_table_over_interval_incremental.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/time_table_over_interval_incremental.rs @@ -9,6 +9,7 @@ use crate::basic_types::PropagatorConflict; use crate::conjunction; use crate::engine::notifications::OpaqueDomainEvent; use crate::engine::notifications::DomainEvent; +use crate::propagation::Priority; use crate::propagation::PropagatorConstructorContext; use crate::propagation::NotificationContext; use crate::propagation::PropagatorConstructor; @@ -498,8 +499,8 @@ impl Propagator } } - fn priority(&self) -> u32 { - 3 + fn priority(&self) -> Priority { + Priority::VeryLowPriority } fn name(&self) -> &str { diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/time_table_per_point_incremental.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/time_table_per_point_incremental.rs index adbf6567c..646baacf8 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/time_table_per_point_incremental.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/time_table_per_point_incremental.rs @@ -15,6 +15,7 @@ use crate::propagation::Domains; use crate::propagation::EnqueueDecision; use crate::propagation::LocalId; use crate::propagation::NotificationContext; +use crate::propagation::Priority; use crate::propagation::PropagationContext; use crate::propagation::Propagator; use crate::propagation::PropagatorConstructor; @@ -523,8 +524,8 @@ impl Propagator } } - fn priority(&self) -> u32 { - 3 + fn priority(&self) -> Priority { + Priority::VeryLowPriority } fn name(&self) -> &str { diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_over_interval.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_over_interval.rs index f71e51c5e..8a01cd929 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_over_interval.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_over_interval.rs @@ -15,6 +15,7 @@ use crate::propagation::Domains; use crate::propagation::EnqueueDecision; use crate::propagation::LocalId; use crate::propagation::NotificationContext; +use crate::propagation::Priority; use crate::propagation::PropagationContext; use crate::propagation::Propagator; use crate::propagation::PropagatorConstructor; @@ -183,8 +184,8 @@ impl Propagator for TimeTableOverIntervalPropaga result.decision } - fn priority(&self) -> u32 { - 3 + fn priority(&self) -> Priority { + Priority::VeryLowPriority } fn name(&self) -> &str { diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_per_point.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_per_point.rs index fb3507c9e..fa75c757b 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_per_point.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_per_point.rs @@ -20,6 +20,7 @@ use crate::propagation::Domains; use crate::propagation::EnqueueDecision; use crate::propagation::LocalId; use crate::propagation::NotificationContext; +use crate::propagation::Priority; use crate::propagation::PropagationContext; use crate::propagation::Propagator; use crate::propagation::PropagatorConstructor; @@ -176,8 +177,8 @@ impl Propagator for TimeTablePerPointPropagator< result.decision } - fn priority(&self) -> u32 { - 3 + fn priority(&self) -> Priority { + Priority::VeryLowPriority } fn name(&self) -> &str { diff --git a/pumpkin-crates/core/src/propagators/element.rs b/pumpkin-crates/core/src/propagators/element.rs index ae1fe43b7..2eb05f8ca 100644 --- a/pumpkin-crates/core/src/propagators/element.rs +++ b/pumpkin-crates/core/src/propagators/element.rs @@ -14,6 +14,7 @@ use crate::proof::InferenceCode; use crate::propagation::DomainEvents; use crate::propagation::ExplanationContext; use crate::propagation::LocalId; +use crate::propagation::Priority; use crate::propagation::PropagationContext; use crate::propagation::Propagator; use crate::propagation::PropagatorConstructor; @@ -95,8 +96,8 @@ where VI: IntegerVariable + 'static, VE: IntegerVariable + 'static, { - fn priority(&self) -> u32 { - 2 + fn priority(&self) -> Priority { + Priority::LowPriority } fn name(&self) -> &str { diff --git a/pumpkin-crates/core/src/propagators/nogoods/nogood_propagator.rs b/pumpkin-crates/core/src/propagators/nogoods/nogood_propagator.rs index 24622e681..ea9a75bdb 100644 --- a/pumpkin-crates/core/src/propagators/nogoods/nogood_propagator.rs +++ b/pumpkin-crates/core/src/propagators/nogoods/nogood_propagator.rs @@ -26,6 +26,7 @@ use crate::propagation::Domains; use crate::propagation::EnqueueDecision; use crate::propagation::ExplanationContext; use crate::propagation::HasAssignments; +use crate::propagation::Priority; use crate::propagation::PropagationContext; use crate::propagation::Propagator; use crate::propagation::PropagatorConstructor; @@ -199,8 +200,8 @@ impl Propagator for NogoodPropagator { "NogoodPropagator" } - fn priority(&self) -> u32 { - 0 + fn priority(&self) -> Priority { + Priority::HighPriority } fn notify_predicate_id_satisfied(&mut self, predicate_id: PredicateId) -> EnqueueDecision { diff --git a/pumpkin-crates/core/src/propagators/reified_propagator.rs b/pumpkin-crates/core/src/propagators/reified_propagator.rs index 5f0b76618..96ed10275 100644 --- a/pumpkin-crates/core/src/propagators/reified_propagator.rs +++ b/pumpkin-crates/core/src/propagators/reified_propagator.rs @@ -7,6 +7,7 @@ use crate::propagation::EnqueueDecision; use crate::propagation::ExplanationContext; use crate::propagation::LocalId; use crate::propagation::NotificationContext; +use crate::propagation::Priority; use crate::propagation::PropagationContext; use crate::propagation::Propagator; use crate::propagation::PropagatorConstructor; @@ -110,7 +111,7 @@ impl Propagator for ReifiedPropagator u32 { + fn priority(&self) -> Priority { self.propagator.priority() } From 062054ace3b021f0f4569b2e30fba381be0cb87f Mon Sep 17 00:00:00 2001 From: Imko Marijnissen Date: Mon, 15 Dec 2025 11:35:30 +0100 Subject: [PATCH 21/29] docs: adding documentation to ReadDomains --- .../core/src/propagation/domains.rs | 42 ++++++++++++++----- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/pumpkin-crates/core/src/propagation/domains.rs b/pumpkin-crates/core/src/propagation/domains.rs index d1a7edc3f..de344852b 100644 --- a/pumpkin-crates/core/src/propagation/domains.rs +++ b/pumpkin-crates/core/src/propagation/domains.rs @@ -2,6 +2,8 @@ use crate::engine::Assignments; use crate::engine::TrailedInteger; use crate::engine::TrailedValues; use crate::predicates::Predicate; +#[cfg(doc)] +use crate::propagation::ExplanationContext; use crate::variables::IntegerVariable; use crate::variables::Literal; @@ -40,14 +42,19 @@ impl HasAssignments for Domains<'_> { } } +/// A trait defining functions for retrieving information about the current domains. pub trait ReadDomains { + /// Returns whether the provided [`Predicate`] is assigned (either true or false) or is + /// currently unassigned. fn evaluate_predicate(&self, predicate: Predicate) -> Option; + /// Returns whether the provided [`Literal`] is assigned (either true or false) or is + /// currently unassigned. fn evaluate_literal(&self, literal: Literal) -> Option { self.evaluate_predicate(literal.get_true_predicate()) } - /// Returns the holes which were created on the current decision level. + /// Returns the holes in the domain which were created on the current checkpoint. fn get_holes_at_current_checkpoint( &self, var: &Var, @@ -57,27 +64,44 @@ pub trait ReadDomains { /// created at previous decision levels). fn get_holes(&self, var: &Var) -> impl Iterator; - /// Returns `true` if the domain of the given variable is singleton. + /// Returns `true` if the domain of the given variable is singleton (i.e., the variable is + /// fixed). fn is_fixed(&self, var: &Var) -> bool; + /// Returns the lowest value in the domain of `var`. fn lower_bound(&self, var: &Var) -> i32; + /// Returns the lowest value in the domain of `var` at the given `trail_position`. + /// + /// The trail position can be retrieved when generating lazy explanations using + /// [`ExplanationContext::get_trail_position`]. fn lower_bound_at_trail_position( &self, var: &Var, trail_position: usize, ) -> i32; + /// Returns the highest value in the domain of `var`. fn upper_bound(&self, var: &Var) -> i32; + /// Returns the highest value in the domain of `var` at the given `trail_position`. + /// + /// The trail position can be retrieved when generating lazy explanations using + /// [`ExplanationContext::get_trail_position`]. fn upper_bound_at_trail_position( &self, var: &Var, trail_position: usize, ) -> i32; + /// Returns whether the provided `value` is in the domain of `var`. fn contains(&self, var: &Var, value: i32) -> bool; + /// Returns whether the provided `value` is in the domain of `var` at the given + /// `trail_position`. + /// + /// The trail position can be retrieved when generating lazy explanations using + /// [`ExplanationContext::get_trail_position`]. fn contains_at_trail_position( &self, var: &Var, @@ -85,10 +109,16 @@ pub trait ReadDomains { trail_position: usize, ) -> bool; + /// Returns an [`Iterator`] over the values in the domain of the provided `var` (including the + /// lower-bound and upper-bound values). fn iterate_domain(&self, var: &Var) -> impl Iterator; + /// Returns whether the provided [`Predicate`] was posted as a decision (i.e., it was posted as + /// a [`Predicate`] without a reason). fn is_decision_predicate(&self, predicate: Predicate) -> bool; + /// If the provided [`Predicate`] is true, then this method returns the checkpoint at which it + /// first become true; otherwise, it returns [`None`]. fn get_checkpoint_for_predicate(&self, predicate: Predicate) -> Option; } @@ -97,7 +127,6 @@ impl ReadDomains for T { self.assignments().evaluate_predicate(predicate) } - /// Returns the holes which were created on the current decision level. fn get_holes_at_current_checkpoint( &self, var: &Var, @@ -105,13 +134,10 @@ impl ReadDomains for T { var.get_holes_at_current_checkpoint(self.assignments()) } - /// Returns all of the holes (currently) in the domain of `var` (including ones which were - /// created at previous decision levels). fn get_holes(&self, var: &Var) -> impl Iterator { var.get_holes(self.assignments()) } - /// Returns `true` if the domain of the given variable is singleton. fn is_fixed(&self, var: &Var) -> bool { self.lower_bound(var) == self.upper_bound(var) } @@ -157,14 +183,10 @@ impl ReadDomains for T { var.iterate_domain(self.assignments()) } - /// Returns whether the provided [`Predicate`] was posted as a decision (i.e., it was posted as - /// a [`Predicate`] without a reason). fn is_decision_predicate(&self, predicate: Predicate) -> bool { self.assignments().is_decision_predicate(&predicate) } - /// If the provided [`Predicate`] is true, then this method returns the checkpoint at which it - /// first become true; otherwise, it returns [`None`]. fn get_checkpoint_for_predicate(&self, predicate: Predicate) -> Option { self.assignments().get_checkpoint_for_predicate(&predicate) } From 67e8e8932ad37ec4659ea2ae2f2c34528c13fa6b Mon Sep 17 00:00:00 2001 From: Imko Marijnissen Date: Mon, 15 Dec 2025 13:12:02 +0100 Subject: [PATCH 22/29] feat: adding trailed integer methods to ReadDomains --- .../core/src/basic_types/solution.rs | 16 +++ .../minimisers/minimisation_context.rs | 8 ++ .../core/src/engine/cp/test_solver.rs | 2 +- .../src/engine/cp/trailed/trailed_integer.rs | 4 +- .../core/src/engine/notifications/mod.rs | 2 +- pumpkin-crates/core/src/engine/state.rs | 4 +- .../core/src/propagation/constructor.rs | 7 +- .../contexts/explanation_context.rs | 8 ++ .../contexts/propagation_context.rs | 99 +++++++------------ .../core/src/propagation/domains.rs | 50 ++++++++-- .../core/src/propagation/propagator.rs | 6 +- .../arithmetic/linear_less_or_equal.rs | 62 +++++++----- .../time_table/explanations/naive.rs | 2 +- .../debug.rs | 11 ++- .../synchronisation.rs | 8 +- .../time_table_over_interval_incremental.rs | 19 +++- .../time_table_per_point_incremental.rs | 19 +++- .../time_table/propagation_handler.rs | 4 +- .../time_table/time_table_over_interval.rs | 19 ++-- .../time_table/time_table_per_point.rs | 8 +- .../cumulative/time_table/time_table_util.rs | 45 +++++---- .../disjunctive/theta_lambda_tree.rs | 6 +- .../src/propagators/reified_propagator.rs | 2 +- 23 files changed, 242 insertions(+), 169 deletions(-) diff --git a/pumpkin-crates/core/src/basic_types/solution.rs b/pumpkin-crates/core/src/basic_types/solution.rs index ded8bf5d3..4dbdb583f 100644 --- a/pumpkin-crates/core/src/basic_types/solution.rs +++ b/pumpkin-crates/core/src/basic_types/solution.rs @@ -94,10 +94,26 @@ impl<'a> HasAssignments for SolutionReference<'a> { fn assignments(&self) -> &'a Assignments { self.assignments } + + fn trailed_values(&self) -> &crate::engine::TrailedValues { + unimplemented!("Currently, this information cannot be retrieved using this structure") + } + + fn trailed_values_mut(&mut self) -> &mut crate::engine::TrailedValues { + unimplemented!("Currently, this information cannot be retrieved using this structure") + } } impl HasAssignments for Solution { fn assignments(&self) -> &Assignments { &self.assignments } + + fn trailed_values(&self) -> &crate::engine::TrailedValues { + unimplemented!("Currently, this information cannot be retrieved using this structure") + } + + fn trailed_values_mut(&mut self) -> &mut crate::engine::TrailedValues { + unimplemented!("Currently, this information cannot be retrieved using this structure") + } } diff --git a/pumpkin-crates/core/src/engine/conflict_analysis/minimisers/minimisation_context.rs b/pumpkin-crates/core/src/engine/conflict_analysis/minimisers/minimisation_context.rs index ce46427eb..c8d38dc71 100644 --- a/pumpkin-crates/core/src/engine/conflict_analysis/minimisers/minimisation_context.rs +++ b/pumpkin-crates/core/src/engine/conflict_analysis/minimisers/minimisation_context.rs @@ -50,4 +50,12 @@ impl<'a> HasAssignments for MinimisationContext<'a> { fn assignments(&self) -> &Assignments { &self.state.assignments } + + fn trailed_values(&self) -> &crate::engine::TrailedValues { + &self.state.trailed_values + } + + fn trailed_values_mut(&mut self) -> &mut crate::engine::TrailedValues { + &mut self.state.trailed_values + } } diff --git a/pumpkin-crates/core/src/engine/cp/test_solver.rs b/pumpkin-crates/core/src/engine/cp/test_solver.rs index f9bd4b44e..f683543c2 100644 --- a/pumpkin-crates/core/src/engine/cp/test_solver.rs +++ b/pumpkin-crates/core/src/engine/cp/test_solver.rs @@ -341,7 +341,7 @@ impl TestSolver { .for_each(|propagator| { propagator.synchronise(Domains::new( &self.state.assignments, - &self.state.trailed_values, + &mut self.state.trailed_values, )) }) } diff --git a/pumpkin-crates/core/src/engine/cp/trailed/trailed_integer.rs b/pumpkin-crates/core/src/engine/cp/trailed/trailed_integer.rs index 23eb66b2e..397f783d2 100644 --- a/pumpkin-crates/core/src/engine/cp/trailed/trailed_integer.rs +++ b/pumpkin-crates/core/src/engine/cp/trailed/trailed_integer.rs @@ -1,7 +1,7 @@ use crate::containers::StorageKey; -/// An integer whose value is trailed by the solver. Backtracking automatically restores the -/// integer to previous values. +/// An integer whose value is automatically restored upon backtracking to its previous value at the +/// checkpoint to which backtracking occurred. #[derive(Debug, Clone, Copy)] pub struct TrailedInteger { id: u32, diff --git a/pumpkin-crates/core/src/engine/notifications/mod.rs b/pumpkin-crates/core/src/engine/notifications/mod.rs index 968d105f2..5e92af65c 100644 --- a/pumpkin-crates/core/src/engine/notifications/mod.rs +++ b/pumpkin-crates/core/src/engine/notifications/mod.rs @@ -309,7 +309,7 @@ impl NotificationEngine { pub(crate) fn process_backtrack_events( &mut self, assignments: &mut Assignments, - trailed_values: &TrailedValues, + trailed_values: &mut TrailedValues, propagators: &mut PropagatorStore, ) -> bool { // If there are no variables being watched then there is no reason to perform these diff --git a/pumpkin-crates/core/src/engine/state.rs b/pumpkin-crates/core/src/engine/state.rs index 1e45b9ef8..808420a70 100644 --- a/pumpkin-crates/core/src/engine/state.rs +++ b/pumpkin-crates/core/src/engine/state.rs @@ -505,13 +505,13 @@ impl State { // + allow incremental synchronisation // + only call the subset of propagators that were notified since last backtrack for propagator in self.propagators.iter_propagators_mut() { - let context = Domains::new(&self.assignments, &self.trailed_values); + let context = Domains::new(&self.assignments, &mut self.trailed_values); propagator.synchronise(context); } let _ = self.notification_engine.process_backtrack_events( &mut self.assignments, - &self.trailed_values, + &mut self.trailed_values, &mut self.propagators, ); self.notification_engine.clear_event_drain(); diff --git a/pumpkin-crates/core/src/propagation/constructor.rs b/pumpkin-crates/core/src/propagation/constructor.rs index 93a9b09fa..c9ef02847 100644 --- a/pumpkin-crates/core/src/propagation/constructor.rs +++ b/pumpkin-crates/core/src/propagation/constructor.rs @@ -66,8 +66,8 @@ impl PropagatorConstructorContext<'_> { } /// Get domain information. - pub fn domains(&self) -> Domains<'_> { - Domains::new(&self.state.assignments, &self.state.trailed_values) + pub fn domains(&mut self) -> Domains<'_> { + Domains::new(&self.state.assignments, &mut self.state.trailed_values) } /// Subscribes the propagator to the given [`DomainEvents`]. @@ -209,15 +209,12 @@ impl DerefMut for RefOrOwned<'_, T> { mod private { use super::*; use crate::propagation::HasAssignments; - use crate::propagation::HasTrailedValues; impl HasAssignments for PropagatorConstructorContext<'_> { fn assignments(&self) -> &Assignments { &self.state.assignments } - } - impl HasTrailedValues for PropagatorConstructorContext<'_> { fn trailed_values(&self) -> &TrailedValues { &self.state.trailed_values } diff --git a/pumpkin-crates/core/src/propagation/contexts/explanation_context.rs b/pumpkin-crates/core/src/propagation/contexts/explanation_context.rs index fea9e0c19..85f2c398e 100644 --- a/pumpkin-crates/core/src/propagation/contexts/explanation_context.rs +++ b/pumpkin-crates/core/src/propagation/contexts/explanation_context.rs @@ -88,6 +88,14 @@ impl HasAssignments for ExplanationContext<'_> { fn assignments(&self) -> &Assignments { self.assignments } + + fn trailed_values(&self) -> &crate::engine::TrailedValues { + unimplemented!("Currently, this information cannot be retrieved using this structure") + } + + fn trailed_values_mut(&mut self) -> &mut crate::engine::TrailedValues { + unimplemented!("Currently, this information cannot be retrieved using this structure") + } } static EMPTY_HEAP: KeyValueHeap = KeyValueHeap::new(); diff --git a/pumpkin-crates/core/src/propagation/contexts/propagation_context.rs b/pumpkin-crates/core/src/propagation/contexts/propagation_context.rs index 708977c07..dc9d6571a 100644 --- a/pumpkin-crates/core/src/propagation/contexts/propagation_context.rs +++ b/pumpkin-crates/core/src/propagation/contexts/propagation_context.rs @@ -2,7 +2,6 @@ use crate::basic_types::PredicateId; use crate::engine::Assignments; use crate::engine::EmptyDomain; use crate::engine::EmptyDomainConflict; -use crate::engine::TrailedInteger; use crate::engine::TrailedValues; use crate::engine::notifications::NotificationEngine; use crate::engine::notifications::PredicateIdAssignments; @@ -13,6 +12,7 @@ use crate::engine::reason::StoredReason; use crate::engine::variables::Literal; use crate::proof::InferenceCode; use crate::propagation::Domains; +use crate::propagation::HasAssignments; #[cfg(doc)] use crate::propagation::Propagator; use crate::propagation::PropagatorId; @@ -22,6 +22,8 @@ use crate::pumpkin_assert_simple; /// Provided to the propagator when it is notified of a domain event. /// +/// Domains can be read through the implementation of [`ReadDomains`]. +/// /// The difference with [`PropagationContext`] is that it is not possible to perform a propagation /// in the notify callback. #[derive(Debug)] @@ -45,11 +47,25 @@ impl<'a> NotificationContext<'a> { } /// Get the current domains. - pub fn domains(&self) -> Domains<'_> { + pub fn domains(&mut self) -> Domains<'_> { Domains::new(self.assignments, self.trailed_values) } } +impl<'a> HasAssignments for NotificationContext<'a> { + fn assignments(&self) -> &Assignments { + self.assignments + } + + fn trailed_values(&self) -> &TrailedValues { + self.trailed_values + } + + fn trailed_values_mut(&mut self) -> &mut TrailedValues { + self.trailed_values + } +} + /// Provides information about the state of the solver to a propagator. /// /// Domains can be read through the implementation of [`ReadDomains`], and changes to the state can @@ -64,6 +80,20 @@ pub struct PropagationContext<'a> { reification_literal: Option, } +impl<'a> HasAssignments for PropagationContext<'a> { + fn assignments(&self) -> &Assignments { + self.assignments + } + + fn trailed_values(&self) -> &TrailedValues { + self.trailed_values + } + + fn trailed_values_mut(&mut self) -> &mut TrailedValues { + self.trailed_values + } +} + impl<'a> PropagationContext<'a> { pub(crate) fn new( trailed_values: &'a mut TrailedValues, @@ -118,7 +148,7 @@ impl<'a> PropagationContext<'a> { } /// Get the current domain information. - pub fn domains(&self) -> Domains<'_> { + pub fn domains(&mut self) -> Domains<'_> { Domains::new(self.assignments, self.trailed_values) } @@ -146,69 +176,6 @@ impl<'a> PropagationContext<'a> { } } -pub(crate) trait HasTrailedValues { - fn trailed_values(&self) -> &TrailedValues; - fn trailed_values_mut(&mut self) -> &mut TrailedValues; -} - -mod private { - use super::*; - use crate::propagation::HasAssignments; - - impl HasTrailedValues for NotificationContext<'_> { - fn trailed_values(&self) -> &TrailedValues { - self.trailed_values - } - - fn trailed_values_mut(&mut self) -> &mut TrailedValues { - self.trailed_values - } - } - - impl HasTrailedValues for PropagationContext<'_> { - fn trailed_values(&self) -> &TrailedValues { - self.trailed_values - } - - fn trailed_values_mut(&mut self) -> &mut TrailedValues { - self.trailed_values - } - } - - impl HasAssignments for PropagationContext<'_> { - fn assignments(&self) -> &Assignments { - self.assignments - } - } - - impl HasAssignments for NotificationContext<'_> { - fn assignments(&self) -> &Assignments { - self.assignments - } - } -} - -pub(crate) trait ManipulateTrailedValues: HasTrailedValues { - fn new_trailed_integer(&mut self, initial_value: i64) -> TrailedInteger { - self.trailed_values_mut().grow(initial_value) - } - - fn value(&self, trailed_integer: TrailedInteger) -> i64 { - self.trailed_values().read(trailed_integer) - } - - fn add_assign(&mut self, trailed_integer: TrailedInteger, addition: i64) { - self.trailed_values_mut() - .add_assign(trailed_integer, addition); - } - - fn assign(&mut self, trailed_integer: TrailedInteger, value: i64) { - self.trailed_values_mut().assign(trailed_integer, value); - } -} - -impl ManipulateTrailedValues for T {} - impl PropagationContext<'_> { /// Assign the truth-value of the given [`Predicate`] to `true` in the current partial /// assignment. diff --git a/pumpkin-crates/core/src/propagation/domains.rs b/pumpkin-crates/core/src/propagation/domains.rs index de344852b..dc40a2196 100644 --- a/pumpkin-crates/core/src/propagation/domains.rs +++ b/pumpkin-crates/core/src/propagation/domains.rs @@ -11,35 +11,44 @@ use crate::variables::Literal; /// /// Implements [`ReadDomains`] to expose information about the current variable domains such as the /// lower-bound of a particular variable. -#[derive(Clone, Copy, Debug)] +#[derive(Debug)] pub struct Domains<'a> { pub(crate) assignments: &'a Assignments, - trailed_values: &'a TrailedValues, + trailed_values: &'a mut TrailedValues, } impl<'a> Domains<'a> { - pub(crate) fn new(assignments: &'a Assignments, trailed_values: &'a TrailedValues) -> Self { + pub(crate) fn new(assignments: &'a Assignments, trailed_values: &'a mut TrailedValues) -> Self { Domains { assignments, trailed_values, } } - /// Read the value of a [`TrailedInteger`]. - pub fn value(&self, trailed_integer: TrailedInteger) -> i64 { - self.trailed_values.read(trailed_integer) + pub fn reborrow(&mut self) -> Domains<'_> { + Domains::new(self.assignments, self.trailed_values) } } /// A helper-trait for implementing [`ReadDomains`], which exposes the assignment. pub(crate) trait HasAssignments { fn assignments(&self) -> &Assignments; + fn trailed_values(&self) -> &TrailedValues; + fn trailed_values_mut(&mut self) -> &mut TrailedValues; } impl HasAssignments for Domains<'_> { fn assignments(&self) -> &Assignments { self.assignments } + + fn trailed_values(&self) -> &TrailedValues { + self.trailed_values + } + + fn trailed_values_mut(&mut self) -> &mut TrailedValues { + self.trailed_values + } } /// A trait defining functions for retrieving information about the current domains. @@ -120,6 +129,18 @@ pub trait ReadDomains { /// If the provided [`Predicate`] is true, then this method returns the checkpoint at which it /// first become true; otherwise, it returns [`None`]. fn get_checkpoint_for_predicate(&self, predicate: Predicate) -> Option; + + /// Returns the current value of the provided [`TrailedInteger`]. + fn value_trailed_integer(&self, trailed_integer: TrailedInteger) -> i64; + + /// Creates a new [`TrailedInteger`] assigned to the provided `initial_value`. + fn new_trailed_integer(&mut self, initial_value: i64) -> TrailedInteger; + + /// Adds `addition` to the value of the provided [`TrailedInteger`]. + fn add_assign_trailed_integer(&mut self, trailed_integer: TrailedInteger, addition: i64); + + /// Assigns the provided [`TrailedInteger`] to the provided `value`. + fn assign_trailed_integer(&mut self, trailed_integer: TrailedInteger, value: i64); } impl ReadDomains for T { @@ -190,4 +211,21 @@ impl ReadDomains for T { fn get_checkpoint_for_predicate(&self, predicate: Predicate) -> Option { self.assignments().get_checkpoint_for_predicate(&predicate) } + + fn value_trailed_integer(&self, trailed_integer: TrailedInteger) -> i64 { + self.trailed_values().read(trailed_integer) + } + + fn new_trailed_integer(&mut self, initial_value: i64) -> TrailedInteger { + self.trailed_values_mut().grow(initial_value) + } + + fn add_assign_trailed_integer(&mut self, trailed_integer: TrailedInteger, addition: i64) { + self.trailed_values_mut() + .add_assign(trailed_integer, addition); + } + + fn assign_trailed_integer(&mut self, trailed_integer: TrailedInteger, value: i64) { + self.trailed_values_mut().assign(trailed_integer, value); + } } diff --git a/pumpkin-crates/core/src/propagation/propagator.rs b/pumpkin-crates/core/src/propagation/propagator.rs index 16bcdf64f..510d331c2 100644 --- a/pumpkin-crates/core/src/propagation/propagator.rs +++ b/pumpkin-crates/core/src/propagation/propagator.rs @@ -143,9 +143,9 @@ pub trait Propagator: Downcast + DynClone { } /// Returns whether the propagator should be enqueued for propagation when a [`Predicate`] (with - /// corresponding [`PredicateId`]) which the propagator is subscribed to (as registered during - /// creation with [`PropagatorConstructor`] using - /// [`PropagatorConstructorContext::register_predicate`]). + /// corresponding [`PredicateId`]) which the propagator is subscribed to (as registered either + /// during using [`PropagationContext::register_predicate`] or during creation with + /// [`PropagatorConstructor`] using [`PropagatorConstructorContext::register_predicate`]). /// /// By default, the propagator will be enqueued. fn notify_predicate_id_satisfied(&mut self, _predicate_id: PredicateId) -> EnqueueDecision { diff --git a/pumpkin-crates/core/src/propagators/arithmetic/linear_less_or_equal.rs b/pumpkin-crates/core/src/propagators/arithmetic/linear_less_or_equal.rs index 5d2509855..f419fb470 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/linear_less_or_equal.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/linear_less_or_equal.rs @@ -14,7 +14,6 @@ use crate::propagation::Domains; use crate::propagation::EnqueueDecision; use crate::propagation::ExplanationContext; use crate::propagation::LocalId; -use crate::propagation::ManipulateTrailedValues; use crate::propagation::NotificationContext; use crate::propagation::Priority; use crate::propagation::PropagationContext; @@ -110,7 +109,7 @@ where Var: IntegerVariable, { fn detect_inconsistency(&self, domains: Domains) -> Option { - if (self.c as i64) < domains.value(self.lower_bound_left_hand_side) { + if (self.c as i64) < domains.value_trailed_integer(self.lower_bound_left_hand_side) { Some(self.create_conflict(domains)) } else { None @@ -126,7 +125,7 @@ where let index = local_id.unpack() as usize; let x_i = &self.x[index]; - let old_bound = context.value(self.current_bounds[index]); + let old_bound = context.value_trailed_integer(self.current_bounds[index]); let new_bound = context.lower_bound(x_i) as i64; pumpkin_assert_simple!( @@ -134,8 +133,8 @@ where "propagator should only be triggered when lower bounds are tightened, old_bound={old_bound}, new_bound={new_bound}" ); - context.add_assign(self.lower_bound_left_hand_side, new_bound - old_bound); - context.assign(self.current_bounds[index], new_bound); + context.add_assign_trailed_integer(self.lower_bound_left_hand_side, new_bound - old_bound); + context.assign_trailed_integer(self.current_bounds[index], new_bound); EnqueueDecision::Enqueue } @@ -173,27 +172,32 @@ where return Err(conflict.into()); } - let lower_bound_left_hand_side = - match TryInto::::try_into(context.value(self.lower_bound_left_hand_side)) { - Ok(bound) => bound, - Err(_) if context.value(self.lower_bound_left_hand_side).is_positive() => { - // We cannot fit the `lower_bound_left_hand_side` into an i32 due to an - // overflow (hence the check that the lower-bound on the left-hand side is - // positive) - // - // This means that the lower-bounds of the current variables will always be - // higher than the right-hand side (with a maximum value of i32). We thus - // return a conflict - return Err(self.create_conflict(context.domains()).into()); - } - Err(_) => { - // We cannot fit the `lower_bound_left_hand_side` into an i32 due to an - // underflow - // - // This means that the constraint is always satisfied - return Ok(()); - } - }; + let lower_bound_left_hand_side = match TryInto::::try_into( + context.value_trailed_integer(self.lower_bound_left_hand_side), + ) { + Ok(bound) => bound, + Err(_) + if context + .value_trailed_integer(self.lower_bound_left_hand_side) + .is_positive() => + { + // We cannot fit the `lower_bound_left_hand_side` into an i32 due to an + // overflow (hence the check that the lower-bound on the left-hand side is + // positive) + // + // This means that the lower-bounds of the current variables will always be + // higher than the right-hand side (with a maximum value of i32). We thus + // return a conflict + return Err(self.create_conflict(context.domains()).into()); + } + Err(_) => { + // We cannot fit the `lower_bound_left_hand_side` into an i32 due to an + // underflow + // + // This means that the constraint is always satisfied + return Ok(()); + } + }; for (i, x_i) in self.x.iter().enumerate() { let bound = self.c - (lower_bound_left_hand_side - context.lower_bound(x_i)); @@ -216,7 +220,11 @@ where let lower_bound_left_hand_side = match TryInto::::try_into(lower_bound_left_hand_side) { Ok(bound) => bound, - Err(_) if context.value(self.lower_bound_left_hand_side).is_positive() => { + Err(_) + if context + .value_trailed_integer(self.lower_bound_left_hand_side) + .is_positive() => + { // We cannot fit the `lower_bound_left_hand_side` into an i32 due to an // overflow (hence the check that the lower-bound on the left-hand side is // positive) diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/explanations/naive.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/explanations/naive.rs index a0cc5fa5e..c92f6b2b0 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/explanations/naive.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/explanations/naive.rs @@ -35,7 +35,7 @@ pub(crate) fn create_naive_propagation_explanation( +pub(crate) fn create_naive_conflict_explanation( conflict_profile: &ResourceProfile, context: Context, ) -> PropositionalConjunction diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/debug.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/debug.rs index 83ca04e55..6c542aba8 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/debug.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/debug.rs @@ -25,14 +25,17 @@ pub(crate) fn time_tables_are_the_same_interval< Var: IntegerVariable + 'static, const SYNCHRONISE: bool, >( - context: Domains, + mut context: Domains, inference_code: InferenceCode, time_table: &OverIntervalTimeTableType, parameters: &CumulativeParameters, ) -> bool { - let time_table_scratch = - create_time_table_over_interval_from_scratch(context, parameters, inference_code) - .expect("Expected no error"); + let time_table_scratch = create_time_table_over_interval_from_scratch( + context.reborrow(), + parameters, + inference_code, + ) + .expect("Expected no error"); if time_table.is_empty() { return time_table_scratch.is_empty(); diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/synchronisation.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/synchronisation.rs index 019af1581..2decdf04c 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/synchronisation.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/synchronisation.rs @@ -81,7 +81,7 @@ pub(crate) fn check_synchronisation_conflict_explanation_over_interval< /// been reported by [`TimeTableOverIntervalPropagator`] by finding the tasks which should be /// included in the profile and sorting them in the same order. pub(crate) fn create_synchronised_conflict_explanation( - context: Domains, + mut context: Domains, inference_code: InferenceCode, conflicting_profile: &mut ResourceProfile, parameters: &CumulativeParameters, @@ -93,7 +93,7 @@ pub(crate) fn create_synchronised_conflict_explanation( time_table: &mut OverIntervalTimeTableType, - context: Domains, + mut context: Domains, ) { if !time_table.is_empty() { // If the time-table is not empty then we merge all the profiles in the range @@ -138,7 +138,7 @@ pub(crate) fn synchronise_time_table( // And then we sort each profile according to upper-bound and then ID time_table .iter_mut() - .for_each(|profile| sort_profile_based_on_upper_bound_and_id(profile, context)) + .for_each(|profile| sort_profile_based_on_upper_bound_and_id(profile, context.reborrow())) } /// Sorts the provided `profile` on non-decreasing order of upper-bound while tie-breaking in diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/time_table_over_interval_incremental.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/time_table_over_interval_incremental.rs index e51247662..aa8e25650 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/time_table_over_interval_incremental.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/time_table_over_interval_incremental.rs @@ -156,7 +156,7 @@ impl /// that all of the adjustments are applied even if a conflict is found. fn add_to_time_table( &mut self, - context: Domains, + mut context: Domains, mandatory_part_adjustments: &MandatoryPartAdjustments, task: &Rc>, ) -> PropagationStatusCP { @@ -180,7 +180,7 @@ impl && conflict.is_none() { conflict = Some(Err(create_conflict_explanation( - context, + context.reborrow(), self.inference_code.unwrap(), &conflict_tasks, self.parameters.options.explanation_type, @@ -420,7 +420,7 @@ impl Propagator fn notify( &mut self, - context: NotificationContext, + mut context: NotificationContext, local_id: LocalId, event: OpaqueDomainEvent, ) -> EnqueueDecision { @@ -460,12 +460,21 @@ impl Propagator result.decision } - fn notify_backtrack(&mut self, context: Domains, local_id: LocalId, event: OpaqueDomainEvent) { + fn notify_backtrack( + &mut self, + mut context: Domains, + local_id: LocalId, + event: OpaqueDomainEvent, + ) { pumpkin_assert_simple!(self.parameters.options.incremental_backtracking); let updated_task = Rc::clone(&self.parameters.tasks[local_id.unpack() as usize]); - backtrack_update(context, &mut self.updatable_structures, &updated_task); + backtrack_update( + context.reborrow(), + &mut self.updatable_structures, + &updated_task, + ); update_bounds_task( context, diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/time_table_per_point_incremental.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/time_table_per_point_incremental.rs index 646baacf8..2c5f12348 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/time_table_per_point_incremental.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/time_table_per_point_incremental.rs @@ -145,7 +145,7 @@ impl /// that all of the adjustments are applied even if a conflict is found. fn add_to_time_table( &mut self, - context: Domains, + mut context: Domains, mandatory_part_adjustments: &MandatoryPartAdjustments, task: &Rc>, ) -> PropagationStatusCP { @@ -181,7 +181,7 @@ impl if current_profile.height > self.parameters.capacity && conflict.is_none() { // The newly introduced mandatory part(s) caused an overflow of the resource conflict = Some(Err(create_conflict_explanation( - context, + context.reborrow(), self.inference_code.unwrap(), current_profile, self.parameters.options.explanation_type, @@ -447,7 +447,7 @@ impl Propagator fn notify( &mut self, - context: NotificationContext, + mut context: NotificationContext, local_id: LocalId, event: OpaqueDomainEvent, ) -> EnqueueDecision { @@ -487,10 +487,19 @@ impl Propagator result.decision } - fn notify_backtrack(&mut self, context: Domains, local_id: LocalId, event: OpaqueDomainEvent) { + fn notify_backtrack( + &mut self, + mut context: Domains, + local_id: LocalId, + event: OpaqueDomainEvent, + ) { let updated_task = Rc::clone(&self.parameters.tasks[local_id.unpack() as usize]); - backtrack_update(context, &mut self.updatable_structures, &updated_task); + backtrack_update( + context.reborrow(), + &mut self.updatable_structures, + &updated_task, + ); update_bounds_task( context, diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/propagation_handler.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/propagation_handler.rs index 428f5734e..882dc3b07 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/propagation_handler.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/propagation_handler.rs @@ -448,7 +448,7 @@ impl CumulativePropagationHandler { /// Creates an explanation of the conflict caused by `conflict_profile` based on the provided /// `explanation_type`. -pub(crate) fn create_conflict_explanation( +pub(crate) fn create_conflict_explanation( context: Context, inference_code: InferenceCode, conflict_profile: &ResourceProfile, @@ -548,7 +548,7 @@ pub(crate) mod test_propagation_handler { }; let reason = create_conflict_explanation( - Domains::new(&self.assignments, &self.trailed_values), + Domains::new(&self.assignments, &mut self.trailed_values), self.propagation_handler.inference_code, &profile, self.propagation_handler.explanation_type, diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_over_interval.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_over_interval.rs index 8a01cd929..d39b39b59 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_over_interval.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_over_interval.rs @@ -150,7 +150,7 @@ impl Propagator for TimeTableOverIntervalPropaga fn notify( &mut self, - context: NotificationContext, + mut context: NotificationContext, local_id: LocalId, event: OpaqueDomainEvent, ) -> EnqueueDecision { @@ -212,16 +212,13 @@ impl Propagator for TimeTableOverIntervalPropaga /// The result of this method is either the time-table of type /// [`OverIntervalTimeTableType`] or the tasks responsible for the /// conflict in the form of an [`PropagatorConflict`]. -pub(crate) fn create_time_table_over_interval_from_scratch< - Var: IntegerVariable + 'static, - Context: ReadDomains + Copy, ->( - context: Context, +pub(crate) fn create_time_table_over_interval_from_scratch( + mut context: Domains, parameters: &CumulativeParameters, inference_code: InferenceCode, ) -> Result, PropagatorConflict> { // First we create a list of all the events (i.e. start and ends of mandatory parts) - let events = create_events(context, parameters); + let events = create_events(context.reborrow(), parameters); // Then we create a time-table using these events create_time_table_from_events(events, context, inference_code, parameters) @@ -234,7 +231,7 @@ pub(crate) fn create_time_table_over_interval_from_scratch< /// is resolved by placing the events which signify the ends of mandatory parts first (if the /// tie is between events of the same type then the tie-breaking is done on the id in /// non-decreasing order). -fn create_events( +fn create_events( context: Context, parameters: &CumulativeParameters, ) -> Vec> { @@ -294,7 +291,7 @@ fn create_events( /// Creates a time-table based on the provided `events` (which are assumed to be sorted /// chronologically, with tie-breaking performed in such a way that the ends of mandatory parts /// are before the starts of mandatory parts). -fn create_time_table_from_events( +fn create_time_table_from_events( events: Vec>, context: Context, inference_code: InferenceCode, @@ -461,12 +458,14 @@ pub(crate) fn propagate_from_scratch_time_table_interval Propagator for TimeTablePerPointPropagator< fn notify( &mut self, - context: NotificationContext, + mut context: NotificationContext, local_id: LocalId, event: OpaqueDomainEvent, ) -> EnqueueDecision { @@ -205,7 +205,7 @@ impl Propagator for TimeTablePerPointPropagator< /// conflict in the form of an [`PropagatorConflict`]. pub(crate) fn create_time_table_per_point_from_scratch< Var: IntegerVariable + 'static, - Context: ReadDomains + Copy, + Context: ReadDomains, >( context: Context, inference_code: InferenceCode, @@ -262,12 +262,14 @@ pub(crate) fn propagate_from_scratch_time_table_point( parameters: &CumulativeParameters, updatable_structures: &UpdatableStructures, updated_task: &Rc>, - context: Domains, + mut context: Domains, empty_time_table: bool, ) -> ShouldEnqueueResult { pumpkin_assert_extreme!( @@ -70,7 +70,7 @@ pub(crate) fn should_enqueue( } // We check whether a mandatory part was extended/introduced - if has_mandatory_part(context, updated_task) { + if has_mandatory_part(context.reborrow(), updated_task) { result.update = Some(UpdatedTaskInfo { task: Rc::clone(updated_task), old_lower_bound, @@ -576,7 +576,7 @@ fn sweep_backward<'a, Var: IntegerVariable + 'static>( fn find_profiles_which_propagate_lower_bound<'a, Var: IntegerVariable + 'static>( profile_index: usize, time_table: &[&'a ResourceProfile], - context: Domains, + mut context: Domains, task: &Rc>, capacity: i32, profile_buffer: &mut Vec<&'a ResourceProfile>, @@ -594,7 +594,12 @@ fn find_profiles_which_propagate_lower_bound<'a, Var: IntegerVariable + 'static> break; } - if overflows_capacity_and_is_not_part_of_profile(context, task, next_profile, capacity) { + if overflows_capacity_and_is_not_part_of_profile( + context.reborrow(), + task, + next_profile, + capacity, + ) { last_propagating_index = current_index; profile_buffer.push(time_table[current_index]) } @@ -609,7 +614,7 @@ fn find_profiles_which_propagate_lower_bound<'a, Var: IntegerVariable + 'static> fn find_profiles_which_propagate_upper_bound<'a, Var: IntegerVariable + 'static>( profile_index: usize, time_table: &[&'a ResourceProfile], - context: Domains, + mut context: Domains, task: &Rc>, capacity: i32, profile_buffer: &mut Vec<&'a ResourceProfile>, @@ -629,8 +634,12 @@ fn find_profiles_which_propagate_upper_bound<'a, Var: IntegerVariable + 'static> break; } - if overflows_capacity_and_is_not_part_of_profile(context, task, previous_profile, capacity) - { + if overflows_capacity_and_is_not_part_of_profile( + context.reborrow(), + task, + previous_profile, + capacity, + ) { last_propagating = current_index; profile_buffer.push(time_table[current_index]); } @@ -654,12 +663,12 @@ fn find_profiles_which_propagate_upper_bound<'a, Var: IntegerVariable + 'static> /// Note: It is assumed that task.resource_usage + height > capacity (i.e. the task has the /// potential to overflow the capacity in combination with the profile) fn lower_bound_can_be_propagated_by_profile( - context: Domains, + mut context: Domains, task: &Rc>, profile: &ResourceProfile, capacity: i32, ) -> bool { - can_be_updated_by_profile(context, task, profile, capacity) + can_be_updated_by_profile(context.reborrow(), task, profile, capacity) && (context.lower_bound(&task.start_variable) + task.processing_time) > profile.start && context.lower_bound(&task.start_variable) <= profile.end } @@ -671,12 +680,12 @@ fn lower_bound_can_be_propagated_by_profile( /// * ub(s) <= end, i.e. the latest start time is before the end of the [`ResourceProfile`] /// Note: It is assumed that the task is known to overflow the [`ResourceProfile`] fn upper_bound_can_be_propagated_by_profile( - context: Domains, + mut context: Domains, task: &Rc>, profile: &ResourceProfile, capacity: i32, ) -> bool { - can_be_updated_by_profile(context, task, profile, capacity) + can_be_updated_by_profile(context.reborrow(), task, profile, capacity) && (context.upper_bound(&task.start_variable) + task.processing_time) > profile.start && context.upper_bound(&task.start_variable) <= profile.end } @@ -689,13 +698,13 @@ fn upper_bound_can_be_propagated_by_profile( /// If the first condition is true, the second false and the third true then this method returns /// true (otherwise it returns false) fn can_be_updated_by_profile( - context: Domains, + mut context: Domains, task: &Rc>, profile: &ResourceProfile, capacity: i32, ) -> bool { - overflows_capacity_and_is_not_part_of_profile(context, task, profile, capacity) - && task_has_overlap_with_interval(context, task, profile.start, profile.end) + overflows_capacity_and_is_not_part_of_profile(context.reborrow(), task, profile, capacity) + && task_has_overlap_with_interval(context.reborrow(), task, profile.start, profile.end) } /// Returns whether the provided `task` passes the following checks: @@ -783,7 +792,7 @@ mod tests { #[test] fn test_finding_last_index_lower_bound() { let mut assignments = Assignments::default(); - let trailed_values = TrailedValues::default(); + let mut trailed_values = TrailedValues::default(); let x = assignments.grow(0, 10); let y = assignments.grow(5, 5); @@ -818,7 +827,7 @@ mod tests { find_profiles_which_propagate_lower_bound( 0, &time_table, - Domains::new(&assignments, &trailed_values), + Domains::new(&assignments, &mut trailed_values), &Rc::new(Task { start_variable: x, processing_time: 6, @@ -834,7 +843,7 @@ mod tests { #[test] fn test_finding_last_index_upper_bound() { let mut assignments = Assignments::default(); - let trailed_values = TrailedValues::default(); + let mut trailed_values = TrailedValues::default(); let x = assignments.grow(7, 7); let y = assignments.grow(5, 5); @@ -869,7 +878,7 @@ mod tests { find_profiles_which_propagate_upper_bound( 1, &time_table, - Domains::new(&assignments, &trailed_values), + Domains::new(&assignments, &mut trailed_values), &Rc::new(Task { start_variable: x, processing_time: 6, diff --git a/pumpkin-crates/core/src/propagators/disjunctive/theta_lambda_tree.rs b/pumpkin-crates/core/src/propagators/disjunctive/theta_lambda_tree.rs index 84dea11f5..45e8631b6 100644 --- a/pumpkin-crates/core/src/propagators/disjunctive/theta_lambda_tree.rs +++ b/pumpkin-crates/core/src/propagators/disjunctive/theta_lambda_tree.rs @@ -416,18 +416,18 @@ mod tests { tree.update(Domains::new( &solver.state.assignments, - &solver.state.trailed_values, + &mut solver.state.trailed_values, )); for task in tasks.iter() { tree.add_to_theta( task, - Domains::new(&solver.state.assignments, &solver.state.trailed_values), + Domains::new(&solver.state.assignments, &mut solver.state.trailed_values), ); } tree.remove_from_theta(&tasks[2]); tree.add_to_lambda( &tasks[2], - Domains::new(&solver.state.assignments, &solver.state.trailed_values), + Domains::new(&solver.state.assignments, &mut solver.state.trailed_values), ); assert_eq!( diff --git a/pumpkin-crates/core/src/propagators/reified_propagator.rs b/pumpkin-crates/core/src/propagators/reified_propagator.rs index 96ed10275..e4387f3ae 100644 --- a/pumpkin-crates/core/src/propagators/reified_propagator.rs +++ b/pumpkin-crates/core/src/propagators/reified_propagator.rs @@ -192,7 +192,7 @@ impl ReifiedPropagator { fn filter_enqueue_decision( &mut self, - context: NotificationContext<'_>, + mut context: NotificationContext<'_>, decision: EnqueueDecision, ) -> EnqueueDecision { if decision == EnqueueDecision::Skip { From 34a85733867d8dc66eec86e8a2187c2194b306b2 Mon Sep 17 00:00:00 2001 From: Imko Marijnissen Date: Mon, 15 Dec 2025 13:16:38 +0100 Subject: [PATCH 23/29] chore: moving method from interface to implementation --- pumpkin-crates/core/src/propagation/domains.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pumpkin-crates/core/src/propagation/domains.rs b/pumpkin-crates/core/src/propagation/domains.rs index dc40a2196..a7a6203a5 100644 --- a/pumpkin-crates/core/src/propagation/domains.rs +++ b/pumpkin-crates/core/src/propagation/domains.rs @@ -59,9 +59,7 @@ pub trait ReadDomains { /// Returns whether the provided [`Literal`] is assigned (either true or false) or is /// currently unassigned. - fn evaluate_literal(&self, literal: Literal) -> Option { - self.evaluate_predicate(literal.get_true_predicate()) - } + fn evaluate_literal(&self, literal: Literal) -> Option; /// Returns the holes in the domain which were created on the current checkpoint. fn get_holes_at_current_checkpoint( @@ -148,6 +146,10 @@ impl ReadDomains for T { self.assignments().evaluate_predicate(predicate) } + fn evaluate_literal(&self, literal: Literal) -> Option { + self.evaluate_predicate(literal.get_true_predicate()) + } + fn get_holes_at_current_checkpoint( &self, var: &Var, From ee277af4374f3cf6b3d2da60a4b78fbc1bb6e9f6 Mon Sep 17 00:00:00 2001 From: Imko Marijnissen Date: Mon, 15 Dec 2025 13:22:15 +0100 Subject: [PATCH 24/29] docs: updating documentation propagator constructor --- pumpkin-crates/core/src/propagation/constructor.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/pumpkin-crates/core/src/propagation/constructor.rs b/pumpkin-crates/core/src/propagation/constructor.rs index c9ef02847..290f625fc 100644 --- a/pumpkin-crates/core/src/propagation/constructor.rs +++ b/pumpkin-crates/core/src/propagation/constructor.rs @@ -21,14 +21,17 @@ use crate::predicates::Predicate; use crate::proof::ConstraintTag; use crate::proof::InferenceCode; use crate::proof::InferenceLabel; +#[cfg(doc)] +use crate::propagation::DomainEvent; use crate::propagation::DomainEvents; use crate::variables::IntegerVariable; /// A propagator constructor creates a fully initialized instance of a [`Propagator`]. /// -/// The constructor is responsible for indicating on which events the propagator should be -/// enqueued. Additionally, the propagator can be initialized with values that come from the state -/// of the solver. +/// The constructor is responsible for: +/// 1) Indicating on which [`DomainEvent`]s the propagator should be enqueued (via the +/// [`PropagatorConstructorContext`]). +/// 2) Initialising the [`PropagatorConstructor::PropagatorImpl`] and its structures. pub trait PropagatorConstructor { /// The propagator that is produced by this constructor. type PropagatorImpl: Propagator + Clone; From 695b77477b2225976fb3acabea296b687c958a04 Mon Sep 17 00:00:00 2001 From: Imko Marijnissen Date: Mon, 15 Dec 2025 13:49:52 +0100 Subject: [PATCH 25/29] docs: update docs of priority --- pumpkin-crates/core/src/propagation/propagator.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pumpkin-crates/core/src/propagation/propagator.rs b/pumpkin-crates/core/src/propagation/propagator.rs index 510d331c2..b953204ce 100644 --- a/pumpkin-crates/core/src/propagation/propagator.rs +++ b/pumpkin-crates/core/src/propagation/propagator.rs @@ -161,8 +161,7 @@ pub trait Propagator: Downcast + DynClone { /// Returns the [`Priority`] of the propagator, used for determining the order in which /// propagators are called. /// - /// The intuition is that propagators with low computational complexity should be assigned a - /// high priority (i.e., should be propagated before computationally expensive propagators). + /// See [`Priority`] documentation for more explanation. /// /// By default the priority is set to [`Priority::VeryLowPriority`]. It is expected that /// propagator implementations would set this value to some appropriate value. @@ -220,7 +219,10 @@ pub enum EnqueueDecision { /// The priority of a propagator, used for determining the order in which propagators will be /// called. /// -/// The intuition is that propagators with low computational complexity should be assigned a high +/// Propagators with high priority are propagated before propagators with low(er) priority. If two +/// propagators have the same priority, then the order in which they are propagated is unspecified. +/// +/// Typically, propagators with low computational complexity should be assigned a high /// priority (i.e., should be propagated before computationally expensive propagators). #[derive(Default, Debug, Clone, Copy, Hash, PartialEq, Eq)] #[repr(u8)] From cf9fa18d9eb2995287d2cb8ddb2ec7cca8347971 Mon Sep 17 00:00:00 2001 From: Imko Marijnissen Date: Mon, 15 Dec 2025 13:51:34 +0100 Subject: [PATCH 26/29] chore: remove priority from name of priority enum variants --- .../core/src/engine/cp/propagator_queue.rs | 10 +++++----- pumpkin-crates/core/src/propagation/propagator.rs | 12 ++++++------ .../src/propagators/arithmetic/absolute_value.rs | 2 +- .../propagators/arithmetic/binary/binary_equals.rs | 2 +- .../arithmetic/binary/binary_not_equals.rs | 2 +- .../src/propagators/arithmetic/integer_division.rs | 2 +- .../propagators/arithmetic/integer_multiplication.rs | 2 +- .../propagators/arithmetic/linear_less_or_equal.rs | 2 +- .../src/propagators/arithmetic/linear_not_equal.rs | 2 +- .../core/src/propagators/arithmetic/maximum.rs | 2 +- .../time_table_over_interval_incremental.rs | 2 +- .../time_table_per_point_incremental.rs | 2 +- .../time_table/time_table_over_interval.rs | 2 +- .../cumulative/time_table/time_table_per_point.rs | 2 +- pumpkin-crates/core/src/propagators/element.rs | 2 +- .../src/propagators/nogoods/nogood_propagator.rs | 2 +- 16 files changed, 25 insertions(+), 25 deletions(-) diff --git a/pumpkin-crates/core/src/engine/cp/propagator_queue.rs b/pumpkin-crates/core/src/engine/cp/propagator_queue.rs index 6d877fd27..b39a40905 100644 --- a/pumpkin-crates/core/src/engine/cp/propagator_queue.rs +++ b/pumpkin-crates/core/src/engine/cp/propagator_queue.rs @@ -106,15 +106,15 @@ mod tests { fn test_ordering() { let mut queue = PropagatorQueue::default(); - queue.enqueue_propagator(PropagatorId(1), Priority::HighPriority); - queue.enqueue_propagator(PropagatorId(0), Priority::MediumPriority); - queue.enqueue_propagator(PropagatorId(3), Priority::VeryLowPriority); - queue.enqueue_propagator(PropagatorId(4), Priority::LowPriority); + queue.enqueue_propagator(PropagatorId(1), Priority::High); + queue.enqueue_propagator(PropagatorId(0), Priority::Medium); + queue.enqueue_propagator(PropagatorId(3), Priority::VeryLow); + queue.enqueue_propagator(PropagatorId(4), Priority::Low); assert_eq!(PropagatorId(1), queue.pop().unwrap()); assert_eq!(PropagatorId(0), queue.pop().unwrap()); - assert_eq!(PropagatorId(4), queue.pop().unwrap()); assert_eq!(PropagatorId(3), queue.pop().unwrap()); + assert_eq!(PropagatorId(4), queue.pop().unwrap()); assert_eq!(None, queue.pop()); } } diff --git a/pumpkin-crates/core/src/propagation/propagator.rs b/pumpkin-crates/core/src/propagation/propagator.rs index b953204ce..85f2ed389 100644 --- a/pumpkin-crates/core/src/propagation/propagator.rs +++ b/pumpkin-crates/core/src/propagation/propagator.rs @@ -163,10 +163,10 @@ pub trait Propagator: Downcast + DynClone { /// /// See [`Priority`] documentation for more explanation. /// - /// By default the priority is set to [`Priority::VeryLowPriority`]. It is expected that + /// By default the priority is set to [`Priority::VeryLow`]. It is expected that /// propagator implementations would set this value to some appropriate value. fn priority(&self) -> Priority { - Priority::VeryLowPriority + Priority::VeryLow } /// A function which returns [`Some`] with a [`PropagatorConflict`] when this propagator can @@ -227,11 +227,11 @@ pub enum EnqueueDecision { #[derive(Default, Debug, Clone, Copy, Hash, PartialEq, Eq)] #[repr(u8)] pub enum Priority { - HighPriority = 0, - MediumPriority = 1, - LowPriority = 2, + High = 0, + Medium = 1, + Low = 2, #[default] - VeryLowPriority = 3, + VeryLow = 3, } impl PartialOrd for Priority { diff --git a/pumpkin-crates/core/src/propagators/arithmetic/absolute_value.rs b/pumpkin-crates/core/src/propagators/arithmetic/absolute_value.rs index 2a75e5219..f7cb232cf 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/absolute_value.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/absolute_value.rs @@ -67,7 +67,7 @@ where VB: IntegerVariable + 'static, { fn priority(&self) -> Priority { - Priority::HighPriority + Priority::High } fn name(&self) -> &str { diff --git a/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_equals.rs b/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_equals.rs index 3857179a5..e2e1b867a 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_equals.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_equals.rs @@ -216,7 +216,7 @@ where } fn priority(&self) -> Priority { - Priority::HighPriority + Priority::High } fn name(&self) -> &str { diff --git a/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_not_equals.rs b/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_not_equals.rs index 3d9a42486..43298ea1e 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_not_equals.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/binary/binary_not_equals.rs @@ -89,7 +89,7 @@ where } fn priority(&self) -> Priority { - Priority::HighPriority + Priority::High } fn name(&self) -> &str { diff --git a/pumpkin-crates/core/src/propagators/arithmetic/integer_division.rs b/pumpkin-crates/core/src/propagators/arithmetic/integer_division.rs index 5bb583621..33e308e71 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/integer_division.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/integer_division.rs @@ -87,7 +87,7 @@ where VC: IntegerVariable, { fn priority(&self) -> Priority { - Priority::HighPriority + Priority::High } fn name(&self) -> &str { diff --git a/pumpkin-crates/core/src/propagators/arithmetic/integer_multiplication.rs b/pumpkin-crates/core/src/propagators/arithmetic/integer_multiplication.rs index 391a7d996..1bacc65b7 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/integer_multiplication.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/integer_multiplication.rs @@ -79,7 +79,7 @@ where VC: IntegerVariable, { fn priority(&self) -> Priority { - Priority::HighPriority + Priority::High } fn name(&self) -> &str { diff --git a/pumpkin-crates/core/src/propagators/arithmetic/linear_less_or_equal.rs b/pumpkin-crates/core/src/propagators/arithmetic/linear_less_or_equal.rs index f419fb470..348470731 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/linear_less_or_equal.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/linear_less_or_equal.rs @@ -140,7 +140,7 @@ where } fn priority(&self) -> Priority { - Priority::HighPriority + Priority::High } fn name(&self) -> &str { diff --git a/pumpkin-crates/core/src/propagators/arithmetic/linear_not_equal.rs b/pumpkin-crates/core/src/propagators/arithmetic/linear_not_equal.rs index aa5196846..9e3f26abb 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/linear_not_equal.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/linear_not_equal.rs @@ -108,7 +108,7 @@ where Var: IntegerVariable + 'static, { fn priority(&self) -> Priority { - Priority::HighPriority + Priority::High } fn name(&self) -> &str { diff --git a/pumpkin-crates/core/src/propagators/arithmetic/maximum.rs b/pumpkin-crates/core/src/propagators/arithmetic/maximum.rs index c44368893..ad71bb01a 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/maximum.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/maximum.rs @@ -71,7 +71,7 @@ impl Prop for MaximumPropagator { fn priority(&self) -> Priority { - Priority::HighPriority + Priority::High } fn name(&self) -> &str { diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/time_table_over_interval_incremental.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/time_table_over_interval_incremental.rs index aa8e25650..522c04179 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/time_table_over_interval_incremental.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/time_table_over_interval_incremental.rs @@ -509,7 +509,7 @@ impl Propagator } fn priority(&self) -> Priority { - Priority::VeryLowPriority + Priority::VeryLow } fn name(&self) -> &str { diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/time_table_per_point_incremental.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/time_table_per_point_incremental.rs index 2c5f12348..b717db86f 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/time_table_per_point_incremental.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/time_table_per_point_incremental.rs @@ -534,7 +534,7 @@ impl Propagator } fn priority(&self) -> Priority { - Priority::VeryLowPriority + Priority::VeryLow } fn name(&self) -> &str { diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_over_interval.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_over_interval.rs index d39b39b59..3e25450f0 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_over_interval.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_over_interval.rs @@ -185,7 +185,7 @@ impl Propagator for TimeTableOverIntervalPropaga } fn priority(&self) -> Priority { - Priority::VeryLowPriority + Priority::VeryLow } fn name(&self) -> &str { diff --git a/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_per_point.rs b/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_per_point.rs index bc4953f76..d555ba75f 100644 --- a/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_per_point.rs +++ b/pumpkin-crates/core/src/propagators/cumulative/time_table/time_table_per_point.rs @@ -178,7 +178,7 @@ impl Propagator for TimeTablePerPointPropagator< } fn priority(&self) -> Priority { - Priority::VeryLowPriority + Priority::VeryLow } fn name(&self) -> &str { diff --git a/pumpkin-crates/core/src/propagators/element.rs b/pumpkin-crates/core/src/propagators/element.rs index 2eb05f8ca..351a423ea 100644 --- a/pumpkin-crates/core/src/propagators/element.rs +++ b/pumpkin-crates/core/src/propagators/element.rs @@ -97,7 +97,7 @@ where VE: IntegerVariable + 'static, { fn priority(&self) -> Priority { - Priority::LowPriority + Priority::Low } fn name(&self) -> &str { diff --git a/pumpkin-crates/core/src/propagators/nogoods/nogood_propagator.rs b/pumpkin-crates/core/src/propagators/nogoods/nogood_propagator.rs index ea9a75bdb..7cfe1cfbb 100644 --- a/pumpkin-crates/core/src/propagators/nogoods/nogood_propagator.rs +++ b/pumpkin-crates/core/src/propagators/nogoods/nogood_propagator.rs @@ -201,7 +201,7 @@ impl Propagator for NogoodPropagator { } fn priority(&self) -> Priority { - Priority::HighPriority + Priority::High } fn notify_predicate_id_satisfied(&mut self, predicate_id: PredicateId) -> EnqueueDecision { From cb179de7c831ea50ccbeddc08721e021dad27367 Mon Sep 17 00:00:00 2001 From: Imko Marijnissen Date: Mon, 15 Dec 2025 13:56:32 +0100 Subject: [PATCH 27/29] chore: rename methods for trailed integers + remove --- .../src/engine/cp/trailed/trailed_values.rs | 1 + pumpkin-crates/core/src/propagation/domains.rs | 16 ++++------------ .../arithmetic/linear_less_or_equal.rs | 17 ++++++++++------- 3 files changed, 15 insertions(+), 19 deletions(-) diff --git a/pumpkin-crates/core/src/engine/cp/trailed/trailed_values.rs b/pumpkin-crates/core/src/engine/cp/trailed/trailed_values.rs index 665719ca5..e2695b522 100644 --- a/pumpkin-crates/core/src/engine/cp/trailed/trailed_values.rs +++ b/pumpkin-crates/core/src/engine/cp/trailed/trailed_values.rs @@ -41,6 +41,7 @@ impl TrailedValues { self.values[trailed_integer] = value; } + #[cfg(test)] pub(crate) fn add_assign(&mut self, trailed_integer: TrailedInteger, addition: i64) { self.write(trailed_integer, self.values[trailed_integer] + addition); } diff --git a/pumpkin-crates/core/src/propagation/domains.rs b/pumpkin-crates/core/src/propagation/domains.rs index a7a6203a5..1f67c341d 100644 --- a/pumpkin-crates/core/src/propagation/domains.rs +++ b/pumpkin-crates/core/src/propagation/domains.rs @@ -129,16 +129,13 @@ pub trait ReadDomains { fn get_checkpoint_for_predicate(&self, predicate: Predicate) -> Option; /// Returns the current value of the provided [`TrailedInteger`]. - fn value_trailed_integer(&self, trailed_integer: TrailedInteger) -> i64; + fn read_trailed_integer(&self, trailed_integer: TrailedInteger) -> i64; /// Creates a new [`TrailedInteger`] assigned to the provided `initial_value`. fn new_trailed_integer(&mut self, initial_value: i64) -> TrailedInteger; - /// Adds `addition` to the value of the provided [`TrailedInteger`]. - fn add_assign_trailed_integer(&mut self, trailed_integer: TrailedInteger, addition: i64); - /// Assigns the provided [`TrailedInteger`] to the provided `value`. - fn assign_trailed_integer(&mut self, trailed_integer: TrailedInteger, value: i64); + fn write_trailed_integer(&mut self, trailed_integer: TrailedInteger, value: i64); } impl ReadDomains for T { @@ -214,7 +211,7 @@ impl ReadDomains for T { self.assignments().get_checkpoint_for_predicate(&predicate) } - fn value_trailed_integer(&self, trailed_integer: TrailedInteger) -> i64 { + fn read_trailed_integer(&self, trailed_integer: TrailedInteger) -> i64 { self.trailed_values().read(trailed_integer) } @@ -222,12 +219,7 @@ impl ReadDomains for T { self.trailed_values_mut().grow(initial_value) } - fn add_assign_trailed_integer(&mut self, trailed_integer: TrailedInteger, addition: i64) { - self.trailed_values_mut() - .add_assign(trailed_integer, addition); - } - - fn assign_trailed_integer(&mut self, trailed_integer: TrailedInteger, value: i64) { + fn write_trailed_integer(&mut self, trailed_integer: TrailedInteger, value: i64) { self.trailed_values_mut().assign(trailed_integer, value); } } diff --git a/pumpkin-crates/core/src/propagators/arithmetic/linear_less_or_equal.rs b/pumpkin-crates/core/src/propagators/arithmetic/linear_less_or_equal.rs index 348470731..5eefca4ee 100644 --- a/pumpkin-crates/core/src/propagators/arithmetic/linear_less_or_equal.rs +++ b/pumpkin-crates/core/src/propagators/arithmetic/linear_less_or_equal.rs @@ -109,7 +109,7 @@ where Var: IntegerVariable, { fn detect_inconsistency(&self, domains: Domains) -> Option { - if (self.c as i64) < domains.value_trailed_integer(self.lower_bound_left_hand_side) { + if (self.c as i64) < domains.read_trailed_integer(self.lower_bound_left_hand_side) { Some(self.create_conflict(domains)) } else { None @@ -125,7 +125,7 @@ where let index = local_id.unpack() as usize; let x_i = &self.x[index]; - let old_bound = context.value_trailed_integer(self.current_bounds[index]); + let old_bound = context.read_trailed_integer(self.current_bounds[index]); let new_bound = context.lower_bound(x_i) as i64; pumpkin_assert_simple!( @@ -133,8 +133,11 @@ where "propagator should only be triggered when lower bounds are tightened, old_bound={old_bound}, new_bound={new_bound}" ); - context.add_assign_trailed_integer(self.lower_bound_left_hand_side, new_bound - old_bound); - context.assign_trailed_integer(self.current_bounds[index], new_bound); + context.write_trailed_integer( + self.lower_bound_left_hand_side, + context.read_trailed_integer(self.lower_bound_left_hand_side) + (new_bound - old_bound), + ); + context.write_trailed_integer(self.current_bounds[index], new_bound); EnqueueDecision::Enqueue } @@ -173,12 +176,12 @@ where } let lower_bound_left_hand_side = match TryInto::::try_into( - context.value_trailed_integer(self.lower_bound_left_hand_side), + context.read_trailed_integer(self.lower_bound_left_hand_side), ) { Ok(bound) => bound, Err(_) if context - .value_trailed_integer(self.lower_bound_left_hand_side) + .read_trailed_integer(self.lower_bound_left_hand_side) .is_positive() => { // We cannot fit the `lower_bound_left_hand_side` into an i32 due to an @@ -222,7 +225,7 @@ where Ok(bound) => bound, Err(_) if context - .value_trailed_integer(self.lower_bound_left_hand_side) + .read_trailed_integer(self.lower_bound_left_hand_side) .is_positive() => { // We cannot fit the `lower_bound_left_hand_side` into an i32 due to an From 9281c92e352ea874e584dc6dfbb58fd6a23bf62d Mon Sep 17 00:00:00 2001 From: Imko Marijnissen Date: Mon, 15 Dec 2025 13:58:34 +0100 Subject: [PATCH 28/29] chore: replace with use --- .../core/src/propagation/contexts/explanation_context.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pumpkin-crates/core/src/propagation/contexts/explanation_context.rs b/pumpkin-crates/core/src/propagation/contexts/explanation_context.rs index 85f2c398e..e69fb5409 100644 --- a/pumpkin-crates/core/src/propagation/contexts/explanation_context.rs +++ b/pumpkin-crates/core/src/propagation/contexts/explanation_context.rs @@ -4,6 +4,7 @@ use crate::basic_types::PredicateId; use crate::basic_types::PredicateIdGenerator; use crate::containers::KeyValueHeap; use crate::engine::Assignments; +use crate::engine::TrailedValues; use crate::engine::notifications::NotificationEngine; use crate::predicates::Predicate; use crate::propagation::HasAssignments; @@ -89,11 +90,11 @@ impl HasAssignments for ExplanationContext<'_> { self.assignments } - fn trailed_values(&self) -> &crate::engine::TrailedValues { + fn trailed_values(&self) -> &TrailedValues { unimplemented!("Currently, this information cannot be retrieved using this structure") } - fn trailed_values_mut(&mut self) -> &mut crate::engine::TrailedValues { + fn trailed_values_mut(&mut self) -> &mut TrailedValues { unimplemented!("Currently, this information cannot be retrieved using this structure") } } From 1cd79b9778178420556700a20f56163056aead67 Mon Sep 17 00:00:00 2001 From: Imko Marijnissen Date: Mon, 15 Dec 2025 14:05:15 +0100 Subject: [PATCH 29/29] fix: fix test case propagator queue --- pumpkin-crates/core/src/engine/cp/propagator_queue.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pumpkin-crates/core/src/engine/cp/propagator_queue.rs b/pumpkin-crates/core/src/engine/cp/propagator_queue.rs index b39a40905..f11456dfe 100644 --- a/pumpkin-crates/core/src/engine/cp/propagator_queue.rs +++ b/pumpkin-crates/core/src/engine/cp/propagator_queue.rs @@ -113,8 +113,8 @@ mod tests { assert_eq!(PropagatorId(1), queue.pop().unwrap()); assert_eq!(PropagatorId(0), queue.pop().unwrap()); - assert_eq!(PropagatorId(3), queue.pop().unwrap()); assert_eq!(PropagatorId(4), queue.pop().unwrap()); + assert_eq!(PropagatorId(3), queue.pop().unwrap()); assert_eq!(None, queue.pop()); } }