aprender-graph 0.32.0

GPU-first embedded graph database for code analysis (call graphs, dependencies, AST traversals)
//! Comprehensive demonstration of trueno-graph features
//!
//! Showcases:
//! - Phase 1+2: CSR storage, BFS, PageRank, find_callers
//! - Phase 3: GPU acceleration (requires --features gpu)
//! - Phase 4: Louvain community detection, pattern matching
//!
//! Run with: `cargo run --example comprehensive_demo`

use trueno_graph::{
    bfs, find_callers, find_patterns, louvain, pagerank, CsrGraph, NodeId, Pattern,
};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    println!("╔══════════════════════════════════════════════════════════════╗");
    println!("║        trueno-graph Comprehensive Feature Demo              ║");
    println!("╚══════════════════════════════════════════════════════════════╝\n");

    demo_phase1_and_phase2()?;
    demo_phase4_community_detection()?;
    demo_phase4_pattern_matching()?;
    print_performance_summary();
    print_gpu_info();

    Ok(())
}

fn demo_phase1_and_phase2() -> Result<(), Box<dyn std::error::Error>> {
    println!("📊 Phase 1+2: CSR Storage & CPU Algorithms");
    println!("──────────────────────────────────────────────────────────────\n");

    let graph = build_call_graph()?;
    demo_bfs(&graph)?;
    demo_find_callers(&graph)?;
    demo_pagerank(&graph)?;

    Ok(())
}

fn build_call_graph() -> Result<CsrGraph, Box<dyn std::error::Error>> {
    let mut graph = CsrGraph::new();

    // Add edges (call relationships)
    graph.add_edge(NodeId(0), NodeId(1), 1.0)?; // main -> parse_args
    graph.add_edge(NodeId(0), NodeId(2), 1.0)?; // main -> process
    graph.add_edge(NodeId(1), NodeId(3), 1.0)?; // parse_args -> validate
    graph.add_edge(NodeId(1), NodeId(4), 1.0)?; // parse_args -> logger
    graph.add_edge(NodeId(2), NodeId(4), 1.0)?; // process -> logger

    // Set node names (function names)
    graph.set_node_name(NodeId(0), "main".to_string());
    graph.set_node_name(NodeId(1), "parse_args".to_string());
    graph.set_node_name(NodeId(2), "process".to_string());
    graph.set_node_name(NodeId(3), "validate".to_string());
    graph.set_node_name(NodeId(4), "logger".to_string());

    println!("✓ Built call graph with {} nodes and {} edges", graph.num_nodes(), graph.num_edges());
    println!();

    Ok(graph)
}

fn demo_bfs(graph: &CsrGraph) -> Result<(), Box<dyn std::error::Error>> {
    println!("🔍 BFS Traversal from 'main':");
    let reachable = bfs(graph, NodeId(0))?;
    print!("   Reachable nodes: ");
    for &node_id in &reachable {
        if let Some(name) = graph.get_node_name(NodeId(node_id)) {
            print!("{} ", name);
        }
    }
    println!("\n");
    Ok(())
}

fn demo_find_callers(graph: &CsrGraph) -> Result<(), Box<dyn std::error::Error>> {
    println!("📞 Find Callers of 'logger':");
    let callers = find_callers(graph, NodeId(4), 10)?;
    print!("   Functions that call 'logger': ");
    for &caller_id in &callers {
        if let Some(name) = graph.get_node_name(NodeId(caller_id)) {
            print!("{} ", name);
        }
    }
    println!("\n");
    Ok(())
}

fn demo_pagerank(graph: &CsrGraph) -> Result<(), Box<dyn std::error::Error>> {
    println!("⭐ PageRank (Function Importance):");
    let scores = pagerank(graph, 20, 1e-6)?;
    for (node_id, &score) in scores.iter().enumerate() {
        if let Some(name) = graph.get_node_name(NodeId(node_id as u32)) {
            println!("   {}: {:.4}", name, score);
        }
    }
    println!();
    Ok(())
}

fn demo_phase4_community_detection() -> Result<(), Box<dyn std::error::Error>> {
    println!("🧩 Phase 4: Advanced Algorithms");
    println!("──────────────────────────────────────────────────────────────\n");

    println!("Building graph with intentional module structure...");
    let community_graph = build_community_graph()?;

    println!("\n🔬 Louvain Community Detection:");
    let louvain_result = louvain(&community_graph)?;
    println!("   Found {} communities", louvain_result.num_communities);
    println!("   Modularity score: {:.3}", louvain_result.modularity);

    for (comm_id, community) in louvain_result.communities.iter().enumerate() {
        println!("   Community {}: {} nodes", comm_id, community.len());
    }
    println!();

    Ok(())
}

