pumpkin_core/branching/
selection_context.rs

1use std::fmt::Debug;
2
3use crate::basic_types::Random;
4#[cfg(doc)]
5use crate::branching::Brancher;
6#[cfg(test)]
7use crate::engine::notifications::NotificationEngine;
8use crate::engine::predicates::predicate::Predicate;
9#[cfg(doc)]
10use crate::engine::propagation::PropagationContext;
11use crate::engine::variables::DomainGeneratorIterator;
12#[cfg(doc)]
13use crate::engine::variables::DomainId;
14use crate::engine::variables::IntegerVariable;
15use crate::engine::Assignments;
16
17/// The context provided to the [`Brancher`],
18/// it allows the retrieval of domain values of variables and access to methods from a [`Random`]
19/// generator.
20#[derive(Debug)]
21pub struct SelectionContext<'a> {
22    assignments: &'a Assignments,
23    random_generator: &'a mut dyn Random,
24}
25
26impl<'a> SelectionContext<'a> {
27    pub fn new(assignments: &'a Assignments, rng: &'a mut dyn Random) -> Self {
28        SelectionContext {
29            assignments,
30            random_generator: rng,
31        }
32    }
33
34    pub fn are_all_variables_assigned(&self) -> bool {
35        self.assignments
36            .get_domains()
37            .all(|domain_id| self.assignments.is_domain_assigned(&domain_id))
38    }
39
40    /// Returns a random generator which can be used to generate random values (see [`Random`] for
41    /// more information).
42    pub fn random(&mut self) -> &mut dyn Random {
43        self.random_generator
44    }
45
46    /// Returns the difference between the upper-bound and the lower-bound of the provided
47    /// [`IntegerVariable`]. Note that this is different from the number of values which are in the
48    /// domain of `var` since this calculation does not take into account holes in the domain.
49    pub fn get_size_of_domain<Var: IntegerVariable>(&self, var: Var) -> i32 {
50        var.upper_bound(self.assignments) - var.lower_bound(self.assignments)
51    }
52
53    /// Returns the lower bound of the provided [`IntegerVariable`]
54    pub fn lower_bound<Var: IntegerVariable>(&self, var: Var) -> i32 {
55        var.lower_bound(self.assignments)
56    }
57
58    /// Returns the upper bound of the provided [`IntegerVariable`]
59    pub fn upper_bound<Var: IntegerVariable>(&self, var: Var) -> i32 {
60        var.upper_bound(self.assignments)
61    }
62
63    /// Determines whether the provided value is in the domain of the provided [`IntegerVariable`]
64    pub fn contains<Var: IntegerVariable>(&self, var: Var, value: i32) -> bool {
65        var.contains(self.assignments, value)
66    }
67
68    /// Determines whether the provided [`IntegerVariable`] has a unit domain (i.e. a domain of size
69    /// 1)
70    pub fn is_integer_fixed<Var: IntegerVariable>(&self, var: Var) -> bool {
71        self.lower_bound(var.clone()) == self.upper_bound(var)
72    }
73
74    pub fn is_predicate_assigned(&self, predicate: Predicate) -> bool {
75        self.assignments.evaluate_predicate(predicate).is_some()
76    }
77
78    /// Returns all currently defined [`DomainId`]s.
79    pub fn get_domains(&self) -> DomainGeneratorIterator {
80        self.assignments.get_domains()
81    }
82
83    #[cfg(test)]
84    /// Create an ['Assignments'] with the variables having the input bounds.
85    pub(crate) fn create_for_testing(
86        domains: Vec<(i32, i32)>,
87    ) -> (Assignments, NotificationEngine) {
88        let mut assignments = Assignments::default();
89        let mut notification_engine = NotificationEngine::default();
90
91        for (lower_bound, upper_bound) in domains {
92            _ = assignments.grow(lower_bound, upper_bound);
93            notification_engine.grow();
94        }
95
96        (assignments, notification_engine)
97    }
98}