Skip to content

Commit

Permalink
Optimizations, maybe
Browse files Browse the repository at this point in the history
  • Loading branch information
jneem committed Oct 10, 2024
1 parent baf1830 commit fb69c86
Show file tree
Hide file tree
Showing 6 changed files with 172 additions and 48 deletions.
10 changes: 5 additions & 5 deletions core/stdlib/std.ncl
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@
# => [ 3, 2, 1 ]
```
"%
= fun pred l => fold_left (fun acc x => if pred x then acc @ [x] else acc) [] l,
= fun pred l => fold_right (fun x acc => if pred x then [x] @ acc else acc) [] l,

flatten
: forall a. Array (Array a) -> Array a
Expand Down Expand Up @@ -532,13 +532,13 @@
```
"%
= fun pred l =>
let aux = fun acc x =>
let aux = fun x acc =>
if (pred x) then
{ right = acc.right @ [x], wrong = acc.wrong }
{ right = [x] @ acc.right, wrong = acc.wrong }
else
{ right = acc.right, wrong = acc.wrong @ [x] }
{ right = acc.right, wrong = [x] @ acc.wrong }
in
fold_left aux { right = [], wrong = [] } l,
fold_right aux { right = [], wrong = [] } l,

generate
: forall a. (Number -> a) -> Number -> Array a
Expand Down
43 changes: 42 additions & 1 deletion funcarray/benches/rpds_comparison.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,5 +72,46 @@ pub fn reverse_count(c: &mut Criterion) {
});
}

criterion_group!(benches, collect, count, reverse_count);
pub fn get(c: &mut Criterion) {
let input = vec![0; 10000];
let vec8: Vector<u32, 8> = input.iter().copied().collect();
let vec32: Vector<u32, 32> = input.iter().copied().collect();
let vec64: Vector<u32, 64> = input.iter().copied().collect();
let rpds: rpds::Vector<u32> = input.iter().copied().collect();
let mut group = c.benchmark_group("get");

group.bench_function("ours 10000, N=8", |b| {
b.iter(|| {
for i in 0..10000 {
black_box(vec8.get(i));
}
});
});

group.bench_function("ours 10000, N=32", |b| {
b.iter(|| {
for i in 0..10000 {
black_box(vec32.get(i));
}
});
});

group.bench_function("ours 10000, N=64", |b| {
b.iter(|| {
for i in 0..10000 {
black_box(vec64.get(i));
}
});
});

group.bench_function("rpds 10000", |b| {
b.iter(|| {
for i in 0..10000 {
black_box(rpds.get(i));
}
});
});
}

criterion_group!(benches, collect, count, reverse_count, get);
criterion_main!(benches);
42 changes: 34 additions & 8 deletions funcarray/src/functional_array.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use std::ops::Index;

use crate::vector::{RevIntoIter, RevIter};
use crate::{
vector::{RevIntoIter, RevIter},
Const, ValidBranchingConstant,
};

use super::Vector;

Expand All @@ -15,15 +18,21 @@ use super::Vector;
/// branching factor. For performance, it should always be a power of 2. Values
/// between `8` and `64` are pretty reasonable.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct FunctionalArray<T, const N: usize> {
pub struct FunctionalArray<T, const N: usize>
where
Const<N>: ValidBranchingConstant,
{
rev_vec: Vector<T, N>,
// Our slice involves the range of indices [start, end), like most slicing.
// But since we work in reverse, our "first" element is at `end - 1`.
start: usize,
end: usize,
}

impl<T, const N: usize> Default for FunctionalArray<T, N> {
impl<T, const N: usize> Default for FunctionalArray<T, N>
where
Const<N>: ValidBranchingConstant,
{
fn default() -> Self {
FunctionalArray {
rev_vec: Default::default(),
Expand All @@ -33,7 +42,10 @@ impl<T, const N: usize> Default for FunctionalArray<T, N> {
}
}

impl<T: Clone + serde::Serialize, const N: usize> serde::Serialize for FunctionalArray<T, N> {
impl<T: Clone + serde::Serialize, const N: usize> serde::Serialize for FunctionalArray<T, N>
where
Const<N>: ValidBranchingConstant,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
Expand All @@ -50,6 +62,8 @@ impl<T: Clone + serde::Serialize, const N: usize> serde::Serialize for Functiona

impl<'de, T: Clone + serde::Deserialize<'de>, const N: usize> serde::Deserialize<'de>
for FunctionalArray<T, N>
where
Const<N>: ValidBranchingConstant,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
Expand All @@ -60,7 +74,10 @@ impl<'de, T: Clone + serde::Deserialize<'de>, const N: usize> serde::Deserialize
}
}

impl<T: Clone, const N: usize> FunctionalArray<T, N> {
impl<T: Clone, const N: usize> FunctionalArray<T, N>
where
Const<N>: ValidBranchingConstant,
{
/// Create a new `FunctionalArray` out of a double-ended iterator.
///
/// `FunctionalArray` doesn't implement `FromIterator` because for efficient
Expand Down Expand Up @@ -225,7 +242,10 @@ impl<T: Clone, const N: usize> FunctionalArray<T, N> {
}
}

impl<T: Clone, const N: usize> IntoIterator for FunctionalArray<T, N> {
impl<T: Clone, const N: usize> IntoIterator for FunctionalArray<T, N>
where
Const<N>: ValidBranchingConstant,
{
type Item = T;
type IntoIter = std::iter::Take<RevIntoIter<T, N>>;

Expand All @@ -241,7 +261,10 @@ impl<T: Clone, const N: usize> IntoIterator for FunctionalArray<T, N> {
}
}

impl<'a, T: Clone, const N: usize> IntoIterator for &'a FunctionalArray<T, N> {
impl<'a, T: Clone, const N: usize> IntoIterator for &'a FunctionalArray<T, N>
where
Const<N>: ValidBranchingConstant,
{
type Item = &'a T;
type IntoIter = std::iter::Take<RevIter<'a, T, N>>;

Expand All @@ -256,7 +279,10 @@ impl<'a, T: Clone, const N: usize> IntoIterator for &'a FunctionalArray<T, N> {
}
}

impl<T: Clone, const N: usize> Index<usize> for FunctionalArray<T, N> {
impl<T: Clone, const N: usize> Index<usize> for FunctionalArray<T, N>
where
Const<N>: ValidBranchingConstant,
{
type Output = T;

fn index(&self, index: usize) -> &Self::Output {
Expand Down
14 changes: 11 additions & 3 deletions funcarray/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@
//! [`Vector`] with support for slicing. It's backwards in order to support efficient access
//! and modification at the beginning.

// TODO:
// - benchmarks for Array

// Not yet implemented (do we need them?)
// - deletion
// - mutable indexing
Expand All @@ -27,5 +24,16 @@
mod functional_array;
pub(crate) mod vector;

pub trait ValidBranchingConstant {}
pub struct Const<const N: usize> {}

impl ValidBranchingConstant for Const<2> {}
impl ValidBranchingConstant for Const<4> {}
impl ValidBranchingConstant for Const<8> {}
impl ValidBranchingConstant for Const<16> {}
impl ValidBranchingConstant for Const<32> {}
impl ValidBranchingConstant for Const<64> {}
impl ValidBranchingConstant for Const<128> {}

pub use functional_array::FunctionalArray;
pub use vector::Vector;
Loading

0 comments on commit fb69c86

Please sign in to comment.