diff --git a/crates/ml-checkpoint/src/versioning.rs b/crates/ml-checkpoint/src/versioning.rs index 5b393b84b..44af30ac1 100644 --- a/crates/ml-checkpoint/src/versioning.rs +++ b/crates/ml-checkpoint/src/versioning.rs @@ -81,23 +81,6 @@ impl SemanticVersion { }) } - /// Convert to string representation - pub fn to_string(&self) -> String { - let mut version = format!("{}.{}.{}", self.major, self.minor, self.patch); - - if let Some(ref pre_release) = self.pre_release { - version.push('-'); - version.push_str(pre_release); - } - - if let Some(ref build_metadata) = self.build_metadata { - version.push('+'); - version.push_str(build_metadata); - } - - version - } - /// Check if this version is compatible with another version pub const fn is_compatible_with(&self, other: &SemanticVersion) -> bool { // Major version must match for compatibility @@ -129,6 +112,19 @@ impl SemanticVersion { } } +impl std::fmt::Display for SemanticVersion { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}.{}.{}", self.major, self.minor, self.patch)?; + if let Some(ref pre_release) = self.pre_release { + write!(f, "-{pre_release}")?; + } + if let Some(ref build_metadata) = self.build_metadata { + write!(f, "+{build_metadata}")?; + } + Ok(()) + } +} + impl PartialOrd for SemanticVersion { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) diff --git a/crates/ml-dqn/src/agent.rs b/crates/ml-dqn/src/agent.rs index 028712bd7..7f2f3a230 100644 --- a/crates/ml-dqn/src/agent.rs +++ b/crates/ml-dqn/src/agent.rs @@ -982,7 +982,7 @@ impl DQNAgent { // Epsilon-greedy selection let mut rng = rand::thread_rng(); let action_idx = if rng.gen::() < epsilon { - valid_actions.iter().nth(rng.gen_range(0..valid_actions.len())).copied().unwrap_or(0) + valid_actions.get(rng.gen_range(0..valid_actions.len())).copied().unwrap_or(0) } else { valid_actions.iter() .max_by(|&&a, &&b| q_vec[a].partial_cmp(&q_vec[b]).unwrap_or(std::cmp::Ordering::Equal)) diff --git a/crates/ml-dqn/src/branching.rs b/crates/ml-dqn/src/branching.rs index 01e8a80ec..d894efd3a 100644 --- a/crates/ml-dqn/src/branching.rs +++ b/crates/ml-dqn/src/branching.rs @@ -700,7 +700,7 @@ impl BranchingDuelingQNetwork { // Q(s, a) = V(s) + (1/D) x sum centered advantages let inv_d = 1.0_f32 / d as f32; - let scale = Tensor::new(inv_d, &output.value.device()) + let scale = Tensor::new(inv_d, output.value.device()) .map_err(|e| MLError::ModelError(format!("Scale tensor: {}", e)))?; let scaled = centered_sum .broadcast_mul(&scale) @@ -742,7 +742,7 @@ impl BranchingDuelingQNetwork { } let inv_d = 1.0_f32 / d as f32; - let scale = Tensor::new(inv_d, &output.value.device()) + let scale = Tensor::new(inv_d, output.value.device()) .map_err(|e| MLError::ModelError(format!("Scale tensor: {}", e)))?; let scaled = centered_sum .broadcast_mul(&scale) diff --git a/crates/ml-dqn/src/distributional.rs b/crates/ml-dqn/src/distributional.rs index b3a55803f..bbc8cc92e 100644 --- a/crates/ml-dqn/src/distributional.rs +++ b/crates/ml-dqn/src/distributional.rs @@ -168,7 +168,7 @@ impl CategoricalDistribution { // atom_idx = (clipped_val - v_min) / delta_z // Shape: [batch, num_atoms] let v_min_broadcast = Tensor::full(self.config.v_min as f32, clipped_target.shape(), device)?; - let delta_z_tensor = Tensor::full(self.delta_z as f32, clipped_target.shape(), device)?; + let delta_z_tensor = Tensor::full(self.delta_z, clipped_target.shape(), device)?; let atom_indices = ((clipped_target - v_min_broadcast)? / delta_z_tensor)?; // Step 3: Compute lower and upper atom indices diff --git a/crates/ml-dqn/src/dqn.rs b/crates/ml-dqn/src/dqn.rs index 12fc4e467..0e5fc8e30 100644 --- a/crates/ml-dqn/src/dqn.rs +++ b/crates/ml-dqn/src/dqn.rs @@ -856,6 +856,11 @@ impl ExperienceReplayBuffer { self.buffer.len() } + /// Check if buffer is empty + pub fn is_empty(&self) -> bool { + self.buffer.is_empty() + } + /// Check if buffer can sample pub fn can_sample(&self, min_size: usize) -> bool { self.buffer.len() >= min_size @@ -947,7 +952,7 @@ impl Sequential { noisy_layers.push(noisy_output); } else { // Standard Linear layers with Xavier initialization - for (i, &hidden_dim) in hidden_dims.into_iter().enumerate() { + for (i, &hidden_dim) in hidden_dims.iter().enumerate() { let layer_name = format!("hidden_{}", i); let layer_vb = var_builder.pp(&layer_name); let layer = linear_xavier(current_dim, hidden_dim, layer_vb).map_err(|e| { @@ -1483,8 +1488,7 @@ impl DQN { .broadcast_as((batch_size, num_actions, num_atoms))?; // Compute expected Q-values: Q(s,a) = Σ(z_i * p_i) - let q_values_dist = (z_probs * atoms_tensor)?.sum(2)?; // Sum over atoms - q_values_dist + (z_probs * atoms_tensor)?.sum(2)? // Sum over atoms } else if let Some(ref dueling_net) = self.dueling_q_network { // Wave 11.4: Priority 2 - Dueling only dueling_net.forward(&state)? @@ -1630,7 +1634,7 @@ impl DQN { let branch_actions = super::branching::BranchingDuelingQNetwork::greedy_branch_actions(&output)?; // branch_actions: [exposure_idx, order_idx, urgency_idx] - let exposure = ExposureLevel::from_index(branch_actions.get(0).copied().unwrap_or(2) as usize)?; + let exposure = ExposureLevel::from_index(branch_actions.first().copied().unwrap_or(2) as usize)?; let order = OrderType::from_index(branch_actions.get(1).copied().unwrap_or(0) as usize)?; let urgency = Urgency::from_index(branch_actions.get(2).copied().unwrap_or(1) as usize)?; FactoredAction { exposure, order, urgency } @@ -2810,9 +2814,9 @@ impl DQN { let next_state_embed = self.get_state_embedding(&next_states_tensor)?; // Sample random quantiles for training (IQN: τ ~ Uniform(0,1)) - let taus = iqn_net.sample_random_quantiles(batch_size, &device) + let taus = iqn_net.sample_random_quantiles(batch_size, device) .map_err(|e| MLError::TrainingError(format!("Failed to sample taus: {}", e)))?; - let target_taus = iqn_target.sample_random_quantiles(batch_size, &device) + let target_taus = iqn_target.sample_random_quantiles(batch_size, device) .map_err(|e| MLError::TrainingError(format!("Failed to sample target taus: {}", e)))?; // Forward through IQN: [batch, num_actions, num_quantiles] @@ -2857,11 +2861,11 @@ impl DQN { let rewards_broadcast = rewards_tensor .unsqueeze(1)? .broadcast_as((batch_size, num_quantiles))?; - let not_done_broadcast = (Tensor::ones(&[batch_size], dtype, &device)? - &dones_tensor)? + let not_done_broadcast = (Tensor::ones(&[batch_size], dtype, device)? - &dones_tensor)? .unsqueeze(1)? .broadcast_as((batch_size, num_quantiles))?; - let gamma_t = Tensor::full(gamma, &[batch_size, num_quantiles], &device) + let gamma_t = Tensor::full(gamma, &[batch_size, num_quantiles], device) .map_err(|e| MLError::TrainingError(format!("Failed to create gamma tensor: {}", e)))? .to_dtype(dtype) .map_err(|e| MLError::TrainingError(format!("Failed to cast gamma tensor: {}", e)))?; @@ -2887,8 +2891,7 @@ impl DQN { .map_err(|e| MLError::TrainingError(format!("Failed to cast weights tensor: {}", e)))? .detach() }; - let weighted_loss = (per_sample_loss * weights_tensor)?.mean_all()?; - weighted_loss + (per_sample_loss * weights_tensor)?.mean_all()? } else if self.dist_dueling_q_network.is_some() { // C51 CATEGORICAL LOSS PATH (Hybrid: Distributional + Dueling) @@ -3042,9 +3045,7 @@ impl DQN { .map_err(|e| MLError::TrainingError(format!("Failed to cast weights tensor: {}", e)))? .detach() }; - let weighted_loss = (per_sample_loss * weights_tensor)?.mean_all()?; - - weighted_loss + (per_sample_loss * weights_tensor)?.mean_all()? } else { // STANDARD DQN SCALAR LOSS PATH (MSE/Huber) @@ -3311,7 +3312,7 @@ impl DQN { let loss_clamped = result.loss_f32_tensor.clamp(0.0_f64, 1e6_f64)?; // Squeeze grad_norm from [1] → scalar for consistent accumulation - let grad_norm_scalar = if grad_norm_tensor.dims().len() > 0 { + let grad_norm_scalar = if !grad_norm_tensor.dims().is_empty() { grad_norm_tensor.squeeze(0)? } else { grad_norm_tensor @@ -3351,7 +3352,7 @@ impl DQN { // Squeeze grad_norm from [1] → rank-0 scalar tensor (GPU path only) #[cfg(feature = "cuda")] - let grad_norm_scalar_tensor = if _grad_norm_tensor.dims().len() > 0 { + let grad_norm_scalar_tensor = if !_grad_norm_tensor.dims().is_empty() { _grad_norm_tensor.squeeze(0)? } else { _grad_norm_tensor @@ -3893,7 +3894,7 @@ impl DQN { /// to eliminate triple-stacking (noisy + epsilon + count bonus). pub const fn get_effective_epsilon(&self) -> f32 { if self.config.use_noisy_nets { - self.config.noisy_epsilon_floor.max(0.02) as f32 // Match actual action selection logic + self.config.noisy_epsilon_floor.max(0.02) // Match actual action selection logic } else { self.epsilon } diff --git a/crates/ml-dqn/src/evaluation/metrics.rs b/crates/ml-dqn/src/evaluation/metrics.rs index 5543efe14..dc8bba181 100644 --- a/crates/ml-dqn/src/evaluation/metrics.rs +++ b/crates/ml-dqn/src/evaluation/metrics.rs @@ -202,9 +202,7 @@ fn calculate_sharpe_ratio(returns: &[f64]) -> f64 { } // Annualize: sqrt(252 trades/year) assuming daily trades - let sharpe = (mean_return / std_dev) * (252.0_f64).sqrt(); - - sharpe + (mean_return / std_dev) * (252.0_f64).sqrt() } /// Calculate Sortino ratio, focusing on downside deviation diff --git a/crates/ml-dqn/src/evaluation/report.rs b/crates/ml-dqn/src/evaluation/report.rs index 5f4da4ec9..0d1795b29 100644 --- a/crates/ml-dqn/src/evaluation/report.rs +++ b/crates/ml-dqn/src/evaluation/report.rs @@ -28,7 +28,7 @@ impl BacktestReport { if let Some(ref _baseline) = self.baseline_results { _ = writeln!(report, "**Baseline**: {}\n", self.baseline_name); } else { - report.push_str("\n"); + report.push('\n'); } // Results table @@ -104,7 +104,7 @@ impl BacktestReport { "", ); - report.push_str("\n"); + report.push('\n'); // Summary report.push_str("## Summary\n\n"); diff --git a/crates/ml-dqn/src/hindsight_replay.rs b/crates/ml-dqn/src/hindsight_replay.rs index b91f6bd18..7d8814d0e 100644 --- a/crates/ml-dqn/src/hindsight_replay.rs +++ b/crates/ml-dqn/src/hindsight_replay.rs @@ -171,8 +171,8 @@ impl HindsightReplayBuffer { // Shuffle while preserving correspondence let mut combined: Vec<_> = all_experiences.into_iter() - .zip(all_weights.into_iter()) - .zip(all_indices.into_iter()) + .zip(all_weights) + .zip(all_indices) .collect(); combined.shuffle(&mut thread_rng()); diff --git a/crates/ml-dqn/src/nstep_buffer.rs b/crates/ml-dqn/src/nstep_buffer.rs index 43e003dc5..86bd37723 100644 --- a/crates/ml-dqn/src/nstep_buffer.rs +++ b/crates/ml-dqn/src/nstep_buffer.rs @@ -68,7 +68,7 @@ impl NStepBuffer { /// /// Panics if n < 1 or n > 10 (sanity check) pub fn new(n: usize, gamma: f64) -> Self { - assert!(n >= 1 && n <= 10, "n must be in range 1-10 (got {})", n); + assert!((1..=10).contains(&n), "n must be in range 1-10 (got {})", n); assert!(gamma > 0.0 && gamma <= 1.0, "gamma must be in (0, 1] (got {})", gamma); Self { diff --git a/crates/ml-dqn/src/prioritized_replay.rs b/crates/ml-dqn/src/prioritized_replay.rs index e4d8b8f95..f8577222a 100644 --- a/crates/ml-dqn/src/prioritized_replay.rs +++ b/crates/ml-dqn/src/prioritized_replay.rs @@ -566,7 +566,7 @@ impl PrioritizedReplayBuffer { let mut max_priority = f32::from_bits(self.max_priority.load(Ordering::Acquire) as u32); let mut update_count = 0; - for (&idx, &priority) in indices.into_iter().zip(priorities.into_iter()) { + for (&idx, &priority) in indices.iter().zip(priorities.iter()) { if idx >= self.config.capacity { continue; } @@ -701,7 +701,7 @@ impl PrioritizedReplayBuffer { metrics.priority_percentiles[4] = sampled_priorities.get(safe_idx(9)).copied().unwrap_or(0.0); // 90th percentile - metrics.min_priority = sampled_priorities.get(0).copied().unwrap_or(0.0); + metrics.min_priority = sampled_priorities.first().copied().unwrap_or(0.0); metrics.max_priority = sampled_priorities.get(len - 1).copied().unwrap_or(0.0); } } diff --git a/crates/ml-dqn/src/rainbow_integration.rs b/crates/ml-dqn/src/rainbow_integration.rs index e1f08980b..17d6b6823 100644 --- a/crates/ml-dqn/src/rainbow_integration.rs +++ b/crates/ml-dqn/src/rainbow_integration.rs @@ -36,8 +36,8 @@ pub struct RainbowMetrics { pub exploration_rate: f64, } -impl RainbowMetrics { - pub const fn new() -> Self { +impl Default for RainbowMetrics { + fn default() -> Self { Self { total_steps: 0, total_episodes: 0, @@ -47,6 +47,12 @@ impl RainbowMetrics { } } +impl RainbowMetrics { + pub fn new() -> Self { + Self::default() + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/ml-dqn/src/rainbow_network.rs b/crates/ml-dqn/src/rainbow_network.rs index 36737bc34..8b6e371cf 100644 --- a/crates/ml-dqn/src/rainbow_network.rs +++ b/crates/ml-dqn/src/rainbow_network.rs @@ -14,8 +14,9 @@ use super::noisy_layers::NoisyLinear; use ml_core::MLError; /// Activation function types -#[derive(Debug, Clone, Copy, Serialize, Deserialize)] +#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize)] pub enum ActivationType { + #[default] ReLU, LeakyReLU, Swish, @@ -24,12 +25,6 @@ pub enum ActivationType { Mish, } -impl Default for ActivationType { - fn default() -> Self { - ActivationType::ReLU - } -} - /// Rainbow network configuration #[derive(Debug, Clone, Serialize, Deserialize)] pub struct RainbowNetworkConfig { @@ -215,29 +210,27 @@ impl RainbowNetwork { })?, ) } + } else if config.use_noisy_layers { + Box::new(NoisyLinear::new( + final_feature_size, + config.num_actions * num_atoms, + vs.pp("action_dist"), + config.noisy_sigma_init, + )?) } else { - if config.use_noisy_layers { - Box::new(NoisyLinear::new( + Box::new( + candle_nn::linear( final_feature_size, config.num_actions * num_atoms, vs.pp("action_dist"), - config.noisy_sigma_init, - )?) - } else { - Box::new( - candle_nn::linear( - final_feature_size, - config.num_actions * num_atoms, - vs.pp("action_dist"), - ) - .map_err(|e| { - MLError::ModelError(format!( - "Failed to create action distribution layer: {}", - e - )) - })?, ) - } + .map_err(|e| { + MLError::ModelError(format!( + "Failed to create action distribution layer: {}", + e + )) + })?, + ) }; let dropout = diff --git a/crates/ml-dqn/src/regime_conditional.rs b/crates/ml-dqn/src/regime_conditional.rs index 5a17b6d6f..57a85cc08 100644 --- a/crates/ml-dqn/src/regime_conditional.rs +++ b/crates/ml-dqn/src/regime_conditional.rs @@ -778,7 +778,7 @@ impl RegimeConditionalDQN { for var in vars { if let Some(src_grad) = source.get(var.as_tensor()) { if let Some(existing) = t.get(var.as_tensor()) { - let summed = existing.add(&src_grad).map_err(|e| { + let summed = existing.add(src_grad).map_err(|e| { MLError::TrainingError(format!("Gradient merge failed: {}", e)) })?; t.insert(var.as_tensor(), summed); @@ -865,7 +865,7 @@ impl RegimeConditionalDQN { for var in vars { if let Some(src_grad) = source.get(var.as_tensor()) { if let Some(existing) = t.get(var.as_tensor()) { - let summed = existing.add(&src_grad).map_err(|e| { + let summed = existing.add(src_grad).map_err(|e| { MLError::TrainingError(format!("Gradient merge failed: {}", e)) })?; t.insert(var.as_tensor(), summed); diff --git a/crates/ml-dqn/src/replay_buffer.rs b/crates/ml-dqn/src/replay_buffer.rs index 1e7974bdb..f866f7536 100644 --- a/crates/ml-dqn/src/replay_buffer.rs +++ b/crates/ml-dqn/src/replay_buffer.rs @@ -182,11 +182,7 @@ impl ReplayBuffer { // Transfer experiences (keep most recent if shrinking) let to_keep = current_size.min(new_capacity); - let start = if current_size > new_capacity { - current_size - new_capacity - } else { - 0 - }; + let start = current_size.saturating_sub(new_capacity); for i in 0..to_keep { new_buffer[i] = buffer[(start + i) % self.config.capacity].clone(); diff --git a/crates/ml-dqn/src/reward.rs b/crates/ml-dqn/src/reward.rs index b684621f8..dde2392ba 100644 --- a/crates/ml-dqn/src/reward.rs +++ b/crates/ml-dqn/src/reward.rs @@ -686,9 +686,9 @@ impl RewardFunction { } } else { // Legacy path: Sharpe blend + optional EMA normalization (unchanged) - let pnl_normalized_f64: f64 = ((next_state.portfolio_features.get(0).unwrap_or(&100000.0) - - current_state.portfolio_features.get(0).unwrap_or(&100000.0)) - / current_state.portfolio_features.get(0).unwrap_or(&100000.0)) as f64; + let pnl_normalized_f64: f64 = ((next_state.portfolio_features.first().unwrap_or(&100000.0) + - current_state.portfolio_features.first().unwrap_or(&100000.0)) + / current_state.portfolio_features.first().unwrap_or(&100000.0)) as f64; // Update returns buffer for Sharpe calculation self.returns_buffer.push_back(pnl_normalized_f64); @@ -812,21 +812,21 @@ impl RewardFunction { target_exposure: f64, ) -> Result { // Validate portfolio_features length (defensive check) - if current_state.portfolio_features.len() < 1 { + if current_state.portfolio_features.is_empty() { tracing::debug!( "Current state portfolio_features is empty, using 100000.0 for portfolio value" ); } - if next_state.portfolio_features.len() < 1 { + if next_state.portfolio_features.is_empty() { tracing::debug!("Next state portfolio_features is empty, using 100000.0 for portfolio value"); } let default_val = Decimal::try_from(100000.0).unwrap_or(Decimal::ONE_HUNDRED); let current_value = - Decimal::try_from(*current_state.portfolio_features.get(0).unwrap_or(&100000.0) as f64) + Decimal::try_from(*current_state.portfolio_features.first().unwrap_or(&100000.0) as f64) .unwrap_or(default_val); let next_value = - Decimal::try_from(*next_state.portfolio_features.get(0).unwrap_or(&100000.0) as f64) + Decimal::try_from(*next_state.portfolio_features.first().unwrap_or(&100000.0) as f64) .unwrap_or(default_val); // Bug #17 Fix: Use percentage-based P&L or absolute dollar change @@ -988,7 +988,7 @@ impl RewardFunction { // This assumes position is normalized (0-1 range) #[allow(unused_variables)] let _portfolio_value = - Decimal::try_from(*current_state.portfolio_features.get(0).unwrap_or(&100000.0) as f64) + Decimal::try_from(*current_state.portfolio_features.first().unwrap_or(&100000.0) as f64) .unwrap_or(Decimal::try_from(100000.0).unwrap_or(Decimal::ZERO)); // Apply urgency multiplier: Patient=0.5x, Normal=1.0x, Aggressive=1.5x diff --git a/crates/ml-features/src/feature_extraction.rs b/crates/ml-features/src/feature_extraction.rs index af3b34c19..4069df50a 100644 --- a/crates/ml-features/src/feature_extraction.rs +++ b/crates/ml-features/src/feature_extraction.rs @@ -87,34 +87,29 @@ impl FeatureExtractor { for i in 0..bars.len() { let bar = &bars[i]; - let mut feature_vec = Vec::with_capacity(15); - - // Features 1-5: OHLCV (normalized) - feature_vec.push(bar.open as f32); - feature_vec.push(bar.high as f32); - feature_vec.push(bar.low as f32); - feature_vec.push(bar.close as f32); - feature_vec.push(bar.volume as f32); - - // Feature 6: RSI - feature_vec.push(rsi_values.get(i).copied().unwrap_or(50.0) as f32); - - // Features 7-8: EMA - feature_vec.push(ema_fast.get(i).copied().unwrap_or(bar.close) as f32); - feature_vec.push(ema_slow.get(i).copied().unwrap_or(bar.close) as f32); - - // Features 9-11: MACD - feature_vec.push(macd_line.get(i).copied().unwrap_or(0.0) as f32); - feature_vec.push(macd_signal.get(i).copied().unwrap_or(0.0) as f32); - feature_vec.push(macd_hist.get(i).copied().unwrap_or(0.0) as f32); - - // Features 12-14: Bollinger Bands - feature_vec.push(bb_upper.get(i).copied().unwrap_or(bar.high) as f32); - feature_vec.push(bb_middle.get(i).copied().unwrap_or(bar.close) as f32); - feature_vec.push(bb_lower.get(i).copied().unwrap_or(bar.low) as f32); - - // Feature 15: ATR - feature_vec.push(atr.get(i).copied().unwrap_or(0.0) as f32); + let feature_vec = vec![ + // Features 1-5: OHLCV (normalized) + bar.open as f32, + bar.high as f32, + bar.low as f32, + bar.close as f32, + bar.volume as f32, + // Feature 6: RSI + rsi_values.get(i).copied().unwrap_or(50.0) as f32, + // Features 7-8: EMA + ema_fast.get(i).copied().unwrap_or(bar.close) as f32, + ema_slow.get(i).copied().unwrap_or(bar.close) as f32, + // Features 9-11: MACD + macd_line.get(i).copied().unwrap_or(0.0) as f32, + macd_signal.get(i).copied().unwrap_or(0.0) as f32, + macd_hist.get(i).copied().unwrap_or(0.0) as f32, + // Features 12-14: Bollinger Bands + bb_upper.get(i).copied().unwrap_or(bar.high) as f32, + bb_middle.get(i).copied().unwrap_or(bar.close) as f32, + bb_lower.get(i).copied().unwrap_or(bar.low) as f32, + // Feature 15: ATR + atr.get(i).copied().unwrap_or(0.0) as f32, + ]; features.push(feature_vec); } diff --git a/crates/ml-features/src/mbp10_loader.rs b/crates/ml-features/src/mbp10_loader.rs index bf1b5271a..08273ffc4 100644 --- a/crates/ml-features/src/mbp10_loader.rs +++ b/crates/ml-features/src/mbp10_loader.rs @@ -95,10 +95,9 @@ pub fn compute_ofi_from_file(file_path: &Path) -> Result, MLError> let snapshot_count = parser .parse_mbp10_streaming(file_path, 100, |snapshot| { - match calculator.calculate(snapshot) { - Ok(f) => features.push(f.to_array()), - Err(_) => {} // Skip failed calculations (e.g. first snapshot with no prev) - } + if let Ok(f) = calculator.calculate(snapshot) { + features.push(f.to_array()); + } // Skip failed calculations (e.g. first snapshot with no prev) }) .map_err(|e| MLError::InsufficientData(format!("MBP-10 streaming parse failed: {}", e)))?; @@ -168,10 +167,9 @@ pub fn compute_ofi_with_trades( trade_cursor += 1; } - match calculator.calculate(snapshot) { - Ok(f) => features.push(f.to_array()), - Err(_) => {} // Skip failed calculations (e.g. first snapshot) - } + if let Ok(f) = calculator.calculate(snapshot) { + features.push(f.to_array()); + } // Skip failed calculations (e.g. first snapshot) }) .map_err(|e| MLError::InsufficientData(format!("MBP-10 streaming parse failed: {}", e)))?; diff --git a/crates/ml-regime/src/transition_matrix.rs b/crates/ml-regime/src/transition_matrix.rs index 1a50ee7ca..4820abb82 100644 --- a/crates/ml-regime/src/transition_matrix.rs +++ b/crates/ml-regime/src/transition_matrix.rs @@ -173,7 +173,7 @@ impl RegimeTransitionMatrix { (1.0 - alpha) * self.transition_matrix[from_idx][j] + alpha; } else { // Other transitions: decrease probability - self.transition_matrix[from_idx][j] *= (1.0 - alpha); + self.transition_matrix[from_idx][j] *= 1.0 - alpha; } } diff --git a/crates/ml-stress-testing/src/lib.rs b/crates/ml-stress-testing/src/lib.rs index 41e4d5b74..d8f50a771 100644 --- a/crates/ml-stress-testing/src/lib.rs +++ b/crates/ml-stress-testing/src/lib.rs @@ -384,10 +384,10 @@ impl StressTestOrchestrator { config: self.config.clone(), total_duration, phase_results, - total_predictions: total_predictions, - total_errors: total_errors, + total_predictions, + total_errors, error_rate, - latency_stats: latency_stats, + latency_stats, requirements_met, throughput_achieved: total_predictions as f64 / total_duration.as_secs_f64(), recommendations, diff --git a/crates/ml-supervised/src/liquid/activation.rs b/crates/ml-supervised/src/liquid/activation.rs index ddd920f0b..1c01ac6a5 100644 --- a/crates/ml-supervised/src/liquid/activation.rs +++ b/crates/ml-supervised/src/liquid/activation.rs @@ -38,7 +38,7 @@ pub fn sigmoid(x: FixedPoint) -> Result { let fraction = (clamped_x / denominator)?; - ((half * fraction)? + half) + (half * fraction)? + half } /// Fast tanh approximation using fixed-point arithmetic @@ -112,7 +112,7 @@ pub fn gelu(x: FixedPoint) -> Result { // 0.5 * x * (1 + tanh(...)) - ((half * x)? * one_plus_tanh) + (half * x)? * one_plus_tanh } /// Linear activation (identity function) diff --git a/crates/ml-supervised/src/mamba/mod.rs b/crates/ml-supervised/src/mamba/mod.rs index 641fd46a9..607736619 100644 --- a/crates/ml-supervised/src/mamba/mod.rs +++ b/crates/ml-supervised/src/mamba/mod.rs @@ -1598,7 +1598,6 @@ impl Mamba2SSM { /// Forward pass with gradient computation enabled pub fn forward_with_gradients(&mut self, input: &Tensor) -> Result { // Gradient flow enabled - do not detach - let input = input; // Input projection with gradients let mut hidden = self.input_projection.forward(input)?; diff --git a/crates/ml-supervised/src/tgnn/mod.rs b/crates/ml-supervised/src/tgnn/mod.rs index d7a79bf17..2bba77bdd 100644 --- a/crates/ml-supervised/src/tgnn/mod.rs +++ b/crates/ml-supervised/src/tgnn/mod.rs @@ -708,7 +708,7 @@ impl TGGN { /// Restore message passing weights from checkpoint state pub const fn restore_message_passing_weights( &mut self, - _weights: &Vec>, + _weights: &[Vec], ) -> Result<(), MLError> { // Production implementation for now - message passing weights would be restored here Ok(())