problemreductions/rules/
decisionmaximumindependentset_integralflowbundles.rs1use crate::models::decision::Decision;
9use crate::models::graph::{IntegralFlowBundles, MaximumIndependentSet};
10use crate::reduction;
11use crate::rules::traits::{ReduceTo, ReductionResult};
12use crate::topology::{Graph, SimpleGraph};
13use crate::types::One;
14
15#[derive(Debug, Clone)]
17pub struct ReductionDecisionMISToIFB {
18 target: IntegralFlowBundles,
19 num_source_vertices: usize,
20}
21
22impl ReductionResult for ReductionDecisionMISToIFB {
23 type Source = Decision<MaximumIndependentSet<SimpleGraph, One>>;
24 type Target = IntegralFlowBundles;
25
26 fn target_problem(&self) -> &Self::Target {
27 &self.target
28 }
29
30 fn extract_solution(
31 &self,
32 target_solution: &<Self::Target as crate::traits::Problem>::Solution,
33 ) -> crate::rules::ExtractionResult<<Self::Source as crate::traits::Problem>::Solution> {
34 crate::rules::traits::validate_target_witness(
35 self.target_problem(),
36 target_solution,
37 |feasible| feasible.0,
38 "target flow must satisfy conservation, bundle capacities, and the requirement",
39 )?;
40 Ok((0..self.num_source_vertices)
41 .map(|i| target_solution[2 * i + 1] == 1)
42 .collect())
43 }
44}
45
46fn flow_dimensions(
48 n: usize,
49 m: usize,
50) -> Result<(usize, usize, usize), crate::rules::ReductionError> {
51 n.checked_add(3)
52 .zip(n.checked_add(1).and_then(|count| count.checked_mul(2)))
53 .zip(n.checked_add(m).and_then(|count| count.checked_add(1)))
54 .map(|((vertices, arcs), bundles)| (vertices, arcs, bundles))
55 .ok_or_else(|| {
56 crate::rules::ReductionError::integer_overflow::<
57 Decision<MaximumIndependentSet<SimpleGraph, One>>,
58 IntegralFlowBundles,
59 >("counting independent-set flow paths and bundles")
60 })
61}
62
63fn flow_requirement(n: usize, bound: i64) -> Result<i64, crate::rules::ReductionError> {
66 let n = <Decision<MaximumIndependentSet<SimpleGraph, One>> as ReduceTo<
67 IntegralFlowBundles,
68 >>::exact_i64(n, "converting the independent-set vertex count")?;
69 let maximum_requirement = n.checked_add(2).ok_or_else(|| {
70 crate::rules::ReductionError::integer_overflow::<
71 Decision<MaximumIndependentSet<SimpleGraph, One>>,
72 IntegralFlowBundles,
73 >("shifting the independent-set decision threshold")
74 })?;
75 Ok(bound.clamp(0, maximum_requirement - 1) + 1)
76}
77
78#[crate::aggregate_reduction(identity)]
79impl crate::rules::AggregateReductionResult for ReductionDecisionMISToIFB {}
80
81#[reduction(
82 transform = exact {
83 max_capacity_bits = "2",
84 num_vertices = "num_vertices + 3",
85 num_arcs = "2 * num_vertices + 2",
86 num_bundles = "num_edges + num_vertices + 1",
87 }
88)]
89impl ReduceTo<IntegralFlowBundles> for Decision<MaximumIndependentSet<SimpleGraph, One>> {
90 type Result = ReductionDecisionMISToIFB;
91
92 fn reduce_to(&self) -> Result<Self::Result, crate::rules::ReductionError> {
93 let graph = self.inner().graph();
94 let n = graph.num_vertices();
95 let (num_vertices, num_arcs, num_bundles) = flow_dimensions(n, graph.num_edges())?;
96 let requirement = flow_requirement(n, *self.bound())?;
97 let sink = n + 2;
98 let mut arcs = Vec::with_capacity(num_arcs);
99 for i in 0..=n {
101 arcs.push((0, i + 1));
102 arcs.push((i + 1, sink));
103 }
104 let mut bundles = Vec::with_capacity(num_bundles);
105 let mut capacities = Vec::with_capacity(num_bundles);
106 for (u, v) in graph.edges() {
109 bundles.push(vec![2 * u, 2 * v + 1]);
110 capacities.push(1);
111 }
112 for i in 0..=n {
113 bundles.push(vec![2 * i, 2 * i + 1]);
114 capacities.push(2);
115 }
116 let target = IntegralFlowBundles::new(
117 crate::topology::DirectedGraph::new(num_vertices, arcs),
118 0,
119 sink,
120 bundles,
121 capacities,
122 requirement,
123 );
124 Ok(ReductionDecisionMISToIFB {
125 target,
126 num_source_vertices: n,
127 })
128 }
129}
130
131#[cfg(feature = "example-db")]
132pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
133 use crate::export::SolutionPair;
134 use crate::solvers::BruteForce;
135 vec![crate::example_db::specs::RuleExampleSpec {
136 id: "decisionmaximumindependentset_to_integralflowbundles",
137 build: || {
138 let source = Decision::new(
139 MaximumIndependentSet::new(SimpleGraph::path(3), vec![One; 3]),
140 2,
141 );
142 let reduction = ReduceTo::<IntegralFlowBundles>::reduce_to(&source)
143 .expect("canonical reduction must succeed");
144 let target_witness = BruteForce::new()
145 .solve(reduction.target_problem())
146 .expect("canonical target evaluation must succeed")
147 .expect("the path has an independent set of size two");
148 let source_witness = reduction.extract_solution(&target_witness).unwrap();
149 crate::example_db::specs::assemble_rule_example(
150 &source,
151 reduction.target_problem(),
152 vec![SolutionPair {
153 source_config: serde_json::json!(source_witness),
154 target_config: serde_json::json!(target_witness),
155 }],
156 )
157 },
158 }]
159}
160
161#[cfg(test)]
162#[path = "../unit_tests/rules/decisionmaximumindependentset_integralflowbundles.rs"]
163mod tests;