diff --git a/pallets/subtensor/src/epoch/math.rs b/pallets/subtensor/src/epoch/math.rs index 6a53c9767b..b110e9b74d 100644 --- a/pallets/subtensor/src/epoch/math.rs +++ b/pallets/subtensor/src/epoch/math.rs @@ -1505,7 +1505,9 @@ pub fn mat_ema_alpha_sparse( // Add alpha_j * new_ij, clamp to [0, 1], and emit sparse entries > 0. let mut out_row: Vec<(u16, I32F32)> = Vec::new(); + let mut new_cols = std::collections::BTreeSet::new(); for &(j, new_val) in new_row.iter() { + new_cols.insert(j); if let (Some(&a), Some(&decayed)) = (alpha_row.get(j as usize), decayed_values.get(j as usize)) { @@ -1517,6 +1519,15 @@ pub fn mat_ema_alpha_sparse( } } + // Emit decayed old entries for columns absent from new_row. + // This ensures old bonds decay gradually rather than dropping to zero instantly. + for (j, &decayed) in decayed_values.iter().enumerate() { + if !new_cols.contains(&(j as u16)) && decayed > zero { + out_row.push((j as u16, decayed)); + } + } + out_row.sort_unstable_by_key(|&(j, _)| j); + result.push(out_row); } diff --git a/pallets/subtensor/src/tests/math.rs b/pallets/subtensor/src/tests/math.rs index 6591d975b0..a844091e28 100644 --- a/pallets/subtensor/src/tests/math.rs +++ b/pallets/subtensor/src/tests/math.rs @@ -2107,15 +2107,18 @@ fn test_math_sparse_mat_ema_alpha() { let alphas = vec_to_mat_fixed(&[0.1; 12], 4, false); let result = mat_ema_alpha_sparse(&new, &old, &alphas); assert_sparse_mat_compare(&result, &target, I32F32::from_num(1e-4)); + // Old entry absent from new must decay via EMA rather than drop to zero instantly. + // With alpha=0.1: old[0][0]=1.0 absent from new => (1-0.1)*1.0 = 0.9 + // new[1][0]=2.0 absent from old => 0.1*2.0 = 0.2 let old: Vec = vec![1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; let new: Vec = vec![0., 0., 0., 0., 2., 0., 0., 0., 0., 0., 0., 0.]; - let target: Vec = vec![0.0, 0., 0., 0., 0.2, 0., 0., 0., 0., 0., 0., 0.]; + let target: Vec = vec![0.9, 0., 0., 0., 0.2, 0., 0., 0., 0., 0., 0., 0.]; let old = vec_to_sparse_mat_fixed(&old, 4, false); let new = vec_to_sparse_mat_fixed(&new, 4, false); let target = vec_to_sparse_mat_fixed(&target, 4, false); let alphas = vec_to_mat_fixed(&[0.1; 12], 4, false); let result = mat_ema_alpha_sparse(&new, &old, &alphas); - assert_sparse_mat_compare(&result, &target, I32F32::from_num(1e-1)); + assert_sparse_mat_compare(&result, &target, I32F32::from_num(1e-4)); } #[test]