quantrs2-anneal 0.1.3

Quantum annealing support for the QuantRS2 framework
Documentation
//! Caching and performance tracking for RL embedding optimizer

use std::collections::HashMap;
use std::time::{Duration, Instant};

use super::embedding::EmbeddingOptimizer;
use super::error::{RLEmbeddingError, RLEmbeddingResult};
use super::types::{
    CacheMetadata, CachedEmbedding, EmbeddingPerformanceResults, EmbeddingQualityMetrics,
    EmbeddingState, RLPerformanceMetrics, RLTrainingStats, RuntimeStatistics,
    TransferLearningStats,
};
use crate::embedding::{Embedding, HardwareTopology};
use crate::ising::IsingModel;

/// Cache management utilities
pub struct CacheManager;

impl CacheManager {
    /// Check cache for similar problems
    #[must_use]
    pub fn check_cache<'a>(
        embedding_cache: &'a HashMap<String, CachedEmbedding>,
        state: &EmbeddingState,
    ) -> Option<&'a CachedEmbedding> {
        // Simple cache lookup based on problem features
        let cache_key = format!(
            "{}_{:.2}_{:.2}",
            state.problem_features.num_vertices,
            state.problem_features.density,
            state.problem_features.average_degree
        );

        embedding_cache.get(&cache_key)
    }

    /// Cache embedding result
    pub fn cache_embedding(
        embedding_cache: &mut HashMap<String, CachedEmbedding>,
        problem: &IsingModel,
        embedding: &Embedding,
        hardware: &HardwareTopology,
        computation_time: Duration,
    ) -> RLEmbeddingResult<()> {
        let cache_key = format!(
            "{}_{:.2}_default",
            problem.num_qubits,
            EmbeddingOptimizer::calculate_problem_density(problem)
        );

        let cached_embedding = CachedEmbedding {
            embedding: embedding.clone(),
            quality_metrics: EmbeddingQualityMetrics {
                overall_score: EmbeddingOptimizer::evaluate_embedding_quality(embedding, hardware)?,
                chain_length_penalty: EmbeddingOptimizer::calculate_average_chain_length(embedding),
                connectivity_score: 0.8, // Placeholder
                utilization_efficiency: EmbeddingOptimizer::calculate_hardware_utilization(
                    embedding, hardware,
                ),
                predicted_performance: 0.7, // Placeholder
            },
            performance_results: EmbeddingPerformanceResults {
                success_probability: 0.8,
                average_energy_gap: 1.0,
                solution_quality: vec![0.8, 0.9, 0.7],
                runtime_stats: RuntimeStatistics {
                    embedding_time: computation_time,
                    execution_time: Duration::from_millis(100),
                    total_time: computation_time + Duration::from_millis(100),
                    memory_usage: 1024 * 1024, // 1MB
                },
            },
            cache_metadata: CacheMetadata {
                created_at: Instant::now(),
                last_accessed: Instant::now(),
                access_count: 1,
                hit_rate: 0.0,
            },
        };

        embedding_cache.insert(cache_key, cached_embedding);
        Ok(())
    }

    /// Update cache statistics
    pub fn update_cache_statistics(
        embedding_cache: &mut HashMap<String, CachedEmbedding>,
        cache_key: &str,
    ) {
        if let Some(cached_embedding) = embedding_cache.get_mut(cache_key) {
            cached_embedding.cache_metadata.last_accessed = Instant::now();
            cached_embedding.cache_metadata.access_count += 1;
        }
    }

    /// Clean up old cache entries
    pub fn cleanup_cache(
        embedding_cache: &mut HashMap<String, CachedEmbedding>,
        max_age: Duration,
    ) {
        let now = Instant::now();
        let mut keys_to_remove = Vec::new();

        for (key, cached_embedding) in embedding_cache.iter() {
            if now.duration_since(cached_embedding.cache_metadata.created_at) > max_age {
                keys_to_remove.push(key.clone());
            }
        }

        for key in keys_to_remove {
            embedding_cache.remove(&key);
        }
    }

    /// Calculate cache hit rate
    #[must_use]
    pub fn calculate_cache_hit_rate(embedding_cache: &HashMap<String, CachedEmbedding>) -> f64 {
        let total_accesses: usize = embedding_cache
            .values()
            .map(|entry| entry.cache_metadata.access_count)
            .sum();

        let cache_hits = embedding_cache.len();

        if total_accesses > 0 {
            cache_hits as f64 / total_accesses as f64
        } else {
            0.0
        }
    }
}

/// Performance metrics tracking
pub struct PerformanceTracker;

impl PerformanceTracker {
    /// Update performance metrics
    pub fn update_performance_metrics(
        metrics: &mut RLPerformanceMetrics,
        embedding_quality: f64,
        baseline_quality: f64,
    ) {
        metrics.problems_solved += 1;

        let improvement = embedding_quality - baseline_quality;

        // Update average improvement (running average)
        let alpha = 0.1; // Learning rate for running average
        metrics.average_improvement =
            alpha * improvement + (1.0 - alpha) * metrics.average_improvement;

        // Update best improvement
        if improvement > metrics.best_improvement {
            metrics.best_improvement = improvement;
        }
    }

    /// Calculate computational efficiency
    #[must_use]
    pub fn calculate_computational_efficiency(
        problems_solved: usize,
        total_time: Duration,
        average_improvement: f64,
    ) -> f64 {
        if total_time.as_secs_f64() > 0.0 {
            (problems_solved as f64 * average_improvement) / total_time.as_secs_f64()
        } else {
            0.0
        }
    }

    /// Update convergence rate
    pub fn update_convergence_rate(
        metrics: &mut RLPerformanceMetrics,
        training_stats: &RLTrainingStats,
    ) {
        if training_stats.loss_history.len() > 10 {
            let recent_losses =
                &training_stats.loss_history[training_stats.loss_history.len() - 10..];
            let initial_loss = recent_losses[0];
            let final_loss = recent_losses[recent_losses.len() - 1];

            if initial_loss > 0.0 {
                metrics.convergence_rate = (initial_loss - final_loss) / initial_loss;
            }
        }
    }

    /// Update transfer learning effectiveness
    pub const fn update_transfer_effectiveness(
        metrics: &mut RLPerformanceMetrics,
        transfer_stats: &TransferLearningStats,
    ) {
        metrics.transfer_effectiveness = transfer_stats.transfer_effectiveness;
    }

    /// Generate performance report
    #[must_use]
    pub fn generate_performance_report(metrics: &RLPerformanceMetrics) -> String {
        format!(
            "RL Embedding Optimizer Performance Report:\n\
             Problems Solved: {}\n\
             Average Improvement: {:.3}\n\
             Best Improvement: {:.3}\n\
             Convergence Rate: {:.3}\n\
             Transfer Effectiveness: {:.3}\n\
             Computational Efficiency: {:.3}",
            metrics.problems_solved,
            metrics.average_improvement,
            metrics.best_improvement,
            metrics.convergence_rate,
            metrics.transfer_effectiveness,
            metrics.computational_efficiency
        )
    }
}