use substrate_fixed::types::{I32F32, I64F64};
#[cfg(test)]
use substrate_fixed::transcendental::exp;
#[cfg(test)]
pub fn fixed(val: f32) -> I32F32 {
I32F32::from_num(val)
}
pub fn fixed_to_u16(x: I32F32) -> u16 {
x.to_num::<u16>()
}
#[cfg(test)]
pub fn fixed_to_u64(x: I32F32) -> u64 {
x.to_num::<u64>()
}
pub fn fixed64_to_u64(x: I64F64) -> u64 {
x.to_num::<u64>()
}
pub fn fixed64_to_fixed32(x: I64F64) -> I32F32 {
I32F32::from_num(x)
}
#[cfg(test)]
pub fn fixed32_to_fixed64(x: I32F32) -> I64F64 {
I64F64::from_num(x)
}
#[cfg(test)]
pub fn u16_to_fixed(x: u16) -> I32F32 {
I32F32::from_num(x)
}
#[cfg(test)]
pub fn u16_proportion_to_fixed(x: u16) -> I32F32 {
I32F32::from_num(x) / I32F32::from_num(u16::MAX)
}
pub fn fixed_proportion_to_u16(x: I32F32) -> u16 {
fixed_to_u16(x * I32F32::from_num(u16::MAX))
}
#[cfg(test)]
pub fn vec_fixed32_to_u64(vec: Vec<I32F32>) -> Vec<u64> {
vec.into_iter().map(|e| fixed_to_u64(e)).collect()
}
pub fn vec_fixed64_to_fixed32(vec: Vec<I64F64>) -> Vec<I32F32> {
vec.into_iter().map(|e| fixed64_to_fixed32(e)).collect()
}
#[cfg(test)]
pub fn vec_fixed32_to_fixed64(vec: Vec<I32F32>) -> Vec<I64F64> {
vec.into_iter().map(|e| fixed32_to_fixed64(e)).collect()
}
pub fn vec_fixed64_to_u64(vec: Vec<I64F64>) -> Vec<u64> {
vec.into_iter().map(|e| fixed64_to_u64(e)).collect()
}
#[cfg(test)]
pub fn vec_u16_proportions_to_fixed(vec: Vec<u16>) -> Vec<I32F32> {
vec.into_iter()
.map(|e| u16_proportion_to_fixed(e))
.collect()
}
#[cfg(test)]
pub fn vec_fixed_proportions_to_u16(vec: Vec<I32F32>) -> Vec<u16> {
vec.into_iter()
.map(|e| fixed_proportion_to_u16(e))
.collect()
}
// Max-upscale vector and convert to u16 so max_value = u16::MAX. Assumes non-negative normalized input.
pub fn vec_max_upscale_to_u16(vec: &Vec<I32F32>) -> Vec<u16> {
let u16_max: I32F32 = I32F32::from_num(u16::MAX);
let threshold: I32F32 = I32F32::from_num(32768);
let max_value: Option<&I32F32> = vec.iter().max();
match max_value {
Some(val) => {
if *val == I32F32::from_num(0) {
return vec
.iter()
.map(|e: &I32F32| (e * u16_max).to_num::<u16>())
.collect();
}
if *val > threshold {
return vec
.iter()
.map(|e: &I32F32| (e * (u16_max / *val)).round().to_num::<u16>())
.collect();
}
return vec
.iter()
.map(|e: &I32F32| ((e * u16_max) / *val).round().to_num::<u16>())
.collect();
}
None => {
let sum: I32F32 = vec.iter().sum();
return vec
.iter()
.map(|e: &I32F32| ((e * u16_max) / sum).to_num::<u16>())
.collect();
}
}
}
// Max-upscale u16 vector and convert to u16 so max_value = u16::MAX. Assumes u16 vector input.
pub fn vec_u16_max_upscale_to_u16(vec: &Vec<u16>) -> Vec<u16> {
let vec_fixed: Vec<I32F32> = vec.iter().map(|e: &u16| I32F32::from_num(*e)).collect();
vec_max_upscale_to_u16(&vec_fixed)
}
// Checks if u16 vector, when normalized, has a max value not greater than a u16 ratio max_limit.
pub fn check_vec_max_limited(vec: &Vec<u16>, max_limit: u16) -> bool {
let max_limit_fixed: I32F32 = I32F32::from_num(max_limit) / I32F32::from_num(u16::MAX);
let mut vec_fixed: Vec<I32F32> = vec.iter().map(|e: &u16| I32F32::from_num(*e)).collect();
inplace_normalize(&mut vec_fixed);
let max_value: Option<&I32F32> = vec_fixed.iter().max();
match max_value {
Some(val) => {
return *val <= max_limit_fixed;
}
None => {
return true;
}
}
}
pub fn sum(x: &Vec<I32F32>) -> I32F32 {
x.iter().sum()
}
// Return true when vector sum is zero.
pub fn is_zero(vector: &Vec<I32F32>) -> bool {
let vector_sum: I32F32 = sum(&vector);
vector_sum == I32F32::from_num(0)
}
// Exp safe function with I32F32 output of I32F32 input.
#[cfg(test)]
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.
#[cfg(test)]
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.
pub fn is_topk(vector: &Vec<I32F32>, k: usize) -> Vec<bool> {
let n: usize = vector.len();
let mut result: Vec<bool> = vec![true; n];
if n < k {
return result;
}
let mut idxs: Vec<usize> = (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.
#[cfg(test)]
pub fn normalize(x: &Vec<I32F32>) -> Vec<I32F32> {
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 {
return x.clone();
}
}
// Normalizes (sum to 1 except 0) the input vector directly in-place.
pub fn inplace_normalize(x: &mut Vec<I32F32>) {
let x_sum: I32F32 = x.iter().sum();
if x_sum == I32F32::from_num(0.0 as f32) {
return;
}
for i in 0..x.len() {
x[i] = x[i] / x_sum;
}
}
// Normalizes (sum to 1 except 0) the input vector directly in-place, using the sum arg.
pub fn inplace_normalize_using_sum(x: &mut Vec<I32F32>, x_sum: I32F32) {
if x_sum == I32F32::from_num(0.0 as f32) {
return;
}
for i in 0..x.len() {
x[i] = x[i] / x_sum;
}
}
// Normalizes (sum to 1 except 0) the I64F64 input vector directly in-place.
pub fn inplace_normalize_64(x: &mut Vec<I64F64>) {
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;
}
}
/// Returns x / y for input vectors x and y, if y == 0 return 0.
pub fn vecdiv(x: &Vec<I32F32>, y: &Vec<I32F32>) -> Vec<I32F32> {
assert_eq!(x.len(), y.len());
let n = x.len();
let mut result: Vec<I32F32> = vec![I32F32::from_num(0); n];
for i in 0..n {
if y[i] != 0 {
result[i] = x[i] / y[i];
}
}
result
}
// Normalizes (sum to 1 except 0) each row (dim=0) of a matrix in-place.
#[cfg(test)]
pub fn inplace_row_normalize(x: &mut Vec<Vec<I32F32>>) {
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);
}
}
}
// 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<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) {
sparse_row
.iter_mut()
.for_each(|(_j, value)| *value /= row_sum);
}
}
}
// Sum across each row (dim=0) of a matrix.
#[cfg(test)]
pub fn row_sum(x: &Vec<Vec<I32F32>>) -> Vec<I32F32> {
if x.is_empty() {
return vec![];
}
if x[0].is_empty() {
return vec![];
}
let rows = x.len();
let mut result: Vec<I32F32> = 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.
pub fn row_sum_sparse(sparse_matrix: &Vec<Vec<(u16, I32F32)>>) -> Vec<I32F32> {
let rows = sparse_matrix.len();
let mut result: Vec<I32F32> = 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.
#[cfg(test)]
pub fn col_sum(x: &Vec<Vec<I32F32>>) -> Vec<I32F32> {
if x.is_empty() {
return vec![];
}
if x[0].is_empty() {
return vec![];
}
let cols = x[0].len();
let mut result: Vec<I32F32> = 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
}
// Sum across each column (dim=1) of a sparse matrix.
#[cfg(test)]
pub fn col_sum_sparse(sparse_matrix: &Vec<Vec<(u16, I32F32)>>, columns: u16) -> Vec<I32F32> {
let mut result: Vec<I32F32> = 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;
}
}
result
}
// Normalizes (sum to 1 except 0) each column (dim=1) of a sparse matrix in-place.
pub fn inplace_col_normalize_sparse(sparse_matrix: &mut Vec<Vec<(u16, I32F32)>>, columns: u16) {
let mut col_sum: Vec<I32F32> = 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;
}
*value /= col_sum[*j as usize];
}
}
}
// Normalizes (sum to 1 except 0) each column (dim=1) of a matrix in-place.
#[cfg(test)]
pub fn inplace_col_normalize(x: &mut Vec<Vec<I32F32>>) {
if x.is_empty() {
return;
}
if x[0].is_empty() {
return;
}
let cols = x[0].len();
let mut col_sum: Vec<I32F32> = 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];
}
}
}
// Max-upscale each column (dim=1) of a sparse matrix in-place.
pub fn inplace_col_max_upscale_sparse(sparse_matrix: &mut Vec<Vec<(u16, I32F32)>>, columns: u16) {
let mut col_max: Vec<I32F32> = 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() {
if col_max[*j as usize] < *value {
col_max[*j as usize] = *value;
}
}
}
for sparse_row in sparse_matrix.iter_mut() {
for (j, value) in sparse_row.iter_mut() {
if col_max[*j as usize] == I32F32::from_num(0.0 as f32) {
continue;
}
*value /= col_max[*j as usize];
}
}
}
// Max-upscale each column (dim=1) of a matrix in-place.
#[cfg(test)]
pub fn inplace_col_max_upscale(x: &mut Vec<Vec<I32F32>>) {
if x.is_empty() {
return;
}
if x[0].is_empty() {
return;
}
let cols = x[0].len();
let mut col_max: Vec<I32F32> = vec![I32F32::from_num(0.0); cols];
for i in 0..x.len() {
assert_eq!(x[i].len(), cols);
for j in 0..cols {
if col_max[j] < x[i][j] {
col_max[j] = x[i][j];
}
}
}
for j in 0..cols {
if col_max[j] == I32F32::from_num(0.0 as f32) {
continue;
}
for i in 0..x.len() {
x[i][j] /= col_max[j];
}
}
}
// Apply mask to vector, mask=true will mask out, i.e. set to 0.
pub fn inplace_mask_vector(mask: &Vec<bool>, vector: &mut Vec<I32F32>) {
if mask.is_empty() {
return;
}
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;
}
}
}
// Apply mask to matrix, mask=true will mask out, i.e. set to 0.
#[cfg(test)]
pub fn inplace_mask_matrix(mask: &Vec<Vec<bool>>, matrix: &mut Vec<Vec<I32F32>>) {
if mask.is_empty() {
return;
}
if mask[0].is_empty() {
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;
}
}
}
}
// Apply row mask to matrix, mask=true will mask out, i.e. set to 0.
#[cfg(test)]
pub fn inplace_mask_rows(mask: &Vec<bool>, matrix: &mut Vec<Vec<I32F32>>) {
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];
}
}
}
// Mask out the diagonal of the input matrix in-place.
#[cfg(test)]
pub fn inplace_mask_diag(matrix: &mut Vec<Vec<I32F32>>) {
if matrix.is_empty() {
return;
}
if matrix[0].is_empty() {
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;
}
}
// Return a new sparse matrix that replaces masked rows with an empty vector placeholder.
pub fn mask_rows_sparse(
mask: &Vec<bool>,
sparse_matrix: &Vec<Vec<(u16, I32F32)>>,
) -> Vec<Vec<(u16, I32F32)>> {
let n: usize = sparse_matrix.len();
assert_eq!(n, mask.len());
let mut result: Vec<Vec<(u16, I32F32)>> = 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.
pub fn mask_diag_sparse(sparse_matrix: &Vec<Vec<(u16, I32F32)>>) -> Vec<Vec<(u16, I32F32)>> {
let n: usize = sparse_matrix.len();
let mut result: Vec<Vec<(u16, I32F32)>> = 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.
pub fn vec_mask_sparse_matrix(
sparse_matrix: &Vec<Vec<(u16, I32F32)>>,
first_vector: &Vec<u64>,
second_vector: &Vec<u64>,
mask_fn: &dyn Fn(u64, u64) -> bool,
) -> Vec<Vec<(u16, I32F32)>> {
let n: usize = sparse_matrix.len();
let mut result: Vec<Vec<(u16, I32F32)>> = 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.
#[cfg(test)]
pub fn row_hadamard(matrix: &Vec<Vec<I32F32>>, vector: &Vec<I32F32>) -> Vec<Vec<I32F32>> {
if matrix.is_empty() {
return vec![vec![]];
}
if matrix[0].is_empty() {
return vec![vec![]];
}
let mut result: Vec<Vec<I32F32>> =
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.
pub fn row_hadamard_sparse(
sparse_matrix: &Vec<Vec<(u16, I32F32)>>,
vector: &Vec<I32F32>,
) -> Vec<Vec<(u16, I32F32)>> {
let mut result: Vec<Vec<(u16, I32F32)>> = 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.
#[cfg(test)]
pub fn matmul(matrix: &Vec<Vec<I32F32>>, vector: &Vec<I32F32>) -> Vec<I32F32> {
if matrix.is_empty() {
return vec![];
}
if matrix[0].is_empty() {
return vec![];
}
assert!(matrix.len() == vector.len());
let mut result: Vec<I32F32> = vec![I32F32::from_num(0.0); matrix[0].len()];
for i in 0..matrix.len() {
for j in 0..matrix[i].len() {
// Compute ranks: r_j = SUM(i) w_ij * s_i
// 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.
#[cfg(test)]
pub fn matmul_transpose(matrix: &Vec<Vec<I32F32>>, vector: &Vec<I32F32>) -> Vec<I32F32> {
if matrix.is_empty() {
return vec![];
}
if matrix[0].is_empty() {
return vec![];
}
assert!(matrix[0].len() == vector.len());
let mut result: Vec<I32F32> = 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 matrix-vector product, column-wise sum: result_j = SUM(i) vector_i * matrix_ij.
pub fn matmul_64(matrix: &Vec<Vec<I64F64>>, vector: &Vec<I64F64>) -> Vec<I64F64> {
if matrix.is_empty() {
return vec![];
}
if matrix[0].is_empty() {
return vec![];
}
assert!(matrix.len() == vector.len());
let mut result: Vec<I64F64> = vec![I64F64::from_num(0.0); matrix[0].len()];
for i in 0..matrix.len() {
for j in 0..matrix[i].len() {
// Compute ranks: r_j = SUM(i) w_ij * s_i
// 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
}
// Row-wise sparse_matrix-vector product, column-wise sum: result_j = SUM(i) vector_i * matrix_ij.
pub fn matmul_sparse(
sparse_matrix: &Vec<Vec<(u16, I32F32)>>,
vector: &Vec<I32F32>,
columns: u16,
) -> Vec<I32F32> {
let mut result: Vec<I32F32> = vec![I32F32::from_num(0.0); columns as usize];
for (i, sparse_row) in sparse_matrix.iter().enumerate() {
for (j, value) in sparse_row.iter() {
// Compute ranks: r_j = SUM(i) w_ij * s_i
// 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;
// println!("{} {} {}", j, vector[i], value)
}
}
result
}
// Column-wise sparse_matrix-vector product, row-wise sum: result_i = SUM(j) vector_j * matrix_ij.
pub fn matmul_transpose_sparse(
sparse_matrix: &Vec<Vec<(u16, I32F32)>>,
vector: &Vec<I32F32>,
) -> Vec<I32F32> {
let mut result: Vec<I32F32> = vec![I32F32::from_num(0.0); sparse_matrix.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.
#[cfg(test)]
pub fn inplace_col_clip(x: &mut Vec<Vec<I32F32>>, col_threshold: &Vec<I32F32>) {
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.
pub fn col_clip_sparse(
sparse_matrix: &Vec<Vec<(u16, I32F32)>>,
col_threshold: &Vec<I32F32>,
) -> Vec<Vec<(u16, I32F32)>> {
let mut result: Vec<Vec<(u16, I32F32)>> = 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.
#[cfg(test)]
pub fn clip(
x: &Vec<Vec<I32F32>>,
threshold: I32F32,
upper: I32F32,
lower: I32F32,
) -> Vec<Vec<I32F32>> {
// Check Nill length.
if x.is_empty() {
return vec![vec![]];
}
let mut result: Vec<Vec<I32F32>> = 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.
#[cfg(test)]
pub fn inplace_clip(x: &mut Vec<Vec<I32F32>>, 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.
#[cfg(test)]
pub fn clip_sparse(
sparse_matrix: &Vec<Vec<(u16, I32F32)>>,
threshold: I32F32,
upper: I32F32,
lower: I32F32,
) -> Vec<Vec<(u16, I32F32)>> {
let mut result: Vec<Vec<(u16, I32F32)>> = 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<I32F32> ):
// - stake, assumed to be normalized.
//
// * 'score': ( &Vec<I32F32> ):
// - score for which median is sought, 0 <= score <= 1
//
// * 'partition_idx' ( &Vec<usize> ):
// - 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.
//
pub fn weighted_median(
stake: &Vec<I32F32>,
score: &Vec<I32F32>,
partition_idx: &Vec<usize>,
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<usize> = vec![];
let mut upper: Vec<usize> = 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).
#[cfg(test)]
pub fn weighted_median_col(
stake: &Vec<I32F32>,
score: &Vec<Vec<I32F32>>,
majority: I32F32,
) -> Vec<I32F32> {
let rows = stake.len();
let columns = score[0].len();
let zero: I32F32 = I32F32::from_num(0);
let mut median: Vec<I32F32> = vec![zero; columns];
for c in 0..columns {
let mut use_stake: Vec<I32F32> = vec![];
let mut use_score: Vec<I32F32> = 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).
pub fn weighted_median_col_sparse(
stake: &Vec<I32F32>,
score: &Vec<Vec<(u16, I32F32)>>,
columns: u16,
majority: I32F32,
) -> Vec<I32F32> {
let rows = stake.len();
let zero: I32F32 = I32F32::from_num(0);
let mut use_stake: Vec<I32F32> = 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<usize> = (0..use_stake.len()).collect();
let minority: I32F32 = stake_sum - majority;
let mut use_score: Vec<Vec<I32F32>> = vec![vec![zero; use_stake.len()]; columns as usize];
let mut median: Vec<I32F32> = 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.
#[cfg(test)]
pub fn hadamard(mat1: &Vec<Vec<I32F32>>, mat2: &Vec<Vec<I32F32>>) -> Vec<Vec<I32F32>> {
assert!(mat1.len() == mat2.len());
if mat1.is_empty() {
return vec![vec![]; 1];
}
if mat1[0].is_empty() {
return vec![vec![]; 1];
}
let mut result: Vec<Vec<I32F32>> = 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.
#[cfg(test)]
pub fn hadamard_sparse(
mat1: &Vec<Vec<(u16, I32F32)>>,
mat2: &Vec<Vec<(u16, I32F32)>>,
columns: u16,
) -> Vec<Vec<(u16, I32F32)>> {
assert!(mat1.len() == mat2.len());
let rows = mat1.len();
let zero: I32F32 = I32F32::from_num(0);
let mut result: Vec<Vec<(u16, I32F32)>> = vec![vec![]; rows];
for i in 0..rows {
let mut row1: Vec<I32F32> = vec![zero; columns as usize];
for (j, value) in mat1[i].iter() {
row1[*j as usize] += value;
}
let mut row2: Vec<I32F32> = 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.
#[cfg(test)]
pub fn mat_ema(new: &Vec<Vec<I32F32>>, old: &Vec<Vec<I32F32>>, alpha: I32F32) -> Vec<Vec<I32F32>> {
if new.is_empty() {
return vec![vec![]; 1];
}
if new[0].is_empty() {
return vec![vec![]; 1];
}
let one_minus_alpha: I32F32 = I32F32::from_num(1.0) - alpha;
let mut result: Vec<Vec<I32F32>> = 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.
pub fn mat_ema_sparse(
new: &Vec<Vec<(u16, I32F32)>>,
old: &Vec<Vec<(u16, I32F32)>>,
alpha: I32F32,
) -> Vec<Vec<(u16, I32F32)>> {
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<(u16, I32F32)>> = vec![vec![]; n];
for i in 0..new.len() {
let mut row: Vec<I32F32> = 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.
#[cfg(test)]
pub fn sparse_threshold(w: &Vec<Vec<(u16, I32F32)>>, threshold: I32F32) -> Vec<Vec<(u16, I32F32)>> {
let mut sparse_threshold_result: Vec<Vec<(u16, I32F32)>> = 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;
use substrate_fixed::types::{I110F18, 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<I32F32>, vb: &Vec<I32F32>, 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<I64F64>, vb: &Vec<I64F64>, epsilon: I64F64) {
assert!(va.len() == vb.len());
for i in 0..va.len() {
assert_float_compare_64(va[i], vb[i], epsilon);
}
}
fn assert_vec_compare_u16(va: &Vec<u16>, vb: &Vec<u16>) {
assert!(va.len() == vb.len());
for i in 0..va.len() {
assert_eq!(va[i], vb[i]);
}
}
fn assert_mat_compare(ma: &Vec<Vec<I32F32>>, mb: &Vec<Vec<I32F32>>, 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<Vec<(u16, I32F32)>>,
mb: &Vec<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
}
}
}
fn vec_to_fixed(vector: &Vec<f32>) -> Vec<I32F32> {
vector.iter().map(|x| I32F32::from_num(*x)).collect()
}
#[test]
fn test_vec_max_upscale_to_u16() {
let vector: Vec<I32F32> = vec_to_fixed(&vec![]);
let target: Vec<u16> = vec![];
let result: Vec<u16> = vec_max_upscale_to_u16(&vector);
assert_vec_compare_u16(&result, &target);
let vector: Vec<I32F32> = vec_to_fixed(&vec![0.]);
let target: Vec<u16> = vec![0];
let result: Vec<u16> = vec_max_upscale_to_u16(&vector);
assert_vec_compare_u16(&result, &target);
let vector: Vec<I32F32> = vec_to_fixed(&vec![0., 0.]);
let target: Vec<u16> = vec![0, 0];
let result: Vec<u16> = vec_max_upscale_to_u16(&vector);
assert_vec_compare_u16(&result, &target);
let vector: Vec<I32F32> = vec_to_fixed(&vec![0., 1.]);
let target: Vec<u16> = vec![0, 65535];
let result: Vec<u16> = vec_max_upscale_to_u16(&vector);
assert_vec_compare_u16(&result, &target);
let vector: Vec<I32F32> = vec_to_fixed(&vec![0., 0.000000001]);
let target: Vec<u16> = vec![0, 65535];
let result: Vec<u16> = vec_max_upscale_to_u16(&vector);
assert_vec_compare_u16(&result, &target);
let vector: Vec<I32F32> = vec_to_fixed(&vec![0., 0.000016, 1.]);
let target: Vec<u16> = vec![0, 1, 65535];
let result: Vec<u16> = vec_max_upscale_to_u16(&vector);
assert_vec_compare_u16(&result, &target);
let vector: Vec<I32F32> = vec_to_fixed(&vec![0.000000001, 0.000000001]);
let target: Vec<u16> = vec![65535, 65535];
let result: Vec<u16> = vec_max_upscale_to_u16(&vector);
assert_vec_compare_u16(&result, &target);
let vector: Vec<I32F32> = vec_to_fixed(&vec![
0.000001, 0.000006, 0.000007, 0.0001, 0.001, 0.01, 0.1, 0.2, 0.3, 0.4,
]);
let target: Vec<u16> = vec![0, 1, 1, 16, 164, 1638, 16384, 32768, 49151, 65535];
let result: Vec<u16> = vec_max_upscale_to_u16(&vector);
assert_vec_compare_u16(&result, &target);
let vector: Vec<I32F32> = vec![I32F32::from_num(16384)];
let target: Vec<u16> = vec![65535];
let result: Vec<u16> = vec_max_upscale_to_u16(&vector);
assert_vec_compare_u16(&result, &target);
let vector: Vec<I32F32> = vec![I32F32::from_num(32768)];
let target: Vec<u16> = vec![65535];
let result: Vec<u16> = vec_max_upscale_to_u16(&vector);
assert_vec_compare_u16(&result, &target);
let vector: Vec<I32F32> = vec![I32F32::from_num(32769)];
let target: Vec<u16> = vec![65535];
let result: Vec<u16> = vec_max_upscale_to_u16(&vector);
assert_vec_compare_u16(&result, &target);
let vector: Vec<I32F32> = vec![I32F32::from_num(65535)];
let target: Vec<u16> = vec![65535];
let result: Vec<u16> = vec_max_upscale_to_u16(&vector);
assert_vec_compare_u16(&result, &target);
let vector: Vec<I32F32> = vec![I32F32::max_value()];
let target: Vec<u16> = vec![65535];
let result: Vec<u16> = vec_max_upscale_to_u16(&vector);
assert_vec_compare_u16(&result, &target);
let vector: Vec<I32F32> = vec_to_fixed(&vec![0., 1., 65535.]);
let target: Vec<u16> = vec![0, 1, 65535];
let result: Vec<u16> = vec_max_upscale_to_u16(&vector);
assert_vec_compare_u16(&result, &target);
let vector: Vec<I32F32> = vec_to_fixed(&vec![0., 0.5, 1., 1.5, 2., 32768.]);
let target: Vec<u16> = vec![0, 1, 2, 3, 4, 65535];
let result: Vec<u16> = vec_max_upscale_to_u16(&vector);
assert_vec_compare_u16(&result, &target);
let vector: Vec<I32F32> = vec_to_fixed(&vec![0., 0.5, 1., 1.5, 2., 32768., 32769.]);
let target: Vec<u16> = vec![0, 1, 2, 3, 4, 65533, 65535];
let result: Vec<u16> = vec_max_upscale_to_u16(&vector);
assert_vec_compare_u16(&result, &target);
let vector: Vec<I32F32> = vec![
I32F32::from_num(0),
I32F32::from_num(1),
I32F32::from_num(32768),
I32F32::from_num(32769),
I32F32::max_value(),
];
let target: Vec<u16> = vec![0, 0, 1, 1, 65535];
let result: Vec<u16> = vec_max_upscale_to_u16(&vector);
assert_vec_compare_u16(&result, &target);
}
#[test]
fn test_vec_u16_max_upscale_to_u16() {
let vector: Vec<u16> = vec![];
let result: Vec<u16> = vec_u16_max_upscale_to_u16(&vector);
assert_vec_compare_u16(&result, &vector);
let vector: Vec<u16> = vec![0];
let result: Vec<u16> = vec_u16_max_upscale_to_u16(&vector);
assert_vec_compare_u16(&result, &vector);
let vector: Vec<u16> = vec![0, 0];
let result: Vec<u16> = vec_u16_max_upscale_to_u16(&vector);
assert_vec_compare_u16(&result, &vector);
let vector: Vec<u16> = vec![1];
let target: Vec<u16> = vec![65535];
let result: Vec<u16> = vec_u16_max_upscale_to_u16(&vector);
assert_vec_compare_u16(&result, &target);
let vector: Vec<u16> = vec![0, 1];
let target: Vec<u16> = vec![0, 65535];
let result: Vec<u16> = vec_u16_max_upscale_to_u16(&vector);
assert_vec_compare_u16(&result, &target);
let vector: Vec<u16> = vec![65534];
let target: Vec<u16> = vec![65535];
let result: Vec<u16> = vec_u16_max_upscale_to_u16(&vector);
assert_vec_compare_u16(&result, &target);
let vector: Vec<u16> = vec![65535];
let target: Vec<u16> = vec![65535];
let result: Vec<u16> = vec_u16_max_upscale_to_u16(&vector);
assert_vec_compare_u16(&result, &target);
let vector: Vec<u16> = vec![65535, 65535];
let target: Vec<u16> = vec![65535, 65535];
let result: Vec<u16> = vec_u16_max_upscale_to_u16(&vector);
assert_vec_compare_u16(&result, &target);
let vector: Vec<u16> = vec![0, 1, 65534];
let target: Vec<u16> = vec![0, 1, 65535];
let result: Vec<u16> = vec_u16_max_upscale_to_u16(&vector);
assert_vec_compare_u16(&result, &target);
let vector: Vec<u16> = vec![0, 1, 2, 3, 4, 65533, 65535];
let result: Vec<u16> = vec_u16_max_upscale_to_u16(&vector);
assert_vec_compare_u16(&result, &vector);
}
#[test]
fn test_check_vec_max_limited() {
let vector: Vec<u16> = vec![];
let max_limit: u16 = 0;
assert!(check_vec_max_limited(&vector, max_limit));
let vector: Vec<u16> = vec![];
let max_limit: u16 = u16::MAX;
assert!(check_vec_max_limited(&vector, max_limit));
let vector: Vec<u16> = vec![u16::MAX];
let max_limit: u16 = u16::MAX;
assert!(check_vec_max_limited(&vector, max_limit));
let vector: Vec<u16> = vec![u16::MAX];
let max_limit: u16 = u16::MAX - 1;
assert!(!check_vec_max_limited(&vector, max_limit));
let vector: Vec<u16> = vec![u16::MAX];
let max_limit: u16 = 0;
assert!(!check_vec_max_limited(&vector, max_limit));
let vector: Vec<u16> = vec![0];
let max_limit: u16 = u16::MAX;
assert!(check_vec_max_limited(&vector, max_limit));
let vector: Vec<u16> = vec![0, u16::MAX];
let max_limit: u16 = u16::MAX;
assert!(check_vec_max_limited(&vector, max_limit));
let vector: Vec<u16> = vec![0, u16::MAX, u16::MAX];
let max_limit: u16 = u16::MAX / 2;
assert!(!check_vec_max_limited(&vector, max_limit));
let vector: Vec<u16> = vec![0, u16::MAX, u16::MAX];
let max_limit: u16 = u16::MAX / 2 + 1;
assert!(check_vec_max_limited(&vector, max_limit));
let vector: Vec<u16> = vec![0, u16::MAX, u16::MAX, u16::MAX];
let max_limit: u16 = u16::MAX / 3 - 1;
assert!(!check_vec_max_limited(&vector, max_limit));
let vector: Vec<u16> = vec![0, u16::MAX, u16::MAX, u16::MAX];
let max_limit: u16 = u16::MAX / 3;
assert!(check_vec_max_limited(&vector, max_limit));
}
#[test]
fn test_math_fixed_overflow() {
let max_32: I32F32 = I32F32::max_value();
let max_u64: u64 = u64::MAX;
let _prod_96: I96F32 = I96F32::from_num(max_32) * I96F32::from_num(max_u64);
// let one: I96F32 = I96F32::from_num(1);
// let prod_96: I96F32 = (I96F32::from_num(max_32) + one) * I96F32::from_num(max_u64); // overflows
let _prod_110: I110F18 = I110F18::from_num(max_32) * I110F18::from_num(max_u64);
let bonds_moving_average_val: u64 = 900_000 as u64;
let bonds_moving_average: I64F64 =
I64F64::from_num(bonds_moving_average_val) / I64F64::from_num(1_000_000);
let alpha: I32F32 = I32F32::from_num(1) - I32F32::from_num(bonds_moving_average);
assert_eq!(I32F32::from_num(0.1), alpha);
let bonds_moving_average: I64F64 = I64F64::from_num(max_32) / I64F64::from_num(max_32);
let alpha: I32F32 = I32F32::from_num(1) - I32F32::from_num(bonds_moving_average);
assert_eq!(I32F32::from_num(0), alpha);
}
#[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::<u16>();
assert_eq!(res, u16::MAX);
let vector: Vec<I32F32> = vec![val; 1000];
let target: Vec<u16> = vec![u16::MAX; 1000];
let output: Vec<u16> = vector.iter().map(|e: &I32F32| e.to_num::<u16>()).collect();
assert_eq!(output, target);
let output: Vec<u16> = vector
.iter()
.map(|e: &I32F32| (*e).to_num::<u16>())
.collect();
assert_eq!(output, target);
let val: I32F32 = I32F32::max_value();
let res: u64 = val.to_num::<u64>();
let vector: Vec<I32F32> = vec![val; 1000];
let target: Vec<u64> = vec![res; 1000];
let output: Vec<u64> = vector.iter().map(|e: &I32F32| e.to_num::<u64>()).collect();
assert_eq!(output, target);
let output: Vec<u64> = vector
.iter()
.map(|e: &I32F32| (*e).to_num::<u64>())
.collect();
assert_eq!(output, target);
let val: I32F32 = I32F32::from_num(0);
let res: u64 = val.to_num::<u64>();
let vector: Vec<I32F32> = vec![val; 1000];
let target: Vec<u64> = vec![res; 1000];
let output: Vec<u64> = vector.iter().map(|e: &I32F32| e.to_num::<u64>()).collect();
assert_eq!(output, target);
let output: Vec<u64> = vector
.iter()
.map(|e: &I32F32| (*e).to_num::<u64>())
.collect();
assert_eq!(output, target);
let val: I96F32 = I96F32::from_num(u64::MAX);
let res: u64 = val.to_num::<u64>();
assert_eq!(res, u64::MAX);
let vector: Vec<I96F32> = vec![val; 1000];
let target: Vec<u64> = vec![u64::MAX; 1000];
let output: Vec<u64> = vector.iter().map(|e: &I96F32| e.to_num::<u64>()).collect();
assert_eq!(output, target);
let output: Vec<u64> = vector
.iter()
.map(|e: &I96F32| (*e).to_num::<u64>())
.collect();
assert_eq!(output, target);
}
#[test]
fn test_math_vec_to_fixed() {
let vector: Vec<f32> = vec![0., 1., 2., 3.];
let target: Vec<I32F32> = 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<f32>, rows: usize, transpose: bool) -> Vec<Vec<I32F32>> {
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<I32F32>> = vec![];
if transpose {
for col in 0..cols as usize {
let mut vals: Vec<I32F32> = 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<f32> = vec![0., 1., 2., 0., 10., 100.];
let target: Vec<Vec<I32F32>> = 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<f32>,
rows: usize,
transpose: bool,
) -> Vec<Vec<(u16, I32F32)>> {
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<(u16, I32F32)>> = 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<f32> = vec![0., 1., 2., 0., 10., 100.];
let target: Vec<Vec<(u16, I32F32)>> = 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<f32> = vec![0., 0.];
let target: Vec<Vec<(u16, I32F32)>> = 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<f32> = vec![0., 1., 2., 0., 10., 100.];
let target: Vec<Vec<(u16, I32F32)>> = 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<f32> = vec![0., 0.];
let target: Vec<Vec<(u16, I32F32)>> = 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<I32F32> = 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<I32F32> = trust
.iter()
.map(|t: &I32F32| sigmoid_safe(*t, I32F32::max_value(), I32F32::max_value()))
.collect();
let target: Vec<I32F32> = 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<I32F32> = trust
.iter()
.map(|t: &I32F32| sigmoid_safe(*t, I32F32::min_value(), I32F32::min_value()))
.collect();
let target: Vec<I32F32> = 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<I32F32> = trust
.iter()
.map(|t: &I32F32| sigmoid_safe(*t, I32F32::from_num(30), I32F32::from_num(0.5)))
.collect();
let target: Vec<f64> = vec![
0.0000000019,
0.0000003057,
0.0474258729,
0.5,
0.952574127,
0.9999996943,
0.9999999981,
];
let target: Vec<I32F32> = target.iter().map(|c: &f64| I32F32::from_num(*c)).collect();
assert_eq!(&consensus, &target);
let trust: Vec<I32F32> =
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<I32F32> = trust
.iter()
.map(|t: &I32F32| sigmoid_safe(*t, I32F32::from_num(40), I32F32::from_num(0.5)))
.collect();
let target: Vec<f64> = 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<I32F32> = target.iter().map(|c: &f64| I32F32::from_num(*c)).collect();
assert_eq!(&consensus, &target);
}
#[test]
fn test_math_is_topk() {
let vector: Vec<I32F32> = vec_to_fixed(&vec![]);
let result = is_topk(&vector, 5);
let target: Vec<bool> = vec![];
assert_eq!(&result, &target);
let vector: Vec<I32F32> = vec_to_fixed(&vec![0., 1., 2., 3., 4., 5., 6., 7., 8., 9.]);
let result = is_topk(&vector, 0);
let target: Vec<bool> = vec![
false, false, false, false, false, false, false, false, false, false,
];
assert_eq!(&result, &target);
let result = is_topk(&vector, 5);
let target: Vec<bool> = vec![
false, false, false, false, false, true, true, true, true, true,
];
assert_eq!(&result, &target);
let result = is_topk(&vector, 10);
let target: Vec<bool> = 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<I32F32> = vec_to_fixed(&vec![9., 8., 7., 6., 5., 4., 3., 2., 1., 0.]);
let result = is_topk(&vector, 5);
let target: Vec<bool> = vec![
true, true, true, true, true, false, false, false, false, false,
];
assert_eq!(&result, &target);
let vector: Vec<I32F32> = vec_to_fixed(&vec![9., 0., 8., 1., 7., 2., 6., 3., 5., 4.]);
let result = is_topk(&vector, 5);
let target: Vec<bool> = vec![
true, false, true, false, true, false, true, false, true, false,
];
assert_eq!(&result, &target);
let vector: Vec<I32F32> =
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<bool> = vec![
true, false, true, false, true, false, true, false, true, false,
];
assert_eq!(&result, &target);
let vector: Vec<I32F32> = vec_to_fixed(&vec![0., 1., 2., 3., 4., 5., 5., 5., 5., 6.]);
let result = is_topk(&vector, 5);
let target: Vec<bool> = 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_normalize() {
let epsilon: I32F32 = I32F32::from_num(0.0001);
let x: Vec<I32F32> = vec![];
let y: Vec<I32F32> = normalize(&x);
assert_vec_compare(&x, &y, epsilon);
let x: Vec<I32F32> = vec![
I32F32::from_num(1.0),
I32F32::from_num(10.0),
I32F32::from_num(30.0),
];
let y: Vec<I32F32> = 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<I32F32> = vec![
I32F32::from_num(-1.0),
I32F32::from_num(10.0),
I32F32::from_num(30.0),
];
let y: Vec<I32F32> = 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<I32F32> = 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<I32F32> = 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,
);
}
#[test]
fn test_math_inplace_normalize_64() {
let epsilon: I64F64 = I64F64::from_num(0.0001);
let mut x1: Vec<I64F64> = 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<I64F64> = 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<I32F32> = vec_to_fixed(&vec![]);
let y: Vec<I32F32> = vec_to_fixed(&vec![]);
let result: Vec<I32F32> = vec_to_fixed(&vec![]);
assert_eq!(result, vecdiv(&x, &y));
let x: Vec<I32F32> = vec_to_fixed(&vec![0., 1., 0., 1.]);
let y: Vec<I32F32> = vec_to_fixed(&vec![0., 1., 1., 0.]);
let result: Vec<I32F32> = vec_to_fixed(&vec![0., 1., 0., 0.]);
assert_eq!(result, vecdiv(&x, &y));
let x: Vec<I32F32> = vec_to_fixed(&vec![1., 1., 10.]);
let y: Vec<I32F32> = vec_to_fixed(&vec![2., 3., 2.]);
let result: Vec<I32F32> = 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<f32> = 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<f32> = 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<f32> = 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<f32> = 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<f32> = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.];
let target: Vec<f32> = 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<f32> = 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<f32> = 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<f32> = 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<f32> = 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<f32> = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.];
let target: Vec<f32> = 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<(u16, I32F32)>> = vec![];
let target: Vec<Vec<(u16, I32F32)>> = vec![];
inplace_col_normalize_sparse(&mut mat, 0);
assert_sparse_mat_compare(&mat, &target, epsilon);
}
#[test]
fn test_math_inplace_col_max_upscale() {
let mut mat: Vec<Vec<I32F32>> = vec![vec![]];
let target: Vec<Vec<I32F32>> = vec![vec![]];
inplace_col_max_upscale(&mut mat);
assert_eq!(&mat, &target);
let mut mat: Vec<Vec<I32F32>> = vec![vec![I32F32::from_num(0)]];
let target: Vec<Vec<I32F32>> = vec![vec![I32F32::from_num(0)]];
inplace_col_max_upscale(&mut mat);
assert_eq!(&mat, &target);
let epsilon: I32F32 = I32F32::from_num(0.0001);
let vector: Vec<f32> = 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<Vec<I32F32>> = vec_to_mat_fixed(&vector, 4, true);
inplace_col_max_upscale(&mut mat);
let target: Vec<f32> = vec![
0., 0.25, 0.5, 0.75, 1., 0., 0.001, 0.01, 0.1, 1., 0., 0., 0., 0., 0., 1., 1., 1., 1.,
1.,
];
assert_mat_compare(&mat, &vec_to_mat_fixed(&target, 4, true), epsilon);
}
#[test]
fn test_math_inplace_col_max_upscale_sparse() {
let mut mat: Vec<Vec<(u16, I32F32)>> = vec![vec![]];
let target: Vec<Vec<(u16, I32F32)>> = vec![vec![]];
inplace_col_max_upscale_sparse(&mut mat, 0);
assert_eq!(&mat, &target);
let mut mat: Vec<Vec<(u16, I32F32)>> = vec![vec![(0, I32F32::from_num(0))]];
let target: Vec<Vec<(u16, I32F32)>> = vec![vec![(0, I32F32::from_num(0))]];
inplace_col_max_upscale_sparse(&mut mat, 1);
assert_eq!(&mat, &target);
let epsilon: I32F32 = I32F32::from_num(0.0001);
let vector: Vec<f32> = 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_max_upscale_sparse(&mut mat, 6);
let target: Vec<f32> = vec![
0., 0.25, 0., 0.5, 0., 0.75, 1., 0., 0.333333, 0., 0.666666, 0., 1., 0., 0.25, 0., 0.,
0.5, 0., 0.75, 1., 0., 0.001, 0., 0.01, 0.1, 0., 1., 0., 0., 0., 0., 0., 0., 0., 1.,
1., 1., 1., 1., 1., 1.,
];
assert_sparse_mat_compare(&mat, &vec_to_sparse_mat_fixed(&target, 6, true), epsilon);
let vector: Vec<f32> = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.];
let target: Vec<f32> = 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_max_upscale_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<(u16, I32F32)>> = vec![];
let target: Vec<Vec<(u16, I32F32)>> = vec![];
inplace_col_max_upscale_sparse(&mut mat, 0);
assert_sparse_mat_compare(&mat, &target, epsilon);
}
#[test]
fn test_math_inplace_mask_vector() {
let mask: Vec<bool> = vec![false, false, false];
let mut vector: Vec<I32F32> = vec_to_fixed(&vec![0., 1., 2.]);
let target: Vec<I32F32> = 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<bool> = vec![false, true, false];
let mut vector: Vec<I32F32> = vec_to_fixed(&vec![0., 1., 2.]);
let target: Vec<I32F32> = 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<bool> = vec![true, true, true];
let mut vector: Vec<I32F32> = vec_to_fixed(&vec![0., 1., 2.]);
let target: Vec<I32F32> = 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<bool>> = vec![
vec![false, false, false],
vec![false, false, false],
vec![false, false, false],
];
let vector: Vec<f32> = 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<bool>> = vec![
vec![true, false, false],
vec![false, true, false],
vec![false, false, true],
];
let target: Vec<f32> = 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<bool>> = vec![
vec![true, true, true],
vec![true, true, true],
vec![true, true, true],
];
let target: Vec<f32> = 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<f32> = vec![1., 2., 3., 4., 5., 6., 7., 8., 9.];
let mask: Vec<bool> = vec![false, false, false];
let target: Vec<f32> = 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<bool> = vec![true, true, true];
let target: Vec<f32> = 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<bool> = vec![true, false, true];
let target: Vec<f32> = 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<f32> = vec![0., 0., 0., 0., 0., 0., 0., 0., 0.];
let mut mat = vec_to_mat_fixed(&input, 3, false);
let mask: Vec<bool> = vec![false, false, false];
let target: Vec<f32> = 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<f32> = vec![1., 2., 3., 4., 5., 6., 7., 8., 9.];
let target: Vec<f32> = 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<f32> = vec![1., 2., 3., 4., 5., 6., 7., 8., 9.];
let mat = vec_to_sparse_mat_fixed(&input, 3, false);
let mask: Vec<bool> = vec![false, false, false];
let target: Vec<f32> = 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<bool> = vec![true, true, true];
let target: Vec<f32> = 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),
);
let mask: Vec<bool> = vec![true, false, true];
let target: Vec<f32> = 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 input: Vec<f32> = vec![0., 0., 0., 0., 0., 0., 0., 0., 0.];
let mat = vec_to_sparse_mat_fixed(&input, 3, false);
let mask: Vec<bool> = vec![false, false, false];
let target: Vec<f32> = 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),
);
}
#[test]
fn test_math_mask_diag_sparse() {
let vector: Vec<f32> = vec![1., 2., 3., 4., 5., 6., 7., 8., 9.];
let target: Vec<f32> = vec![0., 2., 3., 4., 0., 6., 7., 8., 0.];
let mat = vec_to_sparse_mat_fixed(&vector, 3, false);
let result = mask_diag_sparse(&mat);
assert_sparse_mat_compare(
&result,
&vec_to_sparse_mat_fixed(&target, 3, false),
I32F32::from_num(0),
);
let vector: Vec<f32> = vec![1., 0., 0., 0., 5., 0., 0., 0., 9.];
let target: Vec<f32> = vec![0., 0., 0., 0., 0., 0., 0., 0., 0.];
let mat = vec_to_sparse_mat_fixed(&vector, 3, false);
let result = mask_diag_sparse(&mat);
assert_sparse_mat_compare(
&result,
&vec_to_sparse_mat_fixed(&target, 3, false),
I32F32::from_num(0),
);
let vector: Vec<f32> = vec![0., 0., 0., 0., 0., 0., 0., 0., 0.];
let target: Vec<f32> = vec![0., 0., 0., 0., 0., 0., 0., 0., 0.];
let mat = vec_to_sparse_mat_fixed(&vector, 3, false);
let result = mask_diag_sparse(&mat);
assert_sparse_mat_compare(
&result,
&vec_to_sparse_mat_fixed(&target, 3, false),
I32F32::from_num(0),
);
}
#[test]
fn test_math_vec_mask_sparse_matrix() {
let vector: Vec<f32> = vec![1., 2., 3., 4., 5., 6., 7., 8., 9.];
let target: Vec<f32> = vec![0., 2., 3., 4., 0., 6., 7., 8., 0.];
let mat = vec_to_sparse_mat_fixed(&vector, 3, false);
let first_vector: Vec<u64> = vec![1, 2, 3];
let second_vector: Vec<u64> = 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<f32> = vec![1., 0., 0., 4., 5., 0., 7., 8., 9.];
let mat = vec_to_sparse_mat_fixed(&vector, 3, false);
let first_vector: Vec<u64> = vec![1, 2, 3];
let second_vector: Vec<u64> = 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<f32> = vec![0., 0., 0., 0., 0., 0., 0., 0., 0.];
let target: Vec<f32> = vec![0., 0., 0., 0., 0., 0., 0., 0., 0.];
let mat = vec_to_sparse_mat_fixed(&vector, 3, false);
let first_vector: Vec<u64> = vec![1, 2, 3];
let second_vector: Vec<u64> = 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<I32F32> = vec_to_fixed(&vec![1., 2., 3., 4.]);
let matrix: Vec<f32> = 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<f32> = 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<I32F32> = vec_to_fixed(&vec![1., 2., 3., 4.]);
let matrix: Vec<f32> = 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<f32> = 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<f32> = 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<f32> = 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<f32> = 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<f32> = 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<f32> = 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<I32F32> = 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<f32> = 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<I32F32> = vec_to_fixed(&vec![6., 15., 24., 33.]);
assert_vec_compare(&result, &target, I32F32::from_num(0));
let matrix: Vec<f32> = 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<I32F32> = vec_to_fixed(&vec![5., 10., 15., 33.]);
assert_vec_compare(&result, &target, I32F32::from_num(0));
let matrix: Vec<f32> = 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<I32F32> = vec_to_fixed(&vec![6., 0., 24., 33.]);
assert_vec_compare(&result, &target, I32F32::from_num(0));
let matrix: Vec<f32> = 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<I32F32> = 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<f32> = 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<I32F32> = 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<f32> = 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<I32F32> = vec_to_fixed(&vec![22., 26., 30.]);
assert_vec_compare(&result, &target, I32F32::from_num(0));
let matrix: Vec<f32> = 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<I32F32> = vec_to_fixed(&vec![21., 21., 21.]);
assert_vec_compare(&result, &target, I32F32::from_num(0));
let matrix: Vec<f32> = 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<I32F32> = vec_to_fixed(&vec![22., 0., 30.]);
assert_vec_compare(&result, &target, I32F32::from_num(0));
let matrix: Vec<f32> = 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<I32F32> = vec_to_fixed(&vec![0., 0., 0.]);
assert_vec_compare(&result, &target, I32F32::from_num(0));
}
#[test]
fn test_math_matmul() {
let vector: Vec<I32F32> = vec_to_fixed(&vec![1., 2., 3., 4.]);
let matrix: Vec<f32> = 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<I32F32> = 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<I32F32> = vec_to_fixed(&vec![1., 2., 3.]);
let matrix: Vec<f32> = 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<I32F32> = 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<I32F32> = vec_to_fixed(&vec![1., 2., 3., 4.]);
let matrix: Vec<f32> = 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<I32F32> = vec_to_fixed(&vec![70., 80., 90.]);
assert_vec_compare(&result, &target, I32F32::from_num(0));
let matrix: Vec<f32> = 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<I32F32> = vec_to_fixed(&vec![69., 70., 63.]);
assert_vec_compare(&result, &target, I32F32::from_num(0));
let matrix: Vec<f32> = 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<I32F32> = 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<I32F32> = vec_to_fixed(&vec![1., 2., 3.]);
let matrix: Vec<f32> = 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_transpose_sparse(&matrix, &vector);
let target: Vec<I32F32> = vec_to_fixed(&vec![14., 32., 50., 68.]);
assert_vec_compare(&result, &target, I32F32::from_num(0));
let matrix: Vec<f32> = 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<I32F32> = vec_to_fixed(&vec![13., 22., 23., 68.]);
assert_vec_compare(&result, &target, I32F32::from_num(0));
let matrix: Vec<f32> = 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<I32F32> = 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<I32F32> = vec_to_fixed(&vec![0., 5., 12.]);
let matrix: Vec<f32> = 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<f32> = 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<I32F32> = vec_to_fixed(&vec![0., 5., 12.]);
let matrix: Vec<f32> = 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<f32> = 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<f32> = 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<f32> = 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<f32> = 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<f32> = 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<f32> = 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<f32> = 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<f32> = 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<f32> = 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<f32> = 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<f32> = 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<I32F32> = vec_to_fixed(&vec![]);
let score: Vec<I32F32> = 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<I32F32> = normalize(&vec_to_fixed(&vec![0.51]));
let score: Vec<I32F32> = 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<I32F32> = vec_to_fixed(&vec![0.49, 0.51]);
let score: Vec<I32F32> = 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<I32F32> = vec_to_fixed(&vec![0.51, 0.49]);
let score: Vec<I32F32> = 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<I32F32> = vec_to_fixed(&vec![0.49, 0., 0.51]);
let score: Vec<I32F32> = 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<I32F32> = vec_to_fixed(&vec![0.49, 0.01, 0.5]);
let score: Vec<I32F32> = 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<I32F32> = vec_to_fixed(&vec![0.49, 0.51, 0.0]);
let score: Vec<I32F32> = 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<I32F32> = vec_to_fixed(&vec![0.0, 0.49, 0.51]);
let score: Vec<I32F32> = 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<I32F32> = vec_to_fixed(&vec![0.0, 0.49, 0.0, 0.51]);
let score: Vec<I32F32> = 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<I32F32> = vec_to_fixed(&vec![0.0, 0.49, 0.0, 0.51, 0.0]);
let score: Vec<I32F32> = 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<I32F32> = vec_to_fixed(&vec![0.2, 0.2, 0.2, 0.2, 0.2]);
let score: Vec<I32F32> = 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<I32F32> =
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<I32F32> =
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 vec![false, true] {
let mut stake: Vec<I32F32> = vec![];
let mut score: Vec<I32F32> = 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<I32F32> = 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.is_empty() {
medians.push(zero);
}
let stake_idx: Vec<usize> = (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<usize> = (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<I32F32> = vec_to_fixed(&vec![]);
let weights: Vec<Vec<I32F32>> = vec![vec![]];
let median: Vec<I32F32> = vec_to_fixed(&vec![]);
assert_eq!(median, weighted_median_col(&stake, &weights, fixed(0.5)));
let stake: Vec<I32F32> = vec_to_fixed(&vec![0., 0.]);
let weights: Vec<f32> = vec![0., 0., 0., 0.];
let weights: Vec<Vec<I32F32>> = vec_to_mat_fixed(&weights, 2, false);
let median: Vec<I32F32> = vec_to_fixed(&vec![0., 0.]);
assert_eq!(median, weighted_median_col(&stake, &weights, fixed(0.5)));
let stake: Vec<I32F32> = vec_to_fixed(&vec![0., 0.75, 0.25, 0.]);
let weights: Vec<f32> = vec![0., 0.1, 0., 0., 0.2, 0.4, 0., 0.3, 0.1, 0., 0.4, 0.5];
let weights: Vec<Vec<I32F32>> = vec_to_mat_fixed(&weights, 4, false);
let median: Vec<I32F32> = vec_to_fixed(&vec![0., 0.3, 0.4]);
assert_eq!(median, weighted_median_col(&stake, &weights, fixed(0.24)));
let median: Vec<I32F32> = vec_to_fixed(&vec![0., 0.2, 0.4]);
assert_eq!(median, weighted_median_col(&stake, &weights, fixed(0.26)));
let median: Vec<I32F32> = vec_to_fixed(&vec![0., 0.2, 0.1]);
assert_eq!(median, weighted_median_col(&stake, &weights, fixed(0.76)));
let stake: Vec<I32F32> = vec_to_fixed(&vec![0., 0.3, 0.2, 0.5]);
let weights: Vec<f32> = vec![0., 0.1, 0., 0., 0.2, 0.4, 0., 0.3, 0.1, 0., 0., 0.5];
let weights: Vec<Vec<I32F32>> = vec_to_mat_fixed(&weights, 4, false);
let median: Vec<I32F32> = 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<I32F32> = vec_to_fixed(&vec![]);
let weights: Vec<Vec<(u16, I32F32)>> = vec![vec![]];
let median: Vec<I32F32> = vec_to_fixed(&vec![]);
assert_eq!(
median,
weighted_median_col_sparse(&stake, &weights, 0, fixed(0.5))
);
let stake: Vec<I32F32> = vec_to_fixed(&vec![0., 0.]);
let weights: Vec<f32> = vec![0., 0., 0., 0.];
let weights: Vec<Vec<(u16, I32F32)>> = vec_to_sparse_mat_fixed(&weights, 2, false);
let median: Vec<I32F32> = vec_to_fixed(&vec![0., 0.]);
assert_eq!(
median,
weighted_median_col_sparse(&stake, &weights, 2, fixed(0.5))
);
let stake: Vec<I32F32> = vec_to_fixed(&vec![0., 0.75, 0.25, 0.]);
let weights: Vec<f32> = vec![0., 0.1, 0., 0., 0.2, 0.4, 0., 0.3, 0.1, 0., 0.4, 0.5];
let weights: Vec<Vec<(u16, I32F32)>> = vec_to_sparse_mat_fixed(&weights, 4, false);
let median: Vec<I32F32> = 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<I32F32> = 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<I32F32> = 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<I32F32> = vec_to_fixed(&vec![0., 0.3, 0.2, 0.5]);
let weights: Vec<f32> = vec![0., 0.1, 0., 0., 0.2, 0.4, 0., 0.3, 0.1, 0., 0., 0.5];
let weights: Vec<Vec<(u16, I32F32)>> = vec_to_sparse_mat_fixed(&weights, 4, false);
let median: Vec<I32F32> = 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<f32> = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.];
let mat1: Vec<f32> = vec![
10., 20., 30., 40., 50., 60., 70., 80., 90., 100., 110., 120.,
];
let target: Vec<f32> = 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<f32> = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.];
let mat1: Vec<f32> = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.];
let target: Vec<f32> = 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<f32> = vec![1., 0., 0., 0., 2., 0., 0., 0., 3., 0., 0., 0.];
let mat1: Vec<f32> = vec![0., 0., 4., 0., 5., 0., 6., 0., 0., 0., 0., 0.];
let target: Vec<f32> = 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<f32> = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.];
let mat1: Vec<f32> = vec![
10., 20., 30., 40., 50., 60., 70., 80., 90., 100., 110., 120.,
];
let target: Vec<f32> = 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<f32> = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.];
let mat1: Vec<f32> = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.];
let target: Vec<f32> = 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<f32> = vec![1., 0., 0., 0., 2., 0., 0., 0., 3., 0., 0., 0.];
let mat1: Vec<f32> = vec![0., 0., 4., 0., 5., 0., 6., 0., 0., 0., 0., 0.];
let target: Vec<f32> = 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<f32> = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.];
let new: Vec<f32> = vec![
10., 20., 30., 40., 50., 60., 70., 80., 90., 100., 110., 120.,
];
let target: Vec<f32> = 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<f32> = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.];
let new: Vec<f32> = vec![
10., 20., 30., 40., 50., 60., 70., 80., 90., 100., 110., 120.,
];
let target: Vec<f32> = 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<f32> = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.];
let new: Vec<f32> = vec![
10., 20., 30., 40., 50., 60., 70., 80., 90., 100., 110., 120.,
];
let target: Vec<f32> = 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<f32> = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.];
let new: Vec<f32> = vec![
10., 20., 30., 40., 50., 60., 70., 80., 90., 100., 110., 120.,
];
let target: Vec<f32> = 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<f32> = vec![0., 2., 3., 4., 0., 6., 7., 8., 0., 10., 11., 12.];
let new: Vec<f32> = vec![10., 20., 0., 40., 0., 60., 0., 80., 90., 100., 110., 120.];
let target: Vec<f32> = 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<f32> = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.];
let new: Vec<f32> = vec![10., 20., 0., 40., 0., 60., 0., 80., 90., 100., 110., 120.];
let target: Vec<f32> = 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<f32> = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.];
let new: Vec<f32> = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.];
let target: Vec<f32> = 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<f32> = vec![1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.];
let new: Vec<f32> = vec![0., 0., 0., 0., 2., 0., 0., 0., 0., 0., 0., 0.];
let target: Vec<f32> = 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<I32F32>> = 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<I32F32>> = 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<I32F32>> = 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<I32F32>> = 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,
);
}
#[test]
fn test_math_fixed_to_u16() {
let expected = u16::MIN;
assert_eq!(fixed_to_u16(I32F32::from_num(expected)), expected);
let expected = u16::MAX / 2;
assert_eq!(fixed_to_u16(I32F32::from_num(expected)), expected);
let expected = u16::MAX;
assert_eq!(fixed_to_u16(I32F32::from_num(expected)), expected);
}
#[test]
#[should_panic(expected = "overflow")]
fn test_math_fixed_to_u16_panics() {
let bad_input = I32F32::from_num(u32::MAX);
fixed_to_u16(bad_input);
let bad_input = I32F32::from_num(-1);
fixed_to_u16(bad_input);
}
// TODO: Investigate why `I32F32` and not `I64F64`
#[test]
fn test_math_fixed_to_u64() {
let expected = u64::MIN;
assert_eq!(fixed_to_u64(I32F32::from_num(expected)), expected);
// let expected = u64::MAX / 2;
// assert_eq!(fixed_to_u64(I32F32::from_num(expected)), expected);
// let expected = u64::MAX;
// assert_eq!(fixed_to_u64(I32F32::from_num(expected)), expected);
}
#[test]
#[should_panic(expected = "-1 overflows")]
fn test_math_fixed_to_u64_panics() {
let bad_input = I32F32::from_num(-1);
fixed_to_u64(bad_input);
}
#[test]
fn test_math_fixed64_to_u64() {
let expected = u64::MIN;
assert_eq!(fixed64_to_u64(I64F64::from_num(expected)), expected);
let input = i64::MAX / 2;
let expected = u64::try_from(input).unwrap();
assert_eq!(fixed64_to_u64(I64F64::from_num(input)), expected);
let input = i64::MAX;
let expected = u64::try_from(input).unwrap();
assert_eq!(fixed64_to_u64(I64F64::from_num(input)), expected);
}
#[test]
#[should_panic(expected = "-1 overflows")]
fn test_math_fixed64_to_u64_panics() {
let bad_input = I64F64::from_num(-1);
fixed64_to_u64(bad_input);
}
/* @TODO: find the _true_ max, and half, input values */
#[test]
fn test_math_fixed64_to_fixed32() {
let input = u64::MIN;
let expected = u32::try_from(input).unwrap();
assert_eq!(fixed64_to_fixed32(I64F64::from_num(expected)), expected);
let expected = u32::MAX / 2;
let input = u64::try_from(expected).unwrap();
assert_eq!(fixed64_to_fixed32(I64F64::from_num(input)), expected);
}
#[test]
#[should_panic(expected = "overflow")]
fn test_math_fixed64_to_fixed32_panics() {
let bad_input = I64F64::from_num(u32::MAX);
fixed64_to_fixed32(bad_input);
}
#[test]
fn test_math_u16_to_fixed() {
let input = u16::MIN;
let expected = I32F32::from_num(input);
assert_eq!(u16_to_fixed(input), expected);
let input = u16::MAX / 2;
let expected = I32F32::from_num(input);
assert_eq!(u16_to_fixed(input), expected);
let input = u16::MAX;
let expected = I32F32::from_num(input);
assert_eq!(u16_to_fixed(input), expected);
}
#[test]
fn test_math_u16_proportion_to_fixed() {
let input = u16::MIN;
let expected = I32F32::from_num(input);
assert_eq!(u16_proportion_to_fixed(input), expected);
}
#[test]
fn test_fixed_proportion_to_u16() {
let expected = u16::MIN;
let input = I32F32::from_num(expected);
assert_eq!(fixed_proportion_to_u16(input), expected);
}
#[test]
#[should_panic(expected = "overflow")]
fn test_fixed_proportion_to_u16_panics() {
let expected = u16::MAX;
let input = I32F32::from_num(expected);
fixed_proportion_to_u16(input);
}
#[test]
fn test_vec_fixed64_to_fixed32() {
let input = vec![I64F64::from_num(i32::MIN)];
let expected = vec![I32F32::from_num(i32::MIN)];
assert_eq!(vec_fixed64_to_fixed32(input), expected);
let input = vec![I64F64::from_num(i32::MAX)];
let expected = vec![I32F32::from_num(i32::MAX)];
assert_eq!(vec_fixed64_to_fixed32(input), expected);
}
#[test]
#[should_panic(expected = "overflow")]
fn test_vec_fixed64_to_fixed32_panics() {
let bad_input = vec![I64F64::from_num(i64::MAX)];
vec_fixed64_to_fixed32(bad_input);
}
// #[test]
// #[allow(arithmetic_overflow)]
// fn test_checked_sum() {
// let overflowing_input = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, u64::MAX];
// // Expect None when overflow occurs
// assert_eq!(checked_sum(&overflowing_input), None);
//
// let normal_input = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// // Expect Some when no overflow occurs
// assert_eq!(checked_sum(&normal_input), Some(55));
//
// let empty_input: Vec<u16> = vec![];
// // Expect Some(u16::default()) when input is empty
// assert_eq!(checked_sum(&empty_input), Some(u16::default()));
//
// let single_input = vec![1];
// // Expect Some(...) when input is a single value
// assert_eq!(checked_sum(&single_input), Some(1));
// }
}
cw-cyber/contracts/cybernet/src/math.rs
ฯ 0.0%
use ;
use exp;
// Max-upscale vector and convert to u16 so max_value = u16::MAX. Assumes non-negative normalized input.
// Max-upscale u16 vector and convert to u16 so max_value = u16::MAX. Assumes u16 vector input.
// Checks if u16 vector, when normalized, has a max value not greater than a u16 ratio max_limit.
// Return true when vector sum is zero.
// Exp safe function with I32F32 output of I32F32 input.
// Sigmoid safe function with I32F32 output of I32F32 input with offset kappa and (recommended) scaling 0 < rho <= 40.
// Returns a bool vector where an item is true if the vector item is in topk values.
// Returns a normalized (sum to 1 except 0) copy of the input vector.
// Normalizes (sum to 1 except 0) the input vector directly in-place.
// Normalizes (sum to 1 except 0) the input vector directly in-place, using the sum arg.
// Normalizes (sum to 1 except 0) the I64F64 input vector directly in-place.
/// Returns x / y for input vectors x and y, if y == 0 return 0.
// Normalizes (sum to 1 except 0) each row (dim=0) of a matrix in-place.
// Normalizes (sum to 1 except 0) each row (dim=0) of a sparse matrix in-place.
// Sum across each row (dim=0) of a matrix.
// Sum across each row (dim=0) of a sparse matrix.
// Sum across each column (dim=1) of a matrix.
// Sum across each column (dim=1) of a sparse matrix.
// Normalizes (sum to 1 except 0) each column (dim=1) of a sparse matrix in-place.
// Normalizes (sum to 1 except 0) each column (dim=1) of a matrix in-place.
// Max-upscale each column (dim=1) of a sparse matrix in-place.
// Max-upscale each column (dim=1) of a matrix in-place.
// Apply mask to vector, mask=true will mask out, i.e. set to 0.
// Apply mask to matrix, mask=true will mask out, i.e. set to 0.
// Apply row mask to matrix, mask=true will mask out, i.e. set to 0.
// Mask out the diagonal of the input matrix in-place.
// Return a new sparse matrix that replaces masked rows with an empty vector placeholder.
// Return a new sparse matrix with a masked out diagonal of input sparse matrix.
// Remove cells from sparse matrix where the mask function of two vectors is true.
// Row-wise matrix-vector hadamard product.
// Row-wise sparse matrix-vector hadamard product.
// Row-wise matrix-vector product, column-wise sum: result_j = SUM(i) vector_i * matrix_ij.
// Column-wise matrix-vector product, row-wise sum: result_i = SUM(j) vector_j * matrix_ij.
// Row-wise matrix-vector product, column-wise sum: result_j = SUM(i) vector_i * matrix_ij.
// Row-wise sparse_matrix-vector product, column-wise sum: result_j = SUM(i) vector_i * matrix_ij.
// Column-wise sparse_matrix-vector product, row-wise sum: result_i = SUM(j) vector_j * matrix_ij.
// Set inplace matrix values above column threshold to threshold value.
// Return sparse matrix with values above column threshold set to threshold value.
// Set matrix values below threshold to lower, and equal-above to upper.
// Set inplace matrix values below threshold to lower, and equal-above to upper.
// Set sparse matrix values below threshold to lower, and equal-above to upper.
// Does not add missing elements (0 value assumed) when lower!=0.
// 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<I32F32> ):
// - stake, assumed to be normalized.
//
// * 'score': ( &Vec<I32F32> ):
// - score for which median is sought, 0 <= score <= 1
//
// * 'partition_idx' ( &Vec<usize> ):
// - 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.
//
/// Column-wise weighted median, e.g. stake-weighted median scores per server (column) over all validators (rows).
/// Column-wise weighted median, e.g. stake-weighted median scores per server (column) over all validators (rows).
// Element-wise product of two matrices.
// Element-wise product of two sparse matrices.
// 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.
// 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.
// Return sparse matrix only with elements >= threshold of an input sparse matrix.