Browse Source

Implemented 'sum' and 'product' operation

master
Bergmann89 5 years ago
parent
commit
3a53ba393b
4 changed files with 310 additions and 1 deletions
  1. +66
    -0
      asparit/src/core/iterator.rs
  2. +2
    -1
      asparit/src/inner/mod.rs
  3. +121
    -0
      asparit/src/inner/product.rs
  4. +121
    -0
      asparit/src/inner/sum.rs

+ 66
- 0
asparit/src/core/iterator.rs View File

@@ -18,7 +18,9 @@ use crate::{
map::Map,
map_init::MapInit,
map_with::MapWith,
product::Product,
reduce::Reduce,
sum::Sum,
try_fold::{TryFold, TryFoldWith},
try_for_each::{TryForEach, TryForEachInit, TryForEachWith},
try_reduce::TryReduce,
@@ -925,6 +927,70 @@ pub trait ParallelIterator<'a>: Sized + Send {
TryFoldWith::new(self, init, operation)
}

/// Sums up the items in the iterator.
///
/// Note that the order in items will be reduced is not specified,
/// so if the `+` operator is not truly [associative] \(as is the
/// case for floating point numbers), then the results are not
/// fully deterministic.
///
/// [associative]: https://en.wikipedia.org/wiki/Associative_property
///
/// Basically equivalent to `self.reduce(|| 0, |a, b| a + b)`,
/// except that the type of `0` and the `+` operation may vary
/// depending on the type of value being produced.
///
/// # Examples
///
/// ```
/// use rayon::prelude::*;
///
/// let a = [1, 5, 7];
///
/// let sum: i32 = a.par_iter().sum();
///
/// assert_eq!(sum, 13);
/// ```
fn sum<S>(self) -> Sum<Self, S>
where
S: std::iter::Sum<Self::Item> + std::iter::Sum<S> + Send,
{
Sum::new(self)
}

/// Multiplies all the items in the iterator.
///
/// Note that the order in items will be reduced is not specified,
/// so if the `*` operator is not truly [associative] \(as is the
/// case for floating point numbers), then the results are not
/// fully deterministic.
///
/// [associative]: https://en.wikipedia.org/wiki/Associative_property
///
/// Basically equivalent to `self.reduce(|| 1, |a, b| a * b)`,
/// except that the type of `1` and the `*` operation may vary
/// depending on the type of value being produced.
///
/// # Examples
///
/// ```
/// use rayon::prelude::*;
///
/// fn factorial(n: u32) -> u32 {
/// (1..n+1).into_par_iter().product()
/// }
///
/// assert_eq!(factorial(0), 1);
/// assert_eq!(factorial(1), 1);
/// assert_eq!(factorial(5), 120);
/// ```
fn product<P>(self) -> Product<Self, P>
where
P: std::iter::Product<Self::Item> + std::iter::Product<P> + Send,
{
Product::new(self)
}

/// Creates a fresh collection containing all the elements produced
/// by this parallel iterator.
///


+ 2
- 1
asparit/src/inner/mod.rs View File

@@ -11,7 +11,9 @@ pub mod map;
pub mod map_init;
pub mod map_with;
pub mod noop;
pub mod product;
pub mod reduce;
pub mod sum;
pub mod try_fold;
pub mod try_for_each;
pub mod try_reduce;
@@ -51,7 +53,6 @@ mod tests {
move || j.fetch_add(1, Ordering::Relaxed),
|init, item| -> Result<(), ()> {
println!("{:?} - {:?}", init, item);

Ok(())
},
)


+ 121
- 0
asparit/src/inner/product.rs View File

@@ -0,0 +1,121 @@
use std::iter::{empty, once};
use std::marker::PhantomData;

use crate::{core::Driver, Consumer, Executor, Folder, ParallelIterator, Reducer};

/* Product */

pub struct Product<X, P> {
iterator: X,
marker: PhantomData<P>,
}

impl<X, P> Product<X, P> {
pub fn new(iterator: X) -> Self {
Self {
iterator,
marker: PhantomData,
}
}
}

impl<'a, X, P> Driver<'a, P> for Product<X, P>
where
X: ParallelIterator<'a>,
P: std::iter::Product<X::Item> + std::iter::Product + Send + 'a,
{
fn exec_with<E>(self, executor: E) -> E::Result
where
E: Executor<'a, P>,
{
let iterator = self.iterator;
let consumer = ProductConsumer(PhantomData);

iterator.drive(executor, consumer)
}
}

/* ProductConsumer */

