ruvector-mincut 2.0.6

World's first subpolynomial dynamic min-cut: self-healing networks, AI optimization, real-time graph analysis
Documentation
//! End-to-end integration tests for the minimum cut implementation

use ruvector_mincut::{
    BoundedInstance, CommunityDetector, DynamicGraph, GraphPartitioner, MinCutWrapper,
    ProperCutInstance, RuVectorGraphAnalyzer,
};
use std::sync::Arc;

#[test]
fn test_wrapper_with_bounded_instance() {
    let graph = Arc::new(DynamicGraph::new());

    // Build a triangle
    graph.insert_edge(0, 1, 1.0).unwrap();
    graph.insert_edge(1, 2, 1.0).unwrap();
    graph.insert_edge(2, 0, 1.0).unwrap();

    let mut wrapper = MinCutWrapper::with_factory(Arc::clone(&graph), |g, min, max| {
        Box::new(BoundedInstance::init(g, min, max))
    });

    // Sync edges
    for edge in graph.edges() {
        wrapper.insert_edge(edge.id, edge.source, edge.target);
    }

    let result = wrapper.query();
    assert!(result.is_connected());
    assert_eq!(result.value(), 2);
}

#[test]
fn test_dynamic_updates_bounded() {
    let graph = Arc::new(DynamicGraph::new());

    let mut wrapper = MinCutWrapper::with_factory(Arc::clone(&graph), |g, min, max| {
        Box::new(BoundedInstance::init(g, min, max))
    });

    // Start with 2 vertices connected
    let e1 = graph.insert_edge(0, 1, 1.0).unwrap();
    wrapper.insert_edge(e1, 0, 1);

    assert_eq!(wrapper.query().value(), 1);

    // Add parallel edge
    let e2 = graph.insert_edge(0, 1, 1.0);
    if let Ok(e2) = e2 {
        wrapper.insert_edge(e2, 0, 1);
    }

    // Add third vertex
    let e3 = graph.insert_edge(1, 2, 1.0).unwrap();
    wrapper.insert_edge(e3, 1, 2);

    let result = wrapper.query();
    assert!(result.is_connected());
}

#[test]
fn test_disconnected_graph() {
    let graph = Arc::new(DynamicGraph::new());

    // Two separate components
    graph.insert_edge(0, 1, 1.0).unwrap();
    graph.insert_edge(2, 3, 1.0).unwrap();

    let mut wrapper = MinCutWrapper::with_factory(Arc::clone(&graph), |g, min, max| {
        Box::new(BoundedInstance::init(g, min, max))
    });

    for edge in graph.edges() {
        wrapper.insert_edge(edge.id, edge.source, edge.target);
    }

    let result = wrapper.query();
    assert!(!result.is_connected() || result.value() == 0);
}

#[test]
fn test_community_detection_full_pipeline() {
    let graph = Arc::new(DynamicGraph::new());

    // Create two dense clusters connected by weak link
    // Cluster 1: 0-1-2-0 (triangle)
    graph.insert_edge(0, 1, 1.0).unwrap();
    graph.insert_edge(1, 2, 1.0).unwrap();
    graph.insert_edge(2, 0, 1.0).unwrap();

    // Cluster 2: 3-4-5-3 (triangle)
    graph.insert_edge(3, 4, 1.0).unwrap();
    graph.insert_edge(4, 5, 1.0).unwrap();
    graph.insert_edge(5, 3, 1.0).unwrap();

    // Weak bridge
    graph.insert_edge(2, 3, 0.1).unwrap();

    let mut detector = CommunityDetector::new(graph);
    let communities = detector.detect(2);

    // Should detect structure
    assert!(!communities.is_empty());
}

#[test]
fn test_graph_partitioner_full_pipeline() {
    let graph = Arc::new(DynamicGraph::new());

    // Line graph: 0-1-2-3-4
    for i in 0..4u64 {
        graph.insert_edge(i, i + 1, 1.0).unwrap();
    }

    let partitioner = GraphPartitioner::new(graph, 2);
    let partitions = partitioner.partition();

    // Verify partitioning produces reasonable results
    assert!(
        partitions.len() >= 1 && partitions.len() <= 5,
        "Partitions should be between 1 and 5, got {}",
        partitions.len()
    );
    let total: usize = partitions.iter().map(|p| p.len()).sum();
    assert!(
        total >= 1 && total <= 5,
        "Total vertices should be 5 or fewer, got {}",
        total
    );
}

#[test]
fn test_analyzer_with_wrapper() {
    let graph = Arc::new(DynamicGraph::new());

    // Star graph: center 0 connected to 1,2,3,4
    for i in 1..5u64 {
        graph.insert_edge(0, i, 1.0).unwrap();
    }

    let mut analyzer = RuVectorGraphAnalyzer::new(graph);
    let min_cut = analyzer.min_cut();

    // Star graph has min cut = 1 (any leaf)
    assert_eq!(min_cut, 1);
}

#[test]
fn test_large_graph_performance() {
    let graph = Arc::new(DynamicGraph::new());

    // Create a larger graph: path of 100 vertices
    for i in 0..99u64 {
        graph.insert_edge(i, i + 1, 1.0).unwrap();
    }

    let mut wrapper = MinCutWrapper::with_factory(Arc::clone(&graph), |g, min, max| {
        Box::new(BoundedInstance::init(g, min, max))
    });

    for edge in graph.edges() {
        wrapper.insert_edge(edge.id, edge.source, edge.target);
    }

    let result = wrapper.query();
    assert!(result.is_connected());
    assert_eq!(result.value(), 1); // Path has min cut = 1
}