1#![allow(non_snake_case)] use ndarray::{Array1, Array2};
6use rand::rngs::StdRng;
7use rand::{Rng, SeedableRng};
8
9pub fn random_uniform_array(n: usize, low: f64, high: f64) -> Array1<f64> {
11 let mut rng = rand::rng();
12
13 Array1::from_iter((0..n).map(|_| rng.random_range(low..high)))
14}
15
16pub fn random_normal_array(n: usize, mean: f64, std_dev: f64) -> Array1<f64> {
18 let mut rng = rand::rng();
19
20 Array1::from_iter((0..n).map(|_| {
22 let u1: f64 = rng.random::<f64>();
23 let u2: f64 = rng.random::<f64>();
24 let z = (-2.0 * u1.ln()).sqrt() * (2.0 * std::f64::consts::PI * u2).cos();
25 mean + std_dev * z
26 }))
27}
28
29pub fn random_uniform_matrix(rows: usize, cols: usize, low: f64, high: f64) -> Array2<f64> {
31 let mut rng = rand::rng();
32
33 Array2::from_shape_fn((rows, cols), |_| rng.random_range(low..high))
34}
35
36pub fn random_normal_matrix(rows: usize, cols: usize, mean: f64, std_dev: f64) -> Array2<f64> {
38 let mut rng = rand::rng();
39
40 Array2::from_shape_fn((rows, cols), |_| {
41 let u1: f64 = rng.random::<f64>();
42 let u2: f64 = rng.random::<f64>();
43 let z = (-2.0 * u1.ln()).sqrt() * (2.0 * std::f64::consts::PI * u2).cos();
44 mean + std_dev * z
45 })
46}
47
48pub fn random_permutation(n: usize) -> Vec<usize> {
50 let mut rng = rand::rng();
51 let mut indices: Vec<usize> = (0..n).collect();
52
53 for i in 0..n {
54 let j = rng.random_range(i..n);
55 indices.swap(i, j);
56 }
57
58 indices
59}
60
61pub fn shuffle_array<T>(arr: &mut [T]) {
63 let mut rng = rand::rng();
64
65 for i in 0..arr.len() {
66 let j = rng.random_range(i..arr.len());
67 arr.swap(i, j);
68 }
69}
70
71pub fn shuffle_rows(matrix: &mut Array2<f64>) {
73 let mut rng = rand::rng();
74 let n_rows = matrix.nrows();
75
76 for i in 0..n_rows {
77 let j = rng.random_range(i..n_rows);
78 if i != j {
79 let row_i = matrix.row(i).to_owned();
80 let row_j = matrix.row(j).to_owned();
81 matrix.row_mut(i).assign(&row_j);
82 matrix.row_mut(j).assign(&row_i);
83 }
84 }
85}
86
87pub fn bootstrap_sample(data: &Array2<f64>, n_samples: usize) -> Array2<f64> {
89 let mut rng = rand::rng();
90 let n_rows = data.nrows();
91 let n_cols = data.ncols();
92
93 let mut sample = Array2::zeros((n_samples, n_cols));
94
95 for i in 0..n_samples {
96 let idx = rng.random_range(0..n_rows);
97 sample.row_mut(i).assign(&data.row(idx));
98 }
99
100 sample
101}
102
103pub fn train_test_split(
105 data: &Array2<f64>,
106 labels: &Array1<f64>,
107 test_size: f64,
108 shuffle: bool,
109) -> (Array2<f64>, Array2<f64>, Array1<f64>, Array1<f64>) {
110 let n_samples = data.nrows();
111 let n_cols = data.ncols();
112
113 let mut data_indices: Vec<usize> = (0..n_samples).collect();
114 let mut label_indices: Vec<usize> = (0..labels.len()).collect();
115
116 if shuffle {
117 shuffle_array(&mut data_indices);
118 shuffle_array(&mut label_indices);
119 }
120
121 let split_idx = ((n_samples as f64) * (1.0 - test_size)).round() as usize;
122
123 let train_data =
124 Array2::from_shape_fn((split_idx, n_cols), |(i, j)| data[(data_indices[i], j)]);
125
126 let test_data = Array2::from_shape_fn((n_samples - split_idx, n_cols), |(i, j)| {
127 data[(data_indices[split_idx + i], j)]
128 });
129
130 let train_labels = Array1::from_iter((0..split_idx).map(|i| labels[label_indices[i]]));
131 let test_labels = Array1::from_iter((split_idx..n_samples).map(|i| labels[label_indices[i]]));
132
133 (train_data, test_data, train_labels, test_labels)
134}
135
136pub struct SeededRng {
138 rng: StdRng,
139}
140
141impl SeededRng {
142 pub fn new(seed: u64) -> Self {
144 Self {
145 rng: StdRng::seed_from_u64(seed),
146 }
147 }
148
149 pub fn uniform_array(&mut self, n: usize, low: f64, high: f64) -> Array1<f64> {
151 Array1::from_iter((0..n).map(|_| self.rng.random_range(low..high)))
152 }
153
154 pub fn normal_array(&mut self, n: usize, mean: f64, std_dev: f64) -> Array1<f64> {
156 Array1::from_iter((0..n).map(|_| {
157 let u1: f64 = self.rng.random::<f64>();
158 let u2: f64 = self.rng.random::<f64>();
159 let z = (-2.0 * u1.ln()).sqrt() * (2.0 * std::f64::consts::PI * u2).cos();
160 mean + std_dev * z
161 }))
162 }
163}
164
165pub fn random_correlation_matrix(n: usize, eigenvalues: &[f64]) -> Option<Array2<f64>> {
167 if eigenvalues.len() != n {
168 return None;
169 }
170
171 let mut rng = rand::rng();
173 let mut A = Array2::zeros((n, n));
174 for i in 0..n {
175 for j in 0..n {
176 A[(i, j)] = rng.random::<f64>() - 0.5;
177 }
178 }
179
180 let mut D = Array2::zeros((n, n));
186 for i in 0..n {
187 D[(i, i)] = eigenvalues[i].sqrt();
188 }
189
190 let AD = A.dot(&D);
192 let correlation = AD.dot(&AD.t());
193
194 let mut result = Array2::zeros((n, n));
196 for i in 0..n {
197 for j in 0..n {
198 result[(i, j)] =
199 correlation[(i, j)] / (correlation[(i, i)] * correlation[(j, j)]).sqrt();
200 }
201 }
202
203 Some(result)
204}