#[cfg(feature = "gpu")]
use scirs2_core::ndarray::{compat::ArrayStatCompat, Array, Array1};
#[cfg(feature = "gpu")]
use scirs2_special::array_ops::{
convenience::{self, ConfigBuilder},
ArrayConfig, Backend,
};
#[cfg(feature = "gpu")]
use statrs::statistics::Statistics;
#[cfg(feature = "gpu")]
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("=== SCIRS2-SPECIAL Advanced Array Operations Demo ===\n");
demo_basic_operations().await?;
demo_configuration_options().await?;
#[cfg(feature = "lazy")]
demo_lazy_evaluation().await?;
#[cfg(feature = "gpu")]
demo_gpu_acceleration().await?;
demo_large_array_processing().await?;
demo_batch_processing().await?;
demo_memory_efficient_operations().await?;
println!("=== Advanced array operations demo completed successfully! ===");
Ok(())
}
#[cfg(not(feature = "gpu"))]
fn main() {
println!("This example requires the 'gpu' feature to be enabled.");
println!("Please run with: cargo run --features gpu --example advanced_array_operations");
}
#[cfg(feature = "gpu")]
async fn demo_basic_operations() -> Result<(), Box<dyn std::error::Error>> {
println!("1. Basic Array Operations");
println!("========================");
let input_1d = Array1::linspace(1.0, 5.0, 5);
println!("Input 1D array: {:?}", input_1d);
let result_1d = convenience::gamma_1d(&input_1d).await?;
println!("Gamma(input): {:?}", result_1d);
let input_2d = Array::from_shape_vec((2, 3), vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0])?;
println!("\nInput 2D array:\n{:?}", input_2d);
let result_2d = convenience::gamma_2d(&input_2d).await?;
println!("Gamma(input) 2D:\n{:?}", result_2d);
let besselinput = Array1::linspace(0.0, 5.0, 6);
let bessel_result = convenience::j0_1d(&besselinput)?;
println!("\nBessel J0({:?}) = {:?}", besselinput, bessel_result);
let erfinput = Array1::linspace(-2.0, 2.0, 5);
let erf_result = convenience::erf_1d(&erfinput)?;
println!("erf({:?}) = {:?}", erfinput, erf_result);
println!();
Ok(())
}
#[cfg(feature = "gpu")]
async fn demo_configuration_options() -> Result<(), Box<dyn std::error::Error>> {
println!("2. Configuration Options and Backend Selection");
println!("=============================================");
let custom_config = ConfigBuilder::new()
.chunksize(512)
.parallel(true)
.memory_limit(512 * 1024 * 1024) .lazy_threshold(1000)
.build();
println!(
"Custom config: chunksize={}, parallel={}, memory_limit={}MB",
custom_config.chunksize,
custom_config.parallel,
custom_config.memory_limit / (1024 * 1024)
);
let input = Array1::linspace(1.0, 4.0, 4);
let result = convenience::gamma_1d_with_config(&input, &custom_config).await?;
println!("Gamma with custom config: {:?}", result);
let large_config = convenience::large_array_config();
println!(
"\nLarge array config: chunksize={}, lazy_threshold={}",
large_config.chunksize, large_config.lazy_threshold
);
let small_config = convenience::small_array_config();
println!(
"Small array config: chunksize={}, lazy_threshold={}",
small_config.chunksize, small_config.lazy_threshold
);
let backends = vec![Backend::Cpu];
#[cfg(feature = "lazy")]
let backends = {
let mut b = backends;
b.push(Backend::Lazy);
b
};
#[cfg(feature = "gpu")]
let backends = {
let mut b = backends;
b.push(Backend::Gpu);
b
};
for backend in backends {
let config = ArrayConfig {
backend: backend.clone(),
..Default::default()
};
println!("Testing backend: {:?}", backend);
let testinput = Array1::from_vec(vec![1.0, 2.0, 3.0]);
let result = convenience::gamma_1d_with_config(&testinput, &config).await?;
println!(" Result: {:?}", result);
}
println!();
Ok(())
}
#[cfg(feature = "lazy")]
async fn demo_lazy_evaluation() -> Result<(), Box<dyn std::error::Error>> {
println!("3. Lazy Evaluation");
println!("==================");
let largeinput = Array::linspace(1.0, 100.0, 10000);
println!("Created large array with {} elements", largeinput.len());
let lazy_gamma = convenience::gamma_lazy(&largeinput, None)?;
println!("Lazy computation created: {}", lazy_gamma.description());
println!("Cost estimate: {} units", lazy_gamma.cost_estimate());
println!("Is computed: {}", lazy_gamma.is_computed());
println!("Computing lazily...");
let start_time = std::time::Instant::now();
let result = lazy_gamma.compute()?;
let duration = start_time.elapsed();
println!("Computation completed in {:?}", duration);
println!("Result shape: {:?}", result.shape());
println!(
"First 5 values: {:?}",
&result.as_slice().expect("Operation failed")[0..5]
);
println!("\nTesting computation caching...");
let lazy_gamma2 = convenience::gamma_lazy(&largeinput, None)?;
let start_time2 = std::time::Instant::now();
let _result2 = lazy_gamma2.compute()?;
let _result2_cached = lazy_gamma2.compute()?; let duration2 = start_time2.elapsed();
println!("Second computation (with caching) took: {:?}", duration2);
println!();
Ok(())
}
#[cfg(feature = "gpu")]
async fn demo_gpu_acceleration() -> Result<(), Box<dyn std::error::Error>> {
println!("4. GPU Acceleration");
println!("==================");
let gpuinput = Array1::linspace(1.0, 10.0, 1000);
println!("Processing array of {} elements on GPU", gpuinput.len());
match convenience::gamma_gpu(&gpuinput).await {
Ok(gpu_result) => {
println!("GPU computation successful!");
println!("Result shape: {:?}", gpu_result.shape());
println!(
"First 5 values: {:?}",
&gpu_result.as_slice().expect("Operation failed")[0..5]
);
let cpu_result = convenience::gamma_1d(&gpuinput).await?;
let max_diff = gpu_result
.iter()
.zip(cpu_result.iter())
.map(|(a, b)| (a - b).abs())
.fold(0.0, f64::max);
println!("Maximum difference between GPU and CPU: {:.2e}", max_diff);
}
Err(e) => {
println!("GPU computation failed (falling back to CPU): {}", e);
let cpu_result = convenience::gamma_1d(&gpuinput).await?;
println!("CPU fallback result computed successfully");
println!("Result shape: {:?}", cpu_result.shape());
}
}
println!();
Ok(())
}
#[cfg(feature = "gpu")]
async fn demo_large_array_processing() -> Result<(), Box<dyn std::error::Error>> {
println!("5. Large Array Processing");
println!("=========================");
let large_array = Array::linspace(0.1, 10.0, 50000);
println!("Processing large array with {} elements", large_array.len());
let config = convenience::large_array_config();
let start_time = std::time::Instant::now();
let result = convenience::gamma_1d_with_config(&large_array, &config).await?;
let duration = start_time.elapsed();
println!("Large array processing completed in {:?}", duration);
println!("Result statistics:");
println!(
" Min: {:.6}",
result.iter().fold(f64::INFINITY, |a, &b| a.min(b))
);
println!(
" Max: {:.6}",
result.iter().fold(f64::NEG_INFINITY, |a, &b| a.max(b))
);
println!(" Mean: {:.6}", result.clone().mean());
use scirs2_special::array_ops::memory_efficient;
let memory_usage = memory_efficient::estimate_memory_usage::<f64>(result.shape(), 2);
println!(
"Estimated memory usage: {:.2} MB",
memory_usage as f64 / (1024.0 * 1024.0)
);
println!();
Ok(())
}
#[cfg(feature = "gpu")]
async fn demo_batch_processing() -> Result<(), Box<dyn std::error::Error>> {
println!("6. Batch Processing");
println!("==================");
let arrays = vec![
Array1::linspace(1.0, 5.0, 100),
Array1::linspace(2.0, 6.0, 100),
Array1::linspace(3.0, 7.0, 100),
Array1::linspace(0.5, 4.5, 100),
];
println!("Processing batch of {} arrays", arrays.len());
let config = ArrayConfig::default();
let start_time = std::time::Instant::now();
let results = convenience::batch_gamma(&arrays, &config).await?;
let duration = start_time.elapsed();
println!("Batch processing completed in {:?}", duration);
println!("Results summary:");
for (i, result) in results.iter().enumerate() {
let mean = result.mean_or(0.0);
println!(" Array {}: mean = {:.6}", i + 1, mean);
}
println!();
Ok(())
}
#[cfg(feature = "gpu")]
async fn demo_memory_efficient_operations() -> Result<(), Box<dyn std::error::Error>> {
println!("7. Memory-Efficient Operations");
println!("==============================");
let shape = (1000, 100);
let array_2d = Array::ones(shape);
println!("Created 2D array with shape {:?}", shape);
use scirs2_special::array_ops::memory_efficient;
let memory_needed = memory_efficient::estimate_memory_usage::<f64>(
array_2d.shape(),
3, );
println!(
"Estimated memory needed: {:.2} MB",
memory_needed as f64 / (1024.0 * 1024.0)
);
let config = ArrayConfig::default();
let within_limit = memory_efficient::check_memory_limit::<f64>(array_2d.shape(), 3, &config);
println!("Within memory limit: {}", within_limit);
use scirs2_special::array_ops::vectorized;
let chunked_result = vectorized::process_chunks(&array_2d, &config, |x: f64| x * 2.0 + 1.0)?;
println!("Chunked processing completed");
println!("Result shape: {:?}", chunked_result.shape());
println!(
"Sample values: {:?}",
&chunked_result.as_slice().expect("Operation failed")[0..5]
);
#[cfg(feature = "parallel")]
{
let parallelinput = Array1::linspace(-1.0, 1.0, 10000);
println!("\nParallel vs Sequential processing comparison:");
let start_time = std::time::Instant::now();
let _seq_result = convenience::erf_1d(¶llelinput)?;
let seq_duration = start_time.elapsed();
let start_time = std::time::Instant::now();
let _par_result = convenience::erf_parallel(¶llelinput)?;
let par_duration = start_time.elapsed();
println!(" Sequential: {:?}", seq_duration);
println!(" Parallel: {:?}", par_duration);
println!(
" Speedup: {:.2}x",
seq_duration.as_secs_f64() / par_duration.as_secs_f64()
);
}
println!();
Ok(())
}