use scirs2_core::ndarray::Array1;
use std::collections::HashMap;
use std::time::{Duration, Instant};
use super::{
DecompositionStrategy, DiversityMetric, DomainAdaptationStrategy, EvaluationMetric, ModelType,
ProblemAnalysis, QueryStrategy, StructureType,
};
use crate::ising::IsingModel;
#[derive(Debug, Clone)]
pub struct DecompositionStrategyLearner {
pub selection_model: StrategySelectionModel,
pub performance_history: HashMap<String, Vec<PerformanceRecord>>,
pub query_selector: QuerySelector,
pub transfer_learning: TransferLearningManager,
pub learning_stats: LearningStatistics,
}
impl DecompositionStrategyLearner {
pub fn new() -> Result<Self, String> {
Ok(Self {
selection_model: StrategySelectionModel::new(),
performance_history: HashMap::new(),
query_selector: QuerySelector::new(),
transfer_learning: TransferLearningManager::new(),
learning_stats: LearningStatistics::new(),
})
}
pub const fn recommend_strategy(
&self,
problem: &IsingModel,
analysis: &ProblemAnalysis,
) -> Result<DecompositionStrategy, String> {
if problem.num_qubits < 10 {
Ok(DecompositionStrategy::NoDecomposition)
} else if problem.num_qubits < 50 {
Ok(DecompositionStrategy::GraphPartitioning)
} else {
Ok(DecompositionStrategy::CommunityDetection)
}
}
}
#[derive(Debug, Clone)]
pub struct StrategySelectionModel {
pub model_type: ModelType,
pub feature_weights: Array1<f64>,
pub strategy_preferences: HashMap<DecompositionStrategy, f64>,
pub uncertainty_estimates: HashMap<String, f64>,
pub model_parameters: ModelParameters,
}
impl StrategySelectionModel {
#[must_use]
pub fn new() -> Self {
Self {
model_type: ModelType::Linear,
feature_weights: Array1::ones(20),
strategy_preferences: HashMap::new(),
uncertainty_estimates: HashMap::new(),
model_parameters: ModelParameters::default(),
}
}
pub fn get_uncertainty(&self, features: &Array1<f64>) -> Result<f64, String> {
let feature_sum = features.sum();
Ok(1.0 / (1.0 + feature_sum.abs()))
}
pub fn get_strategy_uncertainty(
&self,
strategy: &DecompositionStrategy,
features: &Array1<f64>,
) -> Result<f64, String> {
let base_uncertainty = self.get_uncertainty(features)?;
let strategy_key = format!("{strategy:?}");
if let Some(&stored_uncertainty) = self.uncertainty_estimates.get(&strategy_key) {
Ok(f64::midpoint(base_uncertainty, stored_uncertainty))
} else {
Ok(base_uncertainty)
}
}
}
#[derive(Debug, Clone)]
pub struct ModelParameters {
pub parameters: HashMap<String, f64>,
pub regularization: RegularizationParameters,
pub training_config: ModelTrainingConfig,
}
impl Default for ModelParameters {
fn default() -> Self {
Self {
parameters: HashMap::new(),
regularization: RegularizationParameters {
l1_weight: 0.01,
l2_weight: 0.01,
dropout_rate: 0.1,
early_stopping_patience: 10,
},
training_config: ModelTrainingConfig {
num_epochs: 100,
batch_size: 32,
learning_rate: 0.001,
validation_split: 0.2,
},
}
}
}
#[derive(Debug, Clone)]
pub struct RegularizationParameters {
pub l1_weight: f64,
pub l2_weight: f64,
pub dropout_rate: f64,
pub early_stopping_patience: usize,
}
#[derive(Debug, Clone)]
pub struct ModelTrainingConfig {
pub num_epochs: usize,
pub batch_size: usize,
pub learning_rate: f64,
pub validation_split: f64,
}
#[derive(Debug, Clone)]
pub struct QuerySelector {
pub query_strategy: QueryStrategy,
pub uncertainty_threshold: f64,
pub diversity_constraint: DiversityConstraint,
pub query_history: Vec<QueryRecord>,
}
impl QuerySelector {
#[must_use]
pub const fn new() -> Self {
Self {
query_strategy: QueryStrategy::UncertaintySampling,
uncertainty_threshold: 0.5,
diversity_constraint: DiversityConstraint {
min_distance: 0.1,
diversity_metric: DiversityMetric::Euclidean,
max_similarity: 0.8,
},
query_history: Vec::new(),
}
}
}
#[derive(Debug, Clone)]
pub struct DiversityConstraint {
pub min_distance: f64,
pub diversity_metric: DiversityMetric,
pub max_similarity: f64,
}
#[derive(Debug, Clone)]
pub struct QueryRecord {
pub timestamp: Instant,
pub problem_features: Array1<f64>,
pub recommended_strategy: DecompositionStrategy,
pub query_outcome: QueryOutcome,
pub performance_feedback: Option<PerformanceRecord>,
}
#[derive(Debug, Clone)]
pub struct QueryOutcome {
pub strategy_used: DecompositionStrategy,
pub accepted_recommendation: bool,
pub performance_achieved: f64,
pub feedback_quality: f64,
}
#[derive(Debug, Clone)]
pub struct TransferLearningManager {
pub source_models: Vec<SourceDomainModel>,
pub adaptation_strategy: DomainAdaptationStrategy,
pub transfer_weights: Array1<f64>,
pub transfer_stats: TransferStatistics,
}
impl TransferLearningManager {
#[must_use]
pub fn new() -> Self {
Self {
source_models: Vec::new(),
adaptation_strategy: DomainAdaptationStrategy::FineTuning,
transfer_weights: Array1::ones(5),
transfer_stats: TransferStatistics {
successful_transfers: 0,
failed_transfers: 0,
avg_transfer_benefit: 0.0,
transfer_time_overhead: Duration::from_secs(0),
},
}
}
}
#[derive(Debug, Clone)]
pub struct SourceDomainModel {
pub domain_id: String,
pub model: StrategySelectionModel,
pub domain_characteristics: DomainCharacteristics,
pub applicability_score: f64,
}
#[derive(Debug, Clone)]
pub struct DomainCharacteristics {
pub problem_types: Vec<String>,
pub avg_problem_size: f64,
pub complexity_distribution: Array1<f64>,
pub common_structures: Vec<StructureType>,
}
#[derive(Debug, Clone)]
pub struct TransferStatistics {
pub successful_transfers: usize,
pub failed_transfers: usize,
pub avg_transfer_benefit: f64,
pub transfer_time_overhead: Duration,
}
#[derive(Debug, Clone)]
pub struct LearningStatistics {
pub total_queries: usize,
pub successful_predictions: usize,
pub avg_prediction_accuracy: f64,
pub learning_curve: Vec<(usize, f64)>, pub exploration_exploitation_ratio: f64,
}
impl LearningStatistics {
#[must_use]
pub const fn new() -> Self {
Self {
total_queries: 0,
successful_predictions: 0,
avg_prediction_accuracy: 0.0,
learning_curve: Vec::new(),
exploration_exploitation_ratio: 0.5,
}
}
}
#[derive(Debug, Clone)]
pub struct PerformanceRecord {
pub timestamp: Instant,
pub problem_id: String,
pub strategy_used: DecompositionStrategy,
pub metrics: HashMap<EvaluationMetric, f64>,
pub overall_score: f64,
}