use rand::Rng;
use std::collections::HashSet;
#[derive(Debug, Clone)]
pub struct WeightedGraph {
edges: Vec<(usize, usize, f64)>, num_vertices: usize,
}
impl WeightedGraph {
pub fn new(edges: Vec<(usize, usize, f64)>, num_vertices: usize) -> Self {
Self {
edges,
num_vertices,
}
}
}
pub fn solve(graph: &WeightedGraph, num_trials: usize) -> (HashSet<usize>, f64) {
let mut rng = rand::thread_rng();
let mut best_cut = HashSet::new();
let mut best_weight = 0.0;
for _ in 0..num_trials {
let d = (graph.num_vertices as f64).ln().ceil() as usize;
let vectors: Vec<Vec<f64>> = (0..graph.num_vertices)
.map(|_| generate_random_unit_vector(d, &mut rng))
.collect();
let normal = generate_random_unit_vector(d, &mut rng);
let mut cut = HashSet::new();
for (v, vector) in vectors.iter().enumerate() {
let dot_product: f64 = vector.iter().zip(normal.iter()).map(|(&x, &y)| x * y).sum();
if dot_product >= 0.0 {
cut.insert(v);
}
}
let weight = calculate_cut_weight(&cut, graph);
if weight > best_weight {
best_weight = weight;
best_cut = cut;
}
}
(best_cut, best_weight)
}
fn generate_random_unit_vector(dimension: usize, rng: &mut impl Rng) -> Vec<f64> {
let mut vector: Vec<f64> = (0..dimension).map(|_| rng.gen_range(-1.0..1.0)).collect();
let norm: f64 = vector.iter().map(|&x| x * x).sum::<f64>().sqrt();
for x in &mut vector {
*x /= norm;
}
vector
}
fn calculate_cut_weight(cut: &HashSet<usize>, graph: &WeightedGraph) -> f64 {
graph
.edges
.iter()
.filter(|&&(u, v, _)| cut.contains(&u) != cut.contains(&v))
.map(|&(_, _, weight)| weight)
.sum()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_simple_graph() {
let edges = vec![(0, 1, 1.0), (1, 2, 1.0), (2, 0, 1.0)];
let graph = WeightedGraph::new(edges, 3);
let (cut, weight) = solve(&graph, 100);
assert!(!cut.is_empty() && cut.len() < graph.num_vertices);
assert!(weight >= 0.878 * 2.0); }
#[test]
fn test_weighted_graph() {
let edges = vec![(0, 1, 2.0), (1, 2, 1.0), (2, 0, 1.0)];
let graph = WeightedGraph::new(edges, 3);
let (cut, weight) = solve(&graph, 100);
assert!(!cut.is_empty() && cut.len() < graph.num_vertices);
assert!(weight >= 0.878 * 3.0); }
#[test]
fn test_empty_graph() {
let graph = WeightedGraph::new(Vec::new(), 2);
let (cut, weight) = solve(&graph, 10);
assert!(cut.len() <= 1);
assert_eq!(weight, 0.0);
}
}