malachite_base/num/random/geometric.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::bools::random::{
10 RandomBools, WeightedRandomBools, get_weighted_random_bool, random_bools, weighted_random_bools,
11};
12use crate::num::arithmetic::traits::Gcd;
13use crate::num::basic::integers::PrimitiveInt;
14use crate::num::basic::signeds::PrimitiveSigned;
15use crate::num::basic::unsigneds::PrimitiveUnsigned;
16use crate::num::conversion::traits::ExactInto;
17use crate::random::Seed;
18use std::fmt::Debug;
19
20use super::VariableRangeGenerator;
21
22#[derive(Clone, Copy, Debug, Eq, PartialEq)]
23pub(crate) struct SimpleRational {
24 pub(crate) n: u64,
25 pub(crate) d: u64,
26}
27
28impl SimpleRational {
29 pub(crate) fn new(n: u64, d: u64) -> Self {
30 assert_ne!(d, 0);
31 let gcd = n.gcd(d);
32 Self {
33 n: n / gcd,
34 d: d / gcd,
35 }
36 }
37
38 fn inverse(self) -> Self {
39 assert_ne!(self.n, 0);
40 Self {
41 n: self.d,
42 d: self.n,
43 }
44 }
45
46 // unwrap not const yet
47 #[allow(clippy::missing_const_for_fn)]
48 fn sub_u64(self, x: u64) -> Self {
49 Self {
50 n: self.n.checked_sub(x.checked_mul(self.d).unwrap()).unwrap(),
51 d: self.d,
52 }
53 }
54}
55
56pub(crate) fn mean_to_p_with_min<T: PrimitiveInt>(
57 min: T,
58 um_numerator: u64,
59 um_denominator: u64,
60) -> (u64, u64) {
61 let um = SimpleRational::new(um_numerator, um_denominator);
62 let p = um.sub_u64(ExactInto::<u64>::exact_into(min)).inverse();
63 (p.n, p.d)
64}
65
66/// Generates random unsigned integers from a truncated geometric distribution.
67#[derive(Clone, Debug)]
68pub struct GeometricRandomNaturalValues<T: PrimitiveInt> {
69 xs: WeightedRandomBools,
70 min: T,
71 max: T,
72}
73
74impl<T: PrimitiveInt> Iterator for GeometricRandomNaturalValues<T> {
75 type Item = T;
76
77 fn next(&mut self) -> Option<T> {
78 let mut failures = self.min;
79 loop {
80 if self.xs.next().unwrap() {
81 return Some(failures);
82 }
83 // Wrapping to min is equivalent to restarting this function.
84 if failures == self.max {
85 failures = self.min;
86 } else {
87 failures += T::ONE;
88 }
89 }
90 }
91}
92
93fn geometric_random_natural_values_inclusive_range<T: PrimitiveInt>(
94 seed: Seed,
95 min: T,
96 max: T,
97 um_numerator: u64,
98 um_denominator: u64,
99) -> GeometricRandomNaturalValues<T> {
100 assert!(min <= max);
101 assert_ne!(um_denominator, 0);
102 let (numerator, denominator) = mean_to_p_with_min(min, um_numerator, um_denominator);
103 GeometricRandomNaturalValues {
104 xs: weighted_random_bools(seed, numerator, numerator.checked_add(denominator).unwrap()),
105 min,
106 max,
107 }
108}
109
110fn get_geometric_random_natural_value_from_inclusive_range<T: PrimitiveInt>(
111 range_generator: &mut VariableRangeGenerator,
112 min: T,
113 max: T,
114 um_numerator: u64,
115 um_denominator: u64,
116) -> T {
117 assert!(min <= max);
118 assert_ne!(um_denominator, 0);
119 let (n, denominator) = mean_to_p_with_min(min, um_numerator, um_denominator);
120 let d = n.checked_add(denominator).unwrap();
121 let mut failures = min;
122 loop {
123 if get_weighted_random_bool(range_generator, n, d) {
124 return failures;
125 }
126 // Wrapping to min is equivalent to restarting this function.
127 if failures == max {
128 failures = min;
129 } else {
130 failures += T::ONE;
131 }
132 }
133}
134
135/// Generates random negative signed integers from a modified geometric distribution.
136#[derive(Clone, Debug)]
137pub struct GeometricRandomNegativeSigneds<T: PrimitiveSigned> {
138 xs: WeightedRandomBools,
139 abs_min: T,
140 abs_max: T,
141}
142
143impl<T: PrimitiveSigned> Iterator for GeometricRandomNegativeSigneds<T> {
144 type Item = T;
145
146 fn next(&mut self) -> Option<T> {
147 let mut result = self.abs_min;
148 loop {
149 if self.xs.next().unwrap() {
150 return Some(result);
151 }
152 // Wrapping to min is equivalent to restarting this function.
153 if result == self.abs_max {
154 result = self.abs_min;
155 } else {
156 result -= T::ONE;
157 }
158 }
159 }
160}
161
162fn geometric_random_negative_signeds_inclusive_range<T: PrimitiveSigned>(
163 seed: Seed,
164 abs_min: T,
165 abs_max: T,
166 abs_um_numerator: u64,
167 abs_um_denominator: u64,
168) -> GeometricRandomNegativeSigneds<T> {
169 assert!(abs_min >= abs_max);
170 assert_ne!(abs_um_denominator, 0);
171 let (numerator, denominator) = mean_to_p_with_min(
172 abs_min.checked_neg().unwrap(),
173 abs_um_numerator,
174 abs_um_denominator,
175 );
176 GeometricRandomNegativeSigneds {
177 xs: weighted_random_bools(seed, numerator, numerator.checked_add(denominator).unwrap()),
178 abs_min,
179 abs_max,
180 }
181}
182
183fn get_geometric_random_negative_signed_from_inclusive_range<T: PrimitiveSigned>(
184 range_generator: &mut VariableRangeGenerator,
185 abs_min: T,
186 abs_max: T,
187 abs_um_numerator: u64,
188 abs_um_denominator: u64,
189) -> T {
190 assert!(abs_min >= abs_max);
191 assert_ne!(abs_um_denominator, 0);
192 let (n, denominator) = mean_to_p_with_min(
193 abs_min.checked_neg().unwrap(),
194 abs_um_numerator,
195 abs_um_denominator,
196 );
197 let d = n.checked_add(denominator).unwrap();
198 let mut result = abs_min;
199 loop {
200 if get_weighted_random_bool(range_generator, n, d) {
201 return result;
202 }
203 // Wrapping to min is equivalent to restarting this function.
204 if result == abs_max {
205 result = abs_min;
206 } else {
207 result -= T::ONE;
208 }
209 }
210}
211
212/// Generates random nonzero signed integers from a modified geometric distribution.
213#[derive(Clone, Debug)]
214pub struct GeometricRandomNonzeroSigneds<T: PrimitiveSigned> {
215 bs: RandomBools,
216 xs: WeightedRandomBools,
217 min: T,
218 max: T,
219}
220
221impl<T: PrimitiveSigned> Iterator for GeometricRandomNonzeroSigneds<T> {
222 type Item = T;
223
224 fn next(&mut self) -> Option<T> {
225 loop {
226 if self.bs.next().unwrap() {
227 let mut result = T::ONE;
228 loop {
229 if self.xs.next().unwrap() {
230 return Some(result);
231 } else if result == self.max {
232 break;
233 }
234 result += T::ONE;
235 }
236 } else {
237 let mut result = T::NEGATIVE_ONE;
238 loop {
239 if self.xs.next().unwrap() {
240 return Some(result);
241 } else if result == self.min {
242 break;
243 }
244 result -= T::ONE;
245 }
246 }
247 }
248 }
249}
250
251fn geometric_random_nonzero_signeds_inclusive_range<T: PrimitiveSigned>(
252 seed: Seed,
253 min: T,
254 max: T,
255 abs_um_numerator: u64,
256 abs_um_denominator: u64,
257) -> GeometricRandomNonzeroSigneds<T> {
258 assert!(min <= max);
259 assert_ne!(abs_um_denominator, 0);
260 let (numerator, denominator) = mean_to_p_with_min(T::ONE, abs_um_numerator, abs_um_denominator);
261 GeometricRandomNonzeroSigneds {
262 bs: random_bools(seed.fork("bs")),
263 xs: weighted_random_bools(
264 seed.fork("xs"),
265 numerator,
266 numerator.checked_add(denominator).unwrap(),
267 ),
268 min,
269 max,
270 }
271}
272
273/// Generates random signed integers from a modified geometric distribution.
274#[derive(Clone, Debug)]
275pub struct GeometricRandomSigneds<T: PrimitiveSigned> {
276 bs: RandomBools,
277 xs: WeightedRandomBools,
278 min: T,
279 max: T,
280}
281
282impl<T: PrimitiveSigned> Iterator for GeometricRandomSigneds<T> {
283 type Item = T;
284
285 fn next(&mut self) -> Option<T> {
286 loop {
287 let mut result = T::ZERO;
288 if self.bs.next().unwrap() {
289 loop {
290 if self.xs.next().unwrap() {
291 if result == T::ZERO && self.bs.next().unwrap() {
292 break;
293 }
294 return Some(result);
295 } else if result == self.max {
296 break;
297 }
298 result += T::ONE;
299 }
300 } else {
301 loop {
302 if self.xs.next().unwrap() {
303 if result == T::ZERO && self.bs.next().unwrap() {
304 break;
305 }
306 return Some(result);
307 } else if result == self.min {
308 break;
309 }
310 result -= T::ONE;
311 }
312 }
313 }
314 }
315}
316
317fn geometric_random_signed_inclusive_range_helper<T: PrimitiveSigned>(
318 seed: Seed,
319 min: T,
320 max: T,
321 abs_um_numerator: u64,
322 abs_um_denominator: u64,
323) -> GeometricRandomSigneds<T> {
324 assert!(min <= max);
325 assert_ne!(abs_um_denominator, 0);
326 let (numerator, denominator) =
327 mean_to_p_with_min(T::ZERO, abs_um_numerator, abs_um_denominator);
328 GeometricRandomSigneds {
329 bs: random_bools(seed.fork("bs")),
330 xs: weighted_random_bools(
331 seed.fork("xs"),
332 numerator,
333 numerator.checked_add(denominator).unwrap(),
334 ),
335 min,
336 max,
337 }
338}
339
340fn get_geometric_random_signed_from_inclusive_range_helper<T: PrimitiveSigned>(
341 range_generator: &mut VariableRangeGenerator,
342 min: T,
343 max: T,
344 abs_um_numerator: u64,
345 abs_um_denominator: u64,
346) -> T {
347 assert!(min <= max);
348 assert_ne!(abs_um_denominator, 0);
349 let (n, denominator) = mean_to_p_with_min(T::ZERO, abs_um_numerator, abs_um_denominator);
350 let d = n.checked_add(denominator).unwrap();
351 loop {
352 let mut result = T::ZERO;
353 if range_generator.next_bool() {
354 loop {
355 if get_weighted_random_bool(range_generator, n, d) {
356 if result == T::ZERO && range_generator.next_bool() {
357 break;
358 }
359 return result;
360 } else if result == max {
361 break;
362 }
363 result += T::ONE;
364 }
365 } else {
366 loop {
367 if get_weighted_random_bool(range_generator, n, d) {
368 if result == T::ZERO && range_generator.next_bool() {
369 break;
370 }
371 return result;
372 } else if result == min {
373 break;
374 }
375 result -= T::ONE;
376 }
377 }
378 }
379}
380
381/// Generates random negative signed integers in a range from a modified geometric distribution.
382#[allow(clippy::large_enum_variant)]
383#[derive(Clone, Debug)]
384pub enum GeometricRandomSignedRange<T: PrimitiveSigned> {
385 NonNegative(GeometricRandomNaturalValues<T>),
386 NonPositive(GeometricRandomNegativeSigneds<T>),
387 BothSigns(GeometricRandomSigneds<T>),
388}
389
390impl<T: PrimitiveSigned> Iterator for GeometricRandomSignedRange<T> {
391 type Item = T;
392
393 fn next(&mut self) -> Option<T> {
394 match self {
395 Self::NonNegative(xs) => xs.next(),
396 Self::NonPositive(xs) => xs.next(),
397 Self::BothSigns(xs) => xs.next(),
398 }
399 }
400}
401
402/// Generates random unsigned integers from a truncated geometric distribution.
403///
404/// With this distribution, the probability of a value being generated decreases as the value
405/// increases. The probabilities $P(0), P(1), P(2), \ldots$ decrease in a geometric sequence; that's
406/// where the "geometric" comes from. Unlike a true geometric distribution, this distribution is
407/// truncated, meaning that values above `T::MAX` are never generated.
408///
409/// The probabilities can drop more quickly or more slowly depending on a parameter $m_u$, called
410/// the unadjusted mean. It is equal to `um_numerator / um_denominator`. The unadjusted mean is what
411/// the mean generated value would be if the distribution were not truncated. If $m_u$ is
412/// significantly lower than `T::MAX`, which is usually the case, then it is very close to the
413/// actual mean. The higher $m_u$ is, the more gently the probabilities drop; the lower it is, the
414/// more quickly they drop. $m_u$ must be greater than zero. It may be arbitrarily high, but note
415/// that the iteration time increases linearly with `um_numerator + um_denominator`.
416///
417/// Here is a more precise characterization of this distribution. Let its support $S \subset \Z$
418/// equal $[0, 2^W)$, where $W$ is the width of the type. Then we have
419/// $$
420/// P(n) \neq 0 \leftrightarrow n \in S,
421/// $$
422/// and whenever $n, n + 1 \in S$,
423/// $$
424/// \frac{P(n)}{P(n+1)} = \frac{m_u + 1}{m_u}.
425/// $$
426///
427/// The output length is infinite.
428///
429/// # Expected complexity per iteration
430/// $T(n) = O(n)$
431///
432/// $M(n) = O(1)$
433///
434/// where $T$ is time, $M$ is additional memory, and $n$ is `um_numerator / um_denominator + 1`.
435///
436/// # Panics
437/// Panics if `um_numerator` or `um_denominator` are zero, or, if after being reduced to lowest
438/// terms, their sum is greater than or equal to $2^{64}$.
439///
440/// # Examples
441/// ```
442/// use malachite_base::iterators::prefix_to_string;
443/// use malachite_base::num::random::geometric::geometric_random_unsigneds;
444/// use malachite_base::random::EXAMPLE_SEED;
445///
446/// assert_eq!(
447/// prefix_to_string(geometric_random_unsigneds::<u64>(EXAMPLE_SEED, 1, 1), 10),
448/// "[1, 0, 0, 3, 4, 4, 1, 0, 0, 1, ...]"
449/// )
450/// ```
451///
452/// # Further details
453/// Geometric distributions are more typically parametrized by a parameter $p$. The relationship
454/// between $p$ and $m_u$ is $m_u = \frac{1}{p} - 1$, or $p = \frac{1}{m_u + 1}$.
455///
456/// The probability mass function of this distribution is
457/// $$
458/// P(n) = \\begin{cases}
459/// \frac{(1-p)^np}{1-(1-p)^{2^W}} & \text{if} \\quad 0 \\leq n < 2^W, \\\\
460/// 0 & \\text{otherwise},
461/// \\end{cases}
462/// $$
463/// where $W$ is the width of the type.
464///
465/// It's also useful to note that
466/// $$
467/// \lim_{W \to \infty} P(n) = (1-p)^np.
468/// $$
469pub fn geometric_random_unsigneds<T: PrimitiveUnsigned>(
470 seed: Seed,
471 um_numerator: u64,
472 um_denominator: u64,
473) -> GeometricRandomNaturalValues<T> {
474 assert_ne!(um_numerator, 0);
475 geometric_random_natural_values_inclusive_range(
476 seed,
477 T::ZERO,
478 T::MAX,
479 um_numerator,
480 um_denominator,
481 )
482}
483
484/// Generates random positive unsigned integers from a truncated geometric distribution.
485///
486/// With this distribution, the probability of a value being generated decreases as the value
487/// increases. The probabilities $P(1), P(2), P(3), \ldots$ decrease in a geometric sequence; that's
488/// where the "geometric" comes from. Unlike a true geometric distribution, this distribution is
489/// truncated, meaning that values above `T::MAX` are never generated.
490///
491/// The probabilities can drop more quickly or more slowly depending on a parameter $m_u$, called
492/// the unadjusted mean. It is equal to `um_numerator / um_denominator`. The unadjusted mean is what
493/// the mean generated value would be if the distribution were not truncated. If $m_u$ is
494/// significantly lower than `T::MAX`, which is usually the case, then it is very close to the
495/// actual mean. The higher $m_u$ is, the more gently the probabilities drop; the lower it is, the
496/// more quickly they drop. $m_u$ must be greater than one. It may be arbitrarily high, but note
497/// that the iteration time increases linearly with `um_numerator + um_denominator`.
498///
499/// Here is a more precise characterization of this distribution. Let its support $S \subset \Z$
500/// equal $[1, 2^W)$, where $W$ is the width of the type. Then we have
501/// $$
502/// P(n) \neq 0 \leftrightarrow n \in S
503/// $$
504/// and whenever $n, n + 1 \in S$,
505/// $$
506/// \frac{P(n)}{P(n+1)} = \frac{m_u}{m_u - 1}.
507/// $$
508///
509/// The output length is infinite.
510///
511/// # Expected complexity per iteration
512/// $T(n) = O(n)$
513///
514/// $M(n) = O(1)$
515///
516/// where $T$ is time, $M$ is additional memory, and $n$ is `um_numerator / um_denominator + 1`.
517///
518/// # Panics
519/// Panics if `um_denominator` is zero or if `um_numerator <= um_denominator`.
520///
521/// # Examples
522/// ```
523/// use malachite_base::iterators::prefix_to_string;
524/// use malachite_base::num::random::geometric::geometric_random_positive_unsigneds;
525/// use malachite_base::random::EXAMPLE_SEED;
526///
527/// assert_eq!(
528/// prefix_to_string(
529/// geometric_random_positive_unsigneds::<u64>(EXAMPLE_SEED, 2, 1),
530/// 10
531/// ),
532/// "[2, 1, 1, 4, 5, 5, 2, 1, 1, 2, ...]"
533/// )
534/// ```
535///
536/// # Further details
537/// Geometric distributions are more typically parametrized by a parameter $p$. The relationship
538/// between $p$ and $m_u$ is $m_u = \frac{1}{p}$, or $p = \frac{1}{m_u}$.
539///
540/// The probability mass function of this distribution is
541/// $$
542/// P(n) = \\begin{cases}
543/// \frac{(1-p)^{n-1}p}{1-(1-p)^{2^W-1}} & \text{if} \\quad 0 < n < 2^W, \\\\
544/// 0 & \\text{otherwise},
545/// \\end{cases}
546/// $$
547/// where $W$ is the width of the type.
548///
549/// It's also useful to note that
550/// $$
551/// \lim_{W \to \infty} P(n) = (1-p)^{n-1}p.
552/// $$
553pub fn geometric_random_positive_unsigneds<T: PrimitiveUnsigned>(
554 seed: Seed,
555 um_numerator: u64,
556 um_denominator: u64,
557) -> GeometricRandomNaturalValues<T> {
558 assert!(um_numerator > um_denominator);
559 geometric_random_natural_values_inclusive_range(
560 seed,
561 T::ONE,
562 T::MAX,
563 um_numerator,
564 um_denominator,
565 )
566}
567
568/// Generates random signed integers from a modified geometric distribution.
569///
570/// This distribution can be derived from a truncated geometric distribution by mirroring it,
571/// producing a truncated double geometric distribution. Zero is included.
572///
573/// With this distribution, the probability of a value being generated decreases as its absolute
574/// value increases. The probabilities $P(0), P(\pm 1), P(\pm 2), \ldots$ decrease in a geometric
575/// sequence; that's where the "geometric" comes from. Values below `T::MIN` or above `T::MAX` are
576/// never generated.
577///
578/// The probabilities can drop more quickly or more slowly depending on a parameter $m_u$, called
579/// the unadjusted mean. It is equal to `abs_um_numerator / abs_um_denominator`. The unadjusted mean
580/// is what the mean generated value would be if the distribution were not truncated, and were
581/// restricted to non-negative values. If $m_u$ is significantly lower than `T::MAX`, which is
582/// usually the case, then it is very close to the actual mean of the distribution restricted to
583/// positive values. The higher $m_u$ is, the more gently the probabilities drop; the lower it is,
584/// the more quickly they drop. $m_u$ must be greater than zero. It may be arbitrarily high, but
585/// note that the iteration time increases linearly with `abs_um_numerator + abs_um_denominator`.
586///
587/// Here is a more precise characterization of this distribution. Let its support $S \subset \Z$
588/// equal $[-2^{W-1}, 2^{W-1})$, where $W$ is the width of the type. Then we have
589/// $$
590/// P(n) \neq 0 \leftrightarrow n \in S
591/// $$
592/// Whenever $n \geq 0$ and $n, n + 1 \in S$,
593/// $$
594/// \frac{P(n)}{P(n+1)} = \frac{m_u}{m_u - 1},
595/// $$
596/// and whenever $n \leq 0$ and $n, n - 1 \in S$,
597/// $$
598/// \frac{P(n)}{P(n-1)} = \frac{m_u}{m_u - 1}.
599/// $$
600///
601/// As a corollary, $P(n) = P(-n)$ whenever $n, -n \in S$.
602///
603/// The output length is infinite.
604///
605/// # Expected complexity per iteration
606/// $T(n) = O(n)$
607///
608/// $M(n) = O(1)$
609///
610/// where $T$ is time, $M$ is additional memory, and $n$ is `abs_um_numerator / abs_um_denominator +
611/// 1`.
612///
613/// # Panics
614/// Panics if `abs_um_numerator` or `abs_um_denominator` are zero, or, if after being reduced to
615/// lowest terms, their sum is greater than or equal to $2^{64}$.
616///
617/// # Examples
618/// ```
619/// use malachite_base::iterators::prefix_to_string;
620/// use malachite_base::num::random::geometric::geometric_random_signeds;
621/// use malachite_base::random::EXAMPLE_SEED;
622///
623/// assert_eq!(
624/// prefix_to_string(geometric_random_signeds::<i64>(EXAMPLE_SEED, 1, 1), 10),
625/// "[-1, -1, -1, 1, -2, 1, 0, 0, 0, 0, ...]"
626/// )
627/// ```
628///
629/// Geometric distributions are more typically parametrized by a parameter $p$. The relationship
630/// between $p$ and $m_u$ is $m_u = \frac{1}{p} - 1$, or $p = \frac{1}{m_u + 1}$.
631///
632/// The probability mass function of this distribution is
633/// $$
634/// P(n) = \\begin{cases}
635/// \frac{(1-p)^{|n|}p}{((1-p)^{2^{W-1}}-1)(p-2)} &
636/// \text{if} \\quad -2^{W-1} \leq n < 2^{W-1}, \\\\
637/// 0 & \\text{otherwise},
638/// \\end{cases}
639/// $$
640/// where $W$ is the width of the type.
641///
642/// It's also useful to note that
643/// $$
644/// \lim_{W \to \infty} P(n) = \frac{(1-p)^{|n|}p}{2-p}.
645/// $$
646pub fn geometric_random_signeds<T: PrimitiveSigned>(
647 seed: Seed,
648 abs_um_numerator: u64,
649 abs_um_denominator: u64,
650) -> GeometricRandomSigneds<T> {
651 assert_ne!(abs_um_numerator, 0);
652 geometric_random_signed_inclusive_range_helper(
653 seed,
654 T::MIN,
655 T::MAX,
656 abs_um_numerator,
657 abs_um_denominator,
658 )
659}
660
661/// Generates random natural (non-negative) signed integers from a truncated geometric distribution.
662///
663/// With this distribution, the probability of a value being generated decreases as the value
664/// increases. The probabilities $P(0), P(1), P(2), \ldots$ decrease in a geometric sequence; that's
665/// where the "geometric" comes from. Unlike a true geometric distribution, this distribution is
666/// truncated, meaning that values above `T::MAX` are never generated.
667///
668/// The probabilities can drop more quickly or more slowly depending on a parameter $m_u$, called
669/// the unadjusted mean. It is equal to `um_numerator / um_denominator`. The unadjusted mean is what
670/// the mean generated value would be if the distribution were not truncated. If $m_u$ is
671/// significantly lower than `T::MAX`, which is usually the case, then it is very close to the
672/// actual mean. The higher $m_u$ is, the more gently the probabilities drop; the lower it is, the
673/// more quickly they drop. $m_u$ must be greater than zero. It may be arbitrarily high, but note
674/// that the iteration time increases linearly with `um_numerator + um_denominator`.
675///
676/// Here is a more precise characterization of this distribution. Let its support $S \subset \Z$
677/// equal $[0, 2^{W-1})$, where $W$ is the width of the type. Then we have
678/// $$
679/// P(n) \neq 0 \leftrightarrow n \in S
680/// $$
681/// and whenever $n, n + 1 \in S$,
682/// $$
683/// \frac{P(n)}{P(n+1)} = \frac{m_u + 1}{m_u}.
684/// $$
685///
686/// The output length is infinite.
687///
688/// # Expected complexity per iteration
689/// $T(n) = O(n)$
690///
691/// $M(n) = O(1)$
692///
693/// where $T$ is time, $M$ is additional memory, and $n$ is `um_numerator / um_denominator + 1`.
694///
695/// # Panics
696/// Panics if `um_numerator` or `um_denominator` are zero, or, if after being reduced to lowest
697/// terms, their sum is greater than or equal to $2^{64}$.
698///
699/// # Examples
700/// ```
701/// use malachite_base::iterators::prefix_to_string;
702/// use malachite_base::num::random::geometric::geometric_random_natural_signeds;
703/// use malachite_base::random::EXAMPLE_SEED;
704///
705/// assert_eq!(
706/// prefix_to_string(
707/// geometric_random_natural_signeds::<i64>(EXAMPLE_SEED, 1, 1),
708/// 10
709/// ),
710/// "[1, 0, 0, 3, 4, 4, 1, 0, 0, 1, ...]"
711/// )
712/// ```
713///
714/// # Further details
715/// Geometric distributions are more typically parametrized by a parameter $p$. The relationship
716/// between $p$ and $m_u$ is $m_u = \frac{1}{p} - 1$, or $p = \frac{1}{m_u + 1}$.
717///
718/// The probability mass function of this distribution is
719/// $$
720/// P(n) = \\begin{cases}
721/// \frac{(1-p)^np}{1-(1-p)^{2^{W-1}}} & \text{if} \\quad 0 \\leq n < 2^{W-1}, \\\\
722/// 0 & \\text{otherwise},
723/// \\end{cases}
724/// $$
725/// where $W$ is the width of the type.
726///
727/// It's also useful to note that
728/// $$
729/// \lim_{W \to \infty} P(n) = \\begin{cases}
730/// (1-p)^np & \text{if} \\quad n \geq 0, \\\\
731/// 0 & \\text{otherwise}.
732/// \\end{cases}
733/// $$
734pub fn geometric_random_natural_signeds<T: PrimitiveSigned>(
735 seed: Seed,
736 um_numerator: u64,
737 um_denominator: u64,
738) -> GeometricRandomNaturalValues<T> {
739 assert_ne!(um_numerator, 0);
740 geometric_random_natural_values_inclusive_range(
741 seed,
742 T::ZERO,
743 T::MAX,
744 um_numerator,
745 um_denominator,
746 )
747}
748
749/// Generates random positive signed integers from a truncated geometric distribution.
750///
751/// With this distribution, the probability of a value being generated decreases as the value
752/// increases. The probabilities $P(1), P(2), P(3), \ldots$ decrease in a geometric sequence; that's
753/// where the "geometric" comes from. Unlike a true geometric distribution, this distribution is
754/// truncated, meaning that values above `T::MAX` are never generated.
755///
756/// The probabilities can drop more quickly or more slowly depending on a parameter $m_u$, called
757/// the unadjusted mean. It is equal to `um_numerator / um_denominator`. The unadjusted mean is what
758/// the mean generated value would be if the distribution were not truncated. If $m_u$ is
759/// significantly lower than `T::MAX`, which is usually the case, then it is very close to the
760/// actual mean. The higher $m_u$ is, the more gently the probabilities drop; the lower it is, the
761/// more quickly they drop. $m_u$ must be greater than one. It may be arbitrarily high, but note
762/// that the iteration time increases linearly with `um_numerator + um_denominator`.
763///
764/// Here is a more precise characterization of this distribution. Let its support $S \subset \Z$
765/// equal $[1, 2^{W-1})$, where $W$ is the width of the type. Then we have
766/// $$
767/// P(n) \neq 0 \leftrightarrow n \in S
768/// $$
769///
770/// and whenever $n, n + 1 \in S$,
771/// $$
772/// \frac{P(n)}{P(n+1)} = \frac{m_u}{m_u - 1}.
773/// $$
774///
775/// The output length is infinite.
776///
777/// # Expected complexity per iteration
778/// $T(n) = O(n)$
779///
780/// $M(n) = O(1)$
781///
782/// where $T$ is time, $M$ is additional memory, and $n$ is `um_numerator / um_denominator + 1`.
783///
784/// # Panics
785/// Panics if `um_denominator` is zero or if `um_numerator <= um_denominator`.
786///
787/// # Examples
788/// ```
789/// use malachite_base::iterators::prefix_to_string;
790/// use malachite_base::num::random::geometric::geometric_random_positive_signeds;
791/// use malachite_base::random::EXAMPLE_SEED;
792///
793/// assert_eq!(
794/// prefix_to_string(
795/// geometric_random_positive_signeds::<i64>(EXAMPLE_SEED, 2, 1),
796/// 10
797/// ),
798/// "[2, 1, 1, 4, 5, 5, 2, 1, 1, 2, ...]"
799/// )
800/// ```
801///
802/// # Further details
803/// Geometric distributions are more typically parametrized by a parameter $p$. The relationship
804/// between $p$ and $m_u$ is $m_u = \frac{1}{p}$, or $p = \frac{1}{m_u}$.
805///
806/// The probability mass function of this distribution is
807/// $$
808/// P(n) = \\begin{cases}
809/// \frac{(1-p)^{n-1}p}{1-(1-p)^{2^{W-1}-1}} & \text{if} \\quad 0 < n < 2^{W-1}, \\\\
810/// 0 & \\text{otherwise},
811/// \\end{cases}
812/// $$
813/// where $W$ is the width of the type.
814///
815/// It's also useful to note that
816/// $$
817/// \lim_{W \to \infty} P(n) = \\begin{cases}
818/// (1-p)^{n-1}p & \text{if} \\quad n > 0, \\\\
819/// 0 & \\text{otherwise}.
820/// \\end{cases}
821/// $$
822#[inline]
823pub fn geometric_random_positive_signeds<T: PrimitiveSigned>(
824 seed: Seed,
825 um_numerator: u64,
826 um_denominator: u64,
827) -> GeometricRandomNaturalValues<T> {
828 geometric_random_natural_values_inclusive_range(
829 seed,
830 T::ONE,
831 T::MAX,
832 um_numerator,
833 um_denominator,
834 )
835}
836
837/// Generates random negative signed integers from a modified geometric distribution.
838///
839/// This distribution can be derived from a truncated geometric distribution by negating its domain.
840/// The distribution is truncated at `T::MIN`.
841///
842/// With this distribution, the probability of a value being generated decreases as its absolute
843/// value increases. The probabilities $P(-1), P(-2), P(-3), \ldots$ decrease in a geometric
844/// sequence; that's where the "geometric" comes from. Values below `T::MIN` are never generated.
845///
846/// The probabilities can drop more quickly or more slowly depending on a parameter $m_u$, called
847/// the unadjusted mean. It is equal to `abs_um_numerator / abs_um_denominator`. The unadjusted mean
848/// is what the mean of the absolute values of the generated values would be if the distribution
849/// were not truncated. If $m_u$ is significantly lower than `-T::MIN`, which is usually the case,
850/// then it is very close to the actual mean of the absolute values. The higher $m_u$ is, the more
851/// gently the probabilities drop; the lower it is, the more quickly they drop. $m_u$ must be
852/// greater than one. It may be arbitrarily high, but note that the iteration time increases
853/// linearly with `abs_um_numerator + abs_um_denominator`.
854///
855/// Here is a more precise characterization of this distribution. Let its support $S \subset \Z$
856/// equal $[-2^{W-1}, 0)$, where $W$ is the width of the type. Then we have
857/// $$
858/// P(n) \neq 0 \leftrightarrow n \in S
859/// $$
860///
861/// and whenever $n, n - 1 \in S$,
862/// $$
863/// \frac{P(n)}{P(n-1)} = \frac{m_u}{m_u - 1}.
864/// $$
865///
866/// The output length is infinite.
867///
868/// # Expected complexity per iteration
869/// $T(n) = O(n)$
870///
871/// $M(n) = O(1)$
872///
873/// where $T$ is time, $M$ is additional memory, and $n$ is `abs_um_numerator / abs_um_denominator +
874/// 1`.
875///
876/// # Panics
877/// Panics if `abs_um_denominator` is zero or if `abs_um_numerator <= abs_um_denominator`.
878///
879/// # Examples
880/// ```
881/// use malachite_base::iterators::prefix_to_string;
882/// use malachite_base::num::random::geometric::geometric_random_negative_signeds;
883/// use malachite_base::random::EXAMPLE_SEED;
884///
885/// assert_eq!(
886/// prefix_to_string(
887/// geometric_random_negative_signeds::<i64>(EXAMPLE_SEED, 2, 1),
888/// 10
889/// ),
890/// "[-2, -1, -1, -4, -5, -5, -2, -1, -1, -2, ...]"
891/// )
892/// ```
893///
894/// # Further details
895/// Geometric distributions are more typically parametrized by a parameter $p$. The relationship
896/// between $p$ and $m_u$ is $m_u = \frac{1}{p}$, or $p = \frac{1}{m_u}$.
897///
898/// The probability mass function of this distribution is
899/// $$
900/// P(n) = \\begin{cases}
901/// \frac{(1-p)^{-n-1}p}{1-(1-p)^{2^{W-1}}} & \text{if} \\quad -2^{W-1} \leq n < 0, \\\\
902/// 0 & \\text{otherwise},
903/// \\end{cases}
904/// $$
905/// where $W$ is the width of the type.
906///
907/// It's also useful to note that
908/// $$
909/// \lim_{W \to \infty} P(n) = \\begin{cases}
910/// (1-p)^{-n-1}p & \text{if} \\quad n < 0, \\\\
911/// 0 & \\text{otherwise}.
912/// \\end{cases}
913/// $$
914pub fn geometric_random_negative_signeds<T: PrimitiveSigned>(
915 seed: Seed,
916 abs_um_numerator: u64,
917 abs_um_denominator: u64,
918) -> GeometricRandomNegativeSigneds<T> {
919 assert!(abs_um_numerator > abs_um_denominator);
920 geometric_random_negative_signeds_inclusive_range(
921 seed,
922 T::NEGATIVE_ONE,
923 T::MIN,
924 abs_um_numerator,
925 abs_um_denominator,
926 )
927}
928
929/// Generates random nonzero signed integers from a modified geometric distribution.
930///
931/// This distribution can be derived from a truncated geometric distribution by mirroring it,
932/// producing a truncated double geometric distribution. Zero is excluded.
933///
934/// With this distribution, the probability of a value being generated decreases as its absolute
935/// value increases. The probabilities $P(\pm 1), P(\pm 2), P(\pm 3), \ldots$ decrease in a
936/// geometric sequence; that's where the "geometric" comes from. Values below `T::MIN` or above
937/// `T::MAX` are never generated.
938///
939/// The probabilities can drop more quickly or more slowly depending on a parameter $m_u$, called
940/// the unadjusted mean. It is equal to `abs_um_numerator / abs_um_denominator`. The unadjusted mean
941/// is what the mean of the absolute values of the generated values would be if the distribution
942/// were not truncated. If $m_u$ is significantly lower than `T::MAX`, which is usually the case,
943/// then it is very close to the actual mean of the absolute values. The higher $m_u$ is, the more
944/// gently the probabilities drop; the lower it is, the more quickly they drop. $m_u$ must be
945/// greater than one. It may be arbitrarily high, but note that the iteration time increases
946/// linearly with `abs_um_numerator + abs_um_denominator`.
947///
948/// Here is a more precise characterization of this distribution. Let its support $S \subset \Z$
949/// equal $[-2^{W-1}, 2^{W-1}) \setminus \\{0\\}$, where $W$ is the width of the type. Then we have
950/// $$
951/// P(n) \neq 0 \leftrightarrow n \in S
952/// $$
953/// $$
954/// P(1) = P(-1)
955/// $$
956/// Whenever $n > 0$ and $n, n + 1 \in S$,
957/// $$
958/// \frac{P(n)}{P(n+1)} = \frac{m_u}{m_u - 1},
959/// $$
960/// and whenever $n < 0$ and $n, n - 1 \in S$,
961/// $$
962/// \frac{P(n)}{P(n-1)} = \frac{m_u}{m_u - 1}.
963/// $$
964///
965/// As a corollary, $P(n) = P(-n)$ whenever $n, -n \in S$.
966///
967/// The output length is infinite.
968///
969/// # Expected complexity per iteration
970/// $T(n) = O(n)$
971///
972/// $M(n) = O(1)$
973///
974/// where $T$ is time, $M$ is additional memory, and $n$ is `abs_um_numerator / abs_um_denominator +
975/// 1`.
976///
977/// # Panics
978/// Panics if `abs_um_denominator` is zero or if `abs_um_numerator <= abs_um_denominator`.
979///
980/// # Examples
981/// ```
982/// use malachite_base::iterators::prefix_to_string;
983/// use malachite_base::num::random::geometric::geometric_random_nonzero_signeds;
984/// use malachite_base::random::EXAMPLE_SEED;
985///
986/// assert_eq!(
987/// prefix_to_string(
988/// geometric_random_nonzero_signeds::<i64>(EXAMPLE_SEED, 2, 1),
989/// 10
990/// ),
991/// "[-2, -2, -2, 2, -3, 2, -1, -1, -1, 1, ...]"
992/// )
993/// ```
994///
995/// # Further details
996/// Geometric distributions are more typically parametrized by a parameter $p$. The relationship
997/// between $p$ and $m_u$ is $m_u = \frac{1}{p}$, or $p = \frac{1}{m_u}$.
998///
999/// The probability mass function of this distribution is
1000/// $$
1001/// P(n) = \\begin{cases}
1002/// \frac{(1-p)^{|n|}p}{(1-p)^{2^{W-1}}(p-2)-2p+2} &
1003/// \text{if} \\quad -2^{W-1} \leq n < 0 \\ \mathrm{or} \\ 0 < n < -2^{W-1}, \\\\
1004/// 0 & \\text{otherwise},
1005/// \\end{cases}
1006/// $$
1007/// where $W$ is the width of the type.
1008///
1009/// It's also useful to note that
1010/// $$
1011/// \lim_{W \to \infty} P(n) = \\begin{cases}
1012/// \frac{(1-p)^{|n|}p}{2-2p} & \text{if} \\quad n \neq 0, \\\\
1013/// 0 & \\text{otherwise}.
1014/// \\end{cases}
1015/// $$
1016pub fn geometric_random_nonzero_signeds<T: PrimitiveSigned>(
1017 seed: Seed,
1018 abs_um_numerator: u64,
1019 abs_um_denominator: u64,
1020) -> GeometricRandomNonzeroSigneds<T> {
1021 assert!(abs_um_numerator > abs_um_denominator);
1022 geometric_random_nonzero_signeds_inclusive_range(
1023 seed,
1024 T::MIN,
1025 T::MAX,
1026 abs_um_numerator,
1027 abs_um_denominator,
1028 )
1029}
1030
1031/// Generates random unsigned integers from a truncated geometric distribution over the half-open
1032/// interval $[a, b)$.
1033///
1034/// With this distribution, the probability of a value being generated decreases as the value
1035/// increases. The probabilities $P(a), P(a + 1), P(a + 2), \ldots$ decrease in a geometric
1036/// sequence; that's where the "geometric" comes from. Unlike a true geometric distribution, this
1037/// distribution is truncated, meaning that values above $b$ are never generated.
1038///
1039/// The probabilities can drop more quickly or more slowly depending on a parameter $m_u$, called
1040/// the unadjusted mean. It is equal to `um_numerator / um_denominator`. The unadjusted mean is what
1041/// the mean generated value would be if the distribution were not truncated. If $m_u$ is
1042/// significantly lower than $b$, then it is very close to the actual mean. The higher $m_u$ is, the
1043/// more gently the probabilities drop; the lower it is, the more quickly they drop. $m_u$ must be
1044/// greater than $a$. It may be arbitrarily high, but note that the iteration time increases
1045/// linearly with `um_numerator + um_denominator`.
1046///
1047/// Here is a more precise characterization of this distribution. Let its support $S \subset \Z$
1048/// equal $[a, b)$. Then we have
1049/// $$
1050/// P(n) \neq 0 \leftrightarrow n \in S
1051/// $$
1052///
1053/// and whenever $n, n + 1 \in S$,
1054/// $$
1055/// \frac{P(n)}{P(n+1)} = \frac{m_u + 1}{m_u}.
1056/// $$
1057///
1058/// The output length is infinite.
1059///
1060/// # Expected complexity per iteration
1061/// $T(n) = O(n)$
1062///
1063/// $M(n) = O(1)$
1064///
1065/// where $T$ is time, $M$ is additional memory, and $n$ is `um_numerator / um_denominator + 1`.
1066///
1067/// # Panics
1068/// Panics if $a \geq b$, if `um_numerator` or `um_denominator` are zero, if their ratio is less
1069/// than or equal to $a$, or if they are too large and manipulating them leads to arithmetic
1070/// overflow.
1071///
1072/// # Examples
1073/// ```
1074/// use malachite_base::iterators::prefix_to_string;
1075/// use malachite_base::num::random::geometric::geometric_random_unsigned_range;
1076/// use malachite_base::random::EXAMPLE_SEED;
1077///
1078/// assert_eq!(
1079/// prefix_to_string(
1080/// geometric_random_unsigned_range::<u16>(EXAMPLE_SEED, 1, 7, 3, 1),
1081/// 10
1082/// ),
1083/// "[2, 5, 2, 3, 4, 2, 5, 6, 1, 2, ...]"
1084/// )
1085/// ```
1086///
1087/// # Further details
1088/// Geometric distributions are more typically parametrized by a parameter $p$. The relationship
1089/// between $p$ and $m_u$ is $m_u = \frac{1}{p} + a - 1$, or $p = \frac{1}{m_u - a + 1}$.
1090///
1091/// The probability mass function of this distribution is
1092/// $$
1093/// P(n) = \\begin{cases}
1094/// \frac{(1-p)^np}{(1-p)^a-(1-p)^b} & \text{if} \\quad a \\leq n < b, \\\\
1095/// 0 & \\text{otherwise}.
1096/// \\end{cases}
1097/// $$
1098#[inline]
1099pub fn geometric_random_unsigned_range<T: PrimitiveUnsigned>(
1100 seed: Seed,
1101 a: T,
1102 b: T,
1103 um_numerator: u64,
1104 um_denominator: u64,
1105) -> GeometricRandomNaturalValues<T> {
1106 assert!(a < b, "a must be less than b. a: {a}, b: {b}");
1107 geometric_random_natural_values_inclusive_range(
1108 seed,
1109 a,
1110 b - T::ONE,
1111 um_numerator,
1112 um_denominator,
1113 )
1114}
1115
1116/// Generates random unsigned integers from a truncated geometric distribution over the closed
1117/// interval $[a, b]$.
1118///
1119/// With this distribution, the probability of a value being generated decreases as the value
1120/// increases. The probabilities $P(a), P(a + 1), P(a + 2), \ldots$ decrease in a geometric
1121/// sequence; that's where the "geometric" comes from. Unlike a true geometric distribution, this
1122/// distribution is truncated, meaning that values above $b$ are never generated.
1123///
1124/// The probabilities can drop more quickly or more slowly depending on a parameter $m_u$, called
1125/// the unadjusted mean. It is equal to `um_numerator / um_denominator`. The unadjusted mean is what
1126/// the mean generated value would be if the distribution were not truncated. If $m_u$ is
1127/// significantly lower than $b$, then it is very close to the actual mean. The higher $m_u$ is, the
1128/// more gently the probabilities drop; the lower it is, the more quickly they drop. $m_u$ must be
1129/// greater than $a$. It may be arbitrarily high, but note that the iteration time increases
1130/// linearly with `um_numerator + um_denominator`.
1131///
1132/// Here is a more precise characterization of this distribution. Let its support $S \subset \Z$
1133/// equal $[a, b]$. Then we have
1134/// $$
1135/// P(n) \neq 0 \leftrightarrow n \in S
1136/// $$
1137///
1138/// and whenever $n, n + 1 \in S$,
1139/// $$
1140/// \frac{P(n)}{P(n+1)} = \frac{m_u + 1}{m_u}.
1141/// $$
1142///
1143/// The output length is infinite.
1144///
1145/// # Expected complexity per iteration
1146/// $T(n) = O(n)$
1147///
1148/// $M(n) = O(1)$
1149///
1150/// where $T$ is time, $M$ is additional memory, and $n$ is `um_numerator / um_denominator + 1`.
1151///
1152/// # Panics
1153/// Panics if $a > b$, if `um_numerator` or `um_denominator` are zero, if their ratio is less than
1154/// or equal to $a$, or if they are too large and manipulating them leads to arithmetic overflow.
1155///
1156/// # Examples
1157/// ```
1158/// use malachite_base::iterators::prefix_to_string;
1159/// use malachite_base::num::random::geometric::geometric_random_unsigned_inclusive_range;
1160/// use malachite_base::random::EXAMPLE_SEED;
1161///
1162/// assert_eq!(
1163/// prefix_to_string(
1164/// geometric_random_unsigned_inclusive_range::<u16>(EXAMPLE_SEED, 1, 6, 3, 1),
1165/// 10
1166/// ),
1167/// "[2, 5, 2, 3, 4, 2, 5, 6, 1, 2, ...]"
1168/// )
1169/// ```
1170///
1171/// # Further details
1172/// Geometric distributions are more typically parametrized by a parameter $p$. The relationship
1173/// between $p$ and $m_u$ is $m_u = \frac{1}{p} + a - 1$, or $p = \frac{1}{m_u - a + 1}$.
1174///
1175/// The probability mass function of this distribution is
1176/// $$
1177/// P(n) = \\begin{cases}
1178/// \frac{(1-p)^np}{(1-p)^a-(1-p)^{b+1}} & \text{if} \\quad a \\leq n \\leq b, \\\\
1179/// 0 & \\text{otherwise}.
1180/// \\end{cases}
1181/// $$
1182#[inline]
1183pub fn geometric_random_unsigned_inclusive_range<T: PrimitiveUnsigned>(
1184 seed: Seed,
1185 a: T,
1186 b: T,
1187 um_numerator: u64,
1188 um_denominator: u64,
1189) -> GeometricRandomNaturalValues<T> {
1190 assert!(a <= b, "a must be less than or equal to b. a: {a}, b: {b}");
1191 geometric_random_natural_values_inclusive_range(seed, a, b, um_numerator, um_denominator)
1192}
1193
1194/// Generates random signed integers from a modified geometric distribution over the half-open
1195/// interval $[a, b)$.
1196///
1197/// With this distribution, the probability of a value being generated decreases as its absolute
1198/// value increases. The probabilities $P(n), P(n + \operatorname{sgn}(n)), P(n +
1199/// 2\operatorname{sgn}(n)), \ldots$, where $n, n + \operatorname{sgn}(n), n +
1200/// 2\operatorname{sgn}(n), \ldots \in [a, b) \\setminus \\{0\\}$, decrease in a geometric sequence;
1201/// that's where the "geometric" comes from.
1202///
1203/// The form of the distribution depends on the range. If $a \geq 0$, the distribution is highest at
1204/// $a$ and is truncated at $b$. If $b \leq 1$, the distribution is reflected: it is highest at $b -
1205/// 1$ and is truncated at $a$. Otherwise, the interval includes both positive and negative values.
1206/// In that case the distribution is doubled: it is highest at zero and is truncated at $a$ and $b$.
1207///
1208/// The probabilities can drop more quickly or more slowly depending on a parameter $m_u$, called
1209/// the unadjusted mean. It is equal to `abs_um_numerator / abs_um_denominator`. The unadjusted mean
1210/// is what the mean of the absolute values of the generated values would be if the distribution
1211/// were not truncated. If $m_u$ is significantly lower than $b$, then it is very close to the
1212/// actual mean of the absolute values. The higher $m_u$ is, the more gently the probabilities drop;
1213/// the lower it is, the more quickly they drop. $m_u$ must be greater than $a$. It may be
1214/// arbitrarily high, but note that the iteration time increases linearly with `abs_um_numerator +
1215/// abs_um_denominator`.
1216///
1217/// Here is a more precise characterization of this distribution. Let its support $S \subset \Z$
1218/// equal $[a, b)$. Let $c = \min_{n\in S}|n|$. Geometric distributions are typically parametrized
1219/// by a parameter $p$. The relationship between $p$ and $m_u$ is $m_u = \frac{1}{p} + c - 1$, or $p
1220/// = \frac{1}{m_u - c + 1}$. Then we have
1221/// $$
1222/// P(n) \neq 0 \leftrightarrow n \in S
1223/// $$
1224/// If $0, 1 \in S$, then
1225/// $$
1226/// \frac{P(0)}{P(1)} = \frac{m_u + 1}{m_u}.
1227/// $$
1228/// If $-1, 0 \in S$, then
1229/// $$
1230/// \frac{P(0)}{P(-1)} = \frac{m_u + 1}{m_u}.
1231/// $$
1232/// and whenever $n, n + \operatorname{sgn}(n) \in S \setminus \\{0\\}$,
1233/// $$
1234/// \frac{P(n)}{P(n+\operatorname{sgn}(n))} = \frac{m_u + 1}{m_u}.
1235/// $$
1236///
1237/// As a corollary, $P(n) = P(-n)$ whenever $n, -n \in S$.
1238///
1239/// The output length is infinite.
1240///
1241/// # Expected complexity per iteration
1242/// $T(n) = O(n)$
1243///
1244/// $M(n) = O(1)$
1245///
1246/// where $T$ is time, $M$ is additional memory, and $n$ is `um_numerator / um_denominator + 1`.
1247///
1248/// # Panics
1249/// Panics if $a \geq b$, if `um_numerator` or `um_denominator` are zero, if their ratio is less
1250/// than or equal to $a$, or if they are too large and manipulating them leads to arithmetic
1251/// overflow.
1252///
1253/// # Examples
1254/// ```
1255/// use malachite_base::iterators::prefix_to_string;
1256/// use malachite_base::num::random::geometric::geometric_random_signed_range;
1257/// use malachite_base::random::EXAMPLE_SEED;
1258///
1259/// assert_eq!(
1260/// prefix_to_string(
1261/// geometric_random_signed_range::<i8>(EXAMPLE_SEED, -100, 100, 30, 1),
1262/// 10
1263/// ),
1264/// "[-32, -31, -88, 52, -40, 64, -36, -1, -7, 46, ...]"
1265/// )
1266/// ```
1267///
1268/// # Further details
1269/// The probability mass function of this distribution is
1270/// $$
1271/// P(n) = \\begin{cases}
1272/// \frac{(1-p)^np}{(1-p)^a-(1-p)^b} & \text{if} \\quad 0 \\leq a \\leq n < b, \\\\
1273/// \frac{(1-p)^{-n}p}{(1-p)^{1-b}-(1-p)^{1-a}} & \text{if} \\quad a \\leq n < b \\leq 1, \\\\
1274/// \frac{(1-p)^{|n|}p}{2-p-(1-p)^{1-a}-(1-p)^b} &
1275/// \text{if} \\quad a < 0 < 1 < b \\ \mathrm{and} \\ a \\leq n < b, \\\\
1276/// 0 & \\text{otherwise}.
1277/// \\end{cases}
1278/// $$
1279#[inline]
1280pub fn geometric_random_signed_range<T: PrimitiveSigned>(
1281 seed: Seed,
1282 a: T,
1283 b: T,
1284 abs_um_numerator: u64,
1285 abs_um_denominator: u64,
1286) -> GeometricRandomSignedRange<T> {
1287 assert!(a < b, "a must be less than b. a: {a}, b: {b}");
1288 if a >= T::ZERO {
1289 GeometricRandomSignedRange::NonNegative(geometric_random_natural_values_inclusive_range(
1290 seed,
1291 a,
1292 b - T::ONE,
1293 abs_um_numerator,
1294 abs_um_denominator,
1295 ))
1296 } else if b <= T::ONE {
1297 GeometricRandomSignedRange::NonPositive(geometric_random_negative_signeds_inclusive_range(
1298 seed,
1299 b - T::ONE,
1300 a,
1301 abs_um_numerator,
1302 abs_um_denominator,
1303 ))
1304 } else {
1305 GeometricRandomSignedRange::BothSigns(geometric_random_signed_inclusive_range_helper(
1306 seed,
1307 a,
1308 b - T::ONE,
1309 abs_um_numerator,
1310 abs_um_denominator,
1311 ))
1312 }
1313}
1314
1315/// Generates random signed integers from a modified geometric distribution over the closed interval
1316/// $[a, b]$.
1317///
1318/// With this distribution, the probability of a value being generated decreases as its absolute
1319/// value increases. The probabilities $P(n), P(n + \operatorname{sgn}(n)), P(n +
1320/// 2\operatorname{sgn}(n)), \ldots$, where $n, n + \operatorname{sgn}(n), n +
1321/// 2\operatorname{sgn}(n), \ldots \in [a, b] \\setminus \\{0\\}$, decrease in a geometric sequence;
1322/// that's where the "geometric" comes from.
1323///
1324/// The form of the distribution depends on the range. If $a \geq 0$, the distribution is highest at
1325/// $a$ and is truncated at $b$. If $b \leq 0$, the distribution is reflected: it is highest at $b$
1326/// and is truncated at $a$. Otherwise, the interval includes both positive and negative values. In
1327/// that case the distribution is doubled: it is highest at zero and is truncated at $a$ and $b$.
1328///
1329/// The probabilities can drop more quickly or more slowly depending on a parameter $m_u$, called
1330/// the unadjusted mean. It is equal to `abs_um_numerator / abs_um_denominator`. The unadjusted mean
1331/// is what the mean of the absolute values of the generated values would be if the distribution
1332/// were not truncated. If $m_u$ is significantly lower than $b$, then it is very close to the
1333/// actual mean of the absolute values. The higher $m_u$ is, the more gently the probabilities drop;
1334/// the lower it is, the more quickly they drop. $m_u$ must be greater than $a$. It may be
1335/// arbitrarily high, but note that the iteration time increases linearly with `abs_um_numerator +
1336/// abs_um_denominator`.
1337///
1338/// Here is a more precise characterization of this distribution. Let its support $S \subset \Z$
1339/// equal $[a, b]$. Let $c = \min_{n\in S}|n|$. Geometric distributions are typically parametrized
1340/// by a parameter $p$. The relationship between $p$ and $m_u$ is $m_u = \frac{1}{p} + c - 1$, or $p
1341/// = \frac{1}{m_u - c + 1}$. Then we have
1342/// $$
1343/// P(n) \neq 0 \leftrightarrow n \in S
1344/// $$
1345/// If $0, 1 \in S$, then
1346/// $$
1347/// \frac{P(0)}{P(1)} = \frac{m_u + 1}{m_u}.
1348/// $$
1349/// If $-1, 0 \in S$, then
1350/// $$
1351/// \frac{P(0)}{P(-1)} = \frac{m_u + 1}{m_u}.
1352/// $$
1353/// and whenever $n, n + \operatorname{sgn}(n) \in S \setminus \\{0\\}$,
1354/// $$
1355/// \frac{P(n)}{P(n+\operatorname{sgn}(n))} = \frac{m_u + 1}{m_u}.
1356/// $$
1357///
1358/// As a corollary, $P(n) = P(-n)$ whenever $n, -n \in S$.
1359///
1360/// The output length is infinite.
1361///
1362/// # Expected complexity per iteration
1363/// $T(n) = O(n)$
1364///
1365/// $M(n) = O(1)$
1366///
1367/// where $T$ is time, $M$ is additional memory, and $n$ is `um_numerator / um_denominator + 1`.
1368///
1369/// # Panics
1370/// Panics if $a > b$, if `um_numerator` or `um_denominator` are zero, if their ratio is less than
1371/// or equal to $a$, or if they are too large and manipulating them leads to arithmetic overflow.
1372///
1373/// # Examples
1374/// ```
1375/// use malachite_base::iterators::prefix_to_string;
1376/// use malachite_base::num::random::geometric::geometric_random_signed_inclusive_range;
1377/// use malachite_base::random::EXAMPLE_SEED;
1378///
1379/// assert_eq!(
1380/// prefix_to_string(
1381/// geometric_random_signed_inclusive_range::<i8>(EXAMPLE_SEED, -100, 99, 30, 1),
1382/// 10
1383/// ),
1384/// "[-32, -31, -88, 52, -40, 64, -36, -1, -7, 46, ...]"
1385/// )
1386/// ```
1387///
1388/// # Further details
1389/// The probability mass function of this distribution is
1390/// $$
1391/// P(n) = \\begin{cases}
1392/// \frac{(1-p)^np}{(1-p)^a-(1-p)^{b+1}} & \text{if} \\quad 0 \\leq a \\leq n \\leq b, \\\\
1393/// \frac{(1-p)^{-n}p}{(1-p)^{-b}-(1-p)^{1-a}}
1394/// & \text{if} \\quad a \\leq n \\leq b \\leq 0, \\\\
1395/// \frac{(1-p)^{|n|}p}{2-p-(1-p)^{1-a}-(1-p)^{b+1}}
1396/// & \text{if} \\quad a < 0 < b \\ \mathrm{and} \\ a \\leq n \\leq b, \\\\
1397/// 0 & \\text{otherwise}.
1398/// \\end{cases}
1399/// $$
1400#[inline]
1401pub fn geometric_random_signed_inclusive_range<T: PrimitiveSigned>(
1402 seed: Seed,
1403 a: T,
1404 b: T,
1405 abs_um_numerator: u64,
1406 abs_um_denominator: u64,
1407) -> GeometricRandomSignedRange<T> {
1408 assert!(a <= b, "a must be less than or equal to b. a: {a}, b: {b}");
1409 if a >= T::ZERO {
1410 GeometricRandomSignedRange::NonNegative(geometric_random_natural_values_inclusive_range(
1411 seed,
1412 a,
1413 b,
1414 abs_um_numerator,
1415 abs_um_denominator,
1416 ))
1417 } else if b <= T::ZERO {
1418 GeometricRandomSignedRange::NonPositive(geometric_random_negative_signeds_inclusive_range(
1419 seed,
1420 b,
1421 a,
1422 abs_um_numerator,
1423 abs_um_denominator,
1424 ))
1425 } else {
1426 GeometricRandomSignedRange::BothSigns(geometric_random_signed_inclusive_range_helper(
1427 seed,
1428 a,
1429 b,
1430 abs_um_numerator,
1431 abs_um_denominator,
1432 ))
1433 }
1434}
1435
1436/// Generates a random signed integers from a modified geometric distribution over the closed
1437/// interval $[a, b]$.
1438///
1439/// See [`geometric_random_signed_inclusive_range`] for a detailed description of the distribution.
1440///
1441/// The output length is infinite.
1442///
1443/// # Expected complexity per iteration
1444/// $T(n) = O(n)$
1445///
1446/// $M(n) = O(1)$
1447///
1448/// where $T$ is time, $M$ is additional memory, and $n$ is `um_numerator / um_denominator + 1`.
1449///
1450/// # Panics
1451/// Panics if $a > b$, if `um_numerator` or `um_denominator` are zero, if their ratio is less than
1452/// or equal to $a$, or if they are too large and manipulating them leads to arithmetic overflow.
1453///
1454/// # Examples
1455/// ```
1456/// use malachite_base::num::random::geometric::get_geometric_random_signed_from_inclusive_range;
1457/// use malachite_base::num::random::VariableRangeGenerator;
1458/// use malachite_base::random::EXAMPLE_SEED;
1459///
1460/// assert_eq!(
1461/// get_geometric_random_signed_from_inclusive_range::<i8>(
1462/// &mut VariableRangeGenerator::new(EXAMPLE_SEED),
1463/// -100,
1464/// 99,
1465/// 30,
1466/// 1
1467/// ),
1468/// 8
1469/// )
1470/// ```
1471pub fn get_geometric_random_signed_from_inclusive_range<T: PrimitiveSigned>(
1472 range_generator: &mut VariableRangeGenerator,
1473 a: T,
1474 b: T,
1475 abs_um_numerator: u64,
1476 abs_um_denominator: u64,
1477) -> T {
1478 assert!(a <= b, "a must be less than or equal to b. a: {a}, b: {b}");
1479 if a >= T::ZERO {
1480 get_geometric_random_natural_value_from_inclusive_range(
1481 range_generator,
1482 a,
1483 b,
1484 abs_um_numerator,
1485 abs_um_denominator,
1486 )
1487 } else if b <= T::ZERO {
1488 get_geometric_random_negative_signed_from_inclusive_range(
1489 range_generator,
1490 b,
1491 a,
1492 abs_um_numerator,
1493 abs_um_denominator,
1494 )
1495 } else {
1496 get_geometric_random_signed_from_inclusive_range_helper(
1497 range_generator,
1498 a,
1499 b,
1500 abs_um_numerator,
1501 abs_um_denominator,
1502 )
1503 }
1504}