use core::cmp::Ordering;
use maryada::{
DecoratedInterval, Decoration, Interval, Signal, SignalFlags, convex_hull, decoration_part,
disjoint, interior, intersection, set_dec, subset,
};
#[test]
fn constructors_and_set_operations_follow_the_set_based_model() {
assert!(maryada::new::<Interval>(2.0, 1.0).is_empty());
assert!(maryada::singleton::<Interval>(f64::NAN).is_empty());
assert!(maryada::new::<DecoratedInterval>(2.0, 1.0).is_nai());
assert!(maryada::singleton::<DecoratedInterval>(f64::NAN).is_nai());
let inner = Interval::new(1.0, 2.0);
let outer = Interval::new(0.0, 3.0);
let apart = Interval::new(4.0, 5.0);
assert!(subset(inner, outer));
assert!(interior(inner, outer));
assert!(disjoint(inner, apart));
assert_eq!(intersection(inner, outer), inner);
assert_eq!(convex_hull(inner, outer), outer);
assert_eq!(intersection(inner, apart), Interval::EMPTY);
assert_eq!(convex_hull(Interval::EMPTY, outer), outer);
}
#[test]
fn ergonomic_protocols_preserve_interval_semantics_and_edge_states() {
let x = Interval::new(1.0, 2.0);
let y = Interval::new(3.0, 4.0);
assert_eq!(x + y, maryada::add(x, y));
assert_eq!(x - y, maryada::sub(x, y));
assert_eq!(x * 2.0, maryada::mul(x, 2.0.into()));
assert_eq!(2.0 * x, maryada::mul(2.0.into(), x));
assert_eq!(x / 2.0, maryada::div(x, 2.0.into()));
assert_eq!(2.0 / x, maryada::div(2.0.into(), x));
assert_eq!(-x, maryada::neg(x));
assert_eq!(x.powi(3), Interval::new(1.0, 8.0));
let hypot = x.hypot(y);
assert!(hypot.contains(10.0_f64.sqrt()));
assert!(hypot.contains(20.0_f64.sqrt()));
assert_eq!(x.bounds(), (1.0, 2.0));
let (midpoint, radius) = x.mid_rad();
assert!(midpoint - radius <= x.inf());
assert!(midpoint + radius >= x.sup());
let scalar = 1.5;
assert_eq!(Interval::from(&scalar), Interval::from(scalar));
assert_eq!(
DecoratedInterval::from(&scalar),
DecoratedInterval::from(scalar)
);
assert_eq!(DecoratedInterval::from(&x), DecoratedInterval::from(x));
assert_eq!(Interval::from(&DecoratedInterval::from(x)), x);
assert_eq!(
Interval::from(DecoratedInterval::from(scalar)),
scalar.into()
);
let parsed: Interval = "[1/3,2/3]".parse().unwrap();
let displayed = parsed.to_string();
assert_eq!(displayed.parse::<Interval>().unwrap(), parsed);
assert!("not an interval".parse::<Interval>().is_err());
let decorated: DecoratedInterval = "[1,2]_def".parse().unwrap();
assert_eq!(decoration_part(decorated), Decoration::Def);
assert_eq!(decorated.powi(3).bounds(), (1.0, 8.0));
let decorated_y = set_dec(y, Decoration::Def);
let decorated_hypot = decorated.hypot(decorated_y);
assert!(decorated_hypot.contains(10.0_f64.sqrt()));
assert!(decorated_hypot.contains(20.0_f64.sqrt()));
let (midpoint, radius) = decorated.mid_rad();
assert!(midpoint - radius <= decorated.inf());
assert!(midpoint + radius >= decorated.sup());
assert_eq!(
decorated.to_string().parse::<DecoratedInterval>().unwrap(),
decorated
);
assert!("[empty]_com".parse::<DecoratedInterval>().is_err());
let mut signals = SignalFlags::NONE;
assert!(Interval::new(2.0, 1.0).decorate(&mut signals).is_nai());
assert!(signals.contains(Signal::UndefinedOperation));
signals.clear();
assert!(Interval::new(f64::NAN, 1.0).decorate(&mut signals).is_nai());
assert!(signals.contains(Signal::UndefinedOperation));
assert_eq!(x.partial_cmp(&x), Some(Ordering::Equal));
assert_eq!(
x.partial_cmp(&Interval::new(0.0, 3.0)),
Some(Ordering::Less)
);
assert_eq!(
Interval::new(0.0, 3.0).partial_cmp(&x),
Some(Ordering::Greater)
);
assert_eq!(x.partial_cmp(&Interval::new(1.5, 2.5)), None);
let same_set_lower_decoration = set_dec(x, Decoration::Trv);
let same_set_higher_decoration = set_dec(x, Decoration::Com);
assert_eq!(
same_set_lower_decoration.partial_cmp(&same_set_higher_decoration),
None
);
assert_eq!(
DecoratedInterval::NAI.partial_cmp(&DecoratedInterval::NAI),
Some(Ordering::Equal)
);
let (left, right) = x.bisect();
assert_eq!(left.convex_hull(right), x);
assert_eq!(Interval::EMPTY.bisect(), (Interval::EMPTY, Interval::EMPTY));
let (left, right) = decorated.bisect();
assert_eq!(decoration_part(left), Decoration::Def);
assert_eq!(decoration_part(right), Decoration::Def);
assert_eq!(
DecoratedInterval::NAI.bisect(),
(DecoratedInterval::NAI, DecoratedInterval::NAI)
);
assert_eq!(x.hull_value(5.0), Interval::new(1.0, 5.0));
assert!(x.contains(1.5));
assert!(!x.contains(f64::INFINITY));
assert!(x.intersects(Interval::new(2.0, 3.0)));
assert!(x.is_bounded());
assert!(!Interval::ENTIRE.is_bounded());
assert!(Interval::from(1.0).is_singleton());
assert!(decorated.is_bounded());
assert_eq!(decorated.decoration(), Decoration::Def);
assert_eq!(decorated.hull_value(5.0).bounds(), (1.0, 5.0));
assert!(decorated.intersects(DecoratedInterval::from(2.0)));
assert!(!decorated.is_entire());
assert!(DecoratedInterval::ENTIRE.is_entire());
let decorated_outer = set_dec(Interval::new(0.0, 3.0), Decoration::Def);
assert_eq!(
decorated.partial_cmp(&decorated_outer),
Some(Ordering::Less)
);
assert_eq!(
decorated_outer.partial_cmp(&decorated),
Some(Ordering::Greater)
);
let decorated_overlap = set_dec(Interval::new(1.5, 2.5), Decoration::Def);
assert_eq!(decorated.partial_cmp(&decorated_overlap), None);
let mut invalid_signals = SignalFlags::NONE;
let invalid = Interval::from_be_bytes(&[0; 3], &mut invalid_signals);
assert!(invalid.is_empty());
assert!(invalid_signals.contains(Signal::InvalidOperand));
}
#[test]
fn arithmetic_operators_cover_owned_interval_and_scalar_combinations() {
fn bare(_: Interval) {}
fn decorated(_: DecoratedInterval) {}
macro_rules! check_op {
($op:tt) => {{
let bare_value = Interval::from(2.0);
let decorated_value = DecoratedInterval::from(3.0);
let scalar = 4.0;
bare(bare_value $op bare_value);
decorated(bare_value $op decorated_value);
decorated(decorated_value $op bare_value);
decorated(decorated_value $op decorated_value);
bare(bare_value $op scalar);
bare(scalar $op bare_value);
decorated(decorated_value $op scalar);
decorated(scalar $op decorated_value);
}};
}
check_op!(+);
check_op!(-);
check_op!(*);
check_op!(/);
let mixed = Interval::new(1.0, 2.0) + DecoratedInterval::from(3.0);
assert_eq!(mixed.bounds(), (4.0, 5.0));
assert_eq!(mixed.decoration(), Decoration::Com);
}