4 releases (2 breaking)
0.3.0 | Mar 23, 2024 |
---|---|
0.2.0 | Mar 22, 2024 |
0.1.1 | Mar 22, 2024 |
0.1.0 | Mar 14, 2024 |
#778 in Data structures
125KB
2K
SLoC
SignVec
SignVec
extends the capabilities of the traditional Vec
by providing additional functionalities to efficiently track and manipulate elements based on their sign (positive or negative) using the Signable
trait.
Features
- Tracks the sign of elements for optimized sign-specific operations.
- Provides methods for element counting, access, and manipulation based on sign.
- Integrates with user-defined types via the
Signable
trait.
Usage: Basic operations
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);
}
}
Usage: Monte Carlo simulations
This demonstrates a simple Monte Carlo simulation where site energies in a SignVec
are updated based on simulated dynamics and system energy distribution.
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);
}
Usage: Portfolio management
Demonstrates how SignVec
can be used for managing a financial portfolio, simulating market conditions, and making decisions based on the sign-aware characteristics of assets and liabilities.
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.");
}
}
Benchmarks
The table below is a summary of benchmark results for the specialized functionality of SignVec
.
Operation | SignVec |
Vec |
Speedup |
---|---|---|---|
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 faster |
indices [^2] |
86.42 ns | 1.11 µs | ~12.8x faster |
values [^3] |
579.37 ns | 1.13 µs | ~1.95x faster |
random [^4] |
857.86 ps | 950.84 ns | ~1106x faster |
[^1]: The count_pos
and count_neg
benchmarks are used here for comparison as they represent the optimized paths for counting elements by sign.
[^2]: The indices_pos
and indices_neg
benchmarks are presented as the optimized methods for retrieving indices by sign.
[^3]: The values
operation does not have a direct counterpart in the provided benchmarks but is included for context.
[^4]: The random_pos
and random_neg
benchmarks provide context for the random
operation's performance when the sign is predetermined.
Benchmarks were conducted on a machine with the following specifications:
- Processor: AMD Ryzen™ 5 5600G with Radeon™ Graphics x 12
- Memory: 58.8 GiB
- Operating System: Guix System
- OS Type: 64-bit
Dependencies
~0.5–1MB
~23K SLoC