From 56bcd972454c15c004c7d743c7dcd2cea8bb8d9d Mon Sep 17 00:00:00 2001 From: JP-Ellis Date: Sat, 13 Apr 2019 09:45:17 +1000 Subject: [PATCH 1/5] Add `logspace` constructor for Array1 Signed-off-by: JP-Ellis --- src/impl_constructors.rs | 34 +++++++++++-- src/iterators/mod.rs | 29 ++++++----- src/lib.rs | 8 +-- src/logspace.rs | 105 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 153 insertions(+), 23 deletions(-) create mode 100644 src/logspace.rs diff --git a/src/impl_constructors.rs b/src/impl_constructors.rs index 1c2b84439..f02ac647b 100644 --- a/src/impl_constructors.rs +++ b/src/impl_constructors.rs @@ -10,18 +10,18 @@ //! //! -use num_traits::{Zero, One, Float}; +use num_traits::{Float, One, Zero}; use std::isize; use std::mem; -use crate::imp_prelude::*; -use crate::StrideShape; use crate::dimension; -use crate::linspace; use crate::error::{self, ShapeError}; -use crate::indices; +use crate::imp_prelude::*; use crate::indexes; +use crate::indices; use crate::iterators::{to_vec, to_vec_mapped}; +use crate::StrideShape; +use crate::{linspace, logspace}; /// # Constructor Methods for Owned Arrays /// @@ -101,6 +101,30 @@ impl ArrayBase { Self::from_vec(to_vec(linspace::range(start, end, step))) } + + /// Create a one-dimensional array from the inclusive interval `[start, + /// end]` with `n` elements logarithmically spaced. `A` must be a floating + /// point type. + /// + /// **Panics** if `n` is greater than `isize::MAX`. + /// + /// ```rust + /// use ndarray::{Array, arr1}; + /// + /// let array = Array::logspace(1e0, 1e3, 4); + /// println!("{}", array); + /// assert!(array.all_close(&arr1(&[1e0, 1e1, 1e2, 1e3]), 1e-5)); + /// + /// let array = Array::logspace(-1e3, -1e0, 4); + /// println!("{}", array); + /// assert!(array.all_close(&arr1(&[-1e3, -1e2, -1e1, -1e0]), 1e-5)); + /// ``` + pub fn logspace(start: A, end: A, n: usize) -> Self + where + A: Float, + { + Self::from_vec(to_vec(logspace::logspace(start, end, n))) + } } /// ## Constructor methods for two-dimensional arrays. diff --git a/src/iterators/mod.rs b/src/iterators/mod.rs index b9aab1aa9..b822e416e 100644 --- a/src/iterators/mod.rs +++ b/src/iterators/mod.rs @@ -1214,25 +1214,24 @@ send_sync_read_write!(ElementsBaseMut); /// (Trait used internally) An iterator that we trust /// to deliver exactly as many items as it said it would. -pub unsafe trait TrustedIterator { } +pub unsafe trait TrustedIterator {} -use std; -use crate::linspace::Linspace; -use crate::iter::IndicesIter; use crate::indexes::IndicesIterF; +use crate::iter::IndicesIter; +use crate::{linspace::Linspace, logspace::Logspace}; +use std; -unsafe impl TrustedIterator for Linspace { } -unsafe impl<'a, A, D> TrustedIterator for Iter<'a, A, D> { } -unsafe impl<'a, A, D> TrustedIterator for IterMut<'a, A, D> { } -unsafe impl TrustedIterator for std::iter::Map - where I: TrustedIterator { } -unsafe impl<'a, A> TrustedIterator for slice::Iter<'a, A> { } -unsafe impl<'a, A> TrustedIterator for slice::IterMut<'a, A> { } -unsafe impl TrustedIterator for ::std::ops::Range { } +unsafe impl TrustedIterator for Linspace {} +unsafe impl TrustedIterator for Logspace {} +unsafe impl<'a, A, D> TrustedIterator for Iter<'a, A, D> {} +unsafe impl<'a, A, D> TrustedIterator for IterMut<'a, A, D> {} +unsafe impl TrustedIterator for std::iter::Map where I: TrustedIterator {} +unsafe impl<'a, A> TrustedIterator for slice::Iter<'a, A> {} +unsafe impl<'a, A> TrustedIterator for slice::IterMut<'a, A> {} +unsafe impl TrustedIterator for ::std::ops::Range {} // FIXME: These indices iter are dubious -- size needs to be checked up front. -unsafe impl TrustedIterator for IndicesIter where D: Dimension { } -unsafe impl TrustedIterator for IndicesIterF where D: Dimension { } - +unsafe impl TrustedIterator for IndicesIter where D: Dimension {} +unsafe impl TrustedIterator for IndicesIterF where D: Dimension {} /// Like Iterator::collect, but only for trusted length iterators pub fn to_vec(iter: I) -> Vec diff --git a/src/lib.rs b/src/lib.rs index 8b44c21d2..84ecd447d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -167,14 +167,16 @@ mod free_functions; pub use crate::free_functions::*; pub use crate::iterators::iter; -#[macro_use] mod slice; -mod layout; +#[macro_use] +mod slice; +mod error; mod indexes; mod iterators; +mod layout; mod linalg_traits; mod linspace; +mod logspace; mod numeric_util; -mod error; mod shape_builder; mod stacking; #[macro_use] diff --git a/src/logspace.rs b/src/logspace.rs new file mode 100644 index 000000000..b81b4632b --- /dev/null +++ b/src/logspace.rs @@ -0,0 +1,105 @@ +// Copyright 2014-2016 bluss and ndarray developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +use num_traits::Float; + +/// An iterator of a sequence of logarithmically evenly spaced floats. +/// +/// Iterator element type is `F`. +pub struct Logspace { + current: F, + last: F, + step: F, + index: usize, + len: usize, +} + +impl Iterator for Logspace +where + F: Float, +{ + type Item = F; + + #[inline] + fn next(&mut self) -> Option { + if self.index >= self.len { + None + } else { + self.index += 1; + + let v = self.current; + self.current = self.current * self.step; + Some(v) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let n = self.len - self.index; + (n, Some(n)) + } +} + +impl DoubleEndedIterator for Logspace +where + F: Float, +{ + #[inline] + fn next_back(&mut self) -> Option { + if self.index >= self.len { + None + } else { + self.len -= 1; + + let v = self.last; + self.last = self.last / self.step; + Some(v) + } + } +} + +impl ExactSizeIterator for Logspace where Logspace: Iterator {} + +/// Return an iterator of logarithmically evenly spaced floats. +/// +/// The `Logspace` has `n` elements, where the first element is `a` and the last +/// element is `b`. +/// +/// The sign of `a` and `b` must be the same so that the interval does not +/// include 0. +/// +/// Iterator element type is `F`, where `F` must be either `f32` or `f64`. +#[inline] +pub fn logspace(a: F, b: F, n: usize) -> Logspace +where + F: Float, +{ + assert!( + a != F::zero() && b != F::zero(), + "Start and/or end of logspace cannot be zero.", + ); + assert!( + a.is_sign_negative() == b.is_sign_negative(), + "Logarithmic interval cannot cross 0." + ); + + let log_a = a.abs().ln(); + let log_b = b.abs().ln(); + let step = if n > 1 { + let nf = F::from(n).unwrap(); + ((log_b - log_a) / (nf - F::one())).exp() + } else { + F::one() + }; + Logspace { + current: a, + last: b, + step: step, + index: 0, + len: n, + } +} From c59676a5dff67b617fe1a454f0355f11745765c6 Mon Sep 17 00:00:00 2001 From: JP-Ellis Date: Wed, 17 Apr 2019 12:20:30 +1000 Subject: [PATCH 2/5] Add logspace tests Signed-off-by: JP-Ellis --- src/logspace.rs | 63 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/src/logspace.rs b/src/logspace.rs index b81b4632b..97e0f96c1 100644 --- a/src/logspace.rs +++ b/src/logspace.rs @@ -103,3 +103,66 @@ where len: n, } } + +#[cfg(test)] +mod tests { + use super::logspace; + use crate::{arr1, Array1}; + + #[test] + fn valid() { + let array: Array1<_> = logspace(1e0, 1e3, 4).collect(); + assert!(array.all_close(&arr1(&[1e0, 1e1, 1e2, 1e3]), 1e-5)); + + let array: Array1<_> = logspace(-1e3, -1e0, 4).collect(); + assert!(array.all_close(&arr1(&[-1e3, -1e2, -1e1, -1e0]), 1e-5)); + } + + #[test] + fn iter_forward() { + let mut iter = logspace(1.0f64, 1e3, 4); + + assert!(iter.size_hint() == (4, Some(4))); + + assert!((iter.next().unwrap() - 1e0).abs() < 1e-5); + assert!((iter.next().unwrap() - 1e1).abs() < 1e-5); + assert!((iter.next().unwrap() - 1e2).abs() < 1e-5); + assert!((iter.next().unwrap() - 1e3).abs() < 1e-5); + assert!(iter.next().is_none()); + + assert!(iter.size_hint() == (0, Some(0))); + } + + #[test] + fn iter_backward() { + let mut iter = logspace(1.0f64, 1e3, 4); + + assert!(iter.size_hint() == (4, Some(4))); + + assert!((iter.next_back().unwrap() - 1e3).abs() < 1e-5); + assert!((iter.next_back().unwrap() - 1e2).abs() < 1e-5); + assert!((iter.next_back().unwrap() - 1e1).abs() < 1e-5); + assert!((iter.next_back().unwrap() - 1e0).abs() < 1e-5); + assert!(iter.next_back().is_none()); + + assert!(iter.size_hint() == (0, Some(0))); + } + + #[test] + #[should_panic] + fn zero_lower() { + logspace(0.0, 1.0, 4); + } + + #[test] + #[should_panic] + fn zero_upper() { + logspace(1.0, 0.0, 4); + } + + #[test] + #[should_panic] + fn zero_included() { + logspace(-1.0, 1.0, 4); + } +} From c7131c32b4161fb35a79531f92247212670c8d8e Mon Sep 17 00:00:00 2001 From: JP-Ellis Date: Fri, 19 Apr 2019 10:00:55 +1000 Subject: [PATCH 3/5] More extensive logspace tests Signed-off-by: JP-Ellis --- src/logspace.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/logspace.rs b/src/logspace.rs index 97e0f96c1..39e16fc3b 100644 --- a/src/logspace.rs +++ b/src/logspace.rs @@ -114,8 +114,14 @@ mod tests { let array: Array1<_> = logspace(1e0, 1e3, 4).collect(); assert!(array.all_close(&arr1(&[1e0, 1e1, 1e2, 1e3]), 1e-5)); + let array: Array1<_> = logspace(1e3, 1e0, 4).collect(); + assert!(array.all_close(&arr1(&[1e3, 1e2, 1e1, 1e0]), 1e-5)); + let array: Array1<_> = logspace(-1e3, -1e0, 4).collect(); assert!(array.all_close(&arr1(&[-1e3, -1e2, -1e1, -1e0]), 1e-5)); + + let array: Array1<_> = logspace(-1e0, -1e3, 4).collect(); + assert!(array.all_close(&arr1(&[-1e0, -1e1, -1e2, -1e3]), 1e-5)); } #[test] From 1999880059cf0c897e42096a955b2618ee3e467c Mon Sep 17 00:00:00 2001 From: JP-Ellis Date: Fri, 19 Apr 2019 10:01:44 +1000 Subject: [PATCH 4/5] Remove print statements in doc tests Signed-off-by: JP-Ellis --- src/impl_constructors.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/impl_constructors.rs b/src/impl_constructors.rs index f02ac647b..26ccab830 100644 --- a/src/impl_constructors.rs +++ b/src/impl_constructors.rs @@ -112,11 +112,9 @@ impl ArrayBase /// use ndarray::{Array, arr1}; /// /// let array = Array::logspace(1e0, 1e3, 4); - /// println!("{}", array); /// assert!(array.all_close(&arr1(&[1e0, 1e1, 1e2, 1e3]), 1e-5)); /// /// let array = Array::logspace(-1e3, -1e0, 4); - /// println!("{}", array); /// assert!(array.all_close(&arr1(&[-1e3, -1e2, -1e1, -1e0]), 1e-5)); /// ``` pub fn logspace(start: A, end: A, n: usize) -> Self From 04f2110e7cb529f36f5a04b43e7320d5fbdfb61b Mon Sep 17 00:00:00 2001 From: JP-Ellis Date: Wed, 1 May 2019 19:14:46 +1000 Subject: [PATCH 5/5] Add `geomspace` and make `logspace` compatible with NumPy Signed-off-by: JP-Ellis --- src/geomspace.rs | 173 +++++++++++++++++++++++++++++++++++++++ src/impl_constructors.rs | 39 +++++++-- src/iterators/mod.rs | 3 +- src/lib.rs | 5 +- src/logspace.rs | 87 +++++++------------- 5 files changed, 240 insertions(+), 67 deletions(-) create mode 100644 src/geomspace.rs diff --git a/src/geomspace.rs b/src/geomspace.rs new file mode 100644 index 000000000..f04d44889 --- /dev/null +++ b/src/geomspace.rs @@ -0,0 +1,173 @@ +// Copyright 2014-2016 bluss and ndarray developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +use num_traits::Float; + +/// An iterator of a sequence of geometrically spaced floats. +/// +/// Iterator element type is `F`. +pub struct Geomspace { + sign: F, + start: F, + step: F, + index: usize, + len: usize, +} + +impl Iterator for Geomspace +where + F: Float, +{ + type Item = F; + + #[inline] + fn next(&mut self) -> Option { + if self.index >= self.len { + None + } else { + // Calculate the value just like numpy.linspace does + let i = self.index; + self.index += 1; + let exponent = self.start + self.step * F::from(i).unwrap(); + Some(self.sign * exponent.exp()) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let n = self.len - self.index; + (n, Some(n)) + } +} + +impl DoubleEndedIterator for Geomspace +where + F: Float, +{ + #[inline] + fn next_back(&mut self) -> Option { + if self.index >= self.len { + None + } else { + // Calculate the value just like numpy.linspace does + self.len -= 1; + let i = self.len; + let exponent = self.start + self.step * F::from(i).unwrap(); + Some(self.sign * exponent.exp()) + } + } +} + +impl ExactSizeIterator for Geomspace where Geomspace: Iterator {} + +/// An iterator of a sequence of geometrically spaced values. +/// +/// The `Geomspace` has `n` elements, where the first element is `a` and the +/// last element is `b`. +/// +/// Iterator element type is `F`, where `F` must be either `f32` or `f64`. +/// +/// **Panics** if the interval `[a, b]` contains zero (including the end points). +#[inline] +pub fn geomspace(a: F, b: F, n: usize) -> Geomspace +where + F: Float, +{ + assert!( + a != F::zero() && b != F::zero(), + "Start and/or end of geomspace cannot be zero.", + ); + assert!( + a.is_sign_negative() == b.is_sign_negative(), + "Logarithmic interval cannot cross 0." + ); + + let log_a = a.abs().ln(); + let log_b = b.abs().ln(); + let step = if n > 1 { + let nf: F = F::from(n).unwrap(); + (log_b - log_a) / (nf - F::one()) + } else { + F::zero() + }; + Geomspace { + sign: a.signum(), + start: log_a, + step: step, + index: 0, + len: n, + } +} + +#[cfg(test)] +mod tests { + use super::geomspace; + use crate::{arr1, Array1}; + + #[test] + fn valid() { + let array: Array1<_> = geomspace(1e0, 1e3, 4).collect(); + assert!(array.all_close(&arr1(&[1e0, 1e1, 1e2, 1e3]), 1e-5)); + + let array: Array1<_> = geomspace(1e3, 1e0, 4).collect(); + assert!(array.all_close(&arr1(&[1e3, 1e2, 1e1, 1e0]), 1e-5)); + + let array: Array1<_> = geomspace(-1e3, -1e0, 4).collect(); + assert!(array.all_close(&arr1(&[-1e3, -1e2, -1e1, -1e0]), 1e-5)); + + let array: Array1<_> = geomspace(-1e0, -1e3, 4).collect(); + assert!(array.all_close(&arr1(&[-1e0, -1e1, -1e2, -1e3]), 1e-5)); + } + + #[test] + fn iter_forward() { + let mut iter = geomspace(1.0f64, 1e3, 4); + + assert!(iter.size_hint() == (4, Some(4))); + + assert!((iter.next().unwrap() - 1e0).abs() < 1e-5); + assert!((iter.next().unwrap() - 1e1).abs() < 1e-5); + assert!((iter.next().unwrap() - 1e2).abs() < 1e-5); + assert!((iter.next().unwrap() - 1e3).abs() < 1e-5); + assert!(iter.next().is_none()); + + assert!(iter.size_hint() == (0, Some(0))); + } + + #[test] + fn iter_backward() { + let mut iter = geomspace(1.0f64, 1e3, 4); + + assert!(iter.size_hint() == (4, Some(4))); + + assert!((iter.next_back().unwrap() - 1e3).abs() < 1e-5); + assert!((iter.next_back().unwrap() - 1e2).abs() < 1e-5); + assert!((iter.next_back().unwrap() - 1e1).abs() < 1e-5); + assert!((iter.next_back().unwrap() - 1e0).abs() < 1e-5); + assert!(iter.next_back().is_none()); + + assert!(iter.size_hint() == (0, Some(0))); + } + + #[test] + #[should_panic] + fn zero_lower() { + geomspace(0.0, 1.0, 4); + } + + #[test] + #[should_panic] + fn zero_upper() { + geomspace(1.0, 0.0, 4); + } + + #[test] + #[should_panic] + fn zero_included() { + geomspace(-1.0, 1.0, 4); + } +} diff --git a/src/impl_constructors.rs b/src/impl_constructors.rs index 26ccab830..a57dcfff8 100644 --- a/src/impl_constructors.rs +++ b/src/impl_constructors.rs @@ -21,7 +21,7 @@ use crate::indexes; use crate::indices; use crate::iterators::{to_vec, to_vec_mapped}; use crate::StrideShape; -use crate::{linspace, logspace}; +use crate::{linspace, geomspace, logspace}; /// # Constructor Methods for Owned Arrays /// @@ -102,26 +102,53 @@ impl ArrayBase Self::from_vec(to_vec(linspace::range(start, end, step))) } + /// Create a one-dimensional array with `n` elements logarithmically spaced, + /// with the starting value being `base.powf(start)` and the final one being + /// `base.powf(end)`. `A` must be a floating point type. + /// + /// If `base` is negative, all values will be negative. + /// + /// **Panics** if the length is greater than `isize::MAX`. + /// + /// ```rust + /// use ndarray::{Array, arr1}; + /// + /// let array = Array::logspace(10.0, 0.0, 3.0, 4); + /// assert!(array.all_close(&arr1(&[1e0, 1e1, 1e2, 1e3]), 1e-5)); + /// + /// let array = Array::logspace(-10.0, 3.0, 0.0, 4); + /// assert!(array.all_close(&arr1(&[-1e3, -1e2, -1e1, -1e0]), 1e-5)); + /// ``` + pub fn logspace(base: A, start: A, end: A, n: usize) -> Self + where + A: Float, + { + Self::from_vec(to_vec(logspace::logspace(base, start, end, n))) + } + /// Create a one-dimensional array from the inclusive interval `[start, - /// end]` with `n` elements logarithmically spaced. `A` must be a floating + /// end]` with `n` elements geometrically spaced. `A` must be a floating /// point type. /// + /// The interval can be either all positive or all negative; however, it + /// cannot contain 0 (including the end points). + /// /// **Panics** if `n` is greater than `isize::MAX`. /// /// ```rust /// use ndarray::{Array, arr1}; /// - /// let array = Array::logspace(1e0, 1e3, 4); + /// let array = Array::geomspace(1e0, 1e3, 4); /// assert!(array.all_close(&arr1(&[1e0, 1e1, 1e2, 1e3]), 1e-5)); /// - /// let array = Array::logspace(-1e3, -1e0, 4); + /// let array = Array::geomspace(-1e3, -1e0, 4); /// assert!(array.all_close(&arr1(&[-1e3, -1e2, -1e1, -1e0]), 1e-5)); /// ``` - pub fn logspace(start: A, end: A, n: usize) -> Self + pub fn geomspace(start: A, end: A, n: usize) -> Self where A: Float, { - Self::from_vec(to_vec(logspace::logspace(start, end, n))) + Self::from_vec(to_vec(geomspace::geomspace(start, end, n))) } } diff --git a/src/iterators/mod.rs b/src/iterators/mod.rs index b822e416e..17e137543 100644 --- a/src/iterators/mod.rs +++ b/src/iterators/mod.rs @@ -1218,9 +1218,10 @@ pub unsafe trait TrustedIterator {} use crate::indexes::IndicesIterF; use crate::iter::IndicesIter; -use crate::{linspace::Linspace, logspace::Logspace}; +use crate::{geomspace::Geomspace, linspace::Linspace, logspace::Logspace}; use std; +unsafe impl TrustedIterator for Geomspace {} unsafe impl TrustedIterator for Linspace {} unsafe impl TrustedIterator for Logspace {} unsafe impl<'a, A, D> TrustedIterator for Iter<'a, A, D> {} diff --git a/src/lib.rs b/src/lib.rs index 84ecd447d..5cb59ae5a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -167,9 +167,8 @@ mod free_functions; pub use crate::free_functions::*; pub use crate::iterators::iter; -#[macro_use] -mod slice; mod error; +mod geomspace; mod indexes; mod iterators; mod layout; @@ -178,6 +177,8 @@ mod linspace; mod logspace; mod numeric_util; mod shape_builder; +#[macro_use] +mod slice; mod stacking; #[macro_use] mod zip; diff --git a/src/logspace.rs b/src/logspace.rs index 39e16fc3b..fe62e9990 100644 --- a/src/logspace.rs +++ b/src/logspace.rs @@ -7,12 +7,13 @@ // except according to those terms. use num_traits::Float; -/// An iterator of a sequence of logarithmically evenly spaced floats. +/// An iterator of a sequence of logarithmically spaced number. /// /// Iterator element type is `F`. pub struct Logspace { - current: F, - last: F, + sign: F, + base: F, + start: F, step: F, index: usize, len: usize, @@ -29,11 +30,11 @@ where if self.index >= self.len { None } else { + // Calculate the value just like numpy.linspace does + let i = self.index; self.index += 1; - - let v = self.current; - self.current = self.current * self.step; - Some(v) + let exponent = self.start + self.step * F::from(i).unwrap(); + Some(self.sign * self.base.powf(exponent)) } } @@ -53,51 +54,39 @@ where if self.index >= self.len { None } else { + // Calculate the value just like numpy.linspace does self.len -= 1; - - let v = self.last; - self.last = self.last / self.step; - Some(v) + let i = self.len; + let exponent = self.start + self.step * F::from(i).unwrap(); + Some(self.sign * self.base.powf(exponent)) } } } impl ExactSizeIterator for Logspace where Logspace: Iterator {} -/// Return an iterator of logarithmically evenly spaced floats. -/// -/// The `Logspace` has `n` elements, where the first element is `a` and the last -/// element is `b`. +/// An iterator of a sequence of logarithmically spaced number. /// -/// The sign of `a` and `b` must be the same so that the interval does not -/// include 0. +/// The `Logspace` has `n` elements, where the first element is `base.powf(a)` +/// and the last element is `base.powf(b)`. If `base` is negative, this +/// iterator will return all negative values. /// /// Iterator element type is `F`, where `F` must be either `f32` or `f64`. #[inline] -pub fn logspace(a: F, b: F, n: usize) -> Logspace +pub fn logspace(base: F, a: F, b: F, n: usize) -> Logspace where F: Float, { - assert!( - a != F::zero() && b != F::zero(), - "Start and/or end of logspace cannot be zero.", - ); - assert!( - a.is_sign_negative() == b.is_sign_negative(), - "Logarithmic interval cannot cross 0." - ); - - let log_a = a.abs().ln(); - let log_b = b.abs().ln(); let step = if n > 1 { - let nf = F::from(n).unwrap(); - ((log_b - log_a) / (nf - F::one())).exp() + let nf: F = F::from(n).unwrap(); + (b - a) / (nf - F::one()) } else { - F::one() + F::zero() }; Logspace { - current: a, - last: b, + sign: base.signum(), + base: base.abs(), + start: a, step: step, index: 0, len: n, @@ -111,22 +100,22 @@ mod tests { #[test] fn valid() { - let array: Array1<_> = logspace(1e0, 1e3, 4).collect(); + let array: Array1<_> = logspace(10.0, 0.0, 3.0, 4).collect(); assert!(array.all_close(&arr1(&[1e0, 1e1, 1e2, 1e3]), 1e-5)); - let array: Array1<_> = logspace(1e3, 1e0, 4).collect(); + let array: Array1<_> = logspace(10.0, 3.0, 0.0, 4).collect(); assert!(array.all_close(&arr1(&[1e3, 1e2, 1e1, 1e0]), 1e-5)); - let array: Array1<_> = logspace(-1e3, -1e0, 4).collect(); + let array: Array1<_> = logspace(-10.0, 3.0, 0.0, 4).collect(); assert!(array.all_close(&arr1(&[-1e3, -1e2, -1e1, -1e0]), 1e-5)); - let array: Array1<_> = logspace(-1e0, -1e3, 4).collect(); + let array: Array1<_> = logspace(-10.0, 0.0, 3.0, 4).collect(); assert!(array.all_close(&arr1(&[-1e0, -1e1, -1e2, -1e3]), 1e-5)); } #[test] fn iter_forward() { - let mut iter = logspace(1.0f64, 1e3, 4); + let mut iter = logspace(10.0f64, 0.0, 3.0, 4); assert!(iter.size_hint() == (4, Some(4))); @@ -141,7 +130,7 @@ mod tests { #[test] fn iter_backward() { - let mut iter = logspace(1.0f64, 1e3, 4); + let mut iter = logspace(10.0f64, 0.0, 3.0, 4); assert!(iter.size_hint() == (4, Some(4))); @@ -153,22 +142,4 @@ mod tests { assert!(iter.size_hint() == (0, Some(0))); } - - #[test] - #[should_panic] - fn zero_lower() { - logspace(0.0, 1.0, 4); - } - - #[test] - #[should_panic] - fn zero_upper() { - logspace(1.0, 0.0, 4); - } - - #[test] - #[should_panic] - fn zero_included() { - logspace(-1.0, 1.0, 4); - } }