fix(clippy): resolve misc warnings across ML crates
- Implement Display trait instead of inherent to_string() (versioning.rs)
- Replace iter().nth() with .get(), .get(0) with .first()
- Collapse else-if chains, derive Default for enums
- Fix deref warnings, redundant let bindings, push_str('\n')
- Convert match-to-if-let, use saturating_sub, RangeInclusive::contains
- Replace vec![push;push] with vec![...] literal (feature_extraction.rs)
- Remove redundant redefinitions, unnecessary parentheses, casts
- Fix &Vec<_> to &[_] in function parameters
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -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<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
|
||||
@@ -982,7 +982,7 @@ impl DQNAgent {
|
||||
// Epsilon-greedy selection
|
||||
let mut rng = rand::thread_rng();
|
||||
let action_idx = if rng.gen::<f32>() < 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))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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());
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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::*;
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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<Decimal, MLError> {
|
||||
// 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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -95,10 +95,9 @@ pub fn compute_ofi_from_file(file_path: &Path) -> Result<Vec<[f64; 8]>, 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)))?;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -38,7 +38,7 @@ pub fn sigmoid(x: FixedPoint) -> Result<FixedPoint> {
|
||||
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<FixedPoint> {
|
||||
|
||||
// 0.5 * x * (1 + tanh(...))
|
||||
|
||||
((half * x)? * one_plus_tanh)
|
||||
(half * x)? * one_plus_tanh
|
||||
}
|
||||
|
||||
/// Linear activation (identity function)
|
||||
|
||||
@@ -1598,7 +1598,6 @@ impl Mamba2SSM {
|
||||
/// Forward pass with gradient computation enabled
|
||||
pub fn forward_with_gradients(&mut self, input: &Tensor) -> Result<Tensor, MLError> {
|
||||
// Gradient flow enabled - do not detach
|
||||
let input = input;
|
||||
|
||||
// Input projection with gradients
|
||||
let mut hidden = self.input_projection.forward(input)?;
|
||||
|
||||
@@ -708,7 +708,7 @@ impl TGGN {
|
||||
/// Restore message passing weights from checkpoint state
|
||||
pub const fn restore_message_passing_weights(
|
||||
&mut self,
|
||||
_weights: &Vec<Vec<f32>>,
|
||||
_weights: &[Vec<f32>],
|
||||
) -> Result<(), MLError> {
|
||||
// Production implementation for now - message passing weights would be restored here
|
||||
Ok(())
|
||||
|
||||
Reference in New Issue
Block a user