use num_traits::clamp;
use crate::{
core::{tsrmath::TensorMath, vec::Vector},
prelude::Vec3f,
};
pub const MACHINE_EPSILON32: f32 = f32::EPSILON * 0.5;
pub const ONE_MINUS_EPSILON: f32 = 1.0 - f32::EPSILON;
pub fn gamma(n: i32) -> f32 {
(n as f32 * MACHINE_EPSILON32) / (1. - n as f32 * MACHINE_EPSILON32)
}
pub fn split_index<F>(size: usize, pred: F) -> usize
where
F: Fn(usize) -> bool,
{
let (mut sz, mut first) = (size.saturating_sub(2), 1);
while sz > 0 {
let half = sz >> 1;
let mid = first + half;
let res = pred(mid);
first = if res { mid + 1 } else { first };
sz = if res {
sz.saturating_sub(half + 1)
} else {
half
};
}
clamp(first - 1, 0, size.saturating_sub(2))
}
pub fn factorial(x: i32) -> f32 {
if x == 0 {
return 1f32;
}
(1..x + 1).fold(1., |acc, x| acc * x as f32)
}
pub fn sigmoid(x: f32) -> f32 {
1. / (1. + (-x).exp())
}
pub fn orthogonalization(v0: Vec3f, v1: Vec3f) -> (Vec3f, Vec3f, Vec3f) {
let (v0, v1) = {
let (v0n, v1n) = (v0.normalize(), v1.normalize());
if v0n.abs() != v1n.abs() {
(v0n, v1n)
} else {
let v1p = v1n + Vec3f::vec([f32::EPSILON, 0., 0.]);
(v0n, v1p)
}
};
let right = v0.cross(v1).normalize();
let up = right.cross(v0).normalize();
(v0, up, right)
}
#[test]
fn test_split() {
let arr = [2, 2, 3];
let i = split_index(arr.len(), |i| arr[i] == 2);
assert_eq!(i, 1);
let arr = [2, 2, 2];
let i = split_index(arr.len(), |i| arr[i] == 2);
assert_eq!(i, 1);
let arr = [2, 2, 3];
let i = split_index(arr.len(), |i| arr[i] == 1);
assert_eq!(i, 0);
}