From 08e5a5c87eb1f86bc5c4de98761539dee08826c7 Mon Sep 17 00:00:00 2001 From: Igor Date: Mon, 13 May 2024 15:58:54 +0200 Subject: [PATCH 1/4] Fix root subnetwork weights normalization --- pallets/subtensor/src/math.rs | 12 ++++++++++++ pallets/subtensor/src/root.rs | 6 +++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/pallets/subtensor/src/math.rs b/pallets/subtensor/src/math.rs index f51b33765..e431e6a81 100644 --- a/pallets/subtensor/src/math.rs +++ b/pallets/subtensor/src/math.rs @@ -260,6 +260,18 @@ pub fn inplace_normalize_64(x: &mut [I64F64]) { x.iter_mut().for_each(|value| *value /= x_sum); } +// Normalizes (sum to 1 except 0) each row (dim=0) of a I64F64 matrix in-place. +#[allow(dead_code)] +pub fn inplace_row_normalize_64(x: &mut [Vec]) { + for row in x { + let row_sum: I64F64 = row.iter().sum(); + if row_sum > I64F64::from_num(0.0_f64) { + row.iter_mut() + .for_each(|x_ij: &mut I64F64| *x_ij /= row_sum); + } + } +} + /// Returns x / y for input vectors x and y, if y == 0 return 0. #[allow(dead_code)] pub fn vecdiv(x: &[I32F32], y: &[I32F32]) -> Vec { diff --git a/pallets/subtensor/src/root.rs b/pallets/subtensor/src/root.rs index 224a5bcb3..241d62808 100644 --- a/pallets/subtensor/src/root.rs +++ b/pallets/subtensor/src/root.rs @@ -346,9 +346,13 @@ impl Pallet { // --- 8. Retrieves the network weights in a 2D Vector format. Weights have shape // n x k where is n is the number of registered peers and k is the number of subnets. - let weights: Vec> = Self::get_root_weights(); + let mut weights: Vec> = Self::get_root_weights(); log::debug!("W:\n{:?}\n", &weights); + // Normalize weights. + inplace_row_normalize_64(&mut weights); + log::debug!("W(norm):\n{:?}\n", &weights); + // --- 9. Calculates the rank of networks. Rank is a product of weights and stakes. // Ranks will have shape k, a score for each subnet. let ranks: Vec = matmul_64(&weights, &stake_i64); From 9cd8108ee8b6595d238d022fc6692836021755e6 Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Tue, 14 May 2024 13:01:35 +0400 Subject: [PATCH 2/4] chore: fix test_network_pruning --- pallets/subtensor/src/math.rs | 2 +- pallets/subtensor/src/root.rs | 14 +++++------ pallets/subtensor/tests/root.rs | 41 +++++++++++++++++++++++++-------- 3 files changed, 39 insertions(+), 18 deletions(-) diff --git a/pallets/subtensor/src/math.rs b/pallets/subtensor/src/math.rs index e431e6a81..e10cc0001 100644 --- a/pallets/subtensor/src/math.rs +++ b/pallets/subtensor/src/math.rs @@ -260,7 +260,7 @@ pub fn inplace_normalize_64(x: &mut [I64F64]) { x.iter_mut().for_each(|value| *value /= x_sum); } -// Normalizes (sum to 1 except 0) each row (dim=0) of a I64F64 matrix in-place. +/// Normalizes (sum to 1 except 0) each row (dim=0) of a I64F64 matrix in-place. #[allow(dead_code)] pub fn inplace_row_normalize_64(x: &mut [Vec]) { for row in x { diff --git a/pallets/subtensor/src/root.rs b/pallets/subtensor/src/root.rs index 241d62808..113e022f1 100644 --- a/pallets/subtensor/src/root.rs +++ b/pallets/subtensor/src/root.rs @@ -295,7 +295,7 @@ impl Pallet { // --- 0. The unique ID associated with the root network. let root_netuid: u16 = Self::get_root_netuid(); - // --- 3. Check if we should update the emission values based on blocks since emission was last set. + // --- 1. Check if we should update the emission values based on blocks since emission was last set. let blocks_until_next_epoch: u64 = Self::blocks_until_next_epoch(root_netuid, Self::get_tempo(root_netuid), block_number); if blocks_until_next_epoch != 0 { @@ -304,7 +304,7 @@ impl Pallet { return Err(""); } - // --- 1. Retrieves the number of root validators on subnets. + // --- 2. Retrieves the number of root validators on subnets. let n: u16 = Self::get_num_root_validators(); log::debug!("n:\n{:?}\n", n); if n == 0 { @@ -312,7 +312,7 @@ impl Pallet { return Err("No validators to validate emission values."); } - // --- 2. Obtains the number of registered subnets. + // --- 3. Obtains the number of registered subnets. let k: u16 = Self::get_all_subnet_netuids().len() as u16; log::debug!("k:\n{:?}\n", k); if k == 0 { @@ -344,7 +344,7 @@ impl Pallet { inplace_normalize_64(&mut stake_i64); log::debug!("S:\n{:?}\n", &stake_i64); - // --- 8. Retrieves the network weights in a 2D Vector format. Weights have shape + // --- 7. Retrieves the network weights in a 2D Vector format. Weights have shape // n x k where is n is the number of registered peers and k is the number of subnets. let mut weights: Vec> = Self::get_root_weights(); log::debug!("W:\n{:?}\n", &weights); @@ -353,12 +353,12 @@ impl Pallet { inplace_row_normalize_64(&mut weights); log::debug!("W(norm):\n{:?}\n", &weights); - // --- 9. Calculates the rank of networks. Rank is a product of weights and stakes. + // --- 8. Calculates the rank of networks. Rank is a product of weights and stakes. // Ranks will have shape k, a score for each subnet. let ranks: Vec = matmul_64(&weights, &stake_i64); log::debug!("R:\n{:?}\n", &ranks); - // --- 10. Calculates the trust of networks. Trust is a sum of all stake with weights > 0. + // --- 9. Calculates the trust of networks. Trust is a sum of all stake with weights > 0. // Trust will have shape k, a score for each subnet. let total_networks = Self::get_num_subnets(); let mut trust = vec![I64F64::from_num(0); total_networks as usize]; @@ -385,7 +385,7 @@ impl Pallet { } } - // --- 11. Calculates the consensus of networks. Consensus is a sigmoid normalization of the trust scores. + // --- 10. Calculates the consensus of networks. Consensus is a sigmoid normalization of the trust scores. // Consensus will have shape k, a score for each subnet. log::debug!("T:\n{:?}\n", &trust); let one = I64F64::from_num(1); diff --git a/pallets/subtensor/tests/root.rs b/pallets/subtensor/tests/root.rs index 02b045892..98aff1e60 100644 --- a/pallets/subtensor/tests/root.rs +++ b/pallets/subtensor/tests/root.rs @@ -594,21 +594,42 @@ fn test_network_pruning() { (i as u16) + 1 ); } + // Stakes + // 0 : 10_000 + // 1 : 9_000 + // 2 : 8_000 + // 3 : 7_000 + // 4 : 6_000 + // 5 : 5_000 + // 6 : 4_000 + // 7 : 3_000 + // 8 : 2_000 + // 9 : 1_000 + step_block(1); assert_ok!(SubtensorModule::root_epoch(1_000_000_000)); - assert_eq!(SubtensorModule::get_subnet_emission_value(0), 277_820_113); - assert_eq!(SubtensorModule::get_subnet_emission_value(1), 246_922_263); - assert_eq!(SubtensorModule::get_subnet_emission_value(2), 215_549_466); - assert_eq!(SubtensorModule::get_subnet_emission_value(3), 176_432_500); - assert_eq!(SubtensorModule::get_subnet_emission_value(4), 77_181_559); - assert_eq!(SubtensorModule::get_subnet_emission_value(5), 5_857_251); + // assert_eq!(SubtensorModule::get_subnet_emission_value(0), 277_820_113); + assert_eq!(SubtensorModule::get_subnet_emission_value(0), 385_861_815); + // assert_eq!(SubtensorModule::get_subnet_emission_value(1), 246_922_263); + assert_eq!(SubtensorModule::get_subnet_emission_value(1), 249_435_914); + // assert_eq!(SubtensorModule::get_subnet_emission_value(2), 215_549_466); + assert_eq!(SubtensorModule::get_subnet_emission_value(2), 180_819_837); + // assert_eq!(SubtensorModule::get_subnet_emission_value(3), 176_432_500); + assert_eq!(SubtensorModule::get_subnet_emission_value(3), 129_362_980); + // assert_eq!(SubtensorModule::get_subnet_emission_value(4), 77_181_559); + assert_eq!(SubtensorModule::get_subnet_emission_value(4), 50_857_187); + // assert_eq!(SubtensorModule::get_subnet_emission_value(5), 5_857_251); + assert_eq!(SubtensorModule::get_subnet_emission_value(5), 3_530_356); step_block(1); assert_eq!(SubtensorModule::get_pending_emission(0), 0); // root network gets no pending emission. - assert_eq!(SubtensorModule::get_pending_emission(1), 246_922_263); + // assert_eq!(SubtensorModule::get_pending_emission(1), 246_922_263); + assert_eq!(SubtensorModule::get_pending_emission(1), 249_435_914); assert_eq!(SubtensorModule::get_pending_emission(2), 0); // This has been drained. - assert_eq!(SubtensorModule::get_pending_emission(3), 176_432_500); + // assert_eq!(SubtensorModule::get_pending_emission(3), 176_432_500); + assert_eq!(SubtensorModule::get_pending_emission(3), 129_362_980); assert_eq!(SubtensorModule::get_pending_emission(4), 0); // This network has been drained. - assert_eq!(SubtensorModule::get_pending_emission(5), 5_857_251); + // assert_eq!(SubtensorModule::get_pending_emission(5), 5_857_251); + assert_eq!(SubtensorModule::get_pending_emission(5), 3_530_356); step_block(1); }); } @@ -766,7 +787,7 @@ fn test_weights_after_network_pruning() { /// Run this test using the following command: /// `cargo test --package pallet-subtensor --test root test_issance_bounds` #[test] -fn test_issance_bounds() { +fn test_issuance_bounds() { new_test_ext(1).execute_with(|| { // Simulate 100 halvings convergence to 21M. Note that the total issuance never reaches 21M because of rounding errors. // We converge to 20_999_999_989_500_000 (< 1 TAO away). From 17452ccd3769776c33b6cadc7ce67507497547f0 Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Tue, 14 May 2024 13:36:37 +0400 Subject: [PATCH 3/4] chore: fmt --- pallets/subtensor/tests/root.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pallets/subtensor/tests/root.rs b/pallets/subtensor/tests/root.rs index 98aff1e60..a225004ea 100644 --- a/pallets/subtensor/tests/root.rs +++ b/pallets/subtensor/tests/root.rs @@ -622,13 +622,13 @@ fn test_network_pruning() { assert_eq!(SubtensorModule::get_subnet_emission_value(5), 3_530_356); step_block(1); assert_eq!(SubtensorModule::get_pending_emission(0), 0); // root network gets no pending emission. - // assert_eq!(SubtensorModule::get_pending_emission(1), 246_922_263); + // assert_eq!(SubtensorModule::get_pending_emission(1), 246_922_263); assert_eq!(SubtensorModule::get_pending_emission(1), 249_435_914); assert_eq!(SubtensorModule::get_pending_emission(2), 0); // This has been drained. - // assert_eq!(SubtensorModule::get_pending_emission(3), 176_432_500); + // assert_eq!(SubtensorModule::get_pending_emission(3), 176_432_500); assert_eq!(SubtensorModule::get_pending_emission(3), 129_362_980); assert_eq!(SubtensorModule::get_pending_emission(4), 0); // This network has been drained. - // assert_eq!(SubtensorModule::get_pending_emission(5), 5_857_251); + // assert_eq!(SubtensorModule::get_pending_emission(5), 5_857_251); assert_eq!(SubtensorModule::get_pending_emission(5), 3_530_356); step_block(1); }); From 86c94b87ef388b89e9cabef7ad3d4a5e566b9d67 Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Thu, 16 May 2024 15:53:16 +0400 Subject: [PATCH 4/4] chore: clean up tests --- pallets/subtensor/tests/root.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/pallets/subtensor/tests/root.rs b/pallets/subtensor/tests/root.rs index a225004ea..c42756121 100644 --- a/pallets/subtensor/tests/root.rs +++ b/pallets/subtensor/tests/root.rs @@ -608,27 +608,18 @@ fn test_network_pruning() { step_block(1); assert_ok!(SubtensorModule::root_epoch(1_000_000_000)); - // assert_eq!(SubtensorModule::get_subnet_emission_value(0), 277_820_113); assert_eq!(SubtensorModule::get_subnet_emission_value(0), 385_861_815); - // assert_eq!(SubtensorModule::get_subnet_emission_value(1), 246_922_263); assert_eq!(SubtensorModule::get_subnet_emission_value(1), 249_435_914); - // assert_eq!(SubtensorModule::get_subnet_emission_value(2), 215_549_466); assert_eq!(SubtensorModule::get_subnet_emission_value(2), 180_819_837); - // assert_eq!(SubtensorModule::get_subnet_emission_value(3), 176_432_500); assert_eq!(SubtensorModule::get_subnet_emission_value(3), 129_362_980); - // assert_eq!(SubtensorModule::get_subnet_emission_value(4), 77_181_559); assert_eq!(SubtensorModule::get_subnet_emission_value(4), 50_857_187); - // assert_eq!(SubtensorModule::get_subnet_emission_value(5), 5_857_251); assert_eq!(SubtensorModule::get_subnet_emission_value(5), 3_530_356); step_block(1); assert_eq!(SubtensorModule::get_pending_emission(0), 0); // root network gets no pending emission. - // assert_eq!(SubtensorModule::get_pending_emission(1), 246_922_263); assert_eq!(SubtensorModule::get_pending_emission(1), 249_435_914); assert_eq!(SubtensorModule::get_pending_emission(2), 0); // This has been drained. - // assert_eq!(SubtensorModule::get_pending_emission(3), 176_432_500); assert_eq!(SubtensorModule::get_pending_emission(3), 129_362_980); assert_eq!(SubtensorModule::get_pending_emission(4), 0); // This network has been drained. - // assert_eq!(SubtensorModule::get_pending_emission(5), 5_857_251); assert_eq!(SubtensorModule::get_pending_emission(5), 3_530_356); step_block(1); });