use scirs2_core::error::CoreResult;
use scirs2_core::random::{rng, Rng, RngExt};
use scirs2_graph::{algorithms, generators, measures, DiGraph, Graph};
use std::time::Instant;
#[test]
#[ignore] #[allow(dead_code)]
fn test_large_erdos_renyi_graph() -> CoreResult<()> {
println!("\n=== Erdős-Rényi Graph Stress Test ===");
let sizes = vec![100_000, 500_000, 1_000_000];
let edge_probability = 0.00001;
for n in sizes {
println!("\nTesting with {n} nodes");
let start = Instant::now();
let gen_start = Instant::now();
let mut rng = scirs2_core::random::rng();
let graph = generators::erdos_renyi_graph(n, edge_probability, &mut rng)
.map_err(|e| scirs2_core::error::CoreError::from(e.to_string()))?;
let gen_time = gen_start.elapsed();
println!(" Generation time: {:.2}s", gen_time.as_secs_f64());
println!(" Nodes: {}", graph.node_count());
println!(" Edges: {}", graph.edge_count());
let density = measures::graph_density(&graph)
.map_err(|e| scirs2_core::error::CoreError::from(e.to_string()))?;
println!(" Density: {density:.6}");
let ops_start = Instant::now();
let max_degree = (0..n).map(|i| graph.degree(&i)).max().unwrap_or(0);
println!(" Max degree: {max_degree}");
if n <= 500_000 {
let cc_start = Instant::now();
let components = algorithms::connected_components(&graph);
println!(
" Connected components: {} ({:.2}s)",
components.len(),
cc_start.elapsed().as_secs_f64()
);
}
println!(
" Operations time: {:.2}s",
ops_start.elapsed().as_secs_f64()
);
println!(" Total time: {:.2}s", start.elapsed().as_secs_f64());
}
Ok(())
}
#[test]
#[ignore]
#[allow(dead_code)]
fn test_large_barabasi_albert_graph() -> CoreResult<()> {
println!("\n=== Barabási-Albert Graph Stress Test ===");
let sizes = vec![100_000, 500_000, 1_000_000];
let m = 3;
for n in sizes {
println!("\nTesting with {n} nodes");
let start = Instant::now();
let gen_start = Instant::now();
let mut rng = scirs2_core::random::rng();
let graph = generators::barabasi_albert_graph(n, m, &mut rng)
.map_err(|e| scirs2_core::error::CoreError::from(e.to_string()))?;
let gen_time = gen_start.elapsed();
println!(" Generation time: {:.2}s", gen_time.as_secs_f64());
println!(" Nodes: {}", graph.node_count());
println!(" Edges: {}", graph.edge_count());
let ops_start = Instant::now();
let degrees: Vec<usize> = (0..graph.node_count()).map(|i| graph.degree(&i)).collect();
let max_degree = degrees.iter().max().unwrap_or(&0);
let avg_degree = degrees.iter().sum::<usize>() as f64 / degrees.len() as f64;
println!(" Max degree: {max_degree}");
println!(" Avg degree: {avg_degree:.2}");
let sample_node = n / 2;
let clustering_start = Instant::now();
let coefficients = measures::clustering_coefficient(&graph)
.map_err(|e| scirs2_core::error::CoreError::from(e.to_string()))?;
let local_clustering = coefficients.get(&sample_node).copied().unwrap_or(0.0);
println!(
" Local clustering (node {}): {:.4} ({:.2}s)",
sample_node,
local_clustering,
clustering_start.elapsed().as_secs_f64()
);
println!(
" Operations time: {:.2}s",
ops_start.elapsed().as_secs_f64()
);
println!(" Total time: {:.2}s", start.elapsed().as_secs_f64());
}
Ok(())
}
#[test]
#[ignore]
#[allow(dead_code)]
fn test_large_grid_graph() -> CoreResult<()> {
println!("\n=== Grid Graph Stress Test ===");
let dimensions = vec![(316, 316), (500, 500), (1000, 1000)];
for (rows, cols) in dimensions {
println!("\nTesting {}x{} grid ({} nodes)", rows, cols, rows * cols);
let start = Instant::now();
let gen_start = Instant::now();
let graph = generators::grid_2d_graph(rows, cols)
.map_err(|e| scirs2_core::error::CoreError::from(e.to_string()))?;
let gen_time = gen_start.elapsed();
println!(" Generation time: {:.2}s", gen_time.as_secs_f64());
println!(" Nodes: {}", graph.node_count());
println!(" Edges: {}", graph.edge_count());
let ops_start = Instant::now();
let source = 0;
let target = graph.node_count() - 1;
let path_start = Instant::now();
let path_result = algorithms::dijkstra_path(&graph, &source, &target)
.map_err(|e| scirs2_core::error::CoreError::from(e.to_string()))?;
let path = path_result.expect("Operation failed").nodes;
println!(
" Shortest path (corner to corner): {} steps ({:.2}s)",
path.len() - 1,
path_start.elapsed().as_secs_f64()
);
if rows * cols <= 250_000 {
let diam_start = Instant::now();
let diameter = estimate_diameter(&graph, 10)?;
println!(
" Estimated diameter: {} ({:.2}s)",
diameter,
diam_start.elapsed().as_secs_f64()
);
}
println!(
" Operations time: {:.2}s",
ops_start.elapsed().as_secs_f64()
);
println!(" Total time: {:.2}s", start.elapsed().as_secs_f64());
}
Ok(())
}
#[test]
#[ignore]
#[allow(dead_code)]
fn test_large_directed_graph_algorithms() -> CoreResult<()> {
println!("\n=== Large Directed Graph Algorithms Test ===");
let n = 100_000;
let _edge_probability = 0.00002;
println!("\nGenerating directed graph with {n} nodes");
let start = Instant::now();
let mut graph: DiGraph<usize, f64, u32> = DiGraph::new();
for i in 0..n {
graph.add_node(i);
}
use scirs2_core::random::prelude::*;
let mut rng = scirs2_core::random::rng();
for i in 1..n {
let num_edges = rng.random_range(1..=5);
for _ in 0..num_edges {
let target = rng.random_range(0..i);
graph
.add_edge(i, target, 1.0)
.map_err(|e| scirs2_core::error::CoreError::from(e.to_string()))?;
}
}
println!(" Generation time: {:.2}s", start.elapsed().as_secs_f64());
println!(" Nodes: {}", graph.node_count());
println!(" Edges: {}", graph.edge_count());
let ops_start = Instant::now();
let scc_start = Instant::now();
let sccs = algorithms::strongly_connected_components(&graph);
println!(
" Strongly connected components: {} ({:.2}s)",
sccs.len(),
scc_start.elapsed().as_secs_f64()
);
let largest_scc_size = sccs.iter().map(|scc| scc.len()).max().unwrap_or(0);
println!(" Largest SCC size: {largest_scc_size}");
match algorithms::topological_sort(&graph) {
Ok(_topo) => println!(" Graph is DAG, topological sort computed"),
Err(_) => println!(" Graph contains cycles"),
}
println!(
" Operations time: {:.2}s",
ops_start.elapsed().as_secs_f64()
);
println!(" Total time: {:.2}s", start.elapsed().as_secs_f64());
Ok(())
}
#[test]
#[ignore]
#[allow(dead_code)]
fn test_memory_efficient_operations() -> CoreResult<()> {
println!("\n=== Memory Efficient Operations Test ===");
let n = 1_000_000;
let m = 5;
println!("\nGenerating graph with {n} nodes");
let start = Instant::now();
let mut rng = scirs2_core::random::rng();
let graph = generators::barabasi_albert_graph(n, m, &mut rng)
.map_err(|e| scirs2_core::error::CoreError::from(e.to_string()))?;
println!(" Generation time: {:.2}s", start.elapsed().as_secs_f64());
println!(" Nodes: {}", graph.node_count());
println!(" Edges: {}", graph.edge_count());
let degree_start = Instant::now();
let mut degree_sum = 0u64;
let mut max_degree = 0usize;
for i in 0..graph.node_count() {
let degree = graph.degree(&i);
degree_sum += degree as u64;
max_degree = max_degree.max(degree);
}
let avg_degree = degree_sum as f64 / graph.node_count() as f64;
println!(
" Degree stats: max={}, avg={:.2} ({:.2}s)",
max_degree,
avg_degree,
degree_start.elapsed().as_secs_f64()
);
let clustering_start = Instant::now();
let sample_size = 1000;
let mut clustering_sum = 0.0;
if let Ok(coefficients) = measures::clustering_coefficient(&graph) {
for _ in 0..sample_size {
let node = rng.random_range(0..graph.node_count());
if let Some(cc) = coefficients.get(&node) {
clustering_sum += cc;
}
}
}
let avg_clustering = clustering_sum / sample_size as f64;
println!(
" Avg clustering coefficient (sampled): {:.4} ({:.2}s)",
avg_clustering,
clustering_start.elapsed().as_secs_f64()
);
let bfs_start = Instant::now();
let start_node = n / 2;
let depth_limit = 3;
let reachable = bfs_with_depth_limit(&graph, start_node, depth_limit)?;
println!(
" Nodes within {} hops of {}: {} ({:.2}s)",
depth_limit,
start_node,
reachable,
bfs_start.elapsed().as_secs_f64()
);
Ok(())
}
#[test]
#[ignore]
#[allow(dead_code)]
fn test_parallel_algorithms_on_large_graphs() -> CoreResult<()> {
println!("\n=== Parallel Algorithms on Large Graphs Test ===");
#[cfg(feature = "parallel")]
{
use scirs2_core::parallel_ops::*;
let n = 500_000;
let edge_probability = 0.00002;
println!("\nGenerating graph with {} nodes", n);
let mut rng = scirs2_core::random::rng();
let graph = generators::erdos_renyi_graph(n, edge_probability, &mut rng)
.map_err(|e| scirs2_core::error::CoreError::from(e.to_string()))?;
println!(" Nodes: {}", graph.node_count());
println!(" Edges: {}", graph.edge_count());
let degree_start = Instant::now();
let degrees: Vec<usize> = (0..graph.node_count())
.into_par_iter()
.map(|i| graph.degree(&i))
.collect();
let max_degree = degrees.par_iter().max().unwrap_or(&0);
println!(
" Parallel degree calculation: max={} ({:.2}s)",
max_degree,
degree_start.elapsed().as_secs_f64()
);
println!(" Parallel PageRank: Skipped (requires DiGraph, current test uses Graph)");
}
#[cfg(not(feature = "parallel"))]
{
println!(" Parallel feature not enabled, skipping parallel tests");
}
Ok(())
}
#[allow(dead_code)]
fn estimate_diameter(graph: &Graph<usize, f64>, samples: usize) -> CoreResult<usize> {
use scirs2_core::random::prelude::*;
let mut rng = scirs2_core::random::rng();
let mut max_distance = 0;
for _ in 0..samples {
let source = rng.random_range(0..graph.node_count());
let bfs_nodes = algorithms::breadth_first_search(graph, &source)
.map_err(|e| scirs2_core::error::CoreError::from(e.to_string()))?;
for (dist_count_, _node) in bfs_nodes.into_iter().enumerate() {
max_distance = max_distance.max(dist_count_);
}
}
Ok(max_distance)
}
#[allow(dead_code)]
fn bfs_with_depth_limit(
graph: &Graph<usize, f64>,
start: usize,
depth_limit: usize,
) -> CoreResult<usize> {
use std::collections::{HashSet, VecDeque};
let mut visited = HashSet::new();
let mut queue = VecDeque::new();
visited.insert(start);
queue.push_back((start, 0));
while let Some((node, depth)) = queue.pop_front() {
if depth >= depth_limit {
continue;
}
if let Ok(neighbors) = graph.neighbors(&node) {
for neighbor in neighbors {
if visited.insert(neighbor) {
queue.push_back((neighbor, depth + 1));
}
}
}
}
Ok(visited.len())
}
#[test]
#[ignore]
#[allow(dead_code)]
fn test_extreme_scale_graph() -> CoreResult<()> {
println!("\n=== Extreme Scale Graph Test (5M nodes) ===");
let n = 5_000_000;
let m = 2;
println!("\nGenerating graph with {n} nodes");
let start = Instant::now();
let mut rng = scirs2_core::random::rng();
let graph = generators::barabasi_albert_graph(n, m, &mut rng)
.map_err(|e| scirs2_core::error::CoreError::from(e.to_string()))?;
let gen_time = start.elapsed();
println!(" Generation time: {:.2}s", gen_time.as_secs_f64());
println!(" Nodes: {}", graph.node_count());
println!(" Edges: {}", graph.edge_count());
println!(
" Memory estimate: ~{:.1} MB",
estimate_memory_usage(graph.node_count(), graph.edge_count())
);
let ops_start = Instant::now();
let sample_size = 10_000;
let mut degree_samples = Vec::with_capacity(sample_size);
let step = n / sample_size;
for i in (0..n).step_by(step) {
degree_samples.push(graph.degree(&i));
}
let max_sampled = degree_samples.iter().max().unwrap_or(&0);
let avg_sampled = degree_samples.iter().sum::<usize>() as f64 / degree_samples.len() as f64;
println!(" Sampled degree stats: max={max_sampled}, avg={avg_sampled:.2}");
println!(
" Operations time: {:.2}s",
ops_start.elapsed().as_secs_f64()
);
println!(" Total time: {:.2}s", start.elapsed().as_secs_f64());
Ok(())
}
#[allow(dead_code)]
fn estimate_memory_usage(nodes: usize, edges: usize) -> f64 {
let node_overhead = nodes * 24; let edge_storage = edges * 16; let total_bytes = node_overhead + edge_storage;
total_bytes as f64 / (1024.0 * 1024.0)
}
#[test]
#[ignore]
#[allow(dead_code)]
fn test_algorithm_scaling() -> CoreResult<()> {
println!("\n=== Algorithm Scaling Analysis ===");
let sizes = vec![10_000, 50_000, 100_000, 200_000];
println!("\nTesting algorithm scaling with graph sizes: {sizes:?}");
for n in sizes {
println!("\n--- Graph size: {n} nodes ---");
let mut rng = scirs2_core::random::rng();
let graph = generators::barabasi_albert_graph(n, 3, &mut rng)
.map_err(|e| scirs2_core::error::CoreError::from(e.to_string()))?;
println!(" Edges: {}", graph.edge_count());
let bfs_start = Instant::now();
let _ = algorithms::breadth_first_search(&graph, &0)
.map_err(|e| scirs2_core::error::CoreError::from(e.to_string()))?;
let bfs_time = bfs_start.elapsed();
println!(" BFS time: {:.3}s", bfs_time.as_secs_f64());
let cc_start = Instant::now();
let _ = algorithms::connected_components(&graph);
let cc_time = cc_start.elapsed();
println!(" Connected components time: {:.3}s", cc_time.as_secs_f64());
}
Ok(())
}