use crate::random::{
advanced_numerical::*,
arrays::*,
core::{seeded_rng, Random},
distributions::*,
parallel::{ParallelRng, ThreadLocalRngPool},
scientific::*,
};
use ::ndarray::{Array1, Array2, Array3, ArrayD, Dimension, Ix2};
use rand::{Rng, RngExt};
use rand_distr::{Distribution, Normal, Uniform};
use std::collections::HashMap;
pub struct LinalgBridge;
impl LinalgBridge {
pub fn random_symmetric_positive_definite(
size: usize,
seed: u64,
) -> Result<Array2<f64>, String> {
let mut rng = seeded_rng(seed);
let mut a = Array2::zeros((size, size));
for i in 0..size {
for j in 0..size {
a[[i, j]] = rng.sample(Normal::new(0.0, 1.0).expect("Operation failed"));
}
}
let at = a.t();
let mut result = Array2::zeros((size, size));
for i in 0..size {
for j in 0..size {
let mut sum = 0.0;
for k in 0..size {
sum += a[[i, k]] * at[[k, j]];
}
result[[i, j]] = sum;
}
result[[i, i]] += 1e-6;
}
Ok(result)
}
pub fn random_symmetric_matrix(size: usize, seed: u64) -> Result<Array2<f64>, String> {
let mut rng = seeded_rng(seed);
let mut matrix = Array2::zeros((size, size));
for i in 0..size {
for j in i..size {
let value = rng.sample(Normal::new(0.0, 1.0).expect("Operation failed"));
matrix[[i, j]] = value;
matrix[[j, i]] = value;
}
}
Ok(matrix)
}
pub fn random_orthogonal_matrix(size: usize, seed: u64) -> Result<Array2<f64>, String> {
let mut rng = seeded_rng(seed);
let mut a = Array2::zeros((size, size));
for i in 0..size {
for j in 0..size {
a[[i, j]] = rng.sample(Normal::new(0.0, 1.0).expect("Operation failed"));
}
}
let mut q = Array2::zeros((size, size));
for j in 0..size {
let mut v = Array1::zeros(size);
for i in 0..size {
v[i] = a[[i, j]];
}
for k in 0..j {
let mut proj = 0.0;
for i in 0..size {
proj += v[i] * q[[i, k]];
}
for i in 0..size {
v[i] -= proj * q[[i, k]];
}
}
let norm = (v.iter().map(|x| x * x).sum::<f64>()).sqrt();
if norm > 1e-10 {
for i in 0..size {
q[[i, j]] = v[i] / norm;
}
}
}
Ok(q)
}
pub fn random_eigenvalue_problem(
size: usize,
eigenvalue_spread: f64,
seed: u64,
) -> Result<(Array2<f64>, Vec<f64>, Array2<f64>), String> {
let mut rng = seeded_rng(seed);
let mut eigenvalues = Vec::with_capacity(size);
for _ in 0..size {
eigenvalues
.push(rng.sample(Uniform::new(0.1, eigenvalue_spread).expect("Operation failed")));
}
eigenvalues.sort_by(|a, b| b.partial_cmp(a).expect("Operation failed"));
let eigenvectors = Self::random_orthogonal_matrix(size, seed + 1)?;
let mut diagonal = Array2::zeros((size, size));
for i in 0..size {
diagonal[[i, i]] = eigenvalues[i];
}
let mut vd = Array2::zeros((size, size));
for i in 0..size {
for j in 0..size {
let mut sum = 0.0;
for k in 0..size {
sum += eigenvectors[[i, k]] * diagonal[[k, j]];
}
vd[[i, j]] = sum;
}
}
let mut a = Array2::zeros((size, size));
for i in 0..size {
for j in 0..size {
let mut sum = 0.0;
for k in 0..size {
sum += vd[[i, k]] * eigenvectors[[j, k]]; }
a[[i, j]] = sum;
}
}
Ok((a, eigenvalues, eigenvectors))
}
pub fn random_sparse_matrix(
rows: usize,
cols: usize,
density: f64,
seed: u64,
) -> Result<Vec<(usize, usize, f64)>, String> {
if !(0.0..=1.0).contains(&density) {
return Err("Density must be between 0 and 1".to_string());
}
let mut rng = seeded_rng(seed);
let mut triplets = Vec::new();
let total_elements = rows * cols;
let nnz = (total_elements as f64 * density) as usize;
for _ in 0..nnz {
let row = rng.sample(Uniform::new(0, rows).expect("Operation failed"));
let col = rng.sample(Uniform::new(0, cols).expect("Operation failed"));
let value = rng.sample(Normal::new(0.0, 1.0).expect("Operation failed"));
triplets.push((row, col, value));
}
Ok(triplets)
}
}
pub struct StatsBridge;
impl StatsBridge {
pub fn design_experiment() -> ExperimentDesignBuilder {
ExperimentDesignBuilder::new()
}
pub fn synthetic_dataset(
properties: DatasetProperties,
seed: u64,
) -> Result<SyntheticDataset, String> {
let mut rng = seeded_rng(seed);
let mut data = HashMap::new();
for (name, spec) in properties.features.iter() {
let feature_data = match &spec.distribution {
FeatureDistribution::Normal { mean, std } => {
let normal = Normal::new(*mean, *std).expect("Operation failed");
(0..properties.n_samples)
.map(|_| rng.sample(normal))
.collect::<Vec<f64>>()
}
FeatureDistribution::Uniform { low, high } => {
let uniform = Uniform::new(*low, *high).expect("Operation failed");
(0..properties.n_samples)
.map(|_| rng.sample(uniform))
.collect::<Vec<f64>>()
}
FeatureDistribution::Beta { alpha, beta } => {
let beta_dist = Beta::new(*alpha, *beta)?;
(0..properties.n_samples)
.map(|_| beta_dist.sample(&mut rng))
.collect::<Vec<f64>>()
}
FeatureDistribution::Categorical {
categories,
weights,
} => {
let categorical = Categorical::new(weights.clone())?;
(0..properties.n_samples)
.map(|_| categorical.sample(&mut rng) as f64)
.collect::<Vec<f64>>()
}
};
data.insert(name.clone(), feature_data);
}
Ok(SyntheticDataset { data, properties })
}
pub fn correlated_dataset(
means: Vec<f64>,
correlation_matrix: Vec<Vec<f64>>,
n_samples: usize,
seed: u64,
) -> Result<Array2<f64>, String> {
let mvn = MultivariateNormal::new(means, correlation_matrix)?;
let mut rng = seeded_rng(seed);
let mut samples = Array2::zeros((n_samples, mvn.dimension()));
for i in 0..n_samples {
let sample = mvn.sample(&mut rng);
for j in 0..sample.len() {
samples[[i, j]] = sample[j];
}
}
Ok(samples)
}
pub fn bootstrap_confidence_interval<F>(
data: &[f64],
statistic: F,
confidence_level: f64,
n_bootstrap: usize,
seed: u64,
) -> Result<(f64, f64, f64), String>
where
F: Fn(&[f64]) -> f64 + Send + Sync,
{
let _pool = ThreadLocalRngPool::new(seed);
let bootstrap_stats: Vec<f64> = (0..n_bootstrap)
.map(|iter_idx| {
let mut rng = seeded_rng(seed.wrapping_add(iter_idx as u64));
use crate::random::slice_ops::ScientificSliceRandom;
let bootstrap_sample =
data.scientific_sample_with_replacement(&mut rng, data.len());
let sample_values: Vec<f64> = bootstrap_sample.iter().map(|&&x| x).collect();
statistic(&sample_values)
})
.collect();
let mut sorted_stats = bootstrap_stats;
sorted_stats.sort_by(|a, b| a.partial_cmp(b).expect("Operation failed"));
let alpha = 1.0 - confidence_level;
let lower_idx = (alpha / 2.0 * sorted_stats.len() as f64) as usize;
let upper_idx = ((1.0 - alpha / 2.0) * sorted_stats.len() as f64) as usize;
let lower_bound = sorted_stats[lower_idx];
let upper_bound = sorted_stats[upper_idx.min(sorted_stats.len() - 1)];
let point_estimate = statistic(data);
Ok((point_estimate, lower_bound, upper_bound))
}
}
pub struct NeuralBridge;
impl NeuralBridge {
pub fn xavier_initialization(
layer_sizes: &[usize],
seed: u64,
) -> Result<Vec<Array2<f64>>, String> {
let mut rng = seeded_rng(seed);
let mut weights = Vec::new();
for i in 0..layer_sizes.len() - 1 {
let fan_in = layer_sizes[i] as f64;
let fan_out = layer_sizes[i + 1] as f64;
let std = (2.0 / (fan_in + fan_out)).sqrt();
let normal = Normal::new(0.0, std).expect("Operation failed");
let mut weight_matrix = Array2::zeros((layer_sizes[i + 1], layer_sizes[i]));
for j in 0..layer_sizes[i + 1] {
for k in 0..layer_sizes[i] {
weight_matrix[[j, k]] = rng.sample(normal);
}
}
weights.push(weight_matrix);
}
Ok(weights)
}
pub fn he_initialization(layer_sizes: &[usize], seed: u64) -> Result<Vec<Array2<f64>>, String> {
let mut rng = seeded_rng(seed);
let mut weights = Vec::new();
for i in 0..layer_sizes.len() - 1 {
let fan_in = layer_sizes[i] as f64;
let std = (2.0 / fan_in).sqrt();
let normal = Normal::new(0.0, std).expect("Operation failed");
let mut weight_matrix = Array2::zeros((layer_sizes[i + 1], layer_sizes[i]));
for j in 0..layer_sizes[i + 1] {
for k in 0..layer_sizes[i] {
weight_matrix[[j, k]] = rng.sample(normal);
}
}
weights.push(weight_matrix);
}
Ok(weights)
}
pub fn lecun_initialization(
layer_sizes: &[usize],
seed: u64,
) -> Result<Vec<Array2<f64>>, String> {
let mut rng = seeded_rng(seed);
let mut weights = Vec::new();
for i in 0..layer_sizes.len() - 1 {
let fan_in = layer_sizes[i] as f64;
let std = (1.0 / fan_in).sqrt();
let normal = Normal::new(0.0, std).expect("Operation failed");
let mut weight_matrix = Array2::zeros((layer_sizes[i + 1], layer_sizes[i]));
for j in 0..layer_sizes[i + 1] {
for k in 0..layer_sizes[i] {
weight_matrix[[j, k]] = rng.sample(normal);
}
}
weights.push(weight_matrix);
}
Ok(weights)
}
pub fn dropout_masks(
shapes: &[(usize, usize)],
dropout_rate: f64,
seed: u64,
) -> Result<Vec<Array2<f64>>, String> {
let mut rng = seeded_rng(seed);
let mut masks = Vec::new();
let keep_prob = 1.0 - dropout_rate;
let uniform = Uniform::new(0.0, 1.0).expect("Operation failed");
for &(rows, cols) in shapes {
let mut mask = Array2::zeros((rows, cols));
for i in 0..rows {
for j in 0..cols {
mask[[i, j]] = if rng.sample(uniform) < keep_prob {
1.0 / keep_prob
} else {
0.0
};
}
}
masks.push(mask);
}
Ok(masks)
}
pub fn gradient_noise_injection(
noise_scale: f64,
gradients: &[Array2<f64>],
seed: u64,
) -> Result<Vec<Array2<f64>>, String> {
let mut rng = seeded_rng(seed);
let mut noisy_gradients = Vec::new();
let normal = Normal::new(0.0, noise_scale).expect("Operation failed");
for gradient in gradients {
let mut noisy_gradient = gradient.clone();
for elem in noisy_gradient.iter_mut() {
*elem += rng.sample(normal);
}
noisy_gradients.push(noisy_gradient);
}
Ok(noisy_gradients)
}
pub fn augmentation_parameters(
batch_size: usize,
config: AugmentationConfig,
seed: u64,
) -> AugmentationBatch {
let mut rng = seeded_rng(seed);
let mut batch = AugmentationBatch::new(batch_size);
for _ in 0..batch_size {
let rotation = if config.rotation_range > 0.0 {
rng.sample(
Uniform::new(-config.rotation_range, config.rotation_range)
.expect("Operation failed"),
)
} else {
0.0
};
let scale = if config.scale_range.0 < config.scale_range.1 {
rng.sample(
Uniform::new(config.scale_range.0, config.scale_range.1)
.expect("Operation failed"),
)
} else {
1.0
};
let translation_x = if config.translation_range.0 > 0.0 {
rng.sample(
Uniform::new(-config.translation_range.0, config.translation_range.0)
.expect("Operation failed"),
)
} else {
0.0
};
let translation_y = if config.translation_range.1 > 0.0 {
rng.sample(
Uniform::new(-config.translation_range.1, config.translation_range.1)
.expect("Operation failed"),
)
} else {
0.0
};
batch.add_transform(AugmentationTransform {
rotation,
scale,
translation: (translation_x, translation_y),
horizontal_flip: rng.sample(Uniform::new(0.0, 1.0).expect("Operation failed"))
< config.horizontal_flip_prob,
vertical_flip: rng.sample(Uniform::new(0.0, 1.0).expect("Operation failed"))
< config.vertical_flip_prob,
});
}
batch
}
}
pub struct OptimizationBridge;
impl OptimizationBridge {
pub fn genetic_algorithm_population<T>(
population_size: usize,
individual_generator: impl Fn(&mut Random<rand::rngs::StdRng>) -> T,
seed: u64,
) -> Vec<T> {
let mut rng = seeded_rng(seed);
(0..population_size)
.map(|_| individual_generator(&mut rng))
.collect()
}
pub fn simulated_annealing_perturbation(
current_state: &[f64],
temperature: f64,
perturbation_scale: f64,
seed: u64,
) -> Vec<f64> {
let mut rng = seeded_rng(seed);
let std = perturbation_scale * temperature.sqrt();
let normal = Normal::new(0.0, std).expect("Operation failed");
current_state
.iter()
.map(|&x| x + rng.sample(normal))
.collect()
}
pub fn random_coordinate_directions(
dimensions: usize,
n_directions: usize,
seed: u64,
) -> Array2<f64> {
let mut rng = seeded_rng(seed);
let mut directions = Array2::zeros((n_directions, dimensions));
for i in 0..n_directions {
let mut direction = vec![0.0; dimensions];
for j in 0..dimensions {
direction[j] = rng.sample(Normal::new(0.0, 1.0).expect("Operation failed"));
}
let norm = direction.iter().map(|x| x * x).sum::<f64>().sqrt();
for j in 0..dimensions {
directions[[i, j]] = direction[j] / norm;
}
}
directions
}
pub fn exploration_noise(
action_dimensions: usize,
noise_type: ExplorationNoiseType,
time_step: usize,
seed: u64,
) -> Vec<f64> {
let mut rng = seeded_rng(seed + time_step as u64);
match noise_type {
ExplorationNoiseType::Gaussian { std } => {
let normal = Normal::new(0.0, std).expect("Operation failed");
(0..action_dimensions).map(|_| rng.sample(normal)).collect()
}
ExplorationNoiseType::OrnsteinUhlenbeck { theta, sigma, mu } => {
let dt = 1.0;
let std = sigma * (2.0 * theta * dt).sqrt();
let normal = Normal::new(0.0, std).expect("Operation failed");
(0..action_dimensions)
.map(|_| mu + rng.sample(normal))
.collect()
}
ExplorationNoiseType::EpsilonGreedy { epsilon } => {
let uniform = Uniform::new(0.0, 1.0).expect("Operation failed");
(0..action_dimensions)
.map(|_| {
if rng.sample(uniform) < epsilon {
1.0
} else {
0.0
}
})
.collect()
}
}
}
}
#[derive(Debug, Clone)]
pub struct ExperimentDesignBuilder {
factors: Vec<Vec<f64>>,
replications: usize,
blocking_factors: Vec<String>,
randomization_seed: Option<u64>,
design_type: DesignType,
}
#[derive(Debug, Clone)]
pub enum DesignType {
FullFactorial,
FractionalFactorial {
fraction: f64,
},
CentralComposite {
alpha: f64,
},
LatinHypercube {
n_points: Option<usize>,
},
RandomSampling {
n_points: usize,
},
}
impl ExperimentDesignBuilder {
pub fn new() -> Self {
Self {
factors: Vec::new(),
replications: 1,
blocking_factors: Vec::new(),
randomization_seed: None,
design_type: DesignType::FullFactorial,
}
}
pub fn factors(mut self, factors: &[Vec<f64>]) -> Self {
self.factors = factors.to_vec();
self
}
pub fn replications(mut self, n: usize) -> Self {
self.replications = n;
self
}
pub fn randomization_seed(mut self, seed: u64) -> Self {
self.randomization_seed = Some(seed);
self
}
pub fn design_type(mut self, design: DesignType) -> Self {
self.design_type = design;
self
}
pub fn build(self) -> Result<ExperimentalDesign, String> {
let seed = self.randomization_seed.unwrap_or(42);
let design_points = match self.design_type {
DesignType::FullFactorial => {
crate::random::scientific::ExperimentalDesign::factorial_design(&self.factors)
}
DesignType::FractionalFactorial { fraction } => {
crate::random::scientific::ExperimentalDesign::fractional_factorial_design(
&self.factors,
fraction,
seed,
)
}
DesignType::CentralComposite { alpha } => {
crate::random::scientific::ExperimentalDesign::central_composite_design(
self.factors.len(),
alpha,
)
}
DesignType::LatinHypercube { n_points } => {
crate::random::scientific::ExperimentalDesign::latin_hypercube_design(
&self.factors,
n_points,
seed,
)
}
DesignType::RandomSampling { n_points } => {
let mut rng = seeded_rng(seed);
let mut points = Vec::new();
for _ in 0..n_points {
let mut point = Vec::new();
for factor in &self.factors {
let idx =
rng.sample(Uniform::new(0, factor.len()).expect("Operation failed"));
point.push(factor[idx]);
}
points.push(point);
}
points
}
};
Ok(ExperimentalDesign {
design_points,
replications: self.replications,
factor_names: (0..self.factors.len())
.map(|i| format!("Factor_{}", i))
.collect(),
})
}
}
#[derive(Debug, Clone)]
pub struct ExperimentalDesign {
pub design_points: Vec<Vec<f64>>,
pub replications: usize,
pub factor_names: Vec<String>,
}
#[derive(Debug, Clone)]
pub struct DatasetProperties {
pub n_samples: usize,
pub features: HashMap<String, FeatureSpec>,
}
#[derive(Debug, Clone)]
pub struct FeatureSpec {
pub distribution: FeatureDistribution,
pub correlation_target: Option<String>,
pub correlation_strength: f64,
}
#[derive(Debug, Clone)]
pub enum FeatureDistribution {
Normal {
mean: f64,
std: f64,
},
Uniform {
low: f64,
high: f64,
},
Beta {
alpha: f64,
beta: f64,
},
Categorical {
categories: Vec<usize>,
weights: Vec<f64>,
},
}
#[derive(Debug, Clone)]
pub struct SyntheticDataset {
pub data: HashMap<String, Vec<f64>>,
pub properties: DatasetProperties,
}
#[derive(Debug, Clone)]
pub struct AugmentationConfig {
pub rotation_range: f64,
pub scale_range: (f64, f64),
pub translation_range: (f64, f64),
pub horizontal_flip_prob: f64,
pub vertical_flip_prob: f64,
}
#[derive(Debug, Clone)]
pub struct AugmentationTransform {
pub rotation: f64,
pub scale: f64,
pub translation: (f64, f64),
pub horizontal_flip: bool,
pub vertical_flip: bool,
}
#[derive(Debug)]
pub struct AugmentationBatch {
pub transforms: Vec<AugmentationTransform>,
}
impl AugmentationBatch {
pub fn new(capacity: usize) -> Self {
Self {
transforms: Vec::with_capacity(capacity),
}
}
pub fn add_transform(&mut self, transform: AugmentationTransform) {
self.transforms.push(transform);
}
}
#[derive(Debug, Clone)]
pub enum ExplorationNoiseType {
Gaussian { std: f64 },
OrnsteinUhlenbeck { theta: f64, sigma: f64, mu: f64 },
EpsilonGreedy { epsilon: f64 },
}
#[cfg(test)]
mod tests {
use super::*;
use approx::assert_relative_eq;
#[test]
fn test_linalg_bridge_symmetric_matrix() {
let matrix = LinalgBridge::random_symmetric_matrix(5, 42).expect("Operation failed");
for i in 0..5 {
for j in 0..5 {
assert_relative_eq!(matrix[[i, j]], matrix[[j, i]], epsilon = 1e-10);
}
}
}
#[test]
fn test_linalg_bridge_positive_definite() {
let matrix =
LinalgBridge::random_symmetric_positive_definite(3, 42).expect("Operation failed");
for i in 0..3 {
assert!(matrix[[i, i]] > 0.0);
}
for i in 0..3 {
for j in 0..3 {
assert_relative_eq!(matrix[[i, j]], matrix[[j, i]], epsilon = 1e-10);
}
}
}
#[test]
fn test_neural_bridge_xavier_init() {
let layer_sizes = vec![784, 128, 64, 10];
let weights =
NeuralBridge::xavier_initialization(&layer_sizes, 42).expect("Operation failed");
assert_eq!(weights.len(), 3); assert_eq!(weights[0].shape(), [128, 784]);
assert_eq!(weights[1].shape(), [64, 128]);
assert_eq!(weights[2].shape(), [10, 64]);
}
#[test]
fn test_stats_bridge_bootstrap_ci() {
let data = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0];
let (point_est, lower, upper) = StatsBridge::bootstrap_confidence_interval(
&data,
|samples| samples.iter().sum::<f64>() / samples.len() as f64, 0.95,
1000,
42,
)
.expect("Test: operation failed");
assert_relative_eq!(point_est, 5.5, epsilon = 0.1);
assert!(lower < point_est);
assert!(upper > point_est);
}
#[test]
fn test_optimization_bridge_genetic_population() {
let population = OptimizationBridge::genetic_algorithm_population(
10,
|rng| {
(0..5)
.map(|_| rng.sample(Uniform::new(0.0, 1.0).expect("Operation failed")))
.collect::<Vec<f64>>()
},
42,
);
assert_eq!(population.len(), 10);
for individual in &population {
assert_eq!(individual.len(), 5);
for &gene in individual {
assert!((0.0..=1.0).contains(&gene));
}
}
}
#[test]
fn test_experiment_design_builder() {
let design = StatsBridge::design_experiment()
.factors(&[vec![1.0, 2.0], vec![0.1, 0.2]])
.replications(3)
.randomization_seed(42)
.build()
.expect("Test: operation failed");
assert_eq!(design.design_points.len(), 4); assert_eq!(design.replications, 3);
assert_eq!(design.factor_names.len(), 2);
}
#[test]
fn test_experiment_design_builder_latin_hypercube() {
let design = StatsBridge::design_experiment()
.factors(&[
vec![1.0, 2.0, 3.0, 4.0],
vec![0.1, 0.2, 0.3],
vec![-1.0, 0.0, 1.0, 2.0, 3.0],
])
.replications(2)
.randomization_seed(2026)
.design_type(DesignType::LatinHypercube { n_points: Some(8) })
.build()
.expect("LHS builder must succeed once Latin Hypercube is implemented");
assert_eq!(design.design_points.len(), 8);
for point in &design.design_points {
assert_eq!(point.len(), 3);
}
assert_eq!(design.replications, 2);
assert_eq!(design.factor_names.len(), 3);
}
#[test]
fn test_experiment_design_builder_lhs_default_n_points() {
let design = StatsBridge::design_experiment()
.factors(&[vec![10.0, 20.0, 30.0, 40.0, 50.0], vec![1.0, 2.0]])
.randomization_seed(7)
.design_type(DesignType::LatinHypercube { n_points: None })
.build()
.expect("LHS builder must succeed with default n_points");
assert_eq!(design.design_points.len(), 5);
for point in &design.design_points {
assert_eq!(point.len(), 2);
}
}
}