1use crate::error::MathError;
12use crate::traits::MatrixDimensions;
13use std::fmt::Display;
14
15pub fn evaluate_index(index: impl TryInto<i64> + Display) -> Result<i64, MathError> {
35 let index: i64 = if cfg!(debug_assertions) {
38 let index_str = index.to_string();
40 match index.try_into() {
41 Ok(index) => index,
42 _ => {
43 return Err(MathError::OutOfBounds(
44 "fit into a i64".to_owned(),
45 index_str,
46 ));
47 }
48 }
49 } else {
50 match index.try_into() {
52 Ok(index) => index,
53 _ => {
54 return Err(MathError::OutOfBounds(
55 "fit into a i64".to_owned(),
56 "rerun in debug mode to obtain the incorrect index".to_owned(),
57 ));
58 }
59 }
60 };
61
62 if index < 0 {
64 return Err(MathError::OutOfBounds(
65 "be at least zero".to_owned(),
66 index.to_string(),
67 ));
68 }
69 Ok(index)
70}
71
72pub fn evaluate_indices(
93 index1: impl TryInto<i64> + Display,
94 index2: impl TryInto<i64> + Display,
95) -> Result<(i64, i64), MathError> {
96 let index1_i64 = evaluate_index(index1)?;
97 let index2_i64 = evaluate_index(index2)?;
98
99 Ok((index1_i64, index2_i64))
100}
101
102pub fn evaluate_index_for_vector(
116 index: impl TryInto<i64> + Display,
117 vector_length: i64,
118) -> Result<i64, MathError> {
119 let mut index_i64: i64 = match index.try_into() {
120 Ok(index) => index,
121 _ => {
122 return Err(MathError::OutOfBounds(
123 "fit into a i64".to_owned(),
124 "unknown for performance reasons".to_owned(),
125 ));
126 }
127 };
128
129 if index_i64 < 0 {
130 index_i64 += vector_length;
131 if index_i64 < 0 {
132 return Err(MathError::OutOfBounds(
133 format!("be larger or equal to {}", -vector_length),
134 format!("{}", index_i64 - vector_length),
135 ));
136 }
137 }
138
139 if vector_length <= index_i64 {
140 return Err(MathError::OutOfBounds(
141 format!("be smaller than {vector_length}"),
142 format!("{index_i64}"),
143 ));
144 }
145 Ok(index_i64)
146}
147
148pub fn evaluate_indices_for_matrix<S: MatrixDimensions + MatrixDimensions>(
163 matrix: &S,
164 row: impl TryInto<i64> + Display,
165 column: impl TryInto<i64> + Display,
166) -> Result<(i64, i64), MathError> {
167 let mut row_i64: i64 = match row.try_into() {
168 Ok(index) => index,
169 _ => {
170 return Err(MathError::OutOfBounds(
171 "fit into a i64".to_owned(),
172 "unknown for performance reasons".to_owned(),
173 ));
174 }
175 };
176
177 let mut column_i64: i64 = match column.try_into() {
178 Ok(index) => index,
179 _ => {
180 return Err(MathError::OutOfBounds(
181 "fit into a i64".to_owned(),
182 "unknown for performance reasons".to_owned(),
183 ));
184 }
185 };
186
187 if row_i64 < 0 {
188 row_i64 += matrix.get_num_rows();
189 if row_i64 < 0 {
190 return Err(MathError::OutOfBounds(
191 format!(
192 "be larger or equal to ({}, {})",
193 -matrix.get_num_rows(),
194 -matrix.get_num_columns()
195 ),
196 format!("({}, {})", row_i64 - matrix.get_num_rows(), column_i64),
197 ));
198 }
199 }
200 if column_i64 < 0 {
201 column_i64 += matrix.get_num_columns();
202 if column_i64 < 0 {
203 return Err(MathError::OutOfBounds(
204 format!(
205 "be larger or equal to ({}, {})",
206 -matrix.get_num_rows(),
207 -matrix.get_num_columns()
208 ),
209 format!("({}, {})", row_i64, column_i64 - matrix.get_num_columns()),
210 ));
211 }
212 }
213
214 if matrix.get_num_rows() <= row_i64 || matrix.get_num_columns() <= column_i64 {
215 return Err(MathError::OutOfBounds(
216 format!(
217 "be smaller than ({}, {})",
218 matrix.get_num_rows(),
219 matrix.get_num_columns()
220 ),
221 format!("({row_i64}, {column_i64})"),
222 ));
223 }
224 Ok((row_i64, column_i64))
225}
226
227fn bit_reverse(mut x: usize, log_n: usize) -> usize {
229 let mut res = 0;
230 for _ in 0..log_n {
231 res = (res << 1) | (x & 1);
232 x >>= 1;
233 }
234 res
235}
236
237pub fn bit_reverse_permutation<T>(a: &mut [T]) {
255 let n = a.len();
256 let log_n = n.trailing_zeros() as usize;
257
258 for i in 0..n {
259 let rev_i = bit_reverse(i, log_n);
260 if i < rev_i {
261 a.swap(i, rev_i);
262 }
263 }
264}
265
266#[cfg(test)]
267mod test_eval_index {
268 use super::evaluate_index;
269 use crate::integer::Z;
270
271 #[test]
273 fn is_err_negative() {
274 assert!(evaluate_index(i32::MIN).is_err());
275 }
276
277 #[test]
279 fn is_ok_several_types() {
280 assert!(evaluate_index(i8::MAX).is_ok());
281 assert!(evaluate_index(i16::MAX).is_ok());
282 assert!(evaluate_index(i32::MAX).is_ok());
283 assert!(evaluate_index(i64::MAX).is_ok());
284 assert!(evaluate_index(u8::MAX).is_ok());
285 assert!(evaluate_index(u16::MAX).is_ok());
286 assert!(evaluate_index(u32::MAX).is_ok());
287
288 assert!(evaluate_index(Z::from(10)).is_ok());
289 }
290
291 #[test]
294 fn does_not_fit() {
295 assert!(evaluate_index(u64::MAX).is_err());
296 }
297}
298
299#[cfg(test)]
300mod test_eval_index_for_vector {
301 use super::evaluate_index_for_vector;
302
303 #[test]
305 fn small_negative() {
306 let a = evaluate_index_for_vector(-1, 10).expect("No error with small negative index.");
307
308 assert_eq!(a, 9);
309 }
310
311 #[test]
313 fn negative_out_of_bounds() {
314 assert!(evaluate_index_for_vector(-4, 3).is_err());
315 assert!(evaluate_index_for_vector(3, 3).is_err());
316 }
317
318 #[test]
320 fn is_ok_several_types() {
321 assert!(evaluate_index_for_vector(3i8, 4).is_ok());
322 assert!(evaluate_index_for_vector(3i16, 4).is_ok());
323 assert!(evaluate_index_for_vector(3i32, 4).is_ok());
324 assert!(evaluate_index_for_vector(3i64, 4).is_ok());
325 assert!(evaluate_index_for_vector(3u8, 4).is_ok());
326 assert!(evaluate_index_for_vector(3u16, 4).is_ok());
327 assert!(evaluate_index_for_vector(3u32, 4).is_ok());
328 assert!(evaluate_index_for_vector(3u64, 4).is_ok());
329 }
330
331 #[test]
334 fn does_not_fit() {
335 assert!(evaluate_index_for_vector(u64::MAX - 1, i64::MAX).is_err());
336 }
337}
338
339#[cfg(test)]
340mod test_eval_indices {
341 use super::evaluate_indices_for_matrix;
342 use crate::integer::MatZ;
343
344 #[test]
346 fn small_negative() {
347 let matrix = MatZ::new(10, 10);
348
349 let (a, b) = evaluate_indices_for_matrix(&matrix, -1, -10)
350 .expect("No error with small negative index.");
351
352 assert_eq!(a, 9);
353 assert_eq!(b, 0);
354 }
355
356 #[test]
359 fn negative_out_of_bounds() {
360 let matrix = MatZ::new(1, 1);
361
362 assert!(evaluate_indices_for_matrix(&matrix, 0, -2).is_err());
363 assert!(evaluate_indices_for_matrix(&matrix, -2, 0).is_err());
364 assert!(evaluate_indices_for_matrix(&matrix, -2, -2).is_err());
365 }
366
367 #[test]
369 fn is_ok_several_types() {
370 let matrix = MatZ::new(i16::MAX, u8::MAX);
371
372 assert!(evaluate_indices_for_matrix(&matrix, 3i8, 0).is_ok());
373 assert!(evaluate_indices_for_matrix(&matrix, 3i16, 0).is_ok());
374 assert!(evaluate_indices_for_matrix(&matrix, 3i32, 0).is_ok());
375 assert!(evaluate_indices_for_matrix(&matrix, 3i64, 0).is_ok());
376 assert!(evaluate_indices_for_matrix(&matrix, 3u8, 0).is_ok());
377 assert!(evaluate_indices_for_matrix(&matrix, 3u16, 0).is_ok());
378 assert!(evaluate_indices_for_matrix(&matrix, 3u32, 0).is_ok());
379 assert!(evaluate_indices_for_matrix(&matrix, 3u64, 0).is_ok());
380
381 assert!(evaluate_indices_for_matrix(&matrix, 0, 3i8).is_ok());
382 assert!(evaluate_indices_for_matrix(&matrix, 0, 3i16).is_ok());
383 assert!(evaluate_indices_for_matrix(&matrix, 0, 3i32).is_ok());
384 assert!(evaluate_indices_for_matrix(&matrix, 0, 3i64).is_ok());
385 assert!(evaluate_indices_for_matrix(&matrix, 0, 3u8).is_ok());
386 assert!(evaluate_indices_for_matrix(&matrix, 0, 3u16).is_ok());
387 assert!(evaluate_indices_for_matrix(&matrix, 0, 3u32).is_ok());
388 assert!(evaluate_indices_for_matrix(&matrix, 0, 3u64).is_ok());
389 }
390
391 #[test]
394 fn does_not_fit() {
395 let matrix = MatZ::new(3, 3);
396
397 assert!(evaluate_indices_for_matrix(&matrix, u64::MAX, 0).is_err());
398 assert!(evaluate_indices_for_matrix(&matrix, 0, u64::MAX).is_err());
399 }
400}
401
402#[cfg(test)]
403mod test_bit_reversed_order {
404 use super::bit_reverse_permutation;
405
406 #[test]
408 fn correct_new_order() {
409 let mut vec: Vec<i64> = (0..16).collect();
410 bit_reverse_permutation(&mut vec);
411 let cmp_vec = vec![0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15];
412 assert_eq!(cmp_vec, vec);
413 }
414
415 #[test]
417 fn self_inverse() {
418 let vec: Vec<usize> = (0..12332).collect();
419 let mut vec_perm = vec.clone();
420 bit_reverse_permutation(&mut vec_perm);
421 bit_reverse_permutation(&mut vec_perm);
422 assert_eq!(vec, vec_perm);
423 }
424}