problemreductions/rules/
hamiltoniancircuit_stackercrane.rs1use crate::models::decision::Decision;
16use crate::models::graph::HamiltonianCircuit;
17use crate::models::misc::StackerCrane;
18use crate::reduction;
19use crate::rules::traits::{ReduceTo, ReductionResult};
20use crate::topology::{Graph, SimpleGraph};
21
22#[derive(Debug, Clone)]
24pub struct ReductionHamiltonianCircuitToStackerCrane {
25 target: Decision<StackerCrane>,
26}
27
28impl ReductionResult for ReductionHamiltonianCircuitToStackerCrane {
29 type Source = HamiltonianCircuit<SimpleGraph>;
30 type Target = Decision<StackerCrane>;
31
32 fn target_problem(&self) -> &Self::Target {
33 &self.target
34 }
35
36 fn extract_solution(
37 &self,
38 target_solution: &<Self::Target as crate::traits::Problem>::Solution,
39 ) -> crate::rules::ExtractionResult<<Self::Source as crate::traits::Problem>::Solution> {
40 crate::rules::traits::validate_target_witness(
41 self.target_problem(),
42 target_solution,
43 |value| value.0,
44 "target tour does not certify a Hamiltonian circuit",
45 )?;
46 Ok(target_solution.to_vec())
48 }
49}
50
51#[crate::aggregate_reduction(identity)]
52impl crate::rules::AggregateReductionResult for ReductionHamiltonianCircuitToStackerCrane {}
53
54#[reduction(
55 transform = exact {
56 num_vertices = "2 * num_vertices",
57 num_arcs = "num_vertices",
58 num_edges = "2 * num_edges",
59 }
60)]
61impl ReduceTo<Decision<StackerCrane>> for HamiltonianCircuit<SimpleGraph> {
62 type Result = ReductionHamiltonianCircuitToStackerCrane;
63
64 fn reduce_to(&self) -> Result<Self::Result, crate::rules::ReductionError> {
65 let n = self.num_vertices();
66
67 let (target_num_vertices, target_num_edges) = split_graph_dimensions(n, self.num_edges())?;
69
70 let arcs: Vec<(usize, usize)> = (0..n).map(|i| (2 * i, 2 * i + 1)).collect();
72 let arc_lengths: Vec<i64> = vec![1; n];
73
74 let mut edges = Vec::with_capacity(target_num_edges);
80 let mut edge_lengths = Vec::with_capacity(target_num_edges);
81 for (u, v) in self.graph().edges() {
82 edges.push((2 * u + 1, 2 * v));
83 edge_lengths.push(1);
84 edges.push((2 * v + 1, 2 * u));
85 edge_lengths.push(1);
86 }
87
88 let target =
89 StackerCrane::try_new(target_num_vertices, arcs, edges, arc_lengths, edge_lengths)
90 .map_err(<Self as ReduceTo<Decision<StackerCrane>>>::target_construction)?;
91
92 Ok(ReductionHamiltonianCircuitToStackerCrane {
93 target: Decision::new(
94 target,
95 if n < 3 {
96 -1
97 } else {
98 <Self as ReduceTo<Decision<StackerCrane>>>::exact_i64(
99 target_num_vertices,
100 "encoding the route bound",
101 )?
102 },
103 ),
104 })
105 }
106}
107
108fn split_graph_dimensions(
110 n: usize,
111 m: usize,
112) -> Result<(usize, usize), crate::rules::ReductionError> {
113 type Source = HamiltonianCircuit<SimpleGraph>;
114 let overflow = || {
115 crate::rules::ReductionError::integer_overflow::<Source, Decision<StackerCrane>>(
116 "encoding split graph dimensions and route costs",
117 )
118 };
119 let vertices = n.checked_mul(2).ok_or_else(overflow)?;
120 let edges = m.checked_mul(2).ok_or_else(overflow)?;
121 let cost_bound = n.checked_mul(vertices).ok_or_else(overflow)?;
124 <Source as ReduceTo<Decision<StackerCrane>>>::exact_i64(
125 cost_bound,
126 "bounding split graph route costs",
127 )?;
128 Ok((vertices, edges))
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
135 vec![crate::example_db::specs::RuleExampleSpec {
136 id: "hamiltoniancircuit_to_stackercrane",
137 build: || {
138 let source = HamiltonianCircuit::new(SimpleGraph::cycle(4));
139 crate::example_db::specs::rule_example_with_witness::<_, Decision<StackerCrane>>(
140 source,
141 SolutionPair {
142 source_config: serde_json::json!(vec![0, 1, 2, 3]),
143 target_config: serde_json::json!(vec![0, 1, 2, 3]),
144 },
145 )
146 },
147 }]
148}
149
150#[cfg(test)]
151#[path = "../unit_tests/rules/hamiltoniancircuit_stackercrane.rs"]
152mod tests;