problemreductions/rules/
pathconstrainednetworkflow_ilp.rs1use crate::models::algebraic::{LinearConstraint, ObjectiveSense, ILP};
7use crate::models::graph::PathConstrainedNetworkFlow;
8use crate::reduction;
9use crate::rules::traits::{ReduceTo, ReductionResult};
10
11#[derive(Debug, Clone)]
13pub struct ReductionPCNFToILP {
14 target: ILP<i64>,
15}
16
17impl ReductionResult for ReductionPCNFToILP {
18 type Source = PathConstrainedNetworkFlow;
19 type Target = ILP<i64>;
20
21 fn target_problem(&self) -> &ILP<i64> {
22 &self.target
23 }
24
25 fn extract_solution(
26 &self,
27 target_solution: &<Self::Target as crate::traits::Problem>::Solution,
28 ) -> crate::rules::ExtractionResult<<Self::Source as crate::traits::Problem>::Solution> {
29 crate::rules::traits::validate_target_solution(self.target_problem(), target_solution)?;
30
31 crate::rules::ilp_helpers::decode_usize_values(target_solution)
32 }
33}
34
35#[reduction(
36 transform = exact {
37 num_vars = "num_paths",
38 num_constraints = "num_arcs + 1",
39 },
40 unavailable = {
41 num_nonzeros = "the exact target parameter is not represented by this reduction's symbolic transform",
42 }
43)]
44impl ReduceTo<ILP<i64>> for PathConstrainedNetworkFlow {
45 type Result = ReductionPCNFToILP;
46
47 fn reduce_to(&self) -> Result<Self::Result, crate::rules::ReductionError> {
48 let num_paths = self.num_paths();
49 let num_arcs = self.num_arcs();
50 let mut constraints = Vec::new();
51
52 for arc_idx in 0..num_arcs {
54 let terms: Vec<(usize, i64)> = self
55 .paths()
56 .iter()
57 .enumerate()
58 .filter(|(_, path)| path.contains(&arc_idx))
59 .map(|(path_idx, _)| (path_idx, 1))
60 .collect();
61 if !terms.is_empty() {
62 constraints.push(LinearConstraint::le(terms, self.capacities()[arc_idx]));
63 }
64 }
65
66 let total_terms: Vec<(usize, i64)> = (0..num_paths).map(|i| (i, 1)).collect();
68 constraints.push(LinearConstraint::ge(total_terms, self.requirement()));
69
70 Ok(ReductionPCNFToILP {
71 target: ILP::new(num_paths, constraints, vec![], ObjectiveSense::Minimize)
72 .map_err(Self::target_construction)?,
73 })
74 }
75}
76
77#[cfg(feature = "example-db")]
78pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
79 use crate::topology::DirectedGraph;
80
81 vec![crate::example_db::specs::RuleExampleSpec {
82 id: "pathconstrainednetworkflow_to_ilp",
83 build: || {
84 let source = PathConstrainedNetworkFlow::new(
87 DirectedGraph::new(3, vec![(0, 1), (1, 2), (0, 2)]),
88 vec![1, 1, 1],
89 0,
90 2,
91 vec![vec![0, 1], vec![2]],
92 2,
93 );
94 crate::example_db::specs::rule_example_via_ilp::<_, i64>(source)
95 },
96 }]
97}
98
99#[cfg(test)]
100#[path = "../unit_tests/rules/pathconstrainednetworkflow_ilp.rs"]
101mod tests;