mod common;
use amari_core::Multivector;
use amari_gpu::{
AdaptiveVerificationLevel, AdaptiveVerifier, GpuBoundaryVerifier, GpuCliffordAlgebra,
PlatformCapabilities, StatisticalGpuVerifier, VerificationConfig, VerificationPlatform,
VerificationStrategy, VerifiedMultivector,
};
use common::direct_gpu_runtime_available;
use std::time::Duration;
#[tokio::test]
async fn test_verified_multivector_operations() {
let mv1 =
Multivector::<3, 0, 0>::from_coefficients(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0]);
let mv2 =
Multivector::<3, 0, 0>::from_coefficients(vec![2.0, 1.0, 4.0, 3.0, 6.0, 5.0, 8.0, 7.0]);
let verified1 = VerifiedMultivector::new(mv1);
let verified2 = VerifiedMultivector::new(mv2);
assert_eq!(VerifiedMultivector::<3, 0, 0>::signature(), (3, 0, 0));
assert!(verified1.verify_invariants().is_ok());
assert!(verified2.verify_invariants().is_ok());
assert_eq!(verified1.inner().get(0), 1.0);
assert_eq!(verified2.inner().get(1), 1.0);
}
#[tokio::test]
async fn test_boundary_verification_small_batch() {
if !direct_gpu_runtime_available() {
println!("Skipping GPU boundary verification test in this environment");
return;
}
let config = VerificationConfig {
strategy: VerificationStrategy::Boundary,
performance_budget: Duration::from_millis(100),
tolerance: 1e-12,
enable_invariant_checking: true,
};
let mut verifier = GpuBoundaryVerifier::new(config);
let batch_size = 5;
let mut a_batch = Vec::new();
let mut b_batch = Vec::new();
for i in 0..batch_size {
let a = Multivector::<3, 0, 0>::from_coefficients(vec![
i as f64, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
]);
let b = Multivector::<3, 0, 0>::from_coefficients(vec![
1.0, i as f64, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
]);
a_batch.push(VerifiedMultivector::new(a));
b_batch.push(VerifiedMultivector::new(b));
}
match GpuCliffordAlgebra::new::<3, 0, 0>().await {
Ok(gpu) => {
let result = verifier
.verified_batch_geometric_product(&gpu, &a_batch, &b_batch)
.await;
match result {
Ok(verified_results) => {
assert_eq!(verified_results.len(), batch_size);
for (i, result) in verified_results.iter().enumerate() {
assert!(result.verify_invariants().is_ok());
let expected = a_batch[i].inner().geometric_product(b_batch[i].inner());
let tolerance = 1e-12;
for j in 0..8 {
let diff = (result.inner().get(j) - expected.get(j)).abs();
assert!(
diff < tolerance,
"Component {} mismatch: expected {}, got {}, diff {}",
j,
expected.get(j),
result.inner().get(j),
diff
);
}
}
let stats = verifier.performance_stats();
assert!(stats.operation_count() > 0);
assert!(stats.average_duration() > Duration::ZERO);
}
Err(e) => {
println!(
"Boundary verification failed (expected in test env): {:?}",
e
);
}
}
}
Err(_) => {
println!("No GPU available for boundary verification test");
}
}
}
#[tokio::test]
async fn test_statistical_verification() {
if !direct_gpu_runtime_available() {
return;
}
let mut verifier = StatisticalGpuVerifier::<3, 0, 0>::new(0.2, 1e-12);
let batch_size = 20;
let mut inputs = Vec::new();
let mut gpu_results = Vec::new();
for i in 0..batch_size {
let a = VerifiedMultivector::new(Multivector::<3, 0, 0>::from_coefficients(vec![
i as f64, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
]));
let b = VerifiedMultivector::new(Multivector::<3, 0, 0>::from_coefficients(vec![
1.0, i as f64, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
]));
let expected_result = a.inner().geometric_product(b.inner());
inputs.push((a, b));
gpu_results.push(expected_result);
}
match GpuCliffordAlgebra::new::<3, 0, 0>().await {
Ok(gpu) => {
let result = verifier
.verify_batch_statistical(&gpu, &inputs, &gpu_results)
.await;
match result {
Ok(verified_results) => {
assert_eq!(verified_results.len(), batch_size);
for result in &verified_results {
assert!(result.verify_invariants().is_ok());
}
}
Err(e) => {
println!(
"Statistical verification failed (expected in test env): {:?}",
e
);
}
}
}
Err(_) => {
println!("No GPU available for statistical verification test");
}
}
}
#[tokio::test]
async fn test_adaptive_verification_strategies() {
if !direct_gpu_runtime_available() {
println!("Skipping GPU adaptive verification test in this environment");
return;
}
match AdaptiveVerifier::new().await {
Ok(mut verifier) => {
println!("Detected platform: {:?}", verifier.platform());
println!("Verification level: {:?}", verifier.verification_level());
println!("Performance budget: {:?}", verifier.performance_budget());
let a = VerifiedMultivector::new(Multivector::<3, 0, 0>::from_coefficients(vec![
1.0, 2.0, 3.0, 0.0, 0.0, 0.0, 0.0, 0.0,
]));
let b = VerifiedMultivector::new(Multivector::<3, 0, 0>::from_coefficients(vec![
2.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
]));
let result = verifier.verified_geometric_product(&a, &b).await;
match result {
Ok(verified_result) => {
assert!(verified_result.verify_invariants().is_ok());
let expected = a.inner().geometric_product(b.inner());
for i in 0..8 {
let diff = (verified_result.inner().get(i) - expected.get(i)).abs();
assert!(diff < 1e-12, "Component {} verification failed", i);
}
}
Err(e) => {
println!("Single operation verification failed: {:?}", e);
}
}
let batch_size = 10;
let mut a_batch = Vec::new();
let mut b_batch = Vec::new();
for i in 0..batch_size {
let a = VerifiedMultivector::new(Multivector::<3, 0, 0>::from_coefficients(vec![
i as f64, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
]));
let b = VerifiedMultivector::new(Multivector::<3, 0, 0>::from_coefficients(vec![
1.0, i as f64, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
]));
a_batch.push(a);
b_batch.push(b);
}
let batch_result = verifier
.verified_batch_geometric_product(&a_batch, &b_batch)
.await;
match batch_result {
Ok(verified_results) => {
assert_eq!(verified_results.len(), batch_size);
for (i, result) in verified_results.iter().enumerate() {
assert!(result.verify_invariants().is_ok());
let expected = a_batch[i].inner().geometric_product(b_batch[i].inner());
for j in 0..8 {
let diff = (result.inner().get(j) - expected.get(j)).abs();
assert!(
diff < 1e-12,
"Batch result[{}][{}] verification failed",
i,
j
);
}
}
}
Err(e) => {
println!("Batch verification failed: {:?}", e);
}
}
let should_use_small = verifier.should_use_gpu(10);
let should_use_large = verifier.should_use_gpu(1000);
match verifier.platform() {
VerificationPlatform::Gpu { .. } => {
println!(
"GPU decisions: small={}, large={}",
should_use_small, should_use_large
);
}
_ => {
assert!(!should_use_small);
assert!(!should_use_large);
}
}
}
Err(e) => {
println!(
"Adaptive verifier creation failed (expected in limited env): {:?}",
e
);
}
}
}
#[tokio::test]
async fn test_verification_level_adaptation() {
if !direct_gpu_runtime_available() {
println!("Skipping GPU verification level adaptation test in this environment");
return;
}
let levels = vec![
AdaptiveVerificationLevel::Maximum,
AdaptiveVerificationLevel::High,
AdaptiveVerificationLevel::Balanced,
AdaptiveVerificationLevel::Minimal,
];
for level in levels {
match AdaptiveVerifier::with_config(level.clone(), Duration::from_millis(50)).await {
Ok(mut verifier) => {
assert_eq!(*verifier.verification_level(), level);
assert_eq!(verifier.performance_budget(), Duration::from_millis(50));
verifier.set_verification_level(AdaptiveVerificationLevel::Minimal);
assert_eq!(
*verifier.verification_level(),
AdaptiveVerificationLevel::Minimal
);
println!("Successfully tested verification level: {:?}", level);
}
Err(e) => {
println!("Verification level {:?} test failed: {:?}", level, e);
}
}
}
}
#[test]
fn test_platform_capabilities() {
use amari_gpu::{CpuFeatures, GpuBackend, WasmEnvironment};
let platforms = vec![
VerificationPlatform::NativeCpu {
features: CpuFeatures {
supports_simd: true,
core_count: 8,
cache_size_kb: 8192,
},
},
VerificationPlatform::Gpu {
backend: GpuBackend::Vulkan,
memory_mb: 2048,
compute_units: 32,
},
VerificationPlatform::Wasm {
env: WasmEnvironment::Browser {
engine: "V8".to_string(),
},
},
];
for platform in platforms {
println!("Testing platform: {:?}", platform);
let max_batch = platform.max_batch_size();
assert!(max_batch > 0);
let strategy_small = platform.optimal_strategy(10);
let strategy_large = platform.optimal_strategy(10000);
println!(" Max batch size: {}", max_batch);
println!(" Small workload strategy: {:?}", strategy_small);
println!(" Large workload strategy: {:?}", strategy_large);
let concurrent_support = platform.supports_concurrent_verification();
println!(" Concurrent verification: {}", concurrent_support);
let profile = platform.performance_characteristics();
println!(" Performance profile: {:?}", profile);
assert!(profile.verification_overhead_percent >= 0.0);
assert!(profile.memory_bandwidth_gbps > 0.0);
assert!(profile.compute_throughput_gflops > 0.0);
assert!(profile.latency_microseconds > 0.0);
}
}
#[tokio::test]
async fn test_verification_error_handling() {
if !direct_gpu_runtime_available() {
return;
}
let config = VerificationConfig::default();
let mut verifier = GpuBoundaryVerifier::new(config);
let a_batch = vec![VerifiedMultivector::new(Multivector::<3, 0, 0>::zero())];
let b_batch = vec![
VerifiedMultivector::new(Multivector::<3, 0, 0>::zero()),
VerifiedMultivector::new(Multivector::<3, 0, 0>::zero()),
];
if let Ok(gpu) = GpuCliffordAlgebra::new::<3, 0, 0>().await {
let result = verifier
.verified_batch_geometric_product(&gpu, &a_batch, &b_batch)
.await;
assert!(result.is_err());
println!("Correctly detected batch size mismatch");
}
let invalid_mv = Multivector::<3, 0, 0>::from_coefficients(vec![
f64::INFINITY,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
]);
let invalid_verified = VerifiedMultivector::new(invalid_mv);
let invariant_result = invalid_verified.verify_invariants();
assert!(invariant_result.is_err());
println!("Correctly detected invalid magnitude");
}
#[tokio::test]
async fn test_verification_performance_overhead() {
if !direct_gpu_runtime_available() {
println!("Skipping GPU performance test in this environment");
return;
}
use std::time::Instant;
let batch_size = 100;
let mut a_batch = Vec::new();
let mut b_batch = Vec::new();
for i in 0..batch_size {
let a = Multivector::<3, 0, 0>::from_coefficients(vec![
i as f64, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
]);
let b = Multivector::<3, 0, 0>::from_coefficients(vec![
1.0, i as f64, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
]);
a_batch.push(a);
b_batch.push(b);
}
let start_unverified = Instant::now();
let mut cpu_results = Vec::new();
for (a, b) in a_batch.iter().zip(b_batch.iter()) {
cpu_results.push(a.geometric_product(b));
}
let unverified_duration = start_unverified.elapsed();
println!("Unverified CPU computation: {:?}", unverified_duration);
match AdaptiveVerifier::new().await {
Ok(mut verifier) => {
let verified_a: Vec<_> = a_batch.into_iter().map(VerifiedMultivector::new).collect();
let verified_b: Vec<_> = b_batch.into_iter().map(VerifiedMultivector::new).collect();
let start_verified = Instant::now();
let verified_results = verifier
.verified_batch_geometric_product(&verified_a, &verified_b)
.await
.expect("verified batch product should succeed");
let verified_duration = start_verified.elapsed();
println!("Verified computation: {:?}", verified_duration);
assert_eq!(verified_results.len(), cpu_results.len());
if verified_duration > Duration::ZERO && unverified_duration > Duration::ZERO {
let overhead_percent =
(verified_duration.as_secs_f64() / unverified_duration.as_secs_f64() - 1.0)
* 100.0;
println!("Verification overhead: {:.1}%", overhead_percent);
assert!(
overhead_percent.is_finite(),
"verification overhead should be finite"
);
}
}
Err(e) => {
println!(
"Performance test skipped due to verifier creation failure: {:?}",
e
);
}
}
}
#[test]
fn test_verification_strategies() {
let strategies = vec![
VerificationStrategy::Strict,
VerificationStrategy::Statistical { sample_rate: 0.1 },
VerificationStrategy::Statistical { sample_rate: 0.5 },
VerificationStrategy::Boundary,
VerificationStrategy::Minimal,
];
for strategy in strategies {
let config = VerificationConfig {
strategy: strategy.clone(),
performance_budget: Duration::from_millis(10),
tolerance: 1e-12,
enable_invariant_checking: true,
};
let _verifier = GpuBoundaryVerifier::new(config);
println!(
"Successfully created verifier with strategy: {:?}",
strategy
);
}
}