#![deny(rustdoc::broken_intra_doc_links)]
pub mod bounded;
pub use bounded::{
IntervalBounded, IntervalClosed, IntervalFiniteLength, IntervalFinitePositiveLength,
IntervalFinitePositiveLengthTrait, IntervalFromBounds, IntervalLowerClosedUpperOpen,
IntervalLowerOpenUpperClosed, IntervalOpen, IntervalSingleton, SubIntervalInPartition,
};
pub mod conversions;
pub mod operations;
pub use operations::{IntervalDifference, IntervalOperations, IntervalUnion};
pub mod traits;
pub use traits::{
Contains, GetLowerBoundValue, GetUpperBoundValue, IntervalBoundsRuntime, IntervalHull,
IntervalTrait,
};
pub mod unbounded;
pub use unbounded::{
IntervalInfiniteLength, IntervalLowerBoundedUpperUnboundedTrait,
IntervalLowerClosedUpperUnbounded, IntervalLowerOpenUpperUnbounded,
IntervalLowerUnboundedUpperBoundedTrait, IntervalLowerUnboundedUpperClosed,
IntervalLowerUnboundedUpperOpen, IntervalLowerUnboundedUpperUnbounded,
};
use crate::{
bounds::{
BoundType, Closed, IntervalBoundRuntime, LowerBound, LowerBoundRuntime, Open, UpperBound,
UpperBoundRuntime, ValueWithinBound, max_upper_bound, max_upper_bound_maybe_unbounded,
min_lower_bound, min_lower_bound_maybe_unbounded,
},
grids::traits::Grid1DIntervalBuilder,
};
use duplicate::duplicate_item;
use num_valid::RealScalar;
use serde::{Deserialize, Serialize};
use std::{backtrace::Backtrace, fmt::Debug};
use thiserror::Error;
#[inline]
fn compute_hull_general<RealType: RealScalar, I1, I2>(
interval1: &I1,
interval2: &I2,
) -> Interval<RealType>
where
I1: IntervalBoundsRuntime<RealType = RealType>,
I2: IntervalBoundsRuntime<RealType = RealType>,
{
let lower1 = interval1.lower_bound_runtime();
let upper1 = interval1.upper_bound_runtime();
let lower2 = interval2.lower_bound_runtime();
let upper2 = interval2.upper_bound_runtime();
let lower = min_lower_bound_maybe_unbounded(lower1, lower2);
let upper = max_upper_bound_maybe_unbounded(upper1, upper2);
Interval::try_from_runtime_bounds(lower, upper).unwrap_or_else(move |err| {
panic!(
"Hull computation produced invalid interval bounds: {err}. This indicates a bug in bound selection logic."
)
})
}
#[inline]
fn compute_hull_bounded_intervals<RealType: RealScalar, I1, I2>(
interval1: &I1,
interval2: &I2,
) -> IntervalFinitePositiveLength<RealType>
where
I1: IntervalFinitePositiveLengthTrait<RealType = RealType>,
I2: IntervalFinitePositiveLengthTrait<RealType = RealType>,
{
let lower1 = interval1.lower_bound_runtime().unwrap();
let upper1 = interval1.upper_bound_runtime().unwrap();
let lower2 = interval2.lower_bound_runtime().unwrap();
let upper2 = interval2.upper_bound_runtime().unwrap();
let lower = min_lower_bound(lower1, lower2);
let upper = max_upper_bound(upper1, upper2);
IntervalFinitePositiveLength::try_from_runtime_bounds(lower, upper)
.expect("Failed to create the interval hull!")
}
#[duplicate_item(
T Other;
[IntervalClosed] [IntervalClosed];
[IntervalClosed] [IntervalOpen];
[IntervalClosed] [IntervalLowerClosedUpperOpen];
[IntervalClosed] [IntervalLowerOpenUpperClosed];
[IntervalOpen] [IntervalClosed];
[IntervalOpen] [IntervalOpen];
[IntervalOpen] [IntervalLowerClosedUpperOpen];
[IntervalOpen] [IntervalLowerOpenUpperClosed];
[IntervalLowerClosedUpperOpen] [IntervalClosed];
[IntervalLowerClosedUpperOpen] [IntervalOpen];
[IntervalLowerClosedUpperOpen] [IntervalLowerClosedUpperOpen];
[IntervalLowerClosedUpperOpen] [IntervalLowerOpenUpperClosed];
[IntervalLowerOpenUpperClosed] [IntervalClosed];
[IntervalLowerOpenUpperClosed] [IntervalOpen];
[IntervalLowerOpenUpperClosed] [IntervalLowerClosedUpperOpen];
[IntervalLowerOpenUpperClosed] [IntervalLowerOpenUpperClosed];
)]
impl<RealType: RealScalar> IntervalHull<Other<RealType>> for T<RealType> {
type Output = IntervalFinitePositiveLength<RealType>;
fn hull(&self, other: &Other<RealType>) -> Self::Output {
compute_hull_bounded_intervals(self, other)
}
}
impl<RealType: RealScalar, Other: IntervalTrait<RealType = RealType>> IntervalHull<Other>
for Interval<RealType>
{
type Output = Interval<RealType>;
fn hull(&self, other: &Other) -> Self::Output {
compute_hull_general(self, other)
}
}
#[duplicate_item(
T Other;
[IntervalClosed] [IntervalLowerClosedUpperUnbounded];
[IntervalClosed] [IntervalLowerOpenUpperUnbounded];
[IntervalClosed] [IntervalLowerUnboundedUpperClosed];
[IntervalClosed] [IntervalLowerUnboundedUpperOpen];
[IntervalClosed] [IntervalLowerUnboundedUpperUnbounded];
[IntervalOpen] [IntervalLowerClosedUpperUnbounded];
[IntervalOpen] [IntervalLowerOpenUpperUnbounded];
[IntervalOpen] [IntervalLowerUnboundedUpperClosed];
[IntervalOpen] [IntervalLowerUnboundedUpperOpen];
[IntervalOpen] [IntervalLowerUnboundedUpperUnbounded];
[IntervalLowerClosedUpperOpen] [IntervalLowerClosedUpperUnbounded];
[IntervalLowerClosedUpperOpen] [IntervalLowerOpenUpperUnbounded];
[IntervalLowerClosedUpperOpen] [IntervalLowerUnboundedUpperClosed];
[IntervalLowerClosedUpperOpen] [IntervalLowerUnboundedUpperOpen];
[IntervalLowerClosedUpperOpen] [IntervalLowerUnboundedUpperUnbounded];
[IntervalLowerOpenUpperClosed] [IntervalLowerClosedUpperUnbounded];
[IntervalLowerOpenUpperClosed] [IntervalLowerOpenUpperUnbounded];
[IntervalLowerOpenUpperClosed] [IntervalLowerUnboundedUpperClosed];
[IntervalLowerOpenUpperClosed] [IntervalLowerUnboundedUpperOpen];
[IntervalLowerOpenUpperClosed] [IntervalLowerUnboundedUpperUnbounded];
)]
impl<RealType: RealScalar> IntervalHull<Other<RealType>> for T<RealType> {
type Output = Interval<RealType>;
fn hull(&self, other: &Other<RealType>) -> Self::Output {
compute_hull_general(self, other)
}
}
#[duplicate_item(
T Other;
[IntervalLowerClosedUpperUnbounded] [IntervalClosed];
[IntervalLowerClosedUpperUnbounded] [IntervalOpen];
[IntervalLowerClosedUpperUnbounded] [IntervalLowerClosedUpperOpen];
[IntervalLowerClosedUpperUnbounded] [IntervalLowerOpenUpperClosed];
[IntervalLowerClosedUpperUnbounded] [IntervalLowerClosedUpperUnbounded];
[IntervalLowerClosedUpperUnbounded] [IntervalLowerOpenUpperUnbounded];
[IntervalLowerClosedUpperUnbounded] [IntervalLowerUnboundedUpperClosed];
[IntervalLowerClosedUpperUnbounded] [IntervalLowerUnboundedUpperOpen];
[IntervalLowerClosedUpperUnbounded] [IntervalLowerUnboundedUpperUnbounded];
[IntervalLowerOpenUpperUnbounded] [IntervalClosed];
[IntervalLowerOpenUpperUnbounded] [IntervalOpen];
[IntervalLowerOpenUpperUnbounded] [IntervalLowerClosedUpperOpen];
[IntervalLowerOpenUpperUnbounded] [IntervalLowerOpenUpperClosed];
[IntervalLowerOpenUpperUnbounded] [IntervalLowerClosedUpperUnbounded];
[IntervalLowerOpenUpperUnbounded] [IntervalLowerOpenUpperUnbounded];
[IntervalLowerOpenUpperUnbounded] [IntervalLowerUnboundedUpperClosed];
[IntervalLowerOpenUpperUnbounded] [IntervalLowerUnboundedUpperOpen];
[IntervalLowerOpenUpperUnbounded] [IntervalLowerUnboundedUpperUnbounded];
[IntervalLowerUnboundedUpperClosed] [IntervalClosed];
[IntervalLowerUnboundedUpperClosed] [IntervalOpen];
[IntervalLowerUnboundedUpperClosed] [IntervalLowerClosedUpperOpen];
[IntervalLowerUnboundedUpperClosed] [IntervalLowerOpenUpperClosed];
[IntervalLowerUnboundedUpperClosed] [IntervalLowerClosedUpperUnbounded];
[IntervalLowerUnboundedUpperClosed] [IntervalLowerOpenUpperUnbounded];
[IntervalLowerUnboundedUpperClosed] [IntervalLowerUnboundedUpperClosed];
[IntervalLowerUnboundedUpperClosed] [IntervalLowerUnboundedUpperOpen];
[IntervalLowerUnboundedUpperClosed] [IntervalLowerUnboundedUpperUnbounded];
[IntervalLowerUnboundedUpperOpen] [IntervalClosed];
[IntervalLowerUnboundedUpperOpen] [IntervalOpen];
[IntervalLowerUnboundedUpperOpen] [IntervalLowerClosedUpperOpen];
[IntervalLowerUnboundedUpperOpen] [IntervalLowerOpenUpperClosed];
[IntervalLowerUnboundedUpperOpen] [IntervalLowerClosedUpperUnbounded];
[IntervalLowerUnboundedUpperOpen] [IntervalLowerOpenUpperUnbounded];
[IntervalLowerUnboundedUpperOpen] [IntervalLowerUnboundedUpperClosed];
[IntervalLowerUnboundedUpperOpen] [IntervalLowerUnboundedUpperOpen];
[IntervalLowerUnboundedUpperOpen] [IntervalLowerUnboundedUpperUnbounded];
[IntervalLowerUnboundedUpperUnbounded] [IntervalClosed];
[IntervalLowerUnboundedUpperUnbounded] [IntervalOpen];
[IntervalLowerUnboundedUpperUnbounded] [IntervalLowerClosedUpperOpen];
[IntervalLowerUnboundedUpperUnbounded] [IntervalLowerOpenUpperClosed];
[IntervalLowerUnboundedUpperUnbounded] [IntervalLowerClosedUpperUnbounded];
[IntervalLowerUnboundedUpperUnbounded] [IntervalLowerOpenUpperUnbounded];
[IntervalLowerUnboundedUpperUnbounded] [IntervalLowerUnboundedUpperClosed];
[IntervalLowerUnboundedUpperUnbounded] [IntervalLowerUnboundedUpperOpen];
[IntervalLowerUnboundedUpperUnbounded] [IntervalLowerUnboundedUpperUnbounded];
)]
impl<RealType: RealScalar> IntervalHull<Other<RealType>> for T<RealType> {
type Output = Interval<RealType>;
fn hull(&self, other: &Other<RealType>) -> Self::Output {
compute_hull_general(self, other)
}
}
#[duplicate_item(
I;
[IntervalSingleton];
[IntervalFiniteLength];
[IntervalInfiniteLength];
)]
impl<RealType: RealScalar, Other: IntervalTrait<RealType = RealType>> IntervalHull<Other>
for I<RealType>
where
Other: IntervalTrait<RealType = RealType>,
{
type Output = Interval<RealType>;
fn hull(&self, other: &Other) -> Self::Output {
compute_hull_general(self, other)
}
}
#[derive(Debug, Error)]
pub enum ErrorsIntervalConstruction<RealType: RealScalar> {
#[error("The lower bound ({lower_bound}) must be < than the upper bound ({upper_bound}).")]
LowerBoundGreaterOrEqualThanUpperBound {
lower_bound: RealType,
upper_bound: RealType,
backtrace: Backtrace,
},
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(bound(deserialize = "RealType: for<'a> Deserialize<'a>"))]
pub enum Interval<RealType: RealScalar> {
FiniteLength(IntervalFiniteLength<RealType>),
InfiniteLength(IntervalInfiniteLength<RealType>),
}
impl<RealType: RealScalar> Interval<RealType> {
pub fn try_from_runtime_bounds(
lower_bound: Option<LowerBoundRuntime<RealType>>,
upper_bound: Option<UpperBoundRuntime<RealType>>,
) -> Result<Self, ErrorsIntervalConstruction<RealType>> {
match (lower_bound, upper_bound) {
(None, None) => Ok(Interval::InfiniteLength(
IntervalLowerUnboundedUpperUnbounded::new().into(),
)),
(Some(lower_bound), None) => {
Ok(IntervalInfiniteLength::new_upper_unbounded(lower_bound).into())
}
(None, Some(upper_bound)) => {
Ok(IntervalInfiniteLength::new_lower_unbounded(upper_bound).into())
}
(Some(lower_bound), Some(upper_bound)) => {
Ok(IntervalFiniteLength::try_from_runtime_bounds(lower_bound, upper_bound)?.into())
}
}
}
}
impl<RealType: RealScalar> IntervalOperations for Interval<RealType> {}
impl<RealType: RealScalar> IntervalBoundsRuntime for Interval<RealType> {
type RealType = RealType;
fn lower_bound_runtime(&self) -> Option<LowerBoundRuntime<RealType>> {
match self {
Interval::FiniteLength(interval) => interval.lower_bound_runtime(),
Interval::InfiniteLength(interval) => interval.lower_bound_runtime(),
}
}
fn upper_bound_runtime(&self) -> Option<UpperBoundRuntime<RealType>> {
match self {
Interval::FiniteLength(interval) => interval.upper_bound_runtime(),
Interval::InfiniteLength(interval) => interval.upper_bound_runtime(),
}
}
}
impl<RealType: RealScalar> Contains for Interval<RealType> {
#[inline(always)]
fn contains_point(&self, x: &RealType) -> bool {
match self {
Interval::FiniteLength(interval) => interval.contains_point(x),
Interval::InfiniteLength(interval) => interval.contains_point(x),
}
}
}
impl<RealType: RealScalar> IntervalTrait for Interval<RealType> {}
#[derive(Debug, Error)]
pub enum ErrorsIntervalConversion<RealType: RealScalar> {
#[error("the interval is not of a type that model a positive length interval.")]
NotIntervalPositiveLength {
interval: Interval<RealType>,
backtrace: Backtrace,
},
#[error("the interval is not of a type that model an infinite length interval.")]
NotIntervalInfiniteLength {
interval: Interval<RealType>,
backtrace: Backtrace,
},
#[error("the interval is not of a type that model an finite length interval.")]
NotIntervalFiniteLength {
interval: Interval<RealType>,
backtrace: Backtrace,
},
#[error("the interval is not closed.")]
NotIntervalClosed {
interval: Interval<RealType>,
backtrace: Backtrace,
},
#[error("the interval is not open.")]
NotIntervalOpen {
interval: Interval<RealType>,
backtrace: Backtrace,
},
#[error("the interval is not lower-opem and upper-closed.")]
NotIntervalLowerOpenUpperClosed {
interval: Interval<RealType>,
backtrace: Backtrace,
},
#[error("the interval is not lower-closed and upper-open.")]
NotIntervalLowerClosedUpperOpen {
interval: Interval<RealType>,
backtrace: Backtrace,
},
#[error("the interval is not lower-unbounded and upper-closed.")]
NotIntervalLowerUnboundedUpperClosed {
interval: Interval<RealType>,
backtrace: Backtrace,
},
#[error("the interval is not lower-unbounded and upper-open.")]
NotIntervalLowerUnboundedUpperOpen {
interval: Interval<RealType>,
backtrace: Backtrace,
},
#[error("the interval is not lower-closed and upper-unbounded.")]
NotIntervalLowerClosedUpperUnbounded {
interval: Interval<RealType>,
backtrace: Backtrace,
},
#[error("the interval is not lower-open and upper-unbounded.")]
NotIntervalLowerOpenUpperUnbounded {
interval: Interval<RealType>,
backtrace: Backtrace,
},
#[error("the interval is not a singleton.")]
NotIntervalSingleton {
interval: Interval<RealType>,
backtrace: Backtrace,
},
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{bounds::*, intervals::bounded::*};
use num::One;
use try_create::New;
mod into_interval_conversions {
use super::*;
#[test]
fn to_interval_closed() {
let closed = IntervalClosed::new(0.0, 1.0);
let general = closed.into_interval();
assert!(matches!(
general,
Interval::FiniteLength(IntervalFiniteLength::PositiveLength(
IntervalFinitePositiveLength::Closed(_)
))
));
}
#[test]
fn to_interval_open() {
let open = IntervalOpen::new(0.0, 1.0);
let general = open.into_interval();
assert!(matches!(
general,
Interval::FiniteLength(IntervalFiniteLength::PositiveLength(
IntervalFinitePositiveLength::Open(_)
))
));
}
#[test]
fn to_interval_lower_closed_upper_open() {
let half_open = IntervalLowerClosedUpperOpen::new(0.0, 1.0);
let general = half_open.into_interval();
assert!(matches!(
general,
Interval::FiniteLength(IntervalFiniteLength::PositiveLength(
IntervalFinitePositiveLength::LowerClosedUpperOpen(_)
))
));
}
#[test]
fn to_interval_lower_open_upper_closed() {
let half_open = IntervalLowerOpenUpperClosed::new(0.0, 1.0);
let general = half_open.into_interval();
assert!(matches!(
general,
Interval::FiniteLength(IntervalFiniteLength::PositiveLength(
IntervalFinitePositiveLength::LowerOpenUpperClosed(_)
))
));
}
#[test]
fn to_interval_singleton() {
let singleton = IntervalSingleton::new(5.0);
let general = singleton.into_interval();
assert!(matches!(
general,
Interval::FiniteLength(IntervalFiniteLength::ZeroLength(_))
));
}
#[test]
fn to_interval_lower_closed_upper_unbounded() {
let unbounded = IntervalLowerClosedUpperUnbounded::new(0.0);
let general = unbounded.into_interval();
assert!(matches!(
general,
Interval::InfiniteLength(IntervalInfiniteLength::LowerClosedUpperUnbounded(_))
));
}
#[test]
fn to_interval_lower_open_upper_unbounded() {
let unbounded = IntervalLowerOpenUpperUnbounded::new(0.0);
let general = unbounded.into_interval();
assert!(matches!(
general,
Interval::InfiniteLength(IntervalInfiniteLength::LowerOpenUpperUnbounded(_))
));
}
#[test]
fn to_interval_lower_unbounded_upper_closed() {
let unbounded = IntervalLowerUnboundedUpperClosed::new(1.0);
let general = unbounded.into_interval();
assert!(matches!(
general,
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperClosed(_))
));
}
#[test]
fn to_interval_lower_unbounded_upper_open() {
let unbounded = IntervalLowerUnboundedUpperOpen::new(1.0);
let general = unbounded.into_interval();
assert!(matches!(
general,
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperOpen(_))
));
}
#[test]
fn to_interval_fully_unbounded() {
let unbounded = IntervalLowerUnboundedUpperUnbounded::<f64>::new();
let general = unbounded.into_interval();
assert!(matches!(
general,
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperUnbounded(_))
));
}
#[test]
fn to_interval_enum_finite_positive_length() {
let closed = IntervalClosed::new(0.0, 1.0);
let enum_interval = IntervalFinitePositiveLength::Closed(closed);
let general = enum_interval.into_interval();
assert!(matches!(
general,
Interval::FiniteLength(IntervalFiniteLength::PositiveLength(_))
));
}
#[test]
fn to_interval_enum_finite_length() {
let singleton = IntervalSingleton::new(5.0);
let enum_interval = IntervalFiniteLength::ZeroLength(singleton);
let general = enum_interval.into_interval();
assert!(matches!(general, Interval::FiniteLength(_)));
}
#[test]
fn to_interval_enum_infinite_length() {
let unbounded = IntervalLowerClosedUpperUnbounded::new(0.0);
let enum_interval = IntervalInfiniteLength::LowerClosedUpperUnbounded(unbounded);
let general = enum_interval.into_interval();
assert!(matches!(general, Interval::InfiniteLength(_)));
}
#[test]
fn to_interval_preserves_values() {
let closed = IntervalClosed::new(2.5, 7.5);
let general = closed.into_interval();
if let Some(LowerBoundRuntime::Closed(bound)) = general.lower_bound_runtime() {
assert_eq!(bound.value, 2.5);
} else {
panic!("Expected closed lower bound");
}
if let Some(UpperBoundRuntime::Closed(bound)) = general.upper_bound_runtime() {
assert_eq!(bound.value, 7.5);
} else {
panic!("Expected closed upper bound");
}
}
#[test]
fn to_interval_preserves_boundary_semantics() {
let closed = IntervalClosed::new(0.0, 1.0);
let general_closed = closed.into_interval();
assert!(matches!(
general_closed.lower_bound_runtime(),
Some(LowerBoundRuntime::Closed(_))
));
assert!(matches!(
general_closed.upper_bound_runtime(),
Some(UpperBoundRuntime::Closed(_))
));
let open = IntervalOpen::new(0.0, 1.0);
let general_open = open.into_interval();
assert!(matches!(
general_open.lower_bound_runtime(),
Some(LowerBoundRuntime::Open(_))
));
assert!(matches!(
general_open.upper_bound_runtime(),
Some(UpperBoundRuntime::Open(_))
));
}
#[test]
fn to_interval_in_generic_function() {
fn convert_any_interval<I>(interval: I) -> Interval<f64>
where
I: IntervalTrait<RealType = f64>,
I: Into<Interval<f64>>,
{
interval.into_interval()
}
let closed = IntervalClosed::new(0.0, 1.0);
let result = convert_any_interval(closed);
assert!(matches!(result, Interval::FiniteLength(_)));
let unbounded = IntervalLowerClosedUpperUnbounded::new(0.0);
let result2 = convert_any_interval(unbounded);
assert!(matches!(result2, Interval::InfiniteLength(_)));
}
#[test]
fn generic_interval_bounded_into_interval() {
use crate::bounds::{Closed, Open};
let closed_bounded: IntervalBounded<f64, Closed, Closed> =
IntervalBounded::new(0.0, 1.0);
let interval1: Interval<f64> = closed_bounded.into();
assert!(matches!(
interval1,
Interval::FiniteLength(IntervalFiniteLength::PositiveLength(
IntervalFinitePositiveLength::Closed(_)
))
));
let open_bounded: IntervalBounded<f64, Open, Open> = IntervalBounded::new(0.0, 1.0);
let interval2: Interval<f64> = open_bounded.into();
assert!(matches!(
interval2,
Interval::FiniteLength(IntervalFiniteLength::PositiveLength(
IntervalFinitePositiveLength::Open(_)
))
));
let half_open_bounded: IntervalBounded<f64, Closed, Open> =
IntervalBounded::new(0.0, 1.0);
let interval3: Interval<f64> = half_open_bounded.into();
assert!(matches!(
interval3,
Interval::FiniteLength(IntervalFiniteLength::PositiveLength(
IntervalFinitePositiveLength::LowerClosedUpperOpen(_)
))
));
let other_half_open: IntervalBounded<f64, Open, Closed> =
IntervalBounded::new(0.0, 1.0);
let interval4: Interval<f64> = other_half_open.into();
assert!(matches!(
interval4,
Interval::FiniteLength(IntervalFiniteLength::PositiveLength(
IntervalFinitePositiveLength::LowerOpenUpperClosed(_)
))
));
}
#[test]
fn generic_function_with_interval_bounded() {
use crate::bounds::{Closed, Open};
fn convert_generic_bounded<L: BoundType, U: BoundType>(
interval: IntervalBounded<f64, L, U>,
) -> Interval<f64>
where
IntervalBounded<f64, L, U>: Into<Interval<f64>>,
{
interval.into()
}
let closed = IntervalBounded::<f64, Closed, Closed>::new(0.0, 1.0);
let result = convert_generic_bounded(closed);
assert!(matches!(result, Interval::FiniteLength(_)));
let open = IntervalBounded::<f64, Open, Open>::new(0.0, 1.0);
let result2 = convert_generic_bounded(open);
assert!(matches!(result2, Interval::FiniteLength(_)));
}
#[test]
fn generic_requires_explicit_bound() {
use crate::bounds::Closed;
fn convert_with_bound<L: BoundType, U: BoundType>(
interval: IntervalBounded<f64, L, U>,
) -> Interval<f64>
where
IntervalBounded<f64, L, U>: Into<Interval<f64>>,
{
interval.into()
}
let closed = IntervalBounded::<f64, Closed, Closed>::new(0.0, 1.0);
let _ = convert_with_bound(closed);
}
#[test]
fn interval_bounded_into_interval_method() {
use crate::bounds::{Closed, Open};
let bounded: IntervalBounded<f64, Closed, Open> = IntervalBounded::new(0.0, 1.0);
let interval = bounded.into_interval();
assert!(matches!(
interval,
Interval::FiniteLength(IntervalFiniteLength::PositiveLength(
IntervalFinitePositiveLength::LowerClosedUpperOpen(_)
))
));
}
}
mod lower_bound_value {
use super::*;
#[test]
fn lower_bound_value_interval_closed() {
let interval = IntervalClosed::new(1.0, 2.0);
assert_eq!(interval.lower_bound_value(), &1.0);
}
#[test]
fn lower_bound_value_interval_open() {
let interval = IntervalOpen::new(3.0, 4.0);
assert_eq!(interval.lower_bound_value(), &3.0);
}
#[test]
fn lower_bound_value_interval_lower_open_upper_closed() {
let interval = IntervalLowerOpenUpperClosed::new(5.0, 6.0);
assert_eq!(interval.lower_bound_value(), &5.0);
}
#[test]
fn lower_bound_value_interval_lower_closed_upper_open() {
let interval = IntervalLowerClosedUpperOpen::new(7.0, 8.0);
assert_eq!(interval.lower_bound_value(), &7.0);
}
#[test]
fn lower_bound_value_interval_finite_positive_length() {
let closed = IntervalClosed::new(1.0, 2.0);
let open = IntervalOpen::new(3.0, 4.0);
let left = IntervalLowerOpenUpperClosed::new(5.0, 6.0);
let right = IntervalLowerClosedUpperOpen::new(7.0, 8.0);
let c = IntervalFinitePositiveLength::Closed(closed);
let o = IntervalFinitePositiveLength::Open(open);
let l = IntervalFinitePositiveLength::LowerOpenUpperClosed(left);
let r = IntervalFinitePositiveLength::LowerClosedUpperOpen(right);
assert_eq!(c.lower_bound_value(), &1.0);
assert_eq!(o.lower_bound_value(), &3.0);
assert_eq!(l.lower_bound_value(), &5.0);
assert_eq!(r.lower_bound_value(), &7.0);
}
#[test]
fn lower_bound_value_subinterval_in_partition() {
let closed = IntervalLowerClosedUpperOpen::new(1.0, 2.0);
let left = IntervalClosed::new(2.0, 3.0);
let s1 = SubIntervalInPartition::<IntervalClosed<f64>>::First(closed);
let s2 = SubIntervalInPartition::<IntervalClosed<f64>>::Last(left);
assert_eq!(s1.lower_bound_value(), &1.0);
assert_eq!(s2.lower_bound_value(), &2.0);
}
#[test]
fn lower_bound_value_interval_lower_closed_upper_unbounded() {
let interval = IntervalLowerClosedUpperUnbounded::new(1.0);
assert_eq!(interval.lower_bound_value(), &1.0);
}
#[test]
fn lower_bound_value_interval_lower_open_upper_unbounded() {
let interval = IntervalLowerOpenUpperUnbounded::new(2.0);
assert_eq!(interval.lower_bound_value(), &2.0);
}
}
mod upper_bound_value {
use super::*;
#[test]
fn upper_bound_value_interval_closed() {
let interval = IntervalClosed::new(1.0, 2.0);
assert_eq!(interval.upper_bound_value(), &2.0);
}
#[test]
fn upper_bound_value_interval_open() {
let interval = IntervalOpen::new(3.0, 4.0);
assert_eq!(interval.upper_bound_value(), &4.0);
}
#[test]
fn upper_bound_value_interval_lower_open_upper_closed() {
let interval = IntervalLowerOpenUpperClosed::new(5.0, 6.0);
assert_eq!(interval.upper_bound_value(), &6.0);
}
#[test]
fn upper_bound_value_interval_lower_closed_upper_open() {
let interval = IntervalLowerClosedUpperOpen::new(7.0, 8.0);
assert_eq!(interval.upper_bound_value(), &8.0);
}
#[test]
fn upper_bound_value_interval_finite_positive_length() {
let closed = IntervalClosed::new(1.0, 2.0);
let open = IntervalOpen::new(3.0, 4.0);
let left = IntervalLowerOpenUpperClosed::new(5.0, 6.0);
let right = IntervalLowerClosedUpperOpen::new(7.0, 8.0);
let c = IntervalFinitePositiveLength::Closed(closed);
let o = IntervalFinitePositiveLength::Open(open);
let l = IntervalFinitePositiveLength::LowerOpenUpperClosed(left);
let r = IntervalFinitePositiveLength::LowerClosedUpperOpen(right);
assert_eq!(c.upper_bound_value(), &2.0);
assert_eq!(o.upper_bound_value(), &4.0);
assert_eq!(l.upper_bound_value(), &6.0);
assert_eq!(r.upper_bound_value(), &8.0);
}
#[test]
fn upper_bound_value_subinterval_in_partition() {
let first = IntervalLowerClosedUpperOpen::new(1.0, 2.0);
let last = IntervalClosed::new(2.0, 3.0);
let s1 = SubIntervalInPartition::<IntervalClosed<f64>>::First(first);
let s2 = SubIntervalInPartition::<IntervalClosed<f64>>::Last(last);
assert_eq!(s1.upper_bound_value(), &2.0);
assert_eq!(s2.upper_bound_value(), &3.0);
}
#[test]
fn upper_bound_value_interval_lower_unbounded_upper_closed() {
let interval = IntervalLowerUnboundedUpperClosed::new(1.0);
assert_eq!(interval.upper_bound_value(), &1.0);
}
#[test]
fn upper_bound_value_interval_lower_unbounded_upper_open() {
let interval = IntervalLowerUnboundedUpperOpen::new(2.0);
assert_eq!(interval.upper_bound_value(), &2.0);
}
}
mod into_bounds_pair {
use super::*;
#[test]
fn into_bounds_pair_interval_closed() {
let interval = IntervalClosed::new(1.0, 2.0);
let (a, b) = interval.clone().into_bounds_pair();
assert_eq!(a, 1.0);
assert_eq!(b, 2.0);
assert_eq!(interval.lower_bound_value(), &1.0);
assert_eq!(interval.upper_bound_value(), &2.0);
}
#[test]
fn into_bounds_pair_interval_open() {
let interval = IntervalOpen::new(3.0, 4.0);
let (a, b) = interval.clone().into_bounds_pair();
assert_eq!(a, 3.0);
assert_eq!(b, 4.0);
assert_eq!(interval.lower_bound_value(), &3.0);
assert_eq!(interval.upper_bound_value(), &4.0);
}
#[test]
fn into_bounds_pair_interval_lower_open_upper_closed() {
let interval = IntervalLowerOpenUpperClosed::new(5.0, 6.0);
let (a, b) = interval.clone().into_bounds_pair();
assert_eq!(a, 5.0);
assert_eq!(b, 6.0);
assert_eq!(interval.lower_bound_value(), &5.0);
assert_eq!(interval.upper_bound_value(), &6.0);
}
#[test]
fn into_bounds_pair_interval_lower_closed_upper_open() {
let interval = IntervalLowerClosedUpperOpen::new(7.0, 8.0);
let (a, b) = interval.clone().into_bounds_pair();
assert_eq!(a, 7.0);
assert_eq!(b, 8.0);
assert_eq!(interval.lower_bound_value(), &7.0);
assert_eq!(interval.upper_bound_value(), &8.0);
}
#[test]
fn into_bounds_pair_interval_finite_positive_length_01() {
let closed = IntervalClosed::new(1.0, 2.0);
let open = IntervalOpen::new(3.0, 4.0);
let left = IntervalLowerOpenUpperClosed::new(5.0, 6.0);
let right = IntervalLowerClosedUpperOpen::new(7.0, 8.0);
let c = IntervalFinitePositiveLength::Closed(closed);
let o = IntervalFinitePositiveLength::Open(open);
let l = IntervalFinitePositiveLength::LowerOpenUpperClosed(left);
let r = IntervalFinitePositiveLength::LowerClosedUpperOpen(right);
assert_eq!(c.clone().into_bounds_pair(), (1.0, 2.0));
assert_eq!(o.clone().into_bounds_pair(), (3.0, 4.0));
assert_eq!(l.clone().into_bounds_pair(), (5.0, 6.0));
assert_eq!(r.clone().into_bounds_pair(), (7.0, 8.0));
}
#[test]
fn into_bounds_pair_interval_finite_positive_length_02() {
let closed = IntervalClosed::new(1.0, 2.0);
let open = IntervalOpen::new(1.0, 2.0);
let left = IntervalLowerOpenUpperClosed::new(1.0, 2.0);
let right = IntervalLowerClosedUpperOpen::new(1.0, 2.0);
let c = IntervalFinitePositiveLength::Closed(closed);
let o = IntervalFinitePositiveLength::Open(open);
let l = IntervalFinitePositiveLength::LowerOpenUpperClosed(left);
let r = IntervalFinitePositiveLength::LowerClosedUpperOpen(right);
assert_eq!(c.into_bounds_pair(), (1.0, 2.0));
assert_eq!(o.into_bounds_pair(), (1.0, 2.0));
assert_eq!(l.into_bounds_pair(), (1.0, 2.0));
assert_eq!(r.into_bounds_pair(), (1.0, 2.0));
}
#[test]
fn into_bounds_pair_subinterval_in_partition() {
let first = IntervalLowerClosedUpperOpen::new(1.0, 2.0);
let last = IntervalClosed::new(2.0, 3.0);
let s1 = SubIntervalInPartition::<IntervalClosed<f64>>::First(first);
let s2 = SubIntervalInPartition::<IntervalClosed<f64>>::Last(last);
assert_eq!(s1.clone().into_bounds_pair(), (1.0, 2.0));
assert_eq!(s2.clone().into_bounds_pair(), (2.0, 3.0));
}
#[test]
fn into_inner_interval_singleton() {
let singleton = IntervalSingleton::new(42.0);
let value = singleton.clone().into_inner();
assert_eq!(value, 42.0);
assert_eq!(singleton.value(), &42.0);
}
}
mod length {
use super::*;
#[test]
fn length_interval_closed() {
let interval = IntervalClosed::new(1.0, 3.0);
assert_eq!(interval.length().into_inner(), 2.0);
}
#[test]
fn length_interval_open() {
let interval = IntervalOpen::new(2.0, 5.0);
assert_eq!(interval.length().into_inner(), 3.0);
}
#[test]
fn length_interval_lower_open_upper_closed() {
let interval = IntervalLowerOpenUpperClosed::new(0.0, 4.0);
assert_eq!(interval.length().into_inner(), 4.0);
}
#[test]
fn length_interval_lower_closed_upper_open() {
let interval = IntervalLowerClosedUpperOpen::new(-1.0, 1.0);
assert_eq!(interval.length().into_inner(), 2.0);
}
#[test]
fn length_interval_finite_positive_length() {
let closed = IntervalClosed::new(1.0, 2.0);
let open = IntervalOpen::new(3.0, 6.0);
let left = IntervalLowerOpenUpperClosed::new(5.0, 8.0);
let right = IntervalLowerClosedUpperOpen::new(7.0, 9.0);
let c = IntervalFinitePositiveLength::Closed(closed);
let o = IntervalFinitePositiveLength::Open(open);
let l = IntervalFinitePositiveLength::LowerOpenUpperClosed(left);
let r = IntervalFinitePositiveLength::LowerClosedUpperOpen(right);
assert_eq!(c.length().into_inner(), 1.0);
assert_eq!(o.length().into_inner(), 3.0);
assert_eq!(l.length().into_inner(), 3.0);
assert_eq!(r.length().into_inner(), 2.0);
}
#[test]
fn length_subinterval_in_partition() {
let first = IntervalLowerClosedUpperOpen::new(1.0, 2.5);
let last = IntervalClosed::new(2.5, 5.0);
let s1 = SubIntervalInPartition::<IntervalClosed<f64>>::First(first);
let s2 = SubIntervalInPartition::<IntervalClosed<f64>>::Last(last);
assert_eq!(s1.length().into_inner(), 1.5);
assert_eq!(s2.length().into_inner(), 2.5);
}
}
mod midpoint {
use super::*;
#[test]
fn midpoint_interval_closed() {
let interval = IntervalClosed::new(1.0, 3.0);
assert_eq!(interval.midpoint(), 2.0);
}
#[test]
fn midpoint_interval_open() {
let interval = IntervalOpen::new(2.0, 6.0);
assert_eq!(interval.midpoint(), 4.0);
}
#[test]
fn midpoint_interval_lower_open_upper_closed() {
let interval = IntervalLowerOpenUpperClosed::new(0.0, 4.0);
assert_eq!(interval.midpoint(), 2.0);
}
#[test]
fn midpoint_interval_lower_closed_upper_open() {
let interval = IntervalLowerClosedUpperOpen::new(-1.0, 1.0);
assert_eq!(interval.midpoint(), 0.0);
}
#[test]
fn midpoint_interval_finite_positive_length() {
let closed = IntervalClosed::new(1.0, 3.0);
let open = IntervalOpen::new(2.0, 6.0);
let left = IntervalLowerOpenUpperClosed::new(0.0, 4.0);
let right = IntervalLowerClosedUpperOpen::new(-1.0, 1.0);
let c = IntervalFinitePositiveLength::Closed(closed);
let o = IntervalFinitePositiveLength::Open(open);
let l = IntervalFinitePositiveLength::LowerOpenUpperClosed(left);
let r = IntervalFinitePositiveLength::LowerClosedUpperOpen(right);
assert_eq!(c.midpoint(), 2.0);
assert_eq!(o.midpoint(), 4.0);
assert_eq!(l.midpoint(), 2.0);
assert_eq!(r.midpoint(), 0.0);
}
#[test]
fn midpoint_subinterval_in_partition() {
let first = IntervalLowerClosedUpperOpen::new(1.0, 3.0);
let last = IntervalClosed::new(3.0, 7.0);
let s1 = SubIntervalInPartition::<IntervalClosed<f64>>::First(first);
let s2 = SubIntervalInPartition::<IntervalClosed<f64>>::Last(last);
assert_eq!(s1.midpoint(), 2.0);
assert_eq!(s2.midpoint(), 5.0);
}
}
mod contains_point_with_tolerance {
use super::*;
use num_valid::scalars::NonNegativeRealScalar;
use try_create::TryNew;
fn eps(v: f64) -> NonNegativeRealScalar<f64> {
NonNegativeRealScalar::try_new(v).unwrap()
}
#[test]
fn closed_interior_point() {
let interval = IntervalClosed::new(0.0, 1.0);
assert!(interval.contains_point_with_tolerance(&0.5, &eps(0.1)));
}
#[test]
fn closed_within_tolerance_below() {
let interval = IntervalClosed::new(0.0, 1.0);
assert!(interval.contains_point_with_tolerance(&-0.05, &eps(0.1)));
}
#[test]
fn closed_within_tolerance_above() {
let interval = IntervalClosed::new(0.0, 1.0);
assert!(interval.contains_point_with_tolerance(&1.05, &eps(0.1)));
}
#[test]
fn closed_outside_tolerance() {
let interval = IntervalClosed::new(0.0, 1.0);
assert!(!interval.contains_point_with_tolerance(&-0.2, &eps(0.1)));
assert!(!interval.contains_point_with_tolerance(&1.2, &eps(0.1)));
}
#[test]
fn open_boundary_with_zero_tolerance() {
let open = IntervalOpen::new(0.0, 1.0);
assert!(open.contains_point_with_tolerance(&0.0, &eps(0.0)));
assert!(open.contains_point_with_tolerance(&1.0, &eps(0.0)));
}
#[test]
fn open_interior_with_positive_tolerance() {
let open = IntervalOpen::new(0.0, 1.0);
assert!(open.contains_point_with_tolerance(&0.5, &eps(0.1)));
assert!(open.contains_point_with_tolerance(&-0.05, &eps(0.1)));
assert!(!open.contains_point_with_tolerance(&-0.2, &eps(0.1)));
}
#[test]
fn half_open_with_tolerance() {
let half = IntervalLowerClosedUpperOpen::new(0.0, 1.0);
assert!(half.contains_point_with_tolerance(&1.05, &eps(0.1)));
assert!(!half.contains_point_with_tolerance(&1.2, &eps(0.1)));
}
#[test]
fn singleton_with_tolerance() {
let singleton = IntervalSingleton::new(0.5);
assert!(singleton.contains_point_with_tolerance(&0.55, &eps(0.1)));
assert!(singleton.contains_point_with_tolerance(&0.45, &eps(0.1)));
assert!(!singleton.contains_point_with_tolerance(&0.65, &eps(0.1)));
}
#[test]
fn unbounded_below_with_tolerance() {
let ub = IntervalLowerUnboundedUpperClosed::new(1.0);
assert!(ub.contains_point_with_tolerance(&-1000.0, &eps(0.1)));
assert!(ub.contains_point_with_tolerance(&1.05, &eps(0.1)));
assert!(!ub.contains_point_with_tolerance(&1.2, &eps(0.1)));
}
#[test]
fn unbounded_above_with_tolerance() {
let ub = IntervalLowerClosedUpperUnbounded::new(0.0);
assert!(ub.contains_point_with_tolerance(&1000.0, &eps(0.1)));
assert!(ub.contains_point_with_tolerance(&-0.05, &eps(0.1)));
assert!(!ub.contains_point_with_tolerance(&-0.2, &eps(0.1)));
}
#[test]
fn fully_unbounded_always_true() {
let ub = IntervalLowerUnboundedUpperUnbounded::<f64>::new();
assert!(ub.contains_point_with_tolerance(&f64::MAX, &eps(0.0)));
assert!(ub.contains_point_with_tolerance(&f64::MIN, &eps(0.0)));
}
#[test]
fn finite_positive_length_enum() {
let closed = IntervalFinitePositiveLength::Closed(IntervalClosed::new(0.0, 2.0));
assert!(closed.contains_point_with_tolerance(&2.05, &eps(0.1)));
assert!(!closed.contains_point_with_tolerance(&2.2, &eps(0.1)));
}
#[test]
fn interval_enum_finite() {
let interval = Interval::FiniteLength(IntervalFiniteLength::PositiveLength(
IntervalFinitePositiveLength::Closed(IntervalClosed::new(0.0, 1.0)),
));
assert!(interval.contains_point_with_tolerance(&1.05, &eps(0.1)));
assert!(!interval.contains_point_with_tolerance(&1.2, &eps(0.1)));
}
#[test]
fn negative_bounds() {
let interval = IntervalClosed::new(-3.0, -1.0);
assert!(interval.contains_point_with_tolerance(&-2.0, &eps(0.1)));
assert!(interval.contains_point_with_tolerance(&-0.95, &eps(0.1)));
assert!(!interval.contains_point_with_tolerance(&-0.8, &eps(0.1)));
assert!(interval.contains_point_with_tolerance(&-3.05, &eps(0.1)));
assert!(!interval.contains_point_with_tolerance(&-3.2, &eps(0.1)));
}
}
mod partial_ord {
use super::*;
#[test]
fn partial_ord_lower_bound_closed() {
let a = LowerBoundClosed::new(1.0);
let b = LowerBoundClosed::new(2.0);
assert!(a < b);
assert!(b > a);
assert!(a <= b);
assert!(b >= a);
assert!(a == a);
assert!(b == b);
}
#[test]
fn partial_ord_lower_bound_open() {
let a = LowerBoundOpen::new(1.0);
let b = LowerBoundOpen::new(2.0);
assert!(a < b);
assert!(b > a);
assert!(a <= b);
assert!(b >= a);
assert!(a == a);
assert!(b == b);
}
#[test]
fn partial_ord_upper_bound_closed() {
let a = UpperBoundClosed::new(1.0);
let b = UpperBoundClosed::new(2.0);
assert!(a < b);
assert!(b > a);
assert!(a <= b);
assert!(b >= a);
assert!(a == a);
assert!(b == b);
}
#[test]
fn partial_ord_upper_bound_open() {
let a = UpperBoundOpen::new(1.0);
let b = UpperBoundOpen::new(2.0);
assert!(a < b);
assert!(b > a);
assert!(a <= b);
assert!(b >= a);
assert!(a == a);
assert!(b == b);
}
#[test]
fn partial_ord_lower_bound_cross_types() {
let closed = LowerBoundClosed::new(1.0);
let open = LowerBoundOpen::new(2.0);
assert!(closed < open);
assert!(open > closed);
assert!(closed <= open);
assert!(open >= closed);
assert!(!(closed == open));
}
#[test]
fn partial_ord_upper_bound_cross_types() {
let closed = UpperBoundClosed::new(1.0);
let open = UpperBoundOpen::new(2.0);
assert!(closed < open);
assert!(open > closed);
assert!(closed <= open);
assert!(open >= closed);
assert!(!(closed == open));
}
#[test]
fn partial_ord_lower_bound_open_closed_same_value() {
let closed = LowerBoundClosed::new(1.0);
let open = LowerBoundOpen::new(1.0);
assert!(closed < open);
assert!(open > closed);
assert!(closed <= open);
assert!(open >= closed);
assert!(!(closed == open));
}
#[test]
fn partial_ord_upper_bound_open_closed_same_value() {
let closed = UpperBoundClosed::new(1.0);
let open = UpperBoundOpen::new(1.0);
assert!(open < closed);
assert!(closed > open);
assert!(open <= closed);
assert!(closed >= open);
assert!(!(closed == open));
}
}
mod contains_on_same_interval_type {
use super::*;
#[test]
fn contains_interval_closed() {
let outer = IntervalClosed::new(0.0, 2.0);
let inner = IntervalClosed::new(0.5, 1.5);
assert!(outer.contains_interval(&inner));
assert!(!inner.contains_interval(&outer));
}
#[test]
fn contains_interval_open() {
let outer = IntervalOpen::new(0.0, 2.0);
let inner = IntervalOpen::new(0.5, 1.5);
assert!(outer.contains_interval(&inner));
assert!(!inner.contains_interval(&outer));
}
#[test]
fn contains_interval_lower_open_upper_closed() {
let outer = IntervalLowerOpenUpperClosed::new(0.0, 2.0);
let inner = IntervalLowerOpenUpperClosed::new(0.5, 1.5);
assert!(outer.contains_interval(&inner));
assert!(!inner.contains_interval(&outer));
}
#[test]
fn contains_interval_lower_closed_upper_open() {
let outer = IntervalLowerClosedUpperOpen::new(0.0, 2.0);
let inner = IntervalLowerClosedUpperOpen::new(0.5, 1.5);
assert!(outer.contains_interval(&inner));
assert!(!inner.contains_interval(&outer));
}
#[test]
fn contains_interval_singleton() {
let outer = IntervalClosed::new(1.0, 1.1);
let singleton = IntervalSingleton::new(1.0);
assert!(outer.contains_interval(&singleton));
assert!(singleton.contains_interval(&singleton));
let other = IntervalSingleton::new(2.0);
assert!(!singleton.contains_interval(&other));
}
#[test]
fn contains_interval_finite_positive_length() {
let outer = IntervalFinitePositiveLength::Closed(IntervalClosed::new(0.0, 2.0));
let inner = IntervalFinitePositiveLength::Closed(IntervalClosed::new(0.5, 1.5));
assert!(outer.contains_interval(&inner));
assert!(!inner.contains_interval(&outer));
}
#[test]
fn contains_interval_finite_length() {
let outer = IntervalFiniteLength::PositiveLength(IntervalFinitePositiveLength::Closed(
IntervalClosed::new(0.0, 2.0),
));
let inner = IntervalFiniteLength::PositiveLength(IntervalFinitePositiveLength::Closed(
IntervalClosed::new(0.5, 1.5),
));
assert!(outer.contains_interval(&inner));
assert!(!inner.contains_interval(&outer));
}
#[test]
fn contains_interval_infinite_length() {
let outer = IntervalInfiniteLength::LowerUnboundedUpperUnbounded(
IntervalLowerUnboundedUpperUnbounded::new(),
);
let inner = IntervalInfiniteLength::LowerClosedUpperUnbounded(
IntervalLowerClosedUpperUnbounded::new(0.0),
);
assert!(outer.contains_interval(&inner));
assert!(!inner.contains_interval(&outer));
}
#[test]
fn contains_interval_enum() {
let outer = Interval::FiniteLength(IntervalFiniteLength::PositiveLength(
IntervalFinitePositiveLength::Closed(IntervalClosed::new(0.0, 2.0)),
));
let inner = Interval::FiniteLength(IntervalFiniteLength::PositiveLength(
IntervalFinitePositiveLength::Closed(IntervalClosed::new(0.5, 1.5)),
));
assert!(outer.contains_interval(&inner));
assert!(!inner.contains_interval(&outer));
}
#[test]
fn contains_subinterval_in_partition() {
let outer = SubIntervalInPartition::<IntervalClosed<f64>>::First(
IntervalLowerClosedUpperOpen::new(0.0, 2.0),
);
let inner = SubIntervalInPartition::<IntervalClosed<f64>>::First(
IntervalLowerClosedUpperOpen::new(0.5, 1.5),
);
assert!(outer.contains_interval(&inner));
assert!(!inner.contains_interval(&outer));
let outer =
SubIntervalInPartition::<IntervalClosed<f64>>::Last(IntervalClosed::new(0.0, 2.0));
let inner =
SubIntervalInPartition::<IntervalClosed<f64>>::Last(IntervalClosed::new(0.5, 1.5));
assert!(outer.contains_interval(&inner));
assert!(!inner.contains_interval(&outer));
}
}
mod contains_on_intervals_combinations {
use super::*;
#[test]
fn contains_closed_open() {
let closed = IntervalClosed::new(0.0, 3.0);
let open = IntervalOpen::new(0.5, 2.5);
assert!(closed.contains_interval(&open));
assert!(!open.contains_interval(&closed));
}
#[test]
fn contains_closed_closed() {
let i1 = IntervalClosed::new(0.0, 2.0);
let i2 = IntervalClosed::new(0.5, 1.5);
assert!(i1.contains_interval(&i2));
assert!(!i2.contains_interval(&i1));
}
#[test]
fn contains_closed_left_half_open() {
let closed = IntervalClosed::new(0.0, 3.0);
let left = IntervalLowerOpenUpperClosed::new(0.5, 3.0);
assert!(closed.contains_interval(&left));
assert!(!left.contains_interval(&closed));
}
#[test]
fn contains_closed_right_half_open() {
let closed = IntervalClosed::new(0.0, 3.0);
let right = IntervalLowerClosedUpperOpen::new(0.0, 2.5);
assert!(closed.contains_interval(&right));
assert!(!right.contains_interval(&closed));
}
#[test]
fn contains_open_left_half_open() {
let open = IntervalOpen::new(0.0, 3.0);
let left = IntervalLowerOpenUpperClosed::new(0.5, 2.5);
assert!(open.contains_interval(&left));
assert!(!left.contains_interval(&open));
}
#[test]
fn contains_open_right_half_open() {
let open = IntervalOpen::new(0.0, 3.0);
let right = IntervalLowerClosedUpperOpen::new(0.5, 3.0);
assert!(open.contains_interval(&right));
assert!(!right.contains_interval(&open));
}
#[test]
fn contains_left_half_open_right_half_open() {
let left = IntervalLowerOpenUpperClosed::new(0.0, 3.0);
let right = IntervalLowerClosedUpperOpen::new(0.5, 3.0);
assert!(left.contains_interval(&right));
assert!(!right.contains_interval(&left));
}
#[test]
fn contains_closed_singleton() {
let closed = IntervalClosed::new(0.0, 2.0);
let singleton = IntervalSingleton::new(1.0);
assert!(closed.contains_interval(&singleton));
assert!(!singleton.contains_interval(&closed));
}
#[test]
fn contains_open_singleton() {
let open = IntervalOpen::new(0.0, 2.0);
let singleton = IntervalSingleton::new(1.0);
assert!(open.contains_interval(&singleton));
assert!(!singleton.contains_interval(&open));
let singleton_out = IntervalSingleton::new(0.0);
assert!(!open.contains_interval(&singleton_out));
}
#[test]
fn contains_finite_positive_length_finite_length() {
let closed = IntervalFinitePositiveLength::Closed(IntervalClosed::new(0.0, 2.0));
let finite = IntervalFiniteLength::PositiveLength(
IntervalFinitePositiveLength::Closed(IntervalClosed::new(0.5, 1.5)),
);
assert!(closed.contains_interval(&finite));
assert!(!finite.contains_interval(&closed));
}
#[test]
fn contains_finite_length_singleton() {
let finite = IntervalFiniteLength::PositiveLength(
IntervalFinitePositiveLength::Closed(IntervalClosed::new(0.0, 2.0)),
);
let singleton = IntervalFiniteLength::ZeroLength(IntervalSingleton::new(1.0));
assert!(finite.contains_interval(&singleton));
assert!(!singleton.contains_interval(&finite));
}
#[test]
fn contains_infinite_length_finite_length() {
let inf = IntervalInfiniteLength::LowerUnboundedUpperUnbounded(
IntervalLowerUnboundedUpperUnbounded::new(),
);
let finite = IntervalFiniteLength::PositiveLength(
IntervalFinitePositiveLength::Closed(IntervalClosed::new(-100.0, 100.0)),
);
assert!(inf.contains_interval(&finite));
assert!(!finite.contains_interval(&inf));
}
#[test]
fn contains_enum_variants() {
let closed = Interval::FiniteLength(IntervalFiniteLength::PositiveLength(
IntervalFinitePositiveLength::Closed(IntervalClosed::new(0.0, 2.0)),
));
let open = Interval::FiniteLength(IntervalFiniteLength::PositiveLength(
IntervalFinitePositiveLength::Open(IntervalOpen::new(0.5, 1.5)),
));
assert!(closed.contains_interval(&open));
assert!(!open.contains_interval(&closed));
let inf =
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperUnbounded(
IntervalLowerUnboundedUpperUnbounded::new(),
));
assert!(inf.contains_interval(&closed));
assert!(!closed.contains_interval(&inf));
}
#[test]
fn contains_subinterval_first_not_first() {
type S = SubIntervalInPartition<IntervalClosed<f64>>;
let first = S::First(IntervalLowerClosedUpperOpen::new(0.0, 2.0));
let not_first = S::Last(IntervalClosed::new(0.0, 2.0));
assert!(!first.contains_interval(¬_first));
assert!(not_first.contains_interval(&first));
}
#[test]
fn contains_subinterval_enum() {
type S = SubIntervalInPartition<IntervalClosed<f64>>;
let s1 = S::First(IntervalLowerClosedUpperOpen::new(0.0, 2.0));
let s2 = S::First(IntervalLowerClosedUpperOpen::new(0.5, 1.5));
assert!(s1.contains_interval(&s2));
assert!(!s2.contains_interval(&s1));
let s3 = S::Last(IntervalClosed::new(0.0, 2.0));
assert!(!s1.contains_interval(&s3));
assert!(s3.contains_interval(&s1));
}
}
mod contains_point {
use super::*;
#[test]
fn interval_closed_contains_point() {
let interval = IntervalClosed::new(1.0, 2.0);
assert!(interval.contains_point(&1.0));
assert!(interval.contains_point(&2.0));
assert!(interval.contains_point(&1.5));
assert!(!interval.contains_point(&0.9));
assert!(!interval.contains_point(&2.1));
}
#[test]
fn interval_open_contains_point() {
let interval = IntervalOpen::new(1.0, 2.0);
assert!(!interval.contains_point(&1.0));
assert!(!interval.contains_point(&2.0));
assert!(interval.contains_point(&1.5));
}
#[test]
fn interval_lower_open_upper_closed_contains_point() {
let interval = IntervalLowerOpenUpperClosed::new(1.0, 2.0);
assert!(!interval.contains_point(&1.0));
assert!(interval.contains_point(&2.0));
assert!(interval.contains_point(&1.5));
}
#[test]
fn interval_lower_closed_upper_open_contains_point() {
let interval = IntervalLowerClosedUpperOpen::new(1.0, 2.0);
assert!(interval.contains_point(&1.0));
assert!(!interval.contains_point(&2.0));
assert!(interval.contains_point(&1.5));
}
#[test]
fn interval_singleton_contains_point() {
let interval = IntervalSingleton::new(1.0);
assert!(interval.contains_point(&1.0));
assert!(!interval.contains_point(&0.0));
}
#[test]
fn interval_lower_closed_upper_unbounded_contains_point() {
let interval = IntervalLowerClosedUpperUnbounded::new(1.0);
assert!(interval.contains_point(&1.0));
assert!(interval.contains_point(&100.0));
assert!(!interval.contains_point(&0.9));
}
#[test]
fn interval_lower_open_upper_unbounded_contains_point() {
let interval = IntervalLowerOpenUpperUnbounded::new(1.0);
assert!(!interval.contains_point(&1.0));
assert!(interval.contains_point(&1.00001));
let interval = IntervalInfiniteLength::LowerOpenUpperUnbounded(interval);
assert!(!interval.contains_point(&1.0));
assert!(interval.contains_point(&1.00001));
}
#[test]
fn interval_lower_unbounded_upper_closed_contains_point() {
let interval = IntervalLowerUnboundedUpperClosed::new(2.0);
assert!(interval.contains_point(&2.0));
assert!(interval.contains_point(&-100.0));
assert!(!interval.contains_point(&2.1));
}
#[test]
fn interval_lower_unbounded_upper_open_contains_point() {
let interval = IntervalLowerUnboundedUpperOpen::new(2.0);
assert!(!interval.contains_point(&2.0));
assert!(interval.contains_point(&-100.0));
assert!(interval.contains_point(&1.99999));
let interval = IntervalInfiniteLength::LowerUnboundedUpperOpen(interval);
assert!(!interval.contains_point(&2.0));
assert!(interval.contains_point(&-100.0));
assert!(interval.contains_point(&1.99999));
}
#[test]
fn interval_finite_positive_length_trait() {
let interval = IntervalClosed::new(1.0, 2.0);
assert_eq!(interval.length().into_inner(), 1.0);
assert_eq!(interval.midpoint(), 1.5);
assert!(!interval.is_symmetric());
let interval = IntervalClosed::new(-1.0, 1.0);
assert!(interval.is_symmetric());
}
#[test]
fn subinterval_in_partition_contains_point() {
let first = IntervalLowerClosedUpperOpen::new(0.0, 1.0);
let last = IntervalClosed::new(1.0, 2.0);
let s1 = SubIntervalInPartition::<IntervalClosed<f64>>::First(first);
let s2 = SubIntervalInPartition::<IntervalClosed<f64>>::Last(last);
assert!(s1.contains_point(&0.0));
assert!(!s1.contains_point(&1.0));
assert!(!s1.contains_point(&-1.0));
assert!(s2.contains_point(&1.0));
assert!(s2.contains_point(&2.0));
}
#[test]
fn interval_finite_length_contains_point() {
let closed = IntervalClosed::new(1.0, 2.0);
let singleton = IntervalSingleton::new(1.5);
let finite =
IntervalFiniteLength::PositiveLength(IntervalFinitePositiveLength::Closed(closed));
let zero = IntervalFiniteLength::ZeroLength(singleton);
assert!(finite.contains_point(&1.5));
assert!(zero.contains_point(&1.5));
assert!(!zero.contains_point(&2.0));
}
#[test]
fn interval_enum_contains_point() {
let closed = IntervalClosed::new(1.0, 2.0);
let finite = Interval::FiniteLength(IntervalFiniteLength::PositiveLength(
IntervalFinitePositiveLength::Closed(closed),
));
let inf =
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperUnbounded(
IntervalLowerUnboundedUpperUnbounded::new(),
));
assert!(finite.contains_point(&1.5));
assert!(inf.contains_point(&1000.0));
}
}
mod tests_has_lower_bound {
use super::*;
use num_valid::RealNative64StrictFiniteInDebug;
use try_create::TryNew;
type Real = RealNative64StrictFiniteInDebug;
#[test]
fn test_is_lower_bound_closed_for_closed_intervals() {
let closed_interval =
IntervalClosed::new(Real::try_new(-2.0).unwrap(), Real::try_new(3.0).unwrap());
assert!(closed_interval.is_lower_bound_closed());
assert!(!closed_interval.is_lower_bound_open());
let zero_interval =
IntervalClosed::new(Real::try_new(0.0).unwrap(), Real::try_new(1.0).unwrap());
assert!(zero_interval.is_lower_bound_closed());
assert!(!zero_interval.is_lower_bound_open());
let negative_interval =
IntervalClosed::new(Real::try_new(-5.0).unwrap(), Real::try_new(-1.0).unwrap());
assert!(negative_interval.is_lower_bound_closed());
assert!(!negative_interval.is_lower_bound_open());
}
#[test]
fn test_is_lower_bound_closed_for_open_intervals() {
let open_interval =
IntervalOpen::new(Real::try_new(-1.0).unwrap(), Real::try_new(1.0).unwrap());
assert!(!open_interval.is_lower_bound_closed());
assert!(open_interval.is_lower_bound_open());
let zero_interval =
IntervalOpen::new(Real::try_new(0.0).unwrap(), Real::try_new(2.0).unwrap());
assert!(!zero_interval.is_lower_bound_closed());
assert!(zero_interval.is_lower_bound_open());
let positive_interval =
IntervalOpen::new(Real::try_new(1.0).unwrap(), Real::try_new(5.0).unwrap());
assert!(!positive_interval.is_lower_bound_closed());
assert!(positive_interval.is_lower_bound_open());
}
#[test]
fn test_is_lower_bound_closed_for_half_open_intervals() {
let left_closed = IntervalLowerClosedUpperOpen::new(
Real::try_new(2.0).unwrap(),
Real::try_new(7.0).unwrap(),
);
assert!(left_closed.is_lower_bound_closed());
assert!(!left_closed.is_lower_bound_open());
let left_open = IntervalLowerOpenUpperClosed::new(
Real::try_new(1.0).unwrap(),
Real::try_new(4.0).unwrap(),
);
assert!(!left_open.is_lower_bound_closed());
assert!(left_open.is_lower_bound_open());
}
#[test]
fn test_is_lower_bound_closed_for_unbounded_intervals() {
let lower_closed_unbounded =
IntervalLowerClosedUpperUnbounded::new(Real::try_new(0.0).unwrap());
assert!(lower_closed_unbounded.is_lower_bound_closed());
assert!(!lower_closed_unbounded.is_lower_bound_open());
let lower_open_unbounded =
IntervalLowerOpenUpperUnbounded::new(Real::try_new(5.0).unwrap());
assert!(!lower_open_unbounded.is_lower_bound_closed());
assert!(lower_open_unbounded.is_lower_bound_open());
let negative_unbounded =
IntervalLowerClosedUpperUnbounded::new(Real::try_new(-10.0).unwrap());
assert!(negative_unbounded.is_lower_bound_closed());
assert!(!negative_unbounded.is_lower_bound_open());
}
#[test]
fn test_is_lower_bound_open_complement_property() {
let test_intervals: Vec<Box<dyn GetLowerBoundValue<LowerBoundValue = Real>>> = vec![
Box::new(IntervalClosed::new(
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap(),
)),
Box::new(IntervalOpen::new(
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap(),
)),
Box::new(IntervalLowerClosedUpperOpen::new(
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap(),
)),
Box::new(IntervalLowerOpenUpperClosed::new(
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap(),
)),
Box::new(IntervalLowerClosedUpperUnbounded::new(
Real::try_new(0.0).unwrap(),
)),
Box::new(IntervalLowerOpenUpperUnbounded::new(
Real::try_new(0.0).unwrap(),
)),
];
for interval in test_intervals {
let is_closed = interval.is_lower_bound_closed();
let is_open = interval.is_lower_bound_open();
assert_eq!(
is_open, !is_closed,
"is_lower_bound_open() should be the complement of is_lower_bound_closed() for interval: {:?}",
interval
);
assert!(
is_closed ^ is_open,
"Exactly one of is_lower_bound_closed() or is_lower_bound_open() should be true for interval: {:?}",
interval
);
}
}
#[test]
fn test_boundary_consistency_with_point_containment() {
let closed_interval =
IntervalClosed::new(Real::try_new(1.0).unwrap(), Real::try_new(3.0).unwrap());
assert!(closed_interval.is_lower_bound_closed());
assert!(closed_interval.contains_point(closed_interval.lower_bound_value()));
let open_interval =
IntervalOpen::new(Real::try_new(1.0).unwrap(), Real::try_new(3.0).unwrap());
assert!(open_interval.is_lower_bound_open());
assert!(!open_interval.contains_point(open_interval.lower_bound_value()));
let left_closed = IntervalLowerClosedUpperOpen::new(
Real::try_new(2.0).unwrap(),
Real::try_new(5.0).unwrap(),
);
assert!(left_closed.is_lower_bound_closed());
assert!(left_closed.contains_point(left_closed.lower_bound_value()));
let left_open = IntervalLowerOpenUpperClosed::new(
Real::try_new(2.0).unwrap(),
Real::try_new(5.0).unwrap(),
);
assert!(left_open.is_lower_bound_open());
assert!(!left_open.contains_point(left_open.lower_bound_value()));
}
#[test]
fn test_with_different_scalar_types() {
let f64_closed = IntervalClosed::new(0.0_f64, 1.0_f64);
assert!(f64_closed.is_lower_bound_closed());
assert!(!f64_closed.is_lower_bound_open());
let f64_open = IntervalOpen::new(0.0_f64, 1.0_f64);
assert!(!f64_open.is_lower_bound_closed());
assert!(f64_open.is_lower_bound_open());
use num_valid::RealNative64StrictFinite;
type SafeReal = RealNative64StrictFinite;
let safe_closed = IntervalClosed::new(
SafeReal::try_new(0.0).unwrap(),
SafeReal::try_new(1.0).unwrap(),
);
assert!(safe_closed.is_lower_bound_closed());
assert!(!safe_closed.is_lower_bound_open());
let safe_open = IntervalOpen::new(
SafeReal::try_new(0.0).unwrap(),
SafeReal::try_new(1.0).unwrap(),
);
assert!(!safe_open.is_lower_bound_closed());
assert!(safe_open.is_lower_bound_open());
}
#[test]
fn test_boundary_behavior_at_limits() {
let tiny_closed = IntervalClosed::new(
Real::try_new(1.0).unwrap(),
Real::try_new(1.0 + f64::EPSILON).unwrap(),
);
assert!(tiny_closed.is_lower_bound_closed());
assert!(!tiny_closed.is_lower_bound_open());
let tiny_open = IntervalOpen::new(
Real::try_new(1.0).unwrap(),
Real::try_new(1.0 + f64::EPSILON).unwrap(),
);
assert!(!tiny_open.is_lower_bound_closed());
assert!(tiny_open.is_lower_bound_open());
let extreme_closed =
IntervalLowerClosedUpperUnbounded::new(Real::try_new(f64::MIN).unwrap());
assert!(extreme_closed.is_lower_bound_closed());
assert!(!extreme_closed.is_lower_bound_open());
let extreme_open =
IntervalLowerOpenUpperUnbounded::new(Real::try_new(f64::MAX / 2.0).unwrap());
assert!(!extreme_open.is_lower_bound_closed());
assert!(extreme_open.is_lower_bound_open());
}
#[test]
fn test_generic_programming_pattern() {
fn analyze_lower_boundary<I, T>(interval: &I) -> (bool, bool)
where
I: GetLowerBoundValue<LowerBoundValue = T>,
T: Clone,
{
(
interval.is_lower_bound_closed(),
interval.is_lower_bound_open(),
)
}
let closed =
IntervalClosed::new(Real::try_new(0.0).unwrap(), Real::try_new(1.0).unwrap());
let open = IntervalOpen::new(Real::try_new(0.0).unwrap(), Real::try_new(1.0).unwrap());
let left_closed = IntervalLowerClosedUpperOpen::new(
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap(),
);
let left_open = IntervalLowerOpenUpperClosed::new(
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap(),
);
assert_eq!(analyze_lower_boundary(&closed), (true, false));
assert_eq!(analyze_lower_boundary(&open), (false, true));
assert_eq!(analyze_lower_boundary(&left_closed), (true, false));
assert_eq!(analyze_lower_boundary(&left_open), (false, true));
}
#[test]
fn test_finite_positive_length_intervals() {
let closed = IntervalFinitePositiveLength::Closed(IntervalClosed::new(
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap(),
));
assert!(closed.is_lower_bound_closed());
assert!(!closed.is_lower_bound_open());
let open = IntervalFinitePositiveLength::Open(IntervalOpen::new(
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap(),
));
assert!(!open.is_lower_bound_closed());
assert!(open.is_lower_bound_open());
let left_open_upper_closed = IntervalFinitePositiveLength::LowerOpenUpperClosed(
IntervalLowerOpenUpperClosed::new(
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap(),
),
);
assert!(!left_open_upper_closed.is_lower_bound_closed());
assert!(left_open_upper_closed.is_lower_bound_open());
let left_closed_upper_open = IntervalFinitePositiveLength::LowerClosedUpperOpen(
IntervalLowerClosedUpperOpen::new(
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap(),
),
);
assert!(left_closed_upper_open.is_lower_bound_closed());
assert!(!left_closed_upper_open.is_lower_bound_open());
}
#[test]
fn test_edge_case_zero_bounds() {
let zero_closed =
IntervalClosed::new(Real::try_new(0.0).unwrap(), Real::try_new(1.0).unwrap());
assert!(zero_closed.is_lower_bound_closed());
assert!(!zero_closed.is_lower_bound_open());
assert!(zero_closed.contains_point(&Real::try_new(0.0).unwrap()));
let zero_open =
IntervalOpen::new(Real::try_new(0.0).unwrap(), Real::try_new(1.0).unwrap());
assert!(!zero_open.is_lower_bound_closed());
assert!(zero_open.is_lower_bound_open());
assert!(!zero_open.contains_point(&Real::try_new(0.0).unwrap()));
}
#[test]
fn test_documentation_examples() {
let closed =
IntervalClosed::new(Real::try_new(0.0).unwrap(), Real::try_new(1.0).unwrap());
assert!(closed.is_lower_bound_closed()); assert!(!closed.is_lower_bound_open());
let open = IntervalOpen::new(Real::try_new(0.0).unwrap(), Real::try_new(1.0).unwrap());
assert!(!open.is_lower_bound_closed()); assert!(open.is_lower_bound_open());
let half_open_left_closed = IntervalLowerClosedUpperOpen::new(
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap(),
);
assert!(half_open_left_closed.is_lower_bound_closed()); assert!(!half_open_left_closed.is_lower_bound_open());
let half_open_left_open = IntervalLowerOpenUpperClosed::new(
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap(),
);
assert!(!half_open_left_open.is_lower_bound_closed()); assert!(half_open_left_open.is_lower_bound_open()); }
}
#[test]
fn test_interval_conversion_errors() {
let singleton = IntervalSingleton::new(1.0);
let finite = IntervalFiniteLength::ZeroLength(singleton);
let interval = Interval::FiniteLength(finite);
let result = IntervalFinitePositiveLength::try_from(interval.clone());
assert!(matches!(
result,
Err(ErrorsIntervalConversion::NotIntervalPositiveLength {
interval: Interval::FiniteLength(IntervalFiniteLength::ZeroLength(..)),
..
})
));
let result = IntervalClosed::try_from(interval.clone());
assert!(matches!(
result,
Err(ErrorsIntervalConversion::NotIntervalPositiveLength {
interval: Interval::FiniteLength(IntervalFiniteLength::ZeroLength(..)),
..
})
));
let inf =
Interval::<f64>::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperUnbounded(
IntervalLowerUnboundedUpperUnbounded::new(),
));
let result = IntervalFinitePositiveLength::try_from(inf.clone());
assert!(matches!(
result,
Err(ErrorsIntervalConversion::NotIntervalPositiveLength {
interval: Interval::InfiniteLength(
IntervalInfiniteLength::LowerUnboundedUpperUnbounded(_)
),
..
})
));
let result = IntervalClosed::try_from(inf.clone());
assert!(matches!(
result,
Err(ErrorsIntervalConversion::NotIntervalPositiveLength {
interval: Interval::InfiniteLength(
IntervalInfiniteLength::LowerUnboundedUpperUnbounded(_)
),
..
})
));
}
mod constructors {
use super::*;
#[test]
#[should_panic(expected = "Invalid interval bounds for the closed interval!")]
#[cfg(debug_assertions)]
fn interval_closed_new_panics_on_invalid_bounds() {
let _ = IntervalClosed::new(2.0, 1.0);
}
#[test]
fn open() {
let lower_bound = 0.0;
let upper_bound = 1.0;
let interval = IntervalOpen::new(lower_bound, upper_bound);
assert_eq!(interval.lower_bound_value(), &0.);
assert_eq!(interval.upper_bound_value(), &1.);
assert_eq!(interval.length().into_inner(), 1.);
assert_eq!(interval.midpoint(), 0.5);
assert!(interval.contains_point(&0.5));
assert_eq!(
interval.clone().interior(),
IntervalOpen::new(lower_bound, upper_bound)
);
assert_eq!(
interval.clone().closure(),
IntervalClosed::new(lower_bound, upper_bound)
);
let (lb, ub) = interval.into_bounds_pair();
assert_eq!(lb, lower_bound);
assert_eq!(ub, upper_bound);
}
#[test]
fn closed_01() {
let lower_bound = 0.0;
let upper_bound = 1.0;
let interval = IntervalClosed::new(lower_bound, upper_bound);
assert_eq!(interval.lower_bound_value(), &0.);
assert_eq!(interval.upper_bound_value(), &1.);
assert_eq!(interval.length().into_inner(), 1.);
assert_eq!(interval.midpoint(), 0.5);
let x = 0.5;
assert!(interval.contains_point(&x));
assert_eq!(
interval.clone().interior(),
IntervalOpen::new(lower_bound, upper_bound)
);
assert_eq!(
interval.clone().closure(),
IntervalClosed::new(lower_bound, upper_bound)
);
let (lb, ub) = interval.into_bounds_pair();
assert_eq!(lb, lower_bound);
assert_eq!(ub, upper_bound);
}
#[test]
#[should_panic]
#[cfg(debug_assertions)]
fn closed_02() {
let lower_bound = 1.0;
let upper_bound = 0.0;
let _interval = IntervalClosed::new(lower_bound, upper_bound);
}
#[test]
pub fn left_half_open() {
let lower_bound = 0.0;
let upper_bound = 1.0;
let interval = IntervalLowerOpenUpperClosed::new(lower_bound, upper_bound);
assert_eq!(interval.lower_bound_value(), &0.);
assert_eq!(interval.upper_bound_value(), &1.);
assert_eq!(interval.length().into_inner(), 1.);
assert_eq!(interval.midpoint(), 0.5);
let x = 0.5;
assert!(interval.contains_point(&x));
assert_eq!(
interval.clone().interior(),
IntervalOpen::new(lower_bound, upper_bound)
);
assert_eq!(
interval.clone().closure(),
IntervalClosed::new(lower_bound, upper_bound)
);
let (lb, ub) = interval.into_bounds_pair();
assert_eq!(lb, lower_bound);
assert_eq!(ub, upper_bound);
}
#[test]
pub fn right_half_open() {
let lower_bound = 0.0;
let upper_bound = 1.0;
let interval = IntervalLowerClosedUpperOpen::new(lower_bound, upper_bound);
assert_eq!(interval.lower_bound_value(), &0.);
assert_eq!(interval.upper_bound_value(), &1.);
assert_eq!(interval.length().into_inner(), 1.);
assert_eq!(interval.midpoint(), 0.5);
let x = 0.5;
assert!(interval.contains_point(&x));
assert_eq!(
interval.clone().interior(),
IntervalOpen::new(lower_bound, upper_bound)
);
assert_eq!(
interval.clone().closure(),
IntervalClosed::new(lower_bound, upper_bound)
);
let (lb, ub) = interval.into_bounds_pair();
assert_eq!(lb, lower_bound);
assert_eq!(ub, upper_bound);
}
#[test]
fn unbounded_open_left() {
let lower_bound = 0.0;
let interval = IntervalLowerOpenUpperUnbounded::new(lower_bound);
assert_eq!(interval.lower_bound_value(), &0.);
let x = 0.5;
assert!(interval.contains_point(&x));
}
#[test]
fn unbounded_open_right() {
let upper_bound = 0.0;
let interval = IntervalLowerUnboundedUpperOpen::new(upper_bound);
assert_eq!(interval.upper_bound_value(), &0.);
let x = -0.5;
assert!(interval.contains_point(&x));
}
#[test]
fn unbounded_closed_left() {
let lower_bound = 0.;
let interval = IntervalLowerClosedUpperUnbounded::new(lower_bound);
assert_eq!(interval.lower_bound_value(), &0.);
let x = 0.5;
assert!(
interval.contains_point(&x),
"The interval {interval:?} does not contain the point {x}"
);
}
#[test]
fn unbounded_closed_right() {
let upper_bound = 0.;
let interval = IntervalLowerUnboundedUpperClosed::new(upper_bound);
assert_eq!(interval.upper_bound_value(), &0.);
let x = -0.5;
assert!(interval.contains_point(&x));
}
#[test]
fn singleton() {
let value = 0.;
let interval = IntervalSingleton::new(value);
assert_eq!(interval.value(), &0.);
let x = 0.;
assert!(interval.contains_point(&x));
}
#[test]
#[cfg(debug_assertions)]
#[should_panic]
fn interval_singleton_try_new_invalid() {
let nan = f64::NAN;
let _ = IntervalSingleton::new(nan);
}
#[test]
fn interval_closed_try_new_invalid() {
let res = IntervalClosed::try_new(2.0, 1.0);
assert!(res.is_err());
}
#[test]
fn interval_open_try_new_invalid() {
let res = IntervalOpen::try_new(2.0, 1.0);
assert!(res.is_err());
}
#[test]
fn interval_lower_open_upper_closed_try_new_invalid() {
let res = IntervalLowerOpenUpperClosed::try_new(2.0, 1.0);
assert!(res.is_err());
}
#[test]
fn interval_lower_closed_upper_open_try_new_invalid() {
let res = IntervalLowerClosedUpperOpen::try_new(2.0, 1.0);
assert!(res.is_err());
}
#[test]
#[cfg(debug_assertions)]
#[should_panic]
fn interval_lower_closed_upper_unbounded_try_new_invalid() {
let nan = f64::NAN;
let _ = IntervalLowerClosedUpperUnbounded::new(nan);
}
#[test]
#[cfg(debug_assertions)]
#[should_panic]
fn interval_lower_open_upper_unbounded_try_new_invalid() {
let nan = f64::NAN;
let _ = IntervalLowerOpenUpperUnbounded::new(nan);
}
#[test]
#[cfg(debug_assertions)]
#[should_panic]
fn interval_lower_unbounded_upper_closed_try_new_invalid() {
let nan = f64::NAN;
let _ = IntervalLowerUnboundedUpperClosed::new(nan);
}
#[test]
#[cfg(debug_assertions)]
#[should_panic]
fn interval_lower_unbounded_upper_open_try_new_invalid() {
let nan = f64::NAN;
let _ = IntervalLowerUnboundedUpperOpen::new(nan);
}
#[test]
fn from_bounds_closed_valid() {
use crate::bounds::{LowerBoundClosed, UpperBoundClosed};
let lower = LowerBoundClosed::new(0.0);
let upper = UpperBoundClosed::new(5.0);
let interval = IntervalClosed::from_static_bounds(lower, upper);
assert_eq!(interval.lower_bound_value(), &0.0);
assert_eq!(interval.upper_bound_value(), &5.0);
assert!(interval.contains_point(&0.0));
assert!(interval.contains_point(&5.0));
assert!(interval.contains_point(&2.5));
}
#[test]
fn from_bounds_open_valid() {
use crate::bounds::{LowerBoundOpen, UpperBoundOpen};
let lower = LowerBoundOpen::new(0.0);
let upper = UpperBoundOpen::new(5.0);
let interval = IntervalOpen::from_static_bounds(lower, upper);
assert_eq!(interval.lower_bound_value(), &0.0);
assert_eq!(interval.upper_bound_value(), &5.0);
assert!(!interval.contains_point(&0.0));
assert!(!interval.contains_point(&5.0));
assert!(interval.contains_point(&2.5));
}
#[test]
fn from_bounds_half_open_valid() {
use crate::bounds::{LowerBoundClosed, UpperBoundOpen};
let lower = LowerBoundClosed::new(1.0);
let upper = UpperBoundOpen::new(10.0);
let interval = IntervalLowerClosedUpperOpen::from_static_bounds(lower, upper);
assert_eq!(interval.lower_bound_value(), &1.0);
assert_eq!(interval.upper_bound_value(), &10.0);
assert!(interval.contains_point(&1.0));
assert!(!interval.contains_point(&10.0));
assert!(interval.contains_point(&5.0));
}
#[test]
fn from_bounds_lower_open_upper_closed_valid() {
use crate::bounds::{LowerBoundOpen, UpperBoundClosed};
let lower = LowerBoundOpen::new(-5.0);
let upper = UpperBoundClosed::new(5.0);
let interval = IntervalLowerOpenUpperClosed::from_static_bounds(lower, upper);
assert_eq!(interval.lower_bound_value(), &-5.0);
assert_eq!(interval.upper_bound_value(), &5.0);
assert!(!interval.contains_point(&-5.0));
assert!(interval.contains_point(&5.0));
assert!(interval.contains_point(&0.0));
}
#[test]
fn try_from_bounds_closed_valid() {
use crate::bounds::{LowerBoundClosed, UpperBoundClosed};
let lower = LowerBoundClosed::new(0.0);
let upper = UpperBoundClosed::new(10.0);
let result = IntervalClosed::try_from_static_bounds(lower, upper);
assert!(result.is_ok());
let interval = result.unwrap();
assert_eq!(interval.lower_bound_value(), &0.0);
assert_eq!(interval.upper_bound_value(), &10.0);
}
#[test]
fn try_from_bounds_closed_invalid_lower_greater() {
use crate::bounds::{LowerBoundClosed, UpperBoundClosed};
let lower = LowerBoundClosed::new(10.0);
let upper = UpperBoundClosed::new(5.0);
let result = IntervalClosed::try_from_static_bounds(lower, upper);
assert!(result.is_err());
match result {
Err(ErrorsIntervalConstruction::LowerBoundGreaterOrEqualThanUpperBound {
lower_bound,
upper_bound,
..
}) => {
assert_eq!(lower_bound, 10.0);
assert_eq!(upper_bound, 5.0);
}
_ => panic!("Expected LowerBoundGreaterOrEqualThanUpperBound error"),
}
}
#[test]
fn try_from_bounds_open_invalid_equal_bounds() {
use crate::bounds::{LowerBoundOpen, UpperBoundOpen};
let lower = LowerBoundOpen::new(5.0);
let upper = UpperBoundOpen::new(5.0);
let result = IntervalOpen::try_from_static_bounds(lower, upper);
assert!(result.is_err());
match result {
Err(ErrorsIntervalConstruction::LowerBoundGreaterOrEqualThanUpperBound {
lower_bound,
upper_bound,
..
}) => {
assert_eq!(lower_bound, 5.0);
assert_eq!(upper_bound, 5.0);
}
_ => panic!("Expected LowerBoundGreaterOrEqualThanUpperBound error"),
}
}
#[test]
fn from_bounds_mixed_types() {
use crate::bounds::{
LowerBoundClosed, LowerBoundOpen, UpperBoundClosed, UpperBoundOpen,
};
let interval1 = IntervalLowerClosedUpperOpen::from_static_bounds(
LowerBoundClosed::new(0.0),
UpperBoundOpen::new(10.0),
);
assert!(interval1.contains_point(&0.0));
assert!(!interval1.contains_point(&10.0));
let interval2 = IntervalLowerOpenUpperClosed::from_static_bounds(
LowerBoundOpen::new(0.0),
UpperBoundClosed::new(10.0),
);
assert!(!interval2.contains_point(&0.0));
assert!(interval2.contains_point(&10.0));
}
#[test]
#[cfg(debug_assertions)]
#[should_panic(expected = "Invalid interval bounds")]
fn from_bounds_closed_panics_on_invalid() {
use crate::bounds::{LowerBoundClosed, UpperBoundClosed};
let lower = LowerBoundClosed::new(10.0);
let upper = UpperBoundClosed::new(5.0);
let _ = IntervalClosed::from_static_bounds(lower, upper);
}
#[test]
fn from_bounds_very_small_interval() {
use crate::bounds::{LowerBoundClosed, UpperBoundClosed};
let lower = LowerBoundClosed::new(0.0);
let upper = UpperBoundClosed::new(1e-10);
let interval = IntervalClosed::from_static_bounds(lower, upper);
assert_eq!(interval.lower_bound_value(), &0.0);
assert_eq!(interval.upper_bound_value(), &1e-10);
assert!(interval.contains_point(&5e-11));
}
#[test]
fn from_bounds_negative_bounds() {
use crate::bounds::{LowerBoundOpen, UpperBoundOpen};
let lower = LowerBoundOpen::new(-100.0);
let upper = UpperBoundOpen::new(-10.0);
let interval = IntervalOpen::from_static_bounds(lower, upper);
assert_eq!(interval.lower_bound_value(), &-100.0);
assert_eq!(interval.upper_bound_value(), &-10.0);
assert!(interval.contains_point(&-50.0));
assert!(!interval.contains_point(&-100.0));
assert!(!interval.contains_point(&-10.0));
}
#[test]
fn try_from_bounds_all_types() {
use crate::bounds::{
LowerBoundClosed, LowerBoundOpen, UpperBoundClosed, UpperBoundOpen,
};
let closed = IntervalClosed::try_from_static_bounds(
LowerBoundClosed::new(0.0),
UpperBoundClosed::new(1.0),
);
assert!(closed.is_ok());
let open = IntervalOpen::try_from_static_bounds(
LowerBoundOpen::new(0.0),
UpperBoundOpen::new(1.0),
);
assert!(open.is_ok());
let half_open1 = IntervalLowerClosedUpperOpen::try_from_static_bounds(
LowerBoundClosed::new(0.0),
UpperBoundOpen::new(1.0),
);
assert!(half_open1.is_ok());
let half_open2 = IntervalLowerOpenUpperClosed::try_from_static_bounds(
LowerBoundOpen::new(0.0),
UpperBoundClosed::new(1.0),
);
assert!(half_open2.is_ok());
}
}
mod point_containment {
use super::*;
#[test]
fn contains_point_lower_closed_upper_open_at_lower_bound() {
let interval = IntervalLowerClosedUpperOpen::new(0.0, 10.0);
assert!(
interval.contains_point(&0.0),
"Lower bound 0.0 should be included in [0, 10)"
);
}
#[test]
fn contains_point_lower_closed_upper_open_at_upper_bound() {
let interval = IntervalLowerClosedUpperOpen::new(0.0, 10.0);
assert!(
!interval.contains_point(&10.0),
"Upper bound 10.0 should be excluded from [0, 10)"
);
let interval = IntervalFinitePositiveLength::LowerClosedUpperOpen(interval);
assert!(
!interval.contains_point(&10.0),
"Upper bound 10.0 should be excluded from [0, 10)"
);
}
#[test]
fn contains_point_lower_closed_upper_open_interior() {
let interval = IntervalLowerClosedUpperOpen::new(0.0, 10.0);
assert!(
interval.contains_point(&5.0),
"Interior point 5.0 should be included in [0, 10)"
);
assert!(
interval.contains_point(&0.1),
"Point 0.1 just above lower bound should be included"
);
assert!(
interval.contains_point(&9.9),
"Point 9.9 just below upper bound should be included"
);
}
#[test]
fn contains_point_lower_closed_upper_open_below_lower() {
let interval = IntervalLowerClosedUpperOpen::new(5.0, 15.0);
assert!(
!interval.contains_point(&4.9),
"Point 4.9 below lower bound should be excluded from [5, 15)"
);
assert!(
!interval.contains_point(&0.0),
"Point 0.0 well below lower bound should be excluded"
);
}
#[test]
fn contains_point_lower_closed_upper_open_above_upper() {
let interval = IntervalLowerClosedUpperOpen::new(5.0, 15.0);
assert!(
!interval.contains_point(&15.1),
"Point 15.1 above upper bound should be excluded from [5, 15)"
);
assert!(
!interval.contains_point(&20.0),
"Point 20.0 well above upper bound should be excluded"
);
}
#[test]
fn contains_point_lower_closed_upper_open_negative_bounds() {
let interval = IntervalLowerClosedUpperOpen::new(-10.0, -5.0);
assert!(
interval.contains_point(&-10.0),
"Lower bound -10.0 should be included in [-10, -5)"
);
assert!(
!interval.contains_point(&-5.0),
"Upper bound -5.0 should be excluded from [-10, -5)"
);
assert!(
interval.contains_point(&-7.5),
"Interior point -7.5 should be included"
);
assert!(
!interval.contains_point(&-4.0),
"Point -4.0 above upper bound should be excluded"
);
}
#[test]
fn contains_point_lower_closed_upper_open_tiny_interval() {
let interval = IntervalLowerClosedUpperOpen::new(0.0, 1e-10);
assert!(
interval.contains_point(&0.0),
"Lower bound 0.0 should be included"
);
assert!(
!interval.contains_point(&1e-10),
"Upper bound 1e-10 should be excluded"
);
assert!(
interval.contains_point(&5e-11),
"Interior point 5e-11 should be included"
);
}
#[test]
fn contains_point_lower_closed_upper_open_boundary_precision() {
let interval = IntervalLowerClosedUpperOpen::new(0.0, 1.0);
assert!(
interval.contains_point(&0.0),
"Exact lower bound should be included"
);
assert!(
interval.contains_point(&f64::EPSILON),
"Point just above lower bound should be included"
);
assert!(
!interval.contains_point(&1.0),
"Exact upper bound should be excluded"
);
assert!(
interval.contains_point(&(1.0 - f64::EPSILON)),
"Point just below upper bound should be included"
);
}
#[test]
fn contains_point_lower_closed_upper_open_vs_closed() {
let half_open = IntervalLowerClosedUpperOpen::new(0.0, 10.0);
let closed = IntervalClosed::new(0.0, 10.0);
assert_eq!(
half_open.contains_point(&0.0),
closed.contains_point(&0.0),
"Both should include lower bound"
);
assert!(
!half_open.contains_point(&10.0),
"Half-open should exclude upper bound"
);
assert!(
closed.contains_point(&10.0),
"Closed should include upper bound"
);
assert_eq!(
half_open.contains_point(&5.0),
closed.contains_point(&5.0),
"Both should include interior points"
);
}
#[test]
fn contains_point_lower_closed_upper_open_vs_open() {
let half_open = IntervalLowerClosedUpperOpen::new(0.0, 10.0);
let open = IntervalOpen::new(0.0, 10.0);
assert!(
half_open.contains_point(&0.0),
"Half-open should include lower bound"
);
assert!(
!open.contains_point(&0.0),
"Open should exclude lower bound"
);
assert_eq!(
half_open.contains_point(&10.0),
open.contains_point(&10.0),
"Both should exclude upper bound"
);
assert_eq!(
half_open.contains_point(&5.0),
open.contains_point(&5.0),
"Both should include interior points"
);
}
#[test]
fn contains_point_lower_closed_upper_open_multiple_points() {
let interval = IntervalLowerClosedUpperOpen::new(2.0, 8.0);
let test_points = vec![
(1.0, false), (2.0, true), (3.0, true), (5.0, true), (7.999, true), (8.0, false), (9.0, false), ];
for (point, expected) in test_points {
assert_eq!(
interval.contains_point(&point),
expected,
"Point {} containment in [2, 8) should be {}",
point,
expected
);
}
}
#[test]
fn contains_point_lower_closed_upper_open_unit_interval() {
let interval = IntervalLowerClosedUpperOpen::new(0.0, 1.0);
assert!(interval.contains_point(&0.0), "[0, 1) should include 0.0");
assert!(interval.contains_point(&0.5), "[0, 1) should include 0.5");
assert!(!interval.contains_point(&1.0), "[0, 1) should exclude 1.0");
assert!(
!interval.contains_point(&-0.1),
"[0, 1) should exclude -0.1"
);
assert!(!interval.contains_point(&1.1), "[0, 1) should exclude 1.1");
}
}
mod sub_interval_in_partition {
use super::*;
use num_valid::{RealNative64StrictFiniteInDebug, scalars::PositiveRealScalar};
use try_create::TryNew;
type Real = RealNative64StrictFiniteInDebug;
type TestIntervals = (
SubIntervalInPartition<IntervalClosed<Real>>,
SubIntervalInPartition<IntervalClosed<Real>>,
SubIntervalInPartition<IntervalClosed<Real>>,
);
fn create_test_intervals() -> TestIntervals {
let first = SubIntervalInPartition::First(IntervalLowerClosedUpperOpen::new(
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap(),
));
let interior = SubIntervalInPartition::Middle(IntervalLowerClosedUpperOpen::new(
Real::try_new(1.0).unwrap(),
Real::try_new(2.0).unwrap(),
));
let last = SubIntervalInPartition::Last(IntervalClosed::new(
Real::try_new(2.0).unwrap(),
Real::try_new(3.0).unwrap(),
));
(first, interior, last)
}
#[test]
fn test_construction_and_basic_properties() {
let (first, interior, last) = create_test_intervals();
assert_eq!(first.lower_bound_value(), &Real::try_new(0.0).unwrap());
assert_eq!(first.upper_bound_value(), &Real::try_new(1.0).unwrap());
assert_eq!(interior.lower_bound_value(), &Real::try_new(1.0).unwrap());
assert_eq!(interior.upper_bound_value(), &Real::try_new(2.0).unwrap());
assert_eq!(last.lower_bound_value(), &Real::try_new(2.0).unwrap());
assert_eq!(last.upper_bound_value(), &Real::try_new(3.0).unwrap());
}
#[test]
fn test_point_containment() {
let (first, interior, last) = create_test_intervals();
assert!(first.contains_point(&Real::try_new(0.0).unwrap())); assert!(first.contains_point(&Real::try_new(0.5).unwrap())); assert!(!first.contains_point(&Real::try_new(1.0).unwrap())); assert!(!first.contains_point(&Real::try_new(-0.1).unwrap())); assert!(!first.contains_point(&Real::try_new(1.1).unwrap()));
assert!(interior.contains_point(&Real::try_new(1.0).unwrap())); assert!(interior.contains_point(&Real::try_new(1.5).unwrap())); assert!(!interior.contains_point(&Real::try_new(2.0).unwrap())); assert!(!interior.contains_point(&Real::try_new(0.9).unwrap())); assert!(!interior.contains_point(&Real::try_new(2.1).unwrap()));
assert!(last.contains_point(&Real::try_new(2.0).unwrap())); assert!(last.contains_point(&Real::try_new(2.5).unwrap())); assert!(last.contains_point(&Real::try_new(3.0).unwrap())); assert!(!last.contains_point(&Real::try_new(1.9).unwrap())); assert!(!last.contains_point(&Real::try_new(3.1).unwrap())); }
#[test]
fn test_interval_containment() {
let (first, interior, last) = create_test_intervals();
assert!(first.contains_interval(&first));
assert!(interior.contains_interval(&interior));
assert!(last.contains_interval(&last));
assert!(!first.contains_interval(&interior));
assert!(!first.contains_interval(&last));
assert!(!interior.contains_interval(&first));
assert!(!interior.contains_interval(&last));
assert!(!last.contains_interval(&first));
assert!(!last.contains_interval(&interior));
let small_in_first = SubIntervalInPartition::<IntervalClosed<Real>>::First(
IntervalLowerClosedUpperOpen::new(
Real::try_new(0.2).unwrap(),
Real::try_new(0.8).unwrap(),
),
);
assert!(first.contains_interval(&small_in_first));
assert!(!interior.contains_interval(&small_in_first));
assert!(!last.contains_interval(&small_in_first));
}
#[test]
fn test_length_calculation() {
let (first, interior, last) = create_test_intervals();
let length_one = PositiveRealScalar::try_new(Real::one()).unwrap();
assert_eq!(first.length(), length_one.clone());
assert_eq!(interior.length(), length_one.clone());
assert_eq!(last.length(), length_one);
}
#[test]
fn test_midpoint_calculation() {
let (first, interior, last) = create_test_intervals();
assert_eq!(first.midpoint(), Real::try_new(0.5).unwrap());
assert_eq!(interior.midpoint(), Real::try_new(1.5).unwrap());
assert_eq!(last.midpoint(), Real::try_new(2.5).unwrap());
}
#[test]
fn test_bounds_pair_extraction() {
let (first, interior, last) = create_test_intervals();
assert_eq!(
first.clone().into_bounds_pair(),
(Real::try_new(0.0).unwrap(), Real::try_new(1.0).unwrap())
);
assert_eq!(
interior.clone().into_bounds_pair(),
(Real::try_new(1.0).unwrap(), Real::try_new(2.0).unwrap())
);
assert_eq!(
last.clone().into_bounds_pair(),
(Real::try_new(2.0).unwrap(), Real::try_new(3.0).unwrap())
);
}
#[test]
fn test_symmetry() {
let (first, interior, last) = create_test_intervals();
assert!(!first.is_symmetric());
assert!(!interior.is_symmetric());
assert!(!last.is_symmetric());
let symmetric = SubIntervalInPartition::<IntervalClosed<Real>>::Last(
IntervalClosed::new(Real::try_new(-1.0).unwrap(), Real::try_new(1.0).unwrap()),
);
assert!(symmetric.is_symmetric());
}
#[test]
fn test_intersection_operations() {
let (first, interior, last) = create_test_intervals();
let intersection_first_interior = first.intersection(&interior);
match intersection_first_interior {
Some(Interval::FiniteLength(IntervalFiniteLength::ZeroLength(singleton))) => {
assert_eq!(singleton.value(), &Real::try_new(1.0).unwrap());
}
None => {
}
_ => panic!("Expected singleton or no intersection between [0,1) and [1,2)"),
}
let intersection_interior_last = interior.intersection(&last);
match intersection_interior_last {
Some(Interval::FiniteLength(IntervalFiniteLength::ZeroLength(singleton))) => {
assert_eq!(singleton.value(), &Real::try_new(2.0).unwrap());
}
None => {
}
_ => panic!("Expected singleton or no intersection between [1,2) and [2,3]"),
}
assert!(first.intersection(&last).is_none());
let self_intersection = first.intersection(&first).unwrap();
match self_intersection {
Interval::FiniteLength(IntervalFiniteLength::PositiveLength(positive)) => {
assert_eq!(positive.length().into_inner(), Real::try_new(1.0).unwrap());
assert_eq!(positive.lower_bound_value(), &Real::try_new(0.0).unwrap());
assert_eq!(positive.upper_bound_value(), &Real::try_new(1.0).unwrap());
}
_ => panic!("Self-intersection should return equivalent positive-length interval"),
}
}
#[test]
fn test_boundary_semantics() {
let (first, interior, last) = create_test_intervals();
assert!(first.contains_point(&Real::try_new(0.0).unwrap()));
assert!(!first.contains_point(&Real::try_new(1.0).unwrap()));
assert!(interior.contains_point(&Real::try_new(1.0).unwrap()));
assert!(!interior.contains_point(&Real::try_new(2.0).unwrap()));
assert!(last.contains_point(&Real::try_new(2.0).unwrap()));
assert!(last.contains_point(&Real::try_new(3.0).unwrap()));
}
#[test]
fn test_partition_continuity() {
let (first, interior, last) = create_test_intervals();
assert_eq!(first.upper_bound_value(), interior.lower_bound_value());
assert_eq!(interior.upper_bound_value(), last.lower_bound_value());
let test_points = [0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0];
for &point in &test_points {
let test_point = Real::try_new(point).unwrap();
let containing_intervals = [&first, &interior, &last]
.iter()
.filter(|interval| interval.contains_point(&test_point))
.count();
assert_eq!(
containing_intervals, 1,
"Point {} should be contained in exactly one sub-interval",
point
);
}
}
#[test]
fn test_equality_and_debug() {
let first1 = SubIntervalInPartition::<IntervalLowerClosedUpperOpen<Real>>::First(
IntervalLowerClosedUpperOpen::new(
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap(),
),
);
let first2 = SubIntervalInPartition::<IntervalLowerClosedUpperOpen<Real>>::First(
IntervalLowerClosedUpperOpen::new(
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap(),
),
);
let different = SubIntervalInPartition::<IntervalLowerClosedUpperOpen<Real>>::First(
IntervalLowerClosedUpperOpen::new(
Real::try_new(0.0).unwrap(),
Real::try_new(2.0).unwrap(),
),
);
assert_eq!(first1, first2);
assert_ne!(first1, different);
let debug_str = format!("{:?}", first1);
assert!(debug_str.contains("First"));
}
#[test]
fn test_clone() {
let (first, interior, last) = create_test_intervals();
let first_clone = first.clone();
let interior_clone = interior.clone();
let last_clone = last.clone();
assert_eq!(first, first_clone);
assert_eq!(interior, interior_clone);
assert_eq!(last, last_clone);
assert_eq!(first_clone.length(), first.length());
assert_eq!(interior_clone.midpoint(), interior.midpoint());
assert_eq!(last_clone.into_bounds_pair(), last.into_bounds_pair());
}
#[test]
fn test_with_different_scalar_types() {
let first_f64 = SubIntervalInPartition::<IntervalLowerClosedUpperOpen<f64>>::First(
IntervalLowerClosedUpperOpen::new(0.0_f64, 1.0_f64),
);
assert!(first_f64.contains_point(&0.0));
assert!(first_f64.contains_point(&0.5));
assert!(!first_f64.contains_point(&1.0));
use num_valid::RealNative64StrictFinite;
let first_validated = SubIntervalInPartition::<
IntervalLowerClosedUpperOpen<RealNative64StrictFinite>,
>::First(IntervalLowerClosedUpperOpen::new(
RealNative64StrictFinite::try_new(0.0).unwrap(),
RealNative64StrictFinite::try_new(1.0).unwrap(),
));
assert!(
first_validated.contains_point(&RealNative64StrictFinite::try_new(0.0).unwrap())
);
assert!(
first_validated.contains_point(&RealNative64StrictFinite::try_new(0.5).unwrap())
);
assert!(
!first_validated.contains_point(&RealNative64StrictFinite::try_new(1.0).unwrap())
);
}
#[test]
fn test_conversion_to_general_intervals() {
let (first, interior, last) = create_test_intervals();
let first_general: Interval<Real> = first.into();
let interior_general: Interval<Real> = interior.into();
let last_general: Interval<Real> = last.into();
assert!(first_general.contains_point(&Real::try_new(0.0).unwrap()));
assert!(!first_general.contains_point(&Real::try_new(1.0).unwrap()));
assert!(interior_general.contains_point(&Real::try_new(1.0).unwrap()));
assert!(!interior_general.contains_point(&Real::try_new(2.0).unwrap()));
assert!(last_general.contains_point(&Real::try_new(2.0).unwrap()));
assert!(last_general.contains_point(&Real::try_new(3.0).unwrap()));
}
#[test]
fn test_interior_and_closure_operations() {
let (first, middle, last) = create_test_intervals();
let first_interior: IntervalOpen<_> = first.clone().interior();
let _middle_interior: IntervalOpen<_> = middle.clone().interior();
let _last_interior: IntervalOpen<_> = last.clone().interior();
assert!(!first_interior.contains_point(&Real::try_new(0.0).unwrap()));
assert!(!first_interior.contains_point(&Real::try_new(1.0).unwrap()));
assert!(first_interior.contains_point(&Real::try_new(0.5).unwrap()));
let first_closure: IntervalClosed<_> = first.clone().closure();
let _middle_closure: IntervalClosed<_> = middle.clone().closure();
let _last_closure: IntervalClosed<_> = last.clone().closure();
assert!(first_closure.contains_point(&Real::try_new(0.0).unwrap()));
assert!(first_closure.contains_point(&Real::try_new(1.0).unwrap()));
assert!(first_closure.contains_point(&Real::try_new(0.5).unwrap()));
}
#[test]
fn test_edge_cases() {
let tiny_first = SubIntervalInPartition::<IntervalLowerClosedUpperOpen<Real>>::First(
IntervalLowerClosedUpperOpen::new(
Real::try_new(0.0).unwrap(),
Real::try_new(f64::EPSILON).unwrap(),
),
);
assert!(tiny_first.length().into_inner() > Real::try_new(0.0).unwrap());
assert!(tiny_first.contains_point(&Real::try_new(0.0).unwrap()));
assert!(!tiny_first.contains_point(&Real::try_new(f64::EPSILON).unwrap()));
assert!(!tiny_first.contains_point(&Real::try_new(1.001 * f64::EPSILON).unwrap()));
let negative_last = SubIntervalInPartition::<IntervalLowerClosedUpperOpen<Real>>::Last(
IntervalLowerClosedUpperOpen::new(
Real::try_new(-2.0).unwrap(),
Real::try_new(-1.0).unwrap(),
),
);
assert!(negative_last.contains_point(&Real::try_new(-1.5).unwrap()));
assert!(negative_last.contains_point(&Real::try_new(-2.0).unwrap()));
assert!(!negative_last.contains_point(&Real::try_new(-1.0).unwrap()));
assert!(!negative_last.contains_point(&Real::try_new(0.0).unwrap()));
}
#[test]
fn test_only_interval_in_partition() {
let closed =
IntervalClosed::new(Real::try_new(0.).unwrap(), Real::try_new(1.).unwrap());
let only = SubIntervalInPartition::<IntervalClosed<Real>>::Single(closed.clone());
assert_eq!(only.lower_bound_value(), &Real::try_new(0.0).unwrap());
assert_eq!(only.upper_bound_value(), &Real::try_new(1.0).unwrap());
let closed: Interval<_> = closed.into();
let only: Interval<_> = only.into();
assert_eq!(closed, only);
}
#[test]
fn is_lower_bound_closed_only_closed() {
let domain = IntervalClosed::new(0.0, 10.0);
let sub_interval: SubIntervalInPartition<IntervalClosed<f64>> =
SubIntervalInPartition::Single(domain);
assert!(
sub_interval.is_lower_bound_closed(),
"Only interval with closed domain should have closed lower bound"
);
}
#[test]
fn is_lower_bound_closed_only_open() {
let domain = IntervalOpen::new(0.0, 10.0);
let sub_interval: SubIntervalInPartition<IntervalOpen<f64>> =
SubIntervalInPartition::Single(domain);
assert!(
!sub_interval.is_lower_bound_closed(),
"Only interval with open domain should have open lower bound"
);
}
#[test]
fn is_lower_bound_closed_only_half_open() {
let domain = IntervalLowerClosedUpperOpen::new(0.0, 10.0);
let sub_interval: SubIntervalInPartition<IntervalLowerClosedUpperOpen<f64>> =
SubIntervalInPartition::Single(domain);
assert!(
sub_interval.is_lower_bound_closed(),
"Only interval [a, b) should have closed lower bound"
);
}
#[test]
fn is_lower_bound_closed_first_closed() {
let first_interval = IntervalLowerClosedUpperOpen::new(0.0, 5.0);
let sub_interval: SubIntervalInPartition<IntervalClosed<f64>> =
SubIntervalInPartition::First(first_interval);
assert!(
sub_interval.is_lower_bound_closed(),
"First interval from closed domain should have closed lower bound"
);
}
#[test]
fn is_lower_bound_closed_first_open() {
let first_interval = IntervalLowerOpenUpperClosed::new(0.0, 5.0);
let sub_interval: SubIntervalInPartition<IntervalOpen<f64>> =
SubIntervalInPartition::First(first_interval);
assert!(
!sub_interval.is_lower_bound_closed(),
"First interval from open domain should have open lower bound"
);
}
#[test]
fn is_lower_bound_closed_first_half_open() {
let first_interval = IntervalLowerClosedUpperOpen::new(0.0, 5.0);
let sub_interval: SubIntervalInPartition<IntervalLowerClosedUpperOpen<f64>> =
SubIntervalInPartition::First(first_interval);
assert!(
sub_interval.is_lower_bound_closed(),
"First interval from [a, b) domain should have closed lower bound"
);
}
#[test]
fn is_lower_bound_closed_middle() {
let middle_interval = IntervalLowerClosedUpperOpen::new(5.0, 7.5);
let sub_interval: SubIntervalInPartition<IntervalClosed<f64>> =
SubIntervalInPartition::Middle(middle_interval);
assert!(
sub_interval.is_lower_bound_closed(),
"Middle interval [a, b) should always have closed lower bound"
);
assert!(
sub_interval.is_upper_bound_open(),
"Middle interval [a, b) should always have open upper bound"
);
}
#[test]
fn is_lower_bound_closed_last_closed() {
let last_interval = IntervalClosed::new(7.5, 10.0);
let sub_interval: SubIntervalInPartition<IntervalClosed<f64>> =
SubIntervalInPartition::Last(last_interval);
assert!(
sub_interval.is_lower_bound_closed(),
"Last interval from closed domain should have closed lower bound"
);
assert!(
sub_interval.is_upper_bound_closed(),
"Last interval from closed domain should have closed upper bound"
);
}
#[test]
fn is_lower_bound_closed_last_open() {
let last_interval = IntervalOpen::new(7.5, 10.0);
let sub_interval: SubIntervalInPartition<IntervalOpen<f64>> =
SubIntervalInPartition::Last(last_interval);
assert!(
!sub_interval.is_lower_bound_closed(),
"Last interval from open domain should have open lower bound"
);
}
#[test]
fn is_lower_bound_closed_last_half_open() {
let last_interval = IntervalLowerClosedUpperOpen::new(7.5, 10.0);
let sub_interval: SubIntervalInPartition<IntervalLowerClosedUpperOpen<f64>> =
SubIntervalInPartition::Last(last_interval);
assert!(
sub_interval.is_lower_bound_closed(),
"Last interval from [a, b) domain should have closed lower bound"
);
}
#[test]
fn is_lower_bound_closed_consistency_with_value() {
let closed_interval = IntervalClosed::new(5.0, 10.0);
let sub_interval: SubIntervalInPartition<IntervalClosed<f64>> =
SubIntervalInPartition::Single(closed_interval);
let lower_value = sub_interval.lower_bound_value();
assert_eq!(lower_value, &5.0);
assert!(sub_interval.is_lower_bound_closed());
assert!(
sub_interval.contains_point(&5.0),
"Closed lower bound should contain the boundary point"
);
}
#[test]
fn is_lower_bound_closed_all_variants() {
let only_closed: SubIntervalInPartition<IntervalClosed<f64>> =
SubIntervalInPartition::Single(IntervalClosed::new(0.0, 10.0));
assert!(only_closed.is_lower_bound_closed());
let first: SubIntervalInPartition<IntervalClosed<f64>> =
SubIntervalInPartition::First(IntervalLowerClosedUpperOpen::new(0.0, 3.0));
assert!(first.is_lower_bound_closed());
assert!(!first.is_upper_bound_closed());
let middle: SubIntervalInPartition<IntervalClosed<f64>> =
SubIntervalInPartition::Middle(IntervalLowerClosedUpperOpen::new(3.0, 7.0));
assert!(middle.is_lower_bound_closed());
assert!(!middle.is_upper_bound_closed());
let last: SubIntervalInPartition<IntervalClosed<f64>> =
SubIntervalInPartition::Last(IntervalClosed::new(7.0, 10.0));
assert!(last.is_lower_bound_closed());
assert!(last.is_upper_bound_closed());
}
#[test]
fn is_lower_bound_closed_negative_values() {
type S = SubIntervalInPartition<IntervalClosed<f64>>;
let closed_neg: S = SubIntervalInPartition::Single(IntervalClosed::new(-10.0, -5.0));
assert!(
closed_neg.is_lower_bound_closed(),
"Closed interval with negative bounds should have closed lower bound"
);
assert!(
closed_neg.is_upper_bound_closed(),
"Closed interval with negative bounds should have closed upper bound"
);
let middle_neg: S =
SubIntervalInPartition::Middle(IntervalLowerClosedUpperOpen::new(-5.0, 0.0));
assert!(
middle_neg.is_lower_bound_closed(),
"Middle interval with negative bounds should have closed lower bound"
);
assert!(
!middle_neg.is_upper_bound_closed(),
"Middle interval with negative bounds should have open upper bound"
);
}
#[test]
fn is_upper_bound_closed_only_closed() {
let domain = IntervalClosed::new(0.0, 10.0);
let sub_interval: SubIntervalInPartition<IntervalClosed<f64>> =
SubIntervalInPartition::Single(domain);
assert!(
sub_interval.is_upper_bound_closed(),
"Only interval with closed domain should have closed upper bound"
);
}
#[test]
fn is_upper_bound_closed_only_open() {
let domain = IntervalOpen::new(0.0, 10.0);
let sub_interval: SubIntervalInPartition<IntervalOpen<f64>> =
SubIntervalInPartition::Single(domain);
assert!(
!sub_interval.is_upper_bound_closed(),
"Only interval with open domain should have open upper bound"
);
}
#[test]
fn is_upper_bound_closed_only_half_open() {
let domain = IntervalLowerClosedUpperOpen::new(0.0, 10.0);
let sub_interval: SubIntervalInPartition<IntervalLowerClosedUpperOpen<f64>> =
SubIntervalInPartition::Single(domain);
assert!(
!sub_interval.is_upper_bound_closed(),
"Only interval [a, b) should have open upper bound"
);
}
#[test]
fn is_upper_bound_closed_first_closed() {
let first_interval = IntervalLowerClosedUpperOpen::new(0.0, 5.0);
let sub_interval: SubIntervalInPartition<IntervalClosed<f64>> =
SubIntervalInPartition::First(first_interval);
assert!(
sub_interval.is_lower_bound_closed(),
"First interval from closed domain should have closed lower bound"
);
assert!(
sub_interval.is_upper_bound_open(),
"First interval from closed domain should have open upper bound"
);
}
#[test]
fn is_upper_bound_closed_first_open() {
let first_interval = IntervalLowerOpenUpperClosed::new(0.0, 5.0);
let sub_interval: SubIntervalInPartition<IntervalOpen<f64>> =
SubIntervalInPartition::First(first_interval);
assert!(
sub_interval.is_upper_bound_closed(),
"First interval from open domain should have closed upper bound (gap-free partition)"
);
}
#[test]
fn is_upper_bound_closed_first_half_open() {
let first_interval = IntervalLowerClosedUpperOpen::new(0.0, 5.0);
let sub_interval: SubIntervalInPartition<IntervalLowerClosedUpperOpen<f64>> =
SubIntervalInPartition::First(first_interval);
assert!(
sub_interval.is_lower_bound_closed(),
"First interval from [a, b) domain should have closed lower bound"
);
assert!(
!sub_interval.is_upper_bound_closed(),
"First interval from [a, b) domain should have open upper bound"
);
}
#[test]
fn is_upper_bound_closed_middle() {
let middle_interval = IntervalLowerClosedUpperOpen::new(5.0, 7.5);
let sub_interval: SubIntervalInPartition<IntervalClosed<f64>> =
SubIntervalInPartition::Middle(middle_interval);
assert!(
sub_interval.is_lower_bound_closed(),
"Middle interval [a, b) should always have closed lower bound"
);
assert!(
!sub_interval.is_upper_bound_closed(),
"Middle interval [a, b) should always have open upper bound"
);
}
#[test]
fn is_upper_bound_closed_last_closed() {
let last_interval = IntervalClosed::new(7.5, 10.0);
let sub_interval: SubIntervalInPartition<IntervalClosed<f64>> =
SubIntervalInPartition::Last(last_interval);
assert!(
sub_interval.is_lower_bound_closed(),
"Last interval from closed domain should have closed lower bound"
);
assert!(
sub_interval.is_upper_bound_closed(),
"Last interval from closed domain should have closed upper bound"
);
}
#[test]
fn is_upper_bound_closed_last_open() {
let last_interval = IntervalOpen::new(7.5, 10.0);
let sub_interval: SubIntervalInPartition<IntervalOpen<f64>> =
SubIntervalInPartition::Last(last_interval);
assert!(
!sub_interval.is_upper_bound_closed(),
"Last interval from open domain should have open upper bound"
);
}
#[test]
fn is_upper_bound_closed_last_half_open() {
let last_interval = IntervalLowerClosedUpperOpen::new(7.5, 10.0);
let sub_interval: SubIntervalInPartition<IntervalLowerClosedUpperOpen<f64>> =
SubIntervalInPartition::Last(last_interval);
assert!(
!sub_interval.is_upper_bound_closed(),
"Last interval from [a, b) domain should have open upper bound"
);
}
#[test]
fn is_upper_bound_closed_consistency_with_value() {
let closed_interval = IntervalClosed::new(5.0, 10.0);
let sub_interval: SubIntervalInPartition<IntervalClosed<f64>> =
SubIntervalInPartition::Single(closed_interval);
let upper_value = sub_interval.upper_bound_value();
assert_eq!(upper_value, &10.0);
assert!(sub_interval.is_upper_bound_closed());
assert!(
sub_interval.contains_point(&10.0),
"Closed upper bound should contain the boundary point"
);
}
#[test]
fn is_upper_bound_closed_all_variants() {
type S = SubIntervalInPartition<IntervalClosed<f64>>;
let only_closed: S = SubIntervalInPartition::Single(IntervalClosed::new(0.0, 10.0));
assert!(only_closed.is_lower_bound_closed());
assert!(only_closed.is_upper_bound_closed());
let first_closed: S =
SubIntervalInPartition::First(IntervalLowerClosedUpperOpen::new(0.0, 3.0));
assert!(first_closed.is_lower_bound_closed());
assert!(first_closed.is_upper_bound_open());
let middle: S =
SubIntervalInPartition::Middle(IntervalLowerClosedUpperOpen::new(3.0, 7.0));
assert!(middle.is_lower_bound_closed());
assert!(middle.is_upper_bound_open());
let last_closed: S = SubIntervalInPartition::Last(IntervalClosed::new(7.0, 10.0));
assert!(last_closed.is_lower_bound_closed());
assert!(last_closed.is_upper_bound_closed());
}
#[test]
fn is_upper_bound_closed_negative_values() {
let closed_neg: SubIntervalInPartition<IntervalClosed<f64>> =
SubIntervalInPartition::Single(IntervalClosed::new(-10.0, -5.0));
assert!(
closed_neg.is_upper_bound_closed(),
"Closed interval with negative bounds should have closed upper bound"
);
let middle_neg: SubIntervalInPartition<IntervalClosed<f64>> =
SubIntervalInPartition::Middle(IntervalLowerClosedUpperOpen::new(-5.0, 0.0));
assert!(
middle_neg.is_lower_bound_closed(),
"Middle interval [a, b) with negative bounds should have closed lower bound"
);
assert!(
!middle_neg.is_upper_bound_closed(),
"Middle interval [a, b) with negative bounds should have open upper bound"
);
}
#[test]
fn is_upper_bound_open_only_closed() {
let domain = IntervalClosed::new(0.0, 10.0);
let sub_interval: SubIntervalInPartition<IntervalClosed<f64>> =
SubIntervalInPartition::Single(domain);
assert!(
!sub_interval.is_upper_bound_open(),
"Only interval with closed domain should not have open upper bound"
);
}
#[test]
fn is_upper_bound_open_only_open() {
let domain = IntervalOpen::new(0.0, 10.0);
let sub_interval: SubIntervalInPartition<IntervalOpen<f64>> =
SubIntervalInPartition::Single(domain);
assert!(
sub_interval.is_upper_bound_open(),
"Only interval with open domain should have open upper bound"
);
}
#[test]
fn is_upper_bound_open_only_half_open() {
let domain = IntervalLowerClosedUpperOpen::new(0.0, 10.0);
let sub_interval: SubIntervalInPartition<IntervalLowerClosedUpperOpen<f64>> =
SubIntervalInPartition::Single(domain);
assert!(
sub_interval.is_upper_bound_open(),
"Only interval [a, b) should have open upper bound"
);
}
#[test]
fn is_upper_bound_open_first() {
let first_interval = IntervalLowerClosedUpperOpen::new(0.0, 5.0);
let sub_interval: SubIntervalInPartition<IntervalClosed<f64>> =
SubIntervalInPartition::First(first_interval);
assert!(
sub_interval.is_lower_bound_closed(),
"First interval should have closed lower bound"
);
assert!(
sub_interval.is_upper_bound_open(),
"First interval should have open upper bound"
);
}
#[test]
fn is_upper_bound_open_middle() {
let middle_interval = IntervalLowerClosedUpperOpen::new(5.0, 7.5);
let sub_interval: SubIntervalInPartition<IntervalClosed<f64>> =
SubIntervalInPartition::Middle(middle_interval);
assert!(
sub_interval.is_lower_bound_closed(),
"Middle interval [a, b) should have closed lower bound"
);
assert!(
sub_interval.is_upper_bound_open(),
"Middle interval [a, b) should have open upper bound"
);
}
#[test]
fn is_upper_bound_open_last_closed() {
let last_interval = IntervalClosed::new(7.5, 10.0);
let sub_interval: SubIntervalInPartition<IntervalClosed<f64>> =
SubIntervalInPartition::Last(last_interval);
assert!(
sub_interval.is_lower_bound_closed(),
"Last interval from closed domain should have closed lower bound"
);
assert!(
sub_interval.is_upper_bound_closed(),
"Last interval from closed domain should have closed upper bound"
);
}
#[test]
fn is_upper_bound_open_last_open() {
let last_interval = IntervalOpen::new(7.5, 10.0);
let sub_interval: SubIntervalInPartition<IntervalOpen<f64>> =
SubIntervalInPartition::Last(last_interval);
assert!(
sub_interval.is_upper_bound_open(),
"Last interval from open domain should have open upper bound"
);
}
#[test]
fn is_upper_bound_open_last_half_open() {
let last_interval = IntervalLowerClosedUpperOpen::new(7.5, 10.0);
let sub_interval: SubIntervalInPartition<IntervalLowerClosedUpperOpen<f64>> =
SubIntervalInPartition::Last(last_interval);
assert!(
sub_interval.is_upper_bound_open(),
"Last interval from [a, b) domain should have open upper bound"
);
}
#[test]
fn is_upper_bound_open_complement_relationship() {
let closed: SubIntervalInPartition<IntervalClosed<f64>> =
SubIntervalInPartition::Single(IntervalClosed::new(0.0, 10.0));
assert_eq!(
closed.is_upper_bound_open(),
!closed.is_upper_bound_closed(),
"is_upper_bound_open should be complement of is_upper_bound_closed"
);
let open: SubIntervalInPartition<IntervalOpen<f64>> =
SubIntervalInPartition::Single(IntervalOpen::new(0.0, 10.0));
assert_eq!(
open.is_upper_bound_open(),
!open.is_upper_bound_closed(),
"Complement relationship should hold for open domain"
);
let middle: SubIntervalInPartition<IntervalClosed<f64>> =
SubIntervalInPartition::Middle(IntervalLowerClosedUpperOpen::new(3.0, 7.0));
assert_eq!(
middle.is_upper_bound_open(),
!middle.is_upper_bound_closed(),
"Complement relationship should hold for middle variant"
);
}
#[test]
fn is_upper_bound_open_consistency_with_containment() {
let half_open: SubIntervalInPartition<IntervalLowerClosedUpperOpen<f64>> =
SubIntervalInPartition::Single(IntervalLowerClosedUpperOpen::new(0.0, 10.0));
assert!(half_open.is_upper_bound_open());
assert!(
!half_open.contains_point(&10.0),
"Open upper bound should exclude the boundary point"
);
let closed: SubIntervalInPartition<IntervalClosed<f64>> =
SubIntervalInPartition::Single(IntervalClosed::new(0.0, 10.0));
assert!(!closed.is_upper_bound_open());
assert!(
closed.contains_point(&10.0),
"Closed upper bound should include the boundary point"
);
}
#[test]
fn is_upper_bound_open_all_variants() {
let only_half_open: SubIntervalInPartition<IntervalLowerClosedUpperOpen<f64>> =
SubIntervalInPartition::Single(IntervalLowerClosedUpperOpen::new(0.0, 10.0));
assert!(only_half_open.is_lower_bound_closed());
assert!(only_half_open.is_upper_bound_open());
let first: SubIntervalInPartition<IntervalClosed<f64>> =
SubIntervalInPartition::First(IntervalLowerClosedUpperOpen::new(0.0, 3.0));
assert!(first.is_lower_bound_closed());
assert!(first.is_upper_bound_open());
let middle: SubIntervalInPartition<IntervalClosed<f64>> =
SubIntervalInPartition::Middle(IntervalLowerClosedUpperOpen::new(3.0, 7.0));
assert!(middle.is_lower_bound_closed());
assert!(middle.is_upper_bound_open());
let last_open: SubIntervalInPartition<IntervalOpen<f64>> =
SubIntervalInPartition::Last(IntervalOpen::new(7.0, 10.0));
assert!(last_open.is_lower_bound_open());
assert!(last_open.is_upper_bound_open());
}
#[test]
fn is_upper_bound_open_negative_values() {
let half_open_neg: SubIntervalInPartition<IntervalLowerClosedUpperOpen<f64>> =
SubIntervalInPartition::Single(IntervalLowerClosedUpperOpen::new(-10.0, -5.0));
assert!(
half_open_neg.is_upper_bound_open(),
"Half-open interval with negative bounds should have open upper bound"
);
let closed_neg: SubIntervalInPartition<IntervalClosed<f64>> =
SubIntervalInPartition::Single(IntervalClosed::new(-10.0, -5.0));
assert!(
!closed_neg.is_upper_bound_open(),
"Closed interval with negative bounds should not have open upper bound"
);
}
}
mod test_interval_lower_unbounded_upper_unbounded {
use super::*;
use num_valid::{RealNative64StrictFinite, RealNative64StrictFiniteInDebug};
use try_create::TryNew;
type Real = RealNative64StrictFiniteInDebug;
type SafeReal = RealNative64StrictFinite;
#[test]
fn test_construction() {
let universal_f64 = IntervalLowerUnboundedUpperUnbounded::<f64>::new();
let universal_real = IntervalLowerUnboundedUpperUnbounded::<Real>::new();
let universal_safe = IntervalLowerUnboundedUpperUnbounded::<SafeReal>::new();
assert_eq!(universal_f64, IntervalLowerUnboundedUpperUnbounded::new());
assert_eq!(universal_real, IntervalLowerUnboundedUpperUnbounded::new());
assert_eq!(universal_safe, IntervalLowerUnboundedUpperUnbounded::new());
}
#[test]
fn test_default() {
let universal = IntervalLowerUnboundedUpperUnbounded::<f64>::default();
let expected = IntervalLowerUnboundedUpperUnbounded::<f64>::new();
assert_eq!(universal, expected);
}
#[test]
#[allow(clippy::clone_on_copy)]
fn test_clone_and_equality() {
let universal1 = IntervalLowerUnboundedUpperUnbounded::<f64>::new();
let universal2 = universal1.clone();
assert_eq!(universal1, universal2);
assert_eq!(universal1, universal1); }
#[test]
fn test_contains_point_always_true() {
let universal = IntervalLowerUnboundedUpperUnbounded::<f64>::new();
assert!(universal.contains_point(&0.0));
assert!(universal.contains_point(&1.0));
assert!(universal.contains_point(&-1.0));
assert!(universal.contains_point(&1000.0));
assert!(universal.contains_point(&-1000.0));
assert!(universal.contains_point(&std::f64::consts::PI));
assert!(universal.contains_point(&std::f64::consts::E));
assert!(universal.contains_point(&f64::MIN));
assert!(universal.contains_point(&f64::MAX));
assert!(universal.contains_point(&f64::EPSILON));
assert!(universal.contains_point(&-f64::EPSILON));
assert!(universal.contains_point(&0.0));
assert!(universal.contains_point(&1e-100));
assert!(universal.contains_point(&-1e-100));
assert!(universal.contains_point(&1e100));
assert!(universal.contains_point(&-1e100));
}
#[test]
fn test_contains_point_with_validated_types() {
let universal = IntervalLowerUnboundedUpperUnbounded::<Real>::new();
let zero = Real::try_new(0.0).unwrap();
let positive = Real::try_new(42.0).unwrap();
let negative = Real::try_new(-17.5).unwrap();
assert!(universal.contains_point(&zero));
assert!(universal.contains_point(&positive));
assert!(universal.contains_point(&negative));
}
#[test]
fn test_contains_any_interval() {
let universal = IntervalLowerUnboundedUpperUnbounded::<f64>::new();
let closed = IntervalClosed::new(0.0, 1.0);
let open = IntervalOpen::new(-1.0, 1.0);
let half_open_left = IntervalLowerOpenUpperClosed::new(0.0, 1.0);
let half_open_right = IntervalLowerClosedUpperOpen::new(0.0, 1.0);
let singleton = IntervalSingleton::new(42.0);
assert!(universal.contains_interval(&closed));
assert!(universal.contains_interval(&open));
assert!(universal.contains_interval(&half_open_left));
assert!(universal.contains_interval(&half_open_right));
assert!(universal.contains_interval(&singleton));
let lower_bounded = IntervalLowerClosedUpperUnbounded::new(0.0);
let upper_bounded = IntervalLowerUnboundedUpperClosed::new(100.0);
let lower_open_unbounded = IntervalLowerOpenUpperUnbounded::new(1.0);
let upper_open_unbounded = IntervalLowerUnboundedUpperOpen::new(10.0);
assert!(universal.contains_interval(&lower_bounded));
assert!(universal.contains_interval(&upper_bounded));
assert!(universal.contains_interval(&lower_open_unbounded));
assert!(universal.contains_interval(&upper_open_unbounded));
let universal2 = IntervalLowerUnboundedUpperUnbounded::<f64>::new();
assert!(universal.contains_interval(&universal2));
}
#[test]
fn test_no_other_interval_contains_universal() {
let universal = IntervalLowerUnboundedUpperUnbounded::<f64>::new();
let closed = IntervalClosed::new(-1000.0, 1000.0);
let open = IntervalOpen::new(-1e6, 1e6);
let singleton = IntervalSingleton::new(0.0);
assert!(!closed.contains_interval(&universal));
assert!(!open.contains_interval(&universal));
assert!(!singleton.contains_interval(&universal));
let lower_bounded = IntervalLowerClosedUpperUnbounded::new(-1000.0);
let upper_bounded = IntervalLowerUnboundedUpperClosed::new(1000.0);
assert!(!lower_bounded.contains_interval(&universal));
assert!(!upper_bounded.contains_interval(&universal));
}
#[test]
fn test_intersection_identity_property() {
let universal = IntervalLowerUnboundedUpperUnbounded::<f64>::new();
let closed = IntervalClosed::new(0.0, 1.0);
let open = IntervalOpen::new(-1.0, 1.0);
let singleton = IntervalSingleton::new(0.5);
if let Some(intersection) = universal.intersection(&closed) {
match intersection {
Interval::FiniteLength(IntervalFiniteLength::PositiveLength(positive)) => {
assert_eq!(positive.length().into_inner(), 1.0);
assert_eq!(positive.lower_bound_value(), &0.0);
assert_eq!(positive.upper_bound_value(), &1.0);
}
_ => panic!("Expected finite positive length interval"),
}
} else {
panic!("Universal intersection should always exist");
}
if let Some(intersection) = universal.intersection(&open) {
match intersection {
Interval::FiniteLength(IntervalFiniteLength::PositiveLength(
IntervalFinitePositiveLength::Open(recovered_open),
)) => {
assert_eq!(recovered_open.lower_bound_value(), &-1.0);
assert_eq!(recovered_open.upper_bound_value(), &1.0);
}
_ => panic!("Expected open interval"),
}
} else {
panic!("Universal intersection should always exist");
}
if let Some(intersection) = universal.intersection(&singleton) {
match intersection {
Interval::FiniteLength(IntervalFiniteLength::ZeroLength(
recovered_singleton,
)) => {
assert_eq!(recovered_singleton.value(), &0.5);
}
_ => panic!("Expected singleton interval"),
}
} else {
panic!("Universal intersection should always exist");
}
}
#[test]
fn test_intersection_with_infinite_intervals() {
let universal = IntervalLowerUnboundedUpperUnbounded::<f64>::new();
let lower_bounded = IntervalLowerClosedUpperUnbounded::new(5.0);
let upper_bounded = IntervalLowerUnboundedUpperClosed::new(10.0);
if let Some(intersection) = universal.intersection(&lower_bounded) {
match intersection {
Interval::InfiniteLength(
IntervalInfiniteLength::LowerClosedUpperUnbounded(result),
) => {
assert_eq!(result.lower_bound_value(), &5.0);
}
_ => panic!("Expected lower bounded infinite interval"),
}
}
if let Some(intersection) = universal.intersection(&upper_bounded) {
match intersection {
Interval::InfiniteLength(
IntervalInfiniteLength::LowerUnboundedUpperClosed(result),
) => {
assert_eq!(result.upper_bound_value(), &10.0);
}
_ => panic!("Expected upper bounded infinite interval"),
}
}
}
#[test]
fn test_intersection_with_self() {
let universal1 = IntervalLowerUnboundedUpperUnbounded::<f64>::new();
let universal2 = IntervalLowerUnboundedUpperUnbounded::<f64>::new();
if let Some(intersection) = universal1.intersection(&universal2) {
match intersection {
Interval::InfiniteLength(
IntervalInfiniteLength::LowerUnboundedUpperUnbounded(_),
) => {
}
_ => panic!("Expected universal interval"),
}
} else {
panic!("Universal should intersect with itself");
}
}
#[test]
fn test_intersection_commutativity() {
let universal = IntervalLowerUnboundedUpperUnbounded::<f64>::new();
let finite = IntervalClosed::new(1.0, 2.0);
let intersection1 = universal.intersection(&finite);
let intersection2 = finite.intersection(&universal);
assert_eq!(intersection1, intersection2);
let semi_infinite = IntervalLowerClosedUpperUnbounded::new(0.0);
let intersection3 = universal.intersection(&semi_infinite);
let intersection4 = semi_infinite.intersection(&universal);
assert_eq!(intersection3, intersection4);
}
#[test]
fn test_universal_as_identity_element() {
let universal = IntervalLowerUnboundedUpperUnbounded::<f64>::new();
let test_intervals = vec![
Interval::from(IntervalClosed::new(0.0, 1.0)),
Interval::from(IntervalOpen::new(-1.0, 1.0)),
Interval::from(IntervalSingleton::new(0.5)),
Interval::from(IntervalLowerClosedUpperUnbounded::new(0.0)),
Interval::from(IntervalLowerUnboundedUpperClosed::new(10.0)),
];
for interval in test_intervals {
let intersection = universal.intersection(&interval).unwrap();
for test_point in [-100.0, -1.0, 0.0, 0.5, 1.0, 10.0, 100.0] {
assert_eq!(
interval.contains_point(&test_point),
intersection.contains_point(&test_point),
"Point containment should be identical for point {}",
test_point
);
}
}
}
#[test]
fn test_memory_efficiency() {
let universal = IntervalLowerUnboundedUpperUnbounded::<f64>::new();
let size = std::mem::size_of_val(&universal);
assert!(
size <= 8,
"Universal interval should be very memory efficient, got {} bytes",
size
);
}
#[test]
fn test_debug_and_display() {
let universal = IntervalLowerUnboundedUpperUnbounded::<f64>::new();
let debug_str = format!("{:?}", universal);
assert!(debug_str.contains("IntervalLowerUnboundedUpperUnbounded"));
println!("Debug: {:?}", universal);
}
#[test]
fn test_serialization() {
let universal = IntervalLowerUnboundedUpperUnbounded::<f64>::new();
let _serialized = serde_json::to_string(&universal);
}
#[test]
fn test_mathematical_properties() {
let universal = IntervalLowerUnboundedUpperUnbounded::<f64>::new();
let finite = IntervalClosed::new(0.0, 1.0);
let intersection = universal.intersection(&finite).unwrap();
for test_point in [0.0, 0.5, 1.0] {
assert!(finite.contains_point(&test_point));
assert!(intersection.contains_point(&test_point));
}
for test_point in [-1.0, 2.0] {
assert!(!finite.contains_point(&test_point));
assert!(!intersection.contains_point(&test_point));
}
}
#[test]
fn test_with_different_scalar_types() {
let universal_f64 = IntervalLowerUnboundedUpperUnbounded::<f64>::new();
let universal_real = IntervalLowerUnboundedUpperUnbounded::<Real>::new();
let universal_safe = IntervalLowerUnboundedUpperUnbounded::<SafeReal>::new();
assert!(universal_f64.contains_point(&0.0_f64));
assert!(universal_real.contains_point(&Real::try_new(0.0).unwrap()));
assert!(universal_safe.contains_point(&SafeReal::try_new(0.0).unwrap()));
let finite_f64 = IntervalClosed::new(0.0_f64, 1.0_f64);
let finite_real =
IntervalClosed::new(Real::try_new(0.0).unwrap(), Real::try_new(1.0).unwrap());
assert!(universal_f64.contains_interval(&finite_f64));
assert!(universal_real.contains_interval(&finite_real));
}
#[test]
fn test_edge_cases_and_boundary_conditions() {
let universal = IntervalLowerUnboundedUpperUnbounded::<f64>::new();
assert!(universal.contains_point(&f64::MIN));
assert!(universal.contains_point(&f64::MAX));
assert!(universal.contains_point(&f64::EPSILON));
assert!(universal.contains_point(&f64::MIN_POSITIVE));
assert!(universal.contains_point(&0.0));
assert!(universal.contains_point(&-0.0));
assert!(universal.contains_point(&1e-300));
assert!(universal.contains_point(&-1e-300));
assert!(universal.contains_point(&1e100));
assert!(universal.contains_point(&-1e100));
}
#[test]
fn test_comparison_with_other_intervals() {
let universal = IntervalLowerUnboundedUpperUnbounded::<f64>::new();
let universal2 = IntervalLowerUnboundedUpperUnbounded::<f64>::new();
assert_eq!(universal, universal2);
}
}
mod interval_hull {
use super::*;
use num_valid::RealNative64StrictFiniteInDebug;
use try_create::TryNew;
type Real = RealNative64StrictFiniteInDebug;
#[test]
fn hull_closed_with_closed() {
let interval1 =
IntervalClosed::new(Real::try_new(1.0).unwrap(), Real::try_new(3.0).unwrap());
let interval2 =
IntervalClosed::new(Real::try_new(2.0).unwrap(), Real::try_new(5.0).unwrap());
let hull = interval1.hull(&interval2);
assert_eq!(hull.lower_bound_value(), &1.0);
assert_eq!(hull.upper_bound_value(), &5.0);
}
#[test]
fn hull_open_with_open() {
let interval1 =
IntervalOpen::new(Real::try_new(1.0).unwrap(), Real::try_new(3.0).unwrap());
let interval2 =
IntervalOpen::new(Real::try_new(2.0).unwrap(), Real::try_new(5.0).unwrap());
let hull = interval1.hull(&interval2);
assert_eq!(hull.lower_bound_value(), &1.0);
assert_eq!(hull.upper_bound_value(), &5.0);
}
#[test]
fn hull_closed_with_open() {
let closed =
IntervalClosed::new(Real::try_new(1.0).unwrap(), Real::try_new(3.0).unwrap());
let open = IntervalOpen::new(Real::try_new(2.0).unwrap(), Real::try_new(5.0).unwrap());
let hull = closed.hull(&open);
match hull {
IntervalFinitePositiveLength::LowerClosedUpperOpen(result) => {
assert_eq!(result.lower_bound_value(), &1.0);
assert_eq!(result.upper_bound_value(), &5.0);
}
_ => panic!("Expected LowerClosedUpperOpen interval"),
}
}
#[test]
fn hull_closed_with_lower_closed_upper_open() {
let closed =
IntervalClosed::new(Real::try_new(1.0).unwrap(), Real::try_new(3.0).unwrap());
let half_open = IntervalLowerClosedUpperOpen::new(
Real::try_new(2.0).unwrap(),
Real::try_new(5.0).unwrap(),
);
let hull = closed.hull(&half_open);
match hull {
IntervalFinitePositiveLength::LowerClosedUpperOpen(result) => {
assert_eq!(result.lower_bound_value(), &1.0);
assert_eq!(result.upper_bound_value(), &5.0);
}
_ => panic!("Expected LowerClosedUpperOpen interval"),
}
}
#[test]
fn hull_closed_with_lower_open_upper_closed() {
let closed =
IntervalClosed::new(Real::try_new(1.0).unwrap(), Real::try_new(3.0).unwrap());
let half_open = IntervalLowerOpenUpperClosed::new(
Real::try_new(2.0).unwrap(),
Real::try_new(5.0).unwrap(),
);
let hull = closed.hull(&half_open);
match hull {
IntervalFinitePositiveLength::Closed(result) => {
assert_eq!(result.lower_bound_value(), &1.0);
assert_eq!(result.upper_bound_value(), &5.0);
}
_ => panic!("Expected Closed interval"),
}
}
#[test]
fn hull_open_with_lower_closed_upper_open() {
let open = IntervalOpen::new(Real::try_new(1.0).unwrap(), Real::try_new(3.0).unwrap());
let half_open = IntervalLowerClosedUpperOpen::new(
Real::try_new(2.0).unwrap(),
Real::try_new(5.0).unwrap(),
);
let hull = open.hull(&half_open);
match hull {
IntervalFinitePositiveLength::Open(result) => {
assert_eq!(result.lower_bound_value(), &1.0);
assert_eq!(result.upper_bound_value(), &5.0);
}
_ => panic!("Expected open interval"),
}
}
#[test]
fn hull_open_with_lower_open_upper_closed() {
let open = IntervalOpen::new(Real::try_new(1.0).unwrap(), Real::try_new(3.0).unwrap());
let half_open = IntervalLowerOpenUpperClosed::new(
Real::try_new(2.0).unwrap(),
Real::try_new(5.0).unwrap(),
);
let hull = open.hull(&half_open);
match hull {
IntervalFinitePositiveLength::LowerOpenUpperClosed(result) => {
assert_eq!(result.lower_bound_value(), &1.0);
assert_eq!(result.upper_bound_value(), &5.0);
}
_ => panic!("Expected LowerOpenUpperClosed interval"),
}
}
#[test]
fn hull_lower_closed_upper_open_with_lower_open_upper_closed() {
let interval1 = IntervalLowerClosedUpperOpen::new(
Real::try_new(1.0).unwrap(),
Real::try_new(3.0).unwrap(),
);
let interval2 = IntervalLowerOpenUpperClosed::new(
Real::try_new(2.0).unwrap(),
Real::try_new(5.0).unwrap(),
);
let hull = interval1.hull(&interval2);
match hull {
IntervalFinitePositiveLength::Closed(result) => {
assert_eq!(result.lower_bound_value(), &1.0);
assert_eq!(result.upper_bound_value(), &5.0);
}
_ => panic!("Expected open interval"),
}
}
#[test]
fn hull_disjoint_intervals() {
let interval1 =
IntervalClosed::new(Real::try_new(1.0).unwrap(), Real::try_new(2.0).unwrap());
let interval2 =
IntervalClosed::new(Real::try_new(4.0).unwrap(), Real::try_new(5.0).unwrap());
let hull = interval1.hull(&interval2);
assert_eq!(hull.lower_bound_value(), &1.0);
assert_eq!(hull.upper_bound_value(), &5.0);
assert_eq!(hull.length().as_ref(), &4.0); }
#[test]
fn hull_overlapping_intervals() {
let interval1 =
IntervalClosed::new(Real::try_new(1.0).unwrap(), Real::try_new(4.0).unwrap());
let interval2 =
IntervalClosed::new(Real::try_new(2.0).unwrap(), Real::try_new(5.0).unwrap());
let hull = interval1.hull(&interval2);
assert_eq!(hull.lower_bound_value(), &1.0);
assert_eq!(hull.upper_bound_value(), &5.0);
}
#[test]
fn hull_contained_intervals() {
let outer =
IntervalClosed::new(Real::try_new(1.0).unwrap(), Real::try_new(5.0).unwrap());
let inner =
IntervalClosed::new(Real::try_new(2.0).unwrap(), Real::try_new(3.0).unwrap());
let hull = outer.hull(&inner);
assert_eq!(hull.lower_bound_value(), &1.0);
assert_eq!(hull.upper_bound_value(), &5.0);
}
#[test]
fn hull_identical_intervals() {
let interval1 =
IntervalClosed::new(Real::try_new(2.0).unwrap(), Real::try_new(4.0).unwrap());
let interval2 =
IntervalClosed::new(Real::try_new(2.0).unwrap(), Real::try_new(4.0).unwrap());
let hull = interval1.hull(&interval2);
assert_eq!(hull.lower_bound_value(), &2.0);
assert_eq!(hull.upper_bound_value(), &4.0);
}
#[test]
fn hull_same_bounds_different_types() {
let closed =
IntervalClosed::new(Real::try_new(1.0).unwrap(), Real::try_new(3.0).unwrap());
let open = IntervalOpen::new(Real::try_new(1.0).unwrap(), Real::try_new(3.0).unwrap());
let hull = closed.hull(&open);
match hull {
IntervalFinitePositiveLength::Closed(result) => {
assert_eq!(result.lower_bound_value(), &1.0);
assert_eq!(result.upper_bound_value(), &3.0);
}
_ => panic!("Expected Closed interval"),
}
}
#[test]
fn hull_with_enum_variant() {
let interval1 = IntervalFinitePositiveLength::Closed(IntervalClosed::new(
Real::try_new(1.0).unwrap(),
Real::try_new(3.0).unwrap(),
));
let interval2 = IntervalFinitePositiveLength::Open(IntervalOpen::new(
Real::try_new(2.0).unwrap(),
Real::try_new(5.0).unwrap(),
));
let hull = interval1.hull(&interval2);
match hull {
IntervalFinitePositiveLength::LowerClosedUpperOpen(result) => {
assert_eq!(result.lower_bound_value(), &1.0);
assert_eq!(result.upper_bound_value(), &5.0);
}
_ => panic!("Expected LowerClosedUpperOpen interval"),
}
}
#[test]
fn hull_symmetry_property() {
let interval1 =
IntervalClosed::new(Real::try_new(1.0).unwrap(), Real::try_new(3.0).unwrap());
let interval2 =
IntervalOpen::new(Real::try_new(2.0).unwrap(), Real::try_new(5.0).unwrap());
let hull1 = interval1.hull(&interval2);
let hull2 = interval2.hull(&interval1);
assert_eq!(hull1, hull2);
}
#[test]
fn hull_containment_property() {
let interval1 =
IntervalClosed::new(Real::try_new(1.0).unwrap(), Real::try_new(3.0).unwrap());
let interval2 = IntervalLowerOpenUpperClosed::new(
Real::try_new(2.5).unwrap(),
Real::try_new(4.0).unwrap(),
);
let hull = interval1.hull(&interval2);
let hull_interval: Interval<Real> = match hull {
IntervalFinitePositiveLength::Closed(h) => Interval::from(h),
_ => panic!("Expected Closed interval"),
};
let interval1_general: Interval<Real> = Interval::from(interval1);
let interval2_general: Interval<Real> = Interval::from(interval2);
assert!(hull_interval.contains_interval(&interval1_general));
assert!(hull_interval.contains_interval(&interval2_general));
}
#[test]
fn hull_with_f64() {
let interval1 = IntervalClosed::new(1.0_f64, 3.0_f64);
let interval2 = IntervalOpen::new(2.0_f64, 5.0_f64);
let hull = interval1.hull(&interval2);
match hull {
IntervalFinitePositiveLength::LowerClosedUpperOpen(h) => {
assert_eq!(*h.lower_bound_value(), 1.0);
assert_eq!(*h.upper_bound_value(), 5.0);
}
_ => panic!("Expected LowerClosedUpperOpen interval"),
}
}
#[test]
fn hull_small_intervals() {
let epsilon = Real::try_new(f64::EPSILON).unwrap();
let zero = Real::try_new(0.0).unwrap();
let two_epsilon = Real::try_new(2.0 * f64::EPSILON).unwrap();
let interval1 = IntervalClosed::new(zero, epsilon);
let interval2 = IntervalClosed::new(epsilon, two_epsilon);
let hull = interval1.hull(&interval2);
assert_eq!(hull.lower_bound_value(), &zero);
assert_eq!(hull.upper_bound_value(), &two_epsilon);
}
#[test]
fn hull_reflexivity() {
let interval =
IntervalClosed::new(Real::try_new(2.0).unwrap(), Real::try_new(4.0).unwrap());
let hull = interval.hull(&interval);
assert_eq!(hull.lower_bound_value(), &2.0);
assert_eq!(hull.upper_bound_value(), &4.0);
assert_eq!(hull.length().as_ref(), &2.0);
}
#[test]
fn hull_bounded_with_lower_bounded_upper_unbounded() {
let bounded =
IntervalClosed::new(Real::try_new(0.0).unwrap(), Real::try_new(2.0).unwrap());
let unbounded = IntervalLowerClosedUpperUnbounded::new(Real::try_new(1.0).unwrap());
let hull = bounded.hull(&unbounded);
match hull {
Interval::InfiniteLength(IntervalInfiniteLength::LowerClosedUpperUnbounded(
result,
)) => {
assert_eq!(result.lower_bound_value(), &0.0);
}
_ => panic!("Expected LowerClosedUpperUnbounded interval"),
}
}
#[test]
fn hull_two_lower_bounded_upper_unbounded() {
let unbounded1 = IntervalLowerClosedUpperUnbounded::new(Real::try_new(0.0).unwrap());
let unbounded2 = IntervalLowerOpenUpperUnbounded::new(Real::try_new(5.0).unwrap());
let hull = unbounded1.hull(&unbounded2);
match hull {
Interval::InfiniteLength(IntervalInfiniteLength::LowerClosedUpperUnbounded(
result,
)) => {
assert_eq!(result.lower_bound_value(), &0.0);
}
_ => panic!("Expected LowerClosedUpperUnbounded interval"),
}
}
#[test]
fn hull_bounded_with_lower_unbounded_upper_bounded() {
let bounded =
IntervalClosed::new(Real::try_new(-2.0).unwrap(), Real::try_new(1.0).unwrap());
let upper_unbounded =
IntervalLowerUnboundedUpperClosed::new(Real::try_new(0.0).unwrap());
let hull = bounded.hull(&upper_unbounded);
match hull {
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperClosed(
result,
)) => {
assert_eq!(result.upper_bound_value(), &1.0);
}
_ => panic!("Expected LowerUnboundedUpperClosed interval"),
}
}
#[test]
fn hull_two_lower_unbounded_upper_bounded() {
let upper_unbounded1 =
IntervalLowerUnboundedUpperClosed::new(Real::try_new(2.0).unwrap());
let upper_unbounded2 =
IntervalLowerUnboundedUpperOpen::new(Real::try_new(-1.0).unwrap());
let hull = upper_unbounded1.hull(&upper_unbounded2);
match hull {
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperClosed(
result,
)) => {
assert_eq!(result.upper_bound_value(), &2.0);
}
_ => panic!("Expected LowerUnboundedUpperClosed interval"),
}
}
#[test]
fn hull_bounded_with_fully_unbounded() {
let bounded =
IntervalClosed::new(Real::try_new(0.0).unwrap(), Real::try_new(10.0).unwrap());
let fully_unbounded = IntervalLowerUnboundedUpperUnbounded::<Real>::new();
let hull = bounded.hull(&fully_unbounded);
match hull {
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperUnbounded(
_,
)) => {
}
_ => panic!("Expected LowerUnboundedUpperUnbounded interval"),
}
}
#[test]
fn hull_using_interval_enum() {
let interval1: Interval<Real> = Interval::from(IntervalClosed::new(
Real::try_new(1.0).unwrap(),
Real::try_new(3.0).unwrap(),
));
let interval2: Interval<Real> = Interval::from(IntervalLowerClosedUpperUnbounded::new(
Real::try_new(2.0).unwrap(),
));
let hull = interval1.hull(&interval2);
match hull {
Interval::InfiniteLength(IntervalInfiniteLength::LowerClosedUpperUnbounded(
result,
)) => {
assert_eq!(result.lower_bound_value(), &1.0);
}
_ => panic!("Expected LowerClosedUpperUnbounded interval"),
}
}
#[test]
fn hull_open_bounded_with_closed_unbounded() {
let open = IntervalOpen::new(Real::try_new(0.0).unwrap(), Real::try_new(2.0).unwrap());
let unbounded = IntervalLowerClosedUpperUnbounded::new(Real::try_new(1.5).unwrap());
let hull = open.hull(&unbounded);
match hull {
Interval::InfiniteLength(IntervalInfiniteLength::LowerOpenUpperUnbounded(
result,
)) => {
assert_eq!(result.lower_bound_value(), &0.0);
}
_ => panic!("Expected LowerOpenUpperUnbounded interval"),
}
}
#[test]
fn hull_singleton_with_bounded() {
let singleton = IntervalSingleton::new(Real::try_new(1.5).unwrap());
let closed =
IntervalClosed::new(Real::try_new(0.0).unwrap(), Real::try_new(1.0).unwrap());
let hull = singleton.hull(&closed);
match hull {
Interval::FiniteLength(IntervalFiniteLength::PositiveLength(
IntervalFinitePositiveLength::Closed(result),
)) => {
assert_eq!(result.lower_bound_value(), &0.0);
assert_eq!(result.upper_bound_value(), &1.5);
}
_ => panic!("Expected closed bounded interval"),
}
}
#[test]
fn hull_singleton_with_unbounded() {
let singleton = IntervalSingleton::new(Real::try_new(5.0).unwrap());
let unbounded = IntervalLowerClosedUpperUnbounded::new(Real::try_new(0.0).unwrap());
let hull = singleton.hull(&unbounded);
match hull {
Interval::InfiniteLength(IntervalInfiniteLength::LowerClosedUpperUnbounded(
result,
)) => {
assert_eq!(result.lower_bound_value(), &0.0);
}
_ => panic!("Expected LowerClosedUpperUnbounded interval"),
}
}
#[test]
fn hull_two_fully_unbounded() {
let unbounded1 = IntervalLowerUnboundedUpperUnbounded::<Real>::new();
let unbounded2 = IntervalLowerUnboundedUpperUnbounded::<Real>::new();
let hull = unbounded1.hull(&unbounded2);
match hull {
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperUnbounded(
_,
)) => {
}
_ => panic!("Expected LowerUnboundedUpperUnbounded interval"),
}
}
#[test]
fn hull_bounded_with_lower_open_upper_unbounded() {
let bounded =
IntervalClosed::new(Real::try_new(0.0).unwrap(), Real::try_new(5.0).unwrap());
let unbounded = IntervalLowerOpenUpperUnbounded::new(Real::try_new(3.0).unwrap());
let hull = bounded.hull(&unbounded);
match hull {
Interval::InfiniteLength(IntervalInfiniteLength::LowerClosedUpperUnbounded(
result,
)) => {
assert_eq!(result.lower_bound_value(), &0.0);
}
_ => panic!("Expected LowerClosedUpperUnbounded interval"),
}
}
#[test]
fn hull_bounded_with_lower_unbounded_upper_open() {
let bounded =
IntervalClosed::new(Real::try_new(-5.0).unwrap(), Real::try_new(0.0).unwrap());
let unbounded = IntervalLowerUnboundedUpperOpen::new(Real::try_new(-2.0).unwrap());
let hull = bounded.hull(&unbounded);
match hull {
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperClosed(
result,
)) => {
assert_eq!(result.upper_bound_value(), &0.0);
}
_ => panic!("Expected LowerUnboundedUpperClosed interval"),
}
}
#[test]
fn hull_opposite_unbounded_closed_disjoint() {
let lower_unbounded =
IntervalLowerUnboundedUpperClosed::new(Real::try_new(-5.0).unwrap());
let upper_unbounded =
IntervalLowerClosedUpperUnbounded::new(Real::try_new(10.0).unwrap());
let hull = lower_unbounded.hull(&upper_unbounded);
match hull {
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperUnbounded(
_,
)) => {
}
_ => panic!("Expected LowerUnboundedUpperUnbounded interval"),
}
}
#[test]
fn hull_opposite_unbounded_mixed_boundaries_gap() {
let lower_unbounded = IntervalLowerUnboundedUpperOpen::new(Real::try_new(0.0).unwrap());
let upper_unbounded =
IntervalLowerClosedUpperUnbounded::new(Real::try_new(5.0).unwrap());
let hull = lower_unbounded.hull(&upper_unbounded);
match hull {
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperUnbounded(
_,
)) => {
}
_ => panic!("Expected LowerUnboundedUpperUnbounded interval"),
}
}
#[test]
fn hull_opposite_unbounded_overlapping() {
let lower_unbounded =
IntervalLowerUnboundedUpperClosed::new(Real::try_new(10.0).unwrap());
let upper_unbounded = IntervalLowerOpenUpperUnbounded::new(Real::try_new(5.0).unwrap());
let hull = lower_unbounded.hull(&upper_unbounded);
match hull {
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperUnbounded(
_,
)) => {
}
_ => panic!("Expected LowerUnboundedUpperUnbounded interval"),
}
}
#[test]
fn hull_opposite_unbounded_both_open() {
let lower_unbounded = IntervalLowerUnboundedUpperOpen::new(Real::try_new(3.0).unwrap());
let upper_unbounded =
IntervalLowerOpenUpperUnbounded::new(Real::try_new(-2.0).unwrap());
let hull = lower_unbounded.hull(&upper_unbounded);
match hull {
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperUnbounded(
_,
)) => {
}
_ => panic!("Expected LowerUnboundedUpperUnbounded interval"),
}
}
#[test]
fn hull_two_open_lower_unbounded() {
let unbounded1 = IntervalLowerOpenUpperUnbounded::new(Real::try_new(5.0).unwrap());
let unbounded2 = IntervalLowerOpenUpperUnbounded::new(Real::try_new(2.0).unwrap());
let hull = unbounded1.hull(&unbounded2);
match hull {
Interval::InfiniteLength(IntervalInfiniteLength::LowerOpenUpperUnbounded(
result,
)) => {
assert_eq!(result.lower_bound_value(), &2.0);
}
_ => panic!("Expected LowerOpenUpperUnbounded interval"),
}
}
#[test]
fn hull_two_open_upper_unbounded() {
let unbounded1 = IntervalLowerUnboundedUpperOpen::new(Real::try_new(3.0).unwrap());
let unbounded2 = IntervalLowerUnboundedUpperOpen::new(Real::try_new(7.0).unwrap());
let hull = unbounded1.hull(&unbounded2);
match hull {
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperOpen(
result,
)) => {
assert_eq!(result.upper_bound_value(), &7.0);
}
_ => panic!("Expected LowerUnboundedUpperOpen interval"),
}
}
#[test]
fn hull_same_bound_closed_vs_open_lower_unbounded() {
let closed_unbounded =
IntervalLowerClosedUpperUnbounded::new(Real::try_new(5.0).unwrap());
let open_unbounded = IntervalLowerOpenUpperUnbounded::new(Real::try_new(5.0).unwrap());
let hull = closed_unbounded.hull(&open_unbounded);
match hull {
Interval::InfiniteLength(IntervalInfiniteLength::LowerClosedUpperUnbounded(
result,
)) => {
assert_eq!(result.lower_bound_value(), &5.0);
}
_ => panic!("Expected LowerClosedUpperUnbounded interval"),
}
}
#[test]
fn hull_same_bound_closed_vs_open_upper_unbounded() {
let closed_unbounded =
IntervalLowerUnboundedUpperClosed::new(Real::try_new(3.0).unwrap());
let open_unbounded = IntervalLowerUnboundedUpperOpen::new(Real::try_new(3.0).unwrap());
let hull = closed_unbounded.hull(&open_unbounded);
match hull {
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperClosed(
result,
)) => {
assert_eq!(result.upper_bound_value(), &3.0);
}
_ => panic!("Expected LowerUnboundedUpperClosed interval"),
}
}
#[test]
fn hull_lower_bounded_upper_unbounded_with_bounded() {
let unbounded = IntervalLowerClosedUpperUnbounded::new(Real::try_new(1.0).unwrap());
let bounded =
IntervalClosed::new(Real::try_new(0.0).unwrap(), Real::try_new(2.0).unwrap());
let hull = unbounded.hull(&bounded);
match hull {
Interval::InfiniteLength(IntervalInfiniteLength::LowerClosedUpperUnbounded(
result,
)) => {
assert_eq!(result.lower_bound_value(), &0.0);
}
_ => panic!("Expected LowerClosedUpperUnbounded interval"),
}
}
#[test]
fn hull_lower_unbounded_upper_bounded_with_bounded() {
let upper_unbounded =
IntervalLowerUnboundedUpperClosed::new(Real::try_new(0.0).unwrap());
let bounded =
IntervalClosed::new(Real::try_new(-2.0).unwrap(), Real::try_new(1.0).unwrap());
let hull = upper_unbounded.hull(&bounded);
match hull {
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperClosed(
result,
)) => {
assert_eq!(result.upper_bound_value(), &1.0);
}
_ => panic!("Expected LowerUnboundedUpperClosed interval"),
}
}
#[test]
fn hull_fully_unbounded_with_bounded() {
let fully_unbounded = IntervalLowerUnboundedUpperUnbounded::<Real>::new();
let bounded =
IntervalClosed::new(Real::try_new(0.0).unwrap(), Real::try_new(10.0).unwrap());
let hull = fully_unbounded.hull(&bounded);
match hull {
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperUnbounded(
_,
)) => {
}
_ => panic!("Expected LowerUnboundedUpperUnbounded interval"),
}
}
#[test]
fn hull_closed_unbounded_with_open_bounded() {
let unbounded = IntervalLowerClosedUpperUnbounded::new(Real::try_new(1.5).unwrap());
let open = IntervalOpen::new(Real::try_new(0.0).unwrap(), Real::try_new(2.0).unwrap());
let hull = unbounded.hull(&open);
match hull {
Interval::InfiniteLength(IntervalInfiniteLength::LowerOpenUpperUnbounded(
result,
)) => {
assert_eq!(result.lower_bound_value(), &0.0);
}
_ => panic!("Expected LowerOpenUpperUnbounded interval"),
}
}
#[test]
fn hull_lower_open_upper_unbounded_with_bounded() {
let unbounded = IntervalLowerOpenUpperUnbounded::new(Real::try_new(3.0).unwrap());
let bounded =
IntervalClosed::new(Real::try_new(0.0).unwrap(), Real::try_new(5.0).unwrap());
let hull = unbounded.hull(&bounded);
match hull {
Interval::InfiniteLength(IntervalInfiniteLength::LowerClosedUpperUnbounded(
result,
)) => {
assert_eq!(result.lower_bound_value(), &0.0);
}
_ => panic!("Expected LowerClosedUpperUnbounded interval"),
}
}
#[test]
fn hull_lower_unbounded_upper_open_with_bounded() {
let unbounded = IntervalLowerUnboundedUpperOpen::new(Real::try_new(-2.0).unwrap());
let bounded =
IntervalClosed::new(Real::try_new(-5.0).unwrap(), Real::try_new(0.0).unwrap());
let hull = unbounded.hull(&bounded);
match hull {
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperClosed(
result,
)) => {
assert_eq!(result.upper_bound_value(), &0.0);
}
_ => panic!("Expected LowerUnboundedUpperClosed interval"),
}
}
#[test]
fn hull_opposite_unbounded_closed_disjoint_reverse() {
let upper_unbounded =
IntervalLowerClosedUpperUnbounded::new(Real::try_new(10.0).unwrap());
let lower_unbounded =
IntervalLowerUnboundedUpperClosed::new(Real::try_new(-5.0).unwrap());
let hull = upper_unbounded.hull(&lower_unbounded);
match hull {
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperUnbounded(
_,
)) => {
}
_ => panic!("Expected LowerUnboundedUpperUnbounded interval"),
}
}
#[test]
fn hull_opposite_unbounded_mixed_boundaries_gap_reverse() {
let upper_unbounded =
IntervalLowerClosedUpperUnbounded::new(Real::try_new(5.0).unwrap());
let lower_unbounded = IntervalLowerUnboundedUpperOpen::new(Real::try_new(0.0).unwrap());
let hull = upper_unbounded.hull(&lower_unbounded);
match hull {
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperUnbounded(
_,
)) => {
}
_ => panic!("Expected LowerUnboundedUpperUnbounded interval"),
}
}
#[test]
fn hull_opposite_unbounded_overlapping_reverse() {
let upper_unbounded = IntervalLowerOpenUpperUnbounded::new(Real::try_new(5.0).unwrap());
let lower_unbounded =
IntervalLowerUnboundedUpperClosed::new(Real::try_new(10.0).unwrap());
let hull = upper_unbounded.hull(&lower_unbounded);
match hull {
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperUnbounded(
_,
)) => {
}
_ => panic!("Expected LowerUnboundedUpperUnbounded interval"),
}
}
#[test]
fn hull_opposite_unbounded_both_open_reverse() {
let upper_unbounded =
IntervalLowerOpenUpperUnbounded::new(Real::try_new(-2.0).unwrap());
let lower_unbounded = IntervalLowerUnboundedUpperOpen::new(Real::try_new(3.0).unwrap());
let hull = upper_unbounded.hull(&lower_unbounded);
match hull {
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperUnbounded(
_,
)) => {
}
_ => panic!("Expected LowerUnboundedUpperUnbounded interval"),
}
}
#[test]
fn hull_finite_positive_closed_with_bounded() {
let interval1: Interval<Real> = Interval::FiniteLength(
IntervalFiniteLength::PositiveLength(IntervalFinitePositiveLength::Closed(
IntervalClosed::new(Real::try_new(0.0).unwrap(), Real::try_new(2.0).unwrap()),
)),
);
let interval2: Interval<Real> = Interval::from(IntervalClosed::new(
Real::try_new(1.0).unwrap(),
Real::try_new(3.0).unwrap(),
));
let hull = interval1.hull(&interval2);
match hull {
Interval::FiniteLength(IntervalFiniteLength::PositiveLength(
IntervalFinitePositiveLength::Closed(result),
)) => {
assert_eq!(result.lower_bound_value(), &0.0);
assert_eq!(result.upper_bound_value(), &3.0);
}
_ => panic!("Expected closed bounded interval"),
}
}
#[test]
fn hull_finite_positive_open_with_closed() {
let interval1: Interval<Real> = Interval::FiniteLength(
IntervalFiniteLength::PositiveLength(IntervalFinitePositiveLength::Open(
IntervalOpen::new(Real::try_new(0.0).unwrap(), Real::try_new(2.0).unwrap()),
)),
);
let interval2: Interval<Real> = Interval::from(IntervalClosed::new(
Real::try_new(1.0).unwrap(),
Real::try_new(3.0).unwrap(),
));
let hull = interval1.hull(&interval2);
match hull {
Interval::FiniteLength(IntervalFiniteLength::PositiveLength(
IntervalFinitePositiveLength::LowerOpenUpperClosed(result),
)) => {
assert_eq!(result.lower_bound_value(), &0.0);
assert_eq!(result.upper_bound_value(), &3.0);
}
_ => panic!("Expected lower open, upper closed interval"),
}
}
#[test]
fn hull_finite_positive_half_open_with_open() {
let interval1: Interval<Real> =
Interval::FiniteLength(IntervalFiniteLength::PositiveLength(
IntervalFinitePositiveLength::LowerClosedUpperOpen(
IntervalLowerClosedUpperOpen::new(
Real::try_new(0.0).unwrap(),
Real::try_new(2.0).unwrap(),
),
),
));
let interval2: Interval<Real> = Interval::from(IntervalOpen::new(
Real::try_new(-1.0).unwrap(),
Real::try_new(1.0).unwrap(),
));
let hull = interval1.hull(&interval2);
match hull {
Interval::FiniteLength(IntervalFiniteLength::PositiveLength(
IntervalFinitePositiveLength::Open(result),
)) => {
assert_eq!(result.lower_bound_value(), &-1.0);
assert_eq!(result.upper_bound_value(), &2.0);
}
_ => panic!("Expected open interval"),
}
}
#[test]
fn hull_finite_zero_length_with_bounded() {
let interval1: Interval<Real> =
Interval::FiniteLength(IntervalFiniteLength::ZeroLength(IntervalSingleton::new(
Real::try_new(5.0).unwrap(),
)));
let interval2: Interval<Real> = Interval::from(IntervalClosed::new(
Real::try_new(0.0).unwrap(),
Real::try_new(3.0).unwrap(),
));
let hull = interval1.hull(&interval2);
match hull {
Interval::FiniteLength(IntervalFiniteLength::PositiveLength(
IntervalFinitePositiveLength::Closed(result),
)) => {
assert_eq!(result.lower_bound_value(), &0.0);
assert_eq!(result.upper_bound_value(), &5.0);
}
_ => panic!("Expected closed bounded interval"),
}
}
#[test]
fn hull_finite_length_with_unbounded() {
let interval1: Interval<Real> = Interval::FiniteLength(
IntervalFiniteLength::PositiveLength(IntervalFinitePositiveLength::Closed(
IntervalClosed::new(Real::try_new(0.0).unwrap(), Real::try_new(5.0).unwrap()),
)),
);
let interval2: Interval<Real> = Interval::from(IntervalLowerClosedUpperUnbounded::new(
Real::try_new(3.0).unwrap(),
));
let hull = interval1.hull(&interval2);
match hull {
Interval::InfiniteLength(IntervalInfiniteLength::LowerClosedUpperUnbounded(
result,
)) => {
assert_eq!(result.lower_bound_value(), &0.0);
}
_ => panic!("Expected lower closed, upper unbounded interval"),
}
}
#[test]
fn hull_finite_positive_length_disjoint() {
let interval1: Interval<Real> = Interval::FiniteLength(
IntervalFiniteLength::PositiveLength(IntervalFinitePositiveLength::Closed(
IntervalClosed::new(Real::try_new(0.0).unwrap(), Real::try_new(2.0).unwrap()),
)),
);
let interval2: Interval<Real> = Interval::FiniteLength(
IntervalFiniteLength::PositiveLength(IntervalFinitePositiveLength::Closed(
IntervalClosed::new(Real::try_new(5.0).unwrap(), Real::try_new(7.0).unwrap()),
)),
);
let hull = interval1.hull(&interval2);
match hull {
Interval::FiniteLength(IntervalFiniteLength::PositiveLength(
IntervalFinitePositiveLength::Closed(result),
)) => {
assert_eq!(result.lower_bound_value(), &0.0);
assert_eq!(result.upper_bound_value(), &7.0);
}
_ => panic!("Expected closed bounded interval"),
}
}
#[test]
fn hull_two_finite_zero_length() {
let interval1: Interval<Real> =
Interval::FiniteLength(IntervalFiniteLength::ZeroLength(IntervalSingleton::new(
Real::try_new(2.0).unwrap(),
)));
let interval2: Interval<Real> =
Interval::FiniteLength(IntervalFiniteLength::ZeroLength(IntervalSingleton::new(
Real::try_new(5.0).unwrap(),
)));
let hull = interval1.hull(&interval2);
match hull {
Interval::FiniteLength(IntervalFiniteLength::PositiveLength(
IntervalFinitePositiveLength::Closed(result),
)) => {
assert_eq!(result.lower_bound_value(), &2.0);
assert_eq!(result.upper_bound_value(), &5.0);
}
_ => panic!("Expected closed bounded interval"),
}
}
#[test]
fn hull_finite_length_with_fully_unbounded() {
let interval1: Interval<Real> = Interval::FiniteLength(
IntervalFiniteLength::PositiveLength(IntervalFinitePositiveLength::Open(
IntervalOpen::new(Real::try_new(0.0).unwrap(), Real::try_new(1.0).unwrap()),
)),
);
let interval2: Interval<Real> =
Interval::from(IntervalLowerUnboundedUpperUnbounded::<Real>::new());
let hull = interval1.hull(&interval2);
match hull {
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperUnbounded(
_,
)) => {
}
_ => panic!("Expected fully unbounded interval"),
}
}
#[test]
fn hull_finite_positive_mixed_boundaries() {
let interval1 = IntervalFiniteLength::PositiveLength(
IntervalFinitePositiveLength::LowerClosedUpperOpen(
IntervalLowerClosedUpperOpen::new(
Real::try_new(0.0).unwrap(),
Real::try_new(3.0).unwrap(),
),
),
);
let interval2: Interval<Real> =
Interval::FiniteLength(IntervalFiniteLength::PositiveLength(
IntervalFinitePositiveLength::LowerOpenUpperClosed(
IntervalLowerOpenUpperClosed::new(
Real::try_new(2.0).unwrap(),
Real::try_new(5.0).unwrap(),
),
),
));
let hull = interval1.hull(&interval2);
match hull {
Interval::FiniteLength(IntervalFiniteLength::PositiveLength(
IntervalFinitePositiveLength::Closed(result),
)) => {
assert_eq!(result.lower_bound_value(), &0.0);
assert_eq!(result.upper_bound_value(), &5.0);
}
_ => panic!("Expected closed bounded interval"),
}
}
#[test]
fn hull_infinite_lower_closed_upper_unbounded_with_bounded() {
let interval1 = IntervalInfiniteLength::LowerClosedUpperUnbounded(
IntervalLowerClosedUpperUnbounded::new(Real::try_new(5.0).unwrap()),
);
let interval2: Interval<Real> = Interval::from(IntervalClosed::new(
Real::try_new(0.0).unwrap(),
Real::try_new(3.0).unwrap(),
));
let hull = interval1.hull(&interval2);
match hull {
Interval::InfiniteLength(IntervalInfiniteLength::LowerClosedUpperUnbounded(
result,
)) => {
assert_eq!(result.lower_bound_value(), &0.0);
}
_ => panic!("Expected LowerClosedUpperUnbounded interval"),
}
}
#[test]
fn hull_infinite_lower_open_upper_unbounded_with_bounded() {
let interval1 = IntervalInfiniteLength::LowerOpenUpperUnbounded(
IntervalLowerOpenUpperUnbounded::new(Real::try_new(2.0).unwrap()),
);
let interval2: Interval<Real> = Interval::from(IntervalClosed::new(
Real::try_new(0.0).unwrap(),
Real::try_new(5.0).unwrap(),
));
let hull = interval1.hull(&interval2);
match hull {
Interval::InfiniteLength(IntervalInfiniteLength::LowerClosedUpperUnbounded(
result,
)) => {
assert_eq!(result.lower_bound_value(), &0.0);
}
_ => panic!("Expected LowerClosedUpperUnbounded interval"),
}
}
#[test]
fn hull_infinite_lower_unbounded_upper_closed_with_bounded() {
let interval1: Interval<Real> =
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperClosed(
IntervalLowerUnboundedUpperClosed::new(Real::try_new(0.0).unwrap()),
));
let interval2: Interval<Real> = Interval::from(IntervalClosed::new(
Real::try_new(2.0).unwrap(),
Real::try_new(5.0).unwrap(),
));
let hull = interval1.hull(&interval2);
match hull {
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperClosed(
result,
)) => {
assert_eq!(result.upper_bound_value(), &5.0);
}
_ => panic!("Expected LowerUnboundedUpperClosed interval"),
}
}
#[test]
fn hull_infinite_lower_unbounded_upper_open_with_bounded() {
let interval1: Interval<Real> =
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperOpen(
IntervalLowerUnboundedUpperOpen::new(Real::try_new(3.0).unwrap()),
));
let interval2: Interval<Real> = Interval::from(IntervalOpen::new(
Real::try_new(-2.0).unwrap(),
Real::try_new(10.0).unwrap(),
));
let hull = interval1.hull(&interval2);
match hull {
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperOpen(
result,
)) => {
assert_eq!(result.upper_bound_value(), &10.0);
}
_ => panic!("Expected LowerUnboundedUpperOpen interval"),
}
}
#[test]
fn hull_infinite_fully_unbounded_with_bounded() {
let interval1: Interval<Real> =
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperUnbounded(
IntervalLowerUnboundedUpperUnbounded::<Real>::new(),
));
let interval2: Interval<Real> = Interval::from(IntervalClosed::new(
Real::try_new(0.0).unwrap(),
Real::try_new(10.0).unwrap(),
));
let hull = interval1.hull(&interval2);
match hull {
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperUnbounded(
_,
)) => {
}
_ => panic!("Expected LowerUnboundedUpperUnbounded interval"),
}
}
#[test]
fn hull_infinite_opposite_directions() {
let interval1: Interval<Real> =
Interval::InfiniteLength(IntervalInfiniteLength::LowerClosedUpperUnbounded(
IntervalLowerClosedUpperUnbounded::new(Real::try_new(5.0).unwrap()),
));
let interval2: Interval<Real> =
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperClosed(
IntervalLowerUnboundedUpperClosed::new(Real::try_new(0.0).unwrap()),
));
let hull = interval1.hull(&interval2);
match hull {
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperUnbounded(
_,
)) => {
}
_ => panic!("Expected LowerUnboundedUpperUnbounded interval"),
}
}
#[test]
fn hull_infinite_with_finite_zero_length() {
let interval1: Interval<Real> =
Interval::InfiniteLength(IntervalInfiniteLength::LowerClosedUpperUnbounded(
IntervalLowerClosedUpperUnbounded::new(Real::try_new(5.0).unwrap()),
));
let interval2: Interval<Real> =
Interval::FiniteLength(IntervalFiniteLength::ZeroLength(IntervalSingleton::new(
Real::try_new(2.0).unwrap(),
)));
let hull = interval1.hull(&interval2);
match hull {
Interval::InfiniteLength(IntervalInfiniteLength::LowerClosedUpperUnbounded(
result,
)) => {
assert_eq!(result.lower_bound_value(), &2.0);
}
_ => panic!("Expected LowerClosedUpperUnbounded interval"),
}
}
#[test]
fn hull_infinite_same_direction_open_vs_closed() {
let interval1: Interval<Real> =
Interval::InfiniteLength(IntervalInfiniteLength::LowerClosedUpperUnbounded(
IntervalLowerClosedUpperUnbounded::new(Real::try_new(5.0).unwrap()),
));
let interval2: Interval<Real> =
Interval::InfiniteLength(IntervalInfiniteLength::LowerOpenUpperUnbounded(
IntervalLowerOpenUpperUnbounded::new(Real::try_new(5.0).unwrap()),
));
let hull = interval1.hull(&interval2);
match hull {
Interval::InfiniteLength(IntervalInfiniteLength::LowerClosedUpperUnbounded(
result,
)) => {
assert_eq!(result.lower_bound_value(), &5.0);
}
_ => panic!("Expected LowerClosedUpperUnbounded interval"),
}
}
#[test]
fn hull_infinite_disjoint_regions() {
let interval1: Interval<Real> =
Interval::InfiniteLength(IntervalInfiniteLength::LowerClosedUpperUnbounded(
IntervalLowerClosedUpperUnbounded::new(Real::try_new(10.0).unwrap()),
));
let interval2: Interval<Real> =
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperOpen(
IntervalLowerUnboundedUpperOpen::new(Real::try_new(5.0).unwrap()),
));
let hull = interval1.hull(&interval2);
match hull {
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperUnbounded(
_,
)) => {
}
_ => panic!("Expected LowerUnboundedUpperUnbounded interval"),
}
}
#[test]
fn hull_infinite_same_direction_different_bounds() {
let interval1: Interval<Real> =
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperClosed(
IntervalLowerUnboundedUpperClosed::new(Real::try_new(10.0).unwrap()),
));
let interval2: Interval<Real> =
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperClosed(
IntervalLowerUnboundedUpperClosed::new(Real::try_new(5.0).unwrap()),
));
let hull = interval1.hull(&interval2);
match hull {
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperClosed(
result,
)) => {
assert_eq!(result.upper_bound_value(), &10.0);
}
_ => panic!("Expected LowerUnboundedUpperClosed interval"),
}
}
}
mod try_from_conversions {
use super::*;
use num_valid::RealNative64StrictFiniteInDebug;
use try_create::TryNew;
type Real = RealNative64StrictFiniteInDebug;
#[test]
fn try_from_interval_to_finite_length_positive() {
let interval: Interval<Real> = Interval::from(IntervalClosed::new(
Real::try_new(0.0).unwrap(),
Real::try_new(5.0).unwrap(),
));
let result = IntervalFiniteLength::try_from(interval);
assert!(result.is_ok());
let finite = result.unwrap();
match finite {
IntervalFiniteLength::PositiveLength(positive) => {
assert_eq!(positive.lower_bound_value(), &Real::try_new(0.0).unwrap());
assert_eq!(positive.upper_bound_value(), &Real::try_new(5.0).unwrap());
}
_ => panic!("Expected PositiveLength variant"),
}
}
#[test]
fn try_from_interval_to_finite_length_zero() {
let interval: Interval<Real> =
Interval::from(IntervalSingleton::new(Real::try_new(3.0).unwrap()));
let result = IntervalFiniteLength::try_from(interval);
assert!(result.is_ok());
let finite = result.unwrap();
match finite {
IntervalFiniteLength::ZeroLength(singleton) => {
assert_eq!(singleton.value(), &Real::try_new(3.0).unwrap());
}
_ => panic!("Expected ZeroLength variant"),
}
}
#[test]
fn try_from_interval_to_finite_length_fails_for_infinite() {
let interval: Interval<Real> =
Interval::InfiniteLength(IntervalInfiniteLength::LowerClosedUpperUnbounded(
IntervalLowerClosedUpperUnbounded::new(Real::try_new(0.0).unwrap()),
));
let result = IntervalFiniteLength::<Real>::try_from(interval);
assert!(result.is_err());
match result.unwrap_err() {
ErrorsIntervalConversion::NotIntervalFiniteLength { .. } => {
}
_ => panic!("Expected NotIntervalFiniteLength error"),
}
}
#[test]
fn try_from_interval_to_finite_positive_closed() {
let interval: Interval<Real> = Interval::from(IntervalClosed::new(
Real::try_new(1.0).unwrap(),
Real::try_new(10.0).unwrap(),
));
let result = IntervalFinitePositiveLength::try_from(interval);
assert!(result.is_ok());
let positive = result.unwrap();
match positive {
IntervalFinitePositiveLength::Closed(_) => {
assert_eq!(positive.lower_bound_value(), &Real::try_new(1.0).unwrap());
assert_eq!(positive.upper_bound_value(), &Real::try_new(10.0).unwrap());
}
_ => panic!("Expected Closed variant"),
}
}
#[test]
fn try_from_interval_to_finite_positive_open() {
let interval: Interval<Real> = Interval::from(IntervalOpen::new(
Real::try_new(0.0).unwrap(),
Real::try_new(5.0).unwrap(),
));
let result = IntervalFinitePositiveLength::try_from(interval);
assert!(result.is_ok());
let positive = result.unwrap();
match positive {
IntervalFinitePositiveLength::Open(_) => {}
_ => panic!("Expected Open variant"),
}
}
#[test]
fn try_from_interval_to_finite_positive_fails_for_singleton() {
let interval: Interval<Real> =
Interval::from(IntervalSingleton::new(Real::try_new(5.0).unwrap()));
let result = IntervalFinitePositiveLength::<Real>::try_from(interval);
assert!(result.is_err());
match result.unwrap_err() {
ErrorsIntervalConversion::NotIntervalPositiveLength { .. } => {
}
_ => panic!("Expected NotIntervalPositiveLength error"),
}
}
#[test]
fn try_from_interval_to_finite_positive_fails_for_infinite() {
let interval: Interval<Real> =
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperClosed(
IntervalLowerUnboundedUpperClosed::new(Real::try_new(10.0).unwrap()),
));
let result = IntervalFinitePositiveLength::<Real>::try_from(interval);
assert!(result.is_err());
}
#[test]
fn try_from_interval_to_infinite_length_lower_unbounded() {
let interval: Interval<Real> =
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperClosed(
IntervalLowerUnboundedUpperClosed::new(Real::try_new(5.0).unwrap()),
));
let result = IntervalInfiniteLength::try_from(interval);
assert!(result.is_ok());
let infinite = result.unwrap();
match infinite {
IntervalInfiniteLength::LowerUnboundedUpperClosed(interval) => {
assert_eq!(interval.upper_bound_value(), &Real::try_new(5.0).unwrap());
}
_ => panic!("Expected LowerUnboundedUpperClosed variant"),
}
}
#[test]
fn try_from_interval_to_infinite_length_upper_unbounded() {
let interval: Interval<Real> =
Interval::InfiniteLength(IntervalInfiniteLength::LowerClosedUpperUnbounded(
IntervalLowerClosedUpperUnbounded::new(Real::try_new(0.0).unwrap()),
));
let result = IntervalInfiniteLength::try_from(interval);
assert!(result.is_ok());
let infinite = result.unwrap();
match infinite {
IntervalInfiniteLength::LowerClosedUpperUnbounded(interval) => {
assert_eq!(interval.lower_bound_value(), &Real::try_new(0.0).unwrap());
}
_ => panic!("Expected LowerClosedUpperUnbounded variant"),
}
}
#[test]
fn try_from_interval_to_infinite_fails_for_finite() {
let interval: Interval<Real> = Interval::from(IntervalClosed::new(
Real::try_new(0.0).unwrap(),
Real::try_new(10.0).unwrap(),
));
let result = IntervalInfiniteLength::<Real>::try_from(interval);
assert!(result.is_err());
match result.unwrap_err() {
ErrorsIntervalConversion::NotIntervalInfiniteLength { .. } => {
}
_ => panic!("Expected NotIntervalInfiniteLength error"),
}
}
#[test]
fn try_from_interval_to_closed() {
let interval: Interval<Real> = Interval::from(IntervalClosed::new(
Real::try_new(2.0).unwrap(),
Real::try_new(8.0).unwrap(),
));
let result = IntervalClosed::<Real>::try_from(interval);
assert!(result.is_ok());
let closed = result.unwrap();
assert_eq!(closed.lower_bound_value(), &Real::try_new(2.0).unwrap());
assert_eq!(closed.upper_bound_value(), &Real::try_new(8.0).unwrap());
}
#[test]
fn try_from_interval_to_closed_fails_for_open() {
let interval: Interval<Real> = Interval::from(IntervalOpen::new(
Real::try_new(2.0).unwrap(),
Real::try_new(8.0).unwrap(),
));
let result = IntervalClosed::<Real>::try_from(interval);
assert!(result.is_err());
match result.unwrap_err() {
ErrorsIntervalConversion::NotIntervalClosed { .. } => {
}
_ => panic!("Expected NotIntervalClosed error"),
}
}
#[test]
fn try_from_interval_to_closed_fails_for_singleton() {
let interval: Interval<Real> =
Interval::from(IntervalSingleton::new(Real::try_new(5.0).unwrap()));
let result = IntervalClosed::<Real>::try_from(interval);
assert!(result.is_err());
}
#[test]
fn try_from_interval_to_open() {
let interval: Interval<Real> = Interval::from(IntervalOpen::new(
Real::try_new(1.0).unwrap(),
Real::try_new(9.0).unwrap(),
));
let result = IntervalOpen::<Real>::try_from(interval);
assert!(result.is_ok());
let open = result.unwrap();
assert_eq!(open.lower_bound_value(), &Real::try_new(1.0).unwrap());
assert_eq!(open.upper_bound_value(), &Real::try_new(9.0).unwrap());
}
#[test]
fn try_from_interval_to_open_fails_for_closed() {
let interval: Interval<Real> = Interval::from(IntervalClosed::new(
Real::try_new(1.0).unwrap(),
Real::try_new(9.0).unwrap(),
));
let result = IntervalOpen::<Real>::try_from(interval);
assert!(result.is_err());
match result.unwrap_err() {
ErrorsIntervalConversion::NotIntervalOpen { .. } => {
}
_ => panic!("Expected NotIntervalOpen error"),
}
}
#[test]
fn try_from_interval_to_lower_open_upper_closed() {
let interval: Interval<Real> = Interval::from(IntervalLowerOpenUpperClosed::new(
Real::try_new(0.0).unwrap(),
Real::try_new(5.0).unwrap(),
));
let result = IntervalLowerOpenUpperClosed::<Real>::try_from(interval);
assert!(result.is_ok());
let half_open = result.unwrap();
assert!(!half_open.is_lower_bound_closed());
assert!(half_open.is_upper_bound_closed());
}
#[test]
fn try_from_interval_to_lower_open_upper_closed_fails() {
let interval: Interval<Real> = Interval::from(IntervalLowerClosedUpperOpen::new(
Real::try_new(0.0).unwrap(),
Real::try_new(5.0).unwrap(),
));
let result = IntervalLowerOpenUpperClosed::<Real>::try_from(interval);
assert!(result.is_err());
match result.unwrap_err() {
ErrorsIntervalConversion::NotIntervalLowerOpenUpperClosed { .. } => {
}
_ => panic!("Expected NotIntervalLowerOpenUpperClosed error"),
}
}
#[test]
fn try_from_interval_to_lower_closed_upper_open() {
let interval: Interval<Real> = Interval::from(IntervalLowerClosedUpperOpen::new(
Real::try_new(1.0).unwrap(),
Real::try_new(10.0).unwrap(),
));
let result = IntervalLowerClosedUpperOpen::<Real>::try_from(interval);
assert!(result.is_ok());
let half_open = result.unwrap();
assert!(half_open.is_lower_bound_closed());
assert!(!half_open.is_upper_bound_closed());
}
#[test]
fn try_from_interval_to_lower_closed_upper_open_fails() {
let interval: Interval<Real> = Interval::from(IntervalLowerOpenUpperClosed::new(
Real::try_new(1.0).unwrap(),
Real::try_new(10.0).unwrap(),
));
let result = IntervalLowerClosedUpperOpen::<Real>::try_from(interval);
assert!(result.is_err());
match result.unwrap_err() {
ErrorsIntervalConversion::NotIntervalLowerClosedUpperOpen { .. } => {
}
_ => panic!("Expected NotIntervalLowerClosedUpperOpen error"),
}
}
#[test]
fn try_from_finite_positive_to_closed() {
let positive_length = IntervalFinitePositiveLength::Closed(IntervalClosed::new(
Real::try_new(0.0).unwrap(),
Real::try_new(5.0).unwrap(),
));
let result = IntervalClosed::<Real>::try_from(positive_length);
assert!(result.is_ok());
}
#[test]
fn try_from_finite_positive_to_closed_fails() {
let positive_length = IntervalFinitePositiveLength::Open(IntervalOpen::new(
Real::try_new(0.0).unwrap(),
Real::try_new(5.0).unwrap(),
));
let result = IntervalClosed::<Real>::try_from(positive_length);
assert!(result.is_err());
}
#[test]
fn try_from_finite_positive_to_open() {
let positive_length = IntervalFinitePositiveLength::Open(IntervalOpen::new(
Real::try_new(1.0).unwrap(),
Real::try_new(9.0).unwrap(),
));
let result = IntervalOpen::<Real>::try_from(positive_length);
assert!(result.is_ok());
}
#[test]
fn try_from_finite_positive_to_lower_open_upper_closed() {
let positive_length = IntervalFinitePositiveLength::LowerOpenUpperClosed(
IntervalLowerOpenUpperClosed::new(
Real::try_new(2.0).unwrap(),
Real::try_new(7.0).unwrap(),
),
);
let result = IntervalLowerOpenUpperClosed::<Real>::try_from(positive_length);
assert!(result.is_ok());
}
#[test]
fn try_from_finite_positive_to_lower_closed_upper_open() {
let positive_length = IntervalFinitePositiveLength::LowerClosedUpperOpen(
IntervalLowerClosedUpperOpen::new(
Real::try_new(3.0).unwrap(),
Real::try_new(8.0).unwrap(),
),
);
let result = IntervalLowerClosedUpperOpen::<Real>::try_from(positive_length);
assert!(result.is_ok());
}
#[test]
fn try_from_interval_to_singleton() {
let interval: Interval<Real> =
Interval::from(IntervalSingleton::new(Real::try_new(7.0).unwrap()));
let result = IntervalSingleton::<Real>::try_from(interval);
assert!(result.is_ok());
let singleton = result.unwrap();
assert_eq!(singleton.value(), &Real::try_new(7.0).unwrap());
}
#[test]
fn try_from_interval_to_singleton_fails_for_positive() {
let interval: Interval<Real> = Interval::from(IntervalClosed::new(
Real::try_new(0.0).unwrap(),
Real::try_new(5.0).unwrap(),
));
let result = IntervalSingleton::<Real>::try_from(interval);
assert!(result.is_err());
match result.unwrap_err() {
ErrorsIntervalConversion::NotIntervalSingleton { .. } => {
}
_ => panic!("Expected NotIntervalSingleton error"),
}
}
#[test]
fn try_from_interval_to_singleton_fails_for_infinite() {
let interval: Interval<Real> =
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperUnbounded(
IntervalLowerUnboundedUpperUnbounded::new(),
));
let result = IntervalSingleton::<Real>::try_from(interval);
assert!(result.is_err());
}
#[test]
fn try_from_interval_to_lower_unbounded_upper_closed() {
let interval: Interval<Real> =
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperClosed(
IntervalLowerUnboundedUpperClosed::new(Real::try_new(10.0).unwrap()),
));
let result = IntervalLowerUnboundedUpperClosed::<Real>::try_from(interval);
assert!(result.is_ok());
let unbounded = result.unwrap();
assert_eq!(unbounded.upper_bound_value(), &Real::try_new(10.0).unwrap());
}
#[test]
fn try_from_interval_to_lower_unbounded_upper_closed_fails() {
let interval: Interval<Real> =
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperOpen(
IntervalLowerUnboundedUpperOpen::new(Real::try_new(10.0).unwrap()),
));
let result = IntervalLowerUnboundedUpperClosed::<Real>::try_from(interval);
assert!(result.is_err());
match result.unwrap_err() {
ErrorsIntervalConversion::NotIntervalLowerUnboundedUpperClosed { .. } => {
}
_ => panic!("Expected NotIntervalLowerUnboundedUpperClosed error"),
}
}
#[test]
fn try_from_interval_to_lower_unbounded_upper_open() {
let interval: Interval<Real> =
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperOpen(
IntervalLowerUnboundedUpperOpen::new(Real::try_new(5.0).unwrap()),
));
let result = IntervalLowerUnboundedUpperOpen::<Real>::try_from(interval);
assert!(result.is_ok());
let unbounded = result.unwrap();
assert_eq!(unbounded.upper_bound_value(), &Real::try_new(5.0).unwrap());
}
#[test]
fn try_from_interval_to_lower_unbounded_upper_open_fails() {
let interval: Interval<Real> = Interval::from(IntervalClosed::new(
Real::try_new(0.0).unwrap(),
Real::try_new(5.0).unwrap(),
));
let result = IntervalLowerUnboundedUpperOpen::<Real>::try_from(interval);
assert!(result.is_err());
}
#[test]
fn try_from_interval_to_lower_closed_upper_unbounded() {
let interval: Interval<Real> =
Interval::InfiniteLength(IntervalInfiniteLength::LowerClosedUpperUnbounded(
IntervalLowerClosedUpperUnbounded::new(Real::try_new(0.0).unwrap()),
));
let result = IntervalLowerClosedUpperUnbounded::<Real>::try_from(interval);
assert!(result.is_ok());
let unbounded = result.unwrap();
assert_eq!(unbounded.lower_bound_value(), &Real::try_new(0.0).unwrap());
}
#[test]
fn try_from_interval_to_lower_closed_upper_unbounded_fails() {
let interval: Interval<Real> =
Interval::InfiniteLength(IntervalInfiniteLength::LowerOpenUpperUnbounded(
IntervalLowerOpenUpperUnbounded::new(Real::try_new(0.0).unwrap()),
));
let result = IntervalLowerClosedUpperUnbounded::<Real>::try_from(interval);
assert!(result.is_err());
match result.unwrap_err() {
ErrorsIntervalConversion::NotIntervalLowerClosedUpperUnbounded { .. } => {
}
_ => panic!("Expected NotIntervalLowerClosedUpperUnbounded error"),
}
}
#[test]
fn try_from_interval_to_lower_open_upper_unbounded() {
let interval: Interval<Real> =
Interval::InfiniteLength(IntervalInfiniteLength::LowerOpenUpperUnbounded(
IntervalLowerOpenUpperUnbounded::new(Real::try_new(3.0).unwrap()),
));
let result = IntervalLowerOpenUpperUnbounded::<Real>::try_from(interval);
assert!(result.is_ok());
let unbounded = result.unwrap();
assert_eq!(unbounded.lower_bound_value(), &Real::try_new(3.0).unwrap());
}
#[test]
fn try_from_interval_to_lower_open_upper_unbounded_fails() {
let interval: Interval<Real> = Interval::from(IntervalOpen::new(
Real::try_new(3.0).unwrap(),
Real::try_new(10.0).unwrap(),
));
let result = IntervalLowerOpenUpperUnbounded::<Real>::try_from(interval);
assert!(result.is_err());
match result.unwrap_err() {
ErrorsIntervalConversion::NotIntervalInfiniteLength { .. } => {
}
ErrorsIntervalConversion::NotIntervalLowerOpenUpperUnbounded { .. } => {
}
_ => panic!(
"Expected NotIntervalInfiniteLength or NotIntervalLowerOpenUpperUnbounded error"
),
}
}
#[test]
fn round_trip_closed() {
let original =
IntervalClosed::new(Real::try_new(1.0).unwrap(), Real::try_new(5.0).unwrap());
let interval: Interval<Real> = original.clone().into();
let result = IntervalClosed::<Real>::try_from(interval).unwrap();
assert_eq!(original, result);
}
#[test]
fn round_trip_open() {
let original =
IntervalOpen::new(Real::try_new(2.0).unwrap(), Real::try_new(8.0).unwrap());
let interval: Interval<Real> = original.clone().into();
let result = IntervalOpen::<Real>::try_from(interval).unwrap();
assert_eq!(original, result);
}
#[test]
fn round_trip_singleton() {
let original = IntervalSingleton::new(Real::try_new(4.0).unwrap());
let interval: Interval<Real> = original.clone().into();
let result = IntervalSingleton::<Real>::try_from(interval).unwrap();
assert_eq!(original.value(), result.value());
}
#[test]
fn round_trip_lower_unbounded_upper_closed() {
let original = IntervalLowerUnboundedUpperClosed::new(Real::try_new(10.0).unwrap());
let interval: Interval<Real> = Interval::from(original.clone());
let result = IntervalLowerUnboundedUpperClosed::<Real>::try_from(interval).unwrap();
assert_eq!(original.upper_bound_value(), result.upper_bound_value());
}
#[test]
fn error_contains_interval_info() {
let interval: Interval<Real> = Interval::from(IntervalOpen::new(
Real::try_new(0.0).unwrap(),
Real::try_new(5.0).unwrap(),
));
let result = IntervalClosed::<Real>::try_from(interval.clone());
assert!(result.is_err());
let error = result.unwrap_err();
let error_string = format!("{:?}", error);
assert!(error_string.contains("NotIntervalClosed"));
}
#[test]
fn chained_conversion_interval_to_finite_to_closed() {
let interval: Interval<Real> = Interval::from(IntervalClosed::new(
Real::try_new(1.0).unwrap(),
Real::try_new(10.0).unwrap(),
));
let finite = IntervalFiniteLength::try_from(interval).unwrap();
let interval2: Interval<Real> = finite.into();
let closed = IntervalClosed::<Real>::try_from(interval2).unwrap();
assert_eq!(closed.lower_bound_value(), &Real::try_new(1.0).unwrap());
assert_eq!(closed.upper_bound_value(), &Real::try_new(10.0).unwrap());
}
}
mod new_functions {
use super::*;
#[test]
fn test_new_lower_unbounded_closed() {
use crate::bounds::{UpperBoundClosed, UpperBoundRuntime};
let upper = UpperBoundClosed::new(10.0);
let upper_runtime: UpperBoundRuntime<f64> = upper.into();
let interval = IntervalInfiniteLength::new_lower_unbounded(upper_runtime);
match interval {
IntervalInfiniteLength::LowerUnboundedUpperClosed(result) => {
assert_eq!(result.upper_bound_value(), &10.0);
}
_ => panic!("Expected LowerUnboundedUpperClosed variant"),
}
}
#[test]
fn test_new_lower_unbounded_open() {
use crate::bounds::{UpperBoundOpen, UpperBoundRuntime};
let upper = UpperBoundOpen::new(10.0);
let upper_runtime: UpperBoundRuntime<f64> = upper.into();
let interval = IntervalInfiniteLength::new_lower_unbounded(upper_runtime);
match interval {
IntervalInfiniteLength::LowerUnboundedUpperOpen(result) => {
assert_eq!(result.upper_bound_value(), &10.0);
}
_ => panic!("Expected LowerUnboundedUpperOpen variant"),
}
}
#[test]
fn test_new_upper_unbounded_closed() {
use crate::bounds::{LowerBoundClosed, LowerBoundRuntime};
let lower = LowerBoundClosed::new(0.0);
let lower_runtime: LowerBoundRuntime<f64> = lower.into();
let interval = IntervalInfiniteLength::new_upper_unbounded(lower_runtime);
match interval {
IntervalInfiniteLength::LowerClosedUpperUnbounded(result) => {
assert_eq!(result.lower_bound_value(), &0.0);
}
_ => panic!("Expected LowerClosedUpperUnbounded variant"),
}
}
#[test]
fn test_new_upper_unbounded_open() {
use crate::bounds::{LowerBoundOpen, LowerBoundRuntime};
let lower = LowerBoundOpen::new(0.0);
let lower_runtime: LowerBoundRuntime<f64> = lower.into();
let interval = IntervalInfiniteLength::new_upper_unbounded(lower_runtime);
match interval {
IntervalInfiniteLength::LowerOpenUpperUnbounded(result) => {
assert_eq!(result.lower_bound_value(), &0.0);
}
_ => panic!("Expected LowerOpenUpperUnbounded variant"),
}
}
#[test]
fn test_interval_try_new_fully_unbounded() {
let interval = Interval::<f64>::try_from_runtime_bounds(None, None).unwrap();
match interval {
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperUnbounded(
_,
)) => {
}
_ => panic!("Expected fully unbounded interval"),
}
}
#[test]
fn test_interval_try_new_lower_bounded_closed() {
use crate::bounds::{LowerBoundClosed, LowerBoundRuntime};
let lower = LowerBoundClosed::new(0.0);
let lower_runtime: LowerBoundRuntime<f64> = lower.into();
let interval = Interval::try_from_runtime_bounds(Some(lower_runtime), None).unwrap();
match interval {
Interval::InfiniteLength(IntervalInfiniteLength::LowerClosedUpperUnbounded(
result,
)) => {
assert_eq!(result.lower_bound_value(), &0.0);
}
_ => panic!("Expected LowerClosedUpperUnbounded interval"),
}
}
#[test]
fn test_interval_try_new_lower_bounded_open() {
use crate::bounds::{LowerBoundOpen, LowerBoundRuntime};
let lower = LowerBoundOpen::new(0.0);
let lower_runtime: LowerBoundRuntime<f64> = lower.into();
let interval = Interval::try_from_runtime_bounds(Some(lower_runtime), None).unwrap();
match interval {
Interval::InfiniteLength(IntervalInfiniteLength::LowerOpenUpperUnbounded(
result,
)) => {
assert_eq!(result.lower_bound_value(), &0.0);
}
_ => panic!("Expected LowerOpenUpperUnbounded interval"),
}
}
#[test]
fn test_interval_try_new_upper_bounded_closed() {
use crate::bounds::{UpperBoundClosed, UpperBoundRuntime};
let upper = UpperBoundClosed::new(10.0);
let upper_runtime: UpperBoundRuntime<f64> = upper.into();
let interval = Interval::try_from_runtime_bounds(None, Some(upper_runtime)).unwrap();
match interval {
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperClosed(
result,
)) => {
assert_eq!(result.upper_bound_value(), &10.0);
}
_ => panic!("Expected LowerUnboundedUpperClosed interval"),
}
}
#[test]
fn test_interval_try_new_upper_bounded_open() {
use crate::bounds::{UpperBoundOpen, UpperBoundRuntime};
let upper = UpperBoundOpen::new(10.0);
let upper_runtime: UpperBoundRuntime<f64> = upper.into();
let interval = Interval::try_from_runtime_bounds(None, Some(upper_runtime)).unwrap();
match interval {
Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperOpen(
result,
)) => {
assert_eq!(result.upper_bound_value(), &10.0);
}
_ => panic!("Expected LowerUnboundedUpperOpen interval"),
}
}
#[test]
fn test_interval_try_new_singleton() {
use crate::bounds::{
LowerBoundClosed, LowerBoundRuntime, UpperBoundClosed, UpperBoundRuntime,
};
let value = 5.0;
let lower = LowerBoundClosed::new(value);
let upper = UpperBoundClosed::new(value);
let lower_runtime: LowerBoundRuntime<f64> = lower.into();
let upper_runtime: UpperBoundRuntime<f64> = upper.into();
let interval =
Interval::try_from_runtime_bounds(Some(lower_runtime), Some(upper_runtime))
.unwrap();
match interval {
Interval::FiniteLength(IntervalFiniteLength::ZeroLength(result)) => {
assert_eq!(result.value(), &value);
}
_ => panic!("Expected singleton interval"),
}
}
#[test]
fn test_interval_try_new_closed_interval() {
use crate::bounds::{
LowerBoundClosed, LowerBoundRuntime, UpperBoundClosed, UpperBoundRuntime,
};
let lower = LowerBoundClosed::new(0.0);
let upper = UpperBoundClosed::new(10.0);
let lower_runtime: LowerBoundRuntime<f64> = lower.into();
let upper_runtime: UpperBoundRuntime<f64> = upper.into();
let interval =
Interval::try_from_runtime_bounds(Some(lower_runtime), Some(upper_runtime))
.unwrap();
match interval {
Interval::FiniteLength(IntervalFiniteLength::PositiveLength(
IntervalFinitePositiveLength::Closed(result),
)) => {
assert_eq!(result.lower_bound_value(), &0.0);
assert_eq!(result.upper_bound_value(), &10.0);
}
_ => panic!("Expected closed interval"),
}
}
#[test]
fn test_interval_try_new_half_open() {
use crate::bounds::{
LowerBoundClosed, LowerBoundRuntime, UpperBoundOpen, UpperBoundRuntime,
};
let lower = LowerBoundClosed::new(0.0);
let upper = UpperBoundOpen::new(10.0);
let lower_runtime: LowerBoundRuntime<f64> = lower.into();
let upper_runtime: UpperBoundRuntime<f64> = upper.into();
let interval =
Interval::try_from_runtime_bounds(Some(lower_runtime), Some(upper_runtime))
.unwrap();
match interval {
Interval::FiniteLength(IntervalFiniteLength::PositiveLength(
IntervalFinitePositiveLength::LowerClosedUpperOpen(result),
)) => {
assert_eq!(result.lower_bound_value(), &0.0);
assert_eq!(result.upper_bound_value(), &10.0);
}
_ => panic!("Expected half-open interval [a, b)"),
}
}
#[test]
fn test_interval_try_new_invalid_bounds() {
use crate::bounds::{
LowerBoundClosed, LowerBoundRuntime, UpperBoundClosed, UpperBoundRuntime,
};
let lower = LowerBoundClosed::new(10.0);
let upper = UpperBoundClosed::new(0.0);
let lower_runtime: LowerBoundRuntime<f64> = lower.into();
let upper_runtime: UpperBoundRuntime<f64> = upper.into();
let result =
Interval::try_from_runtime_bounds(Some(lower_runtime), Some(upper_runtime));
assert!(result.is_err(), "Should fail when lower > upper");
}
#[test]
fn test_interval_finite_length_try_new_all_combinations() {
use crate::bounds::{
LowerBoundClosed, LowerBoundOpen, UpperBoundClosed, UpperBoundOpen,
};
let lower = LowerBoundClosed::new(0.0);
let upper = UpperBoundClosed::new(10.0);
let interval =
IntervalFiniteLength::try_from_runtime_bounds(lower.into(), upper.into()).unwrap();
match interval {
IntervalFiniteLength::PositiveLength(IntervalFinitePositiveLength::Closed(_)) => {}
_ => panic!("Expected closed interval"),
}
let lower = LowerBoundClosed::new(0.0);
let upper = UpperBoundOpen::new(10.0);
let interval =
IntervalFiniteLength::try_from_runtime_bounds(lower.into(), upper.into()).unwrap();
match interval {
IntervalFiniteLength::PositiveLength(
IntervalFinitePositiveLength::LowerClosedUpperOpen(_),
) => {}
_ => panic!("Expected [a, b) interval"),
}
let lower = LowerBoundOpen::new(0.0);
let upper = UpperBoundClosed::new(10.0);
let interval =
IntervalFiniteLength::try_from_runtime_bounds(lower.into(), upper.into()).unwrap();
match interval {
IntervalFiniteLength::PositiveLength(
IntervalFinitePositiveLength::LowerOpenUpperClosed(_),
) => {}
_ => panic!("Expected (a, b] interval"),
}
let lower = LowerBoundOpen::new(0.0);
let upper = UpperBoundOpen::new(10.0);
let interval =
IntervalFiniteLength::try_from_runtime_bounds(lower.into(), upper.into()).unwrap();
match interval {
IntervalFiniteLength::PositiveLength(IntervalFinitePositiveLength::Open(_)) => {}
_ => panic!("Expected open interval"),
}
}
#[test]
fn test_interval_finite_length_singleton_creation() {
use crate::bounds::{LowerBoundClosed, UpperBoundClosed};
let value = 5.0;
let lower = LowerBoundClosed::new(value);
let upper = UpperBoundClosed::new(value);
let interval =
IntervalFiniteLength::try_from_runtime_bounds(lower.into(), upper.into()).unwrap();
match interval {
IntervalFiniteLength::ZeroLength(result) => {
assert_eq!(result.value(), &value);
}
_ => panic!("Expected singleton interval"),
}
}
#[test]
fn test_interval_finite_positive_length_try_new() {
use crate::bounds::{
LowerBoundClosed, LowerBoundOpen, UpperBoundClosed, UpperBoundOpen,
};
let lower = LowerBoundClosed::new(0.0);
let upper = UpperBoundClosed::new(10.0);
let interval =
IntervalFinitePositiveLength::try_from_runtime_bounds(lower.into(), upper.into())
.unwrap();
match interval {
IntervalFinitePositiveLength::Closed(result) => {
assert_eq!(result.lower_bound_value(), &0.0);
assert_eq!(result.upper_bound_value(), &10.0);
}
_ => panic!("Expected closed interval"),
}
let lower = LowerBoundClosed::new(0.0);
let upper = UpperBoundOpen::new(10.0);
let interval =
IntervalFinitePositiveLength::try_from_runtime_bounds(lower.into(), upper.into())
.unwrap();
match interval {
IntervalFinitePositiveLength::LowerClosedUpperOpen(_) => {}
_ => panic!("Expected [a, b) interval"),
}
let lower = LowerBoundOpen::new(0.0);
let upper = UpperBoundClosed::new(10.0);
let interval =
IntervalFinitePositiveLength::try_from_runtime_bounds(lower.into(), upper.into())
.unwrap();
match interval {
IntervalFinitePositiveLength::LowerOpenUpperClosed(_) => {}
_ => panic!("Expected (a, b] interval"),
}
let lower = LowerBoundOpen::new(0.0);
let upper = UpperBoundOpen::new(10.0);
let interval =
IntervalFinitePositiveLength::try_from_runtime_bounds(lower.into(), upper.into())
.unwrap();
match interval {
IntervalFinitePositiveLength::Open(_) => {}
_ => panic!("Expected open interval"),
}
}
#[test]
fn test_interval_finite_positive_length_invalid() {
use crate::bounds::{LowerBoundClosed, UpperBoundClosed};
let lower = LowerBoundClosed::new(10.0);
let upper = UpperBoundClosed::new(5.0);
let result =
IntervalFinitePositiveLength::try_from_runtime_bounds(lower.into(), upper.into());
assert!(result.is_err(), "Should fail when lower > upper");
}
}
mod interval_finite_positive_length_bounds {
use super::*;
#[test]
fn is_upper_bound_closed_variant_closed() {
let interval = IntervalFinitePositiveLength::Closed(IntervalClosed::new(0.0, 10.0));
assert!(
interval.is_upper_bound_closed(),
"Closed variant should have closed upper bound"
);
assert!(!interval.is_upper_bound_open());
}
#[test]
fn is_upper_bound_closed_variant_open() {
let interval = IntervalFinitePositiveLength::Open(IntervalOpen::new(0.0, 10.0));
assert!(
!interval.is_upper_bound_closed(),
"Open variant should have open upper bound"
);
assert!(interval.is_upper_bound_open());
}
#[test]
fn is_upper_bound_closed_variant_lower_closed_upper_open() {
let interval = IntervalFinitePositiveLength::LowerClosedUpperOpen(
IntervalLowerClosedUpperOpen::new(0.0, 10.0),
);
assert!(
!interval.is_upper_bound_closed(),
"LowerClosedUpperOpen [a, b) should have open upper bound"
);
assert!(interval.is_upper_bound_open());
}
#[test]
fn is_upper_bound_closed_variant_lower_open_upper_closed() {
let interval = IntervalFinitePositiveLength::LowerOpenUpperClosed(
IntervalLowerOpenUpperClosed::new(0.0, 10.0),
);
assert!(
interval.is_upper_bound_closed(),
"LowerOpenUpperClosed (a, b] should have closed upper bound"
);
assert!(!interval.is_upper_bound_open());
}
#[test]
fn is_upper_bound_open_complement_all_variants() {
let closed = IntervalFinitePositiveLength::Closed(IntervalClosed::new(0.0, 10.0));
assert_eq!(
closed.is_upper_bound_open(),
!closed.is_upper_bound_closed(),
"Complement relationship must hold for Closed"
);
let open = IntervalFinitePositiveLength::Open(IntervalOpen::new(0.0, 10.0));
assert_eq!(
open.is_upper_bound_open(),
!open.is_upper_bound_closed(),
"Complement relationship must hold for Open"
);
let half_open1 = IntervalFinitePositiveLength::LowerClosedUpperOpen(
IntervalLowerClosedUpperOpen::new(0.0, 10.0),
);
assert_eq!(
half_open1.is_upper_bound_open(),
!half_open1.is_upper_bound_closed(),
"Complement relationship must hold for LowerClosedUpperOpen"
);
let half_open2 = IntervalFinitePositiveLength::LowerOpenUpperClosed(
IntervalLowerOpenUpperClosed::new(0.0, 10.0),
);
assert_eq!(
half_open2.is_upper_bound_open(),
!half_open2.is_upper_bound_closed(),
"Complement relationship must hold for LowerOpenUpperClosed"
);
}
#[test]
fn is_upper_bound_closed_negative_values() {
let closed = IntervalFinitePositiveLength::Closed(IntervalClosed::new(-10.0, -5.0));
assert!(
closed.is_upper_bound_closed(),
"Closed interval with negative bounds should have closed upper bound"
);
let open = IntervalFinitePositiveLength::Open(IntervalOpen::new(-10.0, -5.0));
assert!(
!open.is_upper_bound_closed(),
"Open interval with negative bounds should have open upper bound"
);
}
#[test]
fn is_upper_bound_closed_small_intervals() {
let epsilon = 1e-10;
let closed = IntervalFinitePositiveLength::Closed(IntervalClosed::new(0.0, epsilon));
assert!(
closed.is_upper_bound_closed(),
"Small closed interval should have closed upper bound"
);
let half_open = IntervalFinitePositiveLength::LowerClosedUpperOpen(
IntervalLowerClosedUpperOpen::new(0.0, epsilon),
);
assert!(
!half_open.is_upper_bound_closed(),
"Small half-open interval should have open upper bound"
);
}
#[test]
fn is_upper_bound_closed_consistency_with_value() {
let closed = IntervalFinitePositiveLength::Closed(IntervalClosed::new(0.0, 10.0));
assert_eq!(closed.upper_bound_value(), &10.0);
assert!(closed.is_upper_bound_closed());
let open = IntervalFinitePositiveLength::Open(IntervalOpen::new(0.0, 10.0));
assert_eq!(open.upper_bound_value(), &10.0);
assert!(!open.is_upper_bound_closed());
}
#[test]
fn is_lower_bound_closed_variant_closed() {
let interval = IntervalFinitePositiveLength::Closed(IntervalClosed::new(0.0, 10.0));
assert!(
interval.is_lower_bound_closed(),
"Closed variant should have closed lower bound"
);
assert!(!interval.is_lower_bound_open());
}
#[test]
fn is_lower_bound_closed_variant_open() {
let interval = IntervalFinitePositiveLength::Open(IntervalOpen::new(0.0, 10.0));
assert!(
!interval.is_lower_bound_closed(),
"Open variant should have open lower bound"
);
assert!(interval.is_lower_bound_open());
}
#[test]
fn is_lower_bound_closed_variant_lower_closed_upper_open() {
let interval = IntervalFinitePositiveLength::LowerClosedUpperOpen(
IntervalLowerClosedUpperOpen::new(0.0, 10.0),
);
assert!(
interval.is_lower_bound_closed(),
"LowerClosedUpperOpen [a, b) should have closed lower bound"
);
assert!(!interval.is_lower_bound_open());
}
#[test]
fn is_lower_bound_closed_variant_lower_open_upper_closed() {
let interval = IntervalFinitePositiveLength::LowerOpenUpperClosed(
IntervalLowerOpenUpperClosed::new(0.0, 10.0),
);
assert!(
!interval.is_lower_bound_closed(),
"LowerOpenUpperClosed (a, b] should have open lower bound"
);
assert!(interval.is_lower_bound_open());
}
#[test]
fn both_bounds_all_variants() {
let closed = IntervalFinitePositiveLength::Closed(IntervalClosed::new(0.0, 10.0));
assert!(closed.is_lower_bound_closed() && closed.is_upper_bound_closed());
assert!(!closed.is_lower_bound_open() && !closed.is_upper_bound_open());
let open = IntervalFinitePositiveLength::Open(IntervalOpen::new(0.0, 10.0));
assert!(!open.is_lower_bound_closed() && !open.is_upper_bound_closed());
assert!(open.is_lower_bound_open() && open.is_upper_bound_open());
let lc_uo = IntervalFinitePositiveLength::LowerClosedUpperOpen(
IntervalLowerClosedUpperOpen::new(0.0, 10.0),
);
assert!(lc_uo.is_lower_bound_closed() && !lc_uo.is_upper_bound_closed());
assert!(!lc_uo.is_lower_bound_open() && lc_uo.is_upper_bound_open());
let lo_uc = IntervalFinitePositiveLength::LowerOpenUpperClosed(
IntervalLowerOpenUpperClosed::new(0.0, 10.0),
);
assert!(!lo_uc.is_lower_bound_closed() && lo_uc.is_upper_bound_closed());
assert!(lo_uc.is_lower_bound_open() && !lo_uc.is_upper_bound_open());
}
#[test]
fn bound_predicates_with_validated_types() {
use num_valid::RealNative64StrictFiniteInDebug;
use try_create::TryNew;
type Real = RealNative64StrictFiniteInDebug;
let closed = IntervalFinitePositiveLength::Closed(IntervalClosed::new(
Real::try_new(0.0).unwrap(),
Real::try_new(10.0).unwrap(),
));
assert!(closed.is_upper_bound_closed());
assert!(closed.is_lower_bound_closed());
let open = IntervalFinitePositiveLength::Open(IntervalOpen::new(
Real::try_new(0.0).unwrap(),
Real::try_new(10.0).unwrap(),
));
assert!(open.is_upper_bound_open());
assert!(open.is_lower_bound_open());
}
#[test]
fn clamp_value_below_interval() {
let interval = IntervalFinitePositiveLength::Closed(IntervalClosed::new(0.0, 10.0));
assert_eq!(interval.clamp(-5.0), 0.0);
assert_eq!(interval.clamp(-1.0), 0.0);
assert_eq!(interval.clamp(-0.1), 0.0);
}
#[test]
fn clamp_value_above_interval() {
let interval = IntervalFinitePositiveLength::Closed(IntervalClosed::new(0.0, 10.0));
assert_eq!(interval.clamp(15.0), 10.0);
assert_eq!(interval.clamp(11.0), 10.0);
assert_eq!(interval.clamp(10.1), 10.0);
}
#[test]
fn clamp_value_inside_interval() {
let interval = IntervalFinitePositiveLength::Closed(IntervalClosed::new(0.0, 10.0));
assert_eq!(interval.clamp(5.0), 5.0);
assert_eq!(interval.clamp(2.5), 2.5);
assert_eq!(interval.clamp(7.5), 7.5);
assert_eq!(interval.clamp(0.1), 0.1);
assert_eq!(interval.clamp(9.9), 9.9);
}
#[test]
fn clamp_at_boundaries() {
let interval = IntervalFinitePositiveLength::Closed(IntervalClosed::new(0.0, 10.0));
assert_eq!(interval.clamp(0.0), 0.0); assert_eq!(interval.clamp(10.0), 10.0); }
#[test]
fn clamp_all_variants() {
let closed = IntervalFinitePositiveLength::Closed(IntervalClosed::new(5.0, 15.0));
assert_eq!(closed.clamp(3.0), 5.0); assert_eq!(closed.clamp(10.0), 10.0); assert_eq!(closed.clamp(20.0), 15.0);
let open = IntervalFinitePositiveLength::Open(IntervalOpen::new(5.0, 15.0));
assert_eq!(open.clamp(3.0), 5.0); assert_eq!(open.clamp(10.0), 10.0); assert_eq!(open.clamp(20.0), 15.0);
let lc_uo = IntervalFinitePositiveLength::LowerClosedUpperOpen(
IntervalLowerClosedUpperOpen::new(5.0, 15.0),
);
assert_eq!(lc_uo.clamp(3.0), 5.0); assert_eq!(lc_uo.clamp(10.0), 10.0); assert_eq!(lc_uo.clamp(20.0), 15.0);
let lo_uc = IntervalFinitePositiveLength::LowerOpenUpperClosed(
IntervalLowerOpenUpperClosed::new(5.0, 15.0),
);
assert_eq!(lo_uc.clamp(3.0), 5.0); assert_eq!(lo_uc.clamp(10.0), 10.0); assert_eq!(lo_uc.clamp(20.0), 15.0); }
#[test]
fn clamp_negative_bounds() {
let interval = IntervalFinitePositiveLength::Closed(IntervalClosed::new(-10.0, -5.0));
assert_eq!(interval.clamp(-15.0), -10.0); assert_eq!(interval.clamp(-7.5), -7.5); assert_eq!(interval.clamp(-3.0), -5.0); assert_eq!(interval.clamp(-10.0), -10.0); assert_eq!(interval.clamp(-5.0), -5.0); }
#[test]
fn clamp_interval_crossing_zero() {
let interval = IntervalFinitePositiveLength::Closed(IntervalClosed::new(-5.0, 5.0));
assert_eq!(interval.clamp(-10.0), -5.0); assert_eq!(interval.clamp(-2.0), -2.0); assert_eq!(interval.clamp(0.0), 0.0); assert_eq!(interval.clamp(2.0), 2.0); assert_eq!(interval.clamp(10.0), 5.0); }
#[test]
fn clamp_small_interval() {
let epsilon = 1e-10;
let interval = IntervalFinitePositiveLength::Closed(IntervalClosed::new(0.0, epsilon));
assert_eq!(interval.clamp(-1.0), 0.0); assert_eq!(interval.clamp(epsilon / 2.0), epsilon / 2.0); assert_eq!(interval.clamp(1.0), epsilon); }
#[test]
fn clamp_large_values() {
let interval = IntervalFinitePositiveLength::Closed(IntervalClosed::new(0.0, 1000.0));
assert_eq!(interval.clamp(-1e6), 0.0); assert_eq!(interval.clamp(1e6), 1000.0); assert_eq!(interval.clamp(500.0), 500.0); }
#[test]
fn clamp_idempotency() {
let interval = IntervalFinitePositiveLength::Closed(IntervalClosed::new(0.0, 10.0));
let value = 15.0;
let clamped_once = interval.clamp(value);
let clamped_twice = interval.clamp(clamped_once);
assert_eq!(clamped_once, clamped_twice);
for test_value in [-5.0, 0.0, 5.0, 10.0, 15.0] {
let once = interval.clamp(test_value);
let twice = interval.clamp(once);
assert_eq!(once, twice, "Idempotency failed for value {}", test_value);
}
}
#[test]
fn clamp_result_in_range() {
let interval = IntervalFinitePositiveLength::Closed(IntervalClosed::new(0.0, 10.0));
for test_value in [-100.0, -10.0, -1.0, 0.0, 5.0, 10.0, 15.0, 100.0] {
let clamped = interval.clamp(test_value);
assert!(
clamped >= *interval.lower_bound_value(),
"Clamped value {} is below lower bound {}",
clamped,
interval.lower_bound_value()
);
assert!(
clamped <= *interval.upper_bound_value(),
"Clamped value {} is above upper bound {}",
clamped,
interval.upper_bound_value()
);
}
}
#[test]
fn clamp_with_validated_types() {
use num_valid::RealNative64StrictFiniteInDebug;
use try_create::TryNew;
type Real = RealNative64StrictFiniteInDebug;
let interval = IntervalFinitePositiveLength::Closed(IntervalClosed::new(
Real::try_new(0.0).unwrap(),
Real::try_new(10.0).unwrap(),
));
let below = Real::try_new(-5.0).unwrap();
assert_eq!(interval.clamp(below), Real::try_new(0.0).unwrap());
let inside = Real::try_new(5.0).unwrap();
assert_eq!(interval.clamp(inside), Real::try_new(5.0).unwrap());
let above = Real::try_new(15.0).unwrap();
assert_eq!(interval.clamp(above), Real::try_new(10.0).unwrap());
}
#[test]
fn clamp_preserves_interval() {
let interval = IntervalFinitePositiveLength::Closed(IntervalClosed::new(0.0, 10.0));
let original_lower = *interval.lower_bound_value();
let original_upper = *interval.upper_bound_value();
let _ = interval.clamp(-5.0);
let _ = interval.clamp(5.0);
let _ = interval.clamp(15.0);
assert_eq!(*interval.lower_bound_value(), original_lower);
assert_eq!(*interval.upper_bound_value(), original_upper);
}
#[test]
fn clamp_floating_point_edge_cases() {
let interval = IntervalFinitePositiveLength::Closed(IntervalClosed::new(0.0, 10.0));
assert_eq!(interval.clamp(f64::EPSILON), f64::EPSILON);
assert_eq!(interval.clamp(-f64::EPSILON), 0.0);
let just_below_upper = 10.0 - f64::EPSILON;
assert_eq!(interval.clamp(just_below_upper), just_below_upper);
let just_above_lower = 0.0 + f64::EPSILON;
assert_eq!(interval.clamp(just_above_lower), just_above_lower);
}
#[test]
fn clamp_on_very_small_interval() {
let interval = IntervalFinitePositiveLength::Closed(IntervalClosed::new(5.0, 5.001));
assert_eq!(interval.clamp(0.0), 5.0); assert_eq!(interval.clamp(10.0), 5.001);
let mid = 5.0005;
let clamped = interval.clamp(mid);
assert_eq!(clamped, mid);
}
}
mod subinterval_only_variant {
use super::*;
use try_create::IntoInner;
#[test]
fn test_only_variant_lower_bound_runtime() {
let interval = IntervalClosed::new(0.0, 10.0);
let sub = SubIntervalInPartition::Single(interval);
let lower = sub.lower_bound_runtime();
assert!(lower.is_some());
let lower = lower.unwrap();
assert_eq!(*lower.as_ref(), 0.0);
assert!(lower.is_closed_variant());
}
#[test]
fn test_only_variant_upper_bound_runtime() {
let interval = IntervalClosed::new(0.0, 10.0);
let sub = SubIntervalInPartition::Single(interval);
let upper = sub.upper_bound_runtime();
assert!(upper.is_some());
let upper = upper.unwrap();
assert_eq!(*upper.as_ref(), 10.0);
assert!(upper.is_closed_variant());
}
#[test]
fn test_only_variant_into_bounds_pair() {
let interval = IntervalClosed::new(5.0, 15.0);
let sub = SubIntervalInPartition::Single(interval);
let (lower, upper) = sub.into_bounds_pair();
assert_eq!(lower.into_inner(), 5.0);
assert_eq!(upper.into_inner(), 15.0);
}
#[test]
fn test_only_variant_try_new() {
let closed = IntervalClosed::<f64>::new(0.0, 10.0);
let sub = SubIntervalInPartition::Single(closed);
if let SubIntervalInPartition::Single(interval) = sub {
assert_eq!(interval.lower_bound_value(), &0.0);
assert_eq!(interval.upper_bound_value(), &10.0);
} else {
panic!("Expected Single variant");
}
let invalid = IntervalClosed::<f64>::try_new(10.0, 0.0);
assert!(invalid.is_err());
let zero_length = IntervalClosed::<f64>::try_new(5.0, 5.0);
assert!(zero_length.is_err());
}
#[test]
fn test_only_variant_with_open_interval() {
let interval = IntervalOpen::new(-5.0, 5.0);
let sub = SubIntervalInPartition::Single(interval);
assert!(!sub.is_lower_bound_closed());
assert!(!sub.is_upper_bound_closed());
assert_eq!(sub.length().into_inner(), 10.0);
let lower = sub.lower_bound_runtime().unwrap();
assert!(lower.is_open_variant());
let upper = sub.upper_bound_runtime().unwrap();
assert!(upper.is_open_variant());
}
#[test]
fn test_only_variant_with_half_open_interval() {
let interval = IntervalLowerClosedUpperOpen::new(0.0, 1.0);
let sub = SubIntervalInPartition::Single(interval);
assert!(sub.is_lower_bound_closed());
assert!(!sub.is_upper_bound_closed());
assert_eq!(sub.lower_bound_value(), &0.0);
assert_eq!(sub.upper_bound_value(), &1.0);
}
}
}