diff --git a/pallets/subspace/src/math.rs b/pallets/subspace/src/math.rs index c7c7480f4..7aa156ceb 100644 --- a/pallets/subspace/src/math.rs +++ b/pallets/subspace/src/math.rs @@ -1,225 +1,46 @@ use sp_std::{vec, vec::Vec}; -use substrate_fixed::{ - transcendental::exp, - types::{I32F32, I64F64}, -}; - -#[allow(dead_code)] -pub fn bottom_k_u16(vector: &Vec, k: usize) -> Vec { - let mut vec_clone = vector.clone(); - vec_clone.sort(); // Sorting in ascending order - vec_clone.into_iter().take(k).collect() -} - -#[allow(dead_code)] -pub fn top_k_u16(vector: &Vec, k: usize) -> Vec { - let mut vec_clone = vector.clone(); - vec_clone.sort(); // Sorting in ascending order - vec_clone.into_iter().rev().take(k).collect() -} - -#[allow(dead_code)] -pub fn top_k_u64(vector: &Vec, k: usize) -> Vec { - let mut vec_clone = vector.clone(); - vec_clone.sort(); // Sorting in ascending order - vec_clone.into_iter().rev().take(k).collect() -} - -#[allow(dead_code)] -pub fn top_percentile_u16(vector: &Vec, percentile: I32F32) -> Vec { - let mut vec_clone = vector.clone(); - vec_clone.sort(); // Sorting in ascending order - let k: usize = (I32F32::from_num(vec_clone.len()) * percentile).to_num::() as usize; - vec_clone.into_iter().rev().take(k).collect() -} - -#[allow(dead_code)] -pub fn fixed(val: f32) -> I32F32 { - I32F32::from_num(val) -} - -#[allow(dead_code)] -pub fn fixed_to_u16(x: I32F32) -> u16 { - x.to_num::() -} - -#[allow(dead_code)] -pub fn fixed_to_u64(x: I32F32) -> u64 { - x.to_num::() -} - -#[allow(dead_code)] -pub fn fixed64_to_u64(x: I64F64) -> u64 { - x.to_num::() -} - -#[allow(dead_code)] -pub fn fixed64_to_fixed32(x: I64F64) -> I32F32 { - I32F32::from_num(x) -} - -#[allow(dead_code)] -pub fn u16_to_fixed(x: u16) -> I32F32 { - I32F32::from_num(x) -} - -#[allow(dead_code)] -pub fn u16_proportion_to_fixed(x: u16) -> I32F32 { - I32F32::from_num(x) / I32F32::from_num(u16::MAX) -} - -#[allow(dead_code)] -pub fn fixed_proportion_to_u16(x: I32F32) -> u16 { - fixed_to_u16(x * I32F32::from_num(u16::MAX)) -} - -#[allow(dead_code)] -pub fn vec_fixed64_to_fixed32(vec: Vec) -> Vec { - vec.into_iter().map(|e| fixed64_to_fixed32(e)).collect() -} - -#[allow(dead_code)] -pub fn vec_u16_proportions_to_fixed(vec: Vec) -> Vec { - vec.into_iter().map(|e| u16_proportion_to_fixed(e)).collect() -} - -#[allow(dead_code)] -pub fn vec_fixed_proportions_to_u16(vec: Vec) -> Vec { - vec.into_iter().map(|e| fixed_proportion_to_u16(e)).collect() -} - -#[allow(dead_code)] -pub fn sum(x: &Vec) -> I32F32 { - x.iter().sum() -} +use substrate_fixed::types::I32F32; // Return true when vector sum is zero. -#[allow(dead_code)] -pub fn is_zero(vector: &Vec) -> bool { - let vector_sum: I32F32 = sum(&vector); - vector_sum == I32F32::from_num(0) -} - -// Exp safe function with I32F32 output of I32F32 input. -#[allow(dead_code)] -pub fn exp_safe(input: I32F32) -> I32F32 { - let min_input: I32F32 = I32F32::from_num(-20); // <= 1/exp(-20) = 485 165 195,4097903 - let max_input: I32F32 = I32F32::from_num(20); // <= exp(20) = 485 165 195,4097903 - let mut safe_input: I32F32 = input; - if input < min_input { - safe_input = min_input; - } else if max_input < input { - safe_input = max_input; - } - let output: I32F32; - match exp(safe_input) { - Ok(val) => { - output = val; - } - Err(_err) => { - if safe_input <= 0 { - output = I32F32::from_num(0); - } else { - output = I32F32::max_value(); - } - } - } - output -} - -// Sigmoid safe function with I32F32 output of I32F32 input with offset kappa and (recommended) -// scaling 0 < rho <= 40. -#[allow(dead_code)] -pub fn sigmoid_safe(input: I32F32, rho: I32F32, kappa: I32F32) -> I32F32 { - let one: I32F32 = I32F32::from_num(1); - let offset: I32F32 = input.saturating_sub(kappa); // (input - kappa) - let neg_rho: I32F32 = rho.saturating_mul(-one); // -rho - let exp_input: I32F32 = neg_rho.saturating_mul(offset); // -rho*(input-kappa) - let exp_output: I32F32 = exp_safe(exp_input); // exp(-rho*(input-kappa)) - let denominator: I32F32 = exp_output.saturating_add(one); // 1 + exp(-rho*(input-kappa)) - let sigmoid_output: I32F32 = one.saturating_div(denominator); // 1 / (1 + exp(-rho*(input-kappa))) - sigmoid_output -} - -// Returns a bool vector where an item is true if the vector item is in topk values. -#[allow(dead_code)] -pub fn is_topk(vector: &Vec, k: usize) -> Vec { - let n: usize = vector.len(); - let mut result: Vec = vec![true; n]; - if n < k { - return result; - } - let mut idxs: Vec = (0..n).collect(); - idxs.sort_by_key(|&idx| &vector[idx]); // ascending stable sort - for &idx in &idxs[0..(n - k)] { - result[idx] = false; - } - result -} - -// Returns a normalized (sum to 1 except 0) copy of the input vector. -#[allow(dead_code)] -pub fn normalize(x: &Vec) -> Vec { - let x_sum: I32F32 = sum(x); - if x_sum != I32F32::from_num(0.0 as f32) { - return x.iter().map(|xi| xi / x_sum).collect(); - } else { - x.clone() - } +pub fn is_zero(vector: &[I32F32]) -> bool { + vector.iter().sum::() == I32F32::from_num(0) } // Normalizes (sum to 1 except 0) the input vector directly in-place. -#[allow(dead_code)] -pub fn inplace_normalize(x: &mut Vec) { +pub fn inplace_normalize(x: &mut [I32F32]) { let x_sum: I32F32 = x.iter().sum(); if x_sum == I32F32::from_num(0.0) { return; } - for i in 0..x.len() { - x[i] = x[i] / x_sum; + for i in x.iter_mut() { + *i /= x_sum; } } -// Normalizes (sum to 1 except 0) the I64F64 input vector directly in-place. -#[allow(dead_code)] -pub fn inplace_normalize_64(x: &mut Vec) { - let x_sum: I64F64 = x.iter().sum(); - if x_sum == I64F64::from_num(0) { - return; - } - for i in 0..x.len() { - x[i] = x[i] / x_sum; - } +pub fn u16_proportion_to_fixed(x: u16) -> I32F32 { + I32F32::from_num(x) / I32F32::from_num(u16::MAX) } -/// Returns x / y for input vectors x and y, if y == 0 return 0. -#[allow(dead_code)] -pub fn vecdiv(x: &Vec, y: &Vec) -> Vec { - assert_eq!(x.len(), y.len()); - let n = x.len(); - let mut result: Vec = vec![I32F32::from_num(0); n]; - for i in 0..n { - if y[i] != 0 { - result[i] = x[i] / y[i]; - } - } - result +pub fn fixed_proportion_to_u16(x: I32F32) -> u16 { + (x * I32F32::from_num(u16::MAX)).to_num() } -// Normalizes (sum to 1 except 0) each row (dim=0) of a matrix in-place. -#[allow(dead_code)] -pub fn inplace_row_normalize(x: &mut Vec>) { - for i in 0..x.len() { - let row_sum: I32F32 = x[i].iter().sum(); - if row_sum > I32F32::from_num(0.0 as f32) { - x[i].iter_mut().for_each(|x_ij: &mut I32F32| *x_ij /= row_sum); +// Return a new sparse matrix with a masked out diagonal of input sparse matrix. +pub fn mask_diag_sparse(sparse_matrix: &[Vec<(u16, I32F32)>]) -> Vec> { + let n: usize = sparse_matrix.len(); + let mut result: Vec> = vec![vec![]; n]; + for (i, sparse_row) in sparse_matrix.iter().enumerate() { + for (j, value) in sparse_row.iter() { + if i != (*j as usize) { + result[i].push((*j, *value)); + } } } + result } -// Normalizes (sum to 1 except 0) each row (dim=0) of a sparse matrix in-place. -#[allow(dead_code)] -pub fn inplace_row_normalize_sparse(sparse_matrix: &mut Vec>) { +/// Normalizes (sum to 1 except 0) each row (dim=0) of a sparse matrix in-place. +pub fn inplace_row_normalize_sparse(sparse_matrix: &mut [Vec<(u16, I32F32)>]) { for sparse_row in sparse_matrix.iter_mut() { let row_sum: I32F32 = sparse_row.iter().map(|(_j, value)| *value).sum(); if row_sum > I32F32::from_num(0.0) { @@ -228,1155 +49,185 @@ pub fn inplace_row_normalize_sparse(sparse_matrix: &mut Vec>) } } -// Sum across each row (dim=0) of a matrix. -#[allow(dead_code)] -pub fn row_sum(x: &Vec>) -> Vec { - if x.len() == 0 { - return vec![]; - } - if x[0].len() == 0 { - return vec![]; - } - let rows = x.len(); - let mut result: Vec = vec![I32F32::from_num(0); rows]; - for i in 0..x.len() { - for j in 0..x[i].len() { - result[i] += x[i][j]; - } - } - result -} - -// Sum across each row (dim=0) of a sparse matrix. -#[allow(dead_code)] -pub fn row_sum_sparse(sparse_matrix: &Vec>) -> Vec { - let rows = sparse_matrix.len(); - let mut result: Vec = vec![I32F32::from_num(0); rows]; - for (i, sparse_row) in sparse_matrix.iter().enumerate() { - for (_j, value) in sparse_row.iter() { - result[i] += value; - } - } - result -} - -// Sum across each column (dim=1) of a matrix. -#[allow(dead_code)] -pub fn col_sum(x: &Vec>) -> Vec { - if x.len() == 0 { - return vec![]; - } - if x[0].len() == 0 { - return vec![]; - } - let cols = x[0].len(); - let mut result: Vec = vec![I32F32::from_num(0); cols]; - for i in 0..x.len() { - assert_eq!(x[i].len(), cols); - for j in 0..cols { - result[j] += x[i][j]; - } - } - result -} +#[cfg(test)] +mod tests { + use crate::math::*; + use substrate_fixed::types::{I32F32, I64F64, I96F32}; -// Sum across each column (dim=1) of a sparse matrix. -#[allow(dead_code)] -pub fn col_sum_sparse(sparse_matrix: &Vec>, columns: u16) -> Vec { - let mut result: Vec = vec![I32F32::from_num(0); columns as usize]; - for sparse_row in sparse_matrix.iter() { - for (j, value) in sparse_row.iter() { - result[*j as usize] += value; - } + macro_rules! fixed_vec { + () => { + vec![] + }; + ($($x:expr),+ $(,)?) => { + vec![$(I32F32::from_num($x)),+] + }; } - result -} -// Normalizes (sum to 1 except 0) each column (dim=1) of a sparse matrix in-place. -#[allow(dead_code)] -pub fn inplace_col_normalize_sparse(sparse_matrix: &mut Vec>, columns: u16) { - let mut col_sum: Vec = vec![I32F32::from_num(0.0); columns as usize]; // assume square matrix, rows=cols - for sparse_row in sparse_matrix.iter() { - for (j, value) in sparse_row.iter() { - col_sum[*j as usize] += value; - } - } - for sparse_row in sparse_matrix.iter_mut() { - for (j, value) in sparse_row.iter_mut() { - if col_sum[*j as usize] == I32F32::from_num(0.0 as f32) { - continue; + /// Reshape vector to sparse matrix with specified number of input rows, cast f32 to I32F32. + fn vec_to_sparse_mat_fixed( + vector: &[f32], + rows: usize, + transpose: bool, + ) -> Vec> { + assert!( + vector.len() % rows == 0, + "Vector of len {:?} cannot reshape to {rows} rows.", + vector.len() + ); + let cols: usize = vector.len() / rows; + let mut mat: Vec> = vec![]; + if transpose { + for col in 0..cols { + let mut row_vec: Vec<(u16, I32F32)> = vec![]; + for row in 0..rows { + if vector[row * cols + col] > 0. { + row_vec.push((row as u16, I32F32::from_num(vector[row * cols + col]))); + } + } + mat.push(row_vec); + } + } else { + for row in 0..rows { + let mut row_vec: Vec<(u16, I32F32)> = vec![]; + for col in 0..cols { + if vector[row * cols + col] > 0. { + row_vec.push((col as u16, I32F32::from_num(vector[row * cols + col]))); + } + } + mat.push(row_vec); } - *value /= col_sum[*j as usize]; } + mat } -} -// Normalizes (sum to 1 except 0) each column (dim=1) of a matrix in-place. -#[allow(dead_code)] -pub fn inplace_col_normalize(x: &mut Vec>) { - if x.len() == 0 { - return; - } - if x[0].len() == 0 { - return; - } - let cols = x[0].len(); - let mut col_sum: Vec = vec![I32F32::from_num(0.0); cols]; - for i in 0..x.len() { - assert_eq!(x[i].len(), cols); - for j in 0..cols { - col_sum[j] += x[i][j]; - } - } - for j in 0..cols { - if col_sum[j] == I32F32::from_num(0.0 as f32) { - continue; - } - for i in 0..x.len() { - x[i][j] /= col_sum[j]; + /// Returns a normalized (sum to 1 except 0) copy of the input vector. + fn normalize(x: &[I32F32]) -> Vec { + let x_sum: I32F32 = x.iter().sum(); + if x_sum == I32F32::from_num(0.0) { + x.to_vec() + } else { + x.iter().map(|xi| xi / x_sum).collect() } } -} -// Apply mask to vector, mask=true will mask out, i.e. set to 0. -#[allow(dead_code)] -pub fn inplace_mask_vector(mask: &Vec, vector: &mut Vec) { - if mask.len() == 0 { - return; + fn assert_float_compare(a: I32F32, b: I32F32, epsilon: I32F32) { + assert!(I32F32::abs(a - b) <= epsilon, "a({a:?}) != b({b:?})"); } - assert_eq!(mask.len(), vector.len()); - let zero: I32F32 = I32F32::from_num(0.0); - for i in 0..mask.len() { - if mask[i] { - vector[i] = zero; + + fn assert_vec_compare(va: &[I32F32], vb: &[I32F32], epsilon: I32F32) { + assert!(va.len() == vb.len()); + for (a, b) in va.iter().zip(vb.iter()) { + assert_float_compare(*a, *b, epsilon); } } -} -// Apply mask to matrix, mask=true will mask out, i.e. set to 0. -#[allow(dead_code)] -pub fn inplace_mask_matrix(mask: &Vec>, matrix: &mut Vec>) { - if mask.len() == 0 { - return; - } - if mask[0].len() == 0 { - return; - } - assert_eq!(mask.len(), matrix.len()); - let zero: I32F32 = I32F32::from_num(0.0); - for i in 0..mask.len() { - for j in 0..mask[i].len() { - if mask[i][j] { - matrix[i][j] = zero; + fn assert_sparse_mat_compare( + ma: &[Vec<(u16, I32F32)>], + mb: &[Vec<(u16, I32F32)>], + epsilon: I32F32, + ) { + assert!(ma.len() == mb.len()); + for row in 0..ma.len() { + assert!(ma[row].len() == mb[row].len()); + for j in 0..ma[row].len() { + assert!(ma[row][j].0 == mb[row][j].0); // u16 + assert_float_compare(ma[row][j].1, mb[row][j].1, epsilon) // I32F32 } } } -} -// Apply row mask to matrix, mask=true will mask out, i.e. set to 0. -#[allow(dead_code)] -pub fn inplace_mask_rows(mask: &Vec, matrix: &mut Vec>) { - let rows = matrix.len(); - if rows == 0 { - return; - } - let cols = matrix[0].len(); - assert_eq!(mask.len(), rows); - let zero: I32F32 = I32F32::from_num(0); - for i in 0..rows { - if mask[i] { - matrix[i] = vec![zero; cols]; - } + #[test] + fn test_math_u64_normalization() { + let min: u64 = 1; + let min32: u64 = 4_889_444; // 21_000_000_000_000_000 / 4_294_967_296 + let mid: u64 = 10_500_000_000_000_000; + let max: u64 = 21_000_000_000_000_000; + let min_64: I64F64 = I64F64::from_num(min); + let min32_64: I64F64 = I64F64::from_num(min32); + let mid_64: I64F64 = I64F64::from_num(mid); + let max_64: I64F64 = I64F64::from_num(max); + let max_sum: I64F64 = I64F64::from_num(max); + let min_frac: I64F64 = min_64 / max_sum; + assert_eq!(min_frac, I64F64::from_num(0.0000000000000000476)); + let min_frac_32: I32F32 = I32F32::from_num(min_frac); + assert_eq!(min_frac_32, I32F32::from_num(0)); + let min32_frac: I64F64 = min32_64 / max_sum; + assert_eq!(min32_frac, I64F64::from_num(0.00000000023283066664)); + let min32_frac_32: I32F32 = I32F32::from_num(min32_frac); + assert_eq!(min32_frac_32, I32F32::from_num(0.0000000002)); + let half: I64F64 = mid_64 / max_sum; + assert_eq!(half, I64F64::from_num(0.5)); + let half_32: I32F32 = I32F32::from_num(half); + assert_eq!(half_32, I32F32::from_num(0.5)); + let one: I64F64 = max_64 / max_sum; + assert_eq!(one, I64F64::from_num(1)); + let one_32: I32F32 = I32F32::from_num(one); + assert_eq!(one_32, I32F32::from_num(1)); } -} -// Mask out the diagonal of the input matrix in-place. -#[allow(dead_code)] -pub fn inplace_mask_diag(matrix: &mut Vec>) { - if matrix.len() == 0 { - return; - } - if matrix[0].len() == 0 { - return; - } - assert_eq!(matrix.len(), matrix[0].len()); - let zero: I32F32 = I32F32::from_num(0.0); - for i in 0..matrix.len() { - matrix[i][i] = zero; + #[test] + fn test_math_to_num() { + let val: I32F32 = I32F32::from_num(u16::MAX); + let res: u16 = val.to_num::(); + assert_eq!(res, u16::MAX); + let vector: Vec = vec![val; 1000]; + let target: Vec = vec![u16::MAX; 1000]; + let output: Vec = vector.iter().map(|e: &I32F32| e.to_num::()).collect(); + assert_eq!(output, target); + let output: Vec = vector.iter().map(|e: &I32F32| (*e).to_num::()).collect(); + assert_eq!(output, target); + let val: I32F32 = I32F32::max_value(); + let res: u64 = val.to_num::(); + let vector: Vec = vec![val; 1000]; + let target: Vec = vec![res; 1000]; + let output: Vec = vector.iter().map(|e: &I32F32| e.to_num::()).collect(); + assert_eq!(output, target); + let output: Vec = vector.iter().map(|e: &I32F32| (*e).to_num::()).collect(); + assert_eq!(output, target); + let val: I32F32 = I32F32::from_num(0); + let res: u64 = val.to_num::(); + let vector: Vec = vec![val; 1000]; + let target: Vec = vec![res; 1000]; + let output: Vec = vector.iter().map(|e: &I32F32| e.to_num::()).collect(); + assert_eq!(output, target); + let output: Vec = vector.iter().map(|e: &I32F32| (*e).to_num::()).collect(); + assert_eq!(output, target); + let val: I96F32 = I96F32::from_num(u64::MAX); + let res: u64 = val.to_num::(); + assert_eq!(res, u64::MAX); + let vector: Vec = vec![val; 1000]; + let target: Vec = vec![u64::MAX; 1000]; + let output: Vec = vector.iter().map(|e: &I96F32| e.to_num::()).collect(); + assert_eq!(output, target); + let output: Vec = vector.iter().map(|e: &I96F32| (*e).to_num::()).collect(); + assert_eq!(output, target); } -} -// Return a new sparse matrix that replaces masked rows with an empty vector placeholder. -#[allow(dead_code)] -pub fn mask_rows_sparse( - mask: &Vec, - sparse_matrix: &Vec>, -) -> Vec> { - let n: usize = sparse_matrix.len(); - assert_eq!(n, mask.len()); - let mut result: Vec> = vec![vec![]; n]; - for (i, sparse_row) in sparse_matrix.iter().enumerate() { - if !mask[i] { - result[i] = sparse_row.clone(); - } - } - result -} - -// Return a new sparse matrix with a masked out diagonal of input sparse matrix. -#[allow(dead_code)] -pub fn mask_diag_sparse(sparse_matrix: &Vec>) -> Vec> { - let n: usize = sparse_matrix.len(); - let mut result: Vec> = vec![vec![]; n]; - for (i, sparse_row) in sparse_matrix.iter().enumerate() { - for (j, value) in sparse_row.iter() { - if i != (*j as usize) { - result[i].push((*j, *value)); - } - } - } - result -} - -// Remove cells from sparse matrix where the mask function of two vectors is true. -#[allow(dead_code)] -pub fn vec_mask_sparse_matrix( - sparse_matrix: &Vec>, - first_vector: &Vec, - second_vector: &Vec, - mask_fn: &dyn Fn(u64, u64) -> bool, -) -> Vec> { - let n: usize = sparse_matrix.len(); - let mut result: Vec> = vec![vec![]; n]; - for (i, sparse_row) in sparse_matrix.iter().enumerate() { - for (j, value) in sparse_row.iter() { - if !mask_fn(first_vector[i], second_vector[*j as usize]) { - result[i].push((*j, *value)); - } - } - } - result -} - -// Row-wise matrix-vector hadamard product. -#[allow(dead_code)] -pub fn row_hadamard(matrix: &Vec>, vector: &Vec) -> Vec> { - if matrix.len() == 0 { - return vec![vec![]]; - } - if matrix[0].len() == 0 { - return vec![vec![]]; - } - let mut result: Vec> = - vec![vec![I32F32::from_num(0.0); matrix[0].len()]; matrix.len()]; - for i in 0..matrix.len() { - for j in 0..matrix[i].len() { - result[i][j] = vector[i] * matrix[i][j]; - } - } - result -} - -// Row-wise sparse matrix-vector hadamard product. -#[allow(dead_code)] -pub fn row_hadamard_sparse( - sparse_matrix: &Vec>, - vector: &Vec, -) -> Vec> { - let mut result: Vec> = sparse_matrix.clone(); - for (i, sparse_row) in result.iter_mut().enumerate() { - for (_j, value) in sparse_row.iter_mut() { - *value *= vector[i]; - } - } - result -} - -// Row-wise matrix-vector product, column-wise sum: result_j = SUM(i) vector_i * matrix_ij. -#[allow(dead_code)] -pub fn matmul(matrix: &Vec>, vector: &Vec) -> Vec { - if matrix.len() == 0 { - return vec![]; - } - if matrix[0].len() == 0 { - return vec![]; - } - assert!(matrix.len() == vector.len()); - let mut result: Vec = vec![I32F32::from_num(0.0); matrix[0].len()]; - for i in 0..matrix.len() { - for j in 0..matrix[i].len() { - // Compute trust scores: t_j = SUM(i) w_ij * s_i - // result_j = SUM(i) vector_i * matrix_ij - result[j] += vector[i] * matrix[i][j]; - } - } - result -} - -// Column-wise matrix-vector product, row-wise sum: result_i = SUM(j) vector_j * matrix_ij. -#[allow(dead_code)] -pub fn matmul_transpose(matrix: &Vec>, vector: &Vec) -> Vec { - if matrix.len() == 0 { - return vec![]; - } - if matrix[0].len() == 0 { - return vec![]; - } - assert!(matrix[0].len() == vector.len()); - let mut result: Vec = vec![I32F32::from_num(0.0); matrix.len()]; - for i in 0..matrix.len() { - for j in 0..matrix[i].len() { - // Compute dividends: d_j = SUM(i) b_ji * inc_i - // result_j = SUM(i) vector_i * matrix_ji - // result_i = SUM(j) vector_j * matrix_ij - result[i] += vector[j] * matrix[i][j]; - } - } - result -} - -// Row-wise sparse_matrix-vector product, column-wise sum: result_j = SUM(i) vector_i * matrix_ij. -#[allow(dead_code)] -pub fn matmul_sparse( - sparse_matrix: &Vec>, - vector: &Vec, - n: u16, -) -> Vec { - let mut result: Vec = vec![I32F32::from_num(0.0); n as usize]; - for (i, sparse_row) in sparse_matrix.iter().enumerate() { - for (j, value) in sparse_row.iter() { - // Compute trust scores: t_j = SUM(i) w_ij * s_i - // result_j = SUM(i) vector_i * matrix_ij - result[*j as usize] += vector[i] * value; - } - } - result -} - -// Column-wise sparse_matrix-vector product, row-wise sum: result_i = SUM(j) vector_j * matrix_ij. -#[allow(dead_code)] -pub fn matmul_transpose_sparse( - sparse_matrix: &Vec>, - vector: &Vec, -) -> Vec { - let mut result: Vec = vec![I32F32::from_num(0.0); vector.len()]; - for (i, sparse_row) in sparse_matrix.iter().enumerate() { - for (j, value) in sparse_row.iter() { - // Compute dividends: d_j = SUM(i) b_ji * inc_i - // result_j = SUM(i) vector_i * matrix_ji - // result_i = SUM(j) vector_j * matrix_ij - result[i] += vector[*j as usize] * value; - } - } - result -} - -// Set inplace matrix values above column threshold to threshold value. -#[allow(dead_code)] -pub fn inplace_col_clip(x: &mut Vec>, col_threshold: &Vec) { - for i in 0..x.len() { - for j in 0..x[i].len() { - if x[i][j] > col_threshold[j] { - x[i][j] = col_threshold[j]; - } - } - } -} - -// Return sparse matrix with values above column threshold set to threshold value. -#[allow(dead_code)] -pub fn col_clip_sparse( - sparse_matrix: &Vec>, - col_threshold: &Vec, -) -> Vec> { - let mut result: Vec> = vec![vec![]; sparse_matrix.len()]; - for (i, sparse_row) in sparse_matrix.iter().enumerate() { - for (j, value) in sparse_row.iter() { - if col_threshold[*j as usize] < *value { - if 0 < col_threshold[*j as usize] { - result[i].push((*j, col_threshold[*j as usize])); - } - } else { - result[i].push((*j, *value)); - } - } - } - result -} - -// Set matrix values below threshold to lower, and equal-above to upper. -#[allow(dead_code)] -pub fn clip( - x: &Vec>, - threshold: I32F32, - upper: I32F32, - lower: I32F32, -) -> Vec> { - // Check Nill length. - if x.len() == 0 { - return vec![vec![]]; - } - let mut result: Vec> = vec![vec![lower; x[0].len()]; x.len()]; - for i in 0..x.len() { - for j in 0..x[i].len() { - if x[i][j] >= threshold { - result[i][j] = upper; - } - } - } - result -} - -// Set inplace matrix values below threshold to lower, and equal-above to upper. -#[allow(dead_code)] -pub fn inplace_clip(x: &mut Vec>, threshold: I32F32, upper: I32F32, lower: I32F32) { - for i in 0..x.len() { - for j in 0..x[i].len() { - if x[i][j] >= threshold { - x[i][j] = upper; - } else { - x[i][j] = lower; - } - } - } -} - -// Set sparse matrix values below threshold to lower, and equal-above to upper. -// Does not add missing elements (0 value assumed) when lower!=0. -#[allow(dead_code)] -pub fn clip_sparse( - sparse_matrix: &Vec>, - threshold: I32F32, - upper: I32F32, - lower: I32F32, -) -> Vec> { - let mut result: Vec> = vec![vec![]; sparse_matrix.len()]; - for (i, sparse_row) in sparse_matrix.iter().enumerate() { - for (j, value) in sparse_row.iter() { - if *value < threshold { - result[i].push((*j, lower)); - } else { - result[i].push((*j, upper)); - } - } - } - result -} - -// Stake-weighted median score finding algorithm, based on a mid pivot binary search. -// Normally a random pivot is used, but to ensure full determinism the mid point is chosen instead. -// Assumes relatively random score order for efficiency, typically less than O(nlogn) complexity. -// -// # Args: -// * 'stake': ( &Vec ): -// - stake, assumed to be normalized. -// -// * 'score': ( &Vec ): -// - score for which median is sought, 0 <= score <= 1 -// -// * 'partition_idx' ( &Vec ): -// - indices as input partition -// -// * 'minority' ( I32F32 ): -// - minority_ratio = 1 - majority_ratio -// -// * 'partition_lo' ( I32F32 ): -// - lower edge of stake for partition, where partition is a segment [lo, hi] inside stake -// integral [0, 1]. -// -// * 'partition_hi' ( I32F32 ): -// - higher edge of stake for partition, where partition is a segment [lo, hi] inside stake -// integral [0, 1]. -// -// # Returns: -// * 'median': ( I32F32 ): -// - median via random pivot binary search. -// -#[allow(dead_code)] -pub fn weighted_median( - stake: &Vec, - score: &Vec, - partition_idx: &Vec, - minority: I32F32, - partition_lo: I32F32, - partition_hi: I32F32, -) -> I32F32 { - let n = partition_idx.len(); - if n == 0 { - return I32F32::from_num(0); - } - if n == 1 { - return score[partition_idx[0]]; - } - assert!(stake.len() == score.len()); - let mid_idx: usize = n / 2; - let pivot: I32F32 = score[partition_idx[mid_idx]]; - let mut lo_stake: I32F32 = I32F32::from_num(0); - let mut hi_stake: I32F32 = I32F32::from_num(0); - let mut lower: Vec = vec![]; - let mut upper: Vec = vec![]; - for &idx in partition_idx.iter() { - if score[idx] == pivot { - continue; - } - if score[idx] < pivot { - lo_stake += stake[idx]; - lower.push(idx); - } else { - hi_stake += stake[idx]; - upper.push(idx); - } - } - if (partition_lo + lo_stake <= minority) && (minority < partition_hi - hi_stake) { - return pivot; - } else if (minority < partition_lo + lo_stake) && (lower.len() > 0) { - return weighted_median( - stake, - score, - &lower, - minority, - partition_lo, - partition_lo + lo_stake, - ); - } else if (partition_hi - hi_stake <= minority) && (upper.len() > 0) { - return weighted_median( - stake, - score, - &upper, - minority, - partition_hi - hi_stake, - partition_hi, - ); - } - pivot -} - -/// Column-wise weighted median, e.g. stake-weighted median scores per server (column) over all -/// validators (rows). -#[allow(dead_code)] -pub fn weighted_median_col( - stake: &Vec, - score: &Vec>, - majority: I32F32, -) -> Vec { - let rows = stake.len(); - let columns = score[0].len(); - let zero: I32F32 = I32F32::from_num(0); - let mut median: Vec = vec![zero; columns]; - for c in 0..columns { - let mut use_stake: Vec = vec![]; - let mut use_score: Vec = vec![]; - for r in 0..rows { - assert_eq!(columns, score[r].len()); - if stake[r] > zero { - use_stake.push(stake[r]); - use_score.push(score[r][c]); - } - } - if use_stake.len() > 0 { - inplace_normalize(&mut use_stake); - let stake_sum: I32F32 = use_stake.iter().sum(); - let minority: I32F32 = stake_sum - majority; - median[c] = weighted_median( - &use_stake, - &use_score, - &(0..use_stake.len()).collect(), - minority, - zero, - stake_sum, - ); - } - } - median -} - -/// Column-wise weighted median, e.g. stake-weighted median scores per server (column) over all -/// validators (rows). -#[allow(dead_code)] -pub fn weighted_median_col_sparse( - stake: &Vec, - score: &Vec>, - columns: u16, - majority: I32F32, -) -> Vec { - let rows = stake.len(); - let zero: I32F32 = I32F32::from_num(0); - let mut use_stake: Vec = stake.iter().copied().filter(|&s| s > zero).collect(); - inplace_normalize(&mut use_stake); - let stake_sum: I32F32 = use_stake.iter().sum(); - let stake_idx: Vec = (0..use_stake.len()).collect(); - let minority: I32F32 = stake_sum - majority; - let mut use_score: Vec> = vec![vec![zero; use_stake.len()]; columns as usize]; - let mut median: Vec = vec![zero; columns as usize]; - let mut k: usize = 0; - for r in 0..rows { - if stake[r] <= zero { - continue; - } - for (c, val) in score[r].iter() { - use_score[*c as usize][k] = *val; - } - k += 1; - } - for c in 0..columns as usize { - median[c] = weighted_median( - &use_stake, - &use_score[c], - &stake_idx, - minority, - zero, - stake_sum, - ); - } - median -} - -// Element-wise product of two matrices. -#[allow(dead_code)] -pub fn hadamard(mat1: &Vec>, mat2: &Vec>) -> Vec> { - assert!(mat1.len() == mat2.len()); - if mat1.len() == 0 { - return vec![vec![]; 1]; - } - if mat1[0].len() == 0 { - return vec![vec![]; 1]; - } - let mut result: Vec> = vec![vec![I32F32::from_num(0); mat1[0].len()]; mat1.len()]; - for i in 0..mat1.len() { - assert!(mat1[i].len() == mat2[i].len()); - for j in 0..mat1[i].len() { - result[i][j] = mat1[i][j] * mat2[i][j]; - } - } - result -} - -// Element-wise product of two sparse matrices. -#[allow(dead_code)] -pub fn hadamard_sparse( - mat1: &Vec>, - mat2: &Vec>, - columns: u16, -) -> Vec> { - assert!(mat1.len() == mat2.len()); - let rows = mat1.len(); - let zero: I32F32 = I32F32::from_num(0); - let mut result: Vec> = vec![vec![]; rows]; - for i in 0..rows { - let mut row1: Vec = vec![zero; columns as usize]; - for (j, value) in mat1[i].iter() { - row1[*j as usize] += value; - } - let mut row2: Vec = vec![zero; columns as usize]; - for (j, value) in mat2[i].iter() { - row2[*j as usize] += value; - } - for j in 0..columns as usize { - let prod: I32F32 = row1[j] * row2[j]; - if zero < prod { - result[i].push((j as u16, prod)) - } - } - } - result -} - -// Return matrix exponential moving average: `alpha * a_ij + one_minus_alpha * b_ij`. -// `alpha` is the EMA coefficient, how much to add of the new observation, typically small, -// higher alpha discounts older observations faster. -#[allow(dead_code)] -pub fn mat_ema(new: &Vec>, old: &Vec>, alpha: I32F32) -> Vec> { - if new.len() == 0 { - return vec![vec![]; 1]; - } - if new[0].len() == 0 { - return vec![vec![]; 1]; - } - let one_minus_alpha: I32F32 = I32F32::from_num(1.0) - alpha; - let mut result: Vec> = vec![vec![I32F32::from_num(0.0); new[0].len()]; new.len()]; - assert!(new.len() == old.len()); - for i in 0..new.len() { - assert!(new[i].len() == old[i].len()); - for j in 0..new[i].len() { - result[i][j] = alpha * new[i][j] + one_minus_alpha * old[i][j] - } - } - result -} - -// Return sparse matrix exponential moving average: `alpha * a_ij + one_minus_alpha * b_ij`. -// `alpha` is the EMA coefficient, how much to add of the new observation, typically small, -// higher alpha discounts older observations faster. -#[allow(dead_code)] -pub fn mat_ema_sparse( - new: &Vec>, - old: &Vec>, - alpha: I32F32, -) -> Vec> { - assert!(new.len() == old.len()); - let n = new.len(); // assume square matrix, rows=cols - let zero: I32F32 = I32F32::from_num(0.0); - let one_minus_alpha: I32F32 = I32F32::from_num(1.0) - alpha; - let mut result: Vec> = vec![vec![]; n]; - for i in 0..new.len() { - let mut row: Vec = vec![zero; n]; - for (j, value) in new[i].iter() { - row[*j as usize] += alpha * value; - } - for (j, value) in old[i].iter() { - row[*j as usize] += one_minus_alpha * value; - } - for (j, value) in row.iter().enumerate() { - if *value > zero { - result[i].push((j as u16, *value)) - } - } - } - result -} - -// Return sparse matrix only with elements >= threshold of an input sparse matrix. -#[allow(dead_code)] -pub fn sparse_threshold(w: &Vec>, threshold: I32F32) -> Vec> { - let mut sparse_threshold_result: Vec> = vec![vec![]; w.len()]; - for (uid_i, weights_i) in w.iter().enumerate() { - for (uid_j, weight_ij) in weights_i.iter() { - if *weight_ij >= threshold { - sparse_threshold_result[uid_i as usize].push((*uid_j, *weight_ij)); - } - } - } - sparse_threshold_result -} - -#[cfg(test)] -mod tests { - use crate::math::*; - use rand::{seq::SliceRandom, thread_rng, Rng}; - use substrate_fixed::{ - transcendental::exp, - types::{I32F32, I64F64, I96F32}, - }; - - fn assert_float_compare(a: I32F32, b: I32F32, epsilon: I32F32) { - assert!(I32F32::abs(a - b) <= epsilon, "a({:?}) != b({:?})", a, b); - } - - fn assert_float_compare_64(a: I64F64, b: I64F64, epsilon: I64F64) { - assert!(I64F64::abs(a - b) <= epsilon, "a({:?}) != b({:?})", a, b); - } - - fn assert_vec_compare(va: &Vec, vb: &Vec, epsilon: I32F32) { - assert!(va.len() == vb.len()); - for i in 0..va.len() { - assert_float_compare(va[i], vb[i], epsilon); - } - } - - fn assert_vec_compare_64(va: &Vec, vb: &Vec, epsilon: I64F64) { - assert!(va.len() == vb.len()); - for i in 0..va.len() { - assert_float_compare_64(va[i], vb[i], epsilon); - } - } - - fn assert_mat_compare(ma: &Vec>, mb: &Vec>, epsilon: I32F32) { - assert!(ma.len() == mb.len()); - for row in 0..ma.len() { - assert!(ma[row].len() == mb[row].len()); - for col in 0..ma[row].len() { - assert_float_compare(ma[row][col], mb[row][col], epsilon) - } - } - } - - fn assert_sparse_mat_compare( - ma: &Vec>, - mb: &Vec>, - epsilon: I32F32, - ) { - assert!(ma.len() == mb.len()); - for row in 0..ma.len() { - assert!(ma[row].len() == mb[row].len()); - for j in 0..ma[row].len() { - assert!(ma[row][j].0 == mb[row][j].0); // u16 - assert_float_compare(ma[row][j].1, mb[row][j].1, epsilon) // I32F32 - } - } - } - - fn vec_to_fixed(vector: &Vec) -> Vec { - vector.iter().map(|x| I32F32::from_num(*x)).collect() - } - - #[test] - fn test_math_u64_normalization() { - let min: u64 = 1; - let min32: u64 = 4_889_444; // 21_000_000_000_000_000 / 4_294_967_296 - let mid: u64 = 10_500_000_000_000_000; - let max: u64 = 21_000_000_000_000_000; - let min_64: I64F64 = I64F64::from_num(min); - let min32_64: I64F64 = I64F64::from_num(min32); - let mid_64: I64F64 = I64F64::from_num(mid); - let max_64: I64F64 = I64F64::from_num(max); - let max_sum: I64F64 = I64F64::from_num(max); - let min_frac: I64F64 = min_64 / max_sum; - assert_eq!(min_frac, I64F64::from_num(0.0000000000000000476)); - let min_frac_32: I32F32 = I32F32::from_num(min_frac); - assert_eq!(min_frac_32, I32F32::from_num(0)); - let min32_frac: I64F64 = min32_64 / max_sum; - assert_eq!(min32_frac, I64F64::from_num(0.00000000023283066664)); - let min32_frac_32: I32F32 = I32F32::from_num(min32_frac); - assert_eq!(min32_frac_32, I32F32::from_num(0.0000000002)); - let half: I64F64 = mid_64 / max_sum; - assert_eq!(half, I64F64::from_num(0.5)); - let half_32: I32F32 = I32F32::from_num(half); - assert_eq!(half_32, I32F32::from_num(0.5)); - let one: I64F64 = max_64 / max_sum; - assert_eq!(one, I64F64::from_num(1)); - let one_32: I32F32 = I32F32::from_num(one); - assert_eq!(one_32, I32F32::from_num(1)); - } - - #[test] - fn test_math_to_num() { - let val: I32F32 = I32F32::from_num(u16::MAX); - let res: u16 = val.to_num::(); - assert_eq!(res, u16::MAX); - let vector: Vec = vec![val; 1000]; - let target: Vec = vec![u16::MAX; 1000]; - let output: Vec = vector.iter().map(|e: &I32F32| e.to_num::()).collect(); - assert_eq!(output, target); - let output: Vec = vector.iter().map(|e: &I32F32| (*e).to_num::()).collect(); - assert_eq!(output, target); - let val: I32F32 = I32F32::max_value(); - let res: u64 = val.to_num::(); - let vector: Vec = vec![val; 1000]; - let target: Vec = vec![res; 1000]; - let output: Vec = vector.iter().map(|e: &I32F32| e.to_num::()).collect(); - assert_eq!(output, target); - let output: Vec = vector.iter().map(|e: &I32F32| (*e).to_num::()).collect(); - assert_eq!(output, target); - let val: I32F32 = I32F32::from_num(0); - let res: u64 = val.to_num::(); - let vector: Vec = vec![val; 1000]; - let target: Vec = vec![res; 1000]; - let output: Vec = vector.iter().map(|e: &I32F32| e.to_num::()).collect(); - assert_eq!(output, target); - let output: Vec = vector.iter().map(|e: &I32F32| (*e).to_num::()).collect(); - assert_eq!(output, target); - let val: I96F32 = I96F32::from_num(u64::MAX); - let res: u64 = val.to_num::(); - assert_eq!(res, u64::MAX); - let vector: Vec = vec![val; 1000]; - let target: Vec = vec![u64::MAX; 1000]; - let output: Vec = vector.iter().map(|e: &I96F32| e.to_num::()).collect(); - assert_eq!(output, target); - let output: Vec = vector.iter().map(|e: &I96F32| (*e).to_num::()).collect(); - assert_eq!(output, target); - } - - #[test] - fn test_math_vec_to_fixed() { - let vector: Vec = vec![0., 1., 2., 3.]; - let target: Vec = vec![ - I32F32::from_num(0.), - I32F32::from_num(1.), - I32F32::from_num(2.), - I32F32::from_num(3.), - ]; - let result = vec_to_fixed(&vector); - assert_vec_compare(&result, &target, I32F32::from_num(0)); - } - - // Reshape vector to matrix with specified number of rows, cast to I32F32. - fn vec_to_mat_fixed(vector: &Vec, rows: usize, transpose: bool) -> Vec> { - assert!( - vector.len() % rows == 0, - "Vector of len {:?} cannot reshape to {rows} rows.", - vector.len() - ); - let cols: usize = vector.len() / rows; - let mut mat: Vec> = vec![]; - if transpose { - for col in 0..cols as usize { - let mut vals: Vec = vec![]; - for row in 0..rows as usize { - vals.push(I32F32::from_num(vector[row * cols + col])); - } - mat.push(vals); - } - } else { - for row in 0..rows as usize { - mat.push( - vector[row * cols..(row + 1) * cols] - .iter() - .map(|v| I32F32::from_num(*v)) - .collect(), - ); - } - } - mat - } - - #[test] - fn test_math_vec_to_mat_fixed() { - let vector: Vec = vec![0., 1., 2., 0., 10., 100.]; - let target: Vec> = vec![ - vec![ - I32F32::from_num(0.), - I32F32::from_num(1.), - I32F32::from_num(2.), - ], - vec![ - I32F32::from_num(0.), - I32F32::from_num(10.), - I32F32::from_num(100.), - ], - ]; - let mat = vec_to_mat_fixed(&vector, 2, false); - assert_mat_compare(&mat, &target, I32F32::from_num(0)); - } - - // Reshape vector to sparse matrix with specified number of input rows, cast f32 to I32F32. - fn vec_to_sparse_mat_fixed( - vector: &Vec, - rows: usize, - transpose: bool, - ) -> Vec> { - assert!( - vector.len() % rows == 0, - "Vector of len {:?} cannot reshape to {rows} rows.", - vector.len() - ); - let cols: usize = vector.len() / rows; - let mut mat: Vec> = vec![]; - if transpose { - for col in 0..cols as usize { - let mut row_vec: Vec<(u16, I32F32)> = vec![]; - for row in 0..rows as usize { - if vector[row * cols + col] > 0. { - row_vec.push((row as u16, I32F32::from_num(vector[row * cols + col]))); - } - } - mat.push(row_vec); - } - } else { - for row in 0..rows as usize { - let mut row_vec: Vec<(u16, I32F32)> = vec![]; - for col in 0..cols as usize { - if vector[row * cols + col] > 0. { - row_vec.push((col as u16, I32F32::from_num(vector[row * cols + col]))); - } - } - mat.push(row_vec); - } - } - mat - } - - #[test] - fn test_math_vec_to_sparse_mat_fixed() { - let vector: Vec = vec![0., 1., 2., 0., 10., 100.]; - let target: Vec> = vec![ - vec![ - (1 as u16, I32F32::from_num(1.)), - (2 as u16, I32F32::from_num(2.)), - ], - vec![ - (1 as u16, I32F32::from_num(10.)), - (2 as u16, I32F32::from_num(100.)), - ], - ]; - let mat = vec_to_sparse_mat_fixed(&vector, 2, false); - assert_sparse_mat_compare(&mat, &target, I32F32::from_num(0)); - let vector: Vec = vec![0., 0.]; - let target: Vec> = vec![vec![], vec![]]; - let mat = vec_to_sparse_mat_fixed(&vector, 2, false); - assert_sparse_mat_compare(&mat, &target, I32F32::from_num(0)); - let vector: Vec = vec![0., 1., 2., 0., 10., 100.]; - let target: Vec> = vec![ - vec![], - vec![ - (0 as u16, I32F32::from_num(1.)), - (1 as u16, I32F32::from_num(10.)), - ], - vec![ - (0 as u16, I32F32::from_num(2.)), - (1 as u16, I32F32::from_num(100.)), - ], - ]; - let mat = vec_to_sparse_mat_fixed(&vector, 2, true); - assert_sparse_mat_compare(&mat, &target, I32F32::from_num(0)); - let vector: Vec = vec![0., 0.]; - let target: Vec> = vec![vec![]]; - let mat = vec_to_sparse_mat_fixed(&vector, 2, true); - assert_sparse_mat_compare(&mat, &target, I32F32::from_num(0)); - } - - #[test] - fn test_math_exp_safe() { - let zero: I32F32 = I32F32::from_num(0); - let one: I32F32 = I32F32::from_num(1); - let target: I32F32 = exp(zero).unwrap(); - assert_eq!(exp_safe(zero), target); - let target: I32F32 = exp(one).unwrap(); - assert_eq!(exp_safe(one), target); - let min_input: I32F32 = I32F32::from_num(-20); // <= 1/exp(-20) = 485 165 195,4097903 - let max_input: I32F32 = I32F32::from_num(20); // <= exp(20) = 485 165 195,4097903 - let target: I32F32 = exp(min_input).unwrap(); - assert_eq!(exp_safe(min_input), target); - assert_eq!(exp_safe(min_input - one), target); - assert_eq!(exp_safe(I32F32::min_value()), target); - let target: I32F32 = exp(max_input).unwrap(); - assert_eq!(exp_safe(max_input), target); - assert_eq!(exp_safe(max_input + one), target); - assert_eq!(exp_safe(I32F32::max_value()), target); - } - - #[test] - fn test_math_sigmoid_safe() { - let trust: Vec = vec![ - I32F32::min_value(), - I32F32::from_num(0), - I32F32::from_num(0.4), - I32F32::from_num(0.5), - I32F32::from_num(0.6), - I32F32::from_num(1), - I32F32::max_value(), - ]; - let consensus: Vec = trust - .iter() - .map(|t: &I32F32| sigmoid_safe(*t, I32F32::max_value(), I32F32::max_value())) - .collect(); - let target: Vec = vec_to_fixed(&vec![ - 0.0000000019, - 0.0000000019, - 0.0000000019, - 0.0000000019, - 0.0000000019, - 0.0000000019, - 0.5, - ]); - assert_eq!(&consensus, &target); - let consensus: Vec = trust - .iter() - .map(|t: &I32F32| sigmoid_safe(*t, I32F32::min_value(), I32F32::min_value())) - .collect(); - let target: Vec = vec_to_fixed(&vec![ - 0.5, - 0.0000000019, - 0.0000000019, - 0.0000000019, - 0.0000000019, - 0.0000000019, - 0.0000000019, - ]); - assert_eq!(&consensus, &target); - let consensus: Vec = trust - .iter() - .map(|t: &I32F32| sigmoid_safe(*t, I32F32::from_num(30), I32F32::from_num(0.5))) - .collect(); - let target: Vec = vec![ - 0.0000000019, - 0.0000003057, - 0.0474258729, - 0.5, - 0.952574127, - 0.9999996943, - 0.9999999981, - ]; - let target: Vec = target.iter().map(|c: &f64| I32F32::from_num(*c)).collect(); - assert_eq!(&consensus, &target); - let trust: Vec = - vec_to_fixed(&vec![0., 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.]); - let consensus: Vec = trust - .iter() - .map(|t: &I32F32| sigmoid_safe(*t, I32F32::from_num(40), I32F32::from_num(0.5))) - .collect(); - let target: Vec = vec![ - 0.0000000019, - 0.0000001125, - 0.0000061442, - 0.0003353502, - 0.017986214, - 0.5, - 0.9820138067, - 0.9996646498, - 0.9999938558, - 0.9999998875, - 0.9999999981, - ]; - let target: Vec = target.iter().map(|c: &f64| I32F32::from_num(*c)).collect(); - assert_eq!(&consensus, &target); - } - - #[test] - fn test_math_is_topk() { - let vector: Vec = vec_to_fixed(&vec![]); - let result = is_topk(&vector, 5); - let target: Vec = vec![]; - assert_eq!(&result, &target); - let vector: Vec = vec_to_fixed(&vec![0., 1., 2., 3., 4., 5., 6., 7., 8., 9.]); - let result = is_topk(&vector, 0); - let target: Vec = vec![ - false, false, false, false, false, false, false, false, false, false, - ]; - assert_eq!(&result, &target); - let result = is_topk(&vector, 5); - let target: Vec = vec![ - false, false, false, false, false, true, true, true, true, true, - ]; - assert_eq!(&result, &target); - let result = is_topk(&vector, 10); - let target: Vec = vec![true, true, true, true, true, true, true, true, true, true]; - assert_eq!(&result, &target); - let result = is_topk(&vector, 100); - assert_eq!(&result, &target); - let vector: Vec = vec_to_fixed(&vec![9., 8., 7., 6., 5., 4., 3., 2., 1., 0.]); - let result = is_topk(&vector, 5); - let target: Vec = vec![ - true, true, true, true, true, false, false, false, false, false, - ]; - assert_eq!(&result, &target); - let vector: Vec = vec_to_fixed(&vec![9., 0., 8., 1., 7., 2., 6., 3., 5., 4.]); - let result = is_topk(&vector, 5); - let target: Vec = vec![ - true, false, true, false, true, false, true, false, true, false, - ]; - assert_eq!(&result, &target); - let vector: Vec = - vec_to_fixed(&vec![0.9, 0., 0.8, 0.1, 0.7, 0.2, 0.6, 0.3, 0.5, 0.4]); - let result = is_topk(&vector, 5); - let target: Vec = vec![ - true, false, true, false, true, false, true, false, true, false, - ]; - assert_eq!(&result, &target); - let vector: Vec = vec_to_fixed(&vec![0., 1., 2., 3., 4., 5., 5., 5., 5., 6.]); - let result = is_topk(&vector, 5); - let target: Vec = vec![ - false, false, false, false, false, true, true, true, true, true, - ]; - assert_eq!(&result, &target); - } - - #[test] - fn test_math_sum() { - assert!(sum(&vec![]) == I32F32::from_num(0)); - assert!( - sum(&vec![ - I32F32::from_num(1.0), - I32F32::from_num(10.0), - I32F32::from_num(30.0) - ]) == I32F32::from_num(41) - ); - assert!( - sum(&vec![ - I32F32::from_num(-1.0), - I32F32::from_num(10.0), - I32F32::from_num(30.0) - ]) == I32F32::from_num(39) - ); + #[test] + fn test_math_vec_to_sparse_mat_fixed() { + let vector: Vec = vec![0., 1., 2., 0., 10., 100.]; + let target: Vec> = vec![ + vec![(1, I32F32::from_num(1.)), (2, I32F32::from_num(2.))], + vec![(1, I32F32::from_num(10.)), (2, I32F32::from_num(100.))], + ]; + let mat = vec_to_sparse_mat_fixed(&vector, 2, false); + assert_sparse_mat_compare(&mat, &target, I32F32::from_num(0)); + let vector: Vec = vec![0., 0.]; + let target: Vec> = vec![vec![], vec![]]; + let mat = vec_to_sparse_mat_fixed(&vector, 2, false); + assert_sparse_mat_compare(&mat, &target, I32F32::from_num(0)); + let vector: Vec = vec![0., 1., 2., 0., 10., 100.]; + let target: Vec> = vec![ + vec![], + vec![(0, I32F32::from_num(1.)), (1, I32F32::from_num(10.))], + vec![(0, I32F32::from_num(2.)), (1, I32F32::from_num(100.))], + ]; + let mat = vec_to_sparse_mat_fixed(&vector, 2, true); + assert_sparse_mat_compare(&mat, &target, I32F32::from_num(0)); + let vector: Vec = vec![0., 0.]; + let target: Vec> = vec![vec![]]; + let mat = vec_to_sparse_mat_fixed(&vector, 2, true); + assert_sparse_mat_compare(&mat, &target, I32F32::from_num(0)); } #[test] @@ -1385,370 +236,81 @@ mod tests { let x: Vec = vec![]; let y: Vec = normalize(&x); assert_vec_compare(&x, &y, epsilon); - let x: Vec = vec![ - I32F32::from_num(1.0), - I32F32::from_num(10.0), - I32F32::from_num(30.0), - ]; + let x: Vec = fixed_vec![1.0, 10.0, 30.0,]; let y: Vec = normalize(&x); assert_vec_compare( &y, - &vec![ + &[ I32F32::from_num(0.0243902437), I32F32::from_num(0.243902439), I32F32::from_num(0.7317073171), ], epsilon, ); - assert_float_compare(sum(&y), I32F32::from_num(1.0), epsilon); - let x: Vec = vec![ - I32F32::from_num(-1.0), - I32F32::from_num(10.0), - I32F32::from_num(30.0), - ]; + assert_float_compare(y.iter().sum(), I32F32::from_num(1.0), epsilon); + let x: Vec = fixed_vec![-1.0, 10.0, 30.0]; let y: Vec = normalize(&x); assert_vec_compare( &y, - &vec![ - I32F32::from_num(-0.0256410255), - I32F32::from_num(0.2564102563), - I32F32::from_num(0.769230769), - ], - epsilon, - ); - assert_float_compare(sum(&y), I32F32::from_num(1.0), epsilon); - } - - #[test] - fn test_math_inplace_normalize() { - let epsilon: I32F32 = I32F32::from_num(0.0001); - let mut x1: Vec = vec![ - I32F32::from_num(1.0), - I32F32::from_num(10.0), - I32F32::from_num(30.0), - ]; - inplace_normalize(&mut x1); - assert_vec_compare( - &x1, - &vec![ - I32F32::from_num(0.0243902437), - I32F32::from_num(0.243902439), - I32F32::from_num(0.7317073171), - ], - epsilon, - ); - let mut x2: Vec = vec![ - I32F32::from_num(-1.0), - I32F32::from_num(10.0), - I32F32::from_num(30.0), - ]; - inplace_normalize(&mut x2); - assert_vec_compare( - &x2, - &vec![ + &[ I32F32::from_num(-0.0256410255), I32F32::from_num(0.2564102563), I32F32::from_num(0.769230769), ], epsilon, ); + assert_float_compare(y.iter().sum(), I32F32::from_num(1.0), epsilon); } #[test] - fn test_math_inplace_normalize_64() { - let epsilon: I64F64 = I64F64::from_num(0.0001); - let mut x1: Vec = vec![ - I64F64::from_num(1.0), - I64F64::from_num(10.0), - I64F64::from_num(30.0), - ]; - inplace_normalize_64(&mut x1); - assert_vec_compare_64( - &x1, - &vec![ - I64F64::from_num(0.0243902437), - I64F64::from_num(0.243902439), - I64F64::from_num(0.7317073171), - ], - epsilon, - ); - let mut x2: Vec = vec![ - I64F64::from_num(-1.0), - I64F64::from_num(10.0), - I64F64::from_num(30.0), - ]; - inplace_normalize_64(&mut x2); - assert_vec_compare_64( - &x2, - &vec![ - I64F64::from_num(-0.0256410255), - I64F64::from_num(0.2564102563), - I64F64::from_num(0.769230769), - ], - epsilon, - ); - } - - #[test] - fn test_math_vecdiv() { - let x: Vec = vec_to_fixed(&vec![]); - let y: Vec = vec_to_fixed(&vec![]); - let result: Vec = vec_to_fixed(&vec![]); - assert_eq!(result, vecdiv(&x, &y)); - - let x: Vec = vec_to_fixed(&vec![0., 1., 0., 1.]); - let y: Vec = vec_to_fixed(&vec![0., 1., 1., 0.]); - let result: Vec = vec_to_fixed(&vec![0., 1., 0., 0.]); - assert_eq!(result, vecdiv(&x, &y)); - - let x: Vec = vec_to_fixed(&vec![1., 1., 10.]); - let y: Vec = vec_to_fixed(&vec![2., 3., 2.]); - let result: Vec = vec![fixed(1.) / fixed(2.), fixed(1.) / fixed(3.), fixed(5.)]; - assert_eq!(result, vecdiv(&x, &y)); - } - - #[test] - fn test_math_inplace_row_normalize() { - let epsilon: I32F32 = I32F32::from_num(0.0001); - let vector: Vec = vec![ - 0., 1., 2., 3., 4., 0., 10., 100., 1000., 10000., 0., 0., 0., 0., 0., 1., 1., 1., 1., - 1., - ]; - let mut mat = vec_to_mat_fixed(&vector, 4, false); - inplace_row_normalize(&mut mat); - let target: Vec = vec![ - 0., 0.1, 0.2, 0.3, 0.4, 0., 0.0009, 0.009, 0.09, 0.9, 0., 0., 0., 0., 0., 0.2, 0.2, - 0.2, 0.2, 0.2, - ]; - assert_mat_compare(&mat, &vec_to_mat_fixed(&target, 4, false), epsilon); - } - - #[test] - fn test_math_inplace_row_normalize_sparse() { - let epsilon: I32F32 = I32F32::from_num(0.0001); - let vector: Vec = vec![ - 0., 1., 0., 2., 0., 3., 4., 0., 1., 0., 2., 0., 3., 0., 1., 0., 0., 2., 0., 3., 4., 0., - 10., 0., 100., 1000., 0., 10000., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 1., 1., 1., - 1., - ]; - let mut mat = vec_to_sparse_mat_fixed(&vector, 6, false); - inplace_row_normalize_sparse(&mut mat); - let target: Vec = vec![ - 0., 0.1, 0., 0.2, 0., 0.3, 0.4, 0., 0.166666, 0., 0.333333, 0., 0.5, 0., 0.1, 0., 0., - 0.2, 0., 0.3, 0.4, 0., 0.0009, 0., 0.009, 0.09, 0., 0.9, 0., 0., 0., 0., 0., 0., 0., - 0.142857, 0.142857, 0.142857, 0.142857, 0.142857, 0.142857, 0.142857, - ]; - assert_sparse_mat_compare(&mat, &vec_to_sparse_mat_fixed(&target, 6, false), epsilon); - let vector: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let mut mat = vec_to_sparse_mat_fixed(&vector, 3, false); - inplace_row_normalize_sparse(&mut mat); - assert_sparse_mat_compare( - &mat, - &vec_to_sparse_mat_fixed(&target, 3, false), - I32F32::from_num(0), - ); - } - - #[test] - fn test_math_inplace_col_normalize() { - let epsilon: I32F32 = I32F32::from_num(0.0001); - let vector: Vec = vec![ - 0., 1., 2., 3., 4., 0., 10., 100., 1000., 10000., 0., 0., 0., 0., 0., 1., 1., 1., 1., - 1., - ]; - let mut mat = vec_to_mat_fixed(&vector, 4, true); - inplace_col_normalize(&mut mat); - let target: Vec = vec![ - 0., 0.1, 0.2, 0.3, 0.4, 0., 0.0009, 0.009, 0.09, 0.9, 0., 0., 0., 0., 0., 0.2, 0.2, - 0.2, 0.2, 0.2, - ]; - assert_mat_compare(&mat, &vec_to_mat_fixed(&target, 4, true), epsilon); - } - - #[test] - fn test_math_inplace_col_normalize_sparse() { - let epsilon: I32F32 = I32F32::from_num(0.0001); - let vector: Vec = vec![ - 0., 1., 0., 2., 0., 3., 4., 0., 1., 0., 2., 0., 3., 0., 1., 0., 0., 2., 0., 3., 4., 0., - 10., 0., 100., 1000., 0., 10000., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 1., 1., 1., - 1., - ]; - let mut mat = vec_to_sparse_mat_fixed(&vector, 6, true); - inplace_col_normalize_sparse(&mut mat, 6); - let target: Vec = vec![ - 0., 0.1, 0., 0.2, 0., 0.3, 0.4, 0., 0.166666, 0., 0.333333, 0., 0.5, 0., 0.1, 0., 0., - 0.2, 0., 0.3, 0.4, 0., 0.0009, 0., 0.009, 0.09, 0., 0.9, 0., 0., 0., 0., 0., 0., 0., - 0.142857, 0.142857, 0.142857, 0.142857, 0.142857, 0.142857, 0.142857, - ]; - assert_sparse_mat_compare(&mat, &vec_to_sparse_mat_fixed(&target, 6, true), epsilon); - let vector: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let mut mat = vec_to_sparse_mat_fixed(&vector, 3, false); - inplace_col_normalize_sparse(&mut mat, 6); - assert_sparse_mat_compare( - &mat, - &vec_to_sparse_mat_fixed(&target, 3, false), - I32F32::from_num(0), - ); - let mut mat: Vec> = vec![]; - let target: Vec> = vec![]; - inplace_col_normalize_sparse(&mut mat, 0); - assert_sparse_mat_compare(&mat, &target, epsilon); - } - - #[test] - fn test_math_inplace_mask_vector() { - let mask: Vec = vec![false, false, false]; - let mut vector: Vec = vec_to_fixed(&vec![0., 1., 2.]); - let target: Vec = vec_to_fixed(&vec![0., 1., 2.]); - inplace_mask_vector(&mask, &mut vector); - assert_vec_compare(&vector, &target, I32F32::from_num(0)); - let mask: Vec = vec![false, true, false]; - let mut vector: Vec = vec_to_fixed(&vec![0., 1., 2.]); - let target: Vec = vec_to_fixed(&vec![0., 0., 2.]); - inplace_mask_vector(&mask, &mut vector); - assert_vec_compare(&vector, &target, I32F32::from_num(0)); - let mask: Vec = vec![true, true, true]; - let mut vector: Vec = vec_to_fixed(&vec![0., 1., 2.]); - let target: Vec = vec_to_fixed(&vec![0., 0., 0.]); - inplace_mask_vector(&mask, &mut vector); - assert_vec_compare(&vector, &target, I32F32::from_num(0)); - } - - #[test] - fn test_math_inplace_mask_matrix() { - let mask: Vec> = vec![ - vec![false, false, false], - vec![false, false, false], - vec![false, false, false], - ]; - let vector: Vec = vec![0., 1., 2., 3., 4., 5., 6., 7., 8.]; - let mut mat = vec_to_mat_fixed(&vector, 3, false); - inplace_mask_matrix(&mask, &mut mat); - assert_mat_compare( - &mat, - &vec_to_mat_fixed(&vector, 3, false), - I32F32::from_num(0), - ); - let mask: Vec> = vec![ - vec![true, false, false], - vec![false, true, false], - vec![false, false, true], - ]; - let target: Vec = vec![0., 1., 2., 3., 0., 5., 6., 7., 0.]; - let mut mat = vec_to_mat_fixed(&vector, 3, false); - inplace_mask_matrix(&mask, &mut mat); - assert_mat_compare( - &mat, - &vec_to_mat_fixed(&target, 3, false), - I32F32::from_num(0), - ); - let mask: Vec> = vec![ - vec![true, true, true], - vec![true, true, true], - vec![true, true, true], - ]; - let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let mut mat = vec_to_mat_fixed(&vector, 3, false); - inplace_mask_matrix(&mask, &mut mat); - assert_mat_compare( - &mat, - &vec_to_mat_fixed(&target, 3, false), - I32F32::from_num(0), - ); - } - - #[test] - fn test_math_inplace_mask_rows() { - let input: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9.]; - let mask: Vec = vec![false, false, false]; - let target: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9.]; - let mut mat = vec_to_mat_fixed(&input, 3, false); - inplace_mask_rows(&mask, &mut mat); - assert_mat_compare( - &mat, - &vec_to_mat_fixed(&target, 3, false), - I32F32::from_num(0), - ); - let mask: Vec = vec![true, true, true]; - let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let mut mat = vec_to_mat_fixed(&input, 3, false); - inplace_mask_rows(&mask, &mut mat); - assert_mat_compare( - &mat, - &vec_to_mat_fixed(&target, 3, false), - I32F32::from_num(0), - ); - let mask: Vec = vec![true, false, true]; - let target: Vec = vec![0., 0., 0., 4., 5., 6., 0., 0., 0.]; - let mut mat = vec_to_mat_fixed(&input, 3, false); - inplace_mask_rows(&mask, &mut mat); - assert_mat_compare( - &mat, - &vec_to_mat_fixed(&target, 3, false), - I32F32::from_num(0), - ); - let input: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let mut mat = vec_to_mat_fixed(&input, 3, false); - let mask: Vec = vec![false, false, false]; - let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0.]; - inplace_mask_rows(&mask, &mut mat); - assert_mat_compare( - &mat, - &vec_to_mat_fixed(&target, 3, false), - I32F32::from_num(0), - ); - } - - #[test] - fn test_math_inplace_mask_diag() { - let vector: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9.]; - let target: Vec = vec![0., 2., 3., 4., 0., 6., 7., 8., 0.]; - let mut mat = vec_to_mat_fixed(&vector, 3, false); - inplace_mask_diag(&mut mat); - assert_mat_compare( - &mat, - &vec_to_mat_fixed(&target, 3, false), - I32F32::from_num(0), - ); - } - - #[test] - fn test_math_mask_rows_sparse() { - let input: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9.]; - let mat = vec_to_sparse_mat_fixed(&input, 3, false); - let mask: Vec = vec![false, false, false]; - let target: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9.]; - let result = mask_rows_sparse(&mask, &mat); - assert_sparse_mat_compare( - &result, - &vec_to_sparse_mat_fixed(&target, 3, false), - I32F32::from_num(0), - ); - let mask: Vec = vec![true, true, true]; - let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let result = mask_rows_sparse(&mask, &mat); - assert_sparse_mat_compare( - &result, - &vec_to_sparse_mat_fixed(&target, 3, false), - I32F32::from_num(0), + fn test_math_inplace_normalize() { + let epsilon: I32F32 = I32F32::from_num(0.0001); + let mut x1: Vec = fixed_vec![1.0, 10.0, 30.0,]; + inplace_normalize(&mut x1); + assert_vec_compare( + &x1, + &[ + I32F32::from_num(0.0243902437), + I32F32::from_num(0.243902439), + I32F32::from_num(0.7317073171), + ], + epsilon, ); - let mask: Vec = vec![true, false, true]; - let target: Vec = vec![0., 0., 0., 4., 5., 6., 0., 0., 0.]; - let result = mask_rows_sparse(&mask, &mat); - assert_sparse_mat_compare( - &result, - &vec_to_sparse_mat_fixed(&target, 3, false), - I32F32::from_num(0), + let mut x2: Vec = fixed_vec![-1.0, 10.0, 30.0,]; + inplace_normalize(&mut x2); + assert_vec_compare( + &x2, + &[ + I32F32::from_num(-0.0256410255), + I32F32::from_num(0.2564102563), + I32F32::from_num(0.769230769), + ], + epsilon, ); - let input: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let mat = vec_to_sparse_mat_fixed(&input, 3, false); - let mask: Vec = vec![false, false, false]; - let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let result = mask_rows_sparse(&mask, &mat); + } + + #[test] + fn test_math_inplace_row_normalize_sparse() { + let epsilon: I32F32 = I32F32::from_num(0.0001); + let vector: Vec = vec![ + 0., 1., 0., 2., 0., 3., 4., 0., 1., 0., 2., 0., 3., 0., 1., 0., 0., 2., 0., 3., 4., 0., + 10., 0., 100., 1000., 0., 10000., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 1., 1., 1., + 1., + ]; + let mut mat = vec_to_sparse_mat_fixed(&vector, 6, false); + inplace_row_normalize_sparse(&mut mat); + let target: Vec = vec![ + 0., 0.1, 0., 0.2, 0., 0.3, 0.4, 0., 0.166666, 0., 0.333333, 0., 0.5, 0., 0.1, 0., 0., + 0.2, 0., 0.3, 0.4, 0., 0.0009, 0., 0.009, 0.09, 0., 0.9, 0., 0., 0., 0., 0., 0., 0., + 0.142857, 0.142857, 0.142857, 0.142857, 0.142857, 0.142857, 0.142857, + ]; + assert_sparse_mat_compare(&mat, &vec_to_sparse_mat_fixed(&target, 6, false), epsilon); + let vector: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; + let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; + let mut mat = vec_to_sparse_mat_fixed(&vector, 3, false); + inplace_row_normalize_sparse(&mut mat); assert_sparse_mat_compare( - &result, + &mat, &vec_to_sparse_mat_fixed(&target, 3, false), I32F32::from_num(0), ); @@ -1784,922 +346,4 @@ mod tests { I32F32::from_num(0), ); } - - #[test] - fn test_math_vec_mask_sparse_matrix() { - let vector: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9.]; - let target: Vec = vec![0., 2., 3., 4., 0., 6., 7., 8., 0.]; - let mat = vec_to_sparse_mat_fixed(&vector, 3, false); - let first_vector: Vec = vec![1, 2, 3]; - let second_vector: Vec = vec![1, 2, 3]; - let result = vec_mask_sparse_matrix(&mat, &first_vector, &second_vector, &|a, b| a == b); - assert_sparse_mat_compare( - &result, - &vec_to_sparse_mat_fixed(&target, 3, false), - I32F32::from_num(0), - ); - let target: Vec = vec![1., 0., 0., 4., 5., 0., 7., 8., 9.]; - let mat = vec_to_sparse_mat_fixed(&vector, 3, false); - let first_vector: Vec = vec![1, 2, 3]; - let second_vector: Vec = vec![1, 2, 3]; - let result = vec_mask_sparse_matrix(&mat, &first_vector, &second_vector, &|a, b| a < b); - assert_sparse_mat_compare( - &result, - &vec_to_sparse_mat_fixed(&target, 3, false), - I32F32::from_num(0), - ); - let vector: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let mat = vec_to_sparse_mat_fixed(&vector, 3, false); - let first_vector: Vec = vec![1, 2, 3]; - let second_vector: Vec = vec![1, 2, 3]; - let result = vec_mask_sparse_matrix(&mat, &first_vector, &second_vector, &|a, b| a == b); - assert_sparse_mat_compare( - &result, - &vec_to_sparse_mat_fixed(&target, 3, false), - I32F32::from_num(0), - ); - } - - #[test] - fn test_math_row_hadamard() { - let vector: Vec = vec_to_fixed(&vec![1., 2., 3., 4.]); - let matrix: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; - let matrix = vec_to_mat_fixed(&matrix, 4, false); - let result = row_hadamard(&matrix, &vector); - let target: Vec = vec![1., 2., 3., 8., 10., 12., 21., 24., 27., 40., 44., 48.]; - let target = vec_to_mat_fixed(&target, 4, false); - assert_mat_compare(&result, &target, I32F32::from_num(0)); - } - - #[test] - fn test_math_row_hadamard_sparse() { - let vector: Vec = vec_to_fixed(&vec![1., 2., 3., 4.]); - let matrix: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; - let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); - let result = row_hadamard_sparse(&matrix, &vector); - let target: Vec = vec![1., 2., 3., 8., 10., 12., 21., 24., 27., 40., 44., 48.]; - let target = vec_to_sparse_mat_fixed(&target, 4, false); - assert_sparse_mat_compare(&result, &target, I32F32::from_num(0)); - let matrix: Vec = vec![0., 2., 3., 4., 0., 6., 7., 8., 0., 10., 11., 12.]; - let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); - let result = row_hadamard_sparse(&matrix, &vector); - let target: Vec = vec![0., 2., 3., 8., 0., 12., 21., 24., 0., 40., 44., 48.]; - let target = vec_to_sparse_mat_fixed(&target, 4, false); - assert_sparse_mat_compare(&result, &target, I32F32::from_num(0)); - let matrix: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); - let result = row_hadamard_sparse(&matrix, &vector); - let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let target = vec_to_sparse_mat_fixed(&target, 4, false); - assert_sparse_mat_compare(&result, &target, I32F32::from_num(0)); - } - - #[test] - fn test_math_row_sum() { - let matrix: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; - let matrix = vec_to_mat_fixed(&matrix, 4, false); - let result = row_sum(&matrix); - let target: Vec = vec_to_fixed(&vec![6., 15., 24., 33.]); - assert_vec_compare(&result, &target, I32F32::from_num(0)); - } - - #[test] - fn test_math_row_sum_sparse() { - let matrix: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; - let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); - let result = row_sum_sparse(&matrix); - let target: Vec = vec_to_fixed(&vec![6., 15., 24., 33.]); - assert_vec_compare(&result, &target, I32F32::from_num(0)); - let matrix: Vec = vec![0., 2., 3., 4., 0., 6., 7., 8., 0., 10., 11., 12.]; - let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); - let result = row_sum_sparse(&matrix); - let target: Vec = vec_to_fixed(&vec![5., 10., 15., 33.]); - assert_vec_compare(&result, &target, I32F32::from_num(0)); - let matrix: Vec = vec![1., 2., 3., 0., 0., 0., 7., 8., 9., 10., 11., 12.]; - let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); - let result = row_sum_sparse(&matrix); - let target: Vec = vec_to_fixed(&vec![6., 0., 24., 33.]); - assert_vec_compare(&result, &target, I32F32::from_num(0)); - let matrix: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); - let result = row_sum_sparse(&matrix); - let target: Vec = vec_to_fixed(&vec![0., 0., 0., 0.]); - assert_vec_compare(&result, &target, I32F32::from_num(0)); - } - - #[test] - fn test_math_col_sum() { - let matrix: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; - let matrix = vec_to_mat_fixed(&matrix, 4, false); - let result = col_sum(&matrix); - let target: Vec = vec_to_fixed(&vec![22., 26., 30.]); - assert_vec_compare(&result, &target, I32F32::from_num(0)); - } - - #[test] - fn test_math_col_sum_sparse() { - let matrix: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; - let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); - let result = col_sum_sparse(&matrix, 3); - let target: Vec = vec_to_fixed(&vec![22., 26., 30.]); - assert_vec_compare(&result, &target, I32F32::from_num(0)); - let matrix: Vec = vec![0., 2., 3., 4., 0., 6., 7., 8., 0., 10., 11., 12.]; - let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); - let result = col_sum_sparse(&matrix, 3); - let target: Vec = vec_to_fixed(&vec![21., 21., 21.]); - assert_vec_compare(&result, &target, I32F32::from_num(0)); - let matrix: Vec = vec![1., 0., 3., 4., 0., 6., 7., 0., 9., 10., 0., 12.]; - let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); - let result = col_sum_sparse(&matrix, 3); - let target: Vec = vec_to_fixed(&vec![22., 0., 30.]); - assert_vec_compare(&result, &target, I32F32::from_num(0)); - let matrix: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); - let result = col_sum_sparse(&matrix, 3); - let target: Vec = vec_to_fixed(&vec![0., 0., 0.]); - assert_vec_compare(&result, &target, I32F32::from_num(0)); - } - - #[test] - fn test_math_matmul() { - let vector: Vec = vec_to_fixed(&vec![1., 2., 3., 4.]); - let matrix: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; - let matrix = vec_to_mat_fixed(&matrix, 4, false); - let result = matmul(&matrix, &vector); - let target: Vec = vec_to_fixed(&vec![70., 80., 90.]); - assert_vec_compare(&result, &target, I32F32::from_num(0)); - } - - #[test] - fn test_math_matmul_transpose() { - let vector: Vec = vec_to_fixed(&vec![1., 2., 3.]); - let matrix: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; - let matrix = vec_to_mat_fixed(&matrix, 4, false); - let result = matmul_transpose(&matrix, &vector); - let target: Vec = vec_to_fixed(&vec![14., 32., 50., 68.]); - assert_vec_compare(&result, &target, I32F32::from_num(0)); - } - - #[test] - fn test_math_sparse_matmul() { - let vector: Vec = vec_to_fixed(&vec![1., 2., 3., 4.]); - let matrix: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; - let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); - let result = matmul_sparse(&matrix, &vector, 3); - let target: Vec = vec_to_fixed(&vec![70., 80., 90.]); - assert_vec_compare(&result, &target, I32F32::from_num(0)); - let matrix: Vec = vec![0., 2., 3., 4., 0., 6., 7., 8., 0., 10., 11., 12.]; - let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); - let result = matmul_sparse(&matrix, &vector, 3); - let target: Vec = vec_to_fixed(&vec![69., 70., 63.]); - assert_vec_compare(&result, &target, I32F32::from_num(0)); - let matrix: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); - let result = matmul_sparse(&matrix, &vector, 3); - let target: Vec = vec_to_fixed(&vec![0., 0., 0.]); - assert_vec_compare(&result, &target, I32F32::from_num(0)); - } - - // #[test] - // fn test_math_sparse_matmul_transpose() { - // let vector:Vec = vec_to_fixed( &vec![ 1., 2., 3.] ); - // let matrix:Vec = vec![ 1., 2., 3., - // 4., 5., 6., - // 7., 8., 9., - // 10., 11., 12.]; - // let matrix = vec_to_sparse_mat_fixed(&matrix, 3, false); - // let result = matmul_transpose_sparse(&matrix, &vector); - // let target: Vec = vec_to_fixed( &vec![ 14., 32., 50., 68. ] ); - // assert_vec_compare(&result, &target, I32F32::from_num( 0 )); - // let matrix:Vec = vec![ 0., 2., 3., - // 4., 0., 6., - // 7., 8., 0., - // 10., 11., 12.]; - // let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); - // let result = matmul_transpose_sparse(&matrix, &vector); - // let target: Vec = vec_to_fixed( &vec![ 13., 22., 23., 68. ] ); - // assert_vec_compare(&result, &target, I32F32::from_num( 0 )); - // let matrix:Vec = vec![ 0., 0., 0., - // 0., 0., 0., - // 0., 0., 0., - // 0., 0., 0.]; - // let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); - // let result = matmul_transpose_sparse(&matrix, &vector); - // let target: Vec = vec_to_fixed( &vec![ 0., 0., 0., 0. ] ); - // assert_vec_compare(&result, &target, I32F32::from_num( 0 )); - // } - - #[test] - fn test_math_inplace_col_clip() { - let vector: Vec = vec_to_fixed(&vec![0., 5., 12.]); - let matrix: Vec = vec![0., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; - let mut matrix = vec_to_mat_fixed(&matrix, 4, false); - let target: Vec = vec![0., 2., 3., 0., 5., 6., 0., 5., 9., 0., 5., 12.]; - let target = vec_to_mat_fixed(&target, 4, false); - inplace_col_clip(&mut matrix, &vector); - assert_mat_compare(&matrix, &target, I32F32::from_num(0)); - } - - #[test] - fn test_math_col_clip_sparse() { - let vector: Vec = vec_to_fixed(&vec![0., 5., 12.]); - let matrix: Vec = vec![0., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; - let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); - let target: Vec = vec![0., 2., 3., 0., 5., 6., 0., 5., 9., 0., 5., 12.]; - let target = vec_to_sparse_mat_fixed(&target, 4, false); - let result = col_clip_sparse(&matrix, &vector); - assert_sparse_mat_compare(&result, &target, I32F32::from_num(0)); - let matrix: Vec = vec![0., 2., 3., 4., 5., 6., 0., 0., 0., 10., 11., 12.]; - let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); - let target: Vec = vec![0., 2., 3., 0., 5., 6., 0., 0., 0., 0., 5., 12.]; - let target = vec_to_sparse_mat_fixed(&target, 4, false); - let result = col_clip_sparse(&matrix, &vector); - assert_sparse_mat_compare(&result, &target, I32F32::from_num(0)); - let matrix: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); - let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let target = vec_to_sparse_mat_fixed(&target, 4, false); - let result = col_clip_sparse(&matrix, &vector); - assert_sparse_mat_compare(&result, &target, I32F32::from_num(0)); - } - - #[test] - fn test_math_clip_sparse() { - let matrix: Vec = vec![0., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; - let matrix = vec_to_sparse_mat_fixed(&matrix, 4, false); - let target: Vec = vec![0., 1., 1., 1., 1., 1., 1., 100., 100., 100., 100., 100.]; - let target = vec_to_sparse_mat_fixed(&target, 4, false); - let result = clip_sparse( - &matrix, - I32F32::from_num(8), - I32F32::from_num(100), - I32F32::from_num(1), - ); - assert_sparse_mat_compare(&result, &target, I32F32::from_num(0)); - } - - #[test] - fn test_math_clip() { - let matrix: Vec = vec![0., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; - let matrix = vec_to_mat_fixed(&matrix, 4, false); - let target: Vec = vec![1., 1., 1., 1., 1., 1., 1., 100., 100., 100., 100., 100.]; - let target = vec_to_mat_fixed(&target, 4, false); - let result = clip( - &matrix, - I32F32::from_num(8), - I32F32::from_num(100), - I32F32::from_num(1), - ); - assert_mat_compare(&result, &target, I32F32::from_num(0)); - } - - #[test] - fn test_math_inplace_clip() { - let matrix: Vec = vec![0., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; - let mut matrix = vec_to_mat_fixed(&matrix, 4, false); - let target: Vec = vec![1., 1., 1., 1., 1., 1., 1., 100., 100., 100., 100., 100.]; - let target = vec_to_mat_fixed(&target, 4, false); - inplace_clip( - &mut matrix, - I32F32::from_num(8), - I32F32::from_num(100), - I32F32::from_num(1), - ); - assert_mat_compare(&matrix, &target, I32F32::from_num(0)); - } - - #[test] - fn test_math_weighted_median() { - let mut rng = thread_rng(); - let zero: I32F32 = fixed(0.); - let one: I32F32 = fixed(1.); - for _ in 0..100 { - let stake: Vec = vec_to_fixed(&vec![]); - let score: Vec = vec_to_fixed(&vec![]); - let majority: I32F32 = fixed(0.51); - assert_eq!( - zero, - weighted_median( - &stake, - &score, - &(0..stake.len()).collect(), - one - majority, - zero, - stake.iter().sum() - ) - ); - - let stake: Vec = normalize(&vec_to_fixed(&vec![0.51])); - let score: Vec = vec_to_fixed(&vec![1.]); - let majority: I32F32 = fixed(0.51); - assert_eq!( - one, - weighted_median( - &stake, - &score, - &(0..stake.len()).collect(), - one - majority, - zero, - stake.iter().sum() - ) - ); - - let stake: Vec = vec_to_fixed(&vec![0.49, 0.51]); - let score: Vec = vec_to_fixed(&vec![0.5, 1.]); - let majority: I32F32 = fixed(0.51); - assert_eq!( - one, - weighted_median( - &stake, - &score, - &(0..stake.len()).collect(), - one - majority, - zero, - stake.iter().sum() - ) - ); - - let stake: Vec = vec_to_fixed(&vec![0.51, 0.49]); - let score: Vec = vec_to_fixed(&vec![0.5, 1.]); - let majority: I32F32 = fixed(0.51); - assert_eq!( - fixed(0.5), - weighted_median( - &stake, - &score, - &(0..stake.len()).collect(), - one - majority, - zero, - stake.iter().sum() - ) - ); - - let stake: Vec = vec_to_fixed(&vec![0.49, 0., 0.51]); - let score: Vec = vec_to_fixed(&vec![0.5, 0.7, 1.]); - let majority: I32F32 = fixed(0.51); - assert_eq!( - one, - weighted_median( - &stake, - &score, - &(0..stake.len()).collect(), - one - majority, - zero, - stake.iter().sum() - ) - ); - - let stake: Vec = vec_to_fixed(&vec![0.49, 0.01, 0.5]); - let score: Vec = vec_to_fixed(&vec![0.5, 0.7, 1.]); - let majority: I32F32 = fixed(0.51); - assert_eq!( - fixed(0.7), - weighted_median( - &stake, - &score, - &(0..stake.len()).collect(), - one - majority, - zero, - stake.iter().sum() - ) - ); - - let stake: Vec = vec_to_fixed(&vec![0.49, 0.51, 0.0]); - let score: Vec = vec_to_fixed(&vec![0.5, 0.7, 1.]); - let majority: I32F32 = fixed(0.51); - assert_eq!( - fixed(0.7), - weighted_median( - &stake, - &score, - &(0..stake.len()).collect(), - one - majority, - zero, - stake.iter().sum() - ) - ); - - let stake: Vec = vec_to_fixed(&vec![0.0, 0.49, 0.51]); - let score: Vec = vec_to_fixed(&vec![0.5, 0.7, 1.]); - let majority: I32F32 = fixed(0.51); - assert_eq!( - one, - weighted_median( - &stake, - &score, - &(0..stake.len()).collect(), - one - majority, - zero, - stake.iter().sum() - ) - ); - - let stake: Vec = vec_to_fixed(&vec![0.0, 0.49, 0.0, 0.51]); - let score: Vec = vec_to_fixed(&vec![0.5, 0.5, 1., 1.]); - let majority: I32F32 = fixed(0.51); - assert_eq!( - one, - weighted_median( - &stake, - &score, - &(0..stake.len()).collect(), - one - majority, - zero, - stake.iter().sum() - ) - ); - - let stake: Vec = vec_to_fixed(&vec![0.0, 0.49, 0.0, 0.51, 0.0]); - let score: Vec = vec_to_fixed(&vec![0.5, 0.5, 1., 1., 0.5]); - let majority: I32F32 = fixed(0.51); - assert_eq!( - one, - weighted_median( - &stake, - &score, - &(0..stake.len()).collect(), - one - majority, - zero, - stake.iter().sum() - ) - ); - - let stake: Vec = vec_to_fixed(&vec![0.2, 0.2, 0.2, 0.2, 0.2]); - let score: Vec = vec_to_fixed(&vec![0.8, 0.2, 1., 0.6, 0.4]); - let majority: I32F32 = fixed(0.51); - assert_eq!( - fixed(0.6), - weighted_median( - &stake, - &score, - &(0..stake.len()).collect(), - one - majority, - zero, - stake.iter().sum() - ) - ); - - let stake: Vec = - vec_to_fixed(&vec![0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]); - let score: Vec = - vec_to_fixed(&vec![0.8, 0.8, 0.2, 0.2, 1.0, 1.0, 0.6, 0.6, 0.4, 0.4]); - let majority: I32F32 = fixed(0.51); - assert_eq!( - fixed(0.6), - weighted_median( - &stake, - &score, - &(0..stake.len()).collect(), - one - majority, - zero, - stake.iter().sum() - ) - ); - - let n: usize = 100; - for majority in vec_to_fixed(&vec![ - 0., - 0.0000001, - 0.25, - 0.48999999999999, - 0.49, - 0.49000000000001, - 0.5, - 0.509999999999, - 0.51, - 0.5100000000001, - 0.9999999, - 1., - ]) { - for allow_equal in [false, true] { - let mut stake: Vec = vec![]; - let mut score: Vec = vec![]; - let mut last_score: I32F32 = zero; - for i in 0..n { - if allow_equal { - match rng.gen_range(0..2) { - 1 => stake.push(one), - _ => stake.push(zero), - } - match rng.gen_range(0..2) { - 1 => last_score += one, - _ => (), - } - score.push(last_score); - } else { - stake.push(one); - score.push(I32F32::from_num(i)); - } - } - inplace_normalize(&mut stake); - let total_stake: I32F32 = stake.iter().sum(); - let mut minority: I32F32 = total_stake - majority; - if minority < zero { - minority = zero; - } - let mut medians: Vec = vec![]; - let mut median_stake: I32F32 = zero; - let mut median_set = false; - let mut stake_sum: I32F32 = zero; - for i in 0..n { - stake_sum += stake[i]; - if !median_set && stake_sum >= minority { - median_stake = stake_sum; - median_set = true; - } - if median_set { - if median_stake < stake_sum { - if median_stake == minority && !medians.contains(&score[i]) { - medians.push(score[i]); - } - break; - } - if !medians.contains(&score[i]) { - medians.push(score[i]); - } - } - } - if medians.len() == 0 { - medians.push(zero); - } - let stake_idx: Vec = (0..stake.len()).collect(); - let result: I32F32 = - weighted_median(&stake, &score, &stake_idx, minority, zero, total_stake); - assert!(medians.contains(&result)); - for _ in 0..10 { - let mut permuted_uids: Vec = (0..n).collect(); - permuted_uids.shuffle(&mut thread_rng()); - stake = permuted_uids.iter().map(|&i| stake[i]).collect(); - score = permuted_uids.iter().map(|&i| score[i]).collect(); - let result: I32F32 = weighted_median( - &stake, - &score, - &stake_idx, - minority, - zero, - total_stake, - ); - assert!(medians.contains(&result)); - } - } - } - } - } - - #[test] - fn test_math_weighted_median_col() { - let stake: Vec = vec_to_fixed(&vec![]); - let weights: Vec> = vec![vec![]]; - let median: Vec = vec_to_fixed(&vec![]); - assert_eq!(median, weighted_median_col(&stake, &weights, fixed(0.5))); - - let stake: Vec = vec_to_fixed(&vec![0., 0.]); - let weights: Vec = vec![0., 0., 0., 0.]; - let weights: Vec> = vec_to_mat_fixed(&weights, 2, false); - let median: Vec = vec_to_fixed(&vec![0., 0.]); - assert_eq!(median, weighted_median_col(&stake, &weights, fixed(0.5))); - - let stake: Vec = vec_to_fixed(&vec![0., 0.75, 0.25, 0.]); - let weights: Vec = vec![0., 0.1, 0., 0., 0.2, 0.4, 0., 0.3, 0.1, 0., 0.4, 0.5]; - let weights: Vec> = vec_to_mat_fixed(&weights, 4, false); - let median: Vec = vec_to_fixed(&vec![0., 0.3, 0.4]); - assert_eq!(median, weighted_median_col(&stake, &weights, fixed(0.24))); - let median: Vec = vec_to_fixed(&vec![0., 0.2, 0.4]); - assert_eq!(median, weighted_median_col(&stake, &weights, fixed(0.26))); - let median: Vec = vec_to_fixed(&vec![0., 0.2, 0.1]); - assert_eq!(median, weighted_median_col(&stake, &weights, fixed(0.76))); - - let stake: Vec = vec_to_fixed(&vec![0., 0.3, 0.2, 0.5]); - let weights: Vec = vec![0., 0.1, 0., 0., 0.2, 0.4, 0., 0.3, 0.1, 0., 0., 0.5]; - let weights: Vec> = vec_to_mat_fixed(&weights, 4, false); - let median: Vec = vec_to_fixed(&vec![0., 0., 0.4]); - assert_eq!(median, weighted_median_col(&stake, &weights, fixed(0.51))); - } - - #[test] - fn test_math_weighted_median_col_sparse() { - let stake: Vec = vec_to_fixed(&vec![]); - let weights: Vec> = vec![vec![]]; - let median: Vec = vec_to_fixed(&vec![]); - assert_eq!( - median, - weighted_median_col_sparse(&stake, &weights, 0, fixed(0.5)) - ); - - let stake: Vec = vec_to_fixed(&vec![0., 0.]); - let weights: Vec = vec![0., 0., 0., 0.]; - let weights: Vec> = vec_to_sparse_mat_fixed(&weights, 2, false); - let median: Vec = vec_to_fixed(&vec![0., 0.]); - assert_eq!( - median, - weighted_median_col_sparse(&stake, &weights, 2, fixed(0.5)) - ); - - let stake: Vec = vec_to_fixed(&vec![0., 0.75, 0.25, 0.]); - let weights: Vec = vec![0., 0.1, 0., 0., 0.2, 0.4, 0., 0.3, 0.1, 0., 0.4, 0.5]; - let weights: Vec> = vec_to_sparse_mat_fixed(&weights, 4, false); - let median: Vec = vec_to_fixed(&vec![0., 0.3, 0.4]); - assert_eq!( - median, - weighted_median_col_sparse(&stake, &weights, 3, fixed(0.24)) - ); - let median: Vec = vec_to_fixed(&vec![0., 0.2, 0.4]); - assert_eq!( - median, - weighted_median_col_sparse(&stake, &weights, 3, fixed(0.26)) - ); - let median: Vec = vec_to_fixed(&vec![0., 0.2, 0.1]); - assert_eq!( - median, - weighted_median_col_sparse(&stake, &weights, 3, fixed(0.76)) - ); - - let stake: Vec = vec_to_fixed(&vec![0., 0.3, 0.2, 0.5]); - let weights: Vec = vec![0., 0.1, 0., 0., 0.2, 0.4, 0., 0.3, 0.1, 0., 0., 0.5]; - let weights: Vec> = vec_to_sparse_mat_fixed(&weights, 4, false); - let median: Vec = vec_to_fixed(&vec![0., 0., 0.4]); - assert_eq!( - median, - weighted_median_col_sparse(&stake, &weights, 3, fixed(0.51)) - ); - } - - #[test] - fn test_math_hadamard() { - let mat2: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; - let mat1: Vec = vec![ - 10., 20., 30., 40., 50., 60., 70., 80., 90., 100., 110., 120., - ]; - let target: Vec = vec![ - 10., 40., 90., 160., 250., 360., 490., 640., 810., 1000., 1210., 1440., - ]; - let mat2 = vec_to_mat_fixed(&mat2, 4, false); - let mat1 = vec_to_mat_fixed(&mat1, 4, false); - let target = vec_to_mat_fixed(&target, 4, false); - let result = hadamard(&mat1, &mat2); - assert_mat_compare(&result, &target, I32F32::from_num(0.000001)); - let mat2: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let mat1: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let mat2 = vec_to_mat_fixed(&mat2, 4, false); - let mat1 = vec_to_mat_fixed(&mat1, 4, false); - let target = vec_to_mat_fixed(&target, 4, false); - let result = hadamard(&mat1, &mat2); - assert_mat_compare(&result, &target, I32F32::from_num(0.000001)); - let mat2: Vec = vec![1., 0., 0., 0., 2., 0., 0., 0., 3., 0., 0., 0.]; - let mat1: Vec = vec![0., 0., 4., 0., 5., 0., 6., 0., 0., 0., 0., 0.]; - let target: Vec = vec![0., 0., 0., 0., 10., 0., 0., 0., 0., 0., 0., 0.]; - let mat2 = vec_to_mat_fixed(&mat2, 4, false); - let mat1 = vec_to_mat_fixed(&mat1, 4, false); - let target = vec_to_mat_fixed(&target, 4, false); - let result = hadamard(&mat1, &mat2); - assert_mat_compare(&result, &target, I32F32::from_num(0.000001)); - } - - #[test] - fn test_math_hadamard_sparse() { - let mat2: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; - let mat1: Vec = vec![ - 10., 20., 30., 40., 50., 60., 70., 80., 90., 100., 110., 120., - ]; - let target: Vec = vec![ - 10., 40., 90., 160., 250., 360., 490., 640., 810., 1000., 1210., 1440., - ]; - let mat2 = vec_to_sparse_mat_fixed(&mat2, 4, false); - let mat1 = vec_to_sparse_mat_fixed(&mat1, 4, false); - let target = vec_to_sparse_mat_fixed(&target, 4, false); - let result = hadamard_sparse(&mat1, &mat2, 3); - assert_sparse_mat_compare(&result, &target, I32F32::from_num(0.000001)); - let mat2: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let mat1: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let mat2 = vec_to_sparse_mat_fixed(&mat2, 4, false); - let mat1 = vec_to_sparse_mat_fixed(&mat1, 4, false); - let target = vec_to_sparse_mat_fixed(&target, 4, false); - let result = hadamard_sparse(&mat1, &mat2, 3); - assert_sparse_mat_compare(&result, &target, I32F32::from_num(0.000001)); - let mat2: Vec = vec![1., 0., 0., 0., 2., 0., 0., 0., 3., 0., 0., 0.]; - let mat1: Vec = vec![0., 0., 4., 0., 5., 0., 6., 0., 0., 0., 0., 0.]; - let target: Vec = vec![0., 0., 0., 0., 10., 0., 0., 0., 0., 0., 0., 0.]; - let mat2 = vec_to_sparse_mat_fixed(&mat2, 4, false); - let mat1 = vec_to_sparse_mat_fixed(&mat1, 4, false); - let target = vec_to_sparse_mat_fixed(&target, 4, false); - let result = hadamard_sparse(&mat1, &mat2, 3); - assert_sparse_mat_compare(&result, &target, I32F32::from_num(0.000001)); - } - - #[test] - fn test_math_mat_ema() { - let old: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; - let new: Vec = vec![ - 10., 20., 30., 40., 50., 60., 70., 80., 90., 100., 110., 120., - ]; - let target: Vec = vec![ - 1.9, 3.8, 5.7, 7.6, 9.5, 11.4, 13.3, 15.2, 17.1, 19., 20.9, 22.8, - ]; - let old = vec_to_mat_fixed(&old, 4, false); - let new = vec_to_mat_fixed(&new, 4, false); - let target = vec_to_mat_fixed(&target, 4, false); - let result = mat_ema(&new, &old, I32F32::from_num(0.1)); - assert_mat_compare(&result, &target, I32F32::from_num(0.000001)); - let old: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; - let new: Vec = vec![ - 10., 20., 30., 40., 50., 60., 70., 80., 90., 100., 110., 120., - ]; - let target: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; - let old = vec_to_mat_fixed(&old, 4, false); - let new = vec_to_mat_fixed(&new, 4, false); - let target = vec_to_mat_fixed(&target, 4, false); - let result = mat_ema(&new, &old, I32F32::from_num(0)); - assert_mat_compare(&result, &target, I32F32::from_num(0.000001)); - let old: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; - let new: Vec = vec![ - 10., 20., 30., 40., 50., 60., 70., 80., 90., 100., 110., 120., - ]; - let target: Vec = vec![ - 10., 20., 30., 40., 50., 60., 70., 80., 90., 100., 110., 120., - ]; - let old = vec_to_mat_fixed(&old, 4, false); - let new = vec_to_mat_fixed(&new, 4, false); - let target = vec_to_mat_fixed(&target, 4, false); - let result = mat_ema(&new, &old, I32F32::from_num(1)); - assert_mat_compare(&result, &target, I32F32::from_num(0.000001)); - } - - #[test] - fn test_math_sparse_mat_ema() { - let old: Vec = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; - let new: Vec = vec![ - 10., 20., 30., 40., 50., 60., 70., 80., 90., 100., 110., 120., - ]; - let target: Vec = vec![ - 1.9, 3.8, 5.7, 7.6, 9.5, 11.4, 13.3, 15.2, 17.1, 19., 20.9, 22.8, - ]; - let old = vec_to_sparse_mat_fixed(&old, 4, false); - let new = vec_to_sparse_mat_fixed(&new, 4, false); - let target = vec_to_sparse_mat_fixed(&target, 4, false); - let result = mat_ema_sparse(&new, &old, I32F32::from_num(0.1)); - assert_sparse_mat_compare(&result, &target, I32F32::from_num(0.000001)); - let old: Vec = vec![0., 2., 3., 4., 0., 6., 7., 8., 0., 10., 11., 12.]; - let new: Vec = vec![10., 20., 0., 40., 0., 60., 0., 80., 90., 100., 110., 120.]; - let target: Vec = vec![1., 3.8, 2.7, 7.6, 0., 11.4, 6.3, 15.2, 9., 19., 20.9, 22.8]; - let old = vec_to_sparse_mat_fixed(&old, 4, false); - let new = vec_to_sparse_mat_fixed(&new, 4, false); - let target = vec_to_sparse_mat_fixed(&target, 4, false); - let result = mat_ema_sparse(&new, &old, I32F32::from_num(0.1)); - assert_sparse_mat_compare(&result, &target, I32F32::from_num(0.000001)); - let old: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let new: Vec = vec![10., 20., 0., 40., 0., 60., 0., 80., 90., 100., 110., 120.]; - let target: Vec = vec![1., 2., 0., 4., 0., 6., 0., 8., 9., 10., 11., 12.]; - let old = vec_to_sparse_mat_fixed(&old, 4, false); - let new = vec_to_sparse_mat_fixed(&new, 4, false); - let target = vec_to_sparse_mat_fixed(&target, 4, false); - let result = mat_ema_sparse(&new, &old, I32F32::from_num(0.1)); - assert_sparse_mat_compare(&result, &target, I32F32::from_num(0.000001)); - let old: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let new: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let target: Vec = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let old = vec_to_sparse_mat_fixed(&old, 4, false); - let new = vec_to_sparse_mat_fixed(&new, 4, false); - let target = vec_to_sparse_mat_fixed(&target, 4, false); - let result = mat_ema_sparse(&new, &old, I32F32::from_num(0.1)); - assert_sparse_mat_compare(&result, &target, I32F32::from_num(0.000001)); - let old: Vec = vec![1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]; - let new: Vec = vec![0., 0., 0., 0., 2., 0., 0., 0., 0., 0., 0., 0.]; - let target: Vec = vec![0.9, 0., 0., 0., 0.2, 0., 0., 0., 0., 0., 0., 0.]; - let old = vec_to_sparse_mat_fixed(&old, 4, false); - let new = vec_to_sparse_mat_fixed(&new, 4, false); - let target = vec_to_sparse_mat_fixed(&target, 4, false); - let result = mat_ema_sparse(&new, &old, I32F32::from_num(0.1)); - assert_sparse_mat_compare(&result, &target, I32F32::from_num(0.000001)); - } - - #[test] - fn test_math_matmul2() { - let epsilon: I32F32 = I32F32::from_num(0.0001); - let w: Vec> = vec![vec![I32F32::from_num(1.0); 3]; 3]; - assert_vec_compare( - &matmul(&w, &vec![I32F32::from_num(1.0); 3]), - &vec![ - I32F32::from_num(3), - I32F32::from_num(3), - I32F32::from_num(3), - ], - epsilon, - ); - assert_vec_compare( - &matmul(&w, &vec![I32F32::from_num(2.0); 3]), - &vec![ - I32F32::from_num(6), - I32F32::from_num(6), - I32F32::from_num(6), - ], - epsilon, - ); - assert_vec_compare( - &matmul(&w, &vec![I32F32::from_num(3.0); 3]), - &vec![ - I32F32::from_num(9), - I32F32::from_num(9), - I32F32::from_num(9), - ], - epsilon, - ); - assert_vec_compare( - &matmul(&w, &vec![I32F32::from_num(-1.0); 3]), - &vec![ - I32F32::from_num(-3), - I32F32::from_num(-3), - I32F32::from_num(-3), - ], - epsilon, - ); - let w: Vec> = vec![vec![I32F32::from_num(-1.0); 3]; 3]; - assert_vec_compare( - &matmul(&w, &vec![I32F32::from_num(1.0); 3]), - &vec![ - I32F32::from_num(-3), - I32F32::from_num(-3), - I32F32::from_num(-3), - ], - epsilon, - ); - assert_vec_compare( - &matmul(&w, &vec![I32F32::from_num(2.0); 3]), - &vec![ - I32F32::from_num(-6), - I32F32::from_num(-6), - I32F32::from_num(-6), - ], - epsilon, - ); - assert_vec_compare( - &matmul(&w, &vec![I32F32::from_num(3.0); 3]), - &vec![ - I32F32::from_num(-9), - I32F32::from_num(-9), - I32F32::from_num(-9), - ], - epsilon, - ); - assert_vec_compare( - &matmul(&w, &vec![I32F32::from_num(-1.0); 3]), - &vec![ - I32F32::from_num(3), - I32F32::from_num(3), - I32F32::from_num(3), - ], - epsilon, - ); - let w: Vec> = vec![ - vec![I32F32::from_num(1.0); 3], - vec![I32F32::from_num(2.0); 3], - vec![I32F32::from_num(3.0); 3], - ]; - assert_vec_compare( - &matmul(&w, &vec![I32F32::from_num(0.0); 3]), - &vec![ - I32F32::from_num(0.0), - I32F32::from_num(0.0), - I32F32::from_num(0.0), - ], - epsilon, - ); - assert_vec_compare( - &matmul(&w, &vec![I32F32::from_num(2.0); 3]), - &vec![ - I32F32::from_num(12), - I32F32::from_num(12), - I32F32::from_num(12), - ], - epsilon, - ); - let w: Vec> = vec![ - vec![ - I32F32::from_num(1), - I32F32::from_num(2), - I32F32::from_num(3) - ]; - 3 - ]; - assert_vec_compare( - &matmul(&w, &vec![I32F32::from_num(0.0); 3]), - &vec![ - I32F32::from_num(0.0), - I32F32::from_num(0.0), - I32F32::from_num(0.0), - ], - epsilon, - ); - assert_vec_compare( - &matmul(&w, &vec![I32F32::from_num(2.0); 3]), - &vec![ - I32F32::from_num(6), - I32F32::from_num(12), - I32F32::from_num(18), - ], - epsilon, - ); - } }