leiden-rs 0.7.0

High-performance Leiden community detection algorithm for graphs in Rust
Documentation
use leiden_rs::resolution::resolution_scan;
use leiden_rs::{GraphDataBuilder, Leiden, LeidenConfig, QualityType};

fn main() {
    println!("=== Parallel vs Sequential Equivalence Test ===");

    // Test 1: Small graph (uses sequential path)
    println!("\nTest 1: Small graph - sequential path (50 nodes, 100 edges)");
    let mut b1 = GraphDataBuilder::new(50);
    let mut edge_count = 0;
    for u in 0..50 {
        for v in (u + 1)..50 {
            if edge_count < 100 {
                b1.add_edge(u, v, 1.0).unwrap();
                edge_count += 1;
            }
        }
    }
    let small_graph = b1.build().unwrap();
    let leiden_small = Leiden::new(LeidenConfig {
        seed: Some(42),
        resolution: 1.0,
        quality: QualityType::Modularity,
        ..Default::default()
    });
    let result_small = leiden_small.run(&small_graph).unwrap();
    println!("✓ PASS: Small graph runs (sequential path)");
    println!(
        "  Communities: {}, Quality: {:.4}",
        result_small.partition.num_communities(),
        result_small.quality
    );

    // Test 2: Medium graph (uses parallel path)
    println!("\nTest 2: Medium graph - parallel path (200 nodes, 2500 edges)");
    let mut b2 = GraphDataBuilder::new(200);
    let mut edge_count = 0;
    for u in 0..200 {
        for v in (u + 1)..200 {
            if edge_count < 2500 {
                b2.add_edge(u, v, 1.0).unwrap();
                edge_count += 1;
            }
        }
    }
    let medium_graph = b2.build().unwrap();
    let leiden_medium = Leiden::new(LeidenConfig {
        seed: Some(42),
        resolution: 1.0,
        quality: QualityType::Modularity,
        ..Default::default()
    });
    let result_medium = leiden_medium.run(&medium_graph).unwrap();
    println!("✓ PASS: Medium graph runs (parallel path)");
    println!(
        "  Communities: {}, Quality: {:.4}",
        result_medium.partition.num_communities(),
        result_medium.quality
    );

    // Test 3: Large graph (parallel path + aggregation)
    println!("\nTest 3: Large graph - parallel + aggregation (400 nodes, 12000 edges)");
    let mut b3 = GraphDataBuilder::new(400);
    let mut edge_count = 0;
    for u in 0..400 {
        for v in (u + 1)..400 {
            if edge_count < 12000 {
                b3.add_edge(u, v, 1.0).unwrap();
                edge_count += 1;
            }
        }
    }
    let large_graph = b3.build().unwrap();
    let leiden_large = Leiden::new(LeidenConfig {
        seed: Some(42),
        resolution: 1.0,
        quality: QualityType::Modularity,
        ..Default::default()
    });
    let result_large = leiden_large.run(&large_graph).unwrap();
    println!("✓ PASS: Large graph runs (parallel + aggregation)");
    println!(
        "  Communities: {}, Quality: {:.4}",
        result_large.partition.num_communities(),
        result_large.quality
    );

    // Test 4: Resolution scan (tests parallel resolution scan)
    println!("\nTest 4: Resolution scan with parallel execution");
    let scan_results = resolution_scan(
        &medium_graph,
        QualityType::Modularity,
        (0.1, 2.0),
        5,
        Some(42),
    )
    .unwrap();
    println!("✓ PASS: Resolution scan completed");
    println!("  Generated {} profile entries", scan_results.len());
    for (i, entry) in scan_results.iter().enumerate() {
        println!(
            "    Entry {}: gamma={:.2}, communities={}, quality={:.4}",
            i, entry.resolution, entry.num_communities, entry.quality
        );
    }

    // Test 5: Verify reproducibility across runs
    println!("\nTest 5: Reproducibility - same seed on medium graph");
    let leiden_repeat = Leiden::new(LeidenConfig {
        seed: Some(42),
        resolution: 1.0,
        quality: QualityType::Modularity,
        ..Default::default()
    });
    let result_repeat = leiden_repeat.run(&medium_graph).unwrap();

    let p1 = result_medium.partition.as_slice();
    let p2 = result_repeat.partition.as_slice();

    if p1 == p2 {
        println!("✓ PASS: Reproducibility maintained");
        println!(
            "  Communities: {}, Quality: {:.4}",
            result_repeat.partition.num_communities(),
            result_repeat.quality
        );
    } else {
        println!("✗ FAIL: Same seed produced different results!");
        std::process::exit(1);
    }

    println!("\n=== All parallel/sequential tests PASSED ===");
}