Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dogsdogsdogs/src/operators/lookup_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use timely::dataflow::operators::Operator;
use timely::progress::Antichain;

use differential_dataflow::{ExchangeData, Collection, AsCollection, Hashable};
use differential_dataflow::difference::{Semigroup, Monoid};
use differential_dataflow::difference::{IsZero, Semigroup, Monoid};
use differential_dataflow::operators::arrange::Arranged;
use differential_dataflow::trace::{Cursor, TraceReader};
use differential_dataflow::trace::cursor::IntoOwned;
Expand Down
6 changes: 4 additions & 2 deletions examples/monoid-bfs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@ pub struct MinSum {
value: u32,
}

use differential_dataflow::difference::{Semigroup, Multiply};
use differential_dataflow::difference::{IsZero, Semigroup, Multiply};

impl IsZero for MinSum {
fn is_zero(&self) -> bool { false }
}
impl Semigroup for MinSum {
fn plus_equals(&mut self, rhs: &Self) {
self.value = std::cmp::min(self.value, rhs.value);
}
fn is_zero(&self) -> bool { false }
}

impl Multiply<Self> for MinSum {
Expand Down
75 changes: 47 additions & 28 deletions src/difference.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,23 @@
#[deprecated]
pub use self::Abelian as Diff;

/// A type that can be an additive identity for all `Semigroup` implementations.
///
/// This method is extracted from `Semigroup` to avoid ambiguity when used.
/// It refers exclusively to the type itself, and whether it will act as the identity
/// in the course of `Semigroup<Self>::plus_equals()`.
pub trait IsZero {
/// Returns true if the element is the additive identity.
///
/// This is primarily used by differential dataflow to know when it is safe to delete an update.
/// When a difference accumulates to zero, the difference has no effect on any accumulation and can
/// be removed.
///
/// A semigroup is not obligated to have a zero element, and this method could always return
/// false in such a setting.
fn is_zero(&self) -> bool;
}

/// A type with addition and a test for zero.
///
/// These traits are currently the minimal requirements for a type to be a "difference" in differential
Expand All @@ -20,18 +37,9 @@ pub use self::Abelian as Diff;
/// There is a light presumption of commutativity here, in that while we will largely perform addition
/// in order of timestamps, for many types of timestamps there is no total order and consequently no
/// obvious order to respect. Non-commutative semigroups should be used with care.
pub trait Semigroup<Rhs: ?Sized = Self> : Clone {
pub trait Semigroup<Rhs: ?Sized = Self> : Clone + IsZero {
/// The method of `std::ops::AddAssign`, for types that do not implement `AddAssign`.
fn plus_equals(&mut self, rhs: &Rhs);
/// Returns true if the element is the additive identity.
///
/// This is primarily used by differential dataflow to know when it is safe to delete an update.
/// When a difference accumulates to zero, the difference has no effect on any accumulation and can
/// be removed.
///
/// A semigroup is not obligated to have a zero element, and this method could always return
/// false in such a setting.
fn is_zero(&self) -> bool;
}

/// A semigroup with an explicit zero element.
Expand Down Expand Up @@ -61,9 +69,11 @@ pub trait Multiply<Rhs = Self> {
/// Implementation for built-in signed integers.
macro_rules! builtin_implementation {
($t:ty) => {
impl IsZero for $t {
#[inline] fn is_zero(&self) -> bool { self == &0 }
}
impl Semigroup for $t {
#[inline] fn plus_equals(&mut self, rhs: &Self) { *self += rhs; }
#[inline] fn is_zero(&self) -> bool { self == &0 }
}

impl Monoid for $t {
Expand Down Expand Up @@ -108,9 +118,11 @@ builtin_abelian_implementation!(isize);
/// Implementations for wrapping signed integers, which have a different zero.
macro_rules! wrapping_implementation {
($t:ty) => {
impl IsZero for $t {
#[inline] fn is_zero(&self) -> bool { self == &std::num::Wrapping(0) }
}
impl Semigroup for $t {
#[inline] fn plus_equals(&mut self, rhs: &Self) { *self += rhs; }
#[inline] fn is_zero(&self) -> bool { self == &std::num::Wrapping(0) }
}

impl Monoid for $t {
Expand Down Expand Up @@ -159,27 +171,25 @@ mod present {
}
}

impl super::IsZero for Present {
fn is_zero(&self) -> bool { false }
}

impl super::Semigroup for Present {
fn plus_equals(&mut self, _rhs: &Self) { }
fn is_zero(&self) -> bool { false }
}
}

// Pair implementations.
mod tuples {

use super::{Semigroup, Monoid, Abelian, Multiply};
use super::{IsZero, Semigroup, Monoid, Abelian, Multiply};

/// Implementations for tuples. The two arguments must have the same length.
macro_rules! tuple_implementation {
( ($($name:ident)*), ($($name2:ident)*) ) => (
impl<$($name: Semigroup),*> Semigroup for ($($name,)*) {
#[allow(non_snake_case)]
#[inline] fn plus_equals(&mut self, rhs: &Self) {
let ($(ref mut $name,)*) = *self;
let ($(ref $name2,)*) = *rhs;
$($name.plus_equals($name2);)*
}

impl<$($name: IsZero),*> IsZero for ($($name,)*) {
#[allow(unused_mut)]
#[allow(non_snake_case)]
#[inline] fn is_zero(&self) -> bool {
Expand All @@ -190,6 +200,15 @@ mod tuples {
}
}

impl<$($name: Semigroup),*> Semigroup for ($($name,)*) {
#[allow(non_snake_case)]
#[inline] fn plus_equals(&mut self, rhs: &Self) {
let ($(ref mut $name,)*) = *self;
let ($(ref $name2,)*) = *rhs;
$($name.plus_equals($name2);)*
}
}

impl<$($name: Monoid),*> Monoid for ($($name,)*) {
#[allow(non_snake_case)]
#[inline] fn zero() -> Self {
Expand Down Expand Up @@ -227,15 +246,18 @@ mod tuples {
// Vector implementations
mod vector {

use super::{Semigroup, Monoid, Abelian, Multiply};
use super::{IsZero, Semigroup, Monoid, Abelian, Multiply};

impl<R: IsZero> IsZero for Vec<R> {
fn is_zero(&self) -> bool {
self.iter().all(|x| x.is_zero())
}
}

impl<R: Semigroup> Semigroup for Vec<R> {
fn plus_equals(&mut self, rhs: &Self) {
self.plus_equals(&rhs[..])
}
fn is_zero(&self) -> bool {
self.iter().all(|x| x.is_zero())
}
}

impl<R: Semigroup> Semigroup<[R]> for Vec<R> {
Expand All @@ -251,9 +273,6 @@ mod vector {
self.push(element.clone());
}
}
fn is_zero(&self) -> bool {
self.iter().all(|x| x.is_zero())
}
}

#[cfg(test)]
Expand Down
2 changes: 1 addition & 1 deletion src/operators/count.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::trace::cursor::IntoOwned;

use crate::lattice::Lattice;
use crate::{ExchangeData, Collection};
use crate::difference::Semigroup;
use crate::difference::{IsZero, Semigroup};
use crate::hashable::Hashable;
use crate::collection::AsCollection;
use crate::operators::arrange::{Arranged, ArrangeBySelf};
Expand Down