Skip to main content

malachite_base/tuples/
random.rs

1// Copyright © 2026 Mikhail Hogrefe
2//
3// This file is part of Malachite.
4//
5// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
6// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
7// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
8
9use crate::random::Seed;
10use std::cmp::Ordering::*;
11use std::iter::{Repeat, repeat};
12
13/// Generates random units; repeats `()`.
14///
15/// $P(()) = 1$.
16///
17/// The output length is infinite.
18///
19/// # Expected complexity per iteration
20/// Constant time and additional memory.
21///
22/// # Examples
23/// ```
24/// use itertools::Itertools;
25/// use malachite_base::tuples::random::random_units;
26///
27/// assert_eq!(random_units().take(10).collect_vec(), &[(); 10]);
28/// ```
29#[inline]
30pub fn random_units() -> Repeat<()> {
31    repeat(())
32}
33
34// hack for macro
35#[doc(hidden)]
36#[inline]
37pub fn next_helper<I: Iterator>(x: &mut I, _i: usize) -> Option<I::Item> {
38    x.next()
39}
40
41/// Defines random tuple generators.
42///
43/// Malachite provides [`random_pairs`] and [`random_pairs_from_single`], but you can also define
44/// `random_triples`, `random_quadruples`, and so on, and `random_triples_from_single`,
45/// `random_quadruples_from_single`, and so on, in your program using the code below. The
46/// documentation for [`random_pairs`] and [`random_pairs_from_single`] describes these other
47/// functions as well.
48///
49/// See usage examples [here](self#random_pairs) and [here](self#random_pairs_from_single).
50///
51/// ```
52/// use malachite_base::random::Seed;
53/// use malachite_base::random_tuples;
54/// use malachite_base::tuples::random::next_helper;
55///
56/// random_tuples!(
57///     (pub(crate)),
58///     RandomTriples,
59///     RandomTriplesFromSingle,
60///     random_triples,
61///     random_triples_from_single,
62///     (I::Item, I::Item, I::Item),
63///     [0, X, I, xs, xs_gen],
64///     [1, Y, J, ys, ys_gen],
65///     [2, Z, K, zs, zs_gen]
66/// );
67/// random_tuples!(
68///     (pub(crate)),
69///     RandomQuadruples,
70///     RandomQuadruplesFromSingle,
71///     random_quadruples,
72///     random_quadruples_from_single,
73///     (I::Item, I::Item, I::Item, I::Item),
74///     [0, X, I, xs, xs_gen],
75///     [1, Y, J, ys, ys_gen],
76///     [2, Z, K, zs, zs_gen],
77///     [3, W, L, ws, ws_gen]
78/// );
79/// random_tuples!(
80///     (pub(crate)),
81///     RandomQuintuples,
82///     RandomQuintuplesFromSingle,
83///     random_quintuples,
84///     random_quintuples_from_single,
85///     (I::Item, I::Item, I::Item, I::Item, I::Item),
86///     [0, X, I, xs, xs_gen],
87///     [1, Y, J, ys, ys_gen],
88///     [2, Z, K, zs, zs_gen],
89///     [3, W, L, ws, ws_gen],
90///     [4, V, M, vs, vs_gen]
91/// );
92/// random_tuples!(
93///     (pub(crate)),
94///     RandomSextuples,
95///     RandomSextuplesFromSingle,
96///     random_sextuples,
97///     random_sextuples_from_single,
98///     (I::Item, I::Item, I::Item, I::Item, I::Item, I::Item),
99///     [0, X, I, xs, xs_gen],
100///     [1, Y, J, ys, ys_gen],
101///     [2, Z, K, zs, zs_gen],
102///     [3, W, L, ws, ws_gen],
103///     [4, V, M, vs, vs_gen],
104///     [5, U, N, us, us_gen]
105/// );
106/// random_tuples!(
107///     (pub(crate)),
108///     RandomSeptuples,
109///     RandomSeptuplesFromSingle,
110///     random_septuples,
111///     random_septuples_from_single,
112///     (
113///         I::Item,
114///         I::Item,
115///         I::Item,
116///         I::Item,
117///         I::Item,
118///         I::Item,
119///         I::Item
120///     ),
121///     [0, X, I, xs, xs_gen],
122///     [1, Y, J, ys, ys_gen],
123///     [2, Z, K, zs, zs_gen],
124///     [3, W, L, ws, ws_gen],
125///     [4, V, M, vs, vs_gen],
126///     [5, U, N, us, us_gen],
127///     [6, T, O, ts, ts_gen]
128/// );
129/// random_tuples!(
130///     (pub(crate)),
131///     RandomOctuples,
132///     RandomOctuplesFromSingle,
133///     random_octuples,
134///     random_octuples_from_single,
135///     (
136///         I::Item,
137///         I::Item,
138///         I::Item,
139///         I::Item,
140///         I::Item,
141///         I::Item,
142///         I::Item,
143///         I::Item
144///     ),
145///     [0, X, I, xs, xs_gen],
146///     [1, Y, J, ys, ys_gen],
147///     [2, Z, K, zs, zs_gen],
148///     [3, W, L, ws, ws_gen],
149///     [4, V, M, vs, vs_gen],
150///     [5, U, N, us, us_gen],
151///     [6, T, O, ts, ts_gen],
152///     [7, S, P, ss, ss_gen]
153/// );
154/// ```
155#[macro_export]
156macro_rules! random_tuples {
157    (
158        ($($vis:tt)*),
159        $random_struct: ident,
160        $random_struct_from_single: ident,
161        $random_fn: ident,
162        $random_fn_from_single: ident,
163        $single_out: tt,
164        $([$i: expr, $t: ident, $it: ident, $xs: ident, $xs_gen:ident]),*
165    ) => {
166        /// This documentation applies not only to `RandomPairs`, but also to `RandomTriples`,
167        /// `RandomQuadruples`, and so on. See [`random_tuples`] for more information.
168        ///
169        /// Generates random $n$-tuples using elements from $n$ iterators.
170        #[derive(Clone, Debug)]
171        #[allow(dead_code)]
172        $($vis)* struct $random_struct<$($t: Clone, $it: Iterator<Item = $t>,)*> {
173            $($xs: $it,)*
174        }
175
176        impl<$($t: Clone, $it: Iterator<Item = $t>,)*> Iterator for $random_struct<$($t, $it,)*>
177        {
178            type Item = ($($t,)*);
179
180            #[inline]
181            fn next(&mut self) -> Option<Self::Item> {
182                Some(($(self.$xs.next().unwrap()),*))
183            }
184        }
185
186        /// This documentation applies not only to `random_pairs`, but also to `random_triples`,
187        /// `random_quadruples`, and so on. See [`random_tuples`] for more information.
188        ///
189        /// Generates random $n$-tuples with elements from $n$ iterators.
190        ///
191        /// The probability of a particular $n$-tuple being generated is the product of the
192        /// probabilities of each of its elements.
193        ///
194        /// `xs`, `ys`, `zs`, ... must be infinite.
195        ///
196        /// # Examples
197        /// See [here](self#random_pairs).
198        #[allow(dead_code)]
199        $($vis)* fn $random_fn<$($t: Clone, $it: Iterator<Item = $t>,)*>(
200            seed: Seed,
201            $($xs_gen: &dyn Fn(Seed) -> $it,)*
202        ) -> $random_struct<$($t, $it,)*> {
203            $random_struct {
204                $($xs: $xs_gen(seed.fork(stringify!($xs))),)*
205            }
206        }
207
208        /// This documentation applies not only to `RandomPairsFromSingle`, but also to
209        /// `RandomTriplesFromSingle`, `RandomQuadruplesFromSingle`, and so on. See
210        /// [`random_tuples`] for more information.
211        ///
212        /// Generates random $n$-tuples using elements from a single iterator.
213        #[derive(Clone, Debug)]
214        #[allow(dead_code)]
215        $($vis)* struct $random_struct_from_single<I: Iterator> {
216            xs: I
217        }
218
219        impl<I: Iterator> Iterator for $random_struct_from_single<I> {
220            type Item = $single_out;
221
222            #[inline]
223            fn next(&mut self) -> Option<$single_out> {
224                Some(($(next_helper(&mut self.xs, $i).unwrap(),)*))
225            }
226        }
227
228        /// This documentation applies not only to `random_pairs_from_single`, but also to
229        /// `random_triples_from_single`, `random_quadruples_from_single`, and so on. See
230        /// [`random_tuples`] for more information.
231        ///
232        /// Generates random $n$-tuples using elements from a single iterator.
233        ///
234        /// The probability of a particular $n$-tuple being generated is the product of the
235        /// probabilities of each of its elements.
236        ///
237        /// `xs` must be infinite.
238        ///
239        /// # Examples
240        /// See [here](self#random_pairs_from_single).
241        #[allow(dead_code)]
242        #[inline]
243        $($vis)* const fn $random_fn_from_single<I: Iterator>(xs: I)
244                -> $random_struct_from_single<I> {
245            $random_struct_from_single { xs }
246        }
247    }
248}
249
250random_tuples!(
251    (pub),
252    RandomPairs,
253    RandomPairsFromSingle,
254    random_pairs,
255    random_pairs_from_single,
256    (I::Item, I::Item),
257    [0, X, I, xs, xs_gen],
258    [1, Y, J, ys, ys_gen]
259);
260
261/// Defines custom random tuple generators.
262///
263/// You can define custom tuple generators like `random_triples_xyx` in your program using the code
264/// below.
265///
266/// See usage examples [here](self#random_triples_xyx).
267///
268/// ```
269/// use malachite_base::random::Seed;
270/// use malachite_base::random_custom_tuples;
271///
272/// random_custom_tuples!(
273///     (pub(crate)),
274///     RandomTriplesXXY,
275///     (X, X, Y),
276///     random_triples_xxy,
277///     [X, I, xs, xs_gen, [x_0, x_0], [x_1, x_1]],
278///     [Y, J, ys, ys_gen, [y_2, y_2]]
279/// );
280/// random_custom_tuples!(
281///     (pub(crate)),
282///     RandomTriplesXYX,
283///     (X, Y, X),
284///     random_triples_xyx,
285///     [X, I, xs, xs_gen, [x_0, x_0], [x_2, y_1]],
286///     [Y, J, ys, ys_gen, [y_1, x_2]]
287/// );
288/// random_custom_tuples!(
289///     (pub(crate)),
290///     RandomTriplesXYY,
291///     (X, Y, Y),
292///     random_triples_xyy,
293///     [X, I, xs, xs_gen, [x_0, x_0]],
294///     [Y, J, ys, ys_gen, [y_1, y_1], [y_2, y_2]]
295/// );
296/// random_custom_tuples!(
297///     (pub(crate)),
298///     RandomQuadruplesXXXY,
299///     (X, X, X, Y),
300///     random_quadruples_xxxy,
301///     [X, I, xs, xs_gen, [x_0, x_0], [x_1, x_1], [x_2, x_2]],
302///     [Y, J, ys, ys_gen, [y_3, y_3]]
303/// );
304/// random_custom_tuples!(
305///     (pub(crate)),
306///     RandomQuadruplesXXYX,
307///     (X, X, Y, X),
308///     random_quadruples_xxyx,
309///     [X, I, xs, xs_gen, [x_0, x_0], [x_1, x_1], [x_3, y_2]],
310///     [Y, J, ys, ys_gen, [y_2, x_3]]
311/// );
312/// random_custom_tuples!(
313///     (pub(crate)),
314///     RandomQuadruplesXXYZ,
315///     (X, X, Y, Z),
316///     random_quadruples_xxyz,
317///     [X, I, xs, xs_gen, [x_0, x_0], [x_1, x_1]],
318///     [Y, J, ys, ys_gen, [y_2, y_2]],
319///     [Z, K, zs, zs_gen, [z_3, z_3]]
320/// );
321/// random_custom_tuples!(
322///     (pub(crate)),
323///     RandomQuadruplesXYXZ,
324///     (X, Y, X, Z),
325///     random_quadruples_xyxz,
326///     [X, I, xs, xs_gen, [x_0, x_0], [x_2, y_1]],
327///     [Y, J, ys, ys_gen, [y_1, x_2]],
328///     [Z, K, zs, zs_gen, [z_3, z_3]]
329/// );
330/// random_custom_tuples!(
331///     (pub(crate)),
332///     RandomQuadruplesXYYX,
333///     (X, Y, Y, X),
334///     random_quadruples_xyyx,
335///     [X, I, xs, xs_gen, [x_0, x_0], [x_3, y_1]],
336///     [Y, J, ys, ys_gen, [y_1, y_2], [y_2, x_3]]
337/// );
338/// random_custom_tuples!(
339///     (pub(crate)),
340///     RandomQuadruplesXYYZ,
341///     (X, Y, Y, Z),
342///     random_quadruples_xyyz,
343///     [X, I, xs, xs_gen, [x_0, x_0]],
344///     [Y, J, ys, ys_gen, [y_1, y_1], [y_2, y_2]],
345///     [Z, K, zs, zs_gen, [z_3, z_3]]
346/// );
347/// random_custom_tuples!(
348///     (pub(crate)),
349///     RandomQuadruplesXYZZ,
350///     (X, Y, Z, Z),
351///     random_quadruples_xyzz,
352///     [X, I, xs, xs_gen, [x_0, x_0]],
353///     [Y, J, ys, ys_gen, [y_1, y_1]],
354///     [Z, K, zs, zs_gen, [z_2, z_2], [z_3, z_3]]
355/// );
356/// random_custom_tuples!(
357///     (pub(crate)),
358///     RandomQuintuplesXYYYZ,
359///     (X, Y, Y, Y, Z),
360///     random_quintuples_xyyyz,
361///     [X, I, xs, xs_gen, [x_0, x_0]],
362///     [Y, J, ys, ys_gen, [y_1, y_1], [y_2, y_2], [y_3, y_3]],
363///     [Z, K, zs, zs_gen, [z_4, z_4]]
364/// );
365/// ```
366#[macro_export]
367macro_rules! random_custom_tuples {
368    (
369        ($($vis:tt)*),
370        $random_struct: ident,
371        $out_t: ty,
372        $random_fn: ident,
373        $([$t: ident, $it: ident, $xs: ident, $xs_gen: ident, $([$x: ident, $x_ord: ident]),*]),*
374    ) => {
375        // Generates random $n$-tuples with elements from $m$ iterators, where $m \leq n$.
376        //
377        // The mapping from iterators to tuple slots is indicated by the struct name; for example,
378        // in `RandomTriplesXYX` there are two iterators, `X`, and `Y`; `X` generates the elements
379        // in the first and third slots of the output triples, and `Y` generates the elements in the
380        // second slots.
381        #[derive(Clone, Debug)]
382        $($vis)* struct $random_struct<$($t: Clone, $it: Iterator<Item = $t>,)*> {
383            $($xs: $it,)*
384        }
385
386        impl<$($t: Clone, $it: Iterator<Item = $t>,)*> Iterator for $random_struct<$($t, $it,)*>
387        {
388            type Item = $out_t;
389
390            fn next(&mut self) -> Option<Self::Item> {
391                $(
392                    $(
393                        let $x = self.$xs.next().unwrap();
394                    )*
395                )*
396                Some(($($($x_ord,)*)*))
397            }
398        }
399
400        // Generates random $n$-tuples with elements from $m$ iterators, where $m \leq n$.
401        //
402        // The mapping from iterators to tuple slots is indicated by the function name; for example,
403        // `random_triples_xyx` takes two iterators, `xs`, and `ys`; `xs` generates the elements in
404        // the first and third slots of the output triples, and `ys` generates the elements in the
405        // second slots.
406        //
407        // The probability of a particular $n$-tuple being generated is the product of the
408        // probabilities of each of its elements.
409        //
410        // `xs`, `ys`, `zs`, ... must be infinite.
411        //
412        // # Examples
413        // See [here](self#random_triples_xyx).
414        $($vis)* fn $random_fn<$($t: Clone, $it: Iterator<Item = $t>,)*>(
415            seed: Seed,
416            $($xs_gen: &dyn Fn(Seed) -> $it,)*
417        ) -> $random_struct<$($t, $it,)*> {
418            $random_struct {
419                $($xs: $xs_gen(seed.fork(stringify!($xs))),)*
420            }
421        }
422    }
423}
424
425/// Generates random pairs using elements from a single iterator, where the first element is less
426/// than the second.
427#[derive(Clone, Debug)]
428pub struct RandomOrderedUniquePairs<I: Iterator>
429where
430    I::Item: Ord,
431{
432    xs: I,
433}
434
435impl<I: Iterator> Iterator for RandomOrderedUniquePairs<I>
436where
437    I::Item: Ord,
438{
439    type Item = (I::Item, I::Item);
440
441    #[inline]
442    fn next(&mut self) -> Option<Self::Item> {
443        let mut out_0 = None;
444        let out_1;
445        loop {
446            let x = self.xs.next().unwrap();
447            if out_0.is_none() {
448                out_0 = Some(x);
449            } else {
450                match x.cmp(out_0.as_ref().unwrap()) {
451                    Equal => {}
452                    Greater => {
453                        out_1 = x;
454                        break;
455                    }
456                    Less => {
457                        out_1 = out_0.unwrap();
458                        out_0 = Some(x);
459                        break;
460                    }
461                }
462            }
463        }
464        Some((out_0.unwrap(), out_1))
465    }
466}
467
468/// Generates random pairs using elements from a single iterator, where the first element of each
469/// pair is less than the second.
470///
471/// The input iterator must generate at least two distinct elements; otherwise, this iterator will
472/// hang.
473///
474/// $$
475/// P((x\_0, x\_1)) = 2P(x\_0)P(x\_1).
476/// $$
477///
478/// The above formula assumes that the pair is valid, \emph{i.e.} its first element is less than its
479/// second. The probability of an invalid pair is zero.
480///
481/// `xs` must be infinite.
482///
483/// # Expected complexity per iteration
484/// $T(i) = O(T^\prime(i))$
485///
486/// $M(i) = O(M^\prime(i))$
487///
488/// where $T$ is time, $M$ is additional memory, $i$ is the iteration number, and $T^\prime$ and
489/// $M^\prime$ are the time and memory functions of `xs`: each pair requires an expected constant
490/// number of draws, though duplicate draws force retries, and the iterator hangs if `xs` cannot
491/// produce two distinct values.
492#[inline]
493pub const fn random_ordered_unique_pairs<I: Iterator>(xs: I) -> RandomOrderedUniquePairs<I>
494where
495    I::Item: Ord,
496{
497    RandomOrderedUniquePairs { xs }
498}
499
500/// Defines random ordered unique tuple generators.
501///
502/// Malachite provides [`random_ordered_unique_pairs`], but you can also define
503/// `random_ordered_unique_triples`, `random_ordered_unique_quadruples`, and so on, in your program
504/// using the code below.
505///
506/// See usage examples [here](self#random_ordered_unique_quadruples).
507///
508/// ```
509/// use malachite_base::random_ordered_unique_tuples;
510/// use malachite_base::sets::random::{
511///     random_b_tree_sets_fixed_length, RandomBTreeSetsFixedLength,
512/// };
513///
514/// random_ordered_unique_tuples!(
515///     (pub(crate)),
516///     RandomOrderedUniqueTriples,
517///     3,
518///     (I::Item, I::Item, I::Item),
519///     random_ordered_unique_triples,
520///     [0, 1, 2]
521/// );
522/// random_ordered_unique_tuples!(
523///     (pub(crate)),
524///     RandomOrderedUniqueQuadruples,
525///     4,
526///     (I::Item, I::Item, I::Item, I::Item),
527///     random_ordered_unique_quadruples,
528///     [0, 1, 2, 3]
529/// );
530/// random_ordered_unique_tuples!(
531///     (pub(crate)),
532///     RandomOrderedUniqueQuintuples,
533///     5,
534///     (I::Item, I::Item, I::Item, I::Item, I::Item),
535///     random_ordered_unique_quintuples,
536///     [0, 1, 2, 3, 4]
537/// );
538/// random_ordered_unique_tuples!(
539///     (pub(crate)),
540///     RandomOrderedUniqueSextuples,
541///     6,
542///     (I::Item, I::Item, I::Item, I::Item, I::Item, I::Item),
543///     random_ordered_unique_sextuples,
544///     [0, 1, 2, 3, 4, 5]
545/// );
546/// random_ordered_unique_tuples!(
547///     (pub(crate)),
548///     RandomOrderedUniqueSeptuples,
549///     7,
550///     (
551///         I::Item,
552///         I::Item,
553///         I::Item,
554///         I::Item,
555///         I::Item,
556///         I::Item,
557///         I::Item
558///     ),
559///     random_ordered_unique_septuples,
560///     [0, 1, 2, 3, 4, 5, 6]
561/// );
562/// random_ordered_unique_tuples!(
563///     (pub(crate)),
564///     RandomOrderedUniqueOctuples,
565///     8,
566///     (
567///         I::Item,
568///         I::Item,
569///         I::Item,
570///         I::Item,
571///         I::Item,
572///         I::Item,
573///         I::Item,
574///         I::Item
575///     ),
576///     random_ordered_unique_octuples,
577///     [0, 1, 2, 3, 4, 5, 6, 7]
578/// );
579/// ```
580#[macro_export]
581macro_rules! random_ordered_unique_tuples {
582    (
583        ($($vis:tt)*),
584        $struct: ident,
585        $k: expr,
586        $out_t: ty,
587        $fn: ident,
588        [$($i: expr),*]
589    ) => {
590        // Generates random $n$-tuples using elements from a single iterator, where the tuples have
591        // no repeated elements, and the elements are in ascending order.
592        #[derive(Clone, Debug)]
593        $($vis)* struct $struct<I: Iterator> where I::Item: Ord {
594            xs: RandomBTreeSetsFixedLength<I>,
595        }
596
597        impl<I: Iterator> Iterator for $struct<I> where I::Item: Ord {
598            type Item = $out_t;
599
600            #[inline]
601            fn next(&mut self) -> Option<Self::Item> {
602                let mut elements = self.xs.next().unwrap().into_iter();
603                Some(($(((elements.next().unwrap(), $i).0)),*))
604            }
605        }
606
607        // Generates random $n$-tuples using elements from a single iterator, where the tuples have
608        // no repeated elements, and the elements are in ascending order.
609        //
610        // The input iterator must generate at least `len` distinct elements; otherwise, this
611        // iterator will hang.
612        //
613        // $$
614        // P((x\_i)\_{i=0}^{n-1}) = n!\prod\_{i=0}^{n-1}P(x\_i).
615        // $$
616        //
617        // The above formula assumes that the tuple is valid, \emph{i.e.} its elements are strictly
618        // increasing. The probability of an invalid tuple is zero.
619        //
620        // `xs` must be infinite.
621        //
622        // # Examples
623        // See [here](self#random_ordered_unique_quadruples).
624        #[inline]
625        $($vis)* fn $fn<I: Iterator>(xs: I) -> $struct<I>
626        where
627            I::Item: Ord,
628        {
629            $struct {
630                xs: random_b_tree_sets_fixed_length($k, xs),
631            }
632        }
633    }
634}
635
636/// Generates random pairs using elements from a single iterator, where the first element is not
637/// equal to the second.
638#[derive(Clone, Debug)]
639pub struct RandomUniquePairs<I: Iterator>
640where
641    I::Item: Eq,
642{
643    xs: I,
644}
645
646impl<I: Iterator> Iterator for RandomUniquePairs<I>
647where
648    I::Item: Eq,
649{
650    type Item = (I::Item, I::Item);
651
652    #[inline]
653    fn next(&mut self) -> Option<Self::Item> {
654        let mut out_0 = None;
655        let out_1;
656        loop {
657            let x = self.xs.next().unwrap();
658            if let Some(out_0) = out_0.as_ref() {
659                if x != *out_0 {
660                    out_1 = x;
661                    break;
662                }
663            } else {
664                out_0 = Some(x);
665            }
666        }
667        Some((out_0.unwrap(), out_1))
668    }
669}
670
671/// Generates random pairs using elements from a single iterator, where the two elements of each
672/// pair are unequal.
673///
674/// The input iterator must generate at least two distinct elements; otherwise, this iterator will
675/// hang.
676///
677/// `xs` must be infinite.
678///
679/// # Expected complexity per iteration
680/// $T(i) = O(T^\prime(i))$
681///
682/// $M(i) = O(M^\prime(i))$
683///
684/// where $T$ is time, $M$ is additional memory, $i$ is the iteration number, and $T^\prime$ and
685/// $M^\prime$ are the time and memory functions of `xs`: each pair requires an expected constant
686/// number of draws, though duplicate draws force retries, and the iterator hangs if `xs` cannot
687/// produce two distinct values.
688#[inline]
689pub const fn random_unique_pairs<I: Iterator>(xs: I) -> RandomUniquePairs<I>
690where
691    I::Item: Eq,
692{
693    RandomUniquePairs { xs }
694}
695
696/// Defines random unique tuple generators.
697///
698/// Malachite provides [`random_unique_pairs`], but you can also define `random_unique_triples`,
699/// `random_unique_quadruples`, and so on, in your program using the code below.
700///
701/// See usage examples [here](self#random_unique_quadruples).
702///
703/// ```
704/// use malachite_base::random_unique_tuples;
705/// use std::collections::HashMap;
706/// use std::hash::Hash;
707///
708/// random_unique_tuples!(
709///     (pub(crate)),
710///     RandomOrderedUniqueTriples,
711///     3,
712///     (I::Item, I::Item, I::Item),
713///     random_unique_triples,
714///     [0, 1, 2]
715/// );
716/// random_unique_tuples!(
717///     (pub(crate)),
718///     RandomOrderedUniqueQuadruples,
719///     4,
720///     (I::Item, I::Item, I::Item, I::Item),
721///     random_unique_quadruples,
722///     [0, 1, 2, 3]
723/// );
724/// random_unique_tuples!(
725///     (pub(crate)),
726///     RandomOrderedUniqueQuintuples,
727///     5,
728///     (I::Item, I::Item, I::Item, I::Item, I::Item),
729///     random_unique_quintuples,
730///     [0, 1, 2, 3, 4]
731/// );
732/// random_unique_tuples!(
733///     (pub(crate)),
734///     RandomOrderedUniqueSextuples,
735///     6,
736///     (I::Item, I::Item, I::Item, I::Item, I::Item, I::Item),
737///     random_unique_sextuples,
738///     [0, 1, 2, 3, 4, 5]
739/// );
740/// random_unique_tuples!(
741///     (pub(crate)),
742///     RandomOrderedUniqueSeptuples,
743///     7,
744///     (
745///         I::Item,
746///         I::Item,
747///         I::Item,
748///         I::Item,
749///         I::Item,
750///         I::Item,
751///         I::Item
752///     ),
753///     random_unique_septuples,
754///     [0, 1, 2, 3, 4, 5, 6]
755/// );
756/// random_unique_tuples!(
757///     (pub(crate)),
758///     RandomOrderedUniqueOctuples,
759///     8,
760///     (
761///         I::Item,
762///         I::Item,
763///         I::Item,
764///         I::Item,
765///         I::Item,
766///         I::Item,
767///         I::Item,
768///         I::Item
769///     ),
770///     random_unique_octuples,
771///     [0, 1, 2, 3, 4, 5, 6, 7]
772/// );
773/// ```
774#[macro_export]
775macro_rules! random_unique_tuples {
776    (
777        ($($vis:tt)*),
778        $struct: ident,
779        $k: expr,
780        $out_t: ty,
781        $fn: ident,
782        [$($i: tt),*]
783    ) => {
784        #[derive(Clone, Debug)]
785        $($vis)* struct $struct<I: Iterator> where I::Item: Eq + Hash {
786            xs: I,
787        }
788
789        impl<I: Iterator> Iterator for $struct<I> where I::Item: Eq + Hash {
790            type Item = $out_t;
791
792            #[inline]
793            fn next(&mut self) -> Option<Self::Item> {
794                let mut xs_to_indices = HashMap::with_capacity($k);
795                let mut i = 0;
796                while i < $k {
797                    xs_to_indices
798                        .entry(self.xs.next().unwrap())
799                        .or_insert_with(|| {
800                            i += 1;
801                            i - 1
802                        });
803                }
804                let mut out = ($((None, $i).0),*);
805                for (x, i) in xs_to_indices {
806                    match i {
807                        $($i => {out.$i = Some(x)},)*
808                        _ => {}
809                    }
810                }
811                Some(($(out.$i.unwrap()),*))
812            }
813        }
814
815        #[inline]
816        $($vis)* fn $fn<I: Iterator>(xs: I) -> $struct<I> where I::Item: Eq + Hash,
817        {
818            $struct { xs }
819        }
820    }
821}