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::collections::HashSet;
use std::f64;
use Edge;
use graph::AnnotatedGraph;
use matching::Matching;
pub type Weight = f64;
pub type WeightedGraph = AnnotatedGraph<Weight>;
impl WeightedGraph {
pub fn maximin_matching(&self) -> Option<Matching> {
if self.is_empty() {
return Some(Matching::new(&[]));
}
if self.full_matching().is_none() {
return None;
}
let values: HashSet<_> = self.vertices()
.iter()
.flat_map(|&vertex| self.edges_from(vertex).1)
.map(|x| x.to_bits())
.collect();
let mut values = values
.into_iter()
.map(Weight::from_bits)
.collect::<Vec<_>>();
values.sort_by(|&x, &y| {
if y < x {
Less
} else if x.eq(&y) {
Equal
} else {
Greater
}
});
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: Weight) -> WeightedGraph {
self.filter_edges(|_, _, &w| w >= weight)
}
fn weight(&self, edge: &Edge) -> Weight {
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);
}
}