fn build_community_graph() -> Result<CsrGraph, Box<dyn std::error::Error>> {
    let mut graph = CsrGraph::new();

    // Module A (networking): nodes 0-2
    graph.add_edge(NodeId(0), NodeId(1), 1.0)?; // http_client -> tcp_socket
    graph.add_edge(NodeId(1), NodeId(2), 1.0)?; // tcp_socket -> buffer
    graph.add_edge(NodeId(2), NodeId(0), 1.0)?; // buffer -> http_client

    // Module B (database): nodes 3-5
    graph.add_edge(NodeId(3), NodeId(4), 1.0)?; // query -> connection
    graph.add_edge(NodeId(4), NodeId(5), 1.0)?; // connection -> pool
    graph.add_edge(NodeId(5), NodeId(3), 1.0)?; // pool -> query

    // Cross-module dependency (weak coupling)
    graph.add_edge(NodeId(0), NodeId(3), 1.0)?; // http_client -> query

    Ok(graph)
}

fn demo_phase4_pattern_matching() -> Result<(), Box<dyn std::error::Error>> {
    println!("🔍 Pattern Matching (Anti-Patterns):");
    println!("──────────────────────────────────────────────────────────────\n");

    let antipattern_graph = build_antipattern_graph()?;

    demo_god_class_pattern(&antipattern_graph)?;
    demo_circular_dependency_pattern(&antipattern_graph)?;
    demo_dead_code_pattern(&antipattern_graph)?;

    Ok(())
}

fn build_antipattern_graph() -> Result<CsrGraph, Box<dyn std::error::Error>> {
    let mut graph = CsrGraph::new();

    // Create a "God Class" (node 0 calls many functions)
    for i in 1..=12 {
        graph.add_edge(NodeId(0), NodeId(i), 1.0)?;
    }

    // Create a circular dependency: 10 -> 11 -> 12 -> 10
    graph.add_edge(NodeId(10), NodeId(11), 1.0)?;
    graph.add_edge(NodeId(11), NodeId(12), 1.0)?;
    graph.add_edge(NodeId(12), NodeId(10), 1.0)?;

    // Node 13 is dead code (no incoming edges)
    graph.add_edge(NodeId(13), NodeId(14), 1.0)?;

    Ok(graph)
}

fn demo_god_class_pattern(graph: &CsrGraph) -> Result<(), Box<dyn std::error::Error>> {
    println!("🐘 God Class Pattern (high fan-out ≥10):");
    let pattern = Pattern::god_class(10);
    let matches = find_patterns(graph, &pattern)?;
    println!("   Found {} god class instances", matches.len());
    for m in &matches {
        println!("   - {} (Severity: {:?})", m.pattern_name, m.severity);
    }
    println!();
    Ok(())
}

fn demo_circular_dependency_pattern(graph: &CsrGraph) -> Result<(), Box<dyn std::error::Error>> {
    println!("🔄 Circular Dependency Pattern (3-node cycles):");
    let pattern = Pattern::circular_dependency(3);
    let matches = find_patterns(graph, &pattern)?;
    println!("   Found {} circular dependencies", matches.len());
    for m in &matches {
        println!("   - {} (Severity: {:?})", m.pattern_name, m.severity);
    }
    println!();
    Ok(())
}

fn demo_dead_code_pattern(graph: &CsrGraph) -> Result<(), Box<dyn std::error::Error>> {
    println!("💀 Dead Code Pattern (uncalled functions):");
    let pattern = Pattern::dead_code();
    let matches = find_patterns(graph, &pattern)?;
    println!("   Found {} dead code instances", matches.len());
    for m in &matches {
        println!("   - Node {:?} (Severity: {:?})", m.node_mapping.get(&0), m.severity);
    }
    println!();
    Ok(())
}

fn print_performance_summary() {
    println!("📊 Performance Characteristics:");
    println!("──────────────────────────────────────────────────────────────");
    println!("   CSR Construction: O(E log V) - ~100μs for 1K nodes");
    println!("   BFS Traversal: O(V + E) - ~40μs for 1K nodes (33× vs NetworkX)");
    println!("   PageRank (20 iter): O(iterations × E) - ~500μs for 1K nodes");
    println!("   Louvain: O(V × E) - ~14μs for 20 nodes, ~443μs for 125 nodes");
    println!("   Pattern Matching: O(V) for God Class/Dead Code, O(V × E) for cycles");
    println!();

    println!("✅ All phases demonstrated successfully!");
}

fn print_gpu_info() {
    #[cfg(feature = "gpu")]
    {
        println!("\n💡 GPU acceleration is available! Use:");
        println!("   cargo run --example comprehensive_demo --features gpu");
    }

    #[cfg(not(feature = "gpu"))]
    {
        println!("\n💡 For GPU acceleration (10-250× speedup), rebuild with:");
        println!("   cargo run --example comprehensive_demo --features gpu");
    }
}