use crate::fixed_point::imperative::FixedPoint;
use crate::fixed_point::universal::fasc::stack_evaluator::BinaryStorage;
use crate::fixed_point::universal::fasc::stack_evaluator::compute::{
compute_add, compute_checked_add, compute_ceiling, compute_divide,
compute_is_negative, compute_is_zero, compute_negate, downscale_to_storage,
exp_at_compute_tier, ln_at_compute_tier, make_compute_int,
sinhcosh_at_compute_tier, sqrt_at_compute_tier, upscale_to_compute,
};
pub use crate::fixed_point::universal::fasc::stack_evaluator::ComputeStorage;
pub use crate::fixed_point::frac_config::FRAC_BITS;
pub use crate::fixed_point::frac_config::COMPUTE_FRAC_BITS;
#[inline]
pub fn one() -> ComputeStorage {
make_compute_int(1)
}
#[inline]
pub fn ceiling() -> ComputeStorage {
compute_ceiling()
}
#[inline]
pub fn from_fixed(x: FixedPoint) -> ComputeStorage {
upscale_to_compute(x.raw())
}
#[inline]
pub fn to_fixed(x: ComputeStorage) -> FixedPoint {
try_to_fixed(x).expect("compute_tier::to_fixed: value does not fit the storage tier")
}
#[inline]
pub fn try_to_fixed(x: ComputeStorage) -> Option<FixedPoint> {
let raw: BinaryStorage = downscale_to_storage(x).ok()?;
Some(FixedPoint::from_raw(raw))
}
#[inline]
pub fn exp(x: ComputeStorage) -> ComputeStorage {
exp_at_compute_tier(x)
}
#[inline]
pub fn ln(x: ComputeStorage) -> ComputeStorage {
assert!(
!(compute_is_negative(&x) || compute_is_zero(&x)),
"compute_tier::ln: x <= 0 is outside the domain"
);
ln_at_compute_tier(x)
}
#[inline]
pub fn sqrt(x: ComputeStorage) -> ComputeStorage {
assert!(
!compute_is_negative(&x),
"compute_tier::sqrt: x < 0 is outside the domain"
);
sqrt_at_compute_tier(x)
}
#[inline]
pub fn sinhcosh(x: ComputeStorage) -> (ComputeStorage, ComputeStorage) {
sinhcosh_at_compute_tier(x)
}
#[inline]
pub fn sigmoid(x: ComputeStorage) -> ComputeStorage {
let one = make_compute_int(1);
if compute_is_negative(&x) {
let e = exp_at_compute_tier(x);
compute_divide(e, compute_add(one, e))
.expect("sigmoid: denominator in [1,2] cannot overflow")
} else {
let e = exp_at_compute_tier(compute_negate(x));
compute_divide(one, compute_add(one, e))
.expect("sigmoid: denominator in [1,2] cannot overflow")
}
}
#[inline]
pub fn softplus(x: ComputeStorage) -> ComputeStorage {
let one = make_compute_int(1);
let neg_abs = if compute_is_negative(&x) { x } else { compute_negate(x) };
let e = exp_at_compute_tier(neg_abs); let corr = ln_at_compute_tier(compute_add(one, e)); if compute_is_negative(&x) {
corr
} else {
compute_checked_add(x, corr)
.expect("softplus: result does not fit the compute tier")
}
}
#[inline]
pub fn ln1p(x: ComputeStorage) -> ComputeStorage {
let arg = compute_checked_add(make_compute_int(1), x)
.expect("ln1p: 1 + x does not fit the compute tier");
assert!(
!(compute_is_negative(&arg) || compute_is_zero(&arg)),
"compute_tier::ln1p: x <= -1 is outside the domain"
);
ln_at_compute_tier(arg)
}