pumpkin_core/branching/variable_selection/
largest.rs1use log::warn;
2
3use crate::branching::brancher::BrancherEvent;
4use crate::branching::tie_breaking::Direction;
5use crate::branching::tie_breaking::InOrderTieBreaker;
6use crate::branching::tie_breaking::TieBreaker;
7use crate::branching::variable_selection::VariableSelector;
8use crate::branching::SelectionContext;
9use crate::engine::variables::DomainId;
10use crate::pumpkin_assert_eq_simple;
11
12pub struct Largest<Var, TieBreaking> {
18 variables: Vec<Var>,
19 tie_breaker: TieBreaking,
20}
21
22impl<Var, TieBreaking> std::fmt::Debug for Largest<Var, TieBreaking> {
23 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24 f.debug_struct("Largest").finish()
25 }
26}
27
28impl<Var: Clone + 'static> Largest<Var, InOrderTieBreaker<Var, i32>> {
29 pub fn new(variables: &[Var]) -> Self {
30 if variables.is_empty() {
31 warn!("The Largest variable selector was not provided with any variables");
32 return Largest {
33 variables: vec![],
34 tie_breaker: InOrderTieBreaker::new(Direction::Maximum),
35 };
36 }
37 Self {
38 variables: variables.to_vec(),
39 tie_breaker: InOrderTieBreaker::new(Direction::Maximum),
40 }
41 }
42}
43
44impl<Var: Clone + 'static, TieBreaking: TieBreaker<Var, i32>> Largest<Var, TieBreaking> {
45 pub fn with_tie_breaker(variables: &[Var], tie_breaker: TieBreaking) -> Self {
46 pumpkin_assert_eq_simple!(
47 tie_breaker.get_direction(),
48 Direction::Maximum,
49 "The provided tie-breaker to Largest attempts to find the Minimum value
50 instead of the Maximum value, please ensure that you have passed the correct tie-breaker");
51 if variables.is_empty() {
52 warn!("The Largest variable selector was not provided with any variables");
53 return Largest {
54 variables: vec![],
55 tie_breaker,
56 };
57 }
58
59 Self {
60 variables: variables.to_vec(),
61 tie_breaker,
62 }
63 }
64}
65
66impl<TieBreaking> VariableSelector<DomainId> for Largest<DomainId, TieBreaking>
67where
68 TieBreaking: TieBreaker<DomainId, i32>,
69{
70 fn select_variable(&mut self, context: &mut SelectionContext) -> Option<DomainId> {
71 self.variables
72 .iter()
73 .filter(|variable| !context.is_integer_fixed(**variable))
74 .for_each(|variable| {
75 self.tie_breaker
76 .consider(*variable, context.upper_bound(*variable));
77 });
78 self.tie_breaker.select()
79 }
80
81 fn subscribe_to_events(&self) -> Vec<BrancherEvent> {
82 vec![]
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89 use crate::basic_types::tests::TestRandom;
90 use crate::predicate;
91
92 #[test]
93 fn test_correctly_selected() {
94 let (mut assignments, mut notification_engine) =
95 SelectionContext::create_for_testing(vec![(0, 10), (5, 20)]);
96 let mut test_rng = TestRandom::default();
97 let integer_variables = assignments.get_domains().collect::<Vec<_>>();
98 let mut strategy = Largest::new(&integer_variables);
99
100 {
101 let mut context = SelectionContext::new(&assignments, &mut test_rng);
102
103 let selected = strategy.select_variable(&mut context);
104 assert!(selected.is_some());
105 assert_eq!(selected.unwrap(), integer_variables[1]);
106 }
107
108 let _ = assignments.post_predicate(
109 predicate!(integer_variables[1] <= 9),
110 None,
111 &mut notification_engine,
112 );
113
114 let mut context = SelectionContext::new(&assignments, &mut test_rng);
115
116 let selected = strategy.select_variable(&mut context);
117 assert!(selected.is_some());
118 assert_eq!(selected.unwrap(), integer_variables[0]);
119 }
120
121 #[test]
122 fn fixed_variables_are_not_selected() {
123 let (assignments, _) = SelectionContext::create_for_testing(vec![(10, 10), (20, 20)]);
124 let mut test_rng = TestRandom::default();
125 let mut context = SelectionContext::new(&assignments, &mut test_rng);
126 let integer_variables = context.get_domains().collect::<Vec<_>>();
127
128 let mut strategy = Largest::new(&integer_variables);
129 let selected = strategy.select_variable(&mut context);
130 assert!(selected.is_none());
131 }
132}