#![allow(clippy::pedantic, clippy::unnecessary_wraps)]
use quantrs2_tytan::analysis::visualization::*;
use quantrs2_tytan::sampler::{SASampler, SampleResult, Sampler};
use scirs2_core::ndarray::Array;
use scirs2_core::random::prelude::*;
use std::collections::HashMap;
fn create_test_results(n: usize) -> Vec<SampleResult> {
let mut results = Vec::new();
for i in 0..n {
let mut assignments = HashMap::new();
assignments.insert("x0".to_string(), i % 2 == 0);
assignments.insert("x1".to_string(), i % 3 == 0);
assignments.insert("x2".to_string(), i % 5 == 0);
assignments.insert("x3".to_string(), i % 7 == 0);
let energy = (i as f64).mul_add(
0.1,
if i % 2 == 0 { -2.0 } else { -1.0 }
+ if i % 3 == 0 { -1.5 } else { 0.0 }
+ if i % 5 == 0 { -1.0 } else { 0.5 },
);
results.push(SampleResult {
assignments,
energy,
occurrences: 1,
});
}
results
}
#[test]
fn test_energy_landscape_preparation() {
let results = create_test_results(100);
let landscape_data = prepare_energy_landscape(&results, None).unwrap();
assert_eq!(landscape_data.indices.len(), 100);
assert_eq!(landscape_data.energies.len(), 100);
assert!(landscape_data.energies[0] <= landscape_data.energies[99]);
assert_eq!(landscape_data.histogram_bins.len(), 51); assert_eq!(landscape_data.histogram_counts.len(), 50);
assert!(landscape_data.kde_x.is_some());
assert!(landscape_data.kde_y.is_some());
assert_eq!(landscape_data.kde_x.as_ref().unwrap().len(), 200);
}
#[test]
fn test_solution_distribution_analysis() {
let results = create_test_results(50);
let dist_data = analyze_solution_distribution(&results, None).unwrap();
assert_eq!(dist_data.variable_names.len(), 4);
assert_eq!(dist_data.variable_frequencies.len(), 4);
for &freq in dist_data.variable_frequencies.values() {
assert!((0.0..=1.0).contains(&freq));
}
assert!(dist_data.correlations.is_some());
assert_eq!(dist_data.solution_matrix.nrows(), 50);
assert_eq!(dist_data.solution_matrix.ncols(), 4);
}
#[test]
fn test_tsp_tour_extraction() {
let mut assignments = HashMap::new();
assignments.insert("x_0_1".to_string(), true);
assignments.insert("x_1_3".to_string(), true);
assignments.insert("x_3_2".to_string(), true);
assignments.insert("x_2_0".to_string(), true);
assignments.insert("x_0_2".to_string(), false);
assignments.insert("x_0_3".to_string(), false);
assignments.insert("x_1_0".to_string(), false);
assignments.insert("x_1_2".to_string(), false);
let result = SampleResult {
assignments,
energy: -10.0,
occurrences: 1,
};
let tour = extract_tsp_tour(&result, 4).unwrap();
assert_eq!(tour.len(), 4);
assert_eq!(tour[0], 0);
let mut visited = [false; 4];
for &city in &tour {
visited[city] = true;
}
assert!(visited.iter().all(|&v| v));
}
#[test]
fn test_graph_coloring_extraction() {
let mut assignments = HashMap::new();
assignments.insert("x_0_0".to_string(), true); assignments.insert("x_0_1".to_string(), false);
assignments.insert("x_0_2".to_string(), false);
assignments.insert("x_1_1".to_string(), true); assignments.insert("x_1_0".to_string(), false);
assignments.insert("x_1_2".to_string(), false);
assignments.insert("x_2_0".to_string(), true); assignments.insert("x_2_1".to_string(), false);
assignments.insert("x_2_2".to_string(), false);
assignments.insert("x_3_2".to_string(), true); assignments.insert("x_3_0".to_string(), false);
assignments.insert("x_3_1".to_string(), false);
let result = SampleResult {
assignments,
energy: -5.0,
occurrences: 1,
};
let edges = vec![(0, 1), (1, 2), (2, 3)];
let (colors, conflicts) = extract_graph_coloring(&result, 4, 3, &edges).unwrap();
assert_eq!(colors.len(), 4);
assert_eq!(colors[0], 0);
assert_eq!(colors[1], 1);
assert_eq!(colors[2], 0);
assert_eq!(colors[3], 2);
assert_eq!(conflicts.len(), 0);
}
#[test]
fn test_convergence_analysis() {
let mut iteration_results = Vec::new();
for i in 0..10 {
let mut iter_samples = Vec::new();
for j in 0..20 {
let energy =
0.1f64.mul_add(-f64::from(j), -f64::from(i)) + thread_rng().random::<f64>();
iter_samples.push(SampleResult {
assignments: HashMap::new(),
energy,
occurrences: 1,
});
}
iteration_results.push(iter_samples);
}
let conv_data = analyze_convergence(&iteration_results, Some(3)).unwrap();
assert_eq!(conv_data.iterations.len(), 10);
assert_eq!(conv_data.best_energies.len(), 10);
assert_eq!(conv_data.avg_energies.len(), 10);
assert_eq!(conv_data.std_devs.len(), 10);
assert!(conv_data.best_energies[0] > conv_data.best_energies[9]);
assert!(conv_data.ma_best.is_some());
assert_eq!(conv_data.ma_best.as_ref().unwrap().len(), 8); }
#[test]
fn test_csv_export() {
let results = create_test_results(10);
let landscape_data = prepare_energy_landscape(&results, None).unwrap();
let temp_path = "/tmp/test_energy_landscape.csv";
export_to_csv(&landscape_data, temp_path).unwrap();
let contents = std::fs::read_to_string(temp_path).unwrap();
let lines: Vec<&str> = contents.trim().split('\n').collect();
assert_eq!(lines[0], "index,original_index,energy");
assert_eq!(lines.len(), 11);
std::fs::remove_file(temp_path).ok();
}
#[test]
fn test_spring_layout() {
let n_nodes = 5;
let edges = vec![(0, 1), (1, 2), (2, 3), (3, 4), (4, 0), (0, 2)];
let positions = spring_layout(n_nodes, &edges);
assert_eq!(positions.len(), n_nodes);
for &(x, y) in &positions {
assert!((0.0..=1.0).contains(&x));
assert!((0.0..=1.0).contains(&y));
}
}
#[test]
fn example_complete_visualization_workflow() {
println!("\n=== Advanced Visualization Example ===\n");
println!("1. Creating sample results...");
let results = create_test_results(100);
println!(" Created {} sample results", results.len());
println!("\n2. Analyzing energy landscape...");
let landscape_config = EnergyLandscapeConfig {
num_bins: 20,
compute_kde: true,
kde_points: 100,
};
let landscape_data = prepare_energy_landscape(&results, Some(landscape_config)).unwrap();
println!(
" Energy range: {:.2} to {:.2}",
landscape_data.energies.first().unwrap(),
landscape_data.energies.last().unwrap()
);
println!(" Histogram bins: {}", landscape_data.histogram_bins.len());
export_to_csv(&landscape_data, "/tmp/energy_landscape.csv").ok();
println!(" Exported to /tmp/energy_landscape.csv");
println!("\n3. Analyzing solution distribution...");
let dist_config = SolutionDistributionConfig {
compute_correlations: true,
compute_pca: true,
n_components: 2,
};
let dist_data = analyze_solution_distribution(&results, Some(dist_config)).unwrap();
println!(" Variables: {:?}", dist_data.variable_names);
println!(" Variable frequencies:");
for (var, freq) in &dist_data.variable_frequencies {
println!(" {}: {:.2}%", var, freq * 100.0);
}
if let Some(correlations) = &dist_data.correlations {
println!(" Significant correlations:");
for ((var1, var2), corr) in correlations {
if corr.abs() > 0.3 {
println!(" {var1} <-> {var2}: {corr:.3}");
}
}
}
export_solution_matrix(&dist_data, "/tmp/solution_matrix.csv").ok();
println!(" Exported solution matrix to /tmp/solution_matrix.csv");
println!("\n4. TSP visualization example...");
let cities = vec![(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0)];
let mut tsp_assignments = HashMap::new();
tsp_assignments.insert("x_0_1".to_string(), true);
tsp_assignments.insert("x_1_2".to_string(), true);
tsp_assignments.insert("x_2_3".to_string(), true);
tsp_assignments.insert("x_3_0".to_string(), true);
let tsp_result = SampleResult {
assignments: tsp_assignments,
energy: -4.0,
occurrences: 1,
};
let tour = extract_tsp_tour(&tsp_result, 4).unwrap();
let tour_length = calculate_tour_length(&tour, &cities);
println!(" Tour: {tour:?}");
println!(" Tour length: {tour_length:.2}");
println!("\n5. Simulating convergence analysis...");
let mut iteration_results = Vec::new();
for i in 0..20 {
let mut iter_samples = create_test_results(50);
for sample in &mut iter_samples {
sample.energy = f64::from(i).mul_add(-0.5, sample.energy);
}
iteration_results.push(iter_samples);
}
let conv_data = analyze_convergence(&iteration_results, Some(5)).unwrap();
println!(" Iterations: {}", conv_data.iterations.len());
println!(" Initial best energy: {:.2}", conv_data.best_energies[0]);
println!(
" Final best energy: {:.2}",
conv_data.best_energies.last().unwrap()
);
println!(
" Improvement: {:.2}",
conv_data.best_energies[0] - conv_data.best_energies.last().unwrap()
);
println!("\n=== Visualization data prepared successfully ===");
println!("\nNote: The prepared data can be used with external plotting libraries");
println!("such as matplotlib, plotly, or gnuplot for actual visualization.");
}
#[test]
fn example_python_plotting_script() {
println!("\n=== Example Python Plotting Script ===\n");
let python_script = r"
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# Load energy landscape data
df_energy = pd.read_csv('/tmp/energy_landscape.csv')
# Create figure with subplots
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
# Plot 1: Energy landscape
ax1.scatter(df_energy['index'], df_energy['energy'], alpha=0.6)
ax1.set_xlabel('Solution Index (sorted)')
ax1.set_ylabel('Energy')
ax1.set_title('Energy Landscape')
# Plot 2: Solution matrix heatmap
df_solutions = pd.read_csv('/tmp/solution_matrix.csv', index_col=0)
im = ax2.imshow(df_solutions.values.T, aspect='auto', cmap='RdBu')
ax2.set_xlabel('Sample')
ax2.set_ylabel('Variable')
ax2.set_title('Solution Matrix')
ax2.set_yticks(range(len(df_solutions.columns)))
ax2.set_yticklabels(df_solutions.columns)
plt.colorbar(im, ax=ax2)
plt.tight_layout()
plt.savefig('/tmp/quantum_annealing_visualization.png', dpi=150)
plt.show()
";
println!("{python_script}");
std::fs::write("/tmp/plot_visualization.py", python_script).ok();
println!("\nScript saved to: /tmp/plot_visualization.py");
println!("Run with: python /tmp/plot_visualization.py");
}