Skip to main content

optirs_learned/
common.rs

1//! Common types and configurations for learned optimizers
2
3use crate::error::{OptimError, Result};
4use scirs2_core::ndarray::{Array1, Array2};
5use scirs2_core::numeric::{Float, ToPrimitive};
6use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8use std::fmt::Debug;
9
10/// Fallibly convert a primitive numeric value (an `f64` constant, a `usize`
11/// count, ...) into a generic scalar type `T`.
12///
13/// This replaces the `T::from(x).expect("unwrap failed")` pattern that was
14/// spread across this crate: a scalar type that genuinely cannot represent `x`
15/// now produces an honest [`OptimError::InvalidConfig`] instead of panicking in
16/// the middle of an optimizer step.
17pub(crate) fn cast_scalar<T: Float, V: ToPrimitive + Copy + Debug>(value: V) -> Result<T> {
18    T::from(value).ok_or_else(|| {
19        OptimError::InvalidConfig(format!(
20            "{value:?} cannot be represented in this optimizer's scalar type"
21        ))
22    })
23}
24
25/// [`cast_scalar`] for a value that must also be strictly positive, used for
26/// divisors so a zero denominator is reported rather than producing an
27/// infinity or a NaN.
28pub(crate) fn cast_positive<T: Float, V: ToPrimitive + Copy + Debug>(
29    value: V,
30    what: &str,
31) -> Result<T> {
32    let converted: T = cast_scalar(value)?;
33    if converted > T::zero() {
34        Ok(converted)
35    } else {
36        Err(OptimError::InsufficientData(format!(
37            "{what} must be positive, got {value:?}"
38        )))
39    }
40}
41
42/// Base configuration for learned optimizers
43#[derive(Debug, Clone, Serialize, Deserialize)]
44pub struct LearnedOptimizerConfig {
45    /// Learning rate
46    pub learning_rate: f64,
47
48    /// Meta-learning rate for higher-level optimization
49    pub meta_learning_rate: f64,
50
51    /// Batch size for training
52    pub batch_size: usize,
53
54    /// Maximum number of optimization steps
55    pub max_steps: usize,
56
57    /// Convergence threshold
58    pub convergence_threshold: f64,
59
60    /// Whether to use momentum
61    pub use_momentum: bool,
62
63    /// Momentum decay factor
64    pub momentum_decay: f64,
65
66    /// Weight decay for regularization
67    pub weight_decay: f64,
68
69    /// Hidden size for neural networks
70    pub hidden_size: usize,
71
72    /// Number of attention heads
73    pub attention_heads: usize,
74
75    /// Size of gradient history buffer
76    pub gradient_history_size: usize,
77
78    /// Number of input features
79    pub input_features: usize,
80
81    /// Number of output features
82    pub output_features: usize,
83
84    /// Number of layers in neural networks
85    pub num_layers: usize,
86
87    /// Dropout rate for regularization
88    pub dropout_rate: f64,
89
90    /// Whether to use attention mechanisms
91    pub use_attention: bool,
92
93    /// Random seed for reproducibility
94    pub seed: Option<u64>,
95}
96
97impl Default for LearnedOptimizerConfig {
98    fn default() -> Self {
99        Self {
100            learning_rate: 0.001,
101            meta_learning_rate: 0.0001,
102            batch_size: 32,
103            max_steps: 1000,
104            convergence_threshold: 1e-6,
105            use_momentum: true,
106            momentum_decay: 0.9,
107            weight_decay: 1e-4,
108            hidden_size: 256,
109            attention_heads: 8,
110            gradient_history_size: 50,
111            input_features: 256,
112            output_features: 256,
113            num_layers: 3,
114            dropout_rate: 0.1,
115            use_attention: true,
116            seed: None,
117        }
118    }
119}
120
121/// Meta-optimization strategies
122#[derive(Debug, Clone, Serialize, Deserialize, Default)]
123pub enum MetaOptimizationStrategy {
124    /// First-order approximation (FOMAML)
125    #[default]
126    FirstOrder,
127
128    /// Full second-order gradients (MAML)
129    SecondOrder,
130
131    /// MAML algorithm (alias for SecondOrder)
132    MAML,
133
134    /// Reptile algorithm
135    Reptile,
136
137    /// Custom gradient-based meta-learning
138    Custom {
139        inner_steps: usize,
140        outer_learning_rate: f64,
141    },
142}
143
144/// Base optimizer state
145#[derive(Debug, Clone)]
146pub struct OptimizerState<T: Float + Debug + Send + Sync + 'static> {
147    /// Current parameters
148    pub parameters: Array1<T>,
149
150    /// Current gradients
151    pub gradients: Array1<T>,
152
153    /// Momentum buffer
154    pub momentum: Option<Array1<T>>,
155
156    /// Hidden states for neural optimizers
157    pub hidden_states: HashMap<String, Array1<T>>,
158
159    /// Memory buffers for attention mechanisms
160    pub memory_buffers: HashMap<String, Array2<T>>,
161
162    /// Current step number
163    pub step: usize,
164
165    /// Step count (alias for step)
166    pub step_count: usize,
167
168    /// Current loss value
169    pub loss: Option<T>,
170
171    /// Learning rate schedule
172    pub learning_rate: T,
173
174    /// Additional state metadata
175    pub metadata: StateMetadata,
176}
177
178/// Learning rate a freshly-created [`OptimizerState`] starts at.
179pub const DEFAULT_LEARNING_RATE: f64 = 0.001;
180
181impl<T: Float + Debug + Send + Sync + 'static> OptimizerState<T> {
182    /// A zeroed state for `num_params` parameters at
183    /// [`DEFAULT_LEARNING_RATE`].
184    ///
185    /// # Errors
186    /// Returns `Err` when the default learning rate cannot be represented in
187    /// `T`. This used to panic.
188    pub fn new(num_params: usize) -> Result<Self> {
189        Ok(Self {
190            parameters: Array1::zeros(num_params),
191            gradients: Array1::zeros(num_params),
192            momentum: None,
193            hidden_states: HashMap::new(),
194            memory_buffers: HashMap::new(),
195            step: 0,
196            step_count: 0,
197            loss: None,
198            learning_rate: cast_scalar(DEFAULT_LEARNING_RATE)?,
199            metadata: StateMetadata::default(),
200        })
201    }
202}
203
204/// State metadata
205#[derive(Debug, Clone)]
206pub struct StateMetadata {
207    /// Task identifier
208    pub task_id: Option<String>,
209
210    /// Optimizer type used
211    pub optimizer_type: Option<String>,
212
213    /// Version information
214    pub version: String,
215
216    /// Timestamp of creation/update
217    pub timestamp: std::time::SystemTime,
218
219    /// Checksum for integrity
220    pub checksum: u64,
221
222    /// Compression level used
223    pub compression_level: u8,
224
225    /// Additional custom metadata
226    pub custom_data: HashMap<String, String>,
227}
228
229impl Default for StateMetadata {
230    fn default() -> Self {
231        Self {
232            task_id: None,
233            optimizer_type: None,
234            version: "1.0".to_string(),
235            timestamp: std::time::SystemTime::now(),
236            checksum: 0,
237            compression_level: 0,
238            custom_data: HashMap::new(),
239        }
240    }
241}
242
243/// Neural optimizer type variants
244#[derive(Debug, Clone, Serialize, Deserialize)]
245pub enum NeuralOptimizerType {
246    /// Transformer-based optimizer
247    Transformer,
248
249    /// LSTM-based optimizer
250    LSTM,
251
252    /// Simple MLP optimizer
253    MLP,
254
255    /// Convolutional optimizer
256    CNN,
257}
258
259/// Task context for meta-learning
260#[derive(Debug, Clone)]
261pub struct TaskContext<T: Float + Debug + Send + Sync + 'static> {
262    /// Task identifier
263    pub task_id: String,
264
265    /// Initial parameters for the task
266    pub initial_parameters: Array1<T>,
267
268    /// Task-specific data
269    pub task_data: Array2<T>,
270
271    /// Target values for the task
272    pub targets: Array1<T>,
273
274    /// Task difficulty or complexity measure
275    pub difficulty: f64,
276}
277
278/// Neural optimizer metrics
279#[derive(Debug, Clone)]
280pub struct NeuralOptimizerMetrics {
281    /// Average loss over training
282    pub avg_loss: f64,
283
284    /// Convergence rate
285    pub convergence_rate: f64,
286
287    /// Number of steps to convergence
288    pub steps_to_convergence: Option<usize>,
289
290    /// Final accuracy/performance
291    pub final_performance: f64,
292
293    /// Training time in seconds
294    pub training_time: f64,
295}
296
297/// Task performance metrics
298#[derive(Debug, Clone)]
299pub struct TaskPerformance {
300    /// Task identifier
301    pub task_id: String,
302
303    /// Performance score (higher is better)
304    pub score: f64,
305
306    /// Whether the task converged
307    pub converged: bool,
308
309    /// Number of optimization steps taken
310    pub steps_taken: usize,
311
312    /// Final loss value
313    pub final_loss: f64,
314}