Skip to main content

problemreductions/models/graph/
minimum_metric_dimension.rs

1//! Minimum Metric Dimension problem implementation.
2//!
3//! Given a graph G = (V, E), find a minimum resolving set — a smallest subset
4//! V' ⊆ V such that for all distinct u, v ∈ V, there exists w ∈ V' with
5//! d(u, w) ≠ d(v, w), where d denotes shortest-path distance.
6
7use crate::registry::{FieldInfo, ProblemSchemaEntry, VariantDimension};
8use crate::topology::{Graph, SimpleGraph};
9use crate::traits::Problem;
10use crate::types::Min;
11use serde::{Deserialize, Serialize};
12use std::collections::VecDeque;
13
14inventory::submit! {
15    ProblemSchemaEntry {
16        name: "MinimumMetricDimension",
17        display_name: "Minimum Metric Dimension",
18        aliases: &[],
19        dimensions: &[
20            VariantDimension::new("graph", "SimpleGraph", &["SimpleGraph"]),
21        ],
22        module_path: module_path!(),
23        description: "Find minimum resolving set of a graph",
24        fields: &[
25            FieldInfo { name: "graph", type_name: "G", description: "The underlying graph G=(V,E)" },
26        ],
27    }
28}
29
30/// Compute BFS shortest-path distances from a single source vertex.
31///
32/// Returns a vector where `dist[v]` is the shortest-path distance from
33/// `source` to `v`, or `usize::MAX` if `v` is unreachable.
34pub fn bfs_distances<G: Graph>(graph: &G, source: usize) -> Vec<usize> {
35    let n = graph.num_vertices();
36    let mut dist = vec![usize::MAX; n];
37    dist[source] = 0;
38    let mut queue = VecDeque::new();
39    queue.push_back(source);
40    while let Some(u) = queue.pop_front() {
41        for v in graph.neighbors(u) {
42            if dist[v] == usize::MAX {
43                dist[v] = dist[u] + 1;
44                queue.push_back(v);
45            }
46        }
47    }
48    dist
49}
50
51/// The Minimum Metric Dimension problem.
52///
53/// Given a graph G = (V, E), find a minimum-size resolving set V' ⊆ V such
54/// that for every pair of distinct vertices u, v ∈ V, there exists at least
55/// one vertex w ∈ V' with d(u, w) ≠ d(v, w).
56///
57/// # Type Parameters
58///
59/// * `G` - The graph type (e.g., `SimpleGraph`)
60///
61/// # Example
62///
63/// ```
64/// use problemreductions::models::graph::MinimumMetricDimension;
65/// use problemreductions::topology::SimpleGraph;
66/// use problemreductions::{Problem, Solver, BruteForce};
67///
68/// // House graph: vertices 0–4
69/// let graph = SimpleGraph::new(5, vec![(0, 1), (0, 2), (1, 3), (2, 3), (2, 4), (3, 4)]);
70/// let problem = MinimumMetricDimension::new(graph);
71///
72/// let solver = BruteForce::new();
73/// let solution = solver.find_witness(&problem).unwrap();
74/// let value = problem.evaluate(&solution);
75/// assert!(value.is_valid());
76/// ```
77#[derive(Debug, Clone, Serialize)]
78pub struct MinimumMetricDimension<G> {
79    /// The underlying graph.
80    graph: G,
81    /// Precomputed all-pairs shortest-path distances.
82    #[serde(skip)]
83    dist_matrix: Vec<Vec<usize>>,
84}
85
86impl<'de, G: Graph + Deserialize<'de>> Deserialize<'de> for MinimumMetricDimension<G> {
87    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
88    where
89        D: serde::Deserializer<'de>,
90    {
91        #[derive(Deserialize)]
92        struct Helper<G> {
93            graph: G,
94        }
95        let helper = Helper::<G>::deserialize(deserializer)?;
96        Ok(Self::new(helper.graph))
97    }
98}
99
100impl<G: Graph> MinimumMetricDimension<G> {
101    /// Create a MinimumMetricDimension problem from a graph.
102    pub fn new(graph: G) -> Self {
103        let n = graph.num_vertices();
104        let dist_matrix = (0..n).map(|v| bfs_distances(&graph, v)).collect();
105        Self { graph, dist_matrix }
106    }
107
108    /// Get a reference to the underlying graph.
109    pub fn graph(&self) -> &G {
110        &self.graph
111    }
112
113    /// Get the number of vertices in the underlying graph.
114    pub fn num_vertices(&self) -> usize {
115        self.graph.num_vertices()
116    }
117
118    /// Get the number of edges in the underlying graph.
119    pub fn num_edges(&self) -> usize {
120        self.graph.num_edges()
121    }
122
123    /// Check whether a configuration (binary vertex selection) forms a resolving set.
124    ///
125    /// A set S ⊆ V is resolving if for every pair of distinct vertices u, v ∈ V,
126    /// there exists some w ∈ S such that d(u, w) ≠ d(v, w).
127    pub fn is_resolving(&self, config: &[usize]) -> bool {
128        let n = self.graph.num_vertices();
129        let selected: Vec<usize> = (0..n).filter(|&i| config[i] == 1).collect();
130        if selected.is_empty() {
131            return false;
132        }
133
134        // Check that all pairs of distinct vertices have different distance vectors
135        // using precomputed all-pairs distances
136        for u in 0..n {
137            for v in (u + 1)..n {
138                let all_same = selected
139                    .iter()
140                    .all(|&w| self.dist_matrix[w][u] == self.dist_matrix[w][v]);
141                if all_same {
142                    return false;
143                }
144            }
145        }
146
147        true
148    }
149}
150
151impl<G> Problem for MinimumMetricDimension<G>
152where
153    G: Graph + crate::variant::VariantParam,
154{
155    const NAME: &'static str = "MinimumMetricDimension";
156    type Value = Min<usize>;
157
158    fn variant() -> Vec<(&'static str, &'static str)> {
159        crate::variant_params![G]
160    }
161
162    fn dims(&self) -> Vec<usize> {
163        vec![2; self.graph.num_vertices()]
164    }
165
166    fn evaluate(&self, config: &[usize]) -> Min<usize> {
167        if !self.is_resolving(config) {
168            return Min(None);
169        }
170        let count = config.iter().filter(|&&x| x == 1).count();
171        Min(Some(count))
172    }
173}
174
175crate::declare_variants! {
176    default MinimumMetricDimension<SimpleGraph> => "2^num_vertices",
177}
178
179#[cfg(feature = "example-db")]
180pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
181    vec![crate::example_db::specs::ModelExampleSpec {
182        id: "minimum_metric_dimension_simplegraph",
183        instance: Box::new(MinimumMetricDimension::new(SimpleGraph::new(
184            5,
185            vec![(0, 1), (0, 2), (1, 3), (2, 3), (2, 4), (3, 4)],
186        ))),
187        optimal_config: vec![1, 1, 0, 0, 0],
188        optimal_value: serde_json::json!(2),
189    }]
190}
191
192#[cfg(test)]
193#[path = "../../unit_tests/models/graph/minimum_metric_dimension.rs"]
194mod tests;