pub struct ProductConsumer<P>(PhantomData<P>);

impl<P, I> Consumer<I> for ProductConsumer<P>
where
P: std::iter::Product<I> + std::iter::Product + Send,
{
type Folder = ProductFolder<P>;
type Reducer = ProductReducer<P>;
type Result = P;

fn split(self) -> (Self, Self, Self::Reducer) {
let left = self;
let right = ProductConsumer(PhantomData);

(left, right, ProductReducer(PhantomData))
}

fn split_at(self, _index: usize) -> (Self, Self, Self::Reducer) {
let left = self;
let right = ProductConsumer(PhantomData);

(left, right, ProductReducer(PhantomData))
}

fn into_folder(self) -> Self::Folder {
ProductFolder {
product: empty::<I>().product(),
}
}
}

/* ProductFolder */

pub struct ProductFolder<P> {
product: P,
}

impl<P, I> Folder<I> for ProductFolder<P>
where
P: std::iter::Product<I> + std::iter::Product + Send,
{
type Result = P;

fn consume(mut self, item: I) -> Self {
self.product = mul(self.product, once(item).product());

self
}

fn consume_iter<X>(mut self, iter: X) -> Self
where
X: IntoIterator<Item = I>,
{
self.product = mul(self.product, iter.into_iter().product());

self
}

fn complete(self) -> Self::Result {
self.product
}
}

/* ProductReducer */

pub struct ProductReducer<P>(PhantomData<P>);

impl<P> Reducer<P> for ProductReducer<P>
where
P: std::iter::Product + Send,
{
fn reduce(self, left: P, right: P) -> P {
mul(left, right)
}
}

fn mul<T>(left: T, right: T) -> T
where
T: std::iter::Product,
{
once(left).chain(once(right)).product()
}

+ 121
- 0
asparit/src/inner/sum.rs View File

@@ -0,0 +1,121 @@
use std::iter::{empty, once};
use std::marker::PhantomData;

use crate::{core::Driver, Consumer, Executor, Folder, ParallelIterator, Reducer};

/* Sum */

pub struct Sum<X, S> {
iterator: X,
marker: PhantomData<S>,
}

impl<X, S> Sum<X, S> {
pub fn new(iterator: X) -> Self {
Self {
iterator,
marker: PhantomData,
}
}
}

impl<'a, X, S> Driver<'a, S> for Sum<X, S>
where
X: ParallelIterator<'a>,
S: std::iter::Sum<X::Item> + std::iter::Sum + Send + 'a,
{
fn exec_with<E>(self, executor: E) -> E::Result
where
E: Executor<'a, S>,
{
let iterator = self.iterator;
let consumer = SumConsumer(PhantomData);

iterator.drive(executor, consumer)
}
}

/* SumConsumer */

pub struct SumConsumer<S>(PhantomData<S>);

impl<S, I> Consumer<I> for SumConsumer<S>
where
S: std::iter::Sum<I> + std::iter::Sum + Send,
{
type Folder = SumFolder<S>;
type Reducer = SumReducer<S>;
type Result = S;

fn split(self) -> (Self, Self, Self::Reducer) {
let left = self;
let right = SumConsumer(PhantomData);

(left, right, SumReducer(PhantomData))
}

fn split_at(self, _index: usize) -> (Self, Self, Self::Reducer) {
let left = self;
let right = SumConsumer(PhantomData);

(left, right, SumReducer(PhantomData))
}

fn into_folder(self) -> Self::Folder {
SumFolder {
sum: empty::<I>().sum(),
}
}
}

/* SumFolder */

pub struct SumFolder<S> {
sum: S,
}

impl<S, I> Folder<I> for SumFolder<S>
where
S: std::iter::Sum<I> + std::iter::Sum + Send,
{
type Result = S;

fn consume(mut self, item: I) -> Self {
self.sum = add(self.sum, once(item).sum());

self
}

fn consume_iter<X>(mut self, iter: X) -> Self
where
X: IntoIterator<Item = I>,
{
self.sum = add(self.sum, iter.into_iter().sum());

self
}

fn complete(self) -> Self::Result {
self.sum
}
}

/* SumReducer */

pub struct SumReducer<S>(PhantomData<S>);

impl<S> Reducer<S> for SumReducer<S>
where
S: std::iter::Sum + Send,
{
fn reduce(self, left: S, right: S) -> S {
add(left, right)
}
}

fn add<T>(left: T, right: T) -> T
where
T: std::iter::Sum,
{
once(left).chain(once(right)).sum()
}

Loading…
Cancel
Save