2 Commits
Author SHA1 Message Date
swaits 794d6dffb1 bump crate to 0.6.1 2023-02-10 23:02:46 -05:00
swaits c3d210cf16 refactor: switch to array-init
- Use array-init for the lowest level vector operations. Makes them nicer and less bug-prone, with zero performance impact.
- Remove unnecessary/unused ::new() functions on Vector and HeightVector.
- Update README with new dependency.
- Fix typo in README.

Signed-off-by: Stephen Waits <steve@waits.net>
2023-02-10 22:51:38 -05:00
4 changed files with 21 additions and 33 deletions

No files matched your search

+2 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "vivaldi-nc" name = "vivaldi-nc"
version = "0.6.0" version = "0.6.1"
edition = "2021" edition = "2021"
authors = ["Stephen Waits <steve@waits.net>"] authors = ["Stephen Waits <steve@waits.net>"]
description = "Vivaldi network coordinates for fast, distributed latency estimates in multinode networks, with a clean and simple interface." description = "Vivaldi network coordinates for fast, distributed latency estimates in multinode networks, with a clean and simple interface."
@@ -36,6 +36,7 @@ name = "million-updates"
harness = false harness = false
[dependencies] [dependencies]
array-init = "2.1.0"
num-traits = "0.2.15" num-traits = "0.2.15"
rand = "0.8.5" rand = "0.8.5"
serde = {version = "1.0.152", features = ["serde_derive"]} serde = {version = "1.0.152", features = ["serde_derive"]}
+7 -3
View File
@@ -123,9 +123,9 @@ vivaldi-nc = { version = "(version)", features = ["f32"] }
### Examples ### Examples
The repository includes an example which loads a n-to-n latency sample from The repository includes an example which loads a 490 node N-to-N latency sample
PlanetLab and iterates on `NetworkCoordinate`s until some low-enough mean error from PlanetLab and iterates on `NetworkCoordinate`s until some low-enough mean
is reached. The output is a JSON array of elements which contain the NC's error is reached. The output is a JSON array of elements which contain the NC's
position, its height (or stem latency estimate), and its estimation of error position, its height (or stem latency estimate), and its estimation of error
(lower is better) that look like this: (lower is better) that look like this:
@@ -188,6 +188,10 @@ This crate depends on:
- [`serde_with`](https://crates.io/crates/serde_with): Because the inner - [`serde_with`](https://crates.io/crates/serde_with): Because the inner
`Vector<T,N>` uses a const generic length, we use this to help derive `Vector<T,N>` uses a const generic length, we use this to help derive
`Deserialize`. `Deserialize`.
- [`array-init`](https://crates.io/crates/array-init): Makes the array
operations for the internal `Vector` so much nicer. Once we have
`feature(array_zip)` stabilized, we could use that instead. Until then, this
works well with zero performance impact.
## Design Goals & Alternatives ## Design Goals & Alternatives
+2 -7
View File
@@ -92,11 +92,6 @@ pub struct HeightVector<const N: usize> {
// //
impl<const N: usize> HeightVector<N> { impl<const N: usize> HeightVector<N> {
/// A new height vector is a random unit vector
pub(crate) fn new() -> Self {
Self::random()
}
/// A new height vector is a random unit vector /// A new height vector is a random unit vector
pub(crate) fn random() -> Self { pub(crate) fn random() -> Self {
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();
@@ -131,7 +126,7 @@ impl<const N: usize> HeightVector<N> {
ret ret
} else { } else {
// if we have a bad vector, generate a new random vector // if we have a bad vector, generate a new random vector
Self::new() Self::random()
} }
} }
@@ -318,7 +313,7 @@ mod tests {
#[test] #[test]
fn test_new() { fn test_new() {
// new gives us a random unit length vec // new gives us a random unit length vec
let a = HeightVector::<3>::new(); let a = HeightVector::<3>::random();
assert_approx_eq!(a.len(), 1.0); assert_approx_eq!(a.len(), 1.0);
} }
+10 -22
View File
@@ -3,6 +3,7 @@
//! This is the simplest possible implementation of a vector to support the needs of a //! This is the simplest possible implementation of a vector to support the needs of a
//! Vivaldi `HeightVector`. //! Vivaldi `HeightVector`.
use array_init::array_init;
use num_traits::Float; use num_traits::Float;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_with::serde_as; use serde_with::serde_as;
@@ -37,11 +38,6 @@ impl<T, const N: usize> Vector<T, N>
where where
T: Float + Serialize + for<'d> Deserialize<'d>, T: Float + Serialize + for<'d> Deserialize<'d>,
{ {
/// Create a new Zero vector.
pub(crate) fn new() -> Self {
Self::default()
}
/// Compute magnitude of vector. /// Compute magnitude of vector.
pub(crate) fn len(&self) -> T { pub(crate) fn len(&self) -> T {
// use hypot() instead of sqrt() of sum of squares to avoid overflows // use hypot() instead of sqrt() of sum of squares to avoid overflows
@@ -90,11 +86,9 @@ where
/// Vector+Vector addition. /// Vector+Vector addition.
fn add(self, rhs: Self) -> Self::Output { fn add(self, rhs: Self) -> Self::Output {
let mut ret = [T::zero(); N]; //Self::Output::new(); Self::Output {
for i in 0..N { inner: array_init(|i| self[i] + rhs[i]),
ret[i] = self[i] + rhs[i];
} }
Self::Output::from(ret)
} }
} }
@@ -106,11 +100,9 @@ where
/// Vector-Vector subtraction. /// Vector-Vector subtraction.
fn sub(self, rhs: Self) -> Self::Output { fn sub(self, rhs: Self) -> Self::Output {
let mut ret = [T::zero(); N]; //Self::Output::new(); Self::Output {
for i in 0..N { inner: array_init(|i| self[i] - rhs[i]),
ret[i] = self[i] - rhs[i];
} }
Self::Output::from(ret)
} }
} }
@@ -122,11 +114,9 @@ where
/// Vector*scalar multiplication. /// Vector*scalar multiplication.
fn mul(self, rhs: T) -> Self::Output { fn mul(self, rhs: T) -> Self::Output {
let mut ret = Self::Output::new(); Self::Output {
for i in 0..N { inner: array_init(|i| self[i] * rhs),
ret.inner[i] = self.inner[i] * rhs;
} }
ret
} }
} }
@@ -138,11 +128,9 @@ where
/// Vector/scalar division. /// Vector/scalar division.
fn div(self, rhs: T) -> Self::Output { fn div(self, rhs: T) -> Self::Output {
let mut ret = Self::Output::new(); Self::Output {
for i in 0..N { inner: array_init(|i| self[i] / rhs),
ret.inner[i] = self.inner[i] / rhs;
} }
ret
} }
} }
@@ -235,7 +223,7 @@ mod tests {
#[test] #[test]
fn test_default_new() { fn test_default_new() {
let a = Vector::<f32, 3>::default(); let a = Vector::<f32, 3>::default();
let b = Vector::<f32, 3>::new(); let b = Vector::<f32, 3>::from([1.0; 3]) * 0.0;
let c = Vector::<f32, 3>::from([0.0; 3]); let c = Vector::<f32, 3>::from([0.0; 3]);
assert_eq!(a, b); assert_eq!(a, b);
assert_eq!(b, c); assert_eq!(b, c);