use rustygraph::*;
use rustygraph::advanced::{WaveletFeatures, AdvancedFeatures};
use rustygraph::lazy::LazyFeatureBuilder;
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("=== RustyGraph Advanced Features Example ===\n");
println!("1. LAZY EVALUATION");
println!("──────────────────");
let series = TimeSeries::from_raw(datasets::sine_wave(100, 2.0, 1.0))?;
let graph = VisibilityGraph::from_series(&series)
.natural_visibility()?
.with_lazy_metrics();
println!("Graph created with lazy metrics");
println!("First access computes and caches...");
let start = std::time::Instant::now();
let cc1 = graph.average_clustering_coefficient();
let time1 = start.elapsed();
println!(" Clustering: {:.4} (computed in {:?})", cc1, time1);
println!("Second access uses cache...");
let start = std::time::Instant::now();
let cc2 = graph.average_clustering_coefficient();
let time2 = start.elapsed();
println!(" Clustering: {:.4} (cached in {:?})", cc2, time2);
println!(" Speedup: {:.2}x", time1.as_nanos() as f64 / time2.as_nanos() as f64);
println!("\n2. WAVELET MULTI-SCALE ANALYSIS");
println!("────────────────────────────────");
let data = datasets::multi_frequency(128, &[1.0, 4.0, 8.0]);
println!("Multi-frequency signal: [1Hz, 4Hz, 8Hz]");
let (approx, detail) = WaveletFeatures::haar_transform(&data);
println!("\nHaar transform:");
println!(" Approximation coefficients: {}", approx.len());
println!(" Detail coefficients: {}", detail.len());
let details = WaveletFeatures::multi_level_decomposition(&data, 3);
println!("\nMulti-level decomposition (3 levels):");
for (level, coeffs) in details.iter().enumerate() {
let energy = coeffs.iter().map(|&x| x * x).sum::<f64>();
println!(" Level {}: {} coeffs, energy = {:.2}", level + 1, coeffs.len(), energy);
}
println!("\nEnergy by scale:");
for level in 0..3 {
let energy = WaveletFeatures::wavelet_energy(&data, level);
println!(" Scale {}: {:.2}", level + 1, energy);
}
println!("\n3. COMPLEXITY METRICS");
println!("─────────────────────");
let patterns = vec![
("Random Walk", datasets::random_walk(100, 42)),
("Chaotic (Logistic)", datasets::logistic_map(100, 3.9, 0.5)),
("Periodic (Sine)", datasets::sine_wave(100, 2.0, 1.0)),
("Trend", datasets::trend_with_noise(100, 0.1, 0.1, 42)),
];
for (name, data) in &patterns {
let max_val = data.iter().fold(0.0_f64, |acc, &x| acc.max(x.abs()));
let entropy = AdvancedFeatures::sample_entropy(data, 2, 0.2 * max_val);
let hurst = AdvancedFeatures::hurst_exponent(data);
println!("{}", name);
println!(" Sample Entropy: {:.4} (higher = more complex)", entropy);
println!(" Hurst Exponent: {:.4} (0.5=random, >0.5=persistent, <0.5=anti-persistent)", hurst);
let hurst_interp = if (hurst - 0.5).abs() < 0.1 {
"random/Brownian"
} else if hurst > 0.5 {
"persistent/trending"
} else {
"anti-persistent/mean-reverting"
};
println!(" → {}", hurst_interp);
println!();
}
println!("4. ADVANCED FEATURES + VISIBILITY GRAPHS");
println!("─────────────────────────────────────────");
for (name, data) in patterns.iter().take(2) {
let series = TimeSeries::from_raw(data.clone())?;
let graph = VisibilityGraph::from_series(&series)
.natural_visibility()?;
let density = graph.density();
let clustering = graph.average_clustering_coefficient();
let entropy = AdvancedFeatures::sample_entropy(data, 2, 0.2);
let hurst = AdvancedFeatures::hurst_exponent(data);
println!("{}", name);
println!(" Graph density: {:.4}", density);
println!(" Clustering: {:.4}", clustering);
println!(" Entropy: {:.4}", entropy);
println!(" Hurst: {:.4}", hurst);
println!(" → Complexity-density correlation: {:.4}",
(entropy * density).sqrt());
println!();
}
println!("5. LAZY FEATURE COMPUTATION");
println!("───────────────────────────");
let series_data = vec![Some(1.0), Some(2.0), Some(3.0), Some(4.0), Some(5.0)];
let lazy_builder = LazyFeatureBuilder::new(series_data);
println!("Computing features on-demand:");
let _f1 = lazy_builder.get_feature(2, "delta", |s, i| {
println!(" Computing delta for node {}...", i);
if i > 0 && i < s.len() {
match (s[i], s[i - 1]) {
(Some(curr), Some(prev)) => Some(curr - prev),
_ => None,
}
} else {
None
}
});
let _f2 = lazy_builder.get_feature(2, "delta", |s, i| {
println!(" Computing delta for node {} (should not see this)", i);
if i > 0 && i < s.len() {
match (s[i], s[i - 1]) {
(Some(curr), Some(prev)) => Some(curr - prev),
_ => None,
}
} else {
None
}
});
println!("Cache size: {} features", lazy_builder.cache_size());
#[cfg(feature = "advanced-features")]
{
println!("\n6. FREQUENCY DOMAIN FEATURES");
println!("────────────────────────────");
println!("(Requires 'advanced-features' flag)");
use rustygraph::advanced::FrequencyFeatures;
let data = datasets::multi_frequency(64, &[2.0, 5.0]);
let dominant = FrequencyFeatures::dominant_frequency(&data, 32, 64);
println!("Dominant frequency index: {}", dominant);
let energy_low = FrequencyFeatures::spectral_energy(&data, 32, 64, 1, 10);
let energy_high = FrequencyFeatures::spectral_energy(&data, 32, 64, 10, 20);
println!("Low frequency energy: {:.2}", energy_low);
println!("High frequency energy: {:.2}", energy_high);
}
#[cfg(not(feature = "advanced-features"))]
{
println!("\n6. FREQUENCY DOMAIN FEATURES");
println!("────────────────────────────");
println!("Not available (requires 'advanced-features' cargo flag)");
println!("Run with: cargo run --example advanced_optimization --features advanced-features");
}
println!("\n7. SUMMARY");
println!("──────────");
println!("✓ Lazy evaluation provides caching speedup");
println!("✓ Wavelet analysis enables multi-scale patterns");
println!("✓ Complexity metrics (entropy, Hurst) characterize dynamics");
println!("✓ Advanced features complement visibility graph analysis");
println!("✓ On-demand computation reduces memory usage");
Ok(())
}