problemreductions/models/graph/
minimum_graph_bandwidth.rs1use crate::registry::{FieldInfo, ProblemSchemaEntry, VariantDimension};
8use crate::topology::{Graph, SimpleGraph};
9use crate::traits::Problem;
10use crate::types::Min;
11use serde::{Deserialize, Serialize};
12
13inventory::submit! {
14 ProblemSchemaEntry {
15 name: "MinimumGraphBandwidth",
16 display_name: "Minimum Graph Bandwidth",
17 aliases: &["MGB"],
18 dimensions: &[
19 VariantDimension::new("graph", "SimpleGraph", &["SimpleGraph"]),
20 ],
21 category: crate::registry::ProblemCategory::Graph,
22 module_path: module_path!(),
23 description: "Find a vertex ordering minimizing the maximum edge stretch",
24 fields: &[
25 FieldInfo { name: "graph", type_name: "G", description: "The undirected graph G=(V,E)" },
26 ],
27 }
28}
29
30#[derive(Debug, Clone, Serialize, Deserialize)]
62#[serde(bound(deserialize = "G: serde::Deserialize<'de>"))]
63pub struct MinimumGraphBandwidth<G> {
64 graph: G,
66}
67
68impl<G: Graph> MinimumGraphBandwidth<G> {
69 pub fn new(graph: G) -> Self {
74 Self { graph }
75 }
76
77 pub fn graph(&self) -> &G {
79 &self.graph
80 }
81
82 pub fn num_vertices(&self) -> usize {
84 self.graph.num_vertices()
85 }
86
87 pub fn num_edges(&self) -> usize {
89 self.graph.num_edges()
90 }
91
92 fn is_valid_permutation(&self, config: &[usize]) -> bool {
94 let n = self.graph.num_vertices();
95 if config.len() != n {
96 return false;
97 }
98 let mut seen = vec![false; n];
99 for &pos in config {
100 if pos >= n || seen[pos] {
101 return false;
102 }
103 seen[pos] = true;
104 }
105 true
106 }
107
108 pub fn bandwidth(
112 &self,
113 config: &[usize],
114 ) -> Result<Option<i64>, crate::traits::EvaluationError> {
115 if !self.is_valid_permutation(config) {
116 return Ok(None);
117 }
118 let mut max_stretch = 0usize;
119 for (u, v) in self.graph.edges() {
120 let stretch = config[u].abs_diff(config[v]);
121 max_stretch = max_stretch.max(stretch);
122 }
123 Ok(Some(i64::try_from(max_stretch).map_err(|_| {
124 crate::traits::EvaluationError::IntegerOverflow(
125 "converting graph bandwidth to i64".to_string(),
126 )
127 })?))
128 }
129}
130
131impl<G> Problem for MinimumGraphBandwidth<G>
132where
133 G: Graph + crate::variant::VariantParam,
134{
135 const NAME: &'static str = "MinimumGraphBandwidth";
136 type Solution = Vec<usize>;
137 type Value = Min<i64>;
138
139 crate::problem_parameters![("num_edges", num_edges), ("num_vertices", num_vertices),];
140
141 fn variant() -> Vec<(&'static str, &'static str)> {
142 crate::variant_params![G]
143 }
144
145 fn evaluate(
146 &self,
147 config: &Self::Solution,
148 ) -> Result<Min<i64>, crate::traits::EvaluationError> {
149 let n = self.graph.num_vertices();
150 if config.len() != n {
151 return Err(crate::traits::EvaluationError::InvalidConfiguration(
152 "vertex ordering length does not match the graph".into(),
153 ));
154 }
155 if config.iter().any(|&position| position >= n) {
156 return Err(crate::traits::EvaluationError::InvalidConfiguration(
157 "vertex ordering contains an out-of-range position".into(),
158 ));
159 }
160 Ok({
161 match self.bandwidth(config)? {
162 Some(bw) => Min(Some(bw)),
163 None => Min(None),
164 }
165 })
166 }
167}
168
169impl<G> crate::solvers::BruteForceProblem for MinimumGraphBandwidth<G>
170where
171 G: Graph + crate::variant::VariantParam,
172{
173 fn dimensions(&self) -> Vec<usize> {
174 let n = self.graph.num_vertices();
175 vec![n; n]
176 }
177}
178
179crate::declare_variants! {
180 default MinimumGraphBandwidth<SimpleGraph> => "factorial(num_vertices)",
181}
182
183crate::register_brute_force! {
184 MinimumGraphBandwidth<SimpleGraph>,
185}
186
187#[cfg(feature = "example-db")]
188pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
189 use crate::topology::SimpleGraph;
190 vec![crate::example_db::specs::ModelExampleSpec {
196 id: "minimum_graph_bandwidth",
197 instance: Box::new(MinimumGraphBandwidth::new(SimpleGraph::new(
198 4,
199 vec![(0, 1), (0, 2), (0, 3)],
200 ))),
201 optimal_config: serde_json::json!(vec![1, 0, 2, 3]),
202 optimal_value: serde_json::json!(2),
203 }]
204}
205
206#[cfg(test)]
207#[path = "../../unit_tests/models/graph/minimum_graph_bandwidth.rs"]
208mod tests;