|
| 1 | +//! Reduction from MinimumMaximalMatching (on a bipartite graph) to |
| 2 | +//! MinimumMatrixDomination. |
| 3 | +//! |
| 4 | +//! Classical reduction of Yannakakis and Gavril (1980) establishing |
| 5 | +//! NP-completeness of MATRIX DOMINATION (Garey & Johnson MS12). For a bipartite |
| 6 | +//! graph `B = (L, R, F)` with `|L| = m` and `|R| = n`, construct the `N x N` |
| 7 | +//! binary matrix `M` (with `N = m + n`) whose upper-right `m x n` block is the |
| 8 | +//! biadjacency matrix `B*` of `B` and whose remaining entries are zero. The |
| 9 | +//! 1-entries of `M` are in bijection with the edges of `B`, and two 1-entries |
| 10 | +//! share a row or column iff the corresponding edges share an endpoint. Hence a |
| 11 | +//! dominating set of 1-entries in `M` corresponds to an edge dominating set of |
| 12 | +//! `B`, and by Yannakakis and Gavril (1980), the minimum edge dominating set |
| 13 | +//! size equals the minimum maximal matching size. |
| 14 | +//! |
| 15 | +//! ## Witness extraction |
| 16 | +//! |
| 17 | +//! Solving Minimum Matrix Domination on the constructed instance yields a |
| 18 | +//! minimum edge dominating set of `B`, which is in general NOT a matching. |
| 19 | +//! Yannakakis and Gavril (1980) prove that any edge dominating set can be |
| 20 | +//! transformed in polynomial time into an independent edge dominating set |
| 21 | +//! (a maximal matching) of the same size. We implement this conversion by a |
| 22 | +//! direct search: enumerate maximal matchings of `B` and return one of size at |
| 23 | +//! most `|EDS|`. Because every minimum maximal matching is also an EDS and the |
| 24 | +//! two minima are equal, such a matching always exists when the target witness |
| 25 | +//! is optimal. |
| 26 | +//! |
| 27 | +//! ## Source variant |
| 28 | +//! |
| 29 | +//! The reduction requires the bipartite (`BipartiteGraph`) variant of |
| 30 | +//! `MinimumMaximalMatching`. The biadjacency matrix faithfully represents the |
| 31 | +//! edge structure of a bipartite graph (each edge -> exactly one 1-entry), |
| 32 | +//! whereas an undirected adjacency matrix would produce two symmetric 1-entries |
| 33 | +//! per edge that do not preserve the row/column sharing pattern. |
| 34 | +
|
| 35 | +use crate::models::algebraic::MinimumMatrixDomination; |
| 36 | +use crate::models::graph::MinimumMaximalMatching; |
| 37 | +use crate::reduction; |
| 38 | +use crate::rules::traits::{ReduceTo, ReductionResult}; |
| 39 | +use crate::topology::{BipartiteGraph, Graph}; |
| 40 | + |
| 41 | +/// Result of reducing `MinimumMaximalMatching<BipartiteGraph>` to |
| 42 | +/// `MinimumMatrixDomination`. |
| 43 | +/// |
| 44 | +/// Holds the constructed target matrix-domination instance together with a copy |
| 45 | +/// of the source bipartite-matching problem. The source copy is used by |
| 46 | +/// `extract_solution` to perform the Yannakakis-Gavril conversion from an edge |
| 47 | +/// dominating set to an equally-sized maximal matching. |
| 48 | +#[derive(Debug, Clone)] |
| 49 | +pub struct ReductionMMMToMatrixDomination { |
| 50 | + target: MinimumMatrixDomination, |
| 51 | + source: MinimumMaximalMatching<BipartiteGraph>, |
| 52 | +} |
| 53 | + |
| 54 | +impl ReductionResult for ReductionMMMToMatrixDomination { |
| 55 | + type Source = MinimumMaximalMatching<BipartiteGraph>; |
| 56 | + type Target = MinimumMatrixDomination; |
| 57 | + |
| 58 | + fn target_problem(&self) -> &Self::Target { |
| 59 | + &self.target |
| 60 | + } |
| 61 | + |
| 62 | + /// Extract a maximal matching of the source bipartite graph from a |
| 63 | + /// matrix-domination witness. |
| 64 | + /// |
| 65 | + /// The target witness identifies a set of 1-entries of `M`. Each selected |
| 66 | + /// 1-entry in the upper-right block `B*` corresponds bijectively to a |
| 67 | + /// source edge, so the selection induces an edge set `D` of `B` that is an |
| 68 | + /// edge dominating set. The minimum edge dominating set size of a graph |
| 69 | + /// equals the minimum maximal matching size [Yannakakis-Gavril 1980], so |
| 70 | + /// any optimal target witness yields `|D|` equal to `mm(B)`. We then |
| 71 | + /// recover a maximal matching `M` of `B` with `|M| <= |D|` by enumerating |
| 72 | + /// candidate source configurations. |
| 73 | + fn extract_solution(&self, target_solution: &[usize]) -> Vec<usize> { |
| 74 | + let num_source_edges = self.source.graph().num_edges(); |
| 75 | + let target_ones = self.target.ones(); |
| 76 | + let bound: usize = target_solution |
| 77 | + .iter() |
| 78 | + .zip(target_ones.iter()) |
| 79 | + .filter(|(&sel, _)| sel == 1) |
| 80 | + .count(); |
| 81 | + |
| 82 | + // Search for any maximal matching of B with cardinality at most `bound`. |
| 83 | + // For an optimal target witness, |D| = mm(B), so such a matching |
| 84 | + // exists by Yannakakis-Gavril (1980). For canonical example sizes this |
| 85 | + // enumeration is fast; in the worst case it is 2^|E| which mirrors the |
| 86 | + // brute-force solve used elsewhere in the test infrastructure. |
| 87 | + // |
| 88 | + // Iterate by size from 0 upward so we always return a smallest-known |
| 89 | + // maximal matching. |
| 90 | + for target_size in 0..=bound { |
| 91 | + for mask in 0u64..(1u64 << num_source_edges) { |
| 92 | + if mask.count_ones() as usize != target_size { |
| 93 | + continue; |
| 94 | + } |
| 95 | + let config: Vec<usize> = (0..num_source_edges) |
| 96 | + .map(|i| ((mask >> i) & 1) as usize) |
| 97 | + .collect(); |
| 98 | + if self.source.is_valid_maximal_matching(&config) { |
| 99 | + return config; |
| 100 | + } |
| 101 | + } |
| 102 | + } |
| 103 | + |
| 104 | + // Fallback: a zero configuration. This branch is unreachable when the |
| 105 | + // reduction is correct and the supplied target witness is feasible. |
| 106 | + vec![0; num_source_edges] |
| 107 | + } |
| 108 | +} |
| 109 | + |
| 110 | +#[reduction( |
| 111 | + overhead = { |
| 112 | + num_rows = "num_vertices", |
| 113 | + num_cols = "num_vertices", |
| 114 | + num_ones = "num_edges", |
| 115 | + } |
| 116 | +)] |
| 117 | +impl ReduceTo<MinimumMatrixDomination> for MinimumMaximalMatching<BipartiteGraph> { |
| 118 | + type Result = ReductionMMMToMatrixDomination; |
| 119 | + |
| 120 | + fn reduce_to(&self) -> Self::Result { |
| 121 | + let g = self.graph(); |
| 122 | + let m = g.left_size(); |
| 123 | + let n = g.right_size(); |
| 124 | + let big_n = m + n; |
| 125 | + |
| 126 | + // Build the N x N matrix: |
| 127 | + // upper-right m x n block = biadjacency matrix B* |
| 128 | + // all other entries = 0 |
| 129 | + // The matrix is upper triangular: 1-entries lie strictly in rows |
| 130 | + // 0..m and columns m..m+n. |
| 131 | + let mut matrix = vec![vec![false; big_n]; big_n]; |
| 132 | + for &(left_idx, right_idx) in g.left_edges() { |
| 133 | + // Row = l_left_idx (in 0..m), Column = m + right_idx (in m..m+n). |
| 134 | + matrix[left_idx][m + right_idx] = true; |
| 135 | + } |
| 136 | + |
| 137 | + let target = MinimumMatrixDomination::new(matrix); |
| 138 | + |
| 139 | + ReductionMMMToMatrixDomination { |
| 140 | + target, |
| 141 | + source: self.clone(), |
| 142 | + } |
| 143 | + } |
| 144 | +} |
| 145 | + |
| 146 | +#[cfg(feature = "example-db")] |
| 147 | +pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> { |
| 148 | + use crate::export::SolutionPair; |
| 149 | + |
| 150 | + vec![crate::example_db::specs::RuleExampleSpec { |
| 151 | + id: "minimummaximalmatching_to_minimummatrixdomination", |
| 152 | + build: || { |
| 153 | + // Canonical YES instance from the issue. |
| 154 | + // |
| 155 | + // Bipartite graph B with L = {l0, l1}, R = {r0, r1, r2} and edges |
| 156 | + // F = {(l0, r0), (l0, r1), (l0, r2), (l1, r1), (l1, r2)}. |
| 157 | + // |
| 158 | + // Source edge indices (in BipartiteGraph::edges() order): |
| 159 | + // 0: (l0, r0) = (0, 0) |
| 160 | + // 1: (l0, r1) = (0, 1) |
| 161 | + // 2: (l0, r2) = (0, 2) |
| 162 | + // 3: (l1, r1) = (1, 1) |
| 163 | + // 4: (l1, r2) = (1, 2) |
| 164 | + // |
| 165 | + // mm(B) = 2; one optimum is M = {(l0, r0), (l1, r1)} -> |
| 166 | + // source_config = [1, 0, 0, 1, 0]. |
| 167 | + // |
| 168 | + // Constructed N x N matrix with N = 5; 1-entries in row-major |
| 169 | + // order (matching the source edge order above): |
| 170 | + // idx 0: (0, 2) <- (l0, r0) |
| 171 | + // idx 1: (0, 3) <- (l0, r1) |
| 172 | + // idx 2: (0, 4) <- (l0, r2) |
| 173 | + // idx 3: (1, 3) <- (l1, r1) |
| 174 | + // idx 4: (1, 4) <- (l1, r2) |
| 175 | + // |
| 176 | + // Selecting target_config = [1, 0, 0, 1, 0] picks 1-entries |
| 177 | + // {(0, 2), (1, 3)}, which together dominate every other 1-entry by |
| 178 | + // shared row 0 or row 1. |
| 179 | + let source = MinimumMaximalMatching::new(BipartiteGraph::new( |
| 180 | + 2, |
| 181 | + 3, |
| 182 | + vec![(0, 0), (0, 1), (0, 2), (1, 1), (1, 2)], |
| 183 | + )); |
| 184 | + crate::example_db::specs::rule_example_with_witness::<_, MinimumMatrixDomination>( |
| 185 | + source, |
| 186 | + SolutionPair { |
| 187 | + source_config: vec![1, 0, 0, 1, 0], |
| 188 | + target_config: vec![1, 0, 0, 1, 0], |
| 189 | + }, |
| 190 | + ) |
| 191 | + }, |
| 192 | + }] |
| 193 | +} |
| 194 | + |
| 195 | +#[cfg(test)] |
| 196 | +#[path = "../unit_tests/rules/minimummaximalmatching_minimummatrixdomination.rs"] |
| 197 | +mod tests; |
0 commit comments