1pub mod core;
51pub mod seq;
52pub mod slice_ops;
53
54pub mod arrays;
56pub mod distributions;
57pub mod distributions_unified;
58
59pub mod qmc;
61pub mod variance_reduction;
62
63pub mod parallel;
65pub mod secure;
66
67pub mod ml;
69pub mod prelude;
70pub mod quick;
71pub mod scientific;
72
73pub mod advanced_numerical;
75pub mod cutting_edge_mcmc;
76pub mod ecosystem_integration;
77pub mod neural_sampling;
78pub mod quantum_inspired;
79
80pub use core::{seeded_rng, thread_rng, DistributionExt};
82
83pub use rand_chacha::{ChaCha12Rng, ChaCha20Rng, ChaCha8Rng};
85
86pub use core::Random as CoreRandom;
88
89pub use slice_ops::{ScientificSliceRandom, SliceRandomExt};
91
92pub use distributions::{
99 Beta, Categorical, Dirichlet, GammaDist, MultivariateNormal, VonMises, WeightedChoice,
100};
101
102pub use distributions_unified::{
104 UnifiedBeta, UnifiedBinomial, UnifiedCauchy, UnifiedChiSquared, UnifiedDirichlet,
105 UnifiedDistribution, UnifiedDistributionError, UnifiedExp, UnifiedFisherF, UnifiedGamma,
106 UnifiedLogNormal, UnifiedNormal, UnifiedPoisson, UnifiedStudentT, UnifiedWeibull,
107};
108
109pub use arrays::{
111 random_exponential_array, random_gamma_array, random_he_weights, random_normal_array,
112 random_sparse_array, random_uniform_array, random_xavier_weights, OptimizedArrayRandom,
113};
114
115pub use variance_reduction::{
117 AntitheticSampling, CommonRatio, ControlVariate, ImportanceSplitting,
118};
119
120pub use qmc::{
122 HaltonGenerator, LatinHypercubeSampler, LowDiscrepancySequence, QmcError, SobolGenerator,
123};
124
125pub use secure::{utils as secure_utils, SecureRandom, SecureRngPool};
127
128pub use parallel::{BatchRng, DistributedRngPool, ParallelRng, ThreadLocalRngPool};
130
131pub use advanced_numerical::{
133 AdaptiveResult, AdaptiveSampler, ImportanceResult, ImportanceSampler, MLMCResult,
134 MultiLevelMonteCarlo, SequentialMonteCarlo,
135};
136
137pub use cutting_edge_mcmc::{
138 EllipticalSliceSampler, HamiltonianMonteCarlo, NoUTurnSampler, ParallelTempering,
139 SteinVariationalGradientDescent,
140};
141
142pub use neural_sampling::{
143 DiffusionConfig, EnergyBasedModel, NeuralPosteriorEstimation, NormalizingFlow,
144 ScoreBasedDiffusion,
145};
146
147pub use quantum_inspired::{
148 CoinParameters, QuantumAmplitudeAmplification, QuantumInspiredAnnealing,
149 QuantumInspiredEvolutionary, QuantumWalk,
150};
151
152pub use ecosystem_integration::{
153 AugmentationConfig, ExperimentalDesign, LinalgBridge, NeuralBridge, OptimizationBridge,
154 StatsBridge, SyntheticDataset,
155};
156
157pub use ::ndarray::Dimension;
159pub use rand::prelude as rand_prelude;
160pub use rand::rngs;
161pub use rand::seq::SliceRandom;
162pub use rand::{Rng, RngCore, SeedableRng};
163pub use rand_distr as rand_distributions;
164pub use rand_distr::uniform;
165
166pub fn random<T>() -> T
187where
188 rand::distr::StandardUniform: rand::distr::Distribution<T>,
189{
190 rand::random()
191}
192
193pub fn rng() -> rand::rngs::ThreadRng {
208 rand::thread_rng()
209}
210
211pub use rand_distr::{
214 Alphanumeric,
216 Bernoulli as RandBernoulli,
218 Beta as RandBeta,
220 Binomial,
221 Cauchy,
222 ChiSquared,
223 Dirichlet as RandDirichlet,
225 Distribution,
227 Exp,
228 FisherF,
229 Gamma as RandGamma,
230 Geometric,
231 Hypergeometric,
232 InverseGaussian,
233 LogNormal,
234 Normal as RandNormal,
235 Open01,
236 OpenClosed01,
237 Pareto,
238 Pert,
239 Poisson,
240 StandardNormal,
241 StudentT,
242 Triangular,
243 Uniform as RandUniform,
244 UnitBall,
245 UnitCircle,
246 UnitDisc,
247 UnitSphere,
248 Weibull,
249 Zeta,
250 Zipf,
251};
252
253pub use rand_distr::weighted::WeightedIndex;
255
256pub use rand_distr::Bernoulli;
259pub use rand_distr::Exp as Exponential; pub use rand_distr::Gamma;
261pub use rand_distr::Normal;
262pub use rand_distr::Uniform;
263
264#[cfg(feature = "random")]
266pub use ndarray_rand::RandomExt;
267
268#[cfg(not(feature = "random"))]
270pub trait RandomExt<T, D> {
271 fn random_using<R: rand::Rng>(
272 shape: D,
273 distribution: impl rand_distr::Distribution<T>,
274 rng: &mut R,
275 ) -> Self;
276}
277
278#[cfg(not(feature = "random"))]
279impl<T, D> RandomExt<T, D> for crate::ndarray::ArrayBase<crate::ndarray::OwnedRepr<T>, D>
280where
281 D: crate::ndarray::Dimension,
282{
283 fn random_using<R: rand::Rng>(
284 shape: D,
285 distribution: impl rand_distr::Distribution<T>,
286 rng: &mut R,
287 ) -> Self {
288 let size = shape.size();
289 let mut data = Vec::with_capacity(size);
290 for _ in 0..size {
291 data.push(distribution.sample(rng));
292 }
293 Self::from_shape_vec(shape, data).expect("Operation failed")
294 }
295}
296
297pub mod legacy {
299 use super::*;
300 use rand_distr::Uniform;
301
302 pub fn rng() -> Random<rand::rngs::ThreadRng> {
304 Random { rng: rand::rng() }
305 }
306
307 pub fn f64() -> f64 {
309 rand::random::<f64>()
310 }
311
312 pub fn f32() -> f32 {
314 rand::random::<f32>()
315 }
316
317 pub fn usize(range: std::ops::Range<usize>) -> usize {
319 rand::thread_rng().gen_range(range)
320 }
321}
322
323pub mod convenience {
325 use super::*;
326 use ::ndarray::{Array, Dimension, IxDyn};
327 use rand_distr::{Distribution, Normal, Uniform};
328
329 pub fn uniform() -> f64 {
331 let mut rng = thread_rng();
332 rng.sample(Uniform::new(0.0, 1.0).expect("Operation failed"))
333 }
334
335 pub fn normal() -> f64 {
337 let mut rng = thread_rng();
338 rng.sample(Normal::new(0.0, 1.0).expect("Operation failed"))
339 }
340
341 pub fn integer(min: i64, max: i64) -> i64 {
343 let mut rng = thread_rng();
344 rng.sample(Uniform::new_inclusive(min, max).expect("Operation failed"))
345 }
346
347 pub fn boolean() -> bool {
349 let mut rng = thread_rng();
350 rng.gen_bool(0.5)
351 }
352
353 pub fn uniform_array<Sh: Into<IxDyn>>(shape: Sh) -> Array<f64, IxDyn> {
355 let mut rng = thread_rng();
356 let shape = shape.into();
357 let size = shape.size();
358 let values: Vec<f64> = (0..size)
359 .map(|_| rng.sample(Uniform::new(0.0, 1.0).expect("Operation failed")))
360 .collect();
361 Array::from_shape_vec(shape, values).expect("Operation failed")
362 }
363
364 pub fn normal_array<Sh: Into<IxDyn>>(shape: Sh, mean: f64, std: f64) -> Array<f64, IxDyn> {
366 let mut rng = thread_rng();
367 let shape = shape.into();
368 let size = shape.size();
369 let values: Vec<f64> = (0..size)
370 .map(|_| rng.sample(Normal::new(mean, std).expect("Operation failed")))
371 .collect();
372 Array::from_shape_vec(shape, values).expect("Operation failed")
373 }
374}
375
376pub mod sampling {
378 use super::*;
379 use ::ndarray::{Array, Dimension, IxDyn};
380 use rand_distr::{Distribution, Exp, LogNormal, Normal, Uniform};
381
382 pub fn random_uniform01<R: rand::Rng>(rng: &mut Random<R>) -> f64 {
384 rng.sample(Uniform::new(0.0, 1.0).expect("Operation failed"))
385 }
386
387 pub fn random_standard_normal<R: rand::Rng>(rng: &mut Random<R>) -> f64 {
389 rng.sample(Normal::new(0.0, 1.0).expect("Operation failed"))
390 }
391
392 pub fn random_normal<R: rand::Rng>(rng: &mut Random<R>, mean: f64, stddev: f64) -> f64 {
394 rng.sample(Normal::new(mean, stddev).expect("Operation failed"))
395 }
396
397 pub fn random_lognormal<R: rand::Rng>(rng: &mut Random<R>, mean: f64, stddev: f64) -> f64 {
399 rng.sample(LogNormal::new(mean, stddev).expect("Operation failed"))
400 }
401
402 pub fn random_exponential<R: rand::Rng>(rng: &mut Random<R>, lambda: f64) -> f64 {
404 rng.sample(Exp::new(lambda).expect("Operation failed"))
405 }
406
407 pub fn random_integers<R: rand::Rng, Sh>(
409 rng: &mut Random<R>,
410 min: i64,
411 max: i64,
412 shape: Sh,
413 ) -> Array<i64, IxDyn>
414 where
415 Sh: Into<IxDyn>,
416 {
417 rng.sample_array(
418 Uniform::new_inclusive(min, max).expect("Operation failed"),
419 shape,
420 )
421 }
422
423 pub fn random_floats<R: rand::Rng, Sh>(
425 rng: &mut Random<R>,
426 min: f64,
427 max: f64,
428 shape: Sh,
429 ) -> Array<f64, IxDyn>
430 where
431 Sh: Into<IxDyn>,
432 {
433 rng.sample_array(Uniform::new(min, max).expect("Operation failed"), shape)
434 }
435
436 pub fn bootstrap_indices<R: rand::Rng>(
438 rng: &mut Random<R>,
439 data_size: usize,
440 sample_size: usize,
441 ) -> Vec<usize> {
442 let dist = Uniform::new(0, data_size).expect("Operation failed");
443 rng.sample_vec(dist, sample_size)
444 }
445
446 pub fn sample_without_replacement<R: rand::Rng>(
448 rng: &mut Random<R>,
449 data_size: usize,
450 sample_size: usize,
451 ) -> Vec<usize> {
452 use rand::seq::SliceRandom;
453 let mut indices: Vec<usize> = (0..data_size).collect();
454 indices.shuffle(&mut rng.rng);
455 indices.truncate(sample_size);
456 indices
457 }
458}
459
460pub mod importance_sampling {
462 use super::*;
463 use rand_distr::{Normal, Uniform};
464
465 #[derive(Debug)]
467 pub struct ImportanceSampler<R: rand::Rng> {
468 rng: Random<R>,
469 }
470
471 impl<R: rand::Rng> ImportanceSampler<R> {
472 pub fn new(rng: Random<R>) -> Self {
474 Self { rng }
475 }
476
477 pub fn sample_with_weights<F, G>(
479 &mut self,
480 target_pdf: F,
481 proposal_pdf: G,
482 proposal_sampler: impl Fn(&mut Random<R>) -> f64,
483 n_samples: usize,
484 ) -> (Vec<f64>, Vec<f64>)
485 where
486 F: Fn(f64) -> f64,
487 G: Fn(f64) -> f64,
488 {
489 let mut samples = Vec::with_capacity(n_samples);
490 let mut weights = Vec::with_capacity(n_samples);
491
492 for _ in 0..n_samples {
493 let sample = proposal_sampler(&mut self.rng);
494 let weight = target_pdf(sample) / proposal_pdf(sample);
495
496 samples.push(sample);
497 weights.push(weight);
498 }
499
500 (samples, weights)
501 }
502
503 pub fn estimate_expectation<F, G, H>(
505 &mut self,
506 function: F,
507 target_pdf: G,
508 proposal_pdf: H,
509 proposal_sampler: impl Fn(&mut Random<R>) -> f64,
510 n_samples: usize,
511 ) -> f64
512 where
513 F: Fn(f64) -> f64,
514 G: Fn(f64) -> f64,
515 H: Fn(f64) -> f64,
516 {
517 let (samples, weights) =
518 self.sample_with_weights(target_pdf, proposal_pdf, proposal_sampler, n_samples);
519
520 let weighted_sum: f64 = samples
521 .iter()
522 .zip(weights.iter())
523 .map(|(&x, &w)| function(x) * w)
524 .sum();
525
526 let weight_sum: f64 = weights.iter().sum();
527
528 weighted_sum / weight_sum
529 }
530
531 pub fn adaptive_sampling<F>(
533 &mut self,
534 target_log_pdf: F,
535 initial_samples: usize,
536 adaptation_rounds: usize,
537 ) -> Vec<f64>
538 where
539 F: Fn(f64) -> f64,
540 {
541 let mut samples = Vec::new();
542 let mut proposal_mean: f64 = 0.0;
543 let mut proposal_std: f64 = 1.0;
544
545 for round in 0..adaptation_rounds {
546 let round_samples = if round == 0 {
547 initial_samples
548 } else {
549 initial_samples / 2
550 };
551 let normal_dist =
552 Normal::new(proposal_mean, proposal_std).expect("Operation failed");
553
554 let mut round_sample_vec = Vec::new();
555 let mut weights = Vec::new();
556
557 for _ in 0..round_samples {
558 let sample = self.rng.sample(normal_dist);
559
560 let normal_log_pdf = -0.5 * ((sample - proposal_mean) / proposal_std).powi(2)
562 - 0.5 * (2.0 * std::f64::consts::PI).ln()
563 - proposal_std.ln();
564 let log_weight = target_log_pdf(sample) - normal_log_pdf;
565
566 round_sample_vec.push(sample);
567 weights.push(log_weight.exp());
568 }
569
570 let weight_sum: f64 = weights.iter().sum();
572 if weight_sum > 0.0 {
573 let normalized_weights: Vec<f64> =
574 weights.iter().map(|w| w / weight_sum).collect();
575
576 proposal_mean = round_sample_vec
577 .iter()
578 .zip(normalized_weights.iter())
579 .map(|(&x, &w)| x * w)
580 .sum();
581
582 let variance = round_sample_vec
583 .iter()
584 .zip(normalized_weights.iter())
585 .map(|(&x, &w)| w * (x - proposal_mean).powi(2))
586 .sum::<f64>();
587
588 proposal_std = variance.sqrt().max(0.1); }
590
591 samples.extend(round_sample_vec);
592 }
593
594 samples
595 }
596 }
597
598 impl ImportanceSampler<rand::rngs::ThreadRng> {
599 pub fn with_default_rng() -> Self {
601 Self::new(Random::default())
602 }
603 }
604}
605
606#[cfg(feature = "gpu")]
608pub mod gpu {
609 pub struct GpuRng;
612
613 impl Default for GpuRng {
614 fn default() -> Self {
615 Self::new()
616 }
617 }
618
619 impl GpuRng {
620 pub fn new() -> Self {
621 Self
622 }
623 }
624}
625
626#[derive(Debug)]
630pub struct Random<R: rand::Rng + ?Sized = rand::rngs::ThreadRng> {
631 pub(crate) rng: R,
632}
633
634impl Default for Random<rand::rngs::ThreadRng> {
635 fn default() -> Self {
636 Self {
637 rng: rand::thread_rng(),
638 }
639 }
640}
641
642impl<R: rand::Rng + Clone> Clone for Random<R> {
643 fn clone(&self) -> Self {
644 Self {
645 rng: self.rng.clone(),
646 }
647 }
648}
649
650impl<R: rand::Rng> Random<R> {
651 pub fn sample<D, T>(&mut self, distribution: D) -> T
653 where
654 D: rand_distr::Distribution<T>,
655 {
656 use rand_distr::Distribution;
657 distribution.sample(&mut self.rng)
658 }
659
660 pub fn random_range<T: rand_distr::uniform::SampleUniform + PartialOrd + Copy>(
662 &mut self,
663 min: T,
664 max: T,
665 ) -> T {
666 self.sample(rand_distr::Uniform::new(min, max).expect("Operation failed"))
667 }
668
669 #[allow(deprecated)]
671 pub fn gen_range<T, RNG>(&mut self, range: RNG) -> T
672 where
673 T: rand_distr::uniform::SampleUniform,
674 RNG: rand_distr::uniform::SampleRange<T>,
675 {
676 self.rng.gen_range(range)
677 }
678
679 pub fn random_f64(&mut self) -> f64 {
681 self.sample(rand_distr::Uniform::new(0.0, 1.0).expect("Operation failed"))
682 }
683
684 pub fn random_f64_raw(&mut self) -> f64 {
686 self.rng.random()
687 }
688
689 pub fn random_bool(&mut self) -> bool {
691 use rand_distr::Distribution;
692 let dist = rand_distr::Bernoulli::new(0.5).expect("Operation failed");
693 dist.sample(&mut self.rng)
694 }
695
696 pub fn random_bool_with_chance(&mut self, prob: f64) -> bool {
698 use rand_distr::Distribution;
699 let dist = rand_distr::Bernoulli::new(prob).expect("Operation failed");
700 dist.sample(&mut self.rng)
701 }
702
703 pub fn shuffle<T>(&mut self, slice: &mut [T]) {
705 use rand::seq::SliceRandom;
706 slice.shuffle(&mut self.rng);
707 }
708
709 pub fn sample_vec<D, T>(&mut self, distribution: D, size: usize) -> Vec<T>
711 where
712 D: rand_distr::Distribution<T> + Copy,
713 {
714 (0..size)
715 .map(|_| distribution.sample(&mut self.rng))
716 .collect()
717 }
718
719 pub fn sample_array<D, T, Sh>(
721 &mut self,
722 distribution: D,
723 shape: Sh,
724 ) -> crate::ndarray::Array<T, crate::ndarray::IxDyn>
725 where
726 D: rand_distr::Distribution<T> + Copy,
727 Sh: Into<crate::ndarray::IxDyn>,
728 {
729 let shape = shape.into();
730 let size = shape.size();
731 let values = self.sample_vec(distribution, size);
732 crate::ndarray::Array::from_shape_vec(shape, values).expect("Operation failed")
733 }
734}
735
736impl Random<rand::rngs::ThreadRng> {
737 pub fn seed(seed: u64) -> Random<rand::rngs::StdRng> {
739 Random {
740 rng: rand::SeedableRng::seed_from_u64(seed),
741 }
742 }
743}
744
745impl<R: rand::RngCore> rand::RngCore for Random<R> {
747 fn next_u32(&mut self) -> u32 {
748 self.rng.next_u32()
749 }
750
751 fn next_u64(&mut self) -> u64 {
752 self.rng.next_u64()
753 }
754
755 fn fill_bytes(&mut self, dest: &mut [u8]) {
756 self.rng.fill_bytes(dest)
757 }
758}
759
760impl rand::SeedableRng for Random<rand::rngs::StdRng> {
761 type Seed = <rand::rngs::StdRng as rand::SeedableRng>::Seed;
762
763 fn from_seed(seed: Self::Seed) -> Self {
764 Random {
765 rng: rand::rngs::StdRng::from_seed(seed),
766 }
767 }
768
769 fn seed_from_u64(state: u64) -> Self {
770 Random {
771 rng: rand::rngs::StdRng::seed_from_u64(state),
772 }
773 }
774}
775
776use std::cell::RefCell;
778thread_local! {
779 static THREAD_RNG: RefCell<Random> = RefCell::new(Random::default());
780}
781
782#[allow(dead_code)]
784pub fn get_rng<F, R>(f: F) -> R
785where
786 F: FnOnce(&mut Random) -> R,
787{
788 THREAD_RNG.with(|rng| f(&mut rng.borrow_mut()))
789}
790
791pub struct DeterministicSequence {
793 seed: u64,
794 counter: u64,
795}
796
797impl DeterministicSequence {
798 pub fn seed(seed: u64) -> Self {
800 Self { seed, counter: 0 }
801 }
802
803 pub fn next_f64(&mut self) -> f64 {
805 let mut x = self.counter.wrapping_add(self.seed);
807 x = ((x >> 16) ^ x).wrapping_mul(0x45d9f3b);
808 x = ((x >> 16) ^ x).wrapping_mul(0x45d9f3b);
809 x = (x >> 16) ^ x;
810
811 self.counter = self.counter.wrapping_add(1);
812
813 (x as f64) / (u64::MAX as f64)
815 }
816
817 pub fn reset(&mut self) {
819 self.counter = 0;
820 }
821
822 pub fn get_vec(&mut self, size: usize) -> Vec<f64> {
824 (0..size).map(|_| self.next_f64()).collect()
825 }
826
827 pub fn get_array<Sh>(&mut self, shape: Sh) -> crate::ndarray::Array<f64, crate::ndarray::IxDyn>
829 where
830 Sh: Into<crate::ndarray::IxDyn>,
831 {
832 let shape = shape.into();
833 let size = shape.size();
834 let values = self.get_vec(size);
835 crate::ndarray::Array::from_shape_vec(shape, values).expect("Operation failed")
836 }
837}
838
839pub type ThreadRng = Random<rand::rngs::ThreadRng>;
845pub type StdRng = Random<rand::rngs::StdRng>;
846
847pub type UniformDist = rand_distributions::Uniform<f64>;
849pub type NormalDist = rand_distributions::Normal<f64>;
850pub type ExponentialDist = rand_distributions::Exp<f64>;
851
852pub type Array1D<T> = crate::ndarray::Array1<T>;
854pub type Array2D<T> = crate::ndarray::Array2<T>;
855pub type Array3D<T> = crate::ndarray::Array3<T>;
856
857pub use quick as rapid;
863
864pub use scientific as research;
866
867pub use ml as machine_learning;
869
870pub use secure as crypto;
872
873pub mod quasi_monte_carlo {
879 pub use crate::random::qmc::*;
880
881 pub type SobolSequence = crate::random::qmc::SobolGenerator;
883 pub type HaltonSequence = crate::random::qmc::HaltonGenerator;
884 pub type LatinHypercubeSampling = crate::random::qmc::LatinHypercubeSampler;
885}
886
887pub mod specialized_distributions {
889 pub use crate::random::distributions::*;
890}
891
892pub mod optimized_arrays {
894 pub use crate::random::arrays::*;
895}
896
897pub mod slice_random {
899 pub use crate::random::slice_ops::convenience::*;
900}
901
902pub mod essentials {
908 pub use crate::random::rand_distributions::{Normal, Uniform};
909 pub use crate::random::{
910 random_normal_array, random_uniform_array, seeded_rng, thread_rng, Beta, Categorical,
911 Random, Rng, RngCore, SeedableRng, WeightedChoice,
912 };
913}
914
915pub mod statistics {
917 pub use crate::random::{
918 AntitheticSampling, Beta, Categorical, CommonRatio, ControlVariate, Dirichlet,
919 ExponentialDist, GammaDist, HaltonGenerator, LatinHypercubeSampler, MultivariateNormal,
920 SobolGenerator, VonMises, WeightedChoice,
921 };
922}
923
924pub mod hpc {
926 pub use crate::random::{
927 random_he_weights, random_normal_array, random_uniform_array, random_xavier_weights,
928 BatchRng, DistributedRngPool, OptimizedArrayRandom, ParallelRng, ThreadLocalRngPool,
929 };
930}
931
932pub mod cutting_edge {
934 pub use crate::random::{
935 advanced_numerical::*, cutting_edge_mcmc::*, ecosystem_integration::*, neural_sampling::*,
936 quantum_inspired::*,
937 };
938}
939
940pub mod bayesian {
942 pub use crate::random::{
943 EllipticalSliceSampler, HamiltonianMonteCarlo, ImportanceSampler, NoUTurnSampler,
944 ParallelTempering, SteinVariationalGradientDescent,
945 };
946 }
948
949pub mod ai_sampling {
951 pub use crate::random::{
952 DiffusionConfig, EnergyBasedModel, NeuralBridge, NeuralPosteriorEstimation,
953 NormalizingFlow, ScoreBasedDiffusion,
954 };
955}
956
957pub mod quantum {
959 pub use crate::random::{
960 CoinParameters, QuantumAmplitudeAmplification, QuantumInspiredAnnealing,
961 QuantumInspiredEvolutionary, QuantumWalk,
962 };
963}
964
965pub mod numerical_methods {
967 pub use crate::random::{
968 AdaptiveResult, AdaptiveSampler, ImportanceResult, MLMCResult, MultiLevelMonteCarlo,
969 SequentialMonteCarlo,
970 };
971}
972
973pub mod bridges {
975 pub use crate::random::{
976 AugmentationConfig, ExperimentalDesign, LinalgBridge, NeuralBridge, OptimizationBridge,
977 StatsBridge, SyntheticDataset,
978 };
979}