use crate::{entity::ShortFloat, global::Float, parameters::DEFAULT_PARAMETERS};
use nar_dev_utils::pipe;
use std::ops::Not;
impl ShortFloat {
#[inline(always)]
pub fn and(self, value: Self) -> Self {
self & value
}
pub fn and_multi(values: impl IntoIterator<Item = Self>) -> Self {
values
.into_iter()
.fold(Self::ONE, Self::and)
}
pub fn or(self, value: Self) -> Self {
self | value
}
pub fn or_multi(values: impl IntoIterator<Item = Self>) -> Self {
pipe! {
values.into_iter()
=> .map(Self::not)
=> Self::and_multi
=> .not()
}
}
#[doc(alias = "ave_ari")]
pub fn arithmetical_average(values: impl IntoIterator<Item = Self>) -> Self {
let mut sum: Float = 0.0;
let mut len: usize = 0;
for v in values.into_iter() {
sum += v.to_float(); len += 1; }
Self::from_float(sum / len as Float)
}
#[doc(alias = "ave_geo")]
pub fn geometrical_average(values: impl IntoIterator<Item = Self>) -> Self {
let mut product: Float = 1.0;
let mut len: usize = 0;
for v in values.into_iter() {
product *= v.to_float(); len += 1; }
Self::from_float(product.powf(1.0 / len as Float))
}
pub fn w2c(w: Float) -> Self {
Self::from_float(Self::w2c_float(w))
}
pub fn w2c_float(w: Float) -> Float {
w / (w + DEFAULT_PARAMETERS.horizon)
}
#[allow(non_snake_case)]
pub fn W2C1() -> ShortFloat {
Self::w2c(1.0)
}
#[allow(non_snake_case)]
pub fn W2C1_float() -> Float {
Self::w2c_float(1.0)
}
pub fn c2w(&self) -> Float {
let c = self.to_float();
DEFAULT_PARAMETERS.horizon * c / (1.0 - c)
}
pub fn max_from(&mut self, other: Self) {
let max = (*self).max(other);
self.set(max);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::entity::ShortFloat;
use crate::{ok, util::AResult};
use nar_dev_utils::{asserts, for_in_ifs, macro_once};
type SF = ShortFloat;
const N: usize = 4000;
const N_FLOAT: Float = N as Float;
macro_rules! sf {
(0) => {
SF::ZERO
};
(1) => {
SF::ONE
};
(HALF) => {
SF::HALF
};
(1/2) => {
SF::HALF
};
($float:expr) => {
SF::from_float($float)
};
}
fn all_sf() -> impl Iterator<Item = SF> {
(0..=N).map(|v| sf!(v as Float / N_FLOAT))
}
macro_rules! for_all_sf {
( ( $($var:pat $(if $cond:expr)?),* $(,)? ) => $($code:tt)* ) => {
for_in_ifs! {
{ $($code)* }
$( for $var in (all_sf()) $(if ($cond))? )*
}
};
}
#[test]
fn and() -> AResult {
for_all_sf! {
(sf1, sf2) =>
let _ = sf1 & sf2;
}
macro_once! {
macro test($($f1:tt & $f2:tt => $expected:tt)*) {
asserts! {
$(
sf!($f1) & sf!($f2) => sf!($expected)
)*
}
}
0 & 0 => 0
0 & 1 => 0
1 & 0 => 0
1 & 1 => 1
1 & 0.1 => 0.1
1 & 0.2 => 0.2
1 & 0.3 => 0.3
1 & 0.4 => 0.4
1 & 0.5 => 0.5
1 & 0.6 => 0.6
1 & 0.7 => 0.7
1 & 0.8 => 0.8
1 & 0.9 => 0.9
0 & 0.1 => 0
0 & 0.2 => 0
0 & 0.3 => 0
0 & 0.4 => 0
0 & 0.5 => 0
0 & 0.6 => 0
0 & 0.7 => 0
0 & 0.8 => 0
0 & 0.9 => 0
0.5 & 0.5 => 0.25
}
ok!()
}
#[test]
fn and_multi() -> AResult {
for_all_sf! {
(sf1, sf2) =>
assert_eq!(sf1 & sf2, SF::and_multi([sf1, sf2]));
}
let mut sfs = Vec::new();
let v = 0.9;
for n in 1..=4 {
sfs.push(sf!(v));
let multi = SF::and_multi(sfs.iter().cloned());
let pow = sf!(v.powi(n));
assert_eq!(multi, pow);
}
macro_once! {
macro test($( $($f:tt)&* ;)*) {
asserts! {
$(
$(sf!($f))&* => SF::and_multi([$(sf!($f)),*])
)*
}
}
0 & 0;
0 & 1;
1 & 0;
1 & 1;
0 & 0 & 0;
0 & 0 & 1;
0 & 1 & 0;
0 & 1 & 1;
1 & 0 & 0;
1 & 0 & 1;
1 & 1 & 0;
1 & 1 & 1;
0.5;
0.5 & 0.5;
0.5 & 0.5 & 0.5;
0.5 & 0.5 & 0.5 & 0.5;
0.5 & 0.5 & 0.5 & 0.5 & 0.5;
0.5 & 0.5 & 0.5 & 0.5 & 0.5 & 0.5;
}
ok!()
}
#[test]
fn or() -> AResult {
for_all_sf! {
(sf1, sf2) =>
let _ = sf1 | sf2;
}
macro_once! {
macro test($($f1:tt | $f2:tt => $expected:tt)*) {
asserts! {
$(
sf!($f1) | sf!($f2) => sf!($expected)
)*
}
}
0 | 0 => 0
0 | 1 => 1
1 | 0 => 1
1 | 1 => 1
1 | 0.1 => 1
1 | 0.2 => 1
1 | 0.3 => 1
1 | 0.4 => 1
1 | 0.5 => 1
1 | 0.6 => 1
1 | 0.7 => 1
1 | 0.8 => 1
1 | 0.9 => 1
0 | 0.1 => 0.1
0 | 0.2 => 0.2
0 | 0.3 => 0.3
0 | 0.4 => 0.4
0 | 0.5 => 0.5
0 | 0.6 => 0.6
0 | 0.7 => 0.7
0 | 0.8 => 0.8
0 | 0.9 => 0.9
0.5 | 0.5 => 0.75
}
ok!()
}
#[test]
fn or_multi() -> AResult {
for_all_sf! {
(sf1, sf2) =>
assert_eq!(sf1 | sf2, SF::or_multi([sf1, sf2]));
}
macro_once! {
macro test($( $($f:tt)|* ;)*) {
asserts! {
$(
$(sf!($f))|* => SF::or_multi([$(sf!($f)),*])
)*
}
}
0 | 0;
0 | 1;
1 | 0;
1 | 1;
0 | 0 | 0;
0 | 0 | 1;
0 | 1 | 0;
0 | 1 | 1;
1 | 0 | 0;
1 | 0 | 1;
1 | 1 | 0;
1 | 1 | 1;
0.5;
0.5 | 0.5;
0.5 | 0.5 | 0.5;
0.5 | 0.5 | 0.5 | 0.5;
0.5 | 0.5 | 0.5 | 0.5 | 0.5;
0.5 | 0.5 | 0.5 | 0.5 | 0.5 | 0.5;
}
ok!()
}
#[test]
fn arithmetical_average() -> AResult {
for_all_sf! {
(sf1, sf2) =>
let ave_ari = SF::arithmetical_average([sf1 ,sf2]);
let float_ari = sf!((sf1.to_float() + sf2.to_float()) / 2.0);
assert_eq!(ave_ari, float_ari);
}
ok!()
}
#[test]
fn geometrical_average() -> AResult {
for_all_sf! {
(sf1, sf2) =>
let ave_geo = SF::geometrical_average([sf1 ,sf2]);
let float_geo = sf!((sf1.to_float() * sf2.to_float()).sqrt());
assert_eq!(ave_geo, float_geo);
}
ok!()
}
#[test]
fn w2c() -> AResult {
const N: usize = 1000;
for w in 0..=N {
let w = w as Float;
let k = DEFAULT_PARAMETERS.horizon;
let c = SF::w2c(w);
assert_eq!(c, sf!(w / (w + k)))
}
ok!()
}
#[test]
fn c2w() -> AResult {
for_all_sf! {
(c if !c.is_one()) =>
let k = DEFAULT_PARAMETERS.horizon;
let w = c.c2w();
let c = c.to_float();
assert_eq!(w, c * k / (1.0 - c))
}
ok!()
}
#[test]
fn max_from() -> AResult {
for_all_sf! {
(mut sf1, sf2) =>
let expected = sf1.max(sf2);
sf1.max_from(sf2);
assert_eq!(sf1, expected);
}
ok!()
}
}