#[allow(dead_code)]
use scirs2_core::ndarray::{Array1, Array2};
use scirs2_core::numeric::Float;
use std::fmt::Debug;
use serde::{Deserialize, Serialize};
use std::collections::{HashMap, VecDeque};
use std::time::{Duration, Instant};
use super::EvaluationResults;
#[allow(unused_imports)]
use crate::error::Result;
pub struct HyperparameterOptimizer<T: Float + Debug + Send + Sync + 'static> {
strategy: Box<dyn HyperOptStrategy<T>>,
search_space: HyperparameterSearchSpace<T>,
optimization_history: VecDeque<HyperOptResult<T>>,
best_configurations: Vec<HyperparameterConfig<T>>,
fidelity_manager: Option<MultiFidelityManager<T>>,
pbt_manager: Option<PopulationBasedTrainer<T>>,
early_stopping: EarlyStoppingManager<T>,
resource_budget: ResourceBudget<T>,
statistics: HyperOptStatistics<T>,
config_cache: ConfigurationCache<T>,
}
pub trait HyperOptStrategy<T: Float + Debug + Send + Sync + 'static>: Send + Sync {
fn initialize(&mut self, searchspace: &HyperparameterSearchSpace<T>) -> Result<()>;
fn suggest_next(&mut self, history: &[HyperOptResult<T>]) -> Result<HyperparameterConfig<T>>;
fn update(&mut self, result: &HyperOptResult<T>) -> Result<()>;
fn name(&self) -> &str;
fn statistics(&self) -> StrategyStatistics<T>;
fn should_continue(&self, history: &[HyperOptResult<T>]) -> bool;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HyperparameterSearchSpace<T: Float + Debug + Send + Sync + 'static> {
pub continuous_params: HashMap<String, ContinuousParameter<T>>,
pub integer_params: HashMap<String, IntegerParameter>,
pub categorical_params: HashMap<String, CategoricalParameter>,
pub boolean_params: Vec<String>,
pub dependencies: Vec<ParameterDependency>,
pub constraints: Vec<HyperparameterConstraint<T>>,
pub metadata: SearchSpaceMetadata,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ContinuousParameter<T: Float + Debug + Send + Sync + 'static> {
pub min_value: T,
pub max_value: T,
pub distribution: ParameterDistribution,
pub default_value: Option<T>,
pub transformation: Option<ParameterTransformation>,
pub prior_params: Option<PriorParameters<T>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IntegerParameter {
pub min_value: i32,
pub max_value: i32,
pub step: Option<i32>,
pub default_value: Option<i32>,
pub distribution: ParameterDistribution,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CategoricalParameter {
pub choices: Vec<String>,
pub default_value: Option<String>,
pub prior_probabilities: Option<Vec<f64>>,
pub ordinal: bool,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum ParameterDistribution {
Uniform,
LogUniform,
Normal,
LogNormal,
Beta,
Gamma,
Categorical,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum ParameterTransformation {
Log,
Sqrt,
Square,
Logit,
Exp,
Identity,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PriorParameters<T: Float + Debug + Send + Sync + 'static> {
pub distribution_type: PriorDistributionType,
pub parameters: Vec<T>,
pub confidence: T,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum PriorDistributionType {
Normal,
Beta,
Gamma,
Uniform,
Exponential,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ParameterDependency {
pub child_param: String,
pub parent_param: String,
pub condition: DependencyCondition,
pub child_constraints: DependencyConstraints,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum DependencyCondition {
Equals(String),
In(Vec<String>),
GreaterThan(f64),
LessThan(f64),
InRange(f64, f64),
Custom(String),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum DependencyConstraints {
Active(bool),
ContinuousRange(f64, f64),
IntegerRange(i32, i32),
CategoricalChoices(Vec<String>),
Custom(HashMap<String, String>),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HyperparameterConstraint<T: Float + Debug + Send + Sync + 'static> {
pub constraint_type: ConstraintType,
pub parameters: Vec<String>,
pub expression: ConstraintExpression<T>,
pub violation_penalty: T,
pub constraint_level: ConstraintLevel,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum ConstraintType {
Linear,
Nonlinear,
Logical,
Resource,
Performance,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ConstraintExpression<T: Float + Debug + Send + Sync + 'static> {
Linear {
coefficients: Vec<T>,
bound: T,
inequality: InequalityType,
},
Nonlinear {
expression: String,
bound: T,
inequality: InequalityType,
},
Logical { expression: LogicalExpression },
Custom {
evaluator: String,
parameters: HashMap<String, T>,
},
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum InequalityType {
LessEqual,
GreaterEqual,
Equal,
NotEqual,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum LogicalExpression {
And(Vec<String>),
Or(Vec<String>),
Not(String),
Implies(String, String),
IfThenElse(String, String, String),
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum ConstraintLevel {
Hard, Soft, Penalty, }
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SearchSpaceMetadata {
pub total_parameters: usize,
pub estimated_space_size: f64,
pub complexity_score: f64,
pub created_at: String,
pub version: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HyperparameterConfig<T: Float + Debug + Send + Sync + 'static> {
pub id: String,
pub parameters: HashMap<String, ParameterValue<T>>,
pub metadata: ConfigMetadata,
pub generation_info: GenerationInfo,
pub validation_status: ValidationStatus,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ParameterValue<T: Float + Debug + Send + Sync + 'static> {
Continuous(T),
Integer(i32),
Categorical(String),
Boolean(bool),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConfigMetadata {
pub created_at: std::time::SystemTime,
pub source_strategy: String,
pub parent_configs: Vec<String>,
pub config_hash: u64,
pub priority_score: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GenerationInfo {
pub strategy: String,
pub method: GenerationMethod,
pub exploration_score: f64,
pub confidence: f64,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum GenerationMethod {
Random,
Bayesian,
Evolutionary,
GradientBased,
PopulationBased,
MultiFidelity,
Bandit,
HyperBand,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum ValidationStatus {
Valid,
Invalid,
Pending,
ConstraintViolation,
ResourceExceeded,
}
#[derive(Debug, Clone)]
pub struct HyperOptResult<T: Float + Debug + Send + Sync + 'static> {
pub config: HyperparameterConfig<T>,
pub evaluation: EvaluationResults<T>,
pub objectives: HashMap<String, T>,
pub constraint_violations: Vec<ConstraintViolation<T>>,
pub resource_usage: ResourceUsage<T>,
pub eval_metadata: EvaluationMetadata,
pub fidelity_level: Option<FidelityLevel>,
}
#[derive(Debug, Clone)]
pub struct ConstraintViolation<T: Float + Debug + Send + Sync + 'static> {
pub constraint_id: String,
pub violation_amount: T,
pub constraint_type: ConstraintType,
pub severity: ViolationSeverity,
}
#[derive(Debug, Clone, Copy)]
pub enum ViolationSeverity {
Low,
Medium,
High,
Critical,
}
#[derive(Debug, Clone)]
pub struct ResourceUsage<T: Float + Debug + Send + Sync + 'static> {
pub evaluation_time: Duration,
pub memory_mb: T,
pub cpu_hours: T,
pub gpu_hours: T,
pub energy_kwh: T,
pub cost: T,
}
#[derive(Debug, Clone)]
pub struct EvaluationMetadata {
pub timestamp: std::time::SystemTime,
pub evaluator_version: String,
pub environment: EvaluationEnvironment,
pub random_seed: Option<u64>,
pub cv_fold: Option<usize>,
}
#[derive(Debug, Clone)]
pub struct EvaluationEnvironment {
pub hardware: HardwareSpec,
pub software: SoftwareSpec,
pub dataset: DatasetSpec,
}
#[derive(Debug, Clone)]
pub struct HardwareSpec {
pub cpu_model: String,
pub cpu_cores: usize,
pub memory_gb: usize,
pub gpu_model: Option<String>,
pub gpu_memory_gb: Option<usize>,
}
#[derive(Debug, Clone)]
pub struct SoftwareSpec {
pub os: String,
pub rust_version: String,
pub dependencies: HashMap<String, String>,
}
#[derive(Debug, Clone)]
pub struct DatasetSpec {
pub name: String,
pub size: usize,
pub features: usize,
pub task_type: String,
}
pub struct MultiFidelityManager<T: Float + Debug + Send + Sync + 'static> {
fidelity_levels: Vec<FidelityLevel>,
allocation_strategy: FidelityAllocationStrategy,
fidelity_models: HashMap<String, Box<dyn PerformanceModel<T>>>,
budget_allocation: BudgetAllocation<T>,
promotion_criteria: PromotionCriteria<T>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FidelityLevel {
pub name: String,
pub level: f64,
pub resource_multiplier: f64,
pub correlation: Option<f64>,
pub parameters: FidelityParameters,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FidelityParameters {
pub epochs: Option<usize>,
pub dataset_fraction: Option<f64>,
pub model_size_fraction: Option<f64>,
pub evaluation_budget: Option<usize>,
pub custom: HashMap<String, f64>,
}
#[derive(Debug, Clone, Copy)]
pub enum FidelityAllocationStrategy {
SuccessiveHalving,
HyperBand,
Adaptive,
Bandit,
Bayesian,
}
pub trait PerformanceModel<T: Float + Debug + Send + Sync + 'static>: Send + Sync {
fn predict(
&self,
config: &HyperparameterConfig<T>,
target_fidelity: &FidelityLevel,
) -> Result<T>;
fn update(
&mut self,
observations: &[(HyperparameterConfig<T>, FidelityLevel, T)],
) -> Result<()>;
fn uncertainty(&self, config: &HyperparameterConfig<T>, fidelity: &FidelityLevel) -> Result<T>;
}
#[derive(Debug, Clone)]
pub struct BudgetAllocation<T: Float + Debug + Send + Sync + 'static> {
pub total_budget: T,
pub _fidelity_budgets: HashMap<String, T>,
pub used_budget: HashMap<String, T>,
pub strategy: BudgetStrategy,
}
#[derive(Debug, Clone, Copy)]
pub enum BudgetStrategy {
Uniform,
Geometric,
Adaptive,
PerformanceBased,
}
#[derive(Debug, Clone)]
pub struct PromotionCriteria<T: Float + Debug + Send + Sync + 'static> {
pub performance_threshold: T,
pub top_k: Option<usize>,
pub percentile: Option<f64>,
pub min_evaluations: usize,
pub uncertainty_threshold: Option<T>,
}
pub struct PopulationBasedTrainer<T: Float + Debug + Send + Sync + 'static> {
population: Vec<PBTIndividual<T>>,
population_size: usize,
exploration_params: ExplorationParameters<T>,
selection_strategy: SelectionStrategy,
mutation_strategy: MutationStrategy<T>,
population_stats: PopulationStatistics<T>,
}
#[derive(Debug, Clone)]
pub struct PBTIndividual<T: Float + Debug + Send + Sync + 'static> {
pub id: String,
pub config: HyperparameterConfig<T>,
pub performance_history: Vec<T>,
pub age: usize,
pub resource_allocation: T,
pub ancestry: Vec<String>,
}
#[derive(Debug, Clone)]
pub struct ExplorationParameters<T: Float + Debug + Send + Sync + 'static> {
pub exploit_prob: T,
pub explore_prob: T,
pub perturbation_strength: T,
pub resample_prob: T,
}
#[derive(Debug, Clone, Copy)]
pub enum SelectionStrategy {
Tournament,
Rank,
Roulette,
Truncation,
Elite,
}
#[derive(Debug, Clone)]
pub struct MutationStrategy<T: Float + Debug + Send + Sync + 'static> {
pub mutation_type: MutationType,
pub mutation_rate: T,
pub mutation_strength: T,
pub adaptive: bool,
}
#[derive(Debug, Clone, Copy)]
pub enum MutationType {
Gaussian,
Uniform,
Cauchy,
Adaptive,
Crossover,
}
#[derive(Debug, Clone)]
pub struct PopulationStatistics<T: Float + Debug + Send + Sync + 'static> {
pub best_performance: T,
pub average_performance: T,
pub performance_diversity: T,
pub config_diversity: T,
pub convergence: T,
}
pub struct EarlyStoppingManager<T: Float + Debug + Send + Sync + 'static> {
criteria: Vec<EarlyStoppingCriterion<T>>,
grace_period: usize,
performance_history: VecDeque<T>,
patience_counter: usize,
best_performance: Option<T>,
}
#[derive(Debug, Clone)]
pub struct EarlyStoppingCriterion<T: Float + Debug + Send + Sync + 'static> {
pub criterion_type: StoppingCriterionType,
pub threshold: T,
pub patience: usize,
pub min_improvement: T,
pub relative_improvement: bool,
}
#[derive(Debug, Clone, Copy)]
pub enum StoppingCriterionType {
NoImprovement,
PerformanceThreshold,
ResourceBudget,
TimeLimit,
ConvergenceDetection,
UserDefined,
}
#[derive(Debug, Clone)]
pub struct ResourceBudget<T: Float + Debug + Send + Sync + 'static> {
pub max_evaluations: usize,
pub max_time: Duration,
pub max_cost: T,
pub max_memory_gb: T,
pub max_energy_kwh: T,
pub current_usage: ResourceUsage<T>,
}
#[derive(Debug, Clone)]
pub struct HyperOptStatistics<T: Float + Debug + Send + Sync + 'static> {
pub total_evaluations: usize,
pub total_time: Duration,
pub best_performance: T,
pub average_performance: T,
pub improvement_rate: T,
pub strategy_effectiveness: HashMap<String, T>,
pub convergence_metrics: ConvergenceMetrics<T>,
}
#[derive(Debug, Clone)]
pub struct ConvergenceMetrics<T: Float + Debug + Send + Sync + 'static> {
pub convergence_rate: T,
pub plateau_length: usize,
pub diversity: T,
pub exploration_efficiency: T,
}
pub struct ConfigurationCache<T: Float + Debug + Send + Sync + 'static> {
cache: HashMap<u64, HyperOptResult<T>>,
cache_stats: CacheStatistics,
cache_policy: CachePolicy,
max_size: usize,
}
#[derive(Debug, Clone)]
pub struct CacheStatistics {
pub hits: usize,
pub misses: usize,
pub current_size: usize,
pub evictions: usize,
}
#[derive(Debug, Clone, Copy)]
pub enum CachePolicy {
LRU, LFU, TTL, Size, }
#[derive(Debug, Clone)]
pub struct StrategyStatistics<T: Float + Debug + Send + Sync + 'static> {
pub suggestions_made: usize,
pub avg_performance: T,
pub best_performance: T,
pub exploration_ratio: T,
pub custom_metrics: HashMap<String, T>,
}
pub struct BayesianOptimizationStrategy<T: Float + Debug + Send + Sync + 'static> {
gp_model: GaussianProcess<T>,
acquisition_fn: AcquisitionFunction<T>,
observations: Vec<(HyperparameterConfig<T>, T)>,
stats: StrategyStatistics<T>,
hyperparams: BayesianOptParams<T>,
}
#[derive(Debug)]
pub struct GaussianProcess<T: Float + Debug + Send + Sync + 'static> {
kernel: KernelFunction<T>,
training_data: Vec<(Array1<T>, T)>,
kernel_params: KernelParameters<T>,
noise_variance: T,
k_inv: Option<Array2<T>>,
}
#[derive(Debug, Clone)]
pub enum KernelFunction<T: Float + Debug + Send + Sync + 'static> {
RBF { lengthscale: T, variance: T },
Matern32 { lengthscale: T, variance: T },
Matern52 { lengthscale: T, variance: T },
Linear { variance: T },
Polynomial { degree: i32, variance: T },
Composite(Box<KernelFunction<T>>, Box<KernelFunction<T>>),
}
#[derive(Debug, Clone)]
pub struct KernelParameters<T: Float + Debug + Send + Sync + 'static> {
pub lengthscales: Array1<T>,
pub signal_variance: T,
pub noise_variance: T,
pub additional_params: HashMap<String, T>,
}
#[derive(Debug)]
pub enum AcquisitionFunction<T: Float + Debug + Send + Sync + 'static> {
ExpectedImprovement { xi: T },
ProbabilityOfImprovement { xi: T },
UpperConfidenceBound { kappa: T },
EntropySearch,
KnowledgeGradient,
ThompsonSampling,
}
#[derive(Debug, Clone)]
pub struct BayesianOptParams<T: Float + Debug + Send + Sync + 'static> {
pub n_initial_samples: usize,
pub acq_opt_config: AcquisitionOptConfig<T>,
pub gp_opt_config: GPOptConfig<T>,
pub convergence_config: ConvergenceConfig<T>,
}
#[derive(Debug, Clone)]
pub struct AcquisitionOptConfig<T: Float + Debug + Send + Sync + 'static> {
pub n_restarts: usize,
pub max_iterations: usize,
pub tolerance: T,
pub method: AcquisitionOptMethod,
}
#[derive(Debug, Clone, Copy)]
pub enum AcquisitionOptMethod {
LBFGS,
Adam,
CmaEs,
DifferentialEvolution,
RandomSearch,
}
#[derive(Debug, Clone)]
pub struct GPOptConfig<T: Float + Debug + Send + Sync + 'static> {
pub optimize_hyperparams: bool,
pub opt_frequency: usize,
pub ml_method: MLOptMethod,
pub priors: HashMap<String, PriorParameters<T>>,
}
#[derive(Debug, Clone, Copy)]
pub enum MLOptMethod {
LBFGS,
Adam,
MCMC,
VariationalInference,
}
#[derive(Debug, Clone)]
pub struct ConvergenceConfig<T: Float + Debug + Send + Sync + 'static> {
pub min_iterations: usize,
pub max_iterations: usize,
pub improvement_threshold: T,
pub patience: usize,
}
impl<T: Float + Debug + Send + Sync + 'static> HyperparameterOptimizer<T> {
pub fn new(
strategy: Box<dyn HyperOptStrategy<T>>,
search_space: HyperparameterSearchSpace<T>,
resource_budget: ResourceBudget<T>,
) -> Self {
Self {
strategy,
search_space,
optimization_history: VecDeque::new(),
best_configurations: Vec::new(),
fidelity_manager: None,
pbt_manager: None,
early_stopping: EarlyStoppingManager::new(),
resource_budget,
statistics: HyperOptStatistics::default(),
config_cache: ConfigurationCache::new(1000),
}
}
pub fn optimize(&mut self) -> Result<OptimizationResults<T>> {
let start_time = Instant::now();
self.strategy.initialize(&self.search_space)?;
while self.should_continue_optimization() {
let config = self.strategy.suggest_next(
&self
.optimization_history
.iter()
.cloned()
.collect::<Vec<_>>(),
)?;
if let Some(cached_result) = self.config_cache.get(&config) {
self.optimization_history.push_back(cached_result.clone());
continue;
}
let result = self.evaluate_configuration(config)?;
self.strategy.update(&result)?;
self.optimization_history.push_back(result.clone());
self.config_cache.insert(result.clone());
self.update_best_configurations(&result);
self.update_statistics();
}
let total_time = start_time.elapsed();
self.statistics.total_time = total_time;
Ok(OptimizationResults {
best_configs: self.best_configurations.clone(),
history: self.optimization_history.iter().cloned().collect(),
statistics: self.statistics.clone(),
resource_usage: self.resource_budget.current_usage.clone(),
})
}
fn should_continue_optimization(&self) -> bool {
if self.optimization_history.len() >= self.resource_budget.max_evaluations {
return false;
}
if self.statistics.total_time >= self.resource_budget.max_time {
return false;
}
self.early_stopping.should_continue(
&self
.optimization_history
.iter()
.cloned()
.collect::<Vec<_>>(),
)
}
fn evaluate_configuration(&self, config: HyperparameterConfig<T>) -> Result<HyperOptResult<T>> {
let performance = scirs2_core::numeric::NumCast::from(0.8).unwrap_or_else(|| T::zero());
let evaluation = EvaluationResults {
metric_scores: HashMap::new(),
overall_score: performance,
confidence_intervals: HashMap::new(),
evaluation_time: Duration::from_secs(60),
success: true,
error_message: None,
};
Ok(HyperOptResult {
config,
evaluation,
objectives: HashMap::new(),
constraint_violations: Vec::new(),
resource_usage: ResourceUsage {
evaluation_time: Duration::from_secs(60),
memory_mb: scirs2_core::numeric::NumCast::from(1024.0).unwrap_or_else(|| T::zero()),
cpu_hours: scirs2_core::numeric::NumCast::from(1.0).unwrap_or_else(|| T::zero()),
gpu_hours: T::zero(),
energy_kwh: scirs2_core::numeric::NumCast::from(0.1).unwrap_or_else(|| T::zero()),
cost: scirs2_core::numeric::NumCast::from(1.0).unwrap_or_else(|| T::zero()),
},
eval_metadata: EvaluationMetadata {
timestamp: std::time::SystemTime::now(),
evaluator_version: "1.0".to_string(),
environment: EvaluationEnvironment {
hardware: HardwareSpec {
cpu_model: "Unknown".to_string(),
cpu_cores: 8,
memory_gb: 16,
gpu_model: None,
gpu_memory_gb: None,
},
software: SoftwareSpec {
os: "Linux".to_string(),
rust_version: "1.70".to_string(),
dependencies: HashMap::new(),
},
dataset: DatasetSpec {
name: "benchmark".to_string(),
size: 10000,
features: 784,
task_type: "classification".to_string(),
},
},
random_seed: Some(42),
cv_fold: None,
},
fidelity_level: None,
})
}
fn update_best_configurations(&mut self, result: &HyperOptResult<T>) {
self.best_configurations.push(result.config.clone());
self.best_configurations.sort_by(|_a, _b| {
std::cmp::Ordering::Equal
});
if self.best_configurations.len() > 10 {
self.best_configurations.truncate(10);
}
}
fn update_statistics(&mut self) {
self.statistics.total_evaluations = self.optimization_history.len();
}
}
impl<T: Float + Debug + Send + Sync + 'static> EarlyStoppingManager<T> {
fn new() -> Self {
Self {
criteria: Vec::new(),
grace_period: 10,
performance_history: VecDeque::with_capacity(1000),
patience_counter: 0,
best_performance: None,
}
}
fn should_continue(&self, history: &[HyperOptResult<T>]) -> bool {
true
}
}
impl<T: Float + Debug + Send + Sync + 'static> ConfigurationCache<T> {
fn new(maxsize: usize) -> Self {
Self {
cache: HashMap::new(),
cache_stats: CacheStatistics {
hits: 0,
misses: 0,
current_size: 0,
evictions: 0,
},
cache_policy: CachePolicy::LRU,
max_size: maxsize,
}
}
fn get(&mut self, config: &HyperparameterConfig<T>) -> Option<&HyperOptResult<T>> {
let hash = config.metadata.config_hash;
if let Some(result) = self.cache.get(&hash) {
self.cache_stats.hits += 1;
Some(result)
} else {
self.cache_stats.misses += 1;
None
}
}
fn insert(&mut self, result: HyperOptResult<T>) {
let hash = result.config.metadata.config_hash;
if self.cache.len() >= self.max_size {
if let Some((key, _)) = self.cache.iter().next() {
let key = *key;
self.cache.remove(&key);
self.cache_stats.evictions += 1;
}
}
self.cache.insert(hash, result);
self.cache_stats.current_size = self.cache.len();
}
}
#[derive(Debug, Clone)]
pub struct OptimizationResults<T: Float + Debug + Send + Sync + 'static> {
pub best_configs: Vec<HyperparameterConfig<T>>,
pub history: Vec<HyperOptResult<T>>,
pub statistics: HyperOptStatistics<T>,
pub resource_usage: ResourceUsage<T>,
}
impl<T: Float + Debug + Send + Sync + 'static> Default for OptimizationResults<T> {
fn default() -> Self {
Self {
best_configs: Vec::new(),
history: Vec::new(),
statistics: HyperOptStatistics::default(),
resource_usage: ResourceUsage {
evaluation_time: Duration::new(0, 0),
memory_mb: T::zero(),
cpu_hours: T::zero(),
gpu_hours: T::zero(),
energy_kwh: T::zero(),
cost: T::zero(),
},
}
}
}
impl<T: Float + Debug + Send + Sync + 'static> Default for HyperOptStatistics<T> {
fn default() -> Self {
Self {
total_evaluations: 0,
total_time: Duration::new(0, 0),
best_performance: T::zero(),
average_performance: T::zero(),
improvement_rate: T::zero(),
strategy_effectiveness: HashMap::new(),
convergence_metrics: ConvergenceMetrics {
convergence_rate: T::zero(),
plateau_length: 0,
diversity: T::one(),
exploration_efficiency: T::zero(),
},
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_hyperparameter_search_space_creation() {
let mut search_space = HyperparameterSearchSpace::<f64> {
continuous_params: HashMap::new(),
integer_params: HashMap::new(),
categorical_params: HashMap::new(),
boolean_params: Vec::new(),
dependencies: Vec::new(),
constraints: Vec::new(),
metadata: SearchSpaceMetadata {
total_parameters: 0,
estimated_space_size: 1e6,
complexity_score: 5.0,
created_at: "2024-01-01T00:00:00Z".to_string(),
version: "1.0".to_string(),
},
};
search_space.continuous_params.insert(
"learning_rate".to_string(),
ContinuousParameter {
min_value: 1e-6,
max_value: 1e-1,
distribution: ParameterDistribution::LogUniform,
default_value: Some(1e-3),
transformation: Some(ParameterTransformation::Log),
prior_params: None,
},
);
assert_eq!(search_space.continuous_params.len(), 1);
assert!(search_space.continuous_params.contains_key("learning_rate"));
}
#[test]
fn test_hyperparameter_config_creation() {
let mut parameters = HashMap::new();
parameters.insert(
"learning_rate".to_string(),
ParameterValue::Continuous(0.001),
);
parameters.insert("batch_size".to_string(), ParameterValue::Integer(32));
parameters.insert(
"optimizer".to_string(),
ParameterValue::Categorical("Adam".to_string()),
);
parameters.insert("use_dropout".to_string(), ParameterValue::Boolean(true));
let config = HyperparameterConfig {
id: "config_001".to_string(),
parameters,
metadata: ConfigMetadata {
created_at: std::time::SystemTime::now(),
source_strategy: "random".to_string(),
parent_configs: Vec::new(),
config_hash: 12345,
priority_score: 0.8,
},
generation_info: GenerationInfo {
strategy: "random".to_string(),
method: GenerationMethod::Random,
exploration_score: 0.9,
confidence: 0.5,
},
validation_status: ValidationStatus::Valid,
};
assert_eq!(config.parameters.len(), 4);
assert!(matches!(config.validation_status, ValidationStatus::Valid));
}
#[test]
fn test_resource_budget_tracking() {
let budget = ResourceBudget {
max_evaluations: 1000,
max_time: Duration::from_secs(3600),
max_cost: 100.0,
max_memory_gb: 16.0,
max_energy_kwh: 10.0,
current_usage: ResourceUsage {
evaluation_time: Duration::from_secs(0),
memory_mb: 0.0,
cpu_hours: 0.0,
gpu_hours: 0.0,
energy_kwh: 0.0,
cost: 0.0,
},
};
assert_eq!(budget.max_evaluations, 1000);
assert_eq!(budget.max_time.as_secs(), 3600);
}
}