malachite_base/unions/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::num::random::{RandomUnsignedRange, random_unsigned_range};
10use crate::random::Seed;
11use crate::unions::Union2;
12
13/// Defines random union generators.
14///
15/// Malachite provides [`random_union2s`], but you can also define `random_union3s`,
16/// `random_union4s`, and so on, in your program using the code below. The documentation for
17/// [`random_union2s`] describes these other functions as well.
18///
19/// See usage examples [here](self#random_union2s).
20///
21/// ```
22/// use malachite_base::num::random::{random_unsigned_range, RandomUnsignedRange};
23/// use malachite_base::random::Seed;
24/// use malachite_base::unions::UnionFromStrError;
25/// use malachite_base::{random_unions, union_struct};
26/// use std::fmt::{self, Display, Formatter};
27/// use std::str::FromStr;
28///
29/// union_struct!(
30/// (pub(crate)),
31/// Union3,
32/// Union3<T, T, T>,
33/// [A, A, 'A', a],
34/// [B, B, 'B', b],
35/// [C, C, 'C', c]
36/// );
37/// union_struct!(
38/// (pub(crate)),
39/// Union4,
40/// Union4<T, T, T, T>,
41/// [A, A, 'A', a],
42/// [B, B, 'B', b],
43/// [C, C, 'C', c],
44/// [D, D, 'D', d]
45/// );
46/// union_struct!(
47/// (pub(crate)),
48/// Union5,
49/// Union5<T, T, T, T, T>,
50/// [A, A, 'A', a],
51/// [B, B, 'B', b],
52/// [C, C, 'C', c],
53/// [D, D, 'D', d],
54/// [E, E, 'E', e]
55/// );
56/// union_struct!(
57/// (pub(crate)),
58/// Union6,
59/// Union6<T, T, T, T, T, T>,
60/// [A, A, 'A', a],
61/// [B, B, 'B', b],
62/// [C, C, 'C', c],
63/// [D, D, 'D', d],
64/// [E, E, 'E', e],
65/// [F, F, 'F', f]
66/// );
67/// union_struct!(
68/// (pub(crate)),
69/// Union7,
70/// Union7<T, T, T, T, T, T, T>,
71/// [A, A, 'A', a],
72/// [B, B, 'B', b],
73/// [C, C, 'C', c],
74/// [D, D, 'D', d],
75/// [E, E, 'E', e],
76/// [F, F, 'F', f],
77/// [G, G, 'G', g]
78/// );
79/// union_struct!(
80/// (pub(crate)),
81/// Union8,
82/// Union8<T, T, T, T, T, T, T, T>,
83/// [A, A, 'A', a],
84/// [B, B, 'B', b],
85/// [C, C, 'C', c],
86/// [D, D, 'D', d],
87/// [E, E, 'E', e],
88/// [F, F, 'F', f],
89/// [G, G, 'G', g],
90/// [H, H, 'H', h]
91/// );
92///
93/// random_unions!(
94/// (pub(crate)),
95/// Union3,
96/// RandomUnion3s,
97/// random_union3s,
98/// 3,
99/// [0, X, I, A, xs, xs_gen],
100/// [1, Y, J, B, ys, ys_gen],
101/// [2, Z, K, C, zs, zs_gen]
102/// );
103/// random_unions!(
104/// (pub(crate)),
105/// Union4,
106/// RandomUnion4s,
107/// random_union4s,
108/// 4,
109/// [0, X, I, A, xs, xs_gen],
110/// [1, Y, J, B, ys, ys_gen],
111/// [2, Z, K, C, zs, zs_gen],
112/// [3, W, L, D, ws, ws_gen]
113/// );
114/// random_unions!(
115/// (pub(crate)),
116/// Union5,
117/// RandomUnion5s,
118/// random_union5s,
119/// 5,
120/// [0, X, I, A, xs, xs_gen],
121/// [1, Y, J, B, ys, ys_gen],
122/// [2, Z, K, C, zs, zs_gen],
123/// [3, W, L, D, ws, ws_gen],
124/// [4, V, M, E, vs, vs_gen]
125/// );
126/// random_unions!(
127/// (pub(crate)),
128/// Union6,
129/// RandomUnion6s,
130/// random_union6s,
131/// 6,
132/// [0, X, I, A, xs, xs_gen],
133/// [1, Y, J, B, ys, ys_gen],
134/// [2, Z, K, C, zs, zs_gen],
135/// [3, W, L, D, ws, ws_gen],
136/// [4, V, M, E, vs, vs_gen],
137/// [5, U, N, F, us, us_gen]
138/// );
139/// random_unions!(
140/// (pub(crate)),
141/// Union7,
142/// RandomUnion7s,
143/// random_union7s,
144/// 7,
145/// [0, X, I, A, xs, xs_gen],
146/// [1, Y, J, B, ys, ys_gen],
147/// [2, Z, K, C, zs, zs_gen],
148/// [3, W, L, D, ws, ws_gen],
149/// [4, V, M, E, vs, vs_gen],
150/// [5, U, N, F, us, us_gen],
151/// [6, T, O, G, ts, ts_gen]
152/// );
153/// random_unions!(
154/// (pub(crate)),
155/// Union8,
156/// RandomUnion8s,
157/// random_union8s,
158/// 8,
159/// [0, X, I, A, xs, xs_gen],
160/// [1, Y, J, B, ys, ys_gen],
161/// [2, Z, K, C, zs, zs_gen],
162/// [3, W, L, D, ws, ws_gen],
163/// [4, V, M, E, vs, vs_gen],
164/// [5, U, N, F, us, us_gen],
165/// [6, T, O, G, ts, ts_gen],
166/// [7, S, P, H, ss, ss_gen]
167/// );
168/// ```
169#[macro_export]
170macro_rules! random_unions {
171 (
172 ($($vis:tt)*),
173 $union: ident,
174 $random_struct: ident,
175 $random_fn: ident,
176 $n: expr,
177 $([$i: expr, $t: ident, $it: ident, $variant: ident, $xs: ident, $xs_gen: ident]),*
178 ) => {
179 /// This documentation applies not only to `RandomUnion2s`, but also to `RandomUnion3s`,
180 /// `RandomUnion4s`, and so on. See [`random_unions`] for more information.
181 ///
182 /// Generates random $n$-unions with elements from $n$ iterators.
183 #[derive(Clone, Debug)]
184 $($vis)* struct $random_struct<$($t, $it: Iterator<Item=$t>),*> {
185 indices: RandomUnsignedRange<usize>,
186 $($xs: $it,)*
187 }
188
189 impl<$($t, $it: Iterator<Item=$t>),*> Iterator for $random_struct<$($t, $it),*> {
190 type Item = $union<$($t),*>;
191
192 fn next(&mut self) -> Option<Self::Item> {
193 match self.indices.next().unwrap() {
194 $($i => self.$xs.next().map($union::$variant),)*
195 _ => unreachable!(),
196 }
197 }
198 }
199
200 /// This documentation applies not only to `random_union2s`, but also to `random_union3s`,
201 /// `random_union4s`, and so on. See [`random_unions`] for more information.
202 ///
203 /// Generates random $n$-unions with elements from $n$ iterators.
204 ///
205 /// The probability of a particular $n$-union being generated is the probability of its
206 /// element divided by $n$.
207 ///
208 /// `xs`, `ys`, `zs`, ... must be infinite.
209 ///
210 /// # Examples
211 /// See [here](self#random_union2s).
212 $($vis)* fn $random_fn<$($t, $it: Iterator<Item=$t>),*>(
213 seed: Seed, $($xs_gen: &dyn Fn(Seed) -> $it),*
214 ) -> $random_struct<$($t, $it),*> {
215 $random_struct {
216 indices: random_unsigned_range(seed.fork("indices"), 0, $n),
217 $($xs: $xs_gen(seed.fork(stringify!($xs))),)*
218 }
219 }
220 }
221}
222random_unions!(
223 (pub),
224 Union2,
225 RandomUnion2s,
226 random_union2s,
227 2,
228 [0, X, I, A, xs, xs_gen],
229 [1, Y, J, B, ys, ys_gen]
230);