#![allow(clippy::too_many_arguments)]
#![allow(clippy::many_single_char_names)]
use std::cmp::max;
use std::hash::Hash;
use std::mem;
use hashbrown::{HashMap, HashSet};
use petgraph::visit::{
EdgeCount, EdgeRef, GraphBase, GraphProp, IntoEdges, IntoNodeIdentifiers, NodeCount,
NodeIndexable,
};
use petgraph::Undirected;
fn slack(edge_index: usize, dual_var: &[i128], edges: &[(usize, usize, i128)]) -> i128 {
let (source_index, target_index, weight) = edges[edge_index];
dual_var[source_index] + dual_var[target_index] - 2 * weight
}
fn blossom_leaves<E>(
blossom: usize,
num_nodes: usize,
blossom_children: &[Vec<usize>],
) -> Result<Vec<usize>, E> {
let mut out_vec: Vec<usize> = Vec::new();
if blossom < num_nodes {
out_vec.push(blossom);
} else {
let child_blossom = &blossom_children[blossom];
for c in child_blossom {
let child = *c;
if child < num_nodes {
out_vec.push(child);
} else {
for v in blossom_leaves(child, num_nodes, blossom_children)? {
out_vec.push(v);
}
}
}
}
Ok(out_vec)
}
fn assign_label<E>(
w: usize,
t: usize,
p: Option<usize>,
num_nodes: usize,
in_blossoms: &[usize],
labels: &mut Vec<Option<usize>>,
label_ends: &mut Vec<Option<usize>>,
best_edge: &mut Vec<Option<usize>>,
queue: &mut Vec<usize>,
blossom_children: &[Vec<usize>],
blossom_base: &[Option<usize>],
endpoints: &[usize],
mate: &HashMap<usize, usize>,
) -> Result<(), E> {
let b = in_blossoms[w];
assert!(labels[w] == Some(0) && labels[b] == Some(0));
labels[w] = Some(t);
labels[b] = Some(t);
label_ends[b] = p;
label_ends[w] = p;
best_edge[w] = None;
best_edge[b] = None;
if t == 1 {
queue.append(&mut blossom_leaves(b, num_nodes, blossom_children)?);
} else if t == 2 {
let blossom_index: usize = b;
let base: usize = blossom_base[blossom_index].unwrap();
assert!(mate.get(&base).is_some());
assign_label(
endpoints[mate[&base]],
1,
mate.get(&base).map(|p| (p ^ 1)),
num_nodes,
in_blossoms,
labels,
label_ends,
best_edge,
queue,
blossom_children,
blossom_base,
endpoints,
mate,
)?;
}
Ok(())
}
fn scan_blossom(
node_a: usize,
node_b: usize,
in_blossoms: &[usize],
blossom_base: &[Option<usize>],
endpoints: &[usize],
labels: &mut [Option<usize>],
label_ends: &[Option<usize>],
mate: &HashMap<usize, usize>,
) -> Option<usize> {
let mut v: Option<usize> = Some(node_a);
let mut w: Option<usize> = Some(node_b);
let mut path: Vec<usize> = Vec::new();
let mut base: Option<usize> = None;
while v.is_some() || w.is_some() {
let mut blossom = in_blossoms[v.unwrap()];
if labels[blossom].is_none() || labels[blossom].unwrap() & 4 > 0 {
base = blossom_base[blossom];
break;
}
assert!(labels[blossom] == Some(1));
path.push(blossom);
labels[blossom] = Some(5);
assert!(label_ends[blossom] == mate.get(&blossom_base[blossom].unwrap()).copied());
if label_ends[blossom].is_none() {
v = None;
} else {
let tmp = endpoints[label_ends[blossom].unwrap()];
blossom = in_blossoms[tmp];
assert!(labels[blossom] == Some(2));
assert!(label_ends[blossom].is_some());
v = Some(endpoints[label_ends[blossom].unwrap()]);
}
if w.is_some() {
mem::swap(&mut v, &mut w);
}
}
for blossom in path {
labels[blossom] = Some(1);
}
base
}
fn add_blossom<E>(
base: usize,
edge: usize,
blossom_children: &mut [Vec<usize>],
num_nodes: usize,
edges: &[(usize, usize, i128)],
in_blossoms: &mut [usize],
dual_var: &mut [i128],
labels: &mut [Option<usize>],
label_ends: &mut [Option<usize>],
best_edge: &mut [Option<usize>],
queue: &mut Vec<usize>,
blossom_base: &mut [Option<usize>],
endpoints: &[usize],
blossom_endpoints: &mut [Vec<usize>],
unused_blossoms: &mut Vec<usize>,
blossom_best_edges: &mut [Vec<usize>],
blossom_parents: &mut [Option<usize>],
neighbor_endpoints: &[Vec<usize>],
mate: &HashMap<usize, usize>,
) -> Result<(), E> {
let (mut v, mut w, _weight) = edges[edge];
let blossom_b = in_blossoms[base];
let mut blossom_v = in_blossoms[v];
let mut blossom_w = in_blossoms[w];
let blossom = unused_blossoms.pop().unwrap();
blossom_base[blossom] = Some(base);
blossom_parents[blossom] = None;
blossom_parents[blossom_b] = Some(blossom);
blossom_children[blossom].clear();
blossom_endpoints[blossom].clear();
while blossom_v != blossom_b {
blossom_parents[blossom_v] = Some(blossom);
blossom_children[blossom].push(blossom_v);
let blossom_v_endpoint_label = label_ends[blossom_v].unwrap();
blossom_endpoints[blossom].push(blossom_v_endpoint_label);
assert!(
labels[blossom_v] == Some(2)
|| (labels[blossom_v] == Some(1)
&& label_ends[blossom_v]
== mate.get(&blossom_base[blossom_v].unwrap()).copied())
);
assert!(label_ends[blossom_v].is_some());
v = endpoints[blossom_v_endpoint_label];
blossom_v = in_blossoms[v];
}
blossom_children[blossom].push(blossom_b);
blossom_children[blossom].reverse();
blossom_endpoints[blossom].reverse();
blossom_endpoints[blossom].push(2 * edge);
while blossom_w != blossom_b {
blossom_parents[blossom_w] = Some(blossom);
blossom_children[blossom].push(blossom_w);
let blossom_w_endpoint_label = label_ends[blossom_w].unwrap();
blossom_endpoints[blossom].push(blossom_w_endpoint_label ^ 1);
assert!(
labels[blossom_w] == Some(2)
|| (labels[blossom_w] == Some(1)
&& label_ends[blossom_w]
== mate.get(&blossom_base[blossom_w].unwrap()).copied())
);
assert!(label_ends[blossom_w].is_some());
w = endpoints[blossom_w_endpoint_label];
blossom_w = in_blossoms[w];
}
assert!(labels[blossom_b] == Some(1));
labels[blossom] = Some(1);
label_ends[blossom] = label_ends[blossom_b];
dual_var[blossom] = 0;
for node in blossom_leaves(blossom, num_nodes, blossom_children)? {
if labels[in_blossoms[node]] == Some(2) {
queue.push(node);
}
in_blossoms[node] = blossom;
}
let mut best_edge_to: HashMap<usize, usize> = HashMap::with_capacity(2 * num_nodes);
for bv_ref in &blossom_children[blossom] {
let bv = *bv_ref;
let nblists: Vec<Vec<usize>> = if blossom_best_edges[bv].is_empty() {
let mut tmp: Vec<Vec<usize>> = Vec::new();
for node in blossom_leaves(bv, num_nodes, blossom_children)? {
tmp.push(neighbor_endpoints[node].iter().map(|p| p / 2).collect());
}
tmp
} else {
vec![blossom_best_edges[bv].clone()]
};
for nblist in nblists {
for edge_index in nblist {
let (mut i, mut j, _edge_weight) = edges[edge_index];
if in_blossoms[j] == blossom {
mem::swap(&mut i, &mut j);
}
let blossom_j = in_blossoms[j];
if blossom_j != blossom
&& labels[blossom_j] == Some(1)
&& (best_edge_to.get(&blossom_j).is_none()
|| slack(edge_index, dual_var, edges)
< slack(best_edge_to[&blossom_j], dual_var, edges))
{
best_edge_to.insert(blossom_j, edge_index);
}
}
}
blossom_best_edges[bv].clear();
best_edge[bv] = None;
}
blossom_best_edges[blossom] = best_edge_to.values().copied().collect();
best_edge[blossom] = None;
for edge_index in &blossom_best_edges[blossom] {
if best_edge[blossom].is_none()
|| slack(*edge_index, dual_var, edges)
< slack(best_edge[blossom].unwrap(), dual_var, edges)
{
best_edge[blossom] = Some(*edge_index);
}
}
Ok(())
}
fn expand_blossom<E>(
blossom: usize,
end_stage: bool,
num_nodes: usize,
blossom_children: &mut Vec<Vec<usize>>,
blossom_parents: &mut Vec<Option<usize>>,
in_blossoms: &mut Vec<usize>,
dual_var: &[i128],
labels: &mut Vec<Option<usize>>,
label_ends: &mut Vec<Option<usize>>,
best_edge: &mut Vec<Option<usize>>,
queue: &mut Vec<usize>,
blossom_base: &mut Vec<Option<usize>>,
endpoints: &[usize],
mate: &HashMap<usize, usize>,
blossom_endpoints: &mut Vec<Vec<usize>>,
allowed_edge: &mut Vec<bool>,
unused_blossoms: &mut Vec<usize>,
) -> Result<(), E> {
for s in blossom_children[blossom].clone() {
blossom_parents[s] = None;
if s < num_nodes {
in_blossoms[s] = s
} else if end_stage && dual_var[s] == 0 {
expand_blossom(
s,
end_stage,
num_nodes,
blossom_children,
blossom_parents,
in_blossoms,
dual_var,
labels,
label_ends,
best_edge,
queue,
blossom_base,
endpoints,
mate,
blossom_endpoints,
allowed_edge,
unused_blossoms,
)?;
} else {
for v in blossom_leaves(s, num_nodes, blossom_children)? {
in_blossoms[v] = s;
}
}
}
if !end_stage && labels[blossom] == Some(2) {
assert!(label_ends[blossom].is_some());
let entry_child = in_blossoms[endpoints[label_ends[blossom].unwrap() ^ 1]];
let i = blossom_children[blossom]
.iter()
.position(|x| *x == entry_child)
.unwrap();
let mut j = i as i128;
let j_step: i128;
let endpoint_trick: usize = if i & 1 != 0 {
j -= blossom_children[blossom].len() as i128;
j_step = 1;
0
} else {
j_step = -1;
1
};
let mut p = label_ends[blossom].unwrap();
while j != 0 {
labels[endpoints[p ^ 1]] = Some(0);
if j < 0 {
let length = blossom_endpoints[blossom].len();
let index = length - j.unsigned_abs() as usize;
labels[endpoints
[blossom_endpoints[blossom][index - endpoint_trick] ^ endpoint_trick ^ 1]] =
Some(0);
} else {
labels[endpoints[blossom_endpoints[blossom][j as usize - endpoint_trick]
^ endpoint_trick
^ 1]] = Some(0);
}
assign_label(
endpoints[p ^ 1],
2,
Some(p),
num_nodes,
in_blossoms,
labels,
label_ends,
best_edge,
queue,
blossom_children,
blossom_base,
endpoints,
mate,
)?;
let endpoint_index = if j < 0 {
let tmp = j - endpoint_trick as i128;
let length = blossom_endpoints[blossom].len();
let index = length - tmp.unsigned_abs() as usize;
blossom_endpoints[blossom][index]
} else {
blossom_endpoints[blossom][j as usize - endpoint_trick]
};
allowed_edge[endpoint_index / 2] = true;
j += j_step;
p = if j < 0 {
let tmp = j - endpoint_trick as i128;
let length = blossom_endpoints[blossom].len();
let index = length - tmp.unsigned_abs() as usize;
blossom_endpoints[blossom][index] ^ endpoint_trick
} else {
blossom_endpoints[blossom][j as usize - endpoint_trick] ^ endpoint_trick
};
allowed_edge[p / 2] = true;
j += j_step;
}
let blossom_v = if j < 0 {
let length = blossom_children[blossom].len();
let index = length - j.unsigned_abs() as usize;
blossom_children[blossom][index]
} else {
blossom_children[blossom][j as usize]
};
labels[endpoints[p ^ 1]] = Some(2);
labels[blossom_v] = Some(2);
label_ends[endpoints[p ^ 1]] = Some(p);
label_ends[blossom_v] = Some(p);
best_edge[blossom_v] = None;
j += j_step;
let mut j_index = if j < 0 {
let length = blossom_children[blossom].len();
length - j.unsigned_abs() as usize
} else {
j as usize
};
while blossom_children[blossom][j_index] != entry_child {
let bv = blossom_children[blossom][j_index];
if labels[bv] == Some(1) {
j += j_step;
if j < 0 {
let length = blossom_children[blossom].len();
j_index = length - j.unsigned_abs() as usize;
} else {
j_index = j as usize;
}
continue;
}
let mut v: usize = 0;
for tmp in blossom_leaves(bv, num_nodes, blossom_children)? {
v = tmp;
if labels[v].unwrap() != 0 {
break;
}
}
if labels[v] != Some(0) {
assert!(labels[v] == Some(2));
assert!(in_blossoms[v] == bv);
labels[v] = Some(0);
labels[endpoints[mate[&blossom_base[bv].unwrap()]]] = Some(0);
assign_label(
v,
2,
label_ends[v],
num_nodes,
in_blossoms,
labels,
label_ends,
best_edge,
queue,
blossom_children,
blossom_base,
endpoints,
mate,
)?;
}
j += j_step;
if j < 0 {
let length = blossom_children[blossom].len();
j_index = length - j.unsigned_abs() as usize;
} else {
j_index = j as usize;
}
}
}
labels[blossom] = None;
label_ends[blossom] = None;
blossom_children[blossom].clear();
blossom_endpoints[blossom].clear();
blossom_base[blossom] = None;
best_edge[blossom] = None;
unused_blossoms.push(blossom);
Ok(())
}
fn augment_blossom(
blossom: usize,
node: usize,
num_nodes: usize,
blossom_parents: &[Option<usize>],
endpoints: &[usize],
blossom_children: &mut Vec<Vec<usize>>,
blossom_endpoints: &mut Vec<Vec<usize>>,
blossom_base: &mut Vec<Option<usize>>,
mate: &mut HashMap<usize, usize>,
) {
let mut tmp = node;
while blossom_parents[tmp] != Some(blossom) {
tmp = blossom_parents[tmp].unwrap();
}
if tmp >= num_nodes {
augment_blossom(
tmp,
node,
num_nodes,
blossom_parents,
endpoints,
blossom_children,
blossom_endpoints,
blossom_base,
mate,
);
}
let i = blossom_children[blossom]
.iter()
.position(|x| *x == tmp)
.unwrap();
let mut j: i128 = i as i128;
let j_step: i128;
let endpoint_trick: usize = if i & 1 != 0 {
j -= blossom_children[blossom].len() as i128;
j_step = 1;
0
} else {
j_step = -1;
1
};
while j != 0 {
j += j_step;
tmp = if j < 0 {
let length = blossom_children[blossom].len();
let index = length - j.unsigned_abs() as usize;
blossom_children[blossom][index]
} else {
blossom_children[blossom][j as usize]
};
let p = if j < 0 {
let length = blossom_endpoints[blossom].len();
let index = length - j.unsigned_abs() as usize - endpoint_trick;
blossom_endpoints[blossom][index] ^ endpoint_trick
} else {
blossom_endpoints[blossom][j as usize - endpoint_trick] ^ endpoint_trick
};
if tmp > num_nodes {
augment_blossom(
tmp,
endpoints[p],
num_nodes,
blossom_parents,
endpoints,
blossom_children,
blossom_endpoints,
blossom_base,
mate,
);
}
j += j_step;
if j < 0 {
let length = blossom_children[blossom].len();
let index = length - j.unsigned_abs() as usize;
tmp = blossom_children[blossom][index];
} else {
tmp = blossom_children[blossom][j as usize];
}
if tmp > num_nodes {
augment_blossom(
tmp,
endpoints[p ^ 1],
num_nodes,
blossom_parents,
endpoints,
blossom_children,
blossom_endpoints,
blossom_base,
mate,
);
}
mate.insert(endpoints[p], p ^ 1);
mate.insert(endpoints[p ^ 1], p);
}
let mut children: Vec<usize> = blossom_children[blossom][i..].to_vec();
children.extend_from_slice(&blossom_children[blossom][..i]);
blossom_children[blossom] = children;
let mut endpoint: Vec<usize> = blossom_endpoints[blossom][i..].to_vec();
endpoint.extend_from_slice(&blossom_endpoints[blossom][..i]);
blossom_endpoints[blossom] = endpoint;
blossom_base[blossom] = blossom_base[blossom_children[blossom][0]];
assert!(blossom_base[blossom] == Some(node));
}
fn augment_matching(
edge: usize,
num_nodes: usize,
edges: &[(usize, usize, i128)],
in_blossoms: &[usize],
labels: &[Option<usize>],
label_ends: &[Option<usize>],
blossom_parents: &[Option<usize>],
endpoints: &[usize],
blossom_children: &mut Vec<Vec<usize>>,
blossom_endpoints: &mut Vec<Vec<usize>>,
blossom_base: &mut Vec<Option<usize>>,
mate: &mut HashMap<usize, usize>,
) {
let (v, w, _weight) = edges[edge];
for (s_ref, p_ref) in [(v, 2 * edge + 1), (w, 2 * edge)].iter() {
let mut s: usize = *s_ref;
let mut p: usize = *p_ref;
loop {
let blossom_s = in_blossoms[s];
assert!(labels[blossom_s] == Some(1));
assert!(label_ends[blossom_s] == mate.get(&blossom_base[blossom_s].unwrap()).copied());
if blossom_s >= num_nodes {
augment_blossom(
blossom_s,
s,
num_nodes,
blossom_parents,
endpoints,
blossom_children,
blossom_endpoints,
blossom_base,
mate,
);
}
mate.insert(s, p);
if label_ends[blossom_s].is_none() {
break;
}
let t = endpoints[label_ends[blossom_s].unwrap()];
let blossom_t = in_blossoms[t];
assert!(labels[blossom_t] == Some(2));
assert!(label_ends[blossom_t].is_some());
s = endpoints[label_ends[blossom_t].unwrap()];
let j = endpoints[label_ends[blossom_t].unwrap() ^ 1];
assert!(blossom_base[blossom_t] == Some(t));
if blossom_t >= num_nodes {
augment_blossom(
blossom_t,
j,
num_nodes,
blossom_parents,
endpoints,
blossom_children,
blossom_endpoints,
blossom_base,
mate,
);
}
mate.insert(j, label_ends[blossom_t].unwrap());
p = label_ends[blossom_t].unwrap() ^ 1;
}
}
}
fn verify_optimum(
max_cardinality: bool,
num_nodes: usize,
num_edges: usize,
edges: &[(usize, usize, i128)],
endpoints: &[usize],
dual_var: &[i128],
blossom_parents: &[Option<usize>],
blossom_endpoints: &[Vec<usize>],
blossom_base: &[Option<usize>],
mate: &HashMap<usize, usize>,
) {
let dual_var_node_min: i128 = *dual_var[..num_nodes].iter().min().unwrap();
let node_dual_offset: i128 = if max_cardinality {
max(0, -dual_var_node_min)
} else {
0
};
assert!(dual_var_node_min + node_dual_offset >= 0);
assert!(*dual_var[num_nodes..].iter().min().unwrap() >= 0);
for (edge, (i, j, weight)) in edges.iter().enumerate().take(num_edges) {
let mut s = dual_var[*i] + dual_var[*j] - 2 * weight;
let mut i_blossoms: Vec<usize> = vec![*i];
let mut j_blossoms: Vec<usize> = vec![*j];
while blossom_parents[*i_blossoms.last().unwrap()].is_some() {
i_blossoms.push(blossom_parents[*i_blossoms.last().unwrap()].unwrap());
}
while blossom_parents[*j_blossoms.last().unwrap()].is_some() {
j_blossoms.push(blossom_parents[*j_blossoms.last().unwrap()].unwrap());
}
i_blossoms.reverse();
j_blossoms.reverse();
for (blossom_i, blossom_j) in i_blossoms.iter().zip(j_blossoms.iter()) {
if blossom_i != blossom_j {
break;
}
s += 2 * dual_var[*blossom_i];
}
assert!(s >= 0);
if (mate.get(i).is_some() && mate.get(i).unwrap() / 2 == edge)
|| (mate.get(j).is_some() && mate.get(j).unwrap() / 2 == edge)
{
assert!(mate[i] / 2 == edge && mate[j] / 2 == edge);
assert!(s == 0);
}
}
for (node, dual_var_node) in dual_var.iter().enumerate().take(num_nodes) {
assert!(mate.get(&node).is_some() || dual_var_node + node_dual_offset == 0);
}
for blossom in num_nodes..2 * num_nodes {
if blossom_base[blossom].is_some() && dual_var[blossom] > 0 {
assert!(blossom_endpoints[blossom].len() % 2 == 1);
for p in blossom_endpoints[blossom].iter().skip(1).step_by(2) {
assert!(mate.get(&endpoints[*p]).copied() == Some(p ^ 1));
assert!(mate.get(&endpoints[*p ^ 1]) == Some(p));
}
}
}
}
pub fn max_weight_matching<G, F, E>(
graph: G,
max_cardinality: bool,
mut weight_fn: F,
verify_optimum_flag: bool,
) -> Result<HashSet<(usize, usize)>, E>
where
G: EdgeCount
+ NodeCount
+ IntoNodeIdentifiers
+ GraphProp<EdgeType = Undirected>
+ GraphBase
+ NodeIndexable
+ IntoEdges,
F: FnMut(G::EdgeRef) -> Result<i128, E>,
<G as GraphBase>::NodeId: std::cmp::Eq + Hash,
{
let num_edges = graph.edge_count();
let num_nodes = graph.node_count();
let mut out_set: HashSet<(usize, usize)> = HashSet::with_capacity(num_nodes);
if num_edges == 0 {
return Ok(HashSet::new());
}
let node_map: HashMap<G::NodeId, usize> = graph
.node_identifiers()
.enumerate()
.map(|(index, node_index)| (node_index, index))
.collect();
let mut edges: Vec<(usize, usize, i128)> = Vec::with_capacity(num_edges);
let mut max_weight: i128 = 0;
for edge in graph.edge_references() {
let edge_weight: i128 = weight_fn(edge)?;
if edge_weight > max_weight {
max_weight = edge_weight;
};
edges.push((
node_map[&edge.source()],
node_map[&edge.target()],
edge_weight,
));
}
let endpoints: Vec<usize> = (0..2 * num_edges)
.map(|endpoint| {
let edge_tuple = edges[endpoint / 2];
let out_value: usize = if endpoint % 2 == 0 {
edge_tuple.0
} else {
edge_tuple.1
};
out_value
})
.collect();
let mut neighbor_endpoints: Vec<Vec<usize>> = (0..num_nodes).map(|_| Vec::new()).collect();
for edge in 0..num_edges {
neighbor_endpoints[edges[edge].0].push(2 * edge + 1);
neighbor_endpoints[edges[edge].1].push(2 * edge);
}
let mut mate: HashMap<usize, usize> = HashMap::with_capacity(num_nodes);
let mut labels: Vec<Option<usize>>;
let mut label_ends: Vec<Option<usize>>;
let mut in_blossoms: Vec<usize> = (0..num_nodes).collect();
let mut blossom_parents: Vec<Option<usize>> = vec![None; 2 * num_nodes];
let mut blossom_children: Vec<Vec<usize>> = (0..2 * num_nodes).map(|_| Vec::new()).collect();
let mut blossom_base: Vec<Option<usize>> = (0..num_nodes).map(Some).collect();
blossom_base.append(&mut vec![None; num_nodes]);
let mut blossom_endpoints: Vec<Vec<usize>> = (0..2 * num_nodes).map(|_| Vec::new()).collect();
let mut best_edge: Vec<Option<usize>>;
let mut blossom_best_edges: Vec<Vec<usize>> = (0..2 * num_nodes).map(|_| Vec::new()).collect();
let mut unused_blossoms: Vec<usize> = (num_nodes..2 * num_nodes).collect();
let mut dual_var: Vec<i128> = vec![max_weight; num_nodes];
dual_var.append(&mut vec![0; num_nodes]);
let mut allowed_edge: Vec<bool>;
let mut queue: Vec<usize> = Vec::with_capacity(num_nodes);
for _ in 0..num_nodes {
labels = vec![Some(0); 2 * num_nodes];
label_ends = vec![None; 2 * num_nodes];
best_edge = vec![None; 2 * num_nodes];
blossom_best_edges.splice(num_nodes.., (0..num_nodes).map(|_| Vec::new()));
allowed_edge = vec![false; num_edges];
queue.clear();
for v in 0..num_nodes {
if mate.get(&v).is_none() && labels[in_blossoms[v]] == Some(0) {
assign_label(
v,
1,
None,
num_nodes,
&in_blossoms,
&mut labels,
&mut label_ends,
&mut best_edge,
&mut queue,
&blossom_children,
&blossom_base,
&endpoints,
&mate,
)?;
}
}
let mut augmented = false;
loop {
while !queue.is_empty() && !augmented {
let v = queue.pop().unwrap();
assert!(labels[in_blossoms[v]] == Some(1));
for p in &neighbor_endpoints[v] {
let k = *p / 2;
let mut kslack = 0;
let w = endpoints[*p];
if in_blossoms[v] == in_blossoms[w] {
continue;
}
if !allowed_edge[k] {
kslack = slack(k, &dual_var, &edges);
if kslack <= 0 {
allowed_edge[k] = true;
}
}
if allowed_edge[k] {
if labels[in_blossoms[w]] == Some(0) {
assign_label(
w,
2,
Some(*p ^ 1),
num_nodes,
&in_blossoms,
&mut labels,
&mut label_ends,
&mut best_edge,
&mut queue,
&blossom_children,
&blossom_base,
&endpoints,
&mate,
)?;
} else if labels[in_blossoms[w]] == Some(1) {
let base = scan_blossom(
v,
w,
&in_blossoms,
&blossom_base,
&endpoints,
&mut labels,
&label_ends,
&mate,
);
match base {
Some(base) => add_blossom(
base,
k,
&mut blossom_children,
num_nodes,
&edges,
&mut in_blossoms,
&mut dual_var,
&mut labels,
&mut label_ends,
&mut best_edge,
&mut queue,
&mut blossom_base,
&endpoints,
&mut blossom_endpoints,
&mut unused_blossoms,
&mut blossom_best_edges,
&mut blossom_parents,
&neighbor_endpoints,
&mate,
)?,
None => {
augment_matching(
k,
num_nodes,
&edges,
&in_blossoms,
&labels,
&label_ends,
&blossom_parents,
&endpoints,
&mut blossom_children,
&mut blossom_endpoints,
&mut blossom_base,
&mut mate,
);
augmented = true;
break;
}
};
} else if labels[w] == Some(0) {
assert!(labels[in_blossoms[w]] == Some(2));
labels[w] = Some(2);
label_ends[w] = Some(*p ^ 1);
}
} else if labels[in_blossoms[w]] == Some(1) {
let blossom = in_blossoms[v];
if best_edge[blossom].is_none()
|| kslack < slack(best_edge[blossom].unwrap(), &dual_var, &edges)
{
best_edge[blossom] = Some(k);
}
} else if labels[w] == Some(0) {
if best_edge[w].is_none()
|| kslack < slack(best_edge[w].unwrap(), &dual_var, &edges)
{
best_edge[w] = Some(k)
}
}
}
}
if augmented {
break;
}
let mut delta_type = -1;
let mut delta: Option<i128> = None;
let mut delta_edge: Option<usize> = None;
let mut delta_blossom: Option<usize> = None;
if !max_cardinality {
delta_type = 1;
delta = Some(*dual_var[..num_nodes].iter().min().unwrap());
}
for v in 0..num_nodes {
if labels[in_blossoms[v]] == Some(0) && best_edge[v].is_some() {
let d = slack(best_edge[v].unwrap(), &dual_var, &edges);
if delta_type == -1 || Some(d) < delta {
delta = Some(d);
delta_type = 2;
delta_edge = best_edge[v];
}
}
}
for blossom in 0..2 * num_nodes {
if blossom_parents[blossom].is_none()
&& labels[blossom] == Some(1)
&& best_edge[blossom].is_some()
{
let kslack = slack(best_edge[blossom].unwrap(), &dual_var, &edges);
assert!(kslack % 2 == 0);
let d = Some(kslack / 2);
if delta_type == -1 || d < delta {
delta = d;
delta_type = 3;
delta_edge = best_edge[blossom];
}
}
}
for blossom in num_nodes..2 * num_nodes {
if blossom_base[blossom].is_some()
&& blossom_parents[blossom].is_none()
&& labels[blossom] == Some(2)
&& (delta_type == -1 || dual_var[blossom] < delta.unwrap())
{
delta = Some(dual_var[blossom]);
delta_type = 4;
delta_blossom = Some(blossom);
}
}
if delta_type == -1 {
assert!(max_cardinality);
delta_type = 1;
delta = Some(max(0, *dual_var[..num_nodes].iter().min().unwrap()));
}
for v in 0..num_nodes {
if labels[in_blossoms[v]] == Some(1) {
dual_var[v] -= delta.unwrap();
} else if labels[in_blossoms[v]] == Some(2) {
dual_var[v] += delta.unwrap();
}
}
for b in num_nodes..2 * num_nodes {
if blossom_base[b].is_some() && blossom_parents[b].is_none() {
if labels[b] == Some(1) {
dual_var[b] += delta.unwrap();
} else if labels[b] == Some(2) {
dual_var[b] -= delta.unwrap();
}
}
}
if delta_type == 1 {
break;
} else if delta_type == 2 {
allowed_edge[delta_edge.unwrap()] = true;
let (mut i, mut j, _weight) = edges[delta_edge.unwrap()];
if labels[in_blossoms[i]] == Some(0) {
mem::swap(&mut i, &mut j);
}
assert!(labels[in_blossoms[i]] == Some(1));
queue.push(i);
} else if delta_type == 3 {
allowed_edge[delta_edge.unwrap()] = true;
let (i, _j, _weight) = edges[delta_edge.unwrap()];
assert!(labels[in_blossoms[i]] == Some(1));
queue.push(i);
} else if delta_type == 4 {
expand_blossom(
delta_blossom.unwrap(),
false,
num_nodes,
&mut blossom_children,
&mut blossom_parents,
&mut in_blossoms,
&dual_var,
&mut labels,
&mut label_ends,
&mut best_edge,
&mut queue,
&mut blossom_base,
&endpoints,
&mate,
&mut blossom_endpoints,
&mut allowed_edge,
&mut unused_blossoms,
)?;
}
}
if !augmented {
break;
}
for blossom in num_nodes..2 * num_nodes {
if blossom_parents[blossom].is_none()
&& blossom_base[blossom].is_some()
&& labels[blossom] == Some(1)
&& dual_var[blossom] == 0
{
expand_blossom(
blossom,
true,
num_nodes,
&mut blossom_children,
&mut blossom_parents,
&mut in_blossoms,
&dual_var,
&mut labels,
&mut label_ends,
&mut best_edge,
&mut queue,
&mut blossom_base,
&endpoints,
&mate,
&mut blossom_endpoints,
&mut allowed_edge,
&mut unused_blossoms,
)?;
}
}
}
if verify_optimum_flag {
verify_optimum(
max_cardinality,
num_nodes,
num_edges,
&edges,
&endpoints,
&dual_var,
&blossom_parents,
&blossom_endpoints,
&blossom_base,
&mate,
);
}
let mut seen: HashSet<(usize, usize)> = HashSet::with_capacity(2 * num_nodes);
let node_list: Vec<G::NodeId> = graph.node_identifiers().collect();
for (index, node) in mate.iter() {
let tmp = (
graph.to_index(node_list[*index]),
graph.to_index(node_list[endpoints[*node]]),
);
let rev_tmp = (
graph.to_index(node_list[endpoints[*node]]),
graph.to_index(node_list[*index]),
);
if !seen.contains(&tmp) && !seen.contains(&rev_tmp) {
out_set.insert(tmp);
seen.insert(tmp);
seen.insert(rev_tmp);
}
}
Ok(out_set)
}