1#![allow(clippy::too_many_arguments)]
7#![allow(dead_code)]
8
9use crate::error::Result;
10use scirs2_core::ndarray::{Array1, Array2};
11use scirs2_core::numeric::Float;
12use scirs2_core::random::Rng;
13use serde::{Deserialize, Serialize};
14use std::time::Duration;
15
16#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct NetworkConfig {
19 pub optimizer_hidden_layers: Vec<usize>,
21 pub predictor_hidden_layers: Vec<usize>,
23 pub activation: ActivationFunction,
25 pub dropout_rate: f64,
27 pub batch_norm: bool,
29 pub learning_rate: f64,
31 pub weight_decay: f64,
33}
34
35impl Default for NetworkConfig {
36 fn default() -> Self {
37 Self {
38 optimizer_hidden_layers: vec![128, 64, 32],
39 predictor_hidden_layers: vec![64, 32, 16],
40 activation: ActivationFunction::ReLU,
41 dropout_rate: 0.1,
42 batch_norm: true,
43 learning_rate: 0.001,
44 weight_decay: 0.0001,
45 }
46 }
47}
48
49#[derive(Debug, Clone, Serialize, Deserialize)]
51pub enum ActivationFunction {
52 ReLU,
53 LeakyReLU { alpha: f64 },
54 ELU { alpha: f64 },
55 Swish,
56 GELU,
57 Tanh,
58 Sigmoid,
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize)]
63pub struct FeatureConfig {
64 pub extraction_method: FeatureExtractionMethod,
66 pub num_features: usize,
68 pub time_window: Duration,
70 pub auto_feature_selection: bool,
72 pub normalization: FeatureNormalization,
74}
75
76#[derive(Debug, Clone, Serialize, Deserialize)]
78pub enum FeatureExtractionMethod {
79 Statistical,
81 TimeSeries,
83 FrequencyDomain,
85 Wavelet { wavelet_type: String },
87 NeuralAutoencoder { encoding_dim: usize },
89 Ensemble {
91 methods: Vec<FeatureExtractionMethod>,
92 },
93}
94
95#[derive(Debug, Clone, Serialize, Deserialize)]
97pub enum FeatureNormalization {
98 None,
99 StandardScore,
100 MinMax,
101 Robust,
102 Quantile,
103}
104
105#[derive(Debug)]
107pub struct MultiArmedBandit<F: Float + std::fmt::Debug> {
108 actions: Vec<ParameterConfiguration<F>>,
110 algorithm: BanditAlgorithm<F>,
112 rewards: Vec<Vec<F>>,
114 counts: Vec<usize>,
116 exploration_rate: f64,
118 regret_tracker: RegretTracker<F>,
120}
121
122#[derive(Debug, Clone)]
124pub struct ParameterConfiguration<F: Float + std::fmt::Debug> {
125 pub name: String,
127 pub value: F,
129 pub bounds: (F, F),
131 pub param_type: ParameterType,
133}
134
135#[derive(Debug, Clone)]
137pub enum ParameterType {
138 Continuous,
139 Discrete,
140 Integer,
141 Boolean,
142 Categorical(Vec<String>),
143}
144
145#[derive(Debug)]
147pub enum BanditAlgorithm<F: Float> {
148 EpsilonGreedy { epsilon: f64 },
150 UCB { confidence_level: f64 },
152 ThompsonSampling,
154 Exp3 { learning_rate: F },
156}
157
158#[derive(Debug, Clone)]
160pub struct RegretTracker<F: Float + std::fmt::Debug> {
161 cumulative_regret: F,
163 regret_history: Vec<F>,
165 best_reward: F,
167 total_rounds: usize,
169}
170
171impl<F: Float + std::fmt::Debug> Default for RegretTracker<F> {
172 fn default() -> Self {
173 Self {
174 cumulative_regret: F::zero(),
175 regret_history: Vec::new(),
176 best_reward: F::zero(),
177 total_rounds: 0,
178 }
179 }
180}
181
182impl<F: Float + std::fmt::Debug> RegretTracker<F> {
183 pub fn update(&mut self, reward: F, optimal_reward: F) {
184 let regret = optimal_reward - reward;
185 self.cumulative_regret = self.cumulative_regret + regret;
186 self.regret_history.push(regret);
187 self.best_reward = F::max(self.best_reward, optimal_reward);
188 self.total_rounds += 1;
189 }
190
191 pub fn get_average_regret(&self) -> F {
192 if self.total_rounds > 0 {
193 self.cumulative_regret / F::from(self.total_rounds).expect("Failed to convert to float")
194 } else {
195 F::zero()
196 }
197 }
198}
199
200impl<F: Float + std::fmt::Debug + std::ops::AddAssign + std::iter::Sum> MultiArmedBandit<F> {
201 pub fn new(actions: Vec<ParameterConfiguration<F>>, algorithm: BanditAlgorithm<F>) -> Self {
202 let num_actions = actions.len();
203 Self {
204 actions,
205 algorithm,
206 rewards: vec![Vec::new(); num_actions],
207 counts: vec![0; num_actions],
208 exploration_rate: 0.1,
209 regret_tracker: RegretTracker::default(),
210 }
211 }
212
213 pub fn select_action(&mut self) -> Result<usize> {
214 match &self.algorithm {
215 BanditAlgorithm::EpsilonGreedy { epsilon } => {
216 let mut rng = scirs2_core::random::thread_rng();
217 if rng.random::<f64>() < *epsilon {
218 Ok(rng.random_range(0..self.actions.len()))
220 } else {
221 self.get_best_action()
223 }
224 }
225 BanditAlgorithm::UCB { confidence_level } => self.get_ucb_action(*confidence_level),
226 _ => {
227 self.get_best_action()
229 }
230 }
231 }
232
233 fn get_best_action(&self) -> Result<usize> {
234 let mut best_action = 0;
235 let mut best_average = F::neg_infinity();
236
237 for (i, rewards) in self.rewards.iter().enumerate() {
238 if !rewards.is_empty() {
239 let average = rewards.iter().cloned().sum::<F>()
240 / F::from(rewards.len()).expect("Operation failed");
241 if average > best_average {
242 best_average = average;
243 best_action = i;
244 }
245 }
246 }
247
248 Ok(best_action)
249 }
250
251 fn get_ucb_action(&self, confidence_level: f64) -> Result<usize> {
252 let total_counts: usize = self.counts.iter().sum();
253 let mut best_action = 0;
254 let mut best_ucb = F::neg_infinity();
255
256 for (i, rewards) in self.rewards.iter().enumerate() {
257 let ucb = if rewards.is_empty() {
258 F::infinity() } else {
260 let average = rewards.iter().cloned().sum::<F>()
261 / F::from(rewards.len()).expect("Operation failed");
262 let confidence_bonus =
263 F::from(confidence_level * (total_counts as f64 / self.counts[i] as f64).ln())
264 .expect("Operation failed")
265 .sqrt();
266 average + confidence_bonus
267 };
268
269 if ucb > best_ucb {
270 best_ucb = ucb;
271 best_action = i;
272 }
273 }
274
275 Ok(best_action)
276 }
277
278 pub fn update_reward(&mut self, action: usize, reward: F) -> Result<()> {
279 if action >= self.actions.len() {
280 return Err(crate::error::MetricsError::InvalidInput(
281 "Invalid action index".to_string(),
282 ));
283 }
284
285 self.rewards[action].push(reward);
286 self.counts[action] += 1;
287
288 let optimal_reward = self
290 .rewards
291 .iter()
292 .filter_map(|r| {
293 if r.is_empty() {
294 None
295 } else {
296 Some(r.iter().cloned().sum::<F>() / F::from(r.len()).expect("Operation failed"))
297 }
298 })
299 .fold(F::neg_infinity(), F::max);
300
301 self.regret_tracker.update(reward, optimal_reward);
302
303 Ok(())
304 }
305
306 pub fn get_action_statistics(&self) -> Vec<(usize, F, F)> {
307 self.rewards
308 .iter()
309 .enumerate()
310 .map(|(i, rewards)| {
311 if rewards.is_empty() {
312 (0, F::zero(), F::zero())
313 } else {
314 let count = rewards.len();
315 let mean = rewards.iter().cloned().sum::<F>()
316 / F::from(count).expect("Failed to convert to float");
317 let variance = rewards.iter().map(|&x| (x - mean) * (x - mean)).sum::<F>()
318 / F::from(count.max(1)).expect("Operation failed");
319 (count, mean, variance)
320 }
321 })
322 .collect()
323 }
324}
325
326#[derive(Debug)]
328pub struct NeuralFeatureExtractor<F: Float + std::fmt::Debug> {
329 input_dim: usize,
331 output_dim: usize,
333 autoencoder: AutoencoderNetwork<F>,
335 feature_selector: FeatureSelectionNetwork<F>,
337 attention: AttentionMechanism<F>,
339}
340
341#[derive(Debug, Clone)]
343pub struct AutoencoderNetwork<F: Float + std::fmt::Debug> {
344 encoder_layers: Vec<usize>,
346 decoder_layers: Vec<usize>,
348 encoding_dim: usize,
350 weights: Vec<Array2<F>>,
352}
353
354#[derive(Debug, Clone)]
356pub struct FeatureSelectionNetwork<F: Float + std::fmt::Debug> {
357 threshold: F,
359 importance_scores: Array1<F>,
361 selected_features: Vec<usize>,
363}
364
365#[derive(Debug, Clone)]
367pub struct AttentionMechanism<F: Float + std::fmt::Debug> {
368 attention_type: AttentionType,
370 attention_weights: Array1<F>,
372 key_dim: usize,
374 value_dim: usize,
376}
377
378#[derive(Debug, Clone)]
380pub enum AttentionType {
381 SelfAttention,
382 MultiHead { num_heads: usize },
383 CrossAttention,
384}
385
386#[derive(Debug)]
388pub struct AdaptiveLearningScheduler<F: Float + std::fmt::Debug> {
389 initial_lr: F,
391 current_lr: F,
393 scheduler_type: SchedulerType<F>,
395 performance_history: Vec<F>,
397 adaptation_params: SchedulerAdaptationParams<F>,
399}
400
401impl<F: Float + std::fmt::Debug> AdaptiveLearningScheduler<F> {
402 pub fn new(initial_lr: F, scheduler_type: SchedulerType<F>) -> Self {
403 Self {
404 initial_lr,
405 current_lr: initial_lr,
406 scheduler_type,
407 performance_history: Vec::new(),
408 adaptation_params: SchedulerAdaptationParams::default(),
409 }
410 }
411
412 pub fn update(&mut self, performance: F) -> F {
413 self.performance_history.push(performance);
414
415 if self.performance_history.len() > 100 {
417 self.performance_history.remove(0);
418 }
419
420 match &self.scheduler_type {
421 SchedulerType::StepLR { step_size, gamma } => {
422 if self.performance_history.len().is_multiple_of(*step_size) {
423 self.current_lr = self.current_lr * *gamma;
424 }
425 }
426 SchedulerType::ReduceLROnPlateau {
427 factor, patience, ..
428 } => {
429 if self.performance_history.len() > *patience {
430 let recent_performance =
431 &self.performance_history[self.performance_history.len() - patience..];
432 let is_plateau = recent_performance.windows(2).all(|w| {
433 (w[1] - w[0]).abs()
434 < F::from(0.001).expect("Failed to convert constant to float")
435 });
436 if is_plateau {
437 self.current_lr = self.current_lr * *factor;
438 }
439 }
440 }
441 _ => {}
442 }
443
444 self.current_lr
445 }
446
447 pub fn get_learning_rate(&self) -> F {
448 self.current_lr
449 }
450
451 pub fn reset(&mut self) {
452 self.current_lr = self.initial_lr;
453 self.performance_history.clear();
454 }
455}
456
457#[derive(Debug, Clone)]
459pub enum SchedulerType<F: Float> {
460 Constant,
462 StepLR { step_size: usize, gamma: F },
464 ExponentialLR { gamma: F },
466 ReduceLROnPlateau {
468 factor: F,
469 patience: usize,
470 threshold: F,
471 },
472 CosineAnnealingLR { t_max: usize },
474}
475
476#[derive(Debug, Clone)]
478pub struct SchedulerAdaptationParams<F: Float + std::fmt::Debug> {
479 pub min_lr: F,
481 pub max_lr: F,
483 pub sensitivity: F,
485}
486
487impl<F: Float + std::fmt::Debug> Default for SchedulerAdaptationParams<F> {
488 fn default() -> Self {
489 Self {
490 min_lr: F::from(1e-6).expect("Failed to convert constant to float"),
491 max_lr: F::from(1e-1).expect("Failed to convert constant to float"),
492 sensitivity: F::from(0.1).expect("Failed to convert constant to float"),
493 }
494 }
495}
496
497impl<F: Float + std::fmt::Debug + Send + Sync + scirs2_core::ndarray::ScalarOperand>
499 AutoencoderNetwork<F>
500{
501 pub fn new(input_dim: usize, encoding_dim: usize) -> Self {
502 Self {
503 encoder_layers: vec![input_dim, encoding_dim * 2, encoding_dim],
504 decoder_layers: vec![encoding_dim, encoding_dim * 2, input_dim],
505 encoding_dim,
506 weights: Vec::new(), }
508 }
509
510 pub fn encode(&self, _input: &Array1<F>) -> Result<Array1<F>> {
511 Ok(Array1::zeros(self.encoding_dim))
513 }
514}
515
516impl<F: Float + std::fmt::Debug> AttentionMechanism<F> {
517 pub fn new(key_dim: usize, value_dim: usize, attention_type: AttentionType) -> Self {
518 Self {
519 attention_type,
520 attention_weights: Array1::zeros(key_dim),
521 key_dim,
522 value_dim,
523 }
524 }
525}
526
527impl<F: Float + std::fmt::Debug + Send + Sync + scirs2_core::ndarray::ScalarOperand>
528 FeatureSelectionNetwork<F>
529{
530 pub fn new(num_features: usize, threshold: F) -> Self {
531 Self {
532 threshold,
533 importance_scores: Array1::zeros(num_features),
534 selected_features: Vec::new(),
535 }
536 }
537
538 pub fn select_features(&mut self, scores: &Array1<F>) -> Vec<usize> {
539 self.importance_scores = scores.clone();
540 self.selected_features = scores
541 .iter()
542 .enumerate()
543 .filter(|(_, &score)| score > self.threshold)
544 .map(|(i, _)| i)
545 .collect();
546 self.selected_features.clone()
547 }
548}
549
550impl<F: Float + std::fmt::Debug + Send + Sync + scirs2_core::ndarray::ScalarOperand>
551 NeuralFeatureExtractor<F>
552{
553 pub fn new(input_dim: usize, output_dim: usize) -> Self {
554 Self {
555 input_dim,
556 output_dim,
557 autoencoder: AutoencoderNetwork::new(input_dim, output_dim),
558 feature_selector: FeatureSelectionNetwork::new(
559 input_dim,
560 F::from(0.1).expect("Failed to convert constant to float"),
561 ),
562 attention: AttentionMechanism::new(input_dim, output_dim, AttentionType::SelfAttention),
563 }
564 }
565
566 pub fn extract_features(&self, input: &Array1<F>) -> Result<Array1<F>> {
567 self.autoencoder.encode(input)
569 }
570}