# SignVec ![Crates.io](https://img.shields.io/crates/v/signvec) ![docs.rs](https://img.shields.io/docsrs/signvec) ![License](https://img.shields.io/crates/l/signvec) ![GitHub Workflow Status](https://github.com/b-vitamins/signvec/actions/workflows/rust.yml/badge.svg) `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 ```rust 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![&0, &2] ); assert_eq!( vector.indices(Sign::Minus).iter().collect::>(), vec![&1, &3] ); // Retrieve values based on their sign assert_eq!(vector.values(Sign::Plus).collect::>(), vec![&1, &3]); assert_eq!( vector.values(Sign::Minus).collect::>(), 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. ```rust 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::() - 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::() < 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. ```rust 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::() * 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