1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
use std::cmp::Ordering::{Equal, Greater, Less};
use std::f64;
use crate::graph::AnnotatedGraph;
use crate::matching::Matching;
use crate::Edge;
pub type Weight = f64;
pub type WeightedGraph<T = Weight> = AnnotatedGraph<T>;
impl<T> WeightedGraph<T>
where
T: PartialEq + PartialOrd + Copy,
{
pub fn maximin_matching(&self) -> Option<Matching> {
if self.is_empty() {
return Some(Matching::new(&[]));
}
let cmp = |x: &T, y: &T| x.partial_cmp(y).unwrap_or(Equal);
let cmp_rev = |x: &T, y: &T| cmp(y, x);
self.full_matching()?;
let min_max_value = self
.vertices()
.iter()
.map(|&v| self.edges_from(v).1.iter().cloned().max_by(cmp).unwrap())
.min_by(cmp)
.unwrap();
let mut values: Vec<_> = self
.vertices()
.iter()
.flat_map(|&vertex| self.edges_from(vertex).1)
.filter(|&w| cmp(w, &min_max_value) != Greater)
.cloned()
.collect();
values.sort_by(cmp_rev);
for value in values {
let limited = self.limit(value);
if let Some(matching) = limited.full_matching() {
let mut edges: Vec<Edge> = matching
.edges()
.into_iter()
.filter(|edge| limited.weight(edge).eq(&value))
.collect();
edges.sort_by_key(|&(v, w)| limited.vertices_from(v).min(limited.vertices_from(w)));
let sub_matching = limited
.filter_vertices(|&v| v != edges[0].0 && v != edges[0].1)
.maximin_matching()
.unwrap();
return Some(sub_matching.add(&Matching::new(&edges[0..1])));
}
}
None
}
pub fn limit(&self, weight: T) -> WeightedGraph<T> {
self.filter_edges(|_, _, &w| w.partial_cmp(&weight) != Some(Less))
}
fn weight(&self, edge: &Edge) -> T {
let (v, w) = self.edges_from(edge.0);
*v.iter().zip(w.iter()).find(|t| *t.0 == edge.1).unwrap().1
}
}
#[test]
fn find_match_sparse() {
let g = [
(0, (vec![2, 3], vec![0.1, 0.9])),
(1, (vec![2, 3], vec![0.3, 0.2])),
(2, (vec![0, 1], vec![0.1, 0.3])),
(3, (vec![0, 1], vec![0.9, 0.2])),
]
.iter()
.collect::<WeightedGraph>();
let m = g.maximin_matching();
assert!(m.is_some());
if let Some(m) = m {
assert_eq!(m.partner(0), 3);
assert_eq!(m.partner(1), 2);
}
}
#[test]
fn find_match_dense() {
let g = [
(0, (vec![1, 2, 3], vec![0.1, 0.3, 0.5])),
(1, (vec![0, 2, 3], vec![0.1, 0.2, 0.6])),
(2, (vec![0, 1, 3], vec![0.3, 0.2, 0.4])),
(3, (vec![0, 1, 2], vec![0.5, 0.6, 0.4])),
]
.iter()
.collect::<WeightedGraph>();
let m = g.maximin_matching();
assert!(m.is_some());
if let Some(m) = m {
assert_eq!(m.partner(0), 2);
assert_eq!(m.partner(1), 3);
}
}