use std::fmt::Debug;
use scirs2_core::numeric::Float;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OptimizerArchitecture<T: Float + Debug + Send + Sync + 'static> {
pub components: Vec<OptimizerComponent<T>>,
pub connections: Vec<ComponentConnection>,
pub metadata: HashMap<String, String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OptimizerComponent<T: Float + Debug + Send + Sync + 'static> {
pub component_type: ComponentType,
pub hyperparameters: HashMap<String, T>,
pub connections: Vec<ComponentConnection>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum ComponentType {
SGD,
Adam,
AdaGrad,
RMSprop,
AdamW,
LAMB,
LARS,
Lion,
RAdam,
Lookahead,
SAM,
LBFGS,
SparseAdam,
GroupedAdam,
MAML,
Reptile,
MetaSGD,
ConstantLR,
ExponentialLR,
StepLR,
CosineAnnealingLR,
OneCycleLR,
CyclicLR,
L1Regularizer,
L2Regularizer,
ElasticNetRegularizer,
DropoutRegularizer,
GradientClipping,
WeightDecay,
AdaptiveLR,
AdaptiveMomentum,
AdaptiveRegularization,
LSTMOptimizer,
TransformerOptimizer,
AttentionOptimizer,
Custom(String),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ComponentConnection {
pub from: usize,
pub to: usize,
pub connection_type: ConnectionType,
pub weight: f64,
pub metadata: HashMap<String, String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum ConnectionType {
Sequential,
Parallel,
Skip,
Residual,
Attention,
Gating,
Feedback,
Custom(String),
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum ConnectionPattern {
Sequential,
Parallel,
Skip,
Dense,
Hierarchical,
Graph,
Custom,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SearchSpace {
pub component_types: Vec<ComponentType>,
pub hyperparameter_ranges: HashMap<ComponentType, ComponentHyperparameters>,
pub connection_patterns: Vec<ConnectionPattern>,
pub constraints: ArchitectureConstraints,
pub metadata: SearchSpaceMetadata,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ComponentHyperparameters {
pub continuous: HashMap<String, (f64, f64)>,
pub integer: HashMap<String, (i32, i32)>,
pub categorical: HashMap<String, Vec<String>>,
pub boolean: Vec<String>,
pub log_uniform: HashMap<String, (f64, f64)>,
pub dependencies: HashMap<String, ParameterDependency>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ParameterDependency {
pub depends_on: String,
pub condition: DependencyCondition,
pub valid_values: ParameterValues,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum DependencyCondition {
Equals(String),
GreaterThan(f64),
LessThan(f64),
InRange(f64, f64),
InSet(Vec<String>),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ParameterValues {
Continuous(f64, f64),
Integer(i32, i32),
Categorical(Vec<String>),
Boolean(bool),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ArchitectureConstraints {
pub max_components: usize,
pub min_components: usize,
pub max_memory_mb: usize,
pub max_computation_time_ms: f64,
pub max_parameters: usize,
pub compatibility: Vec<CompatibilityConstraint>,
pub performance: PerformanceConstraints,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CompatibilityConstraint {
pub component1: ComponentType,
pub component2: ComponentType,
pub compatibility_type: CompatibilityType,
pub conditions: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum CompatibilityType {
Compatible,
Incompatible,
Conditional,
Synergistic,
Conflicting,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PerformanceConstraints {
pub min_convergence_speed: f64,
pub max_training_time_hours: f64,
pub min_final_performance: f64,
pub max_performance_variance: f64,
pub robustness_requirements: RobustnessRequirements,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RobustnessRequirements {
pub hyperparameter_sensitivity: f64,
pub noise_tolerance: f64,
pub distribution_shift_robustness: f64,
pub initialization_sensitivity: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SearchSpaceMetadata {
pub name: String,
pub version: String,
pub description: String,
pub target_domains: Vec<OptimizationDomain>,
pub complexity_level: ComplexityLevel,
pub created_at: String,
pub author: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum OptimizationDomain {
ComputerVision,
NaturalLanguageProcessing,
ReinforcementLearning,
RecommendationSystems,
TimeSeriesForecasting,
GraphAnalytics,
ScientificComputing,
FinancialModeling,
RoboticsControl,
GeneralMachineLearning,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum ComplexityLevel {
Simple,
Moderate,
Complex,
VeryComplex,
ExpertLevel,
}
#[derive(Debug, Clone)]
pub struct ValidationResult {
pub is_valid: bool,
pub errors: Vec<ValidationError>,
pub warnings: Vec<ValidationWarning>,
pub resource_estimate: ResourceEstimate,
}
#[derive(Debug, Clone)]
pub struct ValidationError {
pub error_type: ValidationErrorType,
pub message: String,
pub component_index: Option<usize>,
pub parameter_name: Option<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ValidationErrorType {
InvalidParameter,
IncompatibleComponents,
ConstraintViolation,
InvalidConnection,
ResourceExceeded,
DependencyViolation,
}
#[derive(Debug, Clone)]
pub struct ValidationWarning {
pub warning_type: ValidationWarningType,
pub message: String,
pub severity: WarningSeverity,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ValidationWarningType {
SuboptimalConfiguration,
PerformanceImpact,
ResourceInefficiency,
CompatibilityIssue,
ExperimentalFeature,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WarningSeverity {
Low,
Medium,
High,
}
#[derive(Debug, Clone)]
pub struct ResourceEstimate {
pub memory_mb: f64,
pub computation_time_ms: f64,
pub model_parameters: usize,
pub training_time_hours: f64,
pub energy_consumption_kwh: f64,
}
pub struct ArchitectureFactory;
impl ArchitectureFactory {
pub fn create_sgd_architecture<T: Float + Debug + Send + Sync + 'static>() -> OptimizerArchitecture<T> {
let mut hyperparameters = HashMap::new();
hyperparameters.insert("learning_rate".to_string(), scirs2_core::numeric::NumCast::from(0.01).unwrap_or_else(|| T::zero()));
hyperparameters.insert("momentum".to_string(), scirs2_core::numeric::NumCast::from(0.9).unwrap_or_else(|| T::zero()));
hyperparameters.insert("weight_decay".to_string(), scirs2_core::numeric::NumCast::from(0.0001).unwrap_or_else(|| T::zero()));
OptimizerArchitecture {
components: vec![OptimizerComponent {
component_type: ComponentType::SGD,
hyperparameters,
connections: Vec::new(),
}],
connections: Vec::new(),
metadata: HashMap::new(),
}
}
pub fn create_adam_architecture<T: Float + Debug + Send + Sync + 'static>() -> OptimizerArchitecture<T> {
let mut hyperparameters = HashMap::new();
hyperparameters.insert("learning_rate".to_string(), scirs2_core::numeric::NumCast::from(0.001).unwrap_or_else(|| T::zero()));
hyperparameters.insert("beta1".to_string(), scirs2_core::numeric::NumCast::from(0.9).unwrap_or_else(|| T::zero()));
hyperparameters.insert("beta2".to_string(), scirs2_core::numeric::NumCast::from(0.999).unwrap_or_else(|| T::zero()));
hyperparameters.insert("epsilon".to_string(), scirs2_core::numeric::NumCast::from(1e-7).unwrap_or_else(|| T::zero())); hyperparameters.insert("weight_decay".to_string(), scirs2_core::numeric::NumCast::from(1e-5).unwrap_or_else(|| T::zero()));
OptimizerArchitecture {
components: vec![OptimizerComponent {
component_type: ComponentType::Adam,
hyperparameters,
connections: Vec::new(),
}],
connections: Vec::new(),
metadata: HashMap::new(),
}
}
pub fn create_hybrid_architecture<T: Float + Debug + Send + Sync + 'static>() -> OptimizerArchitecture<T> {
let mut components = Vec::new();
let mut adam_params = HashMap::new();
adam_params.insert("learning_rate".to_string(), scirs2_core::numeric::NumCast::from(0.001).unwrap_or_else(|| T::zero()));
adam_params.insert("beta1".to_string(), scirs2_core::numeric::NumCast::from(0.9).unwrap_or_else(|| T::zero()));
adam_params.insert("beta2".to_string(), scirs2_core::numeric::NumCast::from(0.999).unwrap_or_else(|| T::zero()));
components.push(OptimizerComponent {
component_type: ComponentType::Adam,
hyperparameters: adam_params,
connections: Vec::new(),
});
let mut scheduler_params = HashMap::new();
scheduler_params.insert("t_max".to_string(), scirs2_core::numeric::NumCast::from(100.0).unwrap_or_else(|| T::zero()));
scheduler_params.insert("eta_min".to_string(), scirs2_core::numeric::NumCast::from(1e-6).unwrap_or_else(|| T::zero()));
components.push(OptimizerComponent {
component_type: ComponentType::CosineAnnealingLR,
hyperparameters: scheduler_params,
connections: Vec::new(),
});
let mut reg_params = HashMap::new();
reg_params.insert("lambda".to_string(), scirs2_core::numeric::NumCast::from(0.0001).unwrap_or_else(|| T::zero()));
components.push(OptimizerComponent {
component_type: ComponentType::L2Regularizer,
hyperparameters: reg_params,
connections: Vec::new(),
});
let connections = vec![
ComponentConnection {
from: 0,
to: 1,
connection_type: ConnectionType::Sequential,
weight: 1.0,
metadata: HashMap::new(),
},
ComponentConnection {
from: 1,
to: 2,
connection_type: ConnectionType::Sequential,
weight: 1.0,
metadata: HashMap::new(),
},
];
OptimizerArchitecture {
components,
connections,
metadata: HashMap::new(),
}
}
pub fn create_lstm_optimizer_architecture<T: Float + Debug + Send + Sync + 'static>() -> OptimizerArchitecture<T> {
let mut hyperparameters = HashMap::new();
hyperparameters.insert("hidden_size".to_string(), scirs2_core::numeric::NumCast::from(256.0).unwrap_or_else(|| T::zero()));
hyperparameters.insert("num_layers".to_string(), scirs2_core::numeric::NumCast::from(2.0).unwrap_or_else(|| T::zero()));
hyperparameters.insert("dropout".to_string(), scirs2_core::numeric::NumCast::from(0.1).unwrap_or_else(|| T::zero()));
hyperparameters.insert("meta_learning_rate".to_string(), scirs2_core::numeric::NumCast::from(0.001).unwrap_or_else(|| T::zero()));
OptimizerArchitecture {
components: vec![OptimizerComponent {
component_type: ComponentType::LSTMOptimizer,
hyperparameters,
connections: Vec::new(),
}],
connections: Vec::new(),
metadata: HashMap::new(),
}
}
}
pub struct ArchitectureValidator {
search_space: SearchSpace,
}
impl ArchitectureValidator {
pub fn new(_searchspace: SearchSpace) -> Self {
Self {
search_space: _searchspace,
}
}
pub fn validate<T: Float + Debug + Send + Sync + 'static>(&self, architecture: &OptimizerArchitecture<T>) -> ValidationResult {
let mut errors = Vec::new();
let mut warnings = Vec::new();
if architecture.components.len() > self.search_space.constraints.max_components {
errors.push(ValidationError {
error_type: ValidationErrorType::ConstraintViolation,
message: format!(
"Too many components: {} > {}",
architecture.components.len(),
self.search_space.constraints.max_components
),
component_index: None,
parameter_name: None,
});
}
if architecture.components.len() < self.search_space.constraints.min_components {
errors.push(ValidationError {
error_type: ValidationErrorType::ConstraintViolation,
message: format!(
"Too few components: {} < {}",
architecture.components.len(),
self.search_space.constraints.min_components
),
component_index: None,
parameter_name: None,
});
}
for (i, component) in architecture.components.iter().enumerate() {
self.validate_component(component, i, &mut errors, &mut warnings);
}
self.validate_connections(architecture, &mut errors, &mut warnings);
self.validate_compatibility(architecture, &mut errors, &mut warnings);
let resource_estimate = self.estimate_resources(architecture);
if resource_estimate.memory_mb > self.search_space.constraints.max_memory_mb as f64 {
errors.push(ValidationError {
error_type: ValidationErrorType::ResourceExceeded,
message: format!(
"Memory usage exceeds limit: {:.2} MB > {} MB",
resource_estimate.memory_mb, self.search_space.constraints.max_memory_mb
),
component_index: None,
parameter_name: None,
});
}
ValidationResult {
is_valid: errors.is_empty(),
errors,
warnings,
resource_estimate,
}
}
fn validate_component<T: Float + Debug + Send + Sync + 'static>(
&self,
component: &OptimizerComponent<T>,
index: usize,
errors: &mut Vec<ValidationError>,
warnings: &mut Vec<ValidationWarning>,
) {
if !self
.search_space
.component_types
.contains(&component.component_type)
{
errors.push(ValidationError {
error_type: ValidationErrorType::InvalidParameter,
message: format!(
"Component type {:?} not in search space",
component.component_type
),
component_index: Some(index),
parameter_name: None,
});
return;
}
if let Some(param_spec) = self
.search_space
.hyperparameter_ranges
.get(&component.component_type)
{
self.validate_hyperparameters(component, param_spec, index, errors, warnings);
}
}
fn validate_hyperparameters<T: Float + Debug + Send + Sync + 'static>(
&self,
component: &OptimizerComponent<T>,
param_spec: &ComponentHyperparameters,
component_index: usize,
errors: &mut Vec<ValidationError>,
_warnings: &mut Vec<ValidationWarning>,
) {
for (param_name, param_value) in &component.hyperparameters {
let value = param_value.to_f64().unwrap_or(0.0);
if let Some((min, max)) = param_spec.continuous.get(param_name) {
if value < *min || value > *max {
errors.push(ValidationError {
error_type: ValidationErrorType::InvalidParameter,
message: format!(
"Parameter {} value {} out of range [{}, {}]",
param_name, value, min, max
),
component_index: Some(component_index),
parameter_name: Some(param_name.clone()),
});
}
}
if let Some((min, max)) = param_spec.log_uniform.get(param_name) {
if value <= 0.0 || value < *min || value > *max {
errors.push(ValidationError {
error_type: ValidationErrorType::InvalidParameter,
message: format!(
"Log-uniform parameter {} value {} out of range [{}, {}]",
param_name, value, min, max
),
component_index: Some(component_index),
parameter_name: Some(param_name.clone()),
});
}
}
if let Some((min, max)) = param_spec.integer.get(param_name) {
let int_value = value as i32;
if int_value < *min || int_value > *max {
errors.push(ValidationError {
error_type: ValidationErrorType::InvalidParameter,
message: format!(
"Integer parameter {} value {} out of range [{}, {}]",
param_name, int_value, min, max
),
component_index: Some(component_index),
parameter_name: Some(param_name.clone()),
});
}
}
}
}
fn validate_connections<T: Float + Debug + Send + Sync + 'static>(
&self,
architecture: &OptimizerArchitecture<T>,
errors: &mut Vec<ValidationError>,
_warnings: &mut Vec<ValidationWarning>,
) {
for connection in &architecture.connections {
if connection.from >= architecture.components.len() {
errors.push(ValidationError {
error_type: ValidationErrorType::InvalidConnection,
message: format!("Connection source index {} out of bounds", connection.from),
component_index: None,
parameter_name: None,
});
}
if connection.to >= architecture.components.len() {
errors.push(ValidationError {
error_type: ValidationErrorType::InvalidConnection,
message: format!("Connection target index {} out of bounds", connection.to),
component_index: None,
parameter_name: None,
});
}
}
}
fn validate_compatibility<T: Float + Debug + Send + Sync + 'static>(
&self,
architecture: &OptimizerArchitecture<T>,
errors: &mut Vec<ValidationError>,
warnings: &mut Vec<ValidationWarning>,
) {
for constraint in &self.search_space.constraints.compatibility {
let component1_exists = architecture
.components
.iter()
.any(|c| c.component_type == constraint.component1);
let component2_exists = architecture
.components
.iter()
.any(|c| c.component_type == constraint.component2);
if component1_exists && component2_exists {
match constraint.compatibility_type {
CompatibilityType::Incompatible => {
errors.push(ValidationError {
error_type: ValidationErrorType::IncompatibleComponents,
message: format!(
"Incompatible components: {:?} and {:?}",
constraint.component1, constraint.component2
),
component_index: None,
parameter_name: None,
});
}
CompatibilityType::Conflicting => {
warnings.push(ValidationWarning {
warning_type: ValidationWarningType::CompatibilityIssue,
message: format!(
"Conflicting components: {:?} and {:?}",
constraint.component1, constraint.component2
),
severity: WarningSeverity::High,
});
}
_ => {} }
}
}
}
fn estimate_resources<T: Float + Debug + Send + Sync + 'static>(
&self,
architecture: &OptimizerArchitecture<T>,
) -> ResourceEstimate {
let mut memory_mb = 0.0;
let mut computation_time_ms = 0.0;
let mut model_parameters = 0;
for component in &architecture.components {
match component.component_type {
ComponentType::LSTMOptimizer => {
let hidden_size = component
.hyperparameters
.get("hidden_size")
.map(|v| v.to_f64().unwrap_or(256.0))
.unwrap_or(256.0);
let num_layers = component
.hyperparameters
.get("num_layers")
.map(|v| v.to_f64().unwrap_or(2.0))
.unwrap_or(2.0);
memory_mb += hidden_size * num_layers * 4.0 / 1024.0 / 1024.0; computation_time_ms += hidden_size * num_layers * 0.01;
model_parameters += (hidden_size * hidden_size * 4.0 * num_layers) as usize;
}
ComponentType::TransformerOptimizer => {
memory_mb += 512.0; computation_time_ms += 10.0;
model_parameters += 1_000_000; }
_ => {
memory_mb += 10.0; computation_time_ms += 1.0;
model_parameters += 1000;
}
}
}
ResourceEstimate {
memory_mb,
computation_time_ms,
model_parameters,
training_time_hours: computation_time_ms / 3600.0 / 1000.0 * 1000.0, energy_consumption_kwh: computation_time_ms / 3600.0 / 1000.0 * 0.1, }
}
}
impl Default for SearchSpace {
fn default() -> Self {
let component_types = vec![
ComponentType::SGD,
ComponentType::Adam,
ComponentType::AdaGrad,
ComponentType::RMSprop,
ComponentType::AdamW,
ComponentType::LAMB,
ComponentType::LARS,
ComponentType::Lion,
ComponentType::ConstantLR,
ComponentType::ExponentialLR,
ComponentType::CosineAnnealingLR,
ComponentType::L1Regularizer,
ComponentType::L2Regularizer,
ComponentType::GradientClipping,
];
let mut hyperparameter_ranges = HashMap::new();
let mut sgd_params = ComponentHyperparameters {
continuous: HashMap::new(),
integer: HashMap::new(),
categorical: HashMap::new(),
boolean: Vec::new(),
log_uniform: HashMap::new(),
dependencies: HashMap::new(),
};
sgd_params
.log_uniform
.insert("learning_rate".to_string(), (1e-6, 1e-1));
sgd_params
.continuous
.insert("momentum".to_string(), (0.0, 0.99));
sgd_params
.log_uniform
.insert("weight_decay".to_string(), (1e-8, 1e-2));
hyperparameter_ranges.insert(ComponentType::SGD, sgd_params);
let mut adam_params = ComponentHyperparameters {
continuous: HashMap::new(),
integer: HashMap::new(),
categorical: HashMap::new(),
boolean: Vec::new(),
log_uniform: HashMap::new(),
dependencies: HashMap::new(),
};
adam_params
.log_uniform
.insert("learning_rate".to_string(), (1e-6, 1e-1));
adam_params
.continuous
.insert("beta1".to_string(), (0.8, 0.999));
adam_params
.continuous
.insert("beta2".to_string(), (0.9, 0.9999));
adam_params
.log_uniform
.insert("epsilon".to_string(), (1e-10, 1e-6));
adam_params
.log_uniform
.insert("weight_decay".to_string(), (1e-8, 1e-2));
hyperparameter_ranges.insert(ComponentType::Adam, adam_params);
Self {
component_types,
hyperparameter_ranges,
connection_patterns: vec![
ConnectionPattern::Sequential,
ConnectionPattern::Parallel,
ConnectionPattern::Skip,
],
constraints: ArchitectureConstraints {
max_components: 10,
min_components: 1,
max_memory_mb: 8192,
max_computation_time_ms: 1000.0,
max_parameters: 10_000_000,
compatibility: Vec::new(),
performance: PerformanceConstraints {
min_convergence_speed: 0.01,
max_training_time_hours: 24.0,
min_final_performance: 0.5,
max_performance_variance: 0.1,
robustness_requirements: RobustnessRequirements {
hyperparameter_sensitivity: 0.1,
noise_tolerance: 0.05,
distribution_shift_robustness: 0.1,
initialization_sensitivity: 0.05,
},
},
},
metadata: SearchSpaceMetadata {
name: "Default Optimizer Search Space".to_string(),
version: "1.0.0".to_string(),
description: "Standard search space for optimizer architectures".to_string(),
target_domains: vec![OptimizationDomain::GeneralMachineLearning],
complexity_level: ComplexityLevel::Moderate,
created_at: "2024-01-01T00:00:00Z".to_string(),
author: "SciRS2 Team".to_string(),
},
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sgd_architecture_creation() {
let arch = ArchitectureFactory::create_sgd_architecture::<f64>();
assert_eq!(arch.components.len(), 1);
assert_eq!(arch.components[0].component_type, ComponentType::SGD);
assert!(arch.components[0]
.hyperparameters
.contains_key("learning_rate"));
}
#[test]
fn test_adam_architecture_creation() {
let arch = ArchitectureFactory::create_adam_architecture::<f64>();
assert_eq!(arch.components.len(), 1);
assert_eq!(arch.components[0].component_type, ComponentType::Adam);
assert!(arch.components[0].hyperparameters.contains_key("beta1"));
assert!(arch.components[0].hyperparameters.contains_key("beta2"));
}
#[test]
fn test_hybrid_architecture_creation() {
let arch = ArchitectureFactory::create_hybrid_architecture::<f64>();
assert_eq!(arch.components.len(), 3);
assert_eq!(arch.connections.len(), 2);
}
#[test]
fn test_architecture_validation() {
let search_space = SearchSpace::default();
let validator = ArchitectureValidator::new(search_space);
let arch = ArchitectureFactory::create_adam_architecture::<f64>();
let result = validator.validate(&arch);
assert!(result.is_valid);
assert!(result.errors.is_empty());
}
#[test]
fn test_resource_estimation() {
let search_space = SearchSpace::default();
let validator = ArchitectureValidator::new(search_space);
let arch = ArchitectureFactory::create_lstm_optimizer_architecture::<f64>();
let result = validator.validate(&arch);
assert!(result.resource_estimate.memory_mb > 0.0);
assert!(result.resource_estimate.model_parameters > 0);
}
}