use crate::float::Float;
use witnessed::{WitnessExt, Witnessed};
pub struct Value01;
impl Value01 {
pub fn witness<T: Float>(v: T) -> Result<Witnessed<T, Self>, &'static str> {
if !v.is_finite() {
return Err("Value01: value must be finite");
}
if v < T::zero() || v > T::one() {
return Err("Value01: value must be in [0, 1]");
}
v.witness().by(|_| Ok(Value01))
}
}
pub struct GtZero;
impl GtZero {
pub fn witness<T: Float>(v: T) -> Result<Witnessed<T, Self>, &'static str> {
if !v.is_finite() {
return Err("GtZero: value must be finite");
}
if v <= T::zero() {
return Err("GtZero: value must be strictly positive");
}
v.witness().by(|_| Ok(GtZero))
}
}
pub struct NormalizedWeight;
impl NormalizedWeight {
pub fn from_normalized_container<T: Float>(
value: T,
container: &Witnessed<Vec<T>, NormalizedContainer>,
) -> Result<Self, &'static str> {
if container
.binary_search_by(|a| a.partial_cmp(&value).unwrap_or(core::cmp::Ordering::Equal))
.is_ok()
{
Ok(NormalizedWeight)
} else {
Err("NormalizedWeight: value not found in validated set")
}
}
}
pub struct NormalizedContainer;
impl NormalizedContainer {
pub fn witness<T: Float>(weights: Vec<T>) -> Result<Witnessed<Vec<T>, Self>, &'static str> {
let mut sum = T::zero();
let len = weights.len();
for &w in &weights {
if !w.is_finite() {
return Err("NormalizedContainer: value must be finite");
}
if w < T::zero() || w > T::one() {
return Err("NormalizedContainer: value must be in [0, 1]");
}
sum = sum + w;
}
let diff = if sum > T::one() {
sum - T::one()
} else {
T::one() - sum
};
let tol = T::from_f64(1e-9) * T::from_f64(len as f64).max(T::one());
if diff > tol {
return Err("NormalizedContainer: set must sum to 1");
}
weights.witness().by(|_| Ok(NormalizedContainer))
}
}
#[cfg(test)]
mod tests_for_value;