fix(weights): normalize challenge weights when sum exceeds 1.0#34
fix(weights): normalize challenge weights when sum exceeds 1.0#34
Conversation
Add proportional normalization for challenge weights to prevent any single challenge from exceeding its allocated weight share. When a challenge returns weights that sum to more than 1.0, each weight is scaled down proportionally to sum exactly to 1.0. - Add normalize_hotkey_weights() function - Integrate normalization in collect_challenge_weights() - Add comprehensive unit tests for edge cases
📝 WalkthroughWalkthroughA new internal weight normalization function Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@crates/bittensor-integration/src/challenge_weight_collector.rs`:
- Around line 87-115: normalize_hotkey_weights currently sums raw weights and
can be skewed by NaN/∞ or negative values; first sanitize the input in
normalize_hotkey_weights by filtering out entries whose weight is not finite
(w.weight.is_finite()) and for finite weights clamp them into a valid range
(e.g., let w = w.weight.clamp(0.0, 1.0)); compute the sum from this sanitized
Vec<HotkeyWeightEntry>, then proceed with the existing logic (if sum>1.0 scale
each sanitized entry by 1.0/sum, otherwise return the sanitized/clamped entries
unchanged) so downstream allocations cannot be distorted by non‑finite or
out‑of‑range weights.
| /// Normalize hotkey weights proportionally if their sum exceeds 1.0 | ||
| /// | ||
| /// When a challenge returns weights that sum to more than 1.0, each weight | ||
| /// is scaled down proportionally so the total equals 1.0. This ensures | ||
| /// no challenge can exceed its allocated weight share. | ||
| /// | ||
| /// - If sum > 1.0: all weights are scaled by (1.0 / sum) | ||
| /// - If sum <= 1.0: weights are returned unchanged | ||
| fn normalize_hotkey_weights(weights: Vec<HotkeyWeightEntry>) -> Vec<HotkeyWeightEntry> { | ||
| if weights.is_empty() { | ||
| return weights; | ||
| } | ||
|
|
||
| let sum: f64 = weights.iter().map(|w| w.weight).sum(); | ||
|
|
||
| // Only normalize if sum exceeds 1.0 | ||
| if sum > 1.0 { | ||
| tracing::info!( | ||
| "Normalizing {} weights: sum={:.4} -> 1.0 (scaling by {:.4})", | ||
| weights.len(), | ||
| sum, | ||
| 1.0 / sum | ||
| ); | ||
| weights | ||
| .into_iter() | ||
| .map(|w| HotkeyWeightEntry { | ||
| hotkey: w.hotkey, | ||
| weight: w.weight / sum, | ||
| }) |
There was a problem hiding this comment.
Sanitize non‑finite/out‑of‑range weights before summing.
Line 100 sums raw weights; NaN/∞ or negative values can bypass normalization and silently distort downstream allocations. Clamp and drop non‑finite values before computing sum.
Proposed fix
-fn normalize_hotkey_weights(weights: Vec<HotkeyWeightEntry>) -> Vec<HotkeyWeightEntry> {
+fn normalize_hotkey_weights(mut weights: Vec<HotkeyWeightEntry>) -> Vec<HotkeyWeightEntry> {
if weights.is_empty() {
return weights;
}
+ for w in &mut weights {
+ if !w.weight.is_finite() {
+ warn!(
+ "Non-finite weight for hotkey {}, defaulting to 0.0",
+ w.hotkey
+ );
+ w.weight = 0.0;
+ }
+ w.weight = w.weight.clamp(0.0, 1.0);
+ }
+
let sum: f64 = weights.iter().map(|w| w.weight).sum();🤖 Prompt for AI Agents
In `@crates/bittensor-integration/src/challenge_weight_collector.rs` around lines
87 - 115, normalize_hotkey_weights currently sums raw weights and can be skewed
by NaN/∞ or negative values; first sanitize the input in
normalize_hotkey_weights by filtering out entries whose weight is not finite
(w.weight.is_finite()) and for finite weights clamp them into a valid range
(e.g., let w = w.weight.clamp(0.0, 1.0)); compute the sum from this sanitized
Vec<HotkeyWeightEntry>, then proceed with the existing logic (if sum>1.0 scale
each sanitized entry by 1.0/sum, otherwise return the sanitized/clamped entries
unchanged) so downstream allocations cannot be distorted by non‑finite or
out‑of‑range weights.
Summary
This PR adds proportional weight normalization for challenge weights to prevent any single challenge from exceeding its allocated weight share (1.0 maximum).
Changes
normalize_hotkey_weights()scales weights proportionally when their sum exceeds 1.0collect_challenge_weights()before converting hotkeys to UIDsBehavior
1.0 / sumTesting
Summary by CodeRabbit
Bug Fixes
Tests