Skip to content

Commit b4cfff0

Browse files
authored
🔍 add searchsorted to get equidistant x-bins (#11)
* 🧹 rename np.bool8 -> np.bool_ * 🚧 add searchsorted functionality * 🥾 cleanup implementation * ♻️ change m4 implementation * 🧹 * ♻️ refactoring + updated MinMax algorithm * 🚧 * ♻️ use f64 for val_step calculation * 🐛 * 🔥 make it fast again * 🧹 * 🔥 update minmaxlttb algorithm * 🦀 update bindings * 😇 do not support f16 as x datatype * 🧹 use num_traits * 🧹 * 🎅 finish python bindings * 🎨 update readme * 🎅 add timedelta64 to readme * 🧹 consistent naming * 🎅 check n_out requirements * 🚧 * 🔥 fix out of bounds indexing issue * 🧹 use f64 to calculate equidistant step * 🔥 check against plotly-resampler downsamplers * 🧹 cleanup * 🙏 new release * 🙈 * 🧹 * 🧹
1 parent ec2f80a commit b4cfff0

30 files changed

+1306
-532
lines changed

.github/workflows/ci-downsample_rs.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ jobs:
4242
run: cargo check --verbose --all-features
4343
- name: formatting check
4444
run: cargo fmt --all -- --check
45-
# TODO: enable clippy once I write docs for all public items
4645
# - name: check with clippy
4746
# run: cargo clippy --all --all-targets --all-features -- -D warnings
4847

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@
2828
- no intermediate data structures are created
2929
* **Flexible**: works on any type of data
3030
- supported datatypes are
31-
- for `x`: `f16`, `f32`, `f64`, `i16`, `i32`, `i64`, `u16`, `u32`, `u64`, `datetime64`
32-
- for `y`: `f16`, `f32`, `f64`, `i8`, `i16`, `i32`, `i64`, `u8`, `u16`, `u32`, `u64`, `bool`
31+
- for `x`: `f32`, `f64`, `i16`, `i32`, `i64`, `u16`, `u32`, `u64`, `datetime64`, `timedelta64`
32+
- for `y`: `f16`, `f32`, `f64`, `i8`, `i16`, `i32`, `i64`, `u8`, `u16`, `u32`, `u64`, `datetime64`, `timedelta64`, `bool`
3333
<details>
3434
<summary><i>!! 🚀 <code>f16</code> <a href="https://github.com/jvdd/argminmax">argminmax</a> is 200-300x faster than numpy</i></summary>
3535
In contrast with all other data types above, <code>f16</code> is *not* hardware supported (i.e., no instructions for f16) by most modern CPUs!! <br>

downsample_rs/Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@ description = "Downsample time series data"
77
license = "MIT"
88

99
[dependencies]
10+
# TODO: perhaps use polars?
1011
ndarray = {version = "0.15.6", default-features = false, features = ["rayon"] }
1112
argminmax = { version = "0.3" , features = ["half"] }
12-
half = { version = "2.1", default-features = false , optional = true}
13+
half = { version = "2.1", default-features = false , features=["num-traits"], optional = true}
14+
num-traits = { version = "0.2.15", default-features = false }
15+
rayon = { version = "1.6.0", default-features = false }
1316

1417
[dev-dependencies]
1518
criterion = "0.3.0"

downsample_rs/benches/bench_lttb.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,30 +12,30 @@ fn lttb_f32_random_array_long(c: &mut Criterion) {
1212
let n = config::ARRAY_LENGTH_LONG;
1313
let x = Array1::from((0..n).map(|i| i as i32).collect::<Vec<i32>>());
1414
let y = utils::get_random_array::<f32>(n, f32::MIN, f32::MAX);
15-
c.bench_function("lttb_scal_f32", |b| {
16-
b.iter(|| lttb_mod::lttb(black_box(x.view()), black_box(y.view()), black_box(2_000)))
15+
c.bench_function("lttb_scalx_f32", |b| {
16+
b.iter(|| lttb_mod::lttb_with_x(black_box(x.view()), black_box(y.view()), black_box(2_000)))
1717
});
1818
}
1919
fn lttb_f32_random_array_50m(c: &mut Criterion) {
2020
let n = 50_000_000;
2121
let x = Array1::from((0..n).map(|i| i as i32).collect::<Vec<i32>>());
2222
let y = utils::get_random_array::<f32>(n, f32::MIN, f32::MAX);
23-
c.bench_function("lttb_scal_50M_f32", |b| {
24-
b.iter(|| lttb_mod::lttb(black_box(x.view()), black_box(y.view()), black_box(2_000)))
23+
c.bench_function("lttb_scalx_50M_f32", |b| {
24+
b.iter(|| lttb_mod::lttb_with_x(black_box(x.view()), black_box(y.view()), black_box(2_000)))
2525
});
2626
}
2727

2828
fn lttb_without_x_f32_random_array_long(c: &mut Criterion) {
2929
let n = config::ARRAY_LENGTH_LONG;
3030
let y = utils::get_random_array::<f32>(n, f32::MIN, f32::MAX);
31-
c.bench_function("lttbnox_scal_f32", |b| {
31+
c.bench_function("lttb_scal_f32", |b| {
3232
b.iter(|| lttb_mod::lttb_without_x(black_box(y.view()), black_box(2_000)))
3333
});
3434
}
3535
fn lttb_without_x_f32_random_array_50m(c: &mut Criterion) {
3636
let n = 50_000_000;
3737
let y = utils::get_random_array::<f32>(n, f32::MIN, f32::MAX);
38-
c.bench_function("lttbnox_scal_50M_f32", |b| {
38+
c.bench_function("lttb_scal_50M_f32", |b| {
3939
b.iter(|| lttb_mod::lttb_without_x(black_box(y.view()), black_box(2_000)))
4040
});
4141
}

downsample_rs/benches/bench_m4.rs

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,47 +7,87 @@ use downsample_rs::m4 as m4_mod;
77
use criterion::{black_box, Criterion};
88
use dev_utils::{config, utils};
99

10+
use ndarray::Array1;
11+
1012
fn m4_f32_random_array_long_single_core(c: &mut Criterion) {
1113
let n = config::ARRAY_LENGTH_LONG;
1214
let data = utils::get_random_array::<f32>(n, f32::MIN, f32::MAX);
1315
c.bench_function("m4_scal_f32", |b| {
14-
b.iter(|| m4_mod::m4_scalar(black_box(data.view()), black_box(2_000)))
16+
b.iter(|| m4_mod::m4_scalar_without_x(black_box(data.view()), black_box(2_000)))
1517
});
1618
c.bench_function("m4_simd_f32", |b| {
17-
b.iter(|| m4_mod::m4_simd(black_box(data.view()), black_box(2_000)))
19+
b.iter(|| m4_mod::m4_simd_without_x(black_box(data.view()), black_box(2_000)))
1820
});
1921
}
2022

2123
fn m4_f32_random_array_long_multi_core(c: &mut Criterion) {
2224
let n = config::ARRAY_LENGTH_LONG;
2325
let data = utils::get_random_array::<f32>(n, f32::MIN, f32::MAX);
2426
c.bench_function("m4_scal_p_f32", |b| {
25-
b.iter(|| m4_mod::m4_scalar_parallel(black_box(data.view()), black_box(2_000)))
27+
b.iter(|| m4_mod::m4_scalar_without_x_parallel(black_box(data.view()), black_box(2_000)))
2628
});
2729
c.bench_function("m4_simd_p_f32", |b| {
28-
b.iter(|| m4_mod::m4_simd_parallel(black_box(data.view()), black_box(2_000)))
30+
b.iter(|| m4_mod::m4_simd_without_x_parallel(black_box(data.view()), black_box(2_000)))
2931
});
3032
}
3133

3234
fn m4_f32_random_array_50M_single_core(c: &mut Criterion) {
3335
let n = 50_000_000;
3436
let data = utils::get_random_array::<f32>(n, f32::MIN, f32::MAX);
37+
let x = Array1::from((0..n).map(|i| i as i32).collect::<Vec<i32>>());
3538
c.bench_function("m4_scal_50M_f32", |b| {
36-
b.iter(|| m4_mod::m4_scalar(black_box(data.view()), black_box(2_000)))
39+
b.iter(|| m4_mod::m4_scalar_without_x(black_box(data.view()), black_box(2_000)))
3740
});
3841
c.bench_function("m4_simd_50M_f32", |b| {
39-
b.iter(|| m4_mod::m4_simd(black_box(data.view()), black_box(2_000)))
42+
b.iter(|| m4_mod::m4_simd_without_x(black_box(data.view()), black_box(2_000)))
43+
});
44+
c.bench_function("m4_scalx_50M_f32", |b| {
45+
b.iter(|| {
46+
m4_mod::m4_scalar_with_x(
47+
black_box(x.view()),
48+
black_box(data.view()),
49+
black_box(2_000),
50+
)
51+
})
52+
});
53+
c.bench_function("m4_simdx_50M_f32", |b| {
54+
b.iter(|| {
55+
m4_mod::m4_simd_with_x(
56+
black_box(x.view()),
57+
black_box(data.view()),
58+
black_box(2_000),
59+
)
60+
})
4061
});
4162
}
4263

4364
fn m4_f32_random_array_50M_multi_core(c: &mut Criterion) {
4465
let n = 50_000_000;
4566
let data = utils::get_random_array::<f32>(n, f32::MIN, f32::MAX);
67+
let x = Array1::from((0..n).map(|i| i as i32).collect::<Vec<i32>>());
4668
c.bench_function("m4_scal_p_50M_f32", |b| {
47-
b.iter(|| m4_mod::m4_scalar_parallel(black_box(data.view()), black_box(2_000)))
69+
b.iter(|| m4_mod::m4_scalar_without_x_parallel(black_box(data.view()), black_box(2_000)))
4870
});
4971
c.bench_function("m4_simd_p_50M_f32", |b| {
50-
b.iter(|| m4_mod::m4_simd_parallel(black_box(data.view()), black_box(2_000)))
72+
b.iter(|| m4_mod::m4_simd_without_x_parallel(black_box(data.view()), black_box(2_000)))
73+
});
74+
c.bench_function("m4_scalx_p_50M_f32", |b| {
75+
b.iter(|| {
76+
m4_mod::m4_scalar_with_x_parallel(
77+
black_box(x.view()),
78+
black_box(data.view()),
79+
black_box(2_000),
80+
)
81+
})
82+
});
83+
c.bench_function("m4_simdx_p_50M_f32", |b| {
84+
b.iter(|| {
85+
m4_mod::m4_simd_with_x_parallel(
86+
black_box(x.view()),
87+
black_box(data.view()),
88+
black_box(2_000),
89+
)
90+
})
5191
});
5292
}
5393

downsample_rs/benches/bench_minmax.rs

Lines changed: 82 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,48 +7,122 @@ use downsample_rs::minmax as minmax_mod;
77
use criterion::{black_box, Criterion};
88
use dev_utils::{config, utils};
99

10+
use ndarray::Array1;
11+
1012
fn minmax_f32_random_array_long_single_core(c: &mut Criterion) {
1113
let n = config::ARRAY_LENGTH_LONG;
1214
let data = utils::get_random_array::<f32>(n, f32::MIN, f32::MAX);
1315
c.bench_function("minmax_scal_f32", |b| {
14-
b.iter(|| minmax_mod::min_max_scalar(black_box(data.view()), black_box(2_000)))
16+
b.iter(|| minmax_mod::min_max_scalar_without_x(black_box(data.view()), black_box(2_000)))
1517
});
1618
c.bench_function("minmax_simd_f32", |b| {
17-
b.iter(|| minmax_mod::min_max_simd(black_box(data.view()), black_box(2_000)))
19+
b.iter(|| minmax_mod::min_max_simd_without_x(black_box(data.view()), black_box(2_000)))
1820
});
1921
}
2022

2123
fn minmax_f32_random_array_long_multi_core(c: &mut Criterion) {
2224
let n = config::ARRAY_LENGTH_LONG;
2325
let data = utils::get_random_array::<f32>(n, f32::MIN, f32::MAX);
2426
c.bench_function("minmax_scal_p_f32", |b| {
25-
b.iter(|| minmax_mod::min_max_scalar_parallel(black_box(data.view()), black_box(2_000)))
27+
b.iter(|| {
28+
minmax_mod::min_max_scalar_without_x_parallel(black_box(data.view()), black_box(2_000))
29+
})
2630
});
2731
c.bench_function("minmax_simd_p_f32", |b| {
28-
b.iter(|| minmax_mod::min_max_simd_parallel(black_box(data.view()), black_box(2_000)))
32+
b.iter(|| {
33+
minmax_mod::min_max_simd_without_x_parallel(black_box(data.view()), black_box(2_000))
34+
})
2935
});
3036
}
3137

3238
fn minmax_f32_random_array_50M_single_core(c: &mut Criterion) {
3339
let n = 50_000_000;
3440
let data = utils::get_random_array::<f32>(n, f32::MIN, f32::MAX);
41+
let x = Array1::from((0..n).map(|i| i as i32).collect::<Vec<i32>>());
3542
c.bench_function("minmax_scal_50M_f32", |b| {
36-
b.iter(|| minmax_mod::min_max_scalar(black_box(data.view()), black_box(2_000)))
43+
b.iter(|| minmax_mod::min_max_scalar_without_x(black_box(data.view()), black_box(2_000)))
3744
});
3845
c.bench_function("minmax_simd_50M_f32", |b| {
39-
b.iter(|| minmax_mod::min_max_simd(black_box(data.view()), black_box(2_000)))
46+
b.iter(|| minmax_mod::min_max_simd_without_x(black_box(data.view()), black_box(2_000)))
47+
});
48+
c.bench_function("minmax_scalx_50M_f32", |b| {
49+
b.iter(|| {
50+
minmax_mod::min_max_scalar_with_x(
51+
black_box(x.view()),
52+
black_box(data.view()),
53+
black_box(2_000),
54+
)
55+
})
4056
});
57+
c.bench_function("minmax_simdx_50M_f32", |b| {
58+
b.iter(|| {
59+
minmax_mod::min_max_simd_with_x(
60+
black_box(x.view()),
61+
black_box(data.view()),
62+
black_box(2_000),
63+
)
64+
})
65+
});
66+
67+
// c.bench_function("minmax_scal_50M_f32", |b| {
68+
// b.iter(|| minmax_mod::min_max_scalar_without_x(black_box(data.view()), black_box(60_000)))
69+
// });
70+
// c.bench_function("minmax_simd_50M_f32", |b| {
71+
// b.iter(|| minmax_mod::min_max_simd_without_x(black_box(data.view()), black_box(60_000)))
72+
// });
73+
// c.bench_function("minmax_scalx_50M_f32", |b| {
74+
// b.iter(|| minmax_mod::min_max_scalar_with_x(black_box(x.view()), black_box(data.view()), black_box(60_000)))
75+
// });
76+
// c.bench_function("minmax_simdx_50M_f32", |b| {
77+
// b.iter(|| minmax_mod::min_max_simd_with_x(black_box(x.view()), black_box(data.view()), black_box(60_000)))
78+
// });
4179
}
4280

4381
fn minmax_f32_random_array_50M_long_multi_core(c: &mut Criterion) {
4482
let n = 50_000_000;
4583
let data = utils::get_random_array::<f32>(n, f32::MIN, f32::MAX);
84+
let x = Array1::from((0..n).map(|i| i as i32).collect::<Vec<i32>>());
4685
c.bench_function("minmax_scal_p_50M_f32", |b| {
47-
b.iter(|| minmax_mod::min_max_scalar_parallel(black_box(data.view()), black_box(2_000)))
86+
b.iter(|| {
87+
minmax_mod::min_max_scalar_without_x_parallel(black_box(data.view()), black_box(2_000))
88+
})
4889
});
4990
c.bench_function("minmax_simd_p_50M_f32", |b| {
50-
b.iter(|| minmax_mod::min_max_simd_parallel(black_box(data.view()), black_box(2_000)))
91+
b.iter(|| {
92+
minmax_mod::min_max_simd_without_x_parallel(black_box(data.view()), black_box(2_000))
93+
})
5194
});
95+
c.bench_function("minmax_scalx_p_50M_f32", |b| {
96+
b.iter(|| {
97+
minmax_mod::min_max_scalar_with_x_parallel(
98+
black_box(x.view()),
99+
black_box(data.view()),
100+
black_box(2_000),
101+
)
102+
})
103+
});
104+
c.bench_function("minmax_simdx_p_50M_f32", |b| {
105+
b.iter(|| {
106+
minmax_mod::min_max_simd_with_x_parallel(
107+
black_box(x.view()),
108+
black_box(data.view()),
109+
black_box(2_000),
110+
)
111+
})
112+
});
113+
114+
// c.bench_function("minmax_scal_p_50M_f32", |b| {
115+
// b.iter(|| minmax_mod::min_max_scalar_without_x_parallel(black_box(data.view()), black_box(60_000)))
116+
// });
117+
// c.bench_function("minmax_simd_p_50M_f32", |b| {
118+
// b.iter(|| minmax_mod::min_max_simd_without_x_parallel(black_box(data.view()), black_box(60_000)))
119+
// });
120+
// c.bench_function("minmax_scalx_p_50M_f32", |b| {
121+
// b.iter(|| minmax_mod::min_max_scalar_with_x_parallel(black_box(x.view()), black_box(data.view()), black_box(60_000)))
122+
// });
123+
// c.bench_function("minmax_simdx_p_50M_f32", |b| {
124+
// b.iter(|| minmax_mod::min_max_simd_with_x_parallel(black_box(x.view()), black_box(data.view()), black_box(60_000)))
125+
// });
52126
}
53127

54128
// fn minmax_f32_worst_case_array_long(c: &mut Criterion) {

0 commit comments

Comments
 (0)