Skip to content

fix(epoch): emit decayed old bond entries absent from new in mat_ema_alpha_sparse#2584

Open
hconsulting987654321-blip wants to merge 1 commit intoopentensor:mainfrom
hconsulting987654321-blip:fix/sparse-ema-old-entries-dropped
Open

fix(epoch): emit decayed old bond entries absent from new in mat_ema_alpha_sparse#2584
hconsulting987654321-blip wants to merge 1 commit intoopentensor:mainfrom
hconsulting987654321-blip:fix/sparse-ema-old-entries-dropped

Conversation

@hconsulting987654321-blip
Copy link
Copy Markdown

Summary

  • mat_ema_alpha_sparse only emitted sparse output entries present in the new matrix. Old bond entries absent from new_row had their decayed values computed ((1 - alpha) * old_val) but never emitted, causing bonds to drop to zero instantly instead of decaying gradually.
  • This diverges from the dense equivalent mat_ema_alpha and breaks the bond decay semantics: when a validator removes weight to a miner, the bond should decay by (1 - alpha) per epoch, not zero immediately.
  • Fix: after the new_row loop, iterate decayed_values for columns not in new_row and emit non-zero entries. Output is sorted by column index to maintain the sparse row invariant.
  • Updated test_math_sparse_mat_ema_alpha to assert the correct value (0.9 instead of 0.0 for alpha=0.1, old=1.0, new=0.0).

Root cause

// Before: only iterates new_row, missing old-only entries
for &(j, new_val) in new_row.iter() {
    // emit alpha*new + (1-alpha)*old for columns in new
}
// old-only columns → decayed_values computed but never pushed to out_row

Fix

// After: also emit decayed old entries for columns absent from new_row
let mut new_cols = std::collections::BTreeSet::new();
for &(j, new_val) in new_row.iter() {
    new_cols.insert(j);
    // ... existing logic ...
}
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);

Test plan

  • cargo test -p pallet-subtensor -- mat_ema — all 15 tests pass
  • test_math_sparse_mat_ema_alpha now correctly validates old-only-entry decay
  • All existing sparse EMA tests (test_mat_ema_alpha_sparse_*) continue to pass

🤖 Generated with Claude Code

…alpha_sparse

The sparse EMA function `mat_ema_alpha_sparse` previously only emitted
output entries present in the `new` matrix. Old bond entries that
existed in `old_row` but were absent from `new_row` had their decayed
values computed into `decayed_values` but never emitted, causing bonds
to drop to zero instantly rather than decaying gradually via EMA.

This diverged from the dense equivalent `mat_ema_alpha` and broke the
intended bond decay behavior: when a validator removes their weight to a
miner, the bond should decay by factor `(1 - alpha)` per epoch rather
than being zeroed immediately.

Fix: after processing new_row entries, iterate over decayed_values for
columns absent from new_row and emit any non-zero decayed value. Output
is sorted by column index to maintain the sparse row invariant.

Also fix the corresponding test that was asserting the buggy behavior
(expected `0.0` corrected to `0.9` for `alpha=0.1`, `old=1.0`).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant