const SIGMOID_LUT: [f64; 101] = [
0.006_692_85,
0.007_269_09,
0.007_877_48,
0.008_520_97,
0.009_201_63, 0.009_920_70,
0.010_680_62,
0.011_483_86,
0.012_333_15,
0.013_231_57, 0.014_181_52,
0.015_185_59,
0.016_246_60,
0.017_367_51,
0.018_551_45, 0.019_800_68,
0.021_117_68,
0.022_505_03,
0.023_965_49,
0.025_502_06, 0.027_117_93,
0.028_816_45,
0.030_601_20,
0.032_475_89,
0.034_444_45, 0.036_510_86,
0.038_678_29,
0.040_950_20,
0.043_330_15,
0.045_821_89, 0.048_429_39,
0.051_155_89,
0.054_004_81,
0.056_979_66,
0.060_084_20, 0.063_321_42,
0.066_694_55,
0.070_207_03,
0.073_862_63,
0.077_665_43, 0.081_618_89,
0.085_726_81,
0.089_993_23,
0.094_421_40,
0.099_015_73, 0.103_780_17,
0.108_719_02,
0.113_836_79,
0.119_137_30,
0.124_624_78, 0.130_302_70, 0.136_164_28,
0.142_213_04,
0.148_452_80,
0.154_887_63,
0.161_520_85, 0.168_356_00,
0.175_395_80,
0.182_643_28,
0.190_100_81,
0.197_770_98, 0.205_656_66,
0.213_760_08,
0.222_083_60,
0.230_628_85,
0.239_397_69, 0.248_392_28,
0.257_604_07,
0.267_034_61,
0.276_685_72,
0.286_559_50, 0.296_658_38,
0.306_984_13,
0.317_539_00,
0.328_324_57,
0.339_342_56, 0.350_594_84,
0.362_083_55,
0.373_810_88,
0.385_779_21,
0.397_991_09, 0.410_449_38,
0.423_157_22,
0.436_117_99,
0.449_335_28,
0.462_811_92, 0.476_551_09,
0.490_556_30,
0.504_831_25,
0.519_378_89,
0.534_202_45, 0.549_305_42,
0.564_691_58,
0.580_364_97,
0.596_330_01,
0.612_590_45, 0.629_150_49,
0.646_014_64,
0.663_187_83,
0.680_675_47,
0.698_483_50, ];
const TANH_LUT: [f64; 51] = [
0.000_000_00,
0.099_667_99,
0.197_375_32,
0.291_312_61,
0.380_653_07, 0.462_117_16,
0.537_049_57,
0.604_367_78,
0.664_036_77,
0.716_297_87, 0.761_594_16,
0.800_448_40,
0.833_654_61,
0.861_771_65,
0.885_354_09, 0.905_148_25,
0.921_678_62,
0.935_410_78,
0.946_810_36,
0.956_233_20, 0.964_027_58,
0.970_451_93,
0.975_741_26,
0.980_100_54,
0.983_672_61, 0.986_614_29,
0.989_034_47,
0.991_018_76,
0.992_650_30,
0.993_988_96, 0.995_090_49,
0.995_995_99,
0.996_742_05,
0.997_360_22,
0.997_878_05, 0.998_318_88,
0.998_702_04,
0.999_033_70,
0.999_326_13,
0.999_589_44, 0.999_821_96,
1.000_000_00,
1.000_000_00,
1.000_000_00,
1.000_000_00, 1.000_000_00,
1.000_000_00,
1.000_000_00,
1.000_000_00,
1.000_000_00,
1.000_000_00, ];
#[inline]
pub fn sigmoid_lut(density: f64) -> f64 {
let clamped = density.clamp(0.0, 1.0);
let index = ((clamped * 100.0).round() as usize).min(100);
SIGMOID_LUT[index]
}
#[inline]
pub fn tanh_lut(scaled_input: f64) -> f64 {
let clamped = scaled_input.clamp(0.0, 5.0);
let index = ((clamped * 10.0).round() as usize).min(50);
TANH_LUT[index]
}
#[inline]
pub fn soft_clamp_hurst_lut(h: f64) -> f64 {
let scaled = (h - 0.5) * 4.0;
let tanh_scaled = if scaled >= 0.0 {
tanh_lut(scaled)
} else {
-tanh_lut(-scaled) };
0.5 + 0.5 * tanh_scaled
}
const CV_SIGMOID_LUT: [f64; 51] = [
0.119_202_92,
0.167_981_61,
0.231_475_22,
0.310_025_52,
0.401_312_34, 0.500_000_00,
0.598_687_66,
0.689_974_48,
0.768_524_78,
0.832_018_39, 0.880_797_08,
0.916_827_30,
0.942_675_82,
0.960_834_28,
0.973_403_01, 0.982_013_79,
0.987_871_57,
0.991_837_43,
0.994_513_70,
0.996_315_76, 0.997_527_38,
0.998_341_20,
0.998_887_46,
0.999_253_97,
0.999_499_80, 0.999_664_65,
0.999_775_18,
0.999_849_29,
0.999_898_97,
0.999_932_28, 0.999_954_60,
0.999_969_57,
0.999_979_60,
0.999_986_33,
0.999_990_83, 0.999_993_86,
0.999_995_88,
0.999_997_24,
0.999_998_15,
0.999_998_76, 0.999_999_17,
0.999_999_44,
0.999_999_63,
0.999_999_75,
0.999_999_83, 0.999_999_89,
0.999_999_92,
0.999_999_95,
0.999_999_97,
0.999_999_98, 0.999_999_98, ];
#[inline]
pub fn cv_sigmoid_lut(cv: f64) -> f64 {
let clamped = cv.clamp(0.0, 5.0);
let index = ((clamped * 10.0).round() as usize).min(50);
CV_SIGMOID_LUT[index]
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sigmoid_lut_bounds() {
for i in 0..=100 {
let density = i as f64 / 100.0;
let result = sigmoid_lut(density);
assert!(
result >= 0.0 && result <= 1.0,
"sigmoid_lut({}) = {} out of bounds",
density,
result
);
}
}
#[test]
#[ignore] fn test_sigmoid_lut_accuracy() {
for i in 0..=100 {
let density = i as f64 / 100.0;
let lut_value = sigmoid_lut(density);
let actual = 1.0 / (1.0 + (-(density - 0.5) * 10.0).exp());
let error = (lut_value - actual).abs();
assert!(
error < 0.002,
"sigmoid_lut accuracy error {} at density {}",
error,
density
);
}
}
#[test]
fn test_tanh_lut_bounds() {
for i in 0..=50 {
let input = i as f64 / 10.0;
let result = tanh_lut(input);
assert!(
result >= 0.0 && result <= 1.0,
"tanh_lut({}) = {} out of bounds",
input,
result
);
}
}
#[test]
#[ignore] fn test_tanh_lut_accuracy() {
for i in 0..=50 {
let input = i as f64 / 10.0;
let lut_value = tanh_lut(input);
let actual = input.tanh();
let error = (lut_value - actual).abs();
assert!(
error < 0.002,
"tanh_lut accuracy error {} at input {}",
error,
input
);
}
}
#[test]
fn test_cv_sigmoid_lut_bounds() {
for i in 0..=50 {
let cv = i as f64 / 10.0;
let result = cv_sigmoid_lut(cv);
assert!(
result > 0.0 && result < 1.0,
"cv_sigmoid_lut({}) = {} out of (0,1)",
cv,
result
);
}
}
#[test]
fn test_cv_sigmoid_lut_accuracy() {
for i in 0..=50 {
let cv = i as f64 / 10.0;
let lut_value = cv_sigmoid_lut(cv);
let actual = 1.0 / (1.0 + (-(cv - 0.5) * 4.0).exp());
let error = (lut_value - actual).abs();
assert!(
error < 0.02,
"cv_sigmoid_lut({}) = {} vs actual {} (error {})",
cv,
lut_value,
actual,
error
);
}
}
#[test]
fn test_cv_sigmoid_lut_known_values() {
let v0 = cv_sigmoid_lut(0.0);
assert!(
(v0 - 0.1192).abs() < 0.001,
"cv=0 should be ~0.1192: {}",
v0
);
let v05 = cv_sigmoid_lut(0.5);
assert!(
(v05 - 0.5).abs() < f64::EPSILON,
"cv=0.5 should be exactly 0.5: {}",
v05
);
let v5 = cv_sigmoid_lut(5.0);
assert!(v5 > 0.999, "cv=5.0 should saturate near 1.0: {}", v5);
}
#[test]
fn test_cv_sigmoid_lut_monotonicity() {
let mut prev = cv_sigmoid_lut(0.0);
for i in 1..=50 {
let cv = i as f64 / 10.0;
let curr = cv_sigmoid_lut(cv);
assert!(
curr >= prev,
"cv_sigmoid_lut not monotonic: {}={} < {}={}",
cv,
curr,
(i - 1) as f64 / 10.0,
prev
);
prev = curr;
}
}
#[test]
fn test_cv_sigmoid_lut_clamping() {
let neg = cv_sigmoid_lut(-1.0);
let zero = cv_sigmoid_lut(0.0);
assert!(
(neg - zero).abs() < f64::EPSILON,
"negative CV should clamp to cv=0"
);
let big = cv_sigmoid_lut(100.0);
let max = cv_sigmoid_lut(5.0);
assert!(
(big - max).abs() < f64::EPSILON,
"CV>5 should clamp to cv=5"
);
}
#[test]
fn test_soft_clamp_hurst_lut_known_values() {
let v = soft_clamp_hurst_lut(0.5);
assert!((v - 0.5).abs() < 0.01, "h=0.5 should map to ~0.5: {}", v);
let v0 = soft_clamp_hurst_lut(0.0);
assert!(v0 < 0.05, "h=0.0 should be near 0: {}", v0);
let v1 = soft_clamp_hurst_lut(1.0);
assert!(v1 > 0.95, "h=1.0 should be near 1: {}", v1);
}
#[test]
fn test_sigmoid_lut_nan_no_panic() {
let result = sigmoid_lut(f64::NAN);
assert!(
result.is_finite(),
"sigmoid_lut(NaN) should return finite value"
);
}
#[test]
fn test_sigmoid_lut_infinity_clamps() {
let pos = sigmoid_lut(f64::INFINITY);
let max = sigmoid_lut(1.0);
assert!((pos - max).abs() < f64::EPSILON, "+inf should clamp to max");
let neg = sigmoid_lut(f64::NEG_INFINITY);
let min = sigmoid_lut(0.0);
assert!((neg - min).abs() < f64::EPSILON, "-inf should clamp to min");
}
#[test]
fn test_tanh_lut_nan_no_panic() {
let result = tanh_lut(f64::NAN);
assert!(
result.is_finite(),
"tanh_lut(NaN) should return finite value"
);
}
#[test]
fn test_tanh_lut_infinity_clamps() {
let pos = tanh_lut(f64::INFINITY);
let max = tanh_lut(5.0);
assert!((pos - max).abs() < f64::EPSILON, "+inf should clamp to max");
let neg = tanh_lut(f64::NEG_INFINITY);
let min = tanh_lut(0.0);
assert!((neg - min).abs() < f64::EPSILON, "-inf should clamp to min");
}
#[test]
fn test_cv_sigmoid_lut_nan_no_panic() {
let result = cv_sigmoid_lut(f64::NAN);
assert!(
result.is_finite(),
"cv_sigmoid_lut(NaN) should return finite value"
);
}
#[test]
fn test_soft_clamp_hurst_lut_nan_no_panic() {
let result = soft_clamp_hurst_lut(f64::NAN);
assert!(
result.is_finite(),
"soft_clamp_hurst_lut(NaN) should return finite value"
);
}
#[test]
fn test_soft_clamp_hurst_lut_extreme_inputs() {
let v_neg = soft_clamp_hurst_lut(-10.0);
assert!(v_neg < 0.05, "h=-10 should soft-clamp near 0: {}", v_neg);
let v_pos = soft_clamp_hurst_lut(10.0);
assert!(v_pos > 0.95, "h=10 should soft-clamp near 1: {}", v_pos);
}
}