#![allow(clippy::too_many_arguments)]
#![allow(clippy::many_single_char_names)]
use crate::{
core::{entities::nodes::node_ref::AsNodeRef, utils::iter::GenLockedIter},
db::{
api::view::IntoDynBoxed,
graph::{edge::EdgeView, edges::Edges, node::NodeView},
},
prelude::*,
};
#[cfg(feature = "python")]
use crate::db::api::view::{DynamicGraph, IntoDynamic, StaticGraphViewOps};
use hashbrown::HashMap;
use raphtory_api::core::entities::{EID, VID};
use raphtory_storage::graph::edges::edge_storage_ops::EdgeStorageOps;
use std::{
cmp::max,
fmt::{Debug, Display, Formatter},
mem,
sync::Arc,
};
fn slack(edge_index: usize, dual_var: &[i64], edges: &[(usize, usize, i64)]) -> i64 {
let (source_index, target_index, weight) = edges[edge_index];
dual_var[source_index] + dual_var[target_index] - 2 * weight
}
fn blossom_leaves(blossom: usize, num_nodes: usize, blossom_children: &[Vec<usize>]) -> Vec<usize> {
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);
}
}
}
}
out_vec
}
fn assign_label(
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>,
) {
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,
);
}
}
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_eq!(labels[blossom], Some(1));
path.push(blossom);
labels[blossom] = Some(5);
assert_eq!(
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_eq!(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(
base: usize,
edge: usize,
blossom_children: &mut [Vec<usize>],
num_nodes: usize,
edges: &[(usize, usize, i64)],
in_blossoms: &mut [usize],
dual_var: &mut [i64],
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>,
) {
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_eq!(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);
}
}
}
fn expand_blossom(
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: &[i64],
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>,
) {
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 i64;
let j_step: i64;
let endpoint_trick: usize = if i & 1 != 0 {
j -= blossom_children[blossom].len() as i64;
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 i64;
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 i64;
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_eq!(labels[v], Some(2));
assert_eq!(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);
}
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: i64 = i as i64;
let j_step: i64;
let endpoint_trick: usize = if i & 1 != 0 {
j -= blossom_children[blossom].len() as i64;
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_eq!(blossom_base[blossom], Some(node));
}
fn augment_matching(
edge: usize,
num_nodes: usize,
edges: &[(usize, usize, i64)],
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_eq!(labels[blossom_s], Some(1));
assert_eq!(
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_eq!(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_eq!(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, i64)],
endpoints: &[usize],
dual_var: &[i64],
blossom_parents: &[Option<usize>],
blossom_endpoints: &[Vec<usize>],
blossom_base: &[Option<usize>],
mate: &HashMap<usize, usize>,
) {
let dual_var_node_min: i64 = *dual_var[..num_nodes].iter().min().unwrap();
let node_dual_offset: i64 = 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_eq!(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_eq!(blossom_endpoints[blossom].len() % 2, 1);
for p in blossom_endpoints[blossom].iter().skip(1).step_by(2) {
assert_eq!(mate.get(&endpoints[*p]).copied(), Some(p ^ 1));
assert_eq!(mate.get(&endpoints[*p ^ 1]), Some(p));
}
}
}
}
pub fn max_weight_matching<'graph, G: GraphViewOps<'graph>>(
g: &'graph G,
weight_prop: Option<&str>,
max_cardinality: bool,
verify_optimum_flag: bool,
) -> Matching<G> {
let num_edges = g.count_edges();
let num_nodes = g.count_nodes();
if num_edges == 0 {
return Matching::empty(g.clone());
}
let node_map: HashMap<VID, usize> = g
.nodes()
.into_iter()
.enumerate()
.map(|(index, node)| (node.node, index))
.collect();
let mut edges: Vec<(usize, usize, i64)> = Vec::with_capacity(num_edges);
let mut max_weight: i64 = 0;
g.edges().iter().for_each(|edge| {
let weight = match weight_prop {
None => 1,
Some(weight_prop) => edge
.properties()
.get(weight_prop)
.unwrap_or(Prop::I64(1))
.into_i64()
.unwrap_or(1),
};
if weight > max_weight {
max_weight = weight;
};
edges.push((
node_map[&edge.src().node],
node_map[&edge.dst().node],
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<i64> = 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_eq!(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_eq!(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<i64> = 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_eq!(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_eq!(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_eq!(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,
);
}
Matching::from_mates(g.clone(), mate, endpoints)
}
#[derive(Clone)]
pub struct Matching<G> {
graph: G,
forward_map: Arc<HashMap<VID, (VID, EID)>>,
reverse_map: Arc<HashMap<VID, (VID, EID)>>,
}
#[cfg(feature = "python")]
impl<G: StaticGraphViewOps + IntoDynamic> Matching<G> {
pub(crate) fn into_dyn(self) -> Matching<DynamicGraph> {
Matching {
graph: self.graph.into_dynamic(),
forward_map: self.forward_map,
reverse_map: self.reverse_map,
}
}
}
impl<'graph, G: GraphViewOps<'graph>> Debug for Matching<G> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Matching")
.field("forward_map", &self.forward_map)
.field("reverse_map", &self.reverse_map)
.finish()
}
}
impl<'graph, G: GraphViewOps<'graph>> Display for Matching<G> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "Matching([")?;
for (src, dst) in self.edges().id() {
write!(f, "({src}, {dst})")?;
}
write!(f, "])")
}
}
impl<'graph, G: GraphViewOps<'graph>> Matching<G> {
fn empty(graph: G) -> Self {
Matching {
graph,
forward_map: Default::default(),
reverse_map: Default::default(),
}
}
fn from_mates(graph: G, mates: HashMap<usize, usize>, endpoints: Vec<usize>) -> Self {
let mut forward_map = HashMap::with_capacity(mates.len() / 2);
let mut reverse_map = HashMap::with_capacity(mates.len() / 2);
let node_map: Vec<_> = graph.nodes().iter().map(|node| node.node).collect();
let edge_map: Vec<_> = graph.edges().iter().map(|edge| edge.edge.pid()).collect();
for (node, edge) in mates.iter() {
let eid = edge_map[*edge / 2];
if edge % 2 == 0 {
reverse_map.insert(node_map[*node], (node_map[endpoints[*edge]], eid));
} else {
forward_map.insert(node_map[*node], (node_map[endpoints[*edge]], eid));
}
}
Self {
graph,
forward_map: forward_map.into(),
reverse_map: reverse_map.into(),
}
}
pub fn len(&self) -> usize {
self.forward_map.len()
}
pub fn is_empty(&self) -> bool {
self.forward_map.is_empty()
}
pub fn edges_iter<'a>(&'a self) -> impl Iterator<Item = EdgeView<&'a G>>
where
'graph: 'a,
{
let storage = self.graph.core_edges();
self.forward_map
.values()
.map(move |(_, eid)| EdgeView::new(&self.graph, storage.as_ref().edge(*eid).out_ref()))
}
pub fn edges(&self) -> Edges<'graph, G> {
let storage = self.graph.core_graph().clone();
let forward_map = self.forward_map.clone();
let edges_iter = Arc::new(move || {
let storage = storage.clone();
let forward_map = forward_map.clone();
GenLockedIter::from(forward_map, move |forward_map| {
forward_map
.values()
.map(move |(_, eid)| storage.edge_entry(*eid).out_ref())
.into_dyn_boxed()
})
.into_dyn_boxed()
});
Edges {
base_graph: self.graph.clone(),
edges: edges_iter,
}
}
pub fn contains<N: AsNodeRef>(&self, src: N, dst: N) -> bool {
if let Some(src) = self.graph.internalise_node(src.as_node_ref()) {
if let Some(dst) = self.graph.internalise_node(dst.as_node_ref()) {
if let Some((nbr, _)) = self.forward_map.get(&src) {
return nbr == &dst;
}
}
}
false
}
pub fn src<'a>(&'a self, dst: impl AsNodeRef) -> Option<NodeView<'a, &'a G>>
where
'graph: 'a,
{
let dst = (&&self.graph).node(dst)?.node;
let (src, _) = self.reverse_map.get(&dst)?;
Some(NodeView::new_internal(&self.graph, *src))
}
pub fn edge_for_src<'a>(&'a self, src: impl AsNodeRef) -> Option<EdgeView<&'a G>>
where
'graph: 'a,
{
let src = (&&self.graph).node(src)?.node;
let (_, eid) = self.forward_map.get(&src)?;
Some(EdgeView::new(
&self.graph,
self.graph.core_edge(*eid).out_ref(),
))
}
pub fn dst<'a>(&'a self, src: impl AsNodeRef) -> Option<NodeView<'a, &'a G>>
where
'graph: 'a,
{
let src = (&&self.graph).node(src)?.node;
let (dst, _) = self.forward_map.get(&src)?;
Some(NodeView::new_internal(&self.graph, *dst))
}
pub fn edge_for_dst<'a>(&'a self, dst: impl AsNodeRef) -> Option<EdgeView<&'a G>>
where
'graph: 'a,
{
let dst = (&&self.graph).node(dst)?.node;
let (_, eid) = self.reverse_map.get(&dst)?;
Some(EdgeView::new(
&self.graph,
self.graph.core_edge(*eid).out_ref(),
))
}
}
#[cfg(test)]
mod test {
use crate::{algorithms::bipartite::max_weight_matching::max_weight_matching, prelude::*};
use itertools::Itertools;
#[test]
fn test() {
let g = Graph::new();
let vs = vec![(1, 2, 5), (2, 3, 11), (3, 4, 5)];
for (src, dst, weight) in &vs {
g.add_edge(0, *src, *dst, [("weight", Prop::I64(*weight))], None)
.unwrap();
}
let res = max_weight_matching(&g, Some("weight"), false, true);
let maxc_res = max_weight_matching(&g, Some("weight"), true, true);
let matching = res;
let maxc_matching = maxc_res;
assert_eq!(matching.len(), 1);
assert!(matching.contains(2, 3));
assert_eq!(maxc_matching.len(), 2);
assert!(maxc_matching.contains(1, 2));
assert!(maxc_matching.contains(3, 4));
assert_eq!(matching.src(3).unwrap().id(), 2);
assert_eq!(matching.src(2), None);
assert_eq!(matching.dst(2).unwrap().id(), 3);
assert_eq!(matching.dst(3), None);
assert_eq!(matching.edge_for_src(2).unwrap(), g.edge(2, 3).unwrap());
assert_eq!(matching.edge_for_src(1), None);
assert_eq!(matching.edge_for_dst(3).unwrap(), g.edge(2, 3).unwrap());
assert_eq!(matching.edge_for_dst(2), None);
assert_eq!(matching.edges().collect(), vec![g.edge(2, 3).unwrap()]);
assert_eq!(
matching.edges_iter().collect_vec(),
vec![g.edge(2, 3).unwrap()]
);
}
}