problemreductions/models/graph/
minimum_maximal_matching.rs1use crate::registry::{FieldInfo, ProblemSchemaEntry, VariantDimension};
7use crate::topology::{Graph, SimpleGraph};
8use crate::traits::Problem;
9use crate::types::Min;
10use serde::{Deserialize, Serialize};
11
12inventory::submit! {
13 ProblemSchemaEntry {
14 name: "MinimumMaximalMatching",
15 display_name: "Minimum Maximal Matching",
16 aliases: &[],
17 dimensions: &[
18 VariantDimension::new("graph", "SimpleGraph", &["SimpleGraph"]),
19 ],
20 module_path: module_path!(),
21 description: "Find a minimum-size matching that cannot be extended",
22 fields: &[
23 FieldInfo { name: "graph", type_name: "G", description: "The underlying graph G=(V,E)" },
24 ],
25 }
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize)]
57pub struct MinimumMaximalMatching<G> {
58 graph: G,
60}
61
62impl<G: Graph> MinimumMaximalMatching<G> {
63 pub fn new(graph: G) -> Self {
65 Self { graph }
66 }
67
68 pub fn graph(&self) -> &G {
70 &self.graph
71 }
72
73 pub fn num_vertices(&self) -> usize {
75 self.graph.num_vertices()
76 }
77
78 pub fn num_edges(&self) -> usize {
80 self.graph.num_edges()
81 }
82
83 pub fn is_valid_maximal_matching(&self, config: &[usize]) -> bool {
90 let edges = self.graph.edges();
91 let n = self.graph.num_vertices();
92
93 let mut vertex_used = vec![false; n];
95 for (idx, &sel) in config.iter().enumerate() {
96 if sel == 1 {
97 let (u, v) = edges[idx];
98 if vertex_used[u] || vertex_used[v] {
99 return false;
100 }
101 vertex_used[u] = true;
102 vertex_used[v] = true;
103 }
104 }
105
106 for (idx, &sel) in config.iter().enumerate() {
108 if sel == 0 {
109 let (u, v) = edges[idx];
110 if !vertex_used[u] && !vertex_used[v] {
112 return false;
113 }
114 }
115 }
116
117 true
118 }
119}
120
121impl<G> Problem for MinimumMaximalMatching<G>
122where
123 G: Graph + crate::variant::VariantParam,
124{
125 const NAME: &'static str = "MinimumMaximalMatching";
126 type Value = Min<usize>;
127
128 fn variant() -> Vec<(&'static str, &'static str)> {
129 crate::variant_params![G]
130 }
131
132 fn dims(&self) -> Vec<usize> {
133 vec![2; self.graph.num_edges()]
134 }
135
136 fn evaluate(&self, config: &[usize]) -> Min<usize> {
137 if config.len() != self.graph.num_edges() {
138 return Min(None);
139 }
140 if !self.is_valid_maximal_matching(config) {
141 return Min(None);
142 }
143 let count = config.iter().filter(|&&x| x == 1).count();
144 Min(Some(count))
145 }
146}
147
148crate::declare_variants! {
149 default MinimumMaximalMatching<SimpleGraph> => "1.3160^num_vertices",
150}
151
152#[cfg(feature = "example-db")]
153pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
154 vec![crate::example_db::specs::ModelExampleSpec {
157 id: "minimum_maximal_matching_simplegraph",
158 instance: Box::new(MinimumMaximalMatching::new(SimpleGraph::new(
159 6,
160 vec![(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)],
161 ))),
162 optimal_config: vec![0, 1, 0, 1, 0],
163 optimal_value: serde_json::json!(2),
164 }]
165}
166
167#[cfg(test)]
168#[path = "../../unit_tests/models/graph/minimum_maximal_matching.rs"]
169mod tests;