From c9efdea6e620e78a305243ee4d2617820610d25b Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Tue, 25 Jun 2024 01:42:17 +0400 Subject: [PATCH] Revert "Merge branch 'devnet-ready' into devnet_companion_refactor/hotkey_swap" This reverts commit 8d198b18b3f96e63cb53096a07434ff38cae133f, reversing changes made to 64b546d9b98ea4c48aaa25b97e9741d0b4e194ea. --- .github/workflows/check-devnet.yml | 15 - .github/workflows/check-finney.yml | 16 +- .github/workflows/check-rust.yml | 41 + .github/workflows/check-testnet.yml | 15 - Cargo.lock | 2 - docs/running-subtensor-locally.md | 9 +- justfile | 17 +- node/src/command.rs | 50 +- pallets/admin-utils/Cargo.toml | 4 +- pallets/admin-utils/src/lib.rs | 46 - pallets/admin-utils/tests/mock.rs | 21 +- pallets/admin-utils/tests/tests.rs | 187 +- pallets/subtensor/Cargo.toml | 5 +- pallets/subtensor/src/epoch.rs | 509 +----- pallets/subtensor/src/errors.rs | 6 - pallets/subtensor/src/lib.rs | 31 +- pallets/subtensor/src/math.rs | 2271 +++++++++++++++++++++++-- pallets/subtensor/src/subnet_info.rs | 10 +- pallets/subtensor/src/utils.rs | 26 +- pallets/subtensor/tests/epoch.rs | 772 +-------- pallets/subtensor/tests/math.rs | 2350 -------------------------- pallets/subtensor/tests/mock.rs | 6 - runtime/src/lib.rs | 21 +- scripts/test_specific.sh | 2 +- zepter.yaml | 3 +- 25 files changed, 2231 insertions(+), 4204 deletions(-) delete mode 100644 pallets/subtensor/tests/math.rs diff --git a/.github/workflows/check-devnet.yml b/.github/workflows/check-devnet.yml index fcc9809d3..d8f2be391 100644 --- a/.github/workflows/check-devnet.yml +++ b/.github/workflows/check-devnet.yml @@ -37,18 +37,3 @@ jobs: echo "network spec_version: $spec_version" if (( $(echo "$local_spec_version <= $spec_version" | bc -l) )); then echo "$local_spec_version ≯ $spec_version ❌"; exit 1; fi echo "$local_spec_version > $spec_version ✅" - - check-devnet-migrations: - name: check devnet migrations - runs-on: ubuntu-22.04 - steps: - - name: Checkout sources - uses: actions/checkout@v3 - - - name: Run Try Runtime Checks - uses: "paritytech/try-runtime-gha@v0.1.0" - with: - runtime-package: "node-subtensor-runtime" - node-uri: "wss://dev.chain.opentensor.ai:443" - checks: "pre-and-post" - extra-args: "--disable-spec-version-check --no-weight-warnings" \ No newline at end of file diff --git a/.github/workflows/check-finney.yml b/.github/workflows/check-finney.yml index 4bb12caf2..c74980bcd 100644 --- a/.github/workflows/check-finney.yml +++ b/.github/workflows/check-finney.yml @@ -2,7 +2,7 @@ name: Finney Deploy Check on: pull_request: - branches: [finney, main] + branches: [finney] env: CARGO_TERM_COLOR: always @@ -37,17 +37,3 @@ jobs: echo "network spec_version: $spec_version" if (( $(echo "$local_spec_version <= $spec_version" | bc -l) )); then echo "$local_spec_version ≯ $spec_version ❌"; exit 1; fi echo "$local_spec_version > $spec_version ✅" - - check-finney-migrations: - name: check finney migrations - runs-on: SubtensorCI - steps: - - name: Checkout sources - uses: actions/checkout@v4 - - name: Run Try Runtime Checks - uses: "paritytech/try-runtime-gha@v0.1.0" - with: - runtime-package: "node-subtensor-runtime" - node-uri: "wss://entrypoint-finney.opentensor.ai:443" - checks: "pre-and-post" - extra-args: "--disable-spec-version-check --no-weight-warnings" \ No newline at end of file diff --git a/.github/workflows/check-rust.yml b/.github/workflows/check-rust.yml index e95308861..1716bd454 100644 --- a/.github/workflows/check-rust.yml +++ b/.github/workflows/check-rust.yml @@ -339,6 +339,47 @@ jobs: - name: Check features run: zepter run check + check-finney-migrations: + name: check finney migrations + runs-on: SubtensorCI + steps: + - name: Checkout sources + uses: actions/checkout@v4 + - name: Run Try Runtime Checks + uses: "paritytech/try-runtime-gha@v0.1.0" + with: + runtime-package: "node-subtensor-runtime" + node-uri: "wss://entrypoint-finney.opentensor.ai:443" + checks: "pre-and-post" + extra-args: "--disable-spec-version-check --no-weight-warnings" + + check-devnet-migrations: + name: check devnet migrations + runs-on: ubuntu-22.04 + steps: + - name: Checkout sources + uses: actions/checkout@v3 + - name: Run Try Runtime Checks + uses: "paritytech/try-runtime-gha@v0.1.0" + with: + runtime-package: "node-subtensor-runtime" + node-uri: "wss://dev.chain.opentensor.ai:443" + checks: "pre-and-post" + extra-args: "--disable-spec-version-check --no-weight-warnings" + + check-testnet-migrations: + name: check testnet migrations + runs-on: ubuntu-22.04 + steps: + - name: Checkout sources + uses: actions/checkout@v3 + - name: Run Try Runtime Checks + uses: "paritytech/try-runtime-gha@v0.1.0" + with: + runtime-package: "node-subtensor-runtime" + node-uri: "wss://test.chain.opentensor.ai:443" + checks: "pre-and-post" + extra-args: "--disable-spec-version-check --no-weight-warnings" diff --git a/.github/workflows/check-testnet.yml b/.github/workflows/check-testnet.yml index 71c46557c..5fe046b06 100644 --- a/.github/workflows/check-testnet.yml +++ b/.github/workflows/check-testnet.yml @@ -37,18 +37,3 @@ jobs: echo "network spec_version: $spec_version" if (( $(echo "$local_spec_version <= $spec_version" | bc -l) )); then echo "$local_spec_version ≯ $spec_version ❌"; exit 1; fi echo "$local_spec_version > $spec_version ✅" - - check-testnet-migrations: - name: check testnet migrations - runs-on: ubuntu-22.04 - steps: - - name: Checkout sources - uses: actions/checkout@v3 - - - name: Run Try Runtime Checks - uses: "paritytech/try-runtime-gha@v0.1.0" - with: - runtime-package: "node-subtensor-runtime" - node-uri: "wss://test.chain.opentensor.ai:443" - checks: "pre-and-post" - extra-args: "--disable-spec-version-check --no-weight-warnings" diff --git a/Cargo.lock b/Cargo.lock index 868e85b89..7ea7732d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4954,7 +4954,6 @@ dependencies = [ "sp-runtime", "sp-tracing 16.0.0 (git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-v1.10.0)", "sp-weights", - "substrate-fixed", "subtensor-macros", ] @@ -5229,7 +5228,6 @@ dependencies = [ "hex-literal", "log", "ndarray", - "num-traits", "pallet-balances", "pallet-collective", "pallet-membership", diff --git a/docs/running-subtensor-locally.md b/docs/running-subtensor-locally.md index 089f4d30a..4d827d858 100644 --- a/docs/running-subtensor-locally.md +++ b/docs/running-subtensor-locally.md @@ -174,7 +174,7 @@ You can now run the public subtensor node either as a lite node or as an archive To run a lite node connected to the mainchain, execute the below command (note the `--sync=warp` flag which runs the subtensor node in lite mode): ```bash title="With --sync=warp setting, for lite node" -./target/release/node-subtensor --chain raw_spec.json --base-path /tmp/blockchain --sync=warp --port 30333 --max-runtime-instances 32 --rpc-max-response-size 2048 --rpc-cors all --rpc-port 9944 --bootnodes /ip4/13.58.175.193/tcp/30333/p2p/12D3KooWDe7g2JbNETiKypcKT1KsCEZJbTzEHCn8hpd4PHZ6pdz5 --no-mdns --in-peers 8000 --out-peers 8000 --prometheus-external --rpc-external +./target/release/node-subtensor --chain raw_spec.json --base-path /tmp/blockchain --sync=warp --execution wasm --wasm-execution compiled --port 30333 --max-runtime-instances 32 --rpc-max-response-size 2048 --rpc-cors all --rpc-port 9944 --bootnodes /ip4/13.58.175.193/tcp/30333/p2p/12D3KooWDe7g2JbNETiKypcKT1KsCEZJbTzEHCn8hpd4PHZ6pdz5 --no-mdns --in-peers 8000 --out-peers 8000 --prometheus-external --rpc-external ``` ### Archive node on mainchain @@ -182,7 +182,7 @@ To run a lite node connected to the mainchain, execute the below command (note t To run an archive node connected to the mainchain, execute the below command (note the `--sync=full` which syncs the node to the full chain and `--pruning archive` flags, which disables the node's automatic pruning of older historical data): ```bash title="With --sync=full and --pruning archive setting, for archive node" -./target/release/node-subtensor --chain raw_spec.json --base-path /tmp/blockchain --sync=full --pruning archive --port 30333 --max-runtime-instances 32 --rpc-max-response-size 2048 --rpc-cors all --rpc-port 9944 --bootnodes /ip4/13.58.175.193/tcp/30333/p2p/12D3KooWDe7g2JbNETiKypcKT1KsCEZJbTzEHCn8hpd4PHZ6pdz5 --no-mdns --in-peers 8000 --out-peers 8000 --prometheus-external --rpc-external +./target/release/node-subtensor --chain raw_spec.json --base-path /tmp/blockchain --sync=full --pruning archive --execution wasm --wasm-execution compiled --port 30333 --max-runtime-instances 32 --rpc-max-response-size 2048 --rpc-cors all --rpc-port 9944 --bootnodes /ip4/13.58.175.193/tcp/30333/p2p/12D3KooWDe7g2JbNETiKypcKT1KsCEZJbTzEHCn8hpd4PHZ6pdz5 --no-mdns --in-peers 8000 --out-peers 8000 --prometheus-external --rpc-external ``` ### Lite node on testchain @@ -190,7 +190,7 @@ To run an archive node connected to the mainchain, execute the below command (no To run a lite node connected to the testchain, execute the below command: ```bash title="With bootnodes set to testnet and --sync=warp setting, for lite node." -./target/release/node-subtensor --chain raw_testspec.json --base-path /tmp/blockchain --sync=warp --port 30333 --max-runtime-instances 32 --rpc-max-response-size 2048 --rpc-cors all --rpc-port 9944 --bootnodes /dns/bootnode.test.finney.opentensor.ai/tcp/30333/p2p/12D3KooWPM4mLcKJGtyVtkggqdG84zWrd7Rij6PGQDoijh1X86Vr --no-mdns --in-peers 8000 --out-peers 8000 --prometheus-external --rpc-external +./target/release/node-subtensor --chain raw_testspec.json --base-path /tmp/blockchain --sync=warp --execution wasm --wasm-execution compiled --port 30333 --max-runtime-instances 32 --rpc-max-response-size 2048 --rpc-cors all --rpc-port 9944 --bootnodes /dns/bootnode.test.finney.opentensor.ai/tcp/30333/p2p/12D3KooWPM4mLcKJGtyVtkggqdG84zWrd7Rij6PGQDoijh1X86Vr --no-mdns --in-peers 8000 --out-peers 8000 --prometheus-external --rpc-external ``` ### Archive node on testchain @@ -198,9 +198,8 @@ To run a lite node connected to the testchain, execute the below command: To run an archive node connected to the testchain, execute the below command: ```bash title="With bootnodes set to testnet and --sync=full and --pruning archive setting, for archive node" -./target/release/node-subtensor --chain raw_testspec.json --base-path /tmp/blockchain --sync=full --pruning archive --port 30333 --max-runtime-instances 32 --rpc-max-response-size 2048 --rpc-cors all --rpc-port 9944 --bootnodes /dns/bootnode.test.finney.opentensor.ai/tcp/30333/p2p/12D3KooWPM4mLcKJGtyVtkggqdG84zWrd7Rij6PGQDoijh1X86Vr --no-mdns --in-peers 8000 --out-peers 8000 --prometheus-external --rpc-external +./target/release/node-subtensor --chain raw_testspec.json --base-path /tmp/blockchain --sync=full --pruning archive --execution wasm --wasm-execution compiled --port 30333 --max-runtime-instances 32 --rpc-max-response-size 2048 --rpc-cors all --rpc-port 9944 --bootnodes /dns/bootnode.test.finney.opentensor.ai/tcp/30333/p2p/12D3KooWPM4mLcKJGtyVtkggqdG84zWrd7Rij6PGQDoijh1X86Vr --no-mdns --in-peers 8000 --out-peers 8000 --prometheus-external --rpc-external ``` ## Running on cloud - We have not tested these installation scripts on any cloud service. In addition, if you are using Runpod cloud service, then note that this service is already [containerized](https://docs.runpod.io/pods/overview). Hence, the only option available to you is to compile from the source, as described in the above [Method 2: Using Source Code](#method-2-using-source-code) section. Note that these scripts have not been tested on Runpod. diff --git a/justfile b/justfile index 72b0f2c89..69a5fd2d1 100644 --- a/justfile +++ b/justfile @@ -25,25 +25,16 @@ benchmarks: clippy: @echo "Running cargo clippy..." - cargo +{{RUSTV}} clippy --workspace --all-targets -- \ + cargo +{{RUSTV}} clippy -- -D clippy::panic \ -D clippy::todo \ -D clippy::unimplemented clippy-fix: @echo "Running cargo clippy with automatic fixes on potentially dirty code..." - cargo +{{RUSTV}} clippy --workspace --all-targets --fix --allow-dirty -- \ + cargo +{{RUSTV}} clippy --fix --allow-dirty -- -A clippy::panic \ -A clippy::todo \ - -A clippy::unimplemented \ - -A clippy::indexing_slicing + -A clippy::unimplemented fix: @echo "Running cargo fix..." cargo +{{RUSTV}} fix --workspace - git diff --exit-code || (echo "There are local changes after running 'cargo fix --workspace' ❌" && exit 1) - -lint: - @echo "Running cargo fmt..." - just fmt - @echo "Running cargo clippy with automatic fixes on potentially dirty code..." - just clippy-fix - @echo "Running cargo clippy..." - just clippy \ No newline at end of file + git diff --exit-code || (echo "There are local changes after running 'cargo fix --workspace' ❌" && exit 1) \ No newline at end of file diff --git a/node/src/command.rs b/node/src/command.rs index 2423d1456..23674ad17 100644 --- a/node/src/command.rs +++ b/node/src/command.rs @@ -17,7 +17,7 @@ use sp_runtime::traits::HashingFor; use node_subtensor_runtime::Block; use sc_cli::SubstrateCli; -use sc_service::{Configuration, PartialComponents}; +use sc_service::PartialComponents; impl SubstrateCli for Cli { fn impl_name() -> String { @@ -209,56 +209,8 @@ pub fn run() -> sc_cli::Result<()> { None => { let runner = cli.create_runner(&cli.run)?; runner.run_node_until_exit(|config| async move { - let config = override_default_heap_pages(config, 60_000); service::new_full(config).map_err(sc_cli::Error::Service) }) } } } - -/// Override default heap pages -fn override_default_heap_pages(config: Configuration, pages: u64) -> Configuration { - Configuration { - default_heap_pages: Some(pages), - impl_name: config.impl_name, - impl_version: config.impl_version, - role: config.role, - tokio_handle: config.tokio_handle, - transaction_pool: config.transaction_pool, - network: config.network, - keystore: config.keystore, - database: config.database, - trie_cache_maximum_size: config.trie_cache_maximum_size, - state_pruning: config.state_pruning, - blocks_pruning: config.blocks_pruning, - chain_spec: config.chain_spec, - wasm_method: config.wasm_method, - wasm_runtime_overrides: config.wasm_runtime_overrides, - rpc_addr: config.rpc_addr, - rpc_max_connections: config.rpc_max_connections, - rpc_cors: config.rpc_cors, - rpc_methods: config.rpc_methods, - rpc_max_request_size: config.rpc_max_request_size, - rpc_max_response_size: config.rpc_max_response_size, - rpc_id_provider: config.rpc_id_provider, - rpc_max_subs_per_conn: config.rpc_max_subs_per_conn, - rpc_port: config.rpc_port, - rpc_message_buffer_capacity: config.rpc_message_buffer_capacity, - rpc_batch_config: config.rpc_batch_config, - rpc_rate_limit: config.rpc_rate_limit, - prometheus_config: config.prometheus_config, - telemetry_endpoints: config.telemetry_endpoints, - offchain_worker: config.offchain_worker, - force_authoring: config.force_authoring, - disable_grandpa: config.disable_grandpa, - dev_key_seed: config.dev_key_seed, - tracing_targets: config.tracing_targets, - tracing_receiver: config.tracing_receiver, - max_runtime_instances: config.max_runtime_instances, - announce_block: config.announce_block, - data_path: config.data_path, - base_path: config.base_path, - informant_output_format: config.informant_output_format, - runtime_cache_size: config.runtime_cache_size, - } -} diff --git a/pallets/admin-utils/Cargo.toml b/pallets/admin-utils/Cargo.toml index 859972fce..fd2d3952e 100644 --- a/pallets/admin-utils/Cargo.toml +++ b/pallets/admin-utils/Cargo.toml @@ -28,7 +28,6 @@ sp-runtime = { workspace = true } log = { workspace = true } pallet-subtensor = { version = "4.0.0-dev", default-features = false, path = "../subtensor" } sp-weights = { workspace = true } -substrate-fixed = { workspace = true } [dev-dependencies] @@ -55,8 +54,7 @@ std = [ "sp-weights/std", "log/std", "sp-core/std", - "sp-io/std", - "substrate-fixed/std", + "sp-io/std" ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", diff --git a/pallets/admin-utils/src/lib.rs b/pallets/admin-utils/src/lib.rs index 9a8744dc6..47799f30d 100644 --- a/pallets/admin-utils/src/lib.rs +++ b/pallets/admin-utils/src/lib.rs @@ -996,45 +996,6 @@ pub mod pallet { log::info!("ToggleSetWeightsCommitReveal( netuid: {:?} ) ", netuid); Ok(()) } - - /// Enables or disables Liquid Alpha for a given subnet. - /// - /// # Parameters - /// - `origin`: The origin of the call, which must be the root account or subnet owner. - /// - `netuid`: The unique identifier for the subnet. - /// - `enabled`: A boolean flag to enable or disable Liquid Alpha. - /// - /// # Weight - /// This function has a fixed weight of 0 and is classified as an operational transaction that does not incur any fees. - #[pallet::call_index(50)] - #[pallet::weight((0, DispatchClass::Operational, Pays::No))] - pub fn sudo_set_liquid_alpha_enabled( - origin: OriginFor, - netuid: u16, - enabled: bool, - ) -> DispatchResult { - T::Subtensor::ensure_subnet_owner_or_root(origin, netuid)?; - T::Subtensor::set_liquid_alpha_enabled(netuid, enabled); - log::info!( - "LiquidAlphaEnableToggled( netuid: {:?}, Enabled: {:?} ) ", - netuid, - enabled - ); - Ok(()) - } - - /// Sets values for liquid alpha - #[pallet::call_index(51)] - #[pallet::weight((0, DispatchClass::Operational, Pays::No))] - pub fn sudo_set_alpha_values( - origin: OriginFor, - netuid: u16, - alpha_low: u16, - alpha_high: u16, - ) -> DispatchResult { - T::Subtensor::ensure_subnet_owner_or_root(origin.clone(), netuid)?; - T::Subtensor::do_set_alpha_values(origin, netuid, alpha_low, alpha_high) - } } } @@ -1130,11 +1091,4 @@ pub trait SubtensorInterface { fn set_target_stakes_per_interval(target_stakes_per_interval: u64); fn set_commit_reveal_weights_interval(netuid: u16, interval: u64); fn set_commit_reveal_weights_enabled(netuid: u16, enabled: bool); - fn set_liquid_alpha_enabled(netuid: u16, enabled: bool); - fn do_set_alpha_values( - origin: RuntimeOrigin, - netuid: u16, - alpha_low: u16, - alpha_high: u16, - ) -> Result<(), DispatchError>; } diff --git a/pallets/admin-utils/tests/mock.rs b/pallets/admin-utils/tests/mock.rs index a78eb6d3d..520dceb3d 100644 --- a/pallets/admin-utils/tests/mock.rs +++ b/pallets/admin-utils/tests/mock.rs @@ -24,7 +24,7 @@ frame_support::construct_runtime!( System: frame_system, Balances: pallet_balances, AdminUtils: pallet_admin_utils, - SubtensorModule: pallet_subtensor::{Pallet, Call, Storage, Event, Error}, + SubtensorModule: pallet_subtensor::{Pallet, Call, Storage, Event}, } ); @@ -111,9 +111,7 @@ parameter_types! { pub const InitialNetworkRateLimit: u64 = 0; pub const InitialTargetStakesPerInterval: u16 = 1; pub const InitialHotkeySwapCost: u64 = 1_000_000_000; - pub const InitialAlphaHigh: u16 = 58982; // Represents 0.9 as per the production default - pub const InitialAlphaLow: u16 = 45875; // Represents 0.7 as per the production default - pub const InitialLiquidAlphaOn: bool = false; // Default value for LiquidAlphaOn + } impl pallet_subtensor::Config for Test { @@ -166,9 +164,6 @@ impl pallet_subtensor::Config for Test { type InitialNetworkRateLimit = InitialNetworkRateLimit; type InitialTargetStakesPerInterval = InitialTargetStakesPerInterval; type HotkeySwapCost = InitialHotkeySwapCost; - type AlphaHigh = InitialAlphaHigh; - type AlphaLow = InitialAlphaLow; - type LiquidAlphaOn = InitialLiquidAlphaOn; } #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] @@ -471,18 +466,6 @@ impl pallet_admin_utils::SubtensorInterface f fn set_commit_reveal_weights_enabled(netuid: u16, enabled: bool) { SubtensorModule::set_commit_reveal_weights_enabled(netuid, enabled); } - - fn set_liquid_alpha_enabled(netuid: u16, enabled: bool) { - SubtensorModule::set_liquid_alpha_enabled(netuid, enabled); - } - fn do_set_alpha_values( - origin: RuntimeOrigin, - netuid: u16, - alpha_low: u16, - alpha_high: u16, - ) -> Result<(), DispatchError> { - SubtensorModule::do_set_alpha_values(origin, netuid, alpha_low, alpha_high) - } } impl pallet_admin_utils::Config for Test { diff --git a/pallets/admin-utils/tests/tests.rs b/pallets/admin-utils/tests/tests.rs index 9df59978f..f87b43e74 100644 --- a/pallets/admin-utils/tests/tests.rs +++ b/pallets/admin-utils/tests/tests.rs @@ -1,12 +1,8 @@ +use frame_support::assert_ok; use frame_support::sp_runtime::DispatchError; -use frame_support::{ - assert_err, assert_ok, - dispatch::{DispatchClass, GetDispatchInfo, Pays}, -}; use frame_system::Config; use pallet_admin_utils::Error; -use pallet_subtensor::Error as SubtensorError; -use pallet_subtensor::{migration, Event}; +use pallet_subtensor::Event; use sp_core::U256; mod mock; @@ -1182,182 +1178,3 @@ fn test_sudo_set_target_stakes_per_interval() { assert_eq!(SubtensorModule::get_target_stakes_per_interval(), to_be_set); }); } - -#[test] -fn test_sudo_set_liquid_alpha_enabled() { - new_test_ext().execute_with(|| { - let netuid: u16 = 1; - let enabled: bool = true; - assert_eq!(!enabled, SubtensorModule::get_liquid_alpha_enabled(netuid)); - - assert_ok!(AdminUtils::sudo_set_liquid_alpha_enabled( - <::RuntimeOrigin>::root(), - netuid, - enabled - )); - - assert_eq!(enabled, SubtensorModule::get_liquid_alpha_enabled(netuid)); - }); -} - -#[test] -fn test_set_alpha_values_dispatch_info_ok() { - new_test_ext().execute_with(|| { - let netuid: u16 = 1; - let alpha_low: u16 = 12_u16; - let alpha_high: u16 = u16::MAX - 10; - let call = RuntimeCall::AdminUtils(pallet_admin_utils::Call::sudo_set_alpha_values { - netuid, - alpha_low, - alpha_high, - }); - - let dispatch_info = call.get_dispatch_info(); - - assert_eq!(dispatch_info.class, DispatchClass::Operational); - assert_eq!(dispatch_info.pays_fee, Pays::No); - }); -} - -#[test] -fn test_sudo_get_set_alpha() { - new_test_ext().execute_with(|| { - let netuid: u16 = 1; - let alpha_low: u16 = 12_u16; - let alpha_high: u16 = u16::MAX - 10; - - let hotkey: U256 = U256::from(1); - let coldkey: U256 = U256::from(1 + 456); - let signer = <::RuntimeOrigin>::signed(coldkey); - - // Enable Liquid Alpha and setup - SubtensorModule::set_liquid_alpha_enabled(netuid, true); - migration::migrate_create_root_network::(); - SubtensorModule::add_balance_to_coldkey_account(&coldkey, 1_000_000_000_000_000); - assert_ok!(SubtensorModule::root_register(signer.clone(), hotkey,)); - assert_ok!(SubtensorModule::add_stake(signer.clone(), hotkey, 1000)); - - // Should fail as signer does not own the subnet - assert_err!( - AdminUtils::sudo_set_alpha_values(signer.clone(), netuid, alpha_low, alpha_high), - DispatchError::BadOrigin - ); - - assert_ok!(SubtensorModule::register_network(signer.clone())); - - assert_ok!(AdminUtils::sudo_set_alpha_values( - signer.clone(), - netuid, - alpha_low, - alpha_high - )); - let (grabbed_alpha_low, grabbed_alpha_high): (u16, u16) = - SubtensorModule::get_alpha_values(netuid); - - log::info!( - "alpha_low: {:?} alpha_high: {:?}", - grabbed_alpha_low, - grabbed_alpha_high - ); - assert_eq!(grabbed_alpha_low, alpha_low); - assert_eq!(grabbed_alpha_high, alpha_high); - - // Convert the u16 values to decimal values - fn unnormalize_u16_to_float(normalized_value: u16) -> f32 { - const MAX_U16: u16 = 65535; - normalized_value as f32 / MAX_U16 as f32 - } - - let alpha_low_decimal = unnormalize_u16_to_float(alpha_low); - let alpha_high_decimal = unnormalize_u16_to_float(alpha_high); - - let (alpha_low_32, alpha_high_32) = SubtensorModule::get_alpha_values_32(netuid); - - let tolerance: f32 = 1e-6; // 0.000001 - - // Check if the values are equal to the sixth decimal - assert!( - (alpha_low_32.to_num::() - alpha_low_decimal).abs() < tolerance, - "alpha_low mismatch: {} != {}", - alpha_low_32.to_num::(), - alpha_low_decimal - ); - assert!( - (alpha_high_32.to_num::() - alpha_high_decimal).abs() < tolerance, - "alpha_high mismatch: {} != {}", - alpha_high_32.to_num::(), - alpha_high_decimal - ); - - // 1. Liquid alpha disabled - SubtensorModule::set_liquid_alpha_enabled(netuid, false); - assert_err!( - AdminUtils::sudo_set_alpha_values(signer.clone(), netuid, alpha_low, alpha_high), - SubtensorError::::LiquidAlphaDisabled - ); - // Correct scenario after error - SubtensorModule::set_liquid_alpha_enabled(netuid, true); // Re-enable for further tests - assert_ok!(AdminUtils::sudo_set_alpha_values( - signer.clone(), - netuid, - alpha_low, - alpha_high - )); - - // 2. Alpha high too low - let alpha_high_too_low = (u16::MAX as u32 * 4 / 5) as u16 - 1; // One less than the minimum acceptable value - assert_err!( - AdminUtils::sudo_set_alpha_values( - signer.clone(), - netuid, - alpha_low, - alpha_high_too_low - ), - SubtensorError::::AlphaHighTooLow - ); - // Correct scenario after error - assert_ok!(AdminUtils::sudo_set_alpha_values( - signer.clone(), - netuid, - alpha_low, - alpha_high - )); - - // 3. Alpha low too low or too high - let alpha_low_too_low = 0_u16; - assert_err!( - AdminUtils::sudo_set_alpha_values( - signer.clone(), - netuid, - alpha_low_too_low, - alpha_high - ), - SubtensorError::::AlphaLowOutOfRange - ); - // Correct scenario after error - assert_ok!(AdminUtils::sudo_set_alpha_values( - signer.clone(), - netuid, - alpha_low, - alpha_high - )); - - let alpha_low_too_high = (u16::MAX as u32 * 4 / 5) as u16 + 1; // One more than the maximum acceptable value - assert_err!( - AdminUtils::sudo_set_alpha_values( - signer.clone(), - netuid, - alpha_low_too_high, - alpha_high - ), - SubtensorError::::AlphaLowOutOfRange - ); - // Correct scenario after error - assert_ok!(AdminUtils::sudo_set_alpha_values( - signer.clone(), - netuid, - alpha_low, - alpha_high - )); - }); -} diff --git a/pallets/subtensor/Cargo.toml b/pallets/subtensor/Cargo.toml index a0835008f..f9ed9d479 100644 --- a/pallets/subtensor/Cargo.toml +++ b/pallets/subtensor/Cargo.toml @@ -44,7 +44,6 @@ hex = { workspace = true } pallet-collective = { version = "4.0.0-dev", default-features = false, path = "../collective" } pallet-membership = { workspace = true } hex-literal = { workspace = true } -num-traits = { version = "0.2.19", default-features = false, features = ["libm"] } [dev-dependencies] pallet-balances = { workspace = true, features = ["std"] } @@ -80,9 +79,7 @@ std = [ "ndarray/std", "serde/std", "serde_bytes/std", - "serde_with/std", - "substrate-fixed/std", - "num-traits/std", + "serde_with/std" ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", diff --git a/pallets/subtensor/src/epoch.rs b/pallets/subtensor/src/epoch.rs index e90f4b73d..cd2666d9d 100644 --- a/pallets/subtensor/src/epoch.rs +++ b/pallets/subtensor/src/epoch.rs @@ -118,19 +118,19 @@ impl Pallet { // Mask weights that are not from permitted validators. inplace_mask_rows(&validator_forbids, &mut weights); - log::trace!("W (permit): {:?}", &weights); + // log::trace!( "W (permit): {:?}", &weights ); // Remove self-weight by masking diagonal. inplace_mask_diag(&mut weights); - log::trace!("W (permit+diag):\n{:?}\n", &weights); + // log::trace!( "W (permit+diag):\n{:?}\n", &weights ); // Mask outdated weights: remove weights referring to deregistered neurons. inplace_mask_matrix(&outdated, &mut weights); - log::trace!("W (permit+diag+outdate):\n{:?}\n", &weights); + // log::trace!( "W (permit+diag+outdate):\n{:?}\n", &weights ); // Normalize remaining weights. inplace_row_normalize(&mut weights); - log::trace!("W (mask+norm):\n{:?}\n", &weights); + // log::trace!( "W (mask+norm):\n{:?}\n", &weights ); // ================================ // == Consensus, Validator Trust == @@ -167,17 +167,21 @@ impl Pallet { let mut bonds: Vec> = Self::get_bonds(netuid); inplace_mask_matrix(&outdated, &mut bonds); // mask outdated bonds inplace_col_normalize(&mut bonds); // sum_i b_ij = 1 - log::trace!("B:\n{:?}\n", &bonds); + // log::trace!( "B:\n{:?}\n", &bonds ); // Compute bonds delta column normalized. let mut bonds_delta: Vec> = row_hadamard(&weights, &active_stake); // ΔB = W◦S inplace_col_normalize(&mut bonds_delta); // sum_i b_ij = 1 - log::trace!("ΔB:\n{:?}\n", &bonds_delta); - // Compute the Exponential Moving Average (EMA) of bonds. - let mut ema_bonds = Self::compute_ema_bonds(netuid, consensus.clone(), bonds_delta, bonds); + // log::trace!( "ΔB:\n{:?}\n", &bonds_delta ); + // Compute bonds moving average. + let bonds_moving_average: I64F64 = I64F64::from_num(Self::get_bonds_moving_average(netuid)) + .saturating_div(I64F64::from_num(1_000_000)); + let alpha: I32F32 = + I32F32::from_num(1).saturating_sub(I32F32::from_num(bonds_moving_average)); + let mut ema_bonds: Vec> = mat_ema(&bonds_delta, &bonds, alpha); inplace_col_normalize(&mut ema_bonds); // sum_i b_ij = 1 - log::trace!("emaB:\n{:?}\n", &ema_bonds); + // log::trace!( "emaB:\n{:?}\n", &ema_bonds ); // Compute dividends: d_i = SUM(j) b_ij * inc_j let mut dividends: Vec = matmul_transpose(&ema_bonds, &incentive); @@ -189,6 +193,8 @@ impl Pallet { // ================================= // Compute emission scores. + + // Compute normalized emission scores. range: I32F32(0, 1) // Compute normalized emission scores. range: I32F32(0, 1) let combined_emission: Vec = incentive .iter() @@ -350,7 +356,7 @@ impl Pallet { pub fn epoch(netuid: u16, rao_emission: u64) -> Vec<(T::AccountId, u64, u64)> { // Get subnetwork size. let n: u16 = Self::get_subnetwork_n(netuid); - log::trace!("Number of Neurons in Network: {:?}", n); + log::trace!("n: {:?}", n); // ====================== // == Active & updated == @@ -396,11 +402,10 @@ impl Pallet { for (uid_i, hotkey) in &hotkeys { stake_64[*uid_i as usize] = I64F64::from_num(Self::get_total_stake_for_hotkey(hotkey)); } - log::trace!("Stake : {:?}", &stake_64); inplace_normalize_64(&mut stake_64); let stake: Vec = vec_fixed64_to_fixed32(stake_64); // range: I32F32(0, 1) - log::trace!("Normalised Stake: {:?}", &stake); + log::trace!("S: {:?}", &stake); // ======================= // == Validator permits == @@ -435,7 +440,7 @@ impl Pallet { // Normalize active stake. inplace_normalize(&mut active_stake); - log::trace!("Active Stake:\n{:?}\n", &active_stake); + log::trace!("S:\n{:?}\n", &active_stake); // ============= // == Weights == @@ -443,15 +448,15 @@ impl Pallet { // Access network weights row unnormalized. let mut weights: Vec> = Self::get_weights_sparse(netuid); - log::trace!("Weights: {:?}", &weights); + // log::trace!( "W: {:?}", &weights ); // Mask weights that are not from permitted validators. weights = mask_rows_sparse(&validator_forbids, &weights); - log::trace!("Weights (permit): {:?}", &weights); + // log::trace!( "W (permit): {:?}", &weights ); // Remove self-weight by masking diagonal. weights = mask_diag_sparse(&weights); - log::trace!("Weights (permit+diag): {:?}", &weights); + // log::trace!( "W (permit+diag): {:?}", &weights ); // Remove weights referring to deregistered neurons. weights = vec_mask_sparse_matrix( @@ -460,11 +465,11 @@ impl Pallet { &block_at_registration, &|updated, registered| updated <= registered, ); - log::trace!("Weights (permit+diag+outdate): {:?}", &weights); + // log::trace!( "W (permit+diag+outdate): {:?}", &weights ); // Normalize remaining weights. inplace_row_normalize_sparse(&mut weights); - log::trace!("Weights (mask+norm): {:?}", &weights); + // log::trace!( "W (mask+norm): {:?}", &weights ); // ================================ // == Consensus, Validator Trust == @@ -472,18 +477,18 @@ impl Pallet { // Compute preranks: r_j = SUM(i) w_ij * s_i let preranks: Vec = matmul_sparse(&weights, &active_stake, n); - log::trace!("Ranks (before): {:?}", &preranks); + // log::trace!( "R (before): {:?}", &preranks ); // Clip weights at majority consensus let kappa: I32F32 = Self::get_float_kappa(netuid); // consensus majority ratio, e.g. 51%. let consensus: Vec = weighted_median_col_sparse(&active_stake, &weights, n, kappa); - log::trace!("Consensus: {:?}", &consensus); + log::trace!("C: {:?}", &consensus); weights = col_clip_sparse(&weights, &consensus); - log::trace!("Weights: {:?}", &weights); + // log::trace!( "W: {:?}", &weights ); let validator_trust: Vec = row_sum_sparse(&weights); - log::trace!("Validator Trust: {:?}", &validator_trust); + log::trace!("Tv: {:?}", &validator_trust); // ============================= // == Ranks, Trust, Incentive == @@ -491,7 +496,7 @@ impl Pallet { // Compute ranks: r_j = SUM(i) w_ij * s_i. let mut ranks: Vec = matmul_sparse(&weights, &active_stake, n); - log::trace!("Ranks (after): {:?}", &ranks); + // log::trace!( "R (after): {:?}", &ranks ); // Compute server trust: ratio of rank after vs. rank before. let trust: Vec = vecdiv(&ranks, &preranks); // range: I32F32(0, 1) @@ -499,7 +504,7 @@ impl Pallet { inplace_normalize(&mut ranks); // range: I32F32(0, 1) let incentive: Vec = ranks.clone(); - log::trace!("Incentive (=Rank): {:?}", &incentive); + log::trace!("I (=R): {:?}", &incentive); // ========================= // == Bonds and Dividends == @@ -507,7 +512,7 @@ impl Pallet { // Access network bonds. let mut bonds: Vec> = Self::get_bonds_sparse(netuid); - log::trace!("B: {:?}", &bonds); + // log::trace!( "B: {:?}", &bonds ); // Remove bonds referring to deregistered neurons. bonds = vec_mask_sparse_matrix( @@ -516,32 +521,36 @@ impl Pallet { &block_at_registration, &|updated, registered| updated <= registered, ); - log::trace!("B (outdatedmask): {:?}", &bonds); + // log::trace!( "B (outdatedmask): {:?}", &bonds ); // Normalize remaining bonds: sum_i b_ij = 1. inplace_col_normalize_sparse(&mut bonds, n); - log::trace!("B (mask+norm): {:?}", &bonds); + // log::trace!( "B (mask+norm): {:?}", &bonds ); // Compute bonds delta column normalized. let mut bonds_delta: Vec> = row_hadamard_sparse(&weights, &active_stake); // ΔB = W◦S (outdated W masked) - log::trace!("ΔB: {:?}", &bonds_delta); + // log::trace!( "ΔB: {:?}", &bonds_delta ); // Normalize bonds delta. inplace_col_normalize_sparse(&mut bonds_delta, n); // sum_i b_ij = 1 - log::trace!("ΔB (norm): {:?}", &bonds_delta); + // log::trace!( "ΔB (norm): {:?}", &bonds_delta ); + + // Compute bonds moving average. + let bonds_moving_average: I64F64 = I64F64::from_num(Self::get_bonds_moving_average(netuid)) + .saturating_div(I64F64::from_num(1_000_000)); + let alpha: I32F32 = + I32F32::from_num(1).saturating_sub(I32F32::from_num(bonds_moving_average)); + let mut ema_bonds: Vec> = mat_ema_sparse(&bonds_delta, &bonds, alpha); - // Compute the Exponential Moving Average (EMA) of bonds. - let mut ema_bonds = - Self::compute_ema_bonds_sparse(netuid, consensus.clone(), bonds_delta, bonds); // Normalize EMA bonds. inplace_col_normalize_sparse(&mut ema_bonds, n); // sum_i b_ij = 1 - log::trace!("Exponential Moving Average Bonds: {:?}", &ema_bonds); + // log::trace!( "emaB: {:?}", &ema_bonds ); // Compute dividends: d_i = SUM(j) b_ij * inc_j. // range: I32F32(0, 1) let mut dividends: Vec = matmul_transpose_sparse(&ema_bonds, &incentive); inplace_normalize(&mut dividends); - log::trace!("Dividends: {:?}", ÷nds); + log::trace!("D: {:?}", ÷nds); // ================================= // == Emission and Pruning scores == @@ -607,25 +616,16 @@ impl Pallet { .map(|e: &I96F32| e.to_num::()) .collect(); - log::trace!( - "Normalized Server Emission: {:?}", - &normalized_server_emission - ); - log::trace!("Server Emission: {:?}", &server_emission); - log::trace!( - "Normalized Validator Emission: {:?}", - &normalized_validator_emission - ); - log::trace!("Validator Emission: {:?}", &validator_emission); - log::trace!( - "Normalized Combined Emission: {:?}", - &normalized_combined_emission - ); - log::trace!("Combined Emission: {:?}", &combined_emission); + log::trace!("nSE: {:?}", &normalized_server_emission); + log::trace!("SE: {:?}", &server_emission); + log::trace!("nVE: {:?}", &normalized_validator_emission); + log::trace!("VE: {:?}", &validator_emission); + log::trace!("nCE: {:?}", &normalized_combined_emission); + log::trace!("CE: {:?}", &combined_emission); // Set pruning scores using combined emission scores. let pruning_scores: Vec = normalized_combined_emission.clone(); - log::trace!("Pruning Scores: {:?}", &pruning_scores); + log::trace!("P: {:?}", &pruning_scores); // =================== // == Value storage == @@ -813,413 +813,4 @@ impl Pallet { } bonds } - - /// Calculate the logistic function parameters 'a' and 'b' based on alpha and consensus values. - /// - /// # Args: - /// * `alpha_high` - The high alpha value. - /// * `alpha_low` - The low alpha value. - /// * `consensus_high` - The high consensus value. - /// * `consensus_low` - The low consensus value. - /// - /// # Returns: - /// A tuple containing the slope 'a' and intercept 'b' for the logistic function. - pub fn calculate_logistic_params( - alpha_high: I32F32, - alpha_low: I32F32, - consensus_high: I32F32, - consensus_low: I32F32, - ) -> (I32F32, I32F32) { - log::trace!("alpha_high: {:?}", alpha_high); - log::trace!("alpha_low: {:?}", alpha_low); - log::trace!("consensus_high: {:?}", consensus_high); - log::trace!("consensus_low: {:?}", consensus_low); - // Check for division by zero - // extra caution to ensure we never divide by zero - if consensus_high <= consensus_low || alpha_low == 0 || alpha_high == 0 { - // Return 0 for both 'a' and 'b' when consensus values are equal - return (I32F32::from_num(0.0), I32F32::from_num(0.0)); - } - - // Calculate the slope 'a' of the logistic function. - // a = (ln((1 / alpha_high - 1)) - ln((1 / alpha_low - 1))) / (consensus_low - consensus_high) - let a = (safe_ln( - (I32F32::from_num(1.0).saturating_div(alpha_high)) - .saturating_sub(I32F32::from_num(1.0)), - ) - .saturating_sub(safe_ln( - (I32F32::from_num(1.0).saturating_div(alpha_low)).saturating_sub(I32F32::from_num(1.0)), - ))) - .saturating_div(consensus_low.saturating_sub(consensus_high)); - log::trace!("a: {:?}", a); - - // Calculate the intercept 'b' of the logistic function. - // b = ln((1 / alpha_low - 1)) + a * consensus_low - let b = safe_ln( - (I32F32::from_num(1.0).saturating_div(alpha_low)).saturating_sub(I32F32::from_num(1.0)), - ) - .saturating_add(a.saturating_mul(consensus_low)); - log::trace!("b: {:?}", b); - - // Return the calculated slope 'a' and intercept 'b'. - (a, b) - } - - /// Compute the alpha values using the logistic function parameters 'a' and 'b'. - /// - /// # Args: - /// * `consensus` - A vector of consensus values. - /// * `a` - The slope of the logistic function. - /// * `b` - The intercept of the logistic function. - /// - /// # Returns: - /// A vector of computed alpha values. - pub fn compute_alpha_values(consensus: &[I32F32], a: I32F32, b: I32F32) -> Vec { - // Compute the alpha values for each consensus value. - let alpha: Vec = consensus - .iter() - .map(|c| { - // Calculate the exponent value for the logistic function. - // exp_val = exp(b - a * c) - let exp_val = safe_exp(b.saturating_sub(a.saturating_mul(*c))); - - // Compute the alpha value using the logistic function formula. - // alpha = 1 / (1 + exp_val) - I32F32::from_num(1.0).saturating_div(I32F32::from_num(1.0).saturating_add(exp_val)) - }) - .collect(); - - // Log the computed alpha values for debugging purposes. - log::trace!("alpha: {:?}", alpha); - - // Return the computed alpha values. - alpha - } - - /// Clamp the alpha values between alpha_high and alpha_low. - /// - /// # Args: - /// * `alpha` - A vector of alpha values. - /// * `alpha_high` - The high alpha value. - /// * `alpha_low` - The low alpha value. - /// - /// # Returns: - /// A vector of clamped alpha values. - pub fn clamp_alpha_values( - alpha: Vec, - alpha_high: I32F32, - alpha_low: I32F32, - ) -> Vec { - let clamped_alpha: Vec = alpha - .iter() - .map(|a| { - // First, clamp the value to ensure it does not exceed the upper bound (alpha_high). - // If 'a' is greater than 'alpha_high', it will be set to 'alpha_high'. - // If 'a' is less than or equal to 'alpha_high', it remains unchanged. - let clamped_a = a - .min(&alpha_high) - // Next, clamp the value to ensure it does not go below the lower bound (alpha_low). - // If the value (after the first clamping) is less than 'alpha_low', it will be set to 'alpha_low'. - // If the value is greater than or equal to 'alpha_low', it remains unchanged. - .max(&alpha_low); - // Return the clamped value. - *clamped_a - }) - .collect(); - log::trace!("alpha_clamped: {:?}", clamped_alpha); - clamped_alpha - } - - /// Compute the Exponential Moving Average (EMA) of bonds using the clamped alpha values for a sparse matrix. - /// - /// # Args: - /// * `bonds_delta` - A vector of bond deltas. - /// * `bonds` - A vector of bonds. - /// * `alpha` - A vector of clamped alpha values. - /// - /// # Returns: - /// A vector of EMA bonds. - pub fn compute_ema_bonds_with_liquid_alpha_sparse( - bonds_delta: &[Vec<(u16, I32F32)>], - bonds: &[Vec<(u16, I32F32)>], - alpha: Vec, - ) -> Vec> { - // Compute the Exponential Moving Average (EMA) of bonds using the provided clamped alpha values. - let ema_bonds = mat_ema_alpha_vec_sparse(bonds_delta, bonds, &alpha); - - // Log the computed EMA bonds for debugging purposes. - log::trace!( - "Exponential Moving Average Bonds Liquid Alpha: {:?}", - ema_bonds - ); - - // Return the computed EMA bonds. - ema_bonds - } - - /// Compute the Exponential Moving Average (EMA) of bonds using the clamped alpha values. - /// - /// # Args: - /// * `bonds_delta` - A vector of bond deltas. - /// * `bonds` - A vector of bonds. - /// * `alpha` - A vector of clamped alpha values. - /// - /// # Returns: - /// A vector of EMA bonds. - pub fn compute_ema_bonds_with_liquid_alpha( - bonds_delta: &[Vec], - bonds: &[Vec], - alpha: Vec, - ) -> Vec> { - // Compute the Exponential Moving Average (EMA) of bonds using the provided clamped alpha values. - let ema_bonds = mat_ema_alpha_vec(bonds_delta, bonds, &alpha); - - // Log the computed EMA bonds for debugging purposes. - log::trace!( - "Exponential Moving Average Bonds Liquid Alpha: {:?}", - ema_bonds - ); - - // Return the computed EMA bonds. - ema_bonds - } - - /// Compute the Exponential Moving Average (EMA) of bonds using a normal alpha value for a sparse matrix. - /// - /// # Args: - /// * `bonds_delta` - A vector of bond deltas. - /// * `bonds` - A vector of bonds. - /// * `netuid` - The network ID. - /// - /// # Returns: - /// A vector of EMA bonds. - pub fn compute_ema_bonds_normal_sparse( - bonds_delta: &[Vec<(u16, I32F32)>], - bonds: &[Vec<(u16, I32F32)>], - netuid: u16, - ) -> Vec> { - // Retrieve the bonds moving average for the given network ID and scale it down. - let bonds_moving_average: I64F64 = I64F64::from_num(Self::get_bonds_moving_average(netuid)) - .saturating_div(I64F64::from_num(1_000_000)); - - // Calculate the alpha value for the EMA calculation. - // Alpha is derived by subtracting the scaled bonds moving average from 1. - let alpha: I32F32 = - I32F32::from_num(1).saturating_sub(I32F32::from_num(bonds_moving_average)); - - // Compute the Exponential Moving Average (EMA) of bonds using the calculated alpha value. - let ema_bonds = mat_ema_sparse(bonds_delta, bonds, alpha); - - // Log the computed EMA bonds for debugging purposes. - log::trace!("Exponential Moving Average Bonds Normal: {:?}", ema_bonds); - - // Return the computed EMA bonds. - ema_bonds - } - - /// Compute the Exponential Moving Average (EMA) of bonds using a normal alpha value. - /// - /// # Args: - /// * `bonds_delta` - A vector of bond deltas. - /// * `bonds` - A vector of bonds. - /// * `netuid` - The network ID. - /// - /// # Returns: - /// A vector of EMA bonds. - pub fn compute_ema_bonds_normal( - bonds_delta: &[Vec], - bonds: &[Vec], - netuid: u16, - ) -> Vec> { - // Retrieve the bonds moving average for the given network ID and scale it down. - let bonds_moving_average: I64F64 = I64F64::from_num(Self::get_bonds_moving_average(netuid)) - .saturating_div(I64F64::from_num(1_000_000)); - - // Calculate the alpha value for the EMA calculation. - // Alpha is derived by subtracting the scaled bonds moving average from 1. - let alpha: I32F32 = - I32F32::from_num(1).saturating_sub(I32F32::from_num(bonds_moving_average)); - - // Compute the Exponential Moving Average (EMA) of bonds using the calculated alpha value. - let ema_bonds = mat_ema(bonds_delta, bonds, alpha); - - // Log the computed EMA bonds for debugging purposes. - log::trace!("Exponential Moving Average Bonds Normal: {:?}", ema_bonds); - - // Return the computed EMA bonds. - ema_bonds - } - - /// Compute the Exponential Moving Average (EMA) of bonds based on the Liquid Alpha setting for a sparse matrix. - /// - /// # Args: - /// * `netuid` - The network ID. - /// * `consensus` - A vector of consensus values. - /// * `bonds_delta` - A vector of bond deltas. - /// * `bonds` - A vector of bonds. - /// - /// # Returns: - /// A vector of EMA bonds. - pub fn compute_ema_bonds_sparse( - netuid: u16, - consensus: Vec, - bonds_delta: Vec>, - bonds: Vec>, - ) -> Vec> { - // Check if Liquid Alpha is enabled, consensus is not empty, and contains non-zero values. - // This way we avoid the quantil function panic. - if LiquidAlphaOn::::get(netuid) - && !consensus.is_empty() - && consensus.iter().any(|&c| c != I32F32::from_num(0)) - { - // Calculate the 75th percentile (high) and 25th percentile (low) of the consensus values. - let consensus_high = quantile(&consensus, 0.75); - let consensus_low = quantile(&consensus, 0.25); - // Further check if the high and low consensus values meet the required conditions. - if (consensus_high > consensus_low) || consensus_high != 0 || consensus_low < 0 { - // if (consensus_high > consensus_low) || consensus_high != 0) || consensus_low != 0 { - // if (consensus_high > consensus_low) || consensus_low != 0 { - log::trace!("Using Liquid Alpha"); - - // Get the high and low alpha values for the network. - let (alpha_low, alpha_high): (I32F32, I32F32) = Self::get_alpha_values_32(netuid); - log::trace!("alpha_low: {:?} alpha_high: {:?}", alpha_low, alpha_high); - - // Calculate the logistic function parameters 'a' and 'b' based on alpha and consensus values. - let (a, b) = Self::calculate_logistic_params( - alpha_high, - alpha_low, - consensus_high, - consensus_low, - ); - - // Compute the alpha values using the logistic function parameters. - let alpha = Self::compute_alpha_values(&consensus, a, b); - - // Clamp the alpha values between alpha_high and alpha_low. - let clamped_alpha = Self::clamp_alpha_values(alpha, alpha_high, alpha_low); - - // Compute the Exponential Moving Average (EMA) of bonds using the clamped alpha values. - Self::compute_ema_bonds_with_liquid_alpha_sparse( - &bonds_delta, - &bonds, - clamped_alpha, - ) - } else { - log::trace!("Using Bonds Moving Average"); - - // Compute the EMA of bonds using a normal alpha value. - Self::compute_ema_bonds_normal_sparse(&bonds_delta, &bonds, netuid) - } - } else { - log::trace!("Using Bonds Moving Average"); - - // Compute the EMA of bonds using a normal alpha value. - Self::compute_ema_bonds_normal_sparse(&bonds_delta, &bonds, netuid) - } - } - - /// Compute the Exponential Moving Average (EMA) of bonds based on the Liquid Alpha setting. - /// - /// # Args: - /// * `netuid` - The network ID. - /// * `consensus` - A vector of consensus values. - /// * `bonds_delta` - A vector of bond deltas. - /// * `bonds` - A vector of bonds. - /// - /// # Returns: - /// A vector of EMA bonds. - pub fn compute_ema_bonds( - netuid: u16, - consensus: Vec, - bonds_delta: Vec>, - bonds: Vec>, - ) -> Vec> { - // Check if Liquid Alpha is enabled, consensus is not empty, and contains non-zero values. - if LiquidAlphaOn::::get(netuid) - && !consensus.is_empty() - && consensus.iter().any(|&c| c != I32F32::from_num(0)) - { - // Calculate the 75th percentile (high) and 25th percentile (low) of the consensus values. - let consensus_high = quantile(&consensus, 0.75); - let consensus_low = quantile(&consensus, 0.25); - - // Further check if the high and low consensus values meet the required conditions. - if (consensus_high > consensus_low) || consensus_high != 0 || consensus_low < 0 { - log::trace!("Using Liquid Alpha"); - - // Get the high and low alpha values for the network. - let (alpha_low, alpha_high): (I32F32, I32F32) = Self::get_alpha_values_32(netuid); - log::trace!("alpha_low: {:?} alpha_high: {:?}", alpha_low, alpha_high); - - // Calculate the logistic function parameters 'a' and 'b' based on alpha and consensus values. - let (a, b) = Self::calculate_logistic_params( - alpha_high, - alpha_low, - consensus_high, - consensus_low, - ); - - // Compute the alpha values using the logistic function parameters. - let alpha = Self::compute_alpha_values(&consensus, a, b); - - // Clamp the alpha values between alpha_high and alpha_low. - let clamped_alpha = Self::clamp_alpha_values(alpha, alpha_high, alpha_low); - - // Compute the Exponential Moving Average (EMA) of bonds using the clamped alpha values. - Self::compute_ema_bonds_with_liquid_alpha(&bonds_delta, &bonds, clamped_alpha) - } else { - log::trace!("Using Bonds Moving Average"); - - // Compute the EMA of bonds using a normal alpha value. - Self::compute_ema_bonds_normal(&bonds_delta, &bonds, netuid) - } - } else { - log::trace!("Using Bonds Moving Average"); - - // Compute the EMA of bonds using a normal alpha value. - Self::compute_ema_bonds_normal(&bonds_delta, &bonds, netuid) - } - } - - pub fn do_set_alpha_values( - origin: T::RuntimeOrigin, - netuid: u16, - alpha_low: u16, - alpha_high: u16, - ) -> Result<(), DispatchError> { - // --- 1. Ensure the function caller is a signed user. - ensure_signed(origin.clone())?; - - // --- 2. Ensure the function caller is the subnet owner or root. - Self::ensure_subnet_owner_or_root(origin, netuid)?; - - // --- 3. Ensure liquid alpha is enabled - ensure!( - Self::get_liquid_alpha_enabled(netuid), - Error::::LiquidAlphaDisabled - ); - - let max_u16: u32 = u16::MAX as u32; // 65535 - let min_alpha_high: u16 = (max_u16.saturating_mul(4).saturating_div(5)) as u16; // 52428 - - // --- 4. Ensure alpha high is greater than the minimum - ensure!(alpha_high >= min_alpha_high, Error::::AlphaHighTooLow); - - // -- 5. Ensure alpha low is within range - ensure!( - alpha_low > 0 && alpha_low < min_alpha_high, - Error::::AlphaLowOutOfRange - ); - - AlphaValues::::insert(netuid, (alpha_low, alpha_high)); - - log::info!( - "AlphaValuesSet( netuid: {:?}, AlphaLow: {:?}, AlphaHigh: {:?} ) ", - netuid, - alpha_low, - alpha_high, - ); - Ok(()) - } } diff --git a/pallets/subtensor/src/errors.rs b/pallets/subtensor/src/errors.rs index 95adae4b4..5ea6ccf2f 100644 --- a/pallets/subtensor/src/errors.rs +++ b/pallets/subtensor/src/errors.rs @@ -126,12 +126,6 @@ mod errors { CommitRevealEnabled, /// Attemtping to commit/reveal weights when disabled. CommitRevealDisabled, - /// Attempting to set alpha high/low while disabled - LiquidAlphaDisabled, - /// Alpha high is too low: alpha_high > 0.8 - AlphaHighTooLow, - /// Alpha low is out of range: alpha_low > 0 && alpha_low < 0.8 - AlphaLowOutOfRange, /// Not able to join the senate. CouldNotJoinSenate, } diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index b746c5604..8c0efc7fe 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -38,7 +38,7 @@ mod block_step; mod epoch; mod errors; mod events; -pub mod math; +mod math; mod registration; mod root; mod serving; @@ -244,16 +244,6 @@ pub mod pallet { /// Cost of swapping a hotkey. #[pallet::constant] type HotkeySwapCost: Get; - /// The upper bound for the alpha parameter. Used for Liquid Alpha. - #[pallet::constant] - type AlphaHigh: Get; - /// The lower bound for the alpha parameter. Used for Liquid Alpha. - #[pallet::constant] - type AlphaLow: Get; - /// A flag to indicate if Liquid Alpha is enabled. - #[pallet::constant] - type LiquidAlphaOn: Get; - } /// Alias for the account ID. @@ -380,14 +370,6 @@ pub mod pallet { ValueQuery, DefaultAccountTake, >; - /// -- ITEM (switches liquid alpha on) - #[pallet::type_value] - pub fn DefaultLiquidAlpha() -> bool { - false - } - #[pallet::storage] // --- MAP ( netuid ) --> Whether or not Liquid Alpha is enabled - pub type LiquidAlphaOn = - StorageMap<_, Blake2_128Concat, u16, bool, ValueQuery, DefaultLiquidAlpha>; /// ===================================== /// ==== Difficulty / Registrations ===== @@ -872,12 +854,6 @@ pub mod pallet { pub fn DefaultWeightsMinStake() -> u64 { 0 } - /// Provides the default value for the upper bound of the alpha parameter. - - #[pallet::type_value] - pub fn DefaultAlphaValues() -> (u16, u16) { - (45875, 58982) // (alpha_low: 0.7, alpha_high: 0.9) - } #[pallet::storage] // ITEM( weights_min_stake ) pub type WeightsMinStake = StorageValue<_, u64, ValueQuery, DefaultWeightsMinStake>; @@ -949,11 +925,6 @@ pub mod pallet { pub type AdjustmentAlpha = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultAdjustmentAlpha>; - // MAP ( netuid ) --> (alpha_low, alpha_high) - #[pallet::storage] - pub type AlphaValues = - StorageMap<_, Identity, u16, (u16, u16), ValueQuery, DefaultAlphaValues>; - #[pallet::storage] // --- MAP (netuid, who) --> (hash, weight) | Returns the hash and weight committed by an account for a given netuid. pub type WeightCommits = StorageDoubleMap< _, diff --git a/pallets/subtensor/src/math.rs b/pallets/subtensor/src/math.rs index 8b6e76f2c..40ee7ebe8 100644 --- a/pallets/subtensor/src/math.rs +++ b/pallets/subtensor/src/math.rs @@ -1,12 +1,6 @@ -// we get a compiler warning for this , even though the trait is used in the -// quantile function. -use crate::alloc::borrow::ToOwned; -#[allow(unused)] -use num_traits::float::Float; -use sp_runtime::traits::{CheckedAdd, Saturating}; -use sp_std::cmp::Ordering; +use sp_runtime::{traits::CheckedAdd, Saturating}; use sp_std::vec; -use substrate_fixed::transcendental::{exp, ln}; +use substrate_fixed::transcendental::exp; use substrate_fixed::types::{I32F32, I64F64}; // TODO: figure out what cfg gate this needs to not be a warning in rustc @@ -187,8 +181,8 @@ pub fn is_zero(vector: &[I32F32]) -> bool { // Exp safe function with I32F32 output of I32F32 input. #[allow(dead_code)] pub fn exp_safe(input: I32F32) -> I32F32 { - let min_input: I32F32 = I32F32::from_num(-20); // <= 1/exp(-20) = 485 165 195,4097903 - let max_input: I32F32 = I32F32::from_num(20); // <= exp(20) = 485 165 195,4097903 + let min_input: I32F32 = I32F32::from_num(-20); // <= 1/exp(-20) = 485 165 195,4097903 + let max_input: I32F32 = I32F32::from_num(20); // <= exp(20) = 485 165 195,4097903 let mut safe_input: I32F32 = input; if input < min_input { safe_input = min_input; @@ -1148,183 +1142,2150 @@ pub fn sparse_threshold(w: &[Vec<(u16, I32F32)>], threshold: I32F32) -> Vec], - old: &[Vec<(u16, I32F32)>], - alpha: &[I32F32], -) -> Vec> { - // Ensure the new and old matrices have the same number of rows. - assert!(new.len() == old.len()); - let n = new.len(); // Assume square matrix, rows=cols - let zero: I32F32 = I32F32::from_num(0.0); - let mut result: Vec> = vec![vec![]; n]; +#[cfg(test)] +#[allow( + clippy::indexing_slicing, + clippy::arithmetic_side_effects, + clippy::unwrap_used +)] +mod tests { + use crate::math::*; + use rand::{seq::SliceRandom, thread_rng, Rng}; + use substrate_fixed::types::{I110F18, I96F32}; - // Iterate over each row of the matrices. - for (i, (new_row, old_row)) in new.iter().zip(old).enumerate() { - // Initialize a row of zeros for the result matrix. - let mut row: Vec = vec![zero; n]; + fn assert_float_compare(a: I32F32, b: I32F32, epsilon: I32F32) { + assert!(I32F32::abs(a - b) <= epsilon, "a({:?}) != b({:?})", a, b); + } + + fn assert_float_compare_64(a: I64F64, b: I64F64, epsilon: I64F64) { + assert!(I64F64::abs(a - b) <= epsilon, "a({:?}) != b({:?})", a, b); + } + + fn assert_vec_compare(va: &[I32F32], vb: &[I32F32], epsilon: I32F32) { + assert!(va.len() == vb.len()); + for i in 0..va.len() { + assert_float_compare(va[i], vb[i], epsilon); + } + } + + fn assert_vec_compare_64(va: &[I64F64], vb: &[I64F64], epsilon: I64F64) { + assert!(va.len() == vb.len()); + for i in 0..va.len() { + assert_float_compare_64(va[i], vb[i], epsilon); + } + } - // Process the new matrix values. - for (j, value) in new_row.iter() { - // Retrieve the alpha value for the current column. - let alpha_val: I32F32 = alpha.get(*j as usize).copied().unwrap_or(zero); - // Compute the EMA component for the new value using saturating multiplication. - if let Some(row_val) = row.get_mut(*j as usize) { - *row_val = alpha_val.saturating_mul(*value); + fn assert_vec_compare_u16(va: &[u16], vb: &[u16]) { + assert!(va.len() == vb.len()); + for i in 0..va.len() { + assert_eq!(va[i], vb[i]); + } + } + + fn assert_mat_compare(ma: &[Vec], mb: &[Vec], epsilon: I32F32) { + assert!(ma.len() == mb.len()); + for row in 0..ma.len() { + assert!(ma[row].len() == mb[row].len()); + for col in 0..ma[row].len() { + assert_float_compare(ma[row][col], mb[row][col], epsilon) } - log::trace!( - "new[{}][{}] * alpha[{}] = {} * {} = {}", - i, - j, - j, - value, - alpha_val, - row.get(*j as usize).unwrap_or(&zero) - ); } + } - // Process the old matrix values. - for (j, value) in old_row.iter() { - // Retrieve the alpha value for the current column. - let alpha_val: I32F32 = alpha.get(*j as usize).copied().unwrap_or(zero); - // Calculate the complement of the alpha value using saturating subtraction. - let one_minus_alpha: I32F32 = I32F32::from_num(1.0).saturating_sub(alpha_val); - // Compute the EMA component for the old value and add it to the row using saturating operations. - if let Some(row_val) = row.get_mut(*j as usize) { - *row_val = row_val.saturating_add(one_minus_alpha.saturating_mul(*value)); + fn assert_sparse_mat_compare( + ma: &[Vec<(u16, I32F32)>], + mb: &[Vec<(u16, I32F32)>], + epsilon: I32F32, + ) { + assert!(ma.len() == mb.len()); + for row in 0..ma.len() { + assert!(ma[row].len() == mb[row].len()); + for j in 0..ma[row].len() { + assert!(ma[row][j].0 == mb[row][j].0); // u16 + assert_float_compare(ma[row][j].1, mb[row][j].1, epsilon) // I32F32 } - log::trace!( - "old[{}][{}] * (1 - alpha[{}]) = {} * {} = {}", - i, - j, - j, - value, - one_minus_alpha, - one_minus_alpha.saturating_mul(*value) - ); } + } - // Collect the non-zero values into the result matrix. - for (j, value) in row.iter().enumerate() { - if *value > zero { - if let Some(result_row) = result.get_mut(i) { - result_row.push((j as u16, *value)); - log::trace!("result[{}][{}] = {}", i, j, value); + fn vec_to_fixed(vector: &[f32]) -> Vec { + vector.iter().map(|x| I32F32::from_num(*x)).collect() + } + + #[test] + fn test_vec_max_upscale_to_u16() { + let vector: Vec = vec_to_fixed(&[]); + let target: Vec = vec![]; + let result: Vec = vec_max_upscale_to_u16(&vector); + assert_vec_compare_u16(&result, &target); + let vector: Vec = vec_to_fixed(&[0.]); + let target: Vec = vec![0]; + let result: Vec = vec_max_upscale_to_u16(&vector); + assert_vec_compare_u16(&result, &target); + let vector: Vec = vec_to_fixed(&[0., 0.]); + let target: Vec = vec![0, 0]; + let result: Vec = vec_max_upscale_to_u16(&vector); + assert_vec_compare_u16(&result, &target); + let vector: Vec = vec_to_fixed(&[0., 1.]); + let target: Vec = vec![0, 65535]; + let result: Vec = vec_max_upscale_to_u16(&vector); + assert_vec_compare_u16(&result, &target); + let vector: Vec = vec_to_fixed(&[0., 0.000000001]); + let target: Vec = vec![0, 65535]; + let result: Vec = vec_max_upscale_to_u16(&vector); + assert_vec_compare_u16(&result, &target); + let vector: Vec = vec_to_fixed(&[0., 0.000016, 1.]); + let target: Vec = vec![0, 1, 65535]; + let result: Vec = vec_max_upscale_to_u16(&vector); + assert_vec_compare_u16(&result, &target); + let vector: Vec = vec_to_fixed(&[0.000000001, 0.000000001]); + let target: Vec = vec![65535, 65535]; + let result: Vec = vec_max_upscale_to_u16(&vector); + assert_vec_compare_u16(&result, &target); + let vector: Vec = vec_to_fixed(&[ + 0.000001, 0.000006, 0.000007, 0.0001, 0.001, 0.01, 0.1, 0.2, 0.3, 0.4, + ]); + let target: Vec = vec![0, 1, 1, 16, 164, 1638, 16384, 32768, 49151, 65535]; + let result: Vec = vec_max_upscale_to_u16(&vector); + assert_vec_compare_u16(&result, &target); + let vector: Vec = vec![I32F32::from_num(16384)]; + let target: Vec = vec![65535]; + let result: Vec = vec_max_upscale_to_u16(&vector); + assert_vec_compare_u16(&result, &target); + let vector: Vec = vec![I32F32::from_num(32768)]; + let target: Vec = vec![65535]; + let result: Vec = vec_max_upscale_to_u16(&vector); + assert_vec_compare_u16(&result, &target); + let vector: Vec = vec![I32F32::from_num(32769)]; + let target: Vec = vec![65535]; + let result: Vec = vec_max_upscale_to_u16(&vector); + assert_vec_compare_u16(&result, &target); + let vector: Vec = vec![I32F32::from_num(65535)]; + let target: Vec = vec![65535]; + let result: Vec = vec_max_upscale_to_u16(&vector); + assert_vec_compare_u16(&result, &target); + let vector: Vec = vec![I32F32::max_value()]; + let target: Vec = vec![65535]; + let result: Vec = vec_max_upscale_to_u16(&vector); + assert_vec_compare_u16(&result, &target); + let vector: Vec = vec_to_fixed(&[0., 1., 65535.]); + let target: Vec = vec![0, 1, 65535]; + let result: Vec = vec_max_upscale_to_u16(&vector); + assert_vec_compare_u16(&result, &target); + let vector: Vec = vec_to_fixed(&[0., 0.5, 1., 1.5, 2., 32768.]); + let target: Vec = vec![0, 1, 2, 3, 4, 65535]; + let result: Vec = vec_max_upscale_to_u16(&vector); + assert_vec_compare_u16(&result, &target); + let vector: Vec = vec_to_fixed(&[0., 0.5, 1., 1.5, 2., 32768., 32769.]); + let target: Vec = vec![0, 1, 2, 3, 4, 65533, 65535]; + let result: Vec = vec_max_upscale_to_u16(&vector); + assert_vec_compare_u16(&result, &target); + let vector: Vec = vec![ + I32F32::from_num(0), + I32F32::from_num(1), + I32F32::from_num(32768), + I32F32::from_num(32769), + I32F32::max_value(), + ]; + let target: Vec = vec![0, 0, 1, 1, 65535]; + let result: Vec = vec_max_upscale_to_u16(&vector); + assert_vec_compare_u16(&result, &target); + } + + #[test] + fn test_vec_u16_max_upscale_to_u16() { + let vector: Vec = vec![]; + let result: Vec = vec_u16_max_upscale_to_u16(&vector); + assert_vec_compare_u16(&result, &vector); + let vector: Vec = vec![0]; + let result: Vec = vec_u16_max_upscale_to_u16(&vector); + assert_vec_compare_u16(&result, &vector); + let vector: Vec = vec![0, 0]; + let result: Vec = vec_u16_max_upscale_to_u16(&vector); + assert_vec_compare_u16(&result, &vector); + let vector: Vec = vec![1]; + let target: Vec = vec![65535]; + let result: Vec = vec_u16_max_upscale_to_u16(&vector); + assert_vec_compare_u16(&result, &target); + let vector: Vec = vec![0, 1]; + let target: Vec = vec![0, 65535]; + let result: Vec = vec_u16_max_upscale_to_u16(&vector); + assert_vec_compare_u16(&result, &target); + let vector: Vec = vec![65534]; + let target: Vec = vec![65535]; + let result: Vec = vec_u16_max_upscale_to_u16(&vector); + assert_vec_compare_u16(&result, &target); + let vector: Vec = vec![65535]; + let target: Vec = vec![65535]; + let result: Vec = vec_u16_max_upscale_to_u16(&vector); + assert_vec_compare_u16(&result, &target); + let vector: Vec = vec![65535, 65535]; + let target: Vec = vec![65535, 65535]; + let result: Vec = vec_u16_max_upscale_to_u16(&vector); + assert_vec_compare_u16(&result, &target); + let vector: Vec = vec![0, 1, 65534]; + let target: Vec = vec![0, 1, 65535]; + let result: Vec = vec_u16_max_upscale_to_u16(&vector); + assert_vec_compare_u16(&result, &target); + let vector: Vec = vec![0, 1, 2, 3, 4, 65533, 65535]; + let result: Vec = vec_u16_max_upscale_to_u16(&vector); + assert_vec_compare_u16(&result, &vector); + } + + #[test] + fn test_check_vec_max_limited() { + let vector: Vec = vec![]; + let max_limit: u16 = 0; + assert!(check_vec_max_limited(&vector, max_limit)); + let vector: Vec = vec![]; + let max_limit: u16 = u16::MAX; + assert!(check_vec_max_limited(&vector, max_limit)); + let vector: Vec = vec![u16::MAX]; + let max_limit: u16 = u16::MAX; + assert!(check_vec_max_limited(&vector, max_limit)); + let vector: Vec = vec![u16::MAX]; + let max_limit: u16 = u16::MAX - 1; + assert!(!check_vec_max_limited(&vector, max_limit)); + let vector: Vec = vec![u16::MAX]; + let max_limit: u16 = 0; + assert!(!check_vec_max_limited(&vector, max_limit)); + let vector: Vec = vec![0]; + let max_limit: u16 = u16::MAX; + assert!(check_vec_max_limited(&vector, max_limit)); + let vector: Vec = vec![0, u16::MAX]; + let max_limit: u16 = u16::MAX; + assert!(check_vec_max_limited(&vector, max_limit)); + let vector: Vec = vec![0, u16::MAX, u16::MAX]; + let max_limit: u16 = u16::MAX / 2; + assert!(!check_vec_max_limited(&vector, max_limit)); + let vector: Vec = vec![0, u16::MAX, u16::MAX]; + let max_limit: u16 = u16::MAX / 2 + 1; + assert!(check_vec_max_limited(&vector, max_limit)); + let vector: Vec = vec![0, u16::MAX, u16::MAX, u16::MAX]; + let max_limit: u16 = u16::MAX / 3 - 1; + assert!(!check_vec_max_limited(&vector, max_limit)); + let vector: Vec = vec![0, u16::MAX, u16::MAX, u16::MAX]; + let max_limit: u16 = u16::MAX / 3; + assert!(check_vec_max_limited(&vector, max_limit)); + } + + #[test] + fn test_math_fixed_overflow() { + let max_32: I32F32 = I32F32::max_value(); + let max_u64: u64 = u64::MAX; + let _prod_96: I96F32 = I96F32::from_num(max_32) * I96F32::from_num(max_u64); + // let one: I96F32 = I96F32::from_num(1); + // let prod_96: I96F32 = (I96F32::from_num(max_32) + one) * I96F32::from_num(max_u64); // overflows + let _prod_110: I110F18 = I110F18::from_num(max_32) * I110F18::from_num(max_u64); + + let bonds_moving_average_val: u64 = 900_000_u64; + let bonds_moving_average: I64F64 = + I64F64::from_num(bonds_moving_average_val) / I64F64::from_num(1_000_000); + let alpha: I32F32 = I32F32::from_num(1) - I32F32::from_num(bonds_moving_average); + assert_eq!(I32F32::from_num(0.1), alpha); + + let bonds_moving_average: I64F64 = I64F64::from_num(max_32) / I64F64::from_num(max_32); + let alpha: I32F32 = I32F32::from_num(1) - I32F32::from_num(bonds_moving_average); + assert_eq!(I32F32::from_num(0), alpha); + } + + #[test] + fn test_math_u64_normalization() { + let min: u64 = 1; + let min32: u64 = 4_889_444; // 21_000_000_000_000_000 / 4_294_967_296 + let mid: u64 = 10_500_000_000_000_000; + let max: u64 = 21_000_000_000_000_000; + let min_64: I64F64 = I64F64::from_num(min); + let min32_64: I64F64 = I64F64::from_num(min32); + let mid_64: I64F64 = I64F64::from_num(mid); + let max_64: I64F64 = I64F64::from_num(max); + let max_sum: I64F64 = I64F64::from_num(max); + let min_frac: I64F64 = min_64 / max_sum; + assert_eq!(min_frac, I64F64::from_num(0.0000000000000000476)); + let min_frac_32: I32F32 = I32F32::from_num(min_frac); + assert_eq!(min_frac_32, I32F32::from_num(0)); + let min32_frac: I64F64 = min32_64 / max_sum; + assert_eq!(min32_frac, I64F64::from_num(0.00000000023283066664)); + let min32_frac_32: I32F32 = I32F32::from_num(min32_frac); + assert_eq!(min32_frac_32, I32F32::from_num(0.0000000002)); + let half: I64F64 = mid_64 / max_sum; + assert_eq!(half, I64F64::from_num(0.5)); + let half_32: I32F32 = I32F32::from_num(half); + assert_eq!(half_32, I32F32::from_num(0.5)); + let one: I64F64 = max_64 / max_sum; + assert_eq!(one, I64F64::from_num(1)); + let one_32: I32F32 = I32F32::from_num(one); + assert_eq!(one_32, I32F32::from_num(1)); + } + + #[test] + fn test_math_to_num() { + let val: I32F32 = I32F32::from_num(u16::MAX); + let res: u16 = val.to_num::(); + assert_eq!(res, u16::MAX); + let vector: Vec = vec![val; 1000]; + let target: Vec = vec![u16::MAX; 1000]; + let output: Vec = vector.iter().map(|e: &I32F32| e.to_num::()).collect(); + assert_eq!(output, target); + let output: Vec = vector + .iter() + .map(|e: &I32F32| (*e).to_num::()) + .collect(); + assert_eq!(output, target); + let val: I32F32 = I32F32::max_value(); + let res: u64 = val.to_num::(); + let vector: Vec = vec![val; 1000]; + let target: Vec = vec![res; 1000]; + let output: Vec = vector.iter().map(|e: &I32F32| e.to_num::()).collect(); + assert_eq!(output, target); + let output: Vec = vector + .iter() + .map(|e: &I32F32| (*e).to_num::()) + .collect(); + assert_eq!(output, target); + let val: I32F32 = I32F32::from_num(0); + let res: u64 = val.to_num::(); + let vector: Vec = vec![val; 1000]; + let target: Vec = vec![res; 1000]; + let output: Vec = vector.iter().map(|e: &I32F32| e.to_num::()).collect(); + assert_eq!(output, target); + let output: Vec = vector + .iter() + .map(|e: &I32F32| (*e).to_num::()) + .collect(); + assert_eq!(output, target); + let val: I96F32 = I96F32::from_num(u64::MAX); + let res: u64 = val.to_num::(); + assert_eq!(res, u64::MAX); + let vector: Vec = vec![val; 1000]; + let target: Vec = vec![u64::MAX; 1000]; + let output: Vec = vector.iter().map(|e: &I96F32| e.to_num::()).collect(); + assert_eq!(output, target); + let output: Vec = vector + .iter() + .map(|e: &I96F32| (*e).to_num::()) + .collect(); + assert_eq!(output, target); + } + + #[test] + fn test_math_vec_to_fixed() { + let vector: Vec = vec![0., 1., 2., 3.]; + let target: Vec = vec![ + I32F32::from_num(0.), + I32F32::from_num(1.), + I32F32::from_num(2.), + I32F32::from_num(3.), + ]; + let result = vec_to_fixed(&vector); + assert_vec_compare(&result, &target, I32F32::from_num(0)); + } + + // Reshape vector to matrix with specified number of rows, cast to I32F32. + fn vec_to_mat_fixed(vector: &[f32], rows: usize, transpose: bool) -> Vec> { + assert!( + vector.len() % rows == 0, + "Vector of len {:?} cannot reshape to {rows} rows.", + vector.len() + ); + let cols: usize = vector.len() / rows; + let mut mat: Vec> = vec![]; + if transpose { + for col in 0..cols { + let mut vals: Vec = vec![]; + for row in 0..rows { + vals.push(I32F32::from_num(vector[row * cols + col])); } + mat.push(vals); + } + } else { + for row in 0..rows { + mat.push( + vector[row * cols..(row + 1) * cols] + .iter() + .map(|v| I32F32::from_num(*v)) + .collect(), + ); } } + mat } - // Return the computed EMA sparse matrix. - result -} + #[test] + fn test_math_vec_to_mat_fixed() { + let vector: Vec = vec![0., 1., 2., 0., 10., 100.]; + let target: Vec> = vec![ + vec![ + I32F32::from_num(0.), + I32F32::from_num(1.), + I32F32::from_num(2.), + ], + vec![ + I32F32::from_num(0.), + I32F32::from_num(10.), + I32F32::from_num(100.), + ], + ]; + let mat = vec_to_mat_fixed(&vector, 2, false); + assert_mat_compare(&mat, &target, I32F32::from_num(0)); + } -/// Return matrix exponential moving average: `alpha_j * a_ij + one_minus_alpha_j * b_ij`. -/// `alpha_` is the EMA coefficient passed as a vector per column. -#[allow(dead_code)] -pub fn mat_ema_alpha_vec( - new: &[Vec], - old: &[Vec], - alpha: &[I32F32], -) -> Vec> { - // Check if the new matrix is empty or its first row is empty. - if new.is_empty() || new.first().map_or(true, |row| row.is_empty()) { - return vec![vec![]; 1]; + // Reshape vector to sparse matrix with specified number of input rows, cast f32 to I32F32. + fn vec_to_sparse_mat_fixed( + vector: &[f32], + rows: usize, + transpose: bool, + ) -> Vec> { + assert!( + vector.len() % rows == 0, + "Vector of len {:?} cannot reshape to {rows} rows.", + vector.len() + ); + let cols: usize = vector.len() / rows; + let mut mat: Vec> = vec![]; + if transpose { + for col in 0..cols { + let mut row_vec: Vec<(u16, I32F32)> = vec![]; + for row in 0..rows { + if vector[row * cols + col] > 0. { + row_vec.push((row as u16, I32F32::from_num(vector[row * cols + col]))); + } + } + mat.push(row_vec); + } + } else { + for row in 0..rows { + let mut row_vec: Vec<(u16, I32F32)> = vec![]; + for col in 0..cols { + if vector[row * cols + col] > 0. { + row_vec.push((col as u16, I32F32::from_num(vector[row * cols + col]))); + } + } + mat.push(row_vec); + } + } + mat } - // Ensure the dimensions of the new and old matrices match. - assert!(new.len() == old.len()); - assert!(new.first().map_or(0, |row| row.len()) == alpha.len()); - - // Initialize the result matrix with zeros, having the same dimensions as the new matrix. - let mut result: Vec> = - vec![vec![I32F32::from_num(0.0); new.first().map_or(0, |row| row.len())]; new.len()]; - - // Iterate over each row of the matrices. - for (i, (new_row, old_row)) in new.iter().zip(old).enumerate() { - // Ensure the current row of the new and old matrices have the same length. - assert!(new_row.len() == old_row.len()); - - // Iterate over each column of the current row. - for (j, &alpha_val) in alpha.iter().enumerate().take(new_row.len()) { - // Calculate the complement of the alpha value using saturating subtraction. - let one_minus_alpha = I32F32::from_num(1.0).saturating_sub(alpha_val); - - // Compute the EMA for the current element using saturating operations. - if let (Some(new_val), Some(old_val), Some(result_val)) = ( - new_row.get(j), - old_row.get(j), - result.get_mut(i).and_then(|row| row.get_mut(j)), - ) { - *result_val = alpha_val - .saturating_mul(*new_val) - .saturating_add(one_minus_alpha.saturating_mul(*old_val)); + #[test] + fn test_math_vec_to_sparse_mat_fixed() { + let vector: Vec = vec![0., 1., 2., 0., 10., 100.]; + let target: Vec> = vec![ + vec![(1_u16, I32F32::from_num(1.)), (2_u16, I32F32::from_num(2.))], + vec![ + (1_u16, I32F32::from_num(10.)), + (2_u16, I32F32::from_num(100.)), + ], + ]; + let mat = vec_to_sparse_mat_fixed(&vector, 2, false); + assert_sparse_mat_compare(&mat, &target, I32F32::from_num(0)); + let vector: Vec = vec![0., 0.]; + let target: Vec> = vec![vec![], vec![]]; + let mat = vec_to_sparse_mat_fixed(&vector, 2, false); + assert_sparse_mat_compare(&mat, &target, I32F32::from_num(0)); + let vector: Vec = vec![0., 1., 2., 0., 10., 100.]; + let target: Vec> = vec![ + vec![], + vec![ + (0_u16, I32F32::from_num(1.)), + (1_u16, I32F32::from_num(10.)), + ], + vec![ + (0_u16, I32F32::from_num(2.)), + (1_u16, I32F32::from_num(100.)), + ], + ]; + let mat = vec_to_sparse_mat_fixed(&vector, 2, true); + assert_sparse_mat_compare(&mat, &target, I32F32::from_num(0)); + let vector: Vec = vec![0., 0.]; + let target: Vec> = vec![vec![]]; + let mat = vec_to_sparse_mat_fixed(&vector, 2, true); + assert_sparse_mat_compare(&mat, &target, I32F32::from_num(0)); + } + + #[test] + fn test_math_exp_safe() { + let zero: I32F32 = I32F32::from_num(0); + let one: I32F32 = I32F32::from_num(1); + let target: I32F32 = exp(zero).unwrap(); + assert_eq!(exp_safe(zero), target); + let target: I32F32 = exp(one).unwrap(); + assert_eq!(exp_safe(one), target); + let min_input: I32F32 = I32F32::from_num(-20); // <= 1/exp(-20) = 485 165 195,4097903 + let max_input: I32F32 = I32F32::from_num(20); // <= exp(20) = 485 165 195,4097903 + let target: I32F32 = exp(min_input).unwrap(); + assert_eq!(exp_safe(min_input), target); + assert_eq!(exp_safe(min_input - one), target); + assert_eq!(exp_safe(I32F32::min_value()), target); + let target: I32F32 = exp(max_input).unwrap(); + assert_eq!(exp_safe(max_input), target); + assert_eq!(exp_safe(max_input + one), target); + assert_eq!(exp_safe(I32F32::max_value()), target); + } + + #[test] + fn test_math_sigmoid_safe() { + let trust: Vec = vec![ + I32F32::min_value(), + I32F32::from_num(0), + I32F32::from_num(0.4), + I32F32::from_num(0.5), + I32F32::from_num(0.6), + I32F32::from_num(1), + I32F32::max_value(), + ]; + let consensus: Vec = trust + .iter() + .map(|t: &I32F32| sigmoid_safe(*t, I32F32::max_value(), I32F32::max_value())) + .collect(); + let target: Vec = vec_to_fixed(&[ + 0.0000000019, + 0.0000000019, + 0.0000000019, + 0.0000000019, + 0.0000000019, + 0.0000000019, + 0.5, + ]); + assert_eq!(&consensus, &target); + let consensus: Vec = trust + .iter() + .map(|t: &I32F32| sigmoid_safe(*t, I32F32::min_value(), I32F32::min_value())) + .collect(); + let target: Vec = vec_to_fixed(&[ + 0.5, + 0.0000000019, + 0.0000000019, + 0.0000000019, + 0.0000000019, + 0.0000000019, + 0.0000000019, + ]); + assert_eq!(&consensus, &target); + let consensus: Vec = trust + .iter() + .map(|t: &I32F32| sigmoid_safe(*t, I32F32::from_num(30), I32F32::from_num(0.5))) + .collect(); + let target: Vec = vec![ + 0.0000000019, + 0.0000003057, + 0.0474258729, + 0.5, + 0.952574127, + 0.9999996943, + 0.9999999981, + ]; + let target: Vec = target.iter().map(|c: &f64| I32F32::from_num(*c)).collect(); + assert_eq!(&consensus, &target); + let trust: Vec = + vec_to_fixed(&[0., 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.]); + let consensus: Vec = trust + .iter() + .map(|t: &I32F32| sigmoid_safe(*t, I32F32::from_num(40), I32F32::from_num(0.5))) + .collect(); + let target: Vec = vec![ + 0.0000000019, + 0.0000001125, + 0.0000061442, + 0.0003353502, + 0.017986214, + 0.5, + 0.9820138067, + 0.9996646498, + 0.9999938558, + 0.9999998875, + 0.9999999981, + ]; + let target: Vec = target.iter().map(|c: &f64| I32F32::from_num(*c)).collect(); + assert_eq!(&consensus, &target); + } + + #[test] + fn test_math_is_topk() { + let vector: Vec = vec_to_fixed(&[]); + let result = is_topk(&vector, 5); + let target: Vec = vec![]; + assert_eq!(&result, &target); + let vector: Vec = vec_to_fixed(&[0., 1., 2., 3., 4., 5., 6., 7., 8., 9.]); + let result = is_topk(&vector, 0); + let target: Vec = vec![ + false, false, false, false, false, false, false, false, false, false, + ]; + assert_eq!(&result, &target); + let result = is_topk(&vector, 5); + let target: Vec = vec![ + false, false, false, false, false, true, true, true, true, true, + ]; + assert_eq!(&result, &target); + let result = is_topk(&vector, 10); + let target: Vec = vec![true, true, true, true, true, true, true, true, true, true]; + assert_eq!(&result, &target); + let result = is_topk(&vector, 100); + assert_eq!(&result, &target); + let vector: Vec = vec_to_fixed(&[9., 8., 7., 6., 5., 4., 3., 2., 1., 0.]); + let result = is_topk(&vector, 5); + let target: Vec = vec![ + true, true, true, true, true, false, false, false, false, false, + ]; + assert_eq!(&result, &target); + let vector: Vec = vec_to_fixed(&[9., 0., 8., 1., 7., 2., 6., 3., 5., 4.]); + let result = is_topk(&vector, 5); + let target: Vec = vec![ + true, false, true, false, true, false, true, false, true, false, + ]; + assert_eq!(&result, &target); + let vector: Vec = vec_to_fixed(&[0.9, 0., 0.8, 0.1, 0.7, 0.2, 0.6, 0.3, 0.5, 0.4]); + let result = is_topk(&vector, 5); + let target: Vec = vec![ + true, false, true, false, true, false, true, false, true, false, + ]; + assert_eq!(&result, &target); + let vector: Vec = vec_to_fixed(&[0., 1., 2., 3., 4., 5., 5., 5., 5., 6.]); + let result = is_topk(&vector, 5); + let target: Vec = vec![ + false, false, false, false, false, true, true, true, true, true, + ]; + assert_eq!(&result, &target); + } + + #[test] + fn test_math_sum() { + assert!(sum(&[]) == I32F32::from_num(0)); + assert!( + sum(&[ + I32F32::from_num(1.0), + I32F32::from_num(10.0), + I32F32::from_num(30.0) + ]) == I32F32::from_num(41) + ); + assert!( + sum(&[ + I32F32::from_num(-1.0), + I32F32::from_num(10.0), + I32F32::from_num(30.0) + ]) == I32F32::from_num(39) + ); + } + + #[test] + fn test_math_normalize() { + let epsilon: I32F32 = I32F32::from_num(0.0001); + let x: Vec = vec![]; + let y: Vec = normalize(&x); + assert_vec_compare(&x, &y, epsilon); + let x: Vec = vec![ + I32F32::from_num(1.0), + I32F32::from_num(10.0), + I32F32::from_num(30.0), + ]; + let y: Vec = normalize(&x); + assert_vec_compare( + &y, + &[ + I32F32::from_num(0.0243902437), + I32F32::from_num(0.243902439), + I32F32::from_num(0.7317073171), + ], + epsilon, + ); + assert_float_compare(sum(&y), I32F32::from_num(1.0), epsilon); + let x: Vec = vec![ + I32F32::from_num(-1.0), + I32F32::from_num(10.0), + I32F32::from_num(30.0), + ]; + let y: Vec = normalize(&x); + assert_vec_compare( + &y, + &[ + I32F32::from_num(-0.0256410255), + I32F32::from_num(0.2564102563), + I32F32::from_num(0.769230769), + ], + epsilon, + ); + assert_float_compare(sum(&y), I32F32::from_num(1.0), epsilon); + } + + #[test] + fn test_math_inplace_normalize() { + let epsilon: I32F32 = I32F32::from_num(0.0001); + let mut x1: Vec = vec![ + I32F32::from_num(1.0), + I32F32::from_num(10.0), + I32F32::from_num(30.0), + ]; + inplace_normalize(&mut x1); + assert_vec_compare( + &x1, + &[ + I32F32::from_num(0.0243902437), + I32F32::from_num(0.243902439), + I32F32::from_num(0.7317073171), + ], + epsilon, + ); + let mut x2: Vec = vec![ + I32F32::from_num(-1.0), + I32F32::from_num(10.0), + I32F32::from_num(30.0), + ]; + inplace_normalize(&mut x2); + assert_vec_compare( + &x2, + &[ + I32F32::from_num(-0.0256410255), + I32F32::from_num(0.2564102563), + I32F32::from_num(0.769230769), + ], + epsilon, + ); + } + + #[test] + fn test_math_inplace_normalize_64() { + let epsilon: I64F64 = I64F64::from_num(0.0001); + let mut x1: Vec = vec![ + I64F64::from_num(1.0), + I64F64::from_num(10.0), + I64F64::from_num(30.0), + ]; + inplace_normalize_64(&mut x1); + assert_vec_compare_64( + &x1, + &[ + I64F64::from_num(0.0243902437), + I64F64::from_num(0.243902439), + I64F64::from_num(0.7317073171), + ], + epsilon, + ); + let mut x2: Vec = vec![ + I64F64::from_num(-1.0), + I64F64::from_num(10.0), + I64F64::from_num(30.0), + ]; + inplace_normalize_64(&mut x2); + assert_vec_compare_64( + &x2, + &[ + I64F64::from_num(-0.0256410255), + I64F64::from_num(0.2564102563), + I64F64::from_num(0.769230769), + ], + epsilon, + ); + } + + #[test] + fn test_math_vecdiv() { + let x: Vec = vec_to_fixed(&[]); + let y: Vec = vec_to_fixed(&[]); + let result: Vec = vec_to_fixed(&[]); + assert_eq!(result, vecdiv(&x, &y)); + + let x: Vec = vec_to_fixed(&[0., 1., 0., 1.]); + let y: Vec = vec_to_fixed(&[0., 1., 1., 0.]); + let result: Vec = vec_to_fixed(&[0., 1., 0., 0.]); + assert_eq!(result, vecdiv(&x, &y)); + + let x: Vec = vec_to_fixed(&[1., 1., 10.]); + let y: Vec = vec_to_fixed(&[2., 3., 2.]); + let result: Vec = vec![fixed(1.) / fixed(2.), fixed(1.) / fixed(3.), fixed(5.)]; + assert_eq!(result, vecdiv(&x, &y)); + } + + #[test] + fn test_math_inplace_row_normalize() { + let epsilon: I32F32 = I32F32::from_num(0.0001); + let vector: Vec = vec![ + 0., 1., 2., 3., 4., 0., 10., 100., 1000., 10000., 0., 0., 0., 0., 0., 1., 1., 1., 1., + 1., + ]; + let mut mat = vec_to_mat_fixed(&vector, 4, false); + inplace_row_normalize(&mut mat); + let target: Vec = vec![ + 0., 0.1, 0.2, 0.3, 0.4, 0., 0.0009, 0.009, 0.09, 0.9, 0., 0., 0., 0., 0., 0.2, 0.2, + 0.2, 0.2, 0.2, + ]; + assert_mat_compare(&mat, &vec_to_mat_fixed(&target, 4, false), epsilon); + } + + #[test] + fn test_math_inplace_row_normalize_sparse() { + let epsilon: I32F32 = I32F32::from_num(0.0001); + let vector: Vec = vec![ + 0., 1., 0., 2., 0., 3., 4., 0., 1., 0., 2., 0., 3., 0., 1., 0., 0., 2., 0., 3., 4., 0., + 10., 0., 100., 1000., 0., 10000., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 1., 1., 1., + 1., + ]; + let mut mat = vec_to_sparse_mat_fixed(&vector, 6, false); + inplace_row_normalize_sparse(&mut mat); + let target: Vec = vec![ + 0., 0.1, 0., 0.2, 0., 0.3, 0.4, 0., 0.166666, 0., 0.333333, 0., 0.5, 0., 0.1, 0., 0., + 0.2, 0., 0.3, 0.4, 0., 0.0009, 0., 0.009, 0.09, 0., 0.9, 0., 0., 0., 0., 0., 0., 0., + 0.142857, 0.142857, 0.142857, 0.142857, 0.142857, 0.142857, 0.142857, + ]; + assert_sparse_mat_compare(&mat, &vec_to_sparse_mat_fixed(&target, 6, false), epsilon); + let vector: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; + let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; + let mut mat = vec_to_sparse_mat_fixed(&vector, 3, false); + inplace_row_normalize_sparse(&mut mat); + assert_sparse_mat_compare( + &mat, + &vec_to_sparse_mat_fixed(&target, 3, false), + I32F32::from_num(0), + ); + } + + #[test] + fn test_math_inplace_col_normalize() { + let epsilon: I32F32 = I32F32::from_num(0.0001); + let vector: Vec = vec![ + 0., 1., 2., 3., 4., 0., 10., 100., 1000., 10000., 0., 0., 0., 0., 0., 1., 1., 1., 1., + 1., + ]; + let mut mat = vec_to_mat_fixed(&vector, 4, true); + inplace_col_normalize(&mut mat); + let target: Vec = vec![ + 0., 0.1, 0.2, 0.3, 0.4, 0., 0.0009, 0.009, 0.09, 0.9, 0., 0., 0., 0., 0., 0.2, 0.2, + 0.2, 0.2, 0.2, + ]; + assert_mat_compare(&mat, &vec_to_mat_fixed(&target, 4, true), epsilon); + } + + #[test] + fn test_math_inplace_col_normalize_sparse() { + let epsilon: I32F32 = I32F32::from_num(0.0001); + let vector: Vec = vec![ + 0., 1., 0., 2., 0., 3., 4., 0., 1., 0., 2., 0., 3., 0., 1., 0., 0., 2., 0., 3., 4., 0., + 10., 0., 100., 1000., 0., 10000., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 1., 1., 1., + 1., + ]; + let mut mat = vec_to_sparse_mat_fixed(&vector, 6, true); + inplace_col_normalize_sparse(&mut mat, 6); + let target: Vec = vec![ + 0., 0.1, 0., 0.2, 0., 0.3, 0.4, 0., 0.166666, 0., 0.333333, 0., 0.5, 0., 0.1, 0., 0., + 0.2, 0., 0.3, 0.4, 0., 0.0009, 0., 0.009, 0.09, 0., 0.9, 0., 0., 0., 0., 0., 0., 0., + 0.142857, 0.142857, 0.142857, 0.142857, 0.142857, 0.142857, 0.142857, + ]; + assert_sparse_mat_compare(&mat, &vec_to_sparse_mat_fixed(&target, 6, true), epsilon); + let vector: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; + let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; + let mut mat = vec_to_sparse_mat_fixed(&vector, 3, false); + inplace_col_normalize_sparse(&mut mat, 6); + assert_sparse_mat_compare( + &mat, + &vec_to_sparse_mat_fixed(&target, 3, false), + I32F32::from_num(0), + ); + let mut mat: Vec> = vec![]; + let target: Vec> = vec![]; + inplace_col_normalize_sparse(&mut mat, 0); + assert_sparse_mat_compare(&mat, &target, epsilon); + } + + #[test] + fn test_math_inplace_col_max_upscale() { + let mut mat: Vec> = vec![vec![]]; + let target: Vec> = vec![vec![]]; + inplace_col_max_upscale(&mut mat); + assert_eq!(&mat, &target); + let mut mat: Vec> = vec![vec![I32F32::from_num(0)]]; + let target: Vec> = vec![vec![I32F32::from_num(0)]]; + inplace_col_max_upscale(&mut mat); + assert_eq!(&mat, &target); + let epsilon: I32F32 = I32F32::from_num(0.0001); + let vector: Vec = vec![ + 0., 1., 2., 3., 4., 0., 10., 100., 1000., 10000., 0., 0., 0., 0., 0., 1., 1., 1., 1., + 1., + ]; + let mut mat: Vec> = vec_to_mat_fixed(&vector, 4, true); + inplace_col_max_upscale(&mut mat); + let target: Vec = vec![ + 0., 0.25, 0.5, 0.75, 1., 0., 0.001, 0.01, 0.1, 1., 0., 0., 0., 0., 0., 1., 1., 1., 1., + 1., + ]; + assert_mat_compare(&mat, &vec_to_mat_fixed(&target, 4, true), epsilon); + } + + #[test] + fn test_math_inplace_col_max_upscale_sparse() { + let mut mat: Vec> = vec![vec![]]; + let target: Vec> = vec![vec![]]; + inplace_col_max_upscale_sparse(&mut mat, 0); + assert_eq!(&mat, &target); + let mut mat: Vec> = vec![vec![(0, I32F32::from_num(0))]]; + let target: Vec> = vec![vec![(0, I32F32::from_num(0))]]; + inplace_col_max_upscale_sparse(&mut mat, 1); + assert_eq!(&mat, &target); + let epsilon: I32F32 = I32F32::from_num(0.0001); + let vector: Vec = vec![ + 0., 1., 0., 2., 0., 3., 4., 0., 1., 0., 2., 0., 3., 0., 1., 0., 0., 2., 0., 3., 4., 0., + 10., 0., 100., 1000., 0., 10000., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 1., 1., 1., + 1., + ]; + let mut mat = vec_to_sparse_mat_fixed(&vector, 6, true); + inplace_col_max_upscale_sparse(&mut mat, 6); + let target: Vec = vec![ + 0., 0.25, 0., 0.5, 0., 0.75, 1., 0., 0.333333, 0., 0.666666, 0., 1., 0., 0.25, 0., 0., + 0.5, 0., 0.75, 1., 0., 0.001, 0., 0.01, 0.1, 0., 1., 0., 0., 0., 0., 0., 0., 0., 1., + 1., 1., 1., 1., 1., 1., + ]; + assert_sparse_mat_compare(&mat, &vec_to_sparse_mat_fixed(&target, 6, true), epsilon); + let vector: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; + let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; + let mut mat = vec_to_sparse_mat_fixed(&vector, 3, false); + inplace_col_max_upscale_sparse(&mut mat, 6); + assert_sparse_mat_compare( + &mat, + &vec_to_sparse_mat_fixed(&target, 3, false), + I32F32::from_num(0), + ); + let mut mat: Vec> = vec![]; + let target: Vec> = vec![]; + inplace_col_max_upscale_sparse(&mut mat, 0); + assert_sparse_mat_compare(&mat, &target, epsilon); + } + + #[test] + fn test_math_inplace_mask_vector() { + let mask: Vec = vec![false, false, false]; + let mut vector: Vec = vec_to_fixed(&[0., 1., 2.]); + let target: Vec = vec_to_fixed(&[0., 1., 2.]); + inplace_mask_vector(&mask, &mut vector); + assert_vec_compare(&vector, &target, I32F32::from_num(0)); + let mask: Vec = vec![false, true, false]; + let mut vector: Vec = vec_to_fixed(&[0., 1., 2.]); + let target: Vec = vec_to_fixed(&[0., 0., 2.]); + inplace_mask_vector(&mask, &mut vector); + assert_vec_compare(&vector, &target, I32F32::from_num(0)); + let mask: Vec = vec![true, true, true]; + let mut vector: Vec = vec_to_fixed(&[0., 1., 2.]); + let target: Vec = vec_to_fixed(&[0., 0., 0.]); + inplace_mask_vector(&mask, &mut vector); + assert_vec_compare(&vector, &target, I32F32::from_num(0)); + } + + #[test] + fn test_math_inplace_mask_matrix() { + let mask: Vec> = vec![ + vec![false, false, false], + vec![false, false, false], + vec![false, false, false], + ]; + let vector: Vec = vec![0., 1., 2., 3., 4., 5., 6., 7., 8.]; + let mut mat = vec_to_mat_fixed(&vector, 3, false); + inplace_mask_matrix(&mask, &mut mat); + assert_mat_compare( + &mat, + &vec_to_mat_fixed(&vector, 3, false), + I32F32::from_num(0), + ); + let mask: Vec> = vec![ + vec![true, false, false], + vec![false, true, false], + vec![false, false, true], + ]; + let target: Vec = vec![0., 1., 2., 3., 0., 5., 6., 7., 0.]; + let mut mat = vec_to_mat_fixed(&vector, 3, false); + inplace_mask_matrix(&mask, &mut mat); + assert_mat_compare( + &mat, + &vec_to_mat_fixed(&target, 3, false), + I32F32::from_num(0), + ); + let mask: Vec> = vec![ + vec![true, true, true], + vec![true, true, true], + vec![true, true, true], + ]; + let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0.]; + let mut mat = vec_to_mat_fixed(&vector, 3, false); + inplace_mask_matrix(&mask, &mut mat); + assert_mat_compare( + &mat, + &vec_to_mat_fixed(&target, 3, false), + I32F32::from_num(0), + ); + } + + #[test] + fn test_math_inplace_mask_rows() { + let input: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9.]; + let mask: Vec = vec![false, false, false]; + let target: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9.]; + let mut mat = vec_to_mat_fixed(&input, 3, false); + inplace_mask_rows(&mask, &mut mat); + assert_mat_compare( + &mat, + &vec_to_mat_fixed(&target, 3, false), + I32F32::from_num(0), + ); + let mask: Vec = vec![true, true, true]; + let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0.]; + let mut mat = vec_to_mat_fixed(&input, 3, false); + inplace_mask_rows(&mask, &mut mat); + assert_mat_compare( + &mat, + &vec_to_mat_fixed(&target, 3, false), + I32F32::from_num(0), + ); + let mask: Vec = vec![true, false, true]; + let target: Vec = vec![0., 0., 0., 4., 5., 6., 0., 0., 0.]; + let mut mat = vec_to_mat_fixed(&input, 3, false); + inplace_mask_rows(&mask, &mut mat); + assert_mat_compare( + &mat, + &vec_to_mat_fixed(&target, 3, false), + I32F32::from_num(0), + ); + let input: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0.]; + let mut mat = vec_to_mat_fixed(&input, 3, false); + let mask: Vec = vec![false, false, false]; + let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0.]; + inplace_mask_rows(&mask, &mut mat); + assert_mat_compare( + &mat, + &vec_to_mat_fixed(&target, 3, false), + I32F32::from_num(0), + ); + } + + #[test] + fn test_math_inplace_mask_diag() { + let vector: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9.]; + let target: Vec = vec![0., 2., 3., 4., 0., 6., 7., 8., 0.]; + let mut mat = vec_to_mat_fixed(&vector, 3, false); + inplace_mask_diag(&mut mat); + assert_mat_compare( + &mat, + &vec_to_mat_fixed(&target, 3, false), + I32F32::from_num(0), + ); + } + + #[test] + fn test_math_mask_rows_sparse() { + let input: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9.]; + let mat = vec_to_sparse_mat_fixed(&input, 3, false); + let mask: Vec = vec![false, false, false]; + let target: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9.]; + let result = mask_rows_sparse(&mask, &mat); + assert_sparse_mat_compare( + &result, + &vec_to_sparse_mat_fixed(&target, 3, false), + I32F32::from_num(0), + ); + let mask: Vec = vec![true, true, true]; + let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0.]; + let result = mask_rows_sparse(&mask, &mat); + assert_sparse_mat_compare( + &result, + &vec_to_sparse_mat_fixed(&target, 3, false), + I32F32::from_num(0), + ); + let mask: Vec = vec![true, false, true]; + let target: Vec = vec![0., 0., 0., 4., 5., 6., 0., 0., 0.]; + let result = mask_rows_sparse(&mask, &mat); + assert_sparse_mat_compare( + &result, + &vec_to_sparse_mat_fixed(&target, 3, false), + I32F32::from_num(0), + ); + let input: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0.]; + let mat = vec_to_sparse_mat_fixed(&input, 3, false); + let mask: Vec = vec![false, false, false]; + let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0.]; + let result = mask_rows_sparse(&mask, &mat); + assert_sparse_mat_compare( + &result, + &vec_to_sparse_mat_fixed(&target, 3, false), + I32F32::from_num(0), + ); + } + + #[test] + fn test_math_mask_diag_sparse() { + let vector: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9.]; + let target: Vec = vec![0., 2., 3., 4., 0., 6., 7., 8., 0.]; + let mat = vec_to_sparse_mat_fixed(&vector, 3, false); + let result = mask_diag_sparse(&mat); + assert_sparse_mat_compare( + &result, + &vec_to_sparse_mat_fixed(&target, 3, false), + I32F32::from_num(0), + ); + let vector: Vec = vec![1., 0., 0., 0., 5., 0., 0., 0., 9.]; + let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0.]; + let mat = vec_to_sparse_mat_fixed(&vector, 3, false); + let result = mask_diag_sparse(&mat); + assert_sparse_mat_compare( + &result, + &vec_to_sparse_mat_fixed(&target, 3, false), + I32F32::from_num(0), + ); + let vector: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0.]; + let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0.]; + let mat = vec_to_sparse_mat_fixed(&vector, 3, false); + let result = mask_diag_sparse(&mat); + assert_sparse_mat_compare( + &result, + &vec_to_sparse_mat_fixed(&target, 3, false), + I32F32::from_num(0), + ); + } + + #[test] + fn test_math_vec_mask_sparse_matrix() { + let vector: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9.]; + let target: Vec = vec![0., 2., 3., 4., 0., 6., 7., 8., 0.]; + let mat = vec_to_sparse_mat_fixed(&vector, 3, false); + let first_vector: Vec = vec![1, 2, 3]; + let second_vector: Vec = vec![1, 2, 3]; + let result = vec_mask_sparse_matrix(&mat, &first_vector, &second_vector, &|a, b| a == b); + assert_sparse_mat_compare( + &result, + &vec_to_sparse_mat_fixed(&target, 3, false), + I32F32::from_num(0), + ); + let target: Vec = vec![1., 0., 0., 4., 5., 0., 7., 8., 9.]; + let mat = vec_to_sparse_mat_fixed(&vector, 3, false); + let first_vector: Vec = vec![1, 2, 3]; + let second_vector: Vec = vec![1, 2, 3]; + let result = vec_mask_sparse_matrix(&mat, &first_vector, &second_vector, &|a, b| a < b); + assert_sparse_mat_compare( + &result, + &vec_to_sparse_mat_fixed(&target, 3, false), + I32F32::from_num(0), + ); + let vector: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0.]; + let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0.]; + let mat = vec_to_sparse_mat_fixed(&vector, 3, false); + let first_vector: Vec = vec![1, 2, 3]; + let second_vector: Vec = vec![1, 2, 3]; + let result = vec_mask_sparse_matrix(&mat, &first_vector, &second_vector, &|a, b| a == b); + assert_sparse_mat_compare( + &result, + &vec_to_sparse_mat_fixed(&target, 3, false), + I32F32::from_num(0), + ); + } + + #[test] + fn test_math_row_hadamard() { + let vector: Vec = vec_to_fixed(&[1., 2., 3., 4.]); + let matrix: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; + let matrix = vec_to_mat_fixed(&matrix, 4, false); + let result = row_hadamard(&matrix, &vector); + let target: Vec = vec![1., 2., 3., 8., 10., 12., 21., 24., 27., 40., 44., 48.]; + let target = vec_to_mat_fixed(&target, 4, false); + assert_mat_compare(&result, &target, I32F32::from_num(0)); + } + + #[test] + fn test_math_row_hadamard_sparse() { + let vector: Vec = vec_to_fixed(&[1., 2., 3., 4.]); + let matrix: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; + let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); + let result = row_hadamard_sparse(&matrix, &vector); + let target: Vec = vec![1., 2., 3., 8., 10., 12., 21., 24., 27., 40., 44., 48.]; + let target = vec_to_sparse_mat_fixed(&target, 4, false); + assert_sparse_mat_compare(&result, &target, I32F32::from_num(0)); + let matrix: Vec = vec![0., 2., 3., 4., 0., 6., 7., 8., 0., 10., 11., 12.]; + let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); + let result = row_hadamard_sparse(&matrix, &vector); + let target: Vec = vec![0., 2., 3., 8., 0., 12., 21., 24., 0., 40., 44., 48.]; + let target = vec_to_sparse_mat_fixed(&target, 4, false); + assert_sparse_mat_compare(&result, &target, I32F32::from_num(0)); + let matrix: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; + let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); + let result = row_hadamard_sparse(&matrix, &vector); + let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; + let target = vec_to_sparse_mat_fixed(&target, 4, false); + assert_sparse_mat_compare(&result, &target, I32F32::from_num(0)); + } + + #[test] + fn test_math_row_sum() { + let matrix: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; + let matrix = vec_to_mat_fixed(&matrix, 4, false); + let result = row_sum(&matrix); + let target: Vec = vec_to_fixed(&[6., 15., 24., 33.]); + assert_vec_compare(&result, &target, I32F32::from_num(0)); + } + + #[test] + fn test_math_row_sum_sparse() { + let matrix: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; + let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); + let result = row_sum_sparse(&matrix); + let target: Vec = vec_to_fixed(&[6., 15., 24., 33.]); + assert_vec_compare(&result, &target, I32F32::from_num(0)); + let matrix: Vec = vec![0., 2., 3., 4., 0., 6., 7., 8., 0., 10., 11., 12.]; + let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); + let result = row_sum_sparse(&matrix); + let target: Vec = vec_to_fixed(&[5., 10., 15., 33.]); + assert_vec_compare(&result, &target, I32F32::from_num(0)); + let matrix: Vec = vec![1., 2., 3., 0., 0., 0., 7., 8., 9., 10., 11., 12.]; + let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); + let result = row_sum_sparse(&matrix); + let target: Vec = vec_to_fixed(&[6., 0., 24., 33.]); + assert_vec_compare(&result, &target, I32F32::from_num(0)); + let matrix: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; + let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); + let result = row_sum_sparse(&matrix); + let target: Vec = vec_to_fixed(&[0., 0., 0., 0.]); + assert_vec_compare(&result, &target, I32F32::from_num(0)); + } + + #[test] + fn test_math_col_sum() { + let matrix: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; + let matrix = vec_to_mat_fixed(&matrix, 4, false); + let result = col_sum(&matrix); + let target: Vec = vec_to_fixed(&[22., 26., 30.]); + assert_vec_compare(&result, &target, I32F32::from_num(0)); + } + + #[test] + fn test_math_col_sum_sparse() { + let matrix: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; + let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); + let result = col_sum_sparse(&matrix, 3); + let target: Vec = vec_to_fixed(&[22., 26., 30.]); + assert_vec_compare(&result, &target, I32F32::from_num(0)); + let matrix: Vec = vec![0., 2., 3., 4., 0., 6., 7., 8., 0., 10., 11., 12.]; + let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); + let result = col_sum_sparse(&matrix, 3); + let target: Vec = vec_to_fixed(&[21., 21., 21.]); + assert_vec_compare(&result, &target, I32F32::from_num(0)); + let matrix: Vec = vec![1., 0., 3., 4., 0., 6., 7., 0., 9., 10., 0., 12.]; + let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); + let result = col_sum_sparse(&matrix, 3); + let target: Vec = vec_to_fixed(&[22., 0., 30.]); + assert_vec_compare(&result, &target, I32F32::from_num(0)); + let matrix: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; + let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); + let result = col_sum_sparse(&matrix, 3); + let target: Vec = vec_to_fixed(&[0., 0., 0.]); + assert_vec_compare(&result, &target, I32F32::from_num(0)); + } + + #[test] + fn test_math_matmul() { + let vector: Vec = vec_to_fixed(&[1., 2., 3., 4.]); + let matrix: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; + let matrix = vec_to_mat_fixed(&matrix, 4, false); + let result = matmul(&matrix, &vector); + let target: Vec = vec_to_fixed(&[70., 80., 90.]); + assert_vec_compare(&result, &target, I32F32::from_num(0)); + } + + #[test] + fn test_math_matmul_transpose() { + let vector: Vec = vec_to_fixed(&[1., 2., 3.]); + let matrix: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; + let matrix = vec_to_mat_fixed(&matrix, 4, false); + let result = matmul_transpose(&matrix, &vector); + let target: Vec = vec_to_fixed(&[14., 32., 50., 68.]); + assert_vec_compare(&result, &target, I32F32::from_num(0)); + } + + #[test] + fn test_math_sparse_matmul() { + let vector: Vec = vec_to_fixed(&[1., 2., 3., 4.]); + let matrix: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; + let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); + let result = matmul_sparse(&matrix, &vector, 3); + let target: Vec = vec_to_fixed(&[70., 80., 90.]); + assert_vec_compare(&result, &target, I32F32::from_num(0)); + let matrix: Vec = vec![0., 2., 3., 4., 0., 6., 7., 8., 0., 10., 11., 12.]; + let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); + let result = matmul_sparse(&matrix, &vector, 3); + let target: Vec = vec_to_fixed(&[69., 70., 63.]); + assert_vec_compare(&result, &target, I32F32::from_num(0)); + let matrix: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; + let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); + let result = matmul_sparse(&matrix, &vector, 3); + let target: Vec = vec_to_fixed(&[0., 0., 0.]); + assert_vec_compare(&result, &target, I32F32::from_num(0)); + } + + #[test] + fn test_math_sparse_matmul_transpose() { + let vector: Vec = vec_to_fixed(&[1., 2., 3.]); + let matrix: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; + let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); + let result = matmul_transpose_sparse(&matrix, &vector); + let target: Vec = vec_to_fixed(&[14., 32., 50., 68.]); + assert_vec_compare(&result, &target, I32F32::from_num(0)); + let matrix: Vec = vec![0., 2., 3., 4., 0., 6., 7., 8., 0., 10., 11., 12.]; + let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); + let result = matmul_transpose_sparse(&matrix, &vector); + let target: Vec = vec_to_fixed(&[13., 22., 23., 68.]); + assert_vec_compare(&result, &target, I32F32::from_num(0)); + let matrix: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; + let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); + let result = matmul_transpose_sparse(&matrix, &vector); + let target: Vec = vec_to_fixed(&[0., 0., 0., 0.]); + assert_vec_compare(&result, &target, I32F32::from_num(0)); + } + + #[test] + fn test_math_inplace_col_clip() { + let vector: Vec = vec_to_fixed(&[0., 5., 12.]); + let matrix: Vec = vec![0., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; + let mut matrix = vec_to_mat_fixed(&matrix, 4, false); + let target: Vec = vec![0., 2., 3., 0., 5., 6., 0., 5., 9., 0., 5., 12.]; + let target = vec_to_mat_fixed(&target, 4, false); + inplace_col_clip(&mut matrix, &vector); + assert_mat_compare(&matrix, &target, I32F32::from_num(0)); + } + + #[test] + fn test_math_col_clip_sparse() { + let vector: Vec = vec_to_fixed(&[0., 5., 12.]); + let matrix: Vec = vec![0., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; + let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); + let target: Vec = vec![0., 2., 3., 0., 5., 6., 0., 5., 9., 0., 5., 12.]; + let target = vec_to_sparse_mat_fixed(&target, 4, false); + let result = col_clip_sparse(&matrix, &vector); + assert_sparse_mat_compare(&result, &target, I32F32::from_num(0)); + let matrix: Vec = vec![0., 2., 3., 4., 5., 6., 0., 0., 0., 10., 11., 12.]; + let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); + let target: Vec = vec![0., 2., 3., 0., 5., 6., 0., 0., 0., 0., 5., 12.]; + let target = vec_to_sparse_mat_fixed(&target, 4, false); + let result = col_clip_sparse(&matrix, &vector); + assert_sparse_mat_compare(&result, &target, I32F32::from_num(0)); + let matrix: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; + let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); + let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; + let target = vec_to_sparse_mat_fixed(&target, 4, false); + let result = col_clip_sparse(&matrix, &vector); + assert_sparse_mat_compare(&result, &target, I32F32::from_num(0)); + } + + #[test] + fn test_math_clip_sparse() { + let matrix: Vec = vec![0., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; + let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); + let target: Vec = vec![0., 1., 1., 1., 1., 1., 1., 100., 100., 100., 100., 100.]; + let target = vec_to_sparse_mat_fixed(&target, 4, false); + let result = clip_sparse( + &matrix, + I32F32::from_num(8), + I32F32::from_num(100), + I32F32::from_num(1), + ); + assert_sparse_mat_compare(&result, &target, I32F32::from_num(0)); + } + + #[test] + fn test_math_clip() { + let matrix: Vec = vec![0., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; + let matrix = vec_to_mat_fixed(&matrix, 4, false); + let target: Vec = vec![1., 1., 1., 1., 1., 1., 1., 100., 100., 100., 100., 100.]; + let target = vec_to_mat_fixed(&target, 4, false); + let result = clip( + &matrix, + I32F32::from_num(8), + I32F32::from_num(100), + I32F32::from_num(1), + ); + assert_mat_compare(&result, &target, I32F32::from_num(0)); + } + + #[test] + fn test_math_inplace_clip() { + let matrix: Vec = vec![0., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; + let mut matrix = vec_to_mat_fixed(&matrix, 4, false); + let target: Vec = vec![1., 1., 1., 1., 1., 1., 1., 100., 100., 100., 100., 100.]; + let target = vec_to_mat_fixed(&target, 4, false); + inplace_clip( + &mut matrix, + I32F32::from_num(8), + I32F32::from_num(100), + I32F32::from_num(1), + ); + assert_mat_compare(&matrix, &target, I32F32::from_num(0)); + } + + #[test] + fn test_math_weighted_median() { + let mut rng = thread_rng(); + let zero: I32F32 = fixed(0.); + let one: I32F32 = fixed(1.); + for _ in 0..100 { + let stake: Vec = vec_to_fixed(&[]); + let score: Vec = vec_to_fixed(&[]); + let majority: I32F32 = fixed(0.51); + assert_eq!( + zero, + weighted_median( + &stake, + &score, + (0..stake.len()).collect::>().as_slice(), + one - majority, + zero, + stake.iter().sum() + ) + ); + + let stake: Vec = normalize(&vec_to_fixed(&[0.51])); + let score: Vec = vec_to_fixed(&[1.]); + let majority: I32F32 = fixed(0.51); + assert_eq!( + one, + weighted_median( + &stake, + &score, + (0..stake.len()).collect::>().as_slice(), + one - majority, + zero, + stake.iter().sum() + ) + ); + + let stake: Vec = vec_to_fixed(&[0.49, 0.51]); + let score: Vec = vec_to_fixed(&[0.5, 1.]); + let majority: I32F32 = fixed(0.51); + assert_eq!( + one, + weighted_median( + &stake, + &score, + (0..stake.len()).collect::>().as_slice(), + one - majority, + zero, + stake.iter().sum() + ) + ); + + let stake: Vec = vec_to_fixed(&[0.51, 0.49]); + let score: Vec = vec_to_fixed(&[0.5, 1.]); + let majority: I32F32 = fixed(0.51); + assert_eq!( + fixed(0.5), + weighted_median( + &stake, + &score, + (0..stake.len()).collect::>().as_slice(), + one - majority, + zero, + stake.iter().sum() + ) + ); + + let stake: Vec = vec_to_fixed(&[0.49, 0., 0.51]); + let score: Vec = vec_to_fixed(&[0.5, 0.7, 1.]); + let majority: I32F32 = fixed(0.51); + assert_eq!( + one, + weighted_median( + &stake, + &score, + (0..stake.len()).collect::>().as_slice(), + one - majority, + zero, + stake.iter().sum() + ) + ); + + let stake: Vec = vec_to_fixed(&[0.49, 0.01, 0.5]); + let score: Vec = vec_to_fixed(&[0.5, 0.7, 1.]); + let majority: I32F32 = fixed(0.51); + assert_eq!( + fixed(0.7), + weighted_median( + &stake, + &score, + (0..stake.len()).collect::>().as_slice(), + one - majority, + zero, + stake.iter().sum() + ) + ); + + let stake: Vec = vec_to_fixed(&[0.49, 0.51, 0.0]); + let score: Vec = vec_to_fixed(&[0.5, 0.7, 1.]); + let majority: I32F32 = fixed(0.51); + assert_eq!( + fixed(0.7), + weighted_median( + &stake, + &score, + (0..stake.len()).collect::>().as_slice(), + one - majority, + zero, + stake.iter().sum() + ) + ); + + let stake: Vec = vec_to_fixed(&[0.0, 0.49, 0.51]); + let score: Vec = vec_to_fixed(&[0.5, 0.7, 1.]); + let majority: I32F32 = fixed(0.51); + assert_eq!( + one, + weighted_median( + &stake, + &score, + (0..stake.len()).collect::>().as_slice(), + one - majority, + zero, + stake.iter().sum() + ) + ); + + let stake: Vec = vec_to_fixed(&[0.0, 0.49, 0.0, 0.51]); + let score: Vec = vec_to_fixed(&[0.5, 0.5, 1., 1.]); + let majority: I32F32 = fixed(0.51); + assert_eq!( + one, + weighted_median( + &stake, + &score, + (0..stake.len()).collect::>().as_slice(), + one - majority, + zero, + stake.iter().sum() + ) + ); + + let stake: Vec = vec_to_fixed(&[0.0, 0.49, 0.0, 0.51, 0.0]); + let score: Vec = vec_to_fixed(&[0.5, 0.5, 1., 1., 0.5]); + let majority: I32F32 = fixed(0.51); + assert_eq!( + one, + weighted_median( + &stake, + &score, + (0..stake.len()).collect::>().as_slice(), + one - majority, + zero, + stake.iter().sum() + ) + ); + + let stake: Vec = vec_to_fixed(&[0.2, 0.2, 0.2, 0.2, 0.2]); + let score: Vec = vec_to_fixed(&[0.8, 0.2, 1., 0.6, 0.4]); + let majority: I32F32 = fixed(0.51); + assert_eq!( + fixed(0.6), + weighted_median( + &stake, + &score, + (0..stake.len()).collect::>().as_slice(), + one - majority, + zero, + stake.iter().sum() + ) + ); + + let stake: Vec = + vec_to_fixed(&[0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]); + let score: Vec = + vec_to_fixed(&[0.8, 0.8, 0.2, 0.2, 1.0, 1.0, 0.6, 0.6, 0.4, 0.4]); + let majority: I32F32 = fixed(0.51); + assert_eq!( + fixed(0.6), + weighted_median( + &stake, + &score, + (0..stake.len()).collect::>().as_slice(), + one - majority, + zero, + stake.iter().sum() + ) + ); + + let n: usize = 100; + for majority in vec_to_fixed(&[ + 0., 0.0000001, 0.25, 0.49, 0.49, 0.49, 0.5, 0.51, 0.51, 0.51, 0.9999999, 1., + ]) { + for allow_equal in [false, true] { + let mut stake: Vec = vec![]; + let mut score: Vec = vec![]; + let mut last_score: I32F32 = zero; + for i in 0..n { + if allow_equal { + match rng.gen_range(0..2) { + 1 => stake.push(one), + _ => stake.push(zero), + } + if rng.gen_range(0..2) == 1 { + last_score += one + } + score.push(last_score); + } else { + stake.push(one); + score.push(I32F32::from_num(i)); + } + } + inplace_normalize(&mut stake); + let total_stake: I32F32 = stake.iter().sum(); + let mut minority: I32F32 = total_stake - majority; + if minority < zero { + minority = zero; + } + let mut medians: Vec = vec![]; + let mut median_stake: I32F32 = zero; + let mut median_set = false; + let mut stake_sum: I32F32 = zero; + for i in 0..n { + stake_sum += stake[i]; + if !median_set && stake_sum >= minority { + median_stake = stake_sum; + median_set = true; + } + if median_set { + if median_stake < stake_sum { + if median_stake == minority && !medians.contains(&score[i]) { + medians.push(score[i]); + } + break; + } + if !medians.contains(&score[i]) { + medians.push(score[i]); + } + } + } + if medians.is_empty() { + medians.push(zero); + } + let stake_idx: Vec = (0..stake.len()).collect(); + let result: I32F32 = + weighted_median(&stake, &score, &stake_idx, minority, zero, total_stake); + assert!(medians.contains(&result)); + for _ in 0..10 { + let mut permuted_uids: Vec = (0..n).collect(); + permuted_uids.shuffle(&mut thread_rng()); + stake = permuted_uids.iter().map(|&i| stake[i]).collect(); + score = permuted_uids.iter().map(|&i| score[i]).collect(); + let result: I32F32 = weighted_median( + &stake, + &score, + &stake_idx, + minority, + zero, + total_stake, + ); + assert!(medians.contains(&result)); + } + } } } } - // Return the computed EMA matrix. - result -} + #[test] + fn test_math_weighted_median_col() { + let stake: Vec = vec_to_fixed(&[]); + let weights: Vec> = vec![vec![]]; + let median: Vec = vec_to_fixed(&[]); + assert_eq!(median, weighted_median_col(&stake, &weights, fixed(0.5))); + + let stake: Vec = vec_to_fixed(&[0., 0.]); + let weights: Vec = vec![0., 0., 0., 0.]; + let weights: Vec> = vec_to_mat_fixed(&weights, 2, false); + let median: Vec = vec_to_fixed(&[0., 0.]); + assert_eq!(median, weighted_median_col(&stake, &weights, fixed(0.5))); + + let stake: Vec = vec_to_fixed(&[0., 0.75, 0.25, 0.]); + let weights: Vec = vec![0., 0.1, 0., 0., 0.2, 0.4, 0., 0.3, 0.1, 0., 0.4, 0.5]; + let weights: Vec> = vec_to_mat_fixed(&weights, 4, false); + let median: Vec = vec_to_fixed(&[0., 0.3, 0.4]); + assert_eq!(median, weighted_median_col(&stake, &weights, fixed(0.24))); + let median: Vec = vec_to_fixed(&[0., 0.2, 0.4]); + assert_eq!(median, weighted_median_col(&stake, &weights, fixed(0.26))); + let median: Vec = vec_to_fixed(&[0., 0.2, 0.1]); + assert_eq!(median, weighted_median_col(&stake, &weights, fixed(0.76))); + + let stake: Vec = vec_to_fixed(&[0., 0.3, 0.2, 0.5]); + let weights: Vec = vec![0., 0.1, 0., 0., 0.2, 0.4, 0., 0.3, 0.1, 0., 0., 0.5]; + let weights: Vec> = vec_to_mat_fixed(&weights, 4, false); + let median: Vec = vec_to_fixed(&[0., 0., 0.4]); + assert_eq!(median, weighted_median_col(&stake, &weights, fixed(0.51))); + } -/// Return the quantile of a vector of I32F32 values. -pub fn quantile(data: &[I32F32], quantile: f64) -> I32F32 { - // Clone the input data to avoid modifying the original vector. - let mut sorted_data = data.to_owned(); + #[test] + fn test_math_weighted_median_col_sparse() { + let stake: Vec = vec_to_fixed(&[]); + let weights: Vec> = vec![vec![]]; + let median: Vec = vec_to_fixed(&[]); + assert_eq!( + median, + weighted_median_col_sparse(&stake, &weights, 0, fixed(0.5)) + ); - // Sort the cloned data in ascending order, handling potential NaN values. - sorted_data.sort_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Equal)); + let stake: Vec = vec_to_fixed(&[0., 0.]); + let weights: Vec = vec![0., 0., 0., 0.]; + let weights: Vec> = vec_to_sparse_mat_fixed(&weights, 2, false); + let median: Vec = vec_to_fixed(&[0., 0.]); + assert_eq!( + median, + weighted_median_col_sparse(&stake, &weights, 2, fixed(0.5)) + ); - // Get the length of the sorted data. - let len = sorted_data.len(); + let stake: Vec = vec_to_fixed(&[0., 0.75, 0.25, 0.]); + let weights: Vec = vec![0., 0.1, 0., 0., 0.2, 0.4, 0., 0.3, 0.1, 0., 0.4, 0.5]; + let weights: Vec> = vec_to_sparse_mat_fixed(&weights, 4, false); + let median: Vec = vec_to_fixed(&[0., 0.3, 0.4]); + assert_eq!( + median, + weighted_median_col_sparse(&stake, &weights, 3, fixed(0.24)) + ); + let median: Vec = vec_to_fixed(&[0., 0.2, 0.4]); + assert_eq!( + median, + weighted_median_col_sparse(&stake, &weights, 3, fixed(0.26)) + ); + let median: Vec = vec_to_fixed(&[0., 0.2, 0.1]); + assert_eq!( + median, + weighted_median_col_sparse(&stake, &weights, 3, fixed(0.76)) + ); - // If the data is empty, return 0 as the quantile value. - if len == 0 { - return I32F32::from_num(0); + let stake: Vec = vec_to_fixed(&[0., 0.3, 0.2, 0.5]); + let weights: Vec = vec![0., 0.1, 0., 0., 0.2, 0.4, 0., 0.3, 0.1, 0., 0., 0.5]; + let weights: Vec> = vec_to_sparse_mat_fixed(&weights, 4, false); + let median: Vec = vec_to_fixed(&[0., 0., 0.4]); + assert_eq!( + median, + weighted_median_col_sparse(&stake, &weights, 3, fixed(0.51)) + ); } - // Calculate the position in the sorted array corresponding to the quantile. - let pos = quantile * (len.saturating_sub(1)) as f64; + #[test] + fn test_math_hadamard() { + let mat2: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; + let mat1: Vec = vec![ + 10., 20., 30., 40., 50., 60., 70., 80., 90., 100., 110., 120., + ]; + let target: Vec = vec![ + 10., 40., 90., 160., 250., 360., 490., 640., 810., 1000., 1210., 1440., + ]; + let mat2 = vec_to_mat_fixed(&mat2, 4, false); + let mat1 = vec_to_mat_fixed(&mat1, 4, false); + let target = vec_to_mat_fixed(&target, 4, false); + let result = hadamard(&mat1, &mat2); + assert_mat_compare(&result, &target, I32F32::from_num(0.000001)); + let mat2: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; + let mat1: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; + let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; + let mat2 = vec_to_mat_fixed(&mat2, 4, false); + let mat1 = vec_to_mat_fixed(&mat1, 4, false); + let target = vec_to_mat_fixed(&target, 4, false); + let result = hadamard(&mat1, &mat2); + assert_mat_compare(&result, &target, I32F32::from_num(0.000001)); + let mat2: Vec = vec![1., 0., 0., 0., 2., 0., 0., 0., 3., 0., 0., 0.]; + let mat1: Vec = vec![0., 0., 4., 0., 5., 0., 6., 0., 0., 0., 0., 0.]; + let target: Vec = vec![0., 0., 0., 0., 10., 0., 0., 0., 0., 0., 0., 0.]; + let mat2 = vec_to_mat_fixed(&mat2, 4, false); + let mat1 = vec_to_mat_fixed(&mat1, 4, false); + let target = vec_to_mat_fixed(&target, 4, false); + let result = hadamard(&mat1, &mat2); + assert_mat_compare(&result, &target, I32F32::from_num(0.000001)); + } - // Determine the lower index by flooring the position. - let low = pos.floor() as usize; + #[test] + fn test_math_hadamard_sparse() { + let mat2: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; + let mat1: Vec = vec![ + 10., 20., 30., 40., 50., 60., 70., 80., 90., 100., 110., 120., + ]; + let target: Vec = vec![ + 10., 40., 90., 160., 250., 360., 490., 640., 810., 1000., 1210., 1440., + ]; + let mat2 = vec_to_sparse_mat_fixed(&mat2, 4, false); + let mat1 = vec_to_sparse_mat_fixed(&mat1, 4, false); + let target = vec_to_sparse_mat_fixed(&target, 4, false); + let result = hadamard_sparse(&mat1, &mat2, 3); + assert_sparse_mat_compare(&result, &target, I32F32::from_num(0.000001)); + let mat2: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; + let mat1: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; + let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; + let mat2 = vec_to_sparse_mat_fixed(&mat2, 4, false); + let mat1 = vec_to_sparse_mat_fixed(&mat1, 4, false); + let target = vec_to_sparse_mat_fixed(&target, 4, false); + let result = hadamard_sparse(&mat1, &mat2, 3); + assert_sparse_mat_compare(&result, &target, I32F32::from_num(0.000001)); + let mat2: Vec = vec![1., 0., 0., 0., 2., 0., 0., 0., 3., 0., 0., 0.]; + let mat1: Vec = vec![0., 0., 4., 0., 5., 0., 6., 0., 0., 0., 0., 0.]; + let target: Vec = vec![0., 0., 0., 0., 10., 0., 0., 0., 0., 0., 0., 0.]; + let mat2 = vec_to_sparse_mat_fixed(&mat2, 4, false); + let mat1 = vec_to_sparse_mat_fixed(&mat1, 4, false); + let target = vec_to_sparse_mat_fixed(&target, 4, false); + let result = hadamard_sparse(&mat1, &mat2, 3); + assert_sparse_mat_compare(&result, &target, I32F32::from_num(0.000001)); + } - // Determine the higher index by ceiling the position. - let high = pos.ceil() as usize; + #[test] + fn test_math_mat_ema() { + let old: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; + let new: Vec = vec![ + 10., 20., 30., 40., 50., 60., 70., 80., 90., 100., 110., 120., + ]; + let target: Vec = vec![ + 1.9, 3.8, 5.7, 7.6, 9.5, 11.4, 13.3, 15.2, 17.1, 19., 20.9, 22.8, + ]; + let old = vec_to_mat_fixed(&old, 4, false); + let new = vec_to_mat_fixed(&new, 4, false); + let target = vec_to_mat_fixed(&target, 4, false); + let result = mat_ema(&new, &old, I32F32::from_num(0.1)); + assert_mat_compare(&result, &target, I32F32::from_num(0.000001)); + let old: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; + let new: Vec = vec![ + 10., 20., 30., 40., 50., 60., 70., 80., 90., 100., 110., 120., + ]; + let target: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; + let old = vec_to_mat_fixed(&old, 4, false); + let new = vec_to_mat_fixed(&new, 4, false); + let target = vec_to_mat_fixed(&target, 4, false); + let result = mat_ema(&new, &old, I32F32::from_num(0)); + assert_mat_compare(&result, &target, I32F32::from_num(0.000001)); + let old: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; + let new: Vec = vec![ + 10., 20., 30., 40., 50., 60., 70., 80., 90., 100., 110., 120., + ]; + let target: Vec = vec![ + 10., 20., 30., 40., 50., 60., 70., 80., 90., 100., 110., 120., + ]; + let old = vec_to_mat_fixed(&old, 4, false); + let new = vec_to_mat_fixed(&new, 4, false); + let target = vec_to_mat_fixed(&target, 4, false); + let result = mat_ema(&new, &old, I32F32::from_num(1)); + assert_mat_compare(&result, &target, I32F32::from_num(0.000001)); + } - // If the low and high indices are the same, return the value at that index. - if low == high { - sorted_data - .get(low) - .copied() - .unwrap_or_else(|| I32F32::from_num(0)) - } else { - // Otherwise, perform linear interpolation between the low and high values. - let low_value = sorted_data - .get(low) - .copied() - .unwrap_or_else(|| I32F32::from_num(0)); - let high_value = sorted_data - .get(high) - .copied() - .unwrap_or_else(|| I32F32::from_num(0)); + #[test] + fn test_math_sparse_mat_ema() { + let old: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; + let new: Vec = vec![ + 10., 20., 30., 40., 50., 60., 70., 80., 90., 100., 110., 120., + ]; + let target: Vec = vec![ + 1.9, 3.8, 5.7, 7.6, 9.5, 11.4, 13.3, 15.2, 17.1, 19., 20.9, 22.8, + ]; + 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 result = mat_ema_sparse(&new, &old, I32F32::from_num(0.1)); + assert_sparse_mat_compare(&result, &target, I32F32::from_num(0.000001)); + let old: Vec = vec![0., 2., 3., 4., 0., 6., 7., 8., 0., 10., 11., 12.]; + let new: Vec = vec![10., 20., 0., 40., 0., 60., 0., 80., 90., 100., 110., 120.]; + let target: Vec = vec![1., 3.8, 2.7, 7.6, 0., 11.4, 6.3, 15.2, 9., 19., 20.9, 22.8]; + 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 result = mat_ema_sparse(&new, &old, I32F32::from_num(0.1)); + assert_sparse_mat_compare(&result, &target, I32F32::from_num(0.000001)); + let old: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; + let new: Vec = vec![10., 20., 0., 40., 0., 60., 0., 80., 90., 100., 110., 120.]; + let target: Vec = vec![1., 2., 0., 4., 0., 6., 0., 8., 9., 10., 11., 12.]; + 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 result = mat_ema_sparse(&new, &old, I32F32::from_num(0.1)); + assert_sparse_mat_compare(&result, &target, I32F32::from_num(0.000001)); + let old: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; + let new: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; + let target: Vec = vec![0., 0., 0., 0., 0., 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 result = mat_ema_sparse(&new, &old, I32F32::from_num(0.1)); + assert_sparse_mat_compare(&result, &target, I32F32::from_num(0.000001)); + 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.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 result = mat_ema_sparse(&new, &old, I32F32::from_num(0.1)); + assert_sparse_mat_compare(&result, &target, I32F32::from_num(0.000001)); + } - // Calculate the weight for interpolation. - let weight = I32F32::from_num(pos - low as f64); + #[test] + fn test_math_matmul2() { + let epsilon: I32F32 = I32F32::from_num(0.0001); + let w: Vec> = vec![vec![I32F32::from_num(1.0); 3]; 3]; + assert_vec_compare( + &matmul(&w, &[I32F32::from_num(1.0); 3]), + &[ + I32F32::from_num(3), + I32F32::from_num(3), + I32F32::from_num(3), + ], + epsilon, + ); + assert_vec_compare( + &matmul(&w, &[I32F32::from_num(2.0); 3]), + &[ + I32F32::from_num(6), + I32F32::from_num(6), + I32F32::from_num(6), + ], + epsilon, + ); + assert_vec_compare( + &matmul(&w, &[I32F32::from_num(3.0); 3]), + &[ + I32F32::from_num(9), + I32F32::from_num(9), + I32F32::from_num(9), + ], + epsilon, + ); + assert_vec_compare( + &matmul(&w, &[I32F32::from_num(-1.0); 3]), + &[ + I32F32::from_num(-3), + I32F32::from_num(-3), + I32F32::from_num(-3), + ], + epsilon, + ); + let w: Vec> = vec![vec![I32F32::from_num(-1.0); 3]; 3]; + assert_vec_compare( + &matmul(&w, &[I32F32::from_num(1.0); 3]), + &[ + I32F32::from_num(-3), + I32F32::from_num(-3), + I32F32::from_num(-3), + ], + epsilon, + ); + assert_vec_compare( + &matmul(&w, &[I32F32::from_num(2.0); 3]), + &[ + I32F32::from_num(-6), + I32F32::from_num(-6), + I32F32::from_num(-6), + ], + epsilon, + ); + assert_vec_compare( + &matmul(&w, &[I32F32::from_num(3.0); 3]), + &[ + I32F32::from_num(-9), + I32F32::from_num(-9), + I32F32::from_num(-9), + ], + epsilon, + ); + assert_vec_compare( + &matmul(&w, &[I32F32::from_num(-1.0); 3]), + &[ + I32F32::from_num(3), + I32F32::from_num(3), + I32F32::from_num(3), + ], + epsilon, + ); + let w: Vec> = vec![ + vec![I32F32::from_num(1.0); 3], + vec![I32F32::from_num(2.0); 3], + vec![I32F32::from_num(3.0); 3], + ]; + assert_vec_compare( + &matmul(&w, &[I32F32::from_num(0.0); 3]), + &[ + I32F32::from_num(0.0), + I32F32::from_num(0.0), + I32F32::from_num(0.0), + ], + epsilon, + ); + assert_vec_compare( + &matmul(&w, &[I32F32::from_num(2.0); 3]), + &[ + I32F32::from_num(12), + I32F32::from_num(12), + I32F32::from_num(12), + ], + epsilon, + ); + let w: Vec> = vec![ + vec![ + I32F32::from_num(1), + I32F32::from_num(2), + I32F32::from_num(3) + ]; + 3 + ]; + assert_vec_compare( + &matmul(&w, &[I32F32::from_num(0.0); 3]), + &[ + I32F32::from_num(0.0), + I32F32::from_num(0.0), + I32F32::from_num(0.0), + ], + epsilon, + ); + assert_vec_compare( + &matmul(&w, &[I32F32::from_num(2.0); 3]), + &[ + I32F32::from_num(6), + I32F32::from_num(12), + I32F32::from_num(18), + ], + epsilon, + ); + } - // Return the interpolated value using saturating operations. - low_value.saturating_add((high_value.saturating_sub(low_value)).saturating_mul(weight)) + #[test] + fn test_math_fixed_to_u16() { + let expected = u16::MIN; + assert_eq!(fixed_to_u16(I32F32::from_num(expected)), expected); + + let expected = u16::MAX / 2; + assert_eq!(fixed_to_u16(I32F32::from_num(expected)), expected); + + let expected = u16::MAX; + assert_eq!(fixed_to_u16(I32F32::from_num(expected)), expected); } -} -/// Safe ln function, returns 0 if value is 0. -pub fn safe_ln(value: I32F32) -> I32F32 { - ln(value).unwrap_or(I32F32::from_num(0.0)) -} + #[test] + #[should_panic(expected = "overflow")] + fn test_math_fixed_to_u16_panics() { + let bad_input = I32F32::from_num(u32::MAX); + fixed_to_u16(bad_input); + + let bad_input = I32F32::from_num(-1); + fixed_to_u16(bad_input); + } + + // TODO: Investigate why `I32F32` and not `I64F64` + #[test] + fn test_math_fixed_to_u64() { + let expected = u64::MIN; + assert_eq!(fixed_to_u64(I32F32::from_num(expected)), expected); + + // let expected = u64::MAX / 2; + // assert_eq!(fixed_to_u64(I32F32::from_num(expected)), expected); -/// Safe exp function, returns 0 if value is 0. -pub fn safe_exp(value: I32F32) -> I32F32 { - exp(value).unwrap_or(I32F32::from_num(0.0)) + // let expected = u64::MAX; + // assert_eq!(fixed_to_u64(I32F32::from_num(expected)), expected); + } + + #[test] + #[should_panic(expected = "-1 overflows")] + fn test_math_fixed_to_u64_panics() { + let bad_input = I32F32::from_num(-1); + fixed_to_u64(bad_input); + } + + #[test] + fn test_math_fixed64_to_u64() { + let expected = u64::MIN; + assert_eq!(fixed64_to_u64(I64F64::from_num(expected)), expected); + + let input = i64::MAX / 2; + let expected = u64::try_from(input).unwrap(); + assert_eq!(fixed64_to_u64(I64F64::from_num(input)), expected); + + let input = i64::MAX; + let expected = u64::try_from(input).unwrap(); + assert_eq!(fixed64_to_u64(I64F64::from_num(input)), expected); + } + + #[test] + #[should_panic(expected = "-1 overflows")] + fn test_math_fixed64_to_u64_panics() { + let bad_input = I64F64::from_num(-1); + fixed64_to_u64(bad_input); + } + + /* @TODO: find the _true_ max, and half, input values */ + #[test] + fn test_math_fixed64_to_fixed32() { + let input = u64::MIN; + let expected = u32::try_from(input).unwrap(); + assert_eq!(fixed64_to_fixed32(I64F64::from_num(expected)), expected); + + let expected = u32::MAX / 2; + let input = u64::from(expected); + assert_eq!(fixed64_to_fixed32(I64F64::from_num(input)), expected); + } + + #[test] + #[should_panic(expected = "overflow")] + fn test_math_fixed64_to_fixed32_panics() { + let bad_input = I64F64::from_num(u32::MAX); + fixed64_to_fixed32(bad_input); + } + + #[test] + fn test_math_u16_to_fixed() { + let input = u16::MIN; + let expected = I32F32::from_num(input); + assert_eq!(u16_to_fixed(input), expected); + + let input = u16::MAX / 2; + let expected = I32F32::from_num(input); + assert_eq!(u16_to_fixed(input), expected); + + let input = u16::MAX; + let expected = I32F32::from_num(input); + assert_eq!(u16_to_fixed(input), expected); + } + + #[test] + fn test_math_u16_proportion_to_fixed() { + let input = u16::MIN; + let expected = I32F32::from_num(input); + assert_eq!(u16_proportion_to_fixed(input), expected); + } + + #[test] + fn test_fixed_proportion_to_u16() { + let expected = u16::MIN; + let input = I32F32::from_num(expected); + assert_eq!(fixed_proportion_to_u16(input), expected); + } + + #[test] + #[should_panic(expected = "overflow")] + fn test_fixed_proportion_to_u16_panics() { + let expected = u16::MAX; + let input = I32F32::from_num(expected); + fixed_proportion_to_u16(input); + } + + #[test] + fn test_vec_fixed64_to_fixed32() { + let input = vec![I64F64::from_num(i32::MIN)]; + let expected = vec![I32F32::from_num(i32::MIN)]; + assert_eq!(vec_fixed64_to_fixed32(input), expected); + + let input = vec![I64F64::from_num(i32::MAX)]; + let expected = vec![I32F32::from_num(i32::MAX)]; + assert_eq!(vec_fixed64_to_fixed32(input), expected); + } + + #[test] + #[should_panic(expected = "overflow")] + fn test_vec_fixed64_to_fixed32_panics() { + let bad_input = vec![I64F64::from_num(i64::MAX)]; + vec_fixed64_to_fixed32(bad_input); + } + + #[test] + #[allow(arithmetic_overflow)] + fn test_checked_sum() { + let overflowing_input = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, u64::MAX]; + // Expect None when overflow occurs + assert_eq!(checked_sum(&overflowing_input), None); + + let normal_input = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + // Expect Some when no overflow occurs + assert_eq!(checked_sum(&normal_input), Some(55)); + + let empty_input: Vec = vec![]; + // Expect Some(u16::default()) when input is empty + assert_eq!(checked_sum(&empty_input), Some(u16::default())); + + let single_input = vec![1]; + // Expect Some(...) when input is a single value + assert_eq!(checked_sum(&single_input), Some(1)); + } } diff --git a/pallets/subtensor/src/subnet_info.rs b/pallets/subtensor/src/subnet_info.rs index 4e9e756a0..bb6f5d4c8 100644 --- a/pallets/subtensor/src/subnet_info.rs +++ b/pallets/subtensor/src/subnet_info.rs @@ -27,7 +27,7 @@ pub struct SubnetInfo { owner: T::AccountId, } -#[freeze_struct("55b472510f10e76a")] +#[freeze_struct("76f4053b3cc4c7ec")] #[derive(Decode, Encode, PartialEq, Eq, Clone, Debug)] pub struct SubnetHyperparams { rho: Compact, @@ -54,9 +54,6 @@ pub struct SubnetHyperparams { difficulty: Compact, commit_reveal_weights_interval: Compact, commit_reveal_weights_enabled: bool, - alpha_high: Compact, - alpha_low: Compact, - liquid_alpha_enabled: bool, } impl Pallet { @@ -160,8 +157,6 @@ impl Pallet { let difficulty = Self::get_difficulty_as_u64(netuid); let commit_reveal_weights_interval = Self::get_commit_reveal_weights_interval(netuid); let commit_reveal_weights_enabled = Self::get_commit_reveal_weights_enabled(netuid); - let liquid_alpha_enabled = Self::get_liquid_alpha_enabled(netuid); - let (alpha_low, alpha_high): (u16, u16) = Self::get_alpha_values(netuid); Some(SubnetHyperparams { rho: rho.into(), @@ -188,9 +183,6 @@ impl Pallet { difficulty: difficulty.into(), commit_reveal_weights_interval: commit_reveal_weights_interval.into(), commit_reveal_weights_enabled, - alpha_high: alpha_high.into(), - alpha_low: alpha_low.into(), - liquid_alpha_enabled, }) } } diff --git a/pallets/subtensor/src/utils.rs b/pallets/subtensor/src/utils.rs index 73e10f4bd..c21ce6a20 100644 --- a/pallets/subtensor/src/utils.rs +++ b/pallets/subtensor/src/utils.rs @@ -1,12 +1,7 @@ use super::*; -use crate::{ - system::{ensure_root, ensure_signed_or_root}, - Error, -}; +use crate::system::{ensure_root, ensure_signed_or_root}; use sp_core::Get; - use sp_core::U256; -use substrate_fixed::types::I32F32; impl Pallet { pub fn ensure_subnet_owner_or_root( @@ -667,24 +662,5 @@ impl Pallet { pub fn get_hotkey_swap_cost() -> u64 { T::HotkeySwapCost::get() - - pub fn get_alpha_values(netuid: u16) -> (u16, u16) { - AlphaValues::::get(netuid) - } - - pub fn get_alpha_values_32(netuid: u16) -> (I32F32, I32F32) { - let (alpha_low, alpha_high): (u16, u16) = AlphaValues::::get(netuid); - let converted_low = I32F32::from_num(alpha_low).saturating_div(I32F32::from_num(u16::MAX)); - let converted_high = - I32F32::from_num(alpha_high).saturating_div(I32F32::from_num(u16::MAX)); - (converted_low, converted_high) - } - - pub fn set_liquid_alpha_enabled(netuid: u16, enabled: bool) { - LiquidAlphaOn::::set(netuid, enabled); - } - - pub fn get_liquid_alpha_enabled(netuid: u16) -> bool { - LiquidAlphaOn::::get(netuid) } } diff --git a/pallets/subtensor/tests/epoch.rs b/pallets/subtensor/tests/epoch.rs index 676b3cd35..635b4fc0b 100644 --- a/pallets/subtensor/tests/epoch.rs +++ b/pallets/subtensor/tests/epoch.rs @@ -5,16 +5,12 @@ )] use crate::mock::*; -use frame_support::{assert_err, assert_ok}; +use frame_support::assert_ok; use frame_system::Config; -use pallet_subtensor::math::safe_exp; -use pallet_subtensor::*; use rand::{distributions::Uniform, rngs::StdRng, seq::SliceRandom, thread_rng, Rng, SeedableRng}; use sp_core::U256; -use sp_runtime::DispatchError; use std::time::Instant; use substrate_fixed::types::I32F32; - mod mock; pub fn fixed(val: f32) -> I32F32 { @@ -1272,254 +1268,6 @@ fn test_bonds() { }); } -#[test] -fn test_bonds_with_liquid_alpha() { - new_test_ext(1).execute_with(|| { - let sparse: bool = true; - let n: u16 = 8; - let netuid: u16 = 1; - let tempo: u16 = u16::MAX - 1; // high tempo to skip automatic epochs in on_initialize, use manual epochs instead - let max_stake: u64 = 4; - let stakes: Vec = vec![1, 2, 3, 4, 0, 0, 0, 0]; - let block_number = System::block_number(); - add_network(netuid, tempo, 0); - SubtensorModule::set_max_allowed_uids(netuid, n); - SubtensorModule::set_max_registrations_per_block(netuid, n); - SubtensorModule::set_target_registrations_per_interval(netuid, n); - SubtensorModule::set_weights_set_rate_limit(netuid, 0); - SubtensorModule::set_min_allowed_weights(netuid, 1); - SubtensorModule::set_max_weight_limit(netuid, u16::MAX); - - // Register validators and servers - for key in 0..n as u64 { - SubtensorModule::add_balance_to_coldkey_account(&U256::from(key), max_stake); - let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - block_number, - key * 1_000_000, - &U256::from(key), - ); - assert_ok!(SubtensorModule::register( - <::RuntimeOrigin>::signed(U256::from(key)), - netuid, - block_number, - nonce, - work, - U256::from(key), - U256::from(key) - )); - SubtensorModule::increase_stake_on_coldkey_hotkey_account( - &U256::from(key), - &U256::from(key), - stakes[key as usize], - ); - } - - // Initilize with first epoch - SubtensorModule::epoch(netuid, 1_000_000_000); - next_block(); - - // Set weights - for uid in 0..(n / 2) { - SubtensorModule::set_validator_permit_for_uid(netuid, uid, true); - assert_ok!(SubtensorModule::set_weights( - RuntimeOrigin::signed(U256::from(uid)), - netuid, - ((n / 2)..n).collect(), - vec![u16::MAX / 4, u16::MAX / 2, (u16::MAX / 4) * 3, u16::MAX], - 0 - )); - } - - // Enable Liquid Alpha - SubtensorModule::set_liquid_alpha_enabled(netuid, true); - // Run epoch with Liquid Alpha - if sparse { - SubtensorModule::epoch(netuid, 1_000_000_000); - } else { - SubtensorModule::epoch_dense(netuid, 1_000_000_000); - } - - // Check bonds and emissions - let bonds = SubtensorModule::get_bonds(netuid); - - /* n: 8 - current_block: 2; activity_cutoff: 5000; - Last update: [1, 1, 1, 1, 0, 0, 0, 0] - activity_cutoff: 5000 - Last update: [2, 2, 2, 2, 1, 1, 1, 1] - Inactive: [false, false, false, false, false, false, false, false] - Block at registration: [1, 1, 1, 1, 1, 1, 1, 1] - hotkeys: [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6), (7, 7)] - Stake: [1, 2, 3, 4, 0, 0, 0, 0] - Normalised Stake: [0.0999999999, 0.2, 0.2999999998, 0.4, 0, 0, 0, 0] - validator_permits: [true, true, true, true, true, true, true, true] - max_allowed_validators: 8 - new_validator_permits: [true, true, true, true, true, true, true, true] - Active Stake: [0.0999999999, 0.2, 0.2999999998, 0.4, 0, 0, 0, 0] - Weights: [[(4, 16383), (5, 32767), (6, 49149), (7, 65535)], [(4, 16383), (5, 32767), (6, 49149), (7, 65535)], [(4, 16383), (5, 32767), (6, 49149), (7, 65535)], [(4, 16383), (5, 32767), (6, 49149), (7, 65535)], [], [], [], []] - Weights (permit): [[(4, 16383), (5, 32767), (6, 49149), (7, 65535)], [(4, 16383), (5, 32767), (6, 49149), (7, 65535)], [(4, 16383), (5, 32767), (6, 49149), (7, 65535)], [(4, 16383), (5, 32767), (6, 49149), (7, 65535)], [], [], [], []] - Weights (permit+diag): [[(4, 16383), (5, 32767), (6, 49149), (7, 65535)], [(4, 16383), (5, 32767), (6, 49149), (7, 65535)], [(4, 16383), (5, 32767), (6, 49149), (7, 65535)], [(4, 16383), (5, 32767), (6, 49149), (7, 65535)], [], [], [], []] - Weights (permit+diag+outdate): [[(4, 16383), (5, 32767), (6, 49149), (7, 65535)], [(4, 16383), (5, 32767), (6, 49149), (7, 65535)], [(4, 16383), (5, 32767), (6, 49149), (7, 65535)], [(4, 16383), (5, 32767), (6, 49149), (7, 65535)], [], [], [], []] - Weights (mask+norm): [[(4, 0.0999975584), (5, 0.2000012207), (6, 0.2999926754), (7, 0.400008545)], [(4, 0.0999975584), (5, 0.2000012207), (6, 0.2999926754), (7, 0.400008545)], [(4, 0.0999975584), (5, 0.2000012207), (6, 0.2999926754), (7, 0.400008545)], [(4, 0.0999975584), (5, 0.2000012207), (6, 0.2999926754), (7, 0.400008545)], [], [], [], []] - Ranks (before): [0, 0, 0, 0, 0.099997558, 0.2000012202, 0.2999926745, 0.4000085443] - Consensus: [0, 0, 0, 0, 0.0999975584, 0.2000012207, 0.2999926754, 0.400008545] - Weights: [[(4, 0.0999975584), (5, 0.2000012207), (6, 0.2999926754), (7, 0.400008545)], [(4, 0.0999975584), (5, 0.2000012207), (6, 0.2999926754), (7, 0.400008545)], [(4, 0.0999975584), (5, 0.2000012207), (6, 0.2999926754), (7, 0.400008545)], [(4, 0.0999975584), (5, 0.2000012207), (6, 0.2999926754), (7, 0.400008545)], [], [], [], []] - Validator Trust: [0.9999999995, 0.9999999995, 0.9999999995, 0.9999999995, 0, 0, 0, 0] - Ranks (after): [0, 0, 0, 0, 0.099997558, 0.2000012202, 0.2999926745, 0.4000085443] - T: [0, 0, 0, 0, 1, 1, 1, 1] - Incentive (=Rank): [0, 0, 0, 0, 0.0999975582, 0.2000012207, 0, 0.0999975582, 0.2000012207, 0.2999926752, 0.4000085455] - B: [[], [], [], [], [], [], [], []] - B (outdatedmask): [[], [], [], [], [], [], [], []] - B (mask+norm): [[], [], [], [], [], [], [], []] - ΔB: [[(4, 0.0099997558), (5, 0.020000122), (6, 0.0299992673), (7, 0.0400008543)], [(4, 0.0199995115), (5, 0.040000244), (6, 0.0599985349), (7, 0.0800017088)], [(4, 0.0299992673), (5, 0.060000366), (6, 0.0899978024), (7, 0.1200025633)], [(4, 0.0399990233), (5, 0.080000488), (6, 0.11999707), (7, 0.1600034179)], [], [], [], []] - ΔB (norm): [[(4, 0.0999999996), (5, 0.0999999999), (6, 0.0999999994), (7, 0.0999999996)], [(4, 0.1999999995), (5, 0.2), (6, 0.1999999997), (7, 0.1999999997)], [(4, 0.299999999), (5, 0.2999999998), (6, 0.3), (7, 0.3)], [(4, 0.4000000013), (5, 0.4), (6, 0.4000000004), (7, 0.4000000001)], [], [], [], []] - Exponential Moving Average Bonds Liquid Alpha: [[(4, 0.0499983232), (5, 0.0899999999), (6, 0.0899999994), (7, 0.0899999996)], [(4, 0.0999966469), (5, 0.18), (6, 0.1799999997), (7, 0.1799999997)], [(4, 0.1499949703), (5, 0.2699999998), (6, 0.2699999998), (7, 0.2699999998)], [(4, 0.199993295), (5, 0.3599999999), (6, 0.36), (7, 0.3599999999)], [], [], [], []] - Exponential Moving Average Bonds: [[(4, 0.0999999992), (5, 0.0999999999), (6, 0.0999999994), (7, 0.0999999996)], [(4, 0.1999999995), (5, 0.2), (6, 0.1999999997), (7, 0.1999999997)], [(4, 0.2999999993), (5, 0.2999999998), (6, 0.3), (7, 0.3)], [(4, 0.4000000015), (5, 0.4), (6, 0.4000000004), (7, 0.4000000001)], [], [], [], []] - Dividends: [0.0999999994, 0.1999999997, 0.3, 0.4000000006, 0, 0, 0, 0] - Normalized Server Emission: [0, 0, 0, 0, 0.049998779, 0.1000006103, 0.1499963375, 0.2000042726] - Server Emission: [0, 0, 0, 0, 49998779, 100000610, 149996337, 200004272] - Normalized Validator Emission: [0.0499999996, 0.0999999999, 0.15, 0.2000000002, 0, 0, 0, 0] - Validator Emission: [49999999, 99999999, 149999999, 200000000, 0, 0, 0, 0] - Normalized Combined Emission: [0.0499999996, 0.0999999999, 0.15, 0.2000000002, 0.049998779, 0.1000006103, 0.1499963375, 0.2000042726] - Combined Emission: [49999999, 99999999, 149999999, 200000000, 49998779, 100000610, 149996337, 200004272] - Pruning Scores: [0.0499999996, 0.0999999999, 0.15, 0.2000000002, 0.049998779, 0.1000006103, 0.1499963375, 0.2000042726] - */ - - // Expected bonds calculations - // For uid 0: - // Initial weights: [0.25, 0.5, 0.75, 1.0] - // Active stake: [1, 2, 3, 4] - // ΔB = W◦S = [0.25*1, 0.5*2, 0.75*3, 1.0*4] = [0.25, 1.0, 2.25, 4.0] - // Normalize ΔB: [0.25/7.5, 1.0/7.5, 2.25/7.5, 4.0/7.5] = [0.0333, 0.1333, 0.3, 0.5333] - // Final bonds for netuid: [16383, 32767, 49151, 65535] - - assert_eq!(bonds[0][4], 16383); // Note: Calculated as explained above - assert_eq!(bonds[1][4], 32767); // Note: Calculated as explained above - assert_eq!(bonds[2][4], 49151); // Note: Calculated as explained above - assert_eq!(bonds[3][4], 65535); // Note: Calculated as explained above - - // === Set self-weight only on val1 - let uid = 0; - assert_ok!(SubtensorModule::set_weights( - RuntimeOrigin::signed(U256::from(uid)), - netuid, - vec![uid], - vec![u16::MAX], - 0 - )); - next_block(); - if sparse { - SubtensorModule::epoch(netuid, 1_000_000_000); - } else { - SubtensorModule::epoch_dense(netuid, 1_000_000_000); - } - - let bonds = SubtensorModule::get_bonds(netuid); - assert_eq!(bonds[0][4], 2862); - assert_eq!(bonds[1][4], 32767); - assert_eq!(bonds[2][4], 49151); - assert_eq!(bonds[3][4], 65535); - - // === Set self-weight only on val2 - let uid = 1; - assert_ok!(SubtensorModule::set_weights( - RuntimeOrigin::signed(U256::from(uid)), - netuid, - vec![uid], - vec![u16::MAX], - 0 - )); - next_block(); - if sparse { - SubtensorModule::epoch(netuid, 1_000_000_000); - } else { - SubtensorModule::epoch_dense(netuid, 1_000_000_000); - } - let bonds = SubtensorModule::get_bonds(netuid); - - /* n: 8 - current_block: 4; activity_cutoff: 5000; - Last update: [2, 3, 2, 2, 1, 1, 1, 1] - Inactive: [false, false, false, false, false, false, false, false] - Block at registration: [1, 1, 1, 1, 1, 1, 1, 1] - hotkeys: [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6), (7, 7)] - Stake: [1, 2, 3, 4, 0, 0, 0, 0] - Normalised Stake: [0.0999999999, 0.2, 0.2999999998, 0.4, 0, 0, 0, 0] - validator_permits: [true, true, true, true, true, true, true, true] - max_allowed_validators: 64 - new_validator_permits: [true, true, true, true, true, true, true, true] - Active Stake: [0.0999999999, 0.2, 0.2999999998, 0.4, 0, 0, 0, 0] - Weights: [[(0, 65535)], [(1, 65535)], [(4, 16383), (5, 32767), (6, 49149), (7, 65535)], [(4, 16383), (5, 32767), (6, 49149), (7, 65535)], [], [], [], []] - Weights (permit): [[(0, 65535)], [(1, 65535)], [(4, 16383), (5, 32767), (6, 49149), (7, 65535)], [(4, 16383), (5, 32767), (6, 49149), (7, 65535)], [], [], [], []] - Weights (permit+diag): [[], [], [(4, 16383), (5, 32767), (6, 49149), (7, 65535)], [(4, 16383), (5, 32767), (6, 49149), (7, 65535)], [], [], [], []] - Weights (permit+diag+outdate): [[], [], [(4, 16383), (5, 32767), (6, 49149), (7, 65535)], [(4, 16383), (5, 32767), (6, 49149), (7, 65535)], [], [], [], []] - Weights (mask+norm): [[], [], [(4, 0.0999975584), (5, 0.2000012207), (6, 0.2999926754), (7, 0.400008545)], [(4, 0.0999975584), (5, 0.2000012207), (6, 0.2999926754), (7, 0.400008545)], [], [], [], []] - Ranks (before): [0, 0, 0, 0, 0.0699982906, 0.1400008542, 0.2099948723, 0.2800059812] - Consensus: [0, 0, 0, 0, 0.0999975584, 0.2000012207, 0.2999926754, 0.400008545] - Weights: [[], [], [(4, 0.0999975584), (5, 0.2000012207), (6, 0.2999926754), (7, 0.400008545)], [(4, 0.0999975584), (5, 0.2000012207), (6, 0.2999926754), (7, 0.400008545)], [], [], [], []] - Validator Trust: [0, 0, 0.9999999995, 0.9999999995, 0, 0, 0, 0] - Ranks (after): [0, 0, 0, 0, 0.0699982906, 0.1400008542, 0.2099948723, 0.2800059812] - T: [0, 0, 0, 0, 1, 1, 1, 1] - Incentive (=Rank): [0, 0, 0, 0, 0.0999975582, 0.2000012207, 0.2999926754, 0.4000085455] - B: [[(4, 7760), (5, 1489), (6, 1489), (7, 1489)], [(4, 32767), (5, 32767), (6, 32767), (7, 32767)], [(4, 49151), (5, 49151), (6, 49151), (7, 49151)], [(4, 65535), (5, 65535), (6, 65535), (7, 65535)], [], [], [], []] - B (outdatedmask): [[(4, 7760), (5, 1489), (6, 1489), (7, 1489)], [(4, 32767), (5, 32767), (6, 32767), (7, 32767)], [(4, 49151), (5, 49151), (6, 49151), (7, 49151)], [(4, 65535), (5, 65535), (6, 65535), (7, 65535)], [], [], [], []] - B (mask+norm): [[(4, 0.0499958121), (5, 0.00999718), (6, 0.00999718), (7, 0.00999718)], [(4, 0.211109894), (5, 0.2199983886), (6, 0.2199983886), (7, 0.2199983886)], [(4, 0.3166680625), (5, 0.3300009398), (6, 0.3300009398), (7, 0.3300009398)], [(4, 0.4222262308), (5, 0.4400034912), (6, 0.4400034912), (7, 0.4400034912)], [], [], [], []] - ΔB: [[], [], [(4, 0.0299992673), (5, 0.060000366), (6, 0.0899978024), (7, 0.1200025633)], [(4, 0.0399990233), (5, 0.080000488), (6, 0.11999707), (7, 0.1600034179)], [], [], [], []] - ΔB (norm): [[], [], [(4, 0.428571427), (5, 0.4285714284), (6, 0.4285714284), (7, 0.4285714284)], [(4, 0.5714285728), (5, 0.5714285714), (6, 0.5714285714), (7, 0.5714285714)], [], [], [], []] - Exponential Moving Average Bonds Liquid Alpha: [[(4, 0.024998744), (5, 0.000999718), (6, 0.000999718), (7, 0.000999718)], [(4, 0.105558486), (5, 0.0219998388), (6, 0.0219998388), (7, 0.0219998388)], [(4, 0.3726178685), (5, 0.4187143792), (6, 0.4187143792), (7, 0.4187143792)], [(4, 0.4968249004), (5, 0.5582860631), (6, 0.5582860631), (7, 0.5582860631)], [], [], [], []] - Exponential Moving Average Bonds: [[(4, 0.024998744), (5, 0.000999718), (6, 0.000999718), (7, 0.000999718)], [(4, 0.105558486), (5, 0.0219998388), (6, 0.0219998388), (7, 0.0219998388)], [(4, 0.3726178687), (5, 0.4187143794), (6, 0.4187143794), (7, 0.4187143794)], [(4, 0.4968249009), (5, 0.5582860636), (6, 0.5582860636), (7, 0.5582860636)], [], [], [], []] - Dividends: [0.0033995616, 0.030355499, 0.4141048414, 0.5521400978, 0, 0, 0, 0] - Normalized Server Emission: [0, 0, 0, 0, 0.049998779, 0.1000006103, 0.1499963377, 0.2000042726] - Server Emission: [0, 0, 0, 0, 49998779, 100000610, 149996337, 200004272] - Normalized Validator Emission: [0.0016997808, 0.0151777493, 0.2070524206, 0.2760700488, 0, 0, 0, 0] - Validator Emission: [1699780, 15177749, 207052420, 276070048, 0, 0, 0, 0] - Normalized Combined Emission: [0.0016997808, 0.0151777493, 0.2070524206, 0.2760700488, 0.049998779, 0.1000006103, 0.1499963377, 0.2000042726] - Combined Emission: [1699780, 15177749, 207052420, 276070048, 49998779, 100000610, 149996337, 200004272] - Pruning Scores: [0.0016997808, 0.0151777493, 0.2070524206, 0.2760700488, 0.049998779, 0.1000006103, 0.1499963377, 0.2000042726] - */ - - assert_eq!(bonds[0][4], 435); - assert_eq!(bonds[1][4], 4985); - assert_eq!(bonds[2][4], 49151); - assert_eq!(bonds[3][4], 65535); - }); -} - -#[test] -fn test_set_alpha_disabled() { - new_test_ext(1).execute_with(|| { - let netuid: u16 = 1; - let hotkey: U256 = U256::from(1); - let coldkey: U256 = U256::from(1 + 456); - let signer = <::RuntimeOrigin>::signed(coldkey); - - // Enable Liquid Alpha and setup - SubtensorModule::set_liquid_alpha_enabled(netuid, true); - migration::migrate_create_root_network::(); - SubtensorModule::add_balance_to_coldkey_account(&coldkey, 1_000_000_000_000_000); - assert_ok!(SubtensorModule::root_register(signer.clone(), hotkey,)); - assert_ok!(SubtensorModule::add_stake(signer.clone(), hotkey, 1000)); - // Only owner can set alpha values - assert_ok!(SubtensorModule::register_network(signer.clone())); - - // Explicitly set to false - SubtensorModule::set_liquid_alpha_enabled(netuid, false); - assert_err!( - SubtensorModule::do_set_alpha_values(signer.clone(), netuid, 12_u16, u16::MAX), - Error::::LiquidAlphaDisabled - ); - - SubtensorModule::set_liquid_alpha_enabled(netuid, true); - assert_ok!(SubtensorModule::do_set_alpha_values( - signer.clone(), - netuid, - 12_u16, - u16::MAX - )); - }); -} - // Test that epoch masks out inactive stake of validators with outdated weights beyond activity cutoff. #[test] fn test_active_stake() { @@ -2230,480 +1978,6 @@ fn test_validator_permits() { } } -#[test] -fn test_compute_alpha_values() { - // Define the consensus values. - let consensus = vec![ - I32F32::from_num(0.1), - I32F32::from_num(0.5), - I32F32::from_num(0.9), - ]; - // Define the logistic function parameters 'a' and 'b'. - let a = I32F32::from_num(1.0); - let b = I32F32::from_num(0.0); - - // Compute the alpha values using the function. - let alpha = SubtensorModule::compute_alpha_values(&consensus, a, b); - - // Ensure the length of the alpha vector matches the consensus vector. - assert_eq!(alpha.len(), consensus.len()); - - // Manually compute the expected alpha values for each consensus value. - // The logistic function is: 1 / (1 + exp(b - a * c)) - // where c is the consensus value. - - // For consensus[0] = 0.1: - // exp_val = exp(0.0 - 1.0 * 0.1) = exp(-0.1) - // alpha[0] = 1 / (1 + exp(-0.1)) ~ 0.9048374180359595 - let exp_val_0 = I32F32::from_num(0.9048374180359595); - let expected_alpha_0 = - I32F32::from_num(1.0).saturating_div(I32F32::from_num(1.0).saturating_add(exp_val_0)); - - // For consensus[1] = 0.5: - // exp_val = exp(0.0 - 1.0 * 0.5) = exp(-0.5) - // alpha[1] = 1 / (1 + exp(-0.5)) ~ 0.6065306597126334 - let exp_val_1 = I32F32::from_num(0.6065306597126334); - let expected_alpha_1 = - I32F32::from_num(1.0).saturating_div(I32F32::from_num(1.0).saturating_add(exp_val_1)); - - // For consensus[2] = 0.9: - // exp_val = exp(0.0 - 1.0 * 0.9) = exp(-0.9) - // alpha[2] = 1 / (1 + exp(-0.9)) ~ 0.4065696597405991 - let exp_val_2 = I32F32::from_num(0.4065696597405991); - let expected_alpha_2 = - I32F32::from_num(1.0).saturating_div(I32F32::from_num(1.0).saturating_add(exp_val_2)); - - // Define an epsilon for approximate equality checks. - let epsilon = I32F32::from_num(1e-6); - - // Assert that the computed alpha values match the expected values within the epsilon. - assert_approx_eq(alpha[0], expected_alpha_0, epsilon); - assert_approx_eq(alpha[1], expected_alpha_1, epsilon); - assert_approx_eq(alpha[2], expected_alpha_2, epsilon); -} - -#[test] -fn test_compute_alpha_values_256_miners() { - // Define the consensus values for 256 miners. - let consensus: Vec = (0..256) - .map(|i| I32F32::from_num(i as f32 / 255.0)) - .collect(); - // Define the logistic function parameters 'a' and 'b'. - let a = I32F32::from_num(1.0); - let b = I32F32::from_num(0.0); - - // Compute the alpha values using the function. - let alpha = SubtensorModule::compute_alpha_values(&consensus, a, b); - - // Ensure the length of the alpha vector matches the consensus vector. - assert_eq!(alpha.len(), consensus.len()); - - // Define an epsilon for approximate equality checks. - let epsilon = I32F32::from_num(1e-6); - - for (i, &c) in consensus.iter().enumerate() { - // Use saturating subtraction and multiplication - let exponent = b.saturating_sub(a.saturating_mul(c)); - - // Use safe_exp instead of exp - let exp_val = safe_exp(exponent); - - // Use saturating addition and division - let expected_alpha = - I32F32::from_num(1.0).saturating_div(I32F32::from_num(1.0).saturating_add(exp_val)); - - // Assert that the computed alpha values match the expected values within the epsilon. - assert_approx_eq(alpha[i], expected_alpha, epsilon); - } -} - -#[test] -fn test_clamp_alpha_values() { - // Define the alpha values. - let alpha = vec![ - I32F32::from_num(0.1), - I32F32::from_num(0.5), - I32F32::from_num(0.9), - ]; - // Define the high and low clamping values. - let alpha_high = I32F32::from_num(0.8); - let alpha_low = I32F32::from_num(0.2); - - // Compute the clamped alpha values using the function. - let clamped_alpha = SubtensorModule::clamp_alpha_values(alpha.clone(), alpha_high, alpha_low); - - // Ensure the length of the clamped alpha vector matches the original alpha vector. - assert_eq!(clamped_alpha.len(), alpha.len()); - - // Manually compute the expected clamped alpha values for each alpha value. - // The clamping logic is: max(alpha_low, min(alpha_high, a)) - - // For alpha[0] = 0.1: - // clamped_a = max(0.2, min(0.8, 0.1)) = max(0.2, 0.1) = 0.2 - let expected_clamped_alpha_0 = I32F32::from_num(0.2); - - // For alpha[1] = 0.5: - // clamped_a = max(0.2, min(0.8, 0.5)) = max(0.2, 0.5) = 0.5 - let expected_clamped_alpha_1 = I32F32::from_num(0.5); - - // For alpha[2] = 0.9: - // clamped_a = max(0.2, min(0.8, 0.9)) = max(0.2, 0.8) = 0.8 - let expected_clamped_alpha_2 = I32F32::from_num(0.8); - - // Assert that the computed clamped alpha values match the expected values. - assert_eq!(clamped_alpha[0], expected_clamped_alpha_0); - assert_eq!(clamped_alpha[1], expected_clamped_alpha_1); - assert_eq!(clamped_alpha[2], expected_clamped_alpha_2); -} - -#[test] -fn test_calculate_logistic_params() { - // Define test inputs - let alpha_high = I32F32::from_num(0.9); - let alpha_low = I32F32::from_num(0.1); - let consensus_high = I32F32::from_num(0.8); - let consensus_low = I32F32::from_num(0.2); - - // Expected values - // a = (ln((1 / alpha_high - 1)) - ln((1 / alpha_low - 1))) / (consensus_low - consensus_high) - // = (ln((1 / 0.9 - 1)) - ln((1 / 0.1 - 1))) / (0.2 - 0.8) - // = (ln(0.1111) - ln(9)) / -0.6 - // = (-2.1972 - 2.1972) / -0.6 - // = -4.3944 / -0.6 - // = 7.324 - let expected_a = I32F32::from_num(7.324); - - // b = ln((1 / alpha_low - 1)) + a * consensus_low - // = ln((1 / 0.1 - 1)) + 7.324 * 0.2 - // = ln(9) + 1.4648 - // = 2.1972 + 1.4648 - // = 3.662 - let expected_b = I32F32::from_num(3.662); - - // Call the function - let (a, b) = SubtensorModule::calculate_logistic_params( - alpha_high, - alpha_low, - consensus_high, - consensus_low, - ); - - // Assert the results - assert!( - (a - expected_a).abs() < I32F32::from_num(0.001), - "Expected a: {:?}, got: {:?}", - expected_a, - a - ); - assert!( - (b - expected_b).abs() < I32F32::from_num(0.001), - "Expected b: {:?}, got: {:?}", - expected_b, - b - ); -} - -#[test] -fn test_calculate_logistic_params_edge_cases() { - // Edge Case 1: Alpha values at their boundaries (0 and 1) - let alpha_high = I32F32::from_num(1.0); - let alpha_low = I32F32::from_num(0.0); - let consensus_high = I32F32::from_num(0.8); - let consensus_low = I32F32::from_num(0.2); - - // Call the function - let (a, b) = SubtensorModule::calculate_logistic_params( - alpha_high, - alpha_low, - consensus_high, - consensus_low, - ); - - // Assert the results - assert_eq!(a, I32F32::from_num(0.0), "Expected a to be 0, got: {:?}", a); - assert_eq!(b, I32F32::from_num(0.0), "Expected b to be 0, got: {:?}", b); - - // Edge Case 2: Consensus values at their boundaries (0 and 1) - let alpha_high = I32F32::from_num(0.9); - let alpha_low = I32F32::from_num(0.1); - let consensus_high = I32F32::from_num(1.0); - let consensus_low = I32F32::from_num(0.0); - - // Call the function - let (a, b) = SubtensorModule::calculate_logistic_params( - alpha_high, - alpha_low, - consensus_high, - consensus_low, - ); - - // Expected values - // a = (ln((1 / 0.9 - 1)) - ln((1 / 0.1 - 1))) / (0.0 - 1.0) - // = (ln(0.1111) - ln(9)) / -1.0 - // = (-2.1972 - 2.1972) / -1.0 - // = -4.3944 / -1.0 - // = 4.3944 - let expected_a = I32F32::from_num(4.3944); - - // b = ln((1 / 0.1 - 1)) + a * 0.0 - // = ln(9) + 0 - // = 2.1972 - let expected_b = I32F32::from_num(2.1972); - - // Assert the results - assert!( - (a - expected_a).abs() < I32F32::from_num(0.001), - "Expected a: {:?}, got: {:?}", - expected_a, - a - ); - assert!( - (b - expected_b).abs() < I32F32::from_num(0.001), - "Expected b: {:?}, got: {:?}", - expected_b, - b - ); - - // Edge Case 3: Alpha values being equal - let alpha_high = I32F32::from_num(0.5); - let alpha_low = I32F32::from_num(0.5); - let consensus_high = I32F32::from_num(0.8); - let consensus_low = I32F32::from_num(0.2); - - // Call the function - let (a, b) = SubtensorModule::calculate_logistic_params( - alpha_high, - alpha_low, - consensus_high, - consensus_low, - ); - - // Assert the results - assert_eq!(a, I32F32::from_num(0.0), "Expected a to be 0, got: {:?}", a); - assert_eq!(b, I32F32::from_num(0.0), "Expected b to be 0, got: {:?}", b); - - // Edge Case 4: Consensus values being equal - let alpha_high = I32F32::from_num(0.9); - let alpha_low = I32F32::from_num(0.1); - let consensus_high = I32F32::from_num(0.5); - let consensus_low = I32F32::from_num(0.5); - - // Call the function - let (a, b) = SubtensorModule::calculate_logistic_params( - alpha_high, - alpha_low, - consensus_high, - consensus_low, - ); - - // Assert the results - assert_eq!(a, I32F32::from_num(0.0), "Expected a to be 0, got: {:?}", a); - assert_eq!(b, I32F32::from_num(0.0), "Expected b to be 0, got: {:?}", b); -} - -#[test] -fn test_compute_ema_bonds_with_liquid_alpha_sparse() { - // Define test inputs - let bonds_delta = vec![ - vec![(0, I32F32::from_num(0.1)), (1, I32F32::from_num(0.2))], - vec![(0, I32F32::from_num(0.3)), (1, I32F32::from_num(0.4))], - ]; - let bonds = vec![ - vec![(0, I32F32::from_num(0.5)), (1, I32F32::from_num(0.6))], - vec![(0, I32F32::from_num(0.7)), (1, I32F32::from_num(0.8))], - ]; - let alpha = vec![I32F32::from_num(0.9), I32F32::from_num(0.8)]; - - // Expected values - // EMA calculation for each bond: - // EMA = alpha * bond_delta + (1 - alpha) * bond - // For bond (0, 0): - // EMA = 0.9 * 0.1 + (1 - 0.9) * 0.5 = 0.09 + 0.05 = 0.14 - // For bond (0, 1): - // EMA = 0.8 * 0.2 + (1 - 0.8) * 0.6 = 0.16 + 0.12 = 0.28 - // For bond (1, 0): - // EMA = 0.9 * 0.3 + (1 - 0.9) * 0.7 = 0.27 + 0.07 = 0.34 - // For bond (1, 1): - // EMA = 0.8 * 0.4 + (1 - 0.8) * 0.8 = 0.32 + 0.16 = 0.48 - let expected_ema_bonds = vec![ - vec![(0, I32F32::from_num(0.14)), (1, I32F32::from_num(0.28))], - vec![(0, I32F32::from_num(0.34)), (1, I32F32::from_num(0.48))], - ]; - - // Call the function - let ema_bonds = - SubtensorModule::compute_ema_bonds_with_liquid_alpha_sparse(&bonds_delta, &bonds, alpha); - - // Assert the results with an epsilon for approximate equality - let epsilon = I32F32::from_num(1e-6); - assert_approx_eq_vec_of_vec(&ema_bonds, &expected_ema_bonds, epsilon); -} - -#[test] -fn test_compute_ema_bonds_with_liquid_alpha_sparse_empty() { - // Test with empty inputs - let bonds_delta: Vec> = vec![]; - let bonds: Vec> = vec![]; - let alpha: Vec = vec![]; - - // Expected values: Empty Vec - let expected_ema_bonds: Vec> = vec![]; - - // Call the function - let ema_bonds = - SubtensorModule::compute_ema_bonds_with_liquid_alpha_sparse(&bonds_delta, &bonds, alpha); - - // Assert the results - assert_eq!( - ema_bonds, expected_ema_bonds, - "Expected EMA bonds: {:?}, got: {:?}", - expected_ema_bonds, ema_bonds - ); -} - -#[test] -fn test_get_set_alpha() { - new_test_ext(1).execute_with(|| { - let netuid: u16 = 1; - let alpha_low: u16 = 12_u16; - let alpha_high: u16 = u16::MAX - 10; - - let hotkey: U256 = U256::from(1); - let coldkey: U256 = U256::from(1 + 456); - let signer = <::RuntimeOrigin>::signed(coldkey); - - // Enable Liquid Alpha and setup - SubtensorModule::set_liquid_alpha_enabled(netuid, true); - migration::migrate_create_root_network::(); - SubtensorModule::add_balance_to_coldkey_account(&coldkey, 1_000_000_000_000_000); - assert_ok!(SubtensorModule::root_register(signer.clone(), hotkey,)); - assert_ok!(SubtensorModule::add_stake(signer.clone(), hotkey, 1000)); - - // Should fail as signer does not own the subnet - assert_err!( - SubtensorModule::do_set_alpha_values(signer.clone(), netuid, alpha_low, alpha_high), - DispatchError::BadOrigin - ); - - assert_ok!(SubtensorModule::register_network(signer.clone())); - - assert_ok!(SubtensorModule::do_set_alpha_values( - signer.clone(), - netuid, - alpha_low, - alpha_high - )); - let (grabbed_alpha_low, grabbed_alpha_high): (u16, u16) = - SubtensorModule::get_alpha_values(netuid); - - log::info!( - "alpha_low: {:?} alpha_high: {:?}", - grabbed_alpha_low, - grabbed_alpha_high - ); - assert_eq!(grabbed_alpha_low, alpha_low); - assert_eq!(grabbed_alpha_high, alpha_high); - - // Convert the u16 values to decimal values - fn unnormalize_u16_to_float(normalized_value: u16) -> f32 { - const MAX_U16: u16 = 65535; - normalized_value as f32 / MAX_U16 as f32 - } - - let alpha_low_decimal = unnormalize_u16_to_float(alpha_low); - let alpha_high_decimal = unnormalize_u16_to_float(alpha_high); - - let (alpha_low_32, alpha_high_32) = SubtensorModule::get_alpha_values_32(netuid); - - let tolerance: f32 = 1e-6; // 0.000001 - - // Check if the values are equal to the sixth decimal - assert!( - (alpha_low_32.to_num::() - alpha_low_decimal).abs() < tolerance, - "alpha_low mismatch: {} != {}", - alpha_low_32.to_num::(), - alpha_low_decimal - ); - assert!( - (alpha_high_32.to_num::() - alpha_high_decimal).abs() < tolerance, - "alpha_high mismatch: {} != {}", - alpha_high_32.to_num::(), - alpha_high_decimal - ); - - // 1. Liquid alpha disabled - SubtensorModule::set_liquid_alpha_enabled(netuid, false); - assert_err!( - SubtensorModule::do_set_alpha_values(signer.clone(), netuid, alpha_low, alpha_high), - Error::::LiquidAlphaDisabled - ); - // Correct scenario after error - SubtensorModule::set_liquid_alpha_enabled(netuid, true); // Re-enable for further tests - assert_ok!(SubtensorModule::do_set_alpha_values( - signer.clone(), - netuid, - alpha_low, - alpha_high - )); - - // 2. Alpha high too low - let alpha_high_too_low = (u16::MAX as u32 * 4 / 5) as u16 - 1; // One less than the minimum acceptable value - assert_err!( - SubtensorModule::do_set_alpha_values( - signer.clone(), - netuid, - alpha_low, - alpha_high_too_low - ), - Error::::AlphaHighTooLow - ); - // Correct scenario after error - assert_ok!(SubtensorModule::do_set_alpha_values( - signer.clone(), - netuid, - alpha_low, - alpha_high - )); - - // 3. Alpha low too low or too high - let alpha_low_too_low = 0_u16; - assert_err!( - SubtensorModule::do_set_alpha_values( - signer.clone(), - netuid, - alpha_low_too_low, - alpha_high - ), - Error::::AlphaLowOutOfRange - ); - // Correct scenario after error - assert_ok!(SubtensorModule::do_set_alpha_values( - signer.clone(), - netuid, - alpha_low, - alpha_high - )); - - let alpha_low_too_high = (u16::MAX as u32 * 4 / 5) as u16 + 1; // One more than the maximum acceptable value - assert_err!( - SubtensorModule::do_set_alpha_values( - signer.clone(), - netuid, - alpha_low_too_high, - alpha_high - ), - Error::::AlphaLowOutOfRange - ); - // Correct scenario after error - assert_ok!(SubtensorModule::do_set_alpha_values( - signer.clone(), - netuid, - alpha_low, - alpha_high - )); - }); -} - // // Map the retention graph for consensus guarantees with an single epoch on a graph with 512 nodes, of which the first 64 are validators, the graph is split into a major and minor set, each setting specific weight on itself and the complement on the other. // // // // ```import torch @@ -2802,47 +2076,3 @@ fn test_get_set_alpha() { // } // println!("]"); // } - -/// Helpers - -/// Asserts that two I32F32 values are approximately equal within a given epsilon. -/// -/// # Arguments -/// * `left` - The first value to compare. -/// * `right` - The second value to compare. -/// * `epsilon` - The maximum allowed difference between the two values. -fn assert_approx_eq(left: I32F32, right: I32F32, epsilon: I32F32) { - if (left - right).abs() > epsilon { - panic!( - "assertion failed: `(left ≈ right)`\n left: `{:?}`,\n right: `{:?}`,\n epsilon: `{:?}`", - left, right, epsilon - ); - } -} - -/// Helper function to assert approximate equality of two vectors of vectors of tuples. -fn assert_approx_eq_vec_of_vec( - left: &[Vec<(u16, I32F32)>], - right: &[Vec<(u16, I32F32)>], - epsilon: I32F32, -) { - assert_eq!(left.len(), right.len(), "Vectors have different lengths"); - for (left_row, right_row) in left.iter().zip(right.iter()) { - assert_eq!( - left_row.len(), - right_row.len(), - "Rows have different lengths" - ); - for ((left_idx, left_val), (right_idx, right_val)) in left_row.iter().zip(right_row.iter()) - { - assert_eq!(left_idx, right_idx, "Indices are different"); - assert!( - (left_val - right_val).abs() < epsilon, - "Values are different: left = {:?}, right = {:?}, epsilon = {:?}", - left_val, - right_val, - epsilon - ); - } - } -} diff --git a/pallets/subtensor/tests/math.rs b/pallets/subtensor/tests/math.rs deleted file mode 100644 index bff4628df..000000000 --- a/pallets/subtensor/tests/math.rs +++ /dev/null @@ -1,2350 +0,0 @@ -#![allow( - clippy::unwrap_used, - clippy::panic, - clippy::indexing_slicing, - clippy::arithmetic_side_effects -)] -use substrate_fixed::types::{I32F32, I64F64}; - -use pallet_subtensor::math::*; -use rand::{seq::SliceRandom, thread_rng, Rng}; -use substrate_fixed::{ - transcendental::exp, - types::{I110F18, I96F32}, -}; - -fn assert_float_compare(a: I32F32, b: I32F32, epsilon: I32F32) { - assert!(I32F32::abs(a - b) <= epsilon, "a({:?}) != b({:?})", a, b); -} - -fn assert_float_compare_64(a: I64F64, b: I64F64, epsilon: I64F64) { - assert!(I64F64::abs(a - b) <= epsilon, "a({:?}) != b({:?})", a, b); -} - -fn assert_vec_compare(va: &[I32F32], vb: &[I32F32], epsilon: I32F32) { - assert!(va.len() == vb.len()); - for i in 0..va.len() { - assert_float_compare(va[i], vb[i], epsilon); - } -} - -fn assert_vec_compare_64(va: &[I64F64], vb: &[I64F64], epsilon: I64F64) { - assert!(va.len() == vb.len()); - for i in 0..va.len() { - assert_float_compare_64(va[i], vb[i], epsilon); - } -} - -fn assert_vec_compare_u16(va: &[u16], vb: &[u16]) { - assert!(va.len() == vb.len()); - for i in 0..va.len() { - assert_eq!(va[i], vb[i]); - } -} - -fn assert_mat_compare(ma: &[Vec], mb: &[Vec], epsilon: I32F32) { - assert!(ma.len() == mb.len()); - for row in 0..ma.len() { - assert!(ma[row].len() == mb[row].len()); - for col in 0..ma[row].len() { - assert_float_compare(ma[row][col], mb[row][col], epsilon) - } - } -} - -fn assert_sparse_mat_compare( - ma: &[Vec<(u16, I32F32)>], - mb: &[Vec<(u16, I32F32)>], - epsilon: I32F32, -) { - assert!(ma.len() == mb.len()); - for row in 0..ma.len() { - assert!(ma[row].len() == mb[row].len()); - for j in 0..ma[row].len() { - assert!(ma[row][j].0 == mb[row][j].0); // u16 - assert_float_compare(ma[row][j].1, mb[row][j].1, epsilon) // I32F32 - } - } -} - -fn vec_to_fixed(vector: &[f32]) -> Vec { - vector.iter().map(|x| I32F32::from_num(*x)).collect() -} - -fn mat_to_fixed(matrix: &[Vec]) -> Vec> { - matrix.iter().map(|row| vec_to_fixed(row)).collect() -} - -fn assert_mat_approx_eq(left: &[Vec], right: &[Vec], epsilon: I32F32) { - assert_eq!(left.len(), right.len()); - for (left_row, right_row) in left.iter().zip(right.iter()) { - assert_eq!(left_row.len(), right_row.len()); - for (left_val, right_val) in left_row.iter().zip(right_row.iter()) { - assert!( - (left_val - right_val).abs() <= epsilon, - "left: {:?}, right: {:?}", - left_val, - right_val - ); - } - } -} - -#[test] -fn test_vec_max_upscale_to_u16() { - let vector: Vec = vec_to_fixed(&[]); - let target: Vec = vec![]; - let result: Vec = vec_max_upscale_to_u16(&vector); - assert_vec_compare_u16(&result, &target); - let vector: Vec = vec_to_fixed(&[0.]); - let target: Vec = vec![0]; - let result: Vec = vec_max_upscale_to_u16(&vector); - assert_vec_compare_u16(&result, &target); - let vector: Vec = vec_to_fixed(&[0., 0.]); - let target: Vec = vec![0, 0]; - let result: Vec = vec_max_upscale_to_u16(&vector); - assert_vec_compare_u16(&result, &target); - let vector: Vec = vec_to_fixed(&[0., 1.]); - let target: Vec = vec![0, 65535]; - let result: Vec = vec_max_upscale_to_u16(&vector); - assert_vec_compare_u16(&result, &target); - let vector: Vec = vec_to_fixed(&[0., 0.000000001]); - let target: Vec = vec![0, 65535]; - let result: Vec = vec_max_upscale_to_u16(&vector); - assert_vec_compare_u16(&result, &target); - let vector: Vec = vec_to_fixed(&[0., 0.000016, 1.]); - let target: Vec = vec![0, 1, 65535]; - let result: Vec = vec_max_upscale_to_u16(&vector); - assert_vec_compare_u16(&result, &target); - let vector: Vec = vec_to_fixed(&[0.000000001, 0.000000001]); - let target: Vec = vec![65535, 65535]; - let result: Vec = vec_max_upscale_to_u16(&vector); - assert_vec_compare_u16(&result, &target); - let vector: Vec = vec_to_fixed(&[ - 0.000001, 0.000006, 0.000007, 0.0001, 0.001, 0.01, 0.1, 0.2, 0.3, 0.4, - ]); - let target: Vec = vec![0, 1, 1, 16, 164, 1638, 16384, 32768, 49151, 65535]; - let result: Vec = vec_max_upscale_to_u16(&vector); - assert_vec_compare_u16(&result, &target); - let vector: Vec = vec![I32F32::from_num(16384)]; - let target: Vec = vec![65535]; - let result: Vec = vec_max_upscale_to_u16(&vector); - assert_vec_compare_u16(&result, &target); - let vector: Vec = vec![I32F32::from_num(32768)]; - let target: Vec = vec![65535]; - let result: Vec = vec_max_upscale_to_u16(&vector); - assert_vec_compare_u16(&result, &target); - let vector: Vec = vec![I32F32::from_num(32769)]; - let target: Vec = vec![65535]; - let result: Vec = vec_max_upscale_to_u16(&vector); - assert_vec_compare_u16(&result, &target); - let vector: Vec = vec![I32F32::from_num(65535)]; - let target: Vec = vec![65535]; - let result: Vec = vec_max_upscale_to_u16(&vector); - assert_vec_compare_u16(&result, &target); - let vector: Vec = vec![I32F32::max_value()]; - let target: Vec = vec![65535]; - let result: Vec = vec_max_upscale_to_u16(&vector); - assert_vec_compare_u16(&result, &target); - let vector: Vec = vec_to_fixed(&[0., 1., 65535.]); - let target: Vec = vec![0, 1, 65535]; - let result: Vec = vec_max_upscale_to_u16(&vector); - assert_vec_compare_u16(&result, &target); - let vector: Vec = vec_to_fixed(&[0., 0.5, 1., 1.5, 2., 32768.]); - let target: Vec = vec![0, 1, 2, 3, 4, 65535]; - let result: Vec = vec_max_upscale_to_u16(&vector); - assert_vec_compare_u16(&result, &target); - let vector: Vec = vec_to_fixed(&[0., 0.5, 1., 1.5, 2., 32768., 32769.]); - let target: Vec = vec![0, 1, 2, 3, 4, 65533, 65535]; - let result: Vec = vec_max_upscale_to_u16(&vector); - assert_vec_compare_u16(&result, &target); - let vector: Vec = vec![ - I32F32::from_num(0), - I32F32::from_num(1), - I32F32::from_num(32768), - I32F32::from_num(32769), - I32F32::max_value(), - ]; - let target: Vec = vec![0, 0, 1, 1, 65535]; - let result: Vec = vec_max_upscale_to_u16(&vector); - assert_vec_compare_u16(&result, &target); -} - -#[test] -fn test_vec_u16_max_upscale_to_u16() { - let vector: Vec = vec![]; - let result: Vec = vec_u16_max_upscale_to_u16(&vector); - assert_vec_compare_u16(&result, &vector); - let vector: Vec = vec![0]; - let result: Vec = vec_u16_max_upscale_to_u16(&vector); - assert_vec_compare_u16(&result, &vector); - let vector: Vec = vec![0, 0]; - let result: Vec = vec_u16_max_upscale_to_u16(&vector); - assert_vec_compare_u16(&result, &vector); - let vector: Vec = vec![1]; - let target: Vec = vec![65535]; - let result: Vec = vec_u16_max_upscale_to_u16(&vector); - assert_vec_compare_u16(&result, &target); - let vector: Vec = vec![0, 1]; - let target: Vec = vec![0, 65535]; - let result: Vec = vec_u16_max_upscale_to_u16(&vector); - assert_vec_compare_u16(&result, &target); - let vector: Vec = vec![65534]; - let target: Vec = vec![65535]; - let result: Vec = vec_u16_max_upscale_to_u16(&vector); - assert_vec_compare_u16(&result, &target); - let vector: Vec = vec![65535]; - let target: Vec = vec![65535]; - let result: Vec = vec_u16_max_upscale_to_u16(&vector); - assert_vec_compare_u16(&result, &target); - let vector: Vec = vec![65535, 65535]; - let target: Vec = vec![65535, 65535]; - let result: Vec = vec_u16_max_upscale_to_u16(&vector); - assert_vec_compare_u16(&result, &target); - let vector: Vec = vec![0, 1, 65534]; - let target: Vec = vec![0, 1, 65535]; - let result: Vec = vec_u16_max_upscale_to_u16(&vector); - assert_vec_compare_u16(&result, &target); - let vector: Vec = vec![0, 1, 2, 3, 4, 65533, 65535]; - let result: Vec = vec_u16_max_upscale_to_u16(&vector); - assert_vec_compare_u16(&result, &vector); -} - -#[test] -fn test_check_vec_max_limited() { - let vector: Vec = vec![]; - let max_limit: u16 = 0; - assert!(check_vec_max_limited(&vector, max_limit)); - let vector: Vec = vec![]; - let max_limit: u16 = u16::MAX; - assert!(check_vec_max_limited(&vector, max_limit)); - let vector: Vec = vec![u16::MAX]; - let max_limit: u16 = u16::MAX; - assert!(check_vec_max_limited(&vector, max_limit)); - let vector: Vec = vec![u16::MAX]; - let max_limit: u16 = u16::MAX - 1; - assert!(!check_vec_max_limited(&vector, max_limit)); - let vector: Vec = vec![u16::MAX]; - let max_limit: u16 = 0; - assert!(!check_vec_max_limited(&vector, max_limit)); - let vector: Vec = vec![0]; - let max_limit: u16 = u16::MAX; - assert!(check_vec_max_limited(&vector, max_limit)); - let vector: Vec = vec![0, u16::MAX]; - let max_limit: u16 = u16::MAX; - assert!(check_vec_max_limited(&vector, max_limit)); - let vector: Vec = vec![0, u16::MAX, u16::MAX]; - let max_limit: u16 = u16::MAX / 2; - assert!(!check_vec_max_limited(&vector, max_limit)); - let vector: Vec = vec![0, u16::MAX, u16::MAX]; - let max_limit: u16 = u16::MAX / 2 + 1; - assert!(check_vec_max_limited(&vector, max_limit)); - let vector: Vec = vec![0, u16::MAX, u16::MAX, u16::MAX]; - let max_limit: u16 = u16::MAX / 3 - 1; - assert!(!check_vec_max_limited(&vector, max_limit)); - let vector: Vec = vec![0, u16::MAX, u16::MAX, u16::MAX]; - let max_limit: u16 = u16::MAX / 3; - assert!(check_vec_max_limited(&vector, max_limit)); -} - -#[test] -fn test_math_fixed_overflow() { - let max_32: I32F32 = I32F32::max_value(); - let max_u64: u64 = u64::MAX; - let _prod_96: I96F32 = I96F32::from_num(max_32) * I96F32::from_num(max_u64); - // let one: I96F32 = I96F32::from_num(1); - // let prod_96: I96F32 = (I96F32::from_num(max_32) + one) * I96F32::from_num(max_u64); // overflows - let _prod_110: I110F18 = I110F18::from_num(max_32) * I110F18::from_num(max_u64); - - let bonds_moving_average_val: u64 = 900_000_u64; - let bonds_moving_average: I64F64 = - I64F64::from_num(bonds_moving_average_val) / I64F64::from_num(1_000_000); - let alpha: I32F32 = I32F32::from_num(1) - I32F32::from_num(bonds_moving_average); - assert_eq!(I32F32::from_num(0.1), alpha); - - let bonds_moving_average: I64F64 = I64F64::from_num(max_32) / I64F64::from_num(max_32); - let alpha: I32F32 = I32F32::from_num(1) - I32F32::from_num(bonds_moving_average); - assert_eq!(I32F32::from_num(0), alpha); -} - -#[test] -fn test_math_u64_normalization() { - let min: u64 = 1; - let min32: u64 = 4_889_444; // 21_000_000_000_000_000 / 4_294_967_296 - let mid: u64 = 10_500_000_000_000_000; - let max: u64 = 21_000_000_000_000_000; - let min_64: I64F64 = I64F64::from_num(min); - let min32_64: I64F64 = I64F64::from_num(min32); - let mid_64: I64F64 = I64F64::from_num(mid); - let max_64: I64F64 = I64F64::from_num(max); - let max_sum: I64F64 = I64F64::from_num(max); - let min_frac: I64F64 = min_64 / max_sum; - assert_eq!(min_frac, I64F64::from_num(0.0000000000000000476)); - let min_frac_32: I32F32 = I32F32::from_num(min_frac); - assert_eq!(min_frac_32, I32F32::from_num(0)); - let min32_frac: I64F64 = min32_64 / max_sum; - assert_eq!(min32_frac, I64F64::from_num(0.00000000023283066664)); - let min32_frac_32: I32F32 = I32F32::from_num(min32_frac); - assert_eq!(min32_frac_32, I32F32::from_num(0.0000000002)); - let half: I64F64 = mid_64 / max_sum; - assert_eq!(half, I64F64::from_num(0.5)); - let half_32: I32F32 = I32F32::from_num(half); - assert_eq!(half_32, I32F32::from_num(0.5)); - let one: I64F64 = max_64 / max_sum; - assert_eq!(one, I64F64::from_num(1)); - let one_32: I32F32 = I32F32::from_num(one); - assert_eq!(one_32, I32F32::from_num(1)); -} - -#[test] -fn test_math_to_num() { - let val: I32F32 = I32F32::from_num(u16::MAX); - let res: u16 = val.to_num::(); - assert_eq!(res, u16::MAX); - let vector: Vec = vec![val; 1000]; - let target: Vec = vec![u16::MAX; 1000]; - let output: Vec = vector.iter().map(|e: &I32F32| e.to_num::()).collect(); - assert_eq!(output, target); - let output: Vec = vector - .iter() - .map(|e: &I32F32| (*e).to_num::()) - .collect(); - assert_eq!(output, target); - let val: I32F32 = I32F32::max_value(); - let res: u64 = val.to_num::(); - let vector: Vec = vec![val; 1000]; - let target: Vec = vec![res; 1000]; - let output: Vec = vector.iter().map(|e: &I32F32| e.to_num::()).collect(); - assert_eq!(output, target); - let output: Vec = vector - .iter() - .map(|e: &I32F32| (*e).to_num::()) - .collect(); - assert_eq!(output, target); - let val: I32F32 = I32F32::from_num(0); - let res: u64 = val.to_num::(); - let vector: Vec = vec![val; 1000]; - let target: Vec = vec![res; 1000]; - let output: Vec = vector.iter().map(|e: &I32F32| e.to_num::()).collect(); - assert_eq!(output, target); - let output: Vec = vector - .iter() - .map(|e: &I32F32| (*e).to_num::()) - .collect(); - assert_eq!(output, target); - let val: I96F32 = I96F32::from_num(u64::MAX); - let res: u64 = val.to_num::(); - assert_eq!(res, u64::MAX); - let vector: Vec = vec![val; 1000]; - let target: Vec = vec![u64::MAX; 1000]; - let output: Vec = vector.iter().map(|e: &I96F32| e.to_num::()).collect(); - assert_eq!(output, target); - let output: Vec = vector - .iter() - .map(|e: &I96F32| (*e).to_num::()) - .collect(); - assert_eq!(output, target); -} - -#[test] -fn test_math_vec_to_fixed() { - let vector: Vec = vec![0., 1., 2., 3.]; - let target: Vec = vec![ - I32F32::from_num(0.), - I32F32::from_num(1.), - I32F32::from_num(2.), - I32F32::from_num(3.), - ]; - let result = vec_to_fixed(&vector); - assert_vec_compare(&result, &target, I32F32::from_num(0)); -} - -// Reshape vector to matrix with specified number of rows, cast to I32F32. -fn vec_to_mat_fixed(vector: &[f32], rows: usize, transpose: bool) -> Vec> { - assert!( - vector.len() % rows == 0, - "Vector of len {:?} cannot reshape to {rows} rows.", - vector.len() - ); - let cols: usize = vector.len() / rows; - let mut mat: Vec> = vec![]; - if transpose { - for col in 0..cols { - let mut vals: Vec = vec![]; - for row in 0..rows { - vals.push(I32F32::from_num(vector[row * cols + col])); - } - mat.push(vals); - } - } else { - for row in 0..rows { - mat.push( - vector[row * cols..(row + 1) * cols] - .iter() - .map(|v| I32F32::from_num(*v)) - .collect(), - ); - } - } - mat -} - -#[test] -fn test_math_vec_to_mat_fixed() { - let vector: Vec = vec![0., 1., 2., 0., 10., 100.]; - let target: Vec> = vec![ - vec![ - I32F32::from_num(0.), - I32F32::from_num(1.), - I32F32::from_num(2.), - ], - vec![ - I32F32::from_num(0.), - I32F32::from_num(10.), - I32F32::from_num(100.), - ], - ]; - let mat = vec_to_mat_fixed(&vector, 2, false); - assert_mat_compare(&mat, &target, I32F32::from_num(0)); -} - -// Reshape vector to sparse matrix with specified number of input rows, cast f32 to I32F32. -fn vec_to_sparse_mat_fixed( - vector: &[f32], - rows: usize, - transpose: bool, -) -> Vec> { - assert!( - vector.len() % rows == 0, - "Vector of len {:?} cannot reshape to {rows} rows.", - vector.len() - ); - let cols: usize = vector.len() / rows; - let mut mat: Vec> = vec![]; - if transpose { - for col in 0..cols { - let mut row_vec: Vec<(u16, I32F32)> = vec![]; - for row in 0..rows { - if vector[row * cols + col] > 0. { - row_vec.push((row as u16, I32F32::from_num(vector[row * cols + col]))); - } - } - mat.push(row_vec); - } - } else { - for row in 0..rows { - let mut row_vec: Vec<(u16, I32F32)> = vec![]; - for col in 0..cols { - if vector[row * cols + col] > 0. { - row_vec.push((col as u16, I32F32::from_num(vector[row * cols + col]))); - } - } - mat.push(row_vec); - } - } - mat -} - -#[test] -fn test_math_vec_to_sparse_mat_fixed() { - let vector: Vec = vec![0., 1., 2., 0., 10., 100.]; - let target: Vec> = vec![ - vec![(1_u16, I32F32::from_num(1.)), (2_u16, I32F32::from_num(2.))], - vec![ - (1_u16, I32F32::from_num(10.)), - (2_u16, I32F32::from_num(100.)), - ], - ]; - let mat = vec_to_sparse_mat_fixed(&vector, 2, false); - assert_sparse_mat_compare(&mat, &target, I32F32::from_num(0)); - let vector: Vec = vec![0., 0.]; - let target: Vec> = vec![vec![], vec![]]; - let mat = vec_to_sparse_mat_fixed(&vector, 2, false); - assert_sparse_mat_compare(&mat, &target, I32F32::from_num(0)); - let vector: Vec = vec![0., 1., 2., 0., 10., 100.]; - let target: Vec> = vec![ - vec![], - vec![ - (0_u16, I32F32::from_num(1.)), - (1_u16, I32F32::from_num(10.)), - ], - vec![ - (0_u16, I32F32::from_num(2.)), - (1_u16, I32F32::from_num(100.)), - ], - ]; - let mat = vec_to_sparse_mat_fixed(&vector, 2, true); - assert_sparse_mat_compare(&mat, &target, I32F32::from_num(0)); - let vector: Vec = vec![0., 0.]; - let target: Vec> = vec![vec![]]; - let mat = vec_to_sparse_mat_fixed(&vector, 2, true); - assert_sparse_mat_compare(&mat, &target, I32F32::from_num(0)); -} - -#[test] -fn test_math_exp_safe() { - let zero: I32F32 = I32F32::from_num(0); - let one: I32F32 = I32F32::from_num(1); - let target: I32F32 = exp(zero).unwrap(); - assert_eq!(exp_safe(zero), target); - let target: I32F32 = exp(one).unwrap(); - assert_eq!(exp_safe(one), target); - let min_input: I32F32 = I32F32::from_num(-20); // <= 1/exp(-20) = 485 165 195,4097903 - let max_input: I32F32 = I32F32::from_num(20); // <= exp(20) = 485 165 195,4097903 - let target: I32F32 = exp(min_input).unwrap(); - assert_eq!(exp_safe(min_input), target); - assert_eq!(exp_safe(min_input - one), target); - assert_eq!(exp_safe(I32F32::min_value()), target); - let target: I32F32 = exp(max_input).unwrap(); - assert_eq!(exp_safe(max_input), target); - assert_eq!(exp_safe(max_input + one), target); - assert_eq!(exp_safe(I32F32::max_value()), target); -} - -#[test] -fn test_math_sigmoid_safe() { - let trust: Vec = vec![ - I32F32::min_value(), - I32F32::from_num(0), - I32F32::from_num(0.4), - I32F32::from_num(0.5), - I32F32::from_num(0.6), - I32F32::from_num(1), - I32F32::max_value(), - ]; - let consensus: Vec = trust - .iter() - .map(|t: &I32F32| sigmoid_safe(*t, I32F32::max_value(), I32F32::max_value())) - .collect(); - let target: Vec = vec_to_fixed(&[ - 0.0000000019, - 0.0000000019, - 0.0000000019, - 0.0000000019, - 0.0000000019, - 0.0000000019, - 0.5, - ]); - assert_eq!(&consensus, &target); - let consensus: Vec = trust - .iter() - .map(|t: &I32F32| sigmoid_safe(*t, I32F32::min_value(), I32F32::min_value())) - .collect(); - let target: Vec = vec_to_fixed(&[ - 0.5, - 0.0000000019, - 0.0000000019, - 0.0000000019, - 0.0000000019, - 0.0000000019, - 0.0000000019, - ]); - assert_eq!(&consensus, &target); - let consensus: Vec = trust - .iter() - .map(|t: &I32F32| sigmoid_safe(*t, I32F32::from_num(30), I32F32::from_num(0.5))) - .collect(); - let target: Vec = vec![ - 0.0000000019, - 0.0000003057, - 0.0474258729, - 0.5, - 0.952574127, - 0.9999996943, - 0.9999999981, - ]; - let target: Vec = target.iter().map(|c: &f64| I32F32::from_num(*c)).collect(); - assert_eq!(&consensus, &target); - let trust: Vec = vec_to_fixed(&[0., 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.]); - let consensus: Vec = trust - .iter() - .map(|t: &I32F32| sigmoid_safe(*t, I32F32::from_num(40), I32F32::from_num(0.5))) - .collect(); - let target: Vec = vec![ - 0.0000000019, - 0.0000001125, - 0.0000061442, - 0.0003353502, - 0.017986214, - 0.5, - 0.9820138067, - 0.9996646498, - 0.9999938558, - 0.9999998875, - 0.9999999981, - ]; - let target: Vec = target.iter().map(|c: &f64| I32F32::from_num(*c)).collect(); - assert_eq!(&consensus, &target); -} - -#[test] -fn test_math_is_topk() { - let vector: Vec = vec_to_fixed(&[]); - let result = is_topk(&vector, 5); - let target: Vec = vec![]; - assert_eq!(&result, &target); - let vector: Vec = vec_to_fixed(&[0., 1., 2., 3., 4., 5., 6., 7., 8., 9.]); - let result = is_topk(&vector, 0); - let target: Vec = vec![ - false, false, false, false, false, false, false, false, false, false, - ]; - assert_eq!(&result, &target); - let result = is_topk(&vector, 5); - let target: Vec = vec![ - false, false, false, false, false, true, true, true, true, true, - ]; - assert_eq!(&result, &target); - let result = is_topk(&vector, 10); - let target: Vec = vec![true, true, true, true, true, true, true, true, true, true]; - assert_eq!(&result, &target); - let result = is_topk(&vector, 100); - assert_eq!(&result, &target); - let vector: Vec = vec_to_fixed(&[9., 8., 7., 6., 5., 4., 3., 2., 1., 0.]); - let result = is_topk(&vector, 5); - let target: Vec = vec![ - true, true, true, true, true, false, false, false, false, false, - ]; - assert_eq!(&result, &target); - let vector: Vec = vec_to_fixed(&[9., 0., 8., 1., 7., 2., 6., 3., 5., 4.]); - let result = is_topk(&vector, 5); - let target: Vec = vec![ - true, false, true, false, true, false, true, false, true, false, - ]; - assert_eq!(&result, &target); - let vector: Vec = vec_to_fixed(&[0.9, 0., 0.8, 0.1, 0.7, 0.2, 0.6, 0.3, 0.5, 0.4]); - let result = is_topk(&vector, 5); - let target: Vec = vec![ - true, false, true, false, true, false, true, false, true, false, - ]; - assert_eq!(&result, &target); - let vector: Vec = vec_to_fixed(&[0., 1., 2., 3., 4., 5., 5., 5., 5., 6.]); - let result = is_topk(&vector, 5); - let target: Vec = vec![ - false, false, false, false, false, true, true, true, true, true, - ]; - assert_eq!(&result, &target); -} - -#[test] -fn test_math_sum() { - assert!(sum(&[]) == I32F32::from_num(0)); - assert!( - sum(&[ - I32F32::from_num(1.0), - I32F32::from_num(10.0), - I32F32::from_num(30.0) - ]) == I32F32::from_num(41) - ); - assert!( - sum(&[ - I32F32::from_num(-1.0), - I32F32::from_num(10.0), - I32F32::from_num(30.0) - ]) == I32F32::from_num(39) - ); -} - -#[test] -fn test_math_normalize() { - let epsilon: I32F32 = I32F32::from_num(0.0001); - let x: Vec = vec![]; - let y: Vec = normalize(&x); - assert_vec_compare(&x, &y, epsilon); - let x: Vec = vec![ - I32F32::from_num(1.0), - I32F32::from_num(10.0), - I32F32::from_num(30.0), - ]; - let y: Vec = normalize(&x); - assert_vec_compare( - &y, - &[ - I32F32::from_num(0.0243902437), - I32F32::from_num(0.243902439), - I32F32::from_num(0.7317073171), - ], - epsilon, - ); - assert_float_compare(sum(&y), I32F32::from_num(1.0), epsilon); - let x: Vec = vec![ - I32F32::from_num(-1.0), - I32F32::from_num(10.0), - I32F32::from_num(30.0), - ]; - let y: Vec = normalize(&x); - assert_vec_compare( - &y, - &[ - I32F32::from_num(-0.0256410255), - I32F32::from_num(0.2564102563), - I32F32::from_num(0.769230769), - ], - epsilon, - ); - assert_float_compare(sum(&y), I32F32::from_num(1.0), epsilon); -} - -#[test] -fn test_math_inplace_normalize() { - let epsilon: I32F32 = I32F32::from_num(0.0001); - let mut x1: Vec = vec![ - I32F32::from_num(1.0), - I32F32::from_num(10.0), - I32F32::from_num(30.0), - ]; - inplace_normalize(&mut x1); - assert_vec_compare( - &x1, - &[ - I32F32::from_num(0.0243902437), - I32F32::from_num(0.243902439), - I32F32::from_num(0.7317073171), - ], - epsilon, - ); - let mut x2: Vec = vec![ - I32F32::from_num(-1.0), - I32F32::from_num(10.0), - I32F32::from_num(30.0), - ]; - inplace_normalize(&mut x2); - assert_vec_compare( - &x2, - &[ - I32F32::from_num(-0.0256410255), - I32F32::from_num(0.2564102563), - I32F32::from_num(0.769230769), - ], - epsilon, - ); -} - -#[test] -fn test_math_inplace_normalize_64() { - let epsilon: I64F64 = I64F64::from_num(0.0001); - let mut x1: Vec = vec![ - I64F64::from_num(1.0), - I64F64::from_num(10.0), - I64F64::from_num(30.0), - ]; - inplace_normalize_64(&mut x1); - assert_vec_compare_64( - &x1, - &[ - I64F64::from_num(0.0243902437), - I64F64::from_num(0.243902439), - I64F64::from_num(0.7317073171), - ], - epsilon, - ); - let mut x2: Vec = vec![ - I64F64::from_num(-1.0), - I64F64::from_num(10.0), - I64F64::from_num(30.0), - ]; - inplace_normalize_64(&mut x2); - assert_vec_compare_64( - &x2, - &[ - I64F64::from_num(-0.0256410255), - I64F64::from_num(0.2564102563), - I64F64::from_num(0.769230769), - ], - epsilon, - ); -} - -#[test] -fn test_math_vecdiv() { - let x: Vec = vec_to_fixed(&[]); - let y: Vec = vec_to_fixed(&[]); - let result: Vec = vec_to_fixed(&[]); - assert_eq!(result, vecdiv(&x, &y)); - - let x: Vec = vec_to_fixed(&[0., 1., 0., 1.]); - let y: Vec = vec_to_fixed(&[0., 1., 1., 0.]); - let result: Vec = vec_to_fixed(&[0., 1., 0., 0.]); - assert_eq!(result, vecdiv(&x, &y)); - - let x: Vec = vec_to_fixed(&[1., 1., 10.]); - let y: Vec = vec_to_fixed(&[2., 3., 2.]); - let result: Vec = vec![fixed(1.) / fixed(2.), fixed(1.) / fixed(3.), fixed(5.)]; - assert_eq!(result, vecdiv(&x, &y)); -} - -#[test] -fn test_math_inplace_row_normalize() { - let epsilon: I32F32 = I32F32::from_num(0.0001); - let vector: Vec = vec![ - 0., 1., 2., 3., 4., 0., 10., 100., 1000., 10000., 0., 0., 0., 0., 0., 1., 1., 1., 1., 1., - ]; - let mut mat = vec_to_mat_fixed(&vector, 4, false); - inplace_row_normalize(&mut mat); - let target: Vec = vec![ - 0., 0.1, 0.2, 0.3, 0.4, 0., 0.0009, 0.009, 0.09, 0.9, 0., 0., 0., 0., 0., 0.2, 0.2, 0.2, - 0.2, 0.2, - ]; - assert_mat_compare(&mat, &vec_to_mat_fixed(&target, 4, false), epsilon); -} - -#[test] -fn test_math_inplace_row_normalize_sparse() { - let epsilon: I32F32 = I32F32::from_num(0.0001); - let vector: Vec = vec![ - 0., 1., 0., 2., 0., 3., 4., 0., 1., 0., 2., 0., 3., 0., 1., 0., 0., 2., 0., 3., 4., 0., - 10., 0., 100., 1000., 0., 10000., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 1., 1., 1., 1., - ]; - let mut mat = vec_to_sparse_mat_fixed(&vector, 6, false); - inplace_row_normalize_sparse(&mut mat); - let target: Vec = vec![ - 0., 0.1, 0., 0.2, 0., 0.3, 0.4, 0., 0.166666, 0., 0.333333, 0., 0.5, 0., 0.1, 0., 0., 0.2, - 0., 0.3, 0.4, 0., 0.0009, 0., 0.009, 0.09, 0., 0.9, 0., 0., 0., 0., 0., 0., 0., 0.142857, - 0.142857, 0.142857, 0.142857, 0.142857, 0.142857, 0.142857, - ]; - assert_sparse_mat_compare(&mat, &vec_to_sparse_mat_fixed(&target, 6, false), epsilon); - let vector: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let mut mat = vec_to_sparse_mat_fixed(&vector, 3, false); - inplace_row_normalize_sparse(&mut mat); - assert_sparse_mat_compare( - &mat, - &vec_to_sparse_mat_fixed(&target, 3, false), - I32F32::from_num(0), - ); -} - -#[test] -fn test_math_inplace_col_normalize() { - let epsilon: I32F32 = I32F32::from_num(0.0001); - let vector: Vec = vec![ - 0., 1., 2., 3., 4., 0., 10., 100., 1000., 10000., 0., 0., 0., 0., 0., 1., 1., 1., 1., 1., - ]; - let mut mat = vec_to_mat_fixed(&vector, 4, true); - inplace_col_normalize(&mut mat); - let target: Vec = vec![ - 0., 0.1, 0.2, 0.3, 0.4, 0., 0.0009, 0.009, 0.09, 0.9, 0., 0., 0., 0., 0., 0.2, 0.2, 0.2, - 0.2, 0.2, - ]; - assert_mat_compare(&mat, &vec_to_mat_fixed(&target, 4, true), epsilon); -} - -#[test] -fn test_math_inplace_col_normalize_sparse() { - let epsilon: I32F32 = I32F32::from_num(0.0001); - let vector: Vec = vec![ - 0., 1., 0., 2., 0., 3., 4., 0., 1., 0., 2., 0., 3., 0., 1., 0., 0., 2., 0., 3., 4., 0., - 10., 0., 100., 1000., 0., 10000., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 1., 1., 1., 1., - ]; - let mut mat = vec_to_sparse_mat_fixed(&vector, 6, true); - inplace_col_normalize_sparse(&mut mat, 6); - let target: Vec = vec![ - 0., 0.1, 0., 0.2, 0., 0.3, 0.4, 0., 0.166666, 0., 0.333333, 0., 0.5, 0., 0.1, 0., 0., 0.2, - 0., 0.3, 0.4, 0., 0.0009, 0., 0.009, 0.09, 0., 0.9, 0., 0., 0., 0., 0., 0., 0., 0.142857, - 0.142857, 0.142857, 0.142857, 0.142857, 0.142857, 0.142857, - ]; - assert_sparse_mat_compare(&mat, &vec_to_sparse_mat_fixed(&target, 6, true), epsilon); - let vector: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let mut mat = vec_to_sparse_mat_fixed(&vector, 3, false); - inplace_col_normalize_sparse(&mut mat, 6); - assert_sparse_mat_compare( - &mat, - &vec_to_sparse_mat_fixed(&target, 3, false), - I32F32::from_num(0), - ); - let mut mat: Vec> = vec![]; - let target: Vec> = vec![]; - inplace_col_normalize_sparse(&mut mat, 0); - assert_sparse_mat_compare(&mat, &target, epsilon); -} - -#[test] -fn test_math_inplace_col_max_upscale() { - let mut mat: Vec> = vec![vec![]]; - let target: Vec> = vec![vec![]]; - inplace_col_max_upscale(&mut mat); - assert_eq!(&mat, &target); - let mut mat: Vec> = vec![vec![I32F32::from_num(0)]]; - let target: Vec> = vec![vec![I32F32::from_num(0)]]; - inplace_col_max_upscale(&mut mat); - assert_eq!(&mat, &target); - let epsilon: I32F32 = I32F32::from_num(0.0001); - let vector: Vec = vec![ - 0., 1., 2., 3., 4., 0., 10., 100., 1000., 10000., 0., 0., 0., 0., 0., 1., 1., 1., 1., 1., - ]; - let mut mat: Vec> = vec_to_mat_fixed(&vector, 4, true); - inplace_col_max_upscale(&mut mat); - let target: Vec = vec![ - 0., 0.25, 0.5, 0.75, 1., 0., 0.001, 0.01, 0.1, 1., 0., 0., 0., 0., 0., 1., 1., 1., 1., 1., - ]; - assert_mat_compare(&mat, &vec_to_mat_fixed(&target, 4, true), epsilon); -} - -#[test] -fn test_math_inplace_col_max_upscale_sparse() { - let mut mat: Vec> = vec![vec![]]; - let target: Vec> = vec![vec![]]; - inplace_col_max_upscale_sparse(&mut mat, 0); - assert_eq!(&mat, &target); - let mut mat: Vec> = vec![vec![(0, I32F32::from_num(0))]]; - let target: Vec> = vec![vec![(0, I32F32::from_num(0))]]; - inplace_col_max_upscale_sparse(&mut mat, 1); - assert_eq!(&mat, &target); - let epsilon: I32F32 = I32F32::from_num(0.0001); - let vector: Vec = vec![ - 0., 1., 0., 2., 0., 3., 4., 0., 1., 0., 2., 0., 3., 0., 1., 0., 0., 2., 0., 3., 4., 0., - 10., 0., 100., 1000., 0., 10000., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 1., 1., 1., 1., - ]; - let mut mat = vec_to_sparse_mat_fixed(&vector, 6, true); - inplace_col_max_upscale_sparse(&mut mat, 6); - let target: Vec = vec![ - 0., 0.25, 0., 0.5, 0., 0.75, 1., 0., 0.333333, 0., 0.666666, 0., 1., 0., 0.25, 0., 0., 0.5, - 0., 0.75, 1., 0., 0.001, 0., 0.01, 0.1, 0., 1., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 1., - 1., 1., 1., - ]; - assert_sparse_mat_compare(&mat, &vec_to_sparse_mat_fixed(&target, 6, true), epsilon); - let vector: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let mut mat = vec_to_sparse_mat_fixed(&vector, 3, false); - inplace_col_max_upscale_sparse(&mut mat, 6); - assert_sparse_mat_compare( - &mat, - &vec_to_sparse_mat_fixed(&target, 3, false), - I32F32::from_num(0), - ); - let mut mat: Vec> = vec![]; - let target: Vec> = vec![]; - inplace_col_max_upscale_sparse(&mut mat, 0); - assert_sparse_mat_compare(&mat, &target, epsilon); -} - -#[test] -fn test_math_inplace_mask_vector() { - let mask: Vec = vec![false, false, false]; - let mut vector: Vec = vec_to_fixed(&[0., 1., 2.]); - let target: Vec = vec_to_fixed(&[0., 1., 2.]); - inplace_mask_vector(&mask, &mut vector); - assert_vec_compare(&vector, &target, I32F32::from_num(0)); - let mask: Vec = vec![false, true, false]; - let mut vector: Vec = vec_to_fixed(&[0., 1., 2.]); - let target: Vec = vec_to_fixed(&[0., 0., 2.]); - inplace_mask_vector(&mask, &mut vector); - assert_vec_compare(&vector, &target, I32F32::from_num(0)); - let mask: Vec = vec![true, true, true]; - let mut vector: Vec = vec_to_fixed(&[0., 1., 2.]); - let target: Vec = vec_to_fixed(&[0., 0., 0.]); - inplace_mask_vector(&mask, &mut vector); - assert_vec_compare(&vector, &target, I32F32::from_num(0)); -} - -#[test] -fn test_math_inplace_mask_matrix() { - let mask: Vec> = vec![ - vec![false, false, false], - vec![false, false, false], - vec![false, false, false], - ]; - let vector: Vec = vec![0., 1., 2., 3., 4., 5., 6., 7., 8.]; - let mut mat = vec_to_mat_fixed(&vector, 3, false); - inplace_mask_matrix(&mask, &mut mat); - assert_mat_compare( - &mat, - &vec_to_mat_fixed(&vector, 3, false), - I32F32::from_num(0), - ); - let mask: Vec> = vec![ - vec![true, false, false], - vec![false, true, false], - vec![false, false, true], - ]; - let target: Vec = vec![0., 1., 2., 3., 0., 5., 6., 7., 0.]; - let mut mat = vec_to_mat_fixed(&vector, 3, false); - inplace_mask_matrix(&mask, &mut mat); - assert_mat_compare( - &mat, - &vec_to_mat_fixed(&target, 3, false), - I32F32::from_num(0), - ); - let mask: Vec> = vec![ - vec![true, true, true], - vec![true, true, true], - vec![true, true, true], - ]; - let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let mut mat = vec_to_mat_fixed(&vector, 3, false); - inplace_mask_matrix(&mask, &mut mat); - assert_mat_compare( - &mat, - &vec_to_mat_fixed(&target, 3, false), - I32F32::from_num(0), - ); -} - -#[test] -fn test_math_inplace_mask_rows() { - let input: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9.]; - let mask: Vec = vec![false, false, false]; - let target: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9.]; - let mut mat = vec_to_mat_fixed(&input, 3, false); - inplace_mask_rows(&mask, &mut mat); - assert_mat_compare( - &mat, - &vec_to_mat_fixed(&target, 3, false), - I32F32::from_num(0), - ); - let mask: Vec = vec![true, true, true]; - let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let mut mat = vec_to_mat_fixed(&input, 3, false); - inplace_mask_rows(&mask, &mut mat); - assert_mat_compare( - &mat, - &vec_to_mat_fixed(&target, 3, false), - I32F32::from_num(0), - ); - let mask: Vec = vec![true, false, true]; - let target: Vec = vec![0., 0., 0., 4., 5., 6., 0., 0., 0.]; - let mut mat = vec_to_mat_fixed(&input, 3, false); - inplace_mask_rows(&mask, &mut mat); - assert_mat_compare( - &mat, - &vec_to_mat_fixed(&target, 3, false), - I32F32::from_num(0), - ); - let input: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let mut mat = vec_to_mat_fixed(&input, 3, false); - let mask: Vec = vec![false, false, false]; - let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0.]; - inplace_mask_rows(&mask, &mut mat); - assert_mat_compare( - &mat, - &vec_to_mat_fixed(&target, 3, false), - I32F32::from_num(0), - ); -} - -#[test] -fn test_math_inplace_mask_diag() { - let vector: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9.]; - let target: Vec = vec![0., 2., 3., 4., 0., 6., 7., 8., 0.]; - let mut mat = vec_to_mat_fixed(&vector, 3, false); - inplace_mask_diag(&mut mat); - assert_mat_compare( - &mat, - &vec_to_mat_fixed(&target, 3, false), - I32F32::from_num(0), - ); -} - -#[test] -fn test_math_mask_rows_sparse() { - let input: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9.]; - let mat = vec_to_sparse_mat_fixed(&input, 3, false); - let mask: Vec = vec![false, false, false]; - let target: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9.]; - let result = mask_rows_sparse(&mask, &mat); - assert_sparse_mat_compare( - &result, - &vec_to_sparse_mat_fixed(&target, 3, false), - I32F32::from_num(0), - ); - let mask: Vec = vec![true, true, true]; - let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let result = mask_rows_sparse(&mask, &mat); - assert_sparse_mat_compare( - &result, - &vec_to_sparse_mat_fixed(&target, 3, false), - I32F32::from_num(0), - ); - let mask: Vec = vec![true, false, true]; - let target: Vec = vec![0., 0., 0., 4., 5., 6., 0., 0., 0.]; - let result = mask_rows_sparse(&mask, &mat); - assert_sparse_mat_compare( - &result, - &vec_to_sparse_mat_fixed(&target, 3, false), - I32F32::from_num(0), - ); - let input: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let mat = vec_to_sparse_mat_fixed(&input, 3, false); - let mask: Vec = vec![false, false, false]; - let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let result = mask_rows_sparse(&mask, &mat); - assert_sparse_mat_compare( - &result, - &vec_to_sparse_mat_fixed(&target, 3, false), - I32F32::from_num(0), - ); -} - -#[test] -fn test_math_mask_diag_sparse() { - let vector: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9.]; - let target: Vec = vec![0., 2., 3., 4., 0., 6., 7., 8., 0.]; - let mat = vec_to_sparse_mat_fixed(&vector, 3, false); - let result = mask_diag_sparse(&mat); - assert_sparse_mat_compare( - &result, - &vec_to_sparse_mat_fixed(&target, 3, false), - I32F32::from_num(0), - ); - let vector: Vec = vec![1., 0., 0., 0., 5., 0., 0., 0., 9.]; - let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let mat = vec_to_sparse_mat_fixed(&vector, 3, false); - let result = mask_diag_sparse(&mat); - assert_sparse_mat_compare( - &result, - &vec_to_sparse_mat_fixed(&target, 3, false), - I32F32::from_num(0), - ); - let vector: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let mat = vec_to_sparse_mat_fixed(&vector, 3, false); - let result = mask_diag_sparse(&mat); - assert_sparse_mat_compare( - &result, - &vec_to_sparse_mat_fixed(&target, 3, false), - I32F32::from_num(0), - ); -} - -#[test] -fn test_math_vec_mask_sparse_matrix() { - let vector: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9.]; - let target: Vec = vec![0., 2., 3., 4., 0., 6., 7., 8., 0.]; - let mat = vec_to_sparse_mat_fixed(&vector, 3, false); - let first_vector: Vec = vec![1, 2, 3]; - let second_vector: Vec = vec![1, 2, 3]; - let result = vec_mask_sparse_matrix(&mat, &first_vector, &second_vector, &|a, b| a == b); - assert_sparse_mat_compare( - &result, - &vec_to_sparse_mat_fixed(&target, 3, false), - I32F32::from_num(0), - ); - let target: Vec = vec![1., 0., 0., 4., 5., 0., 7., 8., 9.]; - let mat = vec_to_sparse_mat_fixed(&vector, 3, false); - let first_vector: Vec = vec![1, 2, 3]; - let second_vector: Vec = vec![1, 2, 3]; - let result = vec_mask_sparse_matrix(&mat, &first_vector, &second_vector, &|a, b| a < b); - assert_sparse_mat_compare( - &result, - &vec_to_sparse_mat_fixed(&target, 3, false), - I32F32::from_num(0), - ); - let vector: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let mat = vec_to_sparse_mat_fixed(&vector, 3, false); - let first_vector: Vec = vec![1, 2, 3]; - let second_vector: Vec = vec![1, 2, 3]; - let result = vec_mask_sparse_matrix(&mat, &first_vector, &second_vector, &|a, b| a == b); - assert_sparse_mat_compare( - &result, - &vec_to_sparse_mat_fixed(&target, 3, false), - I32F32::from_num(0), - ); -} - -#[test] -fn test_math_row_hadamard() { - let vector: Vec = vec_to_fixed(&[1., 2., 3., 4.]); - let matrix: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; - let matrix = vec_to_mat_fixed(&matrix, 4, false); - let result = row_hadamard(&matrix, &vector); - let target: Vec = vec![1., 2., 3., 8., 10., 12., 21., 24., 27., 40., 44., 48.]; - let target = vec_to_mat_fixed(&target, 4, false); - assert_mat_compare(&result, &target, I32F32::from_num(0)); -} - -#[test] -fn test_math_row_hadamard_sparse() { - let vector: Vec = vec_to_fixed(&[1., 2., 3., 4.]); - let matrix: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; - let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); - let result = row_hadamard_sparse(&matrix, &vector); - let target: Vec = vec![1., 2., 3., 8., 10., 12., 21., 24., 27., 40., 44., 48.]; - let target = vec_to_sparse_mat_fixed(&target, 4, false); - assert_sparse_mat_compare(&result, &target, I32F32::from_num(0)); - let matrix: Vec = vec![0., 2., 3., 4., 0., 6., 7., 8., 0., 10., 11., 12.]; - let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); - let result = row_hadamard_sparse(&matrix, &vector); - let target: Vec = vec![0., 2., 3., 8., 0., 12., 21., 24., 0., 40., 44., 48.]; - let target = vec_to_sparse_mat_fixed(&target, 4, false); - assert_sparse_mat_compare(&result, &target, I32F32::from_num(0)); - let matrix: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); - let result = row_hadamard_sparse(&matrix, &vector); - let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let target = vec_to_sparse_mat_fixed(&target, 4, false); - assert_sparse_mat_compare(&result, &target, I32F32::from_num(0)); -} - -#[test] -fn test_math_row_sum() { - let matrix: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; - let matrix = vec_to_mat_fixed(&matrix, 4, false); - let result = row_sum(&matrix); - let target: Vec = vec_to_fixed(&[6., 15., 24., 33.]); - assert_vec_compare(&result, &target, I32F32::from_num(0)); -} - -#[test] -fn test_math_row_sum_sparse() { - let matrix: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; - let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); - let result = row_sum_sparse(&matrix); - let target: Vec = vec_to_fixed(&[6., 15., 24., 33.]); - assert_vec_compare(&result, &target, I32F32::from_num(0)); - let matrix: Vec = vec![0., 2., 3., 4., 0., 6., 7., 8., 0., 10., 11., 12.]; - let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); - let result = row_sum_sparse(&matrix); - let target: Vec = vec_to_fixed(&[5., 10., 15., 33.]); - assert_vec_compare(&result, &target, I32F32::from_num(0)); - let matrix: Vec = vec![1., 2., 3., 0., 0., 0., 7., 8., 9., 10., 11., 12.]; - let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); - let result = row_sum_sparse(&matrix); - let target: Vec = vec_to_fixed(&[6., 0., 24., 33.]); - assert_vec_compare(&result, &target, I32F32::from_num(0)); - let matrix: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); - let result = row_sum_sparse(&matrix); - let target: Vec = vec_to_fixed(&[0., 0., 0., 0.]); - assert_vec_compare(&result, &target, I32F32::from_num(0)); -} - -#[test] -fn test_math_col_sum() { - let matrix: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; - let matrix = vec_to_mat_fixed(&matrix, 4, false); - let result = col_sum(&matrix); - let target: Vec = vec_to_fixed(&[22., 26., 30.]); - assert_vec_compare(&result, &target, I32F32::from_num(0)); -} - -#[test] -fn test_math_col_sum_sparse() { - let matrix: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; - let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); - let result = col_sum_sparse(&matrix, 3); - let target: Vec = vec_to_fixed(&[22., 26., 30.]); - assert_vec_compare(&result, &target, I32F32::from_num(0)); - let matrix: Vec = vec![0., 2., 3., 4., 0., 6., 7., 8., 0., 10., 11., 12.]; - let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); - let result = col_sum_sparse(&matrix, 3); - let target: Vec = vec_to_fixed(&[21., 21., 21.]); - assert_vec_compare(&result, &target, I32F32::from_num(0)); - let matrix: Vec = vec![1., 0., 3., 4., 0., 6., 7., 0., 9., 10., 0., 12.]; - let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); - let result = col_sum_sparse(&matrix, 3); - let target: Vec = vec_to_fixed(&[22., 0., 30.]); - assert_vec_compare(&result, &target, I32F32::from_num(0)); - let matrix: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); - let result = col_sum_sparse(&matrix, 3); - let target: Vec = vec_to_fixed(&[0., 0., 0.]); - assert_vec_compare(&result, &target, I32F32::from_num(0)); -} - -#[test] -fn test_math_matmul() { - let vector: Vec = vec_to_fixed(&[1., 2., 3., 4.]); - let matrix: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; - let matrix = vec_to_mat_fixed(&matrix, 4, false); - let result = matmul(&matrix, &vector); - let target: Vec = vec_to_fixed(&[70., 80., 90.]); - assert_vec_compare(&result, &target, I32F32::from_num(0)); -} - -#[test] -fn test_math_matmul_transpose() { - let vector: Vec = vec_to_fixed(&[1., 2., 3.]); - let matrix: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; - let matrix = vec_to_mat_fixed(&matrix, 4, false); - let result = matmul_transpose(&matrix, &vector); - let target: Vec = vec_to_fixed(&[14., 32., 50., 68.]); - assert_vec_compare(&result, &target, I32F32::from_num(0)); -} - -#[test] -fn test_math_sparse_matmul() { - let vector: Vec = vec_to_fixed(&[1., 2., 3., 4.]); - let matrix: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; - let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); - let result = matmul_sparse(&matrix, &vector, 3); - let target: Vec = vec_to_fixed(&[70., 80., 90.]); - assert_vec_compare(&result, &target, I32F32::from_num(0)); - let matrix: Vec = vec![0., 2., 3., 4., 0., 6., 7., 8., 0., 10., 11., 12.]; - let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); - let result = matmul_sparse(&matrix, &vector, 3); - let target: Vec = vec_to_fixed(&[69., 70., 63.]); - assert_vec_compare(&result, &target, I32F32::from_num(0)); - let matrix: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); - let result = matmul_sparse(&matrix, &vector, 3); - let target: Vec = vec_to_fixed(&[0., 0., 0.]); - assert_vec_compare(&result, &target, I32F32::from_num(0)); -} - -#[test] -fn test_math_sparse_matmul_transpose() { - let vector: Vec = vec_to_fixed(&[1., 2., 3.]); - let matrix: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; - let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); - let result = matmul_transpose_sparse(&matrix, &vector); - let target: Vec = vec_to_fixed(&[14., 32., 50., 68.]); - assert_vec_compare(&result, &target, I32F32::from_num(0)); - let matrix: Vec = vec![0., 2., 3., 4., 0., 6., 7., 8., 0., 10., 11., 12.]; - let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); - let result = matmul_transpose_sparse(&matrix, &vector); - let target: Vec = vec_to_fixed(&[13., 22., 23., 68.]); - assert_vec_compare(&result, &target, I32F32::from_num(0)); - let matrix: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); - let result = matmul_transpose_sparse(&matrix, &vector); - let target: Vec = vec_to_fixed(&[0., 0., 0., 0.]); - assert_vec_compare(&result, &target, I32F32::from_num(0)); -} - -#[test] -fn test_math_inplace_col_clip() { - let vector: Vec = vec_to_fixed(&[0., 5., 12.]); - let matrix: Vec = vec![0., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; - let mut matrix = vec_to_mat_fixed(&matrix, 4, false); - let target: Vec = vec![0., 2., 3., 0., 5., 6., 0., 5., 9., 0., 5., 12.]; - let target = vec_to_mat_fixed(&target, 4, false); - inplace_col_clip(&mut matrix, &vector); - assert_mat_compare(&matrix, &target, I32F32::from_num(0)); -} - -#[test] -fn test_math_col_clip_sparse() { - let vector: Vec = vec_to_fixed(&[0., 5., 12.]); - let matrix: Vec = vec![0., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; - let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); - let target: Vec = vec![0., 2., 3., 0., 5., 6., 0., 5., 9., 0., 5., 12.]; - let target = vec_to_sparse_mat_fixed(&target, 4, false); - let result = col_clip_sparse(&matrix, &vector); - assert_sparse_mat_compare(&result, &target, I32F32::from_num(0)); - let matrix: Vec = vec![0., 2., 3., 4., 5., 6., 0., 0., 0., 10., 11., 12.]; - let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); - let target: Vec = vec![0., 2., 3., 0., 5., 6., 0., 0., 0., 0., 5., 12.]; - let target = vec_to_sparse_mat_fixed(&target, 4, false); - let result = col_clip_sparse(&matrix, &vector); - assert_sparse_mat_compare(&result, &target, I32F32::from_num(0)); - let matrix: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); - let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let target = vec_to_sparse_mat_fixed(&target, 4, false); - let result = col_clip_sparse(&matrix, &vector); - assert_sparse_mat_compare(&result, &target, I32F32::from_num(0)); -} - -#[test] -fn test_math_clip_sparse() { - let matrix: Vec = vec![0., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; - let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); - let target: Vec = vec![0., 1., 1., 1., 1., 1., 1., 100., 100., 100., 100., 100.]; - let target = vec_to_sparse_mat_fixed(&target, 4, false); - let result = clip_sparse( - &matrix, - I32F32::from_num(8), - I32F32::from_num(100), - I32F32::from_num(1), - ); - assert_sparse_mat_compare(&result, &target, I32F32::from_num(0)); -} - -#[test] -fn test_math_clip() { - let matrix: Vec = vec![0., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; - let matrix = vec_to_mat_fixed(&matrix, 4, false); - let target: Vec = vec![1., 1., 1., 1., 1., 1., 1., 100., 100., 100., 100., 100.]; - let target = vec_to_mat_fixed(&target, 4, false); - let result = clip( - &matrix, - I32F32::from_num(8), - I32F32::from_num(100), - I32F32::from_num(1), - ); - assert_mat_compare(&result, &target, I32F32::from_num(0)); -} - -#[test] -fn test_math_inplace_clip() { - let matrix: Vec = vec![0., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; - let mut matrix = vec_to_mat_fixed(&matrix, 4, false); - let target: Vec = vec![1., 1., 1., 1., 1., 1., 1., 100., 100., 100., 100., 100.]; - let target = vec_to_mat_fixed(&target, 4, false); - inplace_clip( - &mut matrix, - I32F32::from_num(8), - I32F32::from_num(100), - I32F32::from_num(1), - ); - assert_mat_compare(&matrix, &target, I32F32::from_num(0)); -} - -#[test] -fn test_math_weighted_median() { - let mut rng = thread_rng(); - let zero: I32F32 = fixed(0.); - let one: I32F32 = fixed(1.); - for _ in 0..100 { - let stake: Vec = vec_to_fixed(&[]); - let score: Vec = vec_to_fixed(&[]); - let majority: I32F32 = fixed(0.51); - assert_eq!( - zero, - weighted_median( - &stake, - &score, - (0..stake.len()).collect::>().as_slice(), - one - majority, - zero, - stake.iter().sum() - ) - ); - - let stake: Vec = normalize(&vec_to_fixed(&[0.51])); - let score: Vec = vec_to_fixed(&[1.]); - let majority: I32F32 = fixed(0.51); - assert_eq!( - one, - weighted_median( - &stake, - &score, - (0..stake.len()).collect::>().as_slice(), - one - majority, - zero, - stake.iter().sum() - ) - ); - - let stake: Vec = vec_to_fixed(&[0.49, 0.51]); - let score: Vec = vec_to_fixed(&[0.5, 1.]); - let majority: I32F32 = fixed(0.51); - assert_eq!( - one, - weighted_median( - &stake, - &score, - (0..stake.len()).collect::>().as_slice(), - one - majority, - zero, - stake.iter().sum() - ) - ); - - let stake: Vec = vec_to_fixed(&[0.51, 0.49]); - let score: Vec = vec_to_fixed(&[0.5, 1.]); - let majority: I32F32 = fixed(0.51); - assert_eq!( - fixed(0.5), - weighted_median( - &stake, - &score, - (0..stake.len()).collect::>().as_slice(), - one - majority, - zero, - stake.iter().sum() - ) - ); - - let stake: Vec = vec_to_fixed(&[0.49, 0., 0.51]); - let score: Vec = vec_to_fixed(&[0.5, 0.7, 1.]); - let majority: I32F32 = fixed(0.51); - assert_eq!( - one, - weighted_median( - &stake, - &score, - (0..stake.len()).collect::>().as_slice(), - one - majority, - zero, - stake.iter().sum() - ) - ); - - let stake: Vec = vec_to_fixed(&[0.49, 0.01, 0.5]); - let score: Vec = vec_to_fixed(&[0.5, 0.7, 1.]); - let majority: I32F32 = fixed(0.51); - assert_eq!( - fixed(0.7), - weighted_median( - &stake, - &score, - (0..stake.len()).collect::>().as_slice(), - one - majority, - zero, - stake.iter().sum() - ) - ); - - let stake: Vec = vec_to_fixed(&[0.49, 0.51, 0.0]); - let score: Vec = vec_to_fixed(&[0.5, 0.7, 1.]); - let majority: I32F32 = fixed(0.51); - assert_eq!( - fixed(0.7), - weighted_median( - &stake, - &score, - (0..stake.len()).collect::>().as_slice(), - one - majority, - zero, - stake.iter().sum() - ) - ); - - let stake: Vec = vec_to_fixed(&[0.0, 0.49, 0.51]); - let score: Vec = vec_to_fixed(&[0.5, 0.7, 1.]); - let majority: I32F32 = fixed(0.51); - assert_eq!( - one, - weighted_median( - &stake, - &score, - (0..stake.len()).collect::>().as_slice(), - one - majority, - zero, - stake.iter().sum() - ) - ); - - let stake: Vec = vec_to_fixed(&[0.0, 0.49, 0.0, 0.51]); - let score: Vec = vec_to_fixed(&[0.5, 0.5, 1., 1.]); - let majority: I32F32 = fixed(0.51); - assert_eq!( - one, - weighted_median( - &stake, - &score, - (0..stake.len()).collect::>().as_slice(), - one - majority, - zero, - stake.iter().sum() - ) - ); - - let stake: Vec = vec_to_fixed(&[0.0, 0.49, 0.0, 0.51, 0.0]); - let score: Vec = vec_to_fixed(&[0.5, 0.5, 1., 1., 0.5]); - let majority: I32F32 = fixed(0.51); - assert_eq!( - one, - weighted_median( - &stake, - &score, - (0..stake.len()).collect::>().as_slice(), - one - majority, - zero, - stake.iter().sum() - ) - ); - - let stake: Vec = vec_to_fixed(&[0.2, 0.2, 0.2, 0.2, 0.2]); - let score: Vec = vec_to_fixed(&[0.8, 0.2, 1., 0.6, 0.4]); - let majority: I32F32 = fixed(0.51); - assert_eq!( - fixed(0.6), - weighted_median( - &stake, - &score, - (0..stake.len()).collect::>().as_slice(), - one - majority, - zero, - stake.iter().sum() - ) - ); - - let stake: Vec = vec_to_fixed(&[0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]); - let score: Vec = vec_to_fixed(&[0.8, 0.8, 0.2, 0.2, 1.0, 1.0, 0.6, 0.6, 0.4, 0.4]); - let majority: I32F32 = fixed(0.51); - assert_eq!( - fixed(0.6), - weighted_median( - &stake, - &score, - (0..stake.len()).collect::>().as_slice(), - one - majority, - zero, - stake.iter().sum() - ) - ); - - let n: usize = 100; - for majority in vec_to_fixed(&[ - 0., 0.0000001, 0.25, 0.49, 0.49, 0.49, 0.5, 0.51, 0.51, 0.51, 0.9999999, 1., - ]) { - for allow_equal in [false, true] { - let mut stake: Vec = vec![]; - let mut score: Vec = vec![]; - let mut last_score: I32F32 = zero; - for i in 0..n { - if allow_equal { - match rng.gen_range(0..2) { - 1 => stake.push(one), - _ => stake.push(zero), - } - if rng.gen_range(0..2) == 1 { - last_score += one - } - score.push(last_score); - } else { - stake.push(one); - score.push(I32F32::from_num(i)); - } - } - inplace_normalize(&mut stake); - let total_stake: I32F32 = stake.iter().sum(); - let mut minority: I32F32 = total_stake - majority; - if minority < zero { - minority = zero; - } - let mut medians: Vec = vec![]; - let mut median_stake: I32F32 = zero; - let mut median_set = false; - let mut stake_sum: I32F32 = zero; - for i in 0..n { - stake_sum += stake[i]; - if !median_set && stake_sum >= minority { - median_stake = stake_sum; - median_set = true; - } - if median_set { - if median_stake < stake_sum { - if median_stake == minority && !medians.contains(&score[i]) { - medians.push(score[i]); - } - break; - } - if !medians.contains(&score[i]) { - medians.push(score[i]); - } - } - } - if medians.is_empty() { - medians.push(zero); - } - let stake_idx: Vec = (0..stake.len()).collect(); - let result: I32F32 = - weighted_median(&stake, &score, &stake_idx, minority, zero, total_stake); - assert!(medians.contains(&result)); - for _ in 0..10 { - let mut permuted_uids: Vec = (0..n).collect(); - permuted_uids.shuffle(&mut thread_rng()); - stake = permuted_uids.iter().map(|&i| stake[i]).collect(); - score = permuted_uids.iter().map(|&i| score[i]).collect(); - let result: I32F32 = - weighted_median(&stake, &score, &stake_idx, minority, zero, total_stake); - assert!(medians.contains(&result)); - } - } - } - } -} - -#[test] -fn test_math_weighted_median_col() { - let stake: Vec = vec_to_fixed(&[]); - let weights: Vec> = vec![vec![]]; - let median: Vec = vec_to_fixed(&[]); - assert_eq!(median, weighted_median_col(&stake, &weights, fixed(0.5))); - - let stake: Vec = vec_to_fixed(&[0., 0.]); - let weights: Vec = vec![0., 0., 0., 0.]; - let weights: Vec> = vec_to_mat_fixed(&weights, 2, false); - let median: Vec = vec_to_fixed(&[0., 0.]); - assert_eq!(median, weighted_median_col(&stake, &weights, fixed(0.5))); - - let stake: Vec = vec_to_fixed(&[0., 0.75, 0.25, 0.]); - let weights: Vec = vec![0., 0.1, 0., 0., 0.2, 0.4, 0., 0.3, 0.1, 0., 0.4, 0.5]; - let weights: Vec> = vec_to_mat_fixed(&weights, 4, false); - let median: Vec = vec_to_fixed(&[0., 0.3, 0.4]); - assert_eq!(median, weighted_median_col(&stake, &weights, fixed(0.24))); - let median: Vec = vec_to_fixed(&[0., 0.2, 0.4]); - assert_eq!(median, weighted_median_col(&stake, &weights, fixed(0.26))); - let median: Vec = vec_to_fixed(&[0., 0.2, 0.1]); - assert_eq!(median, weighted_median_col(&stake, &weights, fixed(0.76))); - - let stake: Vec = vec_to_fixed(&[0., 0.3, 0.2, 0.5]); - let weights: Vec = vec![0., 0.1, 0., 0., 0.2, 0.4, 0., 0.3, 0.1, 0., 0., 0.5]; - let weights: Vec> = vec_to_mat_fixed(&weights, 4, false); - let median: Vec = vec_to_fixed(&[0., 0., 0.4]); - assert_eq!(median, weighted_median_col(&stake, &weights, fixed(0.51))); -} - -#[test] -fn test_math_weighted_median_col_sparse() { - let stake: Vec = vec_to_fixed(&[]); - let weights: Vec> = vec![vec![]]; - let median: Vec = vec_to_fixed(&[]); - assert_eq!( - median, - weighted_median_col_sparse(&stake, &weights, 0, fixed(0.5)) - ); - - let stake: Vec = vec_to_fixed(&[0., 0.]); - let weights: Vec = vec![0., 0., 0., 0.]; - let weights: Vec> = vec_to_sparse_mat_fixed(&weights, 2, false); - let median: Vec = vec_to_fixed(&[0., 0.]); - assert_eq!( - median, - weighted_median_col_sparse(&stake, &weights, 2, fixed(0.5)) - ); - - let stake: Vec = vec_to_fixed(&[0., 0.75, 0.25, 0.]); - let weights: Vec = vec![0., 0.1, 0., 0., 0.2, 0.4, 0., 0.3, 0.1, 0., 0.4, 0.5]; - let weights: Vec> = vec_to_sparse_mat_fixed(&weights, 4, false); - let median: Vec = vec_to_fixed(&[0., 0.3, 0.4]); - assert_eq!( - median, - weighted_median_col_sparse(&stake, &weights, 3, fixed(0.24)) - ); - let median: Vec = vec_to_fixed(&[0., 0.2, 0.4]); - assert_eq!( - median, - weighted_median_col_sparse(&stake, &weights, 3, fixed(0.26)) - ); - let median: Vec = vec_to_fixed(&[0., 0.2, 0.1]); - assert_eq!( - median, - weighted_median_col_sparse(&stake, &weights, 3, fixed(0.76)) - ); - - let stake: Vec = vec_to_fixed(&[0., 0.3, 0.2, 0.5]); - let weights: Vec = vec![0., 0.1, 0., 0., 0.2, 0.4, 0., 0.3, 0.1, 0., 0., 0.5]; - let weights: Vec> = vec_to_sparse_mat_fixed(&weights, 4, false); - let median: Vec = vec_to_fixed(&[0., 0., 0.4]); - assert_eq!( - median, - weighted_median_col_sparse(&stake, &weights, 3, fixed(0.51)) - ); -} - -#[test] -fn test_math_hadamard() { - let mat2: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; - let mat1: Vec = vec![ - 10., 20., 30., 40., 50., 60., 70., 80., 90., 100., 110., 120., - ]; - let target: Vec = vec![ - 10., 40., 90., 160., 250., 360., 490., 640., 810., 1000., 1210., 1440., - ]; - let mat2 = vec_to_mat_fixed(&mat2, 4, false); - let mat1 = vec_to_mat_fixed(&mat1, 4, false); - let target = vec_to_mat_fixed(&target, 4, false); - let result = hadamard(&mat1, &mat2); - assert_mat_compare(&result, &target, I32F32::from_num(0.000001)); - let mat2: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let mat1: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let mat2 = vec_to_mat_fixed(&mat2, 4, false); - let mat1 = vec_to_mat_fixed(&mat1, 4, false); - let target = vec_to_mat_fixed(&target, 4, false); - let result = hadamard(&mat1, &mat2); - assert_mat_compare(&result, &target, I32F32::from_num(0.000001)); - let mat2: Vec = vec![1., 0., 0., 0., 2., 0., 0., 0., 3., 0., 0., 0.]; - let mat1: Vec = vec![0., 0., 4., 0., 5., 0., 6., 0., 0., 0., 0., 0.]; - let target: Vec = vec![0., 0., 0., 0., 10., 0., 0., 0., 0., 0., 0., 0.]; - let mat2 = vec_to_mat_fixed(&mat2, 4, false); - let mat1 = vec_to_mat_fixed(&mat1, 4, false); - let target = vec_to_mat_fixed(&target, 4, false); - let result = hadamard(&mat1, &mat2); - assert_mat_compare(&result, &target, I32F32::from_num(0.000001)); -} - -#[test] -fn test_math_hadamard_sparse() { - let mat2: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; - let mat1: Vec = vec![ - 10., 20., 30., 40., 50., 60., 70., 80., 90., 100., 110., 120., - ]; - let target: Vec = vec![ - 10., 40., 90., 160., 250., 360., 490., 640., 810., 1000., 1210., 1440., - ]; - let mat2 = vec_to_sparse_mat_fixed(&mat2, 4, false); - let mat1 = vec_to_sparse_mat_fixed(&mat1, 4, false); - let target = vec_to_sparse_mat_fixed(&target, 4, false); - let result = hadamard_sparse(&mat1, &mat2, 3); - assert_sparse_mat_compare(&result, &target, I32F32::from_num(0.000001)); - let mat2: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let mat1: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let mat2 = vec_to_sparse_mat_fixed(&mat2, 4, false); - let mat1 = vec_to_sparse_mat_fixed(&mat1, 4, false); - let target = vec_to_sparse_mat_fixed(&target, 4, false); - let result = hadamard_sparse(&mat1, &mat2, 3); - assert_sparse_mat_compare(&result, &target, I32F32::from_num(0.000001)); - let mat2: Vec = vec![1., 0., 0., 0., 2., 0., 0., 0., 3., 0., 0., 0.]; - let mat1: Vec = vec![0., 0., 4., 0., 5., 0., 6., 0., 0., 0., 0., 0.]; - let target: Vec = vec![0., 0., 0., 0., 10., 0., 0., 0., 0., 0., 0., 0.]; - let mat2 = vec_to_sparse_mat_fixed(&mat2, 4, false); - let mat1 = vec_to_sparse_mat_fixed(&mat1, 4, false); - let target = vec_to_sparse_mat_fixed(&target, 4, false); - let result = hadamard_sparse(&mat1, &mat2, 3); - assert_sparse_mat_compare(&result, &target, I32F32::from_num(0.000001)); -} - -#[test] -fn test_math_mat_ema() { - let old: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; - let new: Vec = vec![ - 10., 20., 30., 40., 50., 60., 70., 80., 90., 100., 110., 120., - ]; - let target: Vec = vec![ - 1.9, 3.8, 5.7, 7.6, 9.5, 11.4, 13.3, 15.2, 17.1, 19., 20.9, 22.8, - ]; - let old = vec_to_mat_fixed(&old, 4, false); - let new = vec_to_mat_fixed(&new, 4, false); - let target = vec_to_mat_fixed(&target, 4, false); - let result = mat_ema(&new, &old, I32F32::from_num(0.1)); - assert_mat_compare(&result, &target, I32F32::from_num(0.000001)); - let old: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; - let new: Vec = vec![ - 10., 20., 30., 40., 50., 60., 70., 80., 90., 100., 110., 120., - ]; - let target: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; - let old = vec_to_mat_fixed(&old, 4, false); - let new = vec_to_mat_fixed(&new, 4, false); - let target = vec_to_mat_fixed(&target, 4, false); - let result = mat_ema(&new, &old, I32F32::from_num(0)); - assert_mat_compare(&result, &target, I32F32::from_num(0.000001)); - let old: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; - let new: Vec = vec![ - 10., 20., 30., 40., 50., 60., 70., 80., 90., 100., 110., 120., - ]; - let target: Vec = vec![ - 10., 20., 30., 40., 50., 60., 70., 80., 90., 100., 110., 120., - ]; - let old = vec_to_mat_fixed(&old, 4, false); - let new = vec_to_mat_fixed(&new, 4, false); - let target = vec_to_mat_fixed(&target, 4, false); - let result = mat_ema(&new, &old, I32F32::from_num(1)); - assert_mat_compare(&result, &target, I32F32::from_num(0.000001)); -} - -#[test] -fn test_math_sparse_mat_ema() { - let old: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; - let new: Vec = vec![ - 10., 20., 30., 40., 50., 60., 70., 80., 90., 100., 110., 120., - ]; - let target: Vec = vec![ - 1.9, 3.8, 5.7, 7.6, 9.5, 11.4, 13.3, 15.2, 17.1, 19., 20.9, 22.8, - ]; - 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 result = mat_ema_sparse(&new, &old, I32F32::from_num(0.1)); - assert_sparse_mat_compare(&result, &target, I32F32::from_num(0.000001)); - let old: Vec = vec![0., 2., 3., 4., 0., 6., 7., 8., 0., 10., 11., 12.]; - let new: Vec = vec![10., 20., 0., 40., 0., 60., 0., 80., 90., 100., 110., 120.]; - let target: Vec = vec![1., 3.8, 2.7, 7.6, 0., 11.4, 6.3, 15.2, 9., 19., 20.9, 22.8]; - 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 result = mat_ema_sparse(&new, &old, I32F32::from_num(0.1)); - assert_sparse_mat_compare(&result, &target, I32F32::from_num(0.000001)); - let old: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let new: Vec = vec![10., 20., 0., 40., 0., 60., 0., 80., 90., 100., 110., 120.]; - let target: Vec = vec![1., 2., 0., 4., 0., 6., 0., 8., 9., 10., 11., 12.]; - 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 result = mat_ema_sparse(&new, &old, I32F32::from_num(0.1)); - assert_sparse_mat_compare(&result, &target, I32F32::from_num(0.000001)); - let old: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let new: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let target: Vec = vec![0., 0., 0., 0., 0., 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 result = mat_ema_sparse(&new, &old, I32F32::from_num(0.1)); - assert_sparse_mat_compare(&result, &target, I32F32::from_num(0.000001)); - 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.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 result = mat_ema_sparse(&new, &old, I32F32::from_num(0.1)); - assert_sparse_mat_compare(&result, &target, I32F32::from_num(0.000001)); -} - -#[test] -fn test_math_matmul2() { - let epsilon: I32F32 = I32F32::from_num(0.0001); - let w: Vec> = vec![vec![I32F32::from_num(1.0); 3]; 3]; - assert_vec_compare( - &matmul(&w, &[I32F32::from_num(1.0); 3]), - &[ - I32F32::from_num(3), - I32F32::from_num(3), - I32F32::from_num(3), - ], - epsilon, - ); - assert_vec_compare( - &matmul(&w, &[I32F32::from_num(2.0); 3]), - &[ - I32F32::from_num(6), - I32F32::from_num(6), - I32F32::from_num(6), - ], - epsilon, - ); - assert_vec_compare( - &matmul(&w, &[I32F32::from_num(3.0); 3]), - &[ - I32F32::from_num(9), - I32F32::from_num(9), - I32F32::from_num(9), - ], - epsilon, - ); - assert_vec_compare( - &matmul(&w, &[I32F32::from_num(-1.0); 3]), - &[ - I32F32::from_num(-3), - I32F32::from_num(-3), - I32F32::from_num(-3), - ], - epsilon, - ); - let w: Vec> = vec![vec![I32F32::from_num(-1.0); 3]; 3]; - assert_vec_compare( - &matmul(&w, &[I32F32::from_num(1.0); 3]), - &[ - I32F32::from_num(-3), - I32F32::from_num(-3), - I32F32::from_num(-3), - ], - epsilon, - ); - assert_vec_compare( - &matmul(&w, &[I32F32::from_num(2.0); 3]), - &[ - I32F32::from_num(-6), - I32F32::from_num(-6), - I32F32::from_num(-6), - ], - epsilon, - ); - assert_vec_compare( - &matmul(&w, &[I32F32::from_num(3.0); 3]), - &[ - I32F32::from_num(-9), - I32F32::from_num(-9), - I32F32::from_num(-9), - ], - epsilon, - ); - assert_vec_compare( - &matmul(&w, &[I32F32::from_num(-1.0); 3]), - &[ - I32F32::from_num(3), - I32F32::from_num(3), - I32F32::from_num(3), - ], - epsilon, - ); - let w: Vec> = vec![ - vec![I32F32::from_num(1.0); 3], - vec![I32F32::from_num(2.0); 3], - vec![I32F32::from_num(3.0); 3], - ]; - assert_vec_compare( - &matmul(&w, &[I32F32::from_num(0.0); 3]), - &[ - I32F32::from_num(0.0), - I32F32::from_num(0.0), - I32F32::from_num(0.0), - ], - epsilon, - ); - assert_vec_compare( - &matmul(&w, &[I32F32::from_num(2.0); 3]), - &[ - I32F32::from_num(12), - I32F32::from_num(12), - I32F32::from_num(12), - ], - epsilon, - ); - let w: Vec> = vec![ - vec![ - I32F32::from_num(1), - I32F32::from_num(2), - I32F32::from_num(3) - ]; - 3 - ]; - assert_vec_compare( - &matmul(&w, &[I32F32::from_num(0.0); 3]), - &[ - I32F32::from_num(0.0), - I32F32::from_num(0.0), - I32F32::from_num(0.0), - ], - epsilon, - ); - assert_vec_compare( - &matmul(&w, &[I32F32::from_num(2.0); 3]), - &[ - I32F32::from_num(6), - I32F32::from_num(12), - I32F32::from_num(18), - ], - epsilon, - ); -} - -#[test] -fn test_math_fixed_to_u16() { - let expected = u16::MIN; - assert_eq!(fixed_to_u16(I32F32::from_num(expected)), expected); - - let expected = u16::MAX / 2; - assert_eq!(fixed_to_u16(I32F32::from_num(expected)), expected); - - let expected = u16::MAX; - assert_eq!(fixed_to_u16(I32F32::from_num(expected)), expected); -} - -#[test] -#[should_panic(expected = "overflow")] -fn test_math_fixed_to_u16_panics() { - let bad_input = I32F32::from_num(u32::MAX); - fixed_to_u16(bad_input); - - let bad_input = I32F32::from_num(-1); - fixed_to_u16(bad_input); -} - -// TODO: Investigate why `I32F32` and not `I64F64` -#[test] -fn test_math_fixed_to_u64() { - let expected = u64::MIN; - assert_eq!(fixed_to_u64(I32F32::from_num(expected)), expected); - - // let expected = u64::MAX / 2; - // assert_eq!(fixed_to_u64(I32F32::from_num(expected)), expected); - - // let expected = u64::MAX; - // assert_eq!(fixed_to_u64(I32F32::from_num(expected)), expected); -} - -#[test] -#[should_panic(expected = "-1 overflows")] -fn test_math_fixed_to_u64_panics() { - let bad_input = I32F32::from_num(-1); - fixed_to_u64(bad_input); -} - -#[test] -fn test_math_fixed64_to_u64() { - let expected = u64::MIN; - assert_eq!(fixed64_to_u64(I64F64::from_num(expected)), expected); - - let input = i64::MAX / 2; - let expected = u64::try_from(input).unwrap(); - assert_eq!(fixed64_to_u64(I64F64::from_num(input)), expected); - - let input = i64::MAX; - let expected = u64::try_from(input).unwrap(); - assert_eq!(fixed64_to_u64(I64F64::from_num(input)), expected); -} - -#[test] -#[should_panic(expected = "-1 overflows")] -fn test_math_fixed64_to_u64_panics() { - let bad_input = I64F64::from_num(-1); - fixed64_to_u64(bad_input); -} - -/* @TODO: find the _true_ max, and half, input values */ -#[test] -fn test_math_fixed64_to_fixed32() { - let input = u64::MIN; - let expected = u32::try_from(input).unwrap(); - assert_eq!(fixed64_to_fixed32(I64F64::from_num(expected)), expected); - - let expected = u32::MAX / 2; - let input = u64::from(expected); - assert_eq!(fixed64_to_fixed32(I64F64::from_num(input)), expected); -} - -#[test] -#[should_panic(expected = "overflow")] -fn test_math_fixed64_to_fixed32_panics() { - let bad_input = I64F64::from_num(u32::MAX); - fixed64_to_fixed32(bad_input); -} - -#[test] -fn test_math_u16_to_fixed() { - let input = u16::MIN; - let expected = I32F32::from_num(input); - assert_eq!(u16_to_fixed(input), expected); - - let input = u16::MAX / 2; - let expected = I32F32::from_num(input); - assert_eq!(u16_to_fixed(input), expected); - - let input = u16::MAX; - let expected = I32F32::from_num(input); - assert_eq!(u16_to_fixed(input), expected); -} - -#[test] -fn test_math_u16_proportion_to_fixed() { - let input = u16::MIN; - let expected = I32F32::from_num(input); - assert_eq!(u16_proportion_to_fixed(input), expected); -} - -#[test] -fn test_fixed_proportion_to_u16() { - let expected = u16::MIN; - let input = I32F32::from_num(expected); - assert_eq!(fixed_proportion_to_u16(input), expected); -} - -#[test] -#[should_panic(expected = "overflow")] -fn test_fixed_proportion_to_u16_panics() { - let expected = u16::MAX; - let input = I32F32::from_num(expected); - log::trace!("Testing with input: {:?}", input); // Debug output - let result = fixed_proportion_to_u16(input); - log::trace!("Testing with result: {:?}", result); // Debug output -} -#[test] -fn test_vec_fixed64_to_fixed32() { - let input = vec![I64F64::from_num(i32::MIN)]; - let expected = vec![I32F32::from_num(i32::MIN)]; - assert_eq!(vec_fixed64_to_fixed32(input), expected); - - let input = vec![I64F64::from_num(i32::MAX)]; - let expected = vec![I32F32::from_num(i32::MAX)]; - assert_eq!(vec_fixed64_to_fixed32(input), expected); -} - -#[test] -#[should_panic(expected = "overflow")] -fn test_vec_fixed64_to_fixed32_panics() { - let bad_input = vec![I64F64::from_num(i64::MAX)]; - vec_fixed64_to_fixed32(bad_input); -} - -#[test] -#[allow(arithmetic_overflow)] -fn test_checked_sum() { - let overflowing_input = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, u64::MAX]; - // Expect None when overflow occurs - assert_eq!(checked_sum(&overflowing_input), None); - - let normal_input = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - // Expect Some when no overflow occurs - assert_eq!(checked_sum(&normal_input), Some(55)); - - let empty_input: Vec = vec![]; - // Expect Some(u16::default()) when input is empty - assert_eq!(checked_sum(&empty_input), Some(u16::default())); - - let single_input = vec![1]; - // Expect Some(...) when input is a single value - assert_eq!(checked_sum(&single_input), Some(1)); -} - -#[test] -fn test_mat_ema_alpha_vec_sparse_empty() { - let new: Vec> = Vec::new(); - let old: Vec> = Vec::new(); - let alpha: Vec = Vec::new(); - let result = mat_ema_alpha_vec_sparse(&new, &old, &alpha); - assert_eq!(result, Vec::>::new()); -} - -#[test] -fn test_mat_ema_alpha_vec_sparse_single_element() { - let new: Vec> = vec![vec![(0, I32F32::from_num(1.0))]]; - let old: Vec> = vec![vec![(0, I32F32::from_num(2.0))]]; - let alpha: Vec = vec![I32F32::from_num(0.5)]; - let result = mat_ema_alpha_vec_sparse(&new, &old, &alpha); - assert_eq!(result, vec![vec![(0, I32F32::from_num(1.5))]]); -} - -#[test] -fn test_mat_ema_alpha_vec_sparse_multiple_elements() { - let new: Vec> = vec![ - vec![(0, I32F32::from_num(1.0)), (1, I32F32::from_num(2.0))], - vec![(0, I32F32::from_num(3.0)), (1, I32F32::from_num(4.0))], - ]; - let old: Vec> = vec![ - vec![(0, I32F32::from_num(5.0)), (1, I32F32::from_num(6.0))], - vec![(0, I32F32::from_num(7.0)), (1, I32F32::from_num(8.0))], - ]; - let alpha: Vec = vec![I32F32::from_num(0.1), I32F32::from_num(0.2)]; - let result = mat_ema_alpha_vec_sparse(&new, &old, &alpha); - let expected = vec![ - vec![(0, I32F32::from_num(4.6)), (1, I32F32::from_num(5.2))], - vec![(0, I32F32::from_num(6.6)), (1, I32F32::from_num(7.2))], - ]; - assert_sparse_mat_compare(&result, &expected, I32F32::from_num(0.000001)); -} - -#[test] -fn test_mat_ema_alpha_vec_sparse_zero_alpha() { - let new: Vec> = vec![vec![(0, I32F32::from_num(1.0))]]; - let old: Vec> = vec![vec![(0, I32F32::from_num(2.0))]]; - let alpha: Vec = vec![I32F32::from_num(0.0)]; - let result = mat_ema_alpha_vec_sparse(&new, &old, &alpha); - assert_eq!(result, vec![vec![(0, I32F32::from_num(2.0))]]); -} - -#[test] -fn test_mat_ema_alpha_vec_sparse_one_alpha() { - let new: Vec> = vec![vec![(0, I32F32::from_num(1.0))]]; - let old: Vec> = vec![vec![(0, I32F32::from_num(2.0))]]; - let alpha: Vec = vec![I32F32::from_num(1.0)]; - let result = mat_ema_alpha_vec_sparse(&new, &old, &alpha); - assert_eq!(result, vec![vec![(0, I32F32::from_num(1.0))]]); -} - -#[test] -fn test_mat_ema_alpha_vec_sparse_mixed_alpha() { - let new: Vec> = vec![ - vec![(0, I32F32::from_num(1.0)), (1, I32F32::from_num(2.0))], - vec![(0, I32F32::from_num(3.0)), (1, I32F32::from_num(4.0))], - ]; - let old: Vec> = vec![ - vec![(0, I32F32::from_num(5.0)), (1, I32F32::from_num(6.0))], - vec![(0, I32F32::from_num(7.0)), (1, I32F32::from_num(8.0))], - ]; - let alpha: Vec = vec![I32F32::from_num(0.3), I32F32::from_num(0.7)]; - let result = mat_ema_alpha_vec_sparse(&new, &old, &alpha); - assert_sparse_mat_compare( - &result, - &[ - vec![(0, I32F32::from_num(3.8)), (1, I32F32::from_num(3.2))], - vec![(0, I32F32::from_num(5.8)), (1, I32F32::from_num(5.2))], - ], - I32F32::from_num(0.000001), - ); -} - -#[test] -fn test_mat_ema_alpha_vec_sparse_sparse_matrix() { - let new: Vec> = vec![ - vec![(0, I32F32::from_num(1.0))], - vec![(1, I32F32::from_num(4.0))], - ]; - let old: Vec> = vec![ - vec![(0, I32F32::from_num(5.0))], - vec![(1, I32F32::from_num(8.0))], - ]; - let alpha: Vec = vec![I32F32::from_num(0.5), I32F32::from_num(0.5)]; - let result = mat_ema_alpha_vec_sparse(&new, &old, &alpha); - assert_eq!( - result, - vec![ - vec![(0, I32F32::from_num(3.0))], - vec![(1, I32F32::from_num(6.0))] - ] - ); -} - -#[test] -fn test_mat_ema_alpha_vec_basic() { - let new = mat_to_fixed(&[vec![1.0, 2.0, 3.0], vec![4.0, 5.0, 6.0]]); - let old = mat_to_fixed(&[vec![0.5, 1.5, 2.5], vec![3.5, 4.5, 5.5]]); - let alpha = vec![ - I32F32::from_num(0.5), - I32F32::from_num(0.5), - I32F32::from_num(0.5), - ]; - let expected = mat_to_fixed(&[vec![0.75, 1.75, 2.75], vec![3.75, 4.75, 5.75]]); - let result = mat_ema_alpha_vec(&new, &old, &alpha); - assert_eq!(result, expected); -} - -#[test] -fn test_mat_ema_alpha_vec_varying_alpha() { - let new = mat_to_fixed(&[vec![1.0, 2.0, 3.0], vec![4.0, 5.0, 6.0]]); - let old = mat_to_fixed(&[vec![0.5, 1.5, 2.5], vec![3.5, 4.5, 5.5]]); - let alpha = vec![ - I32F32::from_num(0.2), - I32F32::from_num(0.5), - I32F32::from_num(0.8), - ]; - let expected = mat_to_fixed(&[vec![0.6, 1.75, 2.9], vec![3.6, 4.75, 5.9]]); - let result = mat_ema_alpha_vec(&new, &old, &alpha); - assert_mat_approx_eq(&result, &expected, I32F32::from_num(1e-6)); -} - -#[test] -fn test_mat_ema_alpha_vec_empty_matrices() { - let new: Vec> = vec![]; - let old: Vec> = vec![]; - let alpha: Vec = vec![]; - let expected: Vec> = vec![vec![]; 1]; - let result = mat_ema_alpha_vec(&new, &old, &alpha); - assert_eq!(result, expected); -} - -#[test] -fn test_mat_ema_alpha_vec_single_element() { - let new = mat_to_fixed(&[vec![1.0]]); - let old = mat_to_fixed(&[vec![0.5]]); - let alpha = vec![I32F32::from_num(0.5)]; - let expected = mat_to_fixed(&[vec![0.75]]); - let result = mat_ema_alpha_vec(&new, &old, &alpha); - assert_eq!(result, expected); -} - -// TODO: (@sd): Should these be non panicking? -#[test] -#[should_panic(expected = "assertion failed")] -fn test_mat_ema_alpha_vec_mismatched_dimensions() { - let new = mat_to_fixed(&[vec![1.0, 2.0], vec![3.0, 4.0]]); - let old = mat_to_fixed(&[vec![1.0, 2.0, 3.0], vec![4.0, 5.0, 6.0]]); - let alpha = vec![ - I32F32::from_num(0.5), - I32F32::from_num(0.5), - I32F32::from_num(0.5), - ]; - let _result = mat_ema_alpha_vec(&new, &old, &alpha); -} - -#[test] -fn test_quantile() { - // Test with a non-empty vector and valid quantile values - let data = vec![ - I32F32::from_num(1.0), - I32F32::from_num(2.0), - I32F32::from_num(3.0), - I32F32::from_num(4.0), - I32F32::from_num(5.0), - ]; - - // Test 0th quantile (minimum) - let result = quantile(&data, 0.0); - assert_eq!(result, I32F32::from_num(1.0)); - - // Test 25th quantile - let result = quantile(&data, 0.25); - assert_eq!(result, I32F32::from_num(2.0)); - - // Test 50th quantile (median) - let result = quantile(&data, 0.5); - assert_eq!(result, I32F32::from_num(3.0)); - - // Test 66th quantile - let result = quantile(&data, 0.66); - assert_eq!(result, I32F32::from_num(3.64)); - - // Test 75th quantile - let result = quantile(&data, 0.75); - assert_eq!(result, I32F32::from_num(4.0)); - - // Test 100th quantile (maximum) - let result = quantile(&data, 1.0); - assert_eq!(result, I32F32::from_num(5.0)); -} diff --git a/pallets/subtensor/tests/mock.rs b/pallets/subtensor/tests/mock.rs index 51e3d1346..e5c4c4797 100644 --- a/pallets/subtensor/tests/mock.rs +++ b/pallets/subtensor/tests/mock.rs @@ -161,9 +161,6 @@ parameter_types! { pub const InitialNetworkRateLimit: u64 = 0; pub const InitialTargetStakesPerInterval: u16 = 2; pub const InitialHotkeySwapCost: u64 = 1_000_000_000; - pub const InitialAlphaHigh: u16 = 58982; // Represents 0.9 as per the production default - pub const InitialAlphaLow: u16 = 45875; // Represents 0.7 as per the production default - pub const InitialLiquidAlphaOn: bool = false; // Default value for LiquidAlphaOn } // Configure collective pallet for council @@ -371,9 +368,6 @@ impl pallet_subtensor::Config for Test { type InitialNetworkRateLimit = InitialNetworkRateLimit; type InitialTargetStakesPerInterval = InitialTargetStakesPerInterval; type HotkeySwapCost = InitialHotkeySwapCost; - type AlphaHigh = InitialAlphaHigh; - type AlphaLow = InitialAlphaLow; - type LiquidAlphaOn = InitialLiquidAlphaOn; } impl pallet_utility::Config for Test { diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 32a4f8b59..59b5d62b6 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -139,7 +139,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // `spec_version`, and `authoring_version` are the same between Wasm and native. // This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use // the compatible custom types. - spec_version: 153, + spec_version: 152, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, @@ -869,9 +869,6 @@ parameter_types! { pub const SubtensorInitialNetworkRateLimit: u64 = 7200; pub const SubtensorInitialTargetStakesPerInterval: u16 = 1; pub const SubtensorInitialHotkeySwapCost: u64 = 1_000_000_000; - pub const InitialAlphaHigh: u16 = 58982; // Represents 0.9 as per the production default - pub const InitialAlphaLow: u16 = 45875; // Represents 0.7 as per the production default - pub const InitialLiquidAlphaOn: bool = false; // Default value for LiquidAlphaOn } impl pallet_subtensor::Config for Runtime { @@ -924,9 +921,6 @@ impl pallet_subtensor::Config for Runtime { type InitialNetworkRateLimit = SubtensorInitialNetworkRateLimit; type InitialTargetStakesPerInterval = SubtensorInitialTargetStakesPerInterval; type HotkeySwapCost = SubtensorInitialHotkeySwapCost; - type AlphaHigh = InitialAlphaHigh; - type AlphaLow = InitialAlphaLow; - type LiquidAlphaOn = InitialLiquidAlphaOn; } use sp_runtime::BoundedVec; @@ -1201,19 +1195,6 @@ impl fn set_commit_reveal_weights_enabled(netuid: u16, enabled: bool) { SubtensorModule::set_commit_reveal_weights_enabled(netuid, enabled); } - - fn set_liquid_alpha_enabled(netuid: u16, enabled: bool) { - SubtensorModule::set_liquid_alpha_enabled(netuid, enabled); - } - - fn do_set_alpha_values( - origin: RuntimeOrigin, - netuid: u16, - alpha_low: u16, - alpha_high: u16, - ) -> Result<(), DispatchError> { - SubtensorModule::do_set_alpha_values(origin, netuid, alpha_low, alpha_high) - } } impl pallet_admin_utils::Config for Runtime { diff --git a/scripts/test_specific.sh b/scripts/test_specific.sh index 4e413c6d1..ab06060aa 100755 --- a/scripts/test_specific.sh +++ b/scripts/test_specific.sh @@ -1,4 +1,4 @@ pallet="${3:-pallet-subtensor}" features="${4:-pow-faucet}" -RUST_LOG="pallet_subtensor=trace,info" cargo test --release --features=$features -p $pallet --test $1 -- $2 --nocapture --exact \ No newline at end of file +RUST_LOG=info cargo test --release --features=$features -p $pallet --test $1 -- $2 --nocapture --exact \ No newline at end of file diff --git a/zepter.yaml b/zepter.yaml index 2841580e5..db1f33097 100644 --- a/zepter.yaml +++ b/zepter.yaml @@ -18,7 +18,8 @@ workflows: # Ignore the case that `A` it outside of the workspace. Otherwise it will report errors in external dependencies that we have no influence on. "--left-side-outside-workspace=ignore", # Some features imply that they activate a specific dependency as non-optional. Otherwise the default behaviour with a `?` is used. - "--feature-enables-dep=try-runtime:frame-try-runtime,runtime-benchmarks:frame-benchmarking", # Auxillary flags: + "--feature-enables-dep=try-runtime:frame-try-runtime,runtime-benchmarks:frame-benchmarking", + # Auxillary flags: "--offline", "--locked", "--show-path",