Skip to main content

differential_dataflow/
collection.rs

1//! Types and traits associated with collections of data.
2//!
3//! The `Collection` type is differential dataflow's core abstraction for an updatable pile of data.
4//!
5//! Most differential dataflow programs are "collection-oriented", in the sense that they transform
6//! one collection into another, using operators defined on collections. This contrasts with a more
7//! imperative programming style, in which one might iterate through the contents of a collection
8//! manually. The higher-level of programming allows differential dataflow to provide efficient
9//! implementations, and to support efficient incremental updates to the collections.
10
11use timely::Container;
12use timely::progress::Timestamp;
13use timely::dataflow::{Scope, Stream};
14use timely::dataflow::operators::*;
15
16use crate::difference::Abelian;
17
18/// An evolving collection represented by a stream of abstract containers.
19///
20/// The containers purport to reperesent changes to a collection, and they must implement various traits
21/// in order to expose some of this functionality (e.g. negation, timestamp manipulation). Other actions
22/// on the containers, and streams of containers, are left to the container implementor to describe.
23#[derive(Clone)]
24pub struct Collection<'scope, T: Timestamp, C: 'static> {
25    /// The underlying timely dataflow stream.
26    ///
27    /// This field is exposed to support direct timely dataflow manipulation when required, but it is
28    /// not intended to be the idiomatic way to work with the collection.
29    ///
30    /// The timestamp in the data is required to always be at least the timestamp _of_ the data, in
31    /// the timely-dataflow sense. If this invariant is not upheld, differential operators may behave
32    /// unexpectedly.
33    pub inner: Stream<'scope, T, C>,
34}
35
36impl<'scope, T: Timestamp, C> Collection<'scope, T, C> {
37    /// Creates a new Collection from a timely dataflow stream.
38    ///
39    /// This method seems to be rarely used, with the `as_collection` method on streams being a more
40    /// idiomatic approach to convert timely streams to collections. Also, the `input::Input` trait
41    /// provides a `new_collection` method which will create a new collection for you without exposing
42    /// the underlying timely stream at all.
43    ///
44    /// This stream should satisfy the timestamp invariant as documented on [Collection]; this
45    /// method does not check it.
46    pub fn new(stream: Stream<'scope, T, C>) -> Self { Self { inner: stream } }
47}
48impl<'scope, T: Timestamp, C: Container> Collection<'scope, T, C> {
49    /// Creates a new collection accumulating the contents of the two collections.
50    ///
51    /// Despite the name, differential dataflow collections are unordered. This method is so named because the
52    /// implementation is the concatenation of the stream of updates, but it corresponds to the addition of the
53    /// two collections.
54    ///
55    /// # Examples
56    ///
57    /// ```
58    /// use differential_dataflow::input::Input;
59    ///
60    /// ::timely::example(|scope| {
61    ///
62    ///     let data = scope.new_collection_from(1 .. 10).1;
63    ///
64    ///     let odds = data.clone().filter(|x| x % 2 == 1);
65    ///     let evens = data.clone().filter(|x| x % 2 == 0);
66    ///
67    ///     odds.concat(evens)
68    ///         .assert_eq(data);
69    /// });
70    /// ```
71    pub fn concat(self, other: Self) -> Self {
72        self.inner
73            .concat(other.inner)
74            .as_collection()
75    }
76    /// Creates a new collection accumulating the contents of the two collections.
77    ///
78    /// Despite the name, differential dataflow collections are unordered. This method is so named because the
79    /// implementation is the concatenation of the stream of updates, but it corresponds to the addition of the
80    /// two collections.
81    ///
82    /// # Examples
83    ///
84    /// ```
85    /// use differential_dataflow::input::Input;
86    ///
87    /// ::timely::example(|scope| {
88    ///
89    ///     let data = scope.new_collection_from(1 .. 10).1;
90    ///
91    ///     let odds = data.clone().filter(|x| x % 2 == 1);
92    ///     let evens = data.clone().filter(|x| x % 2 == 0);
93    ///
94    ///     odds.concatenate(Some(evens))
95    ///         .assert_eq(data);
96    /// });
97    /// ```
98    pub fn concatenate<I>(self, sources: I) -> Self
99    where
100        I: IntoIterator<Item=Self>
101    {
102        self.inner
103            .scope()
104            .concatenate(sources.into_iter().map(|x| x.inner).chain([self.inner]))
105            .as_collection()
106    }
107    // Brings a Collection into a nested region.
108    ///
109    /// This method is a specialization of `enter` to the case where the nested scope is a region.
110    /// It removes the need for an operator that adjusts the timestamp.
111    pub fn enter_region<'inner>(self, child: Scope<'inner, T>) -> Collection<'inner, T, C> {
112        self.inner
113            .enter(child)
114            .as_collection()
115    }
116    /// Applies a supplied function to each batch of updates.
117    ///
118    /// This method is analogous to `inspect`, but operates on batches and reveals the timestamp of the
119    /// timely dataflow capability associated with the batch of updates. The observed batching depends
120    /// on how the system executes, and may vary run to run.
121    ///
122    /// # Examples
123    ///
124    /// ```
125    /// use differential_dataflow::input::Input;
126    ///
127    /// ::timely::example(|scope| {
128    ///     scope.new_collection_from(1 .. 10).1
129    ///          .map_in_place(|x| *x *= 2)
130    ///          .filter(|x| x % 2 == 1)
131    ///          .inspect_container(|event| println!("event: {:?}", event));
132    /// });
133    /// ```
134    pub fn inspect_container<F>(self, func: F) -> Self
135    where
136        F: FnMut(Result<(&T, &C), &[T]>)+'static,
137    {
138        self.inner
139            .inspect_container(func)
140            .as_collection()
141    }
142    /// Attaches a timely dataflow probe to the output of a Collection.
143    ///
144    /// This probe is used to determine when the state of the Collection has stabilized and can
145    /// be read out.
146    pub fn probe(self) -> (probe::Handle<T>, Self) {
147        let (handle, stream) = self.inner.probe();
148        (handle, stream.as_collection())
149    }
150    /// Attaches a timely dataflow probe to the output of a Collection.
151    ///
152    /// This probe is used to determine when the state of the Collection has stabilized and all updates observed.
153    /// In addition, a probe is also often use to limit the number of rounds of input in flight at any moment; a
154    /// computation can wait until the probe has caught up to the input before introducing more rounds of data, to
155    /// avoid swamping the system.
156    pub fn probe_with(self, handle: &probe::Handle<T>) -> Self {
157        Self::new(self.inner.probe_with(handle))
158    }
159    /// The scope containing the underlying timely dataflow stream.
160    pub fn scope(&self) -> Scope<'scope, T> {
161        self.inner.scope()
162    }
163
164    /// Creates a new collection whose counts are the negation of those in the input.
165    ///
166    /// This method is most commonly used with `concat` to get those element in one collection but not another.
167    /// However, differential dataflow computations are still defined for all values of the difference type `R`,
168    /// including negative counts.
169    ///
170    /// # Examples
171    ///
172    /// ```
173    /// use differential_dataflow::input::Input;
174    ///
175    /// ::timely::example(|scope| {
176    ///
177    ///     let data = scope.new_collection_from(1 .. 10).1;
178    ///
179    ///     let odds = data.clone().filter(|x| x % 2 == 1);
180    ///     let evens = data.clone().filter(|x| x % 2 == 0);
181    ///
182    ///     odds.negate()
183    ///         .concat(data)
184    ///         .assert_eq(evens);
185    /// });
186    /// ```
187    pub fn negate(self) -> Self where C: containers::Negate {
188        use timely::dataflow::channels::pact::Pipeline;
189        self.inner
190            .unary(Pipeline, "Negate", move |_,_| move |input, output| {
191                input.for_each(|time, data| output.session(&time).give_container(&mut std::mem::take(data).negate()));
192            })
193            .as_collection()
194    }
195
196    /// Brings a Collection into a nested scope.
197    ///
198    /// # Examples
199    ///
200    /// ```
201    /// use timely::dataflow::Scope;
202    /// use differential_dataflow::input::Input;
203    ///
204    /// ::timely::example(|scope| {
205    ///
206    ///     let data = scope.new_collection_from(1 .. 10).1;
207    ///
208    ///     let result = scope.region(|child| {
209    ///         data.clone()
210    ///             .enter(child)
211    ///             .leave(scope)
212    ///     });
213    ///
214    ///     data.assert_eq(result);
215    /// });
216    /// ```
217    pub fn enter<'inner, TInner>(self, child: Scope<'inner, TInner>) -> Collection<'inner, TInner, <C as containers::Enter<T, TInner>>::InnerContainer>
218    where
219        C: containers::Enter<T, TInner, InnerContainer: Container>,
220        TInner: Refines<T>,
221    {
222        use timely::dataflow::channels::pact::Pipeline;
223        self.inner
224            .enter(child)
225            .unary(Pipeline, "Enter", move |_,_| move |input, output| {
226                input.for_each(|time, data| output.session(&time).give_container(&mut std::mem::take(data).enter()));
227            })
228            .as_collection()
229    }
230
231    /// Advances a timestamp in the stream according to the timestamp actions on the path.
232    ///
233    /// The path may advance the timestamp sufficiently that it is no longer valid, for example if
234    /// incrementing fields would result in integer overflow. In this case, the record is dropped.
235    ///
236    /// # Examples
237    /// ```
238    /// use timely::dataflow::Scope;
239    /// use timely::dataflow::operators::{ToStream, Concat, Inspect, vec::BranchWhen};
240    ///
241    /// use differential_dataflow::input::Input;
242    ///
243    /// timely::example(|scope| {
244    ///     let summary1 = 5;
245    ///
246    ///     let data = scope.new_collection_from(1 .. 10).1;
247    ///     /// Applies `results_in` on every timestamp in the collection.
248    ///     data.results_in(summary1);
249    /// });
250    /// ```
251    pub fn results_in(self, step: T::Summary) -> Self
252    where
253        C: containers::ResultsIn<T::Summary>,
254    {
255        use timely::dataflow::channels::pact::Pipeline;
256        self.inner
257            .unary(Pipeline, "ResultsIn", move |_,_| move |input, output| {
258                input.for_each(|time, data| output.session(&time).give_container(&mut std::mem::take(data).results_in(&step)));
259            })
260            .as_collection()
261    }
262}
263
264use timely::progress::timestamp::Refines;
265
266/// Methods requiring a nested scope.
267impl<'scope, T: Timestamp, C: Container> Collection<'scope, T, C>
268{
269    /// Returns the final value of a Collection from a nested scope to its containing scope.
270    ///
271    /// # Examples
272    ///
273    /// ```
274    /// use timely::dataflow::Scope;
275    /// use differential_dataflow::input::Input;
276    ///
277    /// ::timely::example(|scope| {
278    ///
279    ///    let data = scope.new_collection_from(1 .. 10).1;
280    ///
281    ///    let result = scope.region(|child| {
282    ///         data.clone()
283    ///             .enter(child)
284    ///             .leave(scope)
285    ///     });
286    ///
287    ///     data.assert_eq(result);
288    /// });
289    /// ```
290    pub fn leave<'outer, TOuter>(self, outer: Scope<'outer, TOuter>) -> Collection<'outer, TOuter, <C as containers::Leave<T, TOuter>>::OuterContainer>
291    where
292        TOuter: Timestamp,
293        T: Refines<TOuter>,
294        C: containers::Leave<T, TOuter, OuterContainer: Container>,
295    {
296        use timely::dataflow::channels::pact::Pipeline;
297        self.inner
298            .leave(outer)
299            .unary(Pipeline, "Leave", move |_,_| move |input, output| {
300                input.for_each(|time, data| output.session(&time).give_container(&mut std::mem::take(data).leave()));
301            })
302            .as_collection()
303    }
304
305    /// Returns the value of a Collection from a nested region to its containing scope.
306    ///
307    /// This method is a specialization of `leave` to the case that of a nested region.
308    /// It removes the need for an operator that adjusts the timestamp.
309    pub fn leave_region<'outer>(self, outer: Scope<'outer, T>) -> Collection<'outer, T, C> {
310        self.inner
311            .leave(outer)
312            .as_collection()
313    }
314}
315
316pub use vec::Collection as VecCollection;
317/// Specializations of `Collection` that use `Vec` as the container.
318pub mod vec {
319
320    use std::hash::Hash;
321
322    use timely::progress::Timestamp;
323    use timely::order::Product;
324    use timely::dataflow::scope::Iterative;
325    use timely::dataflow::operators::*;
326    use timely::dataflow::operators::vec::*;
327
328    use crate::collection::AsCollection;
329    use crate::difference::{Semigroup, Abelian, Multiply};
330    use crate::lattice::Lattice;
331    use crate::hashable::Hashable;
332    use crate::trace::{BatchCursor, BatchDiff, BatchKey, BatchVal, Navigable};
333    use crate::trace::Cursor;
334
335    /// An evolving collection of values of type `D`, backed by Rust `Vec` types as containers.
336    ///
337    /// The `Collection` type is the core abstraction in differential dataflow programs. As you write your
338    /// differential dataflow computation, you write as if the collection is a static dataset to which you
339    /// apply functional transformations, creating new collections. Once your computation is written, you
340    /// are able to mutate the collection (by inserting and removing elements); differential dataflow will
341    /// propagate changes through your functional computation and report the corresponding changes to the
342    /// output collections.
343    ///
344    /// Each vec collection has three generic parameters. The parameter `T` is the timestamp type of the
345    /// scope in which the collection exists; as you write more complicated programs you may wish to
346    /// introduce nested scopes (e.g. for iteration), and this parameter tracks the scope's timestamp
347    /// (for timely dataflow's benefit). The `D` parameter is the type of data in your collection, for
348    /// example `String`, or `(u32, Vec<Option<()>>)`.
349    /// The `R` parameter represents the types of changes that the data undergo, and is most commonly (and
350    /// defaults to) `isize`, representing changes to the occurrence count of each record.
351    ///
352    /// This type definition instantiates the [`Collection`] type with a `Vec<(D, T, R)>`.
353    pub type Collection<'scope, T, D, R = isize> = super::Collection<'scope, T, Vec<(D, T, R)>>;
354
355
356    impl<'scope, T: Timestamp, D: Clone+'static, R: Clone+'static> Collection<'scope, T, D, R> {
357        /// Creates a new collection by applying the supplied function to each input element.
358        ///
359        /// # Examples
360        ///
361        /// ```
362        /// use differential_dataflow::input::Input;
363        ///
364        /// ::timely::example(|scope| {
365        ///     scope.new_collection_from(1 .. 10).1
366        ///          .map(|x| x * 2)
367        ///          .filter(|x| x % 2 == 1)
368        ///          .assert_empty();
369        /// });
370        /// ```
371        pub fn map<D2, L>(self, mut logic: L) -> Collection<'scope, T, D2, R>
372        where
373            D2: Clone+'static,
374            L: FnMut(D) -> D2 + 'static,
375        {
376            self.inner
377                .map(move |(data, time, delta)| (logic(data), time, delta))
378                .as_collection()
379        }
380        /// Creates a new collection by applying the supplied function to each input element.
381        ///
382        /// Although the name suggests in-place mutation, this function does not change the source collection,
383        /// but rather re-uses the underlying allocations in its implementation. The method is semantically
384        /// equivalent to `map`, but can be more efficient.
385        ///
386        /// # Examples
387        ///
388        /// ```
389        /// use differential_dataflow::input::Input;
390        ///
391        /// ::timely::example(|scope| {
392        ///     scope.new_collection_from(1 .. 10).1
393        ///          .map_in_place(|x| *x *= 2)
394        ///          .filter(|x| x % 2 == 1)
395        ///          .assert_empty();
396        /// });
397        /// ```
398        pub fn map_in_place<L>(self, mut logic: L) -> Collection<'scope, T, D, R>
399        where
400            L: FnMut(&mut D) + 'static,
401        {
402            self.inner
403                .map_in_place(move |&mut (ref mut data, _, _)| logic(data))
404                .as_collection()
405        }
406        /// Creates a new collection by applying the supplied function to each input element and accumulating the results.
407        ///
408        /// This method extracts an iterator from each input element, and extracts the full contents of the iterator. Be
409        /// warned that if the iterators produce substantial amounts of data, they are currently fully drained before
410        /// attempting to consolidate the results.
411        ///
412        /// # Examples
413        ///
414        /// ```
415        /// use differential_dataflow::input::Input;
416        ///
417        /// ::timely::example(|scope| {
418        ///     scope.new_collection_from(1 .. 10).1
419        ///          .flat_map(|x| 0 .. x);
420        /// });
421        /// ```
422        pub fn flat_map<I, L>(self, mut logic: L) -> Collection<'scope, T, I::Item, R>
423        where
424            T: Clone,
425            I: IntoIterator<Item: Clone+'static>,
426            L: FnMut(D) -> I + 'static,
427        {
428            self.inner
429                .flat_map(move |(data, time, delta)| logic(data).into_iter().map(move |x| (x, time.clone(), delta.clone())))
430                .as_collection()
431        }
432        /// Creates a new collection containing those input records satisfying the supplied predicate.
433        ///
434        /// # Examples
435        ///
436        /// ```
437        /// use differential_dataflow::input::Input;
438        ///
439        /// ::timely::example(|scope| {
440        ///     scope.new_collection_from(1 .. 10).1
441        ///          .map(|x| x * 2)
442        ///          .filter(|x| x % 2 == 1)
443        ///          .assert_empty();
444        /// });
445        /// ```
446        pub fn filter<L>(self, mut logic: L) -> Collection<'scope, T, D, R>
447        where
448            L: FnMut(&D) -> bool + 'static,
449        {
450            self.inner
451                .filter(move |(data, _, _)| logic(data))
452                .as_collection()
453        }
454        /// Replaces each record with another, with a new difference type.
455        ///
456        /// This method is most commonly used to take records containing aggregatable data (e.g. numbers to be summed)
457        /// and move the data into the difference component. This will allow differential dataflow to update in-place.
458        ///
459        /// # Examples
460        ///
461        /// ```
462        /// use differential_dataflow::input::Input;
463        ///
464        /// ::timely::example(|scope| {
465        ///
466        ///     let nums = scope.new_collection_from(0 .. 10).1;
467        ///     let x1 = nums.clone().flat_map(|x| 0 .. x);
468        ///     let x2 = nums.map(|x| (x, 9 - x))
469        ///                  .explode(|(x,y)| Some((x,y)));
470        ///
471        ///     x1.assert_eq(x2);
472        /// });
473        /// ```
474        pub fn explode<D2, R2, I, L>(self, mut logic: L) -> Collection<'scope, T, D2, <R2 as Multiply<R>>::Output>
475        where
476            D2: Clone+'static,
477            R2: Semigroup+Multiply<R, Output: Semigroup+'static>,
478            I: IntoIterator<Item=(D2,R2)>,
479            L: FnMut(D)->I+'static,
480        {
481            self.inner
482                .flat_map(move |(x, t, d)| logic(x).into_iter().map(move |(x,d2)| (x, t.clone(), d2.multiply(&d))))
483                .as_collection()
484        }
485
486        /// Joins each record against a collection defined by the function `logic`.
487        ///
488        /// This method performs what is essentially a join with the collection of records `(x, logic(x))`.
489        /// Rather than materialize this second relation, `logic` is applied to each record and the appropriate
490        /// modifications made to the results, namely joining timestamps and multiplying differences.
491        ///
492        /// #Examples
493        ///
494        /// ```
495        /// use differential_dataflow::input::Input;
496        ///
497        /// ::timely::example(|scope| {
498        ///     // creates `x` copies of `2*x` from time `3*x` until `4*x`,
499        ///     // for x from 0 through 9.
500        ///     scope.new_collection_from(0 .. 10isize).1
501        ///          .join_function(|x|
502        ///              //   data      time      diff
503        ///              vec![(2*x, (3*x) as u64,  x),
504        ///                   (2*x, (4*x) as u64, -x)]
505        ///           );
506        /// });
507        /// ```
508        pub fn join_function<D2, R2, I, L>(self, mut logic: L) -> Collection<'scope, T, D2, <R2 as Multiply<R>>::Output>
509        where
510            T: Lattice,
511            D2: Clone+'static,
512            R2: Semigroup+Multiply<R, Output: Semigroup+'static>,
513            I: IntoIterator<Item=(D2,T,R2)>,
514            L: FnMut(D)->I+'static,
515        {
516            self.inner
517                .flat_map(move |(x, t, d)| logic(x).into_iter().map(move |(x,t2,d2)| (x, t.join(&t2), d2.multiply(&d))))
518                .as_collection()
519        }
520
521        /// Brings a Collection into a nested scope, at varying times.
522        ///
523        /// The `initial` function indicates the time at which each element of the Collection should appear.
524        ///
525        /// # Examples
526        ///
527        /// ```
528        /// use timely::dataflow::Scope;
529        /// use differential_dataflow::input::Input;
530        ///
531        /// ::timely::example(|scope| {
532        ///
533        ///     let data = scope.new_collection_from(1 .. 10).1;
534        ///
535        ///     let result = scope.iterative::<u64,_,_>(|child| {
536        ///         data.clone()
537        ///             .enter_at(child, |x| *x)
538        ///             .leave(scope)
539        ///     });
540        ///
541        ///     data.assert_eq(result);
542        /// });
543        /// ```
544        pub fn enter_at<'inner, TInner, F>(self, child: Iterative<'inner, T, TInner>, mut initial: F) -> Collection<'inner, Product<T, TInner>, D, R>
545        where
546            TInner: Timestamp+Hash,
547            F: FnMut(&D) -> TInner + Clone + 'static,
548        {
549            self.inner
550                .enter(child)
551                .map(move |(data, time, diff)| {
552                    let new_time = Product::new(time, initial(&data));
553                    (data, new_time, diff)
554                })
555                .as_collection()
556        }
557
558        /// Delays each difference by a supplied function.
559        ///
560        /// It is assumed that `func` only advances timestamps; this is not verified, and things may go horribly
561        /// wrong if that assumption is incorrect. It is also critical that `func` be monotonic: if two times are
562        /// ordered, they should have the same order or compare equal once `func` is applied to them (this
563        /// is because we advance the timely capability with the same logic, and it must remain `less_equal`
564        /// to all of the data timestamps).
565        pub fn delay<F>(self, func: F) -> Collection<'scope, T, D, R>
566        where
567            T: Hash,
568            F: FnMut(&T) -> T + Clone + 'static,
569        {
570            let mut func1 = func.clone();
571            let mut func2 = func.clone();
572
573            self.inner
574                .delay_batch(move |x| func1(x))
575                .map_in_place(move |x| x.1 = func2(&x.1))
576                .as_collection()
577        }
578
579        /// Applies a supplied function to each update.
580        ///
581        /// This method is most commonly used to report information back to the user, often for debugging purposes.
582        /// Any function can be used here, but be warned that the incremental nature of differential dataflow does
583        /// not guarantee that it will be called as many times as you might expect.
584        ///
585        /// The `(data, time, diff)` triples indicate a change `diff` to the frequency of `data` which takes effect
586        /// at the logical time `time`. When times are totally ordered (for example, `usize`), these updates reflect
587        /// the changes along the sequence of collections. For partially ordered times, the mathematics are more
588        /// interesting and less intuitive, unfortunately.
589        ///
590        /// # Examples
591        ///
592        /// ```
593        /// use differential_dataflow::input::Input;
594        ///
595        /// ::timely::example(|scope| {
596        ///     scope.new_collection_from(1 .. 10).1
597        ///          .map_in_place(|x| *x *= 2)
598        ///          .filter(|x| x % 2 == 1)
599        ///          .inspect(|x| println!("error: {:?}", x));
600        /// });
601        /// ```
602        pub fn inspect<F>(self, func: F) -> Collection<'scope, T, D, R>
603        where
604            F: FnMut(&(D, T, R))+'static,
605        {
606            self.inner
607                .inspect(func)
608                .as_collection()
609        }
610        /// Applies a supplied function to each batch of updates.
611        ///
612        /// This method is analogous to `inspect`, but operates on batches and reveals the timestamp of the
613        /// timely dataflow capability associated with the batch of updates. The observed batching depends
614        /// on how the system executes, and may vary run to run.
615        ///
616        /// # Examples
617        ///
618        /// ```
619        /// use differential_dataflow::input::Input;
620        ///
621        /// ::timely::example(|scope| {
622        ///     scope.new_collection_from(1 .. 10).1
623        ///          .map_in_place(|x| *x *= 2)
624        ///          .filter(|x| x % 2 == 1)
625        ///          .inspect_batch(|t,xs| println!("errors @ {:?}: {:?}", t, xs));
626        /// });
627        /// ```
628        pub fn inspect_batch<F>(self, mut func: F) -> Collection<'scope, T, D, R>
629        where
630            F: FnMut(&T, &[(D, T, R)])+'static,
631        {
632            self.inner
633                .inspect_batch(move |time, data| func(time, data))
634                .as_collection()
635        }
636
637        /// Assert if the collection is ever non-empty.
638        ///
639        /// Because this is a dataflow fragment, the test is only applied as the computation is run. If the computation
640        /// is not run, or not run to completion, there may be un-exercised times at which the collection could be
641        /// non-empty. Typically, a timely dataflow computation runs to completion on drop, and so clean exit from a
642        /// program should indicate that this assertion never found cause to complain.
643        ///
644        /// # Examples
645        ///
646        /// ```
647        /// use differential_dataflow::input::Input;
648        ///
649        /// ::timely::example(|scope| {
650        ///     scope.new_collection_from(1 .. 10).1
651        ///          .map(|x| x * 2)
652        ///          .filter(|x| x % 2 == 1)
653        ///          .assert_empty();
654        /// });
655        /// ```
656        pub fn assert_empty(self)
657        where
658            D: crate::ExchangeData+Hashable,
659            R: crate::ExchangeData+Hashable + Semigroup,
660            T: Lattice+Ord,
661        {
662            self.consolidate()
663                .inspect(|x| panic!("Assertion failed: non-empty collection: {:?}", x));
664        }
665    }
666
667    /// Methods requiring an Abelian difference, to support negation.
668    impl<'scope, T: Timestamp + Clone + 'static, D: Clone+'static, R: Abelian+'static> Collection<'scope, T, D, R> {
669        /// Assert if the collections are ever different.
670        ///
671        /// Because this is a dataflow fragment, the test is only applied as the computation is run. If the computation
672        /// is not run, or not run to completion, there may be un-exercised times at which the collections could vary.
673        /// Typically, a timely dataflow computation runs to completion on drop, and so clean exit from a program should
674        /// indicate that this assertion never found cause to complain.
675        ///
676        /// # Examples
677        ///
678        /// ```
679        /// use differential_dataflow::input::Input;
680        ///
681        /// ::timely::example(|scope| {
682        ///
683        ///     let data = scope.new_collection_from(1 .. 10).1;
684        ///
685        ///     let odds = data.clone().filter(|x| x % 2 == 1);
686        ///     let evens = data.clone().filter(|x| x % 2 == 0);
687        ///
688        ///     odds.concat(evens)
689        ///         .assert_eq(data);
690        /// });
691        /// ```
692        pub fn assert_eq(self, other: Self)
693        where
694            D: crate::ExchangeData+Hashable,
695            R: crate::ExchangeData+Hashable,
696            T: Lattice+Ord,
697        {
698            self.negate()
699                .concat(other)
700                .assert_empty();
701        }
702    }
703
704    use crate::trace::{Trace, Builder};
705    use crate::operators::arrange::{Arranged, TraceAgent};
706
707    impl <'scope, T, K, V, R> Collection<'scope, T, (K, V), R>
708    where
709        T: Timestamp + Lattice + Ord,
710        K: crate::ExchangeData+Hashable,
711        V: crate::ExchangeData,
712        R: crate::ExchangeData+Semigroup,
713    {
714        /// Applies a reduction function on records grouped by key.
715        ///
716        /// Input data must be structured as `(key, val)` pairs.
717        /// The user-supplied reduction function takes as arguments
718        ///
719        /// 1. a reference to the key,
720        /// 2. a reference to the slice of values and their accumulated updates,
721        /// 3. a mutuable reference to a vector to populate with output values and accumulated updates.
722        ///
723        /// The user logic is only invoked for non-empty input collections, and it is safe to assume that the
724        /// slice of input values is non-empty. The values are presented in sorted order, as defined by their
725        /// `Ord` implementations.
726        ///
727        /// # Examples
728        ///
729        /// ```
730        /// use differential_dataflow::input::Input;
731        ///
732        /// ::timely::example(|scope| {
733        ///     // report the smallest value for each group
734        ///     scope.new_collection_from(1 .. 10).1
735        ///          .map(|x| (x / 3, x))
736        ///          .reduce(|_key, input, output| {
737        ///              output.push((*input[0].0, 1))
738        ///          });
739        /// });
740        /// ```
741        pub fn reduce<L, V2: crate::Data, R2: Ord+Abelian+'static>(self, logic: L) -> Collection<'scope, T, (K, V2), R2>
742        where L: FnMut(&K, &[(&V, R)], &mut Vec<(V2, R2)>)+'static {
743            self.reduce_named("Reduce", logic)
744        }
745
746        /// As `reduce` with the ability to name the operator.
747        pub fn reduce_named<L, V2: crate::Data, R2: Ord+Abelian+'static>(self, name: &str, logic: L) -> Collection<'scope, T, (K, V2), R2>
748        where L: FnMut(&K, &[(&V, R)], &mut Vec<(V2, R2)>)+'static {
749            use crate::trace::implementations::{ValBuilder, ValSpine};
750
751            self.arrange_by_key_named(&format!("Arrange: {}", name))
752                .reduce_abelian::<_,ValBuilder<_,_,_,_>,ValSpine<K,V2,_,_>,_,_>(
753                    name,
754                    logic,
755                    |vec, key, upds| { vec.clear(); vec.extend(upds.drain(..).map(|(v,t,r)| ((key.clone(), v),t,r))); },
756                )
757                .as_collection(|k,v| (k.clone(), v.clone()))
758        }
759
760        /// Applies `reduce` to arranged data, and returns an arrangement of output data.
761        ///
762        /// This method is used by the more ergonomic `reduce`, `distinct`, and `count` methods, although
763        /// it can be very useful if one needs to manually attach and re-use existing arranged collections.
764        ///
765        /// # Examples
766        ///
767        /// ```
768        /// use differential_dataflow::input::Input;
769        /// use differential_dataflow::trace::Trace;
770        /// use differential_dataflow::trace::implementations::{ValBuilder, ValSpine};
771        ///
772        /// ::timely::example(|scope| {
773        ///
774        ///     let trace =
775        ///     scope.new_collection_from(1 .. 10u32).1
776        ///          .map(|x| (x, x))
777        ///          .reduce_abelian::<_,ValBuilder<_,_,_,_>,ValSpine<_,_,_,_>>(
778        ///             "Example",
779        ///              move |_key, src, dst| dst.push((*src[0].0, 1))
780        ///          )
781        ///          .trace;
782        /// });
783        /// ```
784        pub fn reduce_abelian<L, Bu, T2>(self, name: &str, mut logic: L) -> Arranged<'scope, TraceAgent<T2>>
785        where
786            T2: Trace<Batch: Navigable, Time=T>+'static,
787            for<'a> BatchCursor<T2>: Cursor<Key<'a>= &'a K, ValOwn = V, Time = T2::Time, Diff: Abelian>,
788            Bu: Builder<Time=T2::Time, Input = Vec<((K, V), T2::Time, BatchDiff<T2>)>, Output = T2::Batch> + 'static,
789            L: FnMut(&K, &[(&V, R)], &mut Vec<(V, BatchDiff<T2>)>)+'static,
790        {
791            self.reduce_core::<_,Bu,T2>(name, move |key, input, output, change| {
792                if !input.is_empty() { logic(key, input, change); }
793                change.extend(output.drain(..).map(|(x,mut d)| { d.negate(); (x, d) }));
794                crate::consolidation::consolidate(change);
795            })
796        }
797
798        /// Solves for output updates when presented with inputs and would-be outputs.
799        ///
800        /// Unlike `reduce_arranged`, this method may be called with an empty `input`,
801        /// and it may not be safe to index into the first element.
802        /// At least one of the two collections will be non-empty.
803        pub fn reduce_core<L, Bu, T2>(self, name: &str, logic: L) -> Arranged<'scope, TraceAgent<T2>>
804        where
805            V: Clone+'static,
806            T2: Trace<Batch: Navigable, Time=T>+'static,
807            for<'a> BatchCursor<T2>: Cursor<Key<'a>=&'a K, ValOwn = V, Time = T2::Time>,
808            Bu: Builder<Time=T2::Time, Input = Vec<((K, V), T2::Time, BatchDiff<T2>)>, Output = T2::Batch> + 'static,
809            L: FnMut(&K, &[(&V, R)], &mut Vec<(V,BatchDiff<T2>)>, &mut Vec<(V, BatchDiff<T2>)>)+'static,
810        {
811            self.arrange_by_key_named(&format!("Arrange: {}", name))
812                .reduce_core::<_,Bu,_,_,_>(
813                    name,
814                    logic,
815                    |vec, key, upds| { vec.clear(); vec.extend(upds.drain(..).map(|(v,t,r)| ((key.clone(), v),t,r))); },
816                )
817        }
818    }
819
820    impl<'scope, T, K, R1> Collection<'scope, T, K, R1>
821    where
822        T: Timestamp + Lattice + Ord,
823        K: crate::ExchangeData+Hashable,
824        R1: crate::ExchangeData+Semigroup
825    {
826
827        /// Reduces the collection to one occurrence of each distinct element.
828        ///
829        /// # Examples
830        ///
831        /// ```
832        /// use differential_dataflow::input::Input;
833        ///
834        /// ::timely::example(|scope| {
835        ///     // report at most one of each key.
836        ///     scope.new_collection_from(1 .. 10).1
837        ///          .map(|x| x / 3)
838        ///          .distinct();
839        /// });
840        /// ```
841        pub fn distinct(self) -> Collection<'scope, T, K, isize> {
842            self.distinct_core()
843        }
844
845        /// Distinct for general integer differences.
846        ///
847        /// This method allows `distinct` to produce collections whose difference
848        /// type is something other than an `isize` integer, for example perhaps an
849        /// `i32`.
850        pub fn distinct_core<R2: Ord+Abelian+'static+From<i8>>(self) -> Collection<'scope, T, K, R2> {
851            self.threshold_named("Distinct", |_,_| R2::from(1i8))
852        }
853
854        /// Transforms the multiplicity of records.
855        ///
856        /// The `threshold` function is obliged to map `R1::zero` to `R2::zero`, or at
857        /// least the computation may behave as if it does. Otherwise, the transformation
858        /// can be nearly arbitrary: the code does not assume any properties of `threshold`.
859        ///
860        /// # Examples
861        ///
862        /// ```
863        /// use differential_dataflow::input::Input;
864        ///
865        /// ::timely::example(|scope| {
866        ///     // report at most one of each key.
867        ///     scope.new_collection_from(1 .. 10).1
868        ///          .map(|x| x / 3)
869        ///          .threshold(|_,c| c % 2);
870        /// });
871        /// ```
872        pub fn threshold<R2: Ord+Abelian+'static, F: FnMut(&K, &R1)->R2+'static>(self, thresh: F) -> Collection<'scope, T, K, R2> {
873            self.threshold_named("Threshold", thresh)
874        }
875
876        /// A `threshold` with the ability to name the operator.
877        pub fn threshold_named<R2: Ord+Abelian+'static, F: FnMut(&K,&R1)->R2+'static>(self, name: &str, mut thresh: F) -> Collection<'scope, T, K, R2> {
878            use crate::trace::implementations::{KeyBuilder, KeySpine};
879
880            self.arrange_by_self_named(&format!("Arrange: {}", name))
881                .reduce_abelian::<_,KeyBuilder<K,T,R2>,KeySpine<K,T,R2>,_,_>(
882                    name,
883                    move |k,s,t| t.push(((), thresh(k, &s[0].1))),
884                    |vec, key, upds| { vec.clear(); vec.extend(upds.drain(..).map(|(v,t,r)| ((key.clone(), v),t,r))); },
885                )
886                .as_collection(|k,_| k.clone())
887        }
888
889    }
890
891    impl<'scope, T, K, R> Collection<'scope, T, K, R>
892    where
893        T: Timestamp + Lattice + Ord,
894        K: crate::ExchangeData+Hashable,
895        R: crate::ExchangeData+Semigroup
896    {
897
898        /// Counts the number of occurrences of each element.
899        ///
900        /// # Examples
901        ///
902        /// ```
903        /// use differential_dataflow::input::Input;
904        ///
905        /// ::timely::example(|scope| {
906        ///     // report the number of occurrences of each key
907        ///     scope.new_collection_from(1 .. 10).1
908        ///          .map(|x| x / 3)
909        ///          .count();
910        /// });
911        /// ```
912        pub fn count(self) -> Collection<'scope, T, (K, R), isize> { self.count_core() }
913
914        /// Count for general integer differences.
915        ///
916        /// This method allows `count` to produce collections whose difference
917        /// type is something other than an `isize` integer, for example perhaps an
918        /// `i32`.
919        pub fn count_core<R2: Ord + Abelian + From<i8> + 'static>(self) -> Collection<'scope, T, (K, R), R2> {
920            use crate::trace::implementations::{ValBuilder, ValSpine};
921            self.arrange_by_self_named("Arrange: Count")
922                .reduce_abelian::<_,ValBuilder<K,R,T,R2>,ValSpine<K,R,T,R2>,_,_>(
923                    "Count",
924                    |_k,s,t| t.push((s[0].1.clone(), R2::from(1i8))),
925                    |vec, key, upds| { vec.clear(); vec.extend(upds.drain(..).map(|(v,t,r)| ((key.clone(), v),t,r))); },
926                )
927                .as_collection(|k,c| (k.clone(), c.clone()))
928        }
929    }
930
931    /// Methods which require data be arrangeable.
932    impl<'scope, T, D, R> Collection<'scope, T, D, R>
933    where
934        T: Timestamp + Clone + 'static + Lattice,
935        D: crate::ExchangeData+Hashable,
936        R: crate::ExchangeData+Semigroup,
937    {
938        /// Aggregates the weights of equal records into at most one record.
939        ///
940        /// This method uses the type `D`'s `hashed()` method to partition the data. The data are
941        /// accumulated in place, each held back until their timestamp has completed.
942        ///
943        /// # Examples
944        ///
945        /// ```
946        /// use differential_dataflow::input::Input;
947        ///
948        /// ::timely::example(|scope| {
949        ///
950        ///     let x = scope.new_collection_from(1 .. 10u32).1;
951        ///
952        ///     x.clone()
953        ///      .negate()
954        ///      .concat(x)
955        ///      .consolidate() // <-- ensures cancellation occurs
956        ///      .assert_empty();
957        /// });
958        /// ```
959        pub fn consolidate(self) -> Self {
960            use crate::trace::implementations::{KeyBatcher, KeyBuilder, KeySpine};
961            self.consolidate_named::<KeyBatcher<_, _, _>,KeyBuilder<_,_,_>, KeySpine<_,_,_>,_>("Consolidate", |key,&()| key.clone())
962        }
963
964        /// As `consolidate` but with the ability to name the operator, specify the trace type,
965        /// and provide the function `reify` to produce owned keys and values..
966        pub fn consolidate_named<Ba, Bu, Tr, F>(self, name: &str, reify: F) -> Self
967        where
968            Ba: crate::trace::Batcher<Output=Vec<((D, ()), T, R)>, Time=T> + 'static,
969            Tr: crate::trace::Trace<Batch: Navigable, Time=T>+'static,
970            for<'a> BatchCursor<Tr>: Cursor<Time=Tr::Time, Diff=R>,
971            Bu: crate::trace::Builder<Time=Tr::Time, Input=Vec<((D, ()), T, R)>, Output=Tr::Batch>,
972            F: Fn(BatchKey<'_, Tr>, BatchVal<'_, Tr>) -> D + 'static,
973        {
974            use crate::operators::arrange::arrangement::Arrange;
975            self.map(|k| (k, ()))
976                .arrange_named::<Ba, Bu, Tr>(name)
977                .as_collection(reify)
978        }
979
980        /// Aggregates the weights of equal records.
981        ///
982        /// Unlike `consolidate`, this method does not exchange data and does not
983        /// ensure that at most one copy of each `(data, time)` pair exists in the
984        /// results. Instead, it acts on each batch of data and collapses equivalent
985        /// `(data, time)` pairs found therein, suppressing any that accumulate to
986        /// zero.
987        ///
988        /// # Examples
989        ///
990        /// ```
991        /// use differential_dataflow::input::Input;
992        ///
993        /// ::timely::example(|scope| {
994        ///
995        ///     let x = scope.new_collection_from(1 .. 10u32).1;
996        ///
997        ///     // nothing to assert, as no particular guarantees.
998        ///     x.clone()
999        ///      .negate()
1000        ///      .concat(x)
1001        ///      .consolidate_stream();
1002        /// });
1003        /// ```
1004        pub fn consolidate_stream(self) -> Self {
1005
1006            use timely::dataflow::channels::pact::Pipeline;
1007            use timely::dataflow::operators::Operator;
1008            use crate::collection::AsCollection;
1009            use crate::consolidation::ConsolidatingContainerBuilder;
1010
1011            self.inner
1012                .unary::<ConsolidatingContainerBuilder<_>, _, _, _>(Pipeline, "ConsolidateStream", |_cap, _info| {
1013
1014                    move |input, output| {
1015                        input.for_each(|time, data| {
1016                            output.session_with_builder(&time).give_iterator(data.drain(..));
1017                        })
1018                    }
1019                })
1020                .as_collection()
1021        }
1022    }
1023
1024    use crate::trace::implementations::{ValSpine, ValBatcher, ValBuilder};
1025    use crate::trace::implementations::{KeySpine, KeyBatcher, KeyBuilder};
1026    use crate::trace::implementations::ContainerChunker;
1027    use crate::operators::arrange::Arrange;
1028
1029    impl<'scope, T, K, V, R> Arrange<'scope, T, Vec<((K, V), T, R)>> for Collection<'scope, T, (K, V), R>
1030    where
1031        T: Timestamp + Lattice,
1032        K: crate::ExchangeData + Hashable,
1033        V: crate::ExchangeData,
1034        R: crate::ExchangeData + Semigroup,
1035    {
1036        fn arrange_named<Ba, Bu, Tr>(self, name: &str) -> Arranged<'scope, TraceAgent<Tr>>
1037        where
1038            Ba: crate::trace::Batcher<Output=Vec<((K, V), T, R)>, Time=T> + 'static,
1039            Bu: crate::trace::Builder<Time=T, Input=Vec<((K, V), T, R)>, Output = Tr::Batch>,
1040            Tr: crate::trace::Trace<Time=T> + 'static,
1041        {
1042            let exchange = timely::dataflow::channels::pact::Exchange::new(move |update: &((K,V),T,R)| (update.0).0.hashed().into());
1043            crate::operators::arrange::arrangement::arrange_core::<_, _, ContainerChunker<Vec<((K, V), T, R)>>, Ba, Bu, _>(self.inner, exchange, name)
1044        }
1045    }
1046
1047    impl<'scope, T, K: crate::ExchangeData+Hashable, R: crate::ExchangeData+Semigroup> Arrange<'scope, T, Vec<((K, ()), T, R)>> for Collection<'scope, T, K, R>
1048    where
1049        T: Timestamp + Lattice + Ord,
1050    {
1051        fn arrange_named<Ba, Bu, Tr>(self, name: &str) -> Arranged<'scope, TraceAgent<Tr>>
1052        where
1053            Ba: crate::trace::Batcher<Output=Vec<((K, ()), T, R)>, Time=T> + 'static,
1054            Bu: crate::trace::Builder<Time=T, Input=Vec<((K, ()), T, R)>, Output = Tr::Batch>,
1055            Tr: crate::trace::Trace<Time=T> + 'static,
1056        {
1057            let exchange = timely::dataflow::channels::pact::Exchange::new(move |update: &((K,()),T,R)| (update.0).0.hashed().into());
1058            crate::operators::arrange::arrangement::arrange_core::<_, _, ContainerChunker<Vec<((K, ()), T, R)>>, Ba, Bu, _>(self.map(|k| (k, ())).inner, exchange, name)
1059        }
1060    }
1061
1062
1063    impl<'scope, T, K: crate::ExchangeData+Hashable, V: crate::ExchangeData, R: crate::ExchangeData+Semigroup> Collection<'scope, T, (K,V), R>
1064    where
1065        T: Timestamp + Lattice + Ord,
1066    {
1067        /// Arranges a collection of `(Key, Val)` records by `Key`.
1068        ///
1069        /// This operator arranges a stream of values into a shared trace, whose contents it maintains.
1070        /// This trace is current for all times completed by the output stream, which can be used to
1071        /// safely identify the stable times and values in the trace.
1072        pub fn arrange_by_key(self) -> Arranged<'scope, TraceAgent<ValSpine<K, V, T, R>>> {
1073            self.arrange_by_key_named("ArrangeByKey")
1074        }
1075
1076        /// As `arrange_by_key` but with the ability to name the arrangement.
1077        pub fn arrange_by_key_named(self, name: &str) -> Arranged<'scope, TraceAgent<ValSpine<K, V, T, R>>> {
1078            self.arrange_named::<ValBatcher<_,_,_,_>,ValBuilder<_,_,_,_>,_>(name)
1079        }
1080    }
1081
1082    impl<'scope, T, K: crate::ExchangeData+Hashable, R: crate::ExchangeData+Semigroup> Collection<'scope, T, K, R>
1083    where
1084        T: Timestamp + Lattice + Ord,
1085    {
1086        /// Arranges a collection of `Key` records by `Key`.
1087        ///
1088        /// This operator arranges a collection of records into a shared trace, whose contents it maintains.
1089        /// This trace is current for all times complete in the output stream, which can be used to safely
1090        /// identify the stable times and values in the trace.
1091        pub fn arrange_by_self(self) -> Arranged<'scope, TraceAgent<KeySpine<K, T, R>>> {
1092            self.arrange_by_self_named("ArrangeBySelf")
1093        }
1094
1095        /// As `arrange_by_self` but with the ability to name the arrangement.
1096        pub fn arrange_by_self_named(self, name: &str) -> Arranged<'scope, TraceAgent<KeySpine<K, T, R>>> {
1097            self.map(|k| (k, ()))
1098                .arrange_named::<KeyBatcher<_,_,_>,KeyBuilder<_,_,_>,_>(name)
1099        }
1100    }
1101
1102    impl<'scope, T, K, V, R> Collection<'scope, T, (K, V), R>
1103    where
1104        T: Timestamp + Lattice + Ord,
1105        K: crate::ExchangeData+Hashable,
1106        V: crate::ExchangeData,
1107        R: crate::ExchangeData+Semigroup,
1108    {
1109        /// Matches pairs `(key,val1)` and `(key,val2)` based on `key` and yields pairs `(key, (val1, val2))`.
1110        ///
1111        /// The [`join_map`](Join::join_map) method may be more convenient for non-trivial processing pipelines.
1112        ///
1113        /// # Examples
1114        ///
1115        /// ```
1116        /// use differential_dataflow::input::Input;
1117        ///
1118        /// ::timely::example(|scope| {
1119        ///
1120        ///     let x = scope.new_collection_from(vec![(0, 1), (1, 3)]).1;
1121        ///     let y = scope.new_collection_from(vec![(0, 'a'), (1, 'b')]).1;
1122        ///     let z = scope.new_collection_from(vec![(0, (1, 'a')), (1, (3, 'b'))]).1;
1123        ///
1124        ///     x.join(y)
1125        ///      .assert_eq(z);
1126        /// });
1127        /// ```
1128        pub fn join<V2, R2>(self, other: Collection<'scope, T, (K,V2), R2>) -> Collection<'scope, T, (K,(V,V2)), <R as Multiply<R2>>::Output>
1129        where
1130            K:  crate::ExchangeData,
1131            V2: crate::ExchangeData,
1132            R2: crate::ExchangeData+Semigroup,
1133            R: Multiply<R2, Output: Semigroup+'static>,
1134        {
1135            self.join_map(other, |k,v,v2| (k.clone(),(v.clone(),v2.clone())))
1136        }
1137
1138        /// Matches pairs `(key,val1)` and `(key,val2)` based on `key` and then applies a function.
1139        ///
1140        /// # Examples
1141        ///
1142        /// ```
1143        /// use differential_dataflow::input::Input;
1144        ///
1145        /// ::timely::example(|scope| {
1146        ///
1147        ///     let x = scope.new_collection_from(vec![(0, 1), (1, 3)]).1;
1148        ///     let y = scope.new_collection_from(vec![(0, 'a'), (1, 'b')]).1;
1149        ///     let z = scope.new_collection_from(vec![(1, 'a'), (3, 'b')]).1;
1150        ///
1151        ///     x.join_map(y, |_key, &a, &b| (a,b))
1152        ///      .assert_eq(z);
1153        /// });
1154        /// ```
1155        pub fn join_map<V2: crate::ExchangeData, R2: crate::ExchangeData+Semigroup, D: crate::Data, L>(self, other: Collection<'scope, T, (K, V2), R2>, mut logic: L) -> Collection<'scope, T, D, <R as Multiply<R2>>::Output>
1156        where R: Multiply<R2, Output: Semigroup+'static>, L: FnMut(&K, &V, &V2)->D+'static {
1157            let arranged1 = self.arrange_by_key();
1158            let arranged2 = other.arrange_by_key();
1159            arranged1.join_core(arranged2, move |k,v1,v2| Some(logic(k,v1,v2)))
1160        }
1161
1162        /// Matches pairs `(key, val)` and `key` based on `key`, producing the former with frequencies multiplied.
1163        ///
1164        /// When the second collection contains frequencies that are either zero or one this is the more traditional
1165        /// relational semijoin. When the second collection may contain multiplicities, this operation may scale up
1166        /// the counts of the records in the first input.
1167        ///
1168        /// # Examples
1169        ///
1170        /// ```
1171        /// use differential_dataflow::input::Input;
1172        ///
1173        /// ::timely::example(|scope| {
1174        ///
1175        ///     let x = scope.new_collection_from(vec![(0, 1), (1, 3)]).1;
1176        ///     let y = scope.new_collection_from(vec![0, 2]).1;
1177        ///     let z = scope.new_collection_from(vec![(0, 1)]).1;
1178        ///
1179        ///     x.semijoin(y)
1180        ///      .assert_eq(z);
1181        /// });
1182        /// ```
1183        pub fn semijoin<R2: crate::ExchangeData+Semigroup>(self, other: Collection<'scope, T, K, R2>) -> Collection<'scope, T, (K, V), <R as Multiply<R2>>::Output>
1184        where R: Multiply<R2, Output: Semigroup+'static> {
1185            let arranged1 = self.arrange_by_key();
1186            let arranged2 = other.arrange_by_self();
1187            arranged1.join_core(arranged2, |k,v,_| Some((k.clone(), v.clone())))
1188        }
1189
1190        /// Subtracts the semijoin with `other` from `self`.
1191        ///
1192        /// In the case that `other` has multiplicities zero or one this results
1193        /// in a relational antijoin, in which we discard input records whose key
1194        /// is present in `other`. If the multiplicities could be other than zero
1195        /// or one, the semantic interpretation of this operator is less clear.
1196        ///
1197        /// In almost all cases, you should ensure that `other` has multiplicities
1198        /// that are zero or one, perhaps by using the `distinct` operator.
1199        ///
1200        /// # Examples
1201        ///
1202        /// ```
1203        /// use differential_dataflow::input::Input;
1204        ///
1205        /// ::timely::example(|scope| {
1206        ///
1207        ///     let x = scope.new_collection_from(vec![(0, 1), (1, 3)]).1;
1208        ///     let y = scope.new_collection_from(vec![0, 2]).1;
1209        ///     let z = scope.new_collection_from(vec![(1, 3)]).1;
1210        ///
1211        ///     x.antijoin(y)
1212        ///      .assert_eq(z);
1213        /// });
1214        /// ```
1215        pub fn antijoin<R2: crate::ExchangeData+Semigroup>(self, other: Collection<'scope, T, K, R2>) -> Collection<'scope, T, (K, V), R>
1216        where R: Multiply<R2, Output=R>, R: Abelian+'static {
1217            self.clone().concat(self.semijoin(other).negate())
1218        }
1219
1220        /// Joins two arranged collections with the same key type.
1221        ///
1222        /// Each matching pair of records `(key, val1)` and `(key, val2)` are subjected to the `result` function,
1223        /// which produces something implementing `IntoIterator`, where the output collection will have an entry for
1224        /// every value returned by the iterator.
1225        ///
1226        /// # Examples
1227        ///
1228        /// ```
1229        /// use differential_dataflow::input::Input;
1230        /// use differential_dataflow::trace::Trace;
1231        ///
1232        /// ::timely::example(|scope| {
1233        ///
1234        ///     let x = scope.new_collection_from(vec![(0u32, 1), (1, 3)]).1
1235        ///                  .arrange_by_key();
1236        ///     let y = scope.new_collection_from(vec![(0, 'a'), (1, 'b')]).1
1237        ///                  .arrange_by_key();
1238        ///
1239        ///     let z = scope.new_collection_from(vec![(1, 'a'), (3, 'b')]).1;
1240        ///
1241        ///     x.join_core(y, |_key, &a, &b| Some((a, b)))
1242        ///      .assert_eq(z);
1243        /// });
1244        /// ```
1245        pub fn join_core<Tr2,I,L,R2> (self, stream2: Arranged<'scope, Tr2>, result: L) -> Collection<'scope, T,I::Item,<R as Multiply<R2>>::Output>
1246        where
1247            Tr2: crate::trace::TraceReader<Batch: Navigable, Time=T>+Clone+'static,
1248            for<'a> BatchCursor<Tr2>: Cursor<Key<'a>=&'a K>,
1249            // Pin the cursor diff to a named param `R2`: a `Multiply` bound on a projection does not
1250            // connect to its use-site (the solver normalizes the use but not the bound's subject).
1251            BatchCursor<Tr2>: Cursor<Diff = R2, Time = T>,
1252            R: Multiply<R2, Output: Semigroup+'static>,
1253            I: IntoIterator<Item: crate::Data>,
1254            L: FnMut(&K,&V,BatchVal<'_, Tr2>)->I+'static,
1255        {
1256            self.arrange_by_key()
1257                .join_core(stream2, result)
1258        }
1259    }
1260}
1261
1262/// Conversion to a differential dataflow Collection.
1263pub trait AsCollection<'scope, T: Timestamp, C> {
1264    /// Converts the type to a differential dataflow collection.
1265    fn as_collection(self) -> Collection<'scope, T, C>;
1266}
1267
1268impl<'scope, T: Timestamp, C> AsCollection<'scope, T, C> for Stream<'scope, T, C> {
1269    /// Converts the type to a differential dataflow collection.
1270    ///
1271    /// By calling this method, you guarantee that the timestamp invariant (as documented on
1272    /// [Collection]) is upheld. This method will not check it.
1273    fn as_collection(self) -> Collection<'scope, T, C> {
1274        Collection::<T,C>::new(self)
1275    }
1276}
1277
1278/// Concatenates multiple collections.
1279///
1280/// This method has the effect of a sequence of calls to `concat`, but it does
1281/// so in one operator rather than a chain of many operators.
1282///
1283/// # Examples
1284///
1285/// ```
1286/// use differential_dataflow::input::Input;
1287///
1288/// ::timely::example(|scope| {
1289///
1290///     let data = scope.new_collection_from(1 .. 10).1;
1291///
1292///     let odds = data.clone().filter(|x| x % 2 == 1);
1293///     let evens = data.clone().filter(|x| x % 2 == 0);
1294///
1295///     differential_dataflow::collection::concatenate(scope, vec![odds, evens])
1296///         .assert_eq(data);
1297/// });
1298/// ```
1299pub fn concatenate<'scope, T, C, I>(scope: Scope<'scope, T>, iterator: I) -> Collection<'scope, T, C>
1300where
1301    T: Timestamp,
1302    C: Container,
1303    I: IntoIterator<Item=Collection<'scope, T, C>>,
1304{
1305    scope
1306        .concatenate(iterator.into_iter().map(|x| x.inner))
1307        .as_collection()
1308}
1309
1310/// Traits that can be implemented by containers to provide functionality to collections based on them.
1311pub mod containers {
1312
1313    /// A container that can negate its updates.
1314    pub trait Negate {
1315        /// Negates Abelian differences of each update.
1316        fn negate(self) -> Self;
1317    }
1318
1319    /// A container that can enter from timestamp `T1` into timestamp `T2`.
1320    pub trait Enter<T1, T2> {
1321        /// The resulting container type.
1322        type InnerContainer;
1323        /// Update timestamps from `T1` to `T2`.
1324        fn enter(self) -> Self::InnerContainer;
1325    }
1326
1327    /// A container that can leave from timestamp `T1` into timestamp `T2`.
1328    pub trait Leave<T1, T2> {
1329        /// The resulting container type.
1330        type OuterContainer;
1331        /// Update timestamps from `T1` to `T2`.
1332        fn leave(self) -> Self::OuterContainer;
1333    }
1334
1335    /// A container that can advance timestamps by a summary `TS`.
1336    pub trait ResultsIn<TS> {
1337        /// Advance times in the container by `step`.
1338        fn results_in(self, step: &TS) -> Self;
1339    }
1340
1341
1342    /// Implementations of container traits for the `Vec` container.
1343    mod vec {
1344
1345        use timely::progress::{Timestamp, timestamp::Refines};
1346        use crate::collection::Abelian;
1347
1348        use super::{Negate, Enter, Leave, ResultsIn};
1349
1350        impl<D, T, R: Abelian> Negate for Vec<(D, T, R)> {
1351            fn negate(mut self) -> Self {
1352                for (_data, _time, diff) in self.iter_mut() { diff.negate(); }
1353                self
1354            }
1355        }
1356
1357        impl<D, T1: Timestamp, T2: Refines<T1>, R> Enter<T1, T2> for Vec<(D, T1, R)> {
1358            type InnerContainer = Vec<(D, T2, R)>;
1359            fn enter(self) -> Self::InnerContainer {
1360                self.into_iter().map(|(d,t1,r)| (d,T2::to_inner(t1),r)).collect()
1361            }
1362        }
1363
1364        impl<D, T1: Refines<T2>, T2: Timestamp, R> Leave<T1, T2> for Vec<(D, T1, R)> {
1365            type OuterContainer = Vec<(D, T2, R)>;
1366            fn leave(self) -> Self::OuterContainer {
1367                self.into_iter().map(|(d,t1,r)| (d,t1.to_outer(),r)).collect()
1368            }
1369        }
1370
1371        impl<D, T: Timestamp, R> ResultsIn<T::Summary> for Vec<(D, T, R)> {
1372            fn results_in(self, step: &T::Summary) -> Self {
1373                use timely::progress::PathSummary;
1374                self.into_iter().filter_map(move |(d,t,r)| step.results_in(&t).map(|t| (d,t,r))).collect()
1375            }
1376        }
1377    }
1378
1379    /// Implementations of container traits for the `Rc` container.
1380    mod rc {
1381        use std::rc::Rc;
1382
1383        use timely::progress::{Timestamp, timestamp::Refines};
1384
1385        use super::{Negate, Enter, Leave, ResultsIn};
1386
1387        impl<C: Negate+Clone+Default> Negate for Rc<C> {
1388            fn negate(mut self) -> Self {
1389                std::mem::take(Rc::make_mut(&mut self)).negate().into()
1390            }
1391        }
1392
1393        impl<C: Enter<T1, T2>+Clone+Default, T1: Timestamp, T2: Refines<T1>> Enter<T1, T2> for Rc<C> {
1394            type InnerContainer = Rc<C::InnerContainer>;
1395            fn enter(mut self) -> Self::InnerContainer {
1396                std::mem::take(Rc::make_mut(&mut self)).enter().into()
1397            }
1398        }
1399
1400        impl<C: Leave<T1, T2>+Clone+Default, T1: Refines<T2>, T2: Timestamp> Leave<T1, T2> for Rc<C> {
1401            type OuterContainer = Rc<C::OuterContainer>;
1402            fn leave(mut self) -> Self::OuterContainer {
1403                std::mem::take(Rc::make_mut(&mut self)).leave().into()
1404            }
1405        }
1406
1407        impl<C: ResultsIn<TS>+Clone+Default, TS> ResultsIn<TS> for Rc<C> {
1408            fn results_in(mut self, step: &TS) -> Self {
1409                std::mem::take(Rc::make_mut(&mut self)).results_in(step).into()
1410            }
1411        }
1412    }
1413}