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