problemreductions/rules/
setsplitting_betweenness.rs1use crate::models::misc::Betweenness;
11use crate::models::set::SetSplitting;
12use crate::reduction;
13use crate::rules::traits::{ReduceTo, ReductionResult};
14
15#[derive(Debug, Clone)]
17pub struct ReductionSetSplittingToBetweenness {
18 target: Betweenness,
19 source_universe_size: usize,
20 pole: usize,
21}
22
23impl ReductionResult for ReductionSetSplittingToBetweenness {
24 type Source = SetSplitting;
25 type Target = Betweenness;
26
27 fn target_problem(&self) -> &Self::Target {
28 &self.target
29 }
30
31 fn extract_solution(&self, target_solution: &[usize]) -> Vec<usize> {
32 assert!(
33 target_solution.len() > self.pole,
34 "Betweenness solution has {} positions but pole index is {}",
35 target_solution.len(),
36 self.pole
37 );
38 assert!(
39 target_solution.len() >= self.source_universe_size,
40 "Betweenness solution has {} positions but source requires {} elements",
41 target_solution.len(),
42 self.source_universe_size
43 );
44
45 let pole_position = target_solution[self.pole];
46 target_solution[..self.source_universe_size]
47 .iter()
48 .map(|&position| usize::from(position > pole_position))
49 .collect()
50 }
51}
52
53#[reduction(
54 overhead = {
55 num_elements = "normalized_universe_size + 1 + normalized_num_size3_subsets",
56 num_triples = "normalized_num_size2_subsets + 2 * normalized_num_size3_subsets",
57 }
58)]
59impl ReduceTo<Betweenness> for SetSplitting {
60 type Result = ReductionSetSplittingToBetweenness;
61
62 fn reduce_to(&self) -> Self::Result {
63 let (normalized_universe_size, normalized_subsets) = self.normalized_instance();
64 let pole = normalized_universe_size;
65 let size3_subsets = normalized_subsets
66 .iter()
67 .filter(|subset| subset.len() == 3)
68 .count();
69 let mut triples = Vec::with_capacity(normalized_subsets.len() + size3_subsets);
70 let mut num_elements = normalized_universe_size + 1;
71
72 for subset in normalized_subsets {
73 match subset.as_slice() {
74 [u, v] => triples.push((*u, pole, *v)),
75 [u, v, w] => {
76 let auxiliary = num_elements;
77 num_elements += 1;
78 triples.push((*u, auxiliary, *v));
79 triples.push((auxiliary, pole, *w));
80 }
81 _ => unreachable!("normalization only produces size-2 or size-3 subsets"),
82 }
83 }
84
85 ReductionSetSplittingToBetweenness {
86 target: Betweenness::new(num_elements, triples),
87 source_universe_size: self.universe_size(),
88 pole,
89 }
90 }
91}
92
93#[cfg(feature = "example-db")]
94pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
95 use crate::export::SolutionPair;
96
97 vec![crate::example_db::specs::RuleExampleSpec {
98 id: "setsplitting_to_betweenness",
99 build: || {
100 crate::example_db::specs::rule_example_with_witness::<_, Betweenness>(
101 SetSplitting::new(
102 5,
103 vec![vec![0, 1, 2], vec![2, 3, 4], vec![0, 3, 4], vec![1, 2, 3]],
104 ),
105 SolutionPair {
106 source_config: vec![1, 0, 1, 0, 0],
107 target_config: vec![8, 2, 9, 0, 1, 4, 3, 6, 7, 5],
108 },
109 )
110 },
111 }]
112}
113
114#[cfg(test)]
115#[path = "../unit_tests/rules/setsplitting_betweenness.rs"]
116mod tests;