#vec #signed #performance

signvec

动态集合快速基于符号操作的向量实现

4 个版本 (2 个重大更改)

0.3.0 2024年3月23日
0.2.0 2024年3月22日
0.1.1 2024年3月22日
0.1.0 2024年3月14日

#425数据结构

Download history 110/week @ 2024-03-14 282/week @ 2024-03-21 19/week @ 2024-03-28 3/week @ 2024-04-04 1/week @ 2024-05-30

每月116次下载

MIT 协议

125KB
2K SLoC

SignVec

Crates.io docs.rs License GitHub Workflow Status

SignVec 通过提供基于 Signable 特性的功能,扩展了传统 Vec 的功能,以便高效地跟踪和操作基于元素符号(正或负)的操作。

特性

  • 跟踪元素的符号以优化符号特定操作。
  • 提供基于符号的元素计数、访问和操作方法。
  • 通过 Signable 特性与用户定义的类型集成。

使用:基本操作

use nanorand::{Rng, WyRand};
use signvec::{svec, Sign, SignVec};

fn main() {
    let mut vector = svec![1, -2, 3, -4];
    assert_eq!(vector.len(), 4);
    assert_eq!(vector[0], 1);
    assert_eq!(vector[1], -2);

    // Count positive and negative elements
    assert_eq!(vector.count(Sign::Plus), 2);
    assert_eq!(vector.count(Sign::Minus), 2);

    // Get indices of positive and negative elements
    assert_eq!(
        vector.indices(Sign::Plus).iter().collect::<Vec<_>>(),
        vec![&0, &2]
    );
    assert_eq!(
        vector.indices(Sign::Minus).iter().collect::<Vec<_>>(),
        vec![&1, &3]
    );

    // Retrieve values based on their sign
    assert_eq!(vector.values(Sign::Plus).collect::<Vec<_>>(), vec![&1, &3]);
    assert_eq!(
        vector.values(Sign::Minus).collect::<Vec<_>>(),
        vec![&-2, &-4]
    );

    // Modify individual elements
    vector.set(1, 5);
    assert_eq!(vector[1], 5);

    // Randomly select an element based on its sign
    let mut rng = WyRand::new();
    if let Some(random_positive) = vector.random(Sign::Plus, &mut rng) {
        println!("Random positive value: {}", random_positive);
    }
}

使用:蒙特卡洛模拟

这演示了一个简单的蒙特卡洛模拟,其中 SignVec 中的站点能量根据模拟动力学和系统能量分布进行更新。

use signvec::{SignVec, svec, Sign, Signable};
use nanorand::{WyRand, Rng};

fn main() {
    let mut energies = svec![1.0, -1.0, 1.5, -1.5, 0.5, -0.5];
    let mut rng = WyRand::new();

    // Simulation loop for multiple Monte Carlo steps
    for _step in 0..100 {
        let site = rng.generate_range(0..energies.len());
        let dE = rng.generate::<f64>() - 0.5; // Change in energy

        let new_energy = energies[site] + dE; // Update site energy
        
        // Make decisions based on system's energy distribution
        if energies.count(Sign::Minus) > energies.count(Sign::Plus) {
            if energies[site].sign() == Sign::Minus && rng.generate::<f64>() < 0.5 {
                energies.set(site, -new_energy); // Flip energy sign
            } else {
                energies.set(site, new_energy);
            }
        } else {
            energies.set(site, new_energy); // Balanced distribution
        }
    }

    println!("Final energy distribution: {:?}", energies);
}

使用:投资组合管理

演示了如何使用 SignVec 进行金融投资组合管理,模拟市场条件,并根据资产和负债的符号特性做出决策。

use signvec::{SignVec, Sign, svec};
use nanorand::WyRand;

fn main() {
    let mut portfolio = svec![150.0, -200.0, 300.0, -50.0, 400.0];
    let market_conditions = vec![1.05, 0.95, 1.10, 1.00, 1.03];

    // Apply market conditions to adjust portfolio balances
    for (index, &factor) in market_conditions.iter().enumerate() {
        portfolio.set(index, portfolio[index] * factor);
    }

    // Decision making based on portfolio's sign-aware characteristics
    if portfolio.count(Sign::Minus) > 2 {
        println!("Consider rebalancing your portfolio to manage risk.");
    } else {
        println!("Your portfolio is well-balanced and diversified.");
    }

    // Calculate 10% of total liabilities for debt reduction
    let debt_reduction = portfolio.values(Sign::Minus).sum::<f64>() * 0.1;
    println!("Plan for a debt reduction of ${:.2} to strengthen your financial position.", debt_reduction.abs());

    // Identify a high-performing asset for potential investment
    let mut rng = WyRand::new();
    if let Some(lucky_asset) = portfolio.random(Sign::Plus, &mut rng) {
        println!("Consider investing more in an asset valued at ${:.2}.", lucky_asset);
    } else {
        println!("No standout assets for additional investment at the moment.");
    }
}

基准测试

下表是 SignVec 专用功能基准结果的摘要。

操作 SignVec Vec 加速
set 1.3922 ns - -
set_unchecked 1.3873 ns - -
random (Plus) 822.90 ps - -
random (Minus) 829.92 ps - -
random_pos 652.96 ps - -
random_neg 687.77 ps - -
count (Plus) 453.21 ps - -
count (Minus) 458.70 ps - -
count_pos 229.73 ps - -
count_neg 228.44 ps - -
indices (Plus) 465.04 ps - -
indices (Minus) 461.85 ps - -
indices_pos 226.99 ps - -
indices_neg 225.83 ps - -
sync 61.208 µs - -
count[^1] 225.74 ps 153.38 ns ~679x 更快
indices[^2] 86.42 ns 1.11 µs ~12.8x 更快
values[^3] 579.37 ns 1.13 µs ~1.95x 更快
random[^4] 857.86 ps 950.84 ns ~1106x 更快

[^1]:此处使用 count_poscount_neg 基准测试进行比较,因为它们代表了按符号计数元素的优化路径。[^2]:将 indices_posindices_neg 基准测试呈现为按符号检索索引的优化方法。[^3]:values 操作在提供的基准测试中没有直接的对应项,但包含在上下文中。[^4]:random_posrandom_neg 基准测试提供了在符号预定的条件下 random 操作性能的上下文。

基准测试是在以下规格的机器上进行的

  • 处理器:AMD Ryzen™ 5 5600G 配备 Radeon™ 图形 x 12
  • 内存:58.8 GiB
  • 操作系统:Guix 系统
  • 操作系统类型:64位

依赖项

~0.6–1.2MB
~26K SLoC