Skip to content

Commit

Permalink
Use u32 instead of usize; return Vec instead of impl Iterator for low…
Browse files Browse the repository at this point in the history
…er MSRV
  • Loading branch information
sd2k committed Feb 14, 2024
1 parent b35fe58 commit 3279e9d
Show file tree
Hide file tree
Showing 7 changed files with 27 additions and 33 deletions.
4 changes: 2 additions & 2 deletions crates/augurs-js/src/seasons.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ use augurs_seasons::{Detector, PeriodogramDetector};

/// Detect the seasonal periods in a time series.
#[wasm_bindgen]
pub fn seasonalities(y: &[f64]) -> Vec<usize> {
PeriodogramDetector::builder().build(y).detect().collect()
pub fn seasonalities(y: &[f64]) -> Vec<u32> {
PeriodogramDetector::builder().build(y).detect()
}
2 changes: 1 addition & 1 deletion crates/augurs-seasons/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ let y = &[
0.09, 0.29, 0.81, 0.49,
0.11, 0.28, 0.78, 0.53,
];
let periods: Vec<_> = PeriodogramDetector::builder().build(y).detect().collect();
let periods = PeriodogramDetector::builder().build(y).detect();
assert_eq!(periods[0], 4);
# }
```
Expand Down
7 changes: 1 addition & 6 deletions crates/augurs-seasons/benches/periodogram.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,7 @@ use augurs_testing::data::SEASON_EIGHT;
fn season_eight(c: &mut Criterion) {
let y = SEASON_EIGHT;
c.bench_function("season_eight", |b| {
b.iter(|| {
PeriodogramDetector::builder()
.build(y)
.detect()
.collect::<Vec<_>>()
});
b.iter(|| PeriodogramDetector::builder().build(y).detect());
});
}

Expand Down
2 changes: 1 addition & 1 deletion crates/augurs-seasons/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@ pub use periodogram::{
/// A detector of periodic signals in a time series.
pub trait Detector {
/// Detects the periods of the time series.
fn detect(&self) -> impl Iterator<Item = usize>;
fn detect(&self) -> Vec<u32>;
}
37 changes: 20 additions & 17 deletions crates/augurs-seasons/src/periodogram.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ const DEFAULT_MAX_FFT_PERIOD: f64 = 512.0;
/// A builder for a periodogram detector.
#[derive(Debug, Clone)]
pub struct Builder {
min_period: usize,
max_period: Option<usize>,
min_period: u32,
max_period: Option<u32>,
threshold: f64,
}

Expand All @@ -32,7 +32,7 @@ impl Builder {
///
/// The default is 4.
#[must_use]
pub fn min_period(mut self, min_period: usize) -> Self {
pub fn min_period(mut self, min_period: u32) -> Self {
self.min_period = min_period;
self
}
Expand All @@ -41,7 +41,7 @@ impl Builder {
///
/// The default is the length of the data divided by 3, or 512, whichever is smaller.
#[must_use]
pub fn max_period(mut self, max_period: usize) -> Self {
pub fn max_period(mut self, max_period: u32) -> Self {
self.max_period = Some(max_period);
self
}
Expand Down Expand Up @@ -71,15 +71,15 @@ impl Builder {
}
}

fn default_max_period(data: &[f64]) -> usize {
(data.len() as f64 / DEFAULT_MIN_FFT_CYCLES).min(DEFAULT_MAX_FFT_PERIOD) as usize
fn default_max_period(data: &[f64]) -> u32 {
(data.len() as f64 / DEFAULT_MIN_FFT_CYCLES).min(DEFAULT_MAX_FFT_PERIOD) as u32
}

/// A periodogram of a time series.
#[derive(Debug, Clone, PartialEq)]
pub struct Periodogram {
/// The periods of the periodogram.
pub periods: Vec<usize>,
pub periods: Vec<u32>,
/// The powers of the periodogram.
pub powers: Vec<f64>,
}
Expand Down Expand Up @@ -125,11 +125,11 @@ pub struct Period {
/// The power of the peak.
pub power: f64,
/// The period of the peak.
pub period: usize,
pub period: u32,
/// The previous period in the periodogram.
pub prev_period: usize,
pub prev_period: u32,
/// The next period in the periodogram.
pub next_period: usize,
pub next_period: u32,
}

/// A season detector which uses a periodogram to identify seasonal periods.
Expand All @@ -140,8 +140,8 @@ pub struct Period {
#[derive(Debug)]
pub struct Detector<'a> {
data: &'a [f64],
min_period: usize,
max_period: usize,
min_period: u32,
max_period: u32,
threshold: f64,
}

Expand All @@ -163,7 +163,7 @@ impl<'a> Detector<'a> {
pub fn periodogram(&self) -> Periodogram {
let frequency = 1.0;
let data_len = self.data.len();
let n_per_segment = (self.max_period * 2).min(data_len / 2);
let n_per_segment = (self.max_period * 2).min(data_len as u32 / 2);
let max_fft_size = (n_per_segment as f64).log2().floor() as usize;
let n_segments = (data_len as f64 / n_per_segment as f64).ceil() as usize;

Expand All @@ -177,7 +177,7 @@ impl<'a> Detector<'a> {
// Periods are the reciprocal of the frequency, since we've used a frequency of 1.
// Make sure we skip the first one, which is 0, and the first power, which corresponds to
// that.
let periods = freqs.iter().skip(1).map(|x| x.recip().round() as usize);
let periods = freqs.iter().skip(1).map(|x| x.recip().round() as u32);
let power = sd.iter().skip(1).copied();

let (periods, powers) = periods
Expand All @@ -202,8 +202,11 @@ impl<'a> Detector<'a> {
}

impl<'a> crate::Detector for Detector<'a> {
fn detect(&self) -> impl Iterator<Item = usize> {
self.periodogram().peaks(self.threshold).map(|x| x.period)
fn detect(&self) -> Vec<u32> {
self.periodogram()
.peaks(self.threshold)
.map(|x| x.period)
.collect()
}
}

Expand All @@ -225,7 +228,7 @@ mod test {
0.09, 0.29, 0.81, 0.49,
0.11, 0.28, 0.78, 0.53,
];
let periods = Detector::builder().build(y).detect().collect::<Vec<_>>();
let periods = Detector::builder().build(y).detect();
assert_eq!(periods[0], 4);
}

Expand Down
2 changes: 1 addition & 1 deletion crates/augurs-seasons/src/test_data.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use augurs_testing::data::{SEASON_EIGHT, SEASON_SEVEN};

pub(crate) struct TestCase {
pub(crate) season_lengths: &'static [usize],
pub(crate) season_lengths: &'static [u32],
pub(crate) data: &'static [f64],
}

Expand Down
6 changes: 1 addition & 5 deletions crates/pyaugurs/src/seasons.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,10 @@ use augurs_seasons::{Detector, PeriodogramDetector};

/// Detect the seasonal periods in a time series.
#[pyfunction]
pub fn seasonalities(
py: Python<'_>,
y: PyReadonlyArray1<'_, f64>,
) -> PyResult<Py<PyArray1<usize>>> {
pub fn seasonalities(py: Python<'_>, y: PyReadonlyArray1<'_, f64>) -> PyResult<Py<PyArray1<u32>>> {
Ok(PeriodogramDetector::builder()
.build(y.as_slice()?)
.detect()
.collect::<Vec<_>>()
.to_pyarray(py)
.into())
}

0 comments on commit 3279e9d

Please sign in to comment.